Reputation: 899
I am trying to set up localization in a laravel app but my middleware seems to be causing an ERR_TOO_MANY_REDIRECTS
error. The site is going to differ per region slightly and I am using the laravel lang/
files to swap out phone numbers etc. This works okay. When I change my locale I get the correct numbers from the lang files. And when I just have the middleware to check if the cookie has been set to set the locale that works too.
I also have middleware to forget the prefix on localised routes so I don't have to update my methods with a locale parameter.
My issue is setting a url prefix if a cookie has been set with an allowed locale in my middleware. I also want to ignore the prefix if the locale is 'en' as it will be default.
Below is the code for everything
routes/web.php
Route::get('/', 'HomeController@index')->name('home');
Route::get('/reader/{identifier}', 'ReaderController@show')->name('reader');
Route::get('/locale/{locale}', SetLocaleController::class)->name('set.locale');
Route::group(['prefix' => '{locale?}', 'where' => ['locale' => implode('|', array_keys(config('app.allowed_locales')))], 'middleware' => 'redirect.localization'], function () {
Route::get('/', 'HomeController@index')->name('home');
Route::middleware('forget.prefix')->get('/reader/{identifier}', 'ReaderController@show')->name('reader');
});
Middleware/Localization.php
- This is added to the web middleware group in Kernel.php
. It checks for a cookie and sets the locale and should redirect to the proper locale prefix. If no cookie is set then we get the users geo and set it.
public function handle($request, Closure $next)
{
// Get requested url
$segments = collect($request->segments());
if ($segments->count() && Arr::exists(config('app.allowed_locales'), $segments[0])) {
$segments->shift();
}
$locale = Cookie::get('locale');
if ($locale ?? false) {
// Set the app locale.
App::setLocale($locale);
if ($locale != 'en') {
$segments->prepend($locale);
return redirect()->to($segments->implode('/'));
}
} else {
// Check for geo here and set it.
}
return $next($request);
}
Middleware/RedirectLocalization.php
- This middleware is only set on the route group for the prefix. It checks if the locale passed is allowed and the sets the locale and cookie. This is set in the $routeMiddleware
array in Kernel.php
public function handle($request, Closure $next)
{
$locale = $request->segment(1);
if (Arr::exists(config('app.allowed_locales'), $locale)) {
// Set the app locale.
App::setLocale($locale);
// Save app locale in a Cookie.
Cookie::queue(Cookie::make('locale', $locale, 525600));
}
return $next($request);
}
Controllers/SetLocaleController.php
- This is where the locale can be manually set from a menu on the site.
public function __invoke($locale, Request $request)
{
$redirectUrl = parse_url(url()->previous());
$segments = Str::of($redirectUrl['path'])->trim('/')->explode('/');
if (Arr::exists(config('app.allowed_locales'), $segments[0])) {
$segments->shift();
}
if (Arr::exists(config('app.allowed_locales'), $locale)) {
// Set the app locale.
App::setLocale($locale);
// Save app locale in a Cookie.
Cookie::queue(Cookie::make('locale', $locale, 525600));
// Add locale to segments for redirect.
if ($locale != 'en') {
$segments->prepend($locale);
}
} else {
// Set locale to current locale.
App::setLocale(config('app.fallback_locale'));
}
// Redirect back
return redirect()->to($segments->implode('/'));
}
Controllers/ReaderController.php
- Nothing out of the ordinary here but I wanted to add it to explain the forget.prefix middleware. If I don't add the forget.prefix middleware then the $reader param becomes the locale.
public function show($reader, Request $request)
{
$reader = Reader::find($reader);
return view('readers.show', [
'reader' => $reader
]);
}
Middleware/ForgetPrefix.php
- This middleware removes the prefix so we can access parameter in controller methods without having to add a $locale param to the method in the controller.
public function handle($request, Closure $next)
{
$request->route()->forgetParameter('locale');
return $next($request);
}
So my question is how can I set the URL prefix if the locale has been set in a cookie without getting the too many redirects error?
Upvotes: 1
Views: 562
Reputation: 899
So I found that my issue was coming from having the Middleware/Localization.php
added to the web middleware group. I added this middleware to $routeMiddleware
in Kernel.php
. Instead I only added the Middleware/Localization.php
to the default locale routes.
My updated web/routes.php
Route::group(['middleware' => 'localization'], function () {
Route::get('/', 'HomeController@index')->name('home');
Route::get('/reader/{identifier}', 'ReaderController@show')->name('reader');
});
Route::group(['prefix' => '{locale?}', 'where' => ['locale' => implode('|', array_keys(config('app.allowed_locales')))], 'middleware' => 'redirect.localization'], function () {
Route::get('/', 'HomeController@index')->name('home');
Route::group(['middleware' => 'forget.prefix'], function () {
Route::get('/reader/{identifier}', 'ReaderController@show')->name('reader');
});
});
// Switch Locale route
Route::get('/locale/{locale}', SetLocaleController::class)->name('set.locale');
Upvotes: 0