Skip to content

Commit

Permalink
Merge pull request #468 from XLSForm/464-select-single-language-images
Browse files Browse the repository at this point in the history
  • Loading branch information
lognaturel authored Sep 9, 2020
2 parents 50921a8 + 47072dc commit e5bb800
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 40 deletions.
7 changes: 6 additions & 1 deletion pyxform/question.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,16 @@ def build_xml(self):
if self["itemset"] and isinstance(self["itemset"], basestring):
choice_filter = self.get("choice_filter")
itemset, file_extension = os.path.splitext(self["itemset"])
has_media = False

if choices.get(itemset):
has_media = bool(choices[itemset][0].get("media"))

if file_extension in [".csv", ".xml"]:
itemset = itemset
itemset_label_ref = "label"
else:
if not multi_language:
if not multi_language and not has_media:
itemset = self["itemset"]
itemset_label_ref = "label"
else:
Expand Down
72 changes: 45 additions & 27 deletions pyxform/survey.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,12 +227,13 @@ def _generate_static_instances(list_name, choice_list):
"""
instance_element_list = []
multi_language = isinstance(choice_list[0].get("label"), dict)
has_media = bool(choice_list[0].get("media"))
for idx, choice in enumerate(choice_list):
choice_element_list = []
# Add a unique id to the choice element in case there is itext
# it references
if multi_language:
itext_id = "-".join(["static_instance", list_name, str(idx)])
if multi_language or has_media:
itext_id = "-".join([list_name, str(idx)])
choice_element_list.append(node("itextId", itext_id))

for name, value in sorted(choice.items()):
Expand Down Expand Up @@ -590,31 +591,41 @@ def _setup_choice_translations(name, choice_value, itext_id):

self._translations = defaultdict(dict) # pylint: disable=W0201
for element in self.iter_descendants():
for d in element.get_translations(self.default_language):

translation_path = d["path"]
form = "long"

if "guidance_hint" in d["path"]:
translation_path = d["path"].replace("guidance_hint", "hint")
form = "guidance"

self._translations[d["lang"]][translation_path] = self._translations[
d["lang"]
].get(translation_path, {})

self._translations[d["lang"]][translation_path].update(
{form: {"text": d["text"], "output_context": d["output_context"],}}
)
# Skip creation of translations for choices in filtered selects
# The creation of these translations is done futher below in this
# function
parent = element.get("parent")
if parent and not parent.get("choice_filter"):
for d in element.get_translations(self.default_language):
translation_path = d["path"]
form = "long"

if "guidance_hint" in d["path"]:
translation_path = d["path"].replace("guidance_hint", "hint")
form = "guidance"

self._translations[d["lang"]][
translation_path
] = self._translations[d["lang"]].get(translation_path, {})

self._translations[d["lang"]][translation_path].update(
{
form: {
"text": d["text"],
"output_context": d["output_context"],
}
}
)

# This code sets up translations for choices in filtered selects.
for list_name, choice_list in self.choices.items():
multi_language = isinstance(choice_list[0].get("label"), dict)
if not multi_language:
has_media = bool(choice_list[0].get("media"))
if not multi_language and not has_media:
continue
for idx, choice in zip(range(len(choice_list)), choice_list):
for name, choice_value in choice.items():
itext_id = "-".join(["static_instance", list_name, str(idx)])
itext_id = "-".join([list_name, str(idx)])
if isinstance(choice_value, dict):
_setup_choice_translations(name, choice_value, itext_id)
elif name == "label":
Expand Down Expand Up @@ -651,14 +662,8 @@ def _setup_media(self):
{language : {element_xpath : {media_type : media}}}
It matches the xform nesting order.
"""
if not self._translations:
self._translations = defaultdict(dict) # pylint: disable=W0201

for survey_element in self.iter_descendants():

translation_key = survey_element.get_xpath() + ":label"
media_dict = survey_element.get("media")

def _set_up_media_translations(media_dict, translation_key):
# This is probably papering over a real problem, but anyway,
# in py3, sometimes if an item is on an xform with multiple
# languages and the item only has media defined in # "default"
Expand Down Expand Up @@ -702,6 +707,19 @@ def _setup_media(self):

translations_trans_key[media_type] = media

