# 帳票設計書 5-翻訳テンプレートPOT

## 概要

本ドキュメントは、プロジェクト内の翻訳可能な文字列を抽出し、Gettext形式のPOTファイルとして出力する帳票の設計書である。

### 本帳票の処理概要

本帳票は、Godotプロジェクト内のスクリプトやシーンファイルから翻訳対象となる文字列を抽出し、GNU Gettext形式のPOT（Portable Object Template）ファイルとして出力する機能を提供する。国際化（i18n）対応のワークフローにおいて、翻訳者が作業するためのテンプレートファイルを生成する。

**業務上の目的・背景**：グローバル市場向けのゲームやアプリケーション開発では、多言語対応が必須である。Gettextは広く使われている翻訳フレームワークであり、poEditなどの翻訳ツールとの互換性がある。本帳票により、プロジェクト内の翻訳対象文字列を標準化された形式で出力し、翻訳ワークフローを効率化できる。

**帳票の利用シーン**：主に以下のシーンで利用される。1) 新規プロジェクトの国際化対応開始時、2) 新機能追加後の翻訳文字列更新時、3) 翻訳者への作業依頼時、4) 翻訳管理システムへのインポート時。

**主要な出力内容**：
1. POTファイルヘッダー（プロジェクト名、MIMEタイプ等）
2. 翻訳者向けコメント（#. TRANSLATORS:）
3. ファイル位置情報（#:）
4. コンテキスト情報（msgctxt）
5. 原文（msgid）と複数形（msgid_plural）
6. 空の翻訳文（msgstr）

**帳票の出力タイミング**：エディタのプロジェクト設定 > ローカライゼーション > POT生成で「Generate POT」ボタンをクリックした際に出力される。

**帳票の利用者**：ローカライゼーションエンジニア、翻訳コーディネーター、翻訳者

## 帳票種別

テンプレートファイル / 翻訳用データ出力

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | プロジェクト設定 | Project > Project Settings > Localization > POT Generation | 「Generate POT」ボタン |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | POT（Portable Object Template） |
| 用紙サイズ | N/A（テキストファイル） |
| 向き | N/A |
| ファイル名 | ユーザー指定（.potフィルター） |
| 出力方法 | プロジェクト設定からのファイル保存 |
| 文字コード | UTF-8 |

### POT固有設定

| 項目 | 内容 |
|-----|------|
| 形式 | GNU Gettext POT形式 |
| MIME-Version | 1.0 |
| Content-Type | text/plain; charset=UTF-8 |
| Content-Transfer-Encoding | 8-bit |

## 帳票レイアウト

### レイアウト概要

POTファイルは標準的なGettext形式に従う。

