如何使用JavaScript为不同语言/区域动态格式化数字、货币和单位?
数字的格式,包括货币和单位等格式,在不同文化、地区和语言之间差异很大,看似无伤大雅的错误也可能导致误解或出错。
把格式硬编码到页面里很容易出问题,而且难以长期维护。Web平台提供了稳健且基于标准的方案来应对这个复杂的问题。本文将介绍如何利用JavaScript自带的Intl对象,让你的网页能够轻松适配不同国际环境下的数字、货币和单位格式。
在介绍解决方案之前,先看看为什么国际化数字、货币和单位格式化并不简单:
许多地区,如美国和英国,使用句点作为小数分隔符(例如1,234.56),而欧洲和南美的大部分地区使用逗号(例如1.234,56)。
在少数情况下,货币符号甚至可以充当小数分隔符,例如佛得角埃斯库多。
数字的分组分隔符有所不同,可能是逗号、句点,也可能是空格。
分组方式也不同。比较常见的是每3位一组(例如1,234,567),但有些地区(如印度)在百位以上采用每2位一组(例如12,34,567)。某些格式也会使用每4位一组。
虽然欧洲数字(0-9)在全球都很常见,但许多文化更偏好使用本地的数字系统。例如,12,345在阿拉伯语中可能写作١٢٬٣٤٥,在泰语中可能写作๑๒,๓๔๕。
符号、代码还是名称:货币可以用多种方式显示:
CA$、US$、MX$)¥或円)EUR、GBP、JPY)美元、日元)位置和间距:符号可以出现在数字前面(例如$100.00),也可以出现在后面(例如1,000 ₫)。我们从这两个例子也可以看出,有些货币符号与数字之间不留空格,而有些则会留空格。
歧义:同一个符号可能代表多种货币(例如$可以表示美元、加元、墨西哥比索等)。
Intl.NumberFormat对象JavaScript中的Intl.NumberFormat对象会自动处理特定语言/区域的小数分隔符、数字分组分隔符、货币符号以及其他数字书写习惯。
Intl.NumberFormat格式化普通数字Intl.NumberFormat允许你按照指定的语言区域来格式化数字。
const number = 1234567.89;
// 面向美国英语用户
const usFormatter = new Intl.NumberFormat('en-US');
console.log(`英语(美国): ${usFormatter.format(number)}`); // 输出:英语(美国): 1,234,567.89
// 面向德语用户
const deFormatter = new Intl.NumberFormat('de-DE');
console.log(`德语: ${deFormatter.format(number)}`); // 输出:德语: 1.234.567,89
// 面向印度英语用户(注意分组方式)
const enINFormatter = new Intl.NumberFormat('en-IN');
console.log(`英语(印度): ${enINFormatter.format(number)}`); // 输出:英语(印度): 12,34,567.89
new Intl.NumberFormat(locales, options)中的options对象是关键所在。
minimumFractionDigits和maximumFractionDigits用于控制小数位数。useGrouping是一个布尔值,用来开启或关闭数字分组。
const pi = 3.14159265;
// 强制指定精度
const preciseFormatter = new Intl.NumberFormat('en-US', {
minimumFractionDigits: 5,
maximumFractionDigits: 5,
});
console.log(`${preciseFormatter.format(pi)}`); // 输出:3.14159
// 不分组
const noGroupingFormatter = new Intl.NumberFormat('en-US', {
useGrouping: false,
});
console.log(`不分组: ${noGroupingFormatter.format(1234567)}`); // 输出:不分组: 1234567
Intl.NumberFormat你可以指定style: 'currency',并提供currency代码(使用ISO 4217标准)。
const price = 500.75;
// 美元
const usdFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
});
console.log(`美元: ${usdFormatter.format(price)}`); // 输出:美元: $500.75
// 德国使用的欧元
const eurDeFormatter = new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR',
});
console.log(`欧元(德国): ${eurDeFormatter.format(price)}`); // 输出:欧元(德国): 500,75 €
// 日元(默认不显示小数位):
const jpyFormatter = new Intl.NumberFormat('ja-JP', {
style: 'currency',
currency: 'JPY',
});
console.log(`日元: ${jpyFormatter.format(price)}`); // 输出:日元: ¥501(会自动四舍五入且不显示小数)
// 越南盾(默认不显示小数位):
const vndFormatter = new Intl.NumberFormat('vi-VN', {
style: 'currency',
currency: 'VND',
});
console.log(`越南盾: ${vndFormatter.format(12000)}`); // 输出:越南盾: 12.000 ₫
Intl.NumberFormat会自动为给定货币处理正确的小数位数。如有需要,你也可以用minimumFractionDigits和maximumFractionDigits来覆盖默认值。
Intl.NumberFormat格式化单位Intl.NumberFormat也可以为带单位的数字设置格式:
const distance = 1000;
const storage = 5;
// 米
const meterFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'meter', // 标准单位标识符
unitDisplay: 'long', // 'long'、'short' 或 'narrow'
});
console.log(`美式英语中的米(长格式): ${meterFormatter.format(distance)}`); // 输出:美式英语中的米(长格式): 1,000 meters
const meterShortFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'meter',
unitDisplay: 'short',
});
console.log(`美式英语中的米(短格式): ${meterShortFormatter.format(distance)}`); // 输出:美式英语中的米(短格式): 1,000 m
// 法语区域设置中的千字节:
const kbFrFormatter = new Intl.NumberFormat('fr-FR', {
style: 'unit',
unit: 'kilobyte',
unitDisplay: 'long',
});
console.log(`法语中的千字节: ${kbFrFormatter.format(storage)}`); // 输出:法语中的千字节: 5 kilooctets
标准单位标识符列表(例如meter、kilogram、liter、kilobyte、percent、hour)可参见ECMAScript国际化API规范。
通常,你会希望根据网页的语言来格式化数字、货币和单位。这可以通过HTML元素上的lang属性来确定(你需要设置这个属性):
// 从HTML lang属性获取页面语言
const pageLocale = document.documentElement.lang || 'en-US'; // 回退为'en-US'
const formatter = new Intl.NumberFormat(pageLocale, { style: 'currency', currency: 'USD' });
console.log(`${formatter.format(627.92)}`);
有时,你可能希望用某个特定语言区域覆盖页面默认语言,例如在制作国际化教程或展示多语言内容时:
// 不管页面语言是什么,都强制使用特定语言区域
const tutorialFormatter = new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' });
console.log(`德语示例: ${tutorialFormatter.format(199.99)}`); // 输出:199,99 €