React 国际化方案

React 国际化方案

. 约 2 分钟读完

最近业务需要,调研了下主流的国际化方案,顺便做个记录。

1、 react-intl,按需加载 intl 作为补丁。react-intl 由 Yahoo 研发。是 Format.js 生态的一部分。

先在 locales 里定义语言,可以用 .ts 也可以用 .json 。

// src/locales/zh-CN.ts
export default {
  welcome: '欢迎光临 Umi 的世界!',
};

然后使用时用 FormattedMessage 渲染。

import { FormattedMessage } from 'react-intl';
<FormattedMessage id="welcome" defaultMessage="Welcome" />

也可以拿到 intl 然后去 formatMessage。不推荐,它脱离了 React 的生命周期,可能导致切换语言时无法触发 DOM 的 re-render 。

import { useIntl } from 'react-intl';
const intl = useIntl();
intl.formatMessage({ id: 'welcome' });

支持动态插值,比如 Hello {name}<FormattedMessage id="welcome" values={{name: 'fooo'}} />

支持切换。

import { setLocale } from 'react-intl';
setLocale('en-US');
// 切换但不刷新
setLocale('en-US', false);
// 切换到默认语言
setLocale();

支持通过配置实现路由 title 的国际化。

2、react-i18next,基于 i18next。周下载 300W+,是 react-intl 的 2-3 倍。

相比 react-intl,react-i18next 的优点是:

1)生态好,大型应用用 react-i18next 更合适
2)国际化文件支持按需加载,性能上会更好
3)SSR 友好
4)TypeScript 支持友好(?)
5)通过 Trans 组件支持复杂的 JSX 内容翻译(句子翻译)

先初始化 i18n 。(注:http backend 通常可以搭配 localstorage-backend 做缓存)

import i18n from 'i18next';
import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
i18n
  // 异步加载国际化数据
  .use(Backend)
  .use(LanguageDetector)
  .use(initReactI18next)
  // options: https://www.i18next.com/overview/configuration-options & https://react.i18next.com/latest/i18next-instance
  .init({});

在 public/locales/zh/translation.json 中定义。

{
  "welcome": "欢迎来到 TNF !",
  "getting-started": "编辑 <1>src/App.zh-CN.js</1> 快速开始。"
}

然后通过 useTranslation 使用(class 可以用 withTranslation hoc)。

import { useTranslation } from 'react-i18next';
const { t, i18n } = useTranslation();
t('welcome')

也可以用 Trans 组件翻译整段 jsx。

import { Trans } from 'react-i18next';
<Trans i18nKey="getting-started">
  To get started, edit <code>src/App.js</code> and save to reload.
</Trans>

加 TypeScript 类型。

import "i18next";
import translation from "locales/en/translation.json";
declare module "i18next" {
  interface CustomTypeOptions {
    resources: {
      translation: typeof translation;
    }
  }
}
本篇已被阅读