acasademont/i18n-routing-bundle
Symfony bundle for internationalized routing: generate localized URLs per locale, translate route patterns, and switch locales seamlessly. Integrates with JMS/Symfony routing to keep route definitions clean while supporting multilingual sites.
Installation
composer require acasademont/i18n-routing-bundle
Register the bundle in config/bundles.php:
return [
// ...
Acasademont\JMSI18nRoutingBundle\JMSI18nRoutingBundle::class => ['all' => true],
];
Configure Locales
Update config/packages/jms_i18n_routing.yaml (or create it):
jms_i18n_routing:
default_locale: en
locales: [en, es, fr]
strategy: prefix_except_default
default_locale: Fallback locale (e.g., en).locales: Supported locales.strategy: Route prefixing logic (prefix_except_default, prefix, prefix_suffix, or domain).First Use Case: Localized Routes
Annotate a controller method with @Route and @I18nRoute:
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\I18nRoute;
class ProductController extends AbstractController
{
/**
* @Route("/products/{id}", name="product_show")
* @I18nRoute(
* locales={"en": "products/{id}", "es": "productos/{id}"},
* requirements={"id" = "\d+"}
* )
*/
public function show(int $id): Response
{
// ...
}
}
/products/123 (English)/productos/123 (Spanish)Use the url() helper with locale parameters:
// Generate URL for Spanish locale
$url = $this->generateUrl('product_show', ['id' => 123], ['_locale' => 'es']);
// Output: /productos/123
JMSI18nRoutingBundle\Middleware\LocaleListener to kernel.middleware to auto-detect locale from:
/es/products).es.example.com)._locale).# config/packages/framework.yaml
framework:
middleware:
- JMSI18nRoutingBundle\Middleware\LocaleListener
Leverage @I18nRoute for locale-specific constraints:
/**
* @I18nRoute(
* locales={
* "en": "/blog/{slug}",
* "es": "/blog/{titulo}",
* "fr": "/blog/{titre}"
* },
* requirements={
* "slug" = "[a-z0-9_-]+",
* "titulo" = "[áéíóúüña-z0-9_-]+",
* "titre" = "[àâäéèêëîïôöùûüça-z0-9_-]+"
* }
* )
*/
$matcher = $this->get('router')->getMatcher();
$context = $matcher->getContext();
$context->setParameter('_locale', 'es');
$matcher->match('/productos/123'); // Returns route object for Spanish locale
return $this->redirectToRoute(
'product_show',
['id' => 123],
['_locale' => $request->get('_locale', 'en')]
);
Pass the current locale to Twig:
{# templates/base.html.twig #}
<a href="{{ path('product_show', {'id': 123}, {'_locale': 'es'}) }}">Spanish</a>
<a href="{{ path('product_show', {'id': 123}, {'_locale': 'fr'}) }}">French</a>
For APIs, use JSON-LD or HAL+JSON to include locale-specific endpoints:
{
"_links": {
"self": { "href": "/api/products/123", "hreflang": "en" },
"es": { "href": "/api/productos/123", "hreflang": "es" }
}
}
Locale Prefix Conflicts
prefix strategy, ensure no other routes conflict with /en/, /es/, etc.prefix_except_default to avoid prefixing the default locale.Case-Sensitive URLs
/ES/ and /es/ as different routes.Caching Issues
php bin/console cache:clear
Fallback Locale Misconfiguration
default_locale is missing or misconfigured, routes may 404.default_locale and test fallback behavior.Subdomain Strategy Pitfalls
es.example.com).prefix or prefix_suffix for simpler setups.Check Route Dumping:
php bin/console debug:router | grep "product_show"
Look for locale-specific paths.
Enable Router Debugging:
# config/packages/framework.yaml
framework:
router:
debug: "%kernel.debug%"
Log Locale Resolution: Add a temporary listener to debug locale selection:
// src/EventListener/LocaleDebugListener.php
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
$this->logger->info('Resolved locale:', ['locale' => $request->get('_locale')]);
}
Custom Locale Strategies
Extend JMSI18nRoutingBundle\Strategy\LocaleStrategyInterface to implement:
Dynamic Locale Switching
Override LocaleListener to add logic (e.g., redirect to user’s preferred locale):
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
$userLocale = $this->getUserLocale(); // Custom logic
$request->set('_locale', $userLocale);
}
Locale-Aware Redirects Create a custom redirect resolver:
// src/EventListener/LocaleRedirectListener.php
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
if ($request->get('_locale') === 'es' && $request->getPathInfo() === '/') {
return new RedirectResponse('/productos/123');
}
}
Integration with API Platform
Use @I18nRoute with API Platform’s @ApiResource:
/**
* @ApiResource(
* collectionOperations={
* "get"={ "path": "/products", "method": "GET" }
* },
* itemOperations={
* "get"={
* "path": "/products/{id}",
* "method": "GET",
* "i18n"={
* "locales": {
* "en": "/products/{id}",
* "es": "/productos/{id}"
* }
* }
* }
* }
* )
*/
strategy: prefix_except_default to minimize route duplication.How can I help you explore Laravel packages today?