I'm new to using NumberFormatter (PHP) and right at the beginning I encountered a strange behavior that I consider a bug. I have searched for a solution but have not found one.
I want to present prices according to customer conventions (correct decimal and thousands separators and correct currency marking), and I always want to present prices without the decimal part.
When I use the setAttribute(NumberFormatter::FRACTION_DIGITS, 0) and/or setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, 0) settings, this only works for the currency intended for payments in that country. For prices in other currencies, it ignores the number of decimal places parameter.
Am I doing something wrong? How to force the given setting for all outputs?
Example code:
<?php
$val = 1234567.891234567890000;
$lngs = array("de_DE", "de_CH", "fr_CH", "nl_NL", "en_US", "en_GB", "cs_CZ");
$crncs = array("EUR", "CZK", "USD", "GBP", "CHF");
echo "<table border='1' style='width:auto;'>";
foreach($lngs as $lng) {
echo "<tr><th colspan='3' style='text-align: center;'>$lng</th>";
foreach ($crncs as $currency) {
$fmt = new NumberFormatter($lng, NumberFormatter::CURRENCY );
$fmt->setAttribute(NumberFormatter::FRACTION_DIGITS, 0); // this will be ignored everywhere except in a direct currency-language match
echo "<tr style='text-align: right;'><td>" . $currency . "</td><td>" . $fmt->formatCurrency($val, $currency) . "</td><td>" . $fmt->formatCurrency(-1 * $val, $currency) . "</td></tr>";
}
}
echo "</table>";
my output:
de_DE EUR 1.234.568 € -1.234.568 € CZK 1.234.567,89 CZK -1.234.567,89 CZK USD 1.234.567,89 $ -1.234.567,89 $ GBP 1.234.567,89 £ -1.234.567,89 £ CHF 1.234.567,90 CHF -1.234.567,90 CHF de_CH EUR € 1'234'567.89 €-1'234'567.89 CZK CZK 1'234'567.89 CZK-1'234'567.89 USD $ 1'234'567.89 $-1'234'567.89 GBP £ 1'234'567.89 £-1'234'567.89 CHF CHF 1'234'568 CHF-1'234'568 fr_CH EUR € 1'234'567.89 €-1'234'567.89 CZK CZK 1'234'567.89 CZK-1'234'567.89 USD $US 1'234'567.89 $US-1'234'567.89 GBP £UK 1'234'567.89 £UK-1'234'567.89 CHF CHF 1'234'568 CHF-1'234'568 nl_NL EUR € 1.234.568 € 1.234.568- CZK CZK 1.234.567,89 CZK 1.234.567,89- USD US$ 1.234.567,89 US$ 1.234.567,89- GBP £ 1.234.567,89 £ 1.234.567,89- CHF CHF 1.234.567,90 CHF 1.234.567,90- en_US EUR €1,234,567.89 (€1,234,567.89) CZK CZK1,234,567.89 (CZK1,234,567.89) USD $1,234,568 ($1,234,568) GBP £1,234,567.89 (£1,234,567.89) CHF CHF1,234,567.90 (CHF1,234,567.90) en_GB EUR €1,234,567.89 -€1,234,567.89 CZK CZK1,234,567.89 -CZK1,234,567.89 USD $1,234,567.89 -$1,234,567.89 GBP £1,234,568 -£1,234,568 CHF CHF1,234,567.90 -CHF1,234,567.90 cs_CZ EUR 1 234 567,89 € -1 234 567,89 € CZK 1 234 568 Kč -1 234 568 Kč USD 1 234 567,89 US$ -1 234 567,89 US$ GBP 1 234 567,89 £ -1 234 567,89 £ CHF 1 234 567,90 CHF -1 234 567,90 CHF
SOLUTION:
After further searching and elaboring I FOUND THE SOLUTION.
Before setting the number of decimal places, you still need to explicitly specify the currency:
$fmt->setTextAttribute(NumberFormatter::CURRENCY_CODE, $currency);
The function code is then:
<?php
$val = 1234567.891234567890000;
$lngs = array("de_DE", "de_CH", "fr_CH", "nl_NL", "en_US", "en_GB", "cs_CZ");
$crncs = array("EUR", "CZK", "USD", "GBP", "CHF");
echo "<table border='1' style='width:auto;'>";
foreach($lngs as $lng) {
echo "<tr><th colspan='3' style='text-align: center;'>$lng</th>";
foreach ($crncs as $currency) {
$fmt = new NumberFormatter($lng, NumberFormatter::CURRENCY );
// new line of code that solves the problem
$fmt->setTextAttribute(NumberFormatter::CURRENCY_CODE, $currency);
$fmt->setAttribute(NumberFormatter::FRACTION_DIGITS, 0);
echo "<tr style='text-align: right;'><td>" . $currency . "</td><td>" . $fmt->formatCurrency($val, $currency) . "</td><td>" . $fmt->formatCurrency(-1 * $val, $currency) . "</td></tr>";
}
}
echo "</table>";