Search code examples
phplocalenumber-formatting

PHP NumberFormatter.format() shows strange output


I have the following code in a PHP function:

$fmt = NumberFormatter::create('de_DE', NumberFormatter::FRACTION_DIGITS);
echo $fmt->format(15);

and the output is two strange characters: ௰௫ which I found to be 15 in Tamil numbers. If I change the number in second line to a fractional number, i. e.

$fmt = NumberFormatter::create('de_DE', NumberFormatter::FRACTION_DIGITS);
echo $fmt->format(15.5);

then, I get the expected result 15,50 in German. This is all running on an English Ubuntu VM with German keyboard. I have no idea where and why Tamil would come into play at all, and why it only affects integer numbers.

Obviously, I am doing something wrong, but I have no idea where. Any ideas or suggestions where to look?


Solution

  • What you're doing wrong is that you're using a constant that is not meant for the purpose of creating the NumberFormatter object. If you take a look at the constructor signature:

    public static NumberFormatter::create ( string $locale , int $style , string $pattern = ? ) : NumberFormatter
    

    you'll see that the second argument is the style to be applied. The manual defines the style as one of the following constants:

    These styles are used by the numfmt_create() to define the type of the formatter.

    NumberFormatter::PATTERN_DECIMAL (int)

    Decimal format defined by pattern

    NumberFormatter::DECIMAL (int)

    Decimal format

    NumberFormatter::CURRENCY (int)

    Currency format

    NumberFormatter::PERCENT (int)

    Percent format

    NumberFormatter::SCIENTIFIC (int)

    Scientific format

    NumberFormatter::SPELLOUT (int)

    Spellout rule-based format

    NumberFormatter::ORDINAL (int)

    Ordinal rule-based format

    NumberFormatter::DURATION (int)

    Duration rule-based format

    NumberFormatter::PATTERN_RULEBASED (int)

    Rule-based format defined by pattern

    NumberFormatter::CURRENCY_ACCOUNTING (int)

    Currency format for accounting, e.g., ($3.00) for negative currency amount instead of -$3.00. Available as of PHP 7.4.1 and ICU 53.

    NumberFormatter::DEFAULT_STYLE (int)

    Default format for the locale

    NumberFormatter::IGNORE (int)

    Alias for PATTERN_DECIMAL

    As you can see, NumberFormatter::FRACTION_DIGITS is not one of them. That one is mentioned later in a section labeled by the following sentence:

    Number format attribute used by numfmt_get_attribute() and numfmt_set_attribute().

    So what you really need to do is select one of the style constants and use it instead.

    What happens that it evokes the Tamil numbers is beyond me, though. If you take a look at the dumps of the constants, this constant has the value of 8 and none of the style constants correspond to that number. I've no idea how PHP handles 8 as the input value there. It might make an interesting question of its own.