pmochine/laravel-tongue
Laravel Tongue is a lightweight localization package for Laravel that simplifies multilingual routes and language switching. Define translated URLs, detect and persist the visitor's locale, and serve localized content with minimal configuration.
Architecture fit. Laravel-Tongue is a localization/routing package that sits between Laravel's router and the application's URL strategy. The 6.1.0 release materially changes its architectural posture: dialect()->localizedRoutes() moves translated route registration from a runtime concern into a declarative, boot-time registration, which is what makes the route table serializable. That is the difference between "works in a dev environment" and "works behind route:cache and Laravel Octane." For any Laravel service that deploys with cached routes and/or runs on Octane — now the default posture for most production Laravel estates — prior versions were effectively disqualified. This release removes that disqualifier.
Integration feasibility. The public surface is small and framework-idiomatic: a dialect() helper, two middleware (detects-tongue, speaks-tongue), and a redirect() method with an optional status. There is no persistence layer, no queue integration, no external service dependency. The main integration surface is middleware ordering, which is a configuration concern rather than a code concern — cheap to adopt, cheap to reverse. The redirect() status-code argument is a small but useful escape hatch for teams that need 301/308 semantics for permanent locale canonicalization rather than the default behavior.
Technical risk. Three areas need scrutiny:
detects-tongue and speaks-tongue ahead of SubstituteBindings is listed under "Changed," not "Breaking," but it is behaviorally significant. Route model binding will now resolve translated slugs, and speaks-tongue will redirect before a failed binding can 404. Any application with custom binding logic, custom route keys, or middleware that previously sat between detection and binding will see different runtime behavior. This is the highest-risk item in the release and the one most likely to be under-tested by the package's own suite relative to a bespoke host app.speaks-tongue redirecting to "the path of the current locale" introduces a class of failure where detection and translation disagree — missing translation for a locale, a locale whose route was not registered, or a misconfigured default locale. Loop protection is not described in the notes and must be verified.Key questions.
bootstrap/app.php) as well as the legacy HTTP Kernel?localizedRoutes() require unique route names per locale, and if so what naming convention does it impose? Route-name collisions are a common failure when multiplying routes by locale.speaks-tongue when a translation is missing for the detected locale?route:cache and route matching at realistic scale (e.g., 200 routes × 12 locales)?route:cache in a way that is stable across builds (deterministic ordering), or can cache artifacts drift between deploys?Stack fit. Fits any Laravel app with a multi-locale URL strategy — subdomain (fr.example.com/bienvenue) or path-prefix — that currently has no clean story for cached or Octane-served translated routes. Poor fit for apps that deliberately keep locale in session/header only, and for headless/API services where redirect-on-locale is the wrong contract.
Migration path. Treat this as a two-step adoption, not one:
^6.1 and do not enable localizedRoutes() yet. Confirm the middleware reordering doesn't change existing behavior — specifically, run the existing binding and 404 test suite, because that's where the ordering change will surface.localizedRoutes() incrementally, starting with a low-traffic locale-partitioned group, then expanding. Keep the old dynamic registration path in place for groups not yet migrated so the rollout is per-route-group rather than big-bang.Compatibility. Two hard gates before merge: php artisan route:cache must succeed and the cached app must serve every locale correctly, and the Octane worker must survive octane:reload with translated routes intact. Add both to CI — a route-cache smoke test is the single highest-value guardrail for this package.
Sequencing.
^6.1, run full suite, diff middleware priority.localizedRoutes() per route group behind a config flag.speaks-tongue, and which status code (default vs. explicit 301/308 via redirect()).Maintenance. Low ongoing code maintenance — the package is a thin layer — but the configuration surface (middleware order, locale list, route registration) becomes load-bearing. Adding a locale is now a deploy-time event that rebuilds the route cache and requires an Octane reload; that must be documented as a runbook step, not discovered during a release.
Support. Expect support load concentrated in two buckets: "redirect loop after adding a locale" and "404 after deploy because route cache was stale." Both are preventable with a documented deploy checklist and a post-deploy smoke check hitting one translated URL per locale. Translated-slug correctness also becomes a content-ops dependency — missing translations now manifest as redirects or binding failures rather than a soft fallback.
Scaling. Route count scales linearly with locale count. A 250-route app at 12 locales becomes ~3,000 route entries in the cached table, affecting cold-start memory, route:cache artifact size, and route-match time. This is generally acceptable but should be measured before committing to a large locale set, and it argues for keeping API routes out of the localized set entirely. Octane amplifies the benefit (routes boot once) while also amplifying any nondeterminism in registration.
Failure modes.
Ramp-up. Modest for a mid-level Laravel developer — the API is small — but the conceptual load sits in middleware priority and route caching, which are exactly the areas many Laravel developers have never had to reason about. Budget half a day of team orientation covering: how localizedRoutes() registration interacts with route:cache, why middleware order matters for binding, and the redirect contract. Add one owner for the locale/redirect policy so SEO and product decisions don't drift from the technical implementation.
How can I help you explore Laravel packages today?