# 帳票設計書 33-テキスト国際化バンドル

## 概要

本ドキュメントは、Symfony IntlコンポーネントにおけるICU ResourceBundleテキスト形式ファイルの出力仕様を定義する帳票設計書である。`TextBundleWriter`クラスによるICU国際化データの`.txt`形式出力について、処理フロー、データ構造、出力形式を詳細に記載する。

### 本帳票の処理概要

ICU（International Components for Unicode）国際化データをICU ResourceBundleテキスト形式（`.txt`）のファイルとして出力する処理である。このテキスト形式はICUの標準BNF記法に準拠しており、`genrb`コマンドでバイナリ`.res`ファイルにコンパイル可能な中間形式として機能する。

**業務上の目的・背景**：ICU ResourceBundleのネイティブなテキスト表現形式で国際化データを出力することで、ICUのツールチェーン（`genrb`コマンドなど）との互換性を維持する。テキスト形式はICUの公式仕様に基づくBNF記法で記述されるため、ICUの他のツールやライブラリからも読み込み・変換が可能である。また、テキスト形式は人間が読解可能であり、データの検証やデバッグに適している。

**帳票の利用シーン**：Symfony Intlコンポーネントのデータ更新プロセスにおいて、ICUデータソースから取得した国際化データを、ICU ResourceBundleテキスト形式に変換する際に利用される。出力された`.txt`ファイルは、`GenrbCompiler`を使用してバイナリ`.res`ファイルにコンパイルされることもある。

**主要な出力内容**：
1. ロケール別の国際化データをICU ResourceBundle BNF記法で出力
2. テーブル型データ（キー・バリューのマップ構造）
3. 配列型データ（リスト構造）
4. 整数型データ（`:int{}`記法）
5. 整数ベクトル型データ（`:intvector{}`記法）
6. 文字列型データ（`""`記法）
7. フォールバック制御（`table(nofallback)`記法）

**帳票の出力タイミング**：ICUデータの更新時、またはSymfony Intlコンポーネントのビルドプロセス実行時。`AbstractDataGenerator::generateData()`メソッドの呼び出しに連動して自動実行される。

**帳票の利用者**：Symfonyフレームワークの開発者、Intlコンポーネントのメンテナー、ICUデータの更新を行うビルドプロセス。出力されたテキストファイルは`genrb`コマンドの入力としても利用される。

## 帳票種別

データエクスポートファイル（ICU ResourceBundleテキスト形式）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | CLIコマンド | N/A | AbstractDataGenerator::generateData()呼び出し |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（ICU ResourceBundle BNF記法） |
| 用紙サイズ | N/A（電子ファイル） |
| 向き | N/A |
| ファイル名 | `{locale}.txt`（例: `ja.txt`, `en.txt`, `root.txt`, `meta.txt`） |
| 出力方法 | ファイルシステムへの直接書き出し（fopen/fwrite/fclose） |
| 文字コード | UTF-8 |

### テキスト形式固有設定

| 項目 | 内容 |
|-----|------|
| インデント | スペース4文字（ネストレベルに応じて増加） |
| 記法仕様 | ICU ResourceBundle BNF記法準拠 |
| フォールバック制御 | `table(nofallback)`属性による制御が可能 |
| 特殊文字エスケープ | コロン（`:`）およびスペース（` `）を含むキーはダブルクォートで囲む |

## 帳票レイアウト

### レイアウト概要

ICU ResourceBundle BNF記法に基づくテキスト構造。ロケール名をルートバンドル名として、テーブル（キー・バリューのペア）で構成される。

