Skip to content

Commit

Permalink
Enable translations fallback (pupilfirst#825)
Browse files Browse the repository at this point in the history
Translations fall back to `I18N_DEFAULT_LOCALE`, or `en` if the
environment variable is missing.

While we don't allow the user to select their locale (yet), we do have a
column in the database that's meant to enable this. There's no reason
to not use this value right now. At least it allows testing to make sure
that locales are working as they should.
  • Loading branch information
harigopal authored Oct 27, 2021
1 parent a2a0c2d commit 43c51ee
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 46 deletions.
114 changes: 72 additions & 42 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class ApplicationController < ActionController::Base
before_action :redirect_to_primary_domain, if: :domain_redirection_required?

around_action :set_time_zone, if: :current_user
around_action :switch_locale, if: :current_user

helper_method :avatar
helper_method :current_host
Expand Down Expand Up @@ -40,7 +41,7 @@ class ApplicationController < ActionController::Base
end

rescue_from ActionController::InvalidAuthenticityToken do
flash[:error] = I18n.t('shared.invalid_authenticity_token_error')
flash[:error] = I18n.t('shared.invalid_authenticity_token_error')
end

# Redirect all requests from unknown domains to service homepage.
Expand All @@ -66,48 +67,56 @@ def current_domain

# Returns the "resolved" school for a request.
def current_school
@current_school ||= if Rails.application.secrets.multitenancy
resolved_school = current_domain&.school
@current_school ||=
if Rails.application.secrets.multitenancy
resolved_school = current_domain&.school

raise RequestFromUnknownDomain if resolved_school.blank?
raise RequestFromUnknownDomain if resolved_school.blank?

resolved_school
else
School.first
end
resolved_school
else
School.first
end
end

def current_coach
@current_coach ||= current_user&.faculty
end

def current_founder
@current_founder ||= begin
if current_user.present?
founder_id = read_cookie(:founder_id)

# Founders in current school for the user
founders = current_user.founders

# Try to select founder from value stored in cookie.
founder = founder_id.present? ? founders.not_dropped_out.find_by(id: founder_id) : nil

# Return selected founder, if any, or return the first founder (if any).
founder.presence || founders.not_dropped_out.first
@current_founder ||=
begin
if current_user.present?
founder_id = read_cookie(:founder_id)

# Founders in current school for the user
founders = current_user.founders

# Try to select founder from value stored in cookie.
founder =
if founder_id.present?
founders.not_dropped_out.find_by(id: founder_id)
else
nil
end

# Return selected founder, if any, or return the first founder (if any).
founder.presence || founders.not_dropped_out.first
end
end
end
end

def current_startup
@current_startup ||= current_founder&.startup
end

def current_school_admin
@current_school_admin ||= begin
if current_user.present? && current_school.present?
current_user.school_admin
@current_school_admin ||=
begin
if current_user.present? && current_school.present?
current_user.school_admin
end
end
end
end

# sets a permanent signed cookie. Additional options such as :tld_length can be passed via the options_hash
Expand Down Expand Up @@ -137,7 +146,8 @@ def feature_enabled?(feature_name)
# Makes redirects observable from integration tests.
def observable_redirect_to(url)
if Rails.env.test?
render plain: "If this wasn't an integration test, you'd be redirected to: #{url}"
render plain:
"If this wasn't an integration test, you'd be redirected to: #{url}"
else
redirect_to(url)
end
Expand All @@ -156,18 +166,20 @@ def pundit_user
helper_method :pundit_user

def api_token
@api_token ||= begin
header = request.headers['Authorization']&.strip
@api_token ||=
begin
header = request.headers['Authorization']&.strip

# Authorization headers are of format "Authorization: <type> <credentials>".
# We only care about the supplied credentials.
header.split(' ')[-1] if header.present?
end
# Authorization headers are of format "Authorization: <type> <credentials>".
# We only care about the supplied credentials.
header.split(' ')[-1] if header.present?
end
end

def current_user
if api_token.present?
@current_user ||= Users::FindByApiTokenService.new(api_token, current_school).find
@current_user ||=
Users::FindByApiTokenService.new(api_token, current_school).find
else
super
end
Expand All @@ -179,6 +191,10 @@ def set_time_zone(&block) # rubocop:disable Naming/AccessorMethodName
Time.use_zone(current_user.time_zone, &block)
end

def switch_locale(&action)
I18n.with_locale(current_user.locale, &action)
end

def sign_out_if_required
service = ::Users::ManualSignOutService.new(self, current_user)
service.sign_out_if_required
Expand All @@ -195,17 +211,28 @@ def authenticate_founder!
end

def storable_location?
non_html_response = destroy_user_session_path || (is_a?(::TargetsController) && params[:action] == "details_v2")
public_page = _process_action_callbacks.none? { |p| p.filter == :authenticate_user! }
non_html_response =
destroy_user_session_path ||
(is_a?(::TargetsController) && params[:action] == 'details_v2')

public_page =
_process_action_callbacks.none? { |p| p.filter == :authenticate_user! }

request.get? && is_navigational_format? && !request.xhr? && !public_page && !non_html_response
request.get? && is_navigational_format? && !request.xhr? && !public_page &&
!non_html_response
end

def store_user_location
store_location_for(:user, request.fullpath)
end

def avatar(name, founder: nil, faculty: nil, version: :mid, background_shape: :circle)
def avatar(
name,
founder: nil,
faculty: nil,
version: :mid,
background_shape: :circle
)
if faculty.present? && faculty.image.attached?
return helpers.image_tag(faculty.image).html_safe
end
Expand All @@ -214,11 +241,14 @@ def avatar(name, founder: nil, faculty: nil, version: :mid, background_shape: :c
return helpers.image_tag(founder.avatar_variant(version)).html_safe
end

Scarf::InitialAvatar.new(
name,
font_family: ['Source Sans Pro', 'sans-serif'],
background_shape: background_shape
).svg.html_safe
Scarf::InitialAvatar
.new(
name,
font_family: ['Source Sans Pro', 'sans-serif'],
background_shape: background_shape
)
.svg
.html_safe
end

def domain_redirection_required?
Expand Down
3 changes: 2 additions & 1 deletion app/javascript/shared/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { I18n } from "i18n-js";
import translations from "locales.json";

export const i18n = new I18n(translations);
i18n.locale = document.documentElement.lang || "en";

i18n.enableFallback = true;
i18n.missingTranslationPrefix = "Missing translation: ";

global.i18n = i18n;
2 changes: 1 addition & 1 deletion config/environments/production.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@

# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = [I18n.default_locale]
config.i18n.fallbacks = true

# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
Expand Down
4 changes: 2 additions & 2 deletions config/initializers/i18n.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ def self.translations
end
end

I18n.available_locales = ENV['I18N_AVAILABLE_LOCALES'].split(',')
I18n.default_locale = ENV['I18N_DEFAULT_LOCALE']
I18n.available_locales = ENV.fetch('I18N_AVAILABLE_LOCALES', 'en').split(',')
I18n.default_locale = ENV.fetch('I18N_DEFAULT_LOCALE', 'en')

0 comments on commit 43c51ee

Please sign in to comment.