Index: django/conf/global_settings.py
===================================================================
--- django/conf/global_settings.py	(.../trunk)	(revision 11464)
+++ django/conf/global_settings.py	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -1,3 +1,4 @@
+# -*- encoding: utf-8 -*-
 # Default Django settings. Override these with settings in the module
 # pointed-to by the DJANGO_SETTINGS_MODULE environment variable.
 
@@ -75,7 +76,7 @@
     ('lt', gettext_noop('Lithuanian')),
     ('mk', gettext_noop('Macedonian')),
     ('nl', gettext_noop('Dutch')),
-    ('no', gettext_noop('Norwegian')),
+    ('nb', gettext_noop(u'Norwegian Bokmål')),
     ('pl', gettext_noop('Polish')),
     ('pt', gettext_noop('Portuguese')),
     ('pt-br', gettext_noop('Brazilian Portuguese')),
@@ -103,6 +104,10 @@
 LOCALE_PATHS = ()
 LANGUAGE_COOKIE_NAME = 'django_language'
 
+# If you set this to True, Django will format dates, numbers and calendars
+# according to user current locale
+USE_FORMAT_I18N = False
+
 # Not-necessarily-technical managers of the site. They get broken link
 # notifications and other various e-mails.
 MANAGERS = ADMINS
@@ -255,6 +260,12 @@
 # you'd pass directly to os.chmod; see http://docs.python.org/lib/os-file-dir.html.
 FILE_UPLOAD_PERMISSIONS = None
 
+# Python module path where user will place custom format definition.
+# The directory where this setting is pointing should contain subdirectories
+# named as the locales, containing a formats.py file
+# (i.e. "myproject.locale" for myproject/locale/en/formats.py etc. use)
+FORMAT_MODULE_PATH = None
+
 # Default formatting for date objects. See all available format strings here:
 # http://docs.djangoproject.com/en/dev/ref/templates/builtins/#now
 DATE_FORMAT = 'N j, Y'
@@ -277,6 +288,72 @@
 # http://docs.djangoproject.com/en/dev/ref/templates/builtins/#now
 MONTH_DAY_FORMAT = 'F j'
 
+# Default shortformatting for date objects. See all available format strings here:
+# http://docs.djangoproject.com/en/dev/ref/templates/builtins/#now
+SHORT_DATE_FORMAT = 'm/d/Y'
+
+# Default short formatting for datetime objects.
+# See all available format strings here:
+# http://docs.djangoproject.com/en/dev/ref/templates/builtins/#now
+SHORT_DATETIME_FORMAT = 'm/d/Y P'
+
+# Default formats tried to parse dates from input boxes
+# These formats are tried in the specified order
+# See all available format string here:
+# http://docs.python.org/library/datetime.html#strftime-behavior
+# * Note that these format strings are different from the ones to display dates
+DATE_INPUT_FORMATS = (
+    '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06'
+    '%b %d %Y', '%b %d, %Y',            # 'Oct 25 2006', 'Oct 25, 2006'
+    '%d %b %Y', '%d %b, %Y',            # '25 Oct 2006', '25 Oct, 2006'
+    '%B %d %Y', '%B %d, %Y',            # 'October 25 2006', 'October 25, 2006'
+    '%d %B %Y', '%d %B, %Y',            # '25 October 2006', '25 October, 2006'
+)
+
+# Default formats tried to parse times from input boxes
+# These formats are tried in the specified order
+# See all available format string here:
+# http://docs.python.org/library/datetime.html#strftime-behavior
+# * Note that these format strings are different from the ones to display dates
+TIME_INPUT_FORMATS = (
+    '%H:%M:%S',     # '14:30:59'
+    '%H:%M',        # '14:30'
+)
+
+# Default formats tried to parse dates and times from input boxes
+# These formats are tried in the specified order
+# See all available format string here:
+# http://docs.python.org/library/datetime.html#strftime-behavior
+# * Note that these format strings are different from the ones to display dates
+DATETIME_INPUT_FORMATS = (
+    '%Y-%m-%d %H:%M:%S',     # '2006-10-25 14:30:59'
+    '%Y-%m-%d %H:%M',        # '2006-10-25 14:30'
+    '%Y-%m-%d',              # '2006-10-25'
+    '%m/%d/%Y %H:%M:%S',     # '10/25/2006 14:30:59'
+    '%m/%d/%Y %H:%M',        # '10/25/2006 14:30'
+    '%m/%d/%Y',              # '10/25/2006'
+    '%m/%d/%y %H:%M:%S',     # '10/25/06 14:30:59'
+    '%m/%d/%y %H:%M',        # '10/25/06 14:30'
+    '%m/%d/%y',              # '10/25/06'
+)
+
+# First day of week, to be used on calendars
+# 0 means Sunday, 1 means Monday...
+FIRST_DAY_OF_WEEK = 0
+
+# Decimal separator symbol
+DECIMAL_SEPARATOR = '.'
+
+# Boolean that sets whether to add thousand separator when formatting numbers
+USE_THOUSAND_SEPARATOR = False
+
+# Number of digits that will be togheter, when spliting them by THOUSAND_SEPARATOR
+# 0 means no grouping, 3 means splitting by thousands...
+NUMBER_GROUPING = 0
+
+# Thousand separator symbol
+THOUSAND_SEPARATOR = ','
+
 # Do you want to manage transactions manually?
 # Hint: you really don't!
 TRANSACTIONS_MANAGED = False
Index: django/forms/extras/widgets.py
===================================================================
--- django/forms/extras/widgets.py	(.../trunk)	(revision 11464)
+++ django/forms/extras/widgets.py	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -8,6 +8,8 @@
 from django.forms.widgets import Widget, Select
 from django.utils.dates import MONTHS
 from django.utils.safestring import mark_safe
+from django.utils.formats import getformat
+from django.conf import settings
 
 __all__ = ('SelectDateWidget',)
 
@@ -45,38 +47,27 @@
                 if match:
                     year_val, month_val, day_val = [int(v) for v in match.groups()]
 
+        choices = [(i, i) for i in self.years]
+        year_html = self.create_select(name, self.year_field, value, year_val, choices)
+        choices = MONTHS.items()
+        month_html = self.create_select(name, self.month_field, value, month_val, choices)
+        choices = [(i, i) for i in range(1, 32)]
+        day_html = self.create_select(name, self.day_field, value, day_val,  choices)
+
+        format = getformat('DATE_FORMAT')
+        escaped = False
         output = []
-
-        if 'id' in self.attrs:
-            id_ = self.attrs['id']
-        else:
-            id_ = 'id_%s' % name
-
-        month_choices = MONTHS.items()
-        if not (self.required and value):
-            month_choices.append(self.none_value)
-        month_choices.sort()
-        local_attrs = self.build_attrs(id=self.month_field % id_)
-        s = Select(choices=month_choices)
-        select_html = s.render(self.month_field % name, month_val, local_attrs)
-        output.append(select_html)
-
-        day_choices = [(i, i) for i in range(1, 32)]
-        if not (self.required and value):
-            day_choices.insert(0, self.none_value)
-        local_attrs['id'] = self.day_field % id_
-        s = Select(choices=day_choices)
-        select_html = s.render(self.day_field % name, day_val, local_attrs)
-        output.append(select_html)
-
-        year_choices = [(i, i) for i in self.years]
-        if not (self.required and value):
-            year_choices.insert(0, self.none_value)
-        local_attrs['id'] = self.year_field % id_
-        s = Select(choices=year_choices)
-        select_html = s.render(self.year_field % name, year_val, local_attrs)
-        output.append(select_html)
-
+        for char in format:
+            if escaped:
+                escaped = False
+            elif char == '\\':
+                escaped = True
+            elif char in 'Yy':
+                output.append(year_html)
+            elif char in 'bFMmNn':
+                output.append(month_html)
+            elif char in 'dj':
+                output.append(day_html)
         return mark_safe(u'\n'.join(output))
 
     def id_for_label(self, id_):
@@ -90,5 +81,27 @@
         if y == m == d == "0":
             return None
         if y and m and d:
-            return '%s-%s-%s' % (y, m, d)
+            if settings.USE_FORMAT_I18N:
+                input_format = getformat('DATE_INPUT_FORMATS')[0]
+                try:
+                    date_value = datetime.date(int(y), int(m), int(d))
+                except ValueError:
+                    pass
+                else:
+                    return date_value.strftime(input_format)
+            else:
+                return '%s-%s-%s' % (y, m, d)
         return data.get(name, None)
+
+    def create_select(self, name, field, value, val, choices):
+        if 'id' in self.attrs:
+            id_ = self.attrs['id']
+        else:
+            id_ = 'id_%s' % name
+        if not (self.required and value):
+            choices.insert(0, self.none_value)
+        local_attrs = self.build_attrs(id=field % id_)
+        s = Select(choices=choices)
+        select_html = s.render(field % name, val, local_attrs)
+        return select_html
+
Index: django/forms/fields.py
===================================================================
--- django/forms/fields.py	(.../trunk)	(revision 11464)
+++ django/forms/fields.py	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -26,6 +26,7 @@
 import django.core.exceptions
 from django.utils.translation import ugettext_lazy as _
 from django.utils.encoding import smart_unicode, smart_str
+from django.utils.formats import getformat
 
 from util import ErrorList, ValidationError
 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, SplitDateTimeWidget, SplitHiddenDateTimeWidget
