A simple approach to localization using middleware

We used this on a recent project and it worked great.

Joel Clermont
Joel Clermont
2023-11-28

Laravel gives you all the necessary pieces to create an application that works in multiple languages, but it doesn't prescribe all the details of how to implement it. That can be useful, because it provides ultimate flexibility, but it can also be a bit overwhelming if you're not sure where to start.

Here's a very simple middleware-based approach that we have used. Our goal was something that doesn't require code spread throughout the application, and that also allows you to include the desired language in any arbitrary URL, for example sending an email to someone in French and having the links load the site in French.

First, we need to create the files to hold our translation strings:

// resources/lang/en.json
{
    "Hello": "Hello"
}

// resources/lang/es.json
{
    "Hello": "Hola"
}

// resources/lang/fr.json
{
    "Hello": "Bonjour"
}

A real app would have many more translation strings, but we're keeping it simple for this example. Next, we need to create a middleware that will set the correct app locale based on a few pieces of information. First, it will check the URL for a querystring. If not present, it will check for a session value. If neither exists, it will default to a fallback language:

// app/Http/Middleware/Localization.php

public function handle(Request $request, Closure $next): Response
{
    $allowedLanguages = ['en', 'es', 'fr']; // you could also use an Enum or config file

    if (($language = $request->get('lang')) && in_array($language, $allowedLanguages)) {
        // a valid language was sent in the querystring - use it, and save for future use
        $request->session()->put('language', $language);
    } else {
        // otherwise use the session language or the fallback
        $language = $request->session()->get('language', config('app.fallback_locale'));
    }

    App::setLocale($language);

    return $next($request);
}

Register this middleware in app/Http/Kernel.php to enable it. Now, anywhere in a Blade file, we can use our translation string: {​{ __('Hello') }}

Accessing the URL without setting a lang querystring parameter will show it in the default language, as defined in the fallback_locale key in config/app.php.

Accessing the URL with a lang querystring parameter will show it in the specified language, and will also set the session value so that future requests will use that language. If some unexpected language is requested, it will use the fallback language.

You can imagine extending this middleware further to using the Accept-Language header. You could also add a language selector to the UI that sets the lang querystring parameter. Even with additional features like that, all the locale-setting logic can live in this one simple middleware, and not get spread across your routes and controllers.

Here's a sample repository showing a full working example.

Here to help,

Joel

P.S. Even in this simple middleware example, we don't forget validation. We truly believe validation is an extremely important part of any Laravel app.

Toss a coin in the jar if you found this helpful.
Want a tip like this in your inbox every weekday? Sign up below 👇🏼

Level up your Laravel skills!

Each 2-minute email has real-world advice you can use.