mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 09:42:07 +08:00
DEV: Catch missing translations during test runs (#26258)
This configuration makes it so that a missing translation will raise an error during test execution. Better discover there than after deploy.
This commit is contained in:
parent
9db83c37e4
commit
69205cb1e5
|
@ -69,7 +69,7 @@ class UserEmail < ActiveRecord::Base
|
|||
self.errors.add(
|
||||
:user_id,
|
||||
I18n.t(
|
||||
"active_record.errors.model.user_email.attributes.user_id.reassigning_primary_email",
|
||||
"activerecord.errors.models.user_email.attributes.user_id.reassigning_primary_email",
|
||||
),
|
||||
)
|
||||
end
|
||||
|
|
|
@ -63,6 +63,9 @@ Discourse::Application.configure do
|
|||
},
|
||||
]
|
||||
|
||||
# Catch missing translations during test runs.
|
||||
config.i18n.raise_on_missing_translations = true
|
||||
|
||||
config.after_initialize do
|
||||
ActiveRecord::LogSubscriber.backtrace_cleaner.add_silencer do |line|
|
||||
line =~ %r{lib/freedom_patches}
|
||||
|
|
|
@ -556,6 +556,7 @@ en:
|
|||
private_message_abbrev: "Msg"
|
||||
|
||||
rss_description:
|
||||
hot: "Hot topics"
|
||||
latest: "Latest topics"
|
||||
top: "Top topics"
|
||||
top_all: "All time top topics"
|
||||
|
@ -1472,6 +1473,7 @@ en:
|
|||
description: "External sources that have linked to this site the most."
|
||||
top_referred_topics:
|
||||
title: "Top Referred Topics"
|
||||
xaxis: ""
|
||||
labels:
|
||||
num_clicks: "Clicks"
|
||||
topic: "Topic"
|
||||
|
|
|
@ -10,6 +10,7 @@ class MigrateOldModeratorPosts < ActiveRecord::Migration[4.2]
|
|||
end
|
||||
|
||||
def up
|
||||
Rails.application.config.i18n.raise_on_missing_translations = false
|
||||
migrate_key("closed.enabled")
|
||||
migrate_key("closed.disabled")
|
||||
migrate_key("archived.enabled")
|
||||
|
@ -18,5 +19,6 @@ class MigrateOldModeratorPosts < ActiveRecord::Migration[4.2]
|
|||
migrate_key("pinned.disabled")
|
||||
migrate_key("pinned_globally.enabled")
|
||||
migrate_key("pinned_globally.disabled")
|
||||
Rails.application.config.i18n.raise_on_missing_translations = true
|
||||
end
|
||||
end
|
||||
|
|
|
@ -36,6 +36,11 @@ class Archetype
|
|||
@archetypes[name] = Archetype.new(name, options)
|
||||
end
|
||||
|
||||
def self.deregister(name)
|
||||
@archetypes ||= {}
|
||||
@archetypes.delete(name)
|
||||
end
|
||||
|
||||
# default archetypes
|
||||
register "regular"
|
||||
register "private_message"
|
||||
|
|
|
@ -122,7 +122,8 @@ module I18n
|
|||
dup_options = nil
|
||||
if options
|
||||
dup_options = options.dup
|
||||
should_raise = dup_options.delete(:raise)
|
||||
should_raise =
|
||||
dup_options.delete(:raise) || Rails.application.config.i18n.raise_on_missing_translations
|
||||
locale = dup_options.delete(:locale)
|
||||
end
|
||||
|
||||
|
|
|
@ -3,7 +3,26 @@
|
|||
describe DiscourseAutomation::AdminAutomationsController do
|
||||
fab!(:automation)
|
||||
|
||||
before { SiteSetting.discourse_automation_enabled = true }
|
||||
before do
|
||||
SiteSetting.discourse_automation_enabled = true
|
||||
I18n.backend.store_translations(
|
||||
:en,
|
||||
{
|
||||
discourse_automation: {
|
||||
scriptables: {
|
||||
something_about_us: {
|
||||
title: "Something about us.",
|
||||
description: "We rock!",
|
||||
},
|
||||
},
|
||||
triggerables: {
|
||||
title: "Triggerables",
|
||||
description: "Triggerables",
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
end
|
||||
|
||||
describe "#show" do
|
||||
context "when logged in as an admin" do
|
||||
|
|
|
@ -41,6 +41,19 @@ describe DiscourseAutomation::AutomationSerializer do
|
|||
DiscourseAutomation::Scriptable.add("foo") do
|
||||
field :bar, component: :text, triggerable: DiscourseAutomation::Triggers::TOPIC
|
||||
end
|
||||
I18n.backend.store_translations(
|
||||
:en,
|
||||
{
|
||||
discourse_automation: {
|
||||
scriptables: {
|
||||
foo: {
|
||||
title: "Something about us.",
|
||||
description: "We rock!",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
end
|
||||
|
||||
context "when automation is not using the specific trigger" do
|
||||
|
|
|
@ -6,6 +6,34 @@ describe "DiscourseAutomation | smoke test", type: :system, js: true do
|
|||
fab!(:badge) { Fabricate(:badge, name: "badge") }
|
||||
|
||||
before do
|
||||
I18n.backend.store_translations(
|
||||
:en,
|
||||
{
|
||||
discourse_automation: {
|
||||
scriptables: {
|
||||
test: {
|
||||
title: "Test",
|
||||
description: "Test",
|
||||
},
|
||||
something_about_us: {
|
||||
title: "Something about us.",
|
||||
description: "We rock!",
|
||||
},
|
||||
nothing_about_us: {
|
||||
title: "Nothing about us.",
|
||||
description: "We don't rock!",
|
||||
},
|
||||
},
|
||||
triggerables: {
|
||||
title: "Triggerable",
|
||||
description: "Triggerable",
|
||||
user_first_logged_in: {
|
||||
description: "User first logged in.",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
SiteSetting.discourse_automation_enabled = true
|
||||
sign_in(admin)
|
||||
end
|
||||
|
|
|
@ -23,6 +23,19 @@ describe "StalledWiki" do
|
|||
before do
|
||||
automation.upsert_field!("stalled_after", "choices", { value: "PT10H" }, target: "trigger")
|
||||
automation.upsert_field!("retriggered_after", "choices", { value: "PT1H" }, target: "trigger")
|
||||
I18n.backend.store_translations(
|
||||
:en,
|
||||
{
|
||||
discourse_automation: {
|
||||
scriptables: {
|
||||
something_about_us: {
|
||||
title: "Something about us.",
|
||||
description: "We rock!",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
end
|
||||
|
||||
it "supports manual triggering" do
|
||||
|
|
|
@ -615,7 +615,7 @@ RSpec.describe DiscourseNarrativeBot::TrackSelector do
|
|||
it "should not trigger the bot" do
|
||||
post.update!(
|
||||
raw:
|
||||
"`@discobot #{I18n.t("discourse_narrative_bot.track_selector.reset_trigger")} #{I18n.t(DiscourseNarrativeBot::NewUserNarrative.reset_trigger)}`",
|
||||
"`@discobot #{I18n.t("discourse_narrative_bot.track_selector.reset_trigger")} #{DiscourseNarrativeBot::NewUserNarrative.reset_trigger}`",
|
||||
)
|
||||
|
||||
expect { described_class.new(:reply, user, post_id: post.id).select }.to_not change {
|
||||
|
@ -750,7 +750,7 @@ RSpec.describe DiscourseNarrativeBot::TrackSelector do
|
|||
user: Fabricate(:user),
|
||||
topic: topic,
|
||||
raw:
|
||||
"@discobot #{I18n.t("discourse_narrative_bot.track_selector.reset_trigger")} #{I18n.t(DiscourseNarrativeBot::NewUserNarrative.reset_trigger)}",
|
||||
"@discobot #{I18n.t("discourse_narrative_bot.track_selector.reset_trigger")} #{DiscourseNarrativeBot::NewUserNarrative.reset_trigger}",
|
||||
)
|
||||
|
||||
user
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
RSpec.describe Jobs::CheckTranslationOverrides do
|
||||
fab!(:up_to_date_translation) { Fabricate(:translation_override, translation_key: "title") }
|
||||
fab!(:deprecated_translation) { Fabricate(:translation_override, translation_key: "foo.bar") }
|
||||
fab!(:deprecated_translation) do
|
||||
allow_missing_translations { Fabricate(:translation_override, translation_key: "foo.bar") }
|
||||
end
|
||||
fab!(:outdated_translation) do
|
||||
Fabricate(:translation_override, translation_key: "posts", original_translation: "outdated")
|
||||
end
|
||||
|
|
|
@ -34,6 +34,10 @@ RSpec.describe Jobs::BulkUserTitleUpdate do
|
|||
let(:customized_badge_name) { "Merit Badge" }
|
||||
|
||||
before do
|
||||
I18n.backend.store_translations(
|
||||
:en,
|
||||
{ badges: { protector_of_the_realm: { name: "Protector of the Realm" } } },
|
||||
)
|
||||
TranslationOverride.upsert!(I18n.locale, Badge.i18n_key(badge.name), customized_badge_name)
|
||||
BadgeGranter.grant(badge, user)
|
||||
user.update(title: customized_badge_name)
|
||||
|
|
|
@ -25,12 +25,13 @@ RSpec.describe Archetype do
|
|||
end
|
||||
end
|
||||
|
||||
describe "register an archetype" do
|
||||
describe "register an archetype" do
|
||||
it "has one more element" do
|
||||
@list = Archetype.list.dup
|
||||
Archetype.register("glados")
|
||||
expect(Archetype.list.size).to eq(@list.size + 1)
|
||||
expect(Archetype.list.find { |a| a.id == "glados" }).to be_present
|
||||
Archetype.deregister("glados")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -23,17 +23,21 @@ RSpec.describe "translate accelerator" do
|
|||
I18n::MissingTranslationData,
|
||||
)
|
||||
|
||||
allow_missing_translations do
|
||||
orig = I18n.t("i_am_an_unknown_key99")
|
||||
|
||||
expect(I18n.t("i_am_an_unknown_key99").object_id).to eq(orig.object_id)
|
||||
expect(I18n.t("i_am_an_unknown_key99")).to eq("Translation missing: en.i_am_an_unknown_key99")
|
||||
end
|
||||
end
|
||||
|
||||
it "has the same 'translation missing' message as upstream" do
|
||||
allow_missing_translations do
|
||||
expect(I18n.t("this_key_does_not_exist")).to eq(
|
||||
I18n.translate_no_cache("this_key_does_not_exist"),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
it "returns the correct language" do
|
||||
expect(I18n.t("foo", locale: :en)).to eq("Foo in :en")
|
||||
|
|
|
@ -236,8 +236,8 @@ RSpec.describe JsLocaleHelper do
|
|||
end
|
||||
|
||||
it "correctly evaluates message formats in en fallback" do
|
||||
allow_missing_translations 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)
|
||||
|
@ -262,6 +262,7 @@ RSpec.describe JsLocaleHelper do
|
|||
"There is one unread",
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
LocaleSiteSetting.values.each do |locale|
|
||||
it "generates valid date helpers for #{locale[:value]} locale" do
|
||||
|
|
|
@ -17,6 +17,8 @@ RSpec.describe Plugin::Instance do
|
|||
some_ruby
|
||||
TEXT
|
||||
|
||||
around { |example| allow_missing_translations(&example) }
|
||||
|
||||
after { DiscoursePluginRegistry.reset! }
|
||||
|
||||
# NOTE: sample_plugin_site_settings.yml is always loaded in tests in site_setting.rb
|
||||
|
|
|
@ -330,6 +330,8 @@ RSpec.describe SiteSettingExtension do
|
|||
|
||||
describe "string setting with regex" do
|
||||
it "Supports custom validation errors" do
|
||||
I18n.backend.store_translations(:en, { oops: "oops" })
|
||||
|
||||
settings.setting(:test_str, "bob", regex: "hi", regex_error: "oops")
|
||||
settings.refresh!
|
||||
|
||||
|
|
|
@ -282,7 +282,7 @@ RSpec.describe IncomingLinksReport do
|
|||
it "returns localized titles" do
|
||||
stub_empty_referred_topics_data
|
||||
expect(top_referred_topics[:title]).to be_present
|
||||
expect(top_referred_topics[:xaxis]).to be_present
|
||||
expect(top_referred_topics[:xaxis]).to be_blank
|
||||
expect(top_referred_topics[:ytitles]).to be_present
|
||||
expect(top_referred_topics[:ytitles][:num_clicks]).to be_present
|
||||
end
|
||||
|
|
|
@ -6,7 +6,7 @@ RSpec.describe TranslationOverride do
|
|||
before do
|
||||
I18n.backend.store_translations(
|
||||
I18n.locale,
|
||||
"user_notifications.user_did_something" => "%{first} %{second}",
|
||||
{ user_notifications: { user_did_something: "%{first} %{second}" } },
|
||||
)
|
||||
|
||||
I18n.backend.store_translations(
|
||||
|
@ -21,7 +21,11 @@ RSpec.describe TranslationOverride do
|
|||
describe "when interpolation keys are missing" do
|
||||
it "should not be valid" do
|
||||
translation_override =
|
||||
TranslationOverride.upsert!(I18n.locale, "some_key", "%{key} %{omg}")
|
||||
TranslationOverride.upsert!(
|
||||
I18n.locale,
|
||||
"user_notifications.user_did_something",
|
||||
"%{key} %{omg}",
|
||||
)
|
||||
|
||||
expect(translation_override.errors.full_messages).to include(
|
||||
I18n.t(
|
||||
|
@ -129,6 +133,7 @@ RSpec.describe TranslationOverride do
|
|||
|
||||
describe "invalid keys" do
|
||||
it "does not transform 'tonz'" do
|
||||
allow_missing_translations do
|
||||
translation_override =
|
||||
TranslationOverride.upsert!(I18n.locale, "something.tonz", "%{key3} %{key4} hello")
|
||||
expect(translation_override.errors.full_messages).to include(
|
||||
|
@ -143,8 +148,10 @@ RSpec.describe TranslationOverride do
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "upserts values" do
|
||||
I18n.backend.store_translations(:en, { some: { key: "initial value" } })
|
||||
TranslationOverride.upsert!("en", "some.key", "some value")
|
||||
|
||||
ovr = TranslationOverride.where(locale: "en", translation_key: "some.key").first
|
||||
|
@ -164,6 +171,7 @@ RSpec.describe TranslationOverride do
|
|||
end
|
||||
|
||||
it "stores js for a message format key" do
|
||||
I18n.backend.store_translations(:en, { some: { key_MF: "initial value" } })
|
||||
TranslationOverride.upsert!(
|
||||
"ru",
|
||||
"some.key_MF",
|
||||
|
@ -300,7 +308,9 @@ RSpec.describe TranslationOverride do
|
|||
end
|
||||
|
||||
context "when the original translation no longer exists" do
|
||||
fab!(:translation) { Fabricate(:translation_override, translation_key: "foo.bar") }
|
||||
fab!(:translation) do
|
||||
allow_missing_translations { Fabricate(:translation_override, translation_key: "foo.bar") }
|
||||
end
|
||||
|
||||
it { expect(translation.original_translation_deleted?).to eq(true) }
|
||||
end
|
||||
|
|
|
@ -2746,7 +2746,7 @@ RSpec.describe User do
|
|||
end
|
||||
|
||||
describe "#title=" do
|
||||
fab!(:badge) { Fabricate(:badge, name: "Badge", allow_title: false) }
|
||||
fab!(:badge) { Badge.find_by(name: "Welcome") }
|
||||
|
||||
it "sets granted_title_badge_id correctly" do
|
||||
BadgeGranter.grant(badge, user)
|
||||
|
|
|
@ -204,6 +204,7 @@ RSpec.configure do |config|
|
|||
config.include FastImageHelpers
|
||||
config.include WithServiceHelper
|
||||
config.include ServiceMatchers
|
||||
config.include I18nHelpers
|
||||
|
||||
config.mock_framework = :mocha
|
||||
config.order = "random"
|
||||
|
|
|
@ -108,6 +108,7 @@ RSpec.describe Admin::SiteTextsController do
|
|||
end
|
||||
|
||||
it "does not return overrides for keys that do not exist in English" do
|
||||
allow_missing_translations do
|
||||
SiteSetting.default_locale = :ru
|
||||
TranslationOverride.create!(
|
||||
locale: :ru,
|
||||
|
@ -136,6 +137,7 @@ RSpec.describe Admin::SiteTextsController do
|
|||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body["site_texts"]).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
it "returns site text from fallback locale if current locale doesn't have a translation" do
|
||||
TranslationOverride.upsert!(
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe ExtraLocalesController do
|
||||
around { |example| allow_missing_translations(&example) }
|
||||
|
||||
describe "#show" do
|
||||
it "won't work with a weird parameter" do
|
||||
get "/extra-locales/-invalid..character!!"
|
||||
|
|
|
@ -3172,7 +3172,10 @@ RSpec.describe UsersController do
|
|||
fab!(:badge) { Fabricate(:badge, name: "Demogorgon", allow_title: true) }
|
||||
let(:user_badge) { BadgeGranter.grant(badge, user1) }
|
||||
|
||||
before { TranslationOverride.upsert!("en", "badges.demogorgon.name", "Boss") }
|
||||
before do
|
||||
I18n.backend.store_translations(:en, { badges: { demogorgon: { name: "D'Artagnan" } } })
|
||||
TranslationOverride.upsert!("en", "badges.demogorgon.name", "Boss")
|
||||
end
|
||||
|
||||
after { TranslationOverride.revert!("en", ["badges.demogorgon.name"]) }
|
||||
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
require_relative "../../../script/import_scripts/base"
|
||||
|
||||
RSpec.describe ImportScripts::Base do
|
||||
before { STDOUT.stubs(:write) }
|
||||
before do
|
||||
I18n.backend.store_translations(:en, { test: "Test" })
|
||||
STDOUT.stubs(:write)
|
||||
end
|
||||
|
||||
class MockSpecImporter < ImportScripts::Base
|
||||
def initialize(data)
|
||||
|
|
|
@ -330,6 +330,10 @@ RSpec.describe BadgeGranter do
|
|||
let(:customized_badge_name) { "Merit Badge" }
|
||||
|
||||
before do
|
||||
I18n.backend.store_translations(
|
||||
:en,
|
||||
{ badges: { Badge.i18n_name(badge.name) => { name: "Badge 0" } } },
|
||||
)
|
||||
TranslationOverride.upsert!(I18n.locale, Badge.i18n_key(badge.name), customized_badge_name)
|
||||
end
|
||||
|
||||
|
@ -381,6 +385,10 @@ RSpec.describe BadgeGranter do
|
|||
|
||||
it "removes custom badge titles" do
|
||||
custom_badge_title = "this is a badge title"
|
||||
I18n.backend.store_translations(
|
||||
:en,
|
||||
{ badges: { Badge.i18n_name(badge.name) => { name: "Badge 0" } } },
|
||||
)
|
||||
TranslationOverride.create!(
|
||||
translation_key: badge.translation_key,
|
||||
value: custom_badge_title,
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
RSpec.describe ProblemCheck::TranslationOverrides do
|
||||
subject(:check) { described_class.new }
|
||||
|
||||
around { |example| allow_missing_translations(&example) }
|
||||
|
||||
describe ".call" do
|
||||
before { Fabricate(:translation_override, status: status) }
|
||||
|
||||
|
|
10
spec/support/i18n_helpers.rb
Normal file
10
spec/support/i18n_helpers.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module I18nHelpers
|
||||
def allow_missing_translations
|
||||
Rails.application.config.i18n.raise_on_missing_translations = false
|
||||
yield
|
||||
ensure
|
||||
Rails.application.config.i18n.raise_on_missing_translations = true
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user