PO4A.7(1)

НАЗВАНИЕ
po4a - платформа для перевода документации и других материалов

Введение
Ниже приводится дополнение на любом языке, но только если оно существует. Если дополнение не существует, об ошибке не сообщается.

Этот документ служит введением в проект po4a, ориентированным на потенциальных пользователей, рассматривающих возможность использования этого инструмента, и на любознательных, желающих понять, почему все происходит именно так, как происходит.

Почему именно po4a?
Философия свободного программного обеспечения (ПО) состоит в том, чтобы сделать технологии по-настоящему доступными всем. Но лицензирование — это не единственное, о чём стоит задуматься: непереведённое свободное ПО бесполезно для неанглоговорящих пользователей. И нам предстоит ещё кое-какая работа, чтобы сделать его доступным по-настоящему для всех.

Эта ситуация хорошо понятна большинству проектов, и все сейчас убеждены в необходимости переводить все. Тем не менее, фактические переводы представляют собой огромную работу многих людей, которая осложняется небольшими техническими трудностями.

К счастью, у ПО с открытым исходным кодом достаточно хорошие переводы, которые удобно поддерживать благодаря инструментам из пакета gettext. Они извлекают строки для перевода из программ, и предоставляют их переводчикам в единообразном формате (называемом PO-файлы, или translation catalogs, каталоги переводов).Целая экосистема различных инструментов выросла вокруг оных, дабы помочь переводчикам собственно переводить эти PO-файлы. Результат их работы затем используется библиотекой gettext во время исполнения программы, чтобы отображать переведённые сообщения пользователю.

Что касается документации, то здесь ситуация все еще несколько неутешительна. Поначалу перевод документации может показаться проще, чем перевод программы, поскольку кажется, что нужно просто скопировать исходный файл документации и начать переводить содержимое. Однако, когда в исходную документацию вносятся изменения, отслеживание этих изменений быстро превращается в кошмар для переводчиков. Если выполнять эту задачу вручную, она становится неприятной и чреватой ошибками.

Устаревшие переводы часто хуже, чем отсутствие перевода вообще. Конечные пользователи могут быть обмануты документацией, описывающей старое поведение программы. Более того, они не могут напрямую взаимодействовать с сопровождающими, поскольку те не говорят по-английски. Кроме того, сопровождающий не может устранить проблему, поскольку не знает всех языков, на которые переведена документация. Эти трудности, часто вызванные плохим инструментарием, могут подорвать мотивацию добровольных переводчиков, что еще больше усугубляет проблему.

Цель проекта po4a - облегчить работу переводчиков документации. В частности, он делает переводы документации поддерживаемыми.

Идея заключается в повторном использовании и адаптации подхода gettext к этой области. Как и в gettext, тексты извлекаются из оригинальных мест и представляются переводчикам в виде каталогов переводов PO. Переводчики могут использовать классические инструменты gettext для контроля за выполнением работы, сотрудничества и организации команд. po4a затем вставляет переводы непосредственно в структуру документации для создания переведенных исходных файлов, которые можно обрабатывать и распространять так же, как и английские файлы. Любой абзац, который не переведен, остается на английском языке в итоговом документе, гарантируя, что конечные пользователи никогда не увидят в документации устаревший перевод.

Это автоматизирует большую часть тяжелой работы по обслуживанию перевода. Обнаружить абзацы, нуждающиеся в обновлении, становится очень просто, а процесс полностью автоматизирован, когда элементы перестраиваются без дополнительных изменений. Конкретная проверка также может быть использована для снижения вероятности ошибок форматирования, которые приведут к поломке документа.

Полный список достоинств и недостатков этого подхода перечислен в разделе «Часто задаваемые вопросы» ниже в этом документе.

  Поддерживаемые форматы
На данный момент этот подход был успешно воплощён для нескольких форматов:

man (зрелый парсер)
    Старый добрый формат man-страниц, который используют так много программ. Поддержка po4a приходится здесь очень кстати, ибо этот формат в некоторой степени сложен, и не особо дружелюбен к новичкам.

    Модуль Locale::Po4a::Man(3pm) также поддерживает формат mdoc, используемый в BSD man pages (они также довольно распространены в Linux).

AsciiDoc (зрелый парсер)
    Этот формат представляет собой легкий формат разметки, предназначенный для облегчения составления документации. Например, он используется для документирования системы git. Эти manpages переведены с помощью po4a.

    Подробнее см. в разделе Locale::Po4a::AsciiDoc.

pod (зрелый парсер)
    Это формат встроенной документации языка Perl (Perl Online Documentation). Сам язык и его расширения документируются с помощью этого формата, а также и большинство существующих сценариев perl. Это делает проще поддержать документацию близкой к исходному коду, так как они вместе находятся в одном и том же файле. Это делает проще жизнь программиста, но, к сожалению, не жизнь переводчика.

    Подробнее см. в разделе Locale::Po4a::Pod.

