# 帳票設計書 31-JSON国際化バンドル

## 概要

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

### 本帳票の処理概要

ICU（International Components for Unicode）国際化データをJSON形式のファイルとして出力する処理である。通貨、言語、地域、スクリプト、タイムゾーンなどの国際化データを、ロケール単位でJSON形式のリソースバンドルファイルとして書き出す。

**業務上の目的・背景**：Webアプリケーションの国際化（i18n）対応において、ICUが提供する公式の国際化データ（通貨名称、言語名称、地域名称など）をSymfonyアプリケーションから効率的に参照できる形式に変換する必要がある。ICUのネイティブバイナリ形式ではPHPから直接扱いづらいため、JSON形式に変換することで、PHPだけでなくフロントエンドのJavaScript等からも容易にアクセス可能な汎用的なデータ形式として保存する。

**帳票の利用シーン**：Symfony Intlコンポーネントのデータ更新プロセス（`icu:update`コマンド相当の処理）において、ICUデータソースから最新の国際化データを取得し、アプリケーションが利用可能なJSON形式に変換する際に利用される。主に開発・ビルド工程で実行される。

**主要な出力内容**：
1. ロケール別の通貨データ（通貨コード、通貨名称、通貨記号）
2. ロケール別の言語データ（言語コード、言語名称）
3. ロケール別の地域データ（地域コード、地域名称）
4. ロケール別のスクリプトデータ（スクリプトコード、スクリプト名称）
5. ロケール別のタイムゾーンデータ（タイムゾーンID、表示名称）
6. メタデータ（サポートロケール一覧、エイリアス情報等）

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

**帳票の利用者**：Symfonyフレームワークの開発者、Intlコンポーネントのメンテナー、およびICUデータの更新を行うビルドプロセス。

## 帳票種別

データエクスポートファイル（国際化リソースバンドル）

## 利用画面

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

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JSON |
| 用紙サイズ | N/A（電子ファイル） |
| 向き | N/A |
| ファイル名 | `{locale}.json`（例: `ja.json`, `en.json`, `root.json`, `meta.json`） |
| 出力方法 | ファイルシステムへの直接書き出し |
| 文字コード | UTF-8（`JSON_UNESCAPED_UNICODE`オプションにより非ASCII文字もそのまま出力） |

### JSON固有設定

| 項目 | 内容 |
|-----|------|
| 整形出力 | 有（`JSON_PRETTY_PRINT`オプション使用） |
| Unicodeエスケープ | 無（`JSON_UNESCAPED_UNICODE`オプション使用） |
| 末尾改行 | 有（ファイル末尾に改行文字を付加） |

## 帳票レイアウト

### レイアウト概要

JSON形式のキー・バリュー構造。ロケールごとに1つのJSONファイルが生成される。データは階層的なオブジェクト構造を持つ。

