别再手写i18n了!深入浏览器原生Intl对象(数字、日期、复数处理)

我们做前端,经常会遇到国际化(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对象,它可能已经为你准备好了更轻量、更标准的解决方案。

相关推荐
程序员是干活的27 分钟前
Java EE前端技术编程脚本语言JavaScript
java·大数据·前端·数据库·人工智能
白云~️32 分钟前
js实现宫格布局图片放大交互动画
开发语言·javascript·交互
南囝coding1 小时前
Coze 开源了!所有人都可以免费使用了
前端·后端·产品
CDwenhuohuo1 小时前
滚动提示组件
java·前端·javascript
说码解字1 小时前
Kotlin 内联函数
前端
PineappleCoder1 小时前
性能优化与状态管理:React的“加速器”与“指挥家”
前端·react.js
讨厌吃蛋黄酥1 小时前
深度解析:useContext + useReducer — React官方状态管理的终极之道
javascript·react.js·前端框架
_一两风1 小时前
深入理解React中的虚拟DOM与Diff算法
前端
GoodTime1 小时前
CodeBuddy IDE深度体验:全球首个产设研一体AI工程师的真实使用报告
前端·后端·架构
前端的日常1 小时前
说说你对 React Hook的闭包陷阱的理解,有哪些解决方案?
前端