PO4A.7(1)

名前
po4a - ドキュメントやその他の素材の翻訳フレームワーク

概要
po4a (PO for anything) は、従来の gettext ツールを使った文書翻訳の保守を容易にするものです。po4aの主な特徴は、内容の翻訳を文書構造から切り離すことです。

このドキュメントではpo4aプロジェクトの紹介を行いこのツールを使うかどうかを検討している潜在的な利用者と、このツールの仕組みのなりたちを理解したいという興味のある読者に焦点を当てます。

なぜpo4aなのか？
自由ソフトウェアの理念は、技術を真に誰もが利用できるようにすることです。しかし、ライセンスだけが考慮すべきことではありません。翻訳されていない自由ソフトウェアは、英語を母国語としない人々にとっては無用の長物なのです。ですから、ソフトウェアを誰もが利用できるようにするためにやるべきことはまだあります。

このような状況はほとんどのプロジェクトで知られており、誰もがあらゆるものを翻訳する必要性を確信しています。しかし、実際の翻訳は、多くの人の膨大な努力の結晶であり、ちょっとした技術的な問題で不自由なことになっているのが現状です。

ありがたいことに、オープンソースソフトウェアは、gettext tool suite を使って実際に非常によく翻訳されています。これらのツールは、プログラムから翻訳する文字列を抽出し、標準化された形式（POファイル、または翻訳カタログと呼ばれます）で翻訳する文字列を提示するために使用されます。翻訳者が実際にこのPOファイルを翻訳するのを助けるために、このツールのエコシステム全体が成立しました。そしてその結果を実行時にgettextが使用し、エンドユーザーに翻訳された文言を表示するのです。

しかし、ドキュメンテーションに関しては、まだ少し残念な状況です。最初の時点は文書の元のファイルを複製して翻訳を始めるだけなので、プログラムの翻訳よりも簡単そうに見えるかもしれません。しかし、元の文書が変更された場合、その変更点を把握しておくことは、すぐさま翻訳者にとって悪夢となります。手作業で行う場合、この作業は不快であり、誤りの温床となるのです。

古い翻訳は、全く翻訳がないことよりも悪いことがよくあります。エンドユーザは、プログラムの古い動作を説明した文書に騙される可能性があります。さらに、彼らは英語を話せないので、保守者と直接対話することができません。加えて、保守者は文書が翻訳されているすべての言語は知らないので、問題を修正することができません。このような困難はしばしば貧弱なツールによって引き起こされるもので、ボランティアの翻訳者のモチベーションを蝕み、問題をさらに悪化させる可能性があります。

po4aプロジェクトの目標は、文書を翻訳する人の仕事を楽にすることです。特に、文書の翻訳を保守可能なものにすることです。

アイディアとしてはgettextの手法を再利用し、この分野に適応させようというものです。gettextと同様、テキストは元の場所から抽出され、POの翻訳カタログとして翻訳者に提示されます。翻訳者はgettextの古典的なツールを活用して、取り組んでいる作業を監査し、チームとして協力・組織化することができます。それからpo4aは翻訳を文書構造に直接注入して、英語ファイルと同様に処理・配布できる翻訳済みソースファイルを生成します。翻訳されなかった段落は、翻訳後の文書に英語のまま残され、エンドユーザーが文書内の古い翻訳を目にすることがないようにします。

これにより、翻訳の保守におけるほとんどの荷の重い作業が自動化されます。更新が必要な段落を発見するのは非常に簡単であり、要素の順番が変わっただけでそれ以外の変更がなければ工程は完全に自動化されます。また何らかの検証を行うことで、文書が壊れてしまうような形式エラーの可能性を減らすことができます。

このアプローチの利点と欠点のより詳しい一覧は、このドキュメントの後ろの FAQ を参照してください。

  サポートするフォーマット
現在、このアプローチで実装に成功しているのは、以下のテキスト整形フォーマットです:

man（成熟した構文解析器）
    たくさんのプログラムで使われている、古き良きマニュアルページの形式です。この形式はいくらか難しく、初心者には本当に易しくありません。

    Locale::Po4a::Man(3pm) モジュールは、BSD の man ページで使われている mdoc 形式にも対応しています（Linux でもかなり一般的になっています）。

