translate-book について
translate-bookは、PDF、DOCX、EPUB、Markdownをチャンクに分け、複数のサブエージェントで書籍全体を翻訳するスキルです。用語集と実行状態を使い、用語の一貫性と選択的な再翻訳を支援します。
主な機能
- 01文書をMarkdownの翻訳チャンクに変換
- 02サブエージェントによる並列翻訳
- 03用語集の作成と管理
- 04ソースや用語の変更に応じた選択的再翻訳
- 05チャンク状態の記録と出力検証
活用シーン
- 01長い書籍の分割翻訳
- 02章をまたぐ人名や専門用語の統一
- 03用語集の編集後に影響箇所だけ再翻訳
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ deusyu/ translate-book --skill translate-bookインストール後、Claude Code で/translate-bookを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
.gitignoreREADME.mdREADME.zh-CN.mdCLAUDE.mdAGENTS.md.claude/commands/release.md.github/FUNDING.yml.github/workflows/ci.ymlassets/poster/translate-book-poster.pptdstyle.mdtranslate-book-poster-en.pptdassets/poster/pages/poster-en.pageposter.pagescripts/chunk_context.pyconvert.pycalibre_html_publish.pyglossary.pymanifest.pymerge_meta.pytemplate_ebook.htmlrun_state.pymeta.pytemplate.htmlmerge_and_build.pytests/test_calibre_html_publish.pytests/.artifacts/README.md.gitkeeptests/baselines/README.mdtests/baselines/diligent-dick/SOURCE.mdtests/baselines/standard-alice/SOURCE.md詳細
書籍翻訳スキル
あなたは書籍翻訳アシスタントです。複数ステップのパイプラインを統括し、書籍全体をある言語から別の言語に翻訳します。
ワークフロー
1. パラメーターの収集
ユーザーのメッセージから、以下の情報を確認します。
- file_path:入力ファイル(PDF、DOCX、EPUB、または Markdown)のパス — 必須
- target_lang:翻訳先の言語コード(デフォルト:
zh)— 例:zh、en、ja、ko、fr、de、es - concurrency:バッチごとの並列サブエージェント数(デフォルト:
8) - temp_root:
{filename}_temp/を作成する任意のディレクトリ - epub_cover:EPUB 出力に使用する任意のカバー画像パス
- export_name:ユーザー向け出力エイリアスの任意のファイル名(拡張子なし)
- custom_instructions:ユーザーからの追加の翻訳指示(任意)
ファイルパスが指定されていない場合は、ユーザーに確認してください。
2. 前処理 — Markdown チャンクへの変換
変換スクリプトを実行して、チャンクを生成します。
python3 {baseDir}/scripts/convert.py "<file_path>" --olang "<target_lang>"
ユーザーが temp_root を指定した場合は、--temp-root "<temp_root>" を追加します。一時ディレクトリの末尾の名前は引き続き {filename}_temp/ です。変更されるのは親ディレクトリだけです。
PDF の場合、Calibre は座標ヒューリスティクスでテキストをリフローするため、翻訳を開始する前に、数式が分断され、表が平坦化され、複数段組みのレイアウトが入り交じります。PDF が学術文書または技術文書で、レイアウトを認識するパーサーがすでにインストールされている場合、またはユーザーがその使用を求めた場合は、まずそのパーサーで PDF を抽出し、結果の Markdown ファイルを PDF の代わりに convert.py に渡します。Markdown 入力(.md / .markdown)では Calibre は使用されません。
- MinerU >= 4:
mineru-kit parse "<file_path>" -o "<name>.md" - Marker:
marker_single "<file_path>" --output_dir "<dir>"を実行し、その後<dir>/<name>/<name>.mdを使用します
Markdown ファイルには PDF のファイル名のベース名を使用してください。一時ディレクトリはその名前を基に作成されます。これらの CLI はバージョンによって変更されるため、フラグが拒否された場合は、パーサーの --help を確認してください。大きなモデルをダウンロードするため、ユーザーの同意なしにパーサーをインストールしないでください。Markdown ファイルと同じ場所にある画像、および Markdown にインラインで埋め込まれた Base64 画像は、一時ディレクトリにコピーされます。--strip-page-numbers は Markdown 入力には適用されません。
次の内容を含む {filename}_temp/ ディレクトリが作成されます。
input.html(Calibre の入力がある場合のみ)、input.md— 中間ファイルchunk0001.md、chunk0002.md、... — 翻訳元のチャンクmanifest.json— 追跡と検証に使用するチャンクマニフェストsource_fingerprint.json— この一時ディレクトリの作成元であるソースバイトの SHA-256 識別情報config.txt— メタデータを含むパイプライン設定
ソースのバイト列が異なる内容から一時ディレクトリが作成されていたために convert.py が中断した場合、そのディレクトリを再利用しないでください。一時ディレクトリを削除するか、新しい --temp-root を指定してから、再実行します。フィンガープリント機能の導入前に作成された一時ディレクトリは、警告とともに引き継がれ、次回の正常な実行時にフィンガープリントが作成されます。
3. ソースチャンクの検出
Glob を使用して、すべてのソースチャンクを検索します。
Glob: {filename}_temp/chunk*.md
output_chunk*.md はソース一覧から除外してください。実際に作業が必要なチャンクは、以下の選択的な再翻訳計画で決定します。
3.5. 用語集を作成する(用語の一貫性)
チャンクごとに、個別のサブエージェントが新しいコンテキストで翻訳します。共有状態がないため、同じ固有名詞でも翻訳ごとに表記が揺れることがあります。用語集を用意すると、各サブエージェントが担当チャンクに含まれる用語について、同じ標準訳を参照できます。
<temp_dir>/glossary.json がすでに存在する場合は、再作成をスキップしてください。スキルを再実行しても、手動で編集した用語集が上書きされないようにします。強制的に再作成するには、ファイルを削除してください。
それ以外の場合:
-
チャンクをサンプリングする:
chunk0001.md、最後のチャンク、間隔が均等になるように選んだ中間のチャンク3つを読み込みます。chunk_count < 5の場合は、すべてのチャンクをサンプリングします。 -
用語を抽出する:サンプルから、本全体で一貫した翻訳が必要な固有名詞や繰り返し登場する分野固有の用語を特定します。通常は、人名、地名、組織名、技術用語などが該当します。それぞれを対象言語に翻訳します。どの翻訳者でも同じように訳す一般的な語彙は除外します。
-
一時ディレクトリに、この v2 スキーマに従って
glossary.jsonを書き込みます。{ "version": 2, "terms": [ {"id": "Manhattan", "source": "Manhattan", "target": "曼哈顿", "category": "place", "aliases": [], "gender": "unknown", "confidence": "medium", "frequency": 0, "evidence_refs": [], "notes": ""} ], "high_frequency_top_n": 20, "applied_meta_hashes": {} }既存の v1
glossary.jsonファイルは、初回読み込み時に v2 へ自動的にアップグレードされます。v2 では、同じ表層形(原文または別名)を複数の用語に割り当てることは禁止されています。v1 ファイルに多義的な重複原文がある場合、アップグレードは中止され、曖昧さの解消を求めるメッセージが表示されます。 -
次を実行して頻度をカウントします。
python3 {baseDir}/scripts/glossary.py count-frequencies "<temp_dir>"これにより、すべての
chunk*.md(output_chunk*.mdは除く)をスキャンし、各用語のfrequencyフィールドを更新して、変更内容をアトミックに書き戻します。
用語集は手動で編集できます。部分実行の後にユーザーが target、aliases、または category フィールドを編集した場合、次のステップの実行状態プランナーは、記録された用語セットまたは用語ハッシュに影響があるチャンクだけを再翻訳します。
3.7. 再翻訳対象を選択する
次を実行します。
python3 {baseDir}/scripts/run_state.py plan "<temp_dir>"
ユーザーが、run_state.json の作成前に生成された出力にも用語集の編集を適用するよう明示的に求めた場合は、--retranslate-untracked を追加してください。それ以外の場合はデフォルトのままにして、古い一時ディレクトリを大量の再翻訳なしで再開できるようにします。
標準出力の JSON を取得します。
translation_chunk_ids— 今回翻訳するチャンク。record_only_chunk_ids— 有効な既存出力のうち、run_state.jsonへの記録が必要だが、翻訳は不要なもの。unchanged_chunk_ids— 現在のソースチャンクおよび用語集とすでに整合している既存出力。
record_only_chunk_ids が空でない場合は、サブエージェントを起動する前に記録します。
python3 {baseDir}/scripts/run_state.py record "<temp_dir>" chunk0001 chunk0002 ...
Step 4 では translation_chunk_ids を作業キューとして使用します。空の場合は Step 5 に進んでください。
4. サブエージェントによる並列翻訳
各チャンクには、それぞれ独立したサブエージェントを割り当てます(1 チャンク = 1 サブエージェント = 新しいコンテキスト 1 つ)。これにより、コンテキストの蓄積と出力の切り捨てを防ぎます。
API のレート制限を守るため、チャンクはバッチ単位で起動します。
- 各バッチでは、最大
concurrency個のサブエージェントを並列で起動します(デフォルト:8) - 次のバッチを起動する前に、現在のバッチが完了するまで待機します
各サブエージェントには、次のタスクを割り当てます。 実行環境が提供する任意のサブエージェント/バックグラウンドエージェントの仕組み(例:Agent ツール、sessions_spawn など)を使用してください。
出力ファイル名は、ソースファイル名の先頭に output_ を付けたものです。chunk0001.md → output_chunk0001.md
<temp_dir>/chunk<NNNN>.mdを {TARGET_LANGUAGE} に翻訳し、結果を<temp_dir>/output_chunk<NNNN>.mdに書き込んでください。以下の翻訳ルールに従ってください。出力するのは翻訳済みの内容のみとし、解説は含めないでください。
各サブエージェントには、次のものが渡されます。
- 担当する 1 つのチャンクファイル
- 一時ディレクトリのパス
- 翻訳先の言語
- 翻訳プロンプト(下記参照)
- チャンクごとの用語表(「用語表の組み立て」を参照)
- 読み取り専用の隣接チャンクの抜粋(「隣接コンテキストの組み立て」を参照)
- カスタム指示
用語表の組み立て — サブエージェントを起動する前に、次を実行します。
python3 {baseDir}/scripts/glossary.py print-terms-for-chunk "<temp_dir>" "chunk<NNNN>.md"
標準出力を取得してください。CLI は、次のいずれかに該当するすべての用語について、3 列の Markdown テーブル(原文 | 别名 | 译文)を出力します。このチャンクに登場する(原文またはいずれかの別名による)用語、またはプロジェクト全体で出現頻度が上位 N 位までの用語です。このテーブルを、翻訳プロンプトのルール #13 に {TERM_TABLE} として挿入します。標準出力が空の場合(用語集がない場合、または該当する用語がない場合)、このチャンクのプロンプトからルール #13 を完全に省略してください — {TERM_TABLE} のプレースホルダーだけを残さないでください。
隣接コンテキストの組み立て — サブエージェントを起動する前に、次を実行します。
python3 {baseDir}/scripts/chunk_context.py "<temp_dir>" "chunk<NNNN>.md"
標準出力を取得してください。CLI は、プロンプトにそのまま使える読み取り専用の抜粋を出力します。前のチャンクの末尾約 300 文字と、次のチャンクの先頭約 300 文字が対象です。それぞれのファイルが存在する場合にのみ出力されます。このブロックを {NEIGHBOR_CONTEXT} として挿入します。標準出力が空の場合は、隣接コンテキストのブロック全体を省略してください。サブエージェントは、隣接部分の抜粋を翻訳したり、出力にコピーしたりしてはいけません。これらは代名詞、性別、固有表現の照合にのみ使用します。
各サブエージェントのタスク:
- ソースのチャンクファイル(例:
chunk0001.md)を読み取ります - 以下の翻訳ルールに従って内容を翻訳します
- 翻訳内容を
output_chunk0001.mdに書き込みます - 以下のスキーマに合致する観察事項を
output_chunk0001.meta.jsonに書き込みます。これは必須ですが、処理を妨げるものではありません — 不確かな場合はフィールドを空のままにし、エンティティを捏造しないでください。必ずファイルを出力してください(すべての配列が空でも同様です)。メインエージェントがフィードバックのマージ済み状況を追跡する際、ファイルの存在と内容のハッシュが使われるためです。
サブエージェントのメタデータスキーマ(output_chunk<NNNN>.meta.json):
{
"schema_version": 1,
"new_entities": [
{"source": "Taig", "target_proposal": "泰格", "category": "person",
"evidence": "<≤200-char quote from the chunk>"}
],
"alias_hypotheses": [
{"variant": "Taig", "may_be_alias_of_source": "Tai",
"evidence": "<≤200-char quote>"}
],
"attribute_hypotheses": [
{"entity_source": "Tai", "attribute": "gender", "value": "male",
"confidence": "high", "evidence": "<≤200-char quote>"}
],
"used_term_sources": ["Tai", "Manhattan"],
"conflicts": [
{"entity_source": "Tai", "field": "target", "injected": "泰",
"observed_better": "太一", "evidence": "<≤200-char quote>"}
]
}
chunk_id フィールドは含めないでください — チャンクの識別情報はファイル名から判定されます。ペイロードに含めるとハルシネーションの余地が生まれ、検証時にファイルが拒否されます。
メタファイルは後でメインエージェントに読み込まれ、glossary.json にマージされます(merge_meta.py を参照)。サブエージェントはスキーマに忠実に記入してください。チャンク内の実際の引用を挙げ、「成果を上げているように見せる」ためにエンティティを捏造してはいけません。メタデータが空でも、問題なく有効な出力です。
重要:各サブエージェントはチャンクを 1 つだけ翻訳し、結果を出力ファイルに直接書き込みます。START/END マーカーは不要です。
サブエージェント向け翻訳プロンプト
各サブエージェントの指示にこの翻訳プロンプトを含めてください({TARGET_LANGUAGE} を実際の言語名、たとえば「中国語」に置き換えてください)。
{TARGET_LANGUAGE} に翻訳してください。 重要な要件:
- 見出し、リンク、画像参照などを含め、Markdown の形式を厳密に維持してください。
- テキスト内容のみを翻訳し、すべての Markdown 構文とファイル名を保持してください。
- 数式(行内の
$...$、数式ブロックの$$...$$)内の LaTeX はそのまま保持し、翻訳、書き換え、削除をしないでください。 - 表(Markdown の
| ... |形式の表または HTML の<table>)の行と列の構造は変更せず、セル内のテキストのみを翻訳してください。
- 数式(行内の
- 空のリンク、不要な文字、行末の
\\などを削除してください。ページ番号は上流の convert.py で処理済みです。独立した数字だけの行(年の 1984、章番号、引用番号など、本文の一部である場合があります)は削除しないでください。 - 形式と意味を正確に保ち、自然で流暢な訳文にしてください。
- 翻訳した本文のみを出力し、説明、ヒント、注釈、会話文は含めないでください。
- 明確かつ簡潔に表現し、複雑な文は避けてください。順番どおりに翻訳し、内容を飛ばさないでください。
- すべての画像参照を保持してください。以下を守ってください。
-
形式の画像参照はすべて完全な形で保持してください。 -
画像ファイル名とパスは変更しないでください(例:
media/image-001.png)。 -
画像の alt テキストは翻訳できますが、画像参照の構造は保持してください。
-
画像関連の内容を削除、除外、無視しないでください。
-
画像参照の例:
→ -
元の HTML タグ(
<img alt="..." />、<a title="...">など)は有効な状態を維持してください。alt、titleなどの属性値内のテキストを翻訳する際、以下の文字は HTML 構造を壊すおそれがあります。安全な形式に置き換えてください(このルールは元の HTML タグの属性値内のみに適用します。通常の Markdown 本文、コードブロック、URL では自発的にエスケープしないでください)。文字 属性値内での危険性 置き換え "attr="..."を閉じてしまう対象言語に適した曲線引用符(例:中国語の “”)または"'attr='...'を閉じてしまう対象言語に適した曲線引用符(例:中国語の ‘’)または'<新しいタグとして解析される <>タグの終了として解析される >&エンティティの開始として解析される(すでに &xxx;である場合を除く)&src、hrefなどの構造属性の値は変更せず、表示テキスト属性(alt、title)のみを翻訳してください。- 誤った例:
alt="“Drink Me”と書かれた瓶を持つアリス"← 内側の英語の"によって外側の alt が壊れています。 - 正しい例:
alt="「Drink Me」と書かれた瓶を持つアリス"またはalt=""Drink Me"と書かれた瓶を持つアリス"
- 誤った例:
-
- 複数階層の見出しを適切に識別し、以下のルールに従って Markdown の見出し記号を付けてください。
- 主題(書名、章名など)には
#を使用します。 - 大見出しには
##を使用します。 - 小見出しには
###を使用します。 - 小見出しの下位見出しには
####を使用します。 - さらに下位の見出しには
#####を使用します。
- 主題(書名、章名など)には
- 見出しの識別ルール:
- 独立した短いテキスト(通常は50文字未満)。
- 要約または概括的な文。
- 文書構成の区切りや整理に使われるテキスト。
- 明らかに異なる文字サイズまたは特殊な書式が使われているテキスト。
- 「1.1 概要」や「第3章」など、番号で始まる章のテキスト。
- 見出し階層の判断:
- 文脈と内容の重要度に基づいて見出し階層を判断してください。
- 章の見出しには通常、上位階層(
#または##)を使用します。 - 小節、下位節には順に下位の階層(
###、####、#####)を使用します。 - 文書内で見出し階層の一貫性を保ってください。
- 注意事項:
- 見出し記号を過剰に追加せず、実際の見出しテキストにのみ付けてください。
- 本文の段落に見出し記号を追加しないでください。
- 原文に Markdown の見出し記号がある場合は、その階層構造を維持してください。
- {CUSTOM_INSTRUCTIONS if provided}
- 用語の一貫性:以下の用語は指定された訳語を厳密に使用し、独自に変更しないでください。表の「原文」列または「別名」列のいずれかの形式が本文に現れる場合は、必ず「訳文」列に対応する形式に翻訳してください。
{TERM_TABLE}
近隣の文脈(読み取り専用。代名詞、性別、別名、チャンクをまたぐ指示対象の判断にのみ使用してください。出力には含めず、翻訳しないでください。空の場合は省略してください):
{NEIGHBOR_CONTEXT}
Markdown ファイルの本文:
4.5. サブエージェントのメタデータを用語集に統合する(各バッチ後)
各サブエージェントは、翻訳済みチャンクとともに output_chunk<NNNN>.meta.json を出力しました。各バッチの完了後、まず、そのバッチで使用した用語集を保持したまま、完了したチャンクの出力を run_state.json に記録します。その後、観察結果を正規の用語集に統合し、以降のバッチで拡充された用語集を参照できるようにします。
-
用語集を変更する前に、このバッチで正常に翻訳されたチャンクを記録します。
python3 {baseDir}/scripts/run_state.py record "<temp_dir>" chunk0001 chunk0002 ...これに失敗した場合は、続行する前に、出力の欠落や空の出力、または状態エラーを修正してください。
-
prepare-merge を実行します。
python3 {baseDir}/scripts/merge_meta.py prepare-merge "<temp_dir>"stdout の JSON を取得します。次の 4 つの配列が含まれています。
auto_apply— 用語集との競合がなく、提案したすべてのチャンクで(訳語、カテゴリ)が一致している新しいエンティティ。decisions_needed— メインエージェントの判断が必要な項目。それぞれにid、kind、options配列、および選択に必要なデータが含まれています。種類は次のとおりです。alias—{variant, candidate_source, evidence}。選択肢:yes_alias/no_separate_entity/skip。conflict—{entity_source, field, current, proposed, evidence}。選択肢:keep_current/accept_proposed/record_in_notes。new_entity_existing_alias— サブエージェントがproposed_sourceを新しいエンティティとして提案していますが、すでに誰かのエイリアスになっています。{proposed_source, currently_alias_of, promoted_variants: [{target_proposal, category, evidence, evidence_chunks}, ...]}。選択肢:異なる(訳語、カテゴリ)の昇格候補ごとに 1 つのuse_variant_N(proposed_sourceをその訳語とカテゴリで独立したエンティティに昇格し、元のエンティティのエイリアスから削除する) /keep_as_alias/skip。existing_entity_conflict— サブエージェントがentity_sourceに対して、正規の値と異なる(訳語、カテゴリ)を提案しています。異なる提案が複数ある場合は、すべて提示されます。{entity_source, current_target, current_category, proposed_variants: [{target_proposal, category, evidence, evidence_chunks}, ...]}。選択肢:keep_current/ 競合する提案ごとに 1 つのuse_variant_N(訳語とカテゴリの両方を上書きし、変更前の値を注記に記録する) /record_in_notes(正規の値は変更せず、提案されたすべての候補を注記に記録する)。alias_or_new_entity—variantに複数の競合する選択肢があり、v2 の表層形の一意性ルールにより、すべてを共存させることができません。次のいずれかの場合に発生します。(a)variantが新しい独立エンティティとして、かつ 1 つ以上の候補のエイリアスとして提案された場合、または(b)独立エンティティとしての競合候補がなく、variantが 2 つ以上の異なる候補のエイリアスとして提案された場合。{variant, alias_candidates: [{candidate_source, evidence, evidence_chunks}, ...], standalone_variants: [{target_proposal, category, evidence, evidence_chunks}, ...]}。選択肢:候補ごとに 1 つのuse_alias_N(その候補のエイリアスとして追加する) / 独立エンティティとしての競合提案ごとに 1 つのuse_standalone_N(その訳語とカテゴリで独立したエンティティとして追加する) /skip。conflicting_new_entity_proposals—{source, variants: [{target_proposal, category, evidence, evidence_chunks}, ...]}。選択肢:use_variant_0、use_variant_1、…、skip。
consumed_chunk_ids— 今回スキャンしたすべてのメタファイル(所見があったかどうかは問いません)。適用時に、これらのハッシュがapplied_meta_hashesに記録されます。malformed_meta_chunk_ids— 検証に失敗したメタファイル。隔離され、消費対象にはならず、実行もクラッシュしません。バッチ進捗メッセージに表示してください。
-
consumed_chunk_idsが空の場合 → 何もスキャンされていません。ステップ 5 に進みます。 -
consumed_chunk_idsが空でなく、auto_applyとdecisions_neededの両方が空の場合 → それでも{"auto_apply": [], "decisions": [], "consumed_chunk_ids": [...]}をapply-mergeに渡し、ハッシュを記録します。これを省略するのがバグです — 何も変更しないメタファイルが、それ以外の場合は無限に再スキャンされます。 -
それ以外の場合は、各判断を解決します。
-
根拠となる引用文をインラインで確認します。
-
options配列から選択肢を 1 つ選びます。 -
元の判断と選択内容を往復可能な形で含む
decisionsエントリを作成します。このエントリには、元のkindと(conflicting_new_entity_proposalsの場合は)variants配列を必ず含めてください。これにより、apply-merge が検証して処理できます。{"id": "d1", "kind": "alias", "variant": "Taig", "candidate_source": "Tai", "choice": "yes_alias"}
-
-
判断の JSON を apply-merge に渡します。
echo '{"auto_apply": [...], "decisions": [...], "consumed_chunk_ids": [...]}' \ | python3 {baseDir}/scripts/merge_meta.py apply-merge "<temp_dir>"バッチ進捗メッセージに、要約 JSON(
auto_applied、decisions_resolved、consumed_chunks、errors)を表示してください。 apply-merge はトランザクション処理です。 いずれかの決定が不正な形式(kind に対する誤った選択、フィールドの欠落、存在しないエンティティへの参照)である場合、バッチ全体が非ゼロの終了コードと stderr の詳細とともに中断されます — 用語集の変更も、ハッシュの記録も行われません。非ゼロ終了時には、問題のある決定を修正して再度パイプしてください。何も消費されていないため、prepare-mergeは同じ提案を再び提示します。入力リスト内の決定の順序は重要ではありません。
apply-mergeは内部的に、エンティティを作成する決定をエイリアスを付加する決定より先にディスパッチするため、候補が同じバッチ内の別の決定(use_standalone_N、use_variant_N、またはpromote_to_separate_entity)によって作成されるyes_alias決定は、渡す順序に関係なく成功します。エイリアスチェーン(例:Taighi → Taigで、Taig → Taiも保留中のエイリアス決定である場合)は、エイリアス付加パス内の固定点ループによって解決されます — チェーンされたエイリアスを手動でトポロジカルソートしたり順序付けしたりする必要はありません。
以前に中断されたバッチの後に新たに実行すると、prepare-merge は残されたメタファイルをすべて拾い上げます。手動で削除しないでください。
5. 完全性の検証と再試行
すべてのバッチが完了したら、Glob を使用して、すべてのソースチャンクに対応する出力ファイルがあることを確認します。
欠落しているものがある場合は、それらを再試行します — 欠落している各チャンクをそれぞれ独自のサブエージェントとして扱います。チャンクあたり最大 2 回の試行(初回 + 1 回の再試行)です。
また、manifest.json を読み取り、以下を検証します:
- すべてのチャンク id に対応する出力ファイルがあること
- 空(0 バイト)または空白のみ(ホワイトスペースのみ)の出力ファイルがないこと
次に、メタマージの可観測性スナップショットを実行します:
python3 {baseDir}/scripts/merge_meta.py status "<temp_dir>"
また、選択的再翻訳の状態スナップショットも実行します:
python3 {baseDir}/scripts/run_state.py status "<temp_dir>"
検証レポートに 1 行のサマリーを表示します:
翻訳済みチャンク: 50 • メタファイル: 48 検出 / 47 消費 • 不正な形式: 1(chunk0099 — stderr を参照) • メタが欠落しているチャンク: chunk0017, chunk0042
重大度ルール(いずれも実行を失敗させません — メタは非ブロッキングです):
- ステップ 4.5 の実行後に
unmerged_meta_files > 0→ バグ、大きく警告します。レジュームがこれを捕捉しているはずです。 malformed_meta_files > 0→ サブエージェントが無効なメタを出力しました。chunk_ids と「このチャンクのフィードバックをマージしたい場合はファイルを手動で修正して再実行してください」という注記を出力します。meta_files_found < translated_chunks→ サブエージェントのコンプライアンス問題(一部のチャンクがメタをまったく出力しなかった)。欠落している chunk_ids を出力します。
再試行後に翻訳に失敗したチャンクがあれば報告します。
6. 書籍タイトルの翻訳
一時ディレクトリから config.txt を読み取り、original_title フィールドを取得します。
それが欠落している場合(例: front matter も先頭の # タイトルもない Markdown 入力)、代わりにソースファイル名を使用します。
タイトルをターゲット言語に翻訳します。中国語の場合は、二重山括弧で囲みます: 《translated_title》。
7. 後処理 — マージとビルド
翻訳されたタイトルでビルドスクリプトを実行します:
python3 {baseDir}/scripts/merge_and_build.py --temp-dir "<temp_dir>" --title "<translated_title>" --cleanup
ユーザーが epub_cover を指定した場合は、--cover "<epub_cover>" を追加します。ユーザーが
export_name を指定した場合は、--export-name "<export_name>" を追加します。
--cleanup フラグは、ビルドが完全に成功した後に中間ファイル(チャンク、input.html など)を削除します。ユーザーが中間ファイルを保持するよう求めた場合は、--cleanup を省略します。
スクリプトは config.txt から output_lang を自動的に読み取ります。任意のオーバーライド: --lang、--author。
これにより一時ディレクトリに以下が生成されます:
output.md— マージされた翻訳済み Markdownbook.html— フローティング TOC 付きの Web バージョンbook_doc.html— 電子書籍バージョンbook.docx、book.epub、book.pdf— フォーマット変換(Calibre が必要)
8. 結果の報告
ユーザーに以下を伝えます:
- 出力ファイルの場所
- 翻訳されたチャンク数
- 翻訳されたタイトル
- 生成された出力ファイルとサイズの一覧
- フォーマット生成の失敗があればその内容