# 帳票設計書 2-CSV翻訳ファイル

## 概要

Symfonyの翻訳コンポーネントにおけるCSV形式の翻訳ファイル出力機能の設計書である。メッセージカタログをセミコロン区切りのCSVファイルとして出力する。

### 本帳票の処理概要

本帳票は、Symfonyアプリケーション内部のメッセージカタログ（MessageCatalogue）に格納された翻訳メッセージを、CSV形式のテキストファイルとして出力する機能を提供する。

**業務上の目的・背景**：CSVは最も汎用的なデータ交換フォーマットの一つであり、スプレッドシートアプリケーション（Excel、Google Sheets等）で直接編集できる。翻訳リソースをCSV形式で出力することで、翻訳者が特別なツールを必要とせず、一般的なスプレッドシートソフトウェアで翻訳作業を行える。また、翻訳データのバルクインポート・エクスポートにも適している。

**帳票の利用シーン**：翻訳データのスプレッドシートへのエクスポート時、翻訳者への翻訳依頼データ送付時、翻訳データの一括管理・編集時、他システムとの翻訳データ連携時に利用される。

**主要な出力内容**：
1. セミコロン区切りのCSVデータ（デフォルト区切り文字: `;`）
2. 各行にソース文字列とターゲット文字列のペアを含む
3. ダブルクォートによるフィールド囲み

**帳票の出力タイミング**：`translation:update`コマンド実行時（format指定）、またはプログラム内から`CsvFileDumper::dump()`メソッドを呼び出した時に出力される。

**帳票の利用者**：アプリケーション開発者、翻訳者、ローカライゼーションマネージャー

## 帳票種別

翻訳データファイル（CSVテキスト）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | CLIコマンド | `php bin/console translation:update` | コマンド実行（--output-format=csv） |
| N/A | プログラムAPI | `CsvFileDumper::dump()` | メソッド呼び出し |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | CSV（セミコロン区切り） |
| 用紙サイズ | N/A（データファイル） |
| 向き | N/A |
| ファイル名 | `%domain%.%locale%.csv`（デフォルト、relativePathTemplateで変更可能） |
| 出力方法 | ファイルシステムへの書き込み（file_put_contents） |
| 文字コード | PHP環境に依存（fputcsvの出力エンコーディング） |

### CSV固有設定

| 項目 | 内容 |
|-----|------|
| 区切り文字 | `;`（セミコロン、setCsvControl()で変更可能） |
| 囲み文字 | `"`（ダブルクォート、setCsvControl()で変更可能） |
| エスケープ文字 | `\`（バックスラッシュ） |
| ヘッダー行 | なし |

## 帳票レイアウト

### レイアウト概要

CSVファイルの各行に、ソース文字列（翻訳キー）とターゲット文字列（翻訳値）のペアが出力される。

```
┌─────────────────────────────────────┐
│ "source1";"target1"                  │
│ "source2";"target2"                  │
│ "source3";"target3"                  │
│ ...                                  │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| N/A | なし | CSVヘッダー行は出力されない | - | - |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | source | 翻訳キー（原文） | MessageCatalogue::all($domain)のキー | CSVフィールド（ダブルクォート囲み） | 可変 |
| 2 | target | 翻訳値（訳文） | MessageCatalogue::all($domain)の値 | CSVフィールド（ダブルクォート囲み） | 可変 |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| N/A | なし | CSVフッターは出力されない | - | - |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| path | 出力先ディレクトリパス | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | メッセージカタログの格納順 | 格納順（挿入順） |

### 改ページ条件

N/A（データファイルのため改ページなし）

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| N/A | 本帳票はデータベースを直接参照しない。MessageCatalogueオブジェクトを入力とする | - |

### テーブル別参照項目詳細

本帳票はデータベースを直接参照せず、MessageCatalogueオブジェクトからデータを取得する。

#### MessageCatalogue（入力データ構造）