sgml (зрелый парсер)
    Даже если он и заменён XML в наши дни, этот формат всё ещё используется в тех документах, что длиннее нескольких экранов. Он может даже использоваться для целых книг. Обновление переводов таких длинных документов может быть настоящим вызовом. В частности, diff зачастую показывает себя абсолютно бесполезным, когда в исходном тексте изменяются отступы после обновления. К счастью, po4a может с этим помочь.

    На данный момент поддерживаются только DebianDoc и DocBook DTD, но добавлять поддержку новых DTD достаточно просто. Возможно даже использование po4a для перевода неизвестного SGML DTD, вообще не вмешиваясь в исходный код; достаточно только предоставить всю необходимую информацию в командной строке. См. подробности в Locale::Po4a::Sgml(3pm).

TeX / LaTeX (зрелый парсер)
    Формат LaTeX — это основной формат публикаций, используемый в мире Свободного ПО.

    Модуль Locale::Po4a::LaTeX(3pm) был проверен на документации Python, одной книге и нескольких презентациях.

text (зрелый парсер)
    Формат Text является базовым для многих форматов, включающих длинные блоки текста, включая Markdown, fortunes, YAML-загаловки (Front Matter), debian/changelog и debian/control.

    Поддерживает общий формат, используемый в генераторах статических сайтов, README и других системах документации. Подробности смотрите в разделе Locale::Po4a::Text(3pm).

xml and XHMTL (похоже, зрелый парсер)
    Формат XML является базовым для многих форматов документации.

    На данный момент, po4a поддерживает DocBook DTD (cм. Locale::Po4a::Docbook(3pm)) и XHTML.

BibTex (похоже, зрелый парсер)
    Формат BibTex используется наряду с LaTex для форматирования списков ссылок (библиографий).

    Подробнее см. в разделе Locale::Po4a::BibTex.

Docbook (похоже, зрелый парсер)
    Язык разметки на основе XML, использующий семантические теги для описания документов.

    Более подробную информацию см. в Locale::Po4a:Docbook.

Guide XML (похоже, зрелый парсер)
    Формат документации XML. Этот модуль был разработан специально для помощи в поддержке и сопровождении переводов документации Gentoo Linux по крайней мере до марта 2016 года (по данным Wayback Machine). С тех пор Gentoo перешла на XML-формат DevBook.

    Более подробную информацию смотрите в Locale::Po4a:Guide.

Wml (похоже, зрелый парсер)
    Язык веб-разметки, не путайте WML с WAP, используемым в мобильных телефонах. Этот модуль основан на модуле Xhtml, который сам основан на модуле XmL.

    Более подробную информацию смотрите в разделе Locale::Po4a::Wml.

Yaml (похоже, зрелый парсер)
    Строгий суперсет JSON. YAML часто используется в качестве системных или конфигурационных проектов. YAML лежит в основе программы Ansible компании Red Hat.

    Более подробную информацию см. в разделе Locale::Po4a::Yaml.

RubyDoc (похоже, зрелый парсер)
    Формат Ruby Document (RD), первоначально формат документации по умолчанию для Ruby и Ruby-проектов до преобразования в RDoc в 2002 году. Хотя, по-видимому, японская версия справочного руководства по Ruby все еще использует RD.

    Более подробную информацию см. в разделе Locale::Po4a::RubyDoc.

Halibut (похоже, экспериментальный парсер)
    Система создания документации, с элементами, похожими на TeX, debiandoc-sgml, TeXinfo и другие, разработанная Саймоном Тэтхемом, разработчиком PuTTY.

    Более подробную информацию см. в разделе Locale::Po4a:Halibut.

Ini (похоже, экспериментальный парсер)
    Формат файла конфигурации, популярный в MS-DOS.

    Более подробную информацию смотрите в разделе Locale::Po4a::Ini.

texinfo (крайне экспериментальный парсер)
    Вся документация GNU написана в этом формате (вообще говоря, это одно из необходимых условий, чтобы стать официальным проектом GNU). Поддержка Locale::Po4a::Texinfo(3pm) в po4a пока в зачаточном состоянии. Пожалуйста сообщайте об ошибках и запрашивайте новые возможности, когда требуется.

gemtext (крайне экспериментальный парсер)
    Собственный текстовый формат документации протокола Gemini. Обычно он использует расширение ".gmi". Поддержка этого формата в po4a пока находится в зачаточном состоянии. Если у вас возникнут какие-либо проблемы, то не стесняйтесь создавать новые сообщения об ошибках или запросы на добавление функций.

org (крайне экспериментальный парсер)
    Формат, используемый в Org-mode. Поддержка этого формата в po4a пока находится в зачаточном состоянии. Если у вас возникнут какие-либо проблемы, то не стесняйтесь создавать новые сообщения об ошибках или запросы на добавление функций.

vimhelp (крайне экспериментальный парсер)
    Формат, используемый для файлов справки Vim (а также документации некоторых сторонних плагинов). Поддержка этого формата в po4a пока находится в зачаточном состоянии. Если у вас возникнут какие-либо проблемы, то не стесняйтесь создавать новые сообщения об ошибках или запросы на добавление функций.

simplepod (крайне экспериментальный парсер)
    Аналогичен ранее упомянутому pod, но этот модуль использует новый парсер Pod::Simple. Поскольку он был создан не так давно, на данный момент возможны некоторые ошибки. Если вы заметите какое-либо странное поведение, пожалуйста, сообщите нам. В конечном итоге этот модуль заменит pod.

