---
createdAt: 2026-04-20
updatedAt: 2026-05-18
title: 2026年におけるNext.jsの最適なi18nソリューション - ベンチマークレポート
description: next-intl、next-i18next、IntlayerなどのNext.js国際化（i18n）ライブラリを比較。バンドルサイズ、リーク、反応性に関する詳細なパフォーマンスレポート。
keywords:
  - benchmark
  - i18n
  - intl
  - nextjs
  - パフォーマンス
  - intlayer
slugs:
  - doc
  - benchmark
  - nextjs
author: Aymeric PINEAU
applicationTemplate: https://github.com/intlayer-org/benchmark-i18n
history:
  - version: 8.9.8
    date: 2026-05-18
    changes: "GitHub スター比較を追加"
  - version: 8.7.5
    date: 2026-01-06
    changes: "ベンチマーク初期化"
---

# Next.js i18nライブラリ - 2026年ベンチマークレポート

このページは、Next.jsにおけるi18nソリューションのベンチマークレポートです。

## 目次

<Toc/>

## インタラクティブベンチマーク

<I18nBenchmark framework="nextjs" vertical/>

## 結果のリファレンス:

<ClickToOpenIframe
src="https://intlayer.org/markdown?url=https%3A%2F%2Fraw.githubusercontent.com%2Fintlayer-org%2Fbenchmark-i18n%2Fmain%2Freport%2Fscripts%2Fsummarize-nextjs.md"
width="100%"
height="600px"
style="border:none;"
/>

