Django v1.0 documentation

国際化

revision-up-to:8961 (1.0)

Django はコードとテンプレートの双方で国際化をフルサポートしています。このド キュメントでは国際化の仕組みについて説明します。

概要

国際化のゴールは、一つの Web アプリケーションが複数の言語でコンテンツや機能 を提供できるようにすることにあります。

Django 開発者は、最小限のフックを Python コードとテンプレートに埋め込むこと で国際化というゴールにたどり着けます。これらのフックは 翻訳文字列 (translation string) と呼ばれています。翻訳文字列は Django に「このテキストについてエンドユーザの言語に合ったテキストがあるなら、テキ ストを翻訳して出力せよ」と指示します。

Django はこれらのフックに注意して、ユーザの言語設定に合わせて Web アプリケー ションをオンザフライで翻訳します。

Django が行っているのは、本質的には以下の二つの作業です:

  • 開発者やテンプレートの作者に、アプリケーションのどの部分を翻訳できるか 指定させます。
  • 指定したフックを使って、特定のユーザの言語設定に従って Web アプリケー ションを翻訳します。

国際化が必要ない場合

Django の国際化フックはデフォルトで有効になっているので、フレームワークの一 部で i18n がらみのわずかなオーバヘッドが生じています。国際化の機能を使いた くなければ、設定ファイルで USE_I18N = False を設定し てください。 USE_I18NFalse に設定すると、 Django は国際 化機構をロードしないよう最適化を行います。

この場合、 TEMPLATE_CONTEXT_PROCESSORS からも 'django.core.context_processors.i18n' を外すことになるでしょう。

国際化が必要な場合: 3 つのステップ

  1. 翻訳対象文字列を Python コードやテンプレートに埋め込みます。
  2. サポートしたい言語について、翻訳対象文字列に対応する翻訳を行います。
  3. Django の設定でロケールミドルウェアを有効化します。

舞台裏では

Django の翻訳機構は、 Python に付属の gettext モジュールを使ってい ます。

1. 翻訳文字列の指定方法

翻訳文字列 (translation string) は、「このテキストを翻訳対象にする」という 指定を行います。翻訳文字列は Python コードにもテンプレートにも現れます。翻 訳可能な文字列をマークしておくのは作者の役割であり、翻訳システムはマークさ れた文字列しか翻訳対象にしません。

Python コード内での指定

標準的な翻訳

翻訳対象文字列を関数 ugettext() で指定します。タイプ数を減らすため、 ugettext()_ という別名で import するのが慣習的なやり方です。

Note

Python の標準ライブラリ gettext は、グローバルの名前空間に _() という名前で gettext() をインストールします。 Django ではこの方法に 従っていませんが、それは以下の理由からです:

  1. 国際化文字セット (Unicode) のサポート下では、 gettext() よりも ugettext() の方が便利だからです。また、ファイルによっては ugettext_lazy() をデフォルトの翻訳用メソッドに使った方がよい 場合もあります。グローバル名前空間に _() がなければ、開発者に 場合に応じて適切な翻訳用メソッドを選ぶ自由を与えられます。
  2. アンダースコア文字は、 Python の対話シェルや doctest で書かれたテ スト中では「直前の式の値」を表します。そのため、グローバル名前空間 に _() をインストールすると、干渉して問題を引き起こします。 ugettext()_() という名前で明示的に import すれば、こ の問題を回避できます。

下の例では、 "Welcome to my site." というテキストを翻訳文字列としてマー クします:

from django.utils.translation import ugettext as _

def my_view(request):
    output = _("Welcome to my site.")
    return HttpResponse(output)

もちろん、 ugettext() に別名を付けなくても使えます。従って、下の例は上 の例と全く同じになります:

from django.utils.translation import ugettext
def my_view(request):
    output = ugettext("Welcome to my site.")
    return HttpResponse(output)

翻訳は計算済みの値に対して行われます。従って、下の例も上の 2 例と同じになり ます:

def my_view(request):
    words = ['Welcome', 'to', 'my', 'site.']
    output = _(' '.join(words))
    return HttpResponse(output)

翻訳は変数に対しても使えます。従って、下の例もまた、上の例と同じになります:

def my_view(request):
    sentence = 'Welcome to my site.'
    output = _(sentence)
    return HttpResponse(output)

(上の 2 つの例のように変数や計算済みの値を使う場合、 Django の翻訳文字列検 出ユーティリティ django-admin.py makemessages はこれらの文字列を検出で きないので注意しておきましょう。詳しくは後の makemessages の節で説明し ます。)

_()ugettext() に渡す文字列には、 Pyton の標準の名前付き補完構文 によるプレースホルダを使えます。例えば:

def my_view(request, m, d):
    output = _('Today is %(month)s, %s(day)s.') % {'month': m, 'day': d}
    return HttpResponse(output)

このテクニックを使うと、言語ごとの翻訳でプレースホルダを並べ変えできるよう になり、例えば、英語の翻訳文が "Today is Nobember, 26." であるのに対し て、スペイン語では "Hoy es 26 de Noviembre." であるように、プレースホル ダの位置を翻訳文の前後で移動できます。

この理由から、引数が複数ある場合には、固定引数を使った補完 (%s%d) ではなく、名前付きの補完 (%(day)s) を使ってください。固定引数 による補完を使った場合、プレースホルダの順番によってうまく翻訳できない場合 があります。

すぐには翻訳しない文字列をマークする

すぐには翻訳しない文字列のマークには django.utils.translation.ugettext_noop() を使って下さい。マークした文字 列は後で変数として使われるときに翻訳されます。

この関数は、ソース言語の中に定数として文字列を置いておきたい場合に使います。 というのも、定数は、例えばデータベース中の文字列のように、システムやユーザ 間で共通な値である一方で、ユーザにメッセージとして提示する最後の段階で翻訳 せねばならない場合があるからです。

翻訳を遅延させる

文字列の翻訳を遅延 (lazy) させるには、 django.utils.translation.ugettext_lazy() を使います。翻訳を遅延させると、 ugettext_lazy() を呼び出すまで翻訳文字列の値にアクセスしません。

例えば、モデルの help_text を翻訳する場合に以下のようにします:

from django.utils.translation import ugettext_lazy

class MyThing(models.Model):
    name = models.CharField(help_text=ugettext_lazy('This is the help text'))

この例では、 ugettext_lazy() は実際の翻訳文字列ではなく、文字列への遅延 参照 (lazy reference) を保存します。翻訳自体は文字列をコンテキストで使った 時、例えば admin サイトでテンプレートをレンダリングしたときに初めて実行され ます。

ugettext_lazy という名前が冗長で嫌なら、以下のようにして _ (アンダー スコア) にエイリアスできます:

from django.utils.translation import ugettext_lazy as _

class MyThing(models.Model):
    name = models.CharField(help_text=_('This is the help text'))

Django モデル の中では、常に遅延翻訳を使うように してください。フィールド名やテーブル名に翻訳をつけておくのも良いアイデアで す。とはいえ、これは Meta クラスで明示的に verbose_nameverbose_name_plural オプションを指定するという作業です:

from django.utils.translation import ugettext_lazy as _

class MyThing(models.Model):
    name = models.CharField(_('name'), help_text=_('This is the help text'))
    class Meta:
        verbose_name = _('my thing')
        verbose_name_plural = _('mythings')

複数形化

複数形のメッセージを指定するには django.utils.translation.ungettext() を 使います。例えば:

from django.utils.translation import ungettext
def hello_world(request, count):
    page = ungettext('there is %(count)d object', 'there are %(count)d objects', count) % {
        'count': count,
    }
    return HttpResponse(page)

ungettext は、単数形の翻訳文字列、複数形の翻訳文字列、そしてオブジェクト の数 (翻訳言語に count という変数で渡されます) という 3 つの引数をとり ます。

テンプレート内での翻訳

Django テンプレート 中の翻訳は、二つのテンプレー トタグを使ってPython コードとは少し違った方法で行います。テンプレートで翻訳 用のタグを使えるようにするには、テンプレートの上の方に {% load i18n %} を入れておきます。

テンプレートタグ {% trans %} は定数の文字列 (シングルクオートまたはダブ ルクオートで囲まれた文字列) や変数を翻訳します:

<title>{% trans "This is the title." %}</title>
<title>{% trans myvar %}</title>

noop オプションを指定すると、値の参照は行われますが、翻訳はしません。 noop は、将来翻訳が必要なコンテンツを「スタブ」するのに便利です。

<title>{% trans "myvar" noop %}</title>

{% trans %} の中では定数文字列とテンプレート変数を同時に扱えません。翻 訳中で変数 (プレースホルダ) を使いたい場合には、以下の例のように {% blocktrans %} を使います:

{% blocktrans %}This string will have {{ value }} inside.{% endblocktrans %}

テンプレート式を翻訳したい場合、すなわちテンプレートフィルタの出力を翻訳し たい場合には、式をローカルな変数にバインドして、翻訳ブロック中で使えるよう にせねばなりません:

{% blocktrans with value|filter as myvar %}
This will have {{ myvar }} inside.
{% endblocktrans %}

blocktrans タグの中で複数個の式を束縛したい場合には、 and を使って 分割します:

{% blocktrans with book|title as book_t and author|title as author_t %}
This is {{ book_t }} by {{ author_t }}
{% endblocktrans %}

複数形化するには、 {% blocktrans %}{% endblocktrans %} の間に {% plural %} タグで単数形と複数形の両方の形式を記述します:

{% blocktrans count list|length as counter %}
There is only one {{ name }} object.
{% plural %}
There are {{ counter }} {{ name }} objects.
{% endblocktrans %}

内部的には、ブロックおよびインラインの翻訳は全て適切な ugettext / ungettext 呼び出しを行います。

