react-native实现国际化

2,113 阅读4分钟

通知:现在出来了比较新的库:i18next,具体实践可以看这篇文章:juejin.cn/post/720473…

其实国际化就是:根据当前选择的语言,将应用中的静态文本切换成对应的语言。

这里主要需要两个信息

  • 选择的语言:可以是跟随系统的,也可以是自己定义的
  • 语言包:k-v存储的内容,k是这个内容的键,v是显示的内容

在开发中,大部分情况都是一开始没有做国际化,后来业务扩展业务到国外,需要英文版的应用,这个时候如果要手工一个个文本替换,工作量未免太大。

不会偷懒的程序员不是好程序员😏,现在肯定有工具可以解决的,然后还真发现了一个,di18n

大概的原理就是转AST,替换文本,再转回来,有兴趣的可以自行查阅。

img

总结一下,需要用到的库

实战部分

新建项目

新建一个rn项目

npx react-native init i18n_practice

安装第三方库

把上文提到的第三方库都安装一下

yarn add react-native-localize i18n-js
yarn add -D di18n-cli

生成国际化语言包和配置

初始化

npx di18n init

初始化完成后会生成一些东西

一个是语言包

image-20210511160226202

一个是配置文件

image-20210511160317263

这里默认的入口是src,rn官方默认的模板没有,所以创建一个src目录把App.js挪进去

image-20210511160647003

另外,配置文件还要做一些修改

module.exports = {
  entry: ['src'],
  exclude: [],
  output: ['src'],
  disableAutoTranslate: true,
  extractOnly: false,
  translator: null,
  ignoreComponents: [],
  ignoreMethods: [],
  primaryLocale: 'zh-CN',
  supportedLocales: ['zh-CN', 'en-US'],
-  importCode: "import { intl } from 'di18n-react';",
-  i18nObject: 'intl',
+  importCode: "import I18n from 'i18n-js';", // 使用i18n-js库
+  i18nObject: 'I18n', // 和上面import的变量保持一致
  i18nMethod: 't',
  prettier: {singleQuote: true, trailingComma: 'es5', endOfLine: 'lf'},
  localeConf: {type: 'file', folder: 'locales'},
};

测试了一下,现在不支持主语言是英语的转换❗️

所以我们要先修改一下APP.js,加入一些中文

image-20210511163138024

转换源代码

现在,运行转换命令

npx di18n sync

然后会发现App.js的内容改变了

  • 在上面导入了importCode属性对应的变量

image-20210511163330314

  • 将中文使用I18n.t包裹起来

image-20210511163500999

语言包也更新了,中文英文是一样的,需要自己修改

image-20210511163843426

修改一下英文语言包

image-20210511164632417

然后发现内容变成了这样

simulator_screenshot_C4EEE3B2-855C-43F0-A344-B2213A01D12C

原因是没有修改I18n的配置,默认的配置无法找到语言包

加入配置文件

新建config/i18n.js

/**
 * 多语言配置文件
 */
import I18n from 'i18n-js';
import * as RNLocalize from 'react-native-localize';
import en from '../locales/en-US';
import zh from '../locales/zh-CN';

// 获取手机本地国际化信息
const locales = RNLocalize.getLocales();
const systemLanguage = locales[0]?.languageCode; // 用户系统偏好语言

I18n.fallbacks = true;

// 加载语言包
I18n.translations = {
  zh,
  en,
};

if (systemLanguage) {
  I18n.locale = systemLanguage;
} else {
  I18n.locale = 'en';
}

export default I18n;

然后就没问题了

![simulator_screenshot_7D5559DD-A5D4-4077-8480-10652CCFA288](/Users/weixiaolin/Library/Application Support/typora-user-images/simulator_screenshot_7D5559DD-A5D4-4077-8480-10652CCFA288.png)

App内切换语言

如果在app内切换语言,需要以app内的语言为准,切换完成要重新刷新js内容才会生效,然后要将用户选择的语言进行持久化存储。

加入两个第三方库

yarn add react-native-restart @react-native-community/async-storage

修改配置文件config/i18n.js,加入修改语言和重置方法

/**
 * 多语言配置文件
 */
import I18n from 'i18n-js';
import * as RNLocalize from 'react-native-localize';
import en from '../locales/en-US';
import zh from '../locales/zh-CN';
import AsyncStorage from '@react-native-community/async-storage';
import RNRestart from 'react-native-restart';

// 获取手机本地国际化信息
const locales = RNLocalize.getLocales();
const systemLanguage = locales[0]?.languageCode; // 用户系统偏好语言
export const languageKey = 'language';

I18n.fallbacks = true;

// 加载语言包
I18n.translations = {
  zh,
  en,
};

/**
 * 初始化
 */
AsyncStorage.getItem(languageKey).then(value => {
  if (value) {
    I18n.locale = value;
  } else if (systemLanguage) {
    I18n.locale = systemLanguage;
  } else {
    I18n.locale = 'en';
  }
});

/**
 * 修改语言
 * @param {*} language 语言
 */
export async function changeLanguage(language) {
  await AsyncStorage.setItem(languageKey, language);
  // Immediately reload the React Native Bundle
  RNRestart?.Restart();
}

/**
 * 重置
 */
export async function resetLanguage() {
  await AsyncStorage.removeItem(languageKey);
  // Immediately reload the React Native Bundle
  RNRestart?.Restart();
}

export default I18n;

app.js中加入测试代码

image-20210512100857221

测试

ok,多语言切换功能完成👏

Kapture 2021-05-12 at 10.39.18

完整代码地址:gitee.com/wcly/i18n_p…