[Top] [Contents] [Index] [ ? ]

GNU gettextユーティリティ

1. イントロダクション  
2. POファイルとPOモードの基本  
3. プログラムソースの準備  
4. 最初のPOファイルの準備  
5. 既存のPOファイルの更新  
6. MOファイルの作成  
7. ユーザとしての視点  
8. プログラマとしての視点  
9. 翻訳者としての視点  
10. 保守担当者としての視点  
11. 結論  

A. 国家コード  ISO 639国家コード

 -- The Detailed Node Listing ---

イントロダクション

1.1 GNU gettextの目的  
1.2 国際化, 地域化, およびそれに類するもの  
1.3 ネイティブランゲージサポートの各側面  
1.4 ファイルの翻訳の流れ  
1.5 GNU gettextの概要  

POファイルとPOモードの基本

2.1 GNU gettextのインストールを完了する  
2.2 POファイルのフォーマット  
2.3 POモードの主要なコマンド  
2.4 エントリの位置  
2.5 エントリ内の文字列の正規化  

プログラムソースの準備

3.1 gettextの処理をトリガする  
3.2 ソース中でのマーク付けの方法  
3.3 翻訳対象文字列のマーク付け  
3.4 続く文字列に関して何かを伝えること  
3.5 特別な翻訳対象文字列  

最初のPOファイルの準備

4.1 xgettextプログラムの起動  
4.2 Cソースの文脈  
4.3 翻訳要約機能の使用  

既存のPOファイルの更新

5.1 msgmergeプログラムの起動  
5.2 翻訳済みエントリ  
5.3 曖昧な翻訳エントリ  
5.4 未翻訳エントリ  
5.5 廃止エントリ  
5.6 翻訳の修正  
5.7 コメントの修正  
5.8 補助POファイルを参考にする  

MOファイルの作成

6.1 msgfmtプログラムの起動  
6.2 GNU MOファイルのフォーマット  

ユーザとしての視点

7.1 現在の`ABOUT-NLS'  
7.2 インストーラへの魔法  
7.3 エンドユーザへの魔法  

プログラマとしての視点

8.1 catgetsについて  
8.2 gettextについて  
8.3 二つのインターフェースの比較  
8.4 独自のプログラムでlibintl.aを使う  
8.5 Being a gettext grok  
8.6 プログラマの章についての一時的なメモ  

catgets について

8.1.1 インターフェース  catgetsのインターフェース
8.1.2 catgetsインターフェースにおける問題点とは?!  

gettext について

8.2.1 インターフェース  
8.2.2 曖昧さの解決  
8.2.3 メッセージカタログファイルの所在  
8.2.4 gettext関数群の最適化  

プログラマの章に関する一時的な情報

8.6.1 一時的な情報 - 二つの実装  
8.6.2 一時的な情報 - catgetsについて  
8.6.3 一時的な情報 - なぜ一つの実装なのか  
8.6.4 一時的な情報 - ノート  

翻訳者としての視点

9.1 イントロダクション0  
9.2 イントロダクション1  
9.3 議論  
9.4 組織  
9.5 情報の流れ  

組織化

9.4.1 中央による調整  
9.4.2 国家チーム  
9.4.3 メーリングリスト  

National Teams

9.4.2.1 サブカルチャー  
9.4.2.2 組織化へのアイディア  

保守担当者としての視点

10.1 フラットまたはノンフラットなディレクトリ構造  
10.2 事前に必要な作業  
10.3 gettextizeプログラムの起動  
10.4 作成するか変更しなければならないファイル  

作成または修正する必要があるファイル

10.4.1 `po/'以下の`POTFILES.in'  
10.4.2 トップレベルに存在する`configure.in'  
10.4.3 トップレベルに存在する`aclocal.m4'  
10.4.4 トップレベルに存在する`acconfig.h'  
10.4.5 トップレベルに存在する`Makefile.in'  
10.4.6 `src/'以下の`Makefile.in'  

結論

11.1 GNU gettextの歴史  
11.2 参考文献  


1. イントロダクション

このマニュアルはまだドラフト状態であり、幾つかのセクションはまだ空 かそれに近い状態です。我々は作成が遅れている部分を統合しながら、他の情報源 (特に電子メールのフォルダ)から適切な統合が遅れている資料を取り込み続けてい ます。

このマニュアルでは、プログラマや保守担当者について話すときには を、翻訳者として彼女を、翻訳済みプログラムをインストールする人 やエンドユーザとして彼らという単語を使用すします。これはこのドキュ メントを明快にするためだけのものであり、決して男性や女性が何から の役割を果たすのにより適しているということを暗示するものではありません。 そしてまた、あなたが考える通り、GNU gettextは性別や人種、宗教や 国籍を問わずコンピュータを扱う人々にとってとても便利なものなのです。

この章では GNU gettextの創造と、フリーの翻訳プロジェクト (Translation Project)が目指すゴールについて説明します。そしてまた、ネイ ティブランゲージ(Native Language)のサポートを取り巻く幾つかの幅広いコン セプトについて説明し、(プログラムに適用可能なものとしての)国または文化的 な特徴に関するメッセージ翻訳の位置付けについて規定します。同様に、ファイ ルの翻訳の流れと、それらのファイルの作成から後々の保守のサイクルに至るま での各種ツールの関係についても説明します。

提案や訂正については、以下へ連絡して下さい。

 
Internet address:
    bug-gnu-utils@prep.ai.mit.edu

マニュアルの版番号と、メッセージを送信した日付を付記して下さい。

1.1 GNU gettextの目的  
1.2 国際化, 地域化, およびそれに類するもの  
1.3 ネイティブランゲージサポートの各側面  
1.4 ファイルの翻訳の流れ  
1.5 GNU gettextの概要  


1.1 GNU gettextの目的

通常、プログラムとドキュメントは英語で記述されます。また、プログラムがユー ザと対話する際にも英語が用いられます。これは GNU によるソフトウェアばかり ではなく、多くの商用ソフトウェアやフリーソフトウェアでも同様です。共通言語 (common language)は、開発者(developer)や保守担当者(maintainer)が全ての国の ユーザとコミュニケーションを取るためには実に便利です。その一方で、多くの人々 は母国語ほど上手には英語を使えません。そして日々の作業でも出来ることなら母 国語が使えることを望むでしょう。多くの人はコンピュータの画面には主に母国語 が表示され、英語は必要最小限であることが望ましいと考えています。

しかしながら多くの人々にとって、それについて考える時間を費やすことさえも価 値のないことだと考えられるほど、この夢は実現には遠いものだったかもしれませ ん。彼らはそんな夢が実現するなんて考えてもみなかったのです。それでも、多く の人は希望を捨てず、彼らの組織を結成しました。「翻訳プロジェクト(The Translation Project)」は、この希望を実現するためのものであり、プログラムの 真のマルチリンガルセット(multi-lingual set)の達成に至るためのよい機会です。

GNU gettextは、様々な他のステップを踏み出すための財産となる、翻訳プ ロジェクトの大切な第一歩です。このパッケージはプログラマ、翻訳者そして全て のユーザに、統合されたツール群とドキュメント類を提供します。特に、GNU gettextユーティリティは他のGNUパッケージがマルチリンガルなメッセー ジを扱えるようなフレームワークを提供します。これらのツールには、メッセージ カタログをサポートするプログラムの作成方法の定義、メッセージカタログのディ レクトリ及びファイル群の命名規則、翻訳済みメッセージを取得するためのランタ イムライブラリ、様々な方法で翻訳された文字列の集合を取り扱うための独立した プログラム群を含んでいます。これらを準備したり最新のものにするためには、 GNU Emacs用の特別なモードもまた役に立つでしょう。

GNU gettextはプログラムソースに対する国際化の影響が可能な限り小さく、 そして目立ちにくくなるようにデザインされています。プログラムのソースを眺め る際、国際化の影響がごく僅かか、あるいは少なくとも影響が小さいと思えるので あれば、国際化はより成功しやすいことでしょう。

翻訳プロジェクトはまた、その構造及び方法を伝達するための媒体としてGNU gettextディストリビューションを使用しています。これは gettextを記述する厳密な専門的事項となります。これによって、翻訳者は 翻訳の対象となるもの全てを可能な限り一ヶ所で見つけることができるようになり ます。この補助ドキュメントも、GNU gettextがどのように翻訳プロジェク トの残作業に関連しているかについてを理解するために、その結果として 大きな一枚絵を垣間見るために、プログラマ及び好奇心の強いユーザの役 に立つことでしょう。


1.2 国際化, 地域化, およびそれに類するもの

プログラムでのネイティブランゲージサポートについて議論するときは、常に二 つの厳密な意味を持つ長い単語が登場します。internationalizationlocalization、この二つの単語には、このドキュメントのためにここで 説明するだけの価値があります。この二つの長い単語を繰り返し繰り返し書くこ とに疲れてしまった多くの人々は、それをきちんと書く代わりに、先頭と最後の 文字を残し、その間にある文字列をその長さで置き換えてi18nl10n と書くようにしました。しかしこのマニュアルでは物事を明確にす るために、そのたびにきちんと正確に書くことにします...

国際化(internationalization)によって、プログラムまたはパッケージとな るプログラム群における処理は複数の言語を認識しサポートできるようになり ます。これは、プログラムから英語の文字列やその他の英語特有の慣習を切り離し て、その代わりに同じことを行う一般的な方法を考慮するという点で、一般化のプ ロセスであると言えます。 プログラムの開発者は、自分が作成するプログラムに 対して様々な国際化の技法を使うことができ、そのうちの幾つかは標準的なものと なっています。gettextはこれらの標準の一つを提案するものです。 See section 8. プログラマとしての視点

地域化(localization)によって、既に国際化されているプログラム群にお ける操作において、プログラムに(そのプログラムが)必要とする全ての情報を与え ることにより、プログラムに対する入力やプログラムからの出力をあるネイティブ ランゲージや文化的特性(cultual habits)について正しく取り扱うことができるよ うになります。国際化されたプログラムで既に実装された一般的な手法を、特殊な 方法で使用するという点で、これは特殊化のプロセスであると言えます。プログラ ミング環境には、プログラマが実行時に設定を調整出来るような幾つかの関数が用 意されています。ある国で使われる言語を対象とした全ての関連した翻訳、そして それと共に使われるその国における文化的特性の固有の集合を、その言語、国に対 する ロカール(locale)といいます。ユーザはプログラムを実行する前に、 どのロカールを使用するのかを示すために特殊な環境変数に適切な値を設定します。 これによってプログラムの地域化が行われます。

実際のところ、ロカールによるロカールメッセージサポートは、特定のロカールを 構成する文化的データ(cultural data)の要素の一つに過ぎません。国際化された ソフトウェアを開発するプログラマの手助けをしたり、ある特定のロカールに属す るデータへのアクセスを実行するための、完全なルーチン群や関数群が存在します。 今、ある人があるロカールを参照するとすれば、それらの関数群やルーチン群は該 当するロカールに格納されているデータを参照しています。同様に、あるプログラ マが「ロカールルーチン群にアクセスする」と言った場合、それらの関数群やルー チン群とはロカールの情報全てにアクセスできるルーチン群の完全な集合 (complete suite)のこととなります。

プログラム中で複数の言語を使用可能とする、国際化と地域化の両方を包含する特 徴及びその活動全体を表現するために、ネイティブランゲージサポート、ま たは稀にNLSという表現が使われます。要約すれば、国際化とは地域化を可能とす るものを越えた処理であると言えるでしょう。

また、非常に大雑把に言ってしまえば、マルチリンガルメッセージを実現する際、 国際化は一般的にプログラマが注意することであり、地域化は一般に翻訳者が注意 することとなります。


1.3 ネイティブランゲージサポートの各側面

完全なマルチリンガルのディストリビューションのためには、出力メッセージ以外 にも翻訳すべき事柄があります。

既に強調したように、メッセージの翻訳はロカールの一側面でしかありません。他 の国際化の側面は現在のGNU gettextではまだサポートされていませんが、 おそらく将来のバージョンではサポートされることになるでしょう。その国の文化 的慣習(cultual conventions)を定義するために必要な属性には様々な種類があり ます。これらの属性にはその国の言語、日付や時刻の表記方法、数値の表記方法、 通貨記号などが含まれます。これらのローカルルールは国のロカールと呼 ばれます。ロカールは、その国の独自属性(native attributes)をサポートするた めに必要となる知識を表わしたものです。

国ごとに大きく異なり得るため、ロカールが必ず記述しなければならない定義項目 が幾つか存在します。以下に挙げるリストは、ロカールに関係する他のタスクの適 切な文脈にマルチリンガルメッセージを配置するときの助けとなるものであり、ま た同様に、GNU gettextが最終的には取り掛かるかもしれないその他の領 域を表わすものです。

文字とコードセット

米国全土と英語圏において、もっとも一般的に使われているコードセットは ASCIIコードセットです。しかしながら、ASCIIコードセットでは対応できないよう な沢山の文字を使用する必要があるロカールもあります。8ビットのISO 8859-1コードセットは主なヨーロッパ圏言語を取り扱うために必要となる特別な 文字のほとんどを含んでいます。しかし多くの場合、ISO 8859-1フォントは 妥当なものではありません。このため、各地域によってどのコードセットを使う必 要があるのかを明示する必要があり、コードセットに対処するための適切な文字取 扱いルーチン(character handling routines)を準備する必要があります。

通貨

通貨記号は、それが記号として使われるときの位置と同じ程、国ごとによってに異 なるものです。ソフトウェアは、ロカール毎の通貨記号に対する方法をきちんと扱 えるようにする必要があります。

日付と時刻

日付のフォーマットはロカールによって様々です。例えば、1994年のクリスマスを 米国では12/25/94と書きますが、オーストラリアでは25/12/94と書きます。その他 の国々ではおそらくISO 8061で定められた日付記法などが使われるでしょう。

時刻はhh:mmhh.mmなどと記述されます。幾つかのロ カールは午前 / 午後の指定を使用せずに24時間制で記述するようになっています。 さらに、夏時間の性質や夏時間が実施される期間は国ごとによって大きく違います。

数値

数値は各ロカールごとに異なる表記法を取ります。例えば、次の数はそれぞれのロ カールごとの表記法によって正しく記述されたものです。

 
12,345.67       英語圏
12.345,67       フランス
1,2345.67       アジア

一部のプログラムではもっと進んでいて、異なる単位系、例えば英単位(English units)やメートル法、あるいは数値をまるまる綴るといった方法のような、様々な 単位系を使用するかもしれません。

メッセージ

もっとも大切なのは、ロカール中の言語サポートです。開発者にとってもユーザに とっても、ソフトウェアがユーザと対話する際の言語を簡単に変更できること、そ れこそがGNU gettextが提供するものです。

近い将来に、メッセージハンドリング以外のロカール構成要素が他のパッケージ 中で使用可能になるということは考えられません。なぜなら、ほとんどの最近の システムでは、そのシステムに欠けているロカール中の構成要素の少なくとも幾 つかを、多少なりとも合理的にサポートしているからです。もう一点は、GNU libcとLinuxが、サポートが欠けているシステムにおいて利用できるよ うな新しく完全で合理的なロカール機能全体の実装を実現するからです。


1.4 ファイルの翻訳の流れ

`.po'ファイルの「PO」とは「Portable Object」を意味します。これは `.mo'ファイルと区別するためです。なお、「MO」は「Machine Object」 に由来します。この考えは、POファイルのフォーマットと同様、Uniforumで開発さ れたNLS標準、そしてSolarisにおいてSunが実装した方法から来ています。

POファイルは人間が読み書きすることを前提にしています。特定のターゲットとさ れた言語用に、指定されたパッケージ内の元々の文字列と、翻訳後の文字列を含ん でいます。対象の言語一つに一つのPOファイルが用意されます。パッケージが複数 の言語をサポートする場合、サポートする言語の一つずつにそれぞれ対応するPOファ イルが必要です。これらのPOファイルはxgettextプログラムによって生成 されるものがベストであり、msgmergeプログラムによって更新されます。 xgettextプログラムはCソースファイル群からマーク付けされたメッセージ を抽出し、空の変換後文字列で初期化されたPOファイルを作成します。 msgmergeプログラムははPOファイルとそれにに対応するソースとの調整を 行います。使われなくなったエントリをコメントアウトし、新しいエントリを追加 し、ソース行との対応を更新します。「`.pot'」で終るファイルはPOファイ ルフォーマットに従った基本翻訳ファイルです。また、「`.pox'」で終るファ イルはしばしば一時的に使用するPOファイルとして扱われます。

MOファイルは、通常はバイナリファイルで、プログラムによって読み込まれます。 既に幾つかのシステムでは、システムに付属しているネイティブランゲージサポー トの一部として、MOファイルの作成や取り扱いをサポートしています。しかしMOファ イルのフォーマットはしばしばシステム毎に異なるものであり、移植性に欠けます。 エンドユーザやインストーラはファイルの拡張子として`.mo'を使う必要はあ りませんが、システムライブラリもこれらのファイルにアクセスするときはこの拡 張子を使うので、同じように矛盾なく使用出来るでしょう。GNU gettextと 既にシステムに提供されているツール群との間に互換性があるのなら、必然的に MOファイルの作成にはシステムが用意したそれらのツールを使えることになるでしょ う。しかしそれらのツールが見つからないか、または使えないようであれば、 GNU gettextがそのシステムにおけるMOファイルの作成手段となり、MOファ イルのフォーマットとなります。`.gmo'で終わっている名前のファイルは実 はMOファイルで、これらのファイルがGNUフォーマットを使っていることを示して います。


1.5 GNU gettextの概要

以下のダイアグラムは、GNU gettextによって操作されるファイルと、その ファイルを使って動作するツールの間の関係をまとめたものです。より詳細な説明 が後に続きますが、この図から目を放さないで下さい。この関係の正確な理解は、 プログラマにも翻訳者にも保守担当者にも役に立つことでしょう。

 
オリジナルのCソース ---> POモード ---> マーク付きのCソース ---.
                                                              |
              .---------<--- GNU gettextライブラリ            |
.--- make <---+                                               |
|             `---------<--------------------+----------------'
|                                            |
|   .-----<--- PACKAGE.pot <--- xgettext <---'   .---<----- 要約PO 
|   |                                            |             ^
|   |                                            `---.         |
|   `---.                                            +---> POモード ----.
|       +----> msgmerge -------> LANG.pox --->-------'                  |
|   .---'                                                               |
|   |                                                                   |
|   `-------------<---------------.                                     |
|                                 +--- LANG.po <--- 新しいLANG.pox <----'
|   .--- LANG.gmo <--- msgfmt <---'
|   |
|   `---> install ---> /.../LANG/PACKAGE.mo ---.
|                                              +---> "こんにちは、世界!"
`-------> install ---> /.../bin/PROGRAM -------'

`POモード'はこの図で二回登場しています。POモードは好きなエディタを使っ た単なる「手作業による編集」と読むこともできますが、GNU Emacsを使っている のであれば、POファイルを編集したり修正したりするのに便利な環境であるPOモー ドというものが使えます。POファイルを編集している間、POモードはPOファイルを 生成する元となるCのプログラムソース群を参照するのと同じくらい簡単に、補助 POファイル(auxiliary PO file)や要約POファイル(compendium PO file)をブラウ ズできます。このモードには、プログラム中の文字列を翻訳可能であるとマーク付 けしたり、エラーを表示するためにPOファイルの当該行にジャンプすることによっ てPOファイルの確認を行うといった、幾つかの特別な機能があります。

プログラマとしてGNU gettextを導入する第一段階は、Cソースの中にある 文字列が翻訳すべきものなのか翻訳しないでおくものなのかを確認することです。 この単調で退屈な作業はEmacsのPOモードを使うことで幾分楽にはなりますが、使 い慣れた様々な方法でCソースを変更していくこともできます。それ以外にも、翻 訳ライブラリ(translation library)を適切に初期化するために、単純かつ標準的 な変更が必要となります。これに関する詳細は @xref{sources}を参照して下さい。

新しくソフトウェアを書くにあたって、ソフトウェアを書きながら文字列にマーク 付けすることはもちろん可能ですし、またそうすべきです。gettextのアプ ローチはこれをとても簡単にします。以下に挙げる行を、各ファイルの先頭または 中心となるヘッダファイルに記述します。

 
#define _(String) (String)
#define N_(String) (String)
#define textdomain(Domain)
#define bindtextdomain(Package, Directory)

これによってソースの国際化の準備が出来ます。gettextライブラリを使う 局面に至ったと思ったら、単純にこれらの定義を取り去り、`libintl.h'を インクルードして`libintl.a'をリンクします。変更する必要があるのはそ れだけです。

Cソースを変更するとxgettextプログラムが全ての翻訳可能な文字列を検索 して展開し、それを元に最初のPOファイルが作成されます。この `package.pot'ファイルはプログラムの全てのオリジナル文字列を含ん でいます。それはそれぞれの文字列がCソース中のどこで使われているかを示す正 確なポインタの集合です。全ての翻訳は空に設定されています。`.pot'tという文字はそれがPOファイルのテンプレートであって、どの言語に対し ても使うことができるものであることを示しています(xgettextプログラム の呼び出しに関しての詳細についてはSee section 4.1 xgettextプログラムの起動)。もしあなた が本当に不精なのでしたら、すぐにたくさん働いてディストリビューショ ン全体のセットアップを行うことに興味を持っているかもしれません (see section 10. 保守担当者としての視点)。そうすることにより、今やmakeがあなたのために 適切なものを自動的に生成するので、あなた自身はgettextコマンドをタイ プせずにすむようになります!

一回目の処理では、`lang.po'はまだ存在しませんので、 msgmergeのステップがスキップされて、単純に `package.pot'`lang.pox'にコピーするだけになるでしょ う。ここで、langは目的とする言語を表わします。

それからメッセージの最初の翻訳となります。翻訳はそれ自身が問題であり、未だ に、このマニュアルの水準をはるかに越える複雑さを備えた人間のみが出来ること なのです。にも関らず、このマニュアルの他の章で幾つかのヒントが与えられてい ます(see section 9. 翻訳者としての視点)。同様にあなたは、翻訳チームへのコンタクトの仕方 についての指標や、そのチームに所属して、あなたが関心を持っているのと同じ言 語をターゲットとしている人と翻訳を共有するための指標を見つけられるでしょう。

翻訳メッセージをPOファイル`lang.pox'に追加している間に、もしあ なたがGNU Emacsを便利に使えないのなら、あなたが自分で完全にPOファイルフォー マットと、クォート処理(quoting conventions)(see section 2.2 POファイルのフォーマット)を考慮するこ とを保証しなければなりません。これは決して不可能な作業ではなく、既に UniforumやSolarisで多くの人がPOファイルを扱うのに行っているやり方です。一 方、GNU EmacsのPOモードを使うのでしたら、POファイルフォーマットのほとんど の詳細部分は(Emacsが)面倒を見てくれますが、その代わりにPOモードそれ自体に ついて慣れておく必要があります。主なPOモードコマンド(see section 2.3 POモードの主要なコマンド)について、エントリ間の移動の仕方(see section 2.4 エントリの位置)と未 翻訳エントリの扱い方(see section 5.4 未翻訳エントリ)は知っておいたほうが良い でしょう。

もし一部の共通翻訳(common translations)が既に要約POファイル(compendium PO file)に保存されているのでしたら、翻訳者はPOモードを、要約から未翻訳エン トリを初期化するため、また選択した翻訳語を要約にセーブしてアップデートする ために使用することができます(see section 4.3 翻訳要約機能の使用)。要約ファイルは、翻訳チー ムのメンバーの間で交換するためのものです。

プログラムやプログラムのパッケージは、本質的に動的なものです。ユーザはバグ レポートや改良案を書き、保守担当者はさまざま方法でプログラムを修正してそれ に反応します。パッケージが既に国際化されているという事実が、保守担当者に新 しい文字列を追加したり既に翻訳した文字列を変更することを恐がらせるようにさ せるべきではありません。彼らは自分のベストな仕事を行うだけです。翻訳プロジェ クトを順調に進めるため、保守担当者には更なる余計な重荷を負わせず、そして翻 訳者をプログラムについての関心からできる限り自由にすることが重要です。

保守担当者が関心を持つべき唯一のことは、翻訳可能な新しい文字列を注意深くマー クすることであり、それが翻訳可能であるかどうかを彼らの作業中に気にすること ではありません(いずれ、それにふさわしい機会が来ます)。その結果として、プロ グラムとその文字列が保守担当者によって調整されたとき、そして通常は翻訳に関 係ない問題のために、xgettextは何度も`package.pot'ファイ ルを構築します。そして`lang.po'に格納されている翻訳は少しづつ実 情にそぐわないものとなっていきます。

