终于还是吃上了react-i18next的细糠

背景

除了经常访问我网站的朋友,几乎就没人知道,我其实一直在做 ElasticSearch 文档的中文翻译,虽然不知道到底能帮助多少人,但既然已经坚持四年了,从 7.11 版本翻译到现在 9.x 版本,我就准备继续坚持下去。

在文档翻译过程中,我最开始的做法,是复制内容到百度翻译一类的网站上进行翻译,然后自己校对,调整格式,保存文档,发布到网站上。

后来,我找到一款比较好用的翻译工具 pot。这款工具很好用,适当减轻了一些工作量,但也只是让我不用去翻译网站上操作。

我翻译文档最大困难,在于翻译过程中,不能保留原网页的格式,我只能一段段翻译,再自己整理为 Markdown 格式,非常浪费时间。

在之前的文章《一种Tauri+NextJS国际化方案》中,我提到我们在开发一款 AI 应用。虽然它胎死腹中,但还是多少给互联网留下了一些电子垃圾。🤣

在文章中我还提到,我自己吃不来 react-i18next 的细糠,所以只能先撸了一个国际化方案来应急解决国际化问题。

我就想复用之前的开发经验,开发一款可以直接将网页翻译为指定 Markdown 格式文档的 AI 工具,这样我复制出翻译结果,就能直接保存为 Docusaurus 能解析的文档,效率倍增!

这次开发同样采用了 Tauri + Next.JS 架构,国际化也先复用了之前的文章中的经验。但应用初步开发出来后,我发现切换页面时,页面会出现闪动,会闪现未翻译的原始 key,非常难看。

AI help AI!

于是,我再次寻求 AI 帮助。可能得益于 AI 模型的升级,这次 DeepSeek 在"调教"下给出了一个基于 next-i18next 的可用方案,真是让我等对前端不熟悉的人觉得香死了。以下记录方案实施方法。

解决方案

1. 目标

  • Tauri 应用中前端页面实现国际化切换功能

2. 场景

  • 纯客户端的场景(Tauri 中无法使用 NextjsSSR)。
  • NextjsAppRouter 模式)

已基于 TauriNextjs 开发了可运行的应用。

3. 安装依赖

bash 复制代码
npm install i18next react-i18next i18next-browser-languagedetector

4. 目录结构示例

  • i18n.ts 国际化配置文件
  • locales 国际化翻译 json 文件
  • layout.tsx 动态加载 i18n 对象

5. 关键文件示例

i18n.ts

tsx 复制代码
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";

import en from "../../locales/en.json";
import zh from "../../locales/zh.json";
import { TauriAdapter } from "../utils/utils";

const adapter = new TauriAdapter();

export async function initI18n() {
  // 从配置文件读取语言设置
  const config = await adapter.readAppData();
  const locale = config.locale || "zh";

  i18n
    .use(LanguageDetector)
    .use(initReactI18next)
    .init({
      resources: {
        en: { translation: en },
        zh: { translation: zh },
      },
      lng: locale,
      fallbackLng: "zh",
      interpolation: {
        escapeValue: false,
      },
    });

  return i18n;
}

export default i18n;

const config = await adapter.readAppData(); 是我自己实现的从配置文件读取当前语言的方法,如果你是其他方式读取语言,需要换成你自己的实现。

同时在以上配置项 resources 里需要把支持的语言都列出。

zh.json

json 复制代码
{
  "locales": {
    "zh": "中文",
    "en": "English"
  }
}

json 格式的翻译文字。

layout.tsx

tsx 复制代码
"use client";
import { useEffect, useState } from "react";
import { I18nextProvider } from "react-i18next";
import "./globals.css";
import "./lib/i18n"; // 导入 i18n 配置
import { initI18n } from "./lib/i18n";

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  const [i18nInstance, setI18nInstance] = useState<any>(null);

  useEffect(() => {
    const initializeApp = async () => {
      try {
        const i18n = await initI18n();
        setI18nInstance(i18n);
      } catch (error) {
        console.error("Failed to initialize i18n:", error);
      }
    };

    initializeApp();
  }, []);

  return (
    <html lang="en">
      <body className={`antialiased`}>
        {i18nInstance ? (
          <I18nextProvider i18n={i18nInstance}>
            {children}
          </I18nextProvider>
        ) : (
          <div
            data-tauri-drag-region
            className="flex flex-col justify-center items-center h-screen"
          >
            <span className="loading loading-dots loading-xl text-primary h-[156px]"></span>
          </div>
        )}
      </body>
    </html>
  );
}

layout.tsx 中使用国际化的 Provider,并动态加载 i18n 对象。

在文件中使用

tsx 复制代码
const { t } = useTranslation();
....

<h1 className="text-[clamp(2rem,5vw,3rem)] font-bold text-gray-800 mb-4 text-center">
            {t("app_name")}
</h1>

语言切换

在我们自己实现的语言切换选择器中,当选中新语言后,使用以下逻辑进行语言变更:

tsx 复制代码
const { i18n, t } = useTranslation();
......
i18n.changeLanguage(newLang);

而语言变更后的国际化,就需要自己处理了。比如在 Tauri 中,目前我是将语言存储在配置文件中。

6.扩展

在以上实现中,我们知道页面上的国际化其实是依赖于全局 layout.tsx 中的国际化 Provider 支持的。但比如在 Tauri 中,还存在独立页面,比如独立的系统托盘菜单。

这种页面是没法依赖 Provider 来使用 t("app_name") 来实现国际化的,但可以通过引入 i18n 对象来实现。如下:

tsx 复制代码
import i18n from "./lib/i18n";
......
i18n.t("translation.clipboard.conflict")

小记

作为非专业的前端,在 AI 帮助下解决了国际化的问题,我觉得值得记下此方案,以备日后复用。

相关推荐
米方2 小时前
ElementPlus 穿梭框支持批量穿梭
前端·javascript·vue.js
InkHeart2 小时前
uni-app开发路上的坑
前端·vue.js
用户4099322502122 小时前
Vue3中v-bind:class与v-bind:style如何实现条件样式、组件样式合并与深层响应式管理?
前端·ai编程·trae
我是天龙_绍2 小时前
如何在前端开发中高效运用AI:从提效到避坑
前端
KenXu2 小时前
从Vue 到 React:Valtio 让状态管理更熟悉
前端
努力学习的少女2 小时前
对SparkRDD的认识
开发语言·前端·javascript
LYFlied2 小时前
Webpack 深度解析:从原理到工程实践
前端·面试·webpack·vite·编译原理·打包·工程化
苏打水com3 小时前
第十二篇:Day34-36 前端工程化进阶——从“单人开发”到“团队协作”(对标职场“大型项目协作”需求)
前端·javascript·css·vue.js·html
知了清语3 小时前
为天地图 JavaScript API v4.0 提供 TypeScript 类型支持 —— tianditu-v4-types 正式发布!
前端