React-Intl + Redux 实现React项目国际化
前言
现在的前端项目中,很多时候我们需要对我们项目的文案进行国际化,以适用各国用户使用,今天我们就用React-Intl
库配合Redux
实现语言的实时切换如果对在React中使用Redux不熟悉的,可以我的参照另外两篇文章:这篇Redux,Redux-Toolkit教程真的很详细React项目中使用Redux,Redux-Toolkit
安装依赖
我们需要安装@reduxjs/toolkit,react-redux,react-intl
三个依赖
npm i @reduxjs/toolkit react-redux react-intl
创建多语言文件夹
在项目中创建一个多语言文件夹,如上图所示,其中包含一个语言文件夹和入口文件,语言文件夹中是每种语言对应文案的翻译,
index.tsx
入口文件实现语言文件的整合
创建语言文件
我们创建三个语言文件,分别是中文,英语,法语。文件对象中的key是我们需要在项目中使用的id
,value是对应的具体文案,当我们切换成某种语言时,就会根据key的值显示对应value具体文案。其中的{name},{text}
是文案占位符,后续我们可以动态传入文案替换{}
中的内容,这也就是在国际化文案中包含变量zh_CN.json
{
"pageTitle": "谨防电信网络诈骗",
"pageContent1": "近期,电信网络诈骗案件屡见不鲜,为了保障您的资金安全,{name}提醒您:{text}"
}
en_US.json
{
"pageTitle": "Beware of Telecommunications and Network Fraud",
"pageContent1": "Recently, cases of telecommunications and network fraud are common. In order to ensure the safety of your funds, {name} reminds you: {text}"
}
fr_FR.json
{
"pageTitle": "Méfiez-vous des télécommunications et de la fraude sur les réseaux",
"pageContent1": "Récemment, les cas de télécommunications et de fraude sur les réseaux sont courants. Afin d'assurer la sécurité de vos fonds, {name} vous rappelle : {text}"
}
整合文件并导出
在index.tsx
整合各个语言文件并导出
import zh_CN from './languageJson/zh_CN.json'
import en_US from './languageJson/en_US.json'
import fr_FR from './languageJson/fr_FR.json'
type LanguageType = 'zh' | 'en' | 'fr'
type LanguageJsonType = {
[key: string]: string
}
type LanguageMessageType = {
[key in LanguageType]: LanguageJsonType
}
type LanguageListType = {
label: string,
value: LanguageType
}[]
const languageList: LanguageListType = [
{
label: '简体中文',
value: 'zh'
},
{
label: 'English',
value: 'en'
},
{
label: 'Français',
value: 'fr'
}
]
const languageMessage: LanguageMessageType = {
zh: zh_CN as LanguageJsonType,
en: en_US as LanguageJsonType,
fr: fr_FR as LanguageJsonType
}
export {
LanguageType,
LanguageJsonType,
languageList,
languageMessage
}
文件解析:
- 定义类型,定义各个变量类型
languageList
,定义后续切换文件所需的语言列表languageMessage
,整合所有语言成一个对象,对象的key为语言的名称,value就是对应的语言文件中的所有字段的对象集合
Redux中创建language状态
import { createSlice } from '@reduxjs/toolkit'
import { LanguageType } from '@src/language'
// 定义action类型
type LanguageActionType = {
type: string,
payload: LanguageType
}
// 定义初始state
const initialState = 'zh'
// 定义counterSlice
const counterSlice = createSlice({
name: 'language',
initialState,
reducers: {
changeLanguageAction(state: LanguageType, action: LanguageActionType) {
return action.payload
}
}
})
// 取出action creator
const { changeLanguageAction } = counterSlice.actions
// 取出reducer
const languageReducer = counterSlice.reducer
export {
languageReducer,
changeLanguageAction
}
创建React根,并注入Redux store
import React from 'react'
import ReactDOM from 'react-dom/client'
import IntlApp from '@app/intlApp'
import { Provider } from 'react-redux'
import store from '@src/reduxToolkit/store'
const rootElement = document.getElementById('root') as HTMLElement
const root = ReactDOM.createRoot(rootElement)
root.render(
<Provider store={store}>
<IntlApp />
</Provider>
)
根组件中注入多语言
import React from 'react'
import { IntlProvider } from 'react-intl'
import { languageMessage, LanguageJsonType } from '@src/language'
import { useSelector, shallowEqual } from 'react-redux'
import { StateType } from '@src/reduxToolkit/stateType'
import Demo01 from '@pages/intlDemo/demo01'
import Demo02 from '@pages/intlDemo/demo02'
type StoreSelector = {
language: string
}
function IntlApp() {
const storeSelector = (state: StateType) => ({
language: state.language
}) as StoreSelector
const { language } = useSelector(storeSelector, shallowEqual) as StoreSelector
return (
<IntlProvider locale={language} messages={languageMessage[language] as LanguageJsonType}>
<Demo01 />
<hr />
<Demo02 />
</IntlProvider>
)
}
export default IntlApp
文件解析:
- 从
react-intl
导入组件IntlProvider
这是react-intl
的核心组件,使用该组件包裹根组件的所有内容,该组件接收两个props,loacle
是当前的语言,messages
是当前语言对应的文案对象 - 我们从Redux中导入当前的
language值
并通过locale传入IntlProvider
,并从language文件夹获取所有语言的文件对象集合,并根据Redux中的当前语言值获取当前语言的文案对象,通过messages传入IntlProvider
- 下面我们引用Demo01,Demo02两个文件分别用来切换语言和显示文案
实现语言切换
Demo01.tsx
import React, { memo, ChangeEvent } from 'react'
import { languageList, LanguageType } from '@src/language'
import { useSelector, shallowEqual, useDispatch } from 'react-redux'
import { StateType } from '@src/reduxToolkit/stateType'
import { changeLanguageAction } from '@src/reduxToolkit/states/language'
type StoreSelector = {
language: string
}
function Demo02() {
const dispatch = useDispatch()
const storeSelector = (state: StateType) => ({
language: state.language
}) as StoreSelector
const { language } = useSelector(storeSelector, shallowEqual) as StoreSelector
const handleChangeLanguage = (e: ChangeEvent<HTMLSelectElement>) => {
if (e.target.value !== language) {
dispatch(changeLanguageAction(e.target.value as LanguageType))
}
}
return (
<div>
<select onChange={handleChangeLanguage} value={language}>
{
languageList.map((item) => (
<option key={item.value} value={item.value}>{item.label}</option>
))
}
</select>
</div>
)
}
export default memo(Demo02)
文件解析:
组件中使用语言
import React, { memo } from 'react'
import { useIntl } from 'react-intl'
function Demo02() {
const { formatMessage } = useIntl()
return (
<div>
<h1>{formatMessage({ id: 'pageTitle' })}</h1>
<h2>
{formatMessage({ id: 'pageContent1' }, {
name: '杭州公安',
text: formatMessage({ id: 'pageTitle' })
})}
</h2>
</div>
)
}
export default memo(Demo02)
文件解析:
- 我们使用文案时,需要一个核心方法
formatMessage
,该方法通过react-intl中的useIntl
返回 formatMessage
方法接收两个参数,第一个参数是一个对象,对象中设置属性id
的值,formatMessage
就会根据id
的值,返回当前语言文件中对应的具体文案formatMessage
的第二个参数也是一个对象,对象中传入的是id
对应文案中变量的值,对象的key对应文案中使用{}
包裹的变量,value是具体的替代文案,替代文案也可以传入其他的文案,如同上面text
所示
测试代码演示
至此我们就实现了使用React-Intl
库配合Redux
实现语言的实时切换,下面是代码演示
转载自:https://juejin.cn/post/7268112665125732404