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)