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

根据 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图标(上面GIF中最后那个图标),然后通知栏弹出翻译:

然而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,全系统都生效,唯独在Translate Tab中不生效。

后来我考虑使用Alfred做一个谷歌翻译workflow,然而立马就遇到了新的问题:句子太长时,在Alfred下拉列表中显示不下;若切割为多行显示,又实在难看且显得格格不入。直接丑拒!

那么只好决定转入popclip插件开发,其实popclip官方API提供的show-result形式,也是很挫的。只能在屏幕中像下面一样显示一长条,不支持换行,太长了就自动截断了,也是让人很醉:

最后好不容易Google到cocoaDialog这种右上角弹出Bubble或者屏幕中央弹出Msgbox的方式,才完美解决多行显示问题。

最后抛弃了 cocoaDialog,因为弹出的MsgBox 30秒后自动消失,可能翻译结果还看不完。最后采取的方式是使用自带的osascript的dialog搞定。这里dialog要显示自定义图片还是很麻烦的,找遍全网搞不定,硬是被自己试出来。。。

3. 调用谷歌翻译

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

上图中的Request URL中有一个tk值,这个值是根据输入的文字调用JavaScript计算的,计算该值的脚本能抓包出来,然而我又不懂JS,这就很尴尬了。网上搜索了一大圈,确实有一位大神把JS脚本计算tk的算法分析出来了,好多博客都声称用这个很好使,然而我亲自试了一下,算出来的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上去,就可以得到结果。不需要科学上网,速度也是超级快。然而谷歌计费方式是每1M个characters收费20美金,我在写代码过程中就随便小测了一下,居然用了3K个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上找到了py-googletrans这个搞定了tk值破解的库。好了,既然有现成的轮子了,我就直接用了,破解tk值的源码暂时也懒得读了,先把软件做出来。

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: 图标文件。这么好的功能当然要有个卡哇伊的图标啦。我本人PS玩的不溜,多亏我两个同学帮我修改,才有了现在这么可爱的图标~~

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

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

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

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

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

1
/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中是这么设定的:

1
2
<key>Before</key>
<string>copy</string>

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

1
2
<key>Requirements</key>
<string>copy</string>

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

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

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

5. 代码与下载

虽然代码很low,我还是开源到github了,一是方便其他写popclip插件的人参考,二是顺便骗个star啦😄

==Github Repo==
==下载地址==

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×