@intlayer/docs 8.9.4 → 8.9.6-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/docs/ar/benchmark/index.md +0 -3
  2. package/docs/ar/benchmark/nextjs.md +15 -6
  3. package/docs/ar/benchmark/solid.md +155 -0
  4. package/docs/ar/benchmark/svelte.md +148 -0
  5. package/docs/ar/benchmark/tanstack.md +12 -3
  6. package/docs/ar/benchmark/vue.md +160 -0
  7. package/docs/ar/configuration.md +16 -12
  8. package/docs/ar/dictionary/content_file.md +51 -1
  9. package/docs/ar/plugins/sync-po.md +0 -21
  10. package/docs/bn/configuration.md +16 -12
  11. package/docs/cs/configuration.md +16 -12
  12. package/docs/de/benchmark/index.md +0 -3
  13. package/docs/de/benchmark/nextjs.md +15 -6
  14. package/docs/de/benchmark/solid.md +155 -0
  15. package/docs/de/benchmark/svelte.md +148 -0
  16. package/docs/de/benchmark/tanstack.md +12 -3
  17. package/docs/de/benchmark/vue.md +160 -0
  18. package/docs/de/configuration.md +16 -12
  19. package/docs/de/dictionary/content_file.md +52 -2
  20. package/docs/de/plugins/sync-po.md +0 -22
  21. package/docs/en/benchmark/nextjs.md +11 -2
  22. package/docs/en/benchmark/solid.md +22 -4
  23. package/docs/en/benchmark/svelte.md +17 -5
  24. package/docs/en/benchmark/tanstack.md +18 -3
  25. package/docs/en/benchmark/vue.md +17 -11
  26. package/docs/en/configuration.md +16 -13
  27. package/docs/en/dictionary/content_file.md +51 -1
  28. package/docs/en/plugins/sync-po.md +0 -21
  29. package/docs/en-GB/benchmark/index.md +0 -3
  30. package/docs/en-GB/benchmark/nextjs.md +15 -6
  31. package/docs/en-GB/benchmark/solid.md +155 -0
  32. package/docs/en-GB/benchmark/svelte.md +148 -0
  33. package/docs/en-GB/benchmark/tanstack.md +12 -3
  34. package/docs/en-GB/benchmark/vue.md +160 -0
  35. package/docs/en-GB/configuration.md +15 -11
  36. package/docs/en-GB/dictionary/content_file.md +51 -1
  37. package/docs/en-GB/plugins/sync-po.md +0 -21
  38. package/docs/es/benchmark/index.md +0 -3
  39. package/docs/es/benchmark/nextjs.md +15 -6
  40. package/docs/es/benchmark/solid.md +155 -0
  41. package/docs/es/benchmark/svelte.md +148 -0
  42. package/docs/es/benchmark/tanstack.md +12 -3
  43. package/docs/es/benchmark/vue.md +160 -0
  44. package/docs/es/configuration.md +16 -12
  45. package/docs/es/dictionary/content_file.md +51 -1
  46. package/docs/es/plugins/sync-po.md +0 -21
  47. package/docs/fr/benchmark/index.md +0 -3
  48. package/docs/fr/benchmark/nextjs.md +15 -6
  49. package/docs/fr/benchmark/solid.md +155 -0
  50. package/docs/fr/benchmark/svelte.md +148 -0
  51. package/docs/fr/benchmark/tanstack.md +12 -3
  52. package/docs/fr/benchmark/vue.md +160 -0
  53. package/docs/fr/configuration.md +16 -12
  54. package/docs/fr/dictionary/content_file.md +51 -1
  55. package/docs/fr/plugins/sync-po.md +0 -21
  56. package/docs/hi/benchmark/nextjs.md +15 -6
  57. package/docs/hi/benchmark/solid.md +155 -0
  58. package/docs/hi/benchmark/svelte.md +148 -0
  59. package/docs/hi/benchmark/tanstack.md +12 -3
  60. package/docs/hi/benchmark/vue.md +160 -0
  61. package/docs/hi/configuration.md +16 -12
  62. package/docs/hi/dictionary/content_file.md +51 -1
  63. package/docs/hi/plugins/sync-po.md +0 -21
  64. package/docs/id/benchmark/index.md +0 -3
  65. package/docs/id/benchmark/nextjs.md +15 -6
  66. package/docs/id/benchmark/solid.md +155 -0
  67. package/docs/id/benchmark/svelte.md +148 -0
  68. package/docs/id/benchmark/tanstack.md +12 -3
  69. package/docs/id/benchmark/vue.md +160 -0
  70. package/docs/id/configuration.md +16 -12
  71. package/docs/id/dictionary/content_file.md +51 -1
  72. package/docs/id/plugins/sync-po.md +0 -21
  73. package/docs/it/benchmark/index.md +1 -4
  74. package/docs/it/benchmark/nextjs.md +15 -6
  75. package/docs/it/benchmark/solid.md +155 -0
  76. package/docs/it/benchmark/svelte.md +148 -0
  77. package/docs/it/benchmark/tanstack.md +12 -3
  78. package/docs/it/benchmark/vue.md +160 -0
  79. package/docs/it/configuration.md +16 -12
  80. package/docs/it/dictionary/content_file.md +51 -1
  81. package/docs/it/plugins/sync-po.md +0 -21
  82. package/docs/ja/benchmark/index.md +5 -5
  83. package/docs/ja/benchmark/nextjs.md +15 -6
  84. package/docs/ja/benchmark/solid.md +155 -0
  85. package/docs/ja/benchmark/svelte.md +148 -0
  86. package/docs/ja/benchmark/tanstack.md +12 -3
  87. package/docs/ja/benchmark/vue.md +160 -0
  88. package/docs/ja/configuration.md +16 -12
  89. package/docs/ja/dictionary/content_file.md +50 -2
  90. package/docs/ja/intlayer_with_nextjs_no_locale_path.md +4 -3
  91. package/docs/ja/plugins/sync-po.md +0 -21
  92. package/docs/ko/benchmark/nextjs.md +15 -6
  93. package/docs/ko/benchmark/solid.md +155 -0
  94. package/docs/ko/benchmark/svelte.md +148 -0
  95. package/docs/ko/benchmark/tanstack.md +12 -3
  96. package/docs/ko/benchmark/vue.md +160 -0
  97. package/docs/ko/configuration.md +16 -12
  98. package/docs/ko/dictionary/content_file.md +51 -1
  99. package/docs/ko/intlayer_with_nextjs_no_locale_path.md +3 -2
  100. package/docs/ko/plugins/sync-po.md +0 -21
  101. package/docs/nl/configuration.md +16 -12
  102. package/docs/pl/benchmark/index.md +0 -3
  103. package/docs/pl/benchmark/nextjs.md +15 -6
  104. package/docs/pl/benchmark/solid.md +155 -0
  105. package/docs/pl/benchmark/svelte.md +148 -0
  106. package/docs/pl/benchmark/tanstack.md +12 -3
  107. package/docs/pl/benchmark/vue.md +160 -0
  108. package/docs/pl/configuration.md +16 -12
  109. package/docs/pl/dictionary/content_file.md +51 -1
  110. package/docs/pl/plugins/sync-po.md +0 -21
  111. package/docs/pt/benchmark/index.md +0 -3
  112. package/docs/pt/benchmark/nextjs.md +16 -7
  113. package/docs/pt/benchmark/solid.md +155 -0
  114. package/docs/pt/benchmark/svelte.md +148 -0
  115. package/docs/pt/benchmark/tanstack.md +13 -4
  116. package/docs/pt/benchmark/vue.md +160 -0
  117. package/docs/pt/configuration.md +16 -12
  118. package/docs/pt/dictionary/content_file.md +51 -1
  119. package/docs/pt/plugins/sync-po.md +0 -21
  120. package/docs/ru/benchmark/nextjs.md +15 -6
  121. package/docs/ru/benchmark/solid.md +155 -0
  122. package/docs/ru/benchmark/svelte.md +148 -0
  123. package/docs/ru/benchmark/tanstack.md +12 -3
  124. package/docs/ru/benchmark/vue.md +160 -0
  125. package/docs/ru/configuration.md +16 -12
  126. package/docs/ru/dictionary/content_file.md +52 -2
  127. package/docs/ru/plugins/sync-po.md +0 -21
  128. package/docs/tr/benchmark/index.md +0 -3
  129. package/docs/tr/benchmark/nextjs.md +15 -6
  130. package/docs/tr/benchmark/solid.md +155 -0
  131. package/docs/tr/benchmark/svelte.md +148 -0
  132. package/docs/tr/benchmark/tanstack.md +12 -3
  133. package/docs/tr/benchmark/vue.md +160 -0
  134. package/docs/tr/configuration.md +16 -12
  135. package/docs/tr/dictionary/content_file.md +51 -1
  136. package/docs/tr/plugins/sync-po.md +0 -21
  137. package/docs/uk/benchmark/nextjs.md +15 -6
  138. package/docs/uk/benchmark/solid.md +155 -0
  139. package/docs/uk/benchmark/svelte.md +148 -0
  140. package/docs/uk/benchmark/tanstack.md +12 -3
  141. package/docs/uk/benchmark/vue.md +160 -0
  142. package/docs/uk/configuration.md +16 -12
  143. package/docs/uk/dictionary/content_file.md +51 -1
  144. package/docs/uk/plugins/sync-po.md +0 -21
  145. package/docs/ur/configuration.md +16 -12
  146. package/docs/vi/benchmark/index.md +0 -3
  147. package/docs/vi/benchmark/nextjs.md +15 -6
  148. package/docs/vi/benchmark/solid.md +155 -0
  149. package/docs/vi/benchmark/svelte.md +148 -0
  150. package/docs/vi/benchmark/tanstack.md +12 -3
  151. package/docs/vi/benchmark/vue.md +160 -0
  152. package/docs/vi/configuration.md +16 -12
  153. package/docs/vi/dictionary/content_file.md +51 -1
  154. package/docs/vi/intlayer_with_nextjs_15.md +10 -57
  155. package/docs/vi/plugins/sync-po.md +0 -21
  156. package/docs/zh/benchmark/nextjs.md +15 -6
  157. package/docs/zh/benchmark/solid.md +155 -0
  158. package/docs/zh/benchmark/svelte.md +148 -0
  159. package/docs/zh/benchmark/tanstack.md +12 -3
  160. package/docs/zh/benchmark/vue.md +160 -0
  161. package/docs/zh/configuration.md +16 -12
  162. package/docs/zh/dictionary/content_file.md +51 -3
  163. package/docs/zh/plugins/sync-po.md +0 -21
  164. package/frequent_questions/ar/intlayerNode.md +3 -3
  165. package/frequent_questions/de/intlayerNode.md +3 -3
  166. package/frequent_questions/en/intlayerNode.md +3 -3
  167. package/frequent_questions/en-GB/intlayerNode.md +3 -3
  168. package/frequent_questions/es/intlayerNode.md +3 -3
  169. package/frequent_questions/fr/intlayerNode.md +3 -3
  170. package/frequent_questions/hi/intlayerNode.md +3 -3
  171. package/frequent_questions/id/intlayerNode.md +3 -3
  172. package/frequent_questions/it/intlayerNode.md +3 -3
  173. package/frequent_questions/ja/intlayerNode.md +3 -3
  174. package/frequent_questions/ko/intlayerNode.md +3 -3
  175. package/frequent_questions/pl/intlayerNode.md +3 -3
  176. package/frequent_questions/pt/intlayerNode.md +3 -3
  177. package/frequent_questions/ru/intlayerNode.md +3 -3
  178. package/frequent_questions/tr/intlayerNode.md +3 -3
  179. package/frequent_questions/uk/intlayerNode.md +3 -3
  180. package/frequent_questions/vi/intlayerNode.md +3 -3
  181. package/frequent_questions/zh/intlayerNode.md +3 -3
  182. package/package.json +8 -8
