最近、mezzanine のソースコードを読んでいて、django-modeltranslation というライブラリの存在を知ったので、紹介したいと思います。
django-modeltranslatioは動的コンテンツのi18n対応を簡単にできるライブラリです
このライブラリを使うと、モデル定義を変更せずに動的コンテンツのi18n対応ができます。
どんなものなのか、実際にサンプルアプリケーションを作って体験してみましょう。
サンプルアプリケーションで使用する環境は以下のとおりです。
Python 3.8.6 Django 2.2.17 django-modeltranslation 0.16 SQLite 3.24.0 サンプルアプリケーションの要件# サンプルアプリケーションの要件は以下のとおりです。
英語・日本語のどちらかの言語で記事を投稿できるニュースサイト ユーザーは自分の言語設定が「英語」なら英語版記事の検索、「日本語」なら日本語版記事の検索を行える 実際に作ってみる# django-modeltranslationのインストール# まず、startproject
コマンドでDjangoプロジェクトを作成し、settings.py
を以下のように編集します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
INSTALLED_APPS = [
'modeltranslation' , # これを追加。必ずdjango.contrib.adminの上に書く。
'django.contrib.admin' ,
'django.contrib.auth' ,
'django.contrib.contenttypes' ,
'django.contrib.sessions' ,
'django.contrib.messages' ,
'django.contrib.staticfiles' ,
]
LANGUAGE_CODE = 'en-us' # ここはデフォルトのままで
# 以下を追加
def gettext (s):
return s
LANGUAGES = (
('ja' , gettext('Japanese' )),
('en' , gettext('English' )),
)
コピー
記事投稿機能のi18n対応# startapp
コマンドでnews
というアプリケーションを追加してみましょう。
モデル定義は以下のとおりです。
1
2
3
4
5
6
from django.db import models
class News (models. Model):
title = models. CharField(max_length= 255 )
text = models. TextField()
コピー
上記モデルは「英語の記事」「日本語の記事」を区別する設計になっていません。このままではi18n対応はできないはずです。
ところが、django-modeltranslationでは直接ソースコードを編集することなく、メタプログラミングでモデル定義を変更させることができます。
news/translation.py
に以下の内容を書いてください。
1
2
3
4
5
6
7
8
9
from modeltranslation.translator import translator, TranslationOptions
from .models import News
class NewsTranslationOptions (TranslationOptions):
fields = ('title' , 'text' )
translator. register(News, NewsTranslationOptions)
コピー
makemigrations
・migrate
コマンド実行後にsqlmigrate
コマンドを実行してテーブル定義を確認してみてください。モデルにはないはずのtitle_ja
・title_en
・text_ja
・text_en
が定義されています。
1
2
3
4
5
6
7
$ ./manage.py sqlmigrate news 0001
BEGIN;
--
-- Create model News
--
CREATE TABLE "news_news" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar( 255) NOT NULL, "title_ja" varchar( 255) NULL, "title_en" varchar( 255) NULL, "text" text NOT NULL, "text_ja" text NULL, "text_en" text NULL) ;
COMMIT;
コピー
ja
・en
は前述のsettings.py
に書いたLANGUAGES
で定義した言語名です。
それでは、News
モデルを利用して実際にニュースを登録してみましょう。shell
コマンドで以下コードを実行してください。
1
2
3
>>> from news.models import News
>>> News. objects. create(title_ja= "木登りできた" , title_en= "I Could Climb a Tree" , text_ja= "上野動物園で6月に誕生したパンダ・シャンシャンが、木登りできるようになった。" , text_en= "Panda Shanshan, born in June at the Ueno Zoo, can now climb trees." )
< News: News object (1 )>
コピー
_ja
・_en
が付いたフィールドを指定して日本語版・英語版のニュースを登録しています。
さて、このデータのtitle
・text
フィールドはどんな内容になっているでしょうか?
1
2
3
4
>>> from news.models import News
>>> n = News. objects. first()
>>> n. title, n. text
('I Could Climb a Tree' , 'Panda Shanshan, born in June at the Ueno Zoo, can now climb trees.' )
コピー
上記例では英語版が表示されましたが、これは現在の言語設定に依存します。言語を'ja'
に変更してもう一度上記コードを実行すると、日本語版が表示されるはずです。
1
2
3
4
5
6
>>> from django.utils.translation import activate
>>> activate('ja' )
>>> from news.models import News
>>> n = News. objects. first()
>>> n. title, n. text
('木登りできた' , '上野動物園で6月に誕生したパンダ・シャンシャンが、木登りできるようになった。' )
コピー
ウェブ上で動的に言語設定を切り替えたい場合はset_language を使います。
記事検索機能のi18n対応# 次に、検索機能を試してみましょう。こちらも言語設定によってどのフィールドを検索対象になるかが変わります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> from django.utils.translation import activate
>>> from news.models import News
>>> # 英語の場合
>>> activate('en-us' )
>>> News. objects. filter(text__icontains= 'panda' )
< MultilingualQuerySet [< News: News object (1 )> ]>
>>> News. objects. filter(text__icontains= 'パンダ' )
< MultilingualQuerySet []>
>>> # 日本語の場合
>>> activate('ja' )
>>> News. objects. filter(text__icontains= 'panda' )
< MultilingualQuerySet []>
>>> News. objects. filter(text__icontains= 'パンダ' )
< MultilingualQuerySet [< News: News object (1 )> ]>
コピー
adminのi18n対応# adminからの記事投稿もi18n対応にできます。news/admin.py
を以下のように編集してください。
1
2
3
4
5
6
7
8
9
10
11
from django.contrib import admin
from modeltranslation.admin import TranslationAdmin
from .models import News
class NewsAdmin (TranslationAdmin):
pass
admin. site. register(News, NewsAdmin)
コピー
すると、http://127.0.0.1:8000/admin/news/news/add/
は以下のような画面になります。
http://127.0.0.1:8000/admin/news/news/add/
の画面
title
・text
フィールドの入力欄は省かれて、title_ja
・title_en
・text_ja
・text_en
だけが入力できるようになっています。
(おまけ)データベース上では title
・text
には何が入っているのか?# dbshell
コマンドで確認してみましょう。
1
2
sqlite> select title, text from news_news;
I Could Climb a Tree|Panda Shanshan, born in June at the Ueno Zoo, can now climb trees.
コピー
こちらは登録時の言語設定の値によって英語・日本語のいずれかが入るようです。上記は言語設定が英語の状態で登録したので英語ですが、日本語に切り替えて登録すると日本語が入っていました。