benatespina/i18n-routing-bundle
Installation:
composer require benatespina/i18n-routing-bundle
Ensure JMSI18nRoutingBundle is already installed (this bundle extends it).
Enable the Bundle:
Add to config/bundles.php:
BenatEspina\I18nRoutingBundle\BenatEspinaI18nRoutingBundle::class => ['all' => true],
Configure Locales:
Extend jms_i18n_routing config in config/packages/jms_i18n_routing.yaml:
jms_i18n_routing:
default_locale: en
locales: [en, es, fr]
routing:
locale_prefix: true
prefix_default_locale: false
First Use Case: Generate locale-aware routes in a controller:
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
public function index(UrlGeneratorInterface $router)
{
return $this->render('home/index.html.twig', [
'homepageUrl' => $router->generate('homepage', [], UrlGeneratorInterface::ABSOLUTE_URL),
'esHomepageUrl' => $router->generate('homepage', ['_locale' => 'es'], UrlGeneratorInterface::ABSOLUTE_URL),
]);
}
Locale Prefix Routing:
/{locale} (e.g., /es/contact).locale_prefix: true in jms_i18n_routing.yaml.Dynamic Locale Switching:
_locale route parameter:
$router->generate('product_show', ['id' => 1, '_locale' => 'fr']);
Accept-Language header).Fallback Locales:
jms_i18n_routing:
locales: [en, es, fr]
fallback_locales: [en, es]
en if es is unavailable.Route Annotations:
@Route with _locale parameter:
/**
* @Route("/product/{id}", name="product_show", requirements={"_locale": "en|es|fr"})
*/
public function show(Product $product) { ... }
Twig Integration:
Use the path() and url() functions with _locale:
<a href="{{ path('homepage', {'_locale': 'es'}) }}">Ir a Español</a>
APIs:
For APIs, avoid locale prefixes and rely on _locale headers or parameters:
# config/routes/api.yaml
api_product:
path: /api/product/{id}
controller: App\Controller\ApiProductController::show
methods: GET
requirements:
_locale: en|es|fr
Testing:
Mock the RequestContext to test locale-specific routes:
$context = $this->createMock(RequestContext);
$context->expects($this->any())->method('getParameter')->with('locale')->willReturn('es');
$router->setContext($context);
Locale Parameter Conflicts:
_locale if you also use it as a query parameter.?locale=es instead of _locale=es in URLs.Caching Issues:
php bin/console cache:clear
Deprecated Features:
router.request_context).Route Generation Edge Cases:
_locale is included in requirements for routes:
requirements:
_locale: en|es|fr
No route found for "..." if locale is invalid.Check Current Locale:
Use a Twig extension or dump the RequestContext:
{{ dump(app.request.attributes.get('_locale')) }}
Route Debugging:
Enable debug toolbar and inspect the Router component for generated paths.
Logs:
Enable verbose routing logs in config/packages/dev/monolog.yaml:
handlers:
routing:
type: stream
level: debug
channels: ["routing"]
Custom Locale Provider:
Extend LocaleProvider to add logic (e.g., database-based locales):
// src/Service/CustomLocaleProvider.php
class CustomLocaleProvider implements LocaleProviderInterface
{
public function getLocales(): array
{
return ['en', 'es', 'custom_locale'];
}
}
Register as a service and override the bundle’s locale_provider tag.
Override Route Loader:
Replace the default JMS\I18nRoutingBundle\Loader\RouterLoader with a custom implementation.
Add Locale to Request:
Use an event subscriber to attach locale to the Request object:
// src/EventListener/LocaleListener.php
class LocaleListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => 'onKernelRequest',
];
}
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
$request->attributes->set('_locale', 'es'); // Force locale
}
}
Default Locale Handling:
If prefix_default_locale: true, omit _locale for the default locale (e.g., /contact instead of /en/contact).
Caveat: May cause confusion in multi-locale APIs.
Locale-Specific Assets:
Use the asset() function with _locale for locale-specific JS/CSS:
<link rel="stylesheet" href="{{ asset('css/styles_' ~ app.request.attributes.get('_locale') ~ '.css') }}">
Symfony 5+ Compatibility:
The bundle lacks Symfony 5/6 support. Use symfony/flex recipes or manually patch the Router service if needed.
How can I help you explore Laravel packages today?