Next: , Previous: , Up: gettext   [Contents][Index]


11.2.5 あいまいさの解決のためにコンテキストを使用する

グラフィカルユーザーインターフェース(GUI)をもつプログラムで、gettext関数を普通に使うと、大きな問題がおきるかもしれない箇所があります。その問題とは、翻訳する必要がある文字列のほとんどが、短い文字列であるような場所で発生します。そらの文字列とは、プルダウンメニューの文字列のように、長さを制限する必要のある文字列です。それらの文字列は、センテンス全体を含んでいなかったり、センテンスの断片がプログラムの異なるシチュエーションで出現し、シチュエーションごとに異なる翻訳を割り当てる必要のあるものです。特にGUIプログラムで頻繁に使用される、1単語の文字列が問題になります。

gettextのアプローチには問題があるので、このような問題が存在しないcatgetsを使う必要があるという人もたくさんいます。しかし、この種の問題を処理するための簡単で強力な方法が、gettext関数には備わっているのです。

それは翻訳するべき文字列に、contextを追加する方法です。contextにもとづく翻訳参照とは、与えられた文字列にたいする翻訳を検索するときに与えられたcontextに検索範囲を限定することです。同じ文字列でも、異なるcontextに属する場合、異なる翻訳を割り当てることができます。ある文字列にたいするcontextごとの翻訳は、1つのMOファイルに一緒に保存でき、翻訳者も1つのPOファイルを編集するだけです。

gettext.hには、context付きの文字列を参照するためのマクロが含まれます。これらは<libintl.h>由来の軽量マクロ、またはインライン関数により実装されています。

const char *pgettext (const char *msgctxt, const char *msgid);

このマクロの呼び出しでは、msgctxtmsgidを文字列リテラルにしなければなりません。マクロは、msgctxtに与えられたcontextの、msgidに対応する翻訳を戻します。

msgctxtは、POファイル中で翻訳者が目にすることのできる文字列です。あなたは何らかの方法により標準的なものを定めることと、それを決して変更しないことが必要です。なぜならmsgctxtを変更する度に、翻訳者はmsgidにたいする翻訳をレビューする必要があるからです。

時間を経過しても変更されないような、標準的なmsgctxt文字列を見つけるのは困難です。しかしpgettextの呼び出しに、ファイル名やクラス名を使うべきではありません – なぜならファイルやクラスの名前を変更するのは開発タスクでは一般的なので、それが翻訳者の作業に影響を及ぼすべきでないからです。また、msgctxtに完全な英語センテンスのコメント形式を使うべきでもありません – なぜなら、そのようなセンテンスに適用される正書法や文法はしばしば変更されるので、繰り返しになりますが、その変更により翻訳者がレビューを強いられるべきではありません。

pgettext’の‘p’は、“particular(特定の)”から由来しています: pgettextは、特定のmsgidから翻訳を取得します。

const char *dpgettext (const char *domain_name,
                       const char *msgctxt, const char *msgid);
const char *dcpgettext (const char *domain_name,
                        const char *msgctxt, const char *msgid,
                        int category);

これらの関数はpgettextを、より一般化したものです。それぞれの関数は、dgettextdcgettextと同様に振る舞います。引数domain_nameには、翻訳のドメインを定義します。引数categoryを指定することにより、LC_MESSAGESとは異なるlocale categoryを指定できます。

次のような例で考えてみましょう。メニューバーをもつGUIプログラムがあり、メニューには以下のようなエントリーがあるとします:

+------------+------------+--------------------------------------+
| File       | Printer    |                                      |
+------------+------------+--------------------------------------+
| Open     | | Select   |
| New      | | Open     |
+----------+ | Connect  |
             +----------+

コード中のFilePrinterOpenNewSelectConnectの文字列は、gettextファミリーの関数によって翻訳される必要があります。しかしOpenという文字列は、2ヶ所で使われており、それにたいして異なる翻訳を割り当てなければならないかもしれず、それゆえ上述したようなジレンマが発生します。

メニュー中の同じ2つの文字列を区別するのは、メニューのルートからそれらのエントリーへのパスです:

Menu|File
Menu|Printer
Menu|File|Open
Menu|File|New
Menu|Printer|Select
Menu|Printer|Open
Menu|Printer|Connect

したがってcontextは、メニューのパスから最後の部分を除いたものになります。そうすると呼び出しは以下のようになるでしょう:

pgettext ("Menu|", "File")
pgettext ("Menu|", "Printer")
pgettext ("Menu|File|", "Open")
pgettext ("Menu|File|", "New")
pgettext ("Menu|Printer|", "Select")
pgettext ("Menu|Printer|", "Open")
pgettext ("Menu|Printer|", "Connect")

contextの最後に、区切り文字の‘|’をつけるかどうかは、スタイルの問題になります。

より複雑なケースとしては、msgctxtmsgidが文字列リテラルでない場合があります。そのようなケースにたいしては、より一般的なマクロが利用できます:

const char *pgettext_expr (const char *msgctxt, const char *msgid);
const char *dpgettext_expr (const char *domain_name,
                            const char *msgctxt, const char *msgid);
const char *dcpgettext_expr (const char *domain_name,
                             const char *msgctxt, const char *msgid,
                             int category);

これらのマクロは、msgctxtmsgidに、任意の文字列変数を指定できるので、より一般的です。どちらの引数も文字列リテラルのときは、‘_expr’が付加されていないマクロのほうが効率的です。