CanCanCan在哪里定义flash "%{subject}",如何修改才能与Rails本地化约定一致?

Where does CanCanCan define flash "%{subject}", and how to modify to be consistent with Rails localization conventions?

如果资源未被授权,CanCanCan 会显示本地化的快速消息。

https://github.com/CanCanCommunity/cancancan/wiki/Translations-(i18n)

# en.yml
en:
  unauthorized:
    manage:
      all: "You do not have access to %{action} %{subject}!"

我已经仔细研究了 GitHub 存储库,但我无法弄清楚 subject 变量是如何定义的。

根据输出,我猜 subject 被定义为 object.class.name.underscore.

我想将其更改为使用 object.model_name.human

这将使它更符合 Rails 约定,并且更容易本地化。

en:
  activerecord:
    models:
      mymodel: MyLocalizedSubjectName

有人可以指点我定义 subject 的代码,或者建议我如何修补 CanCanCan 以使用本地化模型名称吗?

您可以通过在 yml 文件中指定来覆盖您的消息。在你的情况下:

en:
  unauthorized:
    edit:
      widget: "You do not have access to edit item!"

如果您想在所有情况下更改小部件的名称,您可以尝试:

en:
  unauthorized:
    manage:
      widget: "You do not have access to %{action} item!"

您的最后一个选择是简单地覆盖您的小部件 class to_s 方法:

class Widget
  def self.to_s
    'Item'
  end
end

在我看来,消息来自 the unauthorized_message method in ability.rb。特别是这些行:

  variables[:subject] = (subject.class == Class ? subject : subject.class).to_s.underscore.humanize.downcase
  message = I18n.translate(keys.shift, variables.merge(scope: :unauthorized, default: keys + ['']))

因此您可以重新定义该方法来执行您想要的操作(尽管它已经在使用 humanize)。

编辑: 在使用 human 和命名空间模型时包括关于 i18n 键的注释。给定这样的语言环境文件:

en:
  activerecord:
    models:
      user: xxxx
      base: aaaa
      activerecord/base: bbbb
      active_record/base: cccc

我得到这些结果:

2.4.1 :001 > User.model_name.human
 => "xxxx" 
2.4.1 :002 > ActiveRecord::Base.model_name.human
 => "cccc" 
2.4.1 :003 > 

你也可以说ActiveRecord::Base.model_name.i18n_key来避免一些trial-and-error。

localize 在文件夹路径 config/locale 中,如果您只是想更改默认消息,您应该在这里找到您要查找的内容。 否则,如果你想改变语言或有多种语言,你可以通过设置在你身上设置config/application.rb,例如:

I18n.available_locales = [:en, :it]
config.i18n.default_locale = :it

第一行使语言可用,默认语言是 en.yml,但根据您安装的 gem,您可以拥有更多语言。例如,我设计了四个文件:en.yml、it.yml、devise.en.yml 和 devise.it.yml。 要提供一种语言,请确保每个文件都有副本。 如果您想通过控制器在您的应用程序中从一个切换到另一个,您可以通过:

I18n.locale = :it
I18n.locale = :en

或者如果您想通过控制器设置默认值,您可以:

I18n.locale = I18n.default_locale

希望能帮到你,再见