Tech Hotoke Blog

IT観音とは私のことです。

【Rails】Railsアプリケーションの国際化対応

目的

Railsアプリケーション国際化対応の備忘録として

環境

i18nとは?

ソフトウェアを特定の地域の言語、仕様に縛られることなく、世界各国で共通して利用できるようにすることを意味する「Internationalization」を省略した表記方法。間の「18」は、単語の先頭の"I"と末尾の"n"の間にある文字の数を意味している。単語自体が長いために便宜的に使われる表記方法である。 引用:

I18nとは何? Weblio辞書

アプリケーションの「国際化」

使われるすべての文言やロケール固有の要素 (日付や通貨フォーマットなど) の抽象化までの作業を指す 引用:

Rails 国際化(i18n)API - Railsガイド

一方で、ローカライズ(localization)という言葉もあり具体的な翻訳方法を提供したり、そのためのフォーマットを提供したりすることを指すそうです。

また、Railsフレームワーク内のすべての静的文字列(Active Recordのバリデーションメッセージ、時刻や日付のフォーマットなど)の 国際化部分は既に完了しています。

Railsにおける国際化

  • APIが実装されています。
translate # 訳文を参照する
localize  # DateオブジェクトやTimeオブジェクトを現地のフォーマットに変換する

上のメソッドにはそれぞれ#tと#lという別名メソッドがあるので、以下のように簡潔に書けます。

I18n.t 'store.title'
I18n.l Time.now

config/locales以下にあるすべての.rbファイルと.ymlファイルは、自動的に訳文読み込みパスに追加されます。

en:
  hello: "Hello world"

en=ロケール

hello=キー

enというロケールにおいて、helloというキーがHello Worldという文字列に対応付けられることを意味しています。

また、I18nライブラリでは、Englishをデフォルトのロケールとして扱います。デフォルトのロケールに他の言語を指定しなかった場合は、訳文の検索に:enが使われます。

config/application.rbにおいて、デフォルトのロケールを変更したり訳文読み込みパスを設定したりできます。

config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb, yml}')] #今回はここは特別指定しませんが、例として記載
config.i18n.available_locales = [:en, :ja] #アプリケーションでの利用を許可するロケールのリストを渡す
config.i18n.default_locale = :ja #日本語化させたいので

リクエスト間でロケールを管理する

  • I18n.locale=I18n.with_locale を使わない場合、すべての訳文でデフォルトのロケールが使われます。

  • I18n.localeの設定がすべてのコントローラで一貫していないと、同じスレッドやプロセスによって処理される今後のリクエストにI18n.localeが漏出する可能性があります。

  • I18n.locale =の代わりに、漏出が発生しないI18n.with_localeを利用することもできます。

  • ロケールはApplicationControllerのaround_actionで設定できます。

  around_action :switch_locale

  def switch_locale(&action)
    locale = params[:locale] || I18n.default_locale
    I18n.with_locale(locale, &action)
  end
  

この他にもドメインサブドメインをもとにロケールを変更する設定も可能のようです。

around_actionについて

  • after : アクションの実行後(アクションが実行された後にしか処理されないため、リクエストサイクルで問題が発生した場合は実行されないので注意が必要)
  • before :アクションの実行前(アクションを実行する前に認証を求めるとか)
  • around :アクションの実行前後(フィルタ内のどこかで必ずyieldを実行して、関連付けられたアクションを実行する義務が生じます。フィルタの作業にはレンダリングも含まれる)

参考:

Action Controller の概要 - Railsガイド

ロケールファイルの作成

  • ja.ymlを作成していきます。

  • 今回は、下記のgemを使用します。

github.com

  • rails g i18n_translation jaを実行すると、transration_ja.ymlが生成されるため、これらの内容をja.ymlにコピペします。
ja.yml
---
ja:
  activerecord:
    errors:
      messages:
        record_invalid: 'バリデーションに失敗しました: %{errors}'
        restrict_dependent_destroy:
          has_one: "%{record}が存在しているので削除できません"
          has_many: "%{record}が存在しているので削除できません"
>>>>>>>>>>>transration_ja.yml
    models:
      book: 本

    attributes:
      book:
        author: 著者
        memo: メモ
        picture: 写真
        title: タイトル
<<<<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>独自で追加
  back: 戻る
  edit: 編集
  show: 詳細
  destroy: 削除
  new_book: 新規作成
  editing_book: 編集
  created_success_message: "正常に作成されました"
  updated_success_message: "正常に更新されました"
  destroyed_success_message: "正常に削除されました"
