为maple-translate增加更友好的sdcv离线翻译


之前我写的Emacs翻译插件 maple-translate 有一个 sdcv 离线翻译的功能,它使用了 Elisp 解析 StarDict 的字典文件,所以不需要安装其它任何依赖。但是也是因为此原因,首次使用离线翻译需要等待字典文件加载到内存,这不是很友好,此次我将添加 sdcv 二进制文件的支持,使离线翻译能够更加快捷方便

首先是安装 sdcv 二进制文件

 1└──╼ brew install sdcv
 2└──╼ sdcv --help
 3用法:
 4  sdcv [选项…]  words
 5
 6帮助选项:
 7  -h, --help                     显示帮助选项
 8
 9应用程序选项:
10  -v, --version                  display version information and exit
11  -l, --list-dicts               display list of available dictionaries and exit
12  -u, --use-dict=bookname        for search use only dictionary with this bookname
13  -n, --non-interactive          for use in scripts
14  -j, --json-output              print the result formatted as JSON
15  --json                         print the result formatted as JSON
16  -e, --exact-search             do not fuzzy-search for similar words, only return exact matches
17  -0, --utf8-output              output must be in utf8
18  -1, --utf8-input               input of sdcv in utf8
19  -2, --data-dir=path/to/dir     use this directory as path to stardict data directory
20  -x, --only-data-dir            only use the dictionaries in data-dir, do not search in user and system directories
21  -c, --color                    colorize the output

然后定义二进制文件的路径,如果 sdcv 未安装,则返回为 nil

1(defvar maple-translate-sdcv-program (executable-find "sdcv"))

接着修改之前写好的 maple-translate-sdcv 函数,通过判断 maple-translate-sdcv-program 是否为空采取不同的翻译操作

 1(defun maple-translate-sdcv(word &optional callback)
 2  "Search WORD with sdcv, use async request if CALLBACK non-nil."
 3  (if maple-translate-sdcv-program
 4      (maple-translate-execute maple-translate-sdcv-program
 5        :args (append '("-n" "-x" "-j" "-0" "-1" "-2")
 6                      (cl-loop for dict in maple-translate-sdcv-dicts
 7                               collect (expand-file-name (cdr dict) maple-translate-sdcv-dir))
 8                      (list word))
 9        :format (maple-translate-sdcv-format)
10        :callback callback)
11    ;; ...
12    ;; 使用ELisp解析并翻译
13    ))

需要说明的是,由于该函数接收一个 callback 的变量,用于处理异步翻译,如果是同步翻译,可以直接使用 call-process 获取结果

1(with-temp-buffer
2  (apply 'call-process "sdcv" nil t nil '("-n" "-x" "-j" "-0" "-1" "-2" "/Users/xxx/.emacs.d/stardict/stardict-lazyworm-ec-2.4.2" "word"))
3  (buffer-string))

但如果是异步翻译,则需要使用 start-process ,再通过监听进程状态在进程结束后再获取翻译结果

1(let ((name (format "maple-translate-process %s" ,program)))
2  (set-process-sentinel
3   (apply 'start-process name (format "*%s*" name) ,program ,args)
4   (lambda(process _)
5     (unless (process-live-p process)
6       (with-current-buffer (process-buffer process)
7         (prog1 (funcall ,callback ,format)
8           (kill-buffer (current-buffer))))))))

这里的 buffer 名称也可以通过 (generate-new-buffer " *temp*" t) 生成一个临时 buffer

最后就是翻译结果的展示,由于输出的是多行 json,比如:

1[]
2[{"dict": "懒虫简明英汉词典","word":"word","definition":"\n[wә:d]\nn.\n字, 词, 话, 消息, 诺言, 命令\nvt.\n为...措辞"}]

所以我在解析翻译结果时取了个巧,没有使用 (buffer-string) 而是直接在 buffer 里操作,每次都跳到开始位置,再依次向下移动 n 行,这个 n 即是字典的数量,最后使用 (thing-at-point 'line t) 获取当前行的数据

 1(defun maple-translate-sdcv-format()
 2  "Format result with sdcv output."
 3  (let ((results (cl-loop for index from 0
 4                          for dicts in maple-translate-sdcv-dicts
 5                          collect
 6                          (progn
 7                            (goto-char (point-min))
 8                            (forward-line index)
 9                            (string-join (cl-loop for child across-ref (json-read-from-string (decode-coding-string (thing-at-point 'line t) 'utf-8))
10                                                  collect (format "%s: %s"
11                                                                  (alist-get 'dict child)
12                                                                  (alist-get 'definition child)))
13                                         "\n\n")))))
14    (unless (null results)
15      (string-join (cl-remove nil results) "\n\n"))))

最终效果

maple-translate的具体修改可见: dfd0eae

作者: honmaple
链接: https://honmaple.me/articles/2024/04/wei-maple-translatezeng-jia-geng-you-hao-de-sdcvchi-xian-fan-yi.html
版权: CC BY-NC-SA 4.0 知识共享署名-非商业性使用-相同方式共享4.0国际许可协议
wechat
alipay

加载评论