liberusoftware/localization-core-livewire
Livewire components for Liberu Localization Core, providing reactive language switching, translation management, and locale-aware UI bindings inside Laravel Livewire apps. Drop-in components keep multi-language content in sync without full page reloads.
Install the adapter and its core dependency together. The presentation layer does nothing on its own — locale resolution, persistence, and negotiation live in liberusoftware/localization-core:
composer require liberusoftware/localization-core liberusoftware/localization-core-livewire
Confirm the service provider is registered. On Laravel 11+ check bootstrap/providers.php; on older versions check config/app.php. The adapter's provider is what registers the Livewire component alias, so if the component 404s, this is the first thing to verify.
Read these three files before writing any code, in this order:
vendor/liberusoftware/localization-core-livewire/src/*ServiceProvider.php — shows the component alias and any view namespace.$locales, $current) and the action method (switch, setLocale, etc.).Publish config/views only if you need to customize (see Gotchas):
php artisan vendor:publish --provider="Liberu\\Localization\\Core\\Livewire\\...ServiceProvider"
First use case: a language switcher in the top nav. Drop the component into resources/views/layouts/app.blade.php:
<livewire:localization-core-livewire::locale-switcher />
If that alias doesn't resolve, run php artisan livewire:list (Livewire 3) and use the exact name the package registered. Don't guess from the composer name — the alias and namespace rarely match verbatim.
Layout slot, not page-level. Register the switcher once in the layout so every page gets it. Avoid placing it inside Livewire components, because the switch will re-render nested components and can leave stale translated strings in the DOM (see Gotchas).
Let the core own state; the adapter owns the click. Your component's job is to call the core's locale manager and then redirect. Pattern:
public function switch(string $locale)
{
app(\Liberu\Localization\Core\LocaleManager::class)->set($locale);
return redirect()->to(request()->header('Referer') ?? '/');
}
If the package already does this, don't duplicate it — call the component's method from wire:click and only override when you need custom behavior.
Resolve precedence explicitly. In a typical Liberu setup locale can come from URL segment, session, cookie, or Accept-Language. Decide the order once (URL > session > default is common) and rely on the core middleware for it. The switcher should never guess; it should just write to the session through the core and let middleware handle the next request.
URL-prefixed locales need a redirect, not a component refresh. If your app uses /{locale}/... routes, a Livewire action can't rewrite the current URL by itself. In the component, build the localized URL via the core's route helper (or route() with a locale parameter) and redirect()->to($url). Do not just re-render.
React to the change elsewhere with events. The adapter usually dispatches something like locale-changed. Use it in other Livewire components:
#[On('locale-changed')]
public function refreshTranslations() { /* re-read labels */ }
Be aware this only refreshes Livewire-managed content; static Blade strings still need a full page load.
Custom UI, same behavior. Publish the view (--tag=localization-core-livewire-views or the tag listed in the provider) and replace the <select> with an Alpine dropdown, flag icons, or a x-dropdown. Keep the same wire:click / wire:model bindings so the package's method still runs. This is the highest-leverage customization point in the whole package.
Restrict the list without forking. Filter locales in a wrapper component or in the passed-in property:
<livewire:localization-core-livewire::locale-switcher :locales="['en','fr','de']" />
If the component doesn't accept a locales prop, that's a signal to publish the view and read from config('localization-core.supported') yourself.
Multi-tenant / user-preference flows. For "remember my language" functionality, listen to the same event from a small listener and persist the value to users.locale. On login, have the core resolver read the user column before the session — the adapter doesn't need to know about it.
Testing. Component tests are cheap and catch regressions when you upgrade:
Livewire::test(LocaleSwitcher::class)
->call('switch', 'fr')
->assertRedirect();
$this->assertSame('fr', session('locale'));
Add a feature test that hits a page after switching and asserts translated content, since the session-only test won't catch middleware ordering bugs.
The switch takes effect on the next request. app()->setLocale() inside a Livewire action only changes the current request; already-rendered Blade output is untouched. Always end the action with a redirect (or a full location.reload()), and don't try to make the switcher feel "instant" with wire:navigate unless you've verified translations actually refresh. This is the #1 source of "it changed but nothing changed" reports.
wire:navigate can preserve stale content. Turbo-like navigation swaps the body but may reuse cached snapshots. Test switching between two locales on a page with lots of translated text. If it fails, drop wire:navigate on links surrounding the switcher or dispatch a full reload after the locale is set.
Session key conflicts. If you already have a locale session key from older code, the core's resolver may fight with it. Pick one owner. Check session()->get('locale') in php artisan tinker after a switch to confirm the package wrote what you expect.
Config cache is easy to forget. Publish the config, edit locales, then php artisan config:cache — otherwise you'll debug a list that never changes in production but works locally.
Namespace ≠ package name. The composer name is liberusoftware/localization-core-livewire, but the PHP namespace and Livewire alias will differ (likely Liberu\Localization\Core\Livewire\... and something like localization-core-livewire::locale-switcher). Resolve the real names from the provider's boot() method rather than copying snippets from elsewhere.
Livewire 2 vs 3 differences. $emit/$dispatch, wire:model vs wire:model.live, and component auto-discovery changed. If livewire:list doesn't show the component, check the installed Livewire major. The package may target one version only — check composer.json constraints before upgrading Livewire.
Low-signal package. Zero stars, zero dependents, no Stack Overflow footprint. Treat the source as the only documentation, pin the exact version in composer.json, and add your own smoke test. If the README and the code disagree, the code wins.
Extension points, ranked by safety:
Livewire::component('localization-core-livewire.locale-switcher', MySwitcher::class); in a service provider.LocaleManager contract is too restrictive.Debugging checklist when nothing renders:
php artisan livewire:list — is the component there?php artisan about — is the service provider in the list?app()->getLocale() inside a simple route after a switch — confirms whether the issue is the switcher or the resolver.web group; without it, the session value is written but never applied.Don't rely on the adapter for translation storage. If you need per-locale content, route JSON translations, or model translations, use the core package directly. This adapter is deliberately thin; extending it usually means extending core instead.
How can I help you explore Laravel packages today?