diff --git a/lib/dry/validation/constants.rb b/lib/dry/validation/constants.rb index 5344b096..5d83fce8 100644 --- a/lib/dry/validation/constants.rb +++ b/lib/dry/validation/constants.rb @@ -8,6 +8,7 @@ module Validation include Dry::Core::Constants DOT = "." + SPACE = " " # Root path is used for base errors in hash representation of error messages ROOT_PATH = [nil].freeze diff --git a/lib/dry/validation/messages/resolver.rb b/lib/dry/validation/messages/resolver.rb index f4c2107b..dae734c9 100644 --- a/lib/dry/validation/messages/resolver.rb +++ b/lib/dry/validation/messages/resolver.rb @@ -33,7 +33,7 @@ def call(message:, tokens:, path:, meta: EMPTY_HASH) when Symbol Message[->(**opts) { message(message, path: path, tokens: tokens, **opts) }, path, meta] when String - Message[->(**opts) { [message_text(message, path, **opts), meta] }, path, meta] + Message[->(**opts) { [message_text(message, path: path, **opts), meta] }, path, meta] when Hash meta = message.dup text = meta.delete(:text) { |key| @@ -51,18 +51,6 @@ def call(message:, tokens:, path:, meta: EMPTY_HASH) end alias_method :[], :call - # Resolve a message - # - # @return String - # - # @api public - def message_text(message, path, locale: nil, full: false, **opts) - keys = path.to_a.compact - msg_opts = EMPTY_HASH.merge(path: keys, locale: locale || messages.default_locale) - - full ? "#{messages.rule(keys.last, msg_opts) || keys.last} #{message}" : message - end - # Resolve a message # # @return [String] @@ -90,12 +78,29 @@ def message(rule, tokens: EMPTY_HASH, locale: nil, full: false, path:) parsed_tokens = parse_tokens(tokens) text = template.(template.data(parsed_tokens)) - [full ? "#{messages.rule(keys.last, msg_opts)} #{text}" : text, meta] + [message_text(text, path: path, locale: locale, full: full), meta] end # rubocop:enable Metrics/AbcSize private + def message_text(text, path:, locale: nil, full: false) + return text unless full + + key = key_text(path: path, locale: locale) + + [key, text].compact.join(SPACE) + end + + def key_text(path:, locale: nil) + locale ||= messages.default_locale + + keys = path.to_a.compact + msg_opts = {path: keys, locale: locale} + + messages.rule(keys.last, msg_opts) || keys.last + end + def parse_tokens(tokens) Hash[ tokens.map do |key, token| diff --git a/spec/fixtures/messages/errors.en.yml b/spec/fixtures/messages/errors.en.yml index 44388240..f06e312b 100644 --- a/spec/fixtures/messages/errors.en.yml +++ b/spec/fixtures/messages/errors.en.yml @@ -3,6 +3,7 @@ en: rules: email: "E-mail" errors: + format: "has invalid format" rules: not_weekend: "this only works on weekends" email: diff --git a/spec/fixtures/messages/errors.pl.yml b/spec/fixtures/messages/errors.pl.yml index e8209da1..5a6f99dd 100644 --- a/spec/fixtures/messages/errors.pl.yml +++ b/spec/fixtures/messages/errors.pl.yml @@ -1,6 +1,9 @@ pl: dry_validation: + rules: + email: "E-mail" errors: + format: "ma nieprawidłowy format" rules: not_weekend: "to działa tylko w weekendy" email: diff --git a/spec/integration/messages/resolver_spec.rb b/spec/integration/messages/resolver_spec.rb index cc3ab2a7..56ec179b 100644 --- a/spec/integration/messages/resolver_spec.rb +++ b/spec/integration/messages/resolver_spec.rb @@ -46,6 +46,28 @@ Message template for :not_here under "email" was not found STR end + + context "with full: true option" do + it "returns full message text for base rule" do + expect(resolver.message(:not_weekend, path: [nil], locale: locale, full: true)) + .to eql(["this only works on weekends", {}]) + end + + it "returns message text with translated key name" do + expect(resolver.message(:format, path: [:email], locale: locale, full: true)) + .to eql(["E-mail has invalid format", {}]) + end + + it "supports untranslated key names" do + expect(resolver.message(:format, path: [:non_translated_key], locale: locale, full: true)) + .to eql(["non_translated_key has invalid format", {}]) + end + + it "returns full message text for nested rule" do + expect(resolver.message(:invalid, path: %i[address street], locale: locale, full: true)) + .to eql(["street doesn't look good", {}]) + end + end end context ":pl" do @@ -70,6 +92,28 @@ expect(resolver.message(:invalid, path: %i[address street], locale: locale)) .to eql(["nie wygląda dobrze", {}]) end + + context "with full: true option" do + it "returns full message text for base rule" do + expect(resolver.message(:not_weekend, path: [nil], locale: locale, full: true)) + .to eql(["to działa tylko w weekendy", {}]) + end + + it "returns message text with translated key name" do + expect(resolver.message(:format, path: [:email], locale: locale, full: true)) + .to eql(["E-mail ma nieprawidłowy format", {}]) + end + + it "supports untranslated key names" do + expect(resolver.message(:format, path: [:non_translated_key], locale: locale, full: true)) + .to eql(["non_translated_key ma nieprawidłowy format", {}]) + end + + it "returns full message text for nested rule" do + expect(resolver.message(:invalid, path: %i[address street], locale: locale, full: true)) + .to eql(["street nie wygląda dobrze", {}]) + end + end end end