misaf/vendra-localization
misaf/vendra-localization is a Laravel package that adds localization support to Vendra applications, making it easier to manage locales, translations, and multilingual content. Install and configure it to add language switching and localized strings to your project.
Install and publish: composer require misaf/vendra-localization, then run php artisan vendor:publish --provider="Misaf\VendraLocalization\VendraLocalizationServiceProvider" (or the interactive vendor:publish prompt) to get the config file and the language stubs. Tags vary between releases — run php artisan vendor:publish without arguments first and pick the vendra-localization-* entries rather than guessing tag names.
Look here first, in this order:
config/vendra-localization.php — the supported-locale map, fallback, and detection order are almost always the only things you need to touch.Register the middleware. Laravel 11+: append it to the web group in bootstrap/app.php. Laravel 10: add the alias in app/Http/Kernel.php and place it in web after StartSession and ShareErrorsFromSession.
First use case: negotiate the request locale from Accept-Language, persist the user's choice in session, and let app()->getLocale() propagate to __(), validation messages, Blade, and Carbon. Verify in tinker:
app()->setLocale('pt_BR');
__('validation.required'); // should resolve from lang/pt_BR/validation.php
Smoke test the whole chain with a request that sends Accept-Language: pt-BR,pt;q=0.9,en;q=0.8 and assert both the rendered translation and the Content-Language header, otherwise you'll only discover negotiation bugs in production.
Accept-Language → fallback) in config instead of writing your own if chain in a controller.locale column to users, update it in a POST /locale/{locale} controller, and have your resolver read the authenticated user before falling back to Accept-Language. Validate the incoming locale against array_keys(config('vendra-localization.locales')) — never trust the raw string into setLocale()./{locale} group with a ->whereIn('locale', $supported) constraint driven by the same config array. Pair with URL::defaults(['locale' => app()->getLocale()]) in a middleware so route('posts.show', $post) keeps the prefix automatically.$product->name resolves against the current locale with a fallback. Keep one canonical column (name_en) for search/sort if you need indexed queries.<a href="{{ route('locale.switch', $code) }}">, and emit <link rel="alternate" hreflang="…"> tags from the same loop — a switcher without hreflang is half the SEO benefit.api without session writes, keyed strictly on Accept-Language, and echo the resolved locale back in Content-Language. This keeps caching predictable.$job->locale = app()->getLocale()) or wrap sends in Mail::locale($user->locale)->to(...).$this->withHeader('Accept-Language', 'pt-BR') and $this->assertSame('pt_BR', app()->getLocale()). Add a locale-switch feature test that posts an unsupported locale and asserts a 400/422 rather than a silent fallback.pt-BR, Laravel/PHP gettext directories use pt_BR. Normalize in one place (a small normalize() on your resolver) before it reaches setLocale() or your lang/ lookup.StartSession silently loses the persisted preference — you get "it works until you reload" reports. Also be aware that route-model binding for localized slugs needs the locale set before SubstituteBindings.config/vendra-localization.php on the server does nothing until php artisan config:cache is re-run. Conversely, after a package upgrade always run php artisan optimize:clear before debugging "the fix didn't apply."route:cache. Check php artisan route:cache in CI.__('checkout.title') returns checkout.title), not to your fallback locale. Ensure every key exists in the fallback file and add a test that diffs key sets between locales.app()->setLocale() is sticky; reset to config('app.fallback_locale') in tearDown() or you'll get order-dependent green builds.NumberFormatter and won't follow Laravel's locale automatically in every version — set it explicitly where formatting matters (invoices, exports).v1.10.0…v1.12.3), so two minor bumps are rolled into one upgrade: read the compare diff for new config keys, changed resolver contracts, and deprecations before bumping. Pin with "misaf/vendra-localization": "^1.12", republish config without --force (diff and merge manually), clear caches, then run your locale-negotiation and translation-coverage tests. Treat it as a feature release, not a patch — even though the version number ends in .3.LocaleChanged-style event to invalidate per-locale caches (menu caches, sitemaps, hreflang maps) instead of rebuilding them on every request.How can I help you explore Laravel packages today?