Pythonでgettextを使用してNLS(Native Language Support)によるメッセージの国際化を行う(Pythonのコードについて)
「Pythonでgettextを使用してNLS(Native Language Support)によるメッセージの国際化を行う(作業の流れと動作確認・前半)」で扱ったPythonのテストコードの内容に関する覚え書き。
準備
以下、Pythonでgettextによりメッセージを国際化するための一連の処理について。
色々な指定
- gettext.bindtextdomain()の2番目の引数には、ロケール名を含むディレクトリ(例: /usr/share/locale)を指定する
- 「os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "share", "locale")」はプログラムのあるディレクトリから1つ上のディレクトリ階層に上がったところのshare/localeディレクトリを示す
- ロケール名のディレクトリ(例: /usr/share/locale/ja)にはLC_MESSAGESディレクトリがあり、更にその中に[ドメイン].moが存在する必要がある
(2009/3/6)ディレクトリ指定の部分でos.pathの関数を使用するように変更したのに合わせて記述を修正
ここでいう「ドメイン」は、1つのメッセージカタログがカバーする範囲のことで、bindtextdomain()やtextdomain()、dgettext()などの関数からメッセージカタログのファイル名(拡張子の「.mo」を除いた部分)で扱われる。
gettext.install()とgettext.ngettext()
(2011/2/22)gettext.install()を用いてngettext()を動かすための追加メモを「Pythonでgettextによるメッセージ国際化を用いる上でのgettext.install()に関する追加メモ(前半)」「Pythonでgettextによるメッセージ国際化を用いる上でのgettext.install()に関する追加メモ(後半)」で扱っている。以下は古い内容となる。
- gettext.install()を使用すると、それ以外の初期化作業が必要なくなるように見えるが、実行すると
メッセージ 文字列: test 1 item 2 items 0 items B による A 新しいメッセージ
となってしまい、gettext.ngettext()を使用しているところだけ日本語にならなかった。
そこで、どのように動作しているのかを細かく見るため、straceを使用してみた。
[work]$ strace -o stace.log bin/gettexttest.py
このログファイルstrace.logから一部を抜き出すと
write(1, "\346\226\207\345\255\227\345\210\227: test\n", 16) = 16 stat("/usr/share/locale/ja_JP.utf/LC_MESSAGES/messages.mo", 0x7fff23c49c50) = -1 ENOENT (No such file or directory) stat("/usr/share/locale/ja_JP/LC_MESSAGES/messages.mo", 0x7fff23c49c50) = -1 ENOENT (No such file or directory) stat("/usr/share/locale/ja.utf/LC_MESSAGES/messages.mo", 0x7fff23c49c50) = -1 ENOENT (No such file or directory) stat("/usr/share/locale/ja/LC_MESSAGES/messages.mo", 0x7fff23c49c50) = -1 ENOENT (No such file or directory) write(1, "1 item\n", 7) = 7 stat("/usr/share/locale/ja_JP.utf/LC_MESSAGES/messages.mo", 0x7fff23c49c50) = -1 ENOENT (No such file or directory) stat("/usr/share/locale/ja_JP/LC_MESSAGES/messages.mo", 0x7fff23c49c50) = -1 ENOENT (No such file or directory) stat("/usr/share/locale/ja.utf/LC_MESSAGES/messages.mo", 0x7fff23c49c50) = -1 ENOENT (No such file or directory) stat("/usr/share/locale/ja/LC_MESSAGES/messages.mo", 0x7fff23c49c50) = -1 ENOENT (No such file or directory) write(1, "2 items\n", 8) = 8 stat("/usr/share/locale/ja_JP.utf/LC_MESSAGES/gettexttest.mo", 0x7fff23c49e80) = -1 ENOENT (No such file or directory) stat("/usr/share/locale/ja_JP/LC_MESSAGES/gettexttest.mo", 0x7fff23c49e80) = -1 ENOENT (No such file or directory) stat("/usr/share/locale/ja.utf/LC_MESSAGES/gettexttest.mo", 0x7fff23c49e80) = -1 ENOENT (No such file or directory) stat("/usr/share/locale/ja/LC_MESSAGES/gettexttest.mo", 0x7fff23c49e80) = -1 ENOENT (No such file or directory) write(1, "0 items\n", 8) = 8 write(1, "B \343\201\253\343\202\210\343\202\213 A\n", 14) = 14
となっている。これが示すのは
- gettext.ngettext()を使用しているところでは/usr/share/locale以下からmessages.mo*1を読み込もうとしている(が失敗)
- gettext.dngettext()を使用しているところでは(「gettexttest」というドメインを指定しているため)/usr/share/locale*2以下からgettexttest.moを読み込もうとしている(が失敗)
- gettext.ngettext()とgettext.dngettext()を使用しているところでは、出力されるメッセージは全て英語のまま・それ以外のところは日本語が表示されている
ということで、(gettext.install()の代わりに)gettext.bindtextdomain()とgettext.textdomain()を呼んだ場合とは挙動が異なる(うまく動作しない)。
フォーマットの順番を入れ替える際の注意点
print _("%s by %s") % (aaa, bbb)
という書き方をしたところ、xgettextが
../bin/gettexttest.py:[行番号]: 警告: 名無し引数のある 'msgid' フォーマット文字列を適切に特定することができません: 翻訳者は引数を整理し直すことができません. 名前付き引数のあるフォーマット文字列を使うこと, 且つ引数に対して組 (tuple) の代わりにマッピングを使うことを検討してください
という警告を出した。
Pythonでprintf()系関数のようなフォーマット付けを行うときには、上のような形式以外に、フォーマット文字列に
%(名前)[フォーマット文字列(「s」や「d」など)]
の形で名前を付けて
{[名前1] : [名前1に対応する変数], [名前2] : [名前2に対応する変数], ...}
という形の辞書に名前と変数の対応を書くという方法があるのだが、複数の変数をフォーマット付けするところのメッセージを国際化したいときには、こちらの方式を使用することになる。
print _("%(aaa)s by %(bbb)s") % {"aaa" : aaa, "bbb" : bbb}
関連記事:
- Pythonでgettextを使用してNLS(Native Language Support)によるメッセージの国際化を行う(作業の流れと動作確認・前半)
- Pythonでgettextを使用してNLS(Native Language Support)によるメッセージの国際化を行う(作業の流れと動作確認・後半)
- Pythonで作成したgettextのテストプログラムをC言語で書いてみる
- Pythonでgettextによるメッセージ国際化を用いる上でのgettext.install()に関する追加メモ(前半)
- Pythonでgettextによるメッセージ国際化を用いる上でのgettext.install()に関する追加メモ(後半)
参考URL:
- Python ライブラリリファレンス: 2.3.6.2 文字列フォーマット操作
- Python ライブラリリファレンス: 2.3.8 マップ型
- Python ライブラリリファレンス: 6.28.1 GNU gettext API
使用したバージョン:
- Python 2.4.4(2.4.4-r13)
- gettext 0.17