```
┌─────────────────────────────────────┐
│  {locale名}{                        │
│      key1{"value1"}                 │
│      key2{                          │
│          nested_key{"nested_value"} │
│      }                              │
│      intKey:int{42}                 │
│      vectorKey:intvector{           │
│          1,                         │
│          2,                         │
│          3,                         │
│      }                              │
│  }                                  │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | バンドル名 | ロケール識別子（例: `ja`, `en`） | `$locale`引数 | テキスト（バンドル名として先頭に出力） |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | テーブルキー | リソースのキー名 | ICUソースデータ | テキスト（コロン/スペース含む場合はダブルクォート囲み） | N/A |
| 2 | 文字列値 | 文字列型リソース値 | ICUソースデータ | `{"value"}`形式または`"value"`形式 | N/A |
| 3 | 整数値 | 整数型リソース値 | ICUソースデータ | `:int{N}`形式 | N/A |
| 4 | 整数ベクトル値 | 整数配列型リソース値 | ICUソースデータ | `:intvector{N, ...}`形式 | N/A |
| 5 | 配列値 | 配列型リソース値 | ICUソースデータ | `{"item1", "item2", ...}`形式 | N/A |
| 6 | テーブル値 | ネストしたキー・バリュー構造 | ICUソースデータ | `{key{value} ...}`形式 | N/A |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | 閉じ括弧 | ルートテーブルの閉じ括弧 | 固定 | `}` + 改行 |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| ロケール | 出力対象のロケール識別子（例: ja, en, fr） | Yes |
| データ種別 | 通貨/言語/地域/スクリプト/タイムゾーン | Yes |
| 出力先パス | テキストファイルの出力ディレクトリパス | Yes |
| フォールバック | ロケールフォールバックの有効/無効（デフォルト: true） | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | テーブルキー | 元データの順序を保持 |

### 改ページ条件

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

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

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| N/A | 本帳票はデータベースを参照しない。ICUバイナリリソースバンドルファイルを入力とする | N/A |

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

#### ICUリソースバンドル（入力データ）

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| ICUバンドルデータ（配列/Traversable） | ResourceBundleテキスト形式 | ロケール単位で読み込み | `IntlBundleReader`経由で読み込まれたデータ |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| N/A | 本帳票に計算項目は存在しない | N/A | データの形式変換のみ実施 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[AbstractDataGenerator::generateData呼び出し] --> B[GeneratorConfig取得]
    B --> C[LocaleScanner::scanLocales実行]
    C --> D[ICUバンドルのコンパイル]
    D --> E{ロケールごとのループ}
    E --> F[generateDataForLocale実行]
    F --> G{データあり?}
    G -->|Yes| H[TextBundleWriter::write呼び出し]
    G -->|No| E
    H --> I[fopen でファイルオープン]
    I --> J[writeResourceBundle: バンドル名書き出し]
    J --> K[writeTable: ルートテーブル書き出し]
    K --> L{値の型判定}
    L -->|整数| M[writeInteger: :int 記法]
    L -->|整数配列| N[writeIntVector: :intvector 記法]
    L -->|文字列配列| O[writeArray: 配列記法]
    L -->|連想配列| P[writeTable: テーブル記法 - 再帰]
    L -->|文字列/ブール| Q[writeString: 文字列記法]
    M --> R[fclose]
    N --> R
    O --> R
    P --> R
    Q --> R
    R --> S[末尾改行出力]
    S --> E
    E --> T[rootデータ生成・書き出し]
    T --> U[metaデータ生成・書き出し]
    U --> V[一時ディレクトリ削除]
    V --> W[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| ファイルオープン失敗 | 出力先ディレクトリへの書き込み権限がない場合 | PHPのfopen警告/エラー | 出力先ディレクトリのパーミッションを確認 |
| ファイル書き込み失敗 | ディスク容量不足等 | PHPのfwrite警告/エラー | ディスク容量を確認 |
| Traversable変換失敗 | iterator_to_arrayが失敗する場合 | PHP実行時エラー | イテレータの実装を確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 約300ロケール x 5種別 = 約1500ファイル |
| 目標出力時間 | 全ロケール一括で数分以内 |
| 同時出力数上限 | 1（逐次処理） |

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

- 本帳票はICUの公開データを変換するものであり、個人情報は含まれない
- 出力ファイルはICU ResourceBundleテキスト形式であり、直接実行可能なコードではない
- `genrb`コマンドでコンパイルする際は、入力ファイルの信頼性を確認する必要がある
- `@internal`アノテーションにより、外部からの直接利用は非推奨

## 備考

- `TextBundleWriter`は`@internal`としてマークされており、Symfony内部でのみ利用される
- ICU ResourceBundle BNF記法の仕様は http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt を参照
- 出力された`.txt`ファイルは`GenrbCompiler`（`genrb`コマンドのラッパー）でバイナリ`.res`ファイルにコンパイル可能
- `$fallback`パラメータにより、`table(nofallback)`属性の付与を制御できる。`nofallback`を指定すると、ロケール階層での親ロケールへのフォールバックが無効化される
- 他のBundleWriter（JSON、PHP）と異なり、ストリーム書き込み（fopen/fwrite/fclose）を使用している
- ブール値は文字列`"true"`/`"false"`に変換されて出力される

---

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

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

### 推奨読解順序

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

まず、BundleWriterが受け取るデータ構造とインターフェースを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | BundleWriterInterface.php | `src/Symfony/Component/Intl/Data/Bundle/Writer/BundleWriterInterface.php` | `write(string $path, string $locale, mixed $data): void`メソッドのシグネチャを確認 |
| 1-2 | GeneratorConfig.php | `src/Symfony/Component/Intl/Data/Generator/GeneratorConfig.php` | BundleWriterの登録・管理方法を理解 |

**読解のコツ**: `TextBundleWriter::write()`は`BundleWriterInterface`の`write()`に加え、独自の`$fallback`パラメータ（行29）を持つ。インターフェース定義にはない追加パラメータであるため、直接呼び出し時にのみ利用可能。

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

処理の起点となる`AbstractDataGenerator`クラスからWriterが呼び出される流れを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AbstractDataGenerator.php | `src/Symfony/Component/Intl/Data/Generator/AbstractDataGenerator.php` | `generateData()`メソッド（行36-88）がメインの処理フロー |

**主要処理フロー**:
1. **行42**: `$writers = $config->getBundleWriters()` - 設定からWriter一覧を取得
2. **行60-68**: ロケールごとのループでデータ生成とWriter呼び出し
3. **行64-65**: `$writer->write(...)` - BundleWriterInterface経由での呼び出し

#### Step 3: テキスト出力の全体構造を理解する

`TextBundleWriter`の`write()`メソッドとルートの書き出し処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TextBundleWriter.php | `src/Symfony/Component/Intl/Data/Bundle/Writer/TextBundleWriter.php` | `write()`メソッド（行29-36）でファイルオープン、`writeResourceBundle`呼び出し、ファイルクローズの流れ |

**主要処理フロー**:
- **行31**: `fopen($path.'/'.$locale.'.txt', 'w')` - ファイルをライトモードでオープン
- **行33**: `$this->writeResourceBundle($file, $locale, $data, $fallback)` - ルートバンドルの書き出し
- **行35**: `fclose($file)` - ファイルクローズ

#### Step 4: 再帰的な型別出力処理を理解する

各データ型に応じた出力メソッドの分岐と再帰構造を読み解く。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | TextBundleWriter.php | `src/Symfony/Component/Intl/Data/Bundle/Writer/TextBundleWriter.php` | `writeResourceBundle()`（行46-53）→`writeTable()`→`writeResource()`の呼び出しチェーン |

**主要処理フロー**:
- **行46-53**: `writeResourceBundle()` - バンドル名を出力し、ルートテーブルを書き出す
- **行63-103**: `writeResource()` - 型判定による分岐
  - **行65-68**: 整数型 → `writeInteger()`
  - **行71-73**: Traversable → `iterator_to_array()`で配列に変換
  - **行76-85**: 配列の分岐判定
    - **行81-82**: 全要素が整数かつ0始まりの連番キー → `writeIntVector()`
    - **行87-88**: 0始まりの連番キー → `writeArray()`
    - **行93**: 連想配列 → `writeTable()`（再帰）
  - **行98-100**: ブール値 → 文字列`"true"`/`"false"`に変換
  - **行102**: 文字列 → `writeString()`
- **行112-115**: `writeInteger()` - `:int{N}`形式で出力
- **行124-133**: `writeIntVector()` - `:intvector{N, ...}`形式で出力
- **行142-151**: `writeString()` - `{"text"}`または`"text"`形式で出力
- **行160-173**: `writeArray()` - `{ "item1", "item2", ... }`形式で出力
- **行180-204**: `writeTable()` - `{ key{value} ... }`形式で出力。キーにコロンまたはスペースを含む場合はダブルクォートで囲む（行192-194）。`nofallback`属性の制御（行182-184）

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

```
AbstractDataGenerator::generateData()
    |
    +-- GeneratorConfig::getBundleWriters()
    |
    +-- [ロケールごとのループ]
            |
            +-- TextBundleWriter::write()
                    |
                    +-- fopen()  [ファイルオープン]
                    |
                    +-- writeResourceBundle()
                    |       |
                    |       +-- fwrite()  [バンドル名出力]
                    |       +-- writeTable()  [ルートテーブル]
                    |               |
                    |               +-- fwrite()  [開き括弧 + nofallback制御]
                    |               +-- [キーごとのループ]
                    |               |       |
                    |               |       +-- fwrite()  [キー名出力]
                    |               |       +-- writeResource()  [型判定・再帰]
                    |               |               |
                    |               |               +-- writeInteger()   [:int{N}]
                    |               |               +-- writeIntVector() [:intvector{...}]
                    |               |               +-- writeArray()     [{...}]
                    |               |               +-- writeTable()     [{key{val}}] ← 再帰
                    |               |               +-- writeString()    [{"text"}]
                    |               |
                    |               +-- fwrite()  [閉じ括弧]
                    |
                    +-- fclose()  [ファイルクローズ]
