2

I'm having an issue with Intl.NumberFormat using a Swedish locale. If you run:

new Intl.NumberFormat('en-uk', {
   minimumFractionDigits: 2,
   maximumFractionDigits: 2,
}).format(-2);

It returns -2.00 with minus sign U+002D, but if you run:

new Intl.NumberFormat('sv-se', {
   minimumFractionDigits: 2,
   maximumFractionDigits: 2,
}).format(-2);

It returns −2,00 with minus sign U+2212.

This messes up my validation functions because JS cannot do math operations with the U+2212 sign.

10 − 2
Uncaught SyntaxError: Invalid or unexpected token

Is there a way to set the minus character for Intl.NumberFormat? Or is there a way around this without some ugly hack? Thanks!

Norbert
  • 2,741
  • 8
  • 56
  • 111

1 Answers1

1

Based on this excellent answer and the original work of Mike Bostock, you can parse locale numbers, unfortunately seems that it isn't part of the current Intl API.

I extended the method suggested to deal correctly with negative numbers as well.

class NumberParser {
    constructor(locale) {
        const format = new Intl.NumberFormat(locale);
        const parts = format.formatToParts(-12345.6);
        const numerals = Array.from({ length: 10 }).map((_, i) => format.format(i));
        const index = new Map(numerals.map((d, i) => [d, i]));
        this._minusSign = parts[0].value;
        this._group = new RegExp(`[${parts.find(d => d.type === "group").value}]`, "g");
        this._decimal = new RegExp(`[${parts.find(d => d.type === "decimal").value}]`);
        this._numeral = new RegExp(`[${numerals.join("")}]`, "g");
        this._index = d => index.get(d);
    }
    parse(string) {
        return (string = string.trim()
            .replace(this._minusSign, "-")
            .replace(this._group, "")
            .replace(this._decimal, ".")
            .replace(this._numeral, this._index)) ? +string : NaN;
    }
}

const formatter = new Intl.NumberFormat('sv-se', {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
});

const value = -2;
const parser = new NumberParser('sv-se');
console.log(formatter.format(value));               // −2,00 (U+2212)
console.log(parser.parse(formatter.format(value))); // -2 (U+002D)
console.log(parser.parse(formatter.format(value)) === value); // true
Evgeni Dikerman
  • 486
  • 3
  • 18