海外IT企業で働いていた純日本人エンジニアがいろいろと考えてみる。

i18nしてますか?(gettext+PHPその1)

»

 どうも、鹿島和郎(かしまかずお)です。世間では夏休みの方も多いかと思いますが、みなさまいかがお過ごしでしょうか。わたしはというと、連続した休みを取ることができず、金曜日を休みにして3連休にするのが精いっぱいでした。

 子供には「よく遊び、よく学べ」なんて偉そうなことをいうくせに、大人に対しては「よく働き、よく働け」なんですから、日本人は二枚舌ですね。

 とまぁグチってばかりでも仕方ありませんので、今回も引き続きi18n関連の話題で、ロケールに関する補足、そしてgettextの2点に関して説明していきます。

■ロケールに関する補足

○localeコマンド(UNIX系)

 前回、環境変数について触れましたが、localeコマンドを引数なしで実行すると、現在のロケール関係の環境変数の一覧が表示されます。手元のLinux環境で実行した結果を以下に示します。

$ locale
LANG=ja_JP.UTF-8
LC_CTYPE="ja_JP.UTF-8"
LC_NUMERIC="ja_JP.UTF-8"
LC_TIME="ja_JP.UTF-8"
LC_COLLATE="ja_JP.UTF-8"
LC_MONETARY="ja_JP.UTF-8"
LC_MESSAGES="ja_JP.UTF-8"
LC_PAPER="ja_JP.UTF-8"
LC_NAME="ja_JP.UTF-8"
LC_ADDRESS="ja_JP.UTF-8"
LC_TELEPHONE="ja_JP.UTF-8"
LC_MEASUREMENT="ja_JP.UTF-8"
LC_IDENTIFICATION="ja_JP.UTF-8"
LC_ALL=

 また、locale -aとやると、システムで利用可能なロケール名の一覧が表示されます。日本語関連だけ抜粋した結果を以下に示します。

$ locale -a | grep ^ja
ja_JP
ja_JP.eucjp
ja_JP.ujis
ja_JP.utf8
japanese
japanese.euc

 「ja」というロケール名がないのに気付いた方はなかなか鋭いです。これに関しては後ほど(あるいは次回に)また触れたいと思います。

■gettextを使い「日本語から英語」に翻訳

 さて、いよいよ本題です。あなたはプログラマで、ついこないだプログラム(とかサービス)を完成させました。当然プログラム内のメッセージは日本語です。さて、公開してみたところユーザーさんからの評判もなかなかよく、

 「もしかしてわたくしって天才? そろそろハリウッド(あるいはシリコンバレーでも花の都パリでも好きなところ)デビューしちゃおうかしら」

なんて思い始めます。しかし、すぐに

 「でもプログラム内のメッセージ等を英語に訳す必要があるわね」

なんて現実に直面するかもしれません。

 そんなあなたにお勧めしたいのが、今回から2~3回にわたって説明するgettextです。ここではgettextというものを使って、プログラム中の日本語を英語(※1)に翻訳する方法を説明していきます。

 また、言語に関してはPHPを例に説明しますが、スクリプト系の言語(Perl、Ruby、Python)であれば、それほど手順に違いはないと思います。時間の許す限りそれらの言語でも検証して、違いがあれば補足していこうと思います(※2)。

 ※1 gettextに関して説明しているページや書籍をみると、英語のテキストを日本語や各国語に翻訳している例がほとんどです。でも、そもそも日本人が作るプログラム・システムの大半では日本語のテキストはすでに存在するので、ここではすでにある日本語のメッセージをベースに英語やほかの言語に翻訳するという手順でやりたいと思います。

 技術的な補足は、ブログの方に少し書きましたので、興味のある方は見ていただければと思います。

 ※2 最初はCの説明も一緒にしようかと思ったのですが、C固有の話が結構多くなりそうなので今回の対象からは除外します。今後気が向いたら個別にCの説明をしようと思います。また、Javaのi18nではgettextは直接は使いませんので、こちらも改めて書こうと思います。

