# バッチ設計書 20-debug:translation

## 概要

本ドキュメントは、Symfony FrameworkBundleが提供する `debug:translation` コマンドのバッチ設計書である。このコマンドは、指定ロケールの翻訳メッセージ情報を表示し、未使用・未翻訳のメッセージを検出するためのデバッグ用CLIツールである。

### 本バッチの処理概要

`debug:translation` コマンドは、テンプレートから使用されている翻訳キーを抽出し、翻訳ファイルに定義された翻訳メッセージと比較することで、未翻訳（missing）、未使用（unused）、フォールバック一致（fallback）の状態を判定して一覧表示する。

**業務上の目的・背景**：多言語対応のSymfonyアプリケーションでは、翻訳ファイルとテンプレートの間で翻訳キーの整合性を保つ必要がある。テンプレートで使用しているが翻訳ファイルに定義されていないキー（未翻訳）や、翻訳ファイルに定義されているがテンプレートで使用されていないキー（未使用）を検出することで、翻訳の品質と完全性を確保する。国際化対応の品質管理において不可欠なツールである。

**バッチの実行タイミング**：随時実行（手動）。翻訳ファイルの更新後やリリース前の品質チェック時に実行する。

**主要な処理内容**：
1. 翻訳パスとコードパスを決定する（バンドル指定、ディレクトリ指定、または全バンドル対象）
2. テンプレートから使用されている翻訳キーを抽出する（ExtractorInterface）
3. 翻訳ファイルから定義済み翻訳メッセージを読み込む（TranslationReaderInterface）
4. 抽出メッセージと定義メッセージをマージし、各メッセージの状態（missing/unused/fallback）を判定する
5. フォールバックロケールの翻訳カタログも読み込み、フォールバック一致を検出する
6. テーブル形式で結果を出力する

**前後の処理との関連**：`translation:extract` コマンドは未翻訳キーを翻訳ファイルに追加する処理を行う。本コマンドで検出されたmissingキーを `translation:extract` で翻訳ファイルに追加するワークフローが一般的である。

**影響範囲**：読み取り専用の操作であり、翻訳ファイルやテンプレートを変更しない。テンプレートの解析とファイル読み込みにより一定のI/Oを発生させる。

## バッチ種別

デバッグ / 翻訳情報表示

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 随時 |
| 実行時刻 | 任意 |
| 実行曜日 | 該当なし |
| 実行日 | 該当なし |
| トリガー | 手動 |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| TranslatorInterfaceが登録されている | 翻訳サービスがDIコンテナに存在すること |
| TranslationReaderInterfaceが登録されている | 翻訳ファイル読み取りサービスが存在すること |
| ExtractorInterfaceが登録されている | テンプレートからの翻訳キー抽出サービスが存在すること |

### 実行可否判定

指定されたバンドルやディレクトリが存在しない場合はInvalidArgumentExceptionが発生する。翻訳メッセージが見つからない場合は警告メッセージを表示してEXIT_CODE_GENERAL_ERROR (64) を返す。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| locale | string | Yes | なし | 検査対象のロケール |
| bundle | string | No | null | バンドル名またはディレクトリパス |
| --domain | string | No | null | 検査対象の翻訳ドメイン |
| --only-missing | bool | No | false | 未翻訳メッセージのみ表示する |
| --only-unused | bool | No | false | 未使用メッセージのみ表示する |
| --all | bool | No | false | 全登録バンドルの翻訳を対象にする |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| 翻訳ファイル | YAML/XML/PHP/XLIFF等 | 定義済み翻訳メッセージ |
| テンプレートファイル | Twig/PHP | 翻訳キーの使用箇所 |
| フォールバックロケール設定 | Translator設定 | フォールバックロケールの翻訳カタログ |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| 標準出力 | テーブル | State, Domain, Id, Message Preview, Fallback Message Preview のカラムを持つテーブル |

### 出力ファイル仕様

ファイル出力はなし。

## 処理フロー

### 処理シーケンス

