# Django 5.2.8 ドキュメント

# 翻訳

## 概要

Django プロジェクトを翻訳可能にするためには、Python コードやテンプレートに、多少のフックを加筆しなければなりません。このフックは 翻訳文字列 と呼ばれます。翻訳文字列は Django に「このテキストに対する翻訳が有効な場合、このテキストはエンドユーザの言語に翻訳すべきだ」ということを通知します。翻訳可能な文字列をマークすることは開発者の責任です。システムが翻訳できるのは指定された文字列だけなのです。

Django は、翻訳文字列を メッセージファイル に抽出するユーティリティを提供します。このファイルがあるため、翻訳者が対象の言語において翻訳文字列に対応する文字列を用意することが簡単になります。翻訳者がメッセージファイルの中身を書き終わったら、それをコンパイルしなければなりません。このプロセスは GNU gettext ツー ルキットに依存しています。

これが済めば、 Django はユーザの言語設定に従って、オンザフライでアプリケーションを利用可能な言語に翻訳するようになります。

Django の国際化フックはデフォルトで有効になっており、これは、フレームワークの特定の箇所で i18n に関する小さなオーバーヘッドが発生することを意味します。国際化を使わない場合は、 `USE_I18N = False` を設定ファイルに記述してください。そうすれば Django は国際化の部品を読み込まないようにして多少の最適化をします。

注釈

プロジェクトで翻訳機能が有効になっていることを確認してください (最も早いのは、 `MIDDLEWARE` が `django.middleware.locale.LocaleMiddleware` を含むかどうかチェックすることです) 。まだの場合は、Django はどうやって言語の優先順位を検出するのか？ を参照してください。

## Python コードでの国際化

### 標準的な翻訳

翻訳対象の文字列を関数 `gettext()` で指定します。入力の手間を省くため、この関数は短い別名 `_` としてインポートするのが慣例です。

注釈

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

1. 特定のファイルのデフォルトの翻訳メソッドとして `gettext_lazy()` を使うべき場合もあります。グローバル名前空間に `_()` がないと、開発者はどれが最も適切な翻訳関数かを考えなければなりません。

2. アンダースコア文字 (`_`) は、 Python の対話シェルや doctest で書かれたテストの中では「直前の式の値」を表します。そのため、グローバル名前空間に `_()` をインストールすると、干渉して問題を引き起こします。 `gettext()` を `_()` という名前で明示的に import すれば、この問題を回避できます。

`_` として別名をつけられる関数は？

(`makemessages` で使われる) `xgettext` が動作する方法のせいで、単一の文字列引数を持つ関数のみが `_` として import できます。

- `gettext()`

- `gettext_lazy()`

この例では、`"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 の翻訳文字列検出ユーティリティ `django-admin makemessages` はこれらの文字列を検出できません。詳しくは後の `makemessages` の節で説明します。)

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

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

このテクニックを使うと、言語ごとの翻訳でプレースホルダを並び替えられるようになります。例えば、英語の翻訳文 `"Today is Nobember, 26."` に対して、スペイン語では `"Hoy es 26 de noviembre."` となるように、月と日のプレースホルダの位置を入れ替えることができます。

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

Since string extraction is done by the `xgettext` command, only syntaxes supported by `gettext` are supported by Django. Python f-strings cannot be used directly with `gettext` functions because f-string expressions are evaluated before they reach `gettext`. This means `_(f"Welcome {name}")` will not work as expected, as the variable is substituted before translation occurs. Instead, use named-string interpolation:

    # Good
    _("Welcome %(name)s") % {"name": name}

    # Good
    _("Welcome {name}").format(name=name)

    # Bad
    _(f"Welcome {name}")  # f-string evaluated before translation.

JavaScript のテンプレート文字列を使うには、 `gettext` のバージョン 0.21 以降が必要です。

### 翻訳者へのコメント

翻訳可能な文字列についてのヒントを翻訳者に示したい場合、文字列の直前の行で `Translators` キーワードでプレフィックスされたコメントを追加できます。例えば:

    def my_view(request):
        # Translators: This message appears on the home page only
        output = gettext("Welcome to my site.")

コメントは、後に記述された翻訳可能な文章に関連付けられた、結果の `.po` ファイル内に表示され、ほとんどの翻訳ツールで表示されます。

注釈

完全を期すために示すと、以下が結果として生成される対応する `.po` ファイルの断片です。

    #. Translators: This message appears on the home page only
    # path/to/python/file.py:123
    msgid "Welcome to my site."
    msgstr ""

これはテンプレート内でも動作します。詳しくは テンプレートにおける翻訳者のためのコメント を参照してください。

### no-op (何もしない) として文字列をマークする

Use the function `django.utils.translation.gettext_noop()` to mark a string as a translation string without translating it. The string is later translated from a variable.

ソース言語内に保持すべき構成文字列がある場合、これを使ってください。これは、システムやユーザー (たとえばデータベース内の文字列) を介して交換される一方で、最後の時点 (たとえばユーザに文字列が表示されるとき) で翻訳される必要があるからです。

### 複数形

Use the function `django.utils.translation.ngettext()` to specify pluralized messages.

`ngettext` は 3 つの引数を取ります: 単数形の文字列、複数形の文字列、オブジェクトの数です。

この関数は、Django アプリケーションを数と 複数形 の複雑さが英語で 2 より大きい (その値にかかわらず、単数には 'object'、そして `count` が 1 ではない全ての場合に 'objects' となります。) 言語にローカライズさせる必要がある場合に役立ちます。

例:

    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()` を使うときは、リテラルで挿入される全ての変数に対して単一の名前を使うようにしてください。以下の例で、2 つの翻訳文字列でどのように `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,
    }

`django-admin compilemessages` を実行すると、以下のエラーが発生するでしょう。

    a format specification for argument 'name', as in 'msgstr[0]', doesn't exist in 'msgid'

### 文脈マーカー

Sometimes words have several meanings, such as `"May"` in English, which refers to a month name and to a verb. To enable translators to translate these words correctly in different contexts, you can use the `django.utils.translation.pgettext()` function, or the `django.utils.translation.npgettext()` function if the string needs pluralization. Both take a context string as the first variable.

結果の `.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 ""

