Sling Academy
Home/PHP/Localized (i18n) Routes in Symfony: A Practical Guide

Localized (i18n) Routes in Symfony: A Practical Guide

Last updated: January 13, 2024

Introduction

Translating routes in a Symfony application is crucial for creating a multilingual website that provides a localized user experience. Symfony’s Internationalization (i18n) feature allows developers to create routes that adapt based on the user’s locale, improving accessibility and SEO. In this tutorial, we’ll explore how to implement localized routes in your Symfony project from basics to advanced concepts.

Basic Localized Routing

To begin with, make sure you have the Symfony Translation component installed. Run the following Composer command if you’re unsure:

composer require symfony/translation

Let’s start by defining a simple localized route in the routes.yaml file:

app_hello:
    path:
        en: '/hello'
        fr: '/bonjour'
    controller: App\Controller\DefaultController::hello

This will create a route that responds to either /hello or /bonjour, depending on the locale. In your controller, you might have something like this:

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class DefaultController extends AbstractController
{
    public function hello()
    {
        // Your logic here
    }
}

When a user visits /hello, the route will match the English locale, while /bonjour will match the French locale.

Dynamic Locale Setting

In more complex applications, you often need to determine the locale dynamically. This can be done by configuring a listeners in the services.yaml:

services:
    App\EventListener\LocaleListener:
        tags:
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 20 }

Then, in your listener:

namespace App\EventListener;

use Symfony\Component\HttpKernel\Event\RequestEvent;

class LocaleListener
{
    public function onKernelRequest(RequestEvent $event)
    {
        $request = $event->getRequest();
        if ($request->hasPreviousSession()) {
            // Try to see if the locale has been set as a route parameter
            if ($locale = $request->attributes->get('_locale')) {
                $request->getSession()->set('_locale', $locale);
            } else {
                // If no explicit locale has been set on this request, use one from the session
                $request->setLocale($request->getSession()->get('_locale', $request->getDefaultLocale()));
            }
        }
    }
}

This listener will check the request for a ‘_locale’ parameter and set the session’s locale accordingly, which can then be used by subsequent requests to define the user’s preferred language.

Advanced Locale Routing

For even more control over your localized routes, Symfony allows you to use custom route loaders. Here’s an example:

namespace App\Routing;

use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Config\Loader\Loader;

class ExtraLoader extends Loader
{
    private $isLoaded = false;

    public function load($resource, $type = null)
    {
        if ($this->isLoaded) {
            throw new \Exception('Do not add this loader twice');
        }

        $routes = new RouteCollection();

        // Define your localized routes here
        $path = ['en' => '/about', 'fr' => '/a-propos'];
        $routes->add('app_about', new Route($path, ['_controller' => 'App\Controller\DefaultController::about']));

        $this->isLoaded = true;

        return $routes;
    }

    public function supports($resource, $type = null)
    {
        return 'extra' === $type;
    }
}

This extra loader lets you define routes in PHP, giving you more flexibility. It’s important to use this in combination with configuration to avoid issues with route loading:

app_extra_routes:
    resource: .
    type: extra

With ‘extra’ type now supported, Symfony can utilize this custom loader for more nuanced route localization.

Locale-Specific Requirements

Sometimes your routes might need patterns that are different for each locale. We can manage this by specifying localized route requirements like so:

app_contact:
    path:
        en: '/contact'
        fr: '/contactez'
    controller: App\Controller\ContactController::index
    requirements:
        _locale: 'en|fr'

This tells Symfony that for the ‘app_contact’ route, the locale must be either English or French. Additional requirements can be set up similarly, ensuring precise route matching based on locale.

Conclusion

Localized routing is a powerful feature in Symfony that enables the creation of multilingual applications. By defining routes per locale, dynamically setting the locale via event listeners, leveraging custom route loaders, and implementing locale-specific requirements, developers can offer a tailored user experience for users around the world. Through the use of these strategies, your Symfony application will become more accessible and user-friendly on a global scale.

Next Article: Generating URLs in Symfony: A Practical Guide

Previous Article: Using Route Groups with Prefixes in Symfony: A Complete Guide

Series: Symfony & Doctrine Tutotirlas

PHP

You May Also Like

  • Pandas DataFrame.value_counts() method: Explained with examples
  • Constructor Property Promotion in PHP: Tutorial & Examples
  • Understanding mixed types in PHP (5 examples)
  • Union Types in PHP: A practical guide (5 examples)
  • PHP: How to implement type checking in a function (PHP 8+)
  • Symfony + Doctrine: Implementing cursor-based pagination
  • Laravel + Eloquent: How to Group Data by Multiple Columns
  • PHP: How to convert CSV data to HTML tables
  • Using ‘never’ return type in PHP (PHP 8.1+)
  • Nullable (Optional) Types in PHP: A practical guide (5 examples)
  • Explore Attributes (Annotations) in Modern PHP (5 examples)
  • An introduction to WeakMap in PHP (6 examples)
  • Type Declarations for Class Properties in PHP (5 examples)
  • Static Return Type in PHP: Explained with examples
  • PHP: Using DocBlock comments to annotate variables
  • PHP: How to ping a server/website and get the response time
  • PHP: 3 Ways to Get City/Country from IP Address
  • PHP: How to find the mode(s) of an array (4 examples)
  • PHP: Calculate standard deviation & variance of an array