adonisjs / validator

Schema based validator for AdonisJS
MIT License
116 stars 39 forks source link

Allow validations messages to be localized out of the box. #51

Closed thetutlage closed 4 years ago

thetutlage commented 6 years ago

Original message: Copied from https://github.com/adonisjs/discussion/issues/62

I wonder if validator messages will looking for translation (if available) by default. For example, if we have unique, required or any validations error it will looking for available translation first, otherwise use default message.

The translation file would be located in resources/locales/<locale>/validations.json & should contains the following

// resources/locales/<locale>/validations.json
{
  "unique": "The {field} should be unique",
  "required": "The {field} is required",
  "range": "The {field} should between {0} and {1}"
}

I've done this by creating simple helper that dump all validation keys from indicative like this:

Helpers.validationMessages = () => {
  const formats = {}
  const rules = require('indicative/builds/validations')

  for (let rule of Object.keys(rules)) {
    rule = rule.split(/(?=[A-Z])/).join('_').toLowerCase()

    formats[rule] = (field, type, args) => {
      const params = { field, ...args }
      try {
        return Antl.formatMessage(`validations.${type}`, params)
      } catch (err) {
        Logger.debug('Validation translation not found', { err })
      }
    }
  }

  return formats
}

That way I could simply use validate(data, rules, Helpers.validationMessages), so I don't have to translate each form manually.

I thought it would be great if adonis could handle this kind of functionality by default.

P.s. Hope you guys get the idea even tho my english was so poor 😁

thetutlage commented 6 years ago

It will be nice if you can answer following questions.

  1. What will be the convention to store validation messages. For example: In which file, should they be stored.
  2. How to handle cascading messages. For example: Validator allows custom messages for rule <required> or field+rule <username.required>
  3. How to handle messages, which are different at runtime. For example

New user registers

I want to show following error message, if email is missing

{
   'email.required': 'Email address is required to create an account'
}

When user change their email address

{
   'email.required': 'Enter your account email address'
}

When user logins

{
   'email.required': 'Email address is required to login to your account'
}
feryardiant commented 6 years ago
  1. I'm not sure if there's any convention about this, but I believe especially for those who come from laravel world find it's useful to have sort of built-in functionality

  2. Let's just keep it simple, the default validation message should only handle common validation rules, not for specific one. If there <field>.<rule> inside the translation file, that should be for all <field> that have <rule>. For example if we have email.required that will implies to all email field that have required rule.

    You might need to take a look this repo to see my full implementation also please take a look at the following files

  3. For specific runtime, we should be able to override the default by usage. for example : For my repo I could simply

    // SomeController.method()
    const rules = {
      field1: 'required|number',
      field2: 'otherRules'
    }
    const messages = {
      'field1.require': 'Y U No Fill the field'
      'field1.number': 'Man, this field require a number value'
    }
    const data = await this.validate(request, rules, messages)
moltar commented 6 years ago

It should also support internationalization then, if there are defaults defined.

thetutlage commented 6 years ago

Kind of makes less sense to me, that for default messages, it will work fine and as I will try to customizes things a bit, it will just fall apart.

Also majority of apps, does have a slight variation in their messages, based upon the action. So it is simply not usable for them

osman-mohamad commented 6 years ago

hi @thetutlage . validation messages i18n and default back to the english i18n messages . and for the action veriations make the route validation class overwrite the global i18n messages . simply :

check for route validation messages 
if found return them to the user   
else check i18n global messages
else return english validation messages
feryardiant commented 6 years ago

I'm not sure I could describe it clearly but in my case

That's it, i guess

thetutlage commented 6 years ago

I have added this to the list of enhancements.

JhonatanPereira commented 5 years ago

Any updates on that?

sifloz commented 5 years ago

@thetutlage Hello, and thank you for providing a way to localize the custom messages.

Is there any way to achieve this using Route validators? I already created a Validator for each model so I don't use the .validate() function. Instead I use: Route.post('my-route', 'MyController.store').validator('StoreItem')

vaso2 commented 5 years ago

@thetutlage Hi, same question. Any updates for localized error messages from Route validators?

thetutlage commented 5 years ago

After exploring a lot, the following is the best I can come up with.

Messages for Rules

They are defined within the localization file as follows:

{
   "required": "{field} is required"
}

Messages for Field + Rule

{
   "username.required": "{field} is required"
}

Custom message for a specific action or route

Here one can prefix the messages with an identifier and then use that identifier within the Route validator.

{
   "register.username.required": "{field} is required"
}

and the validator will have an additional property

class StoreUser {
   get localizationIdentifier () {
       return 'register'
   }
}
lffg commented 5 years ago

@thetutlage , but then how would I internationalize the field name?

thetutlage commented 5 years ago

I believe, you would know the field name before hand

{
  "username.required": "Username is required"
}
RauppRafael commented 4 years ago

Is this feature ready? If not, how should I localize my validation messages?

bitkidd commented 4 years ago

I do localization on frontend. Just use the error key received from server as an indicator for message, i18n allows you to keep all the messages in plain objects. I do it like this:

{
  email: {
    required: 'Email cannot be blank',
    unique: 'Email should be unique'
  }
}

This way you can differ messages for different situations and use any i18n library without the need to bloat validator files.

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.