Skip to content

Commit f2bad3d

Browse files
committed
T=T for Auth, Grid, and Form
1 parent fde3bd3 commit f2bad3d

4 files changed

Lines changed: 68 additions & 37 deletions

File tree

apps/_scaffold/common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
# #######################################################
8888
# Instantiate the object and actions that handle auth
8989
# #######################################################
90-
auth = Auth(session, db, define_tables=False)
90+
auth = Auth(session, db, define_tables=False, T=T)
9191
auth.use_username = True
9292
auth.param.registration_requires_confirmation = settings.VERIFY_EMAIL
9393
auth.param.registration_requires_approval = settings.REQUIRES_APPROVAL

py4web/utils/auth.py

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ def __init__(
245245
two_factor_validate=None,
246246
template_args=None,
247247
logger=None,
248+
T=None,
248249
):
249250
# configuration parameters
250251
self.param = Param(
@@ -278,6 +279,12 @@ def __init__(
278279
# callbacks for forms
279280
self.on_accept = {}
280281

282+
# translator: if provided, translate user-facing messages immediately
283+
self.T = T if T is not None else (lambda s: s)
284+
self._messages_translated = False
285+
if T is not None:
286+
self._translate_messages(T)
287+
281288
self.__prerequisites__ = []
282289
self.inject = inject
283290
if session:
@@ -981,6 +988,23 @@ def _error(self, message, code=400):
981988
def _success(self, message, code=200):
982989
return {"status": "success", "message": message, "code": code}
983990

991+
def _translate_messages(self, T):
992+
"""Wrap every string value in self.param.messages with T()."""
993+
for group in self.param.messages.values():
994+
for key, value in group.items():
995+
if isinstance(value, str):
996+
group[key] = T(value)
997+
elif (
998+
key == "body"
999+
and isinstance(value, (list, tuple))
1000+
and len(value) == 2
1001+
):
1002+
group[key] = (T(value[0]), T(value[1]))
1003+
else:
1004+
raise RuntimeError(f"Invalid message type {key}:{value}")
1005+
self.T = T
1006+
self._messages_translated = True
1007+
9841008
# Other service methods (that can be overwritten)
9851009

9861010
def send(self, name, user, **attrs):
@@ -1064,20 +1088,8 @@ def enable(self, route="auth", uses=(), env=None, spa=False, allow_api_routes=Tr
10641088
auth = self
10651089

10661090
translators = [fixture for fixture in uses if isinstance(fixture, Translator)]
1067-
if translators:
1068-
T = translators[0]
1069-
for group in self.param.messages.values():
1070-
for key, value in group.items():
1071-
if isinstance(value, str):
1072-
group[key] = T(value)
1073-
elif (
1074-
key == "body"
1075-
and isinstance(value, (list, tuple))
1076-
and len(value) == 2
1077-
):
1078-
group[key] = (T(value[0]), T(value[1]))
1079-
else:
1080-
raise RuntimeError(f"Invalid message type {key}:{value}")
1091+
if translators and not self._messages_translated:
1092+
self._translate_messages(translators[0])
10811093

10821094
methods = ["GET", "POST", "OPTIONS"]
10831095

@@ -1602,7 +1614,7 @@ def register(self, model=False):
16021614
self.auth.get_or_delete_existing_unverified_account(email)
16031615
extra_form_fields = self.auth.extra_form_fields.get("register", [])
16041616
fields += extra_form_fields
1605-
form = Form(fields, submit_value=button_name, formstyle=self.formstyle)
1617+
form = Form(fields, submit_value=button_name, formstyle=self.formstyle, T=self.auth.T)
16061618
user = None
16071619
if form.accepted:
16081620
# notice that here the form is already validated
@@ -1740,6 +1752,7 @@ def login(self, model=False):
17401752
fields,
17411753
submit_value=button_name,
17421754
formstyle=self.formstyle,
1755+
T=self.auth.T,
17431756
)
17441757
user = None
17451758
next_url = prevent_open_redirect(request.query.get("next"))
@@ -1863,6 +1876,7 @@ def two_factor_validate(form):
18631876
form_name="auth_2fa",
18641877
keep_values=True,
18651878
hidden=dict(next_url=next_url),
1879+
T=self.auth.T,
18661880
)
18671881

18681882
if form.accepted:
@@ -1936,6 +1950,7 @@ def request_reset_password(self, model=False):
19361950
fields,
19371951
submit_value=button_name,
19381952
formstyle=self.formstyle,
1953+
T=self.auth.T,
19391954
)
19401955
if form.accepted:
19411956
email = form.vars.get("email", "")
@@ -2004,6 +2019,7 @@ def reset_password(self, model=False):
20042019
fields,
20052020
formstyle=self.formstyle,
20062021
submit_value=button_name,
2022+
T=self.auth.T,
20072023
)
20082024
self._process_change_password_form(form, user, False)
20092025
if form.accepted:
@@ -2049,6 +2065,7 @@ def change_password(self, model=False):
20492065
fields,
20502066
formstyle=self.formstyle,
20512067
submit_value=button_name,
2068+
T=self.auth.T,
20522069
)
20532070
user = self.auth.db.auth_user(self.auth.user_id)
20542071
self._process_change_password_form(form, user, True)

