zoukankan      html  css  js  c++  java
  • 02 基于umi搭建React快速开发框架(国际化)

    前言

    之前写过一篇关于React的国际化文章,主要是用react-intl库,雅虎开源的。react-intl是用高阶组件包装一层来做国际化。
    基于组件化会有一些问题,比如在一些工具方法中需要国际化,就需要自己去实现了。在umi-react快速开发框架我们采用
    react-intl-universal库来实现,不仅支持组件化调用,也支持动态调用,实现国际化。

    react-intl-universal 用法

    1. 安装
    ```
      npm install react-intl-universal --save
    ```
    
    1. 初始化
      在以下示例中,我们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>
            );
          }
      
        }
      
    2. 调用

      • 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项目中加入国际化

    1. 在根目录新建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: '退出登录'
          }
        }
      ```
    
    1. 在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,
              };
            },
          },
        };
      
      
    2. 在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;
      
    3. 在 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={{  100 }}
                  onChange={this.onLocaleChange}>
                  <Option value='zh_CN'>中文</Option>
                  <Option value='en_US'>English</Option>
                </Select>
              </div>
            </div>
          )
        }
      }
      
      export default Header;
      
      
    4. 到此我们的系统国际化就可以用了。我们把登陆页面国际化完善起来。这要调用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

  • 相关阅读:
    怎样在delphi中实现控件和窗体的拖拽
    Ecshop出现问题 includeslib_main.php on line 1329 includeslib_base.php on line
    Scrollbox的滚动条事件scrollbar事件的处理(Lazarus)
    TControl.WMLButtonUp的inherited的作用——是为了给子类控件新的处理消息的机会
    信号槽的被连接几次,就会执行几次(有空要仔细研究connect的各种用法)
    追踪CM_CONTROLCHANGE消息的产生和执行过程,可以较好的领会VCL的思想(就是到处通知,但耦合性很弱)
    TControl的显示函数(5个非虚函数,4个虚函数)和三个例子的执行过程(包括SetParent的例子)
    js广告轮询效果
    TWinControl的刷新过程(5个非虚函数,4个覆盖函数,1个消息函数,默认没有双缓冲,注意区分是TCustomControl还是Windows原生封装控件,执行流程不一样)
    Delphi控件的透明与不透明(要挨个解释一下原因),对InvalidateControl的关键理解
  • 原文地址:https://www.cnblogs.com/qiaojie/p/9673609.html
Copyright © 2011-2022 走看看