内容简介:提起React项目国际化,首先想到著名的由于项目使用redux来管理状态,将语言环境与翻译文本都放入reducer中,使用相关action来触发语言切换:完成之后发现初始化的时候可以访问到store,使用指定的默认语言环境,但切换语言无效,排查后发现触发action后reducer确实更改了,但没有触发组件更新。查阅相关文档后,使用react内部的key属性来强制触发更新:
- 项目:大型数据管理系统,涉及硬件设备数据监控、日常业务信息管理等
- 技术:前后端分离,前端主要基于React-Redux
- 需求:前端一键无缝切换多国语言
使用 react-intl
提起React项目国际化,首先想到著名的 react-intl 库,这个库提供了针对组件、日期、数字、字符串等多种国际化方法。使用方法也很简单:
-
将不同语言的翻译文件放在各自的js文件中,同一处文本的多种语言翻译使用相同的key
// en_US.js const en_US = { "intl_hello": "Hello!", } export default en_US; // zh_CN.js const zh_CN = { "intl_hello": "你好!", } export default zh_CN; 复制代码
-
在入口文件中配置 react-intl 库
// index.js import { addLocaleData, IntlProvider } from 'react-intl'; // 引入多语言环境 import en from 'react-intl/locale-data/en'; import zh from 'react-intl/locale-data/zh'; addLocaleData([...en, ...zh]); // 引入翻译文本 import en_US from '.../intl/en_US.js'; import zh_CN from '.../intl/zh_CN.js'; const messagesMap = { en: en_US, zh: zh_CN } const locale = 'zh'; // 此处做了简化,下文将从redux中获取语言环境 render(( // 使用<IntlProvicer>包装项目组件,配置语言环境和翻译文本 <IntlProvider locale={local} messages={messages[local]}> //··· </IntlProvider> ), document.getElementById("root")); 复制代码
-
使用 react-intl 中内置的组件或方法替换需要做多语言的字符串、时间等,具体可参考 API文档 。
react-intl与redux
由于项目使用redux来管理状态,将语言环境与翻译文本都放入reducer中,使用相关action来触发语言切换:
// actions.js export const switchLocal = local => ({ type: 'SWITCH_INTL_LOCAL', payload: { local }, }); // reducers.js import en_US from '.../intl/en_US.js'; import zh_CN from '.../intl/zh_CN.js'; const messagesMap = { en: en_US, zh: zh_CN } const defaultLocal = { //默认语言环境,也可从浏览器或用户配置数据中获取 local: 'zh', messages: messagesMap.zh }; export const intlLocal = (state=defaultLocal, action) => { switch(action.type) { case 'SWITCH_INTL_LOCAL': return { local: action.payload.local, messages: messagesMap[action.payload.local], } default: return state; } } // index.js // 略去了文件中的redux配置等代码 const { local, messages } = store.getState().intlLocal; // 从store中获取语言配置 render(( // react-redux中的Provider需要包在IntlProvider之外,IntlProvider才能访问到store <Provider store={store}> <IntlProvider locale={local} messages={messages}> //··· </IntlProvider> </Provider> ), document.getElementById("root")); 复制代码
完成之后发现初始化的时候可以访问到store,使用指定的默认语言环境,但切换语言无效,排查后发现触发action后reducer确实更改了,但没有触发组件更新。查阅相关文档后,使用react内部的key属性来强制触发更新:
// index.js render(( <Provider store={store}> // 加入key属性来强制触发更新 <IntlProvider key={local} locale={local} messages={messages}> //··· </IntlProvider> </Provider> ), document.getElementById("root")); 复制代码
存在问题与方案探讨
在上一步中使用key来强制触发更新,对于一般简单的网站或前端系统来说,到这一步就可以了。
万恶的但是,由于接手的系统过于复杂,使用key强制触发组件更新时,会引起此 <IntlProvider>
包裹下的所有组件全部被更新,导致类似于页面整体被刷新的效果,从而出现websocket重连、数据丢失等一系列问题,由于不便于动用其他模块,思考过后剩下两种方案:
- 语言切换时给予相应提示,然后跳转到欢迎界面,这样重新进入各子系统时会重新发起各种连接。由于并不会经常切换语言,而且语言切换一般也就是发生在刚进入系统的时候,所以这个方案是最实用也最省力的。又是万恶的但是,由于项目背景比较复杂,上面领导的意思是像那些大型网站一样“无缝”切换中英文,一跳转就“有缝”了。。根本不考虑一个网站和一个大型B/S系统的差异,于是在需求降级可能性微乎其微的条件下,这个最合适的方案也只能作为紧急备用方案了。
-
修改 react-intl 库,需要包装库中用到的每个方法,将数据源由Context改为redux的store。做的时候发现基本只是在处理字符串,就干脆去掉了 react-intl 库的依赖,手写了个类似于intl库中的
<FormattedMessage>
组件,使用的时候又发现只能用于组件的局限性,又参考阿里的 react-intl-universal ,写了个直接由key生成翻译文本的方法。而这个方案目前还在完善和测试中。
以上所述就是小编给大家介绍的《记一次大型React项目的国际化方案探索》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。