djangoで多言語対応させる方法

djangoで多言語対応させる方法

プロジェクト直下にlocaleディレクトリを作成

mkdir locale

HTMLの編集

{% load i18n %}はextendsであっても全てのhtmlファイルに記述する。
lang=”{{ LANGUAGE_CODE }}でhtmlタグに現在の言語コードを渡す。
翻訳したい文章を{% trans ‘翻訳したい文章’ %}で囲む。

{% load i18n %}

<!doctype HTML>
<html lang="{{ LANGUAGE_CODE }}">
   <head>
       <meta charset="UTF-8">
   </head>
   <body>
	<h1>{% trans 'こんにちは' %}</h1>
   </body>
</html>

settings.pyの記述

from django.utils.translation import gettext_lazy as _

#ミドルウェアを追加(SessionMiddlewareの後、CommonMiddlewareの前)
MIDDLEWARE = [
   'django.middleware.security.SecurityMiddleware',
   'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',  # ここに追加
   'django.middleware.common.CommonMiddleware',
   'django.middleware.csrf.CsrfViewMiddleware',
   'django.contrib.auth.middleware.AuthenticationMiddleware',
   'django.contrib.messages.middleware.MessageMiddleware',
   'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

USE_I18N = True
#デフォルトは日本語
LANGUAGE_CODE = 'ja'
#その他の言語を追加
LANGUAGES = [
    ('ja', _('日本語')),
    ('en', _('English')),
    ('zh-hans', _('簡体')),
    ('zh-hant', _('繁体')),
]

#翻訳内容を記述するフォルダのパス
LOCALE_PATHS = (
    os.path.join(BASE_DIR, 'locale'),
)


urls.pyの記述

from django.contrib import admin
from django.urls import path, include
from django.conf.urls.i18n import i18n_patterns #追加

urlpatterns = [
    path('admin/', admin.site.urls),
    #アプリケーションを下に移動
]

urlpatterns += i18n_patterns(
    #アプリケーションをこっちに移動させる
    path('accounts/', include('accounts.urls')),
    path('', include('toppage.urls')),
)


全てのアプリケーションのurls.pyに1行追加

これによって、日本語版サイトのURLはhttp://example.com/ja/、英語版サイトのURLはhttp://example.com/en/というように個別にURLが割り当てられるようになる。

from django.urls import path,include

from . import views

app_name = "accounts"
urlpatterns = [
    #追加
    path('i18n/', include('django.conf.urls.i18n')),
    path("signup/", views.signup, name="signup"),
    path("signout/", views.signout, name="signout"),
    path("signin/", views.signin, name="signin"),
    path("changeinfo/", views.changeinfo, name="changeinfo"),
    path("profile/", views.profile, name="profile"),
]


翻訳ファイルの作成

django-admin makemessages -l en のように言語ごとに一つずつ作成する。

localeディレクトリの中に各言語のディレクトリと、それぞれに対応するdjango.poが作られる。

django-admin makemessages -l 言語コード


翻訳ファイルの編集

django.poを編集する。
msgstrに翻訳語の内容を記述していく。

msgid "こんにちは"
msgstr "Hello"


翻訳ファイルの更新

htmlで新たにtransを増やした場合などは以下のコマンドでdjango.poを更新できる。

django-admin makemessages -a


コンパイル

各言語のディレクトリにdjango.moが作成されればHTMLに反映される。

django-admin compilemessages


navなどにリンクを記述すればここで切り替えが行えるようになる(その後のページ移動でも言語は引き継がれる)

<ul class="nav nav-pills">
                        <li class="nav-item dropdown">
                            <a class="nav-link dropdown-toggle text-light" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false">Language</a>
                            <ul class="dropdown-menu">
                                <li><a class="dropdown-item" href="/ja/">日本語</a></li>
                                <li><a class="dropdown-item" href="/en/">English</a></li>
                                <li><a class="dropdown-item" href="/zh-hans/">簡体</a></li>
                                <li><a class="dropdown-item" href="/zh-hant/">繁体</a></li>
                            </ul>
                        </li>
                    </ul>



views.pyやforms.py、models.py内の文字を多言語化する方法

gettextとgettext_lazyを使用する

from django.utils.translation import gettext_lazy, gettext as _

gettextの使用方法

翻訳を即座に評価する関数。
文字列を翻訳し、その結果を返す。
主にPythonコード内で使用され、静的なテキストやメッセージを翻訳するのに適している。

def post(self, request, *args, **kwargs):
        form = ReservationForm(request.POST)
        if request.POST.get("email") != request.POST.get("confirmed_mail"):
            self.request.session['form_data'] = request.POST
            messages.add_message(self.request, messages.WARNING, _("メールアドレスが一致しません"))
            return redirect('reservations:reservation')
        elif form.is_valid():
            form = form.save(commit=False)
            form.request_status = "ongoing"
            form.payment_status = "not_yet"
            if request.user.is_authenticated:
                form.user_id = request.user.id
            form.save()
            self.request.session['form_data'] = None
            return create_checkout_session(request, form.id)
        else:
            messages.add_message(self.request, messages.WARNING, _("予約に失敗しました"))
            return redirect('reservations:reservation')

gettext_lazyの使用方法

テンプレートやモデルのフィールドといった遅延評価が必要なコンテキストで使用。
文字列を翻訳せず、文字列そのものをラップし、テンプレートがレンダリングされる際やモデルのデータがクエリされる際に翻訳を遅延さセル。これにより、適切な言語が選択され、ユーザーに表示されるまで待つことができる。

class ReservationForm(forms.ModelForm):
    confirmed_mail = forms.EmailField(label=('*') + gettext_lazy('メールアドレス再入力'))
    field_order = ['username', 'email', 'confirmed_mail']

    class Meta:
        model = Reservation
        fields = ['username', 'email']
        exclude = ["request_status", "user_id"]
        labels={
            'username':('*') + gettext_lazy('予約で使う名前(英語)'),
            'email': gettext_lazy('お客様メールアドレス'),
            }

同じようにコマンドを打ってdjango.poに反映されれば完了。翻訳内容を記述しても翻訳されない場合はgettextとgettext_lazyの使い分けを間違えている可能性があるので確認する。

#: reservations/forms.py:17
msgid "予約で使う名前(英語)"
msgstr ""

#: reservations/forms.py:18
msgid "お客様メールアドレス"
msgstr ""
...
...


中国語の翻訳を作る時の注意点

中国語の翻訳を作るときはロケール名と言語コードが異なるので注意する。開発環境のmacOSでは特に問題なかったが、本番環境にデプロイするとおそらくlinuxなので大文字と小文字が区別され、うまく翻訳されなかった。

settings.pyでは言語コードzh-hansなど「-」を使うが、ロケールファイルは大文字とアンダーバーでzh_Hansとする必要がある。

LANGUAGES = [
    ('ja', '日本語'),
    ('en', 'English'),
    ('zh-hans', '简体'),
    ('zh-hant', '繁體'),
]
django-admin makemessages -l zh_Hans
django-admin makemessages -l zh_Hant


もしgithubからデプロイするタイプなら、githubもデフォルトでは大文字と小文字のコミット変化を区別しないので、もし以下のコマンドでcore.ignorecase=trueならfalseに変更してからコミットする必要がある。

git config -l --local | grep core.ignorecase
git config core.ignorecase false

Comments

No comments yet. Why don’t you start the discussion?

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です