bash-2.0 から $"..." という記法により ... をロケール依存変換することが可能になりました(NEWS より)。 この文書では、この bash-2.0 以降の $"..." 記法による bash script のメッセージの国際化(カタログ化)について 簡単に説明します。
必要なソフトウェア。
これから次のシェルスクリプトを例に使っていきます。
#!/usr/bin/env bash # hello.sh -- say hello script echo hello world
実行例:
$ ./hello.sh hello world $
カタログ化したい文字列をダブルクオート(")で括り、 $ をその先頭につけてください。
#!/usr/bin/env bash # hello.sh -- say hello script echo $"hello world"
実行例の結果は前と変わりません。
スクリプトを --dump-po-strings オプションを付けた bash で処理します。 処理結果はファイルに保存してください。 通例としてファイル名は .po で終わります。 この --dump-po-strings を利用するには bash 2.02 以降が必要です。 bash 2.02 より前のバージョンでは -D (--dump-strings) を使います。 ただ、-D オプションではカタログ化された文字列を抜き出すことしか できないので、手で po 形式に編集する必要があります。
実行例:
$ bash --dump-po-strings hello.sh >hello.po $ cat hello.po #: hello.sh:3 msgid "hello world" msgstr "" $
次にロケール毎のメッセージカタログファイルを作成します。 ここでは日本語(ja)用のメッセージカタログだけ作成します。 まず先に作っておいた hello.po を ja.po にコピーします。 それから ja.po を編集しましょう。 日本語ロケールでは "hello world" のかわりに "こんにちは 世界" を 使うことにします。 このためには ja.po にある msgstr の引数を "" から "こんにちは 世界" に 変更します。
実行例:
$ cp hello.po ja.po $ vi ja.po $ cat ja.po #: hello.sh:3 msgid "hello world" msgstr "こんにちは 世界"
注意: この po ファイルは不完全です。 本来は Content-Type で charset を指定すべきです。 詳しくは参考文献にあげた GNU getttext manual を参照してください。
ja.po を bash がメッセージカタログとして直接取り扱える形式に コンパイルする必要があります。 コンパイルには msgfmt を使います。 ファイル名は .mo で終わる必要があります。 通例 ja.po にたいして ja.mo を作成します。
実行例:
$ ls hello.po hello.sh ja.po $ msgfmt -o ja.mo ja.po $ ls hello.po hello.sh ja.mo ja.po $
コンパイル結果の ja.mo は メッセージカタログ用のディレクトリに置く必要があります。 glibc2 を採用した GNU/Linux システムでは通常 /usr/share/locale 以下に置く必要があるのですが、 これは環境変数 TEXTDOMAINDIR で変更することができます。 ここではカレントディレクトリ以下に直接置くことにします(TEXTDOMAINDIR=.)。
メッセージカタログ(moファイル)は メッセージカタログ用ディレクトリ以下の 言語を表わすディレクトリ(日本語では ja)の LC_MESSAGES というディレクトリに置く必要があります。 つまり ja.moファイルは ./ja/LC_MESSAGES ディレクトリに置くことになるのですが、 ファイル名は ja.mo ではなくプログラムやパッケージをあらわすものに します。 これは後で TEXTDOMAIN という環境変数で指定することになるのですが、 ここでは hello.mo というファイル名にします。
実行例:
$ mkdir -p ja/LC_MESSAGES $ cp ja.mo ja/LC_MESSAGES/hello.mo
ここまで hello.sh -> hello.po -> ja.po -> ja.mo -> ja/LC_MESSAGES/hello.mo という順でメッセージカタログを作成・配置してきました。 hello.sh がこのメッセージカタログを参照するには TEXTDOMAINDIR と TEXTDOMAIN という 二つの環境変数を設定する必要があります。 TEXTDOMAINDIR はメッセージカタログ用ディレクトリを指定します。 この文書の例では TEXTDOMAINDIR=. としてきました。 TEXTDOMAIN は通常プログラム名、 あるいは gnome-core のようなパッケージ名を指定します。 この文書の例では TEXTDOMAIN=hello としました。 つまり ./ja/LC_MESSAGES/hello.mo というファイル名は ${TEXTDOMAINDIR}/言語/LC_MESSAGES/${TEXTDOMAIN}.mo という構成をしているのです。
実行例:
$ LANG=C TEXTDOMAINDIR=. TEXTDOMAIN=hello ./hello.sh hello world $ LANG=ja_JP.eucJP TEXTDOMAINDIR=. TEXTDOMAIN=hello ./hello.sh こんにちは 世界 $
以上で bash スクリプトのメッセージをカタログ化することができました。 しかし TEXTDOMAINDIR と TEXTDOMAIN をスクリプトの外で指定しているのは いかにも不細工です。 次にこれをどうにかします。
単純にスクリプト内で環境変数 TEXTDOMAINDIR と TEXTDOMAIN を 指定しても効果がありません。 このため少々トリッキーなことを行う必要があります。 スクリプトの先頭で環境変数 TEXTDOMAIN をチェックし、 スクリプトの TEXTDOMAIN(hello) ではなかった場合、 環境変数 TEXTDOMAINDIR と TEXTDOMAIN を設定し、 自分自身($0) を exec します。 これで TEXTDOMAINDIR と TEXTDOMAIN をスクリプト内に納めておくことが できます。
編集例:
$ vi hello.sh $ cat hello.sh #!/usr/bin/env bash # hello.sh -- say hello script [ x"$TEXTDOMAIN" = x"hello" ] || TEXTDOMAINDIR=. TEXTDOMAIN=hello exec "$0" echo $"hello world"
実行例:
$ LANG=C ./hello.sh hello world $ LANG=ja_JP.eucJP ./hello.sh こんにちは 世界 $
glibc2 システムでは TEXTDOMAIN=libc とすることで libc のメッセージカタログを参照することができます。
実行例:
$ LANG=ja_JP.eucJP TEXTDOMAIN=libc bash -c 'echo $"No such file or directory"' そのようなファイルやディレクトリはありません
この文書での po/mo ファイルの取り扱いはかなり大雑把です。 詳しくは GNU gettext manual を参照してください。
gettext コマンドがあるので 実のところ bash 組み込みのメッセージカタログ機能を 利用する必要はそれほどないと思いますが、 外部コマンドを使わないという点でメリットがあるでしょう。
間違いの指摘などは
ysjj@unixuser.org まで。変更履歴