九保すこひ@フリーランスエンジニア|累計300万PVのブログ運営中
さてさて、この前「意外と簡単!FlaskをHTTPS対応する方法」という記事を投稿したとおり、現在pythonの軽量フレームワーク・flaskでサイト開発を行っています。
すでに必要な機能の開発はほぼ完了しているので、最後に残った「多言語化」をしようとネット上を探してみたところ「Flask-Babel」を使えばいいとのことだったんで、pipでインストールしてコードを書いてみたところ、
flask.ext.babel is deprecated, use flask_babel instead.
というエラーが発生。内容は、
flask.ext.babelはもう使われてねぇんだよー。代わりにflask_babelを使いな!
と言っているので、仕方なく、flask_babelをインポートしてみると、今度は
そんなパッケージねぇよ!
と言われる始末。その後いろいろとチェックしてみたんですけど、時間だけが過ぎてしまって、ついに、
「いやいや、多言語化なんてjson作って該当データ呼び出すだけじゃん・・・もう自分で作るわ(ぷんぷん!)」
ってなったんで、今回は「シンプルにflaskの多言語化する方法」をまとめてみたいと思います。
方法としては、Laravelのようにlang/ja/messages.jsという形でテキストのマッピング・データを格納しておき、以下の形で呼び出すというシンプルなものです。
gettext('messages.app_name')
では、実際の作業を見ていきましょう。
言語の取得コード
といっても、難しいことをするわけじゃなく、リクエスト・ヘッダーの「Accept-Language」を分解して言語コードを取得するだけ。
※以下のコードでは、英語、日本語以外の場合はすべて英語になるようになっています。もっと言語を増やしたい場合は、各自追加してくださいね。
def get_locale(): locale = 'en' languages = request.headers.get('Accept-Language').split(',') for language in languages: locale_long = language.split(';')[0] locale = locale_long.split('-')[0] break if locale not in ['ja', 'en']: locale = 'en' return locale.lower()
言語テキストを取得するコードを書く
def get_text(key): text = '' locale = get_locale() keys = key.split('.') path = APP_DIR +'/lang/'+ locale +'/'+ '/'.join(keys[:-1]) +'.json' try: with open(path) as f: data = json.load(f) text = data[keys[-1]] except: pass return unicode(text)
次にjsonから該当するテキストを取得するコードです。
Laravelのように「messages.app_name」という形でテキストを呼びだせるようにしています。(といっても、文字列フォーマットの代入は使えないですし、多重配列には対応してはいません。あくまでシンプルでいきます)
気をつけなければいけないところは、APP_DIRの部分です。前にも紹介したmod_wsgiで実行すると相対パスがおかしなことになってしまうんで、絶対パスで指定するようにしています。
あとは、returnの部分です。
ローカル環境だと、文字コードでエラーは出なかったのに、サーバーの方ではunicode()をかましてないと以下のようなエラーが発生してしまいました。
'ascii' codec can't encode ...
やはりpythonで日本語を使うときは少し気をつけないとダメですね(笑)
テンプレートからデータを呼び出せるようにする
flaskでは、context_processorを使うとテンプレートから関数を呼び出すことができます。
@app.context_processor def utility_processor(): return dict(get_text=get_text, get_locale=get_locale)
dictの中で、呼び出すキーと関数を指定しています。
つまり、上の例で言うと、
<html lang="{{ get_locale() }}">
という形でデータ取得ができますし、肝心の言語テキストも、
{{ get_text('messages.app_name') }}
と、シンプルな形で置き換えができるようになります。
ちなみに、今回はわかりやすく説明するためにget_text()という名前にしましたが、実際には次のようにアンダーバーだけの関数を作りました。
{{ _('messages.app_name') }}
その場合は、context_processorを以下のように変更してください。
@app.context_processor def utility_processor(): return dict(_=get_text, get_locale=get_locale)
言語マッピングjsonを作る
といっても、これも簡単で、今回の例では、
- lang/ja/messages.js
- lang/en/messages.js
というフォルダ&ファイルを作成して、翻訳テキストを書き込むだけでOKです。
{ "app_name": "サイト名", "top_page": "トップページ" }
なので、もしも、
{{ _('errors.requied') }}
という形でテキストを表示したい場合は、
- lang/ja/errors.js
- lang/en/errors.js
というファイルを作成して同じようにjson内にテキストをかき込んでください。
ということで、今回はシンプルでしたけどflaskの多言語化をやってみました。もしLaravelだったら今後のことを考えてパッケージ化しておくところなんですけど、flaskは今後そこまで利用頻度が高くなさそうなので、今回はここで終了することにしました。(Laravelにはもうすでに素晴らしい多言語化機能がありますしね^^)
ではでは〜。