Translation In Emacs

screenshot.png
图1  Emacs 中翻译插件的使用截图,包括 emacs-immersive-translate, go-translate, fanyi

Emacs China 的时候看到了一些在 Emacs 中翻译的插件1, 2, 3,我也跟着配置了一些,最近也在使用 deepseek,它的 API 是和 OpenAI 兼容的,和翻译插件结合,翻译的效果还不错。

我想记录一下我都使用了什么插件,怎么配置的以及是如何使用的。

插件使用

插件我主要使用这几个:

Elilif/emacs-immersive-translate
Immersive-translate provides bilingual simultaneous display and translation of any text in Emacs.
lorniu/go-translate
Translator on Emacs. Supports multiple engines such as Google, Bing, deepL, ChatGPT, StarDict, Youdao and so on.
condy0919/fanyi.el
Not only English-Chinese translator for Emacs.
karthink/gptel
A simple LLM client for Emacs.

我使用最多的是 emacs-immersive-translate,它的灵感是 Immersive Translate,是我使用频率极高的一个浏览器翻译插件。

emacs-immersive-translate 给我的体验和 Immersive Translate 很接近,我主要是用来查看 Emacs 中的 Info,它还有 immersive-translate-auto-mode,可以在 buffer 变化的时候自动翻译,很方便。

最开始时我没有 OpenAI 的 API Key,我用的是 translate-shell,实际上就是 Goolge Translate

Google Translate 的翻译速度很快,缺点是有的时候翻译不是那么准确,但也基本够用了。

emacs-immersive-translate 针对 Emacs 中的 Info,elfeed 等做了适配,总体效果看起来是不错的,每次我看 Info 都会用到。

go-translate 的灵活度会更高一些,我主要用来选中文本之后进行翻译。

fanyi 则是当作字典使用,碰到一两个单词不熟悉,就使用 fanyi 进行查询。

我很喜欢 fanyi 里面的 海词,它可以生成图表,呈现单词含义的使用频率,让我了解这个单词最常见的含义。

最后,我还会用到 gptel,它实际上不是专门用来翻译的,但是作为 LLM,我可以在任何地方调用它,帮我完成一些翻译任务。

插件配置

你可以在 init-translate.el 中查看翻译的相关配置。

emacs-immersive-translate

你可以在 MELPA 上直接安装 emacs-immersive-translate。

不过我修改了源码,调整了翻译文字颜色,所以我是作为 git submodules 安装的。

然后我配置了使用 deepseek 作为翻译服务:

