diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8f3e520c95..71a6455d83 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,10 @@ the top. Include a label indicating the component affected. LMS: Fix issue with CourseMode expiration dates +CMS: Add text_customization Dict to advanced settings which can support +string customization at particular spots in the UI. At first just customizing +the Check/Final Check buttons with keys: custom_check and custom_final_check + LMS: Add PaidCourseRegistration mode, where payment is required before course registration. diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py index 88b911a745..03a4ad6365 100644 --- a/common/lib/xmodule/xmodule/capa_module.py +++ b/common/lib/xmodule/xmodule/capa_module.py @@ -152,6 +152,12 @@ class CapaFields(object): help="Source code for LaTeX and Word problems. This feature is not well-supported.", scope=Scope.settings ) + text_customization = Dict( + help="String customization substitutions for particular locations", + scope=Scope.settings + # TODO: someday it should be possible to not duplicate this definition here + # and in inheritance.py + ) class CapaModule(CapaFields, XModule): @@ -342,14 +348,26 @@ class CapaModule(CapaFields, XModule): Determine the name for the "check" button. Usually it is just "Check", but if this is the student's - final attempt, change the name to "Final Check" + final attempt, change the name to "Final Check". + The text can be customized by the text_customization setting. """ - if self.max_attempts is not None: - final_check = (self.attempts >= self.max_attempts - 1) - else: - final_check = False + # The logic flow is a little odd so that _('xxx') strings can be found for + # translation while also running _() just once for each string. + check = _('Check') + final_check = _('Final Check') - return _("Final Check") if final_check else _("Check") + # Apply customizations if present + if 'custom_check' in self.text_customization: + check = _(self.text_customization.get('custom_check')) + if 'custom_final_check' in self.text_customization: + final_check = _(self.text_customization.get('custom_final_check')) + # TODO: need a way to get the customized words into the list of + # words to be translated + + if self.max_attempts is not None and self.attempts >= self.max_attempts - 1: + return final_check + else: + return check def should_show_check_button(self): """ diff --git a/common/lib/xmodule/xmodule/modulestore/inheritance.py b/common/lib/xmodule/xmodule/modulestore/inheritance.py index d68c121b96..a518034e61 100644 --- a/common/lib/xmodule/xmodule/modulestore/inheritance.py +++ b/common/lib/xmodule/xmodule/modulestore/inheritance.py @@ -1,7 +1,7 @@ from datetime import datetime from pytz import UTC -from xblock.fields import Scope, Boolean, String, Float, XBlockMixin +from xblock.fields import Scope, Boolean, String, Float, XBlockMixin, Dict from xmodule.fields import Date, Timedelta from xblock.runtime import KeyValueStore @@ -43,6 +43,10 @@ class InheritanceMixin(XBlockMixin): scope=Scope.settings ) static_asset_path = String(help="Path to use for static assets - overrides Studio c4x://", scope=Scope.settings, default='') + text_customization = Dict( + help="String customization substitutions for particular locations", + scope=Scope.settings + ) def compute_inherited_metadata(descriptor): @@ -87,6 +91,7 @@ def own_metadata(module): """ return module.get_explicitly_set_fields_by_scope(Scope.settings) + class InheritanceKeyValueStore(KeyValueStore): """ Common superclass for kvs's which know about inheritance of settings. Offers simple diff --git a/common/lib/xmodule/xmodule/tests/test_capa_module.py b/common/lib/xmodule/xmodule/tests/test_capa_module.py index c47cfc2ca8..7cbdc130ae 100644 --- a/common/lib/xmodule/xmodule/tests/test_capa_module.py +++ b/common/lib/xmodule/xmodule/tests/test_capa_module.py @@ -77,7 +77,8 @@ class CapaFactory(object): attempts=None, problem_state=None, correct=False, - done=None + done=None, + text_customization=None ): """ All parameters are optional, and are added to the created problem if specified. @@ -113,6 +114,8 @@ class CapaFactory(object): field_data['rerandomize'] = rerandomize if done is not None: field_data['done'] = done + if text_customization is not None: + field_data['text_customization'] = text_customization descriptor = Mock(weight="1") if problem_state is not None: @@ -837,6 +840,19 @@ class CapaModuleTest(unittest.TestCase): module = CapaFactory.create(attempts=0) self.assertEqual(module.check_button_name(), "Check") + def test_check_button_name_customization(self): + module = CapaFactory.create(attempts=1, + max_attempts=10, + text_customization={"custom_check": "Submit", "custom_final_check": "Final Submit"} + ) + self.assertEqual(module.check_button_name(), "Submit") + + module = CapaFactory.create(attempts=9, + max_attempts=10, + text_customization={"custom_check": "Submit", "custom_final_check": "Final Submit"} + ) + self.assertEqual(module.check_button_name(), "Final Submit") + def test_should_show_check_button(self): attempts = random.randint(1, 10)