Index: django/contrib/localflavor/tr/tr_provinces.py
===================================================================
--- django/contrib/localflavor/tr/tr_provinces.py	(revision 0)
+++ django/contrib/localflavor/tr/tr_provinces.py	(revision 0)
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+"""
+This exists in this standalone file so that it's only imported into memory
+when explicitly needed.
+"""
+
+PROVINCE_CHOICES = (
+    ('01', ('Adana')),
+    ('02', ('Adıyaman')),
+    ('03', ('Afyonkarahisar')),
+    ('04', ('Ağrı')),
+    ('68', ('Aksaray')),
+    ('05', ('Amasya')),
+    ('06', ('Ankara')),
+    ('07', ('Antalya')),
+    ('75', ('Ardahan')),
+    ('08', ('Artvin')),
+    ('09', ('Aydın')),
+    ('10', ('Balıkesir')),
+    ('74', ('Bartın')),
+    ('72', ('Batman')),
+    ('69', ('Bayburt')),
+    ('11', ('Bilecik')),
+    ('12', ('Bingöl')),
+    ('13', ('Bitlis')),
+    ('14', ('Bolu')),
+    ('15', ('Burdur')),
+    ('16', ('Bursa')),
+    ('17', ('Çanakkale')),
+    ('18', ('Çankırı')),
+    ('19', ('Çorum')),
+    ('20', ('Denizli')),
+    ('21', ('Diyarbakır')),
+    ('81', ('Düzce')),
+    ('22', ('Edirne')),
+    ('23', ('Elazığ')),
+    ('24', ('Erzincan')),
+    ('25', ('Erzurum')),
+    ('26', ('Eskişehir')),
+    ('27', ('Gaziantep')),
+    ('28', ('Giresun')),
+    ('29', ('Gümüşhane')),
+    ('30', ('Hakkari')),
+    ('31', ('Hatay')),
+    ('76', ('Iğdır')),
+    ('32', ('Isparta')),
+    ('33', ('Mersin')),
+    ('34', ('İstanbul')),
+    ('35', ('İzmir')),
+    ('78', ('Karabük')),
+    ('36', ('Kars')),
+    ('37', ('Kastamonu')),
+    ('38', ('Kayseri')),
+    ('39', ('Kırklareli')),
+    ('40', ('Kırşehir')),
+    ('41', ('Kocaeli')),
+    ('42', ('Konya')),
+    ('43', ('Kütahya')),
+    ('44', ('Malatya')),
+    ('45', ('Manisa')),
+    ('46', ('Kahramanmaraş')),
+    ('70', ('Karaman')),
+    ('71', ('Kırıkkale')),
+    ('79', ('Kilis')),
+    ('47', ('Mardin')),
+    ('48', ('Muğla')),
+    ('49', ('Muş')),
+    ('50', ('Nevşehir')),
+    ('51', ('Niğde')),
+    ('52', ('Ordu')),
+    ('80', ('Osmaniye')),
+    ('53', ('Rize')),
+    ('54', ('Sakarya')),
+    ('55', ('Samsun')),
+    ('56', ('Siirt')),
+    ('57', ('Sinop')),
+    ('58', ('Sivas')),
+    ('73', ('Şırnak')),
+    ('59', ('Tekirdağ')),
+    ('60', ('Tokat')),
+    ('61', ('Trabzon')),
+    ('62', ('Tunceli')),
+    ('63', ('Şanlıurfa')),
+    ('64', ('Uşak')),
+    ('65', ('Van')),
+    ('77', ('Yalova')),
+    ('66', ('Yozgat')),
+    ('67', ('Zonguldak')),
+)

Index: django/contrib/localflavor/tr/__init__.py
===================================================================