○gettextの仕組みは意外と簡単

  gettext、正式にはGNU gettextは、その名の通りGNUのツール群の1つで、GNUのページによると「GNU gettextユーティリティは、他のGNUソフトが多言語メッセージを扱えるようなフレームワークを提供する(筆者超訳)」ものだそうです。実体としては多言語対応の処理を行うライブラリと、ソースコードからテキストを抽出したりするツールからなっています。

 gettextはGNU系のツールをはじめ、他のオープンソースのソフトなどでも幅広く使われており、実装としてもC以外にもさまざまな言語での実装があります。

 gettextを使用したアプリケーションの多言語化の流れは、おおまかには以下の通りです。

  1. ソースコードの修正
  2. 翻訳対象のテキスト抽出(.pot)
  3. テキストの翻訳(.po)
  4. 翻訳したファイルからリソースファイル(.mo)を作成
  5. システムからリソースを使用

 「え? ハリウッドデビューまでこんなにたくさんの手順があるの? 面倒!」

と思われるかもしれませんが、1つ1つの手順は簡単です。以降、各手順について述べたいと思います。

○ソースコードの修正

 まずはソースコードでメッセージを出力している個所にちょっとだけ修正を加えます。

printf("%sさん、こんにちわ!\n", $name); //変更前

printf(_("%sさん、こんにちわ!\n"), $name); //変更後

 たったこれだけです。簡単ですよね。

 作成中のシステム・プログラムを多言語対応をする必要が当面なくても、取りあえずここで説明した「文字列を_()で囲む」という作業だけはやっておくといいかもしれません。

 また、PHPのソースの文字コードがUTF-8でない場合は、UTF-8に変換しておいてください。

 # なお、サンプルプログラム中のメッセージの日本語に違和感を抱いた方もいらっしゃるかと思いますが、しばらくは我慢していただければと思います。

○翻訳対象のテキスト抽出(.pot)

 次に、先ほど修正したソースからメッセージを抜き出します。やりかたはコマンドを1つ実行するだけですので簡単ですね。

$ xgettext -k"_" --from-code=UTF-8 -o hello.pot hello.php

 上のコマンドは、hello.phpの中から_("xx")という形式のテキストを抜き出して、hello.potというファイルを作成します。potという拡張子は、po(後ほど説明)のTemplateという意味だと思います。hello.potの中身は、以下のようなテキストファイルになっています。

# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-08-08 15:37+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: gettext.php:12
#, php-format
msgid "%sさん、こんにちわ!\n"
msgstr ""

 なお、コマンドを使わずに、いろいろな便利な機能がついたGUIのツールを使ってもいいと思います。

○テキストの翻訳(.po)

 次に、前の手順で作成されたメッセージファイルを翻訳するのですが、その前にディレクトリ構造に関して少し説明します。

 この次の回でリソースファイル(.mo)というものを作成するのですが、それは以下のようなディレクトリ構成に従って配置する必要があります。

<ベースディレクトリ>/<ロケール名>/LC_MESSAGES/*.mo

  • ベースディレクトリ:任意のディレクトリ(プログラムからアクセス可能であればどこでも構いません)
  • ロケール名:システムで利用可能なロケール名(今回はハリウッドを目指すので、en_USです)

 ここで、前の手順で作成したhello.potを英語(en_US)用にコピーします。コピー先は*.moを置く場所と同じLC_MESSAGESの下です。コピー後のファイルの拡張子はpoですので気をつけてください。

$ mkdir -p <ベースディレクトリ>/en_US/LC_MESSAGES
$ cp hello.pot <ベースディレクトリ>/en_US/LC_MESSAGES/hello.po

 後は、hello.poの中身を翻訳します。取りあえず以下のような感じでOKでしょう。%sや行末の\nも忘れないようにしましょう。

msgid "%sさん、こんにちわ!\n"
msgstr "Hello %s!\n"

■まとめ・補足

 今回で多言語対応プログラムの作成は大体半分くらい終わりました。今回やったことは、プログラム中の日本語メッセージを_()で囲んで、後は簡単な手順をいくつか実行しただけです。意外と簡単だと思った方も多いのではないでしょうか。

 次回は、今回翻訳したファイル(.po)をリソースファイル(.mo)というものに変換し、それをプログラムから使う方法を説明したいと思います。

 それではまた。

Comment(0)

コメント

コメントを投稿する