Index: django/contrib/localflavor/at/__init__.py
===================================================================
Index: django/contrib/localflavor/at/forms.py
===================================================================
--- django/contrib/localflavor/at/forms.py	(revision 0)
+++ django/contrib/localflavor/at/forms.py	(revision 0)
@@ -0,0 +1,28 @@
+"""
+AT-specific Form helpers
+"""
+
+from django.utils.translation import ugettext_lazy as _
+from django.newforms.fields import Field, RegexField, Select
+import re
+
+class ATZipCodeField(RegexField):
+    """
+    A form field that validates its input is a Austrian postcode.
+    
+    Accepts 4 digits
+    """
+    default_error_messages = {
+        'invalid': _('Enter a zip code in the format XXXX.'),
+    }
+    def __init__(self, *args, **kwargs):
+        super(ATZipCodeField, self).__init__(r'^\d{4}$',
+            max_length=None, min_length=None, *args, **kwargs)
+
+class ATStateSelect(Select):
+    """
+    A Select widget that uses a list of AT states as its choices.
+    """
+    def __init__(self, attrs=None):
+        from at_states import STATE_CHOICES
+        super(ATStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
\ No newline at end of file
Index: django/contrib/localflavor/at/at_states.py
===================================================================
--- django/contrib/localflavor/at/at_states.py	(revision 0)
+++ django/contrib/localflavor/at/at_states.py	(revision 0)
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*
+from django.utils.translation import ugettext_lazy as _
+
+STATE_CHOICES = (
+    ('BL', _('Burgenland')),
+    ('KA', _('Carinthia')),
+    ('NO', _('Lower Austria')),
+    ('OO', _('Upper Austria')),
+    ('SA', _('Salzburg')),
+    ('ST', _('Styria')),
+    ('TI', _('Tyrol')),
+    ('VO', _('Vorarlberg')),
+    ('WI', _('Vienna')),
+)
\ No newline at end of file
