基于create-react-app官方脚手架搭建dva模式的项目(三)

接上一篇:https://blog.csdn.net/xw505501936/article/details/80625613

项目配置到这里之后,接下来就需要处理以下配置了:

  • 国际化
  • store的数据存储结构

 国际化和store数据结构的设计:

此处采用immutable数据格式(immutable一款很棒的数据操作工具,此处不做详解,有兴趣的同学可自行学习),把数据存于model,同样国际化的判断参数定为: i18n 存于app的model中,取值来源于浏览器的本地缓存localStorage用户若设置了某种语言,则存在这里,用户下次访问系统,也依然能唤起上次所选中的语言,当初次访问时,语言默认先取自浏览器,若依然取不到则默认咱们的中文。

这里我们只实现 中文,英文,繁体 三种语言的国家化即可,因为引用了antd组件库,故此处国际化部分包括两部分,

(1) antd库的国际化,比如antd中的固定组件里的 ‘确定,OK’‘下一页,Next Page’等,antd官网有详细说明

(2) 业务框架自己的国际化,比如“用户名,Username”,“密码,Password”等,这里采用react-intl国际化组件实现


1 安装immutable和react-intl

cnpm i immutable react-intl --save

修改models目录下的app.js中引入import {Map} from 'immutable'; 修改如下:

import {Map} from 'immutable';

const initState = Map({
    i18n: 'zh_CN'
})

export default {

    namespace: 'app',
  
    state:initState,
  
    subscriptions: {
      
    },
  
    effects: {

      * changeLang ({
        payload: {value},
        }, { put }) {
            yield put({ type: 'updateLang', payload: {value}});
        },
        
    },
  
    reducers: {
        updateLang (state,{payload:{value}}) {
            return state.set('i18n',value);
        },
    },
  
  };
  

修改routes目录下BBB.js,如下:

import React, { Component } from 'react';
import {connect} from 'dva';
import { Link } from 'dva/router';
import {Row, Col, Dropdown, Menu, Button} from 'antd'

class BBB extends Component {

  changeLang=(e)=>{
    const {dispatch} = this.props;
    dispatch({
      type:'app/changeLang',
      payload:{
        value:e.key
      }
    })
  }

  render() {
    const {i18n} = this.props;
    const menu=(
      <Menu 
        onClick={this.changeLang}
        selectedKeys={[i18n]}
      >
      <Menu.Item key="zh_CN">
        中文
      </Menu.Item>
      <Menu.Item key="en_US">
        英文
      </Menu.Item>
      <Menu.Item key="zh_HK">
        繁体
      </Menu.Item>
    </Menu>
    )

    return (
      <div>
        <p>
          BBB页
        </p>
        <Link to={'/aaa'}>去AAA页面</Link>
        <br />
        <Link to={'/ccc'}>去CCC页面</Link>

        <Row>
          <Col offset={2}>
            <Dropdown trigger={['click']} overlay={menu}>
              <Button>{i18n=='zh_CN'?'中文':i18n=='en_US'?'英文':'繁体'}</Button>
            </Dropdown>
          </Col>
        </Row>
         
      </div>
    );
  }
}

export default connect(({
  app
})=>({
  i18n:app.get('i18n')
}))(BBB)

以上修改主要功能:

app.js 增加初始语言参数i18n,增加effects和reducers方法,用于接收语言切换的action,并存储选中的key值

BBB.js 增加connect使当前组件接入store数据,增加切换组件,用于点击切换语言,并dispatch一个action给app/changeLang,触发修改修改model数据

效果如图:




到这里,数据层面的流程已经打通,接下来处理国际化逻辑,国际化组件必然放于跟组件或最外层组件包裹,这样全局均可以使用并生效

2 src目录下新建文件locale.js,此组件仅用于接入国际化使用:

import {connect} from 'dva';
import React from 'react';
import { LocaleProvider } from 'antd' //antd国际化组件
import {IntlProvider} from 'react-intl' //业务文案的国际化组件
import {ANT_LANGPACKAGE, LANGPACKAGE} from './locales';


const Locale=({ children,i18n })=>{

  return (
    <LocaleProvider locale={ANT_LANGPACKAGE[i18n]}>
      <IntlProvider
        locale={i18n}
        messages={LANGPACKAGE[i18n]}
      >
        {children}
      </IntlProvider>
    </LocaleProvider>
  );
}