パッケージの翻訳は、パッケージのライフサイクルにおける継続的な作業であって、 一回やってしまえば終わりというものではないということを認識しましょう。これ は、翻訳者(と保守担当者も)にとって重要なことです。与えられたパッケージに対 する最初の翻訳作業の後も、時々検査を行うことが必要です。なぜなら、そこかし この翻訳済みのエントリが用済みとなり、同時に翻訳が必要な未翻訳のエントリが 現れるからです。

msgmergeプログラムの目的は、xgettextによって更新されたCソー スから抽出されたより新しいテンプレートファイル`package.pot'と比 較することによって、既にある`lang.po'ファイルを更新することです。 この更新作業はCソース中の文字列の移動を全て調整します。文字列の移動があっ たプログラムは、変更されたプログラムであるからです。同様に、 msgmerge`lang.pox'にある廃止されたものをコメントアウト します。これらは、もはやプログラムソース中では使われていないような翻訳済み エントリであるためです(see section 5.5 廃止エントリ)。結果的に、このツールは新 しい文字列を見つけ出し、そしてそれをPOファイルに未翻訳エントリとして挿入し ます(see section 5.4 未翻訳エントリ)。msgmergeが実際に行っていること に関する詳細はSee section 5.1 msgmergeプログラムの起動

目標は、翻訳したほうがよい全ての文字列が提供されている(アップデートされた) `lang.pox'を得ることです。この作業が完了した時点で、このファイ ル、`lang.pox'は公式の`lang.po'ファイルを置き換える ことになるでしょう。

POファイルの時間移動性(temporal mobility)や時間流動性(time fluidity)とい うものは、翻訳ゲームの重要な部分であり、良く理解して受け入れるべきもので す。人々は翻訳プロジェクトで困難な仕事に参加することを拒んだり、他の参加 者(participants)にそれを押し付けようとするかもしれません! 特に、保守担当 者は関係する配布アーカイブにある全ての使用可能なPOファイルを、それが最近 更新されていないものであっても含めるのが良いでしょう。プレッシャーはユー ザーのコミュニティが使っている特定の言語から来るべきものであり、保守担当 者は翻訳ファイルを適切にしておくことに注意を払うべきです。その一方で、翻 訳者は、パッケージが正式な配布に先立つプリテスト(pretest)の間に、自分達 が扱っているPOファイルを更新すべきです。

POファイルが完全で独立したものになれば、実行時に必要になったときにいつでも POファイルから効率良く翻訳メッセージを取り出すことのできるマシン向けのフォー マットに変換するために、msgfmtプログラム使われます(see section 6.2 GNU MOファイルのフォーマット)。msgfmtプログラムへの実行様式の全てについての詳細は See section 6.1 msgfmtプログラムの起動を参照して下さい。

最後に、修正されマーク付けされたCのソースはコンパイルされ、さらにGNU gettextライブラリと共にリンクされます。通常、この作業はプロジェクト のために与えられた`Makefile'に応じてmakeを通じ行われます。そし て、その結果としての実行ファイルはユーザーが見つけることのできる場所にイン ストールされます。MOファイルそれ自身も適切にインストールすべきです。与えら れた適切な環境変数をセットすると(see section 7.3 エンドユーザへの魔法)、プログラムが実行され ればいつでも自動的に地域化されるでしょう。

本マニュアルの残りの部分は、このセクションで述べた概要をより掘り下げて説 明するためのものとなります。


2. POファイルとPOモードの基本

GNU gettextツールセットは、プログラマと翻訳者が主に(テキスト形式 で、編集可能な)POファイルのような翻訳ファイルを生成したり、更新したり、 あるいは使ったりすることを助けるものです。この章ではPOファイルの書式と、 POモードスタータ(PO mode starter)の構成を強調します。POモードの記述は一ヶ 所にまとめられておらず、このマニュアル全体に散らばっていますので、ここで はPOモードの基本についてのみ解説します。

2.1 GNU gettextのインストールを完了する  
2.2 POファイルのフォーマット  
2.3 POモードの主要なコマンド  主要なコマンド
2.4 エントリの位置  
2.5 エントリ内の文字列の正規化  


2.1 GNU gettextのインストールを完了する

GNU gettextの配布キットを入手し、展開、コンフィグレーション、コンパ イルした後、`make install'というコマンドによってxgettextmsgfmtgettextmsgmergeといったプログラム、そして同 時にそれらのプログラムで使用可能なメッセージカタログが所定の場所にインストー ルされます。完全に快適なインストールのために、あなたはGNU Emacsのユーザ達 がPOモードを使えるようにしたいかもしれません。

