# frozen_string_literal: true

module ActiveSupport
  module HtmlSafeTranslation # :nodoc:
    extend self

    def translate(key, **options)
      if html_safe_translation_key?(key)
        html_safe_options = html_escape_translation_options(options)

        exception = false
        exception_handler = ->(*args) do
          exception = true
          I18n.exception_handler.call(*args)
        end
        translation = I18n.translate(key, **html_safe_options, exception_handler: exception_handler)
        if exception
          translation
        else
          html_safe_translation(translation)
        end
      else
        I18n.translate(key, **options)
      end
    end

    def html_safe_translation_key?(key)
      /(?:_|\b)html\z/.match?(key)
    end

    private
      def html_escape_translation_options(options)
        options.each do |name, value|
          unless i18n_option?(name) || (name == :count && value.is_a?(Numeric))
            options[name] = ERB::Util.html_escape(value.to_s)
          end
        end
      end

      def i18n_option?(name)
        (@i18n_option_names ||= I18n::RESERVED_KEYS.to_set).include?(name)
      end


      def html_safe_translation(translation)
        if translation.respond_to?(:map)
          translation.map { |element| element.respond_to?(:html_safe) ? element.html_safe : element }
        else
          translation.respond_to?(:html_safe) ? translation.html_safe : translation
        end
      end
  end
end
