Javascript number.toLocaleString currency without currency sign
Asked Answered
A

15

47

Suppose we have

var number = 123456.789;

What I want is to display this number in locale 'de-DE' as

123.456,79

in locale 'ja-JP' as

123,457

in locale 'en-US' as

123,456.79

and so on according to user's locale. The problem is that Javascript's number.toLocaleString requires to specify currency sign and I can't find out how to tell to not display it at all.

What I tried:

number.toLocaleString('de-DE', { style: 'currency' }));
// TypeError: undefined currency in NumberFormat() with currency style

number.toLocaleString('de-DE', { style: 'currency', currency: '' }));
// RangeError: invalid currency code in NumberFormat():

number.toLocaleString('de-DE', { style: 'currency', currency: false }));
// RangeError: invalid currency code in NumberFormat(): false

number.toLocaleString('de-DE', { style: 'currency', currency: null }));
// RangeError: invalid currency code in NumberFormat(): null

The function also has option currencyDisplay. I tried the same values as above with currency option but with same result.


UPDATE (2020-11-25)

A few people pointed to .resolvedOptions(). It basically solves the question:

const currencyFractionDigits = new Intl.NumberFormat('de-DE', {
    style: 'currency',
    currency: 'EUR',
}).resolvedOptions().maximumFractionDigits;

const value = (12345.678).toLocaleString('de-DE', {
    maximumFractionDigits: currencyFractionDigits 
});

console.log(value); // prints 12.345,68

Thank you.

Axillary answered 7/7, 2017 at 11:38 Comment(2)
The following statement is wrong: "The problem is that Javascript's number.toLocaleString requires to specify currency sign". You can simply pass the locale string as in number.toLocaleString('de-DE')Craving
If you want $0.50 to be formatted 0.50 and not 0.5, { minimumFractionDigits: currencyFractionDigits} worked for me.Indestructible
A
27

There is no way to pass parameter to toLocaleString and remove currency symbol. so use this function instead.

var convertedNumber = num.toLocaleString('de-DE', { minimumFractionDigits: 2 });

Amorous answered 16/3, 2018 at 6:53 Comment(6)
And how do I know the number of locale's currency fraction digits? It might be 0, 2 or 3.Axillary
copy my line in a function and pass that fraction digit in a variable as argument . I'm using the same way. that is what minimumFractionDigits is for.Amorous
I know where to pass fraction digit. What I don't know is how to get that digit in javascript.Axillary
didn't mean to offend you or question your programming skills. I might havn't understood your question properly brother.Amorous
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).resolvedOptions() will return an object describing how to format the number including minimumIntegerDigits, minimumFractionDigits and maximumFractionDigits fieldsKerseymere
How to get other formatting options - fractional and thousand separators? A complete code would be useful.Dalmatia
D
18

Here how I solved this issue. When I want to format currency without any signs, I format it with the currency code and then just remove 3-chars code from the result.

export function getCurrencyFormatWithSymbol(currencyCode) {
  return {
    style: 'currency',
    currency: currencyCode,
    currencyDisplay: 'symbol',
  }
}

export function getCurrencyFormatWithIsoCode(currencyCode) {
  return {
    style: 'currency',
    currency: currencyCode,
    currencyDisplay: 'code',
  }
}

export function getCurrencyFormatWithLocalName(currencyCode) {
  return {
    style: 'currency',
    currency: currencyCode,
    currencyDisplay: 'name',
  }
}

export function getCurrencyFormatNumbersOnly(currencyCode) {
  return {
    style: 'currency',
    currency: currencyCode,
    currencyDisplay: 'none',
  }
}

export function formatCurrency (value, format, lang) {
  const stripSymbols = (format.currencyDisplay === 'none')
  const localFormat = stripSymbols ? {...format, currencyDisplay: 'code'} : format
  let result = Intl.NumberFormat(lang, localFormat).format(value)
  if (stripSymbols) {
    result = result.replace(/[a-z]{3}/i, "").trim()
  }
  return result
}

Usage:

const format = getCurrencyFormatNumbersOnly('JPY')
formatCurrency(12345, format, 'ja')
formatCurrency(123456, format, 'ja')
formatCurrency(1234567, format, 'ja')
formatCurrency(12345678, format, 'ja')

Edit: The only minus, in this case, is the speed. On simple tasks, it will work perfectly. But if you are going to format a lot of numbers (for example, if you are fetching financial reports with raw data from backend and then format numbers according to user settings) this function can slow down your algorithms significantly and become a bottleneck on some browsers. So, test it carefully before using in production.

