From 7fd9d44210a2e600148a8fa38460bd5c1b3bfc73 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 14 Feb 2014 12:30:14 -0500 Subject: [PATCH 1/8] Remove unused import. --- lms/templates/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/lms/templates/index.html b/lms/templates/index.html index d8e6d75278..b2fdfe0633 100644 --- a/lms/templates/index.html +++ b/lms/templates/index.html @@ -1,7 +1,6 @@ <%! from django.utils.translation import ugettext as _ %> <%! from django.core.urlresolvers import reverse %> -<%! from time import strftime %> <%inherit file="main.html" /> <%namespace name='static' file='static_content.html'/> From 229f3522fa2d025aaf9fd7d0b0e892f652b559a5 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 14 Feb 2014 16:03:32 -0500 Subject: [PATCH 2/8] Move date_utils to common/djangoapps/util --- cms/djangoapps/contentstore/views/assets.py | 2 +- cms/djangoapps/contentstore/views/component.py | 2 +- cms/templates/edit_subsection.html | 2 +- cms/templates/overview.html | 4 ++-- .../xmodule/xmodule => djangoapps}/util/date_utils.py | 0 .../xmodule => djangoapps/util}/tests/test_date_utils.py | 8 +++++--- lms/templates/courseware/accordion.html | 2 +- lms/templates/courseware/progress.html | 2 +- lms/templates/folditbasic.html | 2 +- 9 files changed, 13 insertions(+), 11 deletions(-) rename common/{lib/xmodule/xmodule => djangoapps}/util/date_utils.py (100%) rename common/{lib/xmodule/xmodule => djangoapps/util}/tests/test_date_utils.py (96%) diff --git a/cms/djangoapps/contentstore/views/assets.py b/cms/djangoapps/contentstore/views/assets.py index cd59b811d7..dd96cd213a 100644 --- a/cms/djangoapps/contentstore/views/assets.py +++ b/cms/djangoapps/contentstore/views/assets.py @@ -16,13 +16,13 @@ from xmodule.contentstore.django import contentstore from xmodule.modulestore.django import modulestore from xmodule.modulestore import Location from xmodule.contentstore.content import StaticContent -from xmodule.util.date_utils import get_default_time_display from xmodule.modulestore import InvalidLocationError from xmodule.exceptions import NotFoundError from django.core.exceptions import PermissionDenied from xmodule.modulestore.django import loc_mapper from xmodule.modulestore.locator import BlockUsageLocator +from util.date_utils import get_default_time_display from util.json_request import JsonResponse from django.http import HttpResponseNotFound from django.utils.translation import ugettext as _ diff --git a/cms/djangoapps/contentstore/views/component.py b/cms/djangoapps/contentstore/views/component.py index 8c1bcb7a9d..7b8eb5b252 100644 --- a/cms/djangoapps/contentstore/views/component.py +++ b/cms/djangoapps/contentstore/views/component.py @@ -10,8 +10,8 @@ from django.conf import settings from xmodule.modulestore.exceptions import ItemNotFoundError from edxmako.shortcuts import render_to_response +from util.date_utils import get_default_time_display 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.locator import BlockUsageLocator diff --git a/cms/templates/edit_subsection.html b/cms/templates/edit_subsection.html index be4c042bc7..4103c0752b 100644 --- a/cms/templates/edit_subsection.html +++ b/cms/templates/edit_subsection.html @@ -1,7 +1,7 @@ <%inherit file="base.html" /> <%! 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.core.urlresolvers import reverse %> diff --git a/cms/templates/overview.html b/cms/templates/overview.html index e7aa8da9ad..dc74f5c799 100644 --- a/cms/templates/overview.html +++ b/cms/templates/overview.html @@ -1,7 +1,7 @@ <%inherit file="base.html" /> <%! 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.core.urlresolvers import reverse from xmodule.modulestore.django import loc_mapper @@ -188,7 +188,7 @@ require(["domReady!", "jquery", "js/models/location", "js/models/section", "js/v ${_("Schedule")} %else: ${_("Release date:")} - ${date_utils.get_default_time_display(section.start)} + ${get_default_time_display(section.start)} ${_("Edit section release date")} %endif diff --git a/common/lib/xmodule/xmodule/util/date_utils.py b/common/djangoapps/util/date_utils.py similarity index 100% rename from common/lib/xmodule/xmodule/util/date_utils.py rename to common/djangoapps/util/date_utils.py diff --git a/common/lib/xmodule/xmodule/tests/test_date_utils.py b/common/djangoapps/util/tests/test_date_utils.py similarity index 96% rename from common/lib/xmodule/xmodule/tests/test_date_utils.py rename to common/djangoapps/util/tests/test_date_utils.py index ae6fd7f109..22776d9569 100644 --- a/common/lib/xmodule/xmodule/tests/test_date_utils.py +++ b/common/djangoapps/util/tests/test_date_utils.py @@ -1,10 +1,12 @@ -"""Tests for xmodule.util.date_utils""" +"""Tests for util.date_utils""" + +from datetime import datetime, timedelta, tzinfo 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 pytz import UTC, timezone +from util.date_utils import get_default_time_display, get_time_display, almost_same_datetime + def test_get_default_time_display(): assert_equals("", get_default_time_display(None)) diff --git a/lms/templates/courseware/accordion.html b/lms/templates/courseware/accordion.html index d857fc3ba0..b261e261c6 100644 --- a/lms/templates/courseware/accordion.html +++ b/lms/templates/courseware/accordion.html @@ -1,6 +1,6 @@ <%! 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.conf import settings %> diff --git a/lms/templates/courseware/progress.html b/lms/templates/courseware/progress.html index 7eeea8da59..02cec1f373 100644 --- a/lms/templates/courseware/progress.html +++ b/lms/templates/courseware/progress.html @@ -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 %> diff --git a/lms/templates/folditbasic.html b/lms/templates/folditbasic.html index e05ceb1452..e5073751bb 100644 --- a/lms/templates/folditbasic.html +++ b/lms/templates/folditbasic.html @@ -1,7 +1,7 @@ <%! 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 %>

${_("Due:")} ${get_default_time_display(due)} From 66e598b75d63b7b572f90b09226beadb3af2a1cd Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 14 Feb 2014 16:20:38 -0500 Subject: [PATCH 3/8] Add strftime_localized function, not called yet. --- common/djangoapps/util/date_utils.py | 301 ++++++++++++++++++ .../djangoapps/util/tests/test_date_utils.py | 119 ++++++- 2 files changed, 417 insertions(+), 3 deletions(-) diff --git a/common/djangoapps/util/date_utils.py b/common/djangoapps/util/date_utils.py index a862bc7d31..e147735bcd 100644 --- a/common/djangoapps/util/date_utils.py +++ b/common/djangoapps/util/date_utils.py @@ -1,8 +1,13 @@ """ 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): """ @@ -62,3 +67,299 @@ def almost_same_datetime(dt1, dt2, allowed_delta=timedelta(minutes=1)): :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'), +} diff --git a/common/djangoapps/util/tests/test_date_utils.py b/common/djangoapps/util/tests/test_date_utils.py index 22776d9569..9dddd46456 100644 --- a/common/djangoapps/util/tests/test_date_utils.py +++ b/common/djangoapps/util/tests/test_date_utils.py @@ -1,11 +1,21 @@ -"""Tests for util.date_utils""" +# -*- coding: utf-8 -*- +""" +Tests for util.date_utils +""" from datetime import datetime, timedelta, tzinfo +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, timezone +from pytz import UTC -from util.date_utils import get_default_time_display, get_time_display, almost_same_datetime +from util.date_utils import ( + get_default_time_display, get_time_display, almost_same_datetime, + strftime_localized, +) def test_get_default_time_display(): @@ -106,3 +116,106 @@ def test_almost_same_datetime(): 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) From 64db0e78b59131e73e2caec57770cd18058be74c Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 14 Feb 2014 18:08:47 -0500 Subject: [PATCH 4/8] Fix i18n errors found along the way. --- lms/templates/courseware/accordion.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/templates/courseware/accordion.html b/lms/templates/courseware/accordion.html index b261e261c6..ae344bdcc5 100644 --- a/lms/templates/courseware/accordion.html +++ b/lms/templates/courseware/accordion.html @@ -31,7 +31,7 @@ due_date = '' else: 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) %>

${section['format']} ${due_date}

From be1700602228b043e42831c0d7119bd945fafba4 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 14 Feb 2014 18:10:23 -0500 Subject: [PATCH 5/8] Use strftime_localized for dates. --- common/djangoapps/util/date_utils.py | 16 ++++++++++++---- i18n/dummy.py | 6 ++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/common/djangoapps/util/date_utils.py b/common/djangoapps/util/date_utils.py index e147735bcd..11ca25d087 100644 --- a/common/djangoapps/util/date_utils.py +++ b/common/djangoapps/util/date_utils.py @@ -13,9 +13,12 @@ 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". + + 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"" @@ -26,8 +29,9 @@ def get_default_time_display(dtime): timezone = dtime.strftime('%z') else: timezone = u" UTC" - return unicode(dtime.strftime(u"%b %d, %Y at %H:%M{tz}")).format( - tz=timezone).strip() + + localized = strftime_localized(dtime, "DATE_TIME") + return (localized + timezone).strip() def get_time_display(dtime, format_string=None, coerce_tz=None): @@ -53,7 +57,7 @@ def get_time_display(dtime, format_string=None, coerce_tz=None): if dtime is None or format_string is None: return get_default_time_display(dtime) try: - return unicode(dtime.strftime(format_string)) + return unicode(strftime_localized(dtime, format_string)) except ValueError: return get_default_time_display(dtime) @@ -363,3 +367,7 @@ MONTHS = { # 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 diff --git a/i18n/dummy.py b/i18n/dummy.py index d72c31eb55..27309fc342 100755 --- a/i18n/dummy.py +++ b/i18n/dummy.py @@ -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 """ +import re import sys + import polib from path import path @@ -173,6 +175,10 @@ def make_dummy(filename, locale, converter): raise IOError('File does not exist: %r' % filename) pofile = polib.pofile(filename) 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) # Apply declaration for English pluralization rules so that ngettext will From 3aff96c2e47abcda7391385b3bf50eda9526cd7e Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 14 Feb 2014 22:13:57 -0500 Subject: [PATCH 6/8] Add strftime to the i18n runtime service. --- common/lib/xmodule/xmodule/course_module.py | 16 +++++++++--- lms/djangoapps/courseware/module_render.py | 28 ++++++++++++++++----- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py index 2b5ec749f1..66b3c0630f 100644 --- a/common/lib/xmodule/xmodule/course_module.py +++ b/common/lib/xmodule/xmodule/course_module.py @@ -828,13 +828,17 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): Returns the desired text corresponding the course's start date. Prefers .advertised_start, then falls back to .start """ + i18n = self.runtime.service(self, "i18n") + _ = i18n.ugettext + strftime = i18n.strftime + def try_parse_iso_8601(text): try: result = Date().from_json(text) if result is None: result = text.title() else: - result = result.strftime("%b %d, %Y") + result = strftime(result, "SHORT_DATE") except ValueError: result = text.title() @@ -843,12 +847,12 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): if isinstance(self.advertised_start, basestring): return try_parse_iso_8601(self.advertised_start) 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 # does not yet have an announced start date. return _('TBD') 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 def start_date_is_still_default(self): @@ -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. """ - 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 def forum_posts_allowed(self): diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index cb2036a04c..382131f262 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -25,8 +25,6 @@ from lms.lib.xblock.runtime import LmsModuleSystem, unquote_slashes from edxmako.shortcuts import render_to_string from psychometrics.psychoanalyze import make_psychometrics_data_update_handler 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.fields import Scope from xblock.runtime import KvsFieldData, KeyValueStore @@ -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.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__) @@ -428,10 +430,7 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours wrappers=block_wrappers, get_real_user=user_by_anonymous_id, services={ - # django.utils.translation implements the gettext.Translations - # interface (it has ugettext, ungettext, etc), so we can use it - # directly as the runtime i18n service. - 'i18n': django.utils.translation, + 'i18n': ModuleI18nService(), }, get_user_role=lambda: get_user_role(user, course_id), ) @@ -652,3 +651,20 @@ def _check_files_limits(files): return msg 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 cad2d439399699cca2ee45a3e51417ff12e450e7 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 15 Feb 2014 13:10:56 -0500 Subject: [PATCH 7/8] Refer to the corresponding change in XBlock. --- requirements/edx/github.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/edx/github.txt b/requirements/edx/github.txt index d32df83bb1..f08722afed 100644 --- a/requirements/edx/github.txt +++ b/requirements/edx/github.txt @@ -15,7 +15,7 @@ -e git+https://github.com/eventbrite/zendesk.git@d53fe0e81b623f084e91776bcf6369f8b7b63879#egg=zendesk # 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/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 From de5f30282d4245d4d41493ddf9f85c14c2d1b394 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Tue, 18 Feb 2014 16:37:45 -0500 Subject: [PATCH 8/8] Latest eo language files. --- conf/locale/eo/LC_MESSAGES/django.mo | Bin 366484 -> 368956 bytes conf/locale/eo/LC_MESSAGES/django.po | 353 ++++++++++++++++++++++++- conf/locale/eo/LC_MESSAGES/djangojs.mo | Bin 42215 -> 42215 bytes conf/locale/eo/LC_MESSAGES/djangojs.po | 4 +- 4 files changed, 354 insertions(+), 3 deletions(-) diff --git a/conf/locale/eo/LC_MESSAGES/django.mo b/conf/locale/eo/LC_MESSAGES/django.mo index 79f0d071607faaf6ef5304edb27abdf3ef7645e7..d3e1a12b809ea629b98074f6b6ab3226f4f93b44 100644 GIT binary patch delta 51426 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 USt4`gh@8c9W%d}K^P{}~1H2k+p8x;= diff --git a/conf/locale/eo/LC_MESSAGES/django.po b/conf/locale/eo/LC_MESSAGES/django.po index 8a06f0ed7c..a3d301bd8c 100644 --- a/conf/locale/eo/LC_MESSAGES/django.po +++ b/conf/locale/eo/LC_MESSAGES/django.po @@ -37,7 +37,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\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" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -338,6 +338,357 @@ msgstr "Nämé réqüïréd Ⱡ'#" msgid "Invalid ID" 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 msgid "Invalid Length ({0})" msgstr "Ìnvälïd Léngth ({0}) Ⱡ'σя#" diff --git a/conf/locale/eo/LC_MESSAGES/djangojs.mo b/conf/locale/eo/LC_MESSAGES/djangojs.mo index 271498c7e077bea1cb2a7820812834863e856353..be17cb59c14729d78095f56571b939584a647c26 100644 GIT binary patch delta 39 ucmaEUlIi(LrVX<_S\n" "MIME-Version: 1.0\n"