mirror of
https://github.com/discourse/discourse.git
synced 2024-11-24 15:33:43 +08:00
789e3775df
A site owner attempting to use both the email_subject site setting and translation overrides for normal post notification email subjects would find themselves frusturated at the lack of template argument parity. Make all the variables available for translation overrides by adding the subject variables to the custom interpolation keys list and applying them. Reported at https://meta.discourse.org/t/customize-subject-format-for-standard-emails/20801/47?u=riking
153 lines
4.4 KiB
Ruby
153 lines
4.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "i18n/i18n_interpolation_keys_finder"
|
|
|
|
class TranslationOverride < ActiveRecord::Base
|
|
# Allowlist i18n interpolation keys that can be included when customizing translations
|
|
ALLOWED_CUSTOM_INTERPOLATION_KEYS = {
|
|
"user_notifications.user_" => %w{
|
|
topic_title_url_encoded
|
|
site_title_url_encoded
|
|
context
|
|
|
|
site_name
|
|
optional_re
|
|
optional_pm
|
|
optional_cat
|
|
optional_tags
|
|
topic_title
|
|
}
|
|
}
|
|
include ActiveSupport::Deprecation::DeprecatedConstantAccessor
|
|
deprecate_constant 'CUSTOM_INTERPOLATION_KEYS_WHITELIST', 'TranslationOverride::ALLOWED_CUSTOM_INTERPOLATION_KEYS'
|
|
|
|
validates_uniqueness_of :translation_key, scope: :locale
|
|
validates_presence_of :locale, :translation_key, :value
|
|
|
|
validate :check_interpolation_keys
|
|
|
|
def self.upsert!(locale, key, value)
|
|
params = { locale: locale, translation_key: key }
|
|
|
|
data = { value: value }
|
|
if key.end_with?('_MF')
|
|
_, filename = JsLocaleHelper.find_message_format_locale([locale], fallback_to_english: false)
|
|
data[:compiled_js] = JsLocaleHelper.compile_message_format(filename, locale, value)
|
|
end
|
|
|
|
translation_override = find_or_initialize_by(params)
|
|
params.merge!(data) if translation_override.new_record?
|
|
i18n_changed(locale, [key]) if translation_override.update(data)
|
|
translation_override
|
|
end
|
|
|
|
def self.revert!(locale, keys)
|
|
keys = Array.wrap(keys)
|
|
TranslationOverride.where(locale: locale, translation_key: keys).delete_all
|
|
i18n_changed(locale, keys)
|
|
end
|
|
|
|
def self.reload_all_overrides!
|
|
reload_locale!
|
|
|
|
overrides = TranslationOverride.pluck(:locale, :translation_key)
|
|
overrides = overrides.group_by(&:first).map { |k, a| [k, a.map(&:last)] }
|
|
overrides.each do |locale, keys|
|
|
clear_cached_keys!(locale, keys)
|
|
end
|
|
end
|
|
|
|
def self.reload_locale!
|
|
I18n.reload!
|
|
ExtraLocalesController.clear_cache!
|
|
MessageBus.publish('/i18n-flush', refresh: true)
|
|
end
|
|
|
|
def self.clear_cached_keys!(locale, keys)
|
|
should_clear_anon_cache = false
|
|
keys.each do |key|
|
|
should_clear_anon_cache |= expire_cache(locale, key)
|
|
end
|
|
Site.clear_anon_cache! if should_clear_anon_cache
|
|
end
|
|
|
|
def self.i18n_changed(locale, keys)
|
|
reload_locale!
|
|
clear_cached_keys!(locale, keys)
|
|
end
|
|
|
|
def self.expire_cache(locale, key)
|
|
if key.starts_with?('post_action_types.')
|
|
ApplicationSerializer.expire_cache_fragment!("post_action_types_#{locale}")
|
|
elsif key.starts_with?('topic_flag_types.')
|
|
ApplicationSerializer.expire_cache_fragment!("post_action_flag_types_#{locale}")
|
|
else
|
|
return false
|
|
end
|
|
true
|
|
end
|
|
|
|
private_class_method :reload_locale!
|
|
private_class_method :clear_cached_keys!
|
|
private_class_method :i18n_changed
|
|
private_class_method :expire_cache
|
|
|
|
private
|
|
|
|
def check_interpolation_keys
|
|
transformed_key = transform_pluralized_key(translation_key)
|
|
|
|
original_text = I18n.overrides_disabled do
|
|
I18n.t(transformed_key, locale: :en)
|
|
end
|
|
|
|
if original_text
|
|
original_interpolation_keys = I18nInterpolationKeysFinder.find(original_text)
|
|
new_interpolation_keys = I18nInterpolationKeysFinder.find(value)
|
|
|
|
custom_interpolation_keys = []
|
|
|
|
ALLOWED_CUSTOM_INTERPOLATION_KEYS.select do |key, value|
|
|
if transformed_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.invalid_interpolation_keys',
|
|
keys: invalid_keys.join(', ')
|
|
))
|
|
|
|
false
|
|
end
|
|
end
|
|
end
|
|
|
|
def transform_pluralized_key(key)
|
|
match = key.match(/(.*)\.(zero|two|few|many)$/)
|
|
match ? match.to_a.second + '.other' : key
|
|
end
|
|
end
|
|
|
|
# == Schema Information
|
|
#
|
|
# Table name: translation_overrides
|
|
#
|
|
# id :integer not null, primary key
|
|
# locale :string not null
|
|
# translation_key :string not null
|
|
# value :string not null
|
|
# created_at :datetime not null
|
|
# updated_at :datetime not null
|
|
# compiled_js :text
|
|
#
|
|
# Indexes
|
|
#
|
|
# index_translation_overrides_on_locale_and_translation_key (locale,translation_key) UNIQUE
|
|
#
|