AsciiDoc（成熟した構文解析器）
    この形式は、文書の執筆を容易にすることを目的とした軽量のマークアップ形式です。例えば、git システムのドキュメントに使用されています。これらのmanページは po4a を使って翻訳されています。

    詳しくはLocale::Po4a::AsciiDocをご覧ください。

pod（成熟した構文解析器）
    Perl のオンラインドキュメントフォーマットです。既存のほとんどの Perl スクリプトに加え、言語や拡張機能自体がこの形式を使って記述されています。ドキュメントと実際のコードの両方を同じファイルに組み込んでおくことで両者の内容を近しいものに保ちやすくなっています。プログラマーの体験が良くなりますが、残念ながら翻訳者の生活は楽にはなりません。po4aを使うまではね。

    詳細はLocale::Po4a::Podを見てください。

sgml（成熟した構文解析器）
    現在ではXMLに取って代わられたとはいえ、数画面以上の文書にはこの形式が使われます。本全体に使われることもあります。これだけの長さの文書は、更新するのが非常に困難です。diffは、更新後に元のテキストの字下げが改められた場合、明らかに役に立たないとわかることがよくあります。幸いなことに、po4aはそのような変更処理の後でも助けになります。

    現在、DebianDoc と DocBook DTD のみに対応していますが、新しく対応するものを追加するのは、本当に簡単です。また、コマンドラインに必要な情報を与え、コードを変更せずに未知の SGML DTD を po4a で使用することもできます。詳細は Locale::Po4a::Sgml(3pm) を参照してください。

TeX / LaTeX （成熟した構文解析器）
    LaTeX形式は自由ソフトウェア界や出版界で使われている主要な文書形式です。

    Locale::Po4a::LaTeX(3pm) モジュールは Python のドキュメントや書籍、プレゼンのスライドでの実績があります。

text（成熟した構文解析器）
    テキスト形式は、Markdown、fortunes、YAMLフロントマター節、debian/changelog、debian/control など、長いテキストブロックを含む多くの形式の基本形式となります。

    これは、静的サイトジェネレータ、README、その他のドキュメントシステムで使用される一般的な形式に対応しています。詳しくは Locale::Po4a::Text(3pm) をご覧ください。

xmlとXHTML（恐らく成熟した構文解析器）
    XML フォーマットは多くのドキュメントフォーマットの基礎になっています。

    現在、DocBook の DTD （詳細は Locale::Po4a::Docbook(3pm) を参照）とXHTMLがpo4aでは対応されています。

BibTeX（恐らく成熟した構文解析器）
    BibTeXは、LaTeXと共に出典リスト（参考文献一覧）を整えるために使用されています。

    詳しくはLocale::Po4a::BibTexをご覧ください。

DocBook（恐らく成熟した構文解析器）
    XMLを基にしたマークアップ言語で、文書を記述するのに意味的なタグを用います。

    詳しくはLocale::Po4a:Docbookをご覧ください。

Guide XML（恐らく成熟した構文解析器）
    XMLの文書形式の1つ。このモジュールは、少なくとも2016年3月（Wayback Machineに基づく）までは、Gentoo Linuxドキュメントの翻訳のサポートと保守を支援するために特別に開発されました。Gentooはその後、DevBook XML形式に移行しました。

    詳しくはLocale::Po4a:Guideをご覧ください。

Wml（恐らく成熟した構文解析器）
    Web Markup Languageの略であって、携帯電話で使われているWAPとしてのWMLを混同しないようにしてください。このモジュールはXHTMLモジュールに依存しており、XHTMLモジュール自体もXMLモジュールに依存しています。

    より詳しくは Locale::Po4a::Wmlを見てください。

Yaml（恐らく成熟した構文解析器）
    JSONの厳密なスーパーセットです。YAMLはシステムやプロジェクトの設定としてよく使われます。YAMLはRed HatのAnsibleの中核を成しています。

    より詳しくは Locale::Po4a::Yaml を見てください。

RubyDoc（恐らく成熟した構文解析器）
    Ruby Document (RD) 形式は、2002年にRDocに変換されるまでは、RubyおよびRubyプロジェクトの既定の文書形式でした。ただし、日本語版のRubyリファレンスマニュアルは今でもRDを使用しているようです。

    より詳しくは Locale::Po4a::RubyDocを見てください。

