Localization & Internationalization
Localization (l10n) and internationalization (i18n) allow your Laravel application to support multiple languages and regional preferences. Laravel provides powerful features to easily translate your application's text, format dates and numbers, and manage multilingual content.
Understanding Localization
Key concepts:
- Internationalization (i18n): Designing your application to support multiple languages
- Localization (l10n): Adapting your application for specific languages and regions
- Locale: A language code (e.g., "en", "ar", "fr") that identifies a language and region
- Translation Strings: Text that can be translated into different languages
Note: Laravel stores translation files in the resources/lang directory (Laravel 8) or lang/ directory (Laravel 9+). Each language has its own subdirectory.
Configuration
Configure your default and fallback locales in config/app.php:
<?php
return [
// Default application locale
'locale' => 'en',
// Fallback locale when translation is missing
'fallback_locale' => 'en',
// Available locales
'available_locales' => ['en', 'ar', 'fr', 'es'],
];
Creating Translation Files
Create language directories and translation files:
# Directory structure
resources/lang/
├── en/
│ ├── messages.php
│ ├── auth.php
│ └── validation.php
├── ar/
│ ├── messages.php
│ ├── auth.php
│ └── validation.php
└── fr/
├── messages.php
├── auth.php
└── validation.php
Example translation file resources/lang/en/messages.php:
<?php
return [
'welcome' => 'Welcome to our application',
'goodbye' => 'Goodbye, :name!',
'user_greeting' => 'Hello, :name! You have :count messages.',
'items' => 'You have :count item|You have :count items',
'profile' => [
'title' => 'Profile',
'edit' => 'Edit Profile',
'settings' => 'Settings',
],
'notifications' => [
'success' => 'Operation completed successfully!',
'error' => 'An error occurred. Please try again.',
'warning' => 'Please check your input.',
],
];
Arabic translation resources/lang/ar/messages.php:
<?php
return [
'welcome' => 'مرحبًا بك في تطبيقنا',
'goodbye' => 'وداعًا، :name!',
'user_greeting' => 'مرحبًا، :name! لديك :count رسائل.',
'items' => 'لديك :count عنصر|لديك :count عناصر',
'profile' => [
'title' => 'الملف الشخصي',
'edit' => 'تعديل الملف الشخصي',
'settings' => 'الإعدادات',
],
'notifications' => [
'success' => 'تمت العملية بنجاح!',
'error' => 'حدث خطأ. يرجى المحاولة مرة أخرى.',
'warning' => 'يرجى التحقق من إدخالك.',
],
];
Retrieving Translation Strings
Use the __() helper function or trans() to retrieve translations:
<?php
// Basic translation
echo __('messages.welcome');
// Output: "Welcome to our application"
// Translation with parameters
echo __('messages.goodbye', ['name' => 'John']);
// Output: "Goodbye, John!"
// Nested translation keys
echo __('messages.profile.title');
// Output: "Profile"
// Default value if translation missing
echo __('messages.unknown', [], 'Default text');
// Output: "Default text"
// Using trans() helper
echo trans('messages.welcome');
Using Translations in Blade
Use the @lang directive or translation helpers in Blade templates:
<!-- Using @lang directive -->
<h1>@lang('messages.welcome')</h1>
<!-- Using __() helper -->
<p>{{ __('messages.goodbye', ['name' => $user->name]) }}</p>
<!-- Translation with HTML -->
<div class="alert">
{!! __('messages.notifications.success') !!}
</div>
<!-- Loop with translations -->
@foreach($items as $item)
<li>{{ __("messages.items.$item->type") }}</li>
@endforeach
Switching Locales
Change the application locale at runtime:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Session;
class LocaleController extends Controller
{
public function switch($locale)
{
// Validate locale
if (!in_array($locale, ['en', 'ar', 'fr'])) {
abort(404);
}
// Set application locale
App::setLocale($locale);
// Store in session for persistence
Session::put('locale', $locale);
return redirect()->back();
}
}
// In a middleware
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Session;
class SetLocale
{
public function handle($request, Closure $next)
{
// Get locale from session, URL, or default
$locale = Session::get('locale', config('app.locale'));
App::setLocale($locale);
return $next($request);
}
}
URL-Based Localization
Include locale in URLs for better SEO:
<?php
// routes/web.php
Route::prefix('{locale}')->middleware('setlocale')->group(function () {
Route::get('/', [HomeController::class, 'index'])->name('home');
Route::get('/about', [PageController::class, 'about'])->name('about');
Route::get('/contact', [PageController::class, 'contact'])->name('contact');
});
// Middleware to set locale from URL
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\App;
class SetLocaleFromUrl
{
public function handle($request, Closure $next)
{
$locale = $request->segment(1);
if (in_array($locale, config('app.available_locales'))) {
App::setLocale($locale);
}
return $next($request);
}
}
// Generate localized URLs
route('home', ['locale' => 'en']); // /en
route('about', ['locale' => 'ar']); // /ar/about
Pluralization
Laravel supports pluralization rules for different languages:
<?php
// In translation file
'apples' => '{0} No apples|{1} One apple|[2,*] :count apples',
'time' => '{1} :value minute ago|[2,*] :value minutes ago',
// Usage
echo trans_choice('messages.apples', 0); // "No apples"
echo trans_choice('messages.apples', 1); // "One apple"
echo trans_choice('messages.apples', 5); // "5 apples"
// Arabic pluralization (more complex)
'posts' => '{0} لا توجد منشورات|{1} منشور واحد|{2} منشوران|[3,10] :count منشورات|[11,*] :count منشور',
JSON Translation Files
For simple key-value translations without nesting:
// resources/lang/en.json
{
"Welcome": "Welcome",
"Login": "Login",
"Register": "Register",
"Email": "Email Address",
"Password": "Password"
}
// resources/lang/ar.json
{
"Welcome": "مرحبًا",
"Login": "تسجيل الدخول",
"Register": "التسجيل",
"Email": "عنوان البريد الإلكتروني",
"Password": "كلمة المرور"
}
// Usage (uses the English text as the key)
{{ __('Welcome') }}
{{ __('Email') }}
Tip: JSON translation files are great for simple translations and work well with JavaScript frameworks. Use PHP arrays for complex translations with nesting and pluralization.
Date and Number Formatting
Format dates and numbers according to locale:
<?php
use Illuminate\Support\Carbon;
// Date formatting with Carbon
$date = Carbon::parse('2024-01-15');
App::setLocale('en');
echo $date->translatedFormat('l, F j, Y');
// Output: "Monday, January 15, 2024"
App::setLocale('ar');
echo $date->translatedFormat('l، j F، Y');
// Output: "الاثنين، 15 يناير، 2024"
// Number formatting
$number = 1234567.89;
App::setLocale('en');
echo number_format($number, 2);
// Output: "1,234,567.89"
App::setLocale('ar');
setlocale(LC_NUMERIC, 'ar_AE.utf8');
echo number_format($number, 2);
// May need additional formatting for Arabic numerals
RTL (Right-to-Left) Support
Support RTL languages like Arabic and Hebrew:
<!-- In Blade layout -->
<html lang="{{ app()->getLocale() }}"
dir="{{ in_array(app()->getLocale(), ['ar', 'he', 'fa']) ? 'rtl' : 'ltr' }}">
<head>
@if(in_array(app()->getLocale(), ['ar', 'he', 'fa']))
<link rel="stylesheet" href="{{ asset('css/rtl.css') }}">
@else
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
@endif
</head>
/* CSS for RTL support */
[dir="rtl"] {
text-align: right;
}
[dir="rtl"] .float-left {
float: right;
}
[dir="rtl"] .float-right {
float: left;
}
[dir="rtl"] .text-left {
text-align: right;
}
[dir="rtl"] .ml-3 {
margin-left: 0;
margin-right: 0.75rem;
}
Spatie Laravel Translatable
Use the popular Spatie package for translatable database models:
# Install package
composer require spatie/laravel-translatable
<?php
// Model
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\Translatable\HasTranslations;
class Post extends Model
{
use HasTranslations;
public $translatable = ['title', 'content'];
}
// Migration
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->json('title');
$table->json('content');
$table->timestamps();
});
// Usage
$post = new Post();
$post->setTranslation('title', 'en', 'Hello World');
$post->setTranslation('title', 'ar', 'مرحبا بالعالم');
$post->save();
// Retrieve translations
echo $post->getTranslation('title', 'en'); // "Hello World"
echo $post->title; // Automatically uses current locale
Exercise 1: Basic Localization
Set up a multilingual application:
- Create translation files for English and Arabic
- Add translations for navigation, forms, and messages
- Create a locale switcher in your layout
- Store the selected locale in the session
- Test switching between languages
Exercise 2: URL-Based Locales
Implement locale prefixes in URLs:
- Add locale prefix to all routes (/en/*, /ar/*)
- Create middleware to set locale from URL
- Update all route() helpers to include locale parameter
- Implement hreflang tags for SEO
- Add automatic redirection based on browser language
Exercise 3: Translatable Models
Create a multilingual blog:
- Install Spatie Laravel Translatable
- Make Post model translatable (title, content, excerpt)
- Create forms to input translations for each language
- Display posts in the current locale
- Add RTL CSS support for Arabic
Best Practices
- Organize Translations: Group related translations in separate files
- Use Keys: Use descriptive keys instead of full sentences
- Fallback Locale: Always provide a fallback locale
- Test All Languages: Regularly test your app in all supported languages
- SEO: Use hreflang tags and locale-specific URLs
- RTL Support: Design with RTL in mind from the start
- Professional Translation: Use professional translators, not machine translation
- Context: Provide context for translators (comments in translation files)
Summary
In this lesson, you learned:
- The difference between localization and internationalization
- How to create and organize translation files
- Using the __() helper and @lang directive
- Switching locales at runtime and via URLs
- Pluralization rules for different languages
- Date and number formatting for locales
- Supporting RTL languages like Arabic
- Using Spatie Translatable for database content
Proper localization makes your application accessible to a global audience and provides a better user experience. Plan for localization early in development for easier implementation.