@@ -0,0 +1,160 @@
1
+ ---
2
+ createdAt: 2026-04-20
3
+ updatedAt: 2026-04-21
4
+ title: Giải pháp i18n tốt nhất cho Vue năm 2026 - Báo cáo Benchmark
5
+ description: So sánh các thư viện quốc tế hóa (i18n) Vue như vue-i18n, fluent-vue và Intlayer. Báo cáo hiệu suất chi tiết về kích thước bundle, rò rỉ và tính phản ứng.
6
+ keywords:
7
+ - benchmark
8
+ - i18n
9
+ - intl
10
+ - vue
11
+ - hiệu suất
12
+ - intlayer
13
+ slugs:
14
+ - doc
15
+ - benchmark
16
+ - vue
17
+ author: Aymeric PINEAU
18
+ applicationTemplate: https://github.com/intlayer-org/benchmark-i18n-vue-template
19
+ history:
20
+ - version: 8.7.12
21
+ date: 2026-01-06
22
+ changes: "Khởi tạo benchmark"
23
+ ---
24
+
25
+ # Thư viện i18n cho Vue — Báo cáo Benchmark 2026
26
+
27
+ Trang này là báo cáo benchmark cho các giải pháp i18n trên Vue.
28
+
29
+ ## Mục lục
30
+
31
+ <Toc/>
32
+
33
+ ## Benchmark tương tác
34
+
35
+ <I18nBenchmark framework="vite-vue" vertical/>
36
+
37
+ ## Tham chiếu kết quả:
38
+
39
+ <iframe
40
+ src="https://intlayer.org/markdown?url=https%3A%2F%2Fraw.githubusercontent.com%2Fintlayer-org%2Fbenchmark-i18n%2Fmain%2Freport%2Fscripts%2Fsummarize-vite_vue.md"
41
+ width="100%"
42
+ height="600px"
43
+ style="border:none;">
44
+ </iframe>
45
+
46
+ > https://intlayer.org/markdown?url=https%3A%2F%2Fraw.githubusercontent.com%2Fintlayer-org%2Fbenchmark-i18n%2Fmain%2Freport%2Fscripts%2Fsummarize-vite_vue.md
47
+
48
+ Xem toàn bộ kho lưu trữ benchmark [tại đây](https://github.com/intlayer-org/benchmark-i18n/tree/main).
49
+
50
+ ## Giới thiệu
51
+
52
+ Các giải pháp quốc tế hóa là một trong những phụ thuộc nặng nhất trong một ứng dụng Vue. Rủi ro chính là việc gửi nội dung không cần thiết: bản dịch cho các trang khác và các ngôn ngữ khác trong bundle của một route duy nhất.
53
+
54
+ Khi ứng dụng của bạn phát triển, vấn đề đó có thể nhanh chóng làm bùng nổ lượng JavaScript gửi đến client và làm chậm quá trình điều hướng.
55
+
56
+ Trong thực tế, đối với các triển khai ít được tối ưu hóa nhất, một trang quốc tế hóa có thể nặng hơn gấp nhiều lần so với phiên bản không có i18n.
57
+
58
+ Tác động khác là đối với trải nghiệm nhà phát triển (DX): cách bạn khai báo nội dung, kiểu (types), tổ chức namespace, tải động và tính phản ứng khi thay đổi ngôn ngữ.
59
+
60
+ ## TL;DR
61
+
62
+ - **Intlayer**: Giải pháp nhẹ nhất (v8.7.12) với tính năng scoping và tải động gốc.
63
+ - **vue-i18n**: Tiêu chuẩn ngành với hệ sinh thái phong phú, nhưng có thể trở nên nặng hơn đáng kể và khó tối ưu hóa cho code-splitting trong các ứng dụng lớn.
64
+ - **fluent-vue**: Tổ chức thông báo sáng tạo nhưng thiếu an toàn kiểu (type-safety) và hóa ra là một giải pháp cực kỳ nặng.
65
+
66
+ ## Kiểm tra ứng dụng của bạn
67
+
68
+ Để nhanh chóng phát hiện các vấn đề rò rỉ i18n, tôi đã thiết lập một trình quét miễn phí có sẵn [tại đây](https://intlayer.org/i18n-seo-scanner).
69
+
70
+ <iframe src="https://intlayer.org/i18n-seo-scanner" width="100%" height="600px" style="border:none;"/>
71
+
72
+ ## Vấn đề
73
+
74
+ Hai đòn bẩy là thiết yếu để hạn chế chi phí của một ứng dụng đa ngôn ngữ:
75
+
76
+ - Chia nhỏ nội dung theo trang / namespace để bạn không tải toàn bộ từ điển khi không cần thiết.
77
+ - Tải ngôn ngữ chính xác một cách linh hoạt, chỉ khi cần thiết.
78
+
79
+ Hiểu các hạn chế kỹ thuật của các phương pháp này:
80
+
81
+ **Tải động (Dynamic loading)**
82
+
83
+ Nếu không có tải động, hầu hết các giải pháp giữ tin nhắn trong bộ nhớ từ lần render đầu tiên, điều này làm tăng đáng kể overhead cho các ứng dụng có nhiều route và ngôn ngữ.
84
+
85
+ Với tải động, bạn chấp nhận một sự đánh đổi: ít JS ban đầu hơn, nhưng đôi khi có thêm một request khi chuyển đổi ngôn ngữ.
86
+
87
+ **Chia tách nội dung (Splitting)**
88
+
89
+ Các cú pháp được xây dựng xung quanh `const { t } = useI18n()` + `t('a.b.c')` rất tiện lợi nhưng thường khuyến khích giữ các đối tượng JSON lớn khi runtime. Mô hình đó làm cho tree-shaking trở nên khó khăn trừ khi thư viện cung cấp một chiến lược chia tách thực sự theo từng trang.
90
+
91
+ ## Phương pháp nghiên cứu
92
+
93
+ Đối với benchmark này, chúng tôi đã so sánh các thư viện sau:
94
+
95
+ - `Base App` (Không có thư viện i18n)
96
+ - `vue-intlayer` (v8.7.12)
97
+ - `vue-i18n` (v11.4.0)
98
+ - `fluent-vue` (v3.8.2)
99
+
100
+ Framework là `Vue` với một ứng dụng đa ngôn ngữ gồm **10 trang** và **10 ngôn ngữ**.
101
+
102
+ Chúng tôi đã so sánh **bốn chiến lược tải**:
103
+
104
+ | Chiến lược | Không có namespace (toàn cục) | Có namespace (phạm vi/scoped) |
105
+ | :----------- | :---------------------------------------------- | :----------------------------------------------------------------- |
106
+ | **Tải tĩnh** | **Static**: Mọi thứ trong bộ nhớ khi khởi động. | **Scoped static**: Chia theo namespace; mọi thứ tải khi khởi động. |
107
+ | **Tải động** | **Dynamic**: Tải theo yêu cầu cho mỗi ngôn ngữ. | **Scoped dynamic**: Tải chi tiết theo namespace và ngôn ngữ. |
108
+
109
+ ## Tóm tắt chiến lược
110
+
111
+ - **Static**: Đơn giản; không có độ trễ mạng sau lần tải đầu tiên. Nhược điểm: kích thước bundle lớn.
112
+ - **Dynamic**: Giảm trọng lượng ban đầu (lazy-loading). Lý tưởng khi bạn có nhiều ngôn ngữ.
113
+ - **Scoped static**: Giữ cho mã được tổ chức (tách biệt logic) mà không cần các request mạng bổ sung phức tạp.
114
+ - **Scoped dynamic**: Phương pháp tốt nhất cho _code splitting_ và hiệu suất. Giảm thiểu bộ nhớ bằng cách chỉ tải những gì chế độ xem hiện tại và ngôn ngữ đang hoạt động cần.
115
+
116
+ ### Những gì tôi đã đo lường:
117
+
118
+ Tôi đã chạy cùng một ứng dụng đa ngôn ngữ trong một trình duyệt thực cho mọi stack, sau đó ghi lại những gì thực sự xuất hiện trên mạng và mất bao lâu. Kích thước được báo cáo **sau khi nén web thông thường**, vì điều đó gần với những gì mọi người thực sự tải xuống hơn là số lượng mã nguồn thô.
119
+
120
+ - **Kích thước thư viện quốc tế hóa**: Sau khi đóng gói, tree-shaking và thu gọn, kích thước của thư viện i18n là kích thước của mã provider + composable trong một component trống. Nó không bao gồm việc tải các file bản dịch. Nó trả lời cho câu hỏi thư viện "đắt" như thế nào trước khi nội dung của bạn xuất hiện.
121
+
122
+ - **JavaScript trên mỗi trang**: Đối với mỗi route benchmark, trình duyệt kéo bao nhiêu script cho lần truy cập đó, tính trung bình trên các trang trong bộ thử nghiệm (và trên các ngôn ngữ). Các trang nặng là các trang chậm.
123
+
124
+ - **Rò rỉ từ các ngôn ngữ khác (Leakage)**: Đó là nội dung của cùng một trang nhưng ở ngôn ngữ khác sẽ bị tải nhầm trong trang được kiểm tra. Nội dung này là không cần thiết và nên tránh (ví dụ: nội dung trang `/fr/about` trong bundle trang `/en/about`).
125
+
126
+ - **Rò rỉ từ các route khác**: Ý tưởng tương tự cho **các màn hình khác** trong ứng dụng: liệu văn bản của chúng có đi kèm khi bạn chỉ mở một trang hay không (ví dụ: nội dung trang `/en/about` trong bundle trang `/en/contact`). Điểm số cao gợi ý việc chia tách yếu hoặc các bundle quá rộng.
127
+
128
+ - **Kích thước bundle component trung bình**: Các phần UI phổ biến được đo **từng cái một** thay vì ẩn bên trong một con số ứng dụng khổng lồ. Nó cho thấy liệu quốc tế hóa có âm thầm làm phình to các component hàng ngày hay không. Ví dụ, nếu component của bạn render lại, nó sẽ tải tất cả dữ liệu đó từ bộ nhớ. Việc đính kèm một JSON khổng lồ vào bất kỳ component nào giống như kết nối một kho chứa lớn dữ liệu không sử dụng sẽ làm chậm hiệu suất component của bạn.
129
+
130
+ - **Tính phản ứng khi chuyển đổi ngôn ngữ**: Tôi lật ngôn ngữ bằng chính trình điều khiển của ứng dụng và tính thời gian cho đến khi trang đã chuyển đổi rõ ràng, những gì khách truy cập sẽ nhận thấy.
131
+
132
+ - **Công việc render sau khi thay đổi ngôn ngữ**: Một theo dõi hẹp hơn: giao diện đã tốn bao nhiêu nỗ lực để vẽ lại cho ngôn ngữ mới sau khi quá trình chuyển đổi bắt đầu. Hữu ích khi thời gian "cảm nhận" và chi phí framework khác nhau.
133
+
134
+ - **Thời gian tải trang ban đầu**: Từ khi điều hướng cho đến khi trình duyệt coi trang đã được tải đầy đủ cho các tình huống tôi đã thử nghiệm. Tốt để so sánh cold start.
135
+
136
+ - **Thời gian Hydration**: Thời gian client dành để biến server HTML thành giao diện tương tác. Dấu gạch ngang trong các bảng có nghĩa là triển khai đó không cung cấp con số hydration đáng tin cậy trong benchmark này.
137
+
138
+ ## Kết quả chi tiết
139
+
140
+ ### 1 — Các giải pháp cần tránh
141
+
142
+ > Không có giải pháp rõ ràng nào cần tránh trong hệ sinh thái Vue.
143
+
144
+ ### 2 — Các giải pháp chấp nhận được
145
+
146
+ **(vue-i18n)** (`vue-i18n@11.4.0`):
147
+
148
+ - **vue-i18n** chắc chắn là thư viện i18n được sử dụng nhiều nhất cho Vue, nó có rất nhiều tính năng và một hệ sinh thái khổng lồ. Nhưng thực tế giải pháp này khá nặng. Ngay cả khi vue-i18n tích hợp lazy loading cho các tin nhắn, nó vẫn thiếu tính năng scoping. Trong trường hợp ứng dụng Vue SPA cổ điển thì không có vấn đề gì, nhưng đối với ứng dụng Nuxt, sử dụng @nuxt/i18n, nó dẫn đến việc bao gồm tin nhắn từ tất cả các trang vào một trang duy nhất. Đối với một ứng dụng Nuxt lớn bao gồm hơn 10 trang, nó có thể trở nên thực sự rắc rối.
149
+
150
+ Package này rất nặng (~24.3kb, gấp khoảng 9 lần `vue-intlayer`).
151
+
152
+ **(fluent-vue)** (`fluent-vue@0.5.0`):
153
+
154
+ - **fluent-vue** đưa ra một nỗ lực đổi mới thông qua định dạng .ftl. Tổ chức tin nhắn tuyệt vời, dễ dàng bắt đầu hơn. Nhưng trong thực tế, việc thiếu an toàn kiểu làm tăng rủi ro lỗi và có thể nhanh chóng trở nên tốn thời gian để debug. Hơn nữa, giải pháp đó tải các tin nhắn bằng một plugin vite bắt buộc tải tất cả nội dung ở tất cả các ngôn ngữ vào mỗi trang. Ngoài ra, đây là một giải pháp cực kỳ nặng (~92.7kb, gấp khoảng 34 lần `vue-intlayer`).
155
+
156
+ ### 3 — Khuyến nghị
157
+
158
+ **(Intlayer)** (`vue-intlayer@8.7.12`):
159
+
160
+ Tôi sẽ không đích thân đánh giá `vue-intlayer` vì tính khách quan, vì đó là giải pháp của chính tôi.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  createdAt: 2024-08-13
3
- updatedAt: 2026-04-03
3
+ updatedAt: 2026-05-12
4
4
  title: Cấu hình (Configuration)
5
5
  description: Tìm hiểu cách cấu hình Intlayer cho ứng dụng của bạn. Hiểu các cài đặt và tùy chọn khác nhau có sẵn để tùy chỉnh Intlayer theo nhu cầu của bạn.
6
6
  keywords:
@@ -14,6 +14,9 @@ slugs:
14
14
  - concept
15
15
  - configuration
16
16
  history:
17
+ - version: 8.9.4
18
+ date: 2026-05-12
19
+ changes: "Thêm hỗ trợ cho nhà cung cấp LM Studio"
17
20
  - version: 8.7.0
18
21
  date: 2026-04-07
19
22
  changes: "Thêm tùy chọn `minify` và `prune` vào cấu hình build"
@@ -350,7 +353,7 @@ const config: IntlayerConfig = {
350
353
  ai: {
351
354
  /**
352
355
  * Nhà cung cấp AI được sử dụng.
353
- * Tùy chọn: 'openai', 'anthropic', 'mistral', 'deepseek', 'gemini', 'ollama', 'openrouter', 'alibaba', 'fireworks', 'groq', 'huggingface', 'bedrock', 'googlevertex', 'togetherai'
356
+ * Tùy chọn: 'openai', 'anthropic', 'mistral', 'deepseek', 'gemini', 'ollama', 'openrouter', 'alibaba', 'fireworks', 'groq', 'huggingface', 'bedrock', 'googlevertex', 'togetherai', 'lmstudio'
354
357
  * Mặc định: 'openai'
355
358
  */
356
359
  provider: "openai",
@@ -916,16 +919,17 @@ Intlayer hỗ trợ đa dạng các nhà cung cấp AI để mang lại sự lin
916
919
  - **Groq**
917
920
  - **Amazon Bedrock**
918
921
  - **Together.ai**
919
-
920
- | Trường | Mô tả | Kiểu dữ liệu | Mặc định | Ví dụ | Nhận xét |
921
- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
922
- | `provider` | Nhà cung cấp được sử dụng cho các tính năng AI của Intlayer. | `'openai'` &#124; <br/> `'anthropic'` &#124; <br/> `'mistral'` &#124; <br/> `'deepseek'` &#124; <br/> `'gemini'` &#124; <br/> `'ollama'` &#124; <br/> `'openrouter'` &#124; <br/> `'alibaba'` &#124; <br/> `'fireworks'` &#124; <br/> `'groq'` &#124; <br/> `'huggingface'` &#124; <br/> `'bedrock'` &#124; <br/> `'googleaistudio'` &#124; <br/> `'googlevertex'` &#124; <br/> `'togetherai'` | `undefined` | `'anthropic'` | Các nhà cung cấp khác nhau yêu cầu các khóa API khác nhau và có mức giá khác nhau. |
923
- | `model` | Model AI được sử dụng cho các tính năng AI. | `string` | Không | `'gpt-4o-2024-11-20'` | Các model cụ thể phụ thuộc vào nhà cung cấp. |
924
- | `temperature` | Điều khiển tính ngẫu nhiên của phản hồi AI. | `number` | Không có | `0.1` | Nhiệt độ cao hơn = sáng tạo hơn kém đáng tin cậy hơn. |
925
- | `apiKey` | Khóa API của bạn cho nhà cung cấp đã chọn. | `string` | Không có | `process.env.OPENAI_API_KEY` | Phải được giữ mật; sử dụng biến môi trường. |
926
- | `applicationContext` | Ngữ cảnh bổ sung về ứng dụng của bạn để giúp AI tạo ra các bản dịch chính xác hơn (lĩnh vực, đối tượng mục tiêu, tông điệu, thuật ngữ). | `string` | Không có | `'ngữ cảnh ứng dụng tùy chỉnh của tôi'` | thể được sử dụng để thêm các quy tắc (ví dụ: `"Bạn không nên dịch các URL của bạn"` ). |
927
- | `baseURL` | URL sở cho AI API. | `string` | Không có | `'https://api.openai.com/v1'` <br/> `'http://localhost:5000'` | Có thể trỏ tới các endpoint AI API cục bộ hoặc tùy chỉnh. |
928
- | `dataSerialization` | Định dạng tuần tự hóa dữ liệu cho các tính năng AI. | `'json'` &#124; <br/> `'toon'` | `undefined` | `'toon'` | `'json'`: mặc định, đáng tin cậy; sử dụng nhiều token hơn.<br/>• `'toon'`: ít token hơn, kém ổn định hơn.<br/>• Chuyển ngữ cảnh cho model dưới dạng một tham số phụ (reasoning effort, v.v.). |
922
+ - **LM Studio**
923
+
924
+ | Trường | tả | Kiểu dữ liệu | Mặc định | dụ | Nhận xét |
925
+ | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------- | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
926
+ | `provider` | Nhà cung cấp được sử dụng cho các tính năng AI của Intlayer. | `'openai'` &#124; <br/> `'anthropic'` &#124; <br/> `'mistral'` &#124; <br/> `'deepseek'` &#124; <br/> `'gemini'` &#124; <br/> `'ollama'` &#124; <br/> `'openrouter'` &#124; <br/> `'alibaba'` &#124; <br/> `'fireworks'` &#124; <br/> `'groq'` &#124; <br/> `'huggingface'` &#124; <br/> `'bedrock'` &#124; <br/> `'googleaistudio'` &#124; <br/> `'googlevertex'` &#124; <br/> `'togetherai'` &#124; <br/> `'lmstudio'` | `undefined` | `'anthropic'` | Các nhà cung cấp khác nhau yêu cầu các khóa API khác nhau và có mức giá khác nhau. |
927
+ | `model` | Model AI được sử dụng cho các tính năng AI. | `string` | Không có | `'gpt-4o-2024-11-20'` | Các model cụ thể phụ thuộc vào nhà cung cấp. |
928
+ | `temperature` | Điều khiển tính ngẫu nhiên của phản hồi AI. | `number` | Không có | `0.1` | Nhiệt độ cao hơn = sáng tạo hơn kém đáng tin cậy hơn. |
929
+ | `apiKey` | Khóa API của bạn cho nhà cung cấp đã chọn. | `string` | Không có | `process.env.OPENAI_API_KEY` | Phải được giữ mật; sử dụng biến môi trường. |
930
+ | `applicationContext` | Ngữ cảnh bổ sung về ứng dụng của bạn để giúp AI tạo ra các bản dịch chính xác hơn (lĩnh vực, đối tượng mục tiêu, tông điệu, thuật ngữ). | `string` | Không có | `'ngữ cảnh ứng dụng tùy chỉnh của tôi'` | Có thể được sử dụng để thêm các quy tắc (ví dụ: `"Bạn không nên dịch các URL của bạn"` ). |
931
+ | `baseURL` | URL sở cho AI API. | `string` | Không | `'https://api.openai.com/v1'` <br/> `'http://localhost:5000'` | thể trỏ tới các endpoint AI API cục bộ hoặc tùy chỉnh. |
932
+ | `dataSerialization` | Định dạng tuần tự hóa dữ liệu cho các tính năng AI. | `'json'` &#124; <br/> `'toon'` | `undefined` | `'toon'` | • `'json'`: mặc định, đáng tin cậy; sử dụng nhiều token hơn.<br/>• `'toon'`: ít token hơn, kém ổn định hơn.<br/>• Chuyển ngữ cảnh cho model dưới dạng một tham số phụ (reasoning effort, v.v.). |
929
933
 
930
934
  ---
931
935
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  createdAt: 2025-02-07
3
- updatedAt: 2026-01-28
3
+ updatedAt: 2026-05-12
4
4
  title: Tệp Nội Dung
5
5
  description: Tìm hiểu cách tùy chỉnh các phần mở rộng cho các tệp khai báo nội dung của bạn. Theo dõi tài liệu này để triển khai các điều kiện một cách hiệu quả trong dự án của bạn.
6
6
  keywords:
@@ -12,6 +12,9 @@ slugs:
12
12
  - concept
13
13
  - content
14
14
  history:
15
+ - version: 8.9.0
16
+ date: 2026-05-12
17
+ changes: "Thêm loại nút nội dung `plural`"
15
18
  - version: 8.0.0
16
19
  date: 2026-01-28
17
20
  changes: "Thêm kiểu nút nội dung `html`"
@@ -69,6 +72,7 @@ import { type ReactNode } from "react";
69
72
  import {
70
73
  t,
71
74
  enu,
75
+ plural,
72
76
  cond,
73
77
  nest,
74
78
  md,
@@ -88,6 +92,7 @@ interface Content {
88
92
  };
89
93
  multilingualContent: string;
90
94
  quantityContent: string;
95
+ pluralContent: string;
91
96
  conditionalContent: string;
92
97
  markdownContent: never;
93
98
  htmlContent: never;
@@ -123,6 +128,10 @@ export default {
123
128
  ">5": "Một vài chiếc xe",
124
129
  ">19": "Nhiều chiếc xe",
125
130
  }),
131
+ pluralContent: plural({
132
+ one: "One car",
133
+ other: "{{count}} cars",
134
+ }),
126
135
  conditionalContent: cond({
127
136
  true: "Xác thực được bật",
128
137
  false: "Xác thực bị tắt",
@@ -177,6 +186,13 @@ export default {
177
186
  ">5": "Một vài chiếc xe",
178
187
  ">19": "Nhiều chiếc xe",
179
188
  },
189
+ "pluralContent": {
190
+ "nodeType": "plural",
191
+ "plural": {
192
+ "one": "One car",
193
+ "other": "{{count}} cars",
194
+ },
195
+ },
180
196
  },
181
197
  "conditionalContent": {
182
198
  "nodeType": "condition",
@@ -224,6 +240,7 @@ Các nút nội dung là các khối xây dựng của nội dung từ điển.
224
240
  - **Giá trị nguyên thủy**: chuỗi, số, boolean, null, undefined
225
241
  - **Node kiểu**: Các loại nội dung đặc biệt như bản dịch, điều kiện, markdown, v.v.
226
242
  - **Hàm**: Nội dung động có thể được đánh giá tại thời gian chạy [xem Function Fetching](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dictionary/function_fetching.md)
243
+ - **Nội dung số nhiều**: Xem Nội dung số nhiều [Xem Nội dung số nhiều](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dictionary/plural.md)
227
244
  - **Nội dung lồng nhau**: Tham chiếu đến các từ điển khác
228
245
 
229
246
  #### Các loại nội dung
@@ -554,6 +571,8 @@ multilingualContent: t({
554
571
  });
555
572
  ```
556
573
 
574
+ > Xem [Nội dung dịch (`t`) Tài liệu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dictionary/translation.md) để biết thêm thông tin.
575
+
557
576
  ### Nội dung điều kiện (`cond`)
558
577
 
559
578
  Nội dung thay đổi dựa trên các điều kiện boolean:
@@ -567,6 +586,8 @@ conditionalContent: cond({
567
586
  });
568
587
  ```
569
588
 
589
+ > Xem [Nội dung điều kiện (`cond`) Tài liệu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dictionary/condition.md) để biết thêm thông tin.
590
+
570
591
  ### Nội dung liệt kê (`enu`)
571
592
 
572
593
  Nội dung thay đổi dựa trên các giá trị liệt kê:
@@ -581,6 +602,23 @@ statusContent: enu({
581
602
  });
582
603
  ```
583
604
 
605
+ > Xem [Nội dung liệt kê (`enu`) Tài liệu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dictionary/enumeration.md) để biết thêm thông tin.
606
+
607
+ ### Nội dung số nhiều (`plural`)
608
+
609
+ Nội dung thay đổi dựa trên các quy tắc số nhiều:
610
+
611
+ ```typescript
612
+ import { plural } from "intlayer";
613
+
614
+ pluralContent: plural({
615
+ one: "One car",
616
+ other: "{{count}} cars",
617
+ });
618
+ ```
619
+
620
+ > Xem [Nội dung số nhiều Tài liệu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dictionary/plural.md) để biết thêm thông tin.
621
+
584
622
  ### Nội dung chèn (`insert`)
585
623
 
586
624
  Nội dung có thể được chèn vào các nội dung khác:
@@ -591,6 +629,8 @@ import { insert } from "intlayer";
591
629
  insertionContent: insert("Đoạn văn bản này có thể được chèn vào bất cứ đâu");
592
630
  ```
593
631
 
632
+ > Xem [Nội dung chèn (`insert`) Tài liệu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dictionary/insertion.md) để biết thêm thông tin.
633
+
594
634
  ### Nội dung lồng nhau (`nest`)
595
635
 
596
636
  Tham chiếu đến các từ điển khác:
@@ -601,6 +641,8 @@ import { nest } from "intlayer";
601
641
  nestedContent: nest("about-page");
602
642
  ```
603
643
 
644
+ > Xem [Nội dung lồng nhau (`nest`) Tài liệu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dictionary/nesting.md) để biết thêm thông tin.
645
+
604
646
  ### Nội dung Markdown (`md`)
605
647
 
606
648
  Nội dung văn bản phong phú ở định dạng Markdown:
@@ -613,6 +655,8 @@ markdownContent: md(
613
655
  );
614
656
  ```
615
657
 
658
+ > Xem [Nội dung Markdown (`md`) Tài liệu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dictionary/markdown.md) để biết thêm thông tin.
659
+
616
660
  ### Nội dung HTML (`html`)
617
661
 
618
662
  Nội dung HTML phong phú có thể sử dụng thẻ chuẩn hoặc component tùy chỉnh:
@@ -630,6 +674,8 @@ localizedHtmlContent: t({
630
674
  });
631
675
  ```
632
676
 
677
+ > Xem [Nội dung HTML (`html`) Tài liệu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dictionary/html.md) để biết thêm thông tin.
678
+
633
679
  ### Nội dung theo giới tính (`gender`)
634
680
 
635
681
  Nội dung thay đổi dựa trên giới tính:
@@ -644,6 +690,8 @@ genderContent: gender({
644
690
  });
645
691
  ```
646
692
 
693
+ > Xem [Nội dung theo giới tính (`gender`) Tài liệu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dictionary/gender.md) để biết thêm thông tin.
694
+
647
695
  ### Nội dung tệp tin (`file`)
648
696
 
649
697
  Tham chiếu đến các tệp tin bên ngoài:
@@ -654,6 +702,8 @@ import { file } from "intlayer";
654
702
  fileContent: file("./path/to/content.txt");
655
703
  ```
656
704
 
705
+ > Xem [Nội dung tệp tin (`file`) Tài liệu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dictionary/file.md) để biết thêm thông tin.
706
+
657
707
  ## Tạo các tệp nội dung
658
708
 
659
709
  ### Cấu trúc cơ bản của tệp nội dung
@@ -234,35 +234,22 @@ export default withIntlayer(nextConfig);
234
234
  >
235
235
  > export default nextConfigWithOtherPlugins;
236
236
  > ```
237
- >
238
- > ### Bước 4: Định nghĩa các tuyến đường Locale động
239
- >
240
- > Xóa tất cả mọi thứ trong `RootLayout` và thay thế bằng đoạn mã sau:
241
- >
242
- > ```tsx {3} fileName="src/app/layout.tsx" codeFormat="typescript"
243
- > import type { PropsWithChildren, FC } from "react";
244
- > import "./globals.css";
245
- >
246
- > const RootLayout: FC<PropsWithChildren> = ({ children }) => (
247
- > // Bạn vẫn có thể bao bọc các children với các provider khác, như `next-themes`, `react-query`, `framer-motion`, v.v.
248
- > <>{children}</>
249
- > );
250
- > ```
251
237
 
252
- export default RootLayout;
238
+ ### Bước 4: Định nghĩa các tuyến đường Locale động
253
239
 
254
- ````
240
+ Xóa tất cả mọi thứ trong `RootLayout` và thay thế bằng đoạn mã sau:
255
241
 
256
- ```jsx {3} fileName="src/app/layout.mjx" codeFormat="esm"
242
+ ```tsx {3} fileName="src/app/layout.tsx" codeFormat={["typescript", "esm"]}
243
+ import type { PropsWithChildren, FC } from "react";
257
244
  import "./globals.css";
258
245
 
259
- const RootLayout = ({ children }) => (
260
- // Bạn vẫn có thể bao bọc children với các provider khác, như `next-themes`, `react-query`, `framer-motion`, v.v.
246
+ const RootLayout: FC<PropsWithChildren> = ({ children }) => (
247
+ // Bạn vẫn có thể bao bọc các children với các provider khác, như `next-themes`, `react-query`, `framer-motion`, v.v.
261
248
  <>{children}</>
262
249
  );
263
250
 
264
251
  export default RootLayout;
265
- ````
252
+ ```
266
253
 
267
254
  ```jsx {1,8} fileName="src/app/layout.csx" codeFormat="commonjs"
268
255
  require("./globals.css");
@@ -282,21 +269,7 @@ module.exports = {
282
269
 
283
270
  Để triển khai dynamic routing, cung cấp đường dẫn cho locale bằng cách thêm một layout mới trong thư mục `[locale]` của bạn:
284
271
 
285
- ````tsx fileName="src/app/[locale]/layout.tsx" codeFormat={["typescript", "esm"]}
286
- import type { NextLayoutIntlayer } from "next-intlayer";
287
- import { Inter } from "next/font/google";
288
- import { getHTMLTextDir } from "intlayer";
289
-
290
- const inter = Inter({ subsets: ["latin"] });
291
-
292
- const LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => {
293
- const { locale } = await params;
294
- return (
295
- > Việc giữ cho component `RootLayout` trống cho phép thiết lập các thuộc tính [`lang`](https://developer.mozilla.org/fr/docs/Web/HTML/Global_attributes/lang) và [`dir`](https://developer.mozilla.org/fr/docs/Web/HTML/Global_attributes/dir) cho thẻ `<html>`.
296
-
297
- Để triển khai routing động, cung cấp đường dẫn cho locale bằng cách thêm một layout mới trong thư mục `[locale]` của bạn:
298
-
299
- ```tsx fileName="src/app/[locale]/layout.tsx" codeFormat="typescript"
272
+ ```tsx fileName="src/app/[locale]/layout.tsx" codeFormat={["typescript", "esm"]}
300
273
  import { type NextLayoutIntlayer, IntlayerClientProvider } from "next-intlayer";
301
274
  import { Inter } from "next/font/google";
302
275
  import { getHTMLTextDir } from "intlayer";
@@ -317,27 +290,7 @@ const LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => {
317
290
  };
318
291
 
319
292
  export default LocaleLayout;
320
- ````
321
-
322
- > Đoạn đường dẫn `[locale]` được sử dụng để định nghĩa locale. Ví dụ: `/en-US/about` sẽ tương ứng với `en-US` và `/fr/about` sẽ tương ứng với `fr`.
323
-
324
- const inter = Inter({ subsets: ["latin"] });
325
-
326
- const LocaleLayout = async ({ children, params: { locale } }) => {
327
- const { locale } = await params;
328
- return (
329
-
330
- <html lang={locale} dir={getHTMLTextDir(locale)}>
331
- <body className={inter.className}>
332
- {children}
333
- </body>
334
- </html>
335
- );
336
- };
337
-
338
- module.exports = LocaleLayout;
339
-
340
- ````
293
+ ```
341
294
 
342
295
  > Đoạn đường dẫn `[locale]` được sử dụng để xác định locale. Ví dụ: `/en-US/about` sẽ tham chiếu đến `en-US` và `/fr/about` sẽ tham chiếu đến `fr`.
343
296
 
@@ -353,7 +306,7 @@ const LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => {
353
306
  };
354
307
 
355
308
  export default LocaleLayout;
356
- ````
309
+ ```
357
310
 
358
311
  ```jsx {1} fileName="src/app/[locale]/layout.mjx" codeFormat="esm"
359
312
  export { generateStaticParams } from "next-intlayer"; // Dòng cần chèn
@@ -160,30 +160,9 @@ syncPO({
160
160
  source: ({ key, locale }) => string, // bắt buộc
161
161
  location?: string, // nhãn tùy chọn, mặc định: "sync-po::path/to/source"
162
162
  priority?: number, // ưu tiên tùy chọn để giải quyết xung đột, mặc định: 0
163
- format?: 'icu' | 'i18next' | 'vue-i18n', // tùy chọn, chỉ cần thiết khi giá trị msgstr của bạn sử dụng cú pháp nội suy cụ thể
164
163
  });
165
164
  ```
166
165
 
167
- #### `format` ('icu' | 'i18next' | 'vue-i18n')
168
-
169
- Các tệp PO luôn là các tệp Gettext Portable Object — điều đó là cố định. Tùy chọn này chỉ mô tả **cú pháp nội suy** được sử dụng bên trong các giá trị `msgstr`, để Intlayer có thể chuyển đổi chúng sang định dạng của riêng nó tại thời điểm phân tích cú pháp (thông qua `formatDictionary`) và ngược lại khi ghi đầu ra.
170
-
171
- - `undefined` _(mặc định)_: các giá trị `msgstr` được coi là các chuỗi văn bản thuần túy — không có chuyển đổi. Sử dụng tùy chọn này cho hầu hết các tệp PO.
172
- - `'icu'`: các giá trị `msgstr` sử dụng cú pháp tin nhắn ICU (ví dụ: `{count, plural, one {# item} other {# items}}`).
173
- - `'i18next'`: các giá trị `msgstr` sử dụng cú pháp nội suy i18next (ví dụ: `{{variable}}`).
174
- - `'vue-i18n'`: các giá trị `msgstr` sử dụng cú pháp Vue I18n.
175
-
176
- > Chuyển đổi được áp dụng bởi `formatDictionary` của `@intlayer/chokidar` khi tải và đảo ngược với `formatDictionaryOutput` khi ghi. Đối với các quy tắc phức tạp như số nhiều ICU, độ trung thực của quy trình chuyển đổi qua lại không được đảm bảo.
177
-
178
- **Ví dụ — Các tệp PO chứa nội suy kiểu i18next:**
179
-
180
- ```ts
181
- syncPO({
182
- source: ({ key, locale }) => `./locales/${locale}/${key}.po`,
183
- format: "i18next",
184
- }),
185
- ```
186
-
187
166
  ### Nhiều nguồn PO và mức độ ưu tiên
188
167
 
189
168
  Bạn có thể thêm nhiều plugin `syncPO` để đồng bộ hóa các nguồn PO khác nhau. Điều này hữu ích khi bạn có nhiều nguồn dịch hoặc cấu trúc PO khác nhau trong dự án của mình.
@@ -61,6 +61,13 @@ i18n 库的另一个影响是开发速度变慢。将组件转换为支持多语
61
61
 
62
62
  Intlayer 尝试在这些维度上进行优化。
63
63
 
64
+ ## TL;DR
65
+
66
+ - **Intlayer** & **next-translate**: Next.js 性能的最佳选择,提供最小的体积和最佳的静态渲染支持。
67
+ - **next-intl**: 最热门的选择,但体积庞大且对于大型应用优化复杂。
68
+ - **next-i18next**: 流行且插件丰富,但打包体积显著(约为 Intlayer 的 3 倍)。
69
+ - **应避免**: **gt-next** 和 **lingo.dev**,因为存在严重的性能问题、供应商锁定以及导致构建失败的 Bug。
70
+
64
71
  ## 测试你的应用
65
72
 
66
73
  为了发现这些问题,我构建了一个免费扫描器,你可以在[这里](https://intlayer.org/i18n-seo-scanner)试用。
@@ -99,14 +106,14 @@ Intlayer 尝试在这些维度上进行优化。
99
106
  在此基准测试中,我们对比了以下库:
100
107
 
101
108
  - `Base App`(无 i18n 库)
102
- - `next-intlayer` (v8.7.5)
109
+ - `next-intlayer` (v8.7.12)
103
110
  - `next-i18next` (v16.0.5)
104
111
  - `next-intl` (v4.9.1)
105
112
  - `@lingui/core` (v5.3.0)
106
113
  - `next-translate` (v3.1.2)
107
114
  - `next-international` (v1.3.1)
108
115
  - `@inlang/paraglide-js` (v2.15.1)
109
- - `tolgee` (v7.0.0)
116
+ - `@tolgee/react` (v7.0.0)
110
117
  - `@lingo.dev/compiler` (v0.4.0)
111
118
  - `wuchale` (v0.22.11)
112
119
  - `gt-next` (v6.16.5)
@@ -161,10 +168,10 @@ Intlayer 尝试在这些维度上进行优化。
161
168
 
162
169
  **(General Translation)** (`gt-next@6.16.5`):
163
170
 
164
- - 对于一个 110kb 的应用,`gt-react` 额外增加了超过 440kb。
171
+ - 对于一个 110kb 的应用,`gt-next` 额外增加了超过 440kb。
165
172
  - 第一次使用 General Translation 构建就提示 `Quota Exceeded, please upgrade your plan`(配额超出,请升级计划)。
166
173
  - 翻译未渲染;我收到了错误 `Error: <T> used on the client-side outside of <GTProvider>`,这似乎是库的一个 Bug。
167
- - 在实施 **gt-tanstack-start-react** 时,我还遇到了该库的一个[问题](https://github.com/generaltranslation/gt/issues/1210#event-24510646961):`does not provide an export named 'printAST' - @formatjs/icu-messageformat-parser`,这导致应用崩溃。在报告此问题后,维护者在 24 小时内修复了它。
174
+ - 在实施 **gt-next** 时,我还遇到了该库的一个[问题](https://github.com/generaltranslation/gt/issues/1210#event-24510646961):`does not provide an export named 'printAST' - @formatjs/icu-messageformat-parser`,这导致应用崩溃。在报告此问题后,维护者在 24 小时内修复了它。
168
175
  - 该库阻塞了 Next.js 页面的静态渲染。
169
176
 
170
177
  **(Lingo.dev)** (`@lingo.dev/compiler@0.4.0`):
@@ -186,9 +193,11 @@ Intlayer 尝试在这些维度上进行优化。
186
193
  就个人而言,我不喜欢每次推送到代码库前都要重新生成 JS 文件,这通过 PR 产生了持续的合并冲突风险。该工具似乎也更关注 Vite 而非 Next.js。
187
194
  最后,与其他解决方案相比,Paraglide 不使用存储(如 React Context)来检索当前语言环境以渲染内容。对于解析的每个节点,它都会从 localStorage / Cookie 等请求语言环境。这导致了影响组件响应性的不必要逻辑执行。
188
195
 
196
+ > 关于 Paraglide 的说明:该解决方案通过将代码注入到你的代码库中进行导入,因此在基准测试报告中,“库体积”指标几乎为 0。代码生成是一件好事,因为所使用的函数将仅包含必要的逻辑(全前缀 vs 无前缀、Cookie vs 存储等)。相比之下,Intlayer 通过在构建中注入环境变量来强制打包工具根据逻辑对内容进行 Tree-shaking。得益于此,Paraglide 和 Intlayer 最终成为比 i18next 或 next-intl 轻 6 到 10 倍的解决方案。
197
+
189
198
  ### 3 — 可接受的解决方案
190
199
 
191
- **(Tolgee)** (`tolgee@7.0.0`):
200
+ **(Tolgee)** (`@tolgee/react@7.0.0`):
192
201
 
193
202
  `Tolgee` 解决了前面提到的许多问题。我发现它比类似的工具更难采用。它不提供类型安全,这增加了在编译时捕捉缺失键的难度。我不得不使用自己的函数封装 Tolgee 的函数,以添加缺失键检测。
194
203
 
@@ -216,7 +225,7 @@ Intlayer 尝试在这些维度上进行优化。
216
225
 
217
226
  如果你喜欢 `t()` 风格的 API,`next-translate` 是我的主要推荐方案。它通过 `next-translate-plugin` 优雅运作,利用 Webpack / Turbopack loader 通过 `getStaticProps` 加载命名空间。它也是这些方案中最轻量的(约 2.5kb)。对于命名空间拆分,在配置中为每个页面或路由定义命名空间的设计非常周到,比 **next-intl** 或 **next-i18next** 等主要替代方案更易于维护。在版本 `3.1.2` 中,我注意到静态渲染无法工作,Next.js 会回退到动态渲染。
218
227
 
219
- **(Intlayer)** (`next-intlayer@8.7.5`):
228
+ **(Intlayer)** (`next-intlayer@8.7.12`):
220
229
 
221
230
  出于客观性考量,我不会亲自评价 `next-intlayer`,因为这是我自己的解决方案。
222
231