PHP NumberFormatter y moneda, no se puede establecer la precisión
intl (6)
Creo que tienes que usar una configuración regional que admita la moneda de destino. Así que en_US no tenemos el euro. de_DE lo tengo y fr_FR también. Así que no es extraño que fr_FR apoye el euro.
Parece que esto no es un error.
Quiero establecer una precisión de 0 al usar la clase de PHP NumberFormatter (de la extensión Intl ) con la moneda. Sin embargo tengo un resultado extraño. Aquí:
$numberFormatter = new NumberFormatter(''en-US'', NumberFormatter::CURRENCY);
$numberFormatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 0);
echo $numberFormatter->formatCurrency(''45'', ''USD'');
Sale $45
, que es lo que quiero. Sin embargo, si cambio la moneda a EUR
con la misma configuración:
echo $numberFormatter->formatCurrency(''45'', ''EUR'');
Sale a €45.00
(aunque explícitamente configurado para tener una precisión de cero).
Aún más extraño, si configuro la configuración regional en fr-FR
, genera el número como se esperaba:
$numberFormatter = new NumberFormatter(''fr-FR'', NumberFormatter::CURRENCY);
$numberFormatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 0);
echo $numberFormatter->formatCurrency(''45'', ''EUR'');
Sale a 45 €
.
¿Es esto un error?
Debe proporcionar una combinación de moneda y moneda local que sea correcta. Por ejemplo, fr-FR / fr-bh / fr-ch support €, que es lo que debe proporcionarse en la función formatCurrency.
Esta función usa la información regional para dar formato al número en moneda, el formato que estoy usando es ''% # 10n'' para $:
/**
* 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;
}
Establezca el valor de configuración regional predeterminado en la entrada php que puede usar:
ini_set (''intl.default_locale'', ''de-DE'');
Para cambiar el formato de número use:
setlocale (LC_MONETARY, ''de-DE'');
Michael Gallego se olvidó de actualizar este problema. Echa un vistazo a su informe de errores y las respuestas en php.net.
[2012-10-05 08:21 UTC] jpauli @ email.com
Confirmo que esto es un error de ICU en la rama 4.4.x.
Considera actualizar libicu, 4.8.x da el resultado correcto
Puede usar la siguiente línea de código para formatear el dinero:
$number = 1234.56;
setlocale(LC_MONETARY,"en_US"); // Sets the Default for money
echo money_format("%i", $number);
Te dará salida:
USD 1,234.56