```

### データフロー図

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

ICUバイナリリソースバンドル ───> IntlBundleReader ───> 配列/Traversable
                                                          |
                                                          v
                                               AbstractDataGenerator
                                             (generateDataForLocale)
                                                          |
                                                          v
                                               TextBundleWriter::write()
                                                          |
                                              +-----------+-----------+
                                              |           |           |
                                          writeTable  writeArray  writeString
                                          (再帰的)    writeInt   writeIntVector
                                              |
                                              v
                                         fopen/fwrite/fclose
                                              |
                                              v
                                     {locale}.txt ファイル
                                              |
                                              v  (オプション)
                                     GenrbCompiler::compile()
                                              |
                                              v
                                     {locale}.res バイナリファイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| TextBundleWriter.php | `src/Symfony/Component/Intl/Data/Bundle/Writer/TextBundleWriter.php` | ソース | ICU ResourceBundleテキスト形式の書き出し |
| BundleWriterInterface.php | `src/Symfony/Component/Intl/Data/Bundle/Writer/BundleWriterInterface.php` | ソース | バンドルライターの共通インターフェース |
| AbstractDataGenerator.php | `src/Symfony/Component/Intl/Data/Generator/AbstractDataGenerator.php` | ソース | データ生成の抽象基底クラス（Writerの呼び出し元） |
| GeneratorConfig.php | `src/Symfony/Component/Intl/Data/Generator/GeneratorConfig.php` | ソース | Writer登録・ICUバージョン・ソースディレクトリの設定管理 |
| GenrbCompiler.php | `src/Symfony/Component/Intl/Data/Bundle/Compiler/GenrbCompiler.php` | ソース | `.txt`ファイルをバイナリ`.res`ファイルにコンパイル |
| BundleCompilerInterface.php | `src/Symfony/Component/Intl/Data/Bundle/Compiler/BundleCompilerInterface.php` | ソース | バンドルコンパイラの共通インターフェース |
| CurrencyDataGenerator.php | `src/Symfony/Component/Intl/Data/Generator/CurrencyDataGenerator.php` | ソース | 通貨データ生成の具体実装 |
| LanguageDataGenerator.php | `src/Symfony/Component/Intl/Data/Generator/LanguageDataGenerator.php` | ソース | 言語データ生成の具体実装 |
| RegionDataGenerator.php | `src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php` | ソース | 地域データ生成の具体実装 |
| ScriptDataGenerator.php | `src/Symfony/Component/Intl/Data/Generator/ScriptDataGenerator.php` | ソース | スクリプトデータ生成の具体実装 |
| TimezoneDataGenerator.php | `src/Symfony/Component/Intl/Data/Generator/TimezoneDataGenerator.php` | ソース | タイムゾーンデータ生成の具体実装 |
| IntlBundleReader.php | `src/Symfony/Component/Intl/Data/Bundle/Reader/IntlBundleReader.php` | ソース | ICUバイナリバンドルの読み込み |
