20 декабря 2011

Common Lisp. Интернационализация.

Для интернационализации будем использовать cl-l10n. Внимание, документация на сайте проекта устарела!

Загрузка:

(ql:quickload '#:cl-l10n)

Создание словарей:

(use-package :cl-l10n)

(defresources "ru_RU" 
  ("Hello" "Привет")
  ("world" "мир"))

(defresources "fr_FR" 
  ("Hello" "Bonjour")
  ("world" "monde"))

Включение макроридера для переводимых строк:

(enable-sharpquote-reader)

Использование словаря:

(with-locale (locale "ru_RU")
  (format nil "~a, ~a" #"Hello" #"world"))
"Привет, мир"
(with-locale (locale "fr_FR")
  (format nil "~a, ~a" #"Hello" #"world"))
"Bonjour, monde"

Для restas

Минимальные словари:

(cl-l10n:defresources "ru_RU"
  ("language" "Русский"))

(cl-l10n:defresources "fr_FR"
  ("language" "Française"))

(cl-l10n:defresources "en_US"
  ("language" "English"))

Роут переключающий локаль: сохраняет ее в сессии, и перенаправляет на предыдущую страницу:

(restas:define-route change-locale ("change-locale")
  (let ((done (hunchentoot:parameter :|done|)))
    (setf (hunchentoot:session-value :locale)
          (hunchentoot:parameter :|locale|))
    (restas:redirect (if done done "/"))))                                    

Генератор меню выбора языка. Список локалей представлен в последней строке:

(defun generate-language-menu ()
  (let ((current-locale (if (hunchentoot:session-value :locale)
                            (hunchentoot:session-value :locale)
                            "en_US")))
    (mapcar (lambda (locale-name)
              (cl-l10n:with-locale (cl-l10n:locale locale-name)
                (if (string= current-locale
                             locale-name)
                    (list
                     :data #"language")
                    (list :href (restas:genurl 'change-locale
                                               :locale locale-name
                                               :done (hunchentoot:request-uri*))
                          :data #"language"))))
            '("ru_RU" "en_US" "fr_FR"))))

Примерный вывод предыдущей функции:

((:HREF "/change-locale?locale=ru_RU&done=/index.html" :DATA "Русский")
 (:DATA "English")
 (:HREF "/change-locale?locale=fr_FR&done=/index.html" :DATA "Française"))

closure-templates шаблон:

<div id=language-menu>
  {foreach $locale in $locales}
    {if $locale.href}
      <a href={$locale.href}>{$locale.data}</a>
    {else}
      {$locale.data}
    {/if}
  {/foreach}
</div>

Декоратор для выполнения роута в контексте некоторой локали, по-умолчанию en_US:

(defclass localize (routes:proxy-route) ())

(defmethod restas:process-route ((route localize) bindings)
  (let ((locale (hunchentoot:session-value :locale)))
    (cl-l10n:with-locale (cl-l10n:locale (if locale locale "en_US"))
      (call-next-method))))

(defun @localize (origin)
  (make-instance 'localize :target origin))

Примерное использование декоратора:

(cl-l10n:enable-sharpquote-reader)
(restas:define-route index ("index.html" :decorators '(@localize))
  "Main page"
  (list :title #"Maxima web interface"
        :execute-title #"Execute"))

Комментариев нет:

Отправить комментарий