如何翻譯 ASS/SSA 字幕而不破壞樣式、位置或卡拉 OK 效果
只翻譯 .ass 檔案中可見的對白,然後檢查時間軸、標籤、卡拉 OK 和字型。內含範例檔案、免費檢查工具,以及 9 次本機 LLM 測試。

ASS 或 SSA 字幕檔就像一支小程式:包含標頭、樣式表,以及一連串帶有時間碼的事件,每個事件的最後一個欄位混合了對白與格式代碼。翻譯時,只更動該欄位中可讀的文字,其餘部分保持位元組完全不變,然後檢查三件翻譯工具不會幫你處理的事:字型、間距代碼和卡拉 OK 行。
我們用本機模型將一個包含 14 個事件的範例翻譯成簡體中文九次,使用三種不同的提示詞,並用我們撰寫的腳本檢查每個結果。時間軸、位置、顏色、註解和繪圖在九次結果中都完好無損。出問題的是檔案中假設使用英文的部分:在全部九次結果中,樣式字型都沒有中文字元,因此檔案會依賴播放器替換字型;而英文行中的硬空格在中文裡變成了一個可見的間隙。卡拉 OK 行在每次執行中,時間軸都對應到錯誤的詞語,其中四次執行裡有些音節完全沒有醒目提示。
快速解答:該翻譯什麼、該保留什麼
| 檔案部分 | 我們範例中的例子 | 要翻譯嗎? |
|---|---|---|
[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.
只有第十個欄位 Text 包含觀眾會讀到的內容。libass 專案的 ASS 檔案格式指南 指出,這最後一個欄位「允許包含逗號」,這就是為什麼粗心地按每個逗號分割會破壞像 Well, if it's there, then, we go now. 這樣的列。安全的工具只會在前九個逗號處分割。
在 Text 內部,大括號中的任何內容都是覆寫區塊。Aegisub 的 覆寫標籤參考 定義了您最常遇到的代碼:
\N在每種換行模式下都會強制換行。\n僅在換行模式 2 中換行,否則為空格。\h是不換行空格。\an8使用數字鍵盤佈局設定對齊方式,因此 8 是頂部居中。\pos(960,120)將該列放置在腳本座標中。\k25是卡拉 OK 音節;持續時間以厘秒為單位,因此 25 表示四分之一秒。- 在
\p1之後,文字「將被解釋為繪圖指令」,因此翻譯者若「翻譯」m 0 0 l 200 0,就會破壞圖形。 - 大括號內無法辨識的文字「會被默默忽略」,這就是為什麼粉絲字幕檔案經常在大括號中攜帶翻譯註釋。
以 Comment: 開頭的列使用相同的欄位,但根據 libass 指南,「螢幕上不會顯示任何內容」。
我們測試了什麼
我們撰寫了 sample-source.ass,這是一個設定在書店的 14 事件場景,每個上述功能都有一個範例:斜體、硬換行、對話中的逗號、大括號註釋、註解列、定位標誌、向量方塊、淡入淡出、硬空格、使用 \r 的顏色變更、軟換行、滾動 Banner 效果,以及一個六音節的卡拉 OK 列。
然後我們要求本地模型以三種方式將其翻譯成簡體中文:
- 整個檔案。 貼上整個
.ass檔案,並要求返回翻譯後的檔案。 - 僅文字。 僅將每個對話列的
Text欄位作為 JSON 發送,標籤內聯,並指示保留每個{...}區塊以及每個\N、\n和\h。 - 受保護。 相同,但先將每個大括號區塊和行代碼替換為編號佔位符,然後再將原始內容放回。
在第二和第三種條件下,腳本從未將向量繪圖或註解列發送給模型,因此這些列只能在整個檔案條件下被損壞。
模型是 Qwen 3.6 27B (Q4_K_M),在 Apple M4 Max 搭配 64 GB 記憶體的 LM Studio 0.4.8 中運行,關閉思考功能,溫度設為 0.3。我們每種條件運行三次,總共九次。第三次運行的第一次嘗試因本地伺服器斷開連接而結束,所以我們重新啟動並再次運行第三輪。腳本是 run_llm_ass_test.py,所有九個輸出都未經編輯地與其一起發布;README 列出了每個檔案。如果您從未設定過本地模型,我們的 本地 LLM 翻譯指南 涵蓋了相關設定。
這是一個小型測試,僅涉及一個模型、一個語言對和一個樣本。它展示了哪些問題會發生以及如何捕捉它們。它並不對工具或提示進行排名。
結果:機制倖存;英語假設未能倖免
我們使用 check_ass_translation.py 檢查了每個輸出。完整輸出在 check-results.txt 中,而 results.csv 每次運行有一列,包括腳本無法看到的問題。
| 檢查 | 整個檔案 | 僅文字 | 受保護 |
|---|---|---|---|
| 時間軸、樣式與欄位 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 |
| 所有卡拉 OK 標籤均保留,且各自附有文字 | 3 / 3 | 0 / 3 | 1 / 3 |
有兩個結果讓我們感到意外。貼上整個檔案在三次執行中都保持了結構完整,不過其中兩次也翻譯了標頭中的 Title 行。而聽起來更安全的純文字提示詞,卻產生了唯一一次標籤損壞。在其中一次執行中,它為一行帶有六個卡拉 OK 標籤的文字返回了 {\k25}翻{\k30}页,{\k45}开{\k60}灯。最後兩個標籤和 1.20 秒的高亮時間消失了,因此高亮會在該行結束前就提前結束。同一次執行還把 Room\h12 is upstairs. 變成了 12\h12号房间在楼上。,房間號碼出現了兩次。
所以有用的教訓不是「使用提示詞 X」。而是你所擔心的結構損壞很容易偵測,而全部九次執行中真正漏掉的損壞,位於 ASS 翻譯工具頁面沒有討論到的三個地方。
1. 字型無法繪製新語言
範例的樣式使用 Trebuchet MS 作為對白、Georgia 作為標誌,這對英文發行版來說很正常。這兩種字型都不包含中文字元。當我們將檢查器的字形測試指向這兩個字型檔案時,每次執行中全部 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 欄位。當我們將一個輸出中的所有三個樣式改為 Hiragino Sans GB(macOS 隨附的中文字型),並對該字型執行字形測試時,字形錯誤降為零。
選擇觀眾實際會有的字型,或隨影片一起提供。libass 指南說發行版應附加它們使用的每個字型,最好附加到 MKV 容器。由於目標語言字型是新的,附加它現在成了翻譯工作的一部分。
2. 間距代碼帶有英文習慣
Room\h12 將「Room」黏在「12」上,使它們永遠不會跨行分割。中文詞語之間沒有空格分隔,但每次執行都將 \h 保留在某處:五次執行將它放在 12号房间 和 在楼上 之間,三次放在數字之前,一次放在兩個數字副本之間。無論哪種方式,觀眾都會看到一個多餘的空格。Wait\nhere. 也有同樣的問題。使用 WrapStyle: 0 時,\n 會渲染為空格,所以 在\n这里等 會在三個詞的句子中間顯示一個間隙。
這裡的結構沒問題;語言有問題。對於詞語之間沒有空格的目標語言,請從翻譯文字中移除 \h 和 \n。只在需要強制換行的地方保留 \N,並將其放在目標句子中的自然位置。檢查器將變更的 \h 和 \n 計數報告為警告而非錯誤,原因就在於此,並且當其中一個在中文、日文或韓文文字中倖存時會發出警告。
3. 卡拉 OK 時間屬於原始詞語
卡拉 OK 行 {\k25}Turn {\k30}the {\k45}page, {\k60}turn {\k40}the {\k80}light 將每個英文音節與歌曲計時。翻譯無法有意義地保留該時間,因為中文詞語不會落在相同的節拍上。我們的執行顯示了它出錯的不同方式:
- 在四次執行中,全部六個標籤都被保留,每個都落在與之前不同的詞上。其中一次以
{\k40}打{\k80}开(「打開」)結尾,並將「light」從該行完全丟棄。 - 在四次執行中,一個音節沒有高亮任何內容,例如
打开{\k40}{\k80}灯(在空音節上高亮 0.40 秒)。在其中兩次中,一個 0.45 秒的音節也只高亮了一個逗號。 - 在一次執行中,兩個標籤消失了,如上所述。
檢查器會標記就地翻譯的卡拉 OK 行以及任何沒有文字的音節。更好的修正方法是編輯性的:不要就地翻譯卡拉 OK。保留原始計時行用於跟唱,並將翻譯添加為單獨的事件:複製卡拉 OK 事件,給它自己的樣式(例如,更小並放置在底部),移除 \k 標籤,並翻譯文字。只有當你準備好自己根據音訊計時時,才逐音節重新計時。
經得起考驗的工作流程
-
先讓來源可讀。 如果檔案顯示亂碼字元,請先修正編碼,再做其他事。我們的編碼指南 使用 SRT 範例,但相同的位元組層級步驟也適用於
.ass檔案,並保持原始位元組安全。檢查器只讀取 UTF-8 和 UTF-16。 -
決定範圍。 列出樣式並決定哪些是對白、哪些是螢幕標誌、哪些是卡拉 OK。標誌通常需要翻譯;卡拉 OK 通常需要單獨一行;註解和大括號備註由你決定。
-
只翻譯
Text欄位。 使用解析 ASS 而非將其視為純文字的工具,或者像我們的第三個條件那樣自行保護標籤。將來源檔案保留在輸出旁邊。 -
執行結構檢查。
python3 check_ass_translation.py source.ass translated.ass它比較事件數量、事件類型、欄位 1–9、樣式值、覆寫區塊、繪圖、註解行、
\N、卡拉 OK 音節和持續時間,以及返回為空或未變更的行。它不評判翻譯品質。 -
刻意修正字型。 變更每個現在包含目標語言文字的樣式中的
Fontname,然後對你將要交付的字型檔案執行字符測試:pip install fonttools python3 check_ass_translation.py source.ass translated.ass --font "Noto Sans SC=/path/to/NotoSansSC-Regular.otf"變更的字型名稱會顯示為警告,因此你可以確認每項變更都是有意為之。
-
清理間距代碼和卡拉 OK,如上所述。
-
搭配影片觀看。 在 Aegisub 或你的播放器中開啟檔案。檢查標誌是否仍符合其後方繪製的形狀,因為
\p方塊會保持英文大小,而翻譯後的標誌可能長得多或短得多。檢查台詞是否因其螢幕時間而過長。這兩個問題在檔案本身都看不出來。
BookTranslator 的適用場景
BookTranslator 的字幕翻譯工具 接受 SRT、VTT、ASS 和 SSA 檔案。根據產品頁面說明,它會保留時間戳和字幕順序,並將支援的 ASS 和 SSA 樣式附加到每個字幕項目上,因此你不必自行擷取和重新插入文字。它會以周圍台詞為上下文來翻譯對話,這有助於處理整集出現的名字和反覆出現的笑話。
我們並未為本文將此樣本交由 BookTranslator 處理。無論你使用什麼工具,都請對結果執行步驟 4 到 7。保留英文字型的樣式仍然是無法繪製中文的樣式,而就地翻譯的卡拉 OK 仍然需要編輯決策。關於字幕工作流程的其他部分,請參閱我們的 AI 字幕翻譯指南、字幕翻譯軟體比較,以及如果你的翻譯要上傳到 YouTube,請參閱 YouTube 字幕工作流程。
何時應改為轉換成 SRT
在翻譯前將 ASS 轉換為 SRT 會移除樣式、位置、繪圖和卡拉 OK,這也消除了上述大部分問題。如果你的目標平台只顯示純字幕,或者樣式對該發佈版本從不重要,那麼這是合理的取捨。對於動畫和音樂發佈作品,標誌和卡拉 OK 是作品的一部分,這樣做就是錯誤的取捨。請根據檔案將在何處顯示來決定,而不是根據哪種格式更容易翻譯。
取得測試檔案
本次測試的所有內容均可免費重複使用:
- sample-source.ass:14 個事件的英文樣本;
- check_ass_translation.py:檢查器(Python 標準函式庫;
--font測試需要 fontTools); - run_llm_ass_test.py:適用於任何 OpenAI 相容本機伺服器的三種提示條件;
- results.csv 和 check-results.txt:每次執行的結果;
- README.txt:檔案清單和測試設定,
outputs資料夾中有九個未編輯的輸出。




