Sinatraのerbメソッドは標準ではContent negotiationをサポートしていません。そこで、ユーザエージェント(Webブラウザ)がリクエストに指定したAccept-Languageヘッダの値をもとに、テンプレートを自動的に選択することができるメソッド(erb_l)を新たに定義します。
多分、sinatra-r18nかSinatra本家がサポートするまでの間の暫定対応。
準備
以下のgemが必要です。適当にgem installしておいて下さい。
- i18n
- rack-contrib
コード
アプリ
# coding: utf-8
require 'rack/contrib'
require 'sinatra/base'
class TestApp < Sinatra::Base
use Rack::Locale
helpers do
# erb with content negotiation support
def erb_l(template, options = {}, locals = {})
locale = request.env['rack.locale']
if locale.nil? or locale.to_s !~ /^\w+$/
erb(template, options, locals)
end
tmpl = "#{template.to_s}_#{locale}".to_sym
begin
erb(tmpl, options, locals)
rescue Errno::ENOENT
erb(template, options, locals)
end
end
end
get '/' do
erb_l :index
end
end
erb_lメソッドは、Accept-Languageヘッダの値に基いて、読み込むテンプレートのファイルを決定します。上記の例の場合、日本語を優先する設定のWebブラウザからのリクエストの場合にはindex_ja.erbを、英語を優先するWebブラウザからのリクエストの場合にはindex_en.erbをテンプレートとして使用します。これらのファイルが存在しない場合、index.erbをテンプレートとして使用します。
テンプレートの例
<%# coding: utf-8 %>
<html>
<body>
<h1>Hello, world</h1>
</body>
</html>
<%# coding: utf-8 %>
<html>
<body>
<h1>こんにちは世界</h1>
</body>
</html>
config.ru
require 'rubygems'
require File.join(File.dirname(__FILE__), 'test_app.rb')
run TestApp
実行例
テストのため、上記のアプリを起動しておきます。
% rainbows -E production -p 8080 config.ru
Accept-Languageヘッダを指定しない場合、標準のindex.erbが使われます。
% wget -nv -4 -O - http://localhost:8080/
<html>
<body>
<h1>Hello, world</h1>
</body>
</html>
Accept-Language: enの場合。index_en.erbの利用を試みますが、これは存在しませんので、index.erbが使われます。
% wget -nv -4 -O - --header='Accept-Language: en' http://localhost:8080/
<html>
<body>
<h1>Hello, world</h1>
</body>
</html>
Accept-Language: ja,enの場合。index_ja.erbが使われます。
% wget -nv -4 -O - --header='Accept-Language: ja,en' http://localhost:8080/
<html>
<body>
<h1>こんにちは世界</h1>
</body>
</html>
Accept-Language: frの場合。index_fr.erbの利用を試みますが、これは存在しませんので、index.erbが使われます。
% wget -nv -4 -O - --header='Accept-Language: fr' http://localhost:8080/
<html>
<body>
<h1>Hello, world</h1>
</body>
</html>