3    メッセージ・カタログの作成と使用

メッセージ・カタログは,プログラムからアクセスできる地域化データのファイルです。 langinfo データベースと同じ定義が適用されますが,両者には相違点もあります。

langinfo データベースの地域化データ要素は,オペレーティング・システムによって提供されるライブラリ・ルーチン,コマンド,およびユーティリティを含むすべてのアプリケーションで使用されます。 langinfo データベースは,ロケールを定義するソース・ファイルから作成されます。

langinfo データベースとは異なり,メッセージ・カタログは,1 つのプログラム,または関連するプログラム・セットの地域化に必要な情報を提供します。 メッセージ・カタログは,メッセージ・テキストのソース・ファイルから生成されます。 このファイルには,言語や文化の違いによって変更しなければならない,エラーや情報メッセージ,プロンプト,フォームのバックグラウンド・テキスト,さまざまな文字列や定数が含まれます。

グラフィカル・ユーザ・インタフェースを使用する X アプリケーションや Motif アプリケーションは,タイトル・バー,メニュー,ボタン,およびウィンドウ内の簡単なメッセージなどの少量のテキスト・データを処理するときは,これらのデータをメッセージ・カタログではなく,X リソース・ファイルから取り出します。 Motif アプリケーションでは,ヘルプやエラー・メッセージなどのテキストにアクセスする際に,テキスト・ライブラリ・ファイルに加え,ユーザ・インタフェース言語 (UIL) ファイルをオプションとして使用できます。 ただし,X アプリケーションと Motif アプリケーションはどちらも,メッセージ・カタログ内のテキストにアクセスできます。

この章ではメッセージ・カタログに焦点を当て,以下の各項目について説明します。

テキストの取り出しおよび表示に使用するメソッドに関係なく,メッセージ・カタログ・テキストの翻訳に適用される X および Motif プログラミング・ガイドラインについては,3.1.6 項を参照してください。

3.1    メッセージ・テキスト・ソース・ファイルの作成

メッセージ・カタログを作成し使用する前に,まずメッセージ・テキスト・ソース・ファイルの構成要素,構文,および意味について理解しておかなければなりません。 この章の以降の部分ではソース・ファイルの内容と処理方法について説明しますが,その前に,理解を早めるためにソース・ファイルの例を簡単に説明します。 例 3-1 は,オンラインのサンプル・プログラム xpg4demo のメッセージ・テキスト・ソース・ファイルからの抜粋です。

例 3-1:  メッセージ・テキスト・ソース・ファイル

$ /*   [1]
$  * XPG4 demo program message catalogue.    [1]
$  *   [1]
$  */  [1]
[2]
$quote "   [3]
$set MSGError   [4]
E_COM_EXISTBADGE        "Employee entry for badge number %ld \   [5]
already exists"
E_COM_FINDBADGE         "Cannot find badge number %ld"   [5]
E_COM_INPUT             "Cannot input"   [5]
E_COM_MODIFY            "Data file contains no records to modify"  [5]
E_COM_NOENT             "Data file contains no records to display" [5]
E_COM_NOTDEL            "Data file contains no records to delete"  [5]

.
.
.
$set MSGInfo [4] I_COM_NEWEMP "New employee" [5] I_COM_YN_DELETE "Do you want to delete this record?" [5] I_COM_YN_MODIFY "Do you want to modify this record?" [5] I_COM_YN_REPLACE "Are these the changes you want to make?" [5]
.
.
.
$ NOTE - Message contains the format used to display numeric dates $ The first descriptor, 1$, contains the year $ The second descriptor, 2$, contains the month $ The third descriptor, 3$, contains the day I_SCR_IN_DATE_FMT "%2$d/%3$d/%1$d" [6] $set MSGString [4] $ $ One-character commands. $ Note: These should not be translated because they are keywords for the application. $S_COM_CREATE "c" [7] S_COM_DELETE "d" [7] S_COM_EXIT "e" [7]  
.
.
.
$ Note: These are column heads and spacing and should be maintained $ Column one begins at space 1. $ Column two begins at space 15. $ Column three begins on space 37. $ Column four (an abbreviation of Department) begins at space 60. $ Column five (an abbreviation of Date of Birth) begins at space 68. $ S_COM_LIST_TITLE is output to underscore headers and should be $ increased or decreased as appropriate for translation. S_COM_LIST_TITLE "Badge Name Surname \ Dept DOB\n" [8] S_COM_LIST_LINE "--------------------------------------------\ ---------------------------------\n" [8]
.
.
.
$ $ If surname comes before first name, "y" should be specified. $ S_SCR_SNAME1ST "n" [9]
.
.
.

  1. ドル記号 ($) で始まり,その後にスペースまたはタブ文字が続く行は,コメント行です。 コメント行については,3.1.5 項で説明します。 [例に戻る]

  2. 読みやすくするために,ファイル内の任意の位置に空白行を入れられます。 [例に戻る]

  3. クォート文字は,メッセージ・テキストを区切ります。 quote ディレクティブについては,3.1.4 項で説明します。 [例に戻る]

  4. 識別子は,メッセージ・セットの始まりを示します。 このソース・ファイルには,エラー・メッセージ (MSGError セットに含まれる),情報メッセージ (MSGInfo セットに含まれる),およびその他の文字列と書式 (MSGString セットに含まれる) の,3 つのメッセージ・セットがあります。 メッセージ・セットの定義と削除については,3.1.2 項を参照してください。 [例に戻る]

  5. ソース・ファイル内の大半の行は,メッセージ・エントリです。 このエントリは,重複しない識別子とメッセージ・テキスト文字列から構成されます。 1 番目のメッセージ・エントリは,バックスラッシュ (\) を使用して次の行に継続しています。 他にも,\n (改行) のように,メッセージの出力を制御する特別な文字シーケンスを含むエントリがあります。 メッセージ・エントリの詳細については,3.1.3 項を参照してください。 メッセージ・エントリに適用される規則とオプションについては,3.1.1 項も参照してください。 [例に戻る]

  6. このタイプのメッセージ・エントリは,ユーザにデータ入力を求める際のデータ要素の入力順序を,翻訳者が変更できるようにしています。 プログラム・ロジックでメッセージの書式付けを行う方が好ましいですが,メッセージ・エントリを使用して書式を制御することもできます。 この行は,変数を識別する必要がある翻訳者に対するコメントも示しています。 [例に戻る]

  7. このタイプのメッセージ・エントリは,単語の省略形を定義します。 別の言語を使用した場合でも,略語が一意になるように配慮する必要があります。 [例に戻る]

  8. このタイプのメッセージ・エントリは,メニュー表示のためのヘッダ行を定義します。 これにより,翻訳者はフィールドの順序や行の長さを,文化習慣の違いを吸収するためにプログラムに用意されている他の調整項目に合せて調整できます。 この行は,略語に慣れていない翻訳者や,書式付けされた欄の幅を知る必要がある翻訳者に対するコメントも示しています。 [例に戻る]

  9. このタイプのメッセージ・エントリは,プログラムで名前フィールドの位置関係を決める方法を制御する定数を定義します。 たとえば,xpg4demo プログラムでは,名前と姓の順番を変更できます。 [例に戻る]

1 つまたは複数のメッセージ・テキスト・ソース・ファイルを使用して,プログラムが実行時にアクセスできるメッセージ・カタログ (.cat ファイル) を作成できます。 例 3-1 のソース・ファイルからメッセージ・カタログを作成する手順は,次のとおりです。

  1. mkcatdefs コマンドを使用して,メッセージ・セットとメッセージのシンボリック識別子を,カタログ内でのメッセージ・セットの位置と,各セット内でのメッセージの位置を示す番号に変換します。

  2. gencat コマンドを使用して,mkcatdefs の出力からメッセージ・カタログを作成します。

mkcatdefs コマンドと gencat コマンドについては,3.4 節で説明します。

3.1.1    一般規則

この項では,メッセージ・テキスト・ソース・ファイルの構文に適用される一般的なガイドラインについて説明します。 メッセージ・テキストの内容のスタイル・ガイドラインについては,3.1.6 項で説明します。

メッセージ・テキスト・ソース・ファイル (.msg ファイル) には,メッセージの並びが入っています。 オプションとして,1 つまたは複数のメッセージ・セット内でこれらのメッセージの順序を指定できます。 一般にアプリケーションには,地域化ごとに個別のメッセージ・ソース・ファイルが用意されます。 つまり,ユーザがアプリケーションを実行するロケールごとに (コードセット,言語,および地域の組み合わせごとに) ソース・ファイルがあります。

識別子の値をクォート文字で囲まない場合は,ソース・コードセットで定義されているスペースまたはタブ文字を 1 つ指定して,ソース・ファイルの行中のフィールドを区切ります。 スペースやタブを 2 つ以上指定した場合,余分なスペースやタブは値の一部として扱われます。 quote ディレクティブで指定した文字を使用してメッセージ文字列全体を囲むと,識別子と文字列の間にある余分なスペースやタブが,文字列の一部として扱われるのを防ぐことができます (quote ディレクティブについては,3.1.4 項を参照してください)。 また,末尾にスペースやタブを含むメッセージ・テキストでは,メッセージ文字列をクォート文字で囲まなければ,テキストの末尾にスペースやタブが含まれていることを示すことはできません。

メッセージ・テキスト文字列には,通常の文字に加え,表 3-1 に示す特殊文字のシーケンスを含めることができます。

表 3-1:  メッセージ・テキスト・ソース・ファイルにおける特殊文字の記述

説明 シンボル 文字シーケンス
改行 NL (LF) \n
水平タブ HT \t
垂直タブ VT \v
後退 BS \b
復帰 CR \r
改ページ FF \f
バックスラッシュ \ \\
8 進数値 ddd \ddd [脚注 1]
10 進数値 dddd \xdddd [脚注 2]

メッセージ・ファイル内のバックスラッシュは,表 3-1 に記載されていない文字シーケンスが後に続く場合は無視されます。 たとえば,\m というシーケンスは,メッセージ中に m を出力します。 8 進数値や 16 進数値の形式で文字を表現する場合,特殊文字の数値表現に続く文字も有効な 8 進数字または 16 進数字であれば,数字の前にゼロを付加します。 たとえば,ドル記号の 8 進数が 44 の場合に $5.00 を出力するには,\0445.00 と指定しなければなりません。 この指定により,5 が 8 進数値の一部として解釈されるのを防ぐことができます。

通常,改行文字はメッセージ・エントリを区切ります。 ただし,改行文字の直前にバックスラッシュを入力することにより,メッセージ文字列を次の行に継続させることができます。 この場合,改行文字の入力では,英語キーボードの Return キーまたは Enter キーを押します。 たとえば,次の 2 つのエントリは等価であり,プログラム・ユーザからの見え方は同じです。

MSG_ID        This line continues \
to the next line.
MSG_ID        This line continues to the next line.

メッセージ・ソース・ファイル内の空行は,すべて無視されます。 ファイルを読みやすくするために,空行を入力できます。

3.1.2    メッセージ・セット

メッセージ・セットは,メッセージ・テキスト・ソース・ファイル内のオプションの構成要素であり,省略可能です。 メッセージ・セットは,使用目的を問わず,メッセージをグループ化するのに使用できます。 複数のプログラム・ソース・ファイルから構築されるアプリケーションでは,メッセージ・セットを作成し,プログラム・モジュールに対応させてメッセージを構成したり,あるいは,オンラインのサンプル・プログラム xpg4demo のように,同じカテゴリ (エラー,情報,定義文字列) に属するメッセージをグループ化することができます。

