Articles

Laravel localization step-by-step guide, tutorial with examples

How to localize a Laravel project, how to develop a project in Laravel and make it usable in multiple languages. In this article we see how to work with translation files, create a language switcher and more with examples.

Laravel is an application designed to be local, to adapt to various languages ​​and cultures. Localization tailors internationalized applications to a specific language through translation.

Prerequisites

  • In this article we will refer to Laravel version 8.x;
  • To successfully follow this tutorial, you need to have the necessary knowledge of the PHP programming language and the Laravel framework.
  • Your domain is localhost. If not, replace localhost with your own domain name or IP address (depending on your installation).

Working with translation files

In Laravel, just like in many other frameworks, we can store translations for different languages ​​in separate files. There are two ways to organize Laravel translation files:

  • An older approach that stores files in the following location: resources/lang/{en,fr,ru}/{myfile.php};
  • A new approach that stores files in the following location: resources/lang/{fr.json, ru.json};

For languages ​​that differ by territory, you should name them directory/file of the language according to ISO 15897. For example, for British English you would use en_GB instead of en-gb. In this article, we'll focus on the second approach, but the same goes for the first (except for how translation keys are named and retrieved). 

Simple translations

Now, let's go to the resources/views/welcome.blade.phpfile and replace the contents of the bodytag with ours, like this:

<body class="antialiased">
    <div class="relative flex items-top justify-center min-h-screen bg-gray-100 dark:bg-gray-900 sm:items-center py-4 sm:pt-0">
        <div class="max-w-6xl mx-auto sm:px-6 lg:px-8">
            <div class="flex justify-center pt-8 sm:justify-start sm:pt-0">
                Welcome to our website
            </div>
        </div>
    </div>
</body>

We'll start by preparing our localization welcome message, which is really easy in Laravel. All you have to do is replace the text “Welcome to our website” with the following code: {{ __('Welcome to our website') }}. This will instruct Laravel to display “Welcome to our website” by defaultdefinite and look for translations of this string if a language other than English is set (we'll get to that later). English will be set as the default languagedefinish of our app, so by default settingdefiAt the end we will simply display the text “Welcome to our website”. If the locale is different, we will try to find the matching translation and it will be created in a moment.

Laravel localization

But how does Laravel know which is the current language or which languages ​​are available in the application? It does this by looking at the local configuration in the app config/app.php. Open this file and look for these two associative array keys:

/*
|--------------------------------------------------------------------------
| Application Locale Configuration
|--------------------------------------------------------------------------
|
| The application locale determines the default locale that will be used
| by the translation service provider. You are free to set this value
| to any of the locales which will be supported by the application.
|
*/
'locale' => 'en',
/*
|--------------------------------------------------------------------------
| Application Fallback Locale
|--------------------------------------------------------------------------
|
| The fallback locale determines the locale to use when the current one
| is not available. You may change the value to correspond to any of
| the language folders that are provided through your application.
|
*/
'fallback_locale' => 'en',

The descriptions shown above the keys should be self-explanatory, but in short, the key locale contains the local predefinish of your application (at least, if no other locale has been set in the code). And the fallback_locale it is activated in case we set a non-existent locale in our application.

While we have this file open, let's add a new key for our convenience listing all the locales our application will support. We will use this later when adding a local switcher. However, this is an optional task as Laravel doesn't require us to do it.

/*
|--------------------------------------------------------------------------
| Available locales
|--------------------------------------------------------------------------
|
| List all locales that your application works with
|
*/
'available_locales' => [
  'English' => 'en',
  'Italian' => 'it',
  'French' => 'fr',
],

Now our application supports three languages: English, Italian and French.

Translation file

Now that we've established all the locales we'll be working with, we can go ahead and move on to translating our pre welcome messagedefinite.

Let's start by adding new localization files to the folder resources/lang. First, create a file resources/lang/it.json and add the corresponding translations, as follows:

{
  "Welcome to our website": "Benvenuto nel nostro sito web"
}

Next, create a file resources/lang/fr.json:

{

“Welcome to our website”: “Welcome to our site”

}

As you can see, we always refer to the pre messagedefinito that we added in the file welcome.blade.php (which was {{ __('Welcome to our website') }}). The reason why we don't have to create a file en.json it's because Laravel already knows which messages we pass by pre settingdefifinished at the function __() they are for our local predefinito en.

Local change in Laravel

At this point, Laravel doesn't know how to change locales, so for now, let's do the translations directly inside the path. Modify the welcome path predefinished as shown below:

Route::get('/{locale?}', function ($locale = null) {
    if (isset($locale) && in_array($locale, config('app.available_locales'))) {
        app()->setLocale($locale);
    }
    
    return view('welcome');
});

