@intlayer/docs 8.9.4-canary.0 → 8.9.5
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.
- package/dist/cjs/generated/docs.entry.cjs +20 -0
- package/dist/cjs/generated/docs.entry.cjs.map +1 -1
- package/dist/esm/generated/docs.entry.mjs +20 -0
- package/dist/esm/generated/docs.entry.mjs.map +1 -1
- package/dist/types/generated/docs.entry.d.ts +1 -0
- package/dist/types/generated/docs.entry.d.ts.map +1 -1
- package/docs/ar/benchmark/index.md +0 -3
- package/docs/ar/benchmark/nextjs.md +15 -6
- package/docs/ar/benchmark/solid.md +155 -0
- package/docs/ar/benchmark/svelte.md +148 -0
- package/docs/ar/benchmark/tanstack.md +12 -3
- package/docs/ar/benchmark/vue.md +160 -0
- package/docs/ar/configuration.md +16 -12
- package/docs/ar/dictionary/content_file.md +51 -1
- package/docs/ar/mcp_server.md +30 -17
- package/docs/ar/plugins/sync-po.md +333 -0
- package/docs/bn/configuration.md +16 -12
- package/docs/cs/configuration.md +16 -12
- package/docs/de/benchmark/index.md +0 -3
- package/docs/de/benchmark/nextjs.md +15 -6
- package/docs/de/benchmark/solid.md +155 -0
- package/docs/de/benchmark/svelte.md +148 -0
- package/docs/de/benchmark/tanstack.md +12 -3
- package/docs/de/benchmark/vue.md +160 -0
- package/docs/de/configuration.md +16 -12
- package/docs/de/dictionary/content_file.md +52 -2
- package/docs/de/mcp_server.md +29 -16
- package/docs/de/plugins/sync-po.md +332 -0
- package/docs/en/benchmark/nextjs.md +11 -2
- package/docs/en/benchmark/solid.md +22 -4
- package/docs/en/benchmark/svelte.md +17 -5
- package/docs/en/benchmark/tanstack.md +18 -3
- package/docs/en/benchmark/vue.md +17 -11
- package/docs/en/configuration.md +16 -13
- package/docs/en/dictionary/content_file.md +51 -1
- package/docs/en/mcp_server.md +31 -18
- package/docs/en/plugins/sync-po.md +333 -0
- package/docs/en-GB/benchmark/index.md +0 -3
- package/docs/en-GB/benchmark/nextjs.md +15 -6
- package/docs/en-GB/benchmark/solid.md +155 -0
- package/docs/en-GB/benchmark/svelte.md +148 -0
- package/docs/en-GB/benchmark/tanstack.md +12 -3
- package/docs/en-GB/benchmark/vue.md +160 -0
- package/docs/en-GB/configuration.md +15 -11
- package/docs/en-GB/dictionary/content_file.md +51 -1
- package/docs/en-GB/mcp_server.md +31 -18
- package/docs/en-GB/plugins/sync-po.md +333 -0
- package/docs/es/benchmark/index.md +0 -3
- package/docs/es/benchmark/nextjs.md +15 -6
- package/docs/es/benchmark/solid.md +155 -0
- package/docs/es/benchmark/svelte.md +148 -0
- package/docs/es/benchmark/tanstack.md +12 -3
- package/docs/es/benchmark/vue.md +160 -0
- package/docs/es/configuration.md +16 -12
- package/docs/es/dictionary/content_file.md +51 -1
- package/docs/es/mcp_server.md +30 -17
- package/docs/es/plugins/sync-po.md +333 -0
- package/docs/fr/benchmark/index.md +0 -3
- package/docs/fr/benchmark/nextjs.md +15 -6
- package/docs/fr/benchmark/solid.md +155 -0
- package/docs/fr/benchmark/svelte.md +148 -0
- package/docs/fr/benchmark/tanstack.md +12 -3
- package/docs/fr/benchmark/vue.md +160 -0
- package/docs/fr/configuration.md +16 -12
- package/docs/fr/dictionary/content_file.md +51 -1
- package/docs/fr/mcp_server.md +30 -17
- package/docs/fr/plugins/sync-po.md +333 -0
- package/docs/hi/benchmark/nextjs.md +15 -6
- package/docs/hi/benchmark/solid.md +155 -0
- package/docs/hi/benchmark/svelte.md +148 -0
- package/docs/hi/benchmark/tanstack.md +12 -3
- package/docs/hi/benchmark/vue.md +160 -0
- package/docs/hi/configuration.md +16 -12
- package/docs/hi/dictionary/content_file.md +51 -1
- package/docs/hi/mcp_server.md +31 -18
- package/docs/hi/plugins/sync-po.md +333 -0
- package/docs/id/benchmark/index.md +0 -3
- package/docs/id/benchmark/nextjs.md +15 -6
- package/docs/id/benchmark/solid.md +155 -0
- package/docs/id/benchmark/svelte.md +148 -0
- package/docs/id/benchmark/tanstack.md +12 -3
- package/docs/id/benchmark/vue.md +160 -0
- package/docs/id/configuration.md +16 -12
- package/docs/id/dictionary/content_file.md +51 -1
- package/docs/id/mcp_server.md +30 -17
- package/docs/id/plugins/sync-po.md +333 -0
- package/docs/it/benchmark/index.md +1 -4
- package/docs/it/benchmark/nextjs.md +15 -6
- package/docs/it/benchmark/solid.md +155 -0
- package/docs/it/benchmark/svelte.md +148 -0
- package/docs/it/benchmark/tanstack.md +12 -3
- package/docs/it/benchmark/vue.md +160 -0
- package/docs/it/configuration.md +16 -12
- package/docs/it/dictionary/content_file.md +51 -1
- package/docs/it/mcp_server.md +30 -17
- package/docs/it/plugins/sync-po.md +333 -0
- package/docs/ja/benchmark/index.md +5 -5
- package/docs/ja/benchmark/nextjs.md +15 -6
- package/docs/ja/benchmark/solid.md +155 -0
- package/docs/ja/benchmark/svelte.md +148 -0
- package/docs/ja/benchmark/tanstack.md +12 -3
- package/docs/ja/benchmark/vue.md +160 -0
- package/docs/ja/configuration.md +16 -12
- package/docs/ja/dictionary/content_file.md +50 -2
- package/docs/ja/intlayer_with_nextjs_no_locale_path.md +4 -3
- package/docs/ja/mcp_server.md +29 -16
- package/docs/ja/plugins/sync-po.md +333 -0
- package/docs/ko/benchmark/nextjs.md +15 -6
- package/docs/ko/benchmark/solid.md +155 -0
- package/docs/ko/benchmark/svelte.md +148 -0
- package/docs/ko/benchmark/tanstack.md +12 -3
- package/docs/ko/benchmark/vue.md +160 -0
- package/docs/ko/configuration.md +16 -12
- package/docs/ko/dictionary/content_file.md +51 -1
- package/docs/ko/intlayer_with_nextjs_no_locale_path.md +3 -2
- package/docs/ko/mcp_server.md +31 -18
- package/docs/ko/plugins/sync-po.md +333 -0
- package/docs/nl/configuration.md +16 -12
- package/docs/pl/benchmark/index.md +0 -3
- package/docs/pl/benchmark/nextjs.md +15 -6
- package/docs/pl/benchmark/solid.md +155 -0
- package/docs/pl/benchmark/svelte.md +148 -0
- package/docs/pl/benchmark/tanstack.md +12 -3
- package/docs/pl/benchmark/vue.md +160 -0
- package/docs/pl/configuration.md +16 -12
- package/docs/pl/dictionary/content_file.md +51 -1
- package/docs/pl/mcp_server.md +30 -17
- package/docs/pl/plugins/sync-po.md +333 -0
- package/docs/pt/benchmark/index.md +0 -3
- package/docs/pt/benchmark/nextjs.md +16 -7
- package/docs/pt/benchmark/solid.md +155 -0
- package/docs/pt/benchmark/svelte.md +148 -0
- package/docs/pt/benchmark/tanstack.md +13 -4
- package/docs/pt/benchmark/vue.md +160 -0
- package/docs/pt/configuration.md +16 -12
- package/docs/pt/dictionary/content_file.md +51 -1
- package/docs/pt/mcp_server.md +30 -17
- package/docs/pt/plugins/sync-po.md +333 -0
- package/docs/ru/benchmark/nextjs.md +15 -6
- package/docs/ru/benchmark/solid.md +155 -0
- package/docs/ru/benchmark/svelte.md +148 -0
- package/docs/ru/benchmark/tanstack.md +12 -3
- package/docs/ru/benchmark/vue.md +160 -0
- package/docs/ru/configuration.md +16 -12
- package/docs/ru/dictionary/content_file.md +52 -2
- package/docs/ru/mcp_server.md +30 -17
- package/docs/ru/plugins/sync-po.md +333 -0
- package/docs/tr/benchmark/index.md +0 -3
- package/docs/tr/benchmark/nextjs.md +15 -6
- package/docs/tr/benchmark/solid.md +155 -0
- package/docs/tr/benchmark/svelte.md +148 -0
- package/docs/tr/benchmark/tanstack.md +12 -3
- package/docs/tr/benchmark/vue.md +160 -0
- package/docs/tr/configuration.md +16 -12
- package/docs/tr/dictionary/content_file.md +51 -1
- package/docs/tr/mcp_server.md +31 -18
- package/docs/tr/plugins/sync-po.md +333 -0
- package/docs/uk/benchmark/nextjs.md +15 -6
- package/docs/uk/benchmark/solid.md +155 -0
- package/docs/uk/benchmark/svelte.md +148 -0
- package/docs/uk/benchmark/tanstack.md +12 -3
- package/docs/uk/benchmark/vue.md +160 -0
- package/docs/uk/configuration.md +16 -12
- package/docs/uk/dictionary/content_file.md +51 -1
- package/docs/uk/mcp_server.md +29 -16
- package/docs/uk/plugins/sync-po.md +333 -0
- package/docs/ur/configuration.md +16 -12
- package/docs/vi/benchmark/index.md +0 -3
- package/docs/vi/benchmark/nextjs.md +15 -6
- package/docs/vi/benchmark/solid.md +155 -0
- package/docs/vi/benchmark/svelte.md +148 -0
- package/docs/vi/benchmark/tanstack.md +12 -3
- package/docs/vi/benchmark/vue.md +160 -0
- package/docs/vi/configuration.md +16 -12
- package/docs/vi/dictionary/content_file.md +51 -1
- package/docs/vi/intlayer_with_nextjs_15.md +10 -57
- package/docs/vi/mcp_server.md +30 -17
- package/docs/vi/plugins/sync-po.md +333 -0
- package/docs/zh/benchmark/nextjs.md +15 -6
- package/docs/zh/benchmark/solid.md +155 -0
- package/docs/zh/benchmark/svelte.md +148 -0
- package/docs/zh/benchmark/tanstack.md +12 -3
- package/docs/zh/benchmark/vue.md +160 -0
- package/docs/zh/configuration.md +16 -12
- package/docs/zh/dictionary/content_file.md +51 -3
- package/docs/zh/mcp_server.md +31 -18
- package/docs/zh/plugins/sync-po.md +333 -0
- package/frequent_questions/ar/intlayerNode.md +3 -3
- package/frequent_questions/de/intlayerNode.md +3 -3
- package/frequent_questions/en/intlayerNode.md +3 -3
- package/frequent_questions/en-GB/intlayerNode.md +3 -3
- package/frequent_questions/es/intlayerNode.md +3 -3
- package/frequent_questions/fr/intlayerNode.md +3 -3
- package/frequent_questions/hi/intlayerNode.md +3 -3
- package/frequent_questions/id/intlayerNode.md +3 -3
- package/frequent_questions/it/intlayerNode.md +3 -3
- package/frequent_questions/ja/intlayerNode.md +3 -3
- package/frequent_questions/ko/intlayerNode.md +3 -3
- package/frequent_questions/pl/intlayerNode.md +3 -3
- package/frequent_questions/pt/intlayerNode.md +3 -3
- package/frequent_questions/ru/intlayerNode.md +3 -3
- package/frequent_questions/tr/intlayerNode.md +3 -3
- package/frequent_questions/uk/intlayerNode.md +3 -3
- package/frequent_questions/vi/intlayerNode.md +3 -3
- package/frequent_questions/zh/intlayerNode.md +3 -3
- package/package.json +8 -8
- package/src/generated/docs.entry.ts +20 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-05-10
|
|
3
|
+
updatedAt: 2026-05-10
|
|
4
|
+
title: Plugin Sync PO
|
|
5
|
+
description: Đồng bộ hóa từ điển Intlayer với các tệp Gettext PO. Giữ nguyên i18n hiện tại của bạn trong khi sử dụng Intlayer để quản lý, dịch và kiểm tra các tin nhắn của bạn.
|
|
6
|
+
keywords:
|
|
7
|
+
- Intlayer
|
|
8
|
+
- Sync PO
|
|
9
|
+
- Gettext
|
|
10
|
+
- i18n
|
|
11
|
+
- dịch thuật
|
|
12
|
+
slugs:
|
|
13
|
+
- doc
|
|
14
|
+
- plugin
|
|
15
|
+
- sync-po
|
|
16
|
+
youtubeVideo: https://www.youtube.com/watch?v=MpGMxniDHNg
|
|
17
|
+
history:
|
|
18
|
+
- version: 8.9.4
|
|
19
|
+
date: 2026-05-10
|
|
20
|
+
changes: "Tài liệu ban đầu cho plugin Sync PO"
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# Sync PO (cầu nối i18n) - Đồng bộ hóa PO với hỗ trợ ICU / i18next
|
|
24
|
+
|
|
25
|
+
Sử dụng Intlayer như một tiện ích bổ sung cho ngăn xếp i18n hiện có của bạn. Plugin này giữ cho các tin nhắn Gettext PO của bạn đồng bộ với từ điển Intlayer để bạn có thể:
|
|
26
|
+
|
|
27
|
+
- Giữ nguyên quy trình dịch thuật dựa trên PO hiện tại của bạn.
|
|
28
|
+
- Quản lý và dịch các tin nhắn của bạn với Intlayer (CLI, CI, nhà cung cấp, CMS) mà không cần cấu trúc lại ứng dụng của bạn.
|
|
29
|
+
- Cung cấp các hướng dẫn và nội dung SEO nhắm mục tiêu đến từng hệ sinh thái, đồng thời đề xuất Intlayer như một lớp quản lý PO.
|
|
30
|
+
|
|
31
|
+
Ghi chú và phạm vi hiện tại:
|
|
32
|
+
|
|
33
|
+
- Việc bên ngoài hóa sang CMS hoạt động cho các bản dịch và văn bản cổ điển.
|
|
34
|
+
- Chưa hỗ trợ cho việc chèn, số nhiều/ICU hoặc các tính năng runtime nâng cao của các thư viện khác trong chính các mục nhập PO.
|
|
35
|
+
- Trình chỉnh sửa trực quan chưa được hỗ trợ cho các đầu ra i18n của bên thứ ba.
|
|
36
|
+
|
|
37
|
+
### Khi nào nên sử dụng plugin này
|
|
38
|
+
|
|
39
|
+
- Bạn đã sử dụng các tệp Gettext PO cho các bản dịch của mình.
|
|
40
|
+
- Bạn muốn điền dữ liệu có hỗ trợ AI, kiểm tra trong CI và vận hành nội dung mà không cần thay đổi runtime kết xuất của mình.
|
|
41
|
+
|
|
42
|
+
## Cài đặt
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pnpm add -D @intlayer/sync-po-plugin
|
|
46
|
+
# hoặc
|
|
47
|
+
npm i -D @intlayer/sync-po-plugin
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Plugin
|
|
51
|
+
|
|
52
|
+
Gói này cung cấp hai plugin:
|
|
53
|
+
|
|
54
|
+
- `loadPO`: Tải các tệp PO vào từ điển Intlayer.
|
|
55
|
+
- Plugin này được sử dụng để tải các tệp PO từ một nguồn và sẽ được tải vào từ điển Intlayer. Nó có thể quét toàn bộ mã nguồn và tìm kiếm các tệp PO cụ thể.
|
|
56
|
+
Plugin này có thể được sử dụng:
|
|
57
|
+
- nếu bạn sử dụng một thư viện i18n áp đặt một vị trí cụ thể để tải các tệp PO của bạn, nhưng bạn muốn đặt khai báo nội dung của mình ở bất cứ đâu bạn muốn trong mã nguồn.
|
|
58
|
+
- Nó cũng có thể được sử dụng nếu bạn muốn tìm nạp các tin nhắn của mình từ một nguồn từ xa (ví dụ: CMS, API, v.v.) và lưu trữ các tin nhắn của bạn trong các tệp PO.
|
|
59
|
+
|
|
60
|
+
> Bên dưới, plugin này sẽ quét toàn bộ mã nguồn và tìm kiếm các tệp PO cụ thể và tải chúng vào từ điển Intlayer.
|
|
61
|
+
> Lưu ý rằng plugin này sẽ không ghi kết quả đầu ra và các bản dịch ngược lại vào các tệp PO.
|
|
62
|
+
|
|
63
|
+
- `syncPO`: Đồng bộ hóa các tệp PO với từ điển Intlayer.
|
|
64
|
+
- Plugin này được sử dụng để đồng bộ hóa các tệp PO với từ điển Intlayer. Nó có thể quét vị trí đã cho và tải PO khớp với mẫu cho các tệp PO cụ thể. Plugin này hữu ích nếu bạn muốn nhận được các lợi ích của Intlayer trong khi sử dụng một thư viện i18n khác.
|
|
65
|
+
|
|
66
|
+
## Sử dụng cả hai plugin
|
|
67
|
+
|
|
68
|
+
```ts fileName="intlayer.config.ts"
|
|
69
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
70
|
+
import { loadPO, syncPO } from "@intlayer/sync-po-plugin";
|
|
71
|
+
|
|
72
|
+
const config: IntlayerConfig = {
|
|
73
|
+
internationalization: {
|
|
74
|
+
locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
|
|
75
|
+
defaultLocale: Locales.ENGLISH,
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
// Giữ các tệp PO hiện tại của bạn đồng bộ với từ điển Intlayer
|
|
79
|
+
plugins: [
|
|
80
|
+
/**
|
|
81
|
+
* Sẽ tải tất cả các tệp PO trong src khớp với mẫu {key}.i18n.po
|
|
82
|
+
*/
|
|
83
|
+
loadPO({
|
|
84
|
+
source: ({ key }) => `./src/**/${key}.i18n.po`,
|
|
85
|
+
locale: Locales.ENGLISH,
|
|
86
|
+
priority: 1, // Đảm bảo các tệp PO này được ưu tiên hơn các tệp tại `./locales/en/${key}.po`
|
|
87
|
+
}),
|
|
88
|
+
/**
|
|
89
|
+
* Sẽ tải và ghi kết quả đầu ra và bản dịch ngược lại vào các tệp PO trong thư mục locales
|
|
90
|
+
*/
|
|
91
|
+
syncPO({
|
|
92
|
+
source: ({ key, locale }) => `./locales/${locale}/${key}.po`,
|
|
93
|
+
priority: 0,
|
|
94
|
+
}),
|
|
95
|
+
],
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export default config;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Plugin `syncPO`
|
|
102
|
+
|
|
103
|
+
### Bắt đầu nhanh
|
|
104
|
+
|
|
105
|
+
Thêm plugin vào `intlayer.config.ts` của bạn và trỏ nó vào cấu trúc PO hiện có của bạn.
|
|
106
|
+
|
|
107
|
+
```ts fileName="intlayer.config.ts"
|
|
108
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
109
|
+
import { syncPO } from "@intlayer/sync-po-plugin";
|
|
110
|
+
|
|
111
|
+
const config: IntlayerConfig = {
|
|
112
|
+
internationalization: {
|
|
113
|
+
locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
|
|
114
|
+
defaultLocale: Locales.ENGLISH,
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
// Giữ các tệp PO hiện tại của bạn đồng bộ với từ điển Intlayer
|
|
118
|
+
plugins: [
|
|
119
|
+
syncPO({
|
|
120
|
+
// Bố cục theo từng locale, từng namespace
|
|
121
|
+
source: ({ key, locale }) => `./locales/${locale}/${key}.po`,
|
|
122
|
+
}),
|
|
123
|
+
],
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export default config;
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Thay thế: một tệp duy nhất cho mỗi locale:
|
|
130
|
+
|
|
131
|
+
```ts fileName="intlayer.config.ts"
|
|
132
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
133
|
+
import { syncPO } from "@intlayer/sync-po-plugin";
|
|
134
|
+
|
|
135
|
+
const config: IntlayerConfig = {
|
|
136
|
+
internationalization: {
|
|
137
|
+
locales: [Locales.ENGLISH, Locales.FRENCH],
|
|
138
|
+
defaultLocale: Locales.ENGLISH,
|
|
139
|
+
},
|
|
140
|
+
plugins: [
|
|
141
|
+
syncPO({
|
|
142
|
+
source: ({ locale }) => `./locales/${locale}.po`,
|
|
143
|
+
}),
|
|
144
|
+
],
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export default config;
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### Cách hoạt động
|
|
151
|
+
|
|
152
|
+
- Đọc: plugin khám phá các tệp PO từ trình xây dựng `source` của bạn và tải chúng dưới dạng từ điển Intlayer.
|
|
153
|
+
- Ghi: sau khi xây dựng và điền dữ liệu, nó ghi PO đã bản địa hóa ngược lại các đường dẫn tương ứng (với các tiêu đề Gettext thích hợp).
|
|
154
|
+
- Tự động điền: plugin khai báo một đường dẫn `autoFill` cho mỗi từ điển. Chạy `intlayer fill` sẽ chỉ cập nhật các bản dịch bị thiếu trong các tệp PO của bạn theo mặc định.
|
|
155
|
+
|
|
156
|
+
API:
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
syncPO({
|
|
160
|
+
source: ({ key, locale }) => string, // bắt buộc
|
|
161
|
+
location?: string, // nhãn tùy chọn, mặc định: "sync-po::path/to/source"
|
|
162
|
+
priority?: number, // ưu tiên tùy chọn để giải quyết xung đột, mặc định: 0
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Nhiều nguồn PO và mức độ ưu tiên
|
|
167
|
+
|
|
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.
|
|
169
|
+
|
|
170
|
+
#### Hệ thống ưu tiên
|
|
171
|
+
|
|
172
|
+
Khi nhiều plugin nhắm mục tiêu cùng một khóa từ điển, tham số `priority` sẽ xác định plugin nào được ưu tiên:
|
|
173
|
+
|
|
174
|
+
- Số ưu tiên cao hơn sẽ thắng số thấp hơn
|
|
175
|
+
- Mức độ ưu tiên mặc định của các tệp `.content` là `0`
|
|
176
|
+
- Mức độ ưu tiên mặc định của các plugin là `0`
|
|
177
|
+
- Các plugin có cùng mức độ ưu tiên được xử lý theo thứ tự chúng xuất hiện trong cấu hình
|
|
178
|
+
|
|
179
|
+
```ts fileName="intlayer.config.ts"
|
|
180
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
181
|
+
import { syncPO } from "@intlayer/sync-po-plugin";
|
|
182
|
+
|
|
183
|
+
const config: IntlayerConfig = {
|
|
184
|
+
internationalization: {
|
|
185
|
+
locales: [Locales.ENGLISH, Locales.FRENCH],
|
|
186
|
+
defaultLocale: Locales.ENGLISH,
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
plugins: [
|
|
190
|
+
// Nguồn PO chính (mức ưu tiên cao nhất)
|
|
191
|
+
syncPO({
|
|
192
|
+
source: ({ key, locale }) => `./locales/${locale}/${key}.po`,
|
|
193
|
+
location: "main-translations",
|
|
194
|
+
priority: 10,
|
|
195
|
+
}),
|
|
196
|
+
|
|
197
|
+
// Nguồn PO dự phòng (mức ưu tiên thấp hơn)
|
|
198
|
+
syncPO({
|
|
199
|
+
source: ({ locale }) => `./fallback-locales/${locale}.po`,
|
|
200
|
+
location: "fallback-translations",
|
|
201
|
+
priority: 5,
|
|
202
|
+
}),
|
|
203
|
+
|
|
204
|
+
// Nguồn PO cũ (mức ưu tiên thấp nhất)
|
|
205
|
+
syncPO({
|
|
206
|
+
source: ({ locale }) => `/my/other/app/legacy/${locale}/messages.po`,
|
|
207
|
+
location: "legacy-translations",
|
|
208
|
+
priority: 1,
|
|
209
|
+
}),
|
|
210
|
+
],
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export default config;
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Plugin Load PO
|
|
217
|
+
|
|
218
|
+
### Bắt đầu nhanh
|
|
219
|
+
|
|
220
|
+
Thêm plugin vào `intlayer.config.ts` của bạn để nạp các tệp PO hiện có dưới dạng từ điển Intlayer. Plugin này chỉ dành cho việc đọc (không ghi vào đĩa):
|
|
221
|
+
|
|
222
|
+
```ts fileName="intlayer.config.ts"
|
|
223
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
224
|
+
import { loadPO } from "@intlayer/sync-po-plugin";
|
|
225
|
+
|
|
226
|
+
const config: IntlayerConfig = {
|
|
227
|
+
internationalization: {
|
|
228
|
+
locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
|
|
229
|
+
defaultLocale: Locales.ENGLISH,
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
plugins: [
|
|
233
|
+
// Nạp các tin nhắn PO nằm ở bất kỳ đâu trong cây mã nguồn của bạn
|
|
234
|
+
loadPO({
|
|
235
|
+
source: ({ key }) => `./src/**/${key}.i18n.po`,
|
|
236
|
+
// Tải một locale duy nhất cho mỗi phiên bản plugin (mặc định là defaultLocale của cấu hình)
|
|
237
|
+
locale: Locales.ENGLISH,
|
|
238
|
+
priority: 0,
|
|
239
|
+
}),
|
|
240
|
+
],
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
export default config;
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Thay thế: bố cục theo từng locale, vẫn chỉ dành cho việc đọc (chỉ locale được chọn mới được tải):
|
|
247
|
+
|
|
248
|
+
```ts fileName="intlayer.config.ts"
|
|
249
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
250
|
+
import { loadPO } from "@intlayer/sync-po-plugin";
|
|
251
|
+
|
|
252
|
+
const config: IntlayerConfig = {
|
|
253
|
+
internationalization: {
|
|
254
|
+
locales: [Locales.ENGLISH, Locales.FRENCH],
|
|
255
|
+
defaultLocale: Locales.ENGLISH,
|
|
256
|
+
},
|
|
257
|
+
plugins: [
|
|
258
|
+
loadPO({
|
|
259
|
+
// Chỉ các tệp cho Locales.FRENCH mới được nạp từ mẫu này
|
|
260
|
+
source: ({ key, locale }) => `./locales/${locale}/${key}.po`,
|
|
261
|
+
locale: Locales.FRENCH,
|
|
262
|
+
}),
|
|
263
|
+
],
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
export default config;
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Cách hoạt động
|
|
270
|
+
|
|
271
|
+
- Khám phá: xây dựng một glob từ trình xây dựng `source` của bạn và thu thập các tệp PO phù hợp.
|
|
272
|
+
- Nạp: tải từng tệp PO dưới dạng từ điển Intlayer với `locale` được cung cấp.
|
|
273
|
+
- Chỉ đọc: không ghi hoặc định dạng các tệp đầu ra; sử dụng `syncPO` nếu bạn cần đồng bộ hóa hai chiều.
|
|
274
|
+
- Sẵn sàng tự động điền: xác định một đường dẫn `fill` để `intlayer content fill` có thể điền các khóa bị thiếu.
|
|
275
|
+
|
|
276
|
+
### API
|
|
277
|
+
|
|
278
|
+
```ts
|
|
279
|
+
loadPO({
|
|
280
|
+
// Xây dựng các đường dẫn đến PO của bạn. `locale` là tùy chọn nếu cấu trúc của bạn không có phân đoạn locale
|
|
281
|
+
source: ({ key, locale }) => string,
|
|
282
|
+
|
|
283
|
+
// Locale mục tiêu cho các từ điển được tải bởi phiên bản plugin này
|
|
284
|
+
// Mặc định là configuration.internationalization.defaultLocale
|
|
285
|
+
locale?: Locale,
|
|
286
|
+
|
|
287
|
+
// Nhãn tùy chọn để xác định nguồn
|
|
288
|
+
location?: string, // mặc định: "plugin"
|
|
289
|
+
|
|
290
|
+
// Mức độ ưu tiên được sử dụng để giải quyết xung đột với các nguồn khác
|
|
291
|
+
priority?: number, // mặc định: 0
|
|
292
|
+
});
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Hành vi và quy ước
|
|
296
|
+
|
|
297
|
+
- Nếu mặt nạ `source` của bạn bao gồm một trình giữ chỗ locale, chỉ các tệp cho `locale` được chọn mới được nạp.
|
|
298
|
+
- Nếu không có phân đoạn `{key}` trong mặt nạ của bạn, khóa từ điển là "index".
|
|
299
|
+
- Các khóa được lấy từ đường dẫn tệp bằng cách thay thế trình giữ chỗ `{key}` trong trình xây dựng `source` của bạn.
|
|
300
|
+
- Plugin chỉ sử dụng các tệp được khám phá và không tạo ra các locale hoặc khóa bị thiếu.
|
|
301
|
+
- Đường dẫn `fill` được suy ra từ `source` của bạn và được sử dụng để cập nhật các giá trị bị thiếu thông qua CLI khi bạn chọn tham gia.
|
|
302
|
+
|
|
303
|
+
## Giải quyết xung đột
|
|
304
|
+
|
|
305
|
+
Khi cùng một khóa dịch tồn tại trong nhiều nguồn PO:
|
|
306
|
+
|
|
307
|
+
1. Plugin có mức độ ưu tiên cao nhất sẽ xác định giá trị cuối cùng
|
|
308
|
+
2. Các nguồn ưu tiên thấp hơn được sử dụng làm dự phòng cho các khóa bị thiếu
|
|
309
|
+
3. Điều này cho phép bạn duy trì các bản dịch cũ trong khi dần chuyển sang các cấu trúc mới
|
|
310
|
+
|
|
311
|
+
## CLI
|
|
312
|
+
|
|
313
|
+
Các tệp PO đã đồng bộ hóa sẽ được coi như các tệp `.content` khác. Điều đó có nghĩa là, tất cả các lệnh intlayer sẽ khả dụng cho các tệp PO đã đồng bộ hóa. Bao gồm:
|
|
314
|
+
|
|
315
|
+
- `intlayer content test` để kiểm tra xem có bản dịch nào bị thiếu không
|
|
316
|
+
- `intlayer content list` để liệt kê các tệp PO đã đồng bộ hóa
|
|
317
|
+
- `intlayer content fill` để điền các bản dịch bị thiếu
|
|
318
|
+
- `intlayer content push` để đẩy các tệp PO đã đồng bộ hóa
|
|
319
|
+
- `intlayer content pull` để kéo các tệp PO đã đồng bộ hóa
|
|
320
|
+
|
|
321
|
+
Xem [Intlayer CLI](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/cli/index.md) để biết thêm chi tiết.
|
|
322
|
+
|
|
323
|
+
## Hạn chế (hiện tại)
|
|
324
|
+
|
|
325
|
+
- Không hỗ trợ chèn hoặc số nhiều/ICU khi nhắm mục tiêu đến các thư viện bên thứ ba.
|
|
326
|
+
- Trình chỉnh sửa trực quan chưa khả dụng cho các runtime không phải Intlayer.
|
|
327
|
+
- Chỉ đồng bộ hóa PO; các định dạng danh mục không phải PO không được hỗ trợ.
|
|
328
|
+
|
|
329
|
+
## Tại sao điều này lại quan trọng
|
|
330
|
+
|
|
331
|
+
- Chúng ta có thể đề xuất các giải pháp i18n đã được thiết lập và định vị Intlayer như một tiện ích bổ sung.
|
|
332
|
+
- Chúng ta tận dụng SEO/từ khóa của họ bằng các hướng dẫn kết thúc bằng việc đề xuất Intlayer để quản lý PO.
|
|
333
|
+
- Mở rộng đối tượng có thể tiếp cận từ “các dự án mới” sang “bất kỳ nhóm nào đã sử dụng i18n”.
|
|
@@ -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.
|
|
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
|
-
-
|
|
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-
|
|
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-
|
|
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)** (
|
|
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.
|
|
228
|
+
**(Intlayer)** (`next-intlayer@8.7.12`):
|
|
220
229
|
|
|
221
230
|
出于客观性考量,我不会亲自评价 `next-intlayer`,因为这是我自己的解决方案。
|
|
222
231
|
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-04-20
|
|
3
|
+
updatedAt: 2026-04-21
|
|
4
|
+
title: 2026 年 Solid 最佳 i18n 解决方案 - 基准报告
|
|
5
|
+
description: 比较 Solid 国际化(i18n)库,如 solid-primitives、solid-i18next 和 Intlayer。关于包大小、泄漏和反应性的详细性能报告。
|
|
6
|
+
keywords:
|
|
7
|
+
- benchmark
|
|
8
|
+
- i18n
|
|
9
|
+
- intl
|
|
10
|
+
- solid
|
|
11
|
+
- performance
|
|
12
|
+
- intlayer
|
|
13
|
+
slugs:
|
|
14
|
+
- doc
|
|
15
|
+
- benchmark
|
|
16
|
+
- solid
|
|
17
|
+
author: Aymeric PINEAU
|
|
18
|
+
applicationTemplate: https://github.com/intlayer-org/benchmark-i18n-solid-template
|
|
19
|
+
history:
|
|
20
|
+
- version: 8.7.12
|
|
21
|
+
date: 2026-01-06
|
|
22
|
+
changes: "初始化基准"
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# Solid i18n 库 - 2026 基准报告
|
|
26
|
+
|
|
27
|
+
此页面是 Solid 上 i18n 解决方案的基准报告。
|
|
28
|
+
|
|
29
|
+
## 目录
|
|
30
|
+
|
|
31
|
+
<Toc/>
|
|
32
|
+
|
|
33
|
+
## 交互式基准
|
|
34
|
+
|
|
35
|
+
<I18nBenchmark framework="vite-solid" vertical/>
|
|
36
|
+
|
|
37
|
+
## 结果参考:
|
|
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_solid.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_solid.md
|
|
47
|
+
|
|
48
|
+
查看完整的基准仓库 [此处](https://github.com/intlayer-org/benchmark-i18n/tree/main)。
|
|
49
|
+
|
|
50
|
+
## 简介
|
|
51
|
+
|
|
52
|
+
国际化解决方案是 Solid 应用中最重的依赖项之一。主要风险是发送不必要的内容:单个路由包中包含其他页面和其他语言的翻译。
|
|
53
|
+
|
|
54
|
+
随着应用增长,这个问题会迅速增加发送到客户端의 JavaScript,并减慢导航速度。
|
|
55
|
+
|
|
56
|
+
实际上,对于优化最差的实现,国际化页面的重量可能是非 i18n 版本的几倍。
|
|
57
|
+
|
|
58
|
+
另一个影响是开发者体验(DX):如何声明内容、类型、命名空间组织、动态加载以及语言更改时的反应性。
|
|
59
|
+
|
|
60
|
+
## TL;DR
|
|
61
|
+
|
|
62
|
+
- **Intlayer**: 需要高级功能和优化的专业 Solid 应用的推荐选择(v8.7.12)。
|
|
63
|
+
- **@solid-primitives/i18n**: 简单项目的绝佳轻量级替代方案,但缺乏延迟加载等高级功能。
|
|
64
|
+
- **solid-i18next**: 标准但沉重的选项(约为 Intlayer 的 4.7 倍),具有与 React i18next 相同的缺点。
|
|
65
|
+
- **Paraglide**: 创新的方法,但在某些设置中 DX 复杂且存在 tree-shaking 问题。
|
|
66
|
+
|
|
67
|
+
## 测试您的应用
|
|
68
|
+
|
|
69
|
+
为了快速发现 i18n 泄漏问题,我建立了一个免费扫描仪,可在 [此处](https://intlayer.org/i18n-seo-scanner) 试用。
|
|
70
|
+
|
|
71
|
+
<iframe src="https://intlayer.org/i18n-seo-scanner" width="100%" height="600px" style="border:none;"/>
|
|
72
|
+
|
|
73
|
+
## 问题所在
|
|
74
|
+
|
|
75
|
+
限制多语言应用成本有两个关键杠杆:
|
|
76
|
+
|
|
77
|
+
- 按页面 / 命名空间拆分内容,这样在不需要时就不会加载整个字典
|
|
78
|
+
- 仅在需要时动态加载正确的语言
|
|
79
|
+
|
|
80
|
+
了解这些方案的技术限制:
|
|
81
|
+
|
|
82
|
+
**动态加载**
|
|
83
|
+
|
|
84
|
+
如果没有动态加载,大多数解决方案会从首次渲染开始将消息保留在内存中,这对于具有许多路由和语言的应用会产生显著开销。
|
|
85
|
+
|
|
86
|
+
使用动态加载,您接受一个权衡:减少初始 JS,但有时在切换语言时会有额外的请求。
|
|
87
|
+
|
|
88
|
+
**内容拆分**
|
|
89
|
+
|
|
90
|
+
围绕 `t('a.b.c')` 构建的语法非常方便,但往往鼓励在运行时保留大型 JSON 对象。这种模式使 tree-shaking 变得困难,除非库提供真正的按页面拆分策略。
|
|
91
|
+
|
|
92
|
+
## 研究方法
|
|
93
|
+
|
|
94
|
+
在此基准测试中,我们比较了以下库:
|
|
95
|
+
|
|
96
|
+
- `Base App`(无 i18n 库)
|
|
97
|
+
- `solid-intlayer` (v8.7.12)
|
|
98
|
+
- `@solid-primitives/i18n` (v2.2.1)
|
|
99
|
+
- `solid-i18next` (v17.0.2)
|
|
100
|
+
- `@inlang/paraglide-js` (v2.17.0)
|
|
101
|
+
|
|
102
|
+
框架是 `Solid`,应用包含 **10 个页面** 和 **10 种语言**。
|
|
103
|
+
|
|
104
|
+
我们比较了 **四种加载策略**:
|
|
105
|
+
|
|
106
|
+
| 策略 | 无命名空间(全局) | 具有命名空间(分层/scoped) |
|
|
107
|
+
| :----------- | :------------------------------------- | :------------------------------------------------------ |
|
|
108
|
+
| **静态加载** | **Static**: 启动时所有内容都在内存中。 | **Scoped static**: 按命名空间拆分;启动时加载所有内容。 |
|
|
109
|
+
| **动态加载** | **Dynamic**: 按需按语言加载。 | **Scoped dynamic**: 按命名空间和语言进行细粒度加载。 |
|
|
110
|
+
|
|
111
|
+
## 策略摘要
|
|
112
|
+
|
|
113
|
+
- **静态 (Static)**: 简单;初始加载后无网络延迟。缺点:包体积大。
|
|
114
|
+
- **动态 (Dynamic)**: 减轻初始重量(懒加载)。当您有多种语言时非常理想。
|
|
115
|
+
- **分层静态 (Scoped static)**: 保持代码有序(逻辑分离),无需复杂的额外网络请求。
|
|
116
|
+
- **分层动态 (Scoped dynamic)**: _代码拆分_ 和性能的最佳方法。通过仅加载当前视图和活动语言所需的内容来最小化内存使用。
|
|
117
|
+
|
|
118
|
+
## 结果详情
|
|
119
|
+
|
|
120
|
+
### 1 - 应当避免的解决方案
|
|
121
|
+
|
|
122
|
+
> Solid 生态系统中没有明确应当避免的解决方案。
|
|
123
|
+
|
|
124
|
+
### 2 - 可接受的解决方案
|
|
125
|
+
|
|
126
|
+
**(solid-i18next)** (`solid-i18next@17.0.2`):
|
|
127
|
+
|
|
128
|
+
`solid-i18next` 可能是最受欢迎的选项,因为它是最早满足 JavaScript 应用 i18n 需求的解决方案之一。它还拥有一套广泛的社区插件来解决特定问题。
|
|
129
|
+
|
|
130
|
+
该包很重(~14.6kb,约为 `solid-intlayer` 的 4.7 倍)。
|
|
131
|
+
|
|
132
|
+
尽管如此,它与基于 `t('a.b.c')` 构建的栈具有相同的主要缺点:优化是可能的,但非常耗时,且大型项目面临不良实践(命名空间 + 动态加载 + 类型)的风险。
|
|
133
|
+
|
|
134
|
+
**(@solid-primitives/i18n)** (`@solid-primitives/i18n@2.2.1`):
|
|
135
|
+
|
|
136
|
+
Solid primitive 非常轻量且高效,我推荐将其用于轻量级项目,但对于包含 cookie 管理、代理重定向、格式化器等在内的专业解决方案,它可能会迅速显现功能不足。
|
|
137
|
+
它还缺乏延迟加载和分层命名空间以进行页面大小优化。
|
|
138
|
+
|
|
139
|
+
**(Paraglide)** (`@inlang/paraglide-js@2.17.0`):
|
|
140
|
+
|
|
141
|
+
`Paraglide` 提供了一种创新且深思熟虑的方法。尽管如此,在此基准测试中,他们宣传的 tree-shaking 在我的实现中没有按预期工作。工作流程和 DX 也比其他选项更复杂。
|
|
142
|
+
我个人不喜欢在每次推送前重新生成 JS 文件,这会通过 PR 在开发者之间造成持续的合并冲突风险。
|
|
143
|
+
最后,与其他解决方案相比,Paraglide 不使用 store(例如 Solid signal)来检索当前语言以渲染内容。对于解析的每个节点,它都会从 localStorage / cookie 等请求语言。这导致执行不必要的逻辑,从而影响组件的反应性。
|
|
144
|
+
|
|
145
|
+
### 3 - 建议
|
|
146
|
+
|
|
147
|
+
**(Intlayer)** (`solid-intlayer@8.7.12`):
|
|
148
|
+
|
|
149
|
+
出于客观性考虑,我个人不会对 `solid-intlayer` 做出评价,因为它是我的个人解决方案。
|
|
150
|
+
|
|
151
|
+
### 个人笔记
|
|
152
|
+
|
|
153
|
+
此笔记仅代表个人观点,不影响基准测试结果。尽管如此,在 i18n 领域,您经常会看到围绕 `const t = useTranslation('xx')` + `<>{t('xx.xx')}</>` 模式的翻译内容共识。
|
|
154
|
+
|
|
155
|
+
在 Solid 应用中,将函数作为 `JSX.Element` 注入在我的观点中是一种反模式。它还增加了可避免的复杂性和 JavaScript 执行开销(即使几乎察觉不到)。
|