rack-i18n_locale_switcher 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6 -0
- data/Rakefile +5 -5
- data/lib/rack/i18n_locale_switcher.rb +47 -32
- data/rack-i18n_locale_switcher.gemspec +4 -4
- data/spec/i18n_locale_switcher_spec.rb +81 -22
- metadata +18 -18
data/CHANGELOG
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
= 0.4.0 / 2011-11-26
|
2
|
+
Added support configuration of sources from which to determine the locale
|
3
|
+
as well as the name of the query parameter.
|
4
|
+
Drop support for TLD since locale can't be reliably inferred from it
|
5
|
+
Code refactoring and better test coverage.
|
6
|
+
|
1
7
|
= 0.3.1 / 2011-11-25
|
2
8
|
Code refactoring
|
3
9
|
Don't "clean" then Rack environment
|
data/Rakefile
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
require 'rake'
|
3
3
|
require 'echoe'
|
4
4
|
|
5
|
-
Echoe.new('rack-i18n_locale_switcher', '0.
|
5
|
+
Echoe.new('rack-i18n_locale_switcher', '0.4.0') do |p|
|
6
6
|
|
7
|
-
p.description
|
8
|
-
p.url
|
9
|
-
p.author
|
10
|
-
p.email
|
7
|
+
p.description = "Detects the current locale from query parameter, path prefix, host or accept header."
|
8
|
+
p.url = "http://github.com/christoph-buente/rack-i18n_locale_switcher"
|
9
|
+
p.author = ["Christoph Bünte", "Andreas Korth"]
|
10
|
+
p.email = ["info@christophbuente.de", "andreas.korth@gmail.com"]
|
11
11
|
|
12
12
|
p.retain_gemspec = true
|
13
13
|
|
@@ -1,57 +1,72 @@
|
|
1
1
|
require 'i18n'
|
2
|
-
require 'domainatrix'
|
2
|
+
# require 'domainatrix'
|
3
3
|
|
4
4
|
module Rack
|
5
5
|
class I18nLocaleSwitcher
|
6
6
|
|
7
|
+
DEFAULT_OPTIONS = {
|
8
|
+
:param => 'locale',
|
9
|
+
:source => [ :param, :path, :host, :header ]
|
10
|
+
}.freeze
|
11
|
+
|
7
12
|
def initialize(app, options = {})
|
8
13
|
@app = app
|
14
|
+
|
15
|
+
invalid_options = (options.keys - DEFAULT_OPTIONS.keys)
|
16
|
+
|
17
|
+
if invalid_options.any?
|
18
|
+
raise ArgumentError, "Invalid option(s) #{ invalid_options.map(&:inspect).join(', ') }"
|
19
|
+
end
|
20
|
+
|
21
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
22
|
+
@options[:source] = Array(@options[:source]) unless @options[:source].is_a?(Array)
|
9
23
|
end
|
10
24
|
|
11
25
|
def call(env)
|
12
|
-
I18n.locale =
|
26
|
+
I18n.locale = I18n.default_locale
|
27
|
+
|
28
|
+
@options[:source].each do |source|
|
29
|
+
if locale = send(:"get_locale_from_#{source}", env)
|
30
|
+
I18n.locale = locale
|
31
|
+
break
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
13
35
|
@app.call(env)
|
14
36
|
end
|
15
37
|
|
16
38
|
private
|
17
39
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
uses.each do |use|
|
22
|
-
if locale = send(:"extract_locale_from_#{ use }", request)
|
23
|
-
unless locale.empty?
|
24
|
-
locale = locale.to_sym
|
25
|
-
return locale if I18n.available_locales.include?(locale)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
I18n.default_locale
|
30
|
-
end
|
31
|
-
|
32
|
-
def extract_locale_from_param(request)
|
33
|
-
request.params["locale"]
|
40
|
+
def get_locale_from_param(env)
|
41
|
+
env['QUERY_STRING'] =~ /\b#{ @options[:param] }=([^&]+)\b/
|
42
|
+
to_available_locale($1)
|
34
43
|
end
|
35
44
|
|
36
|
-
def
|
37
|
-
|
45
|
+
def get_locale_from_path(env)
|
46
|
+
env['PATH_INFO'] =~ /^\/([^\/]+)/
|
47
|
+
to_available_locale($1)
|
38
48
|
end
|
39
49
|
|
40
|
-
def
|
41
|
-
|
50
|
+
def get_locale_from_host(env)
|
51
|
+
env['SERVER_NAME'] =~ /^([^.]+)\.[^.]+\.[^.]+/i
|
52
|
+
to_available_locale($1)
|
42
53
|
end
|
43
54
|
|
44
|
-
def
|
45
|
-
|
55
|
+
def get_locale_from_header(env)
|
56
|
+
locale = nil
|
57
|
+
if accept = env['HTTP_ACCEPT_LANGUAGE']
|
58
|
+
locales = accept.scan(/([^;,]+)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i)
|
59
|
+
locales.sort_by{ |loc| 1 - (loc.last || 1).to_f }.each do |loc|
|
60
|
+
break if locale = to_available_locale(loc.first)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
locale
|
46
64
|
end
|
47
|
-
|
48
|
-
def
|
49
|
-
if
|
50
|
-
|
51
|
-
|
52
|
-
l.split(';q=')
|
53
|
-
}.first
|
54
|
-
lang.first.split("-").first
|
65
|
+
|
66
|
+
def to_available_locale(locale)
|
67
|
+
if locale =~ /^([a-z]{1,8})(-[a-z]{1,8})?$/i
|
68
|
+
locale = :"#{ $1.downcase }#{ ($2 || '').upcase }"
|
69
|
+
locale if I18n.available_locales.include?(locale)
|
55
70
|
end
|
56
71
|
end
|
57
72
|
end
|
@@ -2,12 +2,12 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "rack-i18n_locale_switcher"
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.4.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Christoph B\u{fc}nte, Andreas Korth"]
|
9
|
-
s.date = "2011-11-
|
10
|
-
s.description = "Detects the current locale from
|
9
|
+
s.date = "2011-11-26"
|
10
|
+
s.description = "Detects the current locale from query parameter, path prefix, host or accept header."
|
11
11
|
s.email = ["info@christophbuente.de", "andreas.korth@gmail.com"]
|
12
12
|
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.md", "lib/rack/i18n_locale_switcher.rb"]
|
13
13
|
s.files = ["CHANGELOG", "LICENSE", "Manifest", "README.md", "Rakefile", "lib/rack/i18n_locale_switcher.rb", "rack-i18n_locale_switcher.gemspec", "spec/i18n_locale_switcher_spec.rb"]
|
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.require_paths = ["lib"]
|
17
17
|
s.rubyforge_project = "rack-i18n_locale_switcher"
|
18
18
|
s.rubygems_version = "1.8.11"
|
19
|
-
s.summary = "Detects the current locale from
|
19
|
+
s.summary = "Detects the current locale from query parameter, path prefix, host or accept header."
|
20
20
|
|
21
21
|
if s.respond_to? :specification_version then
|
22
22
|
s.specification_version = 3
|
@@ -5,13 +5,19 @@ describe Rack::I18nLocaleSwitcher do
|
|
5
5
|
|
6
6
|
include Rack::Test::Methods
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
let :options do
|
9
|
+
{}
|
10
|
+
end
|
11
|
+
|
12
|
+
let :app do
|
13
|
+
opts = options
|
14
|
+
rack = Rack::Builder.new do
|
10
15
|
map "/" do
|
11
|
-
use Rack::I18nLocaleSwitcher
|
16
|
+
use Rack::I18nLocaleSwitcher, opts
|
12
17
|
run lambda { |env| [200, {}, "Coolness"] }
|
13
18
|
end
|
14
|
-
|
19
|
+
end
|
20
|
+
rack.to_app
|
15
21
|
end
|
16
22
|
|
17
23
|
before do
|
@@ -19,54 +25,107 @@ describe Rack::I18nLocaleSwitcher do
|
|
19
25
|
I18n.default_locale = :en
|
20
26
|
end
|
21
27
|
|
22
|
-
it "should
|
23
|
-
get '/'
|
28
|
+
it "should fall back to the locale to default locale" do
|
29
|
+
get 'http://example.com/some/path'
|
30
|
+
I18n.locale.should eql(I18n.default_locale)
|
31
|
+
|
32
|
+
get 'http://www.example.com/'
|
24
33
|
I18n.locale.should eql(I18n.default_locale)
|
25
34
|
end
|
35
|
+
|
36
|
+
it "should not accept invalid options" do
|
37
|
+
expect {
|
38
|
+
Rack::I18nLocaleSwitcher.new('app', :not_an_option => 'foo')
|
39
|
+
}.to raise_error(ArgumentError, "Invalid option(s) :not_an_option")
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'with custom sources' do
|
43
|
+
|
44
|
+
let :options do
|
45
|
+
{ :source => [ :header, :host ] }
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should honor the sequence" do
|
49
|
+
get 'http://de.example.com' , {}, {'HTTP_ACCEPT_LANGUAGE' => "es"}
|
50
|
+
I18n.locale.should eql(:es)
|
26
51
|
|
27
|
-
|
52
|
+
get 'http://de.example.com' , {}, {'HTTP_ACCEPT_LANGUAGE' => "foo"}
|
53
|
+
I18n.locale.should eql(:de)
|
28
54
|
|
29
|
-
|
30
|
-
get '/', :locale => 'de'
|
31
|
-
last_request.url.should include('?locale=de')
|
55
|
+
get 'http://de.example.com'
|
32
56
|
I18n.locale.should eql(:de)
|
33
57
|
end
|
34
58
|
|
35
|
-
it "should
|
36
|
-
get '
|
37
|
-
I18n.locale.should eql(
|
59
|
+
it "should ignore other sources" do
|
60
|
+
get 'http://example.com?locale=de'
|
61
|
+
I18n.locale.should eql(:en)
|
62
|
+
|
63
|
+
get 'http://example.com/de'
|
64
|
+
I18n.locale.should eql(:en)
|
38
65
|
end
|
39
66
|
end
|
40
67
|
|
41
|
-
context '
|
68
|
+
context 'request param' do
|
42
69
|
|
43
|
-
it "should set the
|
44
|
-
get '
|
70
|
+
it "should set the locale" do
|
71
|
+
get 'http://example.com?locale=de'
|
45
72
|
I18n.locale.should eql(:de)
|
73
|
+
|
74
|
+
get 'http://example.com?locale=en-US'
|
75
|
+
I18n.locale.should eql(:'en-US')
|
76
|
+
|
77
|
+
get 'http://example.com/some/path?foo=bar&locale=es¶m=value'
|
78
|
+
I18n.locale.should eql(:es)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should not set an unavailable locale" do
|
82
|
+
get 'http://example.com?locale=xx'
|
83
|
+
I18n.locale.should eql(I18n.default_locale)
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'name' do
|
87
|
+
|
88
|
+
let :options do
|
89
|
+
{ :param => 'lang' }
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should be configurable" do
|
93
|
+
get 'http://example.com?lang=de'
|
94
|
+
I18n.locale.should eql(:de)
|
95
|
+
end
|
46
96
|
end
|
47
97
|
end
|
48
98
|
|
49
|
-
context 'from
|
99
|
+
context 'from path prefix ' do
|
50
100
|
|
51
101
|
it "should set the I18n locale" do
|
52
|
-
get 'http://
|
102
|
+
get 'http://example.com/de/some/path/'
|
53
103
|
I18n.locale.should eql(:de)
|
104
|
+
|
105
|
+
get 'http://example.com/en-us'
|
106
|
+
I18n.locale.should eql(:'en-US')
|
54
107
|
end
|
55
108
|
end
|
56
109
|
|
57
|
-
context 'from
|
110
|
+
context 'from host' do
|
58
111
|
|
59
112
|
it "should set the I18n locale" do
|
60
|
-
get 'http://example.
|
113
|
+
get 'http://de.example.com/'
|
61
114
|
I18n.locale.should eql(:de)
|
115
|
+
|
116
|
+
get 'http://de-de.example.com/'
|
117
|
+
I18n.locale.should eql(:'de-DE')
|
62
118
|
end
|
63
119
|
end
|
64
120
|
|
65
121
|
context 'from accept-language header' do
|
66
122
|
|
67
123
|
it "should override the client requested locale" do
|
68
|
-
get '
|
69
|
-
I18n.locale.should eql(:de)
|
124
|
+
get 'http://example.com' , {}, {'HTTP_ACCEPT_LANGUAGE' => "de-de,de,en;q=0.5"}
|
125
|
+
I18n.locale.should eql(:'de-DE')
|
126
|
+
|
127
|
+
get 'http://example.com' , {}, {'HTTP_ACCEPT_LANGUAGE' => "en;q=0.5,en-US;q=0.8,es;q=0.7"}
|
128
|
+
I18n.locale.should eql(:'en-US')
|
70
129
|
end
|
71
130
|
end
|
72
131
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-i18n_locale_switcher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-11-
|
12
|
+
date: 2011-11-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
16
|
-
requirement: &
|
16
|
+
requirement: &2158734100 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2158734100
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: i18n
|
27
|
-
requirement: &
|
27
|
+
requirement: &2158733640 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2158733640
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: domainatrix
|
38
|
-
requirement: &
|
38
|
+
requirement: &2158733180 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2158733180
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: echoe
|
49
|
-
requirement: &
|
49
|
+
requirement: &2158732720 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *2158732720
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: rspec
|
60
|
-
requirement: &
|
60
|
+
requirement: &2158732260 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *2158732260
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rack-test
|
71
|
-
requirement: &
|
71
|
+
requirement: &2158731800 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,9 +76,9 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
80
|
-
description: Detects the current locale from
|
81
|
-
|
79
|
+
version_requirements: *2158731800
|
80
|
+
description: Detects the current locale from query parameter, path prefix, host or
|
81
|
+
accept header.
|
82
82
|
email:
|
83
83
|
- info@christophbuente.de
|
84
84
|
- andreas.korth@gmail.com
|
@@ -127,6 +127,6 @@ rubyforge_project: rack-i18n_locale_switcher
|
|
127
127
|
rubygems_version: 1.8.11
|
128
128
|
signing_key:
|
129
129
|
specification_version: 3
|
130
|
-
summary: Detects the current locale from
|
131
|
-
|
130
|
+
summary: Detects the current locale from query parameter, path prefix, host or accept
|
131
|
+
header.
|
132
132
|
test_files: []
|