XLSForm / pyxform

A Python package to create XForms for ODK Collect.
BSD 2-Clause "Simplified" License
77 stars 134 forks source link

Translations not generated for choice list used with search() #689

Closed lognaturel closed 5 months ago

lognaturel commented 5 months ago

Software and hardware versions

pyxform v2.0.1

Problem description

https://forum.getodk.org/t/text-is-not-localizable-for-default-locale/44745

Steps to reproduce the problem

Convert attached form using --skip_validate, notice that an inline select is generated:

            <select1 appearance="autocomplete search('registered_participants')" ref="/data/Select_benefic/search_idcode">
                <label ref="jr:itext('/data/Select_benefic/search_idcode:label')"/>
                <item>
                    <label ref="jr:itext('/data/Select_benefic/search_idcode/foo:label')"/>
                    <value>foo</value>
                </item>
                <item>
                    <label ref="jr:itext('/data/Select_benefic/search_idcode/id_:label')"/>
                    <value>id_</value>
                </item>
            </select1>

But there's no corresponding translation.

Expected behavior

With v1.12.1, we also get

                    <text id="/data/Select_benefic/search_idcode/id_:label">
                        <value>fullname</value>
                    </text>

Other information

I briefly thought it could be something else:

But it's definitely related to the search()-specific code path since an inline select is still generated.

We should continue to generate an inline select in this special case, we just need the translation to also be generated just to satisfy Validate.

lindsay-stevens commented 5 months ago

Some context from May 2023 in this comment:

# External selects from a "search" appearance alone don't work in Enketo. In Collect
# they must have the "item" elements in the body, rather than in an "itemset".

It would be worth checking if the special case is still necessary, since there have been a few Collect releases since then.

lognaturel commented 5 months ago

Yes, it is, we haven't touched that functionality in Collect. search() exists way outside the ODK XForms spec and we don't document it, instead favoring select_*_from_file. It's still in some use, though, so we continue to support it as-is.

lognaturel commented 5 months ago

Failing test:

    def test_includes_translations_for_items(self):
        """Should include translation for items used to configure search() in order to pass validation"""
        md = """
        | survey  |                        |       |            |           |                    |
        |         | type                   | name  | label::en  | label::fr | appearance         |
        |         | select_one things      | thing | Thing      | Chose     | search('my_file')  |
        | choices |                        |       |            |           |
        |         | list_name              | name  | label::en  | label::fr |
        |         | things                 | id    | label_en   | label_fr  |
        """
        self.assertPyxformXform(
            md=md,
            debug=True,
            xml__xpath_match=[
               "/h:html/h:body/x:select1/x:item/x:label",
                xpc.model_itext_choice_text_label_by_pos(
                    "en", "things", ["label_en"]
                ),
                xpc.model_itext_choice_text_label_by_pos(
                    "fr", "things", ["label_fr"]
                )
            ]
        )

Looking at a fix...

lognaturel commented 5 months ago

I initially thought we could remove the check on not is_search in xls2json and also generate a secondary instance for the weird single-item choice list in order to force translations. But that changes the select to a select from secondary instance which won't work.

I'm out of ideas for now. Hoping there's something relatively straightforward that I'm missing!

lindsay-stevens commented 5 months ago

OK thanks, I will have a look.