このページとあなたの好きなAIアシスタントを使ってドキュメントを要約します
このページのコンテンツはAIを使用して翻訳されました。
英語の元のコンテンツの最新バージョンを見るこのドキュメントを改善するアイデアがある場合は、GitHubでプルリクエストを送信することで自由に貢献してください。
ドキュメントへのGitHubリンクドキュメントのMarkdownをクリップボードにコピー
next-intl VS Intlayer | Next.js 国際化 (i18n) ベンチマーク
next-intlはNext.jsで最も人気のあるi18nライブラリです。Intlayerはコンパイラベース、コンポーネントスコープの代替案です。どちらもApp Routerアプリケーションをローカライズします。問題は、アプリがビルドされた後、それぞれがどの程度のコストがかかるかということです。
この記事はチュートリアルではありません。Benchmark Bloomからの数値に基づいた比較です。Benchmark Bloomはオープンソースのベンチマークスイートで、各ライブラリで同じアプリケーションをビルドし、ブラウザが実際にダウンロードして実行するものを測定します。
tl;dr: 同じ Next.js アプリケーションで、next-intlは全ページで +12.6 KB gzip の JavaScript を追加しますが、Intlayer は +0.3 KB です。追加の作業なしで、next-intlは全ページで ~90% の外国語ページ文字列 を配信します。next-intlで 0% のリークを達成するには、namespace スコープと per-pagepick(messages, [...])が必要です。Intlayer はデフォルトで 0% に達します。なぜなら、そのコンパイラがコンテンツをコンポーネント単位でスコープするからです。next-intlAPI を Intlayer の出力で使いたい場合、@intlayer/next-intlアダプタは 1 ページあたり 147.5 KB と測定されたのに対し、元のものは 153.6 KB です。
要するに
- next-intl - 軽量でドキュメントが充実しており、ICU message format、App Router への first-class なサポート、middleware、formatters、navigation helpers を備えています。コンテンツは集中管理された JSON カタログに保存され、パフォーマンス最適化(namespaces、ページごとのメッセージ picking、lazy loading)はあなたの責任です。
- Intlayer - コンポーネント中心のコンテンツモデル。
.content.tsdictionaries はそれが提供するコンポーネントの隣に配置され、build-time compiler がコンポーネントごと、locale ごとに tree-shake と lazy-load を行い、厳密な TypeScript 型がコンテンツから生成され、翻訳漏れは build 時に失敗します。middleware、SEO helpers、Visual Editor / CMS、AI 支援翻訳機能を搭載しています。
テーブルをモーダルで開き、すべてのデータを明確に表示
バッジは自動的に更新されます。スナップショットは時間とともに変わります。
機能比較
テーブルをモーダルで開き、すべてのデータを明確に表示
| 機能 | next-intlayer (Intlayer) | next-intl |
|---|---|---|
| コンポーネント近くの翻訳 | ✅ はい、各コンポーネントに並置された .content.ts | ❌ いいえ、集中管理された messages/{locale}.json |
| TypeScript統合 | ✅ コンテンツから自動生成された厳密な型 | ✅ 良好、global.d.ts 拡張機能を使用してキーに型を付ける |
| 翻訳不足の検出 | ✅ TypeScriptエラー + ビルド時エラー/警告 | ⚠️ ランタイム フォールバック + コンソール警告 |
| リッチコンテンツ (JSX / Markdown / components) | ✅ 直接サポート | ⚠️ t.rich() / t.markup() タグプレースホルダー付き |
| ICU サポート | ⚠️ WIP | ✅ Yes |
| フォーマット (日付、数値、通貨) | ✅ useNumber, useDate, ... (内部的に Intl を使用) | ✅ useFormatter() (内部的に Intl を使用) |
| ローカライズされたルーティング & ミドルウェア | ✅ ビルトイン proxy/middleware、getMultilingualUrls | ✅ ビルトイン middleware、Link、redirect、usePathname |
| SEO ヘルパー (hreflang、sitemap、robots) | ✅ ビルトイン ヘルパー | ⚠️ 手動、ルーティング設定に基づく |
| 同期サーバーコンポーネント | ✅ next-intlayer/server の useIntlayer は任意の子サーバーコンポーネントで動作 | ⚠️ getTranslations は非同期; 同期子は t をプロップとして渡す必要がある |
| 静的レンダリング | ✅ 静的レンダリングをブロックしない | ⚠️ setRequestLocale() が必須; 名前空間付きカタログは、当社のテストでもページを静的レンダリングから除外する |
| Tree-shaking (使用済みコンテンツのみをシップ) | ✅ コンポーネントごと、ロケールごと、コンパイラによって自動化 | ⚠️ 手動: 名前空間 + ページごとの pick(messages, [...]) |
| 遅延読み込み | ✅ importMode: 'dynamic' (設定1行) | ⚠️ 手動: getRequestConfig での動的インポート |
| 未使用コンテンツの削除 | ✅ デッドな辞書はビルド時にドロップされます | ❌ 組み込みではありません |
| 翻訳の欠落をテスト (CLI / CI) | ✅ npx intlayer content test | ⚠️ 組み込みではありません; ドキュメントは npx @lingual/i18n-check を示唆しています |
| AI による翻訳 | ✅ 組み込み、独自のプロバイダーキーを使用します | ❌ いいえ |
| ビジュアルエディタ / CMS | ✅ 無料ビジュアルエディタ + オプションCMS | ❌ いいえ (外部ローカライゼーションプラットフォーム) |
| MCPサーバー & エージェントスキル | ✅ はい | ❌ いいえ |
| エコシステム / コミュニティ | ⚠️ より小規模だが急速に成長中 | ✅ 大規模、Next.jsの参照実装 |
ベンチマーク
測定内容
Benchmark Bloom スイートは、各ライブラリで同じアプリケーションをビルドします:10ページ(ホーム、アバウト、ブログ、キャリア、コンタクト、FAQ、プライシング、プロダクト、設定、チーム)、10ロケール(en、fr、es、de、it、pt、zh、ja、ko、ru)、同一のコンポーネントと同一のコンテンツ。ページはenとfrで測定されます。各ライブラリは、最も単純なセットアップから最適なセットアップまで、最大4つのロード戦略で実装されています:
テーブルをモーダルで開き、すべてのデータを明確に表示
| 戦略 | 説明 | これを行うのは |
|---|---|---|
| static | すべてのlocaleとすべてのページが一緒にバンドルされている | クイックプロトタイプ、AI生成コード |
| dynamic | アクティブなlocaleのみがロードされるが、すべてのページが一度にロードされる | ほとんどのプロジェクト |
| scoped-static | ルートごとのnamespaces、lazy loadingなし | まれ |
| scoped-dynamic | ルートごとのnamespaces + lazy loading。現在のページの現在のlocaleのみが送信される | 厳密なパフォーマンス予算を持つアプリ |
Intlayerには「scoped」バリアントがありません。compilerはコンテンツをコンポーネントごとに自動的にスコープするため、そのstaticとdynamicの行はすでにスコープされています。
各ビルドについて、スイートは以下を記録します:
- Lib size: i18n ライブラリのみをインポートする空のコンポーネントの gzip サイズ。ランタイムの固定コスト。
- Page JS: ページごとにダウンロードされた gzip JavaScript。すべてのページとロケール全体で平均化されます。
- Locale leak %: ダウンロードされた JS に含まれる翻訳文字列のうち、ユーザーが閲覧していないロケールに属する割合(
enとfrでフィンガープリント化されているため、50% は「他の測定されたロケールが完全に存在する」を意味します。10 個のロケールがバンドルされている場合、実際の無駄はさらに大きくなります)。 - Page leak %: ダウンロードされた JS に含まれる翻訳文字列のうち、ユーザーがいないページに属する割合。
- Component avg: 分離してコンパイルされた各コンポーネントの平均 gzip サイズ。単一のコンポーネントが i18n ランタイムをどの程度ドラッグインするかを示します。
- E2E reactivity: 新しいlocaleを選択してから、DOM内の
html[lang]が更新されるまでの実際の経過時間(Playwright、5回の反復)。 - Hydration: Reactのhydrationフェーズの継続時間。
以下の数字は、next-intl4.14.2、use-intl4.14.2、intlayer9.5.1を使用した2026-09-12実行日のものです。テストアプリケーションは意図的に小規模(locale あたり数十個の文字列)であるため、漏洩パーセンテージはパターンを説明します:コンテンツが増えるにつれて増加し、ランタイムコストは固定されたままです。
Next.js(App Router)の結果
テーブルをモーダルで開き、すべてのデータを明確に表示
| Library | Strategy | Lib size (gz) | Page JS avg (gz) | Locale leak | Page leak | Component avg (gz) | E2E reactivity | Hydration |
|---|---|---|---|---|---|---|---|---|
| base (i18n なし) | - | 0.0 KB | 141.0 KB | 0.0% | 0.0% | 0.9 KB | 13.4 ms | 11.8 ms |
next-intl | static | 14.7 KB | 153.6 KB | 4.2% | 89.8% | 21.8 KB | 16.0 ms | 14.7 ms |
next-intl | dynamic | 14.7 KB | 153.6 KB | 9.7% | 89.9% | 21.8 KB | 15.6 ms | 14.8 ms |
next-intl | scoped-static | 14.7 KB | 153.6 KB | 0.0% | 0.0% | 80.1 KB | 17.9 ms | 17.4 ms |
next-intl | scoped-dynamic | 14.7 KB | 153.6 KB | 0.0% | 0.0% | 22.9 KB | 17.8 ms | 16.8 ms |
next-intlayer | static | 5.5 KB | 141.3 KB | 0.0% | 0.0% | 8.5 KB | 15.5 ms | 16.9 ms |
next-intlayer | dynamic | 5.5 KB | 141.3 KB | 0.0% | 0.0% | 6.9 KB | 15.3 ms | 15.9 ms |
@intlayer/next-intl (compat) | static | 8.0 KB | 147.5 KB | 0.0% | 0.0% | 8.1 KB | 14.5 ms | 12.8 ms |
@intlayer/next-intl (compat) | dynamic | 8.0 KB | 148.7 KB | 0.0% | 0.0% | 8.1 KB | 11.7 ms | 12.8 ms |
読み方
- ランタイムコスト。 ベースアプリケーションのサイズはページあたり 141.0 KB です。
next-intlはこれを 153.6 KB に増加させます(毎ページ +12.6 KB gzip)、Intlayer は 141.3 KB に増加させます(+0.3 KB)。このギャップは、文字列がいくつあるかに依存しません。これはライブラリランタイムです。 - Leakage. 最も一般的に使用されている2つのセットアップ(
staticとdynamic)では、next-intlはすべてのページに外国語ページの文字列の約90%を配信します。つまり、すべてのen.jsonがクライアントプロバイダーに組み込まれます。0%に達するには、scoped-*セットアップが必要です。カタログを名前空間に分割し、各ページで正しいものをpick()します。Intlayerは、そのような手段なしに両方の行で0%です。 next-intlのページごとのJSは戦略間で変わりませんでした。 テストコンテンツが小さいため、ここでは~90%のleakはわずか数KBです。実際のアプリで1ページあたり数百の文字列がある場合、その比率が主要なコストになります。一方、+12.6 KBのランタイムはすべての設定で支払われます。- コンポーネントサイズ。
useTranslations()を呼び出すコンポーネントは平均21.8 KBにコンパイルされ、useIntlayer()を使用した同じコンポーネントは6.9 KBにコンパイルされます。scoped-staticセットアップでは、各コンポーネントがそのnamespace catalogをインラインで含めるため、next-intlコンポーネントは80.1 KBにジャンプします。 - リアクティビティとhydrationは、Next.js上の両方のライブラリで同じ範囲内です(15-18 ms)。ここではどちらもボトルネックではありません。
TanStack Startでの結果(use-intl)
use-intlはnext-intlのframework-agnosticなコアです。同じAPI、同じメッセージフォーマット。TanStack Startでintlayerと比較することで、方程式からNext.js固有の部分を削除します。
テーブルをモーダルで開き、すべてのデータを明確に表示
| Library | Strategy | Lib size (gz) | Page JS avg (gz) | Locale leak | Page leak | Component avg (gz) | E2E reactivity |
|---|---|---|---|---|---|---|---|
| base (i18n なし) | - | 0.0 KB | 111.0 KB | 0.0% | 0.0% | 0.7 KB | 8.1 ms |
use-intl | static | 14.1 KB | 179.8 KB | 50.0% | 89.8% | 76.0 KB | 6.7 ms |
use-intl | dynamic | 14.1 KB | 119.4 KB | 0.0% | 89.8% | 75.9 KB | 7.0 ms |
use-intl | scoped-static | 14.1 KB | 128.7 KB | 0.0% | 0.0% | 87.1 KB | 20.9 ms |
use-intl | scoped-dynamic | 14.1 KB | 128.7 KB | 0.0% | 0.0% | 87.1 KB | 13.3 ms |
intlayer | static | 5.0 KB | 125.8 KB | 50.0% | 0.0% | 8.1 KB | 3.2 ms |
intlayer | dynamic | 5.0 KB | 118.6 KB | 0.0% | 0.0% | 6.3 KB | 3.6 ms |
@intlayer/use-intl (compat) | dynamic | 7.3 KB | 129.7 KB | 0.0% | 0.0% | 9.3 KB | 8.7 ms |
読み方
- 素朴な
use-intlセットアップは、ベースアプリより ページあたり 68.8 KB 多い JS を配信しており、文字列の半分は間違ったロケールに属し、90% は間違ったページに属しています。 use-intlのdynamicモードは119.4 KBに達し、Intlayerの118.6 KBに近いですが、それでも89.8%のページリークを抱えています:アクティブなロケールのすべてのページの文字列がすべてのページで読み込まれます。それらをルートごとにスコープする(scoped-*)リークを削除しますが、さらに約9 KBのチャンク オーバーヘッドが必要です。- Intlayerの
static行は既に0%のページリークがあります:コンパイラはページ上のコンポーネントで使用されている辞書のみをバンドルします。intlayer.config.tsで1行のimportMode: 'dynamic'を有効にすると、ロケールリークも削除されます。 - コンポーネントサイズはアーキテクチャが表れる場所です:
use-intlではコンポーネントあたり76~87 KB対Intlayerの6~8 KB。useTranslations()は各コンポーネントをグローバルメッセージツリーにバインドします。useIntlayer()はそれを独自の辞書にバインドします。 - ロケール切り替えは Intlayer で 2 倍~4 倍高速化されています(3 ms 対 7-21 ms)。
なぜギャップがあるのか?集中型カタログ vs コンパイル済み辞書
next-intl は従来のモデルに従います:ロケールごとに 1 つの JSON、getRequestConfig で読み込み、NextIntlClientProvider にプッシュされ、t("namespace.key") で読まれます。
コードをクリップボードにコピー
ランタイムはページがどのキーを使用するかを知ることができないため、安全なデフォルトはカタログ全体を送信することです。最適化するには、あなたがカタログを namespace に分割し、あなたが各ページに必要な namespace を決定し、あなたがコンポーネントが移動するにつれてそのマッピングを同期させ続ける必要があります。ベンチマークの scoped-dynamic 行はその作業の報酬であり、ほとんどのチームはそこに到達しません。
Intlayer は責任を逆転させます。コンテンツはコンポーネントの隣に宣言されます:
コードをクリップボードにコピー
ビルド時に、コンパイラ (@intlayer/swc / @intlayer/babel) はどのコンポーネントがどの辞書をインポートしているかを認識します。これらの辞書をバンドルし、アクティブなロケールのみを対象とし、何もインポートしていないものは削除されます。「scoped-dynamic」パターンは、チームが維持しなければならない規律ではなく、ビルドの出力になります。
dynamic行の数値を取得するには、intlayer.config.tsでdictionary.importMode: 'dynamic'を設定してください。bundle optimization doc を参照してください。
開発者体験
Client component
next-intl
コードをクリップボードにコピー
コードをクリップボードにコピー
このコンポーネントをレンダリングするすべてのページで、NextIntlClientProviderに渡されるメッセージにcounter名前空間を含めることを忘れないでください。
Intlayer
コードをクリップボードにコピー
コードをクリップボードにコピー
ページに登録する必要はありません。コンポーネントが独自のコンテンツを提供します。
同期サーバーコンポーネント
Design-system pieces (navbar, footer, cards) はしばしば client components の子として render される server components であるため、async にすることはできません。
next-intl
コードをクリップボードにコピー
ページは await getTranslations("counter") と await getFormatter() を実行し、その結果を props として下に渡す必要があります。コンポーネントはもはや self-contained ではありません。
Intlayer
コードをクリップボードにコピー
メタデータ
next-intl
コードをクリップボードにコピー
Intlayer
コードをクリップボードにコピー
next-intl API を維持しながら Intlayer の出力を取得する
ベンチマーク結果を得るためにコンポーネントを書き換える必要はありません。@intlayer/next-intl はドロップイン アダプターです。useTranslations、getTranslations、useFormatter、t.rich()、ICU複数形、および next-intl/navigation ヘルパーを保持し、Intlayer コンパイラでコンパイルされた Intlayer辞書から提供します。
コードをクリップボードにコピー
ベンチマークにおいて、同じアプリの互換ビルドは、アプリケーションコードに一切手を加えることなく、ページあたり 153.6 KB から 147.5 KB、コンポーネントあたり 21.8 KB から 8.1 KB、ページリークは 約90% から 0% へと改善しました。既存の messages/{locale}.json ファイルは、JSON 同期プラグイン を通じて信頼できる情報源として維持できます。
ステップバイステップの手順については、next-intl 移行ガイド を参照してください。
どちらを選ぶべきか?
- next-intl を選ぶべきケース: Next.js のエコシステム標準を重視する場合、ICU MessageFormat に依存している場合、アプリが小〜中規模の場合、または中央集権型の JSON を想定する翻訳プラットフォーム(Crowdin、Phrase、Lokalise など)と統合する場合。パフォーマンスが重要な場合は、名前空間カタログの分割やページごとのメッセージ抽出に時間を割く必要があります。
- Intlayer を選ぶべきケース: コンポーネント単位のコンテンツ、厳格な TypeScript、ビルド時のキー不足エラー検出、設定不要のツリーシェイキングと遅延読み込み、同期サーバーコンポーネント、組み込みの編集ツール(ビジュアルエディター、CMS、AI 翻訳、MCP サーバー)を求める場合。特に大規模でモジュール化されたコードベースやデザインシステムに適しています。
@intlayer/next-intlを選ぶべきケース: すでにnext-intlを使用しており、コードを書き換えることなくバンドルサイズの削減効果を得たい場合。
関連する比較
- i18next vs Intlayer (同一ベンチマーク)
- Lingui vs Intlayer (同一ベンチマーク)
- vue-i18n vs Intlayer ベンチマーク (同一ベンチマーク)
- next-i18next vs next-intl vs Intlayer
- next-intl は時代遅れか?
GitHub STARS
GitHub のスター数は、プロジェクトの人気、コミュニティの信頼、長期的な持続可能性を示す強力な指標です。技術的な品質を直接測るものではありませんが、どれだけ多くの開発者がそのプロジェクトを有用だと感じ、その進捗を追い、採用しているかを反映しています。
結論
next-intl は堅牢でよくメンテナンスされたライブラリであり、ベンチマーク結果からも Next.js における決して悪い選択肢ではないことが確認できます。しかし、中央集権型のカタログモデルは、あらゆる最適化の負担を開発者に課します。素朴な構成では他ページのコンテンツが約90%リークし、ランタイムだけでもすべてのページで +12.6 KB gzip のコストが発生します。
Intlayer はその作業をコンパイラに移行します。コンポーネントごとの辞書、ロケールごとの遅延読み込み、不要なコンテンツの削除は、慣習ではなくビルド出力です。同じアプリでの結果は、ページあたり +0.3 KB、リーク 0%、コンポーネントは 3分の1のサイズ、そして TanStack Start での言語切り替えは 2〜4倍高速 でした。
すべての生データ、テストアプリ、スクリプトは Benchmark Bloom リポジトリ で公開されています。ぜひご自身でお試しください。
詳細については、'Why Intlayer?' ドキュメント を参照してください。
コメント
まだコメントはありません。最初のコメントを共有しましょう。
