资讯动态

想做中英双语字幕?用 Python 把原文和译文合成一条双语 SRT,再烧录进视频

发布时间:2026/9/27 9:24:51 来源:尧图企业网站定制
做出海短视频、外语教学切片或者单纯想边看美剧边学英语你大概率遇到过这个需求同一句字幕上面一行原文、下面一行译文。这种双语字幕比单一语言字幕实用得多——观众既能看翻译又能对照原文练听力。可惜大多数字幕翻译工具只给你单语结果要么只有原文、要么只有译文。本文给一套本地可跑的方案用 Python 把两份 SRT原文 译文合成为一条双语字幕再决定是烧录进画面还是封装成软字幕。读完你手上有 en.srt 和 zh.srt十来行代码就能出双语成品。## 一、先想清楚你要的是双语还是双轨这两个经常被搞混但做法完全不同| 形式 | 长什么样 | 怎么实现 | 适合 || — | — | — | — || 双轨字幕 | 两条独立字幕流播放器里切换 | 封装两个 .srt 进容器 | 想保留纯原文/纯译文灵活切换 ||双语字幕本文| 同一时间轴一行原文一行译文叠在一起 | 把两份 SRT 合并成一条 | 学外语、短视频发布、不想让观众切来切去 |双轨上篇文章讲过把 en/zh 两条流 mux 进 mkv。本文聚焦双语合并——它更常见于 B 站/抖音/YouTube 的中英对照视频也是很多人真正想要的那个效果。## 二、准备两份 SRT假设你已经拿到了原文和译文两份字幕怎么来都行本地 ASR 跑出来的原文 翻译接口出的译文、或者手动对齐的两份稿子。文件长这样en.srt100:00:01,000 -- 00:00:04,500Hey, welcome back to the channel.200:00:04,800 -- 00:00:08,200Today were building a bilingual subtitle tool.zh.srt100:00:01,000 -- 00:00:04,500嘿欢迎回到这个频道。200:00:04,800 -- 00:00:08,200今天我们要做一个双语字幕工具。只要两份的**条目数量一致、且按出现顺序一一对应**也就是第 1 句对第 1 句合并就是线性操作非常简单。依赖只要一个bashpip install pysrtpysrt专门用来读/写/操作 SRT比自己写正则省心得多。## 三、核心按时间轴合并成双语思路很直白遍历两份字幕的同一索引位置取原文那条的时间轴把译文 换行 原文拼成新字幕的文本。时间轴用原文或译文挑一个更准的的即可因为两份应当是对齐的。pythonimport pysrtdef merge_bilingual(en_path: str, zh_path: str, out_path: str, topzh, sep\n): 把 en/zh 两份 SRT 合并为一条双语字幕。 top: 上行显示哪种语言 (zh 译文在上 / en 原文在上) en pysrt.open(en_path) zh pysrt.open(zh_path) if len(en) ! len(zh): raise ValueError( f条目数不一致: en{len(en)} zh{len(zh)}请先做时间轴对齐再合并) out pysrt.SubRipFile() for i, (e, z) in enumerate(zip(en, zh), start1): # 时间轴用原文的时间两者应对齐 item pysrt.SubRipItem( indexi, starte.start, ende.end, text(f{z.text}{sep}{e.text} if top zh else f{e.text}{sep}{z.text}), ) out.append(item) out.save(out_path, encodingutf-8) print(f已生成双语字幕: {out_path}共 {len(out)} 条)merge_bilingual(en.srt, zh.srt, bilingual.srt, topzh)跑完得到bilingual.srt每条长这样100:00:01,000 -- 00:00:04,500嘿欢迎回到这个频道。Hey, welcome back to the channel.topzh 表示中文在上、英文在下符合国内观众的阅读习惯想英文在上就改成 topen。## 四、进阶时间轴不完全对齐怎么办现实里两份字幕常常**条目数对不上**——比如译文做了断句合并或者 ASR 把一句话切成了三截。硬按索引合并会错位。这种情况改用**时间轴重叠匹配**对每条译文找时间上覆盖它的原文段。pythondef merge_by_time(en_path, zh_path, out_path, top“zh”): en pysrt.open(en_path) zh pysrt.open(zh_path) out pysrt.SubRipFile() def overlap(a, b): # 两段时间轴是否有交集 return not (a.end b.start or b.end a.start) for i, z in enumerate(zh, start1): # 取与本条译文时间重叠的原文拼成一个块 matched [e.text for e in en if overlap(e, z)] src “.join(matched) if matched else “” text (f”{z.text}\n{src} if top “zh” else f{src}\n{z.text}“) out.append(pysrt.SubRipItem( indexi, startz.start, endz.end, texttext)) out.save(out_path, encoding“utf-8”)这个版本不那么严格、但更耐造译文条数可以和原文不同重叠的原文会被拼到对应译文下面。代价是丢失了一一对应的精确性适合处理机翻断句不规整的稿子。## 五、烧录进视频最易踩坑的一步合成好 bilingual.srt 后先转成 .ass高级字幕格式支持样式因为 SRT 本身不带字体/颜色信息烧录中文时播放器和 ffmpeg 经常找不到中文字体直接给你一堆**方块 tofu **。bash# SRT - ASS保留文本后面加样式ffmpeg -y -i bilingual.srt bilingual.ass然后用 subtitles 滤镜烧录关键是 force_style 指定中文字体名。Windows 上常用微软雅黑macOS/Linux 用Noto Sans CJK SC更稳妥是给 fontfile 绝对路径跨机器都不会翻车bashffmpeg -y -i input.mp4 \ -vf “subtitlesbilingual.ass:force_style‘FontNameMicrosoft YaHei,FontSize24,PrimaryColourH00FFFFFF’” \ -c:a copy output_bilingual.mp4要点- **FontName 必须和系统里装的中文字体名一字不差**否则 ffmpeg 静默回退到默认字体中文又变方块。- 想双行不同颜色比如译文白、原文灰可以在 ASS 里给两行分别打 font color... 标签再用 force_style 兜底。- 字幕位置默认在底部想上移避免挡脸加 MarginV60 之类的参数。如果跨平台发布强烈建议用 fontfile 而不是 FontNamebashffmpeg -y -i input.mp4 \ -vf “subtitlesbilingual.ass:force_style‘FontSize24’:fontfile‘C\:/Windows/Fonts/msyh.ttc’” \ -c:a copy output_bilingual.mp4## 六、不想烧录封装成软字幕也行烧录会把字幕焊死在画面上以后想改字、想关掉都不行。如果想保留灵活性把它当软字幕封装进 mkv/mp4播放器里随时开关bashffmpeg -y -i input.mp4 -i bilingual.srt \ -map 0:v -map 0:a -map 1 \ -c copy -c:s srt \ -metadata:s:s:0 languagechi -metadata:s:s:0 title“中英双语” \ output_bilingual.mkv注意 mp4 对字幕流支持有限很多播放器不显示**要做软字幕优先用 mkv 容器**。## 七、完整可运行脚本把上面拼起来存成 bilingual_subs.py改一下文件路径就能跑通合并 → 转 ASS → 烧录pythonimport pysrt, subprocess, sysEN, ZH “en.srt”, “zh.srtBILINGUAL_SRT, BILINGUAL_ASS “bilingual.srt”, “bilingual.assVIDEO, OUT “input.mp4”, “output_bilingual.mp4FONT “Microsoft YaHei” # 改成你系统里真实存在的中文字体名def merge(top“zh”): en, zh pysrt.open(EN), pysrt.open(ZH) if len(en) ! len(zh): print(“条目数不一致改用 merge_by_time 版本”); sys.exit(1) out pysrt.SubRipFile() for i, (e, z) in enumerate(zip(en, zh), 1): txt f”{z.text}\n{e.text}” if top “zh” else f”{e.text}\n{z.text}” out.append(pysrt.SubRipItem(i, e.start, e.end, txt)) out.save(BILINGUAL_SRT, encoding“utf-8”) print(f合并完成共 {len(out)} 条)def to_ass(): subprocess.run([“ffmpeg”, “-y”, “-i”, BILINGUAL_SRT, BILINGUAL_ASS], checkTrue, capture_outputTrue) print(“已转 ASS”)def burn(): vf (fsubtitles{BILINGUAL_ASS} f:force_style‘FontName{FONT},FontSize24’“) subprocess.run([“ffmpeg”, “-y”, “-i”, VIDEO, “-vf”, vf, “-c:a”, “copy”, OUT], checkTrue, capture_outputTrue) print(f烧录完成 - {OUT}”)ifname “main”: merge(top“zh”) to_ass() burn()## 八、提速与踩坑-字体名是大坑FontName写错不会报错只会出方块。先在你系统字体目录确认名字Windows 在C:/Windows/FontsmacOS 用fc-list或者直接用fontfile绝对路径最稳。-ASS 转义原文里如果带花括号{}、反斜杠\ASS 会当成样式指令。合并前最好把文本里的{}替换掉避免烧录时整条字幕消失。-时间轴偏移校准如果译文整体比原文慢了 0.5 秒可以用pysrt的shift方法统一平移zh.shift(seconds0.5)再合并。-CJK 编码SRT 一定存成 UTF-8否则中文乱码。pysrt.open(..., encodingutf-8)显式指定最安全。-大文件烧录慢烧录是重新编码视频1080p 一小时素材可能要十几分钟。只想快速预览效果先用-ss 0 -t 60截前 60 秒试烧。## 九、工具怎么选| 方案 | 优点 | 缺点 | 适合 || — | — | — | — || 本地 Python 合并 ffmpeg 烧录 | 完全可控、能定双语顺序/样式、可批量 | 要配环境、字体坑多 | 固定产出、要精细调样式 || 在线字幕/翻译工具 | 免安装、上传即出、不用管字体 | 大多只给单语、双语合并要另找工具 | 偶尔一两个视频、不想折腾 |如果你只是想把一段本地视频/音频快速翻成带翻译的字幕、懒得自己跑 ASR 翻译 字幕合成这一整套管线可以把文件上传到像 AIVideoTranslatoraivideotranslator.ai这类在线工具——免费、在线、免注册传上去就能拿到翻译后的字幕/语音结果省去配环境的功夫。要注意它处理的是你上传的本地文件不是粘贴视频链接去抓第三方平台内容用的时侯别搞混。本文这套本地方案胜在可控双语顺序、字体、颜色、烧录还是封装全都能自己定适合长期、批量、要统一风格的产出。## 十、小结双语字幕的本质就是两份对齐的 SRT → 合并成一行双行文本 → 决定烧录还是封装1.pysrt读两份字幕按索引或时间轴重叠拼成译文 换行 原文2. 转 ASS 并用force_style指定中文字体避免烧录出方块3. 要永久就烧录进 mp4要灵活就封装进 mkv 当软字幕。最容易被卡住的就是中文字体那一步——FontName写错静默翻车直接用fontfile绝对路径最省心。把脚本存成bilingual_subs.py、改一下EN/ZH/VIDEO路径就能开跑先截一分钟片段试烧确认字体和排版没问题再跑全片。做出海短视频、外语教学切片或者单纯想边看美剧边学英语你大概率遇到过这个需求同一句字幕上面一行原文、下面一行译文。这种双语字幕比单一语言字幕实用得多——观众既能看翻译又能对照原文练听力。可惜大多数字幕翻译工具只给你单语结果要么只有原文、要么只有译文。本文给一套本地可跑的方案用 Python 把两份 SRT原文 译文合成为一条双语字幕再决定是烧录进画面还是封装成软字幕。读完你手上有 en.srt 和 zh.srt十来行代码就能出双语成品。一、先想清楚你要的是双语还是双轨这两个经常被搞混但做法完全不同形式长什么样怎么实现适合双轨字幕两条独立字幕流播放器里切换封装两个 .srt 进容器想保留纯原文/纯译文灵活切换双语字幕本文同一时间轴一行原文一行译文叠在一起把两份 SRT 合并成一条学外语、短视频发布、不想让观众切来切去双轨上篇文章讲过把 en/zh 两条流 mux 进 mkv。本文聚焦双语合并——它更常见于 B 站/抖音/YouTube 的中英对照视频也是很多人真正想要的那个效果。二、准备两份 SRT假设你已经拿到了原文和译文两份字幕怎么来都行本地 ASR 跑出来的原文 翻译接口出的译文、或者手动对齐的两份稿子。文件长这样en.srt1 00:00:01,000 -- 00:00:04,500 Hey, welcome back to the channel. 2 00:00:04,800 -- 00:00:08,200 Today were building a bilingual subtitle tool.zh.srt1 00:00:01,000 -- 00:00:04,500 嘿欢迎回到这个频道。 2 00:00:04,800 -- 00:00:08,200 今天我们要做一个双语字幕工具。只要两份的条目数量一致、且按出现顺序一一对应也就是第 1 句对第 1 句合并就是线性操作非常简单。依赖只要一个pipinstallpysrtpysrt专门用来读/写/操作 SRT比自己写正则省心得多。三、核心按时间轴合并成双语思路很直白遍历两份字幕的同一索引位置取原文那条的时间轴把译文 换行 原文拼成新字幕的文本。时间轴用原文或译文挑一个更准的的即可因为两份应当是对齐的。importpysrtdefmerge_bilingual(en_path:str,zh_path:str,out_path:str,topzh,sep\n):把 en/zh 两份 SRT 合并为一条双语字幕。 top: 上行显示哪种语言 (zh 译文在上 / en 原文在上) enpysrt.open(en_path)zhpysrt.open(zh_path)iflen(en)!len(zh):raiseValueError(f条目数不一致: en{len(en)}zh{len(zh)}请先做时间轴对齐再合并)outpysrt.SubRipFile()fori,(e,z)inenumerate(zip(en,zh),start1):# 时间轴用原文的时间两者应对齐itempysrt.SubRipItem(indexi,starte.start,ende.end,text(f{z.text}{sep}{e.text}iftopzhelsef{e.text}{sep}{z.text}),)out.append(item)out.save(out_path,encodingutf-8)print(f已生成双语字幕:{out_path}共{len(out)}条)merge_bilingual(en.srt,zh.srt,bilingual.srt,topzh)跑完得到bilingual.srt每条长这样1 00:00:01,000 -- 00:00:04,500 嘿欢迎回到这个频道。 Hey, welcome back to the channel.topzh表示中文在上、英文在下符合国内观众的阅读习惯想英文在上就改成topen。四、进阶时间轴不完全对齐怎么办现实里两份字幕常常条目数对不上——比如译文做了断句合并或者 ASR 把一句话切成了三截。硬按索引合并会错位。这种情况改用时间轴重叠匹配对每条译文找时间上覆盖它的原文段。defmerge_by_time(en_path,zh_path,out_path,topzh):enpysrt.open(en_path)zhpysrt.open(zh_path)outpysrt.SubRipFile()defoverlap(a,b):# 两段时间轴是否有交集returnnot(a.endb.startorb.enda.start)fori,zinenumerate(zh,start1):# 取与本条译文时间重叠的原文拼成一个块matched[e.textforeinenifoverlap(e,z)]src .join(matched)ifmatchedelsetext(f{z.text}\n{src}iftopzhelsef{src}\n{z.text})out.append(pysrt.SubRipItem(indexi,startz.start,endz.end,texttext))out.save(out_path,encodingutf-8)这个版本不那么严格、但更耐造译文条数可以和原文不同重叠的原文会被拼到对应译文下面。代价是丢失了一一对应的精确性适合处理机翻断句不规整的稿子。五、烧录进视频最易踩坑的一步合成好bilingual.srt后先转成.ass高级字幕格式支持样式因为 SRT 本身不带字体/颜色信息烧录中文时播放器和 ffmpeg 经常找不到中文字体直接给你一堆方块 tofu 。# SRT - ASS保留文本后面加样式ffmpeg-y-ibilingual.srt bilingual.ass然后用subtitles滤镜烧录关键是force_style指定中文字体名。Windows 上常用微软雅黑macOS/Linux 用Noto Sans CJK SC更稳妥是给fontfile绝对路径跨机器都不会翻车ffmpeg-y-iinput.mp4\-vfsubtitlesbilingual.ass:force_styleFontNameMicrosoft YaHei,FontSize24,PrimaryColourH00FFFFFF\-c:acopy output_bilingual.mp4要点FontName 必须和系统里装的中文字体名一字不差否则 ffmpeg 静默回退到默认字体中文又变方块。想双行不同颜色比如译文白、原文灰可以在 ASS 里给两行分别打font color...标签再用force_style兜底。字幕位置默认在底部想上移避免挡脸加MarginV60之类的参数。如果跨平台发布强烈建议用fontfile而不是FontNameffmpeg-y-iinput.mp4\-vfsubtitlesbilingual.ass:force_styleFontSize24:fontfileC\\:/Windows/Fonts/msyh.ttc\-c:acopy output_bilingual.mp4六、不想烧录封装成软字幕也行烧录会把字幕焊死在画面上以后想改字、想关掉都不行。如果想保留灵活性把它当软字幕封装进 mkv/mp4播放器里随时开关ffmpeg-y-iinput.mp4-ibilingual.srt\-map0:v-map0:a-map1\-ccopy-c:ssrt\-metadata:s:s:0languagechi -metadata:s:s:0title中英双语\output_bilingual.mkv注意 mp4 对字幕流支持有限很多播放器不显示要做软字幕优先用 mkv 容器。七、完整可运行脚本把上面拼起来存成bilingual_subs.py改一下文件路径就能跑通合并 → 转 ASS → 烧录importpysrt,subprocess,sys EN,ZHen.srt,zh.srtBILINGUAL_SRT,BILINGUAL_ASSbilingual.srt,bilingual.assVIDEO,OUTinput.mp4,output_bilingual.mp4FONTMicrosoft YaHei# 改成你系统里真实存在的中文字体名defmerge(topzh):en,zhpysrt.open(EN),pysrt.open(ZH)iflen(en)!len(zh):print(条目数不一致改用 merge_by_time 版本);sys.exit(1)outpysrt.SubRipFile()fori,(e,z)inenumerate(zip(en,zh),1):txtf{z.text}\n{e.text}iftopzhelsef{e.text}\n{z.text}out.append(pysrt.SubRipItem(i,e.start,e.end,txt))out.save(BILINGUAL_SRT,encodingutf-8)print(f合并完成共{len(out)}条)defto_ass():subprocess.run([ffmpeg,-y,-i,BILINGUAL_SRT,BILINGUAL_ASS],checkTrue,capture_outputTrue)print(已转 ASS)defburn():vf(fsubtitles{BILINGUAL_ASS}f:force_styleFontName{FONT},FontSize24)subprocess.run([ffmpeg,-y,-i,VIDEO,-vf,vf,-c:a,copy,OUT],checkTrue,capture_outputTrue)print(f烧录完成 -{OUT})if__name____main__:merge(topzh)to_ass()burn()八、提速与踩坑字体名是大坑FontName写错不会报错只会出方块。先在你系统字体目录确认名字Windows 在C:/Windows/FontsmacOS 用fc-list或者直接用fontfile绝对路径最稳。ASS 转义原文里如果带花括号{}、反斜杠\ASS 会当成样式指令。合并前最好把文本里的{}替换掉避免烧录时整条字幕消失。时间轴偏移校准如果译文整体比原文慢了 0.5 秒可以用pysrt的shift方法统一平移zh.shift(seconds0.5)再合并。CJK 编码SRT 一定存成 UTF-8否则中文乱码。pysrt.open(..., encodingutf-8)显式指定最安全。大文件烧录慢烧录是重新编码视频1080p 一小时素材可能要十几分钟。只想快速预览效果先用-ss 0 -t 60截前 60 秒试烧。九、工具怎么选方案优点缺点适合本地 Python 合并 ffmpeg 烧录完全可控、能定双语顺序/样式、可批量要配环境、字体坑多固定产出、要精细调样式在线字幕/翻译工具免安装、上传即出、不用管字体大多只给单语、双语合并要另找工具偶尔一两个视频、不想折腾如果你只是想把一段本地视频/音频快速翻成带翻译的字幕、懒得自己跑 ASR 翻译 字幕合成这一整套管线可以把文件上传到像 AIVideoTranslatoraivideotranslator.ai这类在线工具——免费、在线、免注册传上去就能拿到翻译后的字幕/语音结果省去配环境的功夫。要注意它处理的是你上传的本地文件不是粘贴视频链接去抓第三方平台内容用的时侯别搞混。本文这套本地方案胜在可控双语顺序、字体、颜色、烧录还是封装全都能自己定适合长期、批量、要统一风格的产出。十、小结双语字幕的本质就是两份对齐的 SRT → 合并成一行双行文本 → 决定烧录还是封装pysrt读两份字幕按索引或时间轴重叠拼成译文 换行 原文转 ASS 并用force_style指定中文字体避免烧录出方块要永久就烧录进 mp4要灵活就封装进 mkv 当软字幕。最容易被卡住的就是中文字体那一步——FontName写错静默翻车直接用fontfile绝对路径最省心。把脚本存成bilingual_subs.py、改一下EN/ZH/VIDEO路径就能开跑先截一分钟片段试烧确认字体和排版没问题再跑全片。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