• React如何实现国际化?


    目录

     一、Redux准备工作

    commonTypes.js 

    commonActions.js 

    commonReducer.js 

    rootReducer.js 

     二、然后定义SelectLang组件

    index.js 

    index.less 

     三、创建语言包

    welcomeLocale.js 

     index.js

    四、使用

    react的入口文件

    App.js 

     welcome.js


    关于如何实现国际化,有很多方法,比如 vue-i18n  react-i18next  umi 中的 useIntl 等等,网上有很多的资料可以参看,今天不想使用这些库,于是乎打算自己写一个,期初设计是写两个语言文件,每次改变时把语言标识存 localStorage 中,然后刷新页面获取对应的语言文件,但是,本着提供良好的用户体验原则,否则了这一想法。于是想到了使用全局状态容器 Redux ,这样就可以在不刷新页面的情况下更新页面。尝试一下,效果还可以。以React为例,Vue实现也类似,具体代码如下:

     一、Redux准备工作

    为例防止文件过大,对Redux进行了拆分目录如下:

    commonTypes.js 

    1. // commonTypes.js
    2. export const SET_LANGUAGE = 'set_language'
    3. export const SET_LANGUAGE_OBJ = 'set_language_obj'

    commonActions.js 

    1. // commonActions.js
    2. import {
    3. SET_LANGUAGE,
    4. SET_LANGUAGE_OBJ
    5. } from '../actionTypes/commonTypes'
    6. export const setLanguage = payload => {
    7. return {
    8. type: SET_LANGUAGE,
    9. payload
    10. }
    11. }
    12. export const setLanguageObj = payload => {
    13. return {
    14. type: SET_LANGUAGE_OBJ,
    15. payload
    16. }
    17. }

    commonReducer.js 

    1. // commonReducer.js
    2. import {
    3. SET_LANGUAGE,
    4. SET_LANGUAGE_OBJ
    5. } from '../actionTypes/commonTypes'
    6. let lang = 'zh_CN'
    7. if (localStorage.getItem('language') === 'zh_CN' ||
    8. localStorage.getItem('language') === 'en_US'
    9. ) {
    10. // 防止莫名出现其他值
    11. lang = localStorage.getItem('language')
    12. }
    13. const initState = {
    14. language: lang,
    15. languageObj: {}
    16. }
    17. const commonReducer = (state = initState, action) => {
    18. const { type, payload } = action
    19. switch (type) {
    20. case SET_LANGUAGE:
    21. return {
    22. ...state,
    23. language: payload
    24. }
    25. case SET_LANGUAGE_OBJ:
    26. return {
    27. ...state,
    28. languageObj: payload
    29. }
    30. default:
    31. return {
    32. ...state
    33. }
    34. }
    35. }
    36. export default commonReducer

    rootReducer.js 

    1. // rootReducer.js
    2. import commonReducer from './commonReducer'
    3. const rootReducer = {
    4. commonStore: commonReducer
    5. }
    6. export default rootReducer
    1. // index.js
    2. import { createStore, combineReducers } from 'redux'
    3. import rootReducer from './reducers/rootReducer'
    4. const store = createStore(combineReducers(rootReducer))
    5. export default store

     二、然后定义SelectLang组件

    样式参考的antd,目录如下:

    index.js 

    1. // index.js
    2. import React from 'react'
    3. import { useSelector, useDispatch } from 'react-redux'
    4. import { setLanguage } from '../../redux/actions/commonActions'
    5. import './index.less'
    6. const SelectLang = props => {
    7. const language = useSelector(state => state.commonStore.language)
    8. const dispatch = useDispatch()
    9. const changeLanguage = () => {
    10. let lang = language === 'zh_CN' ? 'en_US' : 'zh_CN'
    11. localStorage.setItem('language', lang)
    12. dispatch(setLanguage(lang))
    13. }
    14. let selClassZH = language === 'zh_CN' ? 'acss-1nbrequ acss-1n10ay4' : 'acss-1nbrequ acss-3ew1dt'
    15. let selClassEN = language === 'en_US' ? 'acss-1nbrequ acss-1n10ay4' : 'acss-1nbrequ acss-3ew1dt'
    16. return (
    17. <div className="acss-llcihc" onClick={() => changeLanguage()}>
    18. <span className={selClassZH}>span>
    19. <span className={selClassEN}>Enspan>
    20. div>
    21. )
    22. }
    23. export default SelectLang

    index.less 

    1. /* index.less */
    2. .acss-llcihc {
    3. position: relative;
    4. cursor: pointer;
    5. width: 1.3rem;
    6. height: 1.3rem;
    7. display: inline-block;
    8. .acss-1nbrequ {
    9. position: absolute;
    10. font-size: 1.3rem;
    11. line-height: 1;
    12. color: #ffffff;
    13. }
    14. .acss-1n10ay4 {
    15. left: -5%;
    16. top: 0;
    17. z-index: 1;
    18. color: #ffffff;
    19. -webkit-transform: scale(0.7);
    20. -moz-transform: scale(0.7);
    21. -ms-transform: scale(0.7);
    22. transform: scale(0.7);
    23. transform-origin: 0 0;
    24. }
    25. .acss-3ew1dt {
    26. right: -5%;
    27. bottom: 0;
    28. z-index: 0;
    29. -webkit-transform: scale(0.5);
    30. -moz-transform: scale(0.5);
    31. -ms-transform: scale(0.5);
    32. transform: scale(0.5);
    33. transform-origin: 100% 100%;
    34. }
    35. }

     三、创建语言包

    防止文件过大,可以按类别穿件文件,目录如下:

    welcomeLocale.js 

    1. // welcomeLocale.js
    2. module.exports = {
    3. welcome: 'Welcome To System'
    4. }

     index.js

    1. // index.js
    2. import _ from 'lodash'
    3. const modulesFilesen = require.context('./en', true, /\.js$/)
    4. const modulesen = modulesFilesen.keys().reduce((modules, modulePath) => {
    5. const moduleName = modulePath.replace(/^.\/(.*)\.js/, '$1')
    6. const value = modulesFilesen(modulePath)
    7. modules[moduleName] = value
    8. return modules
    9. }, {})
    10. const modulesFileszh = require.context('./zh', true, /\.js$/)
    11. const moduleszh = modulesFileszh.keys().reduce((modules, modulePath) => {
    12. const moduleName = modulePath.replace(/^.\/(.*)\.js/, '$1')
    13. const value = modulesFileszh(modulePath)
    14. modules[moduleName] = value
    15. return modules
    16. }, {})
    17. // 动态读取文件并组合到一个对象中
    18. export const languageObj = {
    19. zh_CN: moduleszh,
    20. en_US: modulesen
    21. }
    22. // 判断语言包中是否存在该字段,没有返回空
    23. export const formatMessage = (titles, storeState) => {
    24. let titleList = titles.split('.')
    25. let resObj = _.cloneDeep(storeState)
    26. for (let index = 0; index < titleList.length; index++) {
    27. const element = titleList[index]
    28. if (resObj[element]) {
    29. resObj = resObj[element]
    30. } else {
    31. resObj = ''
    32. }
    33. }
    34. return resObj.toString()
    35. }

    四、使用

    react的入口文件

    1. import React from 'react'
    2. import ReactDOM from 'react-dom'
    3. import { BrowserRouter } from 'react-router-dom'
    4. import './index.less'
    5. import App from './App'
    6. import { languageObj } from './locale'
    7. import store from './redux'
    8. import { setLanguageObj } from './redux/actions/commonActions'
    9. import { Provider } from 'react-redux'
    10. const state = store.getState()
    11. const language = state.commonStore.language
    12. if (language === 'zh_CN') {
    13. store.dispatch(setLanguageObj(languageObj['zh_CN']))
    14. }
    15. if (language === 'en_US') {
    16. store.dispatch(setLanguageObj(languageObj['en_US']))
    17. }
    18. ReactDOM.render(
    19. <Provider store={store}>
    20. <BrowserRouter basename={process.env.PUBLIC_URL}>
    21. <App />
    22. BrowserRouter>
    23. Provider>,
    24. document.getElementById('root')
    25. )

    App.js 

    1. // App.js
    2. import React, { useEffect, useState } from 'react'
    3. import { Route, withRouter, Redirect } from 'react-router-dom'
    4. import { ConfigProvider, App } from 'antd'
    5. import { useSelector, useDispatch } from 'react-redux'
    6. import dayjs from 'dayjs'
    7. import 'dayjs/locale/zh-cn'
    8. import zh_CN from 'antd/locale/zh_CN'
    9. import en_US from 'antd/locale/en_US'
    10. import { setLanguageObj } from './redux/actions/commonActions'
    11. import { languageObj } from './locale'
    12. import Welcome from './welcome'
    13. import './App.less'
    14. dayjs.locale('zh-cn')
    15. const AppPage = () => {
    16. const dispatch = useDispatch()
    17. const [locale, setLocal] = useState({})
    18. const languageState = useSelector(state => state.commonStore.language)
    19. useEffect(() => {
    20. if (languageState === 'zh_CN') {
    21. dayjs.locale('zh-cn')
    22. setLocal(zh_CN)
    23. }
    24. if (languageState === 'en_US') {
    25. dayjs.locale('en')
    26. setLocal(en_US)
    27. }
    28. }, [languageState])
    29. useEffect(() => {
    30. dispatch(setLanguageObj(languageObj[languageState]))
    31. }, [locale])
    32. return (
    33. <div>
    34. <ConfigProvider
    35. locale={locale}
    36. >
    37. <App>
    38. <Route exact path="/" component={Welcome} />
    39. App>
    40. ConfigProvider>
    41. div>
    42. )
    43. }
    44. export default withRouter(AppPage)

     welcome.js

     formatMessage 方法参数:

    languageObj.welcomeLocale.welcome

    • languageObj:redux中的对象名
    • welcomeLocale: locale中的文件名
    • welcome:具体内容值

     commonStore :具体store, 可在formatMessage方法优化一下,就可以不用传了,自己处理尝试吧。

    1. // welcome.js
    2. import React from 'react'
    3. import { useSelector } from 'react-redux'
    4. import { formatMessage } from '../locale'
    5. import SelectLang from '../components/SelectLang'
    6. const Welcome = () => {
    7. const commonStore = useSelector(state => state.commonStore)
    8. return (
    9. <div className="welcome">
    10. <SelectLang />
    11. <h2 className="welcome-text">{formatMessage('languageObj.welcomeLocale.welcome', commonStore)}h2>
    12. div>
    13. )
    14. }
    15. export default Welcome

    如果遇到不能动态刷新,尝试可以一下 store.subscribe 

    1. import store from './redux'
    2. store.subscribe(() => {
    3. const state = store.getState()
    4. const language = state.commonStore.language
    5. // ...
    6. })

  • 相关阅读:
    说说js中使用for in遍历数组存在的bug
    9类人事管理场景应用,泛微协助HR释放更多工作量
    jenkins系列-07.轻易级jpom安装
    Linux操作系统使用及C高级编程
    用户粘性︱如何提升用户忠诚度
    nerdctl 工具(用于 containerd 但兼容 docker CLI 习惯)
    谷歌浏览器插件开发
    面经-框架-Spring refresh 流程
    PHP 7.1.13 版本,在使用过程中发现 浮点类型 数据经过 json_encode 之后会出现精度问题
    CountDownLatch(应对并发问题的工具类)
  • 原文地址:https://blog.csdn.net/qq_27829333/article/details/132792140