discourse/app/services/locale_normalizer.rb
Natalie Tay 83670fb01e
FIX: Show localization for regionless locale if they exist (#33702)
Currently if a post is written in Japanese (`ja`) and has been
translated to English (`en`), a British (`en_GB`) user will see the
Japanese post.

WIth this PR we normalize user locales so the best match would show
(`en` first, then `en_GB`, or `pt` and `pt_BR`).

Note: `LocaleNormalizer` is from discourse-ai and will be removed there.
2025-07-21 15:45:14 +08:00

53 lines
1.6 KiB
Ruby

# frozen_string_literal: true
class LocaleNormalizer
# Normalizes locale string, matching the list of I18n.locales where possible
# @param locale [String,Symbol] the locale to normalize
# @return [String] the normalized locale
def self.normalize_to_i18n(locale)
return nil if locale.blank?
locale = locale.to_s.gsub("-", "_")
i18n_pairs.each { |downcased, value| return value if locale.downcase == downcased }
locale
end
# Checks if two locales are the same based on exact match and normalized match
# - is_same?("a_b", "a-b") == true
# - is_same?("a_b", "a") == true
# @param locale1 [String,Symbol] the first locale to compare
# @param locale2 [String,Symbol] the second locale to compare
def self.is_same?(locale1, locale2)
locale1 = locale1.to_s
locale2 = locale2.to_s
return true if locale1 == locale2
locale1 = locale1.gsub("-", "_").downcase
locale2 = locale2.gsub("-", "_").downcase
locale1.split("_").first == locale2.split("_").first
end
private
def self.i18n_pairs
# they should look like this for the input to match against:
# {
# "lowercased" => "actual",
# "en" => "en",
# "zh_cn" => "zh_CN",
# "zh" => "zh_CN",
# }
@locale_map ||=
I18n
.available_locales
.reduce({}) do |output, sym|
locale = sym.to_s
output[locale.downcase] = locale
if locale.include?("_")
short = locale.split("_").first
output[short] = locale if output[short].blank?
end
output
end
end
end