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
// 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 } = actionswitch (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.jsimport _ 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] = valuereturn 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] = valuereturn 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.jsimport 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><ConfigProviderlocale={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.jsimport 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// ...
})
相关文章:
React如何实现国际化?
目录 一、Redux准备工作 commonTypes.js commonActions.js commonReducer.js rootReducer.js 二、然后定义SelectLang组件 index.js index.less 三、创建语言包 welcomeLocale.js index.js 四、使用 react的入口文件 App.js welcome.js 附 关于如何实现国际…...
netrw模拟nerdtree的go命令连续打开多个文件
vim9自带的文件浏览器netrw功能很强大。过去用惯了nerdtree的我,对netrw的文件操作还要适应一些时间。 使用netrw一段时间后发现它没有nerdtree的go命令的替代操作,今天就自制一个。 一、制作go命令: nerdtree的go命令功能:就是…...
算法通关村第十九关——动态规划高频问题(白银)
算法通关村第十九关——动态规划高频问题(白银) 前言1 最少硬币数2 最长连续递增子序列3 最长递增子序列4 完全平方数5 跳跃游戏6 解码方法7 不同路径 II 前言 摘自:代码随想录 动态规划五部曲: 确定dp数组(dp tabl…...
Matlab如何导入Excel数据并进行FFT变换
如果你发现某段信号里面有干扰,想要分析这段信号里面的频率成分,就可以使用matlab导入Excel数据后进行快速傅里叶变换(fft)。 先直接上使用方法,后面再补充理论知识。 可以通过串口将需要分析的数据发送到串口助手&a…...
华为mate60 上线 媒介盒子多家媒体报道
为什么你的品牌营销不见效?如何能推动品牌破圈?让媒介盒子给你一些启发。本期盒子要跟大家分享地新机上市,数码科技行业企业该如何做线上宣传。 HUAWEI Mate 60系列8月29日官宣发布,出色的拍照功能、强大的性能表现和持久的续航能…...
Java知识总结(持续更新)
一、JDK、JRE、JVM三者之间的关系? 1. **JDK (Java Development Kit)**: JDK 是 Java 开发工具包,它包含了用于开发 Java 应用程序的所有必要工具和库。这包括 Java 编译器(javac)、Java 核心类库、开发工具&#x…...
缓存技术:加速应用,提高用户体验
本文总结前期某个系统中使用到的缓存使用经验—仅此而已,效果还不错。 缓存技术在系统架构设计中扮演着至关重要的角色,它不仅可以显著提高系统的性能,还可以改善用户体验。在本文章中,我们将探讨不同类型的缓存、缓存失效以及缓存淘汰等关键概念,帮助在后期的架构设计中…...
MySQL中分区与分表的区别
MySQL中分区与分表的区别 一、分区与分表的区别 分区和分表是在处理大规模数据时的两种技术手段,尽管它们的目标都是提升系统的性能和数据管理的效率,但它们的实现方式和应用场景略有不同。 1. 分区 分区是将一个大表分割为多个更小的子表,…...
Redis主从复制集群的介绍及搭建
在现代的软件开发中,数据的可靠性和可用性是至关重要的。Redis,作为一个开源的、内存中的数据结构存储系统,以其出色的性能和灵活的数据结构,赢得了开发者们的广泛喜爱。而 Redis 的主从复制功能,更是为我们提供了一种…...
MAC M1芯片安装mounty读写移动硬盘中的文件
因为移动硬盘中的文件是微软公司NTFS格式,MAC只支持自己的APFS或者HFS,与微软的NTFS不兼容,所以需要第三方的软件来支持读写硬盘中的文件,经过一上午的折腾,最终选择安装mounty这个免费的第三方软件 工具网址连接&am…...
原生Js Canvas去除视频绿幕背景
Js去除视频背景 注: 这里的去除视频背景并不是对视频文件进行操作去除背景 如果需要对视频扣除背景并导出可以使用ffmpeg等库,这里仅作播放用所以采用这种方法 由于uniapp中的canvas经过封装,且 uniapp 的 drawImage 无法绘制视频帧画面&…...
Vue知识系列(1)每天10个小知识点
目录 系列文章目录知识点**1. Vue修饰符**的概念、作用、原理、特性、优点、缺点、区别、使用场景**2. 双向数据绑定**的概念、作用、原理、特性、优点、缺点、区别、使用场景**3. MVVM、MVC、MVP** 的概念、作用、原理、特性、优点、缺点、区别、使用场景**4. slot** 的概念、…...
Elasticsearch(三)聚合基本使用
基础概念 bucket 数据分组,一些数据按照某个字段进行bucket划分,这个字段值相同的数据放到一个bucket中。可以理解成Java中的Map<String, List>结构,类似于Mysql中的group by后的查询结果。 metric: 对一个数据分组执行…...
单片机C语言实例:14、音频输出
一、喇叭发声原理 程序实例1: #include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义sbit SPK P1^2; //定义喇叭端口 /*------------------------------------------------函数声明 --------------…...
docker 和 podman的区别
Podman 和 Docker 都是用于容器化应用程序的工具,它们在很多方面非常相似,但也有一些关键区别: 1. 架构和权限: - Docker:Docker 使用守护进程(dockerd)来管理容器,它需要在操作…...
苹果手机远程控制安卓手机,为什么不能发起控制?
这位用户想要用iOS设备远程控制安卓设备,在被控端安装好AirDroid之后,就在控制端的苹果手机上也安装了AirDroid,然而打开控制端的软件,却没有在手机界面上看到【远程控制】按钮,于是提出了以上疑问。 解答 想要让iOS设…...
Gradle 配置国内镜像
我们在使用gradle构建项目的时候,每当需要build或者刷新依赖的时候,由于gradle需要从服务器下载各种依赖包,速度非常慢,根本原因是由于gradle服务器在国外,而国内有些一些大厂和高校(比如阿里,华为…...
Spring AOP使用指南: 强大的面向切面编程技术
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…...
Spring Boot集成Elasticsearch实战
文章目录 一、简介二、安装与配置Elasticsearch三、集成Spring Boot与Elasticsearch1. 添加依赖与配置文件2. 创建Elasticsearch数据模型3. 定义Elasticsearch仓库接口4. 实现Elasticsearch数据操作 四、基本查询与索引操作1. 插入与更新数据2. 删除数据与索引3. 条件查询与分页…...
【python零基础入门学习】python基础篇之文件对象open、模块以及函数的使用(三)
本站以分享各种运维经验和运维所需要的技能为主 《python》:python零基础入门学习 《shell》:shell学习 《terraform》持续更新中:terraform_Aws学习零基础入门到最佳实战 《k8》暂未更新 《docker学习》暂未更新 《ceph学习》ceph日常问题解…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
