Locale::Po4a::TransTractor(3) 汎用翻訳抽出機構

説明

po4a (PO for anything) プロジェクトは、gettext ツールが想定していないドキュメントのような領域で翻訳をしやすくすること (またより興味深いのは、翻訳文の保守がしやすくなること) を目標にしています。

このクラスは、翻訳可能な文字列を検索するためのドキュメントのパース、PO ファイルへの抽出、出力したドキュメントへの翻訳した文字列の置換に使用する、すべての po4a パーサの祖先になります。

もっと形式張って言うと、入力として以下の引数を取ります。

-
翻訳するドキュメント
-
翻訳に使用する PO ファイル

以下を出力します。

-
入力ドキュメントから翻訳可能な文字列を抽出した、別の PO ファイル。
-
入力したものと同じ構造で、入力した PO ファイルにある訳で翻訳可能な文字列を置換した、翻訳済みドキュメント。

これを視覚的に表すと次のようになります。

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

個別のパーサでオーバーライドするべき関数

parse()
ここに、入力ドキュメントのパース、出力の生成、翻訳可能文字列の抽出といった、すべての動作を定義しています。後述する 内部関数 セクションで説明する提供された関数を使用するのはかなり簡単です。サンプル付きの 書式 もご覧ください。

この関数は、後述の process() 関数から呼ばれますが、new() 関数を使用して、ドキュメントに内容を手で追加するのを選んだ場合、この関数自体を呼ばねばなりません。

docheader()
この関数は、ターゲットの言語でコメントにするための、適切にクォートした、生成したドキュメントに追加するべきヘッダを返します。この何がよいのかは、po4a(7) の 翻訳についての開発者教育 セクションをご覧ください。

書式

以下の例は、``<p>'' で始まる段落のリストをパースします。簡単にするために、ドキュメントが整形されている、言い換えると、'<p>' タグのみが現れ、各段落はこのタグで必ず始まると見なします。


sub parse {
my $self = shift;
PARAGRAPH: while (1) {
my ($paragraph,$pararef)=("","");
my $first=1;
my ($line,$lref)=$self->shiftline();
while (defined($line)) {
if ($line =~ m/<p>/ && !$first--; ) {
# Not the first time we see <p>.
# Reput the current line in input,
# and put the built paragraph to output
$self->unshiftline($line,$lref);

# Now that the document is formed, translate it:
# - Remove the leading tag
$paragraph =~ s/^<p>//s;
# - push to output the leading tag (untranslated) and the
# rest of the paragraph (translated)
$self->pushline( "<p>"
. $document->translate($paragraph,$pararef)
);
next PARAGRAPH;
} else {
# Append to the paragraph
$paragraph .= $line;
$pararef = $lref unless(length($pararef));
}
# Reinit the loop
($line,$lref)=$self->shiftline();
}
# Did not get a defined line? End of input file.
return;
}
}

parse 関数を実装したら、次のセクションで説明する パブリックインターフェースを用いて document クラスを使用できます。

パーサで使用するスクリプトのパブリックインターフェース

コンストラクタ

process(%)
この関数は、po4a ドキュメントで行うのに必要なすべてを、一度の実行で行います。引数はハッシュとしてパックしなくてはなりません。動作は以下のようになります。
a.
po_in_name で指定した、すべての PO ファイルの読み込み
b.
file_in_name で指定した、すべてのオリジナルドキュメントの読み込み
c.
ドキュメントのパース
d.
指定したすべての追加内容の、読み込み・適用
e.
翻訳したドキュメントの file_out_name への書き出し (与えられた場合)
f.
抽出した PO ファイルの po_out_name への書き出し (与えられた場合)

new() で受け付けるもの以外の引数 (と想定する型)。

file_in_name (@)
読み込むべき入力ドキュメントの、ファイル名のリストです。
file_in_charset ($)
入力ドキュメントで使用している文字セットです (指定しない場合、入力ドキュメントから検出しようとします)。
file_out_name ($)
書き出すべき出力ドキュメントのファイル名です。
file_out_charset ($)
出力ドキュメントで使用する文字セットです (指定しない場合、POファイルの文字セットを使用します)。
po_in_name (@)
読み込むべき入力 PO ファイル (ドキュメントの翻訳に使用する訳文) の、ファイル名のリストです。
po_out_name ($)
書き出すべき出力 PO ファイル (入力ドキュメントから抽出した文字列) のファイル名です。
addendum (@)
読み込むべき追加内容の、ファイル名のリストです。
addendum_charset ($)
追加内容の文字セット
new(%)
新規 po4a ドキュメントを作成します。以下のオプション (ハッシュは不可) を受け取ります。
verbose ($)
冗長表示を有効にします。
debug ($)
デバッグを有効にします。

ドキュメントファイルの操作

read($)
別の入力ドキュメントを、既存のドキュメントの後ろに追加します。引数は読み込むファイル名です。

パースは一切行わないことに注意してください。入力ファイルがドキュメントに格納した時点で parse() 関数を使用するべきです。

write($)
与えたファイル名で翻訳済みドキュメントを書き出します。

