React中多语言的配置方式
作者:shuuy
React中多语言的配置
使用React-intl 插件来实现全局的多语言控制。
通过配置JSON key value键值对的形式来实现适应多语言需求。
第一步
安装多语言插件: react-intl
npm i react-intl
react-intl
文档地址:链接
第二步
准备配置工作。
安装完成以后可以在项目的根目录中建立一个locales文件夹来存放对应的语言包(其实就是一些key value键值对。)
然后建立两个文件夹:分别放置导出的语言配置:我本人的目录结构如下:
首先是两个语言包文件夹: 分别导出index.ts文件夹,后续如果业务有需要可以分别在各自文件夹中建立文件然后在index.ts文件中导入。
以应对后续业务较复杂语言包较多的情况。
en-US.ts
和 zh-CN.ts
两个文件导出了相关的配置。
这里导出的中文的配置如下:
import message from './zh-CN.message'; import zhCN from 'antd/es/locale/zh_CN'; const zh_CN = { message, antd: zhCN, locale: 'zh-CN', } as { message: any, antd:any, locale: 'zh-CN' | 'en-US' } export default zh_CN
因为项目中使用的是React框架,UI组件使用的是antd,antd官方也给出了UI组件的多语言配置所以这里直接从antd中拿到官方导出的组件语言包,供以后组件中使用。
message主要就是自己定义的键值对,locale是语言的标识。然后后续组件就可以引入配置来配置多语言了。
第三步
引入react-intl 中的组件进行配置。
在项目中的APP.tsx文件中进行导入。这里尽量在根节点导入,就像Context的使用方式差不多,在根节点注入以后,子组件中就可以使用。
在项目中导入Provider
import { IntlProvider } from 'react-intl';
导入antd组件的多语言组件:
import { ConfigProvider } from 'antd';
在根节点中包裹子组件。尽量在路由组件上方使用。
interface IProps extends RouteComponentProps<any,any>{ children: React.ReactNode } cosnt App:React.FC<IProps> = (props:IProps) => { return( <> <IntlProvider locale={localType.locale} messages={localType.message}> {/* antd中多语言配置 */} <ConfigProvider locale={localType.antd}> <section className="App"> {props.children} </section> </ConfigProvider> </IntlProvider> </> ) }
IntlProvider
是react-intl 导出的Provider,locale是对应的语言标识字符串,message对应的语言key\value 键值对。ConfigProvider
是antd 导出的Proverder, locale 需要导入antd 导出的语言包。
第四步
在系统中维护一个字符串来标识当前的语言,可以选择在Redux中进行维护,在App.tsx中可以根据当前语言字符串选择给IntlProvider和ConfigProvider 赋值不同的配置。
在state.ts中定义初始 state
const store:storeType = { localLanguage: 'en-US' }
然后开始写reducer 和 action
//reducer: modal/reducer/index.tsx const localLanguage = (state = store.localLanguage,action:actionType) => { switch(action.type) { case actionType.CHANGE_LANGUAGE: return action.data; default: return state; } } //action: modal/acton/index.tsx export const changeLanguage = (value: 'en-US'| 'zh-CN') => { return { type: storeType.CHANGE_LANGUAGE, data: value } } //导出store modal/index.tsx const store = createStore( reducers, applyMiddleware(thunk) ) export default store;
在根节点通过Provider来注入store
//导入store import { Provider } from 'react-redux'; import store from './modal' //使用Provider ReactDOM.render( <Provider store={store}> <RouterAll/>, </Provider>, document.getElementById('root') );
因为我这边想尽可能保持redux中数据的纯净,和reducer的纯函数的特性,所以只存入了字符串作为标识,所以需要在App.tsx中给多语言组件注入不同的值。
由于App.tsx中是用的react hook的方式来书写的,所以使用reducer提供的useSelector 来读取store的数据,根据标识注入不同的多语言数据。
实现代码如下:
import {useSelector} from 'react-redux'; import { RouteComponentProps } from 'react-router-dom' import enUS from './locales/en-US' import zhCN from './locales/zh-CN' interface IProps extends RouteComponentProps<any,any>{ children: React.ReactNode } const App:React.FC<IProps> = (props:IProps) => { const localLanguage = useSelector((state:storeType) => state.localLanguage) const [localType,setLocalType] = useState(enUS); useEffect(() => { setLocalType(localLanguage == 'en-US'? enUS: zhCN); },[localLanguage]) return ( <> {/* 多语言配置 */} <IntlProvider locale={localType.locale} messages={localType.message}> {/* antd中多语言配置 */} <ConfigProvider locale={localType.antd}> <section className="App"> {props.children} </section> </ConfigProvider> </IntlProvider> </> ) }
这个时候多语言的整体已经部署完毕了,接下来就是在后面的页面中进行多语言配置。
最后一步在子页面中使用多语言:这里分两步介绍: 分别为hook和Class组件。
hook 组件中 React-intl
导出了对应的钩子里 来访问intl实例。
其中intl是一个方法可以传入JSON配置来达到想要的效果:这里简单的配置了id : 经过intl执行以后就会拿到对应中英文配置的对应key的value
import React, { useState } from 'react'; import { useIntl } from 'react-intl'; import { useSelector, useDispatch } from 'react-redux' import { storeType } from '../../modal/state' import { changeLanguage } from '../../modal/actions' import { Button } from 'antd'; const TestLanguage: React.FC = () => { const { formatMessage: intl } = useIntl(); const state = useSelector((state: storeType) => state); const dispatch = useDispatch(); const changeLanguageEvent = () => { dispatch(changeLanguage(state.localLanguage === 'en-US' ? 'zh-CN' : 'en-US')) } return ( <> <span>{intl({ id: 'login' })}</span> 语言:{state.localLanguage} <hr /> <Button type="primary" onClick={changeLanguageEvent}>{intl({ id: 'testButton' })}</Button> </> ) } export default TestLanguage;
在class 组件中则是需要导入一个组件来实现: 通过组件中传入对应的属性,就可以渲染出对应的值。
使用如下:
import React, { Component,PureComponent } from 'react'; import { connect } from 'react-redux' import { changeLanguage } from '../../modal/actions' import { RouteComponentProps } from 'react-router-dom' import { Button } from 'antd'; import { FormattedMessage } from 'react-intl'; import { storeType } from '../../modal/state' interface IProps { localLanguage: 'en-US' | 'zh-CN'; dispatch: Function } class TestLanguageClass extends PureComponent<IProps & RouteComponentProps<any,any>, {}> { constructor(props: IProps & RouteComponentProps<any,any>) { super(props); this.state = { } } private buttonClick = () => { const { localLanguage } = this.props; this.props.dispatch(changeLanguage(localLanguage === 'en-US' ? 'zh-CN' : 'en-US')); } render() { const { localLanguage } = this.props; return ( <> <div> 语言:{localLanguage} <hr /> <Button onClick={this.buttonClick}><FormattedMessage id="testButton" /></Button> </div> </> ) } } export default connect( (state: storeType) => ({ localLanguage: state.localLanguage }), dispatch => ({ dispatch }))(TestLanguageClass);
简单的使用场景截图:
可以看出class组件与hook组件相比,不论在使用 redux 或者是使用多语言,hook都比较简介。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。