前言
由于最近APP需要增加对其它语言的支持,因此需要有个可以实现翻译的脚本,摸索了两三天,虽然最后感觉脚本不怎么完美,但还是记录下这期间遇到的问题:
过程
在网上搜了一些如何用python实现google脚本,大致有三种:
1.调用google API的
2.使用别人已经封装好的库
3.类似爬虫方式获取(我没爬过,也不知道算不算)
这里采用第三种,主要是看了利用python调用谷歌翻译API这篇文章,感觉蛮简单,也感觉比较靠谱,然后就开搞了。
按照利用python调用谷歌翻译API这篇文章实现脚本以后,发现只能翻译成中文,而且不适合翻译多个句子。
最后自己摸索了一下,将这个脚本稍微改了下,支持翻译多条语句:
import requests
import json
import execjs # 必须,需要先用pip 安装,用来执行js脚本
from urllib.parse import quote
# 用来判断是否需要打印日志
debug = True
class Py4Js:
def __init__(self):
self.ctx = execjs.compile("""
function TL(a) {
var k = "";
var b = 406644;
var b1 = 3293161072;
var jd = ".";
var $b = "+-a^+6";
var Zb = "+-3^+b+-f";
for (var e = [], f = 0, g = 0; g < a.length; g++) {
var m = a.charCodeAt(g);
128 > m ? e[f++] = m : (2048 > m ? e[f++] = m >> 6 | 192 : (55296 == (m & 64512) && g + 1 < a.length && 56320 == (a.charCodeAt(g + 1) & 64512) ? (m = 65536 + ((m & 1023) << 10) + (a.charCodeAt(++g) & 1023),
e[f++] = m >> 18 | 240,
e[f++] = m >> 12 & 63 | 128) : e[f++] = m >> 12 | 224,
e[f++] = m >> 6 & 63 | 128),
e[f++] = m & 63 | 128)
}
a = b;
for (f = 0; f < e.length; f++) a += e[f],
a = RL(a, $b);
a = RL(a, Zb);
a ^= b1 || 0;
0 > a && (a = (a & 2147483647) + 2147483648);
a %= 1E6;
return a.toString() + jd + (a ^ b)
};
function RL(a, b) {
var t = "a";
var Yb = "+";
for (var c = 0; c < b.length - 2; c += 3) {
var d = b.charAt(c + 2),
d = d >= t ? d.charCodeAt(0) - 87 : Number(d),
d = b.charAt(c + 1) == Yb ? a >>> d: a << d;
a = b.charAt(c) == Yb ? a + d & 4294967295 : a ^ d
}
return a
}
""")
def get_tk(self, text):
return self.ctx.call("TL", text)
def build_url(text, tk, tl='zh-CN'):
"""
需要用转URLEncoder
:param text:
:param tk:
:param tl:
:return:
"""
return 'https://translate.google.cn/translate_a/single?client=webapp&sl=auto&tl=' + tl + '&hl=zh-CN&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&source=btn&ssel=0&tsel=0&kc=0&tk=' \
+ str(tk) + '&q=' + quote(text, encoding='utf-8')
def translate(js, text, tl='zh-CN'):
"""
tl为要翻译的语言
de:德语
ja:日语
sv:瑞典语
nl:荷兰语
ar:阿拉伯语
ko:韩语
pt:葡萄牙语
zh-CN:中文简体
zh-TW:中文繁体
"""
header = {
'authority': 'translate.google.cn',
'method': 'GET',
'path': '',
'scheme': 'https',
'accept': '*/*',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9,ja;q=0.8',
# 'cookie': '_ga=GA1.3.110668007.1547438795; _gid=GA1.3.791931751.1548053917; 1P_JAR=2019-1-23-1; NID=156=biJbQQ3j2gPAJVBfdgBjWHjpC5m9vPqwJ6n6gxTvY8n1eyM8LY5tkYDRsYvacEnWNtMh3ux0-lUJr439QFquSoqEIByw7al6n_yrHqhFNnb5fKyIWMewmqoOJ2fyNaZWrCwl7MA8P_qqPDM5uRIm9SAc5ybSGZijsjalN8YDkxQ',
'cookie':'_ga=GA1.3.110668007.1547438795; _gid=GA1.3.1522575542.1548327032; 1P_JAR=2019-1-24-10; NID=156=ELGmtJHel1YG9Q3RxRI4HTgAc3l1n7Y6PAxGwvecTJDJ2ScgW2p-CXdvh88XFb9dTbYEBkoayWb-2vjJbB-Rhf6auRj-M-2QRUKdZG04lt7ybh8GgffGtepoA4oPN9OO9TeAoWDY0HJHDWCUwCpYzlaQK-gKCh5aVC4HVMeoppI',
# 'cookie': '',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36',
'x-client-data': 'CKi1yQEIhrbJAQijtskBCMG2yQEIqZ3KAQioo8oBCL+nygEI7KfKAQjiqMoBGPmlygE='
}
url = build_url(text, js.get_tk(text), tl)
res = []
try:
r = requests.get(url, headers=header)
result = json.loads(r.text)
r.encoding = "UTF-8"
if debug:
print(r.url)
print(r.headers)
print(r.request.headers)
print(result)
res = result[0]
if res is None:
if result[7] is not None:
# 如果我们文本输错,提示你是不是要找xxx的话,那么重新把xxx正确的翻译之后返回
try:
correct_text = result[7][0].replace('<b><i>', ' ').replace('</i></b>', '')
if debug:
print(correct_text)
correct_url = build_url(correct_text, js.get_tk(correct_text), tl)
correct_response = requests.get(correct_url)
correct_result = json.loads(correct_response.text)
res = correct_result[0]
except Exception as e:
if debug:
print(e)
res = []
except Exception as e:
res = []
if debug:
print(url)
print("翻译" + text + "失败")
print("错误信息:")
print(e)
finally:
return res
def get_translate(word, tl):
js = Py4Js()
translate_result = translate(js, word, tl)
if debug:
print("word== %s, tl== %s" % (word, tl))
print(translate_result)
return translate_result
if __name__ == '__main__':
debug = True
translate_text = '3.Hear voice prompt \"start configuration mode\". click \"reset successfully\" button\n'
results = get_translate(translate_text, 'cs')
translate_result = ""
if "." in translate_text or "?" in translate_text:
for result in results:
translate_result += result[0]
else:
result_translate = results[0]
if debug:
print("translate_result:" + translate_result)
其中: tl 是要进行翻译的其它国家语言的缩写
遇到的问题
1.由于需要翻译上千条字段,于是开启多线程翻译,并且每次请求间隔很短,导致很多请求超时
想到的解决方式是:每次请求翻译尽量多的字段
2.在翻译多个字段的时候,返回的子列表比要翻译的字段多,如:
'3.Hear voice prompt \"start configuration mode\". click \"reset successfully\" button\n'
该字符串中在APP中是一个字段,但是包含两个句子,因为中间包含英文句号’.’,其返回结果
[
['3. Hlasová výzva "start konfigurační režim". ', '3.Hear voice prompt "start configuration mode".', None, None, 3],
['klikněte na tlačítko "obnovit úspěšně"', 'click "reset successfully" button', None, None, 3]
]
备注:最内层的每个列表(一个列表表示一句)就是翻译结果,列表的第1项为翻译结果,第2项为对应要翻译的内容。
因此,遇到有多个句子的字段需要单独翻译
备注:英文句号“.”,问号“?”,换行符“\n”,都会导致返回结果,因此猜测,其它分割语句的符号也是,但是目前脚本没有做其它分割语句的处理。
3.翻译结果符号问题
3.1 莫名多出空格,如:格式化字符串 %d会在中间多出空格:% d,/前后会多出空格等
3.2 要在Android 资源文件中使用,需要注意翻译结果是否出现单引号,出现单引号需要加斜杠’'处理,如果需要显示双引号,也需要加斜杠处理。
附脚本
脚本
该脚本翻译内容从Excel获取,然后将结果放到另一个Excel中。