<<<<<<<<<<<<<<<<<<<<<<<<<
  date:
    abbr_day_names:
    - 日
    - 月
    - 火
    - 水
    - 木
    - 金
    - 土
    abbr_month_names:
    - 
    - 1月
    - 2月
    - 3月
    - 4月
    - 5月
    - 6月
    - 7月
    - 8月
    - 9月
    - 10月
    - 11月
    - 12月
    day_names:
    - 日曜日
    - 月曜日
    - 火曜日
    - 水曜日
    - 木曜日
    - 金曜日
    - 土曜日
    formats:
      default: "%Y/%m/%d"
      long: "%Y年%m月%d日(%a)"
      short: "%m/%d"
    month_names:
    - 
    - 1月
    - 2月
    - 3月
    - 4月
    - 5月
    - 6月
    - 7月
    - 8月
    - 9月
    - 10月
    - 11月
    - 12月
    order:
    - :year
    - :month
    - :day
  datetime:
    distance_in_words:
      about_x_hours:
        one: 約1時間
        other: 約%{count}時間
      about_x_months:
        one: 約1ヶ月
        other: 約%{count}ヶ月
      about_x_years:
        one: 約1年
        other: 約%{count}年
      almost_x_years:
        one: 1年弱
        other: "%{count}年弱"
      half_a_minute: 30秒前後
      less_than_x_seconds:
        one: 1秒以内
        other: "%{count}秒未満"
      less_than_x_minutes:
        one: 1分以内
        other: "%{count}分未満"
      over_x_years:
        one: 1年以上
        other: "%{count}年以上"
      x_seconds:
        one: 1秒
        other: "%{count}秒"
      x_minutes:
        one: 1分
        other: "%{count}分"
      x_days:
        one: 1日
        other: "%{count}日"
      x_months:
        one: 1ヶ月
        other: "%{count}ヶ月"
      x_years:
        one: 1年
        other: "%{count}年"
    prompts:
      second: 秒
      minute: 分
      hour: 時
      day: 日
      month: 月
      year: 年
  errors:
    format: "%{attribute}%{message}"
    messages:
      accepted: を受諾してください
      blank: を入力してください
      confirmation: と%{attribute}の入力が一致しません
      empty: を入力してください
      equal_to: は%{count}にしてください
      even: は偶数にしてください
      exclusion: は予約されています
      greater_than: は%{count}より大きい値にしてください
      greater_than_or_equal_to: は%{count}以上の値にしてください
      inclusion: は一覧にありません
      invalid: は不正な値です
      less_than: は%{count}より小さい値にしてください
      less_than_or_equal_to: は%{count}以下の値にしてください
      model_invalid: 'バリデーションに失敗しました: %{errors}'
      not_a_number: は数値で入力してください
      not_an_integer: は整数で入力してください
      odd: は奇数にしてください
      other_than: は%{count}以外の値にしてください
      present: は入力しないでください
      required: を入力してください
      taken: はすでに存在します
      too_long: は%{count}文字以内で入力してください
      too_short: は%{count}文字以上で入力してください
      wrong_length: は%{count}文字で入力してください
    template:
      body: 次の項目を確認してください
      header:
        one: "%{model}にエラーが発生しました"
        other: "%{model}に%{count}個のエラーが発生しました"
  helpers:
    select:
      prompt: 選択してください
    submit:
      create: 登録する
      submit: 保存する
      update: 更新する
  number:
    currency:
      format:
        delimiter: ","
        format: "%n%u"
        precision: 0
        separator: "."
        significant: false
        strip_insignificant_zeros: false
        unit: 円
    format:
      delimiter: ","
      precision: 3
      separator: "."
      significant: false
      strip_insignificant_zeros: false
    human:
      decimal_units:
        format: "%n %u"
        units:
          billion: 十億
          million: 百万
          quadrillion: 千兆
          thousand: 千
          trillion: 兆
          unit: ''
      format:
        delimiter: ''
        precision: 3
        significant: true
        strip_insignificant_zeros: true
      storage_units:
        format: "%n%u"
        units:
          byte: バイト
          eb: EB
          gb: GB
          kb: KB
          mb: MB
          pb: PB
          tb: TB
    percentage:
      format:
        delimiter: ''
        format: "%n%"
    precision:
      format:
        delimiter: ''
  support:
    array:
      last_word_connector: "、"
      two_words_connector: "、"
      words_connector: "、"
  time:
    am: 午前
    formats:
      default: "%Y年%m月%d日(%a) %H時%M分%S秒 %z"
      long: "%Y/%m/%d %H:%M"
      short: "%m/%d %H:%M"
    pm: 午後

あとは、viewファイルに下記のように記載するかtlメソッドを用いて出力すると良い

# activerecord.models.bookを参照
<h1><%= Book.model_name.human%></h1>
# activerecord.attributes.book.titleを参照
 <th><%= Book.human_attribute_name(:title) %></th>

参考