Intl API强大功能指南:浏览器原生国际化解决方案

前端

📚 本篇依然来自于我们的 《前端周刊》 项目! 🧑‍💻 由团队成员 德育处主任 翻译,欢迎大家 进群 持续追踪全球最新前端资讯!! 📜 原文:The Power Of The Intl API: A Definitive Guide To Browser-Native Internationalization

国际化可不只是翻译文本那么简单。它涉及到根据特定区域设置格式化日期、复数形式转换、名称排序等诸多方面。如今,JavaScript 自带了 Intl API—— 无需依赖臃肿的第三方库,就能原生处理国际化问题。这也在默默提醒我们:网络确实是面向全球的。

很多人觉得国际化(i18n)就是简单的文本翻译,这其实是个误区。翻译固然重要,但只是其中一个方面。真正的复杂之处在于,要根据不同文化的习惯调整信息呈现方式:在日本和德国,日期的显示方式有何不同?在阿拉伯语和英语里,名词的复数形式规则有什么区别?如何对不同语言的名称列表进行排序?

过去,很多开发者会依赖庞大的第三方库,甚至自己手写格式化函数来解决这些问题。这些方案虽然能用,但往往伴随着不少麻烦:包体积增大、可能出现性能瓶颈,还要不断跟进语言规则和区域数据的更新。

这时,ECMAScript 国际化 API(通常称为 Intl 对象)就派上用场了。这个内置在现代 JavaScript 环境中的 “隐形高手”,常常被低估,但其实是处理数据国际化的强大工具 —— 原生支持、性能出色,还符合标准。它证明了网络对全球化的承诺:提供统一高效的方式,根据特定区域设置格式化数字、日期、列表等内容。

Intl 与区域设置:不只是语言代码

Intl 的核心是 “区域设置(locale)” 的概念。区域设置远不止两个字母的语言代码(比如英语是 en,西班牙语是 es),它包含了让信息符合特定文化群体习惯所需的完整上下文,具体包括:

  • 语言:主要的语言(例如 enesfr);

  • 文字系统:书写体系(例如 Latn 代表拉丁字母,Cyrl 代表西里尔字母)。比如 zh-Hans 表示简体中文,zh-Hant 表示繁体中文;

  • 地区:地理区域(例如 US 代表美国,GB 代表英国,DE 代表德国)。这对同一种语言的变体很重要,比如 en-US(美式英语)和 en-GB(英式英语)在日期、时间和数字格式上都有差异;

  • 偏好 / 变体:更具体的文化或语言偏好。更多信息可参考 W3C 的《选择语言标签》。

通常,我们会根据网页的语言选择区域设置,这可以通过 lang 属性获取:

// 从HTML的lang属性获取页面语言
const pageLocale = document.documentElement.lang || 'en-US'; // 默认 fallback 为 'en-US'

偶尔,我们可能需要覆盖页面的区域设置,比如在展示多语言内容时:

// 强制使用特定区域设置,忽略页面语言
const tutorialFormatter = new Intl.NumberFormat('zh-CN', { style: 'currency', currency: 'CNY' });

console.log(`中文示例:${tutorialFormatter.format(199.99)}`); // 输出:¥199.99

有些场景下,还可能需要使用用户的首选语言:

// 使用用户的首选语言
const browserLocale = navigator.language || 'ja-JP';

const formatter = new Intl.NumberFormat(browserLocale, { style: 'currency', currency: 'JPY' });

实例化 Intl 格式化器时,可以传入一个或多个区域设置字符串。API 会根据可用性和优先级选择最合适的区域设置。

核心格式化工具

Intl 对象提供了多个构造函数,每个都对应特定的格式化任务。下面我们来看看最常用的几个,包括一些常被忽略但很强大的功能。

1. Intl.DateTimeFormat:全球化的日期和时间

日期时间格式化是国际化的经典难题。应该用 MM/DD/YYYY 还是 DD.MM.YYYY?月份该用数字还是完整单词?Intl.DateTimeFormat 能轻松搞定这些。

const date = new Date(2025, 6, 27, 14, 30, 0); // 2025年6月27日 14:30:00