export default connect(({
  app
})=>({
  i18n:app.get('i18n')
}))(Locale)

3 src目录下,新建locales目录,里面新建index.js文件,此目录用于存放所有项目的文案国际化文件

其中index.js代码:

import {addLocaleData} from 'react-intl';
import en from 'react-intl/locale-data/en';
import zh from 'react-intl/locale-data/zh';
import zgh from 'react-intl/locale-data/zgh';
import en_US_ant from 'antd/lib/locale-provider/en_US';
import zh_CN_ant from 'antd/lib/locale-provider/zh_CN';
import zh_HK_ant from 'antd/lib/locale-provider/zh_TW';

const zh_CN={
    "App.username": "用户名",
    "App.password": "密码"
}
const en_US={
    "App.username": "Username",
    "App.password": "Password"
}
const zh_HK={
    "App.username": "用戶名",
    "App.password": "密碼"
}


addLocaleData([
  ...en, 
  ...zh, 
  ...zgh,
  {locale: "en_US", parentLocale: "en"},
  {locale: "zh_CN", parentLocale: "zh"},
  {locale: "zh_HK", parentLocale: "zgh"},
]);



export const ANT_LANGPACKAGE = {
  en_US: en_US_ant,
  zh_CN: zh_CN_ant,
  zh_HK: zh_HK_ant
}

export const LANGPACKAGE = {
  en_US,
  zh_CN,
  zh_HK
}



此时项目目录如下:



4 修改router.js文件,包裹组件<Locale>

import React from 'react';
import { Router, Route, Switch } from 'dva/router';
import dynamic from 'dva/dynamic'
import Locale from './locale'
import {config} from './utils'
const { menuGlobal } = config

function RouterConfig({ history, app }) {

  return (
    <Locale>
      <Router history={history}>
        <Switch>
          {
            menuGlobal.map(({path,...dynamics},index)=>(
              <Route
                key={index} 
                path={path} 
                exact 
                component={dynamic({
                  app,
                  ...dynamics
                })} 
              />
            ))
          }
        </Switch>
      </Router>
    </Locale>
  );
}

export default RouterConfig;


5 修改BBB.js 增加injectIntl国际化的接入,并增加三个示例,两个antd组件 分页和日期,一个业务文案 用户名和密码

import React, { Component } from 'react';
import {connect} from 'dva';
import { Link } from 'dva/router';
import {Row, Col, Dropdown, Menu, Button, Pagination, Calendar} from 'antd'
import { injectIntl } from 'react-intl';

class BBB extends Component {

  changeLang=(e)=>{
    const {dispatch} = this.props;
    dispatch({
      type:'app/changeLang',
      payload:{
        value:e.key
      }
    })
  }

  render() {
    const {i18n, intl:{formatMessage}} = this.props;
    const menu=(
      <Menu 
        onClick={this.changeLang}
        selectedKeys={[i18n]}
      >
      <Menu.Item key="zh_CN">
        中文
      </Menu.Item>
      <Menu.Item key="en_US">
        英文
      </Menu.Item>
      <Menu.Item key="zh_HK">
        繁体
      </Menu.Item>
    </Menu>
    )

    return (
      <div>
        <p>
          BBB页
        </p>
        <Link to={'/aaa'}>去AAA页面</Link>
        <br />
        <Link to={'/ccc'}>去CCC页面</Link>

        <Row>
          <Col offset={2} span={10}>
            <Dropdown trigger={['click']} overlay={menu}>
              <Button>{i18n=='zh_CN'?'中文':i18n=='en_US'?'英文':'繁体'}</Button>
            </Dropdown>
          </Col>
          <Col span={12}>
            <p>{formatMessage({id:'App.username'})}</p>
            <p>{formatMessage({id:'App.password'})}</p>
            <div>
              <Pagination defaultCurrent={1} total={20} showSizeChanger />
              <Calendar fullscreen={false}  />
            </div>
          </Col>
        </Row>
         
      </div>
    );
  }
}

export default connect(({
  app
})=>({
  i18n:app.get('i18n')
}))(injectIntl(BBB))

好了,保存文件,重启运行npm start,跑起来咯!





项目已然OK,但是需知,复杂的项目,国际化文案很庞大,我们需要把翻译文件提出来,不能放于locales/index.js文件中。

