wearebraid / vue-formulate-i18n

Internationalization (i18n) support for vue-formulate
MIT License
8 stars 39 forks source link

Question on usecases for the 'min' rule #25

Closed pimhooghiemstra closed 4 years ago

pimhooghiemstra commented 4 years ago

Hi, I have just created a pull request for a slight improvement of the dutch (nl.js) translation. I only changed the 'min' rule as it gave wrong results.

That makes it better already but I am still struggling with a specific use case of the 'min' rule:

Suppose we have an input of type=text and an input of type=number. Both inputs use the min:5 rule for validation and the user leaves the field blank and tabs to the next field. In the dutch language the validation message should be different for these two cases.

For the text field something like this: 'name should be at least 5 characters long'

For the number field something like this: 'age should be greater than 5'

In the current translation, the latter is used (translation reads '$name moet groter zijn dan $arg'), but I am unsure how to change it. I think it is somewhere in these lines (lines 5-8), but I am not sure how to change it accordingly.

min: function ({ name, value, args }) {
    if (Array.isArray(value)) {
      return `Je moet tenminste ${args[0]} selecteren als ${name}.`
    }
    const force = Array.isArray(args) && args[1] ? args[1] : false
    if ((!isNaN(value) && force !== 'length') || force === 'value') {
      return `${s(name)} moet groter zijn dan ${args[0]}.`
    }
    return `${s(name)} moet tenminste ${args[0]} karakters bevatten.`
  },
justin-schroeder commented 4 years ago

Part of this is how the rule is written. min and max (if it is wrong in one it's probably wrong in both) are both capable of string length or numeric value. The rule itself, and the message are aware of this. However, they can also be forced into evaluating one type vs the other, and this would be the recommended way to use the rule. For example, if you want to limit the length of the input min:5,length or in the numeric case, min:5,value. The psuedo logic for the above code is:

min: function ({ name, value, args }) {
  // Case 1. The value is an array, in this case we can only evaluate based on a the length of the array
      // return `Je moet tenminste ${args[0]} selecteren als ${name}.`
  // Case 2. The value is either a number, or the user has declared we should evaluate this as a number
      // return `${s(name)} moet groter zijn dan ${args[0]}.`
  // Case 3. The value must be a string, or the user wants us to evaluate it as a string
      // return `${s(name)} moet tenminste ${args[0]} karakters bevatten.`
}

Empty values are hard to coerce correctly because isNaN('') === false (so it thinks a blank field is a number). So often it's best to combine this with a required rule with a the bail modifier ^required|min:5,value. It might be in your case you just need to adjust the way you're writing the validation rule, but you're the native speaker so feel free to adjust as necessary. Hopefully this sheds some light on what is happening though.

pimhooghiemstra commented 4 years ago

Thanks @justin-schroeder for the very quick reply once more. It took me some time to get my head around it (was reading your comment on my phone). This morning I took some more time to read and trying it.

I didn't know about the way you can force the validation to use either length or value as second value to the min rule. Also, the bail modifier was new to me. I changed my rule to ^required|min:3,length|max:10,length and now it works for all use cases I can think of.

Thanks also for the pseudo logic, that makes reasoning about the logic much easier for me.

All in all, I just checked the docs and it's all there so I think I just didn't read it carefully enough.

Keep up the good work, I read your post featured in the Vue.js developers newsletter #171, hopefully it draws even more attention to this wonderful project!