@@ -33,9 +34,7 @@
 
 __all__ = (
     'Field', 'CharField', 'IntegerField',
-    'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
-    'DEFAULT_TIME_INPUT_FORMATS', 'TimeField',
-    'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField', 'TimeField',
+    'DateField', 'TimeField', 'DateTimeField', 'TimeField',
     'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField',
     'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField',
     'ComboField', 'MultiValueField', 'FloatField', 'DecimalField',
@@ -210,7 +209,9 @@
         if not self.required and value in EMPTY_VALUES:
             return None
         try:
-            value = float(value)
+            # We always accept dot as decimal separator
+            if isinstance(value, str) or isinstance(value, unicode):
+                value = float(value.replace(getformat('DECIMAL_SEPARATOR'), '.'))
         except (ValueError, TypeError):
             raise ValidationError(self.error_messages['invalid'])
         if self.max_value is not None and value > self.max_value:
@@ -246,7 +247,9 @@
             return None
         value = smart_str(value).strip()
         try:
-            value = Decimal(value)
+            # We always accept dot as decimal separator
+            if isinstance(value, str) or isinstance(value, unicode):
+                value = Decimal(value.replace(getformat('DECIMAL_SEPARATOR'), '.'))
         except DecimalException:
             raise ValidationError(self.error_messages['invalid'])
 
@@ -274,14 +277,6 @@
             raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places))
         return value
 
