React Native多语言切换应该是一个比较常见的需求,具体可以分为两种方式:

1. 识别手机系统语言,app自动加载相应的语言文件;

2. 允许用户在App内手动切换语言,这种情况并不需要保证App语言与手机系统语言一致;

下面就来介绍一下这两种方式如何完成,在介绍之前先声明一下本人目前开发所使用的react native版本是0.61.5,且使用的是react hook语法进行组件的编写。

一. 识别系统语言完成自动切换

实现语言的切换,我们需要借助github上的插件,在之前的RN开发中我一般都是使用react-native-i18n这个插件,但是从github上的说明来看,这个库已经废弃而且作者也不再维护了。因此,在新的项目中,我决定使用官方推荐的插件,也就是react-native-localize和i18n-js 。

具体的使用方法也很简单,简而言之就是通过react-native-localize插件获取手机系统语言,然后将其设置给I18n.locale变量即可。

src/languages/index.js

/*** 多语言配置文件*/
import I18n from "i18n-js";
import * as RNLocalize from "react-native-localize";
import cn from './cn';
import en from './en';
import rus from './rus';const locales = RNLocalize.getLocales();
const systemLanguage = locales[0]?.languageCode;  // 用户系统偏好语言if (systemLanguage) {I18n.locale = systemLanguage;
} else {I18n.locale = 'en';  // 默认语言为英文
}I18n.fallbacks = true;
I18n.translations = {zh: cn,en,ru: rus
};export default I18n;

上面的代码中一定要确保I18n.translations对象的键值一定是你设置I18n.locale属性的值,否则翻译文件会对不上。

接下来就是将应用中需要多语言国际化的文本统一配置到若干个语言文件中(上面代码中的cn.js、en.js以及rus.js)。例如:

src/language/cn.js

export default {filter: '筛选',delayTime: '延时',Home: {family: '家庭',device: '%{counts} 个设备',...},...
}

src/language/en.js

export default {filter: 'filters',delayTime: 'delay time',Home: {family: 'family',device: '%{counts} devices',...},...
}

最后在用到相应文本的视图组件中,通过如下形式即可引用当前语言对应的文本内容。

I18n.t('filter');
I18n.t('Home.family');
I18n.t('Home.device', { counts: 2 })

这样第一种语言切换的需求就完成了,是不是很简单。但是假如我们碰到产品要求App不仅能够实现识别系统语言进行自动切换,还要允许用户在App内手动切换语言。这就有点麻烦了。接下来我们看看应该怎么做。

二. 允许用户手动设置App语言

先明确一下思路,如果允许用户设置App语言,那么我们需要持久化一个全局状态来保存用户选择的语言。这里我们使用redux和redux-persist插件来完成。

第一步,定义一个action type,在src/redux/action.js文件中:

/*
* 本文件用于定义action常量,所有常量声明及对应值必须大写
*/
const USER_SET_LANGUAGE = 'USER_SET_LANGUAGE';  // 用户手动设置语言export { USER_SET_LANGUAGE
};

第二步,定义一个actionCreator函数,构造action对象,在src/redux/actionCreators.js文件中:

/*
* 本文件用于定义创建action对象的函数
* 在创建action对象时,必须包含action类型,以及action改变全局状态的最小数据集(payload)
*/
import * as actionType from './actions';// languageCode一定要严格按照RNLocalize.getLocales()中返回各语言字段编码来定义
const setLanguage = (languageCode) => {return {type: actionType.USER_SET_LANGUAGE,payload: {languageCode}}
}export {setLanguage
};

第三步,在已经定义好的reducers函数中添加对这一action的处理,在src/redux/reducers.js文件中:

/*
* 本文件用于定义初始全局状态对象以及用于处理action的reducer函数
*/
import * as actionType from './actions';let initialState = {userLanguageSetting: null  // 用户手动设置的语言
};const publicReducer = (store = initialState, action) => {const { type, payload } = action;switch(type) {case actionType.USER_SET_LANGUAGE:const { languageCode } = payload;return {...store,userLanguageSetting: languageCode}default:return store;}
}export default publicReducer;

