feat(i18n): translate the GUI strings left in English, guard against drift, document the workflow - #499
Open
Guts wants to merge 3 commits into
Open
feat(i18n): translate the GUI strings left in English, guard against drift, document the workflow#499Guts wants to merge 3 commits into
Guts wants to merge 3 commits into
Conversation
…drift Widget text goes through Qt's own i18n, whose .ts files are refreshed by running pylupdate6 by hand. Three merged PRs -- cancellation, parallel scan, driver-based format gating -- added widget text without that step, so 8 strings had no French or Spanish translation at all and showed in English whatever the language selected: "Cancel", "Canceling...", "Folder scan canceled.", "Processing canceled. Partial results were saved to the output.", the unsupported-format tooltip, and the three parallel scan options. Re-run pylupdate6 over dicogis/ui, translate the 8 new entries in both locales, and recompile the .qm with lrelease. Checked at runtime: a QTranslator loading each .qm returns the expected translation for all 8. Add tests/test_ui_i18n.py so this cannot drift again. It collects every `self.tr()` source string by walking the GUI modules with ast -- needing neither PyQt6 nor GDAL -- and fails, naming the offending strings, when one has no translation in a shipped locale. A second test loads the compiled .qm and compares it against the .ts, since only the .qm is read at runtime: a .ts updated without re-running lrelease would change nothing for the end user. Both fail on the previous state, listing exactly those 8 strings. AI-Level: 7 (human specced, bots coded) AI-Model: claude-opus-5 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WABM4NMiD2DhEVreKLxWLq
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #499 +/- ##
=======================================
Coverage 76.09% 76.09%
=======================================
Files 46 46
Lines 3409 3409
Branches 415 415
=======================================
Hits 2594 2594
Misses 695 695
Partials 120 120
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
The pylupdate6/lrelease pipeline was only described in CLAUDE.md, an agent-facing file, so a human contributor had nowhere to learn that adding a `self.tr()` string means regenerating the .ts files and recompiling the .qm. That is exactly how 8 strings ended up shipped untranslated. Modelled on qtribu's own translation page, updated for PyQt6 and for this project's specifics: - pylupdate6 comes with PyQt6 itself, so the `gui` extra suffices; only lrelease and Linguist need system packages (qt6-l10n-tools, linguist-qt6), and Ubuntu puts them outside the default PATH; - no .pro profile is involved, pylupdate6 takes the source files directly; - unlike qtribu, the compiled .qm files are tracked here: they are package data and PyInstaller --add-data inputs, so a stale .qm ships a stale interface; - dicogis_en.ts is a source-language reference, never compiled nor loaded; - the second, separate mechanism -- TextsManager and locale/lang_*.xml -- is documented alongside, since which one applies depends on whether the string is GUI or pipeline output. Also covers adding a new language and points at tests/test_ui_i18n.py. Verified: the Sphinx build succeeds and its warning set is unchanged from master's, page registered in the index toctree. AI-Level: 7 (human specced, bots coded) AI-Model: claude-opus-5 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WABM4NMiD2DhEVreKLxWLq
…tion Rewrapped the new translation guide to one line per paragraph/list item, matching the style already used across docs/**/*.md (see docs/development/documentation.md) instead of the hard-wrapped prose it shipped with. Added the convention to CLAUDE.md's "Conventions" section so it isn't reintroduced next time Markdown prose is authored here. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WABM4NMiD2DhEVreKLxWLq
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Description
Widget text goes through Qt's own i18n, whose
.tsfiles are refreshed by runningpylupdate6by hand. Three merged PRs — cancellation, parallel scan, driver-based format gating — added widget text without that step, so 8 strings had no French or Spanish translation at all and showed in English whatever the language selected:DicoGISCancelDicoGISCanceling...DicoGISFolder scan canceled.DicoGISProcessing canceled. Partial results were saved to the output.TabFilesNot available: the installed GDAL build does not include the driver required for this format.TabSettingsParallelize folder scan (recommended only for network-mounted / high-latency storage; …)TabSettingsParallel scan: max workers (0 = auto)TabSettingsAutoRan
pylupdate6overdicogis/ui, translated the 8 new entries in both locales, and recompiled the.qmwithlrelease. The.tsfiles go from 68 to 76 messages, with 0 unfinished in FR and ES.Verified at runtime, not just on paper: a
QTranslatorloading each compiled.qmreturns the expected translation for all 8 — e.g.Cancel→Annuler/Cancelar. Existing translations are untouched; the FR/ES wording follows the file's conventions (French typographic space before:, none in Spanish).Correcting my own earlier count, in case it was quoted anywhere: I had said "at least 9 strings". It is 8 —
Fund & Supportwas already translated, my grep had missed it because the.tsescapes it asFund & Support.Guarding against the next drift
The real defect is that nothing enforced the pipeline being re-run, so
tests/test_ui_i18n.pyis added:test_every_widget_string_is_translatedcollects everyself.tr()source string by walking the GUI modules withast— so it needs neither PyQt6 nor GDAL and runs in any environment — and fails naming the offending strings.test_compiled_qm_matches_the_tsloads the compiled.qmand compares it against the.ts. Only the.qmis read at runtime, so a.tsupdated without re-runninglreleasechanges nothing for the end user; this catches that half of the mistake. It skips when PyQt6 is absent.test_translatable_sources_are_foundguards the guard: an extraction returning nothing would make the rest vacuously true.Both fail on the previous state, listing exactly those 8 strings:
New page:
docs/development/translation.mdThe pipeline was only described in
CLAUDE.md, an agent-facing file, so a human contributor had nowhere to learn it — which is how those 8 strings shipped untranslated in the first place. Modelled on qtribu's translation page, updated for PyQt6 and for this project:pylupdate6ships with PyQt6 itself, so theguiextra suffices; onlylreleaseand Linguist need system packages (qt6-l10n-tools,linguist-qt6), which Ubuntu installs outside the defaultPATH;.proprofile is involved, unlikepylupdate5—pylupdate6takes the source files directly;.qmare tracked here: they are package data and PyInstaller--add-datainputs, so a stale.qmships a stale interface;dicogis_en.tsis a source-language reference, never compiled nor loaded;TextsManagerandlocale/lang_*.xml— is documented alongside, since which one applies depends on whether the string is GUI or pipeline output.It also covers adding a new language and points at the new tests. Package names and binary paths were checked against the real packages rather than assumed: the Qt 6 Linguist binary is
linguist, notlinguist6.Sphinx build verified: it succeeds, the page is registered in the index toctree, and the warning set is identical to
master's (55 non-intersphinx warnings either way). One iteration was needed — a### Requirementsheading collided withdevelopment/ubuntu.mdunderautosectionlabel, so it is now### Required tools.Related issue(s)
None — found while reviewing the code ahead of the 4.0.0-beta13 release.
Type of change
fix/…branch)feature/…branch) — user-visible translations plus a new guard; the branch is namedfix/…since it repairs shipped behaviour, rename or relabel as you preferdocs/…branch or*.md/docs/**changes)packaging/…branch orbuilder/**changes)tooling/…branch or.github/**changes)tests/**changes)Checklist
pre-commit run --all-filespasses locally — its two ruff hooks on the changed files:ruff-formatreports them already formatted,ruff check --fix-onlyrewrites nothing, andruff checkreports no violation on the new test. It needed one# noqa: S314with a stated reason, the parsed file being the project's own.ts;dicogis/utils/texts.pycarries the same unsuppressed pattern onmaster, so tell me if you would rather I dropped the suppression for consistencypytestpasses locally — 226 passed on the non-GDAL modules and 41 ontests/ui, with the same 8 pre-existing sandbox failures as onmasterAI/LLM disclosure
🤖 Generated with Claude Code
https://claude.ai/code/session_01WABM4NMiD2DhEVreKLxWLq