(push (expand-file-name "lisp/my-lisp/emacs-immersive-translate" user-emacs-directory) load-path)
(require 'immersive-translate)
;; need to add deepseek api-key with user `apikey` in `.authinfo`
(setq immersive-translate-backend 'chatgpt
      immersive-translate-chatgpt-host "api.deepseek.com"
      immersive-translate-chatgpt-model "deepseek-chat"
      immersive-translate-pending-message "(≖ᴗ≖๑)"
      immersive-translate-failed-message "(つд⊂) ")

API Key 在 ~/.authinfo 4, 5中配置,由于 emacs-immersive-translate 是查找 user 为 apikey 的配置,因此 user 这里需要设置为 apikey

machine api.deepseek.com login apikey password ********************************

go-translate

go-translate 也是可以在 MELPA 上直接安装。

我将它配置成使用 deepseek 作为翻译服务,翻译显示在一个新的 buffer 中。

;; @see: https://github.com/lorniu/go-translate
(maybe-require-package 'go-translate)
(maybe-require-package 'plz)
(with-eval-after-load 'go-translate
  (setq gt-langs '(en zh)
        gt-chatgpt-key (spike-leung/get-deepseek-api-key)
        gt-chatgpt-host "https://api.deepseek.com"
        gt-chatgpt-model "deepseek-chat"
        gt-default-translator (gt-translator
                               :engines (list
                                         (gt-chatgpt-engine))
                               :render (gt-buffer-render
                                        :buffer-name "gt-translator"
                                        :window-config '((display-buffer-at-bottom))
                                        :then (lambda (_) (pop-to-buffer "gt-translator"))))))

API Key 也是配置在 ~/.authinfo ,使用 spike-leung/get-deepseek-api-key 这个方法从文件中查找对应的密钥。

spike-leung/get-deepseek-api-key
;;; function to get api-key from authinfo
(defun spike-leung/get-api-key (service)
  "Retrieve the API key for SERVICE from authinfo."
  (let* ((host (format "api.%s.com" service))
         (creds (car (auth-source-search :host host :port 443))))
    (if creds
        (let ((api-key (plist-get creds :secret)))
          (if (functionp api-key)
              (funcall api-key)
            api-key
            (error "API key not found for %s" service)))
      (error "No credentials found for %s" service))))

(defun spike-leung/get-deepseek-api-key ()
  "Retrieve the DeepSeek API key from authinfo."
  (spike-leung/get-api-key "deepseek"))

(defun spike-leung/get-gemini-api-key ()
  "Retrieve the Gemini API key from authinfo."
  (spike-leung/get-api-key "gemini"))

Source

fanyi

fanyi 从 MELPA 上直接安装使用即可。

gptel

gptel 也是从 MELPA 上直接安装,然后配置 deepseek。

API Key 也是放在 ~/.authinfo ,和 go-translate 共用。

获取 API Key 也是通过 spike-leung/get-deepseek-api-key 方法。

;; init-gptel.el --- gptel
;;; Commentary:

(maybe-require-package 'gptel)

(with-eval-after-load 'gptel
  (gptel-make-openai "DeepSeek"
    :host "api.deepseek.com"
    :endpoint "/chat/completions"
    :stream t
    :key (spike-leung/get-deepseek-api-key)
    :models '(deepseek-chat deepseek-coder))
  (gptel-make-gemini "Gemini" :key (spike-leung/get-gemini-api-key) :stream t)
  (setq
   gptel-model 'deepseek-chat
   gptel-backend (gptel-make-openai "DeepSeek"
                   :host "api.deepseek.com"
                   :endpoint "/chat/completions"
                   :stream t
                   :key (spike-leung/get-deepseek-api-key)
                   :models '(deepseek-chat deepseek-coder))))

(global-set-key (kbd "M-o g") 'gptel-menu)

(provide 'init-gptel)
;;; init-gptel.el ends here

gptel 就是当 LLM 用,需要翻译的时候就复制文字和它对话。

此外,在日常开发中,gptel 还能用来重构代码,完成一些重复任务,给我一些初始代码逻辑等,也是我用的很频繁的插件。

deepseek V3 的价格足够便宜,也足够智能,目前我已经退了 ChatGPT Plus 的订阅,需要的时候使用 gptel 和 deepseek 对话。

快捷键

为了方便使用,我将这几个插件绑定到了相同的快捷键入口。

;; gptel
(global-set-key (kbd "M-o g") 'gptel-menu)

;; translate stuff
(defvar spike-leung/my-translate-keymap (make-sparse-keymap)
  "Keymap for translation commands.")

(define-key spike-leung/my-translate-keymap (kbd "i") 'immersive-translate-buffer)
(define-key spike-leung/my-translate-keymap (kbd "f") 'fanyi-dwim2)
(define-key spike-leung/my-translate-keymap (kbd "g") 'gt-do-translate)

(global-set-key (kbd "M-o t") spike-leung/my-translate-keymap)
M-o.png
图2  M-o 绑定的函数,包括 gptel,avy 以及翻译的前缀键
M-o-t.png
图3  M-o t 绑定的函数,主要是翻译相关的

写在最后

有了翻译插件,在阅读 info 等文档上真的帮助很大,极大地提高阅读效率。

集成了 LLM 后,翻译的质量也好了很多。

但依赖翻译插件也有个问题,就是原文会看的比较少,不利于增进英语学习。

如果你还有更好的插件,欢迎推荐啦 (ノ>ω<)ノ

脚注:

Author: Spike Leung

Date: 2025-01-16 Thu 00:00

Last Modified: 2025-01-16 Thu 12:51

License: CC BY-NC 4.0