2013年12月10日火曜日

Rails多言語対応

今日はRailsで日本語と英語の出し分けを実装してました。さすがRails、多言語対応も安定の簡単さ。グリーみたいにアラビア語対応とかしなくていいから更に楽です。ここ(Rails Internationalization (I18n) API)を見ながらちょいちょいと設定が済みました。 基本的にはI18nというオブジェクトですべてハンドルしております。 I18n.lでlocalize、I18n.tで翻訳をします。

2.0.0p247 :010 > I18n.l Time.now
 => "Tue, 03 Dec 2013 17:19:04 +0000" 
2.0.0p247 :022 > I18n.t "hello"
 => "こんにちわ世界" 
どのLocaleを利用するかはI18n.localeに格納されています。

2.0.0p247 :026 > I18n.locale
 => :jp 
2.0.0p247 :027 > I18n.default_locale
 => :en 
言語リソースはymlで用意する。config/locales/*.ymlというファイルを作るとRailsが自動的に読み込んでくれる。

en:
  hello: "Hello world"
jp:
  hello: "こんにちわ世界"
ちなみに階層化できるので、きれいにまとめましょう。

en:
  greeting:
    hi:
      world: "Hi World"
      ippei: "Hi Ippei"
.(ドット)でつなぎます。

2.0.0p247 :004 > I18n.t("greeting")
 => {:hi=>{:world=>"Hi World", :ippei=>"Hi Ippei"}} 
2.0.0p247 :005 > I18n.t("greeting.hi.world")
 => "Hi World" 
2.0.0p247 :006 > I18n.t("greeting.hi.ippei")
 => "Hi Ippei" 
若干ハマったのが、なぜかjp.ymlという言語リソースファイルを追加したのに読んでくれていない。Railsがconfig/locales/から自動的にロードしてくれるのだが、残念ながらファイルを追加した時には動的に呼んでないらしい。ファイルに新しいKeyをアペンドした時は読んでくれるんだけど。たぶんこのパラメータが起動時に作られるのだと思われる。

2.0.0p247 :001 > I18n.load_path
 => ["/Users/ippei/RubymineProjects/eneberg/vendor/bundle/ruby/2.0.0/gems/activesupport-4.0.1/lib/active_support/locale/en.yml", "/Users/ippei/Rubymine.....
また、application.rbからdefault_localeの変更やload_pathの追加をすることもできる。少なくともrails4.0.1では以下のようなComment OutされたエントリーがあるのでComment Inして任意の言語またはディレクトリを追加するだけ。

    # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
    # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
    # config.i18n.default_locale = :de


問題はI18n.localeにどうやって任意の言語を入れてあげるか。つまりどうやって言語を判別するか。 大まかに以下の方法があると思います。組み合わせて使ったりもします。グリーはAccept-Languageだったはず。

  1. ドメインで識別 
    • jp.example.com
    • example.jp
  2. Query Stringで渡す
    • example.com?locale=jp
  3. Pathに追加する
    • example.com/jp
  4. Accept-Languageを見る
    • Accept-Language:en-US,en;q=0.8,ja;q=0.6
  5. GeoIP
  6. ユーザ毎に設定を持たせる

今回はお手軽にQuery StringとAccept-Languageで実装しました。


まずはQuery Stringから。ApplicationController.rbに下記を追加してQuery Stringで渡されたパラメーターをI18n.localeに設定するようにします。

before_action :set_locale
 
def set_locale
  I18n.locale = params[:locale] || I18n.default_locale
end
これだけだと画面遷移時にlocaleが引き継がれないので、以下のmethodをoverrideして常にlocaleパラメータを渡すようにします。

def default_url_options(options={})
  { locale: I18n.locale }
end
お次はAccept-Languageの実装です。残念ながらRails自体にはAccept-LanguageをParseする機能はないようなので、http_accept_languageというGemを使いました。 Gemfileに以下を追加します。
gem "http_accept_language", "~> 2.0.0"
そうするとこんな感じで準備したLocaleに対応する言語を返してくれます。
http_accept_language.compatible_language_from(I18n.available_locales)
Query Stringを優先させるので、終わってみるとApplication Controllerはこんな感じになりました。

  before_action :set_locale

  def default_url_options(options={})
    {:locale => I18n.locale}
  end

  def set_locale
    I18n.locale = extract_locale_from_params ||
        extract_locale_from_accept_language_header ||
        I18n.default_locale
  end

  private
  def extract_locale_from_params
    if params[:locale] and I18n.available_locales.index(params[:locale].to_sym)
      params[:locale]
    end
  end

  def extract_locale_from_accept_language_header
    http_accept_language.compatible_language_from(I18n.available_locales)
  end
後はja.ymlとen.ymlにひたすらリソースを追加して、Templateにせこせこと以下の文字を馬鹿みたいに埋め込み続けるだけの簡単なお仕事です。
<%= t('KEY') %>

0 件のコメント: