new middleware: locale redirection (based on the prefix_default_locale site property)
did
committed Feb 20, 2015
commit c7dbaaf781d9db03f6302fe4fc85c0727b2f7834
Showing 10
changed files with
198 additions
and 20 deletions
locomotive/steam/middlewares.rb b/lib/locomotive/steam/middlewares.rb
+1
-14
| @@ | @@ -1,20 +1,7 @@ |
| require_relative 'middlewares/threadsafe' | |
| require_relative 'middlewares/helpers' | |
| - | require_relative 'middlewares/favicon' |
| - | require_relative 'middlewares/site' |
| - | require_relative 'middlewares/default_env' |
| - | require_relative 'middlewares/locale' |
| - | require_relative 'middlewares/timezone' |
| - | require_relative 'middlewares/logging' |
| - | require_relative 'middlewares/path' |
| - | require_relative 'middlewares/entry_submission' |
| - | require_relative 'middlewares/page' |
| - | require_relative 'middlewares/templatized_page' |
| - | |
| - | require_relative 'middlewares/dynamic_assets' |
| - | |
| - | require_relative 'middlewares/renderer' |
| + | require_relative_all 'middlewares' |
| module Locomotive::Steam | |
| module Middlewares | |
locomotive/steam/middlewares/helpers.rb b/lib/locomotive/steam/middlewares/helpers.rb
+12
-0
| @@ | @@ -22,6 +22,18 @@ module Locomotive::Steam |
| @next_response = [type, { 'Content-Type' => 'text/html', 'Location' => location }, []] | |
| end | |
| + | def modify_path(path = nil, &block) |
| + | path ||= request.path |
| + | |
| + | segments = path.split('/') |
| + | yield(segments) |
| + | path = segments.join('/') |
| + | |
| + | path = '/' if path.blank? |
| + | path += "?#{request.query_string}" unless request.query_string.empty? |
| + | path |
| + | end |
| + | |
| def log(msg, offset = 2) | |
| Locomotive::Common::Logger.info (' ' * offset) + msg | |
| end | |
locomotive/steam/middlewares/locale.rb b/lib/locomotive/steam/middlewares/locale.rb
+8
-1
| @@ | @@ -2,11 +2,15 @@ module Locomotive::Steam |
| module Middlewares | |
| # Set the locale from the path if possible or use the default one | |
| + | # |
| # Examples: | |
| + | # |
| # /fr/index => locale = :fr | |
| # /fr/ => locale = :fr | |
| # /index => locale = :en (default one) | |
| # | |
| + | # The |
| + | # |
| class Locale < ThreadSafe | |
| include Helpers | |
| @@ | @@ -30,7 +34,10 @@ module Locomotive::Steam |
| if _path =~ /^\/(#{site.locales.join('|')})+(\/|$)/ | |
| _locale = $1 | |
| _path = _path.gsub($1 + $2, '') | |
| - | # _path = 'index' if _path.blank? # TODO |
| + | |
| + | # let the other middlewares that the locale was |
| + | # extracted from the path. |
| + | env['steam.locale_in_path'] = true |
| end | |
| env['steam.path'] = _path | |
locomotive/steam/middlewares/locale_redirection.rb b/lib/locomotive/steam/middlewares/locale_redirection.rb
+62
-0
| @@ | @@ -0,0 +1,62 @@ |
| + | module Locomotive::Steam |
| + | module Middlewares |
| + | |
| + | # Redirect to the same page with or without the locale in the url |
| + | # based on the "prefix_default_locale" property of the current site. |
| + | # |
| + | # See the specs (spec/unit/middlewares/locale_redirection_spec.rb) for more details. |
| + | # |
| + | class LocaleRedirection < ThreadSafe |
| + | |
| + | include Helpers |
| + | |
| + | def _call |
| + | if url = redirect_url |
| + | redirect_to url |
| + | end |
| + | end |
| + | |
| + | protected |
| + | |
| + | def redirect_url |
| + | if apply_redirection? |
| + | if site.prefix_default_locale |
| + | path_with_default_locale if locale_not_mentioned_in_path? |
| + | else |
| + | path_without_default_locale if default_locale? && locale_mentioned_in_path? |
| + | end |
| + | end |
| + | end |
| + | |
| + | def apply_redirection? |
| + | site.locales.size > 1 && request.get? |
| + | end |
| + | |
| + | def default_locale? |
| + | locale.to_s == site.default_locale.to_s |
| + | end |
| + | |
| + | def locale_mentioned_in_path? |
| + | env['steam.locale_in_path'] |
| + | end |
| + | |
| + | def locale_not_mentioned_in_path? |
| + | !locale_mentioned_in_path? |
| + | end |
| + | |
| + | def path_with_default_locale |
| + | modify_path do |segments| |
| + | segments.insert(1, site.default_locale) |
| + | end |
| + | end |
| + | |
| + | def path_without_default_locale |
| + | modify_path do |segments| |
| + | segments.delete_at(1) |
| + | end |
| + | end |
| + | |
| + | end |
| + | end |
| + | |
| + | end |
locomotive/steam/repositories/filesystem/models/site.rb b/lib/locomotive/steam/repositories/filesystem/models/site.rb
+4
-1
| @@ | @@ -11,7 +11,10 @@ module Locomotive |
| attr_accessor :root_path | |
| def initialize(attributes = {}) | |
| - | super({ timezone: 'UTC' }.merge(attributes)) |
| + | super({ |
| + | timezone: 'UTC', |
| + | prefix_default_locale: false |
| + | }.merge(attributes)) |
| end | |
| def default_locale | |
locomotive/steam/server.rb b/lib/locomotive/steam/server.rb
+1
-0
| @@ | @@ -51,6 +51,7 @@ module Locomotive::Steam |
| Middlewares::Timezone, | |
| Middlewares::EntrySubmission, | |
| Middlewares::Locale, | |
| + | Middlewares::LocaleRedirection, |
| Middlewares::Path, | |
| Middlewares::Page, | |
| Middlewares::TemplatizedPage | |
spec/integration/server/basic_spec.rb
+1
-1
| @@ | @@ -111,7 +111,7 @@ describe Locomotive::Steam::Server do |
| describe 'translations' do | |
| it 'translates strings' do | |
| - | get '/en' |
| + | get '/' |
| expect(last_response.body).to include 'Powered by' | |
| get '/fr' | |
| expect(last_response.body).to include 'Propulsé par' | |
spec/support/helpers.rb
+4
-0
| @@ | @@ -36,5 +36,9 @@ module Spec |
| def default_fixture_site_path | |
| File.expand_path('../../fixtures/default/', __FILE__) | |
| end | |
| + | |
| + | def env_for(url, opts={}) |
| + | Rack::MockRequest.env_for(url, opts) |
| + | end |
| end | |
| end | |
spec/unit/middlewares/locale_redirection_spec.rb
+105
-0
| @@ | @@ -0,0 +1,105 @@ |
| + | require 'spec_helper' |
| + | |
| + | require_relative '../../../lib/locomotive/steam/middlewares/threadsafe' |
| + | require_relative '../../../lib/locomotive/steam/middlewares/helpers' |
| + | require_relative '../../../lib/locomotive/steam/middlewares/locale_redirection' |
| + | |
| + | describe Locomotive::Steam::Middlewares::LocaleRedirection do |
| + | |
| + | let(:prefixed) { false } |
| + | let(:site) { instance_double('Site', prefix_default_locale: prefixed, default_locale: :de, locales: %w(de fr)) } |
| + | let(:url) { 'http://models.example.com' } |
| + | let(:app) { ->(env) { [200, env, 'app'] } } |
| + | let(:middleware) { Locomotive::Steam::Middlewares::LocaleRedirection.new(app) } |
| + | let(:locale) { 'de' } |
| + | let(:locale_in_path) { true } |
| + | |
| + | subject do |
| + | env = env_for(url, 'steam.site' => site, 'steam.locale' => locale, 'steam.locale_in_path' => locale_in_path) |
| + | env['steam.request'] = Rack::Request.new(env) |
| + | code, env = middleware.call(env) |
| + | [code, env['Location']] |
| + | end |
| + | |
| + | describe 'not prefixed by locale' do |
| + | |
| + | describe 'strip default locale from root path' do |
| + | let(:url) { 'http://models.example.com/de' } |
| + | it { is_expected.to eq [301, '/'] } |
| + | end |
| + | |
| + | describe 'strip default locale' do |
| + | let(:url) { 'http://models.example.com/de/hello' } |
| + | it { is_expected.to eq [301, '/hello'] } |
| + | end |
| + | |
| + | describe 'strip default locale from root path with query' do |
| + | let(:url) { 'http://models.example.com/de?this=is_a_param' } |
| + | it { is_expected.to eq [301, '/?this=is_a_param'] } |
| + | end |
| + | |
| + | describe 'strip default locale from path with query' do |
| + | let(:url) { 'http://models.example.com/de/hello?this=is_a_param' } |
| + | it { is_expected.to eq [301, '/hello?this=is_a_param'] } |
| + | end |
| + | |
| + | describe 'dont strip a non-default locale' do |
| + | let(:locale) { 'fr' } |
| + | let(:url) { 'http://models.example.com/fr/hello' } |
| + | it { is_expected.to eq [200, nil] } |
| + | end |
| + | |
| + | describe 'dont redirect URL without locale' do |
| + | let(:locale) { :de } |
| + | let(:locale_in_path) { false } |
| + | let(:url) { 'http://models.example.com/hello' } |
| + | it { is_expected.to eq [200, nil] } |
| + | end |
| + | |
| + | end |
| + | |
| + | describe 'prefixed by locale' do |
| + | |
| + | let(:prefixed) { true } |
| + | |
| + | describe 'without locale' do |
| + | |
| + | let(:locale_in_path) { false } |
| + | |
| + | describe 'add default locale to root path' do |
| + | let(:url) { 'http://models.example.com/' } |
| + | it { is_expected.to eq [301, '/de'] } |
| + | end |
| + | |
| + | describe 'add default locale to long path' do |
| + | let(:url) { 'http://models.example.com/hello/world' } |
| + | it { is_expected.to eq [301, '/de/hello/world'] } |
| + | end |
| + | |
| + | describe 'add default locale to url with path and query' do |
| + | let(:url) { 'http://models.example.com/hello/world?this=is_me' } |
| + | it { is_expected.to eq [301, '/de/hello/world?this=is_me'] } |
| + | end |
| + | |
| + | end |
| + | |
| + | describe 'with locale' do |
| + | |
| + | let(:locale_in_path) { true } |
| + | |
| + | describe 'dont add default locale if already present' do |
| + | let(:url) { 'http://models.example.com/de/hello/world' } |
| + | it { is_expected.to eq [200, nil] } |
| + | end |
| + | |
| + | describe 'dont add default locale to localized path' do |
| + | let(:locale) { 'fr' } |
| + | let(:url) { 'http://models.example.com/fr/hello/world' } |
| + | it { is_expected.to eq [200, nil] } |
| + | end |
| + | |
| + | end |
| + | |
| + | end |
| + | |
| + | end |
spec/unit/middlewares/renderer_spec.rb
+0
-3
| @@ | @@ -26,7 +26,4 @@ describe Locomotive::Steam::Middlewares::Renderer do |
| end | |
| - | def env_for(url, opts={}) |
| - | Rack::MockRequest.env_for(url, opts) |
| - | end |
| end | |