[Translation] added support for more than one fallback locale
This commit is contained in:
parent
3a4d1a6a22
commit
5526072dba
@ -38,6 +38,7 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c
|
|||||||
|
|
||||||
### Translation
|
### Translation
|
||||||
|
|
||||||
|
* added support for more than one fallback locale
|
||||||
* added support for translations in ResourceBundles
|
* added support for translations in ResourceBundles
|
||||||
* added support for extracting translation messages from templates (Twig and PHP)
|
* added support for extracting translation messages from templates (Twig and PHP)
|
||||||
* added dumpers for translation catalogs
|
* added dumpers for translation catalogs
|
||||||
|
@ -24,7 +24,7 @@ class Translator implements TranslatorInterface
|
|||||||
{
|
{
|
||||||
protected $catalogues;
|
protected $catalogues;
|
||||||
protected $locale;
|
protected $locale;
|
||||||
private $fallbackLocale;
|
private $fallbackLocales;
|
||||||
private $loaders;
|
private $loaders;
|
||||||
private $resources;
|
private $resources;
|
||||||
private $selector;
|
private $selector;
|
||||||
@ -44,6 +44,7 @@ class Translator implements TranslatorInterface
|
|||||||
$this->loaders = array();
|
$this->loaders = array();
|
||||||
$this->resources = array();
|
$this->resources = array();
|
||||||
$this->catalogues = array();
|
$this->catalogues = array();
|
||||||
|
$this->fallbackLocales = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -95,18 +96,18 @@ class Translator implements TranslatorInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the fallback locale.
|
* Sets the fallback locale(s).
|
||||||
*
|
*
|
||||||
* @param string $locale The fallback locale
|
* @param string|array $locale The fallback locale(s)
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
public function setFallbackLocale($locale)
|
public function setFallbackLocale($locales)
|
||||||
{
|
{
|
||||||
// needed as the fallback locale is used to fill-in non-yet translated messages
|
// needed as the fallback locales are linked to the already loaded catalogues
|
||||||
$this->catalogues = array();
|
$this->catalogues = array();
|
||||||
|
|
||||||
$this->fallbackLocale = $locale;
|
$this->fallbackLocales = is_array($locales) ? $locales : array($locales);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -142,15 +143,28 @@ class Translator implements TranslatorInterface
|
|||||||
$this->loadCatalogue($locale);
|
$this->loadCatalogue($locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->catalogues[$locale]->defines((string) $id, $domain)) {
|
$id = (string) $id;
|
||||||
// we will use the fallback
|
|
||||||
$locale = $this->computeFallbackLocale($locale);
|
if (!$this->catalogues[$locale]->defines($id, $domain)) {
|
||||||
|
// we will use the locale fallback
|
||||||
|
foreach ($this->computeFallbackLocales($locale) as $fallback) {
|
||||||
|
if ($this->catalogues[$fallback]->defines($id, $domain)) {
|
||||||
|
$locale = $fallback;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return strtr($this->selector->choose($this->catalogues[$locale]->get((string) $id, $domain), (int) $number, $locale), $parameters);
|
return strtr($this->selector->choose($this->catalogues[$locale]->get($id, $domain), (int) $number, $locale), $parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function loadCatalogue($locale)
|
protected function loadCatalogue($locale)
|
||||||
|
{
|
||||||
|
$this->doLoadCatalogue($locale);
|
||||||
|
$this->optimizeCatalogue($locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function doLoadCatalogue($locale)
|
||||||
{
|
{
|
||||||
$this->catalogues[$locale] = new MessageCatalogue($locale);
|
$this->catalogues[$locale] = new MessageCatalogue($locale);
|
||||||
|
|
||||||
@ -162,29 +176,29 @@ class Translator implements TranslatorInterface
|
|||||||
$this->catalogues[$locale]->addCatalogue($this->loaders[$resource[0]]->load($resource[1], $locale, $resource[2]));
|
$this->catalogues[$locale]->addCatalogue($this->loaders[$resource[0]]->load($resource[1], $locale, $resource[2]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->optimizeCatalogue($locale);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function optimizeCatalogue($locale)
|
private function optimizeCatalogue($locale)
|
||||||
{
|
{
|
||||||
if (!$fallback = $this->computeFallbackLocale($locale)) {
|
$current = $this->catalogues[$locale];
|
||||||
return;
|
foreach ($this->computeFallbackLocales($locale) as $fallback) {
|
||||||
}
|
if (!isset($this->catalogues[$fallback])) {
|
||||||
|
$this->doLoadCatalogue($fallback);
|
||||||
|
}
|
||||||
|
|
||||||
if (!isset($this->catalogues[$fallback])) {
|
$current->addFallbackCatalogue($this->catalogues[$fallback]);
|
||||||
$this->loadCatalogue($fallback);
|
$current = $this->catalogues[$fallback];
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->catalogues[$locale]->addFallbackCatalogue($this->catalogues[$fallback]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function computeFallbackLocale($locale)
|
private function computeFallbackLocales($locale)
|
||||||
{
|
{
|
||||||
|
$locales = $this->fallbackLocales;
|
||||||
|
|
||||||
if (strlen($locale) > 3) {
|
if (strlen($locale) > 3) {
|
||||||
return substr($locale, 0, -strlen(strrchr($locale, '_')));
|
array_unshift($locales, substr($locale, 0, -strlen(strrchr($locale, '_'))));
|
||||||
} else {
|
|
||||||
return $this->fallbackLocale;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $locales;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,20 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertEquals('foobar', $translator->trans('bar'));
|
$this->assertEquals('foobar', $translator->trans('bar'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSetFallbackLocaleMultiple()
|
||||||
|
{
|
||||||
|
$translator = new Translator('en', new MessageSelector());
|
||||||
|
$translator->addLoader('array', new ArrayLoader());
|
||||||
|
$translator->addResource('array', array('foo' => 'foo (en)'), 'en');
|
||||||
|
$translator->addResource('array', array('bar' => 'bar (fr)'), 'fr');
|
||||||
|
|
||||||
|
// force catalogue loading
|
||||||
|
$translator->trans('bar');
|
||||||
|
|
||||||
|
$translator->setFallbackLocale(array('fr_FR', 'fr'));
|
||||||
|
$this->assertEquals('bar (fr)', $translator->trans('bar'));
|
||||||
|
}
|
||||||
|
|
||||||
public function testTransWithFallbackLocale()
|
public function testTransWithFallbackLocale()
|
||||||
{
|
{
|
||||||
$translator = new Translator('fr_FR', new MessageSelector());
|
$translator = new Translator('fr_FR', new MessageSelector());
|
||||||
@ -62,6 +76,19 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertEquals('foobar', $translator->trans('bar'));
|
$this->assertEquals('foobar', $translator->trans('bar'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testTransWithFallbackLocaleTer()
|
||||||
|
{
|
||||||
|
$translator = new Translator('fr_FR', new MessageSelector());
|
||||||
|
$translator->addLoader('array', new ArrayLoader());
|
||||||
|
$translator->addResource('array', array('foo' => 'foo (en_US)'), 'en_US');
|
||||||
|
$translator->addResource('array', array('bar' => 'bar (en)'), 'en');
|
||||||
|
|
||||||
|
$translator->setFallbackLocale(array('en_US', 'en'));
|
||||||
|
|
||||||
|
$this->assertEquals('foo (en_US)', $translator->trans('foo'));
|
||||||
|
$this->assertEquals('bar (en)', $translator->trans('bar'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException RuntimeException
|
* @expectedException RuntimeException
|
||||||
*/
|
*/
|
||||||
@ -173,6 +200,28 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
|
$this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testTransChoiceFallbackBis()
|
||||||
|
{
|
||||||
|
$translator = new Translator('ru', new MessageSelector());
|
||||||
|
$translator->setFallbackLocale(array('en_US', 'en'));
|
||||||
|
$translator->addLoader('array', new ArrayLoader());
|
||||||
|
$translator->addResource('array', array('some_message2' => 'one thing|%count% things'), 'en_US');
|
||||||
|
|
||||||
|
$this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testTransChoiceFallbackWithNoTranslation()
|
||||||
|
{
|
||||||
|
$translator = new Translator('ru', new MessageSelector());
|
||||||
|
$translator->setFallbackLocale('en');
|
||||||
|
$translator->addLoader('array', new ArrayLoader());
|
||||||
|
|
||||||
|
$this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class String
|
class String
|
||||||
|
Reference in New Issue
Block a user