Django
国際化
サーチ…
構文
- gettext(メッセージ)
- ngettext(単数形、複数形、数字)
- ugettext(メッセージ)
- ungettext(単数形、複数形、数字)
- pgettext(コンテキスト、メッセージ)
- npgettext(コンテキスト、単数、複数、数字)
- gettext_lazy(メッセージ)
- ngettext_lazy(単数形、複数形、数字=なし)
- ugettext_lazy(メッセージ)
- ungettext_lazy(単数形、複数形、数字=なし)
- pgettext_lazy(コンテキスト、メッセージ)
- npgettext_lazy(コンテキスト、単数、複数、数値=なし)
- gettext_noop(メッセージ)
- ugettext_noop(メッセージ)
国際化入門
セットアップ
settings.py
from django.utils.translation import ugettext_lazy as _
USE_I18N = True # Enable Internationalization
LANGUAGE_CODE = 'en' # Language in which original texts are written
LANGUAGES = [ # Available languages
('en', _("English")),
('de', _("German")),
('fr', _("French")),
]
# Make sure the LocaleMiddleware is included, AFTER SessionMiddleware
# and BEFORE middlewares using internationalization (such as CommonMiddleware)
MIDDLEWARE_CLASSES = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
]
文字列を翻訳可能なものとしてマークする
翻訳の最初のステップは、 文字列を翻訳可能としてマークすることです。これはgettext
関数の1つを渡しています(「 構文」セクションを参照 )。たとえば、モデル定義の例を次に示します。
from django.utils.translation import ugettext_lazy as _
# It is common to import gettext as the shortcut `_` as it is often used
# several times in the same file.
class Child(models.Model):
class Meta:
verbose_name = _("child")
verbose_name_plural = _("children")
first_name = models.CharField(max_length=30, verbose_name=_("first name"))
last_name = models.CharField(max_length=30, verbose_name=_("last name"))
age = models.PositiveSmallIntegerField(verbose_name=_("age"))
_()
カプセル化されたすべての文字列は、翻訳可能とマークされるようになりました。印刷時には、選択された言語に関係なく、カプセル化された文字列として常に表示されます(まだ翻訳が利用できないため)。
文字列の翻訳
この例は、翻訳を開始するのに十分です。ほとんどの場合、文字列を翻訳可能と見なして 、プロジェクトの将来の国際化を予測したいだけです。したがって、これは別の例で説明されています。
レイジー対ノンレイジー翻訳
非遅延変換を使用すると、文字列はすぐに変換されます。
>>> from django.utils.translation import activate, ugettext as _
>>> month = _("June")
>>> month
'June'
>>> activate('fr')
>>> _("June")
'juin'
>>> activate('de')
>>> _("June")
'Juni'
>>> month
'June'
怠惰を使用する場合、翻訳は実際に使用されるときにのみ発生します。
>>> from django.utils.translation import activate, ugettext_lazy as _
>>> month = _("June")
>>> month
<django.utils.functional.lazy.<locals>.__proxy__ object at 0x7f61cb805780>
>>> str(month)
'June'
>>> activate('fr')
>>> month
<django.utils.functional.lazy.<locals>.__proxy__ object at 0x7f61cb805780>
>>> "month: {}".format(month)
'month: juin'
>>> "month: %s" % month
'month: Juni'
以下のような場合には、遅延変換を使用する必要があります。
-
_("some string")
が評価されたときに翻訳が有効にならない(言語が選択されていない) - 一部の文字列は、起動時(モデルやフォームフィールド定義などのクラス属性など)でのみ評価されます。
テンプレートによる翻訳
テンプレートで翻訳を有効にするには、 i18n
ライブラリを読み込む必要があります。
{% load i18n %}
基本的な翻訳はtrans
テンプレートタグで行われます。
{% trans "Some translatable text" %}
{# equivalent to python `ugettext("Some translatable text")` #}
trans
テンプレートタグはコンテキストをサポートしています:
{% trans "May" context "month" %}
{# equivalent to python `pgettext("May", "month")` #}
翻訳文字列にプレースホルダを含めるには、次のようにします。
_("My name is {first_name} {last_name}").format(first_name="John", last_name="Doe")
blocktrans
テンプレートタグを使用する必要があります:
{% blocktrans with first_name="John" last_name="Doe" %}
My name is {{ first_name }} {{ last_name }}
{% endblocktrans %}
もちろん、 "John"
と"Doe"
ではなく、変数とフィルタを使用できます。
{% blocktrans with first_name=user.first_name last_name=user.last_name|title %}
My name is {{ first_name }} {{ last_name }}
{% endblocktrans %}
first_name
とlast_name
がすでにコンテキスト内にある場合は、 with
節を省略することもできます。
{% blocktrans %}My name is {{ first_name }} {{ last_name }}{% endblocktrans %}
ただし、「トップレベル」のコンテキスト変数のみを使用できます。 これは動作しません:
{% blocktrans %}
My name is {{ user.first_name }} {{ user.last_name }}
{% endblocktrans %}
これは主に、変数名が翻訳ファイルのプレースホルダとして使用されているためです。
blocktrans
テンプレートタグは複数化も受け入れます。
{% blocktrans count nb=users|length }}
There is {{ nb }} user.
{% plural %}
There are {{ nb }} users.
{% endblocktrans %}
最後に、 i18n
ライブラリに関係なく、翻訳可能な文字列を_("")
構文を使用してテンプレートタグに渡すことができます。
{{ site_name|default:_("It works!") }}
{% firstof var1 var2 _("translatable fallback") %}
これは、関数呼び出し構文を模倣するいくつかの魔法の組み込みdjangoテンプレートシステムですが、これは関数呼び出しではありません。 _("It works!")
に渡されたdefault
文字列としてテンプレートタグ'_("It works!")'
と同様に、その後、翻訳可能な文字列を解析され、 name
変数として解析されることになる"name"
になります文字列として解析されます。
文字列の翻訳
文字列を翻訳するには、翻訳ファイルを作成する必要があります。そのために、djangoは管理コマンドmakemessages
ます。
$ django-admin makemessages -l fr
processing locale fr
上記のコマンドは、インストールされたアプリ内で翻訳可能とマークされたすべての文字列を検出し、フランス語翻訳のために各アプリごとに1つの言語ファイルを作成します。たとえば、翻訳可能な文字列を含むapp myapp
が1つしかない場合、 myapp/locale/fr/LC_MESSAGES/django.po
というファイルが作成されます。このファイルは次のようになります。
# SOME DESCRIPTIVE TITLE
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-07-24 14:01+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: myapp/models.py:22
msgid "user"
msgstr ""
#: myapp/models.py:39
msgid "A user already exists with this email address."
msgstr ""
#: myapp/templates/myapp/register.html:155
#, python-format
msgid ""
"By signing up, you accept our <a href=\"%(terms_url)s\" "
"target=_blank>Terms of services</a>."
msgstr ""
まず、プレースホルダを入力する必要があります(大文字で強調)。その後、文字列を翻訳します。 msgid
はあなたのコードで翻訳可能とマークされた文字列です。 msgstr
あなたは上の文字列の翻訳を書く必要があります。
文字列にプレースホルダが含まれている場合は、それらも翻訳に含める必要があります。たとえば、最新のメッセージを次のように翻訳します。
#: myapp/templates/myapp/register.html:155
#, python-format
msgid ""
"By signing up, you accept our <a href=\"%(terms_url)s\" "
"target=_blank>Terms of services</a>."
msgstr ""
"En vous inscrivant, vous acceptez nos <a href=\"%(terms_url)s\" "
"target=_blank>Conditions d'utilisation</a>"
翻訳ファイルが完成したら、 .po
ファイルを.mo
ファイルにコンパイルする必要があります。これは、 compilemessages
管理コマンドを呼び出すことによって行われます。
$ django-admin compilemessages
それで、翻訳が利用できるようになりました。
コードを変更したときに翻訳ファイルを更新するには、 django-admin makemessages -l fr
再実行します。これにより、 .po
ファイルが更新され、既存の翻訳が維持され、新しい翻訳が追加されます。削除された文字列はコメントで引き続き使用できます。すべての言語の.po
ファイルを更新するには、 django-admin makemessages -a
実行します。 .po
ファイルが更新されたら、 django-admin compilemessages
再度実行して.mo
ファイルを生成することを忘れないでください。
Noopユースケース
(u)gettext_noop
では、実際に翻訳することなく文字列を翻訳可能としてマークすることができます。
典型的な使用例は、開発者向けのメッセージを英語で記録したいが、それをクライアントに(要求された言語で)表示したい場合です。 gettext
に変数を渡すことはできますが、その内容は変数ごとに変わるため、翻訳可能な文字列としては検出されません。 。
# THIS WILL NOT WORK AS EXPECTED
import logging
from django.contrib import messages
logger = logging.getLogger(__name__)
error_message = "Oops, something went wrong!"
logger.error(error_message)
messages.error(request, _(error_message))
エラーメッセージは.po
ファイルには表示されず、手動で追加する必要があることを覚えておく必要があります。これを修正するには、 gettext_noop
を使用しgettext_noop
。
error_message = ugettext_noop("Oops, something went wrong!")
logger.error(error_message)
messages.error(request, _(error_message))
今すぐ文字列"Oops, something went wrong!"
生成されると.po
ファイルで検出され、使用可能になります。エラーは引き続き開発者のために英語で記録されます。
共通の落とし穴
あいまいな翻訳
makemessages
は、翻訳のために見つけた文字列が、すでに存在する翻訳と多少類似していると考えるかもしれません。 .po
ファイルに以下のような特別なfuzzy
コメントを付けてマークするとします:
#: templates/randa/map.html:91
#, fuzzy
msgid "Country"
msgstr "Länderinfo"
翻訳が正しいか、それを修正するために翻訳したとしても、あなたがfuzzy
コメント行を削除しない限り、あなたのプロジェクトを翻訳するためには使用されません。
複数行の文字列
makemessages
は、プレーンテキストからPythonコードまでさまざまな形式のファイルを解析しますが、これらの形式の複数行の文字列を持つ可能性のあるすべての規則に従うようには設計されていません。ほとんどの場合、一行の文字列でうまく動作しますが、次のような構造をしている場合は、
translation = _("firstline"
"secondline"
"thirdline")
それは翻訳のためのfirstline
だけを拾うでしょう。これを解決するには、可能なときに複数行の文字列を使用しないようにします。