diff --git a/AUTHORS b/AUTHORS
index bd7ef7770d..3ed70d2cce 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -150,6 +150,7 @@ answer newbie questions, and generally made Django that much better:
Manuzhai
Petar Marić
Nuno Mariz
+ marijn@metronomo.cl
mark@junklight.com
Yasushi Masuda
mattycakes@gmail.com
diff --git a/django/contrib/localflavor/cl/__init__.py b/django/contrib/localflavor/cl/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/django/contrib/localflavor/cl/forms.py b/django/contrib/localflavor/cl/forms.py
new file mode 100644
index 0000000000..b3b9cf8741
--- /dev/null
+++ b/django/contrib/localflavor/cl/forms.py
@@ -0,0 +1,77 @@
+"""
+Chile specific form helpers.
+"""
+from django.newforms import ValidationError
+from django.newforms.fields import RegexField, EMPTY_VALUES
+from django.utils.translation import gettext
+
+class CLRutField(RegexField):
+ """
+ Chilean "Rol Unico Tributario" (RUT) field. This is the Chilean national
+ identification number.
+
+ Samples for testing are available from
+ https://palena.sii.cl/cvc/dte/ee_empresas_emisoras.html
+ """
+ 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=gettext('Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'),
+ *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=gettext(u'Enter valid a Chilean RUT'), *args, **kwargs)
+
+ def clean(self, value):
+ """
+ Check and clean the chilean rut.
+ """
+ super(CLRutField, self).clean(value)
+ if value in EMPTY_VALUES:
+ return u''
+ rut, verificador = self._canonify(value)
+ if self._algorithm(rut) == verificador:
+ return self._format(rut, verificador)
+ else:
+ raise ValidationError(u'The Chilean RUT is not valid.')
+
+ def _algorithm(self, rut):
+ """
+ Takes RUT in pure canonical form, calculates the verifier digit.
+ """
+ suma = 0
+ multi = 2
+ for r in rut[::-1]:
+ suma += int(r) * multi
+ multi += 1
+ if multi == 8:
+ multi = 2
+ return '0123456789K0'[11 - suma % 11]
+
+ def _canonify(self, rut):
+ """
+ Turns the RUT into one normalized format. Returns a (rut, verifier)
+ tuple.
+ """
+ rut = str(rut).replace(' ', '').replace('.', '').replace('-', '')
+ return rut[:-1], rut[-1]
+
+ def _format(self, code, verifier=None):
+ """
+ Formats the RUT from canonical form to the common string representation.
+ If verifier=None, then the last digit in 'code' is the verifier.
+ """
+ if verifier is None:
+ verifier = code[-1]
+ code = code[:-1]
+ while len(code) > 3 and '.' not in code[:3]:
+ pos = code.find('.')
+ if pos == -1:
+ new_dot = -3
+ else:
+ new_dot = pos - 3
+ code = code[:new_dot] + '.' + code[new_dot:]
+ return '%s-%s' % (code, verifier)
+
diff --git a/tests/regressiontests/forms/localflavor.py b/tests/regressiontests/forms/localflavor.py
index e88228f252..1747a0a61c 100644
--- a/tests/regressiontests/forms/localflavor.py
+++ b/tests/regressiontests/forms/localflavor.py
@@ -1150,4 +1150,68 @@ u''
>>> f.render('foo', 'bar')
u''
+
+## CLRutField #############################################################
+
+CLRutField is a Field that checks the validity of the Chilean
+personal identification number (RUT). It has two modes relaxed (default) and
+strict.
+
+>>> from django.contrib.localflavor.cl.forms import CLRutField
+>>> rut = CLRutField()
+
+>>> rut.clean('11-6')
+'11-6'
+>>> rut.clean('116')
+'11-6'
+
+# valid format, bad verifier.
+>>> rut.clean('11.111.111-0')
+Traceback (most recent call last):
+...
+ValidationError: [u'The Chilean RUT is not valid.']
+>>> rut.clean('111')
+Traceback (most recent call last):
+...
+ValidationError: [u'The Chilean RUT is not valid.']
+
+>>> rut.clean('767484100')
+'76.748.410-0'
+>>> rut.clean('78.412.790-7')
+'78.412.790-7'
+>>> rut.clean('8.334.6043')
+'8.334.604-3'
+>>> rut.clean('76793310-K')
+'76.793.310-K'
+
+Strict RUT usage (does not allow imposible values)
+>>> rut = CLRutField(strict=True)
+
+>>> rut.clean('11-6')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
+
+# valid format, bad verifier.
+>>> rut.clean('11.111.111-0')
+Traceback (most recent call last):
+...
+ValidationError: [u'The Chilean RUT is not valid.']
+
+# Correct input, invalid format.
+>>> rut.clean('767484100')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
+>>> rut.clean('78.412.790-7')
+'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.']
+>>> rut.clean('76793310-K')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
+
"""