ezappslab / filament-translatable
Filament Translatable
Package info
github.com/ezappslab/filament-translatable
pkg:composer/ezappslab/filament-translatable
Requires
- php: ^8.2 || ^8.3 || ^8.4 || ^8.5
- filament/filament: ^5.0
- spatie/laravel-package-tools: ^1.93
- spatie/laravel-translatable: ^6.11.4 || ^6.13
Requires (Dev)
- larastan/larastan: ^v3.9
- laravel/pint: ^v1.25
- orchestra/testbench: ^10.9 || ^11.0
- pestphp/pest: ^4.1
- pestphp/pest-plugin: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- pestphp/pest-plugin-livewire: ^4.1
- pestphp/pest-plugin-mutate: ^4.0
This package is not auto-updated.
Last update: 2026-04-28 20:01:28 UTC
README
Filament Translatable adds locale-aware resource pages for Filament panels that use spatie/laravel-translatable.
The package provides:
- A Filament panel plugin for configuring available locales.
- Page concerns for create, edit, list, and view resource pages.
- A locale selector header action.
- A content driver that reads, writes, displays, and searches the active locale of Spatie translatable attributes.
Requirements
- PHP 8.2 or higher.
- Filament 5.
spatie/laravel-translatable6.11.4 or higher.
Installation
Install the package with Composer:
composer require ezappslab/filament-translatable
Run the install command:
php artisan filament-translatable:install
The installer can publish the configuration file and register the package service provider in your application.
Configuration
Configure the locales that should be available in your Filament panel:
use Infinity\FilamentTranslatable\Enums\Locale; return [ 'locales' => [ Locale::English, Locale::Bulgarian, Locale::German, ], 'fallback_locale' => Locale::English, ];
You can also configure locales directly when registering the plugin on a panel:
use Filament\Panel; use Filament\PanelProvider; use Infinity\FilamentTranslatable\Enums\Locale; use Infinity\FilamentTranslatable\FilamentTranslatablePlugin; class AdminPanelProvider extends PanelProvider { public function panel(Panel $panel): Panel { return $panel ->default() ->id('admin') ->path('admin') ->plugin( FilamentTranslatablePlugin::make() ->locales([ Locale::English, Locale::Bulgarian, ]) ->fallbackLocale(Locale::English) ); } }
Preparing Models
Use Spatie's HasTranslations trait on any model that has translated attributes.
The translated columns should be JSON-compatible columns in your database.
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Spatie\Translatable\HasTranslations; class Product extends Model { use HasTranslations; public array $translatable = [ 'name', 'description', ]; protected $fillable = [ 'name', 'description', 'is_active', ]; protected function casts(): array { return [ 'name' => 'array', 'description' => 'array', 'is_active' => 'boolean', ]; } }
Example migration columns:
$table->json('name'); $table->json('description'); $table->boolean('is_active')->default(true);
Using Translatable Resource Pages
Add the matching concern to each Filament resource page and add the locale selector to the page header actions.
List Page
namespace App\Filament\Resources\ProductResource\Pages; use App\Filament\Resources\ProductResource; use Filament\Resources\Pages\ListRecords; use Infinity\FilamentTranslatable\Actions\SelectLocaleAction; use Infinity\FilamentTranslatable\Resources\Pages\Concerns\HasTranslatableListRecords; class ListProducts extends ListRecords { use HasTranslatableListRecords; protected static string $resource = ProductResource::class; protected function getHeaderActions(): array { return [ SelectLocaleAction::make(), ]; } }
Create Page
namespace App\Filament\Resources\ProductResource\Pages; use App\Filament\Resources\ProductResource; use Filament\Resources\Pages\CreateRecord; use Infinity\FilamentTranslatable\Actions\SelectLocaleAction; use Infinity\FilamentTranslatable\Resources\Pages\Concerns\HasTranslatableCreateRecord; class CreateProduct extends CreateRecord { use HasTranslatableCreateRecord; protected static string $resource = ProductResource::class; protected function getHeaderActions(): array { return [ SelectLocaleAction::make(), ]; } }
Edit Page
namespace App\Filament\Resources\ProductResource\Pages; use App\Filament\Resources\ProductResource; use Filament\Resources\Pages\EditRecord; use Infinity\FilamentTranslatable\Actions\SelectLocaleAction; use Infinity\FilamentTranslatable\Resources\Pages\Concerns\HasTranslatableEditRecord; class EditProduct extends EditRecord { use HasTranslatableEditRecord; protected static string $resource = ProductResource::class; protected function getHeaderActions(): array { return [ SelectLocaleAction::make(), ]; } }
View Page
namespace App\Filament\Resources\ProductResource\Pages; use App\Filament\Resources\ProductResource; use Filament\Resources\Pages\ViewRecord; use Infinity\FilamentTranslatable\Actions\SelectLocaleAction; use Infinity\FilamentTranslatable\Resources\Pages\Concerns\HasTranslatableViewRecord; class ViewProduct extends ViewRecord { use HasTranslatableViewRecord; protected static string $resource = ProductResource::class; protected function getHeaderActions(): array { return [ SelectLocaleAction::make(), ]; } }
Resource Example
Once the page concerns are installed, build your resource form and table normally. The package resolves translatable fields through the currently selected locale.
namespace App\Filament\Resources; use App\Filament\Resources\ProductResource\Pages; use App\Models\Product; use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; use Filament\Resources\Resource; use Filament\Schemas\Schema; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; class ProductResource extends Resource { protected static ?string $model = Product::class; public static function form(Schema $schema): Schema { return $schema->components([ TextInput::make('name') ->required(), Textarea::make('description') ->required(), Toggle::make('is_active'), ]); } public static function table(Table $table): Table { return $table->columns([ TextColumn::make('name') ->searchable(), TextColumn::make('description'), IconColumn::make('is_active') ->boolean(), ]); } public static function getPages(): array { return [ 'index' => Pages\ListProducts::route('/'), 'create' => Pages\CreateProduct::route('/create'), 'view' => Pages\ViewProduct::route('/{record}'), 'edit' => Pages\EditProduct::route('/{record}/edit'), ]; } }
When a user selects Bulgarian, name and description are read from and written to
the bg translation values. Non-translatable attributes, such as is_active, are
handled as normal model attributes.
Relationship Fields
Translatable fields inside Filament relationship sections are also supported. Mark the related model attributes as translatable and use the same page concerns on the parent resource pages.
use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; use Filament\Schemas\Components\Section; use Filament\Schemas\Schema; public static function form(Schema $schema): Schema { return $schema->components([ TextInput::make('name') ->required(), TextInput::make('email') ->email() ->required(), Section::make('Profile') ->relationship('profile') ->schema([ TextInput::make('headline') ->required(), TextInput::make('biography') ->required(), Toggle::make('is_public'), ]), ]); }
In this example, profile.headline and profile.biography can be translated per
locale when the Profile model uses Spatie's HasTranslations trait.
Relation Managers
Use HasTranslatableRelationManager on Filament relation managers that manage
models with Spatie translatable attributes. Add SelectLocaleAction to the table
header actions so users can switch the active locale.
namespace App\Filament\Resources\UserResource\RelationManagers; use Filament\Actions\CreateAction; use Filament\Actions\EditAction; use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; use Filament\Resources\RelationManagers\RelationManager; use Filament\Schemas\Schema; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; use Infinity\FilamentTranslatable\Actions\SelectLocaleAction; use Infinity\FilamentTranslatable\Resources\RelationManagers\Concerns\HasTranslatableRelationManager; class ProductsRelationManager extends RelationManager { use HasTranslatableRelationManager; protected static string $relationship = 'products'; public function form(Schema $schema): Schema { return $schema->components([ TextInput::make('name') ->required(), Textarea::make('description') ->required(), ]); } public function table(Table $table): Table { return $table ->columns([ TextColumn::make('name') ->searchable(), TextColumn::make('description'), ]) ->headerActions([ SelectLocaleAction::make(), CreateAction::make(), ]) ->recordActions([ EditAction::make(), ]); } }
The relation manager uses its own active locale session key, scoped by panel, page, and relation manager class.
Scripts
composer lint: Run Pint and PHPStan.composer test: Run Pest tests.composer build: Build workbench assets.composer serve: Serve the workbench application.
Documentation
For more detailed information about the included tools, see docs/tooling.md.