summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJannis Leidel <jannis@leidel.info>2009-12-22 17:58:49 +0000
committerJannis Leidel <jannis@leidel.info>2009-12-22 17:58:49 +0000
commit9233d0426537615e06b78d28010d17d5a66adf44 (patch)
tree5c731977b3ef9bd1e660b63c4edf6caa7b6491ad
parent6632739e94c6c38b4c5a86cf5c80c48ae50ac49f (diff)
downloaddjango-9233d0426537615e06b78d28010d17d5a66adf44.tar.gz
Fixed #7980 - Improved i18n framework to support locale aware formatting (dates and numbers) and form processing.
Thanks to Marc Garcia for working on this during his Google Summer of Code 2009! Additionally fixes #1061, #2203, #3940, #5526, #6449, #6231, #6693, #6783, #9366 and #10891. git-svn-id: http://code.djangoproject.com/svn/django/trunk@11964 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/conf/global_settings.py74
-rw-r--r--django/conf/locale/__init__.py0
-rw-r--r--django/conf/locale/ar/__init__.py0
-rw-r--r--django/conf/locale/ar/formats.py18
-rw-r--r--django/conf/locale/bg/__init__.py0
-rw-r--r--django/conf/locale/bg/formats.py18
-rw-r--r--django/conf/locale/bn/__init__.py0
-rw-r--r--django/conf/locale/bn/formats.py18
-rw-r--r--django/conf/locale/ca/__init__.py0
-rw-r--r--django/conf/locale/ca/formats.py30
-rw-r--r--django/conf/locale/cs/__init__.py0
-rw-r--r--django/conf/locale/cs/formats.py18
-rw-r--r--django/conf/locale/cy/__init__.py0
-rw-r--r--django/conf/locale/cy/formats.py18
-rw-r--r--django/conf/locale/da/__init__.py0
-rw-r--r--django/conf/locale/da/formats.py26
-rw-r--r--django/conf/locale/de/__init__.py0
-rw-r--r--django/conf/locale/de/formats.py32
-rw-r--r--django/conf/locale/el/__init__.py0
-rw-r--r--django/conf/locale/el/formats.py18
-rw-r--r--django/conf/locale/en/__init__.py0
-rw-r--r--django/conf/locale/en/formats.py38
-rw-r--r--django/conf/locale/es/__init__.py0
-rw-r--r--django/conf/locale/es/formats.py30
-rw-r--r--django/conf/locale/es_AR/__init__.py0
-rw-r--r--django/conf/locale/es_AR/formats.py18
-rw-r--r--django/conf/locale/et/__init__.py0
-rw-r--r--django/conf/locale/et/formats.py18
-rw-r--r--django/conf/locale/eu/__init__.py0
-rw-r--r--django/conf/locale/eu/formats.py18
-rw-r--r--django/conf/locale/fa/__init__.py0
-rw-r--r--django/conf/locale/fa/formats.py18
-rw-r--r--django/conf/locale/fi/__init__.py0
-rw-r--r--django/conf/locale/fi/formats.py18
-rw-r--r--django/conf/locale/fr/__init__.py0
-rw-r--r--django/conf/locale/fr/formats.py18
-rw-r--r--django/conf/locale/ga/__init__.py0
-rw-r--r--django/conf/locale/ga/formats.py18
-rw-r--r--django/conf/locale/gl/__init__.py0
-rw-r--r--django/conf/locale/gl/formats.py18
-rw-r--r--django/conf/locale/he/__init__.py0
-rw-r--r--django/conf/locale/he/formats.py18
-rw-r--r--django/conf/locale/hi/__init__.py0
-rw-r--r--django/conf/locale/hi/formats.py18
-rw-r--r--django/conf/locale/hr/__init__.py0
-rw-r--r--django/conf/locale/hr/formats.py18
-rw-r--r--django/conf/locale/hu/__init__.py0
-rw-r--r--django/conf/locale/hu/formats.py18
-rw-r--r--django/conf/locale/is/__init__.py0
-rw-r--r--django/conf/locale/is/formats.py18
-rw-r--r--django/conf/locale/it/__init__.py0
-rw-r--r--django/conf/locale/it/formats.py18
-rw-r--r--django/conf/locale/ja/__init__.py0
-rw-r--r--django/conf/locale/ja/formats.py18
-rw-r--r--django/conf/locale/ka/__init__.py0
-rw-r--r--django/conf/locale/ka/formats.py42
-rw-r--r--django/conf/locale/km/__init__.py0
-rw-r--r--django/conf/locale/km/formats.py18
-rw-r--r--django/conf/locale/kn/__init__.py0
-rw-r--r--django/conf/locale/kn/formats.py18
-rw-r--r--django/conf/locale/ko/__init__.py0
-rw-r--r--django/conf/locale/ko/formats.py44
-rw-r--r--django/conf/locale/lt/__init__.py0
-rw-r--r--django/conf/locale/lt/formats.py18
-rw-r--r--django/conf/locale/lv/__init__.py0
-rw-r--r--django/conf/locale/lv/formats.py18
-rw-r--r--django/conf/locale/mk/__init__.py0
-rw-r--r--django/conf/locale/mk/formats.py18
-rw-r--r--django/conf/locale/nl/__init__.py0
-rw-r--r--django/conf/locale/nl/formats.py48
-rw-r--r--django/conf/locale/no/__init__.py0
-rw-r--r--django/conf/locale/no/formats.py34
-rw-r--r--django/conf/locale/pl/__init__.py0
-rw-r--r--django/conf/locale/pl/formats.py18
-rw-r--r--django/conf/locale/pt/__init__.py0
-rw-r--r--django/conf/locale/pt/formats.py18
-rw-r--r--django/conf/locale/pt_BR/__init__.py0
-rw-r--r--django/conf/locale/pt_BR/formats.py35
-rw-r--r--django/conf/locale/ro/__init__.py0
-rw-r--r--django/conf/locale/ro/formats.py18
-rw-r--r--django/conf/locale/ru/__init__.py0
-rw-r--r--django/conf/locale/ru/formats.py18
-rw-r--r--django/conf/locale/sk/__init__.py0
-rw-r--r--django/conf/locale/sk/formats.py18
-rw-r--r--django/conf/locale/sl/__init__.py0
-rw-r--r--django/conf/locale/sl/formats.py18
-rw-r--r--django/conf/locale/sr/__init__.py0
-rw-r--r--django/conf/locale/sr/formats.py44
-rw-r--r--django/conf/locale/sr_Latn/__init__.py0
-rw-r--r--django/conf/locale/sr_Latn/formats.py44
-rw-r--r--django/conf/locale/sv/__init__.py0
-rw-r--r--django/conf/locale/sv/formats.py18
-rw-r--r--django/conf/locale/ta/__init__.py0
-rw-r--r--django/conf/locale/ta/formats.py18
-rw-r--r--django/conf/locale/te/__init__.py0
-rw-r--r--django/conf/locale/te/formats.py18
-rw-r--r--django/conf/locale/th/__init__.py0
-rw-r--r--django/conf/locale/th/formats.py18
-rw-r--r--django/conf/locale/tr/__init__.py0
-rw-r--r--django/conf/locale/tr/formats.py18
-rw-r--r--django/conf/locale/uk/__init__.py0
-rw-r--r--django/conf/locale/uk/formats.py18
-rw-r--r--django/conf/locale/zh_CN/__init__.py0
-rw-r--r--django/conf/locale/zh_CN/formats.py18
-rw-r--r--django/conf/locale/zh_TW/__init__.py0
-rw-r--r--django/conf/locale/zh_TW/formats.py18
-rw-r--r--django/contrib/admin/media/js/calendar.js5
-rw-r--r--django/contrib/admin/templates/admin/object_history.html2
-rw-r--r--django/contrib/admin/templatetags/admin_list.py38
-rw-r--r--django/contrib/databrowse/datastructures.py10
-rw-r--r--django/forms/extras/widgets.py77
-rw-r--r--django/forms/fields.py61
-rw-r--r--django/forms/widgets.py3
-rw-r--r--django/template/__init__.py2
-rw-r--r--django/template/debug.py5
-rw-r--r--django/template/defaultfilters.py19
-rw-r--r--django/utils/formats.py97
-rw-r--r--django/utils/numberformat.py42
-rw-r--r--django/utils/translation/trans_null.py23
-rw-r--r--django/utils/translation/trans_real.py88
-rw-r--r--django/views/i18n.py29
-rw-r--r--docs/internals/deprecation.txt12
-rw-r--r--docs/ref/settings.txt221
-rw-r--r--docs/ref/templates/builtins.txt17
-rw-r--r--docs/releases/1.2.txt45
-rw-r--r--docs/topics/i18n.txt72
-rw-r--r--tests/regressiontests/i18n/misc.py114
-rw-r--r--tests/regressiontests/i18n/tests.py447
128 files changed, 2314 insertions, 356 deletions
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index 950b5547db..e970c12792 100644
--- a/django/conf/global_settings.py
+++ b/django/conf/global_settings.py
@@ -103,6 +103,10 @@ USE_I18N = True
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_L10N = False
+
# Not-necessarily-technical managers of the site. They get broken link
# notifications and other various e-mails.
MANAGERS = ADMINS
@@ -265,6 +269,12 @@ FILE_UPLOAD_TEMP_DIR = None
# 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'
@@ -287,6 +297,70 @@ YEAR_MONTH_FORMAT = 'F Y'
# 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 to be used when parsing dates from input boxes, in 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 to be used when parsing times from input boxes, in 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 to be used when parsing dates and times from input boxes,
+# in 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
diff --git a/django/conf/locale/__init__.py b/django/conf/locale/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/__init__.py
diff --git a/django/conf/locale/ar/__init__.py b/django/conf/locale/ar/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/ar/__init__.py
diff --git a/django/conf/locale/ar/formats.py b/django/conf/locale/ar/formats.py
new file mode 100644
index 0000000000..d8d627f820
--- /dev/null
+++ b/django/conf/locale/ar/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F، Y'
+TIME_FORMAT = 'g:i:s A'
+# DATETIME_FORMAT =
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'd‏/m‏/Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/bg/__init__.py b/django/conf/locale/bg/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/bg/__init__.py
diff --git a/django/conf/locale/bg/formats.py b/django/conf/locale/bg/formats.py
new file mode 100644
index 0000000000..045543a7ac
--- /dev/null
+++ b/django/conf/locale/bg/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'd F Y'
+TIME_FORMAT = 'H:i:s'
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'd.m.Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = ' '
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/bn/__init__.py b/django/conf/locale/bn/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/bn/__init__.py
diff --git a/django/conf/locale/bn/formats.py b/django/conf/locale/bn/formats.py
new file mode 100644
index 0000000000..46e5da9392
--- /dev/null
+++ b/django/conf/locale/bn/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F, Y'
+TIME_FORMAT = 'g:i:s A'
+# DATETIME_FORMAT =
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'j M, Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = '.'
+THOUSAND_SEPARATOR = ','
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/ca/__init__.py b/django/conf/locale/ca/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/ca/__init__.py
diff --git a/django/conf/locale/ca/formats.py b/django/conf/locale/ca/formats.py
new file mode 100644
index 0000000000..aebaea3d07
--- /dev/null
+++ b/django/conf/locale/ca/formats.py
@@ -0,0 +1,30 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j \de F \de Y'
+TIME_FORMAT = 'G:i:s'
+DATETIME_FORMAT = 'j \de F \de Y \\a \le\s G:i'
+YEAR_MONTH_FORMAT = 'F \de\l Y'
+MONTH_DAY_FORMAT = 'j \de F'
+SHORT_DATE_FORMAT = 'd/m/Y'
+SHORT_DATETIME_FORMAT = 'd/m/Y G:i'
+FIRST_DAY_OF_WEEK = 1 # Monday
+DATE_INPUT_FORMATS = (
+ # '31/12/2009', '31/12/09'
+ '%d/%m/%Y', '%d/%m/%y'
+)
+TIME_INPUT_FORMATS = (
+ # '14:30:59', '14:30'
+ '%H:%M:%S', '%H:%M'
+)
+DATETIME_INPUT_FORMATS = (
+ '%d/%m/%Y %H:%M:%S',
+ '%d/%m/%Y %H:%M',
+ '%d/%m/%y %H:%M:%S',
+ '%d/%m/%y %H:%M',
+)
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+NUMBER_GROUPING = 3
+
diff --git a/django/conf/locale/cs/__init__.py b/django/conf/locale/cs/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/cs/__init__.py
diff --git a/django/conf/locale/cs/formats.py b/django/conf/locale/cs/formats.py
new file mode 100644
index 0000000000..327e77e868
--- /dev/null
+++ b/django/conf/locale/cs/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j. F Y'
+TIME_FORMAT = 'G:i:s'
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+MONTH_DAY_FORMAT = 'j. F'
+SHORT_DATE_FORMAT = 'j.n.Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = ' '
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/cy/__init__.py b/django/conf/locale/cy/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/cy/__init__.py
diff --git a/django/conf/locale/cy/formats.py b/django/conf/locale/cy/formats.py
new file mode 100644
index 0000000000..a58d81f479
--- /dev/null
+++ b/django/conf/locale/cy/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'd F Y'
+TIME_FORMAT = 'g:i:s A'
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+# MONTH_DAY_FORMAT =
+SHORT_DATE_FORMAT = 'j M Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+# DECIMAL_SEPARATOR =
+# THOUSAND_SEPARATOR =
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/da/__init__.py b/django/conf/locale/da/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/da/__init__.py
diff --git a/django/conf/locale/da/formats.py b/django/conf/locale/da/formats.py
new file mode 100644
index 0000000000..9982014cba
--- /dev/null
+++ b/django/conf/locale/da/formats.py
@@ -0,0 +1,26 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j. F Y'
+TIME_FORMAT = 'H:i'
+DATETIME_FORMAT = 'j. F Y H:i'
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j. F'
+SHORT_DATE_FORMAT = 'd.m.Y'
+SHORT_DATETIME_FORMAT = 'd.m.Y H:i'
+FIRST_DAY_OF_WEEK = 1
+DATE_INPUT_FORMATS = (
+ '%d.%m.%Y', # '25.10.2006'
+)
+TIME_INPUT_FORMATS = (
+ '%H:%M:%S', # '14:30:59'
+ '%H:%M', # '14:30'
+)
+DATETIME_INPUT_FORMATS = (
+ '%d.%m.%Y %H:%M:%S', # '25.10.2006 14:30:59'
+ '%d.%m.%Y %H:%M', # '25.10.2006 14:30'
+)
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+NUMBER_GROUPING = 3
diff --git a/django/conf/locale/de/__init__.py b/django/conf/locale/de/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/de/__init__.py
diff --git a/django/conf/locale/de/formats.py b/django/conf/locale/de/formats.py
new file mode 100644
index 0000000000..89b57846b6
--- /dev/null
+++ b/django/conf/locale/de/formats.py
@@ -0,0 +1,32 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j. F Y'
+TIME_FORMAT = 'H:i:s'
+DATETIME_FORMAT = 'j. F Y H:i:s'
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j. F'
+SHORT_DATE_FORMAT = 'd.m.Y'
+SHORT_DATETIME_FORMAT = 'd.m.Y H:i:s'
+FIRST_DAY_OF_WEEK = 1 # Monday
+DATE_INPUT_FORMATS = (
+ '%d.%m.%Y', '%d.%m.%y', # '25.10.2006', '25.10.06'
+ '%Y-%m-%d', '%y-%m-%d', # '2006-10-25', '06-10-25'
+ '%d. %B %Y', '%d. %b. %Y', # '25. October 2006', '25. Oct. 2006'
+)
+TIME_INPUT_FORMATS = (
+ '%H:%M:%S', # '14:30:59'
+ '%H:%M', # '14:30'
+)
+DATETIME_INPUT_FORMATS = (
+ '%d.%m.%Y %H:%M:%S', # '25.10.2006 14:30:59'
+ '%d.%m.%Y %H:%M', # '25.10.2006 14:30'
+ '%d.%m.%Y', # '25.10.2006'
+ '%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'
+)
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+NUMBER_GROUPING = 3
diff --git a/django/conf/locale/el/__init__.py b/django/conf/locale/el/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/el/__init__.py
diff --git a/django/conf/locale/el/formats.py b/django/conf/locale/el/formats.py
new file mode 100644
index 0000000000..d476ab3885
--- /dev/null
+++ b/django/conf/locale/el/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'd F Y'
+TIME_FORMAT = 'g:i:s A'
+# DATETIME_FORMAT =
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'd M Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/en/__init__.py b/django/conf/locale/en/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/en/__init__.py
diff --git a/django/conf/locale/en/formats.py b/django/conf/locale/en/formats.py
new file mode 100644
index 0000000000..3a507cd27e
--- /dev/null
+++ b/django/conf/locale/en/formats.py
@@ -0,0 +1,38 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'N j, Y'
+TIME_FORMAT = 'P'
+DATETIME_FORMAT = 'N j, Y, P'
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'F j'
+SHORT_DATE_FORMAT = 'm/d/Y'
+SHORT_DATETIME_FORMAT = 'm/d/Y P'
+FIRST_DAY_OF_WEEK = 0 # Sunday
+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'
+)
+TIME_INPUT_FORMATS = (
+ '%H:%M:%S', # '14:30:59'
+ '%H:%M', # '14:30'
+)
+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'
+)
+DECIMAL_SEPARATOR = '.'
+THOUSAND_SEPARATOR = ','
+NUMBER_GROUPING = 3
+
diff --git a/django/conf/locale/es/__init__.py b/django/conf/locale/es/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/es/__init__.py
diff --git a/django/conf/locale/es/formats.py b/django/conf/locale/es/formats.py
new file mode 100644
index 0000000000..349810f0fe
--- /dev/null
+++ b/django/conf/locale/es/formats.py
@@ -0,0 +1,30 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j \de F \de Y'
+TIME_FORMAT = 'H:i:s'
+DATETIME_FORMAT = 'j \de F \de Y \a \l\a\s H:i'
+YEAR_MONTH_FORMAT = 'F \de Y'
+MONTH_DAY_FORMAT = 'j \de F'
+SHORT_DATE_FORMAT = 'd/m/Y'
+SHORT_DATETIME_FORMAT = 'd/m/Y H:i'
+FIRST_DAY_OF_WEEK = 1 # Monday
+DATE_INPUT_FORMATS = (
+ # '31/12/2009', '31/12/09'
+ '%d/%m/%Y', '%d/%m/%y'
+)
+TIME_INPUT_FORMATS = (
+ # '14:30:59', '14:30'
+ '%H:%M:%S', '%H:%M'
+)
+DATETIME_INPUT_FORMATS = (
+ '%d/%m/%Y %H:%M:%S',
+ '%d/%m/%Y %H:%M',
+ '%d/%m/%y %H:%M:%S',
+ '%d/%m/%y %H:%M',
+)
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+NUMBER_GROUPING = 3
+
diff --git a/django/conf/locale/es_AR/__init__.py b/django/conf/locale/es_AR/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/es_AR/__init__.py
diff --git a/django/conf/locale/es_AR/formats.py b/django/conf/locale/es_AR/formats.py
new file mode 100644
index 0000000000..6d71786415
--- /dev/null
+++ b/django/conf/locale/es_AR/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+# DATE_FORMAT =
+# TIME_FORMAT =
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+# MONTH_DAY_FORMAT =
+# SHORT_DATE_FORMAT =
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+# DECIMAL_SEPARATOR =
+# THOUSAND_SEPARATOR =
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/et/__init__.py b/django/conf/locale/et/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/et/__init__.py
diff --git a/django/conf/locale/et/formats.py b/django/conf/locale/et/formats.py
new file mode 100644
index 0000000000..b96420c0c1
--- /dev/null
+++ b/django/conf/locale/et/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F Y'
+TIME_FORMAT = 'G:i:s'
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'd.m.Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = ' '
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/eu/__init__.py b/django/conf/locale/eu/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/eu/__init__.py
diff --git a/django/conf/locale/eu/formats.py b/django/conf/locale/eu/formats.py
new file mode 100644
index 0000000000..475f924fe8
--- /dev/null
+++ b/django/conf/locale/eu/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'Yeko M\re\n d\a'
+TIME_FORMAT = 'H:i:s'
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+# MONTH_DAY_FORMAT =
+SHORT_DATE_FORMAT = 'Y M j'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/fa/__init__.py b/django/conf/locale/fa/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/fa/__init__.py
diff --git a/django/conf/locale/fa/formats.py b/django/conf/locale/fa/formats.py
new file mode 100644
index 0000000000..dc11281790
--- /dev/null
+++ b/django/conf/locale/fa/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F Y'
+TIME_FORMAT = 'G:i:s'
+DATETIME_FORMAT = 'j F Y، ساعت G:i:s'
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'Y/n/j'
+SHORT_DATETIME_FORMAT = 'Y/n/j،‏ G:i:s'
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/fi/__init__.py b/django/conf/locale/fi/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/fi/__init__.py
diff --git a/django/conf/locale/fi/formats.py b/django/conf/locale/fi/formats.py
new file mode 100644
index 0000000000..670e26841a
--- /dev/null
+++ b/django/conf/locale/fi/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j. F Y'
+TIME_FORMAT = 'G.i.s'
+# DATETIME_FORMAT =
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j. F'
+SHORT_DATE_FORMAT = 'j.n.Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = ' '
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/fr/__init__.py b/django/conf/locale/fr/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/fr/__init__.py
diff --git a/django/conf/locale/fr/formats.py b/django/conf/locale/fr/formats.py
new file mode 100644
index 0000000000..1d670d7f6a
--- /dev/null
+++ b/django/conf/locale/fr/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F Y'
+TIME_FORMAT = 'H:i:s'
+DATETIME_FORMAT = 'j F Y H:i:s'
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'j M Y'
+SHORT_DATETIME_FORMAT = 'j M Y H:i:s'
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = ' '
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/ga/__init__.py b/django/conf/locale/ga/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/ga/__init__.py
diff --git a/django/conf/locale/ga/formats.py b/django/conf/locale/ga/formats.py
new file mode 100644
index 0000000000..f177bb28d4
--- /dev/null
+++ b/django/conf/locale/ga/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F Y'
+TIME_FORMAT = 'H:i:s'
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'j M Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = '.'
+THOUSAND_SEPARATOR = ','
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/gl/__init__.py b/django/conf/locale/gl/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/gl/__init__.py
diff --git a/django/conf/locale/gl/formats.py b/django/conf/locale/gl/formats.py
new file mode 100644
index 0000000000..e0a95d5106
--- /dev/null
+++ b/django/conf/locale/gl/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'd F Y'
+TIME_FORMAT = 'H:i:s'
+# DATETIME_FORMAT =
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'j M, Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/he/__init__.py b/django/conf/locale/he/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/he/__init__.py
diff --git a/django/conf/locale/he/formats.py b/django/conf/locale/he/formats.py
new file mode 100644
index 0000000000..8d7c7f2a4a
--- /dev/null
+++ b/django/conf/locale/he/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j בF Y'
+TIME_FORMAT = 'H:i:s'
+DATETIME_FORMAT = 'j בF Y H:i:s'
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j בF'
+SHORT_DATE_FORMAT = 'd/m/Y'
+SHORT_DATETIME_FORMAT = 'd/m/Y H:i:s'
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = '.'
+THOUSAND_SEPARATOR = ','
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/hi/__init__.py b/django/conf/locale/hi/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/hi/__init__.py
diff --git a/django/conf/locale/hi/formats.py b/django/conf/locale/hi/formats.py
new file mode 100644
index 0000000000..6afa2581b9
--- /dev/null
+++ b/django/conf/locale/hi/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F Y'
+TIME_FORMAT = 'g:i:s A'
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'd-m-Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = '.'
+THOUSAND_SEPARATOR = ','
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/hr/__init__.py b/django/conf/locale/hr/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/hr/__init__.py
diff --git a/django/conf/locale/hr/formats.py b/django/conf/locale/hr/formats.py
new file mode 100644
index 0000000000..62d1a7edf5
--- /dev/null
+++ b/django/conf/locale/hr/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j. F Y.'
+TIME_FORMAT = 'H:i:s'
+# DATETIME_FORMAT =
+YEAR_MONTH_FORMAT = 'F Y.'
+MONTH_DAY_FORMAT = 'j. F'
+SHORT_DATE_FORMAT = 'j.n.Y.'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/hu/__init__.py b/django/conf/locale/hu/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/hu/__init__.py
diff --git a/django/conf/locale/hu/formats.py b/django/conf/locale/hu/formats.py
new file mode 100644
index 0000000000..6ee2db0cd5
--- /dev/null
+++ b/django/conf/locale/hu/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'Y. F j.'
+TIME_FORMAT = 'G:i:s'
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+MONTH_DAY_FORMAT = 'F j.'
+SHORT_DATE_FORMAT = 'Y.m.d.'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = ' '
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/is/__init__.py b/django/conf/locale/is/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/is/__init__.py
diff --git a/django/conf/locale/is/formats.py b/django/conf/locale/is/formats.py
new file mode 100644
index 0000000000..b6377db40b
--- /dev/null
+++ b/django/conf/locale/is/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j. F Y'
+TIME_FORMAT = 'H:i:s'
+# DATETIME_FORMAT =
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j. F'
+SHORT_DATE_FORMAT = 'j.n.Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/it/__init__.py b/django/conf/locale/it/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/it/__init__.py
diff --git a/django/conf/locale/it/formats.py b/django/conf/locale/it/formats.py
new file mode 100644
index 0000000000..fe86b5bd70
--- /dev/null
+++ b/django/conf/locale/it/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'd F Y'
+TIME_FORMAT = 'H.i.s'
+# DATETIME_FORMAT =
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'd/M/Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/ja/__init__.py b/django/conf/locale/ja/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/ja/__init__.py
diff --git a/django/conf/locale/ja/formats.py b/django/conf/locale/ja/formats.py
new file mode 100644
index 0000000000..853056d8da
--- /dev/null
+++ b/django/conf/locale/ja/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'Y年n月j日'
+TIME_FORMAT = 'G:i:s'
+DATETIME_FORMAT = 'Y年n月j日G:i:s'
+YEAR_MONTH_FORMAT = 'Y年n月'
+MONTH_DAY_FORMAT = 'n月j日'
+SHORT_DATE_FORMAT = 'Y/m/d'
+SHORT_DATETIME_FORMAT = 'Y/m/d G:i:s'
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = '.'
+THOUSAND_SEPARATOR = ','
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/ka/__init__.py b/django/conf/locale/ka/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/ka/__init__.py
diff --git a/django/conf/locale/ka/formats.py b/django/conf/locale/ka/formats.py
new file mode 100644
index 0000000000..665a73fcfc
--- /dev/null
+++ b/django/conf/locale/ka/formats.py
@@ -0,0 +1,42 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'l, j F, Y'
+TIME_FORMAT = 'h:i:s a'
+DATETIME_FORMAT = 'j F, Y h:i:s a'
+YEAR_MONTH_FORMAT = 'F, Y'
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'j.M.Y'
+SHORT_DATETIME_FORMAT = 'j.M.Y H:i:s'
+FIRST_DAY_OF_WEEK = 1 # (Monday)
+DATE_INPUT_FORMATS = (
+ '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06'
+ '%d %b %Y', '%d %b, %Y', '%d %b. %Y', # '25 Oct 2006', '25 Oct, 2006', '25 Oct. 2006'
+ '%d %B %Y', '%d %B, %Y', # '25 October 2006', '25 October, 2006'
+ '%d.%m.%Y', '%d.%m.%y', # '25.10.2006', '25.10.06'
+)
+TIME_INPUT_FORMATS = (
+ '%H:%M:%S', # '14:30:59'
+ '%H:%M', # '14:30'
+)
+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'
+ '%d.%m.%Y %H:%M:%S', # '25.10.2006 14:30:59'
+ '%d.%m.%Y %H:%M', # '25.10.2006 14:30'
+ '%d.%m.%Y', # '25.10.2006'
+ '%d.%m.%y %H:%M:%S', # '25.10.06 14:30:59'
+ '%d.%m.%y %H:%M', # '25.10.06 14:30'
+ '%d.%m.%y', # '25.10.06'
+ '%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'
+)
+DECIMAL_SEPARATOR = '.'
+THOUSAND_SEPARATOR = " "
+NUMBER_GROUPING = 3
diff --git a/django/conf/locale/km/__init__.py b/django/conf/locale/km/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/km/__init__.py
diff --git a/django/conf/locale/km/formats.py b/django/conf/locale/km/formats.py
new file mode 100644
index 0000000000..3736d574fb
--- /dev/null
+++ b/django/conf/locale/km/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j ខែ F ឆ្នាំ Y'
+TIME_FORMAT = 'G:i:s'
+DATETIME_FORMAT = 'j ខែ F ឆ្នាំ Y, G:i:s'
+# YEAR_MONTH_FORMAT =
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'j M Y'
+SHORT_DATETIME_FORMAT = 'j M Y, G:i:s'
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/kn/__init__.py b/django/conf/locale/kn/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/kn/__init__.py
diff --git a/django/conf/locale/kn/formats.py b/django/conf/locale/kn/formats.py
new file mode 100644
index 0000000000..fa7a7b9546
--- /dev/null
+++ b/django/conf/locale/kn/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F Y'
+TIME_FORMAT = 'h:i:s A'
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'j M Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+# DECIMAL_SEPARATOR =
+# THOUSAND_SEPARATOR =
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/ko/__init__.py b/django/conf/locale/ko/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/ko/__init__.py
diff --git a/django/conf/locale/ko/formats.py b/django/conf/locale/ko/formats.py
new file mode 100644
index 0000000000..619047dae0
--- /dev/null
+++ b/django/conf/locale/ko/formats.py
@@ -0,0 +1,44 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'Y년 n월 j일'
+TIME_FORMAT = 'A g:i:s'
+DATETIME_FORMAT = 'Y년 n월 j일 g:i:s A'
+YEAR_MONTH_FORMAT = 'Y년 F월'
+MONTH_DAY_FORMAT = 'F월 j일'
+SHORT_DATE_FORMAT = 'Y-n-j.'
+SHORT_DATETIME_FORMAT = 'Y-n-j H:i'
+# FIRST_DAY_OF_WEEK =
+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'
+ '%Y년 %m월 %d일', # '2006년 10월 25일', with localized suffix.
+)
+TIME_INPUT_FORMATS = (
+ '%H:%M:%S', # '14:30:59'
+ '%H:%M', # '14:30'
+ '%H시 %M분 %S초', # '14시 30분 59초'
+ '%H시 %M분', # '14시 30분'
+)
+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'
+
+ '%Y년 %m월 %d일 %H시 %M분 %S초', # '2006년 10월 25일 14시 30분 59초'
+ '%Y년 %m월 %d일 %H시 %M분', # '2006년 10월 25일 14시 30분'
+)
+
+DECIMAL_SEPARATOR = '.'
+THOUSAND_SEPARATOR = ','
+NUMBER_GROUPING = 3
diff --git a/django/conf/locale/lt/__init__.py b/django/conf/locale/lt/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/lt/__init__.py
diff --git a/django/conf/locale/lt/formats.py b/django/conf/locale/lt/formats.py
new file mode 100644
index 0000000000..d9fb0c86f7
--- /dev/null
+++ b/django/conf/locale/lt/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'Y \m. F j \d.'
+TIME_FORMAT = 'H:i:s'
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+# MONTH_DAY_FORMAT =
+SHORT_DATE_FORMAT = 'Y.m.d'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/lv/__init__.py b/django/conf/locale/lv/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/lv/__init__.py
diff --git a/django/conf/locale/lv/formats.py b/django/conf/locale/lv/formats.py
new file mode 100644
index 0000000000..5dc211cfc0
--- /dev/null
+++ b/django/conf/locale/lv/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'Y. \g\a\d\a j. F'
+TIME_FORMAT = 'H:i:s'
+# DATETIME_FORMAT =
+YEAR_MONTH_FORMAT = 'Y. \g. F'
+MONTH_DAY_FORMAT = 'j. F'
+SHORT_DATE_FORMAT = 'Y. \g\a\d\a j. M'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = ' '
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/mk/__init__.py b/django/conf/locale/mk/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/mk/__init__.py
diff --git a/django/conf/locale/mk/formats.py b/django/conf/locale/mk/formats.py
new file mode 100644
index 0000000000..746ac0ea9f
--- /dev/null
+++ b/django/conf/locale/mk/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'd F Y'
+TIME_FORMAT = 'H:i:s'
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+# MONTH_DAY_FORMAT =
+SHORT_DATE_FORMAT = 'd.n.Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/nl/__init__.py b/django/conf/locale/nl/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/nl/__init__.py
diff --git a/django/conf/locale/nl/formats.py b/django/conf/locale/nl/formats.py
new file mode 100644
index 0000000000..dcef8c1eb7
--- /dev/null
+++ b/django/conf/locale/nl/formats.py
@@ -0,0 +1,48 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F Y' # '20 januari 2009'
+TIME_FORMAT = 'H:i' # '15:23'
+DATETIME_FORMAT = 'j F Y H:i' # '20 januari 2009 15:23'
+YEAR_MONTH_FORMAT = 'F Y' # 'januari 2009'
+MONTH_DAY_FORMAT = 'j F' # '20 januari'
+SHORT_DATE_FORMAT = 'j-n-Y' # '20-1-2009'
+SHORT_DATETIME_FORMAT = 'j-n-Y H:i' # '20-1-2009 15:23'
+FIRST_DAY_OF_WEEK = 1 # Monday (in Dutch 'maandag')
+DATE_INPUT_FORMATS = (
+ '%d-%m-%Y', '%d-%m-%y', '%Y-%m-%d', # '20-01-2009', '20-01-09', '2009-01-20'
+ '%d %b %Y', '%d %b %y', # '20 jan 2009', '20 jan 09'
+ '%d %B %Y', '%d %B %y', # '20 januari 2009', '20 januari 09'
+)
+TIME_INPUT_FORMATS = (
+ '%H:%M:%S', # '15:23:35'
+ '%H.%M:%S', # '15.23:35'
+ '%H.%M', # '15.23'
+ '%H:%M', # '15:23'
+)
+DATETIME_INPUT_FORMATS = (
+ # With time in %H:%M:%S :
+ '%d-%m-%Y %H:%M:%S', '%d-%m-%y %H:%M:%S', '%Y-%m-%d %H:%M:%S', # '20-01-2009 15:23:35', '20-01-09 15:23:35', '2009-01-20 15:23:35'
+ '%d %b %Y %H:%M:%S', '%d %b %y %H:%M:%S', # '20 jan 2009 15:23:35', '20 jan 09 15:23:35'
+ '%d %B %Y %H:%M:%S', '%d %B %y %H:%M:%S', # '20 januari 2009 15:23:35', '20 januari 2009 15:23:35'
+ # With time in %H.%M:%S :
+ '%d-%m-%Y %H.%M:%S', '%d-%m-%y %H.%M:%S', # '20-01-2009 15.23:35', '20-01-09 15.23:35'
+ '%d %b %Y %H.%M:%S', '%d %b %y %H.%M:%S', # '20 jan 2009 15.23:35', '20 jan 09 15.23:35'
+ '%d %B %Y %H.%M:%S', '%d %B %y %H.%M:%S', # '20 januari 2009 15.23:35', '20 januari 2009 15.23:35'
+ # With time in %H:%M :
+ '%d-%m-%Y %H:%M', '%d-%m-%y %H:%M', '%Y-%m-%d %H:%M', # '20-01-2009 15:23', '20-01-09 15:23', '2009-01-20 15:23'
+ '%d %b %Y %H:%M', '%d %b %y %H:%M', # '20 jan 2009 15:23', '20 jan 09 15:23'
+ '%d %B %Y %H:%M', '%d %B %y %H:%M', # '20 januari 2009 15:23', '20 januari 2009 15:23'
+ # With time in %H.%M :
+ '%d-%m-%Y %H.%M', '%d-%m-%y %H.%M', # '20-01-2009 15.23', '20-01-09 15.23'
+ '%d %b %Y %H.%M', '%d %b %y %H.%M', # '20 jan 2009 15.23', '20 jan 09 15.23'
+ '%d %B %Y %H.%M', '%d %B %y %H.%M', # '20 januari 2009 15.23', '20 januari 2009 15.23'
+ # Without time :
+ '%d-%m-%Y', '%d-%m-%y', '%Y-%m-%d', # '20-01-2009', '20-01-09', '2009-01-20'
+ '%d %b %Y', '%d %b %y', # '20 jan 2009', '20 jan 09'
+ '%d %B %Y', '%d %B %y', # '20 januari 2009', '20 januari 2009'
+)
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+NUMBER_GROUPING = 3
diff --git a/django/conf/locale/no/__init__.py b/django/conf/locale/no/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/no/__init__.py
diff --git a/django/conf/locale/no/formats.py b/django/conf/locale/no/formats.py
new file mode 100644
index 0000000000..62ee886f11
--- /dev/null
+++ b/django/conf/locale/no/formats.py
@@ -0,0 +1,34 @@
+DATE_FORMAT = 'j. F Y'
+TIME_FORMAT = 'H:i'
+DATETIME_FORMAT = 'j. F Y H:i'
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j. F'
+SHORT_DATE_FORMAT = 'd.m.Y'
+SHORT_DATETIME_FORMAT = 'd.m.Y H:i'
+FIRST_DAY_OF_WEEK = 1 # Monday
+DATE_INPUT_FORMATS = (
+ '%Y-%m-%d', '%j.%m.%Y', '%j.%m.%y', # '2006-10-25', '25.10.2006', '25.10.06'
+ '%Y-%m-%j', # '2006-10-25',
+ '%j. %b %Y', '%j %b %Y', # '25. okt 2006', '25 okt 2006'
+ '%j. %b. %Y', '%j %b. %Y', # '25. okt. 2006', '25 okt. 2006'
+ '%j. %B %Y', '%j %B %Y', # '25. oktober 2006', '25 oktober 2006'
+)
+TIME_INPUT_FORMATS = (
+ '%H:%i:%S', # '14:30:59'
+ '%H:%i', # '14:30'
+)
+DATETIME_INPUT_FORMATS = (
+ '%Y-%m-%d %H:%i:%S', # '2006-10-25 14:30:59'
+ '%Y-%m-%d %H:%i', # '2006-10-25 14:30'
+ '%Y-%m-%d', # '2006-10-25'
+ '%Y-%m-%j', # '2006-10-25'
+ '%j.%m.%Y %H:%i:%S', # '25.10.2006 14:30:59'
+ '%j.%m.%Y %H:%i', # '25.10.2006 14:30'
+ '%j.%m.%Y', # '25.10.2006'
+ '%j.%m.%y %H:%i:%S', # '25.10.06 14:30:59'
+ '%j.%m.%y %H:%i', # '25.10.06 14:30'
+ '%j.%m.%y', # '25.10.06'
+)
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = ' '
+NUMBER_GROUPING = 3
diff --git a/django/conf/locale/pl/__init__.py b/django/conf/locale/pl/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/pl/__init__.py
diff --git a/django/conf/locale/pl/formats.py b/django/conf/locale/pl/formats.py
new file mode 100644
index 0000000000..860a4a88ca
--- /dev/null
+++ b/django/conf/locale/pl/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F Y'
+TIME_FORMAT = 'H:i:s'
+# DATETIME_FORMAT =
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'd-m-Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = ' '
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/pt/__init__.py b/django/conf/locale/pt/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/pt/__init__.py
diff --git a/django/conf/locale/pt/formats.py b/django/conf/locale/pt/formats.py
new file mode 100644
index 0000000000..053a48af53
--- /dev/null
+++ b/django/conf/locale/pt/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j \de F \de Y'
+TIME_FORMAT = 'H:i:s'
+# DATETIME_FORMAT =
+YEAR_MONTH_FORMAT = 'F \de Y'
+MONTH_DAY_FORMAT = 'j \de F'
+SHORT_DATE_FORMAT = 'd/m/Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/pt_BR/__init__.py b/django/conf/locale/pt_BR/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/pt_BR/__init__.py
diff --git a/django/conf/locale/pt_BR/formats.py b/django/conf/locale/pt_BR/formats.py
new file mode 100644
index 0000000000..f30d5c4dfc
--- /dev/null
+++ b/django/conf/locale/pt_BR/formats.py
@@ -0,0 +1,35 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j \\de N \\de Y'
+TIME_FORMAT = 'H:i'
+DATETIME_FORMAT = 'j \\de N \\de Y à\\s H:i'
+YEAR_MONTH_FORMAT = 'F \\de Y'
+MONTH_DAY_FORMAT = 'j \\de F'
+SHORT_DATE_FORMAT = 'd/m/Y'
+SHORT_DATETIME_FORMAT = 'd/m/Y H:i'
+FIRST_DAY_OF_WEEK = 0 # Sunday
+DATE_INPUT_FORMATS = (
+ '%Y-%m-%d', '%d/%m/%Y', '%d/%m/%y', # '2006-10-25', '25/10/2006', '25/10/06'
+ '%d de %b de %Y', '%d de %b, %Y', # '25 de Out de 2006', '25 Out, 2006'
+ '%d de %B de %Y', '%d de %B, %Y', # '25 de Outubro de 2006', '25 de Outubro, 2006'
+)
+TIME_INPUT_FORMATS = (
+ '%H:%M:%S', # '14:30:59'
+ '%H:%M', # '14:30'
+)
+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'
+ '%d/%m/%Y %H:%M:%S', # '25/10/2006 14:30:59'
+ '%d/%m/%Y %H:%M', # '25/10/2006 14:30'
+ '%d/%m/%Y', # '25/10/2006'
+ '%d/%m/%y %H:%M:%S', # '25/10/06 14:30:59'
+ '%d/%m/%y %H:%M', # '25/10/06 14:30'
+ '%d/%m/%y', # '25/10/06'
+)
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+NUMBER_GROUPING = 3
diff --git a/django/conf/locale/ro/__init__.py b/django/conf/locale/ro/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/ro/__init__.py
diff --git a/django/conf/locale/ro/formats.py b/django/conf/locale/ro/formats.py
new file mode 100644
index 0000000000..6d6e800467
--- /dev/null
+++ b/django/conf/locale/ro/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F Y'
+TIME_FORMAT = 'H:i:s'
+DATETIME_FORMAT = 'j F Y, H:i:s'
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'd.m.Y'
+SHORT_DATETIME_FORMAT = 'd.m.Y, H:i:s'
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/ru/__init__.py b/django/conf/locale/ru/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/ru/__init__.py
diff --git a/django/conf/locale/ru/formats.py b/django/conf/locale/ru/formats.py
new file mode 100644
index 0000000000..9a9ee96561
--- /dev/null
+++ b/django/conf/locale/ru/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F Y г.'
+TIME_FORMAT = 'G:i:s'
+# DATETIME_FORMAT =
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'd.m.Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = ' '
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/sk/__init__.py b/django/conf/locale/sk/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/sk/__init__.py
diff --git a/django/conf/locale/sk/formats.py b/django/conf/locale/sk/formats.py
new file mode 100644
index 0000000000..1bc3549dcf
--- /dev/null
+++ b/django/conf/locale/sk/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j. F Y'
+TIME_FORMAT = 'G:i:s'
+# DATETIME_FORMAT =
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j. F'
+SHORT_DATE_FORMAT = 'j.n.Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = ' '
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/sl/__init__.py b/django/conf/locale/sl/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/sl/__init__.py
diff --git a/django/conf/locale/sl/formats.py b/django/conf/locale/sl/formats.py
new file mode 100644
index 0000000000..4007f10707
--- /dev/null
+++ b/django/conf/locale/sl/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'd. F Y'
+TIME_FORMAT = 'H:i:s'
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+MONTH_DAY_FORMAT = 'j. F'
+SHORT_DATE_FORMAT = 'j. M. Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/sr/__init__.py b/django/conf/locale/sr/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/sr/__init__.py
diff --git a/django/conf/locale/sr/formats.py b/django/conf/locale/sr/formats.py
new file mode 100644
index 0000000000..6dc19cf788
--- /dev/null
+++ b/django/conf/locale/sr/formats.py
@@ -0,0 +1,44 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j. F Y.'
+TIME_FORMAT = 'H:i'
+DATETIME_FORMAT = 'j. F Y. H:i'
+YEAR_MONTH_FORMAT = 'F Y.'
+MONTH_DAY_FORMAT = 'j. F'
+SHORT_DATE_FORMAT = 'j.m.Y.'
+SHORT_DATETIME_FORMAT = 'j.m.Y. H:i'
+FIRST_DAY_OF_WEEK = 1
+DATE_INPUT_FORMATS = (
+ '%Y-%m-%d', # '2006-10-25'
+ '%d.%m.%Y.', '%d.%m.%y.', # '25.10.2006.', '25.10.06.'
+ '%d. %m. %Y.', '%d. %m. %y.', # '25. 10. 2006.', '25. 10. 06.'
+ '%d. %b %y.', '%d. %B %y.', # '25. Oct 06.', '25. October 06.'
+ '%d. %b \'%y.', '%d. %B \'%y.', # '25. Oct '06.', '25. October '06.'
+ '%d. %b %Y.', '%d. %B %Y.', # '25. Oct 2006.', '25. October 2006.'
+)
+TIME_INPUT_FORMATS = (
+ '%H:%M:%S', # '14:30:59'
+ '%H:%M', # '14:30'
+)
+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'
+ '%d.%m.%Y. %H:%M:%S', # '25.10.2006. 14:30:59'
+ '%d.%m.%Y. %H:%M', # '25.10.2006. 14:30'
+ '%d.%m.%Y.', # '25.10.2006.'
+ '%d.%m.%y. %H:%M:%S', # '25.10.06. 14:30:59'
+ '%d.%m.%y. %H:%M', # '25.10.06. 14:30'
+ '%d.%m.%y.', # '25.10.06.'
+ '%d. %m. %Y. %H:%M:%S', # '25. 10. 2006. 14:30:59'
+ '%d. %m. %Y. %H:%M', # '25. 10. 2006. 14:30'
+ '%d. %m. %Y.', # '25. 10. 2006.'
+ '%d. %m. %y. %H:%M:%S', # '25. 10. 06. 14:30:59'
+ '%d. %m. %y. %H:%M', # '25. 10. 06. 14:30'
+ '%d. %m. %y.', # '25. 10. 06.'
+)
+DECIMAL_SEPARATOR = '.'
+THOUSAND_SEPARATOR = ','
+NUMBER_GROUPING = 3
diff --git a/django/conf/locale/sr_Latn/__init__.py b/django/conf/locale/sr_Latn/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/sr_Latn/__init__.py
diff --git a/django/conf/locale/sr_Latn/formats.py b/django/conf/locale/sr_Latn/formats.py
new file mode 100644
index 0000000000..6dc19cf788
--- /dev/null
+++ b/django/conf/locale/sr_Latn/formats.py
@@ -0,0 +1,44 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j. F Y.'
+TIME_FORMAT = 'H:i'
+DATETIME_FORMAT = 'j. F Y. H:i'
+YEAR_MONTH_FORMAT = 'F Y.'
+MONTH_DAY_FORMAT = 'j. F'
+SHORT_DATE_FORMAT = 'j.m.Y.'
+SHORT_DATETIME_FORMAT = 'j.m.Y. H:i'
+FIRST_DAY_OF_WEEK = 1
+DATE_INPUT_FORMATS = (
+ '%Y-%m-%d', # '2006-10-25'
+ '%d.%m.%Y.', '%d.%m.%y.', # '25.10.2006.', '25.10.06.'
+ '%d. %m. %Y.', '%d. %m. %y.', # '25. 10. 2006.', '25. 10. 06.'
+ '%d. %b %y.', '%d. %B %y.', # '25. Oct 06.', '25. October 06.'
+ '%d. %b \'%y.', '%d. %B \'%y.', # '25. Oct '06.', '25. October '06.'
+ '%d. %b %Y.', '%d. %B %Y.', # '25. Oct 2006.', '25. October 2006.'
+)
+TIME_INPUT_FORMATS = (
+ '%H:%M:%S', # '14:30:59'
+ '%H:%M', # '14:30'
+)
+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'
+ '%d.%m.%Y. %H:%M:%S', # '25.10.2006. 14:30:59'
+ '%d.%m.%Y. %H:%M', # '25.10.2006. 14:30'
+ '%d.%m.%Y.', # '25.10.2006.'
+ '%d.%m.%y. %H:%M:%S', # '25.10.06. 14:30:59'
+ '%d.%m.%y. %H:%M', # '25.10.06. 14:30'
+ '%d.%m.%y.', # '25.10.06.'
+ '%d. %m. %Y. %H:%M:%S', # '25. 10. 2006. 14:30:59'
+ '%d. %m. %Y. %H:%M', # '25. 10. 2006. 14:30'
+ '%d. %m. %Y.', # '25. 10. 2006.'
+ '%d. %m. %y. %H:%M:%S', # '25. 10. 06. 14:30:59'
+ '%d. %m. %y. %H:%M', # '25. 10. 06. 14:30'
+ '%d. %m. %y.', # '25. 10. 06.'
+)
+DECIMAL_SEPARATOR = '.'
+THOUSAND_SEPARATOR = ','
+NUMBER_GROUPING = 3
diff --git a/django/conf/locale/sv/__init__.py b/django/conf/locale/sv/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/sv/__init__.py
diff --git a/django/conf/locale/sv/formats.py b/django/conf/locale/sv/formats.py
new file mode 100644
index 0000000000..df4e633562
--- /dev/null
+++ b/django/conf/locale/sv/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F Y'
+TIME_FORMAT = 'H.i.s'
+# DATETIME_FORMAT =
+YEAR_MONTH_FORMAT = 'Y F'
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'j M Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = ' '
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/ta/__init__.py b/django/conf/locale/ta/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/ta/__init__.py
diff --git a/django/conf/locale/ta/formats.py b/django/conf/locale/ta/formats.py
new file mode 100644
index 0000000000..69fa17df33
--- /dev/null
+++ b/django/conf/locale/ta/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F, Y'
+TIME_FORMAT = 'g:i:s A'
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'j M, Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+# DECIMAL_SEPARATOR =
+# THOUSAND_SEPARATOR =
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/te/__init__.py b/django/conf/locale/te/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/te/__init__.py
diff --git a/django/conf/locale/te/formats.py b/django/conf/locale/te/formats.py
new file mode 100644
index 0000000000..e805872d52
--- /dev/null
+++ b/django/conf/locale/te/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F Y'
+TIME_FORMAT = 'g:i:s A'
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'j M Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+# DECIMAL_SEPARATOR =
+# THOUSAND_SEPARATOR =
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/th/__init__.py b/django/conf/locale/th/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/th/__init__.py
diff --git a/django/conf/locale/th/formats.py b/django/conf/locale/th/formats.py
new file mode 100644
index 0000000000..7091dc6b98
--- /dev/null
+++ b/django/conf/locale/th/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F Y'
+TIME_FORMAT = 'G:i:s'
+DATETIME_FORMAT = 'j F Y, G:i:s'
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'j M Y'
+SHORT_DATETIME_FORMAT = 'j M Y, G:i:s'
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = '.'
+THOUSAND_SEPARATOR = ','
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/tr/__init__.py b/django/conf/locale/tr/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/tr/__init__.py
diff --git a/django/conf/locale/tr/formats.py b/django/conf/locale/tr/formats.py
new file mode 100644
index 0000000000..b97878865b
--- /dev/null
+++ b/django/conf/locale/tr/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'd F Y'
+TIME_FORMAT = 'H:i:s'
+# DATETIME_FORMAT =
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'd F'
+SHORT_DATE_FORMAT = 'd M Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/uk/__init__.py b/django/conf/locale/uk/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/uk/__init__.py
diff --git a/django/conf/locale/uk/formats.py b/django/conf/locale/uk/formats.py
new file mode 100644
index 0000000000..8e41bf020d
--- /dev/null
+++ b/django/conf/locale/uk/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+DATE_FORMAT = 'j F Y р.'
+TIME_FORMAT = 'H:i:s'
+# DATETIME_FORMAT =
+YEAR_MONTH_FORMAT = 'F Y'
+MONTH_DAY_FORMAT = 'j F'
+SHORT_DATE_FORMAT = 'j M Y'
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = ' '
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/zh_CN/__init__.py b/django/conf/locale/zh_CN/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/zh_CN/__init__.py
diff --git a/django/conf/locale/zh_CN/formats.py b/django/conf/locale/zh_CN/formats.py
new file mode 100644
index 0000000000..6d71786415
--- /dev/null
+++ b/django/conf/locale/zh_CN/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+# DATE_FORMAT =
+# TIME_FORMAT =
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+# MONTH_DAY_FORMAT =
+# SHORT_DATE_FORMAT =
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+# DECIMAL_SEPARATOR =
+# THOUSAND_SEPARATOR =
+# NUMBER_GROUPING =
diff --git a/django/conf/locale/zh_TW/__init__.py b/django/conf/locale/zh_TW/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/conf/locale/zh_TW/__init__.py
diff --git a/django/conf/locale/zh_TW/formats.py b/django/conf/locale/zh_TW/formats.py
new file mode 100644
index 0000000000..6d71786415
--- /dev/null
+++ b/django/conf/locale/zh_TW/formats.py
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+# This file is distributed under the same license as the Django package.
+#
+
+# DATE_FORMAT =
+# TIME_FORMAT =
+# DATETIME_FORMAT =
+# YEAR_MONTH_FORMAT =
+# MONTH_DAY_FORMAT =
+# SHORT_DATE_FORMAT =
+# SHORT_DATETIME_FORMAT =
+# FIRST_DAY_OF_WEEK =
+# DATE_INPUT_FORMATS =
+# TIME_INPUT_FORMATS =
+# DATETIME_INPUT_FORMATS =
+# DECIMAL_SEPARATOR =
+# THOUSAND_SEPARATOR =
+# NUMBER_GROUPING =
diff --git a/django/contrib/admin/media/js/calendar.js b/django/contrib/admin/media/js/calendar.js
index 90351763a7..3f57145041 100644
--- a/django/contrib/admin/media/js/calendar.js
+++ b/django/contrib/admin/media/js/calendar.js
@@ -25,6 +25,7 @@ function quickElement() {
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 @@ var CalendarNamespace = {
// 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
diff --git a/django/contrib/admin/templates/admin/object_history.html b/django/contrib/admin/templates/admin/object_history.html
index 38b1c34ac8..9e6223acb9 100644
--- a/django/contrib/admin/templates/admin/object_history.html
+++ b/django/contrib/admin/templates/admin/object_history.html
@@ -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>
diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py
index 5a02ab01be..cd05957197 100644
--- a/django/contrib/admin/templatetags/admin_list.py
+++ b/django/contrib/admin/templatetags/admin_list.py
@@ -3,11 +3,11 @@ from django.contrib.admin.views.main import ALL_VAR, EMPTY_CHANGELIST_VALUE
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
@@ -189,25 +189,24 @@ def items_for_result(cl, result, form):
# 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:
@@ -268,7 +267,6 @@ def date_hierarchy(cl):
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: cl.get_query_string(d, [field_generic])
@@ -278,9 +276,9 @@ def date_hierarchy(cl):
'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')
@@ -292,7 +290,7 @@ def date_hierarchy(cl):
},
'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:
@@ -305,7 +303,7 @@ def date_hierarchy(cl):
},
'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:
diff --git a/django/contrib/databrowse/datastructures.py b/django/contrib/databrowse/datastructures.py
index 5fdbdbe134..369f825f0e 100644
--- a/django/contrib/databrowse/datastructures.py
+++ b/django/contrib/databrowse/datastructures.py
@@ -4,9 +4,8 @@ convenience functionality and permalink functions for the databrowse app.
"""
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 @@ class EasyInstanceField(object):
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):
diff --git a/django/forms/extras/widgets.py b/django/forms/extras/widgets.py
index e36b8a1d67..173ef2e1de 100644
--- a/django/forms/extras/widgets.py
+++ b/django/forms/extras/widgets.py
@@ -8,6 +8,8 @@ import re
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 get_format
+from django.conf import settings
__all__ = ('SelectDateWidget',)
@@ -45,38 +47,27 @@ class SelectDateWidget(Widget):
if match:
year_val, month_val, day_val = [int(v) for v in match.groups()]
- 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)
+ 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 = get_format('DATE_FORMAT')
+ escaped = False
+ output = []
+ 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 @@ class SelectDateWidget(Widget):
if y == m == d == "0":
return None
if y and m and d:
- return '%s-%s-%s' % (y, m, d)
+ if settings.USE_L10N:
+ input_format = get_format('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
+
diff --git a/django/forms/fields.py b/django/forms/fields.py
index c0ee2f0955..a4904d452d 100644
--- a/django/forms/fields.py
+++ b/django/forms/fields.py
@@ -7,6 +7,7 @@ import os
import re
import time
import urlparse
+import warnings
from decimal import Decimal, DecimalException
try:
from cStringIO import StringIO
@@ -17,6 +18,7 @@ import django.core.exceptions
import django.utils.copycompat as copy
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode, smart_str
+from django.utils.formats import get_format
from util import ErrorList, ValidationError
from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, SplitDateTimeWidget, SplitHiddenDateTimeWidget
@@ -36,6 +38,20 @@ __all__ = (
# These values, if given to to_python(), will trigger the self.required check.
EMPTY_VALUES = (None, '')
+def en_format(name):
+ """
+ Helper function to stay backward compatible.
+ """
+ from django.conf.locale.en import formats
+ warnings.warn(
+ "`django.forms.fields.DEFAULT_%s` is deprecated; use `django.utils.formats.get_format('%s')` instead." % (name, name),
+ PendingDeprecationWarning
+ )
+ return getattr(formats, name)
+
+DEFAULT_DATE_INPUT_FORMATS = en_format('DATE_INPUT_FORMATS')
+DEFAULT_TIME_INPUT_FORMATS = en_format('TIME_INPUT_FORMATS')
+DEFAULT_DATETIME_INPUT_FORMATS = en_format('DATETIME_INPUT_FORMATS')
class Field(object):
widget = TextInput # Default widget to use when rendering this type of Field.
@@ -200,7 +216,9 @@ class FloatField(Field):
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(get_format('DECIMAL_SEPARATOR'), '.'))
except (ValueError, TypeError):
raise ValidationError(self.error_messages['invalid'])
if self.max_value is not None and value > self.max_value:
@@ -236,7 +254,9 @@ class DecimalField(Field):
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(get_format('DECIMAL_SEPARATOR'), '.'))
except DecimalException:
raise ValidationError(self.error_messages['invalid'])
@@ -264,14 +284,6 @@ class DecimalField(Field):
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 = {
@@ -280,7 +292,7 @@ class DateField(Field):
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):
"""
@@ -294,18 +306,13 @@ class DateField(Field):
return value.date()
if isinstance(value, datetime.date):
return value
- for format in self.input_formats:
+ for format in self.input_formats or get_format('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 = {
@@ -314,7 +321,7 @@ class TimeField(Field):
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):
"""
@@ -326,25 +333,13 @@ class TimeField(Field):
return None
if isinstance(value, datetime.time):
return value
- for format in self.input_formats:
+ for format in self.input_formats or get_format('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 = {
@@ -353,7 +348,7 @@ class DateTimeField(Field):
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):
"""
@@ -373,7 +368,7 @@ class DateTimeField(Field):
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 get_format('DATETIME_INPUT_FORMATS'):
try:
return datetime.datetime(*time.strptime(value, format)[:6])
except ValueError:
diff --git a/django/forms/widgets.py b/django/forms/widgets.py
index d59e6343e5..aabd1b017d 100644
--- a/django/forms/widgets.py
+++ b/django/forms/widgets.py
@@ -10,6 +10,7 @@ from django.utils.html import escape, conditional_escape
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
@@ -208,7 +209,7 @@ class Input(Widget):
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):
diff --git a/django/template/__init__.py b/django/template/__init__.py
index 8764bfada4..4c386bea30 100644
--- a/django/template/__init__.py
+++ b/django/template/__init__.py
@@ -60,6 +60,7 @@ from django.utils.text import smart_split, unescape_string_literal
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')
@@ -815,6 +816,7 @@ def _render_value_in_context(value, context):
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)
diff --git a/django/template/debug.py b/django/template/debug.py
index c58c854858..382fb75ebd 100644
--- a/django/template/debug.py
+++ b/django/template/debug.py
@@ -2,6 +2,7 @@ from django.template import Lexer, Parser, tag_re, NodeList, VariableNode, Templ
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 DebugNodeList(NodeList):
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
diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py
index a8c25670f6..26b6b5ec4e 100644
--- a/django/template/defaultfilters.py
+++ b/django/template/defaultfilters.py
@@ -18,6 +18,7 @@ from django.conf import settings
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 @@ def floatformat(text, arg=-1):
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
@@ -685,9 +686,12 @@ def date(value, arg=None):
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):
@@ -698,9 +702,12 @@ def time(value, arg=None):
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):
diff --git a/django/utils/formats.py b/django/utils/formats.py
new file mode 100644
index 0000000000..e18e120b36
--- /dev/null
+++ b/django/utils/formats.py
@@ -0,0 +1,97 @@
+import decimal
+import datetime
+
+from django.conf import settings
+from django.utils.translation import get_language, to_locale, check_for_language
+from django.utils.importlib import import_module
+from django.utils import dateformat
+from django.utils import numberformat
+
+def get_format_modules():
+ """
+ Returns an iterator over the format modules found in the project and Django
+ """
+ modules = []
+ if not check_for_language(get_language()):
+ return modules
+ locale = to_locale(get_language())
+ if settings.FORMAT_MODULE_PATH:
+ format_locations = [settings.FORMAT_MODULE_PATH + '.%s']
+ else:
+ format_locations = []
+ format_locations.append('django.conf.locale.%s')
+ for location in format_locations:
+ for l in (locale, locale.split('_')[0]):
+ try:
+ mod = import_module('.formats', location % l)
+ except ImportError:
+ pass
+ else:
+ # Don't return duplicates
+ if mod not in modules:
+ modules.append(mod)
+ return modules
+
+def get_format(format_type):
+ """
+ For a specific format type, returns the format for the current
+ language (locale), defaults to the format in the settings.
+ format_type is the name of the format, e.g. 'DATE_FORMAT'
+ """
+ if settings.USE_L10N:
+ for module in get_format_modules():
+ 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, get_format(format or 'DATE_FORMAT'))
+
+def number_format(value, decimal_pos=None):
+ """
+ Formats a numeric value using localization settings
+ """
+ return numberformat.format(
+ value,
+ get_format('DECIMAL_SEPARATOR'),
+ decimal_pos,
+ get_format('NUMBER_GROUPING'),
+ get_format('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_L10N:
+ 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(get_format('DATETIME_INPUT_FORMATS')[0])
+ elif isinstance(value, datetime.date):
+ if not is_input:
+ return date_format(value)
+ else:
+ return value.strftime(get_format('DATE_INPUT_FORMATS')[0])
+ elif isinstance(value, datetime.time):
+ if not is_input:
+ return date_format(value, 'TIME_FORMAT')
+ else:
+ return value.strftime(get_format('TIME_INPUT_FORMATS')[0])
+ return value
+
diff --git a/django/utils/numberformat.py b/django/utils/numberformat.py
new file mode 100644
index 0000000000..78ecb2fbdb
--- /dev/null
+++ b/django/utils/numberformat.py
@@ -0,0 +1,42 @@
+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 float(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
+
diff --git a/django/utils/translation/trans_null.py b/django/utils/translation/trans_null.py
index 98c6de6197..50f41a2c23 100644
--- a/django/utils/translation/trans_null.py
+++ b/django/utils/translation/trans_null.py
@@ -2,6 +2,7 @@
# that don't actually do anything. This is purely for performance, so that
# settings.USE_I18N = False can use this module rather than trans_real.py.
+import warnings
from django.conf import settings
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe, SafeData
@@ -18,10 +19,10 @@ activate = lambda x: None
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 +52,21 @@ def to_locale(language):
def get_language_from_request(request):
return settings.LANGUAGE_CODE
+
+# get_date_formats and get_partial_date_formats aren't used anymore by Django
+# but are kept for backward compatibility.
+def get_date_formats():
+ warnings.warn(
+ '`django.utils.translation.get_date_formats` is deprecated. '
+ 'Please update your code to use the new i18n aware formatting.',
+ PendingDeprecationWarning
+ )
+ return settings.DATE_FORMAT, settings.DATETIME_FORMAT, settings.TIME_FORMAT
+
+def get_partial_date_formats():
+ warnings.warn(
+ '`django.utils.translation.get_partial_date_formats` is deprecated. '
+ 'Please update your code to use the new i18n aware formatting.',
+ PendingDeprecationWarning
+ )
+ return settings.YEAR_MONTH_FORMAT, settings.MONTH_DAY_FORMAT
diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
index 48ed7cc885..8b7db0f123 100644
--- a/django/utils/translation/trans_real.py
+++ b/django/utils/translation/trans_real.py
@@ -4,6 +4,7 @@ import locale
import os
import re
import sys
+import warnings
import gettext as gettext_module
from cStringIO import StringIO
@@ -266,15 +267,16 @@ def do_translate(message, translation_function):
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 +391,6 @@ def get_language_from_request(request):
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 +506,52 @@ def parse_accept_lang_header(lang_string):
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 by Django
+# and are kept for backward compatibility.
+# Note, it's also important to keep format names marked for translation.
+# For compatibility we still want to have formats on translation catalogs.
+# That makes template code like {{ my_date|date:_('DATE_FORMAT') }} still work
+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.
+ """
+ warnings.warn(
+ '`django.utils.translation.get_date_formats` is deprecated. '
+ 'Please update your code to use the new i18n aware formatting.',
+ PendingDeprecationWarning
+ )
+ 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.
+ """
+ warnings.warn(
+ '`django.utils.translation.get_partial_date_formats` is deprecated. '
+ 'Please update your code to use the new i18n aware formatting.',
+ PendingDeprecationWarning
+ )
+ 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
+
diff --git a/django/views/i18n.py b/django/views/i18n.py
index 0280698aae..ddd75203a7 100644
--- a/django/views/i18n.py
+++ b/django/views/i18n.py
@@ -1,10 +1,12 @@
+import os
+import gettext as gettext_module
+
from django import http
from django.conf import settings
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
-import os
-import gettext as gettext_module
+from django.utils.formats import get_format_modules
def set_language(request):
"""
@@ -32,6 +34,24 @@ def set_language(request):
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] + get_format_modules():
+ for attr in FORMAT_SETTINGS:
+ try:
+ result[attr] = getattr(module, attr)
+ except AttributeError:
+ pass
+ return result
+
NullSource = """
/* gettext identity library */
@@ -185,10 +205,13 @@ def javascript_catalog(request, domain='djangojs', packages=None):
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')
+
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt
index 2e44e418bc..1bd58ec0b3 100644
--- a/docs/internals/deprecation.txt
+++ b/docs/internals/deprecation.txt
@@ -62,6 +62,18 @@ their deprecation, as per the :ref:`Django deprecation policy
backwards compatibility. These have been deprecated since the 1.2
release.
+ * ``django.utils.translation.get_date_formats()`` and
+ ``django.utils.translation.get_partial_date_formats()``. These
+ functions are replaced by the new locale aware formatting; use
+ ``django.utils.formats.get_format()`` to get the appropriate
+ formats.
+
+ * In ``django.forms.fields``: ``DEFAULT_DATE_INPUT_FORMATS``,
+ ``DEFAULT_TIME_INPUT_FORMATS`` and
+ ``DEFAULT_DATETIME_INPUT_FORMATS``. Use
+ ``django.utils.formats.get_format()`` to get the appropriate
+ formats.
+
* 2.0
* ``django.views.defaults.shortcut()``. This function has been moved
to ``django.contrib.contenttypes.views.shortcut()`` as part of the
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index 1feb34a90b..bd8be27e5f 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -372,12 +372,32 @@ DATE_FORMAT
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_L10N`` is set to ``True``, then locale format will
+be applied. See :ttag:`allowed date format strings <now>`.
+
+See also ``DATETIME_FORMAT``, ``TIME_FORMAT`` and ``SHORT_DATE_FORMAT``.
+
+.. setting:: DATE_INPUT_FORMATS
-See also ``DATETIME_FORMAT``, ``TIME_FORMAT``, ``YEAR_MONTH_FORMAT``
-and ``MONTH_DAY_FORMAT``.
+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
@@ -386,12 +406,32 @@ DATETIME_FORMAT
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_L10N`` is set to ``True``, then locale format will
+be applied. See :ttag:`allowed date format strings <now>`.
+
+See also ``DATE_FORMAT``, ``TIME_FORMAT`` and ``SHORT_DATETIME_FORMAT``.
-See also ``DATE_FORMAT``, ``DATETIME_FORMAT``, ``TIME_FORMAT``,
-``YEAR_MONTH_FORMAT`` and ``MONTH_DAY_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
@@ -431,6 +471,14 @@ will be suppressed, and exceptions will propagate upwards. This can
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
@@ -680,6 +728,21 @@ system's standard umask.
.. _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 especially 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
@@ -701,6 +764,34 @@ environment variable in any HTTP request. This setting can be used to override
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
@@ -845,7 +936,7 @@ LOGIN_URL
Default: ``'/accounts/login/'``
-The URL where requests are redirected for login, specially when using the
+The URL where requests are redirected for login, especially when using the
:func:`~django.contrib.auth.decorators.login_required` decorator.
.. setting:: LOGOUT_URL
@@ -970,6 +1061,21 @@ locales have different formats. For example, U.S. English would say
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
@@ -1173,6 +1279,32 @@ Default: ``False``
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_L10N`` 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_L10N`` 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
@@ -1277,6 +1409,18 @@ The name of the method to use for starting the test suite. See
.. _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
@@ -1284,12 +1428,28 @@ TIME_FORMAT
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_L10N`` 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
@@ -1344,6 +1504,19 @@ A boolean that specifies whether to output the "Etag" header. This saves
bandwidth but slows down performance. This is only used if ``CommonMiddleware``
is installed (see :ref:`topics-http-middleware`).
+.. setting:: USE_L10N
+
+USE_L10N
+--------
+
+Default ``False``
+
+A boolean that specifies if data will be localized by default or not. If this
+is set to ``True``, e.g. Django will display numbers and dates using the
+format of the current locale.
+
+See also ``USE_I18N`` and ``LANGUAGE_CODE``
+
.. setting:: USE_I18N
USE_I18N
@@ -1356,6 +1529,22 @@ enabled. This provides an easy way to turn it off, for performance. If this is
set to ``False``, Django will make some optimizations so as not to load the
internationalization machinery.
+See also ``USE_L10N``
+
+.. 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_L10N`` must be set to ``True``, in order to format numbers.
+
+See also ``THOUSAND_SEPARATOR`` and ``NUMBER_GROUPING``.
+
.. setting:: YEAR_MONTH_FORMAT
YEAR_MONTH_FORMAT
diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
index bf2d9e899c..b7afa15f7f 100644
--- a/docs/ref/templates/builtins.txt
+++ b/docs/ref/templates/builtins.txt
@@ -1047,7 +1047,12 @@ If ``value`` is ``"String with spaces"``, the output will be ``"Stringwithspaces
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 predefined formats may
+vary depending on the current locale.
For example::
@@ -1062,7 +1067,7 @@ When used without a format string::
{{ value|date }}
...the formatting string defined in the :setting:`DATE_FORMAT` setting will be
-used.
+used, without applying any localization.
.. templatefilter:: default
@@ -1610,7 +1615,11 @@ output will be ``"Joel is a slug"``.
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.
@@ -1627,7 +1636,7 @@ When used without a format string::
{{ value|time }}
...the formatting string defined in the :setting:`TIME_FORMAT` setting will be
-used.
+used, without aplying any localization.
.. templatefilter:: timesince
diff --git a/docs/releases/1.2.txt b/docs/releases/1.2.txt
index 2111212054..200fb4a5b6 100644
--- a/docs/releases/1.2.txt
+++ b/docs/releases/1.2.txt
@@ -318,6 +318,41 @@ For more information, see the full
:ref:`messages documentation <ref-contrib-messages>`. You should begin to
update your code to use the new API immediately.
+Date format helper functions
+----------------------------
+
+``django.utils.translation.get_date_formats()`` and
+``django.utils.translation.get_partial_date_formats()`` have been deprecated
+in favor of the appropriate calls to ``django.utils.formats.get_format()``
+which is locale aware when :setting:`USE_L10N` is set to ``True``, and falls
+back to default settings if set to ``False``.
+
+To get the different date formats, instead of writing::
+
+ from django.utils.translation import get_date_formats
+ date_format, datetime_format, time_format = get_date_formats()
+
+use::
+
+ from django.utils import formats
+
+ date_format = formats.get_format('DATE_FORMAT')
+ datetime_format = formats.get_format('DATETIME_FORMAT')
+ time_format = formats.get_format('TIME_FORMAT')
+
+or, when directly formatting a date value::
+
+ from django.utils import formats
+ value_formatted = formats.date_format(value, 'DATETIME_FORMAT')
+
+The same applies to the globals found in ``django.forms.fields``:
+
+ * ``DEFAULT_DATE_INPUT_FORMATS``
+ * ``DEFAULT_TIME_INPUT_FORMATS``
+ * ``DEFAULT_DATETIME_INPUT_FORMATS``
+
+Use ``django.utils.formats.get_format()`` to get the appropriate formats.
+
What's new in Django 1.2
========================
@@ -440,3 +475,13 @@ The ``test`` subcommand of ``django-admin.py``, and the ``runtests.py`` script
used to run Django's own test suite, support a new ``--failfast`` option.
When specified, this option causes the test runner to exit after
encountering a failure instead of continuing with the test run.
+
+Improved localization
+---------------------
+
+Django's :ref:`internationalization framework <topics-i18n>` has been
+expanded by locale aware formatting and form processing. That means, if
+enabled, dates and numbers on templates will be displayed using the format
+specified for the current locale. Django will also use localized formats
+when parsing data in forms.
+See :ref:`Format localization <format-localization>` for more details.
diff --git a/docs/topics/i18n.txt b/docs/topics/i18n.txt
index c5f4ab6481..993c7b5285 100644
--- a/docs/topics/i18n.txt
+++ b/docs/topics/i18n.txt
@@ -4,20 +4,20 @@
Internationalization
====================
-Django has full support for internationalization of text in code and templates.
-Here's how it works.
+Django has full support for internationalization of text in code and
+templates, and format localization of 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 +29,12 @@ Essentially, Django does two things:
* 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_L10N = True <USE_L10N>` in your settings file. If
+:setting:`USE_L10N` is set to ``True``, 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 +1080,53 @@ have been found to not support this command. Do not attempt to use Django
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:
+
+Format localization
+===================
+
+Django's formatting system is disabled by default. To enable it, it's necessay
+to set :setting:`USE_L10N = True <USE_L10N>` in your settings file.
+
+When using Django's formatting system, dates and numbers on templates will be
+displayed using the format specified for the current locale. 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 might
+want to create your own, 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 your :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, and must be named ``formats.py``.
+
+To customize the 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 a thousand separator, instead of the default for English,
+a comma.
diff --git a/tests/regressiontests/i18n/misc.py b/tests/regressiontests/i18n/misc.py
deleted file mode 100644
index f8f35ad4e4..0000000000
--- a/tests/regressiontests/i18n/misc.py
+++ /dev/null
@@ -1,114 +0,0 @@
-import sys
-
-tests = """
->>> from django.utils.translation.trans_real import parse_accept_lang_header
->>> p = parse_accept_lang_header
-
-#
-# Testing HTTP header parsing. First, we test that we can parse the values
-# according to the spec (and that we extract all the pieces in the right order).
-#
-
-Good headers.
->>> p('de')
-[('de', 1.0)]
->>> p('en-AU')
-[('en-AU', 1.0)]
->>> p('*;q=1.00')
-[('*', 1.0)]
->>> p('en-AU;q=0.123')
-[('en-AU', 0.123)]
->>> p('en-au;q=0.1')
-[('en-au', 0.10000000000000001)]
->>> p('en-au;q=1.0')
-[('en-au', 1.0)]
->>> p('da, en-gb;q=0.25, en;q=0.5')
-[('da', 1.0), ('en', 0.5), ('en-gb', 0.25)]
->>> p('en-au-xx')
-[('en-au-xx', 1.0)]
->>> p('de,en-au;q=0.75,en-us;q=0.5,en;q=0.25,es;q=0.125,fa;q=0.125')
-[('de', 1.0), ('en-au', 0.75), ('en-us', 0.5), ('en', 0.25), ('es', 0.125), ('fa', 0.125)]
->>> p('*')
-[('*', 1.0)]
->>> p('de;q=0.')
-[('de', 1.0)]
->>> p('')
-[]
-
-Bad headers; should always return [].
->>> p('en-gb;q=1.0000')
-[]
->>> p('en;q=0.1234')
-[]
->>> p('en;q=.2')
-[]
->>> p('abcdefghi-au')
-[]
->>> p('**')
-[]
->>> p('en,,gb')
-[]
->>> p('en-au;q=0.1.0')
-[]
->>> p('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXZ,en')
-[]
->>> p('da, en-gb;q=0.8, en;q=0.7,#')
-[]
->>> p('de;q=2.0')
-[]
->>> p('de;q=0.a')
-[]
->>> p('')
-[]
-
-#
-# Now test that we parse a literal HTTP header correctly.
-#
-
->>> from django.utils.translation.trans_real import get_language_from_request
->>> g = get_language_from_request
->>> from django.http import HttpRequest
->>> r = HttpRequest
->>> r.COOKIES = {}
-
-These tests assumes the es, es_AR, pt and pt_BR translations exit in the Django
-source tree.
->>> r.META = {'HTTP_ACCEPT_LANGUAGE': 'pt-br'}
->>> g(r)
-'pt-br'
->>> r.META = {'HTTP_ACCEPT_LANGUAGE': 'pt'}
->>> g(r)
-'pt'
->>> r.META = {'HTTP_ACCEPT_LANGUAGE': 'es,de'}
->>> g(r)
-'es'
->>> r.META = {'HTTP_ACCEPT_LANGUAGE': 'es-ar,de'}
->>> g(r)
-'es-ar'
-"""
-
-# Python 2.3 and 2.4 return slightly different results for completely bogus
-# locales, so we omit this test for that anything below 2.4. It's relatively
-# harmless in any cases (GIGO). This also means this won't be executed on
-# Jython currently, but life's like that sometimes. (On those platforms,
-# passing in a truly bogus locale will get you the default locale back.)
-if sys.version_info >= (2, 5):
- tests += """
-This test assumes there won't be a Django translation to a US variation
-of the Spanish language, a safe assumption. When the user sets it
-as the preferred language, the main 'es' translation should be selected
-instead.
->>> r.META = {'HTTP_ACCEPT_LANGUAGE': 'es-us'}
->>> g(r)
-'es'
-"""
-
-tests += """
-This tests the following scenario: there isn't a main language (zh)
-translation of Django but there is a translation to variation (zh_CN)
-the user sets zh-cn as the preferred language, it should be selected by
-Django without falling back nor ignoring it.
->>> r.META = {'HTTP_ACCEPT_LANGUAGE': 'zh-cn,de'}
->>> g(r)
-'zh-cn'
-"""
diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
index 94e792cf54..c356970166 100644
--- a/tests/regressiontests/i18n/tests.py
+++ b/tests/regressiontests/i18n/tests.py
@@ -1,72 +1,375 @@
-# coding: utf-8
-import misc
-
-regressions = ur"""
-Format string interpolation should work with *_lazy objects.
-
->>> from django.utils.translation import ugettext, ugettext_lazy, activate, deactivate, gettext_lazy
->>> s = ugettext_lazy('Add %(name)s')
->>> d = {'name': 'Ringo'}
->>> s % d
-u'Add Ringo'
->>> activate('de')
->>> s % d
-u'Ringo hinzuf\xfcgen'
->>> activate('pl')
->>> s % d
-u'Dodaj Ringo'
->>> deactivate()
-
-It should be possible to compare *_lazy objects.
-
->>> s1 = ugettext_lazy('Add %(name)s')
->>> s == s1
-True
->>> s2 = gettext_lazy('Add %(name)s')
->>> s3 = gettext_lazy('Add %(name)s')
->>> s2 == s3
-True
->>> s == s2
-True
->>> s4 = ugettext_lazy('Some other string')
->>> s == s4
-False
-
-unicode(string_concat(...)) should not raise a TypeError - #4796
-
->>> import django.utils.translation
->>> reload(django.utils.translation)
-<module 'django.utils.translation' from ...>
->>> unicode(django.utils.translation.string_concat("dja", "ngo"))
-u'django'
-
-Translating a string requiring no auto-escaping shouldn't change the "safe"
-status.
-
->>> from django.utils.safestring import mark_safe, SafeString
->>> s = mark_safe('Password')
->>> type(s)
-<class 'django.utils.safestring.SafeString'>
->>> activate('de')
->>> type(ugettext(s))
-<class 'django.utils.safestring.SafeUnicode'>
->>> deactivate()
-
->>> SafeString('a') + s
-'aPassword'
->>> s + SafeString('a')
-'Passworda'
->>> s + mark_safe('a')
-'Passworda'
->>> mark_safe('a') + s
-'aPassword'
->>> mark_safe('a') + mark_safe('s')
-'as'
->>> print s
-Password
-"""
-
-__test__ = {
- 'regressions': regressions,
- 'misc': misc.tests,
-}
+import sys
+from django.test import TestCase, client
+from django.utils.translation import ugettext, ugettext_lazy, activate, deactivate, gettext_lazy
+
+class TranslationTests(TestCase):
+
+ def test_lazy_objects(self):
+ """
+ Format string interpolation should work with *_lazy objects.
+ """
+ s = ugettext_lazy('Add %(name)s')
+ d = {'name': 'Ringo'}
+ self.assertEqual(u'Add Ringo', s % d)
+ activate('de')
+ self.assertEqual(u'Ringo hinzuf\xfcgen', s % d)
+ activate('pl')
+ self.assertEqual(u'Dodaj Ringo', s % d)
+ deactivate()
+
+ # It should be possible to compare *_lazy objects.
+ s1 = ugettext_lazy('Add %(name)s')
+ self.assertEqual(True, s == s1)
+ s2 = gettext_lazy('Add %(name)s')
+ s3 = gettext_lazy('Add %(name)s')
+ self.assertEqual(True, s2 == s3)
+ self.assertEqual(True, s == s2)
+ s4 = ugettext_lazy('Some other string')
+ self.assertEqual(False, s == s4)
+
+ def test_string_concat(self):
+ """
+ unicode(string_concat(...)) should not raise a TypeError - #4796
+ """
+ import django.utils.translation
+ self.assertEqual(django.utils.translation, reload(django.utils.translation))
+ self.assertEqual(u'django', unicode(django.utils.translation.string_concat("dja", "ngo")))
+
+ def test_safe_status(self):
+ """
+ Translating a string requiring no auto-escaping shouldn't change the "safe" status.
+ """
+ from django.utils.safestring import mark_safe, SafeString, SafeUnicode
+ s = mark_safe('Password')
+ self.assertEqual(SafeString, type(s))
+ activate('de')
+ self.assertEqual(SafeUnicode, type(ugettext(s)))
+ deactivate()
+ self.assertEqual('aPassword', SafeString('a') + s)
+ self.assertEqual('Passworda', s + SafeString('a'))
+ self.assertEqual('Passworda', s + mark_safe('a'))
+ self.assertEqual('aPassword', mark_safe('a') + s)
+ self.assertEqual('as', mark_safe('a') + mark_safe('s'))
+ #self.assertEqual(Password, print s)
+
+ def test_maclines(self):
+ """
+ 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')
+ self.assertEqual(u'Catalan Mac\nEOF\n', ugettext(u'Mac\rEOF\r'))
+ self.assertEqual(u'Catalan Win\nEOF\n', ugettext(u'Win\r\nEOF\r\n'))
+ deactivate()
+
+ def test_dates_and_numbers(self):
+ """
+ Localization of dates and numbers
+ """
+ import datetime
+ import decimal
+ from django.conf import settings
+ from django.utils.formats import get_format, date_format, number_format, localize
+ from django.utils.numberformat import format
+ from django import template, forms
+ from django.forms.extras import SelectDateWidget
+
+ old_use_i18n = settings.USE_I18N
+ old_use_l10n = settings.USE_L10N
+ 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})
+
+ # Locale independent
+
+ 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)
+
+ settings.USE_L10N = True
+ settings.USE_THOUSAND_SEPARATOR = False
+ self.assertEqual(u'66666.66', format(n, decimal_sep='.', decimal_pos=2, grouping=3, thousand_sep=','))
+ self.assertEqual(u'66666A6', format(n, decimal_sep='A', decimal_pos=1, grouping=1, thousand_sep='B'))
+
+ settings.USE_THOUSAND_SEPARATOR = True
+ self.assertEqual(u'66,666.66', format(n, decimal_sep='.', decimal_pos=2, grouping=3, thousand_sep=','))
+ self.assertEqual(u'6B6B6B6B6A6', format(n, decimal_sep='A', decimal_pos=1, grouping=1, thousand_sep='B'))
+ self.assertEqual(u'-66666.6', format(-66666.666, decimal_sep='.', decimal_pos=1))
+ self.assertEqual(u'-66666.0', format(int('-66666'), decimal_sep='.', decimal_pos=1))
+
+ # Catalan locale with format i18n disabled translations will be used, but not formats
+
+ settings.USE_L10N = False
+ activate('ca')
+ self.assertEqual('N j, Y', get_format('DATE_FORMAT'))
+ self.assertEqual(0, get_format('FIRST_DAY_OF_WEEK'))
+ self.assertEqual('.', get_format('DECIMAL_SEPARATOR'))
+ self.assertEqual(u'des. 31, 2009', date_format(d))
+ self.assertEqual(u'desembre 2009', date_format(d, 'YEAR_MONTH_FORMAT'))
+ self.assertEqual(u'12/31/2009 8:50 p.m.', date_format(dt, 'SHORT_DATETIME_FORMAT'))
+ self.assertEqual('No localizable', localize('No localizable'))
+ self.assertEqual(decimal.Decimal('66666.666'), localize(n))
+ self.assertEqual(99999.999, localize(f))
+ self.assertEqual(datetime.date(2009, 12, 31), localize(d))
+ self.assertEqual(datetime.datetime(2009, 12, 31, 20, 50), localize(dt))
+ self.assertEqual(u'66666.666', template.Template('{{ n }}').render(ctxt))
+ self.assertEqual(u'99999.999', template.Template('{{ f }}').render(ctxt))
+ self.assertEqual(u'2009-12-31', template.Template('{{ d }}').render(ctxt))
+ self.assertEqual(u'2009-12-31 20:50:00', template.Template('{{ dt }}').render(ctxt))
+ self.assertEqual(u'66666.67', template.Template('{{ n|floatformat:2 }}').render(ctxt))
+ self.assertEqual(u'100000.0', template.Template('{{ f|floatformat }}').render(ctxt))
+ self.assertEqual(u'12/31/2009', template.Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(ctxt))
+ self.assertEqual(u'12/31/2009 8:50 p.m.', template.Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(ctxt))
+
+ 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'
+ })
+ self.assertEqual(False, form.is_valid())
+ self.assertEqual([u'Introdu\xefu un n\xfamero.'], form.errors['float_field'])
+ self.assertEqual([u'Introdu\xefu un n\xfamero.'], form.errors['decimal_field'])
+ self.assertEqual([u'Introdu\xefu una data v\xe0lida.'], form.errors['date_field'])
+ self.assertEqual([u'Introdu\xefu una data/hora v\xe0lides.'], form.errors['datetime_field'])
+
+ form2 = SelectDateForm({
+ 'date_field_month': u'12',
+ 'date_field_day': u'31',
+ 'date_field_year': u'2009'
+ })
+ self.assertEqual(True, form2.is_valid())
+ self.assertEqual(datetime.date(2009, 12, 31), form2.cleaned_data['date_field'])
+ self.assertEqual(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>', SelectDateWidget().render('mydate', datetime.date(2009, 12, 31)))
+ deactivate()
+
+ # Catalan locale
+
+ settings.USE_L10N = True
+ activate('ca')
+ self.assertEqual('j \de F \de Y', get_format('DATE_FORMAT'))
+ self.assertEqual(1, get_format('FIRST_DAY_OF_WEEK'))
+ self.assertEqual(',', get_format('DECIMAL_SEPARATOR'))
+ self.assertEqual(u'31 de desembre de 2009', date_format(d))
+ self.assertEqual(u'desembre del 2009', date_format(d, 'YEAR_MONTH_FORMAT'))
+ self.assertEqual(u'31/12/2009 20:50', date_format(dt, 'SHORT_DATETIME_FORMAT'))
+ self.assertEqual('No localizable', localize('No localizable'))
+
+ settings.USE_THOUSAND_SEPARATOR = True
+ self.assertEqual(u'66.666,666', localize(n))
+ self.assertEqual(u'99.999,999', localize(f))
+
+ settings.USE_THOUSAND_SEPARATOR = False
+ self.assertEqual(u'66666,666', localize(n))
+ self.assertEqual(u'99999,999', localize(f))
+ self.assertEqual(u'31 de desembre de 2009', localize(d))
+ self.assertEqual(u'31 de desembre de 2009 a les 20:50', localize(dt))
+
+ settings.USE_THOUSAND_SEPARATOR = True
+ self.assertEqual(u'66.666,666', template.Template('{{ n }}').render(ctxt))
+ self.assertEqual(u'99.999,999', template.Template('{{ f }}').render(ctxt))
+
+ settings.USE_THOUSAND_SEPARATOR = False
+ self.assertEqual(u'66666,666', template.Template('{{ n }}').render(ctxt))
+ self.assertEqual(u'99999,999', template.Template('{{ f }}').render(ctxt))
+ self.assertEqual(u'31 de desembre de 2009', template.Template('{{ d }}').render(ctxt))
+ self.assertEqual(u'31 de desembre de 2009 a les 20:50', template.Template('{{ dt }}').render(ctxt))
+ self.assertEqual(u'66666,67', template.Template('{{ n|floatformat:2 }}').render(ctxt))
+ self.assertEqual(u'100000,0', template.Template('{{ f|floatformat }}').render(ctxt))
+ self.assertEqual(u'31/12/2009', template.Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(ctxt))
+ self.assertEqual(u'31/12/2009 20:50', template.Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(ctxt))
+
+ form3 = 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'
+ })
+ self.assertEqual(True, form3.is_valid())
+ self.assertEqual(decimal.Decimal('66666.666'), form3.cleaned_data['decimal_field'])
+ self.assertEqual(99999.999, form3.cleaned_data['float_field'])
+ self.assertEqual(datetime.date(2009, 12, 31), form3.cleaned_data['date_field'])
+ self.assertEqual(datetime.datetime(2009, 12, 31, 20, 50), form3.cleaned_data['datetime_field'])
+ self.assertEqual(datetime.time(20, 50), form3.cleaned_data['time_field'])
+
+ form4 = SelectDateForm({
+ 'date_field_month': u'12',
+ 'date_field_day': u'31',
+ 'date_field_year': u'2009'
+ })
+ self.assertEqual(True, form4.is_valid())
+ self.assertEqual(datetime.date(2009, 12, 31), form4.cleaned_data['date_field'])
+ self.assertEqual(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>', SelectDateWidget().render('mydate', datetime.date(2009, 12, 31)))
+ deactivate()
+
+ # English locale
+
+ settings.USE_L10N = True
+ activate('en')
+ self.assertEqual('N j, Y', get_format('DATE_FORMAT'))
+ self.assertEqual(0, get_format('FIRST_DAY_OF_WEEK'))
+ self.assertEqual('.', get_format('DECIMAL_SEPARATOR'))
+ self.assertEqual(u'Dec. 31, 2009', date_format(d))
+ self.assertEqual(u'December 2009', date_format(d, 'YEAR_MONTH_FORMAT'))
+ self.assertEqual(u'12/31/2009 8:50 p.m.', date_format(dt, 'SHORT_DATETIME_FORMAT'))
+ self.assertEqual('No localizable', localize('No localizable'))
+
+ settings.USE_THOUSAND_SEPARATOR = True
+ self.assertEqual(u'66,666.666', localize(n))
+ self.assertEqual(u'99,999.999', localize(f))
+
+ settings.USE_THOUSAND_SEPARATOR = False
+ self.assertEqual(u'66666.666', localize(n))
+ self.assertEqual(u'99999.999', localize(f))
+ self.assertEqual(u'Dec. 31, 2009', localize(d))
+ self.assertEqual(u'Dec. 31, 2009, 8:50 p.m.', localize(dt))
+
+ settings.USE_THOUSAND_SEPARATOR = True
+ self.assertEqual(u'66,666.666', template.Template('{{ n }}').render(ctxt))
+ self.assertEqual(u'99,999.999', template.Template('{{ f }}').render(ctxt))
+
+ settings.USE_THOUSAND_SEPARATOR = False
+ self.assertEqual(u'66666.666', template.Template('{{ n }}').render(ctxt))
+ self.assertEqual(u'99999.999', template.Template('{{ f }}').render(ctxt))
+ self.assertEqual(u'Dec. 31, 2009', template.Template('{{ d }}').render(ctxt))
+ self.assertEqual(u'Dec. 31, 2009, 8:50 p.m.', template.Template('{{ dt }}').render(ctxt))
+ self.assertEqual(u'66666.67', template.Template('{{ n|floatformat:2 }}').render(ctxt))
+ self.assertEqual(u'100000.0', template.Template('{{ f|floatformat }}').render(ctxt))
+ self.assertEqual(u'12/31/2009', template.Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(ctxt))
+ self.assertEqual(u'12/31/2009 8:50 p.m.', template.Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(ctxt))
+
+ form5 = 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'
+ })
+ self.assertEqual(True, form5.is_valid())
+ self.assertEqual(decimal.Decimal('66666.666'), form5.cleaned_data['decimal_field'])
+ self.assertEqual(99999.999, form5.cleaned_data['float_field'])
+ self.assertEqual(datetime.date(2009, 12, 31), form5.cleaned_data['date_field'])
+ self.assertEqual(datetime.datetime(2009, 12, 31, 20, 50), form5.cleaned_data['datetime_field'])
+ self.assertEqual(datetime.time(20, 50), form5.cleaned_data['time_field'])
+
+ form6 = SelectDateForm({
+ 'date_field_month': u'12',
+ 'date_field_day': u'31',
+ 'date_field_year': u'2009'
+ })
+ self.assertEqual(True, form6.is_valid())
+ self.assertEqual(datetime.date(2009, 12, 31), form6.cleaned_data['date_field'])
+ self.assertEqual(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>', SelectDateWidget().render('mydate', datetime.date(2009, 12, 31)))
+ deactivate()
+
+ # Check if sublocales fall back to the main locale
+ activate('de-at')
+ settings.USE_THOUSAND_SEPARATOR = True
+ self.assertEqual(u'66.666,666', template.Template('{{ n }}').render(ctxt))
+ deactivate()
+
+ activate('es-ar')
+ self.assertEqual(u'31 de Diciembre de 2009', date_format(d))
+ deactivate()
+
+ # Restore defaults
+ settings.USE_I18N = old_use_i18n
+ settings.USE_L10N = old_use_l10n
+ settings.USE_THOUSAND_SEPARATOR = old_use_thousand_separator
+
+
+class MiscTests(TestCase):
+
+ def test_parse_spec_http_header(self):
+ """
+ Testing HTTP header parsing. First, we test that we can parse the
+ values according to the spec (and that we extract all the pieces in
+ the right order).
+ """
+ from django.utils.translation.trans_real import parse_accept_lang_header
+ p = parse_accept_lang_header
+ # Good headers.
+ self.assertEqual([('de', 1.0)], p('de'))
+ self.assertEqual([('en-AU', 1.0)], p('en-AU'))
+ self.assertEqual([('*', 1.0)], p('*;q=1.00'))
+ self.assertEqual([('en-AU', 0.123)], p('en-AU;q=0.123'))
+ self.assertEqual([('en-au', 0.10000000000000001)], p('en-au;q=0.1'))
+ self.assertEqual([('en-au', 1.0)], p('en-au;q=1.0'))
+ self.assertEqual([('da', 1.0), ('en', 0.5), ('en-gb', 0.25)], p('da, en-gb;q=0.25, en;q=0.5'))
+ self.assertEqual([('en-au-xx', 1.0)], p('en-au-xx'))
+ self.assertEqual([('de', 1.0), ('en-au', 0.75), ('en-us', 0.5), ('en', 0.25), ('es', 0.125), ('fa', 0.125)], p('de,en-au;q=0.75,en-us;q=0.5,en;q=0.25,es;q=0.125,fa;q=0.125'))
+ self.assertEqual([('*', 1.0)], p('*'))
+ self.assertEqual([('de', 1.0)], p('de;q=0.'))
+ self.assertEqual([], p(''))
+
+ # Bad headers; should always return [].
+ self.assertEqual([], p('en-gb;q=1.0000'))
+ self.assertEqual([], p('en;q=0.1234'))
+ self.assertEqual([], p('en;q=.2'))
+ self.assertEqual([], p('abcdefghi-au'))
+ self.assertEqual([], p('**'))
+ self.assertEqual([], p('en,,gb'))
+ self.assertEqual([], p('en-au;q=0.1.0'))
+ self.assertEqual([], p('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXZ,en'))
+ self.assertEqual([], p('da, en-gb;q=0.8, en;q=0.7,#'))
+ self.assertEqual([], p('de;q=2.0'))
+ self.assertEqual([], p('de;q=0.a'))
+ self.assertEqual([], p(''))
+
+ def test_parse_literal_http_header(self):
+ """
+ Now test that we parse a literal HTTP header correctly.
+ """
+ from django.utils.translation.trans_real import get_language_from_request
+ g = get_language_from_request
+ from django.http import HttpRequest
+ r = HttpRequest
+ r.COOKIES = {}
+ r.META = {'HTTP_ACCEPT_LANGUAGE': 'pt-br'}
+ self.assertEqual('pt-br', g(r))
+
+ r.META = {'HTTP_ACCEPT_LANGUAGE': 'pt'}
+ self.assertEqual('pt', g(r))
+
+ r.META = {'HTTP_ACCEPT_LANGUAGE': 'es,de'}
+ self.assertEqual('es', g(r))
+
+ r.META = {'HTTP_ACCEPT_LANGUAGE': 'es-ar,de'}
+ self.assertEqual('es-ar', g(r))
+
+ # Python 2.3 and 2.4 return slightly different results for completely
+ # bogus locales, so we omit this test for that anything below 2.4.
+ # It's relatively harmless in any cases (GIGO). This also means this
+ # won't be executed on Jython currently, but life's like that
+ # sometimes. (On those platforms, passing in a truly bogus locale
+ # will get you the default locale back.)
+ if sys.version_info >= (2, 5):
+ # This test assumes there won't be a Django translation to a US
+ # variation of the Spanish language, a safe assumption. When the
+ # user sets it as the preferred language, the main 'es'
+ # translation should be selected instead.
+ r.META = {'HTTP_ACCEPT_LANGUAGE': 'es-us'}
+ self.assertEqual(g(r), 'es')
+
+ # This tests the following scenario: there isn't a main language (zh)
+ # translation of Django but there is a translation to variation (zh_CN)
+ # the user sets zh-cn as the preferred language, it should be selected
+ # by Django without falling back nor ignoring it.
+ r.META = {'HTTP_ACCEPT_LANGUAGE': 'zh-cn,de'}
+ self.assertEqual(g(r), 'zh-cn')