文脈マーカーは、`translate` と `blocktranslate` テンプレートタグによってもサポートされています。

### 遅延 (Lazy な) 翻訳

Lazy に、つまり遅延的に、値が呼ばれたときではなくアクセスされたときに文字列を翻訳するためには、`django.utils.translation` (名前の `lazy` 接尾辞ですぐ分かります) の翻訳関数の lazy バージョンを使ってください、

これらの関数は、Lazy な文字列参照を保持します -- 実際の翻訳ではありません。翻訳自体はテンプレートレンダリング内のように、文字列が文字列コンテキスト内で使われるときに行われます。

これらの関数への呼び出しがモジュールのロード時に実行されるコードパスにある場合は、これは不可欠です。

これは、モデル、フォーム、モデルフォームを定義するときに簡単に発生することができるものです。これは、Django がフィールドを実際にクラスレベルの属性にするように実装するためです。 そのため、以下のような場合は lazy な翻訳を使用してください:

#### モデルフィールドとリレーションシップの `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"))

`verbose_name` オプションを使えば、`ForeignKey`、`ManyToManyField` や `OneToOneField` リレーションシップの名前を翻訳可能にできます:

    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")

#### モデルメソッド `description` を `@display` デコレーターに渡す。

モデルメソッドに対しては、`display()` デコレータの `short_description` 引数で Djangoと admin サイトへの翻訳が提供できます。

    from django.contrib import admin
    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"),
        )

        @admin.display(description=_("Is it a mouse?"))
        def is_mouse(self):
            return self.kind.type == MOUSE_TYPE

### 遅延 (Lazyな) 翻訳オブジェクトの使用方法

`gettext_lazy()` 呼び出しの結果は、他の Django コード内で文字列 (`str` オブジェクト) を使うときはいつでも使うことができますが、気まぐれな Python コードでうまく動作しないかもしれません。例えば、requests ライブラリが `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()` を使用してマークすることはよく行われます。これらのオブジェクトをコードの他の場所で扱う際には、誤って文字列に変換しないよう注意する必要があります。なぜなら、これらの変換は可能な限り遅延されるべきだからです（正しいロケールが効果を発揮するため）。これには、次に説明するヘルパー関数の使用が必要です。

#### 遅延翻訳と複数形

複数の文字列に対して遅延翻訳 (`n[p]gettext_lazy`) を使用する場合、一般的に文字列を定義する時点では `number` 引数を知りません。そのため、 `number` 引数に整数ではなくキー名を渡すことが許可されています。そうすると、文字列の補間時に `number` がそのキーの辞書で検索されます。以下に例を示します:

    from django import forms
    from django.core.exceptions import ValidationError
    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 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 ValidationError(self.error_message % number)

#### 文字列のフォーマット: `format_lazy()`

Python's `str.format()` method will not work when either the `format_string` or any of the arguments to `str.format()` contains lazy translation objects. Instead, you can use `django.utils.text.format_lazy()`, which creates a lazy object that runs the `str.format()` method only when the result is included in a string. For example:

    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` 自体が文字列で使用されるとき（通常はテンプレートのレンダリング時）にだけ文字列に変換されます。

#### その他の遅延翻訳の使い方

翻訳を遅らせたいが、翻訳可能な文字列を別の関数の引数として渡さなければならない場合、この関数を遅延 (Lazy) 呼び出しでラップできます。たとえば次のようにします:

    from django.utils.functional import lazy
    from django.utils.translation import gettext_lazy as _

    def to_lower(string):
        return string.lower()

    to_lower_lazy = lazy(to_lower, str)

その後、次のようにします:

    lazy_string = to_lower_lazy(_("My STRING!"))

### 言語のローカライズされた名前

get_language_info(lang_code)

`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

The `name`, `name_local`, and `name_translated` attributes of the dictionary contain the name of the language in English, in the language itself, and in your current active language respectively. The `bidi` attribute is True only for bi-directional languages.

言語情報のソースは `django.conf.locale` モジュールです。テンプレートコードでも、この情報に対して同じようにアクセスできます。以下を参照してください。

## 国際化: テンプレート内

Django テンプレート 内での翻訳は 2 つのテンプレートタグと Pthon コードとはやや異なるシンタックスを使います。テンプレートでこれらのタグを使えるようにするには、`{% load i18n %}` をテンプレートの先頭に対して設置してください。全てのテンプレートタグと同じように、すでに `i18n` をロードしているテンプレートを extend している場合であっても、翻訳を使用する全てのテンプレートでロードする必要があります。

警告

翻訳された文字列はテンプレートでレンダリングされるときにエスケープされません。これにより、たとえば強調のために HTML を翻訳に含めることができますが、潜在的に危険な文字 (`"` など) も変更されずにレンダリングされます。

### `translate` テンプレートタグ

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

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

`noop` オプションが存在する場合、変数はそのままですが翻訳の対象外となります。将来的に翻訳を必要とするコンテンツを "もみ消している" ときに役立ちます:

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

内部的には、インラインの翻訳は `gettext()` 呼び出しを使っています。

テンプレート var (上記の `myvar`) がタグに渡された場合、最初にランタイムで変数から文字列へと解決し、それからメッセージカタログ内でその文字列をルックアップします。

`{% translate %}` 内の文字列でテンプレート変数を混ぜることはできません。翻訳が変数 (プレースホルダ) とともに文字列を必要とする場合は、代わりに `{% blocktranslate %}` を使ってください。

翻訳された文字列を表示させずに取り出したい場合は、以下の構文が使用できます:

    {% translate "This is the title" as the_title %}

    <title>{{ the_title }}</title>
    <meta name="description" content="{{ the_title }}">