Halibut（恐らく実験的な構文解析器）
    PuTTYの開発者であるSimon Tathamが開発した、TeX、debiandoc-sgml、TeXinfoなどに似た要素を持つ文書作成システムです。

    詳しくはLocale::Po4a:Halibutをご覧ください。

Ini（恐らく実験的な構文解析器）
    MS-DOS によって普及した設定ファイル形式。

    詳しくはLocale::Po4a::Iniをご覧ください。

texinfo（極めて実験的な構文解析器）
    GNU のドキュメントはすべてこの形式で書かれています（公式 GNU プロジェクトになる必要条件の一つでさえあります）。po4a のLocale::Po4a::Texinfo(3pm) 対応は始まったばかりです。バグ報告や機能の要望をお願いします。

gemtext（極めて実験的な構文解析器）
    Geminiプロトコル固有の素のテキスト形式です。拡張子 ".gmi" が一般に使われます。po4aにおけるこのモジュールの対応はまだ始まったばかりです。何か気付いたことがあれば不具合を報告したり機能の提案をお願いします。

org（極めて実験的な構文解析器）
    Orgモードで使われる文書形式です。po4aにおけるこのモジュールの対応はまだ始まったばかりです。何か気付いたことがあれば不具合を報告したり機能の提案をお願いします。

vimhelp（極めて実験的な構文解析器）
    Vimのヘルプファイル（とサードパーティのプラグインの文書）で使われる形式です。po4aにおけるこのモジュールの対応はまだ始まったばかりです。何か気づいたことがあれば、不具合を報告したり、機能の提案をしたりしてください。

simplepod（極めて実験的な構文解析器）
    前述した pod と似ていますが、こちらは構文解析器に新しい Pod::Simple を適用しています。新しく作られたものなので、不具合があることでしょう。何か変な挙動に気付いたら、どうぞお知らせください。最終的にこのモジュールは pod を置き換えます。

他に対応している形式
    po4a は、2.4以上のLinuxカーネル のコンパイルオプションのドキュメント (Locale::Po4a::KernelHelp) や、dia ツールで使用する図 (Locale::Po4a::Dia) といった、もっと稀だったり特殊な形式もサポートしています。新しい形式を追加するのは非常に簡単で、目標の形式の構文解析器を追加するのが主な作業内容となっています。この詳細情報は Locale::Po4a::TransTractor(3pm) を参照してください。

サポート外のフォーマット
    残念ながら、po4aはまだいくつかの文書形式に対応していません。それらの多くは po4a で簡単に対応できるはずです。例えば、パッケージの説明（debやrpm）、パッケージのインストールスクリプトの質問、パッケージの変更履歴、ゲームシナリオや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がpoを更新]"といった角括弧の遷移はpo4aツールの実行を表しており、"{master.docの更新}"のような中括弧の遷移はプロジェクトのファイルの手作業での変更を表します。

                                   master.doc
                                       |
                                       V
     +<-----<----+<-----<-----<--------+------->-------->-------+
     :           |                     |                        :
   {翻訳}         |             {master.docの更新}                :
     :           |                     |                        :
   XX.doc        |                     V                        V
 （省略可能）      |                 master.doc ->-------->------>+
     :           |                   （新）                      |
     V           V                     |                        |
  [po4a-gettextize]   doc.XX.po -->+   |                        |
          |            （旧）       |   |                        |
          |              ^         V   V                        |
          |              |    [po4aがpoを更新]                   |
          V              |           |                          V
   translation.pot       ^           V                          |
          |              |        doc.XX.po                     |
          |              |       （ファジー）                     |
        {翻訳}            |           |                          |
          |              ^           V                          V
          |              |      {手作業の編集}                    |
          |              |           |                          |
          V              |           V                          V
      doc.XX.po --->---->+<---<-- doc.XX.po    addendum     master.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 の Lokalize や poedit などの特定のエディタ、あるいは weblate や pootle などのオンライン現地語化プラットフォームを使用して行うことができます。翻訳結果は、1言語につき1つのPOファイルの集まりです。詳細は gettext のドキュメントを参照してください。