py4web/utils/form.py

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ def make(self, field, value, error, title, placeholder="", readonly=False):
223223

224224

225225
class FileUploadWidget:
226-
def make(self, field, value, error, title, placeholder="", readonly=False):
226+
def make(self, field, value, error, title, placeholder="", readonly=False, T=None):
227+
T = T or (lambda s: s)
227228
field_id = to_id(field)
228229
control = DIV()
229230
if value and not error:
@@ -232,11 +233,11 @@ def make(self, field, value, error, title, placeholder="", readonly=False):
232233
if not readonly:
233234
download_div.append(
234235
LABEL(
235-
"Currently: ",
236+
T("Currently: "),
236237
)
237238
)
238239
url = getattr(field, "download_url", lambda value: "#")(value)
239-
download_div.append(A(" download ", _href=url))
240+
download_div.append(A(T(" download "), _href=url))
240241

241242
if not readonly:
242243
download_div.append(
@@ -247,13 +248,13 @@ def make(self, field, value, error, title, placeholder="", readonly=False):
247248
_title=title,
248249
)
249250
)
250-
download_div.append(" (check to remove)")
251+
download_div.append(T(" (check to remove)"))
251252

252253
control.append(download_div)
253254

254-
control.append(LABEL("Change: "))
255+
control.append(LABEL(T("Change: ")))
255256
else:
256-
control.append(LABEL("Upload: "))
257+
control.append(LABEL(T("Upload: ")))
257258
control.append(INPUT(_type="file", _id=field_id, _name=field.name))
258259
return control
259260

@@ -300,8 +301,10 @@ def __call__(
300301
showreadonly,
301302
show_id,
302303
kwargs=None,
304+
T=None,
303305
):
304306
kwargs = kwargs if kwargs else {}
307+
T = T or (lambda s: s)
305308

