使用您最喜欢的AI助手总结文档,并引用此页面和AI提供商
通过将 Intlayer MCP 服务器集成到您的 AI 助手,您可以直接从 ChatGPT、DeepSeek、Cursor、VSCode 等获取所有文档。
查看 MCP 服务器文档此文档已过期,基础版本已在以下日期更新 2025年11月18日.
前往英文文档版本历史
- Add step 13: Retrieve the locale in your server actions (Optional)v7.3.92025/12/5
- 为 Tanstack Start 添加支持v5.8.12025/9/9
此页面的内容已使用 AI 翻译。
查看英文原文的最新版本如果您有改善此文档的想法,请随时通过在GitHub上提交拉取请求来贡献。
文档的 GitHub 链接复制文档 Markdown 到剪贴板
使用Intlayer翻译您的Tanstack Start | 国际化(i18n)
目录
本指南演示如何在 Tanstack Start 项目中集成 Intlayer,实现无缝国际化,支持基于区域设置的路由、TypeScript 支持以及现代开发实践。
什么是 Intlayer?
Intlayer 是一个创新的开源国际化(i18n)库,旨在简化现代 Web 应用中的多语言支持。
使用 Intlayer,您可以:
- 通过组件级声明式字典轻松管理翻译。
- 动态本地化元数据、路由和内容。
- 通过自动生成的类型确保 TypeScript 支持,提升自动补全和错误检测能力。
- 享受高级功能,如动态区域设置检测和切换。
- 通过 Tanstack Start 的基于文件的路由系统启用区域设置感知路由。
在 Tanstack Start 应用中设置 Intlayer 的分步指南
在 GitHub 上查看应用程序模板。
第一步:创建项目
首先,按照 TanStack Start 网站上的新建项目指南创建一个新的 TanStack Start 项目。
第二步:安装 Intlayer 包
使用您喜欢的包管理器安装所需的包:
npm install intlayer react-intlayernpm install vite-intlayer --save-devintlayer
react-intlayer
将 Intlayer 集成到 React 应用中的包。它为 React 国际化提供上下文提供者和钩子。vite-intlayer
包含用于将 Intlayer 集成到Vite 打包器的 Vite 插件,以及用于检测用户首选语言、管理 Cookie 和处理 URL 重定向的中间件。
第三步:项目配置
创建一个配置文件来配置您的应用程序语言:
复制代码到剪贴板
import type { IntlayerConfig } from "intlayer";import { Locales } from "intlayer";const config: IntlayerConfig = { internationalization: { defaultLocale: Locales.ENGLISH, locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH], },};export default config;通过此配置文件,您可以设置本地化 URL、中间件重定向、cookie 名称、内容声明的位置和扩展名、禁用控制台中的 Intlayer 日志等。有关可用参数的完整列表,请参阅配置文档。
第4步:在您的 Vite 配置中集成 Intlayer
将 intlayer 插件添加到您的配置中:
复制代码到剪贴板
import { tanstackStart } from "@tanstack/react-start/plugin/vite";import viteReact from "@vitejs/plugin-react";import { nitro } from "nitro/vite";import { defineConfig } from "vite";import { intlayer } from "vite-intlayer";import viteTsConfigPaths from "vite-tsconfig-paths";const config = defineConfig({ plugins: [ nitro(), viteTsConfigPaths({ projects: ["./tsconfig.json"], }), tanstackStart(), viteReact(), intlayer(), // To add ],});export default config;intlayer() Vite 插件用于将 Intlayer 集成到 Vite 中。它确保构建内容声明文件并在开发模式下监视它们。它在 Vite 应用中定义了 Intlayer 环境变量。此外,它还提供别名以优化性能。
第5步:创建布局组件
设置您的根布局和特定语言环境的布局:
根布局
复制代码到剪贴板
import { createFileRoute, Outlet } from "@tanstack/react-router";import { IntlayerProvider, useLocale } from "react-intlayer";import { useI18nHTMLAttributes } from "@/hooks/useI18nHTMLAttributes";export const Route = createFileRoute("/{-$locale}")({ component: LayoutComponent,});function LayoutComponent() { const { defaultLocale } = useLocale(); const { locale } = Route.useParams(); return ( <IntlayerProvider locale={locale ?? defaultLocale}> <Outlet /> </IntlayerProvider> );}第6步:声明您的内容
创建并管理您的内容声明以存储翻译:
复制代码到剪贴板
import type { Dictionary } from "intlayer";import { t } from "intlayer";const appContent = { content: { links: { about: t({ zh: "关于", en: "About", es: "Acerca de", fr: "À propos", }), home: t({ zh: "首页", en: "Home", es: "Inicio", fr: "Accueil", }), }, meta: { description: t({ zh: "这是一个使用 Intlayer 和 TanStack Router 的示例", en: "This is an example of using Intlayer with TanStack Router", es: "Este es un ejemplo de uso de Intlayer con TanStack Router", fr: "Ceci est un exemple d'utilisation d'Intlayer avec TanStack Router", }), }, title: t({ zh: "欢迎使用 Intlayer + TanStack Router", en: "Welcome to Intlayer + TanStack Router", es: "Bienvenido a Intlayer + TanStack Router", fr: "Bienvenue à Intlayer + TanStack Router", }), }, key: "app",} satisfies Dictionary;export default appContent;您的内容声明可以在应用程序中的任何位置定义,只要它们被包含在 contentDir 目录中(默认是 ./app)。并且文件扩展名需匹配内容声明文件扩展名(默认是 .content.{json,ts,tsx,js,jsx,mjs,mjx,cjs,cjx})。
更多详情,请参阅内容声明文档。
第7步:创建支持多语言的组件和钩子
创建一个用于多语言导航的 LocalizedLink 组件:
复制代码到剪贴板
import type { FC } from "react";import { Link, type LinkComponentProps } from "@tanstack/react-router";import { useLocale } from "intlayer";export const LOCALE_ROUTE = "{-$locale}" as const;// 主要工具类型export type RemoveLocaleParam<T> = T extends string ? RemoveLocaleFromString<T> : T;export type To = RemoveLocaleParam<LinkComponentProps["to"]>;type CollapseDoubleSlashes<S extends string> = S extends `${infer H}//${infer T}` ? CollapseDoubleSlashes<`${H}/${T}`> : S;type LocalizedLinkProps = { to?: To;} & Omit<LinkComponentProps, "to">;// 辅助类型type RemoveAll< S extends string, Sub extends string,> = S extends `${infer H}${Sub}${infer T}` ? RemoveAll<`${H}${T}`, Sub> : S;type RemoveLocaleFromString<S extends string> = CollapseDoubleSlashes< RemoveAll<S, typeof LOCALE_ROUTE>>;export const LocalizedLink: FC<LocalizedLinkProps> = (props) => { const { locale } = useLocale(); const { localePrefix } = getPrefix(locale); return ( <Link {...props} params={{ locale: localePrefix, ...(typeof props?.params === "object" ? props?.params : {}), }} to={`/${LOCALE_ROUTE}${props.to}` as LinkComponentProps["to"]} /> );};该组件有两个目标:
- 移除 URL 中不必要的 {-$locale} 前缀。
- 将 locale 参数注入 URL,确保用户被直接重定向到本地化路由。
接下来我们可以创建一个用于编程导航的 useLocalizedNavigate 钩子:
复制代码到剪贴板
import { useLocale } from "react-intlayer";import { useNavigate } from "@tanstack/react-router";import { LOCALE_ROUTE } from "@/components/localized-link";import type { FileRouteTypes } from "@/routeTree.gen";export const useLocalizedNavigate = () => { const navigate = useNavigate(); const { locale } = useLocale(); type StripLocalePrefix<T extends string> = T extends | `/${typeof LOCALE_ROUTE}` | `/${typeof LOCALE_ROUTE}/` ? "/" // 去除本地化前缀后返回根路径 : T extends `/${typeof LOCALE_ROUTE}/${infer Rest}` ? `/${Rest}` // 去除本地化前缀后返回剩余路径 : never; type LocalizedTo = StripLocalePrefix<FileRouteTypes["to"]>; interface LocalizedNavigate { (to: LocalizedTo): ReturnType<typeof navigate>; ( opts: { to: LocalizedTo } & Record<string, unknown> ): ReturnType<typeof navigate>; } const localizedNavigate: LocalizedNavigate = (args: any) => { if (typeof args === "string") { return navigate({ to: `/${LOCALE_ROUTE}${args}`, params: { locale } }); } const { to, ...rest } = args; const localedTo = `/${LOCALE_ROUTE}${to}` as any; return navigate({ to: localedTo, params: { locale, ...rest } as any }); }; return localizedNavigate;};第8步:在您的页面中使用 Intlayer
在整个应用程序中访问您的内容字典:
本地化首页
复制代码到剪贴板
import { createFileRoute } from "@tanstack/react-router";import { getIntlayer } from "intlayer";import { useIntlayer } from "react-intlayer";import LocaleSwitcher from "@/components/locale-switcher";import { LocalizedLink } from "@/components/localized-link";import { useLocalizedNavigate } from "@/hooks/useLocalizedNavigate";export const Route = createFileRoute("/{-$locale}/")({ component: RouteComponent, head: ({ params }) => { const { locale } = params; const metaContent = getIntlayer("app", locale); return { meta: [ { title: metaContent.title }, { content: metaContent.meta.description, name: "description" }, ], }; },});function RouteComponent() { const content = useIntlayer("app"); const navigate = useLocalizedNavigate(); return ( <div> <div> {content.title} <LocaleSwitcher /> <div> <LocalizedLink to="/">{content.links.home}</LocalizedLink> <LocalizedLink to="/about">{content.links.about}</LocalizedLink> </div> <div> <button onClick={() => navigate({ to: "/" })}> {content.links.home} </button> <button onClick={() => navigate({ to: "/about" })}> {content.links.about} </button> </div> </div> </div> );}要了解更多关于 useIntlayer 钩子的内容,请参阅文档。
第9步:创建语言切换组件
创建一个组件,允许用户切换语言:
复制代码到剪贴板
import type { FC } from "react";import { useLocation } from "@tanstack/react-router";import { getHTMLTextDir, getLocaleName, getPathWithoutLocale, getPrefix, Locales,} from "intlayer";import { useLocale } from "react-intlayer";import { LocalizedLink, To } from "./localized-link";export const LocaleSwitcher: FC = () => { const { pathname } = useLocation(); const { availableLocales, locale, setLocale } = useLocale(); const pathWithoutLocale = getPathWithoutLocale(pathname); // 获取不带语言前缀的路径 return ( <ol> {availableLocales.map((localeEl) => ( <li key={localeEl}> <LocalizedLink aria-current={localeEl === locale ? "page" : undefined} onClick={() => setLocale(localeEl)} params={{ locale: getPrefix(localeEl).localePrefix }} to={pathWithoutLocale as To} // 跳转到不带语言前缀的路径 > <span> {/* 语言环境 - 例如 FR */} {localeEl} </span> <span> {/* 语言在其自身语言环境中的名称 - 例如 Français */} {getLocaleName(localeEl, locale)} </span> <span dir={getHTMLTextDir(localeEl)} lang={localeEl}> {/* 语言在当前语言环境中的名称 - 例如当前语言环境为 Locales.SPANISH 时显示 Francés */} {getLocaleName(localeEl)} </span> <span dir="ltr" lang={Locales.ENGLISH}> {/* 语言的英文名称 - 例如 French */} {getLocaleName(localeEl, Locales.ENGLISH)} </span> </LocalizedLink> </li> ))} </ol> );};要了解有关 useLocale 钩子的更多信息,请参阅文档。
第10步:添加 HTML 属性管理(可选)
创建一个钩子来管理 HTML 的 lang 和 dir 属性:
复制代码到剪贴板
// src/hooks/useI18nHTMLAttributes.tsximport { getHTMLTextDir } from "intlayer";import { useEffect } from "react";import { useLocale } from "react-intlayer";export const useI18nHTMLAttributes = () => { const { locale } = useLocale(); useEffect(() => { document.documentElement.lang = locale; document.documentElement.dir = getHTMLTextDir(locale); }, [locale]);};然后在你的根组件中使用它:
复制代码到剪贴板
import { createFileRoute, Outlet } from "@tanstack/react-router";import { IntlayerProvider, useLocale } from "react-intlayer";import { useI18nHTMLAttributes } from "@/hooks/useI18nHTMLAttributes"; // 导入钩子export const Route = createFileRoute("/{-$locale}")({ component: LayoutComponent,});function LayoutComponent() { useI18nHTMLAttributes(); // 添加此行 const { defaultLocale } = useLocale(); const { locale } = Route.useParams(); return ( <IntlayerProvider locale={locale ?? defaultLocale}> <Outlet /> </IntlayerProvider> );}第11步:添加中间件(可选)
您还可以使用 intlayerProxy 为您的应用程序添加服务器端路由。该插件将根据 URL 自动检测当前语言环境,并设置相应的语言环境 Cookie。如果未指定语言环境,插件将根据用户浏览器的语言偏好确定最合适的语言环境。如果未检测到语言环境,它将重定向到默认语言环境。
注意,要在生产环境中使用 intlayerProxy,您需要将 vite-intlayer 包从 devDependencies 切换到 dependencies。
复制代码到剪贴板
import { reactRouter } from "@react-router/dev/vite";import tailwindcss from "@tailwindcss/vite";import { defineConfig } from "vite";import { intlayer, intlayerProxy } from "vite-intlayer";import tsconfigPaths from "vite-tsconfig-paths";export default defineConfig({ plugins: [ intlayerProxy(), // 如果使用 Nitro,代理应放在服务器之前 tailwindcss(), reactRouter(), tsconfigPaths(), intlayer(), ],});第12步:国际化您的元数据(可选)
您还可以使用 getIntlayer 钩子在整个应用程序中访问您的内容字典:
复制代码到剪贴板
import { createFileRoute } from "@tanstack/react-router";import { getIntlayer } from "intlayer";export const Route = createFileRoute("/{-$locale}/")({ component: RouteComponent, head: ({ params }) => { const { locale } = params; const metaContent = getIntlayer("page-metadata", locale); return { meta: [ { title: metaContent.title }, { content: metaContent.description, name: "description" }, ], }; },});Step 13: Retrieve the locale in your server actions (Optional)
You may want to access the current locale from inside your server actions or API endpoints. You can do this using the getLocale helper from intlayer.
Here's an example using TanStack Start's server functions:
复制代码到剪贴板
import { createServerFn } from "@tanstack/react-start";import { getRequestHeader, getRequestHeaders,} from "@tanstack/react-start/server";import { getCookie, getIntlayer, getLocale } from "intlayer";export const getLocaleServer = createServerFn().handler(async () => { const locale = await getLocale({ // Get the cookie from the request (default: 'INTLAYER_LOCALE') getCookie: (name) => { const cookieString = getRequestHeader("cookie"); return getCookie(name, cookieString); }, // Get the header from the request (default: 'x-intlayer-locale') // Fallback using Accept-Language negotiation getHeader: (name) => getRequestHeader(name), }); // Retrieve some content using getIntlayer() const content = getIntlayer("app", locale); return { locale, content };});第14步:配置 TypeScript(可选)
Intlayer 使用模块增强来利用 TypeScript 的优势,使您的代码库更健壮。
确保您的 TypeScript 配置包含自动生成的类型:
复制代码到剪贴板
{ // ... 您现有的配置 include: [ // ... 您现有的包含项 ".intlayer/**/*.ts", // 包含自动生成的类型 ],}Git 配置
建议忽略 Intlayer 生成的文件。这样可以避免将它们提交到您的 Git 仓库中。
要做到这一点,您可以将以下指令添加到您的 .gitignore 文件中:
复制代码到剪贴板
# 忽略 Intlayer 生成的文件.intlayerVS Code 扩展
为了提升您使用 Intlayer 的开发体验,您可以安装官方的 Intlayer VS Code 扩展。
该扩展提供:
- 翻译键的自动补全。
- 缺失翻译的实时错误检测。
- 翻译内容的内联预览。
- 轻松创建和更新翻译的快速操作。
有关如何使用该扩展的更多详细信息,请参阅Intlayer VS Code 扩展文档。
深入探索
要进一步使用,您可以实现可视化编辑器或使用内容管理系统(CMS)将内容外部化。
文档参考
本综合指南提供了将 Intlayer 与 Tanstack Start 集成所需的一切,支持完全国际化的应用程序,具备基于区域设置的路由和 TypeScript 支持。