HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/SBogers10/conmeq.komma.pro/app/Komma/Globalization/CultureInfo.php
<?php


namespace App\Komma\Globalization;

/**
 * Class CultureInfo
 *
 * Provides information about a specific culture (called a locale for unmanaged code development)
 * Based of the C# variant.
 *
 * @see https://docs.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo?view=netframework-4.7.2
 * @package App\Komma\Globalization
 */
class CultureInfo extends AbstractCultureParser
{
    /** @var CultureInfo[] cached objects */
    private static $cache = [];

    /** @var string $displayName */
    private $displayName = '';

    /** @var string $englishName */
    private $englishName = '';

    /** @var boolean $isNeutralCulture */
    private $isNeutralCulture;

    /** @var CultureInfo $parent */
    private $parent;

    /** @var string $nativeName */
    private $nativeName = '';

    /** @var string $threeLetterIsoLanguageName */
    private $threeLetterIsoLanguageName = '';

    /** @var string $twoLetterIsoLanguageName */
    private $twoLetterIsoLanguageName = '';

    /** @var string $name */
    private $name = '';

    /** @var array $neutralCultures Cultures that are associated with a language but are not specific to a country/region. Example 'NL'*/
    private static $neutralCultures = [];

    /** @var array $specificCultures Cultures that are specific to a country/region. Example nl-BE */
    private static $specificCultures = [];

    /**
     * Provides information about a specific culture (called a locale for unmanaged code development)
     *
     * The format for the culture name based on RFC 4646 is languagecode2>-country/regioncode2, where languagecode2 is the two-letter
     * language code and country/regioncode2 is the two-letter subculture code. Examples include ja-JP for Japanese (Japan)
     * and en-US for English (United States). In cases where a two-letter language code is not available,
     * a three-letter code derived from ISO 639-2 is used.
     *
     * Notice that some culture names also specify an ISO 15924 script. For example, Cyrl specifies the Cyrillic script
     * and Latn specifies the Latin script. A culture name that includes a script uses the pattern languagecode2-scripttag-country/regioncode2.
     * An example of this type of culture name is uz-Cyrl-UZ for Uzbek (Cyrillic, Uzbekistan).
     *
     * A neutral culture is specified by only the two-letter lowercase language code. For example, fr specifies the neutral culture for French, and de specifies the neutral culture for German.
     *
     * CultureInfo constructor.
     * @param string $name
     */
    public function __construct(string $name)
    {
        if(in_array('name', array_keys(self::$cache), true)) return self::$cache['name']; //Return the culture if it was initiated before

        parent::__construct($name);

        $this->englishName = Culture::DATA[$this->cultureId]['EnglishName'] ??  '';
        $this->name = $this->currentName;
        $this->twoLetterIsoLanguageName = Culture::DATA[$this->cultureId]['ISO-639-1'] ??  '';
        $this->threeLetterIsoLanguageName = Culture::DATA[$this->cultureId]['ISO-639-2'] ??  Culture::DATA[$this->cultureId]['ISO-639-3'] ?? '';

        $this->determineIfNeutralCulture();
        $this->determineParentCulture();
        $this->determineDisplayName();
        $this->determineNativeName();
    }

    /**
     * Parses a culture name into an array that contains the language code, scripttag if needed, and country or region code 2.
     *
     * @param string $name
     */
    protected function parseName(string $name)
    {
        if($name !== "") {
            $explodedCultureName = explode('-', $name);
            $count = count($explodedCultureName);
            if ($count == 3) {
                $this->languageCode2 = strtolower($explodedCultureName[0]);
                $this->scriptTagCountry = strtolower($explodedCultureName[1]);
                $this->countryOrRegionCode2 = strtolower($explodedCultureName[2]);
            } elseif ($count == 2) {
                $this->languageCode2 = strtolower($explodedCultureName[0]);
                $this->countryOrRegionCode2 = strtolower($explodedCultureName[1]);
            } elseif ($count == 1) { //Neutral culture ()
                $this->languageCode2 = strtolower($explodedCultureName[0]);
            }
        } else {
            //Invariant culture that should default to english. Processed in the setId method
        }
    }

    /**
     * Determines the display name
     */
    private function determineDisplayName()
    {
        $displayName = Culture::DATA[$this->cultureId]['DisplayName'];
        if($this->countryOrRegionCode2 && $this->countryOrRegionCode2 !== '') {
            $regionInfo = new RegionInfo($this->countryOrRegionCode2);
            $displayName .= ' ('.$regionInfo->getDisplayName().')';
        }
        $this->displayName = $displayName;
    }

