React項目國際化(antd)多語言開發

前言

最近搭建一個項目,從0開始作,須要作多語言的國際化,今天搞了一下,基本達到了想要的效果,第一次發掘金勿噴,在這裏簡單分享下:html

背景

國際化方案

  • 國際化方案概述
  • 前端國際化詳解、舉例
  • 國際化資源文件管理
  • 項目之間、開發者與翻譯者之間的協做
  • 國際化規範附錄
  • 擴展閱讀

國際化方案概述

國際化是一個看似簡單,實則很是複雜的領域,實際進行國際化工做時,你們會發現它每每會涉及不少內容:前端

  • 前端國際化
  • 服務端國際化
  • 國際化資源文件管理
  • 項目之間、開發者與翻譯者之間如何協做

並且,國際化方案每每與具體的技術棧是綁定的。react

本國際化方案僅針對 React 技術棧,且不會涉及服務端國際化內容。git

前端國際化詳解、舉例

國際化的核心步驟有兩步:github

  1. 建立資源文件,以 key-value 方式存儲
  2. 加載資源文件,將頁面上 key 的內容替換爲相關 value

一些探索

也說不上是探索吧,就Google了一波, GitHub 上找了一個比較成熟的庫以下:
react-i18nextnpm

react-intljson

react-intl-universaapi

接下來一一介紹一下如何使用瀏覽器

react-i18next

安裝bash

npm install i18next react-i18next --save複製代碼

引入App.js

import i18n from 'i18next';
import { useTranslation, initReactI18next } from 'react-i18next';
複製代碼

初始化

const lng = 'en';
i18n
  .use(initReactI18next) // passes i18n down to react-i18next
  .init({
    resources: {
      en: {
        translation: {
          Welcome: 'Welcome to React',
        },
      },
      zh: {
        translation: {
          Welcome: '歡迎進入react',
        },
      },
    },
    lng: lng,
    fallbackLng: lng,

    interpolation: {
      escapeValue: false,
    },
  });
複製代碼

實際使用結果

function App() {
  const { t } = useTranslation();
  return (
    <div className="App">
      <p>{t('Welcome')}</p>
    </div>
  );
}

export default App;
複製代碼

封裝後的成果:

// ...
import i18n from '@src/i18n';
// xxx component
console.log('i18n來一發:', i18n.t('INVALID_ORDER'));
render() { 
  // ...
  <button> {i18n.t('INVALID_ORDER')} </button>
}複製代碼

react-intl

背景:

用於國際化 React 組件,提供 React 組件和 API 來格式化日期,數字,字符串(包括單複數和翻譯)。

react-intl庫是業界很受歡迎的庫之一。 react-intl用包裹組件的形式裝飾你的React.Component,動態注入國際化消息,以便可以動態加載語言環境數據,而且無需從新加載頁面

安裝:

npm install react-intl --save複製代碼

載入語言環境數據。

React Intl 依賴這些數據來支持單複數和相對時間格式化的功能。

// Main.js
import { addLocaleData } from 'react-intl'; /* react-intl imports */
import en from 'react-intl/locale-data/en';
import zh from 'react-intl/locale-data/zh';
addLocaleData([...en, ...zh]);  // 引入多語言環境的數據  複製代碼

雖然我只用到了文本翻譯的功能,覺得就不須要加載這些數據,但後來發現這是必須的步驟。否則會報錯:

[React Intl] Missing locale data for locale: "zh". Using default locale: "en" as fallback.複製代碼

使用

組件包裹須要實現國際化的根組件,這個組件樹以後就會在配置的i18n上下文中了。

因爲項目中用到了react-hot-loader,根組件 Main<AppContainer>包裹了,而且是從單獨的一個文件 import 了 Main 組件。

//app.js
import { AppContainer } from 'react-hot-loader'
import Main from './components/Main'
//... ...
const render = Component => {
    ReactDOM.render(
        <AppContainer>
            <Component />
        </AppContainer>,
        document.getElementById('app')
    )
}
render(Main);複製代碼

因而直接在 Main.js 中使用<IntlProvider>組件。把它加到 render()返回節點的最外層就好了。

// Main.js
import { addLocaleData, IntlProvider } from 'react-intl'; /* react-intl imports */
render(){
    return (
        <IntlProvider>
          //··· ···
        </IntlProvider>
    )
}複製代碼

添加多種語言對應的文本。

好比要支持中英文,爲了方便以後維護,能夠新建兩個文件:

locale目錄下新建
// en_US.js
const en_US = {
    hello: "Hello!",
    //... ...
}
export default en_US;

// zh_CN.js
const zh_CN = {
    hello: "你好!",
    //... ...
}
export default zh_CN;複製代碼

