Rails標準のi18n機能による日本語化まとめ

各ファイルの用途

Ruby on Railsのi18n(国際化)標準機能では、以下の設定ファイル・カタログファイル・Viewテンプレートで多言語カタログを定義できます。

  • config/application.rb: 言語ロケール切り替えを設定するファイル
  • config/locales/*.yml: 各言語の翻訳カタログファイル
  • app/view/*: 一般的なView。テンプレートにカタログを呼び出す関数を実装しておく

この記事では、ネームスペースなどの階層構造を含めて、実利用時に直面するケースをとりあげます。

application.rbのロケール設定

以下の設定は、日本語ロケール指定(1行目)の例。2行目のload_pathは、config/locales以下のサブディレクトリに置いた翻訳カタログファイル(拡張子に.rb, .ymlを指定)を探す設定で、モデルやビュー単位でファイルを分割整理するために有効です。

config.i18n.default_locale = :ja
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]

ロケールの動的切り替え

ロケールは、必要なタイミングでI18n.locale="en"のようにI18nのプロパティを更新することで切り替えられます。

ただし、I18nは全体の設定を切り替える動作となるため、他言語アクセスが混じる場合は、デフォルト値を再設定したいケースが多くあります。

ApplicationControllerに以下のようなフック処理を追加することで、Controllerアクセス時にデフォルトロケールにリセットできます。

# app/controllers/application_controller.rb
before_action :set_locale

def set_locale
    I18n.locale = I18n.default_locale
end

Viewカタログファイルの書式

以下は、翻訳カタログの記載例です。置き場所はapplication.rbのサーチパス内であればどこでも問題ありませんが、Viewの階層構造に沿って整理した方がメンテナンスには有利です。たとえば、 ${RAILS_ROOT}/config/locales/views/admin/users-ja.yml などが有望な例です。

ja:
  admin:
    users:
      index:
        title: ユーザー一覧画面
        name: 氏名
      show:
        title: ユーザー詳細画面
        name: 氏名
        tel: 電話番号
      form:
        register_button: 登録する

ファイルの置き場所はフレキシブルですが、YMLの記述階層はViewの階層構造と一致していないとカタログを適切にひけません。

階層のトップレベルはロケールで、今回のケースではapplication.rbの設定に合わせて”ja”です。本格的に多言語化していく場合では、トップレベルに別言語を指定したファイルを多数用意することになります。

第2階層以下はViewのディレクトリ構造と合わせます。今回は、多層構造の例として、admin/users/以下のViewを日本語化する例を挙げました。Admin::UsersControllerのような namespace付きの階層構造に対応するための記載例です。シンプルなrails g scaffold Userのケースでは、第2階層がusersとなります。

4階層目(上記の例ではindex, show, form)はindex.html.erbなどのテンプレートファイル名に対応しています。

formは rails g scaffold で生成される new.html.erb, edit.html.erb 用の _form.html.erb を指しています。このように partial も各ファイルを指定して和訳していきます。

5階層目が具体的な辞書データです。テンプレートから t('.title')のように呼び出すワードを定義します。左側のラベルは任意に定義できます。

注意事項はタブ文字(¥t)は使えない、などYML特有の記法を守ることです。書式に不備があると実行時にエラーとなります。

Modelカタログファイルの書式

Viewで変数を置き換えることでおおむね日本語化できますが、Modelの日本語化が必要になる部分が一部あります。たとえば、フォームのf.label :nameなどは、Modelの名称をもとにひきあてられます。

ja:
  activerecord:
    models:
      admin/user: ユーザー
    attributes:
      admin/user:
        name: 氏名

第2階層のactiverecordと第3階層のmodels, attributesのキーワードがModel特有の定義です。これも規約に沿って記述しないとうまくカタログをひきあてられないので、決まり文句として記述する必要があります。

先ほどと同様、やや複雑な例としてAdmin::Userモデルの例を記載しています。admin/userという独特のキーワードで階層構造を表現します。シンプルなUserモデルの場合は、4階層目は単にuserになります。

layoutsテンプレートの階層構造

テンプレート内の言語カタログもViewと同じ構造で指定できます。デフォルトのapplication.html.erbの場合は以下のような階層になります。

ja:
  layouts:
    application:
      sitetitle: サイトタイトル

HTMLタグの表示

エスケープせずにHTMLタグを翻訳カタログから表示させたい場合、name_htmlのように”_html”サフィックス(後ろにつける定型文)をつけることでそのままタグが出力されます。(Rails I18n API via Qiita

Viewテンプレートへのタグの埋め込み方

t()という関数を使ってタグを記載することで、Viewテンプレートから翻訳カタログにキーワードをひけます。具体的には<%= t('.name') %>のerbタグは「氏名」などに置き換えられます。ほかにも、link_toの文字列引数などにも指定可能です。

titleタグのローカライゼーション

以上の手順で、個別のファイル内のメッセージを日本語化、多言語化できます。もう1点、共通layoutファイルの多言語化が必要になることが考えられます。典型的なケースは内のタグです。
titleタグは ${RAILS_ROOT}/app/view/layouts/application.html.erb などに共通的に記載されますが、ページ別の内容を表示する必要があります。そのために、個別ページのテンプレートファイルから、layoutに文字列を供給する実装が必要になります。

共通レイアウトファイルには以下のように記述しておきます。Scaffoldでも同様のコードが生成されると思います。

<title><%= content_for?(:title) ? yield(:title) : "" %>

各ページのテンプレートでは、以下のような定義を記述します。

<% content_for :title do %>
  <%= t('.title') %>
<% end %>

この部分は:titleシンボルに文字列を定義しているだけで、各ページに直接文字列が表示されるわけではありません。
このようにcontent_forのブロックでt()関数を呼び出すことで、各ページの翻訳カタログからtitleキーワードの定義をひけます。

flashメッセージなどの多言語化

ViewやModelのカタログ階層には規約がありますが、規約外のカタログを定義して呼び出すことも可能です。
たとえば、書き込み系の操作の際のflashメッセージを多言語化したい場合、以下のように自分で定義したメッセージ階層で整理しておくと探しやすいでしょう。

ja:
  flash:
    some_function:
      create_success: オブジェクトの作成に成功しました
      update_success: オブジェクトの更新に成功しました
      destroy_success: オブジェクトの削除に成功しました

このようなケースでは、t('flash.some_function.create_success')のようにフルパスでt()関数を呼び出すことで、目的のメッセージをひきあてられます。
関数は長くなってしまいますが、カタログファイルは構造化されるため2言語目以降の対応はしやすくなります。