上面的代码中,我是通过userLanguageSetting这一全局状态来保存用户设置的语言(languageCode的形式)。当用户没有手动设置语言时,userLanguageSetting字段为null,App自动加载系统语言。反之如果userLanguageSetting不为null,优先采用用户设置的语言。

如果我们只是用redux保存应用状态,那么这些全局状态会在App重新启动时全部丢失。所以我们需要对redux状态对象树进行持久化,这里可以借助redux-persist插件完成,具体如何配置,可以去查阅官方文档。

然后需要修改语言配置文件,在src/languages/index.js文件中,修改如下:

/*** 多语言配置文件*/
import I18n from "i18n-js";
import * as RNLocalize from "react-native-localize";
import cn from './cn';
import en from './en';
import rus from './rus';
import { store } from '@redux';const locales = RNLocalize.getLocales();
const systemLanguage = locales[0]?.languageCode;  // 用户系统偏好语言
const { userLanguageSetting } = store.getState();  // 用户手动设置语言if (userLanguageSetting) {I18n.locale = userLanguageSetting;
} else if (systemLanguage) {I18n.locale = systemLanguage;
} else {I18n.locale = 'en';  // 用户既没有设置,也没有获取到系统语言时,默认加载英语语言资源
}// 监听应用运行过程中语言的变化
store.subscribe(() => {const { userLanguageSetting: newUserLanguageSetting } = store.getState();if (newUserLanguageSetting && newUserLanguageSetting !== userLanguageSetting) {I18n.locale = newUserLanguageSetting;}
});I18n.fallbacks = true;
I18n.translations = {zh: cn,en,ru: rus
};export default I18n;
export { systemLanguage };

在新的配置文件中,我们需要从redux中获取全局状态判断用户是否设置了系统语言。由于这里并不是在一个React组件中,无法使用react-redux提供的connect方法获取该状态。所以直接导入store对象,通过getState()方法获取。

上面代码中,我们还使用store.subscribe来订阅redux状态的变化,这样在App运行过程中,如果用户选择/切换了语言,我们就能够立刻监听到最新的userLanguageSetting值,并立刻将它设置到I18n.locale中(注:store.subscribe订阅的是整个对象状态树的变化,所以为了避免不必要的更新locale值,需要判断一下变化的状态是否是userLanguageSetting字段)。

在用户切换语言的界面中:

/*** 设置语言界面*/
import React from 'react';
import { View, StyleSheet } from 'react-native';
import I18n, { systemLanguage } from '@languages';
import { Header, MenuItem } from '@components';
import { connect } from 'react-redux';
import { actionCreator } from '@redux';const SetLanguage = (props) => {const { userLanguageSetting, setLanguage } = props;const formatLanguageCodeToKey = (languageCode) => {switch(languageCode) {case 'zh':return 0;case 'en':return 1;case 'ru':return 2;default:return 1;}}// 根据当前语言状态,获取对应语言选项key,用绿色区分显示let currentLanguageKey = 1; // 默认英文if (userLanguageSetting) {currentLanguageKey = formatLanguageCodeToKey(userLanguageSetting);} else if (systemLanguage) {currentLanguageKey = formatLanguageCodeToKey(systemLanguage);}const updateLanguage = (key) => {switch(key) {case 0:setLanguage(actionCreator.setLanguage('zh'));break;case 1:setLanguage(actionCreator.setLanguage('en'));break;case 2:setLanguage(actionCreator.setLanguage('ru'));break;}}const languageGroups = [{ key: 0, centerText: '简体中文', pressFunc: updateLanguage },{ key: 1, centerText: 'English', pressFunc: updateLanguage },{ key: 2, centerText: 'русский', pressFunc: updateLanguage },];return (<View style={styles.container}><Header title={I18n.t('Setting.setting')} /><View style={styles.container}>{languageGroups.map(languageObj => {const { key, centerText, pressFunc } = languageObj;const isCurrentLanguage = currentLanguageKey === key;return (<MenuItemkey={key.toString()}pressFunc={() => {if (pressFunc) {pressFunc(key);}}}centerText={centerText}customCenterTextColor={isCurrentLanguage ? '#26C283' : '#333333'}/>);})}</View></View>);
};const mapStateToProps = (state) => {const { userLanguageSetting } = state;return {userLanguageSetting};
};const mapDispatchToProps = (dispatch) => {return {setLanguage(setLanguageAction) {dispatch(setLanguageAction);}}
}export default connect(mapStateToProps, mapDispatchToProps)(SetLanguage);const styles = StyleSheet.create({container: {flex: 1,backgroundColor: '#F3F4F8'}
});

