国际化之数字价格千分位分隔符 toLocaleString()

10,556 阅读3分钟

之前在只有单个国家的时候我们可以通过对数字进行分割来达到千分位分隔符的效果。

给价格加入符号作为千分位, 默认使用逗号

function formatPrice (number, sign) {
  !sign && (sign = ',')
  var parts = number.toString().split('.')
  parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, sign)
  return parts.join('.')
}

但随着国家的增多,各个国家的分隔符各不相同,小数点的分隔符也不相同。比如印尼(3199=>3.199),法国(3199=>3 199),美国(3199=>3,199)

以之前的通过分割的方式来实现千分位分割已经不能满足之前的效果。[Number.prototype.toLocaleString(locales [, options]) 为我们带来了一种新的解决方法。

使用 locales 参数

function formatNum (num, local) {
    if (typeof num !== 'number') {
        num = Number(num)
    }
    const site = {
        'in': 'en-IN',
        'id': 'id-ID',
        'us': 'en-US',
        'uk': 'en-GB',
        'es': 'es-ES',
        'fr': 'fr-FR',
        'it': 'it-IT',
        'ru': 'ru-RU',
        'hk': 'zh-HK',
        'tw': 'zh-TW'
    }
    let name = site[local] || 'en-GB'
    return num.toLocaleString(name)
}

不同国家/地区可以参考下表: www.lingoes.net/en/translat…
价格单位可参考下表: www.currency-iso.org/en/home/tab…

如果还有使用货币单位的需求可以使用options参数
style
格式化时使用的样式.可能的值有“decimal”表示纯数字格式 , “currency”表示货币格式, 和"percent"表示百分比格式; 默认值是 "decimal".
currency
在货币格式化中使用的货币符号. 可能的值是ISO的货币代码 (the ISO 4217 currency codes,) 例如"USD" 表示美元, "EUR" 表示欧元, or "CNY"是人民币 — 更多请参考 Current currency & funds code list. 没有默认值,如果样式是“currency”,必须提供货币属性. minimumFractionDigits
使用的小数位数的最小数目.可能的值是从0到20;默认为普通的数字和百分比格式为0;默认为货币格式是由国际标准化组织列表( ISO 4217 currency code list )提供(如果列表中没有提供则值为2).

let price = 3199
price.toLocaleString('id-ID', {
    style: 'currency',
    currency: 'EUR',
    minimumFractionDigits: 2
}) // "€3.199,00"

兼容性:
这个API虽说在大部分浏览器上都已经支持,但在部分手机上还是存在不小问题。因此要适配移动端polyfill必不可少。 polyfill-Number.toLocaleString-with-Locales

相关延伸:将 1234567 转换为 1,234,567

解法1:

const num = 1234567
const str = num.toLocaleString()
console.log(str) // 1,234,567

解法2:

/**
* 正则表达式含义:
* \b 表示单词间隔,如 i am here \bhere\b,如果是 iamhere 则用 \bhere\b不能匹配here,只能用here匹配
* \B 和 \b 相反,类似 \d \D的关系。 \B表示非单词间隔上面的例子 iamhere 如果用 \Bhere 则可以匹配
* (?=(\d{3})+(?!\d))意思连续三位为数字,且满足最后一位不是数字,也就是单词结尾了,所以能做到单词往前推三位加上逗号
*/

function formatNumberRgx(num) {
    var parts = num.toString().split(".")
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",")
    return parts.join(".")
}

解法3:

function formatNumber(num) {
    var decimalPart = ''
    num = num.toString()
    if (num.indexOf('.') != -1) {
        decimalPart = '.' + num.split('.')[1]
        num = parseInt(num.split('.')[0])
    }
    var array = num.toString().split('')
    var index = -3
    while(array.length + index > 0) {
        array.splice(index, 0, ',')
        index -= 4
    }
    return array.join('') + decimalPart
}

思路
1. 把数组转化为字符串
2. 获取字符串的长度
3. 判断从前往后添加 ,  的位置
4. 拼接为新的字符串

function formatNumber(num) {
    var index, result, s, startLen
    s = num.toString()
    startLen = s.length % 3
    // 如果startLen为0
    if (!startLen) {
        startLen = 3
    }
    result = s.substr(0,startLen)
    index = startLen
    while (index < s.length) {
        result += ',' + s.substr(index, 3)
        index += 3
    }
    return result
}