Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Form translation #719

Open
salvatj opened this issue Apr 20, 2022 · 6 comments
Open

Form translation #719

salvatj opened this issue Apr 20, 2022 · 6 comments

Comments

@salvatj
Copy link

salvatj commented Apr 20, 2022

Improve Form so we can translate the value of the submit button

form = Form(...., submit_button="Grabar") <-- does not work

and neither works this in the translations file

"Submit": {
"0": "Grabar"
},

@jparga
Copy link
Contributor

jparga commented Apr 20, 2022

This works

form.structure.find("[type=submit]")[0]["_value"] = "Grabar"

@salvatj
Copy link
Author

salvatj commented Apr 21, 2022

Also need to Translate other Form stuff like

"check to delete": {
"0": "Marcar para eliminar"
},

After submit having checked to delete, record is deleted but does not execute the code (browser stays static):
if form.accepted:
redirect(URL("index"))

@jparga
Copy link
Contributor

jparga commented Apr 21, 2022

form = Form([
        Field('product_name'),
        Field('product_quantity', 'integer', requires=IS_NOT_EMPTY()), 
        Field('conditions', type='boolean', label = T('check to delete')),
        ])

The field's labels are translated as usual with the T() fixture.

"check to delete": {
"0": "Marcar para eliminar"
},

@salvatj
Copy link
Author

salvatj commented Apr 21, 2022

This ticket searches an app wide solution to translate native Form stuff,
for simplicity and following the global py4web behavior with the Translations feature.

In the examples app, just add deletable=True to this action in controllers.py and test

@action("create_form", method=["GET", "POST"])
@action("update_form/", method=["GET", "POST"])
@action.uses("form.html", db, session, T)
def example_form(id=None):
form = Form(db.person, id, deletable=True, formstyle=FormStyleDefault)
rows = db(db.person).select()
return dict(form=form, rows=rows)

/translations/es.json

{
"Submit": {
"0": "Grabar"
},
"check to delete": {
"0": "Marcar para eliminar"
}
}

This way, app's will work as far as they find the proper translation language for the user of the app (es, it, fr, ...)
and no need to add extra coding lines in every action.

@jparga
Copy link
Contributor

jparga commented Apr 22, 2022

I agree this is a workaround and a form translation procedure is needed.

# exposed as /examples/create_form or /examples/update_form/<id>
@action("create_form", method=["GET", "POST"])
@action("update_form/<id>", method=["GET", "POST"])
@action.uses(db, session, T, "form.html")
def example_form(id=None):
    form = Form(db.person, id, deletable=True, formstyle=FormStyleDefault)
    rows = db(db.person).select()
    form.structure[4][1] = " Marcar para eliminar"
    form.structure.find("[type=submit]")[0]["_value"] = "Grabar"
    return dict(form=form, rows=rows)

In this case I looked into the form structure and then changed it in the controller. I we want to use T() then:

# exposed as /examples/create_form or /examples/update_form/<id>
@action("create_form", method=["GET", "POST"])
@action("update_form/<id>", method=["GET", "POST"])
@action.uses(db, session, T, "form.html")
def example_form(id=None):
    form = Form(db.person, id, deletable=True, formstyle=FormStyleDefault)
    rows = db(db.person).select()
    form.structure[4][1] = T(" check to delete")
    form.structure.find("[type=submit]")[0]["_value"] = T("Submit")
    return dict(form=form, rows=rows)

@laundmo
Copy link
Contributor

laundmo commented Oct 23, 2024

I ran into this issue as well, specifically also related to

This is my solution for general Form translation - though I haven't tested whether it leads to issues with multiple requests:

class TranslatedFormStyleFactory(FormStyleFactory):
    def __init__(self, translator):
        self.translator = translator
        super().__init__()

    def __call__(self, table, *args, **kwargs):
        labels_before = {} # store what labels were before translation

        # this "all_fields" code is copied from the original FormStyleFactor.__call__
        all_fields = [x for x in table]  # noqa: C416
        if "_virtual_fields" in dir(table):
            all_fields += table._virtual_fields

        # translate the fields labels after storing their original value
        for field in all_fields:
            labels_before[field] = field.label
            field.label = self.translator(field.label)

        # call the actual form style code which creates the forms html
        # this uses the translated field labels
        result = super().__call__(table, *args, **kwargs)

        # reset labels back to what they were before translation
        for field, before in labels_before.items():
            field.label = before

        return result

This requires passing the T instance to this FormStyleFactory, which means you have to redefine the existing form styles to use this factory
Here's how I've done that for Bulma:

from py4web.utils.form import FormStyleBulma as OriginalFormStyleBulma

T = Translator(...)

FormStyleBulma = TranslatedFormStyleFactory(T)
FormStyleBulma.classes.update(OriginalFormStyleBulma.classes)

I haven't extensively tested this, for example, I can imagine it may cause race condition issues when multiple clients request the same form with different translation. Potentially, the fact that I reset the label could reset them while another thread is using them. I just wanted to throw it out there as a possible solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants