02 基于umi搭建React快速开发框架(国际化)
前言
之前写过一篇关于React的国际化文章,主要是用react-intl库,雅虎开源的。react-intl是用高阶组件包装一层来做国际化。
基于组件化会有一些问题,比如在一些工具方法中需要国际化,就需要自己去实现了。在umi-react快速开发框架我们采用
react-intl-universal库来实现,不仅支持组件化调用,也支持动态调用,实现国际化。
react-intl-universal 用法
- 安装
```
npm install react-intl-universal --save
```
-
初始化
在以下示例中,我们intl使用app locale data(locales)初始化并确定动态使用哪个区域设置(currentLocale).
然后intl.get(…)用来获取国际化的消息import intl from \'react-intl-universal\'; const locales = { "en-US": require(\'./locales/en-US.js\'), "zh-CN": require(\'./locales/zh-CN.js\'), }; class App extends Component { state = {initDone: false} componentDidMount() { this.loadLocales(); } loadLocales() { // init method will load CLDR locale data according to currentLocale // react-intl-universal is singleton, so you should init it only once in your app intl.init({ currentLocale: \'en-US\', // TODO: determine locale here locales, }) .then(() => { // After loading CLDR locale data, start to render this.setState({initDone: true}); }); } render() { return ( this.state.initDone && <div> {intl.get(\'SIMPLE\')} </div> ); } }
-
调用
-
HTML Message (HTML 消息)
locale data:
{ "TIP": "This is <span style=\'color:red\'>HTML</span>" }
js code:
intl.getHTML(\'TIP\');
-
Default Message (设置默认消息)
js code:intl.get(\'not-exist-key\').defaultMessage(\'default message\')
也可以用简写设置默认值
intl.get(\'not-exist-key\').d(\'default message\')
getHTML 也支持默认值
intl.getHTML(\'not-exist-key\').d(<div>hello</div>)
-
Message With Variables (消息添加变量)
locale data:
{ "HELLO": "Hello, {name}. Welcome to {where}!" }
js code:
intl.get(\'HELLO\', {name:\'Tony\', where:\'Alibaba\'})
-
在umi-react项目中加入国际化
-
在根目录新建locales文件夹, 添加locale描述文件
en_US.js 文件export default { user: { login: { loginBtn: \'login\', placeholderName: \'Please input user name\', placeholderPws: \'Please input password\', forgetPwd: \'Forget password\', remember: \'Remember me\', }, logout: \'logout\' } }
zh_CN.JS 文件
```
export default {
user: {
login: {
loginBtn: \'登录\',
placeholderName: \'请输入用户名\',
placeholderPws: \'请输入密码\',
forgetPwd: \'忘记密码\',
remember: \'记住我\',
},
logout: \'退出登录\'
}
}
```
-
在global modle中添加初始化state和Effect(changeLocale)和reducers(setLocale)
import intl from \'react-intl-universal\'; import locales from \'../locales\'; import storage from \'utils/localStorage\'; const defaultState = { currLocale: storage.get(\'locale\') || \'zh_CN\', localeLoad: false, } export default { namespace: \'global\', state: defaultState, effects: { *changeLocale({ payload }, { call, put }) { const params = { currentLocale: payload, locales }; // 初始化国际化 yield intl.init(params); yield put({ type: \'setLocale\', payload: { currLocale: payload, localeLoad: true, } }); // 把当前国际化持久化到 localstorage 中 storage.add(\'locale\', payload); }, }, reducers: { setLocale(state, { payload }) { return { ...state, ...payload, }; }, }, };
-
在layouts index.js 中掉用changeLocale初始化国际化和antd组件国际化
import React, { Component } from \'react\' import BaseLayout from \'./baseLayout\'; import { LocaleProvider } from \'antd\'; import { connect } from \'dva\'; import zh_CN from \'antd/lib/locale-provider/zh_CN\'; import en_US from \'antd/lib/locale-provider/en_US\'; import { init } from \'./init\'; @connect(({global}) => { return { currLocale: global.currLocale, localeLoad: global.localeLoad, } }) class Index extends Component { constructor() { super(); init(); this.state = { initDone: false, } } componentDidMount() { const {dispatch, currLocale} = this.props; // 更改国际化 dispatch({ type: \'global/changeLocale\', payload: currLocale, }); } /** * 初始intl国际化和antd组件国际化 */ renderBody = () => { const {location: {pathname}, children, currLocale, localeLoad } = this.props; if (pathname === \'/login\') { return localeLoad && <React.Fragment> {children} </React.Fragment>; } return ( localeLoad && (<LocaleProvider locale={ currLocale === \'zh_CN\' ? zh_CN : en_US }> <BaseLayout {...this.props} /> </LocaleProvider>) ); } render() { return ( <React.Fragment> {this.renderBody()} </React.Fragment> ) } } export default Index;
-
在 src/baseLayout/header.js 添加更改国际化的 select
import React, { Component } from \'react\'; import { Avatar, Dropdown, Menu, Icon, Select } from \'antd\'; import { connect } from \'dva\'; import intl from \'react-intl-universal\'; import styles from \'./baseLayout.less\'; const Option = Select.Option; @connect(({user}) => { return { user: user.user } }) class Header extends Component { /** * 切换语言 */ onLocaleChange = (value) => { this.props.dispatch({ type: \'global/changeLocale\', payload: value, }) } render() { const {currLocale, user} = this.props; return ( <div className={styles.header}> <div className={styles.headerButton}> <Select defaultValue={currLocale} style={{ width: 100 }} onChange={this.onLocaleChange}> <Option value=\'zh_CN\'>中文</Option> <Option value=\'en_US\'>English</Option> </Select> </div> </div> ) } } export default Header;
-
到此我们的系统国际化就可以用了。我们把登陆页面国际化完善起来。这要调用
intl.get
方法import intl from \'react-intl-universal\'; @connect(({user}) => ({ loginErr: user.loginErr, })) @Form.create() class Login extends React.Component { render() { const { loginErr, form:{ getFieldDecorator } } = this.props; const intlLogin = intl.get(\'user.login.loginBtn\'); const intlUsername = intl.get(\'user.login.placeholderName\'); const intlPwd = intl.get(\'user.login.placeholderPws\'); const intlforgetPwd = intl.get(\'user.login.forgetPwd\'); const intlRemember = intl.get(\'user.login.remember\'); return ( <div className={styles.login}> { loginErr && <Alert style={{ marginBottom: \'20px\' }} message=\'用户名密码错误\' type=\'error\' showIcon />} <Form onSubmit={this.handleSubmit} className=\'login-form\'> <FormItem> {getFieldDecorator(\'name\', { rules: [ FormValid.require(intlUsername), ], })( <Input prefix={<Icon type=\'user\' style={{ color: \'rgba(0,0,0,.25)\' }} />} placeholder={intlUsername} /> )} </FormItem> <FormItem> {getFieldDecorator(\'password\', { rules: [ FormValid.require(intlPwd), ], })( <Input prefix={<Icon type=\'lock\' style={{ color: \'rgba(0,0,0,.25)\' }} />} type=\'password\' placeholder={intlPwd} /> )} </FormItem> <FormItem> {getFieldDecorator(\'remember\', { valuePropName: \'checked\', initialValue: true, })( <Checkbox>{intlRemember}</Checkbox> )} <a className=\'login-form-forgot\' href=\'\'>{intlforgetPwd}</a> <Button type=\'primary\' htmlType=\'submit\' className=\'login-form-button\'> {intlLogin} </Button> </FormItem> </Form> </div> ); } } export default Login;
结束语
国际化已经完成, 代码已放到github上,大家可以自行查看umi-react。如果觉得不错,请 start 一下
我建了一个QQ群,大家加进来,可以一起交流。群号 787846148