CaptainChen

提高效率第二弹之自己开发谷歌翻译 popclip 插件

2017-08-04 2132 words (about 9 min read) Views
popclip mac

根据 Google Translate 开发的 Popclip 插件,响应速度是我用过的翻译插件里最快的,可以选择翻译源(.com .cn),有多种国外语言可以翻译,点击按钮后在屏幕右上方显示译文。 ——MAC玩儿法报道

继上次自己开发 Alfred Workflow 后,这次我又盯上了 popclip。

事因是自己一直渴望有一种完美的谷歌翻译使用方式,目的是用鼠标选中待选定句子,然后弹出谷歌翻译内容。无奈一直没人做,只好自己动手实现。

1. 使用效果展示

展示一下最终的自制 popclip 谷歌翻译插件使用效果:

首先设置里面有几个选项可以设置:

  • Google Translate Site: 可选 translate.google.cntranslate.google.com 作为翻译服务器,前者给墙内的朋友使用,后者则是给墙外的使用。
  • Destination LanguageSource Language: 目标外语 (destination language) 和母语 (source language)。程序将对划中的语言进行检测,若检测的语言非母语,则翻译为母语;若检测的语言为母语,则翻译为目标外语。

使用效果GIF:

英译中:

中译英:

确实很方便~

2. 为什么选择popclip

其实 Mac 上的翻译方案很多,在本插件出来之前,个人觉得最好用的当属 Translate Tab了,鼠标选中待翻译字段,点击其 popclip 图标,然后通知栏弹出翻译:

然而 Translate Tab 也是有缺点的:

  • 收费 (其实就是简单封装了一下 google translate 网页版)
  • 通过 popclip 选择文字这种调用方式,第一次打开很慢,经常转了无数圈,结果才翻译出来
  • 服务器只能走 translate.google.com,不翻墙无法使用。我给开发者发邮件,开发者回复道 Theoretically google must redirect app to the domain according to geolocation. I will check this moment,然后我再回复就没有后文了。。。如果用 Surge 的 URL Rewrite 功能设置translate.google.com 跳转到 translate.google.cn,需要开启 MitM,比较浪费性能。

因为我非常喜欢 popclip 这种形式的小软件,因此决定转入 popclip 插件开发。popclip 官方 API 提供了一种 show-result 形式的 GUI 显示文本,然而效果实在太挫了:只能在屏幕中像下面一样显示一长条,不支持换行,太长了就自动截断了,也是让人很醉:

一开始我使用的方案是采用第三方 cocoaDialog 做结果显示 GUI,做了右上角弹出 Bubble 或者屏幕中央弹出 Msgbox 的方式。使用几个版本后还是抛弃了 cocoaDialog,因为弹出的 MsgBox 30 秒后自动消失,往往翻译结果还没看完就消失了。研究 AppleScript 时发现自带的 osascript 提供了 dialog 的组件显示文本,非常好用。就是 dialog 要显示自定义图标文件全网缺少相关文档,找的方案基本不可行,硬是被自己试出来。。。

3. 调用谷歌翻译

如何调用谷歌翻译,我第一反应当然是爬虫,然而用 Chrome 到 translate.google.cn 抓包一看:

上图中的 Request URL 中有一个 tk 值,这个值是根据输入的文字调用 JavaScript 计算的,代码经过了非常复杂的混淆包装,几万行代码就为了混淆一个 tk 值,太可怕了。。。

那就试试谷歌官方的收费 API 吧。于是我去开通了 Google Cloud,绑定了信用卡,然后发现新用户居然赠送 300 美金优惠券(限一年用完)!激动!另外,谷歌翻译官方 API 使用方式也很简单,用自己的 API KEY 组合成这样一个 URL: https://translation.googleapis.com/language/translate/v2?key=' + API_KEY,然后把 {'target':target_lang, 'q': query} post 上去,就可以得到结果。不需要科学上网,速度也是超级快。然而谷歌计费方式是每 1 M 个 characters 收费 20 美金,我在写代码过程中就随便小测了一下,居然用了 3 K 个 characters,所以这个 characters 咋算的,字母数么。。。要是分享出去用的人多了,用不了几天 300 美金就花光了。

然后我又去搜索,有没有免费的谷歌翻译 API,果然在知乎找到了: 请问如何调用谷歌翻译API?。用 http://translate.google.cn/translate_a/single?client=gtx&sl=en&tl=zh-CN&dt=t&q=query 的形式去查询就可以免费调用谷歌翻译。难道是漏网之鱼?不一会我就发现,woc,同一 IP 下调用此 API 多次就直接被 Google 给 ban 了!心机你 Google!