// 特定区域设置和选项(例如:长日期、短时间)
const options = {
  weekday: 'long',
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  hour: 'numeric',
  minute: 'numeric',
  timeZoneName: 'shortOffset' // 例如 "GMT+8"
};

console.log(new Intl.DateTimeFormat('en-US', options).format(date));
// "Friday, June 27, 2025 at 2:30 PM GMT+8"

console.log(new Intl.DateTimeFormat('de-DE', options).format(date));
// "Freitag, 27. Juni 2025 um 14:30 GMT+8"

// 使用 dateStyle 和 timeStyle 定义常见格式
console.log(new Intl.DateTimeFormat('en-GB', { dateStyle: 'full', timeStyle: 'short' }).format(date));
// "Friday 27 June 2025 at 14:30"

console.log(new Intl.DateTimeFormat('ja-JP', { dateStyle: 'long', timeStyle: 'short' }).format(date));
// "2025年6月27日 14:30"

DateTimeFormatoptions 非常灵活,可以控制年份、月份、日期、星期、小时、分钟、秒、时区等多个维度。

2. Intl.NumberFormat:带文化特色的数字

数字格式化可不只是保留几位小数那么简单:千位分隔符、小数点符号、货币符号、百分号在不同区域设置中差异很大。

const price = 123456.789;

// 货币格式化
console.log(new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(price));
// "$123,456.79"(自动四舍五入)

console.log(new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(price));
// "123.456,79 €"

// 单位格式化
console.log(new Intl.NumberFormat('en-US', { style: 'unit', unit: 'meter', unitDisplay: 'long' }).format(100));
// "100 meters"

console.log(new Intl.NumberFormat('fr-FR', { style: 'unit', unit: 'kilogram', unitDisplay: 'short' }).format(5.5));
// "5,5 kg"

通过 minimumFractionDigitsmaximumFractionDigitsnotation(例如 scientific 科学计数法、compact 紧凑格式)等选项,还能实现更精细的控制。

3. Intl.ListFormat:自然语言列表

列表展示看似简单,实则暗藏玄机。英语中用 “and” 连接并列项,用 “or” 表示选择,但很多语言的连接词和标点规则都不一样。

这个 API 能省去复杂的条件判断逻辑:

const items = ['apples', 'oranges', 'bananas'];

// 并列关系("and")列表
console.log(new Intl.ListFormat('en-US', { type: 'conjunction' }).format(items));
// "apples, oranges, and bananas"

console.log(new Intl.ListFormat('de-DE', { type: 'conjunction' }).format(items));
// "Äpfel, Orangen und Bananen"

// 选择关系("or")列表
console.log(new Intl.ListFormat('en-US', { type: 'disjunction' }).format(items));
// "apples, oranges, or bananas"

console.log(new Intl.ListFormat('fr-FR', { type: 'disjunction' }).format(items));
// "apples, oranges ou bananas"

4. Intl.RelativeTimeFormat:人性化时间戳

UI 中经常需要显示 “2 天前” 或 “3 个月后”,但要准确本地化这些表达,需要大量语言数据。Intl.RelativeTimeFormat 能自动处理这一点。

const rtf = new Intl.RelativeTimeFormat('en-US', { numeric: 'auto' });

console.log(rtf.format(-1, 'day'));    // "yesterday"(昨天)
console.log(rtf.format(1, 'day'));     // "tomorrow"(明天)
console.log(rtf.format(-7, 'day'));    // "7 days ago"(7天前)
console.log(rtf.format(3, 'month'));   // "in 3 months"(3个月后)
console.log(rtf.format(-2, 'year'));   // "2 years ago"(2年前)

// 法语示例:
const frRtf = new Intl.RelativeTimeFormat('fr-FR', { numeric: 'auto', style: 'long' });

console.log(frRtf.format(-1, 'day'));    // "hier"(昨天)
console.log(frRtf.format(1, 'day'));     // "demain"(明天)
console.log(frRtf.format(-7, 'day'));    // "il y a 7 jours"(7天前)
console.log(frRtf.format(3, 'month'));   // "dans 3 mois"(3个月后)

如果设置 numeric: 'always',会强制显示数字,比如 “1 day ago”(1 天前)而不是 “yesterday”(昨天)。

