React小知識(3) - 國際化中碰到的問題

引言

react的國際化方案,能夠說是十分紅熟了。react

react-intl 一用上,文本,日期、貨幣通通搞定。git

這裏想和你們交流的並非如何使用 react-intl ,抑或如何在 redux 框架中去使用。github

而是一個小知識,如何在 placeholder 等屬性中支持多語言,而且你只需按照 react-intl 的方式去維護多套語言庫。redux

由於像 placeholder , title 這種 HTML 自帶的屬性,組件庫向來都是直接支持的,那麼問題來了,使用 react-intl 中的 <FormattedMessage /> 做爲一個 Object 是沒法用到這些屬性中去的,那麼咱們應該怎麼去處理這個問題呢?框架

他山之石,能夠攻玉

下面先說幾個我搜索到的方法。dom

  • 方法一:injectIntl() 是官方推薦的方法。
  • 方法二:利用 <FormattedMessage /> 的回調方法。

以上兩種方法均可以在這個issue中找到。ide

兩種方式的實現原理很清晰。函數

方法一,強調使用高階組件來處理這個問題,將 intl 注入到組件的 props 中,最後使用 intl.formatMessage 來解決問題。學習

方法二,很巧妙的利用到了 <FormattedMessage /> 組件的返回值,函數式的渲染了自身的子組件。this

這兩種思路當然都有可取之處,可是也有相應的問題。

方法一: injectIntl()

若是沒有從全局層面出發,去封裝的這種只是用於渲染的高階組件,帶來的成本,可想而知。

舉個例子,咱們有時候會封裝一些本身的基礎業務組件 BaseApp ,他們自己並無render方法,在不一樣權限的客戶訪問時,實現不一樣的派生類( StaffApp , CustomerApp ),對基礎業務組件進行調用。

class BaseApp extends Component {
  renderPersonInfo() {}
  renderDataAnalytical() {}
  renderTasks() {}
}

class StaffApp extends BaseApp {
  render() {
    return (
      {
        this.renderPersonInfo(),
        this.renderDataAnalytical()
      }
    )
  }
}

class CustomerApp extends BaseApp {
   render() {
    return (
      {
        this.renderPersonInfo(),
        this.renderTasks()
      }
    )
  }       
}
複製代碼

假設這個時候咱們對 BaseApp 進行 injectIntl ,那麼本來能夠繼承的方法,就所有失效了。因此咱們必須對派生類進行 injectIntl , 至關於,原本要作一次的事情,作了 N 次。

固然,咱們能夠把 BaseApp 中用到 placeholder 的組件,單獨的抽出來,進行 injectIntl ,不失爲一種解決方案。

因此雖然 injectIntl 是把好刀,可是用得好,用很差,就要看本身對整個項目的理解了。

方法二:組件返回值

拋開這麼寫,究竟是否優美不談。

最大的問題,仍是帶來了沒必要要的 dom 結構,由於 <FormattedMessage /> 組件是會渲染 <span /> 標籤的。

想象下你的 input 組件外面還包了一個 span 是否是瑟瑟發抖呢。

用本身的思路,試試看

基於上述狀況,我認爲以上兩種方法,不太適合目前的項目,那就是要本身造輪子啦。

開心,又能夠本身造輪子啦。

先亮代碼

const intl = {
  lang: {}
};

intl.formatMessage = (props) => {
  let message = intl.lang[props.id] || props.defaultMessage || props.id;

  if (!props.values) return message;
  
  const keys = Object.keys(props.values);

  for (let i = 0, l = keys.length; i < l; i++) {
    const key = keys[i];
    message = message.replace(new RegExp(`{${key}}`, "g"), props.values[key]);
  }

  return message;
}

export default intl;
複製代碼

原理比較簡單,兩步。

程序初始化的時候,對 intl.lang 賦值,同 react-intl

利用 props 中的 idvalues 屬性,獲取值並進行替換,返回真正的值。

使用方法:

<Input 
  value={showName}
  // placeholder="支持(1-10)位中文、英文與數字"
  placeholder={intl.formatMessage({id: "intl.showName.placeholder"})}
  onChange={this.handleNameChange.bind(this)}
  />
複製代碼

總結

  • 學習框架和類庫時,要學習精華之處,同時謹記本身同樣有寫出適合本身項目代碼的類庫的能力,多分析,勤思考。

-----------------------分割線-----------------------

評論中提到的問題

redux中如何使用及如何動態切換語言

粘貼一段項目中的實現

redux Providerreact-intl IntlProvider 並無衝突,能夠直接嵌套使用。

動態切換語言,我這裏的思路是把ReactDOM.render抽成一個方法,切換的使用再次調用就能夠了。僅供參考,可能有更好的思路。

效果:

  • 中文

  • 英文

圖中部分字段還未翻譯,故切換時沒有變動。

相關文章
相關標籤/搜索