Ruby-Locale for Ruby on Rails HOWTO

ruby-locale-rails-howto

サンプルアプリケーション

最初にRuby on Rails 2.2を使ったサンプルアプリケーションを作成してください。

ここでは、すでに作成されたサンプルアプリケーションを国際化していきます。

関連文書

ファイルの編集

以下の順番でファイルを編集していきます。

I18nモジュールの初期化

まずは、他のRails i18nアプリケーション同様にI18nモジュールの初期化を行います。

# in config/initializer/locale.rb

# 翻訳ファイルが置かれているディレクトリを指定します。
I18n.load_path += Dir[ File.join(RAILS_ROOT, 'lib', 'locale', '*.{rb,yml}') ]

# このアプリケーションがサポートしているロケールを指定します。
# これはRuby-Locale for Ruby on Railsが提供する追加機能です。
# 指定がない場合は、特にロケールを限定することなく、WWWブラウザから与えられたロケール情報を
# 値として使用します。
# リソースを適切に絞り込むためにはこの設定が必須です。
I18n.supported_locales = Dir[ File.join(RAILS_ROOT, 'lib', 'locale', '*.{rb,yml}') ].collect{|v| File.basename(v, ".*")}.uniq

# デフォルトのロケールを設定します。"en"以外を指定したい場合のみ、この値を使用します。
# Ruby-Localeでは優先度のもっとも低いロケールとしてこの値が使われます。
I18n.default_locale = "pt-BR" 

1言語のみのアプリとして使用する場合は、I18n.supported_locales, I18n.default_localeにそれぞれ、ターゲットとなる言語のみを記述します。

config/environment.rb

Ruby-Locale, Ruby-Locale for Ruby on Railsのライブラリを読み込みます。

Rails::Initializer.run do |config|
 :
 :
 config.gem 'locale', :version => '2.0.4'
 config.gem 'locale_rails'
end

locale_railsはRailsのバージョンに依存しており、Railsのバージョンによって動作しないことが多いです。そこで使用するバージョンを固定することをお奨めします。 どのRailsバージョンで動作するか、は各ライブラリのREADME.rdocのSupport Matrixを参照してください。

ApplicationController

基本的に、AppicationControllerですべきことは何もありません。 I18n rails guideでは、以下のようにロケールを設定していますがこのような設定は不要です。

# 不要です。
# app/controllers/application.rb
class ApplicationController < ActionController::Base
  before_filter :set_locale
  def set_locale
    I18n.locale = params[:locale] 
  end
end

実際は、上記の設定と同様のことを本ライブラリ内部で実施しています。

この初期化処理により、ユーザからのリクエストごとにロケールが決まるのですが、その前後で何かを実行したい、と言う場合は(before|after)_init_localeを使用してください。 以下にafter_init_localeを使った例を示します。

# app/controllers/application.rb
class ApplicationController < ActionController::Base
  def init_i18n
     OtherL10n.locale = Locale.candidates
  end
  after_init_locale :init_i18n
end

なお、上記の例では、OtherL10n.というライブラリにLocale.candidates(後述します)を使って候補となるロケールを設定する例です。

after_init_localeは、Ruby on Railsに依存しないローカライズされたライブラリ等を使用するときのロケールの初期化に使うとよいでしょう。

Views/ActionMailer

I18n.t等、Rails I18nが提供するメソッドを使うとリクエストごとに適切なロケールでメッセージを表示できます。

# app/views/home/index.html.erb
<h1><%=t :hello_world %></h1>

ローカライズドテンプレートの使用

foo_ja.hml.erb, foo_ja_JP.html.erbと言う風にテンプレート自体を英語の元ファイルから分離させてしまうこともできます。例えば以下のようにファイルを配置します。

/app/views/blog/list.html.erb
/app/views/blog/list_ja.html.erb
/app/views/blog/list_ja_JP.html.erb

このケースでは日本語(jaロケール)の場合のみ、2番目のファイルが呼び出され、それ以外の時は1番目のファイルが呼び出されます。 render_partialの場合は、_foo.html.erb, _foo_ja.html.erbとすると、日本語の場合のみ_foo_ja.html.erbが呼び出されます。

ローカライズドルーティング

":lang"をconfig/routes.rbで使用することでルーティング時にロケールを指定することができます。

# config/routes.rb
ActionController::Routing::Routes.draw do |map|
  # Localized Routing.
  map.connect '/:lang/:controller/:action/:id'
  map.connect '/:lang/:controller/:action/:id.:format'
end

この:langの値は、param[:lang]として本ライブラリ内の最優先のロケールとして使用されます。

上記の記述をすることで、

http://www.foobar.com/ja_JP/foos/show
http://www.foobar.com/fr/foos/show

など、URLを言語ごとに分けてアクセスすることができます。

Viewの方はconfig/routes.rbを上記のように指定した上で、以下のように:langを指定することで上記のURLを生成することができます。

