bambolee-digital/filament-translate
Filament Translate is a Filament plugin for managing multilingual content and translations from your admin panel. It helps streamline locale switching, translation editing, and localization workflows in Laravel apps built with Filament.
bambolee-digital/filament-translate adds per-locale translation UI to Filament resources, so you can translate a record's fields into each configured locale without leaving the admin panel.
Minimal path:
composer require bambolee-digital/filament-translatephp artisan vendor:publish --tag="filament-translate-config". This is where you set locales, the translation driver/credentials, and which field types map to which Filament form components. Look here first — most "why is my field blank / not editable" issues are config, not code.spatie/laravel-translatable — the package reads/writes locale-keyed JSON attributes rather than a separate translations table).->plugin(FilamentTranslatePlugin::make()) in your PanelProvider.Start with one resource and one model. The plugin is thin over your existing form schema, so a bad first model (heavy relations, custom casts, non-translatable columns) will look like a plugin bug when it's a data-shape problem.
Field-type mapping is the core mental model. The plugin renders translation inputs by inspecting the original field type and matching it to a Filament component. As of 1.0.4, MarkdownEditor is supported alongside the existing text/textarea/rich-editor handling. This means long-form content stored as markdown can now be translated and edited in-panel with a proper markdown toolbar instead of being flattened into a plain textarea. If you have a resource with MarkdownEditor::make('body'), upgrade and the translation form should render a matching editor with no schema changes.
Translate-on-save vs. explicit action. Use the explicit translate action for editorial workflows (human reviews machine output), and reserve driver-based auto-translation for content where approximate output is acceptable — marketing copy, meta descriptions, category labels. Don't wire auto-translation into beforeSave on a model with financial or legal text.
Locale-driven UI. Drive the visible locales from config, not from hardcoded lists in resources. When a locale is added, you want the translation form to pick it up automatically. Pair this with a locale switcher in the panel so editors can spot missing translations quickly.
Partial-translation workflow. Treat the source locale as authoritative and let other locales be nullable. Add a table column or badge indicating which locales are complete — this is usually a small custom column reading the raw JSON attribute, and it's the single highest-value addition most projects make on top of the plugin.
Integration with existing form schemas. Because the translation form is derived from your resource schema, keep translation-relevant fields in a consistent, flat section. Deeply nested Grid/Section/Repeater structures are where derived-form approaches tend to degrade; if a field doesn't appear in the translation form, flatten it first before assuming a plugin limitation.
->formatStateUsing() on the original field, check the translated value still round-trips correctly — markdown content with HTML, code fences, or trailing whitespace is where copy-paste-and-save bugs surface. Translate a record containing a code block and diff the stored JSON.locales array and the keys in the model's JSON column is the most common silent failure — the form renders, saves nothing, and throws no error.required on the base field can make the translated field behave unexpectedly. Set per-locale rules explicitly, usually relaxing required for non-source locales.$model->getRawOriginal('field')) rather than the accessor — the accessor returns the current-locale value and will make a working translation look empty.How can I help you explore Laravel packages today?