5. Intl.PluralRules:搞定复数形式

复数规则可能是国际化中最关键的部分之一。不同语言的复数规则差异极大:英语只有单数和复数,阿拉伯语则有零、一、二、多等多种形式。Intl.PluralRules 能帮你确定特定区域设置中某个数字对应的 “复数类别”。

const prEn = new Intl.PluralRules('en-US');

console.log(prEn.select(0));    // "other"(对应“0个物品”)
console.log(prEn.select(1));    // "one"(对应“1个物品”)
console.log(prEn.select(2));    // "other"(对应“2个物品”)

const prAr = new Intl.PluralRules('ar-EG');

console.log(prAr.select(0));    // "zero"
console.log(prAr.select(1));    // "one"
console.log(prAr.select(2));    // "two"
console.log(prAr.select(10));   // "few"
console.log(prAr.select(100));  // "other"

这个 API 不会直接处理文本的复数形式,但能提供关键的分类信息,帮你从消息池中选出正确的翻译文本。比如,如果你的消息键是 item.oneitem.other,就可以用 pr.select(count) 来匹配对应的键。

6. Intl.DisplayNames:所有名称的本地化展示

需要用用户的首选语言显示语言、地区或文字系统的名称?Intl.DisplayNames 能全面解决这个问题。

// 用英语显示语言名称
const langNamesEn = new Intl.DisplayNames(['en'], { type: 'language' });

console.log(langNamesEn.of('fr'));      // "French"(法语)
console.log(langNamesEn.of('es-MX'));   // "Mexican Spanish"(墨西哥西班牙语)

// 用法语显示语言名称
const langNamesFr = new Intl.DisplayNames(['fr'], { type: 'language' });

console.log(langNamesFr.of('en'));      // "anglais"(英语)
console.log(langNamesFr.of('zh-Hans')); // "chinois (simplifié)"(中文(简体))

// 显示地区名称
const regionNamesEn = new Intl.DisplayNames(['en'], { type: 'region' });

console.log(regionNamesEn.of('US'));    // "United States"(美国)
console.log(regionNamesEn.of('DE'));    // "Germany"(德国)

// 显示文字系统名称
const scriptNamesEn = new Intl.DisplayNames(['en'], { type: 'script' });

console.log(scriptNamesEn.of('Latn'));  // "Latin"(拉丁字母)
console.log(scriptNamesEn.of('Arab'));  // "Arabic"(阿拉伯字母)

有了 Intl.DisplayNames,就不用硬编码大量语言、地区或文字系统的名称映射了,能让应用更稳健、更精简。

浏览器支持

你可能会关心浏览器兼容性。好消息是,Intl 在现代浏览器中支持良好。所有主流浏览器(Chrome、Firefox、Safari、Edge)都完全支持上面提到的核心功能(DateTimeFormatNumberFormatListFormatRelativeTimeFormatPluralRulesDisplayNames)。对于大多数用户,你可以放心使用这些 API,无需额外的 polyfill。

结语:用 Intl 拥抱全球网络

Intl API 是面向全球用户的现代 Web 开发的基石。它让前端开发者能轻松实现高度本地化的用户体验,充分利用浏览器内置的优化能力。

采用 Intl 后,你能减少依赖、缩小包体积、提升性能,同时确保应用尊重全球用户的语言和文化习惯。别再纠结于自定义格式化逻辑了,赶紧用起来这个符合标准的工具吧!

不过要注意,Intl 主要处理数据格式化。虽然功能强大,但它不能解决国际化的所有问题。内容翻译、双向文本(RTL/LTR)、特定区域的排版,以及数据格式化之外的深层文化差异,都还需要额外考虑(说不定我以后会写相关内容!)。但在准确、直观地展示动态数据方面,Intl 绝对是浏览器原生的最佳方案。

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
DataSail CDC 数据整库实时入仓入湖实践
在线数据库数据导入到数仓分析的链路已经存在多年,随着近年来实时计算的发展,业务希望有延迟更低、运维更便捷、效率更高的CDC同步通道。本次分享主要介绍DataSail实现CDC整库实时同步的技术方案和业务实践。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论