From fa0653cd1d791a8bce835e8992cbeab6fd70d0e7 Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Wed, 30 Dec 2009 22:12:16 +0000 Subject: [PATCH] Fixed #12454 - Added support for localized formats to admin date and time widgets. git-svn-id: http://code.djangoproject.com/svn/django/trunk@12030 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- .../admin/media/js/admin/DateTimeShortcuts.js | 21 ++++++---- django/contrib/admin/media/js/core.js | 39 +++++++++++++++++++ django/utils/formats.py | 6 ++- django/views/i18n.py | 24 +++++++----- 4 files changed, 72 insertions(+), 18 deletions(-) diff --git a/django/contrib/admin/media/js/admin/DateTimeShortcuts.js b/django/contrib/admin/media/js/admin/DateTimeShortcuts.js index e3ebd03fb2..bae84f267f 100644 --- a/django/contrib/admin/media/js/admin/DateTimeShortcuts.js +++ b/django/contrib/admin/media/js/admin/DateTimeShortcuts.js @@ -44,7 +44,7 @@ var DateTimeShortcuts = { var shortcuts_span = document.createElement('span'); inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling); var now_link = document.createElement('a'); - now_link.setAttribute('href', "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().getHourMinuteSecond());"); + now_link.setAttribute('href', "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + gettext('TIME_INPUT_FORMATS') + "'));"); now_link.appendChild(document.createTextNode(gettext('Now'))); var clock_link = document.createElement('a'); clock_link.setAttribute('href', 'javascript:DateTimeShortcuts.openClock(' + num + ');'); @@ -80,10 +80,10 @@ var DateTimeShortcuts = { quickElement('h2', clock_box, gettext('Choose a time')); time_list = quickElement('ul', clock_box, ''); time_list.className = 'timelist'; - quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().getHourMinuteSecond());") - quickElement("a", quickElement("li", time_list, ""), gettext("Midnight"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", '00:00:00');") - quickElement("a", quickElement("li", time_list, ""), gettext("6 a.m."), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", '06:00:00');") - quickElement("a", quickElement("li", time_list, ""), gettext("Noon"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", '12:00:00');") + quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + gettext('TIME_INPUT_FORMATS') + "'));") + quickElement("a", quickElement("li", time_list, ""), gettext("Midnight"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,0,0,0,0).strftime('" + gettext('TIME_INPUT_FORMATS') + "'));") + quickElement("a", quickElement("li", time_list, ""), gettext("6 a.m."), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,6,0,0,0).strftime('" + gettext('TIME_INPUT_FORMATS') + "'));") + quickElement("a", quickElement("li", time_list, ""), gettext("Noon"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,12,0,0,0).strftime('" + gettext('TIME_INPUT_FORMATS') + "'));") cancel_p = quickElement('p', clock_box, ''); cancel_p.className = 'calendar-cancel'; @@ -237,12 +237,19 @@ var DateTimeShortcuts = { DateTimeShortcuts.calendars[num].drawNextMonth(); }, handleCalendarCallback: function(num) { - return "function(y, m, d) { DateTimeShortcuts.calendarInputs["+num+"].value = y+'-'+(m<10?'0':'')+m+'-'+(d<10?'0':'')+d; document.getElementById(DateTimeShortcuts.calendarDivName1+"+num+").style.display='none';}"; + format = gettext('DATE_INPUT_FORMATS'); + // the format needs to be escaped a little + format = format.replace('\\', '\\\\'); + format = format.replace('\r', '\\r'); + format = format.replace('\n', '\\n'); + format = format.replace('\t', '\\t'); + format = format.replace("'", "\\'"); + return "function(y, m, d) { DateTimeShortcuts.calendarInputs["+num+"].value = new Date(y, m-1, d).strftime('"+format+"');document.getElementById(DateTimeShortcuts.calendarDivName1+"+num+").style.display='none';}" }, handleCalendarQuickLink: function(num, offset) { var d = new Date(); d.setDate(d.getDate() + offset) - DateTimeShortcuts.calendarInputs[num].value = d.getISODate(); + DateTimeShortcuts.calendarInputs[num].value = d.strftime(gettext('DATE_INPUT_FORMATS')); DateTimeShortcuts.dismissCalendar(num); }, cancelEventPropagation: function(e) { diff --git a/django/contrib/admin/media/js/core.js b/django/contrib/admin/media/js/core.js index c8d0db6a8d..a7192c17f1 100644 --- a/django/contrib/admin/media/js/core.js +++ b/django/contrib/admin/media/js/core.js @@ -115,6 +115,10 @@ Date.prototype.getCorrectYear = function() { return (y < 38) ? y + 2000 : y + 1900; } +Date.prototype.getTwelveHours = function() { + return (this.getHours() <= 12) ? this.getHours() : 24 - this.getHours(); +} + Date.prototype.getTwoDigitMonth = function() { return (this.getMonth() < 9) ? '0' + (this.getMonth()+1) : (this.getMonth()+1); } @@ -123,6 +127,10 @@ Date.prototype.getTwoDigitDate = function() { return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate(); } +Date.prototype.getTwoDigitTwelveHour = function() { + return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours(); +} + Date.prototype.getTwoDigitHour = function() { return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours(); } @@ -147,6 +155,37 @@ Date.prototype.getHourMinuteSecond = function() { return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute() + ':' + this.getTwoDigitSecond(); } +Date.prototype.strftime = function(format) { + var fields = { + c: this.toString(), + d: this.getTwoDigitDate(), + H: this.getTwoDigitHour(), + I: this.getTwoDigitTwelveHour(), + m: this.getTwoDigitMonth(), + M: this.getTwoDigitMinute(), + p: (this.getHours() >= 12) ? 'PM' : 'AM', + S: this.getTwoDigitSecond(), + w: '0' + this.getDay(), + x: this.toLocaleDateString(), + X: this.toLocaleTimeString(), + y: ('' + this.getFullYear()).substr(2, 4), + Y: '' + this.getFullYear(), + '%' : '%' + }; + var result = '', i = 0; + while (i < format.length) { + if (format[i] === '%') { + result = result + fields[format[i + 1]]; + ++i; + } + else { + result = result + format[i]; + } + ++i; + } + return result; +} + // ---------------------------------------------------------------------------- // String object extensions // ---------------------------------------------------------------------------- diff --git a/django/utils/formats.py b/django/utils/formats.py index 92e7e7f538..39b4ac2d61 100644 --- a/django/utils/formats.py +++ b/django/utils/formats.py @@ -7,12 +7,12 @@ from django.utils.importlib import import_module from django.utils.encoding import smart_str from django.utils import dateformat, numberformat, datetime_safe -def get_format_modules(): +def get_format_modules(reverse=False): """ Returns an iterator over the format modules found in the project and Django """ modules = [] - if not check_for_language(get_language()): + if not check_for_language(get_language()) or not settings.USE_L10N: return modules locale = to_locale(get_language()) if settings.FORMAT_MODULE_PATH: @@ -30,6 +30,8 @@ def get_format_modules(): # Don't return duplicates if mod not in modules: modules.append(mod) + if reverse: + modules.reverse() return modules def get_format(format_type): diff --git a/django/views/i18n.py b/django/views/i18n.py index 17f5613de5..6a1ee514cd 100644 --- a/django/views/i18n.py +++ b/django/views/i18n.py @@ -37,15 +37,17 @@ def set_language(request): def get_formats(): """ - Returns an iterator over all formats in formats file + Returns all formats strings required for i18n to work """ - FORMAT_SETTINGS = ('DATE_FORMAT', 'DATETIME_FORMAT', 'TIME_FORMAT', + 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') - + 'THOUSAND_SEPARATOR', 'NUMBER_GROUPING', + 'DATE_INPUT_FORMATS', 'TIME_INPUT_FORMATS', 'DATETIME_INPUT_FORMATS' + ) result = {} - for module in [settings] + get_format_modules(): + for module in [settings] + get_format_modules(reverse=True): for attr in FORMAT_SETTINGS: try: result[attr] = getattr(module, attr) @@ -141,7 +143,7 @@ def javascript_catalog(request, domain='djangojs', packages=None): activate(request.GET['language']) if packages is None: packages = ['django.conf'] - if type(packages) in (str, unicode): + if isinstance(packages, basestring): packages = packages.split('+') packages = [p for p in packages if p == 'django.conf' or p in settings.INSTALLED_APPS] default_locale = to_locale(settings.LANGUAGE_CODE) @@ -195,9 +197,9 @@ def javascript_catalog(request, domain='djangojs', packages=None): for k, v in t.items(): if k == '': continue - if type(k) in (str, unicode): + if isinstance(k, basestring): csrc.append("catalog['%s'] = '%s';\n" % (javascript_quote(k), javascript_quote(v))) - elif type(k) == tuple: + elif isinstance(k, tuple): if k[0] not in pdict: pdict[k[0]] = k[1] else: @@ -209,7 +211,11 @@ def javascript_catalog(request, domain='djangojs', packages=None): 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(smart_unicode(v)))) + if isinstance(v, (basestring, int)): + src.append("catalog['%s'] = '%s';\n" % (javascript_quote(k), javascript_quote(smart_unicode(v)))) + elif isinstance(v, (tuple, list)): + v = [javascript_quote(smart_unicode(value)) for value in v] + src.append("catalog['%s'] = ['%s'];\n" % (javascript_quote(k), "', '".join(v))) src.extend(csrc) src.append(LibFoot) src.append(InterPolate)