Index: django/contrib/localflavor/cl/forms.py
===================================================================
--- django/contrib/localflavor/cl/forms.py	(revision 16714)
+++ django/contrib/localflavor/cl/forms.py	(working copy)
@@ -4,11 +4,14 @@
 
 from django.core.validators import EMPTY_VALUES
 from django.forms import ValidationError
-from django.forms.fields import RegexField, Select
+from django.forms.fields import RegexField, Select, CharField
 from django.utils.translation import ugettext_lazy as _
 from django.utils.encoding import smart_unicode
 
+OLD_CAR_PLATE_STYLE = 0
+NEW_CAR_PLATE_STYLE = 1
 
+
 class CLRegionSelect(Select):
     """
     A Select widget that uses a list of Chilean Regions (Regiones)
@@ -93,3 +96,82 @@
             code = code[:new_dot] + '.' + code[new_dot:]
         return u'%s-%s' % (code, verifier)
 
+
+class CLPatenteField(CharField):
+    """
+    Chilean "Patente", Placa Patente Field, support old LL-NNNN and new LLLL-NN
+    type, where L in new can't be vowel or m,n and q.
+    """
+    default_error_messages = {
+        'invalid': _("Enter a valid Chilean Car Plate."),
+    }
+
+    def __init__(self, *args, **kwargs):
+        kwargs['max_length'] = 7
+        kwargs['min_length'] = 6
+        if not kwargs.has_key('label'):
+            kwargs['label'] = _("Car plate")
+        if not kwargs.has_key('help_text'):
+            kwargs['help_text'] = _("Chilean car plate as LL-NNNN or LLLL-NN")
+
+        super(CLPatenteField, self).__init__(*args, **kwargs)
+
+    def clean(self, value):
+        """
+        Check and clean the field for length and type.
+        """
+        super(CLPatenteField, self).clean(value)
+
+        if value in EMPTY_VALUES:
+            return u''
+
+        value = smart_unicode(value.lower())
+        value_length = len(value)
+
+        if self.max_length is not None and value_length > self.max_length:
+            raise ValidationError(self.error_messages['max_length'] % {'max': self.max_length, 'length': value_length})
+        if self.min_length is not None and value_length < self.min_length:
+            raise ValidationError(self.error_messages['min_length'] % {'min': self.min_length, 'length': value_length})
+
+        value = self._canonify(value)
+        _type = self._algorithm(value)
+
+        if _type not in (OLD_CAR_PLATE_STYLE, NEW_CAR_PLATE_STYLE):
+            raise ValidationError(self.error_messages['invalid'])
+
+        return self._format(value.upper(), _type)
+
+    def _algorithm(self, value):
+        """
+        Takes Car Plate in canonical form and verify if it is valid.
+        Returns the type or None if it is not valid.
+        """
+        import re
+        # Old card plate patern
+        op = '^[a-z]{2,2}\d{4,4}$'
+        op = re.compile(op)
+        # New card plate patern
+        np = '^[bcdfghjklprstvwxyz]{4,4}\d{2,2}$'
+        np = re.compile(np)
+        if re.search(op, value):
+            return OLD_CAR_PLATE_STYLE
+        elif re.search(np, value):
+            return NEW_CAR_PLATE_STYLE
+        else:
+            return None
+
+    def _canonify(self, patente):
+        """
+        Turns the Car Plate into one normalized format.
+        """
+        return patente.replace(' ', '').replace('-', '')
+
+    def _format(self, value, _type):
+        """
+        Formats the Car Plate from canonical form to the common string
+        representation. LL-DDDD or LLLL-DD
+        """
+        if _type == OLD_CAR_PLATE_STYLE:
+            return u'-'.join((value[:2], value[2:]))
+        if _type == NEW_CAR_PLATE_STYLE:
+            return u'-'.join((value[:4], value[4:]))
Index: tests/regressiontests/localflavor/cl/tests.py
===================================================================
--- tests/regressiontests/localflavor/cl/tests.py	(revision 16714)
+++ tests/regressiontests/localflavor/cl/tests.py	(working copy)
@@ -1,5 +1,8 @@
-from django.contrib.localflavor.cl.forms import CLRutField, CLRegionSelect
+from django.contrib.localflavor.cl.forms import CLRutField, CLRegionSelect, CLPatenteField
 
+from django.core.validators import MinLengthValidator, MaxLengthValidator
+
+
 from django.test import SimpleTestCase
 
 
@@ -54,3 +57,51 @@
         self.assertFieldOutput(CLRutField,
             {}, invalid, field_kwargs={"strict": True}
         )
+
+    def test_CLPatente(self):
+        """ Tests that the field validates input"""
+        invalid_min_length_data = 'p'
+        invalid_max_length_data = 'pcpcpcpc'
+
+        error_invalid =  [CLPatenteField().default_error_messages['invalid']]
+
+        error_min_length = [MinLengthValidator.message % {'limit_value': CLPatenteField().min_length, 'show_value' :len(invalid_min_length_data)}]
+        error_max_length = [MaxLengthValidator.message % {'limit_value': CLPatenteField().max_length, 'show_value' :len(invalid_max_length_data)}]
+
+        valid = {
+        # Valid new style
+            'rrwr56': 'RRWR-56',
+            'rrwr-56': 'RRWR-56',
+        # Valid old style
+            'aa6056': 'AA-6056',
+            'aa-6056':'AA-6056'
+        }
+        invalid = {
+            invalid_min_length_data: error_min_length,
+            invalid_max_length_data: error_max_length,
+            'ppppcpc': error_invalid,
+            'cpcpcp': error_invalid,
+            'cpcpc0': error_invalid,
+            'cpc606': error_invalid,
+            'c60606': error_invalid,
+            '606060': error_invalid,
+            # Can't contain 'm'
+            'mttt12': error_invalid,
+            # Can't contain 'n'
+            'nttt34': error_invalid,
+            # Can't contain 'q'
+            'qttt56': error_invalid,
+            # Can't contain vowel
+            # 'a'
+            'attt67': error_invalid,
+            # 'e'
+            'ettt67': error_invalid,
+            # 'i'
+            'ittt89': error_invalid,
+            # 'o'
+            'ottt01': error_invalid,
+            # 'u'
+            'uttt23': error_invalid
+        }
+
+        self.assertFieldOutput(CLPatenteField, valid, invalid)
