Hello! Consider the use-case when internationalization (including translating error messages) is done entirely on the client. This means that instead of returning the client a message string for each validation error we need to provide the information which can be used to construct these messages on the client. The essential information consists of the name of the failed predicate and an optional variable
=> value
map for messages which require interpolation.
I have a proof-of-concept implementation here (disregard Messages::NoOp
, naming is hard).
A “message” is a hash with following members:
-
:predicate
— the name of a failed predicate (e.g.,:size?
); -
:variables
— a hash of interpolation variables with their values (e.g.,{ size_left: 4, size_right: 8 }
for the:size?
predicate when the argument type isRange
); -
:options
— other information like what rule has failed or what are the types of arguments and values.
Example of generated errors:
schema = Dry::Validation.Schema do
configure do
config.messages = :no_op
def palindrome?(value)
value = value.downcase
value == value.reverse
end
end
required(:name).filled(:str?, :palindrome?, size?: 4..8)
end
schema.call(name: 3).errors
# => {:name=>[{:predicate=>:str?, :options=>{:path=>[:name], :rule=>:name, :message_type=>:failure, :locale=>:en, :arg_type=>"default", :val_type=>"default", :input=>3}, :variables=>{:input=>3}}]}
schema.call(name: 'ivi').errors
# => {:name=>
# [{:predicate=>:size?,
# :options=>{:path=>[:name], :rule=>:name, :message_type=>:failure, :locale=>:en, :arg_type=>"range", :val_type=>"string", :size_left=>4, :size_right=>8, :input=>"ivi"},
# :variables=>{:size_left=>4, :size_right=>8, :input=>"ivi"}}]}
schema.call(name: 'leya').errors
# => {:name=>[{:predicate=>:palindrome?, :options=>{:path=>[:name], :rule=>:name, :message_type=>:failure, :locale=>:en, :arg_type=>"default", :val_type=>"string", :value=>"leya"}, :variables=>{:value=>"leya"}}]}
Full messages get weird though:
schema.call(name: 'maya').errors(full: true)
# => {:name=>
# ["name {:predicate=>:palindrome?, :options=>{:path=>[:name], :rule=>:name, :message_type=>:failure, :locale=>:en, :arg_type=>\"default\", :val_type=>\"string\", :value=>\"maya\"}, :variables=>{:value=>\"maya\"}}"]}
What do you think about it?
On an unrelated note, the contribution guidelines are not clear to me. PR guidelines say that a PR must address a previously reported issue, issue guidelines say that feature requests should be reported only after discussing it here. Does it mean that to create a PR I must create a corresponding topic on the discussion forum first, then (after discussing it) convert it to a Github issue, then create a PR?