文档
开发指南国际化

国际化

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))
}

📎 延伸阅读

官方文档:

最佳实践:

工具推荐:


下一步: 国际化配置完成后,查看 [邮件系统]./mailing) 了解如何发送多语言邮件。