Provided by:
po4a_0.38-1_all 
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 や kbabel (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 ファイルが変更された時に訳を更新するには、use
the 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
で後々楽になるために支払う価値があると思ってください。ありがたいことに一回だけやればいいのです。
多すぎるとは強調で-
ません。処理を簡単にするのに、翻訳の元にした完全なバージョンを見つけるのが重要です。最高の状況は翻訳に使用した
cvs のリビジョンを控えてお-
、翻訳の中でそれを変更していないことです。この場合、それを利用でい泙后
更新されたオリジナルテゥ好箸鮓鼎に殘と一緒に使用するのは、うまくい-
ません。そういったこともでい泙垢、本当に大変で、で-
れば避けた方がいいでしょう。事実上、もう一度オリジナルテ-
ストを見つけられないなら、一番いいのはあなたのために 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
ファイルを手に入れることです。これを後から更新でい泙后A佇 gettext
化してしまえば、楽になりますので、翻訳の編集をすると良いといわれています。
- 必要であれば、翻訳されていない部分を、オリジナルから削ってください。後でド-
ュメントを po と同期を取るとい房分自身で復元します。
- 構造を少しだけ変えた (2 つの段落をまとめたとか、1
つの段落を分けたとか)のなら、その変更を元に戻してください。オリジナルに問題があるなら、オリジナルの作者に連絡するべ-
でしょう。コミュニティの一部だけのために翻訳で修正していたとして、その上で
po4a を使うのは無理です ;)
- 時には、段落の内容は一致するけれども、型があわない場合があります。その修正法はフォーマットに依存します。pod
や nroff
では、片方の行は空白で始まっているのに、もう片方はそうではない、ということが実際にあります。こういったフォーマットでは、そのような段落は改行で-
ず、別の型となります。そのようなと-
は空白を削除してください。おそらくタグ名のタイプミスでしょう。
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"
フィールドが続い泙后6白が重要です。セミコロン (;) を値に使用で-
ず、クォートが役に立たないことに注意してください。
また恐ろしげに聞こえますが、以下の例は、必要なヘッダ行の-
述法を見つける手助けになるでしょう。議論の前提として、"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 (必須)
"before" か "after" という文字が入り、position point からの
追加内容の位置を指定します。
新しいセクションを、マッチした箇所の次に配置したい場合、以下のようにします。
mode=after
beginboundary (mode=after の時のみ使用。この場合必須)
endboundary (同上)
追加内容を後ろに続けるセクションの、最後にマッチする正規表現です。
mode=after の場合、insertion point は position point
の後になりますが、すぐ後ではありません! position point
で始まるセクションの後ろになります。なお、"???boundary"
引数と行の前 (ないし後) とがマッチします。どちらになるかは
"beginboundary" ないし "endboundary" で決まります。
この場合、以下のように追加して、セクションの終わりに一致するように指定で-
ます。
endboundary=</section>
また、以下のようにして次のセクションの直前を指定でい泙后
beginboundary=<section>
どちらの場合でも、</section> の後で、<section>
の前に追加内容を配置します。ド-
ュメントが再構成されても動作するので、前者の方がいいでしょう。
どちらの形態もあるのは、ド-
ュメントフォーマットが異なるからです。その中には、
(ちょうど使用した "</section>" のような)
セクションの終わりを示すもの、(nroff のような)
明確なセクションの終わりを表さないものがあります。前者の場合は、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
ここでは、".fi" を endboundary
として使用しないでください。明らかに想定していない、"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 は段落ごとに区切って翻訳しています
(実際、各モジュールはこの様に判断していますが、既存のモジュールがすべてそうとは限りませんし、あなたのものもそうです)。この方法には二つの主な利点があります。
o 場面からド-
ュメントの技術的な部分を隠すと、翻訳者はそこを弄ることがで-
ません。翻訳者に提示するマーカが少なければ少ないほど、間違いにくくなります。
o ドゥ絅瓮鵐箸鮴擇襪里蓮▲リジナルド-
ュメントの変更点を隔離する助けになります。オリジナルが変更されたと-
、このプロセスにより、翻訳のどの部分が更新が必要なのかを探しやすくなります。
以上の利点をもってしても、段落ごとに区切って翻訳するというアイディアが気に入らない人はいます。彼らが恐れていることに対して、以下のように、いくつか回答を用意しています。
o このアプローチは、KDE
プロジェクトで成功が実証されました。またそこで翻訳の巨大なコーパスを作成し、私の知る限りド-
ュメントを更新しています。
o 翻訳者は翻訳の際に、po ファイル内の文字列が、オリジナルド-
ュメントと同じ順番であるため、まだ文脈を利用でい泙后そのため、po4a
を使う使わないにかかわらず、
順番通り訳していくのはかなり比較しやすいです。いずれの場合でも、これは私見ですが、テ-
ストフォーマットは、真に読みやすいわけではないので、印刷可能なフォーマットにド-
ュメントを変換で-
る状態にしておくのが、文脈を把握する最善の方法だと思います。
o このアプローチは、プロの翻訳者が採用しています。確かに、彼らはオープンソース翻訳者とは異なる目標を持っています。例えば、内容が変更されるのはまれなので、保守がそれほど重要というわけではありません。
()?
プロ仕様の翻訳ツールは、ド-
ュメントを文レベルで分割し、以前の翻訳を最大限再利用し、作業のスピードアップを図るものがあります。これは同じ文を、文脈に応じて複数の翻訳にする場合に問題になります。
段落は、その定義上、文よりも長いです。これにより、二つのド-
ュメントの同じ段落は、それぞれの文脈に関係なく、同じ意味 (と翻訳)
になることが、おそらく保証でい襪任靴腓Α
文よりも小さい単位で分割するのはい任靴腓Αなぜまずいのかは、ここで説明するには少々長いので、興味のある方は、例えば
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
ファイルに置かなければなりません
(そしてパッケージコンパイル時に配置します)。古いシステムは以下のいくつかの理由で非推奨です。
o 保守の問題
複数の翻訳者が同時にパッチを提供した場合、それらをマージするのは大変です。
翻訳を適用する必要のある、オリジナルからの変更をどのように検出したらよいでしょう?diffを使用するには、どの版を元にして翻訳を行ったか-
しておかねばなりません。言い換えると、あなたのファイルには po
ファイルが必要です ;)
o エンコーディングの問題
この解は、ヨーロッパの言語だけが関わる場合には-
効ですが、韓国語、ロシア語、アラビア語 (訳注: もちろん日本語も)
の導入は、本当に構図を複雑にします。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 cvs,
| 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め
o 翻訳はオリジナルと同時には格納されません。これにより翻訳の更新が遅れていることがわかります。
o 翻訳はそれぞれ分割したファイルに格納され、異なる言語の翻訳者がパッチの提供やエンコードレベルの干渉を、互いに受けないようにします。
o 内部的には "gettext" をベースにしています (が、"po4a"
は非常にシンプルなインターフェースを提供するので、内部で使用していることを理解する必要はありません)。そんなところで車輪の再実装をする必要はなく、これが-
く用いられているために、それらのツールには多かれ少なかれバグがないと考えられます。
o エンドユーザにとっては何も変化ありません
(事実は置いておいて、願わくば翻訳がよりよく保守されますように
:)。ドゥ絅瓮鵐肇侫.ぅ襪分配した結果になるのは、まったく同じです。
o 翻訳者は、新しいファイルの文法を学習する必要はなく、好みの po
ファイルエディタ (emacs の po mode や、kbabel、gtranslator など)
でうまく動作します。
o gettext は、何が完了しており、何をレビュー・更新すべ-
で、何がまだ作業中なのかといった統計を取得する簡単な方法を提供しています。以下のアドレスでいくつか例を見つけることがで-
ます。
- http://kbabel.kde.org/img/previewKonq.png
- http://www.debian.org/intl/l10n/
しかし、すべて問題ないわけではありません。このアプローチには対処するべ-
欠点もあります。
o 追加内容は……一見して、変です
o 翻訳したテ-
ストを、この段落を分割するとか、あの二つの段落を結合するといった、あなたの好みに合わせることがで-
ません。しかし、オリジナルに問題があるのであれば、とりあえずバグとして報告すべ-
だ、という意見もあります。
o 簡単なインターフェースですが、学習が必要な新しいツールのままです。
私の夢の一つは gtranslator や kbabel
に何らかの形で統合することです。sgml
ファイルを開くと、文字列を自動的に抽出します。保存すると、翻訳済み
sgml ファイルをディスクに書すみます。MS Word (TM) モジュール
(少なくとも RTF) でこれがで-
れば、プロの翻訳家もこれを使ってくれるかも知れません。
ト
(モジュールが造蠅覆ぐ奮阿) もっとも大-
な問題は文字コードの取り扱いです。UTF8 perl pragma
を追加して、出力時に再度コード変換する方針ですが、まだ実装していません。
また、sgml モジュールの (ファイル挿入に関する)
コードを、全モジュールが享受でい襪茲Δ TransTractor
に導入したいと思いますが、これはユーザには見えません。
者
Denis Barbier <barbier,linuxfr.org>
Martin Quinson (mquinson#debian.org)