多语言解决方案

next-i18next

next-i18next 用于next.js 项目的插件

  1. 允许快速启动和运行翻译
  2. 完全支持SSR、多个名称空间和代码分割

next-i18next 底层使用的是 i18next 和 react-i18next,需要react和 next 的支持

翻译的文件内容需要遵循一定的规范

默认情况下,next-i18next 中对应的JSON 文件的路径方式如下: 只需要将翻译内容整理到JSON文件中

└── static └── locales ├── en | └── common.json └── de └── common.json

在组件中使用:

  1. 引入高阶组件 import { withNamespaces } from 'i18n';

  2. 使用: (withNamespaces('moduleDemo')(TradeForm)) 调用的时候需要将json文件和组件进行包裹,这样会返回高阶组件处理之后的组件

  3. moduleDemo 为提取的变量,后面的参数是组件

  4. moduleDemo 为 json 文件名称,里面的是页面中的各个变量

  5. withNamespaces 这个高阶组件负责将 函数 t 传给组件,它支持i18next提供的所有翻译功能。 在调用withNamespaces 这个高阶组件的时候,其实就相当于给组件注入了一个函数 t,在返回的组件中就可以使用这个函数 t。

  6. 然后在组件中就可以使用函数 t 对对应的变量进行翻译,json文件中的变量和组件中的变量一一对应

  7. 在json文件中提取的变量最好不要有:,.这样的特殊内容,否则解析会出错。

在非渲染组件中使用

在action中使用:因为在action中有对应的一些提示性的内容,这样就需要提取: action为单独js文件

  1. 引入: import { i18n } from 'i18n';

  2. 调用库里面的方法,返回对应的函数 t: const t = i18n.getFixedT(i18n.language, 'common');

  3. 目前action中的变量提取到 common.json 文件中 之后就可以调用 t 方法来进行翻译

翻译的内容中带参数是如何处理的

  1. 变量中的参数定义: t('Amount can not be less than the minimum {{min}} {{currency}}', { min, currency, });

在这里有两个变量: {{min}} {{currency}}

  1. 同样在json变量文件中也需要同样的变量 "Amount can not be less than the minimum {{min}} {{currency}}": "Amount can not be less than the minimum {{min}} {{currency}}",

  2. 在react中使用就需要用 dangerouslySetInnerHTML 这样的方式来使用:

因为这样会将数据动态的插入到页面中,这样的话,就会涉及到安全性的问题。 这个在React中是不允许的。

'termsContent'),
  }}
/>
复制代码

项目中的配置及读取的方式:

  1. 定义i18n的配置,在项目中的i18n.js:
const NextI18Next = require('next-i18next/dist/commonjs').default;

module.exports = new NextI18Next({
  defaultLanguage: 'en',
  debug: false,
  otherLanguages: ['zh'],
  // localeSubpaths: 'foreign',
  localeSubpaths: 'all',
  // localePath: `${isBrowser() ? '' : 'app/'}static/locales`,
  localePath: 'app/static/locales',
});

复制代码

  1. 获取i18n对象后,构造一个配置内容,比如默认的语言 localePath 这个配置指定本地语言包的路径: app/static/locales/en app/static/locales/zh 以后如果要新增新的语言包就是这样的路径

  2. 项目中server.js中引入了这个配置,并通过中间件的形式调用这个配置

const nextI18NextMiddleware = require('next-i18next/middleware');
const nextI18next = require('./app/i18n');
server.use(nextI18NextMiddleware(nextI18next));
复制代码

问题:

  1. 为什么要使用高阶组件的形式来给组件传递函数?为什么这样使用了,函数t就已经在组件的props中了呢?withNamespaces 做了哪些事情?

高阶组件是一个函数,接收一个组件并返回一个新的组件,这也就意味着,高阶组件可以实现

属性代理

通过包裹原来的组件来操作props,比如我们接收一个组件,同时原封不动的返回这个组件原来的样式,只是对接收组件的props属性进行操作,这样返回的新的组件中就有了新的props 当然操作props只是一个方面,另外可以将被包裹的组件的状态提取到包裹组件中,从而完成组件状态的抽象,比如可以实现将非受控组件转变成受控组件。

  1. 函数t的主要功能是什么?是怎么找到对应的文件中对应的变量的?如何根据语言去选择哪种变量呢?

  2. 在 next-i18next 文档中可以看出,next-i18next 组件底层依赖 react-i18next: import { Trans } from 'react-i18next'

  3. 而 react-i18next 中对这块代码的实现为函数:useTranslation,而这里采用了React最新特性:React Hooks

语言包按需加载

每个页面加载的数据并不是很多,所以对应的语言包文件中的内容也不会特别的多,

而页面加载时需要对语言包文件进行load,如果加载所有的语言包的话,就会非常耗时,这是不可取的。

在加载组件时,作为页面的顶层组件中去获取数据的时候,在next-i18next 中,默认情况下会在初始请求时将所有名称空间发送到客户端,所以默认有个配置:

在配合next.js时,需要通过页面级组件上的getInitialProps返回namespacesRequired数组。

import React from 'react';

class Home extends React.Component {
    static async getInitialProps() {
        return {
            namespacesRequired: ['common', 'footer']
        }
    }
}
复制代码

你可能感兴趣的:(多语言解决方案)