【问题标题】:Get List of Supported Currencies获取支持的货币列表
【发布时间】:2020-01-21 13:41:02
【问题描述】:

除了猜测(就像我在下面所做的那样)之外,是否有一种更直接和更有效的方式来反思检索您的 JavaScript 环境支持的所有货币的列表?

function getSupportedCurrencies() {
  function $(amount, currency) {
    let locale = 'en-US';
    let options = {
      style: 'currency',
      currency: currency,
      currencyDisplay: "name"
    };
    return Intl.NumberFormat(locale, options).format(amount);
  }
  const getAllPossibleThreeLetterWords = () => {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    const arr = [];
    let text = '';
    for (let i = 0; i < chars.length; i++) {
      for (let x = 0; x < chars.length; x++) {
        for (let j = 0; j < chars.length; j++) {
          text += chars[i];
          text += chars[x];
          text += chars[j];
          arr.push(text);
          text = '';
        }
      }
    }
    return arr;
  };
  let ary = getAllPossibleThreeLetterWords();
  let currencies = [];
  const rx = /(?<= ).+/; // This line doesn't work in Firefox versions older than version 78 due to bug 1225665: https://bugzilla.mozilla.org/show_bug.cgi?id=1225665
  ary.forEach((cur) => {
    let output = $(0, cur).trim();
    if (output.replace(/^[^ ]+ /, '') !== cur) {
      let obj = {};
      obj.code = cur;
      obj.name = output.match(rx)[0];
      currencies.push(obj);
    }
  });
  return currencies;
}
console.log(getSupportedCurrencies());

【问题讨论】:

  • 我没有提交此代码以供审核。我只是把它作为一个低效的例子提供(否则本来是一个句子的问题)。
  • 有趣的问题。但这有关系吗? Intl.NumberFormat(),没有指定区域设置,将使用用户计算机的默认设置,这几乎总是我需要的,所以我很好奇为什么你需要用户计算机已安装的区域设置的完整列表。
  • @Shilly 不全是 locales,全是 currencies。不是来自计算机,而是来自当前环境
  • 也许是这个stackoverflow.com/questions/35126247/…的一个版本
  • 我们是否可以让一个 powershell 或 bash 脚本将所有可用的语言环境作为环境变量注入节点?因为至少 powershell 可以遍历所有已安装的语言环境。还是比测试所有字母代码更糟糕?

标签: javascript node.js internationalization currency ecmascript-next


【解决方案1】:

您可以通过此 XML 加载已知列表:

https://www.currency-iso.org/dam/downloads/lists/list_one.xml

列表在这里找到:https://www.currency-iso.org/en/home/tables/table-a1.html

<ISO_4217 Pblshd="2018-08-29">
  <CcyTbl>
    <CcyNtry>
      <CtryNm>
        UNITED KINGDOM OF GREAT BRITAIN AND NORTHERN IRELAND (THE)
      </CtryNm>
      <CcyNm>Pound Sterling</CcyNm>
      <Ccy>GBP</Ccy>
      <CcyNbr>826</CcyNbr>
      <CcyMnrUnts>2</CcyMnrUnts>
    </CcyNtry>
    <CcyNtry>
      <CtryNm>UNITED STATES OF AMERICA (THE)</CtryNm>
      <CcyNm>US Dollar</CcyNm>
      <Ccy>USD</Ccy>
      <CcyNbr>840</CcyNbr>
      <CcyMnrUnts>2</CcyMnrUnts>
    </CcyNtry>
  </CcyTbl>
</ISO_4217>

var xmlString = getSampleCurrencyXml();
var xmlData = (new window.DOMParser()).parseFromString(xmlString, "text/xml");
var knownCodes = [].slice.call(xmlData.querySelectorAll('Ccy')).map(n => n.textContent)

// Fetch the XML instead?
fetch('https://www.currency-iso.org/dam/downloads/lists/list_one.xml', { cache: 'default' })
  .then(response => response.text())
  .then(xmlStr => (new window.DOMParser()).parseFromString(xmlStr, "text/xml"))
  .then(data => knownCodes = data); // This may not work in the Stack Snippet

console.log(getSupportedCurrencies().map(c => c.code + '\t' + c.name).join('\n'));

function getSupportedCurrencies() {
  function $(amount, currency) {
    return Intl.NumberFormat('en-US', {
      style: 'currency',
      currency: currency,
      currencyDisplay: 'name'
    }).format(amount);
  }
  return knownCodes.reduce((currencies, cur) => {
    return (output => {
      return output.replace(/^[^ ]+ /, '') !== cur ?
        currencies.concat({
          code: cur,
          name: output.match(/(?<= ).+/)[0]
        }) :
        currencies;
    })($(0, cur).trim());
  }, []);
}

