Building multilingual applications is essential for reaching a global audience. Laravel provides a robust localization system that makes it easy to retrieve strings in various languages. In this guide, we’ll explore Laravel’s localization features and how to implement them effectively in your applications.
Understanding Laravel Localization
Laravel’s localization features provide a convenient way to retrieve strings in various languages, allowing you to easily support multiple languages within your application. The framework supports two approaches for managing translation strings:
- PHP array files - Traditional approach using
.phpfiles with arrays - JSON files - Recommended for applications with many translatable strings
Setting Up Language Files
Directory Structure
Laravel stores language files in the lang directory. You can create this directory by running:
php artisan lang:publish
This creates the following structure:
/lang
/en
messages.php
validation.php
/es
messages.php
validation.php
en.json
es.json
PHP Array Files
PHP array files are ideal for organizing translations by feature or domain:
lang/en/messages.php:
<?php
return [
'welcome' => 'Welcome to our application!',
'goodbye' => 'Goodbye, see you soon!',
'user' => [
'profile' => 'User Profile',
'settings' => 'Account Settings',
'logout' => 'Log Out',
],
];
lang/es/messages.php:
<?php
return [
'welcome' => '¡Bienvenido a nuestra aplicación!',
'goodbye' => '¡Adiós, hasta pronto!',
'user' => [
'profile' => 'Perfil de Usuario',
'settings' => 'Configuración de Cuenta',
'logout' => 'Cerrar Sesión',
],
];
JSON Files
JSON files are recommended for applications with a large number of translatable strings. They use the default translation string as the key:
lang/en.json:
{
"Welcome to our application!": "Welcome to our application!",
"I love programming.": "I love programming.",
"The :attribute must be a valid email.": "The :attribute must be a valid email."
}
lang/es.json:
{
"Welcome to our application!": "¡Bienvenido a nuestra aplicación!",
"I love programming.": "Me encanta programar.",
"The :attribute must be a valid email.": "El :attribute debe ser un correo electrónico válido."
}
Configuring the Locale
Default Locale
Configure your application’s default locale in config/app.php or via the APP_LOCALE environment variable:
config/app.php:
'locale' => env('APP_LOCALE', 'en'),
'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),
.env:
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
Changing Locale at Runtime
You can change the locale dynamically for a single request:
use Illuminate\Support\Facades\App;
Route::get('/greeting/{locale}', function (string $locale) {
if (!in_array($locale, ['en', 'es', 'fr', 'de'])) {
abort(400);
}
App::setLocale($locale);
return view('greeting');
});
Getting Current Locale
Check the current locale or determine if it matches a specific language:
use Illuminate\Support\Facades\App;
// Get current locale
$locale = App::currentLocale();
// Check if locale is a specific language
if (App::isLocale('en')) {
// Handle English locale
}
Retrieving Translation Strings
Using the __() Helper
The most common way to retrieve translations:
// From PHP array file (lang/en/messages.php)
echo __('messages.welcome');
// Output: "Welcome to our application!"
// Nested keys
echo __('messages.user.profile');
// Output: "User Profile"
// From JSON file (using default string as key)
echo __('I love programming.');
// Output: "I love programming." (or translated version)
In Blade Templates
Use the {{ }} syntax in your Blade templates:
{{-- From PHP array file --}}
<h1>{{ __('messages.welcome') }}</h1>
{{-- From JSON file --}}
<p>{{ __('I love programming.') }}</p>
{{-- With @lang directive --}}
@lang('messages.goodbye')
Parameter Replacement
Laravel allows you to define placeholders in your translation strings:
Basic Parameters
lang/en/messages.php:
<?php
return [
'welcome' => 'Welcome, :name',
'greeting' => 'Hello, :Name! Welcome to :App.',
];
Usage:
echo __('messages.welcome', ['name' => 'John']);
// Output: "Welcome, John"
echo __('messages.greeting', ['name' => 'john', 'app' => 'Laravel']);
// Output: "Hello, John! Welcome to Laravel."
Capitalization
Placeholders automatically handle capitalization:
// :name - lowercase
// :Name - first letter capitalized
// :NAME - all uppercase
'welcome' => 'Welcome, :NAME', // "Welcome, JOHN"
'greeting' => 'Hello, :Name', // "Hello, John"
In Blade Templates
<p>{{ __('messages.welcome', ['name' => $user->name]) }}</p>
<p>{{ __('messages.greeting', ['name' => auth()->user()->name, 'app' => config('app.name')]) }}</p>
Pluralization
Laravel provides powerful pluralization support for handling different quantity forms:
Basic Pluralization
Use the | character to separate singular and plural forms:
lang/en/messages.php:
<?php
return [
'apples' => 'There is one apple|There are many apples',
'notifications' => '{0} No notifications|{1} One notification|[2,*] :count notifications',
];
Using trans_choice()
echo trans_choice('messages.apples', 1);
// Output: "There is one apple"
echo trans_choice('messages.apples', 5);
// Output: "There are many apples"
echo trans_choice('messages.notifications', 0);
// Output: "No notifications"
echo trans_choice('messages.notifications', 1);
// Output: "One notification"
echo trans_choice('messages.notifications', 10);
// Output: "10 notifications"
Advanced Pluralization Rules
Define multiple ranges for complex pluralization:
'items' => '{0} No items|[1,5] A few items|[6,10] Several items|[11,*] Many items',
Pluralization with Parameters
Combine pluralization with parameter replacement:
lang/en/messages.php:
<?php
return [
'minutes_ago' => '{1} :value minute ago|[2,*] :value minutes ago',
'cart_items' => '{0} Your cart is empty|{1} You have :count item in your cart|[2,*] You have :count items in your cart',
];
Usage:
echo trans_choice('messages.minutes_ago', 5, ['value' => 5]);
// Output: "5 minutes ago"
echo trans_choice('messages.cart_items', 3);
// Output: "You have 3 items in your cart"
In Blade Templates
<p>{{ trans_choice('messages.notifications', $notificationCount) }}</p>
<p>{{ trans_choice('messages.cart_items', $cartItems->count()) }}</p>
Building a Language Switcher
Create a language switcher for your application:
Route Setup
routes/web.php:
Route::get('/language/{locale}', function (string $locale) {
if (!in_array($locale, ['en', 'es', 'fr', 'de'])) {
abort(400);
}
session()->put('locale', $locale);
return redirect()->back();
})->name('language.switch');
Middleware
Create middleware to set the locale from session:
app/Http/Middleware/SetLocale.php:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
class SetLocale
{
public function handle(Request $request, Closure $next)
{
if (session()->has('locale')) {
App::setLocale(session('locale'));
}
return $next($request);
}
}
Register in bootstrap/app.php (Laravel 11+):
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
\App\Http\Middleware\SetLocale::class,
]);
})
Blade Component
resources/views/components/language-switcher.blade.php:
<div class="language-switcher">
@foreach(['en' => 'English', 'es' => 'Español', 'fr' => 'Français'] as $locale => $language)
<a href="{{ route('language.switch', $locale) }}"
class="{{ App::currentLocale() === $locale ? 'active' : '' }}">
{{ $language }}
</a>
@endforeach
</div>
Best Practices
1. Organize Translations by Domain
Group related translations into separate files:
/lang
/en
auth.php # Authentication strings
validation.php # Validation messages
dashboard.php # Dashboard UI
emails.php # Email templates
api.php # API responses
2. Use Descriptive Keys
Bad:
'msg1' => 'Welcome',
'btn' => 'Submit',
Good:
'auth.welcome_message' => 'Welcome to your dashboard',
'forms.submit_button' => 'Submit',
3. Provide Context in Comments
<?php
return [
// Displayed on the login page
'login_title' => 'Sign In to Your Account',
// Button text for form submission
'submit' => 'Submit',
// Error message when email is invalid
'invalid_email' => 'Please enter a valid email address.',
];
4. Handle Missing Translations
The __() function returns the key if no translation exists:
// If 'messages.unknown_key' doesn't exist
echo __('messages.unknown_key');
// Output: "messages.unknown_key"
// Provide a default value
echo __('messages.unknown_key') !== 'messages.unknown_key'
? __('messages.unknown_key')
: 'Default text';
5. Use JSON for User-Facing Strings
For large applications, JSON files are easier to manage:
{
"Welcome back, :name!": "Welcome back, :name!",
"You have :count new messages.": "You have :count new messages.",
"Your order has been shipped.": "Your order has been shipped."
}
Managing Translations with Azbox
While Laravel’s built-in localization is powerful, managing translations across multiple languages and team members can become complex. Azbox provides a centralized platform to streamline your Laravel localization workflow:
Benefits of Using Azbox with Laravel
- Centralized Management: Manage all translations in one place
- Team Collaboration: Work with translators without sharing code access
- Import/Export: Import existing Laravel PHP files and export updates
- Translation Memory: Reuse translations across projects
- Quality Assurance: Automated checks for missing translations and inconsistencies
Exporting Laravel Translations to Azbox
- Export your
lang/*.phpfiles as JSON or upload directly - Azbox preserves your key structure and supports nested arrays
- Translators work in a user-friendly interface
- Export back to Laravel PHP format when ready
Workflow Integration
# Export translations to Azbox
php artisan translations:export --format=azbox
# Import translations from Azbox
php artisan translations:import --from=azbox
Common Patterns
Date and Time Formatting
// lang/en/dates.php
return [
'formats' => [
'short' => 'M d, Y',
'long' => 'F d, Y',
'datetime' => 'M d, Y H:i',
],
];
// Usage
$date = now()->format(__('dates.formats.long'));
Currency Formatting
// lang/en/currency.php
return [
'format' => '$:amount',
'thousand_separator' => ',',
'decimal_separator' => '.',
];
// lang/es/currency.php
return [
'format' => ':amount €',
'thousand_separator' => '.',
'decimal_separator' => ',',
];
Validation Messages
Laravel includes localized validation messages. Customize them:
lang/en/validation.php:
return [
'required' => 'The :attribute field is required.',
'email' => 'The :attribute must be a valid email address.',
'custom' => [
'email' => [
'required' => 'We need your email address to continue.',
],
],
'attributes' => [
'email' => 'email address',
'password' => 'password',
],
];
Testing Translations
Feature Tests
public function test_welcome_page_displays_correct_translation()
{
$response = $this->get('/');
$response->assertSee(__('messages.welcome'));
}
public function test_spanish_locale_displays_spanish_text()
{
App::setLocale('es');
$response = $this->get('/');
$response->assertSee('¡Bienvenido a nuestra aplicación!');
}
Check for Missing Translations
Create a command to audit translations:
// app/Console/Commands/AuditTranslations.php
public function handle()
{
$englishKeys = $this->getKeys('en');
$spanishKeys = $this->getKeys('es');
$missing = array_diff($englishKeys, $spanishKeys);
foreach ($missing as $key) {
$this->warn("Missing Spanish translation: {$key}");
}
}
Conclusion
Laravel’s localization system provides a powerful foundation for building multilingual applications. By following the patterns and best practices outlined in this guide, you can:
- Structure translations effectively using PHP arrays or JSON files
- Handle complex scenarios with parameter replacement and pluralization
- Build user-friendly language switchers
- Maintain translation quality across your application
For teams managing translations across multiple projects and languages, Azbox offers a centralized platform that integrates seamlessly with Laravel’s localization system.
Get Started with Azbox
Ready to streamline your Laravel localization workflow?
- Sign up for Azbox - Start with a free trial
- Import your translations - Upload your existing Laravel PHP files
- Collaborate with translators - Invite team members to work on translations
- Export back to Laravel - Download updated PHP files for your project
Explore AZbox’s localization platform and simplify your translation workflow: