From 1c6dfbec32dfe4b287f362e7470ec24677bcec49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Go=C5=9Bcicki?= Date: Tue, 9 Aug 2011 16:09:48 +0200 Subject: [PATCH] Actually set I18n.locale based on http header --- .rspec | 1 + README.md | 7 ++++-- lib/locale_detector/filter.rb | 12 +++++++++- locale_detector.gemspec | 4 ++++ spec/locale_detector/fallback_locale_spec.rb | 9 ++++++++ spec/locale_detector/filter_spec.rb | 24 ++++++++++++++++++++ spec/spec_helper.rb | 9 ++++++++ 7 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 .rspec create mode 100644 spec/locale_detector/fallback_locale_spec.rb create mode 100644 spec/locale_detector/filter_spec.rb create mode 100644 spec/spec_helper.rb diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..4e1e0d2 --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--color diff --git a/README.md b/README.md index ef18840..9a56a29 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,12 @@ # Locale Detector -This Rails gem makes use of the HTTP_ACCEPT_LANGUAGE http header send by web browsers with every request, to set the `I18n.locale` variable. -When this fails (for example if there is no such http header as is the case for Google bot), it will try to determine the locale based on the toplevel domain suffix (so it will set 'de' for the `example.de` domain). +This Rails gem makes use of the HTTP_ACCEPT_LANGUAGE http header sent by web browsers with every request, to set the `I18n.locale` setting. +When this fails (for example if there is no such http header - as is the case for Google bot), it will try to determine the locale based on the toplevel domain suffix (so it will set 'de' for the `example.de` domain). When both fail, it will fall back to the `LocaleDetector.fallback_locale`, which is 'en' by default and can be overriden in `config/initializers/locale_detector.rb`. +The HTTP_ACCEPT_LANGUAGE header parser is based on: +https://github.com/iain/http_accept_language/blob/master/lib/http_accept_language.rb + ## Installation diff --git a/lib/locale_detector/filter.rb b/lib/locale_detector/filter.rb index 414e705..e2d3017 100644 --- a/lib/locale_detector/filter.rb +++ b/lib/locale_detector/filter.rb @@ -9,7 +9,17 @@ module Filter protected def set_locale - I18n.locale = 'en' + I18n.locale = begin + request.env['HTTP_ACCEPT_LANGUAGE'].split(/\s*,\s*/).collect do |l| + l += ';q=1.0' unless l =~ /;q=\d+\.\d+$/ + l.split(';q=') + end.sort do |x,y| + raise "Incorrect format" unless x.first =~ /^[a-z\-]+$/i + y.last.to_f <=> x.last.to_f + end.first.first.gsub(/-[a-z]+$/i, '').downcase + rescue # rescue (anything) from the malformed (or missing) accept language headers + LocaleDetector.fallback_locale + end end end end diff --git a/locale_detector.gemspec b/locale_detector.gemspec index 2ab5348..5b31cfe 100644 --- a/locale_detector.gemspec +++ b/locale_detector.gemspec @@ -21,4 +21,8 @@ Gem::Specification.new do |s| s.add_dependency 'rails', ['>= 3.0.0'] s.add_dependency 'i18n', ['>= 0.5.0'] + s.add_development_dependency 'guard', ['>= 0.5.0'] + s.add_development_dependency 'guard-rspec', ['>= 0.4.0'] + s.add_development_dependency 'rspec', ['>= 2.6'] + s.add_development_dependency 'rspec-rails', ['>= 2.6'] end diff --git a/spec/locale_detector/fallback_locale_spec.rb b/spec/locale_detector/fallback_locale_spec.rb new file mode 100644 index 0000000..6011df9 --- /dev/null +++ b/spec/locale_detector/fallback_locale_spec.rb @@ -0,0 +1,9 @@ +require 'spec_helper' + +describe LocaleDetector do + + subject { LocaleDetector.fallback_locale } + + it { should_not be_empty } + +end diff --git a/spec/locale_detector/filter_spec.rb b/spec/locale_detector/filter_spec.rb new file mode 100644 index 0000000..1ef0af4 --- /dev/null +++ b/spec/locale_detector/filter_spec.rb @@ -0,0 +1,24 @@ +require 'spec_helper' + +describe LocaleDetector::Filter do + + def set_locale(opts = {}) + filter = Object.new.extend(LocaleDetector::Filter) + request = double('request', :env => { 'HTTP_ACCEPT_LANGUAGE' => opts[:language] }) + filter.stub(:request).and_return(request) + filter.send(:set_locale) + end + + specify { set_locale(:language => nil).should eql(LocaleDetector.fallback_locale) } + + specify { set_locale(:language => 'pl').should eql('pl') } + + specify { set_locale(:language => 'pl-PL').should eql('pl') } + + specify { set_locale(:language => 'pl,en-us;q=0.7,en;q=0.3').should eql('pl') } + + specify { set_locale(:language => 'lt,en-us;q=0.8,en;q=0.6,ru;q=0.4,pl;q=0.2').should eql('lt') } + + specify { set_locale(:language => 'pl-PL;q=0.1,en-us;q=0.7,en;q=0.3').should eql('en') } + +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..d9c4208 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,9 @@ +$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) +$:.unshift(File.dirname(__FILE__)) + +require 'rails' +require 'locale_detector' + +RSpec.configure do |config| + config.mock_with :rspec +end