# バッチ設計書 15-translateNewKeys

## 概要

本ドキュメントは、Payload CMSの翻訳パッケージにおける新規翻訳キー自動翻訳バッチ（translateNewKeys）の処理設計を定義する。

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

translateNewKeysは、英語の翻訳ファイルに追加された新規キーを検出し、OpenAI GPT-4 APIを使用して40以上のサポート言語に自動翻訳するバッチ処理である。

**業務上の目的・背景**：Payload CMSは40以上の言語をサポートする国際化対応CMSである。新機能追加やUI改善の際、英語の翻訳キーが追加されるが、手動で全言語に翻訳するのは膨大な作業となる。本バッチは、英語ファイルを基準として他言語ファイルとの差分を検出し、不足しているキーをAIで自動翻訳することで、多言語対応の保守作業を大幅に効率化する。

**バッチの実行タイミング**：開発者がCLIコマンド（`pnpm run translateNewKeys`）を実行した時点で手動実行される。新機能開発後のリリース準備時、または定期的な翻訳更新時に使用。

**主要な処理内容**：
1. 英語翻訳ファイル（enTranslations）の読み込み
2. 全サポート言語の翻訳ファイル読み込み
3. 各言語に存在しないキー（missingKeys）の検出
4. 英語に存在しないキー（obsoleteKeys）の検出と削除
5. OpenAI GPT-4 APIを使用した翻訳（並列度制限あり）
6. 翻訳結果のマージと言語ファイルへの書き込み
7. ESLint自動修正とPrettierフォーマット適用

**前後の処理との関連**：翻訳システム（packages/translations）のメンテナンスツール。本番コード（initI18n等）で使用される翻訳ファイルを生成・更新する。Lexicalエディタ用（richtext-lexical）やプラグイン用の翻訳も同様のスクリプトで処理可能。

**影響範囲**：`packages/translations/src/languages/*.ts`ファイルの更新。Payload CMSの管理画面UI、バリデーションメッセージ、エラーメッセージの多言語表示に影響。

## バッチ種別

データ変換処理 / 翻訳自動化 / 開発支援ツール

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 随時（開発時） |
| 実行時刻 | 任意 |
| 実行曜日 | 任意 |
| 実行日 | 任意 |
| トリガー | 手動（CLIコマンド） |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| OpenAI APIキー | 環境変数OPENAI_KEYが設定されていること |
| Node.js環境 | pnpmとNode.jsが利用可能であること |
| 英語翻訳ファイル | enTranslationsが存在し、基準言語として使用可能であること |

### 実行可否判定

- OPENAI_KEYが未設定の場合はAPI呼び出し時にエラー
- missingKeysがない場合は翻訳処理をスキップ

## 入力仕様

### 入力パラメータ

#### translateObject 関数オプション

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| allTranslationsObject | object | Yes | - | 全言語の既存翻訳オブジェクト |
| fromTranslationsObject | object | Yes | - | 基準言語（英語）の翻訳オブジェクト |
| inlineFile | string | No | - | インライン出力ファイルパス |
| languages | AcceptedLanguages[] | No | acceptedLanguages（英語除く） | 翻訳対象言語配列 |
| targetFolder | string | No | '' | 言語ファイル出力先フォルダ |
| tsFilePrefix | string | No | TypeScript import文 | ファイル先頭テンプレート |
| tsFileSuffix | string | No | Language export文 | ファイル末尾テンプレート |

### translateText 関数パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| text | string | Yes | - | 翻訳対象の英語テキスト |
| targetLang | string | Yes | - | 翻訳先言語コード |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| 英語翻訳ファイル | TypeScript | `packages/translations/src/languages/en.ts` |
| 各言語翻訳ファイル | TypeScript | `packages/translations/src/languages/*.ts` |
| 環境変数 | .env | OPENAI_KEY |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| 言語ファイル | TypeScript | 更新された翻訳ファイル |

### 出力ファイル仕様

| 項目 | 内容 |
|-----|------|
| ファイル名 | `{langCode}.ts`（例: ja.ts, de.ts） |
| 出力先 | `packages/translations/src/languages/` |
| 文字コード | UTF-8 |
| フォーマット | Prettier適用（TypeScript） |

### 出力ファイル構造

```typescript
import type { DefaultTranslationsObject, Language } from '../types.js'

export const {langCode}Translations: DefaultTranslationsObject = {
  // 翻訳オブジェクト
}

export const {langCode}: Language = {
  dateFNSKey: '{dateFNSKey}',
  translations: {langCode}Translations,
}
```

## 処理フロー

### 処理シーケンス