| 参照項目（プロパティ） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| messages[$domain] | source;target行 | all($domain) | ドメイン別メッセージ配列 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| N/A | 特になし（fputcsvによるCSVフォーマットのみ） | N/A | PHPのfputcsv関数がエスケープ処理を行う |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[dump呼び出し] --> B{pathオプション存在?}
    B -->|No| C[InvalidArgumentException]
    B -->|Yes| D[ドメインループ開始]
    D --> E[formatCatalogue呼び出し]
    E --> F[php://memoryストリーム生成]
    F --> G[メッセージループ]
    G --> H[fputcsvで行出力]
    H --> G
    G -->|ループ完了| I[ストリーム内容取得]
    I --> J[file_put_contentsで書き込み]
    J --> D
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| InvalidArgumentException | pathオプションが未指定 | "The file dumper needs a path option." | pathオプションを指定する |
| RuntimeException | 出力先ディレクトリの作成失敗 | 'Unable to create directory "%s".' | ディレクトリの書き込み権限を確認する |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数百〜数千メッセージ/ドメイン |
| 目標出力時間 | 特に規定なし |
| 同時出力数上限 | 特に規定なし |

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

- PHPのfputcsv関数がCSVエスケープ処理を行うため、区切り文字・囲み文字のインジェクションは防止される
- 出力先ディレクトリのパーミッションは0o777で作成される（umaskにより制限される）
- CSVインジェクション（数式インジェクション）対策は本Dumperの責務外

## 備考

- php://memoryストリームを使用して一旦メモリ上にCSVデータを構築し、その後文字列として返す実装となっている
- setCsvControl()メソッドで区切り文字と囲み文字をカスタマイズ可能
- INTL-ICUドメインサフィックス付きメッセージは親クラスFileDumperの仕組みにより別ファイルとして出力される

---

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

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

### 推奨読解順序

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

メッセージカタログの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | MessageCatalogueInterface.php | `src/Symfony/Component/Translation/MessageCatalogueInterface.php` | all()メソッドの定義を確認 |
| 1-2 | MessageCatalogue.php | `src/Symfony/Component/Translation/MessageCatalogue.php` | messages配列の構造を理解する |

**読解のコツ**: CsvFileDumperはメタデータを使用しないため、MessageCatalogueのall($domain)で返されるkey-value配列のみが重要。

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

FileDumperのdump()メソッドからformatCatalogue()が呼ばれる流れを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | FileDumper.php | `src/Symfony/Component/Translation/Dumper/FileDumper.php` | dump()メソッドの共通フロー（41-77行目）を理解する |

**主要処理フロー**:
1. **41-45行目**: pathオプション必須チェック
2. **48行目**: ドメインループ
3. **76行目**: formatCatalogue()呼び出しとfile_put_contents()

#### Step 3: CSV固有のフォーマット処理を理解する

CsvFileDumperのformatCatalogue()メソッドを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CsvFileDumper.php | `src/Symfony/Component/Translation/Dumper/CsvFileDumper.php` | php://memoryストリームを使ったCSV生成処理を理解する |

**主要処理フロー**:
- **23-24行目**: デフォルトの区切り文字（`;`）と囲み文字（`"`）の定義
- **28行目**: php://memoryストリームのオープン
- **30-31行目**: メッセージループでfputcsvにより各行を出力
- **34-36行目**: ストリームの巻き戻しと内容取得
- **44-48行目**: setCsvControl()によるカスタマイズメソッド

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

```
DumperInterface::dump()
    │
    └─ FileDumper::dump()                          [FileDumper.php:41]
           │
           ├─ MessageCatalogue::getDomains()        [MessageCatalogue.php:42]
           ├─ FileDumper::getRelativePath()          [FileDumper.php:93]
           │      └─ CsvFileDumper::getExtension()   [CsvFileDumper.php:50]
           ├─ MessageCatalogue::all($intlDomain)     [MessageCatalogue.php:56]
           └─ CsvFileDumper::formatCatalogue()       [CsvFileDumper.php:26]
                  │
                  ├─ fopen('php://memory')
                  ├─ MessageCatalogue::all($domain)   [MessageCatalogue.php:56]
                  ├─ fputcsv()（ループ）
                  ├─ rewind()
                  ├─ stream_get_contents()
                  └─ fclose()
```

### データフロー図

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

MessageCatalogue ───────▶ FileDumper::dump()
  ├─ locale                     │
  └─ messages[domain]           ├─ ドメインループ
                                │     │
                options ────────▶     ├─ formatCatalogue()
                  └─ path              │     │
                                      │     ├─ php://memory生成
                                      │     ├─ fputcsv()ループ ───▶ {domain}.{locale}.csv
                                      │     └─ stream_get_contents()  （CSV文書）
                                      │
                                      └─ file_put_contents()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| DumperInterface.php | `src/Symfony/Component/Translation/Dumper/DumperInterface.php` | ソース | Dumperインターフェース定義 |
| FileDumper.php | `src/Symfony/Component/Translation/Dumper/FileDumper.php` | ソース | ファイル出力共通基底クラス |
| CsvFileDumper.php | `src/Symfony/Component/Translation/Dumper/CsvFileDumper.php` | ソース | CSV形式固有のフォーマット処理 |
| MessageCatalogue.php | `src/Symfony/Component/Translation/MessageCatalogue.php` | ソース | メッセージカタログデータ構造 |
| MessageCatalogueInterface.php | `src/Symfony/Component/Translation/MessageCatalogueInterface.php` | ソース | メッセージカタログインターフェース |