実際には、テンプレート内の複数の場所で使用できる文字列を取得したり、他のテンプレートタグやフィルタリングするための引数として出力を使用したりする目的でこれを使うことになるでしょう:

    {% translate "starting point" as start %}
    {% translate "end point" as end %}
    {% translate "La Grande Boucle" as race %}

    <h1>
      <a href="/" title="{% blocktranslate %}Back to '{{ race }}' homepage{% endblocktranslate %}">{{ race }}</a>
    </h1>
    <p>
    {% for stage in tour_stages %}
        {% cycle start end %}: {{ stage }}{% if forloop.counter|divisibleby:2 %}<br>{% else %}, {% endif %}
    {% endfor %}
    </p>

`{% translate %}` は、`context` キーワードを使う 文脈マーカー もサポートしています:

    {% translate "May" context "month name" %}

### `blocktranslate` テンプレートタグ

`translate` タグとは対照的に、 `blocktranslate` タグはプレースホルダーを使うことで、リテラルその他の内容からなる複雑な文章を翻訳できます:

    {% blocktranslate %}This string will have {{ value }} inside.{% endblocktranslate %}

オブジェクトの `object` 属性にアクセスしたり、テンプレートフィルタを使ったりといったテンプレート式を翻訳するには、その式を翻訳ブロック内で使うローカル変数に結びつける必要があります。たとえば、次のようにします:

    {% blocktranslate with amount=article.price %}
    That will cost $ {{ amount }}.
    {% endblocktranslate %}

    {% blocktranslate with myvar=value|filter %}
    This will have {{ myvar }} inside.
    {% endblocktranslate %}

単一の `blocktranslate` タグ内で複数の式を使うこともできます:

    {% blocktranslate with book_t=book|title author_t=author|title %}
    This is {{ book_t }} by {{ author_t }}
    {% endblocktranslate %}

注釈

次のような、冗長な古い書式もまだサポートされています: `{% blocktranslate with book|title as book_t and author|title as author_t %}`

他のブロックタグ (例えば `{% for %}` や `{% if %}`) は `blocktranslate` タグの中では使えません。

ブロック引数の解決に失敗した場合、 `blocktranslate` は `deactivate_all()` 関数を用いて、現在アクティブな言語を一時的に非アクティブにすることで、デフォルトの言語にフォールバックします。

このタグは複数形にも対応しています。使用するには:

- カウンタの値を `count` という名前で指定し結び付けます。この値は正しい複数形の選択に使用されます。

- `{% blocktranslate %}` と `{% endblocktranslate %}` のタグの中で単数形と複数形を `{% plural %}` タグで区切って指定してください。

例:

    {% blocktranslate count counter=list|length %}
    There is {{ counter }} {{ name }} object.
    {% plural %}
    There are {{ counter }} {{ name }} objects.
    {% endblocktranslate %}

より複雑な例:

    {% blocktranslate with amount=article.price count years=i.length %}
    That will cost $ {{ amount }} per year.
    {% plural %}
    That will cost $ {{ amount }} per {{ years }} years.
    {% endblocktranslate %}

カウンターの値の追加に複数化機能とローカル変数への値のバインドの両方を使用する場合、 `blocktranslate` 構文は内部的に `ngettext` 呼び出しに変換されることに注意してください。つまり、 ngettext 変数に関する注意事項 と同じことに気を付ける必要があります。

URLの逆引きは `blocktranslate` 内では行えないので、事前に取得（保存）しておく必要があります:

    {% url 'path.to.view' arg arg2 as the_url %}
    {% blocktranslate %}
    This is a URL: {{ the_url }}
    {% endblocktranslate %}

翻訳された文字列を表示させずに取り出したい場合は、以下の構文が使用できます:

    {% blocktranslate asvar the_title %}The title is {{ title }}.{% endblocktranslate %}
    <title>{{ the_title }}</title>
    <meta name="description" content="{{ the_title }}">

実際には、テンプレート内の複数の場所で使用できる文字列を取得したり、他のテンプレートタグやフィルタリングするための引数として出力を使用したりする目的でこれを使うことになるでしょう:

`{% blocktranslate %}` は、`context` キーワードを使う 文脈マーカー もサポートしています:

    {% blocktranslate with name=user.username context "greeting" %}Hi {{ name }}{% endblocktranslate %}

`{% blocktranslate %}` タグのもう1つの機能は、`trimmed` オプションです。このオプションは、`{% blocktranslate %}` タグのコンテンツの先頭と末尾から改行文字を削除し、行の先頭と末尾の空白を置き換え、すべての行を空白文字で区切って1行に結合します。これは、`{% blocktranslate %}` タグのコンテンツをインデントしても、インデント文字が対応する `.po` ファイルのエントリに含まれないようにするのに非常に便利で、翻訳作業が簡単になります。

例えば、次の `{% blocktranslate %}` タグ:

    {% blocktranslate trimmed %}
      First sentence.
      Second paragraph.
    {% endblocktranslate %}

の出力結果は `.po` ファイル内では `"First sentence. Second paragraph."` となります。対照に、 `trimmed` オプションが指定されていない場合は `"\n First sentence.\n Second paragraph.\n"` となります。

### タグとフィルタに渡される文字列リテラル

タグやフィルタの引数として渡された文字列リテラルは、見慣れた `_()` 構文を使って翻訳できます:

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

この場合、タグもフィルタも翻訳された文字列を見るので、翻訳を意識する必要はありません。

注釈

この例では、個々の文字列 `"yes"` と `"no"` ではなく、`"yes,no"` という文字列が翻訳基盤に渡されます。翻訳された文字列は、フィルタをパースするコードが引数をどう分割するかを知るために、カンマを含む必要があります。たとえば、ドイツ語の翻訳者は文字列 `"yes,no"` を `"ja,nein"` (カンマはそのまま) と翻訳するでしょう。

### テンプレートにおける翻訳者のためのコメント

Pythonコード の場合と同様に、これらの翻訳者向けのメモはコメントを使用して指定できます。`comment` タグを使用する場合がその一例です：

    {% comment %}Translators: View verb{% endcomment %}
    {% translate "View" %}

    {% comment %}Translators: Short intro blurb{% endcomment %}
    <p>{% blocktranslate %}A multiline translatable
    literal.{% endblocktranslate %}</p>

