mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-06-19 05:59:26 +08:00
When you click "Translate" in the theme component translation editor, the AI-translated strings get saved but the site keeps showing the old strings or missing-key placeholders like `[ja.js.theme_translations.<id>.foo]`. This PR switches the job to do individual `find_or_initialize_by` + `record.save!`, the same path the manual UI save uses via `ThemeTranslationManager#value=`, so the model's after_commit (which nulls value_baked and clears the theme cache) actually fires. Could batch and invalidate once at the end, but that means duplicating invalidation logic outside the model, which is the same drift that caused this bug. Doing the full upsert first then removing from cache could also cause the UI to be in a weird state while the whole thing finishes, so we're not doing that.
82 lines
2.5 KiB
Ruby
Vendored
82 lines
2.5 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
module Jobs
|
|
class LocalizeThemeTranslations < ::Jobs::Base
|
|
sidekiq_options retry: false
|
|
|
|
def execute(args)
|
|
theme_id = args[:theme_id]
|
|
raise Discourse::InvalidParameters.new(:theme_id) if theme_id.blank?
|
|
|
|
theme = Theme.find_by(id: theme_id)
|
|
return if theme.blank?
|
|
|
|
target_locales = SiteSetting.content_localization_supported_locales.to_s.split("|")
|
|
return if target_locales.empty?
|
|
|
|
source_locale = args[:source_locale].presence || "en"
|
|
non_en_source = source_locale != "en"
|
|
|
|
source_overrides = non_en_source ? load_overrides(theme, source_locale) : {}
|
|
source_yaml = non_en_source ? load_yaml(theme, source_locale) : {}
|
|
en_overrides = load_overrides(theme, "en")
|
|
en_yaml = load_yaml(theme, "en")
|
|
|
|
en_yaml.each_key do |key|
|
|
if (text = source_overrides[key].presence || source_yaml[key].presence)
|
|
effective_locale = source_locale
|
|
elsif (text = en_overrides[key].presence || en_yaml[key].presence)
|
|
effective_locale = "en"
|
|
else
|
|
next
|
|
end
|
|
|
|
(target_locales - [effective_locale]).each do |locale|
|
|
translate_and_upsert(theme, key, text, locale)
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def load_overrides(theme, locale)
|
|
ThemeTranslationOverride
|
|
.where(theme_id: theme.id, locale: locale)
|
|
.pluck(:translation_key, :value)
|
|
.to_h
|
|
end
|
|
|
|
def load_yaml(theme, locale)
|
|
field = theme.theme_fields.find_by(target_id: Theme.targets[:translations], name: locale)
|
|
return {} if field.blank?
|
|
data = field.raw_translation_data[locale.to_sym] || {}
|
|
ThemeTranslationManager
|
|
.list_from_hash(locale: locale, hash: data, theme: theme)
|
|
.each_with_object({}) { |tm, h| h[tm.key] = tm.default }
|
|
end
|
|
|
|
def translate_and_upsert(theme, key, text, locale)
|
|
value =
|
|
DiscourseAi::Translation::ShortTextTranslator.new(
|
|
text: text,
|
|
target_locale: locale,
|
|
).translate
|
|
return if value.blank?
|
|
|
|
record =
|
|
ThemeTranslationOverride.find_or_initialize_by(
|
|
theme_id: theme.id,
|
|
locale: locale,
|
|
translation_key: key,
|
|
)
|
|
record.value = value
|
|
record.save!
|
|
rescue FinalDestination::SSRFDetector::LookupFailedError
|
|
# transient lookup failures
|
|
rescue => e
|
|
DiscourseAi::Translation::VerboseLogger.log(
|
|
"Failed to translate theme #{theme.id} key #{key} to #{locale}: #{e.message}",
|
|
)
|
|
end
|
|
end
|
|
end
|