Другие поддерживаемые форматы
    Po4a также может обрабатывать некоторые более редкие или специализированные форматы, такие как документация опций компиляции для ядер Linux 2.4+ (Locale::Po4a::KernelHelp) или диаграммы, создаваемые инструментом dia (Locale::Po4a::Dia). Добавление нового формата часто очень просто, и главная задача состоит в том, чтобы придумать парсер для вашего целевого формата. Подробнее об этом см. в Locale::Po4a::TransTractor(3pm).

Не поддерживаемые форматы
    К сожалению, в po4a всё ещё нет поддержки нескольких форматов документации. Поддержку многих из них было бы не так сложно добавить. И это включает не только форматы документации, но и, например, описание пакетов (deb и rpm), вопросы, задаваемые интерактивными сценариями установки пакетов, файлы changelogs для пакетов, и все специализированные форматы файлов, которые используются в программах, такие как сценарии игр или файлы ресурсов wine.

Использование po4a
Самый простой способ использовать данный инструментарий в вашем проекте — создать файл настроек для утилиты po4a и в дальнейшем взаимодействовать только с ней. См. подробности в документации po4a(1). Остальная часть данного раздела посвящена более подробному описанию работы po4a для продвинутых пользователей, жаждущих углубить своё понимание.

  Подробная схема рабочего процесса, основанного на po4a
Прежде чем приступить к данному, излишне подробному, разделу, обязательно прочтите po4a(1), дабы получить общее представление о рабочем процессе, которому следует po4a. Возвращайтесь сюда, когда захотите получить всеобъемлющую страшную картину, которая будет включать практически все детали.

На следующей схеме master.doc - это документ, подлежащий переводу; XX.doc - это тот же документ, но переведённый на язык XX, а doc.XX.po - это каталог переводов для этого документа на язык XX. Авторы документации в основном будут иметь дело с master.doc (который может быть man-страницей, XML-документом, файлом AsciiDoc и т.п.); переводчики в основном будут иметь дело с PO-файлом, а конечные пользователи будут видеть только файл XX.doc.

Переходы с пометками в квадратных скобках, например "[po4a updates po]", представляют собой запуск инструментов po4a, а переходы с фигурными скобками, например "{обновление master.doc}" — ручное изменение файлов проекта.

                                   мастер.doc
                                       |
                                       V
      +<----<----+<-----<-----<--------+------->-------->--------+
      :          |                     |                         :
  {перевод}      |           {обновление мастер.doc}             :
      :          |                     |                         :
    XX.doc       |                     V                         V
(необязательно)  |                 мастер.doc ->-------->------->+
      :          |                  (новый)                      |
      V          V                     |                         |
   [po4a-gettextize]  doc.XX.po -->+   |                         |
          |           (старый)     |   |                         |
          |              ^         V   V                         |
          |              |   [po4a обновляет po]                 |
          V              |           |                           V
     перевод.pot         ^           V                           |
          |              |        doc.XX.po                      |
          |              |       (неточный)                      |
      {перевод}          |           |                           |
          |              ^           V                           V
          |              | {ручное редактирование}               |
          |              |           |                           |
          V              |           V                           V
      doc.XX.po --->---->+<---<-- doc.XX.po     аддендум      мастер.doc
     (начальный)                (актуальный) (необязательно) (актуальный)
          :                          |             |             |
          :                          V             |             |
          +----->----->----->------> +             |             |
                                     |             |             |
                                     V             V             V
                                     +------>------+-----<-------+
                                                   |
                                                   V
                                       [po4a обновляет переводы]
                                                   |
                                                   V
                                                 XX.doc
                                              (актуальный)

Опять же, эта схема несколько переусложнена. Для упрощенного обзора см. po4a(1).

В левой части показано, как po4a-gettextize(1) можно использовать для преобразования существующего проекта перевода в инфраструктуру po4a. Этот скрипт берет оригинальный документ и его переведенный аналог и пытается построить соответствующий PO-файл. Такое ручное преобразование довольно громоздко (подробнее см. документацию po4a-gettextize(1)), но оно необходимо только один раз для преобразования существующих переводов. Если у вас нет переводов для преобразования, вы можете забыть об этом и сосредоточиться на нужной части схемы.

В верху правой части, изображены действия автора оригинала — обновление документации. В середине правой части показываются автоматические действия по обновлению перевода. Новые материалы извлекаются и сравниваются с существующим переводом. Для тех частей, которые не были изменены используется уже существующий перевод, а те части, которые были изменены частично соединяются с уже существующим переводом, но с пометкой «неточно» (fuzzy), указывающей, что перевод должен быть обновлён. Новые или сильно изменённые части оказываются непереведёнными.

Затем, в разделе ручное редактирование описываются действия переводчиков, которые изменяют файлы PO, чтобы обеспечить перевод каждой оригинальной строки и абзаца. Это может быть сделано с помощью специального редактора, такого как GNOME Translation Editor, KDE's Lokalize или poedit, или с помощью онлайн-платформы локализации, такой как weblate или pootle. Результатом перевода является набор PO-файлов, по одному на каждый язык. Более подробную информацию см. в документации gettext.

