前端国际化 (i18n) 最佳实践:从零搭建多语言应用

By | 2026年6月30日

前端国际化 (i18n) 最佳实践:从零搭建多语言应用

为什么需要国际化?

随着产品走向全球,支持多语言已成为前端开发的标配需求。但很多团队在初期只考虑单一语言,后期再添加国际化时往往面临代码重构、翻译管理混乱、性能下降等问题。本文将从选型、架构、实现到自动化,分享一套经过实践检验的国际化方案。

方案选型

目前主流的前端国际化库有:

  • i18next:功能强大,生态丰富,支持 React/Vue/Angular 等框架,插件化程度高。
  • react-intl (FormatJS):React 官方推荐,基于组件化 API,但仅限 React。
  • vue-i18n:Vue 生态首选,与 Vue 深度集成。

我的选择:i18next。原因:

  1. 框架无关,可复用同一套配置到不同项目。
  2. 支持嵌套翻译、复数、上下文、ICU MessageFormat 等高级功能。
  3. 强大的插件系统,如自动检测语言、缓存、后端加载等。

项目初始化

以 React + TypeScript 为例,搭建一个多语言应用。

1. 安装依赖


npm install i18next react-i18next i18next-browser-languagedetector i18next-http-backend

2. 配置 i18n

创建 i18n.ts


import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import Backend from 'i18next-http-backend';

i18n
  .use(Backend) // 加载翻译文件
  .use(LanguageDetector) // 自动检测用户语言
  .use(initReactI18next) // 绑定 React
  .init({
    fallbackLng: 'en', // 默认语言
    debug: process.env.NODE_ENV === 'development',
    interpolation: {
      escapeValue: false, // React 已经安全
    },
    backend: {
      loadPath: '/locales/{{lng}}/{{ns}}.json', // 翻译文件路径
    },
    detection: {
      order: ['querystring', 'cookie', 'localStorage', 'navigator', 'htmlTag'],
      caches: ['localStorage', 'cookie'],
    },
  });

export default i18n;

3. 翻译文件结构


public/
  locales/
    en/
      common.json
      home.json
    zh/
      common.json
      home.json

en/common.json 示例:


{
  "app": {
    "title": "My App",
    "description": "Welcome to my app"
  },
  "button": {
    "submit": "Submit",
    "cancel": "Cancel"
  }
}

在 React 中使用

1. 使用 useTranslation Hook


import { useTranslation } from 'react-i18next';

function HomePage() {
  const { t, i18n } = useTranslation('home');

  const changeLanguage = (lng: string) => {
    i18n.changeLanguage(lng);
  };

  return (
    <div>
      <h1>{t('welcome')}</h1>
      <p>{t('intro', { name: 'John' })}</p>
      <button onClick={() => changeLanguage('zh')}>中文</button>
      <button onClick={() => changeLanguage('en')}>English</button>
    </div>
  );
}

home.json


{
  "welcome": "Welcome to the Home Page",
  "intro": "Hello, {{name}}!"
}

2. 使用 Trans 组件处理富文本


import { Trans } from 'react-i18next';

function MyComponent() {
  return (
    <Trans i18nKey="description">
      Read <a href="/docs">the docs</a> for more info.
    </Trans>
  );
}

翻译文件:


{
  "description": "Read <1>the docs</1> for more info."
}

<1> 对应组件中第一个子元素

高级实践

1. 命名空间管理

将翻译文件按模块拆分(如 common, home, about),避免单个文件过大。在 useTranslation 中指定命名空间:


const { t } = useTranslation(['common', 'home']);
// 跨命名空间访问:t('common:button.submit')

2. 动态加载翻译

使用 i18next-http-backend 按需加载,减少初始包体积。配置 loadPath 为动态路径,并在切换语言时自动加载。

3. 类型安全

为翻译键生成 TypeScript 类型,避免拼写错误。使用 i18next-typescript 或自定义脚本:


// i18n.d.ts
declare module 'i18next' {
  interface CustomTypeOptions {
    defaultNS: 'common';
    resources: {
      common: typeof import('../public/locales/en/common.json');
      home: typeof import('../public/locales/en/home.json');
    };
  }
}

4. SEO 优化

对于 SSR 框架(如 Next.js),需要根据语言设置 属性和正确 URL。示例:


// Next.js _app.tsx
import { appWithTranslation } from 'next-i18next';

function MyApp({ Component, pageProps }) {
  return (
    <>
      <Head>
        <html lang={i18n.language} />
      </Head>
      <Component {...pageProps} />
    </>
  );
}

export default appWithTranslation(MyApp);

自动化工作流

1. 提取翻译键

使用 i18next-scannerbabel-plugin-i18next-extract 自动扫描代码中的 t() 调用,生成翻译模板。

安装:


npm install --save-dev i18next-scanner

配置文件 i18next-scanner.config.js


module.exports = {
  input: ['src/**/*.{js,jsx,ts,tsx}', '!src/**/*.spec.*'],
  output: './public/locales',
  options: {
    debug: true,
    func: {
      list: ['t'],
      extensions: ['.js', '.jsx', '.ts', '.tsx'],
    },
    lngs: ['en', 'zh'],
    ns: ['common', 'home'],
    defaultLng: 'en',
    defaultNs: 'common',
    resource: {
      loadPath: '{{lng}}/{{ns}}.json',
      savePath: '{{lng}}/{{ns}}.json',
      jsonIndent: 2,
    },
  },
};

运行:


npx i18next-scanner

2. 翻译管理平台

对接 Lokalise、POEditor 等平台,通过 API 同步翻译文件。示例使用 Lokalise CLI:


lokalise2 file upload --token <token> --project-id <id> --file ./public/locales/en/common.json --lang-iso en

常见坑与解决方案

❌ 问题1:翻译键重复

解决方案:命名空间 + 层级命名,如 home.welcome,避免全局扁平化。

❌ 问题2:动态内容不更新

解决方案:确保组件在语言切换后重新渲染。使用 useTranslationt 函数是响应式的。

❌ 问题3:日期/数字格式化

解决方案:使用 Intl 对象或 i18nextformat 函数。


i18n.services.formatter.add('date', (value, lng) => {
  return new Intl.DateTimeFormat(lng).format(value);
});
// 使用:t('dateKey', { date: new Date(), formatParams: { date: { format: 'date' } } })

❌ 问题4:性能问题

解决方案

  • 按需加载翻译文件
  • 避免在大型列表中使用 Trans 组件
  • 使用 t 函数替代 Trans 尽量静态化

总结

本文从零搭建了一套完整的前端国际化方案,涵盖:

  • 选型 i18next 作为核心库
  • 配置自动检测语言和动态加载
  • 在 React 中使用 hook 和组件
  • 类型安全、SEO 优化等高级实践
  • 自动化提取翻译键和管理平台集成

下一步建议

  • 探索 i18next 的 ICU MessageFormat 支持复数、性别等
  • 结合 CI/CD 自动化翻译同步
  • 考虑使用 i18next-resources-for-backend 实现服务端渲染

希望这篇教程能帮助你构建健壮的多语言应用。如有问题,欢迎留言讨论!