Description
Symfony version(s) affected: 5.2.3, but probably any from 4.1.x
Description
Localized routes that are prefixed with a locale prefix encounter a number of issues:
- When all locales are prefixed, the base route is still accessible.
- When all locales except the default are prefixed, the default route doesn't switch the locale back to the default langage.
How to reproduce
Say you have a controller method bearing the following annotation:
@Route("/shopping", name="shopping")
Issue 1. When all locales are prefixed, the base route is still accessible
This configuration:
shopping:
resource: ../../src/Controller/Application/Shopping/
type: annotation
prefix:
fr: '/fr'
en: '/en'
Will give you 3 routes:
/fr/shopping
/en/shopping
/shopping
which is undesired
Issue 2. When the default locale is not prefixed, the default route doesn't switch the locale back to the default langage
When you don't force a prefix for the default locale, as in this configuration:
shopping:
resource: ../../src/Controller/Application/Shopping/
type: annotation
prefix:
fr: '' # "fr" is the default locale here
en: '/en'
It will give you 2 routes:
/shopping
/en/shopping
Which is the desired behavior. But another bug appears:
- if you visit
/shopping
, the site is in french - if you then go to
/en/shopping
, the site switches to english - if you then go to
/shopping
, the site stays in english
Both A and B issues are undesirable (notably from an SEO standpoint):
- Issue 1:
/shopping
is an unwanted duplicate content of/fr/shopping
- Issue 2: if the bot that visits the website isn't stateless, it can be served english content on a french page (making it a duplicate too, and unreferencing your french page).
Additional context
When routes are declared using the annotation:
* @Route({
* "fr": "/fr/shopping",
* "en": "/en/shopping"
* }, name="shopping")
The issue 1 does not exist. There is no /shopping
route.
Same thing goes for a route that wouldn't have the prefix for the default locale:
* @Route({
* "fr": "/shopping",
* "en": "/en/shopping"
* }, name="shopping")
The issue 2 does not exist. The locale switches correctly back to fr when visiting /shopping
, as expected.
So it seems the issue lies in the way prefixes are implemented.