[Intl] Fix root fallback locale

This commit is contained in:
Roland Franssen 2019-05-07 19:46:35 +02:00
parent 6c6f76f217
commit 11ff24a665
46 changed files with 68 additions and 199 deletions

View File

@ -14,9 +14,6 @@ namespace Symfony\Component\Intl\Data\Generator;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Intl\Data\Bundle\Compiler\BundleCompilerInterface;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface;
use Symfony\Component\Intl\Data\Provider\LanguageDataProvider;
use Symfony\Component\Intl\Data\Provider\RegionDataProvider;
use Symfony\Component\Intl\Data\Provider\ScriptDataProvider;
use Symfony\Component\Intl\Data\Util\LocaleScanner;
use Symfony\Component\Intl\Exception\MissingResourceException;
use Symfony\Component\Intl\Locale;
@ -31,23 +28,11 @@ use Symfony\Component\Intl\Locale;
*/
class LocaleDataGenerator extends AbstractDataGenerator
{
private $languageDataProvider;
private $scriptDataProvider;
private $regionDataProvider;
private $locales;
private $localeAliases;
private $fallbackMapping;
private $fallbackCache = [];
public function __construct(BundleCompilerInterface $compiler, $dirName, LanguageDataProvider $languageDataProvider, ScriptDataProvider $scriptDataProvider, RegionDataProvider $regionDataProvider)
{
parent::__construct($compiler, $dirName);
$this->languageDataProvider = $languageDataProvider;
$this->scriptDataProvider = $scriptDataProvider;
$this->regionDataProvider = $regionDataProvider;
}
/**
* {@inheritdoc}
*/
@ -66,8 +51,12 @@ class LocaleDataGenerator extends AbstractDataGenerator
protected function compileTemporaryBundles(BundleCompilerInterface $compiler, $sourceDir, $tempDir)
{
$filesystem = new Filesystem();
$filesystem->mkdir($tempDir.'/lang');
$filesystem->mkdir([
$tempDir.'/lang',
$tempDir.'/region',
]);
$compiler->compile($sourceDir.'/lang', $tempDir.'/lang');
$compiler->compile($sourceDir.'/region', $tempDir.'/region');
}
/**
@ -83,19 +72,14 @@ class LocaleDataGenerator extends AbstractDataGenerator
*/
protected function generateDataForLocale(BundleEntryReaderInterface $reader, $tempDir, $displayLocale)
{
// Generate aliases, needed to enable proper fallback from alias to its
// target
// Don't generate aliases, as they are resolved during runtime
if (isset($this->localeAliases[$displayLocale])) {
return ['%%ALIAS' => $this->localeAliases[$displayLocale]];
return;
}
// Generate locale names for all locales that have translations in
// at least the language or the region bundle
try {
$displayFormat = $reader->readEntry($tempDir.'/lang', $displayLocale, ['localeDisplayPattern']);
} catch (MissingResourceException $e) {
$displayFormat = $reader->readEntry($tempDir.'/lang', 'root', ['localeDisplayPattern']);
}
$displayFormat = $reader->readEntry($tempDir.'/lang', $displayLocale, ['localeDisplayPattern']);
$pattern = $displayFormat['pattern'] ?? '{0} ({1})';
$separator = $displayFormat['separator'] ?? '{0}, {1}';
$localeNames = [];
@ -110,7 +94,7 @@ class LocaleDataGenerator extends AbstractDataGenerator
// Each locale name has the form: "Language (Script, Region, Variant1, ...)
// Script, Region and Variants are optional. If none of them is
// available, the braces are not printed.
$localeNames[$locale] = $this->generateLocaleName($locale, $displayLocale, $pattern, $separator);
$localeNames[$locale] = $this->generateLocaleName($reader, $tempDir, $locale, $displayLocale, $pattern, $separator);
} catch (MissingResourceException $e) {
// Silently ignore incomplete locale names
// In this case one should configure at least one fallback locale that is complete (e.g. English) during
@ -158,22 +142,26 @@ class LocaleDataGenerator extends AbstractDataGenerator
/**
* @return string
*/
private function generateLocaleName($locale, $displayLocale, $pattern, $separator)
private function generateLocaleName(BundleEntryReaderInterface $reader, $tempDir, $locale, $displayLocale, $pattern, $separator)
{
// Apply generic notation using square brackets as described per http://cldr.unicode.org/translation/language-names
$name = str_replace(['(', ')'], ['[', ']'], $this->languageDataProvider->getName(\Locale::getPrimaryLanguage($locale), $displayLocale));
$name = str_replace(['(', ')'], ['[', ']'], $reader->readEntry($tempDir.'/lang', $displayLocale, ['Languages', \Locale::getPrimaryLanguage($locale)]));
$extras = [];
// Discover the name of the script part of the locale
// i.e. in zh_Hans_MO, "Hans" is the script
if ($script = \Locale::getScript($locale)) {
$extras[] = str_replace(['(', ')'], ['[', ']'], $this->scriptDataProvider->getName($script, $displayLocale));
$extras[] = str_replace(['(', ')'], ['[', ']'], $reader->readEntry($tempDir.'/lang', $displayLocale, ['Scripts', $script]));
}
// Discover the name of the region part of the locale
// i.e. in de_AT, "AT" is the region
if ($region = \Locale::getRegion($locale)) {
$extras[] = str_replace(['(', ')'], ['[', ']'], $this->regionDataProvider->getName($region, $displayLocale));
if (!RegionDataGenerator::isValidCountryCode($region)) {
throw new MissingResourceException('Skipping "'.$locale.'" due an invalid country.');
}
$extras[] = str_replace(['(', ')'], ['[', ']'], $reader->readEntry($tempDir.'/region', $displayLocale, ['Countries', $region]));
}
if ($extras) {

View File

@ -48,6 +48,20 @@ class RegionDataGenerator extends AbstractDataGenerator
*/
private $regionCodes = [];
public static function isValidCountryCode($region)
{
if (isset(self::$blacklist[$region])) {
return false;
}
// WORLD/CONTINENT/SUBCONTINENT/GROUPING
if (ctype_digit($region) || \is_int($region)) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
@ -125,12 +139,7 @@ class RegionDataGenerator extends AbstractDataGenerator
$regionNames = [];
foreach ($unfilteredRegionNames as $region => $regionName) {
if (isset(self::$blacklist[$region])) {
continue;
}
// WORLD/CONTINENT/SUBCONTINENT/GROUPING
if (ctype_digit($region) || \is_int($region)) {
if (!self::isValidCountryCode($region)) {
continue;
}

View File

@ -31,7 +31,7 @@ final class Locale extends \Locale
* The default fallback locale is used as fallback for locales that have no
* fallback otherwise.
*
* @param string $locale The default fallback locale
* @param string|null $locale The default fallback locale
*
* @see getFallback()
*/
@ -43,7 +43,7 @@ final class Locale extends \Locale
/**
* Returns the default fallback locale.
*
* @return string The default fallback locale
* @return string|null The default fallback locale
*
* @see setDefaultFallback()
* @see getFallback()
@ -70,7 +70,7 @@ final class Locale extends \Locale
if (\function_exists('locale_parse')) {
$localeSubTags = locale_parse($locale);
if (1 === \count($localeSubTags)) {
if (self::$defaultFallback === $localeSubTags['language']) {
if ('root' !== self::$defaultFallback && self::$defaultFallback === $localeSubTags['language']) {
return 'root';
}
@ -98,7 +98,7 @@ final class Locale extends \Locale
return substr($locale, 0, $pos);
}
if (self::$defaultFallback === $locale) {
if ('root' !== self::$defaultFallback && self::$defaultFallback === $locale) {
return 'root';
}

View File

@ -11,8 +11,6 @@
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Intl\Data\Bundle\Compiler\GenrbCompiler;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReader;
use Symfony\Component\Intl\Data\Bundle\Reader\JsonBundleReader;
use Symfony\Component\Intl\Data\Bundle\Writer\JsonBundleWriter;
use Symfony\Component\Intl\Data\Generator\CurrencyDataGenerator;
use Symfony\Component\Intl\Data\Generator\GeneratorConfig;
@ -20,9 +18,6 @@ use Symfony\Component\Intl\Data\Generator\LanguageDataGenerator;
use Symfony\Component\Intl\Data\Generator\LocaleDataGenerator;
use Symfony\Component\Intl\Data\Generator\RegionDataGenerator;
use Symfony\Component\Intl\Data\Generator\ScriptDataGenerator;
use Symfony\Component\Intl\Data\Provider\LanguageDataProvider;
use Symfony\Component\Intl\Data\Provider\RegionDataProvider;
use Symfony\Component\Intl\Data\Provider\ScriptDataProvider;
use Symfony\Component\Intl\Intl;
use Symfony\Component\Intl\Locale;
use Symfony\Component\Intl\Util\GitRepository;
@ -171,27 +166,13 @@ echo "Preparing resource bundle compilation (version $icuVersionInDownload)...\n
$compiler = new GenrbCompiler($genrb, $genrbEnv);
$config = new GeneratorConfig($sourceDir.'/data', $icuVersionInDownload);
$jsonDir = dirname(__DIR__).'/data';
$targetDirs = [$jsonDir];
$workingDirs = [$jsonDir];
$config->addBundleWriter($jsonDir, new JsonBundleWriter());
echo "Starting resource bundle compilation. This may take a while...\n";
$filesystem->remove($workingDirs);
foreach ($workingDirs as $targetDir) {
$filesystem->mkdir([
$targetDir.'/'.Intl::CURRENCY_DIR,
$targetDir.'/'.Intl::LANGUAGE_DIR,
$targetDir.'/'.Intl::LOCALE_DIR,
$targetDir.'/'.Intl::REGION_DIR,
$targetDir.'/'.Intl::SCRIPT_DIR,
]);
}
// We don't want to use fallback to English during generation
Locale::setDefaultFallback(null);
Locale::setDefaultFallback('root');
echo "Generating language data...\n";
@ -215,14 +196,7 @@ $generator->generateData($config);
echo "Generating locale data...\n";
$reader = new BundleEntryReader(new JsonBundleReader());
$generator = new LocaleDataGenerator(
$compiler,
Intl::LOCALE_DIR,
new LanguageDataProvider($jsonDir.'/'.Intl::LANGUAGE_DIR, $reader),
new ScriptDataProvider($jsonDir.'/'.Intl::SCRIPT_DIR, $reader),
new RegionDataProvider($jsonDir.'/'.Intl::REGION_DIR, $reader)
);
$generator = new LocaleDataGenerator($compiler, Intl::LOCALE_DIR);
$generator->generateData($config);
echo "Resource bundle compilation complete.\n";
@ -238,18 +212,15 @@ Date: {$git->getLastAuthoredDate()->format('c')}
GIT_INFO;
foreach ($targetDirs as $targetDir) {
$gitInfoFile = $targetDir.'/git-info.txt';
$gitInfoFile = $jsonDir.'/git-info.txt';
file_put_contents($gitInfoFile, $gitInfo);
file_put_contents($gitInfoFile, $gitInfo);
echo "Wrote $gitInfoFile.\n";
echo "Wrote $gitInfoFile.\n";
$versionFile = $targetDir.'/version.txt';
$versionFile = $jsonDir.'/version.txt';
file_put_contents($versionFile, "$icuVersionInDownload\n");
echo "Wrote $versionFile.\n";
}
file_put_contents($versionFile, "$icuVersionInDownload\n");
echo "Wrote $versionFile.\n";
echo "Done.\n";

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "az_Latn_AZ"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "bs_Latn_BA"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "en_VU"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "en_ZW"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "ff_Latn_CM"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "ff_Latn_GN"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "ff_Latn_MR"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "ff_Latn_SN"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "id"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "id_ID"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "he"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "he_IL"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "ro"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "nb"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "nb_NO"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "nn_NO"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "pa_Guru_IN"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "pa_Arab_PK"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "sr_Latn"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "sr_Latn_BA"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "sr_Latn_RS"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "sr_Latn_RS"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "sr_Cyrl_BA"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "sr_Cyrl_RS"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "sr_Cyrl_RS"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "sr_Cyrl_RS"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "sr_Latn_RS"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "sr_Latn_RS"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "sr_Latn_ME"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "sr_Cyrl_RS"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "sr_Cyrl_XK"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "sr_Cyrl_RS"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "fil"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "fil_PH"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "uz_Arab_AF"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "uz_Latn_UZ"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "zh_Hans_CN"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "zh_Hant_HK"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "zh_Hant_MO"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "zh_Hans_SG"
}

View File

@ -1,3 +0,0 @@
{
"%%ALIAS": "zh_Hant_TW"
}

View File

@ -46,4 +46,28 @@ class LocaleTest extends TestCase
{
$this->assertSame($expected, Locale::getFallback($locale));
}
public function testNoDefaultFallback()
{
$prev = Locale::getDefaultFallback();
Locale::setDefaultFallback(null);
$this->assertSame('nl', Locale::getFallback('nl_NL'));
$this->assertNull(Locale::getFallback('nl'));
$this->assertNull(Locale::getFallback('root'));
Locale::setDefaultFallback($prev);
}
public function testDefaultRootFallback()
{
$prev = Locale::getDefaultFallback();
Locale::setDefaultFallback('root');
$this->assertSame('nl', Locale::getFallback('nl_NL'));
$this->assertSame('root', Locale::getFallback('nl'));
$this->assertNull(Locale::getFallback('root'));
Locale::setDefaultFallback($prev);
}
}