または 一行コメント構文 `{#` ... ... `#}` で:

    {# Translators: Label of a button that triggers search #}
    <button type="submit">{% translate "Go" %}</button>

    {# Translators: This is a text of the base template #}
    {% blocktranslate %}Ambiguous translatable block of text{% endblocktranslate %}

注釈

完全を期すために示すと、以下が結果として生成される対応する `.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>{% translate "Welcome to our page" %}</p>

    {% language 'en' %}
        {% get_current_language as LANGUAGE_CODE %}
        <!-- Current language: {{ LANGUAGE_CODE }} -->
        <p>{% translate "Welcome to our page" %}</p>
    {% endlanguage %}

"Welcome to our page" は、1つめのコードでは現在の言語を使って表示されますが、2つめのコードでは常に英語になります。

### その他のタグ

これらのタグには同時に `{% load i18n %}` が必要です。

#### `get_available_languages`

`{% get_available_languages as LANGUAGES %}` はタプルのリストを返します。最初の要素は言語コード language code で、2番目の要素は言語名 (現在アクティブなロケールに翻訳されたもの) です。

#### `get_current_language`

`{% get_current_language as LANGUAGE_CODE %}` は現在のユーザの優先言語を文字列として返します。たとえば `en-us` です。 Django はどうやって言語の優先順位を検出するのか？ を参照してください。

#### `get_current_language_bidi`

`{% get_current_language_bidi as LANGUAGE_BIDI %}` は現在のロケールの文章を書く方向を返します。もし `True` なら、ヘブライ語やアラビア語などの右から左へ書く言語です。もし `False` なら、英語、フランス語、ドイツ語などの左から右へ書く言語です。

#### `i18n` コンテキストプロセッサ

もし `django.template.context_processors.i18n` コンテキストプロセッサを有効にすると、各 `RequestContext` は上で定義した `LANGUAGES`, `LANGUAGE_CODE`, `LANGUAGE_BIDI` にアクセスできるようになります。

#### `get_language_info`

また、提供されているテンプレートタグとフィルタを使えば、利用可能な言語の情報を取得することもできます。一つの言語に関する情報を取得するには `{% get_language_info %}` タグを使います:

    {% get_language_info for LANGUAGE_CODE as lang %}
    {% get_language_info for "pl" as lang %}

その後、下記のように情報にアクセスできます:

    Language code: {{ lang.code }}<br>
    Name of language: {{ lang.name_local }}<br>
    Name in English: {{ lang.name }}<br>
    Bi-directional: {{ lang.bidi }}
    Name in the active language: {{ lang.name_translated }}

#### `get_language_info_list`

また、`{% get_language_info_list %}` のテンプレートタグを使えば、言語のリスト(例えば `LANGUAGES` で指定されたアクティブな言語)の情報を取得できます。`{% get_language_info_list %}` を使って言語セレクタを表示する方法の例は set_language リダイレクトビューのセクション を参照してください。

`LANGUAGES` 形式のタプルのリストに加え、`{% get_language_info_list %}` は言語コードのリストをサポートしています。これをビューで実行すると:

    context = {"available_languages": ["en", "es", "fr"]}
    return render(request, "mytemplate.html", context)

を使用すると、テンプレート内でそれらの言語のリストをイテレートできます:

    {% get_language_info_list for available_languages as langs %}
    {% for lang in langs %} ... {% endfor %}

#### テンプレートフィルタ

いくつかの便利なフィルタが使えます:

- `{{ LANGUAGE_CODE|language_name }}` ("German")

- `{{ LANGUAGE_CODE|language_name_local }}` ("Deutsch")

- `{{ LANGUAGE_CODE|language_bidi }}` (False)

- `{{ LANGUAGE_CODE|language_name_translated }}` ("německy", when active language is Czech)

## 国際化: JavaScript コード内

JavaScript に対する翻訳には、いくつか問題があります:

- JavaScript コードは `gettext` 実行にアクセスできません。

- JavaScript コードは `.po` や `.mo` ファイルにアクセスできません; サーバーによって配布される必要があります。

- JavaScript 用の翻訳カタログはできる限り小さくなければなりません。

Django には、これらの問題に対する総合的な解決策が用意されています: 翻訳を JavaScript に渡し、`gettext` などを JavaScript 内から呼び出せるようにする方法です。

主な解決策は以下の `JavaScriptCatalog` ビューです。これは、`gettext` を擬似的に再現する関数と翻訳文字列の配列で JavaScript コードライブラリを生成します。

### `JavaScriptCatalog` ビュー

class JavaScriptCatalog

  `gettext` インターフェイスを擬似的に再現する関数と翻訳文字列の配列で、JavaScriptのコードライブラリを生成するビューです。

  属性

  domain

    ビューの出力に追加する文字列を含む翻訳ドメインです。デフォルトは `'djangojs'` です。

  packages

    インストールされたアプリケーション間の `application names` のリストです。これらのアプリケーションは `locale` ディレクトリを含んでいる必要があります。これらのカタログに加えて (常に含まれている) `LOCALE_PATHS` 内で見つかった全てのカタログは、1 つのカタログに統合されます。デフォルトは `None` で、全ての `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 src="{% url 'javascript-catalog' %}"></script>

これは、reverse 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` 関数は単語やフレーズを複数形にするインターフェースを提供します:

    const objectCount = 1 // or 0, or 2, or 3, ...
    const string = ngettext(
        'literal for the singular case',
        'literal for the plural case',
        objectCount
    );

#### `interpolate`

`interpolate` 関数は表示形式の文字列の動的な記入をサポートします。補完の構文は Python を模しているので、`interpolate` 関数は位置および名前付きの補完の両方をサポートします。

- 位置による補完: `obj` は、表示されるのと同じ順番で要素の値が一致する `fmt` プレースホルダ内で連続的に補完される JavaScript Array オブジェクトを含んでいます。例えば:

      const formats = ngettext(
        'There is %s object. Remaining: %s',
        'There are %s objects. Remaining: %s',
        11
      );
      const string = interpolate(formats, [11, 20]);
      // string is 'There are 11 objects. Remaining: 20'

- 名前付きの補完: このモードは `named` パラメータを `true` として渡すことで選択されます。`obj` は JavaScript オブジェクトや結合配列を含みます。例えば:

      const data = {
        count: 10,
        total: 50
      };

      const formats = ngettext(
          'Total: %(total)s, there is %(count)s object',
          'there are %(count)s of a total of %(total)s objects',
          data.count
      );
      const string = interpolate(formats, data, true);

ただし文字列補間は、やり過ぎるべきではありません。これはまだ JavaScript なので、コードは何度も正規表現による置換を行う必要があります。これは Python の文字列補間ほど速くはないので、本当に必要な場合（例えば、`ngettext` と組み合わせて適切な複数形を生成する場合など）に限定してください。

#### `get_format`

`get_format` 関数は設定済みの i18n 表示形式設定にアクセスでき、与えられた設定名に対して表示形式文字列を取り出します:

    document.write(get_format('DATE_FORMAT'));
    // 'N j, Y'

以下の設定に対してアクセスします:

- `DATE_FORMAT`

- `DATE_INPUT_FORMATS`

- `DATETIME_FORMAT`

- `DATETIME_INPUT_FORMATS`

- `DECIMAL_SEPARATOR`

- `FIRST_DAY_OF_WEEK`

- `MONTH_DAY_FORMAT`

- `NUMBER_GROUPING`

- `SHORT_DATE_FORMAT`

- `SHORT_DATETIME_FORMAT`

- `THOUSAND_SEPARATOR`

- `TIME_FORMAT`

- `TIME_INPUT_FORMATS`

- `YEAR_MONTH_FORMAT`

これは、Python によってレンダリングされる値と一貫性を持った表示形式を保守するために役立ちます。

#### `gettext_noop`

これは `gettext` 関数をエミュレートしますが、何もせず、渡されたものをそのまま返します:

    document.write(gettext_noop("this will not be translated"))

これは、将来的に翻訳が必要なコードの部分をもみ消しておくのに役立ちます。

#### `pgettext`

The `pgettext` function behaves like the Python variant (`pgettext()`), providing a contextually translated word:

    document.write(pgettext("month name", "May"))

#### `npgettext`

The `npgettext` function also behaves like the Python variant (`npgettext()`), providing a pluralized contextually translated word:

    document.write(npgettext('group', 'party', 1));
    // party
    document.write(npgettext('group', 'party', 2));
    // parties

#### `pluralidx`

`pluralidx` 関数は `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="jsi18n-%s" % get_version())(
                JavaScriptCatalog.as_view()
            ),
            name="javascript-catalog",
        ),
    ]

