Localization in Laravel

In this post, I will go to explain how to localize a Laravel application. The application will support English, Spanish and Galician languages. This is a real example to translate the https://wptranslator.jesusamieiro.com web app. You can find the source code on GitHub.

The steps to localize the application will be:

  1. Create a configuration file to store the languages that will be used by the application.
  2. Define the default language for the application.
  3. Add the translation functions in the views.
  4. Create the JSON translation files.
  5. Create the middleware that updates the application language.
  6. Add the selector in the main view to enable the end-user to change the application language.
  7. Add the route for the change event of the previous selector.
  8. Add the controller to receive the change event from the previous selector.

Configuration file

The first step is to create the configuration file “config/locale.php” to store the languages that will be used by the application. The configuration will store:

  1. A “status” key to enable or disable the translation system.
  2. A “languages” key to store the different languages. In this value it will be stored:
    1. The 2 letters language code (ISO 639-1, list of codes).
    2. The 5 letters language code (RFC4646) (v.gr en_GB or es_ES). Usually, the first two letters identifies the language and the two last letters identify the country (ISO 3166-1 alpha-2).
    3. The third element indicates if the language uses RTL (right-to-left): true if it is RTL, false if it is not.
    4. The fourth element is the language name in the original language.
<?php
return [
    /*
     * Show language selector
     *
     * @var bool
     */
    'status' => true,

    /*
     * Available languages
     *
     * Add the language code to the following array
     * The code must have the same name as in the languages folder
     * Make sure they're in alphabetical order.
     *
     * @var array
     */

    'languages' => [
        /*
         * Key is the Laravel locale code
         * Index 0 of sub-array is the Carbon locale code
         * Index 1 of sub-array is the PHP locale code for setlocale()
         * Index 2 of sub-array is true if the language uses RTL (right-to-left)
         * Index 3 of sub-array is the language name in the original language
         */
        'en'    => ['en', 'en_US', false, 'English'],
        'es'    => ['es', 'es_ES', false, 'Español'],
        'gl'    => ['gl', 'es_ES', false, 'Galego'],
    ],
];

Default language

The default language is “English”. You can change it in the “config/app.php”, changing the locale element:

'locale' => 'en',

With the new language. For example, to put Spanish as the default language, you have to change to:

'locale' => 'es',

In my project, I will use “en” as the default language.

Translate the views

You have to use the __() helper in all strings that you want to localize in your views. This function translates the given translation string or translation key using your localization files. For example:

<nav class="navbar navbar-expand-md navbar-light navbar-secondary">
    <div class="container">
    {{  __('Download pretranslated .po files') }}
    </div>
</nav>

Translations

The translations are located in the “resources/language/” folder. Each language stores its translation strings in a JSON file. For example, the Spanish strings will be stored in the “es.json” file.

The content of the JSON file are key-value elements, where the key is the English string used in the __() helper and the value is the translation in the destination language.

For example, in the Spanish case, some of the content of the “es.json” file is:

