react
的国际化方案,能够说是十分红熟了。react
react-intl
一用上,文本,日期、货币通通搞定。git
这里想和你们交流的并非如何使用 react-intl
,抑或如何在 redux
框架中去使用。github
而是一个小知识,如何在 placeholder
等属性中支持多语言,而且你只需按照 react-intl
的方式去维护多套语言库。redux
由于像 placeholder
, title
这种 HTML
自带的属性,组件库向来都是直接支持的,那么问题来了,使用 react-intl
中的 <FormattedMessage />
做为一个 Object
是没法用到这些属性中去的,那么咱们应该怎么去处理这个问题呢?框架
下面先说几个我搜索到的方法。dom
injectIntl()
是官方推荐的方法。<FormattedMessage />
的回调方法。以上两种方法均可以在这个issue中找到。ide
两种方式的实现原理很清晰。函数
方法一,强调使用高阶组件来处理这个问题,将 intl
注入到组件的 props
中,最后使用 intl.formatMessage
来解决问题。学习
方法二,很巧妙的利用到了 <FormattedMessage />
组件的返回值,函数式的渲染了自身的子组件。this
这两种思路当然都有可取之处,可是也有相应的问题。
injectIntl()
若是没有从全局层面出发,去封装的这种只是用于渲染的高阶组件,带来的成本,可想而知。
举个例子,咱们有时候会封装一些本身的基础业务组件 BaseApp
,他们自己并无render方法,在不一样权限的客户访问时,实现不一样的派生类( StaffApp
, CustomerApp
),对基础业务组件进行调用。
class BaseApp extends Component {
renderPersonInfo() {}
renderDataAnalytical() {}
renderTasks() {}
}
class StaffApp extends BaseApp {
render() {
return (
{
this.renderPersonInfo(),
this.renderDataAnalytical()
}
)
}
}
class CustomerApp extends BaseApp {
render() {
return (
{
this.renderPersonInfo(),
this.renderTasks()
}
)
}
}
复制代码
假设这个时候咱们对 BaseApp
进行 injectIntl
,那么本来能够继承的方法,就所有失效了。因此咱们必须对派生类进行 injectIntl
, 至关于,原本要作一次的事情,作了 N
次。
固然,咱们能够把 BaseApp
中用到 placeholder
的组件,单独的抽出来,进行 injectIntl
,不失为一种解决方案。
因此虽然 injectIntl
是把好刀,可是用得好,用很差,就要看本身对整个项目的理解了。
抛开这么写,究竟是否优美不谈。
最大的问题,仍是带来了没必要要的 dom
结构,由于 <FormattedMessage />
组件是会渲染 <span />
标签的。
想象下你的 input
组件外面还包了一个 span
是否是瑟瑟发抖呢。
基于上述状况,我认为以上两种方法,不太适合目前的项目,那就是要本身造轮子啦。
开心,又能够本身造轮子啦。
先亮代码
const intl = {
lang: {}
};
intl.formatMessage = (props) => {
let message = intl.lang[props.id] || props.defaultMessage || props.id;
if (!props.values) return message;
const keys = Object.keys(props.values);
for (let i = 0, l = keys.length; i < l; i++) {
const key = keys[i];
message = message.replace(new RegExp(`{${key}}`, "g"), props.values[key]);
}
return message;
}
export default intl;
复制代码
原理比较简单,两步。
程序初始化的时候,对 intl.lang
赋值,同 react-intl
。
利用 props
中的 id
和 values
属性,获取值并进行替换,返回真正的值。
使用方法:
<Input
value={showName}
// placeholder="支持(1-10)位中文、英文与数字"
placeholder={intl.formatMessage({id: "intl.showName.placeholder"})}
onChange={this.handleNameChange.bind(this)}
/>
复制代码
-----------------------分割线-----------------------
粘贴一段项目中的实现
redux Provider
和 react-intl IntlProvider
并无冲突,能够直接嵌套使用。
动态切换语言,我这里的思路是把ReactDOM.render
抽成一个方法,切换的使用再次调用就能够了。仅供参考,可能有更好的思路。
效果:
图中部分字段还未翻译,故切换时没有变动。