niels-numbers/laravel-localizer
Locale-aware routing for Laravel and a successor to mcamara/laravel-localization. Registers every route twice as static routes for route:cache support, auto-detects Accept-Language, redirects visitors, and resolves route() per language.
/about, /de/about) are the cheapest way to open new markets: one codebase, one deploy, no per-market infrastructure. This package makes that decision reversible — you can launch a second locale in a sprint rather than a quarter, and kill it if the market doesn't convert without unwinding routing work./en/about vs /about), and whether localized segments are translated (/ueber vs /de/about), are SEO and brand decisions with measurable traffic impact. hide_default_locale and Route::translate() give you those levers as config rather than a rewrite.Route::localizedUrl() produces canonical hreflang alternates and sitemap entries per locale. This is the single highest-leverage item in an internationalization roadmap and is normally the thing teams forget until after launch.route() resolution per locale, and route:cache compatibility is 2–4 engineer-weeks plus permanent maintenance of a subtle, edge-case-heavy subsystem. This is buy territory — the domain logic is commodity, the failure modes are not obvious, and getting redirects wrong silently damages SEO for months.mcamara/laravel-localization is marked abandoned in Composer with this package registered as its replacement (merged by the original maintainer). Teams on the legacy package face a forced decision; this converts it into a scheduled, documented migration with a guide, rather than an unplanned one.setActiveLocales() and setActiveDefaultLocale() let locale availability be a per-tenant, per-plan entitlement at runtime without breaking route:cache or leaking state across Octane workers. That makes "which languages does this customer get" a product/pricing question, not an engineering one.route('about') stays locale-correct in JS, so Inertia/Vue/React SPAs don't need a parallel hand-rolled URL layer — affects whether the team can reuse one routing mental model across stack.RedirectLocale skips non-safe methods (POST/PUT/PATCH/DELETE) to avoid 302→GET body loss, and preserves query strings across redirects. This matters for conversion funnels and campaign attribution — silently dropped UTMs or converted POSTs would corrupt experiment data.Accept-Language, session and cookie makes "we respect the user's language" a defensible default posture rather than a manual switcher-only experience.Adopt when:
mcamara/laravel-localization, or starting greenfield and know a second locale is on the roadmap within 12 months.php artisan route:cache is or will be part of your deploy — the double-registered static-route design is the package's core differentiator, and most alternatives break here.route() to behave identically in PHP and JS.Look elsewhere when:
de.example.com) or ccTLD (example.de) strategies — this is prefix-oriented; forcing it is a fight against the grain.lang/ files plus a locale middleware cover you; routing complexity here is overhead.spatie/laravel-typescript-transformer for route manifests — explicitly flagged as incompatible; route:list and Ziggy work, this generator does not.Mitigations if you adopt anyway: pin an exact version, wrap Route::localize()/Route::translate() usage behind your own route-file convention so a swap is a one-file change, and add a redirect/canonical integration test suite so a package upgrade can't silently regress SEO.
For executives — the one paragraph: Localizing our product currently costs an estimated 3–4 engineer-weeks plus ongoing upkeep of a fiddly subsystem (redirects, canonical URLs, SEO tags) that delivers no differentiated value. This MIT-licensed package, the designated successor to the widely used mcamara/laravel-localization, gives us that capability as configuration: launch a new language market by adding a config entry and translated route file, with correct SEO hreflang handled for us. It's free, MIT-licensed, and already running on the Laravel versions we use. The trade-off is a young, single-maintainer project — so we adopt it behind a thin internal wrapper and a test suite, capping our switching cost at roughly one engineer-day if we ever walk away.
For engineering — why it's not a toy:
route:cache works in production. That is the specific reason the previous generation of packages caused pain.{locale} stripped from the parameter bag so controller signatures stay clean.setActiveLocales, setActiveDefaultLocale) is Octane-safe and route:cache-safe — this is not the kind of thing we'd get right on the first attempt in-house.For the risk register: low code risk, moderate supply-chain risk. 40 stars and zero dependents mean no ecosystem stress-testing; a single maintainer means bus-factor 1. We accept that knowingly, contain it with a version pin and a wrapper, and revisit if the project goes quiet for more than two release cycles or if we need subdomain/ccTLD routing, which this package does not target.
How can I help you explore Laravel packages today?