Installation:
composer require binsoul/symfony-bundle-i18n
Ensure the bundle is enabled in config/bundles.php (Symfony 4+ auto-discovers it).
Load Fixtures:
php bin/console doctrine:fixtures:load --group=binsoul/symfony-bundle-i18n
This populates the Locale and Translation tables (if using Doctrine).
First Use Case:
%locale% to your routes (e.g., /{_locale}/products).{{ 'key'|trans }} in templates. Ensure translator is configured in config/packages/binsoul_i18n.yaml.config/packages/binsoul_i18n.yaml (default fallback locale, supported locales, etc.).src/Entity/Locale.php and src/Entity/Translation.php (if extending).src/DependencyInjection/Configuration.php for customization hooks.Dynamic Locale Switching:
LocaleListener to detect locale from:
_locale).en.example.com).# config/routes.yaml
products:
path: /{_locale}/products
controller: App\Controller\ProductController::index
requirements:
_locale: en|fr|es
Translation Management:
Translation entity (useful for admin-editable content).
// Add a translation to a product
$translation = new Translation();
$translation->setLocale('fr');
$translation->setContent('Contenu traduit');
$translation->setTranslatable($product); // Polymorphic relation
$entityManager->persist($translation);
config/packages/binsoul_i18n.yaml:
fallback_locales:
fr: en
es: en
Twig Extensions:
trans filter for dynamic content:
{{ product.name|trans }}
{{ app.request.locale }}
Form Localization:
AbstractType to handle locale-aware forms:
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'locale' => $this->getCurrentLocale(), // Inject via constructor
]);
}
prePersist/preUpdate to auto-generate translations for entities:
$entityManager->getEventManager()->addEventListener(
[YourEntity::class],
new TranslationLifecycleListener()
);
RequestStack to access locale in controllers:
$locale = $this->get('request_stack')->getCurrentRequest()->getLocale();
LocaleListener to test locale-specific behavior:
$this->container->get('binsoul_i18n.locale_listener')->setLocale('fr');
Locale Detection Order:
LocaleListener if this order doesn’t fit your needs:
// src/EventListener/CustomLocaleListener.php
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
$locale = $request->get('lang', $request->getPreferredLanguage()); // Custom logic
$this->setLocale($locale);
}
Caching Translations:
TranslationReader with a cache layer:
$reader = new DoctrineTranslationReader($entityManager);
$reader->setCache($cache); // Psr\Cache\CacheItemPoolInterface
Route Requirements:
_locale to route requirements will break locale switching:
# WRONG: Missing requirements
path: /{locale}/products
# CORRECT
path: /{_locale}/products
requirements:
_locale: en|fr
Fallback Locale Conflicts:
fallback_locales isn’t configured, missing translations will throw TranslationNotFoundException. Always define a fallback (e.g., en).php bin/console debug:container binsoul_i18n.locale_listener | grep locale
public function onKernelRequest(GetResponseEvent $event)
{
$this->logger->info('Locale set to: ' . $event->getRequest()->getLocale());
}
Custom Locale Providers:
LocaleProviderInterface for non-standard sources (e.g., user preferences):
class UserPreferenceLocaleProvider implements LocaleProviderInterface
{
public function getLocale(Request $request): string
{
return $request->getUser()->getPreferredLocale();
}
}
config/packages/binsoul_i18n.yaml:
locale_providers:
- binsoul_i18n.locale_provider.route
- app.user_preference_locale_provider
Translation Sources:
TranslationReaderInterface to support additional sources (e.g., API calls):
class ApiTranslationReader implements TranslationReaderInterface
{
public function getTranslation(string $id, string $locale): string
{
return $this->apiClient->fetchTranslation($id, $locale);
}
}
Event Dispatching:
binsoul_i18n.locale_changed to trigger side effects (e.g., redirect, cache flush):
$dispatcher->addListener(
'binsoul_i18n.locale_changed',
function (LocaleChangedEvent $event) {
// Clear cache for the new locale
}
);
config/packages/binsoul_i18n.yaml:
default_locale: en
AppKernel (Symfony <5):
$kernel->setLocale('fr');
supported_locales:
- en
- fr
- es
* for dynamic locales (but validate manually).TranslationRepository::findByTranslatable() with DISTINCT to avoid N+1 queries:
$translations = $repository->findByTranslatable($entity, ['locale' => $locale]);
LazyTranslationLoader to fetch translations on-demand.
How can I help you explore Laravel packages today?