306309
kwargs["_accept-charset"] = "utf8"
307310
form_method = "POST"
@@ -388,8 +391,8 @@ def __call__(
388391
field_value = None
389392

390393
field_name = field.name
391-
field_comment = field.comment if field.comment else ""
392-
field_label = field.label
394+
field_comment = T(field.comment) if isinstance(field.comment, str) and field.comment else (field.comment or "")
395+
field_label = T(field.label) if isinstance(field.label, str) else field.label
393396
input_id = to_id(field)
394397
if is_virtual:
395398
value = None
@@ -451,7 +454,7 @@ def __call__(
451454
)
452455
# do we need the variables below?
453456
delete_field_attributes = dict()
454-
delete_field_attributes["_label"] = "Remove"
457+
delete_field_attributes["_label"] = T("Remove")
455458
delete_field_attributes["_value"] = "ON"
456459
delete_field_attributes["_type"] = "checkbox"
457460
delete_field_attributes["_name"] = "_delete_" + field.name
@@ -466,7 +469,10 @@ def __call__(
466469
else:
467470
widget = Widget()
468471

469-
control = widget.make(field, value, error, title, placeholder)
472+
if isinstance(widget, FileUploadWidget):
473+
control = widget.make(field, value, error, title, placeholder, T=T)
474+
else:
475+
control = widget.make(field, value, error, title, placeholder)
470476

471477
key = control.name.rstrip("/")
472478

@@ -515,13 +521,13 @@ def __call__(
515521
wrapped,
516522
LABEL(
517523
" ",
518-
field.label,
524+
field_label,
519525
_for=input_id,
520526
_class=class_label,
521527
_style="display: inline !important",
522528
),
523529
P(error, _class=class_error) if error else "",
524-
P(field.comment or "", _class=class_info),
530+
P(field_comment, _class=class_info),
525531
_class=class_outer,
526532
)
527533
)
@@ -533,10 +539,10 @@ def __call__(
533539

534540
form.append(
535541
DIV(
536-
LABEL(field.label, _for=input_id, _class=class_label),
542+
LABEL(field_label, _for=input_id, _class=class_label),
537543
wrapped,
538544
P(error, _class=class_error) if error else "",
539-
P(field.comment or "", _class=class_info),
545+
P(field_comment, _class=class_info),
540546
_class=class_outer,
541547
)
542548
)
@@ -551,7 +557,7 @@ def __call__(
551557
deletable_field_type = "checkbox"
552558

553559
# Set the deletable json field attributes.
554-
deletable_record_attributes["_label"] = " check to delete"
560+
deletable_record_attributes["_label"] = T(" check to delete")
555561
deletable_record_attributes["_name"] = deletable_field_name
556562
deletable_record_attributes["_type"] = deletable_field_type
557563
deletable_record_attributes["_class"] = self.classes["input[type=checkbox]"]
@@ -590,7 +596,7 @@ def __call__(
590596
submit_button_field_type = "submit"
591597

592598
# Set the deletable json field attributes.
593-
submit_button_attributes["_label"] = "Submit"
599+
submit_button_attributes["_label"] = T("Submit")
594600
submit_button_attributes["_type"] = submit_button_field_type
595601
submit_button_attributes["_class"] = self.classes["input[type=submit]"]
596602

@@ -599,7 +605,7 @@ def __call__(
599605

600606
controls["submit"] = INPUT(
601607
_type=submit_button_field_type,
602-
_value="Submit",
608+
_value=T("Submit"),
603609
_class=self.classes["input[type=submit]"],
604610
)
605611

@@ -769,11 +775,17 @@ def __init__(
769775
csrf_protection=True,
770776
lifespan=None,
771777
signing_info=None,
772-
submit_value="Submit",
778+
submit_value=None,
773779
show_id=False,
774780
auto_process=True,
781+
T=None,
775782
**kwargs,
776783
):
784+
self.T = T if T is not None else (lambda s: s)
785+
if submit_value is None:
786+
submit_value = self.T("Submit")
787+
elif isinstance(submit_value, str):
788+
submit_value = self.T(submit_value)
777789
self.param = Param(
778790
formstyle=formstyle,
779791
hidden=hidden,
@@ -1027,6 +1039,7 @@ def helper(self):
10271039
self.showreadonly,
10281040
show_id=self.show_id,
10291041
kwargs=self.kwargs,
1042+
T=self.T,
10301043
)
10311044
for item in self.param.sidecar:
10321045
helper["form"][-1][-1].append(item)

py4web/utils/grid.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ def _handle_mode_new(self):
656656
if not self.is_creatable():
657657
raise HTTP(
658658
403,
659-
f"You do not have access to create a record in the {self.tablename} table.",
659+
str(self.T("You do not have access to create a record in the %s table.")) % self.tablename,
660660
)
661661
self.form = self._make_form(readonly=False)
662662
if self.param.new_sidecar:
@@ -669,7 +669,7 @@ def _handle_mode_details(self):
669669
if not self.is_readable(self.record):
670670
raise HTTP(
671671
403,
672-
f"You do not have access to read a record from the {self.tablename} table.",
672+
str(self.T("You do not have access to read a record from the %s table.")) % self.tablename,
673673
)
674674
self.form = self._make_form(readonly=True)
675675
if self.param.details_sidecar:
@@ -682,7 +682,7 @@ def _handle_mode_edit(self):
682682
if not self.is_editable(self.record):
683683
raise HTTP(
684684
403,
685-
f"You do not have access to edit a record in the {self.tablename} table.",
685+
str(self.T("You do not have access to edit a record in the %s table.")) % self.tablename,
686686
)
687687
self.form = self._make_form(readonly=False)
688688
if self.param.edit_sidecar:
@@ -910,6 +910,7 @@ def _make_form(self, readonly):
910910
formstyle=self.param.formstyle,
911911
validation=self.param.validation,
912912
show_id=self.param.show_id,
913+
T=self.T,
913914
)
914915

915916
def _iter_pages(

0 commit comments

Comments
 (0)