前言
书到用时方恨少,只能临时抱佛脚。英文pdf看不懂,压根看不懂。正好有百度翻译API和腾讯翻译API,就利用两个API自己写一个简单的翻译工具,充分利用资源,用的也放心。
前期准备
关键肯定是两大厂的翻译API,咱们只是做一个简单的应用,所以还没有API的同学可以申请一下。百度翻译API每个月有100万字符的免费额度,腾讯翻译API每个月有500万字符的免费额度,均指的是文本翻译。
百度翻译开放平台
腾讯云API
简单申请一下,获得两家或一家的id和key即可。
使用Python调用API
调用百度API:
利用百度翻译官方提供的调用demo,改写了一个包装类(Baidu_Text_transAPI.py),方便我们后续的调用。
包装类:
import requests
import random
from hashlib import md5
def make_md5(s, encoding='utf-8'):
return md5(s.encode(encoding)).hexdigest()
class BaiduAPI:
endpoint = 'http://api.fanyi.baidu.com'
path = '/api/trans/vip/translate'
url = endpoint + path
def __init__(self):
self._appid = None
self._appkey = None
@property
def appid(self):
return self._appid
@appid.setter
def appid(self, app_id):
self._appid = app_id
@property
def appkey(self):
return self._appkey
@appkey.setter
def appkey(self, app_key):
self._appkey = app_key
def translate(self, text, from_lang='auto', to_lang='zh'):
salt = random.randint(32768, 65536)
sign = make_md5(self.appid + text + str(salt) + self.appkey)
# Build request
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
payload = {'appid': self.appid, 'q': text, 'from': from_lang, 'to': to_lang, 'salt': salt, 'sign': sign}
# Send request
r = requests.post(self.url, params=payload, headers=headers)
result = r.json()
# Show response
# print(json.dumps(result, indent=4, ensure_ascii=False))
return result["trans_result"][0]["dst"]
调用示例:
from Baidu_Text_transAPI import BaiduAPI
baidu_api = BaiduAPI()
baidu_api.appid = "xxxxxxxxx"
baidu_api.appkey = "xxxxxxxxx"
text = "hello"
print(baidu_api.translate(text)) # 剩余两个参数可以使用默认值,也可以指定
调用腾讯翻译API:
腾讯翻译官方提供了一个SDK,方便我们更加方便的调用,所以只需要简单的封装一下即可(Tencent_Text_transAPI.py)。
封装类:
from tencentcloud.common import credential
from tencentcloud.tmt.v20180321 import tmt_client, models
class TencentAPI:
def __init__(self):
self._cred = None
self._client = None
self._secret_id = None
self._secret_key = None
@property
def secret_id(self):
return self._secret_id
@secret_id.setter
def secret_id(self, s_id):
self._secret_id = s_id
@property
def secret_key(self):
return self._secret_key
@secret_key.setter
def secret_key(self, s_key):
self._secret_key = s_key
def create_client(self):
# 设置API密钥和地域
self._cred = credential.Credential(self.secret_id, self.secret_key)
self._client = tmt_client.TmtClient(self._cred, "ap-guangzhou")
def translate(self, text: str, from_lang='auto', to_lang='zh'):
request = models.TextTranslateRequest()
request.SourceText = text
request.Source = from_lang
request.Target = to_lang
request.ProjectId = 0
response = self._client.TextTranslate(request)
return response.TargetText
调用示例:
from Tencent_Text_transAPI import TencentAPI
tencent_api = TencentAPI()
tencent_api.secret_id = "xxxxxxxxx"
tencent_api.secret_key = "xxxxxxxxx"
text = "hello"
print(tencent_api.translate(text)) # 剩余两个参数可以使用默认值,也可以指定
使用PyQt构建一个简单的页面
翻译的核心关键——调用API,已经熟悉了这个流程,那么接下来就是构建一个简单的页面(demo_config_json.py),方便使用。
界面完整代码:
import json
import sys
import time
import pyperclip
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QWidget, QComboBox, QLabel, QTextEdit, QPushButton, QVBoxLayout, \
QHBoxLayout
from Baidu_Text_transAPI import BaiduAPI
from Tencent_Text_transAPI import TencentAPI
class Worker(QThread):
prev_text = pyqtSignal(str)
pre_value = pyperclip.paste() # 初始化
def run(self):
while True:
# 读取剪贴板内容
curr_text = pyperclip.paste()
# print(self.pre_value)
if curr_text != self.pre_value:
# print([curr_text])
self.prev_text.emit(curr_text)
# 每1秒检查一次剪贴板内容
time.sleep(1)
def read_json_file(file_path):
with open(file_path, 'r') as f:
data = json.load(f)
return data
class Translator(QWidget):
def __init__(self):
super().__init__()
self.th = None
self.translateButton = None
self.outputTextEdit = None
self.outputLabel = None
self.inputTextEdit = None
self.inputLabel = None
self.translatorComboBox = None
self.translatorLabel = None
self.baidu_api = None
self.tencent_api = None
self.tmp = None
self.config = read_json_file('config.json')
self.init_ui()
def init_ui(self):
self.setWindowTitle('翻译工具')
self.setWindowIcon(QIcon('icon.png'))
# 上方选择框
self.translatorLabel = QLabel('翻译API:')
self.translatorComboBox = QComboBox()
# 百度翻译API设置
self.translatorComboBox.addItem('百度翻译')
self.baidu_api = BaiduAPI()
self.baidu_api.appid = self.config['BaiduAPI']['id']
self.baidu_api.appkey = self.config['BaiduAPI']['key']
# 腾讯翻译API设置
self.translatorComboBox.addItem('腾讯翻译')
self.tencent_api = TencentAPI()
self.tencent_api.secret_id = self.config['TencentAPI']['id']
self.tencent_api.secret_key = self.config['TencentAPI']['key']
self.tencent_api.create_client()
translator_layout = QHBoxLayout()
translator_layout.addWidget(self.translatorLabel)
translator_layout.addWidget(self.translatorComboBox)
# 中部输入输出框
self.inputLabel = QLabel('输入文本:')
self.inputTextEdit = QTextEdit()
self.outputLabel = QLabel('翻译结果:')
self.outputTextEdit = QTextEdit()
input_output_layout = QHBoxLayout()
input_output_layout_left = QVBoxLayout()
input_output_layout_left.addWidget(self.inputLabel)
input_output_layout_left.addWidget(self.inputTextEdit)
input_output_layout_right = QVBoxLayout()
input_output_layout_right.addWidget(self.outputLabel)
input_output_layout_right.addWidget(self.outputTextEdit)
input_output_layout.addLayout(input_output_layout_left)
input_output_layout.addLayout(input_output_layout_right)
# 下方翻译按钮
self.translateButton = QPushButton('翻译')
translate_layout = QHBoxLayout()
translate_layout.addStretch(1)
translate_layout.addWidget(self.translateButton)
translate_layout.addStretch(1)
# 整体布局
main_layout = QVBoxLayout()
main_layout.addLayout(translator_layout)
main_layout.addLayout(input_output_layout)
main_layout.addLayout(translate_layout)
self.setLayout(main_layout)
# 信号槽连接
self.translateButton.clicked.connect(self.translate_text)
# 设置窗口属性
self.setWindowFlags(Qt.WindowStaysOnTopHint) # 窗口总在最高层
self.setGeometry(300, 300, 800, 450) # 设置窗口大小和位置
self.th = Worker()
# self.th.update_date.connect(self.show_date)
self.th.prev_text.connect(self.handle_signal)
self.th.start()
self.show()
def handle_signal(self, value):
self.th.pre_value = value
self.tmp = " ".join(value.split("\n"))
self.tmp = self.tmp.replace('\r', "", self.tmp.count('\r'))
self.inputTextEdit.setText(" ".join(self.tmp.split("\r")))
# print([" ".join(self.tmp.split("\r"))])
def translate_text(self):
text = self.inputTextEdit.toPlainText()
# 根据选择框调用不同的API进行翻译
if self.translatorComboBox.currentText() == '百度翻译':
# 调用百度翻译API进行翻译
# print("百度")
self.outputTextEdit.setText(
self.baidu_api.translate(text, from_lang=self.config['from_lang'], to_lang=self.config['to_lang']))
elif self.translatorComboBox.currentText() == '腾讯翻译':
# 调用腾讯翻译API进行翻译
self.outputTextEdit.setText(
self.tencent_api.translate(text, from_lang=self.config['from_lang'], to_lang=self.config['to_lang']))
# print("腾讯")
if __name__ == '__main__':
app = QApplication(sys.argv)
translator = Translator()
sys.exit(app.exec_())
使用pyperclip监控剪切板:
为了在体验上有一定的优化,使用pyperclip库监控剪切板的变化,并自动读取最新的复制内容。
class Worker(QThread):
prev_text = pyqtSignal(str)
pre_value = pyperclip.paste() # 初始化
def run(self):
while True:
# 读取剪贴板内容
curr_text = pyperclip.paste()
# print(self.pre_value)
if curr_text != self.pre_value:
# print([curr_text])
self.prev_text.emit(curr_text)
# 每1秒检查一次剪贴板内容
time.sleep(1)
并且因为存在while True,所以使用QThread,防止阻塞界面。
self.th = Worker()
# self.th.update_date.connect(self.show_date)
self.th.prev_text.connect(self.handle_signal)
self.th.start()
在config.json内填入相关配置:
同级目录下创建config.json,填入相关配置,包括目标语言,API的id和key,才能正常使用。
{
"from_lang": "auto",
"to_lang": "zh",
"BaiduAPI": {
"id": "xxxxxxxxxxxxxxxx",
"key": "xxxxxxxxxxxxxxxx"
},
"TencentAPI": {
"id": "xxxxxxxxxxxxxxxx",
"key": "xxxxxxxxxxxxxxxx"
}
}
使用Pyinstaller打包
如果不想每次都执行python demo_config_json.py来运行,可以自己编写.bat脚本或者使用Pyinstaller进行打包。
详细的打包流程,大家可以去找相关博客,也可以使用如下配置文件:
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
# 所有需要打包的.py文件
file = [
'demo_config_json.py',
'Baidu_Text_transAPI.py',
'Tencent_Text_transAPI.py'
]
a = Analysis(file,
pathex=['D:\\Projects\\Python\\Test'], # 项目绝对路径
binaries=[],
datas=[("icon.png", "."), ("config.json", ".")],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='Baicent', # exe的名称
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False, #console=True表示,打包后的可执行文件双击运行时屏幕会出现一个cmd窗口,不影响原程序运行,如不需要执行窗口,改成False即可
icon='D:\\Projects\\Python\\Test\\favicon.ico') #程序图标的绝对路径
参考博客:python3_将多个.py文件打包成exe程序并添加图标_python打包带图标-CSDN博客
效果及完整项目代码
界面效果:
觉得界面简陋的同学也可以自行构建界面,反正核心就是调API,总体没啥技术难度
完整项目代码:
gitee:项目代码