Commit 399e5209 by Ned Batchelder

Merge pull request #2608 from edx/ned/date-l10n

strftime_localized
parents c246f7da de5f3028
...@@ -16,13 +16,13 @@ from xmodule.contentstore.django import contentstore ...@@ -16,13 +16,13 @@ from xmodule.contentstore.django import contentstore
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from xmodule.modulestore import Location from xmodule.modulestore import Location
from xmodule.contentstore.content import StaticContent from xmodule.contentstore.content import StaticContent
from xmodule.util.date_utils import get_default_time_display
from xmodule.modulestore import InvalidLocationError from xmodule.modulestore import InvalidLocationError
from xmodule.exceptions import NotFoundError from xmodule.exceptions import NotFoundError
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from xmodule.modulestore.django import loc_mapper from xmodule.modulestore.django import loc_mapper
from xmodule.modulestore.locator import BlockUsageLocator from xmodule.modulestore.locator import BlockUsageLocator
from util.date_utils import get_default_time_display
from util.json_request import JsonResponse from util.json_request import JsonResponse
from django.http import HttpResponseNotFound from django.http import HttpResponseNotFound
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
......
...@@ -10,8 +10,8 @@ from django.conf import settings ...@@ -10,8 +10,8 @@ from django.conf import settings
from xmodule.modulestore.exceptions import ItemNotFoundError from xmodule.modulestore.exceptions import ItemNotFoundError
from edxmako.shortcuts import render_to_response from edxmako.shortcuts import render_to_response
from util.date_utils import get_default_time_display
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from xmodule.util.date_utils import get_default_time_display
from xmodule.modulestore.django import loc_mapper from xmodule.modulestore.django import loc_mapper
from xmodule.modulestore.locator import BlockUsageLocator from xmodule.modulestore.locator import BlockUsageLocator
......
<%inherit file="base.html" /> <%inherit file="base.html" />
<%! <%!
import logging import logging
from xmodule.util.date_utils import get_default_time_display, almost_same_datetime from util.date_utils import get_default_time_display, almost_same_datetime
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
%> %>
......
<%inherit file="base.html" /> <%inherit file="base.html" />
<%! <%!
import logging import logging
from xmodule.util import date_utils from util.date_utils import get_default_time_display
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from xmodule.modulestore.django import loc_mapper from xmodule.modulestore.django import loc_mapper
...@@ -188,7 +188,7 @@ require(["domReady!", "jquery", "js/models/location", "js/models/section", "js/v ...@@ -188,7 +188,7 @@ require(["domReady!", "jquery", "js/models/location", "js/models/section", "js/v
<a href="#" class="edit-release-date action" data-date="" data-time="" data-locator="${section_locator}"><i class="icon-time"></i> <span class="sr">${_("Schedule")}</span></a> <a href="#" class="edit-release-date action" data-date="" data-time="" data-locator="${section_locator}"><i class="icon-time"></i> <span class="sr">${_("Schedule")}</span></a>
%else: %else:
<span class="published-status"><strong>${_("Release date:")}</strong> <span class="published-status"><strong>${_("Release date:")}</strong>
${date_utils.get_default_time_display(section.start)}</span> ${get_default_time_display(section.start)}</span>
<a href="#" class="edit-release-date action" data-date="${start_date_str}" data-time="${start_time_str}" data-locator="${section_locator}"><i class="icon-time"></i> <span class="sr">${_("Edit section release date")}</span></a> <a href="#" class="edit-release-date action" data-date="${start_date_str}" data-time="${start_time_str}" data-locator="${section_locator}"><i class="icon-time"></i> <span class="sr">${_("Edit section release date")}</span></a>
%endif %endif
</div> </div>
......
"""
Convenience methods for working with datetime objects
"""
from datetime import timedelta
import re
from pytz import timezone, UTC, UnknownTimeZoneError
from django.utils.translation import pgettext, ugettext
def get_default_time_display(dtime):
"""
Converts a datetime to a string representation. This is the default
representation used in Studio and LMS.
It will use the "DATE_TIME" format in the current language, if provided,
or defaults to "Apr 09, 2013 at 16:00 UTC".
If None is passed in for dt, an empty string will be returned.
"""
if dtime is None:
return u""
if dtime.tzinfo is not None:
try:
timezone = u" " + dtime.tzinfo.tzname(dtime)
except NotImplementedError:
timezone = dtime.strftime('%z')
else:
timezone = u" UTC"
localized = strftime_localized(dtime, "DATE_TIME")
return (localized + timezone).strip()
def get_time_display(dtime, format_string=None, coerce_tz=None):
"""
Converts a datetime to a string representation.
If None is passed in for dt, an empty string will be returned.
If the format_string is None, or if format_string is improperly
formatted, this method will return the value from `get_default_time_display`.
Coerces aware datetime to tz=coerce_tz if set. coerce_tz should be a pytz timezone string
like "US/Pacific", or None
format_string should be a unicode string that is a valid argument for datetime's strftime method.
"""
if dtime is not None and dtime.tzinfo is not None and coerce_tz:
try:
to_tz = timezone(coerce_tz)
except UnknownTimeZoneError:
to_tz = UTC
dtime = to_tz.normalize(dtime.astimezone(to_tz))
if dtime is None or format_string is None:
return get_default_time_display(dtime)
try:
return unicode(strftime_localized(dtime, format_string))
except ValueError:
return get_default_time_display(dtime)
def almost_same_datetime(dt1, dt2, allowed_delta=timedelta(minutes=1)):
"""
Returns true if these are w/in a minute of each other. (in case secs saved to db
or timezone aren't same)
:param dt1:
:param dt2:
"""
return abs(dt1 - dt2) < allowed_delta
DEFAULT_SHORT_DATE_FORMAT = "%b %d, %Y"
DEFAULT_LONG_DATE_FORMAT = "%A, %B %d, %Y"
DEFAULT_TIME_FORMAT = "%I:%M:%S %p"
DEFAULT_DATE_TIME_FORMAT = "%b %d, %Y at %H:%M"
def strftime_localized(dtime, format): # pylint: disable=redefined-builtin
"""
Format a datetime, just like the built-in strftime, but with localized words.
The format string can also be one of:
* "SHORT_DATE" for a date in brief form, localized.
* "LONG_DATE" for a longer form of date, localized.
* "DATE_TIME" for a date and time together, localized.
* "TIME" for just the time, localized.
The localization is based on the current language Django is using for the
request. The exact format strings used for each of the names above is
determined by the translator for each language.
Args:
dtime (datetime): The datetime value to format.
format (str): The format string to use, as specified by
:ref:`datetime.strftime`.
Returns:
A unicode string with the formatted datetime.
"""
if format == "SHORT_DATE":
format = "%x"
elif format == "LONG_DATE":
# Translators: the translation for "LONG_DATE_FORMAT" must be a format
# string for formatting dates in a long form. For example, the
# American English form is "%A, %B %d %Y".
# See http://strftime.org for details.
format = ugettext("LONG_DATE_FORMAT")
if format == "LONG_DATE_FORMAT":
format = DEFAULT_LONG_DATE_FORMAT
elif format == "DATE_TIME":
# Translators: the translation for "DATE_TIME_FORMAT" must be a format
# string for formatting dates with times. For example, the American
# English form is "%b %d, %Y at %H:%M".
# See http://strftime.org for details.
format = ugettext("DATE_TIME_FORMAT")
if format == "DATE_TIME_FORMAT":
format = DEFAULT_DATE_TIME_FORMAT
elif format == "TIME":
format = "%X"
def process_percent_code(match):
"""
Convert one percent-prefixed code in the format string.
Called by re.sub just below.
"""
code = match.group()
if code == "%":
# This only happens if the string ends with a %, which is not legal.
raise ValueError("strftime format ends with raw %")
if code == "%a":
part = pgettext('abbreviated weekday name', WEEKDAYS_ABBREVIATED[dtime.weekday()])
elif code == "%A":
part = pgettext('weekday name', WEEKDAYS[dtime.weekday()])
elif code == "%b":
part = pgettext('abbreviated month name', MONTHS_ABBREVIATED[dtime.month])
elif code == "%B":
part = pgettext('month name', MONTHS[dtime.month])
elif code == "%p":
part = pgettext('am/pm indicator', AM_PM[dtime.hour // 12])
elif code == "%x":
# Get the localized short date format, and recurse.
# Translators: the translation for "SHORT_DATE_FORMAT" must be a
# format string for formatting dates in a brief form. For example,
# the American English form is "%b %d %Y".
# See http://strftime.org for details.
actual_format = ugettext("SHORT_DATE_FORMAT")
if actual_format == "SHORT_DATE_FORMAT":
actual_format = DEFAULT_SHORT_DATE_FORMAT
if "%x" in actual_format:
# Prevent infinite accidental recursion.
actual_format = DEFAULT_SHORT_DATE_FORMAT
part = strftime_localized(dtime, actual_format)
elif code == "%X":
# Get the localized time format, and recurse.
# Translators: the translation for "TIME_FORMAT" must be a format
# string for formatting times. For example, the American English
# form is "%H:%M:%S". See http://strftime.org for details.
actual_format = ugettext("TIME_FORMAT")
if actual_format == "TIME_FORMAT":
actual_format = DEFAULT_TIME_FORMAT
if "%X" in actual_format:
# Prevent infinite accidental recursion.
actual_format = DEFAULT_TIME_FORMAT
part = strftime_localized(dtime, actual_format)
else:
# All the other format codes: just let built-in strftime take
# care of them.
part = dtime.strftime(code)
return part
formatted_date = re.sub(r"%.|%", process_percent_code, format)
return formatted_date
# In order to extract the strings below, we have to mark them with pgettext.
# But we'll do the actual pgettext later, so use a no-op for now, and save the
# real pgettext so we can assign it back to the global name later.
real_pgettext = pgettext
pgettext = lambda context, text: text # pylint: disable=invalid-name
AM_PM = {
# Translators: This is an AM/PM indicator for displaying times. It is
# used for the %p directive in date-time formats. See http://strftime.org
# for details.
0: pgettext('am/pm indicator', 'AM'),
# Translators: This is an AM/PM indicator for displaying times. It is
# used for the %p directive in date-time formats. See http://strftime.org
# for details.
1: pgettext('am/pm indicator', 'PM'),
}
WEEKDAYS = {
# Translators: this is a weekday name that will be used when displaying
# dates, as in "Monday Februrary 10, 2014". It is used for the %A
# directive in date-time formats. See http://strftime.org for details.
0: pgettext('weekday name', 'Monday'),
# Translators: this is a weekday name that will be used when displaying
# dates, as in "Tuesday Februrary 11, 2014". It is used for the %A
# directive in date-time formats. See http://strftime.org for details.
1: pgettext('weekday name', 'Tuesday'),
# Translators: this is a weekday name that will be used when displaying
# dates, as in "Wednesday Februrary 12, 2014". It is used for the %A
# directive in date-time formats. See http://strftime.org for details.
2: pgettext('weekday name', 'Wednesday'),
# Translators: this is a weekday name that will be used when displaying
# dates, as in "Thursday Februrary 13, 2014". It is used for the %A
# directive in date-time formats. See http://strftime.org for details.
3: pgettext('weekday name', 'Thursday'),
# Translators: this is a weekday name that will be used when displaying
# dates, as in "Friday Februrary 14, 2014". It is used for the %A
# directive in date-time formats. See http://strftime.org for details.
4: pgettext('weekday name', 'Friday'),
# Translators: this is a weekday name that will be used when displaying
# dates, as in "Saturday Februrary 15, 2014". It is used for the %A
# directive in date-time formats. See http://strftime.org for details.
5: pgettext('weekday name', 'Saturday'),
# Translators: this is a weekday name that will be used when displaying
# dates, as in "Sunday Februrary 16, 2014". It is used for the %A
# directive in date-time formats. See http://strftime.org for details.
6: pgettext('weekday name', 'Sunday'),
}
WEEKDAYS_ABBREVIATED = {
# Translators: this is an abbreviated weekday name that will be used when
# displaying dates, as in "Mon Feb 10, 2014". It is used for the %a
# directive in date-time formats. See http://strftime.org for details.
0: pgettext('abbreviated weekday name', 'Mon'),
# Translators: this is an abbreviated weekday name that will be used when
# displaying dates, as in "Tue Feb 11, 2014". It is used for the %a
# directive in date-time formats. See http://strftime.org for details.
1: pgettext('abbreviated weekday name', 'Tue'),
# Translators: this is an abbreviated weekday name that will be used when
# displaying dates, as in "Wed Feb 12, 2014". It is used for the %a
# directive in date-time formats. See http://strftime.org for details.
2: pgettext('abbreviated weekday name', 'Wed'),
# Translators: this is an abbreviated weekday name that will be used when
# displaying dates, as in "Thu Feb 13, 2014". It is used for the %a
# directive in date-time formats. See http://strftime.org for details.
3: pgettext('abbreviated weekday name', 'Thu'),
# Translators: this is an abbreviated weekday name that will be used when
# displaying dates, as in "Fri Feb 14, 2014". It is used for the %a
# directive in date-time formats. See http://strftime.org for details.
4: pgettext('abbreviated weekday name', 'Fri'),
# Translators: this is an abbreviated weekday name that will be used when
# displaying dates, as in "Sat Feb 15, 2014". It is used for the %a
# directive in date-time formats. See http://strftime.org for details.
5: pgettext('abbreviated weekday name', 'Sat'),
# Translators: this is an abbreviated weekday name that will be used when
# displaying dates, as in "Sun Feb 16, 2014". It is used for the %a
# directive in date-time formats. See http://strftime.org for details.
6: pgettext('abbreviated weekday name', 'Sun'),
}
MONTHS_ABBREVIATED = {
# Translators: this is an abbreviated month name that will be used when
# displaying dates, as in "Jan 10, 2014". It is used for the %b
# directive in date-time formats. See http://strftime.org for details.
1: pgettext('abbreviated month name', 'Jan'),
# Translators: this is an abbreviated month name that will be used when
# displaying dates, as in "Feb 10, 2014". It is used for the %b
# directive in date-time formats. See http://strftime.org for details.
2: pgettext('abbreviated month name', 'Feb'),
# Translators: this is an abbreviated month name that will be used when
# displaying dates, as in "Mar 10, 2014". It is used for the %b
# directive in date-time formats. See http://strftime.org for details.
3: pgettext('abbreviated month name', 'Mar'),
# Translators: this is an abbreviated month name that will be used when
# displaying dates, as in "Apr 10, 2014". It is used for the %b
# directive in date-time formats. See http://strftime.org for details.
4: pgettext('abbreviated month name', 'Apr'),
# Translators: this is an abbreviated month name that will be used when
# displaying dates, as in "May 10, 2014". It is used for the %b
# directive in date-time formats. See http://strftime.org for details.
5: pgettext('abbreviated month name', 'May'),
# Translators: this is an abbreviated month name that will be used when
# displaying dates, as in "Jun 10, 2014". It is used for the %b
# directive in date-time formats. See http://strftime.org for details.
6: pgettext('abbreviated month name', 'Jun'),
# Translators: this is an abbreviated month name that will be used when
# displaying dates, as in "Jul 10, 2014". It is used for the %b
# directive in date-time formats. See http://strftime.org for details.
7: pgettext('abbreviated month name', 'Jul'),
# Translators: this is an abbreviated month name that will be used when
# displaying dates, as in "Aug 10, 2014". It is used for the %b
# directive in date-time formats. See http://strftime.org for details.
8: pgettext('abbreviated month name', 'Aug'),
# Translators: this is an abbreviated month name that will be used when
# displaying dates, as in "Sep 10, 2014". It is used for the %b
# directive in date-time formats. See http://strftime.org for details.
9: pgettext('abbreviated month name', 'Sep'),
# Translators: this is an abbreviated month name that will be used when
# displaying dates, as in "Oct 10, 2014". It is used for the %b
# directive in date-time formats. See http://strftime.org for details.
10: pgettext('abbreviated month name', 'Oct'),
# Translators: this is an abbreviated month name that will be used when
# displaying dates, as in "Nov 10, 2014". It is used for the %b
# directive in date-time formats. See http://strftime.org for details.
11: pgettext('abbreviated month name', 'Nov'),
# Translators: this is an abbreviated month name that will be used when
# displaying dates, as in "Dec 10, 2014". It is used for the %b
# directive in date-time formats. See http://strftime.org for details.
12: pgettext('abbreviated month name', 'Dec'),
}
MONTHS = {
# Translators: this is a month name that will be used when displaying
# dates, as in "January 10, 2014". It is used for the %B directive in
# date-time formats. See http://strftime.org for details.
1: pgettext('month name', 'January'),
# Translators: this is a month name that will be used when displaying
# dates, as in "February 10, 2014". It is used for the %B directive in
# date-time formats. See http://strftime.org for details.
2: pgettext('month name', 'February'),
# Translators: this is a month name that will be used when displaying
# dates, as in "March 10, 2014". It is used for the %B directive in
# date-time formats. See http://strftime.org for details.
3: pgettext('month name', 'March'),
# Translators: this is a month name that will be used when displaying
# dates, as in "April 10, 2014". It is used for the %B directive in
# date-time formats. See http://strftime.org for details.
4: pgettext('month name', 'April'),
# Translators: this is a month name that will be used when displaying
# dates, as in "May 10, 2014". It is used for the %B directive in
# date-time formats. See http://strftime.org for details.
5: pgettext('month name', 'May'),
# Translators: this is a month name that will be used when displaying
# dates, as in "June 10, 2014". It is used for the %B directive in
# date-time formats. See http://strftime.org for details.
6: pgettext('month name', 'June'),
# Translators: this is a month name that will be used when displaying
# dates, as in "July 10, 2014". It is used for the %B directive in
# date-time formats. See http://strftime.org for details.
7: pgettext('month name', 'July'),
# Translators: this is a month name that will be used when displaying
# dates, as in "August 10, 2014". It is used for the %B directive in
# date-time formats. See http://strftime.org for details.
8: pgettext('month name', 'August'),
# Translators: this is a month name that will be used when displaying
# dates, as in "September 10, 2014". It is used for the %B directive in
# date-time formats. See http://strftime.org for details.
9: pgettext('month name', 'September'),
# Translators: this is a month name that will be used when displaying
# dates, as in "October 10, 2014". It is used for the %B directive in
# date-time formats. See http://strftime.org for details.
10: pgettext('month name', 'October'),
# Translators: this is a month name that will be used when displaying
# dates, as in "November 10, 2014". It is used for the %B directive in
# date-time formats. See http://strftime.org for details.
11: pgettext('month name', 'November'),
# Translators: this is a month name that will be used when displaying
# dates, as in "December 10, 2014". It is used for the %B directive in
# date-time formats. See http://strftime.org for details.
12: pgettext('month name', 'December'),
}
# Now that we are done defining constants, we have to restore the real pgettext
# so that the functions in this module will have the right definition.
pgettext = real_pgettext
"""Tests for xmodule.util.date_utils""" # -*- coding: utf-8 -*-
"""
Tests for util.date_utils
"""
from nose.tools import assert_equals, assert_false # pylint: disable=E0611
from xmodule.util.date_utils import get_default_time_display, get_time_display, almost_same_datetime
from datetime import datetime, timedelta, tzinfo from datetime import datetime, timedelta, tzinfo
from pytz import UTC, timezone from functools import partial
import unittest
import ddt
from mock import patch
from nose.tools import assert_equals, assert_false # pylint: disable=E0611
from pytz import UTC
from util.date_utils import (
get_default_time_display, get_time_display, almost_same_datetime,
strftime_localized,
)
def test_get_default_time_display(): def test_get_default_time_display():
...@@ -104,3 +116,106 @@ def test_almost_same_datetime(): ...@@ -104,3 +116,106 @@ def test_almost_same_datetime():
timedelta(minutes=10) timedelta(minutes=10)
) )
) )
def fake_ugettext(text, translations):
"""
A fake implementation of ugettext, for testing.
"""
return translations.get(text, text)
def fake_pgettext(context, text, translations):
"""
A fake implementation of pgettext, for testing.
"""
return translations.get((context, text), text)
@ddt.ddt
class StrftimeLocalizedTest(unittest.TestCase):
"""
Tests for strftime_localized.
"""
@ddt.data(
("%Y", "2013"),
("%m/%d/%y", "02/14/13"),
("hello", "hello"),
(u'%Y년 %m월 %d일', u"2013년 02월 14일"),
("%a, %b %d, %Y", "Thu, Feb 14, 2013"),
("%I:%M:%S %p", "04:41:17 PM"),
)
def test_usual_strftime_behavior(self, (fmt, expected)):
dtime = datetime(2013, 02, 14, 16, 41, 17)
self.assertEqual(expected, strftime_localized(dtime, fmt))
# strftime doesn't like Unicode, so do the work in UTF8.
self.assertEqual(expected, dtime.strftime(fmt.encode('utf8')).decode('utf8'))
@ddt.data(
("SHORT_DATE", "Feb 14, 2013"),
("LONG_DATE", "Thursday, February 14, 2013"),
("TIME", "04:41:17 PM"),
("%x %X!", "Feb 14, 2013 04:41:17 PM!"),
)
def test_shortcuts(self, (fmt, expected)):
dtime = datetime(2013, 02, 14, 16, 41, 17)
self.assertEqual(expected, strftime_localized(dtime, fmt))
@patch('util.date_utils.pgettext', partial(fake_pgettext, translations={
("abbreviated month name", "Feb"): "XXfebXX",
("month name", "February"): "XXfebruaryXX",
("abbreviated weekday name", "Thu"): "XXthuXX",
("weekday name", "Thursday"): "XXthursdayXX",
("am/pm indicator", "PM"): "XXpmXX",
}))
@ddt.data(
("SHORT_DATE", "XXfebXX 14, 2013"),
("LONG_DATE", "XXthursdayXX, XXfebruaryXX 14, 2013"),
("DATE_TIME", "XXfebXX 14, 2013 at 16:41"),
("TIME", "04:41:17 XXpmXX"),
("%x %X!", "XXfebXX 14, 2013 04:41:17 XXpmXX!"),
)
def test_translated_words(self, (fmt, expected)):
dtime = datetime(2013, 02, 14, 16, 41, 17)
self.assertEqual(expected, strftime_localized(dtime, fmt))
@patch('util.date_utils.ugettext', partial(fake_ugettext, translations={
"SHORT_DATE_FORMAT": "date(%Y.%m.%d)",
"LONG_DATE_FORMAT": "date(%A.%Y.%B.%d)",
"DATE_TIME_FORMAT": "date(%Y.%m.%d@%H.%M)",
"TIME_FORMAT": "%Hh.%Mm.%Ss",
}))
@ddt.data(
("SHORT_DATE", "date(2013.02.14)"),
("Look: %x", "Look: date(2013.02.14)"),
("LONG_DATE", "date(Thursday.2013.February.14)"),
("DATE_TIME", "date(2013.02.14@16.41)"),
("TIME", "16h.41m.17s"),
("The time is: %X", "The time is: 16h.41m.17s"),
("%x %X", "date(2013.02.14) 16h.41m.17s"),
)
def test_translated_formats(self, (fmt, expected)):
dtime = datetime(2013, 02, 14, 16, 41, 17)
self.assertEqual(expected, strftime_localized(dtime, fmt))
@patch('util.date_utils.ugettext', partial(fake_ugettext, translations={
"SHORT_DATE_FORMAT": "oops date(%Y.%x.%d)",
"TIME_FORMAT": "oops %Hh.%Xm.%Ss",
}))
@ddt.data(
("SHORT_DATE", "Feb 14, 2013"),
("TIME", "04:41:17 PM"),
)
def test_recursion_protection(self, (fmt, expected)):
dtime = datetime(2013, 02, 14, 16, 41, 17)
self.assertEqual(expected, strftime_localized(dtime, fmt))
@ddt.data(
"%",
"Hello%"
"%Y/%m/%d%",
)
def test_invalid_format_strings(self, fmt):
dtime = datetime(2013, 02, 14, 16, 41, 17)
with self.assertRaises(ValueError):
strftime_localized(dtime, fmt)
...@@ -828,13 +828,17 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): ...@@ -828,13 +828,17 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
Returns the desired text corresponding the course's start date. Prefers .advertised_start, Returns the desired text corresponding the course's start date. Prefers .advertised_start,
then falls back to .start then falls back to .start
""" """
i18n = self.runtime.service(self, "i18n")
_ = i18n.ugettext
strftime = i18n.strftime
def try_parse_iso_8601(text): def try_parse_iso_8601(text):
try: try:
result = Date().from_json(text) result = Date().from_json(text)
if result is None: if result is None:
result = text.title() result = text.title()
else: else:
result = result.strftime("%b %d, %Y") result = strftime(result, "SHORT_DATE")
except ValueError: except ValueError:
result = text.title() result = text.title()
...@@ -843,12 +847,12 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): ...@@ -843,12 +847,12 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
if isinstance(self.advertised_start, basestring): if isinstance(self.advertised_start, basestring):
return try_parse_iso_8601(self.advertised_start) return try_parse_iso_8601(self.advertised_start)
elif self.start_date_is_still_default: elif self.start_date_is_still_default:
_ = self.runtime.service(self, "i18n").ugettext
# Translators: TBD stands for 'To Be Determined' and is used when a course # Translators: TBD stands for 'To Be Determined' and is used when a course
# does not yet have an announced start date. # does not yet have an announced start date.
return _('TBD') return _('TBD')
else: else:
return (self.advertised_start or self.start).strftime("%b %d, %Y") when = self.advertised_start or self.start
return strftime(when, "SHORT_DATE")
@property @property
def start_date_is_still_default(self): def start_date_is_still_default(self):
...@@ -865,7 +869,11 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): ...@@ -865,7 +869,11 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
If the course does not have an end date set (course.end is None), an empty string will be returned. If the course does not have an end date set (course.end is None), an empty string will be returned.
""" """
return '' if self.end is None else self.end.strftime("%b %d, %Y") if self.end is None:
return ''
else:
strftime = self.runtime.service(self, "i18n").strftime
return strftime(self.end, "SHORT_DATE")
@property @property
def forum_posts_allowed(self): def forum_posts_allowed(self):
......
"""
Convenience methods for working with datetime objects
"""
from datetime import timedelta
from pytz import timezone, UTC, UnknownTimeZoneError
def get_default_time_display(dtime):
"""
Converts a datetime to a string representation. This is the default
representation used in Studio and LMS.
It is of the form "Apr 09, 2013 at 16:00 UTC".
If None is passed in for dt, an empty string will be returned.
"""
if dtime is None:
return u""
if dtime.tzinfo is not None:
try:
timezone = u" " + dtime.tzinfo.tzname(dtime)
except NotImplementedError:
timezone = dtime.strftime('%z')
else:
timezone = u" UTC"
return unicode(dtime.strftime(u"%b %d, %Y at %H:%M{tz}")).format(
tz=timezone).strip()
def get_time_display(dtime, format_string=None, coerce_tz=None):
"""
Converts a datetime to a string representation.
If None is passed in for dt, an empty string will be returned.
If the format_string is None, or if format_string is improperly
formatted, this method will return the value from `get_default_time_display`.
Coerces aware datetime to tz=coerce_tz if set. coerce_tz should be a pytz timezone string
like "US/Pacific", or None
format_string should be a unicode string that is a valid argument for datetime's strftime method.
"""
if dtime is not None and dtime.tzinfo is not None and coerce_tz:
try:
to_tz = timezone(coerce_tz)
except UnknownTimeZoneError:
to_tz = UTC
dtime = to_tz.normalize(dtime.astimezone(to_tz))
if dtime is None or format_string is None:
return get_default_time_display(dtime)
try:
return unicode(dtime.strftime(format_string))
except ValueError:
return get_default_time_display(dtime)
def almost_same_datetime(dt1, dt2, allowed_delta=timedelta(minutes=1)):
"""
Returns true if these are w/in a minute of each other. (in case secs saved to db
or timezone aren't same)
:param dt1:
:param dt2:
"""
return abs(dt1 - dt2) < allowed_delta
...@@ -37,7 +37,7 @@ msgid "" ...@@ -37,7 +37,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PROJECT VERSION\n" "Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2014-02-18 13:34-0500\n" "POT-Creation-Date: 2014-02-18 16:36-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
...@@ -338,6 +338,357 @@ msgstr "Nämé réqüïréd Ⱡ'#" ...@@ -338,6 +338,357 @@ msgstr "Nämé réqüïréd Ⱡ'#"
msgid "Invalid ID" msgid "Invalid ID"
msgstr "Ìnvälïd ÌD Ⱡ#" msgstr "Ìnvälïd ÌD Ⱡ#"
#. Translators: the translation for "LONG_DATE_FORMAT" must be a format
#. string for formatting dates in a long form. For example, the
#. American English form is "%A, %B %d %Y".
#. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgid "LONG_DATE_FORMAT"
msgstr ""
#. Translators: the translation for "DATE_TIME_FORMAT" must be a format
#. string for formatting dates with times. For example, the American
#. English form is "%b %d, %Y at %H:%M".
#. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgid "DATE_TIME_FORMAT"
msgstr ""
#. Translators: the translation for "SHORT_DATE_FORMAT" must be a
#. format string for formatting dates in a brief form. For example,
#. the American English form is "%b %d %Y".
#. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgid "SHORT_DATE_FORMAT"
msgstr ""
#. Translators: the translation for "TIME_FORMAT" must be a format
#. string for formatting times. For example, the American English
#. form is "%H:%M:%S". See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgid "TIME_FORMAT"
msgstr ""
#. Translators: This is an AM/PM indicator for displaying times. It is
#. used for the %p directive in date-time formats. See http://strftime.org
#. for details.
#: common/djangoapps/util/date_utils.py
msgctxt "am/pm indicator"
msgid "AM"
msgstr "ÀM Ⱡ'#"
#. Translators: This is an AM/PM indicator for displaying times. It is
#. used for the %p directive in date-time formats. See http://strftime.org
#. for details.
#: common/djangoapps/util/date_utils.py
msgctxt "am/pm indicator"
msgid "PM"
msgstr "PM Ⱡ'#"
#. Translators: this is a weekday name that will be used when displaying
#. dates, as in "Monday Februrary 10, 2014". It is used for the %A
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "weekday name"
msgid "Monday"
msgstr "Möndäý Ⱡ'σяєм ιρѕ#"
#. Translators: this is a weekday name that will be used when displaying
#. dates, as in "Tuesday Februrary 11, 2014". It is used for the %A
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "weekday name"
msgid "Tuesday"
msgstr "Tüésdäý #"
#. Translators: this is a weekday name that will be used when displaying
#. dates, as in "Wednesday Februrary 12, 2014". It is used for the %A
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "weekday name"
msgid "Wednesday"
msgstr "Wédnésdäý #"
#. Translators: this is a weekday name that will be used when displaying
#. dates, as in "Thursday Februrary 13, 2014". It is used for the %A
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "weekday name"
msgid "Thursday"
msgstr "Thürsdäý #"
#. Translators: this is a weekday name that will be used when displaying
#. dates, as in "Friday Februrary 14, 2014". It is used for the %A
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "weekday name"
msgid "Friday"
msgstr "Frïdäý Ⱡ'σяєм ιρѕ#"
#. Translators: this is a weekday name that will be used when displaying
#. dates, as in "Saturday Februrary 15, 2014". It is used for the %A
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "weekday name"
msgid "Saturday"
msgstr "Sätürdäý #"
#. Translators: this is a weekday name that will be used when displaying
#. dates, as in "Sunday Februrary 16, 2014". It is used for the %A
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "weekday name"
msgid "Sunday"
msgstr "Sündäý Ⱡ'σяєм ιρѕ#"
#. Translators: this is an abbreviated weekday name that will be used when
#. displaying dates, as in "Mon Feb 10, 2014". It is used for the %a
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated weekday name"
msgid "Mon"
msgstr "Mön Ⱡ'σя#"
#. Translators: this is an abbreviated weekday name that will be used when
#. displaying dates, as in "Tue Feb 11, 2014". It is used for the %a
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated weekday name"
msgid "Tue"
msgstr "Tüé Ⱡ'σя#"
#. Translators: this is an abbreviated weekday name that will be used when
#. displaying dates, as in "Wed Feb 12, 2014". It is used for the %a
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated weekday name"
msgid "Wed"
msgstr "Wéd Ⱡ'σя#"
#. Translators: this is an abbreviated weekday name that will be used when
#. displaying dates, as in "Thu Feb 13, 2014". It is used for the %a
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated weekday name"
msgid "Thu"
msgstr "Thü Ⱡ'σя#"
#. Translators: this is an abbreviated weekday name that will be used when
#. displaying dates, as in "Fri Feb 14, 2014". It is used for the %a
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated weekday name"
msgid "Fri"
msgstr "Frï Ⱡ'σя#"
#. Translators: this is an abbreviated weekday name that will be used when
#. displaying dates, as in "Sat Feb 15, 2014". It is used for the %a
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated weekday name"
msgid "Sat"
msgstr "Sät Ⱡ'σя#"
#. Translators: this is an abbreviated weekday name that will be used when
#. displaying dates, as in "Sun Feb 16, 2014". It is used for the %a
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated weekday name"
msgid "Sun"
msgstr "Sün Ⱡ'σя#"
#. Translators: this is an abbreviated month name that will be used when
#. displaying dates, as in "Jan 10, 2014". It is used for the %b
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated month name"
msgid "Jan"
msgstr "Jän Ⱡ'σя#"
#. Translators: this is an abbreviated month name that will be used when
#. displaying dates, as in "Feb 10, 2014". It is used for the %b
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated month name"
msgid "Feb"
msgstr "Féß Ⱡ'σя#"
#. Translators: this is an abbreviated month name that will be used when
#. displaying dates, as in "Mar 10, 2014". It is used for the %b
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated month name"
msgid "Mar"
msgstr "Mär Ⱡ'σя#"
#. Translators: this is an abbreviated month name that will be used when
#. displaying dates, as in "Apr 10, 2014". It is used for the %b
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated month name"
msgid "Apr"
msgstr "Àpr Ⱡ'σя#"
#. Translators: this is an abbreviated month name that will be used when
#. displaying dates, as in "May 10, 2014". It is used for the %b
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated month name"
msgid "May"
msgstr "Mäý Ⱡ'σя#"
#. Translators: this is an abbreviated month name that will be used when
#. displaying dates, as in "Jun 10, 2014". It is used for the %b
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated month name"
msgid "Jun"
msgstr "Jün Ⱡ'σя#"
#. Translators: this is an abbreviated month name that will be used when
#. displaying dates, as in "Jul 10, 2014". It is used for the %b
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated month name"
msgid "Jul"
msgstr "Jül Ⱡ'σя#"
#. Translators: this is an abbreviated month name that will be used when
#. displaying dates, as in "Aug 10, 2014". It is used for the %b
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated month name"
msgid "Aug"
msgstr "Àüg Ⱡ'σя#"
#. Translators: this is an abbreviated month name that will be used when
#. displaying dates, as in "Sep 10, 2014". It is used for the %b
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated month name"
msgid "Sep"
msgstr "Sép Ⱡ'σя#"
#. Translators: this is an abbreviated month name that will be used when
#. displaying dates, as in "Oct 10, 2014". It is used for the %b
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated month name"
msgid "Oct"
msgstr "Öçt Ⱡ'σя#"
#. Translators: this is an abbreviated month name that will be used when
#. displaying dates, as in "Nov 10, 2014". It is used for the %b
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated month name"
msgid "Nov"
msgstr "Növ Ⱡ'σя#"
#. Translators: this is an abbreviated month name that will be used when
#. displaying dates, as in "Dec 10, 2014". It is used for the %b
#. directive in date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "abbreviated month name"
msgid "Dec"
msgstr "Déç Ⱡ'σя#"
#. Translators: this is a month name that will be used when displaying
#. dates, as in "January 10, 2014". It is used for the %B directive in
#. date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "month name"
msgid "January"
msgstr "Jänüärý #"
#. Translators: this is a month name that will be used when displaying
#. dates, as in "February 10, 2014". It is used for the %B directive in
#. date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "month name"
msgid "February"
msgstr "Féßrüärý #"
#. Translators: this is a month name that will be used when displaying
#. dates, as in "March 10, 2014". It is used for the %B directive in
#. date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "month name"
msgid "March"
msgstr "Märçh Ⱡ'σяєм ι#"
#. Translators: this is a month name that will be used when displaying
#. dates, as in "April 10, 2014". It is used for the %B directive in
#. date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "month name"
msgid "April"
msgstr "Àprïl Ⱡ'σяєм ι#"
#. Translators: this is a month name that will be used when displaying
#. dates, as in "May 10, 2014". It is used for the %B directive in
#. date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "month name"
msgid "May"
msgstr "Mäý Ⱡ'σя#"
#. Translators: this is a month name that will be used when displaying
#. dates, as in "June 10, 2014". It is used for the %B directive in
#. date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "month name"
msgid "June"
msgstr "Jüné Ⱡ'σяєм#"
#. Translators: this is a month name that will be used when displaying
#. dates, as in "July 10, 2014". It is used for the %B directive in
#. date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "month name"
msgid "July"
msgstr "Jülý Ⱡ'σяєм#"
#. Translators: this is a month name that will be used when displaying
#. dates, as in "August 10, 2014". It is used for the %B directive in
#. date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "month name"
msgid "August"
msgstr "Àügüst Ⱡ'σяєм ιρѕ#"
#. Translators: this is a month name that will be used when displaying
#. dates, as in "September 10, 2014". It is used for the %B directive in
#. date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "month name"
msgid "September"
msgstr "Séptémßér #"
#. Translators: this is a month name that will be used when displaying
#. dates, as in "October 10, 2014". It is used for the %B directive in
#. date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "month name"
msgid "October"
msgstr "Öçtößér #"
#. Translators: this is a month name that will be used when displaying
#. dates, as in "November 10, 2014". It is used for the %B directive in
#. date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "month name"
msgid "November"
msgstr "Növémßér #"
#. Translators: this is a month name that will be used when displaying
#. dates, as in "December 10, 2014". It is used for the %B directive in
#. date-time formats. See http://strftime.org for details.
#: common/djangoapps/util/date_utils.py
msgctxt "month name"
msgid "December"
msgstr "Déçémßér #"
#: common/djangoapps/util/password_policy_validators.py #: common/djangoapps/util/password_policy_validators.py
msgid "Invalid Length ({0})" msgid "Invalid Length ({0})"
msgstr "Ìnvälïd Léngth ({0}) Ⱡ'σя#" msgstr "Ìnvälïd Léngth ({0}) Ⱡ'σя#"
......
...@@ -7,8 +7,8 @@ msgid "" ...@@ -7,8 +7,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 0.1a\n" "Project-Id-Version: 0.1a\n"
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
"POT-Creation-Date: 2014-02-18 13:34-0500\n" "POT-Creation-Date: 2014-02-18 16:36-0500\n"
"PO-Revision-Date: 2014-02-18 18:34:51.762964\n" "PO-Revision-Date: 2014-02-18 21:36:33.541469\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: openedx-translation <openedx-translation@googlegroups.com>\n" "Language-Team: openedx-translation <openedx-translation@googlegroups.com>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
......
...@@ -23,7 +23,9 @@ generates output conf/locale/$DUMMY_LOCALE/LC_MESSAGES, ...@@ -23,7 +23,9 @@ generates output conf/locale/$DUMMY_LOCALE/LC_MESSAGES,
where $DUMMY_LOCALE is the dummy_locale value set in the i18n config where $DUMMY_LOCALE is the dummy_locale value set in the i18n config
""" """
import re
import sys import sys
import polib import polib
from path import path from path import path
...@@ -173,6 +175,10 @@ def make_dummy(filename, locale, converter): ...@@ -173,6 +175,10 @@ def make_dummy(filename, locale, converter):
raise IOError('File does not exist: %r' % filename) raise IOError('File does not exist: %r' % filename)
pofile = polib.pofile(filename) pofile = polib.pofile(filename)
for msg in pofile: for msg in pofile:
# Some strings are actually formatting strings, don't dummy-ify them,
# or dates will look like "DÀTÉ_TÌMÉ_FÖRMÀT Ⱡ'σ# EST"
if re.match(r"^[A-Z_]+_FORMAT$", msg.msgid):
continue
converter.convert_msg(msg) converter.convert_msg(msg)
# Apply declaration for English pluralization rules so that ngettext will # Apply declaration for English pluralization rules so that ngettext will
......
...@@ -25,8 +25,6 @@ from lms.lib.xblock.runtime import LmsModuleSystem, unquote_slashes ...@@ -25,8 +25,6 @@ from lms.lib.xblock.runtime import LmsModuleSystem, unquote_slashes
from edxmako.shortcuts import render_to_string from edxmako.shortcuts import render_to_string
from psychometrics.psychoanalyze import make_psychometrics_data_update_handler from psychometrics.psychoanalyze import make_psychometrics_data_update_handler
from student.models import anonymous_id_for_user, user_by_anonymous_id from student.models import anonymous_id_for_user, user_by_anonymous_id
from util.json_request import JsonResponse
from util.sandboxing import can_execute_unsafe_code
from xblock.core import XBlock from xblock.core import XBlock
from xblock.fields import Scope from xblock.fields import Scope
from xblock.runtime import KvsFieldData, KeyValueStore from xblock.runtime import KvsFieldData, KeyValueStore
...@@ -42,6 +40,10 @@ from xmodule_modifiers import replace_course_urls, replace_jump_to_id_urls, repl ...@@ -42,6 +40,10 @@ from xmodule_modifiers import replace_course_urls, replace_jump_to_id_urls, repl
from xmodule.lti_module import LTIModule from xmodule.lti_module import LTIModule
from xmodule.x_module import XModuleDescriptor from xmodule.x_module import XModuleDescriptor
from util.date_utils import strftime_localized
from util.json_request import JsonResponse
from util.sandboxing import can_execute_unsafe_code
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -428,10 +430,7 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours ...@@ -428,10 +430,7 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
wrappers=block_wrappers, wrappers=block_wrappers,
get_real_user=user_by_anonymous_id, get_real_user=user_by_anonymous_id,
services={ services={
# django.utils.translation implements the gettext.Translations 'i18n': ModuleI18nService(),
# interface (it has ugettext, ungettext, etc), so we can use it
# directly as the runtime i18n service.
'i18n': django.utils.translation,
}, },
get_user_role=lambda: get_user_role(user, course_id), get_user_role=lambda: get_user_role(user, course_id),
) )
...@@ -652,3 +651,20 @@ def _check_files_limits(files): ...@@ -652,3 +651,20 @@ def _check_files_limits(files):
return msg return msg
return None return None
class ModuleI18nService(object):
"""
Implement the XBlock runtime "i18n" service.
Mostly a pass-through to Django's translation module.
django.utils.translation implements the gettext.Translations interface (it
has ugettext, ungettext, etc), so we can use it directly as the runtime
i18n service.
"""
def __getattr__(self, name):
return getattr(django.utils.translation, name)
def strftime(self, *args, **kwargs):
return strftime_localized(*args, **kwargs)
<%! <%!
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from xmodule.util.date_utils import get_time_display from util.date_utils import get_time_display
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.conf import settings from django.conf import settings
%> %>
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
due_date = '' due_date = ''
else: else:
formatted_string = get_time_display(section['due'], due_date_display_format, coerce_tz=settings.TIME_ZONE) formatted_string = get_time_display(section['due'], due_date_display_format, coerce_tz=settings.TIME_ZONE)
due_date = '' if len(formatted_string)==0 else _('due {date}'.format(date=formatted_string)) due_date = '' if len(formatted_string)==0 else _('due {date}').format(date=formatted_string)
%> %>
<p class="subtitle">${section['format']} ${due_date}</p> <p class="subtitle">${section['format']} ${due_date}</p>
</a> </a>
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
%> %>
<%! <%!
from xmodule.util.date_utils import get_time_display from util.date_utils import get_time_display
from django.conf import settings from django.conf import settings
%> %>
......
<%! from django.utils.translation import ugettext as _ %> <%! from django.utils.translation import ugettext as _ %>
<%! <%!
from xmodule.util.date_utils import get_default_time_display from util.date_utils import get_default_time_display
%> %>
<div class="folditbasic"> <div class="folditbasic">
<p><strong>${_("Due:")}</strong> ${get_default_time_display(due)} <p><strong>${_("Due:")}</strong> ${get_default_time_display(due)}
......
<%! from django.utils.translation import ugettext as _ %> <%! from django.utils.translation import ugettext as _ %>
<%! from django.core.urlresolvers import reverse %> <%! from django.core.urlresolvers import reverse %>
<%! from time import strftime %>
<%inherit file="main.html" /> <%inherit file="main.html" />
<%namespace name='static' file='static_content.html'/> <%namespace name='static' file='static_content.html'/>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
-e git+https://github.com/eventbrite/zendesk.git@d53fe0e81b623f084e91776bcf6369f8b7b63879#egg=zendesk -e git+https://github.com/eventbrite/zendesk.git@d53fe0e81b623f084e91776bcf6369f8b7b63879#egg=zendesk
# Our libraries: # Our libraries:
-e git+https://github.com/edx/XBlock.git@6d431d786587bd8f3a19a893364914d6e2d6c28f#egg=XBlock -e git+https://github.com/edx/XBlock.git@893cd83dfb24405ce81b07f49c1c2e3053cdc865#egg=XBlock
-e git+https://github.com/edx/codejail.git@e3d98f9455#egg=codejail -e git+https://github.com/edx/codejail.git@e3d98f9455#egg=codejail
-e git+https://github.com/edx/diff-cover.git@v0.2.9#egg=diff_cover -e git+https://github.com/edx/diff-cover.git@v0.2.9#egg=diff_cover
-e git+https://github.com/edx/js-test-tool.git@v0.1.5#egg=js_test_tool -e git+https://github.com/edx/js-test-tool.git@v0.1.5#egg=js_test_tool
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment