使用Mobility将翻译结果范围限制为仅当前区域设置
解决方案:基于Locale回退链过滤翻译记录
要实现只返回包含当前区域设置或其回退区域设置翻译的记录,核心思路是生成包含当前Locale及其所有父级(或配置的回退)Locale的数组,再用这个数组作为查询条件。下面分两种场景给出具体实现:
1. 手动解析Locale层级(精准匹配你的需求)
如果你只需要按Locale的层级结构回退(比如fr-FR回退到fr,zh-CN回退到zh),可以手动解析Locale字符串生成回退列表:
步骤1:在Article模型中添加辅助方法和Scope
class Article < ApplicationRecord has_many :translations, class_name: 'ArticleTranslation' # 生成当前Locale的回退链(比如fr-FR → ['fr-FR', 'fr']) def self.locale_fallbacks(locale) locale_str = locale.to_s parts = locale_str.split('-') # 从完整Locale到父级Locale依次生成 (1..parts.size).map { |i| parts.first(i).join('-') }.reverse end # 自定义Scope:过滤出有当前/回退Locale翻译的文章 scope :with_valid_translations, -> { fallback_locales = locale_fallbacks(I18n.locale) # 关联翻译表,过滤Locale并去重(避免同一文章因多个翻译重复返回) joins(:translations) .where(article_translations: { locale: fallback_locales }) .distinct } end
步骤2:使用方式
调用Article.with_valid_translations即可得到符合要求的结果:
- 当
I18n.locale = :fr时,只返回带有fr翻译的文章 - 当
I18n.locale = :'fr-FR'时,返回带有fr-FR或fr翻译的文章
2. 基于Rails I18n Fallbacks(灵活适配自定义回退规则)
如果你的项目需要更复杂的回退逻辑(比如fr-FR不仅回退到fr,还要回退到en),可以利用Rails自带的I18n Fallbacks功能:
步骤1:启用并配置Fallbacks
在config/application.rb中开启Fallbacks,并按需配置自定义规则:
config.i18n.fallbacks = true # 可选:自定义回退规则 config.i18n.fallbacks = { 'fr-FR' => ['fr', 'en'], 'es-AR' => ['es'] }
步骤2:在模型中添加Scope
class Article < ApplicationRecord has_many :translations, class_name: 'ArticleTranslation' scope :with_valid_translations, -> { # 获取I18n配置的完整回退链(包含当前Locale) fallback_locales = I18n.fallbacks[I18n.locale].map(&:to_s) joins(:translations) .where(article_translations: { locale: fallback_locales }) .distinct } end
这种方式会自动遵循你配置的回退规则,扩展性更强。
关键注意点
- 加上
.distinct是为了避免同一篇文章因为存在多个符合条件的翻译(比如同时有fr-FR和fr翻译)而被重复返回。 - 确保你的
ArticleTranslation模型中有locale字段,且存储的是字符串形式(比如"fr"、"fr-FR"),和查询条件格式一致。
内容的提问来源于stack exchange,提问作者partydrone
相关产品推荐
相关产品推荐

