PHPackages                             syriable/filament-auto-translator - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Localization &amp; i18n](/categories/localization)
4. /
5. syriable/filament-auto-translator

ActiveLibrary[Localization &amp; i18n](/categories/localization)

syriable/filament-auto-translator
=================================

Automatic, convention-based translations for Filament v5 panels.

0.1.0(1mo ago)01↑2900%MITPHP ^8.2

Since Jun 3Compare

[ Source](https://github.com/syriable/filament-auto-translator)[ Packagist](https://packagist.org/packages/syriable/filament-auto-translator)[ Docs](https://github.com/syriable/filament-auto-translator)[ RSS](/packages/syriable-filament-auto-translator/feed)WikiDiscussions Synced 1mo ago

READMEChangelog (2)Dependencies (10)Versions (2)Used By (0)

Filament Auto Translator
========================

[](#filament-auto-translator)

[![Tests](https://github.com/syriable/filament-auto-translator/actions/workflows/tests.yml/badge.svg)](https://github.com/syriable/filament-auto-translator/actions/workflows/tests.yml)[![PHPStan](https://github.com/syriable/filament-auto-translator/actions/workflows/phpstan.yml/badge.svg)](https://github.com/syriable/filament-auto-translator/actions/workflows/phpstan.yml)

Automatic, convention-based translations for [Filament v5](https://filamentphp.com)panels. Register one plugin and your labels, headings, placeholders, actions and more are translated from your language files by **convention** — no per-component wiring, and nothing breaks if a key is missing (Filament keeps its own default).

Table of contents
-----------------

[](#table-of-contents)

- [Installation](#installation)
- [Quick start](#quick-start)
- [How keys are derived](#how-keys-are-derived)
- [Auto-translated surfaces](#auto-translated-surfaces)
- [Opt-in artifacts (resources, pages, widgets…)](#opt-in-artifacts)
- [Where to put your translations](#where-to-put-your-translations)
- [Translation groups](#translation-groups)
- [Custom components](#custom-components)
- [Configuration](#configuration)
- [Artisan commands](#artisan-commands)
- [How fallback works](#how-fallback-works)
- [Architecture](#architecture)
- [Development](#development)
- [License](#license)

Installation
------------

[](#installation)

```
composer require syriable/filament-auto-translator
```

The service provider is auto-discovered. Optionally publish the config file:

```
php artisan vendor:publish --tag=filament-auto-translator-config
```

Quick start
-----------

[](#quick-start)

Register the plugin on your panel:

```
use Filament\Panel;
use Syriable\FilamentAutoTranslator\FilamentAutoTranslatorPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->plugin(FilamentAutoTranslatorPlugin::make());
}
```

That's it. From now on, form fields, table columns, filters and actions across the panel are translated automatically from your language files. Resource metadata and other class-based artifacts are opted in with a trait — see [Opt-in artifacts](#opt-in-artifacts).

How keys are derived
--------------------

[](#how-keys-are-derived)

Every translatable string maps to a key built from **where the component lives**:

```
...

```

- **``** — the owning class, taken from `Filament` onwards, kebab-cased, with `\` turned into `/`:

    ClassOwner path`App\Filament\Resources\UserResource``filament/resources/user-resource``App\Filament\Pages\Settings``filament/pages/settings``App\Filament\Clusters\Shop``filament/clusters/shop`
- **``** — the area of the owner (`form`, `table.columns`, `table.filters`, `actions`, `bulk_actions`, …).
- **``** — the component name (e.g. the field or column name).
- **``** — the snake-cased property (`label`, `placeholder`, `modal_heading`, …).

The **owner** of an auto-translated component is the Livewire component it is rendered on: the **Resource** class for a resource page, otherwise the page or component class.

Example — a `TextInput::make('name')->helperText()` on `UserResource` resolves to:

```
filament/resources/user-resource.form.name.hint

```

Auto-translated surfaces
------------------------

[](#auto-translated-surfaces)

These are translated **automatically** once the plugin is registered — you do not touch your components, you only add language keys.

SurfaceComponentKey (under the owner path)Form fieldsany `Field``form..label` · `form..placeholder` · `form..hint`Table columnsany `Column``table.columns..label` · `table.columns..tooltip`Table filtersany `BaseFilter``table.filters..label`Actions (header / record)any `Action``actions..label` and modal text (below)Bulk actionsany `BulkAction``bulk_actions..label` and modal text (below)Action **modal** text is covered too, under the same `actions.` / `bulk_actions.` prefix:

```
…actions.delete.modal_heading
…actions.delete.modal_description
…actions.delete.modal_submit_action_label
…actions.delete.modal_cancel_action_label

```

> The field name used in the key is the component's `->getName()`. Nested state paths (e.g. `address.street`) become a single token joined with `_`(`address_street`).

Opt-in artifacts
----------------

[](#opt-in-artifacts)

Resources, pages, clusters, relation managers, widgets, exporters and importers expose their text through getter methods rather than components, so you opt them in with a trait (or extend the matching drop-in base class under `Syriable\FilamentAutoTranslator\…`). Each trait translates the listed keys and falls back to Filament's default when a key is missing.

TraitApply toKeys (under the owner path)`HasResourceTranslations`Resource`model_label` · `plural_model_label` · `navigation_label` · `navigation_group` · `breadcrumb``HasPageTranslations`Custom page`title` · `heading` · `subheading` · `navigation_label` · `navigation_group``HasClusterTranslations`Cluster`navigation_label` · `cluster_breadcrumb``HasRelationManagerTranslations`Relation manager`title` · `badge` · `model_label` · `plural_model_label``HasChartWidgetTranslations`Chart widget`heading` · `description``HasStatsOverviewWidgetTranslations`Stats widget`heading` · `description``HasTableWidgetTranslations`Table widget`table_heading``HasExporterTranslations`Exporter`completed_notification_title``HasImporterTranslations`Importer`completed_notification_title`Use the trait:

```
use Syriable\FilamentAutoTranslator\Concerns\HasResourceTranslations;

class UserResource extends \Filament\Resources\Resource
{
    use HasResourceTranslations;
}
```

…or extend the drop-in base (it already applies the trait):

```
use Syriable\FilamentAutoTranslator\Resources\Resource;

class UserResource extends Resource
{
    // ...
}
```

Drop-in bases are available at:

- `Syriable\FilamentAutoTranslator\Resources\Resource`
- `Syriable\FilamentAutoTranslator\Pages\Page`
- `Syriable\FilamentAutoTranslator\Clusters\Cluster`
- `Syriable\FilamentAutoTranslator\Resources\RelationManagers\RelationManager`
- `Syriable\FilamentAutoTranslator\Widgets\ChartWidget`
- `Syriable\FilamentAutoTranslator\Widgets\StatsOverviewWidget`
- `Syriable\FilamentAutoTranslator\Widgets\TableWidget`
- `Syriable\FilamentAutoTranslator\Actions\Exports\Exporter`
- `Syriable\FilamentAutoTranslator\Actions\Imports\Importer`

> For exporters/importers, only the completed-notification **title** is translated. The notification **body** is an abstract method you implement yourself, so it stays under your control.

Where to put your translations
------------------------------

[](#where-to-put-your-translations)

A key like `filament/resources/user-resource.form.name.label` maps to the language **file** `lang//filament/resources/user-resource.php`, with the remainder of the key as the nested array path:

```
// lang/en/filament/resources/user-resource.php
return [
    // Resource metadata (needs HasResourceTranslations)
    'model_label' => 'User',
    'plural_model_label' => 'Users',
    'navigation_label' => 'Users',
    'navigation_group' => 'Access',
    'breadcrumb' => 'Users',

    // Form fields (automatic)
    'form' => [
        'name' => [
            'label' => 'Full name',
            'placeholder' => 'Your legal name',
            'hint' => 'As printed on your ID',
        ],
    ],

    // Table (automatic)
    'table' => [
        'columns' => [
            'email' => ['label' => 'Email address', 'tooltip' => 'Primary contact'],
        ],
        'filters' => [
            'verified' => ['label' => 'Verified only'],
        ],
    ],

    // Actions (automatic)
    'actions' => [
        'edit' => ['label' => 'Edit'],
        'delete' => [
            'label' => 'Delete',
            'modal_heading' => 'Delete user',
            'modal_submit_action_label' => 'Yes, delete',
            'modal_cancel_action_label' => 'Cancel',
        ],
    ],
    'bulk_actions' => [
        'delete' => ['label' => 'Delete selected'],
    ],
];
```

Add a `lang/nl/filament/resources/user-resource.php` with the same structure to translate into Dutch, and so on.

Translation groups
------------------

[](#translation-groups)

By default the owner path is derived from the class namespace. Use **translation groups** to remap a namespace fragment to a different path — handy for shortening paths or grouping by panel.

Per panel:

```
FilamentAutoTranslatorPlugin::make()
    ->translationGroups([
        'App\\Filament\\Resources' => 'admin',
    ]);
```

With the map above, `App\Filament\Resources\UserResource` resolves under `admin/user-resource` (file: `lang/en/admin/user-resource.php`) instead of `filament/resources/user-resource`.

You can also set defaults in the config file (see below); per-panel groups are merged on top of the config defaults.

Custom components
-----------------

[](#custom-components)

You can integrate **your own components** so chosen attributes are translated by convention — exactly like the built-in fields/columns/actions. Register the component class, the setter methods to translate, and the surface segment on the plugin:

```
use App\Filament\Schemas\Components\Separator;

FilamentAutoTranslatorPlugin::make()
    ->registerComponent(Separator::class, ['text'], context: 'form')
    // multiple attributes / other surfaces are fine too:
    ->registerComponent(\App\Filament\Tables\Columns\RatingColumn::class, ['label', 'tooltip'], context: 'table.columns');
```

Two requirements for the component itself:

1. **`make()` must call `->configure()`** (the standard Filament pattern) — this is what applies the registered defaults:

    ```
    public static function make(): static
    {
        $static = app(static::class);
        $static->configure();

        return $static;
    }
    ```
2. The component needs an **identity** for the key segment: `getName()` if it has one, otherwise `getKey()`. For a nameless component (e.g. a visual separator), give the instance a key:

    ```
    Separator::make()->key('intro')->text(/* ... */);
    ```

That `Separator` then resolves its `text` to `.form.intro.text`, e.g.:

```
// lang/en/filament/resources/user-resource.php
return [
    'form' => [
        'intro' => ['text' => 'Welcome to your settings'],
    ],
];
```

Each registered attribute is the **setter method name**; the key uses its snake-cased form (`helperText` → `helper_text`). As always, a missing key falls back to the component's own default.

Configuration
-------------

[](#configuration)

`config/filament-auto-translator.php`:

```
return [
    // Remap class-namespace fragments to translation-file paths.
    // Also settable per panel via ->translationGroups([...]).
    'translation_groups' => [
        // 'App\\Filament\\Resources' => 'admin',
    ],

    // When true, multi-segment state-path tokens are joined with "->" instead of
    // "_" (a legacy key convention), for backwards compatibility with existing
    // language files.
    'legacy_keys' => false,
];
```

Artisan commands
----------------

[](#artisan-commands)

**Extract** — emit a starter skeleton of the resource-metadata keys for every registered resource (or for the classes you pass), so you have something to fill in:

```
# Print the keys
php artisan auto-translator:extract

# Write language files (merges into existing files without overwriting values)
php artisan auto-translator:extract --write --locale=en

# Limit to specific resources
php artisan auto-translator:extract "App\Filament\Resources\UserResource"
```

**Audit** — compare locales and report keys present in a reference locale but missing (or orphaned) elsewhere. It exits non-zero when keys are missing, so you can use it as a CI gate:

```
php artisan auto-translator:audit --reference=en
php artisan auto-translator:audit --reference=en --locale=nl --locale=ar
```

How fallback works
------------------

[](#how-fallback-works)

Resolution is non-destructive:

- **Key present** → the translated string is used (with `:count` pluralisation and `:attribute` replacements supported by the Laravel translator where applicable).
- **Key missing** → `null` is returned, so Filament falls back to its own default (the humanised field name for labels; nothing for placeholders/hints/tooltips).

This means you can adopt the plugin on an existing panel without translating everything up front — untranslated parts simply keep working as before.

Architecture
------------

[](#architecture)

A small, direct design:

ClassResponsibility`KeyResolver`Derive the file path and full key from a class + context (pure string logic).`AutoTranslator`Look up a key via the Laravel translator and wire the panel defaults at boot.`FilamentAutoTranslatorPlugin`Filament plugin entry; holds per-panel translation groups.`Concerns\*`Opt-in traits for resources, pages, clusters, relation managers, widgets, exporters, importers.`Commands\*`The `extract` and `audit` commands.Development
-----------

[](#development)

```
composer install
composer test       # Pest
composer analyse    # PHPStan + Larastan (level 5)
composer lint       # Pint
composer ci         # all of the above
```

License
-------

[](#license)

The MIT License (MIT). See [LICENSE.md](LICENSE.md).

###  Health Score

34

—

LowBetter than 75% of packages

Maintenance90

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity36

Early-stage or recently created project

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

51d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/286110444?v=4)[syriable](/maintainers/syriable)[@syriable](https://github.com/syriable)

---

Tags

laravellocalizationtranslationsfilamentfilament-pluginfilamentphpsyriable

###  Code Quality

TestsPest

Static AnalysisPHPStan, Rector

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/syriable-filament-auto-translator/health.svg)

```
[![Health](https://phpackages.com/badges/syriable-filament-auto-translator/health.svg)](https://phpackages.com/packages/syriable-filament-auto-translator)
```

###  Alternatives

[bezhansalleh/filament-language-switch

Zero config Language Switch(Changer/Localizer) plugin for filamentphp admin

3581.3M33](/packages/bezhansalleh-filament-language-switch)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3914.8k](/packages/rawilk-profile-filament-plugin)[backstage/mails

View logged mails and events in a beautiful Filament UI.

16121.5k](/packages/backstage-mails)[croustibat/filament-jobs-monitor

Background Jobs monitoring like Horizon for all drivers for FilamentPHP

274333.4k9](/packages/croustibat-filament-jobs-monitor)[marcelweidum/filament-passkeys

Use passkeys in your filamentphp app

6649.5k2](/packages/marcelweidum-filament-passkeys)[stephenjude/filament-jetstream

A Laravel starter kit built with Filament inspired by Jetstream.

17760.2k3](/packages/stephenjude-filament-jetstream)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
