Next.js 项目中 i18n 多语言实现详解

date
Jul 13, 2025
AI 摘要
slug
nextjs-i18n-implementation-guide
status
Published
tags
front-end
summary
在现代 Web 开发中,国际化(i18n)已成为构建全球化应用不可或缺的一部分。 Next.js 相关架构下,一般可以基于 next-intl 的国际化实现方式,本文将从代码结构、配置方式到实际使用场景,全面介绍 i18n的使用,包括语言配置、翻译消息加载、路由支持、组件使用等核心知识点。
type
Post
在现代 Web 开发中,国际化(i18n)已成为构建全球化应用不可或缺的一部分。
Next.js 相关架构下,一般可以基于 next-intl 的国际化实现方式,本文将从代码结构、配置方式到实际使用场景,全面介绍 i18n的使用,包括语言配置、翻译消息加载、路由支持、组件使用等核心知识点。

一、i18n 实现基础

1.1 使用 next-intl 库实现国际化

next-intl 库来实现国际化功能。该库为 Next.js 提供了完整的国际化解决方案,包括翻译、日期格式化、数字格式化等功能。

1.2 安装与依赖管理

项目使用 pnpm 作为包管理器,安装 next-intl 及其相关依赖非常简单:

1.3 语言配置文件

语言配置主要定义在 /src/config/website.tsx 文件中,包含默认语言和所有支持的语言列表:
此配置不仅用于控制应用的默认语言,还被多个组件引用,如语言切换器、页面标题生成等。

二、翻译消息文件

2.1 翻译消息文件结构

翻译消息存储在 /messages/<locale>.json 文件中,按模块划分,例如 "Common"、"PricingPage" 等:

2.2 在客户端组件中使用翻译

在客户端组件中,使用 useTranslations 钩子获取翻译内容:

2.3 在服务端组件中使用翻译

在服务器端组件中,使用 getTranslations 获取翻译内容:

三、路由国际化配置

3.1 动态路由 [locale] 支持

Next.js 的 App Router 支持通过动态路由 [locale] 来处理不同语言版本的页面请求。路由配置文件位于 /src/i18n/routing.ts,定义了支持的语言列表和默认语言:

3.2 自动检测语言与 Cookie 记忆

设置 localeDetection: false 禁用浏览器自动检测语言的功能。用户语言偏好通过 cookie (NEXT_LOCALE) 记忆。

四、语言切换组件与导航链接

4.1 语言切换组件

可以实现多个语言切换组件,如 LocaleSwitcherLocaleSelector,允许用户手动切换语言:

4.2 带翻译的导航链接

使用自定义的 LocaleLink 组件生成带语言前缀的链接:

五、TypeScript 类型定义与类型安全

为了确保类型安全并提供更好的开发体验,项目中使用全局类型定义文件 global.d.ts 扩展 AppConfig 接口,提供 LocaleMessages 类型定义:
该类型定义文件通常位于项目根目录,并需在 tsconfig.json 中显式包含以确保被识别。
此外,还可以通过 fumadocs-ui 提供的 i18n 工具自动生成 Translations 类型定义,确保类型安全和自动补全支持。

六、新增语言的正确做法

当你需要扩展新的语言或新增翻译字段时,应遵循以下步骤:
  1. 添加新语言 JSON 文件/messages/ 目录,如 es.json
  1. website.tsx 中添加该语言配置,提供国旗、名称等元信息。
  1. routing.ts 中添加语言支持,同步更新语言列表。
  1. 页面中使用 useTranslations('Namespace.key') 即可生效。
这样可以保证国际化系统的一致性和可维护性。

七、国际化布局与上下文注入机制

7.1 LocaleLayout 组件的作用

