
Laravel i18n: Complete Internationalization & Localization Guide
From first locale file to production: configure Laravel's translation system, handle pluralization, fix the JSON fallback bug, and add smart locale fallback chains for regional variants.
Understand Laravel's Translation System
Laravel ships with a built-in translation system that supports two file formats: PHP arrays and JSON. PHP files use nested keys organized by feature (auth.failed, validation.required). JSON files use the source string as the key, which is simpler but doesn't support nesting.
composer create-project laravel/laravel my-app
cd my-app
# Laravel includes i18n out of the box
# No extra packages needed for basic usageConfigure Locale Settings
Set your application's default locale and fallback locale in config/app.php. The fallback locale is used when a translation key is missing from the active locale. Configure supported locales for your application and add middleware to detect and set the user's preferred locale.
// config/app.php
return [
'locale' => 'en', // Default locale
'fallback_locale' => 'en', // Fallback when key is missing
'faker_locale' => 'en_US',
// Available locales (for your language switcher)
'available_locales' => ['en', 'de', 'ja', 'es', 'fr', 'pt-BR'],
];// app/Http/Middleware/SetLocale.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class SetLocale
{
public function handle(Request $request, Closure $next)
{
$locale = $request->segment(1); // e.g. /de/about
if (in_array($locale, config('app.available_locales'))) {
app()->setLocale($locale);
}
return $next($request);
}
}Use Translation Functions
Laravel provides three ways to translate strings: the __() helper function (recommended), the trans() function, and the @lang Blade directive. All three accept the translation key and optional replacement parameters. Use __() in PHP code and Blade templates, and @lang in Blade when you don't need to escape HTML.
// lang/en/messages.php
return [
'welcome' => 'Welcome to our application',
'greeting' => 'Hello, :name!',
'nav' => [
'home' => 'Home',
'about' => 'About',
'settings' => 'Settings',
],
];
// lang/de/messages.php
return [
'welcome' => 'Willkommen in unserer Anwendung',
'greeting' => 'Hallo, :name!',
'nav' => [
'home' => 'Startseite',
'about' => 'Über uns',
'settings' => 'Einstellungen',
],
];Handle Pluralization
Laravel uses a pipe-separated syntax for plural forms. The simplest form is 'apples' => 'There is one apple|There are many apples'. For explicit ranges, use 'apples' => '{0} No apples|{1} One apple|[2,*] :count apples'. The trans_choice() helper or Str::plural() selects the correct form based on the count.
// lang/en.json
{
"Welcome back!": "Welcome back!",
"You have :count new notifications": "You have :count new notifications",
"Copyright :year :company": "Copyright :year :company"
}
// lang/de.json
{
"Welcome back!": "Willkommen zurück!",
"You have :count new notifications": "Sie haben :count neue Benachrichtigungen",
"Copyright :year :company": "Copyright :year :company"
}Add Locale Fallback Chains
Laravel's built-in fallback only goes from the active locale to fallback_locale — there is no intermediate step. A pt-BR user with a missing key sees English instead of the perfectly good pt-PT translation. laravel-locale-chain fixes this by deep-merging translations from a configurable fallback chain at load time.
{{-- Simple translation --}}
<h1>{{ __('messages.welcome') }}</h1>
{{-- With variables --}}
<p>{{ __('messages.greeting', ['name' => $user->name]) }}</p>
{{-- Using @lang directive --}}
<h2>@lang('messages.nav.home')</h2>
{{-- JSON translations (use the string itself as key) --}}
<p>{{ __('Welcome back!') }}</p>
{{-- Pluralization --}}
{{ trans_choice('{0} No items|{1} One item|[2,*] :count items', $count) }}
{{-- Inside Blade components --}}
<x-button>{{ __('messages.nav.settings') }}</x-button>Automate Translations
With your Laravel i18n setup complete, translate your locale files using AI. Point your AI assistant at the source locale file, or use the i18n Agent CLI in your CI/CD pipeline. Both PHP and JSON translation files are supported.
// Install locale chain package
composer require i18n-agent/laravel-locale-chain
// config/locale-chain.php
return [
'chains' => [
'pt-BR' => ['pt-BR', 'pt', 'en'],
'zh-Hant-TW' => ['zh-Hant-TW', 'zh-Hant', 'zh', 'en'],
'es-419' => ['es-419', 'es', 'en'],
],
];
// In AppServiceProvider::boot()
use I18nAgent\LocaleChain\LocaleChainServiceProvider;
// The package automatically deep-merges translations
// across the chain: pt-BR -> pt -> enCommon Pitfalls
Hardcoded Singular/Plural Logic
JSON Translations Don't Fall Back
Mixing PHP and JSON Without Understanding Precedence
Try i18n Agent Now
Drop your translation file here
JSON, YAML, PO, XML, CSV, Markdown, Properties
or click to browse
Target languages