在React中忽略i18n的JSON导出设置

应用场合

用create-react-app创建的项目,当使用i18n-next进行多语言化时,手动编写*.json的翻译数据很麻烦。希望能自动找到*.tsx或*.js中需要翻译的部分,并追加至*.json中!

这次介绍的例子是一个只涉及前端部分的非常简单的SPA。
i18n-next是一个很实用的工具,它可以引入locize,也可以用于后端开发,了解一下会很划算。

迷上瘾的点

我先解释一下陷阱点。

最近似乎很流行babel-plugin-i18next-extract插件。然而,必须更改webpack的配置。如果你正在使用create-react-app创建应用程序,可以通过使用命令npm eject来实现更改webpack配置,但这是一个不可逆的操作,也不是一个可行的解决方案。因此,最好不要继续使用babel-plugin-i18next-extract。相反,推荐的是官方文档中提到的i18next-parser。

在提取工具中我们也提到了i18next-parser。

首先,公式文件中提到的是i18next-parser。

npm install -g i18next-parser

设定

参考公式文档,写下i18next-parser的配置。

module.exports = {
    locales: ['en', 'ja', 'cn'],
    output: 'src/locales/$LOCALE/$NAMESPACE.json',
}
    • locale: 欲しい分だけ言語を追記

 

    output: 位置がsrcの中でないと、tsxからimport出来ないので、デフォルト設定を上書き

设置npm的脚本。

"scripts": {
    "i18next-extract": "i18next 'src/**/*.{tsx,ts}'"
}

现在设置完成了,我会将翻译文件输出为JSON格式。

npm run i18next-extract

然后,应该以以下的结构进行输出。

./
┃
┣━ src
┃    ┣━ locales
┃    ┃    ┣━ cn
┃    ┃    ┃    ┗━ translation.json
┃    ┃    ┣━ en
┃    ┃    ┃    ┗━ translation.json
┃    ┃    ┗━ jp
┃    ┃         ┗━ translation.json

代码更改 ̂

以下是一种可能的中文翻译:
从这里开始,我们会在源代码中添加用于翻译的配置。
首先,在顶层的React文件中编写i18n的初始化设置。
同时,将之前输出的translation.json文件进行配置。

import React from 'react';
import ReactDOM from 'react-dom';
import './index.sass';
import reportWebVitals from './reportWebVitals';
import App from "./components/App";
import { createBrowserHistory } from "history"
import { Router } from 'react-router';
import HeaderApp from './components/header';
// i18n
import i18next from 'i18next';
import { initReactI18next } from 'react-i18next';

import jaCommon from './locales/ja/translation.json'
import enCommon from './locales/en/translation.json'
import cnCommon from './locales/cn/translation.json'

i18next.use(initReactI18next).init({
  debug: true,
  resources : {
    ja:{common:jaCommon},
    en:{common:enCommon},
    cn:{common:cnCommon},
  },
  lng: 'ja',
  fallbackLng: 'ja',
  keySeparator: false,
  interpolation: { escapeValue: false },
});

const history = createBrowserHistory({ basename: '/' });
ReactDOM.render(
  <React.StrictMode>
    <Router history={history}>
      <HeaderApp/>
      <App></App>
    </Router>
  </React.StrictMode>,
  document.getElementById('root')
);

reportWebVitals(console.log);

的定义如下。

import React from 'react';
import i18next from 'i18next';
import { useTranslation } from 'react-i18next';
import { useEffect } from 'react'

import ja_Trans from '../locales/ja/maincontent.json'
import en_Trans from '../locales/en/maincontent.json'
import cn_Trans from '../locales/cn/maincontent.json'

export function Translate() {
    const { t } = useTranslation('maincontent');
    useEffect(() => {
        i18next.addResources('ja', 'maincontent', ja_Trans);
        i18next.addResources('en', 'maincontent', en_Trans);
        i18next.addResources('cn', 'maincontent', cn_Trans);
    }, [])
    return (
        <React.StrictMode>
             <p>{t('message')}</p>
        </React.StrictMode>
    );
}
class App extends React.Component {
    render() {
        return <Translate/>;
    }
}

export default App;

只有这样还无法切换语言。接下来,我将详细介绍在之前的index.tsx中写的的细节。

import React from 'react';
import { FunctionComponent } from "react";
import { LanugageSelector } from "./LanguageSelector";
import { useTranslation } from 'react-i18next'
import { useState } from 'react';
import { useEffect } from 'react';

const HeaderApp: FunctionComponent = () => {
    const [t, i18n] = useTranslation();
    const languages = [{ code: "ja", name: "JAPANESE" }, { code: "en", name: "ENGLISH" }, { code: "cn", name: "CHINESE" }];
    const [currentLang, setCurrentLang] = useState("ja");
    // Change language of i18n
    useEffect(() => {
        i18n.changeLanguage(currentLang);
    }, [currentLang, i18n])
    // Handler
    const handleLanguageSelectionChange = (lang: string) => {
        setCurrentLang(lang);
    }
    return (
        <React.StrictMode>
            <header>
                <div>
                    <ul>
                        <LanugageSelector languages={languages} selectedLanguage={currentLang} onLanguageSelectionChange={handleLanguageSelectionChange} />
                    </ul>
                </div>
            </header>
        </React.StrictMode>
    );

}

export default HeaderApp;

的定义如下。

import React, { FunctionComponent } from "react";

export type LanguageSelectorProps = {
    languages: { code: string, name: string }[],
    selectedLanguage: string,
    onLanguageSelectionChange: (lang: string) => void,
}

export const LanugageSelector: FunctionComponent<LanguageSelectorProps> = (props) => {
    const langs = props.languages.map((lang) => {
        return (lang.code === props.selectedLanguage) ? '' : <li><p onClick={() => props.onLanguageSelectionChange(lang.code)}>{lang.name}</p></li>
    });

    return (
        <div className="i18n">
            {langs}
        </div>
    );
}

通过,显示英语、日语和中文。点击它将切换显示。使用三元运算符,消去了当前显示的语言。

再次提取

如果能写到这个地方,那就再次执行之前的命令试试看吧。

npm run i18next-extract
./
┃
┣━ src
┃    ┣━ locales
┃    ┃    ┣━ cn
┃    ┃    ┃    ┣━ maincontent.json
┃    ┃    ┃    ┗━ translation.json
┃    ┃    ┣━ en
┃    ┃    ┃    ┣━ maincontent.json
┃    ┃    ┃    ┗━ translation.json
┃    ┃    ┗━ jp
┃    ┃    ┃    ┣━ maincontent.json
┃    ┃         ┗━ translation.json

只要你能走到这一步,恭喜你!接下来只需要不断地写翻译就可以了。

总结

在npm start的过程中,如何运行npm run i18next-extract呢?

胜利者!

bannerAds