当用户点击语言选项,会立刻派发一个action,修改userLanguageSetting字段,并在index.js中监听到userLanguageSetting字段值,并更新I18n.locale。这样似乎就大功告成了。

然而,当我们点击切换语言时,会发现一个问题,只有未渲染的页面语言切换了过去,而已渲染的页面则由于没有更新依旧显示的是切换之前的语言(特别是Tab路由加载的页面)。这个问题处理起来是有一点棘手的。我之前没有想到好的办法,去stackoverflow查了一下,发现有部分人建议通过使用react-native-restart这个插件重新加载js资源来解决,但是这样用户体验可能不太好。

后来我想了一下,只要保证用户切换语言后,对应的已渲染页面重绘一次就能够解决这个问题。按照这个思路,我编写了一个自定义hook,来监听语言的变化,并返回最新的语言。

src/hooks/useLanguageUpdate.js文件中:

import React, { useState, useEffect } from 'react';
import { store } from '@redux';
import I18n from '@languages';const useLanguageUpdate = (funcWhenUpdate, listenParamArr = []) => {const [currentLanguageCode, setCurrentLanguageCode] = useState( I18n.locale);useEffect(() => {return store.subscribe(() => {const { userLanguageSetting: newLanguageCode } = store.getState();if (newLanguageCode && newLanguageCode != currentLanguageCode) {setCurrentLanguageCode(newLanguageCode);if (funcWhenUpdate) funcWhenUpdate();}});}, [currentLanguageCode, ...listenParamArr]);return currentLanguageCode;
};export default useLanguageUpdate;

然后在渲染后会长时间存在的页面组件中,使用该hook。例如:

import { useLanguageUpdate } from '@hooks';const Home = () => {useLanguageUpdate();return (...);
};export default Home;

如果组件中有状态依赖更新后语言,可以使用useLanguageUpdate hook的返回值,例如:

let currentLanguage = useLanguageUpdate();switch(currentLanguage) {case 'zh':...break;case 'en':...break;...
}

如果组件中需要在语言更新时执行某些特定的行为,就可以用上funcWhenUpdate参数,例如:

// 自定义Hook,根据切换语言更新当前页面
useLanguageUpdate(() => {getAllDevsAndStragetiesRequest();getAllRoomsRequest();
});

在我目前的项目中,基本上需要添加的页面组件也就7、8个,主要是Tab路由栈的页面,tab标签等。这样基本上就完美的解决了已渲染页面显示切换前语言的问题。

