Next: , Previous: , Up: Top   [Contents][Index]

10 Internationalization


Next: , Up: Internationalization   [Contents][Index]

10.1 Syntax

The easiest way to translate a string or variable is to enclose it between {_ and _}:

{_ var _}
{_ "hello" _}

Next: , Previous: , Up: Internationalization   [Contents][Index]

10.2 Tags


Up: Tags<2>   [Contents][Index]

10.2.1 trans

Translates a variable or string

Example:

{% trans var %}
{% trans "hello" %}

Next: , Previous: , Up: Internationalization   [Contents][Index]

10.3 Filters


Up: Filters<2>   [Contents][Index]

10.3.1 trans

Translates a variable or string.

For example:

{{ var | trans }}
{{ "my string" |  trans }}

Next: , Previous: , Up: Internationalization   [Contents][Index]

10.4 Choosing language

To choose the language to use, set the *CURRENT-LANGUAGE* variable.

For example:

(let ((djula:*current-language* :es))
   (djula:render-template* +translation.html+))

Next: , Previous: , Up: Internationalization   [Contents][Index]

10.5 Backends

Djula supports several backends for doing translations: cl-locale1, gettext2, translate3.

For translations to work, one of the translation backend systems need to be loaded and configured. Otherwise translate function will signal an error.

The ASDF systems are: djula-gettext, djula-locale and djula-translate.

Please have a look at the demo and the documentation of those packages to figure out how to use them.


Next: , Previous: , Up: Internationalization   [Contents][Index]

10.6 Translate backend

TBD


Next: , Previous: , Up: Internationalization   [Contents][Index]

10.7 Locale backend

TBD


Previous: , Up: Internationalization   [Contents][Index]

10.8 Gettext backend


Next: , Up: Gettext backend   [Contents][Index]

10.8.1 Gettext message extraction

For working with gettext library, messages to be translated first need to be extracted from Djula templates, generate a Lisp file with Gettext entries from it, and then extracted again from that file with xgettext library.

Create a Makefile similar to this:

gettext-extract: ## Extract gettext translations from source files
        sbcl --eval '(ql:quickload :my-project)' --eval '(djula::xgettext-templates :my-project-package (asdf:system-relative-pathname :my-project "i18n/xgettext.lisp"))' --quit
        find src -iname "*.lisp" | xargs xgettext --from-code=UTF-8 --keyword=_ --output=i18n/my-project.pot --sort-output

gettext-edit: ## Edit the extracted gettext translations
        msgmerge --update i18n/nb.po i18n/my-project.pot
        xdg-open i18n/nb.po

gettext-compile: ## Compile the edited gettext translations
        msgfmt --output-file=i18n/nb/LC_MESSAGES/ie.mo i18n/nb.po

gettext-init: ## Initialize gettext translations
        msginit --input=i18n/my-project.pot --locale=nb --output=i18n/nb.po

make gettext-extract first uses the Lisp compiler to extract translated strings from templates. That generates a Lisp file that can be used with xgettext command line utility. This Lisp file is basically dead code that should not be loaded into the project, just contains Gettext entries that xgettext utility can understand. Looks like this:

;; THIS FILE IS AUTOGENERATED. DON'T CHANGE BY HAND. USE XGETTEXT-TEMPLATES FUNCTION.
(INVOICE-ENGINE::GETTEXT "Activity")
(INVOICE-ENGINE::GETTEXT "Address 1")
(INVOICE-ENGINE::GETTEXT "Address 2")
(INVOICE-ENGINE::GETTEXT "Amount")
(INVOICE-ENGINE::GETTEXT "API")
(INVOICE-ENGINE::GETTEXT "Balance")
(INVOICE-ENGINE::GETTEXT "Close")
(INVOICE-ENGINE::GETTEXT "Company")
(INVOICE-ENGINE::GETTEXT "Contact person")

Then xgettext can be used to extract the messages from that file.


Previous: , Up: Gettext backend   [Contents][Index]

10.8.2 Gettext utilities

Use GETTEXT:PRELOAD-CATALOGS to inspect current gettext settings:

(gettext:preload-catalogs
   ;; Tell gettext where to find the .mo files
   #.(asdf:system-relative-pathname :my-project "locale/"))

And that returns Gettext information:

#S(GETTEXT::CATALOG
   :KEY ("fr_fr" :LC_MESSAGES "bookshops")
   :HEADERS ((:PROJECT-ID-VERSION . "PACKAGE VERSION")
             (:REPORT-MSGID-BUGS-TO . "")
             (:PO-REVISION-DATE . "YEAR-MO-DA HO:MI +ZONE")
             (:LAST-TRANSLATOR . "FULL NAME <EMAIL@ADDRESS>")
             (:LANGUAGE-TEAM . "LANGUAGE <LL@li.org>") (:LANGUAGE . "")
             (:MIME-VERSION . "1.0")
             (:CONTENT-TYPE . "text/plain; charset=CHARSET")
             (:CONTENT-TRANSFER-ENCODING . "8bit"))
   :NPLURALS 2
   :PLURALS-FUNCTION #<FUNCTION (LAMBDA (GETTEXT::N)) {542C149B}>
   :MESSAGES (SERAPEUM:DICT
               "Login" '("Se connecter")
               "Password" '("Mot de passe")
               "Please login to continue" '("Veuillez vous identifier pour continuer")
               "Results: ~a. Page: ~a/~a~&" '("Resultats: ~a. Page: ~a/~a~&")
               "Welcome to OpenBookStore" '("Bienvenue dans OpenBookStore")
              ) )

Run the following function to reload the translations when developing:

(defun reload-translations ()
  ;; Clear gettext's cache
  (clrhash gettext::*catalog-cache*)
  (gettext:preload-catalogs
   ;; Tell gettext where to find the .mo files
   #.(asdf:system-relative-pathname :my-project "locale/")))

Footnotes

(1)

https://github.com/arielnetworks/cl-locale

(2)

https://github.com/copyleft/gettext

(3)

https://gitlab.common-lisp.net/dkochmanski/translate


Previous: , Up: Gettext backend   [Contents][Index]