Ruby on Rails Guides: Rails Internationalization (I18n) APIを読んでのメモ。全部網羅してたりはしてないので、気になった方は原文見てください。
基本
I18n.translate "store.title" I18n.localize Time.now # 短縮形 I18n.t "store.title" I18n.l Time.now
- デフォルトのlocaleは:en
- I18n.default_localeでデフォルトのlocaleを変更できる
regional用の設定は特にないので、regional設定がしたい場合は例えばen-usとen-ukディレクトリをそれぞれ作る必要がある。それを助けるプラグインもある。
localeの判別
localeの情報をセッションやクッキーには入れるべきではない。URLの一部として解釈されるべき。友達にURL送ってその友達がそのページを見たら、同じページが見れるべき。
クエリ(またはURLの一部)でlocaleを判別する例
before_filter :set_locale def set_locale # if params[:locale] is nil then I18n.default_locale will be used I18n.locale = params[:locale] end
サブドメインでlocaleを判断する例
before_filter :set_locale def set_locale I18n.locale = extract_locale_from_subdomain end def extract_locale_from_subdomain parsed_locale = request.subdomains.first I18n.available_locales.include?(parsed_locale.to_sym) ? parsed_locale : nil end
URLにlocale情報を入れるときのTips
普通はURLにlocale情報を入れる。でもそうすると全てのリンクに
link_to(books_url(:locale => I18n.locale))
とかしなくちゃいけないのでめんどくさい。そんな時はApplicationController#default_url_optionsをオーバライドすると楽。
# app/controllers/application_controller.rb def default_url_options(options={}) { :locale => I18n.locale } end
下記のようなルーティングを定義するとRESTfulな感じになる。
# config/routes.rb scope "/:locale" do resources :books end
上記の設定だと root_url にはlocale設定がないので、下記のようなルーティングも一緒に定義しておくとよい。
# config/routes.rb match '/:locale' => 'dashboard#index'
Accept-Languageを使ってルーティングを振り分ける例
def set_locale logger.debug "* Accept-Language: #{request.env['HTTP_ACCEPT_LANGUAGE']}" I18n.locale = extract_locale_from_accept_language_header logger.debug "* Locale set to '#{I18n.locale}'" end private def extract_locale_from_accept_language_header request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first end
プラグインもあるみたい。
iain's http_accept_language at master - GitHub
lib/rack/locale.rb at master from rtomayko's rack-contrib - GitHub
IPベースでlocaleを判別
国別のIPデータベースであるMaxMind - GeoLite Country | Open Source IP Address to Country Databaseを使うとIPで国を判別できる。コード的にはAccept-Languageと同じような感じ。
ユーザ設定
ユーザにドロップダウンのリスト等でlocaleか選択させてDBに入れとく
RailsでのI18nの基本的な流れ
config/locales/en.yml に辞書ファイルを設定しておく
en: hello_world: Hello World hello_flash: Hello Flash
# app/controllers/home_controller.rb class HomeController < ApplicationController def index flash[:notice] = t(:hello_flash) end end # app/views/home/index.html.erb <h1><%=t :hello_world %></h1> <p><%= flash[:notice] %></p>
辞書ファイルを修正した後にはサーバの再起動が必要。
辞書ファイルにはYAMLとRubyが使えるけど、YAMLの方がおすすめ。でもYAMLはスペースや特殊文字に弱くてもしかしたら適切に読み取れないかもしれない。Rubyファイルは最初のリクエストが来たときにエラーを出すので間違いに気づきやすい。なのでYAMLで変な結果が出たときには関連する場所をRubyファイルに切り出すと良い。
L18nの基本的な流れ
辞書ファイルに下記のように設定する
# config/locale/pirate.yml pirate: time: formats: short: "arrrround %H'ish"
lメソッドでlocalization。:formatオプションでフォーマットを指定できる。デフォルトは:defaultが指定されている
# app/views/home/index.html.erb <h1><%=t :hello_world %></h1> <p><%= flash[:notice] %></p> <p><%= l Time.now, :format => :short %></p>
辞書ファイルの出来合いのファイルがrails/locale at master from svenfuchs's rails-i18n - GitHubにあるので使うといいらしい。
localeによるテンプレート選択
Rails 2.3 から、locale毎にテンプレートを切り替えられる機能が追加されている。例えばindex.es.html.erbファイルを用意しておくと、localeがesの時にそれが呼ばれる。大量の情報を翻訳しなくちゃならないときに便利だけど、修正が大変になるのでそのへん考えて使う必要がある。
辞書ファイルの整理
辞書ファイルの分量が多すぎるときは、辞書ファイルを config/locales 配下にディレクトリを作って分散して整理することが出来る。ネストされたディレクトリはデフォルトではload_pathに入っていないので、下記のようにして明示的にRailsに伝えてあげる必要がある。
# config/application.rb config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
translationメソッドの使い方
tメソッドは引数に文字列とシンボルをとれる
I18n.t :message I18n.t 'message'
オプションの引数としてscopeをとれる。keyの名前空間を指定できる。
I18n.t :invalid, :scope => [:activerecord, :errors, :messages]
下記のように、ドットで区切って文字列に渡しても同じ
I18n.translate :"activerecord.errors.messages.invalid"
下記のメソッドは全部同じ
I18n.t 'activerecord.errors.messages.invalid' I18n.t 'errors.messages.invalid', :scope => :active_record I18n.t :invalid, :scope => 'activerecord.errors.messages' I18n.t :invalid, :scope => [:activerecord, :errors, :messages]
定義が見つからなかったときのデフォルト設定
defaultオプションを設定すると、対応する定義が見つかれなかったときにそれが使われるようになる。
# :missingが見つからなかったら'Not here'を返す I18n.t :missing, :default => 'Not here' # :missingが見つからなかったら:also_missingを探し、無ければ'Not here'を返す I18n.t :missing, :default => [:also_missing, 'Not here']
一度に複数の翻訳情報をゲット
複数のkeyを配列で渡すことで、一度に複数の翻訳をすることができる。
I18n.t [:odd, :even], :scope => 'activerecord.errors.messages' # => ["must be odd", "must be even"]
ネストされてる名前空間を引数に渡すと、Hashで複数の翻訳情報が返ってくる
I18n.t 'activerecord.errors.messages' # => { :inclusion => "is not included in the list", :exclusion => ... }
viewで使える簡単翻訳
Rails 2.3 から実装された、viewから簡単に翻訳する方法。下記のような辞書ファイルを用意しておくと
es: books: index: title: "Título"
app/views/books/index.html.erb上で
<%= t '.title' %>
のようにするだけで"Título"を呼び出せる。
変数展開
変数展開を含んだ翻訳が出来る
I18n.backend.store_translations :en, :thanks => 'Thanks %{name}!' I18n.translate :thanks, :name => 'Jeremy' # => 'Thanks Jeremy!'
複数形にする
下記のような感じで複数形を定義/表示できる。
I18n.backend.store_translations :en, :inbox => { :one => '1 message', :other => '%{count} messages' } I18n.translate :inbox, :count => 2 # => '2 messages'
- countが1なら最初のでそれ以外なら二つ目の定義が使われる。
- 対応したHashが無いときにはI18n::InvalidPluralizationDataが発生する。
localeの設定
# localeの設定をクラスメソッドから I18n.locale = :de I18n.t :foo I18n.l Time.now # 引数としてlocaleを使える I18n.t :foo, :locale => :de I18n.l Time.now, :locale => :de # default localeの設定もクラスメソッドから可能 I18n.default_locale = :de
Modelの翻訳
Modelの翻訳のために
- Model.human_name
- Model.human_attribute_name(attribute)
の二つのメソッドが使える。例えば下記のようにyamlを設定しておいた場合
en: activerecord: models: user: Dude attributes: user: login: "Handle" # will translate User attribute "login" as "Handle"
こんな感じで翻訳結果を取り出せる
User.human_name #=> "Dude" User.human_attribute_name("login") #=> "Handle"
エラーメッセージの翻訳
下記のようなUserモデルがあるとする
class User < ActiveRecord::Base validates_presence_of :name end
nameがnilな状態でsaveしたら、blankが探される。下記の順番で最初に見つかった結果を返す
- activerecord.errors.models.user.attributes.name.blank
- activerecord.errors.models.user.blank
- activerecord.errors.messages.blank
一般的にすると下記のような規則になってる
- activerecord.errors.models.[model_name].attributes.[attribute_name]
- activerecord.errors.models.[model_name]
- activerecord.errors.messages
エラーメッセージの翻訳に継承が使える。例えば下記のようなAdminクラスがあるとする
class Admin < User validates_presence_of :name end
ActiveRecordは下記の順番で定義を探す
- activerecord.errors.models.admin.attributes.title.blank
- activerecord.errors.models.admin.blank
- activerecord.errors.models.user.attributes.title.blank
- activerecord.errors.models.user.blank
- activerecord.errors.messages.blank
エラーメッセージで変数展開
Active Recordのエラーメッセージには"Please fill in your %{attribute}"みたいな感じで変数展開が使える。エラーに対応する辞書ファイルの表は引用するのがめんどくさいので省略。
error_messages_for用の辞書ファイル
下記のような感じで定義する
en: activerecord: errors: template: header: one: "1 error prohibited this %{model} from being saved" other: "%{count} errors prohibited this %{model} from being saved" body: "There were problems with the following fields:"