Dalmatia answered 6/12, 2018 at 3:2 Comment(4)
It is useful but I still hope that there is an option in number.toLocaleString that we don't know about.Axillary
It seems your question can not be solved by native JS tools. I was searching for the same issue and didn't found anything. So the only way it was possible in my project was that I've shown above.Dalmatia
currencyDisplay: "none" is not valid developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Auntie
@Auntie If you look at the code more carefully, you'll see that the none value is only used in my own code and not passed to the Intl.NumberFormat() method. Instead, it is replaced by the code value if none is used in the configuration. The none value is only used to configure my custom functions.Dalmatia
G
8

Here is a solution that isn't using regex and will deal with any locale, properly.

It uses the currency formatter of the locale and iterates all parts of it to exclude the literal and currency, properly, resulting in only getting the number as string. (Btw, the literal is the space between number and currency symbol).

const value = new Intl.NumberFormat('de-DE', {
    style: 'currency',
    currency: 'EUR',
}).formatToParts(12345.678).map(
    p => p.type != 'literal' && p.type != 'currency' ? p.value : ''
).join('')

console.log(value) // prints 12.345,68
Gosser answered 24/11, 2020 at 2:25 Comment(4)
This looks clever at the first glance, but unfortunately doesn’t work. It does not consider all currency-locale- combination specific options. In case of fr-CH with CHF, it will use a decimal comma instead of a decimal point. jsfiddle.net/e80vutwqCacophony
@Cacophony You are right, I updated my answer to fix this. The issue was toLocaleString with style: 'decimal' will use the number decimal sign of the given language, not the currency decimal sign. It's not possible to set the decimal sign when calling toLocaleString, however I found a simpler solution. Simply use the currency formatter and extract all parts using formatToParts, excluding the currency symbol. Please check my updated answer.Gosser
Yes, now it will work. It's now literally a duplicate of the one from @nyg below.Cacophony
@Cacophony Oh, I didn't see his answer and worked this out by myself. I can see that his solution will not exclude the literal and trim the value instead, but this will only work for currencies that use a whitespace as literal. Also I'm joining the segments whereas he uses reduce for that. I didn't intend to come that close to an already-existing solution, but mine should be slightly faster and more fail-proof whatsoever.Gosser
M
3

The solution proposed in the OP won't work for the fr-CH locale because there is a distinction between a “currency amount” and a “non-currency amount”. The former uses a dot as decimal separator whereas the latter uses a comma:

const n = 1234.56
console.log(n.toLocaleString('fr-CH'))
console.log(n.toLocaleString('fr-CH', {
  style: 'currency',
  currency: 'CHF'
}))

Using .replace() either with a regex or directly with the currency code does seem to be the fastest solution but here is a solution with the .formatToParts() function of NumberFormat and how it can be used to solve the OP's question:

console.log(new Intl
  .NumberFormat('fr-CH', { style: 'currency', currency: 'CHF' })
  .formatToParts(1234.56) // returns an array of the different parts of the amount
  .filter(p => p.type != 'currency') // removes the currency part
  .reduce((s, p) => s + p.value, '') // joins the remaining values
  .trim())
Magavern answered 3/5, 2021 at 20:36 Comment(0)
L
2

You can use the currencyDisplay: 'code' option, and since you know the currency code you can easily replace it by the symbol you want :

return Intl.NumberFormat(language, {
    style: 'currency', currency: currency.code, currencyDisplay: 'code'
  }).format(amount).replace(currency.code, currency.symbol);

This way you're keeping all the currency formatting standards implied in NumberFormat and replacing only the symbol. In your case the custom symbol would be an empty string ('') and you may want to trim your string too with .trim().

Larrikin answered 30/10, 2020 at 4:6 Comment(0)
T
2

Slight variation on the OPs answer including the minimumFractionDigits

const resolvedOptions = new Intl.NumberFormat('en-GB', { style: 'currency', currency: 'GBP', }).resolvedOptions();
const currencyOptions = {
    minimumFractionDigits: resolvedOptions.minimumFractionDigits,
    maximumFractionDigits: resolvedOptions.maximumFractionDigits
}
const value = (12345.678).toLocaleString('en-GB', currencyOptions)
Tonatonal answered 22/1, 2022 at 10:26 Comment(0)
L
1

I found this thread by searching this use case, and the trick i use using class Intl.NumberFormat, with Regex of symbol it supported on Mozilla Firefox and Google Chrome.The trick is take currency symbol and using it as a needle for regex replace after localisation.

This sample code should do the trick:

var number = 123456.789;