{
    "About": "Acerca de",
    "License": "Licencia",

You have to translate all the strings to each destination language.

Middleware

Then I create a middleware, stored at “Http/Middleware/LocaleMiddleware”:

To create the middleware I execute the command above:

$ php artisan make:middleware LocaleMiddleware

Then I add the reference to this middleware in the $middlewareGroups variable located in the “app/Http/Kernel.php” file.

protected $middlewareGroups = [
    'web' => [
        \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,
        \App\Http\Middleware\LocaleMiddleware::class,
    ],

Each time the web browser makes a web request, this middleware is executed. The content of the middleware is:

public function handle($request, Closure $next)
{
// Locale is activated
if (config('locale.status')) {
if (Session::has('locale') &&
array_key_exists(Session::get('locale'), config('locale.languages'))) {
App::setLocale(Session::get('locale'));
} else
{
$userLanguages = preg_split('/[,;]/', $request->server('HTTP_ACCEPT_LANGUAGE'));
foreach ($userLanguages as $language) {
if (array_key_exists($language, config('locale.languages'))) {
// Set the Laravel locale
App::setLocale($language);
// Set php setLocale
setlocale(LC_TIME, config('locale.languages')[$language][1]);
// Set the locale configuration for Carbon
Carbon::setLocale(config('locale.languages')[$language][0]);
//Sets the session variable if it has RTL support
if (config('locale.languages')[$language][2]) {
session(['lang-rtl' => true]);
} else {
Session::forget('lang-rtl');
}
break;
}
}
}
}
return $next($request);
}

This middleware make this actions:

  1. Check if the translation is enabled: “locale.status” value from the config file.
  2. If there is a “locale” session variable and the language stored in this variable is in the config file, the middleware sets this language as the app language.
  3. If this session variable is not set, the middleware gets the “HTTP_ACCEPT_LANGUAGE” of the browser (see an example of this above using a Spanish Google Chrome) and sets the first language that finds in the config file.
array:11 [▼
  0 => "es-ES"
  1 => "es"
  2 => "q=0.9"
  3 => "en"
  4 => "q=0.8"
  5 => "pt"
  6 => "q=0.7"
  7 => "gl"
  8 => "q=0.6"
  9 => "en-US"
  10 => "q=0.5"
]

View selector

The user can change the application language with a selector. To do this you need a select in someplace.

<li class="nav-item">
    <select id="language" class="form-control rounded-0" name="language">
        @foreach(array_values(config('locale.languages')) as $language)
            <option value="{{$language[0]}}" @if ($language[0]===App::getLocale()) selected @endif>{{ $language[3]}}</option>
        @endforeach
    </select>
</li>

This code makes a select with all the languages in the config file.

You need to add a small Jquery script to detect a change in the selected language to call a controller that will change the application language.

<script type="application/javascript">
    $("#language").change(function () {
        window.location = './locale/' + $("#language").val();
    });
</script>

Route

To enable the previous script, you need to add one line in the web routes file, located at “routes/web.php”:

Route::get('/locale/{id}', 'HomeController@language');

Controller

To manage the JavaScript request, you need to add one method in the “app/Http/Controllers/HomeController.php”:

/**
 * Update the locale session variable and the app locale
 * 
 * @param Request $request
 * @param string $language
 * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 */
public function language(Request $request, string $language)
{
    try {
        if (array_key_exists($language, config('locale.languages'))) {
            Session::put('locale', $language);
            App::setLocale($language);
            return redirect()->back();
        }
        return redirect('/');
    } catch (\Exception $exception) {
        return redirect('/');
    }
}

This code receives a language strings, adding the “locale” session variable and the app locale if the received language value is in the config file.

Code

You can check the code in this public repository:

  1. Configuration file: locale.php
  2. Default language: app.php
  3. Translated views: app.blade.php and index.blade.php
  4. Translation files: es.json and gl.json
  5. Middleware file: LocaleMiddleware.php
  6. View selector: app.blade.php
  7. Route file: web.php
  8. Controller file: HomeController.php

More information

2 comments

  1. Fantástico ejemplo… e inspirador.

    Yo en la página de login uso un select de idiomas (estilo phpmyadmin) y en el Middelware incluyo:

    public function handle($request, Closure $next) {
    // Locale is activated
    $localecookie = $request->cookie(‘locale’);
    if (config(‘locale.status’)) {
    if (Session::has(‘locale’) &&
    array_key_exists(Session::get(‘locale’), config(‘locale.languages’))) {
    App::setLocale(Session::get(‘locale’));
    } else if($localecookie &&
    array_key_exists($localecookie, config(‘locale.languages’))){
    App::setLocale($localecookie);
    Session::put(‘locale’, $localecookie);
    } else {

    Además en el controlador:
    return redirect()->back()->withCookie(cookie(‘locale’, $language, 24*60*30));

  2. Me corrijo a mi mismo:

    if (config(‘locale.status’)) {
    $localecookie = $request->cookie(‘locale’);
    if (Session::has(‘locale’) &&

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.