作者:
    Creation:2024-08-11Last update:2026-05-31

    使用Intlayer翻译您的Create React App | 国际化(i18n)

    请参阅 GitHub 上的应用模板

    为什么选择 Intlayer 而不是其他方案?

    react-i18nexti18next 等主要解决方案相比,Intlayer 是一个集成了以下优化的解决方案:

    Intlayer 针对 React 进行了优化,提供 组件级内容作用域延迟加载的翻译 以及国际化 (i18n) 扩展所需的所有功能。

    无需将庞大的 JSON 文件加载到页面中,只需加载必要的内容。Intlayer 可帮助 将 bundle 和页面大小减少高达 50%

    对应用程序内容的作用域划分 便于大规模应用的维护。您可以复制或删除单个功能文件夹,而无需审查整个内容代码库的负担。此外,Intlayer 完全类型化,确保内容的准确性。

    共置内容 降低大语言模型 (LLM) 所需的上下文。Intlayer 还提供了一套工具,例如 CLI 用于测试缺失的翻译、LSPMCP 以及 agent skills,使 AI Agent 的开发者体验 (DX) 更加顺畅。

    在 CI/CD 管道中使用自动化翻译,使用您选择的 LLM,按照您的 AI 提供商的成本计费。Intlayer 还提供 编译器 以自动提取内容,以及 网络平台 来帮助 后台翻译

    将庞大的 JSON 文件连接到组件可能导致性能和响应性问题。Intlayer 在构建时优化您的内容加载。

    Intlayer 不仅是一个 i18n 解决方案,还提供 自托管 可视化编辑器完整 CMS 来帮助您 实时 管理多语言内容,使与翻译人员、文案撰写人员和其他团队成员的协作无缝进行。内容可以存储在本地和/或远程。


    在 React 应用中设置 Intlayer 的分步指南

    1. 安装依赖

      使用 npm 安装必要的包:

      bash
      npx intlayer init --interactive
      --interactive 标志是可选的。如果你是 AI 代理,请使用 intlayer-cli init
      此命令将检测你的环境并安装所需的包。例如:
      bash
      npm install intlayer react-intlayer react-scripts-intlayer
      • intlayer

        核心包,提供国际化工具用于配置管理、翻译、内容声明、转译和 CLI 命令

      • react-intlayer

        将 Intlayer 与 React 应用集成的包。它为 React 国际化提供上下文提供者和钩子。

      • react-scripts-intlayer

        包含 react-scripts-intlayer 命令和插件,用于将 Intlayer 与基于 Create React App 的应用集成。这些插件基于 craco,并包含 Webpack bundler 的额外配置。

    2. 配置你的项目

      创建一个配置文件来配置应用的语言:

      intlayer.config.ts
      import { Locales, type IntlayerConfig } from "intlayer";
      
      const config: IntlayerConfig = {
        internationalization: {
          locales: [
            Locales.ENGLISH,
            Locales.FRENCH,
            Locales.SPANISH,
            // 你的其他语言环境
          ],
          defaultLocale: Locales.ENGLISH,
        },
      };
      
      export default config;
      通过此配置文件,你可以设置本地化 URL、中间件重定向、cookie 名称、内容声明的位置和扩展名、禁用 Intlayer 控制台日志等。有关可用参数的完整列表,请参考 配置文档
    3. 在 CRA 配置中集成 Intlayer

      更改你的脚本以使用 react-intlayer

      package.json
        "scripts": {    "build": "react-scripts-intlayer build",    "start": "react-scripts-intlayer start",    "transpile": "intlayer build"  },
      react-scripts-intlayer 脚本基于 CRACO。你也可以基于 intlayer craco 插件实现自己的设置。在此查看示例
    4. 声明你的内容

      创建和管理你的内容声明以存储翻译:

      src/app.content.tsx
      import { t, type Dictionary } from "intlayer";
      import React, { type ReactNode } from "react";
      
      const appContent = {
        key: "app",
        content: {
          getStarted: t<ReactNode>({
            zh: (
              <>
                编辑 <code>src/App.tsx</code> 并保存以重新加载
              </>
            ),
            en: (
              <>
                Edit <code>src/App.tsx</code> and save to reload
              </>
            ),
            fr: (
              <>
                Éditez <code>src/App.tsx</code> et enregistrez pour recharger
              </>
            ),
            es: (
              <>
                Edita <code>src/App.tsx</code> y guarda para recargar
              </>
            ),
          }),
          reactLink: {
            href: "https://reactjs.org",
            content: t({
              zh: "学习 React",
              en: "Learn React",
              fr: "Apprendre React",
              es: "Aprender React",
            }),
          },
        },
      } satisfies Dictionary;
      
      export default appContent;
      你的内容声明可以在应用的任何地方定义,只要它们包含在 contentDir 目录中(默认为 ./src)。并匹配内容声明文件扩展名(默认为 .content.{json,ts,tsx,js,jsx,mjs,cjs,md,mdx,yaml,yml})。
      有关更多详情,请参考 内容声明文档
      如果你的内容文件包含 TSX 代码,你应该考虑在内容文件中导入 import React from "react";
    5. 在你的代码中使用 Intlayer

      在整个应用中访问你的内容字典:

      src/App.tsx
      import logo from "./logo.svg";
      import "./App.css";
      import type { FC } from "react";
      import { IntlayerProvider, useIntlayer } from "react-intlayer";
      
      const AppContent: FC = () => {
        const content = useIntlayer("app");
      
        return (
          <div className="App">
            <img src={logo} className="App-logo" alt="logo" />
      
            {content.getStarted}
            <a
              className="App-link"
              href={content.reactLink.href.value}
              target="_blank"
              rel="noopener noreferrer"
            >
              {content.reactLink.content}
            </a>
          </div>
        );
      };
      
      const App: FC = () => (
        <IntlayerProvider>
          <AppContent />
        </IntlayerProvider>
      );
      
      export default App;
      注意:如果你想在 string 属性中使用你的内容,例如 alttitlehrefaria-label 等,你可以使用函数的值,如下所示:
      html
      <img src="{content.image.src.value}" alt="{content.image.value}" /><img src="{content.image.src.toString()}" alt="{content.image.toString()}" /><img src="{String(content.image.src)}" alt="{String(content.image)}" />
      要了解有关 useIntlayer 钩子的更多信息,请参考 文档
    6. 更改你的内容的语言

      可选

      要更改你的内容的语言,你可以使用 useLocale 钩子提供的 setLocale 函数。此函数允许你设置应用的语言环境并相应地更新内容。

      src/components/LocaleSwitcher.tsx
      import { Locales } from "intlayer";
      import { useLocale } from "react-intlayer";
      
      const LocaleSwitcher = () => {
        const { setLocale } = useLocale();
      
        return (
          <button onClick={() => setLocale(Locales.English)}>更改语言为英文</button>
        );
      };
      要了解有关 useLocale 钩子的更多信息,请参考 文档
    7. 为你的应用添加本地化路由

      可选

      此步骤的目的是为每种语言创建唯一的路由。这对 SEO 和友好的 SEO URL 非常有用。 示例:

      plaintext
      - https://example.com/about- https://example.com/es/about- https://example.com/fr/about
      默认情况下,默认语言的路由没有前缀。如果你想为默认语言添加前缀,可以在配置中将 middleware.prefixDefault 选项设置为 true。有关更多信息,请参考 配置文档

      要为你的应用添加本地化路由,你可以创建一个 LocaleRouter 组件来包装应用的路由并处理基于语言环境的路由。以下是使用 React Router 的示例:

      src/components/LocaleRouter.tsx
      // 导入必要的依赖项和函数
      import { type Locales, configuration, getPathWithoutLocale } from "intlayer"; // 来自 'intlayer' 的实用函数和类型
      // 来自 'intlayer' 的实用函数和类型
      import type { FC, PropsWithChildren } from "react"; // React 函数组件和 props 的类型
      import { IntlayerProvider } from "react-intlayer"; // 国际化上下文的提供者
      import {
        BrowserRouter,
        Routes,
        Route,
        Navigate,
        useLocation,
      } from "react-router-dom"; // 用于管理导航的路由组件
      
      // 从 Intlayer 解构配置
      const { internationalization, middleware } = configuration;
      const { locales, defaultLocale } = internationalization;
      
      /**
       * 一个处理本地化并用适当的语言环境上下文包装子组件的组件。
       * 它管理基于 URL 的语言环境检测和验证。
       */
      const AppLocalized: FC<PropsWithChildren<{ locale: Locales }>> = ({
        children,
        locale,
      }) => {
        const { pathname, search } = useLocation(); // 获取当前 URL 路径
      
        // 确定当前语言环境,如果未提供则回退到默认语言
        const currentLocale = locale ?? defaultLocale;
      
        // 从路径中移除语言环境前缀以构造基本路径
        const pathWithoutLocale = getPathWithoutLocale(
          pathname // 当前 URL 路径
        );
      
        /**
         * 如果 middleware.prefixDefault 为真,默认语言应始终带有前缀。
         */
        if (middleware.prefixDefault) {
          // 验证语言环境
          if (!locale || !locales.includes(locale)) {
            // 重定向到带有更新路径的默认语言
            return (
              <Navigate
                to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
                replace // 用新项替换当前历史记录条目
              />
            );
          }
      
          // 用 IntlayerProvider 包装子组件并设置当前语言环境
          return (
            <IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
          );
        } else {
          /**
           * 当 middleware.prefixDefault 为假时,默认语言没有前缀。
           * 确保当前语言环境有效且不是默认语言。
           */
          if (
            currentLocale.toString() !== defaultLocale.toString() &&
            !locales
              .filter(
                (locale) => locale.toString() !== defaultLocale.toString() // 排除默认语言
              )
              .includes(currentLocale) // 检查当前语言环境是否在有效语言环境列表中
          ) {
            // 重定向到没有语言环境前缀的路径
            return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
          }
      
          // 用 IntlayerProvider 包装子组件并设置当前语言环境
          return (
            <IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
          );
        }
      };
      
      /**
       * 一个设置特定于语言环境的路由的路由组件。
       * 它使用 React Router 来管理导航和呈现本地化组件。
       */
      export const LocaleRouter: FC<PropsWithChildren> = ({ children }) => (
        <BrowserRouter>
          <Routes>
            {locales
              .filter(
                (locale) => middleware.prefixDefault || locale !== defaultLocale
              )
              .map((locale) => (
                <Route
                  // 路由模式以捕获语言环境(例如 /en/、/fr/)并匹配所有后续路径
                  path={`/${locale}/*`}
                  key={locale}
                  element={<AppLocalized locale={locale}>{children}</AppLocalized>} // 使用语言环境管理包装子组件
                />
              ))}
      
            {
              // 如果禁用了默认语言前缀,在根路径直接呈现子组件
              !middleware.prefixDefault && (
                <Route
                  path="*"
                  element={
                    <AppLocalized locale={defaultLocale}>{children}</AppLocalized>
                  } // 使用语言环境管理包装子组件
                />
              )
            }
          </Routes>
        </BrowserRouter>
      );

      然后,你可以在你的应用中使用 LocaleRouter 组件:

      src/App.tsx
      import { LocaleRouter } from "./components/LocaleRouter";
      import type { FC } from "react";
      
      // ... 你的 AppContent 组件
      
      const App: FC = () => (
        <LocaleRouter>
          <AppContent />
        </LocaleRouter>
      );
    8. 当语言环境更改时更改 URL

      可选

      要在语言环境更改时更改 URL,你可以使用 useLocale 钩子提供的 onLocaleChange prop。同时,你可以使用 react-router-dom 中的 useLocationuseNavigate 钩子来更新 URL 路径。

      src/components/LocaleSwitcher.tsx
      import { useLocation, useNavigate } from "react-router-dom";
      import {
        Locales,
        getHTMLTextDir,
        getLocaleName,
        getLocalizedUrl,
      } from "intlayer";
      import { useLocale } from "react-intlayer";
      import { type FC } from "react";
      
      const LocaleSwitcher: FC = () => {
        const { pathname, search } = useLocation(); // 获取当前 URL 路径。示例:/fr/about?foo=bar
        const navigate = useNavigate();
      
        const { locale, availableLocales, setLocale } = useLocale({
          onLocaleChange: (locale) => {
            // 使用更新的语言环境构造 URL
            // 示例:/es/about?foo=bar
            const pathWithLocale = getLocalizedUrl(`${pathname}${search}`, locale);
      
            // 更新 URL 路径
            navigate(pathWithLocale);
          },
        });
      
        return (
          <div>
            <button popoverTarget="localePopover">{getLocaleName(locale)}</button>
            <div id="localePopover" popover="auto">
              {availableLocales.map((localeItem) => (
                <a
                  href={getLocalizedUrl(location.pathname, localeItem)}
                  hrefLang={localeItem}
                  aria-current={locale === localeItem ? "page" : undefined}
                  onClick={(e) => {
                    e.preventDefault();
                    setLocale(localeItem);
                  }}
                  key={localeItem}
                >
                  <span>
                    {/* 语言环境 - 例如 FR */}
                    {localeItem}
                  </span>
                  <span>
                    {/* 该语言环境中的语言 - 例如 Français */}
                    {getLocaleName(localeItem, locale)}
                  </span>
                  <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>
                    {/* 当前语言环境中的语言 - 例如当前语言环境设置为 Locales.SPANISH 时的 Francés */}
                    {getLocaleName(localeItem)}
                  </span>
                  <span dir="ltr" lang={Locales.ENGLISH}>
                    {/* 英文语言 - 例如 French */}
                    {getLocaleName(localeItem, Locales.ENGLISH)}
                  </span>
                </a>
              ))}
            </div>
          </div>
        );
      };

      文档参考:

    9. 切换 HTML 语言和方向属性

      可选
    10. 当你的应用支持多种语言时,更新 <html> 标签的 langdir 属性以匹配当前语言环境至关重要。这样做可以确保:

      • 可访问性:屏幕阅读器和辅助技术依赖正确的 lang 属性来准确地发音和解释内容。
      • 文本呈现dir(方向)属性确保文本按正确的顺序呈现(例如英文的从左到右、阿拉伯语或希伯来语的从右到左),这对可读性至关重要。
      • SEO:搜索引擎使用 lang 属性来确定你页面的语言,帮助在搜索结果中提供正确的本地化内容。

      通过在语言环境更改时动态更新这些属性,你可以为所有支持的语言的用户保证一致和可访问的体验。

      实现钩子

      创建一个自定义钩子来管理 HTML 属性。该钩子监听语言环境更改并相应地更新属性:

      src/hooks/useI18nHTMLAttributes.tsx
      import { useEffect } from "react";
      import { useLocale } from "react-intlayer";
      import { getHTMLTextDir } from "intlayer";
      
      /**
       * 根据当前语言环境更新 HTML <html> 元素的 `lang` 和 `dir` 属性。
       * - `lang`:通知浏览器和搜索引擎页面的语言。
       * - `dir`:确保正确的阅读顺序(例如,英语为 'ltr',阿拉伯语为 'rtl')。
       *
       * 此动态更新对于正确的文本渲染、可访问性和 SEO 至关重要。
       */
      export const useI18nHTMLAttributes = () => {
        const { locale } = useLocale();
      
        useEffect(() => {
          // 将语言属性更新为当前语言环境。
          document.documentElement.lang = locale;
      
          // 根据当前语言环境设置文本方向。
          document.documentElement.dir = getHTMLTextDir(locale);
        }, [locale]);
      };

      在您的应用中使用钩子

      将钩子集成到您的主组件中,以便在语言环境更改时更新 HTML 属性:

      src/App.tsx
      import type { FC } from "react";
      import { IntlayerProvider, useIntlayer } from "react-intlayer";
      import { useI18nHTMLAttributes } from "./hooks/useI18nHTMLAttributes";
      import "./App.css";
      
      const AppContent: FC = () => {
        // 应用钩子以根据语言环境更新 <html> 标签的 lang 和 dir 属性。
        useI18nHTMLAttributes();
      
        // ... 组件的其他部分
      };
      
      const App: FC = () => (
        <IntlayerProvider>
          <AppContent />
        </IntlayerProvider>
      );
      
      export default App;

      通过应用这些更改,您的应用将:

      • 确保 语言 (lang) 属性正确反映当前语言环境,这对 SEO 和浏览器行为非常重要。
      • 根据语言环境调整 文本方向 (dir),提升不同阅读顺序语言的可读性和可用性。
      • 提供更 无障碍 的体验,因为辅助技术依赖这些属性以实现最佳功能。

      配置 TypeScript

      Intlayer 使用模块增强来利用 TypeScript 的优势,使您的代码库更强大。

      Autocompletion

      Translation error

      确保您的 TypeScript 配置包含自动生成的类型。

      tsconfig.json
      {  // ... 您现有的 TypeScript 配置  "include": [    // ... 您现有的 TypeScript 配置    ".intlayer/**/*.ts", // 包含自动生成的类型  ],}

      Git 配置

      建议忽略 Intlayer 生成的文件。这可以避免将它们提交到您的 Git 仓库。

      为此,您可以在 .gitignore 文件中添加以下指令:

      .gitignore
      # 忽略 Intlayer 生成的文件.intlayer

      深入了解

      要进一步了解,您可以实现 可视化编辑器 或使用 CMS 外部化您的内容。 从 VS Code Marketplace 安装

      此扩展提供:

      • 翻译键的自动补全
      • 实时错误检测,用于缺失的翻译。
      • 内联预览已翻译的内容。
      • 快速操作,轻松创建和更新翻译。

      有关如何使用此扩展的更多详细信息,请参阅Intlayer VS Code 扩展文档

      要进一步了解

      要进一步了解,您可以实现 可视化编辑器 或使用 CMS 外部化您的内容。