プログラム・モジュールごとにメッセージをグループ化する利点は,後でアプリケーションからモジュールを削除するときに,そのモジュールに対応するメッセージを簡単に見つけてカタログから削除できることです。

メッセージを使用目的別にグループ化すると,同じアプリケーション内の複数のモジュール間でメッセージを共有できます。 使用目的別にグループ化することにより,アプリケーションの新しいモジュールを作成したり,既存のモジュールを保守するプログラマは,必要なメッセージがすでにファイル内に存在するかどうかを簡単に調べることができます。

set ディレクティブは,後続のメッセージのセット識別子を指定し,次の set ディレクティブまたはファイルの終わりが検出されるまでのメッセージをそのセットに含めます。 set ディレクティブの形式は次のとおりです。

$SET set_id [comment]

set_id 変数は,次のいずれかです。

セット識別子の後にある文字は,コメントと見なされます。

メッセージ・テキスト・ソース・ファイル内に set ディレクティブがない場合,すべてのメッセージは,省略時のメッセージ・セットに割り当てられます。 省略時のメッセージ・セットの番号は,ファイル /usr/include/nl_types.h 内の NL_SETD 定数で定義されています。 プログラムから catgets() 関数を呼び出して,set ディレクティブが含まれていないソースから作成されたカタログからメッセージを取り出すときは,NL_SETD 定数をセット識別子として指定します。

注意

メッセージ・テキスト・ソース・ファイルの set ディレクティブで NL_SETD を指定したり,1 つのメッセージ・カタログ内に省略時のメッセージ・セットとユーザ定義のメッセージ・セットを混在させないようにします。 そのような操作をすると,mkcatdefsgencat ユーティリティでエラーが発生する可能性があります。 また,NL_SETD 定数に割り当てられる値はベンダによって定義されているため,メッセージ・テキスト・ソース・ファイル内で NL_SETD をシンボリック識別子として使用すると,mkcatdefs 出力の移植性が損なわれます。

次に,既存のメッセージ・カタログからメッセージ・セットを削除するエントリについて説明します。 カタログの保守に関する一般的な説明については,3.4.3 項を参照してください。

メッセージ・テキスト・ソース・ファイルには,既存のメッセージ・カタログからメッセージ・セットを削除するための delset ディレクティブを含めることができます。 delset ディレクティブの形式は次のとおりです。

$delset n [comment]

変数 n は,gencat コマンドに指定する,既存のカタログ内のセット番号でなければなりません。 set ディレクティブとは異なり,delset ディレクティブではシンボリック・セット識別子は指定できません。 メッセージ・ファイルを mkcatdefs コマンドで前処理するときは,シンボリック識別子を,mkcatdefs ユーティリティが割り当てたセット番号とメッセージ番号に対応付ける,別のヘッダ・ファイルをオプションとして生成できます。 後でメッセージ・セットを削除したいときは,まずこのヘッダ・ファイルを参照して,削除したいセットのシンボリック識別子に対応する番号を見つけます。 次にその番号を delset ディレクティブに指定して,セットを削除します。

メッセージ・テキスト・ソース・ファイル appl.msg を使用するアプリケーションから,プログラム・モジュール a_mod.c を削除するとします。 また,a_mod.c だけが使用するメッセージは,シンボリック識別子が A_MOD_MSGS であるメッセージ・セットに含まれており,appl_msg.h ファイルは次の定義文を含むものとします。


.
.
.
#define A_MOD_MSGS 2
.
.
.

この場合,対応する delset ディレクティブは,次のようになります。

$delset 2   Removing A_MOD_MSG set for a_mod.c in appl.cat.

delset ディレクティブは,delset 単独でソース・ファイル中に指定することも,delset ディレクティブと set ディレクティブの両方を含む,より一般的なメッセージ・ソース・ファイルの一部として指定することもできます。 後者の場合には,複数のディレクティブが指定子に従って昇順に現れるようにします。

上記の例のディレクティブが単独でソース・ファイル kill_mod_a_msgs.msg に含まれ,既存のメッセージ・カタログはディレクトリ /usr/lib/nls/msg にあるものとします。 この場合,次の ksh ループを使用すると,すべてのロケールのカタログ内の,該当するメッセージ・セットを削除できます。

