gettext/rails のロケール決定方法を変える

require 'gettext/rails' を使う場合、gettext のロケール情報は「ブラウザからのアクセスとCookieへの情報格納」にあるように params[:lang], cookies[:lang], HTTP_ACCEPT_LANGAUGE, "en" の順番に参照され決定されます。

これを params[:lang], cookies[:lang] を使用せず session["language"], HTTP_ACCEPT_LANGUAGE のみによりロケールを決定するように実装したくなり、いろいろ悩んだあげく次のようなコードで解決させました。

class ApplicationController < ActionController::Base
  init_gettext "test"

  private

  def init_gettext_main(cgi)
    set_cgi(gettext_dummy_cgi)
    set_locale_all(nil)
  end

  def gettext_dummy_cgi
    gettext_dummy_cgi_class.new(session["language"], request.env["HTTP_ACCEPT_LANGUAGE"], request.env["HTTP_ACCEPT_CHARSET"])
  end

  @@gettext_dummy_cgi_class = nil

  def gettext_dummy_cgi_class
    unless @@gettext_dummy_cgi_class
      klass = Class.new
      klass.class_eval do
        attr_reader :params, :cookies, :accept_language, :accept_charset
        define_method :initialize do |lang,accept_language,accept_charset|
          @params = { "lang" => lang }
          @cookies = Hash.new { |k,v| [] }
          @accept_language = accept_language
          @accept_charset = accept_charset
        end
        define_method :[] do |index|
          @params[index]
        end
      end
      @@gettext_dummy_cgi_class = klass
    end
    @@gettext_dummy_cgi_class
  end
end

いまのところ gettext-1.8.0 でしか動作しません。

gettext/rails は request.cgi を用いてロケールを決定しようとするので、その cgi の代わりになるオブジェクトをでっちあげてそれを渡すことで実現しています。(かなり強引ですが)