Multilingual infrastructure by BELAAREDJ AHMED
CommunityA 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.
Author:
BELAAREDJ AHMED
Package health
Automated checks of this plugin's Composer package
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.lockis 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.2supports current PHP8.5. - Skipped: Current Symfony version supported
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
.
Documentation
- Features
- Requirements
- Installation
- Configuration
- Translation Fallback
- Localized Form Tabs
- Localized Select
- Localized Relationship Search
- Localized Table Columns
- Localized Infolist Entries
- Supported API
- Filament Panel Plugin
- Locale Configuration
- Using the Components Directly
- Recommended Database Structure
- Testing
- Architecture
- Contributing
- License
- Author
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
LocalizedAPI
#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
FilamentLocalizedPluginso persistent middleware runs on navigation and Livewire requests. - If a flag does not display, use an image URL or set
flag_fallbacktoshort.
#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
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.
Featured Plugins
A selection of plugins curated by the Filament team
Sharp Theme
A theme that gives panels a precise, technical look with square corners, strong borders, and clear contrast.
Filament
Advanced Tables (formerly Filter Sets)
Supercharge your tables with powerful features like user-customizable views, quick filters, multi-column sorting, advanced table searching, convenient view management, and more. Compatible with Resource Panel Tables, Relation Managers, Table Widgets, and Table Builder!
Kenneth Sese
Custom Fields
Eliminate custom field migrations forever. Let your users create and manage form fields directly in Filament admin panels with 20+ built-in field types, validation, and zero database changes.
Relaticle