设计原则
本页深入介绍了 next-intl 所基于的设计原则。
虽然使用本页内容并非在项目中高效使用该库的必读内容,但它能帮助你更好地理解库背后的理念,并助于你评估 next-intl 是否适合你的项目。
本页同时链接了一些计划中的改进,旨在作为未来期待的透明参考。
全面性
国际化显然需要你的代码库具备灵活性。然而,即使是实现单一语言的完整支持,也已经是一个挑战。
使用动态文本标签是国际化中最明显的方面,但良好支持一门语言还包括许多其他方面:
- 复数规则:比如英语只有两种复数形式(单数和复数),而其他语言最多可有六种不同的形式。
- 日期和时间格式:不同语言对日期和时间的格式有不同习惯。甚至年份的显示也会因国家而异,例如泰国采用的佛历比公历提前543年。
- 数字格式:数字的格式化规则在语言之间不同。例如,英语和德语中千位分隔符和小数点符号是互换的。
- 列表格式:像“HTML、CSS 和 JavaScript”这样的列表格式,不仅仅是字符串的简单拼接,还需要使用语言特定的连接词和标点符号。
- 文本方向:大多数语言是从左到右书写,但阿拉伯语等语言是从右到左书写,需要镜像布局。
此外,还有典型的应用问题,例如:
- 富文本格式:许多应用需要支持某种富文本格式,例如在文本标签中嵌入链接(“在富文本文档中了解更多。”)。
- 时区:日期展示需要服务器端和客户端对时区的统一处理,甚至可能基于用户偏好进行定制。
- 相对时间格式:展示“5分钟前”或“2小时后”等相对时间需要特别注意格式,还需要一个统一的当前时间参考值。还可能需要定时更新显示的时间。
- 本地化 URL:URL 应该本地化以匹配用户的语言偏好(如英语用
/en/about-us,西班牙语用/es/sobre-nosotros)。实现上需要将请求映射到正确页面,并提供简化的 API 让开发者能以与语言无关的方式链接页面。 - 语言协商:应基于浏览器设置检测用户语言偏好,同时支持手动配置——即使用户未登录。
- SEO:搜索引擎需要了解页面的本地化版本,以便向用户呈现最佳匹配内容。
- 国家特性:如果你在多个国家提供服务或产品,可能需要考虑不同的货币和计量单位。
- 环境差异:你的组件可能在服务器端、客户端或两者执行。为了实现一致渲染,需要确保整个应用统一访问诸如用户区域设置、时区以及当前时间参考等属性。
考虑上述内容,你可能已经能体会到国际化问题的庞大和不同部分之间的紧密联系。
next-intl 采取全面的国际化方法,推动你遵循处理语言和国家特定习俗的最佳实践,从而让你更专注于打造应用的核心独特之处。
→ 计划中的改进
易用性
本库大胆宣称,当你实现国际化时,应用代码反而会变得更简单而非复杂。
如果你考虑国际化的全局视角,显而易见大部分组件都会以某种方式涉及国际化。鉴于此,next-intl优先提供便利的 API,确保你在开发时高效且可控。作为开发者,你应只需专注于解决实际问题,国际化则作为副产品无缝集成其中。
一旦完成国际化设置,添加新语言在最简单的情况下,仅需添加包含翻译的 JSON 文件——其他由 next-intl 自动处理。
→ 计划中的改进
基于标准
随着ECMAScript 国际化 API 的引入,近年来 JavaScript 在日期、时间、数字、列表和复数格式化方面变得非常强大。next-intl 构建于此 API 之上,提供符合开发习惯的接口,同时结合应用的具体配置需求。
在文本格式化方面,next-intl 基于Unicode 国际组件(ICU)——ICU 是一个成熟且广泛使用的国际化标准,得到许多编程语言和框架支持。next-intl 使用 ICU 消息语法定义文本标签,能简明且易读地表达复杂格式需求,比如变量插值和复数规则,且对译者等非开发者友好。
基于标准,next-intl 确保你的国际化代码具备未来兼容性,并令已有国际化经验的开发者感到熟悉。此外,依赖标准也保证了 next-intl 可很好地与诸如 Crowdin 等翻译管理系统集成。
next-intl 使用嵌套式结构来组织消息,允许以无冗余的方式表达消息层级。通过仅支持单一结构,我们能提供基于此假设的高级功能,如消息的类型安全。若你使用不同结构风格,可考虑迁移到嵌套式结构(详见消息结构文档中的“我可以用其他结构风格吗?”部分)。
随着标准的变化,next-intl 也会跟进 ECMAScript 标准的最新发展(例如 Temporal 和 Intl.MessageFormat)。
→ 计划中的改进
兼容性
虽然 next-intl 设计为以全面方式处理国际化,但国际化往往需要与其他工具和服务集成,允许你采用最合适的工具并与非开发者协作。
典型应用可能需要以下集成:
翻译管理系统(TMS)
通常用于管理翻译和与译者协作。如 Crowdin 提供丰富功能,支持译者在基于网页的界面处理翻译,并以多种机制同步翻译与应用。
next-intl 与此类服务集成良好,因它使用广泛支持的 ICU 消息语法定义文本标签。推荐将消息存储为按语言划分的 JSON 文件,这是一种流行格式,便于导入进 TMS。虽然推荐至少将默认语言的消息本地保存(例如支持类型安全消息),但你也可以动态加载消息,比如从 TMS 提供的 CDN。
内容管理系统(CMS)
若你的应用使用 CMS 内容,可与 next-intl 配合使用。例如,你可能希望在 CMS 管理博客文章或营销文案,同时用 next-intl 管理 UI 标签。
CMS 通常支持多语言内容定义,通过 REST API 获取内容。利用 next-intl 返回的协商后的应用语言(通过 getLocale),并将其传入 CMS API 请求,可获取用户偏好语言的内容。
后端数据
类似 CMS,你可能有后端服务或数据库中的数据需基于用户语言和国家查询。例如,根据国家显示不同价格和货币,或展示本地化的产品名称。通过使用 next-intl 协商的应用语言发起后端请求,可以确保本地化贯穿应用各处。
其他库
Next.js 拥有丰富的生态库,可与 next-intl 配合使用,比如处理认证。通过提供常见集成的文档和示例,next-intl 确保你在与其他库集成时体验顺畅无阻。
→ 计划中的改进
性能优化
next-intl 从设计之初就面向高流量网站,旨在提供快速且可靠的用户体验,并在复杂电商页面中已证明其卓越的核心网络性能指标(Core Web Vitals)。
为实现此目标,next-intl 当前主要依赖以下技术:
- RSC 优先:深度整合 React 服务端组件,将工作转移至构建步骤或高性能服务器,从而减少客户端运行时负担。
- 消息拆分:按语言划分消息,且可按服务器、客户端及组件拆分,减少传给客户端的消息体积。对支持多语言且消息量大的应用尤为关键。
- 缓存:消息解析以及
Intl构造器实例化均在应用中缓存,降低计算量。 - 捷径:比缓存重复工作结果更好的是避免重复计算(例如,检测不需解析的纯文本消息)。
→ 计划中的改进
专为 Next.js 设计
Next.js 提供了许多功能,但同时也带来许多必须谨慎处理的细节,以实现可靠的国际化集成。顾名思义,next-intl 主要设计与 Next.js 深度协同。它不追求一刀切,而是根据需要深度集成 Next.js,持续关注 Next.js 生态的最新发展。
尽管如此,next-intl 核心库为 Next.js 无关,适用于任意 React 应用,甚至纯 JavaScript 环境:use-intl。该核心库包含 next-intl 大多数特性,但缺乏 Next.js 专属的集成如路由 API。其目标是在生态其他部分(如 React Native)复用熟悉 API,且若将来你觉得 Next.js 不再适合项目,也提供简明的迁移路径。
便于迁移
我们都经历过技术演进,有时也需要跟进变化。next-intl 设计为你的代码库友好公民,方便在必要时迁移替换某些堆栈部分。
若你觉得 Next.js 或 next-intl 不再适合你的项目,你有以下多个选项:
- 放弃 Next.js:若决定迁移离开 Next.js,可继续在任何 React 应用中使用核心库
use-intl,例如让你能复用已有组件于 React Router 应用中。 - 放弃
next-intl:若觉得next-intl不符合需求,需修改引用库的应用代码,但仍能复用你的基于标准的 ICU 消息,并可用直接调用ECMAScript 国际化 API 替代格式化 API。
我们不会阻止你,但乐意继续做朋友。
当然,我们会尽全力让 next-intl 成为你项目的好帮手。如果你觉得哪里不尽如人意或有改进建议,请随时在问题追踪区反馈,我们将尽力帮你解决。
哇,这篇文章真长。你真的全读完了吗?next-intl 诞生于对国际化的浓厚兴趣与热情,看来我们志同道合!我们总想知道 next-intl 给你的体验如何,如有反馈或疑问,欢迎随时联系我们!