Andrei Herford
Andrei Herford

Reputation: 18729

Symfony Localization: Redirect /xyz to /en/xyz

I a working on a web app project using Symfony 2. The page will be available in three different languages. More languages will be added later.

So somepage will be available under /en/somepage, /fr/somepage and so on.

I solved this in two steps:

  1. Visitor of of the homepage / are automatically redirected to localized homepage /en, /fr, etc. according to the HTTP language header
  2. All routes are imported with prefix="/{_locale}"

This is the code I use:

app/config/config.xml

...
parameters:
    app.default_locale: en
    app.locales: en|fr|es

src/AppBundle/Resources/config/routing.xml

<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">

    <!-- Home route to redirect to the right route -->
    <route id="home_redirect" path="" methods="GET">
        <default key="_controller">AppBundle:Public:home</default>
    </route>

    <!-- Routes for the localized public pages -->
    <import
        resource="@AppBundle/Resources/config/public_routes.xml" prefix="/{_locale}" >

        <requirement key="_locale">%app.locales%</requirement>
        <default key="_locale">%app.default_locale%</default>        
    </import>

    <!-- Routes that should not be extended by any locale -->
    <import resource="@AppBundle/Resources/config/unlocalized_routes.xml" />
</routes>

src/AppBundle/Resources/config/public_routes.xml

...

<route id="home" path="" methods="GET">
    <default key="_controller">AppBundle:Public:home</default>
</route>

<route id="public_register" path="/somepage" methods="GET">
    <default key="_controller">AppBundle:Public:register</default>
</route>

...

src/AppBundle/Controller/PublicController.php

class PublicController extends Controller {

    public function homeAction(Request $request) {
        // Check if the locale is set in the url
        $locale = $request->attributes->get('_locale');

        if (!$locale) {
            // Try to get the preferred language from the request header
            $locale = AppSettings::getLanguage($request);

            return $this->redirectToRoute('home', array('_locale' => $locale));
        }
        elseif (!AppSettings::checkLanguage($locale)) {
            // Language in URL is not supported --> Page not found
            throw $this->createNotFoundException();
        }

        return $this->render('AppBundle:Default:homepage.html.twig');
    }

}

So visiting example.com is not problem. This will be redirected to example.com/xx where xx is the locale. Additionally all routes imported from public_routes.xml are automatically prefixed with the locale. Routes imported from unlocalized_routes.xml on the other hand, are still available directly / without locale.

However visiting example.com/somepage (defined in public_routes.xml) directly is not possible. One would have to use a supported locale like example.com/en/somepage

I would like to make it possible, to call all routes from public_routes.xml directly (without locale) and let Symfony handle the redirection to the localized page/route. Just like it possible for the homepage / right now.

Of course I could add someroute_redirect to the main routing file for all public routes (as I did for the homepage). This would be possible but quite cumbersome. I am looking for a automated solution here.

Any idea how this can be solved?

Upvotes: 1

Views: 336

Answers (1)

1ed
1ed

Reputation: 3668

You have several options here:

  • create an action to handle the redirect and create a catch-all route for it and put it into app/config/routing.yml as the very last route. You can check the order with the router:debug (or debug:router) command. The action will be executed if no other route match.

  • you can create an event listener for the kernel.exception event and set a redirect response there

  • use an existing bundle JMSI18nRoutingBundle or BeSimpleI18nRoutingBundle

I would go with a bundle.

Upvotes: 2

Related Questions