Filament Plugins

Purchase

Usage

How it works

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

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:

php
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.components.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.components.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:

lang/{locale}/filament/resources/user-resource.php
return [
    'form' => [
        'components' => [
            '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 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:

php
use RalphJSmit\Filament\AutoTranslator\AutoTranslator;
use RalphJSmit\Filament\AutoTranslator\Enums\ActionGroup;

Schemas\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([
            Actions\Action::make('reset_password')
                ->schema([
                    Forms\Components\TextInput::make('password')
                        ->required(),
                    // ...
                ])
                ->action(function (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:

lang/{locale}/filament/resources/user-resource.php
return [
    'form' => [
        'components' => [
            'authorization' => [
                'heading' => 'Section Heading', 
                'description' => 'Section Description Paragraph.', 
                'schema' => [
                    'role' => [
                        'label' => 'Role', 
                    ],
                    'actions' => [
                        'reset_password' => [
                            'schema' => [
                                'components' => [
                                    '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:

php
use RalphJSmit\Filament\AutoTranslator\Enums\SchemaGroup;

Forms\Components\Select::make('role')
    ->options(fn (Forms\Components\Select $component) => [
        'admin' => AutoTranslator::translateSchemaText($component, SchemaGroup::Components, 'options.admin.label'),
        'user' => AutoTranslator::translateSchemaText($component, SchemaGroup::Components, 'options.user.label'),
    ]),

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

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

  • SchemaGroup::Components: use it whenever you are interacting with something that originates from inside a form or infolist schema. This corresponds to e.g. the form.{components} or infolist.{components} key in your resource.
  • ActionGroup::Schema/ActionGroup::Notifications: use Schema when you work with something originating from an action schema, and Notifications when you work with something originating from a notification sent by an action. This corresponds to e.g. the {action_name}.{schema/notifications} key.
  • 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:

php
$table
    ->columns([
        Tables\Columns\TextColumn::make('name'),
        Tables\Columns\TextColumn::make('email'),
    ])
    ->actions([
        Tables\Actions\Action::make('reset_password')
            ->schema([
                Forms\Components\TextInput::make('password')
                    ->required(),
                // ...
            ])
            ->action(function (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:

lang/{locale}/filament/resources/user-resource.php
return [
    'table' => [
        'columns' => [
            'name' => [
                'label' => 'Name', // Required
            ],
            'email' => [
                'label' => 'E-mail', // Required
                'prefix' => 'E-mail: ', // Optional
            ],
        ],
        'actions' => [
            'reset_password' => [
                'schema' => [
                    'components' => [
                        '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:

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

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

lang/{locale}/filament/resources/user-resource.php
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',
                    'schema' => [
                        'components' => [
                            // ..
                        ],
                    ],
                    'extra_modal_footer_actions' => [
                        'second_action' => [
                            'label' => 'Second action',
                            'schema' => [
                                'components' => [
                                    // ..
                                ],
                            ],
                        ],
                        // ...
                    ]
                ],
            ],
        ],
    ],
];

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 [email protected].

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:

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

Override translation key

Sometimes you need to override the default translation key for a certain component or action. You can pass a custom relative translation key or absolute translation key:

php
TextInput::make('input')
    ->translationKey('alternative_name'), // Preserves full namespace such as `filament/resources/user-resource.form.fields.alternative_name.*`

If you would like to replace the entire translation key, you can also pass true as the second parameter to take the key as the top-level translation:

php
class ReusableAction extends Action
{
    protected function setUp(): void
    {
        parent::setUp();
        
        // Absolute without looking at the relative location of the action.
        $this->translationKey('filament/actions/reusable-action', true);    
    }
}

The method is inserted via a Macro, so you might not see it auto-completed.

© FilamentPlugins.com ✦ 2022 – 2026
PrivacyTerms & Conditions
All rights reserved.