diff --git a/problem_builder/instructor_tool.py b/problem_builder/instructor_tool.py
index 37696deb..6cdd4249 100644
--- a/problem_builder/instructor_tool.py
+++ b/problem_builder/instructor_tool.py
@@ -26,12 +26,15 @@
import six
from django.core.paginator import Paginator
+from problem_builder.utils import I18NService
+from .mixins import TranslationContentMixin
from xblock.core import XBlock
from xblock.exceptions import JsonHandlerError
from xblock.fields import Dict, List, Scope, String
from xblock.fragment import Fragment
from xblockutils.resources import ResourceLoader
+
loader = ResourceLoader(__name__)
PAGE_SIZE = 15
@@ -48,7 +51,7 @@ def _(text):
@XBlock.needs("i18n")
@XBlock.wants('user')
-class InstructorToolBlock(XBlock):
+class InstructorToolBlock(XBlock, I18NService, TranslationContentMixin):
"""
InstructorToolBlock: An XBlock for instructors to export student answers from a course.
@@ -142,12 +145,13 @@ def student_view(self, context=None):
_('Long Answer'): 'AnswerBlock',
}
- html = loader.render_template('templates/html/instructor_tool.html', {
+ html = loader.render_django_template('templates/html/instructor_tool.html', {
'block_choices': block_choices,
'course_blocks_api': COURSE_BLOCKS_API,
'root_block_id': six.text_type(getattr(self.runtime, 'course_id', 'course_id')),
- })
+ }, i18n_service=self.i18n_service)
fragment = Fragment(html)
+ fragment.add_javascript(self.get_translation_content())
fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/instructor_tool.css'))
fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/instructor_tool.js'))
fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/vendor/underscore-min.js'))
diff --git a/problem_builder/mentoring.py b/problem_builder/mentoring.py
index a649e5ff..75bb447f 100644
--- a/problem_builder/mentoring.py
+++ b/problem_builder/mentoring.py
@@ -53,7 +53,7 @@
from .mixins import (ExpandStaticURLMixin, MessageParentMixin, QuestionMixin,
StepParentMixin, StudentViewUserStateMixin,
StudentViewUserStateResultsTransformerMixin,
- XBlockWithTranslationServiceMixin, _normalize_id)
+ XBlockWithTranslationServiceMixin, _normalize_id, TranslationContentMixin)
from .step_review import ReviewStepBlock
from .utils import I18NService
@@ -227,7 +227,7 @@ def max_score(self):
class MentoringBlock(
StudentViewUserStateResultsTransformerMixin, I18NService,
- BaseMentoringBlock, StudioContainerWithNestedXBlocksMixin, StepParentMixin,
+ BaseMentoringBlock, StudioContainerWithNestedXBlocksMixin, StepParentMixin, TranslationContentMixin
):
"""
An XBlock providing mentoring capabilities
@@ -484,12 +484,12 @@ def student_view(self, context):
'child_content': child_content,
'missing_dependency_url': self.has_missing_dependency and self.next_step_url,
}, i18n_service=self.i18n_service))
+ fragment.add_javascript(self.get_translation_content())
fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/problem-builder.css'))
fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/vendor/underscore-min.js'))
fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/util.js'))
fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/mentoring_standard_view.js'))
fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/mentoring.js'))
- fragment.add_resource(loader.load_unicode('templates/html/mentoring_attempts.underscore'), "text/html")
# Workbench doesn't have font awesome, so add it:
if WorkbenchRuntime and isinstance(self.runtime, WorkbenchRuntime):
@@ -996,7 +996,6 @@ def student_view(self, context):
fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/step_util.js'))
fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/mentoring_with_steps.js'))
- fragment.add_resource(loader.load_unicode('templates/html/mentoring_attempts.underscore'), "text/html")
fragment.initialize_js('MentoringWithStepsBlock', {
'show_extended_feedback': self.show_extended_feedback(),
})
diff --git a/problem_builder/mixins.py b/problem_builder/mixins.py
index ce9b8e9d..ec2cb73b 100644
--- a/problem_builder/mixins.py
+++ b/problem_builder/mixins.py
@@ -1,7 +1,9 @@
import json
+import pkg_resources
import six
import webob
+from django import utils
from lazy import lazy
from xblock.core import XBlock
from xblock.fields import UNIQUE_ID, Boolean, Float, Scope, String
@@ -290,3 +292,27 @@ def expand_static_url(self, text):
except ImportError:
pass
return text
+
+
+class TranslationContentMixin(object):
+ """
+ Mixin to provide the translation content
+ """
+ @staticmethod
+ def resource_string(path):
+ """Handy helper for getting resources from our kit."""
+ data = pkg_resources.resource_string(__name__, path)
+ return data.decode("utf8")
+
+ def get_translation_content(self):
+ try:
+ # here we need to split the lang code and need to change - to _ and post - characters to
+ # upper case since we have local directories like ja_JP, etc instead of ja-jp, etc
+ language = utils.translation.get_language().split('-')
+ if len(language) == 2:
+ new_lang = language[0] + "_" + language[1].upper()
+ else:
+ new_lang = utils.translation.get_language()
+ return self.resource_string('public/js/translations/{lang}/textjs.js'.format(lang=new_lang))
+ except IOError:
+ return self.resource_string('public/js/translations/en/textjs.js')
diff --git a/problem_builder/public/js/instructor_tool.js b/problem_builder/public/js/instructor_tool.js
index ccc7ee1a..7aa2dd4e 100644
--- a/problem_builder/public/js/instructor_tool.js
+++ b/problem_builder/public/js/instructor_tool.js
@@ -1,9 +1,10 @@
function InstructorToolBlock(runtime, element) {
'use strict';
var $element = $(element);
+ var gettext = window.ProblemBuilderXBlockI18N.gettext;
+ var ngettext = window.ProblemBuilderXBlockI18N.ngettext;
// Pagination
-
$(document).ajaxSend(function(event, jqxhr, options) {
if (options.url.indexOf('get_result_page') !== -1) {
options.data = JSON.stringify(options.data);
diff --git a/problem_builder/public/js/mentoring.js b/problem_builder/public/js/mentoring.js
index 34dd8f53..9486db04 100644
--- a/problem_builder/public/js/mentoring.js
+++ b/problem_builder/public/js/mentoring.js
@@ -1,11 +1,8 @@
function MentoringBlock(runtime, element) {
- // Set up gettext in case it isn't available in the client runtime:
- if (typeof gettext == "undefined") {
- window.gettext = function gettext_stub(string) { return string; };
- window.ngettext = function ngettext_stub(strA, strB, n) { return n == 1 ? strA : strB; };
- }
- var attemptsTemplate = _.template($('#xblock-attempts-template').html());
+ var gettext = window.ProblemBuilderXBlockI18N.gettext;
+ var ngettext = window.ProblemBuilderXBlockI18N.ngettext;
+
var data = $('.mentoring', element).data();
var children = runtime.children(element);
var step = data.step;
@@ -69,7 +66,13 @@ function MentoringBlock(runtime, element) {
function renderAttempts() {
var data = $('.attempts', element).data();
- $('.attempts', element).html(attemptsTemplate(data));
+ if (data != undefined && _.isNumber(data.max_attempts) && data.max_attempts > 0) {
+ var message = _.template(
+ ngettext("You have used {num_used} of 1 submission.", "You have used {num_used} of {max_attempts} submissions.", data.max_attempts),
+ {num_used: _.min([data.num_attempts, data.max_attempts]), max_attempts: data.max_attempts}, {interpolate: /\{(.+?)\}/g}
+ );
+ $('.attempts', element).html("" + message + "");
+ }
}
function renderDependency() {
diff --git a/problem_builder/public/js/mentoring_with_steps.js b/problem_builder/public/js/mentoring_with_steps.js
index faae8dcd..0eb8a519 100644
--- a/problem_builder/public/js/mentoring_with_steps.js
+++ b/problem_builder/public/js/mentoring_with_steps.js
@@ -1,11 +1,7 @@
function MentoringWithStepsBlock(runtime, element) {
-
- // Set up gettext in case it isn't available in the client runtime:
- if (typeof gettext == "undefined") {
- window.gettext = function gettext_stub(string) { return string; };
- window.ngettext = function ngettext_stub(strA, strB, n) { return n == 1 ? strA : strB; };
- }
-
+ // Use problem_builder translations
+ var gettext = window.ProblemBuilderXBlockI18N.gettext;
+ var ngettext = window.ProblemBuilderXBlockI18N.ngettext;
var children = runtime.children(element);
var steps = [];
@@ -19,7 +15,6 @@ function MentoringWithStepsBlock(runtime, element) {
}
var activeStepIndex = $('.mentoring', element).data('active-step');
- var attemptsTemplate = _.template($('#xblock-attempts-template').html());
var message = $('.sb-step-message', element);
var checkmark, submitDOM, nextDOM, reviewButtonDOM, tryAgainDOM,
gradeDOM, attemptsDOM, reviewLinkDOM, submitXHR;
@@ -324,8 +319,12 @@ function MentoringWithStepsBlock(runtime, element) {
function showAttempts() {
var data = attemptsDOM.data();
- if (data.max_attempts > 0) {
- attemptsDOM.html(attemptsTemplate(data));
+ if (_.isNumber(data.max_attempts) && data.max_attempts > 0) {
+ var message = _.template(
+ ngettext("You have used {num_used} of 1 submission.", "You have used {num_used} of {max_attempts} submissions.", data.max_attempts),
+ {num_used: _.min([data.num_attempts, data.max_attempts]), max_attempts: data.max_attempts}, {interpolate: /\{(.+?)\}/g}
+ );
+ attemptsDOM.html("" + message + "");
} // Don't show attempts if unlimited attempts available (max_attempts === 0)
}
diff --git a/problem_builder/public/js/questionnaire.js b/problem_builder/public/js/questionnaire.js
index 4b3d96de..e62dcf6e 100644
--- a/problem_builder/public/js/questionnaire.js
+++ b/problem_builder/public/js/questionnaire.js
@@ -94,6 +94,7 @@ function MessageView(element, mentoring) {
}
function MCQBlock(runtime, element) {
+ var gettext = window.ProblemBuilderXBlockI18N.gettext;
return {
mentoring: null,
init: function(options) {
@@ -182,6 +183,8 @@ function SwipeBlock(runtime, element) {
}
function MRQBlock(runtime, element) {
+ var gettext = window.ProblemBuilderXBlockI18N.gettext;
+ var ngettext = window.ProblemBuilderXBlockI18N.ngettext;
return {
mentoring: null,
init: function(options) {
diff --git a/problem_builder/public/js/step_util.js b/problem_builder/public/js/step_util.js
index 06900667..63e210be 100644
--- a/problem_builder/public/js/step_util.js
+++ b/problem_builder/public/js/step_util.js
@@ -117,20 +117,3 @@
};
})();
-
-var gettext;
-var ngettext;
-if ('ProblemBuilderXBlockI18N' in window) {
- // Use problem builder's local translations
- gettext = window.ProblemBuilderXBlockI18N.gettext;
- ngettext = window.ProblemBuilderXBlockI18N.ngettext;
-} else if ('gettext' in window) {
- // Use edxapp's global translations
- gettext = window.gettext;
- ngettext = window.ngettext;
-}
-if (typeof gettext == "undefined") {
- // No translations -- used by test environment
- gettext = function(string) { return string; };
- ngettext = function(strA, strB, n) { return n == 1 ? strA : strB; };
-}
diff --git a/problem_builder/public/js/util.js b/problem_builder/public/js/util.js
index e4ca1951..31569af3 100644
--- a/problem_builder/public/js/util.js
+++ b/problem_builder/public/js/util.js
@@ -37,20 +37,3 @@ window.ProblemBuilderUtil = {
}
}
};
-
-var gettext;
-var ngettext;
-if ('ProblemBuilderXBlockI18N' in window) {
- // Use problem builder's local translations
- gettext = window.ProblemBuilderXBlockI18N.gettext;
- ngettext = window.ProblemBuilderXBlockI18N.ngettext;
-} else if ('gettext' in window) {
- // Use edxapp's global translations
- gettext = window.gettext;
- ngettext = window.ngettext;
-}
-if (typeof gettext == "undefined") {
- // No translations -- used by test environment
- gettext = function(string) { return string; };
- ngettext = function(strA, strB, n) { return n == 1 ? strA : strB; };
-}
diff --git a/problem_builder/step.py b/problem_builder/step.py
index 1e0bfab4..c4ca0894 100644
--- a/problem_builder/step.py
+++ b/problem_builder/step.py
@@ -20,9 +20,7 @@
import logging
-import pkg_resources
import six
-from django import utils
from lazy.lazy import lazy
from xblock.core import XBlock
from xblock.fields import List, Scope, String
@@ -43,6 +41,7 @@
from problem_builder.plot import PlotBlock
from problem_builder.slider import SliderBlock
from problem_builder.table import MentoringTableBlock
+from .mixins import TranslationContentMixin
from .utils import I18NService
@@ -77,7 +76,7 @@ class Correctness(object):
class MentoringStepBlock(
StudioEditableXBlockMixin, StudioContainerWithNestedXBlocksMixin, XBlockWithPreviewMixin,
EnumerableChildMixin, StepParentMixin, StudentViewUserStateResultsTransformerMixin,
- StudentViewUserStateMixin, XBlock, I18NService
+ StudentViewUserStateMixin, XBlock, I18NService, TranslationContentMixin
):
"""
An XBlock for a step.
@@ -243,27 +242,6 @@ def mentoring_view(self, context=None):
""" Mentoring View """
return self._render_view(context, 'mentoring_view')
- @staticmethod
- def resource_string(path):
- """Handy helper for getting resources from our kit."""
- data = pkg_resources.resource_string(__name__, path)
- return data.decode("utf8")
-
- def get_translation_content(self):
- try:
- # here we need to split the lang code and need to change - to _ and post - characters to
- # upper case since we have local directories like ja_JP, etc instead of ja-jp, etc
- language = utils.translation.get_language().split('-')
- if len(language) == 2:
- new_lang = language[0] + "_" + language[1].upper()
- else:
- new_lang = utils.translation.get_language()
- return self.resource_string('public/js/translations/{lang}/textjs.js'.format(
- lang=new_lang
- ))
- except IOError:
- return self.resource_string('public/js/translations/en/textjs.js')
-
def _render_view(self, context, view):
""" Actually renders a view """
rendering_for_studio = False
diff --git a/problem_builder/templates/html/mentoring_attempts.underscore b/problem_builder/templates/html/mentoring_attempts.underscore
deleted file mode 100644
index f9d9f32b..00000000
--- a/problem_builder/templates/html/mentoring_attempts.underscore
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/problem_builder/tests/unit/test_instructor_tool.py b/problem_builder/tests/unit/test_instructor_tool.py
index 8d6648b4..cc52f745 100644
--- a/problem_builder/tests/unit/test_instructor_tool.py
+++ b/problem_builder/tests/unit/test_instructor_tool.py
@@ -36,6 +36,8 @@ def _get_block(self, block_info):
def setUp(self):
self.course_id = 'course-v1:edX+DemoX+Demo_Course'
self.runtime_mock = Mock()
+ self.service_mock = Mock()
+ self.runtime_mock.service = Mock(return_value=self.service_mock)
self.runtime_mock.get_block = self._get_block
self.runtime_mock.course_id = self.course_id
scope_ids_mock = Mock()
@@ -57,13 +59,14 @@ def test_student_view_template_args(self):
}
with patch('problem_builder.instructor_tool.loader') as patched_loader:
- patched_loader.render_template.return_value = u''
+ patched_loader.render_django_template.return_value = u''
self.block.student_view()
- patched_loader.render_template.assert_called_once_with('templates/html/instructor_tool.html', {
+ self.service_mock.i18n_service = Mock(return_value=None)
+ patched_loader.render_django_template.assert_called_once_with('templates/html/instructor_tool.html', {
'block_choices': block_choices,
'course_blocks_api': COURSE_BLOCKS_API,
'root_block_id': self.course_id,
- })
+ }, i18n_service=self.service_mock)
def test_author_view(self):
"""
diff --git a/setup.py b/setup.py
index 122d5ade..d9a062b0 100644
--- a/setup.py
+++ b/setup.py
@@ -28,7 +28,7 @@
# Constants #########################################################
-VERSION = '3.4.23'
+VERSION = '3.5.0'
# Functions #########################################################