Как переводить субтитры ASS/SSA, не ломая стили, позиции и караоке
Переводите только видимые диалоги в файле .ass, затем проверяйте тайминг, теги, караоке и шрифты. С примером файла, бесплатной проверкой и тестом локальной LLM из 9 запусков.

Файл субтитров ASS или SSA — это небольшая программа: заголовок, таблица стилей и список событий с таймингом, последнее поле которых смешивает диалог с кодом форматирования. Чтобы перевести его, изменяйте только читаемые слова в этом последнем поле, оставляйте всё остальное побайтно нетронутым, а затем проверьте три вещи, которые ни один инструмент перевода не исправит за вас: шрифты, коды интервалов и строки караоке.
Мы перевели образец из 14 событий на упрощённый китайский девять раз с помощью локальной модели, используя три разных промпта, и проверили каждый результат написанным нами скриптом. Тайминг, позиции, цвета, комментарии и рисунки сохранились во всех девяти. Сломались части файла, которые рассчитаны на английский: во всех девяти стилевые шрифты не содержали китайских символов, поэтому файл полагался бы на плеер для подстановки шрифта, а жёсткий пробел из английской строки стал видимым промежутком в китайской. Строка караоке вернулась с таймингом, указывающим на неправильные слова, в каждом запуске, а в четырёх запусках некоторые слоги вообще ничего не подсвечивали.
Краткий ответ: что переводить, а что оставить без изменений
| Часть файла | Пример из нашего образца | Переводить? |
|---|---|---|
Заголовок [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, содержит то, что читает зритель. В руководстве по формату файлов ASS проекта libass отмечается, что это последнее поле «может содержать запятые», поэтому небрежное разбиение по каждой запятой ломает строку вроде Well, if it's there, then, we go now. Надёжный инструмент разбивает только по первым девяти запятым.
Внутри Text всё, что заключено в фигурные скобки, является блоком переопределения. В справочнике по тегам переопределения Aegisub определены коды, которые вы будете встречать чаще всего:
\Nпринудительно переносит строку во всех режимах переноса.\nпереносит строку только в режиме переноса 2, а в остальных случаях является пробелом.\h— неразрывный пробел.\an8задаёт выравнивание с использованием раскладки цифровой клавиатуры, поэтому 8 — это верхний центр.\pos(960,120)размещает строку в координатах скрипта.\k25— караоке-слог; длительность указывается в сантисекундах, поэтому 25 означает четверть секунды.- После
\p1текст «будет интерпретироваться как инструкции для рисования», поэтому переводчик, который «переведёт»m 0 0 l 200 0, уничтожит фигуру. - Нераспознанный текст внутри фигурных скобок «молча игнорируется», поэтому в файлах фансабов часто встречаются примечания переводчика в фигурных скобках.
Строки, начинающиеся с Comment:, используют те же поля, но, согласно руководству libass, «ничего не будет отображаться на экране».
Что мы тестировали
Мы написали sample-source.ass — сцену из 14 событий в книжном магазине, с одним примером каждой из перечисленных выше возможностей: курсив, жёсткий перенос, запятые в диалоге, примечание в фигурных скобках, строка комментария, позиционированная вывеска, векторный прямоугольник, затухание, неразрывный пробел, смена цвета с помощью \r, мягкий перенос, эффект прокрутки Banner и караоке-строка из шести слогов.
Затем мы попросили локальную модель перевести его на упрощённый китайский тремя способами:
- Весь файл. Вставить весь файл
.assи попросить вернуть переведённый файл. - Только текст. Отправить только поле
Textкаждой строки диалога в формате JSON, с тегами внутри, и указанием сохранять каждый блок{...}и каждый\N,\nи\h. - Защищённый. То же самое, но сначала заменить каждый блок в фигурных скобках и каждый код строки на нумерованный заполнитель, а после вернуть оригиналы на место.
Во втором и третьем условиях скрипт никогда не отправляет модели векторный рисунок или строку комментария, поэтому эти строки могли быть повреждены только в условии с целым файлом.
Моделью была Qwen 3.6 27B (Q4_K_M) в LM Studio 0.4.8 на Apple M4 Max с 64 ГБ памяти, с отключённым режимом размышления и температурой 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 |
| Все теги караоке сохранены, каждый с текстом | 3 из 3 | 0 из 3 | 1 из 3 |
Два результата нас удивили. Вставка всего файла целиком сохранила структуру во всех трёх прогонах, хотя в двух из них она также перевела строку Title в заголовке. А промпт «только текст», который звучит безопаснее, дал единственные сломанные теги. В одном прогоне он вернул {\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. Тайминг караоке принадлежит исходным словам
Караоке-строка {\k25}Turn {\k30}the {\k45}page, {\k60}turn {\k40}the {\k80}light синхронизирует каждый английский слог с песней. Перевод не может сохранить этот тайминг осмысленно, потому что китайские слова не попадают на те же доли. Наши прогоны показывают разные способы, которыми это ломается:
- В четырёх прогонах все шесть тегов были сохранены, каждый на другом слове, чем раньше. Один из них закончился на
{\k40}打{\k80}开, «открыть», и полностью выбросил «light» из строки. - В четырёх прогонах слог ничего не подсвечивал, например
打开{\k40}{\k80}灯(0,40 секунды подсветки на пустом слоге). В двух из них слог длительностью 0,45 секунды также подсвечивал только запятую. - В одном прогоне два тега исчезли, как описано выше.
Чекер помечает караоке-строку, переведённую на месте, и любой слог, оставшийся без текста. Лучшее решение — редакторское: не переводите караоке на месте. Сохраните исходную синхронизированную строку для подпевания и добавьте перевод как отдельное событие: скопируйте караоке-событие, задайте ему собственный стиль (например, меньше и внизу), удалите теги \k и переведите текст. Заново синхронизируйте его по слогам, только если вы готовы сами выставлять тайминг по аудио.
Рабочий процесс, который выдерживает проверку
-
Сначала сделайте исходник читаемым. Если файл показывает искажённые символы, исправьте кодировку прежде всего остального. Наше руководство по кодировкам использует примеры SRT, но те же пошаговые действия на уровне байтов работают и для файла
.assи сохраняют исходные байты в безопасности. Чекер читает только UTF-8 и UTF-16. -
Определите объём. Перечислите стили и решите, какие из них — диалоги, какие — вывески на экране, а какие — караоке. Вывески обычно нужно переводить; караоке обычно требует отдельной строки; комментарии и заметки в фигурных скобках — на ваше усмотрение.
-
Переводите только поле
Text. Используйте инструмент, который разбирает ASS, а не обращается с ним как с обычным текстом, или защитите теги самостоятельно, как в нашем третьем условии. Держите исходный файл рядом с выводом. -
Запустите структурную проверку.
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 для результата. Стиль, сохранивший английский шрифт, — это всё ещё стиль, который не может отобразить китайский, а караоке, переведённое на месте, всё ещё требует редакторского решения. Об остальном процессе работы с субтитрами читайте в нашем руководстве по ИИ-переводу субтитров, нашем сравнении программ для перевода субтитров и, если ваш перевод идёт на YouTube, в процессе работы с субтитрами YouTube.
Когда вместо этого конвертировать в SRT
Конвертация ASS в SRT перед переводом удаляет стили, позиции, рисунки и караоке, что также устраняет большинство проблем, описанных выше. Это разумный компромисс, если ваша целевая платформа показывает только простые субтитры или если оформление никогда не было важным для релиза. Это неправильный компромисс для аниме и музыкальных релизов, где надписи и караоке являются частью работы. Решайте, исходя из того, где файл будет показан, а не из того, какой формат проще переводить.
Получите тестовые файлы
Всё из этого теста можно свободно использовать повторно:
- 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.
Похожие статьи




