diff --git a/common/lib/capa/capa/capa_problem.py b/common/lib/capa/capa/capa_problem.py index 209c7ddd50..90a336bde0 100644 --- a/common/lib/capa/capa/capa_problem.py +++ b/common/lib/capa/capa/capa_problem.py @@ -71,7 +71,11 @@ class LoncapaSystem(object): can provide these resources however make sense for their environment, and this code can remain independent. - See :class:`ModuleSystem` for documentation of these attributes. + Attributes: + i18n: an object implementing the `gettext.Translations` interface so + that we can use `.ugettext` to localize strings. + + See :class:`ModuleSystem` for documentation of other attributes. """ def __init__( # pylint: disable=invalid-name @@ -82,6 +86,7 @@ class LoncapaSystem(object): can_execute_unsafe_code, DEBUG, # pylint: disable=invalid-name filestore, + i18n, node_path, render_template, seed, # Why do we do this if we have self.seed? @@ -94,6 +99,7 @@ class LoncapaSystem(object): self.can_execute_unsafe_code = can_execute_unsafe_code self.DEBUG = DEBUG # pylint: disable=invalid-name self.filestore = filestore + self.i18n = i18n self.node_path = node_path self.render_template = render_template self.seed = seed # Why do we do this if we have self.seed? diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index 5db1f61920..ed7b4bfddd 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -875,8 +875,9 @@ class NumericalResponse(LoncapaResponse): correct_ans = evaluator({}, {}, self.correct_answer) except Exception: log.debug("Content error--answer '%s' is not a valid number", self.correct_answer) + _ = self.capa_system.i18n.ugettext raise StudentInputError( - "There was a problem with the staff answer to this problem" + _("There was a problem with the staff answer to this problem") ) return correct_ans diff --git a/common/lib/capa/capa/tests/__init__.py b/common/lib/capa/capa/tests/__init__.py index db0af9cc8a..d5d3f87f81 100644 --- a/common/lib/capa/capa/tests/__init__.py +++ b/common/lib/capa/capa/tests/__init__.py @@ -1,5 +1,6 @@ """Tools for helping with testing capa.""" +import gettext import os import os.path @@ -41,6 +42,7 @@ def test_capa_system(): can_execute_unsafe_code=lambda: False, DEBUG=True, filestore=fs.osfs.OSFS(os.path.join(TEST_DIR, "test_files")), + i18n=gettext.NullTranslations(), node_path=os.environ.get("NODE_PATH", "/usr/local/lib/node_modules"), render_template=tst_render_template, seed=0, diff --git a/common/lib/capa/capa/tests/test_responsetypes.py b/common/lib/capa/capa/tests/test_responsetypes.py index ebf985ceed..d614ac9d27 100644 --- a/common/lib/capa/capa/tests/test_responsetypes.py +++ b/common/lib/capa/capa/tests/test_responsetypes.py @@ -1140,6 +1140,24 @@ class NumericalResponseTest(ResponseTest): "Content error--answer '%s' is not a valid number", staff_ans ) + @mock.patch('capa.responsetypes.log') + def test_responsetype_i18n(self, mock_log): + """Test that LoncapaSystem has an i18n that works.""" + staff_ans = "clearly bad syntax )[+1e" + problem = self.build_problem(answer=staff_ans, tolerance=1e-3) + + class FakeTranslations(object): + """A fake gettext.Translations object.""" + def ugettext(self, text): + """Return the 'translation' of `text`.""" + if text == "There was a problem with the staff answer to this problem": + text = "TRANSLATED!" + return text + problem.capa_system.i18n = FakeTranslations() + + with self.assertRaisesRegexp(StudentInputError, "TRANSLATED!"): + self.assert_grade(problem, '1+j', 'correct') + def test_grade_infinity(self): """ Check that infinity doesn't automatically get marked correct. diff --git a/common/lib/xmodule/xmodule/capa_base.py b/common/lib/xmodule/xmodule/capa_base.py index 7091d4e45f..1475bae4b0 100644 --- a/common/lib/xmodule/xmodule/capa_base.py +++ b/common/lib/xmodule/xmodule/capa_base.py @@ -267,6 +267,7 @@ class CapaMixin(CapaFields): can_execute_unsafe_code=self.system.can_execute_unsafe_code, DEBUG=self.system.DEBUG, filestore=self.system.filestore, + i18n=self.system.service(self, "i18n"), node_path=self.system.node_path, render_template=self.system.render_template, seed=self.system.seed, # Why do we do this if we have self.seed?