Repository navigation
Translate the interface, with German as the second language - #84
Conversation
MatteLoop was English by accident rather than by design: not one tr() call anywhere, every visible string a bare literal at its point of use. #47 had to translate six German strings that had been sitting in the execution-provider feature — found not by a test or a review but because a screenshot of the running window was rendered for the README and the German was simply visible in the picture. Without a translation layer there is no mechanism that can catch the next one. This wraps every user-visible string with Qt's own system: tr() and QCoreApplication.translate(), .ts sources, compiled .qm catalogues, loaded through QTranslator at startup. No new dependency — PySide6 ships lupdate and lrelease. Log lines, error codes, AppError.technical_detail and ProgressEvent payloads stay canonical English: they are data, not copy, and one of them is serialised as exception text. Number and date formatting follows the selected interface language rather than the system locale, which is the decision the issue left open. On a German machine an English interface used to read "6,042 s" inside otherwise English labels; now the two never disagree. The language is chosen in Preferences, persists immediately, and applies at the next start — including the locale, so words and numbers always change together. The catalogue is generated, never written. tests/test_translations.py runs the documented lupdate command into a temporary directory and compares the extracted messages — sources, contexts and numerus flags — against the checked catalogues, so a hand-edited entry or a plural that lupdate cannot see fails CI. That guard is not decorative: two earlier drafts of this change shipped hand-seeded entries the documented command could not reproduce, and a plural form that rendered "1 frames". Rendering the German interface was itself a review, as it was in #43: it showed "Compute acceleration" clipped to "Berechnungsbeschleun", so the German label is now "Beschleunigung". Also makes the language test independent of the host locale. Without a stored value the dialog opens on the system language, so on a German machine switching to German asserted on a no-op — it could only ever have passed on an English runner. The guardrail baselines for inspector.py and timeline.py rise to 897 and 842 lines. The growth is mechanical: tr() wrapping reflows long literals across several lines. The maintainer approved these two before the work started; no function crossed the 60-line budget, and main_window.py stayed inside its own by extracting its render helpers into main_window_render.py. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Trigger: the Gitar review on the pull request. install_translators read QLibraryInfo.LibraryPath.Translations, which does not exist — the member is TranslationsPath — so app.py raised AttributeError before the window appeared. Every launch, on both platforms. The whole suite was green while the application could not start, because nothing called install_translators: it is reached only from _run_gui, and no test runs the real startup path. A wrong enum member is exactly the kind of mistake a type checker cannot see through getattr() and a reading review skims past. So the fix is one name, and the coverage is the point: one test installs the translators for real and asserts a German string comes back, and a second compiles both .ts files with lrelease and compares the result byte for byte against the checked-in .qm. The catalogue tests until now proved the sources were extractable and complete, but never that the compiled files anyone actually ships match them — a stale .qm would have shipped the wrong words while every review of the .ts looked correct. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Code Review ✅ Approved 2 resolved / 2 findingsAdds comprehensive translation support with German as the second language using Qt's ✅ 2 resolved✅ Bug: install_translators uses nonexistent QLibraryInfo enum member
✅ Quality: Compiled .qm catalogues are never verified against .ts sources
OptionsAuto-apply is off → Gitar will not commit updates to this branch. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Gitar |
|



Closes #49.
MatteLoop was English by accident, not by design: not one
tr()call anywhere. #47 had to translate six German strings that had been sitting in the execution-provider feature — caught not by a test or a review, but because a screenshot was rendered for the README and the German was visible in the picture.What this does
Qt's own system —
tr()/QCoreApplication.translate(),.tssources, compiled.qmloaded throughQTranslator. No new dependency; PySide6 ships lupdate and lrelease. The language is chosen in Preferences, persists immediately, and applies at the next start.Number and date formatting follows the interface language, which is the decision the issue left open. A German machine with an English interface used to read
6,042 sinside English labels; the two can no longer disagree, because the locale changes with the language at startup and never in between.Log lines, error codes,
AppError.technical_detailandProgressEventpayloads stay canonical English. They are data, not copy — one of them is serialised as exception text.The catalogue is generated, never written
tests/test_translations.pyruns the documented lupdate command into a temporary directory and compares the extracted messages — sources, contexts and numerus flags — against the checked catalogues. A hand-edited entry, or a plural lupdate cannot see, fails CI.That guard is not decorative. Two earlier drafts of this change were rejected in review for exactly that: 191 hand-seeded entries the documented command could not reproduce, and a plural rendering
1 frames. Both drafts looked complete and passed their own tests.453 messages, none unfinished, 11 plurals as Qt numerus forms.
Rendering it was a review
The German window showed
Compute accelerationclipped toBerechnungsbeschleun, so the German label is nowBeschleunigung. The screenshot above is the corrected render.Guardrails
inspector.pyandtimeline.pyrise to 897 and 842 lines. The growth is mechanical —tr()wrapping reflows long literals — and the maintainer approved these two specifically before the work began. No function crossed the 60-line budget;main_window.pystayed inside its own by extracting its render helpers intomain_window_render.py.Verification
The English screenshots are unchanged, byte for byte.
🤖 Generated with Claude Code