I want to set a precision of 0 when using the NumberFormatter PHP class (from Intl extension) with currency. However I've got some strange result. Here:
我想在使用带货币的NumberFormatter PHP类(来自Intl扩展名)时设置精度为0。但是我有一些奇怪的结果。这里:
$numberFormatter = new NumberFormatter('en-US', NumberFormatter::CURRENCY);
$numberFormatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 0);
echo $numberFormatter->formatCurrency('45', 'USD');
It outputs $45
, which is what I want. However, if I change the currency to EUR
with the same settings:
它输出45美元,这就是我想要的。但是,如果我使用相同的设置将货币更改为EUR:
echo $numberFormatter->formatCurrency('45', 'EUR');
It outputs €45.00
(although I explicitly set to have a precision of zero).
它输出€45.00(虽然我明确设置精度为零)。
Even more strange, if I set the locale to fr-FR
, it outputs the number as expected:
更奇怪的是,如果我将语言环境设置为fr-FR,它会按预期输出数字:
$numberFormatter = new NumberFormatter('fr-FR', NumberFormatter::CURRENCY);
$numberFormatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 0);
echo $numberFormatter->formatCurrency('45', 'EUR');
It outputs 45 €
.
它输出45€。
Is this a bug?
这是一个错误吗?
6 个解决方案
#1
1
Michael Gallego forgot to update this issue. Check out his bug report and the replies at php.net.
Michael Gallego忘了更新这个问题看看他的错误报告和php.net上的回复。
[2012-10-05 08:21 UTC] jpauli@email.com
[2012-10-05 08:21 UTC] jpauli@email.com
I confirm this is an ICU bug in 4.4.x branch.
Consider upgrading libicu, 4.8.x gives correct result我确认这是4.4.x分支中的ICU错误。考虑升级libicu,4.8.x给出正确的结果
#2
0
This function uses locale information to format number into currency, format I am are using is '%#10n' for $ :
此函数使用区域设置信息将数字格式化为货币,我正在使用的格式为'%#10n'为$:
/**
* That it is an implementation of the function money_format for the
* platforms that do not it bear.
* The function accepts to same string of format accepts for the
* original function of the PHP.
* The function is tested using PHP 5.1.4 in Windows XP
* and Apache WebServer.
*
* format I am are using is '%#10n' for $;
*
*/
public static function money_format( $format, $number )
{
$regex = '/%((?:[\^!\-]|\+|\(|\=.)*)([0-9]+)?'.
'(?:#([0-9]+))?(?:\.([0-9]+))?([in%])/';
if (setlocale(LC_MONETARY, 0) == 'C') {
setlocale(LC_MONETARY, '');
}
$locale = localeconv();
preg_match_all($regex, $format, $matches, PREG_SET_ORDER);
foreach ($matches as $fmatch) {
$value = floatval($number);
$flags = array(
'fillchar' => preg_match('/\=(.)/', $fmatch[1], $match) ?
$match[1] : ' ',
'nogroup' => preg_match('/\^/', $fmatch[1]) > 0,
'usesignal' => preg_match('/\+|\(/', $fmatch[1], $match) ?
$match[0] : '+',
'nosimbol' => preg_match('/\!/', $fmatch[1]) > 0,
'isleft' => preg_match('/\-/', $fmatch[1]) > 0
);
$width = trim($fmatch[2]) ? (int)$fmatch[2] : 0;
$left = trim($fmatch[3]) ? (int)$fmatch[3] : 0;
$right = trim($fmatch[4]) ? (int)$fmatch[4] : $locale['int_frac_digits'];
$conversion = $fmatch[5];
$positive = true;
if ($value < 0) {
$positive = false;
$value *= -1;
}
$letter = $positive ? 'p' : 'n';
$prefix = $suffix = $cprefix = $csuffix = $signal = '';
$signal = $positive ? $locale['positive_sign'] : $locale['negative_sign'];
switch (true) {
case $locale["{$letter}_sign_posn"] == 1 && $flags['usesignal'] == '+':
$prefix = $signal;
break;
case $locale["{$letter}_sign_posn"] == 2 && $flags['usesignal'] == '+':
$suffix = $signal;
break;
case $locale["{$letter}_sign_posn"] == 3 && $flags['usesignal'] == '+':
$cprefix = $signal;
break;
case $locale["{$letter}_sign_posn"] == 4 && $flags['usesignal'] == '+':
$csuffix = $signal;
break;
case $flags['usesignal'] == '(':
case $locale["{$letter}_sign_posn"] == 0:
$prefix = '(';
$suffix = ')';
break;
}
if (!$flags['nosimbol']) {
$currency = $cprefix .
($conversion == 'i' ? $locale['int_curr_symbol'] : $locale['currency_symbol']) .
$csuffix;
} else {
$currency = '';
}
$space = $locale["{$letter}_sep_by_space"] ? ' ' : '';
$value = number_format($value, $right, $locale['mon_decimal_point'],
$flags['nogroup'] ? '' : $locale['mon_thousands_sep']);
$value = @explode($locale['mon_decimal_point'], $value);
$n = strlen($prefix) + strlen($currency) + strlen($value[0]);
if ($left > 0 && $left > $n) {
$value[0] = str_repeat($flags['fillchar'], $left - $n) . $value[0];
}
$value = implode($locale['mon_decimal_point'], $value);
if ($locale["{$letter}_cs_precedes"]) {
$value = $prefix . $currency . $space . $value . $suffix;
} else {
$value = $prefix . $value . $space . $currency . $suffix;
}
if ($width > 0) {
$value = str_pad($value, $width, $flags['fillchar'], $flags['isleft'] ?
STR_PAD_RIGHT : STR_PAD_LEFT);
}
$format = str_replace($fmatch[0], $value, $format);
}
return $format;
}
#3
0
You must provide a locale AND currency combination that is correct. For example, fr-FR / fr-bh / fr-ch support €, which is what must be provided in the formatCurrency function.
您必须提供正确的区域设置和货币组合。例如,fr-FR / fr-bh / fr-ch支持€,这是formatCurrency函数中必须提供的。
#4
-1
I think you have to use a locale which supports the destination currency. So en_US don't have the Euro. de_DE have it and fr_FR also. So it is not strange that fr_FR supports Euro.
我认为你必须使用支持目标货币的区域设置。所以en_US没有欧元。 de_DE也有它和fr_FR。所以fr_FR支持欧元并不奇怪。
It seems that this is not a bug.
看来这不是一个bug。
#5
-1
Set the default locale value in the php ini you can use:
在您可以使用的php ini中设置默认语言环境值:
ini_set('intl.default_locale', 'de-DE');
To change the number format use:
要更改数字格式,请使用:
setlocale(LC_MONETARY, 'de-DE');
#6
-1
You can us the following line of code for formatting the money:-
您可以使用以下代码行格式化资金: -
$number = 1234.56;
setlocale(LC_MONETARY,"en_US"); // Sets the Default for money
echo money_format("%i", $number);
It will output you:
它会输出你:
USD 1,234.56
#1
1
Michael Gallego forgot to update this issue. Check out his bug report and the replies at php.net.
Michael Gallego忘了更新这个问题看看他的错误报告和php.net上的回复。
[2012-10-05 08:21 UTC] jpauli@email.com
[2012-10-05 08:21 UTC] jpauli@email.com
I confirm this is an ICU bug in 4.4.x branch.
Consider upgrading libicu, 4.8.x gives correct result我确认这是4.4.x分支中的ICU错误。考虑升级libicu,4.8.x给出正确的结果
#2
0
This function uses locale information to format number into currency, format I am are using is '%#10n' for $ :
此函数使用区域设置信息将数字格式化为货币,我正在使用的格式为'%#10n'为$:
/**
* That it is an implementation of the function money_format for the
* platforms that do not it bear.
* The function accepts to same string of format accepts for the
* original function of the PHP.
* The function is tested using PHP 5.1.4 in Windows XP
* and Apache WebServer.
*
* format I am are using is '%#10n' for $;
*
*/
public static function money_format( $format, $number )
{
$regex = '/%((?:[\^!\-]|\+|\(|\=.)*)([0-9]+)?'.
'(?:#([0-9]+))?(?:\.([0-9]+))?([in%])/';
if (setlocale(LC_MONETARY, 0) == 'C') {
setlocale(LC_MONETARY, '');
}
$locale = localeconv();
preg_match_all($regex, $format, $matches, PREG_SET_ORDER);
foreach ($matches as $fmatch) {
$value = floatval($number);
$flags = array(
'fillchar' => preg_match('/\=(.)/', $fmatch[1], $match) ?
$match[1] : ' ',
'nogroup' => preg_match('/\^/', $fmatch[1]) > 0,
'usesignal' => preg_match('/\+|\(/', $fmatch[1], $match) ?
$match[0] : '+',
'nosimbol' => preg_match('/\!/', $fmatch[1]) > 0,
'isleft' => preg_match('/\-/', $fmatch[1]) > 0
);
$width = trim($fmatch[2]) ? (int)$fmatch[2] : 0;
$left = trim($fmatch[3]) ? (int)$fmatch[3] : 0;
$right = trim($fmatch[4]) ? (int)$fmatch[4] : $locale['int_frac_digits'];
$conversion = $fmatch[5];
$positive = true;
if ($value < 0) {
$positive = false;
$value *= -1;
}
$letter = $positive ? 'p' : 'n';
$prefix = $suffix = $cprefix = $csuffix = $signal = '';
$signal = $positive ? $locale['positive_sign'] : $locale['negative_sign'];
switch (true) {
case $locale["{$letter}_sign_posn"] == 1 && $flags['usesignal'] == '+':
$prefix = $signal;
break;
case $locale["{$letter}_sign_posn"] == 2 && $flags['usesignal'] == '+':
$suffix = $signal;
break;
case $locale["{$letter}_sign_posn"] == 3 && $flags['usesignal'] == '+':
$cprefix = $signal;
break;
case $locale["{$letter}_sign_posn"] == 4 && $flags['usesignal'] == '+':
$csuffix = $signal;
break;
case $flags['usesignal'] == '(':
case $locale["{$letter}_sign_posn"] == 0:
$prefix = '(';
$suffix = ')';
break;
}
if (!$flags['nosimbol']) {
$currency = $cprefix .
($conversion == 'i' ? $locale['int_curr_symbol'] : $locale['currency_symbol']) .
$csuffix;
} else {
$currency = '';
}
$space = $locale["{$letter}_sep_by_space"] ? ' ' : '';
$value = number_format($value, $right, $locale['mon_decimal_point'],
$flags['nogroup'] ? '' : $locale['mon_thousands_sep']);
$value = @explode($locale['mon_decimal_point'], $value);
$n = strlen($prefix) + strlen($currency) + strlen($value[0]);
if ($left > 0 && $left > $n) {
$value[0] = str_repeat($flags['fillchar'], $left - $n) . $value[0];
}
$value = implode($locale['mon_decimal_point'], $value);
if ($locale["{$letter}_cs_precedes"]) {
$value = $prefix . $currency . $space . $value . $suffix;
} else {
$value = $prefix . $value . $space . $currency . $suffix;
}
if ($width > 0) {
$value = str_pad($value, $width, $flags['fillchar'], $flags['isleft'] ?
STR_PAD_RIGHT : STR_PAD_LEFT);
}
$format = str_replace($fmatch[0], $value, $format);
}
return $format;
}
#3
0
You must provide a locale AND currency combination that is correct. For example, fr-FR / fr-bh / fr-ch support €, which is what must be provided in the formatCurrency function.
您必须提供正确的区域设置和货币组合。例如,fr-FR / fr-bh / fr-ch支持€,这是formatCurrency函数中必须提供的。
#4
-1
I think you have to use a locale which supports the destination currency. So en_US don't have the Euro. de_DE have it and fr_FR also. So it is not strange that fr_FR supports Euro.
我认为你必须使用支持目标货币的区域设置。所以en_US没有欧元。 de_DE也有它和fr_FR。所以fr_FR支持欧元并不奇怪。
It seems that this is not a bug.
看来这不是一个bug。
#5
-1
Set the default locale value in the php ini you can use:
在您可以使用的php ini中设置默认语言环境值:
ini_set('intl.default_locale', 'de-DE');
To change the number format use:
要更改数字格式,请使用:
setlocale(LC_MONETARY, 'de-DE');
#6
-1
You can us the following line of code for formatting the money:-
您可以使用以下代码行格式化资金: -
$number = 1234.56;
setlocale(LC_MONETARY,"en_US"); // Sets the Default for money
echo money_format("%i", $number);
It will output you:
它会输出你:
USD 1,234.56