You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This PR was merged into the 4.1-dev branch.
Discussion
----------
[Routing] Implement i18n routing
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? |no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | N/A
| License | MIT
This PR introduces support for I18N routing into core. This is a port from a bundle I've made recently, now merged into the default implementation. While it's ok to have this as a bundle, it was suggested by @nicolas-grekas to create a PR for this so it can be included into the core.
## New usages
### YAML
```yaml
contact:
controller: ContactController::formAction
path:
en: /send-us-an-email
nl: /stuur-ons-een-email
```
Will be effectively the same as declaring:
```yaml
contact.en:
controller: ContactController::formAction
path: /send-us-an-email
defaults:
_locale: en
contact.nl:
controller: ContactController::formAction
path: /stuur-ons-een-email
defaults:
_locale: nl
```
### Annotation usage:
```php
<?php
use Symfony\Component\Routing\Annotation\Route;
class ContactController
{
/**
* @route({"en": "/send-us-an-email", "nl": "/stuur-ons-een-email"}, name="contact")
*/
public function formAction()
{
}
}
/**
* @route("/contact")
*/
class PrefixedContactController
{
/**
* @route({"en": "/send-us-an-email", "nl": "/stuur-ons-een-email"}, name="contact")
*/
public function formAction()
{
}
}
```
### Route generation
```php
<?php
/** @var UrlGeneratorInterface $urlGenerator */
$urlWithCurrentLocale = $urlGenerator->generate('contact');
$urlWithSpecifiedLocale = $urlGenerator->generate('contact', ['_locale' => 'nl']);
```
Route generation is based on your request locale. When not available it falls back on a configured default. This way of route generation means you have a "route locale switcher" out of the box, but generate the current route with another locale for most cases.
## Advantages
Having i18n routes defined like this has some advantages:
* Less error prone.
* No need to keep `requirements` or `defaults` in sync with other definitions.
* No need to `{_locale}` in the path (bad for route matching performance).
* Better developer experience.
### Next steps
I've ported all the things the bundle supported, before moving on I'd like to discuss this first in order not to waste our collective time. This initial PR should give a clear enough picture to see what/how/why this is done.
If and when accepted I/we can move forward to implement the XML loader and @nicolas-grekas mentioned there should be a `Configurator` implemented for this as well. He opted to help with this (for which I'm very thankful).
- [x] Yaml Loader
- [x] Annotation Loader
- [x] XML Loader
- [x] PHP Loader?
- [ ] Documentation
Commits
-------
4ae66dc [Routing] Handle "_canonical_route"
e32c414 [Routing] Implement i18n routing
thrownew \LogicException(sprintf('Route to "%s" is missing paths for locale(s) "%s".', $class->name.'::'.$method->name, implode('", "', array_keys($missing))));
169
+
} else {
170
+
foreach ($pathas$locale => $localePath) {
171
+
if (!isset($prefix[$locale])) {
172
+
thrownew \LogicException(sprintf('Route to "%s" with locale "%s" is missing a corresponding prefix in class "%s".', $method->name, $locale, $class->name));
173
+
}
174
+
175
+
$paths[$locale] = $prefix[$locale].$localePath;
176
+
}
177
+
}
178
+
} elseif (\is_array($prefix)) {
179
+
foreach ($prefixas$locale => $localePrefix) {
180
+
$paths[$locale] = $localePrefix.$path;
181
+
}
182
+
} else {
183
+
$paths[] = $prefix.$path;
184
+
}
163
185
164
-
$collection->add($name, $route);
186
+
foreach ($method->getParameters() as$param) {
187
+
if (isset($defaults[$param->name]) || !$param->isDefaultValueAvailable()) {
188
+
continue;
189
+
}
190
+
foreach ($pathsas$locale => $path) {
191
+
if (false !== strpos($path, sprintf('{%s}', $param->name))) {
thrownew \LogicException(sprintf('Collection "%s" is missing prefixes for locale(s) "%s".', $this->name, implode('", "', array_keys($missing))));
72
+
} else {
73
+
foreach ($prefixas$locale => $localePrefix) {
74
+
if (!isset($this->parentPrefixes[$locale])) {
75
+
thrownew \LogicException(sprintf('Collection "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $this->name, $locale));
thrownew \InvalidArgumentException(sprintf('Route "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $name, $locale));
0 commit comments