Plugins
Auto Translator
A revolutionary new way to start translating your Filament application. Fully automate the tedious task of coming up with and referencing translation keys.
Kit
Developer Tool
Panel Builder
Dark theme support
Yes
Multi language support
Yes
Compatible with the latest version
Supported versions: 3.x
Documentation

A revolutionary new way to start translating your Filament application. Fully automate the tedious task of coming up with and referencing translation keys.

This package fully automates the tedious process of constructing translation keys and applying them in your Filament application. Instead of manually typing translation keys and referencing them using __() or trans() inside all Filament functions like ->label(), this package replaces it by a fully automated approach of constructing a translation key based on where a certain component is located. Whenever you want to insert a translation, just directly open your translation file, add it and it will show up. If you have any Filament application that needs translations, this package will save you so much time ánd make the codebase cleaner and more consistent.

  • All texts are mapped automatically to a consistent translation key, so you will only need to add the actual translation in your language file, but never again need to use the __(...) helper to reference/insert the actual translation – that is all done automatically 🎉
  • It detects if a translation key is present, and if yes, insert it.
  • Required translation keys like ->label() are always enforced, but adding a hint or a helper text is as easy as adding a {field_name}.hint or {field_name}.helper_text key in your translation file.
  • Never need to think about "how do I call this translation key" again, because all translation keys are by definition constructed in a consistent manner. Therefore, this package is also a perfect addition for any team that wants to ensure consistency between team members in their translation files.

The package supports everything in Filament Panels, and can also be used outside Filament panels using a simple HasTranslations interface.

#Features

  • Auto-generate any translation key. ✨
  • Remove thousands of lines of boilerplate code and clean up your Filament files.
  • Ensure full translation consistency across your codebase. 💪
  • Incrementally implement in existing projects or enforce all keys from the start on. 🚀
  • Works across Forms, Infolists, Actions, Tables and Widgets, including infinite nested and complex structures. ⚡️
  • Supports Filament V3 & will support V4. 🎉

#Examples

The following examples are a great indication of all the boilterplate code you can expect to easily remove and let the plugin handle for you:

#Form/infolist

Translation keys relating to a resource form are automatically redirected to the resource level. Also notice the hint action with the Infolist modal on the role field, which the package entirely understands as being a hint action of the role field and thus part of the parent form:

Resource Form

Alternatively, if you were using the ->translateLabel() functionality, your diff of code would look like this:

Resource Form Translate Label

#Table

Translation keys relating to a resource table are automatically redirected to the resource level. Optional methods like heading, description, empty state heading and empty state description are also supported out-of-the-box.

Resource Table

#Actions

The translation key for an action is determined by where the action is located. Is the action part of a page, like via the getHeaderActions() method or via a custom action, then it will look at if the page is part of a resource, and if so, it will redirect the translation key to the resource level (e.g. filament/resources/post-resource.pages.view_post.actions.publish.*). If not, it might redirect the action to the page level (e.g. filament/pages/dashboard.actions.publish.*). The example also shows how you can retrieve a custom translation key for a component or action manually:

Action

Forms and infolists are also understood correctly as being part of the action, even with nested actions, plus you get access to all the nice methods for configuring actions and their failure/success messages.

#Pages

Page and resource attributes can also be defined entirely in your translation file. For example, just adding the key filament/resources/user-resource.navigation_label will apply the navigation label for the resource, no other code or method overrides needed!

Resource Page

The end goal of the package is to remove at least 99% of __()/trans() usage in your application. The following examples give an indication of all the code that you can just simply remove by starting to use this package. I'm committed to automating every translation key I can, so many advanced situations that are too complex for a short snippet are also covered (think of infinite nested actions with varying use of forms and infolists, custom pages, pages with multiple forms and/or infolists, etc).

#Installation guide: Filament AutoTranslator

Thank you for purchasing the AutoTranslator plugin for Filament!

We tried to make the plugin as easy-to-install and versatile as possible. Nevertheless, if you still have a question, feature request or found an unsupported translation, please send an e-mail to support@ralphjsmit.com.

