From 66832c41e9fff481c20ca219b3cc0a4e53b8b551 Mon Sep 17 00:00:00 2001 From: Klaus Weidenbach Date: Wed, 25 Oct 2017 23:21:07 +0200 Subject: :arrow_up: Update intl library. Update intl library from v0.4? (2014) to v0.7.4 (2016). Use global composer autoloader now. --- vendor/commerceguys/intl/src/Calculator.php | 247 ++++++++++++ vendor/commerceguys/intl/src/Country/Country.php | 168 ++++++++ .../intl/src/Country/CountryEntityInterface.php | 51 +++ .../intl/src/Country/CountryInterface.php | 61 +++ .../intl/src/Country/CountryRepository.php | 143 +++++++ .../src/Country/CountryRepositoryInterface.php | 41 ++ vendor/commerceguys/intl/src/Currency/Currency.php | 168 ++++++++ .../intl/src/Currency/CurrencyEntityInterface.php | 51 +++ .../intl/src/Currency/CurrencyInterface.php | 47 +++ .../intl/src/Currency/CurrencyRepository.php | 144 +++++++ .../src/Currency/CurrencyRepositoryInterface.php | 41 ++ .../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 + .../intl/src/Formatter/NumberFormatter.php | 421 +++++++++++++++++++++ .../src/Formatter/NumberFormatterInterface.php | 151 ++++++++ vendor/commerceguys/intl/src/Language/Language.php | 91 +++++ .../intl/src/Language/LanguageEntityInterface.php | 24 ++ .../intl/src/Language/LanguageInterface.php | 23 ++ .../intl/src/Language/LanguageRepository.php | 115 ++++++ .../src/Language/LanguageRepositoryInterface.php | 41 ++ .../commerceguys/intl/src/LocaleResolverTrait.php | 244 ++++++++++++ .../intl/src/NumberFormat/NumberFormat.php | 269 +++++++++++++ .../NumberFormat/NumberFormatEntityInterface.php | 107 ++++++ .../src/NumberFormat/NumberFormatInterface.php | 106 ++++++ .../src/NumberFormat/NumberFormatRepository.php | 91 +++++ .../NumberFormatRepositoryInterface.php | 19 + 30 files changed, 2925 insertions(+) create mode 100644 vendor/commerceguys/intl/src/Calculator.php create mode 100644 vendor/commerceguys/intl/src/Country/Country.php create mode 100644 vendor/commerceguys/intl/src/Country/CountryEntityInterface.php create mode 100644 vendor/commerceguys/intl/src/Country/CountryInterface.php create mode 100644 vendor/commerceguys/intl/src/Country/CountryRepository.php create mode 100644 vendor/commerceguys/intl/src/Country/CountryRepositoryInterface.php create mode 100644 vendor/commerceguys/intl/src/Currency/Currency.php create mode 100644 vendor/commerceguys/intl/src/Currency/CurrencyEntityInterface.php create mode 100644 vendor/commerceguys/intl/src/Currency/CurrencyInterface.php create mode 100644 vendor/commerceguys/intl/src/Currency/CurrencyRepository.php create mode 100644 vendor/commerceguys/intl/src/Currency/CurrencyRepositoryInterface.php create mode 100644 vendor/commerceguys/intl/src/Exception/ExceptionInterface.php create mode 100644 vendor/commerceguys/intl/src/Exception/InvalidArgumentException.php create mode 100644 vendor/commerceguys/intl/src/Exception/UnknownCountryException.php create mode 100644 vendor/commerceguys/intl/src/Exception/UnknownCurrencyException.php create mode 100644 vendor/commerceguys/intl/src/Exception/UnknownLanguageException.php create mode 100644 vendor/commerceguys/intl/src/Exception/UnknownLocaleException.php create mode 100644 vendor/commerceguys/intl/src/Formatter/NumberFormatter.php create mode 100644 vendor/commerceguys/intl/src/Formatter/NumberFormatterInterface.php create mode 100644 vendor/commerceguys/intl/src/Language/Language.php create mode 100644 vendor/commerceguys/intl/src/Language/LanguageEntityInterface.php create mode 100644 vendor/commerceguys/intl/src/Language/LanguageInterface.php create mode 100644 vendor/commerceguys/intl/src/Language/LanguageRepository.php create mode 100644 vendor/commerceguys/intl/src/Language/LanguageRepositoryInterface.php create mode 100644 vendor/commerceguys/intl/src/LocaleResolverTrait.php create mode 100644 vendor/commerceguys/intl/src/NumberFormat/NumberFormat.php create mode 100644 vendor/commerceguys/intl/src/NumberFormat/NumberFormatEntityInterface.php create mode 100644 vendor/commerceguys/intl/src/NumberFormat/NumberFormatInterface.php create mode 100644 vendor/commerceguys/intl/src/NumberFormat/NumberFormatRepository.php create mode 100644 vendor/commerceguys/intl/src/NumberFormat/NumberFormatRepositoryInterface.php (limited to 'vendor/commerceguys/intl/src') diff --git a/vendor/commerceguys/intl/src/Calculator.php b/vendor/commerceguys/intl/src/Calculator.php new file mode 100644 index 000000000..e00a564c1 --- /dev/null +++ b/vendor/commerceguys/intl/src/Calculator.php @@ -0,0 +1,247 @@ + 0). + * + * @param string $number The number. + * @param int $precision The number of decimals to round to. + * @param int $mode The rounding mode. One of the following constants: + * PHP_ROUND_HALF_UP, PHP_ROUND_HALF_DOWN, + * PHP_ROUND_HALF_EVEN, PHP_ROUND_HALF_ODD. + * + * @return string The rounded number. + * + * @throws \InvalidArgumentException + */ + public static function round($number, $precision = 0, $mode = PHP_ROUND_HALF_UP) + { + self::assertNumberFormat($number); + if (!is_numeric($precision) || $precision < 0) { + throw new \InvalidArgumentException('The provided precision should be a positive number'); + } + + // Round the number in both directions (up/down) before choosing one. + $rounding_increment = bcdiv('1', pow(10, $precision), $precision); + if (self::compare($number, '0') == 1) { + $rounded_up = bcadd($number, $rounding_increment, $precision); + } else { + $rounded_up = bcsub($number, $rounding_increment, $precision); + } + $rounded_down = bcsub($number, 0, $precision); + // The rounding direction is based on the first decimal after $precision. + $number_parts = explode('.', $number); + $decimals = !empty($number_parts[1]) ? $number_parts[1] : '0'; + $relevant_decimal = isset($decimals[$precision]) ? $decimals[$precision] : 0; + if ($relevant_decimal < 5) { + $number = $rounded_down; + } elseif ($relevant_decimal == 5) { + if ($mode == PHP_ROUND_HALF_UP) { + $number = $rounded_up; + } elseif ($mode == PHP_ROUND_HALF_DOWN) { + $number = $rounded_down; + } elseif ($mode == PHP_ROUND_HALF_EVEN) { + $integer = bcmul($rounded_up, pow(10, $precision), 0); + $number = bcmod($integer, '2') == 0 ? $rounded_up : $rounded_down; + } elseif ($mode == PHP_ROUND_HALF_ODD) { + $integer = bcmul($rounded_up, pow(10, $precision), 0); + $number = bcmod($integer, '2') != 0 ? $rounded_up : $rounded_down; + } + } elseif ($relevant_decimal > 5) { + $number = $rounded_up; + } + + return $number; + } + + /** + * Compares the first number to the second number. + * + * @param string $first_number The first number. + * @param string $second_number The second number. + * @param int $scale The maximum number of digits after the + * decimal place. Any digit after $scale will + * be truncated. + * + * @return int 0 if both numbers are equal, 1 if the first one is greater, + * -1 otherwise. + */ + public static function compare($first_number, $second_number, $scale = 6) + { + self::assertNumberFormat($first_number); + self::assertNumberFormat($second_number); + + return bccomp($first_number, $second_number, $scale); + } + + /** + * Trims the given number. + * + * By default bcmath returns numbers with the number of digits according + * to $scale. This means that bcadd('2', '2', 6) will return '4.00000'. + * Trimming the number removes the excess zeroes. + * + * @param string $number The number to trim. + * + * @return string The trimmed number. + */ + public static function trim($number) + { + if (strpos($number, '.') != false) { + // The number is decimal, strip trailing zeroes. + // If no digits remain after the decimal point, strip it as well. + $number = rtrim($number, '0'); + $number = rtrim($number, '.'); + } + + return $number; + } + + /** + * Assert that the given number is a numeric string value. + * + * @param string $number The number to check. + * + * @throws \InvalidArgumentException + */ + public static function assertNumberFormat($number) + { + if (is_float($number)) { + throw new \InvalidArgumentException(sprintf('The provided value "%s" must be a string, not a float.', $number)); + } + if (!is_numeric($number)) { + throw new \InvalidArgumentException(sprintf('The provided value "%s" is not a numeric value.', $number)); + } + } +} diff --git a/vendor/commerceguys/intl/src/Country/Country.php b/vendor/commerceguys/intl/src/Country/Country.php new file mode 100644 index 000000000..7063e7d58 --- /dev/null +++ b/vendor/commerceguys/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 getCurrencyCode() + { + return $this->currencyCode; + } + + /** + * {@inheritdoc} + */ + public function setCurrencyCode($currencyCode) + { + $this->currencyCode = $currencyCode; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getLocale() + { + return $this->locale; + } + + /** + * {@inheritdoc} + */ + public function setLocale($locale) + { + $this->locale = $locale; + + return $this; + } +} diff --git a/vendor/commerceguys/intl/src/Country/CountryEntityInterface.php b/vendor/commerceguys/intl/src/Country/CountryEntityInterface.php new file mode 100644 index 000000000..b22bcd42f --- /dev/null +++ b/vendor/commerceguys/intl/src/Country/CountryEntityInterface.php @@ -0,0 +1,51 @@ +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($countryCode, $definitions[$countryCode], $locale); + } + + /** + * {@inheritdoc} + */ + public function getAll($locale = null, $fallbackLocale = null) + { + $locale = $this->resolveLocale($locale, $fallbackLocale); + $definitions = $this->loadDefinitions($locale); + $countries = []; + foreach ($definitions as $countryCode => $definition) { + $countries[$countryCode] = $this->createCountryFromDefinition($countryCode, $definition, $locale); + } + + return $countries; + } + + /** + * {@inheritdoc} + */ + public function getList($locale = null, $fallbackLocale = null) + { + $locale = $this->resolveLocale($locale, $fallbackLocale); + $definitions = $this->loadDefinitions($locale); + $list = []; + foreach ($definitions as $countryCode => $definition) { + $list[$countryCode] = $definition['name']; + } + + return $list; + } + + /** + * 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 string $countryCode The country code. + * @param array $definition The country definition. + * @param string $locale The locale of the country definition. + * + * @return Country + */ + protected function createCountryFromDefinition($countryCode, array $definition, $locale) + { + $country = new Country(); + $setValues = \Closure::bind(function ($countryCode, $definition, $locale) { + $this->countryCode = $countryCode; + $this->name = $definition['name']; + $this->locale = $locale; + if (isset($definition['three_letter_code'])) { + $this->threeLetterCode = $definition['three_letter_code']; + } + if (isset($definition['numeric_code'])) { + $this->numericCode = $definition['numeric_code']; + } + if (isset($definition['currency_code'])) { + $this->currencyCode = $definition['currency_code']; + } + }, $country, '\CommerceGuys\Intl\Country\Country'); + $setValues($countryCode, $definition, $locale); + + return $country; + } +} diff --git a/vendor/commerceguys/intl/src/Country/CountryRepositoryInterface.php b/vendor/commerceguys/intl/src/Country/CountryRepositoryInterface.php new file mode 100644 index 000000000..fbcd5551e --- /dev/null +++ b/vendor/commerceguys/intl/src/Country/CountryRepositoryInterface.php @@ -0,0 +1,41 @@ +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/vendor/commerceguys/intl/src/Currency/CurrencyEntityInterface.php b/vendor/commerceguys/intl/src/Currency/CurrencyEntityInterface.php new file mode 100644 index 000000000..85d4ab83d --- /dev/null +++ b/vendor/commerceguys/intl/src/Currency/CurrencyEntityInterface.php @@ -0,0 +1,51 @@ +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($currencyCode, $definitions[$currencyCode], $locale); + } + + /** + * {@inheritdoc} + */ + public function getAll($locale = null, $fallbackLocale = null) + { + $locale = $this->resolveLocale($locale, $fallbackLocale); + $definitions = $this->loadDefinitions($locale); + $currencies = []; + foreach ($definitions as $currencyCode => $definition) { + $currencies[$currencyCode] = $this->createCurrencyFromDefinition($currencyCode, $definition, $locale); + } + + return $currencies; + } + + /** + * {@inheritdoc} + */ + public function getList($locale = null, $fallbackLocale = null) + { + $locale = $this->resolveLocale($locale, $fallbackLocale); + $definitions = $this->loadDefinitions($locale); + $list = []; + foreach ($definitions as $currencyCode => $definition) { + $list[$currencyCode] = $definition['name']; + } + + return $list; + } + + /** + * 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 string $currencyCode The currency code. + * @param array $definition The currency definition. + * @param string $locale The locale of the currency definition. + * + * @return Currency + */ + protected function createCurrencyFromDefinition($currencyCode, array $definition, $locale) + { + if (!isset($definition['symbol'])) { + $definition['symbol'] = $currencyCode; + } + if (!isset($definition['fraction_digits'])) { + $definition['fraction_digits'] = 2; + } + + $currency = new Currency(); + $setValues = \Closure::bind(function ($currencyCode, $definition, $locale) { + $this->currencyCode = $currencyCode; + $this->name = $definition['name']; + $this->numericCode = $definition['numeric_code']; + $this->symbol = $definition['symbol']; + $this->fractionDigits = $definition['fraction_digits']; + $this->locale = $locale; + }, $currency, '\CommerceGuys\Intl\Currency\Currency'); + $setValues($currencyCode, $definition, $locale); + + return $currency; + } +} diff --git a/vendor/commerceguys/intl/src/Currency/CurrencyRepositoryInterface.php b/vendor/commerceguys/intl/src/Currency/CurrencyRepositoryInterface.php new file mode 100644 index 000000000..f0a091969 --- /dev/null +++ b/vendor/commerceguys/intl/src/Currency/CurrencyRepositoryInterface.php @@ -0,0 +1,41 @@ + [ + 0 => '٠', 1 => '١', 2 => '٢', 3 => '٣', 4 => '٤', + 5 => '٥', 6 => '٦', 7 => '٧', 8 => '٨', 9 => '٩', + ], + NumberFormatInterface::NUMBERING_SYSTEM_ARABIC_EXTENDED => [ + 0 => '۰', 1 => '۱', 2 => '۲', 3 => '۳', 4 => '۴', + 5 => '۵', 6 => '۶', 7 => '۷', 8 => '۸', 9 => '۹', + ], + NumberFormatInterface::NUMBERING_SYSTEM_BENGALI => [ + 0 => '০', 1 => '১', 2 => '২', 3 => '৩', 4 => '৪', + 5 => '৫', 6 => '৬', 7 => '৭', 8 => '৮', 9 => '৯', + ], + NumberFormatInterface::NUMBERING_SYSTEM_DEVANAGARI => [ + 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 + * @throws \RuntimeException + */ + public function __construct(NumberFormatInterface $numberFormat, $style = self::DECIMAL) + { + if (!extension_loaded('bcmath')) { + throw new \RuntimeException('The bcmath extension is required by NumberFormatter.'); + } + $availablePatterns = [ + 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, [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 = []; + $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 = strlen($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 parse($value) + { + $replacements = [ + $this->numberFormat->getGroupingSeparator() => '', + // Convert the localized symbols back to their original form. + $this->numberFormat->getDecimalSeparator() => '.', + $this->numberFormat->getPlusSign() => '+', + $this->numberFormat->getMinusSign() => '-', + + // 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(['(', ')'], '', $value); + } + + return is_numeric($value) ? $value : false; + } + + /** + * {@inheritdoc} + */ + public function parseCurrency($value, CurrencyInterface $currency) + { + $replacements = [ + // Strip the currency code or symbol. + $currency->getCurrencyCode() => '', + $currency->getSymbol() => '', + ]; + $value = strtr($value, $replacements); + + return $this->parse($value); + } + + /** + * 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 = [ + '.' => $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/vendor/commerceguys/intl/src/Formatter/NumberFormatterInterface.php b/vendor/commerceguys/intl/src/Formatter/NumberFormatterInterface.php new file mode 100644 index 000000000..3a510be2a --- /dev/null +++ b/vendor/commerceguys/intl/src/Formatter/NumberFormatterInterface.php @@ -0,0 +1,151 @@ +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/vendor/commerceguys/intl/src/Language/LanguageEntityInterface.php b/vendor/commerceguys/intl/src/Language/LanguageEntityInterface.php new file mode 100644 index 000000000..e36e0bf77 --- /dev/null +++ b/vendor/commerceguys/intl/src/Language/LanguageEntityInterface.php @@ -0,0 +1,24 @@ +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($languageCode, $definitions[$languageCode], $locale); + } + + /** + * {@inheritdoc} + */ + public function getAll($locale = null, $fallbackLocale = null) + { + $locale = $this->resolveLocale($locale, $fallbackLocale); + $definitions = $this->loadDefinitions($locale); + $languages = []; + foreach ($definitions as $languageCode => $definition) { + $languages[$languageCode] = $this->createLanguageFromDefinition($languageCode, $definition, $locale); + } + + return $languages; + } + + /** + * {@inheritdoc} + */ + public function getList($locale = null, $fallbackLocale = null) + { + $locale = $this->resolveLocale($locale, $fallbackLocale); + $definitions = $this->loadDefinitions($locale); + $list = []; + foreach ($definitions as $languageCode => $definition) { + $list[$languageCode] = $definition['name']; + } + + return $list; + } + + /** + * 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 string $languageCode The language code. + * @param array $definition The language definition. + * @param string $locale The locale of the language definition. + * + * @return Language + */ + protected function createLanguageFromDefinition($languageCode, array $definition, $locale) + { + $language = new Language(); + $setValues = \Closure::bind(function ($languageCode, $definition, $locale) { + $this->languageCode = $languageCode; + $this->name = $definition['name']; + $this->locale = $locale; + }, $language, '\CommerceGuys\Intl\Language\Language'); + $setValues($languageCode, $definition, $locale); + + return $language; + } +} diff --git a/vendor/commerceguys/intl/src/Language/LanguageRepositoryInterface.php b/vendor/commerceguys/intl/src/Language/LanguageRepositoryInterface.php new file mode 100644 index 000000000..dd14250e0 --- /dev/null +++ b/vendor/commerceguys/intl/src/Language/LanguageRepositoryInterface.php @@ -0,0 +1,41 @@ + '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; + } +} diff --git a/vendor/commerceguys/intl/src/NumberFormat/NumberFormat.php b/vendor/commerceguys/intl/src/NumberFormat/NumberFormat.php new file mode 100644 index 000000000..077f6721f --- /dev/null +++ b/vendor/commerceguys/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/vendor/commerceguys/intl/src/NumberFormat/NumberFormatEntityInterface.php b/vendor/commerceguys/intl/src/NumberFormat/NumberFormatEntityInterface.php new file mode 100644 index 000000000..debafd6ba --- /dev/null +++ b/vendor/commerceguys/intl/src/NumberFormat/NumberFormatEntityInterface.php @@ -0,0 +1,107 @@ +definitionPath = $definitionPath ? $definitionPath : __DIR__ . '/../../resources/number_format/'; + } + + /** + * {@inheritdoc} + */ + public function get($locale, $fallbackLocale = null) + { + $locale = $this->resolveLocale($locale, $fallbackLocale); + if (!isset($this->numberFormats[$locale])) { + $filename = $this->definitionPath . $locale . '.json'; + $definition = json_decode(file_get_contents($filename), true); + $this->numberFormats[$locale] = $this->createNumberFormatFromDefinition($definition, $locale); + } + + return $this->numberFormats[$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(); + $setValues = \Closure::bind(function ($definition, $locale) { + $this->locale = $locale; + $this->numberingSystem = $definition['numbering_system']; + $this->decimalSeparator = $definition['decimal_separator']; + $this->groupingSeparator = $definition['grouping_separator']; + $this->plusSign = $definition['plus_sign']; + $this->minusSign = $definition['minus_sign']; + $this->percentSign = $definition['percent_sign']; + $this->decimalPattern = $definition['decimal_pattern']; + $this->percentPattern = $definition['percent_pattern']; + $this->currencyPattern = $definition['currency_pattern']; + $this->accountingCurrencyPattern = $definition['accounting_currency_pattern']; + }, $numberFormat, '\CommerceGuys\Intl\NumberFormat\NumberFormat'); + $setValues($definition, $locale); + + return $numberFormat; + } +} diff --git a/vendor/commerceguys/intl/src/NumberFormat/NumberFormatRepositoryInterface.php b/vendor/commerceguys/intl/src/NumberFormat/NumberFormatRepositoryInterface.php new file mode 100644 index 000000000..ff162b522 --- /dev/null +++ b/vendor/commerceguys/intl/src/NumberFormat/NumberFormatRepositoryInterface.php @@ -0,0 +1,19 @@ +