function getSampleCurrencyXml() {
  return `
    <ISO_4217 Pblshd="2018-08-29">
      <CcyTbl>
        <CcyNtry>
          <CtryNm>
            UNITED KINGDOM OF GREAT BRITAIN AND NORTHERN IRELAND (THE)
          </CtryNm>
          <CcyNm>Pound Sterling</CcyNm>
          <Ccy>GBP</Ccy>
          <CcyNbr>826</CcyNbr>
          <CcyMnrUnts>2</CcyMnrUnts>
        </CcyNtry>
        <CcyNtry>
          <CtryNm>UNITED STATES OF AMERICA (THE)</CtryNm>
          <CcyNm>US Dollar</CcyNm>
          <Ccy>USD</Ccy>
          <CcyNbr>840</CcyNbr>
          <CcyMnrUnts>2</CcyMnrUnts>
        </CcyNtry>
      </CcyTbl>
    </ISO_4217>
  `;
}
.as-console-wrapper { top: 0; max-height: 100% !important; }

如果您还想生成代码,可以使用产品迭代。

以下基于Python的itertools.product函数。

let ary = product('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''), 3).map(a => a.join(''));

function product(iterables, repeat) {
  var argv = Array.prototype.slice.call(arguments), argc = argv.length;
  if (argc === 2 && !isNaN(argv[argc - 1])) {
    var copies = [];
    for (var i = 0; i < argv[argc - 1]; i++) { copies.push(argv[0].slice()); }
    argv = copies;
  }
  return argv.reduce((accumulator, value) => {
    var tmp = [];
    accumulator.forEach(a0 => value.forEach(a1 => tmp.push(a0.concat(a1))));
    return tmp;
  }, [[]]);
}

演示

console.log(getSupportedCurrencies().map(c => c.code + '\t' + c.name).join('\n'));

function getSupportedCurrencies() {
  function $(amount, currency) {
    return Intl.NumberFormat('en-US', {
      style: 'currency',
      currency: currency,
      currencyDisplay: 'name'
    }).format(amount);
  }
  let ary = product('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''), 3).map(a => a.join(''));
  return ary.reduce((currencies, cur) => {
    return (output => {
      return output.replace(/^[^ ]+ /, '') !== cur
        ? currencies.concat({ code : cur, name : output.match(/(?<= ).+/)[0] })
        : currencies;
    })($(0, cur).trim());
  }, []);
}

function product(iterables, repeat) {
  var argv = Array.prototype.slice.call(arguments), argc = argv.length;
  if (argc === 2 && !isNaN(argv[argc - 1])) {
    var copies = [];
    for (var i = 0; i < argv[argc - 1]; i++) { copies.push(argv[0].slice()); }
    argv = copies;
  }
  return argv.reduce((accumulator, value) => {
    var tmp = [];
    accumulator.forEach(a0 => value.forEach(a1 => tmp.push(a0.concat(a1))));
    return tmp;
  }, [[]]);
}
.as-console-wrapper { top: 0; max-height: 100% !important; }

【讨论】:

  • 您可能想要过滤该列表中所有具有IsFund="true" 和任何以X 开头的货币代码的事物,因为它们并不是真正的货币。
【解决方案2】:

现在,正如公认的答案所提供的,详尽的测试可能是这里最合理的实用方法。此外,新货币不会出现,旧货币不会死去,而且频率特别高。任何实施支持的货币都保持最新,几乎总是会反映现实。因此,试一试的方法确实不会失败。

但要从规范方面进一步详细说明,规范实际上只关心“格式正确”的货币:三个 ASCII 字母。如果生成的代码是已知的货币,您将获得合适的行为。否则,您将大致优雅地回退到代码本身。所以值得商榷不需要公开支持的列表:货币代码至少对许多用户来说是一个相对容易理解的东西,可能就像在大多数 UI 中看到“3 美元”或“5 加元”之类的东西涉及价格或成本的地方通常意味着用户的货币。

在未来,然而,公开一组已识别货币的spec proposal 正在走向标准化。初始实现可能会在 2021 年底之前开始出现在 Web 浏览器的 JS 实现中,让您这样做:

// This will return an array of currency codes supported
// by Intl.NumberFormat and Intl.DisplayNames, e.g.:
//   ["ADP", "AED", ..., "JPY", ..., "USD", ...]
var currencies = Intl.supportedValuesOf("currency");

【讨论】:

  • 感谢您 7 月 10 日的编辑。感谢更新。我很高兴看到这个。
猜你喜欢
  • 1970-01-01
  • 2014-07-30
  • 1970-01-01
  • 2012-07-20
  • 2018-03-21
  • 1970-01-01
  • 2016-07-13
  • 1970-01-01
  • 2014-12-07
相关资源
最近更新 更多