调用百度翻译API翻译日语srt字幕
先了解下srt字幕的格式:
1
00:00:00,003 --> 00:00:01,003
第一句
2
00:00:02,520 --> 00:00:03,090
第二句
语句序号占一行,起止时间轴点占一行,语句占接下来的一行(或多行) 然后带一个空行
格式比较简单,node.js有第三方库subtitles-parser可以解析srt格式字符串
const fs=require('fs');
const srtpath="yoursrtpath"; //srt路径
const srtContent = fs.readFileSync(srtpath+process.argv.slice(2)[0]+'.srt', 'utf8');
const SubtitlesParser = require('subtitles-parser');
const subtitles = SubtitlesParser.fromSrt(srtContent);
解析后得到一个subtitles对象数组,对象包含起止时间和语句文本,
注意下:srt文件最好是utf8 without bom的编码。
要调用百度翻译api,首先你需要在百度翻译注册账号开通通用文本翻译服务,注册后得到appid和密钥,可以根据自己的情况开通不同级别的服务。标准版(注册后未认证):每月前5万字符免费(QPS=1),超出要收取超出部分费用;单次最长请求1000字符。高级版(个人认证):每月前100万字符免费(QPS=10),超出要收取超出部分费用;单次最长请求6000字符。
调用方式也比较简单,get方式访问翻译url,传入query参数,其中包含源语言,目标语言,待翻译语句,appid和盐和签名,其中盐可以是时间戳,签名是包含APP ID 、 待翻译语句、盐和密钥这些字符串连接起来的串的md5值的16进制码。具体代码如下:
const axios = require('axios');
const crypto = require('crypto');
const APP_ID = 'yourbaiduappid';
const SECRET_KEY = 'yourbaiduappkey';
const URL = 'https://fanyi-api.baidu.com/api/trans/vip/translate';
async function translateText(query, from, to) {
const salt = Date.now();
const sign = crypto.createHash('md5').update(APP_ID + query + salt + SECRET_KEY).digest('hex');
const params = {
q: query,
from: from,
to: to,
appid: APP_ID,
salt: salt,
sign: sign
};
try {
const response = await axios.get(URL, { params });
return response.data;
} catch (error) { console.error('Error calling Baidu Translate API:', error); }
}
为降低api调用频次,可以将srt中多条语句合并起来成批发送。这里提醒下,调用百度翻译api是get方式,请求中翻译语句会采用url编码,这样一个日语字符会占用9个字符位,由于url也有长度限制,所以需要自行调整下每次最大传输字符数。
const maxlength=600; //根据具体情况调整
let rows=subtitles.length; //srt文件中语句数量
let bufrows="";
let start=0;
(async()=>{
//批量翻译 减少调用百度翻译服务次数,翻译结果覆盖subtitles数组中对象的text值
for (let i=0;i<rows;i++) {
if (bufrows.length+subtitles[i]["text"].length+2>maxlength) {
let data=await translateText(bufrows, 'jp', 'zh');
if (data.error_code) console.log(data)
else for (let j=0;j<data.trans_result.length;j++) subtitles[start+j]["text"]=data.trans_result[j]["dst"];
bufrows=subtitles[i]["text"]+"\n";
start=i;
}
else bufrows+=subtitles[i]["text"]+"\n";
}
let data=await translateText(bufrows, 'jp', 'zh');
if (data.error_code) { console.log(data); }
else {
for (let j=0;j<data.trans_result.length;j++) {
subtitles[start+j]["text"]=data.trans_result[j]["dst"];
}
}
//保存subtitles到srt文件
const newSrtContent = SubtitlesParser.toSrt(subtitles);
fs.writeFileSync(srtpath+process.argv.slice(2)[0]+'.cn.srt', newSrtContent);
})();
执行后没有提示报错就可以得到翻译好的汉语字幕了。
有报错的话,要检查下看是哪里的问题。我就遇到百度翻译提示命中敏感词而拒绝当次调用的情况,这种情况下,其实你也没有必要去定位找哪一句命中了,可以考虑用百度翻译的网页版。
从原始字幕文件中提取语句文本出来,
//srt2txt.js
const fs=require('fs');
const srtpath="yoursrtpath"; //srt路径
const SubtitlesParser = require('subtitles-parser');
const srtContent = fs.readFileSync(srtpath+process.argv.slice(2)[0]+'.srt', 'utf8');
const subtitles = SubtitlesParser.fromSrt(srtContent);
let newstr="";
subtitles.forEach(item=>{ newstr+=item.text.replace(/[\r\n]/g, " ")+"\n"; });
fs.writeFileSync(srtpath+process.argv.slice(2)[0]+'.txt', newstr);
将全部语句内容粘贴进网页原文处(注意有10000个字符长度限制,如果超出就先分成几段分别翻译),待翻译完成后,把翻译结果保存到本地txt文件,再使用源字幕的时间轴保存为新的字幕文件。
const fs=require('fs');
const srtpath="yoursrtpath"; //srt路径
const data = fs.readFileSync(srtpath+process.argv.slice(2)[0]+'.cn.txt', 'utf8');//百度翻译网页版翻译结果保存的文件
const lines = data.split('\r\n');
const SubtitlesParser = require('subtitles-parser');
const srtContent = fs.readFileSync(srtpath+process.argv.slice(2)[0]+'.srt', 'utf8');//原始srt字幕文件
const subtitles = SubtitlesParser.fromSrt(srtContent);
let len=subtitles.length;
for (let i=0;i<len;i++) subtitles[i]["text"]=lines[i];
const newSrtContent = SubtitlesParser.toSrt(subtitles);
fs.writeFileSync(srtpath+process.argv.slice(2)[0]+'.cn.srt', newSrtContent);//翻译后的字幕文件
什么,只有视频,没有字幕文件怎么办,推荐一下集成了语言识别vosk的视频字幕工具SubtitleEdit,其实它也支持自动翻译功能,不过它调用的是google翻译或微软bing翻译API,目前我们这里访问有些问题,所以只好退而求其次,整出srt字幕,再自行翻译处理,国内能免费使用的翻译api其实也有好几个,比较了下,百度的给的免费额度大一些。