> [完全なベンチマークデータを見る](https://intlayer.org/markdown?url=https%3A%2F%2Fraw.githubusercontent.com%2Fintlayer-org%2Fbenchmark-i18n%2Fmain%2Freport%2Fscripts%2Fsummarize-nextjs.md)

ベンチマークのリポジトリ全体は[こちら](https://github.com/intlayer-org/benchmark-i18n)でご確認いただけます。

## はじめに

国際化ライブラリはアプリケーションに大きな影響を与えます。主なリスクは、ユーザーが1ページしか閲覧しないにもかかわらず、すべてのページとすべての言語のコンテンツをロードしてしまうことです。

アプリが成長するにつれて、バンドルサイズが指数関数的に増大し、パフォーマンスが著しく低下する可能性があります。

最悪のケースでは、国際化によってページサイズが4倍近くに膨れ上がることがあります。

また、i18nライブラリのもう一つの影響として、開発の遅延が挙げられます。コンポーネントを多言語対応に作り変える作業は時間がかかります。

この問題の解決は難しいため、DX（開発体験）にフォーカスしたもの、パフォーマンスやスケーラビリティにフォーカスしたものなど、さまざまなソリューションが存在します。

Intlayerは、これらの各側面において最適化を試みています。

## TL;DR

- **Intlayer** & **next-translate**: Next.jsのパフォーマンスにおいて最適な選択肢。最小のフットプリントと最高の静的レンダリングサポートを提供。
- **next-intl**: 最もトレンドのオプションだが、大規模なアプリケーション向けに最適化するには重く、複雑。
- **next-i18next**: 人気がありプラグインも豊富だが、バンドル重量が非常に大きい（Intlayer의約3倍）。
- **避けるべき**: **gt-next** と **lingo.dev**。深刻なパフォーマンスの問題、ベンダーロックイン、ビルドを破壊するバグのため。

## アプリをテストする

これらの問題を顕在化させるために、無料のスキャナーを作成しました。[こちら](https://intlayer.org/i18n-seo-scanner)で試すことができます。

<ClickToOpenIframe src="https://intlayer.org/i18n-seo-scanner" width="100%" height="600px" style="border:none;"/>

## 問題点

多言語アプリがバンドルサイズに与える影響を制限するには、主に2つの方法があります。

- JSON（またはコンテンツ）をファイル、変数、ネームスペースごとに分割し、特定のページで使用されないコンテンツをバンドラーがツリーシェイキングできるようにする。
- ページのコンテンツをユーザーの使用言語のみ動的にロードする。

これらのアプローチの技術的な制限：

**動的ロード**

WebpackやTurbopackを使用し、`[locale]/page.tsx`のようなルートを宣言したり、`generateStaticParams`を定義したりしたとしても、バンドラーは`locale`を静的な定数として扱いません。つまり、すべての言語のコンテンツが各ページに引き込まれる可能性があります。これを制限する主な方法は、動的インポート（例：`import('./locales/${locale}.json')`）を介してコンテンツをロードすることです。

ビルド時に何が起こるかというと、Next.jsはロケールごとに1つのJSバンドルを生成します（例：`./locales_fr_12345.js`）。サイトがクライアントに送信され、ページが実行されると、ブラウザは必要なJSファイル（例：`./locales_fr_12345.js`）に対して追加のHTTPリクエストを実行します。

> 同じ問題を解決する別の方法は、`fetch()`を使用してJSONを動的にロードすることです。これは、JSONが`/public`の下にある場合の`Tolgee`や、コンテンツのロードに`getStaticProps`を使用する`next-translate`の仕組みです。流れは同じで、ブラウザがアセットをロードするために追加のHTTPリクエストを行います。

**コンテンツの分割**

`const t = useTranslation()` + `t('my-object.my-sub-object.my-key')`のような構文を使用する場合、通常、ライブラリがキーを解析して解決できるように、JSON全体がバンドルに含まれている必要があります。そのため、ページで使用されていないコンテンツの多くが同梱されてしまいます。

これを軽減するために、一部のライブラリ（`next-i18next`、`next-intl`、`lingui`、`next-translate`、`next-international`など）では、ページごとにロードするネームスペースを宣言する必要があります。

対照的に、`Paraglide`はビルド前にJSONを`const en_my_var = () => 'my value'`のようなフラットなシンボルに変換するステップを追加します。理論的には、これによりページ上の未使用コンテンツをツリーシェイキングできるようになります。しかし、後述するように、この方法にもトレードオフがあります。

最終的に、`Intlayer`はビルド時の最適化を適用し、`useIntlayer('my-key')`が対応するコンテンツに直接置き換えられるようにします。

## 調査方法

このベンチマークでは、以下のライブラリを比較しました。

- `Base App`（i18nライブラリなし）
- `next-intlayer` (v8.7.12)
- `next-i18next` (v16.0.5)
- `next-intl` (v4.9.1)
- `@lingui/core` (v5.3.0)
- `next-translate` (v3.1.2)
- `next-international` (v1.3.1)
- `@inlang/paraglide-js` (v2.15.1)
- `@tolgee/react` (v7.0.0)
- `@lingo.dev/compiler` (v0.4.0)
- `wuchale` (v0.22.11)
- `gt-next` (v6.16.5)

Next.jsのバージョンは`16.2.4`（App Router）を使用しました。

**10ページ**と**10言語**を持つ多言語アプリを作成しました。

**4つのロード戦略**を比較しました。

| 戦略           | ネームスペースなし（グローバル）                | ネームスペースあり（スコープ指定）                                   |
| :------------- | :---------------------------------------------- | :------------------------------------------------------------------- |
| **静的ロード** | **Static**: 起動時にすべてをメモリ上に。        | **Scoped static**: ネームスペースで分割。起動時にすべてロード。      |
| **動的ロード** | **Dynamic**: ロケールごとのオンデマンドロード。 | **Scoped dynamic**: ネームスペースとロケールごとのきめ細かなロード。 |

## 戦略の構成

- **Static**: シンプル。初回ロード後のネットワーク遅延がない。短所：バンドルサイズが大きい。
- **Dynamic**: 初回の重さを軽減（遅延ロード）。ロケールが多い場合に理想的。
- **Scoped static**: 複雑な追加ネットワークリクエストなしで、コードを整理（論理的な分離）できる。
- **Scoped dynamic**: コード分割とパフォーマンスにおいて最良のアプローチ。現在のビューとアクティブなロケールが必要なものだけをロードすることで、メモリ使用量を最小限に抑える。

### 測定対象:

各スタックにおいて、実際のブラウザで同じ多言語アプリを実行し、実際に何が送出され、どのくらいの時間がかかったかを記録しました。サイズは、生のソースコードのカウントよりも実際のダウンロード量に近いため、**一般的なWeb圧縮後**の値を報告しています。

- **国際化ライブラリのサイズ**: バンドル、ツリーシェイキング、および圧縮後のi18nライブラリのサイズです。中身が空のコンポーネントにおけるプロバイダー（例：`NextIntlClientProvider`）とフック（例：`useTranslations`）のコードのサイズを指します。これには翻訳ファイルのロードは含まれません。コンテンツが入る前にライブラリ自体がどれだけコスト高であるかを示します。

- **ページごとのJavaScript量**: 各ベンチマークルートにおいて、ブラウザがその訪問で引き込むスクリプトの量です。スイート内のページ全体（およびレポートで集計されている場合はロケール全体）の平均値です。重いページは遅いページです。

- **他のロケールからのリーク**: 同じページの他の言語のコンテンツが、誤って対象ページにロードされてしまうことです。このコンテンツは不要であり、回避されるべきです（例：`/en/about`ページのバンドルに含まれる`/fr/about`ページのコンテンツ）。

- **他のルートからのリーク**: アプリ内の**他の画面**についても同様です。1ページしか開いていないのに、他のページのコピーが紛れ込んでいないかを測定します（例：`/en/contact`ページのバンドルに含まれる`/en/about`ページのコンテンツ）。スコアが高い場合は、分割が不十分であるか、バンドルが広範囲すぎることを示しています。

- **コンポーネントの平均バンドルサイズ**: 一般的なUIパーツをアプリ全体の巨大な数値に隠すのではなく、**一つずつ**測定します。これにより、国際化が日常的なコンポーネントをひっそりと膨らませていないかを確認できます。たとえば、コンポーネントが再レンダリングされると、それらすべてのデータをメモリからロードすることになります。コンポーネントに巨大なJSONを添付することは、未使用データの大きな蓄積を接続するようなもので、コンポーネントのパフォーマンスを低下させます。

- **言語切り替えの反応性**: アプリ自身のコントロールを使用して言語を切り替え、ページが明確に切り替わるまでにかかる時間を測定します。ラボ内での微細なステップではなく、訪問者が気づく時間を対象としています。

- **言語変更後のレンダリング作業**: 切り替えが進行し始めてから、新しい言語でのインターフェースの再描画にかかった労力の追跡調査です。「体感」時間とフレームワークのコストが乖離している場合に有用です。

- **初回ページロード時間**: ナビゲーションから、テストシナリオにおいてブラウザがページを完全にロードしたと判断するまでの時間です。コールドスタートの比較に適しています。

- **ハイドレーション時間**: アプリが表示している場合、クライアントがサーバーのHTMLを実際にクリックできるものに変換するのにかかる時間です。表内のダッシュ（-）は、その実装がこのベンチマークで信頼できるハイドレーション数値を提供しなかったことを意味します。

## GitHubのスター

GitHubのスターは、プロジェクトの普及度、コミュニティの信頼、および長期的な関連性を示す強力な指標です。技術的な品質を直接測定するものではありませんが、どれだけの開発者がプロジェクトを有用だと感じ、その進捗をフォローし、採用する可能性があるかを反映しています。プロジェクトの価値を見積もる際、スターは代替案との勢いの比較を助け、エコシステムの成長に関する洞察を提供します。

[![Star History Chart](https://api.star-history.com/chart?repos=i18next%2Fnext-i18next%2Camannn%2Fnext-intl%2Clingui%2Fjs-lingui%2Cvinissimus%2Fnext-translate%2Cinostudio%2Fnext-international%2Copral%2paraglide-js%2Ctolgee%2Ftolgee-js%2Caymericzip%2Fintlayer&type=date&legend=top-left)](https://www.star-history.com/#i18next/next-i18next&amannn/next-intl&lingui/js-lingui&vinissimus/next-translate&inostudio/next-international&opral/paraglide-js&tolgee/tolgee-js&aymericzip/intlayer)

## 結果の詳細

### 1 - 避けるべきソリューション

`gt-next`や`lingo.dev`のようなソリューションは、明らかに避けるのが賢明です。これらはベンダーロックインを伴い、コードベースを汚染します。実装に何時間も費やしたにもかかわらず、TanStack StartでもNext.jsでも、正しく動作させることはできませんでした。

遭遇した問題：

**(General Translation)** (`gt-next@6.16.5`):

- 110kbのアプリに対して、`gt-next`は440kb以上の余分なデータを追加します。
- General Translationを使用した最初のビルドで「Quota Exceeded, please upgrade your plan（クォータ超過、プランをアップグレードしてください）」と表示されました。
- 翻訳がレンダリングされません。`Error: <T> used on the client-side outside of <GTProvider>`というエラーが発生しましたが、これはライブラリのバグのようです。
- **gt-next**を実装中、ライブラリの[問題](https://github.com/generaltranslation/gt/issues/1210#event-24510646961)にも遭遇しました。`does not provide an export named 'printAST' - @formatjs/icu-messageformat-parser`というエラーでアプリケーションが壊れました。この問題を報告した後、メンテナは24時間以内に修正しました。
- このライブラリはNext.jsページの静的レンダリングをブロックします。

**(Lingo.dev)** (`@lingo.dev/compiler@0.4.0`):

- AIのクォータを超過し、ビルドが完全にブロックされました。つまり、支払いをしない限りプロダクションへのデプロイができません。
- コンパイラが翻訳コンテンツの約40%を認識していませんでした。動作させるために、すべての`.map`をフラットなコンポーネントブロックに書き換える必要がありました。
- CLIにバグがあり、理由もなく設定ファイルをリセットすることがありました。
- ビルド時に、新しいコンテンツが追加されると生成されたJSONを完全に消去してしまいました。結果として、数個のキーのために既存の300個以上のキーが消失することがありました。

### 2 - 実験的なソリューション

**(Wuchale)** (`wuchale@0.22.11`):

`Wuchale`の背後にあるアイデアは興味深いものですが、まだ実用的ではありません。反応性の問題に遭遇し、アプリを動作させるためにプロバイダーの強制的な再レンダリングが必要でした。ドキュメントもかなり不明瞭で、導入のハードルが高いです。

**(Paraglide)** (`@inlang/paraglide-js@2.15.1`):

`Paraglide`は革新的でよく考えられたアプローチを提供しています。それにもかかわらず、このベンチマークでは、Next.jsやTanStack Startの設定において、宣伝されていたツリーシェイキングは機能しませんでした。ワークフローとDXは他の選択肢よりも複雑です。
個人的には、プッシュのたびにJSファイルを再生成しなければならないのが嫌いです。これはPRを通じて常にマージ競合のリスクを生み出します。また、このツールはNext.jsよりもViteにフォーカスしているように見えます。
最後に、他のソリューションと比較して、Paraglideはコンテンツをレンダリングするために現在のロケールを取得するためのストア（例：Reactコンテキスト）を使用しません。パースされる各ノードについて、localStorageやクッキーなどからロケールをリクエストします。これにより、コンポーネントの反応性に影響を与える不要なロジックが実行されます。

> paraglideについての注意：このソリューションは、インポートのためにコードベースにコードを注入します。その結果、ベンチマークレポートの「ライブラリサイズ」指標はほぼ0になります。コード生成は良いことです。なぜなら、使用される関数には必要なロジック（すべてのプレフィックス対プレフィックスなし、クッキー対ストレージなど）のみが含まれるからです。対照的に、Intlayerはビルド時に環境変数を注入して、ロジックに応じてコンテンツをツリーシェイキングするようバンドラーに強制します。このおかげで、paraglideとintlayerは、i18nextやnext-intlよりも6〜10倍軽量なソリューションとなっています。

### 3 - 許容できるソリューション

**(Tolgee)** (`@tolgee/react@7.0.0`):

`Tolgee`は前述の問題の多くに対処しています。しかし、同様のツールよりも導入が難しいと感じました。型安全性が提供されていないため、コンパイル時に紛失したキーを見つけることも困難です。キーの不備を検出するために、Tolgeeの関数を自前の関数でラップする必要がありました。

**(Next Intl)** (`next-intl@4.9.1`):

`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`のようにネームスペースに分割されている場合、依然として静的レンダリングが壊れます。

**(Next I18next)** (`next-i18next@16.0.5`):

`next-i18next`は、JavaScriptアプリにおける最初期のi18nソリューションの一つであったため、おそらく最も人気のある選択肢です。多くのコミュニティプラグインがあります。これには`next-intl`と同じ大きな欠点があります。パッケージが非常に重いです（`I18nProvider` + `useTranslation`で約18kb、`next-intlayer`の約3倍）。

メッセージ形式も異なります。`next-intl`はICU MessageFormatを使用しますが、`i18next`は独自の形式を使用します。

**(Next International)** (`next-international@1.3.1`):

`next-international`も上記の問題に取り組んでいますが、`next-intl`や`next-i18next`と大きな違いはありません。ネームスペース固有の翻訳のために`scopedT()`が含まれていますが、それを使用してもバンドルサイズへの影響はほとんどありません。

**(Lingui)** (`@lingui/core@5.3.0`):

`Lingui`はしばしば賞賛されます。個人的には、`lingui extract` / `lingui compile`のワークフローが他の選択肢よりも複雑で、明確な利点が見出せませんでした。また、AIを混乱させる一貫性のない構文（例：`t()`、`t''`、`i18n.t()`、`<Trans>`）も見受けられました。

### 4 - 推奨事項

**(Next Translate)** (`next-translate@3.1.2`):

`t()`スタイルのAPIがお好みなら、`next-translate`が私の主な推奨事項です。`next-translate-plugin`を介して優雅に動作し、Webpack / Turbopackローダーを使用して`getStaticProps`経由でネームスペースをロードします。また、今回の中で最も軽量な選択肢です（約2.5kb）。ネームスぺーシングについては、設定ファイルでページやルートごとにネームスペースを定義する方法がよく考えられており、**next-intl**や**next-i18next**のような主要な選択肢よりもメンテナンスが容易です。バージョン`3.1.2`では、静的レンダリングが機能せず、Next.jsが動的レンダリングにフォールバックすることに気づきました。

**(Intlayer)** (`next-intlayer@8.7.12`):

客観性を保つため、自分自身のソリューションである`next-intlayer`については個人的な判断を控えさせていただきます。

### 個人的なメモ

このメモは個人的なものであり、ベンチマークの結果には影響しません。i18nの世界では、`const t = useTranslation('xx')` + `<>{t('xx.xx')}</>`のようなパターンが合意事項としてよく見られます。

Reactアプリにおいて、関数を`ReactNode`として注入することは、私の考えではアンチパターンです。また、避けられるはずの複雑さとJavaScriptの実行オーバーヘッド（たとえ微々たるものであっても）を付加することになります。
