Repository navigation
i18n: let the layers below hand their sentences over, so they can be translated - #478
Conversation
…translated The accessibility findings, the PDF/A problems, the signature details, the page-range mistakes and the edit labels were English in all ten languages, because matching their wording from the UI with a tl! literal would break silently whenever the engine changed it. So each layer now hands the wording over instead, apart from the document's own words: a WORDINGS list of every sentence it can say, with holes in it, and said(&words), which looks the wording up through the closure it is given and fills the holes in a single pass. in_english changes nothing, for the CLI and the tests; the UI passes &i18n::words, a catalog lookup. A wording with no entry comes back as it stands, which is the English, so the nine catalogs this does not touch read exactly as before. a11y::report_html takes a language tag and a words closure, so a saved report reads the way the panel read, down to its lang attribute. print::PrintError gained a variant per thing a person can be wrong about, with the numbers apart from the words; faults rather than mistakes keep their own text. Spanish translates all of it (107 entries). spanish_covers_what_the_engine_says requires an entry per wording in the eight lists and spanish_keeps_the_holes_in_what_the_engine_says requires the holes to survive the translation, so the catalog cannot fall behind the engine unnoticed. No new tl! literal, so the Chinese, French and Russian UI-literal gates are unaffected. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three list files overlapped, and both sides are kept in each: - `ATTRIBUTION.toml`: the Spanish catalog's SHA-256, recomputed over the merged `es.tsv` (`cargo xtask assets` is happy with it). - `docs/localization.md`: main's font paragraph, which now names Bulgarian and German, with the paragraph about the sentences the engine words. - `parity/acrobat-features.toml`, `misc.prefs-language`: main's notes and evidence, plus this branch's three tests and its paragraph; what is missing is the engine's sentences in the other ten catalogs, German included, so the count moved from nine. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The signature code moved under us: `main` now validates adbe.x509.rsa_sha1, notes what it read leniently on the way (BER lengths, segmented OCTET STRINGs, RSA and ECDSA quirks), and says why a certificate that matched the issuer was not used to build the chain. All of it arrived as `String`s built in place. Every new sentence is now a wording the interface can say in its own language: - `x509::signing_problem` and `x509::build_chain_noted` return `Detail` instead of `String`. The three chain refusals became whole sentences rather than a phrase stitched into one, so a language can put the two certificate names where it needs them; the English they render is unchanged. - `Fill::Names` carries those two names. `Detail::said` cuts both holes out of the wording before filling either, so neither name can be taken for the other's hole. - The lenient-reading notes and the weak-hash warnings live in `WORDINGS`, which `wordings_are_complete` now also reads out of `x509.rs`, `cms.rs`, `keys.rs` and `rsa_pad.rs` — the test keeps the list in step with the code. - `change_kind` keeps main's arms, with our `kind::*` constants in place of the bare strings. - The Spanish catalog gains the 19 new sentences and loses the one about a format PdfCraft does not check yet, which it now does. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Noticed while merging
Happy to send a separate PR deleting the two stale copies if that is useful. |
…moved Conflicts, each resolved so both sides survive: - crates/a11y/src/structure.rs: main (storytold#926) rewrote the structure rules as a streaming visitor. The branch's wordings are ported onto it: the `{ty} element[ on page {p}]: {what}` frames via Finding::nested, the IRREGULAR wording with {min}/{max}, and the two heading sentences. - crates/engine/src/lib.rs: the branch's Label arms, plus main's new FillAnnotation (comment properties) and MoveObjects ("Move object" / "Move objects", added to EDIT_LABELS; es.tsv already has them). - crates/ui-egui/src/editing.rs: main's move_error message with the branch's edit_label. - es.tsv, parity/acrobat-features.toml: both sides' entries; the parity entry has main's shortcut evidence and sentence plus the branch's. - ATTRIBUTION.toml: main's, with es.tsv's sha256 recomputed. - engine tests: main's new MoveObjects undo assertion compares as_str(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # ATTRIBUTION.toml # crates/sign/src/pdf.rs
|
Thank you, @feraremag2680! This has landed on main: "i18n: let the layers below hand their sentences over, so they can be translated". I merged main: the structure-tree rules had become a streaming visitor (#926), so your wordings were ported onto it, and the signature verifier now uses your Please join us on Discord if you haven't already: https://discord.gg/artcraft |
Only ROADMAP.md conflicted (both sides added a progress-log line); both lines are kept. storytold#478's translatable print errors leave spooler faults as their own text, so the native path's messages are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What this is
The interface is translated into ten languages, but a good part of what a person actually reads in the Accessibility panel, the PDF/A list, the signature details, the print dialog and the edit history was still English in every one of them. Those sentences are worded by the layers below the UI, and
notify_errorsays why they were left alone:That is exactly right, so this doesn't try to match the wording from the outside. It has each layer hand its own wording over, apart from the document's own words, and lets the UI look it up.
The arrangement
Each layer that words sentences gains three things, in its own vocabulary:
pub const WORDINGS: &[&str]— every sentence it can say, written once, with holes in it ({n},{p},{}).said(&self, words: Words) -> String— says one of them: look the wording up through the closure, then fill the holes with the document's values in a single pass, so a file name containing{n}goes in as written.pub fn in_english(wording: &str) -> String— the closure that changes nothing, for the CLI, the automation layer and the tests.The UI passes
&crate::i18n::words, which is a catalog lookup. A wording with no catalog entry comes back as it stands — which is the English — so a catalog that is missing one shows an English sentence rather than a gap, and the nine catalogs this PR doesn't touch keep reading exactly as they do today.Because the sentence is now data the layer publishes rather than a literal duplicated in the UI, it cannot drift: change the wording and the catalog entry stops matching, which is what the tests check.
What changed
Engine side.
a11y::Finding,preflight::Issue,sign::pdf::Detailandprint::PrintErrorcarried pre-formatted EnglishStrings; they now carry the document's values and name their wording.Edit::label()likewise returns aLabel { wording, value }, listed inEDIT_LABELS/BATCH_LABELS. The lists area11y::{WORDINGS, REPORT_WORDS},preflight::WORDINGS,sign::pdf::{WORDINGS, kind::ALL},print::WORDINGSand the engine's two label lists.a11y::report_htmltakes a language tag and awordsclosure, so a saved report reads the way the panel read, down to itslangattribute.print::PrintErrornow has a variant per thing a person can be wrong about (NoPages,OutOfRange,NotAPage), with the numbers apart from the words;select_listedused to format that same sentence intoInvalid. Faults rather than mistakes — a file that cannot be read, a poisoned lock — keep their own text, andsaidpasses them through.UI side.
a11y_ui.rs(findings and the saved report),standards_ui.rs,sign_ui.rsandprint_ui.rscallsaid(&crate::i18n::words). No newtl!literal is introduced anywhere, so{simplified_chinese,french,russian}_covers_ui_literalsare unaffected (a closure argument is not a literal).Spanish. 107 entries added to
es.tsv, covering all of the lists above, with its SHA-256 updated inATTRIBUTION.toml.Tests
spanish_covers_what_the_engine_says— one catalog entry per wording in all eight lists, so the catalog cannot fall behind the engine without a test saying so.spanish_keeps_the_holes_in_what_the_engine_says— each translation keeps the same holes as the English, named ones included.print::tests::wordings_are_said—said(&in_english) == to_string()for every mistake, one wording per mistake, a fault's text is never translated, and a value containing{count}is not re-read as a hole.cargo fmt --check,cargo clippy --workspace --all-targets -- -D warnings,cargo xtask layers,cargo xtask assets,cargo xtask parityall pass.Two unrelated, pre-existing failures show up on my machine (Windows, system language Spanish), both of them also on an unmodified checkout:
i18n::tests::windows_display_language_query_returns_a_locale_tag—windows_ui_language()returns the preferred-language list joined with\n, so the assertion fails on any Windows with two or more display languages. Described in sign: read the .p12 files Windows writes (BER, not DER) #453.tests/accessibility.rs(both tests) — the kittest harness leaves the language on Auto, so on a machine whose system language has a catalog the shell is drawn translated andget_by_label("Accessibility Checker Options")finds nothing.LC_ALL=en_US.UTF-8 cargo test -p pdfcraft-ui-eguipasses everything. Setting the language explicitly in the harness would fix it; I left it alone to keep this PR to one thing, and I'm happy to send it separately.With the language pinned to English,
cargo test --workspaceis green apart from the first item above.Adding another language
Translate the entries; nothing else is needed.
docs/localization.mdhas a new section, Sentences the engine words, describing the arrangement, and the per-language gate is three lines if you want one.🤖 Generated with Claude Code