gettext —多言語の国際化サービス
ソースコード: :source: `Lib / gettext.py`
gettext モジュールは、Pythonモジュールおよびアプリケーションに国際化(I18N)およびローカリゼーション(L10N)サービスを提供します。 これは、GNU gettext メッセージカタログAPIと、Pythonファイルにより適している可能性のある高レベルのクラスベースAPIの両方をサポートします。 以下で説明するインターフェースを使用すると、モジュールとアプリケーションのメッセージを1つの自然言語で記述し、さまざまな自然言語で実行するための翻訳済みメッセージのカタログを提供できます。
Pythonモジュールとアプリケーションをローカライズするためのヒントもいくつか示されています。
GNU gettext API
gettext モジュールは、GNU gettext APIと非常によく似た次のAPIを定義します。 このAPIを使用すると、アプリケーション全体の翻訳にグローバルに影響します。 多くの場合、これは、アプリケーションが単一言語であり、ユーザーのロケールに応じて言語を選択する場合に必要なものです。 Pythonモジュールをローカライズする場合、またはアプリケーションで言語をオンザフライで切り替える必要がある場合は、代わりにクラスベースのAPIを使用することをお勧めします。
- gettext.bindtextdomain(domain, localedir=None)
ドメインをロケールディレクトリ localedir にバインドします。 より具体的には、 gettext は、パス(Unixの場合)を使用して、指定されたドメインのバイナリ
.mo
ファイルを検索します:localedir/language/LC_MESSAGES/domain.mo
、ここで言語が検索されます環境変数LANGUAGE
、LC_ALL
、LC_MESSAGES
、および [X271X ]LANG
それぞれ。localedir が省略されているか
None
の場合、ドメインの現在のバインディングが返されます。 1
- gettext.bind_textdomain_codeset(domain, codeset=None)
- ドメインをコードセットにバインドし、 lgettext()、 ldgettext()、によって返されるバイト文字列のエンコーディングを変更しますlngettext()および ldngettext()関数。 codeset を省略すると、現在のバインディングが返されます。
- gettext.textdomain(domain=None)
- 現在のグローバルドメインを変更またはクエリします。 domain が
None
の場合、現在のグローバルドメインが返されます。それ以外の場合、グローバルドメインは domain に設定され、返されます。
- gettext.gettext(message)
- 現在のグローバルドメイン、言語、およびロケールディレクトリに基づいて、メッセージのローカライズされた翻訳を返します。 この関数は通常、ローカル名前空間で
_()
としてエイリアスされます(以下の例を参照)。
- gettext.dgettext(domain, message)
- gettext()と同様ですが、指定されたドメインでメッセージを検索します。
- gettext.ngettext(singular, plural, n)
gettext()と同様ですが、複数形を検討してください。 翻訳が見つかった場合は、 n に複数形を適用し、結果のメッセージを返します(一部の言語には3つ以上の複数形があります)。 翻訳が見つからない場合、 n が1の場合、 singular を返します。 それ以外の場合は、複数形を返します。
複数の式は、カタログヘッダーから取得されます。 これは、自由変数 n を持つCまたはPython式です。 式は、カタログ内の複数形のインデックスに評価されます。
.po
ファイルで使用される正確な構文とさまざまな言語の式については、 GNUgettextドキュメントを参照してください。
- gettext.dngettext(domain, singular, plural, n)
- ngettext()と同様ですが、指定されたドメインでメッセージを検索します。
- gettext.pgettext(context, message)
- gettext.dpgettext(domain, context, message)
- gettext.npgettext(context, singular, plural, n)
- gettext.dnpgettext(domain, context, singular, plural, n)
プレフィックスに
p
がない対応する関数と同様です(つまり、 gettext()、 dgettext()、 ngettext()、 dngettext())ですが、翻訳は指定されたメッセージ context に制限されています。バージョン3.8の新機能。
- gettext.lgettext(message)
- gettext.ldgettext(domain, message)
- gettext.lngettext(singular, plural, n)
- gettext.ldngettext(domain, singular, plural, n)
l
プレフィックスのない対応する関数( gettext()、 dgettext()、 ngettext()、 dngettext( ))。ただし、 bind_textdomain_codeset()で他のエンコーディングが明示的に設定されていない場合、変換は優先システムエンコーディングでエンコードされたバイト文字列として返されます。警告
これらの関数はエンコードされたバイトを返すため、Python3では避ける必要があります。 ほとんどのPythonアプリケーションは、人間が読めるテキストをバイトではなく文字列として操作する必要があるため、代わりにUnicode文字列を返す代替手段を使用することをお勧めします。 さらに、翻訳された文字列にエンコードの問題がある場合、予期しないUnicode関連の例外が発生する可能性があります。
GNU gettext もdcgettext()
メソッドを定義していますが、これは役に立たないと見なされたため、現在実装されていないことに注意してください。
このAPIの一般的な使用例を次に示します。
import gettext
gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print(_('This is a translatable string.'))
クラスベースAPI
gettext モジュールのクラスベースAPIは、GNU gettext APIよりも柔軟性と利便性を提供します。 これは、Pythonアプリケーションとモジュールをローカライズするための推奨される方法です。 gettext
は、GNU .mo
形式のファイルの解析を実装し、文字列を返すためのメソッドを持つ GNUTranslations クラスを定義します。 このクラスのインスタンスは、関数_()
として組み込みの名前空間に自分自身をインストールすることもできます。
- gettext.find(domain, localedir=None, languages=None, all=False)
この関数は、標準の
.mo
ファイル検索アルゴリズムを実装します。 domain を取ります。これは、 textdomain()が取るものと同じです。 オプションの localedir は、 bindtextdomain()と同じです。 オプションの languages は文字列のリストであり、各文字列は言語コードです。localedir が指定されていない場合は、デフォルトのシステムロケールディレクトリが使用されます。 2 languages が指定されていない場合、次の環境変数が検索されます:
LANGUAGE
、 [ X136X]、LC_MESSAGES
、およびLANG
。 空でない値を返す最初の値は、 languages 変数に使用されます。 環境変数には、コロンで区切られた言語のリストが含まれている必要があります。これは、コロンで分割されて、予期される言語コード文字列のリストが生成されます。find()は、言語を展開して正規化し、言語を反復処理して、次のコンポーネントで構築された既存のファイルを検索します。
localedir/language/LC_MESSAGES/domain.mo
存在する最初のそのようなファイル名は、 find()によって返されます。 そのようなファイルが見つからない場合は、
None
が返されます。 all を指定すると、すべてのファイル名のリストが、言語リストまたは環境変数に表示される順序で返されます。
- gettext.translation(domain, localedir=None, languages=None, class_=None, fallback=False, codeset=None)
ドメイン、 localedir 、および言語に基づいて
*Translations
インスタンスを返します。これらは、最初に find()に渡されます。 ]関連する.mo
ファイルパスのリストを取得します。 同一の.mo
ファイル名を持つインスタンスがキャッシュされます。 インスタンス化される実際のクラスは、提供されている場合は class_ であり、提供されていない場合は GNUTranslations です。 クラスのコンストラクターは、単一のファイルオブジェクト引数を取る必要があります。 指定されている場合、 codeset は、 lgettext()および lngettext()メソッドで変換された文字列のエンコードに使用される文字セットを変更します。複数のファイルが見つかった場合、後のファイルが前のファイルのフォールバックとして使用されます。 フォールバックの設定を可能にするために、 copy.copy()を使用して、キャッシュから各変換オブジェクトのクローンを作成します。 実際のインスタンスデータは引き続きキャッシュと共有されます。
.mo
ファイルが見つからない場合、この関数は fallback がfalse(デフォルト)の場合に OSError を発生させ、 NullTranslations インスタンスを返します。 フォールバックがtrueの場合。
- gettext.install(domain, localedir=None, codeset=None, names=None)
これにより、関数に渡される domain 、 localedir 、および codeset に基づいて、関数
_()
がPythonの組み込み名前空間にインストールされます。 translation()。names パラメーターについては、変換オブジェクトの install()メソッドの説明を参照してください。
以下に示すように、通常、次のように
_()
関数の呼び出しで文字列をラップすることにより、翻訳の候補となるアプリケーション内の文字列をマークします。print(_('This string will be translated.'))
便宜上、
_()
関数をPythonの組み込み名前空間にインストールして、アプリケーションのすべてのモジュールから簡単にアクセスできるようにする必要があります。
NullTranslations クラス
翻訳クラスは、元のソースファイルのメッセージ文字列から翻訳されたメッセージ文字列への翻訳を実際に実装するものです。 すべての変換クラスで使用される基本クラスは NullTranslations です。 これにより、独自の特殊な翻訳クラスを作成するために使用できる基本的なインターフェイスが提供されます。 NullTranslations
のメソッドは次のとおりです。
- class gettext.NullTranslations(fp=None)
オプションのファイルオブジェクト fp を取りますが、これは基本クラスでは無視されます。 派生クラスによって設定される「保護された」インスタンス変数 _info と _charset 、および add_fallback()[によって設定される _fallback を初期化します。 X184X]。 次に、 fp が
None
でない場合、self._parse(fp)
を呼び出します。- _parse(fp)
基本クラスでは何も実行されません。このメソッドはファイルオブジェクト fp を受け取り、ファイルからデータを読み取り、メッセージカタログを初期化します。 サポートされていないメッセージカタログファイル形式がある場合は、このメソッドをオーバーライドして形式を解析する必要があります。
- add_fallback(fallback)
現在の変換オブジェクトのフォールバックオブジェクトとしてフォールバックを追加します。 翻訳オブジェクトは、特定のメッセージの翻訳を提供できない場合、フォールバックを参照する必要があります。
- gettext(message)
フォールバックが設定されている場合は、
gettext()
をフォールバックに転送します。 それ以外の場合は、メッセージを返します。 派生クラスでオーバーライドされます。
- ngettext(singular, plural, n)
フォールバックが設定されている場合は、
ngettext()
をフォールバックに転送します。 それ以外の場合、 n が1の場合、 singular を返します。 それ以外の場合は、複数形を返します。 派生クラスでオーバーライドされます。
- pgettext(context, message)
フォールバックが設定されている場合は、 pgettext()をフォールバックに転送します。 それ以外の場合は、翻訳されたメッセージを返します。 派生クラスでオーバーライドされます。
バージョン3.8の新機能。
- npgettext(context, singular, plural, n)
フォールバックが設定されている場合は、 npgettext()をフォールバックに転送します。 それ以外の場合は、翻訳されたメッセージを返します。 派生クラスでオーバーライドされます。
バージョン3.8の新機能。
- lgettext(message)
- lngettext(singular, plural, n)
gettext()および ngettext()と同等ですが、 set_output_charset()でエンコードが明示的に設定されていない場合、変換は優先システムエンコーディングでエンコードされたバイト文字列として返されます。 。 派生クラスでオーバーライドされます。
警告
これらのメソッドは、Python3では回避する必要があります。 lgettext()関数の警告を参照してください。
- info()
「保護された」
_info
変数を返します。これは、メッセージカタログファイルで見つかったメタデータを含む辞書です。
- charset()
メッセージカタログファイルのエンコーディングを返します。
- output_charset()
lgettext()および lngettext()で翻訳されたメッセージを返すために使用されるエンコーディングを返します。
- set_output_charset(charset)
翻訳されたメッセージを返すために使用されるエンコーディングを変更します。
- install(names=None)
このメソッドは、 gettext()を組み込みの名前空間にインストールし、
_
にバインドします。names パラメーターを指定する場合は、
_()
に加えて、組み込み名前空間にインストールする関数の名前を含むシーケンスである必要があります。 サポートされている名前は、'gettext'
、'ngettext'
、'pgettext'
、'npgettext'
、'lgettext'
、および'lngettext'
です。これは、
_()
機能をアプリケーションで使用できるようにするための、最も便利な方法ではありますが、1つの方法にすぎないことに注意してください。 これはアプリケーション全体、特に組み込みの名前空間に影響を与えるため、ローカライズされたモジュールは決して_()
をインストールしないでください。 代わりに、次のコードを使用して、モジュールで_()
を使用できるようにする必要があります。import gettext t = gettext.translation('mymodule', ...) _ = t.gettext
これにより、
_()
はモジュールのグローバル名前空間にのみ配置されるため、このモジュール内の呼び出しにのみ影響します。バージョン3.8で変更:
'pgettext'
および'npgettext'
を追加。
GNUTranslations クラス
gettext モジュールは、 NullTranslations から派生した1つの追加クラス GNUTranslations を提供します。 このクラスは_parse()
をオーバーライドして、GNU gettext 形式.mo
ファイルをビッグエンディアン形式とリトルエンディアン形式の両方で読み取れるようにします。
GNUTranslations は、翻訳カタログからオプションのメタデータを解析します。 空の文字列の変換としてメタデータを含めることは、GNU gettext の慣例です。 このメタデータは RFC 822 スタイルのkey: value
ペアであり、Project-Id-Version
キーが含まれている必要があります。 キーContent-Type
が見つかった場合、charset
プロパティを使用して、「保護された」_charset
インスタンス変数が初期化されます。見つからない場合は、デフォルトでNone
になります。 文字セットエンコーディングが指定されている場合、カタログから読み取られたすべてのメッセージIDとメッセージ文字列はこのエンコーディングを使用してUnicodeに変換されます。それ以外の場合はASCIIが想定されます。
メッセージIDもUnicode文字列として読み取られるため、すべての*gettext()
メソッドは、メッセージIDをバイト文字列ではなくUnicode文字列と見なします。
キーと値のペアのセット全体が辞書に配置され、「保護された」_info
インスタンス変数として設定されます。
.mo
ファイルのマジックナンバーが無効な場合、メジャーバージョン番号が予期しない場合、またはファイルの読み取り中に他の問題が発生した場合、 GNUTranslations クラスをインスタンス化すると OSError が発生する可能性があります。
- class gettext.GNUTranslations
次のメソッドは、基本クラスの実装からオーバーライドされます。
- gettext(message)
カタログで message idを検索し、対応するメッセージ文字列をUnicode文字列として返します。 message idのエントリがカタログになく、フォールバックが設定されている場合、ルックアップはフォールバックの gettext()メソッドに転送されます。 それ以外の場合は、メッセージ IDが返されます。
- ngettext(singular, plural, n)
メッセージIDの複数形のルックアップを実行します。 singular は、カタログで検索するためのメッセージIDとして使用され、 n は、使用する複数形を決定するために使用されます。 返されるメッセージ文字列はUnicode文字列です。
メッセージIDがカタログに見つからず、フォールバックが指定されている場合、要求はフォールバックの ngettext()メソッドに転送されます。 それ以外の場合、 n が1の場合、単数形が返され、それ以外の場合は複数形が返されます。
次に例を示します。
n = len(os.listdir('.')) cat = GNUTranslations(somefile) message = cat.ngettext( 'There is %(num)d file in this directory', 'There are %(num)d files in this directory', n) % {'num': n}
- pgettext(context, message)
カタログで context および message idを検索し、対応するメッセージ文字列をUnicode文字列として返します。 メッセージ IDとコンテキストのエントリがカタログになく、フォールバックが設定されている場合、ルックアップはフォールバックの pgettext()に転送されます。 ] 方法。 それ以外の場合は、メッセージ IDが返されます。
バージョン3.8の新機能。
- npgettext(context, singular, plural, n)
メッセージIDの複数形のルックアップを実行します。 singular は、カタログで検索するためのメッセージIDとして使用され、 n は、使用する複数形を決定するために使用されます。
context のメッセージIDがカタログに見つからず、フォールバックが指定されている場合、要求はフォールバックの npgettext()メソッドに転送されます。 それ以外の場合、 n が1の場合、単数形が返され、それ以外の場合は複数形が返されます。
バージョン3.8の新機能。
- lgettext(message)
- lngettext(singular, plural, n)
gettext()および ngettext()と同等ですが、 set_output_charset()でエンコードが明示的に設定されていない場合、変換は優先システムエンコーディングでエンコードされたバイト文字列として返されます。 。
警告
これらのメソッドは、Python3では回避する必要があります。 lgettext()関数の警告を参照してください。
Solarisメッセージカタログのサポート
Solarisオペレーティングシステムは、独自のバイナリ.mo
ファイル形式を定義していますが、この形式に関するドキュメントが見つからないため、現時点ではサポートされていません。
カタログコンストラクター
GNOMEは、JamesHenstridgeによる gettext モジュールのバージョンを使用しますが、このバージョンのAPIは少し異なります。 その文書化された使用法は次のとおりです。
import gettext
cat = gettext.Catalog(domain, localedir)
_ = cat.gettext
print(_('hello world'))
この古いモジュールとの互換性のために、関数Catalog()
は、上記の translation()関数のエイリアスです。
このモジュールとHenstridgeのモジュールの違いの1つは、彼のカタログオブジェクトはマッピングAPIを介したアクセスをサポートしていましたが、これは使用されていないようで、現在はサポートされていません。
プログラムとモジュールの国際化
国際化(I18N)とは、プログラムに複数の言語を認識させる操作のことです。 ローカリゼーション(L10N)とは、プログラムが国際化された後、現地の言語や文化的習慣に適応することを指します。 Pythonプログラムに多言語メッセージを提供するには、次の手順を実行する必要があります。
- 翻訳可能な文字列を特別にマークして、プログラムまたはモジュールを準備します
- マークされたファイルに対して一連のツールを実行して、生のメッセージカタログを生成します
- メッセージカタログの言語固有の翻訳を作成する
- gettext モジュールを使用して、メッセージ文字列が適切に翻訳されるようにします
I18Nのコードを準備するには、ファイル内のすべての文字列を確認する必要があります。 翻訳する必要のある文字列は、_('...')
でラップすることによってマークする必要があります。つまり、関数_()
を呼び出します。 例えば:
filename = 'mylog.txt'
message = _('writing a log message')
with open(filename, 'w') as fp:
fp.write(message)
この例では、文字列'writing a log message'
は翻訳の候補としてマークされていますが、文字列'mylog.txt'
および'w'
はマークされていません。
翻訳用の文字列を抽出するためのツールがいくつかあります。 元のGNU gettext はCまたはC ++ソースコードのみをサポートしていましたが、その拡張バージョン xgettext は、Pythonを含む多くの言語で記述されたコードをスキャンして、翻訳可能としてマークされた文字列を見つけます。 Babel は、メッセージカタログを抽出およびコンパイルするためのpybabel
スクリプトを含むPython国際化ライブラリです。 xpot と呼ばれるFrançoisPinardのプログラムは同様の仕事をし、彼の po-utilsパッケージの一部として利用できます。
(Pythonには、 pygettext.py および msgfmt.py と呼ばれるこれらのプログラムの純粋なPythonバージョンも含まれています。一部のPythonディストリビューションではそれらがインストールされます。 pygettext.py は xgettext に似ていますが、Pythonソースコードのみを理解し、CやC ++などの他のプログラミング言語を処理できません。 pygettext.py は、 xgettext と同様のコマンドラインインターフェイスをサポートしています。 使用方法の詳細については、pygettext.py --help
を実行してください。 msgfmt.py は、GNU msgfmt とバイナリ互換です。 これらの2つのプログラムでは、Pythonアプリケーションを国際化するためにGNU gettext パッケージは必要ない場合があります。)
xgettext 、 pygettext 、および同様のツールは、メッセージカタログである.po
ファイルを生成します。 これらは、ソースコード内のマークされたすべての文字列と、これらの文字列の翻訳バージョンのプレースホルダーを含む、構造化された人間が読める形式のファイルです。
これらの.po
ファイルのコピーは、サポートされているすべての自然言語の翻訳を作成する個々の人間の翻訳者に渡されます。 完成した言語固有のバージョンを<language-name>.po
ファイルとして送り返します。このファイルは、 msgfmt プログラムを使用して機械可読な.mo
バイナリカタログファイルにコンパイルされます。 .mo
ファイルは、実行時の実際の翻訳処理のために gettext モジュールによって使用されます。
コードで gettext モジュールをどのように使用するかは、単一のモジュールを国際化するのか、アプリケーション全体を国際化するのかによって異なります。 次の2つのセクションでは、それぞれのケースについて説明します。
モジュールのローカライズ
モジュールをローカライズする場合は、グローバルな変更を行わないように注意する必要があります。 組み込みの名前空間に。 GNU gettext APIを使用するのではなく、クラスベースのAPIを使用する必要があります。
モジュールが「スパム」と呼ばれ、モジュールのさまざまな自然言語翻訳.mo
ファイルがGNU gettext 形式の/usr/share/locale
にあるとします。 モジュールの上部に配置するものは次のとおりです。
import gettext
t = gettext.translation('spam', '/usr/share/locale')
_ = t.gettext
アプリケーションのローカライズ
アプリケーションをローカライズする場合は、_()
関数を組み込みの名前空間(通常はアプリケーションのメインドライバーファイル)にグローバルにインストールできます。 これにより、すべてのアプリケーション固有のファイルで_('...')
を使用できるようになり、各ファイルに明示的にインストールする必要がなくなります。
単純なケースでは、アプリケーションのメインドライバーファイルに次のコードを追加するだけで済みます。
import gettext
gettext.install('myapplication')
ロケールディレクトリを設定する必要がある場合は、それを install()関数に渡すことができます。
import gettext
gettext.install('myapplication', '/usr/share/locale')
その場で言語を変更する
プログラムが同時に多くの言語をサポートする必要がある場合は、次のように、複数の翻訳インスタンスを作成してから、それらを明示的に切り替えることができます。
import gettext
lang1 = gettext.translation('myapplication', languages=['en'])
lang2 = gettext.translation('myapplication', languages=['fr'])
lang3 = gettext.translation('myapplication', languages=['de'])
# start by using language1
lang1.install()
# ... time goes by, user selects language 2
lang2.install()
# ... more time goes by, user selects language 3
lang3.install()
延期された翻訳
ほとんどのコーディング状況では、文字列はコーディングされた場所で翻訳されます。 ただし、場合によっては、翻訳用に文字列をマークする必要がありますが、実際の翻訳は後日まで延期します。 古典的な例は次のとおりです。
animals = ['mollusk',
'albatross',
'rat',
'penguin',
'python', ]
# ...
for a in animals:
print(a)
ここでは、animals
リストの文字列を翻訳可能としてマークしたいのですが、実際には、印刷されるまで翻訳したくありません。
この状況に対処する1つの方法は次のとおりです。
def _(message): return message
animals = [_('mollusk'),
_('albatross'),
_('rat'),
_('penguin'),
_('python'), ]
del _
# ...
for a in animals:
print(_(a))
_()
のダミー定義は単に文字列を変更せずに返すため、これは機能します。 また、このダミー定義は、組み込み名前空間内の_()
の定義を一時的にオーバーライドします( del コマンドまで)。 ただし、ローカル名前空間に_()
の以前の定義がある場合は、注意してください。
_()
の2回目の使用では、パラメーターが文字列リテラルではないため、「a」が gettext プログラムに翻訳可能であると識別されないことに注意してください。
これを処理する別の方法は、次の例を使用することです。
def N_(message): return message
animals = [N_('mollusk'),
N_('albatross'),
N_('rat'),
N_('penguin'),
N_('python'), ]
# ...
for a in animals:
print(_(a))
この場合、翻訳可能な文字列を関数N_()
でマークします。これは、_()
の定義と競合しません。 ただし、N_()
でマークされた翻訳可能な文字列を探すようにメッセージ抽出プログラムを教える必要があります。 xgettext 、 pygettext 、pybabel extract
、および xpot はすべて、-k
コマンドラインスイッチを使用してこれをサポートします。 ここでのN_()
の選択は完全に任意です。 MarkThisStringForTranslation()
と同じくらい簡単だったかもしれません。
謝辞
次の人々は、このモジュールの作成にコード、フィードバック、設計提案、以前の実装、および貴重な経験を提供しました。
- ピーターファンク
- ジェームズ・ヘンストリッジ
- フアン・デビッド・イバニェス・パロマー
- マークアンドレレンブルグ
- マーティン・フォン・レーウィス
- フランソワ・ピナール
- バリーワルシャワ
- グスタボ・ニーマイヤー
脚注
- 1
- デフォルトのロケールディレクトリはシステムに依存します。 たとえば、RedHatLinuxでは
/usr/share/locale
ですが、Solarisでは/usr/lib/locale
です。 gettext モジュールは、これらのシステム依存のデフォルトをサポートしようとしません。 代わりに、デフォルトはsys.base_prefix/share/locale
です( sys.base_prefix を参照)。 このため、アプリケーションの開始時に明示的な絶対パスを使用して bindtextdomain()を呼び出すのが常に最善です。 - 2
- 上記の bindtextdomain()の脚注を参照してください。