Closed BurakBoz closed 11 months ago
Thank you @BurakBoz How to use the translatable? because I get:
Target class [translator] does not exist.
when adding translatable:
->libraryTypes([
'FILE' => __('File'),
'IMAGE' => __('Image'),
'VIDEO' => __('Video'),
])
also won't be better to allow to pass a Closure!
Hello! Here is my config/app.php
. I believe this will resolve your error.
'providers' => ServiceProvider::defaultProviders()->merge([
/*
* Package Service Providers...
*/
Illuminate\Translation\TranslationServiceProvider::class, // <== Translation Service
/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\Filament\AdminPanelProvider::class,
App\Providers\RouteServiceProvider::class,
])->toArray(),
When it comes to why I'm using cache, I noticed that it was being called three times. I implemented this structure to avoid unnecessary repetitive processing.
I'm using without __ function on my AdminPanelProvider
->libraryTypes([
'FILE' => 'File',
'IMAGE' => 'Image',
'VIDEO' => 'Video',
])
->tagTypes([
'tag' => 'Tag',
'category' => 'Category',
'library' => 'Library',
'faq' => 'Faq',
]))
I've also created a Trait for this that adds support for untranslatable plugin translations:
<?php
namespace BurakBoz\Filament\Support;
use Filament\Forms\Components\Field;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Toggle;
use Filament\Navigation\NavigationGroup;
use Filament\Navigation\NavigationItem;
use Filament\Tables\Columns\Column;
use Filament\Tables\Filters\BaseFilter;
trait TranslateLabels
{
public function autoTranslate(): void
{
$this->translateLabels([
NavigationGroup::class,
NavigationItem::class,
Field::class,
BaseFilter::class,
Placeholder::class,
Column::class,
Toggle::class
]);
}
private function translateLabels(array $components = []): void
{
foreach($components as $component)
{
if(class_exists($component))
{
$component::configureUsing(static function ($c): void
{
method_exists($c, 'translateLabel') && $c->translateLabel();
method_exists($c, 'label') && $c->label(__($c->getLabel()));
});
}
}
}
}
Using it in my AppServiceProvider
class AppServiceProvider extends ServiceProvider
{
use TranslateLabels;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
$this->autoTranslate();
}
Perhaps there are better alternatives to accomplish this; I would appreciate suggestions.
that is a nice solution for translating packages :)
I would do it by passing a Closure the same way for other configurations like skyPrefix
protected Closure| array | null $libraryTypes = [
'FILE' => 'File',
'IMAGE' => 'Image',
'VIDEO' => 'Video',
];
public function libraryTypes(Closure|array $types): static
{
$this->libraryTypes = $types;
return $this;
}
public function getLibraryTypes(): Closure|array|null
{
return $this->evaluate($this->libraryTypes);
}
and then in your panel provider:
->libraryTypes(fn()=>[
'FILE' => __('File'),
'IMAGE' => __('Image'),
'VIDEO' => __('Video'),
])
but I'm not sure about being called three times, does it happen even if you cache the views?
I believe this approach makes more sense. I will test the cache
public function getLibraryTypes(): ?array
{
!isset($GLOBALS["i"]) && $GLOBALS["i"] = 0; dump($GLOBALS["i"]++, debug_backtrace(limit:1));
return $this->libraryTypes;
}
php artisan cache:clear
php artisan optimize:clear
php artisan optimize
php artisan config:cache
php artisan route:cache
php artisan event:cache
php artisan icons:clear
php artisan icons:cache
php artisan view:cache
In a cached app, this results in 7 calls to the /admin/library/create
URL in LibraryResource.php:79
and LibraryResource.php:78
.
If each call executes the translate function, it can significantly slow down the application.
Here is the patched version of LibraryResource that reduces the number of calls to only 3.
<?php
namespace LaraZeus\Sky\Filament\Resources;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\SpatieMediaLibraryFileUpload;
use Filament\Forms\Components\SpatieTagsInput;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Forms\Set;
use Filament\Tables\Actions\Action;
use Filament\Tables\Actions\ActionGroup;
use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Columns\SpatieTagsColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Support\Str;
use LaraZeus\Sky\Filament\Resources\LibraryResource\Pages;
use LaraZeus\Sky\Models\Library;
use LaraZeus\Sky\SkyPlugin;
use Wallo\FilamentSelectify\Components\ButtonGroup;
class LibraryResource extends SkyResource
{
protected static ?string $slug = 'library';
protected static ?string $navigationIcon = 'heroicon-o-folder';
protected static ?int $navigationSort = 4;
public static function getModel(): string
{
return SkyPlugin::get()->getModel('Library');
}
public static function form(Form $form): Form
{
$libraryTypes = SkyPlugin::get()->getLibraryTypes();
return $form
->schema([
Section::make(__('Library File'))
->columns(2)
->schema([
TextInput::make('title')
->label(__('Library Title'))
->required()
->maxLength(255)
->live(onBlur: true)
->afterStateUpdated(function (Set $set, $state, $context) {
if ($context === 'edit') {
return;
}
$set('slug', Str::slug($state));
}),
TextInput::make('slug')
->unique(ignorable: fn (?Library $record): ?Library => $record)
->required()
->maxLength(255)
->label(__('Library Slug')),
Textarea::make('description')
->maxLength(255)
->label(__('Library Description'))
->columnSpan(2),
SpatieTagsInput::make('category')
->type('library')
->label(__('Library Categories')),
Select::make('type')
->label(__('Library Type'))
->visible($libraryTypes !== null)
->options($libraryTypes),
]),
Section::make(__('Library File'))
->collapsible()
->compact()
->schema([
ButtonGroup::make('upload_or_url')
->live()
->dehydrated(false)
->afterStateHydrated(function (Set $set, Get $get) {
$setVal = ($get('file_path') === null) ? 'upload' : 'url';
$set('upload_or_url', $setVal);
})
->options([
'upload' => __('upload'),
'url' => __('url'),
])
->default('upload'),
SpatieMediaLibraryFileUpload::make('file_path_upload')
->disk(SkyPlugin::get()->getUploadDisk())
->directory(SkyPlugin::get()->getUploadDirectory())
->collection('library')
->multiple()
->reorderable()
->visible(fn (Get $get) => $get('upload_or_url') === 'upload')
->label(''),
TextInput::make('file_path')
->label(__('file url'))
->visible(fn (Get $get) => $get('upload_or_url') === 'url')
->url(),
]),
]);
}
public static function table(Table $table): Table
{
$libraryTypes = SkyPlugin::get()->getLibraryTypes();
return $table
->columns([
TextColumn::make('title')->label(__('Library Title'))->searchable()->sortable()->toggleable(),
TextColumn::make('slug')->label(__('Library Slug'))->searchable()->sortable()->toggleable(),
TextColumn::make('type')
->label(__('Library Type'))
->searchable()
->sortable()
->visible($libraryTypes !== null)
->formatStateUsing(fn (string $state): string => str($state)->title())
->color('')
->color(fn (string $state) => match ($state) {
'IMAGE' => 'primary',
'FILE' => 'success',
'VIDEO' => 'warning',
default => '',
})
->icon(fn (string $state) => match ($state) {
'IMAGE' => 'heroicon-o-photo',
'FILE' => 'heroicon-o-document',
'VIDEO' => 'heroicon-o-film',
default => 'heroicon-o-document-magnifying-glass',
})
->toggleable(),
SpatieTagsColumn::make('tags')
->label(__('Library Tags'))
->toggleable()
->type('library'),
])
->actions([
ActionGroup::make([
EditAction::make('edit')->label(__('Edit')),
Action::make('Open')
->color('warning')
->icon('heroicon-o-arrow-top-right-on-square')
->label(__('Open'))
->url(fn (Library $record): string => route('library.item', ['slug' => $record->slug]))
->openUrlInNewTab(),
DeleteAction::make('delete')
->label(__('Delete')),
]),
])
->filters([
SelectFilter::make('type')
->visible()
->options($libraryTypes)
->visible($libraryTypes !== null)
->label(__('type')),
SelectFilter::make('tags')
->multiple()
->relationship('tags', 'name')
->label(__('Tags')),
])
->defaultSort('id', 'desc');
}
public static function getPages(): array
{
return [
'index' => Pages\ListLibrary::route('/'),
'create' => Pages\CreateLibrary::route('/create'),
'edit' => Pages\EditLibrary::route('/{record}/edit'),
];
}
public static function getLabel(): string
{
return __('Library');
}
public static function getPluralLabel(): string
{
return __('Libraries');
}
public static function getNavigationLabel(): string
{
return __('Libraries');
}
}
Closures can be useful for configuration, but they still require a temporary caching solution for translations.
I won't be submitting any more PRs or comments on this topic.
Let's, at the very least, include the Turkish language translation that I have submitted to the package.
No problem :). Thank you again, I will re-visit this and see how to improve it more and enhance the performance
This PR adds fast cached translation support for libraryTypes and tagTypes.