国际化
国际化的目的
- 让h5页面在不同的语言环境下打开, 使用相应的语言
- 奔驰大老板来中国出差旅游要用的,秘书给他在外国装好app来国内用(初心)
国际化的本质
- 根据语言来加载不同的json文件. json文件的内容是对各种文案和资源的配置.
国际化的语言判断(判断用户所属区域 或者 用户所选择语言)
- 入口 URL 附带相关参数(目前我们所选择的方案, 视业务而定)
- 通过 IP 地址进行判断
国际化的使用
- LocaleProvider 使用 React 的 context 特性,只需在应用外围包裹一次即可全局生效。
const args = getUrlParam();
const lang = args.lang || 'zh_CN';
const langFile = require(`./components/locale-provider/${lang}`).default;
<LocaleProvider locale={langFile}>
<Router history={history} routes={routes} />
</LocaleProvider>
- 编写语言配置
//zh_CN.js
export default {
locale: 'zh-cn',
global: {},
multi: {
text: '你好',
}
}
//en_US.js
export default {
locale: 'en-us',
// 全局: 比如 xx小时xx分钟 该怎么转成英文
global: {},
multi: {
text: 'hello',
}
}
- 将语言配置注入组件中
import React, { Component } from 'react';
import { injectLocale } from '@/components/locale-provider';
@injectLocale()
export default class MultiLang extends Component {
render() {
const { locale: { multi } } = this.props;
return <div className="multi">{multi.text}</div>;
}
}
// 等价于
//export default injectLocale()(MultiLang);
国际化的实现
- LocaleProvider(本质是高阶组件)
三种实现方式:
- 组合props
- 继承
- 以函数作为children
// locale-provider/index.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
export default class LocaleProvider extends Component {
getChildContext() {
return {
locale: { ...this.props.locale },
};
}
render() {
return React.Children.only(this.props.children);
}
}
LocaleProvider.propTypes = {
locale: PropTypes.object,
};
LocaleProvider.defaultProps = {
locale: PropTypes.object,
};
LocaleProvider.childContextTypes = {
locale: PropTypes.object,
};
export { default as injectLocale } from './injectLocale';
- injectLocale
import { Component, createElement } from 'react';
import PropTypes from 'prop-types';
import hoistStatics from 'hoist-non-react-statics';
export default function injectLocale(defaultLocale = {}) {
return function wrapWithLocale(WrappedComponent) {
class Inject extends Component {
static contextTypes = {
locale: PropTypes.object,
};
getLocale = () => {
const { locale } = this.context;
const localeFromContext = locale;
return {
...localeFromContext,
...defaultLocale,
};
}
addLocaleProps = () => ({ ...this.props, locale: this.getLocale() })
render() {
return createElement(WrappedComponent, this.addLocaleProps());
}
}
return hoistStatics(Inject, WrappedComponent);
};
}
题外话: decorator
什么是装饰器
- ES7的语法, Object.defineProperty的语法糖
- 对类和**方法(不能修饰函数)**进行修饰, 在不改变原有接口的前提下, 增强它的功能(想象一下钢铁侠, 在不改变他是个人的前提下, 给他装饰了很多武器, 使之无比强大)
- 装饰器的实现
@testable
class A {}
function testable(target) {
target.isTestable = true;
}
MyTestableClass.isTestable // true
// 等同于
class A {}
A = testable(A) || A;
class Person {
@readonly
name() { return `${this.first} ${this.last}` }
}
function readonly(target, name, descriptor){
// descriptor对象原来的值如下
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// };
descriptor.writable = false;
return descriptor;
}
readonly(Person.prototype, 'name', descriptor);
// 类似于
Object.defineProperty(Person.prototype, 'name', descriptor);
Tip: 这代码是几个月前写的, 同时这是我第一次发表文章, 大家给新人一点鼓励哈~