piwik/piwik — pull request #6909 by mnapoli (2014-12-30 04:14:14+00:00)
Title: Refactoring translation handling into a Translation component

Translations were stored in a `$GLOBALS` array and handled by a static class `Piwik\Translate`. Furthermore, handling of translations were spread all over the place, caching logic was mixed with translation logic, …

This refactoring contains:

- created a **Translation** component following the naming of Symfony's Translation component ("Translator" class, "Loaders", …)
- all logic related to loading/handling translations is now encapsulated in that component
- classes of that component are using dependency injection
- `Piwik\Translate` is kept for BC and forwards call to the new `Translator` class
- that new component is decoupled from the rest of Piwik (except for a few exceptions to improve later): it doesn't know about the HTTP request, about Plugins, about Piwik directories, etc...
- translations are **lazily loaded**, i.e. you ask for a french translation then french translations will be loaded automatically
- that means that Piwik/plugins don't have to tell the translator to load anything: the plugin manager just configures the directories where to find translations (which are the installed plugins…)
- there is a `LoaderInterface` with the following implementations:
- `JsonFileLoader`
- `LoaderCache`: caches another loader by wrapping it (which would be the `JsonFileLoader`)
- that way of caching things brings the following benefits:
- caching can be configured in DI, and disabled with the container using the new `dev` environment (which addresses [this TODO](https://github.com/piwik/piwik/blob/master/core/Plugin/Manager.php#L716))
- core translations are cached as well as the plugin ones, which fixes #6060
- as said above, there's a new `dev` environment (= new DI config file) where translation cache is disabled: this environment can be used for other things as well
- there is now a fallback mechanism (previously all translations were merged together in one array): if a french/… translation is not found, then the english one is returned
- that fallback mechanism would allow to do #4983 (regional overrides) by having multiple fallbacks, for example: `fr_CA` (canadian french) would fallback to `fr` which would fallback to `en` (not implemented)

And I was able to unit tests the new classes, which is just an awesome feeling :)

There's still a lot of room for improvement, I'll keep working on that PR. Feedback welcome!