RequestContext は 3 つの翻訳処理固有の変数にアクセスできます:

  • LANGUAGES は各言語の言語コードと (現在有効なロケールを使って翻訳 した) 言語名からなるタプルでできた言語のリストです。
  • LANGUAGE_CODE は現在のユーザ設定言語で、文字列です。例: en-us (後述の "言語設定の検出メカニズム" を参照してください)。
  • LANGUAGE_BIDI は現在の言語の表記方向 (direction) です。 True ならば、ヘブライ語やアラビア語のように右から左に記述する言語を示し、 False なら英語、フランス語、ドイツ語のように左から右に記述する言 語を指します。

RequestContext 拡張を使わなければ、以下の 3 つのタグを使って値を取得でき ます:

{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_current_language_bidi as LANGUAGE_BIDI %}

これらのタグを使うには {% load i18n %} が必要です。

翻訳フックは定数文字列を使うテンプレートブロック全てでも利用できます。 _() 構文を使って翻訳文字列を指定してください。例えば:

{% some_special_tag _("Page not found") value|yesno:_("yes,no") %}

このばあい、タグとフィルタの両方は翻訳済みの文字列を扱うことになるので、翻 訳の有無について気を配る必要がなくなります。

Note

上の例では、翻訳インフラストラクチャには文字列 "yes,no" が渡されま す。 "yes""no" の別々の文字列が渡されるわけではありません。 フィルタが引数の文字列を正しく分割できるように、翻訳済みの文字列にはカ ンマが入っていなければなりません。例えば、ドイツ語の翻訳は、 (カンマを そのまま残して) "yes,no""ja,nein" に翻訳せねばなりません。

遅延翻訳オブジェクトを操作する

モデルやユーティリティ関数では、 ugettext_lazy()ungettext_lazy() を使って文字列をマークすることがよくあります。こうして マークした文字列をコードの他の部分で扱うときには、マークしてできた遅延翻訳 オブジェクトをうっかり文字列に変換してしまわないよう気を付けてください。遅 延翻訳オブジェクトの変換は (ロケールの影響下に入るように) できるだけ遅くせ ねばならないからです。遅延翻訳オブジェクトの変換を遅らせるために、以下の二 つのヘルパ関数があります。

文字列の結合: string_concat()

標準の Python 文字列型の join メソッド (''.join([...])) は、 遅延翻訳オブジェクトの入ったリストをうまく扱えません。その代わり、 django.utils.translation.string_concat() を使ってください。このメソッド は、全ての内容を結合し、 かつ 文字列中に値が取り込まれるまで実際に変換を 行わないような遅延オブジェクトを生成して返します。例えば:

from django.utils.translation import string_concat
...
name = ugettext_lazy(u'John Lennon')
instrument = ugettext_lazy(u'guitar')
result = string_concat([name, ': ', instrument])

上のケースでは、 result 中の遅延翻訳オブジェクトは、 result 自体を 文字列中で使った場合 (テンプレートのレンダリング時など) にしか文字列に変換 されません。

allow_lazy() デコレータ

Django はたくさんのユーティリティ関数を (とりわけ django.utils パッケー ジで) 提供しています。これらの関数の多くは文字列を第一引数にとり、文字列に 対して何らかの処理を行います。関数はテンプレートフィルタ内で使われたり、他 のコードで直接呼び出されたりしています。

同様の関数を自分で作成し、翻訳文字列を扱おうとした場合、第一引数が遅延翻訳 オブジェクトの場合に問題に直面することでしょう。この関数はビューの外側 (つ まり、現在のスレッドのロケール設定が的確でないかもしれない場所) で使われる かもしれないので、関数内で遅延翻訳オブジェクトを文字列に変換したくないはず だからです。

こうした場合のために、 django.utils.functional.allow_lazy() デコレータ を使ってください。このデコレータで関数をラップすると、関数の第一引数に遅延 翻訳オブジェクトを渡した場合、関数の評価を文字列に変換する瞬間まで遅延させ られます。

例を示しましょう:

from django.utils.functional import allow_lazy

def fancy_utility_function(s, ...):
    # Do some conversion on string 's'
    ...
fancy_utility_function = allow_lazy(fancy_utility_function, unicode)

allow_lazy() デコレータは関数名に加えて追加の引数 (*args) をとりま す。この引数には、デコレーション対象の関数の戻り値の型 (複数可) を指定しま す。通常は、 unicode だけを入れておき、関数が必ず Unicode 文字列を返す ようにしておけばよいでしょう。

このデコレータを使えば、適切な文字列を入力として受け取る関数を書いておき、 後で遅延翻訳オブジェクトのサポートを追加できます。

2. 言語ファイルの作成

文字列に翻訳用のタグをつけたら、今度は翻訳文自体を書く (または手に入れる) 必要があります。ここでは翻訳文を書く方法について示します。

ロケールの制約

