这是我参与更文挑战的第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会让你很头疼,很痛苦的事情,像是一种习惯,仍是早养成为好,等最后再去弄,你会感叹怎么这么多东西要翻译,因此一套整合好的国际化解决方案就颇有用。