Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

I18N Routing Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require acasademont/i18n-routing-bundle
    

    Register the bundle in config/bundles.php:

    return [
        // ...
        Acasademont\JMSI18nRoutingBundle\JMSI18nRoutingBundle::class => ['all' => true],
    ];
    
  2. 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).
  3. 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
        {
            // ...
        }
    }
    
    • URLs:
      • /products/123 (English)
      • /productos/123 (Spanish)

Implementation Patterns

1. Route Generation

Use the url() helper with locale parameters:

// Generate URL for Spanish locale
$url = $this->generateUrl('product_show', ['id' => 123], ['_locale' => 'es']);
// Output: /productos/123

2. Dynamic Locale Switching

  • Middleware: Add JMSI18nRoutingBundle\Middleware\LocaleListener to kernel.middleware to auto-detect locale from:
    • URL prefix (e.g., /es/products).
    • Subdomain (e.g., es.example.com).
    • Cookie/session (_locale).
  • Example Middleware Configuration:
    # config/packages/framework.yaml
    framework:
        middleware:
            - JMSI18nRoutingBundle\Middleware\LocaleListener
    

3. Route Requirements & Constraints

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_-]+"
 *     }
 * )
 */

4. Integration with Symfony’s Router

  • Programmatic Route Matching:
    $matcher = $this->get('router')->getMatcher();
    $context = $matcher->getContext();
    $context->setParameter('_locale', 'es');
    $matcher->match('/productos/123'); // Returns route object for Spanish locale
    
  • Locale-Aware Redirects:
    return $this->redirectToRoute(
        'product_show',
        ['id' => 123],
        ['_locale' => $request->get('_locale', 'en')]
    );
    

5. Twig Integration

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>

6. API-First Workflows

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" }
  }
}

Gotchas and Tips

Pitfalls

  1. Locale Prefix Conflicts

    • If using prefix strategy, ensure no other routes conflict with /en/, /es/, etc.
    • Fix: Use prefix_except_default to avoid prefixing the default locale.
  2. Case-Sensitive URLs

    • Apache/Nginx may treat /ES/ and /es/ as different routes.
    • Fix: Configure case-insensitive rewrites or normalize locales to lowercase.
  3. Caching Issues

    • Symfony’s router cache may not invalidate when locales/routes change.
    • Fix: Clear cache after updates:
      php bin/console cache:clear
      
  4. Fallback Locale Misconfiguration

    • If default_locale is missing or misconfigured, routes may 404.
    • Fix: Always specify default_locale and test fallback behavior.
  5. Subdomain Strategy Pitfalls

    • Requires DNS/subdomain support (e.g., es.example.com).
    • Fix: Use prefix or prefix_suffix for simpler setups.

Debugging Tips

  • 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')]);
    }
    

Extension Points

  1. Custom Locale Strategies Extend JMSI18nRoutingBundle\Strategy\LocaleStrategyInterface to implement:

    • User-role-based locales.
    • GeoIP-based locale detection.
  2. 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);
    }
    
  3. 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');
        }
    }
    
  4. 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}"
     *                 }
     *             }
     *         }
     *     }
     * )
     */
    

Performance Optimizations

  • Avoid Over-Fetching: Use strategy: prefix_except_default to minimize route duplication.
  • Cache Locale Resolution: Store resolved locales in session/cookie to reduce middleware overhead.
  • Lazy-Load Routes: For large apps, dynamically generate locale-specific routes only when needed.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware