最近在项目中遇到了多语言价格格式化的需求(即 $2399 => $2,399 的转换)。在过去做大陆站时显然是没有这种需求的,因为千位分隔符(group separator)是为了方便快速看懂大数字位数,根据英语的千位分位方式(千、百万、十亿、万亿)而设置的。中文虽然国标规定四位以内的整数可以不分节,但所有主流网站对更大的数字也都没有进行数字分节。因为千位分隔符对中国人来说本身就是没有卵用的东西,中文即便使用数字分位,也是万位分位方式(万、亿、兆)。
那么用代码对数字进行格式化,显然不是逢三位加逗号这么简单。比如印度在数字分位符号上的处理,就堪称业界奇葩:
印度的数字读法用“拉克”(十万)和“克若尔”(千万),数字标法用不对称的数位分离,即小数点左侧首先是三位分隔,然后继续向左都是两位分隔。如:三千万(3 克若尔)会写成 3,00,00,000。 —— 维基百科
简单的暴利处理无法满足多语言支持,此时使用 Number.prototype.toLocaleString()
进行数字格式化处理再好不过。
使用 .toLocaleString()
在 JavaScript 中,数字对象的 .toLocaleString()
方法如果不传参数,则采用宿主环境的系统语言进行分位处理。
var price = 1024;
price.toLocaleString(); // => "1,024"
使用 locales
参数
在 ECMA-402 标准的实现中,增加了.toLocaleString()
方法对 locales
的支持,语法为 numObj.toLocaleString([locales [, options]])
,locales
参数接收 BCP 47 语言标签格式的字符串或数组。
那么将数字强制转化为印度格式就变的简单:
var price = 1669999;
price.toLocaleString('en-IN'); // => "16,69,999"
这样就可以轻松处理多语言的自动格式化了,只要根据 <html lang="en-IN">
中的 lang
属性动态读取就可以了。
var price = 1669999;
var lang = document.querySelector('html').getAttribute('lang');
price.toLocaleString(lang); // 中文页面下 => "1,669,999"
使用 options
参数
如果仅仅是做到多语言自动格式化数字,显然还不够细腻。通过 .toLocaleString()
方法的 options
参数,可以做到转化至相应语言的货币格式。
在我的项目之前的实现中,多国语言的货币符号是通过模板渲染时读取配置文件完成转换的。如果使用.toLocaleString()
展示或加工展示所有货币数字,则无需这一步骤:
var price = 2499;
price.toLocaleString('en-IN', {
style: 'currency',
currency: 'INR'
});
// => "₹ 2,499.00"
如果不想要显示末尾的小数「.00」,只要设置一下最小分位 minimumFractionDigits
即可(默认是 2):
var price = 2499;
price.toLocaleString('en-IN', {
style: 'currency',
currency: 'INR',
minimumFractionDigits: 0
});
// => "₹ 2,499"
这样一个完美的价格格式化功能就完成了。options
对象参数接收一系列样式属性,常用的有:
style
:可选值为decimal
(小数)、currency
(货币)或percent
(百分比);currency
:设置为货币样式时使用的符号,支持列表在这里;useGrouping
:布尔值,是否显示数字分位。
关于 locales
参数和 options
参数支持的其它属性,例如上面使用的 minimumFractionDigits
,可以查阅 MDN,我刚把最新的英文版翻译了一遍。
兼容性
所有现代浏览器都支持 locales
参数,因此在移动端使用是安全无痛的。桌面端的支持则是 IE11 及以上。
另外,如果想在后端直接对不同页面直接输出对应的货币符或者做分位转换等操作,只要用 node.js 做一个转换就行了。
想到这里,我已经忍不住要萌萌哒了,去优化我们的工作流啦。JavaScript,FTW!
相关链接
-- EOF --