zammad/config/initializers/activemodel_error.rb
2026-01-02 15:41:09 +02:00

89 lines
2.8 KiB
Ruby

# Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/
# This file collects a few Rails extensions to make it possible to translate both
# errors built into Rails or other gems, and also our custom errors in the Zammad codebase.
#
# It works generally like this:
# - The zammad:translation_catalog generator has an extractor that will find error message strings
# defined by Rails and other gems and put them into the catalog of translatable strings.
# - The I18n gem is extended to perform the actual translation lookups via the Zammad Translations API.
#
# Ensure the error message hash is loaded, as the code below relies on it.
I18n.eager_load!
module ActiveModel
class Error
# Make it possible to retrieve errors that are translated with a Zammad locale.
# no_field_name indicates that the default behaviour of Rails which includes the field name
# in the error message should be modified to say "This field ..." rather than "#{fieldname} ...".
def localized_full_message(locale:, no_field_name: false)
override_errors_format(locale, no_field_name) do
::I18n.with_zammad_locale(locale) do
full_message
end
end
end
private
def override_errors_format(locale, no_field_name)
errors_hash = ::I18n.backend.translations[:en][:errors]
orig_format = errors_hash[:format]
errors_hash[:format] = ::Translation.translate(locale, 'This field %s', '%{message}') if no_field_name
yield
ensure
errors_hash[:format] = orig_format
end
end
class Errors
if !method_defined?(:orig_add)
alias orig_add add
# This will add custom string errors to the I18n translation store.
def add(attribute, type = :invalid, **)
return orig_add(attribute, type, **) if !type.is_a?(String)
# I18n uses namespacing to access the messages, so generate a safe symbol without the namespace separator '.'.
type_sym = type.gsub(%r{\W}, '').to_sym
::I18n.backend.translations[:en][:errors][:messages][type_sym] = type
orig_add(attribute, type_sym, **)
end
end
end
end
module I18n
def self.with_zammad_locale(locale)
backend.zammad_locale = locale
yield
ensure
backend.zammad_locale = nil
end
end
class I18n::Backend::Simple
attr_accessor :zammad_locale
if !method_defined?(:orig_lookup)
alias orig_lookup lookup
# Allow I18n to load the default rails error messages from the YAML files,
# but translate them to the target locale before the error messages get generated
# including placeholder subsitition.
def lookup(...)
result = orig_lookup(...)
if result.is_a?(String) && zammad_locale
return Translation.translate(zammad_locale, result)
end
result
end
end
end