好在 GitHub 大神多,一通搜索,有人逆向了谷歌的 tk,还封装好了😅: py-googletrans。好了,既然有现成的轮子了,我就直接用了~

4. popclip 插件的编写

虽说第一次接触 popclip 插件的编写,小试一下,发现还是蛮简单的。写起来比 Alfred Workflow 简单不少,然而没法调试,略蛋疼。全程主要参考了少数派 让剪切板在 OS X 上飞起来:PopClip 插件编写教程 和 popclip 官方 github documentation

一个 popclip 插件,主要包括三部分:

  • Config.plist: 属性列表文件。其实类似于 Python 的字典,主要是用 key-value 的形式,设置变量。这里面最重要的两个主 key 就是 Actions 和 Options。Actions 决定了对鼠标选中的文字如何去传参和处理,如何去调用 Shell Script 或 Apple Script 来执行你想要的功能,以及如何输出。Options 则是处理设定框中的选项,是勾选框还是多选栏。具体的细节官方文档一看就懂。下图是本插件 Config.plist 的一部分截图:
  • Icon.png: 图标文件。这么好的功能当然要有个卡哇伊的图标啦。

  • Script: 脚本文件。执行目标功能。popclip 默认只支持 Shell Script 和 Apple Script。要用其他语言,也只能通过这两种 Script 来调用。

其实,最终实现谷歌翻译的 Python 脚本很简单,一共才 60 余行代码,和上次那个优越加速 Alfred Workflow 几百行相比简单太多,逻辑上也更简单。

首先我的 translate.py 通过 argparse 接受以下几个参数:

--site site_arg --srclang srclang_arg --destlang destlang_arg

然后通过 go.sh 来执行此 py 文件:

/usr/bin/python translate.py --site $POPCLIP_OPTION_SITE  --destlang $POPCLIP_OPTION_DESTLANG --srclang $POPCLIP_OPTION_SRCLANG $POPCLIP_URLENCODED_TEXT &

上面的 $POPCLIP_XXX 是 popclip 传递来的变量。以 --site 为例,在上面提到的 Config.plist文件的 Options 中,我设置了一个标题为 Google Translate Site 的多选栏,设定一个变量,其 key 设定为 sitevalue 设定为 translate.google.cntranslate.google.com (都是字符串),靠用户来选择使用哪个 value。然后选定的 value 以名为 $POPCLIP_OPTION_SITE 的变量存在于整个插件运行的过程中,可随时调用。同样的,$POPCLIP_OPTION_LANG 代表 Target Foreign Language 那一栏的变量的 value,这里的详细设置参见我的 Config.plist

然后有必要交代一下最后那个 $POPCLIP_URLENCODED_TEXT。如何去把鼠标选中的文字转换成一个变量,传递给脚本呢。

起初,我是在 Config.plist 中的 Actions 中是这么设定的:

<key>Before</key>
<string>copy</string>

然后用的变量名为 $POPCLIP_TEXT。Before 指的是在 popclip 执行主要 action 之前要干的事,这里我设定为 copy。这样,只要鼠标选中一段文字,将自动执行 Command + C,同时以 string 的形式保存为一个名叫 $POPCLIP_TEXT 的变量。这样的弊端也是显而易见的,每次鼠标划词都复制文字到剪切板,会扰乱剪切板。因此我改用:

<key>Requirements</key>
<string>copy</string>

根据官方说明,这种情况下的 copy 就不会复制文字到剪切板了。另外之所以用 $POPCLIP_URLENCODED_TEXT,是因为坑爹的 $POPCLIP_TEXT,在遇到空格时就会停止复制,比如鼠标选中了 a b c,其实变量只存了 a。所以只好用 url-encoded 的形式,最后再用 urllib 库的 unquote 转换为正常的 String。

最后,整体流程框图如下:

整体下来思路还是挺清晰的。然后只需要把以上所有文件放在一个文件夹中,强行加上一个 .popclipext 就大功告成啦~

5. 代码与下载

虽然代码很简单,开源到 GitHub 了,方便一下其他人参考编写 popclip 吧~

Github Repo

如果你这里看到有广告,不妨点击一下,就是对本站最大的支持~



本文由 CaptainChen 创作
该文章采用 知识共享署名-非商业性使用 4.0 国际许可协议进行许可。转载请注明出处!
CopyRight © 2017 - 2020
本站已稳定运行 天 总访问量