重复造轮子之Emacs翻译插件maple-translate


我之前一直都在使用 youdao-dictionary 这个插件,虽然没有配置过秘钥,这时会有使用次数的限制(反正是每天1000次还是多少来着,有些忘了),但是我平时使用次数不多,所以也不会达到使用限制,不管是单词翻译还是长句翻译都很不错。但最近几个月 youdao-dictionary 如果不配置私钥,处于一个完全不可用的状态。

我曾寻找过它的替代品,并且使用过一段时间的 fanyi.el,不可否认,这同样是一个非常不错的插件,不管是UI还是功能,但是,可能是因为 fanyi.el 使用异步请求的原因,偶尔会出现一些意想不到的报错,更重要的是它不支持长句翻译和离线翻译。

考虑再三,还是决定自己造一个轮子,主要功能就按照我之前使用 youdao-dictionary 的习惯:

  1. 翻译光标下的单词,以及选中的单词或句子

  2. 翻译的内容输出到 echoarea 或者新的 buffer,方便复制

  3. 增加一个离线翻译的功能,并且可以不依赖外部工具

基于上述,所以有了这个新的轮子 maple-translate

如何使用?

可以使用 quelpa 安装

(use-package maple-translate
  :quelpa (:fetcher github :repo "honmaple/emacs-maple-translate")
  :commands (maple-translate maple-translate+))

或者手动下载仓库

git clone https://github.com/honmaple/emacs-maple-translate ~/.emacs.d/site-lisp/maple-translate

然后进行配置

(use-package maple-translate
  :ensure nil
  :commands (maple-translate maple-translate+))

长句翻译

目前长句翻译仅支持 youdao, 目前支持 youdaogoogle 两种翻译引擎,可以修改设置

(setq maple-translate-engine 'youdao)
;; 或者
(setq maple-translate-engine 'google)

谷歌翻译

国内无法直接使用,但是可以单独为谷歌翻译设置代理

(setq maple-translate-google-url "https://translate.googleapis.com/translate_a/single")
(setq maple-translate-google-proxies
      '(("http" . "127.0.0.1:1086")
        ("https" . "127.0.0.1:1086")))

离线翻译

我个人平时在使用 Emacs 时不太习惯依赖外部的工具,比如我之前就写过一个markdown,org-mode实时预览插件 maple-preview,它区别于其它插件,并不会依赖外部的工具,比如 Pandoc,甚至不会生出任何文件到我的本地环境

同样的,我也不希望使用离线翻译时还要依赖外部诸如 sdcv,goldendict 等工具,我想要直接使用 Elisp 来对词典进行解析。所幸前人栽树,后人乘凉,已经有了一个纯 Elisp 实现的解析器 https://www.emacswiki.org/emacs/stardict.el

我所需要做的,就是下载需要的词典到本地(这个步骤是必须的,即使我不喜欢),然后设置

;; 离线词典所在的目录
(setq maple-translate-sdcv-dir "~/.stardict/dicts")
;; 所使用的词典 -> (词典名词 . 词典具体目录)
(setq maple-translate-sdcv-dicts
      '(("lazyworm-ec" . "stardict-lazyworm-ec-2.4.2")
        ("lazyworm-ce" . "stardict-lazyworm-ce-2.4.2")))

最后修改翻译引擎

(setq maple-translate-engine 'sdcv)

注意:第一次使用离线翻译需要等待词典初始化,这会需要耗费一段时间,后面就快了

多引擎翻译

maple-translate 同样支持多引擎,需要修改设置为一个列表

(setq maple-translate-engine '(youdao dictcn sdcv))

翻译原理

目前支持的几个引擎: youdao(有道)dictcn(海词)iciba(金山词霸)bing(必应)google(谷歌)sdcv(离线)。除 sdcv 外,其它几个都依赖于网络,maple-translate 可以看作是一个爬虫,通过爬取翻译页面,然后使用Emacs内置的 dom 对HTML进行解析,最后获取到想要的内容(谷歌使用API获取)。基于此,我还写了一个超简单的 类xpath 解析器

(defun maple-translate-dom-by-key(dom key)
  (let (func num)
    (when (string-match "\\[\\([0-9]+\\)\\]" key)
      (setq num (match-string 1 key))
      (setq key (substring key 0 (- (length key) (length num) 2))))
    (cond ((string-prefix-p "." key)
           (setq key (substring key 1) func 'dom-by-class))
          ((string-prefix-p "#" key)
           (setq key (substring key 1) func 'dom-by-id))
          ((string-prefix-p "*" key)
           (setq func (lambda(p _) (dom-children p))))
          (t (setq key (intern key) func 'dom-by-tag)))
    (if (null num)
        (funcall func dom key)
      (nth (string-to-number num) (funcall func dom key)))))

(defun maple-translate-dom-find(dom xpath)
  (cl-loop for key in (string-split (string-trim xpath) "/")
           if (consp dom)
           do (setq dom (maple-translate-dom-by-key dom key))
           else return dom)
  dom)

这样,我就能通过一些简单的语法来定位想要的内容,比如在有道里面使用

(maple-translate-dom-find dom ".simple dict-module/.trans-container/.word-exp")

获取到 class 名称为 simple dict-module 下的 class 名称为 trans-container 下的 class 名称为 word-exp 的所有元素, 也就是基本释义

作者: honmaple
链接: https://honmaple.me/articles/2023/11/zhong-fu-zao-lun-zi-zhi-emacsfan-yi-cha-jian-maple-translate.html
版权: CC BY-NC-SA 4.0 知识共享署名-非商业性使用-相同方式共享4.0国际许可协议
wechat
alipay

加载评论