-DEFAULT_DATE_INPUT_FORMATS = (
-    '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06'
-    '%b %d %Y', '%b %d, %Y',            # 'Oct 25 2006', 'Oct 25, 2006'
-    '%d %b %Y', '%d %b, %Y',            # '25 Oct 2006', '25 Oct, 2006'
-    '%B %d %Y', '%B %d, %Y',            # 'October 25 2006', 'October 25, 2006'
-    '%d %B %Y', '%d %B, %Y',            # '25 October 2006', '25 October, 2006'
-)
-
 class DateField(Field):
     widget = DateInput
     default_error_messages = {
@@ -290,7 +285,7 @@
 
     def __init__(self, input_formats=None, *args, **kwargs):
         super(DateField, self).__init__(*args, **kwargs)
-        self.input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS
+        self.input_formats = input_formats
 
     def clean(self, value):
         """
@@ -304,18 +299,13 @@
             return value.date()
         if isinstance(value, datetime.date):
             return value
-        for format in self.input_formats:
+        for format in self.input_formats or getformat('DATE_INPUT_FORMATS'):
             try:
                 return datetime.date(*time.strptime(value, format)[:3])
             except ValueError:
                 continue
         raise ValidationError(self.error_messages['invalid'])
 
-DEFAULT_TIME_INPUT_FORMATS = (
-    '%H:%M:%S',     # '14:30:59'
-    '%H:%M',        # '14:30'
-)
-
 class TimeField(Field):
     widget = TimeInput
     default_error_messages = {
@@ -324,7 +314,7 @@
 
     def __init__(self, input_formats=None, *args, **kwargs):
         super(TimeField, self).__init__(*args, **kwargs)
-        self.input_formats = input_formats or DEFAULT_TIME_INPUT_FORMATS
+        self.input_formats = input_formats
 
     def clean(self, value):
         """
@@ -336,25 +326,13 @@
             return None
         if isinstance(value, datetime.time):
             return value
-        for format in self.input_formats:
+        for format in self.input_formats or getformat('TIME_INPUT_FORMATS'):
             try:
                 return datetime.time(*time.strptime(value, format)[3:6])
             except ValueError:
                 continue
         raise ValidationError(self.error_messages['invalid'])
 
-DEFAULT_DATETIME_INPUT_FORMATS = (
-    '%Y-%m-%d %H:%M:%S',     # '2006-10-25 14:30:59'
-    '%Y-%m-%d %H:%M',        # '2006-10-25 14:30'
-    '%Y-%m-%d',              # '2006-10-25'
-    '%m/%d/%Y %H:%M:%S',     # '10/25/2006 14:30:59'
-    '%m/%d/%Y %H:%M',        # '10/25/2006 14:30'
-    '%m/%d/%Y',              # '10/25/2006'
-    '%m/%d/%y %H:%M:%S',     # '10/25/06 14:30:59'
-    '%m/%d/%y %H:%M',        # '10/25/06 14:30'
-    '%m/%d/%y',              # '10/25/06'
-)
-
 class DateTimeField(Field):
     widget = DateTimeInput
     default_error_messages = {
@@ -363,7 +341,7 @@
 
     def __init__(self, input_formats=None, *args, **kwargs):
         super(DateTimeField, self).__init__(*args, **kwargs)
-        self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS
+        self.input_formats = input_formats
 
     def clean(self, value):
         """
@@ -383,7 +361,7 @@
             if len(value) != 2:
                 raise ValidationError(self.error_messages['invalid'])
             value = '%s %s' % tuple(value)
-        for format in self.input_formats:
+        for format in self.input_formats or getformat('DATETIME_INPUT_FORMATS'):
             try:
                 return datetime.datetime(*time.strptime(value, format)[:6])
             except ValueError:
Index: django/forms/widgets.py
===================================================================
--- django/forms/widgets.py	(.../trunk)	(revision 11464)
+++ django/forms/widgets.py	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -15,6 +15,7 @@
 from django.utils.translation import ugettext
 from django.utils.encoding import StrAndUnicode, force_unicode
 from django.utils.safestring import mark_safe
+from django.utils.formats import localize
 from django.utils import datetime_safe
 from datetime import time
 from util import flatatt
@@ -213,7 +214,7 @@
         final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
         if value != '':
             # Only add the 'value' attribute if a value is non-empty.
-            final_attrs['value'] = force_unicode(value)
+            final_attrs['value'] = force_unicode(localize(value, is_input=True))
         return mark_safe(u'<input%s />' % flatatt(final_attrs))
 
 class TextInput(Input):
Index: django/core/management/commands/importcldr.py
===================================================================
--- django/core/management/commands/importcldr.py	(.../trunk)	(revision 0)
+++ django/core/management/commands/importcldr.py	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -0,0 +1,221 @@
+import sys
+import os
+import re
+from optparse import make_option, OptionParser
+
+from django.core.management.base import LabelCommand, CommandError
+
+try:
+    from lxml import etree
+except ImportError:
+    raise CommandError('You need to install `python-lxml` to run this script')
+
+FORMATS_FILE_NAME = 'formats.py'
+FORMATS_FILE_HEADER = '''# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+'''
+
+def quote(nodes, name,  locale, previous):
+    if len(nodes):
+        return "'%s'" % unicode(nodes[0].text).replace("'", "\\'")
+    else:
+        return None
+
+def convert_time(nodes, name,  locale, previous):
+    SPECIAL_CHARS = ('a', 'A', 'b', 'B', 'd', 'D', 'f', 'F', 'g', 'G', 'h',
+        'H', 'i', 'I', 'j', 'l', 'L', 'm', 'M', 'n', 'N', 'O', 'P', 'r',
+        's', 'S', 't', 'T', 'U', 'w', 'W', 'y', 'Y', 'z', 'Z')
+    FORMAT_STR_MAP = ( # not using a dict, because we have to apply formats in order
+        ('dd', 'd'),
+        ('d', 'j'),
+        ('MMMM', 'F'),
+        ('MMM', 'M'),
+        ('MM', 'm'),
+        ('M', 'n'),
+        ('yyyy', 'Y'),
+        ('yy', 'y'),
+        ('y', 'Y'),
+        ('hh', 'h'),
+        ('h', 'g'),
+        ('HH', 'H'),
+        ('H', 'G'),
+        ('mm', 'i'),
+        ('ss', 's'),
+        ('a', 'A'),
+        ('LLLL', 'F'),
+    )
+    if len(nodes):
+        original = nodes[0].text
+        result = ''
+        for cnt, segment in enumerate(original.split("'")):
+            if cnt % 2:
+                for char in SPECIAL_CHARS:
+                    segment = segment.replace(char, '\\%s' % char)
+                result += segment
+            else:
+                while segment:
+                    found = False
+                    for src, dst in FORMAT_STR_MAP:
+                        if segment[0:len(src)] == src:
+                            result += dst
+                            segment = segment[len(src):]
+                            found = True
+                            break
+                    if not found:
+                        result += segment[0]
+                        segment = segment[1:]
+
+        return "'%s'" % result
+    else:
+        return None
+
+def datetime(nodes, name, locale, previous):
+    result = None
+    if len(nodes) and 'DATE_FORMAT' in previous and 'TIME_FORMAT' in previous:
+        result = nodes[0].text
+        result = result.replace('{0}', previous['TIME_FORMAT'][1:-1])
+        if name == 'SHORT_DATETIME_FORMAT' and 'SHORT_DATE_FORMAT' in previous:
+            result = result.replace('{1}', previous['SHORT_DATE_FORMAT'][1:-1])
+        else:
+            result = result.replace('{1}', previous['DATE_FORMAT'][1:-1])
+    if result:
+        return "'%s'" % result
+    else:
+        return None
+
+FORMATS_MAP = [
+    {
+        'name': 'DATE_FORMAT',
+        'file': os.path.join('common', 'main', '%(locale)s.xml'),
+        'pattern': "/ldml/dates/calendars/calendar[@type='gregorian']/dateFormats/dateFormatLength[@type='long']/dateFormat/pattern",
+        'conversion': convert_time,
+    },
+    {
+        'name': 'TIME_FORMAT',
+        'file': os.path.join('common', 'main', '%(locale)s.xml'),
+        'pattern': "/ldml/dates/calendars/calendar[@type='gregorian']/timeFormats/timeFormatLength[@type='medium']/timeFormat/pattern",
+        'conversion': convert_time,
+    },
+    {
+        'name': 'DATETIME_FORMAT',
+        'file': os.path.join('common', 'main', '%(locale)s.xml'),
+        'pattern': "/ldml/dates/calendars/calendar[@type='gregorian']/dateTimeFormats/dateTimeFormatLength[@type='long']/dateTimeFormat/pattern",
+        'conversion': datetime,
+    },
+    {
+        'name': 'YEAR_MONTH_FORMAT',
+        'file': os.path.join('common', 'main', '%(locale)s.xml'),
+        'pattern': "/ldml/dates/calendars/calendar[@type='gregorian']/dateTimeFormats/availableFormats/dateFormatItem[@id='yMMMM']",
+        'conversion': convert_time,
+    },
+    {
+        'name': 'MONTH_DAY_FORMAT',
+        'file': os.path.join('common', 'main', '%(locale)s.xml'),
+        'pattern': "/ldml/dates/calendars/calendar[@type='gregorian']/dateTimeFormats/availableFormats/dateFormatItem[@id='MMMMd']",
+        'conversion': convert_time,
+    },
+    {
+        'name': 'SHORT_DATE_FORMAT',
+        'file': os.path.join('common', 'main', '%(locale)s.xml'),
+        'pattern': "/ldml/dates/calendars/calendar[@type='gregorian']/dateFormats/dateFormatLength[@type='medium']/dateFormat/pattern",
+        'conversion': convert_time,
+    },
+    {
+        'name': 'SHORT_DATETIME_FORMAT',
+        'file': os.path.join('common', 'main', '%(locale)s.xml'),
+        'pattern': "/ldml/dates/calendars/calendar[@type='gregorian']/dateTimeFormats/dateTimeFormatLength[@type='short']/dateTimeFormat/pattern",
+        'conversion': datetime,
+    },
+    {'name': 'FIRST_DAY_OF_WEEK'},
+    {'name': 'DATE_INPUT_FORMATS'},
+    {'name': 'TIME_INPUT_FORMATS'},
+    {'name': 'DATETIME_INPUT_FORMATS'},
+    {
+        'name': 'DECIMAL_SEPARATOR',
+        'file': os.path.join('common', 'main', '%(locale)s.xml'),
+        'pattern': "/ldml/numbers/symbols/decimal",
+        'conversion': quote,
+    },
+    {
+        'name': 'THOUSAND_SEPARATOR',
+        'file': os.path.join('common', 'main', '%(locale)s.xml'),
+        'pattern': "/ldml/numbers/symbols/group",
+        'conversion': quote,
+    },
+    {'name': 'NUMBER_GROUPING'},
+]
+"""
+"""
+
+def get_locales(django_locale_dir, locale=None):
+    if locale:
+        yield locale
+    else:
+        locale_re = re.compile('[a-z]{2}(_[A-Z]{2})?')
+        for locale in os.listdir(django_locale_dir):
+            if locale_re.match(locale):
+                yield locale
+
+def import_cldr(cldr_dir, locale=None, overwrite=False):
+    """
+    For every locale defined in Django, get from the CLDR locale file all
+    settings defined in output_structure, and write the result to the 
+    locale directories on Django.
+    """
+    if not os.path.isdir(cldr_dir):
+        raise Exception, "Specified CLDR directory '%s' does not exist" % cldr_dir
+
+    import django
+    django_locale_dir = os.path.join(os.path.dirname(django.__file__), 'conf', 'locale')
+
+    for locale in get_locales(django_locale_dir, locale):
+        output_filename = os.path.join(django_locale_dir, locale, FORMATS_FILE_NAME)
+        if os.path.isfile(output_filename) and not overwrite:
+            print "'%s' locale already exists. Skipping" % locale
+        else:
+            result = {}
+            output_file = open(output_filename, 'w')
+            output_file.write(FORMATS_FILE_HEADER)
+            for format in FORMATS_MAP:
+                if 'file' in format:
+                    cldr_file = os.path.join(cldr_dir, format['file'] % dict(locale=locale))
+                    tree = etree.parse(cldr_file) # TODO: error control
+                    try:
+                        original_value = tree.xpath(format['pattern'])
+                    except IndexError:
+                        output_file.write('# %s = \n' % (format['name']))
+                    else:
+                        value = format['conversion'](original_value, format['name'], locale, result)
+                        if value:
+                            output_file.write('%s = %s\n' % (format['name'], value.encode('utf8')))
+                            result[format['name']] = value
+                        else:
+                            output_file.write('# %s = \n' % (format['name']))
+                else:
+                    output_file.write('# %s = \n' % (format['name']))
+            output_file.close()
+
+            init_filename = os.path.join(django_locale_dir, locale, '__init__.py')
+            open(init_filename, 'a').close()
+
+class Command(LabelCommand):
+    option_list = LabelCommand.option_list + (
+        make_option('--locale', '-l', dest='locale',
+            help='The locale to process. Default is to process all.'),
+    ) + (
+        make_option('--overwite', '-o', action='store_true', dest='overwrite',
+            help='Wheter to overwrite format definitions of locales that already have one.'),
+    )
+    help = 'Creates format definition files for locales, importing data from the CLDR.'
+    args = '[cldrpath]'
+    label = 'CLDR path'
+    requires_model_validation = False
+    can_import_settings = False
+
+    def handle_label(self, cldrpath, **options):
+        locale = options.get('locale')
+        overwrite = options.get('overwrite')
+        import_cldr(cldrpath, locale, overwrite)
+
Index: django/views/i18n.py
===================================================================
--- django/views/i18n.py	(.../trunk)	(revision 11464)
+++ django/views/i18n.py	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -3,6 +3,7 @@
 from django.utils import importlib
 from django.utils.translation import check_for_language, activate, to_locale, get_language
 from django.utils.text import javascript_quote
+from django.utils.formats import project_formats_module, django_formats_module
 import os
 import gettext as gettext_module
 
@@ -32,6 +33,25 @@
                 response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code)
     return response
 
+def get_formats():
+    """
+    Returns an iterator over all formats in formats file
+    """
+    FORMAT_SETTINGS = ('DATE_FORMAT', 'DATETIME_FORMAT', 'TIME_FORMAT',
+        'YEAR_MONTH_FORMAT', 'MONTH_DAY_FORMAT', 'SHORT_DATE_FORMAT',
+        'SHORT_DATETIME_FORMAT', 'FIRST_DAY_OF_WEEK', 'DECIMAL_SEPARATOR',
+        'THOUSAND_SEPARATOR', 'NUMBER_GROUPING')
+
+    result = {}
+    for module in (settings, django_formats_module(), project_formats_module()):
+        if module:
+            for attr in FORMAT_SETTINGS:
+                try:
+                    result[attr] = getattr(module, attr)
+                except AttributeError:
+                    pass
+    return result
+    
 NullSource = """
 /* gettext identity library */
 
@@ -185,10 +205,13 @@
         else:
             raise TypeError, k
     csrc.sort()
-    for k,v in pdict.items():
+    for k, v in pdict.items():
         src.append("catalog['%s'] = [%s];\n" % (javascript_quote(k), ','.join(["''"]*(v+1))))
+    for k, v in get_formats().items():
+        src.append("catalog['%s'] = '%s';\n" % (javascript_quote(k), javascript_quote(unicode(v))))
     src.extend(csrc)
     src.append(LibFoot)
     src.append(InterPolate)
     src = ''.join(src)
     return http.HttpResponse(src, 'text/javascript')
+
Index: django/utils/numberformat.py
===================================================================
--- django/utils/numberformat.py	(.../trunk)	(revision 0)
+++ django/utils/numberformat.py	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -0,0 +1,40 @@
+from django.conf import settings
+
+def format(number, decimal_sep, decimal_pos, grouping=0, thousand_sep=''):
+    """
+    Gets a number (as a number or string), and returns it as a string,
+    using formats definied as arguments:
+     * decimal_sep: Decimal separator symbol (for example ".")
+     * decimal_pos: Number of decimal positions
+     * grouping: Number of digits in every group limited by thousand separator
+     * thousand_sep: Thousand separator symbol (for example ",")
+    """
+    # sign
+    if number < 0:
+        sign = '-'
+    else:
+        sign = ''
+    # decimal part
+    str_number = unicode(number)
+    if str_number[0] == '-':
+        str_number = str_number[1:]
+    if '.' in str_number:
+        int_part, dec_part = str_number.split('.')
+        if decimal_pos:
+            dec_part = dec_part[:decimal_pos]
+    else:
+        int_part, dec_part = str_number, ''
+    if decimal_pos:
+        dec_part = dec_part + ('0' * (decimal_pos - len(dec_part)))
+    if dec_part: dec_part = decimal_sep + dec_part
+    # grouping
+    if settings.USE_THOUSAND_SEPARATOR and grouping:
+        int_part_gd = ''
+        for cnt, digit in enumerate(int_part[::-1]):
+            if cnt and not cnt % grouping:
+                int_part_gd += thousand_sep
+            int_part_gd += digit
+        int_part = int_part_gd[::-1]
+
+    return sign + int_part + dec_part
+
Index: django/utils/translation/trans_real.py
===================================================================
--- django/utils/translation/trans_real.py	(.../trunk)	(revision 11464)
+++ django/utils/translation/trans_real.py	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -266,15 +266,16 @@
     translation object to use. If no current translation is activated, the
     message will be run through the default translation object.
     """
+    eol_message = message.replace('\r\n', '\n').replace('\r', '\n')
     global _default, _active
     t = _active.get(currentThread(), None)
     if t is not None:
-        result = getattr(t, translation_function)(message)
+        result = getattr(t, translation_function)(eol_message)
     else:
         if _default is None:
             from django.conf import settings
             _default = translation(settings.LANGUAGE_CODE)
-        result = getattr(_default, translation_function)(message)
+        result = getattr(_default, translation_function)(eol_message)
     if isinstance(message, SafeData):
         return mark_safe(result)
     return result
@@ -389,39 +390,6 @@
 
     return settings.LANGUAGE_CODE
 
-def get_date_formats():
-    """
-    Checks whether translation files provide a translation for some technical
-    message ID to store date and time formats. If it doesn't contain one, the
-    formats provided in the settings will be used.
-    """
-    from django.conf import settings
-    date_format = ugettext('DATE_FORMAT')
-    datetime_format = ugettext('DATETIME_FORMAT')
-    time_format = ugettext('TIME_FORMAT')
-    if date_format == 'DATE_FORMAT':
-        date_format = settings.DATE_FORMAT
-    if datetime_format == 'DATETIME_FORMAT':
-        datetime_format = settings.DATETIME_FORMAT
-    if time_format == 'TIME_FORMAT':
-        time_format = settings.TIME_FORMAT
-    return date_format, datetime_format, time_format
-
-def get_partial_date_formats():
-    """
-    Checks whether translation files provide a translation for some technical
-    message ID to store partial date formats. If it doesn't contain one, the
-    formats provided in the settings will be used.
-    """
-    from django.conf import settings
-    year_month_format = ugettext('YEAR_MONTH_FORMAT')
-    month_day_format = ugettext('MONTH_DAY_FORMAT')
-    if year_month_format == 'YEAR_MONTH_FORMAT':
-        year_month_format = settings.YEAR_MONTH_FORMAT
-    if month_day_format == 'MONTH_DAY_FORMAT':
-        month_day_format = settings.MONTH_DAY_FORMAT
-    return year_month_format, month_day_format
-
 dot_re = re.compile(r'\S')
 def blankout(src, char):
     """
@@ -537,3 +505,42 @@
         result.append((lang, priority))
     result.sort(lambda x, y: -cmp(x[1], y[1]))
     return result
+
+# get_date_formats and get_partial_date_formats aren't used anymore from django
+# itself, and are kept for backward compatibility.
+# Note that it's also important to keep format names maked for translation, so
+# for compatibility we still want to have formats on translation catalogs. That
+# makes template code like {{ my_date|date:_('DATE_FORMAT') }} go on working
+def get_date_formats():
+    """
+    Checks whether translation files provide a translation for some technical
+    message ID to store date and time formats. If it doesn't contain one, the
+    formats provided in the settings will be used.
+    """
+    from django.conf import settings
+    date_format = ugettext('DATE_FORMAT')
+    datetime_format = ugettext('DATETIME_FORMAT')
+    time_format = ugettext('TIME_FORMAT')
+    if date_format == 'DATE_FORMAT':
+        date_format = settings.DATE_FORMAT
+    if datetime_format == 'DATETIME_FORMAT':
+        datetime_format = settings.DATETIME_FORMAT
+    if time_format == 'TIME_FORMAT':
+        time_format = settings.TIME_FORMAT
+    return date_format, datetime_format, time_format
+
+def get_partial_date_formats():
+    """
+    Checks whether translation files provide a translation for some technical
+    message ID to store partial date formats. If it doesn't contain one, the
+    formats provided in the settings will be used.
+    """
+    from django.conf import settings
+    year_month_format = ugettext('YEAR_MONTH_FORMAT')
+    month_day_format = ugettext('MONTH_DAY_FORMAT')
+    if year_month_format == 'YEAR_MONTH_FORMAT':
+        year_month_format = settings.YEAR_MONTH_FORMAT
+    if month_day_format == 'MONTH_DAY_FORMAT':
+        month_day_format = settings.MONTH_DAY_FORMAT
+    return year_month_format, month_day_format
+
Index: django/utils/translation/trans_null.py
===================================================================
--- django/utils/translation/trans_null.py	(.../trunk)	(revision 11464)
+++ django/utils/translation/trans_null.py	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -18,10 +18,10 @@
 deactivate = deactivate_all = lambda: None
 get_language = lambda: settings.LANGUAGE_CODE
 get_language_bidi = lambda: settings.LANGUAGE_CODE in settings.LANGUAGES_BIDI
-get_date_formats = lambda: (settings.DATE_FORMAT, settings.DATETIME_FORMAT, settings.TIME_FORMAT)
-get_partial_date_formats = lambda: (settings.YEAR_MONTH_FORMAT, settings.MONTH_DAY_FORMAT)
 check_for_language = lambda x: True
 
+# date formats shouldn't be used using gettext anymore. This
+# is kept for backward compatibility
 TECHNICAL_ID_MAP = {
     "DATE_WITH_TIME_FULL": settings.DATETIME_FORMAT,
     "DATE_FORMAT": settings.DATE_FORMAT,
@@ -51,3 +51,8 @@
 
 def get_language_from_request(request):
     return settings.LANGUAGE_CODE
+
+# get_date_formats and get_partial_date_formats aren't used anymore from django
+# itself, and are kept for backward compatibility.
+get_date_formats = lambda: (settings.DATE_FORMAT, settings.DATETIME_FORMAT, settings.TIME_FORMAT)
+get_partial_date_formats = lambda: (settings.YEAR_MONTH_FORMAT, settings.MONTH_DAY_FORMAT)
Index: django/utils/formats.py
===================================================================
--- django/utils/formats.py	(.../trunk)	(revision 0)
+++ django/utils/formats.py	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -0,0 +1,95 @@
+import decimal
+import datetime
+
+from django.conf import settings
+from django.utils.translation import get_language
+from django.utils.importlib import import_module
+from django.utils import dateformat
+from django.utils import numberformat 
+
+def project_formats_module():
+    """
+    Returns the formats module for the current locale, defined
+    on the project
+    """
+    if settings.FORMAT_MODULE_PATH:
+        try:
+            return import_module('.formats', '%s.%s' % (settings.FORMAT_MODULE_PATH, get_language()))
+        except ImportError:
+            pass
+    return None
+
+def django_formats_module():
+    """
+    Returns the formats module for the current locale, defined
+    on Django
+    """
+    try:
+        return import_module('.formats', 'django.conf.locale.%s' % get_language())
+    except ImportError:
+        return None
+
+def getformat(format_type):
+    """
+    For a specific format type, returns the format for the
+    current language (locale) defaulting to the format on settings.
+    format_type is the name of the format, for example 'DATE_FORMAT'
+    """
+    if settings.USE_I18N and settings.USE_FORMAT_I18N:
+        for module in (project_formats_module(), django_formats_module()):
+            if module:
+                try:
+                    return getattr(module, format_type)
+                except AttributeError:
+                    pass
+    return getattr(settings, format_type)
+
+def date_format(value, format=None):
+    """
+    Formats a datetime.date or datetime.datetime object using a
+    localizable format
+    """
+    return dateformat.format(value, getformat(format or 'DATE_FORMAT'))
+
+def number_format(value, decimal_pos=None):
+    """
+    Formats a numeric value using localization settings
+    """
+    return numberformat.format(
+        value,
+        getformat('DECIMAL_SEPARATOR'),
+        decimal_pos,
+        getformat('NUMBER_GROUPING'),
+        getformat('THOUSAND_SEPARATOR'),
+    )
+
+def localize(value, is_input=False):
+    """
+    Checks value, and if it has a localizable type (date,
+    number...) it returns the value as a string using
+    current locale format
+    """
+    if settings.USE_I18N and settings.USE_FORMAT_I18N:
+        if isinstance(value, decimal.Decimal):
+            return number_format(value)
+        elif isinstance(value, float):
+            return number_format(value)
+        elif isinstance(value, int):
+            return number_format(value)
+        elif isinstance(value, datetime.datetime):
+            if not is_input:
+                return date_format(value, 'DATETIME_FORMAT')
+            else:
+                return value.strftime(getformat('DATETIME_INPUT_FORMATS')[0])
+        elif isinstance(value, datetime.date):
+            if not is_input:
+                return date_format(value)
+            else:
+                return value.strftime(getformat('DATE_INPUT_FORMATS')[0])
+        elif isinstance(value, datetime.time):
+            if not is_input:
+                return date_format(value, 'TIME_FORMAT')
+            else:
+                return value.strftime(getformat('TIME_INPUT_FORMATS')[0])
+    return value
+
Index: django/contrib/admin/media/js/calendar.js
===================================================================
--- django/contrib/admin/media/js/calendar.js	(.../trunk)	(revision 11464)
+++ django/contrib/admin/media/js/calendar.js	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -25,6 +25,7 @@
 var CalendarNamespace = {
     monthsOfYear: gettext('January February March April May June July August September October November December').split(' '),
     daysOfWeek: gettext('S M T W T F S').split(' '),
+    firstDayOfWeek: parseInt(gettext('FIRST_DAY_OF_WEEK')),
     isLeapYear: function(year) {
         return (((year % 4)==0) && ((year % 100)!=0) || ((year % 400)==0));
     },
@@ -56,10 +57,10 @@
         // Draw days-of-week header
         var tableRow = quickElement('tr', tableBody);
         for (var i = 0; i < 7; i++) {
-            quickElement('th', tableRow, CalendarNamespace.daysOfWeek[i]);
+            quickElement('th', tableRow, CalendarNamespace.daysOfWeek[(i + CalendarNamespace.firstDayOfWeek) % 7]);
         }
 
-        var startingPos = new Date(year, month-1, 1).getDay();
+        var startingPos = new Date(year, month-1, 1 - CalendarNamespace.firstDayOfWeek).getDay();
         var days = CalendarNamespace.getDaysInMonth(month, year);
 
         // Draw blanks before first of month
Index: django/contrib/admin/templatetags/admin_list.py
===================================================================
--- django/contrib/admin/templatetags/admin_list.py	(.../trunk)	(revision 11464)
+++ django/contrib/admin/templatetags/admin_list.py	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -3,11 +3,11 @@
 from django.contrib.admin.views.main import ORDER_VAR, ORDER_TYPE_VAR, PAGE_VAR, SEARCH_VAR
 from django.core.exceptions import ObjectDoesNotExist
 from django.db import models
-from django.utils import dateformat
+from django.utils import formats
 from django.utils.html import escape, conditional_escape
 from django.utils.text import capfirst
 from django.utils.safestring import mark_safe
-from django.utils.translation import get_date_formats, get_partial_date_formats, ugettext as _
+from django.utils.translation import ugettext as _
 from django.utils.encoding import smart_unicode, smart_str, force_unicode
 from django.template import Library
 import datetime
@@ -184,25 +184,24 @@
             # Dates and times are special: They're formatted in a certain way.
             elif isinstance(f, models.DateField) or isinstance(f, models.TimeField):
                 if field_val:
-                    (date_format, datetime_format, time_format) = get_date_formats()
-                    if isinstance(f, models.DateTimeField):
-                        result_repr = capfirst(dateformat.format(field_val, datetime_format))
-                    elif isinstance(f, models.TimeField):
-                        result_repr = capfirst(dateformat.time_format(field_val, time_format))
-                    else:
-                        result_repr = capfirst(dateformat.format(field_val, date_format))
+                    result_repr = formats.localize(field_val)
                 else:
                     result_repr = EMPTY_CHANGELIST_VALUE
+            elif isinstance(f, models.DecimalField):
+                if field_val:
+                    result_repr = formats.number_format(field_val, f.decimal_places)
+                else:
+                    result_repr = EMPTY_CHANGELIST_VALUE
                 row_class = ' class="nowrap"'
+            elif isinstance(f, models.FloatField):
+                if field_val:
+                    result_repr = formats.number_format(field_val)
+                else:
+                    result_repr = EMPTY_CHANGELIST_VALUE
+                row_class = ' class="nowrap"'
             # Booleans are special: We use images.
             elif isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField):
                 result_repr = _boolean_icon(field_val)
-            # DecimalFields are special: Zero-pad the decimals.
-            elif isinstance(f, models.DecimalField):
-                if field_val is not None:
-                    result_repr = ('%%.%sf' % f.decimal_places) % field_val
-                else:
-                    result_repr = EMPTY_CHANGELIST_VALUE
             # Fields with choices are special: Use the representation
             # of the choice.
             elif f.flatchoices:
@@ -263,7 +262,6 @@
         year_lookup = cl.params.get(year_field)
         month_lookup = cl.params.get(month_field)
         day_lookup = cl.params.get(day_field)
-        year_month_format, month_day_format = get_partial_date_formats()
 
         link = lambda d: mark_safe(cl.get_query_string(d, [field_generic]))
 
@@ -273,9 +271,9 @@
                 'show': True,
                 'back': {
                     'link': link({year_field: year_lookup, month_field: month_lookup}),
-                    'title': dateformat.format(day, year_month_format)
+                    'title': capfirst(formats.date_format(day, 'YEAR_MONTH_FORMAT'))
                 },
-                'choices': [{'title': dateformat.format(day, month_day_format)}]
+                'choices': [{'title': capfirst(formats.date_format(day, 'MONTH_DAY_FORMAT'))}]
             }
         elif year_lookup and month_lookup:
             days = cl.query_set.filter(**{year_field: year_lookup, month_field: month_lookup}).dates(field_name, 'day')
@@ -287,7 +285,7 @@
                 },
                 'choices': [{
                     'link': link({year_field: year_lookup, month_field: month_lookup, day_field: day.day}),
-                    'title': dateformat.format(day, month_day_format)
+                    'title': capfirst(formats.date_format(day, 'MONTH_DAY_FORMAT'))
                 } for day in days]
             }
         elif year_lookup:
@@ -300,7 +298,7 @@
                 },
                 'choices': [{
                     'link': link({year_field: year_lookup, month_field: month.month}),
-                    'title': dateformat.format(month, year_month_format)
+                    'title': capfirst(formats.date_format(month, 'YEAR_MONTH_FORMAT'))
                 } for month in months]
             }
         else:
Index: django/contrib/admin/templates/admin/object_history.html
===================================================================
--- django/contrib/admin/templates/admin/object_history.html	(.../trunk)	(revision 11464)
+++ django/contrib/admin/templates/admin/object_history.html	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -27,7 +27,7 @@
         <tbody>
         {% for action in action_list %}
         <tr>
-            <th scope="row">{{ action.action_time|date:_("DATETIME_FORMAT") }}</th>
+            <th scope="row">{{ action.action_time|date }}</th>
             <td>{{ action.user.username }}{% if action.user.get_full_name %} ({{ action.user.get_full_name }}){% endif %}</td>
             <td>{{ action.change_message }}</td>
         </tr>
Index: django/contrib/databrowse/datastructures.py
===================================================================
--- django/contrib/databrowse/datastructures.py	(.../trunk)	(revision 11464)
+++ django/contrib/databrowse/datastructures.py	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -4,9 +4,8 @@
 """
 
 from django.db import models
-from django.utils import dateformat
+from django.utils import formats
 from django.utils.text import capfirst
-from django.utils.translation import get_date_formats
 from django.utils.encoding import smart_unicode, smart_str, iri_to_uri
 from django.utils.safestring import mark_safe
 from django.db.models.query import QuerySet
@@ -156,13 +155,12 @@
             objs = dict(self.field.choices).get(self.raw_value, EMPTY_VALUE)
         elif isinstance(self.field, models.DateField) or isinstance(self.field, models.TimeField):
             if self.raw_value:
-                date_format, datetime_format, time_format = get_date_formats()
                 if isinstance(self.field, models.DateTimeField):
-                    objs = capfirst(dateformat.format(self.raw_value, datetime_format))
+                    objs = capfirst(formats.date_format(self.raw_value, 'DATETIME_FORMAT'))
                 elif isinstance(self.field, models.TimeField):
-                    objs = capfirst(dateformat.time_format(self.raw_value, time_format))
+                    objs = capfirst(formats.date_format(self.raw_value, 'TIME_FORMAT'))
                 else:
-                    objs = capfirst(dateformat.format(self.raw_value, date_format))
+                    objs = capfirst(formats.date_format(self.raw_value, 'DATE_FORMAT'))
             else:
                 objs = EMPTY_VALUE
         elif isinstance(self.field, models.BooleanField) or isinstance(self.field, models.NullBooleanField):
Index: django/template/defaultfilters.py
===================================================================
--- django/template/defaultfilters.py	(.../trunk)	(revision 11464)
+++ django/template/defaultfilters.py	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -18,6 +18,7 @@
 from django.utils.translation import ugettext, ungettext
 from django.utils.encoding import force_unicode, iri_to_uri
 from django.utils.safestring import mark_safe, SafeData
+from django.utils.formats import date_format, number_format
 
 register = Library()
 
@@ -166,14 +167,14 @@
         return input_val
 
     if not m and p < 0:
-        return mark_safe(u'%d' % (int(d)))
+        return mark_safe(number_format(u'%d' % (int(d)), 0))
 
     if p == 0:
         exp = Decimal(1)
     else:
         exp = Decimal('1.0') / (Decimal(10) ** abs(p))
     try:
-        return mark_safe(u'%s' % str(d.quantize(exp, ROUND_HALF_UP)))
+        return mark_safe(number_format(u'%s' % str(d.quantize(exp, ROUND_HALF_UP)), abs(p)))
     except InvalidOperation:
         return input_val
 floatformat.is_safe = True
@@ -684,9 +685,12 @@
     if arg is None:
         arg = settings.DATE_FORMAT
     try:
-        return format(value, arg)
+        return date_format(value, arg)
     except AttributeError:
-        return ''
+        try:
+            return format(value, arg)
+        except AttributeError:
+            return ''
 date.is_safe = False
 
 def time(value, arg=None):
@@ -697,9 +701,12 @@
     if arg is None:
         arg = settings.TIME_FORMAT
     try:
-        return time_format(value, arg)
+        return date_format(value, arg)
     except AttributeError:
-        return ''
+        try:
+            return time_format(value, arg)
+        except AttributeError:
+            return ''
 time.is_safe = False
 
 def timesince(value, arg=None):
Index: django/template/__init__.py
===================================================================
--- django/template/__init__.py	(.../trunk)	(revision 11464)
+++ django/template/__init__.py	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -60,6 +60,7 @@
 from django.utils.encoding import smart_unicode, force_unicode, smart_str
 from django.utils.translation import ugettext as _
 from django.utils.safestring import SafeData, EscapeData, mark_safe, mark_for_escaping
+from django.utils.formats import localize
 from django.utils.html import escape
 
 __all__ = ('Template', 'Context', 'RequestContext', 'compile_string')
@@ -808,6 +809,7 @@
     means escaping, if required, and conversion to a unicode object. If value
     is a string, it is expected to have already been translated.
     """
