Posted at

Phoenixで多言語化(i18n)

More than 1 year has passed since last update.


環境


  • Phoenix 1.2

  • Elixir 1.3.3


やること

Phoenix標準でサポートされている Gettext でi18nします


Gettextとは

poファイルやpotファイルで多言語化するライブラリです。

ソースファイル中のi18n用関数をmix taskのmix gettext.extractmix gettext.mergeからpoファイル, potファイルを自動的に生成してくれます。


Installation



  • mix.exs に依存を追加

def deps do

[{:gettext, "~> 0.8"}]
end


  • application起動時にgettextも起動するよう変更

def application do

[applications: [:gettext, :logger]]
end


  • 依存を更新

mix deps.get


Usage


  • Gettext用のモジュールを作成

web/gettext.ex

defmodule MyApp.Gettext do

use Gettext, otp_app: :my_app
end



  • gettextを使う

defmodule MyApp.FooBar do

import MyApp.Gettext

def foo do
gettext "foo"
end

def bar do
name = "shufo"
message = "How are you?"
gettext "Hello, %{name}. %{message}", name: name, message: message
end
end



  • potファイル(多言語化のためのテンプレート)を生成

mix gettext.extract

priv/gettext/default.potに以下のようなファイルが生成される

## This file is a PO Template file.

##
## `msgid`s here are often extracted from source code.
## Add new translations manually only if they're dynamic
## translations that can't be statically extracted.
##
## Run `mix gettext.extract` to bring this file up to
## date. Leave `msgstr`s empty as changing them here as no
## effect: edit them in PO (`.po`) files instead.
msgid ""
msgstr ""
"Language: INSERT LANGUAGE HERE\n"

#: web/foobar.ex:5
msgid "foo"
msgstr ""

#: web/foobar.ex:11
msgid "Hello, %{name}. %{message}"
msgstr ""

これを元に各poファイルを生成します



  • poファイル(実際に多言語化するための文言を書き込むファイル)を生成

mix gettext.merge priv/gettext --locale ja

priv/gettext/ja/LC_MESSAGES/default.poに以下のようなファイルが生成されます

## `msgid`s in this file come from POT (.pot) files.

##
## Do not add, change, or remove `msgid`s manually here as
## they're tied to the ones in the corresponding POT file
## (with the same domain).
##
## Use `mix gettext.extract --merge` or `mix gettext.merge`
## to merge POT files into PO files.
msgid ""
msgstr ""
"Language: ja\n"

#: web/foobar.ex:5
msgid "foo"
msgstr "フー"

#: web/foobar.ex:11
msgid "Hello, %{name}. %{message}"
msgstr "こんにちは %{name} さん。%{message}"

Languageがjaとなっているのが分かります。ここに実際の各言語の翻訳を書いていきます。


以降はgettext/1をソース内に記述したら都度mix gettext.extractでテンプレートを更新してmix gettext.merge priv/gettextで各言語ファイルに展開するという作業をします。


デフォルト Locale

これだけではgettextで翻訳を呼び出したとき日本語にならないのでデフォルトのlocaleとしてjaを設定します

config/config.exs

config :my_app, MyApp.Gettext,

default_locale: "ja"

これでデフォルトでlocaleがjaの翻訳ファイルが参照されるようになります。


Localeの切り替え

ユーザの条件やリクエスト時のパラメータによってlocaleを変更するにはPlug等で都度localeをセットします

web/plugs/locale.ex

defmodule MyApp.Plug.Locale do

import Plug.Conn

def init(opts), do: nil

def call(conn, _opts) do
case conn.params["locale"] || get_session(conn, :locale) do
nil -> conn
locale ->
Gettext.put_locale(StreamingChat.Gettext, locale)
conn |> put_session(:locale, locale)
end
end
end

web/router.ex

pipeline :browser do

plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
# 追加
plug MyApp.Plug.Locale
end

これでクエリパラメータにlocaleがある場合やセッションにlocaleが設定されている場合はそちらがlocaleとして設定され対応するpoファイルが読み込まれます


まとめ


  • Gettextでi18nをした


  • mix gettext.extractでテンプレートファイルを生成した後 mix gettext.mergeで実際の多言語化ファイルを生成した

  • デフォルトのlocaleを設定した

  • リクエストパラメータ等によってlocaleを変えるようにした