クライアントサイドのキャッシュは帯域を節約し、サイトの読み込みを速くします。ETags (`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 つの仕組みが用意されています:

- `LocaleMiddleware` が、リクエストされた URL からアクティブにする言語を検出できるようにするため、URL パターンのルートに言語のプレフィックスを追加します。

- Making URL patterns themselves translatable via the `django.utils.translation.gettext_lazy()` function.

警告

この 2 つのうちどちらを使う場合でも、各リクエストに対してアクティブな言語をセットすることが必要となります; 言い換えれば、`MIDDLEWARE` 設定内に `django.middleware.locale.LocaleMiddleware` を記述しておく必要があります。

### URL パターンにおける言語プレフィックス

i18n_patterns(*urls, prefix_default_language=True)

この関数は、ルートの URLconf で使うことができ、Django は自動的に現在アクティブな言語のコードを `i18n_patterns()` で定義された全ての URL パターンの先頭に追加します。

`prefix_default_language` を `False` にセットすると、デフォルト言語 (`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/'

警告

`i18n_patterns()` はルートの URLconf のみで使うことができます。インクルードされた URLconf で使うと `ImproperlyConfigured` 例外を投げます。

警告

自動的に追加される言語プレフィックスと重複するようなプレフィックスを持った URL パターンにしないように注意してください。

### URL パターンを翻訳する

URL パターンは、`gettext_lazy()` 関数を使って、翻訳可能にマークすることもできます。例えば:

    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/'

警告

ほとんどの場合、（ `i18n_patterns()` を使用して）翻訳されたURLは、言語コードが接頭辞として付けられたパターンのブロック内でのみ使用することが最も良い選択です。不用意に翻訳された URL が翻訳されていない URL パターンと衝突するのを避けるためです。

### テンプレート内で逆引きする

ローカライズされた URL がテンプレート内でリバースされる場合、常に現在の言語が使用されます。他の言語の URL にリンクを貼るには、`language` テンプレートタグを使ってください。これは、テンプレートの囲まれた範囲内で、指定された言語を有効化します:

    {% load i18n %}

    {% get_available_languages as languages %}

    {% translate "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 %}

`language` タグは引数のみとして言語コードを予期します。

## ローカライズ: 言語ファイルを作成する方法

アプリケーションの文字列リテラルが後の翻訳にためにタグづけされ終わったら、翻訳自体を記述する (もしくは取得する) 必要があります。以下は、その方法です。

### メッセージファイル

最初のステップは、新しい言語に対する message file を作成することです。メッセージファイルはプレーンテキストファイルで、単一の言語を記述します。このファイルは、全ての翻訳可能な文字列とそれらがどのように与えられた言語で表示されるかを含みます。メッセージファイルは `.po` ファイル拡張子を持ちます。

Djangoには `django-admin makemessages` というツールが用意してあり、これらのファイルの作成と保全を自動化します。

Gettext ユーティリティ

`makemessages` コマンド (と後述する `compilemessages`) は、GNU gettext ツールセットからのコマンドを使用します: `xgettext`、`msgfmt`、`msgmerge`、`msguniq` です。

サポートされている `gettext` ユーティリティの最小バージョンは 0.19 です。

メッセージファイルを作成または更新するには、以下のコマンドを実行してください:

    django-admin makemessages -l de

...ここでの `de` は作成したいメッセージファイルに対するロケール名 locale name です。例えば、ブラジル系のポルトガル語に対する `pt_BR`、オーストリア系のドイツ語に対する `de_AT`、インドネシアに対する `id` などです。

スクリプトは、2 つの場所のうち 1 つから実行する必要があります:

- Django プロジェクトのルートディレクトリ (`manage.py` を含むところ)。

- Django アプリケーションのルートディレクトリ。

スクリプトは、プロジェクトのソースツリーもしくはアプリケーションのソースツリーを通じて実行され、翻訳用にマークされた全ての文字列 (Djangoはどうやって翻訳を見つけるのか？ を参照して `LOCALE_PATHS` を正しく設定してください) を抽出します。ディレクトリ `locale/LANG/LC_MESSAGES` にメッセージファイルを作成 (もしくは更新) します。`de` の例では、ファイルは `locale/de/LC_MESSAGES/django.po` となります。

プロジェクトのルートディレクトリから `makemessages` を実行したとき、抽出された文字列は自動的に適切なメッセージファイルへと分配されます。つまり、`locale` ディレクトリを含むアプリケーションのファイルから抽出された文字列は、そのディレクトリ下のメッセージファイルに格納されます。`locale` ディレクトリがないアプリケーションのファイルから抽出された文字列は、`LOCALE_PATHS` 内に最初にリストアップされたディレクトリ下にあるメッセージファイルか、もしくは `LOCALE_PATHS` が空の場合はエラーを生成します。

デフォルトでは `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

警告

JavaScript のソースコードからメッセージファイルを作成する とき、 `-e js` ではなく 、特別な `djangojs` ドメインを使用する必要があります。

Jinja2 テンプレートを使う？

`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 は `makemessages` と似たような機能を提供し、一般的に置き換えることができ、 `gettext` に依存しません。より詳しい情報は メッセージカタログの操作 に関するドキュメントを参照してください。

gettext がない？

`gettext` ユーティリティがインストールされていない場合、 `makemessages` は空のファイルを作成します。そのような場合は、 `gettext` ユーティリティをインストールするか、英語のメッセージファイル (`locale/ja/LC_MESSAGES/django.po`) があれば、それをコピーして、空の翻訳ファイルから始めてください。

Windows で動作する？

あなたが Windows を使っていて、`makemessages` が動作するように GNU gettext ユーティリティをインストールする必要がある場合は、Windows での gettext で詳しい情報を参照してください。

各 `.po` ファイルは、翻訳保守者の連絡先情報などのわずかなメタデータを含みますが、大部分は メッセージ のリストです。これは、特定の言語に対する、翻訳文字列と実際の翻訳済みテキストのマッピングです。

例えば以下のように、Django アプリケーションが `"Welcome to my site."` に対する翻訳文字列を含んでいる場合、:

    _("Welcome to my site.")

...それから `django-admin makemessages` は `.po` ファイルを生成し、そのファイルは以下のようなスニペットを含みます -- メッセージ:

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

簡単に説明すると:

- `msgid` は翻訳文字列で、ソース内に存在します。変更しないでください。

- `msgstr` はあなたが言語に対応する翻訳を記述する場所です。これは空の状態から始まるので、変更するのはあなたの役割です。翻訳をクオートで囲むようにしてください。

- 利便性のため、各メッセージは、`#` でプレフィックスされ `msgid` 行の直前に位置するコメント行の形式の中に、翻訳文字列がどこから拾い集められたかを示すファイル名と行数を含みます。

長いメッセージは特殊なケースです。そこでは、`msgstr` (もしくは `msgid`) 直後の最初の文字列は空の文字列です。それからコンテンツ自身が行ごとに 1 つの文字列として次の数行にわたって記述されます。これらの文字列は直接連結されます。文字列内で最後のスペースを忘れないでください; さもなくば、空白スペースなしで接合されることになります！

文字コードを気にしてください

Due to the way the `gettext` tools work internally and because we want to allow non-ASCII source strings in Django's core and your applications, you must use UTF-8 as the encoding for your `.po` files (the default when `.po` files are created). This means that everybody will be using the same encoding, which is important when Django processes the `.po` files.

Fuzzy（あいまいな）エントリー

`makemessages` は翻訳が以前に翻訳された文字列から推測される場合などに、あいまい (fuzzy) としてマークされた翻訳エントリーを生成することがあります。デフォルトでは、あいまいなエントリは `compilemessages` によって処理されません。

新しい翻訳文字列に対して全てのコードとテンプレートを再検査して 全ての 言語に対する全てのメッセージファイルを更新するには、以下を実行してください:

    django-admin makemessages -a

### メッセージファイルをコンパイルする

メッセージファイルを作成した後 -- そして変更を加えたときそれぞれで -- `gettext` による使用のために、より効率的な形式にコンパイルする必要があります。`django-admin compilemessages` ユーティリティを利用してください。

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

    django-admin compilemessages

これで終わりです。翻訳は使う準備ができました。

Windows で動作する？

あなたが Windows を使っていて、`django-admin compilemessages` が動作するように GNU gettext ユーティリティをインストールする必要がある場合は、Windows での gettext で詳しい情報を参照してください。

`.po` ファイル: エンコーディングと BOM の使用

Django は、UTF-8 でエンコードされ BOM (Byte Order Mark) を持たない `.po` ファイルのみをサポートします。そのため、テキストエディタがデフォルトでこれらのマークをファイルの最初に追加した場合、再構成する必要があります。

### トラブルシューティング: `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 メッセージファイルと同じ方法で (`django-admin makemessages` ツールを使って) 作成や更新を行います。唯一の違いは、`-d djangojs` パラメータを提供することによって、gettext 用語がドメインであること (このケースでは `djangojs` ドメイン) を、以下のように明示的に指定する必要があることです:

    django-admin makemessages -d djangojs -l de

これは、ドイツ語に対して JavaScript 用のメッセージファイルを作成または更新します。メッセージファイルの更新後、通常の Django ファイルと同様の方法で `django-admin compilemessages` を実行してください。

### Windows での `gettext`

これはメッセージ ID を抽出したり、メッセージファイル(`.po`)をコンパイルしたい人だけが必要です。翻訳作業そのものは既存のこの種類のファイルを編集することになりますが、独自のメッセージファイルを作成したい場合や、変更したメッセージファイルをテストしたりコンパイルしたりしたい場合は、 コンパイル済みのバイナリインストーラ をダウンロードしてください。

`xgettext --version` コマンドが正しく動作する限り、他の場所で入手した `gettext` バイナリを使うこともできます。Windows のコマンドプロンプトでコマンド `xgettext --version` を入力すると、ポップアップウィンドウに "`xgettext.exe` has generated errors and will be closed by Windows" と表示される場合は、 `gettext` パッケージを使って Django の翻訳ユーティリティを使おうとしないでください。

### `makemessages` コマンドをカスタマイズする

`xgettext` に追加のパラメータを渡したい場合、独自の `makemessages` コマンドを作成して、その `xgettext_options` 属性をオーバーライドする必要があります:

    from django.core.management.commands import makemessages

    class Command(makemessages.Command):
        xgettext_options = makemessages.Command.xgettext_options + ["--keyword=mytrans"]

もっと柔軟に使う必要があるとき場合には、`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/` でビューを利用できるようにしていることに注意してください)。

警告

上記の URL を `i18n_patterns()` 内に含めないようにしてください。正しく動作するためには、それ自身が言語に依存せず独立している必要があります。

このビューは `POST` メソッド経由で呼び出され、 `language` パラメータがリクエスト内に設定されることを想定しています。ビューはデフォルトでは `django_language` という名前のクッキーに言語選択を保存します。（クッキー名は `LANGUAGE_COOKIE_NAME` 設定によって変更できます。）

言語選択を設定した後、Django は `POST` または `GET` データの `next` パラメータを探します。もしそれが見つかり、 Django が安全な URL (つまり、別のホストを指しておらず、安全なスキームを使っている) と判断した場合、その URL へのリダイレクトが実行されます。そうでない場合、 Django はリクエストの性質に応じて、 `Referer` ヘッダの URL にリダイレクトしたり、ヘッダが設定されていない場合は `/` にリダイレクトしたりします:

- リクエストが(`Accept` HTTPヘッダに基づいて)HTMLコンテンツを受け入れる場合、フォールバックは常に実行されます。

- リクエストがHTMLを受け付けない場合、 `next` パラメータが指定されている場合のみフォールバックが実行されます。そうでない場合はステータスコード 204 (No Content) が返されます。

以下は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 を調べます。

### 明示的にアクティブな言語をセットする

You may want to set the active language for the current session explicitly. Perhaps a user's language preference is retrieved from another system, for example. You've already been introduced to `django.utils.translation.activate()`. That applies to the current thread only. To persist the language for the entire session in a cookie, set the `LANGUAGE_COOKIE_NAME` cookie on the response:

    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)

