diff --git a/corehq/apps/app_manager/app_strings.py b/corehq/apps/app_manager/app_strings.py
index 89fa5f8f18f6..b3c0b30179b1 100644
--- a/corehq/apps/app_manager/app_strings.py
+++ b/corehq/apps/app_manager/app_strings.py
@@ -155,7 +155,7 @@ def _create_module_details_app_strings(module, langs):
clean_trans(column.header, langs)
)
- if column.format in ('enum', 'conditional-enum', 'enum-image', 'clickable-icon'):
+ if column.format in ('enum', 'conditional-enum', 'enum-image', 'clickable-icon', 'translatable-enum'):
for item in column.enum:
yield (
id_strings.detail_column_enum_variable(
diff --git a/corehq/apps/app_manager/detail_screen.py b/corehq/apps/app_manager/detail_screen.py
index 7c418ad9eb33..669f19b9fd11 100644
--- a/corehq/apps/app_manager/detail_screen.py
+++ b/corehq/apps/app_manager/detail_screen.py
@@ -142,8 +142,7 @@ def template(self):
form=self.template_form,
width=self.template_width,
)
-
- if self.column.useXpathExpression:
+ if self.column.useXpathExpression and self.column.format != 'translatable-enum':
xpath = sx.CalculatedPropertyXPath(function=self.xpath)
if re.search(r'\$lang', self.xpath):
xpath.variables.node.append(
@@ -192,8 +191,9 @@ def sort_node(self):
locale_id=self.id_strings.current_language()
).node
)
- xpath_variable = sx.XPathVariable(name='calculated_property', xpath=xpath)
- sort.text.xpath.variables.node.append(xpath_variable.node)
+ if self.column.format != 'translatable-enum':
+ xpath_variable = sx.XPathVariable(name='calculated_property', xpath=xpath)
+ sort.text.xpath.variables.node.append(xpath_variable.node)
if self.sort_element:
if not sort:
@@ -307,7 +307,8 @@ def fields(self):
endpoint_action=self.action,
alt_text=self.alt_text,
)
- elif self.sort_xpath_function and self.detail.display == 'short':
+ elif (self.sort_xpath_function and self.detail.display == 'short'
+ and self.column.format != 'translatable-enum'):
yield sx.Field(
style=self.style,
header=self.header,
@@ -517,6 +518,30 @@ def _xpath_template_context(self, type):
}
+@register_format_type('translatable-enum')
+class TranslatableEnum(Enum):
+ @property
+ def sort_node(self):
+ node = super(TranslatableEnum, self).sort_node
+ if node:
+ variables = self.variables
+ for key in variables:
+ node.text.xpath.node.append(
+ sx.XPathVariable(name=key, locale_id=variables[key]).node
+ )
+ return node
+
+ def _make_xpath(self, type):
+ return sx.XPathEnum.build(
+ enum=self.column.enum,
+ format=self.column.format,
+ type=type,
+ template=None,
+ get_template_context=lambda: {'calculated_property': self.xpath},
+ get_value=lambda key: self.id_strings.detail_column_enum_variable(self.module, self.detail_type,
+ self.column, key))
+
+
@register_format_type('late-flag')
class LateFlag(HideShortHeaderColumn):
template_width = "11%"
diff --git a/corehq/apps/app_manager/static/app_manager/js/details/column.js b/corehq/apps/app_manager/static/app_manager/js/details/column.js
index b0ce9092260b..166f83d166e0 100644
--- a/corehq/apps/app_manager/static/app_manager/js/details/column.js
+++ b/corehq/apps/app_manager/static/app_manager/js/details/column.js
@@ -1,3 +1,4 @@
+'use strict';
/**
* Model for a column in the Display Properties section of case list/detail.
*
@@ -231,6 +232,9 @@ hqDefine("app_manager/js/details/column", function () {
}
}
}
+ } else {
+ // Restrict Translatable Text usage to Calculated Properties only
+ menuOptions.splice(-1);
}
self.format = uiElement.select(menuOptions).val(self.original.format || null);
@@ -245,6 +249,7 @@ hqDefine("app_manager/js/details/column", function () {
multimedia: self.screen.config.multimedia,
values_are_icons: self.original.format === 'enum-image',
keys_are_conditions: self.original.format === 'conditional-enum',
+ values_are_translatable: self.original.format === 'translatable-enum',
};
self.enum_extra = uiElement.key_value_mapping(o);
}());
@@ -394,9 +399,11 @@ hqDefine("app_manager/js/details/column", function () {
fireChange();
});
self.date_extra.value = format.val();
- } else if (this.val() === "enum" || this.val() === "enum-image" || this.val() === 'conditional-enum') {
+ } else if (this.val() === "enum" || this.val() === "enum-image"
+ || this.val() === 'conditional-enum' || this.val() === 'translatable-enum') {
self.enum_extra.values_are_icons(this.val() === 'enum-image');
self.enum_extra.keys_are_conditions(this.val() === 'conditional-enum');
+ self.enum_extra.values_are_translatable(this.val() === 'translatable-enum');
self.format.ui.parent().append(self.enum_extra.ui);
} else if (this.val() === "clickable-icon") {
self.enum_extra.values_are_icons(true);
diff --git a/corehq/apps/app_manager/static/app_manager/js/details/utils.js b/corehq/apps/app_manager/static/app_manager/js/details/utils.js
index f79db7b6e21a..73ee985c0a7b 100644
--- a/corehq/apps/app_manager/static/app_manager/js/details/utils.js
+++ b/corehq/apps/app_manager/static/app_manager/js/details/utils.js
@@ -1,3 +1,4 @@
+'use strict';
/* globals DOMPurify */
/**
* Contains a few UI utilities for the Display Properties
@@ -80,6 +81,12 @@ hqDefine("app_manager/js/details/utils", function () {
label: gettext('Conditional ID Mapping'),
});
}
+ if (addOns.calc_xpaths) {
+ formats.push({
+ value: "translatable-enum",
+ label: gettext('Translatable Text'),
+ });
+ }
if (hqImport('hqwebapp/js/toggles').toggleEnabled('VELLUM_CASE_MICRO_IMAGE')) {
formats.push({
diff --git a/corehq/apps/app_manager/suite_xml/case_tile_templates/bha_referrals.xml b/corehq/apps/app_manager/suite_xml/case_tile_templates/bha_referrals.xml
index 9abd4cae34d0..ca84f4ec0792 100644
--- a/corehq/apps/app_manager/suite_xml/case_tile_templates/bha_referrals.xml
+++ b/corehq/apps/app_manager/suite_xml/case_tile_templates/bha_referrals.xml
@@ -4,7 +4,9 @@
-
+
+ {custom_variables}
+