Where parallels cross

Interesting bits of life

Moldable Emacs: translate string at point in multiple languages!

Too long; didn't read

Have you ever needed to translate text to multiple languages? Select the To multiple languages mold with me-mold to translate your text at point.

The problem

At my current job, I release mobile apps. One release step is to make sure to keep the list of changes accessible to our clients. We support 4-5 languages, so I provide the release notes in many (foreign) languages. That requires me to click around in the translator tab of my browser a few times. This kind of stuff becomes boring pretty soon. Would it not be nice to view a string in many different languages? Even just to see how translations differ from each other! This sounds a job for a mold!

And there is a solution

For this mold we rely on the useful google-translate Emacs extension. This mode makes translation as simple as they should be.

For my use case, I like to translate the string at point or a selection. Usually I translate from English to other languages. That is why I define the following variable like so.

(defcustom me-languages (list :from "en" :to '("fr" "de" "it" "no" "pt" "es" "sv")) "Languages to translate to.")

This is just defining the source and target languages. You can redefine this as you need. And you can also redefine them programmatically, should you need that (by binding the variable in a let).

With such a selection, the string "How are you?", produces the following Org buffer.

* How are you?

** fr #Comment ca va?

** de #Wie geht es Ihnen?

** it #Come stai?

** no #Hvordan har du det?

** pt #Como você está?

** es #¿Cómo estás?

** sv #Hur mår du?

I use the # as a separator because it makes searching the next hit easier for me.

The core of the mold is the function google-translate-translate. This does the actual translation. By default this function displays the translation in a dedicated buffer. In our case, we want it as an Elisp string. You can redefine where to send the output of google-translate-translate, but there is no option to return just a string. Still, it comes with the target kill-ring. That is what we use in the following mold.

(me-register-mold
 :key "To multiple languages"
 :let ((sentence (or (me-get-region)
                     (sentence-at-point t))))
 :given (:fn (and sentence
                  (me-require 'google-translate)))
 :then (:fn
        (let* ((translations
                (-map
                 (lambda (language)
                   (google-translate-translate (plist-get me-languages :from) language sentence 'kill-ring)
                   (list :language language :translation n(car kill-ring)))
                 (plist-get me-languages :to)))
               (tree (--map (append (list :sentence sentence) it) translations)))
          (with-current-buffer buffername
            (org-mode)
            (erase-buffer)
            (insert (format "* %s\n\n" sentence))
            (--each translations
              (insert (format "** %s #%s\n\n"
                              (plist-get it :language)
                              (plist-get it :translation) )))
            (setq-local self tree))))
 :docs "You can translate text to multiple languages."
 :examples nil)

As you can see the mold is simple. With (car kill-ring) we grab the translation from google-translate-translate. We make a translation for each language in the :to of our me-languages variable. The rest of the mold is about formatting the translations in a buffer. Note that the self variable will contain a plist like the following.

((:sentence "How are you?" :language "fr" :translation "Comment ca va?")
 (:sentence "How are you?" :language "de" :translation "Wie geht es Ihnen?")
 (:sentence "How are you?" :language "it" :translation "Come stai?")
 (:sentence "How are you?" :language "no" :translation "Hvordan har du det?")
 (:sentence "How are you?" :language "pt" :translation "Como você está?")
 (:sentence "How are you?" :language "es" :translation "¿Cómo estás?")
 (:sentence "How are you?" :language "sv" :translation "Hur mår du?"))

And in a few lines, I made the translation step of my release pretty quick! Now I just have to automate the input of translations on the app website via Nyxt and... Oh well that is for another time!

Conclusion

Even translations are views! All you need for that is to install google-translate from Melpa and grab a copy of moldable-emacs. Then you will be able to translate to your favourite languages in batches!

Happy translating!

Comments