React Native多语言切换相关推荐

  1. react native多语言_前端福音:为什么使用 React 和 SVG 开发图形 UI 是天作之合?

    本文最初发布于 Data Language 网站,经网站授权由 InfoQ 中文站翻译并分享. React 和 SVG 是一种强大的组合:声明式 UI 组件库与声明式图形语言堪称绝配,是前端开发人员的 ...

  2. 移动端跨平台开发Flutter 与 React Native对比

    移动端跨平台开发Flutter 与 React Native 深入对比分析 2019年6月21日20:41:35 发表评论 154 views 移动端跨平台在经历数年沉浮之后,如今还能在舞台聚光灯下雀 ...

  3. 全网最全 Flutter 与 React Native 深入对比分析

    作为 GSY 开源系列的作者,在去年也整理过 <移动端跨平台开发的深度解析> 的对比文章,时隔一年之后,本篇将重新由 环境搭建.实现原理.编程开发.插件开发.编译运行.性能稳定.发展未来 ...

  4. 【React Native开发】React Native控件之DrawerLayoutAndroid抽屉导航切换组件解说(13)

    转载请标明出处: http://blog.csdn.net/developer_jiangqq/article/details/50599951 本文出自:[江清清的博客] (一)前言 [好消息]个人 ...

  5. 为什么我切换到React Native来创建超级简单的底页

    I recently switched jobs, and one of my first tasks was to create a bottom sheet in React Native. 我最 ...

  6. React Native在美团外卖客户端的实践

    MRN简介 MRN(Meituan React Native) 是基于开源的React Native框架改造并完善而成的一套动态化方案,在开发体验上基本能与原生RN保持一致,同时从业务需求的角度满足从 ...

  7. 开发跨平台app推荐React Native还是flutter?

    嗯...这个问题十分不好回答啊(捋下鱼须).闲鱼作为flutter领域的先驱者,以及fish_redux.flutter_boost等当红flutter库的作者,当然是欢迎广大的开发者多多使用flut ...

  8. 是时候了解React Native了

    随着科技的发展,手机开发也在向好的方向不停的转变.IOS和Android两大手机操作横空出世,称霸江湖.我们每开发一个手机软件最少都需要开发这两个终端. 两大操作系统都在不断的提升完善,能力越来越强大 ...

  9. React Native与React的关系及特点

    一.React.React.js和React Native的关系 React是基础框架,是一套基础设计实现理念,开发者不能直接使用它来开发移动应用或网页. 在React之上发展出了React.js框架 ...

  10. React Native 从入门到原理

    React Native 是最近非常火的一个话题,介绍如何利用 React Native 进行开发的文章和书籍多如牛毛,但面向入门水平并介绍它工作原理的文章却寥寥无几. 本文分为两个部分:上半部分用通 ...

最新文章

  1. 使用Capture 制作元件库
  2. iOS 修改navigationController返回按钮颜色和文字
  3. numpy reshape resize用法
  4. C#调用word打印
  5. mysql二进制安装
  6. 嵌入式Linux系统编程学习之二十四消息队列
  7. 多线程—— Lock(线程锁)
  8. Learun.framework快速开发框架-功能特点与手机app
  9. 遥感导论网课_优化遥感导论课程教学环境的思考|遥感导论期末考试
  10. block的名词形式_block是什么意思_block在线翻译_英语_读音_用法_例句_海词词典
  11. 【跨境电商学习指南】
  12. PCB通孔类焊盘封装
  13. uva 12304(圆的相关函数模板)
  14. 远程视频监控必备专业知识
  15. linux设置mysql防火墙端口映射_Linux防火墙默认是关闭3306端口,iptables实现端口转发、端口映射及双向通路...
  16. 安路FPGA学习之有趣的下载方式
  17. 苹果5G芯片研发失败:继续依赖高通,还要担心被起诉?
  18. Win10最详细优化设置告别卡顿
  19. mac电脑打不开应用程序的解决方法
  20. R语言ggplot绘制地图-报错汇总(一)

热门文章

  1. C++代码审查工具Cppcheck和TscanCode
  2. ArcGis软件出图时修改色带上的刻度并导出色带
  3. origin免安装_美俏女剑士ORIGIN中文免安装版 11.4G
  4. steamcommunity本地反代443端口/80端口被占用解决办法
  5. 输出100以内的素数
  6. C语言输出9 * 9口诀。
  7. 动态规划之矩阵连乘问题详细解读(思路解读+填表+代码)
  8. pbr材质系统和vray材质系统有什么不同
  9. 反向题在测试问卷信效度_调查问卷的信效度分析
  10. python行业中性_知乎