Get the currency symbol for a locale
Asked Answered
C

4

20

How to get the currency symbol for a given currency string ("GBP", "USD" etc)? The best I've come up with seems ridiculously long winded, is there another way or am I better off with a lookup table?

const userLocale = "EN-gb";
const userCurrency = "GBP";
const withValueEl = document.querySelector(".withValue");
const withoutValueEl = document.querySelector(".withoutValue");
const valueWithCurrency = Number(0).toLocaleString(userLocale, {
  style: "currency",
  currency: userCurrency,
  minimumFractionDigits: 2
});
const valueWithoutCurrency = valueWithCurrency.replace(Number(0).toLocaleString(userLocale, {
  minimumFractionDigits: 2
}), "")

withValueEl.innerHTML = valueWithCurrency
withoutValueEl.innerHTML = valueWithoutCurrency
With value:<span class="withValue"></span><br /> Without value:<span class="withoutValue"></span><br />
Circumlocution answered 1/6, 2018 at 20:18 Comment(4)
May I suggest taking a look into dinerojs ?Mcarthur
With vanilla JS that's how you do it. To make it easier, you can use a library. Google "javascript currency symbol map"Nitrosamine
@J.Pichardo I can't work out how to do it any easier with dinerojsCircumlocution
@Amy if you'd like to add this as an answer I'll accept it.Circumlocution
U
31

This looks like more work than it really is when you're including all of the DOM selector and value injection logic, which is not related to the functionality you want. Extracting the symbol is pretty straightforward:

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

Or if you aren't using es6:

function getCurrencySymbol (locale, currency) {
  return (0).toLocaleString(
    locale,
    {
      style: 'currency',
      currency: currency,
      minimumFractionDigits: 0,
      maximumFractionDigits: 0
    }
  ).replace(/\d/g, '').trim()
}

The toLocaleString options are verbose, so there's not much to do about that. But you don't need to use the Number constructor (really ever). If you get the currency value without decimals or separators it's simple to remove the numbers and have only the symbol left. You'll want to take this kind of approach because, depending on the locale and the currency, the symbol is not always a single character. For example:

getCurrencySymbol('en-US', 'CNY') // CN¥
getCurrencySymbol('zh-CN', 'CNY') // ¥

Trimming the result is also a good idea. You can chain .trim() to the result like in the examples, or update the regex to include whitespaces. It should be noted this is a somewhat naive approach, since it only works for number characters 0-9. If you needed to include other number characters, such as Arabic (٠١٢٣٤٥٦٧٨٩), you'd need to update the regex to include unicode ranges: /[0-9\u0660-\u0669]/g. You'd have to add any other number system you need to support in similar fashion.

Localization is a non-trivial problem, so it might make more sense to just use a currency code to symbol map like this one.

Upward answered 12/12, 2018 at 18:15 Comment(0)
H
16

Unfortunately, I do not know of a way to directly get the currency symbol.

What I can suggest is an using Intl.NumberFormat#formatToParts(). It supplies segmented result that covers each part of the formatted string, so it can be programmatically examined it without having to guess where the currency symbol is located:

const sym = (currency, locale) =>
  new Intl.NumberFormat(locale, { style: 'currency', currency })
    .formatToParts(1)
    .find(x => x.type === "currency")
    .value;

console.log(sym('EUR', 'de-DE'));

Otherwise trying to get a currency by position or otherwise by examining the string may not work as the the currency symbol may be in different places:

const options = { style: 'currency', currency: "EUR" };
const us = new Intl.NumberFormat("en-US", options)
  .format(1);
const de = new Intl.NumberFormat("de-DE", options)
  .format(1);

console.log(us);
console.log(de);

Or a code might have multiple letters, not just a single symbol like the Mexican Peso:

const options = { style: 'currency', currency: "MXN" };
const mx = new Intl.NumberFormat("de-DE", options)
  .format(1);

console.log(mx);

For reference, there is Intl.NumberFormat#resolvedOptions() which will get the resolved options of a Intl.NumberFormat object, but it does not provide the symbol. Just the options that can be passed to another formatter:

const initialOptions = { style: 'currency', currency: "USD" };
const numberFormat1 = new Intl.NumberFormat('de-DE', initialOptions);
const options1 = numberFormat1.resolvedOptions();

//clone and change the currency:
const options2 = Object.assign({}, options1, {currency: "EUR"});
const numberFormat2 = new Intl.NumberFormat('de-DE', options2);

console.log(numberFormat1.format(1));
console.log(numberFormat2.format(1));


console.log(options1);
.as-console-wrapper { max-height: 100% !important; }
Harvell answered 19/9, 2022 at 11:28 Comment(0)
B
6

Intnl.NumberFormat#formatToParts (MDN documentation) will return an array of the formatted parts, including an entry that looks like { type: 'currency', value: '$' }, for USD.

So, using that you can do:

const userLocale = "EN-gb";
const userCurrency = "GBP";
const withCurrency = new Intl.NumberFormat(userLocale, { style: 'currency', currency: userCurrency }).formatToParts(3.50).map(val => val.value).join('');
const withoutCurrency = new Intl.NumberFormat(userLocale, { style: 'currency', currency: userCurrency }).formatToParts(3.50).slice(1).map(val => val.value).join('');

And reading the values:

> withCurrency
'£3.50'
> withoutCurrency
'3.50'
Beelzebub answered 5/4, 2020 at 18:47 Comment(1)
The withoutCurrency won't work in all cases as some locale/currency combos (e.g. RU/RUB) display the currency symbol at the end of the amount.Constrained
M
1

Answering just the title of your question.

const currencySymbol = (locale, currency) => {
  const formatter = new Intl.NumberFormat(locale, {
    style: 'currency',
    currency,
  });

  let symbol;
  formatter.formatToParts(0).forEach(({ type, value }) => {
    if (type === 'currency') {
      symbol = value;
    }
  });

  return symbol;
};

console.log(currencySymbol('en-GB', 'GBP'), '   : Your example')
console.log(currencySymbol('zh', 'CNY'), '   : Yuan in China')
console.log(currencySymbol('en-US', 'CNY'), ' : Yuan in USA')
console.log(currencySymbol('en-US', 'USD'), '   : US Dollar in USA')
console.log(currencySymbol('zh', 'USD'), ' : US Dollar in China')

Some helpful references...

Mallette answered 15/9, 2022 at 23:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.