3

I'm working on a multilingual Laravel 12 app. All my routes are grouped under a {locale} prefix, like this:

Route::prefix('{locale}') ->group(function () { Route::get('/activities/{activity}', [ActivityController::class, 'show']) ->name('activities.show'); }); 

In my Localization middleware, I set the locale and define URL defaults:

<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\URL; use Symfony\Component\HttpFoundation\Response; /** * Middleware to set the application's locale based on URL parameter, user preference or session. */ class Localization { /** * Handle an incoming request and set the locale. * * @param Request $request The incoming HTTP request instance. * @param Closure(Request): Response $next The next middleware to call. */ public function handle(Request $request, Closure $next): Response { $locale = $request->route('locale') ?? optional(auth()->user())->language ?? session('locale', config('app.locale')); if (! array_key_exists($locale, config('app.available_locales'))) { $locale = config('app.locale'); } App::setLocale($locale); URL::defaults(['locale' => $locale]); session()->put('locale', $locale); return $next($request); } } 

I am getting this error with my controllers:

TypeError: App\Http\Controllers\ActivityController::show(): Argument #1 ($activity) must be of type App\Models\Activity, string given

My controller looks like this:

 /** * Display the details for a given activity. */ public function show(Activity $activity): View { abort_unless($activity->isPublished(), 404); return view('activities.show', [ 'activity' => $activity, 'title' => $activity->title, ]); } 

If I manually add Request $request or string $locale before $activity, it works - but I'd really prefer not to have to include $locale or $request in every controller action.

Middleware priority is correct: Localization runs before SubstituteBindings.

return Application::configure(basePath: dirname(__DIR__)) ->withRouting( web: __DIR__.'/../routes/web.php', commands: __DIR__.'/../routes/console.php', health: '/up', ) ->withMiddleware(function (Middleware $middleware): void { // Add Localization middleware to web group $middleware->web(append: [ Localization::class, ]); // Prioritize Localization middleware before SubstituteBindings $middleware->prependToPriorityList( before: SubstituteBindings::class, prepend: Localization::class, ); }) 

Is there a clean way to keep my {locale} route prefix and make implicit model binding work without adding $locale or $request to every controller method?

Is this a known limitation or am I missing something subtle?

Here is my LanguageController for better insight:

/** * Controller handling the application language switching. */ class LanguageController extends Controller { /** * Switch the application language. * * Handles changing the application language for both authenticated * and unauthenticated users. For authenticated users, it also updates their * language preference in the database. * * @param Request $request The HTTP request containing the locale. * @return RedirectResponse Redirects back to the previous page with the new locale. */ public function switch(Request $request): RedirectResponse { $validated = $request->validate([ 'locale' => ['required','string', Rule::in(array_keys(config('app.available_locales')))], ]); $newLocale = $validated['locale']; session()->put('locale', $newLocale); $prev = url()->previous(); $uri = Uri::of($prev); $segments = collect(explode('/', ltrim($uri->path(), '/'))); $available = array_keys(config('app.available_locales')); if ($segments->isNotEmpty() && in_array($segments->first(), $available, true)) { $segments[0] = $newLocale; } else { $segments->prepend($newLocale); } $newPath = '/'.$segments->implode('/'); $target = (string) $uri->withPath($newPath); return redirect()->to($target); } } 
2
  • I removed the general "best way" part from your question because without it, your problem is much more focused, and it would be a pity for the post to get closed because of that. There's no such thing as "the best" or "recommended" way - it always depends on the project, goals, and many other factors. When you ask questions like that, you'll often get a wide range of scattered answers that don't necessarily address your original problem. Commented Oct 25 at 8:54
  • Sadly, laravel's route binding requires the parameter on the controller. Are you open for other suggestions for this implementation without the prefix? Commented Nov 5 at 8:32

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.