当前位置:   article > 正文

Next.js i18n国际化实现方案(支持ReactNode类型、可传参)_next国际化

next国际化

前言

抛开Next.js框架不谈,想必其他项目也经常会遇到国际化方案,大概逻辑都是差不多的,只是说这次本人碰巧在Next上的项目有这样的需求,并记录下来。

实现思路:

其实不从代码角度上讲的话,无非是引入一个“变量”,并且所有文本都依赖于这个“变量”,然后再提前配置好一系列的语言文件,只要这个“变量”变了,那我就利用这个变量做出映射,从而达到切换语言的效果,只是说不同方案,对这个“变量”呈现的方式不一样而已。对于变量的呈现方式如下:

方案一:
按域名来控制,就像react官网一样,比如说你要看英文的,那你就访问reactjs.org,如果你要看中文的,那你就访问zh-hans.reactjs.org,如果你要看韩文的,那你就访问ko.reactjs.org,如果你要看…

发现没有,其实就是不同语言,就访问不同的域名

方案二:

按路由来控制,比如你要看英文的,那你就访问http://localhost:8080/en/admin/user,如果你要看中文的,那你就访问http://localhost:8080/zh/admin/user,如果你要看韩文的,那你访问http://localhost:8080/ko/admin/user,如果你要看…

这种其实就是把语言变量放在了路由上

正文

说了上面那么多,总算可以正文了~~
首先Next在版本大于等于v10.0.0后本身就支持国际化,并不需要特意引入网上那些杂七杂八的插件,什么react-intl啊、react-i18next啊、react-i18n-auto啊等等,不是说他们不好,而是我感觉没必要,所以就自己写一个简单的hook demo就好了。大家也可以直接自己看官网,下面的也是按照官网的快速上手来的

修改next项目中的next.config.js配置文件:

// next.config.js
module.exports = {
		i18n: {
		    defaultLocale: 'zh', // 默认语言
		    locales: ['en', 'zh'], // 语言变量
		  },
		  ...others
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

当然我这里采用的是上诉的方案二,按路由来控制,官网中有写到配置域名,也就是按域名来控制语言

然后新增语言文件

// en.jsx
const EN_JSON = {
	"app.title":"international language"
}

// zh.jsx
const ZH_JSON = {
	"app.title":"国际化语言"
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

可能细心的同学会发现,我这里新建的是两个.jsx文件,而不是json,或者js文件,这也就意味着,我们自己的写的这个可以支持ReactNode,并不完全局限于普通文本了!

接着再写一个hook

// useTranslation.js
import { useRouter } from 'next/router';
import En from '@/locales/en'; // 英文语言包,也就是上面的en.jsx
import Zh from '@/locales/zh'; // 中文语言包,也就是上面的zh.jsx
import { useCallback } from 'react';

const LanguageMap = {
  en: En,
  zh: Zh,
};

const useTranslation = () => {
  const router = useRouter();
  const jsonFun = useCallback(
    (key, params = {}) => {
      // 获取当前的语言包里面key所对应的value值
      let value = LanguageMap[router.locale][key]; 
      
      /*
		如果传key进来,或者没有找到value,就直接返回key就好了,
		页面上就显示key,方便找到漏翻译的字段	
	  */
      if (!key || !value) return key; 
      
      /*
		这里是为了能够让我们写的hook能支持传参,比如找到的value为'{name}
		今年{age}岁啦~',这里的nameg和age都是为参数,也就是后面可以这种
		形式传进来:
		const { t } = useTranslation()
		<div>{ t('app.message',{name:"张三", age:18}) }</div>
		// 翻译后的结果就是
		<div>张三今年18岁啦~</div>
	  */
      Object.keys(params).forEach(item => {
        value = value.replace(new RegExp(`{${item}}`, 'g'), params[item]);
      });
      return value;
    },
    [router.locale]
  );
  return {
    t: jsonFun,
  };
};

export default useTranslation;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

然后利用next内置的Link组建进行切换:

import { useRouter } from 'next/router';
import Link from 'next/link';
import { useTranslation } from '@/utils/hooks';

const APP = () => {

	const { t } = useTranslation();
	const { locale, asPath } = useRouter();
	const LanguagesMenu = useMemo(() => {
	    return (
	      <Menu
	        items={[
	          {
	            key: 'en',
	            label: (
	              <Link href={`/en${asPath}`} locale="en">
	                Engilsh
	              </Link>
	            ),
	            disabled: locale === 'en',
	          },
	          {
	            key: 'zh',
	            label: (
	              <Link href={asPath} locale="zh">
	                中文
	              </Link>
	            ),
	            disabled: locale === 'zh',
	          },
	        ]}
	      />
	    );
	  }, [asPath, locale]);
	
		// ReactNode
	return	(<Dropdown
	          overlay={LanguagesMenu}
	          placement="bottom"
	          trigger={['hover']}
	        >
	          <div className={styles.name} onClick={e => e.preventDefault()}>
	            {locale === 'en' ? 'English' : '中文'}
	          </div>
	        </Dropdown>)

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

最后再看下效果吧:
当然我这里是将 / 作为zh的路径
在这里插入图片描述

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号