diff --git a/app/models/category.rb b/app/models/category.rb index 2fd277caf978b..31addb9a0ee47 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -16,6 +16,7 @@ class Category < ActiveRecord::Base include CategoryHashtag include AnonCacheInvalidator include HasDestroyedWebHook + include Localizable SLUG_REF_SEPARATOR = ":" DEFAULT_TEXT_COLORS = %w[FFFFFF 000000] diff --git a/app/models/category_localization.rb b/app/models/category_localization.rb index 615b35f3edd42..1754946515ca4 100644 --- a/app/models/category_localization.rb +++ b/app/models/category_localization.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class CategoryLocalization < ActiveRecord::Base + include LocaleMatchable + belongs_to :category validates :locale, presence: true, length: { maximum: 20 } diff --git a/app/models/concerns/locale_matchable.rb b/app/models/concerns/locale_matchable.rb new file mode 100644 index 0000000000000..662a52425c4d6 --- /dev/null +++ b/app/models/concerns/locale_matchable.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module LocaleMatchable + extend ActiveSupport::Concern + + included do + scope :matching_locale, + ->(locale) do + regionless_locale = locale.to_s.split("_").first + where("locale LIKE ?", "#{regionless_locale}%") + end + end +end diff --git a/app/models/concerns/localizable.rb b/app/models/concerns/localizable.rb new file mode 100644 index 0000000000000..a245f51d7f9bb --- /dev/null +++ b/app/models/concerns/localizable.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Localizable + extend ActiveSupport::Concern + + included { has_many :localizations, class_name: "#{model_name}Localization", dependent: :destroy } + + 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 + + localizations.find { |l| LocaleNormalizer.is_same?(l.locale, locale_str) } + end +end diff --git a/app/models/post.rb b/app/models/post.rb index 7157cae2a2224..9314325ca7b47 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -9,6 +9,7 @@ class Post < ActiveRecord::Base include Searchable include HasCustomFields include LimitedEdit + include Localizable self.ignored_columns = [ "avg_time", # TODO: Remove when 20240212034010_drop_deprecated_columns has been promoted to pre-deploy @@ -67,8 +68,6 @@ class Post < ActiveRecord::Base has_many :user_actions, foreign_key: :target_post_id - has_many :post_localizations, dependent: :destroy - belongs_to :image_upload, class_name: "Upload" has_many :post_hotlinked_media, dependent: :destroy, class_name: "PostHotlinkedMedia" @@ -1343,17 +1342,6 @@ def in_user_locale? LocaleNormalizer.is_same?(locale, I18n.locale) end - def get_localization(locale = I18n.locale) - locale_str = locale.to_s.sub("-", "_") - - # prioritise exact match - if match = post_localizations.find { |l| l.locale == locale_str } - return match - end - - post_localizations.find { |l| LocaleNormalizer.is_same?(l.locale, locale_str) } - end - private def parse_quote_into_arguments(quote) diff --git a/app/models/post_localization.rb b/app/models/post_localization.rb index 150fff545f578..0ec077b7be318 100644 --- a/app/models/post_localization.rb +++ b/app/models/post_localization.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class PostLocalization < ActiveRecord::Base + include LocaleMatchable + belongs_to :post validates :post_version, presence: true diff --git a/app/models/topic.rb b/app/models/topic.rb index b5220ef92ea80..2187e61dbc686 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -11,6 +11,7 @@ class NotAllowed < StandardError include Trashable include Searchable include LimitedEdit + include Localizable extend Forwardable EXTERNAL_ID_MAX_LENGTH = 50 @@ -31,8 +32,6 @@ class NotAllowed < StandardError attr_accessor :allowed_user_ids, :allowed_group_ids, :tags_changed, :includes_destination_category - has_many :topic_localizations, dependent: :destroy - def self.max_fancy_title_length 400 end @@ -2137,24 +2136,13 @@ def self.editable_custom_fields(guardian) end def has_localization?(locale = I18n.locale) - topic_localizations.exists?(locale: locale.to_s.sub("-", "_")) + localizations.exists?(locale: locale.to_s.sub("-", "_")) end def in_user_locale? LocaleNormalizer.is_same?(locale, I18n.locale) end - def get_localization(locale = I18n.locale) - locale_str = locale.to_s.sub("-", "_") - - # prioritise exact match - if match = topic_localizations.find { |l| l.locale == locale_str } - return match - end - - topic_localizations.find { |l| LocaleNormalizer.is_same?(l.locale, locale_str) } - end - private def invite_to_private_message(invited_by, target_user, guardian) diff --git a/app/models/topic_list.rb b/app/models/topic_list.rb index b356ee59e6331..ce06f6b7959c8 100644 --- a/app/models/topic_list.rb +++ b/app/models/topic_list.rb @@ -139,7 +139,7 @@ def load_topics { category: :parent_category }, ] - topic_preloader_associations << :topic_localizations if SiteSetting.content_localization_enabled + topic_preloader_associations << :localizations if SiteSetting.content_localization_enabled DiscoursePluginRegistry.topic_preloader_associations.each do |a| fields = a[:fields] diff --git a/app/models/topic_localization.rb b/app/models/topic_localization.rb index 3429886d67f55..65412531c480f 100644 --- a/app/models/topic_localization.rb +++ b/app/models/topic_localization.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class TopicLocalization < ActiveRecord::Base + include LocaleMatchable + belongs_to :topic validates :locale, presence: true, length: { maximum: 20 } diff --git a/app/serializers/post_serializer.rb b/app/serializers/post_serializer.rb index b3d3ae8b881c6..77c63c97fa350 100644 --- a/app/serializers/post_serializer.rb +++ b/app/serializers/post_serializer.rb @@ -656,11 +656,11 @@ def include_mentioned_users? end def has_post_localizations - object.post_localizations.any? + object.localizations.any? end def post_localizations_count - object.post_localizations.size + object.localizations.size end def include_has_post_localizations? diff --git a/lib/topic_view.rb b/lib/topic_view.rb index 787515bc1ffd9..7c8c82dc1f29a 100644 --- a/lib/topic_view.rb +++ b/lib/topic_view.rb @@ -929,7 +929,7 @@ def filter_posts_by_ids(post_ids) :deleted_by, :incoming_email, :image_upload, - :post_localizations, + :localizations, ) @posts = @posts.includes({ user: :user_status }) if SiteSetting.enable_user_status diff --git a/plugins/discourse-ai/app/jobs/regular/detect_translate_post.rb b/plugins/discourse-ai/app/jobs/regular/detect_translate_post.rb index 7b55ee228d63f..bde9f63c9dfff 100644 --- a/plugins/discourse-ai/app/jobs/regular/detect_translate_post.rb +++ b/plugins/discourse-ai/app/jobs/regular/detect_translate_post.rb @@ -41,9 +41,7 @@ def execute(args) locales.each do |locale| next if LocaleNormalizer.is_same?(locale, detected_locale) - - regionless_locale = locale.split("_").first - exists = post.post_localizations.where("locale LIKE ?", "#{regionless_locale}%").exists? + exists = post.localizations.matching_locale(locale).exists? if exists && !DiscourseAi::Translation::PostLocalizer.has_relocalize_quota?(post, locale) next diff --git a/plugins/discourse-ai/app/jobs/regular/detect_translate_topic.rb b/plugins/discourse-ai/app/jobs/regular/detect_translate_topic.rb index e5cc15436132f..2afe1c5c3c25e 100644 --- a/plugins/discourse-ai/app/jobs/regular/detect_translate_topic.rb +++ b/plugins/discourse-ai/app/jobs/regular/detect_translate_topic.rb @@ -39,8 +39,7 @@ def execute(args) locales.each do |locale| next if LocaleNormalizer.is_same?(locale, detected_locale) - regionless_locale = locale.split("_").first - next if topic.topic_localizations.where("locale LIKE ?", "#{regionless_locale}%").exists? + next if topic.localizations.matching_locale(locale).exists? begin DiscourseAi::Translation::TopicLocalizer.localize(topic, locale) diff --git a/spec/lib/topic_query_spec.rb b/spec/lib/topic_query_spec.rb index aa858e00dbbc1..04fab275eeb86 100644 --- a/spec/lib/topic_query_spec.rb +++ b/spec/lib/topic_query_spec.rb @@ -2400,7 +2400,7 @@ def suggested_for(topic) topic_query = TopicQuery.new(user) topic_list = topic_query.list_latest - expect(topic_list.topics.first.association(:topic_localizations).loaded?).to eq(true) + expect(topic_list.topics.first.association(:localizations).loaded?).to eq(true) queries = track_sql_queries { topic_list.topics.each { |topic| topic.get_localization&.fancy_title } }