Phoenix: 多言語対応#
Phoenixの多言語対応は Gettext モジュールを用いることで実現できます。
本記事は、Phoenixのデフォルトプロジェクトに Gettext を適用させる流れを通し、多言語対応について説明します。
概要#
Gettext を用いた多言語対応は下図の流れにそって行います。
gettextマクロを*.html.eexや*.ex内の翻訳対象文字列に適用する
翻訳対象文字列をpotファイル [1] に抽出する
potファイルから各言語用のpoファイル [2] を作成する
poファイルに翻訳文字列を記述する
以降、流れの順に説明していきます。
$ mix phx.new my_app --no-ecto
$ tree priv/gettext
priv/gettext/
├── en
│ └── LC_MESSAGES
│ └── errors.po
└── errors.pot
gettextマクロの適用#
Phoenixサーバーの localhost:4000 で表示される "Welcome to Phoenix!" はデフォルトでgettextマクロが適用されています。
該当ファイルは以下のように記述されています。
$ head -2 lib/my_app_web/templates/page/index.html.eex
<section class="phx-hero">
<h1><%= gettext "Welcome to %{name}!", name: "Phoenix" %></h1>
このように多言語対応させる文字列にはgettextマクロを適用する必要があります。
翻訳対象文字列の抽出#
mix gettext.extract
を使うことで翻訳対象文字列をpotファイルに抽出することができます。
$ mix gettext.extract
Compiling 13 files (.ex)
Extracted priv/gettext/default.pot
Extracted priv/gettext/errors.pot
$ cat priv/gettext/default.pot
# 中略
#, elixir-format
#: lib/my_app_web/templates/page/index.html.eex:2
msgid "Welcome to %{name}!"
msgstr ""
各言語用poファイルの作成#
mix gettext.merge
を使うことでpoファイルを作成することができます。
$ mix gettext.merge priv/gettext --locale=ja
Created directory priv/gettext/ja/LC_MESSAGES
Wrote priv/gettext/ja/LC_MESSAGES/errors.po (0 new translations, 0 removed, 0 unchanged, 0 reworded (fuzzy))
Wrote priv/gettext/ja/LC_MESSAGES/default.po (1 new translation, 0 removed, 0 unchanged, 0 reworded (fuzzy))
$ cat priv/gettext/ja/LC_MESSAGES/default.po
# 中略
#, elixir-format
#: lib/my_app_web/templates/page/index.html.eex:2
msgid "Welcome to %{name}!"
msgstr ""
poファイルの翻訳文字列の記述#
poファイルのmsgstrに翻訳文字列を記述します。
$ cat priv/gettext/ja/LC_MESSAGES/default.po
# 中略
#, elixir-format
#: lib/my_app_web/templates/page/index.html.eex:2
msgid "Welcome to %{name}!"
msgstr "%{name}にようこそ!"
デフォルトの言語設定をconfigに追記し、
$ tail -n 5 config/config.exs
config :gettext, :default_locale, "ja" # 追加
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs"
反映を確認します。
mix gettext.extract
, mix gettext.merge
は繰り返し実行可能です。警告
poファイルのmsgidの手作業による追加、変更、削除は禁止されています。
また、poファイルの変更は poedit が便利そうです。
動的な言語切替#
まず、localeを切り替えるPlugを作成します。
$ cat lib/my_app_web/plugs/locale.ex
defmodule MyAppWeb.Plug.Locale do
import Plug.Conn
def init(opts), do: opts
def call(conn, _opts) do
case conn.params["hl"] || get_session(conn, :locale) do
locale when locale in ["en", "ja"] ->
Gettext.put_locale(locale)
put_session(conn, :locale, locale)
_ ->
conn
end
end
end
このPlugをrouterの:browser pipelineに追加します。
head -n 11 lib/my_app_web/router.ex
defmodule MyAppWeb.Router do
use MyAppWeb, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug MyAppWeb.Plug.Locale # 追加
end
このPlug追加により、リクエスト毎にクエリーパラメーターまたはセッション値を確認しlocaleを切り替えるようになります。
あとはUIに以下のようなリンクをつけてやれば、
<li><%= link("English", to: Phoenix.Controller.current_path(@conn, %{hl: "en"})) %></li>
<li><%= link("日本語", to: Phoenix.Controller.current_path(@conn, %{hl: "ja"})) %></li>
となります。
LiveViewの場合#
セッションの値をLiveView側で受け、mountで再度put_localeする必要があります。
@impl true
def mount(params, %{"locale" => locale} = _session, socket) do
Gettext.put_locale(locale)
{:ok, socket}
end
ソースコード#
本記事で作成したPhoenixプロジェクトは以下に配置しています。
参考#
以上です。