Điều quan trọng phải nhắc thêm 1 lần nữa: Nếu bạn đang phát triển 1 website mới, hãy cài đặt tính năng đa ngôn ngữ đầu tiên, tránh việc code xong hết mới đi dịch, vì ngôn ngữ là cách để website giao tiếp với user mà, hãy chăm chút nó đầu tiên nhá!
Mở đầu
Dưới đây là form đăng ký tôi mới code xong (tôi sử dụng Zod - code cơ bản tự gen và là default). Điều gì sẽ xảy ra nếu tôi cứ phát triển các tính năng tiếp theo, và thêm các text bằng tiếng anh, rồi bán cho khách hàng việt. Hay tôi nên fix cứng thành tiếng việt ngay từ đầu. Tôi dừng lại việc phát triển các tính năng tiếp theo, và tôi biết rằng, thứ tôi cần là cách triển khai đa ngôn ngữ ngay từ khi website còn sơ sinh.
Khi các dev muốn tích hợp thêm tính năng đa ngôn ngữ, họ sẽ đứng trước phân vân nên dịch thủ công hay sử dụng Google API để dịch tự động. Sau 1 thời gian tìm hiểu, tôi rút ra vài kết luận như sau: Google API sẽ tốn chi phí nếu có nhiều request, nội dung bản dịch thiếu tự nhiên, k sát nghĩa, gây hiểu lầm cho người đọc, nếu dịch động (real-time), mỗi lần đổi ngôn ngữ sẽ phải gọi API => tăng thời gian phản hồi, ảnh hưởng UX. #NextJS sinh ra để tối ưu SEO, SEO hiệu quả đòi hỏi phải có đường dẫn tĩnh cho từng ngôn ngữ (/vi, /en, ...), trong khi Google API chỉ dịch trên frontend. Vậy, giải pháp đưa ra là bạn cần dịch thủ công toàn bộ website của bạn, dưới sự giúp đỡ của 1 thư viện ngôn ngữ nào đó.
=> i18n sinh ra là để dành cho bạn < 3
i18n là gì?
👉 i18n (Internationalization) là kỹ thuật giúp ứng dụng hỗ trợ nhiều ngôn ngữ và tùy chỉnh nội dung theo từng khu vực (locale) mà không cần thay đổi code nhiều lần.
📌 Gọi là "i18n" vì "Internationalization" có 18 chữ cái giữa "I" và "N"
Các khái niệm liên quan đến i18n:
🔹 1. i18n (Internationalization - Quốc tế hóa) Là quá trình chuẩn bị ứng dụng để hỗ trợ nhiều ngôn ngữ. Không dịch ngôn ngữ mà chỉ giúp dễ dàng thay đổi nội dung theo từng locale.
🔹 2. l10n (Localization - Địa phương hóa) Là việc dịch nội dung và điều chỉnh giao diện theo từng ngôn ngữ và văn hóa địa phương. Ví dụ: Ở Mỹ hiển thị $10, còn ở Việt Nam hiển thị 10.000₫.
🔹 3. t9n (Translation - Dịch thuật) Là việc dịch từng đoạn văn bản sang ngôn ngữ khác.
Tích hợp thư viện i18n (next-intl) vào project
Link tham khảo: https://www.youtube.com/watch?v=2Jh9olZXBfw
Yêu cầu của chúng ta là giúp website vừa tích hợp đa ngôn ngữ, vừa tối ưu SEO bằng thẻ Meta. Vì vậy, thư viện ngôn ngữ sử dụng phải thay đổi được tên page + nội dung page.
Bước 1: Install thư viện next-intl
// npm
npm install next-intl // yarn
yarn add next-intl
Sau khi cài đặt thành công, mở file package-json kiểm tra xem nhá:
Mở file next.config.ts và thêm vào đoạn code sau:
import type { NextConfig } from "next";
import createNextIntlPlugin from "next-intl/plugin"; const withNextIntl = createNextIntlPlugin(); const nextConfig: NextConfig = { /* config options here */
}; export default withNextIntl(nextConfig);
Bước 2: Cấu hình thư viện
Tạo 2 file có nội dung như sau:
File i18n.ts - Cấu hình tải dữ liệu ngôn ngữ
import { notFound } from "next/navigation"; // Import hàm điều hướng đến trang 404
import { getRequestConfig } from "next-intl/server"; // Import hàm lấy cấu hình từ next-intl const locales = ["en", "vi"] as const; // Danh sách các ngôn ngữ được hỗ trợ export default getRequestConfig(async ({ locale }) => { if (!locales.includes(locale as (typeof locales)[number])) notFound(); // Nếu locale không hợp lệ, trả về 404 return { messages: (await import(`./messages/${locale}.json`)).default, // Import file JSON tương ứng với locale };
});
File này để: Kiểm tra xem locale có hợp lệ không (en hoặc vi); Nếu không hợp lệ, gọi notFound() để trả về trang 404. Nếu hợp lệ, tải file JSON chứa nội dung dịch cho ngôn ngữ đó.
File middleware.ts - Xử lý ngôn ngữ trong request
import createMiddleware from "next-intl/middleware"; // Import middleware để xử lý i18n export default createMiddleware({ locales: ["en", "vi"], // Danh sách các ngôn ngữ được hỗ trợ defaultLocale: "vi", // Ngôn ngữ mặc định nếu không có locale trong URL
}); export const config = { matcher: ["/", "/(en|vi)/:path*"], // Chỉ áp dụng middleware cho các đường dẫn này
};
✅ Chức năng: Xác định locale từ URL (ví dụ: /vi hoặc /en). Nếu người dùng truy cập /, tự động chuyển hướng đến /vi (ngôn ngữ mặc định).
Bước 3: Thêm file dịch và cấu hình Dynamic Segment cho đa ngôn ngữ
Thêm folder messages và các file dịch
Ví dụ, file vi.json có nội dung như sau:
{ "Nav": { "home": "Trang chủ", "about": "Giới thiệu", "contact": "Liên hệ", "login": "Đăng nhập", "register": "Đăng ký" }, "Home": { "title": "Chào mừng đến với trang web của chúng tôi", "description": "Đây là trang chủ" }, "Register": { "title": "Đăng ký", "description": "Đây là trang đăng ký", "email": "Email", "password": "Mật khẩu", "confirmPassword": "Xác nhận mật khẩu", "register": "Đăng ký" }, "Login": { "title": "Đăng nhập", "description": "Đây là trang đăng nhập" }
}
Cấu hình [locale] - dynamic segment cho route
src/ app/ [locale]/ -> Them folder nay layout.tsx ✅ page.tsx
Ta sẽ tạo ra app/[locale]/page.tsx → URL: /en hoặc /vi (Dấu ngoặc vuông [ ] tạo segment động, nghĩa là nó có thể nhận nhiều giá trị khác nhau)
Tạo thư mục [locale] trong src/app và move 2 file vào folder này
Tại file layout.tsx, import và thêm locale vào thư mục:
// import các thư viện cần
import { NextIntlClientProvider } from "next-intl"; // import thêm thư viện
import { getMessages } from "next-intl/server"; // import thêm thư viện export default async function RootLayout({ children, params: { locale }, // Thêm dòng này
}: Readonly<{ children: React.ReactNode; params: { locale: string }; // Thêm dòng này
}>) { const messages = await getMessages(); // Thêm dòng này return ( <html lang={locale}> <body> <NextIntlClientProvider messages={messages}> <ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange > <header> <Header /> </header> {children} <footer> Footer <ButtonRedirect /> </footer> </ThemeProvider> </NextIntlClientProvider> <Toaster /> </body> </html> );
}
Gòi xong , tôi bị như này các bác ạ...
Nếu bạn gặp lỗi tương tự, move file middleware vào trong thư mục src thay vì để ngoài:
Bạn sẽ thấy, đường link http://localhost:3000/vi sẽ không bị lỗi 404 nữa đâu.
Đó, vậy là tui và các bác vừa hoàn thành xong cách set up đa ngôn ngữ vào project NextJS 15. Kết quả như nào các bác tự trải nghiệm trên web của mình nha. Cảm ơn vì đã đọc bài viết này