Elixir
Phoenix

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を変えるようにした