В нижней части схемы показано, как po4a создаёт переведённый документ из исходного документа master.doc и каталога переводов doc.XX.po, который был обновлён переводчиками. Из исходного документа берётся его структура, а изначальное содержание заменяется его переведенной версией. Чтобы добавить к переводу некий дополнительный текст, при необходимости можно также использовать аддендумы (addendum). Обычно, они применяются для добавления, например, имени переводчика в окончательный документ. Подробности см. ниже.

При запуске po4a автоматически обновляет и файлы перевода, и файлы с переведённой документацией.

  Начало нового проекта перевода
Если вы начинаете с нуля, то вам нужно только создать файл настроек po4a, и на этом всё будет готово. Для файлов, которых нет, будут созданы необходимые шаблоны, которые позволят участникам вашего проекта переводить его на свои языки. Краткое руководство по началу работы и прочие подробности см. в po4a(1).

Если у вас уже есть какой-либо перевод, т.е. файл документации, который был переведён вручную, то вы можете извлечь из него перевод и встроить его в рабочий процесс, основанный на po4a с помощью po4a-gettextize. Этот процесс может быть несколько неуклюжим (как описано на man-странице утилиты), но как только ваш проект будет преобразован, всё будет обновляться автоматически.

  Обновление переводов и документов
После первоначальной настройки, простой запуск po4a будет выполнять и обновление PO-файлов и переведённой документации. Вы можете передать po4a параметр "--no-translations", чтобы не обновлять переводы (т.е. обновлять только PO-файлы) или параметр "--no-update", чтобы не обновлять PO-файлы (т.е. обновлять только переводы). Эти действия примерно соответствует тому, что делали специализированные сценарии po4a-updatepo и po4a-translate, которые сейчас признаны устаревшими (см. «Почему специализированные сценарии признаны устаревшими?» в разделе «Часто задаваемые вопросы» ниже).

  Использование аддендумов (addendum) для добавления дополнительного текста к переводам
Добавление нового текста в перевод - это, пожалуй, единственное, что в долгосрочной перспективе проще, когда вы переводите файлы вручную :). Это происходит, когда вы хотите добавить в переведённый документ дополнительный раздел, не имеющий каких-либо соответствий в исходном документе. Классический вариант — добавление раздела, который отдаёт должное команде переводчиков и указывает, как и куда сообщать о проблемах, связанных с переводом.

В po4a для этого необходимо задать addendum-файлы, которые на концептуальном уровне можно считать некими «патчами», накладываемыми на локализованный документ после его обработки. Каждый аддендум представляет из себя отдельный файла, формат которого, однако, сильно отличается от классических патчей. Первая строка — это строка заголовка, определяющая точку вставки аддендума (с, к сожалению, загадочным синтаксисом - см. ниже), в то время как остальная часть файла добавляется дословно в определенную позицию.

Строка заголовка должна начинаться со строки PO4A-HEADER:, за которой следует список полей key=value, разделенных запятыми.

Например, следующий заголовок указывает, что аддендум должен быть вставлен в самый конец перевода.

 PO4A-HEADER: mode=eof

Если вы хотите добавить своё дополнительное содержимое в середину документа, то всё становится сложнее. Так, следующий заголовок указывает, что аддендум должен быть вставлен после XML-раздела (ограниченного тегом "<section>"), содержащего строку "Об этом документе" (в переводе).

 PO4A-HEADER: position=Об этом документе; mode=after; endboundary=</section>

С практической точки зрения, при применении аддендума po4a ищет первую строку, соответствующую аргументу "position" (он является регулярным выражением). Не забывайте, что в данном случае po4a работает с уже переведённым документом. Например, если вы хотите, добавить аддендум к французскому переводу документа, то строка может выглядеть следующим образом:

 PO4A-HEADER: position=À propos de ce document; mode=after; endboundary=</section>

После того как "position" будет найдена в целевом документе, po4a будет искать среди строк следующих после "position" строку, которая соответствует указанному "endboundary" (также регулярное выражение). Аддендум будет добавлен сразу после этой строки (поскольку мы указали endboundary, то есть границу, заканчивающую текущий раздел).

Точно такого же эффекта можно было бы достичь с помощью следующего заголовка, который эквивалентен предыдущему:

 PO4A-HEADER: position=Об этом документе; mode=after; beginboundary=<section>

Здесь po4a ищет первую строку, которая будет сопоставлена "<section>" после строки, сопоставленной "Об этом документе" в переводе, и вставляет аддендум перед этой строке, поскольку мы указали beginboundary, то есть границу, обозначающую начало следующего раздела. Таким образом, этот заголовок указывает po4a, что аддендум должен быть вставлен после раздела, содержащего "Об этом документе", и задаёт, что раздел начинается со строки, содержащей тег "<section>". Это эквивалентно предыдущему примеру, поскольку на самом деле вам нужно добавить аддендум либо после "</section>", либо перед "<section>".

