mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 04:01:18 +08:00
UX: Text customization for different languages. (#11729)
Admins can now edit translations in different languages without having to change their locale. We display a warning when there's a fallback language set.
This commit is contained in:
@ -21,14 +21,13 @@ class Admin::SiteTextsController < Admin::AdminController
|
||||
|
||||
query = params[:q] || ""
|
||||
|
||||
locale = params[:locale] || I18n.locale
|
||||
raise Discourse::InvalidParameters.new(:locale) if !I18n.locale_available?(locale)
|
||||
locale = fetch_locale(params[:locale])
|
||||
|
||||
if query.blank? && !overridden
|
||||
extras[:recommended] = true
|
||||
results = I18n.with_locale(locale) { self.class.preferred_keys.map { |k| record_for(k) } }
|
||||
results = self.class.preferred_keys.map { |k| record_for(key: k, locale: locale) }
|
||||
else
|
||||
results = I18n.with_locale(locale) { find_translations(query, overridden) }
|
||||
results = find_translations(query, overridden, locale)
|
||||
|
||||
if results.any?
|
||||
extras[:regex] = I18n::Backend::DiscourseI18n.create_search_regexp(query, as_string: true)
|
||||
@ -53,20 +52,37 @@ class Admin::SiteTextsController < Admin::AdminController
|
||||
last = first + per_page
|
||||
|
||||
extras[:has_more] = true if results.size > last
|
||||
render_serialized(results[first..last - 1], SiteTextSerializer, root: 'site_texts', rest_serializer: true, extras: extras, overridden_keys: overridden_keys)
|
||||
|
||||
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
|
||||
site_text = find_site_text
|
||||
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
|
||||
site_text = find_site_text
|
||||
value = site_text[:value] = params[:site_text][:value]
|
||||
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.t(id)
|
||||
translation_override = TranslationOverride.upsert!(I18n.locale, id, value)
|
||||
old_value = I18n.t(id, locale: locale)
|
||||
|
||||
translation_override = TranslationOverride.upsert!(locale, id, value)
|
||||
|
||||
if translation_override.errors.empty?
|
||||
StaffActionLogger.new(current_user).log_site_text_change(id, value, old_value)
|
||||
@ -88,11 +104,14 @@ class Admin::SiteTextsController < Admin::AdminController
|
||||
end
|
||||
|
||||
def revert
|
||||
site_text = find_site_text
|
||||
locale = fetch_locale(params[:locale])
|
||||
|
||||
site_text = find_site_text(locale)
|
||||
id = site_text[:id]
|
||||
old_text = I18n.t(id)
|
||||
TranslationOverride.revert!(I18n.locale, id)
|
||||
site_text = find_site_text
|
||||
old_text = I18n.t(id, locale: locale)
|
||||
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?
|
||||
@ -137,39 +156,39 @@ class Admin::SiteTextsController < Admin::AdminController
|
||||
badge_parts[0] == 'badges' && badge_parts[2] == 'name'
|
||||
end
|
||||
|
||||
def record_for(key, value = nil)
|
||||
def record_for(key:, value: nil, locale:)
|
||||
if key.ends_with?("_MF")
|
||||
override = TranslationOverride.where(translation_key: key, locale: I18n.locale).pluck(:value)
|
||||
override = TranslationOverride.where(translation_key: key, locale: locale).pluck(:value)
|
||||
value = override&.first
|
||||
end
|
||||
|
||||
value ||= I18n.t(key)
|
||||
value ||= I18n.t(key, locale: locale)
|
||||
{ id: key, value: value }
|
||||
end
|
||||
|
||||
PLURALIZED_REGEX = /(.*)\.(zero|one|two|few|many|other)$/
|
||||
|
||||
def find_site_text
|
||||
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]) || TranslationOverride.exists?(locale: I18n.locale, translation_key: params[:id])
|
||||
return record_for(params[:id])
|
||||
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, {}).fetch($2.to_sym)
|
||||
return record_for(params[:id], value) if value
|
||||
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)
|
||||
def find_translations(query, overridden, locale)
|
||||
translations = Hash.new { |hash, key| hash[key] = {} }
|
||||
|
||||
I18n.search(query, overridden: overridden).each do |key, value|
|
||||
I18n.search(query, overridden: overridden, locale: locale).each do |key, value|
|
||||
if PLURALIZED_REGEX.match(key)
|
||||
translations[$1][$2] = value
|
||||
else
|
||||
@ -183,30 +202,46 @@ class Admin::SiteTextsController < Admin::AdminController
|
||||
next unless I18n.exists?(key, :en)
|
||||
|
||||
if value&.is_a?(Hash)
|
||||
value = fix_plural_keys(key, value)
|
||||
value.each do |plural_key, plural_value|
|
||||
results << record_for("#{key}.#{plural_key}", plural_value)
|
||||
fix_plural_keys(key, value, 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
|
||||
results << record_for(key, value)
|
||||
results << record_for(key: key, value: value, locale: locale)
|
||||
end
|
||||
end
|
||||
|
||||
results
|
||||
end
|
||||
|
||||
def fix_plural_keys(key, value)
|
||||
def fix_plural_keys(key, value, locale)
|
||||
value = value.with_indifferent_access
|
||||
plural_keys = I18n.t('i18n.plural.keys')
|
||||
plural_keys = I18n.t('i18n.plural.keys', locale: locale)
|
||||
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|
|
||||
[k, value[k] || fallback_value[k] || fallback_value[:other]]
|
||||
end.to_h
|
||||
if value[k]
|
||||
[k, value[k], locale]
|
||||
else
|
||||
[k, fallback_value[k] || fallback_value[:other], :en]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def overridden_keys
|
||||
TranslationOverride.where(locale: I18n.locale).pluck(:translation_key)
|
||||
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
|
||||
|
Reference in New Issue
Block a user