mvenghaus/filament-plugin-translatable-inline
Install the Package
composer require mvenghaus/filament-plugin-translatable-inline:"^3.0"
Ensure your project uses Filament v3 and has spatie/laravel-translatable as a dependency (handled automatically).
Configure Spatie Translatable Plugin
Follow the Filament Spatie Translatable Plugin docs to register the plugin in your AppServiceProvider or FilamentServiceProvider:
Filament::registerPlugin(
TranslatablePlugin::make()
->locales(['en', 'de', 'fr']) // Define your locales
);
Add Translatable Trait to Your Model
Ensure your Eloquent model uses the Translatable trait:
use Spatie\Translatable\HasTranslations;
class Post extends Model
{
use HasTranslations;
public $translatable = ['title', 'content']; // Fields to translate
}
Use the Plugin in a Resource
Replace the default Translatable trait in your Form with the inline plugin’s trait:
use Mvenghaus\FilamentPluginTranslatableInline\Forms\Components\Translatable;
public static function form(Form $form): Form
{
return $form
->schema([
Translatable::make('title') // Inline translation container
->label('Title')
->required(),
// Other fields...
]);
}
First Use Case
Edit a record in your Filament admin panel. Translations now appear inline below each field (e.g., title_en, title_de) instead of a dropdown locale switcher. Missing translations are visually highlighted.
Field-Level Translations
Wrap any translatable field in Translatable::make():
Translatable::make('content')
->label('Content')
->columns(2) // Adjust layout (optional)
->extraAttributes(['class' => 'mt-4']),
columns() to control how many translations appear side-by-side (e.g., columns(3) for 3 locales).Dynamic Locale Handling Leverage the plugin’s built-in locale detection:
Translatable::make('description')
->locales(['en', 'es', 'pt']) // Override default locales
->defaultLocale('en'), // Set fallback
Integration with Existing Forms
Translatable header/action from the Spatie plugin with this inline component.Partial Translations
Use fillable or guarded in your model to control which fields support translations:
protected $translatable = ['title', 'excerpt']; // Only these fields
Conditional Translations Hide non-translatable fields or show placeholders:
Translatable::make('slug')
->hidden(fn ($record) => !$record->isTranslatable()),
Custom Translation Labels Override the default locale labels (e.g., "English" → "EN"):
Translatable::make('name')
->localeLabels(['en' => '🇬🇧', 'de' => '🇩🇪']),
Nested Translations For nested resources, ensure the parent model’s translations are loaded:
public static function form(Form $form): Form
{
return $form
->schema([
Translatable::make('parent.title'), // Nested field
// ...
]);
}
Bulk Translation Updates Use Filament’s bulk actions to update translations across records:
public static function table(Table $table): Table
{
return $table
->actions([
Tables\Actions\EditAction::make()->button(),
TranslatableBulkAction::make(), // Hypothetical (extend if needed)
]);
}
Fallback Logic
Combine with Spatie’s fallbackLocale in config/translatable.php:
'fallback_locale' => 'en',
Double Registration
Class 'Translatable' not found or duplicate locale headers.Translatable component is used in forms. Remove any TranslatableHeader or TranslatableAction from the Spatie plugin.Missing Translations
php artisan translate:fallback (Spatie command) or manually set defaults in the model:
public function getTitleAttribute($value)
{
return $value ?? __('fallback.title');
}
Locale Mismatch
title_de saved as title_en).locales() in the plugin config match your model’s $translatable fields.Performance with Large Fields
content).columns(1) or lazy-load translations via JavaScript:
Translatable::make('content')
->extraAttributes(['data-lazy' => 'true']),
Check the Database
Run php artisan tinker and inspect a record:
$post = App\Models\Post::find(1);
$post->getTranslations('title'); // Should return ['en' => '...', 'de' => '...']
Log Locale Data
Add a temporary dump in your AppServiceProvider:
public function boot()
{
\Log::info('Translatable locales:', config('translatable.locales'));
}
Clear Cached Views If translations don’t appear:
php artisan view:clear
php artisan cache:clear
Custom Styling
Override the inline container’s Blade template in resources/views/vendor/filament-plugin-translatable-inline/translatable.blade.php:
<div class="custom-translation-container">
@foreach($locales as $locale)
<div class="locale-field">
{{ $field->getLabel($locale) }}
{{ $field->getField($locale) }}
</div>
@endforeach
</div>
Add Validation Extend the component to validate translations per locale:
Translatable::make('title')
->rules([
'en' => 'required|min:3',
'de' => 'nullable|max:50',
]),
Localization of UI Text Publish and translate the plugin’s language lines:
php artisan vendor:publish --tag=filament-plugin-translatable-inline-lang
Then add translations to resources/lang/{locale}/filament-plugin-translatable-inline.php.
Hook into Translation Events
Listen for translatable.saving or translatable.saved events (Spatie’s events) to log or modify translations:
use Spatie\Translatable\Events\TranslatableSaved;
TranslatableSaved::listen(function ($model, $translations) {
\Log::info("Translations saved for {$model->id}:", $translations);
});
Support for Filament Panels If using multiple panels, ensure the plugin is registered in each panel’s service provider:
Filament::registerPlugin(
TranslatablePlugin::make()->locales(['en', 'fr']),
panel: 'admin' // Target specific panel
);
How can I help you explore Laravel packages today?