図の下部は、 po4a が元の文書である master.docと翻訳者によって更新された翻訳カタログである doc.XX.poから翻訳された文書のソースを作成する様子を示しています。文書の構造は再利用され、元の内容は翻訳された対応部分に置き換えられます。もし補遺があれば、それを使って翻訳に追加のテキストを差し込めます。これは、最終的な文書に翻訳者の名前を追加するためによく使用されます。詳しくは以下をご覧ください。

コマンドで呼び出すと、po4aは翻訳ファイルと翻訳された文書ファイルの両方を自動的に更新します。

  新規に翻訳のプロジェクトを始めるには
一から始める場合、po4aの構成ファイルを書きさえすれば準備が整います。欠けているファイルについては関係する雛形が作成され、貢献者が母語でプロジェクトの翻訳をできるようにします。速習のための入門や全ての詳細についてはpo4a(1)をあたってください。

既存の翻訳がある場合、例えば手作業で翻訳された文書ファイルがある場合、po4a-gettextizeを使ってpo4aの作業工程に内容を組み入れることができます。この作業は（このツールのmanページに記述されているように）少し面倒ですが、プロジェクトをpo4aの作業工程に変換してしまえば、全てが自動的に更新されるようになります。

  翻訳と文書を更新する
準備が整ったら、po4aを呼び出すだけで翻訳のPOファイルと翻訳文書の両方が更新されます。 po4a に "--no-translations" を渡して翻訳を更新しない（したがってPOファイルのみが更新される）ようにしたり、"--no-update"を渡してPOファイルを更新しない（したがって翻訳のみが更新される）ようにしたりできます。これはざっくり言うとそれぞれ po4a-updatepo と po4a-translate スクリプトに対応しており、これらは現在非推奨です（後述のFAQの「なぜ個々のスクリプトが非推奨なのか」を参照）。

  補遺を使って翻訳に追加のテキストを入れる
ファイルを手動で翻訳する管理をしていれば、翻訳文に新しいテキストを追加することは、長い目で見れば恐らくどんな管理方法よりも簡単でしょう :)。こうしたことは翻訳された文書に、元の文書のどの内容にも対応しない追加部分を入れたい場合に起こります。古典的な使用例としては、翻訳チームに謝辞を述べたり、翻訳特有の問題を報告する方法を示したりすることがあります。

po4a では addendum ファイルを指定しなければなりませんが、これは概念的に処理後に現地化された文書に適用されるパッチと見なすことができます。各補遺は別々のファイルとして与えられていなければなりませんが、その形式は従来のパッチとは全く異なっています。最初の行は header line で、補遺の挿入位置を定義し（残念ながら不可解な構文で……。後述）、ファイルの残りの部分は決められた位置にそのまま追加されます。

ヘッダ行は、文字列 PO4A-HEADER:で始まり、key=valueフィールドのリストをセミコロンで区切ったものが続く必要があります。

例えば以下のヘッダは翻訳の一番最後に置かなければならない補遺を宣言しています。

 PO4A-HEADER: mode=eof

文書の途中に追加の内容を入れたい場合、話はより複雑になります。以下のヘッダは補遺を "About this document"という文字列を含むXMLのsectionの後に置かなければならないと宣言しています。

 PO4A-HEADER: position=About this document; 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=About this document; mode=after; beginboundary=<section>

ここでは、po4a は翻訳の中の "About this document" に照合する行の後にある "<section>" に照合する最初の行を探し、beginboundary、つまり次の節の始まりを示す境界を与えたので、その行の 前に 補遺を追加するのです。ですから、このヘッダ行は、"About this document"を含む節の後に補遺を置き、"<section>"タグを含む行から節が始まるとpo4aに指示する必要があるとしています。これは前の例と同じです。なぜならここで本当にしたいことは、この補遺を "</section> > の後か "<section> > の前に追加することだからです。""