if not self._translations:
self._translations = defaultdict(dict) # pylint: disable=W0201

for survey_element in self.iter_descendants():
# Skip set up of media for choices in filtered selects.
# Translations for the media content should have been set up
# in _setup_translations
parent = survey_element.get("parent")
if parent and not parent.get("choice_filter"):
translation_key = survey_element.get_xpath() + ":label"
media_dict = survey_element.get("media")
_set_up_media_translations(media_dict, translation_key)

def itext(self):
"""
This function creates the survey's itext nodes from _translations
Expand Down
96 changes: 84 additions & 12 deletions pyxform/tests_v1/test_inline_translations.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ def test_inline_translations(self):
"<label>c</label>",
],
model__excludes=[
'<text id="static_instance-states-0">',
'<text id="static_instance-states-1">',
'<text id="static_instance-states-2">',
"<itextId>static_instance-states-0</itextId>",
"<itextId>static_instance-states-1</itextId>",
"<itextId>static_instance-states-2</itextId>",
'<text id="states-0">',
'<text id="states-1">',
'<text id="states-2">',
"<itextId>states-0</itextId>",
"<itextId>states-1</itextId>",
"<itextId>states-2</itextId>",
],
xml__contains=['<label ref="label"/>'],
xml__excludes=['<label ref="jr:itext(itextId)"/>'],
Expand All @@ -59,12 +59,12 @@ def test_multiple_translations(self):
name="data",
id_string="some-id",
model__contains=[
'<text id="static_instance-states-0">',
'<text id="static_instance-states-1">',
'<text id="static_instance-states-2">',
"<itextId>static_instance-states-0</itextId>",
"<itextId>static_instance-states-1</itextId>",
"<itextId>static_instance-states-2</itextId>",
'<text id="states-0">',
'<text id="states-1">',
'<text id="states-2">',
"<itextId>states-0</itextId>",
"<itextId>states-1</itextId>",
"<itextId>states-2</itextId>",
],
model__excludes=[
"<label>a</label>",
Expand All @@ -74,3 +74,75 @@ def test_multiple_translations(self):
xml__contains=['<label ref="jr:itext(itextId)"/>'],
xml__excludes=['<label ref="label"/>'],
)

def test_select_with_media_and_choice_filter_and_no_translations_generates_media(
self,
):
"""
Selects with media and choice filter should generate itext fields for the media.
"""
xform_md = """
| survey | | | | |
| | type | name | label | choice_filter |
| | select_one consent | consent | Would you like to participate ? | |
| | select_one mood | enumerator_mood | How are you feeling today ? | selected(${consent}, 'y') |
| choices |
| | list_name | name | label | media::image |
| | mood | h | Happy | happy.jpg |
| | mood | s | Sad | sad.jpg |
| | consent | y | Yes | |
| | consent | n | No | |
"""
self.assertPyxformXform(
name="data",
id_string="some-id",
md=xform_md,
errored=False,
debug=False,
model__contains=[
'<text id="mood-0">',
'<text id="mood-1">',
"<itextId>mood-0</itextId>",
"<itextId>mood-1</itextId>",
],
model__excludes=[
'<text id="/data/enumerator_mood/h:label">',
'<text id="/data/enumerator_mood/s:label">',
],
xml__contains=['<label ref="jr:itext(itextId)"/>'],
xml__excludes=['<label ref="label"/>'],
)

def test_select_with_choice_filter_and_translations_generates_single_translation(
self,
):
"""
Selects with choice filter and translations should only have a single itext entry.
"""
xform_md = """
| survey | | | | |
| | type | name | label | choice_filter |
| | select_one list | foo | Foo | name != " |
| choices |
| | list_name | name | label | image | label::French |
| | list | a | A | a.jpg | Ah |
| | list | b | B | b.jpg | Bé |
| | list | c | C | c.jpg | Cé |
"""
self.assertPyxformXform(
name="data",
id_string="some-id",
md=xform_md,
errored=False,
debug=False,
itext__contains=[
'<text id="list-0">',
'<text id="list-1">',
'<text id="list-2">',
],
itext__excludes=[
'<text id="/data/foo/a:label">',
'<text id="/data/foo/b:label">',
'<text id="/data/foo/c:label">',
],
)

0 comments on commit e5bb800

Please sign in to comment.