Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Localization Core Laravel Package

liberusoftware/localization-core

Localization Core is a Laravel package offering foundational localization infrastructure for multi-language applications. It supports locale management and translation organization, giving developers a base for consistent localization across PHP projects.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require liberusoftware/localization-core
php artisan vendor:publish --tag=localization-core-config
php artisan migrate   # only if you opt into per-user preference storage

First look at config/localization-core.php — this is where supported locales, the default fallback, cookie/session keys, and UI-direction mappings live. If the package exposes a service provider under liberusoftware\LocalizationCore\LocalizationCoreServiceProvider, that file also tells you which middleware and Blade directives are registered.

First use case: resolving the active locale for a request. In bootstrap/app.php (Laravel 11+) or Kernel.php (Laravel 10), append the package middleware to the web group:

->withMiddleware(function (Middleware $middleware) {
    $middleware->web(append: [
        \LiberuSoftware\LocalizationCore\Http\Middleware\ResolveLocale::class,
    ]);
})

Then confirm resolution works from the tinker shell before touching views:

app()->getLocale();                       // should reflect the resolved request locale
localization()->supported();              // inspect the configured locale list
localization()->direction(app()->getLocale()); // "ltr" / "rtl"

If app()->getLocale() returns the config default rather than your browser/cookie locale, the middleware isn't running on that route — check the group before debugging anything else.

Implementation Patterns

Route-level locale propagation. The dominant pattern for this kind of package is a locale segment in the URL. Register a parameterised group and let the middleware bind it:

Route::prefix('{locale}')
    ->middleware(['web', 'localization.resolve'])
    ->whereIn('locale', config('localization-core.supported'))
    ->group(function () {
        Route::get('/', HomeController::class);
    });

Keep the canonical locale in the URL for SEO and shareability, and treat cookie/session/browser negotiation as a fallback only. Mixing both without a redirect strategy is where stale URLs creep in — pick one as authoritative.

Persisted user preference. When users change language in the profile page, update the preference record and reset the session key in the same request:

public function update(Request $request, UpdateLocaleAction $action)
{
    $action->handle($request->user(), $request->validated('locale'));

    return redirect()
        ->back()
        ->withCookie(cookie()->forever(config('localization-core.cookie')));
}

Preference should win over Accept-Language but lose to an explicit route segment. Encode that precedence in one place — usually the resolver's ordered strategies — rather than sprinkling if statements through controllers.

Propagation across jobs and notifications. Anything queued loses request context. Use the package's locale-aware job trait/interface (or wrap manually) so the worker rehydrates the right locale:

final class SendInvoice implements ShouldQueue
{
    use \LiberuSoftware\LocalizationCore\Queue\LocalizesJobs;

    public function __construct(public Invoice $invoice)
    {
        $this->captureLocale();   // stores app()->getLocale() on the payload
    }

    public function handle(): void
    {
        // app()->getLocale() is restored here
        Mail::to($this->invoice->user)->send(new InvoiceMail($this->invoice));
    }
}

For mails specifically, set the locale on the mailable or call App::setLocale($user->locale) in the notification's via/constructor — mailables are serialized, so the locale must travel with them.

UI direction. Drive dir and lang from a single view composer or layout variable rather than calling the resolver in every component:

<html lang="{{ str_replace('_', '-', app()->getLocale()) }}"
      dir="{{ localization()->direction(app()->getLocale()) }}">

If you use a component library (Tailwind, Flux, Filament), ensure logical properties (ms-*, me-*, ps-*, pe-*) are used in place of ml-*/mr-*; the package can only tell you the direction, not retrofit your CSS.

Testing. Assert locale resolution as a first-class behaviour — it's the easiest thing to break silently:

it('resolves the locale from the route segment', function () {
    $this->get('/fr/dashboard')->assertOk();
    expect(app()->getLocale())->toBe('fr');
});

Gotchas and Tips

  • Resolution order is the whole API contract. Before you write a single line of integration, read the resolver strategies (route → user → session → cookie → header → default) and treat that as immutable. Most "localization is broken" reports are a strategy firing earlier than the developer expected.
  • Cookies survive locale changes in the URL. A user who bookmarks /fr/... while holding an en cookie will see inconsistent behaviour if the middleware writes the cookie on every request. Decide whether an explicit route segment overwrites the stored preference — and document it.
  • Caching destroys per-request locale. If you use a full-page cache or responsecache, you must vary on locale. Add the locale to the cache key or the Vary header, otherwise the first visitor's language is served to everyone.
  • Accept-Language parsing is not trivial. de-AT,de;q=0.9 must map to a configured de if de-AT is unsupported. Verify the package falls back correctly rather than assuming; test with a two-tier header explicitly.
  • Pluralization and dates need locale, not just translation. Carbon::setLocale() and NumberFormatter/Intl use a different source of truth than Laravel's translator. Wire them in the same middleware or a small LocaleContext service; forgetting this leaves English date formats inside a French page.
  • Blade directives are resolved at compile time. If you add a directive like @direction, clear the view cache (php artisan view:clear) — a stale compiled view is a classic five-minute red herring.
  • Config caching hides new locales. php artisan config:cache must be re-run after editing supported. In CI this frequently makes locale tests fail locally-pass/CI-fail or vice versa.
  • RTL is more than dir="rtl". Icons with directional meaning (arrows, chevrons, progress bars) need explicit mirroring; the package's direction helper is a signal, not a solution.
  • Extension point: if the resolver isn't configurable enough, bind your own strategy implementation to the container rather than editing vendor code — the package's facade generally resolves through an interface, which is the intended seam for custom sources (e.g. tenant locale, subdomain mapping).
  • Zero-dependents reality check. With no downstream users, treat minor version bumps as potentially breaking; pin the version in composer.json and run your locale test suite after every update.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource