# 機能設計書 47-翻訳サービス

## 概要

本ドキュメントは、Laravel Frameworkの翻訳サービス機能の設計仕様を定義する。Translatorクラスを中心とした、多言語対応（国際化/i18n）機能について詳述する。

### 本機能の処理概要

翻訳サービスは、アプリケーションの多言語対応を実現する機能を提供する。翻訳ファイル（PHPファイル、JSONファイル）からテキストを読み込み、ロケールに応じた適切な翻訳を返却する。プレースホルダー置換、複数形対応、フォールバックロケールなどの機能を備える。

**業務上の目的・背景**：グローバル展開するアプリケーションでは、ユーザーの言語に応じた表示が必要となる。翻訳サービスにより、UIテキスト、エラーメッセージ、メール本文などを複数言語で提供でき、ユーザー体験の向上とグローバル市場への対応が可能になる。

**機能の利用シーン**：Bladeテンプレートでの多言語表示、バリデーションメッセージの翻訳、メール本文の多言語対応、APIレスポンスの国際化などで利用される。

**主要な処理内容**：
1. 翻訳キーから翻訳テキストの取得（get）
2. 複数形対応（choice）
3. プレースホルダー置換
4. フォールバックロケール対応
5. 名前空間による翻訳ファイル分離
6. JSON翻訳ファイル対応

**関連システム・外部連携**：翻訳ファイル（lang/*.php、lang/*.json）、Bladeテンプレート、バリデーションシステムと連携する。

**権限による制御**：翻訳サービス自体には権限制御は存在しない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングに翻訳サービス関連の画面なし |

## 機能種別

テキスト変換 / 国際化

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| key | string | Yes | 翻訳キー（例: messages.welcome、validation.required） | - |
| replace | array | No | プレースホルダー置換データ | - |
| locale | string\|null | No | ロケール（null時はデフォルトロケール） | - |
| fallback | bool | No | フォールバック有効/無効 | - |
| number | int\|float\|array | No（choice時） | 複数形判定用の数値 | - |

### 入力データソース

- 翻訳ファイル（lang/{locale}/*.php）
- JSON翻訳ファイル（lang/{locale}.json）
- アプリケーションコードからの__()、trans()呼び出し
- Bladeテンプレートからの@lang、{{ __() }}

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| translation | string\|array | 翻訳されたテキスト（配列キーの場合は配列） |

### 出力先

- 呼び出し元への戻り値

## 処理フロー

### 処理シーケンス

```
1. 翻訳キー解析
   └─ parseKey()で名前空間、グループ、アイテムに分解

2. JSON翻訳確認
   └─ まずJSON翻訳ファイル（*.*）を確認

3. PHP翻訳ファイル読み込み
   └─ load()でファイルから翻訳データをロード

4. ロケール配列構築
   └─ localeArray()でロケールとフォールバックの配列を構築

5. 翻訳行取得
   └─ getLine()で該当する翻訳を取得

6. プレースホルダー置換
   └─ makeReplacements()で:name形式のプレースホルダーを置換

7. 結果返却
   └─ 翻訳が見つからない場合はキーをそのまま返却
```

### フローチャート

```mermaid
flowchart TD
    A[翻訳リクエスト] --> B[load JSON翻訳]
    B --> C{JSON翻訳あり?}
    C -->|Yes| D[JSON翻訳を使用]
    C -->|No| E[parseKey でキー解析]
    E --> F[localeArray 構築]
    F --> G{各ロケールをループ}
    G --> H[load PHP翻訳]
    H --> I[getLine で取得]
    I --> J{翻訳あり?}
    J -->|Yes| K[makeReplacements]
    J -->|No| L{次のロケール?}
    L -->|Yes| G
    L -->|No| M[キーをそのまま返却]
    D --> K
    K --> N[翻訳結果返却]
    M --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-47-1 | JSON優先 | JSON翻訳ファイルを最初に確認 | get()呼び出し時 |
| BR-47-2 | フォールバック | 指定ロケールで見つからない場合はフォールバックロケールを使用 | fallback=true（デフォルト） |
| BR-47-3 | キー返却 | 翻訳が見つからない場合はキーをそのまま返却 | 翻訳未定義時 |
| BR-47-4 | 複数形判定 | choice()ではMessageSelectorで適切な複数形を選択 | choice()呼び出し時 |
| BR-47-5 | 大文字小文字置換 | :Name、:NAME形式で大文字変換も自動適用 | makeReplacements()内 |

### 計算ロジック

| 計算名 | 計算式 | 説明 |
|--------|-------|------|
| 複数形選択 | MessageSelector::choose() | 数値に基づいて適切な複数形テキストを選択 |

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

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | 翻訳サービス自体はデータベース操作を行わない |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| InvalidArgumentException | ロケール不正 | ロケールに/または\を含む場合 | 正しいロケール形式を使用 |

### リトライ仕様

リトライ処理は実装されていない。

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

翻訳サービスはトランザクション管理を行わない。

## パフォーマンス要件

- 翻訳ファイルは一度読み込まれると$loadedにキャッシュ
- 同一リクエスト内での重複読み込みを回避

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

- ロケールにディレクトリトラバーサル文字（/、\）が含まれないよう検証
- ユーザー入力をそのままロケールとして使用しないこと

## 備考

- __()ヘルパー関数が一般的な呼び出し方法
- Macroableトレイトによる拡張が可能

---

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

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

### 推奨読解順序

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

Translatorが管理する内部状態を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Translator.php | `src/Illuminate/Translation/Translator.php` | プロパティ定義（26-82行目）で管理される状態を把握 |
| 1-2 | Translator.php（Contract） | `src/Illuminate/Contracts/Translation/Translator.php` | インターフェース定義 |

**読解のコツ**: $loaderが翻訳ファイル読み込み担当、$localeが現在のロケール、$loadedがキャッシュ済み翻訳データ、$selectorが複数形選択担当。

#### Step 2: エントリーポイントを理解する

翻訳取得の入口を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Translator.php | `src/Illuminate/Translation/Translator.php` | get()（151-190行目）がメインエントリー |
| 2-2 | Translator.php | `src/Illuminate/Translation/Translator.php` | has()（117-140行目）で翻訳存在確認 |

**主要処理フロー**:
1. **153行目**: ロケール決定（指定がなければデフォルト）
2. **158行目**: JSON翻訳をロード
3. **160行目**: JSON翻訳から検索
4. **165-179行目**: PHP翻訳ファイルから検索
5. **189行目**: makeReplacements()でプレースホルダー置換

#### Step 3: 翻訳ファイル読み込みを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Translator.php | `src/Illuminate/Translation/Translator.php` | load()（329-341行目） |
| 3-2 | FileLoader.php | `src/Illuminate/Translation/FileLoader.php` | 実際のファイル読み込み実装 |

**主要処理フロー**:
- **331-333行目**: 既にロード済みならスキップ
- **338行目**: $loaderのload()を呼び出し
- **340行目**: $loadedにキャッシュ

#### Step 4: プレースホルダー置換を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Translator.php | `src/Illuminate/Translation/Translator.php` | makeReplacements()（271-302行目） |

**主要処理フロー**:
- **280-288行目**: Closureの場合はコールバック実行
- **290-294行目**: オブジェクトの場合はstringableHandlersを確認
- **296-298行目**: :key、:Key、:KEY形式で置換

#### Step 5: 複数形対応を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | Translator.php | `src/Illuminate/Translation/Translator.php` | choice()（201-221行目） |
| 5-2 | MessageSelector.php | `src/Illuminate/Translation/MessageSelector.php` | 複数形選択ロジック |

**主要処理フロー**:
- **203-205行目**: 翻訳を取得
- **210-211行目**: 配列/Countableの場合はcount
- **218-220行目**: MessageSelectorで適切な複数形を選択

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

```
__($key, $replace, $locale) [ヘルパー関数]
    │
    └─ Translator::get($key, $replace, $locale, $fallback)
           │
           ├─ load('*', '*', $locale) [JSON翻訳]
           │
           ├─ $loaded['*']['*'][$locale][$key] [JSON検索]
           │
           ├─ parseKey($key)
           │      └─ [$namespace, $group, $item]
           │
           ├─ localeArray($locale)
           │      └─ [$locale, $fallback]
           │
           └─ getLine($namespace, $group, $locale, $item, $replace)
                  │
                  ├─ load($namespace, $group, $locale)
                  │      └─ $loader->load()
                  │
                  ├─ Arr::get($loaded[$namespace][$group][$locale], $item)
                  │
                  └─ makeReplacements($line, $replace)
                         │
                         ├─ [Closure] preg_replace_callback
                         │
                         ├─ [Object] stringableHandlers
                         │
                         └─ strtr($line, $shouldReplace)

Translator::choice($key, $number, $replace, $locale)
    │
    ├─ get($key, [], $locale)
    │
    └─ getSelector()->choose($line, $number, $locale)
           └─ MessageSelector::choose()
```

### データフロー図

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

$key             ───▶  parseKey()               ───▶  [$namespace, $group, $item]
(翻訳キー)              (キー解析)

$locale          ───▶  localeArray()            ───▶  [$locale, $fallback]
(ロケール)              (ロケール配列構築)

$namespace,$group ───▶ load()                   ───▶  $loaded[$ns][$grp][$loc]
(名前空間,グループ)     (ファイル読み込み)

$line, $replace  ───▶  makeReplacements()       ───▶  置換済みテキスト
(翻訳文,置換データ)     (プレースホルダー置換)

$line, $number   ───▶  MessageSelector::choose() ───▶ 複数形テキスト
(翻訳文,数値)           (複数形選択)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Translator.php | `src/Illuminate/Translation/Translator.php` | ソース | 翻訳のメイン実装 |
| TranslationServiceProvider.php | `src/Illuminate/Translation/TranslationServiceProvider.php` | ソース | サービスプロバイダ |
| FileLoader.php | `src/Illuminate/Translation/FileLoader.php` | ソース | ファイル読み込み |
| ArrayLoader.php | `src/Illuminate/Translation/ArrayLoader.php` | ソース | 配列ベースのローダー |
| MessageSelector.php | `src/Illuminate/Translation/MessageSelector.php` | ソース | 複数形選択 |
| Loader.php | `src/Illuminate/Contracts/Translation/Loader.php` | コントラクト | ローダーインターフェース |
| Translator.php | `src/Illuminate/Contracts/Translation/Translator.php` | コントラクト | 翻訳インターフェース |
