mirror of
https://github.com/twigphp/Twig.git
synced 2026-08-17 12:31:38 +00:00
534 lines
21 KiB
PHP
534 lines
21 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This file is part of Twig.
|
|
*
|
|
* (c) Fabien Potencier
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Twig\Extra\Intl;
|
|
|
|
use Symfony\Component\Intl\Countries;
|
|
use Symfony\Component\Intl\Currencies;
|
|
use Symfony\Component\Intl\Exception\MissingResourceException;
|
|
use Symfony\Component\Intl\Languages;
|
|
use Symfony\Component\Intl\Locales;
|
|
use Symfony\Component\Intl\Scripts;
|
|
use Symfony\Component\Intl\Timezones;
|
|
use Twig\Environment;
|
|
use Twig\Error\RuntimeError;
|
|
use Twig\Extension\AbstractExtension;
|
|
use Twig\Extension\CoreExtension;
|
|
use Twig\TwigFilter;
|
|
use Twig\TwigFunction;
|
|
|
|
final class IntlExtension extends AbstractExtension
|
|
{
|
|
private static function availableDateFormats(): array
|
|
{
|
|
static $formats = null;
|
|
|
|
if (null !== $formats) {
|
|
return $formats;
|
|
}
|
|
|
|
$formats = [
|
|
'none' => \IntlDateFormatter::NONE,
|
|
'short' => \IntlDateFormatter::SHORT,
|
|
'medium' => \IntlDateFormatter::MEDIUM,
|
|
'long' => \IntlDateFormatter::LONG,
|
|
'full' => \IntlDateFormatter::FULL,
|
|
];
|
|
|
|
// Assuming that each `RELATIVE_*` constant are defined when one of them is.
|
|
if (\defined('IntlDateFormatter::RELATIVE_FULL')) {
|
|
$formats = array_merge($formats, [
|
|
'relative_short' => \IntlDateFormatter::RELATIVE_SHORT,
|
|
'relative_medium' => \IntlDateFormatter::RELATIVE_MEDIUM,
|
|
'relative_long' => \IntlDateFormatter::RELATIVE_LONG,
|
|
'relative_full' => \IntlDateFormatter::RELATIVE_FULL,
|
|
]);
|
|
}
|
|
|
|
return $formats;
|
|
}
|
|
|
|
private const TIME_FORMATS = [
|
|
'none' => \IntlDateFormatter::NONE,
|
|
'short' => \IntlDateFormatter::SHORT,
|
|
'medium' => \IntlDateFormatter::MEDIUM,
|
|
'long' => \IntlDateFormatter::LONG,
|
|
'full' => \IntlDateFormatter::FULL,
|
|
];
|
|
private const NUMBER_TYPES = [
|
|
'default' => \NumberFormatter::TYPE_DEFAULT,
|
|
'int32' => \NumberFormatter::TYPE_INT32,
|
|
'int64' => \NumberFormatter::TYPE_INT64,
|
|
'double' => \NumberFormatter::TYPE_DOUBLE,
|
|
];
|
|
private const NUMBER_STYLES = [
|
|
'decimal' => \NumberFormatter::DECIMAL,
|
|
'currency' => \NumberFormatter::CURRENCY,
|
|
'percent' => \NumberFormatter::PERCENT,
|
|
'scientific' => \NumberFormatter::SCIENTIFIC,
|
|
'spellout' => \NumberFormatter::SPELLOUT,
|
|
'ordinal' => \NumberFormatter::ORDINAL,
|
|
'duration' => \NumberFormatter::DURATION,
|
|
];
|
|
private const NUMBER_ATTRIBUTES = [
|
|
'grouping_used' => \NumberFormatter::GROUPING_USED,
|
|
'decimal_always_shown' => \NumberFormatter::DECIMAL_ALWAYS_SHOWN,
|
|
'max_integer_digit' => \NumberFormatter::MAX_INTEGER_DIGITS,
|
|
'min_integer_digit' => \NumberFormatter::MIN_INTEGER_DIGITS,
|
|
'integer_digit' => \NumberFormatter::INTEGER_DIGITS,
|
|
'max_fraction_digit' => \NumberFormatter::MAX_FRACTION_DIGITS,
|
|
'min_fraction_digit' => \NumberFormatter::MIN_FRACTION_DIGITS,
|
|
'fraction_digit' => \NumberFormatter::FRACTION_DIGITS,
|
|
'multiplier' => \NumberFormatter::MULTIPLIER,
|
|
'grouping_size' => \NumberFormatter::GROUPING_SIZE,
|
|
'rounding_mode' => \NumberFormatter::ROUNDING_MODE,
|
|
'rounding_increment' => \NumberFormatter::ROUNDING_INCREMENT,
|
|
'format_width' => \NumberFormatter::FORMAT_WIDTH,
|
|
'padding_position' => \NumberFormatter::PADDING_POSITION,
|
|
'secondary_grouping_size' => \NumberFormatter::SECONDARY_GROUPING_SIZE,
|
|
'significant_digits_used' => \NumberFormatter::SIGNIFICANT_DIGITS_USED,
|
|
'min_significant_digits_used' => \NumberFormatter::MIN_SIGNIFICANT_DIGITS,
|
|
'max_significant_digits_used' => \NumberFormatter::MAX_SIGNIFICANT_DIGITS,
|
|
'lenient_parse' => \NumberFormatter::LENIENT_PARSE,
|
|
];
|
|
private const NUMBER_ROUNDING_ATTRIBUTES = [
|
|
'ceiling' => \NumberFormatter::ROUND_CEILING,
|
|
'floor' => \NumberFormatter::ROUND_FLOOR,
|
|
'down' => \NumberFormatter::ROUND_DOWN,
|
|
'up' => \NumberFormatter::ROUND_UP,
|
|
'halfeven' => \NumberFormatter::ROUND_HALFEVEN,
|
|
'halfdown' => \NumberFormatter::ROUND_HALFDOWN,
|
|
'halfup' => \NumberFormatter::ROUND_HALFUP,
|
|
];
|
|
private const NUMBER_PADDING_ATTRIBUTES = [
|
|
'before_prefix' => \NumberFormatter::PAD_BEFORE_PREFIX,
|
|
'after_prefix' => \NumberFormatter::PAD_AFTER_PREFIX,
|
|
'before_suffix' => \NumberFormatter::PAD_BEFORE_SUFFIX,
|
|
'after_suffix' => \NumberFormatter::PAD_AFTER_SUFFIX,
|
|
];
|
|
private const NUMBER_TEXT_ATTRIBUTES = [
|
|
'positive_prefix' => \NumberFormatter::POSITIVE_PREFIX,
|
|
'positive_suffix' => \NumberFormatter::POSITIVE_SUFFIX,
|
|
'negative_prefix' => \NumberFormatter::NEGATIVE_PREFIX,
|
|
'negative_suffix' => \NumberFormatter::NEGATIVE_SUFFIX,
|
|
'padding_character' => \NumberFormatter::PADDING_CHARACTER,
|
|
'currency_code' => \NumberFormatter::CURRENCY_CODE,
|
|
'default_ruleset' => \NumberFormatter::DEFAULT_RULESET,
|
|
'public_rulesets' => \NumberFormatter::PUBLIC_RULESETS,
|
|
];
|
|
private const NUMBER_SYMBOLS = [
|
|
'decimal_separator' => \NumberFormatter::DECIMAL_SEPARATOR_SYMBOL,
|
|
'grouping_separator' => \NumberFormatter::GROUPING_SEPARATOR_SYMBOL,
|
|
'pattern_separator' => \NumberFormatter::PATTERN_SEPARATOR_SYMBOL,
|
|
'percent' => \NumberFormatter::PERCENT_SYMBOL,
|
|
'zero_digit' => \NumberFormatter::ZERO_DIGIT_SYMBOL,
|
|
'digit' => \NumberFormatter::DIGIT_SYMBOL,
|
|
'minus_sign' => \NumberFormatter::MINUS_SIGN_SYMBOL,
|
|
'plus_sign' => \NumberFormatter::PLUS_SIGN_SYMBOL,
|
|
'currency' => \NumberFormatter::CURRENCY_SYMBOL,
|
|
'intl_currency' => \NumberFormatter::INTL_CURRENCY_SYMBOL,
|
|
'monetary_separator' => \NumberFormatter::MONETARY_SEPARATOR_SYMBOL,
|
|
'exponential' => \NumberFormatter::EXPONENTIAL_SYMBOL,
|
|
'permill' => \NumberFormatter::PERMILL_SYMBOL,
|
|
'pad_escape' => \NumberFormatter::PAD_ESCAPE_SYMBOL,
|
|
'infinity' => \NumberFormatter::INFINITY_SYMBOL,
|
|
'nan' => \NumberFormatter::NAN_SYMBOL,
|
|
'significant_digit' => \NumberFormatter::SIGNIFICANT_DIGIT_SYMBOL,
|
|
'monetary_grouping_separator' => \NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL,
|
|
];
|
|
|
|
private const MAX_CACHED_FORMATTERS = 100;
|
|
|
|
private $dateFormatters = [];
|
|
private $numberFormatters = [];
|
|
private $dateFormatterPrototype;
|
|
private $numberFormatterPrototype;
|
|
|
|
public function __construct(?\IntlDateFormatter $dateFormatterPrototype = null, ?\NumberFormatter $numberFormatterPrototype = null)
|
|
{
|
|
$this->dateFormatterPrototype = $dateFormatterPrototype;
|
|
$this->numberFormatterPrototype = $numberFormatterPrototype;
|
|
}
|
|
|
|
public function getFilters(): array
|
|
{
|
|
return [
|
|
// internationalized names
|
|
new TwigFilter('country_name', [$this, 'getCountryName']),
|
|
new TwigFilter('currency_name', [$this, 'getCurrencyName']),
|
|
new TwigFilter('currency_symbol', [$this, 'getCurrencySymbol']),
|
|
new TwigFilter('language_name', [$this, 'getLanguageName']),
|
|
new TwigFilter('locale_name', [$this, 'getLocaleName']),
|
|
new TwigFilter('timezone_name', [$this, 'getTimezoneName']),
|
|
|
|
// localized formatters
|
|
new TwigFilter('format_currency', [$this, 'formatCurrency']),
|
|
new TwigFilter('format_number', [$this, 'formatNumber']),
|
|
new TwigFilter('format_*_number', [$this, 'formatNumberStyle']),
|
|
new TwigFilter('format_datetime', [$this, 'formatDateTime'], ['needs_environment' => true]),
|
|
new TwigFilter('format_date', [$this, 'formatDate'], ['needs_environment' => true]),
|
|
new TwigFilter('format_time', [$this, 'formatTime'], ['needs_environment' => true]),
|
|
];
|
|
}
|
|
|
|
public function getFunctions(): array
|
|
{
|
|
return [
|
|
// internationalized names
|
|
new TwigFunction('country_timezones', [$this, 'getCountryTimezones']),
|
|
new TwigFunction('language_names', [$this, 'getLanguageNames']),
|
|
new TwigFunction('script_names', [$this, 'getScriptNames']),
|
|
new TwigFunction('country_names', [$this, 'getCountryNames']),
|
|
new TwigFunction('locale_names', [$this, 'getLocaleNames']),
|
|
new TwigFunction('currency_names', [$this, 'getCurrencyNames']),
|
|
new TwigFunction('timezone_names', [$this, 'getTimezoneNames']),
|
|
];
|
|
}
|
|
|
|
public function getCountryName(?string $country, ?string $locale = null): string
|
|
{
|
|
if (null === $country) {
|
|
return '';
|
|
}
|
|
|
|
try {
|
|
return Countries::getName($country, $locale);
|
|
} catch (MissingResourceException $exception) {
|
|
return $country;
|
|
}
|
|
}
|
|
|
|
public function getCurrencyName(?string $currency, ?string $locale = null): string
|
|
{
|
|
if (null === $currency) {
|
|
return '';
|
|
}
|
|
|
|
try {
|
|
return Currencies::getName($currency, $locale);
|
|
} catch (MissingResourceException $exception) {
|
|
return $currency;
|
|
}
|
|
}
|
|
|
|
public function getCurrencySymbol(?string $currency, ?string $locale = null): string
|
|
{
|
|
if (null === $currency) {
|
|
return '';
|
|
}
|
|
|
|
try {
|
|
return Currencies::getSymbol($currency, $locale);
|
|
} catch (MissingResourceException $exception) {
|
|
return $currency;
|
|
}
|
|
}
|
|
|
|
public function getLanguageName(?string $language, ?string $locale = null): string
|
|
{
|
|
if (null === $language) {
|
|
return '';
|
|
}
|
|
|
|
try {
|
|
return Languages::getName($language, $locale);
|
|
} catch (MissingResourceException $exception) {
|
|
return $language;
|
|
}
|
|
}
|
|
|
|
public function getLocaleName(?string $data, ?string $locale = null): string
|
|
{
|
|
if (null === $data) {
|
|
return '';
|
|
}
|
|
|
|
try {
|
|
return Locales::getName($data, $locale);
|
|
} catch (MissingResourceException $exception) {
|
|
return $data;
|
|
}
|
|
}
|
|
|
|
public function getTimezoneName(?string $timezone, ?string $locale = null): string
|
|
{
|
|
if (null === $timezone) {
|
|
return '';
|
|
}
|
|
|
|
try {
|
|
return Timezones::getName($timezone, $locale);
|
|
} catch (MissingResourceException $exception) {
|
|
return $timezone;
|
|
}
|
|
}
|
|
|
|
public function getCountryTimezones(string $country): array
|
|
{
|
|
try {
|
|
return Timezones::forCountryCode($country);
|
|
} catch (MissingResourceException $exception) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
public function getLanguageNames(?string $locale = null): array
|
|
{
|
|
try {
|
|
return Languages::getNames($locale);
|
|
} catch (MissingResourceException $exception) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
public function getScriptNames(?string $locale = null): array
|
|
{
|
|
try {
|
|
return Scripts::getNames($locale);
|
|
} catch (MissingResourceException $exception) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
public function getCountryNames(?string $locale = null): array
|
|
{
|
|
try {
|
|
return Countries::getNames($locale);
|
|
} catch (MissingResourceException $exception) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
public function getLocaleNames(?string $locale = null): array
|
|
{
|
|
try {
|
|
return Locales::getNames($locale);
|
|
} catch (MissingResourceException $exception) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
public function getCurrencyNames(?string $locale = null): array
|
|
{
|
|
try {
|
|
return Currencies::getNames($locale);
|
|
} catch (MissingResourceException $exception) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
public function getTimezoneNames(?string $locale = null): array
|
|
{
|
|
try {
|
|
return Timezones::getNames($locale);
|
|
} catch (MissingResourceException $exception) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
public function formatCurrency($amount, string $currency, array $attrs = [], ?string $locale = null): string
|
|
{
|
|
$formatter = $this->createNumberFormatter($locale, 'currency', $attrs);
|
|
|
|
if (false === $ret = $formatter->formatCurrency($amount, $currency)) {
|
|
throw new RuntimeError('Unable to format the given number as a currency.');
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
public function formatNumber($number, array $attrs = [], string $style = 'decimal', string $type = 'default', ?string $locale = null): string
|
|
{
|
|
if (!isset(self::NUMBER_TYPES[$type])) {
|
|
throw new RuntimeError(\sprintf('The type "%s" does not exist, known types are: "%s".', $type, implode('", "', array_keys(self::NUMBER_TYPES))));
|
|
}
|
|
|
|
$formatter = $this->createNumberFormatter($locale, $style, $attrs);
|
|
|
|
if (false === $ret = $formatter->format($number, self::NUMBER_TYPES[$type])) {
|
|
throw new RuntimeError('Unable to format the given number.');
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
public function formatNumberStyle(string $style, $number, array $attrs = [], string $type = 'default', ?string $locale = null): string
|
|
{
|
|
return $this->formatNumber($number, $attrs, $style, $type, $locale);
|
|
}
|
|
|
|
/**
|
|
* @param \DateTimeInterface|string|null $date A date or null to use the current time
|
|
* @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged
|
|
*/
|
|
public function formatDateTime(Environment $env, $date, ?string $dateFormat = 'medium', ?string $timeFormat = 'medium', string $pattern = '', $timezone = null, string $calendar = 'gregorian', ?string $locale = null): string
|
|
{
|
|
$date = $env->getExtension(CoreExtension::class)->convertDate($date, $timezone);
|
|
|
|
$formatterTimezone = $timezone;
|
|
if (null === $formatterTimezone || false === $formatterTimezone) {
|
|
$formatterTimezone = $date->getTimezone();
|
|
} elseif (\is_string($formatterTimezone)) {
|
|
$formatterTimezone = new \DateTimeZone($timezone);
|
|
}
|
|
$formatter = $this->createDateFormatter($locale, $dateFormat, $timeFormat, $pattern, $formatterTimezone, $calendar);
|
|
|
|
if (false === $ret = $formatter->format($date)) {
|
|
throw new RuntimeError('Unable to format the given date.');
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* @param \DateTimeInterface|string|null $date A date or null to use the current time
|
|
* @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged
|
|
*/
|
|
public function formatDate(Environment $env, $date, ?string $dateFormat = 'medium', string $pattern = '', $timezone = null, string $calendar = 'gregorian', ?string $locale = null): string
|
|
{
|
|
return $this->formatDateTime($env, $date, $dateFormat, 'none', $pattern, $timezone, $calendar, $locale);
|
|
}
|
|
|
|
/**
|
|
* @param \DateTimeInterface|string|null $date A date or null to use the current time
|
|
* @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged
|
|
*/
|
|
public function formatTime(Environment $env, $date, ?string $timeFormat = 'medium', string $pattern = '', $timezone = null, string $calendar = 'gregorian', ?string $locale = null): string
|
|
{
|
|
return $this->formatDateTime($env, $date, 'none', $timeFormat, $pattern, $timezone, $calendar, $locale);
|
|
}
|
|
|
|
private function createDateFormatter(?string $locale, ?string $dateFormat, ?string $timeFormat, string $pattern, ?\DateTimeZone $timezone, string $calendar): \IntlDateFormatter
|
|
{
|
|
$dateFormats = self::availableDateFormats();
|
|
|
|
if (null !== $dateFormat && !isset($dateFormats[$dateFormat])) {
|
|
throw new RuntimeError(\sprintf('The date format "%s" does not exist, known formats are: "%s".', $dateFormat, implode('", "', array_keys($dateFormats))));
|
|
}
|
|
|
|
if (null !== $timeFormat && !isset(self::TIME_FORMATS[$timeFormat])) {
|
|
throw new RuntimeError(\sprintf('The time format "%s" does not exist, known formats are: "%s".', $timeFormat, implode('", "', array_keys(self::TIME_FORMATS))));
|
|
}
|
|
|
|
if (null === $locale) {
|
|
if ($this->dateFormatterPrototype) {
|
|
$locale = $this->dateFormatterPrototype->getLocale();
|
|
}
|
|
$locale = $locale ?: \Locale::getDefault();
|
|
}
|
|
|
|
$calendar = 'gregorian' === $calendar ? \IntlDateFormatter::GREGORIAN : \IntlDateFormatter::TRADITIONAL;
|
|
|
|
$dateFormatValue = $dateFormats[$dateFormat] ?? null;
|
|
$timeFormatValue = self::TIME_FORMATS[$timeFormat] ?? null;
|
|
|
|
if ($this->dateFormatterPrototype) {
|
|
$dateFormatValue = $dateFormatValue ?: $this->dateFormatterPrototype->getDateType();
|
|
$timeFormatValue = $timeFormatValue ?: $this->dateFormatterPrototype->getTimeType();
|
|
$timezone = $timezone ?: $this->dateFormatterPrototype->getTimeZone()->toDateTimeZone();
|
|
$calendar = $calendar ?: $this->dateFormatterPrototype->getCalendar();
|
|
$pattern = $pattern ?: $this->dateFormatterPrototype->getPattern();
|
|
}
|
|
|
|
$timezoneName = $timezone ? $timezone->getName() : '(none)';
|
|
|
|
$hash = $locale.'|'.$dateFormatValue.'|'.$timeFormatValue.'|'.$timezoneName.'|'.$calendar.'|'.$pattern;
|
|
|
|
if (!isset($this->dateFormatters[$hash])) {
|
|
if (\count($this->dateFormatters) >= self::MAX_CACHED_FORMATTERS) {
|
|
array_shift($this->dateFormatters);
|
|
}
|
|
$this->dateFormatters[$hash] = new \IntlDateFormatter($locale, $dateFormatValue, $timeFormatValue, $timezone, $calendar, $pattern);
|
|
}
|
|
|
|
return $this->dateFormatters[$hash];
|
|
}
|
|
|
|
private function createNumberFormatter(?string $locale, string $style, array $attrs = []): \NumberFormatter
|
|
{
|
|
if (!isset(self::NUMBER_STYLES[$style])) {
|
|
throw new RuntimeError(\sprintf('The style "%s" does not exist, known styles are: "%s".', $style, implode('", "', array_keys(self::NUMBER_STYLES))));
|
|
}
|
|
|
|
if (null === $locale) {
|
|
$locale = \Locale::getDefault();
|
|
}
|
|
|
|
// textAttrs and symbols can only be set on the prototype as there is probably no
|
|
// use case for setting it on each call.
|
|
$textAttrs = [];
|
|
$symbols = [];
|
|
if ($this->numberFormatterPrototype) {
|
|
foreach (self::NUMBER_ATTRIBUTES as $name => $const) {
|
|
if (!isset($attrs[$name])) {
|
|
$value = $this->numberFormatterPrototype->getAttribute($const);
|
|
if ('rounding_mode' === $name) {
|
|
$value = array_flip(self::NUMBER_ROUNDING_ATTRIBUTES)[$value];
|
|
} elseif ('padding_position' === $name) {
|
|
$value = array_flip(self::NUMBER_PADDING_ATTRIBUTES)[$value];
|
|
}
|
|
$attrs[$name] = $value;
|
|
}
|
|
}
|
|
|
|
foreach (self::NUMBER_TEXT_ATTRIBUTES as $name => $const) {
|
|
$textAttrs[$name] = $this->numberFormatterPrototype->getTextAttribute($const);
|
|
}
|
|
|
|
foreach (self::NUMBER_SYMBOLS as $name => $const) {
|
|
$symbols[$name] = $this->numberFormatterPrototype->getSymbol($const);
|
|
}
|
|
}
|
|
|
|
ksort($attrs);
|
|
$hash = $locale.'|'.$style.'|'.json_encode($attrs).'|'.json_encode($textAttrs).'|'.json_encode($symbols);
|
|
|
|
if (!isset($this->numberFormatters[$hash])) {
|
|
if (\count($this->numberFormatters) >= self::MAX_CACHED_FORMATTERS) {
|
|
array_shift($this->numberFormatters);
|
|
}
|
|
$this->numberFormatters[$hash] = new \NumberFormatter($locale, self::NUMBER_STYLES[$style]);
|
|
}
|
|
|
|
foreach ($attrs as $name => $value) {
|
|
if (!isset(self::NUMBER_ATTRIBUTES[$name])) {
|
|
throw new RuntimeError(\sprintf('The number formatter attribute "%s" does not exist, known attributes are: "%s".', $name, implode('", "', array_keys(self::NUMBER_ATTRIBUTES))));
|
|
}
|
|
|
|
if ('rounding_mode' === $name) {
|
|
if (!isset(self::NUMBER_ROUNDING_ATTRIBUTES[$value])) {
|
|
throw new RuntimeError(\sprintf('The number formatter rounding mode "%s" does not exist, known modes are: "%s".', $value, implode('", "', array_keys(self::NUMBER_ROUNDING_ATTRIBUTES))));
|
|
}
|
|
|
|
$value = self::NUMBER_ROUNDING_ATTRIBUTES[$value];
|
|
} elseif ('padding_position' === $name) {
|
|
if (!isset(self::NUMBER_PADDING_ATTRIBUTES[$value])) {
|
|
throw new RuntimeError(\sprintf('The number formatter padding position "%s" does not exist, known positions are: "%s".', $value, implode('", "', array_keys(self::NUMBER_PADDING_ATTRIBUTES))));
|
|
}
|
|
|
|
$value = self::NUMBER_PADDING_ATTRIBUTES[$value];
|
|
}
|
|
|
|
$this->numberFormatters[$hash]->setAttribute(self::NUMBER_ATTRIBUTES[$name], $value);
|
|
}
|
|
|
|
foreach ($textAttrs as $name => $value) {
|
|
$this->numberFormatters[$hash]->setTextAttribute(self::NUMBER_TEXT_ATTRIBUTES[$name], $value);
|
|
}
|
|
|
|
foreach ($symbols as $name => $value) {
|
|
$this->numberFormatters[$hash]->setSymbol(self::NUMBER_SYMBOLS[$name], $value);
|
|
}
|
|
|
|
return $this->numberFormatters[$hash];
|
|
}
|
|
}
|