Django は、 Django 本体に対する翻訳カタログのない言語への地域化をサポー トしていません。ある言語向けの自作のカタログを提供しても、 Django 本体 にその言語のサポートがなければ、カタログは無視されます。自作のアプリケー ションに特定の言語のロケールをサポートさせたいのなら、まずは Django の コア部分に対する最小限の翻訳カタログを作成する必要があるでしょう。また、 その場合、翻訳されたメッセージ (自作のアプリケーション内のカタログ) と 英語のメッセージ (Django 自体の不完全なカタログ) が入り混じった表示になっ てしまうでしょう。くわしくは LocaleMiddleware の注意事項 を参照して ください。

メッセージファイル

最初のステップは、新たに追加する言語用の メッセージファイル の作成です。 メッセージファイルは平文テキストファイルで、言語ごとに作成され、翻訳文字列 全てと、言語ごとの対応する表現が収められています。メッセージファイルの拡張 子は .po です。

Django には django-admin.py makemessages というツールが付属しています。 このツールはメッセージファイルの作成や維持を自動化します。

ベテラン Django ユーザへの注意

以前からある bin/make-messages.py ツールの機能は、 Django の操作に 一貫性をもたせるために、 django-admin.py makemessages に移動しまし た。

メッセージファイルの作成や更新を行うには、以下のようにコマンドを実行します:

django-admin.py makemessages -l de

ここで、 de は作成したいメッセージファイルの言語コードです。言語コード はロケール表示の形式にします。例えば、ブラジル系ポルトガル語の場合には pt_BR で、オーストリアドイツは de_AT です。

スクリプトは以下の 3 種類の場所のいずれかで実行します:

  • Django プロジェクトのルートディレクトリ。
  • Django アプリケーションのルートディレクトリ。
  • django のルートディレクトリ (Subversion からチェックアウトしたと きのルートではなく、 $PYTHONPATH にリンクされているか、 $PYTHONPATH 上のどこかにあるディレクトリです)。この場所で実行する のは、 Django 自体の翻訳カタログを生成するときだけです。 翻訳の提出と維持 を参照してください。

スクリプトはプロジェクトのソースツリーやアプリケーションのソースツリーを走 査して、翻訳用にマークされた全ての文字列を取り出します。スクリプトは /locale/LANG/LC_MESSAGES 下にメッセージファイルを作成 (もしくは更新) し ます。 de の例では、ファイルは /locale/de/LC_MESSAGES/django.po で す。

デフォルトの設定では、 django-admin.py makemessages は拡張子 .html のファイルも検索します。デフォルトの設定をオーバライドしたければ、 --extension または -e オプションを使って、拡張子を指定してください:

django-admin.py makemessages -l de -e txt

複数の拡張子を扱いたいのなら、カンマで区切るか、 -e--extension を複数回指定します:

django-admin.py makemessages -l=de -e=html,txt -e xml

JavaScript の翻訳カタログ を生成したいのなら、 -e js ではなく 'djangojs' ドメインを使ってください。

gettext がなかったら?

gettext ユーティリティをインストールしていない場合、 django-admin.py makemessages は空のファイルを作成します。その場合、 gettext ユーティリティをインストールするか、英語用の空のメッセージ ファイル (locale/en/LC_MESSAGES/django.po) をコピーして使って下さい。

Windows で動かしたいのですが?

Windows を使っていて、 django-admin compilemessages を動作させるため に GNU gettext ユーティリティをインストールたいのなら、 gettext on Windows を参照してください。

.po ファイルは素直な形式で書かれています。 .po ファイルには翻訳メン テナのコンタクト情報のようなわずかなメタデータが入っています。それ以外の大 部分は メッセージ のリストです。メッセージは翻訳文字列と特定の言語用の 実際の翻訳テキストです。

例えば、 Django アプリケーションに "Welcome to my site." というテキスト の翻訳文字列が以下のように入っていたとします:

_("Welcome to my site.")

django-admin.py makemessages を実行すると、以下のようなコード断片を含む .po ファイルを作成するはずです:

#: path/to/python/module.py:23
msgid "Welcome to my site."
msgstr ""

上の内容を簡単に説明しましょう:

  • msgid は翻訳文字列で、ソースコードに書かれていたものです。変更し てはなりません。
  • msgstr には各言語の翻訳を入れます。最初は空になっており、変更する のはユーザの責任です。翻訳文字列の周りにクオートを忘れないように注意 してください。
  • 便宜上、各メッセージには該当する翻訳文字列のあったファイル名と行番号 が msgid 行の上の # ではじまる行に入っています。

長いメッセージは特別なケースとして扱います。 msgstr (または msgid) の直後の文字列が空文字列の場合、コンテンツ自体はその次の複数行にわたって書 かれているものとみなします。これらの文字列は直接結合されるので、文字列の中 間では末尾にスペースを忘れないようにしましょう。さもないと、空白なしで文字 列がくっついてしまいますよ!

文字コードセットに注意

PO ファイルをテキストエディタで作成するときには、文字コードセット の行 ("CHARSET" を探して下さい) をまず編集して、これから編集に使う 文字セットにしてください。 gettext ツールの内部動作の仕組み上、また、 Django のコア部分やアプリケーションで非 ASCII のソース文字列を扱えるよ うにするために、 PO ファイルのエンコーディングは必ず UTF-8 にしてくださ い。

全てのソースコードとテンプレートを新たな翻訳文字列でためし、 全ての 言 語用にメッセージファイルを更新するには、以下のようにします:

django-admin.py makemessages -a

メッセージファイルのコンパイル

メッセージファイルを作成して、変更し終えたら gettext を使ってメッセージ ファイルをより効率的な形式にコンパイルします。作業は django-admin.py makemessages ユーティリティで行いましょう。

このツールは全ての .po ファイルをコンパイルして .mo ファイルを作成 します。 .mo ファイルはバイナリファイルで、 gettext で使うために最 適化されています。 django-admin.py makemessages を実行したのと同じディ レクトリで、以下のように django-admin.py compilemessages を実行してくだ さい:

django-admin.py compilemessages

これで終わりです。もう翻訳を使えるようになっているはずです。

ベテラン Django ユーザへの注意

以前からある bin/compile-messages.py ツールの機能は、 Django の操作 に一貫性をもたせるために、 django-admin.py compilemessages に移動し ました。

Windows で動かしたいのですが?

Windows を使っていて、 django-admin compilemessages を動作させるため に GNU gettext ユーティリティをインストールたいのなら、 gettext on Windows を参照してください。

3. 言語設定の検出メカニズム

翻訳の準備を完了した、あるいは Django 付属の翻訳を使いたいだけなら、あとは アプリケーションで翻訳を有効にするだけです。

背後では、 Django はユーザの使用言語を決めるモデルを備えています。このモデ ルは柔軟で、インストール全体、あるいは特定のユーザ、またはその両方に対して 使用言語を決定できます。

インストール全体での使用言語を設定するには、 LANGUAGE_CODE を設 定します。 Django この設定をデフォルトの翻訳言語、すなわち他の適切な翻訳が ない場合に試みる言語に設定します。

Django をネイティブの言語で動かしたいだけで、かつ自分の言語に対する言語ファ イルをすでに準備しているのなら、 LANGUAGE_CODE を設定するだけで済みます。

個々のユーザが自分の使いたい言語を選択できるようにするには LocaleMiddleware を使ってください。 LocaleMiddleware は、リクエスト に埋め込まれたデータに基づいた言語の選択を可能にし、ユーザごとにコンテンツ をカスタマイズします。

LocaleMiddleware を使うには、 MIDDLEWARE_CLASSES 設定に 'django.middleware.locale.LocaleMiddleware' を追加します。ミドルウェア の順番は重要で、以下のガイドラインに従って下さい:

  • まず、インストール済みのミドルウェアの先頭にくるようにしてください。
  • LocaleMiddleware はセッションを使うので、 SessionMiddleware の後ろに配置してください。
  • CacheMiddleware を使っているなら、その後ろに LocaleMiddleware を配置してください。

例えば、 MIDDLEWARE_CLASSES は以下のようになります:

MIDDLEWARE_CLASSES = (
   'django.contrib.sessions.middleware.SessionMiddleware',
   'django.middleware.locale.LocaleMiddleware',
   'django.middleware.common.CommonMiddleware',
)

(ミドルウェアの詳細は ミドルウェアのドキュメント を参照してください。)

LocaleMiddleware はユーザの言語設定を以下のようなアルゴリズムで決定しよ うと試みます:

  • まず、現在のユーザのセッションに django_language キーがないか探し ます。

  • なければ、クッキーを探します。

    Django 1.0 で変更されました.

    バージョン 0.96 以前の Djangoでは、クッキーの名前は django_language にハードコードされていました。 1.0 では、クッキー の名前を LANGUAGE_COOKIE で設定します。(クッキーのデフォル ト名は django_language です。)

  • なければ、 Accept-Language HTTP ヘッダを探します。このヘッダはブ ラウザから送信され、サーバに対して順位つきで言語設定を知らせてきます。 Djang はこの設定を順に調べ、利用可能な翻訳のある言語を探します。

  • なければ、グローバルに設定された LANGUAGE_CODE の設定を使います。

注意:

  • 上記のどのステップでも、言語設定は標準の言語名表記法に従った文字列で 書かれているものと想定しています。例えば、ブラジル系ポルトガル語は pt-br です。

  • 基本言語 (base language) が指定されていて、副言語 (sublanguage) が指 定されていない場合、 Django は基本言語の設定を優先します。例えば、ユー ザが de-at (オーストリアドイツ語) を指定しているのに対して、 Django 側には de のしかない場合、 Django は de を使います。

  • LANGUAGES 設定にリストアップした言語しか選択できません。 (全ての言語に対する翻訳を提供できないなどの理由で) 言語選択を指定の言 語のサブセットに制限したい場合には、 LANGUAGES を設定します。例え ば:

    LANGUAGES = (
      ('de', _('German')),
      ('en', _('English')),
    )
    

    この例では、自動生成されるメニューで利用可能な言語をドイツ語:de と 英語:en (および de-ch や en-us のような副言語) に制限しています。

  • 上の項で説明したように、カスタムの LANGUAGES 設定を行った場合、そ の言語を翻訳対象文字列に含めても構いません。ただし、 django.utils.translationugettext() ではなく、「ダミーの」 ugettext() でマークしてください。循環 import を防ぐため、 決して 設定ファイル中で django.utils.translation を import しないでくだ さい。

    カスタム LANGUAGES のマークアップは「ダミーの」 ugettext() 関 数で解決します。以下に設定ファイルでの記述例を示します:

    ugettext = lambda s: s
    
    LANGUAGES = (
        ('de', ugettext('German')),
        ('en', ugettext('English')),
    )
    

    このように設定しておいても、 django-admin.py makemessages は翻訳 文字列を検出して翻訳対象としてマークします。ただし、実行時の翻訳はお こなわれません。したがって、実行時には LANGUAGES を使うコードを 本当の ugettext() でラップしておかねばなりません。

  • LocaleMiddleware で選択できるのは、 Django が基本的な部分の翻訳を 提供している言語だけです。 Django のソースツリーの翻訳セットに入って いない言語の翻訳を提供したければ、まずその言語むけの基本部分の翻訳を 提供する必要があります。例えば、Django はテクニカルメッセージ ID (technical message ID) を使って日付や時刻のフォーマットを解釈するので、 システムを正しく動作させるには少なくともこうした部分の翻訳が必要にな ります。

    作業を始めるには、まず英語用の .po ファイルをコピーするとよいでしょ う。少なくともテクニカルメッセージだけは翻訳します。バリデーション時 のメッセージもやっておくとよいでしょう。

    テクニカルメッセージ ID は簡単に区別できます。メッセージ ID は全て大 文字でできているからです。このメッセージ ID は他のメッセージと同じよ うに翻訳してよいものではなく、ローカルの正しい形式を指定せねばなりま せん。例えば、 DATETIME_FORMAT (あるいは DATE_FORMATTIME_FORMAT) の場合、自分の言語における正しいフォーマット文字列を 指定せねばなりません。フォーマットは now テンプレートタグで使われ ているフォーマット文字列と同じ文法に従います。

LocaleMiddleware がユーザ設定を検出すると、その設定に HttpRequestrequest.LANGUAGE_CODE でアクセスで きます。この値はビューコードで自由に読みだしてかまいません。以下に一例を挙 げます:

def hello_world(request, count):
    if request.LANGUAGE_CODE == 'de-at':
        return HttpResponse("You prefer to read Austrian German.")
    else:
        return HttpResponse("You prefer to read another language.")

静的な (ミドルウェアを使わない) 翻訳では、言語設定は settings.LANGUAGE_CODE の値になり、動的な (ミドルウェアを使った) 翻訳で は、言語設定は request.LANGUAGE_CODE の値になるので注意してください。

自作のプロジェクトで翻訳を使う

Django は以下のアルゴリズムに従って翻訳を探します:

  • まず、現在呼び出されているビューの入っているアプリケーションディレク トリ下に locale ディレクトリを探します。現在選択されている言語に 対応する翻訳があれば、その翻訳をインストールします。
  • 次に、プロジェクトディレクトリ下に locale ディレクトリを探します。 翻訳があれば、その翻訳をインストールします。
  • 最後に、 django/conf/locale にある Django 付属の翻訳をチェックし ます。

こうすることで、独自の翻訳の入ったアプリケーションを書いたり、基本の翻訳の 内容をプロジェクトパスに置いた翻訳でオーバライドしたりできます。また、複数 の小さなアプリケーションで大きめのプロジェクトを構築するときに、全ての翻訳 を一つのプロジェクト単位のメッセージファイルにまとめておけます。どういう方 法をとるかはユーザ次第です。

Note

DJANGO_SETTINGS_MODULE を使わない設定方法 に示したように、 DJANGO_SETTINGS_MODULE を使わずに手動で設定を行った場合、プ ロジェクトディレクトリ内の locale ディレクトリはチェックされません。 これは Django がプロジェクトディレクトリの場所を調べる術を持たないから です (Django は通常、設定ファイルのある場所を基準に locale ディレク トリの場所を調べますが、手動で設定を行うと設定ファイルが存在しなくなっ てしまうからです)。

メッセージファイルリポジトリも同じような構成になっています:

  • $APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)
  • $PROJECTPATH/locale/<language>/LC_MESSAGES/django.(po|mo)
  • 設定ファイルの LOCALE_PATHS に指定されている全てのパスを指定順に 検索して <language>/LC_MESSAGES/django.(po|mo) を探します。
  • $PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)

メッセージファイルの作成には、 Django メッセージファイルと同じ django-admin.py makemessages ツールを使って下さい。ツールの実行は正しい 場所、すなわち conf/locale (ソースツリーの場合) か、あるいは locale (アプリケーションメッセージやプロジェクトメッセージの場合) ディレクトリのあ るディレクトリで行わねばなりません。また、 gettext の使うバイナリ形式の django.mo ファイルを生成するには django-admin.py compilemessages を 使います。

