From 6a1b89db93c65904e77014a0ed652bfa1815e989 Mon Sep 17 00:00:00 2001 From: Sam Arbid <36583694+Samk13@users.noreply.github.com> Date: Fri, 21 Feb 2025 16:23:46 +0100 Subject: [PATCH] docs: update i18n guidelines for string interpolation in Python (#740) --- docs/develop/howtos/i18n.md | 38 ++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/docs/develop/howtos/i18n.md b/docs/develop/howtos/i18n.md index 56111d64..08c9df65 100644 --- a/docs/develop/howtos/i18n.md +++ b/docs/develop/howtos/i18n.md @@ -9,14 +9,42 @@ In order to translate strings, they have to be marked. This ensures that they wi ### Python !!! warning -Do not use `f-strings` for translatable text. Interpolation is not supported for these types of strings (see [Issue](https://github.com/python-babel/babel/issues/594)). + Do not use `f‑strings` for translatable text. + If they are used to construct strings inside tranlsation calls (e.g. `_(f"Hello {name}")`), then the text will be interpolated before the translation step and thus cause a miss in translation lookup. -Instead, use `format`: -```diff -- _(f"Hi {username}") -+ _("Hi {username}".format(username=username)) +Similarly, do not pass keyword arguments to `_()` when using new‑style (curly‑brace) placeholders. For example, avoid this pattern: + +```python +# ❌ Incorrect – the placeholder is not interpolated at runtime. +translated = _("Hello, {username}", username=username) ``` +and also do not perform interpolation inside the `_()` call: + +```python +# ❌ Incorrect – interpolation happens before marking the string for translation. +translated = _("Hello, {username}".format(username=username)) +``` + +Instead, if you prefer new‑style formatting, mark your string with placeholders and apply `.format()` after the `_()` call: + +```python +# ✅ Correct – the extracted message remains "Hello, {username}". +# ⚠️ However, the translation result will be immediately evaluated and thus not a lazy string! +translated = _("Hello, {username}").format(username=username) +``` + +!!!note + Using `.format()` on a lazy string (as returned by `lazy_gettext()`) converts it into a regular (non‑lazy) string. + If lazy evaluation is important, it is recommended to use the old‑style `%` formatting which supports passing parameters directly: + + ```python + # ✅ Recommended for lazy evaluation. + translated = _("Hello, %(username)s", username=username) + ``` + + See [`flask_babel.gettext()`](https://github.com/python-babel/flask-babel/blob/master/flask_babel/__init__.py#L628-L639). + Marking strings in python is done via the `Flask-BabelEx` package. First, make sure to import the package and the `*gettext` function. We usually import it as `_` to be consistent throughout different packages. ```python