rack-locale_chooser 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +32 -0
- data/Rakefile +2 -0
- data/lib/rack-locale_chooser.rb +12 -0
- data/lib/rack-locale_chooser/chooser.rb +94 -0
- data/lib/rack-locale_chooser/version.rb +5 -0
- data/rack-locale_chooser.gemspec +25 -0
- data/spec/rack-locale_chooser_spec.rb +64 -0
- data/spec/spec_helper.rb +14 -0
- metadata +123 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
rack-locale_chooser (0.0.4)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.1.2)
|
10
|
+
i18n (0.4.2)
|
11
|
+
rack (1.1.0)
|
12
|
+
rack-test (0.5.4)
|
13
|
+
rack (>= 1.0)
|
14
|
+
rspec (2.0.1)
|
15
|
+
rspec-core (~> 2.0.1)
|
16
|
+
rspec-expectations (~> 2.0.1)
|
17
|
+
rspec-mocks (~> 2.0.1)
|
18
|
+
rspec-core (2.0.1)
|
19
|
+
rspec-expectations (2.0.1)
|
20
|
+
diff-lcs (>= 1.1.2)
|
21
|
+
rspec-mocks (2.0.1)
|
22
|
+
rspec-core (~> 2.0.1)
|
23
|
+
rspec-expectations (~> 2.0.1)
|
24
|
+
|
25
|
+
PLATFORMS
|
26
|
+
ruby
|
27
|
+
|
28
|
+
DEPENDENCIES
|
29
|
+
i18n
|
30
|
+
rack-locale_chooser!
|
31
|
+
rack-test
|
32
|
+
rspec (~> 2.0.0.beta.22)
|
data/Rakefile
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'net/geoip'
|
2
|
+
|
3
|
+
module Rack::LocaleChooser
|
4
|
+
class Chooser
|
5
|
+
def initialize(app, options = {})
|
6
|
+
@app, @options = app, {
|
7
|
+
:default_domain => 'example.com',
|
8
|
+
:geodb_path => '/usr/local/Cellar/geoip/1.4.6/share/GeoIP/GeoLiteCity.dat'
|
9
|
+
}.merge(options)
|
10
|
+
@geodb = Net::GeoIP.new(@options[:geodb_path])
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
@env = env
|
15
|
+
@request = Rack::Request.new(@env)
|
16
|
+
|
17
|
+
@original_url = @request.url
|
18
|
+
|
19
|
+
set_session_options
|
20
|
+
|
21
|
+
set_locale
|
22
|
+
|
23
|
+
@app.call(env) if @request.post? || @request.put? || @request.delete?
|
24
|
+
|
25
|
+
if @original_url != localized_url then
|
26
|
+
[301, {'Location' => localized_url}, '']
|
27
|
+
else
|
28
|
+
status, headers, body = @app.call(env)
|
29
|
+
response = Rack::Response.new(body, status, headers)
|
30
|
+
response.set_cookie('locale', {
|
31
|
+
:value => I18n.locale,
|
32
|
+
:path => '/',
|
33
|
+
:domain => @env["rack.session.options"][:domain]})
|
34
|
+
response.finish
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# check http://codetunes.com/2009/04/17/dynamic-cookie-domains-with-racks-middleware/
|
39
|
+
def set_session_options
|
40
|
+
@env['rack.session.options'] = {} unless @env['rack.session.options']
|
41
|
+
@env['rack.session.options'][:domain] = @options[:default_domain]
|
42
|
+
end
|
43
|
+
|
44
|
+
def geo_record
|
45
|
+
@geo_record ||= begin
|
46
|
+
@geodb[@env["REMOTE_ADDR"]]
|
47
|
+
rescue Net::GeoIP::RecordNotFoundError
|
48
|
+
return nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def url_locale
|
53
|
+
hosts = @options[:host_mappings].invert
|
54
|
+
hosts["http://#{@request.host}"] if hosts.has_key?("http://#{@request.host}")
|
55
|
+
end
|
56
|
+
|
57
|
+
def cookie_locale
|
58
|
+
@request.cookies['locale']
|
59
|
+
end
|
60
|
+
|
61
|
+
def geo_locale
|
62
|
+
@options[:country_mappings][geo_record.country_code] if @options[:country_mappings] and geo_record
|
63
|
+
end
|
64
|
+
|
65
|
+
def browser_locale
|
66
|
+
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
|
67
|
+
if lang = @env['HTTP_ACCEPT_LANGUAGE']
|
68
|
+
lang = lang.split(",").map { |l|
|
69
|
+
l += ';q=1.0' unless l =~ /;q=\d+\.\d+$/
|
70
|
+
l.split(';q=')
|
71
|
+
}.first
|
72
|
+
browser_locale = lang.first.split("-").first
|
73
|
+
else
|
74
|
+
browser_locale = I18n.default_locale
|
75
|
+
end
|
76
|
+
@options[:host_mappings].has_key?(browser_locale.to_sym) ? browser_locale : I18n.default_locale
|
77
|
+
end
|
78
|
+
|
79
|
+
def locale
|
80
|
+
url_locale || cookie_locale || geo_locale || browser_locale
|
81
|
+
end
|
82
|
+
|
83
|
+
def set_locale
|
84
|
+
I18n.locale = @env['rack.locale'] = locale.to_sym
|
85
|
+
@env['rack.city'] = geo_record.city if geo_record
|
86
|
+
end
|
87
|
+
|
88
|
+
def localized_url
|
89
|
+
current_host = @request.url.gsub(/http\:\/\/(\D*)[\/]|http\:\/\/(\D*)/).first().gsub(/:$|\/$/, '')
|
90
|
+
return @request.url.gsub(current_host, @options[:host_mappings][locale.to_sym]) if @options[:host_mappings][locale.to_sym]
|
91
|
+
@original_url
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "rack-locale_chooser/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "rack-locale_chooser"
|
7
|
+
s.version = Rack::LocaleChooser::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Jefferson Jean Martins Girão"]
|
10
|
+
s.email = ["contato@jefferson.eti.br"]
|
11
|
+
s.homepage = "https://github.com/jeffersongirao/rack-locale_chooser"
|
12
|
+
s.summary = %q{Rack Based Locale Selector}
|
13
|
+
s.description = %q{Rack Based Locale Selector}
|
14
|
+
|
15
|
+
s.rubyforge_project = "rack-locale_chooser"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_development_dependency "rspec", "~> 2.0.0.beta.22"
|
23
|
+
s.add_development_dependency "rack-test"
|
24
|
+
s.add_development_dependency "i18n"
|
25
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Rack::LocaleChooser do
|
4
|
+
def app
|
5
|
+
app = Rack::Builder.new {
|
6
|
+
use Rack::LocaleChooser::Chooser, :host_mappings => { :en => 'http://us.example.com',
|
7
|
+
:es => 'http://es.example.com' },
|
8
|
+
:country_mappings => { 'VE' => :es }
|
9
|
+
run BasicRackApp.new
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
context "request to root domain host" do
|
14
|
+
before do
|
15
|
+
I18n.default_locale = :en
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should be redirected following cookie's value" do
|
19
|
+
get 'http://example.com/', {}, 'HTTP_COOKIE' => 'locale=es'
|
20
|
+
last_response.status.should == 301
|
21
|
+
last_response.headers['Location'].should == 'http://es.example.com/'
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should be redirected folling geolocation" do
|
25
|
+
get 'http://example.com', {}
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should be redirected following HTTP_ACCEPT_LANGUAGE headers" do
|
29
|
+
get 'http://example.com/', {}, 'HTTP_ACCEPT_LANGUAGE' => 'es'
|
30
|
+
last_response.status.should == 301
|
31
|
+
last_response.headers['Location'].should == 'http://es.example.com/'
|
32
|
+
I18n.locale.should == :es
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should map locale to explicit domain mappings" do
|
36
|
+
get 'http://example.com/', {}, 'HTTP_ACCEPT_LANGUAGE' => 'en'
|
37
|
+
last_response.status.should == 301
|
38
|
+
last_response.headers['Location'].should == 'http://us.example.com/'
|
39
|
+
I18n.locale.should == :en
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
it "should map locale to explicit location mappings by country level" do
|
44
|
+
get 'http://example.com/', {}, 'REMOTE_ADDR' => '200.1.1.2' # Cacacas VE
|
45
|
+
last_response.status.should == 301
|
46
|
+
last_response.headers['Location'].should == 'http://es.example.com/'
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
it "fall back to default if accept language headers not on mappings" do
|
51
|
+
get 'http://example.com/', {}, 'HTTP_ACCEPT_LANGUAGE' => 'ru'
|
52
|
+
last_response.status.should == 301
|
53
|
+
last_response.headers['Location'].should == 'http://us.example.com/'
|
54
|
+
I18n.locale.should == :en
|
55
|
+
end
|
56
|
+
|
57
|
+
it "don't change anything if url is called directly" do
|
58
|
+
get 'http://es.example.com/'
|
59
|
+
last_response.status.should == 200
|
60
|
+
I18n.locale.should == :es
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rack/test'
|
3
|
+
require 'rack-locale_chooser/chooser'
|
4
|
+
require 'i18n'
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.include Rack::Test::Methods
|
8
|
+
end
|
9
|
+
|
10
|
+
class BasicRackApp
|
11
|
+
def call(env)
|
12
|
+
[200, {'Content-Type' => 'text/plain'}, 'Hello World']
|
13
|
+
end
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack-locale_chooser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 17
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 7
|
10
|
+
version: 0.0.7
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- "Jefferson Jean Martins Gir\xC3\xA3o"
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-11-03 00:00:00 -03:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 62196431
|
30
|
+
segments:
|
31
|
+
- 2
|
32
|
+
- 0
|
33
|
+
- 0
|
34
|
+
- beta
|
35
|
+
- 22
|
36
|
+
version: 2.0.0.beta.22
|
37
|
+
type: :development
|
38
|
+
version_requirements: *id001
|
39
|
+
- !ruby/object:Gem::Dependency
|
40
|
+
name: rack-test
|
41
|
+
prerelease: false
|
42
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
hash: 3
|
48
|
+
segments:
|
49
|
+
- 0
|
50
|
+
version: "0"
|
51
|
+
type: :development
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: i18n
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
type: :development
|
66
|
+
version_requirements: *id003
|
67
|
+
description: Rack Based Locale Selector
|
68
|
+
email:
|
69
|
+
- contato@jefferson.eti.br
|
70
|
+
executables: []
|
71
|
+
|
72
|
+
extensions: []
|
73
|
+
|
74
|
+
extra_rdoc_files: []
|
75
|
+
|
76
|
+
files:
|
77
|
+
- .gitignore
|
78
|
+
- Gemfile
|
79
|
+
- Gemfile.lock
|
80
|
+
- Rakefile
|
81
|
+
- lib/rack-locale_chooser.rb
|
82
|
+
- lib/rack-locale_chooser/chooser.rb
|
83
|
+
- lib/rack-locale_chooser/version.rb
|
84
|
+
- rack-locale_chooser.gemspec
|
85
|
+
- spec/rack-locale_chooser_spec.rb
|
86
|
+
- spec/spec_helper.rb
|
87
|
+
has_rdoc: true
|
88
|
+
homepage: https://github.com/jeffersongirao/rack-locale_chooser
|
89
|
+
licenses: []
|
90
|
+
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
|
94
|
+
require_paths:
|
95
|
+
- lib
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
hash: 3
|
102
|
+
segments:
|
103
|
+
- 0
|
104
|
+
version: "0"
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
hash: 3
|
111
|
+
segments:
|
112
|
+
- 0
|
113
|
+
version: "0"
|
114
|
+
requirements: []
|
115
|
+
|
116
|
+
rubyforge_project: rack-locale_chooser
|
117
|
+
rubygems_version: 1.3.7
|
118
|
+
signing_key:
|
119
|
+
specification_version: 3
|
120
|
+
summary: Rack Based Locale Selector
|
121
|
+
test_files:
|
122
|
+
- spec/rack-locale_chooser_spec.rb
|
123
|
+
- spec/spec_helper.rb
|