Installation:
composer require jms/translation-bundle
Add to config/bundles.php (Symfony) or config/app.php (Laravel via bridge):
JMS\TranslationBundle\JMSTranslationBundle::class => ['all' => true],
Configuration: Publish the default config:
php artisan vendor:publish --provider="JMS\TranslationBundle\JMSTranslationBundle" --tag=config
Key settings in config/jms_translation.php:
locales: Define supported locales (e.g., ['en', 'fr']).default_locale: Set default (e.g., 'en').fallback_locale: Fallback for missing translations (e.g., 'en').First Use Case: Translate a string in a controller or blade:
$translator = app('translator');
echo $translator->trans('Hello world'); // Uses default locale
echo $translator->transChoice('There is %count% apple', $count, ['%count%' => 1]); // Pluralization
Translation Files:
Create a translations directory in your project root (or configure custom path).
Example structure:
translations/
messages.en.yml
messages.fr.yml
# translations/messages.en.yml
hello_world: "Hello world"
apples: "There is %count% apple|There are %count% apples"
Automatic Extraction:
Use the jms:translation:extract command to scan controllers, views, and classes for __() or trans() calls:
php artisan jms:translation:extract en
Outputs a .pot file (e.g., messages.pot) with extractable strings.
Manual Extraction: Add placeholders in code:
$name = trans('user.greeting', ['name' => $user->name]);
Runtime Switching: Dynamically change locale in middleware or controllers:
$translator->setLocale('fr');
Or via URL parameter (use JMS\TranslationBundle\Translation\TranslationListener):
// config/routes.php
$router->addRoute('locale_switch', '/{_locale}', 'App\Controller\LocaleController::switchLocale');
Session-Based Locale: Store locale in session and restore it on each request:
$request->getSession()->set('locale', 'fr');
Plural Rules:
Define locale-specific plural rules in config/jms_translation.php:
'pluralization' => [
'en' => ['rule' => 'one', 'vars' => ['count']],
'fr' => ['rule' => 'traditional', 'vars' => ['count']],
],
Use in translations:
# messages.fr.yml
apples: "Il y a %count% pomme|Il y a %count% pommes"
Interpolation: Pass variables dynamically:
trans('user.welcome', ['name' => 'John']);
# messages.en.yml
user.welcome: "Welcome, %name%!"
Domain Isolation:
Organize translations by domain (e.g., validation, user):
translations/
validation.en.yml
user.fr.yml
Translate by domain:
$translator->trans('validation.required', [], 'validation');
Domain Fallbacks:
Configure fallback domains in config/jms_translation.php:
'fallback_domains' => ['validation' => 'messages'],
AppServiceProvider:
public function register()
{
$this->app->singleton('translator', function ($app) {
return \JMS\TranslationBundle\Translation\TranslationService::getTranslator();
});
}
Blade::directive('trans', function ($expression) {
return "<?php echo app('translator')->trans($expression); ?>";
});
Usage in Blade:
@trans('user.greeting')
JMS\TranslationBundle\Translation\TranslatorInterface for custom logic (e.g., database-backed translations):
class DatabaseTranslator implements TranslatorInterface
{
public function trans($id, array $parameters = [], $domain = 'messages', $locale = null)
{
// Custom logic (e.g., query DB)
return parent::trans($id, $parameters, $domain, $locale);
}
}
config/jms_translation.php:
'translator' => App\Services\DatabaseTranslator::class,
php artisan jms:translation:validate en
config/jms_translation.php:
'validation' => [
'required' => true,
'max_length' => 255,
],
$translator = $this->getMockBuilder('JMS\TranslationBundle\Translation\TranslatorInterface')
->getMock();
$translator->method('trans')->willReturn('Mocked translation');
$this->app->instance('translator', $translator);
$this->assertEquals('1 apple', $translator->transChoice('apples', 1));
'cache' => [
'enabled' => true,
'provider' => 'file', // or 'redis', 'memcached'
],
php artisan cache:clear
config/jms_translation.php:
'locale_negotiation_strategies' => [
'url', // Highest priority
'session',
'browser',
],
# config/jms_translation.php
'fallback_locales' => [
'fr' => ['en'],
'es' => ['en'],
],
en rule for fr).config/jms_translation.php and test edge cases (e.g., count = 0, count = 2).// trans('user.greeting', ['name' => $name]); // Dynamic
'cache' => [
'enabled' => true,
'tags' => ['translations'],
],
Then clear by tag:
php artisan cache:tags:clear translations
storage/logs/translation.log:
'debug' => true,
$translator->getCatalogue()->all('messages', 'en');
How can I help you explore Laravel packages today?