for i in /usr/lib/nls/msg/*/appl.cat
do
        gencat $i kill_mod_a_msgs.msg
done

3.1.3    メッセージ・エントリ

メッセージ・エントリの形式は次のとおりです。

msg_id message_text

msg_id は,次のいずれかです。

message_text は,プログラムが msg_id を使用して参照する文字列です。 メッセージ・エントリが現れる前に,quote ディレクティブによってクォート文字が使用可能になっている場合,その文字列はクォート文字で囲むことができます。 メッセージ・テキストをクォート文字で囲む利点については,3.1.1 項を参照してください。 quote ディレクティブの規則については,3.1.4 項で説明します。

message_text の合計長は,NL_TEXTMAX 定数で定義されている最大バイト数を超えることはできません。 NL_TEXTMAX 定数は,ファイル /usr/include/limits.h に定義されています。

次に,既存のメッセージ・カタログから特定のメッセージを削除するエントリについて説明します。 メッセージ・カタログの保守に関する一般的な説明については,3.4.3 項を参照してください。

既存のメッセージ・カタログから特定のメッセージを削除するには,削除したいメッセージの識別子だけからなる行を入力します。 このタイプのエントリを使用すると,以降のメッセージの順序に影響を与えずに,メッセージを削除できます。 メッセージの削除が正しく実行されるように,次のガイドラインに従ってください。

  1. 数値のメッセージ識別子を指定します。

    メッセージ・テキスト・ソース・ファイル内でシンボリック識別子を使用している場合は,mkcatdefs コマンドで最後にソース・ファイルを処理したときに生成されたメッセージ・ヘッダ・ファイルから,識別子に対応する番号を取得できます。 delset ディレクティブを使用してメッセージ・セットを削除する場合とは異なり,メッセージの削除にシンボリック・メッセージ識別子を使用しても,mkcatdefs はエラーを生成しません。 ただし,このシンボルの前に,カタログ内と同じ数のメッセージ・エントリがない場合は,誤ったメッセージを削除してしまいます。

  2. 識別子の後には改行以外の文字を置くことはできません。 msg_id の後にスペースやタブの区切り文字が続く場合,メッセージは削除されず,メッセージ・テキストが空文字列に変更されます。

  3. カタログにユーザ定義のメッセージ・セットが含まれている場合は,メッセージを削除するエントリの前に,適切な set ディレクティブがあることを確認します。 適切な set ディレクティブが前にない場合は,誤ったメッセージ・セットからメッセージが削除されることがあります。 ステップ 1 で説明したメッセージ識別子と同じ理由で,set ディレクティブにはシンボリック・セット識別子ではなく,数値セット識別子を使用します。

  4. セット内のすべてのメッセージを置き換えるのでなければ,gencat だけを使用してファイルを処理します。 セット内のすべてのメッセージを置き換えるには,mkcatdefs ユーティリティを使用します。 このユーティリティは,入力ファイル内で指定した個々の set ディレクティブの前に delset ディレクティブを生成します。 これはメッセージ・セット内のすべてのメッセージを置き換えたい場合には有用ですが,削除したいメッセージを 1 つか 2 つだけ入力ファイルに指定した場合には,意図したとおりの結果は得られません。

次の 2 つの例を考えてみます。

3.1.4    quote ディレクティブ

quote ディレクティブは,メッセージ・テキスト文字列を囲むためのクォート文字を有効にするか,無効にします。 quote ディレクティブの形式は次のとおりです。

$quote[ character]

変数 character は,メッセージ文字列の区切り記号として認識される文字です。 次の例の quote ディレクティブは,メッセージ文字列の区切り記号として二重引用符を指定します。

$quote "

quote ディレクティブを指定しないか,character を省略した場合は,メッセージ・テキスト文字列をクォート文字で囲むことはできません。

メッセージ・テキスト・ソース・ファイルには,複数の quote ディレクティブを含めることができます。 この場合,各ディレクティブは,ファイル内のそのディレクティブの後にあるメッセージ・エントリに影響します。 ただし,メッセージ・ファイルは通常,1 番目のメッセージ・エントリの前に quote ディレクティブを 1 つだけしか含みません。

3.1.5    コメント行

$ で始まり,その後にスペースまたはタブ文字が続く行は,コメントと見なされます。 mkcatdefs コマンドと gencat コマンドは,コメント行を無視します。

メッセージ・ファイルは,通常プログラマ以外の人が翻訳します。 そのため,メッセージを翻訳する人のために,コメント行にはリテラルや置換書式指定子を含む文字列を持つメッセージ・エントリの扱い方について,必ず説明を入れるようにします。 次に例を示します。

$ Note to translators: Translate only the text that is within
$ quotation marks ("text text text") on a given line.
$ If you need to continue your translation onto the next line,
$ type a backslash (\) before pressing the newline
$ (Return or Enter) key to finish the message.
$ For an example of line continuation, see the
$ line that starts with the message identifier E_COM_EXISTBADGE.

.
.
.
$ Note to translator: When users see the following message, a badge $ number appears in place of the %ld directive. $ You can move the %ld directive to another position $ in the translated message, but do not delete %ld or replace %ld with $ a word. $ E_COM_EXISTBADGE "Employee entry for badge number %ld \ already exists"
.
.
.
$ $ Note to translator: The item %2$d/%1$d/%3$d indicates month/day/year $ as expressed in decimal numbers; for example, 3/28/81. $ To improve the appropriateness of this date input format, you can change $ only the order of the date elements and the delimiter (/). $ For example, you can change the string to %1$d/%2$d/%3$d or $ %1$d.%2$d.%3$d to indicate day/month/year or day.month.year $ (28/3/81 or 28.3.81). $ I_SCR_IN_DATE_FMT "%2$d/%1$d/%3$d"
.
.
.

3.3 節で説明するように,Tru64 UNIX には翻訳者がメッセージ・ソース・ファイル内の翻訳可能なテキストを素早く見つけ出し,編集できるようにするための,trans ユーティリティが用意されています。 しかし,このユーティリティが使用できるとしても,メッセージの内容やプログラムの構文について,プログラマが情報を提供しなくてもいいことにはなりません。

3.1.6    メッセージ・スタイルのガイドライン

メッセージなどのテキスト文字列を英語で作成するときは,次の点を考慮する必要があります。

3.2    既存のプログラムからのメッセージ・テキストの抽出

既存のプログラムを国際化するときは,メッセージ文字列を抽出してメッセージ・ソース・ファイルに格納し,メッセージ・カタログからメッセージを取り出すように呼び出しを変更する,Tru64 UNIX のツールが利用できます。

ツール 説明
extract コマンド プログラム・ソース・ファイルからテキスト文字列を対話形式で抽出し,抽出した文字列をソース・メッセージ・ファイルへ書き込みます。 またこのコマンドは,抽出された各文字列を,catgets() 関数の呼び出しに置き換えます。
strextract コマンド 文字列をバッチ処理で抽出します。
strmerge コマンド strextract で作成されたメッセージ・ファイルから文字列を読み取り,プログラム・ソース内でこれらの文字列を catgets() 関数の呼び出しに置き換えます。

次の呼び出しを考えてみます。

printf("Hello, world\n");
 

extract コマンドを使用するか,あるいは,strextract コマンドと strmerge コマンドを続けて使用すると,以下の処理を実行できます。

コマンドへの入力が prog.c というプログラム・ソース・ファイルだとすると,コマンドは,prog.msg (メッセージ・テキスト・ソース・ファイル),nl_prog.c (プログラム・ソースの国際化バージョン),および prog.str (他のユーティリティから参照できる中間文字列ファイル) という 3 つのファイルを作成します。 このコマンドは,入力ソース・プログラムに加え,次のファイルを使用します。

extractstrextract,および strmerge コマンドは,プログラムの国際化に必要なすべての変更を行うわけではありません。 たとえば,変更されたプログラム・ソースを手作業で編集し,setlocale()catopen(),および catclose() の呼び出しを追加する必要があります。 さらに,マルチバイト文字変換ルーチンを追加したり (アジア系ロケールの場合),ユーザ定義ルーチンを改善して,ルーチンがメッセージ・カタログや langinfo データベースで定義されている値に応じてその動作を変更するようにしなければならないことがあります。

図 3-1 に,既存のプログラムを変更して,メッセージ・カタログを使用できるようにするためのファイルとツールを示します。 extract コマンド,strextract コマンド,および strmerge コマンドの使用方法については, extract(1)strextract(1)strmerge(1),および patterns(4) のリファレンス・ページを参照してください。

図 3-1:  メッセージ・カタログを使用できるようにするための,既存のプログラムの変換

3.3    メッセージ・ソース・ファイルの編集と翻訳

メッセージ・テキスト・ソース・ファイルの編集には,次の要件を満たす任意のテキスト・エディタが使用できます。

入力デバイスの要件は,西ヨーロッパ言語以外の言語では,地域化されたソフトウェア・サブセットに付属するターミナル・ドライバ,ロケール,フォントなどのコンポーネントによって満たされます。

edex,および vi エディタは,8 ビット・データやマルチバイト・データを透過的に処理するという要件を満たしています。 地域化されたソフトウェア・サブセットには,8 ビット文字やマルチバイト文字を処理できる拡張版のエディタ,たとえば Emacs などが含まれていることがあります。

Tru64 UNIX オペレーティング・システムは,メッセージ・テキスト・ソース・ファイルを別のロケールに翻訳する人のために,trans コマンドを提供しています。 このコマンドにはマルチウィンドウ機能があり,ファイルのオリジナル・バージョンと翻訳バージョンの両方が表示できます。 さらにこのコマンドは,ファイル内の翻訳可能な文字列を自動的にたどる機能も備えています。 詳細については, trans(1) のリファレンス・ページを参照してください。

メッセージの翻訳が正しく行われるように,メッセージ・テキスト・ソース・ファイルに含めるコメントの例については,3.1.5 項を参照してください。

翻訳されたメッセージ・テキスト・ソース・ファイルの例を参照するには,ディレクトリ /usr/examples/i18n/xpg4demo/*.msg ファイルを検索してください。

% cd /usr/examples/i18n/xpg4demo/
% ls *.msg

.
.
.

翻訳されたメッセージ・カタログは特定のロケールおよにエンコーディング・フォーマットに対応付けられています。 多くの言語で,複数のロケールおよびエンコーディング・フォーマットをサポートしています。 このため,このような言語のメッセージ・カタログは,複数のエンコーディング・フォーマットで用意する必要があります。 メッセージ・ソース・ファイルのコードセット変換にはコンバータが利用できますが,1 つの言語に対して複数のメッセージカタログを作成しインストールするのは効率的とはいえません。 このため,catopen() および catgets() 関数は,メッセージ・カタログの動的なコードセット変換をサポートしています。 /usr/share ディレクトリの .msg_conv-locale_name ファイルのセットが,メッセージ・カタログのコードセット変換を制御します。 詳細については, catopen(3) を参照してください。

3.4    メッセージ・カタログの生成

gencat コマンドは,1 つまたは複数のメッセージ・テキスト・ソース・ファイルからメッセージ・カタログを生成します。 メッセージ・セット,メッセージ・エントリ,あるいはその両方において,ソース・ファイルに数値識別子ではなくシンボル識別子が含まれている場合は,mkcatdefs コマンドを使用して,それらのソース・ファイルを前処理しなければなりません。 例 3-2 に,シンボリック識別子を持つメッセージ・テキスト・ソース・ファイルを,省略時のロケールと非省略時のロケールについて,対話形式で処理する例を示します。 この例の内容に基づいて,以降の項で各コマンドについて説明します。

例 3-2:  対話型操作によるメッセージ・カタログの生成

% mkcatdefs xpg4demo xpg4demo.msg | gencat xpg4demo.cat   [1]
mkcatdefs: xpg4demo_msg.h created    [2]
% setenv LANG fr_FR.ISO8859-1    [3]
% mkdir fr_FR    [4]
% mkcatdefs xpg4demo xpg4demo_fr_FR.msg -h | gencat \
fr_FR/xpg4demo.cat     [5]
mkcatdefs: no msg.h created    [6]

  1. mkcatdefs コマンドには次の名前を指定します。

    前処理されたメッセージ・ソースは,パイプを通して gencat コマンドに渡されます。 gencat コマンドには,メッセージ・カタログの名前を指定します。 [例に戻る]

  2. mkcatdefs コマンドは,作成したヘッダ・ファイルの名前を標準エラー出力に出力します。 このユーティリティは,ルート名に _msg.h を付加して,ヘッダ・ファイルの名前とします。 [例に戻る]

  3. 非省略時のロケール用のメッセージ・ファイルを生成するときは,LANG 環境変数に,メッセージ・カタログがサポートするロケール名を設定しなければなりません。 ここでは,fr_FR.ISO8859-1 です。 [例に戻る]

  4. プログラムからオープンされるメッセージ・カタログの名前は,ロケール名が違っても同じです。 そのため,メッセージ・カタログを格納するディレクトリをロケールごとに作成しなければなりません。 [例に戻る]

  5. この行は,地域化されたメッセージ・カタログを作成します。 mkcatdefs ユーティリティによって作成されるヘッダ・ファイルは,どのロケールでも同じです。 省略時のメッセージ・カタログ用のヘッダ・ファイルは,すでに作成されています。 そのため,この mkcatdefs コマンドでは -h フラグを指定して,新たなヘッダ・ファイルを作成しないようにします。 gencat コマンドに指定されたカタログは,一時的なロケール・ディレクトリに置かれます。 ユーザ・システムでは,このバージョンのカタログは,省略時ディレクトリの /usr/lib/nls/msg/fr_FR.ISO8859-1 に移動するか,アプリケーション固有のディレクトリに移動できます。 [例に戻る]

  6. mkcatdefs コマンドは,ヘッダ・ファイルが意図したとおりに作成されなかったことを通知します。 [例に戻る]

アプリケーションを構築するための makefile に,メッセージ・カタログの生成を統合する例については,/usr/examples/i18n/xpg4demo/Makefile ファイルを参照してください。

3.4.1    mkcatdefs コマンドの使用法

mkcatdefs コマンドは,1 つまたは複数のメッセージ・ソース・ファイルを前処理して,シンボリック識別子を数値定数に変換します。 このユーティリティは,次の機能を備えています。

シンボリック識別子の利点は,メッセージ・セット識別子やメッセージ識別子の引数を含む呼び出しをコーディングする際に,番号の代わりにシンボリック識別子を指定できることです。 シンボリック識別子を使用することにより,プログラム・ソース・コードが読みやすくなり,また,メッセージ・カタログ内でのセットとメッセージ・エントリの順序にコードが依存しなくなります。 mkcatdefs ユーティリティは,メッセージ・テキスト・ソース・ファイルを処理するたびに,セットとメッセージ・シンボルを番号に対応付けるヘッダ・ファイルを作成します。 そのため,メッセージ・ファイルの変更が完了すれば,プログラムは,新しいヘッダ・ファイルを使用してコンパイルするだけで更新できます。

注意

mkcatdefs コマンドには,この章でまだ説明していないオプションが 2 つあります。

-S オプションを使用すると,gencat コマンドへ渡される出力で,シンボリック名のサポートが有効になります。 dspmsg コマンド (シェル・スクリプト内で使用) にはこれに対応する -S オプションがあり,このサポートを使って構築されたメッセージ・カタログから,シンボリック名を用いてメッセージを取得できるようになっています。 (libc ライブラリの catgets() 関数は,X/Open UNIX 標準の XSH 仕様によって,実行時に,シンボルではなく数値の識別子を用いてカタログからメッセージを取得するように制限されています。)

-m オプションを指定すると,デフォルト・メッセージ文字列が自動的に生成され,シンボリック名が割り当てられます。 この機能により,dspmsg コマンドや catgets() の呼び出しに,カタログからメッセージが取得できない場合に表示するデフォルト・メッセージ文字列を指定する必要がなくなります。

これらのオプションについての詳細は, mkcatdefs(1) を参照してください。

メッセージ・セットとカタログ用のシンボリック識別子を定義する機能は,XSH 仕様には含まれていません。 このため,この仕様に準拠するすべてのオペレーティング・システムで mkcatdefs コマンドが利用できるわけではありません。 ただし,mkcatdefs コマンドを使用して作成されたソース・テキスト・メッセージ・ファイルとヘッダ・ファイルは,この仕様に準拠するシステム間でポータビリティがあります。

mkcatdefs コマンドは,現在処理しているメッセージ・ソース入力ストリーム中のシンボルの位置に基づいて,シンボル識別子に番号を割り当てます。 既存のカタログを変更するときは,mkcatdefs コマンドへのソース入力で指定するシンボルと,それらのシンボルに対応する,既存のメッセージ・カタログ内の数値を正しく対応させてください。

一般に,mkcatdefs ユーティリティは,メッセージ・カタログの一部を変更するときに使用するツールではなく,メッセージ・カタログ全体を再度作成するためのツールです。 次のガイドラインに従ってください。

3.4.2    gencat コマンドの使用法

gencat コマンドは,1 つまたは複数のメッセージ・テキスト・ソース・ファイルをマージして,メッセージ・カタログを生成します。 次に例を示します。

# gencat en_US/test_program.cat test_program_en_US.msg

gencat コマンドは,カタログ・パスで指定されたカタログが存在しない場合,メッセージ・カタログを新規に作成します。 カタログが存在する場合,このコマンドは指定されたメッセージ・テキスト・ソース・ファイル (複数ファイルも可) を使用して,そのカタログを変更します。 gencat コマンドは,メッセージ・ソース・データを標準入力から読み込むこともできます。 このため,mkcatdefs コマンドなどの別のプログラムの出力をパイプを通して gencat へ渡すときは,ソース・ファイルの引数を省略できます。

X/Open の UNIX 標準では,メッセージ・ソース・ファイルやカタログ・ファイルのファイル名拡張子は規定されていません。 通常,Tru64 UNIX システムでは,ソース・ファイルには .msg,カタログには .cat を拡張子として使用します。 gencat コマンドで作成されたメッセージ・カタログはバイナリ・データとしてエンコードされているため,エンコード・タイプの異なるシステム間ではポータビリティがありません。 mkcatdefs コマンドで前処理されたメッセージ・テキスト・ソース・ファイルは,X/Open UNIX CAE Specifications に準拠するシステム間でポータビリティがあります。

詳細については, gencat(1) のリファレンス・ページを参照してください。

3.4.3    メッセージ・カタログの設計と保守に関する留意点

メッセージ・セットとメッセージ・エントリは,メッセージ・カタログの 1 つのバージョン内での順序を表す番号により,実行時に識別されます。 既存のカタログ内のメッセージ・セットやエントリを追加したり削除する場合,メッセージを識別する順序指定子を変えないように注意が必要です。

"Enter street address:" という英文テキストのメッセージが,メッセージ・カタログのオリジナル・バージョンの生成時には 3 : 10 (3 番目のメッセージ・セットの 10 番目のメッセージ) で識別されたとします。 gencat コマンドに入力されるメッセージ・ソース・ファイルで次のいずれかの操作を行った場合,新しいバージョンのカタログではこのメッセージの識別番号が変わります。

次の 2 つのプログラム・セグメントのように,順序についての制限事項を翻訳者に対して説明するコメントを,コードに追加することを考慮してください。

$ Note - Do not reorder message descriptors for columns.
 
S_COM_LIST_ROW         "%5d        %20s     %20s    %4s     %9s\n"
 
 

$ The first descriptor must always be displayed at the beginning of error messages.
$ The second descriptor contains the first name.
$ The third descriptor contains the surname.
 
S_COM_LIST_ERROR      "%1$s: Error badge number for $2$s   %3$s  incorrect\n"
 

メッセージを数値識別子で参照するプログラム・ソースの場合,メッセージ・セットやメッセージ・エントリの位置を変更すると,メッセージを参照するプログラム呼び出しも変更しなければなりません。 メッセージをシンボリック識別子で参照するプログラム・ソース・ファイルの場合,エントリ位置の変更に伴う保守作業は,各モジュールで大幅に低減されます。 つまり,どのプログラム・モジュールも,mkcatdefs ユーティリティによって生成された新しいヘッダ・ファイルでコンパイルすることにより,メッセージ・カタログの新しいバージョンに同期させることができます。

プログラム・ソースをコンパイルして,新しいメッセージ・カタログに同期させる機能を使用しても,同じメッセージ・カタログを複数のソース・ファイルが参照するような複雑なアプリケーションの問題には対処できません。 そのようなアプリケーションでは,モジュールごとの保守作業を可能にすることが一般的な目標となります。 つまり,アプリケーションが一旦エンド・ユーザ・サイトにインストールされた後は,アプリケーションの全モジュールを再コンパイルして再インストールするのではなく,個別のモジュールとそれに関連するメッセージ・カタログの更新が可能でなければなりません。 この目標を達成するためには,さまざまな設計手法が考えられますが,以下に説明する設計例を参考にして,サイトでのアプリケーションの開発と保守に最適なメッセージ・システムの設計方針を決定してください。

メッセージ・ファイルの保守作業を簡単にするには,次のガイドラインを考慮してください。

3.5    メッセージとロケール・データの表示

メッセージ・カタログを作成した後で,意図したとおりのメッセージがカタログに含まれ,メッセージとメッセージ・セットが適切な順序になっていることを確認するために,カタログの内容を表示することができます。 アプリケーションには,プログラムと同様に,実行時にロケール設定を判定し,ロケールに依存したデータを取り出し,さらに,ロケールに依存した方法でメッセージを表示するのに必要なスクリプトを含めることもできます。

以下のリストでは,メッセージ・カタログ内のメッセージを表示する dspcat コマンド,dspmsg コマンドおよび printf コマンドと,現在のロケール情報を表示する locale コマンドについて説明します。

上記のコマンドについては, dspcat(1)dspmsg(1)printf(1),および locale(1) のリファレンス・ページを参照してください。

3.6    プログラムからのメッセージ・カタログへのアクセス

プログラムは,メッセージ・カタログを参照するために,次の関数を呼び出します。

メッセージ・カタログは通常,NLSPATH 環境変数の設定に従って検索されます。 以降の項では,この変数と,上記の関数呼び出しについて説明します。

3.6.1    メッセージ・カタログのオープン

プログラムは catopen() 関数を呼び出して,メッセージ・カタログをオープンします。 次に例を示します。

#include <locale.h>
#include <nl_types.h>

.
.
.
nl_catd MsgCat;
.
.
.
setlocale(LC_ALL, "");
.
.
.
MsgCat = catopen("new_application.cat", NL_CAT_LOCALE);

この例では,catopen() 関数はメッセージ・カタログ記述子を MsgCat 変数に返します。 記述子が格納されるこの変数は,nl_catd 型として宣言されています。 catopen() 関数と nl_catd 型は,ヘッダ・ファイル /usr/include/nl_types.h で定義されています。 プログラムでは,このヘッダ・ファイルをインクルードしなければなりません。 catopen() の呼び出しには,次の引数が必要です。

メッセージ・カタログの名前とインストール位置は,システムによって異なります。 このため,The Open Group の UNIX 標準では,プログラムが実行されるシステム上でメッセージ・カタログの検索パスとパス名の形式を定義するための NLSPATH 環境変数を規定しています。 catopen() 関数は,プログラムがオープンしたカタログを見つけるために,実行時にこの変数の設定値を参照します。 アプリケーションのメッセージ・カタログをユーザ・システム上の通常の位置にインストールしない場合,アプリケーションのスタートアップ手順で,NLSPATH の現在の検索パスの前に適切なパス名を付加する必要があります。

NLSPATH 環境変数に値を設定する構文は,次のとおりです。

NLSPATH= [ [ [:] ] [ /directory ] [ [ [/] ] [ substitution-field ] [ literal ] ] ... [ [:]alternate_pathname ] ...]

先頭にあるコロン (:) と 2 つ連続するコロン (::) は,現在のディレクトリを示します。 これ以外のコロンは,パス名の区切り文字として扱われます。 検索パス内の各パス名は,次の構成要素から組み立てられます。

LC_MESSAGES 設定,NLSPATH 設定,および catopen() 関数の相互関係を明確にするために,次のような条件を考えてみます。

上記のような条件では,catopen() 関数は,実行時に次に示すパス名の順にカタログを検索します。

  1. xpg4demo.cat

  2. ./fr_FR/xpg4demo.cat

  3. /usr/kits/xpg4demo/msg/fr_FR/xpg4demo.cat

  4. /usr/lib/nls/msg/fr_FR.ISO8859-1/xpg4demo.cat

実行時に発生した問題の原因を調べるときは,設定されていない変数があった場合の catopen() の動作を考察してみます。

LC_MESSAGES が (直接または LANG 変数を通して) 設定されていない場合,%L および %l のフィールドは値 C (LC_MESSAGES のデフォルト・ロケール) となり,%t および %c の置換フィールドは検索パスから削除されます。 この場合,catopen() は次の順序でカタログを検索します。

  1. xpg4demo.cat

  2. ./C_/xpg4demo.cat

  3. /usr/kits/xpg4demo/msg/C/xpg4demo.cat

  4. /usr/lib/nls/msg/C/xpg4demo.cat

LC_MESSAGES は設定されているが,NLSPATH 変数が設定されていない場合,catopen() 関数は,ベンダが定義する省略時の検索パスを使用してカタログを検索します。 Tru64 UNIX システムでは,省略時の検索パスは /usr/lib/nls/msg/%L/%N: です。 この例では,省略時の設定により,catopen() の検索順序は次のようになります。

  1. /usr/lib/nls/msg/fr_FR.ISO8859-1/xpg4demo.cat

  2. xpg4demo.cat

最後に,LC_MESSAGESNLSPATH のどちらも設定されていない場合,catopen() は次の順序で検索を実行します。

  1. /usr/lib/nls/msg/xpg4demo.cat

  2. ./xpg4demo.cat

該当するロケールのメッセージ・カタログが見つからなかった場合,catopen() 関数は次に /usr/share/.msg_conv-locale-name ファイルが存在するかどうか確認します。 このファイルは,メッセージ・カタログが用意されている別のロケールを指定するためのファイルです。 このファイルが見つかると,利用できるメッセージ・カタログがオープンされ,適切なコードセット変換コンバータが起動され,LC_MESSAGES に設定されているコードセットにメッセージが変換されます。 たとえば,ISO8859-1 フォーマットのフランス語の catalog_name が存在し,.msg_conv-fr_FR.UTF-8 ファイルでそれを指定している場合,このカタログがオープンされ UTF-8 フォーマットにメッセージが変換されます。

catopen() 関数は,指定されたメッセージ・カタログがオープンできない場合,エラー・ステータスは返しません。 プログラムの性能を向上するために,カタログを参照する最初の catgets() 呼び出しが実行されるまで,カタログは実際にはオープンされません。 catopen() の呼び出し時に,ファイルのオープンに失敗したことをプログラムで検出する必要がある場合は,catopen() を呼び出した直後に catgets() を呼び出さなければなりません。 これにより,catgets() の呼び出しでエラーが返されたときに,プログラムを終了させることができます。 メッセージ・カタログからメッセージを取り出す前に多くの処理を実行するプログラムでは,早い段階で catgets() を呼び出すようにします。 ただし,カタログのオープンに成功しないかぎり,ユーザの母国語に翻訳されたエラー・メッセージを取り出すことは不可能なため,この特別なエラーをユーザに通知することには問題があります。

catopen() 関数についての詳細は, catopen(3) を参照してください。

注意

実効ユーザ ID が root に設定されているプロセスから呼び出された場合,catopen() 関数は NLSPATH の設定を無視し,パス /usr/lib/nls/msg/%L/%N を使用してメッセージ・カタログを検索します。 プログラムが実効ユーザ ID を root に設定して実行している場合は,次の処理のいずれかを実行しなければなりません。

この制約は,スパーユーザとしてログインしているユーザが起動するプログラムには適用されません。 この制約は,setuid() 呼び出しを実行して,実効ユーザ ID が root になるようなサブプロセスを生成するプログラムにのみ適用されます。

3.6.2    メッセージ・カタログのクローズ

catclose() 関数は,メッセージ・カタログをクローズします。 この関数には引数が 1 つあり,catopen() 関数から返されたカタログ記述子を指定します。 次に例を示します。

(void) catclose(MsgCat);

exit() 関数もまた,プロセスの終了時にオープンされているメッセージ・カタログをクローズします。

3.6.3    プログラム・メッセージの読み取り

catgets() 関数は,メッセージをプログラムに読み込みます。 この関数は次の引数を取ります。

一般に,catgets() 関数は他のルーチンと組み合わせて使用します。 その場合,この関数は直接呼び出すこともできますが,プログラム定義のマクロとして呼び出すこともできます。 次に示すサンプル・プログラム xpg4demo のコードでは,特定のメッセージ・セットにアクセスするマクロを定義し,そのマクロを printf() ルーチンの引数として使用します。


.
.
.
#define GetMsg(id, defmsg)\ catgets(MsgCat, MSGInfo, id, defmsg)
.
.
.
printf(GetMsg(I_COM_DISP_LIST_FMT, "%6ld %20S %-30S %3S %10s\n"), emp->badge_num, emp->first_name, emp->surname, emp->cost_center, buf);
.
.
.

詳細については, catgets(3) のリファレンス・ページを参照してください。

注意

gettxt() 関数も,メッセージ・カタログからメッセージを読み取ります。 この関数は System V Interface Definition (SVID) には含まれていますが,X/Open の UNIX 標準では規定されていません。 この関数については, gettxt(3) のリファレンス・ページを参照してください。