Quick Answer
To localize a PHP application, use array-based translation files. Store translations in PHP arrays (/lang/en/messages.php), create a translation helper function, and use it throughout your app. For frameworks: Laravel has built-in __('key') helper, Symfony uses Translation component, WordPress uses __('text', 'domain'). This approach is simple, fast, and works with any PHP version.
Why PHP Localization Matters
PHP powers 77% of websites (W3Techs, 2026). From WordPress to Laravel, PHP applications serve global audiences.
The challenge: PHP doesn't have built-in i18n like JavaScript frameworks. You need to implement it yourself or use a framework's solution.
The solution: Array-based translations are the PHP standard. Simple, performant, and framework-agnostic.
Basic Setup: Plain PHP
Step 1: Create Translation Files
Directory structure:
/lang
/en
messages.php
validation.php
/es
messages.php
validation.php
/fr
messages.php
validation.php
lang/en/messages.php:
PHP1<?php 2 3return [ 4 'welcome' => 'Welcome to our application', 5 'goodbye' => 'Goodbye, :name!', 6 'items_count' => '{0} No items|{1} One item|[2,*] :count items', 7 8 // Nested arrays for organization 9 'auth' => [ 10 'login' => 'Log in', 11 'logout' => 'Log out', 12 'register' => 'Sign up', 13 'failed' => 'These credentials do not match our records.', 14 ], 15 16 'nav' => [ 17 'home' => 'Home', 18 'about' => 'About Us', 19 'contact' => 'Contact', 20 ], 21];
Laravel Localization
Laravel has built-in localization. It's the same array-based approach, but with more features.
Setup
1. Create translation files:
/lang
/en
messages.php
validation.php
/es
messages.php
validation.php
2. Configure default locale:
PHP1// config/app.php 2 3'locale' => 'en', 4'fallback_locale' => 'en', 5'available_locales' => ['en', 'es', 'fr', 'de'],
3. Use in views:
PHP1<!-- Blade template --> 2<h1>{{ __('messages.welcome') }}</h1> 3<p>{{ __('messages.goodbye', ['name' => $user->name]) }}</p> 4 5<!-- Pluralization --> 6<p>{{ trans_choice('messages.items_count', $count) }}</p> 7 8<!-- Short syntax (Laravel 9+) --> 9<h1>@lang('messages.welcome')</h1>
4. Use in controllers:
PHP1<?php 2 3namespace AppHttpControllers; 4 5class HomeController extends Controller 6{ 7 public function index() 8 { 9 // Get translation 10 $message = __('messages.welcome'); 11 12 // With replacements 13 $greeting = __('messages.goodbye', ['name' => 'John']); 14 15 // Pluralization 16 $items = trans_choice('messages.items_count', 5); 17 18 return view('home', compact('message', 'greeting', 'items')); 19 } 20}
5. Change locale dynamically:
PHP1<?php 2 3// In middleware or controller 4App::setLocale('es'); 5 6// Get current locale 7$locale = App::getLocale(); 8 9// Check if locale is available 10if (in_array($locale, config('app.available_locales'))) { 11 App::setLocale($locale); 12}
Symfony Translation Component
Symfony has a powerful Translation component that works standalone or with the framework.
Installation (Standalone)
Terminalcomposer require symfony/translation
Setup
PHP1<?php 2 3use SymfonyComponentTranslationTranslator; 4use SymfonyComponentTranslationLoaderPhpFileLoader; 5 6$translator = new Translator('en'); 7$translator->setFallbackLocales(['en']); 8 9// Add loader for PHP files 10$translator->addLoader('php', new PhpFileLoader()); 11 12// Load translation files 13$translator->addResource('php', __DIR__ . '/lang/en/messages.php', 'en', 'messages'); 14$translator->addResource('php', __DIR__ . '/lang/es/messages.php', 'es', 'messages'); 15 16// Use translations 17echo $translator->trans('welcome', [], 'messages'); // "Welcome to our application" 18 19// With replacements 20echo $translator->trans('goodbye', ['%name%' => 'John'], 'messages'); // "Goodbye, John!"
WordPress Localization
WordPress uses gettext, but you can also use array-based translations.
Traditional WordPress Way (Gettext)
1. Mark strings for translation:
PHP1<?php 2 3// In theme or plugin 4echo __('Welcome to our site', 'my-theme'); 5echo _e('Hello World', 'my-theme'); // Echo directly 6 7// With variables 8printf(__('Hello, %s!', 'my-theme'), $name); 9 10// Pluralization 11echo _n('%s item', '%s items', $count, 'my-theme');
2. Generate .pot file:
Terminal1# Using WP-CLI 2wp i18n make-pot . languages/my-theme.pot 3 4# Or use Poedit to scan files
Date and Number Formatting
Using PHP Intl Extension
PHP1<?php 2 3$locale = 'es_ES'; 4 5// Date formatting 6$formatter = new IntlDateFormatter( 7 $locale, 8 IntlDateFormatter::LONG, 9 IntlDateFormatter::NONE 10); 11echo $formatter->format(new DateTime()); // "7 de febrero de 2026" 12 13// Number formatting 14$numberFormatter = new NumberFormatter($locale, NumberFormatter::DECIMAL); 15echo $numberFormatter->format(1234.56); // "1.234,56" 16 17// Currency formatting 18$currencyFormatter = new NumberFormatter($locale, NumberFormatter::CURRENCY); 19echo $currencyFormatter->formatCurrency(1234.56, 'EUR'); // "1.234,56 €"
Best Practices
1. Organize Translation Files
/lang
/en
messages.php # General UI strings
validation.php # Form validation messages
auth.php # Authentication messages
emails.php # Email templates
errors.php # Error messages
2. Use Nested Arrays
PHP1<?php 2 3return [ 4 'auth' => [ 5 'login' => 'Log in', 6 'logout' => 'Log out', 7 'register' => 'Sign up', 8 ], 9 'nav' => [ 10 'home' => 'Home', 11 'about' => 'About', 12 ], 13]; 14 15// Usage: __('messages.auth.login')
3. Never Concatenate Translations
PHP1<?php 2 3// ❌ Bad: Word order differs in languages 4echo __('messages.welcome') . ' ' . $name . '!'; 5 6// ✅ Good: Use placeholders 7echo __('messages.welcome_user', ['name' => $name]);
Integration with IntlPull
Setup
Terminalcomposer require intlpullhq/php-sdk
Automated Workflow
Terminal1# Extract strings from code 2php artisan intlpull:extract 3 4# Upload to IntlPull 5php artisan intlpull:upload 6 7# Translate with AI 8php artisan intlpull:translate 9 10# Download translations 11php artisan intlpull:download 12 13# Deploy 14php artisan config:cache
Frequently Asked Questions
Should I use gettext or PHP arrays?
Use PHP arrays for most projects. They're simpler, faster, and don't require PHP extensions. Use gettext only if you need compatibility with existing tools or have translators who prefer .po files.
How do I handle pluralization in PHP?
Use Laravel's trans_choice() or Symfony's trans() with ICU message format. For plain PHP, implement a simple parser that handles {0}, {1}, and [2,*] syntax.
Can I use JSON instead of PHP arrays?
Yes, but PHP arrays are faster. JSON requires parsing on every request. PHP arrays are compiled by OPcache. Use JSON only if you need to share translations with JavaScript.
Conclusion
PHP localization is straightforward with array-based translations.
Quick recap:
- Create
/lang/{locale}/messages.phpfiles - Return arrays with translation keys
- Use
__('key')helper function - Handle pluralization with trans_choice()
- Format dates/numbers with Intl extension
For production apps:
- Use Laravel or Symfony for built-in features
- Integrate with IntlPull for automated workflow
- Cache translations for performance
- Follow best practices (nested arrays, placeholders, context)
Try IntlPull Free | View PHP Documentation | Laravel Package
