| name | pptx-translator |
| description | 既存のPowerPoint(.pptx)ファイルのテキストだけを別言語に一括翻訳し、フォント・色・罫線・図形・レイアウトなどの装飾は一切変更せず、崩れのない状態に仕上げるスキル。「pptxを英語にして」「このパワポの文字を日本語から英語に翻訳して」「スライドの言語を変換して」「PowerPointを多言語化したい」など、既存スライドの言語だけを変えたい依頼で必ず使う。単に内容を要約する・新規スライドを作る依頼では使わない(その場合は素直に読む/作成する)。 |
pptx-translator
概要
pptxの全テキストランをdocument順に抽出し、翻訳を1:1で適用し、崩れがないか実際にレンダリングして確認する、というサイクルを回す。「翻訳リストを作って流し込んだら終わり」ではなく、必ず画像化して目視確認し、崩れていたら直すところまでが本スキルの範囲。 テキスト差し替えだけでは、対象言語が原文より長くなった場合にほぼ確実にオーバーフローが起きるため、確認とフォントサイズ調整のサイクルを省略しない。
装飾(フォント種類・色・太字・罫線・塗り・図形の位置とサイズ)は一切変更しない。変更するのはテキスト文字列と、はみ出し対策としてのフォントサイズ(縮小のみ)だけ。
前提
python-pptx が必要。venvで用意する: python3 -m venv /tmp/pptxenv && /tmp/pptxenv/bin/pip install python-pptx
- スライド画像での目視確認にはmacOSのKeynoteアプリを使う(
scripts/export_slides.shが内部でAppleScript経由により操作する)。Keynoteは日本語ファイル名のpptxも通常問題なく開ける。
- Keynoteの操作で守ること: AppleEventがタイムアウト・失敗しても、Keynoteを
quitやpkillで再起動してリトライしない。強制終了すると次回起動時にバージョン案内・ウィンドウ復元などのモーダルダイアログが出て、AppleEventが恒久的にブロックされる悪循環になる。export_slides.shは失敗時に「ダイアログでブロックされている」か「ドキュメントを開けていない」かを判別して出力するので、前者ならユーザーに画面のダイアログを閉じてもらってから、後者ならそのまま再実行する。Keynoteは起動したまま使い回す。
- 作業用の一時ファイルはスクラッチディレクトリに置き、元のpptxは絶対に上書きしない(出力は別名
<元名>_<言語コード>.pptx 等にする)。
手順
0. 翻訳先言語を確認する
依頼文に翻訳先の言語が含まれていない場合(例: 引数がファイルパスのみ)は、作業を始める前にユーザーに翻訳先言語を確認する。推測で進めない。
1. 全テキストランを抽出する
/tmp/pptxenv/bin/python scripts/extract_texts.py <src.pptx> <work_dir>
<work_dir>/all_runs.json(空白runも含む全run)と<work_dir>/nonblank_pairs.txt(翻訳対象のみ、連番付き)が生成される。
最重要の落とし穴: pptxにはrun.textが空文字列や空白のみのrunが混じっていることが珍しくない(装飾目的の非表示run)。これを見落として「意味のあるテキストの翻訳リスト」を全run数と同じ長さで作ってしまうと、空白runの位置から後ろ全部が1つずつズレて、見出しと本文が入れ替わるような深刻なバグになる。extract_texts.pyは最初からこの空白を除いたnonblank_pairs.txtを出すので、翻訳リストは必ずこのファイルの行数・順序に合わせて作る。
2. 翻訳リストを作成し、全件を目視で照合する
nonblank_pairs.txtの各行に対応する翻訳を、同じ順序・同じ件数のJSON配列として<work_dir>/translations.jsonに書く。
書いたら、原文と翻訳を1行ずつ並べた対照表を作ってファイルに出力し、全件読み比べる。件数が一致しているかのassertだけでは、中身の取り違え(例: 隣の行の翻訳を書いてしまった、コピペで別スライドの文言が紛れ込んだ)は検出できない。実際にこの取り違えは起きる不具合であり、目視確認をサボると「翻訳自体は合っているのに特定の1箇所だけ意味不明な文言になる」というデバッグしづらい症状で現れる。
対照表の作り方の例:
import json
nonblank = [t for i, t in enumerate(json.load(open("all_runs.json"))) if t.strip() != ""]
translations = json.load(open("translations.json"))
for i, (jp, en) in enumerate(zip(nonblank, translations)):
print(f"{i}: JP={jp!r}\n EN={en!r}")
3. テキストのみを置換して適用する
/tmp/pptxenv/bin/python scripts/apply_translations.py <src.pptx> <work_dir>/all_runs.json <work_dir>/translations.json <dst.pptx>
実行時に各runの原文がall_runs.jsonの記録と一致するか検証(drift check)してから書き換えるので、途中でpptxの構造が変わっていた場合はエラーで止まる。
適用後、装飾が本当に変わっていないかを検証する:
/tmp/pptxenv/bin/python scripts/verify_decoration.py <src.pptx> <dst.pptx>
テキスト以外のXML(フォントサイズ・色・罫線・図形位置など)が一言一句一致しているかを構造的にチェックする。ここで差分が出た場合は、テキスト以外の何かが意図せず変わっているということなので原因を調査する。
4. Keynoteで画像化して目視確認する
scripts/export_slides.sh <src.pptx> <images_orig_dir>
scripts/export_slides.sh <dst.pptx> <images_dir>
先に原本もエクスポートしてベースラインにする。 翻訳版で崩れを見つけたら、まず原本の同じスライドと見比べる。原本にも同じ崩れがある(罫線が見出しを貫通している等)なら元のレイアウト問題であり、修正対象外としてユーザーに報告するだけでよい。これをしないと、元から存在する崩れを翻訳起因と誤認して無駄な調査・修正をすることになる。
生成された全PNGを1枚ずつ確認する。チェックする観点:
- テキストが図形の外にはみ出して、下や隣の図形と重なっていないか
- 見出しラベルと本文が意味的に入れ替わっていないか(手順1のズレ・手順2の取り違えが起きていないかの最終確認)
- 独立した2つのラベルが1つの文のように連結して読めてしまっていないか(例:「UI Design (Demo Screen Image)My Attendance」のように見えるなら、実は"UI Design..."と"My Attendance"は別の見出しで、区切りが必要)
スライドの内容がスクリーンショット等の画像として埋め込まれている場合、そのテキストはpython-pptxのテキスト走査では検出できず翻訳できない。該当スライドがあれば、対応不可の旨をユーザーに報告する(無理に画像を作り直したりしない)。
5. はみ出しを自動修正する
/tmp/pptxenv/bin/python scripts/autosize.py <dst.pptx> --report <work_dir>/autosize_report.json
各テキストフレーム・テーブルセルについて、図形の矩形サイズと文字数から、その矩形に収まる最大フォントサイズを計算して縮小する(既に収まっているものは変更しない)。図形の位置やサイズそのものは変更しない。デフォルトの下限フォントサイズは9pt(--min-ptで変更可)。
autosizeは自分のシェイプの矩形内に収める縮小しかできない。 タイトルや見出しが折り返して別のシェイプ(下のキャプションや隣の本文)に重なるケースはautosizeでは直らず、実際の崩れの大半はこのパターン。この場合は翻訳リスト側で訳文を短縮するのが第一手(例: 「Advanced Statistical Analysis & AI」→「Statistical Analysis & AI」)。折返しが起きた見出しは、同じ枠内で1行に収まっている隣の見出しの文字数を目安に短縮する。
同一テキストフレーム内で「見出しA」+「画面名B」のように意味的に独立した2つのrunが翻訳で長くなり連結して見える場合は、翻訳リスト側でrun間に区切り文字(|など)を追記してから再度適用し直す。これもフォントサイズ調整では直らないので手当てが要る。
6. 崩れがなくなるまで4〜5を繰り返す
画像確認→問題箇所の特定→(翻訳リストの見直し、またはautosize.pyの再実行)→再度画像化、を、崩れがなくなるまで繰り返す。テーブルの罫線など、翻訳前から存在する見た目(装飾)は変更対象ではないので、テキストの重なり・はみ出し以外は気にしなくてよい。
フォントサイズが下限に達してもなお収まらない箇所が残った場合は、崩れの程度を具体的に説明し、レイアウト自体(図形の位置・サイズ)を変更してよいかユーザーに判断を仰ぐ。装飾やレイアウトを変えるのは、テキスト差し替えだけでは解決しないとはっきりした場合の最終手段。
スクリプト一覧
| スクリプト | 役割 |
|---|
scripts/extract_texts.py | 全テキストランをdocument順に抽出し、空白runを除いたレビュー用ファイルも出力 |
scripts/apply_translations.py | 翻訳をテキストのみ適用(drift検証つき、空白runは自動スキップ) |
scripts/verify_decoration.py | テキスト以外のXMLが元と完全一致するか検証 |
scripts/autosize.py | 図形の矩形に収まるようフォントサイズを自動縮小(テーブルセル含む) |
scripts/export_slides.sh | Keynote経由でスライドをPNG画像にエクスポート(openの戻り値に依存せずドキュメントが開くのをポーリングで待つ。失敗時はダイアログ有無を判別して報告) |