url = foos_path(:lang => lang)
link_to "Click", :controller => :foos, :action => :show, :lang => lang

ロケール情報の取得

ユーザリクエストごとのロケール情報を取得するには、I18n.localeかLocale.candidatesを使います。

それぞれ、以下のような機能を持ちます。

I18n.locale

I18n.localeはRails2.2 I18n APIが提供するI18n.localeメソッドを拡張したもので、ユーザリクエストのロケール情報のうち、もっとも優先度の高い情報を1つだけ返します。

# app/views/home/index.html.erb
<div><%= I18n.locale.inspect %></div>

返す値はRuby on Rails 2.2標準の文字列形式ではなく、Locale::Tag::Rfcオブジェクト(RFC4646, ja-Hira-JP-VARIANTS、通常はja-JPなどの<language>-<REGION>の形式)です。これにより、CLDR形式、POSIX形式等に変換したり、language部分のみを取得したりすることが可能です。 単に文字列として扱うこともできますので、従来のRails 2.2 I18n APIを利用したプラグイン等でもそのまま利用できます。

Locale.candidates

Locale.candidatesは考えられる候補すべてをLocale::TagListの形式で返します。一番最後の候補としてI18n.default_localeで指定された値が返ります。

Locale.candidatesはデフォルトでCommon形式(ja_Hira_JP_VARIANTS)を返しますが引数で、:simple, :common, :rfc, :cldrを選択することができます。

# app/views/home/index.html.erb
<div><%= Locale.candidates.inspect %></div>

I18n.supported_localesを指定することで、I18n.localeの結果の値をそのまま使えばアプリケーションが想定したロケールを取得できるはずですが、I18n.supported_localesを想定しない場合や何らかの理由で他の候補も使用する場合はLocale.candidatesの中から候補を選ぶとよいでしょう。

Locale.candidates.each do |lang|
  path = "/foo/bar/locale/#{lang}/foo.rb"
  if File.exist?(path)
    File.open(path)
       :
       :
    break
  end
end

なお、I18n.localeはLocale.candidates(:type => :rfc)[0]と同等です。

Railsプラグイン、ライブラリのローカライズの際の注意点

I18n.localeはI18n.supported_localesで定義されたロケールの範囲で値を返します。

このI18n.supported_localesは通常アプリケーションが設定するもので、I18n.localeは、そのアプリケーションのサポートしているロケールの範囲でもっとも優先度の高いロケールIDを返します。

ここで注意していただきたいのですが、この値がRailsプラグイン・ライブラリがサポートできる範囲と同じかどうかというのは要検討だ、ということです。

たとえば、アプリケーション自体がサポートしているロケールとして、I18n.localeがja-JPを返したからと言って、そのプラグインがja-JPをサポートしていないのであれば、その部分だけローカライズ処理に失敗するはずです。

そこで、Locale.candidatesを使って、プラグイン・ライブラリがサポートできるロケールまでフォールバックすると良いでしょう。

ブラウザからのアクセスとCookieへの情報格納

ロケール情報は、QUERY_STRINGのlangの値 > Cookieのlangの値 > WWWブラウザが返すHTTP_ACCEPT_LANGUAGE環境変数 > "en"(英語) の順番で決まります。QUERY_STRINGのlangの値とは、例えば、http://foo/?lang=ja という感じでURLの最後に追加する方法です。 QUERY_STRINGのlangの値やCookieのlangの値はアプリケーション側で適切に設定する必要があります。

アプリケーションを作って最初に確認するときは、http://foo/?lang=ja とアクセスしてみれば日本語になっていることがわかるでしょう。

また、ここでは上記のようにQUERY_STRINGからlangを受け取りCookieに設定して返す機能を紹介します。

Session情報を使う場合はそちらに設定しても良いかもしれません。

class BlogController < ApplicationController
      :
      :
  def cookie_locale
    cookies["lang"] = @params["id"]
    redirect_to :action => 'list'
  end
end

あとは、View側からcoolie_localeをアクションとして呼び出すようにします。

<%= link_to "Set Locale to japanese", :action => "cookie_locale", :id => "ja" %>

キャッシュについて

RailsにはPage/Action/Fragmentの3種類のキャッシュがありますが、Action/Fragmentについてはロケール毎に管理するように拡張されており、特に(本ライブラリを使わない)アプリケーションと同様にRailsのキャッシュ機能を使用することができます。

Pageキャッシュについてはロケールの特定をhttpサーバ、Rails双方でうまく連携をとる必要があるため、今のところ上手な解決策が思いつきません。何かいいアイデアがある方は教えてくださいませ。

ChangeLog

  • 2008-11-24: 新規作成
更新日時:2009/09/23 11:45:44
キーワード:
参照:[Ruby-Locale for Ruby on Rails] [Ruby on RailsでRuby-GetText-Packageを使う (Rails-2.3.2以降)]