diff --git a/django/contrib/localflavor/ar/forms.py b/django/contrib/localflavor/ar/forms.py index 6d86e4e676..6374a48c92 100644 --- a/django/contrib/localflavor/ar/forms.py +++ b/django/contrib/localflavor/ar/forms.py @@ -24,18 +24,20 @@ class ARPostalCodeField(RegexField): See http://www.correoargentino.com.ar/consulta_cpa/home.php """ + default_error_messages = { + 'invalid': ugettext("Enter a postal code in the format NNNN or ANNNNAAA."), + } + def __init__(self, *args, **kwargs): super(ARPostalCodeField, self).__init__(r'^\d{4}$|^[A-HJ-NP-Za-hj-np-z]\d{4}\D{3}$', - min_length=4, max_length=8, - error_message=ugettext("Enter a postal code in the format NNNN or ANNNNAAA."), - *args, **kwargs) + min_length=4, max_length=8, *args, **kwargs) def clean(self, value): value = super(ARPostalCodeField, self).clean(value) if value in EMPTY_VALUES: return u'' if len(value) not in (4, 8): - raise ValidationError(ugettext("Enter a postal code in the format NNNN or ANNNNAAA.")) + raise ValidationError(self.error_messages['invalid']) if len(value) == 8: return u'%s%s%s' % (value[0].upper(), value[1:5], value[5:].upper()) return value @@ -44,6 +46,11 @@ class ARDNIField(CharField): """ A field that validates `Documento Nacional de Identidad´ (DNI) numbers. """ + default_error_messages = { + 'invalid': ugettext("This field requires only numbers."), + 'max_digits': ugettext("This field requires 7 or 8 digits."), + } + def __init__(self, *args, **kwargs): super(ARDNIField, self).__init__(max_length=10, min_length=7, *args, **kwargs) @@ -58,10 +65,9 @@ class ARDNIField(CharField): if not value.isdigit(): value = value.replace('.', '') if not value.isdigit(): - raise ValidationError(ugettext("This field requires only numbers.")) + raise ValidationError(self.error_messages['invalid']) if len(value) not in (7, 8): - raise ValidationError( - ugettext("This field requires 7 or 8 digits.")) + raise ValidationError(self.error_messages['max_digits']) return value @@ -70,9 +76,13 @@ class ARCUITField(RegexField): This field validates a CUIT (Código Único de Identificación Tributaria). A CUIT is of the form XX-XXXXXXXX-V. The last digit is a check digit. """ + default_error_messages = { + 'invalid': ugettext('Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'), + 'checksum': ugettext("Invalid CUIT."), + } + def __init__(self, *args, **kwargs): super(ARCUITField, self).__init__(r'^\d{2}-?\d{8}-?\d$', - error_message=ugettext('Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'), *args, **kwargs) def clean(self, value): @@ -85,7 +95,7 @@ class ARCUITField(RegexField): return u'' value, cd = self._canon(value) if self._calc_cd(value) != cd: - raise ValidationError(ugettext("Invalid CUIT.")) + raise ValidationError(self.error_messages['checksum']) return self._format(value, cd) def _canon(self, cuit): diff --git a/django/contrib/localflavor/au/forms.py b/django/contrib/localflavor/au/forms.py index 33e883511b..ada27b69b9 100644 --- a/django/contrib/localflavor/au/forms.py +++ b/django/contrib/localflavor/au/forms.py @@ -12,14 +12,20 @@ PHONE_DIGITS_RE = re.compile(r'^(\d{10})$') class AUPostCodeField(RegexField): """Australian post code field.""" + default_error_messages = { + 'invalid': ugettext('Enter a 4 digit post code.'), + } + def __init__(self, *args, **kwargs): super(AUPostCodeField, self).__init__(r'^\d{4}$', - max_length=None, min_length=None, - error_message=ugettext('Enter a 4 digit post code.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) class AUPhoneNumberField(Field): """Australian phone number field.""" + default_error_messages = { + 'invalid': u'Phone numbers must contain 10 digits.', + } + def clean(self, value): """ Validate a phone number. Strips parentheses, whitespace and hyphens. @@ -31,7 +37,7 @@ class AUPhoneNumberField(Field): phone_match = PHONE_DIGITS_RE.search(value) if phone_match: return u'%s' % phone_match.group(1) - raise ValidationError(u'Phone numbers must contain 10 digits.') + raise ValidationError(self.error_messages['invalid']) class AUStateSelect(Select): """ diff --git a/django/contrib/localflavor/br/forms.py b/django/contrib/localflavor/br/forms.py index 58bf795292..aa7e3b23fd 100644 --- a/django/contrib/localflavor/br/forms.py +++ b/django/contrib/localflavor/br/forms.py @@ -17,13 +17,19 @@ except NameError: phone_digits_re = re.compile(r'^(\d{2})[-\.]?(\d{4})[-\.]?(\d{4})$') class BRZipCodeField(RegexField): + default_error_messages = { + 'invalid': _('Enter a zip code in the format XXXXX-XXX.'), + } + def __init__(self, *args, **kwargs): super(BRZipCodeField, self).__init__(r'^\d{5}-\d{3}$', - max_length=None, min_length=None, - error_message=_('Enter a zip code in the format XXXXX-XXX.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) class BRPhoneNumberField(Field): + default_error_messages = { + 'invalid': _('Phone numbers must be in XX-XXXX-XXXX format.'), + } + def clean(self, value): super(BRPhoneNumberField, self).clean(value) if value in EMPTY_VALUES: @@ -32,7 +38,7 @@ class BRPhoneNumberField(Field): m = phone_digits_re.search(value) if m: return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3)) - raise ValidationError(_('Phone numbers must be in XX-XXXX-XXXX format.')) + raise ValidationError(self.error_messages['invalid']) class BRStateSelect(Select): """ @@ -48,6 +54,9 @@ class BRStateChoiceField(Field): A choice field that uses a list of Brazilian states as its choices. """ widget = Select + default_error_messages = { + 'invalid': _(u'Select a valid brazilian state. That state is not one of the available states.'), + } def __init__(self, required=True, widget=None, label=None, initial=None, help_text=None): @@ -65,9 +74,7 @@ class BRStateChoiceField(Field): return value valid_values = set([smart_unicode(k) for k, v in self.widget.choices]) if value not in valid_values: - raise ValidationError(_(u'Select a valid brazilian state.' - u' That state is not one' - u' of the available states.')) + raise ValidationError(self.error_messages['invalid']) return value def DV_maker(v): @@ -83,6 +90,12 @@ class BRCPFField(CharField): More information: http://en.wikipedia.org/wiki/Cadastro_de_Pessoas_F%C3%ADsicas """ + default_error_messages = { + 'invalid': _("Invalid CPF number."), + 'max_digits': _("This field requires at most 11 digits or 14 characters."), + 'digits_only': _("This field requires only numbers."), + } + def __init__(self, *args, **kwargs): super(BRCPFField, self).__init__(max_length=14, min_length=11, *args, **kwargs) @@ -100,9 +113,9 @@ class BRCPFField(CharField): try: int(value) except ValueError: - raise ValidationError(_("This field requires only numbers.")) + raise ValidationError(self.error_messages['digits_only']) if len(value) != 11: - raise ValidationError(_("This field requires at most 11 digits or 14 characters.")) + raise ValidationError(self.error_messages['max_digits']) orig_dv = value[-2:] new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(10, 1, -1))]) @@ -112,11 +125,17 @@ class BRCPFField(CharField): new_2dv = DV_maker(new_2dv % 11) value = value[:-1] + str(new_2dv) if value[-2:] != orig_dv: - raise ValidationError(_("Invalid CPF number.")) + raise ValidationError(self.error_messages['invalid']) return orig_value class BRCNPJField(Field): + default_error_messages = { + 'invalid': _("Invalid CNPJ number."), + 'digits_only': _("This field requires only numbers."), + 'max_digits': _("This field requires at least 14 digits"), + } + def clean(self, value): """ Value can be either a string in the format XX.XXX.XXX/XXXX-XX or a @@ -131,10 +150,9 @@ class BRCNPJField(Field): try: int(value) except ValueError: - raise ValidationError("This field requires only numbers.") + raise ValidationError(self.error_messages['digits_only']) if len(value) != 14: - raise ValidationError( - _("This field requires at least 14 digits")) + raise ValidationError(self.error_messages['max_digits']) orig_dv = value[-2:] new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(5, 1, -1) + range(9, 1, -1))]) @@ -144,7 +162,6 @@ class BRCNPJField(Field): new_2dv = DV_maker(new_2dv % 11) value = value[:-1] + str(new_2dv) if value[-2:] != orig_dv: - raise ValidationError(_("Invalid CNPJ number.")) + raise ValidationError(self.error_messages['invalid']) return orig_value - diff --git a/django/contrib/localflavor/ca/forms.py b/django/contrib/localflavor/ca/forms.py index 98f65a5c6c..daeff58acf 100644 --- a/django/contrib/localflavor/ca/forms.py +++ b/django/contrib/localflavor/ca/forms.py @@ -1,37 +1,43 @@ -""" -Canada-specific Form helpers -""" - -from django.newforms import ValidationError -from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES -from django.newforms.util import smart_unicode +""" +Canada-specific Form helpers +""" + +from django.newforms import ValidationError +from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES +from django.newforms.util import smart_unicode from django.utils.translation import gettext, ugettext -import re - +import re + phone_digits_re = re.compile(r'^(?:1-?)?(\d{3})[-\.]?(\d{3})[-\.]?(\d{4})$') sin_re = re.compile(r"^(\d{3})-(\d{3})-(\d{3})$") - -class CAPostalCodeField(RegexField): - """Canadian postal code field.""" - def __init__(self, *args, **kwargs): - super(CAPostalCodeField, self).__init__(r'^[ABCEGHJKLMNPRSTVXYZ]\d[A-Z] \d[A-Z]\d$', - max_length=None, min_length=None, - error_message=gettext(u'Enter a postal code in the format XXX XXX.'), - *args, **kwargs) - -class CAPhoneNumberField(Field): - """Canadian phone number field.""" - def clean(self, value): - """Validate a phone number. - """ - super(CAPhoneNumberField, self).clean(value) + +class CAPostalCodeField(RegexField): + """Canadian postal code field.""" + default_error_messages = { + 'invalid': gettext(u'Enter a postal code in the format XXX XXX.'), + } + + def __init__(self, *args, **kwargs): + super(CAPostalCodeField, self).__init__(r'^[ABCEGHJKLMNPRSTVXYZ]\d[A-Z] \d[A-Z]\d$', + max_length=None, min_length=None, *args, **kwargs) + +class CAPhoneNumberField(Field): + """Canadian phone number field.""" + default_error_messages = { + 'invalid': u'Phone numbers must be in XXX-XXX-XXXX format.', + } + + def clean(self, value): + """Validate a phone number. + """ + super(CAPhoneNumberField, self).clean(value) if value in EMPTY_VALUES: return u'' value = re.sub('(\(|\)|\s+)', '', smart_unicode(value)) m = phone_digits_re.search(value) if m: return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3)) - raise ValidationError(u'Phone numbers must be in XXX-XXX-XXXX format.') + raise ValidationError(self.error_messages['invalid']) class CAProvinceField(Field): """ @@ -39,6 +45,10 @@ class CAProvinceField(Field): It normalizes the input to the standard two-leter postal service abbreviation for the given province. """ + default_error_messages = { + 'invalid': u'Enter a Canadian province or territory.', + } + def clean(self, value): from ca_provinces import PROVINCES_NORMALIZED super(CAProvinceField, self).clean(value) @@ -53,17 +63,17 @@ class CAProvinceField(Field): return PROVINCES_NORMALIZED[value.strip().lower()].decode('ascii') except KeyError: pass - raise ValidationError(u'Enter a Canadian province or territory.') - -class CAProvinceSelect(Select): - """ - A Select widget that uses a list of Canadian provinces and - territories as its choices. - """ - def __init__(self, attrs=None): - from ca_provinces import PROVINCE_CHOICES # relative import + raise ValidationError(self.error_messages['invalid']) + +class CAProvinceSelect(Select): + """ + A Select widget that uses a list of Canadian provinces and + territories as its choices. + """ + def __init__(self, attrs=None): + from ca_provinces import PROVINCE_CHOICES # relative import super(CAProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES) - + class CASocialInsuranceNumberField(Field): """ A Canadian Social Insurance Number (SIN). @@ -74,24 +84,28 @@ class CASocialInsuranceNumberField(Field): * Passes the check digit process "Luhn Algorithm" See: http://en.wikipedia.org/wiki/Social_Insurance_Number """ + default_error_messages = { + 'invalid': ugettext('Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.'), + } + def clean(self, value): super(CASocialInsuranceNumberField, self).clean(value) if value in EMPTY_VALUES: return u'' - msg = ugettext('Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.') + match = re.match(sin_re, value) if not match: - raise ValidationError(msg) - - number = u'%s-%s-%s' % (match.group(1), match.group(2), match.group(3)) + raise ValidationError(self.error_messages['invalid']) + + number = u'%s-%s-%s' % (match.group(1), match.group(2), match.group(3)) check_number = u'%s%s%s' % (match.group(1), match.group(2), match.group(3)) if not self.luhn_checksum_is_valid(check_number): - raise ValidationError(msg) + raise ValidationError(self.error_messages['invalid']) return number - + def luhn_checksum_is_valid(self, number): """ - Checks to make sure that the SIN passes a luhn mod-10 checksum + Checks to make sure that the SIN passes a luhn mod-10 checksum See: http://en.wikipedia.org/wiki/Luhn_algorithm """ @@ -109,4 +123,4 @@ class CASocialInsuranceNumberField(Field): sum = sum + digit - return ( (sum % 10) == 0 ) \ No newline at end of file + return ( (sum % 10) == 0 ) diff --git a/django/contrib/localflavor/ch/forms.py b/django/contrib/localflavor/ch/forms.py index 5e601f5d74..2158fba697 100644 --- a/django/contrib/localflavor/ch/forms.py +++ b/django/contrib/localflavor/ch/forms.py @@ -12,11 +12,13 @@ id_re = re.compile(r"^(?P\w{8})(?P(\d{1}|<))(?P\d{1})$ phone_digits_re = re.compile(r'^0([1-9]{1})\d{8}$') class CHZipCodeField(RegexField): + default_error_messages = { + 'invalid': ugettext('Enter a zip code in the format XXXX.'), + } + def __init__(self, *args, **kwargs): super(CHZipCodeField, self).__init__(r'^\d{4}$', - max_length=None, min_length=None, - error_message=ugettext('Enter a zip code in the format XXXX.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) class CHPhoneNumberField(Field): """ @@ -25,6 +27,10 @@ class CHPhoneNumberField(Field): '0XX.XXX.XX.XX' and '0XXXXXXXXX' validate but are corrected to '0XX XXX XX XX'. """ + default_error_messages = { + 'invalid': 'Phone numbers must be in 0XX XXX XX XX format.', + } + def clean(self, value): super(CHPhoneNumberField, self).clean(value) if value in EMPTY_VALUES: @@ -33,7 +39,7 @@ class CHPhoneNumberField(Field): m = phone_digits_re.search(value) if m: return u'%s %s %s %s' % (value[0:3], value[3:6], value[6:8], value[8:10]) - raise ValidationError('Phone numbers must be in 0XX XXX XX XX format.') + raise ValidationError(self.error_messages['invalid']) class CHStateSelect(Select): """ @@ -54,6 +60,10 @@ class CHIdentityCardNumberField(Field): Algorithm is documented at http://adi.kousz.ch/artikel/IDCHE.htm """ + default_error_messages = { + 'invalid': ugettext('Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.'), + } + def has_valid_checksum(self, number): given_number, given_checksum = number[:-1], number[-1] new_number = given_number @@ -87,23 +97,22 @@ class CHIdentityCardNumberField(Field): def clean(self, value): super(CHIdentityCardNumberField, self).clean(value) - error_msg = ugettext('Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.') if value in EMPTY_VALUES: return u'' match = re.match(id_re, value) if not match: - raise ValidationError(error_msg) + raise ValidationError(self.error_messages['invalid']) idnumber, pos9, checksum = match.groupdict()['idnumber'], match.groupdict()['pos9'], match.groupdict()['checksum'] if idnumber == '00000000' or \ idnumber == 'A0000000': - raise ValidationError(error_msg) + raise ValidationError(self.error_messages['invalid']) all_digits = "%s%s%s" % (idnumber, pos9, checksum) if not self.has_valid_checksum(all_digits): - raise ValidationError(error_msg) + raise ValidationError(self.error_messages['invalid']) return u'%s%s%s' % (idnumber, pos9, checksum) diff --git a/django/contrib/localflavor/cl/forms.py b/django/contrib/localflavor/cl/forms.py index d2d37a3712..2f5ac29b39 100644 --- a/django/contrib/localflavor/cl/forms.py +++ b/django/contrib/localflavor/cl/forms.py @@ -25,16 +25,21 @@ class CLRutField(RegexField): Samples for testing are available from https://palena.sii.cl/cvc/dte/ee_empresas_emisoras.html """ + default_error_messages = { + 'invalid': ugettext('Enter a valid Chilean RUT.'), + 'strict': ugettext('Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.'), + 'checksum': ugettext('The Chilean RUT is not valid.'), + } + def __init__(self, *args, **kwargs): if 'strict' in kwargs: del kwargs['strict'] super(CLRutField, self).__init__(r'^(\d{1,2}\.)?\d{3}\.\d{3}-[\dkK]$', - error_message=ugettext('Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'), - *args, **kwargs) + error_message=self.default_error_messages['strict'], *args, **kwargs) else: # In non-strict mode, accept RUTs that validate but do not exist in # the real world. - super(CLRutField, self).__init__(r'^[\d\.]{1,11}-?[\dkK]$', error_message=ugettext('Enter valid a Chilean RUT'), *args, **kwargs) + super(CLRutField, self).__init__(r'^[\d\.]{1,11}-?[\dkK]$', *args, **kwargs) def clean(self, value): """ @@ -47,7 +52,7 @@ class CLRutField(RegexField): if self._algorithm(rut) == verificador: return self._format(rut, verificador) else: - raise ValidationError(u'The Chilean RUT is not valid.') + raise ValidationError(self.error_messages['checksum']) def _algorithm(self, rut): """ diff --git a/django/contrib/localflavor/de/forms.py b/django/contrib/localflavor/de/forms.py index 1a0b8587a6..76ce215dca 100644 --- a/django/contrib/localflavor/de/forms.py +++ b/django/contrib/localflavor/de/forms.py @@ -10,11 +10,12 @@ import re id_re = re.compile(r"^(?P\d{10})(?P\w{1,3})[-\ ]?(?P\d{7})[-\ ]?(?P\d{7})[-\ ]?(?P\d{1})$") class DEZipCodeField(RegexField): + default_error_messages = { + 'invalid': ugettext('Enter a zip code in the format XXXXX.'), + } def __init__(self, *args, **kwargs): super(DEZipCodeField, self).__init__(r'^\d{5}$', - max_length=None, min_length=None, - error_message=ugettext('Enter a zip code in the format XXXXX.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) class DEStateSelect(Select): """ @@ -36,6 +37,10 @@ class DEIdentityCardNumberField(Field): Algorithm is documented at http://de.wikipedia.org/wiki/Personalausweis """ + default_error_messages = { + 'invalid': ugettext('Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.'), + } + def has_valid_checksum(self, number): given_number, given_checksum = number[:-1], number[-1] calculated_checksum = 0 @@ -57,23 +62,22 @@ class DEIdentityCardNumberField(Field): def clean(self, value): super(DEIdentityCardNumberField, self).clean(value) - error_msg = ugettext('Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.') if value in EMPTY_VALUES: return u'' match = re.match(id_re, value) if not match: - raise ValidationError(error_msg) + raise ValidationError(self.error_messages['invalid']) gd = match.groupdict() residence, origin = gd['residence'], gd['origin'] birthday, validity, checksum = gd['birthday'], gd['validity'], gd['checksum'] if residence == '0000000000' or birthday == '0000000' or validity == '0000000': - raise ValidationError(error_msg) + raise ValidationError(self.error_messages['invalid']) all_digits = u"%s%s%s%s" % (residence, birthday, validity, checksum) if not self.has_valid_checksum(residence) or not self.has_valid_checksum(birthday) or \ not self.has_valid_checksum(validity) or not self.has_valid_checksum(all_digits): - raise ValidationError(error_msg) + raise ValidationError(self.error_messages['invalid']) return u'%s%s-%s-%s-%s' % (residence, origin, birthday, validity, checksum) diff --git a/django/contrib/localflavor/es/forms.py b/django/contrib/localflavor/es/forms.py index 29b41828f6..81186f8b3d 100644 --- a/django/contrib/localflavor/es/forms.py +++ b/django/contrib/localflavor/es/forms.py @@ -15,12 +15,14 @@ class ESPostalCodeField(RegexField): Spanish postal code is a five digits string, with two first digits between 01 and 52, assigned to provinces code. """ + default_error_messages = { + 'invalid': _('Enter a valid postal code in the range and format 01XXX - 52XXX.'), + } + def __init__(self, *args, **kwargs): super(ESPostalCodeField, self).__init__( r'^(0[1-9]|[1-4][0-9]|5[0-2])\d{3}$', - max_length=None, min_length=None, - error_message=_('Enter a valid postal code in the range and format 01XXX - 52XXX.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) class ESPhoneNumberField(RegexField): """ @@ -33,11 +35,13 @@ class ESPhoneNumberField(RegexField): TODO: accept and strip characters like dot, hyphen... in phone number """ + default_error_messages = { + 'invalid': _('Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.'), + } + def __init__(self, *args, **kwargs): super(ESPhoneNumberField, self).__init__(r'^(6|8|9)\d{8}$', - max_length=None, min_length=None, - error_message=_('Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) class ESIdentityCardNumberField(RegexField): """ @@ -58,19 +62,23 @@ class ESIdentityCardNumberField(RegexField): public, and different authors have different opinions on which ones allows letters, so both validations are assumed true for all types. """ + default_error_messages = { + 'invalid': _('Please enter a valid NIF, NIE, or CIF.'), + 'invalid_only_nif': _('Please enter a valid NIF or NIE.'), + 'invalid_nif': _('Invalid checksum for NIF.'), + 'invalid_nie': _('Invalid checksum for NIE.'), + 'invalid_cif': _('Invalid checksum for CIF.'), + } + def __init__(self, only_nif=False, *args, **kwargs): self.only_nif = only_nif self.nif_control = 'TRWAGMYFPDXBNJZSQVHLCKE' self.cif_control = 'JABCDEFGHI' self.cif_types = 'ABCDEFGHKLMNPQS' self.nie_types = 'XT' - if self.only_nif: - self.id_types = 'NIF or NIE' - else: - self.id_types = 'NIF, NIE, or CIF' super(ESIdentityCardNumberField, self).__init__(r'^([%s]?)[ -]?(\d+)[ -]?([%s]?)$' % (self.cif_types + self.nie_types + self.cif_types.lower() + self.nie_types.lower(), self.nif_control + self.nif_control.lower()), max_length=None, min_length=None, - error_message=_('Please enter a valid %s.' % self.id_types), + error_message=self.default_error_messages['invalid%s' % (self.only_nif and '_only_nif' or '')], *args, **kwargs) def clean(self, value): @@ -88,13 +96,13 @@ class ESIdentityCardNumberField(RegexField): if letter2 == nif_get_checksum(number): return value else: - raise ValidationError, _('Invalid checksum for NIF.') + raise ValidationError, self.error_messages['invalid_nif'] elif letter1 in self.nie_types and letter2: # NIE if letter2 == nif_get_checksum(number): return value else: - raise ValidationError, _('Invalid checksum for NIE.') + raise ValidationError, self.error_messages['invalid_nie'] elif not self.only_nif and letter1 in self.cif_types and len(number) in [7, 8]: # CIF if not letter2: @@ -103,9 +111,9 @@ class ESIdentityCardNumberField(RegexField): if letter2 in [checksum, self.cif_control[checksum]]: return value else: - raise ValidationError, _('Invalid checksum for CIF.') + raise ValidationError, self.error_messages['invalid_cif'] else: - raise ValidationError, _('Please enter a valid %s.' % self.id_types) + raise ValidationError, self.error_messages['invalid'] class ESCCCField(RegexField): """ @@ -130,11 +138,14 @@ class ESCCCField(RegexField): TODO: allow IBAN validation too """ + default_error_messages = { + 'invalid': _('Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX.'), + 'checksum': _('Invalid checksum for bank account number.'), + } + def __init__(self, *args, **kwargs): super(ESCCCField, self).__init__(r'^\d{4}[ -]?\d{4}[ -]?\d{2}[ -]?\d{10}$', - max_length=None, min_length=None, - error_message=_('Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) def clean(self, value): super(ESCCCField, self).clean(value) @@ -147,7 +158,7 @@ class ESCCCField(RegexField): if get_checksum('00' + entity + office) + get_checksum(account) == checksum: return value else: - raise ValidationError, _('Invalid checksum for bank account number.') + raise ValidationError, self.error_messages['checksum'] class ESRegionSelect(Select): """ diff --git a/django/contrib/localflavor/fi/forms.py b/django/contrib/localflavor/fi/forms.py index 82e024f7b1..a0274da44c 100644 --- a/django/contrib/localflavor/fi/forms.py +++ b/django/contrib/localflavor/fi/forms.py @@ -8,11 +8,12 @@ from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES from django.utils.translation import ugettext class FIZipCodeField(RegexField): + default_error_messages = { + 'invalid': ugettext('Enter a zip code in the format XXXXX.'), + } def __init__(self, *args, **kwargs): super(FIZipCodeField, self).__init__(r'^\d{5}$', - max_length=None, min_length=None, - error_message=ugettext('Enter a zip code in the format XXXXX.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) class FIMunicipalitySelect(Select): """ @@ -23,6 +24,10 @@ class FIMunicipalitySelect(Select): super(FIMunicipalitySelect, self).__init__(attrs, choices=MUNICIPALITY_CHOICES) class FISocialSecurityNumber(Field): + default_error_messages = { + 'invalid': ugettext('Enter a valid Finnish social security number.'), + } + def clean(self, value): super(FISocialSecurityNumber, self).clean(value) if value in EMPTY_VALUES: @@ -37,9 +42,9 @@ class FISocialSecurityNumber(Field): (?P(\d{3})) (?P[%s])$""" % checkmarks, value, re.VERBOSE | re.IGNORECASE) if not result: - raise ValidationError(ugettext('Enter a valid Finnish social security number.')) + raise ValidationError(self.error_messages['invalid']) gd = result.groupdict() checksum = int(gd['date'] + gd['serial']) if checkmarks[checksum % len(checkmarks)] == gd['checksum'].upper(): return u'%s' % value.upper() - raise ValidationError(ugettext('Enter a valid Finnish social security number.')) + raise ValidationError(self.error_messages['invalid']) diff --git a/django/contrib/localflavor/fr/forms.py b/django/contrib/localflavor/fr/forms.py index cc0a5db259..635b62edd5 100644 --- a/django/contrib/localflavor/fr/forms.py +++ b/django/contrib/localflavor/fr/forms.py @@ -11,11 +11,13 @@ import re phone_digits_re = re.compile(r'^0\d(\s|\.)?(\d{2}(\s|\.)?){3}\d{2}$') class FRZipCodeField(RegexField): + default_error_messages = { + 'invalid': ugettext('Enter a zip code in the format XXXXX.'), + } + def __init__(self, *args, **kwargs): super(FRZipCodeField, self).__init__(r'^\d{5}$', - max_length=None, min_length=None, - error_message=ugettext('Enter a zip code in the format XXXXX.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) class FRPhoneNumberField(Field): """ @@ -24,6 +26,10 @@ class FRPhoneNumberField(Field): '0X.XX.XX.XX.XX' and '0XXXXXXXXX' validate but are corrected to '0X XX XX XX XX'. """ + default_error_messages = { + 'invalid': u'Phone numbers must be in 0X XX XX XX XX format.', + } + def clean(self, value): super(FRPhoneNumberField, self).clean(value) if value in EMPTY_VALUES: @@ -32,7 +38,7 @@ class FRPhoneNumberField(Field): m = phone_digits_re.search(value) if m: return u'%s %s %s %s %s' % (value[0:2], value[2:4], value[4:6], value[6:8], value[8:10]) - raise ValidationError(u'Phone numbers must be in 0X XX XX XX XX format.') + raise ValidationError(self.error_messages['invalid']) class FRDepartmentSelect(Select): """ diff --git a/django/contrib/localflavor/in_/forms.py b/django/contrib/localflavor/in_/forms.py index 5febc40e67..1cb303d772 100644 --- a/django/contrib/localflavor/in_/forms.py +++ b/django/contrib/localflavor/in_/forms.py @@ -10,11 +10,13 @@ import re class INZipCodeField(RegexField): + default_error_messages = { + 'invalid': gettext(u'Enter a zip code in the format XXXXXXX.'), + } + def __init__(self, *args, **kwargs): super(INZipCodeField, self).__init__(r'^\d{6}$', - max_length=None, min_length=None, - error_message=gettext(u'Enter a zip code in the format XXXXXXX.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) class INStateField(Field): """ @@ -22,6 +24,10 @@ class INStateField(Field): abbreviation. It normalizes the input to the standard two-letter vehicle registration abbreviation for the given state or union territory """ + default_error_messages = { + 'invalid': u'Enter a Indian state or territory.', + } + def clean(self, value): from in_states import STATES_NORMALIZED super(INStateField, self).clean(value) @@ -36,7 +42,7 @@ class INStateField(Field): return smart_unicode(STATES_NORMALIZED[value.strip().lower()]) except KeyError: pass - raise ValidationError(u'Enter a Indian state or territory.') + raise ValidationError(self.error_messages['invalid']) class INStateSelect(Select): """ diff --git a/django/contrib/localflavor/is_/forms.py b/django/contrib/localflavor/is_/forms.py index ef8799e29c..ea7a1e00c3 100644 --- a/django/contrib/localflavor/is_/forms.py +++ b/django/contrib/localflavor/is_/forms.py @@ -13,10 +13,14 @@ class ISIdNumberField(RegexField): Icelandic identification number (kennitala). This is a number every citizen of Iceland has. """ + default_error_messages = { + 'invalid': ugettext('Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.'), + 'checksum': ugettext(u'The Icelandic identification number is not valid.'), + } + def __init__(self, *args, **kwargs): - error_msg = ugettext('Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.') kwargs['min_length'],kwargs['max_length'] = 10,11 - super(ISIdNumberField, self).__init__(r'^\d{6}(-| )?\d{4}$', error_message=error_msg, *args, **kwargs) + super(ISIdNumberField, self).__init__(r'^\d{6}(-| )?\d{4}$', *args, **kwargs) def clean(self, value): value = super(ISIdNumberField, self).clean(value) @@ -28,7 +32,7 @@ class ISIdNumberField(RegexField): if self._validate(value): return self._format(value) else: - raise ValidationError(ugettext(u'The Icelandic identification number is not valid.')) + raise ValidationError(self.error_messages['checksum']) def _canonify(self, value): """ diff --git a/django/contrib/localflavor/it/forms.py b/django/contrib/localflavor/it/forms.py index 0b6eecec45..88e65734e4 100644 --- a/django/contrib/localflavor/it/forms.py +++ b/django/contrib/localflavor/it/forms.py @@ -10,11 +10,12 @@ from django.contrib.localflavor.it.util import ssn_check_digit, vat_number_check import re class ITZipCodeField(RegexField): + default_error_messages = { + 'invalid': ugettext('Enter a valid zip code.'), + } def __init__(self, *args, **kwargs): super(ITZipCodeField, self).__init__(r'^\d{5}$', - max_length=None, min_length=None, - error_message=ugettext('Enter a valid zip code.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) class ITRegionSelect(Select): """ @@ -38,11 +39,13 @@ class ITSocialSecurityNumberField(RegexField): For reference see http://www.agenziaentrate.it/ and search for 'Informazioni sulla codificazione delle persone fisiche'. """ - err_msg = ugettext(u'Enter a valid Social Security number.') + default_error_messages = { + 'invalid': ugettext(u'Enter a valid Social Security number.'), + } + def __init__(self, *args, **kwargs): super(ITSocialSecurityNumberField, self).__init__(r'^\w{3}\s*\w{3}\s*\w{5}\s*\w{5}$', - max_length=None, min_length=None, error_message=self.err_msg, - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) def clean(self, value): value = super(ITSocialSecurityNumberField, self).clean(value) @@ -52,26 +55,29 @@ class ITSocialSecurityNumberField(RegexField): try: check_digit = ssn_check_digit(value) except ValueError: - raise ValidationError(self.err_msg) + raise ValidationError(self.error_messages['invalid']) if not value[15] == check_digit: - raise ValidationError(self.err_msg) + raise ValidationError(self.error_messages['invalid']) return value class ITVatNumberField(Field): """ A form field that validates Italian VAT numbers (partita IVA). """ + default_error_messages = { + 'invalid': ugettext(u'Enter a valid VAT number.'), + } + def clean(self, value): value = super(ITVatNumberField, self).clean(value) if value == u'': return value - err_msg = ugettext(u'Enter a valid VAT number.') try: vat_number = int(value) except ValueError: - raise ValidationError(err_msg) + raise ValidationError(self.error_messages['invalid']) vat_number = str(vat_number).zfill(11) check_digit = vat_number_check_digit(vat_number[0:10]) if not vat_number[10] == check_digit: - raise ValidationError(err_msg) + raise ValidationError(self.error_messages['invalid']) return smart_unicode(vat_number) diff --git a/django/contrib/localflavor/jp/forms.py b/django/contrib/localflavor/jp/forms.py index 682ffb8c31..13083aab6e 100644 --- a/django/contrib/localflavor/jp/forms.py +++ b/django/contrib/localflavor/jp/forms.py @@ -15,11 +15,13 @@ class JPPostalCodeField(RegexField): Accepts 7 digits, with or without a hyphen. """ + default_error_messages = { + 'invalid': ugettext('Enter a postal code in the format XXXXXXX or XXX-XXXX.'), + } + def __init__(self, *args, **kwargs): super(JPPostalCodeField, self).__init__(r'^\d{3}-\d{4}$|^\d{7}$', - max_length=None, min_length=None, - error_message=ugettext('Enter a postal code in the format XXXXXXX or XXX-XXXX.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) def clean(self, value): """ diff --git a/django/contrib/localflavor/nl/forms.py b/django/contrib/localflavor/nl/forms.py index e202ab0595..748484926e 100644 --- a/django/contrib/localflavor/nl/forms.py +++ b/django/contrib/localflavor/nl/forms.py @@ -17,24 +17,27 @@ class NLZipCodeField(Field): """ A Dutch postal code field. """ + default_error_messages = { + 'invalid': _('Enter a valid postal code'), + } + def clean(self, value): super(NLZipCodeField, self).clean(value) if value in EMPTY_VALUES: return u'' - - msg = _('Enter a valid postal code') + value = value.strip().upper().replace(' ', '') if not pc_re.search(value): - raise ValidationError(msg) - + raise ValidationError(self.error_messages['invalid']) + if int(value[:4]) < 1000: - raise ValidationError(msg) - + raise ValidationError(self.error_messages['invalid']) + return u'%s %s' % (value[:4], value[4:]) class NLProvinceSelect(Select): """ - A Select widget that uses a list of provinces of the Netherlands as its + A Select widget that uses a list of provinces of the Netherlands as its choices. """ def __init__(self, attrs=None): @@ -45,48 +48,53 @@ class NLPhoneNumberField(Field): """ A Dutch telephone number field. """ + default_error_messages = { + 'invalid': _('Enter a valid phone number'), + } + def clean(self, value): super(NLPhoneNumberField, self).clean(value) if value in EMPTY_VALUES: return u'' - - msg = _('Enter a valid phone number') + phone_nr = re.sub('[\-\s\(\)]', '', smart_unicode(value)) - + if len(phone_nr) == 10 and numeric_re.search(phone_nr): return value - + if phone_nr[:3] == '+31' and len(phone_nr) == 12 and \ numeric_re.search(phone_nr[3:]): return value - - raise ValidationError(msg) + + raise ValidationError(self.error_messages['invalid']) class NLSoFiNumberField(Field): """ A Dutch social security number (SoFi/BSN) field. - + http://nl.wikipedia.org/wiki/Sofinummer """ + default_error_messages = { + 'invalid': _('Enter a valid SoFi number'), + } + def clean(self, value): super(NLSoFiNumberField, self).clean(value) if value in EMPTY_VALUES: return u'' - - msg = _('Enter a valid SoFi number') - + if not sofi_re.search(value): - raise ValidationError(msg) - + raise ValidationError(self.error_messages['invalid']) + if int(value) == 0: - raise ValidationError(msg) - + raise ValidationError(self.error_messages['invalid']) + checksum = 0 for i in range(9, 1, -1): checksum += int(value[9-i]) * i checksum -= int(value[-1]) - + if checksum % 11 != 0: - raise ValidationError(msg) - + raise ValidationError(self.error_messages['invalid']) + return value diff --git a/django/contrib/localflavor/no/forms.py b/django/contrib/localflavor/no/forms.py index 2de3df14d8..8dc001955d 100644 --- a/django/contrib/localflavor/no/forms.py +++ b/django/contrib/localflavor/no/forms.py @@ -8,11 +8,13 @@ from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES from django.utils.translation import ugettext class NOZipCodeField(RegexField): + default_error_messages = { + 'invalid': ugettext('Enter a zip code in the format XXXX.'), + } + def __init__(self, *args, **kwargs): super(NOZipCodeField, self).__init__(r'^\d{4}$', - max_length=None, min_length=None, - error_message=ugettext('Enter a zip code in the format XXXX.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) class NOMunicipalitySelect(Select): """ @@ -27,14 +29,17 @@ class NOSocialSecurityNumber(Field): """ Algorithm is documented at http://no.wikipedia.org/wiki/Personnummer """ + default_error_messages = { + 'invalid': ugettext(u'Enter a valid Norwegian social security number.'), + } + def clean(self, value): super(NOSocialSecurityNumber, self).clean(value) if value in EMPTY_VALUES: return u'' - msg = ugettext(u'Enter a valid Norwegian social security number.') if not re.match(r'^\d{11}$', value): - raise ValidationError(msg) + raise ValidationError(self.error_messages['invalid']) day = int(value[:2]) month = int(value[2:4]) @@ -52,7 +57,7 @@ class NOSocialSecurityNumber(Field): if 900 <= inum < 1000 and year2 > 39: self.birthday = datetime.date(1900+year2, month, day) except ValueError: - raise ValidationError(msg) + raise ValidationError(self.error_messages['invalid']) sexnum = int(value[8]) if sexnum % 2 == 0: @@ -68,9 +73,9 @@ class NOSocialSecurityNumber(Field): return sum([(a * b) for (a, b) in zip(aval, bval)]) if multiply_reduce(digits, weight_1) % 11 != 0: - raise ValidationError(msg) + raise ValidationError(self.error_messages['invalid']) if multiply_reduce(digits, weight_2) % 11 != 0: - raise ValidationError(msg) + raise ValidationError(self.error_messages['invalid']) return value diff --git a/django/contrib/localflavor/pe/forms.py b/django/contrib/localflavor/pe/forms.py index b1ae215417..57c9d441f7 100644 --- a/django/contrib/localflavor/pe/forms.py +++ b/django/contrib/localflavor/pe/forms.py @@ -19,6 +19,11 @@ class PEDNIField(CharField): """ A field that validates `Documento Nacional de IdentidadŽ (DNI) numbers. """ + default_error_messages = { + 'invalid': ugettext("This field requires only numbers."), + 'max_digits': ugettext("This field requires 8 digits."), + } + def __init__(self, *args, **kwargs): super(PEDNIField, self).__init__(max_length=8, min_length=8, *args, **kwargs) @@ -31,9 +36,9 @@ class PEDNIField(CharField): if value in EMPTY_VALUES: return u'' if not value.isdigit(): - raise ValidationError(ugettext("This field requires only numbers.")) + raise ValidationError(self.error_messages['invalid']) if len(value) != 8: - raise ValidationError(ugettext("This field requires 8 digits.")) + raise ValidationError(self.error_messages['max_digits']) return value @@ -42,6 +47,11 @@ class PERUCField(RegexField): This field validates a RUC (Registro Unico de Contribuyentes). A RUC is of the form XXXXXXXXXXX. """ + default_error_messages = { + 'invalid': ugettext("This field requires only numbers."), + 'max_digits': ugettext("This field requires 11 digits."), + } + def __init__(self, *args, **kwargs): super(PERUCField, self).__init__(max_length=11, min_length=11, *args, **kwargs) @@ -54,8 +64,8 @@ class PERUCField(RegexField): if value in EMPTY_VALUES: return u'' if not value.isdigit(): - raise ValidationError(ugettext("This field requires only numbers.")) + raise ValidationError(self.error_messages['invalid']) if len(value) != 11: - raise ValidationError(ugettext("This field requires 11 digits.")) + raise ValidationError(self.error_messages['max_digits']) return value diff --git a/django/contrib/localflavor/pl/forms.py b/django/contrib/localflavor/pl/forms.py index 3d1c4234d3..b02dad7025 100644 --- a/django/contrib/localflavor/pl/forms.py +++ b/django/contrib/localflavor/pl/forms.py @@ -35,16 +35,19 @@ class PLNationalIdentificationNumberField(RegexField): The algorithm is documented at http://en.wikipedia.org/wiki/PESEL. """ + default_error_messages = { + 'invalid': _(u'National Identification Number consists of 11 digits.'), + 'checksum': _(u'Wrong checksum for the National Identification Number.'), + } def __init__(self, *args, **kwargs): super(PLNationalIdentificationNumberField, self).__init__(r'^\d{11}$', - max_length=None, min_length=None, error_message=_(u'National Identification Number consists of 11 digits.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) def clean(self,value): super(PLNationalIdentificationNumberField, self).clean(value) if not self.has_valid_checksum(value): - raise ValidationError(_(u'Wrong checksum for the National Identification Number.')) + raise ValidationError(self.error_messages['checksum']) return u'%s' % value def has_valid_checksum(self, number): @@ -65,17 +68,20 @@ class PLTaxNumberField(RegexField): Checksum algorithm based on documentation at http://wipos.p.lodz.pl/zylla/ut/nip-rego.html """ + default_error_messages = { + 'invalid': _(u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.'), + 'checksum': _(u'Wrong checksum for the Tax Number (NIP).'), + } def __init__(self, *args, **kwargs): super(PLTaxNumberField, self).__init__(r'^\d{3}-\d{3}-\d{2}-\d{2}$|^\d{2}-\d{2}-\d{3}-\d{3}$', - max_length=None, min_length=None, - error_message=_(u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.'), *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) def clean(self,value): super(PLTaxNumberField, self).clean(value) value = re.sub("[-]", "", value) if not self.has_valid_checksum(value): - raise ValidationError(_(u'Wrong checksum for the Tax Number (NIP).')) + raise ValidationError(self.error_messages['checksum']) return u'%s' % value def has_valid_checksum(self, number): @@ -102,15 +108,19 @@ class PLNationalBusinessRegisterField(RegexField): The checksum algorithm is documented at http://wipos.p.lodz.pl/zylla/ut/nip-rego.html """ + default_error_messages = { + 'invalid': _(u'National Business Register Number (REGON) consists of 7 or 9 digits.'), + 'checksum': _(u'Wrong checksum for the National Business Register Number (REGON).'), + } + def __init__(self, *args, **kwargs): super(PLNationalBusinessRegisterField, self).__init__(r'^\d{7,9}$', - max_length=None, min_length=None, error_message=_(u'National Business Register Number (REGON) consists of 7 or 9 digits.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) def clean(self,value): super(PLNationalBusinessRegisterField, self).clean(value) if not self.has_valid_checksum(value): - raise ValidationError(_(u'Wrong checksum for the National Business Register Number (REGON).')) + raise ValidationError(self.error_messages['checksum']) return u'%s' % value def has_valid_checksum(self, number): @@ -142,9 +152,10 @@ class PLPostalCodeField(RegexField): A form field that validates as Polish postal code. Valid code is XX-XXX where X is digit. """ + default_error_messages = { + 'invalid': _(u'Enter a postal code in the format XX-XXX.'), + } + def __init__(self, *args, **kwargs): super(PLPostalCodeField, self).__init__(r'^\d{2}-\d{3}$', - max_length=None, min_length=None, - error_message=_(u'Enter a postal code in the format XX-XXX.'), - *args, **kwargs) - + max_length=None, min_length=None, *args, **kwargs) diff --git a/django/contrib/localflavor/sk/forms.py b/django/contrib/localflavor/sk/forms.py index 0aa000a0a5..711d70fc2b 100644 --- a/django/contrib/localflavor/sk/forms.py +++ b/django/contrib/localflavor/sk/forms.py @@ -26,11 +26,13 @@ class SKPostalCodeField(RegexField): A form field that validates its input as Slovak postal code. Valid form is XXXXX or XXX XX, where X represents integer. """ + default_error_messages = { + 'invalid': ugettext(u'Enter a postal code in the format XXXXX or XXX XX.'), + } + def __init__(self, *args, **kwargs): super(SKPostalCodeField, self).__init__(r'^\d{5}$|^\d{3} \d{2}$', - max_length=None, min_length=None, - error_message=ugettext(u'Enter a postal code in the format XXXXX or XXX XX.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) def clean(self, value): """ diff --git a/django/contrib/localflavor/uk/forms.py b/django/contrib/localflavor/uk/forms.py index 2b162230de..68e15aac38 100644 --- a/django/contrib/localflavor/uk/forms.py +++ b/django/contrib/localflavor/uk/forms.py @@ -12,11 +12,13 @@ class UKPostcodeField(RegexField): The regular expression used is sourced from the schema for British Standard BS7666 address types: http://www.govtalk.gov.uk/gdsc/schemas/bs7666-v2-0.xsd """ + default_error_messages = { + 'invalid': ugettext(u'Enter a postcode. A space is required between the two postcode parts.'), + } + def __init__(self, *args, **kwargs): super(UKPostcodeField, self).__init__(r'^(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HIK-Y][0-9](|[0-9]|[ABEHMNPRVWXY]))|[0-9][A-HJKSTUW]) [0-9][ABD-HJLNP-UW-Z]{2})$', - max_length=None, min_length=None, - error_message=ugettext(u'Enter a postcode. A space is required between the two postcode parts.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) class UKCountySelect(Select): """ diff --git a/django/contrib/localflavor/us/forms.py b/django/contrib/localflavor/us/forms.py index 259a7f7058..d6aa684cba 100644 --- a/django/contrib/localflavor/us/forms.py +++ b/django/contrib/localflavor/us/forms.py @@ -12,13 +12,19 @@ phone_digits_re = re.compile(r'^(?:1-?)?(\d{3})[-\.]?(\d{3})[-\.]?(\d{4})$') ssn_re = re.compile(r"^(?P\d{3})[-\ ]?(?P\d{2})[-\ ]?(?P\d{4})$") class USZipCodeField(RegexField): + default_error_messages = { + 'invalid': ugettext('Enter a zip code in the format XXXXX or XXXXX-XXXX.'), + } + def __init__(self, *args, **kwargs): super(USZipCodeField, self).__init__(r'^\d{5}(?:-\d{4})?$', - max_length=None, min_length=None, - error_message=ugettext('Enter a zip code in the format XXXXX or XXXXX-XXXX.'), - *args, **kwargs) + max_length=None, min_length=None, *args, **kwargs) class USPhoneNumberField(Field): + default_error_messages = { + 'invalid': u'Phone numbers must be in XXX-XXX-XXXX format.', + } + def clean(self, value): super(USPhoneNumberField, self).clean(value) if value in EMPTY_VALUES: @@ -27,7 +33,7 @@ class USPhoneNumberField(Field): m = phone_digits_re.search(value) if m: return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3)) - raise ValidationError(u'Phone numbers must be in XXX-XXX-XXXX format.') + raise ValidationError(self.error_messages['invalid']) class USSocialSecurityNumberField(Field): """ @@ -44,28 +50,31 @@ class USSocialSecurityNumberField(Field): promotional use or distribution (e.g., the Woolworth's number or the 1962 promotional number). """ + default_error_messages = { + 'invalid': ugettext('Enter a valid U.S. Social Security number in XXX-XX-XXXX format.'), + } + def clean(self, value): super(USSocialSecurityNumberField, self).clean(value) if value in EMPTY_VALUES: return u'' - msg = ugettext('Enter a valid U.S. Social Security number in XXX-XX-XXXX format.') match = re.match(ssn_re, value) if not match: - raise ValidationError(msg) + raise ValidationError(self.error_messages['invalid']) area, group, serial = match.groupdict()['area'], match.groupdict()['group'], match.groupdict()['serial'] # First pass: no blocks of all zeroes. if area == '000' or \ group == '00' or \ serial == '0000': - raise ValidationError(msg) + raise ValidationError(self.error_messages['invalid']) # Second pass: promotional and otherwise permanently invalid numbers. if area == '666' or \ (area == '987' and group == '65' and 4320 <= int(serial) <= 4329) or \ value == '078-05-1120' or \ value == '219-09-9999': - raise ValidationError(msg) + raise ValidationError(self.error_messages['invalid']) return u'%s-%s-%s' % (area, group, serial) class USStateField(Field): @@ -74,6 +83,10 @@ class USStateField(Field): It normalizes the input to the standard two-leter postal service abbreviation for the given state. """ + default_error_messages = { + 'invalid': u'Enter a U.S. state or territory.', + } + def clean(self, value): from us_states import STATES_NORMALIZED super(USStateField, self).clean(value) @@ -88,7 +101,7 @@ class USStateField(Field): return STATES_NORMALIZED[value.strip().lower()].decode('ascii') except KeyError: pass - raise ValidationError(u'Enter a U.S. state or territory.') + raise ValidationError(self.error_messages['invalid']) class USStateSelect(Select): """ diff --git a/django/contrib/localflavor/za/forms.py b/django/contrib/localflavor/za/forms.py index b04b7cf6ab..b3613b507d 100644 --- a/django/contrib/localflavor/za/forms.py +++ b/django/contrib/localflavor/za/forms.py @@ -16,10 +16,9 @@ class ZAIDField(Field): using the Luhn checksum, and uses a simlistic (read: not entirely accurate) check for the birthdate """ - - def __init__(self, *args, **kwargs): - super(ZAIDField, self).__init__() - self.error_message = _(u'Enter a valid South African ID number') + default_error_messages = { + 'invalid': _(u'Enter a valid South African ID number'), + } def clean(self, value): # strip spaces and dashes @@ -31,9 +30,9 @@ class ZAIDField(Field): return u'' match = re.match(id_re, value) - + if not match: - raise ValidationError(self.error_message) + raise ValidationError(self.error_messages['invalid']) g = match.groupdict() @@ -43,15 +42,18 @@ class ZAIDField(Field): # There is no way to guess the century of a ZA ID number d = date(int(g['yy']) + 2000, int(g['mm']), int(g['dd'])) except ValueError: - raise ValidationError(self.error_message) + raise ValidationError(self.error_messages['invalid']) if not luhn(value): - raise ValidationError(self.error_message) + raise ValidationError(self.error_messages['invalid']) return value class ZAPostCodeField(RegexField): + default_error_messages = { + 'invalid': _(u'Enter a valid South African postal code'), + } + def __init__(self, *args, **kwargs): super(ZAPostCodeField, self).__init__(r'^\d{4}$', - max_length=None, min_length=None, - error_message=_(u'Enter a valid South African postal code')) + max_length=None, min_length=None) diff --git a/tests/regressiontests/forms/localflavor/cl.py b/tests/regressiontests/forms/localflavor/cl.py index 407f6610e4..23e7a41902 100644 --- a/tests/regressiontests/forms/localflavor/cl.py +++ b/tests/regressiontests/forms/localflavor/cl.py @@ -41,7 +41,7 @@ Strict RUT usage (does not allow imposible values) >>> rut.clean('11-6') Traceback (most recent call last): ... -ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'] +ValidationError: [u'Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.'] # valid format, bad verifier. >>> rut.clean('11.111.111-0') @@ -53,17 +53,17 @@ ValidationError: [u'The Chilean RUT is not valid.'] >>> rut.clean('767484100') Traceback (most recent call last): ... -ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'] +ValidationError: [u'Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.'] >>> rut.clean('78.412.790-7') u'78.412.790-7' >>> rut.clean('8.334.6043') Traceback (most recent call last): ... -ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'] +ValidationError: [u'Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.'] >>> rut.clean('76793310-K') Traceback (most recent call last): ... -ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'] +ValidationError: [u'Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.'] ## CLRegionSelect ######################################################### >>> from django.contrib.localflavor.cl.forms import CLRegionSelect