Вы также можете установить режим вставки (mode) в значение "before" с аналогичной семантикой: при указании "mode=before" совместно с "endboundary" аддендум будет размещён сразу после строки сопоставленной "endboundary", которая расположена до "position"; при указании "mode=before" совместно с "beginboundary" аддендум будет размещён сразу перед строкой сопоставленной "beginboundary" которая расположена до "position".

  Режим  |  Вид границы  |    Используемая граница    | Точка вставки относительно границы
 ========|===============|============================|===================================
 'before'|'endboundary'  | последняя перед 'position' | Прямо после выбранной границы
 'before'|'beginboundary'| последняя перед 'position' | Прямо перед выбранной границей
 'after' |'endboundary'  | первая после 'position'    | Прямо после выбранной границы
 'after' |'beginboundary'| первая после 'position'    | Прямо перед выбранной границей
 'eof'   | (нет)         | н/д                        | Конец файла

Советы и хитрости при использовании аддендумов

•   Запомните, что параметры аргументов аддендумов — это регулярные выражения. Например, если вы хотите сопоставить конец секции nroff, которая заканчивается строкой ".fi", то не стоит использовать ".fi" в качестве endboundary, ибо в таком случае также будет сопоставлена строка "the[ fi]le", что, очевидно, не то, что вы ожидаете. Правильный endboundary в этом случае будет: "^\.fi$".

•   Для параметров "position" и границ пробелы ВАЖНЫ. Например, две следующие строки различны. Вторая из них будет найден только в том случае, если в переведенном документе окажутся лишние пробелы на конце строки.

     PO4A-HEADER: position=Об этом документе; mode=after; beginboundary=<section>
     PO4A-HEADER: position=Об этом документе ; mode=after; beginboundary=<section>

•   Хотя и можно считать, что этот контекстный поиск, грубо говоря, перебирает текст перевода построчно, но на самом деле он работает со строками во внутреннем представлении данных документов. Этой строкой может быть, например, текст целого абзаца, разбитый на несколько фактических строк или один XML-тег сам по себе. Непосредственная точка вставки аддендума должна быть или до, или после таковой строки во внутреннем представлении и не может быть вставлена в середину оной.

•   Чтобы лучше понять, как аддендумы добавляются к переводу, передайте po4a параметр "-vv". Также, когда ваш аддендум не применяется и вы не можете определить, почему, то может быть полезно запустить po4a в режиме отладки, чтобы непосредственно увидеть строку с данными во внутреннем представлении.

Примеры аддендумов

•   Если вы хотите добавить что-то после следующего раздела nroff (формат man-страниц):

      .SH "АВТОРЫ"

    Вам следует выбрать подход с двумя регулярными выражениями, т.е. задать mode=after. Затем сузьте поиск до строк идущих после АВТОРЫ с помощью регулярного выражения в аргументе position. После этого вы должны сопоставить начало следующей секции (например, с помощью ^\.SH) в аргументе beginboundary. Короче говоря:

     PO4A-HEADER: mode=after; position=АВТОРЫ; beginboundary=\.SH

•   Если вы хотите добавить что-то сразу после конкретной строки (например, после «Copyright Большая Шишка»), используйте значение position, соответствующее этой строке, задайте mode=after, а beginboundary — значение, соответствие любой строке.

     PO4A-HEADER:mode=after;position=Copyright Большая Шишка, 2004;beginboundary=^

•   Если вы хотите добавить что-то в конец документа, то присвойте position регулярное выражение, сопоставляемое любой строке вашего документа (но только одна строке; po4a выдаст ошибку, если она будет не уникальна), и задайте endboundary не соответствующее ни чему. Лучше не использовать здесь простые строки, например "EOF", а отдать предпочтение тем, у которых меньше шансов оказаться в вашем документе.

     PO4A-HEADER:mode=after;position=О программе;beginboundary=FakePo4aBoundary

Более подробный пример

Исходный документ (формат POD):

 |=head1 NAME
 |
 |dummy - a dummy program
 |
 |=head1 AUTHOR
 |
 |Me <me@example.com>

Тогда следующий аддендум обеспечит добавление раздела о переводчике (на русском) в конец файла.

 |PO4A-HEADER:mode=after;position=АВТОР;beginboundary=^=head
 |
 |=head1 ПЕРЕВОД
 |
 |Я <me@example.ru>
 |

Чтобы поместить свой аддендум перед «АВТОР», используйте следующий заголовок:

 PO4A-HEADER:mode=after;position=ИМЯ;beginboundary=^=head1

Это работает, так как следующая сопоставляемая beginboundary "/^=head1/" строка после раздела «NAME» (переведённого как «ИМЯ» на русский) и начинает раздел с перечислением авторов. Таким образом, аддендум будет помещено между этими двумя разделами. Заметьте, что если в дальнейшем какой-либо другой раздел будет добавлен между разделами «ИМЯ» и «АВТОР», то данный пример будет работать не корректно, ибо аддендум будет вставляться перед этим новым разделом.

Чтобы избежать этого, можете использовать аналогичный заголовок с mode=before:

 PO4A-HEADER:mode=before;position=^=head1 АВТОР

Как это работает?
В этой главе даётся краткий обзор внутренних компонентов po4a так, чтобы вы могли чувствовать себя увереннее, если вы захотите помочь нам сопровождать и улучшать его. Это также может помочь вам понять, почему он не делаете того, что вы ожидали, и как решить ваши проблемы.

  TransTractors и архитектура проекта
В сердце всего проекта po4a находится Locale::Po4a::TransTractor(3pm), общий предком всех классов-парсеров. Своё странное имя он получил оттого, что он одновременно отвечает и за перевод документа и извлечение строк.