而後在Main.js中引入這兩個變量。

// Main.js
import zh_CN from "../locale/zh_CN"     // import defined messages in Chinese
import en_US from "../locale/en_US"     // import defined messages in English複製代碼

全局配置當前的語言,和相對應的文本。

即配置<IntlProvider>組件的兩個屬性localemessages

// Main.js
render(){
    let messages = {}
    messages['en'] = en_US;
    messages['zh'] = zh_CN;
    return (
        <IntlProvider locale={this.state.lang} messages={messages[this.state.lang]}>
            //··· ···
        </IntlProvider>
    )
}複製代碼

這樣基本配置就完成了,能夠經過改變 this.state.lang的值來改變頁面語言。

// Main.js
/**
 * Change language
 * @param {String} lang new language
 */
changeLanguage(lang) {
    this.setState({
        lang: lang
    })
}複製代碼

接下來,添加翻譯的文本到頁面中

基本只須要使用到一個組件:<FormattedMessage>。這個組件默認生成一個<span>,內容是翻譯後的文本,也就是 messages中對應字段的值。

在須要添加國際化文本的組件中,引入FormattedMessage組件。

import { FormattedMessage  } from 'react-intl'; /* react-intl imports */
//... ...
<FormattedMessage id="hello" />複製代碼

當前語言爲en時,生成結果:

<span>Hello!</span>複製代碼

到這裏,react-intl基本的國際化就實現了。

尾聲

編寫規範

  1. 必須填寫 defaultMessage,並將 defaultMessage 做爲中文翻譯
  2. id 不得重複
  3. 在使用 intl.formatMessage() 時,必須使用 defineMessages,預約義消息

擴展閱讀

react-intl-universal

背景:

由阿里巴巴推出的react國際化庫

這個庫最好地方在於使用簡單方便,侵入性低

安裝

使用npm安裝

npm install react-intl-universal --save複製代碼

初始化

在初始頁面,進行該庫的初始化,配置語言包,json文件根據須要支持幾種語言來決定,下面的圖片中僅支持中英文

image.png

於項目入口文件中配置國際化

import intl from 'react-intl-universal';

// locale data
const locales = {
  "en-US": require('./locales/en-US.json'),
  "zh-CN": require('./locales/zh-CN.json'),
};

class App extends Component {

  state = {initDone: false}

  componentDidMount() {
    this.loadLocales();
  }

  loadLocales() {
    // react-intl-universal 是單例模式, 只應該實例化一次
    intl.init({
      currentLocale: 'en-US', // TODO: determine locale here
      locales,
    })
    .then(() => {
    this.setState({initDone: true});
    });
  }

  render() {
    return (
      this.state.initDone &&
      <div>
        {intl.get('SIMPLE')}
      </div>
    );
  }

}複製代碼

語言配置文件能夠是json或者js,json格式以下:

英語配置文件 ./locales/en-US.json

{
    "SIMPLE": "Simple Sentence",
    "LANG_TYPE": "paas-us",
    "INPUT_MOBILE": "Mobile Number",
    "HELLO": "Hello, {name}. Welcome to {where}!"
}複製代碼

中文配置文件 ./locales/zh-CN.json

{
    "SIMPLE": "簡單的句子",
    "LANG_TYPE": "paas-cn",
    "INPUT_MOBILE": "手機號",
    "HELLO": "你好, {name}。歡迎來到{where}!"
}複製代碼

調用

在剛纔的初始化代碼中,render函數裏面已經進行了調用了。在整個項目的其餘地方,因爲已經進行了初始化了,因此能夠直接調用了。調用的例子以下:

import intl from 'react-intl-universal';

class Test extends Component {
  render() {
    return (
      <div>
        {intl.get('INPUT_MOBILE')}
      </div>
    );
  }

}複製代碼

切換

再來看一下初始化函數

intl.init({
    currentLocale: 'en-US', // TODO: determine locale here
    locales,
})複製代碼

初始化的時候,除了直接指定語言外,還能夠由函數determineLocale根據如下配置進行指定:

  1. Url中的query參數
  2. cookie中的參數
  3. 瀏覽器的當前語言(當沒有配置query參數和cookie參數時)

這些配置的生效以下面代碼所示:

let currentLocale = intl.determineLocale({
  urlLocaleKey: "lang",
  cookieLocaleKey: "lang"
});

intl.init({
    currentLocale, // determine locale here
    locales,
})複製代碼

那麼,咱們能夠利用以下方式進行切換:當選擇相應語言時,觸發回調函數,在函數內,修改url或者cookie,而後進行頁面刷新,從新初始化,便可以切換語言了。

下面我給出一個根據cookie切換的例子:

