前言
前段時間公司拓展了海外業(yè)務,因此需要前端系統(tǒng)的開發(fā)在完成業(yè)務需求的同時襟齿,可以實現(xiàn)國際化铸本,以滿足用戶的使用需要。
技術挑戰(zhàn)
之前完全沒有接觸相關的技術体斩,乍一看感覺很是簡單梭稚,就是翻譯一下文案。但是真正著手做的時候發(fā)現(xiàn)面臨很多技術上的挑戰(zhàn)絮吵,隨著項目上線弧烤,所以梳理一下整個開發(fā)過程中的思路。
需要進行國際化開發(fā)的內容
label蹬敲、placeholder暇昂、字段校驗提示信息
第三方插件
公司項目中用到了第三發(fā)組件:Antdesign和bootstraptable莺戒,都支持國際化開發(fā),但是其中bootstraptable的官方文檔對相關的內容較少急波,所以花費了較多的時間从铲。
開發(fā)思路
了解到React有支持國際化的組件-ReactIntl,所以除第三方插件以外澄暮,項目中的文案名段,基本都可以實現(xiàn)。把需要翻譯的文案提取出來泣懊,放到對應的語言文件(en_US.js)中伸辟,因為項目中好多內容是重復的,所以工作量不是很大嗅定,如果內容很多的話自娩,這種方式的工作量太大了,需要更換方案渠退。
開發(fā)過程
- 安裝ReactR-Intl組件
React-intl是雅虎的語言國際化開源項目FormatJS的一部分忙迁,通過其提供的組件和API可以與ReactJS綁定。上面這句話援引了官方文檔的說辭碎乃,主要表達的是姊扔,這是一個很好的開源項目,有大團隊支持梅誓,使用量也很大恰梢,不會有太多坑,可以放心用梗掰。
React-intl提供了兩種使用方法嵌言,一種是引用React組件,另一種是直接調取API及穗,官方更加推薦在React項目中使用前者摧茴,只有在無法使用React組件的地方,才應該調用框架提供的API埂陆,事實上苛白,我在項目的過程大部分都是用API的方式。
- 安裝react-intl需要執(zhí)行下面的命令:
npm install intl --save
- 在項目中引入react-intl
import { FormattedMessage } from 'react-intl';
該組件提供了全面的API來幫助我們進行開發(fā)焚虱,這里我們不詳細講解各個API购裙,只是介紹如何使用,其中使用頻率較高API包括:FormattedMessage(字符串格式化API)鹃栽、injectIntl(高階組件)躏率、FormattedPlural(格式化量詞)
- 通過代碼來了解一下如何使用上述API
import { injectIntl, FormattedMessage } from 'react-intl';
class Mycomponent extends Reflux.Component{
render(){
const {messages, loacal} = this.props.intl;
return (
<Input placeholder={messages["warehouseCodeplacehoder"]}/>
<Button type="primary" htmlType="submit" icon="search" ><FormattedMessage id="common_SearchSubmitBtn"/></Button>
)
}
}
export default injectIntl(Mycomponent );
通過injectIntl 在我們在 組件的 props 上會得到一個 intl 對象,它提供formatDate禾锤、formatTime私股、formatPlural摹察、formatMessage等方法和locale恩掷、formats、messages等屬性供嚎,這時候我們想要顯示字符串黄娘,可以使用formatMessage進行字符串的格式化。loacal可以拿到當前代碼的語言環(huán)境克滴。
可以直接利用messages['id]的方式逼争,可以直接從語言文件中拿到當前語言環(huán)境下文檔中對應id的字符串。
對于其他的字符串劝赔,可以使用formatMessageAPI進行格式化誓焦。
這種方式的應用場景還是蠻多的。
- 配置語言文件
語言的配置文件zh-config.js是比較關鍵的着帽,我們舉例說明
import appLocaleData from 'react-intl/locale-data/zh';
import messages from './zh_CN';
window.appLocale = {
messages: Object.assign({}, messages),
locale: 'zh-CN',
data: appLocaleData,
},
};
export default window.appLocale;
下面是語言文件zh.js杂伟,即key-value鍵值對
const zh_CN = {
id: "中文字符串",
}
export default zh_CN;
主入口文件mian.js
import React, {Component} from 'react';
import { IntlProvider, addLocaleData } from 'react-intl';
function getLocale(lang){
let result={};
switch(lang){
case 'zh_CN':
result = require('./locale/zh-config');
break;
case 'en_US':
result = require('./locale/en-US.config');
break;
default: result = require('./locale/zh-config');
}
return result.default || result;
}
class Lang extends React.Component{
constructor(props){
super(props);
this.state={
lan:" "
}
this.changeLang=this.changeLang.bind(this);
}
changeLang(p){
if(p==='en-US'){
this.setState({
lan:"en_US"
})
}
else {
this.setState(
{lan:"zh_CN"}
)
}
}
render(){
const {lan} = this.state;
const appLocale = getLocale(lan);
addLocaleData(...appLocale.data);
window.lang = appLocale.locale;
return (
<div >
<IntlProvider
locale={appLocale.locale}
messages={appLocale.messages}
>
<LocaleProvider locale={appLocale.antd}>
<Index />
</LocaleProvider>
</IntlProvider>
<Radio.Group style={style}>
<Radio.Button onClick={() => this.changeLang('zh-CN')} >中文</Radio.Button>
<Radio.Button onClick={() => this.changeLang('en-US')}>En</Radio.Button>
</Radio.Group>
</div>
)
}
}
ReactDOM.render(<Lang/>,document.getElementById('root'));
當設置了上述兩個文件時,我們可以根據當前l(fā)ocale值來找對應的配置文件仍翰,從而找到對應的語言文件赫粥,再去匹配對應的id,拿到value值予借。我們在主入口文件中進行設置越平,切換到對應語言時,導入該語言的配置文件和語言包灵迫,從而全面替換字符串秦叛,實現(xiàn)多語言切換。
- bootstraptable的國際化開發(fā)
bootstraptable的國際化開發(fā)難點在于瀑粥,他的官方文檔這方面寫的較簡潔挣跋,所以摸索了較長時間,最后也是同過injectIntl高階組件包裹table利凑,從而拿到當前語言浆劲,再配置表格自動導入對應的語言包。
import createReactClass from 'create-react-class';
import 'bootstrap';
import 'bootstrap-table';
import {injectIntl } from "react-intl";
import Main from './main/Main';
const Layout = createReactClass({
changeLang (p){
switch(p){
case "en-US": require("bootstrap-table-locale-en");
break;
case "th-TH": require("bootstrap-table-locale-th");
break;
case "zh-CN": require("bootstrap-table-locale-zh");
break;
default: require("bootstrap-table-locale-en");
}
},
render(){
this.changeLang(this.props.intl.locale)
return (
<div>
<Main {...this.props}></Main>
</div>
);
},
});
module.exports = injectIntl(Layout);
- antd國際化開發(fā)
antd 提供了一個 React 組件 LocaleProvider 用于全局配置國際化文案哀澈。
LocaleProvider 使用 React 的 context 特性牌借,只需在應用外圍包裹一次即可全局生效。
mian.js中有具體的使用方法割按,可以參考膨报。
解決store中的多語言實現(xiàn)
項目中調用接口的回調處理都在store文件中實現(xiàn),會有一些提示信息。但是react-intl并不支持store中字符串的多語言现柠,這個比較不好處理院领,在git上找到了一種解決方案。
首先添加一個組件 CurrentLocale.js
import {injectIntl} from 'react-intl';
// Does not actually render anything visible.
// We need it to provide access to internationalization for classes
// which are not a React component
class CurrentLocale extends React.Component {
static CurrentLocale = null;
componentWillMount() {
if (!CurrentLocale.instance)
CurrentLocale.instance = this;
}
render() {
return null;
}
}
export default injectIntl(CurrentLocale);
export function intl() {
return CurrentLocale.instance.props.intl;
}
export function formatMessage(...args) {
return intl().formatMessage(...args);
}
在項目入口處引入
然后在store文件中引入使用即可
import {formatMessage} from "../../../../locale/CurrentLocale";
class MyComponent extends Reflux.Store{
onFunctionCompleted(res){
if(res.state==='success'){
message.success(formatMessage({id:"OperateSuccess"}));
}else{
Modal.error({title:formatMessage({id:"OperateFailed"}),content:res.error});
}
}
}
export default MyComponent ;
寫在后面
畢業(yè)后的第一個項目就要求實現(xiàn)國際化够吩,對于之前沒有項目經驗又沒有人帶的我來說比然,挑戰(zhàn)巨大。因為之前沒有接觸過周循,所以全部都是邊學邊用强法,發(fā)現(xiàn)可以參考的文章不是很多,所以總結一下自己開發(fā)過程中的難點和通點湾笛,如果這篇文章可以幫助到大家饮怯,那么也算是做了一件有意義的事情。