@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: Sync PO プラグイン
|
|
5
|
+
description: Intlayer 辞書を Gettext PO ファイルと同期します。Intlayer を使用してメッセージの管理、翻訳、テストを行いながら、既存の i18n を維持します。
|
|
6
|
+
keywords:
|
|
7
|
+
- Intlayer
|
|
8
|
+
- Sync PO
|
|
9
|
+
- Gettext
|
|
10
|
+
- i18n
|
|
11
|
+
- 翻訳
|
|
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: "Sync PO プラグインの初期ドキュメント"
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# Sync PO (i18n ブリッジ) - ICU / i18next サポート付きの Sync PO
|
|
24
|
+
|
|
25
|
+
既存の i18n スタックのアドオンとして Intlayer を使用します。このプラグインは、Gettext PO メッセージを Intlayer 辞書と同期させ、以下のことを可能にします。
|
|
26
|
+
|
|
27
|
+
- 既存の PO ベースの翻訳ワークフローを維持する。
|
|
28
|
+
- アプリをリファクタリングすることなく、Intlayer(CLI、CI、プロバイダー、CMS)を使用してメッセージを管理および翻訳する。
|
|
29
|
+
- Intlayer を PO 管理レイヤーとして提案しながら、各エコシステムをターゲットにしたチュートリアルや SEO コンテンツをリリースする。
|
|
30
|
+
|
|
31
|
+
注意点と現在の範囲:
|
|
32
|
+
|
|
33
|
+
- CMS への外部化は、翻訳と通常のテキストで機能します。
|
|
34
|
+
- 挿入、複数形/ICU、または PO エントリ自体の内部にある他のライブラリの高度なランタイム機能はまだサポートされていません。
|
|
35
|
+
- ビジュアルエディターは、サードパーティの i18n 出力ではまだサポートされていません。
|
|
36
|
+
|
|
37
|
+
### このプラグインを使用する場合
|
|
38
|
+
|
|
39
|
+
- すでに翻訳に Gettext PO ファイルを使用している場合。
|
|
40
|
+
- レンダリングランタイムを変更せずに、AI による補完、CI でのテスト、コンテンツ運用を行いたい場合。
|
|
41
|
+
|
|
42
|
+
## インストール
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pnpm add -D @intlayer/sync-po-plugin
|
|
46
|
+
# または
|
|
47
|
+
npm i -D @intlayer/sync-po-plugin
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## プラグイン
|
|
51
|
+
|
|
52
|
+
このパッケージは 2 つのプラグインを提供します。
|
|
53
|
+
|
|
54
|
+
- `loadPO`: PO ファイルを Intlayer 辞書にロードします。
|
|
55
|
+
- このプラグインは、ソースから PO ファイルをロードして Intlayer 辞書に読み込むために使用されます。コードベース全体をスキャンして特定の PO ファイルを検索できます。
|
|
56
|
+
このプラグインの使用例:
|
|
57
|
+
- i18n ライブラリが PO ファイルの読み込み場所を制限しているが、コンテンツ宣言はコードベース内の好きな場所に配置したい場合。
|
|
58
|
+
- リモートソース(例:CMS、API など)からメッセージを取得し、メッセージを PO ファイルに保存したい場合。
|
|
59
|
+
|
|
60
|
+
> 内部的には、このプラグインはコードベース全体をスキャンして特定の PO ファイルを検索し、Intlayer 辞書に読み込みます。
|
|
61
|
+
> このプラグインは、出力や翻訳を PO ファイルに書き戻さないことに注意してください。
|
|
62
|
+
|
|
63
|
+
- `syncPO`: PO ファイルを Intlayer 辞書と同期させます。
|
|
64
|
+
- このプラグインは、PO ファイルを Intlayer 辞書と同期させるために使用されます。指定された場所をスキャンし、特定の PO ファイルのパターンに一致する PO をロードできます。このプラグインは、別の i18n ライブラリを使用しながら Intlayer の利点を得たい場合に役立ちます。
|
|
65
|
+
|
|
66
|
+
## 両方のプラグインの使用
|
|
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
|
+
// 現在の PO ファイルを Intlayer 辞書と同期させる
|
|
79
|
+
plugins: [
|
|
80
|
+
/**
|
|
81
|
+
* src 内の {key}.i18n.po パターンに一致するすべての PO ファイルをロードします
|
|
82
|
+
*/
|
|
83
|
+
loadPO({
|
|
84
|
+
source: ({ key }) => `./src/**/${key}.i18n.po`,
|
|
85
|
+
locale: Locales.ENGLISH,
|
|
86
|
+
priority: 1, // `./locales/en/${key}.po` のファイルよりもこれらの PO ファイルが優先されるようにします
|
|
87
|
+
}),
|
|
88
|
+
/**
|
|
89
|
+
* ロードし、出力と翻訳を locales ディレクトリの PO ファイルに書き戻します
|
|
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
|
+
## `syncPO` プラグイン
|
|
102
|
+
|
|
103
|
+
### クイックスタート
|
|
104
|
+
|
|
105
|
+
プラグインを `intlayer.config.ts` に追加し、既存の PO 構造を指すようにします。
|
|
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
|
+
// 現在の PO ファイルを Intlayer 辞書と同期させる
|
|
118
|
+
plugins: [
|
|
119
|
+
syncPO({
|
|
120
|
+
// ロケール別、名前空間別のレイアウト
|
|
121
|
+
source: ({ key, locale }) => `./locales/${locale}/${key}.po`,
|
|
122
|
+
}),
|
|
123
|
+
],
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export default config;
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
代替案:ロケールごとに 1 つのファイル:
|
|
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
|
+
#### 仕組み
|
|
151
|
+
|
|
152
|
+
- 読み取り: プラグインは `source` ビルダーから PO ファイルを検出し、Intlayer 辞書として読み込みます。
|
|
153
|
+
- 書き込み: ビルドと補完の後、ローカライズされた PO を同じパスに書き戻します(適切な Gettext ヘッダー付き)。
|
|
154
|
+
- 自動補完: プラグインは各辞書の `autoFill` パスを宣言します。`intlayer fill` を実行すると、デフォルトで PO ファイルの不足している翻訳のみが更新されます。
|
|
155
|
+
|
|
156
|
+
API:
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
syncPO({
|
|
160
|
+
source: ({ key, locale }) => string, // 必須
|
|
161
|
+
location?: string, // オプションのラベル、デフォルト: "sync-po::path/to/source"
|
|
162
|
+
priority?: number, // 競合解決のためのオプションの優先度、デフォルト: 0
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 複数の PO ソースと優先度
|
|
167
|
+
|
|
168
|
+
複数の `syncPO` プラグインを追加して、異なる PO ソースを同期させることができます。これは、プロジェクトに複数の翻訳ソースや異なる PO 構造がある場合に役立ちます。
|
|
169
|
+
|
|
170
|
+
#### 優先度システム
|
|
171
|
+
|
|
172
|
+
複数のプラグインが同じ辞書キーをターゲットにしている場合、`priority` パラメーターによってどのプラグインが優先されるかが決まります。
|
|
173
|
+
|
|
174
|
+
- 優先度の高い数値が低い数値よりも優先されます
|
|
175
|
+
- `.content` ファイルのデフォルト優先度は `0` です
|
|
176
|
+
- プラグインのデフォルト優先度は `0` です
|
|
177
|
+
- 同じ優先度のプラグインは、設定に表示される順序で処理されます
|
|
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
|
+
// 主要な PO ソース (最高優先度)
|
|
191
|
+
syncPO({
|
|
192
|
+
source: ({ key, locale }) => `./locales/${locale}/${key}.po`,
|
|
193
|
+
location: "main-translations",
|
|
194
|
+
priority: 10,
|
|
195
|
+
}),
|
|
196
|
+
|
|
197
|
+
// フォールバック PO ソース (低い優先度)
|
|
198
|
+
syncPO({
|
|
199
|
+
source: ({ locale }) => `./fallback-locales/${locale}.po`,
|
|
200
|
+
location: "fallback-translations",
|
|
201
|
+
priority: 5,
|
|
202
|
+
}),
|
|
203
|
+
|
|
204
|
+
// レガシー PO ソース (最低優先度)
|
|
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
|
+
## Load PO プラグイン
|
|
217
|
+
|
|
218
|
+
### クイックスタート
|
|
219
|
+
|
|
220
|
+
既存の PO ファイルを Intlayer 辞書として取り込むために、プラグインを `intlayer.config.ts` に追加します。このプラグインは読み取り専用です(ディスクへの書き込みはありません)。
|
|
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
|
+
// ソースツリー内の任意の場所にある PO メッセージを取り込む
|
|
234
|
+
loadPO({
|
|
235
|
+
source: ({ key }) => `./src/**/${key}.i18n.po`,
|
|
236
|
+
// プラグインインスタンスごとに単一のロケールをロードします (デフォルトは config の defaultLocale です)
|
|
237
|
+
locale: Locales.ENGLISH,
|
|
238
|
+
priority: 0,
|
|
239
|
+
}),
|
|
240
|
+
],
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
export default config;
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
代替案:ロケール別のレイアウト、依然として読み取り専用(選択したロケールのみがロードされます):
|
|
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
|
+
// このパターンから Locales.FRENCH のファイルのみが読み込まれます
|
|
260
|
+
source: ({ key, locale }) => `./locales/${locale}/${key}.po`,
|
|
261
|
+
locale: Locales.FRENCH,
|
|
262
|
+
}),
|
|
263
|
+
],
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
export default config;
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### 仕組み
|
|
270
|
+
|
|
271
|
+
- 発見: `source` ビルダーから glob を構築し、一致する PO ファイルを収集します。
|
|
272
|
+
- 取り込み: 各 PO ファイルを指定された `locale` で Intlayer 辞書として読み込みます。
|
|
273
|
+
- 読み取り専用: 出力ファイルを書き込んだりフォーマットしたりしません。ラウンドトリップ同期が必要な場合は `syncPO` を使用してください。
|
|
274
|
+
- 自動補完対応: `intlayer content fill` が不足しているキーを入力できるように `fill` パスを定義します。
|
|
275
|
+
|
|
276
|
+
### API
|
|
277
|
+
|
|
278
|
+
```ts
|
|
279
|
+
loadPO({
|
|
280
|
+
// PO へのパスを構築します。構造にロケールセグメントがない場合、`locale` はオプションです。
|
|
281
|
+
source: ({ key, locale }) => string,
|
|
282
|
+
|
|
283
|
+
// このプラグインインスタンスによってロードされる辞書のターゲットロケール
|
|
284
|
+
// デフォルトは configuration.internationalization.defaultLocale です
|
|
285
|
+
locale?: Locale,
|
|
286
|
+
|
|
287
|
+
// ソースを識別するためのオプションのラベル
|
|
288
|
+
location?: string, // デフォルト: "plugin"
|
|
289
|
+
|
|
290
|
+
// 他のソースとの競合解決に使用される優先度
|
|
291
|
+
priority?: number, // デフォルト: 0
|
|
292
|
+
});
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### 動作と規約
|
|
296
|
+
|
|
297
|
+
- `source` マスクにロケールプレースホルダーが含まれている場合、選択した `locale` のファイルのみが取り込まれます。
|
|
298
|
+
- マスクに `{key}` セグメントがない場合、辞書キーは "index" になります。
|
|
299
|
+
- キーは、`source` ビルダー内の `{key}` プレースホルダーを置き換えることにより、ファイルパスから派生します。
|
|
300
|
+
- プラグインは発見されたファイルのみを使用し、不足しているロケールやキーを捏造しません。
|
|
301
|
+
- `fill` パスは `source` から推測され、オプトインしたときに CLI を介して不足している値を更新するために使用されます。
|
|
302
|
+
|
|
303
|
+
## 競合解決
|
|
304
|
+
|
|
305
|
+
同じ翻訳キーが複数の PO ソースに存在する場合:
|
|
306
|
+
|
|
307
|
+
1. 優先度が最も高いプラグインが最終的な値を決定します
|
|
308
|
+
2. 優先度の低いソースは、不足しているキーのフォールバックとして使用されます
|
|
309
|
+
3. これにより、新しい構造に徐々に移行しながら、レガシーな翻訳を維持することができます
|
|
310
|
+
|
|
311
|
+
## CLI
|
|
312
|
+
|
|
313
|
+
同期された PO ファイルは、他の `.content` ファイルと同様に扱われます。つまり、同期された PO ファイルに対してすべての intlayer コマンドが利用可能になります。以下を含みます。
|
|
314
|
+
|
|
315
|
+
- `intlayer content test`: 不足している翻訳があるかどうかをテストします
|
|
316
|
+
- `intlayer content list`: 同期された PO ファイルをリストします
|
|
317
|
+
- `intlayer content fill`: 不足している翻訳を埋めます
|
|
318
|
+
- `intlayer content push`: 同期された PO ファイルをプッシュします
|
|
319
|
+
- `intlayer content pull`: 同期された PO ファイルをプルします
|
|
320
|
+
|
|
321
|
+
詳細は [Intlayer CLI](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/cli/index.md) を参照してください。
|
|
322
|
+
|
|
323
|
+
## 制限事項(現在)
|
|
324
|
+
|
|
325
|
+
- サードパーティライブラリをターゲットにする場合、挿入や複数形/ICU のサポートはありません。
|
|
326
|
+
- Intlayer 以外のランタイムでは、ビジュアルエディターはまだ利用できません。
|
|
327
|
+
- PO 同期のみ。PO 以外のカタログ形式はサポートされていません。
|
|
328
|
+
|
|
329
|
+
## なぜこれが重要なのか
|
|
330
|
+
|
|
331
|
+
- 確立された i18n ソリューションを推奨し、Intlayer をアドオンとして位置付けることができます。
|
|
332
|
+
- Intlayer を使用して PO を管理することを提案して終わるチュートリアルで、彼らの SEO/キーワードを活用します。
|
|
333
|
+
- 対応可能なオーディエンスを「新しいプロジェクト」から「すでに 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**는 심각한 성능 문제, 벤더 종속성 및 빌드를 중단시키는 버그로 인해 권장하지 않습니다.
|
|
70
|
+
|
|
64
71
|
## 앱 테스트하기
|
|
65
72
|
|
|
66
73
|
이러한 문제들을 파악하기 위해 [여기](https://intlayer.org/i18n-seo-scanner)에서 시도해 볼 수 있는 무료 스캐너를 구축했습니다.
|
|
@@ -99,14 +106,14 @@ Webpack이나 Turbopack을 사용하고 `generateStaticParams`가 정의되어
|
|
|
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 @@ Next.js 버전 `16.2.4`와 App Router를 사용했습니다.
|
|
|
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>` 오류가 발생하며, 이는 라이브러리의 버그로 보입니다.
|
|
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 @@ Next.js 버전 `16.2.4`와 App Router를 사용했습니다.
|
|
|
186
193
|
개인적으로 푸시할 때마다 JS 파일을 다시 생성해야 하는 것이 싫습니다. 이는 PR을 통한 지속적인 머지 충돌 위험을 만듭니다. 또한 이 도구는 Next.js보다 Vite에 더 집중하는 것으로 보입니다.
|
|
187
194
|
마지막으로, 다른 솔루션과 비교할 때 Paraglide는 콘텐츠를 렌더링하기 위해 현재 로케일을 조회하는 스토어(예: React context)를 사용하지 않습니다. 파싱되는 각 노드에 대해 localStorage / 쿠키 등에서 로케일을 요청합니다. 이는 컴포넌트 반응성에 영향을 주는 불필요한 로직 실행으로 이어집니다.
|
|
188
195
|
|
|
196
|
+
> paraglide에 관한 참고 사항: 이 솔루션은 임포트를 위해 코드베이스에 코드를 주입하므로 벤치마크 리포트의 '라이브러리 크기' 지표는 거의 0에 가깝습니다. 코드 생성은 좋은 기능입니다. 사용되는 함수가 필요한 로직(모든 접두사 vs 접두사 없음, 쿠키 vs 스토리지 등)만 포함하기 때문입니다. 이에 비해 Intlayer는 빌드 시 환경 변수 주입을 통해 로직에 따라 번들러가 콘텐츠를 트리 쉐이킹하도록 강제합니다. 이 덕분에 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 @@ Next.js 버전 `16.2.4`와 App Router를 사용했습니다.
|
|
|
216
225
|
|
|
217
226
|
`t()` 스타일의 API를 선호한다면 `next-translate`가 주요 추천 사항입니다. Webpack / Turbopack 로더를 통해 `getStaticProps`에서 네임스페이스를 로드하는 `next-translate-plugin`을 통해 우아하게 작동합니다. 또한 여기에서 가장 가벼운 옵션입니다(약 2.5kb). 네임스페이싱의 경우 설정 파일에서 페이지 또는 경로별 네임스페이스를 정의하는 방식이 잘 생각되어 있으며 **next-intl**이나 **next-i18next**와 같은 주요 대안보다 유지 관리가 쉽습니다. 버전 `3.1.2`에서 정적 렌더링이 작동하지 않았고 Next.js가 동적 렌더링으로 폴백(fallback)되는 것을 확인했습니다.
|
|
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-primitives, solid-i18next, Intlayer와 같은 Solid 국제화(i18n) 라이브러리를 비교합니다. 번들 크기, 누수, 반응성에 관한 상세 성능 리포트.
|
|
6
|
+
keywords:
|
|
7
|
+
- benchmark
|
|
8
|
+
- i18n
|
|
9
|
+
- intl
|
|
10
|
+
- solid
|
|
11
|
+
- 성능
|
|
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가 복잡하고 일부 설정에서 트리 쉐이킹 문제가 발생합니다.
|
|
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 객체를 유지하도록 조장하는 경우가 많습니다. 이 모델은 라이브러리가 실제 페이지별 분리 전략을 제공하지 않는 한 트리 쉐이킹을 어렵게 만듭니다.
|
|
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
|
+
| 전략 | 네임스페이스 없음 (글로벌) | 네임스페이스 포함 (스코프) |
|
|
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는 매우 가볍고 효율적입니다. 소규모 프로젝트에는 이 솔루션을 추천하지만 쿠키 관리, 프록시 리다이렉션, 포맷터 등을 포함한 전문 솔루션에는 기능이 부족할 수 있습니다.
|
|
137
|
+
또한 페이지 크기 최적화를 위한 지연 로딩 및 네임스페이스 스코핑 기능도 누락되어 있습니다.
|
|
138
|
+
|
|
139
|
+
**(Paraglide)** (`@inlang/paraglide-js@2.17.0`):
|
|
140
|
+
|
|
141
|
+
`Paraglide`는 혁신적이고 잘 설계된 접근 방식을 제공합니다. 그럼에도 불구하고 이 벤치마크에서는 광고된 트리 쉐이킹이 나의 구현에서 작동하지 않았습니다. 워크플로우와 DX 또한 다른 옵션보다 복잡합니다.
|
|
142
|
+
개인적으로 푸시할 때마다 JS 파일을 다시 생성해야 하는 것을 선호하지 않으며, 이는 PR을 통한 개발자들 간의 지속적인 머지 충돌 위험을 만듭니다.
|
|
143
|
+
마지막으로 다른 솔루션과 비교하여 Paraglide는 콘텐츠를 렌더링하기 위한 현재 로케일을 가져오기 위해 스토어(예: Solid signal)를 사용하지 않습니다. 파싱되는 각 노드에 대해 localStorage / 쿠키 등에서 로케일을 요청합니다. 이는 컴포넌트 반응성에 영향을 미주는 불필요한 로직 실행을 초래합니다.
|
|
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 실행 오버헤드(거의 눈에 띄지 않더라도)를 추가합니다.
|