webard/filament-translatable
Installation:
composer require webard/filament-translatable
Publish the config (if needed):
php artisan vendor:publish --provider="Webard\FilamentTranslatable\FilamentTranslatableServiceProvider" --tag="config"
Model Integration:
Add the Translatable trait to your Eloquent model:
use Webard\FilamentTranslatable\Traits\Translatable;
class Post extends Model
{
use Translatable;
public $translatable = ['title', 'content'];
}
First Use Case:
Create a Filament resource for your model (e.g., PostResource). The package will automatically add translation fields to the form and table if configured.
config/filament-translatable.php (for global settings like default locale, fallback behavior).setupForm() and setupTable() methods in your Filament resource to see how translation fields are injected.Basic CRUD with Translations:
public static function form(Form $form): Form
{
return $form
->schema([
// Translatable fields are added automatically
TextInput::make('title')->required(),
RichEditor::make('content'),
]);
}
Locale-Specific Forms:
Use the TranslatableFields helper to group fields by locale:
public static function form(Form $form): Form
{
return $form
->schema([
TranslatableFields::make('title', 'content')
->locales(['en', 'es', 'fr']),
]);
}
Conditional Translations: Dynamically enable/disable translations based on user roles or model state:
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('title')
->translatable()
->visible(fn () => auth()->user()->can('translate')),
]);
}
Table Localization: Display translations in tables with a dropdown to switch locales:
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('title')
->translatable()
->locale(fn () => request()->get('locale', 'en')),
]);
}
Custom Field Types:
Extend the package to support custom Filament fields (e.g., Select, Checkbox):
use Webard\FilamentTranslatable\Fields\TranslatableField;
class TranslatableSelect extends TranslatableField
{
protected static string $fieldType = Select::class;
public static function make(string $name, ?string $label = null): static
{
return parent::make($name, $label)->columnSpanFull();
}
}
API Responses:
Use the toArray() or toJson() methods with the translatable option:
return Post::withTranslations()->get()->toJson(['translatable' => true]);
Middleware for Locale: Set a default locale via middleware:
public function handle(Request $request, Closure $next)
{
app()->setLocale(request()->get('locale', config('filament-translatable.default_locale')));
return $next($request);
}
Seeding Translations:
Use the createTranslations() helper in seeders:
Post::createTranslations([
'title' => ['en' => 'Hello', 'es' => 'Hola'],
'content' => ['en' => 'World', 'es' => 'Mundo'],
]);
Field Name Collisions:
created_at), explicitly specify the translatable fields in the model:
public $translatable = ['title', 'content']; // Avoids ambiguity
Locale Fallback:
config('filament-translatable.fallback_locale') is set to avoid errors when a translation is missing.'fallback_locale' => 'en',
Database Schema:
json column for translations by default. For large datasets, consider using a dedicated translations table (customize via config('filament-translatable.storage')).Caching Issues:
php artisan filament:cache-reset
Nested Resources:
setupForm()/setupTable() calls are after the child's to avoid field duplication.Missing Translations:
translatable array in your model includes all fields.Form Not Rendering:
TranslatableFields helper or translatable() method is called on the field.Performance:
withTranslations() sparingly in queries. For tables, use locale() to limit loaded translations:
$table->columns([
TextColumn::make('title')
->translatable()
->locale('en'), // Load only English translations
]);
Custom Storage Engine:
Override the default storage by binding a custom TranslationRepository:
$this->app->bind(
Webard\FilamentTranslatable\Contracts\TranslationRepository::class,
CustomTranslationRepository::class
);
Field Customization:
Extend the TranslatableField class to add logic (e.g., validation, conditional rendering):
class CustomTranslatableField extends TranslatableField
{
public function required(): static
{
return $this->rule('required');
}
}
Translation Events:
Listen for translation-related events (e.g., translatable.saving, translatable.saved):
event(new TranslatableSaving($model, $locale, $attributes));
Locale Switcher: Add a dynamic locale switcher to your Filament panel:
use Webard\FilamentTranslatable\Widgets\LocaleSwitcher;
public function getWidgets(): array
{
return [
LocaleSwitcher::make(),
];
}
Bulk Updates:
Use the updateTranslations() method for batch updates:
Post::where('id', 1)->updateTranslations([
'title' => ['es' => 'Nuevo Título'],
]);
Fallback Logic: Implement custom fallback logic in the model:
public function getTitleAttribute($value)
{
return $this->getTranslation('title', config('filament-translatable.fallback_locale'));
}
Testing:
Use the actingAsTranslator() helper in tests to simulate locale-specific actions:
$this->actingAsTranslator('es')->create(Post::class, ['title' => 'Prueba']);
Localization in API:
Pass the Accept-Language header to API requests for consistent responses:
$response = Http::withHeaders(['Accept-Language' => 'es'])->get('/api/posts');
How can I help you explore Laravel packages today?