```
┌─────────────────────────────────────┐
│         JSONルートオブジェクト         │
│  {                                  │
│    "key1": "value1",                │
│    "key2": {                        │
│      "nested_key": "nested_value"   │
│    },                               │
│    "key3": [1, 2, 3]                │
│  }                                  │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| N/A | N/A | JSONファイルにはヘッダー部は存在しない | N/A | N/A |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | ロケールデータキー | 国際化データの識別キー | ICUソースデータ | 文字列キー | N/A |
| 2 | ロケールデータ値 | 国際化データの値（文字列、数値、配列、オブジェクト） | ICUソースデータ | JSON値 | N/A |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| N/A | N/A | JSONファイルにはフッター部は存在しない | N/A | N/A |

## 出力条件

### 抽出条件

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

### ソート順

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

### 改ページ条件

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

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

### 参照テーブル一覧

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

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

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

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| ICUバンドルデータ（配列/Traversable） | JSONルートオブジェクト | ロケール単位で読み込み | `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[BundleWriterInterface::write呼び出し]
    G -->|No| E
    H --> I[Traversableをarrayに変換]
    I --> J[再帰的にTraversableを変換]
    J --> K[json_encode実行]
    K --> L[file_put_contents実行]
    L --> E
    E --> M[rootデータ生成・書き出し]
    M --> N[metaデータ生成・書き出し]
    N --> O[一時ディレクトリ削除]
    O --> P[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| ファイル書き込み失敗 | 出力先ディレクトリへの書き込み権限がない場合 | PHPのfile_put_contentsエラー | 出力先ディレクトリのパーミッションを確認 |
| JSONエンコード失敗 | データにJSON変換不可能な値が含まれる場合 | json_encodeの戻り値がfalse | 入力データの妥当性を確認 |
| Traversable変換失敗 | iterator_to_arrayが失敗する場合 | PHP実行時エラー | イテレータの実装を確認 |

## パフォーマンス要件

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

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

- 本帳票はICUの公開データを変換するものであり、個人情報は含まれない
- 出力ファイルはアプリケーションのソースコードリポジトリにコミットされるため、書き込み先ディレクトリのアクセス制御はリポジトリの権限管理に依存する
- `@internal`アノテーションにより、外部からの直接利用は非推奨

## 備考

- `JsonBundleWriter`は`@internal`としてマークされており、Symfony内部でのみ利用される
- 対応するリーダークラスとして`JsonBundleReader`が存在し、出力されたJSONファイルを読み込み可能
- `JSON_PRETTY_PRINT`オプションにより人間可読な整形出力が行われるが、ファイルサイズは圧縮形式と比較して大きくなる

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | BundleWriterInterface.php | `src/Symfony/Component/Intl/Data/Bundle/Writer/BundleWriterInterface.php` | `write(string $path, string $locale, mixed $data): void`メソッドのシグネチャを確認。3つの引数（出力先パス、ロケール、データ）を受け取りvoidを返す |
| 1-2 | GeneratorConfig.php | `src/Symfony/Component/Intl/Data/Generator/GeneratorConfig.php` | BundleWriterの登録・管理方法を理解。`addBundleWriter()`（行39）で出力先ディレクトリとWriterの対応を保持 |

**読解のコツ**: `BundleWriterInterface`は`@internal`であり、Symfony内部のデータ生成パイプラインでのみ使用される。`mixed $data`パラメータは実際には配列またはTraversableオブジェクトが渡される。

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AbstractDataGenerator.php | `src/Symfony/Component/Intl/Data/Generator/AbstractDataGenerator.php` | `generateData()`メソッド（行36-88）がメインの処理フロー。ロケールスキャン→コンパイル→データ生成→Writer呼び出しの流れ |

**主要処理フロー**:
1. **行42**: `$writers = $config->getBundleWriters()` - 設定からWriter一覧を取得
2. **行46-49**: 出力先ディレクトリの初期化（削除・再作成）
3. **行54**: `$locales = $this->scanLocales(...)` - 対象ロケール一覧のスキャン
4. **行56**: `$this->compileTemporaryBundles(...)` - ICUバンドルの一時コンパイル
5. **行60-68**: ロケールごとのループでデータ生成とWriter呼び出し
6. **行64-65**: `$writer->write($targetDir.'/'.$this->dirName, $locale, $localeData)` - 実際のファイル出力

#### Step 3: JSON出力処理を理解する

`JsonBundleWriter`の具体的な出力処理を読み解く。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | JsonBundleWriter.php | `src/Symfony/Component/Intl/Data/Bundle/Writer/JsonBundleWriter.php` | `write()`メソッド（行23-38）の全処理フロー。Traversable変換→再帰的変換→JSONエンコード→ファイル書き出し |

**主要処理フロー**:
- **行25-27**: トップレベルのTraversableオブジェクトをarray_iterator_to_arrayで配列に変換
- **行29-33**: `array_walk_recursive`で入れ子のTraversableも再帰的に配列へ変換
- **行35**: `json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)`で整形済みJSON文字列を生成し末尾に改行を付加
- **行37**: `file_put_contents($path.'/'.$locale.'.json', $contents)`でロケール名をファイル名としてJSON出力

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

```
AbstractDataGenerator::generateData()
    |
    +-- GeneratorConfig::getBundleWriters()
    |
    +-- LocaleScanner::scanLocales()
    |
    +-- BundleCompilerInterface::compile()  [一時バンドルコンパイル]
    |
    +-- [ロケールごとのループ]
    |       |
    |       +-- generateDataForLocale()  [抽象メソッド: 各ジェネレーター実装]
    |       |
    |       +-- JsonBundleWriter::write()
    |               |
    |               +-- iterator_to_array()  [Traversable→配列変換]
    |               +-- array_walk_recursive()  [再帰的変換]
    |               +-- json_encode()  [JSONエンコード]
    |               +-- file_put_contents()  [ファイル書き出し]
    |
    +-- generateDataForRoot()
    |
    +-- generateDataForMeta()
```

### データフロー図

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

ICUバイナリリソースバンドル ───> IntlBundleReader ───> 配列/Traversable
                                                          |
                                                          v
                                               AbstractDataGenerator
                                             (generateDataForLocale)
                                                          |
                                                          v
                                               JsonBundleWriter::write()
                                                          |
                                              +-----------+-----------+
                                              |                       |
                                     Traversable→配列変換      json_encode
                                              |                       |
                                              v                       v
                                                   file_put_contents
                                                          |
                                                          v
                                               {locale}.json ファイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| JsonBundleWriter.php | `src/Symfony/Component/Intl/Data/Bundle/Writer/JsonBundleWriter.php` | ソース | JSON形式のリソースバンドル書き出し |
| 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バージョン・ソースディレクトリの設定管理 |
| 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` | ソース | タイムゾーンデータ生成の具体実装 |
| JsonBundleReader.php | `src/Symfony/Component/Intl/Data/Bundle/Reader/JsonBundleReader.php` | ソース | JSON形式バンドルの読み込み（対応するリーダー） |
