React如何实现国际化?

news/2024/7/15 18:27:27 标签: react.js, 前端

目录

 一、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 

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

commonActions.js 

// commonActions.js
import {
  SET_LANGUAGE,
  SET_LANGUAGE_OBJ
} from '../actionTypes/commonTypes'

export const setLanguage = payload => {
  return {
    type: SET_LANGUAGE,
    payload
  }
}

export const setLanguageObj = payload => {
  return {
    type: SET_LANGUAGE_OBJ,
    payload
  }
}

commonReducer.js 

// commonReducer.js
import {
  SET_LANGUAGE,
  SET_LANGUAGE_OBJ
} from '../actionTypes/commonTypes'
let lang = 'zh_CN'
if (localStorage.getItem('language') === 'zh_CN' ||
  localStorage.getItem('language') === 'en_US'
) {
  // 防止莫名出现其他值
  lang = localStorage.getItem('language')
}
const initState = {
  language: lang,
  languageObj: {}
}
const commonReducer = (state = initState, action) => {
  const { type, payload } = action
  switch (type) {
    case SET_LANGUAGE:
      return {
        ...state,
        language: payload
      }
    case SET_LANGUAGE_OBJ:
      return {
        ...state,
        languageObj: payload
      }
    default:
      return {
        ...state
      }
  }
}
 
export default commonReducer

rootReducer.js 

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

 二、然后定义SelectLang组件

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

index.js 

// index.js
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { setLanguage } from '../../redux/actions/commonActions'
 
import './index.less'
 
const SelectLang = props => {
  const language = useSelector(state => state.commonStore.language)
  const dispatch = useDispatch()
  const changeLanguage = () => {
    let lang = language === 'zh_CN' ? 'en_US' : 'zh_CN'
    localStorage.setItem('language', lang)
    dispatch(setLanguage(lang))
  }
  let selClassZH = language === 'zh_CN' ? 'acss-1nbrequ acss-1n10ay4' : 'acss-1nbrequ acss-3ew1dt'
  let selClassEN = language === 'en_US' ? 'acss-1nbrequ acss-1n10ay4' : 'acss-1nbrequ acss-3ew1dt'
  return (
    <div className="acss-llcihc" onClick={() => changeLanguage()}>
      <span className={selClassZH}>中</span>
      <span className={selClassEN}>En</span>
    </div>
  )
}
 
export default SelectLang

index.less 

// index.less
.acss-llcihc {
  position: relative;
  cursor: pointer;
  width: 1.3rem;
  height: 1.3rem;
  display: inline-block;
  .acss-1nbrequ {
    position: absolute;
    font-size: 1.3rem;
    line-height: 1;
    color: #ffffff;
  }
  .acss-1n10ay4 {
    left: -5%;
    top: 0;
    z-index: 1;
    color: #ffffff;
    -webkit-transform: scale(0.7);
    -moz-transform: scale(0.7);
    -ms-transform: scale(0.7);
    transform: scale(0.7);
    transform-origin: 0 0;
  }
  .acss-3ew1dt {
    right: -5%;
    bottom: 0;
    z-index: 0;
    -webkit-transform: scale(0.5);
    -moz-transform: scale(0.5);
    -ms-transform: scale(0.5);
    transform: scale(0.5);
    transform-origin: 100% 100%;
  }
}

 三、创建语言包

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

welcomeLocale.js 

// welcomeLocale.js
module.exports = {
  welcome: 'Welcome To System'
}

 index.js

// index.js

import _ from 'loadsh'

const modulesFilesen = require.context('./en', true, /\.js$/)
const modulesen = modulesFilesen.keys().reduce((modules, modulePath) => {
  const moduleName = modulePath.replace(/^.\/(.*)\.js/, '$1')
  const value = modulesFilesen(modulePath)
  modules[moduleName] = value
  return modules
}, {})

const modulesFileszh = require.context('./zh', true, /\.js$/)
const moduleszh = modulesFileszh.keys().reduce((modules, modulePath) => {
  const moduleName = modulePath.replace(/^.\/(.*)\.js/, '$1')
  const value = modulesFileszh(modulePath)
  modules[moduleName] = value
  return modules
}, {})

// 动态读取文件并组合到一个对象中
export const languageObj = {
  zh_CN: moduleszh,
  en_US: modulesen
}

// 判断语言包中是否存在该字段,没有返回空
export const formatMessage = (titles, storeState) => {
  let titleList = titles.split('.')
  let resObj = _.cloneDeep(storeState)
  for (let index = 0; index < titleList.length; index++) {
    const element = titleList[index]
    if (resObj[element]) {
      resObj = resObj[element]
    } else {
      resObj = ''
    }
  }
  return resObj.toString()
}

四、使用

react的入口文件

import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import './index.less'
import App from './App'
import { languageObj } from './locale'
import store from './redux'
import { setLanguageObj } from './redux/actions/commonActions'
import { Provider } from 'react-redux'

const state = store.getState()
const language = state.commonStore.language
if (language === 'zh_CN') {
  store.dispatch(setLanguageObj(languageObj['zh_CN']))
}
if (language === 'en_US') {
  store.dispatch(setLanguageObj(languageObj['en_US']))
}
ReactDOM.render(
  <Provider store={store}>
    <BrowserRouter basename={process.env.PUBLIC_URL}>
      <App />
    </BrowserRouter>
  </Provider>,
  document.getElementById('root')
)

App.js 

// App.js

import React, { useEffect, useState } from 'react'
import { Route, withRouter, Redirect } from 'react-router-dom'
import { ConfigProvider, App } from 'antd'
import { useSelector, useDispatch } from 'react-redux'
import dayjs from 'dayjs'
import 'dayjs/locale/zh-cn'
import zh_CN from 'antd/locale/zh_CN'
import en_US from 'antd/locale/en_US'
import { setLanguageObj } from './redux/actions/commonActions'
import { languageObj } from './locale'
import Welcome from './welcome'
import './App.less'
dayjs.locale('zh-cn')
 
const AppPage = () => {
  const dispatch = useDispatch()
  const [locale, setLocal] = useState({})
  const languageState = useSelector(state => state.commonStore.language)
  useEffect(() => {
    if (languageState === 'zh_CN') {
      dayjs.locale('zh-cn')
      setLocal(zh_CN)
    }
    if (languageState === 'en_US') {
      dayjs.locale('en')
      setLocal(en_US)
    }
  }, [languageState])
 
  useEffect(() => {
    dispatch(setLanguageObj(languageObj[languageState]))
  }, [locale])
  return (
    <div>
      <ConfigProvider
        locale={locale}
      >
        <App>
        <Route exact path="/" component={Welcome} />
        </App>
      </ConfigProvider>
    </div>
  )
}
 
export default withRouter(AppPage)

 welcome.js

 formatMessage 方法参数:

languageObj.welcomeLocale.welcome

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

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

// welcome.js

import React from 'react'
import { useSelector } from 'react-redux'
import { formatMessage } from '../locale'
const Welcome = () => {
  const commonStore = useSelector(state => state.commonStore)
  return (
    <div className="welcome">
      <h2 className="welcome-text">{formatMessage('languageObj.welcomeLocale.welcome', commonStore)}</h2>
    </div>
  )
}
 
export default Welcome

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

import store from './redux'
store.subscribe(() => {
  const state = store.getState()
  const language = state.commonStore.language
  // ...
})


http://www.niftyadmin.cn/n/5017553.html

相关文章

2022年12月 C/C++(八级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C++编程(1~8级)全部真题・点这里 第1题:生理周期 人生来就有三个生理周期,分别为体力、感情和智力周期,它们的周期长度为23天、28天和33天。每一个周期中有一天是高峰。在高峰这天,人会在相应的方面表现出色。例如,智力周期的高峰,人会思维敏捷,精力容易高度集中。因…

【pygame】01 pygame制作游戏的最小系统

这次使用sublimepython进行pygame的游戏开发&#xff0c;目的是学习使用python的基本操作和常用模块 添加一个文件夹到工程 最小系统 1.导入使用的模块 2.初始化&#xff1a;pygame.init函数包含了各个子模块的初始化&#xff0c;可以重复调用 3.pygame.display.set_mode返…

python版本是3.9.3,如何匹配相应的pip或pip3?

在 Windows 中&#xff0c;可以通过以下步骤来安装匹配 Python 3.9.3 版本的 pip&#xff1a; 在浏览器中打开 https://bootstrap.pypa.io/get-pip.py 并下载该文件&#xff1b; 打开命令提示符&#xff08;Command Prompt&#xff09;&#xff0c;输入以下命令来运行刚刚下载…

【MySql】MySql存储过程与函数

存储过程与函数 存储过程没有返回值&#xff0c;函数有返回值 存储过程 存储过程就是一组预先编译好的SQL语句的封装&#xff0c;需要执行时客户端向服务器发送调用请求&#xff0c;服务器就会将这一系列预先存储好的SQL语句全部执行。 简单举例&#xff1a;存储过程的创建…

图解 LeetCode 算法汇总——回溯

本文首发公众号&#xff1a;小码A梦 回溯算法是一种常见的算法&#xff0c;常见用于解决排列组合、排列问题、搜索问题等算法&#xff0c;在一个搜索空间中寻找所有的可能的解。通过向分支不断尝试获取所有的解&#xff0c;然后找到合适的解&#xff0c;找完一个分支后再往回搜…

设计模式-备忘录模式(Memento Pattern)

文章目录 前言一、备忘录模式的概念二、备忘录模式的实现三、备忘录优缺点优点&#xff1a;缺点&#xff1a;总结 前言 备忘录模式&#xff08;Memento Pattern&#xff09;是一种行为型设计模式&#xff0c;它用于捕获和存储对象的内部状态&#xff0c;以便在以后可以恢复到先…

java实现课程表 II

题目&#xff1a; 现在你总共有 numCourses 门课需要选&#xff0c;记为 0 到 numCourses - 1。给你一个数组 prerequisites &#xff0c;其中 prerequisites[i] [ai, bi] &#xff0c;表示在选修课程 ai 前 必须 先选修 bi 。 例如&#xff0c;想要学习课程 0 &#xff0c;…

[技术讨论]讨论问题的两个基本原则——17年前的文字仍然有效

前两天又有人找我讨论问题&#xff0c;而且是他自己的项目&#xff0c;内容与我没有任何关系&#xff0c;他说的&#xff0c;却是讨论。 其实就是想来做咨询&#xff0c;又不想付费。 今天看到了十七年前写的这篇文字&#xff0c;就重发一下了&#xff0c;当然有少量文字修订&a…