function getCurrencySymbol(locale, currency) {
  return (0).toLocaleString(locale, {
    style: 'currency',
    currency: currency,
    minimumFractionDigits: 0,
    maximumFractionDigits: 0
  }).replace(/\d/g, '').trim();
}
var numeric_format = new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', currencyDisplay: 'symbol' });
var localCurrencySymbol  = getCurrencySymbol('id-ID', 'IDR');
var CurrencySymbolNeedle = new RegExp(localCurrencySymbol, "g");

var amount = numeric_format.format(number);
console.log(localCurrencySymbol); // Rp
console.log(amount); // Rp 123.456,79
amount = amount.replace(CurrencySymbolNeedle, '').replace(/\s+/g, '');
console.log(amount); // 123.456,79

I don't test if this class support cross browser

Edit: Function to get currency symbol take from Get the currency symbol for a locale

Lozano answered 1/11, 2019 at 1:27 Comment(0)
Z
1

You just need to split the string with the sign, and then get the second value of the array.

// value 350011
 const valueFormated = (value).toLocaleString('en-US', {
  style: 'currency',
  currency: 'USD',
 });

 valueFormated.split('$')
 // if you console.log the result would be
 (2) ['', '3,500.11']

 // here is the value formated
 valueFormated.split('$')[1]
 // 3,500.11
Zebulen answered 11/1, 2022 at 18:0 Comment(2)
Splitting is not a good option because sometimes the sign comes last in some currencies, and you can't guess.Raker
@AdamAAllalou from my testing the position of the currencyDisplay is set by locale. If you do 'en' it will always be at the start, 'de' at the end. So you should have a reliable position if you set the locale.Cahill
M
0

Do you need the currency sign? If not number.toLocaleString('de-DE') should do the trick.

Marriage answered 7/7, 2017 at 11:47 Comment(3)
And how do I know the number of locale's currency fraction digits? It might be 0, 2 or 3: currency-iso.org/en/home/tables/table-a1.htmlAxillary
Sorry, i think i might have misunderstood you. What is your use-case?Marriage
@dMedia. new Intl.NumberFormat('en', { style: 'currency', currency: 'EUR', }).resolvedOptions().maximumFractionDigitsDisable
B
0
const locale = 'en-US';
const currency = 'USD';

const getCurrencySymbol = () =>
  (0)
    .toLocaleString(locale, {
      style: 'currency',
      currency: currency,
      maximumFractionDigits: 0,
      minimumFractionDigits: 0,
    })
    .replace(/\d/g, '')
    .trim();

const formattedNumberWithoutSymbol = new Intl.NumberFormat(locale, {
  style: 'currency',
  currency: currency,
}).format(499.99).replace(getCurrencySymbol(), '');

console.log(formattedNumberWithoutSymbol);
Blowhard answered 23/6, 2023 at 11:37 Comment(0)
A
0

According to Mozilla's documentation, there is the style option "decimal" which returns the plain number:

"decimal" (default) For plain number formatting.

Code looks like this (style is optional in this case):

console.log(
  new Intl.NumberFormat('de-DE', { style: 'decimal', currency: 'EUR', maximumFractionDigits: 2 }).format(
    number,
  ),
);
// Expected output: "123.456,79"

Try it on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat

Ascham answered 4/3, 2024 at 15:27 Comment(0)
O
-1

Just put options as:

{ minimumFractionDigits: 2, maximumFractionDigits: 2 }

const s = 1234.567 
const options = { minimumFractionDigits: 2, maximumFractionDigits: 2 }
const result = new Intl.NumberFormat('pt-BR', options).format(s);
Oneness answered 23/10, 2020 at 12:20 Comment(0)
N
-1

according to MDN you can use following format

new Intl.NumberFormat('de-DE', { maximumSignificantDigits: 3 }).format(number))

use maximumSignificantDigits option only

Neutrino answered 27/6, 2022 at 10:24 Comment(3)
And how do we get the maximumSignificantDigits value?Axillary
@dMedia it's a value you use based on need. in some cases you need two digit separation, in cases you need 3 digit separation. mostly depends on the currency systemNeutrino
The question was basically about how to get the number of the locale's currency fraction digits.Axillary
D
-1

Since you know the currency symbol being formated you can just use .substring(n) accordingly based on the currency symbol and its position.

Desiccator answered 10/4, 2023 at 7:57 Comment(0)
M
-2

THIS WHAT YOU NEED TO DO

const formatToDecimal = (amount: number) => {
 return Number(amount).toFixed(1).replace(/\d(?=(\d{3})+\.)/g, '$&,');
};
Megacycle answered 23/10, 2021 at 22:18 Comment(1)
then you don't get the right decimals, always. eg try BHDCahill

© 2022 - 2025 — McMap. All rights reserved.