```
┌─────────────────────────────────────────────────────────────┐
│              ヘッダーコメント（対象ファイル一覧）               │
├─────────────────────────────────────────────────────────────┤
│              空のmsgidエントリ（メタデータ）                   │
├─────────────────────────────────────────────────────────────┤
│              翻訳エントリ1                                   │
│              （コメント、位置、msgctxt、msgid、msgstr）        │
├─────────────────────────────────────────────────────────────┤
│              翻訳エントリ2                                   │
│              ...                                            │
└─────────────────────────────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | ファイルリスト | 抽出対象ファイル一覧 | translations_pot_files設定 | # ファイルパス形式 |
| 2 | Project-Id-Version | プロジェクト名 | application/config/name | ヘッダー文字列 |
| 3 | MIME-Version | MIMEバージョン | 固定値 | 1.0 |
| 4 | Content-Type | コンテンツタイプ | 固定値 | text/plain; charset=UTF-8 |

### 明細部（翻訳エントリ）

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | コメント | 翻訳者向け説明 | MessageData::comments | #. TRANSLATORS: 形式 |
| 2 | ファイル位置 | 文字列の出所 | MessageData::locations | #: ファイル:行番号 形式 |
| 3 | コンテキスト | 同一文字列の区別用 | Translation::MessageKey::msgctxt | msgctxt "..." |
| 4 | 原文 | 翻訳対象文字列 | Translation::MessageKey::msgid | msgid "..." |
| 5 | 複数形原文 | 複数形の原文 | MessageData::plural | msgid_plural "..." |
| 6 | 翻訳文 | 空の翻訳（テンプレート） | 固定値 | msgstr "" |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| 抽出対象ファイル設定 | translations_pot_filesに対象ファイルが設定されている | Yes |
| パーサー対応 | 対象ファイルの拡張子に対応するパーサーが存在する | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | MessageMap内部順序 | HashMap内部順 |

### 改ページ条件

N/A（テキストファイルのため改ページなし）

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

### 参照テーブル一覧

本帳票はデータベースを参照せず、プロジェクト設定とソースファイルからデータを取得する。

| データソース | 用途 | 取得方法 |
|-----------|------|---------|
| internationalization/locale/translations_pot_files | 抽出対象ファイル一覧 | GLOBAL_GET |
| internationalization/locale/translation_add_builtin_strings_to_pot | 組み込み文字列追加フラグ | GLOBAL_GET |
| application/config/name | プロジェクト名 | GLOBAL_GET |
| EditorTranslationParser | ファイルからの文字列抽出 | get_singleton()->parse_file() |

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

#### プロジェクト設定

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|---------|----------------|---------|------|
| translations_pot_files | 抽出対象ファイルリスト | 常時 | Vector<String> |
| translation_add_builtin_strings_to_pot | 組み込み文字列追加 | 常時 | bool |
| application/config/name | プロジェクト名 | 常時 | String |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| エスケープ処理 | json_escape() | N/A | 特殊文字のエスケープ |
| 改行処理 | split("\n") | N/A | 複数行対応 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[generate呼び出し] --> B[プロジェクト設定から対象ファイル取得]
    B --> C[parse関数でファイル解析]
    C --> D{add_builtin?}
    D -->|Yes| E[組み込み文字列を追加]
    D -->|No| F[プロジェクト名を追加]
    E --> F
    F --> G[MessageMapを構築]
    G --> H{map空?}
    H -->|Yes| I[警告表示して終了]
    H -->|No| J[ファイルオープン]
    J --> K{拡張子判定}
    K -->|.pot| L[_write_to_pot呼び出し]
    K -->|.csv| M[_write_to_csv呼び出し]
    L --> N[ヘッダー書き込み]
    N --> O[エントリループ]
    O --> P[コメント書き込み]
    P --> Q[位置情報書き込み]
    Q --> R[msgctxt書き込み]
    R --> S[msgid書き込み]
    S --> T{plural存在?}
    T -->|Yes| U[msgid_plural/msgstr[0]/msgstr[1]書き込み]
    T -->|No| V[msgstr書き込み]
    U --> W{次のエントリ?}
    V --> W
    W -->|Yes| O
    W -->|No| X[終了]
    I --> X
    M --> X
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 翻訳文字列なし | mapが空 | "No translatable strings found." | WARN_PRINT_ED出力 |
| パーサー非対応 | 拡張子に対応するパーサーがない | "Cannot parse file '...': unrecognized file extension. Skipping." | ERR_CONTINUE_MSG |
| ファイルオープン失敗 | 書き込み権限なし等 | "Failed to open [path]" | ERR_FAIL_COND_MSG |
| 不正な拡張子 | .pot/.csv以外 | "Unrecognized translation template file extension: [ext]" | ERR_FAIL_MSG |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数百〜数千の翻訳文字列 |
| 目標出力時間 | プロジェクトサイズに依存 |
| 同時出力数上限 | 1（シングル処理） |

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

- プロジェクト内の文字列がすべて出力されるため、機密情報が含まれないか注意
- ファイルパスからプロジェクト構造が推測可能

## 備考

- 同一msgidでmsgctxtが異なる場合は別エントリとして扱われる
- 複数形（plural）定義が異なる場合は警告を出力してスキップ
- 組み込み文字列を追加するオプションにより、エンジン標準UIの翻訳も対応可能

---

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

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

### 推奨読解順序

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

まず、翻訳データの内部構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | template_generator.h | `editor/translations/template_generator.h` | MessageData、MessageMapの定義 |
| 1-2 | translation.h | `core/string/translation.h` | Translation::MessageKeyの構造 |

**読解のコツ**: MessageKeyはmsgctxtとmsgidの組み合わせで一意に識別される。MessageDataには複数形、コメント、位置情報が含まれる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | template_generator.cpp | `editor/translations/template_generator.cpp` | generate()（102-124行目）がエントリーポイント |

**主要処理フロー**:
1. **103-104行目**: プロジェクト設定から対象ファイルとadd_builtinフラグ取得
2. **106行目**: parse()でファイルを解析しMessageMapを構築
3. **107-110行目**: map空チェック、警告表示
4. **112-114行目**: FileAccess::openでファイルを開く
5. **116-123行目**: 拡張子に応じて_write_to_pot()または_write_to_csv()を呼び出し

#### Step 3: パース処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | template_generator.cpp | `editor/translations/template_generator.cpp` | parse()（37-99行目）でファイル解析 |

**主要処理フロー**:
- **40-62行目**: 各ファイルをEditorTranslationParserで解析
- **64-68行目**: add_builtinフラグに応じて組み込み文字列を追加
- **70-75行目**: プロジェクト名を翻訳対象として追加
- **77-98行目**: rawデータをMessageMapに変換、重複チェック

#### Step 4: POT出力処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | template_generator.cpp | `editor/translations/template_generator.cpp` | _write_to_pot()（152-214行目） |

**主要処理フロー**:
- **153-174行目**: ヘッダーの生成と書き込み
- **176-213行目**: 各エントリのループ処理（コメント、位置、msgctxt、msgid、msgstr）

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

```
TranslationTemplateGenerator::generate(p_file)
    │
    ├─ GLOBAL_GET("internationalization/locale/translations_pot_files")
    │
    ├─ GLOBAL_GET("internationalization/locale/translation_add_builtin_strings_to_pot")
    │
    ├─ parse(files, add_builtin)
    │      │
    │      ├─ EditorTranslationParser::get_singleton()->can_parse(extension)
    │      │
    │      ├─ get_parser(extension)->parse_file(path, &parsed)
    │      │
    │      ├─ get_extractable_message_list() [add_builtin時]
    │      │
    │      └─ GLOBAL_GET("application/config/name") [プロジェクト名追加]
    │
    ├─ FileAccess::open(p_file, WRITE)
    │
    └─ _write_to_pot(file, map) [拡張子が.potの場合]
           │
           ├─ ヘッダー書き込み
           │
           └─ エントリループ
                  │
                  ├─ コメント書き込み (#. TRANSLATORS:)
                  │
                  ├─ 位置情報書き込み (#:)
                  │
                  ├─ msgctxt書き込み
                  │
                  ├─ _write_pot_field("msgid", msgid)
                  │
                  └─ msgstr / msgid_plural+msgstr[n] 書き込み
```

### データフロー図

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

プロジェクト設定 ─────────▶ translations_pot_files ──────▶ 対象ファイルリスト
      │                                                         │
      │                                                         │
ソースファイル ──────────▶ EditorTranslationParser ──────▶ parsed (raw data)
      │                    parse_file()                         │
      │                                                         │
      │                                                         │
組み込み文字列 ──────────▶ get_extractable_message_list() ─▶ raw配列に追加
      │                                                         │
      │                                                         │
      └─────────────────▶ MessageMap構築 ─────────────────▶ MessageMap
                               │
                               │
                          _write_to_pot()
                               │
                               ▼
                          [POTファイル]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| template_generator.h | `editor/translations/template_generator.h` | ヘッダー | TranslationTemplateGeneratorクラス定義 |
| template_generator.cpp | `editor/translations/template_generator.cpp` | ソース | generate()、parse()、_write_to_pot()実装 |
| editor_translation_parser.h | `editor/translations/editor_translation_parser.h` | ヘッダー | EditorTranslationParserクラス定義 |
| translation.h | `core/string/translation.h` | ヘッダー | Translation::MessageKey定義 |
| localization_editor.cpp | `editor/translations/localization_editor.cpp` | ソース | UI側のPOT生成呼び出し |
| project_settings.h | `core/config/project_settings.h` | ヘッダー | GLOBAL_GETマクロ定義 |
