3.8.4 国际化 i18n
一句话破题
国际化是让代码支持多语言的架构,而不是把中文翻译成英文那么简单。
核心价值
国际化 (i18n = internationalization, 首尾字母间18个字母) 是把文本从代码中抽离出来,让产品能够支持任意语言,而无需修改代码。
Next.js + next-intl 方案
bash
npm install next-intl目录结构:
src/
├── app/
│ └── [locale]/
│ ├── layout.tsx
│ └── page.tsx
├── messages/
│ ├── en.json
│ └── zh.json
└── i18n.ts配置文件:
ts
// i18n.ts
import { getRequestConfig } from 'next-intl/server'
export default getRequestConfig(async ({ locale }) => ({
messages: (await import(`./messages/${locale}.json`)).default
}))
// middleware.ts
import createMiddleware from 'next-intl/middleware'
export default createMiddleware({
locales: ['en', 'zh'],
defaultLocale: 'zh'
})
export const config = {
matcher: ['/((?!api|_next|.*\\..*).*)']
}翻译文件
json
// messages/zh.json
{
"common": {
"submit": "提交",
"cancel": "取消",
"loading": "加载中...",
"error": "出错了"
},
"home": {
"title": "欢迎来到我们的网站",
"description": "这是一个示例描述"
},
"auth": {
"login": "登录",
"logout": "退出",
"welcome": "欢迎回来,{name}!"
}
}
// messages/en.json
{
"common": {
"submit": "Submit",
"cancel": "Cancel",
"loading": "Loading...",
"error": "Something went wrong"
},
"home": {
"title": "Welcome to our website",
"description": "This is a sample description"
},
"auth": {
"login": "Login",
"logout": "Logout",
"welcome": "Welcome back, {name}!"
}
}在组件中使用
tsx
// app/[locale]/page.tsx
import { useTranslations } from 'next-intl'
export default function HomePage() {
const t = useTranslations('home')
const tCommon = useTranslations('common')
return (
<div>
<h1>{t('title')}</h1>
<p>{t('description')}</p>
<button>{tCommon('submit')}</button>
</div>
)
}
// 带参数
function WelcomeMessage({ name }: { name: string }) {
const t = useTranslations('auth')
return <p>{t('welcome', { name })}</p>
// 输出: "欢迎回来,张三!" 或 "Welcome back, Zhang San!"
}复数和性别
json
// messages/en.json
{
"cart": {
"items": "{count, plural, =0 {No items} one {# item} other {# items}}",
"total": "Total: {price}"
}
}
// messages/zh.json
{
"cart": {
"items": "{count}件商品",
"total": "总计: {price}"
}
}tsx
function CartSummary({ count, total }: { count: number; total: string }) {
const t = useTranslations('cart')
return (
<div>
<p>{t('items', { count })}</p>
<p>{t('total', { price: total })}</p>
</div>
)
}
// count=0: "No items" / "0件商品"
// count=1: "1 item" / "1件商品"
// count=5: "5 items" / "5件商品"日期和数字格式化
tsx
import { useFormatter } from 'next-intl'
function FormattedContent() {
const format = useFormatter()
const date = new Date()
const price = 1234.56
return (
<div>
{/* 日期格式化 */}
<p>{format.dateTime(date, { dateStyle: 'long' })}</p>
{/* en: "January 15, 2024" / zh: "2024年1月15日" */}
{/* 相对时间 */}
<p>{format.relativeTime(date)}</p>
{/* en: "2 hours ago" / zh: "2小时前" */}
{/* 数字格式化 */}
<p>{format.number(price, { style: 'currency', currency: 'CNY' })}</p>
{/* en: "CN¥1,234.56" / zh: "¥1,234.56" */}
</div>
)
}语言切换
tsx
'use client'
import { useLocale } from 'next-intl'
import { useRouter, usePathname } from 'next/navigation'
function LanguageSwitcher() {
const locale = useLocale()
const router = useRouter()
const pathname = usePathname()
const switchLocale = (newLocale: string) => {
const newPath = pathname.replace(`/${locale}`, `/${newLocale}`)
router.push(newPath)
}
return (
<select
value={locale}
onChange={(e) => switchLocale(e.target.value)}
aria-label="选择语言"
>
<option value="zh">中文</option>
<option value="en">English</option>
</select>
)
}服务端组件中使用
tsx
// app/[locale]/page.tsx
import { getTranslations } from 'next-intl/server'
export async function generateMetadata({ params: { locale } }) {
const t = await getTranslations({ locale, namespace: 'home' })
return {
title: t('title'),
description: t('description'),
}
}
export default async function Page() {
const t = await getTranslations('home')
return <h1>{t('title')}</h1>
}翻译键管理
tsx
// 使用 TypeScript 类型安全
// 创建类型定义
// types/i18n.d.ts
import en from '../messages/en.json'
type Messages = typeof en
declare global {
interface IntlMessages extends Messages {}
}AI 协作指南
核心意图:让 AI 帮你实现国际化架构。
需求定义公式:
- 框架选择:Next.js + [next-intl/react-i18next]
- 支持语言:[中文/英文/日文...]
- 功能需求:[日期格式化/复数/性别]
示例 Prompt:
请帮我设置 Next.js + next-intl 国际化:
1. 支持中文和英文
2. 基于 URL 路径切换语言 (/zh, /en)
3. 包含语言切换组件
4. 配置日期和货币格式化
5. 提供完整的目录结构和配置文件验收清单
- [ ] 文本从代码中抽离
- [ ] 支持语言切换
- [ ] 日期/数字正确格式化
- [ ] SEO 元数据多语言支持
- [ ] 翻译键有 TypeScript 类型
