Nextjs——国际化那些事儿

背景: 某一天,产品经理跟我说,我们的产品需要搞国际化

国际化的需求说白了就是把项目中的文案翻译成不同的语言,用户想用啥语言来浏览网页就用啥语言,虽然说英语是通用语言,但国际化了嘛,产品才能更好的向全球推广(像我这种英文渣渣,看文档的时候有中文版绝对不会去翻英文(除非中文翻译得太烂))。那就开干吧

国际化在代码层面的实现上原理其实很简单,最基础的是准备好语言物料,也就是需要翻译成多少种语言,保证项目中每种语言都有对应的翻译版本,然后就是用户选择什么语言,页面就显示对应的文案,完美~

1. 用户自己解决

如果用户有翻译插件,那问题就会变得很简单,点开页面,翻译软件就能自动识别文案并翻译,没我们什么事,在chrome浏览器中,google translate就做得很好,打开很多页面的时候,google translate都能识别当前语言和系统语言是否一致,并且提供翻译提醒。但是……google translate也不是万能的,next.js网站中,使用google translate会导致网站崩溃,但后来人家也说了,这不是next的锅,锅在react那,并且已持续多年。
issue传送:Make React resilient to DOM mutations from Google Translate
google translate的兼容性都那么不好,其他的翻译插件兼容性如何也就成了未知数,为了网站的稳定性,减少网站崩溃次数,建议在head中关闭翻译功能。

<meta name="google" content="notranslate" />

2. 第三方SaaS

既然不能靠用户,那就只能自己来了,那有没有开发成本小,低代码或者零代码就能实现呢?世界人民如此聪明,当然有了。现在市面上有很多成熟的SaaS国际化软件,当时经过各种比较之后选了Weglot添加链接描述进行测试(不是广告,比较之后发现它比较好上手而已)。它的原理也比较简单:获取页面上它觉得需要进行翻译的元素,通过接口将翻译之后的内容返回并在页面上进行替换,具体的操作步骤如下:

    1. 在网站内注册,创建自己的项目,把js代码以及项目的key注入代码
// useWeglot
// 在最外层的layout或者是需要国际化的目录的根文件中使用
"use client";

import {
    useEffect } from "react";

export default function useWeglot() {
   
  useEffect(() => {
   
    const initializeWeglot = () => {
   
      if (typeof window?.Weglot !== "undefined") {
   
        window?.Weglot.initialize({
   
          api_key: "这里写你的key", 
          originalLanguage: "en",
          auto_switch_fallback: "zh",
        });
      }
    };

    const loadWeglotScript = () => {
   
      const existingScript = document.getElementById("weglot-script");
      if (!existingScript) {
   
        const script = document.createElement("script");
        script.id = "weglot-script";
        script.src = "https://cdn.weglot.com/weglot.min.js";
        script.async = true;
        script.onload = initializeWeglot;
        document.body.appendChild(script);
      } else {
   
        initializeWeglot();
      }
    };
    loadWeglotScript();
  }, []);

  return null;
}

在这里插入图片描述

    1. 自定义规则,将需要翻译和不需要翻译的部分都用规则标记上(比如class),这样翻译时它就能避开一些本来不需要翻译的部分,比如接口返回的数据
      在这里插入图片描述
      在这里插入图片描述
    1. 微调,默认都是机翻,有些翻译得不是很通顺的地方可以人工调整
      在这里插入图片描述
      如果是简单的项目,它还是很好用的,代码侵入性小,翻译之后的文本也全部都维护到weglot里,通过接口返回,需要翻译修改时直接在网站中改完实时更新,特别省事。
      但缺点也是显而易见的,首先,它免费额度不太大,项目比较大,涉及语言比较多的话价格也不便宜;其次,因为是接口返回的翻译内容,用户第一次进入页面时会先出现原本的语言,再跳到对应的语言,首次加载会闪下(可能有优化方案,知道的朋友踢我下);而且因为是代码读取元素内容,很有可能出现多翻译或者少翻的情况,在实际开发中调试也需要一定时间。

3. 自己开发

啰里八嗦了一大堆终于到了正题,经过了一系列的研究和探讨,最终决定了,自己开发!!!代码开发最主要是确认两个问题,一是系统要如何获取语言,二是系统如何跟翻译好的文本进行交互,这两个问题解决完,国际化也就完成了大半。

如何获取语言

世界上有很多很多的语言种类,国际上对语言有一个编码规范(ISO 639,有兴趣的可以了解下,比如简体中文为啥有些地方直接写zh,有时候是zh-CN),在编码的时候,也是遵循这套标准定义,规范好了,那通过什么方式告诉系统,当前是什么语言呢?通常有以下两种:

Google 建议对每种语言版本的网页使用不同的网址,而不是使用 Cookie 或浏览器设置来调整网页上的内容语言。

    1. 路由
    • 通过host获取,比如维基百科:https://zh.wikipedia.org/
    • 放在pathname中,比如MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript
    • 放在参数中,比如google开发者平台:https://developers.google.com/?hl=zh-cn
      google 对国际化网站有一些建议:
      在这里插入图片描述
    1. 缓存(cookie或者localStorage)
      从上面来看就是google不太推荐用这种形式,但它在实现上相对简单,只需要存在浏览器本地,运行时读取浏览器数据,渲染出对应的语言信息。需要注意的是,如果后端接口也需要国际化(比如一些接口报错啥的),可以使用cookie,但cookie会涉及数据隐私问题(欧盟标准),一旦用户选择不使用cookie,就不能通过cookie进行语言的切换。
如何进行翻译文本的交互

不管什么形式获取的语言,最后反应到系统程序上都是一个语言代码的形式,用户通过获取这个语言代码,将代码匹配到对应的翻译文本中,就能将对应语言的文案展示出来了。
为了方便,接下来所有文本都以这两个json文件为例:

// dictionaries/en.json
{
   
	"title":"hello world",
	"desc": {
   
		name:"xiaoqian"
	}
}

// dictionaries/zh.json
{
   
	"title":"你好",
	"desc": {
   
		name:"小千"
	}
}
// i18n-config.ts
export const i18n = {
   
    defaultLocale: 'en',
    locales: ['en', 'zh'],
  } as const
  
export type Locale = (typeof i18n)['locales'][number]


### Next.js App Router 中的国际化配置及实现 在 Next.js 的 App Router 中,可以通过 `next-intl` 或其他类似的库来实现国际化功能。以下是关于如何通过 `next-intl` 实现国际化的具体说明。 #### 配置多语言支持 为了使应用能够支持多种语言环境,首先需要创建一个多语言路由配置文件 `routing.ts` 来定义支持的语言及其默认值[^2]: ```typescript import { defineRouting } from 'next-intl/routing'; import { createNavigation } from 'next-intl/navigation'; export const routing = defineRouting({ // 定义支持的所有语言代码 locales: ['en', 'de'], // 默认语言代码 defaultLocale: 'en', }); // 创建基于导航 API 的工具函数 export const { Link, redirect, usePathname, useRouter } = createNavigation(routing); ``` 上述代码片段中,`locales` 数组列出了所有支持的语言代码,而 `defaultLocale` 则指定了当未找到匹配语言时应使用的默认语言。 #### Middleware 文件配置 为了让中间件识别并处理不同语言路径下的请求,在 `middleware.ts` 文件中需引入之前定义好的路由逻辑,并根据用户的浏览器偏好或 URL 路径动态重定向到对应语言版本的内容: ```typescript import { NextRequest, NextResponse } from 'next/server'; import { matchLocale } from 'next-intl/match-locale'; import { routing } from './lib/routing'; const publicPaths = ['/favicon.ico']; export function middleware(request: NextRequest) { if (publicPaths.includes(request.nextUrl.pathname)) return; const pathname = request.nextUrl.locale ? `/${request.nextUrl.locale}${request.nextUrl.pathname}` : request.nextUrl.pathname; const matchedLocale = matchLocale( routing.locales, request.headers.get('accept-language') || '', routing.defaultLocale ); if (!pathname.startsWith(`/${matchedLocale}`)) { const url = new URL(request.url); url.pathname = '/' + matchedLocale + (pathname === '/' ? '' : pathname.replace(/^\//, '/')) || ''; return NextResponse.redirect(url); } } ``` 此段脚本实现了检测客户端接受头字段 (`Accept-Language`) 并据此决定最佳适配语种的功能;如果当前访问地址不符合任何已知语言前缀,则执行一次跳转操作至最接近目标用户偏好的那个版本页面上去显示出来给浏览者看得到相应内容展示效果更好一点吧! #### 使用 i18n 功能 最后一步是在实际项目里调用这些预先设定好参数的方法完成整个流程闭环工作啦!比如我们可以在任意组件内部轻松获取当前所在位置以及切换链接等功能如下所示例子演示了这一点是如何做到的具体细节方面情况怎么样呢😊: ```tsx 'use client'; import React from 'react'; import { usePathname, useRouter, Link } from 'next-intl/navigation'; function LanguageSwitcher() { const router = useRouter(); const currentPathname = usePathname(); return ( <> <button onClick={() => router.push('/en' + currentPathname)}>English</button> <button onClick={() => router.push('/de' + currentPathname)}>Deutsch</button> {/* Alternatively */} <nav> <Link href="/about">About Us</Link> <Link href="/contact">Contact Us</Link> </nav> </> ); } export default LanguageSwitcher; ``` 以上展示了两种不同的方式让用户可以选择他们喜欢的语言界面呈现形式之一就是点击按钮触发事件改变URL从而达到目的另一种则是利用超链接标签直接指向特定资源位置处进行加载渲染过程当中去体验不一样的视觉盛宴享受其中乐趣无穷无尽啊😄!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值