@intlayer/docs 8.7.4 → 8.7.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/blog/de/next-i18next_vs_next-intl_vs_intlayer.md +0 -2
- package/blog/en-GB/next-i18next_vs_next-intl_vs_intlayer.md +0 -2
- package/blog/es/next-i18next_vs_next-intl_vs_intlayer.md +0 -2
- package/blog/fr/next-i18next_vs_next-intl_vs_intlayer.md +0 -2
- package/blog/id/list_i18n_technologies/frameworks/svelte.md +0 -2
- package/blog/it/next-i18next_vs_next-intl_vs_intlayer.md +0 -2
- package/blog/ja/next-i18next_vs_next-intl_vs_intlayer.md +0 -2
- package/blog/ko/next-i18next_vs_next-intl_vs_intlayer.md +0 -2
- package/blog/pl/list_i18n_technologies/frameworks/svelte.md +0 -2
- package/blog/pt/next-i18next_vs_next-intl_vs_intlayer.md +0 -2
- package/blog/ru/next-i18next_vs_next-intl_vs_intlayer.md +0 -2
- package/blog/vi/list_i18n_technologies/frameworks/svelte.md +0 -2
- package/blog/zh/next-i18next_vs_next-intl_vs_intlayer.md +0 -2
- package/dist/cjs/generated/docs.entry.cjs +60 -0
- package/dist/cjs/generated/docs.entry.cjs.map +1 -1
- package/dist/esm/generated/docs.entry.mjs +60 -0
- package/dist/esm/generated/docs.entry.mjs.map +1 -1
- package/dist/types/generated/docs.entry.d.ts +3 -0
- package/dist/types/generated/docs.entry.d.ts.map +1 -1
- package/docs/ar/benchmark/index.md +29 -0
- package/docs/ar/benchmark/nextjs.md +227 -0
- package/docs/ar/benchmark/tanstack.md +193 -0
- package/docs/ar/intlayer_with_tanstack.md +0 -2
- package/docs/de/benchmark/index.md +29 -0
- package/docs/de/benchmark/nextjs.md +227 -0
- package/docs/de/benchmark/tanstack.md +193 -0
- package/docs/en/benchmark/___NOTE.md +82 -0
- package/docs/en/benchmark/___nextjs.md +195 -0
- package/docs/en/benchmark/___tanstack.md +187 -0
- package/docs/en/benchmark/index.md +29 -0
- package/docs/en/benchmark/nextjs.md +228 -0
- package/docs/en/benchmark/tanstack.md +217 -0
- package/docs/en-GB/benchmark/index.md +29 -0
- package/docs/en-GB/benchmark/nextjs.md +228 -0
- package/docs/en-GB/benchmark/tanstack.md +193 -0
- package/docs/es/benchmark/index.md +29 -0
- package/docs/es/benchmark/nextjs.md +226 -0
- package/docs/es/benchmark/tanstack.md +193 -0
- package/docs/fr/benchmark/index.md +29 -0
- package/docs/fr/benchmark/nextjs.md +227 -0
- package/docs/fr/benchmark/tanstack.md +193 -0
- package/docs/hi/benchmark/index.md +29 -0
- package/docs/hi/benchmark/nextjs.md +227 -0
- package/docs/hi/benchmark/tanstack.md +193 -0
- package/docs/id/benchmark/index.md +29 -0
- package/docs/id/benchmark/nextjs.md +227 -0
- package/docs/id/benchmark/tanstack.md +193 -0
- package/docs/id/intlayer_with_react_native+expo.md +0 -2
- package/docs/it/benchmark/index.md +29 -0
- package/docs/it/benchmark/nextjs.md +227 -0
- package/docs/it/benchmark/tanstack.md +193 -0
- package/docs/ja/benchmark/index.md +29 -0
- package/docs/ja/benchmark/nextjs.md +227 -0
- package/docs/ja/benchmark/tanstack.md +193 -0
- package/docs/ko/benchmark/index.md +29 -0
- package/docs/ko/benchmark/nextjs.md +227 -0
- package/docs/ko/benchmark/tanstack.md +193 -0
- package/docs/ko/intlayer_with_tanstack.md +0 -2
- package/docs/pl/benchmark/index.md +29 -0
- package/docs/pl/benchmark/nextjs.md +227 -0
- package/docs/pl/benchmark/tanstack.md +193 -0
- package/docs/pt/benchmark/index.md +29 -0
- package/docs/pt/benchmark/nextjs.md +227 -0
- package/docs/pt/benchmark/tanstack.md +193 -0
- package/docs/ru/benchmark/index.md +29 -0
- package/docs/ru/benchmark/nextjs.md +227 -0
- package/docs/ru/benchmark/tanstack.md +193 -0
- package/docs/tr/benchmark/index.md +29 -0
- package/docs/tr/benchmark/nextjs.md +227 -0
- package/docs/tr/benchmark/tanstack.md +193 -0
- package/docs/uk/benchmark/index.md +29 -0
- package/docs/uk/benchmark/nextjs.md +227 -0
- package/docs/uk/benchmark/tanstack.md +193 -0
- package/docs/vi/benchmark/index.md +29 -0
- package/docs/vi/benchmark/nextjs.md +227 -0
- package/docs/vi/benchmark/tanstack.md +193 -0
- package/docs/zh/benchmark/index.md +29 -0
- package/docs/zh/benchmark/nextjs.md +227 -0
- package/docs/zh/benchmark/tanstack.md +193 -0
- package/package.json +6 -6
- package/src/generated/docs.entry.ts +60 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-04-20
|
|
3
|
+
updatedAt: 2026-04-21
|
|
4
|
+
title: 2026年におけるNext.jsの最適なi18nソリューション - ベンチマークレポート
|
|
5
|
+
description: next-intl、next-i18next、IntlayerなどのNext.js国際化(i18n)ライブラリを比較。バンドルサイズ、リーク、反応性に関する詳細なパフォーマンスレポート。
|
|
6
|
+
keywords:
|
|
7
|
+
- benchmark
|
|
8
|
+
- i18n
|
|
9
|
+
- intl
|
|
10
|
+
- nextjs
|
|
11
|
+
- パフォーマンス
|
|
12
|
+
- intlayer
|
|
13
|
+
slugs:
|
|
14
|
+
- doc
|
|
15
|
+
- benchmark
|
|
16
|
+
- nextjs
|
|
17
|
+
author: Aymeric PINEAU
|
|
18
|
+
applicationTemplate: https://github.com/intlayer-org/benchmark-i18n
|
|
19
|
+
history:
|
|
20
|
+
- version: 8.7.5
|
|
21
|
+
date: 2026-01-06
|
|
22
|
+
changes: "ベンチマーク初期化"
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# Next.js i18nライブラリ — 2026年ベンチマークレポート
|
|
26
|
+
|
|
27
|
+
このページは、Next.jsにおけるi18nソリューションのベンチマークレポートです。
|
|
28
|
+
|
|
29
|
+
## 目次
|
|
30
|
+
|
|
31
|
+
<Toc/>
|
|
32
|
+
|
|
33
|
+
## インタラクティブベンチマーク
|
|
34
|
+
|
|
35
|
+
<I18nBenchmark framework="nextjs" 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-nextjs.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-nextjs.md
|
|
47
|
+
|
|
48
|
+
ベンチマークのリポジトリ全体は[こちら](https://github.com/intlayer-org/benchmark-i18n)でご確認いただけます。
|
|
49
|
+
|
|
50
|
+
## はじめに
|
|
51
|
+
|
|
52
|
+
国際化ライブラリはアプリケーションに大きな影響を与えます。主なリスクは、ユーザーが1ページしか閲覧しないにもかかわらず、すべてのページとすべての言語のコンテンツをロードしてしまうことです。
|
|
53
|
+
|
|
54
|
+
アプリが成長するにつれて、バンドルサイズが指数関数的に増大し、パフォーマンスが著しく低下する可能性があります。
|
|
55
|
+
|
|
56
|
+
最悪のケースでは、国際化によってページサイズが4倍近くに膨れ上がることがあります。
|
|
57
|
+
|
|
58
|
+
また、i18nライブラリのもう一つの影響として、開発の遅延が挙げられます。コンポーネントを多言語対応に作り変える作業は時間がかかります。
|
|
59
|
+
|
|
60
|
+
この問題の解決は難しいため、DX(開発体験)にフォーカスしたもの、パフォーマンスやスケーラビリティにフォーカスしたものなど、さまざまなソリューションが存在します。
|
|
61
|
+
|
|
62
|
+
Intlayerは、これらの各側面において最適化を試みています。
|
|
63
|
+
|
|
64
|
+
## アプリをテストする
|
|
65
|
+
|
|
66
|
+
これらの問題を顕在化させるために、無料のスキャナーを作成しました。[こちら](https://intlayer.org/i18n-seo-scanner)で試すことができます。
|
|
67
|
+
|
|
68
|
+
<iframe src="https://intlayer.org/i18n-seo-scanner" width="100%" height="600px" style="border:none;"/>
|
|
69
|
+
|
|
70
|
+
## 問題点
|
|
71
|
+
|
|
72
|
+
多言語アプリがバンドルサイズに与える影響を制限するには、主に2つの方法があります。
|
|
73
|
+
|
|
74
|
+
- JSON(またはコンテンツ)をファイル、変数、ネームスペースごとに分割し、特定のページで使用されないコンテンツをバンドラーがツリーシェイキングできるようにする。
|
|
75
|
+
- ページのコンテンツをユーザーの使用言語のみ動的にロードする。
|
|
76
|
+
|
|
77
|
+
これらのアプローチの技術的な制限:
|
|
78
|
+
|
|
79
|
+
**動的ロード**
|
|
80
|
+
|
|
81
|
+
WebpackやTurbopackを使用し、`[locale]/page.tsx`のようなルートを宣言したり、`generateStaticParams`を定義したりしたとしても、バンドラーは`locale`を静的な定数として扱いません。つまり、すべての言語のコンテンツが各ページに引き込まれる可能性があります。これを制限する主な方法は、動的インポート(例:`import('./locales/${locale}.json')`)を介してコンテンツをロードすることです。
|
|
82
|
+
|
|
83
|
+
ビルド時に何が起こるかというと、Next.jsはロケールごとに1つのJSバンドルを生成します(例:`./locales_fr_12345.js`)。サイトがクライアントに送信され、ページが実行されると、ブラウザは必要なJSファイル(例:`./locales_fr_12345.js`)に対して追加のHTTPリクエストを実行します。
|
|
84
|
+
|
|
85
|
+
> 同じ問題を解決する別の方法は、`fetch()`を使用してJSONを動的にロードすることです。これは、JSONが`/public`の下にある場合の`Tolgee`や、コンテンツのロードに`getStaticProps`を使用する`next-translate`の仕組みです。流れは同じで、ブラウザがアセットをロードするために追加のHTTPリクエストを行います。
|
|
86
|
+
|
|
87
|
+
**コンテンツの分割**
|
|
88
|
+
|
|
89
|
+
`const t = useTranslation()` + `t('my-object.my-sub-object.my-key')`のような構文を使用する場合、通常、ライブラリがキーを解析して解決できるように、JSON全体がバンドルに含まれている必要があります。そのため、ページで使用されていないコンテンツの多くが同梱されてしまいます。
|
|
90
|
+
|
|
91
|
+
これを軽減するために、一部のライブラリ(`next-i18next`、`next-intl`、`lingui`、`next-translate`、`next-international`など)では、ページごとにロードするネームスペースを宣言する必要があります。
|
|
92
|
+
|
|
93
|
+
対照的に、`Paraglide`はビルド前にJSONを`const en_my_var = () => 'my value'`のようなフラットなシンボルに変換するステップを追加します。理論的には、これによりページ上の未使用コンテンツをツリーシェイキングできるようになります。しかし、後述するように、この方法にもトレードオフがあります。
|
|
94
|
+
|
|
95
|
+
最終的に、`Intlayer`はビルド時の最適化を適用し、`useIntlayer('my-key')`が対応するコンテンツに直接置き換えられるようにします。
|
|
96
|
+
|
|
97
|
+
## 調査方法
|
|
98
|
+
|
|
99
|
+
このベンチマークでは、以下のライブラリを比較しました。
|
|
100
|
+
|
|
101
|
+
- `Base App`(i18nライブラリなし)
|
|
102
|
+
- `next-intlayer` (v8.7.5)
|
|
103
|
+
- `next-i18next` (v16.0.5)
|
|
104
|
+
- `next-intl` (v4.9.1)
|
|
105
|
+
- `@lingui/core` (v5.3.0)
|
|
106
|
+
- `next-translate` (v3.1.2)
|
|
107
|
+
- `next-international` (v1.3.1)
|
|
108
|
+
- `@inlang/paraglide-js` (v2.15.1)
|
|
109
|
+
- `tolgee` (v7.0.0)
|
|
110
|
+
- `@lingo.dev/compiler` (v0.4.0)
|
|
111
|
+
- `wuchale` (v0.22.11)
|
|
112
|
+
- `gt-next` (v6.16.5)
|
|
113
|
+
|
|
114
|
+
Next.jsのバージョンは`16.2.4`(App Router)を使用しました。
|
|
115
|
+
|
|
116
|
+
**10ページ**と**10言語**を持つ多言語アプリを作成しました。
|
|
117
|
+
|
|
118
|
+
**4つのロード戦略**を比較しました。
|
|
119
|
+
|
|
120
|
+
| 戦略 | ネームスペースなし(グローバル) | ネームスペースあり(スコープ指定) |
|
|
121
|
+
| :------------- | :---------------------------------------------- | :------------------------------------------------------------------- |
|
|
122
|
+
| **静的ロード** | **Static**: 起動時にすべてをメモリ上に。 | **Scoped static**: ネームスペースで分割。起動時にすべてロード。 |
|
|
123
|
+
| **動的ロード** | **Dynamic**: ロケールごとのオンデマンドロード。 | **Scoped dynamic**: ネームスペースとロケールごとのきめ細かなロード。 |
|
|
124
|
+
|
|
125
|
+
## 戦略の構成
|
|
126
|
+
|
|
127
|
+
- **Static**: シンプル。初回ロード後のネットワーク遅延がない。短所:バンドルサイズが大きい。
|
|
128
|
+
- **Dynamic**: 初回の重さを軽減(遅延ロード)。ロケールが多い場合に理想的。
|
|
129
|
+
- **Scoped static**: 複雑な追加ネットワークリクエストなしで、コードを整理(論理的な分離)できる。
|
|
130
|
+
- **Scoped dynamic**: コード分割とパフォーマンスにおいて最良のアプローチ。現在のビューとアクティブなロケールが必要なものだけをロードすることで、メモリ使用量を最小限に抑える。
|
|
131
|
+
|
|
132
|
+
### 測定対象:
|
|
133
|
+
|
|
134
|
+
各スタックにおいて、実際のブラウザで同じ多言語アプリを実行し、実際に何が送出され、どのくらいの時間がかかったかを記録しました。サイズは、生のソースコードのカウントよりも実際のダウンロード量に近いため、**一般的なWeb圧縮後**の値を報告しています。
|
|
135
|
+
|
|
136
|
+
- **国際化ライブラリのサイズ**: バンドル、ツリーシェイキング、および圧縮後のi18nライブラリのサイズです。中身が空のコンポーネントにおけるプロバイダー(例:`NextIntlClientProvider`)とフック(例:`useTranslations`)のコードのサイズを指します。これには翻訳ファイルのロードは含まれません。コンテンツが入る前にライブラリ自体がどれだけコスト高であるかを示します。
|
|
137
|
+
|
|
138
|
+
- **ページごとのJavaScript量**: 各ベンチマークルートにおいて、ブラウザがその訪問で引き込むスクリプトの量です。スイート内のページ全体(およびレポートで集計されている場合はロケール全体)の平均値です。重いページは遅いページです。
|
|
139
|
+
|
|
140
|
+
- **他のロケールからのリーク**: 同じページの他の言語のコンテンツが、誤って対象ページにロードされてしまうことです。このコンテンツは不要であり、回避されるべきです(例:`/en/about`ページのバンドルに含まれる`/fr/about`ページのコンテンツ)。
|
|
141
|
+
|
|
142
|
+
- **他のルートからのリーク**: アプリ内の**他の画面**についても同様です。1ページしか開いていないのに、他のページのコピーが紛れ込んでいないかを測定します(例:`/en/contact`ページのバンドルに含まれる`/en/about`ページのコンテンツ)。スコアが高い場合は、分割が不十分であるか、バンドルが広範囲すぎることを示しています。
|
|
143
|
+
|
|
144
|
+
- **コンポーネントの平均バンドルサイズ**: 一般的なUIパーツをアプリ全体の巨大な数値に隠すのではなく、**一つずつ**測定します。これにより、国際化が日常的なコンポーネントをひっそりと膨らませていないかを確認できます。たとえば、コンポーネントが再レンダリングされると、それらすべてのデータをメモリからロードすることになります。コンポーネントに巨大なJSONを添付することは、未使用データの大きな蓄積を接続するようなもので、コンポーネントのパフォーマンスを低下させます。
|
|
145
|
+
|
|
146
|
+
- **言語切り替えの反応性**: アプリ自身のコントロールを使用して言語を切り替え、ページが明確に切り替わるまでにかかる時間を測定します。ラボ内での微細なステップではなく、訪問者が気づく時間を対象としています。
|
|
147
|
+
|
|
148
|
+
- **言語変更後のレンダリング作業**: 切り替えが進行し始めてから、新しい言語でのインターフェースの再描画にかかった労力の追跡調査です。「体感」時間とフレームワークのコストが乖離している場合に有用です。
|
|
149
|
+
|
|
150
|
+
- **初回ページロード時間**: ナビゲーションから、テストシナリオにおいてブラウザがページを完全にロードしたと判断するまでの時間です。コールドスタートの比較に適しています。
|
|
151
|
+
|
|
152
|
+
- **ハイドレーション時間**: アプリが表示している場合、クライアントがサーバーのHTMLを実際にクリックできるものに変換するのにかかる時間です。表内のダッシュ(-)は、その実装がこのベンチマークで信頼できるハイドレーション数値を提供しなかったことを意味します。
|
|
153
|
+
|
|
154
|
+
## 結果の詳細
|
|
155
|
+
|
|
156
|
+
### 1 — 避けるべきソリューション
|
|
157
|
+
|
|
158
|
+
`gt-next`や`lingo.dev`のようなソリューションは、明らかに避けるのが賢明です。これらはベンダーロックインを伴い、コードベースを汚染します。実装に何時間も費やしたにもかかわらず、TanStack StartでもNext.jsでも、正しく動作させることはできませんでした。
|
|
159
|
+
|
|
160
|
+
遭遇した問題:
|
|
161
|
+
|
|
162
|
+
**(General Translation)** (`gt-next@6.16.5`):
|
|
163
|
+
|
|
164
|
+
- 110kbのアプリに対して、`gt-react`は440kb以上の余分なデータを追加します。
|
|
165
|
+
- General Translationを使用した最初のビルドで「Quota Exceeded, please upgrade your plan(クォータ超過、プランをアップグレードしてください)」と表示されました。
|
|
166
|
+
- 翻訳がレンダリングされません。`Error: <T> used on the client-side outside of <GTProvider>`というエラーが発生しましたが、これはライブラリのバグのようです。
|
|
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時間以内に修正しました。
|
|
168
|
+
- このライブラリはNext.jsページの静的レンダリングをブロックします。
|
|
169
|
+
|
|
170
|
+
**(Lingo.dev)** (`@lingo.dev/compiler@0.4.0`):
|
|
171
|
+
|
|
172
|
+
- AIのクォータを超過し、ビルドが完全にブロックされました。つまり、支払いをしない限りプロダクションへのデプロイができません。
|
|
173
|
+
- コンパイラが翻訳コンテンツの約40%を認識していませんでした。動作させるために、すべての`.map`をフラットなコンポーネントブロックに書き換える必要がありました。
|
|
174
|
+
- CLIにバグがあり、理由もなく設定ファイルをリセットすることがありました。
|
|
175
|
+
- ビルド時に、新しいコンテンツが追加されると生成されたJSONを完全に消去してしまいました。結果として、数個のキーのために既存の300個以上のキーが消失することがありました。
|
|
176
|
+
|
|
177
|
+
### 2 — 実験的なソリューション
|
|
178
|
+
|
|
179
|
+
**(Wuchale)** (`wuchale@0.22.11`):
|
|
180
|
+
|
|
181
|
+
`Wuchale`の背後にあるアイデアは興味深いものですが、まだ実用的ではありません。反応性の問題に遭遇し、アプリを動作させるためにプロバイダーの強制的な再レンダリングが必要でした。ドキュメントもかなり不明瞭で、導入のハードルが高いです。
|
|
182
|
+
|
|
183
|
+
**(Paraglide)** (`@inlang/paraglide-js@2.15.1`):
|
|
184
|
+
|
|
185
|
+
`Paraglide`は革新的でよく考えられたアプローチを提供しています。それにもかかわらず、このベンチマークでは、Next.jsやTanStack Startの設定において、宣伝されていたツリーシェイキングは機能しませんでした。ワークフローとDXは他の選択肢よりも複雑です。
|
|
186
|
+
個人的には、プッシュのたびにJSファイルを再生成しなければならないのが嫌いです。これはPRを通じて常にマージ競合のリスクを生み出します。また、このツールはNext.jsよりもViteにフォーカスしているように見えます。
|
|
187
|
+
最後に、他のソリューションと比較して、Paraglideはコンテンツをレンダリングするために現在のロケールを取得するためのストア(例:Reactコンテキスト)を使用しません。パースされる各ノードについて、localStorageやクッキーなどからロケールをリクエストします。これにより、コンポーネントの反応性に影響を与える不要なロジックが実行されます。
|
|
188
|
+
|
|
189
|
+
### 3 — 許容できるソリューション
|
|
190
|
+
|
|
191
|
+
**(Tolgee)** (`tolgee@7.0.0`):
|
|
192
|
+
|
|
193
|
+
`Tolgee`は前述の問題の多くに対処しています。しかし、同様のツールよりも導入が難しいと感じました。型安全性が提供されていないため、コンパイル時に紛失したキーを見つけることも困難です。キーの不備を検出するために、Tolgeeの関数を自前の関数でラップする必要がありました。
|
|
194
|
+
|
|
195
|
+
**(Next Intl)** (`next-intl@4.9.1`):
|
|
196
|
+
|
|
197
|
+
`next-intl`は最もトレンディな選択肢であり、AIエージェントが最も推奨するものですが、私の見解ではそれは間違いです。導入は簡単です。しかし実際には、リークを制限するための最適化は複雑です。動的ロード、ネームスぺーシング、TypeScriptの型を組み合わせると、開発スピードが著しく低下します。パッケージもかなり重いです(`NextIntlClientProvider` + `useTranslations`で約13kb、これは`next-intlayer`の2倍以上です)。**next-intl**はかつてNext.jsページの静的レンダリングをブロックしていました。`setRequestLocale()`というヘルパーを提供していますが、`en.json`や`fr.json`のような集中管理されたファイルに対しては部分的に対処されているものの、コンテンツが`en/shared.json`、`fr/shared.json`、`es/shared.json`のようにネームスペースに分割されている場合、依然として静的レンダリングが壊れます。
|
|
198
|
+
|
|
199
|
+
**(Next I18next)** (`next-i18next@16.0.5`):
|
|
200
|
+
|
|
201
|
+
`next-i18next`は、JavaScriptアプリにおける最初期のi18nソリューションの一つであったため、おそらく最も人気のある選択肢です。多くのコミュニティプラグインがあります。これには`next-intl`と同じ大きな欠点があります。パッケージが非常に重いです(`I18nProvider` + `useTranslation`で約18kb、`next-intlayer`の約3倍)。
|
|
202
|
+
|
|
203
|
+
メッセージ形式も異なります。`next-intl`はICU MessageFormatを使用しますが、`i18next`は独自の形式を使用します。
|
|
204
|
+
|
|
205
|
+
**(Next International)** (`next-international@1.3.1`):
|
|
206
|
+
|
|
207
|
+
`next-international`も上記の問題に取り組んでいますが、`next-intl`や`next-i18next`と大きな違いはありません。ネームスペース固有の翻訳のために`scopedT()`が含まれていますが、それを使用してもバンドルサイズへの影響はほとんどありません。
|
|
208
|
+
|
|
209
|
+
**(Lingui)** (`@lingui/core@5.3.0`):
|
|
210
|
+
|
|
211
|
+
`Lingui`はしばしば賞賛されます。個人的には、`lingui extract` / `lingui compile`のワークフローが他の選択肢よりも複雑で、明確な利点が見出せませんでした。また、AIを混乱させる一貫性のない構文(例:`t()`、`t''`、`i18n.t()`、`<Trans>`)も見受けられました。
|
|
212
|
+
|
|
213
|
+
### 4 — 推奨事項
|
|
214
|
+
|
|
215
|
+
**(Next Translate)** (`next-translate@3.1.2`):
|
|
216
|
+
|
|
217
|
+
`t()`スタイルのAPIがお好みなら、`next-translate`が私の主な推奨事項です。`next-translate-plugin`を介して優雅に動作し、Webpack / Turbopackローダーを使用して`getStaticProps`経由でネームスペースをロードします。また、今回の中で最も軽量な選択肢です(約2.5kb)。ネームスぺーシングについては、設定ファイルでページやルートごとにネームスペースを定義する方法がよく考えられており、**next-intl**や**next-i18next**のような主要な選択肢よりもメンテナンスが容易です。バージョン`3.1.2`では、静的レンダリングが機能せず、Next.jsが動的レンダリングにフォールバックすることに気づきました。
|
|
218
|
+
|
|
219
|
+
**(Intlayer)** (`next-intlayer@8.7.5`):
|
|
220
|
+
|
|
221
|
+
客観性を保つため、自分自身のソリューションである`next-intlayer`については個人的な判断を控えさせていただきます。
|
|
222
|
+
|
|
223
|
+
### 個人的なメモ
|
|
224
|
+
|
|
225
|
+
このメモは個人的なものであり、ベンチマークの結果には影響しません。i18nの世界では、`const t = useTranslation('xx')` + `<>{t('xx.xx')}</>`のようなパターンが合意事項としてよく見られます。
|
|
226
|
+
|
|
227
|
+
Reactアプリにおいて、関数を`ReactNode`として注入することは、私の考えではアンチパターンです。また、避けられるはずの複雑さとJavaScriptの実行オーバーヘッド(たとえ微々たるものであっても)を付加することになります。
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-04-20
|
|
3
|
+
updatedAt: 2026-04-21
|
|
4
|
+
title: 2026年におけるTanStack Startの最適なi18nソリューション - ベンチマークレポート
|
|
5
|
+
description: react-i18next、use-intl、IntlayerなどのTanStack Start国際化ライブラリを比較。バンドルサイズ、リーク、反応性に関する詳細なパフォーマンスレポート。
|
|
6
|
+
keywords:
|
|
7
|
+
- benchmark
|
|
8
|
+
- i18n
|
|
9
|
+
- intl
|
|
10
|
+
- tanstack
|
|
11
|
+
- パフォーマンス
|
|
12
|
+
- intlayer
|
|
13
|
+
slugs:
|
|
14
|
+
- doc
|
|
15
|
+
- benchmark
|
|
16
|
+
- tanstack
|
|
17
|
+
author: Aymeric PINEAU
|
|
18
|
+
applicationTemplate: https://github.com/intlayer-org/benchmark-i18n-tanstack-start-template
|
|
19
|
+
history:
|
|
20
|
+
- version: 8.7.5
|
|
21
|
+
date: 2026-01-06
|
|
22
|
+
changes: "ベンチマーク初期化"
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# TanStack Start i18nライブラリ — 2026年ベンチマークレポート
|
|
26
|
+
|
|
27
|
+
このページは、TanStack Startにおけるi18nソリューションのベンチマークレポートです。
|
|
28
|
+
|
|
29
|
+
## 目次
|
|
30
|
+
|
|
31
|
+
<Toc/>
|
|
32
|
+
|
|
33
|
+
## インタラクティブベンチマーク
|
|
34
|
+
|
|
35
|
+
<I18nBenchmark framework="tanstack" 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-tanstack.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-tanstack.md
|
|
47
|
+
|
|
48
|
+
ベンチマークのリポジトリ全体は[こちら](https://github.com/intlayer-org/benchmark-i18n/tree/main)でご確認いただけます。
|
|
49
|
+
|
|
50
|
+
## はじめに
|
|
51
|
+
|
|
52
|
+
国際化ソリューションは、Reactアプリにおいて最も重い依存関係の一つです。TanStack Startにおいて主なリスクとなるのは、不必要なコンテンツ(単一ルートのバンドルに含まれる他のページや他のロケールの翻訳)を送出してしまうことです。
|
|
53
|
+
|
|
54
|
+
アプリが成長するにつれて、この問題はクライアントに送信されるJavaScriptを急速に肥大化させ、ナビゲーションを低下させる可能性があります。
|
|
55
|
+
|
|
56
|
+
実際、最適化が不十分な実装では、国際化されたページがi18nなしのバージョンよりも数倍重くなることがあります。
|
|
57
|
+
|
|
58
|
+
もう一つの影響は開発体験(DX)への影響です。コンテンツの宣言方法、型、ネームスペースの構成、動的ロード、およびロケール変更時の反応性などが挙げられます。
|
|
59
|
+
|
|
60
|
+
## アプリをテストする
|
|
61
|
+
|
|
62
|
+
i18nのリーク問題を素早く特定するために、無料のスキャナーを用意しました。[こちら](https://intlayer.org/i18n-seo-scanner)で利用可能です。
|
|
63
|
+
|
|
64
|
+
<iframe src="https://intlayer.org/i18n-seo-scanner" width="100%" height="600px" style="border:none;"/>
|
|
65
|
+
|
|
66
|
+
## 問題点
|
|
67
|
+
|
|
68
|
+
多言語アプリのコストを制限するには、2つの手段が不可欠です。
|
|
69
|
+
|
|
70
|
+
- ページやネームスペースごとにコンテンツを分割し、不要なときに辞書全体をロードしないようにする
|
|
71
|
+
- 必要なときにのみ、適切なロケールを動的にロードする
|
|
72
|
+
|
|
73
|
+
これらのアプローチの技術的な制限を理解する:
|
|
74
|
+
|
|
75
|
+
**動的ロード**
|
|
76
|
+
|
|
77
|
+
動的ロードを行わない場合、ほとんどのソリューションは最初のレンダリングからメッセージをメモリ上に保持し続けます。これにより、多くのルートとロケールを持つアプリでは大きなオーバーヘッドが生じます。
|
|
78
|
+
|
|
79
|
+
動的ロードを採用する場合、トレードオフを受け入れることになります。初回のJS量は減りますが、言語の切り替え時に追加のリクエストが発生する場合があります。
|
|
80
|
+
|
|
81
|
+
**コンテンツの分割**
|
|
82
|
+
|
|
83
|
+
`const t = useTranslation()` + `t('a.b.c')`を中心に構築された構文は非常に便利ですが、実行時に大きなJSONオブジェクトを保持することを助長しがちです。ライブラリがページごとの本当の分割戦略を提供していない限り、このモデルではツリーシェイキングが困難になります。
|
|
84
|
+
|
|
85
|
+
## 調査方法
|
|
86
|
+
|
|
87
|
+
このベンチマークでは、以下のライブラリを比較しました。
|
|
88
|
+
|
|
89
|
+
- `Base App`(i18nライブラリなし)
|
|
90
|
+
- `react-intlayer` (v8.7.5-canary.0)
|
|
91
|
+
- `react-i18next` (v17.0.2)
|
|
92
|
+
- `use-intl` (v4.9.1)
|
|
93
|
+
- `@lingui/core` (v5.3.0)
|
|
94
|
+
- `@inlang/paraglide-js` (v2.15.1)
|
|
95
|
+
- `tolgee` (v7.0.0)
|
|
96
|
+
- `react-intl` (v10.1.1)
|
|
97
|
+
- `wuchale` (v0.22.11)
|
|
98
|
+
- `gt-react` (vlatest)
|
|
99
|
+
- `lingo.dev` (v0.133.9)
|
|
100
|
+
|
|
101
|
+
フレームワークは`TanStack Start`で、**10ページ**と**10言語**を持つ多言語アプリを使用しました。
|
|
102
|
+
|
|
103
|
+
**4つのロード戦略**を比較しました。
|
|
104
|
+
|
|
105
|
+
| 戦略 | ネームスペースなし(グローバル) | ネームスペースあり(スコープ指定) |
|
|
106
|
+
| :------------- | :---------------------------------------------- | :------------------------------------------------------------------- |
|
|
107
|
+
| **静的ロード** | **Static**: 起動時にすべてをメモリ上に。 | **Scoped static**: ネームスペースで分割。起動時にすべてロード。 |
|
|
108
|
+
| **動的ロード** | **Dynamic**: ロケールごとのオンデマンドロード。 | **Scoped dynamic**: ネームスペースとロケールごとのきめ細かなロード。 |
|
|
109
|
+
|
|
110
|
+
## 戦略の構成
|
|
111
|
+
|
|
112
|
+
- **Static**: シンプル。初回ロード後のネットワーク遅延がない。短所:バンドルサイズが大きい。
|
|
113
|
+
- **Dynamic**: 初回の重さを軽減(遅延ロード)。ロケールが多い場合に理想的。
|
|
114
|
+
- **Scoped static**: 複雑な追加ネットワークリクエストなしで、コードを整理(論理的な分離)できる。
|
|
115
|
+
- **Scoped dynamic**: コード分割とパフォーマンスにおいて最良のアプローチ。現在のビューとアクティブなロケールが必要なものだけをロードすることで、メモリ使用量を最小限に抑える。
|
|
116
|
+
|
|
117
|
+
## 結果の詳細
|
|
118
|
+
|
|
119
|
+
### 1 — 避けるべきソリューション
|
|
120
|
+
|
|
121
|
+
`gt-react`や`lingo.dev`のようなソリューションは、明らかに避けるべきものです。これらはベンダーロックインを伴い、コードベースを汚染します。さらに悪いことに、実装に何時間も費やしたにもかかわらず、Next.jsと同様にTanStack Startでも正しく動作させることはできませんでした。
|
|
122
|
+
|
|
123
|
+
遭遇した問題:
|
|
124
|
+
|
|
125
|
+
**(General Translation)** (`gt-react@latest`):
|
|
126
|
+
|
|
127
|
+
- 約110kbのアプリに対して、`gt-react`は440kb以上の余分なデータを追加することがあります(同ベンチマークのNext.js実装で見られた規模)。
|
|
128
|
+
- General Translationを使用した最初のビルドで「Quota Exceeded, please upgrade your plan(クォータ超過、プランをアップグレードしてください)」と表示されました。
|
|
129
|
+
- 翻訳がレンダリングされません。`Error: <T> used on the client-side outside of <GTProvider>`というエラーが発生しましたが、これはライブラリのバグのようです。
|
|
130
|
+
- **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時間以内に修正しました。
|
|
131
|
+
- これらのライブラリは、`initializeGT()`関数を通じてアンチパターンを使用しており、バンドルがクリーンにツリーシェイキングされるのを妨げています。
|
|
132
|
+
|
|
133
|
+
**(Lingo.dev)** (`lingo.dev@0.133.9`):
|
|
134
|
+
|
|
135
|
+
- AIのクォータを超過(またはサーバー依存関係のブロック)し、支払いをしない限りビルドやプロダクションへのデプロイがリスクとなります。
|
|
136
|
+
- コンパイラが翻訳コンテンツの約40%を認識していませんでした。動作させるために、すべての`.map`をフラットなコンポーネントブロックに書き換える必要がありました。
|
|
137
|
+
- CLIにバグがあり、理由もなく設定ファイルをリセットすることがありました。
|
|
138
|
+
- ビルド時に、新しいコンテンツが追加されると生成されたJSONを完全に消去してしまいました。結果として、数個のキーのために既存の何百ものキーが消失することがありました。
|
|
139
|
+
- TanStack Startでの反応性に問題がありました。ロケール変更時にプロバイダーの強制的な再レンダリングが必要でした。
|
|
140
|
+
|
|
141
|
+
### 2 — 実験的なソリューション
|
|
142
|
+
|
|
143
|
+
**(Wuchale)** (`wuchale@0.22.11`):
|
|
144
|
+
|
|
145
|
+
`Wuchale`の背後にあるアイデアは興味深いものですが、まだ実用的ではありません。反応性の問題に遭遇し、TanStack Startでアプリを動作させるためにプロバイダーの強制的な再レンダリングが必要でした。ドキュメントもかなり不明瞭で、導入のハードルが高いです。
|
|
146
|
+
|
|
147
|
+
### 3 — 許容できるソリューション
|
|
148
|
+
|
|
149
|
+
**(Paraglide)** (`@inlang/paraglide-js@2.15.1`):
|
|
150
|
+
|
|
151
|
+
`Paraglide`は革新的でよく考えられたアプローチを提供しています。それにもかかわらず、このベンチマークでは、Next.jsの実装やTanStack Startにおいて、彼らが宣伝していたツリーシェイキングは機能しませんでした。ワークフローとDXも他の選択肢より複雑です。個人的には、プッシュのたびにJSファイルを再生成しなければならないのが好きではありません。これはPRを通じて常にマージ競合のリスクを生み出します。
|
|
152
|
+
|
|
153
|
+
**(Tolgee)** (`tolgee@7.0.0`):
|
|
154
|
+
|
|
155
|
+
`Tolgee`は前述の問題の多くに対処しています。しかし、同様のアプローチを持つ他のツールよりも導入が難しいと感じました。型安全性が提供されていないため、コンパイル時に紛失したキーを見つけることが非常に困難です。キーの不備を検出するために、TolgeeのAPIを自前のAPIでラップする必要がありました。
|
|
156
|
+
|
|
157
|
+
TanStack Startでは反応性の問題もありました。ロケール変更時にプロバイダーを強制的に再レンダリングし、ロケール変更イベントを購読して、別の言語でのロードが正しく動作するようにする必要がありました。
|
|
158
|
+
|
|
159
|
+
**(use-intl)** (`use-intl@4.9.1`):
|
|
160
|
+
|
|
161
|
+
`use-intl`は、Reactエコシステムにおける最もファッショナブルな「intl」の一部であり(`next-intl`と同じファミリー)、AIエージェントによって頻繁に推奨されますが、パフォーマンス重視の設定においては間違いであるというのが私の見解です。導入は比較的簡単です。しかし実際には、リークを最適化し制限するプロセスは非常に複雑です。同様に、動的ロード、ネームスぺーシング、TypeScriptの型を組み合わせると、開発が著しく遅くなります。
|
|
162
|
+
|
|
163
|
+
TanStack Startでは、Next.js特有の罠(`setRequestLocale`、静的レンダリング)は回避できますが、根本的な問題は同じです。厳格な規律がなければ、バンドルはすぐに大量のメッセージを抱え込み、ルートごとのネームスペースの維持は苦痛になります。
|
|
164
|
+
|
|
165
|
+
**(react-i18next)** (`react-i18next@17.0.2`):
|
|
166
|
+
|
|
167
|
+
`react-i18next`は、JavaScriptアプリのi18nニーズに応えた初期のソリューションの一つであったため、おそらく最も人気のある選択肢です。特定の課題に対するコミュニティプラグインも豊富です。
|
|
168
|
+
|
|
169
|
+
それでも、`t('a.b.c')`上に構築されたスタックと同じ大きな欠点を共有しています。最適化は可能ですが非常に時間がかかり、大規模プロジェクトでは悪い習慣(ネームスペース、動的ロード、型)に陥るリスクがあります。
|
|
170
|
+
|
|
171
|
+
メッセージ形式も異なります。`use-intl`はICU MessageFormatを使用しますが、`i18next`は独自の形式を使用しており、これらを混ぜるとツールや移行が複雑になります。
|
|
172
|
+
|
|
173
|
+
**(Lingui)** (`@lingui/core@5.3.0`):
|
|
174
|
+
|
|
175
|
+
`Lingui`はしばしば賞賛されます。個人的には、`lingui extract` / `lingui compile`を巡るワークフローが他のアプローチよりも複雑で、このTanStack Startベンチマークにおいて明確な利点が見出せませんでした。また、AIを混乱させる一貫性のない構文(例:`t()`、`t''`、`i18n.t()`、`<Trans>`)も見受けられました。
|
|
176
|
+
|
|
177
|
+
**(react-intl)** (`react-intl@10.1.1`):
|
|
178
|
+
|
|
179
|
+
`react-intl`は、Format.jsチームによるパフォーマンス重視の実装です。DXは冗長なままです。`const intl = useIntl()` + `intl.formatMessage({ id: "xx.xx" })`は複雑さを増し、JavaScriptの余分な作業を増やし、グローバルなi18nインスタンスをReactツリーの多くのノードに結びつけます。
|
|
180
|
+
|
|
181
|
+
### 4 — 推奨事項
|
|
182
|
+
|
|
183
|
+
このTanStack Startベンチマークには、`next-translate`(Next.jsプラグイン + `getStaticProps`)に直接相当するものはありません。成熟したエコシステムと`t()` APIを切望するチームにとって、`react-i18next`や`use-intl`は「妥当な」選択肢であり続けますが、リークを回避するための最適化には多くの時間を投資することを覚悟してください。
|
|
184
|
+
|
|
185
|
+
**(Intlayer)** (`react-intlayer@8.7.5-canary.0`):
|
|
186
|
+
|
|
187
|
+
客観性を保つため、自分自身のソリューションである`react-intlayer`については個人的な判断を控えさせていただきます。
|
|
188
|
+
|
|
189
|
+
### 個人的なメモ
|
|
190
|
+
|
|
191
|
+
このメモは個人的なものであり、ベンチマークの結果には影響しません。それでも、i18nの世界では、翻訳されたコンテンツに対して`const t = useTranslation('xx')` + `<>{t('xx.xx')}</>`のようなパターンが合意事項としてよく見られます。
|
|
192
|
+
|
|
193
|
+
Reactアプリにおいて、関数を`ReactNode`として注入することは、私の考えではアンチパターンです。また、避けられるはずの複雑さとJavaScriptの実行オーバーヘッド(たとえ微々たるものであっても)を付加することになります。
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-04-20
|
|
3
|
+
updatedAt: 2026-04-20
|
|
4
|
+
title: i18n 라이브러리 벤치마크
|
|
5
|
+
description: Intlayer 가 성능 및 번들 크기 측면에서 다른 i18n 라이브러리와 어떻게 비교되는지 알아보세요.
|
|
6
|
+
keywords:
|
|
7
|
+
- benchmark
|
|
8
|
+
- i18n
|
|
9
|
+
- intl
|
|
10
|
+
- nextjs
|
|
11
|
+
- tanstack
|
|
12
|
+
- intlayer
|
|
13
|
+
slugs:
|
|
14
|
+
- doc
|
|
15
|
+
- benchmark
|
|
16
|
+
history:
|
|
17
|
+
- version: 8.7.5
|
|
18
|
+
date: 2026-01-06
|
|
19
|
+
changes: "벤치마크 초기화"
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# Benchmark - 리포트
|
|
23
|
+
|
|
24
|
+
Benchmark Bloom은 여러 React 프레임워크와 로딩 전략에서 i18n(국제화) 라이브러리가 실제로 미치는 영향을 측정하는 성능 벤치마크 모음입니다.
|
|
25
|
+
|
|
26
|
+
각 프레임워크에 대한 상세 리포트와 기술 문서는 아래에서 확인할 수 있습니다.
|
|
27
|
+
|
|
28
|
+
- [**Next.js 벤치마크 리포트**](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ko/benchmark/nextjs.md)
|
|
29
|
+
- [**TanStack Start 벤치마크 리포트**](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ko/benchmark/tanstack.md)
|