From 6758835387c0737c74ee595dcf3c9f5d0f605ef5 Mon Sep 17 00:00:00 2001 From: Jarek Radosz Date: Tue, 8 Feb 2022 02:31:08 +0100 Subject: [PATCH] FIX: Overridden MessageFormat fallbacks (#15855) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …were missing pluralization rules This resulted in errors like `MessageFormat.locale.en is not a function` --- lib/js_locale_helper.rb | 7 +++ spec/components/js_locale_helper_spec.rb | 57 ++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/lib/js_locale_helper.rb b/lib/js_locale_helper.rb index 4ca3cd5864a..d5a319b41e3 100644 --- a/lib/js_locale_helper.rb +++ b/lib/js_locale_helper.rb @@ -289,6 +289,13 @@ module JsLocaleHelper result = +"MessageFormat = {locale: {}};\n" result << "I18n._compiledMFs = {#{formats}};\n" result << File.read(filename) << "\n" + + if locale != "en" + # Include "en" pluralization rules for use in fallbacks + _, en_filename = find_message_format_locale(["en"], fallback_to_english: false) + result << File.read(en_filename) << "\n" + end + result << File.read("#{Rails.root}/lib/javascripts/messageformat-lookup.js") << "\n" end diff --git a/spec/components/js_locale_helper_spec.rb b/spec/components/js_locale_helper_spec.rb index 887ae8dc0d9..27c8290ef90 100644 --- a/spec/components/js_locale_helper_spec.rb +++ b/spec/components/js_locale_helper_spec.rb @@ -87,7 +87,7 @@ describe JsLocaleHelper do end it 'handles message format special keys' do - JsLocaleHelper.set_translations('en', "en" => { + JsLocaleHelper.set_translations('en', "en" => { "js" => { "hello" => "world", "test_MF" => "{HELLO} {COUNT, plural, one {1 duck} other {# ducks}}", @@ -113,7 +113,7 @@ describe JsLocaleHelper do expect(ctx.eval('I18n.messageFormat("foo_MF", { HELLO: "hi", COUNT: 4 })')).to eq("hi 4 ducks") end - it 'load pluralizations rules before precompile' do + it 'load pluralization rules before precompile' do message = JsLocaleHelper.compile_message_format(message_format_filename('ru'), 'ru', 'format') expect(message).not_to match 'Plural Function not found' end @@ -186,6 +186,43 @@ describe JsLocaleHelper do end end + it "correctly evaluates message formats in en fallback" do + JsLocaleHelper.set_translations("en", "en" => { + "js" => { + "something_MF" => "en mf", + }, + }) + + JsLocaleHelper.set_translations("de", "de" => { + "js" => { + "something_MF" => "de mf", + }, + }) + + TranslationOverride.upsert!("en", "js.something_MF", <<~MF.strip) + There { + UNREAD, plural, + =0 {are no} + one {is one unread} + other {are # unread} + } + MF + + ctx = MiniRacer::Context.new + ctx.eval("var window = this;") + ctx.load(Rails.root + "app/assets/javascripts/locales/i18n.js") + ctx.eval(JsLocaleHelper.output_locale("de")) + ctx.eval(JsLocaleHelper.output_client_overrides("de")) + ctx.eval(<<~JS) + for (let [key, value] of Object.entries(I18n._mfOverrides || {})) { + key = key.replace(/^[a-z_]*js\./, ""); + I18n._compiledMFs[key] = value; + } + JS + + expect(ctx.eval("I18n.messageFormat('something_MF', { UNREAD: 1 })")).to eq("There is one unread") + end + LocaleSiteSetting.values.each do |locale| it "generates valid date helpers for #{locale[:value]} locale" do js = JsLocaleHelper.output_locale(locale[:value]) @@ -207,12 +244,24 @@ describe JsLocaleHelper do end describe ".find_message_format_locale" do + it "finds locale's message format rules" do + locale, filename = JsLocaleHelper.find_message_format_locale([:de], fallback_to_english: false) + expect(locale).to eq("de") + expect(filename).to end_with("/de.js") + end + it "finds locale for en_GB" do - locale, filename = JsLocaleHelper.find_message_format_locale([:en_GB], fallback_to_english: false) + locale, filename = JsLocaleHelper.find_message_format_locale([:en_GB], fallback_to_english: false) expect(locale).to eq("en") expect(filename).to end_with("/en.js") - locale, filename = JsLocaleHelper.find_message_format_locale(["en_GB"], fallback_to_english: false) + locale, filename = JsLocaleHelper.find_message_format_locale(["en_GB"], fallback_to_english: false) + expect(locale).to eq("en") + expect(filename).to end_with("/en.js") + end + + it "falls back to en when locale doesn't have own message format rules" do + locale, filename = JsLocaleHelper.find_message_format_locale([:nonexistent], fallback_to_english: true) expect(locale).to eq("en") expect(filename).to end_with("/en.js") end