Если точнее, TransTractor берёт документ для перевода плюс PO-файл с переводами, кои являются его входными данными, и производит два отдельных набора выходных данных: другой PO-файл (как результат извлечения переводимых строк из входного документа) и переведённый документ (с той же структурой, что и входной, но со всеми переводимыми строками заменёнными содержимым входного PO-файла). Ниже приведено графическое представление этого процесса:

   Входной документ -\                            /---> Выходной документ
                      \      TransTractor::      /       (переведённый)
                      +-->--   parse()  --------+
                     /                           \
   Входной PO ------/                             \---> Выходной PO
                                                       (извлечённый)

Эта маленькая косточка и является ядром всей архитектуры po4a. Если вы предоставляете оба входных файла и игнорируете выходной PO-файл, вы получаете po4a-translate. Если вместо этого вы проигнорируете выходной документ то, вы получите po4a-updatepo. po4a сначала использует один TransTractor для получения актуального выходного POT-файла (игнорирую выходные документы), вызывает msgmerge -U для обновления PO-файлов перевода, а затем создаёт второй TransTractor, который использует эти файлы для обновления уже выходных документов. Короче говоря, po4a предоставляет комплексное решение для обновления всего, что нужно обновить, используя всего одну команду и один файл настроек.

po4a-gettextize также использует два экземпляра TransTractor, но по-другому: она создаёт по одному TransTractor для каждого языка, а затем создаёт новый PO-файл, используя значения msgid из исходного документа в качестве, собственно, msgid и значения msgid из переведённого документа в качестве msgstr. При этом требуется значительная осторожность, чтобы гарантировать, что строки, сопоставленные таким образом, действительно соответствуют друг другу, как описано в po4a-gettextize(1).

  Парсеры, специфические для конкретных форматов
Парсеры всех форматов в po4a реализованы поверх TransTractor. Некоторые из них очень простые, например Text, Markdown и AsciiDoc. Они загружают строки одну за другой, используя TransTractor::shiftline(), и накапливают содержимое абзацев (или что-то еще). После того как целая логическая строка (обычно, абзац) будет прочитана и разобрана, парсер использует TransTractor::translate(), чтобы (1) добавить эту строку в выходной PO-файл и (2) получить перевод из входного PO-файла. Далее парсер отправляет результат в выходной файл с помощью TransTractor::pushline().

Некоторые другие парсиры более сложны, поскольку для анализа входного документа они полагаются на сторонние парсеры. Так например, парсеры Xml, HTML, SGML и Pod построены на основе SAX-парсеров. Они создают обратные вызовы для таких событий, как «Я нашёл новый заголовок со следующим содержимым», чтобы обновить выходной документ и выходные POT-файлы в соответствии со входным содержимым, используя TransTractor::translate() и TransTractor::pushline(). Парсер Yaml также похож, но отличается: он сохраняет структуру данных, созданную парсером YAML::Tiny. В этом причина того, что Yaml-модуль po4a не может корректно сохранять сноски на расположение строк в исходном файле: синтаксический анализатор не сохраняет расположение каждой строки, поэтому всё что мы можем, это только добавить «$имя_файла:1» в качестве местоположения строки. Парсеры же, основанные на SAX-модели, используют глобальные переменные и другие приёмы для сохранения имен файлов и номеров строк в сносках.

Особый класс проблем возникает из-за кодировок файлов и маркера порядка байт. Более простые парсеры могут не волноваться об этом, так как TransTractor::read() (используется внутри пасеров для чтения входного документа) сам заботится об обработке кодировок. А вот модули, использующие внешний парсеры, должны сами контролировать, что все файлы, которые они читают проходят через соответствующие уровни декодирования PerlIO. Самое простое — открыть файл самостоятельно и передать внешнему парсеру или дескриптор файла, или прочитать его самостоятельно и передать всё его содержимое парсеру в виде строки. В качестве примера см. Pod::read() и Pod::parse(). В случае, когда дескриптор файла передаётся внешнему парсеру, то то, что читает TransTractor, должно быть проигнорированно, а также важно, чтобы при открытии файла perl-функции open() передавалась корректная кодировка: "<:encoding($charset)".

  PO-объекты
Класс Locale::Po4a::Po(3pm) отвечает за загрузку PO и POT-файлов, а также запрос переведённых строк из них. Если кратко, то вы можете читать файл, добавлять в него записи, получать из него переводы с помощью gettext() и снова сохранять PO-файл. Более сложная функциональность, вроде объединение PO-файлов с POT-файлами или проверка файлов, отдаётся уже на откуп утилитам msgmerge и msgfmt соответственно.

  Внесение своего вклада в po4a
Даже если вы никогда раньше не участвовали в каких-либо проектах с открытым исходным кодом, мы будем вам рады: здесь мы готовы помочь вам и, по-необходимости, можем дать вам некоторые наставления. po4a в настоящее время в основном поддерживается пользователями. Поскольку нам не хватает рабочей силы, мы стараемся сделать проект приветливым и привлекательным, улучшая документацию и автоматизированные тесты, чтобы вам было проще внести свой вклад в проект. Более подробную информацию можно найти в файле CONTRIBUTING.md.

