Remix实现多语言

JS 中不同框架都有自己的多语言库,在 Remix 使用多语言,需要安装 remix-i18next 这个库。这个包是基于 i18next 开发的,使用方式可以到官网查看。 Remix-i18next 安装步骤如下:

安装依赖

npm install remix-i18next i18next react-i18next i18next-browser-languagedetector i18next-http-backend i18next-fs-backend

创建语言文件

创建英文和中文的语言文件。

public/locales/en/common.json

{"greeting": "Hello"
}

public/locales/zh/common.json

{"greeting": "你好"
}

i18n 配置文件

app/i18n.ts

export default {// 这是您的应用程序支持的语言列表supportedLngs: ["en", "zh"],// 如果用户的语言不在 supportedLngs 中,// 您希望使用的默认语言fallbackLng: "zh",// i18next 的默认命名空间是 "translation",// 但您可以在这里自定义defaultNS: "common",
};

app/i18next.server.ts

import Backend from "i18next-fs-backend";  // 导入 i18next 文件系统后端
import { resolve } from "node:path";       // 导入 node 的 path 解析函数
import { RemixI18Next } from "remix-i18next/server";  // 导入 Remix 的 i18next 服务器端模块
import i18n from "~/i18n"; // 导入您的 i18n 配置文件let i18next = new RemixI18Next({detection: {supportedLanguages: i18n.supportedLngs,  // 支持的语言列表fallbackLanguage: i18n.fallbackLng,      // 默认回退语言},// 以下是仅在服务器端翻译消息时使用的 i18next 配置i18next: {...i18n,backend: {loadPath: resolve("./public/locales/{{lng}}/{{ns}}.json"),  // 指定翻译文件加载路径},},// 您希望 RemixI18next 在 loaders 和 actions 中通过 `i18n.getFixedT` 使用的 i18next 插件。// 例如:文件系统后端插件用于从文件系统加载翻译// 提示:您可以将 `resources` 传递给 `i18next` 配置并在此处避免使用后端plugins: [Backend],
});export default i18next;  // 导出 i18next 配置

Remix Client

app/entry.client.tsx

import { RemixBrowser } from "@remix-run/react";
import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";
import i18n from "./i18n";
import i18next from "i18next";
import { I18nextProvider, initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import Backend from "i18next-http-backend";
import { getInitialNamespaces } from "remix-i18next/client";async function hydrate() {await i18next.use(initReactI18next) // 告诉 i18next 使用 react-i18next 插件.use(LanguageDetector) // 设置客户端语言检测.use(Backend) // 配置您的后端.init({...i18n, // 展开配置// 此功能检测您的路由在服务端渲染时使用的命名空间ns: getInitialNamespaces(),backend: { loadPath: "/locales/{{lng}}/{{ns}}.json" },detection: {// 这里仅启用 htmlTag 检测, 我们将仅在服务器端使用 remix-i18next 检测语言// 通过使用 `<html lang>` 属性,我们可以通知客户端服务器端检测到的语言order: ["htmlTag"],// 因为我们只使用 htmlTag,没有理由在浏览器上缓存语言,所以我们禁用它caches: [],},});startTransition(() => {hydrateRoot(document,<I18nextProvider i18n={i18next}><StrictMode><RemixBrowser /></StrictMode></I18nextProvider>,);});
}if (window.requestIdleCallback) {window.requestIdleCallback(hydrate);
} else {// Safari 不支持 requestIdleCallback// https://caniuse.com/requestidlecallbackwindow.setTimeout(hydrate, 1);
}

Remix Server

app/entry.server.tsx

import { PassThrough } from "stream";
import {createReadableStreamFromReadable,type EntryContext,
} from "@remix-run/node";
import { RemixServer } from "@remix-run/react";
import { isbot } from "isbot";
import { renderToPipeableStream } from "react-dom/server";
import { createInstance } from "i18next";
import i18next from "./i18next.server";
import { I18nextProvider, initReactI18next } from "react-i18next";
import Backend from "i18next-fs-backend";
import i18n from "./i18n"; // 你的 i18n 配置文件
import { resolve } from "node:path";const ABORT_DELAY = 5000;  // 终止延迟时间export default async function handleRequest(request: Request,responseStatusCode: number,responseHeaders: Headers,remixContext: EntryContext,
) {let callbackName = isbot(request.headers.get("user-agent"))? "onAllReady"  // 当所有内容准备就绪时: "onShellReady";  // 当外壳准备就绪时let instance = createInstance();let lng = await i18next.getLocale(request);  // 获取请求的语言环境let ns = i18next.getRouteNamespaces(remixContext);  // 获取即将渲染的路由的命名空间await instance.use(initReactI18next) // 告诉我们的实例使用 react-i18next.use(Backend) // 设置我们的后端.init({...i18n, // 展开配置lng, // 我们上面检测到的语言环境ns, // 路由想要使用的命名空间backend: { loadPath: resolve("./public/locales/{{lng}}/{{ns}}.json") },  // 加载路径});return new Promise((resolve, reject) => {let didError = false;let { pipe, abort } = renderToPipeableStream(<I18nextProvider i18n={instance}><RemixServer context={remixContext} url={request.url} /></I18nextProvider>,{[callbackName]: () => {let body = new PassThrough();const stream = createReadableStreamFromReadable(body);responseHeaders.set("Content-Type", "text/html");  // 设置内容类型resolve(new Response(stream, {headers: responseHeaders,status: didError ? 500 : responseStatusCode,}),);pipe(body);},onShellError(error: unknown) {  // 外壳错误处理reject(error);},onError(error: unknown) {  // 错误处理didError = true;console.error(error);  // 打印错误信息},},);setTimeout(abort, ABORT_DELAY);  // 设置终止时间});
}

