# 機能設計書 85-国際化（i18n）

## 概要

本ドキュメントは、Next.jsにおける国際化（i18n）機能の設計書である。ロケール検出・ドメインルーティング・ロケールパス正規化・言語切替のサポートを含む、Pages Router向けの国際化機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：グローバルに展開するWebアプリケーションでは、ユーザーの言語・地域に応じたコンテンツ配信が必要となる。Next.jsのi18n機能は、URLパスやドメインによるロケール判定、Accept-Languageヘッダーに基づく自動リダイレクト、Cookieによるロケール記憶などを組み合わせた包括的な国際化サポートを提供する。

**機能の利用シーン**：Pages RouterでのWeb多言語サイト構築時に使用される。`next.config.js`の`i18n`設定でロケール一覧・デフォルトロケール・ドメインマッピングを定義し、URLパスのロケールプレフィックスに基づくルーティングが自動的に行われる。

**主要な処理内容**：
1. URLパスからのロケール検出と正規化（`normalizeLocalePath`）
2. ドメインに基づくロケール検出（`detectDomainLocale`）
3. Accept-Languageヘッダーとcookieに基づくロケール判定
4. 適切なロケールへの自動リダイレクト（`getLocaleRedirect`）
5. カスタムルート（Rewrites/Redirects）のロケール対応展開

**関連システム・外部連携**：Pages Router（ルーティング統合）、カスタムルート（ロケール展開）

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能は画面を持たないルーティング機構である（Pages Router経由で各ページに適用） |

## 機能種別

ルーティング制御 / リクエスト処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| i18n.defaultLocale | string | Yes | デフォルトロケール | ロケール文字列 |
| i18n.locales | string[] | Yes | サポートするロケール一覧 | 空でない文字列配列 |
| i18n.domains | DomainLocale[] | No | ドメインとロケールのマッピング | 有効なドメイン設定配列 |
| i18n.localeDetection | false | No | ロケール自動検出を無効にする | undefinedまたはfalse |

### 入力データソース

- `next.config.js`の`i18n`設定
- HTTPリクエストのAccept-Languageヘッダー
- NEXT_LOCALEクッキー
- リクエストURLのパス部分
- リクエストのホスト名

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| detectedLocale | string | 検出されたロケール |
| pathname | string | ロケールプレフィックスを除去したパス |
| redirectUrl | string | ロケールリダイレクト先URL（リダイレクト必要時） |
| DomainLocale | object | マッチしたドメインロケール設定 |

### 出力先

- Router Server（リクエスト処理の判定結果）
- HTTPレスポンス（リダイレクトレスポンス）

## 処理フロー

### 処理シーケンス

