Đặt câu hỏi và nhận tóm tắt tài liệu bằng cách tham chiếu trang này và nhà cung cấp AI bạn chọn
Bằng cách tích hợp Intlayer MCP Server vào trợ lý AI ưa thích của bạn, bạn có thể truy xuất toàn bộ tài liệu trực tiếp từ ChatGPT, DeepSeek, Cursor, VSCode, v.v.
Xem tài liệu MCP ServerLịch sử phiên bản
- Phiên bản đầu tiênv7.0.01/11/2025
Nội dung của trang này đã được dịch bằng AI.
Xem phiên bản mới nhất của nội dung gốc bằng tiếng AnhNếu bạn có ý tưởng để cải thiện tài liệu này, vui lòng đóng góp bằng cách gửi pull request trên GitHub.
Liên kết GitHub tới tài liệuSao chép Markdown của tài liệu vào bộ nhớ tạm
Cách quốc tế hóa ứng dụng Next.js của bạn bằng next-intl vào năm 2025
Mục lục
next-intl là gì?
next-intl là một thư viện quốc tế hóa (i18n) phổ biến được thiết kế đặc biệt cho Next.js App Router. Nó cung cấp một cách liền mạch để xây dựng các ứng dụng Next.js đa ngôn ngữ với hỗ trợ TypeScript xuất sắc và các tối ưu hóa tích hợp sẵn.
Nếu bạn muốn, bạn cũng có thể tham khảo hướng dẫn next-i18next, hoặc sử dụng trực tiếp Intlayer.
Xem so sánh tại next-i18next vs next-intl vs Intlayer.
Các thực hành bạn nên tuân theo
Trước khi chúng ta đi vào phần triển khai, đây là một số thực hành bạn nên tuân theo:
- Đặt thuộc tính lang và dir cho HTML
Trong layout của bạn, tính toán dir bằng cách sử dụng getLocaleDirection(locale) và đặt <html lang={locale} dir={dir}> để đảm bảo khả năng truy cập và SEO đúng cách. - Phân tách thông điệp theo namespace
Tổ chức các file JSON theo từng locale và namespace (ví dụ: common.json, about.json) để chỉ tải những gì bạn cần. - Giảm thiểu payload cho client
Trên các trang, chỉ gửi các namespace cần thiết tới NextIntlClientProvider (ví dụ: pick(messages, ['common', 'about'])). - Ưu tiên các trang tĩnh
Sử dụng trang tĩnh càng nhiều càng tốt để cải thiện hiệu suất và SEO. - I18n trong các component phía server
Các server components, như các trang hoặc tất cả các components không được đánh dấu là client là các thành phần tĩnh và có thể được pre-render tại thời điểm build. Vì vậy, chúng ta sẽ phải truyền các hàm dịch sang chúng dưới dạng props. - Thiết lập các kiểu TypeScript
Cho các locales của bạn để đảm bảo an toàn kiểu trong toàn bộ ứng dụng. - Proxy cho việc chuyển hướng
Sử dụng proxy để xử lý phát hiện locale và routing, đồng thời chuyển hướng người dùng đến URL có tiền tố locale phù hợp. - Quốc tế hóa metadata, sitemap, robots.txt của bạn
Quốc tế hóa metadata, sitemap, robots.txt bằng cách sử dụng hàm generateMetadata do Next.js cung cấp để đảm bảo các công cụ tìm kiếm có thể khám phá tốt hơn ở tất cả các locales. - Địa phương hóa các liên kết
Localize Links sử dụng component Link để chuyển hướng người dùng đến URL có tiền tố locale phù hợp. Điều này rất quan trọng để đảm bảo các trang của bạn được khám phá trong tất cả các locales. - Tự động hóa kiểm thử và dịch thuật
Tự động hóa kiểm thử và dịch thuật giúp tiết kiệm thời gian duy trì ứng dụng đa ngôn ngữ của bạn.
Xem tài liệu của chúng tôi liệt kê tất cả những gì bạn cần biết về quốc tế hóa và SEO: Internationalization (i18n) with next-intl.
Hướng Dẫn Từng Bước Để Thiết Lập next-intl Trong Ứng Dụng Next.js
Xem Application Template trên GitHub.
Dưới đây là cấu trúc dự án mà chúng ta sẽ tạo:
.├── global.ts├── locales│ ├── en│ │ ├── common.json│ │ └── about.json│ ├── fr│ │ ├── common.json│ │ └── about.json│ └── es│ ├── common.json│ └── about.json└── src # Src là tùy chọn ├── proxy.ts ├── app │ ├── i18n.ts │ └── [locale] │ ├── layout.tsx │ ├── (home) # / (Nhóm Route để không làm lộn xộn tất cả các trang với tài nguyên home) │ │ ├── layout.tsx │ │ └── page.tsx │ └── about # /about │ ├── layout.tsx │ └── page.tsx └── components ├── ClientComponent.tsx └── ServerComponent.tsxBước 1: Cài đặt các phụ thuộc
Cài đặt các gói cần thiết sử dụng npm:
npm install next-intl- next-intl: Thư viện quốc tế hóa cốt lõi cho Next.js App Router cung cấp các hook, hàm server và provider client để quản lý bản dịch.
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 hỗ trợ và thiết lập cấu hình yêu cầu của next-intl. Tệp này đóng vai trò là nguồn duy nhất cho thiết lập i18n của bạn và đảm bảo an toàn kiểu trong toàn bộ ứng dụng của bạn.
Việc tập trung cấu hình ngôn ngữ giúp tránh sự không nhất quán và làm cho việc thêm hoặc loại bỏ ngôn ngữ trong tương lai trở nên dễ dàng hơn. Hàm getRequestConfig chạy trên mỗi yêu cầu và chỉ tải các bản dịch cần thiết cho từng trang, cho phép phân tách mã và giảm kích thước gói.
Sao chép đoạn mã vào khay nhớ tạm (clipboard)
import { notFound } from "next/navigation";import createMiddleware from "next-intl/middleware";import { createNavigation } from "next-intl/navigation";// Định nghĩa các ngôn ngữ được hỗ trợ với an toàn kiểuexport const locales = ["en", "fr", "es"] as const;export type Locale = (typeof locales)[number];export const defaultLocale: Locale = "en";export function isRTL(locale: Locale | (string & {})) { // Kiểm tra xem ngôn ngữ có phải là ngôn ngữ viết từ phải sang trái không return /^(ar|fa|he|iw|ur|ps|sd|ug|yi|ckb|ku)(-|$)/i.test(locale);}// Tải các thông điệp một cách động theo từng ngôn ngữ để hỗ trợ phân tách mã// Promise.all tải các namespace song song để cải thiện hiệu suấtasync function loadMessages(locale: Locale) { // Chỉ tải các namespace mà layout/các trang của bạn cần const [common, home, about] = await Promise.all([ import(`../locales/${locale}/common.json`).then((m) => m.default), import(`../locales/${locale}/home.json`).then((m) => m.default), import(`../locales/${locale}/about.json`).then((m) => m.default), // ... Các tệp JSON trong tương lai nên được thêm vào đây ]); return { common, home, about } as const;}// Trợ giúp để tạo URL có địa phương hóa (ví dụ: /about so với /fr/about)export function localizedPath(locale: string, path: string) { return locale === defaultLocale ? path : `/${locale}${path}`;}// getRequestConfig chạy trên mỗi yêu cầu và cung cấp các thông điệp cho các thành phần server// Đây là nơi next-intl tích hợp với server-side rendering của Next.jsexport default async function getRequestConfig({ requestLocale,}: { requestLocale: Promise<string | undefined>;}) { const requested: Locale = ((await requestLocale) as Locale) ?? defaultLocale; if (!locales.includes(requested)) notFound(); return { locale: requested, messages: await loadMessages(requested), };}export function getCookie(locale: Locale) { return [ `NEXT_LOCALE=${locale}`, "Path=/", `Max-Age=${60 * 60 * 24 * 365}`, // 1 năm "SameSite=Lax", ].join("; ");}const routingOptions = { locales, defaultLocale, localePrefix: "as-needed", // Thay đổi route /en/... thành /... // Tùy chọn: các đường dẫn có địa phương hóa // pathnames: { // '/': '/', // '/about': {en: '/about', fr: '/a-propos', es: '/acerca-de'}, // '/blog/[slug]': '/blog/[slug]' // } // localeDetection: true, // ngăn chặn chuyển hướng "/" -> "/en" dựa trên cookie} as const;export const { Link, redirect, usePathname, useRouter, getPathname } = createNavigation(routingOptions);export const proxy = createMiddleware(routingOptions);Bước 3: Định nghĩa các route địa phương động
Thiết lập định tuyến động cho các locale bằng cách tạo thư mục [locale] trong thư mục app của bạn. Điều này cho phép Next.js xử lý định tuyến dựa trên locale, trong đó mỗi locale trở thành một phân đoạn URL (ví dụ: /en/about, /fr/about).
Sử dụng các route động cho phép Next.js tạo các trang tĩnh cho tất cả các locale trong thời gian build, cải thiện hiệu suất và SEO. Thành phần layout thiết lập các thuộc tính HTML lang và dir dựa trên locale, điều này rất quan trọng cho khả năng truy cập và hiểu biết của công cụ tìm kiếm.
Sao chép đoạn mã vào khay nhớ tạm (clipboard)
import type { ReactNode } from "react";import { locales } from "@/i18n";import { getLocaleDirection, setRequestLocale } from "next-intl/server";// Tạo trước các trang tĩnh cho tất cả các locale trong thời gian build (SSG)// Điều này cải thiện hiệu suất và SEOexport function generateStaticParams() { return locales.map((locale) => ({ locale }));}export default function LocaleLayout({ children, params,}: { children: ReactNode; params: Promise<{ locale: string }>;}) { // Trong Next.js App Router, params là một Promise (có thể await) // Điều này cho phép các phân đoạn route động được giải quyết bất đồng bộ const { locale } = await params; // Quan trọng: setRequestLocale thông báo cho next-intl biết locale nào sẽ được sử dụng cho yêu cầu này // Nếu không có điều này, getTranslations() sẽ không biết locale nào để sử dụng trong các component server setRequestLocale(locale); // Lấy hướng văn bản (LTR/RTL) để render HTML đúng cách const dir = getLocaleDirection(locale); return ( <html lang={locale} dir={dir}> <body>{children}</body> </html> );}Sao chép đoạn mã vào khay nhớ tạm (clipboard)
import { getTranslations, getMessages, getFormatter } from "next-intl/server";import { NextIntlClientProvider } from "next-intl";import pick from "lodash/pick";import ServerComponent from "@/components/ServerComponent";import ClientComponent from "@/components/ClientComponent";export default async function AboutPage({ params,}: { params: Promise<{ locale: string }>;}) { const { locale } = await params; // Các thông điệp được tải phía server. Chỉ đẩy những gì cần thiết cho client. // Điều này giảm thiểu kích thước gói JavaScript gửi đến trình duyệt const messages = await getMessages(); const clientMessages = pick(messages, ["common", "about"]); // Dịch/định dạng chỉ chạy phía server // Những cái này chạy trên server và có thể được truyền dưới dạng props cho các component const tAbout = await getTranslations("about"); const tCounter = await getTranslations("about.counter"); const format = await getFormatter(); const initialFormattedCount = format.number(0); return ( // NextIntlClientProvider làm cho các bản dịch có sẵn cho các component phía client // Chỉ truyền những namespace mà các component client của bạn thực sự sử dụng <NextIntlClientProvider locale={locale} messages={clientMessages}> <main> <h1>{tAbout("title")}</h1> <ClientComponent /> <ServerComponent formattedCount={initialFormattedCount} label={tCounter("label")} increment={tCounter("increment")} /> </main> </NextIntlClientProvider> );}Bước 4: Tạo Các Tệp Dịch Thuật Của Bạn
Tạo các tệp JSON cho từng locale và namespace. Cấu trúc này cho phép bạn tổ chức các bản dịch một cách hợp lý và chỉ tải những gì bạn cần cho mỗi trang.
Việc tổ chức bản dịch theo namespace (ví dụ: common.json, about.json) giúp tách mã và giảm kích thước gói. Bạn chỉ tải các bản dịch cần thiết cho mỗi trang, cải thiện hiệu suất.
Sao chép đoạn mã vào khay nhớ tạm (clipboard)
{ "welcome": "Welcome", "greeting": "Hello, world!"}Sao chép đoạn mã vào khay nhớ tạm (clipboard)
{ "welcome": "Bienvenue", "greeting": "Bonjour le monde!"}Sao chép đoạn mã vào khay nhớ tạm (clipboard)
{ "title": "About", "description": "About page description", "counter": { "label": "Counter", "increment": "Increment" }}Sao chép đoạn mã vào khay nhớ tạm (clipboard)
{ "title": "À propos", "description": "Description de la page À propos", "counter": { "label": "Compteur", "increment": "Incrémenter" }}Bước 5: Sử Dụng Bản Dịch Trong Các Trang Của Bạn
Tạo một component trang tải bản dịch trên server và truyền chúng cho cả component server và client. Điều này đảm bảo bản dịch được tải trước khi render và ngăn chặn hiện tượng nhấp nháy nội dung.
Việc tải bản dịch phía server cải thiện SEO và ngăn chặn FOUC (Flash of Untranslated Content). Bằng cách sử dụng pick để chỉ gửi các namespace cần thiết cho client provider, chúng ta giảm thiểu kích thước bundle JavaScript gửi đến trình duyệt.
Sao chép đoạn mã vào khay nhớ tạm (clipboard)
import { getTranslations, getMessages, getFormatter } from "next-intl/server";import { NextIntlClientProvider } from "next-intl";import pick from "lodash/pick";import ServerComponent from "@/components/ServerComponent";import ClientComponent from "@/components/ClientComponent";export default async function AboutPage({ params,}: { params: Promise<{ locale: string }>;}) { const { locale } = await params; // Các thông điệp được tải phía server. Chỉ gửi những gì cần thiết cho client. // Điều này giúp giảm kích thước gói JavaScript gửi đến trình duyệt const messages = await getMessages(); const clientMessages = pick(messages, ["common", "about"]); // Dịch/định dạng chỉ chạy phía server // Những phần này chạy trên server và có thể được truyền dưới dạng props cho các component const tAbout = await getTranslations("about"); const tCounter = await getTranslations("about.counter"); const format = await getFormatter(); const initialFormattedCount = format.number(0); return ( // NextIntlClientProvider làm cho các bản dịch có sẵn cho các component phía client // Chỉ truyền các namespace mà các component client của bạn thực sự sử dụng <NextIntlClientProvider locale={locale} messages={clientMessages}> <main> <h1>{tAbout("title")}</h1> <ClientComponent /> <ServerComponent formattedCount={initialFormattedCount} label={tCounter("label")} increment={tCounter("increment")} /> </main> </NextIntlClientProvider> );}Bước 6: Sử dụng bản dịch trong các component phía client
Các component phía client có thể sử dụng các hook useTranslations và useFormatter để truy cập các bản dịch và các hàm định dạng. Các hook này đọc dữ liệu từ ngữ cảnh NextIntlClientProvider.
Các component phía client cần các hook của React để truy cập bản dịch. Các hook useTranslations và useFormatter tích hợp liền mạch với next-intl và cung cấp các cập nhật phản ứng khi locale thay đổi.
Đừng quên thêm các namespace cần thiết vào các thông điệp client của trang (chỉ bao gồm các namespace mà các component phía client thực sự cần).
Sao chép đoạn mã vào khay nhớ tạm (clipboard)
"use client";import React, { useState } from "react";import { useTranslations, useFormatter } from "next-intl";const ClientComponent = () => { // Phạm vi trực tiếp tới đối tượng lồng nhau // useTranslations/useFormatter là các hook đọc từ ngữ cảnh NextIntlClientProvider // Chúng chỉ hoạt động nếu component được bao bọc trong NextIntlClientProvider const t = useTranslations("about.counter"); const format = useFormatter(); const [count, setCount] = useState(0); return ( <div> <p>{format.number(count)}</p> <button aria-label={t("label")} onClick={() => setCount((count) => count + 1)} > {t("increment")} </button> </div> );};Bước 7: Sử dụng Bản dịch trong các Server Components
Các server component không thể sử dụng React hooks, vì vậy chúng nhận các bản dịch và hàm định dạng thông qua props từ các component cha. Cách tiếp cận này giữ cho các server component đồng bộ và cho phép chúng được lồng bên trong các client component.
Các component server có thể được lồng bên trong các ranh giới client cần phải đồng bộ. Bằng cách truyền các chuỗi đã dịch và các giá trị đã định dạng dưới dạng props, chúng ta tránh các thao tác bất đồng bộ và đảm bảo việc render đúng cách. Tính toán trước các bản dịch và định dạng trong component trang cha.
Sao chép đoạn mã vào khay nhớ tạm (clipboard)
// Các component server được lồng bên trong các component client phải đồng bộ// React không thể tuần tự hóa các hàm async qua ranh giới server/client// Giải pháp: tính toán trước các bản dịch/định dạng trong component cha và truyền dưới dạng propstype ServerComponentProps = { formattedCount: string; label: string; increment: string;};const ServerComponent = ({ formattedCount, label, increment,}: ServerComponentProps) => { return ( <div> <p>{formattedCount}</p> <button aria-label={label}>{increment}</button> </div> );};Trong trang/layout của bạn, sử dụng getTranslations và getFormatter từ next-intl/server để tính trước các bản dịch và định dạng, sau đó truyền chúng dưới dạng props cho các component server.
(Tùy chọn) Bước 8: Thay đổi ngôn ngữ nội dung của bạn
Để thay đổi ngôn ngữ nội dung với next-intl, hãy render các liên kết nhận biết locale trỏ đến cùng một pathname trong khi chuyển đổi locale. Provider sẽ tự động viết lại URL, vì vậy bạn chỉ cần nhắm mục tiêu đến route hiện tại.
Sao chép đoạn mã vào khay nhớ tạm (clipboard)
"use client";import Link from "next/link";import { usePathname } from "next/navigation";import { useLocale } from "next-intl";import { defaultLocale, getCookie, type Locale, locales } from "@/i18n";const getLocaleLabel = (locale: Locale): string => { try { const displayNames = new Intl.DisplayNames([locale], { type: "language" }); return displayNames.of(locale) ?? locale.toUpperCase(); } catch { return locale.toUpperCase(); }};const localeFlags: Record<Locale, string> = { en: "🇬🇧", fr: "🇫🇷", es: "🇪🇸",};export default function LocaleSwitcher() { const activeLocale = useLocale(); const pathname = usePathname(); // Loại bỏ tiền tố locale khỏi pathname để lấy đường dẫn cơ sở const getBasePath = (path: string) => { for (const locale of locales) { if (path.startsWith(`/${locale}`)) { return path.slice(locale.length + 1) || "/"; } } return path; }; const basePath = getBasePath(pathname); return ( <nav aria-label="Bộ chọn ngôn ngữ"> <div> {(locales as readonly Locale[]).map((locale) => { const isActive = locale === activeLocale; // Xây dựng href dựa trên việc có phải là locale mặc định hay không const href = locale === defaultLocale ? basePath : `/${locale}${basePath}`; return ( <Link key={locale} href={href} aria-current={isActive ? "page" : undefined} onClick={() => { document.cookie = getCookie(locale); }} > <span>{localeFlags[locale]}</span> <span>{getLocaleLabel(locale)}</span> <span>{locale.toUpperCase()}</span> </Link> ); })} </div> </nav> );}(Tùy chọn) Bước 9: Sử dụng component Link đã được bản địa hóa
next-intl cung cấp một gói con next-intl/navigation chứa một component link đã được bản địa hóa, tự động áp dụng locale đang hoạt động. Chúng tôi đã trích xuất sẵn cho bạn trong file @/i18n, vì vậy bạn có thể sử dụng như sau:
Sao chép đoạn mã vào khay nhớ tạm (clipboard)
import { Link } from "@/i18n";return <Link href="/about">t("about.title")</Link>;(Tùy chọn) Bước 10: Truy cập locale đang hoạt động bên trong Server Actions
Server Actions có thể đọc locale hiện tại bằng cách sử dụng next-intl/server. Điều này hữu ích cho việc gửi email bản địa hóa hoặc lưu trữ tùy chọn ngôn ngữ cùng với dữ liệu được gửi lên.
Sao chép đoạn mã vào khay nhớ tạm (clipboard)
"use server";import { getLocale } from "next-intl/server";export async function getCurrentLocale() { return getLocale();}export async function handleContactForm(formData: FormData) { const locale = await getCurrentLocale(); // Sử dụng locale để chọn mẫu, nhãn phân tích, v.v. console.log(`Đã nhận biểu mẫu liên hệ từ locale ${locale}`);}getLocale đọc locale được thiết lập bởi proxy next-intl, vì vậy nó hoạt động ở bất kỳ đâu trên server: Route Handlers, Server Actions và edge functions.
(Tùy chọn) Bước 11: Quốc tế hóa Metadata của bạn
Việc dịch nội dung là quan trọng, nhưng mục tiêu chính của quốc tế hóa là làm cho trang web của bạn trở nên dễ thấy hơn với thế giới. I18n là một đòn bẩy tuyệt vời để cải thiện khả năng hiển thị trang web của bạn thông qua SEO đúng cách.
Metadata được quốc tế hóa đúng cách giúp các công cụ tìm kiếm hiểu được những ngôn ngữ nào có sẵn trên các trang của bạn. Điều này bao gồm việc thiết lập các thẻ meta hreflang, dịch tiêu đề và mô tả, cũng như đảm bảo các URL chuẩn (canonical) được thiết lập chính xác cho từng ngôn ngữ.
Sao chép đoạn mã vào khay nhớ tạm (clipboard)
import type { Metadata } from "next";import { locales, defaultLocale, localizedPath } from "@/i18n";import { getTranslations } from "next-intl/server";// generateMetadata chạy cho mỗi locale, tạo metadata thân thiện với SEO// Điều này giúp các công cụ tìm kiếm hiểu các phiên bản ngôn ngữ thay thếexport async function generateMetadata({ params,}: { params: { locale: string };}): Promise<Metadata> { const { locale } = params; const t = await getTranslations({ locale, namespace: "about" }); const url = "/about"; const languages = Object.fromEntries( locales.map((locale) => [locale, localizedPath(locale, url)]) ); return { title: t("title"), description: t("description"), alternates: { canonical: localizedPath(locale, url), languages: { ...languages, "x-default": url }, }, };}// ... Phần còn lại của mã trang(Tùy chọn) Bước 12: Quốc tế hóa Sitemap của bạn
Tạo một sitemap bao gồm tất cả các phiên bản ngôn ngữ (locale) của các trang của bạn. Điều này giúp các công cụ tìm kiếm khám phá và lập chỉ mục tất cả các phiên bản ngôn ngữ của nội dung của bạn.
Một sitemap được quốc tế hóa đúng cách đảm bảo các công cụ tìm kiếm có thể tìm thấy và lập chỉ mục tất cả các phiên bản ngôn ngữ của các trang của bạn. Điều này cải thiện khả năng hiển thị trong kết quả tìm kiếm quốc tế.
Sao chép đoạn mã vào khay nhớ tạm (clipboard)
import type { MetadataRoute } from "next";import { defaultLocale, locales } from "@/i18n";const origin = "https://example.com";const formatterLocalizedPath = (locale: string, path: string) => locale === defaultLocale ? `${origin}${path}` : `${origin}/${locale}${path}`;/** * Lấy bản đồ tất cả các locale và các đường dẫn được địa phương hóa tương ứng * * Ví dụ kết quả: * { * "en": "https://example.com", * "fr": "https://example.com/fr", * "es": "https://example.com/es", * "x-default": "https://example.com" * } */const getLocalizedMap = (path: string) => Object.fromEntries([ ...locales.map((locale) => [locale, formatterLocalizedPath(locale, path)]), ["x-default", formatterLocalizedPath(defaultLocale, path)], ]);// Tạo sitemap với tất cả các biến thể ngôn ngữ để cải thiện SEO// Trường alternates thông báo cho các công cụ tìm kiếm về các phiên bản ngôn ngữexport default function sitemap(): MetadataRoute.Sitemap { return [ { url: formatterLocalizedPath(defaultLocale, "/"), lastModified: new Date(), changeFrequency: "monthly", priority: 1.0, alternates: { languages: getLocalizedMap("/") }, }, { url: formatterLocalizedPath(defaultLocale, "/about"), lastModified: new Date(), changeFrequency: "monthly", priority: 0.7, alternates: { languages: getLocalizedMap("/about") }, }, ];}(Tùy chọn) Bước 13: Quốc tế hóa tệp robots.txt của bạn
Tạo một tệp robots.txt xử lý đúng tất cả các phiên bản ngôn ngữ của các tuyến đường được bảo vệ của bạn. Điều này đảm bảo rằng các công cụ tìm kiếm không lập chỉ mục các trang quản trị hoặc bảng điều khiển bằng bất kỳ ngôn ngữ nào.
Cấu hình đúng tệp robots.txt cho tất cả các ngôn ngữ giúp ngăn các công cụ tìm kiếm lập chỉ mục các trang nhạy cảm khi các tuyến đường của bạn khác nhau cho từng ngôn ngữ.
Sao chép đoạn mã vào khay nhớ tạm (clipboard)
import type { MetadataRoute } from "next";import { locales, defaultLocale } from "@/i18n";const origin = "https://example.com";// Tạo các đường dẫn cho tất cả các ngôn ngữ (ví dụ: /admin, /fr/admin, /es/admin)const withAllLocales = (path: string) => [ path, ...locales .filter((locale) => locale !== defaultLocale) .map((locale) => "/" + locale + path),];export default function robots(): MetadataRoute.Robots { const disallow = [ ...withAllLocales("/dashboard"), ...withAllLocales("/admin"), ]; return { rules: { userAgent: "*", allow: ["/"], disallow }, host: origin, sitemap: origin + "/sitemap.xml", };}(Tùy chọn) Bước 14: Thiết lập Proxy cho Định tuyến Locale
Tạo một proxy để tự động phát hiện locale ưu tiên của người dùng và chuyển hướng họ đến URL có tiền tố locale phù hợp. next-intl cung cấp một hàm proxy tiện lợi xử lý việc này một cách tự động.
Proxy đảm bảo rằng người dùng sẽ được tự động chuyển hướng đến ngôn ngữ ưu tiên của họ khi truy cập trang web của bạn. Nó cũng lưu lại sở thích của người dùng cho các lần truy cập sau, cải thiện trải nghiệm người dùng.
Sao chép đoạn mã vào khay nhớ tạm (clipboard)
import { proxy } from "@/i18n";// Middleware chạy trước các route, xử lý phát hiện locale và định tuyến// localeDetection: true sử dụng header Accept-Language để tự động phát hiện localeexport default proxy;export const config = { // Bỏ qua API, các phần nội bộ của Next và tài nguyên tĩnh // Regex: khớp tất cả các route ngoại trừ những route bắt đầu bằng api, _next hoặc chứa dấu chấm (file) matcher: ["/((?!api|_next|.*\\..*).*)"],};(Tùy chọn) Bước 15: Thiết lập kiểu TypeScript cho Locale
Thiết lập TypeScript sẽ giúp bạn có tính năng tự động hoàn thành và an toàn kiểu cho các khóa của bạn.
Để làm điều đó, bạn có thể tạo một file global.ts trong thư mục gốc dự án của bạn và thêm đoạn mã sau:
Sao chép đoạn mã vào khay nhớ tạm (clipboard)
import type { locales } from "@/i18n";type Messages = { common: typeof import("./locales/en/common.json"); home: typeof import("./locales/en/home.json"); about: typeof import("./locales/en/about.json"); // ... Các file JSON trong tương lai cũng nên được thêm vào đây};declare module "next-intl" { interface AppConfig { Locale: (typeof locales)[number]; Messages: Messages; }}Đoạn mã này sẽ sử dụng Module Augmentation để thêm locales và messages vào kiểu AppConfig của next-intl.
(Tùy chọn) Bước 15: Tự động hóa bản dịch của bạn bằng Intlayer
Intlayer là một thư viện miễn phí và mã nguồn mở được thiết kế để hỗ trợ quá trình bản địa hóa trong ứng dụng của bạn. Trong khi next-intl xử lý việc tải và quản lý bản dịch, Intlayer giúp tự động hóa quy trình làm việc bản dịch.
Quản lý bản dịch thủ công có thể tốn nhiều thời gian và dễ xảy ra lỗi. Intlayer tự động hóa việc kiểm tra, tạo và quản lý bản dịch, giúp bạn tiết kiệm thời gian và đảm bảo tính nhất quán trên toàn bộ ứng dụng của bạn.
Intlayer sẽ cho phép bạn:
Khai báo nội dung của bạn ở bất cứ đâu bạn muốn trong codebase Intlayer cho phép khai báo nội dung của bạn ở bất cứ đâu bạn muốn trong codebase bằng cách sử dụng các file .content.{ts|js|json}. Điều này sẽ giúp tổ chức nội dung tốt hơn, đảm bảo khả năng đọc và bảo trì codebase hiệu quả hơn.
Kiểm tra các bản dịch còn thiếu Intlayer cung cấp các hàm kiểm thử có thể được tích hợp vào pipeline CI/CD của bạn hoặc trong các bài kiểm thử đơn vị. Tìm hiểu thêm về kiểm thử bản dịch của bạn.
Tự động hóa bản dịch của bạn, Intlayer cung cấp một CLI và một tiện ích mở rộng VSCode để tự động hóa bản dịch của bạn. Nó có thể được tích hợp vào pipeline CI/CD của bạn. Tìm hiểu thêm về tự động hóa bản dịch của bạn. Bạn có thể sử dụng khóa API riêng của bạn và nhà cung cấp AI mà bạn chọn. Nó cũng cung cấp bản dịch nhận biết ngữ cảnh, xem thêm tự động điền nội dung.
Kết nối nội dung bên ngoài Intlayer cho phép bạn kết nối nội dung của mình với một hệ thống quản lý nội dung (CMS) bên ngoài. Để lấy nội dung đó một cách tối ưu và chèn vào các tài nguyên JSON của bạn. Tìm hiểu thêm về lấy nội dung bên ngoài.
Trình chỉnh sửa trực quan
Intlayer cung cấp một trình chỉnh sửa trực quan miễn phí để chỉnh sửa nội dung của bạn bằng trình chỉnh sửa trực quan. Tìm hiểu thêm về chỉnh sửa trực quan bản dịch của bạn.
Và còn nhiều hơn thế nữa. Để khám phá tất cả các tính năng mà Intlayer cung cấp, vui lòng tham khảo Lợi ích của tài liệu Intlayer.