Проекты с открытым исходным кодом, использующие po4a
Вот очень неполный список проектов, которые используют po4a при переводе своей документации. Если вы хотите добавить свой проект в список, то просто напишите нам e-mail (или запрос на слияние).

•   adduser (man): инструмент по управлению пользователями и группами.

•   apt (man, docbook): менеджер пакетов Debian.

•   aptitude (docbook, svg): консольный менеджер пакетов для Debian

•   F-Droid website <https://gitlab.com/fdroid/fdroid-website> (markdown): каталог свободных и открытых приложений (Free and Open Source Software) для платформы Android.

•   git <https://github.com/jnavila/git-manpages-l10n> (asciidoc): распределённая система контроля изменений исходного кода.

•   Linux manpages <https://salsa.debian.org/manpages-l10n-team/manpages-l10n> (man)

    Также этот проект предоставляет инфраструктуру для перевода на разные языки множества разношёрстных man-страниц, которые затем интегрируются во многие основные дистрибутивы (в частности, Arch Linux, Debian и его производные, Fedora).

•   Stellarium <https://github.com/Stellarium/stellarium> (HTML): свободный планетарий для Вашего компьютера с открытым исходным кодом. po4a используется для перевода названий созвездий в различных культурах.

•   Jamulus <https://jamulus.io/> (markdown, yaml, HTML): FOSS-приложение для онлайн джем-сессий в режиме реального времени. Переводы документации и веб-сайта на несколько языков поддерживаются с использованием po4a.

•   И другие проекты, в которых мы пока не разобрались: <https://gitlab.com/fdroid/fdroid-website/> <https://github.com/fsfe/reuse-docs/pull/61>

Часто задаваемые вопросы

  Как вы произносите «po4a»?
Лично я произношу это как pouah <https://en.wiktionary.org/wiki/pouah>, это французское междометие, подобное русскому «фу!» :) Возможно, у меня странное чувство юмора :)

  Почему специализированные сценарии признаны устаревшими?
po4a-updatepo и po4a-translate, действительно, считаются устаревшими (depricated) в пользу po4a. Причина в том, что, с одной стороны, po4a можно использовать в качестве прямой замены этих сценариев, а с другой — между ними довольно много дублирующегося кода, который сложно поддерживать. Отдельные сценарии состоят примерно из 150 строк кода, а утилита po4a — из 1200, так что она имеет куда более изощрённую логику. К тому же, дублирование кода приводит к тому, что ошибки, возникающие в обеих версиях, требуют того, чтобы их исправляли дважды. Одним из таких примеров может служить баг #1022216 в Debian и сообщение об ошибке #442 на GitHub, для которых требовались практически одинаковые действия по исправлению, но одно было в po4a, а другое в po4a-updatepo.

В долгосрочной перспективе я бы хотел полностью отказаться от специализированных сценариев и поддерживать только одну версию этого кода. Разумеется, в специализированные сценарии больше не будет добавляться ни какой новой функциональности, которая будет только в po4a. При этом нет никакой срочности в полном отказе от оных. Я планирую сохранять специализированные сценарии как можно дольше, по крайней мере, до 2030 года. Если в 2030 году ваш проект по-прежнему будет использовать po4a-updatepo и po4a-translate, то у вас могут возникнуть проблемы.

Мы также можем в какой-то момент и отменить решение о признании этих скриптов устаревшими, в случае, если рефакторинг кода когда-нибудь полностью устранит дупликацию. Если у вас есть идея на этот счёт (а лучше патч), ваша помощь приветствуется.

  Как насчёт других инструментов перевода документации, использующих gettext?
Таковых есть несколько. Вот их (возможно неполный) список, а также на горизонте маячат несколько новых инструментов.

poxml
    Это инструмент, разработанный командой KDE для работы с DocBook XML. На сколько я знаю, это была первая программа, которая извлекала переводимые строки из документации в PO-файлы и подставляла их обратно после перевода.

    Она может обрабатывать только XML и только с определённым DTD. Мне не очень нравится, как она обрабатывает списки, которые представляются одним большим msgid. Когда список становится большим, весь этот кусок становится сложно переработать.

po-debiandoc
    Эта программа, созданная Денисом Барбье, является своего рода предшественником модуля SGML в po4a, который более или менее делает её устаревшей. Как становится ясно из названия, она обрабатывает только DTD DebianDoc, который также относительно устарел.

xml2po.py
    Используется командой документации GIMP с 2004 года; работает достаточно хорошо, даже с учётом того, что, как следует из названия, она работает только с XML-файлами, а также она требует специализированных make-файлов.

Sphinx
    Генератор документации Sphinx также активно использует gettext для управления переводами. К сожалению, он работает только с ограниченным набором текстовых форматов: rest и markdown, хотя это, пожалуй, единственный инструмент, который полностью управляет всем процессом перевода.

Основные преимущества po4a перед оными — это простота добавления дополнительного содержипого (по крайней мере там это реализовано ещё хуже) и возможность проведения геттекстизации.

  РЕЗЮМЕ преимуществ подхода, основанного на gettext

•   Переводы хранятся отдельно от оригиналов, что позволяет определить, устарели ли первые.

