Nhận thông báo về các bản phát hành sắp tới của Intlayer
    Ngày tạo:2024-12-07Cập nhật lần cuối:2025-06-29

    Dịch trang web Next.js và Page Router của bạn bằng Intlayer | Quốc tế hóa (i18n)

    Mục lục

    Intlayer là gì?

    Intlayer là một thư viện quốc tế hóa (i18n) mã nguồn mở, sáng tạo, được thiết kế để đơn giản hóa việc hỗ trợ đa ngôn ngữ trong các ứng dụng web hiện đại. Intlayer tích hợp liền mạch với framework Next.js mới nhất, bao gồm cả Page Router truyền thống của nó.

    Với Intlayer, bạn có thể:

    • Dễ dàng quản lý bản dịch bằng cách sử dụng các từ điển khai báo ở cấp độ component.
    • Địa phương hóa động metadata, các route và nội dung.
    • Đảm bảo hỗ trợ TypeScript với các kiểu được tự động tạo, cải thiện tính năng tự động hoàn thành và phát hiện lỗi.
    • Tận hưởng các tính năng nâng cao, như phát hiện và chuyển đổi locale động.
    Intlayer tương thích với Next.js 12, 13, 14 và 15. Nếu bạn đang sử dụng Next.js App Router, hãy tham khảo hướng dẫn App Router. Đối với Next.js 15, hãy theo dõi hướng dẫn này.

    Hướng Dẫn Từng Bước Để Cài Đặt Intlayer Trong Ứng Dụng Next.js Sử Dụng Page Router

    Bước 1: Cài Đặt Các Phụ Thuộc

    Cài đặt các gói cần thiết bằng trình quản lý gói bạn ưa thích:

    npm install intlayer next-intlayer
    • intlayer

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

    • next-intlayer

      Gói tích hợp Intlayer với Next.js. Nó cung cấp các context provider và hook cho quốc tế hóa trong Next.js. Ngoài ra, nó bao gồm plugin Next.js để tích hợp Intlayer với Webpack hoặc Turbopack, cũng như middleware để phát hiện ngôn ngữ ưu tiên của người dùng, quản lý cookie, và xử lý chuyển hướng URL.

    Bước 2: Cấu hình Dự án của Bạn

    Tạo một tệp cấu hình để định nghĩa các ngôn ngữ được ứng dụng của bạn hỗ trợ:

    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [      Locales.ENGLISH,      Locales.FRENCH,      Locales.SPANISH,      // Thêm các ngôn ngữ khác của bạn ở đây    ],    defaultLocale: Locales.ENGLISH,  },};export default config;
    Thông qua tệp cấu hình này, bạn có thể thiết lập các URL địa phương hóa, 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 của bạn, tắt các bản ghi Intlayer trong bảng điều khiển, 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.

    Bước 3: Tích hợp Intlayer với cấu hình Next.js

    Chỉnh sửa cấu hình Next.js của bạn để tích hợp Intlayer:

    next.config.mjs
    import { withIntlayer } from "next-intlayer/server";/** @type {import('next').NextConfig} */const nextConfig = {  // Cấu hình Next.js hiện có của bạn};export default withIntlayer(nextConfig);
    Plugin Next.js withIntlayer() được sử dụng để tích hợp Intlayer với Next.js. 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 môi trường Webpack hoặc Turbopack. Ngoài ra, nó cung cấp các bí danh để tối ưu hiệu suất và đảm bảo tương thích với các thành phần server.

    Hàm withIntlayer() là một hàm promise. Nếu bạn muốn sử dụng nó cùng với các plugin khác, bạn có thể sử dụng await. Ví dụ:

    const nextConfig = await withIntlayer(nextConfig);const nextConfigWithOtherPlugins = withOtherPlugins(nextConfig);export default nextConfigWithOtherPlugins;

    Bước 4: Cấu hình Middleware để Phát hiện Ngôn ngữ

    Thiết lập middleware để tự động phát hiện và xử lý ngôn ngữ ưu tiên của người dùng:

    src/middleware.ts
    export { intlayerProxy as middleware } from "next-intlayer/middleware";export const config = {  matcher:    "/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",};
    Điều chỉnh tham số matcher để phù hợp với các route của ứng dụng bạn. Để biết thêm chi tiết, tham khảo tài liệu Next.js về cấu hình matcher.

    Bước 5: Định nghĩa các Route Địa phương Động

    Triển khai routing động để phục vụ nội dung được địa phương hóa dựa trên ngôn ngữ của người dùng.

    1. Tạo các Trang theo Ngôn ngữ Cụ thể:

      Đổi tên file trang chính của bạn để bao gồm phân đoạn động [locale].

      mv src/pages/index.tsx src/pages/[locale]/index.tsx
    2. Cập nhật _app.tsx để Xử lý Đa ngôn ngữ:

      Sửa đổi _app.tsx của bạn để bao gồm các provider của Intlayer.

      src/pages/_app.tsx
      import type { FC } from "react";import type { AppProps } from "next/app";import { IntlayerClientProvider } from "next-intlayer";const App = FC<AppProps>({ Component, pageProps }) => {  const { locale } = pageProps;  return (    <IntlayerClientProvider locale={locale}>      <Component {...pageProps} />    </IntlayerClientProvider>  );}export default MyApp;
    3. Thiết Lập getStaticPathsgetStaticProps:

      Trong file [locale]/index.tsx của bạn, định nghĩa các đường dẫn và props để xử lý các locale khác nhau.

    src/pages/[locale]/index.tsx
    import type { GetStaticPaths, GetStaticProps } from "next";import { getConfiguration } from "intlayer";const HomePage = () => <div>{/* Nội dung của bạn ở đây */}</div>;export const getStaticPaths: GetStaticPaths = async () => {  const { internationalization } = getConfiguration();  const { locales } = internationalization;  const paths = locales.map((locale: string) => ({    params: { locale },  }));  return { paths, fallback: false };};export const getStaticProps: GetStaticProps = async ({ params }) => {  const locale = params?.locale;  return {    props: {      locale,    },  };};export default HomePage;
    getStaticPathsgetStaticProps đảm bảo rằng ứng dụng của bạn sẽ xây dựng trước các trang cần thiết cho tất cả các locale trong Next.js Page Router. Cách tiếp cận này giảm thiểu tính toán khi chạy và mang lại trải nghiệm người dùng tốt hơn. Để biết thêm chi tiết, hãy tham khảo tài liệu Next.js về getStaticPathsgetStaticProps.

    Bước 6: Khai báo Nội dung của Bạn

    Tạo và quản lý các khai báo nội dung để lưu trữ các bản dịch.

    src/pages/[locale]/home.content.ts
    import { t, type Dictionary } from "intlayer";const homeContent = {  key: "home",  content: {    title: t({      en: "Welcome to My Website",      fr: "Bienvenue sur mon site Web",      es: "Bienvenido a mi sitio web",    }),    description: t({      en: "Bắt đầu bằng cách chỉnh sửa trang này.",      fr: "Commencez par éditer cette page.",      es: "Comience por editar esta página.",    }),  },} satisfies Dictionary;export default homeContent;

    Để biết thêm thông tin về cách khai báo nội dung, hãy tham khảo hướng dẫn khai báo nội dung.

    Bước 7: Sử dụng Nội dung trong Mã của Bạn

    Truy cập các từ điển nội dung của bạn trong toàn bộ ứng dụng để hiển thị nội dung đã được dịch.

    src/pages/[locale]/index.tsx
    import type { FC } from "react";import { useIntlayer } from "next-intlayer";import { ComponentExample } from "@components/ComponentExample";const HomePage: FC = () => {  const content = useIntlayer("home");  return (    <div>      <h1>{content.title}</h1>      <p>{content.description}</p>      <ComponentExample />      {/* Các thành phần bổ sung */}    </div>  );};// ... Phần còn lại của mã, bao gồm getStaticPaths và getStaticPropsexport default HomePage;
    src/components/ComponentExample.tsx
    import type { FC } from "react";import { useIntlayer } from "next-intlayer";export const ComponentExample: FC = () => {  const content = useIntlayer("component-example"); // Đảm bảo bạn có khai báo nội dung tương ứng  return (    <div>      <h2>{content.title}</h2>      <p>{content.content}</p>    </div>  );};
    Khi sử dụng bản dịch trong các thuộc tính string (ví dụ: alt, title, href, aria-label), hãy gọi
    giá trị của hàm như sau:
    <img src={content.image.src.value} alt={content.image.value} />
    Để tìm hiểu thêm về hook useIntlayer, hãy tham khảo tài liệu.

    (Tùy chọn) Bước 8: Quốc tế hóa metadata của bạn

    Trong trường hợp bạn muốn quốc tế hóa metadata, chẳng hạn như tiêu đề của trang, bạn có thể sử dụng hàm getStaticProps do Next.js Page Router cung cấp. Bên trong, bạn có thể lấy nội dung từ hàm getIntlayer để dịch metadata của bạn.

    src/pages/[locale]/metadata.content.ts
    import { type Dictionary, t } from "intlayer";import { type Metadata } from "next";const metadataContent = {  key: "page-metadata",  content: {    title: t({      en: "Create Next App",      fr: "Créer une application Next.js",      es: "Crear una aplicación Next.js",    }),    description: t({      en: "Generated by create next app",      fr: "Généré par create next app",      es: "Generado por create next app",    }),  },} satisfies Dictionary<Metadata>;export default metadataContent;
    src/pages/[locale]/index.tsx
    import { GetStaticPaths, GetStaticProps } from "next";import { getIntlayer, getMultilingualUrls } from "intlayer";import { useIntlayer } from "next-intlayer";import Head from "next/head";import type { FC } from "react";interface HomePageProps {  locale: string;  metadata: {    title: string;    description: string;  };  multilingualUrls: Record<string, string>;}const HomePage: FC<HomePageProps> = ({  metadata,  multilingualUrls,  locale,}) => {  const content = useIntlayer("page");  return (    <div>      <Head>        <title>{metadata.title}</title>        <meta name="description" content={metadata.description} />        {/* Tạo các thẻ hreflang cho SEO */}        {Object.entries(multilingualUrls).map(([lang, url]) => (          <link key={lang} rel="alternate" hrefLang={lang} href={url} />        ))}        <link rel="canonical" href={multilingualUrls[locale]} />      </Head>      {/* Nội dung trang */}      <main>{/* Nội dung trang của bạn ở đây */}</main>    </div>  );};export const getStaticProps: GetStaticProps<HomePageProps> = async ({  params,}) => {  const locale = params?.locale as string;  const metadata = getIntlayer("page-metadata", locale);  /**   * Tạo một đối tượng chứa tất cả các url cho mỗi locale.   *   * Ví dụ:   * ```ts   *  getMultilingualUrls('/about');   *   *  // Trả về   *  // {   *  //   en: '/about',   *  //   fr: '/fr/about',   *  //   es: '/es/about',   *  // }   * ```   */  const multilingualUrls = getMultilingualUrls("/");  return {    props: {      locale,      metadata,      multilingualUrls,    },  };};export default HomePage;// ... Phần còn lại của code bao gồm getStaticPaths

    // ... Phần còn lại của code bao gồm getStaticPaths

    Lưu ý rằng hàm getIntlayer được nhập từ next-intlayer trả về nội dung của bạn được bao bọc trong một IntlayerNode, cho phép tích hợp với trình soạn thảo trực quan. Ngược lại, hàm getIntlayer được nhập từ intlayer trả về nội dung của bạn trực tiếp mà không có thuộc tính bổ sung.

    Ngoài ra, bạn có thể sử dụng hàm getTranslation để khai báo metadata của bạn. Tuy nhiên, việc sử dụng các tệp khai báo nội dung được khuyến nghị để tự động hóa việc dịch metadata và ngoại hóa nội dung vào một thời điểm nào đó.

    src/pages/[locale]/index.tsx
    import { GetStaticPaths, GetStaticProps } from "next";import { getTranslation, getMultilingualUrls } from "intlayer";import { useIntlayer } from "next-intlayer";import Head from "next/head";import type { FC } from "react";type Metadata = {  title: string;  description: string;};interface HomePageProps {  locale: string;  metadata: Metadata;  multilingualUrls: Record<string, string>;}const HomePage: FC<HomePageProps> = ({  metadata,  multilingualUrls,  locale,}) => {  const content = useIntlayer("page");  return (    <div>      <Head>        <title>{metadata.title}</title>        <meta name="description" content={metadata.description} />        {/* Tạo các thẻ hreflang cho SEO */}        {Object.entries(multilingualUrls).map(([lang, url]) => (          <link key={lang} rel="alternate" hrefLang={lang} href={url} />        ))}        <link rel="canonical" href={multilingualUrls[locale]} />      </Head>      {/* Nội dung trang */}      <main>{/* Nội dung trang của bạn ở đây */}</main>    </div>  );};export const getStaticProps: GetStaticProps<HomePageProps> = async ({  params,}) => {  const locale = params?.locale as string;  const t = (content: Record<string, string>) =>    getTranslation(content, locale);  const metadata: Metadata = {    title: t({      en: "My title",      fr: "Mon titre",      es: "Mi título",    }),    description: t({      en: "My description",      fr: "Ma description",      es: "Mi descripción",    }),  };  const multilingualUrls = getMultilingualUrls("/");  return {    props: {      locale,      metadata,      multilingualUrls,    },  };};export default HomePage;// ... Phần còn lại của mã bao gồm getStaticPaths
    Tìm hiểu thêm về tối ưu hóa metadata trong tài liệu chính thức của Next.js.

    (Tùy chọn) Bước 9: Thay đổi ngôn ngữ nội dung của bạn

    Để thay đổi ngôn ngữ nội dung trong Next.js, cách được khuyến nghị là sử dụng component Link để chuyển hướng người dùng đến trang được địa phương hóa phù hợp. Component Link cho phép tải trước trang, giúp tránh tải lại toàn bộ trang.

    src/components/LanguageSwitcher.tsx
    import {  Locales,  getHTMLTextDir,  getLocaleName,  getLocalizedUrl,} from "intlayer";import { useLocalePageRouter } from "next-intlayer";import { type FC } from "react";import Link from "next/link";const LocaleSwitcher: FC = () => {  const { locale, pathWithoutLocale, availableLocales } = useLocalePageRouter();  return (    <div>      <button popoverTarget="localePopover">{getLocaleName(locale)}</button>      <div id="localePopover" popover="auto">        {availableLocales.map((localeItem) => (          <Link            href={getLocalizedUrl(pathWithoutLocale, localeItem)}            hrefLang={localeItem}            key={localeItem}            aria-current={locale === localeItem ? "page" : undefined}            onClick={() => setLocale(localeItem)}          >            <span>              {/* Ngôn ngữ địa phương - ví dụ: FR */}              {localeItem}            </span>            <span>              {/* Ngôn ngữ trong chính ngôn ngữ đó - ví dụ: Français */}              {getLocaleName(localeItem, locale)}            </span>            <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>              {/* Ngôn ngữ trong Locale hiện tại - ví dụ: Francés với locale hiện tại được đặt thành 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>        ))}      </div>    </div>  );};
    Một cách thay thế là sử dụng hàm setLocale được cung cấp bởi hook useLocale. Hàm này sẽ không cho phép tải trước trang và sẽ tải lại trang.
    Trong trường hợp này, không sử dụng chuyển hướng với router.push, chỉ có mã phía server của bạn sẽ thay đổi locale của nội dung.
    src/components/LocaleSwitcher.tsx
    "use client";import { useRouter } from "next/navigation";import { useLocale } from "next-intlayer";import { getLocalizedUrl } from "intlayer";// ... Phần còn lại của mãconst router = useRouter();const { setLocale } = useLocale({  onLocaleChange: (locale) => {    router.push(getLocalizedUrl(pathWithoutLocale, locale));  },});return (  <button onClick={() => setLocale(Locales.FRENCH)}>    Chuyển sang tiếng Pháp  </button>);
    API useLocalePageRouter giống với useLocale. Để tìm hiểu thêm về hook useLocale, hãy tham khảo tài liệu.

    Tham khảo tài liệu:

    Để đảm bảo rằng điều hướng trong ứng dụng của bạn tôn trọng locale hiện tại, bạn có thể tạo một thành phần Link tùy chỉnh. Thành phần này tự động thêm tiền tố ngôn ngữ hiện tại vào các URL nội bộ, ví dụ, khi một người dùng nói tiếng Pháp nhấp vào liên kết đến trang "About", họ sẽ được chuyển hướng đến /fr/about thay vì /about.

    Hành vi này hữu ích vì một số lý do:

    • SEO và Trải nghiệm Người dùng: URL đa ngôn ngữ giúp các công cụ tìm kiếm lập chỉ mục chính xác các trang theo ngôn ngữ cụ thể và cung cấp nội dung cho người dùng theo ngôn ngữ ưu tiên của họ.
    • Tính nhất quán: Bằng cách sử dụng liên kết đa ngôn ngữ trong toàn bộ ứng dụng của bạn, bạn đảm bảo rằng điều hướng luôn nằm trong locale hiện tại, ngăn chặn việc chuyển đổi ngôn ngữ không mong muốn.
    • Dễ bảo trì: Tập trung logic đa ngôn ngữ vào một thành phần duy nhất giúp đơn giản hóa việc quản lý URL, làm cho codebase của bạn dễ bảo trì và mở rộng khi ứng dụng phát triển.

    Dưới đây là triển khai của một thành phần Link đa ngôn ngữ bằng TypeScript:

    src/components/Link.tsx
    "use client";import { getLocalizedUrl } from "intlayer";import NextLink, { type LinkProps as NextLinkProps } from "next/link";import { useLocale } from "next-intlayer";import { forwardRef, PropsWithChildren, type ForwardedRef } from "react";/** * Hàm tiện ích để kiểm tra xem một URL có phải là liên kết ngoài hay không. * Nếu URL bắt đầu bằng http:// hoặc https://, nó được coi là liên kết ngoài. */export const checkIsExternalLink = (href?: string): boolean =>  /^https?:\/\//.test(href ?? "");/** * Một thành phần Link tùy chỉnh điều chỉnh thuộc tính href dựa trên locale hiện tại. * Đối với các liên kết nội bộ, nó sử dụng `getLocalizedUrl` để thêm tiền tố locale vào URL (ví dụ: /fr/about). * Điều này đảm bảo điều hướng luôn nằm trong cùng ngữ cảnh locale. */export const Link = forwardRef<  HTMLAnchorElement,  PropsWithChildren<NextLinkProps>>(({ href, children, ...props }, ref: ForwardedRef<HTMLAnchorElement>) => {  const { locale } = useLocale();  const isExternalLink = checkIsExternalLink(href.toString());  // Nếu liên kết là nội bộ và href hợp lệ được cung cấp, lấy URL đã được địa phương hóa.  const hrefI18n: NextLinkProps["href"] =    href && !isExternalLink ? getLocalizedUrl(href.toString(), locale) : href;  return (    <NextLink href={hrefI18n} ref={ref} {...props}>      {children}    </NextLink>  );});Link.displayName = "Link";

    Cách Hoạt Động

    • Phát hiện Liên kết Ngoài: Hàm trợ giúp checkIsExternalLink xác định xem một URL có phải là liên kết ngoài hay không. Các liên kết ngoài được giữ nguyên vì chúng không cần được địa phương hóa.

    • Lấy Ngôn ngữ Hiện tại: // Hook useLocale cung cấp locale hiện tại (ví dụ: fr cho tiếng Pháp).

    • Địa phương hóa URL: Đối với các liên kết nội bộ (tức là không phải liên kết ngoài), getLocalizedUrl được sử dụng để tự động thêm tiền tố locale hiện tại vào URL. Điều này có nghĩa là nếu người dùng của bạn đang ở chế độ tiếng Pháp, việc truyền /about làm href sẽ chuyển thành /fr/about.

    • Trả về Liên kết: Component trả về một phần tử <a> với URL đã được địa phương hóa, đảm bảo điều hướng nhất quán với locale.

    Bằng cách tích hợp component Link này trong toàn bộ ứng dụng của bạn, bạn duy trì trải nghiệm người dùng nhất quán và nhận biết ngôn ngữ đồng thời cải thiện SEO và khả năng sử dụng.

    (Tùy chọn) Bước 11: Tối ưu kích thước bundle của bạn

    Khi sử dụng next-intlayer, các từ điển được bao gồm trong bundle cho mỗi trang theo mặc định. Để tối ưu kích thước bundle, Intlayer cung cấp một plugin SWC tùy chọn thay thế thông minh các lệnh gọi useIntlayer bằng cách sử dụng macro. Điều này đảm bảo các từ điển chỉ được bao gồm trong bundle của những trang thực sự sử dụng chúng.

    Để kích hoạt tối ưu hóa này, hãy cài đặt gói @intlayer/swc. Khi đã cài đặt, next-intlayer sẽ tự động phát hiện và sử dụng plugin:

    npm install @intlayer/swc --save-dev
    Lưu ý: Tối ưu hóa này chỉ có sẵn cho Next.js 13 trở lên.
    Lưu ý: Gói này không được cài đặt mặc định vì các plugin SWC vẫn đang trong giai đoạn thử nghiệm trên Next.js. Điều này có thể thay đổi trong tương lai.

    Cấu hình TypeScript

    Intlayer sử dụng module augmentation để tận dụng lợi ích của TypeScript và làm cho codebase của bạn mạnh mẽ hơn.

    Tự động hoàn thành

    Lỗi dịch thuật

    Đảm bảo cấu hình TypeScript của bạn bao gồm các kiểu được tạo tự động.

    tsconfig.json
    {  // ... Các cấu hình TypeScript hiện có của bạn  "include": [    // ... Các cấu hình TypeScript hiện có của bạn    ".intlayer/**/*.ts", // Bao gồm các kiểu được tạo tự động  ],}

    Cấu hình Git

    Để giữ cho kho lưu trữ của bạn sạch sẽ và tránh việc commit các file được tạo tự động, bạn nên bỏ qua các file do Intlayer tạo ra.

    Thêm các dòng sau vào file .gitignore của bạn:

    .gitignore
    # Bỏ qua các file đượ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 các 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 Intlayer cho VS Code.

    Tài nguyên bổ sung

    Bằng cách làm theo hướng dẫn này, bạn có thể tích hợp hiệu quả Intlayer vào ứng dụng Next.js của mình sử dụng Page Router, cho phép hỗ trợ quốc tế hóa mạnh mẽ và có khả năng mở rộng cho các dự án web của bạn.

    Tiến 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 bên ngoài bằng cách sử dụng CMS.

    Nhận thông báo về các bản phát hành sắp tới của Intlayer