routesの設定と言語選択の優先順位 の変更点
更新- 追加された行はこの色です。
- 削除された行はこの色です。
- ソフトウェア/rails/言語ネゴシエーション/routesの設定と言語選択の優先順位 へ行く。
- ソフトウェア/rails/言語ネゴシエーション/routesの設定と言語選択の優先順位 の差分を削除
SIZE(22){COLOR(RED){このページの内容は非常に古いです(Rails 1.x.x)。最新の Rails では洗練された国際化の機構が標準で入っているため、下記は読むだけ無駄な内容になっています。}}
[[ソフトウェア/rails/言語ネゴシエーション]]
#contents
* 多言語化したビューの作成 [#b2db2fc3]
今作ったビューを削除して、日本語版と英語版を作成。
まだ rails に手を入れていないので、そのままではエラーになる。
LANG:console
$ rm app/views/test/index.html.erb
$ echo "Test" > app/views/test/index.html.en.erb
$ echo "テスト" > app/views/test/index.html.ja.erb
$ wget -O- http://localhost:3000/test
エラー 404: Not Found
これを正しく表示できるようにするのが目標なのだが、
その前に rails に言語ファイル選択の優先順位を教える必要がある。
* config/routes.rb の設定 [#w47da434]
多言語化後は、各ページに対して
http://localhost:3000/test
http://localhost:3000/test.ja
http://localhost:3000/test/index
http://localhost:3000/test/index.ja
http://localhost:3000/test/index/0
http://localhost:3000/test/index/0.ja
http://localhost:3000/test/index/0.html
http://localhost:3000/test/index/0.html.ja
などの形でアクセスできるようにする。
+ .ja などの言語指定がない場合
-- ブラウザからも指定が無ければサーバー側の優先順位で表示言語を選ぶ
-- ブラウザが優先順位を指定していれば、その順で表示言語を選ぶ
+ .ja などの言語指定があれば、その言語で表示する
+ 一旦言語指定を行ったら、以降は言語指定がない場合にサーバーやブラウザの優先順位を無視して、
直前に行った言語指定と同じ言語で表示する
+ 表示したい言語のテンプレートファイルが無ければ、ある物を使って表示する
3. は、明示的に表示言語を選択できるようにするためのもの。
受け入れ可能な言語のリストは config/routes.rb の先頭で
ENV['RAILS_ACCEPTABLE_LANGUAGES'] ||= 'ja|en'
として設定する事にする。
サーバー側の優先順位はここでの指定順で決まる物とする。~
これ以外の言語が指定されても無視することにする。
route の設定は、
map.connect ':controller/:action/:id.:rails_language',
:requirements => { :rails_language => /ja|en/ }
のようになる。/^(ja|en)$/ ではなく /ja|en/ とするのが正しいらしい。
以下がコード。
config/routes.rb
LANG:ruby(linenumber)
ENV['RAILS_ACCEPTABLE_LANGUAGES'] ||= 'ja|en'
ActionController::Routing::Routes.draw do |map|
lang_regexp= Regexp.new( ENV['RAILS_ACCEPTABLE_LANGUAGES'] )
map.connect ':controller.:rails_language', :format => 'html', :action => 'index',
:requirements => { :rails_language => lang_regexp }
map.connect ':controller/:action.:rails_language', :format => 'html',
:requirements => { :rails_language => lang_regexp }
map.connect ':controller/:action/:id.:rails_language', :format => 'html',
:requirements => { :rails_language => lang_regexp }
map.connect ':controller/:action/:id', :format => 'html'
map.connect ':controller/:action/:id.:format.:rails_language',
:requirements => { :rails_language => lang_regexp }
map.connect ':controller/:action/:id.:format',
:defaults => { :action => 'index', :format => 'html' }
end
** テスト [#s18f0fb5]
LANG:console
$ (restart script/server)
$ jed app/controllers/test_controller.rb
class TestController < ApplicationController
def index
render :text => params[:rails_language].inspect + "\n"
end
end
$ wget -qO- http://localhost:3000/test
nil
$ wget -qO- http://localhost:3000/test.ja
"ja"
$ wget -O- http://localhost:3000/test.html.ja
404: Not Found
$ wget -qO- http://localhost:3000/test/index
nil
$ wget -qO- http://localhost:3000/test/index.ja
"ja"
$ wget -O- http://localhost:3000/test/index.html.ja
404: Not Found
$ wget -qO- http://localhost:3000/test/index/0.html
nil
$ wget -qO- http://localhost:3000/test/index/0.html.ja
"ja"
言語指定を正しく行えている事が分かる。
* 言語が指定されていない時を含めた言語選択の優先順位 [#k5f2df0a]
優先順位は以下のようにする。
+ 指定された言語 (指定されていれば)
+ 前回指定された言語 (もしあれば cookie に保存しておく)
+ ブラウザから送られる Accept-Language (もしあれば)
+ RAILS_ACCEPTABLE_LANGUAGES に記述された言語(記述された順)
この順で提供可能な言語(作成されている言語テンプレート)を検索し、
見つかった物を使って表示する。
優先順位を決定するコードは以下の通り:
config/environment.rb の末尾に
LANG:ruby(linenumber)
class ActionController::AbstractRequest
def self.acceptable_languages
@acceptable_languages ||=
ENV['RAILS_ACCEPTABLE_LANGUAGES'].split('|').map {|l| l.to_sym}
end
def self.acceptable_language?(l)
acceptable_languages.include?(l.to_sym)
end
end
class ActionController::AbstractRequest
# will be set by ActionView::Base._pick_template
attr :language, true
def accepts_languages!(language=nil)
@accepts_languages= [
language ? language.to_sym : nil,
( cookie = cookies['rails_language'] and l = cookie.first and
ActionController::AbstractRequest.acceptable_language?(l) ) ? l.to_sym : nil,
( @env['HTTP_ACCEPT_LANGUAGE'] || '' ).split(",").collect {|l|
lsym= l.split(/;|\-/,2)[0].downcase.to_sym
ActionController::AbstractRequest.acceptable_language?(lsym) ? lsym : nil
},
ActionController::AbstractRequest.acceptable_languages
].flatten.compact.uniq
end
def accepts_languages
@accepts_languages || accepts_languages!
end
end
class ActionController::Base
# before_filter :set_language
# fails for some unknown reason.
# following is a workaround.
def perform_action_with_set_rails_language
set_rails_language
perform_action_without_set_rails_language
end
alias_method_chain :perform_action, :set_rails_language
protected
def set_rails_language
rails_language= params[:rails_language]
if rails_language && ActionController::AbstractRequest.acceptable_language?(rails_language)
cookies['rails_language']= rails_language
request.accepts_languages!(rails_language)
end
end
end
ブラウザから送られる Accept ヘッダーを解釈して、
ブラウザの受け入れ可能な Mime::Type の配列にして返す関数が
ActionController::AbstractRequest::accepts
という名前であるのに習って、
Accept-Language を解釈して配列にして返す関数を accepts_languages とした。
一旦指定された言語選択は、ActionController::Base.set_rails_language にて
cookies['rails_language'] に保存される。
クッキーの書き換えを行った場合には、accepts_languages を更新する必要がある。
このための関数が accepts_languages! 。
set_rails_language を before_fileter に登録したかったのだけれど、
なぜかうまく行かなかったので、perform_action の前に無理矢理はさんだ。
実際にどの言語で送信されるかは、優先順位に従ってテンプレートファイルを検索し、
初めて見つかった物が何であるかによって決まる。
request.language はこの実際のテンプレートファイルの言語を表すプロパティで、
後から ActionView::Base._pick_template によって設定される事になる。
** テスト [#h4a02e5d]
LANG:console
$ jed app/controllers/test_controller.rb
class TestController < ApplicationController
def index
render :text => request.accepts_languages.inspect + "\n"
end
end
$ (restart script/server)
$ wget -qO- http://localhost:3000/test
[:ja, :en]
$ wget -qO- --header="Accept-Language:ja" http://localhost:3000/test
[:ja, :en]
$ wget -qO- --header="Accept-Language:en" http://localhost:3000/test
[:en, :ja]
$ wget -qO- http://localhost:3000/test
[:ja, :en]
$ wget -qO- http://localhost:3000/test.en
[:en, :ja]
$ alias wgetc="wget -qO- --load-cookies=tmp/wget.cookie --save-cookies=tmp/wget.cookie --keep-session-cookies"
$ cat tmp/wget.cookie
cat: tmp/wget.cookie: そのようなファイルやディレクトリはありません
$ wgetc http://localhost:3000/test
[:ja, :en]
$ cat tmp/wget.cookie
# HTTP cookie file.
# Edit at your own risk.
$ wgetc http://localhost:3000/test.en
[:en, :ja]
$ cat tmp/wget.cookie
# HTTP cookie file.
# Edit at your own risk.
localhost:3000 FALSE / FALSE 0 _negotiation_session BAh7BiIKZm...
localhost:3000 FALSE / FALSE 0 rails_language en
$ wgetc http://localhost:3000/test
[:en, :ja]
$ wgetc http://localhost:3000/test.ja
[:ja, :en]
$ wgetc http://localhost:3000/test
[:ja, :en]
正しく切り換えができている事が分かる。
ACCEPT_LANGUAGE や rails_language, cookie['rails_language']
に不正な言語指定が送られてもはじくようになっている。
[[#### 前へ>ソフトウェア/rails/言語ネゴシエーション/negotiation という名前のアプリケーションの作成]]~
[[#### 上へ>ソフトウェア/rails/言語ネゴシエーション]]~
[[#### 次へ>ソフトウェア/rails/言語ネゴシエーション/言語が指定されていない時を含めた言語選択の優先順位]]~
Counter: 4954 (from 2010/06/03),
today: 1,
yesterday: 1