    /**
     * Determines the display name
     */
    private function determineNativeName()
    {
        $nativeName = Culture::DATA[$this->cultureId]['NativeName'];
        if($this->countryOrRegionCode2 && $this->countryOrRegionCode2 !== '') {
            $regionInfo = new RegionInfo($this->countryOrRegionCode2);
            $nativeName .= ' ('.$regionInfo->getNativeName().')';
        }
        $this->nativeName = $nativeName;
    }

    /**
     * Looks up any combination of languageCode2, scriptTagCountry and countryOrRegionCode2 in the data in
     * AbstractCultureData and stores the ID
     */
    protected function setId()
    {
        foreach(Culture::DATA as $cultureId => $cultureData) {
            if(isset($cultureData['ISO-639-1'])) {
                if($this->languageCode2 == '' && $this->scriptTagCountry == '' && $this->countryOrRegionCode2) {
                    //Invariant culture. An invariant culture is culture-insensitive.
                    //Your application specifies the invariant culture by name using an empty string ("") or by its identifier.
                    //It is associated with the English language but not with any country/region. To make improve this function we should return an instance of a
                    //yet still non existing culture instance called InvariantCulture.
                    if($cultureData['ISO-639-1'] == 'en') $this->cultureId = $cultureId;
                }
                else if(strtoupper($cultureData['ISO-639-1']) == strtoupper($this->languageCode2)) {
                    $this->cultureId = $cultureId;
                }
            }
        }
    }

    /**
     * Parses the neutral cultures. e.g. Cultures not associated to a country, but with a language. For example with name 'nl';
     */
    private static function parseNeutralCultures()
    {
        if(empty(self::$neutralCultures)) {
            foreach (Culture::DATA as $cultureId => $cultureData)
                self::$neutralCultures[] = new self(strtolower($cultureData['ISO-639-1']));
        }
    }

    /**
     * Parses specific cultures. e.g. Cultures both associated with to a country and language. For example with name 'nl-BE'
     */
    private static function parseSpecificCultures()
    {
        if(empty(self::$specificCultures)) {
            foreach (Culture::DATA as $cultureId => $cultureData) {
                $languageCode = $cultureData['ISO-639-1'];
                foreach($cultureData['country/regions'] as $countryRegionId => $countryRegion) {
                    $countryRegionCode = strtolower($countryRegion['TwoLetterISORegionName']);
                    self::$specificCultures[] = new self($languageCode.'-'.strtoupper($countryRegionCode));
                }
            }
        }
    }

    /**
     * A neutral culture is a culture that is associated with a language but not with a country/region.
     * A specific culture is a culture that is associated with a language and a country/region. For example,
     * fr is the neutral name for the French culture, and fr-FR is the name of the specific French (France) culture.
     */
    private function determineIfNeutralCulture()
    {
        $this->isNeutralCulture = ($this->languageCode2 !== '' && $this->countryOrRegionCode2 == '' && $this->scriptTagCountry == '');
    }

    /**
     * Set the CultureInfo that represents the parent culture of the current CultureInfo.
     */
    private function determineParentCulture()
    {
        if(strtolower($this->currentName) != strtolower($this->languageCode2)) {
            $this->parent = new self($this->languageCode2);
        }
    }

    /**
     * @return string
     */
    public function getDisplayName(): string
    {
        return $this->displayName;
    }

    /**
     * @return string
     */
    public function getEnglishName(): string
    {
        return $this->englishName;
    }

    /**
     * A neutral culture is a culture that is associated with a language but not with a country/region.
     * A specific culture is a culture that is associated with a language and a country/region. For example,
     * fr is the neutral name for the French culture, and fr-FR is the name of the specific French (France) culture.
     *
     * @return bool
     */
    public function isNeutralCulture(): bool
    {
        return $this->isNeutralCulture;
    }

    /**
     * @return CultureInfo
     */
    public function getParent(): ? CultureInfo
    {
        return $this->parent;
    }

    /**
     * @return string
     */
    public function getNativeName(): string
    {
        return $this->nativeName;
    }

    /**
     * @return string
     */
    public function getThreeLetterIsoLanguageName(): string
    {
        return $this->threeLetterIsoLanguageName;
    }

    /**
     * @return string
     */
    public function getTwoLetterIsoLanguageName(): string
    {
        return $this->twoLetterIsoLanguageName;
    }

    /**
     * @return string
     */
    public function getName(): string
    {
        return $this->name;
    }

    /**
     * @param int $type a CultureType value
     * @return CultureInfo[]
     */
    public static function getCultures(int $type): array
    {
        self::parseNeutralCultures();
        self::parseSpecificCultures();

        //Determine what to return
        switch ($type) {
            case CultureTypes::ALL_CULTURES:
                return array_merge(self::$neutralCultures, self::$specificCultures);
            case CultureTypes::NEUTRAL_CULTURES:
                return self::$neutralCultures;
            case CultureTypes::SPECIFIC_CULTURES:
                return self::$specificCultures;
        }
    }
}