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日常问题解…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...
保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!
目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...
大数据治理的常见方式
大数据治理的常见方式 大数据治理是确保数据质量、安全性和可用性的系统性方法,以下是几种常见的治理方式: 1. 数据质量管理 核心方法: 数据校验:建立数据校验规则(格式、范围、一致性等)数据清洗&…...
【深尚想】TPS54618CQRTERQ1汽车级同步降压转换器电源芯片全面解析
1. 元器件定义与技术特点 TPS54618CQRTERQ1 是德州仪器(TI)推出的一款 汽车级同步降压转换器(DC-DC开关稳压器),属于高性能电源管理芯片。核心特性包括: 输入电压范围:2.95V–6V,输…...
