diff --git a/src/Symfony/Component/Translation/Tests/TranslatorCacheTest.php b/src/Symfony/Component/Translation/Tests/TranslatorCacheTest.php index 24514b73dc96..88a73de28117 100644 --- a/src/Symfony/Component/Translation/Tests/TranslatorCacheTest.php +++ b/src/Symfony/Component/Translation/Tests/TranslatorCacheTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Translation\Tests; +use Symfony\Component\Translation\Loader\ArrayLoader; use Symfony\Component\Translation\Translator; use Symfony\Component\Translation\MessageCatalogue; use Symfony\Component\Translation\MessageSelector; @@ -164,6 +165,34 @@ public function testLoadCatalogueWithCachingWithInvalidLocale() } } + public function testFallbackCatalogueIsCachedIndependently() + { + $translator = new Translator('a', null, $this->tmpDir); + $translator->setFallbackLocales(array('b', 'c')); + + $translator->addLoader('array', new ArrayLoader()); + $translator->addResource('array', array('foo' => 'foo (a)'), 'a'); + $translator->addResource('array', array('foo' => 'foo (b)'), 'b'); + $translator->addResource('array', array('bar' => 'bar (b)'), 'b'); + $translator->addResource('array', array('baz' => 'baz (c)'), 'c'); + + $translator->trans('foo'); // Prime the cache with the "a", "b" and "c" catalogues + + /* + * Now, a fresh translator should be able to re-use the cached "b" catalogue. + * It does not need to have a loader registered, it can use the cache. + */ + $translator = new Translator('b', null, $this->tmpDir); + $this->assertEquals('bar (b)', $translator->trans('bar')); + + /* + * Also, as this second translator does not have "c" as a fallback locale, "baz" from the "c" catalogue + * must not be available. (It was a registered fallback locale *at the time the cache was + * primed*). + */ + $this->assertEquals('baz', $translator->trans('baz')); + } + protected function getCatalogue($locale, $messages) { $catalogue = new MessageCatalogue($locale); diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index 001788479f5f..0aa222b6dc4c 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -351,15 +351,13 @@ protected function initializeCatalogue($locale) private function initializeCacheCatalogue($locale, $forceRefresh = false) { if (isset($this->catalogues[$locale])) { - return; + return; // don't see how this could ever happen...? } $this->assertValidLocale($locale); $cache = new ConfigCache($this->cacheDir.'/catalogue.'.$locale.'.php', $this->debug); if ($forceRefresh || !$cache->isFresh()) { $this->initializeCatalogue($locale); - $fallbackContent = $this->getFallbackContent($this->catalogues[$locale]); - $content = sprintf(<<getResourcesHash($locale), $locale, - var_export($this->catalogues[$locale]->all(), true), - $fallbackContent + var_export($this->catalogues[$locale]->all(), true) ); $cache->write($content, $this->catalogues[$locale]->getResources()); @@ -399,51 +395,7 @@ private function initializeCacheCatalogue($locale, $forceRefresh = false) } $this->catalogues[$locale] = $catalogue; - } - - private function getFallbackContent(MessageCatalogue $catalogue) - { - if (!$this->debug) { - // merge all fallback catalogues messages into $catalogue - $fallbackCatalogue = $catalogue->getFallbackCatalogue(); - $messages = $catalogue->all(); - while ($fallbackCatalogue) { - $messages = array_replace_recursive($fallbackCatalogue->all(), $messages); - $fallbackCatalogue = $fallbackCatalogue->getFallbackCatalogue(); - } - foreach ($messages as $domain => $domainMessages) { - $catalogue->add($domainMessages, $domain); - } - - return ''; - } - - $fallbackContent = ''; - $current = ''; - $replacementPattern = '/[^a-z0-9_]/i'; - $fallbackCatalogue = $catalogue->getFallbackCatalogue(); - while ($fallbackCatalogue) { - $fallback = $fallbackCatalogue->getLocale(); - $fallbackSuffix = ucfirst(preg_replace($replacementPattern, '_', $fallback)); - $currentSuffix = ucfirst(preg_replace($replacementPattern, '_', $current)); - - $fallbackContent .= sprintf(<<addFallbackCatalogue(\$catalogue%s); - -EOF - , - $fallbackSuffix, - $fallback, - var_export($fallbackCatalogue->all(), true), - $currentSuffix, - $fallbackSuffix - ); - $current = $fallbackCatalogue->getLocale(); - $fallbackCatalogue = $fallbackCatalogue->getFallbackCatalogue(); - } - - return $fallbackContent; + $this->loadFallbackCatalogues($locale); } private function getResourcesHash($locale) @@ -455,6 +407,11 @@ private function getResourcesHash($locale) return sha1(serialize($this->resources[$locale])); } + /** + * Initializes $this->catalogues[$locale] by running the appropriate loaders. + * + * @param $locale The locale to load the catalogue for + */ private function doLoadCatalogue($locale) { $this->catalogues[$locale] = new MessageCatalogue($locale); @@ -471,13 +428,15 @@ private function doLoadCatalogue($locale) private function loadFallbackCatalogues($locale) { - $current = $this->catalogues[$locale]; - foreach ($this->computeFallbackLocales($locale) as $fallback) { if (!isset($this->catalogues[$fallback])) { - $this->doLoadCatalogue($fallback); + $this->loadCatalogue($fallback); } + } + $current = $this->catalogues[$locale]; + + foreach ($this->computeFallbackLocales($locale) as $fallback) { $current->addFallbackCatalogue($this->catalogues[$fallback]); $current = $this->catalogues[$fallback]; } @@ -486,19 +445,36 @@ private function loadFallbackCatalogues($locale) protected function computeFallbackLocales($locale) { $locales = array(); + $candidateLocales = array(); + + if (strrchr($this->locale, '_') !== false) { + $candidateLocales[] = substr($this->locale, 0, -strlen(strrchr($this->locale, '_'))); + } + foreach ($this->fallbackLocales as $fallback) { + $candidateLocales[] = $fallback; + if (strrchr($fallback, '_') !== false) { + $candidateLocales[] = substr($fallback, 0, -strlen(strrchr($fallback, '_'))); + } + } + + $candidateLocales = array_unique($candidateLocales); + + $findSecondLevelFallback = in_array($locale, $candidateLocales); + $seenLocale = false; + + foreach ($candidateLocales as $fallback) { if ($fallback === $locale) { + $seenLocale = true; continue; } - $locales[] = $fallback; - } - - if (strrchr($locale, '_') !== false) { - array_unshift($locales, substr($locale, 0, -strlen(strrchr($locale, '_')))); + if ($seenLocale || !$findSecondLevelFallback) { + $locales[] = $fallback; + } } - return array_unique($locales); + return $locales; } /**