SRTファイルの構成

SRTファイルは、番号付きのブロックが並んだものです。各ブロックは3つの部分からなります。番号、hours:minutes:seconds,milliseconds の形式で書かれた開始時刻と終了時刻、そして1〜2行のテキストです。空行でブロックが終わります。

329
00:24:22,584 --> 00:24:23,784
absence ...

動画プレーヤーが読むのは時刻だけです。開始時刻から終了時刻までテキストを表示し、それ以外は無視します。だから、翻訳が完璧に読めても、再生するとおかしくなることがあります。言葉は正しくても、間違った時刻に結びついてしまっているのです。

翻訳でタイミングが崩れる3つのパターン

以下の例は4つの長い作業を試したテストによるものです。このテストでは、3つのチャットモデルがそれぞれ、同じ1,200行・85分のSRTファイルを1回の返信でスペイン語に翻訳しました。

1. 行が直前の行に取り込まれる。 元のファイルでは、328行目が「...take advantage of Lady Bracknell's temporary」、329行目が「absence ...」でした。あるモデルは文全体を328行目に入れ、329行目を削除しました。その結果、画面には「absence」が1秒早く表示され、329行目の時間枠は空になります。

2. 行が抜け落ちると、以降がすべて振り直される。 同じモデルは、その後のファイルを329番から隙間なく振り直しました。357行目で2回目の取り込みが起きた後には、1,200行のうち870行が元とは違う番号になっていました。ファイルは再生できます。しかし、ご自身や編集者が翻訳を元のファイルと行番号で比べると、329行目より後のすべての行が違う行と対応づけられてしまいます。

3. タイムコードの数字が1つ変わる。 別のモデルは、元は 00:54:45,839 --> 00:54:51,039 だった行を 00:54:55,839 --> 00:54:51,039 と書きました。この行は開始より前に終わることになります。プレーヤーによって、その行が飛ばされたり、一瞬だけ表示されたり、ファイルが読み込めなくなったりします。

最初の行からすべての行が同じだけずれているファイル全体のずれは、別の問題です。字幕が動画の別のカット版や別のフレームレート用に作られていたのであり、翻訳が原因ではありません。

2分でできるチェック

元の字幕ファイルと翻訳後のファイルを、任意のテキストエディタで並べて開きます。

  1. 最終行。 両方のファイルの末尾に移動します。最後の番号と最後のタイムコードは同じになっているはずです。翻訳側が1,198で終わり、元のファイルが1,200で終わっている場合は、2行が結合されたか、欠落しています。
  2. 途中の3か所。 元のファイルの全体の約4分の1、半分、4分の3あたりからタイムコードを3つ選び、翻訳側で検索します。どちらのファイルでも同じ番号になっているはずです。番号が最初にずれた箇所が、行が欠落した場所です。
  3. ありえない時刻。 終了時刻が開始時刻より前になっている行がないか探します。長いファイルでは、小さなスクリプトや字幕エディタのエラーチェック機能を使えば、すぐに見つかります。
  4. 最後の10分間。 翻訳したファイルをプレーヤーで読み込み、終盤付近にジャンプします。そこで字幕が正しいタイミングで表示されれば、ファイルはほぼ問題ありません。

Pythonが使える場合は、この短いスクリプトで、任意の2つのファイルに対してチェック1〜3を実行できます(python3 srtcheck.py original.srt translated.srt)。テストで使った3つの翻訳では、上で説明したとおりのエラーがそのまま報告されました。

import re, sys

def cues(path):
    text = open(path, encoding="utf-8-sig").read().replace("\r", "")
    return re.findall(r"^(\d+)\n(\d\d:\d\d:\d\d,\d{3}) --> (\d\d:\d\d:\d\d,\d{3})", text, re.M)

a, b = cues(sys.argv[1]), cues(sys.argv[2])
print(f"lines: {len(a)} original, {len(b)} translated")
print(f"last:  {a[-1]} vs {b[-1]}")
times = {(s, e): n for n, s, e in a}
renumbered = sum(1 for n, s, e in b if (s, e) in times and times[(s, e)] != n)
changed = [n for n, s, e in b if (s, e) not in times]
broken = [n for n, s, e in b if e <= s]
missing = [n for n, s, e in a if (s, e) not in {(s2, e2) for _, s2, e2 in b}]
print(f"renumbered: {renumbered}, changed time codes: {changed[:10]}, "
      f"end before start: {broken[:10]}, original lines missing: {missing[:10]}")

4つすべてに合格したら、そのまま使えます。1つでも不合格だった場合は、手作業で直すより、タイミングを保持するツールでもう一度翻訳するほうが早いことがほとんどです。

行の長さは別のチェックです

スペイン語、ドイツ語、フランス語への翻訳は、英語より長くなることがよくあります。Netflixの英語(米国)スタイルガイドでは、1行42文字まで、1つの字幕につき2行までとされています。今回のテストでは、42文字を超える行を含む翻訳行の数は、モデルによって1,200行中32行から447行まで幅がありました。弊社のツールでは105行だったので、どのツールを使う場合でも確認しておく価値があります。長い行は読みにくくなりますが、タイミングが壊れることはありません。

問題を避けるには

上記のエラーが起きるのは、翻訳と一緒に番号や時刻までモデルに書き出させているためです。番号や時刻は、モデルに触らせないようにしましょう。弊社の字幕翻訳は、.srtまたは.vttファイルを読み込み、テキストだけを最大60行ずつのブロックに分けて送信します。返ってこなかった行があれば再度依頼し、番号と時刻はすべて元のファイルからそのままコピーします。同じ1,200行のテストファイルでは、1,200行すべてが同じ番号とタイムコードで返ってきました。

各ジョブの最初の部分は無料で、アカウントも不要です。映画1本やシーズン丸ごと、最大30ファイル・5,000行までは、一回払いのみで$5です。人気の翻訳先には専用ページもあります:SRTをスペイン語へ、アラビア語、ペルシア語。

方法とデータ

出典

  1. SubRip (SRT file format) — Wikipedia
  2. English (USA) Timed Text Style Guide — Netflix Partner Help Center
  3. Timed Text Style Guide: General Requirements — Netflix Partner Help Center