You would typically want to use both: `django.utils.translation.activate()` changes the language for this thread, and setting the cookie makes this preference persist in future requests.

### ビューやテンプレートの外で翻訳を使う

Django はビューやテンプレートで使うための豊富な国際化ツールセットを提供していますが、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'` という値で呼び出すと、 `LANGUAGE_CODE` やミドルウェアで設定されている言語に関係なく、 `"Willkommen"` が返されます。

Functions of particular interest are `django.utils.translation.get_language()` which returns the language used in the current thread, `django.utils.translation.activate()` which activates a translation catalog for the current thread, and `django.utils.translation.check_for_language()` which checks if the given language is supported by Django.

To help write more concise code, there is also a context manager `django.utils.translation.override()` that stores the current language on enter and restores it on exit. With it, the above example becomes:

    from django.utils import translation

    def welcome_translated(language):
        with translation.override(language):
            return translation.gettext("welcome")

### 言語クッキー

言語クッキーのオプションを調整するには、多くの設定が使用できます:

- `LANGUAGE_COOKIE_NAME`

- `LANGUAGE_COOKIE_AGE`

- `LANGUAGE_COOKIE_DOMAIN`

- `LANGUAGE_COOKIE_HTTPONLY`

- `LANGUAGE_COOKIE_PATH`

