[Top] | [Contents] | [Index] | [ ? ] |
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
grok8.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 参考文献
このマニュアルはまだドラフト状態であり、幾つかのセクションはまだ空 かそれに近い状態です。我々は作成が遅れている部分を統合しながら、他の情報源 (特に電子メールのフォルダ)から適切な統合が遅れている資料を取り込み続けてい ます。
このマニュアルでは、プログラマや保守担当者について話すときには彼
を、翻訳者として彼女を、翻訳済みプログラムをインストールする人
やエンドユーザとして彼らという単語を使用すします。これはこのドキュ
メントを明快にするためだけのものであり、決して男性や女性が何から
の役割を果たすのにより適しているということを暗示するものではありません。
そしてまた、あなたが考える通り、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
の概要
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
がどのように翻訳プロジェク
トの残作業に関連しているかについてを理解するために、その結果として
大きな一枚絵を垣間見るために、プログラマ及び好奇心の強いユーザの役
に立つことでしょう。
プログラムでのネイティブランゲージサポートについて議論するときは、常に二 つの厳密な意味を持つ長い単語が登場します。internationalizationと localization、この二つの単語には、このドキュメントのためにここで 説明するだけの価値があります。この二つの長い単語を繰り返し繰り返し書くこ とに疲れてしまった多くの人々は、それをきちんと書く代わりに、先頭と最後の 文字を残し、その間にある文字列をその長さで置き換えてi18nと l10n と書くようにしました。しかしこのマニュアルでは物事を明確にす るために、そのたびにきちんと正確に書くことにします...
国際化(internationalization)によって、プログラムまたはパッケージとな
るプログラム群における処理は複数の言語を認識しサポートできるようになり
ます。これは、プログラムから英語の文字列やその他の英語特有の慣習を切り離し
て、その代わりに同じことを行う一般的な方法を考慮するという点で、一般化のプ
ロセスであると言えます。 プログラムの開発者は、自分が作成するプログラムに
対して様々な国際化の技法を使うことができ、そのうちの幾つかは標準的なものと
なっています。gettext
はこれらの標準の一つを提案するものです。
See section 8. プログラマとしての視点 。
地域化(localization)によって、既に国際化されているプログラム群にお ける操作において、プログラムに(そのプログラムが)必要とする全ての情報を与え ることにより、プログラムに対する入力やプログラムからの出力をあるネイティブ ランゲージや文化的特性(cultual habits)について正しく取り扱うことができるよ うになります。国際化されたプログラムで既に実装された一般的な手法を、特殊な 方法で使用するという点で、これは特殊化のプロセスであると言えます。プログラ ミング環境には、プログラマが実行時に設定を調整出来るような幾つかの関数が用 意されています。ある国で使われる言語を対象とした全ての関連した翻訳、そして それと共に使われるその国における文化的特性の固有の集合を、その言語、国に対 する ロカール(locale)といいます。ユーザはプログラムを実行する前に、 どのロカールを使用するのかを示すために特殊な環境変数に適切な値を設定します。 これによってプログラムの地域化が行われます。
実際のところ、ロカールによるロカールメッセージサポートは、特定のロカールを 構成する文化的データ(cultural data)の要素の一つに過ぎません。国際化された ソフトウェアを開発するプログラマの手助けをしたり、ある特定のロカールに属す るデータへのアクセスを実行するための、完全なルーチン群や関数群が存在します。 今、ある人があるロカールを参照するとすれば、それらの関数群やルーチン群は該 当するロカールに格納されているデータを参照しています。同様に、あるプログラ マが「ロカールルーチン群にアクセスする」と言った場合、それらの関数群やルー チン群とはロカールの情報全てにアクセスできるルーチン群の完全な集合 (complete suite)のこととなります。
プログラム中で複数の言語を使用可能とする、国際化と地域化の両方を包含する特 徴及びその活動全体を表現するために、ネイティブランゲージサポート、ま たは稀にNLSという表現が使われます。要約すれば、国際化とは地域化を可能とす るものを越えた処理であると言えるでしょう。
また、非常に大雑把に言ってしまえば、マルチリンガルメッセージを実現する際、 国際化は一般的にプログラマが注意することであり、地域化は一般に翻訳者が注意 することとなります。
完全なマルチリンガルのディストリビューションのためには、出力メッセージ以外 にも翻訳すべき事柄があります。
gettext
はCプログラムが出力するメッセージ群を翻訳するた
めの完全なツールセットを提供します。perlスクリプトとシェルスクリプトもま
た翻訳が必要です。しかし、たとえこれを成し遂げるためのいくつかのフックが
現在存在したとしても、それらはまだきちんと統合されていません。
autoconf
やbison
のような幾つかのプログラムは、他のプログラム
(やスクリプト)を生成することが出来ます。それらの生成プログラム自身が国際化
されていたとしても、それらの生成プログラムが生成したプログラムも国際化され
なければなりません。そして、この間接的な国際化は生成側のプログラムによって
自動化することもできるかもしれません。実際のところ、ほとんどの場合には生成
側のプログラムと生成されたプログラムをそれぞれ別個に国際化するような労力が
必要になるでしょう。
recode
が実行時に再構成することができる各キャ
ラクタに対する英語表記を提供しています。これらの記述はRFCから機械的に展開
されたものですので、これらを翻訳するためには当然RFC自身の翻訳が事前に必要
となります。
gcc
が区別された文字(diacriticized characters)を識別子中や予約語中
に使ったりすることができるようにしたいと望むかもしれません。`rm -
i'はそれに対する返事として、`y'や`n'以外のものを受け付ける
かもしれません。プログラムが最終的にその出力のほとんどを外国語で行うように
なったとしても、入力の構文やオプションの値なども地域化するのかしないのかを
決定する必要があります。
既に強調したように、メッセージの翻訳はロカールの一側面でしかありません。他
の国際化の側面は現在の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:mm、hh.mmなどと記述されます。幾つかのロ カールは午前 / 午後の指定を使用せずに24時間制で記述するようになっています。 さらに、夏時間の性質や夏時間が実施される期間は国ごとによって大きく違います。
数値は各ロカールごとに異なる表記法を取ります。例えば、次の数はそれぞれのロ カールごとの表記法によって正しく記述されたものです。
12,345.67 英語圏 12.345,67 フランス 1,2345.67 アジア |
一部のプログラムではもっと進んでいて、異なる単位系、例えば英単位(English units)やメートル法、あるいは数値をまるまる綴るといった方法のような、様々な 単位系を使用するかもしれません。
もっとも大切なのは、ロカール中の言語サポートです。開発者にとってもユーザに
とっても、ソフトウェアがユーザと対話する際の言語を簡単に変更できること、そ
れこそがGNU gettext
が提供するものです。
近い将来に、メッセージハンドリング以外のロカール構成要素が他のパッケージ
中で使用可能になるということは考えられません。なぜなら、ほとんどの最近の
システムでは、そのシステムに欠けているロカール中の構成要素の少なくとも幾
つかを、多少なりとも合理的にサポートしているからです。もう一点は、GNU
libc
とLinuxが、サポートが欠けているシステムにおいて利用できるよ
うな新しく完全で合理的なロカール機能全体の実装を実現するからです。
`.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フォーマットを使っていることを示して
います。
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 エンドユーザへの魔法)、プログラムが実行され
ればいつでも自動的に地域化されるでしょう。
本マニュアルの残りの部分は、このセクションで述べた概要をより掘り下げて説 明するためのものとなります。
GNU gettext
ツールセットは、プログラマと翻訳者が主に(テキスト形式
で、編集可能な)POファイルのような翻訳ファイルを生成したり、更新したり、
あるいは使ったりすることを助けるものです。この章ではPOファイルの書式と、
POモードスタータ(PO mode starter)の構成を強調します。POモードの記述は一ヶ
所にまとめられておらず、このマニュアル全体に散らばっていますので、ここで
はPOモードの基本についてのみ解説します。
2.1 GNU gettext
のインストールを完了する2.2 POファイルのフォーマット 2.3 POモードの主要なコマンド 主要なコマンド 2.4 エントリの位置 2.5 エントリ内の文字列の正規化
gettext
のインストールを完了する
GNU gettext
の配布キットを入手し、展開、コンフィグレーション、コンパ
イルした後、`make install'というコマンドによってxgettext
、
msgfmt
、gettext
、msgmerge
といったプログラム、そして同
時にそれらのプログラムで使用可能なメッセージカタログが所定の場所にインストー
ルされます。完全に快適なインストールのために、あなたは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) |
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
プログ
ラムが扱います。現在のところ、二つの形式のフラグが定義されています。
msgmerge
プログラムによって生成されうるか、または翻訳者
自身によって付与されうるものです。これはmsgstr
文字列がおそらく正し
い翻訳でないことを示しています。翻訳者は更に翻訳を進めるか、あるいは現在の
ままでいくかを決定するだけです。ひとたび翻訳が完了したなら、彼女はこの
曖昧属性を取り除きます。msgmerge
プログラムは曖昧検索(fuzzy
search)の後でmsgid
とmsgstr
が結合されたときのみこの属性を付
与します。See section 5.3 曖昧な翻訳エントリ。
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-stringとtranslated-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.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-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 gettext
の
msgfmt
ツールはMOファイルをPOファイルから作成するという目的を持って
います。そして、POモードはこのプログラムの機能を全ての個別のエントリのチェッ
ク、そしてPOファイル全体のフォーマットのチェックのために使っています。
msgfmt
プログラムはEmacsと非同期に動作するので、翻訳者は即座にPOファ
イルの制御を取り戻します。エラー出力はGNU Emacsの`*compilation*'バッ
ファに集められて別のウィンドウで表示されます。通常のGNU Emacsコマンド
C-x`(next-error
)は、他の通常のコンパイルコマンドと同様、POファ
イルの問題となった部分にすばやく移動することを可能とします。一旦カーソルが
エラーのある行に移れば、翻訳者はエラーを修正するのに役立つ任意のPOモードア
クションを取ることができます。
POファイルウィンドウにあるカーソルはほとんど常にエントリの一部です。唯一の 例外はファイルの最後のエントリの後ろにある場合、あるいはPOファイルが空の場 合といった特殊なものです。多くのPOモードコマンドはカレントエントリで動作す るので、翻訳者はPOファイルを眺めて回ることよりもカーソルを移動することのほ うが多くなります。カーソルを移動するということは、コマンドの操作対象となる エントリを選択することにもなります。
いくつかののPOモードコマンドは特殊なやり方でカーソル位置を変えます。これら の特殊な目的での位置の移動の幾つかをここで説明し、その他のものはこの後のセ クションで説明します。
幾つかの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を使います。
POファイルの各エントリに特定の文字列をエンコードしておくということについて
は、多くの異なった方法があります。なぜなら、複数行に渡る文字列の引用や分割
の方法はたくさんありますし、更に、バックスラッシュの付いたエスケープシーケ
ンスによる特殊キャラクタの表現方法も一つではないからです。POモードの幾つか
の機能は、既に存在しているPOファイル中でmsgid
フィールドにあるエンコー
ドされた特定の文字列を検索するPOモードの機能に依存しています。この認識を簡
単に実装するために、POモードがすべての組み込み機能を内部的に持っていたとし
ても、それを高速に行うのは技術的には困難です。この効率に関する問題を解決す
るため、我々は文字列を標準的(canonical)に表現することを決定しました。
POファイルにおける伝統的な(conventional)文字列の表現に関しては現在議論中で
あり、そしてPOモードの標準的記法についても実験中です。等価な文字列を表わす
ための統一的な方法に向けて、xgettext
とPOモードの両方を統合すること
は有用です。GNU gettext
のxgettext
を使った時点で、POモードが
必要とする内部的な正規化が自動的に実行されるのですから。事細かなPOモードに
よる正規化は、どこかからかインポートされるPOファイルに対してのみに、あるい
はそれ自身を発展させるための議論のときのみに必要となります。
POファイル内にある、少なからず標準的記法を必要としている文字列を正規化する には、以下のPOモードのコマンドを使います。
特殊コマンドM-x po-normalize(特定のキーには割り当てられていません)は すべてのエントリを再検査し、オリジナルのものと翻訳されたものの両方の文字列 のエントリがPOファイルにおける規定の形式でクォートされていることを保証しま す。このコマンドは最後のエントリの後ろにあるゴミも取り除きます。このコマン ドはPOファイルをどこかから新規にインポートしてきたときや、標準的なクォート のフォーマットに変更する際に有用です。この標準的なクォートのフォーマットに 変換することにより、よりクリーンなPOファイルを得ることが出来るだけでなく、 他のPOモードコマンドが文字列を高速に検索することが出来るようになります。
M-x po-normalizeは各エントリに対して処理を三回試行します。最初の方法
はGNU gettext
0.6より前に採用されていたPOファイル変換のヒューリスティ
クスで、msgid
とmsgstr
フィールドは複数行を扱う際にK&Rスタイ
ルのC文字列を使っていました。これらのヒューリスティクスは廃止されたエント
リと関連づけられておらず、かつバックスラッシュで終了するコメントに対しては
失敗していました。これらのヒューリスティクスは廃止されたエントリに続く行も
コメントにしてしまっていたからです。一旦全ての古いPOファイルが修正されたな
ら、この最初の方法は消滅するでしょう。第二、第三の方法は全ての
msgid
と msgstr
文字列を個別に正規化します。これらの方法は
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" |
文字列の正規化の細部については、まだ幾つかの未決定事項が残されています。 それらの問題が解決したら、このマニュアルに記載されます。
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 特別な翻訳対象文字列
gettext
の処理をトリガする ロカールデータの初期化は、どのプログラムでもこのような形で行われます。下の 例を参照してみて下さい。
int main (argc, argv) int argc; char argv; { ... setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); ... } |
PACKAGEとLOCALEDIRは、共に`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_CTYPE
、
LC_COLLATE
、LC_MONETARY
、LC_NUMERIC
、そして
LC_TIME
ロカールカテゴリが使用可能になっています。一部の現代的なシス
テムでは、XPG2準拠システムでかつてLC_RESPONSES
と呼ばれていた、
LC_MESSAGES
ロカールが定義されています。
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"'は翻訳を 必要としない文字列の例です。
POモードにおける機能は翻訳者向けと云うよりはプログラマ向けです。そして、プ ログラマに対してプログラムソース中にある文字列が翻訳可能であるか、そうでな いかのマーク付けを対話的に行うことができるようになっています。そのような文 字列を見つけだしてマーク付けをするという作業が、プログラマにとって自分の好 きなエディタを使って行えるごく簡単な作業であったとしても、POモードはこの作 業をより快適にするのです。更にPOモードは、国際化されたパッケージのプログラ ムソース中の翻訳対象となる文字列にマーク付けしている間、プログラマに翻訳者 のような気分を、翻訳者にプログラマのような気分を味わせます。
ここで説明するPOモードのコマンドが対象とするプログラムソース群は、プロジェク トのために構築されたEmacsタグテーブルを持つべきです。これは簡単なことで、 任意のシェルウィンドウ中でプロジェクトのルートディレクトリに移動し、次に挙 げるようなコマンドを実行するだけです。
etags src/*.[hc] lib/*.[hc] |
ここで、`src/'や`lib/'といったディレクトリにある全ての `.h'と`.c'とを処理したい状況を考えてみましょう。このコマンドは全 てのファイルを探索して、プロジェクトのルートディレクトリに`TAGS'とい うファイルを作成します。これはEmacsが理解することの出来る、特殊なフォーマッ トによる内容の要約になります。
GNUコーディング標準に従っているパッケージでは、ソースを構成する全てのファ
イルから構成されたタグファイル(tags
かTAGS
)が全てのディレクト
リに存在することになっています。
`TAGS'というファイルが用意されれば、プログラマがソースファイル中にあ る翻訳対象文字列をマーク付けするために後述するコマンド群が使用できます。こ れらのコマンドはPOファイルウィンドウの中で起動される必要があるのですが、ま だPOファイルが作成されていないことということがありがちです。これはそれほど 問題にはなりません。これらのコマンドを主に使用するために、安全に新しい空の POファイルを開くことができます。あなたがマーク付けしたプログラムソース中の 翻訳対象文字列によって、この空のPOファイルは徐々に満たされてゆくでしょう。
,(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-search
や
tags-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-,コマンドの組み込みとして既に 設定されているからです。
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オプションがこの問題
を解決するために使えることがわかります。
注意深い読者はここで、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_noop
をxgettext
に知ら
せる方法については、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.1 xgettext
プログラムの起動4.2 Cソースの文脈 4.3 翻訳要約機能の使用
xgettext
プログラムの起動
xgettext [option] inputfile ... |
xgettext
プログラムによって決定されるもので、フォー
マットフォームはプログラマがそう規定した場合に使われます。
デフォルトではc-formatフォームのみが使われます。翻訳者はこの詳細に ついて考えるべきではありません。
特別なドメイン名である`-'または`/dev/stdout'は、`標準出力' に出力することを意味します。
明らかに使用しないことを指定しない限り、
gettext
、dgettext
、dcgettext
とgettext_noop
が
デフォルトのキーワードとなります。
.gmo
ファイル生成時の変動を絶つことが出来るので、テスト目的に使用す
るのに便利です。これらのファイルはGNU gettext
パッケージで使用でき、
msgfmt
でも使用できます。両方の結果は同じものになります。
追加のPOファイルのサーチパスは`/usr/local/share/nls/src/'となります。
inputfileとして`-'が指定されたときは、標準入力から読み込みます。
xgettext
のこの実装はプリプロセッサマクロ中の文字列、ANSI規格での隣
接した文字列の連結、文字列の継続のための行末のエスケープなどのような、幾つ
かの厄介なケースの処理を可能とします。
POモードは、GNU gettext
ユーティリティを使って作られたPOファイルを扱
うときに力を発揮します。GNU gettext
ユーティリティは生成したPOファイ
ルに特殊なコメントを挿入します。これらの特殊なコメントの一部は、POファイル
のエントリとプログラムソース中の未翻訳文字列が出現する場所を関連付けます。
翻訳者が未翻訳エントリを扱う際、彼女が扱う未翻訳文字列はしばしば簡潔すぎた り、暗号的であったり、曖昧であったりといった、わかりにくいものであることが あります。その文字列をどのように翻訳するかを考える前に、翻訳者はそれが何を 意味しているのか、そしてどのような翻訳が適切なのかを理解する必要があります。 そのような問題に直面したとき、翻訳者が判断を下すためにはその文字列が使われ ている本物のプログラムソースを読み、文字列の近くにあるプログラマが書き残し たコメントを捜し出し、そして何らかの手掛かりを得るしかありません。
もちろん、翻訳者が手練のプログラマであればプログラムソースを読むことで更な る情報を得ることが出来るでしょう。しかし、彼女が経験を積んだプログラマでな く、Cのコードに戸惑いを感じたとしても、ソースを読むことについて臆病になっ てはいけません。翻訳者が必要とする何らかのヒントを得ることが出来るという可 能性はまだあるのですから。翻訳者はすぐに、プログラマのコメント、(プログラ マが理由を持って命名した)変数及び関数名、全体の構造について一層注意を払う ことで、プログラムコードが不快なものではないということを学ぶでしょう。
以下のコマンド群は、翻訳者がPOファイルのエントリに関係するプログラムソース の文脈を調べるときに役立つようになっています。
コマンド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
)は、翻訳者がもはや必要としなくなったディレク
トリをサーチパスから選択するために使われます(補完機能付きで)。
要約機能はまだ実装されていません。
POモードの将来の実装では、翻訳者は既に翻訳したものの要約を保守することにな ります。要約とは、多くのパッケージで頻繁に用いられる翻訳文字列群をま とめた特別なPOファイルのことです。翻訳者は自分が使用する要約に新しいエント リを追加しておき、後で未翻訳エントリを初期化するとき、あるいは既に翻訳され たエントリを更新するときに、要約から翻訳文字列を引き出すことが出来ます。し かしこの作業のためには、要約は正規化されていなければなりません。 See section 2.5 エントリ内の文字列の正規化。
5.1 msgmerge
プログラムの起動5.2 翻訳済みエントリ 5.3 曖昧な翻訳エントリ 5.4 未翻訳エントリ 5.5 廃止エントリ 5.6 翻訳の修正 5.7 コメントの修正 5.8 補助POファイルを参考にする
msgmerge
プログラムの起動
それぞれのPOファイルエントリについて、msgstr
に翻訳が定義され、かつ
曖昧(see section 5.3 曖昧な翻訳エントリ)であるとマーク付けされていない場合、そのエント
リは翻訳済エントリと呼ばれます。翻訳済エントリは後からGNU
msgfmt
によってコンパイルされ、プログラム中で使用可能にされるだけで
す。その他のエントリタイプは締め出されます。それらについては翻訳が作成され
なかったのです。
幾つかのコマンドはより密接に翻訳済エントリの処理と結び付いています。
コマンドt(po-next-translated-entry
)とM-t
(po-previous-transted-entry
)は前後に移動し、翻訳済エントリを探し出
します。見つからなかった場合、POファイルバッファを回り込んで検索が行われま
す。
翻訳済エントリは通常、翻訳者がエントリを翻訳して作成されます
5.6 翻訳の修正。しかし、もし変数
po-auto-fuzzy-on-edit
がnil
でなかった場合、最初に新しい翻訳が
なされたエントリは曖昧なエントリとなります。そのエントリは後から、公式かつ
本物の翻訳済エントリとなる前に曖昧ではなくされなければなりません
See section 5.3 曖昧な翻訳エントリ。
それぞれのPOファイルエントリは属性の組を持っています。それらは名前が
付けられた品質であり、特別なシステムコメントを使用することでエントリの翻訳
と明白に結び付けられます。これらの属性のうちの一つは曖昧
と名付けら
れており、この属性を持つエントリは曖昧な翻訳を持っていると言われます。単純
に曖昧なエントリとも呼ばれます。
曖昧なエントリは、たとえ多くの他の目的のためにそれらが翻訳済エントリとみな
されるとしても、通常は翻訳者によって修正されなければなりません。幾つかの新
しいmsgid
が古いPOファイル中にあるmsgid
からわずかに修正された
ものであり、かつその新しく修正されたエントリに対応する、古い翻訳であると考
えられるものとが対になるとmsgmerge
プログラムが仮定したとき、
msgmerge
プログラムが新しいPOテンプレートファイルによって古い翻訳済
POファイルを更新することによって、これらのエントリが作成されます。本来の文
字列(msgid
にある文字列)に対する若干の変更はしばしば翻訳済文字列に影
響し、これは翻訳者による修正を要求します。このため、msgmerge
はいく
つかのエントリを曖昧であるとしてマーク付けすることでしょう。
翻訳者はまた、エントリに再び手を入れる必要があるということを記憶してきたい ときに、自分自身の利便のためにエントリを曖昧であるとしてマークしておくこと が出来ます。幾つかのコマンドはより密接に曖昧なエントリの処理と結び付いてい ます。
コマンドf(po-next-fuzzy
) とM-f
(po-previous-fuzzy
)は前後に移動し、曖昧なエントリを探し出します。見
つからなかった場合、POファイルバッファを回り込んで検索が行われます。
コマンドTAB(po-unfuzzy
)はエントリに結び付いた曖昧属性を外し、
通常は翻訳済にします。さらに、もし変数po-auto-select-on-unfuzzy
が
nil
でない場合、TABコマンドは自動的に他に作業する必要があるエ
ントリを探し出します。po-auto-select-on-unfuzzy
の初期値は
nil
です。
po-auto-fuzzy-on-edit
の初期値はnil
です。しかし、変数
po-auto-select-on-unfuzzy
がt
に設定されたならば、 RETコ
マンドによって編集されたエントリには曖昧属性が付与されます。それはダブルク
リックを用いることと同じです。この場合、(常にではないにせよ)翻訳者が修正し
たときはいつでも、エントリは曖昧になるということが普通になります。もし彼女
が翻訳に満足した場合、彼女は曖昧属性を吹き飛ばし、TABを使って他のエ
ントリに対する作業にかかるでしょう。もし彼女がまだ満足していない場合は、そ
のエントリを曖昧なままにしたまま他のエントリに移るために、ただSPCを
使うだけです。
翻訳者はまた、あるエントリに後で作業するために簡単に戻れるようにしたいと考
えたのなら、翻訳済エントリを曖昧にするためにDELコマンド
(po-fade-out-entry
)を使うこともできます。
そして、qコマンドを使ってPOファイルバッファでの作業が完了させたとき に曖昧なエントリがまだ残っていれば、POモードは翻訳者に対して作業を終了する かどうかを確認します。
xgettext
が最初にPOファイルを生成したとき、msgid
は未翻訳文字
列で初期化され、msgstr
には空文字列が設定されます。空の翻訳文字列を
持つエントリは未翻訳エントリと呼ばれます。その後、プログラマがプログ
ラム中で一部の文字列をほんのちょっとだけ修正した場合、修正された文字列は未
翻訳文字列として、POファイルに新しいエントリとして追加されることになります。
エントリ間を移動する通常のコマンドは、アクティブになったエントリと同じレベ ルにある未翻訳エントリに注意を払います。未翻訳エントリは`msgstr ""'で終了するという事実から、簡単に発見することが出来ます。
翻訳者の作業というのは、未翻訳エントリを探しだして翻訳し、その作業を未翻訳 エントリがなくなるまで繰り返すという意味では(本当に単純な)作業に思えるかも しれません。幾つかのコマンドは未翻訳エントリ処理に特化しています。
u(po-next-untranslated-entry
)コマンドとM-u
(po-previous-untransted-entry
)コマンドはそれぞれ、前方と後方に移動
して未翻訳のエントリを探し出します。見つからなかった場合には、検索はPOファ
イルバッファを回りこんで継続します。
翻訳文字列を単に空にすることによって、エントリを未翻訳のエントリへと戻すこ
とが出来ます。これにはkコマンド(po-kill-msgstr
)を使います。
See section 5.6 翻訳の修正.
qコマンドを使用してPOバッファでの作業を終了する際、もし未翻訳の文字 列が残ったままの場合は、POモードは翻訳者に対して作業を終了するかどうかを確 認します。
地域化されているパッケージにおいて、これ以上翻訳する必要がないエントリは
msgmerge
を使用することによって発見され、コメントアウトされます。こ
れらのエントリは、廃止エントリと呼ばれます。
エントリ間を移動する通常のコマンドは、アクティブになったエントリと同じレベ
ルにある廃止エントリに注意を払います。廃止エントリはmsgid
又は
msgstr
を含む全ての行が#で開始されているという事実によって簡単
に発見することが出来ます。
幾つかのコマンドは、元々の未翻訳文字列によって翻訳文字列を初期化します。キ ルリングを扱うコマンドのインターフェースは、以前に保存されたテキストを翻訳 文字列として格納することが出来ます。ユーザは翻訳を対話的に編集することが出 来ます。これら全てのコマンドは、その結果として廃止エントリを廃止エントリの ままにしておくことが出来ます。
更に、幾つかのコマンドは廃止エントリの処理に特化しています。
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モードは完 全に翻訳者に決定をさせます。翻訳者の決定作業を簡単にするための使いやすいツー ルの準備をするだけになります。
POモードでは、POファイルを直接編集してEmacsバッファの内容を変更することは 出来ません。そうすることによって、翻訳者がファイルフォーマット全体における 書式の間違いを防いだり、文字列を適切にクォートしたりすることが出来るのです。 それ以外のエラーがまだ起きる可能性はありますが、その一部に関しては Vコマンドによって実行できるバッチ検証プロセスによって検査することが 出来ます。それ以外のエラーは、翻訳者自身の判定、あるいは翻訳されたパッケー ジの(翻訳者と同じ母国語を使う)ユーザによるレポートに頼らざるを得ません。
翻訳文字列を作成するとき、あるいは機械的に検査されたりユーザから報告された エラーを修正するときには、翻訳者は翻訳文字列を修正するために以下に挙げるコ マンドの力を借りなければなりません。
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-kはC-]と同じように動作する
ようにバインドされています。または、通常通り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-msgid
を
t
に設定すれば、もしまだ翻訳が存在しない場合、オリジナルの文字列によっ
て初期化されます。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。
真剣に行われたあらゆる翻訳作業は、決定されるべきこと、そして更なる文書化の 選択について、多くの言語的困難を増大させます。これらのドキュメントは、翻訳 者が自由に作成し、削除し、修正することが出来る翻訳者コメントの形でPOファイ ル中に保存されます。これらのコメントは、翻訳者が後からこのPOファイルで作業 するときに便利なものとなるでしょう。
最初の`#'の直後に空白を伴わないコメント、例えば`#.'や`#:'は
翻訳者コメントではありません。これらはもっぱら他のgettext
ツー
ルによって作成されます。以下に述べるコマンドはコメントを追加する際に先の決
まりを変更することはなく、翻訳者に修正させることはありません。See section 2.2 POファイルのフォーマット。
以下のコマンドは、それらが適応される一般的な傾向から、翻訳を修正するコマン ドに幾分似ています。See section 5.6 翻訳の修正
これらのコマンドは翻訳文字列を修正するための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
)を使うことが出来ます。
POモードは多くの言語に通じた知識のある翻訳者の助けとなります。既に作業を完 了した翻訳の成果を、たまたま彼女が知っている別の言語に対して用いることが出 来ます。POモードはこれら他の言語への翻訳を、翻訳者の仕事への追加のコンテキ ストとして準備します。さらに、このような方法で作業することを好む翻訳者に対 しては、一度に多くの言語への翻訳を行うことを簡単にする機能があります。
補助POファイルとは、翻訳者が作業の対象としている一つのパッケージ中に 存在する、異なった母国語をターゲットとするPOファイルです。補助POファイルを 宣言し、操作するための、そして作業中のエントリのコンテキストを示すためのコ マンド群が存在します。
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.1 msgfmt
プログラムの起動6.2 GNU MOファイルのフォーマット
msgfmt
プログラムの起動
Usage: msgfmt [option] filename.po ... |
我々はSunの実装におけるこの動作はどちらかと言えばあまりスマートで ないと考えますので、デフォルトではこのモードは選択されていません。
msgid
とmsgstr
の文字列は調査、比較されます。一方の文字列が改
行で始まったり、あるいは改行で終わっているにも関わらず、もう一方がそうでな
いのは正常でないと判断されます。
同様に、文字列がprintf
系関数で使われるフォーマット文字列として出現
しているならば、両方の文字列は同じ数、そして同じ種類のの`%'書式指定子
を持っているはずです。フラグc-format
または
possible-c-format
が特別なコメント#,としてこのエントリに出現し
ているなら、チェックが実行されます。例えば、このチェックは`%.*s'に対
する`%s'や、`%d'に対する`%s'、`%d'に対する `%x'な
どを検査します。これは位置パラメータ(positional parameter)に対しても行われ
ます。
通常、xgettext
プログラムは文字列がフォーマット文字列かそうでないか
を自動的に決定します。しかし、このアルゴリズムは完全ではありません。
printf
系関数で使われていないにも関わらず文字列をフォーマット文字列
と見なすことがあり、そのような場合msgfmt
はエラーを報告することでしょ
う。逆の事例、すなわち文字列がprintf
系関数中で使用されているのに、
フォーマット文字列として認識されないといったこともあります。
この問題を解決するため、プログラマはxgettext
プログラムに対してどち
らであるかを指示することが出来ます (see section 3.4 続く文字列に関して何かを伝えること)。翻訳者は#,行
からこのフラグを削除するということを考えてはいけません。この「修正」は、次
回msgmerge
が呼び出されたときに速やかに元に戻されます。
入力ファイルが`-'の場合、標準入力から読み込みが行われます。出力が `-'であれば、出力は標準出力に書き出されます。
生成されたMOファイルのフォーマットは、後で例示する図によってもっともわかり やすく記述されています。
最初の2ワードはファイルの識別に用いられます。マジックナンバーはGNU MOファ
イルであることを常に示します。このナンバーはMOファイルを生成した計算機のバ
イトオーダーで格納されており、したがってマジックナンバーは実際には
0x950412de
と0xde120495
の二種類があります。二番目のワードは、
ファイルフォーマットの現在のリビジョンを表わしています。現在のところ、この
リビジョンは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番めの訳語 <-----------------' | | ... ... | | +------------------------------------------+ |
GNU gettext
が真にそのゴールにたどり着いたとき、平均的なユーザはある
種の驚きの喜びを感じるでしょう。スクリーンのどこにでも彼ら自身のネイティブ
ランゲージが表示されるという、奇妙な魔法の効果が現れるからです。愚直なユー
ザはそれについて全く驚くことなく、ただ単に彼らの言語が認められたと
話し合うだけで、どちらかと言えば他の点で不幸になるかもしれません。
それでは、ユーザの視点がなるべく単純になるように、全ての方法の中で人が
GNU gettext
を見るように、その魔法についてここで説明することにしましょ
う。全ての他のソフトウェアエンジニア、すなわちプログラマ、翻訳者、保守担当
者はこの魔法が実現するようにいっしょになって働きます。これは長くそして革新
的な仕事で、進捗状況についての情報は翻訳プロジェクトから入手可能です。
パッケージが配布されたとき、そこには二種類のユーザが存在します。それは、
自分や他の人が使うために配布物を受けとって展開し、コンフィグレーションし
てコンパイルとインストールを行うインストーラと、インストールされた
パッケージのプログラムを使うエンドユーザです。GNU gettext
は
インストーラとエンドユーザの両方に魔法の効果を提供します。
7.1 現在の`ABOUT-NLS'表 7.2 インストーラへの魔法 7.3 エンドユーザへの魔法
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アーカイブサイトで見つけることができま
す。
GNU gettext
を内部で全面的に使用しているパッケージは、デフォルトでは
翻訳されたメッセージが使用可能になるようにしてインストールされます。コンフィ
グレーション時に、それらのパッケージは基礎となるホストシステムが提供し使用
可能となっているcatgets
やgettext
といった関数を検出します。こ
れらのどちらかが使用可能であれば、GNU gettext
ライブラリは自動的に準
備されて使われるようになります。インストーラにはコンフィグレーション時に特
別なオプションを与えることが出来、それによってインストーラの動作を変えるこ
とができます。`./configure --with-included-gettext'コマンドはシステム
のcatgets
やgettext
をバイパスして、代わりにGNU
gettext
を使用します。`./configure --disable-nls'とすると、翻訳
メッセージを全面的に使用しないプログラムを生成します。
国際化対応されたパッケージは通常、多くの`ll.po'ファイルを持って
います。翻訳が禁止されていない限り、これらのファイルはすべてパッケージといっ
しょにインストールされます。しかし環境変数LINGUAS
が設定されている場
合は、コンフィグレーションに優先してインストールするファイルを制限します。
LINGUAS
に設定する内容は、使用する言語を示すためのスペースで区切られ
た2文字のコードのリストです。
ここで、GNU gettext
を内部的に使っているパッケージ、そしてインストー
ラがconfigure時に翻訳を無効にしなかった場合について考えてみましょう。
ユーザがするべきことは、パッケージ中のプログラムを使う前に環境変数
LANG
に適切な`ll'を設定するだけですSee section 7.1 現在の`ABOUT-NLS'表。たとえ
ば、ドイツのサイトの場合を考えてみましょう。ユーザはシェルプロンプトで
`setenv LANG de'(csh
の場合)、または`export LANG;
LANG=de'(sh
の場合)と実行するだけです。ユーザーはこれを彼らの
`.login'や`.profile'の中で行うこともできます。
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
grok8.6 プログラマの章についての一時的なメモ
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
インターフェースにおける問題点とは?!
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
を呼び出すことは、
もはや合法ではありません。
catgets
インターフェースにおける問題点とは?!
ここで、我々がお話する問題がどこにあるのかを明確にしましょう。事実、このイ
ンターフェースは現実的な方法で使うことはできますが、メッセージカタログの構
築は苦痛です。この理由はcatgests
の第三引数、つまり一意なメッセージ
IDにあります。ある単一のセット中の全てのメッセージは数値でなければなりませ
ん。おそらくあなたは、ソースコードを変更している間、ずっとこのようなリスト
を保持し続けるという問題について理解出来るでしょう。こっちで新しいメッセー
ジを追加して、あっちで一つ削除します。もちろん、この混乱を収拾するのを助け
るための多くのツールが開発されてはいますが、ある局面で使えるものは他の局面
では使えなかったりするのです。我々は、別のアプローチには全く問題がないのに、
それらはずっと扱いやすいとは言いたくありません。
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関数群の最適化
インターフェースは最低限の機能として、a) 文字列を持ってくるドメイン (domain)の選択(単一ドメインを全てのプログラムに、というのは構築と保守が難 しくなり、また恐らくは不可能ですので、現実的ではありません)、b) 選択したド メインの文字列へのアクセス、を備えていなければなりません。
これは主としてgettext
のインターフェースの説明です。このインターフェー
スはグローバルドメインを持っています。もちろんこのドメインはユーザにより選
択可能です。
char *textdomain (const char *domain_name); |
この関数によってLC_MESSAGE
カテゴリの現在のグローバルドメインのステー
タスを変更したり、問い合わせたりすることができます。引数はNUL文字で終端さ
れた文字列で、その文字列はファイル名に使うことのできるものである必要があり
ます。引数domain_nameがNULL
であった場合、この関数は現在の設定
値を返します。もし事前に値がセットされていなければ、デフォルトドメインの名
前としてmessagesが返されます。ここで、textdomain
の戻り値の型
がchar *
であるにも関らず、書き換えが許されていないことに注意して下
さい。同様に、有効性のチェックがなされないということも重要です。名前が有効
でない場合、対応する翻訳文字列が返ってこないということでそれが認識できるで
しょう。
textdomain
関数を使って設定したドメインを使うには
char *gettext (const char *msgid); |
のようにします。これは想像できる最も単純で現実的な形式です。もし現在のドメ
インで取得可能ならば、msgidを翻訳した文字列が返されます。もし取得で
きなければ、引数がそのまま返されます。引数がNULL
であったときの結果
は未定義です。
使用しているドメインは曖昧なものであるということを覚えておいていて下さい。
LC_MESSAGES
ロカールに対する現在のドメインの値が使用されます。プログ
ラム中でgettext
を呼び出す間にLC_MESSAGES
ロカールの変更を行っ
たなら、それぞれの呼び出しでは(他方と)異なったメッセージカタログが参照され
ます。
国際化されたパッケージが通常使用するもっとも単純なケースでは、
textdomain
の呼び出しが最初に一度だけ行われ、ここでドメインにユニー
クな名前、通常はパッケージ名がセットされます。それ以降のコードでは、翻訳さ
れるべき全ての文字列はgettext関数を通じて翻訳されます。これによって、パッ
ケージはあなたの使う言語をしゃべるようになります。
一つのドメインだけを使うという手法は殆んどのアプリケーションで有効に働きま
すが、二つ以上のドメインから翻訳文字列を取り出す必要があるかもしれません。
もちろん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_nameがNULL
であっ
たり、categoryが未知の値であった場合、その結果は未定義です。同様に、
この関数はこの関数ファミリの二番目に知られた実装(Solarisでの実装です)の一
部ではないということに注意するべきです。
二つめの曖昧さは、おそらくは一つ以上のドメインが同じ名前を持っているという ことです。これは必要なメッセージカタログが置かれている場所を指定することに よって解決できます。
char *bindtextdomain (const char *domain_name, const char *dir_name); |
この関数を呼び出すことにより、与えられたドメインを指定されたディレクトリに
結び付けます(ファイルそのものを結び付ける方法については後述)。システムのデ
フォルトの位置にあるファイルについては、それ以上指定する必要はありません
(単にtextdomain
を使った場合と全く同じです)。dir_nameを
NULL
にした場合は、domain_nameに結び付けられたディレクトリを返
します。domain_nameそのものがNULL
であった場合は何も起こらず、
NULL
ポインタが返されます。他の全ての関数と同じように、戻り値は変更
してはいけません!
dir_nameパラメータに与えられるパス名は問題を起こすことがありますので、
このことをしっかり覚えておいて下さい。パスは常にカレントディレクトリからの
相対位置として求められるため、プログラムがchdir
コマンドを実行したと
きは異なった結果が返されます。パスを取得する際には常に依存性と不確実性を回
避せねばなりません。
多くの異なった言語を多くの異なったパッケージに格納しなければならないので、
何らかの方法で言語やパッケージに関する情報をメッセージカタログファイルに追
加する必要があります。UNIX環境で通常使われている方法は、ファイル名にエンコー
ディングを含めるというものです。ここでも同様にしています。
bindtextdomain
の第二引数(あるいはデフォルトのディレクトリ)で与えら
れたディレクトリ名には、以下に記述するようにロカールやドメイン名の値や名前
が後ろに続いています。
dir_name/locale/LC_category/domain_name.mo |
dir_nameの既定値はシステムに依存します。GNUライブラリ、そしてGNUの方 針を頑なに信奉するパッケージでの既定値は
/usr/local/share/locale |
です。
localeは、LC_category
をいう名前を持つロカールの値です。
gettext
とdgettext
にとって、このロカールは常に
LC_MESSAGES
です。dcgettext
は三番目の引数によってロカールを指
定します(2)。
(3)
この辺りで、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'で定義されており、この変数は新しいメッセージカタログが
ロードされた時点で変更されます。
以下に挙げる議論はおそらく染められた小さなビット(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(ファイル)をこのように使います。(o'は8859-2 oachteを意味し、これはどちらかと言えばaogonekに似たokreskaです)
1 plik 2,3,4 pliki 5-21 pliko'w 22-24 pliki 25-31 pliko'w
可能なアプローチは、おそらく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])); } |
この方法は、数値の範囲が狭いときのみ有効であるということは明らかでしょう。
バージョン0.9.4以降、libintl.h
は自己包括(self-contained)でなければ
ならなくなっています。すなわち、追加の関数を用意することなくこれをあなた自
身のプログラムで使用できます。`Makefile'はヘッダとライブラリを、
$(prefix)
で指定されたディレクトリに格納します。
HP-UXシステムにおいては、上記に関する唯一の例外が発生します。Cライブラリが
alloca
関数を含んでいないのです(そしてHPのコンパイラはこれをインライ
ンとして展開しません)。しかしそれはこのバカなシステムのためだけにライブラ
リ全体を書き直すといったことを意味しません。代わりに、libintl.a
を使
用する全てのパッケージがalloca
関数をインクルードします。
gettext
grok
ソースコードを読むことは、GNU gettext
の機能を完全に活用するための助
けになるでしょう。しかし、(時として込み入った内容の)コードを読むために時間
を費やすことを望まない人々のために、幾つかのコメントを挙げておきます。
対話的なプログラムにおいては、使用する言語を実行時に尋ねたほうが有用である
ことがあります。これを理解するためには、関数が使用する言語をどのように決定
しているのかを知る必要があります。ここに示す方法はGNUによる
gettext
関数の実装においてのみ正しいものです。catgets
関数やシ
ステム付属のCライブラリによるgettext
関数については当てはまらないで
しょう。もちろん、メッセージハンドリングにGNU gettext
ライブラリを使
用しているGNU Cライブラリは例外です。
dcgettext
関数は呼出しごとに、環境変数の中で最高のプライオリティを持
つものを探し出して使用します。プライオリティは以下のリストで示されます。プ
ライオリティは下にいくにつれて低くなります。
LANGUAGE
LC_ALL
LC_xxx
, 選択されたロカールによる
LANG
その後、検索された値を用いてパスが設定され、可能であれば翻訳ファイルがロー ドされます。
「今」とは、LANGUAGE
が変更されたときです。上で説明した過程に従い、
この変数の新しい値はdcgettext
関数が呼び出された時点で決定されます。
これは(おそらく)異なったメッセージカタログがロードされることを意味します。
即ち、使用する言語が変更されるのです。
しかし、これは一つの小さなフックに過ぎません。 gcc 2.7.0以上のコードでは幾
分の最適化が図られています。この最適化は通常、dcgettext
関数の呼び出
しによって新しいカタログがロードされる前に行われます。しかし、もし
dcgettext
が呼び出されなければ、プログラムもまたLANGUAGE
変数
の値が変更されたことを知ることができないでしょう(see section 8.2.4 gettext関数群の最適化)。この解決方法は非常に簡単です。以下のコードを言語変更関数の前に
置けばよいのです。
/* 言語の変更 */ setenv ("LANGUAGE", "fr", 1); /* 変更を知らせる */ { extern int _nl_msg_cat_cntr; ++_nl_msg_cat_cntr; } |
変数_nl_msg_cat_cntr
は`loadmsgcat.c'中で定義されています。プロ
グラマは、長時間動作し、実行時にユーザに言語を選択する余地を与えるようなプ
ログラムの開発中に、このような構造の必要性を感じることでしょう。非対話的な
プログラム(あらゆる小さなUNIXツールのような)は決してこのようなことを必要と
しません。
8.6.1 一時的な情報 - 二つの実装 8.6.2 一時的な情報 - catgets
について8.6.3 一時的な情報 - なぜ一つの実装なのか 8.6.4 一時的な情報 - ノート
言語に依存せずにメッセージを扱う二つの手法があります。一つはX/Openの
catgets
によるものであり、もう一つはUniforumのgettext
によるも
のです。catgets
による方法では、整数によってメッセージを指定します。
gettext
による方法では、英語のメッセージによって指定します。。
catgets
による方法は長く使われ、多くのベンダでサポートされています。
gettext
による方法ははSunでサポートされていて、COSEマルチベンダイニ
シアティブ(COSE multivendor initiative)がサポートするようです。どちらも
POSIX標準とはなりませんでした。POSIX.1 委員会では、この件に関して様々な見
解の相違がありました。
二つの手法のいずれもPOSIX標準ではありません。gettext
と
catgets
(XPG)ルーチンのいずれを標準として採用するかについて、
POSIX.1 委員会ではは様々な議論がなされました。委員会の終盤に至っても何らの
合意は得られず、結局メッセージングシステムは標準規格には含まれませんでした。
私はXPG3メッセージングインターフェースに関する追記を標準に付与するのは有益
であると信じていますし"...メッセージングシステムの実例は既に実装され
ているのです..."
委員会は、ある一つのインターフェースの実装を使うのが良いということをどの場 所でも言わないように非常に注意していました。この話題に関するこれ以上の情報 については、国際化プログラミングFAQ(Programming for Internationalization FAQ)を参照して下さい。
catgets
について
catgets
を基盤として使用することに関する討議の末期には、幾つかの議論
がありました。その議論の両側を提示することは大切だと思いますし、これから、
私はちょっとしたことに対して「悪魔の弁護士」となってみることにします。
catgets
はもっと良くデザイン出来たでだろうということは否定しません。
その実装には既に指摘したような制限が少なからずあります。
しかしながら、その一貫性と標準化の度合いについては 申し分ありません。 UNIXソフトウェアを書くときに繰り返し発生する 問題とは、UNIXプラットフォーム間での移植性に関する問題です。それは全ての UNIXベンダがオペレーティングシステム上を調べて改良する部分を見つけたような ものです。疑いもなく、これらの修正は革新的なものであり、現実の問題を解決す るものです。しかしながら、ソフトウェアベンダがこれらの変更を多くのプラット フォームで行いつづけるには、多くの労力が必要です。
そしてこれは各UNIXベンダが自社のシステムを標準化することを促進します。 Spec1170に準拠するためにです。、各主要UNIXベンダはこの標準化のために委員会 を設けました。そして全てのUNIXソフトウェア開発者はこの標準に従ってソフトウェ アを作成し、異なるプラットフォームへソフトウェアを導入する際には (autoconfを使うことなく)リコンパイルするだけで済むようになる日を心待ちにし ているのです。
私の理解しているところでは、Spec1170はX/Open Portability Guidelinesのバー
ジョン4(XPG4)に基づいたものです。catgets
とその眷属がXPG4で定義され
ているので、私はcatgets
がSpec1170の一部であり、それがすべてのUNIXシ
ステムの標準的なコンポーネントになることを信じています。
メッセージカタログにアクセスするために二つの異なるシステムをインストールす
ることは不経済なことのように思えます。我々がcatgets
の不足しているも
のを改善したいと思ったのなら、なぜ新しいシステムを実装するのではなく、
catgets
を(互換性を保ちながら)拡張しようとしないのでしょうか? いずれ
にせよ我々は、メッセージカタログにアクセスするためのシステムをオペレーティ
ングシステムに対して二つインストールすることになるでしょう。一つはGNUソフ
トウェアのためルーチン群であり、もう一つはその他全てのソフトウェアのための
ルーチン群(catgets)です。傲慢でしょうか?
カタログにアクセスする別のシステムが実装されたと仮定してみましょう。我々が
お奨めするのはどちらでしょうか? 少なくともLinuxシステムに対しては、我々は
可能な限り多くのソフトウェア開発者を呼び込む必要があります。そのため、我々
はソフトウェア開発者が彼らのソフトウェアを移植しやすいようにする必要があり
ます。そしてそれはcatgets
をサポートすることを意味します。我々は
glocale
コードをGNU libc
中に実装するでしょうが、GNU
libc
には別のメッセージカタログに対するアクセス方法を同じように取り
込まなければいけないということなのでしょうか? そして、glocale
と非
catgets
ルーチンを組み合わせて使おうとする人達に関してはどうでしょう
か? ソフトウェア開発者が彼らのソフトウェアを他のプラットフォームに移植する
際、彼らはそのソフトウェアに単にglocale
を含めるだけでなく、フロント
エンド(glocale
)コードと、バックエンド(非catgets
アクセスルー
チン)コードを付け加えようとするでしょう。
しかしメッセージカタログのサポートは氷山の一角に過ぎません。他のロカールカ
テゴリのデータはどうでしょうか。それらもまた、多くの相違点を持っています。
我々はそれに対処することを諦めて、重複したルーチン群を別々に開発せねばなら
ないのでしょうか(glocale
をメッセージカタログサポート以上のものにす
べきなのでしょうか)?
UNIX上の改良可能な多くの部分と同じように、我々は将来に向けて改良を加えつつ も、過去のものに対する互換性を落とさないようにしていました。
多くの実装が最終形式からかけ離れたものであったため、X/Openが標準形式を承認 するのは非常に遅くなりました。私の使っている両方のシステム(古いLinux catgetsとUltrix-4)には奇妙なバリエーションがあります。
最後の変更を加えた後、私はGNU/Linux libc
のgettext
関数群を作
成するために時間を割かねばなりませんでした。従って、将来的にはSolarisが
gettextを備えた唯一のシステムであるということはなくなります。
9.1 イントロダクション0 9.2 イントロダクション1 9.3 議論 9.4 組織 9.5 情報の流れ
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'に作業するこ との出来る言語を明記してメールを送って下さい。
現在公式に、GNUは国際化しつつあります! 以下は1995年1月の GNU Bulletinで述 べられた声明です。
一握りのGNUパッケージには幾つかの言語に対するメッセージの翻訳が適用・提供 されています。翻訳チームは組織化され始めており、これらのパッケージを起点と して使っています。しかしまだまだ多くのパッケージがあり、多くの言語について はボランティアの翻訳者がいません。もし翻訳チームでボランティアとして作業し たいと思うのでしたら、`gnu-translation@prep.ai.mit.edu'に作業するこ との出来る言語を明記してメールを送って下さい。
本ドキュメントはその過程に興味を持ったり、貢献したいと考えている人々が持つ 多くの疑問に答えます。願わくばざっと目を通し、GNUの国際化に対するこの集合 的努力から産み出される大量のメールの幾ばくかでもを担当して下さい。
広く共用される多くのフリーソフトウェアのプログラミングは英語で行われてい ます。そして現在のところ、英語はGNUプロジェクトに協力する国家的コミュニ ティ間での主要なコミュニケーション言語として使われています。このドキュメ ントでさえも英語で書かれています。これは当面変わらないでしょう。
しかしながら、多くのソフトウェアで自国語や自国の習慣を用いたいという、国家 的コミュニティからの強い欲求があります。また、GNUソフトウェアをそのように するための努力が現在も行われています。この試みは今までのところプリテスタか らの熱心な反応の向上によって動かされており、我々はGNUの国際化は成功すると 信じています。
このドキュメントに対する内容の明確化、追加、訂正に関する提案については、 `gnu-translation@prep.ai.mit.edu'までメールを送って下さい。
この国際化の効果を目の当たりにして、幾人かのユーザが彼らの考えを表明してい ます。紹介され議論されたこれらの疑問の幾つかをここに挙げてみましょう。
幾つかの言語は多くの人々によって話されていないため、その言語を話す人々はフ リーソフトウェアパッケージの当該言語版に対する必要性はあまりないと考えてい ます。更に、幾つかの国にいるコンピュータの中にいる多くの人々は一般 的に英語版ソフトウェアのほうを好むようです。
一方で、人々は自分達の言語を非常に好きですし、彼らのお気に入りのフリーソフ トウェアが彼らの母国語を喋ることが出来るように努力します。彼らは個人的な楽 しみのためにそれを行います。そしてどのくらいの人間がその作業によって便益を 得るかなどといったことは考えません。
ある種の誤ったプロパガンダのせいか、一部のユーザは自身の言語を押し出すこと について臆病になっています。ある人は、ネットワークの向こう側にはその言語を うるさくせがむユーザがいるに違いないと考えています。
しかしあらゆる言語には地域化される価値があります。なぜなら、その言語が大切 で敬愛されるものであると考える人々がその言語の向こうにいるからです。
誰もがメッセージを理解出来るためには、正しい翻訳を見つけ出すことがもっとも 大きな問題となります。翻訳は通常、少し変なものなのです。一部の人々は、「ど ちらかといえば押しが強く、嫌でときどき滑稽な」彼らの言語に対する翻訳を行う ことが出来る程度には英語を扱うことが出来ます。フランス語を話す人間として、 私は韓国または台湾において商品の取扱説明書を貧弱なフランス語へと翻訳した経 験があります。...
我々はときどきある種の国家的計算機文化を作り上げる必要があるというのは事実 です。そして、その作業は彼らの母国語によって繋がっている多くの人間の協調作 業なしに簡単に出来ることではありません。翻訳は彼ら自身の言語を知りそして愛 する人々によってより良く行われ、より良い結果を得るという点において一緒に作 業されるものなのです。
何人かの人々は、彼らが彼らのプログラムをフリーにしたくない場合、又は別の種
類の自由を与えたい場合に、GNU gettext
を使うことによって彼らのパッケー
ジをGNU一般公有許諾書(GNU General Public License)の保護の元で配布する必要
があるのではないかと思案します。これに対する単純な答えは「はい」です。
パッケージ中の僅かな地域化された文字列のマーキング、又は国際化のための条件 つきの数行の包含はGPLのコードを含んでいません。しかしながら、地域化ルーチ ンそれ自身はGPLの元にあり、もしパッケージの残りの部分が地域化ルーチンと共 に配布されるのであれば、残りの部分もGPLの元で配布されることになるでしょう。 私は、問題となるものとして、地域化ルーチンそれ自身を準備しないが、地域化を 準備したパッケージを、エンドインストーラにアセンブルすることの重荷を負わせ ることによって回避することができると仮定します。
大きな尺度で見れば、真の解決方法は有志が参加できるようなある種の正しく厳密 な集合を組織化することでしょう。私は、最近このアイディアについて幾つかの考 察を行い、幾つかの微妙なポイントがあるであろうことを認識しています。私は、 そのようなプロジェクトを開始するために、Richard Stallmanに連絡することを考 えましたが、まず最初に我々の間でアイディアを揺り落とすことが良いだろうと感じ ました。おそらく、Linux Internationalは既にこの分野における幾らかの経験、 または、有志の作業のオーケストラのようなものを持っています。あらゆる場合に、 思考のための食物を!
我々は早々に何らかの方法で何かをセットアップせねばならないと考えます。同じ 言語に対する作業のインターロックと重複を避けるという点で、それは多くの言語 のコントリビュータを助けるでしょう。そして、更にそれらの言語(大部分の言語 では技術的な英語の翻訳について独特な多くの問題点があります)についての独特 な問題を共に解決するように連絡が取れるようにします。スウェーデンのコントリ ビュータはこれらの問題点を認め、そして私はフランス語においてのそれらの問題 点に相当に気が付いています。
確かにこれは技術的問題ではありません、しかし我々は、コントリビュータ、及び 管理者間の国家チーム層のインターフェースに関わらず、ロカールコントリビュー タの努力が最大限に有益になるように管理するべきです。
翻訳プロジェクトは言語コーディネータを統合するためにある準備を必要とします。
一度この作業が始められたなら、発展中のプログラムのローカライズは、確かにフ
リーソフトウェアコミュニティにおいて永久の、そして、連続的な動きになるでしょ
う。 GNU gettext
が公式の現実になる前に、最小限の準備が完了し、そし
てテストされているべきです。電子メールアドレス
`translation@iro.umontreal.ca'は、これらの話題に基づくボランティア、
及び、一般的な電子メールから申し出を受けるための準備でした。このアドレスは、
翻訳プロジェクトのコーディネータに届きます。
9.4.1 中央による調整 9.4.2 国家チーム 9.4.3 メーリングリスト
そのことについて考えるよりも更に早く、GNUは誰かがそれらのグループを組織化 し調整する方法を準備する必要があると私もまた考えます。ある種のグループのグ ループです。GNUは直ちに共同で働いているボランティアの小さなグループにこの タスクを委託することが良いだろうと、私は考えています。 おそらく、この国家 委員会的なグループのリストは`gnu.announce'において公表され得ます。
コーディネータとしての私の役割は単に、Ulrichをフリーソフトウェアの地域化に 興味を持っているドイツ語を話すボランティアに紹介すること、そして国家的グルー プの準備が出来るまでの国家的登録機関のメンテナンス中に、国家的グループの最 初の組織化を助けることです。実際、コーディネータは、ボランティアが国家チー ム(言語または国(局地的言語)について1人のコーディネータを選択するべきです) を作成するために相互と連絡を取りやすくせねばなりません。これが正しく行われ たならば、コーディネーションは不可抗力的作業を除いて便利なものとなり、代理 人に時間を任せることが出来るようになります。
私は、我々が個々の言語のための有志のコーディネータ/エディタを捜すことを提 案します。これらの人々は彼ら自身の言語のために、様々なプログラムの翻訳ファ イルを探し出し、そして、語法に対する高度で一定の標準を保証することになるで しょう。
今までの他の人々との間の私の現在の経験によれば、地域化を実現する人々はこの プロセスに対して非常に熱心であり、彼らは自分自身が地域化するプログラムより も地域化のプロセスにほうに興味を持ち、それだけでなく多くのプログラムを地域 化したいと思うものです。この事実は、各言語のためのコーディネータ/エディタ を持つことは良いアイディアであることを確信させます。
我々は、問題となる言語において明瞭かつ簡潔な文章を書く際、適任となる人物を 選択する必要があります。これは難しい作業です---我々は、自分自身でそれをチェッ クすることができません。従って、我々は数人の人間対してに互いの記述を判断す るように要請し、そして最適任者を選択する必要があります。
私は私のプレリリースを20人から30人の人々に発表ましたが、そのプレリリースが 既に生み出した全ての議論をあなたは信じないでしょう。私は、真に、公式に、世 界中でこの作業が開始されるときに起こるであろうことを想像すると身震いがしま す。例えば、相互に反論しあう二人のチェコスロヴァキアのユーザーの間を仲裁す るのは私なのでしょうか?
私がこれらの公式化について判断することが出来ないように、あなたのドイツ語が 私のフランス語よりはるかに良いとは限らないと推測します。私が提案するものは、 各言語に対してPOファイルをメンテナンスしその変更を判定する人々のグループを 置くということです。そのような人々のグループがどのように行動するかについて、 グループ間には文化的な相違点があると考えます。幾つかのグループはは緩い方法 を採用し、簡単にコンセンサスの一致に達し、グループ中の誰もが保守者に関わる ことができます。一方は死ぬまで戦い、重い管理を国家の標準にまで組織化し、厳 密なチャネルを使用するでしょう。
ドイツのチームは良い例を出しています。直ちに、彼らはおそらくお互いの翻訳を 訂正する半数の人々と言語上の論点について議論する半ダースの人々です。私は全 ての名前を知っているわけではありません。Ulrich Drepperはドイツのチームのコー ディネートを担当しています。彼は私のプレテストのリストの購読を申し込みまし た。従って、私は彼に対して、連絡されるリリースの詳細について警告する必要は 特にありません。
各言語を担当する翻訳チームを得るためには、それはよいアイディアだと思います。 翻訳を更に良く首尾一貫した状態にするでしょう。
9.4.2.1 サブカルチャー 9.4.2.2 組織化へのアイディア
フランス語を例に取ってみましょう。コンピュータの世界では、意味が異なる語彙 を持つ幾つかのサブカルチャーがあります。組織化された方法でこの問題を提起す ることなしにあちこちでボランティアを選んでいると、プロジェクトにはすぐに国 際化されたプログラムのごちゃ混ぜ状態が発生します。そしてことによると、実際 にこの問題を気にする人々の間で終りなき口論が始まるでしょう。
国際化されたプログラムをフランス語へ地域化する過程において、ある種の統一を
保つことは難しい(そしてデリケートな)仕事です。フランス人のラテンな人柄
(:-)を知っていても、もし我々がこのことを間違った方法で捉えれば、我々はどこ
とも知れぬ場所で終わってしまうか、多くのエネルギーを無駄にしてしまうことで
しょう。おそらく我々は、gettext
が公式に発表される前に真剣に
この問題に取り組まなければならないでしょう。
私は、公式リリース後に次の大きな変更があると考えています。どうか、私が短い GPLメッセージのドイツ語翻訳を用いることに注目してください。我々は、フリー ソフトウェアコミュニティにおける真の地域化が消え去ってしまう前に2、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において各国のチー ムのためのメーリングリストを提供することは確かに有益でしょう。そうです、私 にどのようにメーリングリストを作成し扱えばよいかを説明して下さい。
我々は一時的なメーリングリストを、人々を組織化しやすいように国ごとに一つづ つ作らねばなりません。なぜ一時的か、なぜなら一度再構成されたなら、各国のボ ランティアは彼らのリストへと戻ってきて、そして自分達が望むように管 理するだろうからです。このことについては、個々のチームは自分達の国の中から 自分達のリストを動かすだろうと思います。全てのチームが購読することの出来る、 中央のメーリングリストも作る必要があるでしょう。
パッケージが最終的にリリースされた後、このメッセージについての幾つかの議論 があることでしょう。今、人々が更に良い幾つかのメッセージを提案したとしたら、 あなたはどうしますか? ジム、私が提供する1ダース近い地域化されたプログラム と同様、どうか直ちにそれらのメッセージに注目して下さい。私は翻訳とそれらに 関する調整の両方を受け取るのです。
私が事前にテストするものを一つ置いたならば、Ulrichはその告知を受け取り、そ してそれを最後に修正するドイツ語のチームに渡します。そして彼は保守者 として私に翻訳ファイルを引き渡します。私が保守していないフリーのパッケー ジについては何も聞きません。私が思うに、全ての翻訳プロジェクトにおいてこの スキームが作られるでしょう。セキュリティに関わる理由のために、おそらく Ulrich(実際の国家的コーディネータ)は時折翻訳プロジェクト(Jim、私、又は Lenの新人)によって保持される中央のレジストリをアップデートすべきです。
私は小さなGNUパッケージは一週間に一つずつ、より大きなパッケージは数週間か 数ヵ月をかけるという責務を私自身に課し、12月か1月には私はにGNUの全パッケー ジを国際化する準備を積極的に整えていました。しかし、それはそのようには動き ません。私は最初に、私が責任を持つ全てのことを行いました。私は他の保守者の 幾らかの伝道作業に対して何も持っていませんでした。しかし私もまた多くのエネ ルギーを失いました---同じ議論を繰り返します。
そして、最初に地域化されたパッケージがリリースされるとき、我々は、醜悪な翻 訳:- )についての多くの反応を得るでことしょう。確かに、そして我々は事前に、 パッケージ保守者と国家チームの間の情報の流れを制御することに関する良いアイ ディアを持つ必要があります。
どうかどこかに各POファイルの迅速なヒストリを保存し始めて下さい。コメントを 認めることによってファイルフォーマットがいずれ変更されるであろうことを私は 知っています。各ファイルがログのようなもの、そしてコメントや不平の申し立て、 又はその他の貢献をしたいと思う人々へのリファレンスを持つほうがよいでしょう。 私は高速でフレキシブルなフォーマットに関する申し立てをしましたが、しかしそ れはまだGNUの意思決定者によって受け入れられていません。私がこれについてよ り多くの情報を得たなら、このことについてお話しすることになるでしょう。
パッケージの保守担当者は多くの責任を持ちます。一つは多くのプラットホームで パッケージを簡単にインストール出来るようにすること、そして既に述べた魔法 (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 作成するか変更しなければならないファイル
幾つかのフリーソフトウェアパッケージは一つのディレクトリ中に展開される
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
をフラットな配布物に対して適応させる経験を今後積んだなら、フ
ラットな構造を処理する方法について新たに記述することにします。
パッケージにGNU gettext
を適用させる前に、やっておかなければならない
幾つかの作業があります。これらの作業は、この章での注意を逐一記述せずに済ま
せるための一種の一般法則です。それらの作業について記述します。
m4
、GNU AutoconfそしてGNU gettext
の最新のバージョンが既
にあなたのサイトにインストールことを確認します。もしインストールされていな
いならば、最初にそれらをインストールして下さい。これらが全てインストールさ
れているにしても、GNU Autoconfが構成される前にGNU m4
が完全に
インストールされねばならないことに気をつけて下さい。
automake
パッケージは、パッケージ管理者の作業がより簡単になるように
設計・実装されました。現在、GNU gettext
はこのツールを使っており、
`intl/'と`po/'にある`Makefile'はautomake
及びプロジェ
クト中にある`libintl'を使用するために必要な全てのゴールについて知って
います
これら4つのパッケージは保守担当者だけが必要とします。パッケージのインストー
ラやエンドユーザには、メッセージが適切に変換されているパッケージをインストー
ルし動作させるために、GNU m4
、GNU Autoconf、GNU gettext
そし
てautomake
が本当に必要だというわけではありません。しかし、もしパッ
ケージ中に国際化されたシェルスクリプトが含まれているなら話は変わってきます。
もしエンドユーザがシェルスクリプトのメッセージを翻訳して使いたいと思う場合
は、GNU gettext
がユーザのサイトにインストールされている必要がありま
す。
保守担当者がPOファイルの提供に対しどのように理想的に振舞うべきかについて、 少し説明する必要があるでしょう。保守担当者としての役割は、翻訳プロジェクト の適切な翻訳チームの代表者(疑問がある場合は提出物を `translation@iro.umontreal.ca'に転送します)としての提供元を承認する ことです。POファイルの内容が激しく壊れていないこと、正常なインストールを妨 げないことが保証出来たら、最後はただ単にこれらのPOファイルを配布物の `po/'ディレクトリに入れるだけです。
保守担当者として、あなたは翻訳が適切か完全かというようなチェックの報告につ いて責任を負う必要はなく、言語上の問題に没頭することは避けなければなりませ ん。翻訳チームは自ら動き、そして翻訳プロジェクトに対する言語の選択について 充分に責任を負っています。翻訳チームは保守担当者によって動かされているので はないということを心に止めておかなければなりません。保守担当者は言 語上の問題に関わるユーザとのコミュニケーションや、ユーザからの報告の全てを 注意深く転送することによって、適切な翻訳チームを助けることが出来ます。また、 それらをいかにして翻訳チームに届けるか、あるいはどのようにして翻訳チームに 加わればよいかをユーザに対して説明することも出来ます。もっとも単純な方法は、 ユーザに`ABOUT-NLS'ファイルを送ることでしょう。
保守担当者は決して翻訳チームを無視してPOファイルのバグレポートを適 用してはいけません。もし何人かの翻訳者が彼女のチームの中で話の確信を掴むこ とが難しいというのであれば、彼女は直に保守担当者と翻訳を取り決めてもよいで しょう。しかし通常、翻訳チームはチーム自身でそれらの問題を解決するべきです。 保守担当者が翻訳チームに関して本当に問題があると考えているとしても、保守担 当者は決してチームの問題を解決してはならないのです。
gettextize
プログラムの起動
GNU gettext
を使って国際化された全てのパッケージには、幾つかのファイ
ルが常にそして同じように必要です。扱いやすいように、gettextize
プロ
グラムはこれらのファイルをパッケージ中に正しく置きます。このプログラムは以
下の書式を取ります。
gettextize [ option... ] [ directory ] |
以下のオプションが使用可能です。
gettext
コードを使用できますが、保守担当者がソースに適用する幾つかの
メカニズムを妨害するかもしれません。gettextize
を実行するのは簡単な
ことですので、コピーを使うことに関する問題が発生するべきではありません。
directoryが与えられていれば、それはGNU gettext
が使われるパッ
ケージの最上位のディレクトリとなります。与えられていなければ、カレントディ
レクトリがそのパッケージの最上位ディレクトリであると仮定されます。
gettextize
プログラムは以下のファイルを用意します。--force
(-f
)オプションが指定されていない限り、存在するファイルが置き換えら
れることはありません。
gettextize
が準備する`ABOUT-NLS'ファイルよりも新
しいファイルをパッケージに入れたいと考えるかもしれません。最新の
`ABOUT-NLS'ファイルは殆んどのGNUアーカイブサイトから手に入れることが
できます。
gettext
配布パッケージ中の
`po/Makefile.in.in'ファイルが格納されているだけです(ファイル名に二つ
の.inがついていることに注意して下さい)。もし`po/'ディレクトリが既に存
在するのであれば、poディレクトリとディレクトリ中のファイルはそのままにして、
`Makefile.in.in'のみが上書きされます。
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'は全てのパッ
ケージにおいて同じであり得るように設計されています。
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'
`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'ファイルからの相対位置ではなく、パッケージの最 上位ディレクトリからの相対位置で記述します。
宣言が行われた例を示します。
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'となります)。
利用可能な言語は、空白で区切られた引用文字列としてALL_LINGUAS
に一行
で定義します。例えばこのように。
ALL_LINGUAS="de fr" |
この例は、ドイツ語とフランス語がパッケージでサポートされるべく、この二つの
言語のPOファイルが使用可能なことを表しています。インストール時のインストー
ル言語の設定について更なる制限をかけたいとしても、それは
`configure.in'中のALL_LINGUAS
を修正することによって行うべきで
はありません。その代わりに環境変数LINGUAS
を使用します
(see section 7.2 インストーラへの魔法)。
これは、国際化サポートを実現するためのメインのm4
マクロです。
`configure.in'に次の行を追加して下さい。
AM_GNU_GETTEXT |
これによってチェックやアクションのためにconfigureに長い時間がかかるように なりますが、この呼出そのものは実に簡単です。
`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'であるためです。
パッケージ中に`aclocal.m4'ファイルがない場合、もっとも簡単な解決策は、
GNU gettext
から`aclocal.m4'をコピーすることです。しかし厳密に
は、必要となるのはマクロAM_LC_MESSAGES
、AM_WITH_NLS
、
AM_GNU_GETTEXT
、AM_PATH_PROG_WITH_TEST
(AM_WITH_NLS
に
よって呼びだされる)だけです。従って、エディタを使うことによって必要でない
マクロを取り除く必要があるかもしれません。
既に`aclocal.m4'ファイルが存在するならば、前述のマクロをあなたの
`aclocal.m4'にマージしなければならないでしょう。もし以前のリリースの
gettext
からアップグレードしているのならば、通常、GNU
gettext
のリリースの間には小さな変更が含まれているため、おそらく前述
のマクロを置き換える必要があるであろうことに注意して下さい。それら
の内容は、変わったシステムに対して我々が対応するために変更されるかもしれま
せん。
これらのマクロは国際化をサポートする関数とその関連情報をチェックします。安
定化したなら、おそらくこれらのマクロは標準のAutoconfのセットに組み込まれる
ことでしょう。なぜなら、このm4
コードはgettext
を使用する全て
のプロジェクトで同じものになると思われるからです。
配布物中に`acconfig.h'が含まれていない場合、もっとも簡単な解決策は
GNU gettext
から`acconfig.h'をコピーすることです。しかし厳密に
は、必要となるのはENABLE_NLS
、HAVE_CATGETS
、
HAVE_GETTEXT
、HAVE_LC_MESSAGES
、HAVE_STPCPY
、
PACKAGE
、VERSION
が含まれた行とコメントだけです。従って、エディ
タを使うことによって必要としない部分を全て取り除く必要があるかもしれません。
既に`acconfig.h'ファイルが存在するなら、前述の定義をあなたの
`acconfig.h'にマージする必要があります。
トップレベルに存在するの`Makefile.in'ファイルに対する幾つかの修正点に ついて述べます。
PACKAGE = @PACKAGE@ VERSION = @VERSION@ |
DISTFILES
定義に`ABOUT-NLS'ファイルを追加して下さい。
これによってこのファイルは配布対象となります。
automakeから生成されるか、或いはGNUコーディング規約に注意深く従った手書き のMakefileを使用している場合、新しいサブディレクトリに対して実行されるゴー ルとして、`installdirs'、`install'、`uninstall'、 `clean'、`distclean'を含む必要があります。
ここに厳密な処理の順番の例を示します。この例では後ほど`dist:'ゴールで
使えるように、Makefile.in
でSUBDIRS
をもまた定義しています。
SUBDIRS = doc lib @INTLSUB@ src @POSUB@ |
これが、あなたのパッケージに対して適用せなければならないことです。
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) |
メインの`Makefile.in'に対して行われた幾つかの修正は、あなたのパッケー ジソース(ここでは`src/'サブディレクトリに置かれていると仮定される)の `Makefile.in'に対しても必要になるでしょう。`src/Makefile.in'に必 要となる全ての修正を示します。
PACKAGE = @PACKAGE@ VERSION = @VERSION@ |
top_srcdir
が定義されることを保証しな
ければなりません。これはcpp
インクルードファイルに貢献するでしょう。
この行を追加するだけです。
top_srcdir = @top_srcdir@ |
subdir
として`src'もまた定義したいと考えるでしょう。後から述べ
る`dist:'ゴールに関する項では、次の定義がなされていると仮定します。
subdir = src |
@INTLLIBS@
が使用されるように
しなければなりません。それをLIBS
に追加してしまうのが簡単です。この
ようにします。
LIBS = @INTLLIBS@ @LIBS@ |
GNU gettext
によって国際化された多くのパッケージには、ビルド用の補助
関数群が含まれるライブラリを置くための`lib/'ディレクトリがあるでしょ
う(少なくとも、GNU gettext
ライブラリ自身が必要とする幾つかの関数が
必要になります)。しかし`lib/'中の幾つかの関数は、当然ながら翻訳される
べきメッセージをもまた含んでいます。この問題を解決するためには、補助ライブ
ラリ(`libsupport.a'としましょう)を前述の例における
@INTLLIBS@
と@LIBS@
の間に置くだけでは不十分です。その代り
に、このようにします。
LIBS = ../lib/libsupport.a @INTLLIBS@ ../lib/libsupport.a @LIBS@ |
distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) dist: Makefile $(DISTFILES) for file in $(DISTFILES); do \ ln $$file $(distdir) 2>/dev/null || cp -p $$file $(distdir); \ done |
我々はこのGNU gettext
マニュアルを翻訳プロジェクトの歴史でもって
締めくくろうと思います。最後にネイティブランゲージサポートについて読んだ
り、調べたりしたい人のために幾つかのポインタを示します。
11.1 GNU gettext
の歴史11.2 参考文献
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マニュアルも寄贈しています。
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/ |
ISO 639は多くの国家に対して2文字のコードを規定しています。翻訳プロジェ クトが国家や言語に対して使用している省略形には、この標準が採用されています。
[Top] | [Contents] | [Index] | [ ? ] |
この制限はGNU gettext
によって強制され
たものではなく、Solarisのmsgfmt
の実装から来ています。
Ultrixなどの一部のシステムではLC_MESSAGES
を持って
いなません。ここで我々はこのために恣意的な値(arbitrary value)を使います。
システムがsetlocale
をサポートしていないとき、ロカールの値
を設定する動作は環境変数を参照することによりシミュレートされます。
[Top] | [Contents] | [Index] | [ ? ] |
gettext
の目的
gettext
の概要
gettext
のインストールを完了する
gettext
の処理をトリガする
xgettext
プログラムの起動
msgmerge
プログラムの起動
msgfmt
プログラムの起動
catgets
について
catgets
インターフェースにおける問題点とは?!
gettext
について
gettext
grok
catgets
について
gettextize
プログラムの起動
gettext
の歴史
[Top] | [Contents] | [Index] | [ ? ] |
1. イントロダクション
2. POファイルとPOモードの基本
3. プログラムソースの準備
4. 最初のPOファイルの準備
5. 既存のPOファイルの更新
6. MOファイルの作成
7. ユーザとしての視点
8. プログラマとしての視点
9. 翻訳者としての視点
10. 保守担当者としての視点
11. 結論
A. 国家コード
[Top] | [Contents] | [Index] | [ ? ] |
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 |