このページとあなたの好きなAIアシスタントを使ってドキュメントを要約します
このページのコンテンツはAIを使用して翻訳されました。
英語の元のコンテンツの最新バージョンを見るこのドキュメントを改善するアイデアがある場合は、GitHubでプルリクエストを送信することで自由に貢献してください。
ドキュメントへのGitHubリンクドキュメントのMarkdownをクリップボードにコピー
i18next VS @intlayer/i18next | 同じAPI、異なるバンドルサイズ
@intlayer/i18next、@intlayer/react-i18next、@intlayer/next-i18next は互換アダプターです。既存のコードが使用している i18next のAPI(useTranslation、t()、<Trans>、i18n.changeLanguage()、getFixedT、serverSideTranslations など)をそのまま公開し、Intlayerによってコンパイルされた辞書からデータを提供します。コンポーネント自体は変更されず、内部のランタイムのみが置き換わります。
本記事では、同一のNext.jsアプリケーションを next-i18next と @intlayer/next-i18next のそれぞれでビルドしてその差異を測定しました。数値は Benchmark Bloom から引用しています。ライブラリ単体としての i18next と Intlayer の比較については i18next vs Intlayer をご覧ください。本記事では、既存のコードをそのまま維持した状態でアダプターが何をもたらすかに焦点を当てます。
要約 (tl;dr): 同一のNext.jsアプリにおいて、next-i18nextを@intlayer/next-i18nextに置き換えることで、ページごとのJavaScriptサイズがgzipで 218.5 KB から 150.7 KB へ削減され(基本構成比)、完全に最適化されたnext-i18nextの構成(163.4 KB)よりもさらに 12.7 KB 小さくなりました。コンポーネントの平均サイズは 78.5 KB から 9.7 KB に激減し、他ページの文字列リークは ~90% から 0% に、ハイドレーション時間は 15.6 ms から 11.3 ms に、ランタイム自体も 19.7 KB から 9.4 KB に縮小しました。コンポーネントの書き換えは不要で、Providerファイルを1つ差し替えるだけで導入可能です。i18nextのプラグイン(バックエンド、言語検出器)は受け入れられますが何もしません。ランタイム時にロードや検出を行う必要がなくなるためです。
@intlayer/i18next とは
i18next はランタイムです。i18n.init({ resources }) やバックエンドプラグインによって locales/{lng}/{ns}.json がグローバルインスタンスに読み込まれ、useTranslation("about") でコンポーネントが購読し、t("title") がレンダリング時にキーを検索します。名前空間、遅延読み込み、ページごとの名前空間リスト、型安全性はすべて開発者が手動で構成・維持する必要があります。
互換アダプターはAPIを維持しつつ、そのインスタンスを置き換えます。
- インポートのエイリアス化。
@intlayer/next-i18next/pluginのcreateNextI18nPlugin()(またはwithI18next)がwithIntlayerをラップし、Webpack / Turbopack のエイリアスを追加することで、next-i18next、react-i18next、i18nextがそれぞれの@intlayer/*パッケージに解決されるようにします。Vite環境では@intlayer/react-i18next/pluginのreactI18nextVitePlugin()が同様の処理を行います。インポート文を変更する必要はありません。 - 信頼できる唯一の情報源としてのJSON。
syncJSONプラグインが既存のlocales/{lng}/{ns}.jsonをformat: "i18next"で読み込み({{name}}、$t()のネスト、_one/_other、コンテキストサフィックスを正常に解析)、CLIやCMSによる更新時に翻訳を書き戻します。 - コールサイト(呼び出し箇所)でのバインディング。 Intlayerの最適化パスが
useTranslation("about")を書き換え、アクティブなロケールにおけるabout辞書を直接受け取る呼び出しに変換します。これにより、コンポーネントはグローバルストアを参照しなくなります。
コードをクリップボードにコピー
コードをクリップボードにコピー
このコード書き換えこそが、後述のコンポーネントサイズ縮小やページリーク解消の原動力となっています。
アダプターが保持、無視、および代替しない機能
テーブルをモーダルで開き、すべてのデータを明確に表示
i18next API | @intlayer/* を適用した場合 |
|---|---|
useTranslation("ns"), useTranslation("ns", { keyPrefix }) | ✅ 保持。ビルド時に ns 辞書へバインドされ、コンテンツに沿って型付けされます |
t("key", { name }), {{interpolation}}, $t(key) ネスト | ✅ 保持 |
key_one / key_other 複数形、key_male コンテキスト、returnObjects | ✅ 保持。複数形は Intl.PluralRules で評価されます |
components、番号付きタグ <1>...</1>、values を持つ <Trans> | ✅ 保持 |
withTranslation, Translation, I18nContext | ✅ 保持 |
i18n.changeLanguage(), i18n.language, i18n.dir(), on("languageChanged") | ✅ 保持。changeLanguage がIntlayerのロケールを切り替えます |
getFixedT(lng, ns, keyPrefix), i18n.exists(), hasLoadedNamespace() | ✅ 保持 |
i18n.use(Backend).use(LanguageDetector).init({...}) | ⚠️ use() はプラグインの init を呼んで即終了します。読み込みや検出の対象がなくなるためです |
init({ resources }), addResourceBundle() | ⚠️ resources は警告付きで無視されます。バンドル削減の恩恵を得るためにJSONインポートを削除してください |
I18nextProvider i18n={i18n} | ⚠️ IntlayerProvider をレンダリングします。i18n プロパティは無視されます。App Routerではロケールを渡します(後述) |
serverSideTranslations(locale, ["common"]) (next-i18next) | ⚠️ 期待通りのオブジェクト構造を返しますが何も読み込みません。残しても削除しても無害です |
appWithTranslation(App) (next-i18next) | ✅ 保持 |
next-i18next.config.js | ⚠️ 読み込まれません。ロケール設定は intlayer.config.ts で管理します |
名前空間を指定しない素の useTranslation() | ✅ ファイル全体の translation 辞書に対して解決されます(splitKeys: false) |
ベンチマーク
測定対象
Benchmark Bloom スイートは、各構成で同一のアプリケーションをビルドして検証しています。10ページ(home、about、blog、careers、contact、FAQ、pricing、products、settings、team)、10ロケール(en、fr、es、de、it、pt、zh、ja、ko、ru)、同一のコンポーネントおよびコンテンツで構成され、en と fr のページを測定しています。
next-i18next は、全ロケールのJSONを resources に直接インポートする構成(static)から、ルートごとに名前空間を分離してバックエンド経由で遅延ロードする構成(scoped-dynamic)まで、4つの読み込み戦略でビルドされました。アダプターは基本構成と同一のコンポーネントを用い、next.config.ts、intlayer.config.ts、およびProviderファイルのみを変更してビルドされました。コンパイラがコンポーネント単位でコンテンツをスコープ化するため、手動の "scoped" バリアントは不要です。
各ビルドで以下の指標を記録しています。
- Lib size: i18nライブラリのみをインポートした空コンポーネントのgzipサイズ。
- Page JS: 全ページ・全ロケールの平均ダウンロードJavaScriptサイズ(gzip)。
- Locale leak %: ダウンロードされたJSのうち、ユーザーが閲覧していないロケールに属する翻訳文字列の割合。
- Page leak %: ダウンロードされたJSのうち、ユーザーが滞在していないページに属する翻訳文字列の割合。
- Component avg: 各コンポーネントを個別にコンパイルした場合の平均gzipサイズ。
- E2E reactivity: 新しいロケールを選択してからDOM内の
html[lang]が更新されるまでの実測時間(Playwright、5回試行)。 - Hydration: Reactのハイドレーションフェーズにかかる時間。
下記の測定値は 2026-09-12 時点のもので、next-i18next16.3.0(react-i18next17.0.13、i18next26.4.2)および@intlayer/next-i18next9.5.1 を使用しています。テストアプリは意図的に軽量化(1言語あたり数十行)されているため、リーク率は傾向を示しています。コンテンツが増えるほどリーク量は膨張しますが、ランタイムの固定コストは変わりません。
Next.js での検証結果
テーブルをモーダルで開き、すべてのデータを明確に表示
| 構成 | 戦略 | Libサイズ (gz) | ページJS平均 (gz) | ロケールリーク | ページリーク | コンポーネント平均 (gz) | E2E反応速度 | ハイドレーション |
|---|---|---|---|---|---|---|---|---|
| base (i18nなし) | - | 0.0 KB | 141.0 KB | 0.0% | 0.0% | 0.9 KB | 13.4 ms | 11.8 ms |
next-i18next | static | 19.7 KB | 218.5 KB | 0.0% | 89.8% | 78.5 KB | 16.4 ms | 15.6 ms |
next-i18next | dynamic | 19.7 KB | 169.5 KB | 50.0% | 89.8% | 26.1 KB | 15.4 ms | 27.7 ms |
next-i18next | scoped-static | 19.7 KB | 220.1 KB | 0.0% | 89.8% | 78.9 KB | 16.4 ms | 14.7 ms |
next-i18next | scoped-dynamic | 19.7 KB | 163.4 KB | 0.0% | 0.0% | 27.1 KB | 15.9 ms | 15.1 ms |
@intlayer/next-i18next | static | 9.4 KB | 150.7 KB | 0.0% | 0.0% | 9.7 KB | 10.7 ms | 11.3 ms |
@intlayer/next-i18next | dynamic | 9.4 KB | 150.7 KB | 0.0% | 0.0% | 9.7 KB | 11.9 ms | 10.6 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 |
データの読み解き方
- 基本構成比でページあたり68 KBの軽量化。
resources: { en, fr, ... }の構成では、すべてのロケールと全名前空間が毎ページ送信され 218.5 KB に達します。同一コンポーネントをアダプター経由でビルドすると 150.7 KB に抑制されます。また、i18nextのランタイム単体で19.7 KBあるのに対しアダプターは9.4 KBであるため、next-i18nextの最も綿密な最適化構成(163.4 KB)よりもさらに12.7 KB軽量です。 - コンポーネントに手を加えることなくリーク率0%を達成。 手動で厳密に分割した設定を除き、従来の
next-i18nextは約90%もの他ページ用文字列を同梱してしまいます。dynamic設定ではページ間リークが残る上に、言語別バックエンドがtranslation名前空間全体を取得するため 50%のロケールリーク が新たに発生します。アダプター構成では、既存コードのままで 0% / 0% を達成します。 - コンポーネントが約8分の1のサイズに。 単体コンパイルされた
useTranslation()コンポーネントは、tがグローバルストアに束縛されているため、インラインresourcesで平均 78.5 KB、バックエンド構成でも 26〜27 KB に達します。アダプターを導入すると平均 9.7 KB まで激減します。 - ハイドレーションと切り替え速度の向上。 ハイドレーション時間は15.6 msから 11.3 ms に短縮されます(バックエンド取得がクリティカルパスに乗る
dynamicの27.7 msと比較すると大幅な改善)。ロケール切り替えも15〜16 msから 11〜12 ms へ高速化します。 - アダプターはネイティブランタイムとは別物。
next-intlayerはベースアプリ比わずか+0.3 KBの 141.3 KB です。アダプターはIntlayerのコア上にi18nextのAPI互換レイヤー(補間構文、複数形・コンテキスト解決、<Trans>解析)を保持しているため、ネイティブ比で+9.4 KBとなります。これは移行のための架け橋であり、最終ゴールではありません。
Vite / TanStack Start 環境での react-i18next アダプターはこのテストには含まれていません。TanStack Start における基準値は i18next vs Intlayer で確認できます。
なぜ数値が改善するのか
components/ 配下のソースコードは一切変わっていません。この改善は、useTranslation が何にバインドされているかの違いによるものです。
i18next の場合、コンポーネントはグローバルインスタンスにバインドされます。インスタンスに読み込まれたデータ(static の全言語、dynamic のアクティブ言語全体)は、useTranslation() を呼びすすべてのコンポーネントから参照可能になります。バンドラーはインスタンスが保持している単位未満にはコードを分割できず、ランタイムもどのキーが必要とされるかを予測できません。
コードをクリップボードにコピー
@intlayer/next-i18next の場合、コンポーネントは辞書ファイルに直接バインドされます。syncJSON が各名前空間ファイルを辞書に変換し、最適化パスが指定された辞書だけを直接インポートとしてコンポーネントに渡すため、バンドラーはページごと・ロケールごとに過不足なくコード分割できます。
コードをクリップボードにコピー
i18n/i18n.ts やその resources インポートは不要なデッドコードとなり、これによって68 KBの削減が実現します。
3ステップでの移行手順
インストール
bashコードをコピーコードをクリップボードにコピー
このコマンドは
i18next/react-i18next/next-i18nextを自動検出し、intlayer、フレームワークパッケージ(next-intlayerまたはreact-intlayer)、対応する@intlayer/*アダプター、および@intlayer/sync-json-pluginをインストールしてintlayer.config.tsを初期設定します。元のパッケージは型定義の提供およびピア依存関係として必要となるため、インストールしたままにしておきます。ロケールファイルを指定する
intlayer.config.tsコードをコピーコードをクリップボードにコピー
言語ごとに単一の
translation.jsonのみを使用している場合(i18nextのデフォルト名前空間)、splitKeys: falseを設定することでファイル全体が単一辞書として保持され、名前空間なしのuseTranslation()もそのまま動作します。プラグインを追加する
next.config.tsコードをコピーコードをクリップボードにコピー
App Routerでは、クライアントコンポーネントは
[locale]セグメントからロケールを取得します。アダプターのI18nextProviderはロケール引数を取らないため、Providerファイルを一度だけ更新します。components/AppProviders.tsxコードをコピーコードをクリップボードにコピー
配下の全コンポーネントは引き続き
useTranslation()をそのまま呼び出せます。vite.config.tsコードをコピーコードをクリップボードにコピー
reactI18nextVitePlugin()はvite-intlayerをラップし、react-i18nextとi18nextのエイリアスを設定します。React以外のプロジェクトでは、@intlayer/i18next/pluginのi18nextVitePlugin()がi18next単体をエイリアス化します。
移行後に削除できるコード
テーブルをモーダルで開き、すべてのデータを明確に表示
| ファイル / パターン | 削除できる理由 |
|---|---|
resources: { en, fr, ... } および関連JSONインポート | アダプターによって無視されます。ここに68 KB分の原因がありました |
i18next-http-backend, i18next-resources-to-backend | 実行時に取得するものがなくなります |
i18next-browser-languagedetector | ロケール検出はIntlayerのルーティング設定(URLプレフィックス、Cookie、ヘッダー)に統合されます |
getStaticProps 内の serverSideTranslations() | 空のオブジェクトを返すだけとなり、削除しても動作に影響しません |
next-i18next.config.js | 読み込まれません。設定はすべて intlayer.config.ts で管理します |
ページごとの ns: [...] 定義リスト | コンパイラがコンポーネント単位で必要な名前空間を自動判別します |
容量削減以外のメリット
- 型付けされたキー。
useTranslation("about")はコンパイルされたabout辞書に対して型付けされ、存在しないキーt("does.not.exist")は文字列ではなくTypeScriptのエラーとして即座に検出されます。 npx intlayer testで、いずれかの言語に欠落キーがある場合にCIを失敗させることができます。またnpx intlayer fillを使えば、自身のAPIキー(OpenAI、Anthropic、Mistral、Geminiなど)で未翻訳キーを自動翻訳し、locales/{lng}/{ns}.jsonに書き戻せます。- ビジュアルエディターとCMS が同一のJSON上で動作するため、翻訳者がUI経由でテキストを編集するとGitリポジトリ上のファイルが直接更新されます。
.content.tsへの段階的移行が可能。 コンポーネントごとに個別のコンテンツファイルを配置し、useTranslation("about")からuseIntlayer("about")へ少しずつ切り替えることができます。JSONと.content.ts辞書は完全に共存可能です。
事前に把握しておくべき制限事項
- バックエンドと検出器は不活性化します。
i18n.use(HttpBackend)はプラグインのinitを呼ぶだけで動作を完了します。リクエスト時に外部CMSからリアルタイムで翻訳を取得していたワークフローは動作しなくなるため、IntlayerのCMSまたはintlayer pull/pushコマンドをご利用ください。 resourcesはマージされず無視されます。 一部のアダプターと異なり、@intlayer/i18nextはインラインのresourcesをフォールバックとして使用しません。すべてのキーは同期された辞書内に存在する必要があり、これはintlayer testで検証できます。- App RouterではProviderの変更が必要です。 上述の通り1ファイルのみ差し替えます。Pages Routerで
appWithTranslationを使用している場合は変更不要です。 next-i18next.config.jsは無視されます。localePath、fallbackLng、reloadOnPrerenderなどの設定は機能しません。ロケールおよびフォールバックはintlayer.config.tsに記述してください。- アダプター自体のオーバーヘッド。 ネイティブの
next-intlayerと比較して、ランタイムで9.4 KB、ページあたり+9.4 KBのコストが発生します。すべてのコンポーネントがuseIntlayerへ移行完了した後は、アダプターをアンインストールすることをおすすめします。
選択の指針
i18nextを維持すべきケース: ランタイム時の動的バックエンド(リクエスト時に外部CMSから配信される翻訳)、固有のプラグイン群、またはアダプターがサポートしていない非React環境に強く依存している場合。@intlayer/*を採用すべきケース:react-i18nextやnext-i18nextを利用中で、コードを書き換えることなく68 KBの削減、8倍軽量なコンポーネント、リーク率0%、型付きキー、CI検証を即座に導入したい場合。既存のi18nextコードベースにとって最も手軽な選択肢です。- ネイティブ(
next-intlayer/react-intlayer)へ移行すべきケース: 新規プロジェクト、またはアダプターによる移行が安定した段階。3つの中で最も軽量(5.5 KB、ページあたり+0.3 KB)であり、同期Server Componentsやコンポーネント共配置の.content.tsが利用できます。
関連する比較記事
- i18next vs Intlayer(ライブラリ自体の直接比較、同一ベンチマーク)
- next-intl vs @intlayer/next-intl(同アダプターシリーズ)
- Lingui vs @intlayer/lingui(同アダプターシリーズ)
- vue-i18n vs @intlayer/vue-i18n(同アダプターシリーズ)
- 移行ガイド: i18next, react-i18next, next-i18next
- 互換アダプター仕様: i18next, react-i18next, next-i18next
まとめ
i18next は本ベンチマークの中で最も重いランタイムですが、互換アダプターを導入すればAPIを一切変更することなくその大部分を削ぎ落とせます。同一のNext.jsアプリにおいて、設定ファイルとProviderの軽微な変更だけで、初期構成比でページあたり68 KBの削減、最高度に手動最適化された構成比でも12.7 KBの削減、コンポーネントサイズ8分の1、リーク率0%、ハイドレーション速度4 ms向上が達成されます。
すべての測定データ、検証用アプリ、再現スクリプトは Benchmark Bloom リポジトリ に公開されています。
詳細は なぜIntlayerなのか? ドキュメントをご覧ください。
コメント
まだコメントはありません。最初のコメントを共有しましょう。
