Javascript number.toLocaleString currency without currency sign

38,648

Solution 1

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.

Solution 2

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 });

Solution 3

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

Solution 4

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)

Solution 5

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().

Share:
38,648
dMedia
Author by

dMedia

Updated on January 23, 2022

Comments

  • dMedia
    dMedia over 2 years

    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.

  • dMedia
    dMedia almost 7 years
    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.html
  • Cornelius Fillmore
    Cornelius Fillmore almost 7 years
    Sorry, i think i might have misunderstood you. What is your use-case?
  • dMedia
    dMedia about 6 years
    And how do I know the number of locale's currency fraction digits? It might be 0, 2 or 3.
  • Shahzaib Hayat Khan
    Shahzaib Hayat Khan about 6 years
    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.
  • dMedia
    dMedia about 6 years
    I know where to pass fraction digit. What I don't know is how to get that digit in javascript.
  • dMedia
    dMedia over 5 years
    It is useful but I still hope that there is an option in number.toLocaleString that we don't know about.
  • Alexander  Pravdin
    Alexander Pravdin over 5 years
    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.
  • Shahzaib Hayat Khan
    Shahzaib Hayat Khan over 5 years
    didn't mean to offend you or question your programming skills. I might havn't understood your question properly brother.
  • Aner
    Aner almost 4 years
    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 fields
  • Karolis.sh
    Karolis.sh almost 4 years
    @dMedia. new Intl.NumberFormat('en', { style: 'currency', currency: 'EUR', }).resolvedOptions().maximumFractionDigits
  • KohlerDominik
    KohlerDominik over 2 years
    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/e80vutwq
  • Martin Braun
    Martin Braun over 2 years
    @KohlerDominik 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.
  • KohlerDominik
    KohlerDominik over 2 years
    Yes, now it will work. It's now literally a duplicate of the one from @nyg below.
  • Martin Braun
    Martin Braun over 2 years
    @KohlerDominik 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.
  • Ray
    Ray over 2 years
  • Alexander  Pravdin
    Alexander Pravdin over 2 years
    @Ray 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.
  • Alexander  Pravdin
    Alexander Pravdin over 2 years
    How to get other formatting options - fractional and thousand separators? A complete code would be useful.