From 3a5bef58cdb3c7e171b240074f800c523a823f31 Mon Sep 17 00:00:00 2001 From: Steph Date: Fri, 8 Dec 2023 16:32:17 -0500 Subject: [PATCH 01/27] add form model properties --- corehq/apps/app_manager/models.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/corehq/apps/app_manager/models.py b/corehq/apps/app_manager/models.py index 369abc077d26..74131bd2dc2f 100644 --- a/corehq/apps/app_manager/models.py +++ b/corehq/apps/app_manager/models.py @@ -1048,6 +1048,9 @@ class FormBase(DocumentSchema): # computed datums IDs that are allowed in endpoints function_datum_endpoints = StringListProperty() + submit_label = DictProperty(default={}) + submit_notification_label = DictProperty(default={}) + def __repr__(self): return f"{self.doc_type}(id='{self.id}', name='{self.default_name()}', unique_id='{self.unique_id}')" From 7f9fd56d375deed86d665f66f3518e2d94617d11 Mon Sep 17 00:00:00 2001 From: Steph Date: Tue, 12 Dec 2023 15:04:43 -0500 Subject: [PATCH 02/27] add getter function in form model --- corehq/apps/app_manager/models.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/corehq/apps/app_manager/models.py b/corehq/apps/app_manager/models.py index 74131bd2dc2f..001193006380 100644 --- a/corehq/apps/app_manager/models.py +++ b/corehq/apps/app_manager/models.py @@ -1341,6 +1341,11 @@ def get_save_to_case_updates(self): updates_by_case_type[case_type].update(save_to_case_update.properties) return updates_by_case_type + def get_submit_label(self, lang): + if lang in self.submit_label: + return self.submit_label[lang] + return 'Submit' + class IndexedFormBase(FormBase, IndexedSchema, CommentMixin): From b94b99869662ed802668de5dd4aa8956a81ed289 Mon Sep 17 00:00:00 2001 From: Steph Date: Tue, 12 Dec 2023 15:23:28 -0500 Subject: [PATCH 03/27] add to app translation upload & download code --- corehq/apps/translations/app_translations/download.py | 4 ++++ corehq/apps/translations/app_translations/upload_form.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/corehq/apps/translations/app_translations/download.py b/corehq/apps/translations/app_translations/download.py index a936b49197b2..e26589dd7bdb 100644 --- a/corehq/apps/translations/app_translations/download.py +++ b/corehq/apps/translations/app_translations/download.py @@ -392,6 +392,10 @@ def get_form_question_label_name_media(langs, form): value += part itext_items[text_id][(lang, value_form)] = value + itext_items['submit_label'] = {} + for lang in langs: + itext_items['submit_label'][(lang, 'default')] = form.get_submit_label(lang) + app = form.get_app() for text_id, values in itext_items.items(): row = [text_id] diff --git a/corehq/apps/translations/app_translations/upload_form.py b/corehq/apps/translations/app_translations/upload_form.py index 912668434953..505c847004f6 100644 --- a/corehq/apps/translations/app_translations/upload_form.py +++ b/corehq/apps/translations/app_translations/upload_form.py @@ -39,6 +39,7 @@ def __init__(self, app, sheet_name, unique_id=None, lang=None): # These attributes get populated by update self.markdowns = None self.markdown_vetoes = None + self.submit_label = None def _get_xform(self): if not isinstance(self.form, ShadowForm) and self.form.source: @@ -85,6 +86,9 @@ def update(self, rows): # Skip labels that have no translation provided label_ids_to_skip = self._get_label_ids_to_skip(rows) + if self.submit_label: + self._update_translation(self.submit_label, self.form.submit_label) + # Update the translations for lang in self.langs: translation_node = self.itext.find("./{f}translation[@lang='%s']" % lang) From e847adf953e901223b57c409934b92e9122dd37f Mon Sep 17 00:00:00 2001 From: Steph Date: Tue, 12 Dec 2023 15:24:05 -0500 Subject: [PATCH 04/27] add translation to id_strings --- corehq/apps/app_manager/id_strings.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/corehq/apps/app_manager/id_strings.py b/corehq/apps/app_manager/id_strings.py index 0fd44d2a5766..c4f9798c4699 100644 --- a/corehq/apps/app_manager/id_strings.py +++ b/corehq/apps/app_manager/id_strings.py @@ -415,6 +415,14 @@ def form_custom_icon_locale(form, icon_form): ) +@pattern('forms.m%df%d.submit_label') +def form_submit_label_locale(form): + return "forms.m{module.id}f{form.id}.submit_label".format( + module=form.get_module(), + form=form + ) + + @pattern('case_list_form.m%d.icon') def case_list_form_icon_locale(module): return "case_list_form.m{module.id}.icon".format(module=module) From 8692cbf50e565188785eed2bbe71f79dad0e7da9 Mon Sep 17 00:00:00 2001 From: Steph Date: Tue, 12 Dec 2023 15:24:46 -0500 Subject: [PATCH 05/27] add to app_strings and test --- corehq/apps/app_manager/app_strings.py | 2 ++ .../apps/app_manager/tests/test_app_strings.py | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/corehq/apps/app_manager/app_strings.py b/corehq/apps/app_manager/app_strings.py index 53b4deb89f0a..f2117071deb9 100644 --- a/corehq/apps/app_manager/app_strings.py +++ b/corehq/apps/app_manager/app_strings.py @@ -479,6 +479,8 @@ def _create_forms_app_strings( clean_trans(custom_assertion.text, langs) ) + yield id_strings.form_submit_label_locale(form), form.get_submit_label(lang) + def _create_case_list_form_app_strings( app, diff --git a/corehq/apps/app_manager/tests/test_app_strings.py b/corehq/apps/app_manager/tests/test_app_strings.py index d1aa911d0f89..42976e3aa276 100644 --- a/corehq/apps/app_manager/tests/test_app_strings.py +++ b/corehq/apps/app_manager/tests/test_app_strings.py @@ -256,3 +256,20 @@ def test_no_items_text_app_strings(self): en_app_strings = self._generate_app_strings(app, 'default', build_profile_id='en') except AttributeError: self.fail("_generate_app_strings raised AttributeError unexpectedly") + + def test_form_submit_label(self): + factory = AppFactory(build_version='2.40.0') + factory.app.langs = ['en', 'es'] + module, form = factory.new_basic_module('my_module', 'cases') + form.submit_label = { + 'en': 'Submit Button', + 'es': 'Botón de Enviar', + } + en_strings = self._generate_app_strings(factory.app, 'en') + self.assertEqual(en_strings['forms.m0f0.submit_label'], form.submit_label['en']) + + es_strings = self._generate_app_strings(factory.app, 'es') + self.assertEqual(es_strings['forms.m0f0.submit_label'], form.submit_label['es']) + + default_strings = self._generate_app_strings(factory.app, 'default') + self.assertEqual(default_strings['forms.m0f0.submit_label'], form.submit_label['en']) From aaea02f32b9bb77a6e57b6116b856ab06368c7ac Mon Sep 17 00:00:00 2001 From: Steph Date: Thu, 14 Dec 2023 14:48:38 -0500 Subject: [PATCH 06/27] use notification text by lang rather than set constant --- corehq/form_processor/submission_post.py | 32 +++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/corehq/form_processor/submission_post.py b/corehq/form_processor/submission_post.py index 3356f31ee7aa..9838f3f685b0 100644 --- a/corehq/form_processor/submission_post.py +++ b/corehq/form_processor/submission_post.py @@ -166,8 +166,12 @@ def _get_success_message(self, instance, cases=None): return ' √ ' user = CouchUser.get_by_user_id(instance.user_id) - messages = [_("'{form_name}' successfully saved!") - .format(form_name=self._get_form_name(instance, user))] + notification_text = self._get_form_submission_text(instance, user) + if notification_text: + messages = [notification_text] + else: + messages = [_("'{form_name}' successfully saved!") + .format(form_name=self._get_form_name(instance, user))] if user and user.is_web_user(): messages.extend(self._success_message_links(user, instance, cases)) return "\n\n".join(messages) @@ -182,6 +186,17 @@ def _get_form_name(self, instance, user): return names[default_language] return instance.name + def _get_form_submission_text(self, instance, user): + if instance.build_id: + default_language, submission_text_by_lang = _get_form_submit_notification_text_info(instance.domain, + instance.build_id) + submission_text_dict = submission_text_by_lang.get(instance.xmlns, {}) + if user and user.language and submission_text_dict.get(user.language): + return submission_text_dict[user.language] + if submission_text_dict.get(default_language): + return submission_text_dict[default_language] + return None + def _success_message_links(self, user, instance, cases): """Yield links to reports/exports, if accessible""" from corehq.apps.export.views.list import CaseExportListView, FormExportListView @@ -230,7 +245,6 @@ def _success_message_links(self, user, instance, cases): elif case_export_link: yield _("Click to export your [case data]({}).").format(case_export_link) - def run(self): self.track_load() with self.timing_context("process_xml"): @@ -671,3 +685,15 @@ def _get_form_name_info(domain, build_id): app_build.default_language, {form.xmlns: dict(form.name) for form in app_build.get_forms() if form.form_type != 'shadow_form'} ) + + +@quickcache(['domain', 'build_id']) +def _get_form_submit_notification_text_info(domain, build_id): + try: + app_build = get_current_app(domain, build_id) + except ResourceNotFound: + return 'en', {} + return ( + app_build.default_language, + {form.xmlns: dict(form.submit_notification_label) for form in app_build.get_forms()} + ) From f54f43433d8082c04504e3c1a5dc673c76a8cbc4 Mon Sep 17 00:00:00 2001 From: Steph Date: Thu, 14 Dec 2023 15:29:22 -0500 Subject: [PATCH 07/27] add migration --- .../commands/add_form_translation_fields.py | 53 +++++++++++++++++++ .../migrations/0030_add_form_translations.py | 22 ++++++++ 2 files changed, 75 insertions(+) create mode 100644 corehq/apps/app_manager/management/commands/add_form_translation_fields.py create mode 100644 corehq/apps/app_manager/migrations/0030_add_form_translations.py diff --git a/corehq/apps/app_manager/management/commands/add_form_translation_fields.py b/corehq/apps/app_manager/management/commands/add_form_translation_fields.py new file mode 100644 index 000000000000..3b948d7791fc --- /dev/null +++ b/corehq/apps/app_manager/management/commands/add_form_translation_fields.py @@ -0,0 +1,53 @@ +from corehq.apps.app_manager.management.commands.helpers import AppMigrationCommandBase +from corehq.apps.app_manager.models import Application + +from dimagi.utils.chunked import chunked +from corehq.util.log import with_progress_bar + + +class ResourceNotFound(object): + pass + + +class Command(AppMigrationCommandBase): + help = """ + Populate new 'submit_label' and 'submit_notification_label' in the FormBase class with language translations + """ + + def get_apps(self): + return Application.objects.all() + + def get_apps_to_migrate(self): + apps_to_migrate = [] + apps = self.get_apps() + for app in chunked(with_progress_bar(apps), 100): + if self._app_need_to_be_migrated(app.build_spec.version): + apps_to_migrate.append(app) + return apps_to_migrate + + def _app_need_to_be_migrated(self, app_version): + major, minor, patch = [int(x) for x in app_version.split('.')] + return major >= 2 and minor >= 53 + + def migrate_form(self, form, translations): + submit_label_dict = {} + form_submission_notification_label_dict = {} + for lang in translations.items(): + submit_label_dict[lang] = "Submit" + form_submission_notification_label_dict[lang] = "${0} successfully saved!" + form.submit_label = submit_label_dict + form.submit_notification_label = form_submission_notification_label_dict + + def migrate(self, app): + try: + translations = app.translations + except (ResourceNotFound, AttributeError): + return + modules = list(self.app.get_modules()) + for module in modules: + for form in module.get_forms(): + self.migrate_form(form, translations) + + def handle(self): + for app in self.apps_to_migrate(): + self.migrate(app) diff --git a/corehq/apps/app_manager/migrations/0030_add_form_translations.py b/corehq/apps/app_manager/migrations/0030_add_form_translations.py new file mode 100644 index 000000000000..ded7937815a9 --- /dev/null +++ b/corehq/apps/app_manager/migrations/0030_add_form_translations.py @@ -0,0 +1,22 @@ +from django.core.management import call_command +from django.db import migrations + +from corehq.util.django_migrations import skip_on_fresh_install + + +class Migration(migrations.Migration): + + @skip_on_fresh_install + def _populate_form_translation_fields(apps, schema_editor): + call_command("add_form_translation_fields") + + dependencies = [ + ('app_manager', '0029_delete_case_list_custom_variable_xml'), + ] + + operations = [ + migrations.RunPython( + _populate_form_translation_fields, + reverse_code=migrations.RunPython.noop, + ), + ] From 7c95176fb5dcb681b2473f962454ed80a0db5f90 Mon Sep 17 00:00:00 2001 From: Steph Date: Fri, 15 Dec 2023 16:37:47 -0500 Subject: [PATCH 08/27] replace submit text with submit translation from translations --- .../cloudcare/static/cloudcare/js/form_entry/form_ui.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js b/corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js index 567dc116d699..3f73d87d288d 100644 --- a/corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js +++ b/corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js @@ -458,11 +458,17 @@ hqDefine("cloudcare/js/form_entry/form_ui", function () { return !self.isSubmitting() && self.erroredQuestions().length === 0; }); + self.getSubmitTranslation = function () { + var translations = self.translations; + const [key, _] = Object.entries(translations).find(([k]) => k.includes("submit_label")); + return ko.toJS(translations[key]); + }; + self.submitText = ko.computed(function () { if (self.isSubmitting()) { return gettext('Submitting...'); } - return gettext('Submit'); + return gettext(self.getSubmitTranslation()); }); self.forceRequiredVisible = ko.observable(false); From 80a42dd61e9dc7a56cb4f06b33c55185f8869127 Mon Sep 17 00:00:00 2001 From: Steph Date: Fri, 15 Dec 2023 17:20:48 -0500 Subject: [PATCH 09/27] swap DictProperty for LabelProperty --- corehq/apps/app_manager/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/corehq/apps/app_manager/models.py b/corehq/apps/app_manager/models.py index 74131bd2dc2f..f2d45e315ecc 100644 --- a/corehq/apps/app_manager/models.py +++ b/corehq/apps/app_manager/models.py @@ -1048,8 +1048,8 @@ class FormBase(DocumentSchema): # computed datums IDs that are allowed in endpoints function_datum_endpoints = StringListProperty() - submit_label = DictProperty(default={}) - submit_notification_label = DictProperty(default={}) + submit_label = LabelProperty(default={}) + submit_notification_label = LabelProperty(default={}) def __repr__(self): return f"{self.doc_type}(id='{self.id}', name='{self.default_name()}', unique_id='{self.unique_id}')" From 382db9039ca4a7c7b5e38d90b1217ecc31601ddf Mon Sep 17 00:00:00 2001 From: Steph Date: Fri, 15 Dec 2023 17:41:28 -0500 Subject: [PATCH 10/27] add getter function in form model --- corehq/apps/app_manager/models.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/corehq/apps/app_manager/models.py b/corehq/apps/app_manager/models.py index 3ce928436958..6401fdad1f1e 100644 --- a/corehq/apps/app_manager/models.py +++ b/corehq/apps/app_manager/models.py @@ -1347,6 +1347,11 @@ def get_submit_label(self, lang): return self.submit_label[lang] return 'Submit' + def get_submit_notification_label(self, lang): + if lang in self.submit_notification_label: + return self.get_submit_notification_label[lang] + return None + class IndexedFormBase(FormBase, IndexedSchema, CommentMixin): From a2ddb8e16d3d3172d8d24cf5de5779d220dd8a75 Mon Sep 17 00:00:00 2001 From: Steph Date: Fri, 15 Dec 2023 17:46:16 -0500 Subject: [PATCH 11/27] add to app translation upload & download code --- corehq/apps/translations/app_translations/download.py | 2 ++ corehq/apps/translations/app_translations/upload_form.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/corehq/apps/translations/app_translations/download.py b/corehq/apps/translations/app_translations/download.py index 804c9ce76f4d..a6da03ae7ecc 100644 --- a/corehq/apps/translations/app_translations/download.py +++ b/corehq/apps/translations/app_translations/download.py @@ -381,8 +381,10 @@ def get_form_question_label_name_media(langs, form): itext_items[text_id][(lang, value_form)] = value itext_items['submit_label'] = {} + itext_items['submit_notification_label'] = {} for lang in langs: itext_items['submit_label'][(lang, 'default')] = form.get_submit_label(lang) + itext_items['submit_notification_label'][(lang, 'default')] = form.get_submit_notification_label(lang) app = form.get_app() for text_id, values in itext_items.items(): diff --git a/corehq/apps/translations/app_translations/upload_form.py b/corehq/apps/translations/app_translations/upload_form.py index 67fbeacc84d0..18684947ffde 100644 --- a/corehq/apps/translations/app_translations/upload_form.py +++ b/corehq/apps/translations/app_translations/upload_form.py @@ -40,6 +40,7 @@ def __init__(self, app, sheet_name, unique_id=None, lang=None): self.markdowns = None self.markdown_vetoes = None self.submit_label = None + self.submit_notification_label = None def _get_xform(self): if not isinstance(self.form, ShadowForm) and self.form.source: @@ -89,6 +90,9 @@ def update(self, rows): if self.submit_label: self._update_translation(self.submit_label, self.form.submit_label) + if self.submit_notification_label: + self._update_translation(self.submit_notification_label, self.form.submit_notification_label) + # Update the translations for lang in self.langs: translation_node = self.itext.find("./{f}translation[@lang='%s']" % lang) From acd7bf2008514d6cdc765368d7a2efd2cd2b12cd Mon Sep 17 00:00:00 2001 From: Steph Date: Fri, 15 Dec 2023 17:49:23 -0500 Subject: [PATCH 12/27] add translation to id_strings --- corehq/apps/app_manager/id_strings.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/corehq/apps/app_manager/id_strings.py b/corehq/apps/app_manager/id_strings.py index ce938a176d4b..f5299f5dbffe 100644 --- a/corehq/apps/app_manager/id_strings.py +++ b/corehq/apps/app_manager/id_strings.py @@ -422,6 +422,14 @@ def form_submit_label_locale(form): ) +@pattern('forms.m%df%d.submit_notification_label') +def form_submit_notification_label_locale(form): + return "forms.m{module.id}f{form.id}.submit_notification_label".format( + module=form.get_module(), + form=form + ) + + @pattern('case_list_form.m%d.icon') def case_list_form_icon_locale(module): return "case_list_form.m{module.id}.icon".format(module=module) From 161b2e941f693166681a3d70d10b468398e3e443 Mon Sep 17 00:00:00 2001 From: Steph Date: Fri, 15 Dec 2023 17:55:21 -0500 Subject: [PATCH 13/27] add to app_strings and update test --- corehq/apps/app_manager/app_strings.py | 1 + corehq/apps/app_manager/tests/test_app_strings.py | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/corehq/apps/app_manager/app_strings.py b/corehq/apps/app_manager/app_strings.py index f2117071deb9..ff1d5c25a3fa 100644 --- a/corehq/apps/app_manager/app_strings.py +++ b/corehq/apps/app_manager/app_strings.py @@ -480,6 +480,7 @@ def _create_forms_app_strings( ) yield id_strings.form_submit_label_locale(form), form.get_submit_label(lang) + yield id_strings.form_notification_submit_label_locale(form), form.get_submit_notification_label(lang) def _create_case_list_form_app_strings( diff --git a/corehq/apps/app_manager/tests/test_app_strings.py b/corehq/apps/app_manager/tests/test_app_strings.py index 88677d149712..ad7d97a893df 100644 --- a/corehq/apps/app_manager/tests/test_app_strings.py +++ b/corehq/apps/app_manager/tests/test_app_strings.py @@ -267,11 +267,19 @@ def test_form_submit_label(self): 'en': 'Submit Button', 'es': 'Botón de Enviar', } + form.submit_notification_label = { + 'en': 'You submitted the form!', + 'es': '¡Enviaste el formulario!', + } en_strings = self._generate_app_strings(factory.app, 'en') self.assertEqual(en_strings['forms.m0f0.submit_label'], form.submit_label['en']) + self.assertEqual(en_strings['forms.m0f0.submit_notification_label'], form.submit_notification_label['en']) es_strings = self._generate_app_strings(factory.app, 'es') self.assertEqual(es_strings['forms.m0f0.submit_label'], form.submit_label['es']) + self.assertEqual(es_strings['forms.m0f0.submit_notification_label'], form.submit_notification_label['es']) default_strings = self._generate_app_strings(factory.app, 'default') self.assertEqual(default_strings['forms.m0f0.submit_label'], form.submit_label['en']) + self.assertEqual(default_strings['forms.m0f0.submit_notification_label'], + form.submit_notification_label['en']) From 7782026c91b9f5629423c2c0da195143590f0e71 Mon Sep 17 00:00:00 2001 From: Steph Date: Sun, 17 Dec 2023 13:08:11 -0500 Subject: [PATCH 14/27] remove migration --- .../commands/add_form_translation_fields.py | 53 ------------------- .../migrations/0030_add_form_translations.py | 22 -------- 2 files changed, 75 deletions(-) delete mode 100644 corehq/apps/app_manager/management/commands/add_form_translation_fields.py delete mode 100644 corehq/apps/app_manager/migrations/0030_add_form_translations.py diff --git a/corehq/apps/app_manager/management/commands/add_form_translation_fields.py b/corehq/apps/app_manager/management/commands/add_form_translation_fields.py deleted file mode 100644 index 3b948d7791fc..000000000000 --- a/corehq/apps/app_manager/management/commands/add_form_translation_fields.py +++ /dev/null @@ -1,53 +0,0 @@ -from corehq.apps.app_manager.management.commands.helpers import AppMigrationCommandBase -from corehq.apps.app_manager.models import Application - -from dimagi.utils.chunked import chunked -from corehq.util.log import with_progress_bar - - -class ResourceNotFound(object): - pass - - -class Command(AppMigrationCommandBase): - help = """ - Populate new 'submit_label' and 'submit_notification_label' in the FormBase class with language translations - """ - - def get_apps(self): - return Application.objects.all() - - def get_apps_to_migrate(self): - apps_to_migrate = [] - apps = self.get_apps() - for app in chunked(with_progress_bar(apps), 100): - if self._app_need_to_be_migrated(app.build_spec.version): - apps_to_migrate.append(app) - return apps_to_migrate - - def _app_need_to_be_migrated(self, app_version): - major, minor, patch = [int(x) for x in app_version.split('.')] - return major >= 2 and minor >= 53 - - def migrate_form(self, form, translations): - submit_label_dict = {} - form_submission_notification_label_dict = {} - for lang in translations.items(): - submit_label_dict[lang] = "Submit" - form_submission_notification_label_dict[lang] = "${0} successfully saved!" - form.submit_label = submit_label_dict - form.submit_notification_label = form_submission_notification_label_dict - - def migrate(self, app): - try: - translations = app.translations - except (ResourceNotFound, AttributeError): - return - modules = list(self.app.get_modules()) - for module in modules: - for form in module.get_forms(): - self.migrate_form(form, translations) - - def handle(self): - for app in self.apps_to_migrate(): - self.migrate(app) diff --git a/corehq/apps/app_manager/migrations/0030_add_form_translations.py b/corehq/apps/app_manager/migrations/0030_add_form_translations.py deleted file mode 100644 index ded7937815a9..000000000000 --- a/corehq/apps/app_manager/migrations/0030_add_form_translations.py +++ /dev/null @@ -1,22 +0,0 @@ -from django.core.management import call_command -from django.db import migrations - -from corehq.util.django_migrations import skip_on_fresh_install - - -class Migration(migrations.Migration): - - @skip_on_fresh_install - def _populate_form_translation_fields(apps, schema_editor): - call_command("add_form_translation_fields") - - dependencies = [ - ('app_manager', '0029_delete_case_list_custom_variable_xml'), - ] - - operations = [ - migrations.RunPython( - _populate_form_translation_fields, - reverse_code=migrations.RunPython.noop, - ), - ] From 028264ed26f0f4d4f3072ca8e1a38c23b1d42730 Mon Sep 17 00:00:00 2001 From: Steph Date: Mon, 18 Dec 2023 12:25:04 -0500 Subject: [PATCH 15/27] fail gracefully if nothing contains submit_label --- .../static/cloudcare/js/form_entry/form_ui.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js b/corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js index a6cec130ae3e..053b3d020ef2 100644 --- a/corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js +++ b/corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js @@ -460,8 +460,14 @@ hqDefine("cloudcare/js/form_entry/form_ui", function () { self.getSubmitTranslation = function () { var translations = self.translations; - const [key, _] = Object.entries(translations).find(([k]) => k.includes("submit_label")); - return ko.toJS(translations[key]); + if (translations) { + const result = Object.entries(translations).find(([k]) => k.includes("submit_label")); + if (result) { + const [key, _] = result; // Destructuring the found entry + return ko.toJS(translations[key]); + } + } + return "Submit"; }; self.submitText = ko.computed(function () { From d3febb65556be46868b3d9fc448609efed60fb80 Mon Sep 17 00:00:00 2001 From: Steph Date: Mon, 18 Dec 2023 12:56:00 -0500 Subject: [PATCH 16/27] add submit_label to test cases in test_bulk_app_translation.py --- .../tests/test_bulk_app_translation.py | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/corehq/apps/translations/tests/test_bulk_app_translation.py b/corehq/apps/translations/tests/test_bulk_app_translation.py index e75126e60f53..f6424e7adf41 100644 --- a/corehq/apps/translations/tests/test_bulk_app_translation.py +++ b/corehq/apps/translations/tests/test_bulk_app_translation.py @@ -95,10 +95,12 @@ 'jr://file/commcare/image/data/What_does_this_look_like.png', '', ''), ('no_media-label', 'No media', '', '', ''), ('has_refs-label', 'Here is a ref with some trailing text ' - 'and "bad" < xml.', '', '', ''))), + 'and "bad" < xml.', '', '', ''), + ('submit_label', 'Submit', '', '', ''))), ('menu2', (('no_items_text', 'list', 'List is empty.'), ('name', 'list', 'Name'), ('name', 'detail', 'Name'))), ('menu2_form1', - ('name_of_series-label', 'Name of series', '', '', '')), + (('name_of_series-label', 'Name of series', '', '', ''), + ('submit_label', 'Submit', '', '', ''))), ('menu3', (('no_items_text', 'list', 'List is empty.'), ('name', 'list', 'Name'), @@ -114,7 +116,8 @@ ('graph annotation 1', 'detail', 'This is (2, 2)'))), ('menu3_form1', (('x-label', 'x', '', '' ''), - ('y-label', 'y', '', '', ''))), + ('y-label', 'y', '', '', ''), + ('submit_label', 'Submit', '', '', ''))), ('menu4', (('no_items_text', 'list', 'List is empty.'), ('x', 'list', 'X'), @@ -127,12 +130,13 @@ (('confirm_remove-label', 'Swipe to remove the point at ( ,).'), - '', '', '')), + '/casedb/case[@case_id = instance(\'commcaresession\')/session/data/case_id]/y"/>).', '', '', ''), + ('submit_label', 'Submit', '', '', ''))), ('menu5', ()), ('menu6', (('no_items_text', 'list', 'List is empty.'), ('name', 'list', 'Name'), ('name', 'detail', 'Name'))), ('menu6_form1', - (('this_form_does_nothing-label', 'This form does nothing.', '', '', ''),)), + (('this_form_does_nothing-label', 'This form does nothing.', '', '', ''), + ('submit_label', 'Submit', '', '', ''))), ) @@ -1130,6 +1134,7 @@ def test_form_rows(self): ['has_refs-label', 'Here is a ref with some trailing text and "bad" < xml.', '', '', ''], + ['submit_label', 'Submit', '', '', ''] ]) @patch.object(Application, 'supports_empty_case_list_text', lambda: True) @@ -1137,6 +1142,12 @@ def test_bulk_app_sheet_rows(self): actual_headers = get_bulk_app_sheet_headers(self.app) actual_sheets = get_bulk_app_sheets_by_name(self.app) + print() + print() + print(title for title, headers in actual_headers) + print() + + actual_workbook = [ {'name': title, 'rows': [dict(zip(headers, row)) for row in actual_sheets[title]]} @@ -1203,6 +1214,7 @@ def test_bulk_app_single_sheet_rows(self): ['menu1_form1', '', '', 'has_refs-label', 'Here is a ref with some trailing text and "bad" < xml.', '', '', '', ''], + ['menu1_form1', '', '', 'submit_label', 'Submit', '', '', '', ''], ['menu2', '', '', '', 'Register Series', '', '', '', 'b9c25abe21054632a3623199debd7cfa'], ['menu2', 'name', 'list', '', 'Name', '', '', '', ''], @@ -1210,6 +1222,7 @@ def test_bulk_app_single_sheet_rows(self): ['menu2_form1', '', '', '', 'Registration Form', None, None, '', '280b1b06d1b442b9bba863453ba30bc3'], ['menu2_form1', '', '', 'name_of_series-label', 'Name of series', '', '', '', ''], + ['menu2_form1', '', '', 'submit_label', 'Submit', '', '', '', ''], ['menu3', '', '', '', 'Followup Series', '', '', '', '217e1c8de3dd46f98c7d2806bc19b580'], ['menu3', 'name', 'list', '', 'Name', '', '', '', ''], @@ -1227,6 +1240,7 @@ def test_bulk_app_single_sheet_rows(self): ['menu3_form1', '', '', '', 'Add Point to Series', None, None, '', 'a01b55fd2c1a483492c1166029946249'], ['menu3_form1', '', '', 'x-label', 'x', '', '', '', ''], ['menu3_form1', '', '', 'y-label', 'y', '', '', '', ''], + ['menu3_form1', '', '', 'submit_label', 'Submit', '', '', '', ''], ['menu4', '', '', '', 'Remove Point', '', '', '', '17195132472446ed94bd91ba19a2b379'], ['menu4', 'x', 'list', '', 'X', '', '', '', ''], @@ -1241,6 +1255,7 @@ def test_bulk_app_single_sheet_rows(self): '( ,).', '', '', '', ''], + ['menu4_form1', '', '', 'submit_label', 'Submit', '', '', '', ''], ['menu5', '', '', '', 'Empty Reports Module', '', '', '', '703eb807ae584d1ba8bf9457d7ac7590'], @@ -1250,6 +1265,7 @@ def test_bulk_app_single_sheet_rows(self): ['menu6_form1', '', '', '', 'Advanced Form', None, None, '', '2b9c856ba2ea4ec1ab8743af299c1627'], ['menu6_form1', '', '', 'this_form_does_nothing-label', 'This form does nothing.', '', '', '', ''], + ['menu6_form1', '', '', 'submit_label', 'Submit', '', '', '', ''], ['menu6_form2', '', '', '', 'Shadow Form', '', '', '', 'c42e1a50123c43f2bd1e364f5fa61379']]) def test_bulk_app_single_sheet_blacklisted(self): From f8e281a5cfd6fcde87b3cfd87ecabad3cb8dae80 Mon Sep 17 00:00:00 2001 From: Steph Date: Mon, 18 Dec 2023 18:46:51 -0500 Subject: [PATCH 17/27] remove leftovr print statments --- corehq/apps/translations/tests/test_bulk_app_translation.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/corehq/apps/translations/tests/test_bulk_app_translation.py b/corehq/apps/translations/tests/test_bulk_app_translation.py index f6424e7adf41..460b935464e6 100644 --- a/corehq/apps/translations/tests/test_bulk_app_translation.py +++ b/corehq/apps/translations/tests/test_bulk_app_translation.py @@ -1142,12 +1142,6 @@ def test_bulk_app_sheet_rows(self): actual_headers = get_bulk_app_sheet_headers(self.app) actual_sheets = get_bulk_app_sheets_by_name(self.app) - print() - print() - print(title for title, headers in actual_headers) - print() - - actual_workbook = [ {'name': title, 'rows': [dict(zip(headers, row)) for row in actual_sheets[title]]} From 9b9f4309ff65e067e863342415584f09d3d83ec6 Mon Sep 17 00:00:00 2001 From: Steph Date: Mon, 18 Dec 2023 20:11:47 -0500 Subject: [PATCH 18/27] modify logic on upload to save the new submit_label to the form --- .../apps/translations/app_translations/upload_form.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/corehq/apps/translations/app_translations/upload_form.py b/corehq/apps/translations/app_translations/upload_form.py index 67fbeacc84d0..d1925f30d73f 100644 --- a/corehq/apps/translations/app_translations/upload_form.py +++ b/corehq/apps/translations/app_translations/upload_form.py @@ -39,7 +39,6 @@ def __init__(self, app, sheet_name, unique_id=None, lang=None): # These attributes get populated by update self.markdowns = None self.markdown_vetoes = None - self.submit_label = None def _get_xform(self): if not isinstance(self.form, ShadowForm) and self.form.source: @@ -86,9 +85,6 @@ def update(self, rows): # Skip labels that have no translation provided label_ids_to_skip = self._get_label_ids_to_skip(rows) - if self.submit_label: - self._update_translation(self.submit_label, self.form.submit_label) - # Update the translations for lang in self.langs: translation_node = self.itext.find("./{f}translation[@lang='%s']" % lang) @@ -97,6 +93,12 @@ def update(self, rows): for row in rows: if row['label'] in label_ids_to_skip: continue + if row['label'] == 'submit_label': + try: + self.form.submit_label[lang] = row[self._get_col_key('default', lang)] + except KeyError: + pass + continue try: self._add_or_remove_translations(lang, row) except BulkAppTranslationsException as e: From 88176c989989ee27d0fc9c491dc186e83d53af3f Mon Sep 17 00:00:00 2001 From: Steph Date: Mon, 18 Dec 2023 20:12:20 -0500 Subject: [PATCH 19/27] add upload test for submit label --- .../translations/tests/test_bulk_app_translation.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/corehq/apps/translations/tests/test_bulk_app_translation.py b/corehq/apps/translations/tests/test_bulk_app_translation.py index 460b935464e6..8bb0c458aac9 100644 --- a/corehq/apps/translations/tests/test_bulk_app_translation.py +++ b/corehq/apps/translations/tests/test_bulk_app_translation.py @@ -398,6 +398,7 @@ class BulkAppTranslationBasicTest(BulkAppTranslationTestBaseWithApp): ('remove_markdown-label', 'no longer markdown', 'just plain text', '', '', '', '', '', ''), ('vetoed_markdown-label', '*i just happen to like stars a lot*', '*i just happen to like stars a lot*', '', '', '', '', '', ''), + ("submit_label", "new submit", "nouveau", "", "", "", "", "", ""), )) ) @@ -784,6 +785,16 @@ def test_empty_translations(self): ] ) + def test_form_submit_label_on_upload(self): + form = self.app.get_module(0).get_form(0) + form.submit_label = {'en': 'old label', 'fra': 'passé'} + self.assertEqual(form.submit_label, {'en': 'old label', 'fra': 'passé'}) + + # note changes on upload with new value + self.upload_raw_excel_translations(self.multi_sheet_upload_headers, self.multi_sheet_upload_data) + self.assertEqual(form.submit_label, {'en': 'new submit', 'fra': 'nouveau'}) + + def test_case_search_labels_on_upload(self): module = self.app.get_module(0) From 073f508bde6b269e47982242d09256912af511ca Mon Sep 17 00:00:00 2001 From: Steph Date: Mon, 18 Dec 2023 20:20:58 -0500 Subject: [PATCH 20/27] modify upload logic to properly update submit_notification_label --- .../apps/translations/app_translations/upload_form.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/corehq/apps/translations/app_translations/upload_form.py b/corehq/apps/translations/app_translations/upload_form.py index 2ef80ec468eb..04795ca37638 100644 --- a/corehq/apps/translations/app_translations/upload_form.py +++ b/corehq/apps/translations/app_translations/upload_form.py @@ -39,7 +39,6 @@ def __init__(self, app, sheet_name, unique_id=None, lang=None): # These attributes get populated by update self.markdowns = None self.markdown_vetoes = None - self.submit_notification_label = None def _get_xform(self): if not isinstance(self.form, ShadowForm) and self.form.source: @@ -86,9 +85,6 @@ def update(self, rows): # Skip labels that have no translation provided label_ids_to_skip = self._get_label_ids_to_skip(rows) - if self.submit_notification_label: - self._update_translation(self.submit_notification_label, self.form.submit_notification_label) - # Update the translations for lang in self.langs: translation_node = self.itext.find("./{f}translation[@lang='%s']" % lang) @@ -103,6 +99,12 @@ def update(self, rows): except KeyError: pass continue + if row['label'] == 'submit_notification_label': + try: + self.form.submit_notification_label[lang] = row[self._get_col_key('default', lang)] + except KeyError: + pass + continue try: self._add_or_remove_translations(lang, row) except BulkAppTranslationsException as e: From 52be9ae1de9ba9fd2eef5074ef9bd3d2f714564b Mon Sep 17 00:00:00 2001 From: Steph Date: Mon, 18 Dec 2023 20:21:34 -0500 Subject: [PATCH 21/27] add test for upload of submit_notification_label --- .../translations/tests/test_bulk_app_translation.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/corehq/apps/translations/tests/test_bulk_app_translation.py b/corehq/apps/translations/tests/test_bulk_app_translation.py index 8bb0c458aac9..f4f3c78227ca 100644 --- a/corehq/apps/translations/tests/test_bulk_app_translation.py +++ b/corehq/apps/translations/tests/test_bulk_app_translation.py @@ -399,6 +399,7 @@ class BulkAppTranslationBasicTest(BulkAppTranslationTestBaseWithApp): ('vetoed_markdown-label', '*i just happen to like stars a lot*', '*i just happen to like stars a lot*', '', '', '', '', '', ''), ("submit_label", "new submit", "nouveau", "", "", "", "", "", ""), + ("submit_notification_label", "new submit notification", "nouveau", "", "", "", "", "", ""), )) ) @@ -794,6 +795,15 @@ def test_form_submit_label_on_upload(self): self.upload_raw_excel_translations(self.multi_sheet_upload_headers, self.multi_sheet_upload_data) self.assertEqual(form.submit_label, {'en': 'new submit', 'fra': 'nouveau'}) + def test_submit_notification_label_on_upload(self): + form = self.app.get_module(0).get_form(0) + form.submit_notification_label = {'en': 'old submission label', 'fra': 'passé'} + self.assertEqual(form.submit_notification_label, {'en': 'old submission label', 'fra': 'passé'}) + + # note changes on upload with new value + self.upload_raw_excel_translations(self.multi_sheet_upload_headers, self.multi_sheet_upload_data) + self.assertEqual(form.submit_notification_label, {'en': 'new submit notification', 'fra': 'nouveau'}) + def test_case_search_labels_on_upload(self): module = self.app.get_module(0) From 9a288ed9b5504ee03076ead2be6322a482efdeba Mon Sep 17 00:00:00 2001 From: Steph Date: Mon, 18 Dec 2023 20:28:30 -0500 Subject: [PATCH 22/27] check if submit_notification_label exists in getter function --- corehq/apps/app_manager/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/corehq/apps/app_manager/models.py b/corehq/apps/app_manager/models.py index 5bcbed864350..6aec46f2745b 100644 --- a/corehq/apps/app_manager/models.py +++ b/corehq/apps/app_manager/models.py @@ -1348,7 +1348,7 @@ def get_submit_label(self, lang): return 'Submit' def get_submit_notification_label(self, lang): - if lang in self.submit_notification_label: + if self.submit_notification_label and lang in self.submit_notification_label: return self.get_submit_notification_label[lang] return None From c85d3aaf2fe2e5bf3eb99131ec21c9b7a399f778 Mon Sep 17 00:00:00 2001 From: Steph Date: Mon, 18 Dec 2023 21:26:38 -0500 Subject: [PATCH 23/27] correct naming of form_submit_notification_label_locale --- corehq/apps/app_manager/app_strings.py | 3 +-- .../apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/corehq/apps/app_manager/app_strings.py b/corehq/apps/app_manager/app_strings.py index ff1d5c25a3fa..1ca714e37264 100644 --- a/corehq/apps/app_manager/app_strings.py +++ b/corehq/apps/app_manager/app_strings.py @@ -480,8 +480,7 @@ def _create_forms_app_strings( ) yield id_strings.form_submit_label_locale(form), form.get_submit_label(lang) - yield id_strings.form_notification_submit_label_locale(form), form.get_submit_notification_label(lang) - + yield id_strings.form_submit_notification_label_locale(form), form.get_submit_notification_label(lang) def _create_case_list_form_app_strings( app, diff --git a/corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js b/corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js index 053b3d020ef2..d0878caa9f2d 100644 --- a/corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js +++ b/corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js @@ -460,10 +460,13 @@ hqDefine("cloudcare/js/form_entry/form_ui", function () { self.getSubmitTranslation = function () { var translations = self.translations; + console.log(translations) if (translations) { const result = Object.entries(translations).find(([k]) => k.includes("submit_label")); + console.log(result) if (result) { const [key, _] = result; // Destructuring the found entry + console.log(ko.toJS(translations[key])) return ko.toJS(translations[key]); } } From ac034e3cc3b87af5f410704311ea6375b514bc4c Mon Sep 17 00:00:00 2001 From: Steph Date: Mon, 18 Dec 2023 21:48:30 -0500 Subject: [PATCH 24/27] implement workaround for build issues with default value --- corehq/apps/app_manager/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/corehq/apps/app_manager/models.py b/corehq/apps/app_manager/models.py index 6aec46f2745b..31ee44a9256d 100644 --- a/corehq/apps/app_manager/models.py +++ b/corehq/apps/app_manager/models.py @@ -1350,7 +1350,7 @@ def get_submit_label(self, lang): def get_submit_notification_label(self, lang): if self.submit_notification_label and lang in self.submit_notification_label: return self.get_submit_notification_label[lang] - return None + return 'Successfully saved!' # TODO: figure our default value since setting to None cause build issues class IndexedFormBase(FormBase, IndexedSchema, CommentMixin): From f3997f95400d4426feb2be5ace1cdaadb5de373c Mon Sep 17 00:00:00 2001 From: Steph Date: Tue, 19 Dec 2023 09:54:51 -0500 Subject: [PATCH 25/27] get rid of unused variable --- corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js b/corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js index 053b3d020ef2..43f2ccaf7ed2 100644 --- a/corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js +++ b/corehq/apps/cloudcare/static/cloudcare/js/form_entry/form_ui.js @@ -463,7 +463,7 @@ hqDefine("cloudcare/js/form_entry/form_ui", function () { if (translations) { const result = Object.entries(translations).find(([k]) => k.includes("submit_label")); if (result) { - const [key, _] = result; // Destructuring the found entry + const key = result[0]; return ko.toJS(translations[key]); } } From 971e16ac66535ceafed19463f36750dc65e85db1 Mon Sep 17 00:00:00 2001 From: Steph Date: Tue, 19 Dec 2023 12:56:55 -0500 Subject: [PATCH 26/27] correctly return submit_notification_label[lang] --- corehq/apps/app_manager/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/corehq/apps/app_manager/models.py b/corehq/apps/app_manager/models.py index 31ee44a9256d..2d640cb3f10d 100644 --- a/corehq/apps/app_manager/models.py +++ b/corehq/apps/app_manager/models.py @@ -1349,7 +1349,7 @@ def get_submit_label(self, lang): def get_submit_notification_label(self, lang): if self.submit_notification_label and lang in self.submit_notification_label: - return self.get_submit_notification_label[lang] + return self.submit_notification_label[lang] return 'Successfully saved!' # TODO: figure our default value since setting to None cause build issues From 77ad5dd489f636f91a765190528f9c4de9cd807d Mon Sep 17 00:00:00 2001 From: Steph Date: Tue, 19 Dec 2023 13:22:44 -0500 Subject: [PATCH 27/27] allow for blank submit notifiction row for download, but only upload the change if the value is not blank --- corehq/apps/app_manager/models.py | 2 +- corehq/apps/translations/app_translations/download.py | 3 +++ corehq/apps/translations/app_translations/upload_form.py | 5 ++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/corehq/apps/app_manager/models.py b/corehq/apps/app_manager/models.py index 2d640cb3f10d..c7461c813726 100644 --- a/corehq/apps/app_manager/models.py +++ b/corehq/apps/app_manager/models.py @@ -1350,7 +1350,7 @@ def get_submit_label(self, lang): def get_submit_notification_label(self, lang): if self.submit_notification_label and lang in self.submit_notification_label: return self.submit_notification_label[lang] - return 'Successfully saved!' # TODO: figure our default value since setting to None cause build issues + return '' class IndexedFormBase(FormBase, IndexedSchema, CommentMixin): diff --git a/corehq/apps/translations/app_translations/download.py b/corehq/apps/translations/app_translations/download.py index a6da03ae7ecc..70a40271208c 100644 --- a/corehq/apps/translations/app_translations/download.py +++ b/corehq/apps/translations/app_translations/download.py @@ -402,5 +402,8 @@ def get_form_question_label_name_media(langs, form): # Don't add empty rows: if any(row[1:]): rows.append(row) + # allow empty for submit_notification_label row + if row[0] == 'submit_notification_label' and not any(row[1:]): + rows.append(row) return rows diff --git a/corehq/apps/translations/app_translations/upload_form.py b/corehq/apps/translations/app_translations/upload_form.py index 04795ca37638..ea3d796445e0 100644 --- a/corehq/apps/translations/app_translations/upload_form.py +++ b/corehq/apps/translations/app_translations/upload_form.py @@ -100,10 +100,13 @@ def update(self, rows): pass continue if row['label'] == 'submit_notification_label': + notification_value = '' try: - self.form.submit_notification_label[lang] = row[self._get_col_key('default', lang)] + notification_value = row[self._get_col_key('default', lang)] except KeyError: pass + if notification_value: + self.form.submit_notification_label[lang] = notification_value continue try: self._add_or_remove_translations(lang, row)