handleClick = (lang) => {
    Cookies.set('lang', lang, { expires: '1Y' });
    window.location.reload(true);
}複製代碼

進階

react-intl-universal庫在語言處理上,還有不少其餘功能,如:

  • 帶HTML標籤的HTML 文本
  • 變量
  • 單複數形式
  • 貨幣
  • 日期

html中引用資源包裏的文字

a.純文字,使用intl.get()

<div> {intl.get('SIMPLE')} </div>複製代碼

b.帶html模板的文字,使用intl.getHTML()方法

例如資源包裏是這樣定義的

{ 
   "SIMPLE": "This is <span style='color:red'>HTML</span>" 
}複製代碼

引用時需使用getHTML()方法獲取文字

<div>{intl.getHTML('SIMPLE')}</div>
複製代碼

數字形式和千分位分隔符

下例中的變量爲num,給它標記爲plural後,它的值只能爲數字。當num值爲0時,顯示"no photos.";當值爲1時,顯示"one photo.";當值爲其餘數字好比25000時,顯示「25,000 photos.」,這裏的'#'表示給num的值添加千分位分隔符後顯示

{ 
   "PHOTO": "You have {num, plural, =0 {no photos.} =1 {one photo.} other {# photos.}}" 
}複製代碼

引用結果以下:

intl.get('PHOTO', {num:0}); // "You have no photos."
intl.get('PHOTO', {num:1}); // "You have one photo."
intl.get('PHOTO', {num:1000000}); // "You have 1,000,000 photos."複製代碼

顯示貨幣格式

具體語法爲{變量名, 類型, 格式化},下例中變量名爲"price",它的類型是number,"USD"表示在值前面加上美圓符號($)

{ 
   "SALE_PRICE": "The price is {price, number, USD}" 
}複製代碼

引用及顯示結果以下:

intl.get('SALE_PRICE', {price:123456.78}); // The price is $123,456.78複製代碼

顯示日期

語法同上:{變量名, 類型, 格式化},當類型爲"date"時,格式化有如下幾個選項:short,medium,long,full,也可不格式化

{
  "SALE_START": "Sale begins {start, date}",
  "SALE_END": "Sale ends {end, date, long}"
}複製代碼

引用及顯示:

intl.get('SALE_START', {start:new Date()}); // Sale begins 4/19/2017
intl.get('SALE_END', {end:new Date()}); // Sale ends April 19, 2017複製代碼

配置默認message

當遇到好比因拼寫錯誤致使沒法匹配到資源包裏的文字時,能夠事先配置默認的message,這時當沒法匹配的資源包時會顯示默認message

//"defaultMessage()"可簡寫爲"d()"
intl.get('not-exist-key').defaultMessage('沒有找到這句話');複製代碼

同理亦可配置帶html模板的默認message

intl.getHTML('not-exist-key').d(<h2>沒有找到這句話</h2>)複製代碼

帶變量的message

資源包裏的配置以下

{
    "HELLO": "Hello, {name}. Welcome to {where}!" 
}複製代碼

在html中引用時

<div> intl.get('HELLO', {name:'banana', where:'China'}) </div>複製代碼

顯示的結果爲:Hello, banana. Welcome to China!

尾聲

到此react-intl-universal基本的使用方法介紹完畢了,若是以上達不到你的需求請前往git翻看更多readme文檔和api文檔。

git地址:github.com/alibaba/rea…

antd/antd-mobile 國際化方案

LocaleProvider國際化

組件 LocaleProvider 用於全局配置國際化文案

ant.design/components/…

爲組件內建文案提供統一的國際化支持

使用
LocaleProvider 使用 React 的 context 特性,只需在應用外圍包裹一次便可全局生效。

import { LocaleProvider } from 'antd';
import zh_CN from 'antd/lib/locale-provider/zh_CN';
import moment from 'moment';
import 'moment/locale/zh-cn';

moment.locale('zh-cn');
...

return <LocaleProvider locale={zh_CN}><App /></LocaleProvider>;複製代碼

提供了英語,中文,俄語,法語,德語等多種語言支持,全部語言包能夠在 這裏 找到。

注意:若是你須要使用 UMD 版的 dist 文件,應該引入 antd/dist/antd-with-locales.js,同時引入 moment 對應的 locale,而後按如下方式使用:

const { LocaleProvider, locales } = window.antd;

...

return <LocaleProvider locale={locales.en_US}><App /></LocaleProvider>;複製代碼

到此今天的國際化分享大全就結束了,我我的感受仍是react-intl-universal比較好用,若是對你有幫助記得點點關注哦,

案例已上傳到github,有相關需求的能夠去看看,第一次寫勿噴,若是有問題請指正!

相關文章
相關標籤/搜索