快速实现 react 多语言改造

2021/5/19 2:56:43webframework

1,安装依赖

yarn add i18next react-i18next i18next-browser-languagedetector

2,创建i18n.jsx

image.png

import i18n from 'i18next';
import {initReactI18next} from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import translationEN from './locales/en/translation.json';
import translationZH from './locales/zh/translation.json';
const resources = {
    en: {
        translation: translationEN
    },
    zh: {
        translation: translationZH
    },
};

i18n
    // detect user language
    // learn more: https://github.com/i18next/i18next-browser-languageDetector
    .use(LanguageDetector)
    // pass the i18n instance to react-i18next.
    .use(initReactI18next)
    // init i18next
    // for all options read: https://www.i18next.com/overview/configuration-options
    .init({
        lng:'zh', // default
        whitelist: ['en', 'zh'],
        fallbackLng: 'en',
        debug: true,

        resources,

        interpolation: {
            escapeValue: false, // not needed for react as it escapes by default
        },

        detection: {
            order: ['path'],
            // checkWhitelist: true,
        }
    }, () => {

    });

function setLang() {
    let urlLanguage = 'zh';
  	// 如果在地址栏中带有语言选项:http://localhost:3000/en/home
  	// 也可以使用其他方案:http://localhost:3000/home?lang=en
  	// 或者放到缓存中读取。localStorage.getItem('lang')
    if (window.location.pathname.indexOf('/en') !== -1) {
        urlLanguage = 'en';
    }
    if (urlLanguage !== i18n.language) {
        i18n.changeLanguage(urlLanguage);
    }
}

setLang()
window.onpopstate = setLang

export default i18n;

3,创建translation.json

{
	"home": {
  	"login": "登录"
  }
}

实际开中,需要配置多个json文件,很难保证相互之间的一致性。
所以写了一个小工具,只需要维护一份json,然后自动生成对应的语言包。
image.png

createLanguage.js

let fs = require('fs')
let lang = fs.readFileSync(`${__dirname}/lang.json`, {encoding: 'utf8'})

let locales = {
    en: {},
    zh: {},
}

for (let i in locales) {
    let newLang = splitLang(JSON.parse(lang), i)
    fs.writeFileSync(`${__dirname}/${i}/translation.json`, JSON.stringify(newLang, null, 4), {encoding: 'utf8'})
}

function splitLang(langObj, local) {
    for (let i in langObj) {
        if (langObj && langObj.hasOwnProperty(i)) {
            if (langObj[i].en) {
                langObj[i] = langObj[i][local] || langObj[i].en
            } else {
                let item = langObj[i]
                if (item && typeof item === 'object') {
                    splitLang(item, local)
                }
            }
        }
    }
    return langObj
}

console.log('\n\nlanguage build successfull!!!\n\n')

lang.json

{
	"home": {
  	"login": {
    	"en": "Login",
      "zh": "登录"
    }
  }
}

然后把生成命令添加到package.json中,就可以自动生成指定的语言包了。
image.png
如果临时修改了lang.json,也可以手动执行package中的命令:createLanguageFile

4,入口文件中引入i18n.jsx:

image.png

5,路由中配置多语言:

image.png

6,页面中使用语言项:

image.png

切换语言实现逻辑:

const changeLanguage = (lng: string) => {
  const oldLanguage = i18n.language;
  if (oldLanguage === lng) {
    return;
  }

  // 切换语言 i18n.changeLanguage
  i18n.changeLanguage(lng, function () {
    if (Array.isArray(i18n.options.fallbackLng)) {
      let pathName = pathname === '/' ? '' : pathname
      // 从地址中,删除旧的语言选项
      pathName = pathName.replace(new RegExp(`\\/(${Object.keys(langName).join('|')})`, 'i'), '')
      let url = '/' + lng + pathName

      window.history.pushState({}, '', url)
    }
  })
};

<li onClick="changeLanguage('en')">English</li>
<li onClick="changeLanguage('zh')">中文</li>

最后:访问地址实例:http://localhost:3000/zh/home