修改入口文件

修改 root.tsx 文件,添加 i18n相关配置。

import { useChangeLanguage } from "remix-i18next/react";
import { useTranslation } from "react-i18next";
import i18next from "~/i18next.server";export async function loader({ request }: LoaderArgs) {let locale = await i18next.getLocale(request);return json({ locale });
}export let handle = {// In the handle export, we can add a i18n key with namespaces our route// will need to load. This key can be a single string or an array of strings.// TIP: In most cases, you should set this to your defaultNS from your i18n config// or if you did not set one, set it to the i18next default namespace "translation"i18n: "common",
};export default function Root() {// Get the locale from the loaderlet { locale } = useLoaderData<typeof loader>();let { i18n } = useTranslation();// This hook will change the i18n instance language to the current locale// detected by the loader, this way, when we do something to change the// language, this locale will change and i18next will load the correct// translation filesuseChangeLanguage(locale);return (<html lang={locale} dir={i18n.dir()}><head><Meta /><Links /></head><body><Outlet /><ScrollRestoration /><Scripts /><LiveReload /></body></html>);
}

把 t 方法引进来直接使用即可。

let { i18n, t} = useTranslation();

配置生效

在这里插入图片描述
更多的用法可以参考官网,例如在语言文件中添加参数。

#配置文件
en: {translation: {greeting: "Hello, {{name}}! Welcome to our website."}}
# 参数
t 将参数传入
t('greeting', { name: userName });    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/8974.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

go导入包时提示no required module provides package解决方法

原因&#xff0c;这个包在你的本机没有安装 如redis包的提示为 could not import github.com/gomodule/redigo/redis (no required module provides package "github.com/gomodule/redigo/redis")解决方法&#xff1a; go get github.com/gomodule/redigo/redis

easy_signin_ctfshow_2023愚人杯

https://ctf.show/challenges#easy_signin-3967 2023愚人杯信息检索&#xff0c;在请求荷载中发现一个base64 face.pngencode ZmFjZS5wbmc解密结果 flag.pngencode ZmxhZy5wbmc尝试一下 返回内容 Warning: file_get_contents(flag.png): failed to open stream: No such file…

压缩和归档库-LZ4介绍

1.简介 LZ4是一种快速的压缩算法&#xff0c;提供压缩和解压缩的速度&#xff0c;而牺牲了压缩率。它被设计用于快速的数据压缩和解压缩&#xff0c;特别是用于数据存储和传输。LZ4通常用于需要高速数据处理的场景&#xff0c;如数据库、日志文件处理和实时数据传输。 LZ4的特…

