prunacatalin / filament-locale-switcher
Drop-in topbar locale switcher for Filament v4/v5 panels. Session + per-user persistence, explicit locale list, render-hook dropdown.
Package info
github.com/PrunaCatalin/filament-locale-switcher
pkg:composer/prunacatalin/filament-locale-switcher
Requires
- php: ^8.2
- filament/filament: ^3.0|^4.0|^5.0
- illuminate/contracts: ^10.0|^11.0|^12.0|^13.0
- illuminate/support: ^10.0|^11.0|^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^9.0|^10.0|^11.0
- pestphp/pest: ^3.0|^4.0
- pestphp/pest-plugin-laravel: ^3.0|^4.0
README
Drop-in locale switcher for Filament v4/v5 panels. Topbar dropdown (or user-menu items), session / per-user / cookie persistence, explicit locale whitelist, six-step resolution chain.
Install
composer require prunacatalin/filament-locale-switcher
Publish the config (optional — the plugin works without it, but config is the recommended source of truth):
php artisan vendor:publish --tag=filament-locale-switcher-config
If you intend to persist the user's choice on their account, run the migration to add a locale column to users:
php artisan migrate
Configure
config/filament-locale-switcher.php:
return [ 'locales' => ['en', 'ro', 'fr', 'it'], 'labels' => [ 'en' => 'English', 'ro' => 'Română', 'fr' => 'Français', 'it' => 'Italiano', ], 'flags' => [ 'en' => '🇬🇧', 'ro' => '🇷🇴', 'fr' => '🇫🇷', 'it' => '🇮🇹', ], 'persist' => 'user', // session | user | cookie 'user_column' => 'locale', // column on User when persist=user 'placement' => 'topbar', // topbar | user-menu | both 'topbar_offset' => '4.5rem', // CSS gap between switcher and user-menu ];
Wire it into your panel
Two lines: register the plugin, append the middleware to your panel middleware list (it MUST run after StartSession).
use Prunacatalin\FilamentLocaleSwitcher\Http\Middleware\ApplyLocale; use Prunacatalin\FilamentLocaleSwitcher\LocaleSwitchPlugin; public function panel(Panel $panel): Panel { return $panel // …your usual config… ->plugin(LocaleSwitchPlugin::make()) ->middleware([ // …default Filament middleware (EncryptCookies, StartSession, …)… ApplyLocale::class, ]); }
That's it. The plugin reads from config/filament-locale-switcher.php; the dropdown renders in the panel topbar; clicking a flag persists the choice and reloads the current page in that language.
Per-panel override
Every config key has a matching fluent setter. Useful when a single Laravel app hosts two panels with different policies:
$panel->plugin( LocaleSwitchPlugin::make() ->locales(['en', 'de']) // narrower than the global list ->persist('cookie') // override global persist ->placement('user-menu'), // override global placement );
Setters always win over config.
Resolution chain (per request)
?lang=xxquery parameter- session value (last switch in this browser)
- cookie (when
persist=cookie) - authenticated user's column (when
persist=user) Accept-Languageheaderconfig('app.locale')
Anything outside the configured locales whitelist is rejected — tampered session/cookie values can never load an arbitrary lang path.
Testing
composer install
composer test
Pest suite uses Orchestra Testbench with SQLite :memory:. 21 tests / 39 assertions cover the resolver chain, the plugin's config hydration, the middleware, and every controller persistence branch.
License
MIT.