基於react-intl實現手動國際化切換

知乎專欄:zhuanlan.zhihu.com/c_215040065,我的博客:blog.caichengnan.com/css

前言

國際化是一個很常見的需求,以前沒有這方面的相關經驗,因此決定練一下手。正好最近在寫一個react骨架(新項目可直接移植的骨架),上網查了一下,經常使用的解決方案是yahoo的react-intl庫,大體效果以下。react

實現思路

  • 首先解決靜態國際化,即根據瀏覽器的語言,自動加載對應的語言模板。這裏只需判斷navigator.language類型便可,而後經過react-intl提供了IntlProvider組件,加載組件屬性的locale和messages,最後在須要用到國際化的組件裏,引入FormattedMessage組件(react-intl內置),經過id映射到對應的國際化文件裏的屬性(例以下面的en_US.js的hello)。便可實現靜態國際化。git

  • 動態國際化,即用戶能夠經過按鈕切換,實現語言的切換。最容易想到的方案就是,在語言模板放在redux的store裏,提供一個切換語言的action,改變store裏的國家和語言模板,再觸發對應的FormattedMessage組件渲染。let's do it!github

代碼實現

  • 在src下新建locale文件存放國際化語言的文件,這裏咱們新建了en_US.js和zh_CN.js。

en_US.jsredux

const en_US = {
  hello: 'Hello, world!',
  name: 'my name is {name}'
}    
export default en_US;
複製代碼

zh_CN.js瀏覽器

const zh_CN = {
  hello: '你好,世界!',
  name: '個人名字是 {name}'
}
export default zh_CN; 
複製代碼

一個是常規的變量hello,一個是帶有變量{name}的字段nameide

  • react-intl的IntlProvider組件相似redux的Provider組件,須要在全局引入。因此咱們封裝一下Intl.jsx組件,將redux和IntlProvider相結合。

Intl.jsxsvg

import React, { Component } from 'react';
import { addLocaleData, IntlProvider } from 'react-intl';
import { connect } from 'react-redux';
import zh_CN from './locale/lang/zh_CN';
import en_US from './locale/lang/en_US.js';
import zh from 'react-intl/locale-data/zh';
import en from 'react-intl/locale-data/en';

addLocaleData([...zh,...en]);

class Inter extends Component {
  render() {
    let { locale, localeMessage, children } = this.props;
    return (
      <IntlProvider key={locale} locale={locale} messages={localeMessage}> {children} </IntlProvider>
    )
  }
};

function chooseLocale(val) {
  let _val = val || navigator.language.split('_')[0];
  switch (_val) {
    case 'en':
      return en_US;
    case 'zh':
      return zh_CN;
    default:
      return en_US;
  }
}

const mapStateToProps = (state, ownProps) => ({
  locale: state.root.language,
  localeMessage: chooseLocale(state.root.language)
});

let Intl = connect(mapStateToProps)(Inter);

export default Intl;
複製代碼

解釋一下這個組件,組件是將redux裏的數據綁定到IntlProvider組件上,addLocaleData函數添加須要本地化的語言,這個須要聲明。redux中傳遞兩個props,locale表明當前語言,localeMessage表明locale裏的語言文件內容。函數

這裏有一個很關鍵的地方,即key屬性。IntlProvider中的屬性變動並不會觸發FormattedMessage從新渲染,剛開始想要forceUpdate強制更新組件,後來上網查了一個解決方案,在組件中加入key,就能解決這個問題ui

  • 在實際使用語言的組件中引入FormattedMessage,固然react-intl還支持其餘類型的轉換組件,好比時間類型FormattedDate等等。可從官網上查詢API。github

App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import { FormattedMessage } from 'react-intl';
import actions from '../actions/index.js';
import { connect } from 'react-redux';

class App extends Component {
  changeLanguage() {
    let lang = this.props.locale;
    lang = lang === 'zh' ? 'en' : 'zh';
    this.props.changeLanguage(lang);
  }
  render() {
    const { locale } = this.props;
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">
            <FormattedMessage
              id="hello"
            />
          </h1>
        </header>
        <p className="App-intro">
          <FormattedMessage
            id="name"
            values={{ name: <b>{'carroll'}</b> }}
          />
        </p>
        <button onClick={() => this.changeLanguage()}>{locale === 'zh' ? '切換英文' : 'change chinese'}</button>

      </div>
    );
  }
}
const mapStateToProps = (state, ownProps) => ({
  locale: state.root.language,
});
const mapDispatchToProps = (dispatch, ownProps) => ({
  changeLanguage: (val) => dispatch(actions.changeLanguage(val))
});
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App);
複製代碼

App.js主要實現了兩個功能,一個實現動態切換的action,一個FormattedMessageid與數據的綁定。

  • 最後在根文件引入Intl.jsx便可
// ... 省略前面的引入
ReactDOM.render(
  <Provider store={store}> <Intl> <App /> </Intl> </Provider>,
  document.getElementById('root'));
複製代碼
  • 下面是github上的源碼

github源碼

總結

總體實現下來,動態的國際化切換也沒有多難,可是咱們要有思考。把國際化的數據放在redux中是否有些浪費,能否不引入FormattedMessage也能解決文字的切換,在IntlProvider上綁定key是否會形成其餘無關組件的從新渲染。這些都是咱們須要考慮的問題。

若是錯誤請指出,若是對您有幫助,麻煩點個贊

相關文章
相關標籤/搜索