We can now visit our website, specifying any of the available languages ​​as the first path segment: for example, localhost/rulocalhost/fr. You should see the localized content. In case you specify an unsupported locale or don't specify a locale at all, Laravel will use enby defaultdefinita.

Middleware

Switching the locale for each site link may not be what you want, and it may not look as clean aesthetically. That's why we will do the language setting through a special language switcher and use the user session to display the translated content. Therefore, create a new middleware inside the app/Http/Middleware/Localization.phpfile or by running artisan make:middleware Localization.

<?php

namespace App\Http\Middleware;

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

class Localization
{
    /**
    * Handle an incoming request.
    *
    * @param  \Illuminate\Http\Request  $request
    * @param  \Closure  $next
    * @return mixed
    */
    public function handle(Request $request, Closure $next)
    {
        if (Session::has('locale')) {
            App::setLocale(Session::get('locale'));
        }
        return $next($request);
    }
}

This middleware will instruct Laravel to use the user selected locale if this selection is present in the session.

Since we need this to be done on every request, we also need to add it to the pre middleware stackdefifinished in app/http/Kernel.phpfor the webmiddleware group:

* The application's route middleware groups.
*
* @var array
*/
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\Localization::class, /* <--- add this */
  ],

Change course

Next, we need to add a path to change the locale. We're using a closure path, but you can use exactly the same code inside your controller if you like:

Route::get('language/{locale}', function ($locale) {
    app()->setLocale($locale);
    session()->put('locale', $locale);

    return redirect()->back();
});

Also, don't forget to remove the locale toggle previously added in our pre welcome pathdefinite:

Route::get('/', function () {
    return view('welcome');
});

Once this is done, the only way for the user to change the currently set language is by entering localhost/language/{locale}. The localeselection will be stored within the session and will redirect users to where they came from (check the Localizationmiddleware). To try it, go to localhost/language/ru(as long as your session cookie is present in your browser) and you will see the translated content. You can move around the website freely or try to refresh the page and see that the selected language is preserved.

The commutator

Now we need to create something that the user can click to change the language instead of manually entering local codes into the URL. To do this, we'll add a very simple language checker. Therefore, create a new resources/views/partials/language_switcher.blade.phpfile with the following code:

<div class="flex justify-center pt-8 sm:justify-start sm:pt-0">
    @foreach($available_locales as $locale_name => $available_locale)
        @if($available_locale === $current_locale)
            <span class="ml-2 mr-2 text-gray-700">{{ $locale_name }}</span>
        @else
            <a class="ml-1 underline ml-2 mr-2" href="language/{{ $available_locale }}">
                <span>{{ $locale_name }}</span>
            </a>
        @endif
    @endforeach
</div>

Include the newly created switcher in the "welcome" view:

<body class="antialiased">
    <div class="relative flex items-top justify-center min-h-screen bg-gray-100 dark:bg-gray-900 sm:items-center py-4 sm:pt-0">
        <div class="max-w-6xl mx-auto sm:px-6 lg:px-8">
            @include('partials/language_switcher')
            <div class="flex justify-center pt-8 sm:justify-start sm:pt-0">
                {{ __('Welcome to our website') }}
            </div>
        </div>
    </div>
</body>

Open the app/Providers/AppServiceProvider.phpfile and add the code to share when our language switcher will be composed. Specifically, we will share the current locale that can be accessed as a file {{ $current_locale }}.

Innovation newsletter
Don't miss the most important news on innovation. Sign up to receive them by email.

Advanced translation options in PHP Laravel

We will mainly work with resources/views/welcome.blade.php, so everything must happen in our welcome view unless otherwise specified.

Parameters in translation strings

For example, let's say hello to our imaginary user (Amanda) instead of just displaying a generic message:

{{ __('Welcome to our website, :Name', ['name' => 'caroline']) }}

Note that we used the name with the first letter in lowercase, but the placeholder with the first letter in uppercase. This way, Laravel can help you automatically capitalize the actual word. This will happen if the placeholder starts with an uppercase letter, for example, :Nameproduces “Caroline” or a fully capitalized word,  :NAME, produces “CAROLINE”.

We also update our translation files resources/lang/fr.jsonresources/lang/it.json , as at the moment we will only see the English version anywhere as the translation keys don't match the translations.

French:

{

   "Welcome to our website, :Name": "Bienvenue sur notre site, :Name"

}

Italian:

{

   "Welcome to our website, :Name": "Benvenuto sul nostro sito web, :Name"

}

Pluralization

To see pluralization in action, let's add a new paragraph of text. 

To perform pluralization, you must use the function trans_choice instead of __(), eg:

{{ __('Welcome to our website, :Name', ['name' => 'caroline']) }}
<br>
{{ trans_choice('There is one apple|There are many apples', 2) }}

As you can see, plural forms are separated by a |.

Now, what if we need multiple plural forms? 

This is also possible:

{{ trans_choice('{0} There :form no apples|{1} There :form just :count apple|[2,19] There :form :count apples', 24) }}

In this case, we allow numbers 01, And 219, and finally from 20 onwards. Of course, you can add as many rules as you need.

So what if we want the placeholders in our plural forms? 

{{ trans_choice('{0} There :form no apples|{1} There :form just :count apple|[2,19] There :form :count apples', 24, ['form' => 'is']) }}

We can also use the count passed in `trans_choice` if needed using a placeholder :count special:

{{ trans_choice('{0} There :form no apples|{1} There :form just :count apple|[2,19] There :form :count apples', 1, ['form' => 'is']) }}

Finally, don't forget to update your translation files with any changes you made to the base translation.

Italian:

{
  "Welcome to our website, :Name": "Benvenuto nel nostro sito, :Name",
  "{0} There :form no apples|{1} There :form just :count apple|[2,19] There :form :count apples": "{0} Nessuna mela|{1} C'è:count mela|[2,19] Ci sono :count mele"
}

French:

{    
  "Welcome to our website, :Name": "Bienvenue sur notre site, :Name",
  "{0} There :form no apples|{1} There :form just :count apple|[2,19] There :form :count apples": "{0} Il n'y a pas de pommes|{1} Il n'y :form :count pomme|[2,19] Il y :form :count pommes"
}

Working with localized dates in Laravel

To locate dates, we will harness the power of Carbon , which comes with Laravel by defaultdefinita. Check out the Carbon documentation ; you can do a lot of interesting things. For example, we can set our locale with date and time rules.

For our simple example, we'll show the current date localized for the selected language. In our routes/web.php, we update the welcome page path and pass the localized date message to ours view welcome:

<?php
Route::get('/', function () {
    $today = \Carbon\Carbon::now()
        ->settings(
            [
                'locale' => app()->getLocale(),
            ]
        );

    // LL is macro placeholder for MMMM D, YYYY (you could write same as dddd, MMMM D, YYYY)
    $dateMessage = $today->isoFormat('dddd, LL');

    return view('welcome', [
        'date_message' => $dateMessage
    ]);
});

Let's update resources/views/welcome.blade.php adding date display, like so:

{{ __('Welcome to our website, :Name', ['name' => 'amanda']) }}
<br>
{{ trans_choice('{0} There :form :count apples|{1} There :form just :count apple|[2,19] There :form :count apples', 1, ['form' => 'is']) }}
<br>
{{ $date_message }}

Trying to change the language on the home page of localhost, we will see that the dates are now localized, for example:

Formatting numbers and currencies with NumberFormatter

In different countries, people use different formats to represent numbers, for example:

  • United States → 123.123,12
  • France → 123 123,12

Therefore, to reflect these differences in your Laravel app, you can use NumberFormatter in the following way:

<?php
$num = NumberFormatter::create('en_US', NumberFormatter::DECIMAL);

$num2 = NumberFormatter::create('fr', NumberFormatter::DECIMAL);

You can also write the number in a particular language and display something like “one hundred twenty three thousand one hundred twenty three point one two”:

<?php
$num = NumberFormatter::create('en_US', NumberFormatter::SPELLOUT);
$num2 = NumberFormatter::create('fr', NumberFormatter::SPELLOUT);

In addition, NumberFormatter allows you to easily locate currencies, for example:

<?php
$currency1 = NumberFormatter::create('fr', NumberFormatter::CURRENCY);
$currency2 = NumberFormatter::create('en_US', NumberFormatter::CURRENCY);

So for fr you will see Euros, while for en_US the currency will be in US dollars.

Ercole Palmeri

Innovation newsletter
Don't miss the most important news on innovation. Sign up to receive them by email.

Latest Articles

The Benefits of Coloring Pages for Children - a world of magic for all ages

Developing fine motor skills through coloring prepares children for more complex skills like writing. To color…

May 2, 2024

The Future is Here: How the Shipping Industry is Revolutionizing the Global Economy

The naval sector is a true global economic power, which has navigated towards a 150 billion market...

May 1, 2024

Publishers and OpenAI sign agreements to regulate the flow of information processed by Artificial Intelligence

Last Monday, the Financial Times announced a deal with OpenAI. FT licenses its world-class journalism…

April 30 2024

Online Payments: Here's How Streaming Services Make You Pay Forever

Millions of people pay for streaming services, paying monthly subscription fees. It is common opinion that you…

April 29 2024