От переводчика: Это деcятая статья из цикла о Node.js от команды Mozilla Identity, которая занимается проектом Persona.В прошлой статье о локализации приложений Node.js мы узнали, как использовать модуль i18n-abide в нашем коде. Наша работа, как программистов, фактически закончилась на том, что мы обернули строки в шаблонах и коде приложения в вызовы
gettext(). Но работа по локализации и переводу приложения только начинается.Инструментарий
Инструментарий локализации команды Mozilla Persona совместим с теми инструментами, которые используются в остальном сообществе Mozilla, и при этом сохраняет преимущества в дружественности и гибкости, присущие Node.
Проекту Mozilla уже почти 15 лет, и наша команда локализаторов и переводчиков одна из самых больших (и клёвых) в мире Open Source. Поэтому у нас широко используются давно привычные, можно даже сказать старинные и причудливые инструменты.
Gettext
GNU Gettext — это набор инструментов, предназначенный для локализации настольных и веб-приложений. Когда вы пишете код и шаблоны для Node, вы используете везде английские фразы, но оборачиваете каждую из них в вызов
gettext().gettext делает две вещи:
- во время сборки составляет каталог всех строк, встреченных в приложении;
- во время выполнения заменяет их на локализованные варианты.
Все извлечённые строки хранятся в текстовых файлах с расширением
.po В дальнейшем мы будем называть их 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, Verbatim, Translate Toolkit и Pootle. Вместо того, чтобы заставлять людей переучиваться, мы решили разработать для них инструменты, совместимые с привычными стандартами и процессами.
Po-файлы — общепринятый формат обмена и сотрудничества наших переводчиков. Именно в этом формате они должны получать от нас строки для перевода, и отдавать нам готовый текст.
Имея большой опыт разработки в Mozilla ещё на PHP и Python, я нахожу Gettext очень удобным. По мере того, как веб-приложение растёт и содержит всё больше текста, проявляется всё больше нюансов, которые требуют применения хорошо проверенных инструментов и API Gettext.
Создаём po-файлы для переводчиков
Итак, мы разметили наш код вызовами gettext. Что дальше? В дело вступает тот, кого мы называем «строководом». Это можете быть вы сами, переводчик или администратор. Что делает строковод?
- Извлекает строки, впервые появившиеся в приложении.
- Находит новые, изменившиеся строки или помечает удалённые в последующих релизах.
- Готовит po-файлы для каждой команды переводчиков.
- Разрешает конфликты и помечает изменённые или удалённые строки переводов.
Это может звучать несколько запутанно, но, к счастью, большинство этих задач хорошо автоматизируется. Строководу приходится вмешиваться только, когда возникают проблемы.
msginit, xgettext, msgfmt и другие инструменты GNU Gettext — это мощный набор для работы с каталогами строк. С этими инструментами работает только строковод. Большинство разработчиков могут оставаться в блаженном неведении относительно них.
Создание дерева файлов для локали:
$ 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-файла для китайского языка.
Создание локали
Команда 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-файлы для американского английского, немецкого и испанского языков.
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-файлы, приводя их в соответствие с текущей версией приложения. После этого команды переводчиков могут снова браться за работу.
Gettext против синдрома «изобретено не здесь»
Нет ничего сложного в том, чтобы изобрести свой велосипед на основе JSON вместо gettext. Большинство авторов модулей Node пошли именно этим путём. Но по мере роста приложения и добавления новых и новых языков мелкие неприятности будут нарастать как снежный ком. Например, без merge-po.sh вам рано или поздно придётся писать и отлаживать собственные инструменты для слияния. Вручную обновить 30 файлов для 30 локалей, ничего при этом не потеряв и не перепутав — та ещё морока.
А в gettext всё необходимое уже есть и это экономит нам кучу времени и нервов.
Заключение
Теперь, когда мы окончательно разобрались, как создавать и обновлять po-файлы, можно перепоручить их заботам переводчиков. Вообще, всегда лучше заранее пообщаться с ними и обсудить, когда можно будет начать перевод, какой предполагается объём и когда желательно закончить. Также будет нелишним изучить документацию gettext.
Итак, строки переведены, и в следующей статье мы узнаем, как работает локализация во время выполнения приложения.
Продолжение следует...
This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:
- Massacres That Matter - Part 1 - 'Responsibility To Protect' In Egypt, Libya And Syria
- Massacres That Matter - Part 2 - The Media Response On Egypt, Libya And Syria
- National demonstration: No attack on Syria - Saturday 31 August, 12 noon, Temple Place, London, UK
Этот комментарий был удален автором.
ОтветитьУдалитьДобрый день! Если Вы заинтересованы в локализации web-ПО, ПО для персональных компьютеров, ПО для мобильных устройств либо иного вида программного обеспечения, я рекомендую Вам использовать этот инструмент на базе web: https://poeditor.com/
ОтветитьУдалитьPOEditor является интуитивным, хорошо проработанным инструментом, обладающим рядом полезных свойств, которые помогают организовать процесс управления переводом. Он поддерживает множество популярных форматов файлов и обладает собственным API, что обеспечивает лучшую автоматизацию. Желаю Вам больших успехов в Ваших проектах!