BookingSync/globalize-validations

View on GitHub
lib/globalize-validations/concern.rb

Summary

Maintainability
A
1 hr
Test Coverage
module Globalize
  module Validations
    module Concern
      extend ActiveSupport::Concern

      private

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

        # Define which locales to validate against
        locales = if globalize_validations_locales.respond_to?(:call)
                    globalize_validations_locales.call(self)
                  else
                    globalize_validations_locales
                  end
        locales ||= []

        globalized_errors = globalized_errors_for_locales(translated_attribute_names, locales)

        # Add translated attributes errors back to the object
        globalized_errors.each do |attribute, messages|
          messages.each do |message|
            errors.add(attribute, message)
          end
        end
      end

      # Return all translated attributes with errors for the given locales,
      # including their error messages
      def globalized_errors_for_locales(attribute_names, source_locales)
        locales = source_locales.map(&:to_s)
        additional_locales = locales - [I18n.locale.to_s]

        {}.tap do |globalized_errors|
          if locales.include? I18n.locale.to_s
            # Track errors for current locale
            globalized_errors_for_locale(globalized_errors, attribute_names, I18n.locale)
          end

          # Validates the given object against each locale except the current one
          # and track their errors
          additional_locales.each do |locale|
            Globalize.with_locale(locale) do
              globalized_errors_for_locale(globalized_errors, attribute_names, locale) if invalid?
            end
          end
        end
      end

      # Return all translated attributes with errors for the given locale,
      # including their error messages
      def globalized_errors_for_locale(globalized_errors, translated_attribute_names, locale)
        translated_attribute_names.each do |attribute|
          value = send(attribute)
          if value.respond_to?(:translation_metadata)
            fallback_locale = value.translation_metadata[:locale]
          end

          error = errors.delete(attribute.to_sym)
          if error.present?
            next if fallback_locale.present? &&
              globalized_errors["#{attribute}_#{fallback_locale.to_s.underscore}".to_sym].present?

            globalized_errors["#{attribute}_#{locale.to_s.underscore}".to_sym] = error
          end
        end
      end
    end
  end
end