multi-translate.el 用多个翻译服务翻译当前单词和选区

初衷是为了对比各家对长句的翻译

支持 bing(bing-dict)、google(google-translate) 和 youdao(youdao-dictionary)。

原本想把 DeepL 纳进来,自己写一个 deepl-translate.el 结果发现 deepl 做了限制,不知如何获得 jsonrpc 请求的 id(如果有人知道望告知)。

目前采用的是同步请求,体验稍差。想改成异步的,但只有 bing-dict 支持异步调用。

google-translate 略显复杂,分好几次 url-retrieve-synchronously 才得到翻译结果,估计改异步比较困难。

youdao-dictionary 不知 @xuchunyang 可否提供异步接口?


新增功能:

  • 添加对 sdcv 的支持
  • 允许设置单词用本地词典、句子用在线翻译。
  • 添加 bing 和 youdao 的异步支持。
  • 支持查询条件的再编辑(amend)。#46
  • 允许保留多次查询结果。#47
9 个赞

界面挺好看www Emacs在text ui上还是很有一套。

1 个赞

这个插件很有用。支持作者。

据我了解 jsonrpc 的 ID 随便写,服务器保证返回相同的 ID,客户端不同请求使用不同 ID(比如从 0 递增),这样能区别哪一个返回对应哪一个请求,因为客户端依次异步发送 A B C 三个请求,服务器可能按 A C B 这个顺序返回。

可以,晚上写看看。

1 个赞

google-translate 是应该能够支持异步的,我有时间看看代码,看能不能修改核心函数。

DeepL 的 jsonrpc 请求 ID 是随页面下发的,我审查元素看了一下它几个混淆过的 js,没发现 ID 的存储位置和构造方法。修改 ID 会收到错误:

Too many requests.

我在 github 找了几个第三方 DeepL 客户端都因为这个挂了。

前几天我还看到有人写了一个百度翻译

懒猫大神好像也说过要写个类似的从网页返回翻译的插件,对英语不是很熟练的人很有帮助啊e87da72297dda144859f4dd6a5b7d0a20df4866f

1 个赞

我想的是如果有人能写个整合版的插件就好了,查询单词通过本地词典查询,长句就通过谷歌、必应……就是星际译王早就停止开发了,goldendict在mac终端下使用会出问题

整合应该是能够做到的。sdcv, goldendict, google-translate, baidu, bing, 都已经有现成项目了。加一个单词和长句的判断也容易。这个 multi-translate 插件更进一步应该可以。

1 个赞

google-translate-backend--emacs 含有 url-retrieve-synchronously, 被调用了两次,一次是为了获取tkk参数,第二次是真正的翻译请求。我试了一下,把 url-retrieve-synchronously 改成 url-retrieve 会导致很多其他的函数都需要修改支持异步。太麻烦了。

我之前也是觉得这里改动成本有点高。

完全可以实现单词/长句分别使用本地/远程查询。

我开始写的时候也考虑过这个问题, 当时用空格判断是否为句子。但这个不太准确,有时候一些复合词在本地判断为句子,但是远程返回来是单词详解。

如果不在意这些的不一致(其实也没什么影像),立即就可以把本地的 sdcv 支持起来。

这样的小问题可以放到后面等想到更好的解决办法的时候再弄,先支持起来。嘿嘿嘿

之前的维护者一直没时间,这段时间就我一个人在简单维护 google-translate, 看看吧,如果还需要修改的地方不那么多,我或许会尝试一下。合并也容易,自己就审核了。

想问一下,这种变量要如何传递?我这种本办法用全局变量的,感觉不好。有没有更好的办法?

modified   google-translate-backend.el
@@ -100,18 +100,26 @@ (defun google-translate-backend--log (&rest args)
         (insert message)
         (newline)))))
 
+(defvar google-translate-backend--url nil)
+(defvar google-translate-backend--buffer-content nil)
+
 (defun google-translate-backend--emacs (url)
   "Get URL contents by `url-retrieve-synchronously'."
+  (setq google-translate-backend--url url)
   (insert
    (let ((url-user-agent google-translate-backend-user-agent))
-     (with-current-buffer (url-retrieve-synchronously url)
-       (set-buffer-multibyte t)
-       (google-translate-backend--log url 'emacs)
-       (goto-char (point-min))
-       (re-search-forward "\n\n")
-       (prog1 (buffer-substring (point)
-                                (point-max))
-         (kill-buffer))))))
+     (url-retrieve
+      url
+      (lambda (_status)
+        (with-current-buffer (current-buffer)
+          (set-buffer-multibyte t)
+          (google-translate-backend--log google-translate-backend--url 'emacs)
+          (goto-char (point-min))
+          (re-search-forward "\n\n")
+          (prog1 (setq google-translate-backend--buffer-content
+                       (buffer-substring (point) (point-max)))
+            (kill-buffer)))))
+     google-translate-backend--buffer-content)))
 
 (defun google-translate-backend--process (url key spec)
   "Get URL contents by `call-process'.

异步不能这样返回吧?

如果只请求一次还好处理,就像:

多次请求的话可能要在 callback 里面发起第二次请求,然后再 callback。

是的,我在看 promise.el 这个包,但是没用过promise,看不懂。。。看这个包似乎是模仿JS的promise,我去看看JS的是怎么用的。

加了个 youdao-dictionary-search-async 命令。也可以自己从 Lisp 调用,比如:

(youdao-dictionary--request
 "hello"
 (lambda (_status)
   (message "%s"
            (youdao-dictionary--format-result
             (youdao-dictionary--parse-response)))))

打印如下内容:

hello [həˈləʊ]

* Basic Explains
- int. 喂;哈罗,你好,您好
- n. 表示问候, 惊奇或唤起注意时的用语
- n. (Hello) 人名;(法)埃洛

* Web References
- Hello :: 你好; 您好; 哈啰
- Hello Kitty :: 凯蒂猫; 昵称; 吉蒂猫
- Hello Bebe :: 哈乐哈乐; 乐扣乐扣
1 个赞

赞。我明天看看怎么整合。


添加了 sdcv 的支持。 对于单词(也许被误判为单词),如果 sdcv 没有返回结果,再提交到远程翻译。句子则直接提交给远程翻译。

1 个赞

:japanese_ogre: :japanese_goblin: 神速,感谢