スタイル・位置・カラオケを崩さずにASS/SSA字幕を翻訳する方法
.assファイル内の表示される台詞だけを翻訳し、タイミング、タグ、カラオケ、フォントを確認します。サンプルファイル、無料チェッカー、9回のローカルLLMテスト付き。

ASSまたはSSA字幕ファイルは小さなプログラムです。ヘッダー、スタイルの表、そして最後のフィールドに台詞と書式コードが混在するタイムイベントのリストで構成されています。翻訳するには、その最後のフィールド内の読める単語だけを変更し、それ以外はすべてバイト単位でそのままにし、その後、どの翻訳ツールも自動では直してくれない3つの点を確認します。それはフォント、間隔コード、カラオケ行です。
私たちは14イベントのサンプルをローカルモデルで9回、3種類のプロンプトを使って簡体字中国語に翻訳し、自作のスクリプトで全結果を検証しました。タイミング、位置、色、コメント、描画は9回すべてで維持されました。壊れたのは、ファイル内で英語を前提としている部分です。9回すべてでスタイルのフォントに中国語の文字が含まれておらず、プレーヤーによるフォント代替に頼る状態になり、英語行のハードスペースが中国語では目に見える隙間になりました。カラオケ行は毎回、タイミングが誤った単語を指し、4回では一部の音節が何もハイライトしませんでした。
簡単な答え:翻訳するものとそのままにするもの
| ファイルの部分 | サンプルからの例 | 翻訳する? |
|---|---|---|
[Script Info] ヘッダー | PlayResX: 1920, WrapStyle: 0 | いいえ。位置はこれらの値から計算されます。 |
[V4+ Styles] | Style: Default,Trebuchet MS,64,... | いいえ。ただしフォント名は意図的に変更が必要な場合があります |
| イベントフィールド1~9 | 0,0:00:01.00,0:00:03.20,Default,Jun,0,0,0, | いいえ。これらはレイヤー、タイミング、スタイル、話者、マージン、エフェクトです。 |
| オーバーライドブロック | {\i1}, {\an8\pos(960,120)}, {\k25} | いいえ |
| 描画 | {\p1}m 0 0 l 200 0 200 60 0 60{\p0} | いいえ。これはベクター図形であり、テキストではありません。 |
Comment: イベント | Comment: ...,Earlier draft: Try the stacks. | 任意。コメントは画面に表示されません。 |
| 波括弧内の注記 | {TL note: "stacks" means the closed shelves} | 任意。プレーヤーは無視します。 |
| 表示される台詞 | Did you find the second volume? | はい |
| 行コード | \N, \n, \h | \N はそのまま残します。\n と \h はケースバイケースで判断してください。 |
このガイドの残りの部分では、各行がなぜ重要か、そして結果をどう確認するかを説明します。
ASS 行の構造
[Events] セクションの各行は、そのすぐ上で宣言された形式に従います:
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,0:00:03.40,0:00:06.10,Default,Mara,0,0,0,,{\i1}I thought it was{\i0} sold out.
視聴者が読む内容が入るのは、10 番目のフィールド Text だけです。libass プロジェクトの ASS ファイル形式ガイド によると、この最後のフィールドは「カンマを含むことが許されて」いるため、すべてのカンマで安易に分割すると Well, if it's there, then, we go now. のような行が壊れます。安全なツールは最初の 9 つのカンマだけで分割します。
Text 内では、中括弧で囲まれたものはすべてオーバーライドブロックです。Aegisub の オーバーライドタグリファレンス では、よく出会うコードが定義されています:
\Nはすべての折り返しモードで強制的に改行します。\nは折り返しモード 2 でのみ改行し、それ以外ではスペースになります。\hは非改行スペースです。\an8は数値キーパッドのレイアウトで配置を設定するので、8 は中央上になります。\pos(960,120)はスクリプト座標で行を配置します。\k25はカラオケの音節です。長さはセンチ秒単位なので、25 は 0.25 秒を意味します。\p1の後では、テキストは「描画命令として解釈される」ため、m 0 0 l 200 0を「翻訳」する翻訳者は図形を破壊してしまいます。- 中括弧内の認識されないテキストは「黙って無視される」ため、ファンサブファイルには中括弧で囲まれた翻訳者メモがよく含まれています。
Comment: で始まる行も同じフィールドを使いますが、libass ガイドによると「画面には何も表示されません」。
テストした内容
本屋を舞台にした 14 イベントのシーン sample-source.ass を作成し、上記の各機能の例を 1 つずつ入れました: 斜体、強制改行、セリフ内のカンマ、中括弧メモ、コメント行、位置指定の看板、ベクター図形のボックス、フェード、非改行スペース、\r による色変更、ソフト改行、スクロールする Banner 効果、6 音節のカラオケ行です。
次に、ローカルモデルにこれを簡体字中国語へ 3 通りの方法で翻訳させました:
- ファイル全体。
.assファイル全体を貼り付け、翻訳されたファイルを返すよう依頼します。 - テキストのみ。 各セリフ行の
Textフィールドだけを JSON として送信し、タグはインラインのまま、すべての{...}ブロックとすべての\N、\n、\hを保持するよう指示します。 - 保護あり。 同様ですが、最初にすべての中括弧ブロックと行コードを番号付きプレースホルダーに置き換え、後で元に戻します。
2 番目と 3 番目の条件では、スクリプトはベクター図形やコメント行をモデルに送信しないため、それらの行はファイル全体の条件でのみ破損する可能性がありました。
モデルは Apple M4 Max(メモリ 64 GB)上の LM Studio 0.4.8 で動く Qwen 3.6 27B(Q4_K_M)で、思考はオフ、temperature は 0.3 に設定しました。各条件を 3 回ずつ、合計 9 回実行しました。3 回目の最初の試行はローカルサーバーが接続を切ったため終了し、再起動して 3 回目のラウンドをやり直しました。スクリプトは run_llm_ass_test.py で、9 つの出力はすべて編集せずにスクリプトと一緒に公開しています。README にすべてのファイルが一覧されています。ローカルモデルの設定が初めての方は、ローカル LLM 翻訳ガイド で設定を説明しています。
これは 1 つのモデル、1 つの言語ペア、1 つのサンプルによる小規模なテストでした。どのような問題が起きるか、そしてどうやってそれを見つけるかを示すものです。ツールやプロンプトの優劣をランク付けするものではありません。
結果: 仕組みは生き残ったが、英語の前提は生き残らなかった
すべての出力を check_ass_translation.py で確認しました。完全な出力は check-results.txt にあり、results.csv には実行ごとに 1 行、スクリプトでは見えない問題も含めて記録されています。
| チェック | ファイル全体 | テキストのみ | 保護済み |
|---|---|---|---|
| タイミング、スタイル、フィールド1–9は変更なし | 3/3 | 3/3 | 3/3 |
| 上書きタグは変更なし | 3/3 | 2/3 | 3/3 |
| 描画行とコメント行は未変更 | 3/3 | 3/3 | 3/3 |
| 翻訳を描画できるスタイルフォント | 0/3 | 0/3 | 0/3 |
\h と \n は中国語テキスト内の空白として残る | 3/3 | 3/3 | 3/3 |
| すべてのカラオケタグを保持し、それぞれにテキストを付与 | 3/3 | 0/3 | 1/3 |
2つの結果に驚かされました。ファイル全体を貼り付けた場合、3回の実行すべてで構造が保たれましたが、そのうち2回ではヘッダーの Title 行も翻訳されてしまいました。そして、より安全に思えるテキストのみのプロンプトが、唯一タグを壊す結果を生みました。ある実行では、6つのカラオケタグを含む行に対して {\k25}翻{\k30}页,{\k45}开{\k60}灯 を返しました。最後の2つのタグと1.20秒分のハイライトタイミングが失われ、ハイライトは行のずっと手前で終わってしまう状態でした。同じ実行で Room\h12 is upstairs. が 12\h12号房间在楼上。 になり、部屋番号が二重に現れました。
つまり、有益な教訓は「プロンプトXを使え」ということではありません。恐れている構造的損傷は簡単に検出できるということであり、9回すべての実行で実際にすり抜けた損傷は、ASS翻訳のツールページでは議論されていない3つの箇所に存在するということです。
1. フォントが新しい言語を描画できない
サンプルのスタイルは、セリフにTrebuchet MS、看板にGeorgiaを使用しており、英語版としては普通のことです。どちらのフォントにも漢字は含まれていません。チェッカーのグリフテストを2つのフォントファイルに対して実行したところ、すべての実行で翻訳された12個のテキストイベントがすべて失敗しました:
ERROR event 1: font 'Trebuchet MS' has no glyph for 9 characters, e.g. 了二你到卷吗找第?
ERROR event 7: font 'Georgia' has no glyph for 10 characters, e.g. 书人仅作员工库架闭限
プレーヤーがインストールされている別のフォントで代替する可能性があるため、字幕は表示されるかもしれませんが、リリース側がその見た目を制御できなくなり、適切なフォントを持たないシステムの視聴者には空の四角が表示される可能性があります。修正は、各スタイルの Fontname フィールドを意図的に編集することです。ある出力の3つのスタイルすべてを、macOSに付属する中国語フォントのHiragino Sans GBに変更し、そのフォントに対してグリフテストを実行したところ、グリフエラーはゼロになりました。
視聴者が実際に持っているフォントを選ぶか、動画と一緒にフォントを配布してください。libassのガイドでは、リリースには使用するすべてのフォントを添付すべきであり、できればMKVコンテナに添付することを推奨しています。ターゲット言語のフォントは新しいため、それを添付することも翻訳作業の一部となります。
2. スペーシングコードが英語の習慣を引き継ぐ
Room\h12 は「Room」と「12」を接着し、行をまたいで分割されないようにします。中国語では単語はスペースで区切られませんが、すべての実行で \h がどこかに残りました。5回の実行では 12号房间 と 在楼上 の間に配置され、3回は数字の前に、1回は数字の2つのコピーの間に配置されました。いずれにせよ、視聴者には余分なスペースが見えます。Wait\nhere. も同じ問題を抱えていました。WrapStyle: 0 では、\n はスペースとしてレンダリングされるため、在\n这里等 は3語の文の途中に隙間を見せます。
ここでは構造は問題ありませんが、言語が問題です。単語間にスペースを置かないターゲット言語では、翻訳されたテキストから \h と \n を削除してください。\N は強制改行が必要な場所にのみ残し、ターゲット文の自然な位置に配置してください。チェッカーが変更された \h と \n のカウントをエラーではなく警告として報告するのはこのためであり、中国語、日本語、韓国語のテキスト内で生き残った場合に警告します。
3. カラオケのタイミングは元の単語に属する
カラオケ行 {\k25}Turn {\k30}the {\k45}page, {\k60}turn {\k40}the {\k80}light は、各英語音節を歌に合わせてタイミングを取ります。翻訳はそのタイミングを意味のある形で保つことはできません。中国語の単語が同じビートに乗らないからです。私たちの実行は、それがうまくいかないさまざまな方法を示しています:
- 4回の実行では、6つのタグすべてが保持され、それぞれ以前とは異なる単語に付けられました。そのうちの1つは
{\k40}打{\k80}开(「開く」)で終わり、行から「light」が完全に削除されました。 - 4回の実行では、音節が何もハイライトしませんでした。例えば
打开{\k40}{\k80}灯(空の音節に0.40秒のハイライト)です。そのうち2回では、0.45秒の音節がコンマだけをハイライトしました。 - 1回の実行では、上記のように2つのタグが消えました。
チェッカーは、その場で翻訳されたカラオケ行と、テキストが残っていない音節にフラグを立てます。より良い修正は編集的なものです:カラオケをその場で翻訳しないでください。歌に合わせるための元のタイミング行を保持し、翻訳を別のイベントとして追加します。カラオケイベントをコピーし、独自のスタイル(例えば、小さくして下部に配置)を付け、\k タグを削除し、テキストを翻訳します。自分で音声に合わせてタイミングを取る用意がある場合にのみ、音節ごとに再タイミングしてください。
持ちこたえるワークフロー
-
まずソースを読めるようにする。 ファイルに文字化けが表示される場合は、何よりも先にエンコーディングを修正してください。エンコーディングガイドではSRTの例を使用していますが、同じバイトレベルの手順が
.assファイルにも機能し、元のバイトを安全に保ちます。チェッカーはUTF-8とUTF-16のみを読み取ります。 -
範囲を決める。 スタイルをリストアップし、どれがセリフで、どれが画面上の看板で、どれがカラオケかを決めます。看板は通常翻訳が必要で、カラオケは通常別の行が必要です。コメントと波括弧のメモはあなたが決めてください。
-
Textフィールドのみを翻訳する。 プレーンテキストとして扱うのではなく、ASSを解析するツールを使用するか、3番目の条件のように自分でタグを保護してください。ソースファイルを出力の隣に保持してください。 -
構造チェックを実行する。
python3 check_ass_translation.py source.ass translated.assイベント数、イベントタイプ、フィールド1~9、スタイル値、オーバーライドブロック、描画、コメント行、
\N、カラオケ音節とその長さ、空または変更されずに返された行を比較します。翻訳の品質は判断しません。 -
フォントは意図的に修正する。 対象言語のテキストを含む各スタイルの
Fontnameを変更し、出荷するフォントファイルに対してグリフテストを実行します:pip install fonttools python3 check_ass_translation.py source.ass translated.ass --font "Noto Sans SC=/path/to/NotoSansSC-Regular.otf"変更されたフォント名は警告として表示されるため、すべての変更が意図したものであることを確認できます。
-
スペーシングコードとカラオケをクリーンアップする 上記の説明に従ってください。
-
動画で確認する。 Aegisub またはお使いのプレーヤーでファイルを開きます。
\pボックスは英語のサイズを保つ一方、翻訳された看板は大幅に長くなったり短くなったりするため、看板が背景に描かれた図形にまだ収まっているかを確認します。また、画面上の表示時間に対して行が長すぎないかも確認します。どちらの問題もファイル自体では見えません。
BookTranslator の役割
BookTranslator の字幕翻訳ツールは SRT、VTT、ASS、SSA ファイルに対応しています。製品ページによると、タイムスタンプとキュー順序を維持し、対応する ASS および SSA のスタイルを各字幕エントリに付けたままにするため、テキストを自分で抽出して再挿入する必要はありません。周囲の行をコンテキストとして対話を翻訳するため、エピソード全体を通した名前や繰り返しのジョークの処理に役立ちます。
この記事では、このサンプルを BookTranslator で実行していません。どのツールを使用する場合でも、結果に対して手順 4 から 7 を実行してください。英語のフォントを保持するスタイルは、中国語を描画できないスタイルのままであり、その場で翻訳されたカラオケには依然として編集上の判断が必要です。字幕ワークフローの残りの部分については、AI 字幕翻訳ガイド、字幕翻訳ソフトウェアの比較、および翻訳を YouTube に公開する場合は YouTube 字幕ワークフロー をご覧ください。
代わりに SRT に変換する場合
翻訳前に ASS を SRT に変換すると、スタイル、位置、描画、カラオケが削除され、上記の問題のほとんども削除されます。出力先がプレーンな字幕のみを表示する場合、またはスタイルがリリースにとって重要でなかった場合は、合理的なトレードオフです。看板やカラオケが作品の一部であるアニメや音楽リリースには不適切なトレードオフです。翻訳のしやすさではなく、ファイルが表示される場所に基づいて判断してください。
テストファイルを入手する
このテストのすべては自由に再利用できます:
- sample-source.ass:14 イベントの英語サンプル;
- check_ass_translation.py:チェッカー(Python 標準ライブラリ。
--fontテストには fontTools が必要); - run_llm_ass_test.py:OpenAI 互換のローカルサーバー向けの 3 つのプロンプト条件;
- results.csv と check-results.txt:実行ごとの結果;
- README.txt:ファイルリストとテスト設定。
outputsフォルダに 9 つの未編集出力があります。




