# General Translation Knowledge Base: 言語リダイレクトと SEO：URL、クッキー、Accept-Language のどれを使うべきか
URL: https://generaltranslation.com/ja/kb/locale-routing-seo.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: Googlebot は Accept-Language ヘッダーを送信せず、クロールの大半を米国の IP アドレスから行います。そのため、インデックスさせたいすべてのページの言語は URL で決めましょう。保存済みのクッキーの選択、次いで Accept-Language を使うのは、/ のような中立的なルートのリダイレクト先を決める場合だけにとどめ、その際は一時的な 302 または 307 を使います。
Category: 多言語SEO
Last updated: 2026-10-20
Authors: Kevin Wu, Jackie Chen
Published: 2026-10-20

3 つのシグナルはいずれも有用ですが、それぞれが示すものは異なります。URL はどのバージョンがリクエストされたかを、クッキーはその訪問者が以前に何を選んだかを、`Accept-Language` はブラウザの言語設定を示します。クローラーにも訪問者にも同じように見えるのは URL だけです。したがって、ページの内容を決めるシグナルは URL でなければなりません。

## なぜ言語ごとに専用の URL が必要なのか?

この問題については、Google の[ロケール適応ページ](https://developers.google.com/search/docs/specialty/international/locale-adaptive-pages)に関するガイダンスで説明されています。訪問者の国や言語を推定してページが異なるコンテンツを返す場合、Google がすべてのバージョンをクロール、インデックス登録、ランク付けするとは限りません。Googlebot のデフォルトの IP アドレスは米国にあるように見え、さらにクローラーは `Accept-Language` ヘッダーを付けずにリクエストを送信するためです。Google は、ロケールごとに個別の URL を用意し、[hreflang](/kb/what-is-hreflang) でアノテーションを付けることを推奨しています。

Googlebot は米国外の IP アドレスからもクロールを行いますが、Google の[多地域対応サイトに関するガイド](https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites)によると、サイトのバリエーションを検出する目的でクローラーの位置を変えることはありません。同ガイドでは、「クッキーやブラウザの設定を使用するのではなく」、言語ごとに異なる URL を使用することを推奨しています。

その影響は明確です。たとえば、`/pricing` がドイツ語を優先するブラウザにはドイツ語を、それ以外のユーザーには英語を返すとします。Googlebot は `Accept-Language` もクッキーもない状態でアクセスするため、英語のページを受け取り、英語版をインデックスに登録します。ドイツ語版はユーザー向けには存在していても、Google に検出・インデックス登録されない可能性があります。

## 各シグナルの用途

| シグナル               | わかること                 | クローラーが送るもの                        | 用途                              |
| ------------------ | --------------------- | --------------------------------- | ------------------------------- |
| URL (`/de/preise`) | リクエストされたバージョン         | リンク、サイトマップ、または hreflang で見つけた URL | コンテンツの決定 (インデックス対象となる信頼できる情報源)  |
| クッキー (`locale=de`) | この訪問者が以前に選んだ言語        | 訪問者の選択は一切含まれない                    | 明示的な選択を次回以降の訪問で記憶する             |
| `Accept-Language`  | ブラウザの UI 言語と設定済みの優先言語 | なし (Googlebot はこのヘッダーを送信しない)      | 初回訪問時に言語を提案する                   |
| IP ジオロケーション        | おおよその国 (言語ではない)       | ほとんどが米国のアドレス                      | リージョンの提案。導入する価値はほぼない            |

ブラウザのヘッダーは、見かけほど当てになりません。MDN の [`Accept-Language` リファレンス](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept-Language)はこれをあくまでヒントと位置づけています。そのうえで、 (旅行中など) ユーザーが制御できない場合が多いこと、Safari や Chrome のシークレットモードでは1つの言語しか送信されないことを指摘し、サーバーは明示的な言語選択を決して上書きすべきではないと述べています。IP はさらに当てになりません。Google も IP による位置分析を「困難で、一般的に信頼性が低い」としています ([IP ジオロケーションが適切なシグナルではない理由](/kb/detect-user-language)を参照) 。

## 優先順位：URL、保存された選択、ヘッダーの順

シグナル同士が食い違う場合は、次の順序で解決します。

1. **URL。** `/de/preise` へのリクエストには、どのブラウザからでも常にドイツ語が返されます。これにより各 URL のコンテンツが一定に保たれます。クローラーやキャッシュはこの点に依存しています。
2. **保存された選択。** 訪問者が言語を選んだ際に設定されたクッキーやアカウント設定です。中立的なルートからの遷移先や、提案する別言語版を決めるのには使えますが、訪問者がクリックしたローカライズ済み URL を書き換えることはありません。[言語切り替え機能](/kb/language-switcher)では、現在表示中の言語がわかるようにしてください。
3. **`Accept-Language` ヘッダー。** 保存された選択がない場合にのみ使用し、用途もルートからの遷移先の決定か、提案の表示に限ります。
4. **デフォルトロケール。** 何も一致しない場合のフォールバックです。Googlebot に返されるのもこのロケールです。

言語切り替え機能で言語を選ぶとその言語の URL に遷移するため、ルール 1 が適用されます。

下位のシグナルが URL と食い違う場合は、言語を切り替えるのではなく、別言語版を提案してください。「このページは Deutsch でもご覧いただけます」といったバナーを表示すれば、訪問者がたどったリンクと、訪問者がおそらく希望している言語の両方を尊重できます。これらのシグナルの読み取り方については、[ユーザーのブラウザ言語を検出する方法](/kb/detect-user-language)で解説しています。

## ブラウザの言語に基づいて訪問者をリダイレクトすべきか？

よくある間違いは、ローカライズされたURLをヘッダーやIPに基づいてリダイレクトすることです。たとえば、フランス語のブラウザを使う訪問者が `/en/pricing` を開くと、`/fr/tarifs` に飛ばされてしまいます。Googleのガイドでもこれは避けるべきとされており、ユーザーの言語を推測してリダイレクトすると、ユーザーや検索エンジンがサイトのすべてのバージョンを閲覧できなくなるおそれがあると説明されています。英語のページを見たいフランス語話者はそのページにたどり着けず、米国のアドレスからアクセスするクローラーは英語版以外にアクセスできなくなります。

代わりに、次の2つの方法を使います。

* **バージョン間のリンク。** Googleは、ユーザーが自分で選べるよう、各ページから他の言語バージョンへリンクすることを推奨しています。すべてのページに言語切り替えを設置すれば、クローラーもすべてのバージョンへたどり着けるようになります。
* **中立的なルートでのみリダイレクトする。** `/` のように独自のコンテンツを持たないルートURLであれば、保存された選択やヘッダーに基づいてリダイレクトしたり、言語セレクターを表示したりできます。このURLは、ホームページのhreflangクラスタで任意の `x-default` として指定できます。Googleは言語セレクターや自動リダイレクトを行うホームページをユースケースとして挙げています。一方、下層ページでは、そのページのコンテンツに対して適切なフォールバックを用意しておくべきです。

### ルートで使用すべきステータスコード

リダイレクト先はリクエスト元によって変わるため、一時的なリダイレクト (`302` または `307`) を使用してください。Google の[リダイレクトに関するガイド](https://developers.google.com/search/docs/crawling-indexing/301-redirects)では、一時的なルーティングと恒久的な URL の移転を区別しています。一時的なリダイレクトでは翻訳元の URL が保持されやすい一方、恒久的なリダイレクト (`301` または `308`) は、リダイレクト先を優先すべきだという強いシグナルになります。そのため、リダイレクト先が訪問者ごとの選択にすぎない場合に、言語に依存しないルートから恒久的なリダイレクトを行うと、誤ったシグナルを送ることになります。

## レスポンスが変化する場合のキャッシュ

キャッシュはレスポンスを URL ごとに保存します。1 つの URL がヘッダーやクッキーに応じて異なる言語を返す場合、CDN がある訪問者向けの言語を別の訪問者に返してしまうおそれがあります。HTTP では、`Vary` レスポンスヘッダーでこの問題に対処します。

* **`Vary: Accept-Language`** を指定すると、[MDN のキャッシュガイド](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Caching#vary)にあるとおり、キャッシュは URL とヘッダーの組み合わせをキーとしてレスポンスを保存します。ただし、ヘッダーの値は多種多様なため (`en-US,en;q=0.9` と `en-GB,en;q=0.9,de;q=0.8` は別のキーになります) 、ヒット率は低下します。
* **`Vary: Cookie`** はさらに不利です。[RFC 9111](https://www.rfc-editor.org/rfc/rfc9111#section-4.1) では、指定されたリクエストヘッダーが一致する場合にしか保存済みレスポンスは再利用されません。しかし `Cookie` ヘッダーには、セッション用や分析用も含め、すべてのクッキーが入っています。MDN は、レスポンスがパーソナライズされている場合は、クッキーで Vary を指定するのではなく `Cache-Control: private` を使うよう推奨しています。

URL にロケールを含めれば、翻訳済みコンテンツを URL 単位でキャッシュできます。ただし、レスポンス全体を安全に共有できるのは、それ以外のコンテンツも訪問者に依存しない場合に限られます。この例では、パーソナライズされたルートのリダイレクトに `Vary: Accept-Language, Cookie` と `Cache-Control: private` を指定します。サーバーでレンダリングされた言語の提案やアカウント情報が訪問者ごとに異なる場合は、そのレスポンスも private にするか、提案をクライアント側で別途レンダリングしてください。

## フレームワークに依存しない例

この関数は、ルーティングと言語ネゴシエーションを切り離します。[言語検出ガイド](/kb/detect-user-language)を参考に、まず保存済みのユーザーの選択から、次にブラウザの言語設定からロケールを解決します。こうして得られたサポート対象のロケールを `preferredLocale` として渡すと、リダイレクトするか、そのまま配信するか、別のバージョンを提案するかを関数が判断します。

```ts title="routeLocale.ts"
const LOCALES = ['en', 'de', 'fr', 'es-MX'];
const DEFAULT_LOCALE = 'en';

type Decision =
  | { action: 'serve'; locale: string; suggest?: string }
  | { action: 'redirect'; status: 302; location: string; headers: Record<string, string> }
  | { action: 'not-found' };

export function routeLocale(pathname: string, preferredLocale?: string): Decision {
  const preferred = LOCALES.includes(preferredLocale ?? '') ? preferredLocale : undefined;

  if (pathname === '/') {
    return {
      action: 'redirect',
      status: 302,
      location: `/${preferred ?? DEFAULT_LOCALE}/`,
      headers: { Vary: 'Accept-Language, Cookie', 'Cache-Control': 'private' },
    };
  }

  const segment = pathname.split('/')[1];
  const urlLocale = LOCALES.find((l) => l.toLowerCase() === segment.toLowerCase());
  if (!urlLocale) return { action: 'not-found' };

  return preferred && preferred !== urlLocale
    ? { action: 'serve', locale: urlLocale, suggest: preferred }
    : { action: 'serve', locale: urlLocale };
}
```

| パス            | 解決済みの優先言語          | 判定                   |
| ------------- | ------------------ | -------------------- |
| `/`           | なし                 | `/en/` へ一時リダイレクト     |
| `/`           | `de`               | `/de/` へ一時リダイレクト     |
| `/`           | `fr` (保存済みの選択による)  | `/fr/` へ一時リダイレクト     |
| `/de/preise`  | なし                 | ドイツ語で配信              |
| `/de/preise`  | `fr`               | ドイツ語で配信し、フランス語版を提案   |
| `/en/pricing` | `de`               | 英語で配信し、ドイツ語版を提案      |
| `/pt/precos`  | なし                 | Not found：ポルトガル語は未設定 |

この関数はルーティングの判定を返すだけで、リダイレクトの送信やページのレンダリングは行いません。ステータスとキャッシュヘッダーはサーバー側のインテグレーションで適用してください。また、別言語版を提案するのは、そのページが提案先の言語で公開されている場合に限ってください。ルートのみを対象とするこのパターンは実装の一例にすぎません。実際のコンテンツが固定のローカライズ済み URL に置かれている場合は、プレフィックスのない他のパスも中立的なエントリポイントとして使えます。

## General Translation の gt-next が言語を決定する仕組み

`gt-next` では、[`createNextMiddleware`](/docs/react/nextjs/reference/functions/create-next-middleware) が保存済みのロケールクッキーや `Accept-Language` ヘッダーよりも先に URL 内のロケールを確認します。そのため、ローカライズされた URL では、その URL に対応する言語が配信されます。解決順序の詳細とクッキー名については、[ユーザーのブラウザ言語を検出する方法](/kb/detect-user-language)を参照してください。

公開サイトでは、[`createNextMiddleware`](/docs/react/nextjs/reference/functions/create-next-middleware) で `prefixDefaultLocale: true` を設定してください。英語は `/en/about`、フランス語は `/fr/about` に配置され、各コンテンツの URL は訪問者の言語設定にかかわらず、常に同じ言語で表示されます。`/about` のようなプレフィックスなしのパスは、一時的なリダイレクトを行う中立的なエントリポイントとして機能します。この設定とカノニカル URL、メタデータ、サイトマップとの関係については、[Next.js SEO ガイド](/kb/multilingual-nextjs-seo)で解説しています。

デフォルトの設定では英語にプレフィックスが付かず、保存済みのクッキーやブラウザのヘッダーに応じて `/about` がリダイレクトされる場合があります。プレフィックスを明示的に有効にすれば、同じ URL が英語コンテンツと言語設定に基づくエントリポイントを兼ねる状態を避けられます。ブラウザのヘッダーによる言語設定を無視するには、`withGTConfig` で [`ignoreBrowserLocales`](/docs/react/nextjs/config#ignore-browser-locales) を `true` に設定してください。この場合でも、URL と保存済みの選択は引き続き適用されます。

## 重要なポイント

* Googlebot は `Accept-Language` ヘッダーを送信せず、主に米国の IP アドレスからクロールします。そのため、ヘッダー、クッキー、IP に基づいて出し分けたコンテンツは、他の言語版がインデックスされない可能性があります。
* 言語は URL、保存済みの選択、`Accept-Language`、デフォルトの順に解決し、優先度の低いシグナルで URL を上書きしないようにしてください。
* このパターンでは、ネゴシエーションは中立的なルートでのみ、一時的な `302` または `307` を使って行います。`x-default` は任意です。ローカライズされたコンテンツの URL は固定し、他の言語版へのリンクを提示してください。
* 言語ごとに URL が固定されていればキャッシュを共有できますが、訪問者ごとのリダイレクト、言語の提案、アカウントデータには、引き続き適切なキャッシュ制御が必要です。
* `gt-next` では、URL のロケールがクッキーやヘッダーより優先されます。`prefixDefaultLocale` と `ignoreBrowserLocales` を使うと、このルールをさらに厳格にできます。

## Related questions

- [ユーザーのブラウザ言語を検出するには？](https://generaltranslation.com/ja/kb/detect-user-language.mdx): ブラウザが持つ優先順位付きの言語リスト（JavaScript では navigator.languages、サーバー側では q 値で並べ替えた Accept-Language ヘッダー）を読み取り、フォールバックを用意したうえで対応ロケールとマッチングします。なお、Safari や Chrome のシークレットモードでは 1 つの言語しか通知されません。また、IP ジオロケーションでわかるのは所在地であって、言語ではありません。
- [言語切り替え機能のベストプラクティス：UX、SEO、アクセシビリティ](https://generaltranslation.com/ja/kb/language-switcher.mdx): 各言語は Deutsch や 日本語 のようにその言語自身の名称で表記し、国を表す国旗は使わないでください。各選択肢からは、クロール可能なリンクで同じページの該当言語版へ遷移させ、選択内容はクッキーに保存します。ローカライズされた URL は決して自動リダイレクトしないでください。
- [hreflang とは？設定方法を解説](https://generaltranslation.com/ja/kb/what-is-hreflang.mdx): hreflang は、どの URL が同じページの言語版または地域版であるかを Google に伝え、検索結果に適切なページを表示させるための仕組みです。HTML の link タグ、HTTP の Link ヘッダー、またはサイトマップで追加し、すべてのリンクを相互に参照させたうえで、en-UK ではなく en-GB のような有効なコードを使用してください。
- [多言語SEOにおけるサブディレクトリ・サブドメイン・ccTLDの比較](https://generaltranslation.com/ja/kb/multilingual-url-structure.mdx): 1つのプロダクトでサイトとリリースプロセスを共有するなら、example.com/de/ のようなサブディレクトリを使いましょう。国を示せるのは ccTLD だけで、サブドメインなら個別にホスティングできます。Google は ?lang= パラメータを推奨しておらず、.io や .ai のようなバニティドメインは汎用ドメインとして扱います。
- [多言語対応の 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 でタイトルを翻訳します。

## Previous and next questions

- Previous question: [翻訳管理システム（TMS）とは？](https://generaltranslation.com/ja/kb/what-is-a-translation-management-system.mdx)
- Next question: [言語切り替え機能のベストプラクティス：UX、SEO、アクセシビリティ](https://generaltranslation.com/ja/kb/language-switcher.mdx)

## Sitemap

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