Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve multi language support #10714

Merged
merged 5 commits into from Jan 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions api/app/controllers/spree/api/base_controller.rb
Expand Up @@ -6,6 +6,7 @@ class BaseController < ActionController::API
include Spree::Api::ControllerSetup
include Spree::Core::ControllerHelpers::Store
include Spree::Core::ControllerHelpers::StrongParameters
include Spree::Core::ControllerHelpers::Locale
include Spree::Core::ControllerHelpers::Currency

attr_accessor :current_api_user
Expand Down
7 changes: 1 addition & 6 deletions api/app/controllers/spree/api/v2/base_controller.rb
Expand Up @@ -5,13 +5,12 @@ class BaseController < ActionController::API
include CanCan::ControllerAdditions
include Spree::Core::ControllerHelpers::StrongParameters
include Spree::Core::ControllerHelpers::Store
include Spree::Core::ControllerHelpers::Locale
include Spree::Core::ControllerHelpers::Currency
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
rescue_from CanCan::AccessDenied, with: :access_denied
rescue_from Spree::Core::GatewayError, with: :gateway_error

before_action :set_user_language

def content_type
Spree::Api::Config[:api_v2_content_type]
end
Expand Down Expand Up @@ -96,10 +95,6 @@ def access_denied(exception)
def gateway_error(exception)
render_error_payload(exception.message)
end

def set_user_language
I18n.locale = current_store.default_locale
end
end
end
end
Expand Down
1 change: 1 addition & 0 deletions backend/app/controllers/spree/admin/base_controller.rb
Expand Up @@ -2,6 +2,7 @@ module Spree
module Admin
class BaseController < Spree::BaseController
helper 'spree/admin/navigation'
helper 'spree/locale'
layout 'spree/layouts/admin'

before_action :authorize_admin
Expand Down
14 changes: 0 additions & 14 deletions backend/app/controllers/spree/admin/stores_controller.rb
Expand Up @@ -9,8 +9,6 @@ class StoresController < Spree::Admin::BaseController
before_action :load_all_countries, only: [:new, :edit, :update, :create]
before_action :load_all_zones, only: %i[new edit]

helper_method :all_locales_options

def index
if params[:ids]
load_stores_by_ids
Expand Down Expand Up @@ -132,18 +130,6 @@ def normalize_supported_currencies
def set_default_country_id
@store.default_country_id = Spree::Config[:default_country_id]
end

def all_locales_options
if defined?(SpreeI18n)
SpreeI18n::Locale.all.map { |locale| locale_presentation(locale) }.push(['English (EN)', :en])
else
[['English (EN)', :en]]
end
end

def locale_presentation(locale)
[Spree.t('i18n.this_file_language', locale: locale), locale]
end
end
end
end
1 change: 1 addition & 0 deletions core/app/controllers/spree/base_controller.rb
Expand Up @@ -7,6 +7,7 @@ class Spree::BaseController < ApplicationController
include Spree::Core::ControllerHelpers::Search
include Spree::Core::ControllerHelpers::Store
include Spree::Core::ControllerHelpers::StrongParameters
include Spree::Core::ControllerHelpers::Locale
include Spree::Core::ControllerHelpers::Currency

respond_to :html
Expand Down
19 changes: 19 additions & 0 deletions core/app/helpers/spree/locale_helper.rb
@@ -0,0 +1,19 @@
module Spree
module LocaleHelper
def all_locales_options
supported_locales_for_all_stores.map { |locale| locale_presentation(locale) }
end

def available_locales_options
available_locales.map { |locale| locale_presentation(locale) }
end

def locale_presentation(locale)
if defined?(SpreeI18n)
[Spree.t('i18n.this_file_language', locale: locale), locale]
else
locale.to_s == 'en' ? ['English (US)', :en] : [locale, locale]
end
end
end
end
30 changes: 21 additions & 9 deletions core/app/models/spree/store.rb
Expand Up @@ -43,36 +43,47 @@ def self.default
end
end

def self.available_locales
Rails.cache.fetch('stores_available_locales') do
Spree::Store.all.map(&:supported_locales_list).flatten.uniq
end
end

def supported_currencies_list
(read_attribute(:supported_currencies).to_s.split(',') << default_currency).map(&:to_s).map do |code|
@supported_currencies_list ||= (read_attribute(:supported_currencies).to_s.split(',') << default_currency).map(&:to_s).map do |code|
::Money::Currency.find(code.strip)
end.uniq.compact
end

def supported_locales_list
# TODO: add support of multiple supported languages to a single Store
@supported_locales_list ||= [default_locale].compact.uniq
end

def unique_name
"#{name} (#{code})"
@unique_name ||= "#{name} (#{code})"
end

def formatted_url
return if url.blank?

if url.match(/http:\/\/|https:\/\//)
url
else
Rails.env.development? ? "http://#{url}" : "https://#{url}"
end
@formatted_url ||= if url.match(/http:\/\/|https:\/\//)
url
else
Rails.env.development? ? "http://#{url}" : "https://#{url}"
end
end

def countries_available_for_checkout
checkout_zone_or_default.try(:country_list) || Spree::Country.all
@countries_available_for_checkout ||= checkout_zone_or_default.try(:country_list) || Spree::Country.all
end

def states_available_for_checkout(country)
checkout_zone_or_default.try(:state_list_for, country) || country.states
end

def checkout_zone_or_default
checkout_zone || Spree::Zone.default_checkout_zone
@checkout_zone_or_default ||= checkout_zone || Spree::Zone.default_checkout_zone
end

private
Expand All @@ -94,6 +105,7 @@ def validate_not_default

def clear_cache
Rails.cache.delete('default_store')
Rails.cache.delete('stores_available_locales')
end
end
end
1 change: 1 addition & 0 deletions core/lib/spree/core.rb
Expand Up @@ -105,4 +105,5 @@ class DestroyWithOrdersError < StandardError; end
require 'spree/core/controller_helpers/search'
require 'spree/core/controller_helpers/store'
require 'spree/core/controller_helpers/strong_parameters'
require 'spree/core/controller_helpers/locale'
require 'spree/core/controller_helpers/currency'
14 changes: 6 additions & 8 deletions core/lib/spree/core/controller_helpers/common.rb
Expand Up @@ -10,8 +10,6 @@ module Common

layout :get_layout

before_action :set_user_language

protected

# can be used in views as well as controllers.
Expand Down Expand Up @@ -43,12 +41,12 @@ def accurate_title
private

def set_user_language
locale = session[:locale]
locale = store_locale if respond_to?(:store_locale, true) && locale.blank?
locale = config_locale if respond_to?(:config_locale, true) && locale.blank?
locale = Rails.application.config.i18n.default_locale if locale.blank?
locale = I18n.default_locale unless I18n.available_locales.map(&:to_s).include?(locale.to_s)
I18n.locale = locale
ActiveSupport::Deprecation.warn(<<-DEPRECATION, caller)
ControllerHelpers::Common#set_user_language is deprecated and will be removed in Spree 5.0.
Please use `before_action :set_locale` instead
DEPRECATION

set_locale
end

# Returns which layout to render.
Expand Down
57 changes: 57 additions & 0 deletions core/lib/spree/core/controller_helpers/locale.rb
@@ -0,0 +1,57 @@
module Spree
module Core
module ControllerHelpers
module Locale
extend ActiveSupport::Concern

included do
before_action :set_locale

helper_method :supported_locales
helper_method :supported_locales_for_all_stores
helper_method :current_locale
helper_method :supported_locale?
helper_method :available_locales
end

def set_locale
I18n.locale = current_locale
end

def current_locale
# session support was previously in SpreeI18n so we would like to keep it for now
# for easer upgrade
@current_locale ||= if defined?(session) && session.key?(:locale) && supported_locale?(session[:locale])
session[:locale]
elsif params[:locale].present? && supported_locale?(params[:locale])
params[:locale]
elsif respond_to?(:config_locale, true) && config_locale.present?
config_locale
else
current_store.default_locale || Rails.application.config.i18n.default_locale || I18n.default_locale
end
end

def supported_locales
@supported_locales ||= current_store.supported_locales_list
end

def supported_locale?(locale_code)
supported_locales.include?(locale_code&.to_s)
end

def supported_locales_for_all_stores
@supported_locales_for_all_stores ||= (if defined?(SpreeI18n)
(SpreeI18n::Locale.all << :en).map(&:to_s)
else
[Rails.application.config.i18n.default_locale, I18n.locale, :en]
end).uniq.compact
end

def available_locales
Spree::Store.available_locales
end
end
end
end
end
66 changes: 66 additions & 0 deletions core/spec/lib/spree/core/controller_helpers/locale_spec.rb
@@ -0,0 +1,66 @@
require 'spec_helper'

class FakesController < ApplicationController
include Spree::Core::ControllerHelpers::Auth
include Spree::Core::ControllerHelpers::Order
include Spree::Core::ControllerHelpers::Store
include Spree::Core::ControllerHelpers::Locale
end

class FakesControllerWithLocale < FakesController
def config_locale
'en'
end
end

describe Spree::Core::ControllerHelpers::Locale, type: :controller do
controller(FakesController) {}

describe '#current_locale' do
context 'store with local set' do
let!(:store) { create :store, default: true, default_locale: 'fr' }

it 'returns current store default locale' do
expect(controller.current_locale.to_s).to eq('fr')
end
end

context 'config_locale present' do
controller(FakesControllerWithLocale) {}

let!(:store) { create :store, default: true, default_locale: 'fr' }

it 'returns config_locale if present' do
expect(controller.current_locale.to_s).to eq('en')
end
end

context 'store without locale set' do
let!(:store) { create :store, default: true }

context 'without I18n.default_locale set' do
it 'fallbacks to english' do
expect(controller.current_locale.to_s).to eq('en')
end
end

context 'with I18n.default_locale set' do
before { I18n.default_locale = :de }

after { I18n.default_locale = :en }

it 'fallbacks to the default application locale' do
expect(controller.current_locale.to_s).to eq('de')
end
end
end
end

describe '#supported_locales' do
let!(:store) { create :store, default: true, default_locale: 'de' }

it 'returns supported currencies' do
expect(controller.supported_locales.to_s).to include('de')
end
end
end