Reputation: 18729
I am working on a WebApp project using Symfony 2.8. I would like to add different languages to the page. Depending on the users locale all routes/URLs should be changed from /some/url
to /locale/some/url, e.g.
/en/some/url`.
Before adding the languages the main routing file looked like this:
<?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">
<!-- Routes for the public pages -->
<import
resource="@AppBundle/Resources/config/routing/public_routes.xml" />
...
</routes>
And the public_routes.xml
has the following content:
<?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">
<route id="home" path="" methods="GET">
<default key="_controller">AppBundle:Default:home</default>
</route>
<route id="public_price" path="/price" methods="GET">
<default key="_controller">AppBundle:Default:price</default>
</route>
<route id="public_about" path="/about" methods="GET">
<default key="_controller">AppBundle:Default:about</default>
</route>
...
</routes>
So far, so simple. Now I have added the following to the routing to add the localization:
<?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:Default:home</default>
</route>
<!-- Routes for the localized public pages -->
<import
resource="@AppBundle/Resources/config/routing/public_routes.xml"
prefix="/{_locale}" />
...
</routes>
So the import of the public pages was extended with prefix="/{_locale}"
which automatically adds the current locale to all routes from public_routes.xml
.
This works fine. I can now navigate to /en
, /en/price
, /en/about
, etc.
However the still has to be an "empty" route. Otherwise the domain itself would have not valid route anymore. (BTW: Is there any difference between path=""
and path="/"
?)
This is handeled by the new home_redirect
route with its controller:
public function homeAction(Request $request) {
$locale = $request->attributes->get('_locale');
if (!$locale) {
// Try to get the preferred language from the request
$locale = MySettings::getLanguage($request);
return $this->redirectToRoute('home', array('_locale' => $locale));
} elseif (!MySettings::checkLanguage($locale)) {
// Invalid Locale...
throw $this->createNotFoundException();
}
return $this->render('AppBundle:Default:homepage.html.twig');
}
So if _locale
is set for the request, the homeAction
checks if the language is supported or throws an error. If _locale
is not set, homeAction
tries to get the current _locale from the request (e.g. from the browser accepted languages).
THE PROBLEM:
This solution above workes fine for all calles to /
. In this case _locale
is not set and thus the call is re-directed to /someLocale/
, e.g. `/en/.
BUT: All calls to /somepage
are also handled by homeAction
. This is because somepage
is interpreted as locale! Thus homeAction
gets called with $request->attributes->get('_locale') == 'somepage'
. This cannot work obviously.
So if someone calls the old URL /about
instead of the new /en/about
, the routing systems matches this call with route home
with _locale about
and the page is not found.
Where exactly does Symfony extracts _locale
from the URL? Is it possible to intercept this extraction and make it a little bit smarter? E.g. to ignore all "locales" that are more than 2 letters long?
Thanks!
Upvotes: 1
Views: 1323
Reputation: 17906
simply make use of requirements
and default
properties of routedefinition
so you can set {_locale} for all routes
requirements:
_locale: fr|en
defaults: { _locale: fr}
in this yml example it defaults to "fr" if no _locale was given e.g /
and due to the requirements about
would not be matched as _locale
Upvotes: 3