Multilingual infrastructure plugin screenshot
Dark mode ready
Multilingual support
Supports v5.x

Multilingual infrastructure by BELAAREDJ AHMED

Community

A powerful multilingual toolkit for Filament 5 applications, providing localized form fields, relationship selects, searchable table columns, infolist entries, a flexible locale switcher, RTL/LTR support, and configurable translation fallbacks for building scalable multilingual admin panels.

Tags: Panels Form Field Table Column Infolist Entry Developer Tool
Supported versions:
5.x
BELAAREDJ AHMED avatar Author: BELAAREDJ AHMED

Package health

Automated checks of this plugin's Composer package

100 / 100
Security 100
Maintenance 100
Ecosystem 100
15 checks
  • Passed: GitHub Actions pinned to SHA
  • Skipped: GitLab CI includes pinned to SHA
  • Passed: Open security advisories
  • Passed: Dependabot PR responsiveness — No open Dependabot PRs.
  • Skipped: Renovate MR responsiveness
  • Passed: Dependabot or Renovate configured
  • Passed: Dependency update cooldown configured
  • Passed: Provides a security policy
  • Passed: Abandoned or archived — No consulted source marks the package abandoned (packagist, github).
  • Passed: Commit and release recency — Active: last commit 2 days ago; last release 2 days ago.
  • Passed: composer.lock not committed by library — composer.lock is absent from the released dist archive.
  • Passed: Dist archive is lean
  • Passed: Current Laravel version supported — Package dependencies resolve together with current Laravel 13.0.
  • Passed: Current PHP version supported — Constraint ^8.2 supports current PHP 8.5.
  • Skipped: Current Symfony version supported
Third-party plugin. This is built by the community, not the Filament team. Filament does not review, endorse, or vet the security of plugins outside the filament/ namespace. Review the source and install at your own risk. Found malware or an unresolved security issue the author won't address? Report it .
Powered by Plumb Last scanned 11 hours ago

Documentation

Filament Localized is a Laravel package for building multilingual Filament 5 applications. It provides localized form components, relationship selects, table columns, infolist entries, multilingual search, and configurable translation fallbacks.

Installation · Configuration · Translation fallback · Localized form tabs · Localized select · Relationship search · Table columns · Infolist entries · Panel plugin · Locale configuration · Database structure · Testing · Contributing · License

#Features

  • Multilingual form tabs
  • Localized relationship selects and search
  • Localized table columns and infolist entries
  • RTL/LTR locale metadata
  • Configurable translation fallbacks
  • Centralized locale configuration and a reusable Localized API

#Requirements

  • PHP ^8.2
  • Filament ^5.0
  • Laravel application compatible with Filament 5

#Installation

Install the package with Composer:

composer require belaaredj/filament-localized

Publish the package configuration:

php artisan vendor:publish --tag=filament-localized-config

To persist each user's selected locale across logouts and devices, publish and run the optional migration:

php artisan vendor:publish --tag=filament-localized-migrations
php artisan migrate

The configuration file will be available at:

config/filament-localized.php

Publish the configuration when you want to customize supported locales, fallback behavior, or locale persistence.

#Configuration

The package stores translations as JSON objects.

For example:

{
    "ar": "الروبوتات",
    "fr": "Robotique",
    "en": "Robotics"
}

The default configuration supports Arabic, French, and English:

'locales' => [

    'ar' => [
        'label' => 'العربية',
        'short' => 'AR',
        'direction' => 'rtl',
    ],

    'fr' => [
        'label' => 'Français',
        'short' => 'FR',
        'direction' => 'ltr',
    ],

    'en' => [
        'label' => 'English',
        'short' => 'EN',
        'direction' => 'ltr',
    ],

],

You can add or remove locales according to your application.

For example:

'locales' => [

    'ar' => [
        'label' => 'العربية',
        'short' => 'AR',
        'direction' => 'rtl',
    ],

    'fr' => [
        'label' => 'Français',
        'short' => 'FR',
        'direction' => 'ltr',
    ],

    'en' => [
        'label' => 'English',
        'short' => 'EN',
        'direction' => 'ltr',
    ],

    'de' => [
        'label' => 'Deutsch',
        'short' => 'DE',
        'direction' => 'ltr',
    ],

],

#Translation Fallback

The package resolves translations using the following order:

Current locale → fr → en → ar

For example, when the current locale is ar:

[
    'fr' => 'Robotique',
    'en' => 'Robotics',
]

The resolved value will be:

Robotique

If French is also unavailable:

[
    'en' => 'Robotics',
]

the package will resolve:

Robotics

Configure the fallback order in:

'fallback_locales' => [
    'fr',
    'en',
    'ar',
],

The current application locale is always checked first.

#Localized Form Tabs

Use Localized::tabs() to create language tabs for your form fields.

use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\RichEditor;
use Belaaredj\FilamentLocalized\Facades\Localized;

Localized::tabs([
    TextInput::make('name')
        ->label('Name'),

    RichEditor::make('description')
        ->label('Description'),
]);

The package generates a field structure based on the configured locales.

For example:

name.ar
name.fr
name.en

description.ar
description.fr
description.en

The resulting state can be stored directly in a JSON column:

{
    "ar": "الروبوتات",
    "fr": "Robotique",
    "en": "Robotics"
}

#Database columns

Your translation fields should normally use a JSON-compatible database column.

For Laravel migrations:

$table->json('name')->nullable();
$table->json('description')->nullable();

For MySQL, make sure the database supports JSON columns.

#Localized Select

Use Localized::select() for localized relationship options.

use Belaaredj\FilamentLocalized\Facades\Localized;

Localized::select('skill_id')
    ->relationship('skill')
    ->localizedTitle('name')
    ->localizedSearch()
    ->searchable();

The option label is resolved using the configured translation fallback.

For example:

{
    "ar": "الروبوتات",
    "fr": "Robotique",
    "en": "Robotics"
}

The displayed option automatically follows the current locale and fallback configuration.

#Multiple relationships

The same API works with multiple relationships:

Localized::select('skills')
    ->multiple()
    ->relationship('skills')
    ->localizedTitle('name')
    ->localizedSearch()
    ->searchable();

#Localized Relationship Search

When:

->localizedSearch()

is enabled, relationship searches are performed across the configured search locales.

For example:

Localized::select('skill_id')
    ->relationship('skill')
    ->localizedTitle('name')
    ->localizedSearch()
    ->searchable();

A search can match:

العربية

or:

Robotique

or:

Robotics

depending on the configured search locales.

By default:

'search_locales' => null,

means that all configured locales are searched.

You can restrict the locales:

'search_locales' => [
    'ar',
    'fr',
],

#Localized Table Columns

Use Localized::column() for translated JSON attributes in Filament tables.

use Belaaredj\FilamentLocalized\Facades\Localized;

Localized::column('name')
    ->label('Name');

Enable multilingual searching with:

Localized::column('name')
    ->label('Name')
    ->localizedSearch()
    ->searchable();

The column automatically resolves the displayed translation using the configured fallback order.

#Localized Infolist Entries

Use Localized::entry() for translated attributes in Filament infolists.

use Belaaredj\FilamentLocalized\Facades\Localized;

Localized::entry('description')
    ->label('Description');

The displayed value follows the same locale and fallback rules used by the other package components.

#Supported API

The package provides a centralized API:

Method Purpose
Localized::tabs() Create multilingual form tabs
Localized::select() Create localized relationship selects
Localized::column() Display and search localized table columns
Localized::entry() Display localized infolist values

The underlying specialized components are also available:

LocalizedTabs
LocalizedSelect
LocalizedTextColumn
LocalizedTextEntry

#Filament Panel Plugin

The package also provides a Filament plugin class:

use Belaaredj\FilamentLocalized\FilamentLocalizedPlugin;

$panel
    ->plugin(
        FilamentLocalizedPlugin::make()
    );

The plugin is intentionally lightweight. The localized components can be used independently and do not require additional panel-specific configuration.

#Locale Switcher

The plugin includes an enabled-by-default locale switcher in the Filament topbar. Configure it per panel:

use Filament\View\PanelsRenderHook;
use Belaaredj\FilamentLocalized\FilamentLocalizedPlugin;

$panel->plugin(
    FilamentLocalizedPlugin::make()
        ->localeSwitcher()
        ->localeSwitcherHook(PanelsRenderHook::TOPBAR_END)
);

Disable it for a panel with ->localeSwitcher(false). The switcher validates locales, stores the selection in the session, and redirects back to the same-site referring page. When user persistence is enabled, it also saves the selection on the authenticated user. Persistent panel middleware reapplies the locale before Filament renders each request, including Livewire requests.

#Locale Configuration

The complete configuration is available in:

config/filament-localized.php

Example:

return [

    'locales' => [

        'ar' => [
            'label' => 'العربية',
            'short' => 'AR',
            'direction' => 'rtl',
        ],

        'fr' => [
            'label' => 'Français',
            'short' => 'FR',
            'direction' => 'ltr',
        ],

        'en' => [
            'label' => 'English',
            'short' => 'EN',
            'direction' => 'ltr',
        ],

    ],

    'default_locale' => 'fr',

    'fallback_locales' => [
        'fr',
        'en',
        'ar',
    ],

    'search_locales' => null,

    'locale_switcher' => [
        'enabled' => true,
        'show_flag' => true,
        'show_label' => true,
        'show_short' => false,
        'flag_fallback' => 'short',
    ],

    'locale_persistence' => [
        'session' => true,
        'user' => [
            'enabled' => false,
            'attribute' => 'locale',
        ],
        'browser' => [
            'enabled' => false,
        ],
    ],

];

#Locale properties

Each locale supports:

Property Description
label Full display name
short Short locale label
direction rtl or ltr
flag Text, emoji, or image URL

For example:

'ar' => [
    'label' => 'العربية',
    'short' => 'AR',
    'direction' => 'rtl',
],

Missing flags use flag_fallback (short, label, or none), so the switcher remains usable on systems whose fonts do not provide emoji flags. Locale resolution uses this priority: explicit valid request locale, optional authenticated-user attribute, session locale, optional browser language, then the configured default. User persistence and browser detection are disabled by default, so no user column or migration is required unless user persistence is enabled.

#Persisting a user's language across devices

To keep a user's selected language after logout or when they sign in on another device, run the optional migration commands from Installation. The migration adds a nullable locale column to the conventional users table.

If your authentication model uses a different table, edit the published migration before running it.

Then enable user persistence in your application's config/filament-localized.php (not in the package's vendor directory):

'locale_persistence' => [
    'session' => true,
    'user' => [
        'enabled' => true,
        'attribute' => 'locale',
    ],
],

Then select the language again while signed in so it is saved to the account. When enabled, authenticated selections update the configured user attribute. On authenticated requests the saved user language takes precedence over the session; explicit valid locale requests still take precedence over both. Guests continue to use the session. If your user model or table uses another attribute, adjust the migration and attribute setting to match. The migration is published, not run automatically, and user persistence remains disabled by default so the package does not modify an application's database without an explicit opt-in.

The locale direction is metadata for the selected language. The package does not force the entire Filament document into RTL or LTR by default. Apply LocaleManager::direction(app()->getLocale()) in an application layout only when the whole interface should follow that direction.

#Troubleshooting

  • Clear configuration cache after changing the config with php artisan config:clear.
  • Confirm the locale code is a key in locales; unsupported route values are rejected.
  • Ensure the panel uses FilamentLocalizedPlugin so persistent middleware runs on navigation and Livewire requests.
  • If a flag does not display, use an image URL or set flag_fallback to short.

#Using the Components Directly

The facade is the recommended API for most applications.

However, the underlying components can also be imported directly.

#Localized Select

use Belaaredj\FilamentLocalized\Components\Forms\LocalizedSelect;

LocalizedSelect::make('skill_id')
    ->relationship('skill')
    ->localizedTitle('name')
    ->localizedSearch()
    ->searchable();

#Localized Table Column

use Belaaredj\FilamentLocalized\Components\Tables\LocalizedTextColumn;

LocalizedTextColumn::make('name')
    ->localizedSearch()
    ->searchable();

#Localized Infolist Entry

use Belaaredj\FilamentLocalized\Components\Infolists\LocalizedTextEntry;

LocalizedTextEntry::make('name');

#Recommended Database Structure

A translated attribute should be stored as JSON.

Example migration:

Schema::create('skills', function (Blueprint $table) {
    $table->id();
    $table->json('name');
    $table->json('description')->nullable();
    $table->boolean('is_active')->default(true);
    $table->timestamps();
});

Example Eloquent model:

class Skill extends Model
{
    protected $fillable = [
        'name',
        'description',
        'is_active',
    ];

    protected function casts(): array
    {
        return [
            'name' => 'array',
            'description' => 'array',
            'is_active' => 'boolean',
        ];
    }
}

The package does not require a translation-specific database table.

#Testing

The package uses Pest for automated testing.

Run the test suite:

composer test

Run static analysis:

composer analyse

Run code formatting:

composer lint

Check formatting without modifying files:

composer lint:test

Run all non-mutating checks before publishing:

composer test
composer analyse
composer lint:test

#Architecture

The package is organized around a small set of reusable components:

Belaaredj\FilamentLocalized
│
├── Components
│   ├── Forms
│   │   ├── LocalizedTabs
│   │   └── LocalizedSelect
│   │
│   ├── Infolists
│   │   └── LocalizedTextEntry
│   │
│   └── Tables
│       └── LocalizedTextColumn
│
├── Support
│   ├── LocaleManager
│   ├── TranslationManager
│   └── TranslationQuery
│
├── Facades
│   └── Localized
│
├── FilamentLocalized
├── FilamentLocalizedPlugin
└── FilamentLocalizedServiceProvider

The package intentionally keeps translation resolution and multilingual querying separate from the UI components, making the underlying functionality reusable across forms, tables, infolists, and relationship fields.

#Contributing

Contributions, bug reports, and feature requests are welcome.

Before submitting a pull request, run the tests, static analysis, and formatting check:

composer test
composer analyse
composer lint:test

For bugs and feature requests, use the GitHub issue tracker.

#License

This package is licensed under the MIT License. See LICENSE.md for details.

#Author

Developed by Belaaredj Ahmed.


Filament Localized — reusable multilingual infrastructure for Filament 5.

The author

BELAAREDJ AHMED avatar Author: BELAAREDJ AHMED

Full-Stack & Open Source Developer 🇩🇿 I build modern, scalable applications and developer tools with Laravel, FilamentPHP, and React Native. Passionate about open source, clean architecture, multilingual systems, and developer experience, I enjoy turning real-world problems into reliable and reusable software.

Plugins
1
Stars
1