```
1. 環境変数読み込み
   └─ dotenv.config()で.envからOPENAI_KEY取得
2. 翻訳オブジェクト準備
   └─ 全言語の既存翻訳をallTranslationsObjectにロード
3. 言語ループ開始
   └─ acceptedLanguages（英語除く）をイテレート
   3.1. 削除対象キー検出
        └─ findMissingKeys(既存翻訳, 英語翻訳)で英語にないキーを検出
   3.2. 削除対象キー削除
        └─ 既存翻訳から不要キーを削除
   3.3. 不足キー検出
        └─ findMissingKeys(英語翻訳, 既存翻訳)で不足キーを検出
   3.4. 翻訳実行
        └─ 各missingKeyに対してtranslateTextを呼び出し
        3.4.1. 並列度制御
               └─ 同時12リクエストまでに制限
        3.4.2. OpenAI API呼び出し
               └─ GPT-4でtext→targetLang翻訳
        3.4.3. 結果マージ
               └─ deepMergeSimpleで既存翻訳に追加
4. ファイル出力
   4.1. TypeScriptソース生成
        └─ generateTsObjectLiteralでオブジェクトリテラル生成
   4.2. ESLint適用
        └─ applyEslintFixesで自動修正
   4.3. Prettier適用
        └─ formatでフォーマット
   4.4. ファイル書き込み
        └─ fs.writeFileSyncで保存
5. 完了ログ出力
   └─ 新規翻訳キー一覧をコンソール出力
```

### フローチャート

```mermaid
flowchart TD
    A[translateNewKeys開始] --> B[環境変数読み込み]
    B --> C[翻訳オブジェクト準備]
    C --> D{次の言語?}
    D -->|No| E[完了ログ出力]
    D -->|Yes| F[削除対象キー検出]
    F --> G{削除キーあり?}
    G -->|Yes| H[キー削除]
    G -->|No| I[不足キー検出]
    H --> I
    I --> J{不足キーあり?}
    J -->|No| K[ファイル出力]
    J -->|Yes| L{並列度12未満?}
    L -->|No| M[Promise.race待機]
    M --> L
    L -->|Yes| N[translateText呼び出し]
    N --> O[OpenAI API呼び出し]
    O --> P{翻訳成功?}
    P -->|Yes| Q[結果マージ]
    P -->|No| R[エラーログ]
    Q --> S{次のキー?}
    R --> S
    S -->|Yes| L
    S -->|No| K
    K --> T[TypeScriptソース生成]
    T --> U[ESLint適用]
    U --> V[Prettier適用]
    V --> W[ファイル書き込み]
    W --> D
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベース操作なし（ファイル操作のみ） |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| API_KEY_MISSING | 設定エラー | OPENAI_KEYが未設定 | .envファイルにOPENAI_KEYを設定 |
| API_ERROR | 外部連携エラー | OpenAI APIエラー | APIキーの有効性とレート制限を確認 |
| TRANSLATION_FAILED | 翻訳エラー | 翻訳結果が取得できない | 対象テキストとログを確認 |
| KEY_NOT_OBJECT | 型エラー | キーパスの途中が文字列 | 翻訳データ構造を確認 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（エラー時は例外スロー） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

### 障害時対応

- 翻訳失敗時はエラーログを出力して例外をスロー
- 部分的な翻訳結果は保存されない（全て成功した言語のみファイル出力）

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | N/A（ファイル操作） |
| コミットタイミング | 言語ファイルへの書き込み時 |
| ロールバック条件 | N/A（ファイルは上書き） |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 新規キー数 × サポート言語数（約40言語） |
| 目標処理時間 | OpenAI APIレスポンス時間に依存 |
| メモリ使用量上限 | 翻訳オブジェクト全体がメモリに保持 |

### 並列度制御

- 同時API呼び出し数は最大12リクエスト
- Promise.race()で完了待機してからnew requestを発行
- レート制限回避のための制御

## 排他制御

- ファイル書き込みは逐次実行（言語ごと）
- 同時実行時のファイル競合は考慮されていない

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 情報ログ | 削除キー検出時 | 削除対象キー一覧 |
| 情報ログ | 不足キー検出時 | 言語と不足キー一覧 |
| 情報ログ | 翻訳実行時 | 元テキストと翻訳結果 |
| エラーログ | API エラー時 | エラー詳細 |
| 情報ログ | 完了時 | 新規翻訳オブジェクト |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 処理時間 | N/A（手動実行） | コンソール出力 |
| エラー発生 | 1件以上 | 例外スロー |

## 備考

### OpenAI プロンプト設計

システムプロンプトには以下の指示が含まれる：

1. **Payload用語の定義**
   - Collection, Field, Document, Global, Locale, Tenant, SEO, Payload, Import/Export

2. **翻訳ルール**
   - 大文字開始の単語は固有名詞として翻訳しない
   - フォーマルで専門的な言語を使用
   - `{{variable}}`形式の変数は翻訳しない
   - 翻訳不可の場合は`[SKIPPED]`を返却

3. **言語別例**
   - nl（オランダ語）: Locale→Taal, Collection→Collectie
   - es（スペイン語）: Locale→Idioma, Collection→Colección

### サポート言語

acceptedLanguages配列で定義（40言語以上）:
- ar, az, bg, ca, cs, da, de, el, en, es, et, fa, fi, fr, he, hr, hu, it, ja, ko, lt, lv, my, nb, nl, pl, pt, ro, rs, rsLatin, ru, sk, sl, sv, th, tr, uk, vi, zh, zhTW

### 関連コマンド

```bash
# コア翻訳の更新
pnpm run translateNewKeys

# Lexicalエディタ翻訳の更新
cd packages/richtext-lexical && pnpm run translateNewKeys

# プラグイン翻訳の更新
# 各プラグインディレクトリで同様のスクリプトを実行
```
