开发指南国际化
国际化
inbox
- 【 】 建议寻找一个大模型服务,自动翻译 en.json -> zh.json
{
"scripts": {
"i18n:check": "i18n-check --locales src/lib/i18n/translations --source en --format i18next"
}
}
Solution Summary
✅ Analysis Complete: Used the existing analyze-missing-translations.js script to identify all 403 missing translation keys ✅ Translation Generation: Created comprehensive English translations using a combination of manual translations for important UI content and automated translation for common terms✅ Implementation: Applied all 403 translations to en.json using a merge script ✅ Verification: Confirmed 0 missing keys remain
🚀 Cheatsheet (快速执行)
目标: 5分钟内为你的应用添加多语言支持,让全球用户都能使用
最快上手方式:
# 1. 已经配置好了,直接使用
# 支持的语言: 中文(默认)、英文、德语
# 2. 添加新翻译
echo '{"welcome": "欢迎"}' > src/lib/i18n/translations/zh/common.json
echo '{"welcome": "Welcome"}' > src/lib/i18n/translations/en/common.json
# 3. 在组件中使用
import { useTranslations } from 'next-intl'
const t = useTranslations('common')
return <h1>{t('welcome')}</h1>
立即生效: 访问 /en
查看英文版,/zh
查看中文版
使用 i18n Ally 插件
- 在 Vscode / Cursor 中安装插件 i18n Ally
- Open Command Palette (Ctrl-Shift-P or ⌘⇧P), type i18n Ally: Manual configure locales path then press enter and follow the guide.
- Go to the settings of VSCode and set i18n-ally.localesPaths manually.
- 设置路径为: src/lib/i18n/translations
- 接着打开编辑器侧边栏, 找到 i18n Ally 插件的页面(是一个翻译图标),接下来你就可以快速查看当前翻译的进度了
❓ 为什么要做国际化
对 MVP 的直接价值:
- 扩大用户群: 支持多语言,用户量可能翻倍
- 提升转化率: 用户看到母语界面,信任度更高
- SEO 优势: 多语言页面,搜索引擎覆盖更广
- 竞争优势: 很多产品不支持多语言,这是差异化
真实场景举例: 你的 AI 工具支持中英文,中国用户看到中文界面更愿意付费,美国用户看到英文界面转化率提升 40%。
🤔 为什么选择 next-intl
我们的实战经验:
- App Router 原生支持: 专为 Next.js 13+ 设计,无兼容问题
- 类型安全: 翻译键错误在编译时就能发现
- SEO 友好: 自动生成
/en/about
、/zh/about
等路由 - 服务端支持: 服务端渲染也能正确显示翻译
对比其他方案:
react-i18next: 配置复杂,App Router 支持不好
next-i18next: 不支持 App Router
自建方案: 开发时间长,功能不完整
next-intl: ✅ 完美适配,开箱即用
🧠 简要原理 & 最简案例
工作原理: URL 路径 → 语言检测 → 加载翻译文件 → 渲染页面
最简使用示例:
// 1. 翻译文件 (src/lib/i18n/translations/zh/common.json)
{
"welcome": "欢迎使用",
"login": "登录"
}
// 2. 组件中使用
import { useTranslations } from 'next-intl'
export function Header() {
const t = useTranslations('common')
return (
<div>
<h1>{t('welcome')}</h1>
<button>{t('login')}</button>
</div>
)
}
🛠️ 实际操作步骤
1. 添加新语言支持 (3分钟)
创建翻译文件:
# 创建日语翻译目录
mkdir -p src/lib/i18n/translations/ja
# 复制现有翻译作为模板
cp src/lib/i18n/translations/en/common.json src/lib/i18n/translations/ja/common.json
# 编辑日语翻译
# {"welcome": "ようこそ", "login": "ログイン"}
更新语言配置:
// src/lib/i18n/config.ts
export const locales = ['zh', 'en'] as const
export const localeNames = {
'zh': '中文',
en: 'English'
}
2. 翻译现有内容 (10分钟)
找到需要翻译的文本:
# 搜索硬编码的中文文本
grep -r "登录\|注册\|设置" src/app --include="*.tsx"
# 替换为翻译函数
# "登录" → {t('login')}
批量翻译技巧:
// 使用对象解构,一次性获取多个翻译
const t = useTranslations('auth')
const { login, signup, forgot } = {
login: t('login'),
signup: t('signup'),
forgot: t('forgotPassword')
}
return (
<div>
<button>{login}</button>
<button>{signup}</button>
<a>{forgot}</a>
</div>
)
3. 动态内容翻译 (5分钟)
带参数的翻译:
// translations/zh/user.json
{
"welcome": "欢迎回来,{name}!",
"itemCount": "你有 {count} 个项目"
}
// 组件中使用
const t = useTranslations('user')
return (
<div>
<h1>{t('welcome', { name: user.name })}</h1>
<p>{t('itemCount', { count: items.length })}</p>
</div>
)
复数形式处理:
// translations/en/user.json
{
"itemCount": {
"zero": "No items",
"one": "One item",
"other": "{count} items"
}
}
💡 高级使用技巧
语言切换组件
// components/LanguageSwitcher.tsx
'use client'
import { useRouter, usePathname } from 'next/navigation'
import { locales, localeNames } from '@/lib/i18n/config'
export function LanguageSwitcher() {
const router = useRouter()
const pathname = usePathname()
const switchLanguage = (locale: string) => {
// 保持当前路径,只切换语言
const newPath = pathname.replace(/^\/[a-z]{2}/, `/${locale}`)
router.push(newPath)
}
return (
<select onChange={(e) => switchLanguage(e.target.value)}>
{locales.map(locale => (
<option key={locale} value={locale}>
{localeNames[locale]}
</option>
))}
</select>
)
}
服务端翻译
// app/[locale]/page.tsx
import { getTranslations } from 'next-intl/server'
export default async function HomePage() {
const t = await getTranslations('home')
return (
<div>
<h1>{t('title')}</h1>
<p>{t('description')}</p>
</div>
)
}
// 生成页面元数据
export async function generateMetadata({ params: { locale } }) {
const t = await getTranslations({ locale, namespace: 'meta' })
return {
title: t('title'),
description: t('description')
}
}
日期和数字本地化
// 日期格式化
const formatDate = (date: Date, locale: string) => {
return new Intl.DateTimeFormat(locale, {
year: 'numeric',
month: 'long',
day: 'numeric'
}).format(date)
}
// 数字格式化
const formatNumber = (number: number, locale: string) => {
return new Intl.NumberFormat(locale).format(number)
}
// 货币格式化
const formatCurrency = (amount: number, locale: string) => {
const currency = locale === 'zh' ? 'CNY' : 'USD'
return new Intl.NumberFormat(locale, {
style: 'currency',
currency
}).format(amount)
}
🎯 翻译文件组织
按功能模块组织
src/lib/i18n/translations/
├── zh/
│ ├── common.json # 通用翻译 (按钮、标签)
│ ├── auth.json # 认证相关
│ ├── dashboard.json # 仪表板
│ ├── settings.json # 设置页面
│ └── errors.json # 错误信息
├── en/
│ ├── common.json
│ ├── auth.json
│ └── ...
翻译文件示例
// common.json
{
"buttons": {
"save": "保存",
"cancel": "取消",
"delete": "删除",
"edit": "编辑"
},
"status": {
"loading": "加载中...",
"success": "操作成功",
"error": "操作失败"
}
}
// auth.json
{
"login": {
"title": "登录账户",
"email": "邮箱地址",
"password": "密码",
"submit": "立即登录",
"forgotPassword": "忘记密码?"
},
"signup": {
"title": "创建账户",
"confirmPassword": "确认密码",
"submit": "立即注册"
}
}
🔧 SEO 和路由优化
多语言 URL 结构
# 中文 (默认语言,无前缀)
https://yoursite.com/about
https://yoursite.com/pricing
# 英文
https://yoursite.com/en/about
https://yoursite.com/en/pricing
自动语言检测
// middleware.ts
import createMiddleware from 'next-intl/middleware'
export default createMiddleware({
locales: ['zh', 'en'],
defaultLocale: 'zh',
// 自动检测用户语言
localeDetection: true,
// 路径名本地化
pathnames: {
'/about': {
'zh': '/about',
'en': '/about',
},
'/pricing': {
'zh': '/pricing',
'en': '/pricing',
}
}
})
搜索引擎优化
// 生成 hreflang 标签
export function generateHrefLang(pathname: string) {
return locales.map(locale => ({
hrefLang: locale,
href: `https://yoursite.com${locale === 'zh' ? '' : `/${locale}`}${pathname}`
}))
}
🚀 部署和性能优化
翻译文件懒加载
// 只加载当前语言的翻译文件
const loadTranslations = async (locale: string) => {
const translations = await import(`./translations/${locale}/index.js`)
return translations.default
}
翻译缓存策略
// 缓存翻译文件,避免重复加载
const translationCache = new Map()
export function getTranslations(locale: string, namespace: string) {
const key = `${locale}-${namespace}`
if (!translationCache.has(key)) {
const translations = loadTranslationFile(locale, namespace)
translationCache.set(key, translations)
}
return translationCache.get(key)
}
🆘 常见问题解决
问题1: 翻译不显示
// 检查翻译键是否存在
const t = useTranslations('common')
console.log(t.has('welcome')) // true/false
// 提供默认值
const welcome = t('welcome', { fallback: '欢迎' })
问题2: 路由跳转语言丢失
// 使用 Link 组件保持语言
import { Link } from '@/lib/i18n/navigation'
<Link href="/about">{t('about')}</Link>
// 自动生成 /en/about 或 /zh/about
问题3: 服务端客户端不一致
// 确保服务端和客户端使用相同的语言
export default function RootLayout({
children,
params: { locale }
}: {
children: React.ReactNode
params: { locale: string }
}) {
return (
<html lang={locale}>
<body>
<NextIntlClientProvider locale={locale}>
{children}
</NextIntlClientProvider>
</body>
</html>
)
}
📊 翻译管理工具
翻译进度检查
# 检查缺失的翻译
bun run i18n:check
# 输出示例:
# ❌ en/auth.json 缺少: forgotPassword
# ✅ zh/common.json 完整
自动翻译脚本
// scripts/auto-translate.ts
import { translateText } from './translate-api'
async function autoTranslate(sourceLocale: string, targetLocale: string) {
const sourceFile = `./translations/${sourceLocale}/common.json`
const targetFile = `./translations/${targetLocale}/common.json`
const source = JSON.parse(fs.readFileSync(sourceFile, 'utf8'))
const target = {}
for (const [key, value] of Object.entries(source)) {
target[key] = await translateText(value, targetLocale)
}
fs.writeFileSync(targetFile, JSON.stringify(target, null, 2))
}
📎 延伸阅读
官方文档:
- next-intl 文档 - 完整的 API 参考
- Next.js 国际化 - Next.js 官方指南
最佳实践:
工具推荐:
下一步: 国际化配置完成后,查看 [邮件系统]./mailing) 了解如何发送多语言邮件。