Translations 1/2: gettext catalogues and the CI resource gate #25
No reviewers
Labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
schaefera/utStudyBIble!25
Loading…
Reference in a new issue
No description provided.
Delete branch "phase1/gettext"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
The first half of translations (#14): the app's UI text comes from gettext catalogues, with German as the first one. It also adds a CI gate for start-up time, which is checked on two profiles.
core::i18nreads.mocatalogues. It has no new dependency and nounsafe, and it is Qt-free. The language comes from LANGUAGE, LC_ALL, LC_MESSAGES and LANG, tried asde_DE, thende. If a string has no translation, the English source shows.tr(). These include "no Bible open", the unknown-reference errors, "not in this Bible" and the three start-up notices.qsTrin QML reaches the same catalogue through oneQTranslatorinqt/main.cpp, so no libintl or glibc locale is needed on the phone..mois built into the click (share/locale/de/LC_MESSAGES/utstudybible.schaefera.mo).po/:utstudybible.schaefera.potandde.po, with all 23 strings translated.cargo make i18nrefreshes them, andcargo make i18n-checkand CI fail when they are stale.LANGUAGE=deand English under C;tools/mem-check/budget-start-ms2000 ms,budget-start-slow-ms3000 ms);Book names are not gettext. They stay JSword data in the module's language. Part 2 covers more languages, plurals and context, and an in-app language override.
Blast radius
Tier: trunk
Trunk paths touched:
qt/glue (main.cpp,src/i18n.rs,src/lib.rs),core/src/worker/session.rsandsession/jump.rs,CMakeLists.txt,Makefile.toml,tools/mem-check/,tools/ci/app.shTesting tier: elevated. It adds a new CI gate (start-up time, slow profile) and changes all text on screen. There are no new dependencies and no schema change.
Gate / rollback: nothing is behind a flag. With no catalogue for the phone's language, every string falls back to its English source, so an English phone sees no change. Rollback is a revert of this merge and reinstalling the previous click; no data is touched.
Proof
cargo make app-docker) and in CI.tools/i18n/check-app.sh: German title "Studienbibel" with 10+ translated messages, and C locale "Study Bible" with 0.cargo makeexit 0 on the merged tree (c013a10): fmt, clippy, tests with coverage (core lib 105 passed), release check, deny and audit. After3010631, clippy and core tests passed again.cargo make app-dockerexit 0 onefdde90.core/src/i18n.rs(byte order, plural skip, empty msgstr, region fallback and others), each killed by a named test.SLOW=1 BUDGET_START_MS=100fails with "the first chapter took 313 ms, over the 100 ms baseline", exit 1.BUDGET_KB=100000fails on PSS.UTSB_LOCALE_DIR=/nonexistentexits 1.i18n-checkfailed in CI's image when the .pot order differed (it caught the locale-dependent sort fixed here).0-6:2gives0 2 4 6,0,2,4gives0 2 4,3gives3, and1-3,8gives1 2 3 8.docker run --cpuset-cpus=0 … SLOW=1 run.shexits 1 with "slow profile needs 2 usable CPUs, this process has 1". Beforeefdde90it ended with "pid: parameter not set", exit 2.3010631build.efdde90differs only intools/mem-check.build 0.0.1 phase1/gettext@3010631fe, window loaded after 325 ms,restored KJV 172 0.530, showing Gen 7.en_US, so it logged "0 translated messages", which is the English fallback.de.mo is in the click.3010631build is left installed.3010631, and again onefdde90, the last code commit.1f85405(the empty trailer commit, same tree),appfailed after 2m38s. A normal run takes about 3m. This Forgejo serves no job logs or reruns through the API, so the failing step was not seen.cargo make app-dockeron that tree passed locally (slow profile 314 ms, peak PSS 141062 kB). The empty commit90b716freran CI, andapppassed in 3m8s..moread at start (German is 2055 bytes; none is read on an English phone). Text on screen is 206 ms normal and 312 ms slow. main had no text-on-screen gate to compare against, and this PR adds it..mo.core/src/tasks.rs's "tasks: …" errors are not wrapped intr()yet, because no UI shows them. They will be wrapped when #10 part 2 surfaces them.Review
Reviewer: fresh-context reviews and audits, each in a new agent:
a73c38a: 3 lows, all fixed in104c1af: CPUs read from the allowed set, budgets raised to 2 s and 3 s, and no orphaned app in check-app.104c1af: 2 lows, both fixed in828d056and39abee8: fewer than 2 CPUs now fails, and strided cpusets are read correctly.translatereturning an empty, non-null QString; fixed in62a0f4e.3010631.kill ""was declined, because the window has no command that can fail.Review-Confidence: 50/100. Every changed trunk file was reviewed, all code after
104c1afis covered by delta reviews 217–219, CI is green onefdde90, and the auditor's own read found no missed defect. Points off for the round-1 findings that cite files without lines, the translator's disambiguation branch that nothing runs, and the%2re-substitution (both now #33), and for fixes made after delta reviews.Confidence by part
core/src/i18n.rs(the .mo reader): high. It is mutant-tested and the CI app check reads a real catalogue.qt/main.cpptranslator: high. Review 219 covered it, and check-app shows German and English.tools/mem-check/run.shslow profile: medium-high. The parser outputs and the one-CPU exit are recorded. Strided cpusets were seen only in hand-fed input.po/de.powording: medium. Two reviewers checked it, but no native speaker has. Read it.Closes nothing; part of #14 (part 1/2).
🤖 Generated with Claude Code
Delta review (medium) of 104c1af..c013a10
Checked: merge resolution (session.rs go_to removed in favour of main's jump.rs, no leftover callers or markers; qt/src/lib.rs has i18n, picker_model, reading_model; mem-check header has both sides' checks), the three jump.rs tr() calls (%1/%2 used correctly, order matches de.po), all new QML strings (PickerPage, SettingsPage, ReadingPane) wrapped in qsTr, de.po translations, and update.sh LC_ALL=C sort.
tools/i18n/update.sh --checkpasses locally (20 messages).Findings:
No high or medium findings.
Delta review (medium) of c013a10..3010631
Findings:
.replace("%1", &a.module).replace("%2", ...)would also substitute a "%2" inside the module name. Failure scenario: a module named "X%2" shows the wrong text. SWORD module names are alphanumeric, so this is practically unreachable. Replacing %2 first, or a single-pass substitute, removes the risk.Checked and fine:
Delta review (medium) of 104c1af..efdde90: qt/main.cpp, tools/mem-check/run.sh, qt glue
Files reviewed: qt/main.cpp, tools/mem-check/run.sh, tools/ci/app.sh, qt/src/lib.rs, qt/src/i18n.rs (this branch's part only; also checked core/src/i18n.rs for the empty-msgstr case).
Checked, no problem:
head -n 2closing the pipe early is harmless, since there is no pipefail. Fewer than 2 CPUs exits 1 before any process is started.hog= pid= xvfb=before the trap is fine under set -u. The restartpid=$!assignments (lines 249 and 351) followkill -9andwaiton the old pid, so the trap kills the live one. The hog (taskset execs sh, so $! is the loop shell) is killed by the trap. No barewaitexists that would block on the hog.mod i18nand the#[unsafe(no_mangle)]externs match the extern "C" declarations in main.cpp. The null check on msgid is correct.No findings.
Note (below the reporting threshold, not a finding): under dash,
kill "" Xaborts the builtin on the empty operand. If run.sh ever exited after Xvfb starts but beforepid=$!(a one-second window with no command that can fail), Xvfb would not be killed. bash continues past the bad operand.WIP: Translations 1/2: gettext catalogues and the CI resource gateto Translations 1/2: gettext catalogues and the CI resource gateGate (step 8):
1f85405, and it is mergeable.3010631), deferred to #33 with a reason, or declined with a reason in the body.efdde90, is success for rust, audit, app and click. CI on the trailer commit1f85405is still pending. It changes no files.1f85405with an unchanged tree; app-docker passes locally)Gate (step 8):
90b716f, and it is mergeable.1f85405(git diff --stat is empty), made to rerun CI after the flaky app job, as the CI bullet explains. origin/main is an ancestor of the head.3010631), deferred to #33 with a reason, or declined with a reason in the body. Approval 220 on1f85405is stale, as expected.90b716f: combined state success; rust, audit, app and click all success.