2019-04-30 08:27:42 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2022-07-28 10:27:38 +08:00
|
|
|
RSpec.describe "translate accelerator" do
|
2021-06-15 23:25:06 +08:00
|
|
|
before do
|
2018-09-18 18:59:00 +08:00
|
|
|
@original_i18n_load_path = I18n.load_path.dup
|
|
|
|
I18n.load_path += Dir["#{Rails.root}/spec/fixtures/i18n/translate_accelerator.*.yml"]
|
|
|
|
I18n.reload!
|
|
|
|
end
|
|
|
|
|
2018-01-25 19:09:18 +08:00
|
|
|
after do
|
2021-06-15 23:25:06 +08:00
|
|
|
I18n.load_path = @original_i18n_load_path
|
2018-01-25 19:09:18 +08:00
|
|
|
I18n.reload!
|
|
|
|
end
|
2016-08-24 17:53:03 +08:00
|
|
|
|
2018-09-18 18:59:00 +08:00
|
|
|
def override_translation(locale, key, value)
|
|
|
|
expect(I18n.exists?(key, locale)).to eq(true)
|
|
|
|
override = TranslationOverride.upsert!(locale, key, value)
|
|
|
|
expect(override.persisted?).to eq(true)
|
|
|
|
end
|
|
|
|
|
2019-06-05 12:30:25 +08:00
|
|
|
it "supports raising if requested, and cache bypasses" do
|
|
|
|
expect { I18n.t('i_am_an_unknown_key99', raise: true) }.to raise_error(I18n::MissingTranslationData)
|
|
|
|
|
|
|
|
orig = I18n.t('i_am_an_unknown_key99')
|
|
|
|
|
|
|
|
expect(I18n.t('i_am_an_unknown_key99').object_id).to eq(orig.object_id)
|
2021-01-21 04:32:22 +08:00
|
|
|
expect(I18n.t('i_am_an_unknown_key99')).to eq("translation missing: en.i_am_an_unknown_key99")
|
2019-06-05 12:30:25 +08:00
|
|
|
end
|
|
|
|
|
2019-06-05 20:19:46 +08:00
|
|
|
it "returns the correct language" do
|
|
|
|
expect(I18n.t('foo', locale: :en)).to eq('Foo in :en')
|
|
|
|
expect(I18n.t('foo', locale: :de)).to eq('Foo in :de')
|
|
|
|
|
|
|
|
I18n.with_locale(:en) do
|
|
|
|
expect(I18n.t('foo')).to eq('Foo in :en')
|
|
|
|
end
|
|
|
|
|
|
|
|
I18n.with_locale(:de) do
|
|
|
|
expect(I18n.t('foo')).to eq('Foo in :de')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-04-30 17:56:27 +08:00
|
|
|
it "converts language keys to symbols" do
|
|
|
|
expect(I18n.t('foo', locale: :en)).to eq('Foo in :en')
|
|
|
|
expect(I18n.t('foo', locale: "en")).to eq('Foo in :en')
|
|
|
|
|
|
|
|
expect(I18n.instance_variable_get(:@loaded_locales)).to contain_exactly(:en)
|
|
|
|
end
|
|
|
|
|
2016-08-24 17:53:03 +08:00
|
|
|
it "overrides for both string and symbol keys" do
|
2018-09-18 18:59:00 +08:00
|
|
|
key = 'user.email.not_allowed'
|
2021-12-16 23:44:21 +08:00
|
|
|
text_overridden = 'foobar'
|
2016-08-24 17:53:03 +08:00
|
|
|
|
|
|
|
expect(I18n.t(key)).to be_present
|
|
|
|
|
2021-12-16 23:44:21 +08:00
|
|
|
override_translation('en', key, text_overridden)
|
2016-08-24 17:53:03 +08:00
|
|
|
|
2021-12-16 23:44:21 +08:00
|
|
|
expect(I18n.t(key)).to eq(text_overridden)
|
|
|
|
expect(I18n.t(key.to_sym)).to eq(text_overridden)
|
2016-08-24 17:53:03 +08:00
|
|
|
end
|
|
|
|
|
2018-09-18 18:59:00 +08:00
|
|
|
describe ".overrides_by_locale" do
|
|
|
|
it "should cache overrides for each locale" do
|
|
|
|
override_translation('en', 'got', 'summer')
|
|
|
|
override_translation('zh_TW', 'got', '冬季')
|
2017-07-07 11:28:00 +08:00
|
|
|
|
|
|
|
I18n.overrides_by_locale('en')
|
|
|
|
I18n.overrides_by_locale('zh_TW')
|
|
|
|
|
|
|
|
expect(I18n.instance_variable_get(:@overrides_by_site)).to eq(
|
2018-09-18 18:59:00 +08:00
|
|
|
'default' => {
|
2021-04-30 17:56:27 +08:00
|
|
|
en: { 'got' => 'summer' },
|
|
|
|
zh_TW: { 'got' => '冬季' }
|
2017-07-07 11:28:00 +08:00
|
|
|
}
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
describe "plugins" do
|
2018-01-25 19:09:18 +08:00
|
|
|
before do
|
|
|
|
DiscoursePluginRegistry.register_locale(
|
2018-09-18 18:59:00 +08:00
|
|
|
'foo',
|
|
|
|
name: 'Foo',
|
|
|
|
nativeName: 'Foo Bar',
|
2018-01-25 19:09:18 +08:00
|
|
|
plural: {
|
|
|
|
keys: [:one, :few, :other],
|
|
|
|
rule: lambda do |n|
|
|
|
|
return :one if n == 1
|
|
|
|
return :few if n < 10
|
|
|
|
:other
|
|
|
|
end
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
LocaleSiteSetting.reset!
|
|
|
|
I18n.reload!
|
|
|
|
end
|
|
|
|
|
|
|
|
after do
|
|
|
|
DiscoursePluginRegistry.reset!
|
|
|
|
LocaleSiteSetting.reset!
|
|
|
|
end
|
|
|
|
|
|
|
|
it "loads plural rules from plugins" do
|
|
|
|
I18n.locale = :foo
|
|
|
|
|
|
|
|
expect(I18n.t('i18n.plural.keys')).to eq([:one, :few, :other])
|
|
|
|
expect(I18n.t('items', count: 1)).to eq('one item')
|
|
|
|
expect(I18n.t('items', count: 3)).to eq('some items')
|
|
|
|
expect(I18n.t('items', count: 20)).to eq('20 items')
|
|
|
|
end
|
|
|
|
end
|
2018-09-18 18:59:00 +08:00
|
|
|
|
|
|
|
describe "with overrides" do
|
2019-05-16 05:43:00 +08:00
|
|
|
before { I18n.locale = :en }
|
|
|
|
|
2018-09-18 18:59:00 +08:00
|
|
|
it "returns the overridden key" do
|
|
|
|
override_translation('en', 'foo', 'Overwritten foo')
|
|
|
|
expect(I18n.t('foo')).to eq('Overwritten foo')
|
|
|
|
|
|
|
|
override_translation('en', 'foo', 'new value')
|
|
|
|
expect(I18n.t('foo')).to eq('new value')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns the overridden key after switching the locale" do
|
|
|
|
override_translation('en', 'foo', 'Overwritten foo in EN')
|
|
|
|
override_translation('de', 'foo', 'Overwritten foo in DE')
|
|
|
|
|
|
|
|
expect(I18n.t('foo')).to eq('Overwritten foo in EN')
|
|
|
|
I18n.locale = :de
|
|
|
|
expect(I18n.t('foo')).to eq('Overwritten foo in DE')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can be searched" do
|
|
|
|
override_translation('en', 'wat', 'Overwritten value')
|
|
|
|
expect(I18n.search('wat')).to include('wat' => 'Overwritten value')
|
|
|
|
expect(I18n.search('Overwritten')).to include('wat' => 'Overwritten value')
|
|
|
|
|
|
|
|
override_translation('en', 'wat', 'Overwritten with (parentheses)')
|
|
|
|
expect(I18n.search('Overwritten with (')).to include('wat' => 'Overwritten with (parentheses)')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "supports disabling" do
|
|
|
|
orig_title = I18n.t('title')
|
|
|
|
override_translation('en', 'title', 'overridden title')
|
|
|
|
|
|
|
|
I18n.overrides_disabled do
|
|
|
|
expect(I18n.t('title')).to eq(orig_title)
|
|
|
|
end
|
2019-06-05 12:30:25 +08:00
|
|
|
|
2018-09-18 18:59:00 +08:00
|
|
|
expect(I18n.t('title')).to eq('overridden title')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "supports interpolation" do
|
|
|
|
override_translation('en', 'world', 'my %{world}')
|
|
|
|
expect(I18n.t('world', world: 'foo')).to eq('my foo')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "supports interpolation named count" do
|
|
|
|
override_translation('en', 'wat', 'goodbye %{count}')
|
|
|
|
expect(I18n.t('wat', count: 123)).to eq('goodbye 123')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "ignores interpolation named count if it is not applicable" do
|
|
|
|
override_translation('en', 'wat', 'bar')
|
|
|
|
expect(I18n.t('wat', count: 1)).to eq('bar')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "supports one and other" do
|
|
|
|
override_translation('en', 'items.one', 'one fish')
|
|
|
|
override_translation('en', 'items.other', '%{count} fishies')
|
|
|
|
expect(I18n.t('items', count: 13)).to eq('13 fishies')
|
|
|
|
expect(I18n.t('items', count: 1)).to eq('one fish')
|
|
|
|
end
|
|
|
|
|
2021-04-30 19:54:45 +08:00
|
|
|
it "works with strings and symbols for non-pluralized string when count is given" do
|
|
|
|
override_translation('en', 'fish', 'trout')
|
|
|
|
expect(I18n.t(:fish, count: 1)).to eq('trout')
|
|
|
|
expect(I18n.t('fish', count: 1)).to eq('trout')
|
|
|
|
end
|
|
|
|
|
2020-08-29 06:11:45 +08:00
|
|
|
it "supports one and other with fallback locale" do
|
2021-01-21 04:32:22 +08:00
|
|
|
override_translation('en_GB', 'items.one', 'one fish')
|
|
|
|
override_translation('en_GB', 'items.other', '%{count} fishies')
|
2020-08-29 06:11:45 +08:00
|
|
|
|
2021-01-21 04:32:22 +08:00
|
|
|
I18n.with_locale(:en_GB) do
|
2020-08-29 06:11:45 +08:00
|
|
|
expect(I18n.t('items', count: 13)).to eq('13 fishies')
|
|
|
|
expect(I18n.t('items', count: 1)).to eq('one fish')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-09-18 18:59:00 +08:00
|
|
|
it "supports one and other when only a single pluralization key is overridden" do
|
|
|
|
override_translation('en', 'keys.magic.other', 'no magic keys')
|
|
|
|
expect(I18n.t('keys.magic', count: 1)).to eq('one magic key')
|
|
|
|
expect(I18n.t('keys.magic', count: 2)).to eq('no magic keys')
|
|
|
|
end
|
|
|
|
|
2021-12-16 23:44:21 +08:00
|
|
|
it "returns the overridden text when falling back" do
|
2018-09-18 18:59:00 +08:00
|
|
|
override_translation('en', 'got', 'summer')
|
|
|
|
expect(I18n.t('got')).to eq('summer')
|
|
|
|
expect(I18n.with_locale(:zh_TW) { I18n.t('got') }).to eq('summer')
|
|
|
|
|
|
|
|
override_translation('en', 'throne', '%{title} is the new queen')
|
|
|
|
expect(I18n.t('throne', title: 'snow')).to eq('snow is the new queen')
|
|
|
|
expect(I18n.with_locale(:en) { I18n.t('throne', title: 'snow') })
|
|
|
|
.to eq('snow is the new queen')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns override if it exists before falling back" do
|
|
|
|
expect(I18n.t('got', default: '')).to eq('winter')
|
|
|
|
expect(I18n.with_locale(:ru) { I18n.t('got', default: '') }).to eq('winter')
|
|
|
|
|
|
|
|
override_translation('ru', 'got', 'summer')
|
|
|
|
expect(I18n.t('got', default: '')).to eq('winter')
|
|
|
|
expect(I18n.with_locale(:ru) { I18n.t('got', default: '') }).to eq('summer')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not affect ActiveModel::Naming#human" do
|
|
|
|
Fish = Class.new(ActiveRecord::Base)
|
|
|
|
|
|
|
|
override_translation('en', 'fish', 'fake fish')
|
|
|
|
expect(Fish.model_name.human).to eq('Fish')
|
|
|
|
end
|
2022-05-04 23:35:22 +08:00
|
|
|
|
|
|
|
it "works when the override contains an interpolation key" do
|
|
|
|
expect(I18n.t("foo_with_variable")).to eq("Foo in :en with %{variable}")
|
|
|
|
I18n.with_locale(:de) { expect(I18n.t("foo_with_variable")).to eq("Foo in :de with %{variable}") }
|
|
|
|
|
|
|
|
override_translation("en", "foo_with_variable", "Override in :en with %{variable}")
|
|
|
|
expect(I18n.t("foo_with_variable")).to eq("Override in :en with %{variable}")
|
|
|
|
I18n.with_locale(:de) { expect(I18n.t("foo_with_variable")).to eq("Foo in :de with %{variable}") }
|
|
|
|
|
|
|
|
override_translation("de", "foo_with_variable", "Override in :de with %{variable}")
|
|
|
|
expect(I18n.t("foo_with_variable")).to eq("Override in :en with %{variable}")
|
|
|
|
I18n.with_locale(:de) { expect(I18n.t("foo_with_variable")).to eq("Override in :de with %{variable}") }
|
|
|
|
end
|
2018-09-18 18:59:00 +08:00
|
|
|
end
|
2021-12-16 23:44:21 +08:00
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
describe "translation precedence" do
|
2021-12-16 23:44:21 +08:00
|
|
|
def translation_should_equal(key, expected_value)
|
|
|
|
I18n.locale = :en
|
|
|
|
expect(I18n.t(key, locale: :de)).to eq(expected_value)
|
|
|
|
expect(I18n.search(key, locale: :de)[key]).to eq(expected_value)
|
|
|
|
|
|
|
|
I18n.locale = :de
|
|
|
|
expect(I18n.t(key)).to eq(expected_value)
|
|
|
|
expect(I18n.search(key)[key]).to eq(expected_value)
|
|
|
|
end
|
|
|
|
|
|
|
|
context "with existing translations in current locale and fallback locale" do
|
|
|
|
context "with overrides in both locales" do
|
|
|
|
it "should return the override from the current locale" do
|
|
|
|
override_translation("de", "foo", "Override of foo in :de")
|
|
|
|
override_translation("en", "foo", "Override of foo in :en")
|
|
|
|
translation_should_equal("foo", "Override of foo in :de")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "with override only in current locale" do
|
|
|
|
it "should return the override from the current locale" do
|
|
|
|
override_translation("de", "foo", "Override of foo in :de")
|
|
|
|
translation_should_equal("foo", "Override of foo in :de")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "with override only in fallback locale" do
|
|
|
|
it "should return the translation from the current locale" do
|
|
|
|
override_translation("en", "foo", "Override of foo in :en")
|
|
|
|
translation_should_equal("foo", "Foo in :de")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "with no overrides" do
|
|
|
|
it "should return the translation from the current locale" do
|
|
|
|
translation_should_equal("foo", "Foo in :de")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "with existing translation in fallback locale" do
|
|
|
|
context "with overrides in both locales" do
|
|
|
|
it "should return the override from the current locale" do
|
|
|
|
override_translation("de", "fish", "Override of fish in :de")
|
|
|
|
override_translation("en", "fish", "Override of fish in :en")
|
|
|
|
translation_should_equal("fish", "Override of fish in :de")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "with override only in current locale" do
|
|
|
|
it "should return the override from the current locale" do
|
|
|
|
override_translation("de", "fish", "Override of fish in :de")
|
|
|
|
translation_should_equal("fish", "Override of fish in :de")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "with override only in fallback locale" do
|
|
|
|
it "should return the translation from the current locale" do
|
|
|
|
override_translation("en", "fish", "Override of fish in :en")
|
|
|
|
translation_should_equal("fish", "Override of fish in :en")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "with no overrides" do
|
|
|
|
it "should return the translation from the fallback locale" do
|
|
|
|
translation_should_equal("fish", "original fish")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-08-24 17:53:03 +08:00
|
|
|
end
|