diff --git a/AUTHORS b/AUTHORS
index 564cd0a139..027dbc39ba 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -181,6 +181,7 @@ answer newbie questions, and generally made Django that much better:
     Luke Plant 
     plisk
     Daniel Poelzleithner 
+    polpak@yahoo.com
     J. Rademaker
     Michael Radziej 
     ramiro
@@ -224,6 +225,7 @@ answer newbie questions, and generally made Django that much better:
     wam-djangobug@wamber.net
     Dan Watson 
     Chris Wesseling 
+    charly.wilhelm@gmail.com
     Rachel Willmer 
     Gary Wilson 
     wojtek
diff --git a/django/contrib/localflavor/ch/__init__.py b/django/contrib/localflavor/ch/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/django/contrib/localflavor/ch/ch_states.py b/django/contrib/localflavor/ch/ch_states.py
new file mode 100644
index 0000000000..e9bbcc6268
--- /dev/null
+++ b/django/contrib/localflavor/ch/ch_states.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*
+from django.utils.translation import gettext_lazy as _
+
+STATE_CHOICES = (
+    ('AG', _('Aargau')),
+    ('AI', _('Appenzell Innerrhoden')),
+    ('AR', _('Appenzell Ausserrhoden')),
+    ('BS', _('Basel-Stadt')),
+    ('BL', _('Basel-Land')),
+    ('BE', _('Berne')),
+    ('FR', _('Fribourg')),
+    ('GE', _('Geneva')),
+    ('GL', _('Glarus')),
+    ('GR', _('Graubuenden')),
+    ('JU', _('Jura')),
+    ('LU', _('Lucerne')),
+    ('NE', _('Neuchatel')),
+    ('NW', _('Nidwalden')),
+    ('OW', _('Obwalden')),
+    ('SH', _('Schaffhausen')),
+    ('SZ', _('Schwyz')),
+    ('SO', _('Solothurn')),
+    ('SG', _('St. Gallen')),
+    ('TG', _('Thurgau')),
+    ('TI', _('Ticino')),
+    ('UR', _('Uri')),
+    ('VS', _('Valais')),
+    ('VD', _('Vaud')),
+    ('ZG', _('Zug')),
+    ('ZH', _('Zurich'))
+)
diff --git a/django/contrib/localflavor/ch/forms.py b/django/contrib/localflavor/ch/forms.py
new file mode 100644
index 0000000000..51e52dc0e9
--- /dev/null
+++ b/django/contrib/localflavor/ch/forms.py
@@ -0,0 +1,109 @@
+"""
+Swiss-specific Form helpers
+"""
+
+from django.newforms import ValidationError
+from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
+from django.utils.encoding import smart_unicode
+from django.utils.translation import gettext
+import re
+
+id_re = re.compile(r"^(?P\w{8})(?P(\d{1}|<))(?P\d{1})$")
+phone_digits_re = re.compile(r'^0([1-9]{1})\d{8}$')
+
+class CHZipCodeField(RegexField):
+    def __init__(self, *args, **kwargs):
+        super(CHZipCodeField, self).__init__(r'^\d{4}$',
+        max_length=None, min_length=None,
+        error_message=gettext('Enter a zip code in the format XXXX.'),
+        *args, **kwargs)
+
+class CHPhoneNumberField(Field):
+    """
+    Validate local Swiss phone number (not international ones)
+    The correct format is '0XX XXX XX XX'.
+    '0XX.XXX.XX.XX' and '0XXXXXXXXX' validate but are corrected to
+    '0XX XXX XX XX'.
+    """
+    def clean(self, value):
+        super(CHPhoneNumberField, 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 %s %s' % (value[0:3], value[3:6], value[6:8], value[8:10])
+        raise ValidationError('Phone numbers must be in 0XX XXX XX XX format.')
+
+class CHStateSelect(Select):
+    """
+    A Select widget that uses a list of CH states as its choices.
+    """
+    def __init__(self, attrs=None):
+        from ch_states import STATE_CHOICES # relative import
+        super(CHStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
+
+class CHIdentityCardNumberField(Field):
+    """
+    A Swiss identity card number.
+
+    Checks the following rules to determine whether the number is valid:
+
+        * Conforms to the X1234567<0 or 1234567890 format.
+        * Included checksums match calculated checksums
+
+    Algorithm is documented at http://adi.kousz.ch/artikel/IDCHE.htm
+    """
+    def has_valid_checksum(self, number):
+        given_number, given_checksum = number[:-1], number[-1]
+        new_number = given_number
+        calculated_checksum = 0
+        fragment = ""
+        parameter = 7
+
+        first = str(number[:1])
+        if first.isalpha():
+            num = ord(first.upper()) - 65
+            if num < 0 or num > 8:
+                return False
+            new_number = str(num) + new_number[1:]
+            new_number = new_number[:8] + '0'
+
+        if not new_number.isdigit():
+            return False
+
+        for i in range(len(new_number)):
+          fragment = int(new_number[i])*parameter
+          calculated_checksum += fragment
+
+          if parameter == 1:
+            parameter = 7
+          elif parameter == 3:
+            parameter = 1
+          elif parameter ==7:
+            parameter = 3
+
+        return str(calculated_checksum)[-1] == given_checksum
+
+    def clean(self, value):
+        super(CHIdentityCardNumberField, self).clean(value)
+        error_msg = gettext('Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.')
+        if value in EMPTY_VALUES:
+            return u''
+
+        match = re.match(id_re, value)
+        if not match:
+            raise ValidationError(error_msg)
+
+        idnumber, pos9, checksum = match.groupdict()['idnumber'], match.groupdict()['pos9'], match.groupdict()['checksum']
+
+        if idnumber == '00000000' or \
+           idnumber == 'A0000000':
+            raise ValidationError(error_msg)
+
+        all_digits = "%s%s%s" % (idnumber, pos9, checksum)
+        if not self.has_valid_checksum(all_digits):
+            raise ValidationError(error_msg)
+
+        return u'%s%s%s' % (idnumber, pos9, checksum)
+
diff --git a/django/core/management.py b/django/core/management.py
index 4a08b1e54d..883cbe1ca7 100644
--- a/django/core/management.py
+++ b/django/core/management.py
@@ -598,6 +598,7 @@ def syncdb(verbosity=1, interactive=True):
     # Install custom SQL for the app (but only if this
     # is a model we've just created)
     for app in models.get_apps():
+        app_name = app.__name__.split('.')[-2]
         for model in models.get_models(app):
             if model in created_models:
                 custom_sql = get_custom_sql_for_model(model)
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index b78a3e9a70..f9aed8b98e 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -893,6 +893,12 @@ class USStateField(Field):
     def get_manipulator_field_objs(self):
         return [oldforms.USStateField]
 
+    def formfield(self, **kwargs):
+        from django.contrib.localflavor.us.forms import USStateSelect
+        defaults = {'widget': USStateSelect}
+        defaults.update(kwargs)
+        return super(USStateField, self).formfield(**defaults)
+
 class XMLField(TextField):
     def __init__(self, verbose_name=None, name=None, schema_path=None, **kwargs):
         self.schema_path = schema_path
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 142fee04c2..93dcdd1776 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -903,6 +903,13 @@ def find_field(name, field_list, related_query):
         return None
     return matches[0]
 
+def field_choices(field_list, related_query):
+    if related_query:
+        choices = [f.field.related_query_name() for f in field_list]
+    else:
+        choices = [f.name for f in field_list]
+    return choices
+
 def lookup_inner(path, lookup_type, value, opts, table, column):
     qn = backend.quote_name
     joins, where, params = SortedDict(), [], []
@@ -987,7 +994,11 @@ def lookup_inner(path, lookup_type, value, opts, table, column):
     except FieldFound: # Match found, loop has been shortcut.
         pass
     else: # No match found.
-        raise TypeError, "Cannot resolve keyword '%s' into field" % name
+        choices = field_choices(current_opts.many_to_many, False) + \
+            field_choices(current_opts.get_all_related_many_to_many_objects(), True) + \
+            field_choices(current_opts.get_all_related_objects(), True) + \
+            field_choices(current_opts.fields, False)
+        raise TypeError, "Cannot resolve keyword '%s' into field, choices are: %s" % (name, ", ".join(choices))
 
     # Check whether an intermediate join is required between current_table
     # and new_table.
diff --git a/docs/settings.txt b/docs/settings.txt
index 8cc400dfde..aae9a1da04 100644
--- a/docs/settings.txt
+++ b/docs/settings.txt
@@ -500,44 +500,17 @@ in standard language format. For example, U.S. English is ``"en-us"``. See the
 LANGUAGES
 ---------
 
-Default: A tuple of all available languages. Currently, this is::
+Default: A tuple of all available languages. This list is continually growing
+and including a copy here would inevitably become rapidly out of date. You can
+see the current list of translated languages by looking in
+``django/conf/global_settings.py`` (or view the `online source`_).
 
-    LANGUAGES = (
-        ('ar', _('Arabic')),
-        ('bn', _('Bengali')),
-        ('cs', _('Czech')),
-        ('cy', _('Welsh')),
-        ('da', _('Danish')),
-        ('de', _('German')),
-        ('el', _('Greek')),
-        ('en', _('English')),
-        ('es', _('Spanish')),
-        ('es_AR', _('Argentinean Spanish')),
-        ('fr', _('French')),
-        ('gl', _('Galician')),
-        ('hu', _('Hungarian')),
-        ('he', _('Hebrew')),
-        ('is', _('Icelandic')),
-        ('it', _('Italian')),
-        ('ja', _('Japanese')),
-        ('nl', _('Dutch')),
-        ('no', _('Norwegian')),
-        ('pt-br', _('Brazilian')),
-        ('ro', _('Romanian')),
-        ('ru', _('Russian')),
-        ('sk', _('Slovak')),
-        ('sl', _('Slovenian')),
-        ('sr', _('Serbian')),
-        ('sv', _('Swedish')),
-        ('ta', _('Tamil')),
-        ('uk', _('Ukrainian')),
-        ('zh-cn', _('Simplified Chinese')),
-        ('zh-tw', _('Traditional Chinese')),
-    )
+.. _online source: http://code.djangoproject.com/browser/django/trunk/django/conf/global_settings.py
 
-A tuple of two-tuples in the format (language code, language name). This
-specifies which languages are available for language selection. See the
-`internationalization docs`_ for details.
+The list is a tuple of two-tuples in the format (language code, language
+name) -- for example, ``('ja', 'Japanese')``. This specifies which languages
+are available for language selection. See the `internationalization docs`_ for
+details.
 
 Generally, the default value should suffice. Only set this setting if you want
 to restrict language selection to a subset of the Django-provided languages.
diff --git a/tests/modeltests/custom_columns/models.py b/tests/modeltests/custom_columns/models.py
index c09ca05557..b2b7261c89 100644
--- a/tests/modeltests/custom_columns/models.py
+++ b/tests/modeltests/custom_columns/models.py
@@ -71,7 +71,7 @@ __test__ = {'API_TESTS':"""
 >>> Author.objects.filter(firstname__exact='John')
 Traceback (most recent call last):
     ...
-TypeError: Cannot resolve keyword 'firstname' into field
+TypeError: Cannot resolve keyword 'firstname' into field, choices are: article, id, first_name, last_name
 
 >>> a = Author.objects.get(last_name__exact='Smith')
 >>> a.first_name
diff --git a/tests/modeltests/lookup/models.py b/tests/modeltests/lookup/models.py
index 106c97d3b4..c28f0e015f 100644
--- a/tests/modeltests/lookup/models.py
+++ b/tests/modeltests/lookup/models.py
@@ -223,11 +223,11 @@ DoesNotExist: Article matching query does not exist.
 >>> Article.objects.filter(pub_date_year='2005').count()
 Traceback (most recent call last):
     ...
-TypeError: Cannot resolve keyword 'pub_date_year' into field
+TypeError: Cannot resolve keyword 'pub_date_year' into field, choices are: id, headline, pub_date
 
 >>> Article.objects.filter(headline__starts='Article')
 Traceback (most recent call last):
     ...
-TypeError: Cannot resolve keyword 'headline__starts' into field
+TypeError: Cannot resolve keyword 'headline__starts' into field, choices are: id, headline, pub_date
 
 """}
diff --git a/tests/modeltests/many_to_one/models.py b/tests/modeltests/many_to_one/models.py
index 82eb3257d0..3ed449d598 100644
--- a/tests/modeltests/many_to_one/models.py
+++ b/tests/modeltests/many_to_one/models.py
@@ -174,13 +174,13 @@ False
 >>> Article.objects.filter(reporter_id__exact=1)
 Traceback (most recent call last):
     ...
-TypeError: Cannot resolve keyword 'reporter_id' into field
+TypeError: Cannot resolve keyword 'reporter_id' into field, choices are: id, headline, pub_date, reporter
 
 # You need to specify a comparison clause
 >>> Article.objects.filter(reporter_id=1)
 Traceback (most recent call last):
     ...
-TypeError: Cannot resolve keyword 'reporter_id' into field
+TypeError: Cannot resolve keyword 'reporter_id' into field, choices are: id, headline, pub_date, reporter
 
 # You can also instantiate an Article by passing
 # the Reporter's ID instead of a Reporter object.
diff --git a/tests/modeltests/reverse_lookup/models.py b/tests/modeltests/reverse_lookup/models.py
index 7e6712676f..d30269c5c6 100644
--- a/tests/modeltests/reverse_lookup/models.py
+++ b/tests/modeltests/reverse_lookup/models.py
@@ -55,5 +55,5 @@ __test__ = {'API_TESTS':"""
 >>> Poll.objects.get(choice__name__exact="This is the answer")
 Traceback (most recent call last):
     ...
-TypeError: Cannot resolve keyword 'choice' into field
+TypeError: Cannot resolve keyword 'choice' into field, choices are: poll_choice, related_choice, id, question, creator
 """}
diff --git a/tests/regressiontests/forms/localflavor.py b/tests/regressiontests/forms/localflavor.py
index f725fb38b7..ede89de2a0 100644
--- a/tests/regressiontests/forms/localflavor.py
+++ b/tests/regressiontests/forms/localflavor.py
@@ -1011,6 +1011,60 @@ Traceback (most recent call last):
 ...
 ValidationError: [u'Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.']
 
+# CHZipCodeField ############################################################
+
+>>> from django.contrib.localflavor.ch.forms import CHZipCodeField
+>>> f = CHZipCodeField()
+>>> f.clean('800x')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXX.']
+>>> f.clean('80 00')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXX.']
+>>> f.clean('8000')
+u'8000'
+
+# CHPhoneNumberField ########################################################
+
+>>> from django.contrib.localflavor.ch.forms import CHPhoneNumberField
+>>> f = CHPhoneNumberField()
+>>> f.clean('01234567890')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in 0XX XXX XX XX format.']
+>>> f.clean('1234567890')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in 0XX XXX XX XX format.']
+>>> f.clean('0123456789')
+u'012 345 67 89'
+
+# CHIdentityCardNumberField #################################################
+
+>>> from django.contrib.localflavor.ch.forms import CHIdentityCardNumberField
+>>> f = CHIdentityCardNumberField()
+>>> f.clean('C1234567<0')
+u'C1234567<0'
+>>> f.clean('C1234567<1')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.']
+>>> f.clean('2123456700')
+u'2123456700'
+>>> f.clean('2123456701')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.']
+
+# CHStateSelect #############################################################
+
+>>> from django.contrib.localflavor.ch.forms import CHStateSelect
+>>> w = CHStateSelect()
+>>> w.render('state', 'AG')
+u''
+
 ## AUPostCodeField ##########################################################
 
 A field that accepts a four digit Australian post code.
diff --git a/tests/regressiontests/null_queries/models.py b/tests/regressiontests/null_queries/models.py
index 09024f18c2..4396ab4005 100644
--- a/tests/regressiontests/null_queries/models.py
+++ b/tests/regressiontests/null_queries/models.py
@@ -32,7 +32,7 @@ __test__ = {'API_TESTS':"""
 >>> Choice.objects.filter(foo__exact=None) 
 Traceback (most recent call last):
 ...
-TypeError: Cannot resolve keyword 'foo' into field
+TypeError: Cannot resolve keyword 'foo' into field, choices are: id, poll, choice
 
 # Can't use None on anything other than __exact
 >>> Choice.objects.filter(id__gt=None)