[NSSRound#1 Basic]basic_check

[NSSRound#1 Basic]basic_check 开题什么都没有&#xff0c;常规信息搜集也无效 发现题目允许PUT的两种做法&#xff1a; 1、 CURL的OPTIONS请求方法查看允许的请求方式 curl -v -X OPTIONS http://node4.anna.nssctf.cn:28545/index.php2、 kali自带的nikto工具扫描网址 Nik…

DetCLIPv3:面向多功能生成开放词汇的目标检测

DetCLIPv3:面向多功能生成开放词汇的目标检测 摘要IntroductionRelated worksMethod DetCLIPv3: Towards Versatile Generative Open-vocabulary Object Detection 摘要 现有的开词汇目标检测器通常需要用户预设一组类别&#xff0c;这大大限制了它们的应用场景。在本文中&…

新能源汽车充电站智慧充电电能服务综合解决方案

安科瑞薛瑶瑶18701709087/17343930412 ★解决方案 ✔目的地充电-EMS微电网平台 基于EMS解决方案从设备运维的角度解决本地充电的能量管理及运维问题&#xff0c;与充电管理平台打通数据&#xff0c;为企业微电网提供源、网、荷、储、充一体化解决方案。 ✔运营场站--电能服务…

python3有serial库吗

一、概述 pyserial模块封装了对串口的访问。 二、特性 在支持的平台上有统一的接口。 通过python属性访问串口设置。 支持不同的字节大小、停止位、校验位和流控设置。 可以有或者没有接收超时。 类似文件的API&#xff0c;例如read和write&#xff0c;也支持readline等…

基于Detectron2的计算机视觉实践

书籍&#xff1a;Hands-On Computer Vision with Detectron2: Develop object detection and segmentation models with a code and visualization approach 作者&#xff1a;Van Vung Pham&#xff0c;Tommy Dang 出版&#xff1a;Packt Publishing 书籍下载-《基于Detectr…

MySQL学习笔记11——数据备份 范式 ER模型

数据备份 & 范式 & ER模型 一、数据备份1、如何进行数据备份&#xff08;1&#xff09;备份数据库中的表&#xff08;2&#xff09;备份数据库&#xff08;3&#xff09;备份整个数据库服务器 2、如何进行数据恢复3、如何导出和导入表里的数据&#xff08;1&#xff09…

(二十一)springboot实战——Spring AI劲爆来袭

前言 本节内容是关于Spring生态新发布的Spring AI的介绍&#xff0c;Spring AI 是一个面向人工智能工程的应用框架。其目标是将 Spring 生态系统的设计原则&#xff0c;如可移植性和模块化设计&#xff0c;应用到人工智能领域&#xff0c;并推广使用普通的Java对象&#xff08…

雪球期权是什么意思?你了解雪球期权吗?

今天期权懂带你了解雪球期权是什么意思&#xff1f;你了解雪球期权吗&#xff1f;雪球期权属于场外期权的一种&#xff0c;交易的方式只能通过线下跟券商询价的方式进行&#xff0c;类似场外个股期权的交易方式。 雪球期权是什么意思&#xff1f; 雪球期权&#xff0c;顾名思义…

js逆向,参数加密js混淆

关键词 JS 混淆、源码乱码、参数动态加密 逆向目标 题目1&#xff1a;抓取所有&#xff08;5页&#xff09;机票的价格&#xff0c;并计算所有机票价格的平均值&#xff0c;填入答案。 目标网址&#xff1a;https://match.yuanrenxue.cn/match/1目标接口&#xff1a;https://ma…

SSE介绍(实现流式响应)

写在前面 本文一起来看下SSE相关内容。 1&#xff1a;SSE是什么 全称&#xff0c;server-send events&#xff0c;基于http协议&#xff0c;一次http请求&#xff0c;server端可以分批推送数据&#xff0c; 不同于websocket的全双工通信&#xff0c;SSM单向通信,一般应用于需…

如何利用IPIDEA代理IP优化数据采集效率?

一、 前言二、 IPIDEA介绍三、体验步骤四、实战训练五、结语 一、 前言 在全球化与信息化交织的当代社会&#xff0c;数据已成为驱动商业智慧与技术革新的核心引擎。网络&#xff0c;作为信息汇聚与交流的枢纽&#xff0c;不仅是人们获取知识的窗口&#xff0c;更是商业活动与技…

【数据结构】详解栈

今天我们主要来了解栈&#xff01;如果对知识点有模糊&#xff0c;可翻阅以往文章哦&#xff01; 个人主页&#xff1a;小八哥向前冲~-CSDN博客 所属专栏&#xff1a;数据结构【c语言版】_小八哥向前冲~的博客-CSDN博客 c语言专栏&#xff1a;c语言_小八哥向前冲~的博客-CSDN博…

树和二叉树的定义和基本术语

文章目录 前言一、树的定义二、树的基本术语三、二叉树的定义总结 前言 T_T此专栏用于记录数据结构及算法的&#xff08;痛苦&#xff09;学习历程&#xff0c;便于日后复习&#xff08;这种事情不要啊&#xff09;。所用教材为《数据结构 C语言版 第2版》严蔚敏。 一、树的定义…

win7开启远程桌面却连接不上,如何解决Win7系统开启远程桌面但无法连接的问题

在使用Win7系统时&#xff0c;有时候我们可能会遇到这样的问题&#xff1a;已经成功开启了远程桌面功能&#xff0c;但尝试连接时却总是失败。这可能是由于多种原因导致的&#xff0c;下面我们将详细分析并提供相应的解决方案。 确保本地网络连接正常 可以尝试通过Ping命令测试…

C++程序设计:C++的内存分布与管理

C的内存分布与管理 栈区堆区全局区代码区常量区 栈区 &#xff08;1&#xff09;什么是栈区&#xff1f; 栈区&#xff08;Stack&#xff09; 是用于存储函数调用&#xff0c;局部变量和函数参数的一种内存区域&#xff0c;它的特性就是先进后出&#xff08;FILO&#xff09;。…

Spring底层入门(七)

1、异常处理 在DispatcherServlet中&#xff0c;doDispatch(HttpServletRequest request, HttpServletResponse response) 方法用于进行任务处理&#xff1a; 在捕获到异常后没有立刻进行处理&#xff0c;而是先用一个局部变量dispatchException进行记录&#xff0c;然后统一由…

AI电视起风,三星电视打破“隔代飞跃”,在AI纪元再次领跑

作者 | 曾响铃 文 | 响铃说 要说什么是当下最热的话题&#xff0c;刚落下帷幕的北京车展一定是其中之一&#xff0c;除了各类让人眼花缭乱的新车&#xff0c;纷至沓来的各界行业大佬&#xff0c;也让车展话题度被不断拉高。在此之外&#xff0c;此次车展还刮起了一股“旋风”…