afsakar/filament-translate-action
Filament Translate Action adds a ready-made translation action to Filament forms, letting editors translate model fields between locales via configurable drivers and manage multilingual content without leaving the admin panel.
afsakar/filament-translate-action adds a translate button to Filament form fields so editors can machine-translate a value from a source locale into the other locales configured for the panel, without leaving the resource form.
Minimal setup:
composer require afsakar/filament-translate-actionphp artisan vendor:publish --tag="filament-translate-action-config"config/filament-translate-action.php.use Afsakar\FilamentTranslateAction\Actions\TranslateAction;
TextInput::make('title')
->suffixAction(TranslateAction::make('translate'))
First real use case: a PostResource with spatie/laravel-translatable on title and body. Open the Turkish tab, write the copy, hit the translate action, and the action fills the remaining locale entries so a human can review them.
Where to look first: the published config (the locale list is the thing you will change most), the README example for the exact action-builder methods in your installed version, and composer.json for the Filament major version constraint — v1.2.x targets the Filament v3/v4 era, and mixing majors produces confusing Livewire mount errors rather than a clean composer conflict.
One action per field, driven by shared config. Don't hardcode locales at every call site; read them from config (or a LanguageSwitcher-style helper) so the panel's locale list and the action's target list can't drift apart.
Per-locale tabs, source first. Put each locale in a Tabs component (->persistTabInQueryString()), source language as the first tab, and place the translate action on the source tab's fields. Editors translate once, then review each tab — this mirrors how translation work actually flows.
Compose a resource-level field helper. Wrap the repeated ->suffixAction(TranslateAction::make(...)) into a small static method or custom field class in your app. When you have 15 translatable fields across 6 resources, this is the difference between a one-line change and a scavenger hunt.
Translate-then-review, never translate-then-publish. Treat the output as a draft: keep the action non-destructive where possible (write only into empty target locales on edit forms), and let validation run again after the state update so length/format rules apply to machine output too.
Pair with spatie/laravel-translatable. The natural integration is a translatable model plus one JSON per attribute; the action writes into the locale keys. For plain per-locale columns (title_en, title_tr), attach the action to each column and point it at the source field explicitly.
Queue long content. For body/RichEditor fields, keep the interactive action for short fields (titles, taglines, SEO meta) and dispatch a job for long copy, then refresh the form. Inline translation of a 6k-character article will stall the Livewire round trip.
Custom provider. If Google is not acceptable (cost, compliance, quality), bind your own translator implementation in a service provider and point the config at it — keep the provider behind an interface so swapping to DeepL is a config change, not a code rewrite.
afterStateUpdated for every keystroke.pt and pt-BR, zh-CN and zh-TW. Filament locale keys don't always match; map them explicitly in config or you get wrong-language output that looks plausible — the worst kind of bug.php artisan config:cache after touching the locale list, or your panel and the action disagree about which locales exist.maxLength. Re-validate and surface errors on the target tabs, otherwise the form fails on save with a message pointing at a tab the editor never opened.lang files — check lang/vendor/filament-translate-action after publishing.->targetLanguages([...]) everywhere; bind a custom translator in a service provider for provider swaps.How can I help you explore Laravel packages today?