Installation:
composer require sonata-project/intl-bundle
Enable the bundle in config/bundles.php:
return [
// ...
SonataIntlBundle\SonataIntlBundle::class => ['all' => true],
];
Configuration:
Add to config/packages/sonata_intl.yaml:
sonata_intl:
locale_default: en
locale_fallback: en
locales: [en, fr, es, de]
timezone: Europe/Paris
First Use Case:
Use the IntlListener to automatically detect and set the locale from:
?locale=fr)sonata_intl_locale)Example route:
// config/routes.yaml
sonata_intl_locale:
path: /{_locale}
defaults: { _locale: en }
requirements:
_locale: en|fr|es|de
Locale Switching in Controllers:
use SonataIntlBundle\Helper\IntlHelper;
public function index(IntlHelper $intlHelper)
{
$currentLocale = $intlHelper->getCurrentLocale();
// Use $currentLocale in logic or pass to view
}
Translating with Current Locale:
{{ 'homepage.title'|trans }}
(Automatically uses the current locale from IntlHelper.)
Dynamic Locale Selection:
$intlHelper->setCurrentLocale('es'); // Force locale for a request
Timezone Handling:
$timezone = $intlHelper->getCurrentTimezone();
$formattedDate = (new \DateTime())->setTimezone($timezone)->format('Y-m-d');
Integration with Forms:
use SonataIntlBundle\Form\Type\LocaleType;
$builder->add('locale', LocaleType::class, [
'choices' => ['en' => 'English', 'fr' => 'Français'],
'expanded' => true,
'multiple' => false,
]);
Custom Locale Detection:
Extend the LocaleDetector service:
# config/services.yaml
SonataIntlBundle\Intl\LocaleDetector:
arguments:
$detectors: ['sonata_intl.locale_detector.session', 'sonata_intl.locale_detector.url', 'app.custom_locale_detector']
Define a custom detector:
// src/Service/CustomLocaleDetector.php
class CustomLocaleDetector implements LocaleDetectorInterface
{
public function detect(): ?string
{
// Custom logic (e.g., API request, user profile)
return 'es';
}
}
Locale-Specific Routes:
# config/routes.yaml
app_home:
path: /{_locale}/home
defaults: { _controller: 'App\Controller\HomeController::index', _locale: en }
requirements:
_locale: en|fr|es
Database Locale Storage:
Store user preferences in the database and hydrate the IntlHelper:
$userLocale = $user->getLocale(); // Assume User entity has getLocale()
$intlHelper->setCurrentLocale($userLocale);
Fallback Logic: Override the fallback chain in config:
sonata_intl:
locale_fallbacks: [en, fr, es] # Custom fallback order
Locale Not Persisting:
IntlListener is registered (it is by default in Symfony 5+).locale_default or locales array in config._locale route parameter is correctly named in your routes.Timezone Mismatches:
sonata_intl.timezone in config. If dates appear incorrect, validate this setting matches your application’s expectations.created_at fields).Translation Fallbacks:
locale_fallback chain includes a locale with complete translations (e.g., en as the last fallback).Route Caching:
php bin/console cache:clear
Session Locale Cookie:
sonata_intl_locale) to persist the user’s choice. If this doesn’t work:
session.storage.handler in Symfony config (e.g., session.storage.mock_file for testing).same_site and secure cookie flags are compatible with your deployment (e.g., HTTPS).Log Current Locale: Add a temporary controller method to debug:
public function debugLocale(IntlHelper $intlHelper)
{
return new Response(
'Current Locale: '.$intlHelper->getCurrentLocale().'<br>'.
'Available Locales: '.implode(', ', $intlHelper->getAvailableLocales())
);
}
Check Detector Order:
The first detector to return a non-null locale wins. Use dump() to inspect:
$detectors = $container->get('sonata_intl.locale_detector');
foreach ($detectors as $detector) {
dump(get_class($detector), $detector->detect());
}
Override Locale Programmatically: Temporarily force a locale in tests or debugging:
$intlHelper->setCurrentLocale('fr');
Custom Detectors:
Implement LocaleDetectorInterface and tag it as a service:
services:
app.custom_locale_detector:
class: App\Service\CustomLocaleDetector
tags: [sonata_intl.locale_detector]
Modify Locale List Dynamically:
Override the LocaleList service:
// src/Service/CustomLocaleList.php
class CustomLocaleList extends LocaleList
{
public function getLocales(): array
{
return ['en', 'fr', 'es', 'de', 'ja']; // Add/remove locales
}
}
Register it in config/services.yaml:
SonataIntlBundle\Intl\LocaleList: '@app.custom_locale_list'
Event Listeners:
Listen to sonata.intl.locale.switch to react to locale changes:
use SonataIntlBundle\Event\LocaleSwitchEvent;
public function onLocaleSwitch(LocaleSwitchEvent $event)
{
$newLocale = $event->getLocale();
// Log, update user session, or trigger other logic
}
Register the listener:
services:
App\EventListener\LocaleSwitchListener:
tags:
- { name: kernel.event_listener, event: sonata.intl.locale.switch, method: onLocaleSwitch }
Override Twig Extensions:
Extend or replace the IntlTwigExtension for custom filters/filters:
// src/Twig/AppExtension.php
class AppExtension extends \Twig\Extension\AbstractExtension
{
public function getFilters()
{
return [
new \Twig\TwigFilter('custom_trans', [$this, 'customTranslate']),
];
}
}
Register it after the Sonata extension in config/services.yaml:
SonataIntlBundle\Twig\IntlTwigExtension:
tags: [twig.extension]
App\Twig\AppExtension:
tags: [twig.extension]
arguments: ['@sonata_intl.intl_helper'] # Inject if needed
LocaleList service is cached by default. Extend it only if you need dynamic locale management./{_locale}) for better SEO and explicit user control.How can I help you explore Laravel packages today?