- `LANGUAGE_COOKIE_SAMESITE`

- `LANGUAGE_COOKIE_SECURE`

## 実装時のためのノート

### Djangoの翻訳の特徴

Django の翻訳システムは Python に付属している標準の `gettext` モジュールを使います。 `gettext` を知っていれば、Django が翻訳を行う方法について、以下のような特徴があることに気づくかもしれません:

- 文字列ドメインは `django` または `djangojs` です。この文字列ドメインは、共通のメッセージファイルライブラリ (通常は `/usr/share/locale/`) にデータを保存する異なるプログラムを区別するために使用されます。 `django` ドメインは Python とテンプレートの翻訳文字列に使われ、グローバル翻訳カタログに読み込まれます。 `djangojs` ドメインはできるだけ小さくなるように、 JavaScript の翻訳カタログにだけ使われます。

- Django は `xgettext` だけを使っているわけではありません。これは `xgettext` と `msgfmt` を Python でラップしたものです。これは主に利便性のためです。

### Django はどうやって言語の優先順位を検出するのか？

翻訳を準備したら、あるいは Django に付属している翻訳を使いたい場合は、アプリの設定で翻訳を有効にする必要があります。

Djangoは、インストール全体、特定のユーザー、またはその両方に対して、使用する言語を決定する非常に柔軟なモデルを持っています。

インストール全体の優先言語を設定するには、 `LANGUAGE_CODE` を設定してください。Django はこの言語をデフォルトの翻訳として使います。ロケールミドルウェアが採用するメソッド (下記参照) を使って、より適切な翻訳が見つからなかった場合の最終的な翻訳です。

Django を母国語で動かしたいだけなら、 `LANGUAGE_CODE` を設定し、対応する メッセージファイル とそのコンパイルバージョン (`.mo`) が存在することを確認するだけです。

