diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 7442600260a8c..d0bd5cefe5ea4 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -94,6 +94,15 @@ HttpKernel * Renamed `PostResponseEvent` to `TerminateEvent` * Deprecated `TranslatorListener` in favor of `LocaleAwareListener` +Intl +---- + + * Deprecated `ResourceBundle` namespace + * Deprecated `Intl::getCurrencyBundle()`, use `Currencies` instead + * Deprecated `Intl::getLanguageBundle()`, use `Languages` or `Scripts` instead + * Deprecated `Intl::getLocaleBundle()`, use `Locales` instead + * Deprecated `Intl::getRegionBundle()`, use `Regions` instead + Messenger --------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index b163e76678286..e8c479c6bc332 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -237,6 +237,15 @@ HttpKernel * Removed `PostResponseEvent`, use `TerminateEvent` instead * Removed `TranslatorListener` in favor of `LocaleAwareListener` +Intl +---- + + * Removed `ResourceBundle` namespace + * Removed `Intl::getLanguageBundle()`, use `Languages` or `Scripts` instead + * Removed `Intl::getCurrencyBundle()`, use `Currencies` instead + * Removed `Intl::getLocaleBundle()`, use `Locales` instead + * Removed `Intl::getRegionBundle()`, use `Regions` instead + Messenger --------- diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php index 2373dee5ff908..ff50c2fb00fef 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php @@ -15,7 +15,7 @@ use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Regions; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -44,7 +44,7 @@ public function configureOptions(OptionsResolver $resolver) $choiceTranslationLocale = $options['choice_translation_locale']; return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { - return array_flip(Intl::getRegionBundle()->getCountryNames($choiceTranslationLocale)); + return array_flip(Regions::getNames($choiceTranslationLocale)); }); }, 'choice_translation_domain' => false, @@ -83,7 +83,7 @@ public function loadChoiceList($value = null) return $this->choiceList; } - return $this->choiceList = new ArrayChoiceList(array_flip(Intl::getRegionBundle()->getCountryNames()), $value); + return $this->choiceList = new ArrayChoiceList(array_flip(Regions::getNames()), $value); } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php index 134d568e4d174..486bdc7b20206 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php @@ -15,7 +15,7 @@ use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Currencies; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -44,7 +44,7 @@ public function configureOptions(OptionsResolver $resolver) $choiceTranslationLocale = $options['choice_translation_locale']; return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { - return array_flip(Intl::getCurrencyBundle()->getCurrencyNames($choiceTranslationLocale)); + return array_flip(Currencies::getNames($choiceTranslationLocale)); }); }, 'choice_translation_domain' => false, @@ -83,7 +83,7 @@ public function loadChoiceList($value = null) return $this->choiceList; } - return $this->choiceList = new ArrayChoiceList(array_flip(Intl::getCurrencyBundle()->getCurrencyNames()), $value); + return $this->choiceList = new ArrayChoiceList(array_flip(Currencies::getNames()), $value); } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php b/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php index 88761598ab84b..4a0cbe1f8f459 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php @@ -15,7 +15,7 @@ use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Languages; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -44,7 +44,7 @@ public function configureOptions(OptionsResolver $resolver) $choiceTranslationLocale = $options['choice_translation_locale']; return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { - return array_flip(Intl::getLanguageBundle()->getLanguageNames($choiceTranslationLocale)); + return array_flip(Languages::getNames($choiceTranslationLocale)); }); }, 'choice_translation_domain' => false, @@ -83,7 +83,7 @@ public function loadChoiceList($value = null) return $this->choiceList; } - return $this->choiceList = new ArrayChoiceList(array_flip(Intl::getLanguageBundle()->getLanguageNames()), $value); + return $this->choiceList = new ArrayChoiceList(array_flip(Languages::getNames()), $value); } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php index 853f98a928c25..41e016df1008b 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php @@ -15,7 +15,7 @@ use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Locales; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -44,7 +44,7 @@ public function configureOptions(OptionsResolver $resolver) $choiceTranslationLocale = $options['choice_translation_locale']; return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { - return array_flip(Intl::getLocaleBundle()->getLocaleNames($choiceTranslationLocale)); + return array_flip(Locales::getNames($choiceTranslationLocale)); }); }, 'choice_translation_domain' => false, @@ -83,7 +83,7 @@ public function loadChoiceList($value = null) return $this->choiceList; } - return $this->choiceList = new ArrayChoiceList(array_flip(Intl::getLocaleBundle()->getLocaleNames()), $value); + return $this->choiceList = new ArrayChoiceList(array_flip(Locales::getNames()), $value); } /** diff --git a/src/Symfony/Component/Form/composer.json b/src/Symfony/Component/Form/composer.json index 6de2563a7bb09..d448e77e5a7fe 100644 --- a/src/Symfony/Component/Form/composer.json +++ b/src/Symfony/Component/Form/composer.json @@ -18,7 +18,7 @@ "require": { "php": "^7.1.3", "symfony/event-dispatcher": "^4.3", - "symfony/intl": "~3.4|~4.0", + "symfony/intl": "^4.3", "symfony/options-resolver": "~4.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0", @@ -43,6 +43,7 @@ "symfony/doctrine-bridge": "<3.4", "symfony/framework-bundle": "<3.4", "symfony/http-kernel": "<4.3", + "symfony/intl": "<4.3", "symfony/translation": "<4.2", "symfony/twig-bridge": "<3.4.5|<4.0.5,>=4.0" }, diff --git a/src/Symfony/Component/Intl/CHANGELOG.md b/src/Symfony/Component/Intl/CHANGELOG.md index 4a61ee7178fab..7c8d46745533d 100644 --- a/src/Symfony/Component/Intl/CHANGELOG.md +++ b/src/Symfony/Component/Intl/CHANGELOG.md @@ -1,6 +1,15 @@ CHANGELOG ========= +4.3.0 +----- + + * deprecated `ResourceBundle` namespace + * added `Currencies` in favor of `Intl::getCurrencyBundle()` + * added `Languages` and `Scripts` in favor of `Intl::getLanguageBundle()` + * added `Locales` in favor of `Intl::getLocaleBundle()` + * added `Regions` in favor of `Intl::getRegionBundle()` + 4.2.0 ----- diff --git a/src/Symfony/Component/Intl/Currencies.php b/src/Symfony/Component/Intl/Currencies.php new file mode 100644 index 0000000000000..5d6a4b06cce63 --- /dev/null +++ b/src/Symfony/Component/Intl/Currencies.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Intl; + +use Symfony\Component\Intl\Exception\MissingResourceException; + +/** + * Gives access to currency-related ICU data. + * + * @author Bernhard Schussek + * @author Roland Franssen + */ +final class Currencies extends ResourceBundle +{ + private const INDEX_SYMBOL = 0; + private const INDEX_NAME = 1; + private const INDEX_FRACTION_DIGITS = 0; + private const INDEX_ROUNDING_INCREMENT = 1; + + /** + * @return string[] + */ + public static function getCurrencyCodes(): array + { + return self::readEntry(['Currencies'], 'meta'); + } + + public static function exists(string $currency): bool + { + try { + self::readEntry(['Names', $currency, self::INDEX_NAME]); + + return true; + } catch (MissingResourceException $e) { + return false; + } + } + + public static function getName(string $currency, string $displayLocale = null): string + { + return self::readEntry(['Names', $currency, self::INDEX_NAME], $displayLocale); + } + + /** + * @return string[] + */ + public static function getNames(string $displayLocale = null): array + { + // ==================================================================== + // For reference: It is NOT possible to return names indexed by + // numeric code here, because some numeric codes map to multiple + // 3-letter codes (e.g. 32 => "ARA", "ARP", "ARS") + // ==================================================================== + + $names = self::readEntry(['Names'], $displayLocale); + + if ($names instanceof \Traversable) { + $names = iterator_to_array($names); + } + + array_walk($names, function (&$value) { + $value = $value[self::INDEX_NAME]; + }); + + return self::asort($names, $displayLocale); + } + + public static function getSymbol(string $currency, string $displayLocale = null): string + { + return self::readEntry(['Names', $currency, self::INDEX_SYMBOL], $displayLocale); + } + + public static function getFractionDigits(string $currency): int + { + try { + return self::readEntry(['Meta', $currency, self::INDEX_FRACTION_DIGITS], 'meta'); + } catch (MissingResourceException $e) { + return self::readEntry(['Meta', 'DEFAULT', self::INDEX_FRACTION_DIGITS], 'meta'); + } + } + + /** + * @return float|int + */ + public static function getRoundingIncrement(string $currency) + { + try { + return self::readEntry(['Meta', $currency, self::INDEX_ROUNDING_INCREMENT], 'meta'); + } catch (MissingResourceException $e) { + return self::readEntry(['Meta', 'DEFAULT', self::INDEX_ROUNDING_INCREMENT], 'meta'); + } + } + + public static function getNumericCode(string $currency): int + { + return self::readEntry(['Alpha3ToNumeric', $currency], 'meta'); + } + + public static function forNumericCode(int $numericCode): array + { + return self::readEntry(['NumericToAlpha3', (string) $numericCode], 'meta'); + } + + protected static function getPath(): string + { + return Intl::getDataDirectory().'/'.Intl::CURRENCY_DIR; + } +} diff --git a/src/Symfony/Component/Intl/Data/Provider/CurrencyDataProvider.php b/src/Symfony/Component/Intl/Data/Provider/CurrencyDataProvider.php index 61814dfda3058..d4ee9af69b206 100644 --- a/src/Symfony/Component/Intl/Data/Provider/CurrencyDataProvider.php +++ b/src/Symfony/Component/Intl/Data/Provider/CurrencyDataProvider.php @@ -20,7 +20,7 @@ * * @author Bernhard Schussek * - * @internal + * @internal to be removed in 5.0. */ class CurrencyDataProvider { diff --git a/src/Symfony/Component/Intl/Data/Provider/LanguageDataProvider.php b/src/Symfony/Component/Intl/Data/Provider/LanguageDataProvider.php index 60a364b6447b0..b507f25b8f0d0 100644 --- a/src/Symfony/Component/Intl/Data/Provider/LanguageDataProvider.php +++ b/src/Symfony/Component/Intl/Data/Provider/LanguageDataProvider.php @@ -19,7 +19,7 @@ * * @author Bernhard Schussek * - * @internal + * @internal to be removed in 5.0. */ class LanguageDataProvider { diff --git a/src/Symfony/Component/Intl/Data/Provider/LocaleDataProvider.php b/src/Symfony/Component/Intl/Data/Provider/LocaleDataProvider.php index f42be225bcc5b..216ede8810f00 100644 --- a/src/Symfony/Component/Intl/Data/Provider/LocaleDataProvider.php +++ b/src/Symfony/Component/Intl/Data/Provider/LocaleDataProvider.php @@ -19,7 +19,7 @@ * * @author Bernhard Schussek * - * @internal + * @internal to be removed in 5.0. */ class LocaleDataProvider { diff --git a/src/Symfony/Component/Intl/Data/Provider/RegionDataProvider.php b/src/Symfony/Component/Intl/Data/Provider/RegionDataProvider.php index f45cae16a1f18..bf6a634aa200a 100644 --- a/src/Symfony/Component/Intl/Data/Provider/RegionDataProvider.php +++ b/src/Symfony/Component/Intl/Data/Provider/RegionDataProvider.php @@ -19,7 +19,7 @@ * * @author Bernhard Schussek * - * @internal + * @internal to be removed in 5.0. */ class RegionDataProvider { diff --git a/src/Symfony/Component/Intl/Data/Provider/ScriptDataProvider.php b/src/Symfony/Component/Intl/Data/Provider/ScriptDataProvider.php index 43651cae591d0..9f1ed1711f186 100644 --- a/src/Symfony/Component/Intl/Data/Provider/ScriptDataProvider.php +++ b/src/Symfony/Component/Intl/Data/Provider/ScriptDataProvider.php @@ -19,7 +19,7 @@ * * @author Bernhard Schussek * - * @internal + * @internal to be removed in 5.0. */ class ScriptDataProvider { diff --git a/src/Symfony/Component/Intl/Intl.php b/src/Symfony/Component/Intl/Intl.php index 70fc55697a841..7d121971e880d 100644 --- a/src/Symfony/Component/Intl/Intl.php +++ b/src/Symfony/Component/Intl/Intl.php @@ -113,14 +113,18 @@ public static function isExtensionLoaded() * Returns the bundle containing currency information. * * @return CurrencyBundleInterface The currency resource bundle + * + * @deprecated since Symfony 4.3, to be removed in 5.0. Use {@see Currencies} instead. */ public static function getCurrencyBundle() { + @trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.3, use "%s" instead.', __METHOD__, Currencies::class), E_USER_DEPRECATED); + if (null === self::$currencyBundle) { self::$currencyBundle = new CurrencyBundle( self::getDataDirectory().'/'.self::CURRENCY_DIR, self::getEntryReader(), - self::getLocaleBundle() + self::$localeBundle ?? self::$localeBundle = new LocaleBundle(self::getDataDirectory().'/'.self::LOCALE_DIR, self::getEntryReader()) ); } @@ -131,14 +135,18 @@ public static function getCurrencyBundle() * Returns the bundle containing language information. * * @return LanguageBundleInterface The language resource bundle + * + * @deprecated since Symfony 4.3, to be removed in 5.0. Use {@see Languages} or {@see Scripts} instead. */ public static function getLanguageBundle() { + @trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.3, use "%s" or "%s" instead.', __METHOD__, Languages::class, Scripts::class), E_USER_DEPRECATED); + if (null === self::$languageBundle) { self::$languageBundle = new LanguageBundle( self::getDataDirectory().'/'.self::LANGUAGE_DIR, self::getEntryReader(), - self::getLocaleBundle(), + self::$localeBundle ?? self::$localeBundle = new LocaleBundle(self::getDataDirectory().'/'.self::LOCALE_DIR, self::getEntryReader()), new ScriptDataProvider( self::getDataDirectory().'/'.self::SCRIPT_DIR, self::getEntryReader() @@ -153,9 +161,13 @@ public static function getLanguageBundle() * Returns the bundle containing locale information. * * @return LocaleBundleInterface The locale resource bundle + * + * @deprecated since Symfony 4.3, to be removed in 5.0. Use {@see Locales} instead. */ public static function getLocaleBundle() { + @trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.3, use "%s" instead.', __METHOD__, Locales::class), E_USER_DEPRECATED); + if (null === self::$localeBundle) { self::$localeBundle = new LocaleBundle( self::getDataDirectory().'/'.self::LOCALE_DIR, @@ -170,14 +182,18 @@ public static function getLocaleBundle() * Returns the bundle containing region information. * * @return RegionBundleInterface The region resource bundle + * + * @deprecated since Symfony 4.3, to be removed in 5.0. Use {@see Regions} instead. */ public static function getRegionBundle() { + @trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.3, use "%s" instead.', __METHOD__, Regions::class), E_USER_DEPRECATED); + if (null === self::$regionBundle) { self::$regionBundle = new RegionBundle( self::getDataDirectory().'/'.self::REGION_DIR, self::getEntryReader(), - self::getLocaleBundle() + self::$localeBundle ?? self::$localeBundle = new LocaleBundle(self::getDataDirectory().'/'.self::LOCALE_DIR, self::getEntryReader()) ); } diff --git a/src/Symfony/Component/Intl/Languages.php b/src/Symfony/Component/Intl/Languages.php new file mode 100644 index 0000000000000..64d85a6ade3ec --- /dev/null +++ b/src/Symfony/Component/Intl/Languages.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Intl; + +use Symfony\Component\Intl\Exception\MissingResourceException; + +/** + * Gives access to language-related ICU data. + * + * @author Bernhard Schussek + * @author Roland Franssen + */ +final class Languages extends ResourceBundle +{ + /** + * Returns all available languages. + * + * Languages are returned as lowercase ISO 639-1 two-letter language codes. + * For languages that don't have a two-letter code, the ISO 639-2 + * three-letter code is used instead. + * + * A full table of ISO 639 language codes can be found here: + * http://www-01.sil.org/iso639-3/codes.asp + * + * @return string[] an array of canonical ISO 639 language codes + */ + public static function getLanguageCodes(): array + { + return self::readEntry(['Languages'], 'meta'); + } + + public static function exists(string $language): bool + { + try { + self::readEntry(['Names', $language]); + + return true; + } catch (MissingResourceException $e) { + return false; + } + } + + public static function getName(string $language, string $displayLocale = null): string + { + return self::readEntry(['Names', $language], $displayLocale); + } + + /** + * @return string[] + */ + public static function getNames(string $displayLocale = null): array + { + return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale); + } + + /** + * Returns the ISO 639-2 three-letter code of a language. + * + * @throws MissingResourceException if the language has no corresponding three-letter code + */ + public static function getAlpha3Code(string $language): string + { + return self::readEntry(['Alpha2ToAlpha3', $language], 'meta'); + } + + protected static function getPath(): string + { + return Intl::getDataDirectory().'/'.Intl::LANGUAGE_DIR; + } +} diff --git a/src/Symfony/Component/Intl/Locales.php b/src/Symfony/Component/Intl/Locales.php new file mode 100644 index 0000000000000..980c8f8b6b679 --- /dev/null +++ b/src/Symfony/Component/Intl/Locales.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Intl; + +use Symfony\Component\Intl\Exception\MissingResourceException; + +/** + * Gives access to locale-related ICU data. + * + * @author Bernhard Schussek + * @author Roland Franssen + */ +final class Locales extends ResourceBundle +{ + /** + * @return string[] + */ + public static function getLocales(): array + { + return self::readEntry(['Locales'], 'meta'); + } + + /** + * @return string[] + */ + public static function getAliases(): array + { + return self::readEntry(['Aliases'], 'meta'); + } + + public static function exists(string $locale): bool + { + try { + self::readEntry(['Names', $locale]); + + return true; + } catch (MissingResourceException $e) { + return false; + } + } + + public static function getName(string $locale, string $displayLocale = null): string + { + return self::readEntry(['Names', $locale], $displayLocale); + } + + /** + * @return string[] + */ + public static function getNames($displayLocale = null) + { + return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale); + } + + protected static function getPath(): string + { + return Intl::getDataDirectory().'/'.Intl::LOCALE_DIR; + } +} diff --git a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php index c668d9a3c13ca..9f644ef8cd6ae 100644 --- a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php +++ b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Intl\NumberFormatter; +use Symfony\Component\Intl\Currencies; use Symfony\Component\Intl\Exception\MethodArgumentNotImplementedException; use Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException; use Symfony\Component\Intl\Exception\MethodNotImplementedException; use Symfony\Component\Intl\Exception\NotImplementedException; use Symfony\Component\Intl\Globals\IntlGlobals; -use Symfony\Component\Intl\Intl; use Symfony\Component\Intl\Locale\Locale; /** @@ -318,8 +318,8 @@ public function formatCurrency($value, $currency) return $this->format($value); } - $symbol = Intl::getCurrencyBundle()->getCurrencySymbol($currency, 'en'); - $fractionDigits = Intl::getCurrencyBundle()->getFractionDigits($currency); + $symbol = Currencies::getSymbol($currency, 'en'); + $fractionDigits = Currencies::getFractionDigits($currency); $value = $this->roundCurrency($value, $currency); @@ -682,8 +682,8 @@ protected function resetError() */ private function roundCurrency($value, $currency) { - $fractionDigits = Intl::getCurrencyBundle()->getFractionDigits($currency); - $roundingIncrement = Intl::getCurrencyBundle()->getRoundingIncrement($currency); + $fractionDigits = Currencies::getFractionDigits($currency); + $roundingIncrement = Currencies::getRoundingIncrement($currency); // Round with the formatter rounding mode $value = $this->round($value, $fractionDigits); diff --git a/src/Symfony/Component/Intl/Regions.php b/src/Symfony/Component/Intl/Regions.php new file mode 100644 index 0000000000000..b3606c0b30197 --- /dev/null +++ b/src/Symfony/Component/Intl/Regions.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Intl; + +use Symfony\Component\Intl\Exception\MissingResourceException; + +/** + * Gives access to region-related ICU data. + * + * @author Bernhard Schussek + * @author Roland Franssen + */ +final class Regions extends ResourceBundle +{ + /** + * @return string[] + */ + public static function getRegionCodes(): array + { + return self::readEntry(['Regions'], 'meta'); + } + + public static function exists(string $region): bool + { + try { + self::readEntry(['Names', $region]); + + return true; + } catch (MissingResourceException $e) { + return false; + } + } + + public static function getName(string $region, string $displayLocale = null): string + { + return self::readEntry(['Names', $region], $displayLocale); + } + + /** + * @return string[] + */ + public static function getNames($displayLocale = null) + { + return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale); + } + + protected static function getPath(): string + { + return Intl::getDataDirectory().'/'.Intl::REGION_DIR; + } +} diff --git a/src/Symfony/Component/Intl/ResourceBundle.php b/src/Symfony/Component/Intl/ResourceBundle.php new file mode 100644 index 0000000000000..46115838cdb7a --- /dev/null +++ b/src/Symfony/Component/Intl/ResourceBundle.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Intl; + +use Symfony\Component\Intl\Data\Bundle\Reader\BufferedBundleReader; +use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReader; +use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface; +use Symfony\Component\Intl\Data\Bundle\Reader\JsonBundleReader; + +/** + * @author Roland Franssen + * + * @internal + */ +abstract class ResourceBundle +{ + private static $entryReader; + + abstract protected static function getPath(): string; + + /** + * Reads an entry from a resource bundle. + * + * @see BundleEntryReaderInterface::readEntry() + * + * @param string[] $indices The indices to read from the bundle + * @param string $locale The locale to read + * @param bool $fallback Whether to merge the value with the value from + * the fallback locale (e.g. "en" for "en_GB"). + * Only applicable if the result is multivalued + * (i.e. array or \ArrayAccess) or cannot be found + * in the requested locale. + * + * @return mixed returns an array or {@link \ArrayAccess} instance for + * complex data and a scalar value for simple data + */ + final protected static function readEntry(array $indices, string $locale = null, bool $fallback = true) + { + if (null === self::$entryReader) { + self::$entryReader = new BundleEntryReader(new BufferedBundleReader( + new JsonBundleReader(), + Intl::BUFFER_SIZE + )); + + $localeAliases = self::$entryReader->readEntry(Intl::getDataDirectory().'/'.Intl::LOCALE_DIR, 'meta', ['Aliases']); + self::$entryReader->setLocaleAliases($localeAliases instanceof \Traversable ? iterator_to_array($localeAliases) : $localeAliases); + } + + return self::$entryReader->readEntry(static::getPath(), $locale ?? \Locale::getDefault(), $indices, $fallback); + } + + final protected static function asort(iterable $list, string $locale = null): array + { + if ($list instanceof \Traversable) { + $list = iterator_to_array($list); + } + + $collator = new \Collator($locale ?? \Locale::getDefault()); + $collator->asort($list); + + return $list; + } + + private function __construct() + { + } +} diff --git a/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundle.php b/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundle.php index 86e020570f7ac..b7ea33ea58574 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundle.php +++ b/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundle.php @@ -21,7 +21,7 @@ * * @author Bernhard Schussek * - * @internal + * @internal to be removed in 5.0. */ class CurrencyBundle extends CurrencyDataProvider implements CurrencyBundleInterface { diff --git a/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundleInterface.php b/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundleInterface.php index eb82f6849e6a4..421973b9fed31 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundleInterface.php +++ b/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundleInterface.php @@ -15,6 +15,8 @@ * Gives access to currency-related ICU data. * * @author Bernhard Schussek + * + * @deprecated since Symfony 4.3, to be removed in 5.0. */ interface CurrencyBundleInterface extends ResourceBundleInterface { diff --git a/src/Symfony/Component/Intl/ResourceBundle/LanguageBundle.php b/src/Symfony/Component/Intl/ResourceBundle/LanguageBundle.php index b2fbde3fe5430..eabd94821db2c 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/LanguageBundle.php +++ b/src/Symfony/Component/Intl/ResourceBundle/LanguageBundle.php @@ -22,7 +22,7 @@ * * @author Bernhard Schussek * - * @internal + * @internal to be removed in 5.0. */ class LanguageBundle extends LanguageDataProvider implements LanguageBundleInterface { diff --git a/src/Symfony/Component/Intl/ResourceBundle/LanguageBundleInterface.php b/src/Symfony/Component/Intl/ResourceBundle/LanguageBundleInterface.php index aa0c3e0f2c0b6..ab2c1805d145b 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/LanguageBundleInterface.php +++ b/src/Symfony/Component/Intl/ResourceBundle/LanguageBundleInterface.php @@ -15,6 +15,8 @@ * Gives access to language-related ICU data. * * @author Bernhard Schussek + * + * @deprecated since Symfony 4.3, to be removed in 5.0. */ interface LanguageBundleInterface extends ResourceBundleInterface { diff --git a/src/Symfony/Component/Intl/ResourceBundle/LocaleBundle.php b/src/Symfony/Component/Intl/ResourceBundle/LocaleBundle.php index 078b1de2ddd8e..19acc41782cf2 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/LocaleBundle.php +++ b/src/Symfony/Component/Intl/ResourceBundle/LocaleBundle.php @@ -19,7 +19,7 @@ * * @author Bernhard Schussek * - * @internal + * @internal to be removed in 5.0. */ class LocaleBundle extends LocaleDataProvider implements LocaleBundleInterface { diff --git a/src/Symfony/Component/Intl/ResourceBundle/LocaleBundleInterface.php b/src/Symfony/Component/Intl/ResourceBundle/LocaleBundleInterface.php index 6fa4e5c0abbf5..f7791adcbfec7 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/LocaleBundleInterface.php +++ b/src/Symfony/Component/Intl/ResourceBundle/LocaleBundleInterface.php @@ -15,6 +15,8 @@ * Gives access to locale-related ICU data. * * @author Bernhard Schussek + * + * @deprecated since Symfony 4.3, to be removed in 5.0. */ interface LocaleBundleInterface extends ResourceBundleInterface { diff --git a/src/Symfony/Component/Intl/ResourceBundle/RegionBundle.php b/src/Symfony/Component/Intl/ResourceBundle/RegionBundle.php index b5717a000f205..4cb34c2a09dda 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/RegionBundle.php +++ b/src/Symfony/Component/Intl/ResourceBundle/RegionBundle.php @@ -21,7 +21,7 @@ * * @author Bernhard Schussek * - * @internal + * @internal to be removed in 5.0. */ class RegionBundle extends RegionDataProvider implements RegionBundleInterface { diff --git a/src/Symfony/Component/Intl/ResourceBundle/RegionBundleInterface.php b/src/Symfony/Component/Intl/ResourceBundle/RegionBundleInterface.php index 12d0dd240824c..a417dbb3812da 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/RegionBundleInterface.php +++ b/src/Symfony/Component/Intl/ResourceBundle/RegionBundleInterface.php @@ -15,6 +15,8 @@ * Gives access to region-related ICU data. * * @author Bernhard Schussek + * + * @deprecated since Symfony 4.3, to be removed in 5.0. */ interface RegionBundleInterface extends ResourceBundleInterface { diff --git a/src/Symfony/Component/Intl/ResourceBundle/ResourceBundleInterface.php b/src/Symfony/Component/Intl/ResourceBundle/ResourceBundleInterface.php index 5c4c97483da94..37ef2648bddc9 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/ResourceBundleInterface.php +++ b/src/Symfony/Component/Intl/ResourceBundle/ResourceBundleInterface.php @@ -15,6 +15,8 @@ * Gives access to ICU data. * * @author Bernhard Schussek + * + * @deprecated since Symfony 4.3, to be removed in 5.0. */ interface ResourceBundleInterface { diff --git a/src/Symfony/Component/Intl/Scripts.php b/src/Symfony/Component/Intl/Scripts.php new file mode 100644 index 0000000000000..b01ff848efb97 --- /dev/null +++ b/src/Symfony/Component/Intl/Scripts.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Intl; + +use Symfony\Component\Intl\Exception\MissingResourceException; + +/** + * Gives access to script-related ICU data. + * + * @author Bernhard Schussek + * @author Roland Franssen + */ +final class Scripts extends ResourceBundle +{ + /** + * @return string[] + */ + public static function getScriptCodes(): array + { + return self::readEntry(['Scripts'], 'meta'); + } + + public static function exists(string $script): bool + { + try { + self::readEntry(['Names', $script]); + + return true; + } catch (MissingResourceException $e) { + return false; + } + } + + public static function getName(string $script, string $displayLocale = null): string + { + return self::readEntry(['Names', $script], $displayLocale); + } + + /** + * @return string[] + */ + public static function getNames($displayLocale = null) + { + return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale); + } + + protected static function getPath(): string + { + return Intl::getDataDirectory().'/'.Intl::SCRIPT_DIR; + } +} diff --git a/src/Symfony/Component/Intl/Tests/CurrenciesTest.php b/src/Symfony/Component/Intl/Tests/CurrenciesTest.php new file mode 100644 index 0000000000000..1f1a4e567b7a8 --- /dev/null +++ b/src/Symfony/Component/Intl/Tests/CurrenciesTest.php @@ -0,0 +1,789 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Intl\Tests; + +use Symfony\Component\Intl\Currencies; +use Symfony\Component\Intl\Locale; + +/** + * @group intl-data + */ +class CurrenciesTest extends ResourceBundleTestCase +{ + // The below arrays document the state of the ICU data bundled with this package. + + private static $currencies = [ + 'ADP', + 'AED', + 'AFA', + 'AFN', + 'ALK', + 'ALL', + 'AMD', + 'ANG', + 'AOA', + 'AOK', + 'AON', + 'AOR', + 'ARA', + 'ARL', + 'ARM', + 'ARP', + 'ARS', + 'ATS', + 'AUD', + 'AWG', + 'AZM', + 'AZN', + 'BAD', + 'BAM', + 'BAN', + 'BBD', + 'BDT', + 'BEC', + 'BEF', + 'BEL', + 'BGL', + 'BGM', + 'BGN', + 'BGO', + 'BHD', + 'BIF', + 'BMD', + 'BND', + 'BOB', + 'BOL', + 'BOP', + 'BOV', + 'BRB', + 'BRC', + 'BRE', + 'BRL', + 'BRN', + 'BRR', + 'BRZ', + 'BSD', + 'BTN', + 'BUK', + 'BWP', + 'BYB', + 'BYN', + 'BYR', + 'BZD', + 'CAD', + 'CDF', + 'CHE', + 'CHF', + 'CHW', + 'CLE', + 'CLF', + 'CLP', + 'CNH', + 'CNX', + 'CNY', + 'COP', + 'COU', + 'CRC', + 'CSD', + 'CSK', + 'CUC', + 'CUP', + 'CVE', + 'CYP', + 'CZK', + 'DDM', + 'DEM', + 'DJF', + 'DKK', + 'DOP', + 'DZD', + 'ECS', + 'ECV', + 'EEK', + 'EGP', + 'ERN', + 'ESA', + 'ESB', + 'ESP', + 'ETB', + 'EUR', + 'FIM', + 'FJD', + 'FKP', + 'FRF', + 'GBP', + 'GEK', + 'GEL', + 'GHC', + 'GHS', + 'GIP', + 'GMD', + 'GNF', + 'GNS', + 'GQE', + 'GRD', + 'GTQ', + 'GWE', + 'GWP', + 'GYD', + 'HKD', + 'HNL', + 'HRD', + 'HRK', + 'HTG', + 'HUF', + 'IDR', + 'IEP', + 'ILP', + 'ILR', + 'ILS', + 'INR', + 'IQD', + 'IRR', + 'ISJ', + 'ISK', + 'ITL', + 'JMD', + 'JOD', + 'JPY', + 'KES', + 'KGS', + 'KHR', + 'KMF', + 'KPW', + 'KRH', + 'KRO', + 'KRW', + 'KWD', + 'KYD', + 'KZT', + 'LAK', + 'LBP', + 'LKR', + 'LRD', + 'LSL', + 'LTL', + 'LTT', + 'LUC', + 'LUF', + 'LUL', + 'LVL', + 'LVR', + 'LYD', + 'MAD', + 'MAF', + 'MCF', + 'MDC', + 'MDL', + 'MGA', + 'MGF', + 'MKD', + 'MKN', + 'MLF', + 'MMK', + 'MNT', + 'MOP', + 'MRO', + 'MRU', + 'MTL', + 'MTP', + 'MUR', + 'MVP', + 'MVR', + 'MWK', + 'MXN', + 'MXP', + 'MXV', + 'MYR', + 'MZE', + 'MZM', + 'MZN', + 'NAD', + 'NGN', + 'NIC', + 'NIO', + 'NLG', + 'NOK', + 'NPR', + 'NZD', + 'OMR', + 'PAB', + 'PEI', + 'PEN', + 'PES', + 'PGK', + 'PHP', + 'PKR', + 'PLN', + 'PLZ', + 'PTE', + 'PYG', + 'QAR', + 'RHD', + 'ROL', + 'RON', + 'RSD', + 'RUB', + 'RUR', + 'RWF', + 'SAR', + 'SBD', + 'SCR', + 'SDD', + 'SDG', + 'SDP', + 'SEK', + 'SGD', + 'SHP', + 'SIT', + 'SKK', + 'SLL', + 'SOS', + 'SRD', + 'SRG', + 'SSP', + 'STD', + 'STN', + 'SUR', + 'SVC', + 'SYP', + 'SZL', + 'THB', + 'TJR', + 'TJS', + 'TMM', + 'TMT', + 'TND', + 'TOP', + 'TPE', + 'TRL', + 'TRY', + 'TTD', + 'TWD', + 'TZS', + 'UAH', + 'UAK', + 'UGS', + 'UGX', + 'USD', + 'USN', + 'USS', + 'UYI', + 'UYP', + 'UYU', + 'UYW', + 'UZS', + 'VEB', + 'VEF', + 'VES', + 'VND', + 'VNN', + 'VUV', + 'WST', + 'XAF', + 'XCD', + 'XEU', + 'XFO', + 'XFU', + 'XOF', + 'XPF', + 'XRE', + 'YDD', + 'YER', + 'YUD', + 'YUM', + 'YUN', + 'YUR', + 'ZAL', + 'ZAR', + 'ZMK', + 'ZMW', + 'ZRN', + 'ZRZ', + 'ZWD', + 'ZWL', + 'ZWR', + ]; + + private static $alpha3ToNumeric = [ + 'AFA' => 4, + 'ALK' => 8, + 'ALL' => 8, + 'DZD' => 12, + 'ADP' => 20, + 'AON' => 24, + 'AOK' => 24, + 'AZM' => 31, + 'ARA' => 32, + 'ARP' => 32, + 'ARS' => 32, + 'AUD' => 36, + 'ATS' => 40, + 'BSD' => 44, + 'BHD' => 48, + 'BDT' => 50, + 'AMD' => 51, + 'BBD' => 52, + 'BEF' => 56, + 'BMD' => 60, + 'BTN' => 64, + 'BOB' => 68, + 'BOP' => 68, + 'BAD' => 70, + 'BWP' => 72, + 'BRN' => 76, + 'BRE' => 76, + 'BRC' => 76, + 'BRB' => 76, + 'BZD' => 84, + 'SBD' => 90, + 'BND' => 96, + 'BGL' => 100, + 'MMK' => 104, + 'BUK' => 104, + 'BIF' => 108, + 'BYB' => 112, + 'KHR' => 116, + 'CAD' => 124, + 'CVE' => 132, + 'KYD' => 136, + 'LKR' => 144, + 'CLP' => 152, + 'CNY' => 156, + 'COP' => 170, + 'KMF' => 174, + 'ZRZ' => 180, + 'ZRN' => 180, + 'CRC' => 188, + 'HRK' => 191, + 'HRD' => 191, + 'CUP' => 192, + 'CYP' => 196, + 'CSK' => 200, + 'CZK' => 203, + 'DKK' => 208, + 'DOP' => 214, + 'ECS' => 218, + 'SVC' => 222, + 'GQE' => 226, + 'ETB' => 230, + 'ERN' => 232, + 'EEK' => 233, + 'FKP' => 238, + 'FJD' => 242, + 'FIM' => 246, + 'FRF' => 250, + 'DJF' => 262, + 'GEK' => 268, + 'GMD' => 270, + 'DEM' => 276, + 'DDM' => 278, + 'GHC' => 288, + 'GIP' => 292, + 'GRD' => 300, + 'GTQ' => 320, + 'GNS' => 324, + 'GNF' => 324, + 'GYD' => 328, + 'HTG' => 332, + 'HNL' => 340, + 'HKD' => 344, + 'HUF' => 348, + 'ISJ' => 352, + 'ISK' => 352, + 'INR' => 356, + 'IDR' => 360, + 'IRR' => 364, + 'IQD' => 368, + 'IEP' => 372, + 'ILP' => 376, + 'ILR' => 376, + 'ILS' => 376, + 'ITL' => 380, + 'JMD' => 388, + 'JPY' => 392, + 'KZT' => 398, + 'JOD' => 400, + 'KES' => 404, + 'KPW' => 408, + 'KRW' => 410, + 'KWD' => 414, + 'KGS' => 417, + 'LAK' => 418, + 'LBP' => 422, + 'LSL' => 426, + 'LVR' => 428, + 'LVL' => 428, + 'LRD' => 430, + 'LYD' => 434, + 'LTL' => 440, + 'LTT' => 440, + 'LUF' => 442, + 'MOP' => 446, + 'MGF' => 450, + 'MWK' => 454, + 'MYR' => 458, + 'MVR' => 462, + 'MLF' => 466, + 'MTL' => 470, + 'MTP' => 470, + 'MRO' => 478, + 'MUR' => 480, + 'MXP' => 484, + 'MXN' => 484, + 'MNT' => 496, + 'MDL' => 498, + 'MAD' => 504, + 'MZE' => 508, + 'MZM' => 508, + 'OMR' => 512, + 'NAD' => 516, + 'NPR' => 524, + 'NLG' => 528, + 'ANG' => 532, + 'AWG' => 533, + 'VUV' => 548, + 'NZD' => 554, + 'NIC' => 558, + 'NIO' => 558, + 'NGN' => 566, + 'NOK' => 578, + 'PKR' => 586, + 'PAB' => 590, + 'PGK' => 598, + 'PYG' => 600, + 'PEI' => 604, + 'PES' => 604, + 'PEN' => 604, + 'PHP' => 608, + 'PLZ' => 616, + 'PTE' => 620, + 'GWP' => 624, + 'GWE' => 624, + 'TPE' => 626, + 'QAR' => 634, + 'ROL' => 642, + 'RUB' => 643, + 'RWF' => 646, + 'SHP' => 654, + 'STD' => 678, + 'SAR' => 682, + 'SCR' => 690, + 'SLL' => 694, + 'SGD' => 702, + 'SKK' => 703, + 'VND' => 704, + 'SIT' => 705, + 'SOS' => 706, + 'ZAR' => 710, + 'ZWD' => 716, + 'RHD' => 716, + 'YDD' => 720, + 'ESP' => 724, + 'SSP' => 728, + 'SDD' => 736, + 'SDP' => 736, + 'SRG' => 740, + 'SZL' => 748, + 'SEK' => 752, + 'CHF' => 756, + 'SYP' => 760, + 'TJR' => 762, + 'THB' => 764, + 'TOP' => 776, + 'TTD' => 780, + 'AED' => 784, + 'TND' => 788, + 'TRL' => 792, + 'TMM' => 795, + 'UGX' => 800, + 'UGS' => 800, + 'UAK' => 804, + 'MKD' => 807, + 'RUR' => 810, + 'SUR' => 810, + 'EGP' => 818, + 'GBP' => 826, + 'TZS' => 834, + 'USD' => 840, + 'UYP' => 858, + 'UYU' => 858, + 'UZS' => 860, + 'VEB' => 862, + 'WST' => 882, + 'YER' => 886, + 'YUN' => 890, + 'YUD' => 890, + 'YUM' => 891, + 'CSD' => 891, + 'ZMK' => 894, + 'TWD' => 901, + 'UYW' => 927, + 'VES' => 928, + 'MRU' => 929, + 'STN' => 930, + 'CUC' => 931, + 'ZWL' => 932, + 'BYN' => 933, + 'TMT' => 934, + 'ZWR' => 935, + 'GHS' => 936, + 'VEF' => 937, + 'SDG' => 938, + 'UYI' => 940, + 'RSD' => 941, + 'MZN' => 943, + 'AZN' => 944, + 'RON' => 946, + 'CHE' => 947, + 'CHW' => 948, + 'TRY' => 949, + 'XAF' => 950, + 'XCD' => 951, + 'XOF' => 952, + 'XPF' => 953, + 'XEU' => 954, + 'ZMW' => 967, + 'SRD' => 968, + 'MGA' => 969, + 'COU' => 970, + 'AFN' => 971, + 'TJS' => 972, + 'AOA' => 973, + 'BYR' => 974, + 'BGN' => 975, + 'CDF' => 976, + 'BAM' => 977, + 'EUR' => 978, + 'MXV' => 979, + 'UAH' => 980, + 'GEL' => 981, + 'AOR' => 982, + 'ECV' => 983, + 'BOV' => 984, + 'PLN' => 985, + 'BRL' => 986, + 'BRR' => 987, + 'LUL' => 988, + 'LUC' => 989, + 'CLF' => 990, + 'ZAL' => 991, + 'BEL' => 992, + 'BEC' => 993, + 'ESB' => 995, + 'ESA' => 996, + 'USN' => 997, + 'USS' => 998, + ]; + + public function testGetCurrencies() + { + $this->assertSame(self::$currencies, Currencies::getCurrencyCodes()); + } + + /** + * @dataProvider provideLocales + */ + public function testGetNames($displayLocale) + { + $names = Currencies::getNames($displayLocale); + + $keys = array_keys($names); + + sort($keys); + + $this->assertSame(self::$currencies, $keys); + + // Names should be sorted + $sortedNames = $names; + $collator = new \Collator($displayLocale); + $collator->asort($names); + + $this->assertSame($sortedNames, $names); + } + + public function testGetNamesDefaultLocale() + { + Locale::setDefault('de_AT'); + + $this->assertSame(Currencies::getNames('de_AT'), Currencies::getNames()); + } + + /** + * @dataProvider provideLocaleAliases + */ + public function testGetNamesSupportsAliases($alias, $ofLocale) + { + // Can't use assertSame(), because some aliases contain scripts with + // different collation (=order of output) than their aliased locale + // e.g. sr_Latn_ME => sr_ME + $this->assertEquals(Currencies::getNames($ofLocale), Currencies::getNames($alias)); + } + + /** + * @dataProvider provideLocales + */ + public function testGetName($displayLocale) + { + $expected = Currencies::getNames($displayLocale); + $actual = []; + + foreach ($expected as $currency => $name) { + $actual[$currency] = Currencies::getName($currency, $displayLocale); + } + + $this->assertSame($expected, $actual); + } + + public function testGetNameDefaultLocale() + { + Locale::setDefault('de_AT'); + + $expected = Currencies::getNames('de_AT'); + $actual = []; + + foreach ($expected as $currency => $name) { + $actual[$currency] = Currencies::getName($currency); + } + + $this->assertSame($expected, $actual); + } + + /** + * @dataProvider provideLocales + */ + public function testGetSymbol($displayLocale) + { + $currencies = Currencies::getCurrencyCodes(); + + foreach ($currencies as $currency) { + $this->assertGreaterThan(0, mb_strlen(Currencies::getSymbol($currency, $displayLocale))); + } + } + + public function provideCurrencies() + { + return array_map( + function ($currency) { return [$currency]; }, + self::$currencies + ); + } + + /** + * @dataProvider provideCurrencies + */ + public function testGetFractionDigits($currency) + { + $this->assertInternalType('numeric', Currencies::getFractionDigits($currency)); + } + + /** + * @dataProvider provideCurrencies + */ + public function testGetRoundingIncrement($currency) + { + $this->assertInternalType('numeric', Currencies::getRoundingIncrement($currency)); + } + + public function provideCurrenciesWithNumericEquivalent() + { + return array_map( + function ($value) { return [$value]; }, + array_keys(self::$alpha3ToNumeric) + ); + } + + /** + * @dataProvider provideCurrenciesWithNumericEquivalent + */ + public function testGetNumericCode($currency) + { + $this->assertSame(self::$alpha3ToNumeric[$currency], Currencies::getNumericCode($currency)); + } + + public function provideCurrenciesWithoutNumericEquivalent() + { + return array_map( + function ($value) { return [$value]; }, + array_diff(self::$currencies, array_keys(self::$alpha3ToNumeric)) + ); + } + + /** + * @dataProvider provideCurrenciesWithoutNumericEquivalent + * @expectedException \Symfony\Component\Intl\Exception\MissingResourceException + */ + public function testGetNumericCodeFailsIfNoNumericEquivalent($currency) + { + Currencies::getNumericCode($currency); + } + + public function provideValidNumericCodes() + { + $numericToAlpha3 = $this->getNumericToAlpha3Mapping(); + + return array_map( + function ($numeric, $alpha3) { return [$numeric, $alpha3]; }, + array_keys($numericToAlpha3), + $numericToAlpha3 + ); + } + + /** + * @dataProvider provideValidNumericCodes + */ + public function testForNumericCode($numeric, $expected) + { + $actual = Currencies::forNumericCode($numeric); + + // Make sure that a different array order doesn't break the test + sort($actual); + sort($expected); + + $this->assertSame($expected, $actual); + } + + public function provideInvalidNumericCodes() + { + $validNumericCodes = array_keys($this->getNumericToAlpha3Mapping()); + $invalidNumericCodes = array_diff(range(0, 1000), $validNumericCodes); + + return array_map( + function ($value) { return [$value]; }, + $invalidNumericCodes + ); + } + + /** + * @dataProvider provideInvalidNumericCodes + * @expectedException \Symfony\Component\Intl\Exception\MissingResourceException + */ + public function testForNumericCodeFailsIfInvalidNumericCode($currency) + { + Currencies::forNumericCode($currency); + } + + private function getNumericToAlpha3Mapping() + { + $numericToAlpha3 = []; + + foreach (self::$alpha3ToNumeric as $alpha3 => $numeric) { + if (!isset($numericToAlpha3[$numeric])) { + $numericToAlpha3[$numeric] = []; + } + + $numericToAlpha3[$numeric][] = $alpha3; + } + + return $numericToAlpha3; + } +} diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractCurrencyDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractCurrencyDataProviderTest.php index 428f6f89b0045..65140b9d2bd20 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractCurrencyDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractCurrencyDataProviderTest.php @@ -17,6 +17,8 @@ /** * @author Bernhard Schussek + * + * @group legacy */ abstract class AbstractCurrencyDataProviderTest extends AbstractDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractDataProviderTest.php index d0ef4d273b45a..b61f97c7a403c 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractDataProviderTest.php @@ -18,6 +18,8 @@ /** * @author Bernhard Schussek + * + * @group legacy */ abstract class AbstractDataProviderTest extends TestCase { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLanguageDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLanguageDataProviderTest.php index 310fe791608f9..580b7ed951165 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLanguageDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLanguageDataProviderTest.php @@ -17,6 +17,8 @@ /** * @author Bernhard Schussek + * + * @group legacy */ abstract class AbstractLanguageDataProviderTest extends AbstractDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLocaleDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLocaleDataProviderTest.php index aeca40cdbd6cd..0fe89266002a9 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLocaleDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLocaleDataProviderTest.php @@ -17,6 +17,8 @@ /** * @author Bernhard Schussek + * + * @group legacy */ abstract class AbstractLocaleDataProviderTest extends AbstractDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractRegionDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractRegionDataProviderTest.php index 1f5febb2b86bf..0e0325cdb784c 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractRegionDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractRegionDataProviderTest.php @@ -17,6 +17,8 @@ /** * @author Bernhard Schussek + * + * @group legacy */ abstract class AbstractRegionDataProviderTest extends AbstractDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractScriptDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractScriptDataProviderTest.php index db4b81ebdb13f..669bbfa3459bb 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractScriptDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractScriptDataProviderTest.php @@ -18,6 +18,7 @@ /** * @author Bernhard Schussek * @group intl-data + * @group legacy */ abstract class AbstractScriptDataProviderTest extends AbstractDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonCurrencyDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonCurrencyDataProviderTest.php index 1baca128d687f..ff12edb44126b 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonCurrencyDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonCurrencyDataProviderTest.php @@ -19,6 +19,7 @@ /** * @author Bernhard Schussek * @group intl-data + * @group legacy */ class JsonCurrencyDataProviderTest extends AbstractCurrencyDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonLanguageDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonLanguageDataProviderTest.php index ba4c0ee08c143..74049ab53e13f 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonLanguageDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonLanguageDataProviderTest.php @@ -19,6 +19,7 @@ /** * @author Bernhard Schussek * @group intl-data + * @group legacy */ class JsonLanguageDataProviderTest extends AbstractLanguageDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonLocaleDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonLocaleDataProviderTest.php index 2e5e803b1d443..ba00439bdcea0 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonLocaleDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonLocaleDataProviderTest.php @@ -19,6 +19,7 @@ /** * @author Bernhard Schussek * @group intl-data + * @group legacy */ class JsonLocaleDataProviderTest extends AbstractLocaleDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonRegionDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonRegionDataProviderTest.php index c3dba262475ca..9bb3bba48917d 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonRegionDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonRegionDataProviderTest.php @@ -19,6 +19,7 @@ /** * @author Bernhard Schussek * @group intl-data + * @group legacy */ class JsonRegionDataProviderTest extends AbstractRegionDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonScriptDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonScriptDataProviderTest.php index ec1eede660cd8..9648cbaca306f 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonScriptDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonScriptDataProviderTest.php @@ -19,6 +19,7 @@ /** * @author Bernhard Schussek * @group intl-data + * @group legacy */ class JsonScriptDataProviderTest extends AbstractScriptDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/IntlTest.php b/src/Symfony/Component/Intl/Tests/IntlTest.php index de722baf948f3..fd8f294a3841e 100644 --- a/src/Symfony/Component/Intl/Tests/IntlTest.php +++ b/src/Symfony/Component/Intl/Tests/IntlTest.php @@ -24,21 +24,33 @@ public function testIsExtensionLoadedChecksIfIntlExtensionIsLoaded() $this->assertTrue(Intl::isExtensionLoaded()); } + /** + * @group legacy + */ public function testGetCurrencyBundleCreatesTheCurrencyBundle() { $this->assertInstanceOf('Symfony\Component\Intl\ResourceBundle\CurrencyBundleInterface', Intl::getCurrencyBundle()); } + /** + * @group legacy + */ public function testGetLanguageBundleCreatesTheLanguageBundle() { $this->assertInstanceOf('Symfony\Component\Intl\ResourceBundle\LanguageBundleInterface', Intl::getLanguageBundle()); } + /** + * @group legacy + */ public function testGetLocaleBundleCreatesTheLocaleBundle() { $this->assertInstanceOf('Symfony\Component\Intl\ResourceBundle\LocaleBundleInterface', Intl::getLocaleBundle()); } + /** + * @group legacy + */ public function testGetRegionBundleCreatesTheRegionBundle() { $this->assertInstanceOf('Symfony\Component\Intl\ResourceBundle\RegionBundleInterface', Intl::getRegionBundle()); @@ -65,6 +77,7 @@ public function testGetDataDirectoryReturnsThePathToIcuData() } /** + * @group legacy * @requires extension intl */ public function testLocaleAliasesAreLoaded() diff --git a/src/Symfony/Component/Intl/Tests/LanguagesTest.php b/src/Symfony/Component/Intl/Tests/LanguagesTest.php new file mode 100644 index 0000000000000..6fa059b29445a --- /dev/null +++ b/src/Symfony/Component/Intl/Tests/LanguagesTest.php @@ -0,0 +1,918 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Intl\Tests; + +use Symfony\Component\Intl\Languages; +use Symfony\Component\Intl\Locale; + +/** + * @group intl-data + */ +class LanguagesTest extends ResourceBundleTestCase +{ + // The below arrays document the state of the ICU data bundled with this package. + + private static $languages = [ + 'aa', + 'ab', + 'ace', + 'ach', + 'ada', + 'ady', + 'ae', + 'aeb', + 'af', + 'afh', + 'agq', + 'ain', + 'ak', + 'akk', + 'akz', + 'ale', + 'aln', + 'alt', + 'am', + 'an', + 'ang', + 'anp', + 'ar', + 'ar_001', + 'arc', + 'arn', + 'aro', + 'arp', + 'arq', + 'ars', + 'arw', + 'ary', + 'arz', + 'as', + 'asa', + 'ase', + 'ast', + 'av', + 'avk', + 'awa', + 'ay', + 'az', + 'az_Arab', + 'ba', + 'bal', + 'ban', + 'bar', + 'bas', + 'bax', + 'bbc', + 'bbj', + 'be', + 'bej', + 'bem', + 'bew', + 'bez', + 'bfd', + 'bfq', + 'bg', + 'bgn', + 'bho', + 'bi', + 'bik', + 'bin', + 'bjn', + 'bkm', + 'bla', + 'bm', + 'bn', + 'bo', + 'bpy', + 'bqi', + 'br', + 'bra', + 'brh', + 'brx', + 'bs', + 'bss', + 'bua', + 'bug', + 'bum', + 'byn', + 'byv', + 'ca', + 'cad', + 'car', + 'cay', + 'cch', + 'ccp', + 'ce', + 'ceb', + 'cgg', + 'ch', + 'chb', + 'chg', + 'chk', + 'chm', + 'chn', + 'cho', + 'chp', + 'chr', + 'chy', + 'ckb', + 'co', + 'cop', + 'cps', + 'cr', + 'crh', + 'crs', + 'cs', + 'csb', + 'cu', + 'cv', + 'cy', + 'da', + 'dak', + 'dar', + 'dav', + 'de', + 'de_AT', + 'de_CH', + 'del', + 'den', + 'dgr', + 'din', + 'dje', + 'doi', + 'dsb', + 'dtp', + 'dua', + 'dum', + 'dv', + 'dyo', + 'dyu', + 'dz', + 'dzg', + 'ebu', + 'ee', + 'efi', + 'egl', + 'egy', + 'eka', + 'el', + 'elx', + 'en', + 'en_AU', + 'en_CA', + 'en_GB', + 'en_US', + 'enm', + 'eo', + 'es', + 'es_419', + 'es_ES', + 'es_MX', + 'esu', + 'et', + 'eu', + 'ewo', + 'ext', + 'fa', + 'fa_AF', + 'fan', + 'fat', + 'ff', + 'fi', + 'fil', + 'fit', + 'fj', + 'fo', + 'fon', + 'fr', + 'fr_CA', + 'fr_CH', + 'frc', + 'frm', + 'fro', + 'frp', + 'frr', + 'frs', + 'fur', + 'fy', + 'ga', + 'gaa', + 'gag', + 'gan', + 'gay', + 'gba', + 'gbz', + 'gd', + 'gez', + 'gil', + 'gl', + 'glk', + 'gmh', + 'gn', + 'goh', + 'gom', + 'gon', + 'gor', + 'got', + 'grb', + 'grc', + 'gsw', + 'gu', + 'guc', + 'gur', + 'guz', + 'gv', + 'gwi', + 'ha', + 'hai', + 'hak', + 'haw', + 'he', + 'hi', + 'hif', + 'hil', + 'hit', + 'hmn', + 'ho', + 'hr', + 'hsb', + 'hsn', + 'ht', + 'hu', + 'hup', + 'hy', + 'hz', + 'ia', + 'iba', + 'ibb', + 'id', + 'ie', + 'ig', + 'ii', + 'ik', + 'ilo', + 'inh', + 'io', + 'is', + 'it', + 'iu', + 'izh', + 'ja', + 'jam', + 'jbo', + 'jgo', + 'jmc', + 'jpr', + 'jrb', + 'jut', + 'jv', + 'ka', + 'kaa', + 'kab', + 'kac', + 'kaj', + 'kam', + 'kaw', + 'kbd', + 'kbl', + 'kcg', + 'kde', + 'kea', + 'ken', + 'kfo', + 'kg', + 'kgp', + 'kha', + 'kho', + 'khq', + 'khw', + 'ki', + 'kiu', + 'kj', + 'kk', + 'kkj', + 'kl', + 'kln', + 'km', + 'kmb', + 'kn', + 'ko', + 'koi', + 'kok', + 'kos', + 'kpe', + 'kr', + 'krc', + 'kri', + 'krj', + 'krl', + 'kru', + 'ks', + 'ksb', + 'ksf', + 'ksh', + 'ku', + 'kum', + 'kut', + 'kv', + 'kw', + 'ky', + 'la', + 'lad', + 'lag', + 'lah', + 'lam', + 'lb', + 'lez', + 'lfn', + 'lg', + 'li', + 'lij', + 'liv', + 'lkt', + 'lmo', + 'ln', + 'lo', + 'lol', + 'lou', + 'loz', + 'lrc', + 'lt', + 'ltg', + 'lu', + 'lua', + 'lui', + 'lun', + 'luo', + 'lus', + 'luy', + 'lv', + 'lzh', + 'lzz', + 'mad', + 'maf', + 'mag', + 'mai', + 'mak', + 'man', + 'mas', + 'mde', + 'mdf', + 'mdr', + 'men', + 'mer', + 'mfe', + 'mg', + 'mga', + 'mgh', + 'mgo', + 'mh', + 'mi', + 'mic', + 'min', + 'mk', + 'ml', + 'mn', + 'mnc', + 'mni', + 'moh', + 'mos', + 'mr', + 'mrj', + 'ms', + 'mt', + 'mua', + 'mus', + 'mwl', + 'mwr', + 'mwv', + 'my', + 'mye', + 'myv', + 'mzn', + 'na', + 'nan', + 'nap', + 'naq', + 'nb', + 'nd', + 'nds', + 'nds_NL', + 'ne', + 'new', + 'ng', + 'nia', + 'niu', + 'njo', + 'nl', + 'nl_BE', + 'nmg', + 'nn', + 'nnh', + 'no', + 'nog', + 'non', + 'nov', + 'nqo', + 'nr', + 'nso', + 'nus', + 'nv', + 'nwc', + 'ny', + 'nym', + 'nyn', + 'nyo', + 'nzi', + 'oc', + 'oj', + 'om', + 'or', + 'os', + 'osa', + 'ota', + 'pa', + 'pag', + 'pal', + 'pam', + 'pap', + 'pau', + 'pcd', + 'pcm', + 'pdc', + 'pdt', + 'peo', + 'pfl', + 'phn', + 'pi', + 'pl', + 'pms', + 'pnt', + 'pon', + 'prg', + 'pro', + 'ps', + 'pt', + 'pt_BR', + 'pt_PT', + 'qu', + 'quc', + 'qug', + 'raj', + 'rap', + 'rar', + 'rgn', + 'rif', + 'rm', + 'rn', + 'ro', + 'ro_MD', + 'rof', + 'rom', + 'root', + 'rtm', + 'ru', + 'rue', + 'rug', + 'rup', + 'rw', + 'rwk', + 'sa', + 'sad', + 'sah', + 'sam', + 'saq', + 'sas', + 'sat', + 'saz', + 'sba', + 'sbp', + 'sc', + 'scn', + 'sco', + 'sd', + 'sdc', + 'sdh', + 'se', + 'see', + 'seh', + 'sei', + 'sel', + 'ses', + 'sg', + 'sga', + 'sgs', + 'sh', + 'shi', + 'shn', + 'shu', + 'si', + 'sid', + 'sk', + 'sl', + 'sli', + 'sly', + 'sm', + 'sma', + 'smj', + 'smn', + 'sms', + 'sn', + 'snk', + 'so', + 'sog', + 'sq', + 'sr', + 'sr_ME', + 'srn', + 'srr', + 'ss', + 'ssy', + 'st', + 'stq', + 'su', + 'suk', + 'sus', + 'sux', + 'sv', + 'sw', + 'sw_CD', + 'swb', + 'syc', + 'syr', + 'szl', + 'ta', + 'tcy', + 'te', + 'tem', + 'teo', + 'ter', + 'tet', + 'tg', + 'th', + 'ti', + 'tig', + 'tiv', + 'tk', + 'tkl', + 'tkr', + 'tl', + 'tlh', + 'tli', + 'tly', + 'tmh', + 'tn', + 'to', + 'tog', + 'tpi', + 'tr', + 'tru', + 'trv', + 'ts', + 'tsd', + 'tsi', + 'tt', + 'ttt', + 'tum', + 'tvl', + 'tw', + 'twq', + 'ty', + 'tyv', + 'tzm', + 'udm', + 'ug', + 'uga', + 'uk', + 'umb', + 'ur', + 'uz', + 'vai', + 've', + 'vec', + 'vep', + 'vi', + 'vls', + 'vmf', + 'vo', + 'vot', + 'vro', + 'vun', + 'wa', + 'wae', + 'wal', + 'war', + 'was', + 'wbp', + 'wo', + 'wuu', + 'xal', + 'xh', + 'xmf', + 'xog', + 'yao', + 'yap', + 'yav', + 'ybb', + 'yi', + 'yo', + 'yrl', + 'yue', + 'za', + 'zap', + 'zbl', + 'zea', + 'zen', + 'zgh', + 'zh', + 'zh_Hans', + 'zh_Hant', + 'zu', + 'zun', + 'zza', + ]; + + private static $alpha2ToAlpha3 = [ + 'aa' => 'aar', + 'ab' => 'abk', + 'af' => 'afr', + 'ak' => 'aka', + 'sq' => 'sqi', + 'am' => 'amh', + 'ar' => 'ara', + 'an' => 'arg', + 'hy' => 'hye', + 'as' => 'asm', + 'av' => 'ava', + 'ae' => 'ave', + 'ay' => 'aym', + 'az' => 'aze', + 'ba' => 'bak', + 'bm' => 'bam', + 'eu' => 'eus', + 'be' => 'bel', + 'bn' => 'ben', + 'bi' => 'bis', + 'bo' => 'bod', + 'bs' => 'bos', + 'br' => 'bre', + 'bg' => 'bul', + 'my' => 'mya', + 'ca' => 'cat', + 'cs' => 'ces', + 'ch' => 'cha', + 'ce' => 'che', + 'zh' => 'zho', + 'cu' => 'chu', + 'cv' => 'chv', + 'kw' => 'cor', + 'co' => 'cos', + 'cr' => 'cre', + 'cy' => 'cym', + 'da' => 'dan', + 'de' => 'deu', + 'dv' => 'div', + 'nl' => 'nld', + 'dz' => 'dzo', + 'et' => 'est', + 'el' => 'ell', + 'en' => 'eng', + 'eo' => 'epo', + 'ik' => 'ipk', + 'ee' => 'ewe', + 'fo' => 'fao', + 'fa' => 'fas', + 'fj' => 'fij', + 'fi' => 'fin', + 'fr' => 'fra', + 'fy' => 'fry', + 'ff' => 'ful', + 'om' => 'orm', + 'ka' => 'kat', + 'gd' => 'gla', + 'ga' => 'gle', + 'gl' => 'glg', + 'gv' => 'glv', + 'gn' => 'grn', + 'gu' => 'guj', + 'ht' => 'hat', + 'ha' => 'hau', + 'he' => 'heb', + 'hz' => 'her', + 'hi' => 'hin', + 'ho' => 'hmo', + 'hr' => 'hrv', + 'hu' => 'hun', + 'ig' => 'ibo', + 'is' => 'isl', + 'io' => 'ido', + 'ii' => 'iii', + 'iu' => 'iku', + 'ie' => 'ile', + 'ia' => 'ina', + 'id' => 'ind', + 'it' => 'ita', + 'jv' => 'jav', + 'ja' => 'jpn', + 'kl' => 'kal', + 'kn' => 'kan', + 'ks' => 'kas', + 'kr' => 'kau', + 'kk' => 'kaz', + 'mn' => 'mon', + 'km' => 'khm', + 'ki' => 'kik', + 'rw' => 'kin', + 'ky' => 'kir', + 'ku' => 'kur', + 'kg' => 'kon', + 'kv' => 'kom', + 'ko' => 'kor', + 'kj' => 'kua', + 'lo' => 'lao', + 'la' => 'lat', + 'lv' => 'lav', + 'li' => 'lim', + 'ln' => 'lin', + 'lt' => 'lit', + 'lb' => 'ltz', + 'lu' => 'lub', + 'lg' => 'lug', + 'mk' => 'mkd', + 'mh' => 'mah', + 'ml' => 'mal', + 'mi' => 'mri', + 'mr' => 'mar', + 'ms' => 'msa', + 'mg' => 'mlg', + 'mt' => 'mlt', + 'na' => 'nau', + 'nv' => 'nav', + 'nr' => 'nbl', + 'nd' => 'nde', + 'ng' => 'ndo', + 'ne' => 'nep', + 'nn' => 'nno', + 'nb' => 'nob', + 'ny' => 'nya', + 'oc' => 'oci', + 'oj' => 'oji', + 'or' => 'ori', + 'os' => 'oss', + 'pa' => 'pan', + 'ps' => 'pus', + 'pi' => 'pli', + 'pl' => 'pol', + 'pt' => 'por', + 'qu' => 'que', + 'rm' => 'roh', + 'ro' => 'ron', + 'rn' => 'run', + 'ru' => 'rus', + 'sg' => 'sag', + 'sa' => 'san', + 'sr' => 'srp', + 'si' => 'sin', + 'sk' => 'slk', + 'sl' => 'slv', + 'se' => 'sme', + 'sm' => 'smo', + 'sn' => 'sna', + 'sd' => 'snd', + 'so' => 'som', + 'st' => 'sot', + 'es' => 'spa', + 'sc' => 'srd', + 'ss' => 'ssw', + 'su' => 'sun', + 'sw' => 'swa', + 'sv' => 'swe', + 'ty' => 'tah', + 'ta' => 'tam', + 'tt' => 'tat', + 'te' => 'tel', + 'tg' => 'tgk', + 'th' => 'tha', + 'ti' => 'tir', + 'to' => 'ton', + 'tn' => 'tsn', + 'ts' => 'tso', + 'tk' => 'tuk', + 'tr' => 'tur', + 'ug' => 'uig', + 'uk' => 'ukr', + 'ur' => 'urd', + 'uz' => 'uzb', + 've' => 'ven', + 'vi' => 'vie', + 'vo' => 'vol', + 'wa' => 'wln', + 'wo' => 'wol', + 'xh' => 'xho', + 'yi' => 'yid', + 'yo' => 'yor', + 'za' => 'zha', + 'zu' => 'zul', + ]; + + public function testGetLanguages() + { + $this->assertEquals(self::$languages, Languages::getLanguageCodes()); + } + + /** + * @dataProvider provideLocales + */ + public function testGetNames($displayLocale) + { + $languages = array_keys(Languages::getNames($displayLocale)); + + sort($languages); + + $this->assertNotEmpty($languages); + $this->assertEmpty(array_diff($languages, self::$languages)); + } + + public function testGetNamesDefaultLocale() + { + Locale::setDefault('de_AT'); + + $this->assertSame(Languages::getNames('de_AT'), Languages::getNames()); + } + + /** + * @dataProvider provideLocaleAliases + */ + public function testGetNamesSupportsAliases($alias, $ofLocale) + { + // Can't use assertSame(), because some aliases contain scripts with + // different collation (=order of output) than their aliased locale + // e.g. sr_Latn_ME => sr_ME + $this->assertEquals(Languages::getNames($ofLocale), Languages::getNames($alias)); + } + + /** + * @dataProvider provideLocales + */ + public function testGetName($displayLocale) + { + $names = Languages::getNames($displayLocale); + + foreach ($names as $language => $name) { + $this->assertSame($name, Languages::getName($language, $displayLocale)); + } + } + + public function testGetNameDefaultLocale() + { + Locale::setDefault('de_AT'); + + $names = Languages::getNames('de_AT'); + + foreach ($names as $language => $name) { + $this->assertSame($name, Languages::getName($language)); + } + } + + public function provideLanguagesWithAlpha3Equivalent() + { + return array_map( + function ($value) { return [$value]; }, + array_keys(self::$alpha2ToAlpha3) + ); + } + + /** + * @dataProvider provideLanguagesWithAlpha3Equivalent + */ + public function testGetAlpha3Code($language) + { + $this->assertSame(self::$alpha2ToAlpha3[$language], Languages::getAlpha3Code($language)); + } + + public function provideLanguagesWithoutAlpha3Equivalent() + { + return array_map( + function ($value) { return [$value]; }, + array_diff(self::$languages, array_keys(self::$alpha2ToAlpha3)) + ); + } + + /** + * @dataProvider provideLanguagesWithoutAlpha3Equivalent + * @expectedException \Symfony\Component\Intl\Exception\MissingResourceException + */ + public function testGetAlpha3CodeFailsIfNoAlpha3Equivalent($language) + { + Languages::getAlpha3Code($language); + } +} diff --git a/src/Symfony/Component/Intl/Tests/LocalesTest.php b/src/Symfony/Component/Intl/Tests/LocalesTest.php new file mode 100644 index 0000000000000..e7ffbd2ca9a42 --- /dev/null +++ b/src/Symfony/Component/Intl/Tests/LocalesTest.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Intl\Tests; + +use Symfony\Component\Intl\Locale; +use Symfony\Component\Intl\Locales; + +/** + * @group intl-data + */ +class LocalesTest extends ResourceBundleTestCase +{ + public function testGetLocales() + { + $this->assertSame($this->getLocales(), Locales::getLocales()); + } + + public function testGetLocaleAliases() + { + $this->assertSame($this->getLocaleAliases(), Locales::getAliases()); + } + + /** + * @dataProvider provideLocales + */ + public function testGetNames($displayLocale) + { + $locales = array_keys(Locales::getNames($displayLocale)); + + sort($locales); + + // We can't assert on exact list of locale, as there's too many variations. + // The best we can do is to make sure getNames() returns a subset of what getLocales() returns. + $this->assertNotEmpty($locales); + $this->assertEmpty(array_diff($locales, $this->getLocales())); + } + + public function testGetNamesDefaultLocale() + { + Locale::setDefault('de_AT'); + + $this->assertSame(Locales::getNames('de_AT'), Locales::getNames()); + } + + /** + * @dataProvider provideLocaleAliases + */ + public function testGetNamesSupportsAliases($alias, $ofLocale) + { + // Can't use assertSame(), because some aliases contain scripts with + // different collation (=order of output) than their aliased locale + // e.g. sr_Latn_ME => sr_ME + $this->assertEquals(Locales::getNames($ofLocale), Locales::getNames($alias)); + } + + /** + * @dataProvider provideLocales + */ + public function testGetName($displayLocale) + { + $names = Locales::getNames($displayLocale); + + foreach ($names as $locale => $name) { + $this->assertSame($name, Locales::getName($locale, $displayLocale)); + } + } + + public function testGetNameDefaultLocale() + { + Locale::setDefault('de_AT'); + + $names = Locales::getNames('de_AT'); + + foreach ($names as $locale => $name) { + $this->assertSame($name, Locales::getName($locale)); + } + } +} diff --git a/src/Symfony/Component/Intl/Tests/RegionsTest.php b/src/Symfony/Component/Intl/Tests/RegionsTest.php new file mode 100644 index 0000000000000..80d4ca98bf638 --- /dev/null +++ b/src/Symfony/Component/Intl/Tests/RegionsTest.php @@ -0,0 +1,346 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Intl\Tests; + +use Symfony\Component\Intl\Locale; +use Symfony\Component\Intl\Regions; + +/** + * @group intl-data + */ +class RegionsTest extends ResourceBundleTestCase +{ + // The below arrays document the state of the ICU data bundled with this package. + + private static $territories = [ + 'AC', + 'AD', + 'AE', + 'AF', + 'AG', + 'AI', + 'AL', + 'AM', + 'AO', + 'AQ', + 'AR', + 'AS', + 'AT', + 'AU', + 'AW', + 'AX', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BJ', + 'BL', + 'BM', + 'BN', + 'BO', + 'BQ', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CC', + 'CD', + 'CF', + 'CG', + 'CH', + 'CI', + 'CK', + 'CL', + 'CM', + 'CN', + 'CO', + 'CR', + 'CU', + 'CV', + 'CW', + 'CX', + 'CY', + 'CZ', + 'DE', + 'DG', + 'DJ', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EA', + 'EC', + 'EE', + 'EG', + 'EH', + 'ER', + 'ES', + 'ET', + 'FI', + 'FJ', + 'FK', + 'FM', + 'FO', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GF', + 'GG', + 'GH', + 'GI', + 'GL', + 'GM', + 'GN', + 'GP', + 'GQ', + 'GR', + 'GS', + 'GT', + 'GU', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'IC', + 'ID', + 'IE', + 'IL', + 'IM', + 'IN', + 'IO', + 'IQ', + 'IR', + 'IS', + 'IT', + 'JE', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KP', + 'KR', + 'KW', + 'KY', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'LY', + 'MA', + 'MC', + 'MD', + 'ME', + 'MF', + 'MG', + 'MH', + 'MK', + 'ML', + 'MM', + 'MN', + 'MO', + 'MP', + 'MQ', + 'MR', + 'MS', + 'MT', + 'MU', + 'MV', + 'MW', + 'MX', + 'MY', + 'MZ', + 'NA', + 'NC', + 'NE', + 'NF', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NU', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PF', + 'PG', + 'PH', + 'PK', + 'PL', + 'PM', + 'PN', + 'PR', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RE', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SD', + 'SE', + 'SG', + 'SH', + 'SI', + 'SJ', + 'SK', + 'SL', + 'SM', + 'SN', + 'SO', + 'SR', + 'SS', + 'ST', + 'SV', + 'SX', + 'SY', + 'SZ', + 'TA', + 'TC', + 'TD', + 'TF', + 'TG', + 'TH', + 'TJ', + 'TK', + 'TL', + 'TM', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'UM', + 'US', + 'UY', + 'UZ', + 'VA', + 'VC', + 'VE', + 'VG', + 'VI', + 'VN', + 'VU', + 'WF', + 'WS', + 'XA', + 'XB', + 'XK', + 'YE', + 'YT', + 'ZA', + 'ZM', + 'ZW', + ]; + + public function testGetRegions() + { + $this->assertSame(self::$territories, Regions::getRegionCodes()); + } + + /** + * @dataProvider provideLocales + */ + public function testGetNames($displayLocale) + { + $countries = array_keys(Regions::getNames($displayLocale)); + + sort($countries); + + $this->assertSame(self::$territories, $countries); + } + + public function testGetNamesDefaultLocale() + { + Locale::setDefault('de_AT'); + + $this->assertSame(Regions::getNames('de_AT'), Regions::getNames()); + } + + /** + * @dataProvider provideLocaleAliases + */ + public function testGetNamesSupportsAliases($alias, $ofLocale) + { + // Can't use assertSame(), because some aliases contain scripts with + // different collation (=order of output) than their aliased locale + // e.g. sr_Latn_ME => sr_ME + $this->assertEquals(Regions::getNames($ofLocale), Regions::getNames($alias)); + } + + /** + * @dataProvider provideLocales + */ + public function testGetName($displayLocale) + { + $names = Regions::getNames($displayLocale); + + foreach ($names as $country => $name) { + $this->assertSame($name, Regions::getName($country, $displayLocale)); + } + } + + /** + * @requires extension intl + */ + public function testLocaleAliasesAreLoaded() + { + \Locale::setDefault('zh_TW'); + $countryNameZhTw = Regions::getName('AD'); + + \Locale::setDefault('zh_Hant_TW'); + $countryNameHantZhTw = Regions::getName('AD'); + + \Locale::setDefault('zh'); + $countryNameZh = Regions::getName('AD'); + + $this->assertSame($countryNameZhTw, $countryNameHantZhTw, 'zh_TW is an alias to zh_Hant_TW'); + $this->assertNotSame($countryNameZh, $countryNameZhTw, 'zh_TW does not fall back to zh'); + } +} diff --git a/src/Symfony/Component/Intl/Tests/ResourceBundleTestCase.php b/src/Symfony/Component/Intl/Tests/ResourceBundleTestCase.php new file mode 100644 index 0000000000000..3e460985896c7 --- /dev/null +++ b/src/Symfony/Component/Intl/Tests/ResourceBundleTestCase.php @@ -0,0 +1,751 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Intl\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Intl\Locale; + +abstract class ResourceBundleTestCase extends TestCase +{ + // Include the locales statically so that the data providers are decoupled + // from the Intl class. Otherwise tests will fail if the intl extension is + // not loaded, because it is NOT possible to skip the execution of data + // providers. + + private static $locales = [ + 'af', + 'af_NA', + 'af_ZA', + 'ak', + 'ak_GH', + 'am', + 'am_ET', + 'ar', + 'ar_001', + 'ar_AE', + 'ar_BH', + 'ar_DJ', + 'ar_DZ', + 'ar_EG', + 'ar_EH', + 'ar_ER', + 'ar_IL', + 'ar_IQ', + 'ar_JO', + 'ar_KM', + 'ar_KW', + 'ar_LB', + 'ar_LY', + 'ar_MA', + 'ar_MR', + 'ar_OM', + 'ar_PS', + 'ar_QA', + 'ar_SA', + 'ar_SD', + 'ar_SO', + 'ar_SS', + 'ar_SY', + 'ar_TD', + 'ar_TN', + 'ar_YE', + 'as', + 'as_IN', + 'az', + 'az_AZ', + 'az_Cyrl', + 'az_Cyrl_AZ', + 'az_Latn', + 'az_Latn_AZ', + 'be', + 'be_BY', + 'bg', + 'bg_BG', + 'bm', + 'bm_ML', + 'bn', + 'bn_BD', + 'bn_IN', + 'bo', + 'bo_CN', + 'bo_IN', + 'br', + 'br_FR', + 'bs', + 'bs_BA', + 'bs_Cyrl', + 'bs_Cyrl_BA', + 'bs_Latn', + 'bs_Latn_BA', + 'ca', + 'ca_AD', + 'ca_ES', + 'ca_FR', + 'ca_IT', + 'ce', + 'ce_RU', + 'cs', + 'cs_CZ', + 'cy', + 'cy_GB', + 'da', + 'da_DK', + 'da_GL', + 'de', + 'de_AT', + 'de_BE', + 'de_CH', + 'de_DE', + 'de_IT', + 'de_LI', + 'de_LU', + 'dz', + 'dz_BT', + 'ee', + 'ee_GH', + 'ee_TG', + 'el', + 'el_CY', + 'el_GR', + 'en', + 'en_001', + 'en_150', + 'en_AE', + 'en_AG', + 'en_AI', + 'en_AS', + 'en_AT', + 'en_AU', + 'en_BB', + 'en_BE', + 'en_BI', + 'en_BM', + 'en_BS', + 'en_BW', + 'en_BZ', + 'en_CA', + 'en_CC', + 'en_CH', + 'en_CK', + 'en_CM', + 'en_CX', + 'en_CY', + 'en_DE', + 'en_DG', + 'en_DK', + 'en_DM', + 'en_ER', + 'en_FI', + 'en_FJ', + 'en_FK', + 'en_FM', + 'en_GB', + 'en_GD', + 'en_GG', + 'en_GH', + 'en_GI', + 'en_GM', + 'en_GU', + 'en_GY', + 'en_HK', + 'en_IE', + 'en_IL', + 'en_IM', + 'en_IN', + 'en_IO', + 'en_JE', + 'en_JM', + 'en_KE', + 'en_KI', + 'en_KN', + 'en_KY', + 'en_LC', + 'en_LR', + 'en_LS', + 'en_MG', + 'en_MH', + 'en_MO', + 'en_MP', + 'en_MS', + 'en_MT', + 'en_MU', + 'en_MW', + 'en_MY', + 'en_NA', + 'en_NF', + 'en_NG', + 'en_NH', + 'en_NL', + 'en_NR', + 'en_NU', + 'en_NZ', + 'en_PG', + 'en_PH', + 'en_PK', + 'en_PN', + 'en_PR', + 'en_PW', + 'en_RH', + 'en_RW', + 'en_SB', + 'en_SC', + 'en_SD', + 'en_SE', + 'en_SG', + 'en_SH', + 'en_SI', + 'en_SL', + 'en_SS', + 'en_SX', + 'en_SZ', + 'en_TC', + 'en_TK', + 'en_TO', + 'en_TT', + 'en_TV', + 'en_TZ', + 'en_UG', + 'en_UM', + 'en_US', + 'en_US_POSIX', + 'en_VC', + 'en_VG', + 'en_VI', + 'en_VU', + 'en_WS', + 'en_ZA', + 'en_ZM', + 'en_ZW', + 'eo', + 'eo_001', + 'es', + 'es_419', + 'es_AR', + 'es_BO', + 'es_BR', + 'es_BZ', + 'es_CL', + 'es_CO', + 'es_CR', + 'es_CU', + 'es_DO', + 'es_EA', + 'es_EC', + 'es_ES', + 'es_GQ', + 'es_GT', + 'es_HN', + 'es_IC', + 'es_MX', + 'es_NI', + 'es_PA', + 'es_PE', + 'es_PH', + 'es_PR', + 'es_PY', + 'es_SV', + 'es_US', + 'es_UY', + 'es_VE', + 'et', + 'et_EE', + 'eu', + 'eu_ES', + 'fa', + 'fa_AF', + 'fa_IR', + 'ff', + 'ff_CM', + 'ff_GN', + 'ff_Latn', + 'ff_Latn_BF', + 'ff_Latn_CM', + 'ff_Latn_GH', + 'ff_Latn_GM', + 'ff_Latn_GN', + 'ff_Latn_GW', + 'ff_Latn_LR', + 'ff_Latn_MR', + 'ff_Latn_NE', + 'ff_Latn_NG', + 'ff_Latn_SL', + 'ff_Latn_SN', + 'ff_MR', + 'ff_SN', + 'fi', + 'fi_FI', + 'fo', + 'fo_DK', + 'fo_FO', + 'fr', + 'fr_BE', + 'fr_BF', + 'fr_BI', + 'fr_BJ', + 'fr_BL', + 'fr_CA', + 'fr_CD', + 'fr_CF', + 'fr_CG', + 'fr_CH', + 'fr_CI', + 'fr_CM', + 'fr_DJ', + 'fr_DZ', + 'fr_FR', + 'fr_GA', + 'fr_GF', + 'fr_GN', + 'fr_GP', + 'fr_GQ', + 'fr_HT', + 'fr_KM', + 'fr_LU', + 'fr_MA', + 'fr_MC', + 'fr_MF', + 'fr_MG', + 'fr_ML', + 'fr_MQ', + 'fr_MR', + 'fr_MU', + 'fr_NC', + 'fr_NE', + 'fr_PF', + 'fr_PM', + 'fr_RE', + 'fr_RW', + 'fr_SC', + 'fr_SN', + 'fr_SY', + 'fr_TD', + 'fr_TG', + 'fr_TN', + 'fr_VU', + 'fr_WF', + 'fr_YT', + 'fy', + 'fy_NL', + 'ga', + 'ga_IE', + 'gd', + 'gd_GB', + 'gl', + 'gl_ES', + 'gu', + 'gu_IN', + 'gv', + 'gv_IM', + 'ha', + 'ha_GH', + 'ha_NE', + 'ha_NG', + 'he', + 'he_IL', + 'hi', + 'hi_IN', + 'hr', + 'hr_BA', + 'hr_HR', + 'hu', + 'hu_HU', + 'hy', + 'hy_AM', + 'ia', + 'ia_001', + 'id', + 'id_ID', + 'ig', + 'ig_NG', + 'ii', + 'ii_CN', + 'in', + 'in_ID', + 'is', + 'is_IS', + 'it', + 'it_CH', + 'it_IT', + 'it_SM', + 'it_VA', + 'iw', + 'iw_IL', + 'ja', + 'ja_JP', + 'ja_JP_TRADITIONAL', + 'jv', + 'jv_ID', + 'ka', + 'ka_GE', + 'ki', + 'ki_KE', + 'kk', + 'kk_KZ', + 'kl', + 'kl_GL', + 'km', + 'km_KH', + 'kn', + 'kn_IN', + 'ko', + 'ko_KP', + 'ko_KR', + 'ks', + 'ks_IN', + 'ku', + 'ku_TR', + 'kw', + 'kw_GB', + 'ky', + 'ky_KG', + 'lb', + 'lb_LU', + 'lg', + 'lg_UG', + 'ln', + 'ln_AO', + 'ln_CD', + 'ln_CF', + 'ln_CG', + 'lo', + 'lo_LA', + 'lt', + 'lt_LT', + 'lu', + 'lu_CD', + 'lv', + 'lv_LV', + 'mg', + 'mg_MG', + 'mi', + 'mi_NZ', + 'mk', + 'mk_MK', + 'ml', + 'ml_IN', + 'mn', + 'mn_MN', + 'mo', + 'mr', + 'mr_IN', + 'ms', + 'ms_BN', + 'ms_MY', + 'ms_SG', + 'mt', + 'mt_MT', + 'my', + 'my_MM', + 'nb', + 'nb_NO', + 'nb_SJ', + 'nd', + 'nd_ZW', + 'ne', + 'ne_IN', + 'ne_NP', + 'nl', + 'nl_AW', + 'nl_BE', + 'nl_BQ', + 'nl_CW', + 'nl_NL', + 'nl_SR', + 'nl_SX', + 'nn', + 'nn_NO', + 'no', + 'no_NO', + 'no_NO_NY', + 'om', + 'om_ET', + 'om_KE', + 'or', + 'or_IN', + 'os', + 'os_GE', + 'os_RU', + 'pa', + 'pa_Arab', + 'pa_Arab_PK', + 'pa_Guru', + 'pa_Guru_IN', + 'pa_IN', + 'pa_PK', + 'pl', + 'pl_PL', + 'ps', + 'ps_AF', + 'ps_PK', + 'pt', + 'pt_AO', + 'pt_BR', + 'pt_CH', + 'pt_CV', + 'pt_GQ', + 'pt_GW', + 'pt_LU', + 'pt_MO', + 'pt_MZ', + 'pt_PT', + 'pt_ST', + 'pt_TL', + 'qu', + 'qu_BO', + 'qu_EC', + 'qu_PE', + 'rm', + 'rm_CH', + 'rn', + 'rn_BI', + 'ro', + 'ro_MD', + 'ro_RO', + 'ru', + 'ru_BY', + 'ru_KG', + 'ru_KZ', + 'ru_MD', + 'ru_RU', + 'ru_UA', + 'rw', + 'rw_RW', + 'sd', + 'sd_PK', + 'se', + 'se_FI', + 'se_NO', + 'se_SE', + 'sg', + 'sg_CF', + 'sh', + 'sh_BA', + 'sh_CS', + 'sh_YU', + 'si', + 'si_LK', + 'sk', + 'sk_SK', + 'sl', + 'sl_SI', + 'sn', + 'sn_ZW', + 'so', + 'so_DJ', + 'so_ET', + 'so_KE', + 'so_SO', + 'sq', + 'sq_AL', + 'sq_MK', + 'sq_XK', + 'sr', + 'sr_BA', + 'sr_CS', + 'sr_Cyrl', + 'sr_Cyrl_BA', + 'sr_Cyrl_CS', + 'sr_Cyrl_ME', + 'sr_Cyrl_RS', + 'sr_Cyrl_XK', + 'sr_Cyrl_YU', + 'sr_Latn', + 'sr_Latn_BA', + 'sr_Latn_CS', + 'sr_Latn_ME', + 'sr_Latn_RS', + 'sr_Latn_XK', + 'sr_Latn_YU', + 'sr_ME', + 'sr_RS', + 'sr_XK', + 'sr_YU', + 'sv', + 'sv_AX', + 'sv_FI', + 'sv_SE', + 'sw', + 'sw_CD', + 'sw_KE', + 'sw_TZ', + 'sw_UG', + 'ta', + 'ta_IN', + 'ta_LK', + 'ta_MY', + 'ta_SG', + 'te', + 'te_IN', + 'tg', + 'tg_TJ', + 'th', + 'th_TH', + 'th_TH_TRADITIONAL', + 'ti', + 'ti_ER', + 'ti_ET', + 'tk', + 'tk_TM', + 'tl', + 'tl_PH', + 'to', + 'to_TO', + 'tr', + 'tr_CY', + 'tr_TR', + 'tt', + 'tt_RU', + 'ug', + 'ug_CN', + 'uk', + 'uk_UA', + 'ur', + 'ur_IN', + 'ur_PK', + 'uz', + 'uz_AF', + 'uz_Arab', + 'uz_Arab_AF', + 'uz_Cyrl', + 'uz_Cyrl_UZ', + 'uz_Latn', + 'uz_Latn_UZ', + 'uz_UZ', + 'vi', + 'vi_VN', + 'wo', + 'wo_SN', + 'xh', + 'xh_ZA', + 'yi', + 'yi_001', + 'yo', + 'yo_BJ', + 'yo_NG', + 'zh', + 'zh_CN', + 'zh_HK', + 'zh_Hans', + 'zh_Hans_CN', + 'zh_Hans_HK', + 'zh_Hans_MO', + 'zh_Hans_SG', + 'zh_Hant', + 'zh_Hant_HK', + 'zh_Hant_MO', + 'zh_Hant_TW', + 'zh_MO', + 'zh_SG', + 'zh_TW', + 'zu', + 'zu_ZA', + ]; + + private static $localeAliases = [ + 'az_AZ' => 'az_Latn_AZ', + 'bs_BA' => 'bs_Latn_BA', + 'en_NH' => 'en_VU', + 'en_RH' => 'en_ZW', + 'ff_CM' => 'ff_Latn_CM', + 'ff_GN' => 'ff_Latn_GN', + 'ff_MR' => 'ff_Latn_MR', + 'ff_SN' => 'ff_Latn_SN', + 'in' => 'id', + 'in_ID' => 'id_ID', + 'iw' => 'he', + 'iw_IL' => 'he_IL', + 'mo' => 'ro', + 'no' => 'nb', + 'no_NO' => 'nb_NO', + 'no_NO_NY' => 'nn_NO', + 'pa_IN' => 'pa_Guru_IN', + 'pa_PK' => 'pa_Arab_PK', + 'sh' => 'sr_Latn', + 'sh_BA' => 'sr_Latn_BA', + 'sh_CS' => 'sr_Latn_RS', + 'sh_YU' => 'sr_Latn_RS', + 'sr_BA' => 'sr_Cyrl_BA', + 'sr_CS' => 'sr_Cyrl_RS', + 'sr_Cyrl_CS' => 'sr_Cyrl_RS', + 'sr_Cyrl_YU' => 'sr_Cyrl_RS', + 'sr_Latn_CS' => 'sr_Latn_RS', + 'sr_Latn_YU' => 'sr_Latn_RS', + 'sr_ME' => 'sr_Latn_ME', + 'sr_RS' => 'sr_Cyrl_RS', + 'sr_XK' => 'sr_Cyrl_XK', + 'sr_YU' => 'sr_Cyrl_RS', + 'tl' => 'fil', + 'tl_PH' => 'fil_PH', + 'uz_AF' => 'uz_Arab_AF', + 'uz_UZ' => 'uz_Latn_UZ', + 'zh_CN' => 'zh_Hans_CN', + 'zh_HK' => 'zh_Hant_HK', + 'zh_MO' => 'zh_Hant_MO', + 'zh_SG' => 'zh_Hans_SG', + 'zh_TW' => 'zh_Hant_TW', + ]; + + private static $rootLocales; + + protected function setUp() + { + Locale::setDefault('en'); + Locale::setDefaultFallback('en'); + } + + public function provideLocales() + { + return array_map( + function ($locale) { return [$locale]; }, + $this->getLocales() + ); + } + + public function provideLocaleAliases() + { + return array_map( + function ($alias, $ofLocale) { return [$alias, $ofLocale]; }, + array_keys($this->getLocaleAliases()), + $this->getLocaleAliases() + ); + } + + public function provideRootLocales() + { + return array_map( + function ($locale) { return [$locale]; }, + $this->getRootLocales() + ); + } + + protected function getLocales() + { + return self::$locales; + } + + protected function getLocaleAliases() + { + return self::$localeAliases; + } + + protected function getRootLocales() + { + if (null === self::$rootLocales) { + self::$rootLocales = array_filter($this->getLocales(), function ($locale) { + // no locales for which fallback is possible (e.g "en_GB") + return false === strpos($locale, '_'); + }); + } + + return self::$rootLocales; + } +} diff --git a/src/Symfony/Component/Intl/Tests/ScriptsTest.php b/src/Symfony/Component/Intl/Tests/ScriptsTest.php new file mode 100644 index 0000000000000..5b404fda85aaa --- /dev/null +++ b/src/Symfony/Component/Intl/Tests/ScriptsTest.php @@ -0,0 +1,277 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Intl\Tests; + +use Symfony\Component\Intl\Locale; +use Symfony\Component\Intl\Scripts; + +/** + * @group intl-data + */ +class ScriptsTest extends ResourceBundleTestCase +{ + // The below arrays document the state of the ICU data bundled with this package. + + protected static $scripts = [ + 'Adlm', + 'Afak', + 'Aghb', + 'Ahom', + 'Arab', + 'Armi', + 'Armn', + 'Avst', + 'Bali', + 'Bamu', + 'Bass', + 'Batk', + 'Beng', + 'Bhks', + 'Blis', + 'Bopo', + 'Brah', + 'Brai', + 'Bugi', + 'Buhd', + 'Cakm', + 'Cans', + 'Cari', + 'Cham', + 'Cher', + 'Cirt', + 'Copt', + 'Cprt', + 'Cyrl', + 'Cyrs', + 'Deva', + 'Dogr', + 'Dsrt', + 'Dupl', + 'Egyd', + 'Egyh', + 'Egyp', + 'Elba', + 'Elym', + 'Ethi', + 'Geok', + 'Geor', + 'Glag', + 'Gong', + 'Gonm', + 'Goth', + 'Gran', + 'Grek', + 'Gujr', + 'Guru', + 'Hanb', + 'Hang', + 'Hani', + 'Hano', + 'Hans', + 'Hant', + 'Hatr', + 'Hebr', + 'Hira', + 'Hluw', + 'Hmng', + 'Hmnp', + 'Hrkt', + 'Hung', + 'Inds', + 'Ital', + 'Jamo', + 'Java', + 'Jpan', + 'Jurc', + 'Kali', + 'Kana', + 'Khar', + 'Khmr', + 'Khoj', + 'Knda', + 'Kore', + 'Kpel', + 'Kthi', + 'Lana', + 'Laoo', + 'Latf', + 'Latg', + 'Latn', + 'Lepc', + 'Limb', + 'Lina', + 'Linb', + 'Lisu', + 'Loma', + 'Lyci', + 'Lydi', + 'Mahj', + 'Maka', + 'Mand', + 'Mani', + 'Marc', + 'Maya', + 'Medf', + 'Mend', + 'Merc', + 'Mero', + 'Mlym', + 'Modi', + 'Mong', + 'Moon', + 'Mroo', + 'Mtei', + 'Mult', + 'Mymr', + 'Nand', + 'Narb', + 'Nbat', + 'Newa', + 'Nkgb', + 'Nkoo', + 'Nshu', + 'Ogam', + 'Olck', + 'Orkh', + 'Orya', + 'Osge', + 'Osma', + 'Palm', + 'Pauc', + 'Perm', + 'Phag', + 'Phli', + 'Phlp', + 'Phlv', + 'Phnx', + 'Plrd', + 'Prti', + 'Qaag', + 'Rjng', + 'Rohg', + 'Roro', + 'Runr', + 'Samr', + 'Sara', + 'Sarb', + 'Saur', + 'Sgnw', + 'Shaw', + 'Shrd', + 'Sidd', + 'Sind', + 'Sinh', + 'Sogd', + 'Sogo', + 'Sora', + 'Soyo', + 'Sund', + 'Sylo', + 'Syrc', + 'Syre', + 'Syrj', + 'Syrn', + 'Tagb', + 'Takr', + 'Tale', + 'Talu', + 'Taml', + 'Tang', + 'Tavt', + 'Telu', + 'Teng', + 'Tfng', + 'Tglg', + 'Thaa', + 'Thai', + 'Tibt', + 'Tirh', + 'Ugar', + 'Vaii', + 'Visp', + 'Wara', + 'Wcho', + 'Wole', + 'Xpeo', + 'Xsux', + 'Yiii', + 'Zanb', + 'Zinh', + 'Zmth', + 'Zsye', + 'Zsym', + 'Zxxx', + 'Zyyy', + 'Zzzz', + ]; + + public function testGetScripts() + { + $this->assertSame(self::$scripts, Scripts::getScriptCodes()); + } + + /** + * @dataProvider provideLocales + */ + public function testGetNames($displayLocale) + { + $scripts = array_keys(Scripts::getNames($displayLocale)); + + sort($scripts); + + // We can't assert on exact list of scripts, as there's too many variations between locales. + // The best we can do is to make sure getNames() returns a subset of what getScripts() returns. + $this->assertNotEmpty($scripts); + $this->assertEmpty(array_diff($scripts, self::$scripts)); + } + + public function testGetNamesDefaultLocale() + { + Locale::setDefault('de_AT'); + + $this->assertSame(Scripts::getNames('de_AT'), Scripts::getNames()); + } + + /** + * @dataProvider provideLocaleAliases + */ + public function testGetNamesSupportsAliases($alias, $ofLocale) + { + // Can't use assertSame(), because some aliases contain scripts with + // different collation (=order of output) than their aliased locale + // e.g. sr_Latn_ME => sr_ME + $this->assertEquals(Scripts::getNames($ofLocale), Scripts::getNames($alias)); + } + + /** + * @dataProvider provideLocales + */ + public function testGetName($displayLocale) + { + $names = Scripts::getNames($displayLocale); + + foreach ($names as $script => $name) { + $this->assertSame($name, Scripts::getName($script, $displayLocale)); + } + } + + public function testGetNameDefaultLocale() + { + Locale::setDefault('de_AT'); + + $names = Scripts::getNames('de_AT'); + + foreach ($names as $script => $name) { + $this->assertSame($name, Scripts::getName($script)); + } + } +} diff --git a/src/Symfony/Component/Validator/Constraints/Bic.php b/src/Symfony/Component/Validator/Constraints/Bic.php index c0eeade9a9d48..bd782f4c38934 100644 --- a/src/Symfony/Component/Validator/Constraints/Bic.php +++ b/src/Symfony/Component/Validator/Constraints/Bic.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Regions; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; @@ -47,7 +47,7 @@ class Bic extends Constraint public function __construct($options = null) { - if (!class_exists(Intl::class)) { + if (!class_exists(Regions::class)) { // throw new LogicException(sprintf('The "symfony/intl" component is required to use the "%s" constraint.', __CLASS__)); @trigger_error(sprintf('Using the "%s" constraint without the "symfony/intl" component installed is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED); } diff --git a/src/Symfony/Component/Validator/Constraints/BicValidator.php b/src/Symfony/Component/Validator/Constraints/BicValidator.php index 3036d200e0668..3bbed7bfd0f20 100644 --- a/src/Symfony/Component/Validator/Constraints/BicValidator.php +++ b/src/Symfony/Component/Validator/Constraints/BicValidator.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Regions; use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccessor; @@ -105,8 +105,8 @@ public function validate($value, Constraint $constraint) } // @deprecated since Symfony 4.2, will throw in 5.0 - if (class_exists(Intl::class)) { - $validCountryCode = isset(Intl::getRegionBundle()->getCountryNames()[substr($canonicalize, 4, 2)]); + if (class_exists(Regions::class)) { + $validCountryCode = Regions::exists(substr($canonicalize, 4, 2)); } else { $validCountryCode = ctype_alpha(substr($canonicalize, 4, 2)); // throw new LogicException('The "symfony/intl" component is required to use the Bic constraint.'); diff --git a/src/Symfony/Component/Validator/Constraints/Country.php b/src/Symfony/Component/Validator/Constraints/Country.php index 09e1996d5bcb8..adedb665b6467 100644 --- a/src/Symfony/Component/Validator/Constraints/Country.php +++ b/src/Symfony/Component/Validator/Constraints/Country.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Regions; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Exception\LogicException; @@ -33,7 +33,7 @@ class Country extends Constraint public function __construct($options = null) { - if (!class_exists(Intl::class)) { + if (!class_exists(Regions::class)) { // throw new LogicException(sprintf('The "symfony/intl" component is required to use the "%s" constraint.', __CLASS__)); @trigger_error(sprintf('Using the "%s" constraint without the "symfony/intl" component installed is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED); } diff --git a/src/Symfony/Component/Validator/Constraints/CountryValidator.php b/src/Symfony/Component/Validator/Constraints/CountryValidator.php index ad5dc36a9ab54..057420f7bcbed 100644 --- a/src/Symfony/Component/Validator/Constraints/CountryValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CountryValidator.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Regions; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\LogicException; @@ -42,14 +42,13 @@ public function validate($value, Constraint $constraint) throw new UnexpectedValueException($value, 'string'); } - if (!class_exists(Intl::class)) { + if (!class_exists(Regions::class)) { throw new LogicException('The "symfony/intl" component is required to use the Country constraint.'); } $value = (string) $value; - $countries = Intl::getRegionBundle()->getCountryNames(); - if (!isset($countries[$value])) { + if (!Regions::exists($value)) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) ->setCode(Country::NO_SUCH_COUNTRY_ERROR) diff --git a/src/Symfony/Component/Validator/Constraints/Currency.php b/src/Symfony/Component/Validator/Constraints/Currency.php index 4f9d7d26fc444..73ea29488f561 100644 --- a/src/Symfony/Component/Validator/Constraints/Currency.php +++ b/src/Symfony/Component/Validator/Constraints/Currency.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Currencies; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Exception\LogicException; @@ -34,7 +34,7 @@ class Currency extends Constraint public function __construct($options = null) { - if (!class_exists(Intl::class)) { + if (!class_exists(Currencies::class)) { // throw new LogicException(sprintf('The "symfony/intl" component is required to use the "%s" constraint.', __CLASS__)); @trigger_error(sprintf('Using the "%s" constraint without the "symfony/intl" component installed is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED); } diff --git a/src/Symfony/Component/Validator/Constraints/CurrencyValidator.php b/src/Symfony/Component/Validator/Constraints/CurrencyValidator.php index 44e5df246cb89..cc25aa738e32d 100644 --- a/src/Symfony/Component/Validator/Constraints/CurrencyValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CurrencyValidator.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Currencies; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\LogicException; @@ -43,14 +43,13 @@ public function validate($value, Constraint $constraint) throw new UnexpectedValueException($value, 'string'); } - if (!class_exists(Intl::class)) { + if (!class_exists(Currencies::class)) { throw new LogicException('The "symfony/intl" component is required to use the Currency constraint.'); } $value = (string) $value; - $currencies = Intl::getCurrencyBundle()->getCurrencyNames(); - if (!isset($currencies[$value])) { + if (!Currencies::exists($value)) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) ->setCode(Currency::NO_SUCH_CURRENCY_ERROR) diff --git a/src/Symfony/Component/Validator/Constraints/Language.php b/src/Symfony/Component/Validator/Constraints/Language.php index ce01bba15f09f..47b9389557b50 100644 --- a/src/Symfony/Component/Validator/Constraints/Language.php +++ b/src/Symfony/Component/Validator/Constraints/Language.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Languages; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Exception\LogicException; @@ -33,7 +33,7 @@ class Language extends Constraint public function __construct($options = null) { - if (!class_exists(Intl::class)) { + if (!class_exists(Languages::class)) { // throw new LogicException(sprintf('The "symfony/intl" component is required to use the "%s" constraint.', __CLASS__)); @trigger_error(sprintf('Using the "%s" constraint without the "symfony/intl" component installed is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED); } diff --git a/src/Symfony/Component/Validator/Constraints/LanguageValidator.php b/src/Symfony/Component/Validator/Constraints/LanguageValidator.php index 22ddb0fe53459..b193ceda84107 100644 --- a/src/Symfony/Component/Validator/Constraints/LanguageValidator.php +++ b/src/Symfony/Component/Validator/Constraints/LanguageValidator.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Languages; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\LogicException; @@ -42,14 +42,13 @@ public function validate($value, Constraint $constraint) throw new UnexpectedValueException($value, 'string'); } - if (!class_exists(Intl::class)) { + if (!class_exists(Languages::class)) { throw new LogicException('The "symfony/intl" component is required to use the Language constraint.'); } $value = (string) $value; - $languages = Intl::getLanguageBundle()->getLanguageNames(); - if (!isset($languages[$value])) { + if (!Languages::exists($value)) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) ->setCode(Language::NO_SUCH_LANGUAGE_ERROR) diff --git a/src/Symfony/Component/Validator/Constraints/Locale.php b/src/Symfony/Component/Validator/Constraints/Locale.php index 0e4ccf69ce319..d56db7cf212f7 100644 --- a/src/Symfony/Component/Validator/Constraints/Locale.php +++ b/src/Symfony/Component/Validator/Constraints/Locale.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Locales; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Exception\LogicException; @@ -38,7 +38,7 @@ public function __construct($options = null) @trigger_error('The "canonicalize" option with value "false" is deprecated since Symfony 4.1, set it to "true" instead.', E_USER_DEPRECATED); } - if (!class_exists(Intl::class)) { + if (!class_exists(Locales::class)) { // throw new LogicException(sprintf('The "symfony/intl" component is required to use the "%s" constraint.', __CLASS__)); @trigger_error(sprintf('Using the "%s" constraint without the "symfony/intl" component installed is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED); } diff --git a/src/Symfony/Component/Validator/Constraints/LocaleValidator.php b/src/Symfony/Component/Validator/Constraints/LocaleValidator.php index d4bca35a70375..244d0f554ba09 100644 --- a/src/Symfony/Component/Validator/Constraints/LocaleValidator.php +++ b/src/Symfony/Component/Validator/Constraints/LocaleValidator.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator\Constraints; use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Locales; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; @@ -46,10 +47,8 @@ public function validate($value, Constraint $constraint) if ($constraint->canonicalize) { $value = \Locale::canonicalize($value); } - $localeBundle = Intl::getLocaleBundle(); - $locales = $localeBundle->getLocaleNames(); - if (!isset($locales[$value]) && !\in_array($value, $localeBundle->getAliases(), true)) { + if (!Locales::exists($value) && !\in_array($value, Locales::getAliases(), true)) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($inputValue)) ->setCode(Locale::NO_SUCH_LOCALE_ERROR) diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json index 9813a88563afc..b6eae402a8009 100644 --- a/src/Symfony/Component/Validator/composer.json +++ b/src/Symfony/Component/Validator/composer.json @@ -26,7 +26,7 @@ "symfony/http-foundation": "~4.1", "symfony/http-kernel": "~3.4|~4.0", "symfony/var-dumper": "~3.4|~4.0", - "symfony/intl": "~4.1", + "symfony/intl": "^4.3", "symfony/yaml": "~3.4|~4.0", "symfony/config": "~3.4|~4.0", "symfony/dependency-injection": "~3.4|~4.0", @@ -43,7 +43,7 @@ "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", "symfony/dependency-injection": "<3.4", "symfony/http-kernel": "<3.4", - "symfony/intl": "<4.1", + "symfony/intl": "<4.3", "symfony/translation": "<4.2", "symfony/yaml": "<3.4" }, pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy