diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 180776a63..6dfff28b6 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -4,10 +4,6 @@ class ApplicationController < ActionController::Base protect_from_forgery with: :exception - before_action :set_current_locale - before_action :set_current_theme - - before_action :set_site_locale before_action :check_for_redirection before_action :strip_file_extension before_action :authorize, if: :staging? @@ -46,25 +42,6 @@ def authorize redirect_to [:signin], alert: 'You need to sign in to view that page.' unless signed_in? end - def set_current_locale - locale = request.subdomain - I18n.locale = locale if I18n.available_locales.include?(locale.to_sym) - - # Force the subdomain to match the locale. - # Don’t do this in development, because typically local development - # environments don’t support subdomains (en.localhost doesn’t resolve). - if (I18n.locale != I18n.default_locale) && # Don’t redirect to en.crimethinc.com - request.subdomain.empty? && # Don’t redirect if there’s a subdomain - Rails.env.production? # Don’t redirect in development - - redirect_to({ subdomain: I18n.locale }.merge(params.permit!)) - end - end - - def set_current_theme - Current.theme = ENV.fetch('THEME') { '2017' } - end - def check_for_redirection redirect = Redirect.where(source_path: request.path.downcase).last redirect = Redirect.where(source_path: "#{request.path.downcase}/").last if redirect.blank? @@ -146,10 +123,5 @@ def page_share_image_url # TODO: implement this algorithm 'https://cloudfront.crimethinc.com/assets/share/crimethinc-site-share.png' end - - def set_site_locale - @site_locale = LocaleService.find(locale: nil, lang_code: I18n.locale) - end - # ...Page Share end diff --git a/app/controllers/steal_something_from_work_day_controller.rb b/app/controllers/steal_something_from_work_day_controller.rb index 7958a1ede..a763adc9f 100644 --- a/app/controllers/steal_something_from_work_day_controller.rb +++ b/app/controllers/steal_something_from_work_day_controller.rb @@ -11,7 +11,7 @@ class StealSomethingFromWorkDayController < ApplicationController def show # Remove current locale from language switcher in the view @locales = STEAL_SOMETHING_FROM_WORK_DAY_LOCALES.dup - @locales.delete I18n.locale + @locales.delete Current.locale @sections = [ 'Introduction', diff --git a/app/helpers/locales_helper.rb b/app/helpers/locales_helper.rb index 515e0ec71..a130d02d3 100644 --- a/app/helpers/locales_helper.rb +++ b/app/helpers/locales_helper.rb @@ -6,7 +6,7 @@ def locale abbreviation def locale_nav_item_classes_for locale classes = [] classes << locale.abbreviation - classes << 'current' if I18n.locale.to_s == locale.abbreviation + classes << 'current' if Current.locale == locale classes end end diff --git a/app/helpers/markdown_helper.rb b/app/helpers/markdown_helper.rb index 70430e822..1f68f4d26 100644 --- a/app/helpers/markdown_helper.rb +++ b/app/helpers/markdown_helper.rb @@ -1,6 +1,13 @@ module MarkdownHelper def render_markdown_for page: - content = File.read [Rails.root, "config/locales/pages/#{I18n.locale}", "#{page}.markdown"].join('/') + content = File.read [ + Rails.root, + 'config', + 'locales', + 'pages', + Current.locale.abbreviation, + "#{page}.markdown" + ].join('/') render_markdown content end diff --git a/app/helpers/tags_helper.rb b/app/helpers/tags_helper.rb index ac2cac6e2..b2e9514cc 100644 --- a/app/helpers/tags_helper.rb +++ b/app/helpers/tags_helper.rb @@ -3,11 +3,11 @@ module TagsHelper attr_accessor :html_id def html_dir - article_locale&.language_direction.presence || t('language_direction') + article_locale&.language_direction.presence || Current.locale.language_direction end def html_lang - article_locale&.abbreviation.presence || I18n.locale + article_locale&.abbreviation.presence || Current.locale.abbreviation end def html_prefix diff --git a/app/middlewares/rack/current_locale.rb b/app/middlewares/rack/current_locale.rb new file mode 100644 index 000000000..5bb6abdb6 --- /dev/null +++ b/app/middlewares/rack/current_locale.rb @@ -0,0 +1,86 @@ +module Rack + class CurrentLocale + def initialize app + @app = app + end + + def call env + @req = Rack::Request.new(env) + + set_current_locale + set_current_locale_from_subdomain + redirect_to_locale_subdomain + + @app.call(env) + end + + private + + def set_current_locale + Current.locale = ::Locale.find_by abbreviation: I18n.locale + end + + def set_current_locale_from_subdomain + return if subdomain.blank? + return unless I18n.available_locales.include? subdomain.to_sym + + Current.locale = ::Locale.find_by abbreviation: subdomain + end + + def redirect_to_locale_subdomain + # Force the subdomain to match the locale. + # Don’t do this in development, because typically local development + # environments don’t support subdomains (en.localhost doesn’t resolve). + + # Don’t redirect to en.crimethinc.com + return if Current.locale.english? + + # Don’t redirect if there’s a subdomain + return if subdomain.present? + + # Don’t redirect in development + return if Rails.env.production? + + redirect localized_url + end + + def subdomain + fully_qualified_domain = @req.host + locale_subdomain = fully_qualified_domain.split('.').first + + locale_subdomain unless locale_subdomain == fully_qualified_domain + end + + def decorated_subdomain + "#{subdomain}." unless subdomain.blank? + end + + def decorated_port + ":#{@req.port}" if Rails.env.development? + end + + def decorated_query_params + "?#{@req.query_string}" if @req.query_string.present? + end + + def localized_url + [ + @req.scheme, + '://', + decorated_subdomain, + @req.host, + decorated_port, + @req.path, + decorated_query_params + ].join + end + + def redirect location + [ + 301, + { 'Location' => location, 'Content-Type' => 'text/html' }, + ['Moved Permanently'] + ] + end + end +end diff --git a/app/middlewares/rack/current_theme.rb b/app/middlewares/rack/current_theme.rb new file mode 100644 index 000000000..e181def97 --- /dev/null +++ b/app/middlewares/rack/current_theme.rb @@ -0,0 +1,13 @@ +module Rack + class CurrentTheme + def initialize app + @app = app + end + + def call env + Current.theme = ENV.fetch('THEME') { '2017' } + + @app.call(env) + end + end +end diff --git a/app/models/article.rb b/app/models/article.rb index 1a6f438f1..aa778ac8a 100644 --- a/app/models/article.rb +++ b/app/models/article.rb @@ -105,13 +105,13 @@ def localizations def localization_in locale [ - Article.published.live.find_by(locale: locale, canonical_id: id), - Article.published.live.find_by(locale: locale, id: canonical_id) + Article.published.live.find_by(locale: locale.abbreviation, canonical_id: id), + Article.published.live.find_by(locale: locale.abbreviation, id: canonical_id) ].compact.first end def preferred_localization - localization_in(I18n.locale).presence || self + localization_in(Current.locale).presence || self end def canonical_article diff --git a/app/models/concerns/translatable.rb b/app/models/concerns/translatable.rb index b775161a9..b851b5b9f 100644 --- a/app/models/concerns/translatable.rb +++ b/app/models/concerns/translatable.rb @@ -15,11 +15,11 @@ def id_and_name end def preferred_localization - localization_in(I18n.locale).presence || self + localization_in(Current.locale).presence || self end def localization_in locale - self.class.published.live.where(locale: locale).where('id = ? OR canonical_id = ?', canonical_id, id).limit(1).first + self.class.published.live.where(locale: locale.abbreviation).where('id = ? OR canonical_id = ?', canonical_id, id).limit(1).first end def localizations diff --git a/app/models/current.rb b/app/models/current.rb index 49d647a38..8908d161b 100644 --- a/app/models/current.rb +++ b/app/models/current.rb @@ -1,3 +1,3 @@ class Current < ActiveSupport::CurrentAttributes - attribute :user, :theme + attribute :user, :locale, :theme end diff --git a/app/models/locale.rb b/app/models/locale.rb index 3fd964dbd..854fc64c5 100644 --- a/app/models/locale.rb +++ b/app/models/locale.rb @@ -13,14 +13,6 @@ class Locale < ApplicationRecord default_scope { order(abbreviation: :asc) } class << self - def current - I18n.locale - end - - def english? - I18n.locale == :en - end - def live Locale.unscoped.order(articles_count: :desc, abbreviation: :asc).where.not(articles_count: 0) end diff --git a/app/views/2017/languages/show.html.erb b/app/views/2017/languages/show.html.erb index 8292acfe1..d6776534c 100644 --- a/app/views/2017/languages/show.html.erb +++ b/app/views/2017/languages/show.html.erb @@ -14,7 +14,7 @@
<%= link_to(t("footer.site_mode"), url_for_current_path_with_subdomain(subdomain: :lite)) %>
diff --git a/app/views/2017/shared/_header.html.erb b/app/views/2017/shared/_header.html.erb index cb2400c41..d17b49592 100644 --- a/app/views/2017/shared/_header.html.erb +++ b/app/views/2017/shared/_header.html.erb @@ -16,9 +16,9 @@<%= link_to(t('footer.site_mode'), url_for_current_path_with_subdomain(subdomain: :lite)) %>
diff --git a/config/application.rb b/config/application.rb index a74a000c1..12457df41 100644 --- a/config/application.rb +++ b/config/application.rb @@ -8,6 +8,8 @@ require_relative '../app/middlewares/rack/pic_twitter_redirect' require_relative '../app/middlewares/rack/redirect' require_relative '../app/middlewares/rack/teapot' +require_relative '../app/middlewares/rack/current_locale' +require_relative '../app/middlewares/rack/current_theme' require 'rack/contrib' # Require the gems listed in Gemfile, including any gems @@ -25,6 +27,8 @@ class Application < Rails::Application config.middleware.use Rack::Redirect config.middleware.use Rack::Attack config.middleware.use Rack::Locale + config.middleware.use Rack::CurrentLocale + config.middleware.use Rack::CurrentTheme config.middleware.insert_after ActionDispatch::Static, Rack::Deflater # Initialize configuration defaults for originally generated Rails version. diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 64a0afcc0..302549a0e 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -6,6 +6,11 @@ driven_by :selenium_headless, using: :firefox end + config.before do + Current.locale = FactoryBot.build_stubbed :locale + Current.theme = '2017' + end + config.expect_with :rspec do |expectations| expectations.include_chain_clauses_in_custom_matcher_descriptions = true end