#Prerequisites

The package is supported on Laravel 10 or higher and Filament V3 (Filament V4 will be added).

#Installation via Composer

To install the package you should add the following lines to your composer.json file in the repositories key in order to get access to the private package:

{
"repositories": [
{
"type": "composer",
"url": "https://satis.ralphjsmit.com"
}
]
}

If you have one of my other premium packages installed already, then you don't need to repeat these lines.

Next, you should require the package via the command line. You will be prompted for your username (which is your e-mail) and your password (which is your license key, e.g. 8c21df8f-6273-4932-b4ba-8bcc723ef500).

composer require ralphjsmit/laravel-filament-auto-translator

#Configuring the plugin per-panel

#Existing project

The plugin works by generating the translations for all $livewire components that implement RalphJSmit\Filament\AutoTranslator\Contracts\HasTranslations. Therefore, if you already have an existing project, you will need to choose whether you want to immediately enable the AutoTranslator for all resources, and potentially need to convert some translation keys, or if you only want to enable it for new resources.

For all resources/pages/clusters/widgets that you want to enable the auto translations for, extend the following files provided by the AutoTranslator instead of those provided by Filament. You can easily do this as a global search-and-replace:

  • Replace Filament\Clusters\Cluster with RalphJSmit\Filament\AutoTranslator\Filament\Clusters\Cluster.
  • Replace Filament\Pages\Page with RalphJSmit\Filament\AutoTranslator\Filament\Pages\Page.
  • Replace Filament\Resources\Resource with RalphJSmit\Filament\AutoTranslator\Filament\Resources\Resource.
  • Replace Filament\Resources\RelationManagers\RelationManager with RalphJSmit\Filament\AutoTranslator\Filament\Resources\Resource\RelationManagers\RelationManager.
  • Replace Filament\Resources\Pages\CreateRecord with RalphJSmit\Filament\AutoTranslator\Filament\Resources\Resource\Pages\CreateRecord.
  • Replace Filament\Resources\Pages\EditRecord with RalphJSmit\Filament\AutoTranslator\Filament\Resources\Resource\Pages\EditRecord.
  • Replace Filament\Resources\Pages\ListRecords with RalphJSmit\Filament\AutoTranslator\Filament\Resources\Resource\Pages\ListRecords.
  • Replace Filament\Resources\Pages\ManageRecords with RalphJSmit\Filament\AutoTranslator\Filament\Resources\Resource\Pages\ManageRecords.
  • Replace Filament\Resources\Pages\ManageRelatedRecords with RalphJSmit\Filament\AutoTranslator\Filament\Resources\Resource\Pages\ManageRelatedRecords.
  • Replace Filament\Resources\Pages\Page with RalphJSmit\Filament\AutoTranslator\Filament\Resources\Resource\Pages\Page.
  • Replace Filament\Resources\Pages\ViewRecord with RalphJSmit\Filament\AutoTranslator\Filament\Resources\Resource\Pages\ViewRecord.
  • Replace Filament\Widgets\ChartWidget with RalphJSmit\Filament\AutoTranslator\Filament\Widgets\ChartWidget.
  • Replace Filament\Widgets\StatsOverviewWidget with RalphJSmit\Filament\AutoTranslator\Filament\Widgets\StatsOverviewWidget.
  • Replace Filament\Widgets\TableWidget with RalphJSmit\Filament\AutoTranslator\Filament\Widgets\TableWidget.
  • Replace Filament\Widgets\Widget with RalphJSmit\Filament\AutoTranslator\Filament\Widgets\Widget.