POモードがインストールされているときは、`.emacs'に以下のような数行の 修正を追加したくなるでしょう。

 
(setq auto-mode-alist
      (cons '("\\.po[tx]?\\'\\|\\.po\\." . po-mode) auto-mode-alist))
(autoload 'po-mode "po-mode")

この修正後、`.po'ファイル、`.pot'ファイル、`.pox'ファイル、 あるいは`.po.'という文字列をファイル名中に含むファイルを編集するとき はいつでも、Emacsは`po-mode.elc'(あるいは`po-mode.el')を必要に応 じてロードします。そして、`.po'などを編集しているバッファでは自動的に POモードのコマンドが有効になります。POモードが有効になっているバッファでは、 POという文字列がモードラインに表示されます。一つのEmacsセッションに おいて複数のPOファイルを扱っても、このアクティブ化は一度だけしか実施されま せん。

もしあなたが使用しているEmacsのバージョンが20かそれ以上であり、既に適切 な多国語フォントをシステムにインストールしているのであれば、必要なときは いつでもそれらのフォントを自動的にロードしてEmacsの画面表示に使用するこ とが出来ます。そのためには、以下の行を`.emacs'ファイルに追加すれ ばよいでしょう。

 
(autoload 'po-find-file-coding-system "po-mode")
(modify-coding-system-alist 'file "\\.po[tx]?\\'\\|\\.po\\."
                            'po-find-file-coding-system)


2.2 POファイルのフォーマット

POファイルは多くのエントリから構成されています。各エントリはオリジナルの翻 訳されていない文字列と、それを翻訳したものとの関係を保持しています。POファ イル中の全てのエントリは、通常一つのプロジェクトのみに関係し、また全ての翻 訳文字列は一つの(翻訳先の)言語で表わされます。一つのPOファイルのエントリは 次のような構造をとります。

 
white-space
#  translator-comments
#. automatic-comments
#: reference...
#, flag...
msgid untranslated-string
msgstr translated-string

POファイルの一般的な構成は、翻訳者が良く理解できるようなものであると良いで しょう。POモードを使用するときに、POモードが翻訳者に対して注意しているのと同 じように、翻訳者がフォーマットのディテールに関することをあまり知る必要がな いようにするべきです。

エントリは幾つかの(省略可能な)空白で始まります。通常、GNU gettextツー ルを通じて生成された場合にはエントリとエントリの間に一行だけ空行が入ります。 これに、#で始まっているコメント行が続きます。コメントには二種類あり ます。一つは#の直後に幾つかの空白が続いているようなコメントで、これ はもっぱら翻訳者によって作成や保守が行われるものです。もう一つは#の 直後に空白ではないキャラクタが続いているもので、これはGNU gettextツー ルによって自動的に作成されたり保守されたりするものです。すべてのコメントは その種類によらず省略することもできます。

空白とコメントの後にエントリの二つの文字列があります。最初の文字列はオリジ ナルのソースプログラムにあったような未翻訳の文字列、もう一つはその文字列の 翻訳です。オリジナルの文字列はmsgidというキーワードの後に置かれ、翻 訳された文字列はmsgstrの後に置かれます。これら二つの文字列(翻訳前 /翻訳後)はPOファイル中で"\を使った方法でクォートされますが、 POモードがクォートの面倒を見るので、翻訳者はクォートのフォーマットに対して 注意を払う必要はありません。

msgidは自動的に作成されるコメントと同様、他のGNU gettextツー ルによって生成されたり、管理されたりするものです。POモードはmsgidの 作成/管理に代わる機能を翻訳者に提供しません。彼女(翻訳者)が行えることの大 部分は、単にそれらを削除することと、エントリを丸ごと削除することのみです。 その一方でmsgstrという文字列は、翻訳者のコメントと同じように、翻訳 者のためのものであり、彼女(翻訳者)は必要とする全ての制御をPOモードで行うこ とができます。

プログラムがコメントとして完全に無視するわけではないという点で、#,で 始まるコメント行は特別なものです。flagのコンマ区切りのリストは 、幾 つかの有用な診断メッセージをユーザに与えるものとして、msgfmtプログ ラムが扱います。現在のところ、二つの形式のフラグが定義されています。

曖昧(fuzzy)
このフラグはmsgmergeプログラムによって生成されうるか、または翻訳者 自身によって付与されうるものです。これはmsgstr文字列がおそらく正し い翻訳でないことを示しています。翻訳者は更に翻訳を進めるか、あるいは現在の ままでいくかを決定するだけです。ひとたび翻訳が完了したなら、彼女はこの 曖昧属性を取り除きます。msgmergeプログラムは曖昧検索(fuzzy search)の後でmsgidmsgstrが結合されたときのみこの属性を付 与します。See section 5.3 曖昧な翻訳エントリ

c-format
no-c-format
このフラグは人間によって付与されるものではありません。xgettextプロ グラムのみがこれを付与します。ここで提案された自動的なPOファイル処理システ ムによって、xgettextプログラムが新しいテンプレートファイルを生成す るやいなや、ユーザによる変更は再度失われます。

c-formatフラグが文字列に付与された場合、msgfmtは翻訳が正当な ものであるかどうかについて更なるチェックを行います。See section 6.1 msgfmtプログラムの起動

空白やコメントが何行か、POファイルの最後のエントリの後に続くようなことがあ ります。このような行はどのエントリの一部でもなく、POモードはこのような行に 対して何のアクションも取りません。POモードの関数M-x po-normalizeを使うことによって、翻訳者はそういった余計な行を取り除くこと ができます。See section 2.5 エントリ内の文字列の正規化.

このセクションの残りの部分は、POモードを使うに当たってスキップすることもで きるでしょう。しかし、POファイルのフォーマットについてより良いアイディアを持っ ている人にとっては興味深いものであるかもしれません。一方、ここでは述べられ ていないGNU Emacsの便利な機能については注意深く読みつづけるべきです。

untranslated-stringtranslated-stringは、それを囲むクォート や(文字列中の)バックスラッシュエスケープシーケンスも含めて、それぞれキャラ クタ文字列に対するCの構文を反映しています。複数行にまたがる文字列を書く事 態になったときは改行のエスケープを行うのではなく、その代わりに継続する行の最 後のキャラクタに続けてクォートを置いて、その次の行の最初にもう一度クォート を置きます。例を挙げましょう。

 
msgid ""
"Here is an example of how one might continue a very long string\n"
"for the common case the string represents multi-line output.\n"

(訳注: これは出力が複数行に渡るような非常に長い文字列を継続させるやり方の例です。)

この例では、`Here'という単語のH`for'fを揃えるた めに、空文字列が最初の行で使われています。この例のキーワードmsgidは 連結が行われる三つの文字列を伴っています。空文字列の連結は最終的な文字列全 体に対して何の変更も行いません。しかし、これは我々がよりきれいに配置したよ うに複数行の体裁を左寄せにしながらも、msgidの文字列は同じ行になけれ ばならないという制限に従うための方法です。空文字列は取り除くこともできます が、そのためには先の例では`Here'で始まる行をがmsgidの右側に置 かなければなりません(1)。後ろの二つ の文字列のクォートは改行`\n'の直後で切り替える必要があるわけではなく、 その他の任意の文字の後で行うこともできます。我々が改行の後で区切ったのは、 その方がすっきりしているからです。

メッセージ文字列の一部としてクォートの内側に存在する`\n'のよう な行の終端と、文字列のクォートの外側にあってメッセージ文字列には含まれない POファイルの行それ自身の行の終端とは、気をつけて区別した方が良いでしょう。

文字列の外側では、自由に空行やコメントを置くことができます。コメントは行の 先頭の`#'から始まり、その行の終わりまでがコメントとなります。翻訳者に よって書かれたコメントは、#のすぐ後ろに幾つかの空白が置くようにするのがよ いでしょう。もしそのような空白がなければ、そのコメント行はGNUツールによっ て生成されたり扱われたりするものとほとんど同じであり、POファイルが msgmergeに与えられたときに、思いがけなく見失ったり置き換えられたり してしまうかもしれません。


2.3 POモードの主要なコマンド

2.1 GNU gettextのインストールを完了するで設定したようにEmacsの設定が完了した後、EmacsがPOファイ ルを読み込んだならば、そのウィンドウではPOモードがアクティブになります。ウィ ンドウは読み取り専用となり、po-mode-mapが開始されます。 po-mode-hookとして関数が定義されている場合は、それが実行されます。

POモードがウィンドウに対してアクティブにされた時点で、`PO'という文字 列がウィンドウのモードラインに表示されます。モードラインには、POファイル中 のあらゆる種別のエントリの数もまた表示されます。例えば、 `132t+3f+10u+2o'という文字列が表示された場合、それはPOモード中に132の 翻訳エントリ(see section 5.2 翻訳済みエントリ)があり、3つの曖昧なエントリ (see section 5.3 曖昧な翻訳エントリ)があり、10の未翻訳エントリ(see section 5.4 未翻訳エントリがあり)、2つの廃止されたエントリ(see section 5.5 廃止エントリ)があるこ とを示しています。一つも存在しないエントリは表示されません。例えば、もし曖 昧なエントリが解決され、未翻訳のエントリが翻訳され、廃止されたエントリが削 除されたなら、モードラインにはカウンタとして`145t'が表示されることで しょう。

主なPOコマンドは後のセクションにある他のカテゴリにはあてはまりません。これ らはPOモードを終了するか、ウィンドウを特別な方法で管理するためのものです。

U
POファイルに対する最後の変更を取り消します。

Q
処理を中断し、POファイルを保存します。

q
可能であれば確認してから、処理を中断します。

O
POファイルのウィンドウから一時的に離れます。

?
h
POモードに関するヘルプを表示します。

=
POファイルの幾つかの統計を表示します。

V
POファイル全体の書式の正当性のチェックを行います。

U(po-undo)コマンドはGNU Emacsのundo機能に対するインター フェースです。See section `Undoing Changes' in The Emacs Editor. Uがタイプされる度に、翻訳者がPOファイルに対して行った変更は少し元に 戻されます。アンドゥのために、POモードの各コマンドの処理はアトミックなもの となっています。これはRETコマンドのときに特にそうです。たとえ 編集それ自身が幾つかのアクションによるものであったとしても、一回の RETコマンドによる編集は一度に取り消されます。しかしながら、編 集ウィンドウで作業している間は編集作業を一つ一つチマチマとアンドゥできます。

Qコマンド(po-quit)とqコマンド (po-confirm-and-quit)は、翻訳者がPOファイルに対する操作を終えるとき に使用します。前者は少しだけ冗長さに欠けるものです。もしファイルが変更され ていれば、最初にファイルがディスクにセーブされます。両方のケースにおいて、 そして全てを行う前に、このコマンドはPOファイルに翻訳されていないメッセージ が残っているかチェックし、もしあれば翻訳者に対するPOファイルの編集を本当に やめるのかの問い合わせを行ないます。これはEmacs のPOファイルバッファを扱う のに好ましい方法です。バッファの削除を通常のC-x k (kill-buffer)コマンドで行うのは良くない方法です。

O(po-other-window)コマンドは、POモードから抜け出るためのもう 一つの柔軟なやり方です(一時的に、ですが)。このコマンドはカーソルを別の Emacsウィンドウに動かして、必要ならばそのウィンドウをポップアップするとい うものです。例えば、翻訳者はPOモードでソースコードを見ているときに、修正す る必要があるプログラムソース中に明らかなバグを見つけるかもしれません。この コマンドは翻訳者がプログラマとなり、(この時点でプログラマとなった)翻訳者が 修正しようとしているウィンドウにカーソルを移すことを許します。この後でカー ソルをPOファイルのウィンドウに戻すか、Emacsにこのファイルをもう一度編集す るということを伝えれば、POモードは復活します。

hコマンド(po-help)は、すべての使用可能なPOモードコマンドのサマ リを表示します。その後で翻訳者が任意のキャラクタをタイプすると、通常のPO モードオペレーションに復帰します。?コマンドはhと同じ効果を持ちま す。

=コマンド(po-statistics)はPOファイル中のエントリの総数、カレ ントエントリの順番(1からカウントされます)、未翻訳のエントリの数、廃止され たエントリの数を計算し、これらの数字全てを表示します。

Vコマンド(po-validate) は、現在のPOファイルに対して msgfmtを饒舌モード(verbose mode)で起動します。このコマンドは最初に 現在のPOファイルをディスクに保存することを提案します。GNU gettextmsgfmtツールはMOファイルをPOファイルから作成するという目的を持って います。そして、POモードはこのプログラムの機能を全ての個別のエントリのチェッ ク、そしてPOファイル全体のフォーマットのチェックのために使っています。

msgfmtプログラムはEmacsと非同期に動作するので、翻訳者は即座にPOファ イルの制御を取り戻します。エラー出力はGNU Emacsの`*compilation*'バッ ファに集められて別のウィンドウで表示されます。通常のGNU Emacsコマンド C-x`(next-error)は、他の通常のコンパイルコマンドと同様、POファ イルの問題となった部分にすばやく移動することを可能とします。一旦カーソルが エラーのある行に移れば、翻訳者はエラーを修正するのに役立つ任意のPOモードア クションを取ることができます。


2.4 エントリの位置

POファイルウィンドウにあるカーソルはほとんど常にエントリの一部です。唯一の 例外はファイルの最後のエントリの後ろにある場合、あるいはPOファイルが空の場 合といった特殊なものです。多くのPOモードコマンドはカレントエントリで動作す るので、翻訳者はPOファイルを眺めて回ることよりもカーソルを移動することのほ うが多くなります。カーソルを移動するということは、コマンドの操作対象となる エントリを選択することにもなります。

いくつかののPOモードコマンドは特殊なやり方でカーソル位置を変えます。これら の特殊な目的での位置の移動の幾つかをここで説明し、その他のものはこの後のセ クションで説明します。

.
現在のエントリを再表示します。

n
n
現在のエントリの次のエントリを選択します。

p
p
現在のエントリの前のエントリを選択します。

<
POファイルの先頭にあるエントリを選択します。

>
POファイルの最後のエントリを選択します。

m
後で使用するときのために、現在のエントリの位置を記録します。

l
直前に保存した位置へ復帰します。

x
現在のエントリ位置と、直前に保存したエントリ位置とを交換します。

幾つかのGNU EmacsコマンドはPOモードにあるカレントエントリを選択するために カーソルの位置設定をすることができます。文字、行、パラグラフ、スクリーン、 あるいはページ単位で移動するコマンドや、検索コマンドです。しかしながら、 POモード中にあるカレントエントリを表示するための標準的な方法があります。こ れはカーソルの移動を強制しないような通常のGNU Emacsコマンドです。.コ マンド(po-current-entry)は、カレントエントリが変更された後や、 Emacsのスクリーンなどの状態が変わった後で、適切なカレントエントリの再表示 を行うというただひとつの目的を持っています。

翻訳者が作業をする間、強制的にウィンドウの制御全てを保持し続けることが翻訳 者にとって作業しやすいのかそうでないのか、この点についてはまだ決めかねてい ます。我々はウィンドウがこのように振る舞うのは素晴らしいアイディアだと思いま したが、しかし一方で、Emacsを使う人がウィンドウを完全にコントロール出来る 方がよいのかもしれないとは思います。ウィンドウの制御については、翻訳者がそ れを有効か無効かを切り替えるオプションを実験的にPOモード用に提供するかもし れません。誰もそのような必要性を感じないか、あるいはそれを作成するように強 制されたら、我々はそのようなアイディアを放棄するでしょう。このことを実行する ための動機となるのは、他人がどのように翻訳をするのかを考えて いるプログラマからよりも、むしろそれに価値を見いだす経験を積んだ翻訳者か らの意見です。

n(po-next-entry)コマンドやp (po-previous-entry)コマンドは、それぞれ直後のエントリ、直前のエント リにカーソルを動かします。nが最後のエントリにあるときに指定されたり、 pが最初のエントリにあるときに指定された場合はカーソルを移動しません。

<(po-first-entry)と>(po-last-entry)というコマン ドは、それぞれカーソルをPOファイルの最初のエントリ、最後のエントリに移動し ます。カーソルがPOファイルの最後のエントリにあったとき、ほとんどのPOモード コマンドは`After last entry'のエラーを報告するでしょう。しかし、 <>はカーソルがPOファイルのエントリにないような状態でも動作 が可能なようになっており、カーソルが最後のエントリに置かれた場合でも使うこ とができます。しかし、これらのコマンドを空のPOファイルで実行した場合にはエ ラーとなります。POモードを、対話的にソースから空のPOファイルを埋めていくよ うにする開発計画があります。See section 3.3 翻訳対象文字列のマーク付け.

特定のエントリを翻訳する前に、翻訳者は関連するエントリで使われている用語や 語法を参照するためにPOファイルの残りの部分を眺める必要があるかどうかを決め ることができます。翻訳者はもちろん、その時点でのカーソル位置を幾つかのレジ スタに保存し、後でカーソル位置を戻すためにレジスタに保存した値を使うという Emacsの標準的なやり方を使うことができますし、location ringを使うこともでき ます。

POモードは別のアプローチを提供します。カーソル位置を特別なスタックに保存す るというものです。mコマンド(po-push-location)は、単に現在の位 置をスタックに追加して、以前に保存されている位置情報の上に新しいものをプッ シュします。rコマンド(po-pop-location)はスタックの最上位の要 素を取り出して、取り出した要素に結び付けられている位置へとカーソルを移動し ます。この位置はカーソルを直前に保存された位置へ移動させるrが次に使 われたときに消費されます。この位置情報は使用されるまでスタック上に留まりつ づけます。

翻訳者が位置スタック上に位置を保存しておきたいと望むのでしたら、スタックの 最上位にある要素に結び付けられたエントリを見ることによってなされるでしょう。 そして翻訳者はrの直後にmを使って、後で戻るための目印を伴いつつ 任意の場所へ移動します。

x(po-exchange-location)コマンドは保存されたロケーションのスタッ クの最上位にある要素に関連付けられたエントリへのカーソルの再位置付け (reposition)をシミュレートして、移動前に現在のエントリの位置に対応する最上 位要素を置き換えます。従って、xコマンドを繰り返し実行すると、二つの エントリの間で入れ替えが行われます。これを成し遂げるために、翻訳者は最初の エントリにカーソルを置いてmを使って、それからカーソルを二番目のエン トリに動かします。そして入れ替えのためにxを使います。


2.5 エントリ内の文字列の正規化

POファイルの各エントリに特定の文字列をエンコードしておくということについて は、多くの異なった方法があります。なぜなら、複数行に渡る文字列の引用や分割 の方法はたくさんありますし、更に、バックスラッシュの付いたエスケープシーケ ンスによる特殊キャラクタの表現方法も一つではないからです。POモードの幾つか の機能は、既に存在しているPOファイル中でmsgidフィールドにあるエンコー ドされた特定の文字列を検索するPOモードの機能に依存しています。この認識を簡 単に実装するために、POモードがすべての組み込み機能を内部的に持っていたとし ても、それを高速に行うのは技術的には困難です。この効率に関する問題を解決す るため、我々は文字列を標準的(canonical)に表現することを決定しました。

POファイルにおける伝統的な(conventional)文字列の表現に関しては現在議論中で あり、そしてPOモードの標準的記法についても実験中です。等価な文字列を表わす ための統一的な方法に向けて、xgettextとPOモードの両方を統合すること は有用です。GNU gettextxgettextを使った時点で、POモードが 必要とする内部的な正規化が自動的に実行されるのですから。事細かなPOモードに よる正規化は、どこかからかインポートされるPOファイルに対してのみに、あるい はそれ自身を発展させるための議論のときのみに必要となります。

POファイル内にある、少なからず標準的記法を必要としている文字列を正規化する には、以下のPOモードのコマンドを使います。

M-x po-normalize
POファイル全体を、エントリの形式を揃えるようにすることで整頓します。

特殊コマンドM-x po-normalize(特定のキーには割り当てられていません)は すべてのエントリを再検査し、オリジナルのものと翻訳されたものの両方の文字列 のエントリがPOファイルにおける規定の形式でクォートされていることを保証しま す。このコマンドは最後のエントリの後ろにあるゴミも取り除きます。このコマン ドはPOファイルをどこかから新規にインポートしてきたときや、標準的なクォート のフォーマットに変更する際に有用です。この標準的なクォートのフォーマットに 変換することにより、よりクリーンなPOファイルを得ることが出来るだけでなく、 他のPOモードコマンドが文字列を高速に検索することが出来るようになります。

M-x po-normalizeは各エントリに対して処理を三回試行します。最初の方法 はGNU gettext 0.6より前に採用されていたPOファイル変換のヒューリスティ クスで、msgidmsgstrフィールドは複数行を扱う際にK&Rスタイ ルのC文字列を使っていました。これらのヒューリスティクスは廃止されたエント リと関連づけられておらず、かつバックスラッシュで終了するコメントに対しては 失敗していました。これらのヒューリスティクスは廃止されたエントリに続く行も コメントにしてしまっていたからです。一旦全ての古いPOファイルが修正されたな ら、この最初の方法は消滅するでしょう。第二、第三の方法は全ての msgidmsgstr文字列を個別に正規化します。これらの方法は XViewの msgfmtが継続行に対して使用していたものであり、継続するバッ クスラッシュを削除します。

他のソースファイルからPOファイルへとインポートすることを可能にする明快な正規化 コマンドがあるものの、今では現在の規定の進化はより芸術的に緩和されていま す。正規化のコマンドとして提案されている修正を行うのは簡単です。結局のと ころ、他の GNU gettextツール群が自動的に協調して動作すればよいの です。文字列の標準的記法について以下に述べます。これらの情報はGNU Emacs を使用せず、独自の方法でPOファイルを編集する人々に対して役に立つでしょう。

POモードでは、文字列は単一行でも複数行でもかまいません。 `[^\n]\n+[^\n]'にマッチするような埋め込まれた改行が文字列にあ れば、その文字列は複数行となります。例を挙げてみましょう。

 
msgstr "\n\nHello, world!\n\n\n"

しかし、スペースを改行で置き換えれば次のようになります。

 
msgstr ""
"\n"
"\n"
"Hello,\n"
"world!\n"
"\n"
"\n"

我々はここで、問題点を明確にするためにちょっとおおげさな例を使いましたが、 通常は複数行のメッセージはこんな体裁の悪いものではありません。次のような提 案を実装することはあり得るでしょう。空文字列内の最初の改行文字をひとまとめ として扱い、全ての改行文字は行末で終了するというものです(ここで n > 1であるとします。n - 1 番目の改行は分割された文字列だ とします)。前に挙げた例は次のようになるでしょう。

 
msgstr "\n\n"
"Hello,\n"
"world!\n"
"\n\n"

文字列の正規化の細部については、まだ幾つかの未決定事項が残されています。 それらの問題が解決したら、このマニュアルに記載されます。


3. プログラムソースの準備

Cプログラムソースコードの変更は3段階に分けて行われます。最初に、メッセージ 変換が必要な全てのモジュールに、地域化用の関数群の存在を知らせなければなり ません。次に、プログラム初期化時にGNU gettextを使う準備をする必要 があります。これは通常main関数内で行われます。最後に、プログラム中で変換が 必要な全文字列を捜し出してマーク付けしましょう。

ここで、プログラム又はパッケージが既に必要なGNU gettextファイルを利 用できるように修正されており、そして`Makefile'の修正も完了しており、 (see section 10. 保守担当者としての視点) 、文字列の翻訳の対象となる全てのCプログラムに次の一 行が追加されていると仮定します。

 
#include <libintl.h>

Cのソースプログラムに対するその他の変更については、この章の後のセクション で説明します。

3.1 gettextの処理をトリガする  
3.2 ソース中でのマーク付けの方法  
3.3 翻訳対象文字列のマーク付け  
3.4 続く文字列に関して何かを伝えること  
3.5 特別な翻訳対象文字列  


3.1 gettextの処理をトリガする

ロカールデータの初期化は、どのプログラムでもこのような形で行われます。下の 例を参照してみて下さい。

 
int
main (argc, argv)
     int argc;
     char argv;
{
  ...
  setlocale (LC_ALL, "");
  bindtextdomain (PACKAGE, LOCALEDIR);
  textdomain (PACKAGE);
  ...
}

PACKAGELOCALEDIRは、共に`config.h'又はMakefile中で 定義するのがよいでしょう。より多くの情報が必要であれば、gettextの ソースを参照して下さい。

LC_ALLの使用は適切ではないかもしれません。LC_ALLは全てのロカー ルカテゴリ、特にLC_CTYPEを含んでいます。LC_CTYPEは、 `ctype.h'内で定義されるisalnum関数などが扱うキャラクタクラスの 決定に影響します。これらは特に、ある種の入力言語を扱うプログラムに対してよ くありません。例えば、ソースコード中でc + (訳注: セディユ、 フランス語で使用される文字)を使用している場合、そのプログラムはフランスで は動いても米国では動かないでしょう。

一部のシステムではまた、LC_ALLロカール以外のものが使われている場合、 scanf関数中の数値のパースに関する問題を抱えていることがあります。 "C"ロカール内にあっても認識される追加のフォーマットについて、規格で は言及されています。。しかし、一部のシステムは"C"ロカールのフォーマッ トにある数値を無視するようです。このような状況下では、数値が"C"ロカー ルまたはローカルのフォーマットにあろうとなかろうと、数値表記方法の認識が不 可能になるような問題があることでしょう。これは何千ものセパレータ文字が使わ れていることに起因します。一部のロカールは、"C"ロカールにおいて小数 点として定義されている'.'を国家的事情のために別な用途に使うように定 義しています。

このため、場合によっては上の例におけるLC_ALLの行を setlocaleの行の並びに置き換える必要があります。例えば、

 
{
  ...
  setlocale (LC_TIME, "");
  setlocale (LC_MESSAGES, "");
  ...
}

このようにします。全てのPOSIX準拠のシステムでは、LC_CTYPELC_COLLATELC_MONETARYLC_NUMERIC、そして LC_TIMEロカールカテゴリが使用可能になっています。一部の現代的なシス テムでは、XPG2準拠システムでかつてLC_RESPONSESと呼ばれていた、 LC_MESSAGESロカールが定義されています。


3.2 ソース中でのマーク付けの方法

Cソース中の翻訳を必要とする全ての文字列はマーク付け(marking)されるべきです。 マーク付けがなされた翻訳可能な文字列は、ある特定の関数やプリプロセッサマク ロの単一の引数として表されます。翻訳のために使うことのできる関数やマクロは ほんの少ししかなく、それらの名前はマーク付け用キーワード(marking keyword)と呼ばれます。マーク付けは文字列に対して行うというよりはむしろ、、 文字列それ自身と結び付けられるものです。この手法は他でも使われます。一例と して、フォーマットされることにより出力されるエラーメッセージのことを考えて みましょう。エラーメッセージの書式文字列は翻訳を必要とします。このような書 式指定文字列中では、書式指定文字列中の`%s'書式指定を通じて様々な文字 列が挿入されますから、出力結果は様々な形になります。このような書式を取る `error_string_out()'のような関数のために、この関数の出力の結果全てを リストアップするのは得策ではありません。

このマーク付け操作には二つのゴールがあります。最初のゴールは実行時に翻訳文 字列を取り出すための引き金となることです。キーワードは、適切な翻訳文字列を 動的に返すことのできるルーチンを通じて解決されます。大部分の翻訳が必要な文 字列は実行位置で検索され、変数に反映したり、関数に対する引数として与えられ ます。しかしこれは一般的な方法であり、一部の翻訳文字列は構造的な初期化方法 によって検索されます。See section 3.5 特別な翻訳対象文字列を参照して下さい。

マーク付けの二番目のゴールは、xgettextがプログラムソースにある全て の翻訳対象文字列をスキャンして抽出し、POファイルのテンプレートを生成するの を手助けすることです。

翻訳可能な文字列のマーク付けをするための標準的キーワードは`gettext' です。これはGNU gettext全体の名前にもなっています。パッケージ中で、 `gettext'というキーワードやマクロ、関数だけを使うことは非常に簡単で す。しかし、パッケージ中でgettextインターフェースを使うと煩雑になっ てしまうので、主なキーワードとしては短く便利で目立たないものを提供すべき でしょう。実際のところ、キーワードは国際化されたパッケージ中の多くの文字 列に対して現れるでしょうが、プログラマは自分のプログラムソースにそういっ たものが溢れかえるようなことは普通望まないでしょう。更に、ソースコードを 79桁から80桁に収めるためには、水平方向にスペースを取る長いキーワードは不 利になります。

パッケージの多くでは、キーワードとして`_'(単一のアンダーライン)を使っ ていて、`gettext("Translatable string")'の代わりに `_("Translatable string")'と記述しています。更に、GNU標準におけるコー ディング規則で要求されている「キーワードと開き括弧の間に一つのスペースを置 く」という規則が、これ特有な使い方を明確にするために緩められています。これ で、翻訳文字列ひとつあたりに必要な文字数のオーバーヘッドは、アンダーライン と一つの括弧のペアの三文字に押えられます。しかしながら、GNU gettextがこのやり方を内部的に使っていたとしても、公式には勧めません。 実際のところ、本当の正しいキーワードは`gettext'なのです。 `gettext'の代わりに`_'を使用できるようにするのは非常に簡単で、次 のように宣言しておきます。

 
#include <libintl.h>
#define _(String) gettext (String)

単純に`#include <libintl.h>'とするより、上の例のようにします。

保守という作業は、最初の手間に比べれば相対的に簡単です。プログラマとして、 あなたが文字列を追加・修正したりしたら、追加・修正された文字列が翻訳を必要 とするかどうかを確認する必要があるでしょう。そしてそれが翻訳されるべきだと 思ったのなら、それを`_()'の内側に置きます。`"%s: %d"'は翻訳を 必要としない文字列の例です。


3.3 翻訳対象文字列のマーク付け

POモードにおける機能は翻訳者向けと云うよりはプログラマ向けです。そして、プ ログラマに対してプログラムソース中にある文字列が翻訳可能であるか、そうでな いかのマーク付けを対話的に行うことができるようになっています。そのような文 字列を見つけだしてマーク付けをするという作業が、プログラマにとって自分の好 きなエディタを使って行えるごく簡単な作業であったとしても、POモードはこの作 業をより快適にするのです。更にPOモードは、国際化されたパッケージのプログラ ムソース中の翻訳対象となる文字列にマーク付けしている間、プログラマに翻訳者 のような気分を、翻訳者にプログラマのような気分を味わせます。

ここで説明するPOモードのコマンドが対象とするプログラムソース群は、プロジェク トのために構築されたEmacsタグテーブルを持つべきです。これは簡単なことで、 任意のシェルウィンドウ中でプロジェクトのルートディレクトリに移動し、次に挙 げるようなコマンドを実行するだけです。

 
etags src/*.[hc] lib/*.[hc]

ここで、`src/'`lib/'といったディレクトリにある全ての `.h'`.c'とを処理したい状況を考えてみましょう。このコマンドは全 てのファイルを探索して、プロジェクトのルートディレクトリに`TAGS'とい うファイルを作成します。これはEmacsが理解することの出来る、特殊なフォーマッ トによる内容の要約になります。

GNUコーディング標準に従っているパッケージでは、ソースを構成する全てのファ イルから構成されたタグファイル(tagsTAGS)が全てのディレクト リに存在することになっています。

`TAGS'というファイルが用意されれば、プログラマがソースファイル中にあ る翻訳対象文字列をマーク付けするために後述するコマンド群が使用できます。こ れらのコマンドはPOファイルウィンドウの中で起動される必要があるのですが、ま だPOファイルが作成されていないことということがありがちです。これはそれほど 問題にはなりません。これらのコマンドを主に使用するために、安全に新しい空の POファイルを開くことができます。あなたがマーク付けしたプログラムソース中の 翻訳対象文字列によって、この空のPOファイルは徐々に満たされてゆくでしょう。

,
プログラムソースから、翻訳の候補になると思われる文字列を検索します。

M-,
最後に見つかった文字列に`_()'で目印付けをします。

M-.
最後に見つけた文字列に、可能なキーワードセットから取り出したキーワードで目 印付けをします。このコマンドは、これらのキーワードの幾分の管理を許すような 前置引数を取ります。

,(po-tags-search)コマンドは次に現れる翻訳の対象となるような文 字列を検索します。そしてEmacsの別のウィンドウにプログラムソースを表示し、 そのウィンドウの先頭付近に検索された文字列がくるようにします。もし文字列が ウィンドウに収まらないほど大きければ、その終端部分だけが表示されます。この ような場合、カーソルはPOファイルのウィンドウに残ります。表示されている文字 列が別の言語では異なった表記をされるものであれば、M-,M-.を使っ てマークすることができます。その文字列を無視するのなら、単に,コマン ドを繰り返すことによって次の文字列へとスキップすることが出来ます。

三文字以上の長さの文字列は翻訳対象となり得ます。二文字から成る文字列は、そ れが文字以外のものを含んでいなければ翻訳候補としてみなされるでしょう。コマ ンドは文字を含まない文字列や、同じ文字からのみ構成される文字列を無視します。 また、コメント中にある文字列や、POモードが知っているキーワード(後述)によっ て既にマークされている文字列についても無視します。

もしまだEmacsに対してどの`TAGS'を使用するかを指定していないのであれば、 このコマンドを最初に実行したとき、このコマンドはミニバッファでどの `TAGS'ファイルを使用するかを尋ねます。EmacsのM-x visit-tags-tableコマンドを使って、使用したい`TAGS'ファイルに後から 変更することもできます。@xref{Tags, , Tag Tables, The Emacs Editor}.

,コマンドを使うと、検索は直前に行われた検索の位置から再開されます。 この処理は`TAGS'ファイルに従って全てのプログラムソースが処理されるま で続けられます。しかし、前置引数(C-u ,)を与えることによって、最 初のファイルから検索を再開するように指定することも出来ます。但しこの場合、 (翻訳するとして)既にマーク付けした文字列は自動的にスキップされます。

,コマンドを使うことによって、通常のEmacsのタグコマンドを邪魔してしま うようなことはありません。例えば、通常のtags-searchtags-query-replaceといったコマンドは、,のサーチの流れを中断す ることなく使うことが出来ます。しかしながら、実装によっては最初の ,コマンド(もしくは 前置引数を伴った,コマンド)は最初のタグファ イルを検索するための通常のEmacsタグを再び初期化してしまうかもしれず、その ためにこの再初期化は不当なものであると看做されるかもしれません。

M-,(po-mark-translatable)コマンドは、一番最近見つかった文字列 を`_'キーワードでマーク付けします。M-. (po-select-mark-and-mark)コマンドは、ミニバッファからキーワードを一 つ読み込み、そのキーワードを使って文字列のマーク付けをします。これら両方の コマンドは、マーク付けされた文字列を使ってPOファイル中に新しい未翻訳エント リを自動的に生成します(もし直ちに翻訳することが好きなのであれば、これによ りすぐに翻訳が行えるようになります)。M-,M-.による変更はプ ログラムソース中の行を80カラムよりも長くすることがあり、あなたは改行してそ の行を異なる形で再インデントしなければならなくなるでしょう。POモードから Oコマンドを使ったり、GNU Emacsからウィンドウを変更するコマンドを使う ことによって、プログラムのソースウィンドウに移動して何らかの必要な修正を行 うことができます。後続の文字列に対してM-,を使いたいのであれば、POファ イルウィンドウにカーソルを戻すために通常のEmacsコマンドを使う必要があるで しょう。

M-.には、毎回キーワードを明示的にタイプしなくてもすむよう、作業をス ピードアップさせる幾つかの機能が組み込まれています。最初のスピードアップは、 好みのキーワードが表示された場合、それを使うにはただ単にプロンプト に対してRETをタイプすればよいというものです。第二のスピードアッ プは、キーワードの最初のほうをタイプすれば、コマンドがそれを自動的に補完し てくれるというものです。PO modeは使用可能な全てのキーワードを知って おり、これによってキーワードのミスタイプは弾かれるようになります。

キーワードのリクエストに対して?をタイプすると、コマンドはあなたが選 択することのできる既知のキーワード全てをリストアップします。コマンドに前置 引数が渡された場合(C-u M-.)、プログラムソースやPOファイルのバッ ファに対する更新は行われず、代わりに単純なキーワード管理が行われます。この 場合、コマンドはキーワードを訊ねます。キーワードを完全に記述することにより、 ここで設定したキーワードが以後のM-.で使用されるキーワードになります。 更に、この新しいキーワードは自動的に以後の好みのキーワードとなりま す。C-u M-.に対する入力として既知のキーワードを入力した場合、た だ単に好みのキーワードが変更されるだけとなります。

M-.コマンドのために使用される全てのキーワードは、文字列の検索時に ,コマンドによっても認識されます。そしてあらゆる既知のキーワードによっ て既にマーク付けされている文字列は自動的にスキップされます。もし多くのPOファ イルが同時に開かれている場合、それらは独自に既知のキーワードの組を保持して います。現在、POモードには既知のキーワードを削除する手段はありません。既知 のキーワードを削除するためには、ファイルを閉じて(qコマンドが使えるで しょう)、新たに開き直す必要があります。POファイルがEmacsの新しいウィンドウ として開かれた場合、`gettext'`_'だけが既知のキーワードとなり、 `gettext'M-.の好みのキーワードとなります。事実、`_'を選 択するのは好ましくありません。それはM-,コマンドの組み込みとして既に 設定されているからです。


3.4 続く文字列に関して何かを伝えること

Cプログラム中の文字列はしばしば、printfファミリの関数呼び出し中で使 われます。これらのフォーマット文字列(format strings)は、それらが%か ら始まるフォーマット指定子(format specifiers)を含むことが出来るという点で 特殊なものです。ここで、このようなコードがあると仮定します。

 
printf (gettext ("String `%s' has %d characters\n"), s, strlen (s));

上記の文字列をドイツ語へと翻訳した場合、このようになるでしょう。

 
"%d Zeichen lang ist die Zeichenkette `%s'"

たとえドイツ語が話せなかったとしても、Cプログラマはこれでは何かまずいと思 うでしょう。二つのフォーマット指定子の順番が変更されているにも関わらず、 printfの引数はもちろんそのままなのです。ここでは、文字列の長さが文 字列へのアドレスとして見做されるため、これはおそらく問題となることでしょう。

実行時に翻訳によって引き起こされるエラーを防ぐため、msgfmtツールは 本来の引数と翻訳文字列が型と個数においてマッチしているかどうかを静的にチェッ クすることができます。もしそうでなかった場合は警告が出されることになり、実 行時にエラーによって問題が発生することはなくなります。

先のドイツ語翻訳における語順が正しいとすれば、それはこのように書かれるべき です。

 
"%2$d Zeichen lang ist die Zeichenkette `%1$s'"

msgfmt中のルーチンはこの特別な記法を扱えます。

全てのプログラム中の文字列がフォーマット文字列であることはないので、 `.po'ファイル中の全ての文字列についてテストすることはmsgfmtに とって好ましくありません。printf中で使われていないにも関わらず、文 字列がフォーマット指定子のように見える文字列を含んでいることがあるので、こ れは問題となる得るからです。

従って、xgettextはフォーマット文字列と考えられるそれらの文字列に対 して特別なタグを付与します。これには絶対的なルールがあるわけではなく、あく までもヒューリスティックなものです。`.po'ファイル中で、そのエントリは c-formatとして#,コメント行にマーク付けされます(see section 2.2 POファイルのフォーマット)。

注意深い読者はここで、これは再び問題を起こすと言うことでしょう。ヒューリス ティクスはそれを悪いと推測するでしょう。これは真実であり、 xgettextはプログラマに決定を行わせるための特別な種類のコメントを認 識することができます。gettextキーワードと同じ行か、あるいは直前の行 において、xgettextプログラムがxgettext:c-formatという語を含ん だコメントを見つけ出したなら、どのような場合でのその文字列には c-formatフラグが付与されるでしょう。このコメントは、文字列がテストさ れそれが本当にフォーマット文字列であるにも関わらず、xgettextがそれ をフォーマット文字列として認識できかった場合にも使用できます。コメントが gettextキーワードと同じ行にある場合は、それは翻訳される文字列よりも 前になければならないことを覚えておいて下さい。

この状況は頻繁に発生します。printf関数はしばしばフォーマット指定子 を含まない文字列と共に呼び出されます。もちろん、それはfputsを使用す るときもも通常そうです。このような場合、xgettextはその文字列をフォー マット文字列として認識しませんが、もし翻訳が正しいフォーマット指定子を含ん でいた場合はどうなるのでしょう。printf関数はパラメータにアクセスし ようとしますが、本来のコードはいかなるパラメータも参照していないので、パラ メータは存在しません。

もちろんxgettextはあべこべの間違った決定をすることがあります。フォー マット文字列としてマークされた文字列は実はフォーマット文字列ではありません でした。このような場合、msgfmtは大量の警告を出し、`.po'ファイ ルの翻訳をさせません。このような間違った決定をやめさせるために、先に使った のと同じような方法が使用できます。xgettext:no-c-formatという文字列を 含んだコメントを使用すればいいだけです。

c-formatとして文字列がマークされたにも関わらず、それが正しくない場合、 信頼できる決定が行えるユーザはそれを発見することができます。 See section 4.1 xgettextプログラムの起動を参照すれば、--debugオプションがこの問題 を解決するために使えることがわかります。


3.5 特別な翻訳対象文字列

注意深い読者はここで、gettextやその他の同様のツールは翻訳可能な文字 列を常にマーク付け出来るものではないということを指摘するかもしれません。次 のような場合を考えてみましょう。

 
{
  static const char *messages[] = {
    "some very meaningful message",
    "and another one"
  };
  const char *string;
  ...
  string
    = index > 1 ? "a default message" : messages[index];

  fputs (string);
  ...
}

"a default message"という文字列に対するマーク付けには問題ありません が、messagesを初期化している文字列に対するマーク付けはできません。 ここで行うことは何でしょう? 我々は二つの作業を行わねばなりません。最初に行 うべきことは、xgettextプログラム(see section 4.1 xgettextプログラムの起動)がその ような文字列を見つけることができるようにマーク付けをすることで、二番目に行 うべきことは、実行時に文字列が表示される前に文字列を翻訳するということです。

最初の仕事は、no-opという名前の新しいキーワードを作成することにより達成で きます。二番目の仕事として、配列中に格納された文字列を参照している全ての場 所にマーク付けをする必要があります。解決例は次のようなものになります。

 
#define gettext_noop(String) (String)

{
  static const char *messages[] = {
    gettext_noop ("some very meaningful message"),
    gettext_noop ("and another one")
  };
  const char *string;
  ...
  string
    = index > 1 ? gettext ("a default message") : gettext (messages[index]);

  fputs (string);
  ...
}

fputsによって出力される文字列はどの場合でも翻訳されたものであること を理解して下さい。追加キーワードgettext_noopxgettextに知ら せる方法については、4.1 xgettextプログラムの起動で説明されています。

もちろん、先の例だけが解決方法ではありません。次のようにしても同じことが出 来ます。

 
#define gettext_noop(String) (String)

{
  static const char *messages[] = {
    gettext_noop ("some very meaningful message",
    gettext_noop ("and another one")
  };
  const char *string;
  ...
  string
    = index > 1 ? gettext_noop ("a default message") : messages[index];

  fputs (gettext (string));
  ...
}

しかしこれには幾つかの欠点があります。第一に、プログラマは自分が"a default message"という文字列のためにgettext_noopを使っているという ことに対して注意を払わなければなりません、gettextの使用は稀れに予測 できない結果を生むことがあるからです。第二に、GNU gettextライブラリ の内部の問題として、このやり方では効率が下がるからです。

出力が本当に全てのケースで翻訳されているかどうかということを確実にするため に、制御フローを解析する必要がないということは一つの利点となります。しかし この解析は一般的にそんなに難しいことではありません。もしあらゆる状況におい てそうすべきであれば、あなたはこの状況下でこの二番目の手法を使うことができ ます。


4. 最初のPOファイルの準備

4.1 xgettextプログラムの起動  
4.2 Cソースの文脈  
4.3 翻訳要約機能の使用  


4.1 xgettextプログラムの起動

 
xgettext [option] inputfile ...

`-a'
`--extract-all'
すべての文字列を抽出します。

`-c [tag]'
`--add-comments[=tag]'
tag(もしくはキーワードが先行している行)を持つコメント部分を出力ファ イルに出力します。

`-C'
`--c++'
C++形式のコメントを認識します。

`--debug'
フォーマット文字列としてメッセージをマーク付けする責任を負う人間が、 c-formatフラグとpossible-c-formatフラグを表示するために使いま す。後者のフォームはxgettextプログラムによって決定されるもので、フォー マットフォームはプログラマがそう規定した場合に使われます。

デフォルトではc-formatフォームのみが使われます。翻訳者はこの詳細に ついて考えるべきではありません。

`-d name'
`--default-domain=name'
出力先を`messages.po'ではなく、`name.po'にします。

特別なドメイン名である`-'または`/dev/stdout'は、`標準出力' に出力することを意味します。

`-D directory'
`--directory=directory'
ソースファイルをスキャンする前にディレクトリをdirectoryに変更します。 最終的に`.po'ファイルは元々のディレクトリに書き出されます。

`-f file'
`--files-from=file'
入力ファイル名をコマンドラインから得る代わりに、fileから取得します。

`--force'
たとえメッセージが定義されていなかったとしても、常に出力ファイルを生成しま す。

`-h'
`--help'
このヘルプを表示して終了します。

`-I list'
`--input-path=list'
入力ファイルを検索するディレクトリのリストを指定します。

`-j'
`--join-existing'
既に存在するファイルに出力を追加します。

`-k word'
`--keyword[=word]'
検索するキーワードを追加します(wordを指定しない場合、デフォルトのキー ワードを使わないという意味になります)。

明らかに使用しないことを指定しない限り、 gettextdgettextdcgettextgettext_noopが デフォルトのキーワードとなります。

`-m [string]'
`--msgstr-prefix[=string]'
msgstrエントリの接頭辞として、stringや""を使用します。

`-M [string]'
`--msgstr-suffix[=string]'
msgstrエントリの接尾辞として、stringや""を使用します。

`--no-location'
`#: filename:line'という行を出力しません。

`-n'
`--add-location'
`#: filename:line'という行を生成します(デフォルト)。

`--omit-header'
`msgid ""'エントリを持つヘッダを出力しません。

.gmoファイル生成時の変動を絶つことが出来るので、テスト目的に使用す るのに便利です。これらのファイルはGNU gettextパッケージで使用でき、 msgfmtでも使用できます。両方の結果は同じものになります。

`-p dir'
`--output-dir=dir'
dirというディレクトリにファイルを出力します。

`-s'
`--sort-output'
ソート済みの出力を生成し、重複したものは取り除きます。

`--strict'
Uniforum規定のPOファイルフォーマットに厳密に従った形式で出力します。

`-v'
`--version'
バージョン情報を出力して終了します。

`-x file'
`--exclude-file=file'
fileからのエントリを抽出しません。

追加のPOファイルのサーチパスは`/usr/local/share/nls/src/'となります。

inputfileとして`-'が指定されたときは、標準入力から読み込みます。

xgettextのこの実装はプリプロセッサマクロ中の文字列、ANSI規格での隣 接した文字列の連結、文字列の継続のための行末のエスケープなどのような、幾つ かの厄介なケースの処理を可能とします。


4.2 Cソースの文脈

POモードは、GNU gettextユーティリティを使って作られたPOファイルを扱 うときに力を発揮します。GNU gettextユーティリティは生成したPOファイ ルに特殊なコメントを挿入します。これらの特殊なコメントの一部は、POファイル のエントリとプログラムソース中の未翻訳文字列が出現する場所を関連付けます。

翻訳者が未翻訳エントリを扱う際、彼女が扱う未翻訳文字列はしばしば簡潔すぎた り、暗号的であったり、曖昧であったりといった、わかりにくいものであることが あります。その文字列をどのように翻訳するかを考える前に、翻訳者はそれが何を 意味しているのか、そしてどのような翻訳が適切なのかを理解する必要があります。 そのような問題に直面したとき、翻訳者が判断を下すためにはその文字列が使われ ている本物のプログラムソースを読み、文字列の近くにあるプログラマが書き残し たコメントを捜し出し、そして何らかの手掛かりを得るしかありません。

もちろん、翻訳者が手練のプログラマであればプログラムソースを読むことで更な る情報を得ることが出来るでしょう。しかし、彼女が経験を積んだプログラマでな く、Cのコードに戸惑いを感じたとしても、ソースを読むことについて臆病になっ てはいけません。翻訳者が必要とする何らかのヒントを得ることが出来るという可 能性はまだあるのですから。翻訳者はすぐに、プログラマのコメント、(プログラ マが理由を持って命名した)変数及び関数名、全体の構造について一層注意を払う ことで、プログラムコードが不快なものではないということを学ぶでしょう。

以下のコマンド群は、翻訳者がPOファイルのエントリに関係するプログラムソース の文脈を調べるときに役立つようになっています。

s
プログラムソースの文脈を(繰り返し)表示します。

M-s
メニューから選択することによって、プログラムソースの文脈を表示します。

S
ソースファイルを検索するパスにディレクトリを追加します。

M-S
ソースファイルを検索するパスからディレクトリを削除します。

コマンドs(po-cycle-reference)とコマンド M-s(po-select-source-reference)は、両方ともソースプログラムファイル を別のウィンドウとして開き、現在の翻訳対象となる文字列を表示します。しかし、 もしエントリにソースへの参照がなかった場合、またはソースへの参照を含むソー スファイルがプログラムソースのサーチパス内に存在しなかった場合、コマンドは エラーを表示します。

s(又はM-s)は新しいウィンドウを開きますが、カーソルはPOファイ ルのウィンドウ内に留まります。もし翻訳者がカーソルをプログラムソースウィン ドウに移動させたい場合、もちろんそうすべきなのですが、コマンドOを使 用する必要があるでしょう。

最初にsがタイプされた時点、あるいは直前にソースコードの文脈を参照す るために使われたものとは別のPOファイルエントリが選択された時点で、コマンド sはこのエントリのための最初の文脈を再度表示します。現在のPOファイル エントリにおけるある文脈が表示された時点で、翻訳者が別の文脈を試したい場合 は、ただ単に再度sをタイプするだけで別のウィンドウに文脈が表示されま す。翻訳者がソースファイル中でカーソルをその文脈から動かした場合は、コマン ドsはカーソルを元の文脈に戻すでしょう。あるエントリ中で、他のコマン ドを使用せずコマンドsを繰り返し使用した場合、かつ途中に他のコマンド を使用しなかった場合、POモードは最初に表示した文脈に戻るまで、そのエントリ が参照可能な文脈を次々と表示します。

コマンドM-sの振舞いはそれとは異なります。参照箇所を次々と表示してい く代わりに、参照箇所の一覧を表示して翻訳者にその中から特定の参照箇所を選択 させます。これは補完機能(completion)と一緒に使うのが最善です。翻訳者が M-sの直後にTABをタイプすると、質問に対する(マッチする可能性の ある)答として可能な参照個所全てがメニューとして提示されます。このコマンド はある一つの翻訳対象文字列が本当に複数の文脈で登場するときのみ便利です。

通常、プログラムソースファイルはPOファイルと同じディレクトリで検索されます。 特定の規定として、ソースファイルの検索が失敗した場合、プログラムソース群は POファイルが置かれたディレクトリの直上のディレクトリで検索されます。POファ イルを扱う場合、これら2つの対応によって通常問題は起きません。しかしながら、 POファイルが偶然別のディレクトリに配置されたり、通常のディレクトリとは異な るディレクトリで編集されることもあります。このような場合、翻訳者は正しい POファイルが通常どこに存在するのかをPOモードに伝えなければなりません。その ようなディレクトリが数多く指定された場合、それらはプログラムソースのための いわゆるサーチパスを構成します。コマンド S(po-consider-source-path)は、対話的に新しいディレクトリをサー チパスの先頭に格納するために使われます。コマンドM-S (po-ignore-source-path)は、翻訳者がもはや必要としなくなったディレク トリをサーチパスから選択するために使われます(補完機能付きで)。


4.3 翻訳要約機能の使用

要約機能はまだ実装されていません。

POモードの将来の実装では、翻訳者は既に翻訳したものの要約を保守することにな ります。要約とは、多くのパッケージで頻繁に用いられる翻訳文字列群をま とめた特別なPOファイルのことです。翻訳者は自分が使用する要約に新しいエント リを追加しておき、後で未翻訳エントリを初期化するとき、あるいは既に翻訳され たエントリを更新するときに、要約から翻訳文字列を引き出すことが出来ます。し かしこの作業のためには、要約は正規化されていなければなりません。 See section 2.5 エントリ内の文字列の正規化


5. 既存のPOファイルの更新

5.1 msgmergeプログラムの起動  
5.2 翻訳済みエントリ  
5.3 曖昧な翻訳エントリ  
5.4 未翻訳エントリ  
5.5 廃止エントリ  
5.6 翻訳の修正  
5.7 コメントの修正  
5.8 補助POファイルを参考にする  


5.1 msgmergeプログラムの起動


5.2 翻訳済みエントリ

それぞれのPOファイルエントリについて、msgstrに翻訳が定義され、かつ 曖昧(see section 5.3 曖昧な翻訳エントリ)であるとマーク付けされていない場合、そのエント リは翻訳済エントリと呼ばれます。翻訳済エントリは後からGNU msgfmtによってコンパイルされ、プログラム中で使用可能にされるだけで す。その他のエントリタイプは締め出されます。それらについては翻訳が作成され なかったのです。

幾つかのコマンドはより密接に翻訳済エントリの処理と結び付いています。

t
次の翻訳済エントリを探します。

M-t
前の翻訳済エントリを探します。

コマンドt(po-next-translated-entry)とM-t (po-previous-transted-entry)は前後に移動し、翻訳済エントリを探し出 します。見つからなかった場合、POファイルバッファを回り込んで検索が行われま す。

翻訳済エントリは通常、翻訳者がエントリを翻訳して作成されます 5.6 翻訳の修正。しかし、もし変数 po-auto-fuzzy-on-editnilでなかった場合、最初に新しい翻訳が なされたエントリは曖昧なエントリとなります。そのエントリは後から、公式かつ 本物の翻訳済エントリとなる前に曖昧ではなくされなければなりません See section 5.3 曖昧な翻訳エントリ


5.3 曖昧な翻訳エントリ

それぞれのPOファイルエントリは属性の組を持っています。それらは名前が 付けられた品質であり、特別なシステムコメントを使用することでエントリの翻訳 と明白に結び付けられます。これらの属性のうちの一つは曖昧と名付けら れており、この属性を持つエントリは曖昧な翻訳を持っていると言われます。単純 に曖昧なエントリとも呼ばれます。

曖昧なエントリは、たとえ多くの他の目的のためにそれらが翻訳済エントリとみな されるとしても、通常は翻訳者によって修正されなければなりません。幾つかの新 しいmsgidが古いPOファイル中にあるmsgidからわずかに修正された ものであり、かつその新しく修正されたエントリに対応する、古い翻訳であると考 えられるものとが対になるとmsgmergeプログラムが仮定したとき、 msgmergeプログラムが新しいPOテンプレートファイルによって古い翻訳済 POファイルを更新することによって、これらのエントリが作成されます。本来の文 字列(msgidにある文字列)に対する若干の変更はしばしば翻訳済文字列に影 響し、これは翻訳者による修正を要求します。このため、msgmergeはいく つかのエントリを曖昧であるとしてマーク付けすることでしょう。

翻訳者はまた、エントリに再び手を入れる必要があるということを記憶してきたい ときに、自分自身の利便のためにエントリを曖昧であるとしてマークしておくこと が出来ます。幾つかのコマンドはより密接に曖昧なエントリの処理と結び付いてい ます。

f
次の曖昧なエントリを探します。

M-f
前の曖昧なエントリを探します。

TAB
現在のエントリの曖昧属性を外します。

コマンドf(po-next-fuzzy) とM-f (po-previous-fuzzy)は前後に移動し、曖昧なエントリを探し出します。見 つからなかった場合、POファイルバッファを回り込んで検索が行われます。

コマンドTAB(po-unfuzzy)はエントリに結び付いた曖昧属性を外し、 通常は翻訳済にします。さらに、もし変数po-auto-select-on-unfuzzynilでない場合、TABコマンドは自動的に他に作業する必要があるエ ントリを探し出します。po-auto-select-on-unfuzzyの初期値は nilです。

po-auto-fuzzy-on-editの初期値はnilです。しかし、変数 po-auto-select-on-unfuzzytに設定されたならば、 RETコ マンドによって編集されたエントリには曖昧属性が付与されます。それはダブルク リックを用いることと同じです。この場合、(常にではないにせよ)翻訳者が修正し たときはいつでも、エントリは曖昧になるということが普通になります。もし彼女 が翻訳に満足した場合、彼女は曖昧属性を吹き飛ばし、TABを使って他のエ ントリに対する作業にかかるでしょう。もし彼女がまだ満足していない場合は、そ のエントリを曖昧なままにしたまま他のエントリに移るために、ただSPCを 使うだけです。

翻訳者はまた、あるエントリに後で作業するために簡単に戻れるようにしたいと考 えたのなら、翻訳済エントリを曖昧にするためにDELコマンド (po-fade-out-entry)を使うこともできます。

そして、qコマンドを使ってPOファイルバッファでの作業が完了させたとき に曖昧なエントリがまだ残っていれば、POモードは翻訳者に対して作業を終了する かどうかを確認します。


5.4 未翻訳エントリ

xgettextが最初にPOファイルを生成したとき、msgidは未翻訳文字 列で初期化され、msgstrには空文字列が設定されます。空の翻訳文字列を 持つエントリは未翻訳エントリと呼ばれます。その後、プログラマがプログ ラム中で一部の文字列をほんのちょっとだけ修正した場合、修正された文字列は未 翻訳文字列として、POファイルに新しいエントリとして追加されることになります。

エントリ間を移動する通常のコマンドは、アクティブになったエントリと同じレベ ルにある未翻訳エントリに注意を払います。未翻訳エントリは`msgstr ""'で終了するという事実から、簡単に発見することが出来ます。

翻訳者の作業というのは、未翻訳エントリを探しだして翻訳し、その作業を未翻訳 エントリがなくなるまで繰り返すという意味では(本当に単純な)作業に思えるかも しれません。幾つかのコマンドは未翻訳エントリ処理に特化しています。

u
次の未翻訳のエントリを検索します。

M-u
前にある未翻訳のエントリを検索します。

k
現在のエントリを未翻訳の状態にします。

u(po-next-untranslated-entry)コマンドとM-u (po-previous-untransted-entry)コマンドはそれぞれ、前方と後方に移動 して未翻訳のエントリを探し出します。見つからなかった場合には、検索はPOファ イルバッファを回りこんで継続します。

翻訳文字列を単に空にすることによって、エントリを未翻訳のエントリへと戻すこ とが出来ます。これにはkコマンド(po-kill-msgstr)を使います。 See section 5.6 翻訳の修正.

qコマンドを使用してPOバッファでの作業を終了する際、もし未翻訳の文字 列が残ったままの場合は、POモードは翻訳者に対して作業を終了するかどうかを確 認します。


5.5 廃止エントリ

地域化されているパッケージにおいて、これ以上翻訳する必要がないエントリは msgmergeを使用することによって発見され、コメントアウトされます。こ れらのエントリは、廃止エントリと呼ばれます。

エントリ間を移動する通常のコマンドは、アクティブになったエントリと同じレベ ルにある廃止エントリに注意を払います。廃止エントリはmsgid又は msgstrを含む全ての行が#で開始されているという事実によって簡単 に発見することが出来ます。

幾つかのコマンドは、元々の未翻訳文字列によって翻訳文字列を初期化します。キ ルリングを扱うコマンドのインターフェースは、以前に保存されたテキストを翻訳 文字列として格納することが出来ます。ユーザは翻訳を対話的に編集することが出 来ます。これら全てのコマンドは、その結果として廃止エントリを廃止エントリの ままにしておくことが出来ます。

更に、幾つかのコマンドは廃止エントリの処理に特化しています。

o
次の廃止エントリを検索します。

M-o
前にある廃止エントリを検索します

DEL
アクティブなエントリを廃止エントリにします。又は、廃止エントリを削除します。

o(po-next-obsolete-entry)コマンドとM-o (po-previous-obsolete-entry) コマンドはそれぞれ前方と後方に向かって 廃止エントリを検索します。もしそのようなエントリが見つからなければ、検索は POファイルバッファを回りこんで処理を継続します。

POモードは、廃止エントリのコメントをはずしたり、エントリをアクティブにする ような方法を提供しません。なぜなら、これによってプログラムソース中にあるマー ク付けされた文字列ではない未翻訳文字列が再び導入されてしまうことになるから です。これは無駄なmsgidを導入しないという哲学に基づいています。

しかし、アクティブなエントリをコメントアウトすることは可能であり、これによ りエントリは廃止エントリとなります。GNU gettextユーティリティは後程、 未翻訳文字列を使用することによる翻訳の消失に対して反応します。DELコ マンド(po-fade-out-entry) はカレントのエントリをちょっとだけ消滅さ せる方向へと向かわせます。もしエントリがアクティブ(翻訳対象エントリ)なら、 そのエントリはまず曖昧にされます。もし既に曖昧であれば、確認後にそのエント リはコメントアウトされます。エントリが既に廃止エントリであった場合、そのエ ントリはPOファイルから完全に削除されます。削除したものをPOファイル中の他の (通常は未翻訳の)エントリに置くことによって、翻訳文字列は簡単に再利用出来ま す。See section 5.6 翻訳の修正.

眠れない夜のために、将来のPOモード開発によって解決する興味深い問題について ここで紹介しておきましょう。そのアイディアとは、POモードがより賢くなるであろ うものです。新しく追加された未翻訳の文字列に対して、POモードは全ての廃止エ ントリの中からおそらく適当であろうと思われるものを探しだしてきて当てはめる ようになります。これを実現するためには、アルゴリズム的に難しい問題があるで しょう。文字列の類似性を効果的に測定するための方法を開発しなければなりませ ん。POモードが適切な廃止エントリを発見できるようになったとき、POモードは完 全に翻訳者に決定をさせます。翻訳者の決定作業を簡単にするための使いやすいツー ルの準備をするだけになります。


5.6 翻訳の修正

POモードでは、POファイルを直接編集してEmacsバッファの内容を変更することは 出来ません。そうすることによって、翻訳者がファイルフォーマット全体における 書式の間違いを防いだり、文字列を適切にクォートしたりすることが出来るのです。 それ以外のエラーがまだ起きる可能性はありますが、その一部に関しては Vコマンドによって実行できるバッチ検証プロセスによって検査することが 出来ます。それ以外のエラーは、翻訳者自身の判定、あるいは翻訳されたパッケー ジの(翻訳者と同じ母国語を使う)ユーザによるレポートに頼らざるを得ません。

翻訳文字列を作成するとき、あるいは機械的に検査されたりユーザから報告された エラーを修正するときには、翻訳者は翻訳文字列を修正するために以下に挙げるコ マンドの力を借りなければなりません。

RET
翻訳を対話的に編集します。

LFD
翻訳文字列を、オリジナルの未翻訳文字列で再初期化します。

k
翻訳文字列をキルリングに保存し、それから削除します。

w
翻訳文字列をキルリングに保存しますが、削除しません。

y
翻訳文字列をキルリングから取り出したものに置き換えます。

RET(po-edit-msgstr)コマンドは、現在のPOファイルエントリから取 り出した文字列のコピーが置かれた、新しいEmacsウィンドウを開きます。このウィ ンドウは直ちに編集することが出来、GNU Emacsの修正コマンドの補完機能を使い ながら修正することも出来ます。(ウィンドウにある)文字列は、翻訳者のために引 用符ははぎとられていますから、クォートされていない文字列をウィンドウ内で修 正することが出来ます。作業が完了したなら、通常のEmacsコマンドM-C-c (exit-recursive-edit)を使って元のPOファイルの編集へと戻ることができ ます。このとき、翻訳文字列は新しいもので置き換えられます。C-c C-cというキーはM-C-cと同じ動作をするようにバインドされています。

もし翻訳者が自分自身の翻訳に満足できなくなり、RETコマンドで編集する 前の翻訳を残したほうがよいと感じた場合、まだ元の翻訳が残っている間であれば Emacsの標準コマンドC-](abort-recursive-edit)を使用して、元の 翻訳に戻すことが出来ます。C-c C-kC-]と同じように動作する ようにバインドされています。または、通常通りC-c C-cで終了したあ と、Uをタイプすることによって編集結果を元に戻すことが出来ます。

po-subedit-mode-hookに関数が設定されていた場合、文字列が編集バッファ に挿入された後、かつ再帰的編集が開始される前に設定されていた関数が実行され ます。

翻訳文字列を編集している間に翻訳者が気をつけるべきことは、余計な RET(改行)文字を翻訳文字列に入れてしまったり、逆に必要な改行を 取り除いてしまうということをしないようにするということです。この文字は編集 バッファ上では目に見えないので、間違いを犯しやすいのです。これを防ぐために、 RETは自動的に<という文字を編集している文字列の終端に付加 しますが、この<は文字列の一部ではありません。C-c C-cを使っ て編集ウィンドウから抜けるときに、POモードは自動的に(先程付加した) <を取り除きます。もし翻訳者が文字列の最後の<の後ろに文字を追加 した場合、<に備わった終端属性は失われ、<は文字列の一部となって しまいます。もし翻訳者が<を自分で取り除いてしまったなら、編集した文 字列はあるがままの状態に置かれ、目に見えない改行が文字列の後ろに続 いていたとしてもそれは取り除かれません。また、翻訳文字列が本物の<で 終わる文字列だったのなら、<は取り除かれません。文字列は編集ウィンド ウの中に二つの<が最後に付いているような状態で見えることでしょう。

翻訳文字列(もしくはコメント)が編集されているとき、翻訳者はカーソルをPOファ イルバッファに戻して、さらに別のエントリに移って眺めるようなことをするかも しれません。同時に修正可能なエントリは一つだけなので、編集されたエントリは 編集が終了するとすぐに元通りになります。編集しているものがオープンされたま まで翻訳者がPOファイルバッファをうろつきまわったとしたら、彼女は他のどのエ ントリも修正することができません。もし修正しようとしたなら、POモードは現在 の編集を中断するか、あるいは、他のエントリを変更するために現在の編集を終了 するようにアドバイスするでしょう。

LFD(po-msgid-to-msgstr) というコマンドは、翻訳語を元々の文字 列で初期化、もしくは再初期化します。このコマンドはそれまでの作業を無視して、 オリジナルの文字列で翻訳を再度元に戻したいというときに使われます。

未翻訳エントリを編集するときはいつでも、LFDコマンドが自動的に実行さ れるように設定することが出来ます。po-auto-edit-with-msgidtに設定すれば、もしまだ翻訳が存在しない場合、オリジナルの文字列によっ て初期化されます。po-auto-edit-with-msgidの初期値はnilです。

事実、空の文字列から翻訳を開始するのとオリジナルの文字列のコピーと共に開始 するのとのどちらがよいのかは、単に好みの問題です。あるときは、元々の言語と ターゲットとする言語は、白紙から書き始めたほうがよいほど異なっています。ま た別の場合、元々の言語とターゲットとする言語はオリジナルの文字列して設定さ れているものの幾つかの単語を再度打ち直すだけですむかもしれません。翻訳者も また、彼女の目の前にオリジナルの文字列があるほうを好むことでしょう。彼女は オリジナルの文字列を翻訳によって上書きしていくことになります。仮にオリジナ ルの文字列を消去するために余分な編集作業が必要となるにしても。

コマンドk(po-kill-msgstr)は、エントリを未翻訳エントリへと戻す ことによって、翻訳文字列を空にするだけのものです。しかしこの間に、以前の翻 訳文字列はキルリングとして知られる別の特別な場所に置かれます。コマンド w(po-kill-ring-save-msgstr)もまた翻訳のコピーをキルリングに置 きますが、この場合は別の方法でエントリを抜け出します。つまり、翻訳はそのエ ントリから取り除かれないのです。両方のコマンドは正確にバッファ間で 共有されるキルリングを使います。そしてそれはGNU Emacsを愛する人にとっては 既によく知られたものです。

翻訳者はキルリングを様々な翻訳の置き場として使うために、kまたは wを頻繁に使うことになるでしょう。キルリングからは、文字列を後から様々 なEmacsバッファに再挿入することが出来ます。特に、キルリングは一つのPOファ イルバッファ中の異なるエントリ間での翻訳文字列の移動、またもし同時に複数の バッファを操作しているであれば、複数のPOファイルの間での翻訳文字列の移動を 行うために使用することが出来ます

POモードを使用していないバッファとも容易にデータ交換が行えるように、 kコマンドは翻訳文字列を保存前のクォートされていない状態でキルリング に置きます。外部クォートは除去され、複数行からなる文字列は連結され、バック スラッシュによるエスケープシーケンスは対応するキャラクタに置き換えられます。 廃止エントリに対する場合でも、翻訳は保存前のコメントが解除された状態となり ます。

コマンドy(po-yank-msgstr)は現在のエントリをキルリングから取り 出された文字列で完全に置き換えます。GNU Emacsでの用語に従えば、置き換える 文字列はPOファイルバッファにヤンクされたと言いますSee section `Yanking' in The Emacs Editor。最初にyが使用されたとき、翻訳は一番最近に キルリングに加えられたデータで置き換えられます。もし yが再度タイプさ れたなら、途中に何らかのキーストロークを必要とすることなく直ちに、挿入され た翻訳は取り去られて二番目に新しくキルリングに加えられたデータで置き換えら れます。ある行中で繰り返しyが使用された場合、翻訳者が本当に必要とし た文字列を見つけ出すまで、翻訳はキルリング中に保存された文字列によって次々 と置き換えられます。

POファイルエントリに文字列がヤンクされたとき、文字列はPOファイルのフォーマッ トに従うよう、完全にそして自動的に再度クォートされます。更に、もしエントリ が廃止エントリであれば、POモードは挿入された文字列を適切にコメント化します。 もう一度、翻訳者はにクォートに関する配慮、それにもちろん、プログラム中で使 われる翻訳文字列それぞれの必要性に関する配慮を、翻訳者自身に負わせてはいけ ません。

kまたはwは、文字列をキルリングに格納する唯一のコマンドではない ことを覚えておいて下さい。翻訳文字列(または翻訳者コメント)を置き換えるほと んどのPOモードコマンドは、自動的に古い文字列をキルリングに格納します。この ルールの主な例外は、ヤンクするコマンド群自身です。

キルとヤンクの操作を明確にするために、一般的な状況を取り上げて実際の例を示 しましょう。プログラマがプログラムに合うように文字列をちょっとだけ修正した とすると、その変更は後程、修正された文字列用に新しい未翻訳エントリとして POファイルに反映され、以前の翻訳エントリは廃止エントリとなります。多くの場 合、翻訳者は自分の作業が楽になるように廃止エントリから翻訳文字列を戻します ので、未翻訳エントリのmsgstrフィールドは以前の翻訳で初期化されます。 一度この作業を行えば廃止エントリは不要となり、安全に削除出来るようになるで しょう。

翻訳者が未翻訳のエントリを発見し、翻訳に多少の違いが存在すると感じたなら、 彼女は現在のエントリの位置をマークするために直ちにmを使用し、未翻訳 の文字列に対応する翻訳が見つかることを期待しながらoを用いて廃止エン トリを探し出します。見つかったなら、彼女は翻訳を消去するDELコ マンドを使用して廃止されたエントリを削除し、翻訳をキルリングに置きます。そ して、rによって元々の未翻訳エントリの位置へと戻り、yを使って保 存した翻訳をmsgstrフィールドへとヤンクします。翻訳者は RETを使って翻訳の内容をより良く修正し、後程u、そして mを再度使用して次の未翻訳文字列へと移動します。

キーの流れを繰り返しタイプしていると、これらのシーケンスを学習し要求時にそ のシーケンスを再度実行するというEmacsの能力に習熟すれば便利になるというこ とに翻訳者は気が付くでしょうSee section `Keyboard Macros' in The Emacs Editor


5.7 コメントの修正

真剣に行われたあらゆる翻訳作業は、決定されるべきこと、そして更なる文書化の 選択について、多くの言語的困難を増大させます。これらのドキュメントは、翻訳 者が自由に作成し、削除し、修正することが出来る翻訳者コメントの形でPOファイ ル中に保存されます。これらのコメントは、翻訳者が後からこのPOファイルで作業 するときに便利なものとなるでしょう。

最初の`#'の直後に空白を伴わないコメント、例えば`#.'`#:'は 翻訳者コメントではありません。これらはもっぱら他のgettextツー ルによって作成されます。以下に述べるコマンドはコメントを追加する際に先の決 まりを変更することはなく、翻訳者に修正させることはありません。See section 2.2 POファイルのフォーマット

以下のコマンドは、それらが適応される一般的な傾向から、翻訳を修正するコマン ドに幾分似ています。See section 5.6 翻訳の修正

#
翻訳者コメントを対話的に編集します。

K
翻訳者コメントをキルリングに保存して、削除します。

W
御訳者コメントをキルリングに保存しますが、削除しません。

Y
翻訳者コメントをキルリングから取り出したもので置換します。

これらのコマンドは翻訳文字列を修正するためのPOモードコマンドに似ており、同 じような方法で動作しますが、翻訳文字列ではなく翻訳者が使うためのPOファイル のコメントを扱うという点で異なっています。ですので、以下に述べる説明はごく 簡潔に抑えてあります。詳細は既に述べているのですから。See section 5.6 翻訳の修正

#(po-edit-comment)コマンドは、現在のPOファイルエントリにある 翻訳者コメントのコピーと共に新たなEmacsのウィンドウを開きます。該当するコ メントがなければ、POモードは翻訳者がそのエントリに対してコメントを付加しよ うとしていると判断して、空のウィンドウを開きます。コメント記号(#)と それに続くスペースは編集前に自動的に取り除かれ、編集後に再度挿入されます。 廃止エントリにある翻訳者コメントに対しては、コメント外し(uncommenting)と再 コメント化(recommenting)が行われます。ウィンドウを一度編集したなら、翻訳者 はC-c C-cによってコメントの編集を終えることができます。

po-subedit-mode-hookに定義された関数群がもしあれば、それらは文字列 が編集バッファに挿入された後、かつ再帰的な編集に入る前に実行されます。

K(po-kill-comment)コマンドは全ての翻訳者コメントを切り取り、 それをキルリングに保存します。W(po-kill-ring-save-comment)は 翻訳者コメントのコピーを取得しそれをキルリングに置きますが、現在のエントリ はそのままの状態にします。M-Y(po-yank-comment)コマンドは、キ ルリングの先頭から取り出した文字列で翻訳者コメントを完全に置き換えます。こ のコマンドがすぐに繰り返された場合、挿入されたコメントは回収され、キルリン グから取り出した別の文字列によって置き換えられることになります。

キルリングにおいては、全ての文字列は自然に振る舞います。翻訳翻訳者コメントの間に区別はありません。例えば、翻訳者がある翻訳をたっ た今完了したが、その翻訳があまりよいものではなく、問題点を記録しておこうと 考えて新しい翻訳者コメントを作成しようとしていると仮定してみます。彼女は直 前の翻訳を翻訳者コメント中に引用したいことでしょう。そのために、彼女は翻訳 者コメントを、まだキルリングの先頭に置かれている直前の翻訳によって初期化し ます。編集によって直前の翻訳は既にキルリングに置かれているので、彼女がただ 単に#の前にM-wをタイプすれば直前の翻訳はそこに置かれ、説明文を 記述する準備は整います。

一方、既に何らかの翻訳者コメントが存在し、翻訳者がそれらのコメントを完全に 別のもので置き換えたいとします。そのような場合、彼女は#を使ってコメ ントを編集します。編集ウィンドウに移ったならば、彼女は通常のGNU Emacsのコ マンドであるC-y(yank)、あるいは以前の翻訳を取り出すために M-y(yank-pop)を使うことが出来ます。


5.8 補助POファイルを参考にする

POモードは多くの言語に通じた知識のある翻訳者の助けとなります。既に作業を完 了した翻訳の成果を、たまたま彼女が知っている別の言語に対して用いることが出 来ます。POモードはこれら他の言語への翻訳を、翻訳者の仕事への追加のコンテキ ストとして準備します。さらに、このような方法で作業することを好む翻訳者に対 しては、一度に多くの言語への翻訳を行うことを簡単にする機能があります。

補助POファイルとは、翻訳者が作業の対象としている一つのパッケージ中に 存在する、異なった母国語をターゲットとするPOファイルです。補助POファイルを 宣言し、操作するための、そして作業中のエントリのコンテキストを示すためのコ マンド群が存在します。

POモード中で使用可能な補助ファイル用のコマンドには、このようなものがありま す。

a
同じエントリに対する別の翻訳への補助ファイルを検索します。

M-a
特定の補助POファイルへと切り替えます。

A
POファイルを補助ファイルとして宣言します。

M-A
作業中のPOファイルを補助ファイルのリストから削除します。

コマンドA(po-consider-as-auxiliary)は、コマンド M-A(po-ignore-as-auxiliaryによって削除されるまで、現在のPOファ イルを補助ファイルのリストへと追加します。

コマンドa(po-cycle-auxiliary)は、現在のエントリと同じ msgidフィールドを持つ別の言語の翻訳エントリを、全ての補助POファイル 中から検索します。検索されたPOファイルがもしあれば、そのファイルは現在の POファイルとして(ウィンドウの上部に)表示されます。もしまだそうでなければ、 この処理を行う前に現在のPOファイルもまた補助ファイルにします。この新しく表 示されたPOファイルでaが実行されれば、別ののPOファイルを検索すること になるでしょう。結局のところ、aはオリジナルのPOファイルへとyield backすることになります。

コマンドM-a(po-select-auxiliary)は翻訳者に選択した補助ファイ ル名を補完機能付きで尋ね、選択されたPOファイルへと切り替えます。このコマン ドは選択されたファイルが現在のエントリと合致するmsgidフィールドを持っ ているかどうかを調べ、もし持っていればこのエントリをカレントにします。でな ければ、選択されたファイルのカーソルはそのままです。

全てが完全に動作するためには、補助POファイルは正規化、つまり、 msgid厳密に同じように書かれていなければなりません。同じ文 字列を表現するmsgidフィールドは様々な方法で記述される可能性がありま すが、異なった記述はPOモードの補助ファイルを扱うコマンドの元々の動作を妨害 することでしょう。既存の多くのPOファイルは同じGNU gettextツール群に よって作成されたmsgidエントリを持っているので、実際にはこれが問題と はなることは考えにくいです。

しかし、ソースファイル中の文字列をマーキングしながら最初にPOモードによって 作られたPOファイルは異なった形で正規化されています。それらは`M-x normalize'コマンドの結果作られたPOファイルです。POモードとその他のGNU gettextツール群の間にあるこれらの矛盾が完全に解決されるまでに、翻訳 者は正規化の問題点に気が付いているでしょう。


6. MOファイルの作成

6.1 msgfmtプログラムの起動  
6.2 GNU MOファイルのフォーマット  


6.1 msgfmtプログラムの起動

 
Usage: msgfmt [option] filename.po ...

`-a number'
`--alignment=number'
文字列のアライメントをnumberバイト(デフォルトでは1)にします。

`-h'
`--help'
このヘルプを表示して終了します。

`-I list'
`--input-path=list'
入力ファイルを検索するディレクトリのリストを指定します。

`--no-hash'
バイナリファイルにハッシュテーブルを含まないようにします。

`-o file'
`--output-file=file'
出力するファイルの名前をfileにします。

`--strict'
Uniforum/Sunの実装に厳密に従うよう、プログラムに指示します。現状、これは出 力ファイルの命名ににみ影響します。このオプションが与えられていないときは、 出力ファイルの名称はドメイン名称と同じものとなります。もし「厳密な Uniforumモード」が指定されているならば、既に存在するのでなければファイル名 の末尾に`.mo'が付与されます。

我々はSunの実装におけるこの動作はどちらかと言えばあまりスマートで ないと考えますので、デフォルトではこのモードは選択されていません

`-v'
`--verbose'
翻訳エラーとなるような入力ファイルの異常を検査して見つけ出します。 msgidmsgstrの文字列は調査、比較されます。一方の文字列が改 行で始まったり、あるいは改行で終わっているにも関わらず、もう一方がそうでな いのは正常でないと判断されます。

同様に、文字列がprintf系関数で使われるフォーマット文字列として出現 しているならば、両方の文字列は同じ数、そして同じ種類のの`%'書式指定子 を持っているはずです。フラグc-formatまたは possible-c-formatが特別なコメント#,としてこのエントリに出現し ているなら、チェックが実行されます。例えば、このチェックは`%.*s'に対 する`%s'や、`%d'に対する`%s'`%d'に対する `%x'な どを検査します。これは位置パラメータ(positional parameter)に対しても行われ ます。

通常、xgettextプログラムは文字列がフォーマット文字列かそうでないか を自動的に決定します。しかし、このアルゴリズムは完全ではありません。 printf系関数で使われていないにも関わらず文字列をフォーマット文字列 と見なすことがあり、そのような場合msgfmtはエラーを報告することでしょ う。逆の事例、すなわち文字列がprintf系関数中で使用されているのに、 フォーマット文字列として認識されないといったこともあります。

この問題を解決するため、プログラマはxgettextプログラムに対してどち らであるかを指示することが出来ます (see section 3.4 続く文字列に関して何かを伝えること)。翻訳者は#,行 からこのフラグを削除するということを考えてはいけません。この「修正」は、次 回msgmergeが呼び出されたときに速やかに元に戻されます。

`-V'
`--version'
バージョン情報を出力して終了します。

入力ファイルが`-'の場合、標準入力から読み込みが行われます。出力が `-'であれば、出力は標準出力に書き出されます。


6.2 GNU MOファイルのフォーマット

生成されたMOファイルのフォーマットは、後で例示する図によってもっともわかり やすく記述されています。

最初の2ワードはファイルの識別に用いられます。マジックナンバーはGNU MOファ イルであることを常に示します。このナンバーはMOファイルを生成した計算機のバ イトオーダーで格納されており、したがってマジックナンバーは実際には 0x950412de0xde120495の二種類があります。二番目のワードは、 ファイルフォーマットの現在のリビジョンを表わしています。現在のところ、この リビジョンは0です。これは将来のバージョンでは変わる可能性があり、MOファイ ルを読み出すプログラムが新しいフォーマットと古いフォーマットを区別できるこ とを保証します。それによってどちらのフォーマットも正しく扱うことができます。 バージョンはマジックナンバーとは分離されており、異なるフォーマットのために 異なるマジックナンバーが使われることはありません。これは主に、 `/etc/magic'がそれ程頻繁にはアップデートされないためです。内部フォー マットバージョン識別子とマジックナンバーを分離しておくのは良いことでしょう。

続いて、ファイル後方にあるテーブルへのポインタの数があり、MOファイルを読み 込むプログラムをリコンパイルことなくにMOファイルの前方部分の拡張ができるよ うになっています。幾つかのフラグビット、使用しているキャラクタセットの指定、 新しいテーブルなどを後から挿入するときに便利でしょう。

さらに続いて、図中ではオフセットOとオフセットTとして示される、 文字列ディスクリプタの二つのテーブルがあります。このテーブルは両方とも、二 つの32ビット整数を使った文字列ディスクリプタであり、一つは文字列の長さ、も う一つはMOファイル中の文字列に対する、ファイルの先頭を起点としてバイトで数 えたオフセット位置を表わしています。最初のテーブルにはオリジナル文字列に対 するディスクリプタが置かれており、オリジナルの文字列は昇順の辞書式順序で並 べられています。二番目のテーブルには翻訳文字列のディスクリプタが置かれてい ます。これは最初のテーブルと相似するものであり、適切な翻訳文字列を見つける には、オリジナル文字列のあったのと同じインデックスで、二番目の配列の配列ス ロットにアクセスする必要があります。

オリジナル文字列はソートされていますので、MOファイルがハッシュテーブルを持っ ていなかったり、MOファイルにあるハッシュテーブルを使うのが現実的でないとき には単純な二分検索を行うことが可能です。これには別の利点もあります。すなわ ち、GNU gettextのPOファイル中にある空文字列は通常、特定のMOファイル に添付される幾つかのシステム情報へと翻訳されます。そしてこの空文字 列はオリジナル文字列のテーブルの先頭に、対応する翻訳も翻訳文字列のテーブル の先頭に置かれるので、システム情報を非常に簡単に見つけられるようになるので す。

ハッシュテーブルのサイズSは0であっても構いません。その場合、ハッシュ テーブルはそのMOファイルの中にはないということになります。人によっては、事 前に算出されたハッシュテーブルがディスクスペースを食い、スピードもそれほど 向上するわけではないため、ハッシュテーブルがないことを好むかもしれません。 このハッシュテーブルはMOファイルにある文字列のソート済み配列に索引を設定す るものです。衝突の解決はダブルハッシング(double hasing)によって行われます。 使用されている正確なハッシングアルゴリズムはGNU gettextのコードに依 存していますので、ここでは説明しません。

ハッシュテーブルに続いて、文字列そのものが置かれます。各文字列は NULで終端されていますが、このNULは文字列ディスクリプタにあった 文字列の長さとしては数えられていません。msgfmtプログラムはMOファイ ル文字列のアライメントを選択するオプションを持っています。このオプションを 使うことで、各文字列は指定されたアライメントで始まるように配置されます。一 部のRISCマシンでは正しいアライメントに置くことによってスピードが向上します。

MOファイルはNULが埋めこまれている文字列を持つことが出来ます。しかし、 プログラムのインターフェースは現在すでに文字列がNULで終端されている ことを仮定していますので、NULを埋めこむということは少々意味がないこ とです。しかし、MOファイルのフォーマットは後から他のインターフェースを扱え るほど汎用的です。たとえば、MOファイル中に(NULが思いがけず入ってしま うような)ワイド文字を正しくインプリメントしたいと考えたとしても問題ありま せん。

この独特の結果は、GNU gettext開発フォーラムにおいて非常に激しく討論 され、MOファイルフォーマットは何度も発展し、変化することが出来るようにされ ました。後から同時に複数のフォーマットをサポートすることさえ可能とするもの なのです。しかし確実に、我々はスタート地点となるものを得ました。ここで説明 したMOファイルフォーマットはよい出発点です。コンクリートで固められたような ものは何もなく、フォーマットは後日簡単に進化できるものであり、我々は現在の アプローチを快適なものだと感じています。

 
        バイト
             +------------------------------------------+
          0  | マジックナンバー = 0x950412de            |
             |                                          |
          4  | ファイルフォーマットのリビジョン = 0     |
             |                                          |
          8  | 文字列領域の長さ                         |  == N
             |                                          |
         12  | オリジナル文字列テーブルへのオフセット   |  == O
             |                                          |
         16  | 翻訳文字列テーブルへのオフセット         |  == T
             |                                          |
         20  | ハッシュテーブルのサイズ                 |  == S
             |                                          |
         24  | ハッシュテーブルのオフセット             |  == H
             |                                          |
             .                                          .
             .  (更にエントリが追加される可能性がある)  .
             .                                          .
             .                                          .
             |                                          |
          O  | 0番めの文字列の長さとオフセット   ----------.
      O + 8  | 1番めの文字列の長さとオフセット   ------------.
              ...                                    ...   | |
O + ((N-1)*8)| (N-1)番めの文字列の長さとオフセット      |  | |
             |                                          |  | |
          T  | 0番目の翻訳の長さとオフセット  -----------------.
      T + 8  | 1番目の翻訳の長さとオフセット    -----------------.
              ...                                    ...   | | | |
T + ((N-1)*8)| (N-1)1番目の翻訳の長さとオフセット       |  | | | |
             |                                          |  | | | |
          H  | ハッシュテーブルの先頭                   |  | | | |
              ...                                    ...   | | | |
  H + S * 4  | ハッシュテーブルの終わり                 |  | | | |
             |                                          |  | | | |
             | NULで終端された0番めの文字列  <-------------' | | |
             |                                          |    | | |
             | NULで終端された1番めの文字列  <---------------' | |
             |                                          |      | |
              ...                                    ...       | |
             |                                          |      | |
             | NULで終端された0番めの訳語      <---------------' |
             |                                          |        |
             | NULで終端された1番めの訳語      <-----------------'
             |                                          |
              ...                                    ...
             |                                          |
             +------------------------------------------+


7. ユーザとしての視点

GNU gettextが真にそのゴールにたどり着いたとき、平均的なユーザはある 種の驚きの喜びを感じるでしょう。スクリーンのどこにでも彼ら自身のネイティブ ランゲージが表示されるという、奇妙な魔法の効果が現れるからです。愚直なユー ザはそれについて全く驚くことなく、ただ単に彼らの言語が認められたと 話し合うだけで、どちらかと言えば他の点で不幸になるかもしれません。

それでは、ユーザの視点がなるべく単純になるように、全ての方法の中で人が GNU gettextを見るように、その魔法についてここで説明することにしましょ う。全ての他のソフトウェアエンジニア、すなわちプログラマ、翻訳者、保守担当 者はこの魔法が実現するようにいっしょになって働きます。これは長くそして革新 的な仕事で、進捗状況についての情報は翻訳プロジェクトから入手可能です。

パッケージが配布されたとき、そこには二種類のユーザが存在します。それは、 自分や他の人が使うために配布物を受けとって展開し、コンフィグレーションし てコンパイルとインストールを行うインストーラと、インストールされた パッケージのプログラムを使うエンドユーザです。GNU gettextは インストーラとエンドユーザの両方に魔法の効果を提供します。

7.1 現在の`ABOUT-NLS'  
7.2 インストーラへの魔法  
7.3 エンドユーザへの魔法  


7.1 現在の`ABOUT-NLS'

GNU gettextを使用している全てのパッケージにおいて、全ての言語が等し くサポートされているわけではありません。あるGNUパッケージがGNU gettextを使っているかどうかは、配布物中に`NLS'情報ファイルがあ るかどうか、`ll.po'ファイルがあるかどうか、`intl/'ディレク トリがあるかどうかということをチェックすることで確認できます。国際化対応さ れたパッケージは、通常多くの`ll.po'ファイルを持っています。ここ で挙げたllは言語を示しています。7.3 エンドユーザへの魔法ではllフォーマッ トについて完全な解説を行っています。

より一般的には、マトリックスは翻訳プロジェクトのその時点での状態を明らか にし、多言語メッセージ(multilingual messages)のために準備されたパッケー ジのリストアップや、各パッケージがサポートしている言語のリストアップを行っ ています。この情報は頻繁に変更されるので、このマトリックスはGNU gettextマニュアルの中には含まれていません。この情報はGNUの配布パッ ケージの中の`ABOUT-NLS'ファイルで確認することができますが、しかしこ の情報は配布パッケージそのものと同じくらい古いものです。この `ABOUT-NLS'ファイルの、更新された情報を含む最新のコピーは翻訳プロジェ クトのサイト、そしてほとんどのGNUアーカイブサイトで見つけることができま す。


7.2 インストーラへの魔法

GNU gettextを内部で全面的に使用しているパッケージは、デフォルトでは 翻訳されたメッセージが使用可能になるようにしてインストールされます。コンフィ グレーション時に、それらのパッケージは基礎となるホストシステムが提供し使用 可能となっているcatgetsgettextといった関数を検出します。こ れらのどちらかが使用可能であれば、GNU gettextライブラリは自動的に準 備されて使われるようになります。インストーラにはコンフィグレーション時に特 別なオプションを与えることが出来、それによってインストーラの動作を変えるこ とができます。`./configure --with-included-gettext'コマンドはシステム のcatgetsgettextをバイパスして、代わりにGNU gettextを使用します。`./configure --disable-nls'とすると、翻訳 メッセージを全面的に使用しないプログラムを生成します。

国際化対応されたパッケージは通常、多くの`ll.po'ファイルを持って います。翻訳が禁止されていない限り、これらのファイルはすべてパッケージといっ しょにインストールされます。しかし環境変数LINGUASが設定されている場 合は、コンフィグレーションに優先してインストールするファイルを制限します。 LINGUASに設定する内容は、使用する言語を示すためのスペースで区切られ た2文字のコードのリストです。


7.3 エンドユーザへの魔法

ここで、GNU gettextを内部的に使っているパッケージ、そしてインストー ラがconfigure時に翻訳を無効にしなかった場合について考えてみましょう。 ユーザがするべきことは、パッケージ中のプログラムを使う前に環境変数 LANGに適切な`ll'を設定するだけですSee section 7.1 現在の`ABOUT-NLS'。たとえ ば、ドイツのサイトの場合を考えてみましょう。ユーザはシェルプロンプトで `setenv LANG de'(cshの場合)、または`export LANG; LANG=de'(shの場合)と実行するだけです。ユーザーはこれを彼らの `.login'`.profile'の中で行うこともできます。


8. プログラマとしての視点

GNU gettextによって提供される現在のメッセージカタログの実装における 一つの狙いは、インストールする人間が望むならばシステムのメッセージカタログ の取り扱いに使えるということでした。そのため、おそらく我々は既に知っている 解決方法について検討すべきでした。POSIXコミュニティの人々は、以下に述べる 準公式標準については意見を合わせようとしませんでした。事実彼らは全てのもの と意見を合わせようとせず、インターフェースの例を含むものさえ決定しませんで した。主要なUNIXベンダは二つの重要な仕様のどちらを採用しているかで分けられ ます。X/Opensのcatgetsと、Uniforumのgettextインターフェースです。ここでは 両方について記述した後、このジレンマに関して我々の取った解決方法について説 明します。

8.1 catgetsについて  
8.2 gettextについて  
8.3 二つのインターフェースの比較  
8.4 独自のプログラムでlibintl.aを使う  
8.5 Being a gettext grok  
8.6 プログラマの章についての一時的なメモ  


8.1 catgetsについて

catgetsの実装はX/OpenのX/Open Protability Guide, Volume 3, XSI Supplementary Definitions, Chapter 5. で定義されているものです。しかし、こ の標準を作成するプロセスは一部のUNIXベンダには遅すぎ、そのため一部のベンダ は標準の仮バージョンの段階で実装を行ってしまいました。もちろんこれは、たと えcatgetsの使い方と同一のインターフェースを保証していたとしても、プ ラットホームに依存しないプログラムの作成には問題となります。

もう一つ、ただ委員会メンバの一グループだけによってこのインターフェースが作 成されたということについて、個人的に言いたいことがあります。彼らは決して実 際にこのインターフェースを使ってプログラムしようとはしてはいません。このイ ンターフェースは高速かつメモリを節約する実装で、このインターフェースを使う ということはユーザにとっては幸せでしょう。しかし、プログラマはこのインター フェースを嫌っています(少なくとも私と、その他数人はそうです...)。

しかし我々は、UNIX(tm)に関する権利の委譲に関する全てのトラブルの後で、最終 的にX/Openへと至らしめたのはこのインターフェースを発行した人間と同じ人間だ という一点を忘れてはなりません。これは私に、このインターフェースは将来の UNIX標準(たとえばSpec1170)となり、したがって全てのUNIXの実装(この名前を有 することを許されている実装)の一部となると予想しています。

8.1.1 インターフェース  catgetsのインターフェース
8.1.2 catgetsインターフェースにおける問題点とは?!  


8.1.1 インターフェース

catgetsに対するインターフェースの実装は、ファイルアクセスとして使用 される三つの関数からなります。一つは使用するカタログをオープンする catopen、二つめはメッセージテーブルのアクセスを行うcatgets、 三つめは作業が終了した後でクローズするためのcatcloseです。これらの 関数のプロトタイプと(巻数が必要とする)定義は<nl_types.h>というヘッ ダファイルにあります。

catopenは次のように使用します。

 
nl_catd catd = catopen ("catalog_name", 0);

この関数は引数としてカタログの名前をとります。これは通常、プログラムまたは パッケージの名前を参照します。二番目の引数は標準では指定しません。様々なシ ステムに対して実装されるためなのかもしれませんが、私は正確なところは知りま せん。そのため一般的な助言としては「この値として0を使いなさい」とい うことになります。この関数の戻り値はメッセージカタログのハンドルであり、 openが返すファイルハンドルと同様な意味を持っています。

このハンドルはもちろん、次のようにしてcatgetsの引数として使うことが できます。

 
char *translation = catgets (catd, set_no, msg_id, "original string");

この関数呼び出しの最初の引数はカタログディスクリプタです。2番目の引数はこ のカタログ中のメッセージを特定するもので、msg_idで指定されるメッセー ジが取得されます。catgetsは従って、3段アドレッシング(three-stage adressing)を使用します。

 
カタログ名 => 番号のセット => メッセージID => 翻訳

四番目の引数は翻訳文字列を特定するためには使われません。この引数は翻訳文字 列の特定が失敗したときに使用されるデフォルト値として与えられます。忘れては いけない重要なことは、catgetsの戻り値の型がchar *であるにも関らず、 返された文字列を変更してはいけないということです。これは const char *としたほうが良いのですが、この標準はANSI Cの一年前、 1988年に出版されていました。

これらの関数の最後のものは期待通りに使われ、動作します。

 
catclose (catd);

この呼び出しを行った後、この記述子を使ってcatgetsを呼び出すことは、 もはや合法ではありません。


8.1.2 catgetsインターフェースにおける問題点とは?!

ここで、我々がお話する問題がどこにあるのかを明確にしましょう。事実、このイ ンターフェースは現実的な方法で使うことはできますが、メッセージカタログの構 築は苦痛です。この理由はcatgestsの第三引数、つまり一意なメッセージ IDにあります。ある単一のセット中の全てのメッセージは数値でなければなりませ ん。おそらくあなたは、ソースコードを変更している間、ずっとこのようなリスト を保持し続けるという問題について理解出来るでしょう。こっちで新しいメッセー ジを追加して、あっちで一つ削除します。もちろん、この混乱を収拾するのを助け るための多くのツールが開発されてはいますが、ある局面で使えるものは他の局面 では使えなかったりするのです。我々は、別のアプローチには全く問題がないのに、 それらはずっと扱いやすいとは言いたくありません。


8.2 gettextについて

gettextのインターフェースの定義はUniformの提案から来ていて、また、 少なくともひとつの主要なUNIXベンダ(Sun)による最新の実装に従っています。し かし、これは何らかの正式な標準(official standard)によって規定されている規 格ではありません。

このソリューションにおける大きな特徴は、通常のファイル操作(オープン - 使用 - クローズ)の方法に従わず、プログラマにそれ程多くの、特にユニークなキーの 扱いに関して、負荷を与えないということです。もちろん、この方法でもユニーク なキーは必要となりますが、キーとしてメッセージそれ自身(どれほど長かろうと 短かろうと)とを使用します。これら二つの手法の比較についての詳細は See section 8.3 二つのインターフェースの比較

次のセクションにはこのインターフェースの詳細な説明があります。このインター フェースはGNU gettextライブラリのために選ばれたインターフェースなの で、詳しく説明します。このライブラリの使用法に興味を持ったプログラマは、こ こでの説明にも興味を持つでしょう。

8.2.1 インターフェース  
8.2.2 曖昧さの解決  
8.2.3 メッセージカタログファイルの所在  
8.2.4 gettext関数群の最適化  


8.2.1 インターフェース

インターフェースは最低限の機能として、a) 文字列を持ってくるドメイン (domain)の選択(単一ドメインを全てのプログラムに、というのは構築と保守が難 しくなり、また恐らくは不可能ですので、現実的ではありません)、b) 選択したド メインの文字列へのアクセス、を備えていなければなりません。

これは主としてgettextのインターフェースの説明です。このインターフェー スはグローバルドメインを持っています。もちろんこのドメインはユーザにより選 択可能です。

 
char *textdomain (const char *domain_name);

この関数によってLC_MESSAGEカテゴリの現在のグローバルドメインのステー タスを変更したり、問い合わせたりすることができます。引数はNUL文字で終端さ れた文字列で、その文字列はファイル名に使うことのできるものである必要があり ます。引数domain_nameNULLであった場合、この関数は現在の設定 値を返します。もし事前に値がセットされていなければ、デフォルトドメインの名 前としてmessagesが返されます。ここで、textdomainの戻り値の型 がchar *であるにも関らず、書き換えが許されていないことに注意して下 さい。同様に、有効性のチェックがなされないということも重要です。名前が有効 でない場合、対応する翻訳文字列が返ってこないということでそれが認識できるで しょう。

textdomain関数を使って設定したドメインを使うには

 
char *gettext (const char *msgid);

のようにします。これは想像できる最も単純で現実的な形式です。もし現在のドメ インで取得可能ならば、msgidを翻訳した文字列が返されます。もし取得で きなければ、引数がそのまま返されます。引数がNULLであったときの結果 は未定義です。

使用しているドメインは曖昧なものであるということを覚えておいていて下さい。 LC_MESSAGESロカールに対する現在のドメインの値が使用されます。プログ ラム中でgettextを呼び出す間にLC_MESSAGESロカールの変更を行っ たなら、それぞれの呼び出しでは(他方と)異なったメッセージカタログが参照され ます。

国際化されたパッケージが通常使用するもっとも単純なケースでは、 textdomainの呼び出しが最初に一度だけ行われ、ここでドメインにユニー クな名前、通常はパッケージ名がセットされます。それ以降のコードでは、翻訳さ れるべき全ての文字列はgettext関数を通じて翻訳されます。これによって、パッ ケージはあなたの使う言語をしゃべるようになります。


8.2.2 曖昧さの解決

一つのドメインだけを使うという手法は殆んどのアプリケーションで有効に働きま すが、二つ以上のドメインから翻訳文字列を取り出す必要があるかもしれません。 もちろんtextdomainを呼び出して異なるドメインに切り替えることも出来 ますが、これは便利ではありませんし、高速でもありません。このドキュメントを 記述している間に議論されたケースはこの例に当てはまるでしょう。「一般的に使 用される関数に関する全てのエラーメッセージは、分割されたerrorという ドメインに格納するのが良い」というものです。これにより我々は、エラーメッセー ジを一度だけ翻訳すれば良くなるでしょう。

このため、さらに二つの関数の文字列取得用関数があります。

 
char *dgettext (const char *domain_name, const char *msgid);
char *dcgettext (const char *domain_name, const char *msgid,
                 int category);

これらの関数は両方とも先頭に追加の引数を取ります。この引数は textdomainの引数に対応するものです。dcgettextの第三引数は、 LC_MESSAGES以外の別のロカールを使うことを許可します。しかし私には、 これが便利なのかどうかはわかりません。domain_nameNULLであっ たり、categoryが未知の値であった場合、その結果は未定義です。同様に、 この関数はこの関数ファミリの二番目に知られた実装(Solarisでの実装です)の一 部ではないということに注意するべきです。

二つめの曖昧さは、おそらくは一つ以上のドメインが同じ名前を持っているという ことです。これは必要なメッセージカタログが置かれている場所を指定することに よって解決できます。

 
char *bindtextdomain (const char *domain_name,
                      const char *dir_name);

この関数を呼び出すことにより、与えられたドメインを指定されたディレクトリに 結び付けます(ファイルそのものを結び付ける方法については後述)。システムのデ フォルトの位置にあるファイルについては、それ以上指定する必要はありません (単にtextdomainを使った場合と全く同じです)。dir_nameNULLにした場合は、domain_nameに結び付けられたディレクトリを返 します。domain_nameそのものがNULLであった場合は何も起こらず、 NULLポインタが返されます。他の全ての関数と同じように、戻り値は変更 してはいけません!

dir_nameパラメータに与えられるパス名は問題を起こすことがありますので、 このことをしっかり覚えておいて下さい。パスは常にカレントディレクトリからの 相対位置として求められるため、プログラムがchdirコマンドを実行したと きは異なった結果が返されます。パスを取得する際には常に依存性と不確実性を回 避せねばなりません。


8.2.3 メッセージカタログファイルの所在

多くの異なった言語を多くの異なったパッケージに格納しなければならないので、 何らかの方法で言語やパッケージに関する情報をメッセージカタログファイルに追 加する必要があります。UNIX環境で通常使われている方法は、ファイル名にエンコー ディングを含めるというものです。ここでも同様にしています。 bindtextdomainの第二引数(あるいはデフォルトのディレクトリ)で与えら れたディレクトリ名には、以下に記述するようにロカールやドメイン名の値や名前 が後ろに続いています。

 
dir_name/locale/LC_category/domain_name.mo

dir_nameの既定値はシステムに依存します。GNUライブラリ、そしてGNUの方 針を頑なに信奉するパッケージでの既定値は

 
/usr/local/share/locale

です。

localeは、LC_categoryをいう名前を持つロカールの値です。 gettextdgettextにとって、このロカールは常に LC_MESSAGESです。dcgettextは三番目の引数によってロカールを指 定します(2)(3)


8.2.4 gettext関数群の最適化

この辺りで、GNU gettextの実装におけるアドバンテージについて話す必要 があるでしょう。一部の読者は、内部ループ中で幾つかの文字列を翻訳しなければ ならないような国際化プログラムは、貧弱なパフォーマンスしかあげられないこと を指摘するかもしれません。その文字列が一回のループの実行中に変更されるなら ば仕方ありませんが、ループ中で文字列が常に同じ値を取るならば時間の浪費でし かありません。以下の例を見て下さい。

 
{
  while (...)
    {
      puts (gettext ("Hello world"));
    }
}

ロカールが二回の実行の間で変更されないとき、文字列は常に同じ値を取ります。 このような場合に取ることが出来る方法としては、以下のようなものがあります。

 
{
  str = gettext ("Hello world");
  while (...)
    {
      puts (str);
    }
}

しかしこの解決法はあらゆる局面で使えるわけではありませんし(例えば、ロカー ルが変更されるような場合)、読みやすいわけでもありません。

GNU Cコンパイラのバージョン2.7かそれ以上では、これに対して別の解決方法を準 備しています。ここに挙げる数行を intl/libgettext.h ファイルに記述するとい うものです。式のコマンドブロック(expression command block)に関する説明につ いては、section `Statements and Declarations in Expressions' in The GNU CC Manualを参照して下さい。

 
#  if defined __GNUC__ && __GNUC__ == 2 && __GNUC_MINOR__ >= 7
extern int _nl_msg_cat_cntr;
#   define	dcgettext(domainname, msgid, category)           \
  (__extension__                                                 \
   ({                                                            \
     char *result;                                               \
     if (__builtin_constant_p (msgid))                           \
       {                                                         \
         extern int _nl_msg_cat_cntr;                            \
         static char *__translation__;                           \
         static int __catalog_counter__;                         \
         if (! __translation__                                   \
             || __catalog_counter__ != _nl_msg_cat_cntr)         \
           {                                                     \
             __translation__ =                                   \
               dcgettext__ ((domainname), (msgid), (category));  \
             __catalog_counter__ = _nl_msg_cat_cntr;             \
           }                                                     \
         result = __translation__;                               \
       }                                                         \
     else                                                        \
       result = dcgettext__ ((domainname), (msgid), (category)); \
     result;                                                     \
    }))
#  endif

ここで興味深いのは__builtin_constant_pです。これはコンパイル時に評 価され、直ちに最適化されます。ここで二つのケースに分岐します。 gettextの引数が定数でない場合は単純にdcgettext__が呼び出され、 dcgettext関数の実際の実装が用いられます。

文字列引数が定数の場合、ロカールが変更されていなければ既に取得され ている翻訳を再利用することが出来ます。これは正確にこの場で行われます。 _nl_msg_cat_cntr変数は、`libintl.a'中で利用可能な `loadmsgcat.c'で定義されており、この変数は新しいメッセージカタログが ロードされた時点で変更されます。


8.3 二つのインターフェースの比較

以下に挙げる議論はおそらく染められた小さなビット(a little bit colored)です。 既に述べたように、我々はGNU gettextをUniforumの提案に従って実装しま したし、これにはそうするだけの理由があります。しかし、我々がどのようにこの 決定にいたったのかを説明したほうが良いでしょう。

第一に、我々は開発プロセスに注目しました。gettextにより提供される NLSを用いてアプリケーションを開発するとき、我々はいつも通りに作業します。 ユーザが見ることになり、翻訳される必要があるであろう文字列を扱うときにだけ、 "..."の代わりにgettext("...")を置きます。各ソースファ イル(もしくは中心的なヘッダファイル)の先頭で次のような定義を行います。

 
#define gettext(String) (String)

この定義によって、システム自身のCライブラリによってgettextがサポー トされている場合でも、それを無効にすることができます。このコードをコンパイ ルしても、その結果はNLSコードを使わない場合と同じものになります。GNU gettextのコードに注目したなら、我々がgettext("...")では なく_("...")を使っていることに気がつくでしょう。これにより、翻 訳可能文字列一つ当たりで増加する文字数を三つに押えられます。

プログラムの製品バージョンでは定義を

 
#define _(String) (String)

から

 
#include <libintl.h>
#define _(String) gettext (String)

のように変更します。更に翻訳可能文字列を含むソースファイルに対して `xgettext'を実行します。翻訳が可能であるかどうかには依存しませんが、 翻訳が使用可能であれば翻訳を使用できる実行プログラムが出来上がります。

gettext_noopに対しても同じ手続きが取られます(see section 3.5 特別な翻訳対象文字列)。最初に、gettext_noopをno-opマクロとして定義し、後から `libintl.h'での定義を使用します。この名前はSunによる `libintl.h'の実装では使われていないので、あなたのプロジェクトに対して 以下のコードを考慮する必要があるでしょう。

 
#ifdef gettext_noop
# define N_(String) gettext_noop (String)
#else
# define N_(String) (String)
#endif

N__と同様の短い形式です。GNU gettextの`po/'ディレクト リ中の`Makefile'は先に述べられた両方の短い形式をデフォルトで理解しま す。そのためあなたは、自分自身が楽になるためにこの提案を理解する必要があり ます。

現在のcatgetsにおける最も大きな問題はプログラマが行う作業です。翻訳 文字列を扱うたび、プログラマはメッセージカタログに対しても対応する数値(も しくはシンボル的定数: symbolic constant)を定義しなければなりません。重複し たエントリ、メッセージIDなどにも注意する必要があります。GNU gettextプログラムが提供するメッセージカタログと同程度のクオリティの メッセージカタログを必要とするのであれば、彼は全ソースコードファイル中の文 字列とその出現位置に対する記述的なコメントをメッセージカタログに入れる必要 があります。これは「ミッション: インポッシブル」に近い話です。

しかし、catgetsには長所と呼べるかもしれない幾つかのポイントがありま す。あなたがある文字列中に一つの単語を持っており、この文字列が異なるコンテ キストで使われるとしましょう。言語によってはこの単語に対して異なる訳語が割 り当てられるかもしれません。

 
printf ("%s: %d", gettext ("number"), number_of_errors)

printf ("you should see %d %s", number_count,
        number_count == 1 ? gettext ("number") : gettext ("numbers"))

この例では、我々は"number"という文字列を二度翻訳しなければなりませ ん。あなたが英語に似た言語を話さないとしても、二つの語が異なる意味を持って いることは認識できるでしょう。ドイツ語では最初の文字列は"Anzahl"に、 二番目の文字列は"Zahl"に翻訳されます。

ここであなたはこの例が実に難解(esoteric)であると言うでしょう。それは正しい ことです! 正にこの問題に対して、我々はさほど重要ではないという結論を得まし た。この問題を解決するのは非常に簡単です。

 
printf ("%s %d", gettext ("number:"), number_of_errors)

printf (number_count == 1 ? gettext ("you should see %d number")
                          : gettext ("you should see %d numbers"),
        number_count)

我々はこの方法によって全ての衝突を解決できると考えています。もしこれが困難 であれば、衝突している文字列をほんの少し変えるということも出来ます。しかし、 この問題を克服することは不可能ではありません。

翻訳者ノート: 単一の's'を付加することによって名詞の複数形式を作ることが出 来ないということを英語を話すプログラマに伝えることは、恐らく重要なことです。 他のほとんどの言語では異なる手法を使っています。Rafal Maszkowski <rzm@mat.uni.torun.pl>のレポートによると、全ての言語に対して対処するには、 上記のフォームでも不十分です。

ポーランド語では我々は、例えばplik(ファイル)をこのように使います。
 
1 plik
2,3,4 pliki
5-21 pliko'w
22-24 pliki
25-31 pliko'w
(o'は8859-2 oachteを意味し、これはどちらかと言えばaogonekに似たokreskaです)

可能なアプローチは、おそらくPOSIX.2標準中にあるLC_TIMEで使用されて いるような方法を考慮に入れることでしょう。alt_digitsの値は1から 100を表現する100以上の文字列となり得ます。表現される数によって順序付けされ た翻訳文字列の配列を用いれば、国際化されたプログラム中でこの方法を使用する ことが出来ます。単純な例を示します。

 
void
print_month_info (int month)
{
  const char *month_pos[12] =
  { N_("first"), N_("second"), N_("third"),    N_("fourth"),
    N_("fifth"), N_("sixth"),  N_("seventh"),  N_("eighth"),
    N_("ninth"), N_("tenth"),  N_("eleventh"), N_("twelfth") };
  printf (_("%s is the %s month\n"), nl_langinfo (MON_1 + month),
          _(month_pos[month]));
}

この方法は、数値の範囲が狭いときのみ有効であるということは明らかでしょう。


8.4 独自のプログラムでlibintl.aを使う

バージョン0.9.4以降、libintl.hは自己包括(self-contained)でなければ ならなくなっています。すなわち、追加の関数を用意することなくこれをあなた自 身のプログラムで使用できます。`Makefile'はヘッダとライブラリを、 $(prefix)で指定されたディレクトリに格納します。

HP-UXシステムにおいては、上記に関する唯一の例外が発生します。Cライブラリが alloca関数を含んでいないのです(そしてHPのコンパイラはこれをインライ ンとして展開しません)。しかしそれはこのバカなシステムのためだけにライブラ リ全体を書き直すといったことを意味しません。代わりに、libintl.aを使 用する全てのパッケージがalloca関数をインクルードします。


8.5 Being a gettext grok

ソースコードを読むことは、GNU gettextの機能を完全に活用するための助 けになるでしょう。しかし、(時として込み入った内容の)コードを読むために時間 を費やすことを望まない人々のために、幾つかのコメントを挙げておきます。


8.6 プログラマの章についての一時的なメモ

8.6.1 一時的な情報 - 二つの実装  
8.6.2 一時的な情報 - catgetsについて  
8.6.3 一時的な情報 - なぜ一つの実装なのか  
8.6.4 一時的な情報 - ノート  


8.6.1 一時的な情報 - 二つの実装

言語に依存せずにメッセージを扱う二つの手法があります。一つはX/Openの catgetsによるものであり、もう一つはUniforumのgettextによるも のです。catgetsによる方法では、整数によってメッセージを指定します。 gettextによる方法では、英語のメッセージによって指定します。。 catgetsによる方法は長く使われ、多くのベンダでサポートされています。 gettextによる方法ははSunでサポートされていて、COSEマルチベンダイニ シアティブ(COSE multivendor initiative)がサポートするようです。どちらも POSIX標準とはなりませんでした。POSIX.1 委員会では、この件に関して様々な見 解の相違がありました。

二つの手法のいずれもPOSIX標準ではありません。gettextcatgets(XPG)ルーチンのいずれを標準として採用するかについて、 POSIX.1 委員会ではは様々な議論がなされました。委員会の終盤に至っても何らの 合意は得られず、結局メッセージングシステムは標準規格には含まれませんでした。 私はXPG3メッセージングインターフェースに関する追記を標準に付与するのは有益 であると信じていますし"...メッセージングシステムの実例は既に実装され ているのです..."

委員会は、ある一つのインターフェースの実装を使うのが良いということをどの場 所でも言わないように非常に注意していました。この話題に関するこれ以上の情報 については、国際化プログラミングFAQ(Programming for Internationalization FAQ)を参照して下さい。


8.6.2 一時的な情報 - catgetsについて

catgetsを基盤として使用することに関する討議の末期には、幾つかの議論 がありました。その議論の両側を提示することは大切だと思いますし、これから、 私はちょっとしたことに対して「悪魔の弁護士」となってみることにします。

catgetsはもっと良くデザイン出来たでだろうということは否定しません。 その実装には既に指摘したような制限が少なからずあります。

しかしながら、その一貫性と標準化の度合いについては 申し分ありません。 UNIXソフトウェアを書くときに繰り返し発生する 問題とは、UNIXプラットフォーム間での移植性に関する問題です。それは全ての UNIXベンダがオペレーティングシステム上を調べて改良する部分を見つけたような ものです。疑いもなく、これらの修正は革新的なものであり、現実の問題を解決す るものです。しかしながら、ソフトウェアベンダがこれらの変更を多くのプラット フォームで行いつづけるには、多くの労力が必要です。

そしてこれは各UNIXベンダが自社のシステムを標準化することを促進します。 Spec1170に準拠するためにです。、各主要UNIXベンダはこの標準化のために委員会 を設けました。そして全てのUNIXソフトウェア開発者はこの標準に従ってソフトウェ アを作成し、異なるプラットフォームへソフトウェアを導入する際には (autoconfを使うことなく)リコンパイルするだけで済むようになる日を心待ちにし ているのです。

私の理解しているところでは、Spec1170はX/Open Portability Guidelinesのバー ジョン4(XPG4)に基づいたものです。catgetsとその眷属がXPG4で定義され ているので、私はcatgetsがSpec1170の一部であり、それがすべてのUNIXシ ステムの標準的なコンポーネントになることを信じています。


8.6.3 一時的な情報 - なぜ一つの実装なのか

メッセージカタログにアクセスするために二つの異なるシステムをインストールす ることは不経済なことのように思えます。我々がcatgetsの不足しているも のを改善したいと思ったのなら、なぜ新しいシステムを実装するのではなく、 catgetsを(互換性を保ちながら)拡張しようとしないのでしょうか? いずれ にせよ我々は、メッセージカタログにアクセスするためのシステムをオペレーティ ングシステムに対して二つインストールすることになるでしょう。一つはGNUソフ トウェアのためルーチン群であり、もう一つはその他全てのソフトウェアのための ルーチン群(catgets)です。傲慢でしょうか?

カタログにアクセスする別のシステムが実装されたと仮定してみましょう。我々が お奨めするのはどちらでしょうか? 少なくともLinuxシステムに対しては、我々は 可能な限り多くのソフトウェア開発者を呼び込む必要があります。そのため、我々 はソフトウェア開発者が彼らのソフトウェアを移植しやすいようにする必要があり ます。そしてそれはcatgetsをサポートすることを意味します。我々は glocaleコードをGNU libc中に実装するでしょうが、GNU libcには別のメッセージカタログに対するアクセス方法を同じように取り 込まなければいけないということなのでしょうか? そして、glocaleと非 catgetsルーチンを組み合わせて使おうとする人達に関してはどうでしょう か? ソフトウェア開発者が彼らのソフトウェアを他のプラットフォームに移植する 際、彼らはそのソフトウェアに単にglocaleを含めるだけでなく、フロント エンド(glocale)コードと、バックエンド(非catgetsアクセスルー チン)コードを付け加えようとするでしょう。

しかしメッセージカタログのサポートは氷山の一角に過ぎません。他のロカールカ テゴリのデータはどうでしょうか。それらもまた、多くの相違点を持っています。 我々はそれに対処することを諦めて、重複したルーチン群を別々に開発せねばなら ないのでしょうか(glocaleをメッセージカタログサポート以上のものにす べきなのでしょうか)?

UNIX上の改良可能な多くの部分と同じように、我々は将来に向けて改良を加えつつ も、過去のものに対する互換性を落とさないようにしていました。


8.6.4 一時的な情報 - ノート

多くの実装が最終形式からかけ離れたものであったため、X/Openが標準形式を承認 するのは非常に遅くなりました。私の使っている両方のシステム(古いLinux catgetsとUltrix-4)には奇妙なバリエーションがあります。

最後の変更を加えた後、私はGNU/Linux libcgettext関数群を作 成するために時間を割かねばなりませんでした。従って、将来的にはSolarisが gettextを備えた唯一のシステムであるということはなくなります。


9. 翻訳者としての視点

9.1 イントロダクション0  
9.2 イントロダクション1  
9.3 議論  
9.4 組織  
9.5 情報の流れ  


9.1 イントロダクション0

GNUは国際化しつつあります! 翻訳プロジェクトは保守担当者、翻訳者、そしてユー ザーを全てまとめるもので、そのためGNUソフトウェアは徐々に多くの言語を喋る ことが出来るようになります。

GNU gettextツールセットには、保守担当者がパッケージのメッセージを国 際化するために必要となる全てがあります。また、パッケージが国際化さ れた後で、翻訳者がメッセージの地域化を行う際の助けになるような便利なツール もあります。

翻訳プロジェクトを完遂するために、我々は自分の国の言葉を愛し、良く書くこと が出来、そして他の翻訳者が話しているのと同じ言語で助けることの出来る (synergize)能力を持った人間を数多く必要としています。もしあなたが翻訳チー ムでボランティアとして働くことを望むなら、該当する翻訳チームにメー ルを出して下さい。

各チームはLinux Internationalの好意による自身のメーリングリストを持ってい ます。`ll@li.org'というアドレスのllをあなたの注目する言 語のISO 639の二文字コードに置き換えることによって、その言語の翻訳チー ムに連絡できます。言語コードはISO 3166に定められている国コードと 同じではありません。現時点では以下の翻訳チームが存在します。

アイルランド語 ga、 イタリア語 it、 インドネシア語 in、 エスペラント語 eo、 オランダ語 nl、 ギリシャ語 el、 スウェーデン語 sv、 スペイン語 es、 チェコ語 cs、 中国語 zh、 デンマーク語 da、 ドイツ語 de、 トルコ語 tr、 日本語 ja、 ノルウェー語 no、 フィンランド語 fi、 フランス語 fr、 ポーランド語 pl、 ポルトガル語 pt、 ロシア語 ru

仮に中国語翻訳チームにメールを出すとすれば、`zh@li.org'となります。 翻訳チームのメンバーになるには、その言語チームのメーリングリストに登録する 必要があります。例えば、スウェーデン人は本文に以下の内容を記述して `sv-request@li.org'にメールを出します。

 
subscribe

チームのメンバーは翻訳作業に興味を持つべきだということを心に留めて置いて下 さい。そうでなければ翻訳を果たすことは難しいのです。もしが希望する言語のチー ムがまだ存在せず、その言語のチームを作りたいという場合には `gnu-translation@prep.ai.mit.edu'まで連絡して下さい。それによっ て全ての翻訳チームの調整者に連絡が取れます。

一握りのGNUパッケージには幾つかの言語に対するメッセージの翻訳が適用・提供 されています。翻訳チームは組織化され始めており、これらのパッケージを起点と して使っています。しかしまだまだ多くのパッケージがあり、多くの言語について はボランティアの翻訳者がいません。もし翻訳チームでボランティアとして作業し たいと思うのでしたら、`gnu-translation@prep.ai.mit.edu'に作業するこ との出来る言語を明記してメールを送って下さい。


9.2 イントロダクション1

現在公式に、GNUは国際化しつつあります! 以下は1995年1月の GNU Bulletinで述 べられた声明です。

一握りのGNUパッケージには幾つかの言語に対するメッセージの翻訳が適用・提供 されています。翻訳チームは組織化され始めており、これらのパッケージを起点と して使っています。しかしまだまだ多くのパッケージがあり、多くの言語について はボランティアの翻訳者がいません。もし翻訳チームでボランティアとして作業し たいと思うのでしたら、`gnu-translation@prep.ai.mit.edu'に作業するこ との出来る言語を明記してメールを送って下さい。

本ドキュメントはその過程に興味を持ったり、貢献したいと考えている人々が持つ 多くの疑問に答えます。願わくばざっと目を通し、GNUの国際化に対するこの集合 的努力から産み出される大量のメールの幾ばくかでもを担当して下さい。

広く共用される多くのフリーソフトウェアのプログラミングは英語で行われてい ます。そして現在のところ、英語はGNUプロジェクトに協力する国家的コミュニ ティ間での主要なコミュニケーション言語として使われています。このドキュメ ントでさえも英語で書かれています。これは当面変わらないでしょう。

しかしながら、多くのソフトウェアで自国語や自国の習慣を用いたいという、国家 的コミュニティからの強い欲求があります。また、GNUソフトウェアをそのように するための努力が現在も行われています。この試みは今までのところプリテスタか らの熱心な反応の向上によって動かされており、我々はGNUの国際化は成功すると 信じています。

このドキュメントに対する内容の明確化、追加、訂正に関する提案については、 `gnu-translation@prep.ai.mit.edu'までメールを送って下さい。


9.3 議論

この国際化の効果を目の当たりにして、幾人かのユーザが彼らの考えを表明してい ます。紹介され議論されたこれらの疑問の幾つかをここに挙げてみましょう。


9.4 組織

大きな尺度で見れば、真の解決方法は有志が参加できるようなある種の正しく厳密 な集合を組織化することでしょう。私は、最近このアイディアについて幾つかの考 察を行い、幾つかの微妙なポイントがあるであろうことを認識しています。私は、 そのようなプロジェクトを開始するために、Richard Stallmanに連絡することを考 えましたが、まず最初に我々の間でアイディアを揺り落とすことが良いだろうと感じ ました。おそらく、Linux Internationalは既にこの分野における幾らかの経験、 または、有志の作業のオーケストラのようなものを持っています。あらゆる場合に、 思考のための食物を!

我々は早々に何らかの方法で何かをセットアップせねばならないと考えます。同じ 言語に対する作業のインターロックと重複を避けるという点で、それは多くの言語 のコントリビュータを助けるでしょう。そして、更にそれらの言語(大部分の言語 では技術的な英語の翻訳について独特な多くの問題点があります)についての独特 な問題を共に解決するように連絡が取れるようにします。スウェーデンのコントリ ビュータはこれらの問題点を認め、そして私はフランス語においてのそれらの問題 点に相当に気が付いています。

確かにこれは技術的問題ではありません、しかし我々は、コントリビュータ、及び 管理者間の国家チーム層のインターフェースに関わらず、ロカールコントリビュー タの努力が最大限に有益になるように管理するべきです。

翻訳プロジェクトは言語コーディネータを統合するためにある準備を必要とします。 一度この作業が始められたなら、発展中のプログラムのローカライズは、確かにフ リーソフトウェアコミュニティにおいて永久の、そして、連続的な動きになるでしょ う。 GNU gettextが公式の現実になる前に、最小限の準備が完了し、そし てテストされているべきです。電子メールアドレス `translation@iro.umontreal.ca'は、これらの話題に基づくボランティア、 及び、一般的な電子メールから申し出を受けるための準備でした。このアドレスは、 翻訳プロジェクトのコーディネータに届きます。

9.4.1 中央による調整  
9.4.2 国家チーム  
9.4.3 メーリングリスト  


9.4.1 中央による調整

そのことについて考えるよりも更に早く、GNUは誰かがそれらのグループを組織化 し調整する方法を準備する必要があると私もまた考えます。ある種のグループのグ ループです。GNUは直ちに共同で働いているボランティアの小さなグループにこの タスクを委託することが良いだろうと、私は考えています。 おそらく、この国家 委員会的なグループのリストは`gnu.announce'において公表され得ます。

コーディネータとしての私の役割は単に、Ulrichをフリーソフトウェアの地域化に 興味を持っているドイツ語を話すボランティアに紹介すること、そして国家的グルー プの準備が出来るまでの国家的登録機関のメンテナンス中に、国家的グループの最 初の組織化を助けることです。実際、コーディネータは、ボランティアが国家チー ム(言語または国(局地的言語)について1人のコーディネータを選択するべきです) を作成するために相互と連絡を取りやすくせねばなりません。これが正しく行われ たならば、コーディネーションは不可抗力的作業を除いて便利なものとなり、代理 人に時間を任せることが出来るようになります。


9.4.2 国家チーム

私は、我々が個々の言語のための有志のコーディネータ/エディタを捜すことを提 案します。これらの人々は彼ら自身の言語のために、様々なプログラムの翻訳ファ イルを探し出し、そして、語法に対する高度で一定の標準を保証することになるで しょう。

今までの他の人々との間の私の現在の経験によれば、地域化を実現する人々はこの プロセスに対して非常に熱心であり、彼らは自分自身が地域化するプログラムより も地域化のプロセスにほうに興味を持ち、それだけでなく多くのプログラムを地域 化したいと思うものです。この事実は、各言語のためのコーディネータ/エディタ を持つことは良いアイディアであることを確信させます。

我々は、問題となる言語において明瞭かつ簡潔な文章を書く際、適任となる人物を 選択する必要があります。これは難しい作業です---我々は、自分自身でそれをチェッ クすることができません。従って、我々は数人の人間対してに互いの記述を判断す るように要請し、そして最適任者を選択する必要があります。

私は私のプレリリースを20人から30人の人々に発表ましたが、そのプレリリースが 既に生み出した全ての議論をあなたは信じないでしょう。私は、真に、公式に、世 界中でこの作業が開始されるときに起こるであろうことを想像すると身震いがしま す。例えば、相互に反論しあう二人のチェコスロヴァキアのユーザーの間を仲裁す るのは私なのでしょうか?

私がこれらの公式化について判断することが出来ないように、あなたのドイツ語が 私のフランス語よりはるかに良いとは限らないと推測します。私が提案するものは、 各言語に対してPOファイルをメンテナンスしその変更を判定する人々のグループを 置くということです。そのような人々のグループがどのように行動するかについて、 グループ間には文化的な相違点があると考えます。幾つかのグループはは緩い方法 を採用し、簡単にコンセンサスの一致に達し、グループ中の誰もが保守者に関わる ことができます。一方は死ぬまで戦い、重い管理を国家の標準にまで組織化し、厳 密なチャネルを使用するでしょう。

ドイツのチームは良い例を出しています。直ちに、彼らはおそらくお互いの翻訳を 訂正する半数の人々と言語上の論点について議論する半ダースの人々です。私は全 ての名前を知っているわけではありません。Ulrich Drepperはドイツのチームのコー ディネートを担当しています。彼は私のプレテストのリストの購読を申し込みまし た。従って、私は彼に対して、連絡されるリリースの詳細について警告する必要は 特にありません。

各言語を担当する翻訳チームを得るためには、それはよいアイディアだと思います。 翻訳を更に良く首尾一貫した状態にするでしょう。

9.4.2.1 サブカルチャー  
9.4.2.2 組織化へのアイディア  


9.4.2.1 サブカルチャー

フランス語を例に取ってみましょう。コンピュータの世界では、意味が異なる語彙 を持つ幾つかのサブカルチャーがあります。組織化された方法でこの問題を提起す ることなしにあちこちでボランティアを選んでいると、プロジェクトにはすぐに国 際化されたプログラムのごちゃ混ぜ状態が発生します。そしてことによると、実際 にこの問題を気にする人々の間で終りなき口論が始まるでしょう。

国際化されたプログラムをフランス語へ地域化する過程において、ある種の統一を 保つことは難しい(そしてデリケートな)仕事です。フランス人のラテンな人柄 (:-)を知っていても、もし我々がこのことを間違った方法で捉えれば、我々はどこ とも知れぬ場所で終わってしまうか、多くのエネルギーを無駄にしてしまうことで しょう。おそらく我々は、gettextが公式に発表される前に真剣に この問題に取り組まなければならないでしょう。


9.4.2.2 組織化へのアイディア

私は、公式リリース後に次の大きな変更があると考えています。どうか、私が短い GPLメッセージのドイツ語翻訳を用いることに注目してください。我々は、フリー ソフトウェアコミュニティにおける真の地域化が消え去ってしまう前に2、3の良い 例を示す必要があります、ここでは、議論が必要ないくつかのポイントを示します。


9.4.3 メーリングリスト

GNU gettextに関するあらゆる問合せについては、以下に送ってください。

 
`translation@iro.umontreal.ca'

`*-pretest'リストは、私にとって本当に有益です、アイディアはおそらく、 多くのGNU、及び、非GNUパッケージへと一般化されるでしょう。しかし、保守者以 外の、彼/彼女の方法!

François、我々は、チーム、チームをサポートするメーリングリストそしてロ グメンバを追跡するために、`gnu.ai.mit.edu'に適当なメカニズムを持って います。我々は、あなたが使うわずかな優先権を持っています。 これがあなたに とって問題ないならば、私はあなたに情報を与えることができます。

事物は変化しています! 2、3年前、Daniel Feketeと私がGNU地域化のメーリングリ スト(FSFの中にあった)に尋ねたとき、我々は作業をどこででも組織化するように 礼儀正しく勧められ、そして我々はそれを実行しました。私のプリテスタと連絡を 取るために、私はmajordomoで管理される少数のメーリングリストを iro.umontreal.caに作成しました。これらのリストは今までのところ非常に 信頼できました...

私は、ドイツ語のチームがドイツにあるメーリングリストを組織化し、他の国にも 組織化をさせると思います。しかし組織化が行われる前に、FSFにおいて各国のチー ムのためのメーリングリストを提供することは確かに有益でしょう。そうです、私 にどのようにメーリングリストを作成し扱えばよいかを説明して下さい。

我々は一時的なメーリングリストを、人々を組織化しやすいように国ごとに一つづ つ作らねばなりません。なぜ一時的か、なぜなら一度再構成されたなら、各国のボ ランティアは彼らのリストへと戻ってきて、そして自分達が望むように管 理するだろうからです。このことについては、個々のチームは自分達の国の中から 自分達のリストを動かすだろうと思います。全てのチームが購読することの出来る、 中央のメーリングリストも作る必要があるでしょう。


9.5 情報の流れ

パッケージが最終的にリリースされた後、このメッセージについての幾つかの議論 があることでしょう。今、人々が更に良い幾つかのメッセージを提案したとしたら、 あなたはどうしますか? ジム、私が提供する1ダース近い地域化されたプログラム と同様、どうか直ちにそれらのメッセージに注目して下さい。私は翻訳とそれらに 関する調整の両方を受け取るのです。

私が事前にテストするものを一つ置いたならば、Ulrichはその告知を受け取り、そ してそれを最後に修正するドイツ語のチームに渡します。そして彼は保守者 として私に翻訳ファイルを引き渡します。私が保守していないフリーのパッケー ジについては何も聞きません。私が思うに、全ての翻訳プロジェクトにおいてこの スキームが作られるでしょう。セキュリティに関わる理由のために、おそらく Ulrich(実際の国家的コーディネータ)は時折翻訳プロジェクト(Jim、私、又は Lenの新人)によって保持される中央のレジストリをアップデートすべきです。

私は小さなGNUパッケージは一週間に一つずつ、より大きなパッケージは数週間か 数ヵ月をかけるという責務を私自身に課し、12月か1月には私はにGNUの全パッケー ジを国際化する準備を積極的に整えていました。しかし、それはそのようには動き ません。私は最初に、私が責任を持つ全てのことを行いました。私は他の保守者の 幾らかの伝道作業に対して何も持っていませんでした。しかし私もまた多くのエネ ルギーを失いました---同じ議論を繰り返します。

そして、最初に地域化されたパッケージがリリースされるとき、我々は、醜悪な翻 訳:- )についての多くの反応を得るでことしょう。確かに、そして我々は事前に、 パッケージ保守者と国家チームの間の情報の流れを制御することに関する良いアイ ディアを持つ必要があります。

どうかどこかに各POファイルの迅速なヒストリを保存し始めて下さい。コメントを 認めることによってファイルフォーマットがいずれ変更されるであろうことを私は 知っています。各ファイルがログのようなもの、そしてコメントや不平の申し立て、 又はその他の貢献をしたいと思う人々へのリファレンスを持つほうがよいでしょう。 私は高速でフレキシブルなフォーマットに関する申し立てをしましたが、しかしそ れはまだGNUの意思決定者によって受け入れられていません。私がこれについてよ り多くの情報を得たなら、このことについてお話しすることになるでしょう。


10. 保守担当者としての視点

パッケージの保守担当者は多くの責任を持ちます。一つは多くのプラットホームで パッケージを簡単にインストール出来るようにすること、そして既に述べた魔法 (see section 7. ユーザとしての視点)がインストーラやエンドユーザに対して働くようにすることです。

もちろん、GNU gettextを配布物に統合するためには様々な方法があります。 しかし、この章ではそれら全ての一般法則について述べることはしません。その代 わり、GNU標準に従う、またさらに良ければGnits標準に従う配布物、そしてその他 多くの素晴らしいフリーのパッケージに対して可能な限り最も適切な(なぜなら、 GNU gettextは特に全GNUプロジェクト、そしてそして可能な限りその他多 くの素晴らしいフリーのパッケージの国際化を支援するためのものですから)一つ のアプローチについて詳説します。従って、ここで提示する保守担当者の視点は、 パッケージが既に`configure.in'ファイルをその中に含み、そして Autoconfを使用しているものであると仮定します。

それでもなお、GNU gettextはGNU標準やGNUの習慣に従っていない他のフリー のパッケージにとっても本当に便利なものです。しかしそれらのパッケージの保守 担当者は、gettextがいかなる状況下でもパッケージと共に動作するように、 配布物の組織化について想像力とイニシアティブを示さなければなりません。

たとえgettextの手法が現在安定しているとしても、続くgettextの バージョンの間では僅かな修正が必要となることでしょう。従って、次のリリース 時にはこの章をそれに合う形に訂正するべきです。

10.1 フラットまたはノンフラットなディレクトリ構造  
10.2 事前に必要な作業  
10.3 gettextizeプログラムの起動  
10.4 作成するか変更しなければならないファイル  


10.1 フラットまたはノンフラットなディレクトリ構造

幾つかのフリーソフトウェアパッケージは一つのディレクトリ中に展開される tarファイルによって配布されます。これらはフラットな配布物と呼 ばれます。その他のフリーソフトウェアパッケージは1階層のサブディレクトリ構 造を持ちます。例えば、`doc/'というサブディレクトリにはTexinfoマニュア ルやmanページが格納され、`lib/'というディレクトリにはCライブラリを置 き換えたり補完する関数群が収められ、`src/'というサブディレクトリには パッケージ独自のソースコードが収められています。これらの配布物はノン フラットと呼ばれます。

ここでは、フラットな配布物についてこれ以上言及しません。フラットなディレク トリ構造は、GNU gettextの新しいバージョンへのアップグレードが難しく なっていくので不利です。多くのPOファイルを扱う場合、単一のディレクトリは幾 分散らかってしまうことにもなります。GNU gettext配布パッケージには、 `misc/'ディレクトリ中に`combine-sh'という名前のシェルスクリプト が含まれています。このスクリプトは`intl/'ディレクトリ内の全Cファイル をCファイルのペア(一つの`.c'ファイルと一つの`.h'ファイル)にする ために使われます。これら二つの生成されたファイルはフラットなディレクトリ構 造により簡単に適応できるので、プロジェクトにこれら二つのファイルを追加する 必要が出てくるでしょう。

おそらく、GNU gettext自身がノンフラット構造を持っているため、我々に とってはこの方法のほうが扱いやすいのです。この章の残りの部分ではこの方法に ついて記述していくことになるでしょう。何人かの保守担当者はこれをいい機会だ と捉え、パッケージ構造を非フラットなものにするでしょう。GNU gettextをフラットな配布物に対して適応させる経験を今後積んだなら、フ ラットな構造を処理する方法について新たに記述することにします。


10.2 事前に必要な作業

パッケージにGNU gettextを適用させる前に、やっておかなければならない 幾つかの作業があります。これらの作業は、この章での注意を逐一記述せずに済ま せるための一種の一般法則です。それらの作業について記述します。

保守担当者がPOファイルの提供に対しどのように理想的に振舞うべきかについて、 少し説明する必要があるでしょう。保守担当者としての役割は、翻訳プロジェクト の適切な翻訳チームの代表者(疑問がある場合は提出物を `translation@iro.umontreal.ca'に転送します)としての提供元を承認する ことです。POファイルの内容が激しく壊れていないこと、正常なインストールを妨 げないことが保証出来たら、最後はただ単にこれらのPOファイルを配布物の `po/'ディレクトリに入れるだけです。

保守担当者として、あなたは翻訳が適切か完全かというようなチェックの報告につ いて責任を負う必要はなく、言語上の問題に没頭することは避けなければなりませ ん。翻訳チームは自ら動き、そして翻訳プロジェクトに対する言語の選択について 充分に責任を負っています。翻訳チームは保守担当者によって動かされているので はないということを心に止めておかなければなりません。保守担当者は言 語上の問題に関わるユーザとのコミュニケーションや、ユーザからの報告の全てを 注意深く転送することによって、適切な翻訳チームを助けることが出来ます。また、 それらをいかにして翻訳チームに届けるか、あるいはどのようにして翻訳チームに 加わればよいかをユーザに対して説明することも出来ます。もっとも単純な方法は、 ユーザに`ABOUT-NLS'ファイルを送ることでしょう。

保守担当者は決して翻訳チームを無視してPOファイルのバグレポートを適 用してはいけません。もし何人かの翻訳者が彼女のチームの中で話の確信を掴むこ とが難しいというのであれば、彼女は直に保守担当者と翻訳を取り決めてもよいで しょう。しかし通常、翻訳チームはチーム自身でそれらの問題を解決するべきです。 保守担当者が翻訳チームに関して本当に問題があると考えているとしても、保守担 当者は決してチームの問題を解決してはならないのです。


10.3 gettextizeプログラムの起動

GNU gettextを使って国際化された全てのパッケージには、幾つかのファイ ルが常にそして同じように必要です。扱いやすいように、gettextizeプロ グラムはこれらのファイルをパッケージ中に正しく置きます。このプログラムは以 下の書式を取ります。

 
gettextize [ option... ] [ directory ]

以下のオプションが使用可能です。

`-c'
`--copy'
シンボリックリンクを作成する代わりに、必要なファイルをコピーします。シンボ リックリンクを使用することによってパッケージは常にシステムの最新の gettextコードを使用できますが、保守担当者がソースに適用する幾つかの メカニズムを妨害するかもしれません。gettextizeを実行するのは簡単な ことですので、コピーを使うことに関する問題が発生するべきではありません。

`-f'
`--force'
既に存在するファイルを強制的に置き換えます。

`-h'
`--help'
ヘルプを表示して終了します。

`--version'
バージョン情報を表示して終了します。

directoryが与えられていれば、それはGNU gettextが使われるパッ ケージの最上位のディレクトリとなります。与えられていなければ、カレントディ レクトリがそのパッケージの最上位ディレクトリであると仮定されます。

gettextizeプログラムは以下のファイルを用意します。--force (-f)オプションが指定されていない限り、存在するファイルが置き換えら れることはありません。

  1. `ABOUT-NLS'ファイルはパッケージの最上位ディレクトリにコピーされます。 このファイルにはプログラムのインストール方法とナショナルランゲージサポート の使用方法に関する主要な指示が記述されています。もしこのファイルが簡単に手 に入るのなら、gettextizeが準備する`ABOUT-NLS'ファイルよりも新 しいファイルをパッケージに入れたいと考えるかもしれません。最新の `ABOUT-NLS'ファイルは殆んどのGNUアーカイブサイトから手に入れることが できます。

  2. `po/'ディレクトリは全ての翻訳ファイルをいつの日か格納するために作られ ますが、最初はGNU gettext配布パッケージ中の `po/Makefile.in.in'ファイルが格納されているだけです(ファイル名に二つ の.inがついていることに注意して下さい)。もし`po/'ディレクトリが既に存 在するのであれば、poディレクトリとディレクトリ中のファイルはそのままにして、 `Makefile.in.in'のみが上書きされます。

  3. `intl/'ディレクトリは、GNU gettextの配布パッケージにある `intl/'ディレクトリ中のファイルの殆んどが格納された状態で作成されます。 もしオプション--force(-f)が与えられた場合、`intl/'ディ レクトリは最初から空のまま作成されます。

もしサイトがシンボリックリンクをサポートしているのなら、 gettextizeはパッケージ中に本当にコピーすることはせず、その代わりに シンボリックリンクを作成します。これにより、全てのパッケージに必要なディス クスペースの重複を避けることが出来ます。配布物からtarアーカイブを作 る際、ただ単に`-h'オプションを使うだけで、それぞれのリンクは実際に配 布アーカイブの中にコピーされることになります。強調したいのは、メインの `Makefile.in'のために必ずtarと共に`-h'オプションを使わね ばならないということです。

1つのパッケージにおいてGNU gettextをサポートするための新しいファイ ルの殆んどが`intl/'、及び、 `po/'サブディレクトリへ分かれている 理由を理解するのは興味深いことです。これらの2つのディレクトリの間の1つの区 別は、`intl/'がGNU gettextを使う全てのパッケージにおいて完全に 同じものであり、一方、最近作成された全てのファイル(パッケージごとに異なる はず)は`po/'に入るということです。`po/'ディレクトリが自分のため の`Makefile'を必要とするため、`po/'には一般的な `Makefile.in.in'があります。そして、`Makefile.in.in'は全てのパッ ケージにおいて同じであり得るように設計されています。


10.4 作成するか変更しなければならないファイル

gettextizeによって自動的に加えられるファイル以外にも、 GNU gettextと共に適切に使用するためには多くのファイルに対して変更を加え なければなりません。Makefileの設計やオートコンフィグレーション (auto-configuration)がGNU標準に密接に従っているなら、変更作業自体は更に簡 単になります。ここでは、個々のファイルに対して必要となる変更について一つ一 つ説明します。

以下にファイルの一覧を示します。個々のファイルに対する必要な全ての変更につ いては、それに続いて記述します。多くの例は、GNU gettext 0.10それ自身から採用されています。gettextパッケージのソー スコードを参照すると良いでしょう。GNU gettextパッケージは良い例であり、そ してそれ自身の機能を使うための実装の原本として使えるからです。

10.4.1 `po/'以下の`POTFILES.in'  
10.4.2 トップレベルに存在する`configure.in'  
10.4.3 トップレベルに存在する`aclocal.m4'  
10.4.4 トップレベルに存在する`acconfig.h'  
10.4.5 トップレベルに存在する`Makefile.in'  
10.4.6 `src/'以下の`Makefile.in'  


10.4.1 `po/'以下の`POTFILES.in'

`po/'ディレクトリには`POTFILES.in'ファイルが必要です。このファイ ルは全てのプログラムソースに対して、翻訳が必要な文字列がどのファイルにある かを示しています。以下に例を示します。

 
# List of source files containing translatable strings.
# Copyright (C) 1995 Free Software Foundation, Inc.

# Common library files
lib/error.c
lib/getopt.c
lib/xmalloc.c

# Package source files
src/gettextp.c
src/msgfmt.c
src/xgettext.c

コメント行と空白行は無視されます。その他の全ての行は、翻訳が必要な文字列を 含んでいるファイルのリストです(see section 3.2 ソース中でのマーク付けの方法)。このリストでは、各 ファイルは`POTFILES.in'ファイルからの相対位置ではなく、パッケージの最 上位ディレクトリからの相対位置で記述します。


10.4.2 トップレベルに存在する`configure.in'

  1. パッケージとバージョンの宣言

    宣言が行われた例を示します。

     
    PACKAGE=gettext
    VERSION=0.10
    AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
    AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
    AC_SUBST(PACKAGE)
    AC_SUBST(VERSION)
    

    もちろん、`gettext'はあなたのパッケージの名前に、 `0.10'はあなたのパッケージのバージョン番号に置き換えます。 これらはソフトウェアのtarパッケージのファイル名に含まれることになる でしょう(ここでは`gettext-0.10.tar.gz'となります)。

  2. 利用可能な翻訳の宣言

    利用可能な言語は、空白で区切られた引用文字列としてALL_LINGUASに一行 で定義します。例えばこのように。

     
    ALL_LINGUAS="de fr"
    

    この例は、ドイツ語とフランス語がパッケージでサポートされるべく、この二つの 言語のPOファイルが使用可能なことを表しています。インストール時のインストー ル言語の設定について更なる制限をかけたいとしても、それは `configure.in'中のALL_LINGUASを修正することによって行うべきで はありません。その代わりに環境変数LINGUASを使用します (see section 7.2 インストーラへの魔法)。

  3. 国際化サポートのチェック

    これは、国際化サポートを実現するためのメインのm4マクロです。 `configure.in'に次の行を追加して下さい。

     
    AM_GNU_GETTEXT
    

    これによってチェックやアクションのためにconfigureに長い時間がかかるように なりますが、この呼出そのものは実に簡単です。

  4. 出力ファイルの作成

    `configure.in'の最後にあるAC_OUTPUTディレクティブは二つの方法 で修正されなければなりません。

     
    AC_OUTPUT([existing configuration files intl/Makefile po/Makefile.in],
    existing additional actions])
    

    AC_OUTPUTの最初の引数に対する修正は、`intl/'`po/'ディレ クトリの置換を確認します。`.in'サフィックスが`po/'に対してのみ使 われていることに注意して下さい。配布されるファイルが実際に `po/Makefile.in.in'であるためです。


10.4.3 トップレベルに存在する`aclocal.m4'

パッケージ中に`aclocal.m4'ファイルがない場合、もっとも簡単な解決策は、 GNU gettextから`aclocal.m4'をコピーすることです。しかし厳密に は、必要となるのはマクロAM_LC_MESSAGESAM_WITH_NLSAM_GNU_GETTEXTAM_PATH_PROG_WITH_TEST(AM_WITH_NLSに よって呼びだされる)だけです。従って、エディタを使うことによって必要でない マクロを取り除く必要があるかもしれません。

既に`aclocal.m4'ファイルが存在するならば、前述のマクロをあなたの `aclocal.m4'にマージしなければならないでしょう。もし以前のリリースの gettextからアップグレードしているのならば、通常、GNU gettextのリリースの間には小さな変更が含まれているため、おそらく前述 のマクロを置き換える必要があるであろうことに注意して下さい。それら の内容は、変わったシステムに対して我々が対応するために変更されるかもしれま せん。

これらのマクロは国際化をサポートする関数とその関連情報をチェックします。安 定化したなら、おそらくこれらのマクロは標準のAutoconfのセットに組み込まれる ことでしょう。なぜなら、このm4コードはgettextを使用する全て のプロジェクトで同じものになると思われるからです。


10.4.4 トップレベルに存在する`acconfig.h'

配布物中に`acconfig.h'が含まれていない場合、もっとも簡単な解決策は GNU gettextから`acconfig.h'をコピーすることです。しかし厳密に は、必要となるのはENABLE_NLSHAVE_CATGETSHAVE_GETTEXTHAVE_LC_MESSAGESHAVE_STPCPYPACKAGEVERSIONが含まれた行とコメントだけです。従って、エディ タを使うことによって必要としない部分を全て取り除く必要があるかもしれません。 既に`acconfig.h'ファイルが存在するなら、前述の定義をあなたの `acconfig.h'にマージする必要があります。


10.4.5 トップレベルに存在する`Makefile.in'

トップレベルに存在するの`Makefile.in'ファイルに対する幾つかの修正点に ついて述べます。

  1. `dist:'ゴールが正しく機能するように(以下で説明されるように)、 `Makefile.in'の先頭近くに以下の行を追加して下さい。

     
    PACKAGE = @PACKAGE@
    VERSION = @VERSION@
    

  2. DISTFILES定義に`ABOUT-NLS'ファイルを追加して下さい。 これによってこのファイルは配布対象となります。

  3. `Makefile.in'中のどこででサブディレクトリを処理するにしても、 `intl'`po'もまた処理されることを確認して下さい。 `Makefiles'中の特別なルールは、国際化が必要とされない場合に処理を行い ます。

    automakeから生成されるか、或いはGNUコーディング規約に注意深く従った手書き のMakefileを使用している場合、新しいサブディレクトリに対して実行されるゴー ルとして、`installdirs'`install'`uninstall'`clean'`distclean'を含む必要があります。

    ここに厳密な処理の順番の例を示します。この例では後ほど`dist:'ゴールで 使えるように、Makefile.inSUBDIRSをもまた定義しています。

     
    SUBDIRS = doc lib @INTLSUB@ src @POSUB@
    

    これが、あなたのパッケージに対して適用せなければならないことです。

  4. `dist:'ゴールは大切なポイントです。なぜなら、`intl/Makefile'`po/Makefile'は共に、適切な配布ディレクトリがメインの `Makefile'によってセットされていると後から仮定するからです。ここで `dist:'がどのようなものであるかの例を示します。

     
    distdir = $(PACKAGE)-$(VERSION)
    dist: Makefile
    	rm -fr $(distdir)
    	mkdir $(distdir)
    	chmod 777 $(distdir)
    	for file in $(DISTFILES); do \
    	  ln $$file $(distdir) 2>/dev/null || cp -p $$file $(distdir); \
    	done
    	for subdir in $(SUBDIRS); do \
    	  mkdir $(distdir)/$$subdir || exit 1; \
    	  chmod 777 $(distdir)/$$subdir; \
    	  (cd $$subdir && $(MAKE) $@) || exit 1; \
    	done
    	tar chozf $(distdir).tar.gz $(distdir)
    	rm -fr $(distdir)
    


10.4.6 `src/'以下の`Makefile.in'

メインの`Makefile.in'に対して行われた幾つかの修正は、あなたのパッケー ジソース(ここでは`src/'サブディレクトリに置かれていると仮定される)の `Makefile.in'に対しても必要になるでしょう。`src/Makefile.in'に必 要となる全ての修正を示します。

  1. `dist:'ゴール用に、これらの行を`src/Makefile.in'の最初のほうにお く必要があります。

     
    PACKAGE = @PACKAGE@
    VERSION = @VERSION@
    

  2. まだ行われていないのであれば、top_srcdirが定義されることを保証しな ければなりません。これはcppインクルードファイルに貢献するでしょう。 この行を追加するだけです。

     
    top_srcdir = @top_srcdir@
    

  3. 全ての`Makefile.in'中でほぼ同一に`dist:'ゴールを使用できるように、 subdirとして`src'もまた定義したいと考えるでしょう。後から述べ る`dist:'ゴールに関する項では、次の定義がなされていると仮定します。

     
    subdir = src
    

  4. 最終的なリンクでは、ライブラリとして@INTLLIBS@が使用されるように しなければなりません。それをLIBSに追加してしまうのが簡単です。この ようにします。

     
    LIBS = @INTLLIBS@ @LIBS@
    

    GNU gettextによって国際化された多くのパッケージには、ビルド用の補助 関数群が含まれるライブラリを置くための`lib/'ディレクトリがあるでしょ う(少なくとも、GNU gettextライブラリ自身が必要とする幾つかの関数が 必要になります)。しかし`lib/'中の幾つかの関数は、当然ながら翻訳される べきメッセージをもまた含んでいます。この問題を解決するためには、補助ライブ ラリ(`libsupport.a'としましょう)を前述の例における @INTLLIBS@@LIBS@の間に置くだけでは不十分です。その代り に、このようにします。

     
    LIBS = ../lib/libsupport.a @INTLLIBS@ ../lib/libsupport.a @LIBS@
    

  5. `intl/'ディレクトリもまた、いかなる場合でもその中にあるインクルードファ イルがCプリプロセッサによって検索されるようにしなければなりません。従って、 `-I../intl'`-I$(top_srcdir)/intl'の両方がCコンパイラに与えられ るようにする必要があります。

  6. `dist:'ゴールは他のものと一致する必要があります。このための簡単な定義 は次のようなものです。

     
    distdir = ../$(PACKAGE)-$(VERSION)/$(subdir)
    dist: Makefile $(DISTFILES)
    	for file in $(DISTFILES); do \
    	  ln $$file $(distdir) 2>/dev/null || cp -p $$file $(distdir); \
    	done
    


11. 結論

我々はこのGNU gettextマニュアルを翻訳プロジェクトの歴史でもって 締めくくろうと思います。最後にネイティブランゲージサポートについて読んだ り、調べたりしたい人のために幾つかのポインタを示します。

11.1 GNU gettextの歴史  
11.2 参考文献  


11.1 GNU gettextの歴史

国際対応の重要性やアルゴリズムは、非公式にではありますがが毎日のように数年 に渡ってGNUで論議されてきました。ときにはGNU libに関係して、あると きはHurdに関係して、あるいはその他のものに関係してです(誰もはっきり とは覚えていません)。そしてそれから作業は実際に始まりましたが、これは先だっ ての議論とは独立したものでした。

全ては、Patrick D'CruzeがGNU fileutilsバージョン3.9.2の国際対応につ いてのアイディアそして主導権を得たとき、つまり1994年の7月に始まりました。 彼はそれから保守担当者であるJim Meyeringに、国際対応に関する変更をどのよう にして正式リリースに含めるかについて尋ねました。最初のドラフトは #ifdefの塊で面食らうような代物でしたので、Jimはもっと良い方法を求め ていました。PatrickとJimはこの分野においての試みや経験を共有していました。 そして、結局のところこの作業はGNUに大きなインパクトを与えると感じたので、 Jimは標準がどのようなものであるかを知りたくなり、そして彼はRichard Stallmanにコンタクトを取りました。Richardはその時点で、glocaleとな るコード全体のデザインについて非常に手早くかつ丁寧に記述しました。

Jimはglocaleを実装し、PatrickやRichardから多くのフィードバックを受 けました。もちろん、Mitchum DSouza(catgetsのようなパッケージを記述 した)やRoland McGrath, またDavid MacKenzieや Pinard、 Paul Eggertらからのフィードバックもありました。様々な方向性が入り乱れ、し かもそれら全てに互換性があるというわけではなかったため、二、三のテストリリー スの後、glocaleは破棄されました。

Jimがある程度距離と時間をおき、そして二人目のパパになった間に、Rolandは GNU libcを国際対応させたいと望んでおり、Ulrich Drepperがそのプロジェ クトに加わりました。glocaleから作業を始める代わりに、Ulrichは一から コードを書き直しましたが、それはglocaleの作業で明らかになったガイド ラインにより一層従う形になっていました。それからUlrichは以前のフォーラムか ら新しいプロジェクト用に人員を獲得し、glocaleをまず msgutilsと改称しました。それは後にnlsutilsという名前になり、 さらにgettextという名称になりました。これは1995年5月頃にRichardによっ て公式に受諾されました。

Ulrich Drepperが1995年の四月にGNU gettextで書いたことに言及してまと めとしようかと思います。POモードを含んだパッケージの最初の公式リリースは 1995年の7月に行われ、そのバージョン番号は0.7でした。その他の人々は Ulrichの回りの議論フォーラムで作成された、小さなコードのかけらやテストの結 果といった諸々のものを寄贈しました。彼らの名前はGNU gettextに付随す るTHANKSファイルに納められました。

この作業が進んでいた間、Françoisは最初に半ダースのGNUパッケージに glocaleを、続いてgettextを現在のように適用してプリテストの状 態にし、進化するツールを微調整するための効果的なユーザ環境を準備しました。 彼はまた、翻訳プロジェクトを組織化し統合する責任をも引き受けました。 Patrick D'Cruzeは多くのネイティブランゲージのための20の非モデレートなメー リングリスト、そして二つのモデレートされたリスト(一つは全てのチームに直ち に届くもの、もう一つは国際化されたフリーソフトウェアパッケージの全ての自発 的な管理者に連絡するためのもの)を作成し管理しました。そしてほぼ一年の間に 多くの国々の人々の間で非公式な情報交換が行われ、翻訳者チームが1995年5月に 発足しました。

はまたGreg McGaryの協力を受け、1995年の六月にPOモードを書 きあげています。これはUlrichのパッケージに寄贈されました。彼はまたGNU gettextのTexinfoマニュアルも寄贈しています。


11.2 参考文献

Eugene H. Dorr(`dorre@well.com')はInternationalization Reference Listという国際化対応に関する興味深い文献の保守を行っています。 これは次の場所で入手可能です。
 
ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/i18n-books.txt

Michael Gschwind(`mike@vlsivie.tuwien.ac.at')はProgramming for Internationalisationというタイトルの「良くある質問」(Frequently Asked Questions (FAQ))のリストを保守しています。このFAQは異なる言語慣習、 キャラクタセットなどを扱うことが可能なプログラムの記述について論じています。 そしてこれは、特にISO 8859-1及び全てのキャラクタセットエンコーディング に対して適用できます。これは通常、

`comp.unix.questions', `comp.std.internat', `comp.software.international', `comp.lang.c', `comp.windows.x', `comp.std.c', `comp.answers'`news.answers'といったUsenetのグループに投稿されています。 このドキュメントの入手先は以下の通りです。

 
ftp://ftp.vlsivie.tuwien.ac.at/pub/8bit/ISO-programming

Patrick D'Cruze(`pdcruze@li.org')はNLSに関するチュートリアルを書きま した。そしてJochen Hein(`Hein@student.tu-clausthal.de')はそれに関す る保守作業を引き継ぎました。この文書は次の場所にあります。

 
ftp://sunsite.unc.edu/pub/Linux/utils/nls/catalogs/Incoming/...
     ...locale-tutorial-0.8.txt.gz
このサイトは以下のサイトへミラーリングされています。
 
ftp://ftp.ibp.fr/pub/linux/sunsite/

同じチュートリアルのフランス語版は以下にあります。
 
ftp://ftp.ibp.fr/pub/linux/french/docs/
ここには、フランス語に訳されたLinux関係のドキュメントもあります。


A. 国家コード

ISO 639は多くの国家に対して2文字のコードを規定しています。翻訳プロジェ クトが国家や言語に対して使用している省略形には、この標準が採用されています。


[Top] [Contents] [Index] [ ? ]

Footnotes

(1)

この制限はGNU gettextによって強制され たものではなく、Solarisのmsgfmtの実装から来ています。

(2)

Ultrixなどの一部のシステムではLC_MESSAGESを持って いなません。ここで我々はこのために恣意的な値(arbitrary value)を使います。

(3)

システムがsetlocaleをサポートしていないとき、ロカールの値 を設定する動作は環境変数を参照することによりシミュレートされます。


[Top] [Contents] [Index] [ ? ]

Table of Contents


[Top] [Contents] [Index] [ ? ]

Short Table of Contents

1. イントロダクション
2. POファイルとPOモードの基本
3. プログラムソースの準備
4. 最初のPOファイルの準備
5. 既存のPOファイルの更新
6. MOファイルの作成
7. ユーザとしての視点
8. プログラマとしての視点
9. 翻訳者としての視点
10. 保守担当者としての視点
11. 結論
A. 国家コード

[Top] [Contents] [Index] [ ? ]

About this document

This document was generated by & Yosiaki on November, 13 2000 using texi2html

The buttons in the navigation panels have the following meaning:

Button Name Go to From 1.2.3 go to
[ < ] Back previous section in reading order 1.2.2
[ > ] Forward next section in reading order 1.2.4
[ << ] FastBack previous or up-and-previous section 1.1
[ Up ] Up up section 1.2
[ >> ] FastForward next or up-and-next section 1.3
[Top] Top cover (top) of document  
[Contents] Contents table of contents  
[Index] Index concept index  
[ ? ] About this page  

where the Example assumes that the current position is at Subsubsection One-Two-Three of a document of the following structure:

This document was generated by & Yosiaki on November, 13 2000 using texi2html