mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 09:42:07 +08:00
a16faa27cd
When searching for site texts for admin using the english version of the text, previously we would show the english version in the results _even if_ there was another locale translated version available when a locale was selected from the dropdown. This commit adds a "Only show results in selected locale" checkbox option which will instead make it so the results shown are in the target locale, making it easier for translators to tell when there is actually translations vs. missing tranlsations.
285 lines
8.6 KiB
Ruby
285 lines
8.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class Admin::SiteTextsController < Admin::AdminController
|
|
def self.preferred_keys
|
|
%w[
|
|
system_messages.usage_tips.text_body_template
|
|
education.new-topic
|
|
education.new-reply
|
|
login_required.welcome_message
|
|
]
|
|
end
|
|
|
|
def self.restricted_keys
|
|
%w[
|
|
user_notifications.confirm_old_email.title
|
|
user_notifications.confirm_old_email.subject_template
|
|
user_notifications.confirm_old_email.text_body_template
|
|
]
|
|
end
|
|
|
|
def index
|
|
overridden = params[:overridden] == "true"
|
|
outdated = params[:outdated] == "true"
|
|
untranslated = params[:untranslated] == "true"
|
|
only_selected_locale = params[:only_selected_locale] == "true"
|
|
extras = {}
|
|
|
|
query = params[:q] || ""
|
|
|
|
locale = fetch_locale(params[:locale])
|
|
|
|
if query.blank? && !overridden && !outdated && !untranslated
|
|
extras[:recommended] = true
|
|
results = self.class.preferred_keys.map { |k| record_for(key: k, locale: locale) }
|
|
else
|
|
results =
|
|
find_translations(query, overridden, outdated, locale, untranslated, only_selected_locale)
|
|
|
|
if results.any?
|
|
extras[:regex] = I18n::Backend::DiscourseI18n.create_search_regexp(query, as_string: true)
|
|
end
|
|
|
|
results.sort! do |x, y|
|
|
if x[:value].casecmp(query) == 0
|
|
-1
|
|
elsif y[:value].casecmp(query) == 0
|
|
1
|
|
else
|
|
(x[:id].size + x[:value].size) <=> (y[:id].size + y[:value].size)
|
|
end
|
|
end
|
|
end
|
|
|
|
page = params[:page].to_i
|
|
raise Discourse::InvalidParameters.new(:page) if page < 0
|
|
|
|
per_page = 50
|
|
first = page * per_page
|
|
last = first + per_page
|
|
|
|
extras[:has_more] = true if results.size > last
|
|
|
|
if LocaleSiteSetting.fallback_locale(locale).present?
|
|
extras[:fallback_locale] = LocaleSiteSetting.fallback_locale(locale)
|
|
end
|
|
|
|
overridden = overridden_keys(locale)
|
|
render_serialized(
|
|
results[first..last - 1],
|
|
SiteTextSerializer,
|
|
root: "site_texts",
|
|
rest_serializer: true,
|
|
extras: extras,
|
|
overridden_keys: overridden,
|
|
)
|
|
end
|
|
|
|
def show
|
|
locale = fetch_locale(params[:locale])
|
|
site_text = find_site_text(locale)
|
|
render_serialized(site_text, SiteTextSerializer, root: "site_text", rest_serializer: true)
|
|
end
|
|
|
|
def update
|
|
locale = fetch_locale(params.dig(:site_text, :locale))
|
|
|
|
site_text = find_site_text(locale)
|
|
value = site_text[:value] = params.dig(:site_text, :value)
|
|
id = site_text[:id]
|
|
old_value = I18n.with_locale(locale) { I18n.t(id) }
|
|
|
|
translation_override = TranslationOverride.upsert!(locale, id, value)
|
|
|
|
if translation_override.errors.empty?
|
|
StaffActionLogger.new(current_user).log_site_text_change(id, value, old_value)
|
|
system_badge_id = Badge.find_system_badge_id_from_translation_key(id)
|
|
if system_badge_id.present? && is_badge_title?(id)
|
|
Jobs.enqueue(
|
|
:bulk_user_title_update,
|
|
new_title: value,
|
|
granted_badge_id: system_badge_id,
|
|
action: Jobs::BulkUserTitleUpdate::UPDATE_ACTION,
|
|
)
|
|
end
|
|
render_serialized(site_text, SiteTextSerializer, root: "site_text", rest_serializer: true)
|
|
else
|
|
render json:
|
|
failed_json.merge(message: translation_override.errors.full_messages.join("\n\n")),
|
|
status: 422
|
|
end
|
|
end
|
|
|
|
def revert
|
|
locale = fetch_locale(params[:locale])
|
|
|
|
site_text = find_site_text(locale)
|
|
id = site_text[:id]
|
|
old_text = I18n.with_locale(locale) { I18n.t(id) }
|
|
TranslationOverride.revert!(locale, id)
|
|
|
|
site_text = find_site_text(locale)
|
|
StaffActionLogger.new(current_user).log_site_text_change(id, site_text[:value], old_text)
|
|
system_badge_id = Badge.find_system_badge_id_from_translation_key(id)
|
|
if system_badge_id.present?
|
|
Jobs.enqueue(
|
|
:bulk_user_title_update,
|
|
granted_badge_id: system_badge_id,
|
|
action: Jobs::BulkUserTitleUpdate::RESET_ACTION,
|
|
)
|
|
end
|
|
render_serialized(site_text, SiteTextSerializer, root: "site_text", rest_serializer: true)
|
|
end
|
|
|
|
def dismiss_outdated
|
|
locale = fetch_locale(params[:locale])
|
|
override = TranslationOverride.find_by(locale: locale, translation_key: params[:id])
|
|
|
|
raise Discourse::NotFound if override.blank?
|
|
|
|
if override.make_up_to_date!
|
|
render json: success_json
|
|
else
|
|
render json: failed_json.merge(message: "Can only dismiss outdated translations"), status: 422
|
|
end
|
|
end
|
|
|
|
def get_reseed_options
|
|
render_json_dump(
|
|
categories: SeedData::Categories.with_default_locale.reseed_options,
|
|
topics: SeedData::Topics.with_default_locale.reseed_options,
|
|
)
|
|
end
|
|
|
|
def reseed
|
|
hijack do
|
|
if params[:category_ids].present?
|
|
SeedData::Categories.with_default_locale.update(site_setting_names: params[:category_ids])
|
|
end
|
|
|
|
if params[:topic_ids].present?
|
|
SeedData::Topics.with_default_locale.update(site_setting_names: params[:topic_ids])
|
|
end
|
|
|
|
render json: success_json
|
|
end
|
|
end
|
|
|
|
protected
|
|
|
|
def is_badge_title?(id = "")
|
|
badge_parts = id.split(".")
|
|
badge_parts[0] == "badges" && badge_parts[2] == "name"
|
|
end
|
|
|
|
def record_for(key:, value: nil, locale:)
|
|
en_key = TranslationOverride.transform_pluralized_key(key)
|
|
value ||= I18n.with_locale(locale) { I18n.t(key) }
|
|
|
|
interpolation_keys =
|
|
I18nInterpolationKeysFinder.find(I18n.overrides_disabled { I18n.t(en_key, locale: :en) })
|
|
custom_keys = TranslationOverride.custom_interpolation_keys(en_key)
|
|
{ id: key, value: value, locale: locale, interpolation_keys: interpolation_keys + custom_keys }
|
|
end
|
|
|
|
PLURALIZED_REGEX = /(.*)\.(zero|one|two|few|many|other)\z/
|
|
|
|
def find_site_text(locale)
|
|
if self.class.restricted_keys.include?(params[:id])
|
|
raise Discourse::InvalidAccess.new(
|
|
nil,
|
|
nil,
|
|
custom_message: "email_template_cant_be_modified",
|
|
)
|
|
end
|
|
|
|
if I18n.exists?(params[:id], locale) ||
|
|
TranslationOverride.exists?(locale: locale, translation_key: params[:id])
|
|
return record_for(key: params[:id], locale: locale)
|
|
end
|
|
|
|
if PLURALIZED_REGEX.match(params[:id])
|
|
value = fix_plural_keys($1, {}, locale).detect { |plural| plural[0] == $2.to_sym }
|
|
return record_for(key: params[:id], value: value[1], locale: value[2]) if value
|
|
end
|
|
|
|
raise Discourse::NotFound
|
|
end
|
|
|
|
def find_translations(query, overridden, outdated, locale, untranslated, only_selected_locale)
|
|
translations = Hash.new { |hash, key| hash[key] = {} }
|
|
search_results =
|
|
I18n.with_locale(locale) do
|
|
I18n.search(query, only_overridden: overridden, only_untranslated: untranslated)
|
|
end
|
|
|
|
if outdated
|
|
outdated_keys =
|
|
TranslationOverride.where(status: %i[outdated invalid_interpolation_keys]).pluck(
|
|
:translation_key,
|
|
)
|
|
search_results.select! { |k, _| outdated_keys.include?(k) }
|
|
end
|
|
|
|
search_results.each do |key, value|
|
|
if PLURALIZED_REGEX.match(key)
|
|
translations[$1][$2] = value
|
|
else
|
|
translations[key] = value
|
|
end
|
|
end
|
|
|
|
results = []
|
|
|
|
translations.each do |key, value|
|
|
next unless I18n.exists?(key, :en)
|
|
|
|
if value.is_a?(Hash)
|
|
fix_plural_keys(key, value, locale, only_selected_locale).each do |plural|
|
|
plural_key = plural[0]
|
|
plural_value = plural[1]
|
|
|
|
results << record_for(
|
|
key: "#{key}.#{plural_key}",
|
|
value: plural_value,
|
|
locale: plural.last,
|
|
)
|
|
end
|
|
else
|
|
value = I18n.with_locale(locale) { I18n.t(key) } if only_selected_locale
|
|
results << record_for(key: key, value: value, locale: locale)
|
|
end
|
|
end
|
|
|
|
results
|
|
end
|
|
|
|
def fix_plural_keys(key, value, locale, only_selected_locale = false)
|
|
value = value.with_indifferent_access
|
|
plural_keys = I18n.with_locale(locale) { I18n.t("i18n.plural.keys") }
|
|
return value if value.keys.size == plural_keys.size && plural_keys.all? { |k| value.key?(k) }
|
|
|
|
fallback_value = I18n.t(key, locale: :en, default: {})
|
|
plural_keys.map do |k|
|
|
if value[k]
|
|
value[k] = I18n.with_locale(locale) { I18n.t("#{key}.#{k}") } if only_selected_locale
|
|
[k, value[k], locale]
|
|
else
|
|
[k, fallback_value[k] || fallback_value[:other], :en]
|
|
end
|
|
end
|
|
end
|
|
|
|
def overridden_keys(locale)
|
|
TranslationOverride.where(locale: locale).pluck(:translation_key)
|
|
end
|
|
|
|
def fetch_locale(locale_from_params)
|
|
locale_from_params.tap do |locale|
|
|
if locale.blank? || !I18n.locale_available?(locale)
|
|
raise Discourse::InvalidParameters.new(:locale)
|
|
end
|
|
end
|
|
end
|
|
end
|