Index: django/contrib/localflavor/tr/forms.py
===================================================================
--- django/contrib/localflavor/tr/forms.py	(revision 0)
+++ django/contrib/localflavor/tr/forms.py	(revision 0)
@@ -0,0 +1,91 @@
+"""
+TR-specific Form helpers
+"""
+
+from django.core.validators import EMPTY_VALUES
+from django.forms import ValidationError
+from django.forms.fields import Field, RegexField, Select, CharField
+from django.utils.encoding import smart_unicode
+from django.utils.translation import ugettext_lazy as _
+import re
+
+phone_digits_re = re.compile(r'^(\+90|0)? ?(([1-9]\d{2})|\([1-9]\d{2}\)) ?([2-9]\d{2} ?\d{2} ?\d{2})$')
+
+class TRPostalCodeField(RegexField):
+    default_error_messages = {
+        'invalid': _(u'Enter a postal code in the format XXXXX.'),
+    }
+
+    def __init__(self, *args, **kwargs):
+        super(TRPostalCodeField, self).__init__(r'^\d{5}$',
+            max_length=5, min_length=5, *args, **kwargs)
+
+    def clean(self, value):
+        value = super(TRPostalCodeField, self).clean(value)
+        if value in EMPTY_VALUES:
+            return u''
+        if len(value) != 5:
+            raise ValidationError(self.error_messages['invalid'])
+        province_code = int(value[:2])
+        if province_code == 0 or province_code > 81:
+            raise ValidationError(self.error_messages['invalid'])
+        return value
+
+
+class TRPhoneNumberField(CharField):
+    default_error_messages = {
+        'invalid': _(u'Phone numbers must be in 0XXX XXX XXXX format.'),
+    }
+
+    def clean(self, value):
+        super(TRPhoneNumberField, 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' % (m.group(2), m.group(4))
+        raise ValidationError(self.error_messages['invalid'])
+
+class TRIdentificationNumberField(Field):
+    """
+    A Turkey Identification Number number.
+	See: http://tr.wikipedia.org/wiki/T%C3%BCrkiye_Cumhuriyeti_Kimlik_Numaras%C4%B1
+
+    Checks the following rules to determine whether the number is valid:
+
+        * The number is 11-digits.
+        * First digit is not 0.
+        * Conforms to the following two formula:
+          (sum(1st, 3rd, 5th, 7th, 9th)*7 - sum(2nd,4th,6th,8th)) % 10 = 10th digit
+          sum(1st to 10th) % 10 = 11th digit
+    """
+    default_error_messages = {
+        'invalid': _(u'Enter a valid Turkish Identification number.'),
+        'not_11': _(u'Turkish Identification number must be 11 digits.'),
+    }
+
+    def clean(self, value):
+        super(TRIdentificationNumberField, self).clean(value)
+        if value in EMPTY_VALUES:
+            return u''
+        if len(value) != 11:
+            raise ValidationError(self.error_messages['not_11'])
+        if not re.match(r'^\d{11}$', value):
+            raise ValidationError(self.error_messages['invalid'])
+        if int(value[0]) == 0:
+            raise ValidationError(self.error_messages['invalid'])
+        chksum = (sum([int(value[i]) for i in xrange(0,9,2)])*7-
+				          sum([int(value[i]) for i in xrange(1,9,2)])) % 10
+        if chksum != int(value[9]) or \
+           (sum([int(value[i]) for i in xrange(10)]) % 10) != int(value[10]):
+            raise ValidationError(self.error_messages['invalid'])
+        return value
+
+class TRProvinceSelect(Select):
+    """
+    A Select widget that uses a list of provinces in Turkey as its choices.
+    """
+    def __init__(self, attrs=None):
+        from tr_provinces import PROVINCE_CHOICES
+        super(TRProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES)

Index: tests/regressiontests/forms/tests.py
===================================================================
--- tests/regressiontests/forms/tests.py	(revision 14405)
+++ tests/regressiontests/forms/tests.py	(working copy)
@@ -28,6 +28,7 @@
 from localflavor.ro import tests as localflavor_ro_tests
 from localflavor.se import tests as localflavor_se_tests
 from localflavor.sk import tests as localflavor_sk_tests
+from localflavor.tr import TurkeyLocalFlavorTests
 from localflavor.uk import tests as localflavor_uk_tests
 from localflavor.us import tests as localflavor_us_tests
 from localflavor.uy import tests as localflavor_uy_tests

Index: tests/regressiontests/forms/localflavor/tr.py
===================================================================
--- tests/regressiontests/forms/localflavor/tr.py	(revision 0)
+++ tests/regressiontests/forms/localflavor/tr.py	(revision 0)
@@ -0,0 +1,73 @@
+# Tests for the contrib/localflavor/ TR form fields.
+
+from django.contrib.localflavor.tr import forms as trforms
+from django.core.exceptions import ValidationError
+from django.utils.unittest import TestCase
+
+class TurkeyLocalFlavorTests(TestCase):
+    def testTRPostalCodeField(self):
+        f = trforms.TRPostalCodeField()
+        self.assertEqual(f.clean("06531"), "06531")
+        self.assertEqual(f.clean("12345"), "12345")
+        self.assertRaisesRegexp(ValidationError,
+            "Enter a postal code in the format XXXXX.",
+            f.clean, "a1234")
+        self.assertRaisesRegexp(ValidationError,
+            "Enter a postal code in the format XXXXX.",
+            f.clean, "1234")
+        self.assertRaisesRegexp(ValidationError,
+            "Enter a postal code in the format XXXXX.",
+            f.clean, "82123")
+        self.assertRaisesRegexp(ValidationError,
+            "Enter a postal code in the format XXXXX.",
+            f.clean, "00123")
+        self.assertRaisesRegexp(ValidationError,
+            "Enter a postal code in the format XXXXX.",
+            f.clean, "123456")
+        self.assertRaisesRegexp(ValidationError,
+            "Enter a postal code in the format XXXXX.",
+            f.clean, "12 34")
+        self.assertRaises(ValidationError, f.clean, None)
+
+    def testTRPhoneNumberField(self):
+        f = trforms.TRPhoneNumberField()
+        self.assertEqual(f.clean("312 455 56 78"), "3124555678")
+        self.assertEqual(f.clean("312 4555678"), "3124555678")
+        self.assertEqual(f.clean("3124555678"), "3124555678")
+        self.assertEqual(f.clean("0312 455 5678"), "3124555678")
+        self.assertEqual(f.clean("0 312 455 5678"), "3124555678")
+        self.assertEqual(f.clean("0 (312) 455 5678"), "3124555678")
+        self.assertEqual(f.clean("+90 312 455 4567"), "3124554567")
+        self.assertEqual(f.clean("+90 312 455 45 67"), "3124554567")
+        self.assertEqual(f.clean("+90 (312) 4554567"), "3124554567")
+        self.assertRaisesRegexp(ValidationError,
+            'Phone numbers must be in 0XXX XXX XXXX format.',
+            f.clean, "1234 233 1234")
+        self.assertRaisesRegexp(ValidationError,
+            'Phone numbers must be in 0XXX XXX XXXX format.',
+            f.clean, "0312 233 12345")
+        self.assertRaisesRegexp(ValidationError,
+            'Phone numbers must be in 0XXX XXX XXXX format.',
+            f.clean, "0312 233 123")
+        self.assertRaisesRegexp(ValidationError,
+            'Phone numbers must be in 0XXX XXX XXXX format.',
+            f.clean, "0312 233 xxxx")
+
+    def testTRIdentificationNumberField(self):
+        f = trforms.TRIdentificationNumberField()
+        self.assertEqual(f.clean("10000000146"), "10000000146")
+        self.assertRaisesRegexp(ValidationError,
+            'Enter a valid Turkish Identification number.',
+            f.clean, "10000000136")
+        self.assertRaisesRegexp(ValidationError,
+            'Enter a valid Turkish Identification number.',
+            f.clean, "10000000147")
+        self.assertRaisesRegexp(ValidationError,
+            'Turkish Identification number must be 11 digits.',
+            f.clean, "123456789")
+        self.assertRaisesRegexp(ValidationError,
+            'Enter a valid Turkish Identification number.',
+            f.clean, "1000000014x")
+        self.assertRaisesRegexp(ValidationError,
+            'Enter a valid Turkish Identification number.',
+            f.clean, "x0000000146")
