Browse files

Merge pull request #60 from jamesarosen/james/i18n-sort

Some fixes & improvements to Rack::Locale
  • Loading branch information...
2 parents 58f5b31 + ccb8b09 commit 7b0b1094c5fca5917a25dc764a673e79a8ee3811 @rkh rkh committed Dec 10, 2012
Showing with 84 additions and 16 deletions.
  1. +27 −16 lib/rack/contrib/locale.rb
  2. +57 −0 test/spec_rack_locale.rb
View
43 lib/rack/contrib/locale.rb
@@ -8,24 +8,35 @@ def initialize(app)
def call(env)
old_locale = I18n.locale
- locale = nil
-
- # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
- if lang = env["HTTP_ACCEPT_LANGUAGE"]
- lang = lang.split(",").map { |l|
- l += ';q=1.0' unless l =~ /;q=\d+\.\d+$/
- l.split(';q=')
- }.first
- locale = lang.first.split("-").first
- else
- locale = I18n.default_locale
+
+ begin
+ locale = accept_locale(env) || I18n.default_locale
+ locale = env['rack.locale'] = I18n.locale = locale.to_s
+ status, headers, body = @app.call(env)
+ headers['Content-Language'] = locale
+ [status, headers, body]
+ ensure
+ I18n.locale = old_locale
end
+ end
+
+ private
+
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
+ def accept_locale(env)
+ accept_langs = env["HTTP_ACCEPT_LANGUAGE"]
+ return if accept_langs.nil?
+
+ languages_and_qvalues = accept_langs.split(",").map { |l|
+ l += ';q=1.0' unless l =~ /;q=\d+(?:\.\d+)?$/
+ l.split(';q=')
+ }
+
+ lang = languages_and_qvalues.sort_by { |(locale, qvalue)|
+ qvalue.to_f
+ }.last.first
- locale = env['rack.locale'] = I18n.locale = locale.to_s
- status, headers, body = @app.call(env)
- headers['Content-Language'] = locale
- I18n.locale = old_locale
- [status, headers, body]
+ lang == '*' ? nil : lang
end
end
end
View
57 test/spec_rack_locale.rb
@@ -0,0 +1,57 @@
+require 'test/spec'
+require 'rack/mock'
+
+context "Rack::Locale" do
+
+ setup do
+ begin
+ require 'rack/contrib/locale'
+ rescue LoadError
+ warn "I18n required for Rack::Locale specs"
+ end
+ end
+
+ def app
+ @app ||= Rack::Builder.new do
+ use Rack::Locale
+ run lambda { |env| [ 200, {}, [ I18n.locale.to_s ] ] }
+ end
+ end
+
+ def response_with_languages(accept_languages)
+ Rack::MockRequest.new(app).get('/', { 'HTTP_ACCEPT_LANGUAGE' => accept_languages } )
+ end
+
+ specify 'should use I18n.default_locale if no languages are requested' do
+ I18n.default_locale = :zh
+ response_with_languages(nil).body.should.equal('zh')
+ end
+
+ specify 'should treat an empty qvalue as 1.0' do
+ response_with_languages('en,es;q=0.95').body.should.equal('en')
+ end
+
+ specify 'should set the Content-Language response header' do
+ headers = response_with_languages('de;q=0.7,dk;q=0.9').headers
+ headers['Content-Language'].should.equal('dk')
+ end
+
+ specify 'should pick the language with the highest qvalue' do
+ response_with_languages('en;q=0.9,es;q=0.95').body.should.equal('es')
+ end
+
+ specify 'should retain full language codes' do
+ response_with_languages('en-gb,en-us;q=0.95;en').body.should.equal('en-gb')
+ end
+
+ specify 'should treat a * as "all other languages"' do
+ response_with_languages('*,en;q=0.5').body.should.equal( I18n.default_locale.to_s )
+ end
+
+ specify 'should reset the I18n locale after the response' do
+ I18n.locale = 'es'
+ response_with_languages('en,de;q=0.8')
+ I18n.locale.should.equal(:es)
+ end
+
+end

0 comments on commit 7b0b109

Please sign in to comment.