Filament Translate Field is a library for Filament CMS that simplifies managing multiple translatable fields in different languages.
You can install the package via composer:
composer require solution-forest/filament-translate-field
- There's a conflict with the Translatable trait in the filament/spatie-laravel-translatable-plugin when used on the EditPage. Avoid using Translatable while editing.
- Define translatable fields in your model using a translatable package (e.g., "spatie/laravel-translatable" or "dimsav/laravel-translatable").
- Configure translatable fields in the model's $translatable property.
For version before 1.x.x
To add a plugin to a panel, you must include it in the configuration file using the plugin() method:
use SolutionForest\FilamentTranslateField\FilamentTranslateFieldPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugin(FilamentTranslateFieldPlugin::make());
}
To set up the locales that can be used to translate content, you can pass an array of locales to the `defaultLocales()` plugin method:
use SolutionForest\FilamentTranslateField\FilamentTranslateFieldPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugin(
FilamentTranslateFieldPlugin::make()
->defaultLocales(['en', 'es', 'fr']),
);
}
For version equal or after 1.x.x
Since the plugin after 1.x.x is a standalone plugin, which does not need to be related to Filament Panel, so you need to globally set it up in the config file or use the boot method in `AppServiceProvider`.
To set up the locales that can be used to translate content, you can pass an array of locales to the `defaultLocales()` plugin method:
use SolutionForest\FilamentTranslateField\Facades\FilamentTranslateField;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
FilamentTranslateField::defaultLocales(['en', 'es', 'fr']);
}
}
Or, you can publish configuration file config/filament-translate-field.php
and add default locales on locales
:
return [
'locales' => ['en', 'es', 'fr'],
];
By using the Translate
component, you can easily configure your form fields to support multiple languages and provide translations for each locale.
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\RichEditor;
use SolutionForest\FilamentTranslateField\Forms\Component\Translate;
Translate::make()
->schema([
// Your form fields here
])
By default, the translatable locales can be set globally for all translate form component in the plugin configuration. Alternatively, you can customize the translatable locales for a particular resource by overriding the locales()
method in Translate
class:
use SolutionForest\FilamentTranslateField\Forms\Component\Translate;
Translate::make()->locales(['en', 'es'])
You have the flexibility to customize the translate label for each field in each locale. You can use the fieldTranslatableLabel()
method to provide custom labels based on the field instance and the current locale.
use SolutionForest\FilamentTranslateField\Forms\Component\Translate;
Translate::make()
->schema([
// Fields
])
->fieldTranslatableLabel(fn ($field, $locale) => __($field->getName(), locale: $locale))
If you simply want to add a prefix or suffix locale label to the form field, you can use the prefixLocaleLabel()
or suffixLocaleLabel()
method. This makes it easier for users to identify the language associated with each field.
use SolutionForest\FilamentTranslateField\Forms\Component\Translate;
Translate::make()
->schema([
// Fields
])
->prefixLocaleLabel()
->suffixLocaleLabel()
`prefixLocaleLabel:
suffixLocaleLabel
:
By default, the prefix/suffix locale display name is generated by locale code and enclosed in parentheses, "()". You may customize this using the preformLocaleLabelUsing()
method:
use SolutionForest\FilamentTranslateField\Forms\Component\Translate;
Translate::make()
->preformLocaleLabelUsing(fn (string $locale, string $label) => "[{$label}]");
Additionally, if you need to access the current form field instance, you can inject the $field
parameter into the callback functions. This allows you to perform specific actions or conditions based on the field being processed.
use Filament\Forms\Components\Component;
use SolutionForest\FilamentTranslateField\Forms\Component\Translate;
Translate::make()
// ...
->prefixLocaleLabel(function(Component $field) {
// need return boolean value
return $field->getName() == 'title';
})
->suffixLocaleLabel(function(Component $field) {
// need return boolean value
return $field->getName() == 'title';
})
You may add actions before each container of children components using the actions()
method:
use Filament\Forms\Components\Actions\Action;
use SolutionForest\FilamentTranslateField\Forms\Component\Translate;
Translate::make()
->actions([
Action::make('fillDumpTitle')
])
If have multiple
Translate
components and have action in each component, please add id toTranslate
component byid()
method
If you wish to access the locale that have been passed to the action, define an $arguments
parameter and get the value of locale
from $arguments
:
use Filament\Forms\Components\Actions\Action;
use SolutionForest\FilamentTranslateField\Forms\Component\Translate;
Translate::make()
->actions([
Action::make('fillDumpTitle')
->action(function (array $arguments) {
$locale = $arguments['locale'];
// ...
})
])
If you wish to access the current locale instance for the field, define a $locale
parameter:
use Filament\Forms\Components\TextInput;
use SolutionForest\FilamentTranslateField\Forms\Component\Translate;
Translate::make()
->schema(fn (string $locale) => [TextInput::make('title')->required($locale == 'en')])
By default, translate component and their content are wrapped in a container styled as a card. You may remove the styled container using contained()
:
use SolutionForest\FilamentTranslateField\Forms\Component\Translate;
Translate::make()
->contained(false)
The exclude
feature allows you to specify fields that you don't want to be included in the translation process. This can be useful for fields that contain dynamic content or that shouldn't be translated into other languages.
use SolutionForest\FilamentTranslateField\Forms\Component\Translate;
Translate::make([
Forms\Components\TextInput::make('title'),
Forms\Components\TextInput::make('description'),
])
->exclude(['description'])
Without exclude
{
"title": {
"en": "Dump",
"es": "Dump",
"fr": "Dump"
},
"description": {
"en": null,
"es": null,
"fr": null
}
}
With Exclude
{
"title": {
"en": "Dump",
"es": "Dump",
"fr": "Dump"
},
"description": null
}
To publish the views, use:
php artisan vendor:publish --provider="SolutionForest\\FilamentTranslateField\\FilamentTranslateFieldServiceProvider" --tag="filament-translate-field-views"
To publish the configuration file, use:
php artisan vendor:publish --provider="SolutionForest\\FilamentTranslateField\\FilamentTranslateFieldServiceProvider" --tag="filament-translate-field-config"
FIlament.Translate.Field.Demo-2.mp4
In Filament panel:
use SolutionForest\FilamentTranslateField\FilamentTranslateFieldPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugin(FilamentTranslateFieldPlugin::make()
->defaultLocales(['en', 'es', 'fr'])
);
}
In app/Filament/Resources/NewsResource.php:
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\RichEditor;
use Filament\Resources\Resource;
use SolutionForest\FilamentTranslateField\Forms\Component\Translate;
class NewsResource extends Resource
{
// ...
public static function form(Form $form): Form
{
return $form
->schema([
Translate::make()
->columnSpanFull()
->columns(2)
->schema([
TextInput::make('title')->required(),
Textarea::make('short_desc'),
RichEditor::make('description')->columnSpanFull(),
])
->fieldTranslatableLabel(fn ($field, $locale) => __($field->getName(), locale: $locale))
->actions([
Forms\Components\Actions\Action::make('testy')
->label("Fill dump title")
->visible(fn ($arguments) => $arguments['locale'] == 'en')
->action(function ($set, $arguments) {
$locale = $arguments['locale'] ?? null;
if (! $locale) {
return;
}
$set("title.$locale", fake()->text(50));
})
]),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\ColumnGroup::make('Data')
->columns([
Tables\Columns\TextColumn::make('title')
->getStateUsing(fn ($record) => new HtmlString(collect($record->title)
->map(fn ($state, $locale) => <<<Html
<div class="flex gap-2">
<div class="text-sm text-gray-500">$locale</div>
<div>$state</div>
</div>
Html)
->implode(''))),
Tables\Columns\TextColumn::make('short_desc')
->getStateUsing(fn ($record) => new HtmlString(collect($record->short_desc)
->map(fn ($state, $locale) => <<<Html
<div class="flex gap-2">
<div class="text-sm text-gray-500">$locale</div>
<div>$state</div>
</div>
Html)
->implode(''))),
Tables\Columns\TextColumn::make('description')
->getStateUsing(fn ($record) => new HtmlString(collect($record->description)
->map(fn ($state, $locale) => <<<Html
<div class="flex gap-2">
<div class="text-sm text-gray-500">$locale</div>
<div>$state</div>
</div>
Html)
->implode(''))),
]),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
]);
}
// ...
}
In app/Models/News.php:
use Illuminate\Database\Eloquent\Model;
use Spatie\Translatable\HasTranslations;
class News extends Model
{
use HasTranslations;
// ...
protected $guarded = ['id'];
public $translatable = ['title', 'short_desc', 'description'];
public $casts = [
'title' => 'json',
'short_desc' => 'json',
'description' => 'json',
];
// ...
}
In resources/lang/en.json:
{
"title": "Title",
"short_desc": "Short description",
"description": "Description"
}
In resources/lang/es.json:
{
"title": "Título",
"short_desc": "Breve descripción",
"description": "Descripción"
}
In resources/lang/fr.json:
{
"title": "Titre",
"short_desc": "Brève description",
"description": "Description"
}
In the given example, when you save the model, the data will be stored in the following format:
{
"id": 1,
"title": {
"en": "Dump",
"es": "Dump",
"fr": "Dump"
},
"short_desc": {
"en": null,
"es": null,
"fr": null
},
"description": {
"en": null,
"es": null,
"fr": null
}
}
composer test
See the CHANGELOG for more information on what has changed recently.
See CONTRIBUTING for details.
If you discover any security related issues, please email info+package@solutionforest.net instead of using the issue tracker.
- [Carly]
- All Contributors
Filament Tree is open-sourced software licensed under the MIT license.
Solution Forest Web development agency based in Hong Kong. We help customers to solve their problems. We Love Open Soruces.
We have built a collection of best-in-class products:
- VantagoAds: A self manage Ads Server, Simplify Your Advertising Strategy.
- GatherPro.events: A Event Photos management tools, Streamline Your Event Photos.
- Website CMS Management: Website CMS Management - Filament CMS Plugin
- Filaletter: Filaletter - Filament Newsletter Plugin