Courses

Multi-Language Laravel: All You Need to Know

Working With Locales

When you show a translation string, Laravel needs to know what language to load, right? In tech terms, it's called "locale", and each Laravel project has the primary and the fallback locales.

In this lesson, we'll cover how to set them.


Setting The Locale

To set the default locale is simple - just open the config/app.php and modify the locale key:

config/app.php

'locale' => 'es',
// Or any other shortcode.
// It has to match with the `lang/FOLDER` folder name
// or the `lang/KEY.json` name.

This will be your application's default language for all users. Don't leave it as en if you are building an application with a different language.


Setting The Fallback Locale

In this example, we've set our application to use es as a default language, but it's missing some translations:

Translations will return the full key by default unless you set a fallback locale:

config/app.php

'fallback_locale' => 'en',

Then it will take the fallback language and load its text:

lang/en/auth.php

return [
// ...
'register' => 'Registration',
];

Which will result in the following:

Now we see that Register is used instead of the key. While this is not perfect because it's not in Spanish, it's better than showing the key to the user.


JSON Translations are Different

Now here's the catch for JSON file-based translations. They don't really have a fallback as you would expect. It will not go to the fallback language, rather it will just display the key output.

In the same scenario, I've used JSON files instead of .php files for translations and fallback did nothing. Here's what it did:

Changed the text to Registration:

lang/en.json

{
"Register": "Registration"
}

Configured the locale and fallback locale:

config/app.php

'locale' => 'es',
'fallback_locale' => 'en',

But this still displays Register instead of Registration that's defined in en language:

This is because JSON tried to look for a translated value in the es.json file, but it didn't find it. So it just displayed the key.

To illustrate this even more, let's say we are trying to look for:

<a href="{{ route('register') }}" class="ml-4 font-semibold text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-sm focus:outline-red-500">
{{ __('Register to Join our Community') }}
</a>

And we have a translation for this in en.json:

lang/en.json

{
"Register to Join our Community": "Sign up to join our community"
}

What do you think the output will be? "Sign up to join our community" or "Register to Join our Community". Since we have a translation fallback - we'd expect the Sign up... to be displayed. But it displays this:

We did not get what we expected as JSON doesn't look for fallback language or at least it doesn't do it in the same way as PHP files do.


Setting the Locale Dynamically in Code

For multi-language projects, the locale should be set by user preference or URL. Then we should use this code:

use Illuminate\Support\Facades\App;
 
// ...
 
if(! in_array($locale, ['en', 'es'])) {
abort(404);
}
 
App::setLocale($locale);
 
// ...

You would ask, where to place it?

This can be placed anywhere, but in my experience, it's best to place it in Middleware. We will cover a practical example of this later, in our lesson about UI-based Language switching.

In general, as soon as you start working with multi-language applications - you need to pick one language as your primary source of truth. This should become your fallback language. It will help you spot missing translations and will prevent users from seeing random translation keys.

No comments or questions yet...