django-admin.py compilemessages --settings=path.to.settings を実行すれ ば、コンパイラに LOCALE_PATHS に設定された全てのディレクトリを処理させ られます。

アプリケーションメッセージファイルを発見するメカニズムはやや複雑で、 LocaleMiddleware が必要になります。従って、このミドルウェアを使わない場 合、 Django メッセージファイルとプロジェクトメッセージファイルだけが処理さ れます。

最後に、翻訳ファイルをどのように構成するかしっかりと考えておくように勧めま す。自分の作ったアプリケーションを他のユーザに配ったり、他のプロジェクトで 利用したりするなら、アプリケーション固有の翻訳が必要になるでしょう。しかし、 アプリケーション固有のメッセージやプロジェクトごとの翻訳は makemessages にまつわる困った問題を引き起こすことがあります: makemessages は現在のパス以下の全てのディレクトリを検索してしまうので、 すでにアプリケーションメッセージファイルに入っているメッセージ ID が、プロ ジェクトのメッセージファイルに入ってしまうことがあるのです。

この問題の最も簡単な解決法は、プロジェクトを直接的に構築しない (なおかつ独 自の翻訳を備えている) アプリケーションをプロジェクトツリーの外に配置してお くというものです。こうすれば、プロジェクトレベルで django-admin.py make-messages を実行しても、自分のプロジェクトに明に関 係する部分の文字列だけを翻訳し、別個に配布されたアプリケーションの文字列を 対象にしなくなります。

set_language リダイレクトビュー

利便性のために、 Django には django.views.i18n.set_language ビューが定 義されています。このビューはユーザの言語プリファレンスを設定して、遷移前の ページにリダイレクトします。

このビューを有効にするには、以下の行を URLconf に追加します:

(r'^i18n/', include('django.conf.urls.i18n')),

(この例では /i18n/setlang/ でビューを使えるようにします)