挿入 l<mode>を値 "before"に設定することもでき、これは似た意味を持ちます。 "mode=before"と "endboundary"を組み合わせると、照合した境界のちょうど 後ろに補遺を置き、最後の潜在的な境界線が "position"の前に来ます。"mode=before"と "beginboundary"を組み合わせると照合した境界のちょうど 前に 補遺が置かれ、最後の潜在的な境界線が "position"の前に来ます。

  モード  | 境界の種類     |     使われる境界        | 境界と比較する挿入地点
 ======== |=============== |======================== |=======================
 'before' | 'endboundary'  | 'position'の直前        | 選択された境界の直後
 'before' |'beginboundary' | 'position'の直前        | 選択された境界の直前
 'after'  | 'endboundary'  | 'position'の直後        | 選択された境界の直後
 'after'  |'beginboundary' | 'position'の直後        | 選択された境界の直前
 'eof'    |   （なし）     |  n/a                    | ファイル終端

補遺についてのヒントとコツ

•   これらが正規表現であることを覚えておいてください。例えば ".fi"で終わるnroffの節の終端に照合させたいときは、endboundary として ".fi" を使用しないでください。明らかに想定していない "the[ fi]le" にも照合してしまいます。この場合の正しい endboundary は "^\.fi$" です。

•   "position"と境界の内容の中ではまさに空白が要です。ですから、次の2つの行は異なります。2番目の行は、翻訳された文書に充分な後続の空白がある場合にのみ検出されます。

     PO4A-HEADER: position=About this document; mode=after; beginboundary=<section>
     PO4A-HEADER: position=About this document ; mode=after; beginboundary=<section>

•   この文脈検索は、翻訳文書の各行に対して大まかに操作しているように思われますが、実際には翻訳文書の内部データ文字列に対して操作しています。この内部データ文字列は、複数行を含む段落にまたがるテキストでやXMLタグそのものになりえます。補遺の正確な挿入点は、内部データ文字列の前か後でなければならず、内部データ文字列の中にあることはできません。

•   po4a に "-vv" 引数を渡すと、どのように補遺が翻訳に追加されるかを理解することができます。また、補遺が適用されないときの実際の内部データ文字列を見るために、 po4a をデバッグモードで実行することも役に立つかもしれません。

補遺の例

•   以下の nroff 節の後に何か追加したいとします:

      .SH "AUTHORS"

    mode=afterを設定して2工程の手法を選択します。それから position 引数の正規表現で AUTHORS の後の行に検索を絞り込みます。次に、beginboundary 引数の正規表現で、次の節の先頭（つまり^\.SH）に照合させます。つまり次のようになります。

     PO4A-HEADER:mode=after;position=AUTHORS;beginboundary=\.SH

•   与えられた行の直後に何かを追加したければ、この行に照合する position と mode=after を使い、任意の行に照合するbeginboundaryを与えてください。

     PO4A-HEADER:mode=after;position=Copyright Big Dude, 2004;beginboundary=^

•   ドキュメントの最後に何か追加したい場合、position はドキュメントの任意の行 (しかし 1 行のみ。ユニークでないと po4a は処理しません) にマッチするように与え、endboundary は何もマッチしないように与えます。"EOF" のような単純な文字列を使用せず、ドキュメントにたまたま含まれているものを使用してください。

     PO4A-HEADER:mode=after;position=About this document;beginboundary=FakePo4aBoundary

もっと詳細な例

オリジナルドキュメント (POD フォーマット):

 |=head1 NAME
 |
 |dummy - a dummy program
 |
 |=head1 AUTHOR
 |
 |me

そして、以下の補遺は確実に（フランス語で）翻訳者についての節をファイルの最後に追加されます（フランス語の "TRADUCTEUR" は "TRANSLATOR"、"moi" は "me" の意味です）。

 |PO4A-HEADER:mode=after;position=AUTEUR;beginboundary=^=head
 |
 |=head1 TRADUCTEUR
 |
 |moi
 |

AUTHOR の前に追加内容を追加するには、以下のヘッダを使用してください:

 PO4A-HEADER:mode=after;position=NOM;beginboundary=^=head1

これは、"NAME" 節（フランス語では "NOM"と翻訳される）の後にある beginboundary "/^=head1/" に照合した次の行が作者を宣言しているからうまくいくのです。そのため、両方の節の間に追加内容が挿入されます。なお他の節がNAMEとAUTHORの節に後で追加される場合、po4aは補遺を新しい節の前に置くため間違ったことになります。

これを防ぐために mode=before を使って同じことを達成できます：

 PO4A-HEADER:mode=before;position=^=head1 AUTEUR

どのように動作しますか?
この章ではpo4aの内部の全体像を手短かに説明します。こちらをお読みいただければ、po4aを保守し改善していく手助けをするにあたってより自信がつくかもしれません。また、なぜ思ったように動作しないか、どのように問題を解決すればいいかを理解する助けになるかもしれません。

  TransTractorとプロジェクトのアーキテクチャ
po4aプロジェクトの核心にはLocale::Po4a::TransTractor(3pm)クラスがあり、全てのpo4a構文解析器に共通する先祖となっています。この奇妙な名前は文書の翻訳と文字列の抽出を同時に行うところから付けられています。

もっと形式張っていうと、入力として翻訳する文書と翻訳が入っているPOファイルを取り、結果を別のPOファイル（入力文書から翻訳可能な文字列を抽出した結果）と翻訳済み文書（入力したファイルと同じ構造ですが、翻訳可能な文字列は入力POファイルの内容で置換されているファイル）の2つに分けて出力します。以下に図示します。

   入力ドキュメント-\                             /---> 出力ドキュメント
                     \      TransTractor::       /         (翻訳済み)
                      +-->--   parse()  --------+
                     /                           \
   入力 PO ---------/                             \---> 出力 PO
                                                         (抽出済み)

この小さな骨子は、po4aアーキテクチャの中核の全てを表しています。両方の入力を与え、出力のPOを無視すると、po4a-translateになります。代えて出力文書を無視するとpo4a-updatepoになります。po4aは最初にTransTractorを使って最新の出力POTファイルを得て、msgmerge -Uを呼び出してディスク上の翻訳POファイルを更新します。それからこれらの更新されたPOファイルで2回目のTransTractorを構築し、出力文書を更新します。要は、po4aは必要な更新について1つの構成ファイルを使って一括で行う解決策を提供するわけです。

po4a-gettextizeも2つのTransTractorを使いますが、違ったやり方をします。1つ目のTransTractorを言語毎に構築し、それから元の文書のmsgidはmsgidとして、翻訳文書のmsgidはmsgstrとして使い、新しいPOファイルを構築します。po4a-gettextize(1)に記載されているように、このようにして照合された文字列が実際に照合できているかについては注意が必要です。

  形式に固有の構文解析器
全てのpo4aの形式の構文解析器はTransTractorを土台に実装されています。Text、Markdown、AsciiDocといったとても単純なものがあります。これらはTransTractor::shiftline()を使って1行ずつ読み込み、段落の内容か何かを積み上げていきます。文字列が完全に構文解析できたら、構文解析器はTransTractor::translate()を使って（１）この文字列を出力POファイルに追加し（２）入力POファイルから翻訳を取得します。それから構文解析器はTransTractor::pushline()を使って出力ファイルに結果を押し込みます。

その他の構文解析器はもっと複雑ですが、それは入力文書を解析するために外部の構文解析器に依存しているためです。Xml、HTML、SGML、Podの構文解析器はSAX構文解析器を土台に構築されています。これらの解析器は「以下の内容の新規題名を見付けました」というようなイベントのコールバックを宣言し、 TransTractor::translate() と TransTractor::pushline() を使って入力の内容に沿って出力文書と出力POTファイルを更新します。Yaml構文解析器はより単純ですが毛色が違います。YAML::Tiny構文解析器により生成されるデータ構造を直列化するのです。これがpo4aのYamlモジュールでは参照行の宣言ができないことの理由です。入力ファイルの各文字列の位置は構文解析器で保持されず、文字列の場所として与えられるのは「$filename:1」のみなのです。SAXに基づく構文解析は大域変数とその他の仕掛けを使ってファイル名と参照のための行番号を保存します。

ファイルの符号化方式とBOMの印により引き起こされる問題があります。単純な構文解析器では TransTractor::read() （入力文書の行を取得するために内部的に使用されます）で対処されるためこの問題を無視できます。しかし外部の構文解析器に依存するモジュールでは全てのファイルがPerlIOデコード層で適切に読み込まれるようにしなくてはなりません。最も簡単なのは、外部の構文解析器にファイルを自分で開いてファイルハンドルないし完全な文字列を与えることです。一例については Pod::read() と Pod::parse() を見てください。TransTractorにより読まれた内容は無視されますが、外部の構文解析器に新しいファイルハンドルが渡されています。重要な部分は "<:encoding($charset)" モードで、これが open() perl関数に渡されます。

  Poオブジェクト
Locale::Po4a::Po(3pm)クラスはPOとPOTファイルの読み込みと活用を担います。基本的に、ファイルを読み、項目を追加し、 gettext() メソッドで翻訳を取得し、POをファイルに書き込めます。POTファイルにPOファイルを統合したりファイルを健勝したりするより発展的な機能についてはそれぞれ msgmerge と msgfmt に説明を委ねます。

  po4aに貢献する
過去に全くオープンソースプロジェクトに貢献したことがなくても歓迎します。喜んで手助けしたりメンタリングします。po4aは今日も利用者により最高の保守がなされています。人手は足りていませんが、ドキュメントと自動的なテストを改善してプロジェクトへの貢献に自信が持てるようにすることで、プロジェクトへの貢献を迎え入れられるように努めています。詳細についてはCONTRIBUTING.mdファイルを参照してください。

po4aを使っているオープンソースプロジェクト
以下はプロダクション環境でドキュメント用にpo4aを使っているプロジェクトのほんの一部の一覧です。もし一覧へのご自身のプロジェクトの追加をご希望でしたらEメール（またはマージリクエスト）をお寄せください。

•   adduser (man): ユーザーとグループの管理ツール。

•   apt (man, docbook): Debianのパッケージ管理。

•   aptitude (docbook, svg): Debian用の端末ベースのパッケージ管理

•   F-Droidのwebサイト <https://gitlab.com/fdroid/fdroid-website> (markdown): Androidプラットフォーム用のインストール可能なFOSS（自由でオープンソースなソフトウェア）の目録。

•   git <https://github.com/jnavila/git-manpages-l10n> (asciidoc): ソースコードの変更を追跡するための分散バージョン管理システム。

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

    このプロジェクトは多くのパッケージと別の言語に翻訳するインフラを提供しており、複数の主要なディストリビューション（Arch Linux、Debianとその派生、Fedora）への統合の準備が整っています。

•   Stellarium <https://github.com/Stellarium/stellarium> (HTML): 手元のコンピュータ用の自由でオープンソースなプラネタリウム。po4aは空の文化の説明を翻訳するために使われています。

•   Jamulus <https://jamulus.io/> (markdown, yaml, HTML): 実時間でオンラインのジャズを演奏するためのFOSSアプリケーションです。webサイトのドキュメントはpo4aを使って複数言語で保守されています。

•   その他未整理の項目： <https://gitlab.com/fdroid/fdroid-website/> <https://github.com/fsfe/reuse-docs/pull/61>

FAQ

  po4aはどう発音するのですか？
個人的には pouah <https://en.wiktionary.org/wiki/pouah> と発声しており、これは yuck の意味のフランス語の擬音語です :)。ヘンなユーモアのセンスかもしれません :)

  なぜ個別のスクリプトが非推奨となったのか
po4a-updatepo と po4a-translate はpo4aが代わることにより非推奨となりました。その理由はpo4aがこれらのスクリプトをそのまま置き換えられる一方、コードの重複がかなりあるためです。個別のスクリプトは150行のコードですがpo4aプログラムは1200行に及びます。故にこれらの個別のスクリプトは共通する内部の処理に加えて沢山のことをしています。コードの重複は両方のバージョンに於いて不具合に繋がっており、2つともを修正する必要が生じます。そのような重複の例はDebianの#1022216やGitHubの#442です。これは全く同じ修正ですが、かつは po4a でかつは po4a-updatepo にありました。

長い目で見たとき、個別のスクリプトを管理から外し、この1つのバージョンのみを保守したいと考えています。確かなことは個別のスクリプトは最早改善が行われないということで、po4aだけに新機能が加えられます。つまり、取り急ぎの非推奨というものはありません。少なくとも2030年まではできる限り個別のスクリプトを保持しておく計画でいます。もしプロジェクトでまだ po4a-updatepo と po4a-translate を使っているのであれば、問題が起こるかもしれません。

