如何用filament/spatie-laravel-translatable-plugin实现多语言编辑器与表格展示
Laravel Filament 2.x 多语言相关问题解决方案
核心问题
1. 创建支持动态语言列表的多语言编辑器(保存至JSON字段)
先确保模型集成Spatie Translatable:
// app/Models/Banner.php use Spatie\Translatable\HasTranslations; use Illuminate\Database\Eloquent\Model; class Banner extends Model { use HasTranslations; // 定义需要翻译的字段 public $translatable = ['title', 'content']; // 字段类型转换 protected $casts = [ 'title' => 'array', 'content' => 'array', ]; }
在资源的form方法中,基于系统配置的动态语言列表生成输入框:
// app/Filament/Resources/BannerResource.php use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Textarea; use Filament\Forms\Form; public static function form(Form $form): Form { // 从配置获取动态语言列表(需预先在config/app.php中定义locales数组) $locales = config('app.locales'); $fallbackLocale = config('app.fallback_locale'); return $form ->schema([ // 其他非翻译字段... // 生成标题的多语言输入框 ...collect($locales)->map(function ($locale) use ($fallbackLocale) { return TextInput::make("title.$locale") ->label(__('Title') . " ($locale)") ->required($locale === $fallbackLocale); // 默认语言必填 })->toArray(), // 生成内容的多语言输入框 ...collect($locales)->map(function ($locale) { return Textarea::make("content.$locale") ->label(__('Content') . " ($locale)"); })->toArray(), ]); }
编辑时每个语言的输入值会自动保存到JSON字段,Filament会处理数组与JSON的转换。
2. 表格中显示默认语言的标签
在资源的table方法中,直接调用模型的翻译字段即可(Spatie Translatable默认返回 fallback 语言值):
// app/Filament/Resources/BannerResource.php use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; public static function table(Table $table): Table { return $table ->columns([ // 其他列... TextColumn::make('title') ->label(__('Title')), TextColumn::make('content') ->label(__('Content')) ->limit(50), ]); }
如果需要手动指定语言,可使用getStateUsing:
TextColumn::make('title') ->label(__('Title')) ->getStateUsing(function (Banner $record) { return $record->getTranslation('title', config('app.fallback_locale')); });
附加问题解答
1. 编辑模式下获取当前记录
Filament 2.x中,form方法内可通过$form->getRecord()获取,或在字段回调中直接注入:
// 方式1:在form方法开头获取 public static function form(Form $form): Form { $record = $form->getRecord(); if ($record) { \Log::info("当前编辑记录ID:{$record->id}"); } // ... } // 方式2:在字段回调中获取 public static function form(Form $form): Form { return $form ->schema([ TextInput::make('title') ->afterStateHydrated(function (TextInput $component, $state, Banner $record) { \Log::info("当前记录标题:{$record->title}"); }), ]); }
2. EditBanner.php的类似mutateFormDataBeforeCreate方法
存在对应方法mutateFormDataBeforeSave,用于编辑前修改数据:
// app/Filament/Resources/BannerResource/Pages/EditBanner.php use App\Filament\Resources\BannerResource; use Filament\Resources\Pages\EditRecord; class EditBanner extends EditRecord { protected static string $resource = BannerResource::class; protected function mutateFormDataBeforeSave(array $data): array { // 示例:修剪默认语言标题的空格 $fallbackLocale = config('app.fallback_locale'); $data['title'][$fallbackLocale] = trim($data['title'][$fallbackLocale]); return $data; } }
3. 字段级内联语言切换器(无需全局LocaleSwitcher)
使用filament/spatie-laravel-translatable-plugin提供的TranslatableInput组件,实现字段独立的语言切换:
// app/Filament/Resources/BannerResource.php use Filament\Forms\Components\SpatieTranslatable\TranslatableInput; public static function form(Form $form): Form { return $form ->schema([ TranslatableInput::make('title') ->label(__('Title')) ->locales(config('app.locales')) // 动态语言列表 ->required(), TranslatableInput::make('content') ->label(__('Content')) ->locales(config('app.locales')) ->type('textarea'), ]); }
每个字段会自带语言切换按钮,无需切换后台全局语言即可编辑对应语言内容。
4. 解决getLocaleInputs返回Closure的问题
你的代码中getLocaleInputs返回的是匿名函数但未执行,正确做法是直接传入record参数调用:
// app/Filament/Resources/BannerResource.php public static function form(Form $form): Form { $record = $form->getRecord(); if ($record) { $localeInputs = (new self)->getLocaleInputs($record); \Log::info($localeInputs); } // ... } protected function getLocaleInputs(Banner $record) { // 这里直接返回record或处理你的业务逻辑 return $record; }
内容的提问来源于stack exchange,提问作者mstdmstd
相关产品推荐
相关产品推荐

