# General Translation Knowledge Base: Next.js Pages Router アプリに i18n を追加するには？
URL: https://generaltranslation.com/ja/kb/add-i18n-to-nextjs-pages-router.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: next.config.js に locales と defaultLocale を含む i18n ブロックを追加すると、Next.js は /es や /fr を配信し、ブラウザの言語に基づいて訪問者をリダイレクトし、ロケールを getStaticProps と getServerSideProps に渡します。メッセージのレンダリングはライブラリが担います。General Translation の gt-next なら、JSX にインラインで書いた文言から翻訳の生成まで行えます。
Category: 国際化
Last updated: 2026-10-28
Authors: General Translation Team
Published: 2026-10-28

Pages Router には Next.js 10 以降、国際化ルーティングが組み込まれています。`next.config.js` の `i18n` ブロックにロケールとデフォルトロケールを指定すると、Next.js は言語ごとに個別の URL で配信し、初回訪問者をブラウザの言語に応じてリダイレクトし、アクティブなロケールをデータ関数に渡します。ただし、テキストの読み込み、レンダリング、翻訳は一切行いません。このルーティングは i18n ライブラリとの併用を前提に設計されているため、メッセージを扱うライブラリと翻訳を用意する手段は別途選ぶ必要があります ([Next.js Pages Router internationalization](https://nextjs.org/docs/pages/guides/internationalization)) 。

## 組み込みのi18nルーティングでできること

機能全体は、次の設定ブロック1つだけです。

```js title="next.config.js"
/** @type {import('next').NextConfig} */
module.exports = {
  i18n: {
    // サイトで配信するすべてのロケール（デフォルトロケールを含む）
    locales: ['en', 'es', 'fr'],
    // プレフィックスなしで配信: /about, /es/about, /fr/about
    defaultLocale: 'en',
  },
};
```

これを設定すると、Next.js は次の4つの処理を担います。

* **URL。** サブパスルーティングでは、デフォルトロケールは `/about` のまま、それ以外のロケールにはプレフィックスが付きます (`/fr/about`) 。代わりに `example.fr` のような別ドメインでロケールを配信したい場合は、各エントリに `domain` と `defaultLocale` を指定した `domains` リストを追加します。
* **検出。** `/` にアクセスがあると、Next.js は `Accept-Language` ヘッダーを読み取り、マッチングしたプレフィックスまたはドメインへリダイレクトします。言語切り替え機能で設定される `NEXT_LOCALE` クッキーは、ヘッダーより優先されます。リダイレクトを無効にするには `localeDetection: false` を設定します。
* **コード内のロケール。** `useRouter()` は `locale`、`locales`、`defaultLocale` を返します。`getStaticProps` と `getServerSideProps` は `context` で `locale` を受け取り、`getStaticPaths` は `locales` を受け取ります。
* **`<html lang>`。** `_document` で独自に設定していない限り、Next.js はこの属性をアクティブなロケールに設定します。

i18n を手作業で構築するにはこれで十分です。このページでは、ビルド時にロケールごとに1つの JSON ファイルを読み込みます。

```tsx title="pages/index.tsx"
import type { GetStaticProps, InferGetStaticPropsType } from 'next';
import Link from 'next/link';
import { useRouter } from 'next/router';

export const getStaticProps = (async ({ locale }) => {
  // Next.js はビルド時に、設定されたロケールごとにこれを 1 回ずつ呼び出します。
  const messages = (await import(`../messages/${locale}.json`)).default;
  return { props: { messages } };
}) satisfies GetStaticProps;

export default function Home({ messages }: InferGetStaticPropsType<typeof getStaticProps>) {
  const { locales } = useRouter(); // ['en', 'es', 'fr']

  return (
    <main>
      <h1>{messages.title}</h1>
      <nav>
        {locales?.map((code) => (
          // 同じページの各言語版: /, /es, /fr
          <Link key={code} href="/" locale={code} lang={code}>
            {new Intl.DisplayNames([code], { type: 'language' }).of(code)}
          </Link>
        ))}
      </nav>
    </main>
  );
}
```

本番環境のビルドでは、`/es` はスペイン語の見出しを含む `<html lang="es">` として配信され、`Accept-Language: fr-CA` を指定した `/` へのリクエストは `/fr` に 307 でリダイレクトされます。各リンクには、[言語切り替え機能](/kb/language-switcher)として本来あるべき形で、各言語がその言語自身の表記 (English、español、français) で表示されます。

### 開発者に任されていること

ルーティングが担うのは URL までです。複数形、数値や日付のフォーマット、文字列の補間はライブラリの役割であり、コンポーネントの変更に合わせてメッセージファイルを同期し続けるのも同様です。また、Next.js は言語版間の `hreflang` リンクを追加しないため、`next/head` を使って自分で追加する必要があります ([hreflang とは？](/kb/what-is-hreflang) を参照) 。そして、いずれの機能も翻訳そのものを生成するわけではありません。

計画の際には、次の 3 つの制限に注意が必要です。

* **静的エクスポートは不可。** 国際化ルーティングは Next.js のルーティング層に依存しているため、`output: 'export'` では動作しません。
* **ビルド時間はロケール数に比例して増加。** 動的でない `getStaticProps` ページはロケールごとに 1 回ずつビルドされるため、50 ロケール × 10 ページで 500 回の呼び出しになります。動的ルートでは `getStaticPaths` から各ロケールを返す必要があり、返さない場合、Next.js はデフォルトロケールのみをビルドします。
* **上限。** `locales` と `domains` はそれぞれ 100 エントリまでに制限されています。

### App Routerには引き継がれない

`i18n` 設定はPages Routerの機能です。App Routerでは、`next/navigation` の `useRouter` から `locale`、`locales`、`defaultLocale` が削除されており、Next.jsも `app` ディレクトリでは組み込みのi18n機能は不要であると明記しています ([移行ガイド](https://nextjs.org/docs/app/guides/migrating/app-router-migration#step-5-migrating-routing-hooks)) 。App Routerのアプリでは、代わりにロケールを `[locale]` セグメントに含めるか、ミドルウェアで解決します ([Next.js App Routerアプリにi18nを追加するには？](/kb/add-i18n-to-nextjs)を参照) 。

## メッセージをレンダリングするライブラリ

| ライブラリ                                                                      | Pages Router のセットアップ                                                                                                                                       | テキストの書き方                                                                                                        | 翻訳の提供元                                                                         |
| -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| [next-i18next](https://github.com/i18next/next-i18next#pages-router-setup) | `appWithTranslation` で `_app` をラップし、`getStaticProps` または `getServerSideProps` 内で `next-i18next/pages` の `serverSideTranslations(locale, ['common'])` を呼び出す | JSON 名前空間内のキーを `t('title')` でレンダリング                                                                             | 開発者自身、翻訳者、または Locize などの翻訳管理システム (TMS)                                         |
| [next-intl](https://next-intl.dev/docs/getting-started/pages-router)       | `_app` 内の `NextIntlClientProvider` に、`getStaticProps` から返した `messages` を渡す                                                                                 | ロケールごとに 1 つの JSON ファイルに置いたキーを [`useTranslations`](/docs/react/reference/hooks/use-translations) でレンダリング         | 開発者自身または翻訳者                                                                    |
| [react-intl](https://formatjs.github.io/docs/react-intl)                   | `_app` 内の `IntlProvider` に、アクティブなロケールとそのメッセージを渡す                                                                                                           | ICU メッセージを `defaultMessage` としてインラインで記述し、`formatjs extract` で抽出                                                 | 開発者自身、翻訳者、または TMS                                                              |
| General Translation (`gt-next`)                                            | 各ページで `withGTServerSideProps` または `withGTStaticProps` を使用し、`_app` に [`GTProvider`](/docs/react/reference/components/gt-provider) を配置                       | JSX は [`<T>`](/docs/react/reference/components/t) でラップし、文字列には [`useGT`](/docs/react/reference/hooks/use-gt) を使用 | [`npx gt translate`](/docs/cli/reference/commands/translate) で生成し、ダッシュボードでレビュー |

next-i18next 16 は両方のルーターに対応しており、おなじみの Pages Router 向け API も `next-i18next/pages` で引き続き提供しています。next-intl のドキュメントでは App Router が推奨されていますが、Pages Router も引き続き完全にサポートされています。Pages Router では、どちらのライブラリも前述の `i18n` ブロックと組み合わせて、URL の処理とロケール検出を行います。

すでに i18next の名前空間を使っている場合や、そのプラグインエコシステムを活用したい場合は next-i18next が適しています。App Router への移行を予定しており、移行前後で同じ API を使いたい場合は next-intl が適しています。メッセージが翻訳者が普段から扱っている ICU 文字列である場合は react-intl が適しています。テキストをコンポーネント内にインラインで書いたまま、コードの変更に合わせて翻訳の生成・レビュー・更新を行いたい場合は General Translation が適しています。 (両者の詳しい比較は [next-intl vs. gt-next](/kb/next-intl-vs-gt-next) を参照してください。) 

next-i18next や next-intl を使い続ける場合でも、General Translation の CLI を使えば、移行せずにそれらの JSON ファイルを ICU 文字列も含めて翻訳できます ([JSON ファイルの翻訳](/docs/cli/reference/formats/json-files)) 。

## Pages Router アプリに General Translation を追加する

このセットアップでは、Pages Router アプリにスペイン語とフランス語を追加し、言語ごとに個別の URL で提供します。動作確認は、`create-next-app` 16.4.3 (`--no-app`) で作成したアプリ、Next.js 16.4.3、`gt-next@11.4.16`、`gt@2.26.11` の環境で行っています。`gt-next` は Next.js 13.0.0 以降に対応しています (15.2.1 および 15.2.2 を除く) 。なお、`gt-next/server` エントリは App Router 専用です。

### 1. ライブラリとCLIをインストールする

```bash
npm install gt-next@11.4.16
npm install --save-dev gt@2.26.11
```

### 2. 言語を設定する

```json title="gt.config.json"
{
  "defaultLocale": "en",
  "locales": ["en", "es", "fr"],
  "files": {
    "gt": {
      "output": "public/_gt/[locale].json"
    }
  }
}
```

`locales` には `en` を残しておいてください。同じリストが Next.js の `i18n` ブロックにも渡され、そちらではデフォルトロケールの指定が必須となるためです。

### 3. Next.js の i18nルーティングを有効にする

```ts title="next.config.ts"
import type { NextConfig } from 'next';
import { withGTConfig } from 'gt-next/config';
import gtConfig from './gt.config.json';

const nextConfig: NextConfig = {
  i18n: {
    locales: gtConfig.locales,
    defaultLocale: gtConfig.defaultLocale,
  },
};

export default withGTConfig(nextConfig);
```

上で説明したルーティングとロケール検出は Next.js が行います。`gt-next` のミドルウェアや `pages/[locale]` フォルダーは不要です。

`create-next-app` は `pages/_document.tsx` に `<Html lang="en">` を出力しますが、これによってロケールが上書きされてしまいます。テストアプリでは、`/es` のテキストはスペイン語なのに `lang="en"` が返されました。Next.js が値を設定できるよう、このプロパティを削除してください：

```tsx title="pages/_document.tsx"
import { Html, Head, Main, NextScript } from 'next/document';

export default function Document() {
  return (
    <Html>
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}
```

### 4. ローカルファイルから翻訳を読み込む

```ts title="loadTranslations.ts"
export default async function loadTranslations(locale: string) {
  try {
    const translations = await import(`./public/_gt/${locale}.json`);
    return translations.default;
  } catch {
    // ファイルが生成されるまでは原文をレンダリングする
    return {};
  }
}
```

`withGTConfig` は、プロジェクトルートまたは `src/` にある `loadTranslations.ts` を自動的に検出します。翻訳はビルドに含まれるため、ランタイムにアプリから General Translation への呼び出しは発生しません ([翻訳の保存](/docs/react/guides/storing-translations)を参照してください) 。

### 5. すべてのページにロケールと翻訳を渡す

各ページのデータ関数をラップします。ラッパーは Next.js から `context.locale` を読み取り、ページの props に `locale` と `translations` を追加します。

```tsx title="pages/about.tsx"
import { T, withGTStaticProps } from 'gt-next';

// Next.js はこのページをロケールごとに1回ずつビルドします。
export const getStaticProps = withGTStaticProps();

export default function About() {
  return (
    <T>
      <h1>About us</h1>
    </T>
  );
}
```

サーバーでレンダリングされたページでは、同じように `withGTServerSideProps()` を使用します。どちらも `withGTStaticProps(async (context) => ({ props: { posts } }))` のように独自のデータ関数を引数に取り、`redirect` や `notFound` の結果は変更せずにそのまま返します。翻訳済みコンテンツをレンダリングするページは、すべてこれらでラップしてください。

次に、それらの props を `_app` 内の [`GTProvider`](/docs/react/reference/components/gt-provider) に渡します。

```tsx title="pages/_app.tsx"
import type { AppProps } from 'next/app';
import Router from 'next/router';
import { GTProvider, type WithGTServerSideProps } from 'gt-next';

export default function App({ Component, pageProps }: AppProps<WithGTServerSideProps>) {
  const { locale, translations } = pageProps;

  return (
    <GTProvider
      locale={locale}
      translations={translations}
      // Next.js のナビゲーションで言語を切り替え（/es、/fr、/ に戻る）
      _reload={({ locale: nextLocale }) => {
        void Router.push(Router.pathname, Router.asPath, { locale: nextLocale });
      }}
    >
      <Component {...pageProps} />
    </GTProvider>
  );
}
```

### 6. 翻訳対象のコンテンツをマークする

```tsx title="pages/index.tsx"
import { LocaleSelector, T, useGT, withGTServerSideProps } from 'gt-next';

export const getServerSideProps = withGTServerSideProps();

export default function Home() {
  const gt = useGT();

  return (
    <main>
      <LocaleSelector />
      <T>
        <h1>Find your next project</h1>
        <p>Explore projects from teams around the world.</p>
      </T>
      <input type="search" placeholder={gt('Search projects')} aria-label={gt('Search projects')} />
    </main>
  );
}
```

[`<T>`](/docs/react/reference/components/t) は、見出しと段落をまとめて翻訳し、そのマークアップを文脈として利用します。[`useGT`](/docs/react/reference/hooks/use-gt) は属性の文字列を処理します。[`<LocaleSelector>`](/docs/react/reference/components/locale-selector) は、各ロケールをその言語自身での名称で一覧表示します。Español を選択すると `NEXT_LOCALE=es` が保存され、次回 `/` にアクセスしたときに Next.js がこの値を読み取ります。さらに、`_reload` コールバックによってページが `/es` に遷移します。

### 7. 翻訳を生成してビルドを確認する

[`npx gt login`](/docs/cli/reference/commands/login) でサインインし、`GT_PROJECT_ID` を設定してから [`npx gt translate`](/docs/cli/reference/commands/translate) を実行すると、`public/_gt/es.json` と `fr.json` が書き出されます。アカウントなしでセットアップを試したい場合は、[`npx gt generate`](/docs/cli/reference/commands/generate) を実行してください。英語の原文が入った同じファイルが書き出されるので、それを手作業で翻訳できます。

テストアプリでは、スペイン語のファイルに翻訳を入力した状態で `next build` が成功し、`next start` で次のように配信されました。

* `/` は英語の見出しを含む `<html lang="en">` として配信
* `/es` はスペイン語の見出しとプレースホルダーを含む `<html lang="es">` として配信
* `withGTStaticProps` でビルドした `/es/about` はスペイン語で配信
* `Accept-Language: es` を指定した `/` へのリクエストは `/es` に 307 リダイレクト

## 翻訳をリリースして常に最新に保つ

毎回のビルド前に翻訳を実行すれば、新しいテキストをすべての言語でリリースできます:

```json title="package.json"
{
  "scripts": {
    "build": "gt validate && gt translate && next build"
  }
}
```

ホスティングプロバイダーで `GT_PROJECT_ID` を設定し、**ファイル &gt; 書き込み** と **Translation queue &gt; Enabled** の権限を持つプロジェクトAPIキーを `GT_API_KEY` として設定します。キーはサーバーサイドで保持し、`NEXT_PUBLIC_` プレフィックスは絶対に付けないでください。ビルドのたびに `public/_gt/` が再生成される場合は、`.gitignore` に追加してください。[`gt validate`](/docs/cli/reference/commands/validate) は、翻訳を壊す原因となるコンテンツがあれば API を呼び出す前にビルドを失敗させます。また、2回目以降の実行では、新規または変更された翻訳元だけが翻訳されます。

レビュー担当者は General Translation の[翻訳エディター](/docs/platform/dashboard/guides/reviewing-translations)であらゆる翻訳を修正できます。また、[コンテキストグループ](/docs/platform/dashboard/guides/defining-context-for-translations)を使えば、用語集の用語やトーンを他のプロジェクトと統一できます。各言語版を検索エンジンにインデックスさせるには、`hreflang`、カノニカルURL、翻訳済みのタイトルを追加してください。それぞれの詳細は [Next.js の多言語SEO](/kb/multilingual-nextjs-seo) で解説しています。

## よくある質問

### next.config.js の i18n オプションは App Router で使えますか？

いいえ。これは Pages Router 向けの機能です。App Router のアプリでは `[locale]` ルートセグメントまたはミドルウェアを使用します。なお、`gt-next` では App Router 向けのセットアップ手順を別途用意しています。

### gt-next で getStaticProps を使用できますか？

はい。`withGTStaticProps` でラップすると、Next.js はロケールごとにページを生成します。動的ルートの場合は、これまでどおり `getStaticPaths` からロケールごとにパスを返します。

### Pages Router の i18n にミドルウェアは必要ですか？

いいえ、不要です。データ関数が実行される前に、Next.js が URL、`NEXT_LOCALE` クッキー、`Accept-Language` からロケールを解決します。

## 重要なポイント

* `next.config.js` の `i18n` ブロックは、Pages Router にロケール付き URL、`/` での `Accept-Language` に基づくリダイレクト、`NEXT_LOCALE` クッキー、そして `useRouter()` やデータ関数で使える `locale` を提供します。
* ただし、メッセージのレンダリングや翻訳、`hreflang` の追加は行いません。また、`output: 'export'` とは併用できず、App Router にも適用されません。
* `pages/_document.tsx` にハードコードされている `lang="en"` は削除してください。残したままだと、すべてのロケールの HTML が英語として宣言されてしまいます。
* next-i18next、next-intl、react-intl は、開発者が用意した翻訳をレンダリングするだけですが、General Translation の `gt-next` は翻訳の生成まで行います。各ページで `withGTStaticProps` または `withGTServerSideProps` を使用し、`_app` に [`GTProvider`](/docs/react/reference/components/gt-provider) を配置してください。
* `next build` の前に [`gt validate && gt translate`](/docs/cli/reference/commands/validate) を追加すれば、すべてのリリースを全言語で提供できます。

## Related questions

- [Next.js App Router アプリに i18n を追加するには？](https://generaltranslation.com/ja/kb/add-i18n-to-nextjs.mdx): まず gt init を実行して、対応する App Router プロジェクトに General Translation を設定します。次にソースコンテンツをマークし、翻訳を生成して、言語の切り替えが機能することを確認します。gt-next はテキストを翻訳の文脈とともに JSX 内に保持し、生成、レビュー、継続的な更新は CLI、ダッシュボード エディター、Locadex が担います。このガイドでは、ローカルファイルを明示的に使うセットアップ方法も紹介します。
- [next-intl の代替：gt-next と next-intl の比較](https://generaltranslation.com/ja/kb/next-intl-vs-gt-next.mdx): next-intl は、言語ごとのメッセージカタログに用意した翻訳をレンダリングします。gt-next も翻訳をレンダリングしますが、それに加えて General Translation が JSX にインラインで記述したテキストから翻訳を生成します。どちらも MIT ライセンスで、App Router とサーバーコンポーネントに対応しています。既存の next-intl のカタログが問題なく機能しているなら、移行せずにそのまま使い続けながら、General Translation で翻訳できます。
- [多言語対応の Next.js アプリで SEO を設定するには？](https://generaltranslation.com/ja/kb/multilingual-nextjs-seo.mdx): 各言語に /en/about や /es/about のようなプレフィックス付きの URL を割り当て、公開している言語ごとに html lang、自己参照のカノニカル、x-default を含む hreflang の代替リンク、翻訳済みのタイトルと説明文、サイトマップのエントリを出力します。未公開のバージョンには noindex を指定します。General Translation の gt-next は各言語を専用の URL にルーティングし、getGT でタイトルを翻訳します。
- [言語切り替え機能のベストプラクティス：UX、SEO、アクセシビリティ](https://generaltranslation.com/ja/kb/language-switcher.mdx): 各言語は Deutsch や 日本語 のようにその言語自身の名称で表記し、国を表す国旗は使わないでください。各選択肢からは、クロール可能なリンクで同じページの該当言語版へ遷移させ、選択内容はクッキーに保存します。ローカライズされた URL は決して自動リダイレクトしないでください。
- [i18next の代替：General Translation と i18next の比較](https://generaltranslation.com/ja/kb/general-translation-vs-i18next.mdx): テキストを React コンポーネント内にインラインで記述したまま、JSX 構造とプロダクトの文脈を活かして翻訳を生成したい場合は、General Translation を選びましょう。i18next を使い続けながら、General Translation で既存のカタログを翻訳することもできます。i18next はメッセージのレンダリングと複数形の選択を担いますが、翻訳の生成には別のサービスが必要です。

## Previous and next questions

- Previous question: [Lottie アニメーションを翻訳するには？](https://generaltranslation.com/ja/kb/translate-lottie-animations.mdx)
- Next question: [Payload CMS でコンテンツを翻訳するにはどうすればよいですか？](https://generaltranslation.com/ja/kb/translate-payload-content.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/ja/kb/sitemap.md) for every article.
