react項目國際化實現過程以及store中如何實現多語言開發

前言

前段時間公司拓展了海外業務,因此需要前端系統的開發在完成業務需求的同時,可以實現國際化,以滿足用戶的使用需要。

技術挑戰

之前完全沒有接觸相關的技術,乍一看感覺很是簡單,就是翻譯一下文案。但是真正著手做的時候發現面臨很多技術上的挑戰,隨著項目上線,所以梳理一下整個開發過程中的思路。

需要進行國際化開發的內容

label、placeholder、字段校驗提示信息
需要進行語言切換的內容.png
第三方插件

公司項目中用到了第三發組件:Antdesign和bootstraptable,都支持國際化開發,但是其中bootstraptable的官方文檔對相關的內容較少,所以花費了較多的時間。

開發思路

了解到React有支持國際化的組件-ReactIntl,所以除第三方插件以外,項目中的文案,基本都可以實現。
項目中文案整理.png

把需要翻譯的文案提取出來,放到對應的語言文件(en_US.js)中,因為項目中好多內容是重復的,所以工作量不是很大,如果內容很多的話,這種方式的工作量太大了,需要更換方案。
開發過程

  • 安裝ReactR-Intl組件
    React-intl是雅虎的語言國際化開源項目FormatJS的一部分,通過其提供的組件和API可以與ReactJS綁定。上面這句話援引了官方文檔的說辭,主要表達的是,這是一個很好的開源項目,有大團隊支持,使用量也很大,不會有太多坑,可以放心用。
    React-intl提供了兩種使用方法,一種是引用React組件,另一種是直接調取API,官方更加推薦在React項目中使用前者,只有在無法使用React組件的地方,才應該調用框架提供的API,事實上,我在項目的過程大部分都是用API的方式。
  1. 安裝react-intl需要執行下面的命令:
npm install intl --save
  1. 在項目中引入react-intl
import { FormattedMessage } from 'react-intl';

該組件提供了全面的API來幫助我們進行開發,這里我們不詳細講解各個API,只是介紹如何使用,其中使用頻率較高API包括:FormattedMessage(字符串格式化API)、injectIntl(高階組件)、FormattedPlural(格式化量詞)

  1. 通過代碼來了解一下如何使用上述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可以拿到當前代碼的語言環境。

可以直接利用messages['id]的方式,可以直接從語言文件中拿到當前語言環境下文檔中對應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'));

當設置了上述兩個文件時,我們可以根據當前locale值來找對應的配置文件,從而找到對應的語言文件,再去匹配對應的id,拿到value值。我們在主入口文件中進行設置,切換到對應語言時,導入該語言的配置文件和語言包,從而全面替換字符串,實現多語言切換。

  • bootstraptable的國際化開發
    bootstraptable的國際化開發難點在于,他的官方文檔這方面寫的較簡潔,所以摸索了較長時間,最后也是同過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國際化開發
    antd 提供了一個 React 組件 LocaleProvider 用于全局配置國際化文案。
    LocaleProvider 使用 React 的 context 特性,只需在應用外圍包裹一次即可全局生效。
    mian.js中有具體的使用方法,可以參考。

解決store中的多語言實現

項目中調用接口的回調處理都在store文件中實現,會有一些提示信息。但是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 ;

寫在后面

畢業后的第一個項目就要求實現國際化,對于之前沒有項目經驗又沒有人帶的我來說,挑戰巨大。因為之前沒有接觸過,所以全部都是邊學邊用,發現可以參考的文章不是很多,所以總結一下自己開發過程中的難點和通點,如果這篇文章可以幫助到大家,那么也算是做了一件有意義的事情。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,615評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,606評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,826評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,227評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,447評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,992評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,807評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,001評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,243評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,709評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,996評論 2 374

推薦閱讀更多精彩內容

  • 開始之前,先了解目前常用的 React 國際化插件:The Best Libraries for React i1...
    Evelynzzz閱讀 41,925評論 0 18
  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,154評論 4 61
  • 時間過的真快啊,似乎就在轉瞬間,我們天人永隔已經五載。你的弟弟也已經到了一個狗都嫌棄的年紀。前幾天,有人跟媽媽聊...
    禾言_2176閱讀 3,873評論 1 1
  • 我初中和高中的班主任很是巧地都姓張,都是三十歲出頭的年輕人,偏偏都有點顯老,同樣永遠模糊的鏡片,同樣喜歡把襯衫扎進...
    珂鳴閱讀 274評論 0 1
  • 寫給讀者的話: 敬愛的讀者,你好! 如果你是因為標題而進來的讀者,那么,恭喜你被騙了,因為我寫下的這篇文章,純粹是...
    謝卓錕閱讀 3,630評論 6 3