diff options
Diffstat (limited to 'vendor/commerceguys/intl/src/Locale.php')
-rw-r--r-- | vendor/commerceguys/intl/src/Locale.php | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/vendor/commerceguys/intl/src/Locale.php b/vendor/commerceguys/intl/src/Locale.php new file mode 100644 index 000000000..f8f3f7cb8 --- /dev/null +++ b/vendor/commerceguys/intl/src/Locale.php @@ -0,0 +1,432 @@ +<?php + +namespace CommerceGuys\Intl; + +use CommerceGuys\Intl\Exception\UnknownLocaleException; + +final class Locale +{ + /** + * Locale aliases. + * + * @var array + */ + protected static $aliases = [ + 'az-AZ' => 'az-Latn-AZ', + 'bs-BA' => 'bs-Latn-BA', + 'ha-GH' => 'ha-Latn-GH', + 'ha-NE' => 'ha-Latn-NE', + 'ha-NG' => 'ha-Latn-NG', + 'in' => 'id', + 'in-ID' => 'id-ID', + 'iw' => 'he', + 'iw-IL' => 'he-IL', + 'kk-KZ' => 'kk-Cyrl-KZ', + 'ks-IN' => 'ks-Arab-IN', + 'ky-KG' => 'ky-Cyrl-KG', + 'mn-MN' => 'mn-Cyrl-MN', + 'mo' => 'ro-MD', + 'ms-BN' => 'ms-Latn-BN', + 'ms-MY' => 'ms-Latn-MY', + 'ms-SG' => 'ms-Latn-SG', + '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', + 'shi-MA' => 'shi-Tfng-MA', + 'sr-BA' => 'sr-Cyrl-BA', + 'sr-ME' => 'sr-Latn-ME', + 'sr-RS' => 'sr-Cyrl-RS', + 'sr-XK' => 'sr-Cyrl-XK', + 'tl' => 'fil', + 'tl-PH' => 'fil-PH', + 'tzm-MA' => 'tzm-Latn-MA', + 'ug-CN' => 'ug-Arab-CN', + 'uz-AF' => 'uz-Arab-AF', + 'uz-UZ' => 'uz-Latn-UZ', + 'vai-LR' => 'vai-Vaii-LR', + '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', + ]; + + /** + * Locale parents. + * + * @var array + */ + protected static $parents = [ + 'en-150' => 'en-001', + 'en-AG' => 'en-001', + 'en-AI' => 'en-001', + 'en-AU' => 'en-001', + 'en-BB' => 'en-001', + 'en-BM' => 'en-001', + 'en-BS' => 'en-001', + 'en-BW' => 'en-001', + 'en-BZ' => 'en-001', + 'en-CA' => 'en-001', + 'en-CC' => 'en-001', + 'en-CK' => 'en-001', + 'en-CM' => 'en-001', + 'en-CX' => 'en-001', + 'en-CY' => 'en-001', + 'en-DG' => 'en-001', + 'en-DM' => 'en-001', + 'en-ER' => 'en-001', + 'en-FJ' => 'en-001', + 'en-FK' => 'en-001', + 'en-FM' => 'en-001', + 'en-GB' => 'en-001', + 'en-GD' => 'en-001', + 'en-GG' => 'en-001', + 'en-GH' => 'en-001', + 'en-GI' => 'en-001', + 'en-GM' => 'en-001', + 'en-GY' => 'en-001', + 'en-HK' => 'en-001', + 'en-IE' => 'en-001', + 'en-IL' => 'en-001', + 'en-IM' => 'en-001', + 'en-IN' => 'en-001', + 'en-IO' => 'en-001', + 'en-JE' => 'en-001', + 'en-JM' => 'en-001', + 'en-KE' => 'en-001', + 'en-KI' => 'en-001', + 'en-KN' => 'en-001', + 'en-KY' => 'en-001', + 'en-LC' => 'en-001', + 'en-LR' => 'en-001', + 'en-LS' => 'en-001', + 'en-MG' => 'en-001', + 'en-MO' => 'en-001', + 'en-MS' => 'en-001', + 'en-MT' => 'en-001', + 'en-MU' => 'en-001', + 'en-MW' => 'en-001', + 'en-MY' => 'en-001', + 'en-NA' => 'en-001', + 'en-NF' => 'en-001', + 'en-NG' => 'en-001', + 'en-NR' => 'en-001', + 'en-NU' => 'en-001', + 'en-NZ' => 'en-001', + 'en-PG' => 'en-001', + 'en-PH' => 'en-001', + 'en-PK' => 'en-001', + 'en-PN' => 'en-001', + 'en-PW' => 'en-001', + 'en-RW' => 'en-001', + 'en-SB' => 'en-001', + 'en-SC' => 'en-001', + 'en-SD' => 'en-001', + 'en-SG' => 'en-001', + 'en-SH' => 'en-001', + 'en-SL' => 'en-001', + 'en-SS' => 'en-001', + 'en-SX' => 'en-001', + 'en-SZ' => 'en-001', + 'en-TC' => 'en-001', + 'en-TK' => 'en-001', + 'en-TO' => 'en-001', + 'en-TT' => 'en-001', + 'en-TV' => 'en-001', + 'en-TZ' => 'en-001', + 'en-UG' => 'en-001', + 'en-VC' => 'en-001', + 'en-VG' => 'en-001', + 'en-VU' => 'en-001', + 'en-WS' => 'en-001', + 'en-ZA' => 'en-001', + 'en-ZM' => 'en-001', + 'en-ZW' => 'en-001', + 'en-AT' => 'en-150', + 'en-BE' => 'en-150', + 'en-CH' => 'en-150', + 'en-DE' => 'en-150', + 'en-DK' => 'en-150', + 'en-FI' => 'en-150', + 'en-NL' => 'en-150', + 'en-SE' => 'en-150', + 'en-SI' => 'en-150', + 'es-AR' => 'es-419', + 'es-BO' => 'es-419', + 'es-BR' => 'es-419', + 'es-BZ' => 'es-419', + 'es-CL' => 'es-419', + 'es-CO' => 'es-419', + 'es-CR' => 'es-419', + 'es-CU' => 'es-419', + 'es-DO' => 'es-419', + 'es-EC' => 'es-419', + 'es-GT' => 'es-419', + 'es-HN' => 'es-419', + 'es-MX' => 'es-419', + 'es-NI' => 'es-419', + 'es-PA' => 'es-419', + 'es-PE' => 'es-419', + 'es-PR' => 'es-419', + 'es-PY' => 'es-419', + 'es-SV' => 'es-419', + 'es-US' => 'es-419', + 'es-UY' => 'es-419', + 'es-VE' => 'es-419', + 'pt-AO' => 'pt-PT', + 'pt-CH' => 'pt-PT', + 'pt-CV' => 'pt-PT', + 'pt-FR' => 'pt-PT', + 'pt-GQ' => 'pt-PT', + 'pt-GW' => 'pt-PT', + 'pt-LU' => 'pt-PT', + 'pt-MO' => 'pt-PT', + 'pt-MZ' => 'pt-PT', + 'pt-ST' => 'pt-PT', + 'pt-TL' => 'pt-PT', + 'az-Arab' => 'root', + 'az-Cyrl' => 'root', + 'blt-Latn' => 'root', + 'bm-Nkoo' => 'root', + 'bs-Cyrl' => 'root', + 'byn-Latn' => 'root', + 'cu-Glag' => 'root', + 'dje-Arab' => 'root', + 'dyo-Arab' => 'root', + 'en-Dsrt' => 'root', + 'en-Shaw' => 'root', + 'ff-Adlm' => 'root', + 'ff-Arab' => 'root', + 'ha-Arab' => 'root', + 'iu-Latn' => 'root', + 'kk-Arab' => 'root', + 'ku-Arab' => 'root', + 'ky-Arab' => 'root', + 'ky-Latn' => 'root', + 'ml-Arab' => 'root', + 'mn-Mong' => 'root', + 'ms-Arab' => 'root', + 'pa-Arab' => 'root', + 'sd-Deva' => 'root', + 'sd-Khoj' => 'root', + 'sd-Sind' => 'root', + 'shi-Latn' => 'root', + 'so-Arab' => 'root', + 'sr-Latn' => 'root', + 'sw-Arab' => 'root', + 'tg-Arab' => 'root', + 'ug-Cyrl' => 'root', + 'uz-Arab' => 'root', + 'uz-Cyrl' => 'root', + 'vai-Latn' => 'root', + 'wo-Arab' => 'root', + 'yo-Arab' => 'root', + 'yue-Hans' => 'root', + 'zh-Hant' => 'root', + 'zh-Hant-MO' => 'zh-Hant-HK', + ]; + + /** + * Checks whether two locales match. + * + * @param string $firstLocale The first locale. + * @param string $secondLocale The second locale. + * + * @return bool TRUE if the locales match, FALSE otherwise. + */ + public static function match($firstLocale, $secondLocale) + { + if (empty($firstLocale) || empty($secondLocale)) { + return false; + } + + return self::canonicalize($firstLocale) === self::canonicalize($secondLocale); + } + + /** + * Checks whether two locales have at least one common candidate. + * + * For example, "de" and "de-AT" will match because they both have + * "de" in common. This is useful for partial locale matching. + * + * @see self::getCandidates + * + * @param string $firstLocale The first locale. + * @param string $secondLocale The second locale. + * + * @return bool TRUE if there is a common candidate, FALSE otherwise. + */ + public static function matchCandidates($firstLocale, $secondLocale) + { + if (empty($firstLocale) || empty($secondLocale)) { + return false; + } + + $firstLocale = self::canonicalize($firstLocale); + $secondLocale = self::canonicalize($secondLocale); + $firstLocaleCandidates = self::getCandidates($firstLocale); + $secondLocaleCandidates = self::getCandidates($secondLocale); + + return (bool) array_intersect($firstLocaleCandidates, $secondLocaleCandidates); + } + + /** + * Resolves the locale from the available locales. + * + * Takes all locale candidates for the requested locale + * and fallback locale, searches for them in the available + * locale list. The first found locale is returned. + * If no candidate is found in the list, an exception is thrown. + * + * @see self::getCandidates + * + * @param array $availableLocales The available locales. + * @param string $locale The requested locale (i.e. fr-FR). + * @param string $fallbackLocale A fallback locale (i.e "en"). + * + * @return string + * + * @throws UnknownLocaleException + */ + public static function resolve(array $availableLocales, $locale, $fallbackLocale = null) + { + $locale = self::canonicalize($locale); + $resolvedLocale = null; + foreach (self::getCandidates($locale, $fallbackLocale) as $candidate) { + if (in_array($candidate, $availableLocales)) { + $resolvedLocale = $candidate; + break; + } + } + // No locale could be resolved, stop here. + if (!$resolvedLocale) { + throw new UnknownLocaleException($locale); + } + + return $resolvedLocale; + } + + /** + * Canonicalizes the given locale. + * + * Standardizes separators and capitalization, turning + * a locale such as "sr_rs_latn" into "sr-RS-Latn". + * + * @param string $locale The locale. + * + * @return string The canonicalized locale. + */ + public static function canonicalize($locale) + { + if (empty($locale)) { + return $locale; + } + + $locale = str_replace('_', '-', strtolower($locale)); + $localeParts = explode('-', $locale); + foreach ($localeParts as $index => $part) { + if ($index === 0) { + // The language code should stay lowercase. + continue; + } + + if (strlen($part) == 4) { + // Script code. + $localeParts[$index] = ucfirst($part); + } else { + // Country or variant code. + $localeParts[$index] = strtoupper($part); + } + } + + return implode('-', $localeParts); + } + + /** + * Gets locale candidates. + * + * For example, "bs-Cyrl-BA" has the following candidates: + * 1) bs-Cyrl-BA + * 2) bs-Cyrl + * 3) bs + * + * The locale is de-aliased, e.g. the candidates for "sh" are: + * 1) sr-Latn + * 2) sr + * + * @param string $locale The locale (i.e. fr-FR). + * @param string $fallbackLocale A fallback locale (i.e "en"). + * + * @return array An array of all variants of a locale. + */ + public static function getCandidates($locale, $fallbackLocale = null) + { + $locale = self::replaceAlias($locale); + $candidates = [$locale]; + while ($parent = self::getParent($locale)) { + $candidates[] = $parent; + $locale = $parent; + } + if (isset($fallbackLocale)) { + $candidates[] = $fallbackLocale; + while ($parent = self::getParent($fallbackLocale)) { + $candidates[] = $parent; + $fallbackLocale = $parent; + } + } + + return array_unique($candidates); + } + + /** + * Gets the parent for the given locale. + * + * @param string $locale + * The locale. + * + * @return string|null + * The parent, or null if none found. + */ + public static function getParent($locale) + { + $parent = null; + if (isset(self::$parents[$locale])) { + $parent = self::$parents[$locale]; + } elseif (strpos($locale, '-') !== false) { + $localeParts = explode('-', $locale); + array_pop($localeParts); + $parent = implode('-', $localeParts); + } + // The library doesn't have data for the empty 'root' locale, it + // is more user friendly to use the configured fallback instead. + if ($parent == 'root') { + $parent = null; + } + + return $parent; + } + + /** + * Replaces a locale alias with the real locale. + * + * For example, "zh-CN" is replaced with "zh-Hans-CN". + * + * @param string $locale The locale. + * + * @return string The locale. + */ + public static function replaceAlias($locale) + { + if (!empty($locale) && isset(self::$aliases[$locale])) { + $locale = self::$aliases[$locale]; + } + + return $locale; + } +} |