```
1. URLパスからロケール検出
   └─ normalizeLocalePath(pathname, locales)
   └─ パスの先頭セグメントをロケール一覧と照合
2. ドメインからロケール検出
   └─ detectDomainLocale(domains, hostname, detectedLocale)
3. ロケール判定の優先順位適用
   └─ pathLocale > domainLocale > NEXT_LOCALEクッキー > Accept-Language > defaultLocale
4. リダイレクト判定
   └─ getLocaleRedirect({...options})
   └─ 検出ロケールがdefaultLocaleと異なる場合リダイレクト
   └─ ドメインが異なる場合ドメインリダイレクト
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B[URLパスからロケール検出]
    B --> C[ドメインからロケール検出]
    C --> D{localeDetection有効?}
    D -->|No| E[デフォルトロケール使用]
    D -->|Yes| F[Accept-Language/Cookie判定]
    F --> G{リダイレクト必要?}
    G -->|Yes| H{ドメインリダイレクト?}
    H -->|Yes| I[別ドメインにリダイレクト]
    H -->|No| J[ロケールパスにリダイレクト]
    G -->|No| K[ロケール付きでレンダリング]
    E --> K
    I --> L[終了]
    J --> L
    K --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-85-01 | ロケール検出優先順位 | pathLocale > domainLocale > cookie > Accept-Language > defaultLocale | リクエスト処理時 |
| BR-85-02 | 大文字小文字非依存 | ロケール照合は大文字小文字を区別しない | パスロケール検出時 |
| BR-85-03 | デフォルトロケール非表示 | defaultLocaleはURLパスから省略される | defaultLocaleアクセス時 |
| BR-85-04 | ドメインルーティング | ドメインごとに異なるdefaultLocaleを設定可能 | domains設定時 |
| BR-85-05 | App Router非対応 | i18n設定はApp Routerでは非推奨（警告表示） | App Routerプロジェクト時 |
| BR-85-06 | output:export非互換 | output: "export"とi18n設定は併用不可 | 静的エクスポート時 |

### 計算ロジック

ロケール検出の優先順位ロジック（`detectLocale`関数）:
```
pathLocale || domainLocale?.defaultLocale || cookieLocale || preferredLocale || i18n.defaultLocale
```

## データベース操作仕様

本機能はデータベースに対する操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | output: "export"とi18n設定の併用 | いずれかを削除する |
| - | Warning | App Routerプロジェクトでi18n設定を使用 | App Router対応の国際化方式に移行する |

### リトライ仕様

リトライは行わない。

## トランザクション仕様

トランザクション管理は不要。

## パフォーマンス要件

ロケール検出はリクエストごとに実行されるが、軽量な文字列比較のみで構成されている。WeakMapキャッシュにより小文字変換結果がキャッシュされる。

## セキュリティ考慮事項

- ドメインルーティングではHTTP/HTTPSプロトコルの制御が可能（`http`フラグ）
- Accept-Languageヘッダーの解析時にエラーハンドリングが行われる

## 備考

- App Routerでの国際化はミドルウェアとroute groupsを使用した手動実装が推奨される
- i18n設定はPages Routerに特化した機能であり、App Routerとの共存時は警告が表示される

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | config-shared.ts | `packages/next/src/server/config-shared.ts` | **36-48行目**: `I18NConfig`と`DomainLocale`インターフェース |
| 1-2 | normalize-locale-path.ts | `packages/next/src/shared/lib/i18n/normalize-locale-path.ts` | **1-4行目**: `PathLocale`インターフェース（detectedLocale?, pathname） |

**読解のコツ**: I18NConfigの`locales`は`readonly string[]`型で不変配列として定義されている。

#### Step 2: ロケールパス正規化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | normalize-locale-path.ts | `packages/next/src/shared/lib/i18n/normalize-locale-path.ts` | **22-61行目**: `normalizeLocalePath`関数 |

**主要処理フロー**:
- **30-33行目**: WeakMapキャッシュによるロケール小文字変換の最適化
- **40行目**: パスの先頭2セグメントを分割
- **47行目**: 2番目のセグメントを小文字化してロケール一覧と照合
- **51-52行目**: indexOf照合でロケール検出
- **58行目**: パスからロケールプレフィックスを除去

#### Step 3: ドメインロケール検出を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | detect-domain-locale.ts | `packages/next/src/shared/lib/i18n/detect-domain-locale.ts` | **3-25行目**: `detectDomainLocale`関数（hostname/detectedLocaleでドメイン設定を照合） |

**主要処理フロー**:
- **16行目**: ドメインからポート番号を除去して小文字化
- **17-21行目**: hostname一致、defaultLocale一致、locales配列内一致のいずれかでマッチ

#### Step 4: ロケールリダイレクト判定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | get-locale-redirect.ts | `packages/next/src/shared/lib/i18n/get-locale-redirect.ts` | **70-117行目**: `getLocaleRedirect`関数 |

**主要処理フロー**:
- **34-54行目**: `detectLocale` - ロケール検出優先順位の実装
- **56-68行目**: `getAcceptPreferredLocale` - Accept-Languageヘッダーの解析
- **78-81行目**: localeDetection有効かつルートパス（"/"）の場合のみリダイレクト判定
- **92-106行目**: ドメインリダイレクト判定
- **108-115行目**: ロケールパスへのリダイレクト

### プログラム呼び出し階層図

```
リクエスト処理（Router Server）
    |
    +-- normalizeLocalePath(pathname, locales)
    |       └─ パスからロケール検出・除去
    |
    +-- detectDomainLocale(domains, hostname)
    |       └─ ドメインからロケール設定を検出
    |
    +-- getLocaleRedirect({...})
            +-- getAcceptPreferredLocale(i18n, headers)
            |       └─ acceptLanguage(header, locales)
            +-- detectLocale({...})
            |       └─ getLocaleFromCookie(i18n, headers)
            +-- detectDomainLocale(domains, undefined, preferredLocale)
            +-- formatUrl({...})  # リダイレクトURL生成
```

### データフロー図

```
[入力]                    [処理]                          [出力]

URLパス ──────────────▶ normalizeLocalePath() ──▶ detectedLocale + cleanPath
ホスト名 ─────────────▶ detectDomainLocale() ──▶ DomainLocale設定
Accept-Language ──────▶ getLocaleRedirect() ───▶ リダイレクトURL or undefined
NEXT_LOCALEクッキー ──┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| normalize-locale-path.ts | `packages/next/src/shared/lib/i18n/normalize-locale-path.ts` | ソース | URLパスのロケール検出・正規化 |
| detect-domain-locale.ts | `packages/next/src/shared/lib/i18n/detect-domain-locale.ts` | ソース | ドメインに基づくロケール検出 |
| get-locale-redirect.ts | `packages/next/src/shared/lib/i18n/get-locale-redirect.ts` | ソース | ロケールリダイレクト判定 |
| config-shared.ts | `packages/next/src/server/config-shared.ts` | ソース | I18NConfig、DomainLocale型定義 |
| config.ts | `packages/next/src/server/config.ts` | ソース | i18n設定の検証・正規化 |
| load-custom-routes.ts | `packages/next/src/lib/load-custom-routes.ts` | ソース | カスタムルートのロケール展開 |
| accept-header.ts | `packages/next/src/server/accept-header.ts` | ソース | Accept-Languageヘッダーの解析 |
