* Fix broken localization: tr(f-string) never matches translation catalog
tr(f'Invalid configuration: {error}') evaluates the f-string before
tr() runs, so xgettext extracts the literal placeholder as the msgid
while runtime passes the formatted string - the two never match.
Switch to tr('...{}').format(...) and update msgid in base.pot.
* Add CI validation for translations and pot_tools dev utility
Add translation-check workflow with two jobs:
- validate-po: msgfmt --check on changed .po files, .mo sync warning,
tr(f-string) anti-pattern grep on changed .py files
- validate-pot: verify all tr() strings exist in base.pot when .py
files change
Workflow only triggers on .py/.po/.pot file changes.
Add scripts/pot_tools.py developer utility (stats, list, add_missing)
for managing base.pot.
* Fix code style: use tabs and reformat xgettext arguments
Align check_pot_freshness.py and pot_tools.py with project
indentation (tabs) and ruff format requirements.
Sorry :-)
* Replace custom PO parser with msgcmp, drop pot_tools.py
Address review feedback: use standard gettext msgcmp instead of
hand-rolled parser for base.pot freshness check. Remove pot_tools.py
that duplicated locales_generator.sh functionality.
* Move translation checks into locales_generator.sh, simplify CI workflow
Use msgcmp instead of diff for base.pot validation to avoid failing on
legacy stale entries - the same cascading breakage that killed the
original workflow (disabled 2023, removed in #4483).
* Fix broken .po files: duplicate msgid in Hindi, missing format args in Finnish
The workflow has been fully commented out since #2119 (2023-09-28) when
translation handling was reworked. Because the file has no `on:` triggers,
GitHub Actions creates a failed workflow run for every push, polluting
the Actions tab without affecting PR check-runs.