I18N是Internationalization的缩写 I(中间18个字符)n
原理
- 语言包作为静态资源单独保存: xml, json
- 每种语言对应一个文件
- 切换语言设置时,语言文件也会随之切换
I18n工具
- i18next : 目前最主流的框架
- react-i18next : i18next 的 React 插件
安装
yarn add react-i18next i18next
(自带了 ts 声明, 不需要安装额外 ts 声明文件)
配置
在src目录新建 i18n 目录
将 json 格式的语言包都放在这个目录
语言包的格式就是 key: value 的hash表, 不同的语言,key相同,value不同
{
"header": {
"slogan": "Make travel happier",
"add_new_language": "add new language",
"title": "React Travel",
"register":"Register",
"signin":"Sign In",
"home_page": "Home",
"weekend": "Weekend",
"group": "Group",
"backpack": "Backpack",
"private": "Private",
"cruise": "Cruise",
"hotel": "Hotel & Attractions",
"local": "Local",
"theme": "Theme",
"custom": "Custom",
"study": "Study",
"visa":"Visa",
"enterprise":"Enterprise",
"high_end":"High-end",
"outdoor":"Outdoor",
"insurance":"Insurance"
},
"footer": {
"detail" : "All rights reserved @ ReactTravel.com"
},
}
新建 configs.ts
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
// 导入语言包
import translation_en from './en.json'
import translation_zh from './zh.json'
const resources = {
en: {
translation: translation_en,
},
zh: {
translation: translation_zh,
},
}
i18n
.use(initReactI18next) // passes i18n down to react-i18next
.init({
resources,
lng: 'zh', // 默认语言
// keySeparator: false, // we do not use keys in form messages.welcome
// header.slogan
interpolation: {
escapeValue: false, // react already safes from xss
},
})
export default i18n
在入口文件 index.tsx 中导入 configs.ts
import './i18n/configs'
此时就配置完成了,可以使用 i18n 了
插入语言包内容
在类组件中使用
// ...
// 引入高阶组件withTranslation和接口WithTranslation
import { withTranslation, WithTranslation } from 'react-i18next'
class HomePageComponent extends React.Component<WithTranslation> {
render() {
const { t } = this.props // 通过 t 访问json语言包中的key
return (
<>
<Header />
<div className={styles['page-content']}>
// ...
<ProductCollection
title={
<Typography.Title level={3} type="warning">
{t('home_page.hot_recommended')} // 获取语言包中对应的项
</Typography.Title>
}
sideImage={sideImage}
products={productList1}
/>
// ...
</div>
</>
)
}
}
// 导出高阶组件, 注意withTranslation有2个括号
export const HomePage = withTranslation()(HomePageComponent)
在函数式组件中使用
import { Layout, Typography } from 'antd'
import { useTranslation } from 'react-i18next'
export const Footer: React.FC = () => {
const { t } = useTranslation() // 使用钩子
return (
<Layout.Footer>
<Typography.Title level={3} style={{ textAlign: 'center' }}>
{t('footer.detail')} {/* 获取语言包中对应的项*/}
</Typography.Title>
</Layout.Footer>
)
}
切换语言
使用 i18next.changeLanguage 实现语言切换
i18next.changeLanguage(lng, callback) // 返回的是一个promise
import i18n from "i18next";
i18n.changeLanguage('en');
在redux的reducer中实现语言切换
reducer应该是纯函数,不该有副作用
import i18n from "i18next";
export default (state = defaultState, action) => {
switch (action.type) {
case "change_language":
i18n.changeLanguage(action.payload); // 这样处理是不标准的,有副作用
return { ...state, language: action.payload };
// ...
default:
return state;
}
};