Skip to content

Commit

Permalink
MCKIN-21527 Problem Builder (FTE, Assessment, MCQ, MRQ) - On opening …
Browse files Browse the repository at this point in the history
…these modules, none of the text is translated on notifications dropdown. (#298)
  • Loading branch information
wasifarbisoft authored Aug 28, 2020
1 parent 687bc77 commit 8ef282b
Show file tree
Hide file tree
Showing 13 changed files with 69 additions and 98 deletions.
10 changes: 7 additions & 3 deletions problem_builder/instructor_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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'))
Expand Down
7 changes: 3 additions & 4 deletions problem_builder/mentoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -227,7 +227,7 @@ def max_score(self):

class MentoringBlock(
StudentViewUserStateResultsTransformerMixin, I18NService,
BaseMentoringBlock, StudioContainerWithNestedXBlocksMixin, StepParentMixin,
BaseMentoringBlock, StudioContainerWithNestedXBlocksMixin, StepParentMixin, TranslationContentMixin
):
"""
An XBlock providing mentoring capabilities
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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(),
})
Expand Down
26 changes: 26 additions & 0 deletions problem_builder/mixins.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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')
3 changes: 2 additions & 1 deletion problem_builder/public/js/instructor_tool.js
Original file line number Diff line number Diff line change
@@ -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);
Expand Down
17 changes: 10 additions & 7 deletions problem_builder/public/js/mentoring.js
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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("<span>" + message + "</span>");
}
}

function renderDependency() {
Expand Down
19 changes: 9 additions & 10 deletions problem_builder/public/js/mentoring_with_steps.js
Original file line number Diff line number Diff line change
@@ -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 = [];
Expand All @@ -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;
Expand Down Expand Up @@ -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("<span>" + message + "</span>");
} // Don't show attempts if unlimited attempts available (max_attempts === 0)
}

Expand Down
3 changes: 3 additions & 0 deletions problem_builder/public/js/questionnaire.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ function MessageView(element, mentoring) {
}

function MCQBlock(runtime, element) {
var gettext = window.ProblemBuilderXBlockI18N.gettext;
return {
mentoring: null,
init: function(options) {
Expand Down Expand Up @@ -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) {
Expand Down
17 changes: 0 additions & 17 deletions problem_builder/public/js/step_util.js
Original file line number Diff line number Diff line change
Expand Up @@ -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; };
}
17 changes: 0 additions & 17 deletions problem_builder/public/js/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -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; };
}
26 changes: 2 additions & 24 deletions problem_builder/step.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
11 changes: 0 additions & 11 deletions problem_builder/templates/html/mentoring_attempts.underscore

This file was deleted.

9 changes: 6 additions & 3 deletions problem_builder/tests/unit/test_instructor_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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):
"""
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

# Constants #########################################################

VERSION = '3.4.23'
VERSION = '3.5.0'

# Functions #########################################################

Expand Down

0 comments on commit 8ef282b

Please sign in to comment.