這是我參與更文挑戰的第4天,活動詳情查看: 更文挑戰前端
簡單說就是翻譯一下,切換中英文,但毫不是把整個語言包放進去,那可不必,只是按需處理便可,那麼如何制定一個優雅的國際化方案,纔是須要重點研究的。react
react-intl
庫react-intl
是一個 Yahoo 公司出品的,有興趣能夠自行了解一下。git
yarn add react-intl
複製代碼
...
import { IntlProvider } from "react-intl";
...
class Root extends Component {
render() {
const {
global: { locale },//可枚舉的值爲"zh"和"en"
} = this.props;
return (
<IntlProvider locale={locale} messages={language.getData()[locale]}> <App /> </IntlProvider>
);
}
}
複製代碼
分析:github
IntlProvider
包裹一下。locale
: 當前語言環境 。messages
:按需配置的語言包(下面重點分析)。至此基本裝配夠用了,其餘「高玩」的配置有興趣的能夠繼續探究。shell
我們以 login 爲例:markdown
en-US
:app
const login = {
"login.title": "User Center",
"login.username": "please enter username",
"login.usernameEmpty": "username cannot be empty!",
"login.maxLength": "username is no more than 100 characters",
};
export default login;
複製代碼
zh-CN
:ide
const login = {
"login.title": "用戶中心",
"login.username": "請輸入用戶名",
"login.usernameEmpty": "用戶名不能爲空!",
"login.maxLength": "用戶名不得多於100個字符",
};
export default login;
複製代碼
...
/* 引入 */
import { injectIntl } from "react-intl";
...
/* 注入專屬國際化數據 */
@injectIntl
class Login extends React.Component {
constructor(props) {
super(props);
const {
intl: { formatMessage },
} = this.props;
/* 使用 */
message.warning(formatMessage({ id: "login.maxLength" }))
}
...
}
複製代碼
分析:函數
en-US
和zh-CN
目錄下配置兩個結構相同,值不一樣的文件。react-intl
提供的injectIntl
高階組件對所在組件進行包裝,從而能夠直接經過 props 得到國際化數據intl
。intl
中得到formatMessage
,傳入片斷id
,就能得到翻譯的值。但有弊端:oop
配置上要配置兩組大致同樣就是值不一樣的數據,一是重複了,二是還得人工對仗着寫,這就很噁心了。
全部頁面都能「用」一個總體🤔️???這很差維護啊,權限沒控制好啊,頁面對翻譯片斷的依賴會愈來愈混亂,最好仍是借鑑 mobx 這種倉庫的思想,你依賴啥我給你啥,不依賴就不給你。
每次使用我都須要formatMessage
翻譯,文件很少片斷很少還行,要是都多呢?那豈不是要寫不少行,每次 render 都去執行翻譯函數,慄 🌰:
...
render() {
const {
intl: { formatMessage },
} = this.props;
const { codeImage } = this.state;
const usernamePlaceholder = formatMessage({ id: "login.username" });
const usernameEmpty = formatMessage({ id: "login.usernameEmpty" });
const passwordPlaceholder = formatMessage({ id: "login.password" });
const passwordEmpty = formatMessage({ id: "login.passwordEmpty" });
const codePlaceholder = formatMessage({ id: "login.code" });
const maxLength = formatMessage({ id: "login.maxLength" });
const pwdMaxLength = formatMessage({ id: "header_pwdMaxLength" });
const codeEmpty = formatMessage({ id: "login.codeEmpty" });
return (
<div className="loginpagewrap"> ... </div>)
}
...
複製代碼
這明顯不合理啊,得想個轍啊。
首先針對傳統模式各個環節進行優化。
import BaseIntl from "./baseIntl";
let config = {
light_searchSelect: {
en: "searchSelect",
zh: "聯想select",
},
light_baseSelect: {
en: "baseSelect",
zh: "基本select",
},
light_computeNum: {
en: "computeNum",
zh: "計算值",
},
};
export default new BaseIntl({ config });
複製代碼
一個文件解決,這多好,而且經過baseIntl
進行擴展,主要爲其補充了共用的翻譯片斷,這樣大大的解決了重複翻譯片斷的問題。
react-intl
定製一個屬於咱們的高階組件intlHoc
作這個高階組件前,得先明確咱們不是破壞react-intl
,而是擴展 ta。
直接上代碼:
import React from "react";
import { inject, observer } from "mobx-react";
import { injectIntl } from "react-intl";
import language from "SRC/language";
function hoc(id) {
return function (WrappedComponent) {
@injectIntl
@inject("global")
class IntlHoc extends React.Component {
constructor(props) {
super(props);
const {
global: { locale },
} = this.props;
this.state = {
formatedMessage: this.formatMessage(),
localeFlag: locale,
};
}
formatMessage() {
const { intl } = this.props;
const { formatMessage } = intl;
let targetArr = language.getIntlById(id);
let trmpArr = {};
for (let key in targetArr) {
trmpArr[key] = formatMessage({ id: key });
}
return trmpArr;
}
shouldComponentUpdate() {
const {
global: { locale },
} = this.props;
if (this.state.localeFlag !== locale) {
this.setState({
localeFlag: locale,
formatedMessage: this.formatMessage(),
});
}
return true;
}
render() {
const { formatedMessage } = this.state;
const props = Object.assign({}, this.props, {
intlData: formatedMessage,
});
return <WrappedComponent {...props} />;
}
}
return IntlHoc;
};
}
export default hoc;
複製代碼
而後代替injectIntl
進行包裝,慄 🌰:
...
import injectInternational from "COMMON/hocs/intlHoc";
...
@injectInternational("light")
class TempEdit extends Component {
const {
intlData
} = this.props;
render(){
return <div>{intlData.light_editting}</div>
}
}
複製代碼
分析:
formatMessage
翻譯的方式,並將其在高階組件內部統一作好以後,再將數據注入到組件props中,經過intlData獲取,直接經過「.」的方式就能得到翻譯,既簡化了流程又避免了函數的多餘執行。國際化是一件若是你不在乎ta,ta會讓你很頭疼,很痛苦的事情,像是一種習慣,仍是早養成爲好,等最後再去弄,你會感嘆怎麼這麼多東西要翻譯,因此一套整合好的國際化解決方案就頗有用。