1
votes

I'm trying to create a website with multiple languages (with Laravel 5.5). Therefore I follow the tutorial https://mydnic.be/post/how-to-build-an-efficient-and-seo-friendly-multilingual-architecture-for-your-laravel-application, but somehow I have troubles with the language middleware part:

// BeforeLanguage.php 

namespace App\Http\Middleware;

use Closure;

class BeforeLanguage
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // Check if the first segment matches a language code
        if (!array_key_exists($request->segment(1), config('translatable.locales')) ) {

            // Store segments in array
            $segments = $request->segments();

            // Set the default language code as the first segment
            $segments = array_prepend($segments, config('app.fallback_locale'));

            // Redirect to the correct url
            return redirect()->to(implode('/', $segments));
        }

        return $next($request);
    }
}

It works if I open a URL with the identifier for the language, e. g. http://ps.dev/de/app/login but I get "Sorry, the page you are looking for could not be found." if I try to open the page without the language identifier in the URI, e. g. http://ps.dev/app/login.

But here I would expect that the middleware adds the language segment to the URI. Any idea what could go wrong?

Below I would like to provide some additional information.

web.php

Route::prefix('app')->group(function () {

    // Authentication routes
    Route::get('login', 'SessionsController@create')->name('login');

    // ...
});

Kernel.php

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\BeforeLanguage::class,
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        'throttle:60,1',
        'bindings',
    ],
];

According to the Laravel documentation page the middlewares assigned to the middleware group web get executed by default for any route defined inside web.php. (Out of the box, the web middleware group is automatically applied to your routes/web.php file by the RouteServiceProvider.)

RouteServiceProvider.php

protected function mapWebRoutes()
{

    $locale = Request::segment(1);

    Route::prefix($locale)
        ->middleware('web')
        ->namespace($this->namespace)
        ->group(base_path('routes/web.php'));

}
2
You probably don't have a route for URLs without the language prefix. - tkausl
@tkausl Thanks for the quick response. You're right. I didn't define a route for URLs without language prefix. But if I understand it correctly I don't need to define one as there is the BeforeLanguage Middleware that should take every request and add the language prefix in case its missing, but somehow the middleware does not get executed in my case. - Andreas
You mentioned it yourself, "According to the Laravel documentation page the middlewares assigned to the middleware group web get executed by default for any route defined inside web.php", this is your dilemma. As long as there is no route defined in web.php for the current URL, the middleware(-group) does not get executed. Laravel does not know which middlewares to run before it finds a route first. - tkausl
@tkausl hm... I am still struggling a bit. As you can see on the page that I refer to in my question the author states in terms of the language middleware: As you can see with above code, we recreate the whole URL path if the language code is missing. That way, you will always have a language defined. - Andreas
Check the comment section beneath the tutorial, there are multiple users with the same problem, maybe some of their suggestions works for you. - tkausl

2 Answers

3
votes

I think you had chosen a hard way something like "Reinvent the Wheel!" ;)

Although It's your decision and respectful, as a suggestion try this nice package for localization in Laravel :D

0
votes

The reason why it is sending to the 404 is that the url doesn't exist. In your route file, you have not created the paths for language. So ultimately, if your middleware works it will send to the non-existing route path, which will be 404.

Add an identifier for the language :-

Route::get('{lang}/login', 'SessionsController@create')->name('login');

Check you routes by the following artisan command in cmd

php artisan route:list