Alternatively, if for the above classes you already have your own (abstract) base class in your application, then you can also implement the HasTranslations interface and add the following traits:

  • Cluster: RalphJSmit\Filament\AutoTranslator\Concerns\HasClusterTranslations
  • Page: RalphJSmit\Filament\AutoTranslator\Concerns\HasPageTranslations
  • Resource: RalphJSmit\Filament\AutoTranslator\Concerns\HasResourceTranslations
  • Resource relation manager: RalphJSmit\Filament\AutoTranslator\Concerns\HasResourceRelationManagerTranslations
  • Resource page: RalphJSmit\Filament\AutoTranslator\Concerns\HasResourcePageTranslations
  • Widget: RalphJSmit\Filament\AutoTranslator\Concerns\HasWidgetTranslations

Example for an abstract base Resource class in your own project:

use Filament\Resources\Resource as BaseResource;
use RalphJSmit\Filament\AutoTranslator\Concerns\HasResourceTranslations;
use RalphJSmit\Filament\AutoTranslator\Contracts\HasTranslations;
 
abstract class Resource extends BaseResource implements HasTranslations
{
use HasResourceTranslations;
}

Next, go on to the Registering plugin section.

#New projects

If you are starting a new project, you can either choose for all your resource/page/cluster/widget classes to extend the classes provided by this package, or to start creating an abstract base class for each of the objects that you extend. For example, look at the above Resource class example. In your project, every time you generate a new resource, you will need to make sure to extend the abstract base class that you created. Having an abstract base class can also be very beneficial in the future if you ever need to add any custom code that should apply to every resource/page/cluster/widget, then you already have a base class, which is a good Filament pattern.

Alternatively, it is also perfectly fine to not bother with abstract base classes but to just extend the classes by the AutoTranslator provided above.

#Registering plugin

Second, you should register the plugin in any of the panels you want to be translated:

use RalphJSmit\Filament\AutoTranslator\FilamentAutoTranslator;
 
$panel
->plugin(FilamentAutoTranslator::make())

In the rest of the docs, if we refer to the $plugin variable, then we mean the $plugin = FilamentAutoTranslator::make(). This is not necessarily a variable, but it helps to keep the code examples shorter and simpler.

#Usage

Once you installed the plugin into your panel, it will automatically start generating translation keys for all the resources/pages/clusters/widget where you extended the base class/implemented the HasTranslations interface.

#How does it work/getting started

When starting to use the package, the generated translation keys really explain themselves because of their consistency and because the key is generated based on the location of the text. However, below is an introduction with several examples for people just getting started to use the plugin, or to get an idea beforehand how it would work.

#Translating forms

Consider the example that you have an EditUser page under a UserResource. The form defined in the UserResource ->form() method has a component as follows:

Forms\Components\Select::make('role'),

The plugin will now look at various aspects to determine a consistent translation key. In this case, it will notice that the form component is placed on a resource page App\Filament\Resources\UserResource\Pages\EditUser, the $operation is edit and that generally the form for that page is defined under the UserResource, so it will compile the following translation key: filament/resources/user-resource.form.fields.role.label.

If the translation key is present in your language files it will get displayed, and if not, you will see the raw translation key, giving you a visual indication that you are missing this translation key. On production, the plugin will fall back to the default Filament behaviour, which is to make an English headline out of the component name. This will only happen for required translations, so if you are not having an optional helperText() or a hint() translation defined for a certain field, it will of course not display a raw translation key or force you to add it. However, if you add a translation key filament/resources/user-resource.form.fields.role.helper_text, the plugin will automatically pick up the translation. The same applies for pretty much all other methods you can think of, from things like ->addActionLabel() to ->hint(), ->prefix(), ->suffix(), ->tooltip(), ->validationAttribute() and ->loadingMessage().

This is very convenient, because adding any translation comes down to just adding a new key in your translation file only and no other files need to be opened or touched.

The lang/{locale}/filament/resources/user-resource.php translation could now look like this:

return [
'form' => [
'fields' => [
'role' => [
'label' => 'Role', // Required
'helper_text' => 'The role of the user', // Optional, will be recognized once you add it.
'loading_message' => 'Loading available roles from server', // Optional, will be recognized once you add it.
'prefix' => 'Role ', // Optional, will be recognized once you add it.
'suffix' => ' for user', // Optional, will be recognized once you add it.
// Etc...
],
],
],
];

