Laravel I18n Quickstart Guide

Laravel provides a lot of built-in i18n help, making it one of the easier frameworks to use when it comes time to localize your app.

Make sure you check out the full docs if you want a deep dive. This article is to get you up and running localizing your application in as short a time as possible.

Language files

Prior to Laravel 9, language files were stored in the /resources/lang directory. Laravel 9 moved them to /lang/. You can store your translation strings in either JSON or PHP files or use a mix of both. I find JSON translations files easier to work with for one big reason:

When you use JSON files, you use the default string in your views, like so:

{{ __('My name is Alice') }}

If you store your translation strings in PHP files, you'll give the strings a name to reference, so it would look like this in a Blade template:

{{ __('messages.name') }}

If you wanted to know what that referenced, you would need to open the language file. Some code editor extensions can show you the phrase on hover, but I find it much easier to just use JSON.

Use whatever you're comfortable with. But for ease of implementation and maintainability, I like JSON.

i18n File Naming and Structure

You can use any arbitrary string as a locale in Laravel. But, do yourself a favor and stick to ISO 639-1 codes with optional ISO 3166-1 country codes if needed. Laravel won't stop from using locale names like America or Mexico, but en and es-mx will make your life easier if you integrate with third party tools or use off-the-shelf UI components.

JSON

JSON files are stored in the lang/ root and named [LOCALE].json. For example,

lang/en.json
lang/es-mx.json

Structure is standard JSON:

{
    "default string": "translated value",
    "My name is Alice": "Me llamo Alice"
}

PHP

PHP files will be stored in [LOCALE]/[filename].php. For example,

lang/en/messages.php
lang/en/auth.php
lang/es-mx/messages.php
lang/es-mx/auth.php

And these files just return an array:

<?php
return [
  'string_name' => 'translated_value',
  'mynameis' => 'My llamo Alice',
];

Displaying Translations Strings

There's a whole lot of functions and blade directives you can use when displaying your translation strings. Since this is an opinionated guide, I'm going to recommend you stick with two Laravel helper functions: __ and trans_choice. We'll talk about trans_choice more in the section on pluralization.

__ can be used anywhere the string doesn't require pluralization rules (one apple vs two apples). In a blade template, that would look like this:

{{ __('My name is Alice') }}

You're not restricted to using these functions in your views. For example, you could translate the subject line of an email based on the app's locale.

<?php
/**

 * Build the message

 *

 * @return $this

 */

public function build

{

    return $this->from('example@example.com', 'Example')

        ->subject(__('Your order has shipped'))

        ->view('emails.orders.shipped');

}

Interpolating variables in your translation strings

We've been using the example string "My name is Alice" throughout this article. What if we want to change the name in that string based on the logged in user? Simple!

Just use a placeholder when you define the string by prefixing a variable name with a colon. It looks like this in JSON

{
    'My name is :name': 'Me llamo :name'
}

or in PHP:

<?php
return [
  'mynameis' => 'My llamo :name',
];

Then, when you display the phrase, the __ helper takes an optional second argument, like so:

{{ __('My name is :name', ['name' => 'Alice']) }}

Pluralization

Languages have all kinds of different pluralization rules. In fact, if you’re into this stuff and want a geeky side trip, the Unicode plural rules page is fascinating.

Even though dealing with pluralization rules isn’t always straightforward, Laravel handles it in a pretty simple way. Let’s look at an example in JSON.

{
	"{0} I have no apples|{1} I have one apple|[2,]I have :count apples": "{0} No tengo manzanas|{1} Tengo una manzana|[2,] Tengo :count manzanas",
}

Let’s break it down.

Different pluralizations are separated by vertical pipes, and begin with a count or range. The counts or ranges are optional, but they make everything more readable and you will need to do less later if you support a language with different pluralization rules.

Use the trans_choice function to display a pluralized phrase. trans_choice is similar to the __ helper we've been using, but it takes a count as its second argument to decide what to display.

  {{ trans_choice("{0} I have no apples|{1} I have one apple|[2,*]I have :count apples", 0) }} {{-- will output "No tengo manzanas" --}}

  {{ trans_choice("{0} I have no apples|{1} I have one apple|[2,*]I have :count apples", 1) }} {{-- will output "Tengo una manzana" --}}

  {{ trans_choice("{0} I have no apples|{1} I have one apple|[2,*]I have :count apples", 2) }} {{-- will output "Tengo 2 manzanas" --}}

The count you pass as the second argument to trans_choice is available in your phrases as :count.

Setting the App Locale

Laravel mostly leaves it up to you to implement locale switching, but it's really simple. Your app's default locale is set in config/app.php.

'locale' => 'en',

You can also set a fallback locale in config/app.php - a locale where translation strings will be loaded from if it can't find them in the current locale:

'fallback_locale' => 'en',

Anywhere you might use a non-default language - displaying a page or sending an email, for example - you need to call

<?php
use Illuminate\Support\Facades\App;
App::setLocale('es');

For views, the easiest way to do this is through a middlware. I like to store the user's chosen locale in the session and then just use a simple middleware

<?php
namespace App\Http\Middleware;

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

class SetLocale
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */

    public function handle(Request $request, Closure $next)
    {
        App::setLocale(Session::get('locale') ?? config('app.locale'));
        return $next($request);
    }

}

For logged in users, just store their chosen locale in the users table and pull it from there.

Translating Your Strings

Laravel makes i18n fairly painless. Now, you just need to hire translators, set up an interface for them to use and manually update your translation files every time you push a new feature.

OR

You could use TranslateCI and it will handle everything for you.