Files
DarkRoom/ui
dtourolleandClaude Opus 5 7409cb7767 Make the launch screen translatable, and say how the rest follows
`@tr(` appeared zero times in 14,482 lines of markup. Every string the user
reads was a literal, so NFR-A11Y-1 was not partly done or done badly — there
was nothing to extract and nothing a translator could have been given.

The mechanism turns out to cost almost nothing, and the reason is worth
stating because it decides the order of the work: a string written `@tr("Sign
in")` is already correct in a build with no translation at all. Slint's
`translate()` formats the original and hands it back when neither delivery
path is active, so a converted string and a literal are the same string until
someone writes a `.po`. That means the interface can be converted a screen at
a time rather than in one 14,000-line commit that nobody can review, and every
intermediate state is shippable.

So the delivery half is wired and left inert. `build.rs` asks for bundled
translations only once `lang/<lang>/LC_MESSAGES/dr-ui.po` exists — the first
catalogue anyone commits turns it on with no build-system change, and until
then a checkout with no `lang/` builds exactly as it did. Bundling rather than
the `gettext` feature because of Android: under ARCH §6.9's storage model
there is no path a `.mo` could sit at that the app can reach, and no C library
to link it against. The extraction command and the one flag that must not be
passed to it are recorded in the module docs.

The launch screen is converted whole: 32 calls covering every heading, button,
caption and placeholder. It goes first because it is the screen a user cannot
get past — an unreadable preferences page can be ignored, an unreadable sign-in
cannot. Four kinds of literal are deliberately left alone and the file says
which: the product name, example values whose shape is the message, `..`, and
the path separator.

Two things this leaves open, recorded rather than papered over. The headings
carry their own capitals, because `PanelHeading` draws what it is handed — so
a translator supplies "SERVEUR", not "Serveur", and styling in the string is a
real cost now paid rather than a surprise later. And `@tr()` is markup only:
the operation and parameter labels NFR-A11Y-1 names explicitly resolve in
`labels.rs`, in Rust, because the core may not depend on a localisation
library — those need a second mechanism, and it is not built.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-30 10:25:16 +02:00
..