#Complex forms

The plugin is can understand infinitely nested and complex structures, including those with Builders/Repeaters, nested actions, affix actions, et cetera. Consider the following example which is a good indication of how "clean" your Filament files will become without all the boilerplate code only for translations:

use RalphJSmit\Filament\AutoTranslator\AutoTranslator;
use RalphJSmit\Filament\AutoTranslator\Enums\ActionGroup;
 
Forms\Components\Section::make('authorization') // The value passed here is used as a key in the translation file...
->schema([
Forms\Components\Select::make('role')
->required(),
Forms\Components\Actions::make([
Forms\Components\Actions\Action::make('reset_password')
->form([
Forms\Components\TextInput::make('password')
->required(),
// ...
])
->action(function (Forms\Components\Actions\Action $action, array $data, User $record) {
// Perform action...
 
Notification::make()
->title(AutoTranslator::translateActionText($action, ActionGroup::Notifications, 'success.title', ['userName' => $record->name]))
->body(AutoTranslator::translateActionText($action, ActionGroup::Notifications, 'success.body'))
->success()
->send();
})
]),
]),
]),

Which corresponds to the following translation file in filament/resources/user-resource.php:

return [
'form' => [
'fields' => [
'authorization' => [
'heading' => 'Section Heading',
'description' => 'Section Description Paragraph.',
'schema' => [
'role' => [
'label' => 'Role',
],
'actions' => [
'reset_password' => [
'form' => [
'fields' => [
'password' => [
'label' => 'New password',
],
// ...
],
],
'notifications' => [
'success' => [
'title' => 'Reset password for :userName',
'body' => 'Password successfully reset',
],
],
],
],
],
],
],
],
];

As you can see, the translation keys are generated very consistently and in a clear format that corresponds to their place in the Filament panel.

#Manually request a translation key

You can also easily request a translation key manually using the AutoTranslator::translate*Text() methods, where you pass in the component you want to get a sub-key for and it will automatically compile and construct the right translation key:

use RalphJSmit\Filament\AutoTranslator\Enums\FormGroup;
 
Forms\Components\Select::make('role')
->options(fn (Forms\Components\Select $component) => [
'admin' => AutoTranslator::translateFormText($component, FormGroup::Fields, 'options.admin.label'),
'user' => AutoTranslator::translateFormText($component, FormGroup::Fields, 'options.user.label'),
]),

There are methods like these for translateFormText(), translateActionText(), translateTableText() and translateInfoListText().

Each of these functions accept the form/action/table/infolist component that you want to retrieve the translation key for, plus a "top-level" group:

  • FormGroup::Fields: use it whenever you are interacting with something that originates from inside a form. This corresponds to e.g. the form.{fields} key in your resource.
  • ActionGroup::Form/ActionGroup::Infolist/ActionGroup::Notifications: use Form when you work with something originating from an action form, Infolist when you work with something originating from an infolist, and Notifications when you work with something originating from a notification sent by an action. This corresponds to e.g. the {action_name}.{form/infolist/notifications} key.
  • InfolistGroup::Entries: use it when you work with something originating from an infolist entry. This corresponds to e.g. the infolist.{entries} key in your resource.
  • TableGroup::Actions/TableGroup::BulkActions/TableGroup::Columns/TableGroup::Filters/TableGroup::Summarizers: use Actions when you work with something originating from a table action, BulkActions when you work with something originating from a table bulk action, Columns when you work with something originating from a table column, and Filters when you work with something originating from a table filter. This corresponds to e.g. the table.{actions/bulk_actions/columns/filters/summarizers} key.

#Translating tables

Now, consider the following table on the UserResource:

$table
->columns([
Tables\Columns\TextColumn::make('name'),
Tables\Columns\TextColumn::make('email'),
])
->actions([
Tables\Actions\Action::make('reset_password')
->form([
Forms\Components\TextInput::make('password')
->required(),
// ...
])
->action(function (Tables\Actions\Action $action, array $data, User $record) {
// Perform action...
 
Notification::make()
->title(AutoTranslator::translateTableText($action, ActionGroup::Notifications, 'success.title', ['userName' => $record->name]))
->body(AutoTranslator::translateTableText($action, ActionGroup::Notifications, 'success.body'))
->success()
->send();
})
])
->filters([
Tables\Filters\SelectFilter::make('role')
->options(fn (Tables\Filters\SelectFilter $filter) => [
'admin' => AutoTranslator::translateTableText($filter, TableGroup::Filters, 'options.admin.label'),
'user' => AutoTranslator::translateTableText($filter, TableGroup::Filters, 'options.user.label'),
]),
])

This corresponds to the following translation file:

return [
'table' => [
'columns' => [
'name' => [
'label' => 'Name', // Required
],
'email' => [
'label' => 'E-mail', // Required
'prefix' => 'E-mail: ', // Optional
],
],
'actions' => [
'reset_password' => [
'form' => [
'fields' => [
'password' => [
'label' => 'New password',
],
// ...
],
],
'notifications' => [
'success' => [
'title' => 'Reset password for :userName',
'body' => 'Password successfully reset',
],
],
],
],
'filters' => [
'role' => [
'label' => 'Role',
'options' => [
// Custom translation key requested manually
'admin' => 'Admin',
'user' => 'User',
],
],
],
'empty_state_heading' => 'No users found',
],
];

#Translating actions

The package will also generate translation keys for actions, even if they are infinitely nested. Consider the following header action on the App\Filament\Resources\UserResource\Pages\EditUser page:

protected function getHeaderActions(): array
{
return [
Actions\Action::make('first_action')
->infolist([
// ..
])
->extraModalFooterActions([
Actions\Action::make('second_action')
->form([
//
]),
// ...
]),
];
}

The translation keys are generated as follows in the filament/resources/user-resource.php file:

return [
'pages' => [
'edit-user' => [
'navigation-label' => 'Navigation label',
'title' => 'Page title',
'subheading' => 'This page allows you to edit a user and perform several actions.',
'actions' => [
'first_action' => [
'label' => 'First action',
'infolist' => [
'entries' => [
// ..
],
],
'extra_modal_footer_actions' => [
'second_action' => [
'label' => 'Second action',
'form' => [
// ..
],
],
// ...
]
],
],
],
],
];

As you can see, I hope you have gotten a good impression of how this package will have an automated translation key for pretty much anything you can imagine, from the important ones like $field->label() to the tiniest ones as $table->emptyStateDescription() or infinitely nested actions within actions. The goal is to remove at least 99% of __() usage in your application, so if you are running into an issue with a translation key, let me know at support@ralphjsmit.com.

#Translation Namespace

The default namespace for a translation is generated based on the FQCN of the class where it originates. Shortly speaking, a FQCN App\Filament\Resources\UserResource will get a translation key of filament/resources/user-resource.php, whereas an FQCN App\Filament\Admin\Resources\UserResource will get a translation key of filament/admin/resources/user-resource.php.

In case that you want to override the namespace, you can override it using the $plugin->translationGroups() method:

$plugin
->translationGroups([
'App\\Filament\\Admin' => 'filament/admin-panel', // Re-codes all files under `App\Filament\Admin` to the translation key `filament/admin-panel/...`.
])

#Roadmap

I hope this package will be useful to you! If you have any ideas or suggestions on how to make it more useful, please let me know (support@ralphjsmit.com).

#Support

If you have a question, bug or feature request, please e-mail me at support@ralphjsmit.com or tag @ralphjsmit on #auto-translator-pro on the Filament Discord. Love to hear from you!

🙋‍ Ralph J. Smit

Ralph J. Smit

Ralph, a skilled full-stack Laravel software engineer, freelances and has a strong presence in the Filament community. He's the developer behind Media Library Pro and crafts other premium Filament packages as well.

9
Plugins
643
Stars
More from this author
Featured Plugins