在 Next.js 的 App Router 中,[locale] 路由下的 LocaleLayout 是整个国际化的根布局组件。它的主要职责包括:
  • 加载当前语言的翻译消息文件(如 /messages/en.json/messages/zh.json
  • 注入国际化上下文,通过 NextIntlClientProvider
  • 设置 HTML 标签的语言属性,确保 SEO 和无障碍支持
  • 包裹页面内容,使所有子组件都能基于正确的语言环境渲染
示例代码片段:
⚠️ 注意:虽然目前项目中未显式导入消息文件,但 NextIntlClientProvider 默认会从 /messages/<locale>.json 自动加载翻译消息。

7.2 NextIntlClientProvider 的作用

NextIntlClientProvidernext-intl 提供的核心组件之一,它通过 React Context 将翻译数据传递给所有客户端组件。
主要功能:
功能
描述
翻译注入
messages 注入 React 上下文,使 useTranslations 可用
客户端支持
所有使用 useTranslations 的组件均可访问翻译键值
本地化格式化
支持日期、时间、数字等本地化格式输出
示例用法:
📌 提示:如果你希望手动控制消息加载方式,可以显式传入 messages 属性给 NextIntlClientProvider。

7.3 整体流程图解

4. 最佳实践建议

  • ✅ 新增语言时只需添加 /messages/<new-locale>.json 文件即可生效
  • ✅ 在 website.tsx 中注册语言元信息
  • ✅ 在 routing.ts 中同步更新语言列表
  • ❗ 不建议修改 LocaleLayout 的结构,除非你有特殊需求
通过以上机制,可以实现了简洁、可维护且高效的国际化系统,适合大型 SaaS 应用的多语言需求。

八、翻译消息加载机制详解

8.1 为什么没有显式导入翻译消息?

/src/app/[locale]/layout.tsx 中,你不会看到类似 import messages from '@/messages/zh.json' 的代码片段,这是因为 next-intl 提供了自动加载翻译消息的能力。
✅ 自动加载机制
NextIntlClientProvider 默认会从 /messages/<locale>.json 路径加载对应语言的消息文件。只要项目结构符合预期(如 /messages/en.json/messages/zh.json 存在),就可以无需手动导入。
示例代码如下:
📌 注意:这里并没有传入 messages 属性,表示使用默认的自动加载方式。
⚠️ 手动加载的适用场景
如果你需要自定义路径、延迟加载或调试,可以显式导入并传入 messages 属性:
但目前项目中不推荐这样做,因为结构和配置已完全符合自动加载的要求。

8.2 翻译消息文件路径约定

  • 消息文件必须存放在 /messages/<locale>.json
  • 示例:
    • /messages/en.json
    • /messages/zh.json
💡 建议:新增语言时只需添加对应的 JSON 文件即可生效,无需修改 layout.tsx。

8.3 加载方式对比

方式
是否需要手动导入
使用场景
✅ 自动加载
标准项目结构、消息文件在 /messages/<locale>.json
🔁 手动加载
自定义消息路径、动态加载、服务器渲染等高级用法

8.4 最佳实践建议

  • ✅ 新增语言时只需添加 /messages/<new-locale>.json 文件即可生效
  • ✅ 在 website.tsx 中注册语言元信息
  • ✅ 在 routing.ts 中同步更新语言列表
  • ❗ 不建议修改 LocaleLayout 的结构,除非你有特殊需求
通过以上机制,MkSaaS 模板实现了简洁、可维护且高效的国际化系统,适合大型 SaaS 应用的多语言需求。

九、语言配置的职责划分:website.tsx 与 routing.ts 的作用解析

在 MkSaaS 模板中,国际化(i18n)的语言配置分别定义在两个文件中:
  • website.tsx:用于提供语言元信息和 UI 显示;
  • routing.ts:用于控制路由系统中的多语言行为。

9.1 website.tsx:UI 层语言配置

路径: /src/config/website.tsx
示例代码:
作用:
  • 定义网站支持的语言列表及默认语言;
  • 提供语言元信息(如国旗、名称),用于 UI 显示;
  • 被多个组件引用,例如语言切换器、页面标题生成等。
📌 这是面向前端 UI 的语言配置,主要用于控制语言选择器、显示标签等。

9.2 routing.ts:框架层语言路由配置

路径: /src/i18n/routing.ts
示例代码:
作用:
  • 配置 App Router 中的国际化路由规则;
  • 控制 URL 是否添加语言前缀(如 /en/about vs /about);
  • 设置语言检测方式(浏览器自动检测 or cookie);
  • 定义多语言 Cookie 名称(如 NEXT_LOCALE)。
📌 这是面向 Next.js 路由系统的语言配置,主要用于控制语言感知的路由行为和请求处理。

9.3 为什么不统一到一个地方?

虽然从表面上看将语言配置合并到一个文件中似乎更简洁,但实际原因如下:
维度
website.tsx
routing.ts
用途
提供语言元信息(UI 层)
控制路由行为(框架层)
使用者
前端组件、翻译钩子
Next.js App Router、中间件
功能
显示语言选项、翻译内容
多语言 URL、Cookie 存储、路由匹配
是否可合并?
❌ 不建议
❌ 不建议
✅ 正确做法:同步更新两处配置
当你新增一种语言(如西班牙语 es)时,应执行以下步骤:
1、 在 website.tsx 添加语言配置
2、 在 routing.ts 更新语言列表
3、 创建对应语言的消息文件
/messages/es.json
✅ 总结
问题
回答
为什么要分开配置?
因为 website.tsx 提供 UI 元信息,routing.ts 控制路由行为,二者职责不同。
能否统一?
不建议,违反单一职责原则且可能导致类型冲突。
新增语言应怎么做?
在 website.tsx 添加语言元信息,在 routing.ts 同步更新,并创建对应 JSON 消息文件。
这样设计确保了国际化系统的灵活性和可维护性,是符合最佳实践的结构.

© CodeXun 2025