翻訳
概要
Djangoプロジェクトを翻訳可能にするには、Pythonコードとテンプレートに最小限のフックを追加する必要があります。 これらのフックは変換文字列と呼ばれます。 彼らはDjangoに次のように語っています。「このテキストの翻訳がエンドユーザーの言語で利用できる場合、このテキストはエンドユーザーの言語に翻訳する必要があります。」 翻訳可能な文字列にマークを付けるのはあなたの責任です。 システムは、知っている文字列のみを翻訳できます。
次に、Djangoは、翻訳文字列をメッセージファイルに抽出するユーティリティを提供します。 このファイルは、翻訳者がターゲット言語の翻訳文字列に相当するものを提供するための便利な方法です。 翻訳者がメッセージファイルに入力したら、コンパイルする必要があります。 このプロセスは、GNUgettextツールセットに依存しています。
これが完了すると、Djangoは、ユーザーの言語設定に応じて、利用可能な各言語でWebアプリをその場で翻訳します。
Djangoの国際化フックはデフォルトでオンになっています。つまり、フレームワークの特定の場所にi18n関連のオーバーヘッドが少しあります。 国際化を使用しない場合は、設定に2秒かかる必要があります :setting: `USE_I18N = False ` 設定ファイルで。 次に、Djangoは、国際化機構をロードしないようにいくつかの最適化を行います。
ノート
Djangoがフォーマットのローカリゼーションを実装するかどうかを制御する、独立しているが関連する:setting: `USE_L10N` 設定もあります。 詳細については、フォーマットのローカリゼーションを参照してください。
ノート
プロジェクトの翻訳がアクティブになっていることを確認してください(最も速い方法は、:setting: `MIDDLEWARE` に django.middleware.locale.LocaleMiddleware が含まれているかどうかを確認することです)。 まだ読んでいない場合は、 Djangoが言語設定を検出する方法を参照してください。
国際化:Pythonコードで
標準翻訳
関数 gettext()を使用して翻訳文字列を指定します。 入力を節約するために、これを短いエイリアス_
としてインポートするのが慣例です。
ノート
gettext
関数のu
プレフィックスは、もともとPython2でのUnicode文字列とバイト文字列の使用法を区別するためのものでした。 Python 3のみをサポートするコードの場合、これらは同じ意味で使用できます。 プレフィックス付き関数の非推奨は、将来のDjangoリリースで発生する可能性があります。
ノート
Pythonの標準ライブラリgettext
モジュールは、gettext()
のエイリアスとして_()
をグローバル名前空間にインストールします。 Djangoでは、いくつかの理由から、このプラクティスに従わないことを選択しました。
- 特定のファイルのデフォルトの翻訳方法として、 gettext_lazy()を使用する必要がある場合があります。 グローバル名前空間に
_()
がない場合、開発者はどちらが最も適切な変換関数であるかを考える必要があります。 - アンダースコア文字(
_
)は、Pythonのインタラクティブシェルおよびdoctestテストで「前の結果」を表すために使用されます。 グローバル_()
関数をインストールすると、干渉が発生します。gettext()
を_()
として明示的にインポートすると、この問題を回避できます。
_
としてエイリアスされる可能性のある関数は何ですか?
xgettext
(:djadmin: `makemessages` で使用)がどのように機能するかにより、単一の文字列引数をとる関数のみを_
としてインポートできます。
この例では、テキスト"Welcome to my site."
が翻訳文字列としてマークされています。
from django.http import HttpResponse
from django.utils.translation import gettext as _
def my_view(request):
output = _("Welcome to my site.")
return HttpResponse(output)
明らかに、エイリアスを使用せずにこれをコーディングできます。 この例は前の例と同じです。
from django.http import HttpResponse
from django.utils.translation import gettext
def my_view(request):
output = gettext("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の翻訳文字列検出ユーティリティです。 :djadmin: `django-admin makemessages ` 、これらの文字列を見つけることができなくなります。 :djadmin: `makemessages` については後で詳しく説明します。)
_()
またはgettext()
に渡す文字列は、Pythonの標準の名前付き文字列補間構文で指定されたプレースホルダーを取ることができます。 例:
def my_view(request, m, d):
output = _('Today is %(month)s %(day)s.') % {'month': m, 'day': d}
return HttpResponse(output)
この手法により、言語固有の翻訳でプレースホルダーテキストを並べ替えることができます。 たとえば、英語の翻訳は"Today is November 26."
であり、スペイン語の翻訳は"Hoy es 26 de Noviembre."
であり、月と日のプレースホルダーが入れ替わっています。
このため、複数のパラメーターがある場合は、位置補間(%s
または%d
など)の代わりに名前付き文字列補間(%(day)s
など)を使用する必要があります。 。 位置補間を使用した場合、翻訳ではプレースホルダーテキストを並べ替えることができません。
文字列の抽出はxgettext
コマンドによって行われるため、gettext
でサポートされている構文のみがDjangoでサポートされています。 Python f-strings および JavaScriptテンプレート文字列は、xgettext
ではまだサポートされていません。
文字列をno-opとしてマークする
関数 django.utils.translation.gettext_noop()を使用して、文字列を翻訳せずに翻訳文字列としてマークします。 文字列は後で変数から変換されます。
データベース内の文字列など、システムまたはユーザーを介して交換されるためにソース言語で保存する必要があるが、文字列が表示されるときなど、可能な限り最後の時点で変換する必要がある定数文字列がある場合は、これを使用しますユーザーに。
複数化
関数 django.utils.translation.ngettext()を使用して、複数のメッセージを指定します。
ngettext()
は、単数の翻訳文字列、複数の翻訳文字列、およびオブジェクトの数の3つの引数を取ります。
この関数は、複数形の数と複雑さが英語で使用される2つの形式(単数形の場合は「object」、 count
が値に関係なく、1つと異なるすべての場合。)
例えば:
from django.http import HttpResponse
from django.utils.translation import ngettext
def hello_world(request, count):
page = ngettext(
'there is %(count)d object',
'there are %(count)d objects',
count) % {
'count': count,
}
return HttpResponse(page)
この例では、オブジェクトの数がcount
変数として翻訳言語に渡されます。
複数化は複雑であり、言語ごとに動作が異なることに注意してください。 count
を1と比較することは、必ずしも正しいルールではありません。 このコードは洗練されているように見えますが、一部の言語では誤った結果が生成されます。
from django.utils.translation import ngettext
from myapp.models import Report
count = Report.objects.count()
if count == 1:
name = Report._meta.verbose_name
else:
name = Report._meta.verbose_name_plural
text = ngettext(
'There is %(count)d %(name)s available.',
'There are %(count)d %(name)s available.',
count
) % {
'count': count,
'name': name
}
独自の単数形または複数形のロジックを実装しようとしないでください。 それは正しくありません。 このような場合は、次のようなことを検討してください。
text = ngettext(
'There is %(count)d %(name)s object available.',
'There are %(count)d %(name)s objects available.',
count
) % {
'count': count,
'name': Report._meta.verbose_name,
}
ノート
ngettext()
を使用する場合は、リテラルに含まれるすべての外挿変数に単一の名前を使用するようにしてください。 上記の例では、両方の変換文字列でname
Python変数をどのように使用したかに注意してください。 この例は、上記のように一部の言語で正しくないことに加えて、失敗します。
text = ngettext(
'There is %(count)d %(name)s available.',
'There are %(count)d %(plural_name)s available.',
count
) % {
'count': Report.objects.count(),
'name': Report._meta.verbose_name,
'plural_name': Report._meta.verbose_name_plural
}
実行時にエラーが発生します :djadmin: `django-admin compilemessages ` :
a format specification for argument 'name', as in 'msgstr[0]', doesn't exist in 'msgid'
コンテキストマーカー
英語の"May"
のように、単語にはいくつかの意味がある場合があります。これは、月の名前と動詞を指します。 翻訳者がこれらの単語をさまざまなコンテキストで正しく翻訳できるようにするには、 django.utils.translation.pgettext()関数、または django.utils.translation.npgettext()を使用できます。文字列に複数形が必要な場合に機能します。 どちらも最初の変数としてコンテキスト文字列を取ります。
結果の.po
ファイルでは、同じ文字列に異なるコンテキストマーカーがあるのと同じ頻度で文字列が表示され(コンテキストはmsgctxt
行に表示されます)、翻訳者はそれらのそれぞれに異なる翻訳。
例えば:
from django.utils.translation import pgettext
month = pgettext("month name", "May")
また:
from django.db import models
from django.utils.translation import pgettext_lazy
class MyThing(models.Model):
name = models.CharField(help_text=pgettext_lazy(
'help text for MyThing model', 'This is the help text'))
.po
ファイルに次のように表示されます。
msgctxt "month name"
msgid "May"
msgstr ""
コンテキストマーカーは、:ttag: `trans` および:ttag:` blocktrans` テンプレートタグでもサポートされています。
怠惰な翻訳
django.utils.translation の遅延バージョンの変換関数(名前のlazy
サフィックスで簡単に認識できます)を使用して、文字列を遅延変換します。再呼び出されました。
これらの関数は、実際の翻訳ではなく、文字列への遅延参照を格納します。 翻訳自体は、テンプレートレンダリングなど、文字列コンテキストで文字列が使用されるときに実行されます。
これは、これらの関数の呼び出しがモジュールのロード時に実行されるコードパスにある場合に不可欠です。
これは、モデル、フォーム、モデルフォームを定義するときに簡単に発生する可能性があります。これは、Djangoがこれらを実装して、フィールドが実際にはクラスレベルの属性になるためです。 そのため、次の場合は必ず遅延翻訳を使用してください。
モデルフィールドと関係verbose_nameおよびhelp_textオプション値
たとえば、次のモデルの name フィールドのヘルプテキストを翻訳するには、次のようにします。
from django.db import models
from django.utils.translation import gettext_lazy as _
class MyThing(models.Model):
name = models.CharField(help_text=_('This is the help text'))
ForeignKey 、 ManyToManyField 、または OneToOneField 関係の名前は、 verbose_name オプションを使用して、翻訳可能としてマークできます。
class MyThing(models.Model):
kind = models.ForeignKey(
ThingKind,
on_delete=models.CASCADE,
related_name='kinds',
verbose_name=_('kind'),
)
verbose_name で行うのと同じように、Djangoは必要に応じて自動的にタイトルケースを付けるため、リレーションに小文字の詳細な名前のテキストを指定する必要があります。
詳細な名前の値をモデル化する
Djangoがモデルのクラス名を調べて実行する冗長な名前のフォールバック英語中心のややナイーブな決定に依存するのではなく、常に明示的な verbose_name および verbose_name_plural オプションを提供することをお勧めします。
from django.db import models
from django.utils.translation import gettext_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 = _('my things')
モデルメソッドshort_description属性値
モデルメソッドの場合、short_description
属性を使用してDjangoと管理サイトに翻訳を提供できます。
from django.db import models
from django.utils.translation import gettext_lazy as _
class MyThing(models.Model):
kind = models.ForeignKey(
ThingKind,
on_delete=models.CASCADE,
related_name='kinds',
verbose_name=_('kind'),
)
def is_mouse(self):
return self.kind.type == MOUSE_TYPE
is_mouse.short_description = _('Is it a mouse?')
怠惰な翻訳オブジェクトの操作
gettext_lazy()
呼び出しの結果は、他のDjangoコードで文字列(str
オブジェクト)を使用する場所ならどこでも使用できますが、任意のPythonコードでは機能しない可能性があります。 たとえば、リクエストライブラリはgettext_lazy
オブジェクトを処理しないため、以下は機能しません。
body = gettext_lazy("I \u2764 Django") # (unicode :heart:)
requests.post('https://example.com/send', data={'body': body})
gettext_lazy()
オブジェクトを非Djangoコードに渡す前にテキスト文字列にキャストすることで、このような問題を回避できます。
requests.post('https://example.com/send', data={'body': str(body)})
長いgettext_lazy
名が気に入らない場合は、次のように_
(アンダースコア)とエイリアスすることができます。
from django.db import models
from django.utils.translation import gettext_lazy as _
class MyThing(models.Model):
name = models.CharField(help_text=_('This is the help text'))
gettext_lazy()
およびngettext_lazy()
を使用して、モデルおよびユーティリティ関数の文字列をマークするのが一般的な操作です。 コードの他の場所でこれらのオブジェクトを操作するときは、オブジェクトをできるだけ遅く変換する必要があるため(正しいロケールが有効になるように)、誤って文字列に変換しないようにする必要があります。 これには、次に説明するヘルパー関数を使用する必要があります。
怠惰な翻訳と複数形
複数形の文字列([u]n[p]gettext_lazy
)に遅延変換を使用する場合、通常、文字列定義の時点でnumber
引数はわかりません。 したがって、number
引数として整数の代わりにキー名を渡すことが許可されています。 次に、number
は、文字列補間中にそのキーの下の辞書で検索されます。 次に例を示します。
from django import forms
from django.utils.translation import ngettext_lazy
class MyForm(forms.Form):
error_message = ngettext_lazy("You only provided %(num)d argument",
"You only provided %(num)d arguments", 'num')
def clean(self):
# ...
if error:
raise forms.ValidationError(self.error_message % {'num': number})
文字列に名前のないプレースホルダーが1つだけ含まれている場合は、number
引数を使用して直接補間できます。
class MyForm(forms.Form):
error_message = ngettext_lazy(
"You provided %d argument",
"You provided %d arguments",
)
def clean(self):
# ...
if error:
raise forms.ValidationError(self.error_message % number)
文字列のフォーマット:format_lazy()
format_string
またはstr.format()
の引数のいずれかに遅延変換オブジェクトが含まれている場合、Pythonのstr.format()
メソッドは機能しません。 代わりに、 django.utils.text.format_lazy()を使用できます。これにより、結果が文字列に含まれている場合にのみstr.format()
メソッドを実行するレイジーオブジェクトが作成されます。 例えば:
from django.utils.text import format_lazy
from django.utils.translation import gettext_lazy
...
name = gettext_lazy('John Lennon')
instrument = gettext_lazy('guitar')
result = format_lazy('{name}: {instrument}', name=name, instrument=instrument)
この場合、result
の遅延変換は、result
自体が文字列で使用されている場合にのみ文字列に変換されます(通常はテンプレートのレンダリング時)。
遅延翻訳における怠惰の他の使用法
翻訳を遅らせたいが、翻訳可能な文字列を引数として別の関数に渡す必要があるその他の場合は、この関数を遅延呼び出し内にラップすることができます。 例えば:
from django.utils.functional import lazy
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
mark_safe_lazy = lazy(mark_safe, str)
そして後で:
lazy_string = mark_safe_lazy(_("<p>My <strong>string!</strong></p>"))
言語のローカライズされた名前
- get_language_info()
get_language_info()
関数は、言語に関する詳細情報を提供します。
>>> from django.utils.translation import activate, get_language_info
>>> activate('fr')
>>> li = get_language_info('de')
>>> print(li['name'], li['name_local'], li['name_translated'], li['bidi'])
German Deutsch Allemand False
辞書のname
、name_local
、およびname_translated
属性には、それぞれ英語、言語自体、および現在のアクティブな言語での言語の名前が含まれています。 bidi
属性は、双方向言語の場合にのみTrueになります。
言語情報のソースはdjango.conf.locale
モジュールです。 この情報への同様のアクセスは、テンプレートコードで利用できます。 下記参照。
国際化:テンプレートコード内
Djangoテンプレートでの翻訳では、2つのテンプレートタグと、Pythonコードとは少し異なる構文が使用されます。 テンプレートにこれらのタグへのアクセスを許可するには、{% load i18n %}
をテンプレートの上部に配置します。 すべてのテンプレートタグと同様に、このタグは、i18n
タグを既にロードしている他のテンプレートから拡張されたテンプレートであっても、翻訳を使用するすべてのテンプレートにロードする必要があります。
警告
翻訳された文字列は、テンプレートでレンダリングされたときにエスケープされません。 これにより、たとえば強調のためにHTMLを翻訳に含めることができますが、潜在的に危険な文字( "
)も変更されずにレンダリングされます。
transテンプレートタグ
{% trans %}
テンプレートタグは、定数文字列(一重引用符または二重引用符で囲まれている)または変数コンテンツのいずれかを変換します。
<title>{% trans "This is the title." %}</title>
<title>{% trans myvar %}</title>
noop
オプションが存在する場合、変数ルックアップは引き続き実行されますが、変換はスキップされます。 これは、将来翻訳が必要になるコンテンツを「スタブアウト」するときに役立ちます。
<title>{% trans "myvar" noop %}</title>
内部的には、インライン翻訳は gettext()呼び出しを使用します。
テンプレート変数(上記のmyvar
)がタグに渡された場合、タグは最初にそのような変数を実行時に文字列に解決し、次にメッセージカタログでその文字列を検索します。
{% trans %}
内の文字列内にテンプレート変数を混在させることはできません。 翻訳に変数(プレースホルダー)を含む文字列が必要な場合は、 :ttag: `{%blocktrans%} ` 代わりは。
翻訳された文字列を表示せずに取得する場合は、次の構文を使用できます。
{% trans "This is the title" as the_title %}
<title>{{ the_title }}</title>
<meta name="description" content="{{ the_title }}">
実際には、これを使用して、テンプレート内の複数の場所で使用できる文字列を取得するか、出力を他のテンプレートタグまたはフィルターの引数として使用できます。
{% trans "starting point" as start %}
{% trans "end point" as end %}
{% trans "La Grande Boucle" as race %}
<h1>
<a href="/" title="{% blocktrans %}Back to '{{ race }}' homepage{% endblocktrans %}">{{ race }}</a>
</h1>
<p>
{% for stage in tour_stages %}
{% cycle start end %}: {{ stage }}{% if forloop.counter|divisibleby:2 %}<br>{% else %}, {% endif %}
{% endfor %}
</p>
{% trans %}
は、context
キーワードを使用したコンテキストマーカーもサポートしています。
{% trans "May" context "month name" %}
blocktransテンプレートタグ
:ttag: `trans` タグとは対照的に、blocktrans
タグを使用すると、プレースホルダーを使用して、リテラルと可変コンテンツで構成される複雑な文を翻訳用にマークできます。
{% blocktrans %}This string will have {{ value }} inside.{% endblocktrans %}
テンプレート式を変換するには(たとえば、オブジェクト属性へのアクセスやテンプレートフィルターの使用)、変換ブロック内で使用するために式をローカル変数にバインドする必要があります。 例:
{% blocktrans with amount=article.price %}
That will cost $ {{ amount }}.
{% endblocktrans %}
{% blocktrans with myvar=value|filter %}
This will have {{ myvar }} inside.
{% endblocktrans %}
1つのblocktrans
タグ内で複数の式を使用できます。
{% blocktrans with book_t=book|title author_t=author|title %}
This is {{ book_t }} by {{ author_t }}
{% endblocktrans %}
ノート
以前のより詳細な形式は引き続きサポートされます:{% blocktrans with book|title as book_t and author|title as author_t %}
他のブロックタグ(たとえば、{% for %}
または{% if %}
)は、blocktrans
タグ内では許可されていません。
ブロック引数の1つが解決に失敗した場合、blocktrans
は、 deactivate_all()関数を使用して現在アクティブな言語を一時的に非アクティブ化することにより、デフォルト言語にフォールバックします。
このタグは、複数形化も提供します。 それを使用するには:
count
という名前のカウンター値を指定してバインドします。 この値は、正しい複数形を選択するために使用される値になります。{% blocktrans %}
タグと{% endblocktrans %}
タグ内の{% plural %}
タグで、単数形と複数形の両方を指定します。
例:
{% blocktrans count counter=list|length %}
There is only one {{ name }} object.
{% plural %}
There are {{ counter }} {{ name }} objects.
{% endblocktrans %}
より複雑な例:
{% blocktrans with amount=article.price count years=i.length %}
That will cost $ {{ amount }} per year.
{% plural %}
That will cost $ {{ amount }} per {{ years }} years.
{% endblocktrans %}
カウンタ値に加えて、複数化機能とローカル変数へのバインド値の両方を使用する場合、blocktrans
構造は内部でngettext
呼び出しに変換されることに注意してください。 これは、ngettext変数に関する同じ注記が適用されることを意味します。
blocktrans
内では逆URLルックアップを実行できないため、事前に取得(および保存)する必要があります。
{% url 'path.to.view' arg arg2 as the_url %}
{% blocktrans %}
This is a URL: {{ the_url }}
{% endblocktrans %}
翻訳された文字列を表示せずに取得する場合は、次の構文を使用できます。
{% blocktrans asvar the_title %}The title is {{ title }}.{% endblocktrans %}
<title>{{ the_title }}</title>
<meta name="description" content="{{ the_title }}">
実際には、これを使用して、テンプレート内の複数の場所で使用できる文字列を取得するか、出力を他のテンプレートタグまたはフィルターの引数として使用できます。
{% blocktrans %}
は、context
キーワードを使用したコンテキストマーカーもサポートしています。
{% blocktrans with name=user.username context "greeting" %}Hi {{ name }}{% endblocktrans %}
{% blocktrans %}
がサポートするもう1つの機能は、trimmed
オプションです。 このオプションは、{% blocktrans %}
タグのコンテンツの最初と最後から改行文字を削除し、行の最初と最後の空白を置き換え、スペース文字を使用してすべての行を1つにマージして区切ります。 これは、{% blocktrans %}
タグのコンテンツをインデントするのに非常に便利です。インデント文字がPOファイルの対応するエントリに含まれることなく、翻訳プロセスが簡単になります。
たとえば、次の{% blocktrans %}
タグ:
{% blocktrans trimmed %}
First sentence.
Second paragraph.
{% endblocktrans %}
trimmed
オプションが指定されていない場合、"\n First sentence.\n Second sentence.\n"
と比較して、POファイルにエントリ"First sentence. Second paragraph."
が生成されます。
テンプレート内の翻訳者へのコメント
Pythonコードと同様に、翻訳者向けのこれらのメモは、:ttag: `comment` タグのいずれかを使用してコメントを使用して指定できます。
{% comment %}Translators: View verb{% endcomment %}
{% trans "View" %}
{% comment %}Translators: Short intro blurb{% endcomment %}
<p>{% blocktrans %}A multiline translatable
literal.{% endblocktrans %}</p>
または{#
…#}
1行コメント構造を使用:
{# Translators: Label of a button that triggers search #}
<button type="submit">{% trans "Go" %}</button>
{# Translators: This is a text of the base template #}
{% blocktrans %}Ambiguous translatable block of text{% endblocktrans %}
ノート
完全を期すために、これらは結果の.po
ファイルの対応するフラグメントです。
#. Translators: View verb
# path/to/template/file.html:10
msgid "View"
msgstr ""
#. Translators: Short intro blurb
# path/to/template/file.html:13
msgid ""
"A multiline translatable"
"literal."
msgstr ""
# ...
#. Translators: Label of a button that triggers search
# path/to/template/file.html:100
msgid "Go"
msgstr ""
#. Translators: This is a text of the base template
# path/to/template/file.html:103
msgid "Ambiguous translatable block of text"
msgstr ""
テンプレートで言語を切り替える
テンプレート内の言語を選択する場合は、language
テンプレートタグを使用できます。
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
<!-- Current language: {{ LANGUAGE_CODE }} -->
<p>{% trans "Welcome to our page" %}</p>
{% language 'en' %}
{% get_current_language as LANGUAGE_CODE %}
<!-- Current language: {{ LANGUAGE_CODE }} -->
<p>{% trans "Welcome to our page" %}</p>
{% endlanguage %}
「Welcometoour page」の最初の出現は現在の言語を使用しますが、2番目の出現は常に英語になります。
国際化:JavaScriptコードで
JavaScriptに翻訳を追加すると、いくつかの問題が発生します。
- JavaScriptコードは、
gettext
実装にアクセスできません。 - JavaScriptコードは、
.po
または.mo
ファイルにアクセスできません。 それらはサーバーによって配信される必要があります。 - JavaScriptの翻訳カタログはできるだけ小さくする必要があります。
Djangoは、これらの問題に対する統合ソリューションを提供します。翻訳をJavaScriptに渡すため、JavaScript内からgettext
などを呼び出すことができます。
これらの問題の主な解決策は、次のJavaScriptCatalog
ビューです。これは、gettext
インターフェイスを模倣する関数と翻訳文字列の配列を含むJavaScriptコードライブラリを生成します。
JavaScriptCatalogビュー
- class JavaScriptCatalog
gettext
インターフェースを模倣する関数と翻訳文字列の配列を備えたJavaScriptコードライブラリを生成するビュー。属性
- domain
ビュー出力に追加する文字列を含む翻訳ドメイン。 デフォルトは
'djangojs'
です。
- packages
インストールされているアプリケーションの中のアプリケーション名のリスト。 これらのアプリには、
locale
ディレクトリが含まれている必要があります。 これらすべてのカタログに加えて、:setting: `LOCALE_PATHS` (常に含まれている)にあるすべてのカタログが1つのカタログにマージされます。 デフォルトはNone
です。これは、すべての:setting: `INSTALLED_APPS` から使用可能なすべての翻訳がJavaScript出力で提供されることを意味します。
デフォルト値の例:
from django.views.i18n import JavaScriptCatalog urlpatterns = [ path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'), ]
カスタムパッケージの例:
urlpatterns = [ path('jsi18n/myapp/', JavaScriptCatalog.as_view(packages=['your.app.label']), name='javascript-catalog'), ]
ルートURLconfが i18n_patterns()を使用する場合、カタログを正しく生成するには、
JavaScriptCatalog
もi18n_patterns()
でラップする必要があります。の例
i18n_patterns()
:from django.conf.urls.i18n import i18n_patterns urlpatterns = i18n_patterns( path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'), )
翻訳の優先順位は、packages
引数の後半に表示されるパッケージが、最初に表示されるパッケージよりも優先されるようになっています。 これは、同じリテラルの翻訳が衝突する場合に重要です。
サイトで複数のJavaScriptCatalog
ビューを使用し、それらの一部が同じ文字列を定義している場合、最後にロードされたカタログ内の文字列が優先されます。
JavaScript翻訳カタログの使用
カタログを使用するには、次のように動的に生成されたスクリプトをプルします。
<script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
これは、逆URLルックアップを使用してJavaScriptカタログビューのURLを検索します。 カタログが読み込まれると、JavaScriptコードは次のメソッドを使用できます。
gettext
ngettext
interpolate
get_format
gettext_noop
pgettext
npgettext
pluralidx
gettext
gettext
関数は、Pythonコード内の標準のgettext
インターフェースと同様に動作します。
document.write(gettext('this is to be translated'));
ngettext
ngettext
関数は、単語やフレーズを複数形にするためのインターフェースを提供します。
var object_count = 1 // or 0, or 2, or 3, ...
s = ngettext('literal for the singular case',
'literal for the plural case', object_count);
interpolate
interpolate
関数は、フォーマット文字列の動的な入力をサポートします。 補間構文はPythonから借用されているため、interpolate
関数は位置補間と名前付き補間の両方をサポートします。
位置補間:
obj
にはJavaScript配列オブジェクトが含まれており、その要素値は、対応する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
と組み合わせて適切な複数形を生成します)。
get_format
get_format
関数は、構成されたi18nフォーマット設定にアクセスし、指定された設定名のフォーマット文字列を取得できます。
document.write(get_format('DATE_FORMAT'));
// 'N j, Y'
次の設定にアクセスできます。
- :setting: `DATE_FORMAT`
- :setting: `DATE_INPUT_FORMATS`
- :setting: `DATETIME_FORMAT`
- :setting: `DATETIME_INPUT_FORMATS`
- :setting: `DECIMAL_SEPARATOR`
- :setting: `FIRST_DAY_OF_WEEK`
- :setting: `MONTH_DAY_FORMAT`
- :setting: `NUMBER_GROUPING`
- :setting: `SHORT_DATE_FORMAT`
- :setting: `SHORT_DATETIME_FORMAT`
- :setting: `THOUSAND_SEPARATOR`
- :setting: `TIME_FORMAT`
- :setting: `TIME_INPUT_FORMATS`
- :setting: `YEAR_MONTH_FORMAT`
これは、Pythonでレンダリングされた値とのフォーマットの一貫性を維持するのに役立ちます。
gettext_noop
これはgettext
関数をエミュレートしますが、何も実行せず、渡されたものをすべて返します。
document.write(gettext_noop('this will not be translated'));
これは、将来変換が必要になるコードの部分をスタブ化するのに役立ちます。
pgettext
pgettext
関数はPythonバリアント( pgettext())のように動作し、文脈に応じて翻訳された単語を提供します。
document.write(pgettext('month name', 'May'));
npgettext
npgettext
関数もPythonバリアント( npgettext())のように動作し、複数のコンテキスト翻訳された単語を提供します。
document.write(npgettext('group', 'party', 1));
// party
document.write(npgettext('group', 'party', 2));
// parties
pluralidx
pluralidx
関数は、:tfilter: `pluralize` テンプレートフィルターと同様に機能し、特定のcount
が複数形の単語を使用するかどうかを決定します。 :
document.write(pluralidx(0));
// true
document.write(pluralidx(1));
// false
document.write(pluralidx(2));
// true
最も単純なケースでは、カスタムの複数化が必要ない場合、整数1
の場合はfalse
を返し、他のすべての数値の場合はtrue
を返します。
ただし、複数化はすべての言語でこれほど単純ではありません。 言語が複数形化をサポートしていない場合は、空の値が提供されます。
さらに、複数化に関する複雑なルールがある場合、カタログビューは条件式をレンダリングします。 これは、true
(複数形にする必要があります)またはfalse
(複数形にする必要はありません)のいずれかの値に評価されます。
JSONCatalogビュー
- class JSONCatalog
別のクライアント側ライブラリを使用して翻訳を処理するには、
JSONCatalog
ビューを利用することをお勧めします。 JavaScriptCatalog に似ていますが、JSON応答を返します。JavaScriptCatalog のドキュメントを参照して、可能な値と
domain
およびpackages
属性の使用法を確認してください。応答形式は次のとおりです。
{ "catalog": { # Translations catalog }, "formats": { # Language formats for date, time, etc. }, "plural": "..." # Expression for plural forms, or null. }
パフォーマンスに関する注意
さまざまなJavaScript / JSON i18nビューは、リクエストごとに.mo
ファイルからカタログを生成します。 その出力は一定であるため、少なくともサイトの特定のバージョンでは、キャッシュの候補として適しています。
サーバー側のキャッシュにより、CPUの負荷が軽減されます。 cache_page()デコレータを使用して簡単に実装できます。 翻訳が変更されたときにキャッシュの無効化をトリガーするには、以下の例に示すように、バージョンに依存するキープレフィックスを指定するか、バージョンに依存するURLにビューをマップします。
from django.views.decorators.cache import cache_page
from django.views.i18n import JavaScriptCatalog
# The value returned by get_version() must change when translations change.
urlpatterns = [
path('jsi18n/',
cache_page(86400, key_prefix='js18n-%s' % get_version())(JavaScriptCatalog.as_view()),
name='javascript-catalog'),
]
クライアント側のキャッシュは帯域幅を節約し、サイトの読み込みを高速化します。 ETag( ConditionalGetMiddleware )を使用している場合は、すでに説明されています。 それ以外の場合は、条件付きデコレータを適用できます。 次の例では、アプリケーションサーバーを再起動するたびにキャッシュが無効になります。
from django.utils import timezone
from django.views.decorators.http import last_modified
from django.views.i18n import JavaScriptCatalog
last_modified_date = timezone.now()
urlpatterns = [
path('jsi18n/',
last_modified(lambda req, **kw: last_modified_date)(JavaScriptCatalog.as_view()),
name='javascript-catalog'),
]
デプロイメント手順の一部としてJavaScriptカタログを事前に生成し、静的ファイルとして提供することもできます。 この急進的な手法は、 django-statici18n に実装されています。
国際化:URLパターンで
Djangoは、URLパターンを国際化するための2つのメカニズムを提供します。
- URLパターンのルートに言語プレフィックスを追加して、 LocaleMiddleware が要求されたURLからアクティブ化する言語を検出できるようにします。
- django.utils.translation.gettext_lazy()関数を使用してURLパターン自体を翻訳可能にします。
警告
これらの機能のいずれかを使用するには、リクエストごとにアクティブな言語を設定する必要があります。 つまり、:setting: `MIDDLEWARE` 設定に django.middleware.locale.LocaleMiddleware が必要です。
URLパターンの言語プレフィックス
- i18n_patterns(*urls, prefix_default_language=True)
この関数はルートURLconfで使用でき、Djangoは i18n_patterns()内で定義されたすべてのURLパターンの前に現在のアクティブな言語コードを自動的に追加します。
prefix_default_language
をFalse
に設定すると、デフォルト言語からプレフィックスが削除されます(:setting: `LANGUAGE_CODE` )。 これは、現在のURLが変更されないように、既存のサイトに翻訳を追加するときに役立ちます。
URLパターンの例:
from django.conf.urls.i18n import i18n_patterns
from django.urls import include, path
from about import views as about_views
from news import views as news_views
from sitemap.views import sitemap
urlpatterns = [
path('sitemap.xml', sitemap, name='sitemap-xml'),
]
news_patterns = ([
path('', news_views.index, name='index'),
path('category/<slug:slug>/', news_views.category, name='category'),
path('<slug:slug>/', news_views.details, name='detail'),
], 'news')
urlpatterns += i18n_patterns(
path('about/', about_views.main, name='about'),
path('news/', include(news_patterns, namespace='news')),
)
これらのURLパターンを定義した後、Djangoはi18n_patterns
関数によって追加されたURLパターンに言語プレフィックスを自動的に追加します。 例:
>>> from django.urls import reverse
>>> from django.utils.translation import activate
>>> activate('en')
>>> reverse('sitemap-xml')
'/sitemap.xml'
>>> reverse('news:index')
'/en/news/'
>>> activate('nl')
>>> reverse('news:detail', kwargs={'slug': 'news-slug'})
'/nl/news/news-slug/'
prefix_default_language=False
およびLANGUAGE_CODE='en'
の場合、URLは次のようになります。
>>> activate('en')
>>> reverse('news:index')
'/news/'
>>> activate('nl')
>>> reverse('news:index')
'/nl/news/'
警告
自動的に追加された言語プレフィックスと衝突する可能性のあるプレフィックスなしのURLパターンがないことを確認してください。
URLパターンの翻訳
gettext_lazy()関数を使用して、URLパターンを翻訳可能としてマークすることもできます。 例:
from django.conf.urls.i18n import i18n_patterns
from django.urls import include, path
from django.utils.translation import gettext_lazy as _
from about import views as about_views
from news import views as news_views
from sitemaps.views import sitemap
urlpatterns = [
path('sitemap.xml', sitemap, name='sitemap-xml'),
]
news_patterns = ([
path('', news_views.index, name='index'),
path(_('category/<slug:slug>/'), news_views.category, name='category'),
path('<slug:slug>/', news_views.details, name='detail'),
], 'news')
urlpatterns += i18n_patterns(
path(_('about/'), about_views.main, name='about'),
path(_('news/'), include(news_patterns, namespace='news')),
)
翻訳を作成した後、 reverse()関数はアクティブな言語でURLを返します。 例:
>>> from django.urls import reverse
>>> from django.utils.translation import activate
>>> activate('en')
>>> reverse('news:category', kwargs={'slug': 'recent'})
'/en/news/category/recent/'
>>> activate('nl')
>>> reverse('news:category', kwargs={'slug': 'recent'})
'/nl/nieuws/categorie/recent/'
警告
ほとんどの場合、不注意に翻訳されたURLが翻訳されていないURLと衝突する可能性を回避するために、言語コードでプレフィックスが付けられたパターンのブロック内でのみ翻訳されたURLを使用することをお勧めします( i18n_patterns()を使用)。パターン。
テンプレートの反転
ローカライズされたURLがテンプレートで逆になっている場合、それらは常に現在の言語を使用します。 別の言語のURLにリンクするには、:ttag: `language` テンプレートタグを使用します。 同封のテンプレートセクションで指定された言語を有効にします。
{% load i18n %}
{% get_available_languages as languages %}
{% trans "View this category in:" %}
{% for lang_code, lang_name in languages %}
{% language lang_code %}
<a href="{% url 'category' slug=category.slug %}">{{ lang_name }}</a>
{% endlanguage %}
{% endfor %}
:ttag: `language` タグは、唯一の引数として言語コードを想定しています。
ローカリゼーション:言語ファイルの作成方法
アプリケーションの文字列リテラルが後で翻訳するためにタグ付けされたら、翻訳自体を書き込む(または取得する)必要があります。 これがその仕組みです。
メッセージファイル
最初のステップは、新しい言語のメッセージファイルを作成することです。 メッセージファイルは、単一の言語を表すプレーンテキストファイルであり、使用可能なすべての翻訳文字列と、それらを特定の言語で表現する方法が含まれています。 メッセージファイルのファイル拡張子は.po
です。
Djangoにはツールが付属しています。 :djadmin: `django-admin makemessages ` 、これらのファイルの作成と維持を自動化します。
Gettextユーティリティ
makemessages
コマンド(および後で説明するcompilemessages
)は、GNU gettextツールセットのコマンドxgettext
、msgfmt
、msgmerge
、およびmsguniq
。
サポートされているgettext
ユーティリティの最小バージョンは0.15です。
メッセージファイルを作成または更新するには、次のコマンドを実行します。
django-admin makemessages -l de
…ここで、de
は、作成するメッセージファイルのロケール名です。 たとえば、ブラジルポルトガル語の場合はpt_BR
、オーストリアドイツ語の場合はde_AT
、インドネシア語の場合はid
です。
スクリプトは、次の2つの場所のいずれかから実行する必要があります。
- Djangoプロジェクトのルートディレクトリ(
manage.py
を含むディレクトリ)。 - Djangoアプリの1つのルートディレクトリ。
スクリプトはプロジェクトソースツリーまたはアプリケーションソースツリー上で実行され、翻訳用にマークされたすべての文字列を引き出します( Djangoが翻訳を検出する方法を参照し、:setting: `LOCALE_PATHS` が構成されていることを確認してください正しく)。 ディレクトリlocale/LANG/LC_MESSAGES
にメッセージファイルを作成(または更新)します。 de
の例では、ファイルはlocale/de/LC_MESSAGES/django.po
になります。
プロジェクトのルートディレクトリからmakemessages
を実行すると、抽出された文字列が適切なメッセージファイルに自動的に配布されます。 つまり、locale
ディレクトリを含むアプリのファイルから抽出された文字列は、そのディレクトリの下のメッセージファイルに入れられます。 locale
ディレクトリのないアプリのファイルから抽出された文字列は、:setting: `LOCALE_PATHS` で最初にリストされたディレクトリの下のメッセージファイルに入るか、の場合にエラーを生成します。 X204X]:setting: `LOCALE_PATHS` は空です。
デフォルトでは :djadmin: `django-admin makemessages ` を含むすべてのファイルを調べます.html
、.txt
また.py
ファイル拡張子。 このデフォルトを上書きする場合は、--extension
または-e
オプションを使用して、調べるファイル拡張子を指定します。
django-admin makemessages -l de -e txt
複数の拡張子をカンマで区切るか、-e
または--extension
を複数回使用します。
django-admin makemessages -l de -e html,txt -e xml
Jinja2テンプレートを使用していますか?
:djadmin: `makemessages` はJinja2テンプレートの構文を理解していません。 Jinja2テンプレートを含むプロジェクトから文字列を抽出するには、代わりに Babel から Message Extracting を使用します。
次に、babel.cfg
構成ファイルの例を示します。
# Extraction from Python source files
[python: **.py]
# Extraction from Jinja2 templates
[jinja2: **.jinja]
extensions = jinja2.ext.with_
使用しているすべての拡張機能を必ずリストしてください。 そうしないと、Babelはこれらの拡張機能によって定義されたタグを認識せず、それらを完全に含むJinja2テンプレートを無視します。
Babelは、:djadmin: `makemessages` と同様の機能を提供し、一般的に置き換えることができ、gettext
に依存しません。 詳細については、メッセージカタログの操作に関するドキュメントを参照してください。
gettextがありませんか?
gettext
ユーティリティがインストールされていない場合、:djadmin: `makemessages` は空のファイルを作成します。 その場合は、gettext
ユーティリティをインストールするか、可能な場合は英語のメッセージファイル(locale/en/LC_MESSAGES/django.po
)をコピーして、開始点として使用してください。 それはただの空の翻訳ファイルです。
Windowsで作業していますか?
Windowsを使用していて、:djadmin: `makemessages` が機能するようにGNUgettextユーティリティをインストールする必要がある場合、詳細については、 Windows上のgettext を参照してください。
.po
ファイルのフォーマットは簡単です。 各.po
ファイルには、翻訳保守者の連絡先情報などのメタデータが少し含まれていますが、ファイルの大部分はメッセージのリストです。翻訳文字列と実際に翻訳されたものとの間の単純なマッピングです。特定の言語のテキスト。
たとえば、Djangoアプリにテキスト"Welcome to my site."
の翻訳文字列が含まれている場合、次のようになります。
_("Welcome to my site.")
…それから :djadmin: `django-admin makemessages ` を作成します.po
次のスニペットを含むファイル–メッセージ:
#: path/to/python/module.py:23
msgid "Welcome to my site."
msgstr ""
簡単な説明:
msgid
は、ソースに表示される翻訳文字列です。 変更しないでください。msgstr
は、言語固有の翻訳を配置する場所です。 最初は空なので、変更するのはあなたの責任です。 翻訳の前後に引用符を付けてください。- 便宜上、各メッセージには、
#
で始まり、msgid
行の上にあるコメント行の形式で、翻訳文字列が収集されたファイル名と行番号が含まれています。
長いメッセージは特殊なケースです。 そこでは、msgstr
(またはmsgid
)の直後の最初の文字列は空の文字列です。 次に、コンテンツ自体が1行に1つの文字列として次の数行に書き込まれます。 これらの文字列は直接連結されます。 文字列内の末尾のスペースを忘れないでください。 それ以外の場合は、空白なしで一緒にタックされます!
文字セットに注意してください
gettext
ツールが内部で機能する方法と、Djangoのコアとアプリケーションで非ASCIIソース文字列を許可するため、POのエンコーディングとしてUTF-8を使用する必要がありますファイル(POファイルが作成されるときのデフォルト)。 これは、全員が同じエンコーディングを使用することを意味します。これは、DjangoがPOファイルを処理するときに重要です。
すべてのソースコードとテンプレートで新しい翻訳文字列を再確認し、すべての言語のすべてのメッセージファイルを更新するには、次のコマンドを実行します。
django-admin makemessages -a
メッセージファイルのコンパイル
メッセージファイルを作成した後、そしてそれを変更するたびに、gettext
で使用できるように、より効率的な形式にコンパイルする必要があります。 でこれを行う :djadmin: `django-admin compilemessages ` 効用。
このツールは、使用可能なすべての.po
ファイルに対して実行され、gettext
での使用に最適化されたバイナリファイルである.mo
ファイルを作成します。 実行したのと同じディレクトリ内 :djadmin: `django-admin makemessages ` 、 走る :djadmin: `django-admin compilemessages ` このような:
django-admin compilemessages
それでおしまい。 翻訳を使用する準備が整いました。
Windowsで作業していますか?
Windowsを使用していて、GNU gettextユーティリティをインストールする必要がある場合は、 :djadmin: `django-admin compilemessages ` 作品を参照してください Windowsでのgettext 詳細については。
.poファイル:エンコーディングとBOMの使用法。
DjangoはUTF-8でエンコードされた.po
ファイルのみをサポートし、BOM(Byte Order Mark)はサポートされないため、テキストエディターがデフォルトでファイルの先頭にそのようなマークを追加する場合は、再構成する必要があります。
トラブルシューティング:gettext()は、パーセント記号のある文字列でpython-formatを誤って検出します
場合によっては、パーセント記号の後にスペースが続く文字列や文字列変換タイプ(例: _("10% interest")
)、 gettext()は、文字列にpython-format
のフラグを誤って付けます。
誤ってフラグが付けられた文字列を含むメッセージファイルをコンパイルしようとすると、number of format specifications in 'msgid' and 'msgstr' does not match
や'msgstr' is not a valid Python format string, unlike 'msgid'
のようなエラーメッセージが表示されます。
これを回避するには、2番目のパーセント記号を追加してパーセント記号をエスケープします。
from django.utils.translation import gettext as _
output = _("10%% interest")
または、no-python-format
を使用して、すべてのパーセント記号がリテラルとして扱われるようにすることもできます。
# xgettext:no-python-format
output = _("10% interest")
JavaScriptソースコードからのメッセージファイルの作成
メッセージファイルは、他のDjangoメッセージファイルと同じ方法で作成および更新します。 :djadmin: `django-admin makemessages ` 道具。 唯一の違いは、次のように-d djangojs
パラメータを指定して、gettext用語でドメインと呼ばれるもの(この場合はdjangojs
ドメイン)を明示的に指定する必要があることです。
django-admin makemessages -d djangojs -l de
これにより、ドイツ語のJavaScriptのメッセージファイルが作成または更新されます。 メッセージファイルを更新した後、実行するだけです :djadmin: `django-admin compilemessages ` 通常のDjangoメッセージファイルの場合と同じ方法です。
Windowsのgettext
これは、メッセージIDを抽出するか、メッセージファイル(.po
)をコンパイルする必要がある場合にのみ必要です。 翻訳作業自体は、このタイプの既存のファイルを編集するだけですが、独自のメッセージファイルを作成する場合、または変更されたメッセージファイルをテストまたはコンパイルする場合は、プリコンパイル済みバイナリインストーラーをダウンロードしてください。
xgettext --version
コマンドが正しく機能する限り、他の場所で入手したgettext
バイナリを使用することもできます。 Windowsコマンドプロンプトでコマンドxgettext --version
を入力すると、「xgettext.exeがエラーを生成し、Windowsによって閉じられる」というポップアップウィンドウが表示される場合は、gettext
パッケージでDjango翻訳ユーティリティを使用しないでください。 」。
makemessagesコマンドのカスタマイズ
xgettext
に追加のパラメーターを渡す場合は、カスタム:djadmin: `makemessages` コマンドを作成し、そのxgettext_options
属性をオーバーライドする必要があります。
from django.core.management.commands import makemessages
class Command(makemessages.Command):
xgettext_options = makemessages.Command.xgettext_options + ['--keyword=mytrans']
さらに柔軟性が必要な場合は、カスタム:djadmin: `makemessages` コマンドに新しい引数を追加することもできます。
from django.core.management.commands import makemessages
class Command(makemessages.Command):
def add_arguments(self, parser):
super().add_arguments(parser)
parser.add_argument(
'--extra-keyword',
dest='xgettext_keywords',
action='append',
)
def handle(self, *args, **options):
xgettext_keywords = options.pop('xgettext_keywords')
if xgettext_keywords:
self.xgettext_options = (
makemessages.Command.xgettext_options[:] +
['--keyword=%s' % kwd for kwd in xgettext_keywords]
)
super().handle(*args, **options)
その他
set_languageリダイレクトビュー
- set_language(request)
便宜上、Djangoにはビュー django.views.i18n.set_language()が付属しています。このビューは、ユーザーの言語設定を設定し、特定のURLにリダイレクトするか、デフォルトで前のページに戻ります。
URLconfに次の行を追加して、このビューをアクティブにします。
path('i18n/', include('django.conf.urls.i18n')),
(この例では、ビューが/i18n/setlang/
で使用可能になることに注意してください。)
ビューは、language
パラメーターが要求に設定された状態で、POST
メソッドを介して呼び出されることを想定しています。 セッションサポートが有効になっている場合、ビューはユーザーのセッションで選択した言語を保存します。 また、デフォルトでdjango_language
という名前のCookieに言語の選択を保存します。 (名前は:setting: `LANGUAGE_COOKIE_NAME` 設定で変更できます。)
バージョン2.1で変更:古いバージョンでは、セッションサポートが有効になっていない場合にのみCookieが設定されます。
言語の選択を設定した後、DjangoはPOST
またはGET
データでnext
パラメーターを探します。 それが見つかり、Djangoがそれを安全なURLと見なした場合(つまり、 別のホストを指さず、安全なスキームを使用します)、そのURLへのリダイレクトが実行されます。 そうしないと、リクエストの性質に応じて、DjangoがフォールバックしてReferer
ヘッダーからURLにリダイレクトするか、設定されていない場合は/
にリダイレクトする可能性があります。
- AJAXリクエストの場合、フォールバックは
next
パラメーターが設定されている場合にのみ実行されます。 それ以外の場合は、204ステータスコード(コンテンツなし)が返されます。 - 非AJAXリクエストの場合、フォールバックは常に実行されます。
HTMLテンプレートコードの例を次に示します。
{% load i18n %}
<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}">
<select name="language">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
<input type="submit" value="Go">
</form>
この例では、Djangoはredirect_to
コンテキスト変数でユーザーがリダイレクトされるページのURLを検索します。
アクティブな言語を明示的に設定する
現在のセッションのアクティブな言語を明示的に設定することをお勧めします。 たとえば、ユーザーの言語設定は別のシステムから取得される可能性があります。 django.utils.translation.activate()はすでに紹介されています。 これは現在のスレッドにのみ適用されます。 セッション全体で言語を永続化するには、セッションの LANGUAGE_SESSION_KEY も変更します。
from django.utils import translation
user_language = 'fr'
translation.activate(user_language)
request.session[translation.LANGUAGE_SESSION_KEY] = user_language
通常は両方を使用する必要があります。 django.utils.translation.activate()はこのスレッドの言語を変更し、セッションを変更すると、この設定が今後のリクエストでも保持されます。
セッションを使用していない場合、言語はCookieに保持され、その名前は:setting: `LANGUAGE_COOKIE_NAME` で構成されます。 例えば:
from django.conf import settings
from django.http import HttpResponse
from django.utils import translation
user_language = 'fr'
translation.activate(user_language)
response = HttpResponse(...)
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, user_language)
ビューとテンプレートの外部での翻訳の使用
Djangoは、ビューとテンプレートで使用するための豊富なi18nツールのセットを提供しますが、使用をDjango固有のコードに制限するものではありません。 Djangoの翻訳メカニズムを使用して、任意のテキストをDjangoでサポートされている任意の言語に翻訳できます(もちろん、適切な翻訳カタログが存在する場合)。 翻訳カタログを読み込んでアクティブ化し、テキストを選択した言語に翻訳できますが、翻訳カタログのアクティブ化はスレッドごとに行われ、そのような変更は同じスレッドで実行されているコードに影響するため、元の言語に戻すことを忘れないでください。
例えば:
from django.utils import translation
def welcome_translated(language):
cur_language = translation.get_language()
try:
translation.activate(language)
text = translation.gettext('welcome')
finally:
translation.activate(cur_language)
return text
値'de'
を指定してこの関数を呼び出すと、:setting: `LANGUAGE_CODE` およびミドルウェアによって設定された言語に関係なく、"Willkommen"
が得られます。
特に重要な関数は、現在のスレッドで使用されている言語を返す django.utils.translation.get_language()、翻訳カタログをアクティブ化する django.utils.translation.activate()です。現在のスレッドの場合、および django.utils.translation.check_for_language()は、指定された言語がDjangoでサポートされているかどうかを確認します。
より簡潔なコードを書くのを助けるために、入力時に現在の言語を保存し、終了時にそれを復元するコンテキストマネージャー django.utils.translation.override()もあります。 これにより、上記の例は次のようになります。
from django.utils import translation
def welcome_translated(language):
with translation.override(language):
return translation.gettext('welcome')
実装上の注意
Django翻訳の専門分野
Djangoの翻訳機構は、Pythonに付属する標準のgettext
モジュールを使用します。 gettext
をご存知の場合は、Djangoが翻訳を行う方法でこれらの専門分野に気付くかもしれません。
- 文字列ドメインは
django
またはdjangojs
です。 この文字列ドメインは、共通のメッセージファイルライブラリ(通常は/usr/share/locale/
)にデータを格納するさまざまなプログラムを区別するために使用されます。django
ドメインは、Pythonおよびテンプレートの翻訳文字列に使用され、グローバル翻訳カタログに読み込まれます。djangojs
ドメインは、JavaScript翻訳カタログにのみ使用され、それらが可能な限り小さいことを確認します。 - Djangoは
xgettext
を単独で使用しません。xgettext
とmsgfmt
の周りにPythonラッパーを使用します。 これは主に便宜のためです。
Djangoが言語設定を検出する方法
翻訳を準備したら、またはDjangoに付属の翻訳を使用したいだけの場合は、アプリの翻訳をアクティブ化する必要があります。
舞台裏では、Djangoには、インストール全体、特定のユーザー、またはその両方で、使用する言語を決定する非常に柔軟なモデルがあります。
インストール全体の言語設定を設定するには、:setting: `LANGUAGE_CODE` を設定します。 Djangoは、この言語をデフォルトの翻訳として使用します。ロケールミドルウェアで採用されている方法の1つで、より適切な翻訳が見つからない場合の最後の試みです(以下を参照)。
母国語でDjangoを実行するだけの場合は、:setting: `LANGUAGE_CODE` を設定し、対応するメッセージファイルとそのコンパイル済みバージョン([ X203X] )が存在します。
個々のユーザーに好みの言語を指定させたい場合は、LocaleMiddleware
も使用する必要があります。 LocaleMiddleware
は、リクエストからのデータに基づいて言語を選択できるようにします。 ユーザーごとにコンテンツをカスタマイズします。
LocaleMiddleware
を使用するには、'django.middleware.locale.LocaleMiddleware'
を:setting: `MIDDLEWARE` 設定に追加します。 ミドルウェアの順序が重要であるため、次のガイドラインに従ってください。
- それが最初にインストールされたミドルウェアの1つであることを確認してください。
LocaleMiddleware
はセッションデータを利用するため、SessionMiddleware
の後に来る必要があります。 また、CommonMiddleware
は、要求されたURLを解決するためにアクティブ化された言語を必要とするため、CommonMiddleware
の前に来る必要があります。CacheMiddleware
を使用する場合は、その後にLocaleMiddleware
を付けてください。
たとえば、:setting: `MIDDLEWARE` は次のようになります。
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
]
(ミドルウェアの詳細については、ミドルウェアのドキュメントを参照してください。)
LocaleMiddleware
は、次のアルゴリズムに従って、ユーザーの言語設定を決定しようとします。
まず、要求されたURLで言語プレフィックスを探します。 これは、ルートURLconfで
i18n_patterns
関数を使用している場合にのみ実行されます。 言語プレフィックスとURLパターンを国際化する方法の詳細については、国際化:URLパターンを参照してください。それができない場合は、現在のユーザーのセッションで LANGUAGE_SESSION_KEY キーを探します。
それが失敗すると、Cookieを探します。
使用するCookieの名前は、:setting: `LANGUAGE_COOKIE_NAME` 設定で設定されます。 (デフォルト名は
django_language
です。)それができない場合は、
Accept-Language
HTTPヘッダーを調べます。 このヘッダーはブラウザから送信され、優先度の高い順にサーバーにどの言語を使用するかを通知します。 Djangoは、利用可能な翻訳がある言語が見つかるまで、ヘッダー内の各言語を試します。それができない場合は、グローバル:setting: `LANGUAGE_CODE` 設定を使用します。
ノート:
これらの各場所で、言語設定は標準の言語形式で文字列として使用されることが期待されています。 たとえば、ブラジルポルトガル語は
pt-br
です。基本言語が利用可能であるが、指定されたサブ言語が利用できない場合、Djangoは基本言語を使用します。 たとえば、ユーザーが
de-at
(オーストリアドイツ語)を指定したが、Djangoで使用できるのはde
しかない場合、Djangoはde
を使用します。:setting: `LANGUAGES` 設定にリストされている言語のみを選択できます。 言語の選択を提供された言語のサブセットに制限する場合(アプリケーションがそれらの言語すべてを提供するわけではないため)、:setting: `LANGUAGES` を言語のリストに設定します。 例えば:
LANGUAGES = [ ('de', _('German')), ('en', _('English')), ]
この例では、自動選択に使用できる言語をドイツ語と英語(および
de-ch
やen-us
などのサブ言語)に制限しています。前の箇条書きで説明したように、カスタム:setting: `LANGUAGES` 設定を定義すると、言語名を翻訳文字列としてマークできますが、[の代わりに gettext_lazy()を使用してくださいX199X] gettext()は、循環インポートを回避します。
サンプル設定ファイルは次のとおりです。
from django.utils.translation import gettext_lazy as _ LANGUAGES = [ ('de', _('German')), ('en', _('English')), ]
LocaleMiddleware
がユーザーの設定を決定すると、 HttpRequest ごとにrequest.LANGUAGE_CODE
としてこの設定を使用できるようになります。 ビューコードでこの値を自由に読んでください。 簡単な例を次に示します。
from django.http import HttpResponse
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が翻訳を発見する方法
実行時に、Djangoはリテラル-翻訳のメモリ内統合カタログを構築します。 これを実現するために、コンパイルされたメッセージファイル(.mo
)をロードするためのさまざまなファイルパスを調べる順序と、同じリテラル:
- :setting: `LOCALE_PATHS` にリストされているディレクトリの優先順位が最も高く、最初に表示されるディレクトリの優先順位が後で表示されるディレクトリよりも高くなります。
- 次に、:setting: `INSTALLED_APPS` にリストされているインストール済みアプリのそれぞれに
locale
ディレクトリが存在するかどうかを検索して使用します。 最初に表示されるものは、後で表示されるものよりも優先されます。 - 最後に、
django/conf/locale
でDjangoが提供する基本翻訳がフォールバックとして使用されます。
も参照してください
JavaScriptアセットに含まれるリテラルの翻訳は、類似しているが同一ではないアルゴリズムに従って検索されます。 詳細については、 JavaScriptCatalog を参照してください。
:setting: `FORMAT_MODULE_PATH` も設定している場合は、カスタムフォーマットファイルを:setting:` LOCALE_PATHS` ディレクトリに配置することもできます。
すべての場合において、翻訳を含むディレクトリの名前は、ロケール名表記を使用して名前が付けられることが期待されます。 例えば de
、pt_BR
、es_AR
など。 地域言語バリアントの未翻訳の文字列は、一般言語の翻訳を使用します。 たとえば、翻訳されていないpt_BR
文字列は、pt
翻訳を使用します。
バージョン2.1で変更:上記の汎用言語へのフォールバックが追加されました。
このようにして、独自の翻訳を含むアプリケーションを作成したり、プロジェクトの基本翻訳を上書きしたりできます。 または、複数のアプリから大きなプロジェクトを構築し、すべての翻訳を、作成しているプロジェクトに固有の1つの大きな共通メッセージファイルに入れることもできます。 選択はあなた次第です。
すべてのメッセージファイルリポジトリは同じように構成されています。 彼らです:
- 設定ファイルの:setting: `LOCALE_PATHS` にリストされているすべてのパスで、
<language>/LC_MESSAGES/django.(po|mo)
が検索されます。 $APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)
$PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)
メッセージファイルを作成するには、 :djadmin: `django-admin makemessages ` 道具。 そして、あなたは使用します :djadmin: `django-admin compilemessages ` バイナリを生成する.mo
によって使用されるファイルgettext
。
実行することもできます :djadmin: `django-admin compilemessages --settings = path.to.settings ` コンパイラにあなたのすべてのディレクトリを処理させるために :setting: `LOCALE_PATHS` 設定。
英語以外の基本言語を使用する
Djangoは、翻訳可能なプロジェクトの元の文字列が英語で書かれていることを一般的に想定しています。 別の言語を選択することもできますが、特定の制限に注意する必要があります。
gettext
は、元のメッセージに対して2つの複数形しか提供しないため、基本言語の複数形が英語と異なる場合は、基本言語の翻訳を提供して、すべての複数形を含める必要があります。- 英語のバリアントがアクティブ化され、英語の文字列が欠落している場合、フォールバック言語はプロジェクトの:setting: `LANGUAGE_CODE` ではなく、元の文字列になります。 たとえば、:setting: `LANGUAGE_CODE` がスペイン語に設定され、元の文字列がロシア語で書かれているサイトにアクセスする英語のユーザーには、スペイン語ではなくロシア語のテキストが表示されます。
翻訳者へのコメント
翻訳可能な文字列に関するヒントを翻訳者に提供したい場合は、文字列の前の行に
Translators
キーワードのプレフィックスが付いたコメントを追加できます。例:コメントは、その下にある翻訳可能な構成に関連付けられた結果の
.po
ファイルに表示され、ほとんどの翻訳ツールでも表示されます。ノート
完全を期すために、これは結果の
.po
ファイルの対応するフラグメントです。これはテンプレートでも機能します。 詳細については、テンプレートの翻訳者へのコメントを参照してください。