高林と申します
クライアントから渡される Accept-Language: の値に従って、サー
バが返すファイルを切り替える機能 (Apache の Multiviews に相当)
を実現するために、メール末尾のコードを書きました。
たとえば、foo.html へのアクセスに対して、 Accept-Language:
ja を渡すブラウザに対しては、foo.html.ja を返し、en を渡すブ
ラウザには foo.html.en を返す、といったことができます。
WEBrick::HTTPUtils::mime_type と
WEBRick::HTTPServlet::FileHander::set_filename を置き換える
というやや強引な方法を取っています。
もしよければ、WEBrick 本体の FileHandler で Accept-Language:
に対応していただけると助かります。FileHandler のオプションに
:AcceptLanguage => true を指定するとAccept-Language を見る、
といった感じで指定できると便利だと思います。
module WEBrick::HTTPUtils
# FIXME: Apache のように AddLanguage した言語だけを認識す
# る、という実装の方がいいかも
def mime_type(filename, mime_tab)
suffix1 = (/\.(\w+)$/ =~ filename && $1.downcase)
# ex. index.html.en, foo.html.ja
suffix2 = (/\.(\w+)\.[\w-]+$/ =~ filename && $1.downcase)
mime_tab[suffix1] || mime_tab[suffix2] || "application/octet-stream"
end
module_function :mime_type
end
class MultilingualFileHandler < HTTPServlet::FileHandler
def get_accept_languages (req)
if req["Accept-Language"]
tmp = []
parts = req["Accept-Language"].split(/,\s*/)
parts.each {|part|
if m = /^([\w-]+)(?:;q=([\d]+(?:\.[\d]+)))?$/.match(part)
lang = m[1]
q = (m[2] or 1).to_f
tmp.push([lang, q])
end
}
return tmp.sort_by {|lang, q| q }.map {|lang, q| lang}.reverse
else
return []
end
end
def set_filename(req, res)
original_path_info = req.path_info
begin
return super(req, res)
rescue HTTPStatus::NotFound => e
accept_languages = get_accept_languages(req)
# FIXME: Accept-Language が渡されないときの優先順位は
# Apache の LanguagePriority のように指定できる方がいいかも
accept_languages = ["en"] if accept_languages.empty?
accept_languages.each {|lang|
begin
req.path_info = original_path_info + "." + lang
return super(req, res)
rescue HTTPStatus::NotFound
end
}
req.path_info = original_path_info
raise e
end
end
end