QuickIR 多国語対応の方法
gettext について調べてみたので、忘れないようメモメモ・・・
Raspberry Pi 3 Model B 、まだ届きません。それでもポツポツと「在庫あり」の販売店が出だしたので、以前のオーダーをキャンセルして「在庫あり」の店にオーダーを出しました。
またケースもオーダーしました。Raspberry Pi 3 Model B では CPUの温度がかなり上がるという話もあるので、少し高いのですがファン付きケースにしてみました。
予定どおりなら、来月初旬に届くはずですが、どうなることやら。
次の目標は多国語対応(と言っても英語と日本語だけ)しようかな〜?などと思っています。
|
と言ってしまったこともあり、勉強を兼ねて QuickIR を多国語化する方法について調べました。せっかく調べたので忘れないように書き残しておこうと思います。
現在、多くのプログラムが使用している多国語対応のための仕組み(フレームワーク)は GNU gettext というもので、Pythonにも gettext の機能(API)を使うためのモジュールが標準で組み込まれています。しかしPythonのgettextを読んでみても、どうすれば良いのかサッパリ理解できませんでした。実は Pythonプログラムを多国語化するためには、この gettextモジュールを完全に理解する必要などないのでした。(たぶん、初期設定などで実行時に言語を切り替えるとか、もっと難しいことをしようとすると話は別なんでしょうけど。)と言うことで、以下は QuickIRを例にした多国語化の方法です。
1. 準備:GNU gettextのインストール
多国語対応の作業をするためには GNU gettext が必要になります。が、主に作業している MacOS X 10.9.5 (Mavericks) には GNU gettext が入っていないようでしたので、先ずはこれをインストールします。
最近はインストールと言っても Homebrew等を使ってコマンド一発でというのが多いのですが、今回はソースからビルドしてインストールする方法を採りました。(とは言え、こちらも一般的なビルド&インストールの方法と同じです。)
- GNU gettext のソースをダウンロードする
GNU gettext本家から、最新版の gettextソースパッケージをダウンロードする。現時点での最新版は Ver.0.19.7 だった。
- 解凍してビルドする
$ tar xzf gettext-0.19.7.tar.gz
$ cd gettext-0.19.7
$ ./configure
$ make
$ make check
|
- インストールする
- インストールされた gettextに PATHを通す
"/usr/local"配下にインストールされるので、"/usr/local/bin" にPATHを通す。"~/.bashrc" 等に
export PATH="/usr/local/bin:$PATH"
|
などと書いておく。
2. 多国語対応の大まかな流れ
GNU gettextを使ってプログラムを多国語対応させるには、以下のような流れで行うことになります。
- ソースプログラムの修正(多国語化する文字列のラップ)
- xgettext コマンドでラップされている文字列を抽出して ".pot"(Potable Object Template)ファイルを作る
- msginit や msgmerge コマンドで、".pot" ファイルから ".po"(Portable Object)ファイルを作る
- ".po" ファイルに抽出された文字列を翻訳する
- msgfmt コマンドで ".po"ファイルをコンパイルして、バイナリの ".mo"(Machine Object)ファイルを作成
- ".mo"ファイルを "locale/ja/LC_MESSAGES" に配置する
まぁ、このくらいの事は Wikipediaの方が詳しいですね。次から上の大まかな流れを、QuickIR を例に具体的にやってみます。
3. ソースプログラムの修正(多国語化する文字列のラップ)
ここで書いているのは QuickIRプログラム(Python メインプログラム)を多国語対応する方法です。Pythonモジュールを多国語対応する場合には、また少し方法が異なりますので注意。
- QuickIRプログラムの始めの方に、以下の「おまじない」を書き加えます。
import gettext
gettext.install('QuickIR',
os.path.join(os.path.dirname(__file__), 'locale'))
|
Pythonのgettextモジュールを読み込んで、installメソッドを呼び出しています。installメソッドの意味はPythonのgettextに書かれています。実は、gettextモジュールで使うのはこれだけです。
- 次に多国語化する翻訳対象の文字列を
_( ) でラップ(括って)いきます。例えば、
show_error(_("File not found."))
|
こんな感じ。
元々は"ファイルが見つかりません。" という日本語のメッセージだったところを、"File not found." という英語のメッセージに書き換えて _( ) で括ります。この場合は、後のステップで "File not found." を"ファイルが見つかりません。" と日本語に翻訳することになります。
まぁ、日本語のメッセージのまま _("ファイルが見つかりません") としておいて、日本語から英語に翻訳することも可能なのですが、一般的にはプログラム内には英語で書いておいて、英語から日本語に翻訳するのが作法でしょうね。(*1)
4. xgettext コマンドでラップされている文字列を抽出して ".pot"(Potable Object Template)ファイルを作る
xgettext コマンドを用いて、ソースプログラム中の _( ) でラップされている文字列を抽出し、".pot"ファイルを作ります。xgettext コマンドは例えば、
$ xgettext [--no-location] [--no-wrap] --language=python -k"_" QuickIR.py -o QuickIR.pot
|
という具合に使用します。"[ ]" は省略可能という意味ですので、"--no-location", "--no-wrap" オプションはお好みで。
"--no-location" オプションは位置情報(行番号)を出力しないようにするオプションです。位置情報(行番号)は翻訳作業の時にはあった方が楽ですが、出力量が少し多くなるのと、少しプログラムを変更しただけで位置が変わってしまうため、バージョン(修正履歴)管理の差分量が多くなるのがネックです。
"--no-wrap" オプションは長いメッセージ行を折り返さないようにするオプションです。
5. msginit や msgmerge コマンドで、".pot" ファイルから ".po"(Portable Object)ファイルを作る
msginitコマンドは、一番最初に ".pot" ファイルから ".po" ファイルを作る際に使用します。msgmergeコマンドは、既にある ".po"ファイルを更新する場合に使用します。
- 新規に .poファイルを作成する場合の実行例
$ msginit [--no-wrap] --locale=ja_JP.UTF-8 --input=QuickIR.pot --output-file=QuickIR.po
ユーザが翻訳に関するフィードバックをあなたに送ることができるように,
新しいメッセージカタログにはあなたの email アドレスを含めてください.
またこれは, 予期せぬ技術的な問題が発生した場合に管理者があなたに連絡が取れる
ようにするという目的もあります.
Is the following your email address?
EMAIL@ADDRESS
Please confirm by pressing Return, or enter your email address.
hoge@email.address.com ←メールアドレスを入力
QuickIR.po を生成.
|
- 既存の .poファイルを更新する実行例
$ msgmerge [--no-location --no-wrap] --update QuickIR.po QuickIR.pot
.. 完了.
|
全部いっぺんに英語化するのは難しいので、最初の1回だけ msginitコマンドを使い、少し英語化しては msgmergeコマンドを使うという事になりますね。これで ".po" ファイルが作成されます。
6. ".po" ファイルに抽出された文字列を翻訳する
".po" ファイルをエディタで編集し、抽出された文字列を日本語に翻訳して行きます。ただ、初回だけ".po" ファイルのヘッダ部分も修正する必要があります。修正したら文字コードUTF-8で保存します。
# Japanese translations for QuickIR package.
# Copyright (C) 2016 THE QuickIR'S COPYRIGHT HOLDER
# This file is distributed under the same license as the QuickIR package.
# My Name <hoge@email.address.com>, 2016. ←★
#
msgid ""
msgstr ""
"Project-Id-Version: QuickIR 1.0.7¥n"
"Report-Msgid-Bugs-To: ¥n"
"POT-Creation-Date: 2016-03-11 15:28+0900¥n"
"PO-Revision-Date: 2016-03-11 15:28+0900¥n"
"Last-Translator: My Name <hoge@email.address.com>¥n" ←★
"Language-Team: ¥n" ←★
"Language: ja_JP.UTF-8¥n"
"MIME-Version: 1.0¥n"
"Content-Type: text/plain; charset=UTF-8¥n" ←★UTF-8にする
"Content-Transfer-Encoding: 8bit¥n"
"Plural-Forms: nplurals=1; plural=0;¥n"
#: QuickIR.py:64
msgid "File not found."
msgstr "ファイルが見つかりません。" ←★翻訳した日本語文字列を入力
|
注)¥ は半角の"\"(バックスラッシュ)です。
7. msgfmt コマンドで ".po"ファイルをコンパイルして、バイナリの ".mo"ファイルを作成
$ msgfmt QuickIR.po --output-file QuickIR.mo
|
8. ".mo"ファイルを "locale/ja/LC_MESSAGES" に配置する
".mo"ファイルが実行時に読み込まれて、_( ) でラップされている文字列が置き換えられます。"LC_MESSAGES"環境変数で指定されたロケール配下の ".mo" ファイルが読み込まれるので、QuickIR.py プログラムがあるディレクトリ配下にディレクトリを作って ".mo"ファイルを配置します。
$ mkdir locale
$ mkdir locale/ja
$ mkdir locale/ja/LC_MESSAGES
$ mv QuickIR.mo locale/ja/LC_MESSAGES/
|
上のようにディレクトリを作れば、次からは
$ msgfmt QuickIR.po --output-file locale/ja/LC_MESSAGES/QuickIR.mo
|
と".mo"ファイルを直接置き換えてしまって構いません。
- (*1):
- ロケールに対応する".mo"ファイルが見つからない場合は、プログラムに書かれている文字列がそのまま出力されます。日本語から翻訳することにすると、英語圏以外では、きっと「何か解らない謎の文字列が出てきたぞ。東洋の神秘だ!」ということになるのだと思います。なので、ロケールに対応する".mo"ファイルが無い(翻訳できていない)場合には英語で出力されるよう、プログラムには英語で書いておくのが作法でしょう。
|