translate a region or an X11 selection in GNU Emacs

Overivew

Here's the small function that translates the region of text inside Emacs or the x-seleciton in an arbitrary graphical program. It uses a program called SDCV for translation. It also leverages the built-in functionality of GNU Emacs to fold the output of sdcv using outline-mode. It is useful, when you perform lookup it multiple dictionaries at once.

To expand an entry from the folded list place the cursor on it and press C-c C-e. To expand all the entries in this list press press C-c C-a. To fold an entry place the cursor on it and press C-c C-c. To fold all the entries in this list press press C-c C-t.

The list is folded by default. To disable folding set the variable my-sdcv-outline to t. To disable outline-mode set the variable my-sdcv-outline to nil.

(defvar my-sdcv-outline :hide-body
  "Can be t | nil | :hide-body")

(defvar my-sdcv-outline-regexp "^-->.*\n-->.*")

(defun my-sdcv ()
	"Translate a phrase from X11 selection. Depends on sdcv."
	(interactive)
	(let (phrase)
  ;; read x-selection or region
  (cond
   ;; if inside exwm buffer, use x-selection
   ;; (that's a hack for a number of packages like objed and atp)
   ((eq major-mode 'exwm-mode)
	(setq phrase (x-selection)))
   ;; if in emacs buffer, then use region
   ((region-active-p)
	(setq phrase (buffer-substring (region-beginning) (region-end)))
	(deactivate-mark))
   ;; else, use x-selection
   (t
	(setq phrase (x-selection))))
  ;; run the translator in a dedicated buffer
  (let ((my-sdcv-buffer (format "sdcv: %s"
				 (if (> 8 (length phrase))
					 phrase
				   (substring phrase 0 7)))))
	;; run sdcv and format the output when it's finished
	(set-process-sentinel
	 (start-process "sdcv"
			my-sdcv-buffer
			"sdcv"
			"-n" ;; non-interactive mode for sdcv
			 phrase)
	 (lambda (proc event)
	   (when (= 0 (process-exit-status proc))
		 (with-current-buffer (buffer-name (process-buffer proc))
	   (outline-mode)  
	   (setq-local outline-regexp  my-sdcv-outline-regexp)
	   (beginning-of-buffer)
	   (when (eql my-sdcv-outline :hide-body)
		 (outline-hide-body))))))
	;; display the result
	(let ((window (display-buffer my-sdcv-buffer)))
	  (if (not (window-live-p window))
	  (error "Got a dead window %S" window)
		(select-window window)
		(beginning-of-buffer))))))

It may have some bugs, use at it your own risk.

Integration with desktop environments

If you use a conventional desktop environment or a window manager, then you must run the emacs server and bind the following command to some convenient key combination in your desktop environment. Then you'll be able to look up the words from an X-selection in any desktop application and display the output in Emacs.

emacsclient -e '(my-sdcv)'

Also, you may want to display every buffer associated with sdcv in a separate pop-up frame. To do it add the following to your Emacs config (see the Emacs manual).

(add-to-list 'display-buffer-alist
	 (list "^sdcv:.*" #'display-buffer-pop-up-frame))

Without Emacs

The same can be done outside Emacs with the tiny program called sselp, and any dialog application like Zenity.

sselp | xargs sdcv -n | zenity --text-info --width=800 --height=800 --title="wrdef: $(sselp)"

Created: 2022-02-12 Сб 12:25