aboutsummaryrefslogblamecommitdiffstats
path: root/vendor/commerceguys/intl/src/LocaleResolverTrait.php
blob: 797e5abaf561649df1b87a5289be5383299a0efb (plain) (tree)



















































































































































































































































                                                                            
<?php

namespace CommerceGuys\Intl;

use CommerceGuys\Intl\Exception\UnknownLocaleException;

trait LocaleResolverTrait
{
    /**
     * The path where per-locale definitions are stored.
     *
     * @var string
     */
    protected $definitionPath;

    /**
     * The default locale.
     *
     * @var string
     */
    protected $defaultLocale = 'en';

    /**
     * The fallback locale.
     *
     * @var string
     */
    protected $fallbackLocale = null;

    /**
     * Common locale aliases.
     *
     * @var array
     */
    protected $localeAliases = [
        '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',
    ];

    /**
     * Determines which locale should be used for loading definitions.
     *
     * If the "bs-Cyrl-BA" locale is requested, with an "en" fallback,
     * the system will try to find the definitions for:
     * 1) bs-Cyrl-BA
     * 2) bs-Cyrl
     * 3) bs
     * 4) en
     * The first locale for which a definition file is found, wins.
     * Otherwise, an exception is thrown.
     *
     * @param string $locale         The desired locale (i.e. fr-FR).
     * @param string $fallbackLocale A fallback locale (i.e "en").
     *
     * @return string
     *
     * @throws UnknownLocaleException
     */
    protected function resolveLocale($locale = null, $fallbackLocale = null)
    {
        $locale = $locale ?: $this->getDefaultLocale();
        $locale = $this->canonicalizeLocale($locale);
        $locale = $this->resolveLocaleAlias($locale);
        // List all possible variants (i.e. en-US gives "en-US" and "en").
        $localeVariants = $this->getLocaleVariants($locale);
        // A fallback locale was provided, add it to the end of the chain.
        $fallbackLocale = $fallbackLocale ?: $this->getFallbackLocale();
        if (isset($fallbackLocale)) {
            $localeVariants[] = $fallbackLocale;
        }

        // Try to resolve a locale by finding a matching definition file.
        $resolvedLocale = null;
        foreach ($localeVariants as $localeVariant) {
            $path = $this->definitionPath . $localeVariant . '.json';
            if (file_exists($path)) {
                $resolvedLocale = $localeVariant;
                break;
            }
        }
        // No locale could be resolved, stop here.
        if (!$resolvedLocale) {
            throw new UnknownLocaleException($locale);
        }

        return $resolvedLocale;
    }

    /**
     * Resolves known locale aliases.
     *
     * For example, "zh-CN" is resolved to "zh-Hans-CN".
     *
     * @param string $locale The locale.
     *
     * @return string The locale.
     */
    protected function resolveLocaleAlias($locale = null)
    {
        if ($locale && isset($this->localeAliases[$locale])) {
            $locale = $this->localeAliases[$locale];
        }

        return $locale;
    }

    /**
     * Canonicalize the given locale.
     *
     * @param string $locale The locale.
     *
     * @return string The canonicalized locale.
     */
    protected function canonicalizeLocale($locale = null)
    {
        if (is_null($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 the default locale.
     *
     * @return string The default locale.
     */
    public function getDefaultLocale()
    {
        return $this->defaultLocale;
    }

    /**
     * Sets the default locale.
     *
     * @return void
     */
    public function setDefaultLocale($locale)
    {
        $this->defaultLocale = $locale;
    }

    /**
     * Gets the fallback locale.
     *
     * @return string The fallback locale.
     */
    public function getFallbackLocale()
    {
        return $this->fallbackLocale;
    }

    /**
     * Sets the fallback locale.
     *
     * @return void
     */
    public function setFallbackLocale($locale)
    {
        $this->fallbackLocale = $locale;
    }

    /**
     * Gets all variants of a locale.
     *
     * For example, "bs-Cyrl-BA" has the following variants:
     * 1) bs-Cyrl-BA
     * 2) bs-Cyrl
     * 3) bs
     *
     * @param string $locale The locale (i.e. fr-FR).
     *
     * @return array An array of all variants of a locale.
     */
    protected function getLocaleVariants($locale)
    {
        $localeVariants = [];
        $localeParts = explode('-', $locale);
        while (!empty($localeParts)) {
            $localeVariants[] = implode('-', $localeParts);
            array_pop($localeParts);
        }

        return $localeVariants;
    }
}