如何在移动性中使用 locale 或 fallthrough 访问器来验证翻译?

如何解决如何在移动性中使用 locale 或 fallthrough 访问器来验证翻译?

如何在创建或更新时使用访问器来验证具有区域设置或失败访问器和移动性 gem 的模型?

使用移动宝石: v1.0.5

c = Category.new(name_en: 'Cat. 1',name_de: 'Kat. 1')
c.valid?
# => false
c.errors
# Should output the individual validation errors for every single locale accessor.

示例:

  • 姓名(en):已被占用。
  • 姓名 (de):有效。
=> #<ActiveModel::Errors:0x00007fb75c488ee0 ...
@messages={:name_en=>["has already been taken"]},@details={:name_en=>[{:error=>:taken,:value=>"Cat. 1"}]}

解决方法

最后我编写了一个名为 ValidatesAccessors 的插件。欢迎反馈。

配置移动性

# config/initializers/mobility.rb

Mobility.configure do
  # PLUGINS
  plugins do
    # ...

    # One of both must be set.
    fallthrough_accessors
    locale_accessors
    
    # Add ValidatesAccessors plugin
    validates_accessors
  end
end

添加移动插件代码

# lib/mobility/plugins/validates_accessors.rb

module Mobility
  # Mobility plugins.
  module Plugins
    # Adds accessor validation so you can easily validate accessor attributes like +name_en+.
    module ValidatesAccessors
      extend Plugin

      default true

      initialize_hook do |*names|
        if options[:validates_accessors] &&
           !options[:fallthrough_accessors] &&
           !options[:locale_accessors]
          warn 'The Validates Accessors plugin depends on Fallthrough Accessors or Locale '\
               'Accessors being enabled,but both options are falsey'
        else
          options[:validates_accessors] = {} unless options[:validates_accessors].is_a?(Hash)
          options[:validates_accessors].reverse_merge!(locales: Mobility.available_locales)

          names.each do |name|
            define_accessors_locales(name,options[:validates_accessors])
          end

          include Mobility::Validations::Concern
        end
      end

      private

      def define_accessors_locales(name,options)
        module_eval <<~RUBY,__FILE__,__LINE__ + 1
          def mobility_accessors_locales_#{name}
            #{options[:locales].map(&:to_sym)}
          end
        RUBY
      end
    end

    register_plugin(:validates_accessors,ValidatesAccessors)
  end
end

添加移动模型关注代码

# lib/mobility/validations/concern.rb

module Mobility
  module Validations
    # Mobility validations concern module.
    module Concern
      extend ActiveSupport::Concern

      private

      # This validation will perform a validation round against each mobility locales and add
      # errors for mobility attributes names.
      def validates_mobility_attributes
        # Only validates mobility attributes from the admin locale.
        return unless Mobility.locale.to_sym == I18n.locale.to_sym

        mobility_errors = mobility_errors_for_attributes(self.class.mobility_attributes)

        # Add translated attributes errors back to the object.
        mobility_errors.each do |attribute,attribute_errors|
          attribute_errors[:messages].zip(attribute_errors[:details]).each do |attribute_error|
            errors.add(attribute,attribute_error.second.delete(:error),message: attribute_error.first,**attribute_error.second)
          end
        end
      end

      # Return all translated attributes with errors for the given locales,including their error
      # messages.
      def mobility_errors_for_attributes(attribute_names)
        {}.tap do |mobility_errors|
          locales = mobility_accessors_locales(attribute_names)
          additional_locales = locales - [I18n.locale.to_sym]
          # Track errors for current locale.
          if locales.include?(I18n.locale.to_sym)
            mobility_errors.merge!(mobility_errors_for_locale(attribute_names,I18n.locale.to_sym))
          end

          # Validates the given object against each locale except the current one and track their
          # errors.
          additional_locales.each do |locale|
            Mobility.with_locale(locale) do
              if invalid?
                mobility_errors.merge!(mobility_errors_for_locale(attribute_names,locale))
              end
            end
          end
        end
      end

      # Return all translated attributes with errors for the given locale,including their error
      # messages.
      def mobility_errors_for_locale(attribute_names,locale)
        {}.tap do |mobility_errors|
          attribute_names.each do |attribute|
            next unless mobility_accessors_locales_for(attribute).include?(locale) &&
                        (messages = errors.messages.delete(attribute.to_sym)).present?

            mobility_errors["#{attribute}_#{locale.to_s.underscore}".to_sym] = {
              messages: messages,details:  errors.details.delete(attribute.to_sym)
            }
          end
        end
      end

      # Define which locales to validate against all translated attribute.
      def mobility_accessors_locales(attribute_names)
        locales = []
        attribute_names.each { |attribute| locales |= mobility_accessors_locales_for(attribute) }
        locales
      end

      # Define which locales to validate against for a single translated attribute.
      def mobility_accessors_locales_for(attribute)
        locales = if try("mobility_accessors_locales_#{attribute}").respond_to?(:call)
                    try("mobility_accessors_locales_#{attribute}").call(self)
                  else
                    try("mobility_accessors_locales_#{attribute}")
                  end
        locales || []
      end
    end
  end
end

使用插件

class Category < ApplicationRecord
  extend Mobility

  translates :name # without config.
  translates :name,validates_accessors: { locales: %i[en de fr] } # specifying locales to validate.
  translates :description,validates_accessors: { locales: %i[en de] } # using another attribute.
  translates :name,:description,validates_accessors: { locales: %i[en de fr] } # same config for both attributes.

  # Add here your translated attributes validations.
  validates :name,presence:   true,uniqueness: true,length:     { maximum: 5 }
    
  # After validations add mobility ValidatesAccessors validation.
  validate  :validates_mobility_attributes

  # ...
end

示例:

  • 姓名(en):已被占用。
  • 姓名 (de):有效。
=> #<ActiveModel::Errors:0x00007fb75c488ee0 ...
@messages={:name_en=>["has already been taken"]},@details={:name_en=>[{:error=>:taken,:value=>"Cat. 1"}]}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?