Đặ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 Lingui vào năm 2026
Mục lục
Lingui là gì?
Lingui là một thư viện i18n được xây dựng xoay quanh macro và trích xuất thông điệp (message extraction). Bạn viết văn bản nguồn trực tiếp trong các component của mình ( t`Hello` , <Trans>Hello</Trans>), lệnh lingui extract sẽ thu thập mọi thông điệp vào các catalog (mặc định là các tệp PO), các biên dịch viên sẽ điền nội dung bản dịch, và Vite plugin sẽ biên dịch chúng thành JavaScript nhỏ gọn. Các thông điệp sử dụng ICU MessageFormat, vì vậy hỗ trợ đầy đủ số nhiều (plural) và lựa chọn (select).
TanStack Start không đi kèm sẵn một tầng i18n, do đó hướng dẫn này sẽ tích hợp Lingui vào dự án từ đầu:
- Các macro được biên dịch bởi Babel thông qua
@rolldown/plugin-babel(bắt buộc với@vitejs/plugin-reactv6 và Vite 8). - Định tuyến ngôn ngữ (locale routing) với một phân đoạn tùy chọn
{-$locale}(/about,/fr/about). - Mỗi ngôn ngữ một catalog, được tải theo nhu cầu (on demand), và một instance
I18nriêng cho mỗi lần render để các yêu cầu SSR đồng thời không bao giờ chia sẻ trạng thái ngôn ngữ. - SEO đa ngôn ngữ hoàn chỉnh:
<title>và description đã dịch, URL chuẩn (canonical),hreflangvớix-default, Open Graph locales, 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 bộ công nghệ khác? Xem hướng dẫn TanStack Start + use-intl, hướng dẫn TanStack Start + Paraglide, hoặc hướng dẫn TanStack Start + Intlayer.
Bạn đang sử dụng Next.js? Xem hướng dẫn Next.js + Lingui. So sánh các thư viện? Đọc bài viết Lingui vs Intlayer.
Benchmark nói gì về Lingui trên TanStack Start
Bài 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 những gì trình duyệt thực sự tải xuống.
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 @lingui/core@6.6.0, đ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
| Cấu hình | Kích thước thư viện | JS mỗi trang | Rò rỉ ngôn ngữ khác | Rò rỉ trang khác |
|---|---|---|---|---|
| Không i18n (ứng dụng gốc) | - | 111.0 KB | 0% | 0% |
| Lingui (cấu hình trong bài này) | 56.7 KB | 115.2 KB | 9.3% | 0% |
@intlayer/lingui (compat) | 9.8 KB | 136.7 KB | 9.9% | 0% |
react-intlayer (Intlayer gốc) | 4.5 KB | 126.8 KB | 0% | 0% |
Những điểm cốt lõi cần lưu ý:
- Tải một catalog cho mỗi ngôn ngữ theo nhu cầu. Điều này giữ cho dung lượng các trang gần với ứng dụng gốc.
- Runtime vẫn tương đối nặng (~57 KB gzip). Adapter tương thích
@intlayer/lingui(bước 16) giữ nguyên các macro của bạn và giảm kích thước xuống còn ~10 KB.
Xem toàn bộ dữ liệu tại: 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 Lingui so sánh với các thư viện khác thường 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 vị trí (Co-located) | ❌ JSON tập trung | ❌ Một tệp JSON cho mỗi ngôn ngữ | ⚠️ Văn bản nguồn trong component |
| Tích hợp TypeScript | ✅ Kiểu dữ liệu tự động tạo | ✅ Qua AppConfig | ✅ Các hàm thông điệp có kiểu | ⚠️ Chỉ macro |
| Phát hiện thiếu bản dịch | ✅ Lỗi kiểu và cảnh báo lúc build | ⚠️ Dự phòng runtime | ⚠️ Dự phòng về ngôn ngữ gốc | ⚠️ Dự phòng về văn bản nguồn |
| Nội dung phong phú (JSX, Markdown) | ✅ Hỗ trợ trực tiếp | ⚠️ Thẻ qua t.rich | ⚠️ Chuỗi | ✅ JSX bên trong <Trans> |
| Định tuyến bản địa hóa | ✅ Tích hợp sẵn | ❌ Thủ công {-$locale} | ✅ urlPatterns + viết lại router | ❌ Thủ công {-$locale} |
| Chuyển ngôn ngữ không cần tải lại | ✅ 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 tự động bằng AI | ✅ Nhà cung cấp và API key của bạn | ❌ Không | ❌ Không | ❌ Không |
| Trình chỉnh sửa trực quan / CMS | ✅ Editor cục bộ + CMS tùy chọn | ❌ Nền tảng bên ngoài | ⚠️ Các ứ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 (ngôn ngữ / trang) | 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 |
Các số liệu về kích thước runtime và rò rỉ đến từ benchmark TanStack Start. Rò rỉ được đo trên cấu hình tối ưu nhất của từng thư viện.
Các hướng dẫn khác cho TanStack Start: use-intl, Paraglide JS, và Intlayer.
Các thực hành tốt nhất bạn nên tuân thủ
- Thiết lập
langvàdirtrên thẻ<html>từ ngôn ngữ của route, đảm bảo chúng chính xác trong HTML phía server. - Giữ một URL riêng cho mỗi ngôn ngữ với tiền tố prefix, để mọi phiên bản ngôn ngữ đều có thể được lập chỉ mục.
- Tạo một instance
I18nriêng cho mỗi ngôn ngữ, không bao giờ thay đổi một instance toàn cục trong quá trình SSR: hai yêu cầu đồng thời có thể ghi đè ngôn ngữ của nhau. - Chỉ tải catalog đang hoạt động, không bao giờ import tất cả catalog trong mã phía client.
- Chọn một phong cách macro nhất quán (
useLingui+ttrong component,msgcho các descriptor lười tải) và kiên định với nó. Việc kết hợp lẫn lộnt,i18n._,i18n.tvà<Trans>làm cho mã nguồn trở nên khó đọc hơn đối với con người và các trợ lý AI. - Chạy
lingui extracttrong CI để không có thông điệp mới nào bị đưa lên mà chưa được dịch. - Dịch metadata của bạn, đồng thời khai báo
canonical,hreflangvàx-defaulttrên mỗi trang. - Tạo sitemap và robots.txt đa ngôn ngữ, và pre-render mọi ngôn ngữ.
- Sử dụng các thẻ liên kết thật cho bộ chuyển đổi ngôn ngữ, để trình thu thập dữ liệu (crawlers) có thể khám phá mọi 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 Lingui 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
Cài đặt các gói phụ thuộc
bashSao chép mãSao chép mã vào clipboard
- @lingui/core / @lingui/react: runtime,
I18nProvidervà các macro (@lingui/core/macro,@lingui/react/macro). - @lingui/cli: lệnh
lingui extractđể thu thập thông điệp vào các catalog. - @lingui/vite-plugin: biên dịch các catalog
.pokhi import, vì vậy không cần chạy lệnhlingui compile. - @lingui/babel-plugin-lingui-macro + @rolldown/plugin-babel: chuyển đổi các macro tại thời điểm build.
- @lingui/core / @lingui/react: runtime,
Tập trung hóa cấu hình ngôn ngữ của bạn
Ngôn ngữ mặc định không có tiền tố (
/about), các ngôn ngữ khác có tiền tố (/fr/about).src/i18n/config.tsSao chép mãSao chép mã vào clipboard
Cấu hình Lingui
Cấu hình Lingui tái sử dụng cùng danh sách ngôn ngữ, do đó các catalog, router và sitemap không bao giờ bị lệch nhau.
lingui.config.tsSao chép mãSao chép mã vào clipboard
Thêm các script trích xuất:
package.jsonSao chép mãSao chép mã vào clipboard
i18n:checksẽ thất bại trong CI khi một component chứa thông điệp chưa được trích xuất và commit.Cấu hình Vite
Với
@vitejs/plugin-reactv6, Babel không còn được tích hợp sẵn.@rolldown/plugin-babelsẽ chạy plugin macro của Lingui, vàlinguiTransformerBabelPresetchỉ xử lý các tệp có import macro, giúp quá trình build diễn ra nhanh chóng.vite.config.tsSao chép mãSao chép mã vào clipboard
Tải Catalog theo từng ngôn ngữ
Template literal trong
import()cho phép Vite xuất ra mỗi catalog một chunk riêng, và Lingui plugin sẽ biên dịch tệp.povào đó. Người dùng tiếng Pháp sẽ chỉ tải riêng catalog tiếng Pháp.Các thông điệp đã biên dịch là dữ liệu thuần túy, do đó chúng có thể được trả về bởi route loader, tuần tự hóa vào HTML và tái sử dụng khi hydration.
src/i18n/lingui.tsSao chép mãSao chép mã vào clipboard
Để TypeScript chấp nhận cú pháp import
.po, hãy khai báo module một lần:src/i18n/po.d.tsSao chép mãSao chép mã vào clipboard
Tạo tài liệu Root
Root route đọc param ngôn ngữ tùy chọn để thiết lập
langvàdirtrên thẻ<html>được render phía server.src/routes/__root.tsxSao chép mãSao chép mã vào clipboard
Tạo Locale Layout Route
Thư mục
{-$locale}tạo ra một phân đoạn đường dẫn tùy chọn:/aboutvà/fr/aboutđều khớp với/{-$locale}/about. Layout sẽ từ chối các tiền tố không hợp lệ, tải catalog của ngôn ngữ hiện tại và cung cấp một instanceI18nriêng biệt.src/routes/{-$locale}/route.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
Viết văn bản nguồn trực tiếp trong component. Các macro sẽ biến nó thành các message ID tại thời điểm build, và
lingui extractsẽ thu thập chúng.<Trans>cho nội dung JSX, bao gồm các phần tử lồng nhau;useLingui().tcho chuỗi (thuộc tính, props);<Plural>cho số nhiều ICU.
src/routes/{-$locale}/about.tsxSao chép mãSao chép mã vào clipboard
Thao tác
import()động của catalog được lưu vào bộ nhớ cache bởi hệ thống module, do đó việc gọiloadI18ntrong nhiều loader sẽ không tải catalog lại hai lần.Trích xuất và dịch thông điệp của bạn
Chạy lệnh trích xuất. Lingui sẽ ghi mọi thông điệp vào catalog của từng ngôn ngữ:
bashSao chép mãSao chép mã vào clipboard
Sau đó dịch trường
msgstrcủa từng mục:src/locales/fr/messages.poSao chép mãSao chép mã vào clipboard
src/locales/es/messages.poSao chép mãSao chép mã vào clipboard
Theo mặc định, message ID là mã băm (hash) của văn bản nguồn: việc thay đổi văn bản tiếng Anh sẽ tạo ra một thông điệp mới. Sử dụng ID tường minh (
<Trans id="about.title">About us</Trans>) cho các văn bản thường xuyên thay đổi.Xây dựng Component liên kết bản địa hóa
Tùy chọnMọi route đều nằm dưới
{-$locale}, vì vậy các liên kết phải mang theo param ngôn ngữ hiện tại.src/components/LocalizedLink.tsxSao chép mãSao chép mã vào clipboard
Thay đổi ngôn ngữ nội dung của bạn
Tùy chọnHiển thị bộ chuyển đổi dưới dạng các thẻ liên kết (links) để các trình thu thập dữ liệu tìm thấy mọi phiên bản ngôn ngữ.
to="."giữ nguyên trang hiện tại và thay thế param ngôn ngữ. Loader của layout ngôn ngữ sau đó sẽ nạp catalog mới.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
<title>và description đã được dịch, thẻ canonical tự tham chiếu, mộthreflangcho mỗi ngôn ngữ cộng vớix-default, Open Graph locales và JSON-LD vớiinLanguage. Metadata được dịch trong loader (bước 8), và helper này sẽ xây dựng phần còn lại:src/i18n/seo.tsSao chép mãSao chép mã vào clipboard
Quốc tế hóa Sitemap và robots.txt của bạn
Tùy chọnSitemap liệt kê mọi URL của từng ngôn ngữ, mỗi mục khai báo tất cả các phiên bản thay thế với
xhtml:link.robots.txtchặn các đường dẫn riêng tư trong mọi ngôn ngữ và trỏ tới sitemap. Xóapublic/robots.txtnếu mẫu starter đã tạo một tệp như vậy.src/routes/sitemap[.]xml.tsSao chép mãSao chép mã vào clipboard
src/routes/robots[.]txt.tsSao chép mãSao chép mã vào clipboard
Pre-render mọi ngôn ngữ
Tùy chọnLiệt kê mọi đường dẫn đã bản địa hóa để TanStack Start pre-render tất cả các phiên bản ngôn ngữ tại thời điểm build:
vite.config.tsSao chép mãSao chép mã vào clipboard
Chuyển hướng khách truy cập lần đầu và xử lý trang 404
Tùy chọnMột request middleware sẽ chuyển khách truy cập khi vào
/tới ngôn ngữ ưu tiên của họ (ưu tiên cookie trước, sau đó đếnAccept-Language). Các deep link không bao giờ bị chuyển hướng, đảm bảo trình thu thập dữ liệu và các URL được chia sẻ luôn nhận đúng trang được yêu cầu.src/i18n/negotiateLocale.tsSao chép mãSao chép mã vào clipboard
src/start.tsSao chép mãSao chép mã vào clipboard
Đối với các trang 404, một catch-all route sẽ render component
notFoundComponentđã được bản địa hóa của layout. Đánh dấu trang vớinoindex: React 19 sẽ tự động đưa thẻ<meta>lên<head>.src/components/NotFound.tsxSao chép mãSao chép mã vào clipboard
src/routes/{-$locale}/$.tsxSao chép mãSao chép mã vào clipboard
Giữ lại Macro, Giảm thiểu Runtime với Intlayer
Tùy chọnAdapter tương thích
@intlayer/linguigiữ nguyên mã nguồn của bạn: các macro vẫn được biên dịch chính xác như trước, và các lời gọii18n._(),useLingui()cùng<Trans>được phục vụ bởi các dictionary Intlayer đã biên dịch. Trong bài benchmark, kích thước runtime giảm từ ~56.7 KB xuống còn ~9.8 KB gzip.bashSao chép mãSao chép mã vào clipboard
Thêm plugin sau bước chuyển đổi macro để plugin này alias
@lingui/corevà@lingui/reactsang adapter:vite.config.tsSao chép mãSao chép mã vào clipboard
Các catalog được đồng bộ hóa với plugin sync JSON (cho catalog JSON) hoặc plugin sync PO (cho catalog PO). Xem toàn bộ cấu hình trong hướng dẫn tương thích Lingui, và xem so sánh chi tiết trong bài viết Lingui vs @intlayer/lingui.
Tự động hóa bản dịch của bạn với Intlayer
Tùy chọnLingui giúp trích xuất thông điệp, nhưng việc điền hàng chục catalog bằng tay là công đoạn tốn nhiều thời gian nhất. Intlayer là công cụ miễn phí và mã nguồn mở, hoạt động song song cùng Lingui:
- Dịch tự động bằng AI sử dụng API key và nhà cung cấp của riêng bạn. Xem tự động điền bản dịch và CLI.
- Giữ các tệp PO của bạn làm nguồn chân lý duy nhất với plugin sync PO.
- Kiểm tra thiếu bản dịch trong CI. Xem kiểm thử bản dịch.
- Kiểm tra website đã triển khai để phát hiện thiếu
hreflang, canonical sai và rò rỉ ngôn ngữ với lệnh scan.
Các câu hỏi thường gặp
Có. Lingui không có gói tích hợp riêng cho TanStack Start, nhưng Vite plugin và Babel macro plugin của nó hoạt động hoàn toàn bình thường. Hai điểm mấu chốt cần thực hiện đúng là chạy các macro qua @rolldown/plugin-babel (Vite 8 và @vitejs/plugin-react v6 không còn tích hợp sẵn Babel), và tạo một instance I18n riêng cho mỗi ngôn ngữ thay vì kích hoạt một instance toàn cục trong quá trình SSR.
Trên server, một tiến trình duy nhất sẽ render nhiều request cùng một thời điểm. Việc gọi i18n.activate("fr") trên một đối tượng chia sẻ chung sẽ làm thay đổi ngôn ngữ của một request đang render tiếng Anh song song. setupI18n tạo ra một instance độc lập cho từng ngôn ngữ, đảm bảo an toàn tuyệt đối.
Không. @lingui/vite-plugin sẽ tự động biên dịch các catalog .po khi chúng được import. Bạn chỉ cần chạy lingui extract để thu thập các thông điệp mới.
Khai báo chúng với macro msg, và dịch chúng trong route loader bằng i18n._(msg`...`). Loader sẽ trả về các chuỗi thuần túy, do đó head() luôn đồng bộ và các giá trị được tuần tự hóa cho quá trình hydration. Bước 8 và bước 12 sẽ hướng dẫn chi tiết cách thiết lập này.
Bài benchmark đo được khoảng ~56.7 KB gzip cho runtime. Khi tải mỗi ngôn ngữ một catalog theo nhu cầu, các trang nặng khoảng ~115 KB so với 111 KB khi không có i18n. Nếu import tĩnh tất cả các catalog, dung lượng sẽ tăng lên ~152 KB.
Có. Adapter @intlayer/lingui giữ nguyên các macro và thay thế phần runtime. Sau đó, bạn có thể chuyển đổi dần từng component sang useIntlayer. Xem các adapter tương thích.
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.
