國(guó)際化可以使web站點(diǎn)或者app在不同的國(guó)家或者地區(qū)使用??梢試?guó)際化的內(nèi)容有文本,日期、時(shí)間和數(shù)字的格式,還有貨幣等。目前市場(chǎng)上流行的react國(guó)際化框架主要有react-i18n和react-intl,本文主要以文本國(guó)際化來(lái)介紹兩種方案的入門用法及對(duì)比。
React-i18next
介紹
react-i18next是基于i18next的一款強(qiáng)大的國(guó)際化框架,可以用于react和react-native應(yīng)用,以下是react-i18next一些特點(diǎn):
- 基于i18next不僅限于react,學(xué)一次就可以用在其它地方
- 提供多種組件在hoc、hook和class的情況下進(jìn)行國(guó)際化操作
- 適合服務(wù)端的渲染
- 歷史悠久,始于2011年比大多數(shù)的前端框架都要年長(zhǎng)
- 因?yàn)闅v史悠久所以更成熟,目前還沒(méi)有i18next解決不了的國(guó)際化問(wèn)題
- 有許多插件的支持,比如可以用插件檢測(cè)當(dāng)前系統(tǒng)的語(yǔ)言環(huán)境,從服務(wù)器或者文件系統(tǒng)加載翻譯資源
準(zhǔn)備開(kāi)始
- 安裝依賴
# npm
$ npm install react-i18next i18next --save
# 如果需要檢測(cè)當(dāng)前瀏覽器的語(yǔ)言或者從服務(wù)器獲取配置資源可以安裝下面依賴
$ npm install i18next-http-backend i18next-browser-languagedetector --save
-
在locales目錄下添加多語(yǔ)言配置文件,文件類型為json。
E5277497-767F-43AF-9E38-599F5DAD2FD9.png
#en.json
{
"歡迎使用 react-i18next": "Welcome to react using react-i18next",
"切換語(yǔ)言": "change language",
"切換到中文": "change to Chinese",
"切換到英文": "change to English",
"切換到日文": "change to Japenese",
"methods": {
"renderProps": "change language with render props",
"hook": "change language with hook",
"hoc": "change language with hoc"
}
#ja.json
{
"歡迎使用 react-i18next": "ご利用を歓迎する react-i18next",
"切換語(yǔ)言": "言語(yǔ)を切り替える",
"切換到中文": "中國(guó)語(yǔ)に切り替える",
"切換到英文": "英文に切り替える",
"切換到日文": "日本語(yǔ)に切り替える",
"methods": {
"renderProps": "renderProps方式で言語(yǔ)を変換する",
"hook": "hook方式で言語(yǔ)を変換する",
"hoc": "hoc方式で言語(yǔ)を変換する"
}
}
#zh.json
{
"methods": {
"renderProps": "用renderProps轉(zhuǎn)換",
"hook": "用hook轉(zhuǎn)換",
"hoc": "用hoc轉(zhuǎn)換"
}
}
- 初始化配置,新建i18n.js文件,對(duì)i18n進(jìn)行初始化操作及插件配置
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import resources from './locales/resources'
// don't want to use this?
// have a look at the Quick start guide
// for passing in lng and translations on init
i18n
// load translation using http -> see /public/locales (i.e. https://github.com/i18next/react-i18next/tree/master/example/react/public/locales)
// learn more: https://github.com/i18next/i18next-http-backend
.use(Backend)
// detect user language
// learn more: https://github.com/i18next/i18next-browser-languageDetector
.use(LanguageDetector)
// pass the i18n instance to react-i18next.
.use(initReactI18next)
// init i18next
// for all options read: https://www.i18next.com/overview/configuration-options
.init({
fallbackLng: 'zh',
lng: 'zh',
debug: true,
resources: resources,
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
}
});
export default i18n;
- 將i18n.js文件引入到入口文件中App.js
import React from 'react';
import './i18n';
export default class App extends React.Component {
render() {
return (
<div>
{/* 省略...... */}
</div>
)
}
}
- 切換語(yǔ)言
<Button onClick={() => i18n.changeLanguage('zh')}>{t('切換到中文')}</Button>
- 通過(guò)RenderProps的方式國(guó)際化組件
import React from 'react';
import { Translation } from 'react-i18next';
const Index = () => {
return (
<Translation>
{
t => {
return (
<div style={{background: 'red', margin: 20, color: 'white', width: 200}}>
{t('methods.renderProps')}
</div>
);
}
}
</Translation>
)
}
export default Index;
- 在hook中使用react-i18next國(guó)際化
import React from 'react';
import { useTranslation } from 'react-i18next';
const Index = () => {
const { t } = useTranslation();
return (
<div style={{ background: 'yellow', margin: 20, width: 200 }}>
{t('methods.hook')}
</div>
)
}
export default Index;
- 使用高階組件(Hoc)的方式處理國(guó)際化
import React from 'react';
import { withTranslation } from 'react-i18next';
const Index = ({ t }) => {
return (
<div style={{ background: 'blue', margin: 20, color: 'white', width: 200 }}>
{t('methods.hoc')}
</div>
);
}
export default withTranslation()(Index);
React-intl
介紹
React-intl通過(guò)context api的方式為react項(xiàng)目提供多語(yǔ)言支持,可以對(duì)文本、數(shù)字、日期等進(jìn)行翻譯。以下代碼以組件的方式進(jìn)行國(guó)際化操作。
準(zhǔn)備開(kāi)始
- 安裝依賴
npm i -S react-intl
- 在locales文件夾中創(chuàng)建多語(yǔ)言資源文件,與i18next不同的是,資源文件的類型為js類型,導(dǎo)出的是一個(gè)對(duì)象,因?yàn)榉g的文本中可以存在變量靈活替換,比如代碼中的 { value }。
1603187400393.jpg
export default {
welcome: "Welcome to use react-intl",
changeToChinese: "change to Chinese",
changeToEnglish: "change to English",
changeToJapanese: "change to Japanese",
description: "description",
value: "use value {value}",
function: "function as the child"
}
export default {
welcome: "react?intlの使用を歓迎します",
changeToChinese: "中國(guó)語(yǔ)に切り替える",
changeToEnglish: "英文に切り替える",
changeToJapanese: "日本語(yǔ)に切り替える",
description: "描寫",
value: "値を使う(value) {value}",
function: "関數(shù)はサブセットとする"
}
- 初始化,將入口文件的組件App包裹在IntlProvider組件中。
import React from 'react';
import { IntlProvider, FormattedMessage } from 'react-intl';
import App from './App';
export default class Index extends React.Component {
render() {
const { locale } = this.state;
return (
<IntlProvider locale={locale} messages={this.messages[locale]}>
<App >
</IntlProvider>
)
}
}
- 切換語(yǔ)言,react-intl沒(méi)有提供切換語(yǔ)言的接口,所以需要開(kāi)發(fā)者手動(dòng)完成。以下是通過(guò)按鈕點(diǎn)擊修改state中語(yǔ)言的類型來(lái)切換語(yǔ)言的。
import React from 'react';
import { IntlProvider, FormattedMessage } from 'react-intl';
import { Button, Row, Col } from 'antd';
import zh from './locales/zh';
import en from './locales/en';
import ja from './locales/ja';
export default class Index extends React.Component {
messages = {
zh: zh,
en: en,
ja: ja
}
state = {
locale: 'zh'
}
render() {
return (
<IntlProvider locale={this.state.locale} messages={this.messages[this.state.locale]}>
<Row gutter={16} style={{ margin: 20 }}>
<Col>
<Button onClick={() => this.setState({ locale: 'zh' })}>
<FormattedMessage id='changeToChinese' />
</Button>
</Col>
<Col>
<Button onClick={() => this.setState({ locale: 'en' })}>
<FormattedMessage id='changeToEnglish' />
</Button>
</Col>
<Col>
<Button onClick={() => this.setState({ locale: 'ja' })}>
<FormattedMessage id='changeToJapanese' />
</Button>
</Col>
</Row>
</IntlProvider>
)
}
}
- 與react-i18next不同,react-intl只提供了組件(文本組件 FormattedMessage)和api(intl.formatMessage())的方式來(lái)進(jìn)行國(guó)際化處理,通過(guò)id獲取對(duì)應(yīng)的語(yǔ)言文本進(jìn)行國(guó)際化。
<div style={{ margin: 20, background: 'red', color: 'white', width: 233 }}>
<FormattedMessage id='welcome' />
</div>
- 使用缺省消息,如果當(dāng)前的id在當(dāng)前語(yǔ)言的資源文件中沒(méi)有對(duì)應(yīng)的配置,那就會(huì)顯示defaultMessage中的文本。
<div style={{ margin: 20, background: 'purple', color: 'white', width: 233 }}>
<FormattedMessage id='defaultMessage' defaultMessage='使用缺省消息' />
</div>
- 使用描述
<div style={{ margin: 20, background: 'black', color: 'white', width: 233 }}>
<FormattedMessage id='description' defaultMessage='描述' description='使用描述' />
</div>
- 通過(guò)value傳值
<div style={{ margin: 20, background: 'blue', color: 'white', width: 233 }}>
<FormattedMessage id='value' values={{ value: 233 }} />
</div>
- 函數(shù)作為FormattedMessage的子組件,可以通過(guò)這種方式來(lái)傳遞國(guó)際化的組件。
<div style={{ margin: 20, background: 'green', color: 'white', width: 233 }}>
<FormattedMessage id='function'>
{
txt => (
<div style={{fontSize: 30}}>{txt}</div>
)
}
</FormattedMessage>
</div>
對(duì)比
- React-i18next初始化的時(shí)候需要將初始化配置放置在初始化文件(i18n.js)中,然后將初始化文件(i18n.js)通過(guò)import的方式引入到入口文件中即可。當(dāng)然也可以通過(guò)I18nextProvider將i18n往下傳遞到各子組件。React-intl提供的是context api初始化方案,需要將初始化配置放在IntlProvider組件中,并且將入口文件的組件(如<App />)作為IntlProvider的子組件來(lái)使用;
- React-i18next提供了切換語(yǔ)言的接口(i18n.changeLanguage),react-intl則需要對(duì)切換做一些封裝的工作;
- React-i18next提供了三種方式進(jìn)行國(guó)際化操作(render props、hook和hoc), react-intl提供了api(intl.formatMessage())和組件(<FormattedMessage />)兩種方式進(jìn)行國(guó)際化;
- React-i18next的語(yǔ)言資源文件為json格式,react-intl為js格式,同時(shí)支持變量傳值;
- React-i18next有很多插件可以使用比如檢測(cè)當(dāng)前系統(tǒng)語(yǔ)言,從后端獲取數(shù)據(jù)等;
- React-intl除文本翻譯外還提供日期、時(shí)間和金額的國(guó)際化支持;
參考文檔
- https://react.i18next.com/
- https://formatjs.io/
- https://blog.bitsrc.io/react-i18n-how-to-internationalize-your-react-application-3a12bba5a980

