
При разработке CMF я столкнулся с необходимостью грамотно реализовать i18n (мультиязычность), и стал рассматривать различные варианты…
Сначала, исходя из прошлого опыта, я хотел сделать «языковые константы» и мытарствах с хаками для числительных. Но потом к счастью остановил свой выбор на GNU gettext, на мощном и популярном (в Unix-среде) инструменте. Вскоре я понял что нет смысла излишне нагружать сервер переводами фраз, которые не индексируются поисковиками, и что в ряде случаев лучше переводить на клиенте. Однако, необходима была унифицированная система, позволяющая делать переводы в едином формате.
Прогуглив gettext javascript, я увидел несколько реализаций.
Первой попалась — code.google.com/p/gettext-js
Плюс в том что она не требует дополнительной переконвертации исходного po-файла, минус — нету ngettext.
Потом я нашел plugins.jquery.com/project/gettext
Её я и решил использовать. Однако, для работы плагина требуется подготовка специального JSON-файла из MO-файла.
Для конвертации приводится функция на Python:
import simplejson as enc import gettext def gettext_json(domain, path, lang = [], indent = False): try: tr = gettext.translation(domain, path, lang) # for unknown reasons, instead of having plural entries like # key: [sg, pl1...] # tr._catalog has (key, n): pln, keys = tr._catalog.keys() keys.sort() ret = {} for k in keys: v = tr._catalog[k] if type(k) is tuple: if k[0] not in ret: ret[k[0]] = [] ret[k[0]].append(v) else: ret[k] = v return enc.dumps(ret, ensure_ascii = False, indent = indent) except IOError: return None
Пришлось потратить… дцать минут на гуглеж и изучение доки, чтоб поправить код и заставить работать. В результате родил нормальную Unix-программу.
gettext2json
#!/usr/bin/python import sys import simplejson as enc import gettext def gettext_json(domain, path, lang = [], indent = False): try: tr = gettext.translation(domain, path, lang) # for unknown reasons, instead of having plural entries like # key: [sg, pl1...] # tr._catalog has (key, n): pln, keys = tr._catalog.keys() keys.sort() ret = {} for k in keys: v = tr._catalog[k] if type(k) is tuple: if k[0] not in ret: ret[k[0]] = [] ret[k[0]].append(v) else: ret[k] = v return enc.dumps(ret, ensure_ascii = True, indent = indent) except IOError as (errno, strerror): print "I/O error({0}): {1}".format(errno, strerror) print gettext_json(sys.argv[1],sys.argv[2],[sys.argv[3]], True)
Также, решил автоматизировать процесс создания бинарных MO-файлов из текстовых PO-файлов:
BuildLocales:
#!/usr/bin/php -q <?php chdir(__DIR__); $lcPath = './locale'; $jsPath = './static/locale'; foreach (glob($lcPath.'/*/LC_MESSAGES/*.po') as $poFile) { $locale = pathinfo(dirname(dirname($poFile)), PATHINFO_FILENAME); $domain = pathinfo($poFile, PATHINFO_FILENAME); $moFile = dirname($poFile).'/'.$domain.'.mo'; $jsFile = $jsPath.'/'.$locale.'/'.$domain.'.json'; shell_exec('mkdir -p '.escapeshellarg($jsPath.'/'.$locale)); shell_exec('msgfmt -o '.escapeshellarg($moFile).' '.escapeshellarg($poFile)); $cmd = 'gettext2json '.escapeshellarg($domain).' '.escapeshellarg($lcPath ).' '.escapeshellarg($locale).' > '.escapeshellarg($jsFile); shell_exec($cmd); }
Таким образом, для подготовки всех файлов достаточно лишь создать/изменить текстовый .po файлы в папке locale и запустить скрипт BuildLocales.
Для подключения gettext к Javascript необходимо указать атрибут lang у тега html, добавить в head элемент link с путем до json-файла и подгрузить jquery.gettext.js.
Начало HTML-кода страницы будет выглядеть примерно так:
<!DOCTYPE html> <html lang="ru"> ... <link href="/locale/ru/mydomain.json" lang="ru" rel="gettext"/> <script type="text/javascript" src="/js/jquery.gettext.js" /> ...
Затем можно вызывать функцию _(«Hello world!») и наслаждаться. Упс! Не работает!
Придется кое-что поправить в jquery.gettext.js, накладываем patch:
63,66c63,70 < try { < var messages = eval('(' + data + ')'); < } catch(e) { < return; --- > if (typeof(data) == 'object') { > var messages = data; > } else { > try { > var messages = eval('(' + data + ')'); > } catch(e) { > return; > }
Те кому лень накладывать патч берут jquery.gettext.js.
Надеюсь жаркое вам понравилось, спасибо за внимание.
