diff --git a/django/contrib/localflavor/is_/__init__.py b/django/contrib/localflavor/is_/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/django/contrib/localflavor/is_/forms.py b/django/contrib/localflavor/is_/forms.py
new file mode 100644
index 00000000000..3ee2d76937e
--- /dev/null
+++ b/django/contrib/localflavor/is_/forms.py
@@ -0,0 +1,81 @@
+"""
+Iceland specific form helpers.
+"""
+from django.newforms import ValidationError
+from django.newforms.fields import RegexField, EMPTY_VALUES
+from django.newforms.widgets import Select
+from django.utils.translation import gettext
+
+
+class ISIdNumberField(RegexField):
+ """
+ Icelandic identification number (kennitala). This is a number every citizen
+ of Iceland has.
+ """
+ def __init__(self, *args, **kwargs):
+ error_msg = gettext(u'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)
+
+ def clean(self, value):
+ value = super(ISIdNumberField, self).clean(value)
+
+ if value in EMPTY_VALUES:
+ return u''
+
+ value = self._canonify(value)
+ if self._validate(value):
+ return self._format(value)
+ else:
+ raise ValidationError(gettext(u'The Icelandic identification number is not valid.'))
+
+
+ def _canonify(self, value):
+ """
+ Returns the value as only digits.
+ """
+ return value.replace('-', '').replace(' ', '')
+
+ def _validate(self, value):
+ """
+ Takes in the value in canonical form and checks the verifier digit. The
+ method is modulo 11.
+ """
+ check = [3, 2, 7, 6, 5, 4, 3, 2, 1, 0]
+ return sum(int(value[i]) * check[i] for i in range(10)) % 11 == 0
+
+ def _format(self, value):
+ """
+ Takes in the value in canonical form and returns it in the common
+ display format.
+ """
+ return value[:6]+'-'+value[6:]
+
+
+class ISPhoneNumberField(RegexField):
+ """
+ Icelandic phone number. Seven digits with an optional hyphen or space after
+ the first three digits.
+ """
+ def __init__(self, *args, **kwargs):
+ kwargs['min_length'], kwargs['max_length'] = 7,8
+ super(ISPhoneNumberField, self).__init__(r'^\d{3}(-| )?\d{4}$', *args, **kwargs)
+
+ def clean(self, value):
+ value = super(ISPhoneNumberField, self).clean(value)
+
+ if value in EMPTY_VALUES:
+ return u''
+
+ return value.replace('-', '').replace(' ', '')
+
+
+class ISPostalCodeSelect(Select):
+ """
+ A Select widget that uses a list of Icelandic postal codes as its choices.
+ """
+ def __init__(self, attrs=None):
+ from is_postalcodes import IS_POSTALCODES
+ super(ISPostalCodeSelect, self).__init__(attrs, choices=IS_POSTALCODES)
+
diff --git a/django/contrib/localflavor/is_/is_postalcodes.py b/django/contrib/localflavor/is_/is_postalcodes.py
new file mode 100644
index 00000000000..4feca9c0131
--- /dev/null
+++ b/django/contrib/localflavor/is_/is_postalcodes.py
@@ -0,0 +1,151 @@
+# -*- coding: utf-8 -*-
+
+IS_POSTALCODES = (
+ ('101', u'101 Reykjavík'),
+ ('103', u'103 Reykjavík'),
+ ('104', u'104 Reykjavík'),
+ ('105', u'105 Reykjavík'),
+ ('107', u'107 Reykjavík'),
+ ('108', u'108 Reykjavík'),
+ ('109', u'109 Reykjavík'),
+ ('110', u'110 Reykjavík'),
+ ('111', u'111 Reykjavík'),
+ ('112', u'112 Reykjavík'),
+ ('113', u'113 Reykjavík'),
+ ('116', u'116 Kjalarnes'),
+ ('121', u'121 Reykjavík'),
+ ('123', u'123 Reykjavík'),
+ ('124', u'124 Reykjavík'),
+ ('125', u'125 Reykjavík'),
+ ('127', u'127 Reykjavík'),
+ ('128', u'128 Reykjavík'),
+ ('129', u'129 Reykjavík'),
+ ('130', u'130 Reykjavík'),
+ ('132', u'132 Reykjavík'),
+ ('150', u'150 Reykjavík'),
+ ('155', u'155 Reykjavík'),
+ ('170', u'170 Seltjarnarnes'),
+ ('172', u'172 Seltjarnarnes'),
+ ('190', u'190 Vogar'),
+ ('200', u'200 Kópavogur'),
+ ('201', u'201 Kópavogur'),
+ ('202', u'202 Kópavogur'),
+ ('203', u'203 Kópavogur'),
+ ('210', u'210 Garðabær'),
+ ('212', u'212 Garðabær'),
+ ('220', u'220 Hafnarfjörður'),
+ ('221', u'221 Hafnarfjörður'),
+ ('222', u'222 Hafnarfjörður'),
+ ('225', u'225 Álftanes'),
+ ('230', u'230 Reykjanesbær'),
+ ('232', u'232 Reykjanesbær'),
+ ('233', u'233 Reykjanesbær'),
+ ('235', u'235 Keflavíkurflugvöllur'),
+ ('240', u'240 Grindavík'),
+ ('245', u'245 Sandgerði'),
+ ('250', u'250 Garður'),
+ ('260', u'260 Reykjanesbær'),
+ ('270', u'270 Mosfellsbær'),
+ ('300', u'300 Akranes'),
+ ('301', u'301 Akranes'),
+ ('302', u'302 Akranes'),
+ ('310', u'310 Borgarnes'),
+ ('311', u'311 Borgarnes'),
+ ('320', u'320 Reykholt í Borgarfirði'),
+ ('340', u'340 Stykkishólmur'),
+ ('345', u'345 Flatey á Breiðafirði'),
+ ('350', u'350 Grundarfjörður'),
+ ('355', u'355 Ólafsvík'),
+ ('356', u'356 Snæfellsbær'),
+ ('360', u'360 Hellissandur'),
+ ('370', u'370 Búðardalur'),
+ ('371', u'371 Búðardalur'),
+ ('380', u'380 Reykhólahreppur'),
+ ('400', u'400 Ísafjörður'),
+ ('401', u'401 Ísafjörður'),
+ ('410', u'410 Hnífsdalur'),
+ ('415', u'415 Bolungarvík'),
+ ('420', u'420 Súðavík'),
+ ('425', u'425 Flateyri'),
+ ('430', u'430 Suðureyri'),
+ ('450', u'450 Patreksfjörður'),
+ ('451', u'451 Patreksfjörður'),
+ ('460', u'460 Tálknafjörður'),
+ ('465', u'465 Bíldudalur'),
+ ('470', u'470 Þingeyri'),
+ ('471', u'471 Þingeyri'),
+ ('500', u'500 Staður'),
+ ('510', u'510 Hólmavík'),
+ ('512', u'512 Hólmavík'),
+ ('520', u'520 Drangsnes'),
+ ('522', u'522 Kjörvogur'),
+ ('523', u'523 Bær'),
+ ('524', u'524 Norðurfjörður'),
+ ('530', u'530 Hvammstangi'),
+ ('531', u'531 Hvammstangi'),
+ ('540', u'540 Blönduós'),
+ ('541', u'541 Blönduós'),
+ ('545', u'545 Skagaströnd'),
+ ('550', u'550 Sauðárkrókur'),
+ ('551', u'551 Sauðárkrókur'),
+ ('560', u'560 Varmahlíð'),
+ ('565', u'565 Hofsós'),
+ ('566', u'566 Hofsós'),
+ ('570', u'570 Fljót'),
+ ('580', u'580 Siglufjörður'),
+ ('600', u'600 Akureyri'),
+ ('601', u'601 Akureyri'),
+ ('602', u'602 Akureyri'),
+ ('603', u'603 Akureyri'),
+ ('610', u'610 Grenivík'),
+ ('611', u'611 Grímsey'),
+ ('620', u'620 Dalvík'),
+ ('621', u'621 Dalvík'),
+ ('625', u'625 Ólafsfjörður'),
+ ('630', u'630 Hrísey'),
+ ('640', u'640 Húsavík'),
+ ('641', u'641 Húsavík'),
+ ('645', u'645 Fosshóll'),
+ ('650', u'650 Laugar'),
+ ('660', u'660 Mývatn'),
+ ('670', u'670 Kópasker'),
+ ('671', u'671 Kópasker'),
+ ('675', u'675 Raufarhöfn'),
+ ('680', u'680 Þórshöfn'),
+ ('681', u'681 Þórshöfn'),
+ ('685', u'685 Bakkafjörður'),
+ ('690', u'690 Vopnafjörður'),
+ ('700', u'700 Egilsstaðir'),
+ ('701', u'701 Egilsstaðir'),
+ ('710', u'710 Seyðisfjörður'),
+ ('715', u'715 Mjóifjörður'),
+ ('720', u'720 Borgarfjörður eystri'),
+ ('730', u'730 Reyðarfjörður'),
+ ('735', u'735 Eskifjörður'),
+ ('740', u'740 Neskaupstaður'),
+ ('750', u'750 Fáskrúðsfjörður'),
+ ('755', u'755 Stöðvarfjörður'),
+ ('760', u'760 Breiðdalsvík'),
+ ('765', u'765 Djúpivogur'),
+ ('780', u'780 Höfn í Hornafirði'),
+ ('781', u'781 Höfn í Hornafirði'),
+ ('785', u'785 Öræfi'),
+ ('800', u'800 Selfoss'),
+ ('801', u'801 Selfoss'),
+ ('802', u'802 Selfoss'),
+ ('810', u'810 Hveragerði'),
+ ('815', u'815 Þorlákshöfn'),
+ ('820', u'820 Eyrarbakki'),
+ ('825', u'825 Stokkseyri'),
+ ('840', u'840 Laugarvatn'),
+ ('845', u'845 Flúðir'),
+ ('850', u'850 Hella'),
+ ('851', u'851 Hella'),
+ ('860', u'860 Hvolsvöllur'),
+ ('861', u'861 Hvolsvöllur'),
+ ('870', u'870 Vík'),
+ ('871', u'871 Vík'),
+ ('880', u'880 Kirkjubæjarklaustur'),
+ ('900', u'900 Vestmannaeyjar'),
+ ('902', u'902 Vestmannaeyjar')
+)
diff --git a/tests/regressiontests/forms/localflavor.py b/tests/regressiontests/forms/localflavor.py
index 3f4f41ae8d4..e88228f2524 100644
--- a/tests/regressiontests/forms/localflavor.py
+++ b/tests/regressiontests/forms/localflavor.py
@@ -1052,4 +1052,102 @@ states/territories as its choices.
+
+## ISIdNumberField #############################################################
+
+>>> from django.contrib.localflavor.is_.forms import *
+>>> f = ISIdNumberField()
+>>> f.clean('2308803449')
+u'230880-3449'
+>>> f.clean('230880-3449')
+u'230880-3449'
+>>> f.clean('230880 3449')
+u'230880-3449'
+>>> f.clean('230880343')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 10 characters.']
+>>> f.clean('230880343234')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 11 characters.']
+>>> f.clean('abcdefghijk')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('2308803439')
+Traceback (most recent call last):
+...
+ValidationError: [u'The Icelandic identification number is not valid.']
+>>> f.clean('2308803440')
+u'230880-3440'
+>>> f = ISIdNumberField(required=False)
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+
+## ISPhoneNumberField #############################################################
+
+>>> from django.contrib.localflavor.is_.forms import *
+>>> f = ISPhoneNumberField()
+>>> f.clean('1234567')
+u'1234567'
+>>> f.clean('123 4567')
+u'1234567'
+>>> f.clean('123-4567')
+u'1234567'
+>>> f.clean('123-456')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid value.']
+>>> f.clean('123456')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 7 characters.']
+>>> f.clean('123456555')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 8 characters.']
+>>> f.clean('abcdefg')
+Traceback (most recent call last):
+ValidationError: [u'Enter a valid value.']
+>>> f.clean(' 1234567 ')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 8 characters.']
+>>> f.clean(' 12367 ')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid value.']
+
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f = ISPhoneNumberField(required=False)
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+
+## ISPostalCodeSelect #############################################################
+
+>>> from django.contrib.localflavor.is_.forms import *
+>>> f = ISPostalCodeSelect()
+
+>>> f.render('foo', 'bar')
+u''
"""