各ユーザに好きな言語を指定させたい場合は、 `LocaleMiddleware` を使用する必要があります。ロケール ミドルウェア `LocaleMiddleware` はリクエストのデータに基づいて言語を選択できるようにします。これは各ユーザのためにコンテンツをカスタマイズします。

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

- 最初にインストールされるミドルウェアの1つであることを確認してください。

- なぜなら `LocaleMiddleware` はセッションデータを利用するからです。また、 `CommonMiddleware` はリクエストされたURLを解決するために有効な言語を必要とするので、 `CommonMiddleware` の前に来る必要があります。

- `CacheMiddleware` を使用する場合は、その後ろに `LocaleMiddleware` を記述してください。

たとえば、`MIDDLEWARE` は次のようになります:

    MIDDLEWARE = [
        "django.contrib.sessions.middleware.SessionMiddleware",
        "django.middleware.locale.LocaleMiddleware",
        "django.middleware.common.CommonMiddleware",
    ]

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

`LocaleMiddleware` は以下のアルゴリズムに従ってユーザーの言語設定を決定しようとします:

- First, it looks for the language prefix in the requested URL. This is only performed when you are using the `i18n_patterns` function in your root URLconf. See 国際化: URL パターン内 for more information about the language prefix and how to internationalize URL patterns.

- それに失敗すれば、クッキーを探します。

  使用されるクッキーの名前は `LANGUAGE_COOKIE_NAME` 設定によって設定されます。(デフォルトの名前は `django_language` です)。

- それに失敗した場合は `Accept-Language` HTTPヘッダを調べます。このヘッダはブラウザから送られ、サーバにどの言語を優先するのかを伝えます。Django は、翻訳可能な言語が見つかるまで、ヘッダの各言語を試します。

- それに失敗すると、グローバルな `LANGUAGE_CODE` 設定を使用します。

メモ:

- これらの場所では、言語設定は標準の 言語コード 文字列で指定します。たとえば、ブラジルポルトガル語は `pt-br` です。

- ベース言語が利用可能で、指定されたサブ言語が利用できない場合、 Django はベース言語を使います。たとえば、ユーザが `de-at` (オーストリアのドイツ語) を指定したが、 Django には `de` しかない場合、 Django は `de` を使います。

- 選択できるのは `LANGUAGES` 設定にリストされている言語だけです。言語選択を提供されている言語のサブセットに制限したい場合(アプリケーションがすべての言語を提供していないため)、 `LANGUAGES` に言語のリストを設定します。たとえば、次のようにします：

      LANGUAGES = [
          ("de", _("German")),
          ("en", _("English")),
      ]

  この例では、自動選択できる言語をドイツ語と英語（および `de-ch` や `en-us` のようなサブ言語）に制限しています。

- 前の箇所で説明したように、カスタムの `LANGUAGES` 設定を定義すれば、言語名を翻訳文字列としてマークできます。ただし、循環インポートを避けるために、 `gettext()` の代わりに `gettext_lazy()` を使ってください。

  以下はサンプルの設定ファイルです:

      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`) を読み込むために異なるファイルパスを調べる順序と、同じリテラルに対して複数の翻訳がある場合の優先順位について、以下のアルゴリズムに従って翻訳を探します:

1. `LOCALE_PATHS` に列挙されているディレクトリが最も優先され、最初に記述されているものが後に記述されているものよりも優先されます。

2. Then, it looks for and uses if it exists a `locale` directory in each of the installed apps listed in `INSTALLED_APPS`. The ones appearing first have higher precedence than the ones appearing later.

3. 最後に、 django/conf/locale にある Django が提供する基本翻訳がフォールバックとして使われます。

参考

JavaScriptアセットに含まれるリテラルの翻訳は同じようなアルゴリズムで検索されますが、同じではありません。詳細は `JavaScriptCatalog` を参照してください。

また、 `FORMAT_MODULE_PATH` を設定すれば、 カスタムフォーマットファイル を `LOCALE_PATHS` ディレクトリに置くこともできます。

すべての場合において、翻訳を含むディレクトリの名前は locale name 表記で指定します。例えば `de`、`pt_BR`、`es_AR` などです。地域言語バリアントの未翻訳の文字列は一般言語の翻訳を使用します。たとえば、未翻訳の `pt_BR` 文字列は `pt` の翻訳を使用します。

こうすることで、独自の翻訳を含むアプリケーションを書くことができ、プロジェクトでベースとなる翻訳を上書きできます。あるいは、いくつかのアプリから大きなプロジェクトを作り、すべての翻訳を、作成中のプロジェクトに特化した1つの大きな共通メッセージファイルにまとめることもできます。選択肢はあなたの自由です。

メッセージ・ファイルのリポジトリはすべて同じ構造になっています。それらは下記のようなものです:

- 設定ファイルの `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)`

メッセージファイルを作成するには `django-admin makemessages` ツールを使用します。また、 `django-admin compilemessages` を使って、 `gettext` が使用するバイナリファイル `.mo` を作成します。

また、 `django-admin compilemessages --settings=path.to.settings` を実行すると、コンパイラが `LOCALE_PATHS` 設定にあるすべてのディレクトリを処理するようになります。

### 英語以外の言語をベース言語として使う

Django は、翻訳可能なプロジェクト内の元の文字列は英語で書かれているという一般的な前提に立っています。他の言語を選ぶこともできますが、ある制限に注意する必要があります:

- `gettext` はオリジナルのメッセージに対して2つの複数形しか提供しないので、もしベース言語の複数形のルールが英語と異なる場合は、すべての複数形を含むようにベース言語の翻訳も提供する必要があります。

- 英語のバージョンが有効になっていて、英語の文字列がない場合、フォールバック言語はプロジェクトの `LANGUAGE_CODE` ではなく、オリジナルの文字列になります。たとえば、`LANGUAGE_CODE` がスペイン語に設定されていて、元の文字列がロシア語で書かれているサイトを訪れた英語のユーザは、スペイン語ではなくロシア語のテキストを見ることになります。