```
1. 翻訳パスとコードパスの決定
   └─ bundle引数なし：デフォルトの翻訳パスとコードパスを使用
   └─ bundle引数あり：
      └─ バンドルとして解決可能：バンドルの翻訳パスとテンプレートパスを使用
      └─ バンドル不明：ディレクトリパスとして扱う
   └─ --all指定：全バンドルの翻訳パスとテンプレートパスを追加
2. テンプレートからの翻訳キー抽出
   └─ ExtractorInterface::extract でテンプレートからMessageCatalogueを生成
3. 翻訳ファイルからの定義メッセージ読み込み
   └─ TranslationReaderInterface::read で翻訳ファイルからMessageCatalogueを生成
4. メッセージのマージ
   └─ MergeOperation で抽出カタログと定義カタログをマージ
   └─ --domain指定時はドメインでフィルタリング
5. メッセージが存在しない場合
   └─ 警告メッセージを表示してEXIT_CODE_GENERAL_ERROR (64) で終了
6. フォールバックカタログの読み込み
   └─ Translator/DataCollectorTranslator/LoggingTranslatorのフォールバックロケール設定から読み込み
7. 各メッセージの状態判定
   └─ 抽出にあり+定義になし → MESSAGE_MISSING (missing)
   └─ 抽出になし+定義にあり → MESSAGE_UNUSED (unused)
   └─ フォールバックロケールの値と同一 → MESSAGE_EQUALS_FALLBACK (fallback)
8. フィルタリング
   └─ --only-missing: unused メッセージを除外
   └─ --only-unused: missing メッセージを除外
9. テーブル形式で結果を出力
10. 終了コード
   └─ missing検出時: EXIT_CODE_MISSING (65) をOR加算
   └─ unused検出時: EXIT_CODE_UNUSED (66) をOR加算
   └─ fallback検出時: EXIT_CODE_FALLBACK (68) をOR加算
```

### フローチャート

```mermaid
flowchart TD
    A[コマンド開始] --> B[翻訳パスとコードパスの決定]
    B --> C[テンプレートから翻訳キーを抽出]
    C --> D[翻訳ファイルから定義メッセージを読み込み]
    D --> E[MergeOperationでマージ]
    E --> F{メッセージ存在?}
    F -->|いいえ| G[警告: メッセージなし]
    G --> H[EXIT_CODE_GENERAL_ERROR で終了]
    F -->|はい| I[フォールバックカタログ読み込み]
    I --> J[各メッセージの状態判定]
    J --> K[--only-missing/--only-unusedフィルタ]
    K --> L[テーブル形式で出力]
    L --> M[ビットOR終了コードで終了]
```

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

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

データベースへの操作は行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 64 | メッセージなし | 指定ロケール（+ドメイン）で翻訳メッセージが見つからない | ロケール名・ドメイン名を確認する |
| InvalidArgumentException | パス不正 | bundle引数で指定したパスが存在しない | 正しいバンドル名またはディレクトリパスを指定する |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

### 障害時対応

翻訳ファイルやテンプレートのパスが正しいか確認する。バンドル名で解決できない場合はディレクトリパスを直接指定する。

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | 該当なし（読み取り専用） |
| コミットタイミング | 該当なし |
| ロールバック条件 | 該当なし |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 翻訳キー数（数十〜数千、プロジェクト規模に依存） |
| 目標処理時間 | 数秒〜数十秒（テンプレート解析量に依存） |
| メモリ使用量上限 | テンプレートと翻訳ファイルの読み込みに必要なメモリ |

## 排他制御

読み取り専用操作のため排他制御は不要。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 警告ログ | メッセージなし時 | 「No defined or extracted messages for locale "{locale}"」 |
| テーブル出力 | 結果表示時 | State, Domain, Id, Message Preview, Fallback Message Preview |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 該当なし | 該当なし | 該当なし |

手動実行コマンドのため、定常的な監視・アラートは設定しない。

## 備考

- 終了コードはビットORで構成される：0（成功）、64（一般エラー）、65（missing検出）、66（unused検出）、68（fallback検出）
- --only-missingと--only-unusedオプションは表示フィルタであり、終了コードにも影響する（フィルタされたカテゴリは終了コードに加算されない）
- フォールバックロケールの取得はTranslator, DataCollectorTranslator, LoggingTranslatorのいずれかに対応
- メッセージプレビューは40文字にサニタイズ（トリム＋空白正規化＋切り詰め）される
- バンドル指定時はデフォルト翻訳パス（defaultTransPath）とデフォルトビューパス（defaultViewsPath）も追加される
- --allオプション指定時は全登録バンドルの翻訳パスとテンプレートパスが追加される
- シェル補完機能があり、locale引数でenabledLocales候補、bundle引数でバンドル名候補、--domainオプションでドメイン名候補が表示される
- バンドルのtranslationsディレクトリは新旧両方のパス（Resources/translations と translations）に対応
