本帖最后由 CrLf 于 2017-5-11 02:23 编辑
因为一直没找到合适的命令行工具,所以自己实现了一个,很适合用来翻译外国命令行工具的自带帮助
(是的,就是用在 Batch-CN 第三方库的搜集整理上)
一年多前写的,用的是百度翻译api,实现了双语对照、全文翻译、参数控制等功能
但因为这个api有限制每月翻译字符数,共用难免会超,所以一直都未公开
现在把源码分享出来,基于 python3,另外需要大家自行注册api,修改【】符号所在位置的 appid 和 secretKey 即可使用
如需使用剪贴板相关功能,还需要 pyperclip 模块支持,请运行 pip3 install pyperclip 自行安装,不安装该模块也不影响其他功能的使用
百度翻译api接入申请地址:http://api.fanyi.baidu.com/api/trans/product/index- #/usr/bin/env python
- # -*- encoding:utf-8 -*-
-
- #by CrLf
-
- import getopt, sys
- import json
- import re
- import http.client
- import hashlib
- import urllib
- import urllib.request
- import urllib.parse
- import random
- import os
- from io import StringIO
-
- try:
- import pyperclip
- except ImportError:
- pyperclip = {}
-
- zhPattern = re.compile(u'[\u4e00-\u9fa5]+')
-
- appid = '20151113000005349' #【测试用的 appid】
- secretKey = 'osubCEzlGjzvw8qdQc41' #【测试用的 secretKey】
-
- jsonPath = jsonPath_base = (os.path.realpath(sys.argv[0]))+'.json'
- #配置文件路径默认为此脚本/程序所在目录
- #有 .json 时,默认使用该文件中的配置
-
- if not ( appid and secretKey ) :
- print("你需要在脚本中设置 appid 和 secretKey", file=sys.stderr)
- print("API接口申请: http://api.fanyi.baidu.com/api/trans/product/index", file=sys.stderr)
- sys.exit(2)
-
- option = {}
- globalVar = {'num':0}
- httpClient = None
- stdinfo = sys.stderr
-
-
- def main():
- if os.path.isfile(jsonPath) :
- getConfig(jsonPath)
-
- try:
- opts,args = getopt.getopt(sys.argv[1:], "hnf:t:DTc", ["help", "from=", "to=", "dict", "text", "num", "debug","web=","clip"])
-
- except Exception as e:
- print("参数错误", file=sys.stderr)
- sys.exit(2)
-
- for opt,arg in opts:
- if opt in ("-h", "--help"):
- usage()
- sys.exit(0)
- elif opt in ("-c","--clip"):
- if not pyperclip :
- print('-c 选项需 pyperclip 模块支持', file=sys.stderr)
- sys.exit(2)
-
- option['clip'] = True
- args = [pyperclip.paste()]
- elif opt in ("-n","--num"):
- option['num'] = True
- elif opt in ("-f", "--form"):
- option['from'] = arg
- if 'to' in option and arg.lower() != 'zh' : option['to']='zh'
- elif opt in ("-t", "--to"):
- option['to'] = arg
- if 'from' in option and arg.lower() != 'zh' : option['from']='zh'
- elif opt in ("-D","--dict"):
- option['dict'] = True
- elif opt in ("-T","--text"):
- option['text'] = True
- elif opt in ("--debug"):
- option['debug'] = True
- elif opt in ("--web"):
- if arg == 'baidu':
- os.system("start http://fanyi.baidu.com/")
- elif arg == 'google':
- os.system("start https://translate.google.cn/")
- elif arg == 'youdao':
- os.system("start http://fanyi.youdao.com/")
- elif arg == 'iciba':
- os.system("start http://fy.iciba.com/")
- elif arg == 'haici':
- os.system("start http://fanyi.dict.cn/")
- else:
- print("--web baidu | google | youdao | iciba | haici")
- sys.exit(0)
- else:
- print("%s ==> %s" %(opt, arg))
-
- if 'debug' in option:
- print("Opts:\r\n%s" % opts, file=stdinfo)
- print("Args:\r\n%s" % args, file=stdinfo)
- print("Option:\r\n%s" % option, file=stdinfo)
-
- fromLang = option['from'] if 'from' in option else 'auto'
- toLang = option['to'] if 'to' in option else 'zh'
-
-
- try:
- if len(args)==0 :
- if sys.stdin.isatty():
- usage()
- else:
- q = re.sub(r'\r?\n','\r\n',sys.stdin.read())
- choiceMode(q, fromLang, toLang)
-
- sys.exit(0)
-
- if len(args)==1 :
- choiceMode(args[0], fromLang, toLang)
- sys.exit(0)
-
-
- if 'dict' in option:
- for arg in args:
-
- if fromLang == 'auto' and zhPattern.search(arg) :
- toLang = 'en'
-
- print('[Dict Mode] %s -> %s\r\n' % (fromLang, toLang), file=stdinfo)
-
- words = re.split(r'\s+',arg)
- for word in words:
- word = word.strip()
- trans_dict(word, fromLang, toLang)
- print('\r\n');
- sys.exit(0)
- else:
- q = '\r\n'.join(args)
-
- if fromLang == 'auto' and zhPattern.search(q) :
- toLang = 'en'
-
- print('[Text Mode] %s -> %s\r\n' % (fromLang, toLang), file=stdinfo)
- trans_text(q, fromLang, toLang)
-
- except Exception as e:
- print(e, file=sys.stderr)
- sys.exit(1)
-
-
-
- def trans_dict(word, fromLang, toLang):
- resp=urllib.request.urlopen(compose_request(word))
- if(resp.status==200):
- handle_result(resp.read().decode('utf-8'))
- else:
- print('Rquest Error: \r\n HTTP Status: %d \r\n Reason: %s \r\n', resp.status, resp.reason)
-
-
- def trans_text(q, fromLang, toLang):
- salt = random.randint(32768, 65536)
-
- sign = appid+q+str(salt)+secretKey
- m1 = hashlib.md5()
- m1.update(bytes(sign, encoding = "utf8") )
- sign = m1.hexdigest()
-
- myurl = '/api/trans/vip/translate?appid='+appid+'&q='+urllib.parse.quote(q)+'&from='+fromLang+'&to='+toLang+'&salt='+str(salt)+'&sign='+sign
-
- try:
- httpClient = http.client.HTTPConnection('api.fanyi.baidu.com')
- httpClient.request('GET', myurl)
-
- #response是HTTPResponse对象
- response = httpClient.getresponse()
- ret = response.read()
- retstr = str(ret,'utf-8')
- retobj= json.loads(retstr)
-
- if 'num' in option:
- str_template='[%05d] -----------------------------------------\r\n%s'
- else:
- str_template='%0.s-------------------------------------------------\r\n%s'
-
- if 'error_code' in retobj and retobj['error_code'] != '52000' :
- print(" 错误码: " + retobj['error_code'], file=sys.stderr)
- print(" 说明: " + retobj['error_msg'], file=sys.stderr)
- sys.exit(retobj['error_code'])
- else :
- for trans_result in retobj['trans_result']:
- globalVar['num']=globalVar['num']+1
- print(str_template % (globalVar['num'], trans_result['src']), file=stdinfo)
- print(trans_result['dst'])
-
- except Exception as e:
- print(e, file=sys.stderr)
- finally:
- if httpClient:
- httpClient.close()
-
-
- def getConfig(configPath):
- config_default = {}
- config = config_default
-
- if os.path.isfile(configPath) :
- try :
- fp = open(configPath,"r")
- config = json.load(fp)
- fp.close()
- except Exception as e:
- config = config_default
-
- global appid, secretKey
-
- if 'appid' in config and 'secretKey' in config and config['appid'] and config['secretKey'] :
- appid = config['appid']
- secretKey = config['secretKey']
-
-
- def usage():
- argshelp = '''
- -f lang --from lang
- 指定翻译前的语言为 lang,可选项详见百度翻译api文档
-
- -t lang --to lang
- 指定翻译后的语言为 lang,可选项详见百度翻译api文档
-
- -T --text
- 以文本形式翻译
-
- -D --dict
- 以字典形式翻译
-
- -n --num
- 以数字形式翻译
-
- -c --clip
- 从剪贴板获取要翻译的内容
-
- --web name
- 用浏览器打开翻译页面(不支持长文本),name 为所用的翻译引擎
- 可选项为 baidu/google/youdao/iciba/haici
-
- --debug
- 调试模式
-
- -h --help
- 显示简单的帮助信息'''
-
- print("Usage:%s [-f lang] [-t lang] [--web name] [-c] [-n|-T|-D] args...." % os.path.basename(sys.argv[0]))
- print(argshelp)
-
- if os.path.isfile(jsonPath) :
- print("\r\n 配置文件: \"%s\"" % jsonPath)
- print(" 该文件用于设置要使用的 appid 和 secretKey")
- print(" 接口申请地址:\"http://api.fanyi.baidu.com/api/trans/product/index\"")
- else :
- print("\r\n 当前无配置文件,默认使用测试 ID")
- print(" 接口申请地址:\"http://api.fanyi.baidu.com/api/trans/product/index\"")
- print("\r\n 如需自定义 appid 和 secretKey,请以 JSON 格式保存到配置文件:")
- print(" \"%s\"" % jsonPath)
- print("\r\n 配置文件的格式为:")
- print(" {'appid': '你的 APPID', 'secretKey': '你的秘钥'}")
-
-
- class Result:
- def __init__(self, src, dest, meanings=None):
- self.src=src
- self.dest=dest
- self.meanings=meanings
-
- def parse_from_json(json_data):
- trans_data=json_data['trans_result']['data'][0]
- try:
- means=None
- if 'simple_means' in json_data['dict_result']:
- dict_data=json_data['dict_result']['simple_means']['symbols'][0]['parts']
- means=list()
- for item in dict_data:
- tmp=item['means']
- if isinstance(tmp[0],dict):
- for t_item in tmp:
- means.append(t_item['word_mean'])
- else:
- means.append(tmp)
- except KeyError:
- means=None
-
- return Result(trans_data['src'],trans_data['dst'],means)
-
- def show(self,file=sys.stdout):
- if 'num' in option:
- str_template='<<<translate\r\n %05d:\t %s ---> %s\r\n\r\n<<<meaning'
- else:
- str_template='<<<translate\r\n %0.s%s ---> %s\r\n\r\n<<<meaning'
-
- globalVar['num']=globalVar['num']+1
-
- print(str_template % (globalVar['num'], self.src, self.dest), file=stdinfo)
- [print(" %s" % meaning) for meaning in self.meanings]
-
-
- def handle_result(content):
- json_data=json.loads(content)
- Result.parse_from_json(json_data).show()
-
- def compose_request(word):
- TRANS_URL='http://fanyi.baidu.com/v2transapi'
- ORIGIN_HOST='fanyi.baidu.com'
-
- r"""
- compose urllib.request.Request object accordingly
-
- """
- body=StringIO()
- body.write('from=zh&to=en' if zhPattern.search(word) else 'from=en&to=zh')
- body.write('&')
- body.write(urllib.parse.urlencode({'query': word }, encoding='utf-8'))
- body.write('&transtype=trans&simple_means_flag=3')
- body=body.getvalue()
-
- headers={'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
- 'X-Requested-With':'XMLHttpRequest'
- }
-
- return urllib.request.Request(TRANS_URL, body.encode(encoding='utf-8'), headers=headers, origin_req_host=ORIGIN_HOST, method='POST')
-
-
-
- def choiceMode(q, fromLang, toLang):
- if fromLang == 'auto' and zhPattern.search(q) :
- toLang = 'en'
-
- word = re.sub(r'\r|\r\n','',q).strip()
- if re.search(r'\s',word):
-
- print('[Text Mode] %s -> %s\r\n' % (fromLang, toLang), file=stdinfo)
- trans_text(q, fromLang, toLang)
- else:
- print('[Dict Mode] %s -> %s\r\n' % (fromLang, toLang), file=stdinfo)
- trans_dict(word, fromLang, toLang)
-
- main()
复制代码
|