NumberFormatter: strange behaviour with a minus sign in different locales

Viewed 227

I came across a problem with Symfony/Form which under the hood use NumberFormatter to format NumberType field. Our project is multilingual and for each country, we use a different locale.

$formatter->format() returns the different minus sign for negative numbers. For example:

$formatter = new \NumberFormatter('en', \NumberFormatter::DECIMAL);
$value = $formatter->format('-150');
var_dump($value); // string(4) "-150"

$formatter = new \NumberFormatter('lt', \NumberFormatter::DECIMAL);
$value = $formatter->format('-150');
var_dump($value); // string(6) "−150" <-- here is the problem

As you can see the NumberFormatter changes the minus sign to something else.

Why is it important for me? Because some elements on the page are generated with javascript, and js cannot parse −150 number and returns NaN.

Can somebody explain the reason for this behaviour and how to get correct minus sign from NumberFormatter for lt locale?

2 Answers

I've found a solution. Symfony/Form has a great feature to add a view transformers, which is rendered right before rendering a form element.

Here is my FormType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('amount', NumberType::class, array(
        'required' => true,
        'scale' => 4,
    ));

    $builder->get('amount')->addViewTransformer(new CallbackTransformer(
        function ($forward) {
            // Transform the lithuanian minus sign to the normal minus sign.
            return preg_replace('/\x{2212}/u', '-', $forward);
        },
        function ($reverse) {
            return $reverse;
        }
    ));

    // others form elements...
}

This approach allows to override the default view transformer for \Symfony\Component\Form\Extension\Core\Type\NumberType which add spesific minus sign.

$builder->addViewTransformer(new NumberToLocalizedStringTransformer(
    $options['scale'],
    $options['grouping'],
    $options['rounding_mode'],
    $options['html5'] ? 'en' : null
));

To be clear, the view transformer added in a custom form has higher priority over any others incorporated transformers.

It doesn't fix the problem in general for NumberFormatter, but help me fixed my problem.

How about transforming to ascii?

$formatter = new \NumberFormatter('lt', \NumberFormatter::DECIMAL);
$value = $formatter->format('-150');
$valueAsAscii = iconv('utf8', 'ascii//translit', $value);

var_dump($value);
var_dump($valueAsAscii);

Working example.

output

string(6) "−150"
string(4) "-150"

references

Related