6 在locales目录下新建三个目录:en_US zh_CN zh_HK 用于存放翻译文件

7 在中英繁对应目录下创建如下文件:


以zh_CN目录为例

index.js代码:

import App from './app.json'
import Aaa from './aaa.json'
import Bbb from './bbb.json'

const document = {
  ...App,
  ...Aaa,
  ...Bbb,
}

export default document;

app.json代码:

{
  "App.username": "用户名",
  "App.password": "密码"
}

aaa.json代码:

{
  "Aaa.title": "A标题"
}

bbb.json代码:

{
  "Bbb.title": "B标题"
}

同样zh_HK和en_US目录页一样:



8 修改locales目录下index.js文件:

import {addLocaleData} from 'react-intl';
import en from 'react-intl/locale-data/en';
import zh from 'react-intl/locale-data/zh';
import zgh from 'react-intl/locale-data/zgh';
import en_US_ant from 'antd/lib/locale-provider/en_US';
import zh_CN_ant from 'antd/lib/locale-provider/zh_CN';
import zh_HK_ant from 'antd/lib/locale-provider/zh_TW';
import zh_CN from './zh_CN';
import en_US from './en_US';
import zh_HK from './zh_HK';

addLocaleData([
  ...en, 
  ...zh, 
  ...zgh,
  {locale: "en_US", parentLocale: "en"},
  {locale: "zh_CN", parentLocale: "zh"},
  {locale: "zh_HK", parentLocale: "zgh"},
]);


export const ANT_LANGPACKAGE = {
  en_US: en_US_ant,
  zh_CN: zh_CN_ant,
  zh_HK: zh_HK_ant
}

export const LANGPACKAGE = {
  en_US,
  zh_CN,
  zh_HK
}

修改BBB.js文件:

import React, { Component } from 'react';
import {connect} from 'dva';
import { Link } from 'dva/router';
import {Row, Col, Dropdown, Menu, Button, Pagination, Calendar} from 'antd'
import { injectIntl } from 'react-intl';

class BBB extends Component {

  changeLang=(e)=>{
    const {dispatch} = this.props;
    dispatch({
      type:'app/changeLang',
      payload:{
        value:e.key
      }
    })
  }

  render() {
    const {i18n, intl:{formatMessage}} = this.props;
    const menu=(
      <Menu 
        onClick={this.changeLang}
        selectedKeys={[i18n]}
      >
      <Menu.Item key="zh_CN">
        中文
      </Menu.Item>
      <Menu.Item key="en_US">
        英文
      </Menu.Item>
      <Menu.Item key="zh_HK">
        繁体
      </Menu.Item>
    </Menu>
    )

    return (
      <div>
        <p>
          BBB页
        </p>
        <Link to={'/aaa'}>去AAA页面</Link>
        <br />
        <Link to={'/ccc'}>去CCC页面</Link>

        <Row>
          <Col offset={2} span={10}>
            <Dropdown trigger={['click']} overlay={menu}>
              <Button>{i18n=='zh_CN'?'中文':i18n=='en_US'?'英文':'繁体'}</Button>
            </Dropdown>
          </Col>
          <Col span={12}>
            <p>{formatMessage({id:'App.username'})}</p>
            <p>{formatMessage({id:'App.password'})}</p>
            <p>{formatMessage({id:'Aaa.title'})}</p>
            <p>{formatMessage({id:'Bbb.title'})}</p>
            <div>
              <Pagination defaultCurrent={1} total={20} showSizeChanger />
              <Calendar fullscreen={false}  />
            </div>
          </Col>
        </Row>
         
      </div>
    );
  }
}

export default connect(({
  app
})=>({
  i18n:app.get('i18n')
}))(injectIntl(BBB))

OK,重启刷新,查看页面:



项目至此,基础架构已搭建完毕,剩下的就是布局Layout和公用组件components的封装了,比如业务组件转化器,业务组件过滤器等等。

给大家推荐几个常用并且好用的工具,也许对你有帮助,可自行网上查阅资料,研究使用:

path-to-regexp

react-helmet

classnames

moment


目前的项目基础已经形成,可以说非常干净的一个流程,没有复杂化的东西,希望对你有所帮助!

Thank!


猜你喜欢

转载自blog.csdn.net/xw505501936/article/details/80625626