Tác giả:
    Ngày tạo:2025-09-04Cập nhật lần cuối:2026-06-23

    Dịch trang web React Router v7 của bạn bằng Intlayer | Quốc tế hóa (i18n)

    Hướng dẫn này trình bày cách tích hợp Intlayer để thực hiện quốc tế hóa liền mạch trong các dự án React Router v7 với định tuyến nhận biết locale, hỗ trợ TypeScript và các thực hành phát triển hiện đại.

    Đối với định tuyến phía máy khách, hãy tham khảo hướng dẫn Intlayer với React Router v7.

    Table of Contents

    Tại sao Intlayer thay thế các lựa chọn thay thế?

    So với các giải pháp chính như react-i18next hay i18next, Intlayer là giải pháp đi kèm với các tính năng tối ưu hóa tích hợp như:

    Intlayer được tối ưu hóa để hoạt động hoàn hảo với React Router bằng cách cung cấp định tuyến nhận biết ngôn ngữ, phần mềm trung gian để phát hiện ngôn ngữ và tất cả các tính năng cần thiết để mở rộng quy mô quốc tế hóa (i18n).

    Thay vì tải các tệp JSON lớn vào trang của bạn, hãy chỉ tải nội dung cần thiết. Intlayer giúp giảm tới 50% kích thước bundle và kích thước trang.

    Xác định phạm vi nội dung ứng dụng của bạn tạo điều kiện bảo trì cho các ứng dụng quy mô lớn. Bạn có thể sao chép hoặc xóa một thư mục tính năng mà không phải lo lắng về việc xem lại toàn bộ cơ sở mã nội dung của mình. Ngoài ra, Intlayer được nhập đầy đủ để đảm bảo tính chính xác cho nội dung của bạn.

    Nội dung cùng định vị giảm ngữ cảnh cần thiết của Mô hình ngôn ngữ lớn (LLM). Intlayer cũng đi kèm một bộ công cụ, chẳng hạn như CLI để kiểm tra các bản dịch bị thiếu,LSP, MCPagent skills, để giúp trải nghiệm của nhà phát triển (DX) trở nên mượt mà hơn nữa đối với các tác nhân AI.

    Sử dụng tính năng tự động hóa để dịch trong quy trình CI/CD của bạn bằng cách sử dụng LLM mà bạn chọn với chi phí do nhà cung cấp AI của bạn chi trả. Intlayer cũng cung cấp trình biên dịch để tự động trích xuất nội dung cũng như nền tảng web để giúp dịch ở chế độ nền.

    Việc kết nối các tệp JSON lớn với các thành phần có thể dẫn đến các vấn đề về hiệu suất và khả năng phản hồi. Intlayer tối ưu hóa việc tải nội dung của bạn tại thời điểm build.

    Không chỉ là giải pháp i18n, Intlayer còn cung cấp trình chỉnh sửa trực quanCMS đầy đủ để giúp bạn quản lý nội dung đa ngôn ngữ của mình trong thời gian thực, giúp việc cộng tác với người dịch, người viết quảng cáo và các thành viên khác trong nhóm trở nên liền mạch. Nội dung có thể được lưu trữ cục bộ và/hoặc từ xa.


    Hướng dẫn từng bước để thiết lập Intlayer trong ứng dụng React Router v7 với các route dựa trên hệ thống tệp

    www.youtube.com
    ide.intlayer.org
    intlayer-react-router-v7.vercel.app

    See Application Template on GitHub.

  1. Cài đặt Dependencies

    Cài đặt các package cần thiết bằng package manager ưa thích của bạn:

    bash
    npm install intlayer react-intlayer
    npm install vite-intlayer --save-dev
    npm install @react-router/fs-routes --save-dev
    npx intlayer init
    
    • intlayer

    Gói core cung cấp các công cụ quốc tế hóa để quản lý cấu hình, dịch thuật, khai báo nội dung, transpilation, và lệnh CLI.

    • react-intlayer Package tích hợp Intlayer với ứng dụng React. Nó cung cấp context providers và hooks cho quốc tế hóa React.

    • vite-intlayer Bao gồm plugin Vite để tích hợp Intlayer với Vite bundler, cũng như middleware để phát hiện ngôn ngữ ưa thích của người dùng, quản lý cookies và xử lý chuyển hướng URL.

    • @react-router/fs-routes Package cho phép định tuyến dựa trên hệ thống tệp cho React Router v7.

  2. Cấu hình dự án của bạn

  3. Tạo một file cấu hình để cấu hình các ngôn ngữ của ứng dụng của bạn:

    intlayer.config.ts
    import { type IntlayerConfig, Locales } from "intlayer";
    
    const config: IntlayerConfig = {
      internationalization: {
        defaultLocale: Locales.ENGLISH,
        locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
      },
    };
    
    export default config;
    
    Thông qua tệp cấu hình này, bạn có thể thiết lập URL theo ngôn ngữ, chuyển hướng middleware, tên cookie, vị trí và phần mở rộng của các khai báo nội dung, tắt các log của Intlayer trên console, và nhiều hơn nữa. Để xem danh sách đầy đủ các tham số có sẵn, hãy tham khảo tài liệu cấu hình.
    1. Tích hợp Intlayer vào cấu hình Vite của bạn

      Thêm plugin intlayer vào cấu hình của bạn:

      vite.config.ts
      import { reactRouter } from "@react-router/dev/vite";
      import { defineConfig } from "vite";
      import { intlayer } from "vite-intlayer";
      
      export default defineConfig({
        plugins: [reactRouter(), intlayer()],
      });
      
      Plugin Vite intlayer() được sử dụng để tích hợp Intlayer với Vite. Nó đảm bảo việc xây dựng các tệp khai báo nội dung và giám sát chúng trong chế độ phát triển. Nó định nghĩa các biến môi trường Intlayer trong ứng dụng Vite. Ngoài ra, nó còn cung cấp các alias để tối ưu hiệu suất.
    2. Cấu hình các Route của React Router v7

      Thiết lập cấu hình routing với các route nhận biết ngôn ngữ:

      app/routes.ts
      import { layout, route, type RouteConfig } from "@react-router/dev/routes";
      
      export default [
        layout("routes/layout.tsx", [
          route("/:lang?", "routes/page.tsx"), // Trang chủ có hỗ trợ đa ngôn ngữ
          route("/:lang?/about", "routes/about/page.tsx"), // Trang about có hỗ trợ đa ngôn ngữ
        ]),
      ] satisfies RouteConfig;
      
      Hàm flatRoutes từ @react-router/fs-routes cho phép định tuyến dựa trên hệ thống tệp, trong đó cấu trúc tệp trong thư mục routes/ xác định các tuyến của ứng dụng của bạn. Tùy chọn ignoredRouteFiles đảm bảo rằng các tệp khai báo nội dung Intlayer (.content.ts, v.v.) không được coi là các tệp tuyến.
    3. Tạo các Component Layout

      Với file-system routing, bạn sử dụng quy ước đặt tên phẳng trong đó các dấu chấm (.) đại diện cho các phân đoạn đường dẫn và dấu ngoặc đơn () biểu thị các phân đoạn tùy chọn.

      Thiết lập root layout và các layout theo ngôn ngữ cụ thể:

      Cấu trúc File

      bash
      app/
      ├── root.tsx                         # Layout wrapper for locale routes
      └──routes/
          ├── ($locale)._index.tsx         # Home page (/, /es, etc.)
          ├── ($locale)._index.content.ts  # Home page content
          ├── ($locale).about.tsx          # About page (/about, /es/about, etc.)
          └── ($locale).about.content.ts   # About page content
      

      Các quy ước đặt tên:

      • ($locale) - Optional dynamic segment cho locale parameter
      • _layout - Layout route bao bọc các child routes
      • _index - Index route (renders tại parent path)
      • . (dot) - Separates path segments (e.g., ($locale).about/:locale?/about)

      Thành phần Layout

      app/root.tsx
      import { getLocaleFromPath } from "intlayer";
      import { IntlayerProvider } from "react-intlayer";
      import {
        isRouteErrorResponse,
        Meta,
        Outlet,
        Scripts,
        ScrollRestoration,
        useLoaderData,
      } from "react-router";
      
      import type { Route } from "./+types/root";
      
      import "./app.css";
      
      // ... Mã App, links và ErrorBoundary không thay đổi
      
      export async function loader({ request }: Route.LoaderArgs) {
        const locale = getLocaleFromPath(request.url);
      
        return { locale };
      }
      
      export function Layout({
        children,
      }: { children: React.ReactNode } & Route.ComponentProps) {
        const data = useLoaderData<typeof loader>();
        const { locale } = data ?? {};
      
        return (
          <html lang={locale}>
            <head>
              <meta charSet="utf-8" />
              <meta content="width=device-width, initial-scale=1" name="viewport" />
              <Meta />
              <Links />
            </head>
            <body>
              <IntlayerProvider locale={locale}>{children}</IntlayerProvider>
              <ScrollRestoration />
              <Scripts />
            </body>
          </html>
        );
      }
      

      Root Layout

      app/components/localized-link.tsx
      import type { FC } from "react";
      
      import { getLocalizedUrl, type LocalesValues } from "intlayer";
      import { useLocale } from "react-intlayer";
      import { Link, type LinkProps, type To } from "react-router";
      
      const isExternalLink = (to: string) => /^(https?:)?\/\//.test(to);
      
      export const locacalizeTo = (to: To, locale: LocalesValues): To => {
        if (typeof to === "string") {
          if (isExternalLink(to)) {
            return to;
          }
      
          return getLocalizedUrl(to, locale);
        }
      
        if (isExternalLink(to.pathname ?? "")) {
          return to;
        }
      
        return {
          ...to,
          pathname: getLocalizedUrl(to.pathname ?? "", locale),
        };
      };
      
      export const LocalizedLink: FC<LinkProps> = (props) => {
        const { locale } = useLocale();
      
        return <Link {...props} to={locacalizeTo(props.to, locale)} />;
      };
      

      Trang Chủ Đã Được Địa Phương Hóa

      app/routes/[lang]/page.tsx
      import { useIntlayer } from "react-intlayer";
      import { LocalizedLink } from "~/components/localized-link";
      
      export default function Page() {
        const { title, description, aboutLink } = useIntlayer("page");
      
        return (
          <div>
            <h1>{title}</h1>
            <p>{description}</p>
            <nav>
              <LocalizedLink to="/about">{aboutLink}</LocalizedLink>
            </nav>
          </div>
        );
      }
      
    4. Khai báo Nội dung của Bạn

      Tạo và quản lý các khai báo nội dung của bạn để lưu trữ các bản dịch. Đặt các tệp nội dung cùng với các tệp route của bạn:

      app/routes/($locale)._index.content.ts
      import { t, type Dictionary } from "intlayer";
      
      const pageContent = {
        key: "page",
        content: {
          title: t({
            vi: "Chào mừng đến với React Router v7 + Intlayer",
            en: "Welcome to React Router v7 + Intlayer",
            es: "Bienvenido a React Router v7 + Intlayer",
            fr: "Bienvenue sur React Router v7 + Intlayer",
          }),
          description: t({
            vi: "Xây dựng các ứng dụng đa ngôn ngữ một cách dễ dàng bằng cách sử dụng React Router v7 và Intlayer.",
            en: "Build multilingual applications with ease using React Router v7 and Intlayer.",
            es: "Cree aplicaciones multilingües fácilmente usando React Router v7 y Intlayer.",
            fr: "Créez des applications multilingues facilement avec React Router v7 et Intlayer.",
          }),
          aboutLink: t({
            vi: "Tìm Hiểu Về Chúng Tôi",
            en: "Learn About Us",
            es: "Aprender Sobre Nosotros",
            fr: "En savoir plus sur nous",
          }),
        },
      } satisfies Dictionary;
      
      export default pageContent;
      
      app/routes/($locale).about.content.ts
      import { t, type Dictionary } from "intlayer";
      
      const aboutContent = {
        key: "about",
        content: {
          title: t({
            vi: "Về chúng tôi",
            en: "About Us",
            es: "Sobre Nosotros",
            fr: "À propos de nous",
          }),
          content: t({
            vi: "Đây là nội dung của trang về chúng tôi.",
            en: "This is the about page content.",
            es: "Este es el contenido de la página de información.",
            fr: "Ceci est le contenu de la page à propos.",
          }),
          homeLink: t({
            vi: "Trang chủ",
            en: "Home",
            es: "Inicio",
            fr: "Accueil",
          }),
        },
      } satisfies Dictionary;
      
      export default aboutContent;
      
      Các khai báo nội dung của bạn có thể được định nghĩa ở bất kỳ đâu trong ứng dụng của bạn miễn là chúng được đưa vào thư mục contentDir (mặc định là ./app). Và phải khớp với phần mở rộng tệp khai báo nội dung (mặc định là .content.{json,ts,tsx,js,jsx,mjs,cjs,md,mdx,yaml,yml}).
      Để tìm hiểu thêm về hook useIntlayer, hãy tham khảo tài liệu.
      Nếu ứng dụng của bạn đã tồn tại, bạn có thể sử dụng Intlayer Compiler kết hợp với lệnh extract để chuyển đổi hàng nghìn component chỉ trong một giây.
    5. Tạo Các Thành Phần Nhận Biết Locale

      Tạo một component LocalizedLink cho điều hướng nhận biết locale:

      app/components/localized-link.tsx
      import type { FC } from "react";
      
      import { getLocalizedUrl, type LocalesValues } from "intlayer";
      import { useLocale } from "react-intlayer";
      import { Link, type LinkProps, type To } from "react-router";
      
      const isExternalLink = (to: string) => /^(https?:)?\/\//.test(to);
      
      export const locacalizeTo = (to: To, locale: LocalesValues): To => {
        if (typeof to === "string") {
          if (isExternalLink(to)) {
            return to;
          }
      
          return getLocalizedUrl(to, locale);
        }
      
        if (isExternalLink(to.pathname ?? "")) {
          return to;
        }
      
        return {
          ...to,
          pathname: getLocalizedUrl(to.pathname ?? "", locale),
        };
      };
      
      export const LocalizedLink: FC<LinkProps> = (props) => {
        const { locale } = useLocale();
      
        return <Link {...props} to={locacalizeTo(props.to, locale)} />;
      };
      

      Trong trường hợp bạn muốn điều hướng đến các tuyến đường được bản địa hóa, bạn có thể sử dụng hook useLocalizedNavigate:

      app/hooks/useLocalizedNavigate.ts
      import { useLocale } from "react-intlayer";
      import { type NavigateOptions, type To, useNavigate } from "react-router";
      
      import { locacalizeTo } from "~/components/localized-link";
      
      export const useLocalizedNavigate = () => {
        const navigate = useNavigate();
        const { locale } = useLocale();
      
        const localizedNavigate = (to: To, options?: NavigateOptions) => {
          const localedTo = locacalizeTo(to, locale);
      
          navigate(localedTo, options);
        };
      
        return localizedNavigate;
      };
      
    6. Tạo Thành Phần Chuyển Đổi Ngôn Ngữ

      Tạo một thành phần cho phép người dùng thay đổi ngôn ngữ:

      app/components/locale-switcher.tsx
      import type { FC } from "react";
      
      import {
        getHTMLTextDir,
        getLocaleName,
        getLocalizedUrl,
        getPathWithoutLocale,
        Locales,
      } from "intlayer";
      import { setLocaleInStorage, useIntlayer, useLocale } from "react-intlayer";
      import { Link, useLocation } from "react-router";
      
      export const LocaleSwitcher: FC = () => {
        const { localeSwitcherLabel } = useIntlayer("locale-switcher");
        const { pathname } = useLocation();
      
        const { availableLocales, locale } = useLocale();
      
        const pathWithoutLocale = getPathWithoutLocale(pathname);
      
        return (
          <ol>
            {availableLocales.map((localeItem) => (
              <li key={localeItem}>
                <Link
                  aria-current={localeItem === locale ? "page" : undefined}
                  aria-label={`${localeSwitcherLabel.value} ${getLocaleName(localeItem)}`}
                  onClick={() => setLocale(localeItem)}
                  to={getLocalizedUrl(pathWithoutLocale, localeItem)}
                >
                  <span>
                    {/* Ngôn ngữ - ví dụ: FR */}
                    {localeItem}
                  </span>
                  <span>
                    {/* Ngôn ngữ theo Locale riêng của nó - ví dụ: Français */}
                    {getLocaleName(localeItem, locale)}
                  </span>
                  <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>
                    {/* Ngôn ngữ theo Locale hiện tại - ví dụ: Francés với locale hiện tại được đặt là Locales.SPANISH */}
                    {getLocaleName(localeItem)}
                  </span>
                  <span dir="ltr" lang={Locales.ENGLISH}>
                    {/* Ngôn ngữ bằng tiếng Anh - ví dụ: French */}
                    {getLocaleName(localeItem, Locales.ENGLISH)}
                  </span>
                </Link>
              </li>
            ))}
          </ol>
        );
      };
      
      Để tìm hiểu thêm về hook useLocale, tham khảo tài liệu.
    7. Thêm quản lý thuộc tính HTML

      Tạo một hook để quản lý các thuộc tính lang và dir của HTML:

      app/hooks/useI18nHTMLAttributes.tsx
      import { getHTMLTextDir } from "intlayer";
      import { useEffect } from "react";
      import { useLocale } from "react-intlayer";
      
      export const useI18nHTMLAttributes = () => {
        const { locale } = useLocale();
      
        useEffect(() => {
          document.documentElement.lang = locale; // đặt thuộc tính lang của thẻ gốc theo locale hiện tại
          document.documentElement.dir = getHTMLTextDir(locale); // đặt thuộc tính dir của thẻ gốc theo locale hiện tại
        }, [locale]);
      };
      

      Hook này đã được sử dụng trong layout component (($locale)._layout.tsx) được hiển thị ở Bước 5.

    8. Sau đó sử dụng nó trong component gốc của bạn:

      Bạn cũng có thể sử dụng intlayerProxy để thêm định tuyến phía máy chủ vào ứng dụng của mình. Plugin này sẽ tự động phát hiện locale hiện tại dựa trên URL và đặt cookie locale thích hợp. Nếu không có locale nào được chỉ định, plugin sẽ xác định locale phù hợp nhất dựa trên tùy chọn ngôn ngữ trình duyệt của người dùng. Nếu không phát hiện được locale nào, nó sẽ chuyển hướng đến locale mặc định.

      Lưu ý rằng để sử dụng intlayerProxy trong production, bạn cần chuyển package vite-intlayer từ devDependencies sang dependencies.
      Kể từ Intlayer v9, intlayerProxy() được đóng gói trực tiếp vào plugin intlayer() và được bật theo mặc định thông qua tùy chọn routing.enableProxy (true theo mặc định). Việc đăng ký nó riêng biệt như được hiển thị bên dưới hiện là tùy chọn — nó được giữ lại để tương thích ngược và cho các cấu hình cần kiểm soát thứ tự plugin. Đặt routing.enableProxy: false để không sử dụng. Xem ghi chú phát hành v9.
      app/routes/layout.tsx
      import { Outlet } from "react-router";
      import { IntlayerProvider } from "react-intlayer";
      
      import { useI18nHTMLAttributes } from "app/hooks/useI18nHTMLAttributes"; // nhập hook
      
      export default function RootLayout() {
        useI18nHTMLAttributes(); // gọi hook
      
        return (
          <IntlayerProvider>
            <Outlet />
          </IntlayerProvider>
        );
      }
      
    9. Trích xuất nội dung các thành phần của bạn

      Tùy chọn

      Nếu bạn có một cơ sở mã hiện có, việc chuyển đổi hàng nghìn tệp có thể tốn nhiều thời gian.

      Để đơn giản hóa quy trình này, Intlayer đề xuất một trình biên dịch / trình trích xuất để chuyển đổi các thành phần của bạn và trích xuất nội dung.

      Để thiết lập, bạn có thể thêm phần compiler vào tệp intlayer.config.ts của mình:

      intlayer.config.ts
      import { type IntlayerConfig } from "intlayer";
      
      const config: IntlayerConfig = {
        // ... Phần còn lại của cấu hình
        compiler: {
          /**
           * Cho biết trình biên dịch có nên được bật hay không.
           */
          enabled: true,
      
          /**
           * Xác định đường dẫn các tệp đầu ra
           */
          output: ({ fileName, extension }) => `./${fileName}${extension}`,
      
          /**
           * Cho biết các thành phần có nên được lưu sau khi chuyển đổi hay không. Bằng cách đó, trình biên dịch có thể được chạy chỉ một lần để chuyển đổi ứng dụng, sau đó có thể được gỡ bỏ.
           */
          saveComponents: false,
      
          /**
           * Tiền tố khóa từ điển
           */
          dictionaryKeyPrefix: "",
        },
      };
      
      export default config;
      

      Chạy trình trích xuất để chuyển đổi các thành phần và trích xuất nội dung

      bash
      npx intlayer extract
      
      Since v9, the intlayerCompiler is included in the intlayer plugin. So you don't need to add it manually.

      Cập nhật vite.config.ts của bạn để bao gồm plugin intlayerCompiler:

      vite.config.ts
      import { defineConfig } from "vite";
      import { intlayer, intlayerCompiler } from "vite-intlayer";
      
      export default defineConfig({
        plugins: [
          intlayer(),
          intlayerCompiler(), // Adds the compiler plugin
        ],
      });
      
      bash
      npm run build # Hoặc npm run dev
      

    10. </Steps>

      Configure TypeScript

      Intlayer uses module augmentation to get benefits of TypeScript and make your codebase stronger.

      Ensure your TypeScript configuration includes the autogenerated types:

      tsconfig.json
      {
        // ... your existing configurations
        include: [
          // ... your existing includes
          ".intlayer/**/*.ts", // Include the auto-generated types
        ],
      }
      

      Cấu hình Git

      Khuyến nghị bỏ qua các tệp được tạo bởi Intlayer. Điều này giúp bạn tránh việc commit chúng vào kho Git của mình.

      Để làm điều này, bạn có thể thêm các hướng dẫn sau vào tệp .gitignore của bạn:

      .gitignore
      # Bỏ qua các tệp được tạo bởi Intlayer
      .intlayer
      

      Tiện ích mở rộng VS Code

      Để cải thiện trải nghiệm phát triển với Intlayer, bạn có thể cài đặt Tiện ích mở rộng Intlayer cho VS Code chính thức.

      Cài đặt từ VS Code Marketplace

      Tiện ích mở rộng này cung cấp:

      • Tự động hoàn thành cho các khóa dịch.
      • Phát hiện lỗi thời gian thực cho các bản dịch bị thiếu.
      • Xem trước nội dung dịch ngay trong dòng.
      • Hành động nhanh để dễ dàng tạo và cập nhật bản dịch.

      Để biết thêm chi tiết về cách sử dụng tiện ích mở rộng, hãy tham khảo Tài liệu Tiện ích mở rộng VS Code của Intlayer.


      Đi xa hơn

      Để đi xa hơn, bạn có thể triển khai trình chỉnh sửa trực quan hoặc tách nội dung của bạn ra ngoài bằng cách sử dụng CMS.


      Tham khảo Tài liệu

      Hướng dẫn toàn diện này cung cấp tất cả những gì bạn cần để tích hợp Intlayer với React Router v7 cho một ứng dụng được quốc tế hóa hoàn chỉnh với định tuyến nhận biết locale và hỗ trợ TypeScript.