Filament Translatable
#Filament Translatable
Enhanced Filament plugin for spatie/laravel-translatable with translation status indicators, locale flags, and improved developer experience.
#Version Compatibility
| Branch | Filament | PHP | Laravel | Tailwind | Livewire | Install |
|---|---|---|---|---|---|---|
| 1.x | v3 | ^8.1 | 10+ | 3.x | 3.x | "^1.0" |
| 2.x | v4 | ^8.2 | 11+ | 4.x | 3.x | "^2.0" |
| 3.x | v5 | ^8.2 | 11.28+ | 4.x | 4.x | "^3.0" |
You are viewing the documentation for branch 3.x (Filament v5).
#Features
- Locale Switching - Switch between locales on Create, Edit, List, View, and Manage pages
- Translation Status Column - Visual table column showing translation completeness per locale with colored badges
- Translation Status Trait - Introspect translation status (complete/partial/empty) and completeness percentage
- Locale Flags - Emoji flag support with configurable display (flag+label, flag only, label only)
- Unified DX Trait -
InteractsWithTranslationsfor less boilerplate - SQLite Search - JSON search support for SQLite (in addition to MySQL and PostgreSQL)
- RelationManager Support - Independent locale management for relation managers
- 30+ Built-in Flags - Pre-configured emoji flags for the most common locales
#Installation
You can install the package via composer:
composer require jeffersongoncalves/filament-translatable:"^3.0"
Optionally publish the config:
php artisan vendor:publish --tag="filament-translatable-config"
#Setup
#1. Configure your Model
Your model must use Spatie's HasTranslations trait:
use Illuminate\Database\Eloquent\Model; use Spatie\Translatable\HasTranslations; class Post extends Model { use HasTranslations; protected $fillable = ['title', 'content', 'slug']; public array $translatable = ['title', 'content']; }
Translatable columns must use json type in your migration:
Schema::create('posts', function (Blueprint $table) { $table->id(); $table->json('title'); $table->json('content'); $table->string('slug'); // non-translatable fields use regular column types $table->timestamps(); });
#2. Register the Plugin
Add the plugin to your PanelProvider:
use JeffersonGoncalves\FilamentTranslatable\FilamentTranslatablePlugin; public function panel(Panel $panel): Panel { return $panel ->plugins([ FilamentTranslatablePlugin::make() ->defaultLocales(['en', 'pt_BR', 'es']), ]); }
#3. Add Translatable to your Resource
use JeffersonGoncalves\FilamentTranslatable\Resources\Concerns\Translatable; class PostResource extends Resource { use Translatable; // ... }
#4. Add Translatable to Pages
Each page type needs its own trait and the LocaleSwitcher header action:
use JeffersonGoncalves\FilamentTranslatable\Actions\LocaleSwitcher; use JeffersonGoncalves\FilamentTranslatable\Resources\Pages\CreateRecord; use JeffersonGoncalves\FilamentTranslatable\Resources\Pages\EditRecord; use JeffersonGoncalves\FilamentTranslatable\Resources\Pages\ListRecords; class CreatePost extends CreateRecord { use CreateRecord\Concerns\Translatable; protected function getHeaderActions(): array { return [LocaleSwitcher::make()]; } } class EditPost extends EditRecord { use EditRecord\Concerns\Translatable; protected function getHeaderActions(): array { return [LocaleSwitcher::make()]; } } class ListPosts extends ListRecords { use ListRecords\Concerns\Translatable; protected function getHeaderActions(): array { return [LocaleSwitcher::make()]; } }
Additional page types are also supported:
use JeffersonGoncalves\FilamentTranslatable\Resources\Pages\ViewRecord; use JeffersonGoncalves\FilamentTranslatable\Resources\Pages\ManageRecords; // ViewRecord class ViewPost extends ViewRecord { use ViewRecord\Concerns\Translatable; protected function getHeaderActions(): array { return [LocaleSwitcher::make()]; } } // ManageRecords (simple resource) class ManagePosts extends ManageRecords { use ManageRecords\Concerns\Translatable; protected function getHeaderActions(): array { return [LocaleSwitcher::make()]; } }
#Translation Status Column
Show translation completeness per locale in your table with colored badges:
use JeffersonGoncalves\FilamentTranslatable\Tables\Columns\TranslationStatusColumn; public static function table(Table $table): Table { return $table->columns([ TextColumn::make('title'), TranslationStatusColumn::make('translations') ->showPercentage() // show completion percentage ->onlyShowMissing() // hide locales that are fully translated ->showFlags() // show emoji flags next to locale labels ->locales(['en', 'pt_BR', 'es']), // override plugin locales ]); }
Each locale displays a colored badge indicating its translation status:
- Success (green) - All translatable attributes are filled
- Warning (yellow) - Some translatable attributes are filled
- Danger (red) - No translatable attributes are filled
#Translation Status Trait
Use HasTranslationStatus on any page to check translation status programmatically:
use JeffersonGoncalves\FilamentTranslatable\Concerns\HasTranslationStatus; class EditPost extends EditRecord { use EditRecord\Concerns\Translatable; use HasTranslationStatus; }
Available methods:
// Get status per locale: 'complete', 'partial', or 'empty' $this->getTranslationStatus($record); // => ['en' => 'complete', 'pt_BR' => 'partial', 'fr' => 'empty'] // Get completeness percentage per locale (0-100) $this->getTranslationCompleteness($record); // => ['en' => 100, 'pt_BR' => 50, 'fr' => 0] // Get locales that have at least one translated attribute $this->getTranslatedLocales($record); // => ['en', 'pt_BR']
#Locale Flags
The plugin ships with 30+ built-in emoji flags. Configure them per locale in the plugin or via config:
FilamentTranslatablePlugin::make() ->defaultLocales(['en', 'pt_BR', 'es']) ->localeFlags([ 'en' => "\u{1F1FA}\u{1F1F8}", 'pt_BR' => "\u{1F1E7}\u{1F1F7}", 'es' => "\u{1F1EA}\u{1F1F8}", ]) ->flagDisplay('flag_and_label'), // 'flag_and_label' | 'flag_only' | 'label_only'
Built-in flags include: en, pt_BR, pt, es, fr, de, it, nl, ja, ko, zh, ru, ar, hi, tr, pl, uk, sv, da, no, fi, cs, el, ro, hu, th, vi, id, ms, he.
#Custom Locale Labels
Override how locale names are displayed:
FilamentTranslatablePlugin::make() ->defaultLocales(['en', 'pt_BR']) ->getLocaleLabelUsing(fn (string $locale) => match ($locale) { 'en' => 'English', 'pt_BR' => 'Portugues', default => null, // falls back to locale_get_display_name() }),
#RelationManager
Relation managers have independent locale management using a dedicated LocaleSwitcher:
use JeffersonGoncalves\FilamentTranslatable\Resources\RelationManagers\Concerns\Translatable; use JeffersonGoncalves\FilamentTranslatable\Tables\Actions\LocaleSwitcher; class CommentsRelationManager extends RelationManager { use Translatable; protected function getHeaderActions(): array { return [LocaleSwitcher::make()]; } }
Note: Relation managers use
JeffersonGoncalves\FilamentTranslatable\Tables\Actions\LocaleSwitcher(fromTables\Actions), while pages useJeffersonGoncalves\FilamentTranslatable\Actions\LocaleSwitcher(fromActions).
#InteractsWithTranslations
For less boilerplate, you can use the unified InteractsWithTranslations trait instead of page-specific traits:
use JeffersonGoncalves\FilamentTranslatable\Concerns\InteractsWithTranslations; class EditPost extends EditRecord { use InteractsWithTranslations; // Automatically detects the page type and provides // getTranslatableLocales() and locale management }
#Configuration
// config/filament-translatable.php return [ /* |-------------------------------------------------------------------------- | Locale Flags |-------------------------------------------------------------------------- | | Map of locale codes to emoji flags. Used by the LocaleSwitcher and | TranslationStatusColumn to display visual locale indicators. | */ 'locale_flags' => [ 'en' => "\u{1F1FA}\u{1F1F8}", // US 'pt_BR' => "\u{1F1E7}\u{1F1F7}", // BR 'es' => "\u{1F1EA}\u{1F1F8}", // ES 'fr' => "\u{1F1EB}\u{1F1F7}", // FR 'de' => "\u{1F1E9}\u{1F1EA}", // DE // ... 25+ more built-in ], /* |-------------------------------------------------------------------------- | Flag Display Format |-------------------------------------------------------------------------- | | Controls how locale labels are displayed in the LocaleSwitcher. | Options: 'flag_and_label', 'flag_only', 'label_only' | */ 'flag_display' => 'flag_and_label', /* |-------------------------------------------------------------------------- | Translation Status Colors |-------------------------------------------------------------------------- | | Filament color names used by the TranslationStatusColumn badges. | */ 'status_colors' => [ 'complete' => 'success', 'partial' => 'warning', 'empty' => 'danger', ], ];
#Migration from filament/spatie-laravel-translatable-plugin
This package is an enhanced fork of Filament's official translatable plugin. Migration is straightforward:
1. Replace the package:
composer remove filament/spatie-laravel-translatable-plugin
composer require jeffersongoncalves/filament-translatable:"^3.0"
2. Update PanelProvider imports:
// Before use Filament\SpatieLaravelTranslatablePlugin; // After use JeffersonGoncalves\FilamentTranslatable\FilamentTranslatablePlugin;
3. Update Resource and Page imports:
Replace Filament\Resources\ with JeffersonGoncalves\FilamentTranslatable\Resources\ in all translatable traits.
4. Update LocaleSwitcher imports:
// Before use Filament\Actions\LocaleSwitcher; // After (for pages) use JeffersonGoncalves\FilamentTranslatable\Actions\LocaleSwitcher; // After (for relation managers) use JeffersonGoncalves\FilamentTranslatable\Tables\Actions\LocaleSwitcher;
5. Enjoy the new features - Translation Status Column, locale flags, and status introspection are ready to use.
#Testing
composer test
#Changelog
Please see Releases for more information on what has changed recently.
#Security Vulnerabilities
Please see SECURITY for details.
#Credits
#License
The MIT License (MIT). Please see License File for more information.