I18N是Internationalization的缩写 I(中间18个字符)n

原理

  • 语言包作为静态资源单独保存: xml, json
  • 每种语言对应一个文件
  • 切换语言设置时,语言文件也会随之切换

I18n工具

  • i18next : 目前最主流的框架
  • react-i18next : i18next 的 React 插件

react-i18next 官方文档

安装

  1. yarn add react-i18next i18next

(自带了 ts 声明, 不需要安装额外 ts 声明文件)

配置

在src目录新建 i18n 目录
将 json 格式的语言包都放在这个目录
语言包的格式就是 key: value 的hash表, 不同的语言,key相同,value不同

  1. {
  2. "header": {
  3. "slogan": "Make travel happier",
  4. "add_new_language": "add new language",
  5. "title": "React Travel",
  6. "register":"Register",
  7. "signin":"Sign In",
  8. "home_page": "Home",
  9. "weekend": "Weekend",
  10. "group": "Group",
  11. "backpack": "Backpack",
  12. "private": "Private",
  13. "cruise": "Cruise",
  14. "hotel": "Hotel & Attractions",
  15. "local": "Local",
  16. "theme": "Theme",
  17. "custom": "Custom",
  18. "study": "Study",
  19. "visa":"Visa",
  20. "enterprise":"Enterprise",
  21. "high_end":"High-end",
  22. "outdoor":"Outdoor",
  23. "insurance":"Insurance"
  24. },
  25. "footer": {
  26. "detail" : "All rights reserved @ ReactTravel.com"
  27. },
  28. }

新建 configs.ts

  1. import i18n from 'i18next'
  2. import { initReactI18next } from 'react-i18next'
  3. // 导入语言包
  4. import translation_en from './en.json'
  5. import translation_zh from './zh.json'
  6. const resources = {
  7. en: {
  8. translation: translation_en,
  9. },
  10. zh: {
  11. translation: translation_zh,
  12. },
  13. }
  14. i18n
  15. .use(initReactI18next) // passes i18n down to react-i18next
  16. .init({
  17. resources,
  18. lng: 'zh', // 默认语言
  19. // keySeparator: false, // we do not use keys in form messages.welcome
  20. // header.slogan
  21. interpolation: {
  22. escapeValue: false, // react already safes from xss
  23. },
  24. })
  25. export default i18n

在入口文件 index.tsx 中导入 configs.ts

  1. import './i18n/configs'

此时就配置完成了,可以使用 i18n 了

插入语言包内容

在类组件中使用

  1. // ...
  2. // 引入高阶组件withTranslation和接口WithTranslation
  3. import { withTranslation, WithTranslation } from 'react-i18next'
  4. class HomePageComponent extends React.Component<WithTranslation> {
  5. render() {
  6. const { t } = this.props // 通过 t 访问json语言包中的key
  7. return (
  8. <>
  9. <Header />
  10. <div className={styles['page-content']}>
  11. // ...
  12. <ProductCollection
  13. title={
  14. <Typography.Title level={3} type="warning">
  15. {t('home_page.hot_recommended')} // 获取语言包中对应的项
  16. </Typography.Title>
  17. }
  18. sideImage={sideImage}
  19. products={productList1}
  20. />
  21. // ...
  22. </div>
  23. </>
  24. )
  25. }
  26. }
  27. // 导出高阶组件, 注意withTranslation有2个括号
  28. export const HomePage = withTranslation()(HomePageComponent)

在函数式组件中使用

  1. import { Layout, Typography } from 'antd'
  2. import { useTranslation } from 'react-i18next'
  3. export const Footer: React.FC = () => {
  4. const { t } = useTranslation() // 使用钩子
  5. return (
  6. <Layout.Footer>
  7. <Typography.Title level={3} style={{ textAlign: 'center' }}>
  8. {t('footer.detail')} {/* 获取语言包中对应的项*/}
  9. </Typography.Title>
  10. </Layout.Footer>
  11. )
  12. }

切换语言

使用 i18next.changeLanguage 实现语言切换

  1. i18next.changeLanguage(lng, callback) // 返回的是一个promise
  1. import i18n from "i18next";
  2. i18n.changeLanguage('en');

在redux的reducer中实现语言切换
reducer应该是纯函数,不该有副作用

  1. import i18n from "i18next";
  2. export default (state = defaultState, action) => {
  3. switch (action.type) {
  4. case "change_language":
  5. i18n.changeLanguage(action.payload); // 这样处理是不标准的,有副作用
  6. return { ...state, language: action.payload };
  7. // ...
  8. default:
  9. return state;
  10. }
  11. };