一个用于 antd 的 i18n 方案

基于 i18next 实现,实现的一套基于 antd
更新于: 2023-11-27 10:05:08
项目主页: https://github.com/afeiship/react-ant-i18n

快用

一条命令就可以在项目中使用此功能。

npx @jswork/ant-i18n-init

安装

npm i -S @jswork/react-ant-i18n

使用

  • 添加 locales 目录
  • 针对项目初始化
    • backend 方式: 各种 json 会以 ajax/fetch 方式加载 
    • memory 方式:  直接添加 resources 文件
  • 使用 t 来完成取值

cra/public 目录下,添加 locals 目录,如果需要修改:可以参考配置里的 backend 相关。

en-US.json 示例

{
  "key": "hello world",
  "open-a-modal": "Open a Modal",
  "desc": "Edit <code>src/App.tsx</code> and save to reload.",
  "mtxt": "From a modal"
}

实现一个 language-detector LngDetect.tsx

ps: 这一步,不是必须的。

import Cookies from 'js-cookie';

export default class {
  public static readonly type = 'languageDetector';

  init() {
  }

  detect() {
    return Cookies.get('lang') || localStorage.getItem('i18next.lang');
  }

  cacheUserLanguage(lng: string) {
    localStorage.setItem('i18next.lang', lng);
  }
}

初始化 index.tsx

backend 方式: 这一步,实际是初始化一个 i18next 的实例,一般项目都是使用的单例,所以,这一步很多时候也可以用项目已经存在的初始化逻辑。

import React, { Suspense } from 'react';
import ReactDOM from 'react-dom';
import { LocaleProvider } from "@jswork/react-ant-i18n";
import LngDetect from './lng-detect';
import App from './app';

ReactDOM.render(
  <Suspense fallback={<div>Loading...</div>}>
    <LocaleProvider mode="backend" plugins={[LngDetect]}>
      <App />
    </LocaleProvider>
  </Suspense>,
  document.getElementById('root')
);

初始化 index.tsx

memory 方式: 这一步,实际是初始化一个 i18next 的实例,一般项目都是使用的单例,所以,这一步很多时候也可以用项目已经存在的初始化逻辑。

import React, { Suspense } from 'react';
import ReactDOM from 'react-dom';
import { LocaleProvider } from "@jswork/react-ant-i18n";
import LngDetect from './lng-detect';
import App from './app';

const resources = {
  'en-US': { translation: require('../locales/en-US.json') },
  'zh-CN': { translation: require('../locales/zh-CN.json') }
};

ReactDOM.render(
  <Suspense fallback={<div>Loading...</div>}>
    <LocaleProvider mode="memory" options={{ resources }} plugins={[LngDetect]}>
      <App />
    </LocaleProvider>
  </Suspense>,
  document.getElementById('root')
);

使用 useIntl 取得 t

import React from "react";
import { useIntl } from "@jswork/react-ant-i18n";
import { Space} from "antd";
import nx from "@jswork/next";

export default () => {
  const { t, i18n } = useIntl();

  // inject as global for debug
  nx.t = t;
  nx.i18n = i18n;

  return (
    <div className="App">
      <header className="App-header">
        <Space direction="vertical">
          <h1 style={{ color: "#fff" }}>{t("key")}</h1>
          <p
            dangerouslySetInnerHTML={{
              __html: t("desc", { interpolation: { escapeValue: false } }),
            }}
          />
        </Space>
      </header>
    </div>
  );
};

添加 typescript 自动提示

在项目中 t 提示如图
  • 在 src 目录添加 react-i18next.d.ts ,这个位置其实是可以放在你觉得合适的地方
  • tsconfig.json 里确认这个配置:"resolveJsonModule": true
  • 添加内容,如下
  • 参考: https://react.i18next.com/latest/typescript

放在 react-app-env.d.ts 或者加到公用的 global.d.ts里。

文件位置关系如图
import lang from '../public/locales/en-US.json';

export const locale = {translation: lang} as const;

declare module 'react-i18next' {
  interface CustomTypeOptions {
    defaultNS: 'translation';
    resources: typeof locale;
  }
}

declare global {
  interface NxStatic {
    t: (key: keyof typeof locale['translation'], opts?: any) => string;
    i18n: import('i18next').i18n;
  }
}

精典目录

如我现在的应用,上面的代码(react-app-env.d.ts),就可以放在 global.d.ts

.
├── craco.config.js
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── locales
├── src
│   ├── app.tsx
│   ├── glotal.d.ts
│   ├── index.tsx
│   ├── react-app-env.d.ts
│   ├── react-i18next.d.ts
├── tsconfig.json
└── tsconfig.paths.json

说了这么多,有没有简单的接入方法

当然有,一行代码,脚手架一键生成即可!

安装: https://github.com/afeiship/generator-react-app

yo @jswork/react-app:antd-i18n

预览