•   Переводы на разные языки хранятся в отдельных файлах, что не даёт разноязычным переводчикам мешать друг другу, как при отправке ими патчей, так и на уровне кодировок файлов.

•   Внутренне устройство основано на gettext (но po4a предлагает простой интерфейс, так что вам не нужно понимать его внутреннее устройство, чтобы просто пользоваться им). Таким образом, нам не приходится заново изобретать колесо, а, так как gettext широко используется, мы можем считать, что в нём остаётся относительно мало программных ошибок.

•   Для конечного пользователя ничего не меняется (помимо того факта, что, надо надеяться, перевод будет лучше поддерживаться). Полученный файл документации распространяется точно так же.

•   Переводчикам не нужно изучать новый синтаксис файлов, и их любимого редактора PO-файлов (например, PO-режим Emacs, Lokalize или Gtranslator) будет вполне достаточно.

•   gettext предлагает простой способ получить статистику о том, что готово, что должно быть проверено и обновлено, а что ещё предстоит сделать. Некоторые примеры можно найти по следующим ссылкам:

     - https://docs.kde.org/stable5/en/kdesdk/lokalize/project-view.html
     - http://www.debian.org/intl/l10n/

Но не всё так радужно, и этот подход также имеет некоторые недостатки, с которыми нам приходится смириться.

•   Аддендумы несколько странные на первый взгляд.

•   Вы не можете приспособить переведённый текст к своим предпочтениям, например, разделить какой-то абзац здесь-то или объединили два в один там-то. Но в некотором смысле, если есть проблема в оригинале, об этом должно быть сообщено, как об ошибке.

•   Даже при том, что интерфейс является простым, po4a остаётся новым инструментом, который людям придётся изучать.

    Одна моя мечта состоит в том, чтобы каким-то образом интегрировать po4a в Gtranslator или Lokalize. Тогда при открытии файла документации, строки автоматически извлекались бы, а когда он сохранялся, переведённый файл и PO-файл мог ли бы записываться на диск. Если бы нам удалось сделать модуль MS Word (TM) (или, по крайней мере, RTF), то даже профессиональные переводчики могли бы использовать po4a.

СМОТРИТЕ ТАКЖЕ

•   Документацию po4a(1), основной утилиты, которую вы должны использовать.

•   Документация отдельных сценариев po4a: po4a-gettextize(1), po4a-updatepo(1), po4a-translate(1), po4a-normalize(1).

•   Дополнительные вспомогательные сценарии: msguntypot(1), po4a-display-man(1), po4a-display-pod(1).

•   Парсеры для каждого отдельного формата, в особенности обратите внимание на параметры, принимаемые каждым из них: Locale::Po4a::AsciiDoc(3pm) Locale::Po4a::Dia(3pm), Locale::Po4a::Gemtext(3pm), Locale::Po4a::Guide(3pm), Locale::Po4a::Ini(3pm), Locale::Po4a::KernelHelp(3pm), Locale::Po4a::Man(3pm), Locale::Po4a::RubyDoc(3pm), Locale::Po4a::Texinfo(3pm), Locale::Po4a::Text(3pm), Locale::Po4a::Xhtml(3pm), Locale::Po4a::Yaml(3pm), Locale::Po4a::BibTeX(3pm), Locale::Po4a::Docbook(3pm), Locale::Po4a::Halibut(3pm), Locale::Po4a::LaTeX(3pm), Locale::Po4a::Org(3pm), Locale::Po4a::Pod(3pm), Locale::Po4a::Sgml(3pm), Locale::Po4a::TeX(3pm), Locale::Po4a::VimHelp, Locale::Po4a::Wml(3pm), Locale::Po4a::Xml(3pm).Locale::Po4a::Dia(3pm), Locale::Po4a::Gemtext(3pm), Locale::Po4a::Guide(3pm), Locale::Po4a::Ini(3pm), Locale::Po4a::KernelHelp(3pm), Locale::Po4a::Man(3pm), Locale::Po4a::RubyDoc(3pm), Locale::Po4a::Texinfo(3pm), Locale::Po4a::Text(3pm), Locale::Po4a::Xhtml(3pm), Locale::Po4a::Yaml(3pm), Locale::Po4a::BibTeX(3pm), Locale::Po4a::Docbook(3pm), Locale::Po4a::Halibut(3pm), Locale::Po4a::LaTeX(3pm), Locale::Po4a::Org(3pm), Locale::Po4a::Pod(3pm), Locale::Po4a::SimplePod(3pm), Locale::Po4a::Sgml(3pm), Locale::Po4a::TeX(3pm), Locale::Po4a::VimHelp, Locale::Po4a::Wml(3pm), Locale::Po4a::Xml(3pm).

•   Реализации базовых классов: Locale::Po4a::TransTractor(3pm) (особенно важно для понимания организации кода), Locale::Po4a::Chooser(3pm), Locale::Po4a::Po(3pm), Locale::Po4a::Common(3pm). Также проверьте файл CONTRIBUTING.md в дереве исходного кода.

АВТОРЫ
 Денис Барбье (Denis Barbier) <barbier,linuxfr.org>
 Мартин Кенсон (Martin Quinson) (mquinson#debian.org)