March 19, 2018 Javier Eguiluz

We recently improved the performance of the Routing component to make it the fastest PHP router available. Now, just in time for including it in Symfony 4.1, we added another amazing feature to it: support for internationalized routes.

This feature allows to define different paths for each route depending on the user locale. This feature is essential for internationalized apps and that's why third-party bundles like JMSI18nRoutingBundle have millions on downloads. In Symfony 4.1 we decided to integrate this into the routing component itself so you can use it out-of-the-box in Symfony apps.

In practice, when defining a route you can now provide an array in the path option to define a different path per locale:

1 2 3 4 5 contact : controller : App\Controller\ContactController::send path : en : /send-us-an-email nl : /stuur-ons-een-email

This format is also supported for routes defined in XML and PHP annotations:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 use Symfony\Component\Routing\Annotation\Route ; class ContactController { /** * @Route({ * "en": "/send-us-an-email", * "nl": "/stuur-ons-een-email" * }, name="contact") */ public function send () { // ... } }

Internally Symfony creates one route per locale (called contact.en and contact.nl in this example) but you can still use the original route name to generate URLs. When generating a URL, the request locale is used by default, but you can pass the locale explicitly to generate any of the alternative URLs:

1 2 3 4 5 6 7 8 /** @var UrlGeneratorInterface $urlGenerator */ // uses the current request locale $url = $urlGenerator -> generate ( 'contact' ); // ignores the current request locale and generates '/stuur-ons-een-email' $url = $urlGenerator -> generate ( 'contact' , [ '_locale' => 'nl' ]); // this would also work, but it's not recommended: // $url = $urlGenerator->generate('contact.nl');

The route prefix can also be translated (both in YAML/XML files and @Route annotations defined at controller class level) and you can mix translated and not translated paths too:

1 2 3 4 5 6 7 # config/routes/annotations.yaml site : resource : '../src/Controller/' type : annotation prefix : en : '/site' es : '/sitio'

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class DefaultController extends Controller { /** * @Route({"en": "/contact", "es": "/contacto"}, name="contact") */ public function contact () { // ... } /** * @Route("/page/{slug}", name="page") */ public function page ( $slug ) { // ... } }

The four resulting routes generated by Symfony will be: