Provided by: po4a_0.41-1ubuntu1_all bug

po4a の使い方は?
       この章は、処理全体を理解していただけるように、ユーザの質問に答える形の
       リファレンスマニュアルの一種です。po4a をどのように使用するかを紹介
       し、特定のツールのドキュメントに導入する方法を提供します。

   概要図
       以下の図は po4a を用いたドキュメント翻訳過程の概要です。複雑になってし
       まいましたが、おじけづかないでください。処理の  を表そうとして、こ
       のようになってしまいました。いったんプロジェクトを po4a に変換すると図
       の右の部分のみが関係します。

       翻訳する文書の例として master.doc をとり、対応する翻訳済み文書を
       translation.doc とします。拡張子は、フォーマットにより .pod, .xml,
       .sgml となります。図の各部の詳細は、次節で説明します。

                                          master.doc
                                              |
                                              V
            +<-----<----+<-----<-----<--------+------->-------->-------+
            :           |                     |                        :
          {翻訳}        |            { master.doc の更新 }             :
            :           |                     |                        :
          XX.doc        |                     V                        V
       (オプション)     |                 master.doc ->-------->------>+
            :           |                    (新)                      |
            V           V                     |                        |
         [po4a-gettextize]   doc.XX.po--->+   |                        |
                 |             (旧)       |   |                        |
                 |              ^         V   V                        |
                 |              |     [po4a-updatepo]                  |
                 V              |           |                          V
          translation.pot       ^           V                          |
                 |              |         doc.XX.po                    |
                 |              |         (fuzzy)                      |
              { 翻訳 }          |           |                          |
                 |              ^           V                          V
                 |              |       {手動編集}                     |
                 |              |           |                          |
                 V              |           V                          V
             doc.XX.po --->---->+<---<---- doc.XX.po   addendum     master.doc
               (初期)                      (最新化)  (オプション)    (最新化)
                 :                          |            |             |
                 :                          V            |             |
                 +----->----->----->------> +            |             |
                                            |            |             |
                                            V            V             V
                                            +------>-----+------<------+
                                                         |
                                                         V
                                                  [po4a-translate]
                                                         |
                                                         V
                                                       XX.doc
                                                      (最新化)

       左側で、po4a を使用していない翻訳のこのシステムへの変換を表します。右側
       の先頭でオリジナルの作者の行動 (ドキュメントの更新) を描いています。右
       側の中盤で po4a が自動で行う動作を描いています。新しい要素を抽出し、既
       存の翻訳と比較しています。変更のなかった部分には以前の翻訳を使いま
       す。一部変更がある部分には、以前の翻訳を使いますが、翻訳を更新する必要
       があるというマークが付きます。図の下部は、整形済みドキュメントがどのよ
       うに組み立てられるかを示しています。

       実際には、翻訳者として、唯一手で操作しなければならないのは、{手動編集}
       と印が付いている部分です。あぁ申し訳ありません。po4a は翻訳の助けにはな
       りますが、翻訳をしてくれるわけではありません……

   新規翻訳を始めるには?
       この節では、po4a で新しく翻訳を始めるのに必要な手順を説明します。既存プ
       ロジェクトをこのシステムに変換する方法は、関連セクションで詳しく取り扱
       います。

       po4a を用いて新しく翻訳を始めるには、以下の手順を行う必要があります。

       - オリジナルの <master.doc> ドキュメントから、翻訳するテキストを新しい
         翻訳テンプレート <translation.pot> ファイル (gettext フォーマット) に
         抽出します。これには po4a-gettextize プログラムを以下のように使いま
         す。

           $ po4a-gettextize -f <format> -m <master.doc> -p <translation.pot>

         <format> は、通常 master.doc ドキュメントで使用しているフォーマットで
         す。おそらく、translation.pot に出力されます。オプションについての詳
         細は po4a-gettextize(1) をご覧ください。

       - 翻訳すべき箇所を、実際に翻訳してください。これには POT ファイルの名前
         を、例えば doc.XX.po (XX は翻訳する ISO639 の言語コード。例: フランス
         語は fr) と変更し、そのファイルを編集します。プログラムのメッセージに
         対する翻訳と混同しないように、XX.po と言う名前を付けないようにするの
         が良い方法ですが、これはあなた次第です。PO ファイルのヘッダの編集を忘
         れないでください。これが重要です。

         実際の翻訳は、Emacs の PO mode や Lokalize (KDE 由来)、Gtranslator
         (GNOME 由来)、またはお好みのプログラムを用いて行えます。またこのため
         のモードがなくても、古き良き vi で当初の目的を達成できるでしょう。

         これについてもっと学ぶのなら、gettext-doc パッケージにある gettext の
         ドキュメントを決定版として参照する必要があります。

   翻訳をドキュメントファイルに適用するには?
       翻訳が終わったら、翻訳したドキュメントを、オリジナルのものと併せてユー
       ザに提供しましょう。これには以下のように po4a-translate(1) プログラムを
       使用してください (XX は言語コードです)。

         $ po4a-translate -f <format> -m <master.doc> -p <doc.XX.po> -l <XX.doc>

       先ほどと同様に、<format> は master.doc ドキュメントで使用しているフォー
       マットです。しかし今度は、-p フラグで指定する PO ファイルが入力部にあり
       ます。これはあなたが訳したものです。XX.doc に出力します。

       詳細は po4a-translate(1) をご覧ください。

   po4a 翻訳を更新するには?
       オリジナルの master.doc ファイルが変更された時に訳を更新するには、
       po4a-updatepo(1) を以下のように使用します。

         $ po4a-updatepo -f <format> -m <new_master.doc> -p <old_doc.XX.po>

       (詳細は po4a-updatepo(1) をご覧ください)

       当然、ドキュメントの新しい段落が、この操作で魔法のように PO ファイルで
       翻訳されている、ということはありません。PO ファイルを手で更新する必要が
       あります。同様に、多少変更があった段落についても、再度翻訳する必要があ
       ります。変更を見逃さないように、この修正の間、"fuzzy" マーカが付
       き、po4a-translate を使用する前にそのマーカを消さなければなりません。初
       期翻訳と同様にお好みの PO エディタを使用するのが最善です。

       未訳部や fuzzy な部分を取り除いて、PO ファイルを再度最新にしたら、前節
       で説明したように翻訳済みドキュメントファイルを生成できます。

   既存の訳を po4a にコンバートするには?
       オリジナルの master.doc ドキュメントが大きく再編成されるまでは、手で翻
       訳するのに不満はなかったでしょう。diff のようなツールがうまくいかなく
       なったから、po4a に乗り換えようとしているのだと思います。もちろん、この
       処理で既存の翻訳を失いたくはありません。ご心配なく。この場合も po4a で
       は扱えます。これを gettext 化と呼びます。

       ここでのキーは、ツールが内容のすりあわせを行えるように、訳したドキュメ
       ントとオリジナルドキュメントが同じ構造をしていることです。

       あなたがツイていれば (例えば両方のドキュメントの構造が完全に一致すると
       か)、シームレスに一瞬で完了します。そうでなければ、この手順に何故こんな
       ひどい名前が付いているのか理解するでしょう。とはいえこんなひどい作業で
       も準備しておくに越したことはありません。いずれにしろ、po4a で後々楽にな
       るために支払う価値があると思ってください。ありがたいことに一回だけやれ
       ばいいのです。

       このことは、どれだけ強調しても、しすぎということはないでしょう。処理を
       簡単にするのに、翻訳の元にした完全なバージョンを見つけるのが重要で
       す。最高の状況は翻訳に使用した VCS のリビジョンを控えておき、翻訳の中で
       それを変更していないことです。この場合、それを利用できます。

       更新されたオリジナルテキストを古い翻訳と一緒に使用するのは、うまくいき
       ません。そういったこともできますが、本当に大変で、できれば避けた方がい
       いでしょう。事実上、もう一度オリジナルテキストを見つけられないなら、一
       番いいのはあなたのために gettext 化してくれる人を見つけることでしょ
       う。(あ、いや、私じゃないですよ ;)

       おそらくドラマチックすぎるでしょうが、何か問題があるとしても、すべてを
       もう一度翻訳し直すよりは速いと思います。既存の Perl ドキュメントフラン
       ス語訳を gettext 化するのに、問題も ありました が、1 日でできました。こ
       れは 2MB のテキストで、新規に翻訳するには数ヶ月を要したでしょう。

       ではまず、手順の基本を説明します。それから何か問題があれば、戻ってきて
       ヒントを示したいと思います。理解しやすいように、もう一度上記の例を使用
       しましょう。

       翻訳した XX.doc に対応する、古い master.doc をもう一度用意する
       と、translation.pot ファイルを手で訳さなくても、PO ファイル doc.XX.po
       を、直接 gettext 化できます。

        $ po4a-gettextize -f <format> -m <old_master.doc> -l <XX.doc> -p <doc.XX.po>

       ツイているならこれで完了です。古い翻訳を po4a に変換し、すぐに更新タス
       クを行えます。数節前に説明した、最新のオリジナルドキュメントと PO ファ
       イルの同期を取る手順に従い、翻訳を更新してください。

       うまくいっているように見えても、この処理に誤りの入り込む余地があること
       に注意してください。ポイントは po4a が、オリジナルと翻訳が一致している
       かどうかを理解できないということです。この処理の結果、すべての文字列に
       "fuzzy" マークが付いてしまうのはこういうわけです。マーカを削除する前
       に、注意してチェックする必要があります。

       しばしば、ドキュメント構造が完全に一致する、というわけには行きませ
       ん。この場合ゲームの内容は、構造を一致させるのにファイルを編集する、と
       いうことになります。

       後にある gettext: どのように動作しますか?  節を読むと参考になると思
       います。内部処理を理解することは、この作業の助けになりま
       す。po4a-gettextize の利点は、何か問題が発生すると、詳しく教えてくれる
       ことです。まず、ドキュメントに構造上の食い違いがある場合、その箇所を指
       摘します。これで一致しない文字列や、テキスト中の箇所、それらの型が分か
       ります。さらに、そこまでで生成した PO ファイル
       は、gettextization.failed.po に書き出してあります。

       -   翻訳者名や、翻訳に貢献した人々への謝辞といった、翻訳で追加した箇所
           を取り除いてください。次節で説明する追加内容に後で改めて追加できま
           す。

       -   遠慮なくオリジナルと翻訳の両方を編集してください。最も重要なのは PO
           ファイルを手に入れることです。これを後から更新できます。双方
           gettext 化してしまえば、楽になりますので、翻訳の編集をすると良いと
           いわれています。

       -   必要であれば、翻訳されていない部分を、オリジナルから削ってくださ
           い。後でドキュメントを PO と同期を取るときに自分自身で復元します。

       -   構造を少しだけ変えた (2 つの段落をまとめたとか、1 つの段落を分けた
           とか)のなら、その変更を元に戻してください。オリジナルに問題があるな
           ら、オリジナルの作者に連絡するべきでしょう。コミュニティの一部だけ
           のために翻訳で修正していたとして、その上で po4a を使うのは無理です
           ;)

       -   時には、段落の内容は一致するけれども、型があわない場合がありま
           す。その修正法はフォーマットに依存します。POD や man では、片方の行
           は空白で始まっているのに、もう片方はそうではない、ということが実際
           にあります。こういったフォーマットでは、そのような段落は改行でき
           ず、別の型となります。そのようなときは空白を削除してください。おそ
           らくタグ名のタイプミスでしょう。

           POD では、分割行に空白が入っていたり、=item 行や item の内容の前に
           空行がない場合、2 つの段落を 1 つにまとめてしまいます。

       -   時々、ファイル間で同期が取れておらず、翻訳が間違った段落に割り当て
           られることがあります。これはファイルに以前から問題があったことを示
           しています。gettextization.failed.po をチェックして、同期が取れない
           箇所を探し、修正してください。

       -   時々、po4a がオリジナルや翻訳のテキスト部分を、食べてしまったと強く
           思うかもしれません。gettextization.failed.po に緩く一致した箇所
           が、どちらも記録されます。その後、前後の正しいものと一致するかを試
           して gettext 化は失敗し、正しいものが見えなくなります。初めて私の身
           に起きたとき、私がしたように、po4a を盛大に罵ってください。

           この不幸な状況は、同じ段落がドキュメント中で繰り返されているときに
           起こります。この場合、PO ファイルに新しいエントリは追加されません
           が、既存のエントリに参照が追加されます。

           そのため、オリジナルに同じ段落が 2 度でてきても、翻訳が同じように訳
           されていない場合、オリジナルが消えてしまったと感じることになりま
           す。新しい翻訳を単に消してください。その翻訳の方が質が良くて、はじ
           めの翻訳の方を消すつもりなら、はじめの翻訳のあったところに 2 番目の
           翻訳を置き、元のところから削除してください。

           反対に、2 つの似て非なる段落が、全く同じように翻訳されていると、翻
           訳した段落が見えなくなったと感じることでしょう。その場合は、無駄な
           文字列をオリジナルの段落に追加すると解決します ("I'm different" な
           ど)。これは同期中に見えなくなりますが、気にしないでください。テキス
           トが十分短ければ、gettext は翻訳と既存のテキストをマッチしま
           す。(fuzzy にしますが、gettext 化した後は、すべての文字列が fuzzy
           になるので気にすることはありません)

       うまくいけば、以上の tips は gettext 化作業を助け、大事な PO ファイルを
       もたらすでしょう。ファイルの同期や、翻訳を始める準備ができています。大
       きなテキストの場合、最初の同期が長時間にわたる場合があることに注意して
       ください。

       例えば、初めてフランス語版 Perl ドキュメント (5.5 MB の PO ファイル) に
       po4a-updatepo を実行したとき、1GHz G5 コンピュータでまるまる 2 日かかり
       ました。ええ、48 時間です。しかしその後は、私の古いノートパソコンで十数
       秒しかかかりません。これは初回の実行で、PO ファイルのほとんどの msgid
       が POT ファイルのものと一致しなかったからです。このため gettext
       は、もっとも近いものを探すのに、実行コストの高い文字列近接アルゴリズム
       を使わなくてはなりません。

   翻訳におまけのテキスト (翻訳者名など) を追加するには?
       gettext アプローチ故に、po4a でのテキストの追加は、単にオリジナルのもの
       に沿って新しいファイルを編集するよりも難しくなっています。しかし、いわ
       ゆる 追加内容 のおかげで追加できます。

       追加内容を、処理後のローカライズしたドキュメントに適用するパッチの類と
       して見なすとわかりやすいでしょう。通常のパッチとは非常に異なっています
       (1 行だけの文章、Perlの正規表現を埋め込み、削除できず新しいテキストの追
       加のみ) が、機能的には同じです。

       目標は、オリジナルドキュメントにない内容を、翻訳したドキュメントに追加
       できるようにすることです。よくある使用法は、翻訳自体に関する節や、貢献
       者リスト、翻訳についてのバグレポートのしかたを追加することです。

       追加内容は別個のファイルで提供されなければなりません。最初の行では、生
       成したドキュメントのどこに配置するかといったことを記述します。追加内容
       ファイルの残りは、結果のドキュメントの決まった場所へ、逐次追加されま
       す。

       ヘッダには、以下のようにかなり厳密な文法があります。PO4A-HEADER: で始め
       なければならず、セミコロン (;) 区切りの key=value フィールドが続きま
       す。空白が重要です。セミコロン (;) を値に使用できず、クォートが役に立た
       ないことに注意してください。

       また恐ろしげに聞こえますが、以下の例は、必要なヘッダ行の記述法を見つけ
       る手助けになるでしょう。議論の前提として、"About this document" 節の後
       に "About this translation" 節を追加することとします。

       以下に有効なヘッダキーを挙げます。

       position (必須)
           正規表現です。追加内容をこの正規表現でマッチした行のそばに配置しま
           す。ここではオリジナルドキュメントではなく、翻訳済みドキュメントに
           ついて説明していることに注意してください。この正規表現にマッチする
           行が複数ある (もしくはない) 場合、追加に失敗します。実際のとこ
           ろ、追加内容を間違った場所に挿入してしまうより、エラーを報告した方
           がよいでしょう。

           以下この行を position point と呼びます。追加内容を追加するポイント
           を insertion point と呼びます。この二つのポイントはお互い近くにあり
           ますが、同じではありません。例えば、新しい節を挿入する場
           合、position point を前節のタイトルとして、po4a にはその節の最後に
           挿入するよう指示するのが簡単です (position point は特定の行がマッチ
           するような正規表現で表すことを覚えておいてください)。

           position point に対する insertion point の地域化は、以下で説明する
           mode, beginboundary, endboundary の各フィールドで制御します。

           この場合、以下のようになります。

                position=<title>About this document</title>

       mode (必須)
           beforeafter という文字が入り、position point からの 追加内容の
           位置を指定します。

           新しいセクションを、マッチした箇所の次に配置したい場合、以下のよう
           にします。

                mode=after

       beginboundary (mode=after の時のみ使用。この場合必須)
       endboundary (同上)
           追加内容を後ろに続けるセクションの、最後にマッチする正規表現です。

           mode=after の場合、insertion pointposition point の後になります
           が、すぐ後ではありません! position point で始まるセクションの後ろに
           なります。なお、???boundary 引数と行の前 (ないし後) とがマッチしま
           す。どちらになるかは beginboundary ないし endboundary で決まりま
           す。

           この場合、以下のように追加して、セクションの終わりに一致するように
           指定できます。

              endboundary=</section>

           また、以下のようにして次のセクションの直前を指定できます。

              beginboundary=<section>

           どちらの場合でも、</section> の後で、<section> の前に追加内容を配置
           します。ドキュメントが再構成されても動作するので、前者の方がいいで
           しょう。

           どちらの形態もあるのは、ドキュメントフォーマットが異なるからで
           す。その中には、 (ちょうど使用した </section> のような) セクション
           の終わりを示すもの、(man のような) 明確なセクションの終わりを表さな
           いものがあります。前者の場合は、boundary に一致
           するので、insertion point はその後になります。後者の場合
           は、boundary に一致するので、insertion
           point はその前になります。

       これは分かりにくいですが、次の例はよく分かると思います。

       今まで説明したことをまとめると、SGML ドキュメントの "About this
       document" の後に "About this translation" を追加するには、以下のヘッダ
       行のどちらかを使用できます。
          PO4A-HEADER: mode=after; position=About this document; endboundary=</section>
          PO4A-HEADER: mode=after; position=About this document; beginboundary=<section>

       以下の nroff セクションの後に何か追加したいとします。
           .SH "AUTHORS"

         position はこの行にマッチし、beginboundary は次のセクションの先頭 (例
         ^\.SH) にマッチすべきでしょう。そこで、追加内容をこの position point
         の 後 で、beginboundary にマッチした先頭行の 直前 に追加します。以下
         のようになります。

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

       セクション全体を追加するのではなく、セクション内 ("Copyright Big Dude"
       の後など) に何か追加したい場合、position はこの行にマッチするように与
       え、beginboundary は任意の行にマッチするように与えます。
          PO4A-HEADER:mode=after;position=Copyright Big Dude, 2004;beginboundary=^

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

       いずれの場合にも、正規表現であることを忘れないでください。例えば、次の
       行で終わっている、nroff セクションの最後にマッチしたい場合を考えます。

         .fi

       ここでは、.fiendboundary として使用しないでください。明らかに想定し
       ていない、"the[ fi]le" にもマッチしてしまいます。正しい endboundary
       は、この場合  ^\.fi$ となります。

       追加内容が想定通りにうまく動作しない場合、-vv 引数をツールに渡してみて
       ください。追加内容を配置する際の挙動を、表示してくれます

       

       オリジナルドキュメント (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/ にマッチした次の行が作者を定義している、と
       いうことで動作します。そのため、両方のセクションの間に追加内容が挿入さ
       れます。

   一度のプログラム実行でこのすべてを行うには?
       po4a を使うことは、それぞれ 3 つ以上の引数が必要な 2 つの異なるプログラ
       ムを、ユーザが正しい順番 (po4a-updatepo のあとに po4a-translate) で実行
       しなければならないということで、少々誤る傾向にあるということがわかりま
       した。その上で、複数のフォーマットが使われているすべてのドキュメント
       を、一つだけの PO ファイルにするのは、このシステムでは難しいことでし
       た。

       この難しさを解消するために、po4a(1) プログラムは設計されました。一度こ
       のシステムに移行すれば、どこに翻訳したファイルがあるか (PO と POT)? オ
       リジナルドキュメントがどこにあるか? そのフォーマットは? 翻訳はどこに置
       くべきか?  を説明するシンプルな設定ファイルを書くことになります。

       そして、このファイルで po4a(1) を呼ぶことで、PO ファイルがオリジナルド
       キュメントに対して同期が取れており、翻訳済みドキュメントが適切に生成さ
       れることを保証できます。もちろん、このプログラムを二度呼びたくなるかも
       知れません。一度目は編集前に PO ファイルを更新するために、二度目はその
       後で、完璧に更新された翻訳済みドキュメントを得るために。しかし一つのコ
       マンドラインしか覚えておく必要はありません。

   po4a をカスタマイズするには
       po4a モジュールは、モジュールの挙動を変更するオプション (-o オプション
       で指定) があります。

       モジュールをカスタマイズしたり、新規 / 派生 / 変更モジュールを
       lib/Locale/Po4a/ に配置できます。また、PERLLIB 環境や PERL5LIB 環境で指
       定されるパスに、lib に追加することもできます。

          PERLLIB=$PWD/lib po4a --previous po4a/po4a.cfg

       注: lib ディレクトリの実際の名前は重要ではありません。

どのように動作しますか?
       この章では、保守改良を自信を持って助けていただけるよう po4a 内部の概要
       を説明します。また、何故思ったように動作しないか、どのように問題を解決
       すればいいかを理解する助けになるかもしれません。

   この大きな絵はなんですか?
       po4a のアーキテクチャはオブジェクト指向です (Perl で。きちんとしていま
       せんか?)。すべてのパーサクラス共通の派生元は、TransTractor と呼ばれてい
       ます。このヘンな名前は、ドキュメントの翻訳と文字列の抽出を同時に行うと
       ころから付けられています。

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

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

       この小さな骨状の絵は、po4a アーキテクチャのすべてのコアを表していま
       す。入力 PO や出力ドキュメントを省略すると、po4a-gettextize になりま
       す。両方の入力を行い、出力 PO を無視すると、po4a-translate になります。

       TransTractor::parse() は各モジュールで実装されている仮想関数です。どの
       ように動作するかを説明するのに、簡単なサンプルがあります。これは、先頭
       に <p> が付いた段落のリストをパースします。

         1 sub parse {
         2   PARAGRAPH: while (1) {
         3     $my ($paragraph,$pararef,$line,$lref)=("","","","");
         4     $my $first=1;
         5     while (($line,$lref)=$document->shiftline() && defined($line)) {
         6       if ($line =~ m/<p>/ && !$first--; ) {
         7         $document->unshiftline($line,$lref);
         8
         9         $paragraph =~ s/^<p>//s;
        10         $document->pushline("<p>".$document->translate($paragraph,$pararef));
        11
        12         next PARAGRAPH;
        13       } else {
        14         $paragraph .= $line;
        15         $pararef = $lref unless(length($pararef));
        16       }
        17     }
        18     return; # Did not got a defined line? End of input file.
        19   }
        20 }

       6 行目で、2 回目の <p> が現れました。これは次の段落である印です。そこ
       で、得た行をオリジナルドキュメントに戻し (7 行目)、これまで生成した
       paragraph を出力に push します。9 行目で先頭の <p> を削除した後、このタ
       グと残りの段落を翻訳したものを結合して push します。

       translate() 関数はとてもクールです。引数を出力 PO ファイル (抽出済) に
       挿入し、入力 PO ファイル (翻訳) で見つかった翻訳を返します。pushline()
       の引数の一部で使用するため、この翻訳が出力ドキュメントに定着します。

       クールじゃないですか? 十分シンプルなフォーマットなら、完全な po4a のモ
       ジュールを 20 行以下で作成できます……

       Locale::Po4a::TransTractor(3pm) で、これについてもっと知ることができま
       す。

   gettext: どのように動作しますか?
       ここでの考え方は、オリジナルドキュメントとその翻訳を取り、翻訳から抽出
       した N 番目の文字列は、オリジナルから抽出した N 番目の文字列の翻訳であ
       ると言うことです。動作するには、双方のファイルの構造がまったく同じでな
       ければなりません。例えば、ファイルが以下の構造を持つ場合、残念ながら翻
       訳の 4 番目の文字列 (型が「章」) は、オリジナルの 4 番目の文字列 (型が
       「段落」) の翻訳となります。

           オリジナル       翻訳

         章                 章
           段落               段落
           段落               段落
           段落             章
         章                   段落
           段落               段落

       これについては、po4a のパーサはオリジナルファイルと翻訳ファイルの双方
       で、PO ファイルを抽出するのに使用されます。オリジナルファイル由来の PO
       ファイルにある文字列の翻訳が、翻訳ファイル由来の PO ファイルの文字列で
       あるとして、新しく PO ファイルを生成します。出力した文字列が実際にそれ
       ぞれの翻訳となっているかをチェックするために、po4a のドキュメントパーサ
       は、ドキュメントから抽出した文字列の構文タイプ情報を出力すべきです (既
       存のものはすべてそうしますし、あなたのものもそうするべきです)。さらにそ
       の情報を、双方のドキュメントが同じ構文であるかどうかを確認するのに使用
       します。先の例では、4 番目の文字列は片方では段落ですが、もう片方では章
       見出しであることを検出し、問題を報告できます。

       理論上、問題を検出した後でファイルを (ちょうど diff がするように) 再同
       期することは可能です。しかし、非同期の前にある、再同期するべき文字列は
       明確ではなく、何度もまずい結果に終わるでしょう。以上が、何かまずい場
       合、現在の実装では再同期を行わず、失敗について詳しく出力する理由で
       す。問題の修正にはファイルの手修正が必要です。

       これだけ用心していても、この部分は非常に間違いやすいです。そのため、こ
       のように推測された翻訳すべてを fuzzy とマークし、翻訳者のレビューと確認
       を行うようにしています。

   追加内容: どのように動作しますか?
       さて、これはかなり簡単です。すべての追加内容が適用されるまで、翻訳済み
       ドキュメントは、直接ディスクに書かれていませんが、メモリに保管されてい
       ます。ここに関わるアルゴリズムはかなり率直です。position 正規表現にマッ
       チする行を探し、mode=before の場合はその前に追加内容を挿入します。そう
       でなければ、boundary にマッチする次の行を探し、それが endboundary の場
       合はその行の後に、beginboundary の場合はその行の前に追加内容を挿入しま
       す。

FAQ

       本章ではよく訊かれる質問を分類します。実際、以下のような形でほとんどの
       質問を定型化できました。「なぜああではなく、このような設計をしたのです
       か?」 po4a がドキュメントを翻訳する正しい方法ではないと感じたら、この節
       を読むようにするべきです。あなたの疑問への答えにならないな
       ら、<po4a-devel@lists.alioth.debian.org> メーリングリストで私たちにお問
       い合わせください。私たちはフィードバックが大好きです。

   何故段落ごとに分割して翻訳するのでしょうか?
       はい、po4a は段落ごとに区切って翻訳しています (実際、各モジュールはこの
       様に判断していますが、既存のモジュールがすべてそうとは限りませんし、あ
       なたのものもそうです)。この方法には二つの主な利点があります。

       · 場面からドキュメントの技術的な部分を隠すと、翻訳者はそこを弄ることが
         できません。翻訳者に提示するマーカが少なければ少ないほど、間違いにく
         くなります。

       · ドキュメントを切るのは、オリジナルドキュメントの変更点を隔離する助け
         になります。オリジナルが変更されたとき、このプロセスにより、翻訳のど
         の部分が更新が必要なのかを探しやすくなります。

       以上の利点をもってしても、段落ごとに区切って翻訳するというアイディアが
       気に入らない人はいます。彼らが恐れていることに対して、以下のように、い
       くつか回答を用意しています。

       · このアプローチは、KDE プロジェクトで成功が実証されました。またそこで
         翻訳の巨大なコーパスを作成し、私の知る限りドキュメントを更新していま
         す。

       · 翻訳者は翻訳の際に、PO ファイル内の文字列が、オリジナルドキュメントと
         同じ順番であるため、まだ文脈を利用できます。そのため、po4a を使う使わ
         ないにかかわらず、 順番通り訳していくのはかなり比較しやすいです。いず
         れの場合でも、これは私見ですが、テキストフォーマットは、真に読みやす
         いわけではないので、印刷可能なフォーマットにドキュメントを変換できる
         状態にしておくのが、文脈を把握する最善の方法だと思います。

       · このアプローチは、プロの翻訳者が採用しています。確かに、彼らはオープ
         ンソース翻訳者とは異なる目標を持っています。例えば、内容が変更される
         のはまれなので、保守がそれほど重要というわけではありません。

   文レベル (またはそれ以下) で分割しないのは何故ですか?
       プロ仕様の翻訳ツールは、ドキュメントを文レベルで分割し、以前の翻訳を最
       大限再利用し、作業のスピードアップを図るものがあります。これは同じ文
       を、文脈に応じて複数の翻訳にする場合に問題になります。

       段落は、その定義上、文よりも長いです。これにより、二つのドキュメントの
       同じ段落は、それぞれの文脈に関係なく、同じ意味 (と翻訳) になること
       が、おそらく保証できるでしょう。

       文よりも小さい単位で分割するのは、非常にまずいでしょう。なぜまずいのか
       は、ここで説明するには少々長いので、興味のある方は、例えば
       Locale::Maketext::TPJ13(3pm) の man ページ (Perl のドキュメントに同梱)
       をご覧ください。短くするにしろ、各言語は特定の構文規則を持ち、既存の全
       言語で (話者の多い 10 言語のうち 5 言語やそれ以下でも) 動作するよう
       な、文の一部を集めて文を組み立てる方法はありません。

   オリジナルをコメントとして翻訳中 (やその他のところ) につけないのは何故です
       か?
       一見したところ、gettext はすべての種類の翻訳に適合できるようには見えま
       せん。例えば、debconf (すべての Debian パッケージが使用する、インストー
       ル時の対話インターフェース) には適合できるようには見えませんでした。こ
       の場合、翻訳するテキストはかなり短く (パッケージごとに 1 ダース)、パッ
       ケージのインストール前に有効にならなければならない、特化したファイルに
       翻訳を挿入するのは難しいものでした。

       これが debconf の開発者が、オリジナルよりも翻訳を同じファイルに配置する
       という別解の実装を決定した理由です。これはかなり魅力的です。XML に対し
       てはそのようにしたがってさえいます。例えば以下のように見えます。

        <section>
         <title lang="en">My title</title>
         <title lang="fr">Mon titre</title>

         <para>
          <text lang="en">My text.</text>
          <text lang="fr">Mon texte.</text>
         </para>
        </section>

       しかしこれには問題があるため、現在は PO ベースのアプローチを採用してい
       ます。ファイルではオリジナルしか編集できず、翻訳はマスターテンプレート
       から抽出した PO ファイルに置かなければなりません (そしてパッケージコン
       パイル時に配置します)。古いシステムは以下のいくつかの理由で非推奨です。

       ·   保守の問題

           複数の翻訳者が同時にパッチを提供した場合、それらをマージするのは大
           変です。

           翻訳を適用する必要のある、オリジナルからの変更をどのように検出した
           らよいでしょう?diffを使用するには、どの版を元にして翻訳を行ったか記
           しておかねばなりません。言い換えると、あなたのファイルには PO ファ
           イルが必要です ;)

       ·   エンコーディングの問題

           この解は、ヨーロッパの言語だけが関わる場合には有効ですが、韓国
           語、ロシア語、アラビア語 (訳注: もちろん日本語も) の導入は、本当に
           構図を複雑にします。UTF は解になり得ますが、まだ問題があります。

           さらに、この問題を検出するのが難しいのです (言い換えると、「ロシア
           語の翻訳者のせいで」韓国語のエンコードが壊れていることを検出するの
           は、韓国人の読者のみです)。

       gettext はこの問題をすべて解決します。

   しかし、gettext はこんな用途向けには設計されていません!
       そうですね。しかし現在のところ他にもっといい方法がないのです。唯一の代
       替手段が手動翻訳であり、それには保守の問題があります。

   gettext を使ったドキュメント翻訳ツールは他に何がありますか?
       知る限りでは、以下の 2 つしかありません。

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

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

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

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

   翻訳についての開発者教育
       ドキュメントやプログラムの翻訳を行う際、3 つの問題に行き当たります。言
       語について (皆が 2 つの言語で話せるわけではありません)、技術について
       (po4a が存在する理由です)、人との連携についてです。すべての開発者が、翻
       訳の必要性について理解しているわけではありません。立派な意志があったと
       しても、翻訳者が作業しやすいやり方を無視する可能性もあります。これを補
       助するのに、po4a は参照可能なたくさんのドキュメントを用意しています。

       その他の重要な点として、このファイルが何で、どのように使用するのか、を
       示す短いコメントで、各翻訳済みファイルが始まるということがあります。こ
       れは、話すのも困難な言語の洪水におぼれている哀れな開発者を助け、ファイ
       ルを正しく扱う助けとなるはずです。

       po4a プロジェクトでは、翻訳済みドキュメントはもうソースファイルではあり
       ません。SGML ファイルは慣習的にソースファイルですが、これは簡単な誤りで
       す。これが、すべてのファイルに以下のヘッダを表示する理由です。

        |       *****************************************************
        |       *           GENERATED FILE, DO NOT EDIT             *
        |       * THIS IS NO SOURCE FILE, BUT RESULT OF COMPILATION *
        |       *****************************************************
        |
        | This file was generated by po4a-translate(1). Do not store it (in VCS,
        | for example), but store the PO file used as source file by po4a-translate.
        |
        | In fact, consider this as a binary, and the PO file as a regular source file:
        | If the PO gets lost, keeping this translation up-to-date will be harder ;)

       同様に、gettext の通常の PO ファイルは、po/ ディレクトリにコピーされる
       必要があるだけです。しかし、これは po4a によって操作されたものの例では
       ありません。ここには、開発者が、ドキュメントの翻訳がある、自分のプログ
       ラムの既存の翻訳を削除するという、大きな危険があります (双方を同じ PO
       ファイルに納めることはできません。これは、ドキュメントはコンパイル時に
       のみ翻訳が必要であるのに対して、プログラムは翻訳を mo ファイルとしてイ
       ンストールしなければならないからです)。以上が、po-debiandoc モジュール
       が以下のヘッダをつけて PO ファイルを提供する理由です。

        #
        #  ADVISES TO DEVELOPERS:
        #    - you do not need to manually edit POT or PO files.
        #    - this file contains the translation of your debconf templates.
        #      Do not replace the translation of your program with this !!
        #        (or your translators will get very upset)
        #
        #  ADVISES TO TRANSLATORS:
        #    If you are not familiar with the PO format, gettext documentation
        #     is worth reading, especially sections dedicated to this format.
        #    For example, run:
        #         info -n '(gettext)PO Files'
        #         info -n '(gettext)Header Entry'
        #
        #    Some information specific to po-debconf are available at
        #            /usr/share/doc/po-debconf/README-trans
        #         or http://www.debian.org/intl/l10n/po-debconf/README-trans
        #

   gettext ベースアプローチの利点まとめ
       · 翻訳はオリジナルと同時には格納されません。これにより翻訳の更新が遅れ
         ていることがわかります。

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

       · 内部的には gettext をベースにしています (が、po4a は非常にシンプルな
         インターフェースを提供するので、内部で使用していることを理解する必要
         はありません)。そんなところで車輪の再実装をする必要はなく、これが広く
         用いられているために、それらのツールには多かれ少なかれバグがないと考
         えられます。

       · エンドユーザにとっては何も変化ありません (事実は置いておいて、願わく
         ば翻訳がよりよく保守されますように :)。ドキュメントファイルが分配した
         結果になるのは、まったく同じです。

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

       · gettext は、何が完了しており、何をレビュー・更新すべきで、何がまだ作
         業中なのかといった統計を取得する簡単な方法を提供しています。以下のア
         ドレスでいくつか例を見つけることができます。

          - http://kv-53.narod.ru/kaider1.png
          - http://www.debian.org/intl/l10n/

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

       · 追加内容は……一見して、変です

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

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

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

著者
        Denis Barbier <barbier,linuxfr.org>
        Martin Quinson (mquinson#debian.org)