Localization (v0.9.0 R5)¶
The desktop GUI ships with English as the source language and
Russian (ru_RU) as the first translated locale. Switching the
language is hot — Settings → Appearance → Language re-installs
the translator and persists the choice to state.json. Restarting
the app, or opening a screen for the first time after a switch,
picks up the new strings.
Available locales (v0.9)¶
| Locale | Status | Coverage (CTA strings) | Maintainer |
|---|---|---|---|
en_US |
source | n/a | yt-uniquifier core |
ru_RU |
translated | ≥ 50 % | yt-uniquifier core |
The coverage figure is the fraction of SOURCE_KEYS in
gui/i18n/translations.py that have a non-empty entry in the
locale's table. It is checked at CI time by
tests/unit/test_i18n.py::test_coverage_ratio_ru_is_substantial,
which fails if ru_RU slides below 50 %. Strings without an entry
fall back to the source verbatim — by design.
Why no .ts / .qm?¶
The canonical Qt pipeline is pylupdate6 → .ts → lrelease
→ .qm. v0.9 deliberately skips it:
- the catalogue is small (≈ 40 keys) — a Python dict is faster to edit and review;
- contributors don't need to install Qt's developer tools;
- the wheel ships exactly the bytes a maintainer wrote, no build-time compilation step that can drift across releases.
The runtime translator (gui/i18n.RuntimeTranslator) subclasses
QTranslator and overrides translate() to read out of
TRANSLATIONS[locale]. QObject.tr() and
QCoreApplication.translate() route through it without code
changes elsewhere.
If a future locale grows past a few hundred strings the trade-off
flips: migrate to .ts + .qm, keep the same public API
(install_translator, available_locales), and the dict goes
away as an implementation detail.
Adding a new locale¶
- Open
src/yt_uniquifier/gui/i18n/translations.py. - Copy the
ru_RUblock, rename the key to your locale code (use the POSIX form, e.g.de_DE,fr_FR). - Replace each right-hand value with your translation. Leave a
key out to fall back to English. Do not invent new keys —
the test suite rejects entries that do not map a string in
SOURCE_KEYS. - Preserve mnemonic markers (
&Run→&Запустить). Pick a letter close to the English one; Qt highlights whatever character follows the&. - Run
pytest tests/unit/test_i18n.py -v. The coverage test prints your locale's percentage in its log line.
Adding a new translatable string in the GUI¶
- Wrap it in
self.tr("…")(orQObject.tr("…")for module- level use). - Add the exact source string to
SOURCE_KEYSingui/i18n/translations.py. Keep the list alphabetised within its commented section. - Optionally add a
ru_RUentry. Missing entries fall back.
Caveats¶
- Strings cached on a widget that has already painted stay in
the language they were rendered with until that widget rebuilds.
v0.9 does not implement per-screen
retranslate_uihooks; the Settings combo flashes a status hint reminding the user to reopen screens for a full refresh. - Numbers and units are not currently formatted through
QLocale—1,234stays comma-separated regardless of locale. v1.0 will revisit when more European locales land. - CLI is English-only. Translating developer-facing output (Typer help text, log lines) was explicitly deferred — the audience is global English-speaking developers and changing it would break script grep'ability.