- PVSM.RU - https://www.pvsm.ru -
От переводчика: Это деcятая статья из цикла о Node.js [1] от команды Mozilla Identity, которая занимается проектом Persona [2].
gettext()
. Но работа по локализации и переводу приложения только начинается.
Инструментарий локализации команды Mozilla Persona совместим с теми инструментами, которые используются в остальном сообществе Mozilla, и при этом сохраняет преимущества в дружественности и гибкости, присущие Node.
Проекту Mozilla уже почти 15 лет, и наша команда локализаторов и переводчиков одна из самых больших (и клёвых) в мире Open Source. Поэтому у нас широко используются давно привычные, можно даже сказать старинные и причудливые инструменты.
GNU Gettext — это набор инструментов, предназначенный для локализации настольных и веб-приложений. Когда вы пишете код и шаблоны для Node, вы используете везде английские фразы, но оборачиваете каждую из них в вызов gettext()
.
gettext делает две вещи:
Все извлечённые строки хранятся в текстовых файлах с расширением .po
В дальнейшем мы будем называть их po-файлы.
Po-файлы — это текстовые файлы определённого формата, которые gettext может читать, писать и объединять.
Вот пример содержимого po-файла zhTW/LCMESSAGES/messages.po:
#: resources/views/about.ejs:46
msgid "Persona preserves your privacy"
msgstr "Persona 保護您的隱私"
Подробнее мы его рассмотрим позже, а сейчас нам важно понимать, что msgid
— это английская строка, а msgstr
— её перевод на китайский. Всё, что начинается с #
— комментарий. Комментарий в этом примере указывает на расположение этой строки в коде.
Gettext предоставляет множество других инструментов для работы со строками и po-файлами. Мы коснёмся и их.
Прежде чем мы погрузимся в более подробное изучение модулей Node.js для работы с gettext, мы должны спросить себя, почему мы выбрали именно этот набор инструментов?
Год назад я подробно исследовал существующие модули Node.js для интернационализации и локализации. Большинство из них изобретали собственные велосипеды и основанные на JSON форматы для хранения строк.
С другой стороны, в Mozilla давно и успешно используются такие инструменты, как POEdit [12], Verbatim [13], Translate Toolkit [14] и Pootle [15]. Вместо того, чтобы заставлять людей переучиваться, мы решили разработать для них инструменты, совместимые с привычными стандартами и процессами.
Po-файлы — общепринятый формат обмена и сотрудничества наших переводчиков. Именно в этом формате они должны получать от нас строки для перевода, и отдавать нам готовый текст.
Имея большой опыт разработки в Mozilla ещё на PHP и Python, я нахожу Gettext очень удобным. По мере того, как веб-приложение растёт и содержит всё больше текста, проявляется всё больше нюансов, которые требуют применения хорошо проверенных инструментов и API Gettext.
Итак, мы разметили наш код вызовами gettext. Что дальше? В дело вступает тот, кого мы называем «строководом». Это можете быть вы сами, переводчик или администратор. Что делает строковод?
Это может звучать несколько запутанно, но, к счастью, большинство этих задач хорошо автоматизируется. Строководу приходится вмешиваться только, когда возникают проблемы.
msginit, xgettext, msgfmt и другие инструменты GNU Gettext [16] — это мощный набор для работы с каталогами строк. С этими инструментами работает только строковод. Большинство разработчиков могут оставаться в блаженном неведении относительно них.
Создание дерева файлов для локали:
$ mkdir -p locale/templates/LC_MESSAGES
В этой директории хранятся шаблоны po-файлов — файлы .pot
. Они будут использованы gettext в дальнейшем.
В прошлой статье мы установили i18n-abide:
$ npm install i18n-abide
Среди других инструментов командной строки, abide предоставляет extract-pot. Эта команда используется для извлечения строк в директорию локали:
mkdir -p locale/templates/LC_MESSAGES
$ ./node_modules/.bin/extract-pot --locale locale
Скрипт пройдёт по всему исходному коду приложения, находит строки и записывает их в файл шаблона po.
Для создания pot-файлов можно было бы воспользоваться и традиционными утилитами gettext, но мы написали специальный модуль jsxgettext, удобный и кроссплатформенный. Под капотом extract-pot использует именно его.
Jsxgettext ищет в коде вызовы gettext()
и извлекает из них строковый аргумент, затем он форматирует строки в формат, совместимый с инструментарием gettext. Вот отрывок такого pot-файла:
#: resources/views/about.ejs:46
msgid "Persona preserves your privacy"
msgstr ""
#: resources/views/about.ejs:47
msgid ""
"Persona does not track your activity around the Web. It creates a wall "
"between signing you in and what you do once you're there. The history of "
"what sites you visit is stored only on your own computer."
msgstr ""
""
#: resources/views/about.ejs:51
msgid "Persona for developers"
msgstr ""
Позже на основе этого шаблона будут созданы po-файлы с переводом. Они будут выглядеть так:
#: resources/views/about.ejs:46
msgid "Persona preserves your privacy"
msgstr "Persona 保護您的隱私"
#: resources/views/about.ejs:47
msgid ""
"Persona does not track your activity around the Web. It creates a wall "
"between signing you in and what you do once you're there. The history of "
"what sites you visit is stored only on your own computer."
msgstr ""
"Persona 只是連結您登入過程的一座橋樑,不會追蹤您在網路上的行為。您的網頁瀏覽"
"紀錄只會留在您自己的電腦當中。"
#: resources/views/about.ejs:51
msgid "Persona for developers"
msgstr "Persona 的開發人員資訊"
Чтобы лучше почувствовать тему, вы можете взглянуть на полный вариант po-файла [17] для китайского языка.
Команда msginit из набора Gettext используется для создания po-файла для конкретной локали, основанного на файле шаблона:
$ for l in en_US de es; do
mkdir -p locale/${l}/LC_MESSAGES/
msginit --input=./locale/templates/LC_MESSAGES/messages.pot
--output-file=./locale/${l}/LC_MESSAGES/messages.po
-l ${l}
done
Мы только что создали po-файлы для американского английского, немецкого и испанского языков.
Итак, мы извлекли строки и создали папки локалей. Вот так выглядит наше дерево файлов:
locale/
el/
LC_MESSAGES/
messages.po
en_US
LC_MESSAGES/
messages.po
es
LC_MESSAGES/
messages.po
templates
LC_MESSAGES/
messages.pot
К этим частям вашего приложения можно дать доступ переводчикам. К примеру, испанская команда будет иметь доступ к locale/es/LC_MESSAGES/messages.po
. Если у вас очень большой проект, могут быть даже две отдельные локали для испанского и аргентинского вариантов испанского языка: es-ES и es-AR.
Со временем могут добавляться новые локали.
Релиз за релизом вы будете добавлять новые, менять и удалять старые строки. Вам будет необходимо обновлять все po-файлы в соответствии с этими изменениями. В gettext есть мощные инструменты для этого. Для себя мы сделали скрипт-обертку merge-po.sh, который использует команду msgmerge из пакета GNU Gettext.
Добавим инструменты i18n-abide в системные пути:
$ export PATH=$PATH:node_modules/i18n-abide/bin
и запустим процесс слияния строк:
$ ./node_modules/.bin/extract-pot --locale locale .
$ merge_po.sh ./locale
Как и в первый раз, extract-pot собирает все строки и создаёт шаблон. Затем merge-po.sh обновляет все po-файлы, приводя их в соответствие с текущей версией приложения. После этого команды переводчиков могут снова браться за работу.
Нет ничего сложного в том, чтобы изобрести свой велосипед на основе JSON вместо gettext. Большинство авторов модулей Node пошли именно этим путём. Но по мере роста приложения и добавления новых и новых языков мелкие неприятности будут нарастать как снежный ком. Например, без merge-po.sh вам рано или поздно придётся писать и отлаживать собственные инструменты для слияния. Вручную обновить 30 файлов для 30 локалей, ничего при этом не потеряв и не перепутав — та ещё морока.
А в gettext всё необходимое уже есть и это экономит нам кучу времени и нервов.
Теперь, когда мы окончательно разобрались, как создавать и обновлять po-файлы, можно перепоручить их заботам переводчиков. Вообще, всегда лучше заранее пообщаться с ними и обсудить, когда можно будет начать перевод, какой предполагается объём и когда желательно закончить. Также будет нелишним изучить документацию gettext.
Итак, строки переведены, и в следующей статье мы узнаем, как работает локализация во время выполнения приложения.
Автор: ilya42
Источник [18]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/46045
Ссылки в тексте:
[1] цикла о Node.js: https://hacks.mozilla.org/category/a-node-js-holiday-season/
[2] Persona: http://ru.wikipedia.org/wiki/Mozilla_Persona
[3] Охотимся за утечками памяти в Node.js: http://habrahabr.ru/company/nordavind/blog/195494/
[4] Нагружаем Node под завязку: http://habrahabr.ru/company/nordavind/blog/195686/
[5] Храним сессии на клиенте, чтобы упростить масштабирование приложения: http://habrahabr.ru/company/nordavind/blog/196018/
[6] Производительность фронтэнда. Часть 1 — конкатенация, компрессия, кэширование: http://habrahabr.ru/company/nordavind/blog/196358/
[7] Пишем сервер, который не падает под нагрузкой: http://habrahabr.ru/company/nordavind/blog/196518/
[8] Производительность фронтэнда. Часть 2 — кешируем динамический контент с помощью etagify: http://habrahabr.ru/company/nordavind/blog/196818/
[9] Приручаем конфигурации веб-приложений с помощью node-convict: http://habrahabr.ru/company/nordavind/blog/197166/
[10] Производительность фронтенда. Часть 3 — оптимизация шрифтов: http://habrahabr.ru/company/nordavind/blog/197370/
[11] Локализация приложений Node.js. Часть 1: http://habrahabr.ru/company/nordavind/blog/197566/
[12] POEdit: http://www.poedit.net/
[13] Verbatim: https://localize.mozilla.org/
[14] Translate Toolkit: https://github.com/translate/translate
[15] Pootle: https://github.com/translate/pootle
[16] инструменты GNU Gettext: http://www.gnu.org/software/gettext/
[17] полный вариант po-файла: http://svn.mozilla.org/projects/l10n-misc/trunk/browserid/locale/zh_TW/LC_MESSAGES/messages.po
[18] Источник: http://habrahabr.ru/post/198154/
Нажмите здесь для печати.