Laravel localization - Setup multi-languages system

Localization is a way to manage multiple languages on your website. This article will walk you through how to set up localization in your website with Laravel 9 blade as well as with API. The way to do that is by attaching the language header and creating a middleware to intercept language to set the language according to what is passed by the language header.

Setup language files

In the resources/lang is where you put your localization file there. By default, Laravel will use the wrapper folder name as a way to identify the language.

resources/lang
	/en
		/welcome.php
	/kh
		/welcome.php

In resources/lang/en/welcome.php

<?php
 
return [
   'welcome' => 'Welcome'
];

In resources/lang/kh/welcome.php

<?php
 
return [
   'welcome' => 'សូមស្វាគមន៍'
];

Create middleware for languages

The middleware language will check if the request is an API request check the X-Language header and set Laravel locale. Otherwise, if the request is not API which means from view blade set Laravel locale by cookie instead.

Note: The Laravel locale is set on every request with middleware by cookie or header so the language change will be by the browser which is great when a user change language and it does not affect another user language.

php artisan make:middleware LanguageMiddleware

In app/Http/Middleware/LanguageMiddleware.php

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;

class LanguageMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse)  $next
     * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
     */
    public function handle(Request $request, Closure $next)
    {
        $locale = '';
        if ($request->expectsJson()) {
            $locale = $request->header('X-Language');
        } else {
            $locale = $request->cookie('X-Language');
        }
        // When there is wrong locale set to default english language
        if (!in_array($locale, ['en', 'kh'])) {
            $locale = 'en';
        }
     
        App::setLocale($locale);
        return $next($request);
    }
}

Set language middleware to kernel

In app/Http/Kernel.php add the language middleware to the middleware variable all the middleware in that variable will run at every request.

protected $middleware = [
        // \App\Http\Middleware\TrustHosts::class,
        \App\Http\Middleware\TrustProxies::class,
        \Fruitcake\Cors\HandleCors::class,
        \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        \App\Http\Middleware\CorsHeader::class,
        \App\Http\Middleware\LanguageMiddleware::class
    ];

As we use the cookie to store language when using with Laravel blade and by default Laravel automatically encrypts the cookie store in the browser so we need to ignore the language cookie to not encrypt. 

In the app/Http/Middleware/EncryptCookies.php

<?php

namespace App\Http\Middleware;

use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;

class EncryptCookies extends Middleware
{
    /**
     * The names of the cookies that should not be encrypted.
     *
     * @var array<int, string>
     */
    protected $except = [
        'X-Language'
    ];
}

Create language controller

The function setLang will set the language cookie to a browser with the redirect back. The expiration for the cookie will be a year.

php artisan make:controller LanguageController

In the app/Http/Controllers/LanguageController.php

<?php

namespace App\Http\Controllers;

class LanguageController extends Controller
{
    public function setLang($locale)
    {
        return back()->cookie('X-Language', $locale, 60 * 24 * 30 * 12);
    }

    public function welcome()
    {
        return view('welcome');
    }
}

Create view

Create a view for test language with Laravel blade.

In resources/views/welcome.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Welcome</title>
</head>
<body>
    <a href="{{ route('set.locale', ['locale' => 'en']) }}">
        <button>En</button>
    </a>
    <a href="{{ route('set.locale', ['locale' => 'kh']) }}">
        <button>Kh</button>
    </a>
    <p>{{ __('welcome.welcome') }}</p>
</body>
</html>

Web route

This sample has two routes first for redirecting to the welcome page to demonstrate the language switch. Second /languages/{locale} for switching the languages from Laravel views.

In the routes/web.php

<?php

use App\Http\Controllers\LanguageController;
use App\Http\Controllers\SampleController;
use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', [LanguageController::class, 'welcome'])->name('home');
Route::get('/languages/{locale}', [LanguageController::class, 'setLang'])->name('set.locale');

API

For API use __('welcome.welcome') where you want translation and on API request attaches the X-Language header.

Conclusion

The article will give you an implementation also the concept of how to handle multi-language with Laravel including with view as well as with API requests. Here is the step:

  • Setup languages 
  • Middleware for intercepting language
  • Register middleware to global middleware in kernel
  • Create language controller to handle language changes on view
  • Sample view for switching language usage