Jinja2を導入すれば簡単に国際化できると思ったら大間違いだった。
Jinja2と国際化フレームワークのBabelを使うことで、Djangoの国際化機能と同じようなことが実現できる、
ということだったらしい。何度か「Kay Frameworkにしときゃ良かったか...」と思った。
苦労したけどどうにかこうにか国際化できたので、方法をメモっておく。
ちなみにappengineでJinja2を使う方法については別の記事に書いたのでそちらも良かったらお読みください。
Babelの本サイト(ダウンロードとマニュアル)
http://babel.edgewall.org/
Babelの使い方について参考にさせていただいた記事
http://d.hatena.ne.jp/nullpobug/20100923/1285251361
下記のような方法をとりました。
BabelとJinja2をインストール
Babel用のコマンドを使うのと、BabelでJinja2拡張を使えるようにするためにeasy_installで両方インストール。
easy_install Jinja2 easy_install Babel
それとは別にプロジェクト内でBabelモジュールを使用するので、
Babelのソースをダウンロードしてzip化してプロジェクト内に配置し、パスに追加しておく。
テンプレートを編集
国際化したい文字列を{% trans %}{% endtrans %}で囲んだり、{{ _("") }}で囲んだりします。
この辺はDjangoの国際化と似てる。翻訳文字列内でHTMLタグを使用したい時はtransタグにした方がいいみたい。
翻訳ファイルを作る
ここからBabelの出番。
Babelの設定ファイルを作成し、pybabelコマンドで各言語用の翻訳ファイルを生成します。
Babelの設定ファイルはひとまずプロジェクトの直下に配置。
Jinja2拡張を使えるようにして、pyファイルとhtmlファイルを翻訳対象にしてる。
babel.cfg
[extractors] jinja2 = jinja2.ext.babel_extract [python: **.py] [jinja2: **/templates/**.html] encoding=utf-8 extensions=jinja2.ext.with_
ここからコマンドを色々実行。プロジェクト直下で実行する。
まずextract処理を実行する。これは対象のファイルから翻訳対象の情報を抽出する処理らしい。
pybabel extract -F babel.cfg -o messages.pot .
これでmessages.potというファイルがプロジェクト直下に生成される。
次に言語用のpoファイルを作成する。今回はja。
pybabel init -i messages.pot -d project1/translations -l ja
これで、
プロジェクトディレクトリ/project1/translations/ja/LC_MESSAGES/message.po
が作成されるので、ファイルを開いて翻訳テキストを入力していく。このあたりはDjangoと同じ。
翻訳が終わったら、コンパイルしてmoファイルを作成する。
pybabel compile -d project1/translations
これで、
プロジェクトディレクトリ/project1/translations/ja/LC_MESSAGES/message.mo
が作成される。
テンプレートを変更したら、再extract後、initの代わりにupdateでpoファイルを更新する。
その後でcompileを実行する。
pybabel update -i messages.pot -d project1/translations
テンプレートのレンダリング処理に国際化処理を追加
ここがまだちゃんと書けてないところ。とりあえずjaのみ日本語で表示して、それ以外は英語で表示するようにしてる。
import re import os import jinja2 import werkzeug.urls from babel.support import Translations from babel.core import parse_locale from django.template import defaultfilters as django_filters import appengine_utilities.sessions from project1 import settings class NullUndefined(jinja2.Undefined): def __int__(self): return 0 def __getattr__(self, name): return u"" def render_response(handler, template_name, params): env = jinja2.Environment( loader=jinja2.FileSystemLoader([settings.TEMPLATE_DIR], encoding="utf8"), autoescape=True, undefined=NullUndefined, extensions=[ 'jinja2.ext.with_', 'jinja2.ext.i18n', ] ) env.filters.update({ "linebreaksbr": django_filters.linebreaksbr, "urlencode": werkzeug.urls.url_quote_plus, }) locale = "en_US" if "Accept-Language" in handler.request.headers: langs = handler.request.headers["Accept-Language"] if langs: lang_list = langs.split(",") lang_list = [lang.replace(" ", "") for lang in lang_list] for lang in lang_list: if lang.startswith("ja"): locale = "ja" break trans_file_path = os.path.join(settings.TRANSLATIONS_DIR, locale, 'LC_MESSAGES', 'messages.mo') if os.path.exists(trans_file_path): trans_file = open(trans_file_path, "rb") trans = Translations(trans_file) else: trans = Translations() env.install_gettext_translations(trans) try: template = env.get_template(template_name) except jinja2.TemplateNotFound: raise jinja2.TemplateNotFound(template_name) handler.response.out.write(template.render(params))
スゴロコのトップページだけ国際化してみた。
http://sugolo.co