Đặ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
Lịch sử phiên bản
- "Phiên bản ban đầu"v9.5.1026/9/2026
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 TanStack Start của bạn bằng Paraglide JS trong năm 2026
Mục lục
Paraglide JS là gì?
Paraglide JS (phát triển bởi inlang) là một thư viện i18n dựa trên trình biên dịch (compiler-based). Thay vì cung cấp một runtime tra cứu các khóa trong một đối tượng JSON, nó biên dịch từng thông điệp thành một hàm JavaScript có kiểu dữ liệu tĩnh (m.about_title()). Các thông điệp không dùng đến có thể được bundler loại bỏ (tree-shaking), và lỗi chính tả trong khóa sẽ trở thành lỗi biên dịch (compile error).
Paraglide là phương pháp tiếp cận i18n được sử dụng trong các ví dụ chính thức của TanStack Router, và nó tích hợp với TanStack Start thông qua ba thành phần:
- một Vite plugin biên dịch các thông điệp và runtime vào thư mục
src/paraglide; - một server middleware giải quyết locale cho từng yêu cầu (request);
- một router rewrite ánh xạ các URL đã bản địa hóa (
/fr/about) tới cây route của bạn (/about), nhờ đó bạn không cần phân đoạn$locale.
Hướng dẫn này sẽ thiết lập cả ba thành phần trên, sau đó trình bày tất cả những gì Paraglide để bạn tự xử lý: lang và dir, bộ chuyển đổi ngôn ngữ (locale switcher), metadata được dịch, canonical, hreflang với x-default, Open Graph, JSON-LD, sitemap, robots.txt, pre-rendering và các trang 404 được bản địa hóa.
Bạn đang tìm kiếm một tech stack khác? Hãy xem Hướng dẫn TanStack Start + use-intl, Hướng dẫn TanStack Start + Lingui, hoặc Hướng dẫn TanStack Start + Intlayer.
So sánh hai phương pháp tiếp cận dựa trên trình biên dịch? Đọc bài viết Intlayer có nhẹ hơn Paraglide không?.
Dữ liệu benchmark nói gì về Paraglide trên TanStack Start
Bài kiểm thử benchmark i18n chạy cùng một ứng dụng TanStack Start 10 trang, 10 ngôn ngữ với mọi thư viện phổ biến và đo lường dung lượng thực tế mà trình duyệt tải về.
Tải JSON động
Tải chậm các bản dịch trong thời gian chạy
JSON có phạm vi (phân không gian tên)
Không gian tên dịch trên mỗi trang
Điểm chuẩn hiệu suất I18n
Số liệu này là gì?
Tổng kích thước nén gzip của gói thư viện quốc tế hóa. Nó chỉ bao gồm logic của nhà cung cấp và truy xuất nội dung sau khi tree-shaking và thu nhỏ (minification).
Tại sao nó quan trọng?
Kích thước thư viện nhỏ hơn giúp giảm tải trọng JavaScript ban đầu, tốc độ tải nhanh hơn.
Xem dưới dạng
Các số liệu chính cho @inlang/paraglide-js@2.15.1, được đo vào ngày 2026-09-26 (gzip):
Mở bảng trong một cửa sổ bật lên để xem toàn bộ nội dung dữ liệu một cách rõ ràng
| Thiết lập | Kích thước thư viện | JS mỗi trang | Rò rỉ ngôn ngữ khác | Rò rỉ trang khác | Tải trang |
|---|---|---|---|---|---|
| Không i18n (ứng dụng gốc) | - | 111.0 KB | 0% | 0% | 15.7 ms |
| Paraglide JS | 1.8 KB | 125.1 KB | 49.7% | 0% | 22.1 ms |
react-intlayer | 4.5 KB | 126.8 KB | 0% | 0% | 14.8 ms |
use-intl | 75.9 KB | 128.7 KB | 0% | 0% | 17.4 ms |
| Lingui | 56.7 KB | 120.2 KB | 8.6% | 0% | 21.9 ms |
Những điểm cần lưu ý:
- Runtime rất nhỏ gọn và các trang không bị rò rỉ. Runtime được tạo riêng cho cấu hình của bạn, và các thông điệp chỉ được import ở nơi chúng được sử dụng.
- Rò rỉ ngôn ngữ (Locales leak). Mỗi hàm thông điệp chứa tất cả các ngôn ngữ, vì vậy khoảng một nửa chuỗi dịch được gửi đến một trang thuộc về các ngôn ngữ mà khách truy cập không sử dụng. Bạn càng thêm nhiều locale, tỷ lệ này càng lớn.
- Thời gian tải trang chậm nhất trong nhóm, một phần vì locale được giải quyết thông qua các chiến lược (strategies) trong mỗi lần gọi thay vì đọc trực tiếp từ React context.
Xem toàn bộ dữ liệu: Báo cáo benchmark TanStack Start, và kho lưu trữ benchmark.
So sánh tính năng trên TanStack Start
Cách Paraglide JS so sánh với các thư viện khác thường được dùng trên TanStack Start:
Mở bảng trong một cửa sổ bật lên để xem toàn bộ nội dung dữ liệu một cách rõ ràng
| Tính năng | react-intlayer (Intlayer) | use-intl | Paraglide JS | Lingui |
|---|---|---|---|---|
| Bản dịch đặt gần component | ✅ Đặt cùng (Co-located) | ❌ JSON tập trung | ❌ Một tệp JSON cho mỗi locale | ⚠️ Văn bản gốc trong component |
| Tích hợp TypeScript | ✅ Tự động tạo kiểu | ✅ Qua AppConfig | ✅ Các hàm thông điệp có kiểu | ⚠️ Chỉ qua macro |
| Phát hiện bản dịch thiếu | ✅ Lỗi kiểu và cảnh báo build | ⚠️ Dự phòng khi chạy | ⚠️ Dự phòng về locale cơ sở | ⚠️ Dự phòng về văn bản gốc |
| Nội dung phong phú (JSX, Markdown) | ✅ Hỗ trợ trực tiếp | ⚠️ Thẻ qua t.rich | ⚠️ Chuỗi | ✅ JSX bên trong <Trans> |
| Routing bản địa hóa | ✅ Tích hợp sẵn | ❌ Thủ công {-$locale} | ✅ urlPatterns + router rewrite | ❌ Thủ công {-$locale} |
| Đổi ngôn ngữ không tải lại trang | ✅ Có | ✅ Có | ❌ Tải lại toàn bộ trang | ✅ Có |
| Xử lý số nhiều (Pluralization) | ✅ Dựa trên liệt kê | ✅ ICU | ✅ Biến thể (Variants) | ✅ ICU |
| ICU MessageFormat | ✅ Qua format: "icu" | ✅ Tích hợp gốc | ⚠️ Qua plugin inlang | ✅ Tích hợp gốc |
| Định dạng nội dung | ✅ .ts, .json, .md, .yaml... | ⚠️ .json | ⚠️ inlang JSON | ✅ PO, JSON, CSV |
| Dịch thuật AI | ✅ Nhà cung cấp và API key riêng | ❌ Không | ❌ Không | ❌ Không |
| Trình chỉnh sửa trực quan / CMS | ✅ Trình soạn thảo cục bộ + CMS tùy chọn | ❌ Nền tảng bên ngoài | ⚠️ Ứng dụng hệ sinh thái inlang | ❌ Nền tảng bên ngoài |
| Hỗ trợ SEO (hreflang, sitemap) | ✅ Tích hợp sẵn | ❌ Thủ công | ⚠️ URL bản địa hóa, còn lại thủ công | ❌ Thủ công |
| Kích thước runtime (gzip, benchmark) | 4.5 KB | 75.9 KB | 1.8 KB | 56.7 KB |
| Rò rỉ, thiết lập tối ưu (locale / page) | 0% / 0% | 0% / 0% | 49.7% / 0% | 8.6% / 0% |
| Bản dịch thiếu trong CI | ✅ npx intlayer test | ⚠️ Không tích hợp sẵn | ⚠️ Không tích hợp sẵn | ✅ lingui compile --strict |
Kích thước runtime và số liệu rò rỉ đến từ Benchmark TanStack Start. Độ rò rỉ được đo trên thiết lập tối ưu nhất của từng thư viện.
Các hướng dẫn TanStack Start khác: Lingui, use-intl, và Intlayer.
Các nguyên tắc thực hành bạn nên tuân theo
- Thiết lập
langvàdirtrên thẻ<html>từ locale đã được giải quyết, ngay trên server. - Duy trì một URL riêng cho mỗi ngôn ngữ với chiến lược tiền tố (
/fr/about), để mọi phiên bản ngôn ngữ đều có thể lập chỉ mục (indexable). - Đặt
urllên đầu tiên trong chiến lược locale của bạn, để URL là nguồn chân lý duy nhất (source of truth), và trình thu thập dữ liệu (crawler) nhận được đúng trang được yêu cầu. - Sử dụng các khóa thông điệp phẳng, có tính mô tả (
about_title) ánh xạ rõ ràng thành tên hàm. - Commit các tệp
messages/*.json, không commit thư mục được tạosrc/paraglide, nhằm tránh xung đột merge trên các tệp tự động sinh. - Dịch metadata của bạn, và khai báo
canonical,hreflangcùngx-defaulttrên mỗi trang. - Tạo sitemap đa ngôn ngữ và robots.txt, và pre-render mọi ngôn ngữ.
- Sử dụng các liên kết thực cho bộ chuyển đổi ngôn ngữ, để crawler phát hiện được tất cả các ngôn ngữ.
Xem hướng dẫn của chúng tôi về quốc tế hóa và SEO và hướng dẫn hreflang.
Hướng dẫn từng bước thiết lập Paraglide JS trong ứng dụng TanStack Start
Dưới đây là cấu trúc dự án chúng ta sẽ tạo:
Sao chép mã vào clipboard
Lưu ý rằng không có thư mục $locale: router rewrite sẽ loại bỏ tiền tố trước khi khớp route.
Cài đặt các gói phụ thuộc
Bắt đầu từ một dự án TanStack Start, sau đó khởi tạo Paraglide. Lệnh init sẽ tạo
project.inlang/settings.json, tệpmessages/en.jsonđầu tiên và cài đặt gói cần thiết.bashSao chép mãSao chép mã vào clipboard
- @inlang/paraglide-js: trình biên dịch và Vite plugin của nó. Không có gói runtime nào cần cài đặt: runtime được tạo trực tiếp vào dự án của bạn.
Cấu hình các Locale
project.inlang/settings.jsonlà nguồn chân lý duy nhất cho các locale. Plugin định dạng thông điệp đọc một tệp JSON cho mỗi ngôn ngữ.project.inlang/settings.jsonSao chép mãSao chép mã vào clipboard
Cấu hình Vite Plugin và Chiến lược URL
Plugin biên dịch các thông điệp trên mỗi lần thay đổi. Có ba tùy chọn quan trọng cho TanStack Start:
strategy: danh sách có thứ tự các vị trí đọc locale.urlđặt đầu tiên giúp URL trở thành nguồn chân lý.cookievàpreferredLanguageđược middleware sử dụng khi URL không xác định được locale.urlPatterns: cách một locale ánh xạ tới URL. Các locale không phải mặc định được liệt kê trước, vì pattern khớp đầu tiên sẽ được áp dụng. Ở đây locale mặc định không có tiền tố (/about), và các locale khác có tiền tố (/fr/about).outputStructure: "message-modules": mỗi thông điệp là một module, cho phép bundler loại bỏ các thông điệp mà trang không import.
vite.config.tsSao chép mãSao chép mã vào clipboard
Thêm thư mục được tạo tự động vào
.gitignore. Nó sẽ được xây dựng lại khi chạydevvàbuild:.gitignoreSao chép mãSao chép mã vào clipboard
Tạo các tệp bản dịch của bạn
Mỗi khóa trở thành một hàm được export từ
src/paraglide/messages. Các khóa phẳng dạng snake_case mang lại tên hàm rõ ràng nhất. Các biến sử dụng trình giữ chỗ{name}.messages/en.jsonSao chép mãSao chép mã vào clipboard
messages/fr.jsonSao chép mãSao chép mã vào clipboard
Dạng số nhiều sử dụng cú pháp variants của inlang message format:
messages/en.jsonSao chép mãSao chép mã vào clipboard
Thêm Server Middleware
Middleware giải quyết locale cho từng yêu cầu bằng chiến lược của bạn, và cung cấp nó cho
getLocale()trong toàn bộ quá trình render trên server thông qua một scopeAsyncLocalStorage. Điều này giúp các yêu cầu đồng thời bằng các ngôn ngữ khác nhau diễn ra an toàn.Trong TanStack Start, hãy bọc server entry mặc định:
src/server.tsSao chép mãSao chép mã vào clipboard
Ghi đè các URL bản địa hóa trong Router
Tùy chọn
rewritecủa TanStack Router dịch các URL tại ranh giới của router:- đầu vào (input):
/fr/aboutđược hủy bản địa hóa (de-localize) về/abouttrước khi khớp route, nhờ đó một routeabout.tsxduy nhất phục vụ mọi ngôn ngữ; - đầu ra (output): mọi
hrefđược tạo (liên kết, chuyển hướng, điều hướng) đều được bản địa hóa cho locale đang hoạt động, do đó<Link to="/about">sẽ render thành/fr/abouttrên trang tiếng Pháp.
src/router.tsxSao chép mãSao chép mã vào clipboard
Vì các liên kết được bản địa hóa thông qua cơ chế rewrite, bạn không cần component
LocalizedLinktùy chỉnh: chỉ cần sử dụng componentLinkcủa TanStack Router như bình thường.- đầu vào (input):
Tạo Root Document
getLocale()trả về locale được giải quyết bởi middleware trên server, và locale từ URL trong trình duyệt, vì vậylangvàdirlà đồng nhất trong mã HTML từ server và sau khi hydrate.src/i18n/config.tsSao chép mãSao chép mã vào clipboard
src/routes/__root.tsxSao chép mãSao chép mã vào clipboard
Sử dụng bản dịch trong các trang của bạn
Các thông điệp là các hàm thông thường: import
m, gọi hàm, truyền các biến dưới dạng một đối tượng. Mọi thứ đều được định kiểu (typed), bao gồm cả các biến.src/routes/index.tsxSao chép mãSao chép mã vào clipboard
src/routes/about.tsxSao chép mãSao chép mã vào clipboard
Một hàm thông điệp cũng chấp nhận một locale tường minh:
m.about_title({}, { locale: "fr" }). Điều này hữu ích trong mã server cần kết xuất ngôn ngữ khác với ngôn ngữ của request, chẳng hạn như gửi email.Thay đổi ngôn ngữ nội dung của bạn
Tùy chọnRender bộ chuyển đổi dưới dạng các liên kết với
localizeHref, để trình thu thập dữ liệu (crawler) phát hiện ra mọi ngôn ngữ.setLocalelưu lựa chọn vào cookie và tải lại trang bằng ngôn ngữ mới: tải lại toàn bộ trang là hành vi mặc định của Paraglide, vì các hàm thông điệp đọc locale ở mỗi lần gọi thay vì đăng ký vào một React state.src/components/LocaleSwitcher.tsxSao chép mãSao chép mã vào clipboard
Quốc tế hóa Metadata của bạn
Tùy chọnMỗi phiên bản ngôn ngữ có thể xếp hạng độc lập, miễn là mỗi trang cung cấp:
- một
<title>vàdescriptionđã được dịch; - một URL canonical trỏ về chính nó;
- một thẻ thay thế
hreflangcho mỗi locale, cộng vớix-default; - Open Graph
og:locale,og:locale:alternatevàog:url; - JSON-LD với
inLanguage.
Hàm
localizeUrlcủa Paraglide xây dựng các URL thay thế từurlPatternscủa bạn, vì vậy chúng không bao giờ bị lệch khỏi routing thực tế:src/i18n/seo.tsSao chép mãSao chép mã vào clipboard
- một
Quốc tế hóa Sitemap của bạn
Tùy chọnMột sitemap đa ngôn ngữ liệt kê mọi URL của từng locale, và mỗi mục khai báo tất cả các phiên bản thay thế của nó bằng
xhtml:link:src/routes/sitemap[.]xml.tsSao chép mãSao chép mã vào clipboard
Quốc tế hóa robots.txt của bạn
Tùy chọnCác route riêng tư tồn tại trong mọi ngôn ngữ, vì vậy các quy tắc
Disallowphải bao gồm tất cả các đường dẫn được bản địa hóa. Xóapublic/robots.txtnếu project starter đã tạo, sau đó phục vụ nó từ một route:src/routes/robots[.]txt.tsSao chép mãSao chép mã vào clipboard
Pre-render mọi Locale
Tùy chọnLiệt kê đường dẫn bản địa hóa của từng trang để TanStack Start pre-render tất cả các phiên bản ngôn ngữ.
localizeHreflà mã được tạo tự động không phụ thuộc vào trình duyệt, vì vậy nó có thể chạy trongvite.config.ts, nhưng tệp này chỉ tồn tại sau lần biên dịch đầu tiên. Liệt kê các đường dẫn thủ công, như dưới đây, sẽ tránh được vấn đề thứ tự đó:vite.config.tsSao chép mãSao chép mã vào clipboard
Vì bộ chuyển đổi ngôn ngữ render các liên kết thực,
crawlLinks: truecũng sẽ phát hiện các trang mà bạn quên liệt kê.Xử lý các trang 404 bản địa hóa
Tùy chọnNhờ có cơ chế rewrite,
/fr/does-not-existđược khớp dưới dạng/does-not-exist, vàgetLocale()vẫn trả vềfr, do đó componentnotFoundComponentgốc ở bước 7 sẽ render bằng tiếng Pháp. Một route dạng catch-all đảm bảo các đường dẫn sâu hơn cũng đến được đây. Đánh dấu trang lànoindex: React 19 sẽ tự động đẩy thẻ<meta>lên<head>.src/components/NotFound.tsxSao chép mãSao chép mã vào clipboard
src/routes/$.tsxSao chép mãSao chép mã vào clipboard
Truy cập Locale trong Server Functions
Tùy chọnCác hàm phía server chạy bên trong scope của Paraglide middleware, vì vậy
getLocale()cũng hoạt động tại đó:src/server/sendWelcomeEmail.tsSao chép mãSao chép mã vào clipboard
So sánh với Intlayer
Tùy chọnKhông có adapter chuyển đổi trực tiếp từ Paraglide sang Intlayer, vì cả hai đều đi theo cùng một triết lý: biên dịch nội dung tại thời điểm build và đưa càng ít runtime vào bundle càng tốt. Sự khác biệt nằm ở những gì được gửi tới trình duyệt và cách tổ chức nội dung:
- Các Locale: Intlayer tải từ điển động (dynamic dictionaries) cho từng locale (0% rò rỉ ngôn ngữ trong benchmark), trong khi mỗi hàm thông điệp của Paraglide mang theo tất cả các ngôn ngữ (49.7%).
- Tổ chức nội dung: nội dung có thể nằm trong các tệp
.content.tsbên cạnh từng component, hoặc trong các tệp tập trung. Xem so sánh i18n theo component và i18n tập trung. - Chuyển đổi ngôn ngữ: nội dung được đọc từ một React context, vì vậy việc chuyển đổi locale sẽ re-render mà không cần tải lại trang.
- Mã được tạo: không có gì được tạo bên trong thư mục
src, do đó không cần phải tạo lại mã trước khi commit.
Nếu bạn chuyển từ một thư viện khác thay vì Paraglide, các compat adapter sẽ giữ nguyên API của
use-intl,next-intl,react-i18next,react-intlhoặc Lingui và chỉ thay thế runtime.Xem Intlayer có nhẹ hơn Paraglide không? và Hướng dẫn Intlayer cho TanStack Start.
Tự động hóa bản dịch bằng Intlayer
Tùy chọnParaglide giúp hiển thị các bản dịch, nhưng nó không hỗ trợ bạn tạo chúng. Intlayer là miễn phí và mã nguồn mở, cùng bộ công cụ hữu ích ngay cả trong dự án Paraglide:
- Dịch bằng AI sử dụng API key và nhà cung cấp của riêng bạn. Xem tự động điền (auto fill) và CLI.
- Giữ các tệp JSON của bạn làm nguồn chân lý với plugin đồng bộ JSON.
- Kiểm tra các bản dịch bị thiếu trong quy trình CI. Xem kiểm thử bản dịch của bạn.
- Quét trang web đã triển khai của bạn để phát hiện các thẻ
hreflangbị thiếu, canonical sai và rò rỉ ngôn ngữ với lệnh scan.
Các câu hỏi thường gặp
Đó là một lựa chọn đáng tin cậy: nó được sử dụng trong các ví dụ chính thức của TanStack Router, có runtime nhỏ nhất trong bài kiểm thử benchmark (~1.8 KB gzip), và các thông điệp có kiểu dữ liệu đầy đủ. Sự đánh đổi là mỗi hàm thông điệp chứa toàn bộ các locale, làm rò rỉ khoảng một nửa chuỗi dịch tới người dùng ngôn ngữ khác, và việc đổi ngôn ngữ sẽ tải lại trang.
Không. Router rewrite loại bỏ tiền tố locale trước khi khớp route và thêm lại nó vào các liên kết được tạo, nhờ đó một tệp about.tsx duy nhất có thể phục vụ /about, /fr/about và /es/about.
Các hàm thông điệp đọc locale khi chúng được gọi, chúng không đăng ký lắng nghe state trong React. Vì vậy setLocale mặc định tải lại trang để mọi thông điệp được render lại bằng ngôn ngữ mới. Bạn có thể truyền { reload: false }, nhưng khi đó bạn phải tự xử lý việc render lại cây component.
Tốt hơn là không nên. Thư mục này được tạo lại sau mỗi lần chạy dev và build, và việc commit nó sẽ gây ra xung đột merge trên các tệp tự sinh. Hãy commit messages/*.json và project.inlang/settings.json thay vào đó.
Sử dụng localizeUrl để xây dựng một URL tuyệt đối cho mỗi locale trong hàm head() của route, và thêm x-default trỏ về locale cơ sở. Bước 10 cung cấp một hàm helper có thể tái sử dụng, và bước 11 thêm các liên kết thay thế tương tự vào sitemap.
Các thông điệp (messages) không sử dụng sẽ bị loại bỏ khi bạn dùng outputStructure: "message-modules", vì vậy nội dung của các trang khác không bị rò rỉ. Tuy nhiên các ngôn ngữ (locales) không dùng đến thì không: mỗi hàm thông điệp chứa tất cả các bản dịch, đó là lý do benchmark ghi nhận mức rò rỉ ngôn ngữ 49.7%.
Bình luận
Chưa có bình luận nào. Hãy là người đầu tiên chia sẻ suy nghĩ của bạn.
