Fix crash with no translation for default locale

When we were visiting a page showing the content of a record which uses
globalize and our locale was the default one and there was no
translation for the default locale, the application was crashing in some
places because there are no fallbacks for the default locale.

For example, when visiting a legislation process, the line with
`CGI.escape(title)` was crashing because `title` was `nil` for the
default locale.

We've decided to solve this issue by using any available translations as
globalize fallbacks instead of showing a 404 error or a translation
missing error because these solutions would (we thinkg) either require
modifying many places in the application or making the translatable
logic even more complex.

Initially we tried to add this solution to an initializer, but it must
be called after initializing the application so I18n.fallbacks[locale]
gets the value defined in config.i18n.fallbacks.

Also note the line:

fallbacks[locale] = I18n.fallbacks[locale] + I18n.available_locales

Doesn't mention `I18n.default_locale` because the method
`I18n.fallbacks[locale]` automatically adds the default locale.
This commit is contained in:
Javi Martín
2018-10-17 01:07:23 +02:00
parent 5e8746f026
commit 2e6644d513
5 changed files with 74 additions and 0 deletions

View File

@@ -48,6 +48,8 @@ module Consul
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')] config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', 'custom', '**', '*.{rb,yml}')] config.i18n.load_path += Dir[Rails.root.join('config', 'locales', 'custom', '**', '*.{rb,yml}')]
config.after_initialize { Globalize.set_fallbacks_to_all_available_locales }
config.assets.paths << Rails.root.join("app", "assets", "fonts") config.assets.paths << Rails.root.join("app", "assets", "fonts")
# Do not swallow errors in after_commit/after_rollback callbacks. # Do not swallow errors in after_commit/after_rollback callbacks.

View File

@@ -11,3 +11,9 @@ module Globalize
end end
end end
end end
def Globalize.set_fallbacks_to_all_available_locales
Globalize.fallbacks = I18n.available_locales.each_with_object({}) do |locale, fallbacks|
fallbacks[locale] = (I18n.fallbacks[locale] + I18n.available_locales).uniq
end
end

View File

@@ -141,6 +141,14 @@ feature 'Legislation' do
expect(page).to_not have_content("Additional information") expect(page).to_not have_content("Additional information")
end end
scenario "Shows another translation when the default locale isn't available" do
process = create(:legislation_process, title_fr: "Français")
process.translations.where(locale: :en).first.destroy
visit legislation_process_path(process)
expect(page).to have_content("Français")
end
end end
context 'debate phase' do context 'debate phase' do

View File

@@ -3,6 +3,8 @@ require 'rails_helper'
describe AdminNotification do describe AdminNotification do
let(:admin_notification) { build(:admin_notification) } let(:admin_notification) { build(:admin_notification) }
it_behaves_like "globalizable", :admin_notification
it "is valid" do it "is valid" do
expect(admin_notification).to be_valid expect(admin_notification).to be_valid
end end

View File

@@ -0,0 +1,56 @@
require "spec_helper"
shared_examples_for "globalizable" do |factory_name|
let(:record) { create(factory_name) }
let(:field) { record.translated_attribute_names.first }
describe "Fallbacks" do
before do
allow(I18n).to receive(:available_locales).and_return(%i[ar de en es fr])
record.update_attribute(field, "In English")
{ es: "En español", de: "Deutsch" }.each do |locale, text|
Globalize.with_locale(locale) do
record.translated_attribute_names.each do |attribute|
record.update_attribute(attribute, record.send(attribute))
end
record.update_attribute(field, text)
end
end
end
after do
allow(I18n).to receive(:available_locales).and_call_original
allow(I18n.fallbacks).to receive(:[]).and_call_original
Globalize.set_fallbacks_to_all_available_locales
end
context "With a defined fallback" do
before do
allow(I18n.fallbacks).to receive(:[]).and_return([:fr, :es])
Globalize.set_fallbacks_to_all_available_locales
end
it "Falls back to the defined fallback" do
Globalize.with_locale(:fr) do
expect(record.send(field)).to eq "En español"
end
end
end
context "Without a defined fallback" do
before do
allow(I18n.fallbacks).to receive(:[]).and_return([:fr])
Globalize.set_fallbacks_to_all_available_locales
end
it "Falls back to the first available locale" do
Globalize.with_locale(:fr) do
expect(record.send(field)).to eq "Deutsch"
end
end
end
end
end