diff --git a/src/Symfony/Component/Intl/CHANGELOG.md b/src/Symfony/Component/Intl/CHANGELOG.md index 88b9a2c070..657e6adb43 100644 --- a/src/Symfony/Component/Intl/CHANGELOG.md +++ b/src/Symfony/Component/Intl/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG ----- * excluded language code `root` + * added to both `Countries` and `Languages` the methods `getAlpha3Codes`, `getAlpha3Code`, `getAlpha2Code`, `alpha3CodeExists`, `getAlpha3Name` and `getAlpha3Names` 4.3.0 ----- diff --git a/src/Symfony/Component/Intl/Countries.php b/src/Symfony/Component/Intl/Countries.php index 07812f5131..f3fae27c20 100644 --- a/src/Symfony/Component/Intl/Countries.php +++ b/src/Symfony/Component/Intl/Countries.php @@ -39,12 +39,44 @@ final class Countries extends ResourceBundle } /** - * @param string $country Alpha2 country code + * Returns all available countries (3 letters). + * + * Countries are returned as uppercase ISO 3166 three-letter country codes. + * + * This list only contains "officially assigned ISO 3166-1 alpha-3" country codes. + * + * @return string[] an array of canonical ISO 3166 alpha-3 country codes */ - public static function exists(string $country): bool + public static function getAlpha3Codes(): array + { + return self::readEntry(['Alpha2ToAlpha3'], 'meta'); + } + + public static function getAlpha3Code(string $alpha2Code): string + { + return self::readEntry(['Alpha2ToAlpha3', $alpha2Code], 'meta'); + } + + public static function getAlpha2Code(string $alpha3Code): string + { + return self::readEntry(['Alpha3ToAlpha2', $alpha3Code], 'meta'); + } + + public static function exists(string $alpha2Code): bool { try { - self::readEntry(['Names', $country]); + self::readEntry(['Names', $alpha2Code]); + + return true; + } catch (MissingResourceException $e) { + return false; + } + } + + public static function alpha3CodeExists(string $alpha3Code): bool + { + try { + self::getAlpha2Code($alpha3Code); return true; } catch (MissingResourceException $e) { @@ -53,15 +85,25 @@ final class Countries extends ResourceBundle } /** - * Gets the country name from alpha2 code. + * Gets the country name from its alpha2 code. * - * @throws MissingResourceException if the country code does not exists + * @throws MissingResourceException if the country code does not exist */ public static function getName(string $country, string $displayLocale = null): string { return self::readEntry(['Names', $country], $displayLocale); } + /** + * Gets the country name from its alpha3 code. + * + * @throws MissingResourceException if the country code does not exist + */ + public static function getAlpha3Name(string $alpha3Code, string $displayLocale = null): string + { + return self::getName(self::getAlpha2Code($alpha3Code), $displayLocale); + } + /** * Gets the list of country names indexed with alpha2 codes as keys. * @@ -72,6 +114,24 @@ final class Countries extends ResourceBundle return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale); } + /** + * Gets the list of country names indexed with alpha3 codes as keys. + * + * Same as method getNames, but with alpha3 codes instead of alpha2 codes as keys. + * + * @return string[] + */ + public static function getAlpha3Names($displayLocale = null): array + { + $alpha2Names = self::getNames($displayLocale); + $alpha3Names = []; + foreach ($alpha2Names as $alpha2Code => $name) { + $alpha3Names[self::getAlpha3Code($alpha2Code)] = $name; + } + + return $alpha3Names; + } + protected static function getPath(): string { return Intl::getDataDirectory().'/'.Intl::REGION_DIR; diff --git a/src/Symfony/Component/Intl/Data/Generator/LanguageDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/LanguageDataGenerator.php index 0f0f44538d..9bd666b06f 100644 --- a/src/Symfony/Component/Intl/Data/Generator/LanguageDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/LanguageDataGenerator.php @@ -162,11 +162,16 @@ class LanguageDataGenerator extends AbstractDataGenerator sort($this->languageCodes); + $alpha2ToAlpha3 = $this->generateAlpha2ToAlpha3Mapping($metadataBundle); + $alpha3ToAlpha2 = array_flip($alpha2ToAlpha3); + asort($alpha3ToAlpha2); + return [ 'Version' => $rootBundle['Version'], 'Languages' => $this->languageCodes, 'Aliases' => array_column(iterator_to_array($metadataBundle['alias']['language']), 'replacement'), - 'Alpha2ToAlpha3' => $this->generateAlpha2ToAlpha3Mapping($metadataBundle), + 'Alpha2ToAlpha3' => $alpha2ToAlpha3, + 'Alpha3ToAlpha2' => $alpha3ToAlpha2, ]; } diff --git a/src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php index 7430ba5bf5..842b70eec2 100644 --- a/src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php @@ -27,6 +27,17 @@ use Symfony\Component\Intl\Data\Util\LocaleScanner; */ class RegionDataGenerator extends AbstractDataGenerator { + /** + * Source https://www.iso.org/obp/ui/#iso:pub:PUB500001:en + */ + private static $preferredAlpha2ToAlpha3Mapping = [ + 'DE' => 'DEU', + 'FR' => 'FRA', + 'MM' => 'MMR', + 'TL' => 'TLS', + 'YE' => 'YEM', + ]; + private static $blacklist = [ // Exceptional reservations 'AC' => true, // Ascension Island @@ -82,6 +93,7 @@ class RegionDataGenerator extends AbstractDataGenerator protected function compileTemporaryBundles(BundleCompilerInterface $compiler, $sourceDir, $tempDir) { $compiler->compile($sourceDir.'/region', $tempDir); + $compiler->compile($sourceDir.'/misc/metadata.txt', $tempDir); } /** @@ -125,14 +137,25 @@ class RegionDataGenerator extends AbstractDataGenerator protected function generateDataForMeta(BundleEntryReaderInterface $reader, $tempDir) { $rootBundle = $reader->read($tempDir, 'root'); + $metadataBundle = $reader->read($tempDir, 'metadata'); $this->regionCodes = array_unique($this->regionCodes); + $alpha2ToAlpha3 = $this->generateAlpha3($metadataBundle); + sort($this->regionCodes); + $alpha3ToAlpha2 = []; + foreach ($this->regionCodes as $alpha2Code) { + $alpha3code = $alpha2ToAlpha3[$alpha2Code]; + $alpha3ToAlpha2[$alpha3code] = $alpha2Code; + } + return [ 'Version' => $rootBundle['Version'], 'Regions' => $this->regionCodes, + 'Alpha2ToAlpha3' => $alpha2ToAlpha3, + 'Alpha3ToAlpha2' => $alpha3ToAlpha2, ]; } @@ -154,4 +177,38 @@ class RegionDataGenerator extends AbstractDataGenerator return $regionNames; } + + protected function generateAlpha3(ArrayAccessibleResourceBundle $metadataBundle) + { + $alpha2Codes = array_flip($this->regionCodes); + $alpha2ToAlpha3 = []; + foreach ($metadataBundle['alias']['territory'] as $alias => $data) { + if (3 !== \strlen($alias) || 'overlong' !== $data['reason'] || ctype_digit($alias)) { + continue; + } + + $alpha2Code = $data['replacement']; + if (!isset($alpha2Codes[$alpha2Code])) { + continue; + } + + if (!isset($alpha2ToAlpha3[$alpha2Code])) { + $alpha2ToAlpha3[$alpha2Code] = $alias; + continue; + } + + // Found a second alias for the same country + if (isset(self::$preferredAlpha2ToAlpha3Mapping[$alpha2Code])) { + $preferred = self::$preferredAlpha2ToAlpha3Mapping[$alpha2Code]; + // Only use the preferred mapping if it actually is in the mapping + if ($alias === $preferred) { + $alpha2ToAlpha3[$alpha2Code] = $preferred; + } + } + } + + asort($alpha2ToAlpha3); + + return $alpha2ToAlpha3; + } } diff --git a/src/Symfony/Component/Intl/Languages.php b/src/Symfony/Component/Intl/Languages.php index a70a7e8b9c..437295b821 100644 --- a/src/Symfony/Component/Intl/Languages.php +++ b/src/Symfony/Component/Intl/Languages.php @@ -50,9 +50,9 @@ final class Languages extends ResourceBundle } /** - * Gets the language name from alpha2 code. + * Gets the language name from its alpha2 code. * - * @throws MissingResourceException if the language code does not exists + * @throws MissingResourceException if the language code does not exist */ public static function getName(string $language, string $displayLocale = null): string { @@ -79,6 +79,73 @@ final class Languages extends ResourceBundle return self::readEntry(['Alpha2ToAlpha3', $language], 'meta'); } + /** + * Returns the ISO 639-1 two-letter code of a language, given a three letter code. + * + * @throws MissingResourceException if the language has no corresponding three-letter code + */ + public static function getAlpha2Code(string $language): string + { + return self::readEntry(['Alpha3ToAlpha2', $language], 'meta'); + } + + /** + * Returns all available languages as three-letter codes. + * + * Languages are returned as lowercase ISO 639-2 three-letter language codes. + * + * @return string[] an array of canonical ISO 639-2 language codes + */ + public static function getAlpha3Codes(): array + { + return self::readEntry(['Alpha2ToAlpha3'], 'meta'); + } + + /** + * @param string $language ISO 639-2 three-letter language code + */ + public static function alpha3CodeExists(string $language): bool + { + try { + self::getAlpha2Code($language); + + return true; + } catch (MissingResourceException $e) { + return false; + } + } + + /** + * Gets the language name from its ISO 639-2 three-letter code. + * + * @throws MissingResourceException if the country code does not exists + */ + public static function getAlpha3Name(string $language, string $displayLocale = null): string + { + return self::getName(self::getAlpha2Code($language), $displayLocale); + } + + /** + * Gets the list of language names indexed with ISO 639-2 three-letter codes as keys. + * + * Same as method getNames, but with ISO 639-2 three-letter codes instead of ISO 639-1 codes as keys. + * + * @return string[] + */ + public static function getAlpha3Names($displayLocale = null): array + { + $alpha2Names = self::getNames($displayLocale); + $alpha3Names = []; + foreach ($alpha2Names as $alpha2Code => $name) { + try { + $alpha3Names[self::getAlpha3Code($alpha2Code)] = $name; + } catch (MissingResourceException $e) { + } + } + + return $alpha3Names; + } + protected static function getPath(): string { return Intl::getDataDirectory().'/'.Intl::LANGUAGE_DIR; diff --git a/src/Symfony/Component/Intl/Resources/data/languages/meta.json b/src/Symfony/Component/Intl/Resources/data/languages/meta.json index e820b722e7..dadb22560a 100644 --- a/src/Symfony/Component/Intl/Resources/data/languages/meta.json +++ b/src/Symfony/Component/Intl/Resources/data/languages/meta.json @@ -800,5 +800,187 @@ "za": "zha", "zh": "zho", "zu": "zul" + }, + "Alpha3ToAlpha2": { + "aar": "aa", + "abk": "ab", + "ave": "ae", + "afr": "af", + "aka": "ak", + "amh": "am", + "arg": "an", + "ara": "ar", + "asm": "as", + "ava": "av", + "aym": "ay", + "aze": "az", + "bak": "ba", + "bel": "be", + "bul": "bg", + "bis": "bi", + "bam": "bm", + "ben": "bn", + "bod": "bo", + "bre": "br", + "bos": "bs", + "cat": "ca", + "che": "ce", + "cha": "ch", + "cos": "co", + "cre": "cr", + "ces": "cs", + "chu": "cu", + "chv": "cv", + "cym": "cy", + "dan": "da", + "deu": "de", + "div": "dv", + "dzo": "dz", + "ewe": "ee", + "ell": "el", + "eng": "en", + "epo": "eo", + "spa": "es", + "est": "et", + "eus": "eu", + "fas": "fa", + "ful": "ff", + "fin": "fi", + "fij": "fj", + "fao": "fo", + "fra": "fr", + "fry": "fy", + "gle": "ga", + "gla": "gd", + "glg": "gl", + "grn": "gn", + "guj": "gu", + "glv": "gv", + "hau": "ha", + "heb": "he", + "hin": "hi", + "hmo": "ho", + "hrv": "hr", + "hat": "ht", + "hun": "hu", + "hye": "hy", + "her": "hz", + "ina": "ia", + "ind": "id", + "ile": "ie", + "ibo": "ig", + "iii": "ii", + "ipk": "ik", + "ido": "io", + "isl": "is", + "ita": "it", + "iku": "iu", + "jpn": "ja", + "jav": "jv", + "kat": "ka", + "kon": "kg", + "kik": "ki", + "kua": "kj", + "kaz": "kk", + "kal": "kl", + "khm": "km", + "kan": "kn", + "kor": "ko", + "kau": "kr", + "kas": "ks", + "kur": "ku", + "kom": "kv", + "cor": "kw", + "kir": "ky", + "lat": "la", + "ltz": "lb", + "lug": "lg", + "lim": "li", + "lin": "ln", + "lao": "lo", + "lit": "lt", + "lub": "lu", + "lav": "lv", + "mlg": "mg", + "mah": "mh", + "mri": "mi", + "mkd": "mk", + "mal": "ml", + "mon": "mn", + "mar": "mr", + "msa": "ms", + "mlt": "mt", + "mya": "my", + "nau": "na", + "nob": "nb", + "nde": "nd", + "nep": "ne", + "ndo": "ng", + "nld": "nl", + "nno": "nn", + "nbl": "nr", + "nav": "nv", + "nya": "ny", + "oci": "oc", + "oji": "oj", + "orm": "om", + "ori": "or", + "oss": "os", + "pan": "pa", + "pli": "pi", + "pol": "pl", + "pus": "ps", + "por": "pt", + "que": "qu", + "roh": "rm", + "run": "rn", + "ron": "ro", + "rus": "ru", + "kin": "rw", + "san": "sa", + "srd": "sc", + "snd": "sd", + "sme": "se", + "sag": "sg", + "sin": "si", + "slk": "sk", + "slv": "sl", + "smo": "sm", + "sna": "sn", + "som": "so", + "sqi": "sq", + "srp": "sr", + "ssw": "ss", + "sot": "st", + "sun": "su", + "swe": "sv", + "swa": "sw", + "tam": "ta", + "tel": "te", + "tgk": "tg", + "tha": "th", + "tir": "ti", + "tuk": "tk", + "tsn": "tn", + "ton": "to", + "tur": "tr", + "tso": "ts", + "tat": "tt", + "tah": "ty", + "uig": "ug", + "ukr": "uk", + "urd": "ur", + "uzb": "uz", + "ven": "ve", + "vie": "vi", + "vol": "vo", + "wln": "wa", + "wol": "wo", + "xho": "xh", + "yid": "yi", + "yor": "yo", + "zha": "za", + "zho": "zh", + "zul": "zu" } } diff --git a/src/Symfony/Component/Intl/Resources/data/regions/meta.json b/src/Symfony/Component/Intl/Resources/data/regions/meta.json index f6e9554df9..98afda08de 100644 --- a/src/Symfony/Component/Intl/Resources/data/regions/meta.json +++ b/src/Symfony/Component/Intl/Resources/data/regions/meta.json @@ -250,5 +250,507 @@ "ZA", "ZM", "ZW" - ] + ], + "Alpha2ToAlpha3": { + "AW": "ABW", + "AF": "AFG", + "AO": "AGO", + "AI": "AIA", + "AX": "ALA", + "AL": "ALB", + "AD": "AND", + "AE": "ARE", + "AR": "ARG", + "AM": "ARM", + "AS": "ASM", + "AQ": "ATA", + "TF": "ATF", + "AG": "ATG", + "AU": "AUS", + "AT": "AUT", + "AZ": "AZE", + "BI": "BDI", + "BE": "BEL", + "BJ": "BEN", + "BQ": "BES", + "BF": "BFA", + "BD": "BGD", + "BG": "BGR", + "BH": "BHR", + "BS": "BHS", + "BA": "BIH", + "BL": "BLM", + "BY": "BLR", + "BZ": "BLZ", + "BM": "BMU", + "BO": "BOL", + "BR": "BRA", + "BB": "BRB", + "BN": "BRN", + "BT": "BTN", + "BV": "BVT", + "BW": "BWA", + "CF": "CAF", + "CA": "CAN", + "CC": "CCK", + "CH": "CHE", + "CL": "CHL", + "CN": "CHN", + "CI": "CIV", + "CM": "CMR", + "CD": "COD", + "CG": "COG", + "CK": "COK", + "CO": "COL", + "KM": "COM", + "CV": "CPV", + "CR": "CRI", + "CU": "CUB", + "CW": "CUW", + "CX": "CXR", + "KY": "CYM", + "CY": "CYP", + "CZ": "CZE", + "DE": "DEU", + "DJ": "DJI", + "DM": "DMA", + "DK": "DNK", + "DO": "DOM", + "DZ": "DZA", + "EC": "ECU", + "EG": "EGY", + "ER": "ERI", + "EH": "ESH", + "ES": "ESP", + "EE": "EST", + "ET": "ETH", + "FI": "FIN", + "FJ": "FJI", + "FK": "FLK", + "FR": "FRA", + "FO": "FRO", + "FM": "FSM", + "GA": "GAB", + "GB": "GBR", + "GE": "GEO", + "GG": "GGY", + "GH": "GHA", + "GI": "GIB", + "GN": "GIN", + "GP": "GLP", + "GM": "GMB", + "GW": "GNB", + "GQ": "GNQ", + "GR": "GRC", + "GD": "GRD", + "GL": "GRL", + "GT": "GTM", + "GF": "GUF", + "GU": "GUM", + "GY": "GUY", + "HK": "HKG", + "HM": "HMD", + "HN": "HND", + "HR": "HRV", + "HT": "HTI", + "HU": "HUN", + "ID": "IDN", + "IM": "IMN", + "IN": "IND", + "IO": "IOT", + "IE": "IRL", + "IR": "IRN", + "IQ": "IRQ", + "IS": "ISL", + "IL": "ISR", + "IT": "ITA", + "JM": "JAM", + "JE": "JEY", + "JO": "JOR", + "JP": "JPN", + "KZ": "KAZ", + "KE": "KEN", + "KG": "KGZ", + "KH": "KHM", + "KI": "KIR", + "KN": "KNA", + "KR": "KOR", + "KW": "KWT", + "LA": "LAO", + "LB": "LBN", + "LR": "LBR", + "LY": "LBY", + "LC": "LCA", + "LI": "LIE", + "LK": "LKA", + "LS": "LSO", + "LT": "LTU", + "LU": "LUX", + "LV": "LVA", + "MO": "MAC", + "MF": "MAF", + "MA": "MAR", + "MC": "MCO", + "MD": "MDA", + "MG": "MDG", + "MV": "MDV", + "MX": "MEX", + "MH": "MHL", + "MK": "MKD", + "ML": "MLI", + "MT": "MLT", + "MM": "MMR", + "ME": "MNE", + "MN": "MNG", + "MP": "MNP", + "MZ": "MOZ", + "MR": "MRT", + "MS": "MSR", + "MQ": "MTQ", + "MU": "MUS", + "MW": "MWI", + "MY": "MYS", + "YT": "MYT", + "NA": "NAM", + "NC": "NCL", + "NE": "NER", + "NF": "NFK", + "NG": "NGA", + "NI": "NIC", + "NU": "NIU", + "NL": "NLD", + "NO": "NOR", + "NP": "NPL", + "NR": "NRU", + "NZ": "NZL", + "OM": "OMN", + "PK": "PAK", + "PA": "PAN", + "PN": "PCN", + "PE": "PER", + "PH": "PHL", + "PW": "PLW", + "PG": "PNG", + "PL": "POL", + "PR": "PRI", + "KP": "PRK", + "PT": "PRT", + "PY": "PRY", + "PS": "PSE", + "PF": "PYF", + "QA": "QAT", + "RE": "REU", + "RO": "ROU", + "RU": "RUS", + "RW": "RWA", + "SA": "SAU", + "SD": "SDN", + "SN": "SEN", + "SG": "SGP", + "GS": "SGS", + "SH": "SHN", + "SJ": "SJM", + "SB": "SLB", + "SL": "SLE", + "SV": "SLV", + "SM": "SMR", + "SO": "SOM", + "PM": "SPM", + "RS": "SRB", + "SS": "SSD", + "ST": "STP", + "SR": "SUR", + "SK": "SVK", + "SI": "SVN", + "SE": "SWE", + "SZ": "SWZ", + "SX": "SXM", + "SC": "SYC", + "SY": "SYR", + "TC": "TCA", + "TD": "TCD", + "TG": "TGO", + "TH": "THA", + "TJ": "TJK", + "TK": "TKL", + "TM": "TKM", + "TL": "TLS", + "TO": "TON", + "TT": "TTO", + "TN": "TUN", + "TR": "TUR", + "TV": "TUV", + "TW": "TWN", + "TZ": "TZA", + "UG": "UGA", + "UA": "UKR", + "UM": "UMI", + "UY": "URY", + "US": "USA", + "UZ": "UZB", + "VA": "VAT", + "VC": "VCT", + "VE": "VEN", + "VG": "VGB", + "VI": "VIR", + "VN": "VNM", + "VU": "VUT", + "WF": "WLF", + "WS": "WSM", + "YE": "YEM", + "ZA": "ZAF", + "ZM": "ZMB", + "ZW": "ZWE" + }, + "Alpha3ToAlpha2": { + "AND": "AD", + "ARE": "AE", + "AFG": "AF", + "ATG": "AG", + "AIA": "AI", + "ALB": "AL", + "ARM": "AM", + "AGO": "AO", + "ATA": "AQ", + "ARG": "AR", + "ASM": "AS", + "AUT": "AT", + "AUS": "AU", + "ABW": "AW", + "ALA": "AX", + "AZE": "AZ", + "BIH": "BA", + "BRB": "BB", + "BGD": "BD", + "BEL": "BE", + "BFA": "BF", + "BGR": "BG", + "BHR": "BH", + "BDI": "BI", + "BEN": "BJ", + "BLM": "BL", + "BMU": "BM", + "BRN": "BN", + "BOL": "BO", + "BES": "BQ", + "BRA": "BR", + "BHS": "BS", + "BTN": "BT", + "BVT": "BV", + "BWA": "BW", + "BLR": "BY", + "BLZ": "BZ", + "CAN": "CA", + "CCK": "CC", + "COD": "CD", + "CAF": "CF", + "COG": "CG", + "CHE": "CH", + "CIV": "CI", + "COK": "CK", + "CHL": "CL", + "CMR": "CM", + "CHN": "CN", + "COL": "CO", + "CRI": "CR", + "CUB": "CU", + "CPV": "CV", + "CUW": "CW", + "CXR": "CX", + "CYP": "CY", + "CZE": "CZ", + "DEU": "DE", + "DJI": "DJ", + "DNK": "DK", + "DMA": "DM", + "DOM": "DO", + "DZA": "DZ", + "ECU": "EC", + "EST": "EE", + "EGY": "EG", + "ESH": "EH", + "ERI": "ER", + "ESP": "ES", + "ETH": "ET", + "FIN": "FI", + "FJI": "FJ", + "FLK": "FK", + "FSM": "FM", + "FRO": "FO", + "FRA": "FR", + "GAB": "GA", + "GBR": "GB", + "GRD": "GD", + "GEO": "GE", + "GUF": "GF", + "GGY": "GG", + "GHA": "GH", + "GIB": "GI", + "GRL": "GL", + "GMB": "GM", + "GIN": "GN", + "GLP": "GP", + "GNQ": "GQ", + "GRC": "GR", + "SGS": "GS", + "GTM": "GT", + "GUM": "GU", + "GNB": "GW", + "GUY": "GY", + "HKG": "HK", + "HMD": "HM", + "HND": "HN", + "HRV": "HR", + "HTI": "HT", + "HUN": "HU", + "IDN": "ID", + "IRL": "IE", + "ISR": "IL", + "IMN": "IM", + "IND": "IN", + "IOT": "IO", + "IRQ": "IQ", + "IRN": "IR", + "ISL": "IS", + "ITA": "IT", + "JEY": "JE", + "JAM": "JM", + "JOR": "JO", + "JPN": "JP", + "KEN": "KE", + "KGZ": "KG", + "KHM": "KH", + "KIR": "KI", + "COM": "KM", + "KNA": "KN", + "PRK": "KP", + "KOR": "KR", + "KWT": "KW", + "CYM": "KY", + "KAZ": "KZ", + "LAO": "LA", + "LBN": "LB", + "LCA": "LC", + "LIE": "LI", + "LKA": "LK", + "LBR": "LR", + "LSO": "LS", + "LTU": "LT", + "LUX": "LU", + "LVA": "LV", + "LBY": "LY", + "MAR": "MA", + "MCO": "MC", + "MDA": "MD", + "MNE": "ME", + "MAF": "MF", + "MDG": "MG", + "MHL": "MH", + "MKD": "MK", + "MLI": "ML", + "MMR": "MM", + "MNG": "MN", + "MAC": "MO", + "MNP": "MP", + "MTQ": "MQ", + "MRT": "MR", + "MSR": "MS", + "MLT": "MT", + "MUS": "MU", + "MDV": "MV", + "MWI": "MW", + "MEX": "MX", + "MYS": "MY", + "MOZ": "MZ", + "NAM": "NA", + "NCL": "NC", + "NER": "NE", + "NFK": "NF", + "NGA": "NG", + "NIC": "NI", + "NLD": "NL", + "NOR": "NO", + "NPL": "NP", + "NRU": "NR", + "NIU": "NU", + "NZL": "NZ", + "OMN": "OM", + "PAN": "PA", + "PER": "PE", + "PYF": "PF", + "PNG": "PG", + "PHL": "PH", + "PAK": "PK", + "POL": "PL", + "SPM": "PM", + "PCN": "PN", + "PRI": "PR", + "PSE": "PS", + "PRT": "PT", + "PLW": "PW", + "PRY": "PY", + "QAT": "QA", + "REU": "RE", + "ROU": "RO", + "SRB": "RS", + "RUS": "RU", + "RWA": "RW", + "SAU": "SA", + "SLB": "SB", + "SYC": "SC", + "SDN": "SD", + "SWE": "SE", + "SGP": "SG", + "SHN": "SH", + "SVN": "SI", + "SJM": "SJ", + "SVK": "SK", + "SLE": "SL", + "SMR": "SM", + "SEN": "SN", + "SOM": "SO", + "SUR": "SR", + "SSD": "SS", + "STP": "ST", + "SLV": "SV", + "SXM": "SX", + "SYR": "SY", + "SWZ": "SZ", + "TCA": "TC", + "TCD": "TD", + "ATF": "TF", + "TGO": "TG", + "THA": "TH", + "TJK": "TJ", + "TKL": "TK", + "TLS": "TL", + "TKM": "TM", + "TUN": "TN", + "TON": "TO", + "TUR": "TR", + "TTO": "TT", + "TUV": "TV", + "TWN": "TW", + "TZA": "TZ", + "UKR": "UA", + "UGA": "UG", + "UMI": "UM", + "USA": "US", + "URY": "UY", + "UZB": "UZ", + "VAT": "VA", + "VCT": "VC", + "VEN": "VE", + "VGB": "VG", + "VIR": "VI", + "VNM": "VN", + "VUT": "VU", + "WLF": "WF", + "WSM": "WS", + "YEM": "YE", + "MYT": "YT", + "ZAF": "ZA", + "ZMB": "ZM", + "ZWE": "ZW" + } } diff --git a/src/Symfony/Component/Intl/Tests/CountriesTest.php b/src/Symfony/Component/Intl/Tests/CountriesTest.php index fec90d3fde..c8aab74494 100644 --- a/src/Symfony/Component/Intl/Tests/CountriesTest.php +++ b/src/Symfony/Component/Intl/Tests/CountriesTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Intl\Tests; use Symfony\Component\Intl\Countries; +use Symfony\Component\Intl\Exception\MissingResourceException; /** * @group intl-data @@ -272,6 +273,258 @@ class CountriesTest extends ResourceBundleTestCase 'ZW', ]; + private static $alpha2ToAlpha3 = [ + 'AW' => 'ABW', + 'AF' => 'AFG', + 'AO' => 'AGO', + 'AI' => 'AIA', + 'AX' => 'ALA', + 'AL' => 'ALB', + 'AD' => 'AND', + 'AE' => 'ARE', + 'AR' => 'ARG', + 'AM' => 'ARM', + 'AS' => 'ASM', + 'AQ' => 'ATA', + 'TF' => 'ATF', + 'AG' => 'ATG', + 'AU' => 'AUS', + 'AT' => 'AUT', + 'AZ' => 'AZE', + 'BI' => 'BDI', + 'BE' => 'BEL', + 'BJ' => 'BEN', + 'BQ' => 'BES', + 'BF' => 'BFA', + 'BD' => 'BGD', + 'BG' => 'BGR', + 'BH' => 'BHR', + 'BS' => 'BHS', + 'BA' => 'BIH', + 'BL' => 'BLM', + 'BY' => 'BLR', + 'BZ' => 'BLZ', + 'BM' => 'BMU', + 'BO' => 'BOL', + 'BR' => 'BRA', + 'BB' => 'BRB', + 'BN' => 'BRN', + 'BT' => 'BTN', + 'BV' => 'BVT', + 'BW' => 'BWA', + 'CF' => 'CAF', + 'CA' => 'CAN', + 'CC' => 'CCK', + 'CH' => 'CHE', + 'CL' => 'CHL', + 'CN' => 'CHN', + 'CI' => 'CIV', + 'CM' => 'CMR', + 'CD' => 'COD', + 'CG' => 'COG', + 'CK' => 'COK', + 'CO' => 'COL', + 'KM' => 'COM', + 'CV' => 'CPV', + 'CR' => 'CRI', + 'CU' => 'CUB', + 'CW' => 'CUW', + 'CX' => 'CXR', + 'KY' => 'CYM', + 'CY' => 'CYP', + 'CZ' => 'CZE', + 'DE' => 'DEU', + 'DJ' => 'DJI', + 'DM' => 'DMA', + 'DK' => 'DNK', + 'DO' => 'DOM', + 'DZ' => 'DZA', + 'EC' => 'ECU', + 'EG' => 'EGY', + 'ER' => 'ERI', + 'EH' => 'ESH', + 'ES' => 'ESP', + 'EE' => 'EST', + 'ET' => 'ETH', + 'FI' => 'FIN', + 'FJ' => 'FJI', + 'FK' => 'FLK', + 'FR' => 'FRA', + 'FO' => 'FRO', + 'FM' => 'FSM', + 'GA' => 'GAB', + 'GB' => 'GBR', + 'GE' => 'GEO', + 'GG' => 'GGY', + 'GH' => 'GHA', + 'GI' => 'GIB', + 'GN' => 'GIN', + 'GP' => 'GLP', + 'GM' => 'GMB', + 'GW' => 'GNB', + 'GQ' => 'GNQ', + 'GR' => 'GRC', + 'GD' => 'GRD', + 'GL' => 'GRL', + 'GT' => 'GTM', + 'GF' => 'GUF', + 'GU' => 'GUM', + 'GY' => 'GUY', + 'HK' => 'HKG', + 'HM' => 'HMD', + 'HN' => 'HND', + 'HR' => 'HRV', + 'HT' => 'HTI', + 'HU' => 'HUN', + 'ID' => 'IDN', + 'IM' => 'IMN', + 'IN' => 'IND', + 'IO' => 'IOT', + 'IE' => 'IRL', + 'IR' => 'IRN', + 'IQ' => 'IRQ', + 'IS' => 'ISL', + 'IL' => 'ISR', + 'IT' => 'ITA', + 'JM' => 'JAM', + 'JE' => 'JEY', + 'JO' => 'JOR', + 'JP' => 'JPN', + 'KZ' => 'KAZ', + 'KE' => 'KEN', + 'KG' => 'KGZ', + 'KH' => 'KHM', + 'KI' => 'KIR', + 'KN' => 'KNA', + 'KR' => 'KOR', + 'KW' => 'KWT', + 'LA' => 'LAO', + 'LB' => 'LBN', + 'LR' => 'LBR', + 'LY' => 'LBY', + 'LC' => 'LCA', + 'LI' => 'LIE', + 'LK' => 'LKA', + 'LS' => 'LSO', + 'LT' => 'LTU', + 'LU' => 'LUX', + 'LV' => 'LVA', + 'MO' => 'MAC', + 'MF' => 'MAF', + 'MA' => 'MAR', + 'MC' => 'MCO', + 'MD' => 'MDA', + 'MG' => 'MDG', + 'MV' => 'MDV', + 'MX' => 'MEX', + 'MH' => 'MHL', + 'MK' => 'MKD', + 'ML' => 'MLI', + 'MT' => 'MLT', + 'MM' => 'MMR', + 'ME' => 'MNE', + 'MN' => 'MNG', + 'MP' => 'MNP', + 'MZ' => 'MOZ', + 'MR' => 'MRT', + 'MS' => 'MSR', + 'MQ' => 'MTQ', + 'MU' => 'MUS', + 'MW' => 'MWI', + 'MY' => 'MYS', + 'YT' => 'MYT', + 'NA' => 'NAM', + 'NC' => 'NCL', + 'NE' => 'NER', + 'NF' => 'NFK', + 'NG' => 'NGA', + 'NI' => 'NIC', + 'NU' => 'NIU', + 'NL' => 'NLD', + 'NO' => 'NOR', + 'NP' => 'NPL', + 'NR' => 'NRU', + 'NZ' => 'NZL', + 'OM' => 'OMN', + 'PK' => 'PAK', + 'PA' => 'PAN', + 'PN' => 'PCN', + 'PE' => 'PER', + 'PH' => 'PHL', + 'PW' => 'PLW', + 'PG' => 'PNG', + 'PL' => 'POL', + 'PR' => 'PRI', + 'KP' => 'PRK', + 'PT' => 'PRT', + 'PY' => 'PRY', + 'PS' => 'PSE', + 'PF' => 'PYF', + 'QA' => 'QAT', + 'RE' => 'REU', + 'RO' => 'ROU', + 'RU' => 'RUS', + 'RW' => 'RWA', + 'SA' => 'SAU', + 'SD' => 'SDN', + 'SN' => 'SEN', + 'SG' => 'SGP', + 'GS' => 'SGS', + 'SH' => 'SHN', + 'SJ' => 'SJM', + 'SB' => 'SLB', + 'SL' => 'SLE', + 'SV' => 'SLV', + 'SM' => 'SMR', + 'SO' => 'SOM', + 'PM' => 'SPM', + 'RS' => 'SRB', + 'SS' => 'SSD', + 'ST' => 'STP', + 'SR' => 'SUR', + 'SK' => 'SVK', + 'SI' => 'SVN', + 'SE' => 'SWE', + 'SZ' => 'SWZ', + 'SX' => 'SXM', + 'SC' => 'SYC', + 'SY' => 'SYR', + 'TC' => 'TCA', + 'TD' => 'TCD', + 'TG' => 'TGO', + 'TH' => 'THA', + 'TJ' => 'TJK', + 'TK' => 'TKL', + 'TM' => 'TKM', + 'TL' => 'TLS', + 'TO' => 'TON', + 'TT' => 'TTO', + 'TN' => 'TUN', + 'TR' => 'TUR', + 'TV' => 'TUV', + 'TW' => 'TWN', + 'TZ' => 'TZA', + 'UG' => 'UGA', + 'UA' => 'UKR', + 'UM' => 'UMI', + 'UY' => 'URY', + 'US' => 'USA', + 'UZ' => 'UZB', + 'VA' => 'VAT', + 'VC' => 'VCT', + 'VE' => 'VEN', + 'VG' => 'VGB', + 'VI' => 'VIR', + 'VN' => 'VNM', + 'VU' => 'VUT', + 'WF' => 'WLF', + 'WS' => 'WSM', + 'YE' => 'YEM', + 'ZA' => 'ZAF', + 'ZM' => 'ZMB', + 'ZW' => 'ZWE', + ]; + public function testGetCountryCodes() { $this->assertSame(self::$countries, Countries::getCountryCodes()); @@ -348,4 +601,67 @@ class CountriesTest extends ResourceBundleTestCase $this->assertTrue(Countries::exists('NL')); $this->assertFalse(Countries::exists('ZZ')); } + + public function testGetAlpha3Codes() + { + $this->assertSame(self::$alpha2ToAlpha3, Countries::getAlpha3Codes()); + } + + public function testGetAlpha3Code() + { + foreach (self::$countries as $country) { + $this->assertSame(self::$alpha2ToAlpha3[$country], Countries::getAlpha3Code($country)); + } + } + + public function testGetAlpha2Code() + { + foreach (self::$countries as $alpha2Code) { + $alpha3Code = self::$alpha2ToAlpha3[$alpha2Code]; + $this->assertSame($alpha2Code, Countries::getAlpha2Code($alpha3Code)); + } + } + + public function testAlpha3CodeExists() + { + $this->assertTrue(Countries::alpha3CodeExists('NOR')); + $this->assertTrue(Countries::alpha3CodeExists('NLD')); + $this->assertFalse(Countries::alpha3CodeExists('NIO')); + $this->assertFalse(Countries::alpha3CodeExists('ZZZ')); + } + + /** + * @dataProvider provideLocales + */ + public function testGetAlpha3Name($displayLocale) + { + $names = Countries::getNames($displayLocale); + + foreach ($names as $alpha2 => $name) { + $alpha3 = self::$alpha2ToAlpha3[$alpha2]; + $this->assertSame($name, Countries::getAlpha3Name($alpha3, $displayLocale)); + } + } + + public function testGetAlpha3NameWithInvalidCountryCode() + { + $this->expectException(MissingResourceException::class); + + Countries::getAlpha3Name('ZZZ'); + } + + /** + * @dataProvider provideLocales + */ + public function testGetAlpha3Names($displayLocale) + { + $names = Countries::getAlpha3Names($displayLocale); + + $alpha3Codes = array_keys($names); + sort($alpha3Codes); + $this->assertSame(array_values(self::$alpha2ToAlpha3), $alpha3Codes); + + $alpha2Names = Countries::getNames($displayLocale); + $this->assertSame(array_values($alpha2Names), array_values($names)); + } } diff --git a/src/Symfony/Component/Intl/Tests/LanguagesTest.php b/src/Symfony/Component/Intl/Tests/LanguagesTest.php index 296f3b2eee..224a5172c4 100644 --- a/src/Symfony/Component/Intl/Tests/LanguagesTest.php +++ b/src/Symfony/Component/Intl/Tests/LanguagesTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Intl\Tests; +use Symfony\Component\Intl\Exception\MissingResourceException; use Symfony\Component\Intl\Languages; /** @@ -925,4 +926,66 @@ class LanguagesTest extends ResourceBundleTestCase $this->assertTrue(Languages::exists('nl')); $this->assertFalse(Languages::exists('zxx')); } + + public function testGetAlpha3Codes() + { + $this->assertSame(self::$alpha2ToAlpha3, Languages::getAlpha3Codes()); + } + + public function testGetAlpha2Code() + { + foreach (self::$alpha2ToAlpha3 as $alpha2Code => $alpha3Code) { + $this->assertSame($alpha2Code, Languages::getAlpha2Code($alpha3Code)); + } + } + + public function testAlpha3CodeExists() + { + $this->assertTrue(Languages::alpha3CodeExists('nob')); + $this->assertTrue(Languages::alpha3CodeExists('nld')); + $this->assertFalse(Languages::alpha3CodeExists('foo')); + $this->assertFalse(Languages::alpha3CodeExists('zzz')); + } + + /** + * @dataProvider provideLocales + */ + public function testGetAlpha3Name($displayLocale) + { + $names = Languages::getNames($displayLocale); + + foreach ($names as $alpha2 => $name) { + $alpha3 = self::$alpha2ToAlpha3[$alpha2] ?? false; + if ($alpha3) { + $this->assertSame($name, Languages::getAlpha3Name($alpha3, $displayLocale)); + } + } + } + + public function testGetAlpha3NameWithInvalidCountryCode() + { + $this->expectException(MissingResourceException::class); + + Languages::getAlpha3Name('ZZZ'); + } + + /** + * @dataProvider provideLocales + */ + public function testGetAlpha3Names($displayLocale) + { + $names = Languages::getAlpha3Names($displayLocale); + + $alpha3Codes = array_keys($names); + sort($alpha3Codes); + $this->assertSame(array_values(self::$alpha2ToAlpha3), $alpha3Codes); + + $alpha2Names = Languages::getNames($displayLocale); + foreach ($alpha2Names as $alpha2Code => $name) { + if (!isset(self::$alpha2ToAlpha3[$alpha2Code])) { + unset($alpha2Names[$alpha2Code]); + } + } + $this->assertSame(array_values($alpha2Names), array_values($names)); + } }