You need to use the narrow option when formatting numbers in JS
"narrowSymbol" to use a narrow format symbol ("$100" rather than "US$100"),
const amount = 123444;
console.log(new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', currencyDisplay: 'narrowSymbol'}).format(amount));
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat for full details.
Answer from John on Stack OverflowYou need to use the narrow option when formatting numbers in JS
"narrowSymbol" to use a narrow format symbol ("$100" rather than "US$100"),
const amount = 123444;
console.log(new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', currencyDisplay: 'narrowSymbol'}).format(amount));
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat for full details.
V8 JavaScript engine is using ICU library for i18N.
See there for all currency data: https://github.com/unicode-org/icu/tree/master/icu4c/source/data/curr
But for sure French people use $ and not $US when talking about US dollar.
Videos
One simple way to do achieve what you want is to use String#replace() to remove the currency from the string. To make this easier, you can set currencyDisplay to "code" which will use the ISO currency code - the same one passed in to currency:
const number = 123456.789;
console.log(new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR',
currencyDisplay: "code"
})
.format(number)
.replace("EUR", "")
.trim()
); // 123.456,79
// the Japanese yen doesn't use a minor unit
console.log(new Intl.NumberFormat('ja-JP', {
style: 'currency',
currency: 'JPY',
currencyDisplay: "code"
})
.format(number)
.replace("JPY", "")
.trim()
); // 123,457
This can be extracted into a function:
const number = 123456.789;
console.log(format('de-DE', 'EUR', number)); // 123.456,79
console.log(format('ja-JP', 'JPY', number)); // 123,457
function format (locale, currency, number) {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency,
currencyDisplay: "code"
})
.format(number)
.replace(currency, "")
.trim();
}
An alternative that allows you more control is to use Intl.NumberFormat#formatToParts() which formats the number but gives you tokens that you can programmatically consume and manipulate. For example, using the method with locale = "de-DE" and currency = "EUR" you get the following output:
[
{
"type": "integer",
"value": "123"
},
{
"type": "group",
"value": "."
},
{
"type": "integer",
"value": "456"
},
{
"type": "decimal",
"value": ","
},
{
"type": "fraction",
"value": "79"
},
{
"type": "literal",
"value": " "
},
{
"type": "currency",
"value": "EUR"
}
]
Which means that you can easily filter out "type": "currency" and then combine the rest into a string. For example:
const number = 123456.789;
console.log(format('de-DE', 'EUR', number)); // 123.456,79
console.log(format('ja-JP', 'JPY', number)); // 123,457
function format (locale, currency, number) {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency,
currencyDisplay: "code",
})
.formatToParts(number)
.filter(x => x.type !== "currency")
.filter(x => x.type !== "literal" || x.value.trim().length !== 0)
.map(x => x.value)
.join("")
}
NOTE: the exclusion here: .filter(x => x.type !== "literal" || x.value.trim().length !== 0) handles whitespace characters within the number. That might come up when using the option currencySign: 'accounting' in the formatter. In some locales this will use parentheses for negative numbers which would leave a space inside if just the currency is removed:
const number = -123456.789;
const parts = new Intl.NumberFormat('ja-JP', {
style: 'currency',
currency: 'JPY',
currencySign: "accounting",
currencyDisplay: "code",
})
.formatToParts(number);
console.log(parts);
/* output:
[
{ type: "literal" , value: "(" },
{ type: "currency", value: "JPY" },
{ type: "literal" , value: " " },
{ type: "integer" , value: "123" },
{ type: "group" , value: "," },
{ type: "integer" , value: "457" },
{ type: "literal" , value: ")" }
]
*/
.as-console-wrapper { max-height: 100% !important; }
Thus negative numbers are handled correctly:
const number = -123456.789;
console.log(format('de-DE', 'EUR', number)); // 123.456,79
console.log(format('ja-JP', 'JPY', number)); // 123,457
function format (locale, currency, number) {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency,
currencyDisplay: "code",
currencySign: "accounting",
})
.formatToParts(number)
.filter(x => x.type !== "currency")
.filter(x => x.type !== "literal" || x.value.trim().length !== 0)
.map(x => x.value)
.join("")
}
Thanks to Chris Peckham for pointing out potential pitfalls when using the accounting currency sign option.
If you only want the separators in between individual digits, just format as a number instead of using currency:
const numberFormatter = new Intl.NumberFormat("en-US", {
// Do not show fractions - front end should only handle whole numbers
maximumFractionDigits: 0,
});
And then numberFormatter.format(asNumber); with whatever number you like.
For your example of 123456, "de-DE" is 123.456, "ja-JP" is 123,456
The problem might be that the browser you're using doesn't support the narrowSymbol currency display. You can check with Can I Use here:
https://caniuse.com/?search=currencyDisplay
You'll see how a few browsers like Safari have a note:
Doesn't support currencyDisplay: 'narrowSymbol'.
For these browsers that don't support it, you may need to polyfill Intl.NumberFormat so that you have access to narrowSymbol.
There are lots of polyfill options out there. I've used formatjs.io for this exact issue. You can find out more here:
https://formatjs.io/docs/polyfills/intl-numberformat
I had the same problem on iOS14 with React Native. narrowSymbol was simply not supported.
The Intl.NumberFormat should have the symbols you need, you just have to make sure you specify the correct language code.
You can find a mapping of ISO language codes here: https://www.w3schools.com/tags/ref_language_codes.asp
In this case you will need to use the Polish value "pl" instead of "en-US"
Intl.NumberFormat("pl",{
style:'currency',
minimumIntegerDigits:1,
currency: 'PLN',
currencyDisplay: 'symbol'
}).format(43);
To display just the currency symbol more concisely, you might consider using currencyDisplay: 'narrowSymbol' instead of symbol in your Intl.NumberFormat configuration. This option is also applicable for toLocaleString. As explained in the MDN documentation, narrowSymbol provides a more streamlined symbol format, e.g., "$100" rather than "US$100".
Intl.NumberFormat("en-US", {
style: 'currency',
currency: 'PLN',
currencyDisplay: 'narrowSymbol'
}).format(43);
Displays 'zł 43.00'
However, please verify the compatibility with your target browsers here on CanIUse as narrowSymbol is not supported in some older or less common browsers.