From 36ddfd58b926d29256dba85532ca94283f27b38e Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Wed, 8 May 2019 20:13:28 +0200 Subject: [PATCH] [Intl] Add FallbackTrait for data generation --- .../Intl/Data/Generator/FallbackTrait.php | 73 +++++++++++++++++ .../Data/Generator/LocaleDataGenerator.php | 82 +++++++------------ 2 files changed, 102 insertions(+), 53 deletions(-) create mode 100644 src/Symfony/Component/Intl/Data/Generator/FallbackTrait.php diff --git a/src/Symfony/Component/Intl/Data/Generator/FallbackTrait.php b/src/Symfony/Component/Intl/Data/Generator/FallbackTrait.php new file mode 100644 index 0000000000..25e177abfa --- /dev/null +++ b/src/Symfony/Component/Intl/Data/Generator/FallbackTrait.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Intl\Data\Generator; + +use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface; +use Symfony\Component\Intl\Locale; + +/** + * @author Roland Franssen + * + * @internal + */ +trait FallbackTrait +{ + private $fallbackCache = []; + private $generatingFallback = false; + + /** + * @param string $tempDir + * @param string $displayLocale + * + * @return array|null + * + * @see AbstractDataGenerator::generateDataForLocale() + */ + abstract protected function generateDataForLocale(BundleEntryReaderInterface $reader, $tempDir, $displayLocale); + + /** + * @param string $tempDir + * + * @return array|null + * + * @see AbstractDataGenerator::generateDataForRoot() + */ + abstract protected function generateDataForRoot(BundleEntryReaderInterface $reader, $tempDir); + + /** + * @param string $tempDir + * @param string $displayLocale + * + * @return array + */ + private function generateFallbackData(BundleEntryReaderInterface $reader, $tempDir, $displayLocale) + { + if (null === $fallback = Locale::getFallback($displayLocale)) { + return []; + } + + if (isset($this->fallbackCache[$fallback])) { + return $this->fallbackCache[$fallback]; + } + + $prevGeneratingFallback = $this->generatingFallback; + $this->generatingFallback = true; + + try { + $data = 'root' === $fallback ? $this->generateDataForRoot($reader, $tempDir) : $this->generateDataForLocale($reader, $tempDir, $fallback); + } finally { + $this->generatingFallback = $prevGeneratingFallback; + } + + return $this->fallbackCache[$fallback] = $data ?: []; + } +} diff --git a/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php index d4f6ab4acc..7fb0096e04 100644 --- a/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php @@ -16,7 +16,6 @@ use Symfony\Component\Intl\Data\Bundle\Compiler\BundleCompilerInterface; use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface; use Symfony\Component\Intl\Data\Util\LocaleScanner; use Symfony\Component\Intl\Exception\MissingResourceException; -use Symfony\Component\Intl\Locale; /** * The rule for compiling the locale bundle. @@ -28,10 +27,10 @@ use Symfony\Component\Intl\Locale; */ class LocaleDataGenerator extends AbstractDataGenerator { - private $locales; - private $localeAliases; - private $fallbackMapping; - private $fallbackCache = []; + use FallbackTrait; + + private $locales = []; + private $localeAliases = []; /** * {@inheritdoc} @@ -40,7 +39,6 @@ class LocaleDataGenerator extends AbstractDataGenerator { $this->locales = $scanner->scanLocales($sourceDir.'/locales'); $this->localeAliases = $scanner->scanAliases($sourceDir.'/locales'); - $this->fallbackMapping = $this->generateFallbackMapping(array_diff($this->locales, array_keys($this->localeAliases)), $this->localeAliases); return $this->locales; } @@ -64,7 +62,6 @@ class LocaleDataGenerator extends AbstractDataGenerator */ protected function preGenerate() { - $this->fallbackCache = []; } /** @@ -73,7 +70,8 @@ class LocaleDataGenerator extends AbstractDataGenerator protected function generateDataForLocale(BundleEntryReaderInterface $reader, $tempDir, $displayLocale) { // Don't generate aliases, as they are resolved during runtime - if (isset($this->localeAliases[$displayLocale])) { + // Unless an alias is needed as fallback for de-duplication purposes + if (isset($this->localeAliases[$displayLocale]) && !$this->generatingFallback) { return; } @@ -85,7 +83,7 @@ class LocaleDataGenerator extends AbstractDataGenerator $localeNames = []; foreach ($this->locales as $locale) { // Ensure a normalized list of pure locales - if (isset($this->localeAliases[$displayLocale]) || \Locale::getAllVariants($locale)) { + if (\Locale::getAllVariants($locale)) { continue; } @@ -102,21 +100,27 @@ class LocaleDataGenerator extends AbstractDataGenerator } } - // Process again to de-duplicate locales and their fallback locales - // Only keep the differences - $fallback = $displayLocale; - while (isset($this->fallbackMapping[$fallback])) { - if (!isset($this->fallbackCache[$fallback = $this->fallbackMapping[$fallback]])) { - $this->fallbackCache[$fallback] = $this->generateDataForLocale($reader, $tempDir, $fallback) ?: []; - } - if (isset($this->fallbackCache[$fallback]['Names'])) { - $localeNames = array_diff($localeNames, $this->fallbackCache[$fallback]['Names']); - } + $data = [ + 'Names' => $localeNames, + ]; + + // Don't de-duplicate a fallback locale + // Ensures the display locale can be de-duplicated on itself + if ($this->generatingFallback) { + return $data; } - if ($localeNames) { - return ['Names' => $localeNames]; + // Process again to de-duplicate locale and its fallback locales + // Only keep the differences + $fallbackData = $this->generateFallbackData($reader, $tempDir, $displayLocale); + if (isset($fallbackData['Names'])) { + $data['Names'] = array_diff($data['Names'], $fallbackData['Names']); } + if (!$data['Names']) { + return; + } + + return $data; } /** @@ -131,12 +135,10 @@ class LocaleDataGenerator extends AbstractDataGenerator */ protected function generateDataForMeta(BundleEntryReaderInterface $reader, $tempDir) { - if ($this->locales || $this->localeAliases) { - return [ - 'Locales' => $this->locales, - 'Aliases' => $this->localeAliases, - ]; - } + return [ + 'Locales' => $this->locales, + 'Aliases' => $this->localeAliases, + ]; } /** @@ -175,30 +177,4 @@ class LocaleDataGenerator extends AbstractDataGenerator return $name; } - - private function generateFallbackMapping(array $displayLocales, array $aliases) - { - $displayLocales = array_flip($displayLocales); - $mapping = []; - - foreach ($displayLocales as $displayLocale => $_) { - $mapping[$displayLocale] = null; - $fallback = $displayLocale; - - // Recursively search for a fallback locale until one is found - while (null !== ($fallback = Locale::getFallback($fallback))) { - // Currently, no locale has an alias as fallback locale. - // If this starts to be the case, we need to add code here. - \assert(!isset($aliases[$fallback])); - - // Check whether the fallback exists - if (isset($displayLocales[$fallback])) { - $mapping[$displayLocale] = $fallback; - break; - } - } - } - - return $mapping; - } }