ビューは、リクエストに language が設定された状態で、 POST メソッド で呼び出すようになっています。セッションのサポートが有効であれば、ビューは ユーザのセッションに選択した言語を保存します。セッションのサポートがなけれ ば、言語設定を django_language` クッキーに保存します。 (開発版の Django を使っているなら、クッキーの名前は LANGUAGE_COOKIE_NAME 設定で変更できます。)

選択された言語に設定した後、 Django は以下のアルゴリズムに従ってリダイレク トを行います:

  • Django は POST データから next パラメタを探します。
  • next がないか、空の値なら、 Referer ヘッダを使って遷移元を決 定しようとします。
  • Referer の値も空の場合、例えばユーザのブラウザがリファラの送信を 抑制している場合には、フォールバックとして、ユーザは / (サイトの ルート URL) にリダイレクトします。

以下に HTML テンプレートのコード例を示します:

<form action="/i18n/setlang/" method="post">
<input name="next" type="hidden" value="/next/page/" />
<select name="language">
{% for lang in LANGUAGES %}
<option value="{{ lang.0 }}">{{ lang.1 }}</option>
{% endfor %}
</select>
<input type="submit" value="Go" />
</form>

翻訳と JavaScript

JavaScript に翻訳を追加しようとすると、いくつかの問題に直面します:

  • JavaScript コードには gettext 実装へのアクセス手段がありません。
  • JavaScript コードには .po や .mo ファイルへのアクセス手段がありません。 というのも、これらのファイルはサーバに置かれているからです。
  • JavaScript の翻訳カタログはできるだけ小さくしておかねばなりません。

Django では、これらの問題に対する解決策を組み込みで提供しています。この解決 策は翻訳を JavaScript に渡して、 gettext などを JavaScript コード内で呼 び出せるようにします。

javascript_catalog ビュー

前述の問題に対する解決策は、 javascript_catalog ビューにあります。この ビューは gettext インタフェースをまねた関数の入った JavaScript コードと、 翻訳文字列のアレイを送信します。翻訳文字列のアレイは info_dict や URL の指定に従ってアプリケーションやプロジェクト、Django コア部分から取り出され ます。

例えば以下のようにフックをかけたとしましょう:

js_info_dict = {
    'packages': ('your.app.package',),
}

urlpatterns = patterns('',
    (r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
)

packages のタプルに入っている各文字列は Python のドット区切りのパッケー ジ表記 (INSTALLED_APPS で使われている書式と同じ) で、 locale ディレ クトリの入っているパッケージにします。複数のパッケージを指定した場合、全て のカタログが一つのカタログに統合されます。この仕様は、複数のアプリケーショ ンの文字列を扱うような JavaScript で便利です。

URL パターンにパッケージ名を入れておけば、ビューを動的にできます:

urlpatterns = patterns('',
    (r'^jsi18n/(?P<packages>\S+?)/$', 'django.views.i18n.javascript_catalog'),
)

こうしておいて、パッケージ名を '+' で区切ったパッケージ名リストとして指定で きます。これは、複数のアプリケーションからのコードを使っていて、変更が頻繁 に起きている場合、巨大なカタログファイルを毎回プルしなくてすむので便利です。 セキュリティ上の理由から、パッケージ名リストに指定できるのは、 django.confINSTALLED_APPS 設定に入っているアプリケーションだけ です。

JavaScript 翻訳カタログを使う

カタログを使うには、単に以下のようにして動的に生成されたスクリプトをプルし ます:

<script type="text/javascript" src="/path/to/jsi18n/"></script>

これはまさに admin がサーバから翻訳を取り出しているのと同じ方法です。カタロ グをロードしたら、JavaScript から標準的な gettext インタフェースを使っ てアクセスできるようになります:

document.write(gettext('this is to be translated'));

ngettext インタフェースもあります:

var object_cnt = 1 // or 0, or 2, or 3, ...
s = ngettext('literal for the singular case',
        'literal for the plural case', object_cnt);

文字列補完を行う関数もあります:

function interpolate(fmt, obj, named);

interpolate 関数は、固定引数による補完と名前付き補完の両方をサポートし ています。従って、上のコードは以下のようにも書けます:

s = interpolate(ungettext('this is %s object', 'this are %s objects', 11), [11]);

補完の構文は Python から借りたもので、固定引数と名前つきの文字列補完をサポー トしています:

  • 固定引数型の補完: obj には JavaScript の Array オブジェクトが入り ます。 interpolate は Array の各要素を使って、 fmt 内のプレー スホルダを順番に置換してゆきます。例えば:

    fmts = ngettext('There is %s object. Remaining: %s',
            'There are %s objects. Remaining: %s', 11);
    s = interpolate(fmts, [11, 20]);
    // s is 'There are 11 objects. Remaining: 20'
  • 名前つき補完: このモードは、オプションの named パラメタに true を指定して選択します。 obj には JavaScript のオブジェク トか、連想配列が入ります。例えば:

    d = {
        count: 10
        total: 50
    };
    
    fmts = ngettext('Total: %(total)s, there is %(count)s object',
    'there are %(count)s of a total of %(total)s objects', d.count);
    s = interpolate(fmts, d, true);

とはいえ、この文字列補完を派手に使わない方がよいでしょう: 補完機能は JavaScript で動いており、中では何度も正規表現置換を行っています。この処理は Python の文字列補完ほど高速ではないので、本当に必要な場合 (例えば ngettext を使って適切な複数形表現を実現したい場合) だけにしてください。

JavaScript の翻訳カタログを作成する

JavaScript の翻訳カタログの作成と更新方法、他の Django の翻訳カタログの場合 と同じで、 django-admin.py makemessages ツールを使います。ただし、 -d djangojs パラメタを指定してください。例えば:

django-admin.py makemessages -d djangojs -l de

上の例では、ドイツ語向けの JavaScript の翻訳カタログを作成または更新してい ます。翻訳カタログを更新したら、通常の Django 翻訳カタログと同じように、 django-admin.py compilemessages を実行してください。

Django 翻訳の特徴

gettext について詳しければ、 Django の翻訳機能には以下のような特徴があ ることに気づくでしょう:

  • 文字列ドメインは django または djangojs です。この文字列ドメ インは、共通のメッセージファイルライブラリ (通常は /usr/share/locale/ にあります) にデータを保存している他のプログラ ムと Django のデータを区別するためです。 django ドメインは、 Python とテンプレート翻訳文字列に使われ、グローバルな翻訳カタログ上に 読み込まれます。 djangojs は JavaScript だけで使うために、可能な かぎり小さくして分けてあります。
  • Django は xgettext を単体では使いません。 Django では、 xgettextmsgfmt を Python ラッパ越しに使います。これは便宜 上の理由によります。

Windows で gettext を使う

この節の操作が必要なのは、 メッセージ ID を抜き出したり、メッセージファイル を (.po に) コンパイルしたいときだけです。翻訳の作業自体はファイルを編 集するだけですが、メッセージファイルを自分で作成したい場合や、変更したメッ セージファイルをテストしたりコンパイルしたい場合には、以下のようにして gettext ユーティリティを入れる必要があります:

  • 以下の ZIP ファイルを http://sourceforge.net/projects/gettext から取得します:
    • gettext-runtime-X.bin.woe32.zip
    • gettext-tools-X.bin.woe32.zip
    • libiconv-X.bin.woe32.zip
  • ダウンロードしたファイルを同じフォルダ (例えば C:\ProgramFiles\gettext-utils) に展開します。
  • システム環境変数の PATH を変更します:
    • コントロールパネル > システム > 高度な設定 > 環境変数 の順に辿 ります。
    • システム環境変数 リストで、 Path を選び、 編集 を押しま す。
    • 変数値 フィールドの値の末尾に ;C:\Program Files\gettext-utils\bin を追加します。