discourse/app/models/concerns/localizable.rb
Natalie Tay 523b64b722
FIX: Topic has localization's inconsistent locale matching (#38365)
`Topic#has_localization?` used `localizations.exists?` for exact
matching, while `get_localization` uses `LocaleNormalizer.is_same?` for
fuzzy matching. This meant `has_localization?("ja")` returns `false`
when only `"ja_JP"` exists, even though `get_localization("ja")` finds
it.

This commit moves `has_localization?` into the `Localizable` concern,
removing overrides from both Topic and Post making things more
consistent.
2026-03-09 19:18:37 +08:00

41 lines
1.4 KiB
Ruby

# frozen_string_literal: true
module Localizable
extend ActiveSupport::Concern
included { has_many :localizations, class_name: "#{model_name}Localization", dependent: :destroy }
# Returns the localization for (in order of priority):
# - the given locale,
# - or the best match if an exact match is not found
# - or the site default locale if `content_localization_use_default_locale_when_unsupported` enabled
#
# The query used to find the localization is optimized for performance, and assumes
# that localizations are indexed by locale, and have been preloaded.
# @return [Localization, nil] the localization object for the given locale, or nil if no match is found.
def get_localization(locale = I18n.locale)
locale_str = locale.to_s.sub("-", "_")
# prioritise exact match
if match = localizations.find { |l| l.locale == locale_str }
return match
end
if match = localizations.find { |l| LocaleNormalizer.is_same?(l.locale, locale_str) }
return match
end
if SiteSetting.content_localization_use_default_locale_when_unsupported
default_locale = SiteSetting.default_locale.to_s.sub("-", "_")
localizations.find { |l| LocaleNormalizer.is_same?(l.locale, default_locale) }
end
end
def has_localization?(locale = I18n.locale)
get_localization(locale).present?
end
def in_user_locale?
LocaleNormalizer.is_same?(locale, I18n.locale)
end
end