さて、翻訳のためにすべての適切な文字列をマークする作業を始められるところまで来ました。 すべての文字列をマークする必要はないことに注意して下さい。 設定ファイルなどはロカール依存とはならないでしょうから、 ユーザーが見ることのない文字列は通常はそのままにしておくべきです。 いくつかのエラーメッセージについても翻訳しないでおきたいと思うかもしれません。 ユーザーはそれらのメッセージをコピーし、メールに貼り付けしてあなたに送り、 あなたはそれらを理解してコードから grep で見つけ出すことができます。 通常名前を翻訳する必要はありませんが、 アプリケーションの情報ボックスで何が起きるかについては 項5. 「秘訣と技」 を参照して下さい。
一般的な法則として、 アプリケーションの通常の操作でユーザーに見られる文字列は翻訳するべきです。 例えばデバッグ出力と内部エラーメッセージといった、 開発者向けの文字列を翻訳するべきではありません。
翻訳のためにマークするメッセージを決める際には注意するべきです。 重要な、[ユーザーに]見える文字列を未翻訳のままにしておくのは、 素人くさく、ユーザーに不便を強いてしまいます。 無関係の文字列を翻訳のためにマークするのは、無意味であり、 GNOME のために作業している多くの翻訳ボランティアが提供しているサービスの誤用となるだけです。
C または C++ ソースコードからそれらしいすべての文字列を探し出す最初の試みとして、 ソースコードディレクトリでコマンド xgettext -a -o my-strings --omit-header *.c *.h を実行します。
これによって、 ディレクトリのすべての .c そして .h ファイルを走査して、すべての文字列をファイル my-strings に出力します。 このファイルは翻訳時に翻訳者が作業するものにとてもよく似ていますが、 当面注目すべきは各々の行のフォーマットです。次のようになっているはずです。
#: slice-n-dice.c:36 msgid "Sharpening the knives and preparing for action." msgstr "" |
これはこの文字列がファイル slice-n-dice.c の行番号 36 にあることを示しています。 よって、もしこの文字列を翻訳するべきと判断したのなら、 このファイルを開いてその文字列を _( と ) で囲みます。つまり、例えばコード
popup_display ("Sharpening the knives and preparing for action."); |
を次のように変更します。
popup_display (_("Sharpening the knives and preparing for action.")); |
マークアップの方法には一つだけ問題があります。 _() は関数呼出しなので、すべての状況で使えるわけではありません。 例えば、文字列をいくつか含む static 配列を初期化しているなら、 その初期化時に関数を呼出すことはできません。 次のようなコードについて考えてみます。
ShapeData shapes[] = {"circle", "square", "triangle", NULL}; |
このような場合文字列をマークアップするのには N_() を使うべきです。 このマクロは、結局のところ何かするわけでもありませんが、 gettext ツールは翻訳可能な文字列を探すのにコードを走査してこの種のマークアップをみつけたことを伝え、 これらの文字列を抽出します。上の例は次のようになります。
ShapeData shapes[] = {N_("circle"), N_("square"), N_("triangle"), NULL}; |
一度 N_() で文字列をマークアップしたら、 コード内でこれらの文字列が使われている箇所をすべて探し出し、 文字列を出現させるコードを _() で囲む必要があります。 これは _() がメッセージを検索し、翻訳する関数だからです。 上の例について続けると、 (i18n マークアップの後で) 次のようなコードを書けばいいでしょう。
for (i = 0; shapes[i] != NULL; ++i) show_shape_name (_(shapes[i])); |
shapes[] からの文字列の取得は _() の呼出しを通して行なわれ、そうして show_shape_name() 関数は元の文字列ではなく、 翻訳された文字列を使っていることに注意して下さい。 static 文字列が実際に使われている場所を見落すことは珍しくないので、 (文字列を N_() で適切にマークアップしていても) コードマークアップのこの部分を正しく行うには、 おそらく少し用心しなければならないでしょう。
一度、先につくった my-strings ファイル内のすべての文字列についてくまなく調べてみて翻訳するべきかどうか決定したら、 そのファイルは削除できます。 このファイルは単に手順を先に進めるだめだけのものでした。 この段階で(いつものように)、 まだ i18n 部分が機能していなくても (ENABLE_NLS が未定義なので、すべての特別なマークアップは何もないのと同じになります) コードはなおも通常どおりビルド、動作できるはずです。 後で問題が起きるのを避けるためにビルド可能かどうかはテストしておくべきです。
ライブラリを書いているのであっても、 スタンドアローンのアプリケーションについて前に書いたほとんどすべてをあてはめることができます。 唯一の問題は、 ライブラリが文字列を処理する際に、 ライブラリ固有のドメインがアクティブであるようにしたくても、 通常ライブラリ自身はその時点でアクティブなメッセージドメインを決して知ることがないということです。 この問題の最も単純な解決方法は 項2.1. 「i18n ヘッダーファイル」 セクションでふれた i18n ヘッダーファイル内の定義の一つを変更することです。 次のような箇所を探し、
#define _(String) gettext(String) |
これを次のように変更します。
#define _(String) dgettext(GETTEXT_PACKAGE, String) |
このようにして _() 関数を介するすべての文字列は常にライブラリのドメインで翻訳されるようになります。
他のもう一つの状況は起こることは非常にまれですが知っておく価値があるでしょう。 例えば libgnomeui, 内には文字列の配列 (ここではメニューアイテム) を処理する関数があります。 これらの文字列のいくつかは標準的なもので、ライブラリ自身の中で翻訳されています。 他はクライアントアプリケーションが提供し、そのドメイン内で翻訳されます。 そこで libgnomeui は次の関数と便利なマクロを定義しています。
例 2. libgnomeui/gnome-app-helper.cから引用
#define L_(x) gnome_app_helper_gettext (x) const gchar * gnome_app_helper_gettext (const gchar *str) { char *s; s = gettext (str); if ( s == str ) s = dgettext (GETTEXT_PACKAGE, str); return s; } |
これによって、L_() でマークされた文字列は、 可能ならその時アクティブなドメイン、さもなくばライブラリのドメインで翻訳されます。 同じような状況にあるのならこのコードを複製してもよいでしょう。
desktop ファイルは GNOME ではパネルメニュー内のどのメニューの下にアプリケーションを表示するか決定するために使われています。 また desktop ファイルには、 どのようにしてアプリケーションを起動するか、どのアイコンを表示するかという情報と一緒に、 パネル上のアプリケーションのツールチップとして表示する説明文を含んでいます。
国際化の観点から .desktop のパーツで興味を引くところは Name と Comment フィールドです。 GNOME 2 ではこれら二つのフィールドだけが使われ、これらは desktop ファイル仕様の中で、 翻訳可能なものとして定義されています。
これらフィールドを翻訳可能なものとしてマークするには、 desktop ファイル slice-n-dice.desktop を slice-n-dice.desktop.in (.in 接尾辞は伝統的なものです) にコピーして、 Name と Comment タグの前に下線(_) を加えます。 マークアップの後ではファイルは次のようになります。
例 3. slice-n-dice.desktop.in
[Desktop Entry] Encoding=UTF-8 _Name=Slice 'n' Dice _Comment=Chop things up into shapes Exec=slice-n-dice Icon=slice-n-dice.png Terminal=false Type=Application Categories=GNOME;Application; |
このように翻訳のためにファイルを変更する度にファイル名を記録しておきましょう。 これはこのセクションとさらに後で述べるいくつかのセクションでふれているファイルタイプの両方にあてはまります。 後に 項3.3. 「Makefile の変更」 で、 これらの新しいファイルを利用するためにビルド変更を施す必要がありますので、 リストを持っておけばそれらの内どれについても見落すことがなくなります。
一度 項3. 「パッケージのビルドインフラに i18n [の仕組み]を取り込み 」 セクションでの変更を施したら、 slice-n-dice.desktop.in だけを残して slice-n-dice.desktop は削除するべきです。 ビルドプロセスはこのテンプレートに翻訳を統合し、 すべての利用可能なロカールについての文字列を含む desktop ファイルを生成します。
要求に応じてコンポーネントをアクティブにする bonobo-activation-server が呼ぶアプリケーションは、 どのようにアクティブにするかを記述し、[自身についての]説明文を含む .server という拡張子を持つファイルを持っています。 そして、これらのファイルについても翻訳のために同様にマークアップする必要があります。
desktop ファイルと同じようにファイルの名前を GNOME_slice.server から GNOME_slice.server.in に変更します。 そしてファイルを開き、 type="string" 属性を持つ <oaf_attribute> タグを編集します。 これらのタグは value="..." 属性を持っているので、 これを _value="..." と変更します。 こうしてマークアップを終えたら次のような数行があるはずです。
<oaf_attribute name="name" type="string" _value="Slicing factory"/> <oaf_attribute name="description" type="string" _value="Factory for slicing and dicing"/> |
いくつか (本当のところほとんど) のプロジェクトでは、 コンポーネントが最終的にどこにインストールされるのかといった、 configure スクリプトによって置き換えられるいくつかの変数がサーバーファイルの中に含まれているので、 サーバーファイルは既にテンプレートになっているでしょう。 よってそのファイルは既に GNOME_slice.server.in という名前になっているでしょう。 この場合は単にさらに .in 拡張子を追加した GNOME_slice.server.in.in ファイルを作成します。 intltool アプリケーションは configure が置き換えてしまう前に実行されることに注意して下さい。 そして 項3. 「パッケージのビルドインフラに i18n [の仕組み]を取り込み 」 ではただ GNOME_slice.server.in.in は intltool によって GNOME_slice.server.in に変換されるということだけ覚えておいて下さい。
ユーザーインターフェースを構築するのに Glade を使っているのなら、 glade ファイル内の文字列を翻訳できるものとわかるようにするのにマークアップする必要は特にありません。 次のセクションで設定する予定の intltool アプリケーションは、 glade 形式のファイルのどの部分 (ウィジェットラベル、メッセージ、アクセシビリティ文字列など) が翻訳可能であるか知っていて、自動的にそれらを抽出します。
唯一つだけ、Glade を使っているときには、 オプションボックスの LibGlade タブの中の 翻訳可能な文字列を保存する を設定しないようにしておく必要があります。 代りに Glade が自動的にマークアップ文字列を含むファイルを生成します。
もしアプリケーションが任意の形式の XML ファイルを伴うのなら、 同様にそれらのファイルの一部を翻訳のためにマークアップすることができます。 前と同じように slice.xml を slice.xml.in と名前を変更します。 それからファイル全体を通して翻訳するべき要素を下線でマークします。 例えば、
<type level="safe"> <shape>blunt triangle</shape> <description>Creates a triangle without sharp corners.</description> </type> |
を次のようにマークアップします。
<type level="safe"> <shape>blunt triangle</shape> <_description>Creates a triangle without sharp corners.</_description> </type> |
<description> タグを翻訳のためにどのようにマークアップしているかわかるでしょう。 また閉タグも同様に変更され、 (おそらく元々の同じ DTD には従っていないけれども) そのファイルがなおも well-formed XML となっていることにも注意して下さい。
FIXME: 要素が翻訳のためにマークアップされたときそれに含まれる他の要素についてはどうなるか? 内側の要素についてもマークアップされるべきかどうか。
もし doc-i18n-tool が修正されないのなら、 それは奥行かしすぎるので、このセクションは置き換えられるべき。
Gconf が使う schema ファイルにはキーの長短[様々な]説明が含まれていることがあり、 これらの文字列は明らかに翻訳の候補となります。 また schema ファイル中のキーも、 より適切なものにローカライズするべきという意味で、翻訳可能なデフォルト値を持ち得ます。 例えば、金融[関係の]アプリケーションは C ロカールで Stock Exchange キーのデフォルト値として "New York" を持っているかもしれませんが、 de [ドイツ] ロカールではこのキーのデフォルト値は "Frankfurt" である方がよいはずです。
schema ファイルから引き出す適切なキーを持つための方法は、 それらを <locale> 要素でくるみ、 オリジナルファイルのロカールを C と指定することです。 上述の金融アプリケーションの場合例えば次のようになります (いくつかの行は冗長なので省略しています)。
例 4. financial.schemas
<schema> <key>/schemas/apps/finance/preferences/current_market</key> ... <locale name="C"> <default>New York</default> <short>Current stock exchange</short> <long>This key holds the name of the stock exchange that we are currently querying. It can have any string value that corresponds to a world market.</long> </locale> </schema> |
<locale name="C"> 要素内の説明文やデフォルト値を持たないキーは翻訳されません。 普通は長短[様々な]説明文についてはすべて翻訳したいと思うでしょうが、 デフォルト値についてはほんのたまにそうしたいと思うだけでしょう。