我们做前端,经常会遇到国际化(i18n)的需求。最常见的就是,如何根据用户的地区,显示不同格式的数字、货币和日期。
在不了解Intl
对象之前,我们可能会写出这样的代码:
JavaScript
// 场景:显示商品价格
function formatPrice(price, currency) {
if (currency === 'USD') {
return '$' + price.toFixed(2);
} else if (currency === 'JPY') {
return '¥' + price.toFixed(0);
} else {
// 更多if...else...
return price;
}
}
这段代码不仅繁琐、难以维护,而且根本不严谨。比如,数字的千分位分隔符在不同国家是不一样的(美国用逗号,
,德国用点.
)。
为了解决这些问题,我们通常会引入一个庞大的第三方库,增加了项目的打包体积。
但实际上,浏览器已经给了我们一个"官方答案"------Intl
对象。本文将带你深入了解这个原生API,看看如何用它来优雅地处理国际化需求,让你告别大部分手写i18n的繁琐工作。
数字格式化 (Intl.NumberFormat
):不只是加个千分位
这是Intl
对象中最常用的功能之一。它可以根据不同的语言环境,格式化数字、货币、单位等。
1. 千分位处理
JavaScript
const number = 1234567.89;
// 美式英语
console.log(new Intl.NumberFormat('en-US').format(number));
// 输出: "1,234,567.89"
// 德语
console.log(new Intl.NumberFormat('de-DE').format(number));
// 输出: "1.234.567,89" (注意分隔符的区别)
2. 格式化货币、单位和百分比
Intl.NumberFormat
的第二个参数是一个options
对象,可以解锁更多强大的功能。
JavaScript
const price = 99.9;
// 格式化货币
console.log(new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(price));
// 输出: "$99.90"
console.log(new Intl.NumberFormat('ja-JP', { style: 'currency', currency: 'JPY' }).format(price));
// 输出: "¥100" (日元会自动四舍五入到整数)
const speed = 120;
// 格式化单位
console.log(new Intl.NumberFormat('en-US', { style: 'unit', unit: 'kilometer-per-hour' }).format(speed));
// 输出: "120 km/h"
console.log(new Intl.NumberFormat('zh-CN', { style: 'unit', unit: 'gigabyte', unitDisplay: 'long' }).format(100));
// 输出: "100吉字节"
const percentage = 0.85;
// 格式化百分比
console.log(new Intl.NumberFormat('en-US', { style: 'percent' }).format(percentage));
// 输出: "85%"
3. 紧凑数字格式
这个功能非常适合在UI空间有限的地方显示大数字。
JavaScript
const views = 123456;
console.log(new Intl.NumberFormat('en-US', { notation: 'compact' }).format(views));
// 输出: "123K"
console.log(new Intl.NumberFormat('zh-CN', { notation: 'compact' }).format(views));
// 输出: "12万"
日期和时间格式化 (Intl.DateTimeFormat
):date-fns
的轻量替代
处理日期是另一个常见的痛点。Intl.DateTimeFormat
提供了一套完整且灵活的解决方案。
1. 基础用法与预设样式
JavaScript
const date = new Date(); // 假设现在是 2025年7月25日
// 使用预设样式
console.log(new Intl.DateTimeFormat('en-US', { dateStyle: 'full' }).format(date));
// 输出: "Friday, July 25, 2025"
console.log(new Intl.DateTimeFormat('zh-CN', { dateStyle: 'long' }).format(date));
// 输出: "2025年7月25日"
console.log(new Intl.DateTimeFormat('en-GB', { dateStyle: 'short', timeStyle: 'short' }).format(date));
// 输出: "25/07/2025, 11:11" (英式日期格式)
2. 自定义格式与时区处理
你可以精确地控制你想显示的每一个部分。
JavaScript
const date = new Date();
const options = {
year: 'numeric', // "2025"
month: 'long', // "July" or "七月"
day: '2-digit', // "25"
weekday: 'short', // "Fri" or "周五"
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
timeZoneName: 'short',
timeZone: 'Asia/Taipei' // 关键!指定时区
};
console.log(new Intl.DateTimeFormat('en-US', options).format(date));
// 输出: "Fri, July 25, 2025 at 11:11:10 AM GMT+8"
console.log(new Intl.DateTimeFormat('zh-TW', options).format(date));
// 输出: "2025年7月25日 週五 上午11:11:10 GMT+8"
时区处理 是Intl.DateTimeFormat
的一大亮点,无需任何第三方库,就能准确地在不同时区之间转换和显示时间。
复数处理 (Intl.PluralRules
):终结 if (count > 1)
如何根据数量显示单数或复数?比如 "1 item" 和 "2 items"。在英语里,一个if (count > 1)
似乎就解决了。但在其他语言里,复数规则远比这复杂(比如俄语、阿拉伯语有好几种复数形式)。
Intl.PluralRules
就是用来解决这个问题的"标准答案"。它不会直接帮你拼接字符串,而是告诉你一个数字在特定语言环境下,属于哪种复数类别 ("zero"
, "one"
, "two"
, "few"
, "many"
, "other"
)。
JavaScript
// 以英语为例
const enPluralRules = new Intl.PluralRules('en-US');
console.log(enPluralRules.select(0)); // "other"
console.log(enPluralRules.select(1)); // "one"
console.log(enPluralRules.select(2)); // "other"
// 以波兰语为例,它的复数规则更复杂
const plPluralRules = new Intl.PluralRules('pl-PL');
console.log(plPluralRules.select(1)); // "one" (1)
console.log(plPluralRules.select(2)); // "few" (2, 3, 4)
console.log(plPluralRules.select(5)); // "many" (5, 6, ...)
用法:
JavaScript
const messages = {
zh: {
one: `有 {count} 个项目`,
other: `有 {count} 个项目`
},
en: {
one: `Found {count} item`,
other: `Found {count} items`
}
};
function getPluralMessage(locale, count) {
const langMessages = messages[locale];
const pluralRules = new Intl.PluralRules(locale);
const rule = pluralRules.select(count); // 获取复数类别
return langMessages[rule].replace('{count}', count); // 根据类别选择正确的字符串
}
console.log(getPluralMessage('en', 1)); // "Found 1 item"
console.log(getPluralMessage('en', 5)); // "Found 5 items"
相对时间格式化 (Intl.RelativeTimeFormat
)
这也是一个非常实用的功能,用于显示"昨天"、"5分钟前"、"3周后"这种相对时间。
JavaScript
const rtf = new Intl.RelativeTimeFormat('zh-CN', { numeric: 'auto' });
console.log(rtf.format(-1, 'day')); // "昨天"
console.log(rtf.format(0, 'day')); // "今天"
console.log(rtf.format(2, 'hour')); // "2小时后"
console.log(rtf.format(-5, 'minute'));// "5分钟前"
Intl
对象是浏览器提供的一套强大、标准且高效的国际化工具集。
下次再遇到国际化需求时,先别急着npm install
。看一看浏览器原生的Intl
对象,它可能已经为你准备好了更轻量、更标准的解决方案。