PO ファイルの操作

readpo($)
既存の入力 PO に、(引数で渡した名前の) ファイルの内容を追加します。古い内容は破棄されません。
writepo($)
抽出した PO ファイルを、与えたファイル名で書き出します。
stats()
現在までに翻訳した内容に関する統計を返します。msgfmt --statistic が出力する統計とは、同じとは限らないことに注意してください。ここでは、PO ファイルの最新の使用法についての統計ですが、msgfmt が報告するのは、ファイルの状態についてです。これは、Locale::Po4a::Po::stats_get 関数を入力した PO ファイルに適用するラッパーです。サンプルは以下のようになります。

    [po4a ドキュメントの通常の使用...]
    ($percent,$hit,$queries) = $document->stats();
    print "We found translations for $percent\%  ($hit from $queries) of strings.\n";

追加内容の操作

addendum($)
追加内容とは何か、や、翻訳者はどのように書いたらよいのかといった情報は、po4a(7) を参照してください。翻訳したドキュメントに追加内容を適用するには、この関数に単純にファイル名を渡し、実行するだけです。

この関数は、エラー時には 非 null の数値を返します。

派生パーサ作成時に使用する内部関数

入力と出力

入力を受け付け、出力を返す関数を 4 つ用意しています。これらは shift/unshift や push/pop とよく似ています。最初の組は入力用、後の組は出力用です。入力では shift がするように最初の行を扱い、出力では push がするように、結果の最後に追加すると覚えればいいでしょう。
shiftline()
この関数は、パースする doc_in の次の行とその参照を、(配列にパックして) 返します。
unshiftline($$)
入力ドキュメントの行とその参照を unshift します。
pushline($)
doc_out に新しい行を挿入します。
popline()
doc_out から最後に push した行を pop します。

文字列を翻訳可能としてマーク

翻訳するべきテキストを扱う関数を 1 つ用意しています。
translate($$$)
与える引数
-
翻訳する文字列
-
この文字列の参照 (言い換えると、入力ファイルの場所)
-
文字列の型 (つまり構造上の役割をテキストで説明したもの。Locale::Po4a::Po::gettextization() で使用します。 po4a(7) の gettext 化: どのように動作しますか? 節もご覧ください)

この関数は、いくつか追加引数を取れます。ハッシュとしてまとめなければなりません。

  $self->translate("string","ref","type",
                   'wrap' => 1);
wrap
文字列中の空白が、重要でないとして扱うかどうかを示す真偽値です。重要でない場合、この関数は、翻訳を探したり抽出したりする前の文字列を納め、翻訳を折り返します。
wrapcol
改行を行う幅です (デフォルト: 76)。
comment
エントリに追加するコメント

動作:

-
文字列、参照、型を po_out に push します。
-
パーサが doc_out を構築できるように、文字列の翻訳 (po_in に見つかったもの) を返します。
-
文字列を po_out に送る前や翻訳を返す前に、文字列を再コード化する文字セットを扱います。

その他の関数

verbose()
TransTractor の生成時に verbose オプションが渡された場合、返します。
debug()
TransTractor の生成時に debug オプションが渡された場合、返します。
detected_charset($)
これは、入力ドキュメントから新しい文字セット (第一引数) を検出したと、TransTractor に伝えます。通常、ドキュメントのヘッダから読むことができます。process() の引数から来たものとドキュメントから検出したもののうち、最初の文字セットのみが対象となります。
get_out_charset()
この関数は、出力ドキュメントで使用する文字セットを返します (入力ドキュメントの検出した (その場所にあった) 文字セットを置き換えるのに便利です)

コマンドラインで指定した出力文字セットが使われます。指定しない場合で、入力 PO ファイルに デフォルトの ``CHARSET'' がある場合は、入力 PO ファイルの文字セットを使用します。エンコーディングが与えられなかった場合は、入力ドキュメントの文字セットを返します。

recode_skipped_text($)
この関数は、引数で渡したテキストを、入力ドキュメントの文字セットから、出力ドキュメントの文字セットへ、再コード化して返します。これは、文字列を翻訳する際には必要ありませんが (translate() は、自分ですべて再コード化します)、入力ドキュメントからの文字列をスキップし、出力ドキュメントを共通のエンコードで一致させたい場合に必要です。

将来の方向性

現在の TransTractor の欠点の一つに、(debconf テンプレートや、.desktop ファイルのような) すべての言語を含む翻訳済みドキュメントを扱えないというものがあります。

この問題に対処するには、以下のようにインターフェースのみを変更することが必要です。

-
po_in_name (言語ごとのリスト) としてハッシュを取ります。
-
対象言語を示すための翻訳する引数を追加します。
-
以下の map のような書式を使用する、全言語の内容に対する pushline のような、pushline_all 関数を作成します。

    $self->pushline_all({ "Description[".$langcode."]=".
                          $self->translate($line,$ref,$langcode) 
                        });

これで十分だといいのですが ;)

著者

 Denis Barbier <[email protected]>
 Martin Quinson (mquinson#debian.org)
 Jordi Vilalta <[email protected]>