From 9cab8ae58a29ecf7387e6865aa170715caeabf04 Mon Sep 17 00:00:00 2001 From: Stefan Parviainen Date: Tue, 30 Dec 2014 19:57:12 +0100 Subject: Language names via intl library. Fixes #773 --- library/intl/src/Country/Country.php | 168 +++++++++ library/intl/src/Country/CountryInterface.php | 99 +++++ library/intl/src/Country/CountryRepository.php | 124 +++++++ .../src/Country/CountryRepositoryInterface.php | 31 ++ library/intl/src/Currency/Currency.php | 168 +++++++++ library/intl/src/Currency/CurrencyInterface.php | 82 +++++ library/intl/src/Currency/CurrencyRepository.php | 122 +++++++ .../src/Currency/CurrencyRepositoryInterface.php | 31 ++ library/intl/src/Exception/ExceptionInterface.php | 7 + .../src/Exception/InvalidArgumentException.php | 11 + .../intl/src/Exception/UnknownCountryException.php | 11 + .../src/Exception/UnknownCurrencyException.php | 11 + .../src/Exception/UnknownLanguageException.php | 11 + .../intl/src/Exception/UnknownLocaleException.php | 10 + library/intl/src/Formatter/NumberFormatter.php | 406 +++++++++++++++++++++ .../src/Formatter/NumberFormatterInterface.php | 134 +++++++ library/intl/src/Language/Language.php | 91 +++++ library/intl/src/Language/LanguageInterface.php | 37 ++ library/intl/src/Language/LanguageRepository.php | 96 +++++ .../src/Language/LanguageRepositoryInterface.php | 31 ++ library/intl/src/LocaleResolverTrait.php | 89 +++++ library/intl/src/NumberFormat/NumberFormat.php | 269 ++++++++++++++ .../src/NumberFormat/NumberFormatInterface.php | 185 ++++++++++ .../src/NumberFormat/NumberFormatRepository.php | 87 +++++ .../NumberFormatRepositoryInterface.php | 19 + 25 files changed, 2330 insertions(+) create mode 100644 library/intl/src/Country/Country.php create mode 100644 library/intl/src/Country/CountryInterface.php create mode 100644 library/intl/src/Country/CountryRepository.php create mode 100644 library/intl/src/Country/CountryRepositoryInterface.php create mode 100644 library/intl/src/Currency/Currency.php create mode 100644 library/intl/src/Currency/CurrencyInterface.php create mode 100644 library/intl/src/Currency/CurrencyRepository.php create mode 100644 library/intl/src/Currency/CurrencyRepositoryInterface.php create mode 100644 library/intl/src/Exception/ExceptionInterface.php create mode 100644 library/intl/src/Exception/InvalidArgumentException.php create mode 100644 library/intl/src/Exception/UnknownCountryException.php create mode 100644 library/intl/src/Exception/UnknownCurrencyException.php create mode 100644 library/intl/src/Exception/UnknownLanguageException.php create mode 100644 library/intl/src/Exception/UnknownLocaleException.php create mode 100644 library/intl/src/Formatter/NumberFormatter.php create mode 100644 library/intl/src/Formatter/NumberFormatterInterface.php create mode 100644 library/intl/src/Language/Language.php create mode 100644 library/intl/src/Language/LanguageInterface.php create mode 100644 library/intl/src/Language/LanguageRepository.php create mode 100644 library/intl/src/Language/LanguageRepositoryInterface.php create mode 100644 library/intl/src/LocaleResolverTrait.php create mode 100644 library/intl/src/NumberFormat/NumberFormat.php create mode 100644 library/intl/src/NumberFormat/NumberFormatInterface.php create mode 100644 library/intl/src/NumberFormat/NumberFormatRepository.php create mode 100644 library/intl/src/NumberFormat/NumberFormatRepositoryInterface.php (limited to 'library/intl/src') diff --git a/library/intl/src/Country/Country.php b/library/intl/src/Country/Country.php new file mode 100644 index 000000000..5ac65fd0d --- /dev/null +++ b/library/intl/src/Country/Country.php @@ -0,0 +1,168 @@ +getCountryCode(); + } + + /** + * {@inheritdoc} + */ + public function getCountryCode() + { + return $this->countryCode; + } + + /** + * {@inheritdoc} + */ + public function setCountryCode($countryCode) + { + $this->countryCode = $countryCode; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->name; + } + + /** + * {@inheritdoc} + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getThreeLetterCode() + { + return $this->threeLetterCode; + } + + /** + * {@inheritdoc} + */ + public function setThreeLetterCode($threeLetterCode) + { + $this->threeLetterCode = $threeLetterCode; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getNumericCode() + { + return $this->numericCode; + } + + /** + * {@inheritdoc} + */ + public function setNumericCode($numericCode) + { + $this->numericCode = $numericCode; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getTelephoneCode() + { + return $this->telephoneCode; + } + + /** + * {@inheritdoc} + */ + public function setTelephoneCode($telephoneCode) + { + $this->telephoneCode = $telephoneCode; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getLocale() + { + return $this->locale; + } + + /** + * {@inheritdoc} + */ + public function setLocale($locale) + { + $this->locale = $locale; + + return $this; + } +} diff --git a/library/intl/src/Country/CountryInterface.php b/library/intl/src/Country/CountryInterface.php new file mode 100644 index 000000000..245a49be9 --- /dev/null +++ b/library/intl/src/Country/CountryInterface.php @@ -0,0 +1,99 @@ +definitionPath = $definitionPath ? $definitionPath : __DIR__ . '/../../resources/country/'; + } + + /** + * {@inheritdoc} + */ + public function get($countryCode, $locale = null, $fallbackLocale = null) + { + $locale = $this->resolveLocale($locale, $fallbackLocale); + $definitions = $this->loadDefinitions($locale); + if (!isset($definitions[$countryCode])) { + throw new UnknownCountryException($countryCode); + } + + return $this->createCountryFromDefinition($definitions[$countryCode], $locale); + } + + /** + * {@inheritdoc} + */ + public function getAll($locale = null, $fallbackLocale = null) + { + $locale = $this->resolveLocale($locale, $fallbackLocale); + $definitions = $this->loadDefinitions($locale); + $countries = array(); + foreach ($definitions as $countryCode => $definition) { + $countries[$countryCode] = $this->createCountryFromDefinition($definition, $locale); + } + + return $countries; + } + + /** + * Loads the country definitions for the provided locale. + * + * @param string $locale The desired locale. + * + * @return array + */ + protected function loadDefinitions($locale) + { + if (!isset($this->definitions[$locale])) { + $filename = $this->definitionPath . $locale . '.json'; + $this->definitions[$locale] = json_decode(file_get_contents($filename), true); + + // Make sure the base definitions have been loaded. + if (empty($this->baseDefinitions)) { + $this->baseDefinitions = json_decode(file_get_contents($this->definitionPath . 'base.json'), true); + } + // Merge-in base definitions. + foreach ($this->definitions[$locale] as $countryCode => $definition) { + $this->definitions[$locale][$countryCode] += $this->baseDefinitions[$countryCode]; + } + } + + return $this->definitions[$locale]; + } + + /** + * Creates a country object from the provided definition. + * + * @param array $definition The country definition. + * @param string $locale The locale of the country definition. + * + * @return Country + */ + protected function createCountryFromDefinition(array $definition, $locale) + { + $country = new Country(); + $country->setCountryCode($definition['code']); + $country->setName($definition['name']); + $country->setLocale($locale); + if (isset($definition['three_letter_code'])) { + $country->setThreeLetterCode($definition['three_letter_code']); + } + if (isset($definition['numeric_code'])) { + $country->setNumericCode($definition['numeric_code']); + } + if (isset($definition['telephone_code'])) { + $country->setTelephoneCode($definition['telephone_code']); + } + + return $country; + } +} diff --git a/library/intl/src/Country/CountryRepositoryInterface.php b/library/intl/src/Country/CountryRepositoryInterface.php new file mode 100644 index 000000000..ae1cbd0c9 --- /dev/null +++ b/library/intl/src/Country/CountryRepositoryInterface.php @@ -0,0 +1,31 @@ +getCurrencyCode(); + } + + /** + * {@inheritdoc} + */ + public function getCurrencyCode() + { + return $this->currencyCode; + } + + /** + * {@inheritdoc} + */ + public function setCurrencyCode($currencyCode) + { + $this->currencyCode = $currencyCode; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->name; + } + + /** + * {@inheritdoc} + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getNumericCode() + { + return $this->numericCode; + } + + /** + * {@inheritdoc} + */ + public function setNumericCode($numericCode) + { + $this->numericCode = $numericCode; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getSymbol() + { + return $this->symbol; + } + + /** + * {@inheritdoc} + */ + public function setSymbol($symbol) + { + $this->symbol = $symbol; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getFractionDigits() + { + return $this->fractionDigits; + } + + /** + * {@inheritdoc} + */ + public function setFractionDigits($fractionDigits) + { + $this->fractionDigits = $fractionDigits; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getLocale() + { + return $this->locale; + } + + /** + * {@inheritdoc} + */ + public function setLocale($locale) + { + $this->locale = $locale; + + return $this; + } +} diff --git a/library/intl/src/Currency/CurrencyInterface.php b/library/intl/src/Currency/CurrencyInterface.php new file mode 100644 index 000000000..ccd03c7e0 --- /dev/null +++ b/library/intl/src/Currency/CurrencyInterface.php @@ -0,0 +1,82 @@ +definitionPath = $definitionPath ? $definitionPath : __DIR__ . '/../../resources/currency/'; + } + + /** + * {@inheritdoc} + */ + public function get($currencyCode, $locale = null, $fallbackLocale = null) + { + $locale = $this->resolveLocale($locale, $fallbackLocale); + $definitions = $this->loadDefinitions($locale); + if (!isset($definitions[$currencyCode])) { + throw new UnknownCurrencyException($currencyCode); + } + + return $this->createCurrencyFromDefinition($definitions[$currencyCode], $locale); + } + + /** + * {@inheritdoc} + */ + public function getAll($locale = null, $fallbackLocale = null) + { + $locale = $this->resolveLocale($locale, $fallbackLocale); + $definitions = $this->loadDefinitions($locale); + $currencies = array(); + foreach ($definitions as $currencyCode => $definition) { + $currencies[$currencyCode] = $this->createCurrencyFromDefinition($definition, $locale); + } + + return $currencies; + } + + /** + * Loads the currency definitions for the provided locale. + * + * @param string $locale The desired locale. + * + * @return array + */ + protected function loadDefinitions($locale) + { + if (!isset($this->definitions[$locale])) { + $filename = $this->definitionPath . $locale . '.json'; + $this->definitions[$locale] = json_decode(file_get_contents($filename), true); + + // Make sure the base definitions have been loaded. + if (empty($this->baseDefinitions)) { + $this->baseDefinitions = json_decode(file_get_contents($this->definitionPath . 'base.json'), true); + } + // Merge-in base definitions. + foreach ($this->definitions[$locale] as $currencyCode => $definition) { + $this->definitions[$locale][$currencyCode] += $this->baseDefinitions[$currencyCode]; + } + } + + return $this->definitions[$locale]; + } + + /** + * Creates a currency object from the provided definition. + * + * @param array $definition The currency definition. + * @param string $locale The locale of the currency definition. + * + * @return Currency + */ + protected function createCurrencyFromDefinition(array $definition, $locale) + { + if (!isset($definition['fraction_digits'])) { + $definition['fraction_digits'] = 2; + } + + $currency = new Currency(); + $currency->setCurrencyCode($definition['code']); + $currency->setName($definition['name']); + $currency->setNumericCode($definition['numeric_code']); + $currency->setFractionDigits($definition['fraction_digits']); + $currency->setSymbol($definition['symbol']); + $currency->setLocale($locale); + + return $currency; + } +} diff --git a/library/intl/src/Currency/CurrencyRepositoryInterface.php b/library/intl/src/Currency/CurrencyRepositoryInterface.php new file mode 100644 index 000000000..d72fcf137 --- /dev/null +++ b/library/intl/src/Currency/CurrencyRepositoryInterface.php @@ -0,0 +1,31 @@ + array( + 0 => '٠', 1 => '١', 2 => '٢', 3 => '٣', 4 => '٤', + 5 => '٥', 6 => '٦', 7 => '٧', 8 => '٨', 9 => '٩', + ), + NumberFormatInterface::NUMBERING_SYSTEM_ARABIC_EXTENDED => array( + 0 => '۰', 1 => '۱', 2 => '۲', 3 => '۳', 4 => '۴', + 5 => '۵', 6 => '۶', 7 => '۷', 8 => '۸', 9 => '۹', + ), + NumberFormatInterface::NUMBERING_SYSTEM_BENGALI => array( + 0 => '০', 1 => '১', 2 => '২', 3 => '৩', 4 => '৪', + 5 => '৫', 6 => '৬', 7 => '৭', 8 => '৮', 9 => '৯', + ), + NumberFormatInterface::NUMBERING_SYSTEM_DEVANAGARI => array( + 0 => '०', 1 => '१', 2 => '२', 3 => '३', 4 => '४', + 5 => '५', 6 => '६', 7 => '७', 8 => '८', 9 => '९', + ), + ); + + /** + * Creaes a NumberFormatter instance. + * + * @param NumberFormatInterface $numberFormat The number format. + * @param int $style The formatting style. + * + * @throws InvalidArgumentException + */ + public function __construct(NumberFormatInterface $numberFormat, $style = self::DECIMAL) + { + $availablePatterns = array( + self::DECIMAL => $numberFormat->getDecimalPattern(), + self::PERCENT => $numberFormat->getPercentPattern(), + self::CURRENCY => $numberFormat->getCurrencyPattern(), + self::CURRENCY_ACCOUNTING => $numberFormat->getAccountingCurrencyPattern(), + ); + if (!array_key_exists($style, $availablePatterns)) { + // Unknown type. + throw new InvalidArgumentException('Unknown format style provided to NumberFormatter::__construct().'); + } + + // Split the selected pattern into positive and negative patterns. + $patterns = explode(';', $availablePatterns[$style]); + if (!isset($patterns[1])) { + // No explicit negative pattern was provided, construct it. + $patterns[1] = '-' . $patterns[0]; + } + + $this->numberFormat = $numberFormat; + $this->positivePattern = $patterns[0]; + $this->negativePattern = $patterns[1]; + $this->groupingUsed = (strpos($this->positivePattern, ',') !== false); + // This pattern has number groups, parse them. + if ($this->groupingUsed) { + preg_match('/#+0/', $this->positivePattern, $primaryGroupMatches); + $this->primaryGroupSize = $this->secondaryGroupSize = strlen($primaryGroupMatches[0]); + $numberGroups = explode(',', $this->positivePattern); + if (count($numberGroups) > 2) { + // This pattern has a distinct secondary group size. + $this->secondaryGroupSize = strlen($numberGroups[1]); + } + } + + // Initialize the fraction digit settings for decimal and percent + // styles only. The currency ones will default to the currency values. + if (in_array($style, array(self::DECIMAL, self::PERCENT))) { + $this->minimumFractionDigits = 0; + $this->maximumFractionDigits = 3; + } + $this->currencyDisplay = self::CURRENCY_DISPLAY_SYMBOL; + } + + /** + * {@inheritdoc} + */ + public function format($value) + { + if (!is_numeric($value)) { + $message = sprintf('The provided value "%s" must be a valid number or numeric string.', $value); + throw new InvalidArgumentException($message); + } + + // Ensure that the value is positive and has the right number of digits. + $negative = (bccomp('0', $value, 12) == 1); + $signMultiplier = $negative ? '-1' : '1'; + $value = bcdiv($value, $signMultiplier, $this->maximumFractionDigits); + // Split the number into major and minor digits. + $valueParts = explode('.', $value); + $majorDigits = $valueParts[0]; + // Account for maximumFractionDigits = 0, where the number won't + // have a decimal point, and $valueParts[1] won't be set. + $minorDigits = isset($valueParts[1]) ? $valueParts[1] : ''; + + if ($this->groupingUsed) { + // Reverse the major digits, since they are grouped from the right. + $majorDigits = array_reverse(str_split($majorDigits)); + // Group the major digits. + $groups = array(); + $groups[] = array_splice($majorDigits, 0, $this->primaryGroupSize); + while (!empty($majorDigits)) { + $groups[] = array_splice($majorDigits, 0, $this->secondaryGroupSize); + } + // Reverse the groups and the digits inside of them. + $groups = array_reverse($groups); + foreach ($groups as &$group) { + $group = implode(array_reverse($group)); + } + // Reconstruct the major digits. + $majorDigits = implode(',', $groups); + } + + if ($this->minimumFractionDigits < $this->maximumFractionDigits) { + // Strip any trailing zeroes. + $minorDigits = rtrim($minorDigits, '0'); + if (strlen($minorDigits) < $this->minimumFractionDigits) { + // Now there are too few digits, re-add trailing zeroes + // until the desired length is reached. + $neededZeroes = $this->minimumFractionDigits - strlen($minorDigits); + $minorDigits .= str_repeat('0', $neededZeroes); + } + } + + // Assemble the final number and insert it into the pattern. + $value = $minorDigits ? $majorDigits . '.' . $minorDigits : $majorDigits; + $pattern = $negative ? $this->negativePattern : $this->positivePattern; + $value = preg_replace('/#(?:[\.,]#+)*0(?:[,\.][0#]+)*/', $value, $pattern); + + // Localize the number. + $value = $this->replaceDigits($value); + $value = $this->replaceSymbols($value); + + return $value; + } + + /** + * {@inheritdoc} + */ + public function formatCurrency($value, CurrencyInterface $currency) + { + // Use the currency defaults if the values weren't set by the caller. + $resetMinimumFractionDigits = $resetMaximumFractionDigits = false; + if (!isset($this->minimumFractionDigits)) { + $this->minimumFractionDigits = $currency->getFractionDigits(); + $resetMinimumFractionDigits = true; + } + if (!isset($this->maximumFractionDigits)) { + $this->maximumFractionDigits = $currency->getFractionDigits(); + $resetMaximumFractionDigits = true; + } + + // Format the decimal part of the value first. + $value = $this->format($value); + + // Reset the fraction digit settings, so that they don't affect + // future formattings with different currencies. + if ($resetMinimumFractionDigits) { + $this->minimumFractionDigits = null; + } + if ($resetMaximumFractionDigits) { + $this->maximumFractionDigits = null; + } + + // Determine whether to show the currency symbol or the currency code. + if ($this->currencyDisplay == self::CURRENCY_DISPLAY_SYMBOL) { + $symbol = $currency->getSymbol(); + } else { + $symbol = $currency->getCurrencyCode(); + } + + return str_replace('¤', $symbol, $value); + } + + /** + * {@inheritdoc} + */ + public function parseCurrency($value, CurrencyInterface $currency) + { + $replacements = array( + // Convert the localized symbols back to their original form. + $this->numberFormat->getDecimalSeparator() => '.', + $this->numberFormat->getPlusSign() => '+', + $this->numberFormat->getMinusSign() => '-', + + // Strip any grouping separators, the currency code or symbol. + $this->numberFormat->getGroupingSeparator() => '', + $currency->getCurrencyCode() => '', + $currency->getSymbol() => '', + + // Strip whitespace (spaces and non-breaking spaces). + ' ' => '', + chr(0xC2) . chr(0xA0) => '', + ); + $numberingSystem = $this->numberFormat->getNumberingSystem(); + if (isset($this->digits[$numberingSystem])) { + // Convert the localized digits back to latin. + $replacements += array_flip($this->digits[$numberingSystem]); + } + + $value = strtr($value, $replacements); + if (substr($value, 0, 1) == '(' && substr($value, -1, 1) == ')') { + // This is an accounting formatted negative number. + $value = '-' . str_replace(array('(', ')'), '', $value); + } + + return is_numeric($value) ? $value : false; + } + + /** + * Replaces digits with their localized equivalents. + * + * @param string $value The value being formatted. + * + * @return string + */ + protected function replaceDigits($value) + { + $numberingSystem = $this->numberFormat->getNumberingSystem(); + if (isset($this->digits[$numberingSystem])) { + $value = strtr($value, $this->digits[$numberingSystem]); + } + + return $value; + } + + /** + * Replaces number symbols with their localized equivalents. + * + * @param string $value The value being formatted. + * + * @return string + * + * @see http://cldr.unicode.org/translation/number-symbols + */ + protected function replaceSymbols($value) + { + $replacements = array( + '.' => $this->numberFormat->getDecimalSeparator(), + ',' => $this->numberFormat->getGroupingSeparator(), + '+' => $this->numberFormat->getPlusSign(), + '-' => $this->numberFormat->getMinusSign(), + '%' => $this->numberFormat->getPercentSign(), + ); + + return strtr($value, $replacements); + } + + /** + * {@inheritdoc} + */ + public function getNumberFormat() + { + return $this->numberFormat; + } + + /** + * {@inheritdoc} + */ + public function getMinimumFractionDigits() + { + return $this->minimumFractionDigits; + } + + /** + * {@inheritdoc} + */ + public function setMinimumFractionDigits($minimumFractionDigits) + { + $this->minimumFractionDigits = $minimumFractionDigits; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getMaximumFractionDigits() + { + return $this->maximumFractionDigits; + } + + /** + * {@inheritdoc} + */ + public function setMaximumFractionDigits($maximumFractionDigits) + { + $this->maximumFractionDigits = $maximumFractionDigits; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function isGroupingUsed() + { + return $this->groupingUsed; + } + + /** + * {@inheritdoc} + */ + public function setGroupingUsed($groupingUsed) + { + $this->groupingUsed = $groupingUsed; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCurrencyDisplay() + { + return $this->currencyDisplay; + } + + /** + * {@inheritdoc} + */ + public function setCurrencyDisplay($currencyDisplay) + { + $this->currencyDisplay = $currencyDisplay; + + return $this; + } +} diff --git a/library/intl/src/Formatter/NumberFormatterInterface.php b/library/intl/src/Formatter/NumberFormatterInterface.php new file mode 100644 index 000000000..721107555 --- /dev/null +++ b/library/intl/src/Formatter/NumberFormatterInterface.php @@ -0,0 +1,134 @@ +getLanguageCode(); + } + + /** + * {@inheritdoc} + */ + public function getLanguageCode() + { + return $this->languageCode; + } + + /** + * {@inheritdoc} + */ + public function setLanguageCode($languageCode) + { + $this->languageCode = $languageCode; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->name; + } + + /** + * {@inheritdoc} + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getLocale() + { + return $this->locale; + } + + /** + * {@inheritdoc} + */ + public function setLocale($locale) + { + $this->locale = $locale; + + return $this; + } +} diff --git a/library/intl/src/Language/LanguageInterface.php b/library/intl/src/Language/LanguageInterface.php new file mode 100644 index 000000000..612389142 --- /dev/null +++ b/library/intl/src/Language/LanguageInterface.php @@ -0,0 +1,37 @@ +definitionPath = $definitionPath ? $definitionPath : __DIR__ . '/../../resources/language/'; + } + + /** + * {@inheritdoc} + */ + public function get($languageCode, $locale = null, $fallbackLocale = null) + { + $locale = $this->resolveLocale($locale, $fallbackLocale); + $definitions = $this->loadDefinitions($locale); + if (!isset($definitions[$languageCode])) { + throw new UnknownLanguageException($languageCode); + } + + return $this->createLanguageFromDefinition($definitions[$languageCode], $locale); + } + + /** + * {@inheritdoc} + */ + public function getAll($locale = null, $fallbackLocale = null) + { + $locale = $this->resolveLocale($locale, $fallbackLocale); + $definitions = $this->loadDefinitions($locale); + $languages = array(); + foreach ($definitions as $languageCode => $definition) { + $languages[$languageCode] = $this->createLanguageFromDefinition($definition, $locale); + } + + return $languages; + } + + /** + * Loads the language definitions for the provided locale. + * + * @param string $locale The desired locale. + * + * @return array + */ + protected function loadDefinitions($locale) + { + if (!isset($this->definitions[$locale])) { + $filename = $this->definitionPath . $locale . '.json'; + $this->definitions[$locale] = json_decode(file_get_contents($filename), true); + } + + return $this->definitions[$locale]; + } + + /** + * Creates a language object from the provided definition. + * + * @param array $definition The language definition. + * @param string $locale The locale of the language definition. + * + * @return Language + */ + protected function createLanguageFromDefinition(array $definition, $locale) + { + $language = new Language(); + $language->setLanguageCode($definition['code']); + $language->setName($definition['name']); + $language->setLocale($locale); + + return $language; + } +} diff --git a/library/intl/src/Language/LanguageRepositoryInterface.php b/library/intl/src/Language/LanguageRepositoryInterface.php new file mode 100644 index 000000000..ebdc0200a --- /dev/null +++ b/library/intl/src/Language/LanguageRepositoryInterface.php @@ -0,0 +1,31 @@ +getLocaleVariants($locale); + // A fallback locale was provided, add it to the end of the chain. + 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; + } + + /** + * Returns 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 = array(); + $localeParts = explode('-', $locale); + while (!empty($localeParts)) { + $localeVariants[] = implode('-', $localeParts); + array_pop($localeParts); + } + + return $localeVariants; + } +} diff --git a/library/intl/src/NumberFormat/NumberFormat.php b/library/intl/src/NumberFormat/NumberFormat.php new file mode 100644 index 000000000..0c512b7ab --- /dev/null +++ b/library/intl/src/NumberFormat/NumberFormat.php @@ -0,0 +1,269 @@ +locale; + } + + /** + * {@inheritdoc} + */ + public function setLocale($locale) + { + $this->locale = $locale; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getNumberingSystem() + { + return $this->numberingSystem; + } + + /** + * {@inheritdoc} + */ + public function setNumberingSystem($numberingSystem) + { + $this->numberingSystem = $numberingSystem; + } + + /** + * {@inheritdoc} + */ + public function getDecimalSeparator() + { + return $this->decimalSeparator; + } + + /** + * {@inheritdoc} + */ + public function setDecimalSeparator($decimalSeparator) + { + $this->decimalSeparator = $decimalSeparator; + } + + /** + * {@inheritdoc} + */ + public function getGroupingSeparator() + { + return $this->groupingSeparator; + } + + /** + * {@inheritdoc} + */ + public function setGroupingSeparator($groupingSeparator) + { + $this->groupingSeparator = $groupingSeparator; + } + + /** + * {@inheritdoc} + */ + public function getPlusSign() + { + return $this->plusSign; + } + + /** + * {@inheritdoc} + */ + public function setPlusSign($plusSign) + { + $this->plusSign = $plusSign; + } + + /** + * {@inheritdoc} + */ + public function getMinusSign() + { + return $this->minusSign; + } + + /** + * {@inheritdoc} + */ + public function setMinusSign($minusSign) + { + $this->minusSign = $minusSign; + } + + /** + * {@inheritdoc} + */ + public function getPercentSign() + { + return $this->percentSign; + } + + /** + * {@inheritdoc} + */ + public function setPercentSign($percentSign) + { + $this->percentSign = $percentSign; + } + + /** + * {@inheritdoc} + */ + public function getDecimalPattern() + { + return $this->decimalPattern; + } + + /** + * {@inheritdoc} + */ + public function setDecimalPattern($decimalPattern) + { + $this->decimalPattern = $decimalPattern; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getPercentPattern() + { + return $this->percentPattern; + } + + /** + * {@inheritdoc} + */ + public function setPercentPattern($percentPattern) + { + $this->percentPattern = $percentPattern; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCurrencyPattern() + { + return $this->currencyPattern; + } + + /** + * {@inheritdoc} + */ + public function setCurrencyPattern($currencyPattern) + { + $this->currencyPattern = $currencyPattern; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getAccountingCurrencyPattern() + { + return $this->accountingCurrencyPattern; + } + + /** + * {@inheritdoc} + */ + public function setAccountingCurrencyPattern($accountingCurrencyPattern) + { + $this->accountingCurrencyPattern = $accountingCurrencyPattern; + + return $this; + } +} diff --git a/library/intl/src/NumberFormat/NumberFormatInterface.php b/library/intl/src/NumberFormat/NumberFormatInterface.php new file mode 100644 index 000000000..fa382df70 --- /dev/null +++ b/library/intl/src/NumberFormat/NumberFormatInterface.php @@ -0,0 +1,185 @@ +definitionPath = $definitionPath ? $definitionPath : __DIR__ . '/../../resources/number_format/'; + } + + /** + * {@inheritdoc} + */ + public function get($locale, $fallbackLocale = null) + { + $locale = $this->resolveLocale($locale, $fallbackLocale); + if (!isset($this->definitions[$locale])) { + $filename = $this->definitionPath . $locale . '.json'; + $this->definitions[$locale] = json_decode(file_get_contents($filename), true); + } + + return $this->createNumberFormatFromDefinition($this->definitions[$locale], $locale); + } + + /** + * Creates a number format object from the provided definition. + * + * @param array $definition The number format definition. + * @param string $locale The locale of the number format definition. + * + * @return NumberFormat + */ + protected function createNumberFormatFromDefinition(array $definition, $locale) + { + if (!isset($definition['decimal_separator'])) { + $definition['decimal_separator'] = '.'; + } + if (!isset($definition['grouping_separator'])) { + $definition['grouping_separator'] = ','; + } + if (!isset($definition['plus_sign'])) { + $definition['plus_sign'] = '+'; + } + if (!isset($definition['minus_sign'])) { + $definition['minus_sign'] = '-'; + } + if (!isset($definition['percent_sign'])) { + $definition['percent_sign'] = '%'; + } + + $numberFormat = new NumberFormat(); + $numberFormat->setLocale($locale); + $numberFormat->setNumberingSystem($definition['numbering_system']); + $numberFormat->setDecimalSeparator($definition['decimal_separator']); + $numberFormat->setGroupingSeparator($definition['grouping_separator']); + $numberFormat->setPlusSign($definition['plus_sign']); + $numberFormat->setMinusSign($definition['minus_sign']); + $numberFormat->setPercentSign($definition['percent_sign']); + $numberFormat->setDecimalPattern($definition['decimal_pattern']); + $numberFormat->setPercentPattern($definition['percent_pattern']); + $numberFormat->setCurrencyPattern($definition['currency_pattern']); + $numberFormat->setAccountingCurrencyPattern($definition['accounting_currency_pattern']); + + return $numberFormat; + } +} diff --git a/library/intl/src/NumberFormat/NumberFormatRepositoryInterface.php b/library/intl/src/NumberFormat/NumberFormatRepositoryInterface.php new file mode 100644 index 000000000..ff162b522 --- /dev/null +++ b/library/intl/src/NumberFormat/NumberFormatRepositoryInterface.php @@ -0,0 +1,19 @@ +