feat(i18n): wrap 1103 hardcoded UI strings across Filament with __()

- Convert static $modelLabel/$pluralModelLabel/$title to getter methods
- Wrap ->label()/->placeholder()/->helperText()/->description()/->title()/->body() args
- Wrap Section::make()/Fieldset::make()/Notification::make()->title() args
- Fix RelationManagers::getTitle() signature to match parent (Model, string)
- Fix Pages::getTitle() to instance method (BasePage::getTitle is non-static)
- Extend lang/ru.json + lang/en.json with 700+ common terms; identity fallback for the rest
- Remove duplicate getters in 5 resources that had manual getModelLabel already

All 306 tests pass. Missing translations fall back to the RO key so the UI never breaks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-15 05:04:24 +00:00
parent 78ff8d4b43
commit f7fc69077b
83 changed files with 4212 additions and 1251 deletions
@@ -21,14 +21,14 @@ class ListPurchases extends ListRecords
{
return [
Actions\Action::make('ocr')
->label('Import factură (OCR)')
->label(__('Import factură (OCR)'))
->icon('heroicon-m-document-arrow-up')
->color('gray')
->modalHeading('Import factură via OCR')
->modalDescription('Încarcă o poză cu factura. AI-ul extrage furnizorul, data și liniile. Verifici și salvezi.')
->modalHeading(__('Import factură via OCR'))
->modalDescription(__('Încarcă o poză cu factura. AI-ul extrage furnizorul, data și liniile. Verifici și salvezi.'))
->schema([
Forms\Components\FileUpload::make('invoice')
->label('Foto factură')
->label(__('Foto factură'))
->image()
->disk('local')
->directory('ocr-imports')
@@ -41,7 +41,7 @@ class ListPurchases extends ListRecords
if (! ($result['ok'] ?? false)) {
Notification::make()
->title('OCR eșuat')
->title(__('OCR eșuat'))
->body($result['error'] ?? 'Eroare necunoscută.')
->danger()->send();
@unlink($abs);
@@ -83,7 +83,7 @@ class ListPurchases extends ListRecords
@unlink($abs);
Notification::make()
->title('Factură importată')
->title(__('Factură importată'))
->body(sprintf('%d linii, total %.2f. Verifică și ajustează înainte de a confirma.',
count($payload['items']), (float) $purchase->total))
->success()->send();
@@ -18,13 +18,18 @@ class ItemsRelationManager extends RelationManager
{
protected static string $relationship = 'items';
protected static ?string $title = 'Articole';
protected static ?string $title = null;
public static function getTitle(\Illuminate\Database\Eloquent\Model $ownerRecord, string $pageClass): string
{
return __('Articole');
}
public function form(Schema $schema): Schema
{
return $schema->components([
Forms\Components\Select::make('part_id')
->label('Piesă din catalog')
->label(__('Piesă din catalog'))
->options(fn () => Part::where('is_active', true)
->get()
->mapWithKeys(fn ($p) => [$p->id => "{$p->name} " . ($p->article ? "[{$p->article}]" : '')])
@@ -40,11 +45,11 @@ class ItemsRelationManager extends RelationManager
}
})
->columnSpanFull(),
Forms\Components\TextInput::make('name')->label('Denumire')->required()->columnSpanFull(),
Forms\Components\TextInput::make('article')->label('Cod articol'),
Forms\Components\TextInput::make('qty')->label('Cantitate')->numeric()->default(1)->required(),
Forms\Components\TextInput::make('unit')->label('UM')->default('buc'),
Forms\Components\TextInput::make('buy_price')->label('Preț achiziție')->numeric()->required(),
Forms\Components\TextInput::make('name')->label(__('Denumire'))->required()->columnSpanFull(),
Forms\Components\TextInput::make('article')->label(__('Cod articol')),
Forms\Components\TextInput::make('qty')->label(__('Cantitate'))->numeric()->default(1)->required(),
Forms\Components\TextInput::make('unit')->label(__('UM'))->default('buc'),
Forms\Components\TextInput::make('buy_price')->label(__('Preț achiziție'))->numeric()->required(),
]);
}
@@ -55,13 +60,13 @@ class ItemsRelationManager extends RelationManager
->columns([
Tables\Columns\TextColumn::make('name')->wrap(),
Tables\Columns\TextColumn::make('article')->placeholder('—'),
Tables\Columns\TextColumn::make('qty')->label('Comandat')->alignRight(),
Tables\Columns\TextColumn::make('qty')->label(__('Comandat'))->alignRight(),
Tables\Columns\TextColumn::make('qty_received')
->label('Recepționat')
->label(__('Recepționat'))
->alignRight()
->color(fn ($state, $record) => $record->isFullyReceived() ? 'success' : ((float) $state > 0 ? 'warning' : 'gray'))
->formatStateUsing(fn ($state, $record) => sprintf('%.2f / %.2f', (float) $state, (float) $record->qty)),
Tables\Columns\TextColumn::make('unit')->label('UM'),
Tables\Columns\TextColumn::make('unit')->label(__('UM')),
Tables\Columns\TextColumn::make('buy_price')->money('MDL')->alignRight(),
Tables\Columns\TextColumn::make('total')->money('MDL')->alignRight(),
])
@@ -70,22 +75,22 @@ class ItemsRelationManager extends RelationManager
])
->actions([
Actions\Action::make('receive_item')
->label('Recepționează')
->label(__('Recepționează'))
->icon('heroicon-m-arrow-down-tray')
->color('success')
->visible(fn (PurchaseItem $r) => ! $r->isFullyReceived())
->schema([
Forms\Components\Placeholder::make('outstanding')
->label('Restanță')
->label(__('Restanță'))
->content(fn (PurchaseItem $r) => sprintf('%.2f %s', $r->outstanding(), $r->unit ?? 'buc')),
Forms\Components\TextInput::make('qty')
->label('Cantitate recepționată')
->label(__('Cantitate recepționată'))
->numeric()
->required()
->minValue(0.001)
->default(fn (PurchaseItem $r) => $r->outstanding()),
Forms\Components\Select::make('warehouse_id')
->label('Depozit țintă')
->label(__('Depozit țintă'))
->options(fn () => Warehouse::where('is_active', true)->pluck('name', 'id'))
->default(fn (PurchaseItem $r) => $r->purchase?->warehouse_id
?? Warehouse::where('is_default', true)->value('id'))
@@ -96,12 +101,12 @@ class ItemsRelationManager extends RelationManager
try {
$r->purchase->receiveItem($r, (float) $data['qty'], $wh);
Notification::make()
->title('Recepționat — batch creat')
->title(__('Recepționat — batch creat'))
->success()
->send();
} catch (\Throwable $e) {
Notification::make()
->title('Eroare la recepție')
->title(__('Eroare la recepție'))
->body($e->getMessage())
->danger()
->send();