新闻详情

新闻详情

首页 / 资讯中心 / 详情

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

发布时间:2026/9/27 9:24:43来源:尧图网络
想做中英双语字幕?用 Python 把原文和译文合成一条双语 SRT,再烧录进视频
做出海短视频、外语教学切片或者单纯想边看美剧边学英语你大概率遇到过这个需求同一句字幕上面一行原文、下面一行译文。这种双语字幕比单一语言字幕实用得多——观众既能看翻译又能对照原文练听力。可惜大多数字幕翻译工具只给你单语结果要么只有原文、要么只有译文。本文给一套本地可跑的方案用 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路径就能开跑先截一分钟片段试烧确认字体和排版没问题再跑全片。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

STM32红外PM2.5传感器驱动:定时器输入捕获测占空比与浓度换算 2026/9/27 10:52:37

STM32红外PM2.5传感器驱动:定时器输入捕获测占空比与浓度换算

1. 项目缘起与整体设计思路1.1 为什么选红外PM2.5传感器而不是激光款做环境监测类项目,PM2.5传感器基本绕不开两个选择:红外散射式和激光散射式。激光款精度高、能测到0.3微米颗粒,但价格普遍在几十到上百元,而且需要风扇或加热电…

阅读更多 →
STM32嵌入式项目V1封装实战:CAN、FreeRTOS、Flash与PI控制集成 2026/9/27 10:52:30

STM32嵌入式项目V1封装实战:CAN、FreeRTOS、Flash与PI控制集成

1. 从零散模块到可交付系统:V1封装的真实动机做嵌入式项目的人大概都有过这种体验:功能一个个都调通了,CAN能收发、Flash能读写、FreeRTOS任务跑得也挺欢,但当你试图把整个工程交给别人、或者过两个月自己再回来看的时候&#xff…

阅读更多 →
数字频率计数器选购指南:从时基到微波架构,一次讲透核心参数与选型逻辑 2026/9/27 10:52:30

数字频率计数器选购指南:从时基到微波架构,一次讲透核心参数与选型逻辑

1. 从一次踩坑说起:为什么你需要一台靠谱的数字频率计数器前阵子帮一个做射频模块的朋友调一套发射链路,手头只有一台入门级台式万用表,测个几十兆的信号频率,读数跳得跟心电图似的,最后一位数字基本靠猜。后来借了一台…

阅读更多 →
县区工会网站建设方案图解步骤 2026/9/27 10:52:30

县区工会网站建设方案图解步骤

县区工会网站建设避坑指南:3步搞定安全与SEO 很多县区工会的朋友,手里拿着预算想建个官网,心里却直打鼓: 自己不会代码想做网站 ,找外包怕被坑,自己弄又怕搞砸。别慌,这份 避坑指南…

阅读更多 →
STM32红外PM2.5传感器驱动实战:ADC采样、PWM捕获与数据标定 2026/9/27 10:52:30

STM32红外PM2.5传感器驱动实战:ADC采样、PWM捕获与数据标定

1. 从一颗传感器说起:为什么选择红外PM2.5方案PM2.5监测这两年从专业设备慢慢下沉到了家用和创客圈,我最早接触这个需求是帮朋友做一个室内空气质量看板,要求成本压到百元以内、能实时刷新、数据还得靠谱。翻了一圈方案,激光散射的…

阅读更多 →
设计网站公司讲湖南岚鸿多少钱及防黑实战复盘 2026/9/27 10:52:23

设计网站公司讲湖南岚鸿多少钱及防黑实战复盘

设计网站公司讲湖南岚鸿多少钱及防黑实战复盘 网站被黑挂马不知道怎么办?别慌,先查日志再找专业团队,别自己瞎折腾。很多老板问我,设计网站公司讲湖南岚鸿多少钱,其实价格背后是安全成本的博弈。 一、 项目背景:一次典型的“被黑”事故…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