[ C++で開発 ]
国際化機能の1つで、プログラムで使用する文字列を外部ファイルから読み出すことで実行時にメッセージ文字列を切り替えることができます。切り替えにはロケールを使用するので、外部ファイルをロケール(言語)ごとに作成し配置することで、プログラムを実行した環境変数に応じて所定の言語のメッセージ文字列が使用されます。
外部ファイルは、メッセージIDとメッセージ文字列がペアとなっており、プログラムからはIDをキーに文字列を取得することになります。
このメッセージカタログの仕組みは、X/Openで定義されています。
メッセージカタログの簡単なサンプルを示します。
#include <nl_types.h> #include <iostream> int main(int argc, char* argv[]) { // メッセージカタログを開く nl_catd catd = ::catopen("hello.cat", 0); if (reinterpret_cast<int>(catd) == -1) { std::cerr << "メッセージカタログのオープンに失敗" << std::endl; return -1; } // メッセージカタログからメッセージを取得 int setNumber = 1; int messageNumber = 123; const char* defaultMessage = "Default message"; char* message = ::catgets(catd, setNumber, messageNumber, defaultMessage); std::cout << "message : " << message << std::endl; // メッセージカタログを閉じる int ret = ::catclose(catd); if (ret == -1) { std::cerr << "メッセージカタログのクローズに失敗" << std::endl; return -1; } } |
このプログラムのポイントは以下です。詳細は後に記述します。
メッセージカタログのオープンで指定しているファイル名 "hello.cat" を作成します。hello.catはバイナリファイルで、gencatコマンドで生成するものです。そのため、gencatに読ませるテキストファイルを作成することになります。
$set 1 123 こんにちは 赤ちゃん |
gencatコマンドでhello.msgからhello.catを生成します。
work$ gencat hello.cat hello.msg work$
国際化では、hello.catはロケールごとに作成されます。ファイル名が同一なので、ロケールに応じたディレクトリに分けて配置します。配置場所の指定は、環境変数NLSPATHを使用します。
ここでは、hello_catalogプログラムのデータを置くディレクトリを、/usr/local/share/hello_catalogとして、その下にロケールに対応したディレクトリを作成します。
work$ sudo mkdir -p /usr/local/share/hello_catalog/ja_JP.UTF-8 work$ cp hello.cat /usr/local/share/hello_catalog/ja_JP.UTF-8/ work$
上記ディレクトリに置く場合、環境変数NLSPATHを以下に設定します。
work$ export NLSPATH=/usr/local/share/hello_catalog/%L/%N work$
ここで、%Lはプログラム実行時にcatopen関数の中で、ロケールに応じて実際のディレクトリ名に展開されます。
%Nは、catopen関数に渡したメッセージカタログ名に展開されます。
work$ g++ -o hello_catalog hello_catalog.cpp work$ ./hello_catalog message : こんにちは 赤ちゃん work$
メッセージカタログを扱う関数仕様について
関数名 |
catopen |
|
---|---|---|
必要なヘッダー |
<nl_types.h> |
/usr/includeに置かれている |
戻り値 |
nl_catd |
オープンに成功したメッセージカタログのディスクリプタで、型はvoid* のtypedef エラーのときは、-1となり、errnoにエラー原因が設定される |
引数 |
const char* name |
メッセージカタログ名 |
int flag |
ロケールの決め方を制御するフラグ 0 : 環境変数LANGによる NL_CAT_LOCALE : LC_MESSAGESによる |
戻り値のエラー判定は、void*型とint型の比較演算がエラーとなるため、いったんint型へキャストする必要があります。しかし、本関数がエラーになってもプログラムの続行が可能であるため、通常エラー判定はしません。
引数のnameは、環境変数NLSPATHの%N部分になります。
引数のflagは、setlocale等でプログラム内でロケール設定をしていない場合、通常0でよいでしょう。
関数名 |
catgets |
|
---|---|---|
必要なヘッダー |
<nl_types.h> |
/usr/includeに置かれている |
戻り値 |
char* |
メッセージカタログに引数で指定したIDに合致する文字列がある場合はその文字列、ない場合もしくは引数で指定したディスクリプタが無効な場合は、引数messageで指定した文字列 |
引数 |
nl_catd catalog |
catopenで生成されたメッセージカタログのディスクリプタ |
int set_number |
メッセージカタログの集合ID | |
int message_number |
メッセージカタログのメッセージID | |
const char* message |
メッセージカタログから文字列が取得できない場合、この文字列を戻り値として使用する |
IDに合致した文字列がある場合、戻り値で返却されるアドレスは、関数内部で確保された領域となるので、変更/破棄はしてはなりません。
関数名 |
catclose |
|
---|---|---|
必要なヘッダー |
<nl_types.h> |
/usr/includeに置かれている |
戻り値 |
int |
0 : クローズに成功 -1 : クローズに失敗 |
引数 |
nl_catd |
catopenで生成されたメッセージカタログのディスクリプタ |
カタログファイルを生成するコマンドgencatに入力するテキストファイルの書き方をまとめます。
配列等でIDを1から連続で使用したいとき、$setで番号を変えると他のメッセージと重ならずに定義できます。
テキストで作成したファイルから、バイナリのカテゴリファイルに変換します。
work$ gencat hello.cat hello.msg work$ work$
gencatは、カテゴリファイルが既にあれば、そのファイルに追加するので、たとえば複数のテキストファイルを1つのカテゴリファイルに結合することができます。
たとえば、$setの数値ごとに別ファイルにメッセージを記述し、それらを1つのカテゴリファイルにまとめるなどです。
環境変数NLSPATHでは、以下の特殊な記法が使われます。
記法 | 内容 | 例 |
%L |
ロケール名(正式名) |
ja_JP.UTF-8 |
%l |
ロケール名の言語部分 |
ja |
%t |
ロケール名の国部分 |
JP |
%c |
ロケール名のコードセット部分 |
UTF-8 |
%N |
メッセージカタログファイル名 (catopen関数で指定) |
hello.cat |