You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 19:43:18