diff --git a/app/models/translation_override.rb b/app/models/translation_override.rb index 3cdff253b53..4c2ac9b82ca 100644 --- a/app/models/translation_override.rb +++ b/app/models/translation_override.rb @@ -2,6 +2,15 @@ require 'js_locale_helper' require "i18n/i18n_interpolation_keys_finder" class TranslationOverride < ActiveRecord::Base + # Whitelist i18n interpolation keys that can be included when customizing translations + CUSTOM_INTERPOLATION_KEYS_WHITELIST = { + "user_notifications.user_" => %w{ + topic_title_url_encoded + site_title_url_encoded + context + } + } + validates_uniqueness_of :translation_key, scope: :locale validates_presence_of :locale, :translation_key, :value @@ -41,12 +50,23 @@ class TranslationOverride < ActiveRecord::Base if original_text original_interpolation_keys = I18nInterpolationKeysFinder.find(original_text) new_interpolation_keys = I18nInterpolationKeysFinder.find(value) - missing_keys = (original_interpolation_keys - new_interpolation_keys) - if missing_keys.present? + custom_interpolation_keys = [] + + CUSTOM_INTERPOLATION_KEYS_WHITELIST.select do |key, value| + if self.translation_key.start_with?(key) + custom_interpolation_keys = value + end + end + + invalid_keys = (original_interpolation_keys | new_interpolation_keys) - + original_interpolation_keys - + custom_interpolation_keys + + if invalid_keys.present? self.errors.add(:base, I18n.t( - 'activerecord.errors.models.translation_overrides.attributes.value.missing_interpolation_keys', - keys: missing_keys.join(', ') + 'activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys', + keys: invalid_keys.join(', ') )) return false diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 9b0cf7a8cbc..338475ee13f 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -423,7 +423,7 @@ en: translation_overrides: attributes: value: - missing_interpolation_keys: 'The following interpolation key(s) are missing: "%{keys}"' + invalid_interpolation_keys: 'The following interpolation key(s) are invalid: "%{keys}"' watched_word: attributes: word: diff --git a/spec/controllers/admin/site_texts_controller_spec.rb b/spec/controllers/admin/site_texts_controller_spec.rb index b0a5191ff7d..fe3f30def61 100644 --- a/spec/controllers/admin/site_texts_controller_spec.rb +++ b/spec/controllers/admin/site_texts_controller_spec.rb @@ -53,7 +53,7 @@ describe Admin::SiteTextsController do it 'returns the right error message' do put :update, params: { - id: 'some_key', site_text: { value: 'hello %{key}' } + id: 'some_key', site_text: { value: 'hello %{key} %{omg}' } }, format: :json expect(response.status).to eq(422) @@ -61,8 +61,8 @@ describe Admin::SiteTextsController do body = JSON.parse(response.body) expect(body['message']).to eq(I18n.t( - 'activerecord.errors.models.translation_overrides.attributes.value.missing_interpolation_keys', - keys: 'first, second' + 'activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys', + keys: 'key, omg' )) end end diff --git a/spec/mailers/user_notifications_spec.rb b/spec/mailers/user_notifications_spec.rb index 37da9a05977..9e3327aa927 100644 --- a/spec/mailers/user_notifications_spec.rb +++ b/spec/mailers/user_notifications_spec.rb @@ -547,6 +547,8 @@ describe UserNotifications do You are now officially notified. %{header_instructions} %{message} %{respond_instructions} + %{topic_title_url_encoded} + %{site_title_url_encoded} BODY body << "%{context}" if notification_type != :invited_to_topic diff --git a/spec/models/translation_override_spec.rb b/spec/models/translation_override_spec.rb index e331a73e3d7..9929d325f66 100644 --- a/spec/models/translation_override_spec.rb +++ b/spec/models/translation_override_spec.rb @@ -10,14 +10,29 @@ describe TranslationOverride do describe 'when interpolation keys are missing' do it 'should not be valid' do translation_override = TranslationOverride.upsert!( - I18n.locale, 'some_key', '%{first}' + I18n.locale, 'some_key', '%{key} %{omg}' ) expect(translation_override.errors.full_messages).to include(I18n.t( - 'activerecord.errors.models.translation_overrides.attributes.value.missing_interpolation_keys', - keys: 'second' + 'activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys', + keys: 'key, omg' )) end + + context 'when custom interpolation keys are included' do + it 'should be valid' do + translation_override = TranslationOverride.upsert!( + I18n.locale, + 'some_key', + "#{described_class::CUSTOM_INTERPOLATION_KEYS_WHITELIST['user_notifications.user_'].join(", ")} %{something}" + ) + + expect(translation_override.errors.full_messages).to include(I18n.t( + 'activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys', + keys: 'something' + )) + end + end end end end diff --git a/spec/requests/admin/email_templates_controller_spec.rb b/spec/requests/admin/email_templates_controller_spec.rb index 6ddd34380ba..071ff0fd48c 100644 --- a/spec/requests/admin/email_templates_controller_spec.rb +++ b/spec/requests/admin/email_templates_controller_spec.rb @@ -113,27 +113,52 @@ RSpec.describe Admin::EmailTemplatesController do end context "when subject is invalid" do - let(:email_subject) { 'Subject with missing interpolation key' } - let(:email_body) { 'The body contains [%{site_name}](%{base_url}) and %{email_token}.' } - let(:expected_errors) { ['Subject: The following interpolation key(s) are missing: "email_prefix"'] } + let(:email_subject) { '%{email_wrongfix} Foo' } + let(:email_body) { 'Body with missing interpolation keys' } + + let(:expected_errors) do + [ + "Subject: #{I18n.t( + 'activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys', + keys: 'email_wrongfix' + )}" + ] + end include_examples "invalid email template" end context "when body is invalid" do - let(:email_subject) { '%{email_prefix} Foo' } - let(:email_body) { 'Body with some missing interpolation keys: %{email_token}' } - let(:expected_errors) { ['Body: The following interpolation key(s) are missing: "site_name, base_url"'] } + let(:email_subject) { 'Subject with missing interpolation key' } + let(:email_body) { 'Body with %{invalid} interpolation key' } + + let(:expected_errors) do + [ + "Body: #{I18n.t( + 'activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys', + keys: 'invalid' + )}" + ] + end include_examples "invalid email template" end context "when subject and body are invalid invalid" do - let(:email_subject) { 'Subject with missing interpolation key' } - let(:email_body) { 'Body with some missing interpolation keys: %{email_token}' } + let(:email_subject) { 'Subject with %{invalid} interpolation key' } + let(:email_body) { 'Body with some invalid interpolation keys: %{invalid}' } + let(:expected_errors) do - ['Subject: The following interpolation key(s) are missing: "email_prefix"', - 'Body: The following interpolation key(s) are missing: "site_name, base_url"'] + [ + "Subject: #{I18n.t( + 'activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys', + keys: 'invalid' + )}", + "Body: #{I18n.t( + 'activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys', + keys: 'invalid' + )}", + ] end include_examples "invalid email template"