Localization¶
quadletman uses Babel and GNU gettext for i18n. The active
locale is resolved from the browser's Accept-Language header at the start of each request.
Supported languages: English (en, default) and Finnish (fi).
Key files¶
| File | Purpose |
|---|---|
quadletman/i18n.py |
Thin gettext wrapper; set_translations(lang) called by middleware; gettext as _ imported by routers |
quadletman/templates_config.py |
Shared Jinja2Templates instance with i18n Jinja2 extension; _() and ngettext() available in every template |
quadletman/locale/quadletman.pot |
Master message catalog — generated by pybabel extract, committed to the repo |
quadletman/locale/{lang}/LC_MESSAGES/quadletman.po |
Per-language translation catalog (human-edited) |
quadletman/locale/{lang}/LC_MESSAGES/quadletman.mo |
Compiled binary — generated by pybabel compile, committed to the repo |
babel.cfg |
Babel extraction config; maps .py and .html files to extractors |
Using translations in code¶
Python (routers and services):
Jinja2 templates — _() and ngettext() are globals, no import needed:
Workflow: adding or changing a translatable string¶
Every user-visible string must be wrapped in _() (singular) or ngettext() (plural). After
adding or changing any such string, run the full catalog update cycle:
# 1. Extract all marked strings into the .pot master catalog
uv run pybabel extract -F babel.cfg -o quadletman/locale/quadletman.pot .
# 2. Merge new/changed strings into each existing .po file
uv run pybabel update -i quadletman/locale/quadletman.pot -d quadletman/locale -D quadletman
# 3. Edit the .po file(s) — translate new or fuzzy entries (see Fuzzy entries below)
# 4. Compile .po → .mo for runtime use
uv run pybabel compile -d quadletman/locale -D quadletman
Commit .pot, all .po files, and the compiled .mo files together in the same commit
as the code change.
Fuzzy entries¶
pybabel update marks auto-guessed translations as #, fuzzy. These are not served at
runtime — the fallback string is used instead. Always review and fix fuzzy entries after
pybabel update. Remove the #, fuzzy comment once the translation is verified.
Adding a new language¶
- Create the directory:
quadletman/locale/{lang}/LC_MESSAGES/ - Initialize the catalog:
- Add the language code to
AVAILABLE_LANGSinquadletman/i18n.py. - Translate all
msgstrentries in the new.pofile. - Compile:
uv run pybabel compile -d quadletman/locale -D quadletman
Finnish vocabulary¶
Use these canonical Finnish terms. Do not invent alternatives.
| English | Finnish | Notes |
|---|---|---|
| Container | Kontti | Plural: kontit; partitive: kontteja; inessive: konteissa. Not "säiliö" or "containerit". |
| Image | Levykuva | Plural: levykuvat. Not "säilökuva". |
| Volume | Levyosio | |
| Image store / image registry (local) | Levykuvataltio | Not "kuvavarasto". |
| Podman store / Podman storage | podman-taltio | Lowercase. Not "Podman-varasto". |
| Podman network | podman-verkko | Inflects: podman-verkollaan etc. Not "Podman-network". |
| Non-host containers | host-verkkoon kytkeytymättömät kontit | Not "ei-host-kontit". |
| Secret | Salaisuus | |
| Compartment | Osasto | |
| Cancel | Peruuta | |
| Save | Tallenna | |
| Delete | Poista | |
| Create | Luo | |
| Update | Päivitä | |
| Add secret | Lisää salaisuus | |
| New value | Uusi arvo | |
| New secret value… | Uusi salaisuuden arvo… | Placeholder text. |
| Secret value… | Salaisuuden arvo… | Placeholder for new secret. |
| Name | Nimi | |
| Value | Arvo | |
| Hook | Koukku | Notification hooks. |
| Any container | Mikä tahansa kontti |
Note: some older strings used "säiliö" for Container. The canonical term is Kontti. Correct any occurrence of "säiliö" found during translation work.
Checklist when adding a user-visible string¶
- Wrap the string in
_()orngettext()at the call site (Python or Jinja2). - Run the full extract → update → translate → compile cycle.
- For Finnish: verify the term against the vocabulary table above.
- Stage
.pot,.po, and.mofiles in the same commit.