Some weeks ago there has been a discussion about this problem, but I did not find any solution in the new version 1.93.2 Therefore: may I repeat a proposal?
>From the description of /gluon/validators.py: Built-in validators have constructors that take the optional argument error message which allows you to change the default error message. Here is an example of a validator on a database table:: db.person.name.requires=IS_NOT_EMPTY(error_message=T('fill this')) where we have used the translation operator T to allow for internationalization. Notice that default error messages are not translated. This solution is not very beautiful, because I have to repeat the string 'fill this', but it works. *It does not work for classes like IS_INT_IN_RANGE,* because there is a lot of error messages, depending on the values: if minimum is None: if maximum is None: self.error_message = error_message or 'enter an integer' else: self.maximum = int(maximum) if error_message is None: error_message = 'enter an integer less than or equal to %(max)g' self.error_message = error_message % dict(max=self.maximum-1) elif maximum is None: self.minimum = int(minimum) if error_message is None: error_message = 'enter an integer greater than or equal to %(min)g' self.error_message = error_message % dict(min=self.minimum) else: self.minimum = int(minimum) self.maximum = int(maximum) if error_message is None: error_message = 'enter an integer between %(min)g and %(max)g' self.error_message = error_message % dict(min=self.minimum, max=self.maximum-1) Using the T-"operator" there is no way to translate these error message for example to German. And I think it looks very unprofessional to have mixes English and German messages. My proposal: I have changed the following lines (file validators.py, class IS_INT_IN_RANGE) def __init__( self, minimum=None, maximum=None, error_message=None, *T=lambda x:x, # One additional parameter with a default value* ): self.minimum = self.maximum = None if minimum is None: if maximum is None: self.error_message = error_message or *T('enter an integer') * else: self.maximum = int(maximum) if error_message is None: error_message = *T('enter an integer less than or equal to %(max)g')* self.error_message = error_message % dict(max=self.maximum-1) elif maximum is None: self.minimum = int(minimum) if error_message is None: error_message = *T('enter an integer greater than or equal to %(min)g')* self.error_message = error_message % dict(min=self.minimum) else: self.minimum = int(minimum) self.maximum = int(maximum) if error_message is None: error_message = *T('enter an integer between %(min)g and %(max)g')* self.error_message = error_message % dict(min=self.minimum, max=self.maximum-1) And I have used it in the following way: Field('number', type='integer', requires=IS_INT_IN_RANGE(2,5,*T=T*), label=T('number')), Now every error message can be translated using the usual way. Advantages: - It is not necessary to repeat error messages as in IS_NOT_EMPTY(error_message=T('fill this')) (remember: Dont repeat yourself) - It's full compatible with current programs. - Every nested error message could be translated. Disadvantage: - To use this feature there has to be an additional parameter on calling the constructor, e.g. requires=IS_INT_IN_RANGE(2,5,*T=T*) But without this parameter it works like the current version. Are there any other disadvantages in my solution? Or is there any other solution? Of course, every class in validators.py should be changed in this way. Maybe this solution would be useful for the file tools.py too? Regards, Martin