zendframework/zf2 — pull request #4050 by DASPRiD (2013-03-16 01:21:58+00:00)
Title: [WIP] Translable routing segments

**Preamble**
This is the initial prototype for the translatable segments. It is considered work in progress, although it should be fully functional. Eventually, only the unit tests are missing.

I already implemented the parsing of translatable segments very early in the beginning, but totally forgot about them until now. This evening I was finally able to make up a good way to implement them.

**Introduction**
So, first of, I completely killed translatable parameters, and only left translatable literals in. This has the reason, that translatable parameters would eventually only serve a very small set of possible values, which can eventually be represented with child-routes and translatable literals. This also makes the implementation a lot easier.

To not force an already configured translator when the router itself is fetched from the service manager the very first time, I decided to move the translation logic completely into the match() and assemble() methods. This also allows to re-use the matching methods with different locales (there may be some use-cases for that, e.g. testing URLs in a CMS).

**New hard dependency**
The problem now comes with a new hard dependency (```Zend\I18n```), of which I'm not really proud of. But considering that we already have a strong binding on ```Zend\I18n``` in our view helpers, it makes me feel a little better.

The segment route itself is not that much of a problem for this, as it only has a ```use Zend\I18n\Translator\Translator``` in its head, but only actually uses that class if translatable segments exist. On the other hand, we have the TreeRouteStack, which now implements the TranslatorAwareInterface. This is required so the translator is injected by the ServiceManager.

As some of you can probably see, I could extend the TreeRouteStack and place that one in the ```Zend\I18n``` namespace. Though this would kinda split up two things, which are already related (i18n TreeRouteStack and Segment route). Extending the Segment route in the ```Zend\I18n``` namespace wouldn't work, as it would almost be a complete rewrite, as it touches many internals there.

So eventually, I decided to leave everything in the ```Zend\Mvc\Router\Http``` namespace.

**Usage**
Eventually, I introduced a few new features here and there, to make the implementation as sane as possible. No BC breaks were done for it, at least as far as I know. All existing unit tests pass (except for the ones which tested for the "not implemented" exceptions, but those were already removed by the initial comit).

To make use of the translatable segments, you first have to inject a translator into the router. This can be done either automatically by the ServiceManager (thanks to the ```TranslatorAwareInterface```) or manually through ```$router->setTranslator()```.

Optionally you can specify a text domain to use for route translations with ```$router->setTranslatorTextDomain()```. If you don't set one, the "default" text domain will be used.

Now you are ready to create translatable segments. Take for instance the following route definition, where the translatable segment is encapsulated in curly brackets:

```
/{bacon}/:id
```

When matching, the ```bacon``` parameter will be replaced with the translation of the message id "bacon" in the matching regex and then the regex will be evaluated against the request as usual. When assembling, the same thing happens again. This is a much more efficient approach than the one we had in ZF1, where the route had to get **all** translations from the translator.

You also have the possibility to change the translator, the text domain and the locale on-the-fly both for matching and for assembling. For the match() method, a third (non-interface) ```array $options = array()``` parameter was added after the ```$pathOffset``` parameter. This allows to pass down "translator", "text_domain" and "locale" down the tree. The same options are also taken into account by the ```assemble()``` method.

**Sidenote**
I also fixed a few formatting issues and changed some docblocks, nothing to worry about :)