コードの改修によりコードの重複がゼロに低減されれば、どこかの時点でこれらのスクリプトの非推奨を取り消す可能性もあります。もし思い付いたこと（欲を言えばパッチ）があればご協力を歓迎します。

  gettext を使ったドキュメント翻訳ツールは他に何がありますか?
いくつかあります。以下は恐らく不完全な一覧で、もっと多くのツールが現れてきています。

poxml
    KDE の人たちが DocBook XML を扱うために開発したツールです。知る限りでは、ドキュメントから PO ファイルへ翻訳する文字列を抽出し、翻訳後に注入する初めてのプログラムです。

    これは XML のみ、さらに特定の DTD のみを扱えます。リストが一つの大きな msgid になってしまうため、私はリストの扱いにかなり不満があります。リストが大きくなると、ひとかたまりの構造をつかみにくくなります。

po-debiandoc
    Denis Barbier によって作られたこのプログラムは、多少の異論があるとはいえ po4a SGML モジュールの先駆けといえます。名前の通り、少々非推奨の DTD である DebianDoc DTD のみを扱います。

xml2po.py
    2004年からGIMPドキュメントチームに使われています。名前から推測されるようにXMLファイルのみ対応であり、特有のMakefileの設定が必要ですが、かなり良く動作します。

Sphinx
    Sphinx文書プロジェクトも翻訳を管理するためにgettextをふんだんに使っています。翻訳過程の全体を管理する恐らく唯一のツールではありますが、不運にもreSTやMarkdownといったいくつかのテキスト形式でのみ動作します。

以上に対する po4a の主な利点は、簡単に内容を追加できること (欠点かもしれませんが) と、gettext 化が簡単なことです。

  gettext ベースアプローチの利点まとめ

•   翻訳はオリジナルと一緒に保存されません。その翻訳が古くなった場合、検出することが可能となります。

•   翻訳は互いに別々のファイルに格納され、異なる言語の翻訳者がパッチの提供やエンコードレベルの干渉を、互いに受けないようにします。

•   内部的には gettext をベースにしています (が、po4a は非常にシンプルなインターフェースを提供するので、内部で使用していることを理解する必要はありません)。そんなところで車輪の再発明をする必要はなく、これは広く用いられているので、バグに悩まされることはないと考えていいでしょう。

•   エンドユーザにとっては何も変化ありません (願わくば翻訳がよりよく保守されるようになる、という事実は置いておいて)。出来上がりの配布されるファイルはまったく同じです。

•   翻訳者は、新しいファイルの文法を学習する必要はなく、好みの PO ファイルエディタ (Emacs の PO mode や、Lokalize、Gtranslator など) でうまく動作します。

•   gettext は、完了しているもの (t)、レビューや更新が必要なもの (f)、そしてまだ翻訳作業が残っているもの (u) について、統計を取得する簡単な方法を提供しています。以下のアドレスでいくつか例を見つけることができます:

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

しかし、すべて問題ないわけではありません。このアプローチには対処するべき欠点もあります。

•   補遺は一見してどこか奇妙です。

•   翻訳したテキストを、段落をここで分割する、二つの段落を片方に結合するといった、あなたの好みに合わせることができません。しかし、オリジナルに問題があるのであれば、とりあえずバグとして報告すべきだ、という意見もあります。

•   簡単なインターフェースですが、学習が必要な新しいツールのままです。

    私の夢の一つは Gtranslator や Lokalize に何らかの形で統合することです。文書ファイルを開くと文字列を自動的に抽出し、翻訳されたファイルとPOファイルをディスクに書き込みます。MS Word (TM) モジュール (少なくとも RTF) でこれができれば、プロの翻訳家もこれを使ってくれるかも知れません。

関連項目

•   全てが1つに集まっている使うべきツールである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::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)

訳者
 倉澤 望 <nabetaro@debian.or.jp>
 Debian JP Documentation ML <debian-doc@debian.or.jp>

POD ERRORS
Hey! The above document had some coding errors, which are explained below:

Around line 317:
    Unterminated C< C< ... > > sequence