+    value = localize(value)
     value = force_unicode(value)
     if (context.autoescape and not isinstance(value, SafeData)) or isinstance(value, EscapeData):
         return escape(value)
Index: django/template/debug.py
===================================================================
--- django/template/debug.py	(.../trunk)	(revision 11464)
+++ django/template/debug.py	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -2,6 +2,7 @@
 from django.utils.encoding import force_unicode
 from django.utils.html import escape
 from django.utils.safestring import SafeData, EscapeData
+from django.utils.formats import localize
 
 class DebugLexer(Lexer):
     def __init__(self, template_string, origin):
@@ -84,7 +85,9 @@
 class DebugVariableNode(VariableNode):
     def render(self, context):
         try:
-            output = force_unicode(self.filter_expression.resolve(context))
+            output = self.filter_expression.resolve(context)
+            output = localize(output)
+            output = force_unicode(output)
         except TemplateSyntaxError, e:
             if not hasattr(e, 'source'):
                 e.source = self.source
Index: tests/regressiontests/i18n/tests.py
===================================================================
--- tests/regressiontests/i18n/tests.py	(.../trunk)	(revision 11464)
+++ tests/regressiontests/i18n/tests.py	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -64,6 +64,283 @@
 'as'
 >>> print s
 Password
+
+Translations on files with mac or dos end of lines will be converted
+to unix eof in .po catalogs, and they have to match when retrieved
+
+>>> from django.utils.translation.trans_real import translation
+>>> ca_translation = translation('ca')
+>>> ca_translation._catalog[u'Mac\nEOF\n'] = u'Catalan Mac\nEOF\n'
+>>> ca_translation._catalog[u'Win\nEOF\n'] = u'Catalan Win\nEOF\n'
+>>> activate('ca')
+>>> ugettext(u'Mac\rEOF\r')
+u'Catalan Mac\nEOF\n'
+>>> ugettext(u'Win\r\nEOF\r\n')
+u'Catalan Win\nEOF\n'
+>>> deactivate()
+
+Localization of dates and numbers
+
+>>> import datetime
+>>> import decimal
+>>> from django.conf import settings
+>>> from django.utils.formats import getformat, date_format, number_format, localize
+>>> from django.utils.numberformat import format
+>>> from django import template
+>>> from django import forms
+>>> from django.forms.extras import SelectDateWidget
+
+>>> old_use_i18n = settings.USE_I18N
+>>> old_use_format_i18n = settings.USE_FORMAT_I18N
+>>> old_use_thousand_separator = settings.USE_THOUSAND_SEPARATOR
+
+>>> n = decimal.Decimal('66666.666')
+>>> f = 99999.999
+>>> d = datetime.date(2009, 12, 31)
+>>> dt = datetime.datetime(2009, 12, 31, 20, 50)
+>>> ctxt = template.Context({'n': n, 'd': d, 'dt': dt, 'f': f})
+>>> class I18nForm(forms.Form):
+...     decimal_field = forms.DecimalField()
+...     float_field = forms.FloatField()
+...     date_field = forms.DateField()
+...     datetime_field = forms.DateTimeField()
+...     time_field = forms.TimeField()
+>>> class SelectDateForm(forms.Form):
+...     date_field = forms.DateField(widget=SelectDateWidget)
+
+Locale independent
+
+>>> settings.USE_FORMAT_I18N = True
+>>> settings.USE_THOUSAND_SEPARATOR = False
+>>> format(n, decimal_sep='.', decimal_pos=2, grouping=3, thousand_sep=',')
+u'66666.66'
+>>> format(n, decimal_sep='A', decimal_pos=1, grouping=1, thousand_sep='B')
+u'66666A6'
+>>> settings.USE_THOUSAND_SEPARATOR = True
+>>> format(n, decimal_sep='.', decimal_pos=2, grouping=3, thousand_sep=',')
+u'66,666.66'
+>>> format(n, decimal_sep='A', decimal_pos=1, grouping=1, thousand_sep='B')
+u'6B6B6B6B6A6'
+
+Catalan locale with format i18n disabled
+translations will be used, but not formats
+
+>>> settings.USE_FORMAT_I18N = False
+>>> activate('ca')
+>>> getformat('DATE_FORMAT')
+'N j, Y'
+>>> getformat('FIRST_DAY_OF_WEEK')
+0
+>>> getformat('DECIMAL_SEPARATOR')
+'.'
+>>> date_format(d)
+u'des. 31, 2009'
+>>> date_format(d, 'YEAR_MONTH_FORMAT')
+u'desembre 2009'
+>>> date_format(dt, 'SHORT_DATETIME_FORMAT')
+u'12/31/2009 8:50 p.m.'
+>>> localize('No localizable')
+'No localizable'
+>>> localize(n)
+Decimal('66666.666')
+>>> localize(f)
+99999.999
+>>> localize(d)
+datetime.date(2009, 12, 31)
+>>> localize(dt)
+datetime.datetime(2009, 12, 31, 20, 50)
+>>> template.Template('{{ n }}').render(ctxt)
+u'66666.666'
+>>> template.Template('{{ f }}').render(ctxt)
+u'99999.999'
+>>> template.Template('{{ d }}').render(ctxt)
+u'2009-12-31'
+>>> template.Template('{{ dt }}').render(ctxt)
+u'2009-12-31 20:50:00'
+>>> template.Template('{{ n|floatformat:2 }}').render(ctxt)
+u'66666.67'
+>>> template.Template('{{ f|floatformat }}').render(ctxt)
+u'100000.0'
+>>> template.Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(ctxt)
+u'12/31/2009'
+>>> template.Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(ctxt)
+u'12/31/2009 8:50 p.m.'
+>>> form = I18nForm({'decimal_field': u'66666,666', 'float_field': u'99999,999', 'date_field': u'31/12/2009', 'datetime_field': u'31/12/2009 20:50', 'time_field': u'20:50'})
+>>> form.is_valid()
+False
+>>> form.errors['float_field']
+[u'Introdu\xefu un n\xfamero.']
+>>> form.errors['decimal_field']
+[u'Introdu\xefu un n\xfamero.']
+>>> form.errors['date_field']
+[u'Introdu\xefu una data v\xe0lida.']
+>>> form.errors['datetime_field']
+[u'Introdu\xefu una data/hora v\xe0lides.']
+>>> form2 = SelectDateForm({'date_field_month': u'12', 'date_field_day': u'31', 'date_field_year': u'2009'})
+>>> form2.is_valid()
+True
+>>> form2.cleaned_data['date_field']
+datetime.date(2009, 12, 31)
+>>> SelectDateWidget().render('mydate', datetime.date(2009, 12, 31))
+u'<select name="mydate_month" id="id_mydate_month">\n<option value="1">gener</option>\n<option value="2">febrer</option>\n<option value="3">mar\xe7</option>\n<option value="4">abril</option>\n<option value="5">maig</option>\n<option value="6">juny</option>\n<option value="7">juliol</option>\n<option value="8">agost</option>\n<option value="9">setembre</option>\n<option value="10">octubre</option>\n<option value="11">novembre</option>\n<option value="12" selected="selected">desembre</option>\n</select>\n<select name="mydate_day" id="id_mydate_day">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31" selected="selected">31</option>\n</select>\n<select name="mydate_year" id="id_mydate_year">\n<option value="2009" selected="selected">2009</option>\n<option value="2010">2010</option>\n<option value="2011">2011</option>\n<option value="2012">2012</option>\n<option value="2013">2013</option>\n<option value="2014">2014</option>\n<option value="2015">2015</option>\n<option value="2016">2016</option>\n<option value="2017">2017</option>\n<option value="2018">2018</option>\n</select>'
+
+Catalan locale
+
+>>> settings.USE_FORMAT_I18N = True
+>>> activate('ca')
+>>> getformat('DATE_FORMAT')
+'j \\de F \\de Y'
+>>> getformat('FIRST_DAY_OF_WEEK')
+1
+>>> getformat('DECIMAL_SEPARATOR')
+','
+>>> date_format(d)
+u'31 de desembre de 2009'
+>>> date_format(d, 'YEAR_MONTH_FORMAT')
+u'desembre del 2009'
+>>> date_format(dt, 'SHORT_DATETIME_FORMAT')
+u'31/12/2009 20:50'
+>>> localize('No localizable')
+'No localizable'
+>>> settings.USE_THOUSAND_SEPARATOR = True
+>>> localize(n)
+u'66.666,666'
+>>> localize(f)
+u'99.999,999'
+>>> settings.USE_THOUSAND_SEPARATOR = False
+>>> localize(n)
+u'66666,666'
+>>> localize(f)
+u'99999,999'
+>>> localize(d)
+u'31 de desembre de 2009'
+>>> localize(dt)
+u'31 de desembre de 2009 a les 20:50'
+>>> settings.USE_THOUSAND_SEPARATOR = True
+>>> template.Template('{{ n }}').render(ctxt)
+u'66.666,666'
+>>> template.Template('{{ f }}').render(ctxt)
+u'99.999,999'
+>>> settings.USE_THOUSAND_SEPARATOR = False
+>>> template.Template('{{ n }}').render(ctxt)
+u'66666,666'
+>>> template.Template('{{ f }}').render(ctxt)
+u'99999,999'
+>>> template.Template('{{ d }}').render(ctxt)
+u'31 de desembre de 2009'
+>>> template.Template('{{ dt }}').render(ctxt)
+u'31 de desembre de 2009 a les 20:50'
+>>> template.Template('{{ n|floatformat:2 }}').render(ctxt)
+u'66666,67'
+>>> template.Template('{{ f|floatformat }}').render(ctxt)
+u'100000,0'
+>>> template.Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(ctxt)
+u'31/12/2009'
+>>> template.Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(ctxt)
+u'31/12/2009 20:50'
+>>> form = I18nForm({'decimal_field': u'66666,666', 'float_field': u'99999,999', 'date_field': u'31/12/2009', 'datetime_field': u'31/12/2009 20:50', 'time_field': u'20:50'})
+>>> form.is_valid()
+True
+>>> form.cleaned_data['decimal_field']
+Decimal('66666.666')
+>>> form.cleaned_data['float_field']
+99999.999
+>>> form.cleaned_data['date_field']
+datetime.date(2009, 12, 31)
+>>> form.cleaned_data['datetime_field']
+datetime.datetime(2009, 12, 31, 20, 50)
+>>> form.cleaned_data['time_field']
+datetime.time(20, 50)
+>>> form2 = SelectDateForm({'date_field_month': u'12', 'date_field_day': u'31', 'date_field_year': u'2009'})
+>>> form2.is_valid()
+True
+>>> form2.cleaned_data['date_field']
+datetime.date(2009, 12, 31)
+>>> SelectDateWidget().render('mydate', datetime.date(2009, 12, 31))
+u'<select name="mydate_day" id="id_mydate_day">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31" selected="selected">31</option>\n</select>\n<select name="mydate_month" id="id_mydate_month">\n<option value="1">gener</option>\n<option value="2">febrer</option>\n<option value="3">mar\xe7</option>\n<option value="4">abril</option>\n<option value="5">maig</option>\n<option value="6">juny</option>\n<option value="7">juliol</option>\n<option value="8">agost</option>\n<option value="9">setembre</option>\n<option value="10">octubre</option>\n<option value="11">novembre</option>\n<option value="12" selected="selected">desembre</option>\n</select>\n<select name="mydate_year" id="id_mydate_year">\n<option value="2009" selected="selected">2009</option>\n<option value="2010">2010</option>\n<option value="2011">2011</option>\n<option value="2012">2012</option>\n<option value="2013">2013</option>\n<option value="2014">2014</option>\n<option value="2015">2015</option>\n<option value="2016">2016</option>\n<option value="2017">2017</option>\n<option value="2018">2018</option>\n</select>'
+
+English locale
+
+>>> settings.USE_FORMAT_I18N = True
+>>> activate('en')
+>>> getformat('DATE_FORMAT')
+'N j, Y'
+>>> getformat('FIRST_DAY_OF_WEEK')
+0
+>>> getformat('DECIMAL_SEPARATOR')
+'.'
+>>> date_format(d)
+u'Dec. 31, 2009'
+>>> date_format(d, 'YEAR_MONTH_FORMAT')
+u'December 2009'
+>>> date_format(dt, 'SHORT_DATETIME_FORMAT')
+u'12/31/2009 8:50 p.m.'
+>>> localize('No localizable')
+'No localizable'
+>>> settings.USE_THOUSAND_SEPARATOR = True
+>>> localize(n)
+u'66,666.666'
+>>> localize(f)
+u'99,999.999'
+>>> settings.USE_THOUSAND_SEPARATOR = False
+>>> localize(n)
+u'66666.666'
+>>> localize(f)
+u'99999.999'
+>>> localize(d)
+u'Dec. 31, 2009'
+>>> localize(dt)
+u'Dec. 31, 2009, 8:50 p.m.'
+>>> settings.USE_THOUSAND_SEPARATOR = True
+>>> template.Template('{{ n }}').render(ctxt)
+u'66,666.666'
+>>> template.Template('{{ f }}').render(ctxt)
+u'99,999.999'
+>>> settings.USE_THOUSAND_SEPARATOR = False
+>>> template.Template('{{ n }}').render(ctxt)
+u'66666.666'
+>>> template.Template('{{ f }}').render(ctxt)
+u'99999.999'
+>>> template.Template('{{ d }}').render(ctxt)
+u'Dec. 31, 2009'
+>>> template.Template('{{ dt }}').render(ctxt)
+u'Dec. 31, 2009, 8:50 p.m.'
+>>> template.Template('{{ n|floatformat:2 }}').render(ctxt)
+u'66666.67'
+>>> template.Template('{{ f|floatformat }}').render(ctxt)
+u'100000.0'
+>>> template.Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(ctxt)
+u'12/31/2009'
+>>> template.Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(ctxt)
+u'12/31/2009 8:50 p.m.'
+>>> form = I18nForm({'decimal_field': u'66666.666', 'float_field': u'99999.999', 'date_field': u'12/31/2009', 'datetime_field': u'12/31/2009 20:50', 'time_field': u'20:50'})
+>>> form.is_valid()
+True
+>>> form.cleaned_data['decimal_field']
+Decimal('66666.666')
+>>> form.cleaned_data['float_field']
+99999.999
+>>> form.cleaned_data['date_field']
+datetime.date(2009, 12, 31)
+>>> form.cleaned_data['datetime_field']
+datetime.datetime(2009, 12, 31, 20, 50)
+>>> form.cleaned_data['time_field']
+datetime.time(20, 50)
+>>> form2 = SelectDateForm({'date_field_month': u'12', 'date_field_day': u'31', 'date_field_year': u'2009'})
+>>> form2.is_valid()
+True
+>>> form2.cleaned_data['date_field']
+datetime.date(2009, 12, 31)
+>>> SelectDateWidget().render('mydate', datetime.date(2009, 12, 31))
+u'<select name="mydate_month" id="id_mydate_month">\n<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12" selected="selected">December</option>\n</select>\n<select name="mydate_day" id="id_mydate_day">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31" selected="selected">31</option>\n</select>\n<select name="mydate_year" id="id_mydate_year">\n<option value="2009" selected="selected">2009</option>\n<option value="2010">2010</option>\n<option value="2011">2011</option>\n<option value="2012">2012</option>\n<option value="2013">2013</option>\n<option value="2014">2014</option>\n<option value="2015">2015</option>\n<option value="2016">2016</option>\n<option value="2017">2017</option>\n<option value="2018">2018</option>\n</select>'
+
+Restore defaults
+
+>>> settings.USE_I18N = old_use_i18n
+>>> settings.USE_FORMAT_I18N = old_use_format_i18n
+>>> settings.USE_THOUSAND_SEPARATOR = old_use_thousand_separator
+>>> deactivate()
+
 """
 
 __test__ = {
Index: docs/topics/i18n.txt
===================================================================
--- docs/topics/i18n.txt	(.../trunk)	(revision 11464)
+++ docs/topics/i18n.txt	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -4,20 +4,21 @@
 Internationalization
 ====================
 
-Django has full support for internationalization of text in code and templates.
-Here's how it works.
+Django has full support for internationalization, including translation
+capabilities of text in code and templates, and format localization for
+dates and numbers. Here's how it works.
 
 Overview
 ========
 
 The goal of internationalization is to allow a single Web application to offer
-its content and functionality in multiple languages.
+its content and functionality in multiple languages and locales.
 
-You, the Django developer, can accomplish this goal by adding a minimal amount
-of hooks to your Python code and templates. These hooks are called
-**translation strings**. They tell Django: "This text should be translated into
-the end user's language, if a translation for this text is available in that
-language."
+For text translation, you, the Django developer, can accomplish this goal by
+adding a minimal amount of hooks to your Python code and templates. These hooks
+are called **translation strings**. They tell Django: "This text should be
+translated into the end user's language, if a translation for this text is
+available in that language."
 
 Django takes care of using these hooks to translate Web apps, on the fly,
 according to users' language preferences.
@@ -29,6 +30,12 @@
     * It uses these hooks to translate Web apps for particular users according
       to their language preferences.
 
+For format localization, it's just necessary to set
+:setting:`USE_FORMAT_I18N = True <USE_FORMAT_I18N>` in your settings file. If
+:settings:`USE_FORMAT_I18N` is set to ``True``, then Django will display
+numbers and dates in the format of the current locale. That includes field
+representation on templates, and allowed input formats on the admin.
+
 If you don't need internationalization in your app
 ==================================================
 
@@ -1074,3 +1081,53 @@
 translation utilities with a ``gettext`` package if the command ``xgettext
 --version`` entered at a Windows command prompt causes a popup window saying
 "xgettext.exe has generated errors and will be closed by Windows".
+
+Format localization
+===================
+
+Django's formatting system is disabled by default. To enable it, it's necessay
+to set :setting:`USE_FORMAT_I18N = True <USE_FORMAT_I18N>` in your settings
+file.  Note that :setting:`USE_FORMAT_I18N` requires `USE_I18N` to be ``True``.
+
+When using Django's formatting system, dates and numbers on templates will be
+displayed using the format specified for the current locale. That means, two
+users accessing the same content, but in different language, will see date and
+number fields formatted in different ways, depending on the format for their
+current locale.
+
+Django will also use localized formats when parsing data in forms. That means
+Django uses different formats for different locales when guessing the format
+used by the user when inputting data on forms. Note that Django uses different
+formats for displaying data, and for parsing it.
+
+Creating custom format files
+----------------------------
+
+Django provides format definitions for many locales, but sometimes you could
+want to create your own ones, because a format files doesn't exist for your
+locale, or because you want to overwrite some of the values.
+
+To use custom formats, first thing to do, is to specify the path where you'll
+place format files. To do that, just set :setting:`FORMAT_MODULE_PATH` setting
+to the the path (in the format ``'foo.bar.baz``) where format files will
+exists.
+
+Files are not placed directly in this directory, but in a directory named as
+the locale. File must be named ``formats.py``. 
+
+For customazing English formats, a structure like this would be needed::
+
+    mysite/
+        formats/
+            __init__.py
+            en/
+                __init__.py
+                formats.py
+
+where :file:`formats.py` contains custom format definitions. For example::
+
+    THOUSAND_SEPARATOR = ' '
+
+to use a space as thousand separator, instead of the default for English,
+comma.
+
Index: docs/ref/settings.txt
===================================================================
--- docs/ref/settings.txt	(.../trunk)	(revision 11464)
+++ docs/ref/settings.txt	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -243,13 +243,33 @@
 
 Default: ``'N j, Y'`` (e.g. ``Feb. 4, 2003``)
 
-The default formatting to use for date fields on Django admin change-list
-pages -- and, possibly, by other parts of the system. See
-:ttag:`allowed date format strings <now>`.
+The default formatting to use for date fields in any part of the system.
+Note that if ``USE_FORMAT_I18N`` is set to ``True``, then locale format will
+be applied. See :ttag:`allowed date format strings <now>`.
 
-See also ``DATETIME_FORMAT``, ``TIME_FORMAT``, ``YEAR_MONTH_FORMAT``
-and ``MONTH_DAY_FORMAT``.
+See also ``DATETIME_FORMAT``, ``TIME_FORMAT`` and ``SHORT_DATE_FORMAT``.
 
+.. setting:: DATE_INPUT_FORMATS
+
+DATE_INPUT_FORMATS
+------------------
+
+Default::
+
+    ('%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', '%b %d %Y',
+    '%b %d, %Y', '%d %b %Y', '%d %b, %Y', '%B %d %Y',
+    '%B %d, %Y', '%d %B %Y', '%d %B, %Y')
+
+A tuple of formats that will be accepted when inputting data on a date
+field. Formats will be tried in order, using the first valid.
+Note that these format strings are specified in Python's datetime_ module
+syntax, that is different from the one used by Django for formatting dates
+to be displayed.
+
+See also ``DATETIME_INPUT_FORMATS`` and ``TIME_INPUT_FORMATS``.
+
+.. _datetime: http://docs.python.org/library/datetime.html#strftime-behavior
+
 .. setting:: DATETIME_FORMAT
 
 DATETIME_FORMAT
@@ -257,13 +277,33 @@
 
 Default: ``'N j, Y, P'`` (e.g. ``Feb. 4, 2003, 4 p.m.``)
 
-The default formatting to use for datetime fields on Django admin change-list
-pages -- and, possibly, by other parts of the system. See
-:ttag:`allowed date format strings <now>`.
+The default formatting to use for datetime fields in any part of the system.
+Note that if ``USE_FORMAT_I18N`` is set to ``True``, then locale format will
+be applied. See :ttag:`allowed date format strings <now>`.
 
-See also ``DATE_FORMAT``, ``DATETIME_FORMAT``, ``TIME_FORMAT``,
-``YEAR_MONTH_FORMAT`` and ``MONTH_DAY_FORMAT``.
+See also ``DATE_FORMAT``, ``TIME_FORMAT`` and ``SHORT_DATETIME_FORMAT``.
 
+.. setting:: DATETIME_INPUT_FORMATS
+
+DATETIME_INPUT_FORMATS
+----------------------
+
+Default::
+
+    ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M', '%Y-%m-%d',
+    '%m/%d/%Y %H:%M:%S', '%m/%d/%Y %H:%M', '%m/%d/%Y',
+    '%m/%d/%y %H:%M:%S', '%m/%d/%y %H:%M', '%m/%d/%y')
+
+A tuple of formats that will be accepted when inputting data on a datetime
+field. Formats will be tried in order, using the first valid.
+Note that these format strings are specified in Python's datetime_ module
+syntax, that is different from the one used by Django for formatting dates
+to be displayed.
+
+See also ``DATE_INPUT_FORMATS`` and ``TIME_INPUT_FORMATS``.
+
+.. _datetime: http://docs.python.org/library/datetime.html#strftime-behavior
+
 .. setting:: DEBUG
 
 DEBUG
@@ -302,7 +342,15 @@
 be useful for some test setups, and should never be used on a live
 site.
 
+.. setting:: DECIMAL_SEPARATOR
 
+DECIMAL_SEPARATOR
+-----------------
+
+Default: ``'.'`` (Dot)
+
+Default decimal separator used when formatting decimal numbers.
+
 .. setting:: DEFAULT_CHARSET
 
 DEFAULT_CHARSET
@@ -528,6 +576,21 @@
 
 .. _documentation for os.chmod: http://docs.python.org/lib/os-file-dir.html
 
+.. setting:: FIRST_DAY_OF_WEEK
+
+FIRST_DAY_OF_WEEK
+-----------------
+
+Default: ``0`` (Sunday)
+
+Number representing the first day of the week. This is specially useful
+when displaying a calendar. This value is only used when not using
+format internationalization, or when a format cannot be found for the
+current locale.
+
+The value must be an integer from 0 to 6, where 0 means Sunday, 1 means
+Monday and so on.
+
 .. setting:: FIXTURE_DIRS
 
 FIXTURE_DIRS
@@ -549,6 +612,34 @@
 the server-provided value of ``SCRIPT_NAME``, which may be a rewritten version
 of the preferred value or not supplied at all.
 
+.. setting:: FORMAT_MODULE_PATH
+
+FORMAT_MODULE_PATH
+------------------
+
+Default: ``None``
+
+A full Python path to a Python package that contains format definitions for
+project locales. If not ``None``, Django will check for a ``formats.py``
+file, under the directory named as the current locale, and will use the
+formats defined on this file.
+
+For example, if ``FORMAT_MODULE_PATH`` is set to ``mysite.formats``, and
+current language is ``en`` (English), Django will expect a directory tree
+like::
+
+    mysite/
+        formats/
+            __init__.py
+            en/
+                __init__.py
+                formats.py
+
+Available formats are ``DATE_FORMAT``, ``TIME_FORMAT``, ``DATETIME_FORMAT``,
+``YEAR_MONTH_FORMAT``, ``MONTH_DAY_FORMAT``, ``SHORT_DATE_FORMAT``,
+``SHORT_DATETIME_FORMAT``, ``FIRST_DAY_OF_WEEK``, ``DECIMAL_SEPARATOR``,
+``THOUSAND_SEPARATOR`` and ``NUMBER_GROUPING``.
+
 .. setting:: IGNORABLE_404_ENDS
 
 IGNORABLE_404_ENDS
@@ -774,6 +865,21 @@
 See :ttag:`allowed date format strings <now>`. See also ``DATE_FORMAT``,
 ``DATETIME_FORMAT``, ``TIME_FORMAT`` and ``YEAR_MONTH_FORMAT``.
 
+.. setting:: NUMBER_GROUPING
+
+NUMBER_GROUPING
+----------------
+
+Default: ``0``
+
+Number of digits grouped together on the integer part of a number. Common use
+is to display a thousand separator. If this setting is ``0``, then, no grouping
+will be applied to the number. If this setting is greater than ``0`` then the
+setting ``THOUSAND_SEPARATOR`` will be used as the separator between those
+groups.
+
+See also ``THOUSAND_SEPARATOR``
+
 .. setting:: PREPEND_WWW
 
 PREPEND_WWW
@@ -965,6 +1071,32 @@
 Whether to save the session data on every request. See
 :ref:`topics-http-sessions`.
 
+.. setting:: SHORT_DATE_FORMAT
+
+SHORT_DATE_FORMAT
+-----------------
+
+Default: ``m/d/Y`` (e.g. ``12/31/2003``)
+
+An available formatting that can be used for date fields on templates.
+Note that if ``USE_FORMAT_I18N`` is set to ``True``, then locale format will
+be applied. See :ttag:`allowed date format strings <now>`.
+
+See also ``DATE_FORMAT`` and ``SHORT_DATETIME_FORMAT``.
+
+.. setting:: SHORT_DATETIME_FORMAT
+
+SHORT_DATETIME_FORMAT
+---------------------
+
+Default: ``m/d/Y P`` (e.g. ``12/31/2003 4 p.m.``)
+
+An available formatting that can be used for datetime fields on templates.
+Note that if ``USE_FORMAT_I18N`` is set to ``True``, then locale format will
+be applied. See :ttag:`allowed date format strings <now>`.
+
+See also ``DATE_FORMAT`` and ``SHORT_DATETIME_FORMAT``.
+
 .. setting:: SITE_ID
 
 SITE_ID
@@ -1110,6 +1242,18 @@
 
 .. _Testing Django Applications: ../testing/
 
+.. setting:: THOUSAND_SEPARATOR
+
+THOUSAND_SEPARATOR
+------------------
+
+Default ``,`` (Comma)
+
+Default thousand separator used when formatting numbers. This setting is
+used only when ``NUMBER_GROUPPING`` is set.
+
+See also ``NUMBER_GROUPPING``, ``DECIMAL_SEPARATOR``
+
 .. setting:: TIME_FORMAT
 
 TIME_FORMAT
@@ -1117,13 +1261,29 @@
 
 Default: ``'P'`` (e.g. ``4 p.m.``)
 
-The default formatting to use for time fields on Django admin change-list
-pages -- and, possibly, by other parts of the system. See
-:ttag:`allowed date format strings <now>`.
+The default formatting to use for time fields in any part of the system.
+Note that if ``USE_FORMAT_I18N`` is set to ``True``, then locale format will
+be applied. See :ttag:`allowed date format strings <now>`.
 
-See also ``DATE_FORMAT``, ``DATETIME_FORMAT``, ``TIME_FORMAT``,
-``YEAR_MONTH_FORMAT`` and ``MONTH_DAY_FORMAT``.
+See also ``DATE_FORMAT`` and ``DATETIME_FORMAT``.
 
+.. setting:: TIME_INPUT_FORMATS
+
+TIME_INPUT_FORMATS
+------------------
+
+Default: ``('%H:%M:%S', '%H:%M')``
+
+A tuple of formats that will be accepted when inputting data on a time
+field. Formats will be tried in order, using the first valid.
+Note that these format strings are specified in Python's datetime_ module
+syntax, that is different from the one used by Django for formatting dates
+to be displayed.
+
+See also ``DATE_INPUT_FORMATS`` and ``DATETIME_INPUT_FORMATS``.
+
+.. _datetime: http://docs.python.org/library/datetime.html#strftime-behavior
+
 .. setting:: TIME_ZONE
 
 TIME_ZONE
@@ -1177,6 +1337,20 @@
 bandwidth but slows down performance. This is only used if ``CommonMiddleware``
 is installed (see :ref:`topics-http-middleware`).
 
+.. setting:: USE_FORMAT_I18N
+
+USE_FORMAT_I18N
+---------------
+
+Default ``False``
+
+A boolean that specifies if data will be localized by default or not. If this is
+set to ``True``, Django will display numbers and dates using the format of the
+current locale. It is required to set ``USE_I18N`` to ``True`` to allow data
+format localization.
+
+See also ``USE_I18N``
+
 .. setting:: USE_I18N
 
 USE_I18N
@@ -1189,6 +1363,22 @@
 set to ``False``, Django will make some optimizations so as not to load the
 internationalization machinery.
 
+See also ``USE_FORMAT_I18N``
+
+.. setting:: USE_THOUSAND_SEPARATOR
+
+USE_THOUSAND_SEPARATOR
+----------------------
+
+Default ``False``
+
+A boolean that specifies wheter to display numbers using a thousand separator.
+If this is set to ``True``, Django will use values from ``THOUSAND_SEPARATOR``
+and ``NUMBER_GROUPING`` from current locale, to format the number.
+``USE_FORMAT_I18N`` must be set to ``True``, in order to format numbers.
+
+See also ``THOUSAND_SEPARATOR`` and ``NUMBER_GROUPING``.
+
 .. setting:: YEAR_MONTH_FORMAT
 
 YEAR_MONTH_FORMAT
Index: docs/ref/templates/builtins.txt
===================================================================
--- docs/ref/templates/builtins.txt	(.../trunk)	(revision 11464)
+++ docs/ref/templates/builtins.txt	(.../branches/soc2009/i18n-improvements)	(revision 11464)
@@ -897,8 +897,12 @@
 date
 ~~~~
 
-Formats a date according to the given format (same as the `now`_ tag).
+Formats a date according to the given format.
 
+Given format can be one of the predefined ones ``DATE_FORMAT``, ``DATETIME_FORMAT``,
+``SHORT_DATE_FORMAT`` or ``SHORT_DATETIME_FORMAT``, or a custom format, same as the
+`now`_ tag. Note that prefedined formats vary depending on the current locale.
+
 For example::
 
     {{ value|date:"D d M Y" }}
@@ -912,7 +916,7 @@
     {{ value|date }}
 
 ...the formatting string defined in the :setting:`DATE_FORMAT` setting will be
-used.
+used, without applying any localization.
 
 .. templatefilter:: default
 
@@ -1460,7 +1464,10 @@
 time
 ~~~~
 
-Formats a time according to the given format (same as the `now`_ tag).
+Formats a time according to the given format.
+
+Given format can be the predefined one ``TIME_FORMAT``, or a custom format, same as the `now`_ tag. Note that the predefined format is locale depending.
+
 The time filter will only accept parameters in the format string that relate
 to the time of day, not the date (for obvious reasons). If you need to
 format a date, use the `date`_ filter.
@@ -1477,7 +1484,7 @@
     {{ value|time }}
 
 ...the formatting string defined in the :setting:`TIME_FORMAT` setting will be
-used.
+used, without aplying any localization.
 
 .. templatefilter:: timesince
 
