Commit Graph
311 Commits
Author SHA1 Message Date
4995da0653 i18n: add Russian (ru) interface translation (#375)
* i18n: add Russian (ru) interface translation

- Add ru.tsv catalog (~1950 entries, clean-room translations following PhotoCraft terminology: Слой, Образцы, Обработка контуров, Монтажная область, Обводка, Заливка)
- Register ru in LANGUAGES with plural_russian (one/few/many with 11-14 exception)
- Add Russian tests: registration, command/catalogue coverage, UI literals, history/diagnostics, plural forms
- Add ATTRIBUTION.toml entry for ru.tsv
- Update docs/localization.md, ROADMAP.md with Russian language
- All i18n tests pass, cargo fmt and clippy clean

* ru: translate labels added on main since the catalog was written; Russian in the Latin-font coverage test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ru: '>' in the JavaScript-off hint, as the other catalogs (Inter has no ▸)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 19:24:51 -04:00
f88a59f762 M10.2: Create PDF from multiple files, edited as pages in the Organize grid (#361)
* M10.2: create PDF from multiple files

Create a PDF ▸ Multiple files takes PDFs, images and .txt files, lets the
user reorder them, and makes one combined PDF (a bookmark and an optional
page range per file) or one PDF per file in a chosen folder, never
overwriting what is there.

- create: source_kind() tells PDFs, images and text apart (moved from the shell)
- engine: Session::convert_to_pdf, shared by Open, the dialog and the tool
- automation: doc_create_multiple (combine or separate)
- ui: Multiple files dialog reusing the Combine files list; translations
- parity entry and ROADMAP updated; catalog hashes refreshed

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M10.2: multiple files open in the page grid; insert files at any gap

Create a PDF ▸ Multiple files now opens the picked files as one unsaved
document in the Organize page grid instead of a file-list dialog: pages
are removed and reordered there, and Save pages writes what is shown.

- grid: a "+" at every gap inserts files right there; Save pages button
- insert from file: several files in order, images and text converted,
  inserted pages selected
- the file-list dialog is removed; one PDF per file stays in the
  doc_create_multiple tool
- translations, catalog hashes, parity notes and ROADMAP updated

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M4: insert files by dropping them on the page grid

On desktop, PDFs, images and .txt files dropped on the Organize page grid
are inserted at the gap under the pointer, in order, and selected; a
dropped file still opens as a document everywhere else.

winit does not report the pointer while files are dragged over the
window on every platform, so a drop waits (up to a second) for the
pointer to show up and otherwise appends at the end.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M4: files dragged over the page grid follow the pointer (macOS)

winit sends no pointer moves while files are dragged over the window, so
egui kept the place the pointer entered at: the insertion bar froze there
and the files were inserted there. During a file drag the pointer is now
read from AppKit (safe objc2 calls, crates already in the tree) and fed
to egui, so the bar and a "+" badge follow the pointer and the files go
where they are released.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-08 17:42:13 -04:00
Devon LlewellynandBrandon Thomas acb8e96aff Update image signatures live during resize and movement (#355)
* M5.7: update image signatures live during resize and movement

* M5.7: preserve image signature proportions when resizing corners

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-08 17:17:05 -04:00
05c8ab3b3e M14: Telugu (తెలుగు) interface language (#349)
* M14: Telugu interface font

- The interface takes `Telu` faces from craft-fonts after the CJK and Arabic ones, on the web too
- Test: Telugu text has glyphs in every family and its conjuncts are shaped

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>

* M14: Telugu interface language

- Complete te catalog: 1,984 entries plus whole-phrase Undo/Redo; te and te_IN locales use it
- Undo and Redo labels use a catalog phrase when the language has one (Telugu puts the verb last)
- Tests, docs, attribution, parity and ROADMAP

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>

* Add my contributor name (chiranjeevi-max)

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>

* M14: catalog contexts for labels with two meanings

- tl_ctx! gives the signature pad's Type, the Action Wizard's Start and the comment menu's Edit their own context; Telugu translates them, other languages keep their current translation
- Preferences' All tools goes through the catalog in every language

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>

* M14: Telugu for the look-alike web address warnings

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>

* M14: Telugu for the image signature notices

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>

* Telugu for Open Recent (#323)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 17:00:25 -04:00
Devon Llewellyn e17833a64e Add image signatures with placement preview and resize controls (#335)
* M5.7: import images as Fill & Sign signatures and initials

* M5.7: preview image signatures and select after placement
2026-10-08 16:36:26 -04:00
9140b44792 M4: Combine files in its own tab, with a sortable table and unlocking of protected files (#321)
* M4: Combine files in its own tab, with a sortable table and unlocking of protected files

Combine files was a modal dialog with a cramped list and up/down buttons on
every row. It is now a tab next to Home and the documents, showing a table
of the files: File name | Pages | Size | Modified | Warnings.

- Columns sort when their heading is clicked (anywhere in the cell; again to
  reverse; names in natural order), resize from their edges and move by
  dragging the heading. Order and widths are kept in the settings; a
  right-click on a heading resets them.
- Rows select like a file manager (click, Ctrl/Cmd+click, Shift+click,
  Shift+arrows, Ctrl/Cmd+A). One toolbar moves, removes and unlocks the
  selection; Alt+arrows and dragging move it too. Every change to the list
  undoes and redoes with Cmd/Ctrl+Z (also toolbar buttons).
- Add files, Add folder, Add folder and subfolders (a split button), Add open
  documents, or drop files and folders on the tab.
- Problems show before Combine: password-protected files, security settings
  that withhold page assembly, page ranges (checked as typed, with the pages
  they take), duplicates. Files that open but are protected say that the
  combined file won't keep their security; the result is never encrypted.
- Unlock... asks for a file's open or permissions password (one password can
  be tried on several files). Passwords stay in memory, are never printed,
  and reach the engine through combine_unlocked; doc_combine takes them as
  `passwords`. The engine decides whether a password works, since the
  inspector rejects some it accepts (RC4 owner passwords).

organize.combine-sort is shipped and organize.combine-options partial
(include open files). Strings are translated for es, fr, ja, zh-hans, zh-hant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Credit Marlon Konrad (mlkonrad) in the About window

Adds my own entry to contributors/people.toml, as docs/contributors.md asks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-08 15:37:10 -04:00
d801407a9f Windows MSI: reject per-user overrides and retain progress text (#305) (#310)
* #305: harden Windows MSI deployment and progress UI

Co-authored-by: Codex <noreply@openai.com>

* Keep the MSI manufacturer as Learning Machines LLC

The company name matches the Linux packages; changing it is the owner's call.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* #305: keep compiled-MSI checks compatible with PowerShell COM

Validated the compiled x64 MSI and negative scope, publisher and progress mutations.

Co-authored-by: Codex <noreply@openai.com>

* ROADMAP: the publisher name is unchanged

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:40:30 -04:00
7458f7d47d M14: complete Simplified Chinese About credits and multiline guidance (#311)
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-08 13:39:40 -04:00
edce549a32 M9: sign with the Windows certificate store (#179) (#304)
List Current User Personal CNG identities alongside file digital IDs and sign
without exporting their private keys through safe rustls-cng wrappers.
Expose Windows store references through automation and the desktop dialogs,
with RSA and ECDSA validation, certificate cleanup, and UI regression coverage.

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-08 13:02:52 -04:00
cd8c753527 M14: French interface catalog (#291)
Add Français (fr) as a complete UI catalog and select it for every
French locale. Preferences lists it, and Auto follows fr, fr_FR,
fr_CA and fr_BE. About credits labels now go through the catalog.

Coverage tests check commands, All tools labels and every tl! literal.
The bundled Latin faces cover the catalog.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: iMhack <iMhack87@users.noreply.github.com>
2026-10-08 11:16:30 -04:00
Sameh ElhawaryandClaude Opus 5.5 d30bb111db M14: Arabic and Hebrew file names render in the tab strip, recent files and Properties (#285)
A tab named in Arabic showed replacement boxes: no interface font had the
glyphs, and egui joins the letters of a right-to-left word but places the
runs in logical order.

- Fonts: the interface takes `Arab` faces from the craft-fonts build input
  (also on wasm), and on desktop adds one font already installed on the
  machine as the last fallback of every family. It is read at runtime, never
  embedded; PDFCRAFT_SYSTEM_FONTS=0 turns it off and `cargo xtask screenshots`
  sets that. AGENTS.md §1.4 records the rule.
- Order: bidi::visual puts single-line text in display order with a
  left-to-right base, used for the painted tab label and hover text, the
  recent-files name and path, and the Properties File and Location rows.
  Accessibility names keep the logical text.

misc.rtl-ui stays planned: multi-line text, text input and a mirrored layout
are not done.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:46:58 -04:00
Chiranjeevi U 8407c87ef9 #214: wheel paging, Page display menu, default layout and zoom (#241)
- The wheel turns pages in single-page view: one per notch, one per swipe.
- The rail's Page display menu offers Acrobat's view choices.
- Preferences: default page display and default zoom.
- Fit page and Fit height no longer jump across mixed page sizes.
2026-10-08 06:35:51 -04:00
932967a30d Restore #196, #202, #203 and the macOS release-runner change, reverted by the i18n chain (#229)
* Release CI: macOS job on macos-15-xlarge

Custom macOS larger runners in a runner group do not pick up jobs; the
built-in M2 Pro label does. Only release.yml uses it, and the
actions_macos_xl budget caps the monthly spend.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 90d60b0c98)

* CI: tell actionlint about the org's macos-release runner label (#202)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit ddea3c72e0)

* About: contributor and model credits compiled in (grab bag + table, self-submitted names) (#196)

* About: contributors compiled in from contributors.json (grab bag + table, sortable, name toggle)

Adds About ▸ Contributors and About ▸ Models tabs per the craftrules standard
(standards/contributors.md): contributors/contributors.json is generated by
craftrules/scripts/contributors.py and baked into the binary by crates/ui-egui/build.rs as
static tables; nothing is read at run time. Each contributor line: @username, opt-in
display/real name, PRs, commits, lines +/−/Δ, binary assets +/−, first/last commit.
Sortable by every column; alphabetical ignores case and the leading @.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: self-submitted names in contributors/people.toml; AGENTS.md credit-yourself section

build.rs reads contributors/people.toml next to the generated contributors.json and shows a name only
for entries the generator verified as written by that person (craftrules standards/contributors.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: regenerate (verified people.toml entries)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 41e214c318)

* M13: exit cleanly when stdout pipe closes (#203)

Co-authored-by: Brandon Thomas <echelon@gmail.com>
(cherry picked from commit 1cf0d319e4)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Ayan <108534604+excited-raccoon@users.noreply.github.com>
2026-10-08 03:33:35 -04:00
42078a8365 Fix theme controls with shared System, Light and Dark preferences (#212)
* M3: unify toolbar and menu theme preferences

Co-authored-by: Codex <noreply@openai.com>

* M3: use the current egui style API in theme regression

Co-authored-by: Codex <noreply@openai.com>

---------

Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-08 01:50:59 -04:00
ec980d0743 fix(i18n): follow Windows display language for Chinese UI (#216)
* fix(i18n): follow Windows display language for Chinese UI

M14: resolve Auto through the Windows UI culture after locale environment
variables. Reuse Chinese region/script mapping and cover the query and
fallback behavior.

Refs #215

Co-authored-by: Codex <noreply@openai.com>

* Windows Auto language: ask Windows directly instead of starting PowerShell

sys-locale (1Password, MIT OR Apache-2.0) reads GetUserPreferredUILanguages, so
Auto no longer launches a hidden powershell.exe at startup (slow, and the kind of
behaviour endpoint security tools flag). All preferred display languages are
tried in order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 01:19:07 -04:00
6974c6550d Measure: add distance, perimeter and area tools (#208)
* M12: add calibrated 2D measurement tools

* M12: harden measurement tools for landing (#208)

Bounded snap targets (endpoints only for accepted segments, page-wide cap),
lenient extraction (deep q nesting and undecodable streams are skipped and
reported), per-page snap cache, measure::list reports unsupported entries
instead of failing, closed polygons with a repeated vertex, printable unit
labels (m²), cached panel listing, WinAnsi captions, indirect /VP kept,
measure.export skipped in the command test like other pickers, missing
translations, honest parity (scale and distance partial) and ROADMAP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 00:38:57 -04:00
才倾梦华VandBrandon Thomas 77893e8ab3 M14: complete Simplified Chinese translation catalog (#209)
* M14: complete Simplified Chinese translation catalog

* M14: translate new XFA notices and counts

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-07 23:45:02 -04:00
0bbba8cafa #161: keep the Save-changes prompt inside the screen (#207)
An unwrapped title carried a long file name past the viewport: egui's Modal
sizes to its content, so the centered panel grew to the name's full width,
clipped its own message and pushed Save/Cancel off-screen (reported on
Windows, reproduced everywhere). Wrap the title to the dialog width in the
save prompt and the password prompt, and pin the title and all three
buttons inside a 1365x719 screen in a regression test.

Co-authored-by: Mawfyy <mawfy12@gmail.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-07 23:14:45 -04:00
607d3d1c0e #190: choose DPI when creating PDFs from images (#206)
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-07 23:14:22 -04:00
355de9038e i18n: Simplified Chinese UI language option (#112)
* i18n: Czech interface language

Adds Czech (Čeština, code `cs`) next to English and Japanese:
Preferences ▸ Interface language, `ui.set language cs`, `ui.state`
and persisted preferences all accept it.

- i18n: `Language::Cs`; `tr()` picks the language's table with a match
  (English has none), panic-free. The CZECH table (83 entries) covers
  every label passed to `.tr("…")` (main menu, View zoom/theme/side-panel
  entries, Preferences dialog), every registered File/Edit/Pages/View/Help
  command shown by `registry_menu`, and every key of the Japanese table.
  Written clean-room from the English meaning, not from any Acrobat
  localisation.
- Tests: Czech covers every registered menu title and label, every
  `.tr("…")` literal found by scanning the crate's sources, and the
  Japanese keys; nothing is left identical except an explicit KEEP_AS_IS
  list ("OK"); ellipses match the source; keys are unique per language;
  `cs` round-trips through set_option, ui.set/ui.state and persistence.
- theme: the font setup is split into `font_definitions()`, and a test
  checks with skrifa (dev-dependency, already in the tree via egui) that
  Inter Regular/Medium/SemiBold and JetBrains Mono draw all Czech letters
  and every Czech translation, so nothing falls back to Shippori Mincho.
- The `language` error lists `cs`; docs/localization.md, the parity note
  for misc.prefs-language and the ROADMAP log mention Czech.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* M14: translation catalogs, same system as PhotoCraft

Move the interface translations to PhotoCraft's i18n system: one TSV
catalog per language (crates/ui-egui/src/i18n/ja.tsv), the tl! macro,
entries keyed by command id, context or plural forms, and catalog tests
(format, duplicates, placeholders, command ids).

The 49 existing Japanese strings move over unchanged, plus "Auto". The
language preference now defaults to "auto" and follows the system
language (English when it has no catalog); "en" and "ja" still persist
and unknown values are rejected.

Update docs/localization.md, ROADMAP.md and the misc.prefs-language
parity entry.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* M14: add Traditional Chinese (Taiwan) UI localization

Co-Authored-By: Codex <noreply@openai.com>

* M14: translate shortcuts and expose language preferences in Edit menu

Add command-comma and verify language switching through the actual selector.

Co-authored-by: Codex <noreply@openai.com>

* M14: expand Traditional Chinese dialogs, panels and diagnostics

Preserve opaque values in translated templates and keep application diagnostics at the UI boundary. Extend native control and template regression coverage.

Co-authored-by: Codex <noreply@openai.com>

* M14: finish Traditional Chinese signature prompts and history labels

Translate generated action labels without changing filenames or field names. Complete checkbox styles, resolution labels and native picker filters.

Co-authored-by: Codex <noreply@openai.com>

* M14: complete Japanese dialogs, panels, shortcuts and diagnostics

Expand Japanese from 49 to 1830 interface entries, expose language preferences in the Edit menu, preserve opaque template and history values, and localize known application diagnostics only at the UI boundary. Add control, persistence, template and desktop/web glyph regressions.

Co-authored-by: Codex <noreply@openai.com>

* i18n: Simplified Chinese UI language option

Adds Language::Zh alongside en/ja (--language zh, preferences switch,
persisted): full Chinese translation table covering every user-visible
label, generic Hans font fallback plumbing, and a build.rs skip-guard
plus test so Noto CJK is never embedded (AGENTS.md 1.1). Pairs with
storytold/craft-fonts#5 (ChillRoundF Regular, OFL-1.1 Adobe-free
chain), which supplies the Hans glyphs. Also fixes a startup deadlock
from translating inside lazy widget_info closures.

* i18n: add Brazilian Portuguese (pt-br) UI translation

Adds Language::PtBr (code pt-br, endonym Português (Brasil)) with serde rename so it persists as "pt-br", registers it in Language::ALL (Preferences ▸ Interface language and ui.set/ui.state) and translates the same 49 menu/command keys as the Japanese table. Extends the i18n tests (table parity, codes, persistence) and updates docs/localization.md.

* M14: strict catalog validation, one-pass fmt, translation assets

Fold in the infrastructure parts of #175:
- `fmt` fills placeholders in one pass, so inserted values (a file name
  containing `{n}`) are never substituted again.
- Catalog validation rejects unknown escapes, unknown `@` contexts,
  placeholder, ellipsis and plural-form mismatches and duplicates. The
  bundled catalogs must have no errors (tests); at run time a bad line is
  still only skipped and logged, so the rest of the catalog loads.
- `.tsv` files count as assets in `cargo xtask assets`, with a
  `translation` kind that may never come from Adobe; ja.tsv gets its
  ATTRIBUTION.toml entry.
- Control-channel test: switching the language keeps documents, their
  dirty state and command ids.

Also make the drawing language thread-local, as in PhotoCraft, so
parallel kittest harnesses can't change each other's language.

Co-Authored-By: 才倾梦华V <185041488+CQMHV@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: Brazilian Portuguese as a TSV catalog

Move #165's Portuguese table into crates/ui-egui/src/i18n/pt-br.tsv
(same 49 strings, plus Auto) and register it in LANGUAGES with
PhotoCraft's Portuguese plural rule (0 and 1 singular). Any Portuguese
locale (pt_BR, pt_PT, pt) follows the Brazilian catalog, as in
PhotoCraft. The catalog is an attributed asset (ATTRIBUTION.toml), and
the docs and parity notes list the new code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: Czech as a TSV catalog

Move #68's Czech table into crates/ui-egui/src/i18n/cs.tsv (PrintCraft
labels renamed PdfCraft, plus Auto) and register it with PhotoCraft's
Czech plural rule (one / few / other). #68's tests become catalog
tests: Czech covers every registered menu title and menu command label,
keeps ellipses, uses no three-dot ellipsis or stray whitespace, and only
leaves "OK" untranslated; the code persists and `cz` is rejected. The
source-scanning `.tr("…")` test is dropped: strings now go through tl!
and the catalog tests check consistency.

The font-coverage test moves to tests/fonts.rs and covers both Latin
catalogs (cs, pt-br) against Inter and JetBrains Mono. It keeps skrifa
as a dev-dependency (the version pdfcraft-fonts already uses): egui's
has_glyphs can't answer it, since a family with only the primary face
also uses that face as its replacement face.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: route every UI string through the catalog; Japanese as ja.tsv

Port #141's wiring to the catalog API from land/106:
- `crate::i18n::tr(ui, s)` becomes `tl!(s)`, `tr_fmt`/`tr_template`
  become `i18n::fmt(tl!(..), ..)`, and `Language::get`/`store` (the
  egui temp-data copy of the language) are gone: the drawing language
  is the per-thread `i18n::current()`, set from the preference at the
  start of each frame. Worker threads (export, OCR, batch actions) take
  the UI's language with them for their summaries.
- ja.rs (1,830 pairs) becomes ja.tsv, merged with the existing entries
  and renamed PrintCraft -> PdfCraft. The 29 diagnostic templates of
  errors.rs are dropped.
- `Language::diagnostic` and errors.rs are dropped: matching engine and
  OS messages against English templates breaks silently whenever the
  wording changes. Error details are shown as they are, inside the
  translated frame ("{label} failed: {e}").
- History labels (`command_label`/`action_label`) move into i18n and keep
  captured file and field names; registry menus prefer `@id` entries.
- Preferences: Auto plus every registered language, relabelled at once.
- Tests: Japanese covers every command and All tools entry; Japanese
  labels have glyphs with the desktop faces and with the web subset
  (with craft-fonts); history labels; #141's control tests, with the
  error-detail expectation updated.

Co-Authored-By: shuiyue-cmyk <291597411+shuiyue-cmyk@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: Preferences in the Edit menu, Cmd/Ctrl-comma

Split out of #141: register app.preferences in the Edit menu with the
platform's usual shortcut (Command-comma on macOS, Ctrl-comma
elsewhere), so the interface language can be found and changed with no
document open. Shortcut keys may now be punctuation (egui's key name
","). #141's control test drives the menu item, the language selector
and the shortcut in Japanese and English.

Co-Authored-By: sakamoto824 <sakamoto824@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: Traditional Chinese as zh-hant.tsv

Reduce #140 to its translations: zh_tw.rs becomes
crates/ui-egui/src/i18n/zh-hant.tsv (PrintCraft renamed PdfCraft; the
29 errors.rs diagnostic templates dropped, as for Japanese) and one
registry row, code `zh-hant` (Taiwan vocabulary). Locales zh_TW, zh_HK,
zh_MO and zh-Hant-* resolve to it. #140's own copy of the UI wiring and
its errors.rs diagnostics are not taken: land/141 carries the wiring.
Tests: registration, locale mapping, every command label translated.
The catalog is an attributed asset; docs, ROADMAP and parity list it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: Simplified Chinese as zh-hans.tsv

Reduce #112's translations to crates/ui-egui/src/i18n/zh-hans.tsv
(PrintCraft renamed PdfCraft) and one registry row, code `zh-hans`
(#112 used `zh`; `zh`, `zh_CN`, `zh_SG` and `zh-Hans` locales still
resolve to it through the system-language match). #112's own copy of
the UI wiring is superseded by land/141. Tests: registration, locale
mapping, menu coverage. The catalog is an attributed asset; docs,
ROADMAP and parity list it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: CJK font order follows the UI language

From #112: `ui_cjk_fonts(prefer_hans)` orders the craft-fonts CJK faces
for the interface, and `theme::font_definitions_for` installs them. In
Simplified Chinese the `Hans` faces come first; otherwise the Japanese
ones (the previous behaviour). egui draws each character with the first
face that has it, so with Japanese first a Simplified-only character
(欢) would land in another face and sit on a different baseline. The
fonts are reinstalled when the language crosses that line (same family
names, so named fonts stay valid while the new set loads).

Changes from #112: within each group BIZ UDPGothic still leads, so a
serif listed first in the manifest (Shippori Mincho) never becomes the
Chinese-mode UI fallback; the unused `document_chinese_font` is left
out; and the crates/fonts/build.rs special case that skipped
"Noto Sans CJK SC" (and its test assertion and README line) is not
taken. Without CRAFT_FONTS_DIR, or without a `Hans` face, the order
logic yields only what exists: Chinese characters then show replacement
boxes and nothing panics (tests/fonts.rs, the fonts crate test, and the
control test switching ja -> zh-hans -> en).

Also document `--language` on the app's command line.

Co-Authored-By: shuiyue-cmyk <291597411+shuiyue-cmyk@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Petr Leo Compel <petrleocompel@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Simon Leblanc <contact@leblanc-simon.eu>
Co-authored-by: sakamoto824 <sakamoto824@gmail.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: shuiyue-cmyk <291597411+shuiyue-cmyk@users.noreply.github.com>
Co-authored-by: RicSchonfelder <ricschonfelder@icloud.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: 才倾梦华V <185041488+CQMHV@users.noreply.github.com>
2026-10-07 22:17:00 -04:00
ab4c87926a M14: expand Traditional Chinese UI, dialogs and language preferences (#140)
* i18n: Czech interface language

Adds Czech (Čeština, code `cs`) next to English and Japanese:
Preferences ▸ Interface language, `ui.set language cs`, `ui.state`
and persisted preferences all accept it.

- i18n: `Language::Cs`; `tr()` picks the language's table with a match
  (English has none), panic-free. The CZECH table (83 entries) covers
  every label passed to `.tr("…")` (main menu, View zoom/theme/side-panel
  entries, Preferences dialog), every registered File/Edit/Pages/View/Help
  command shown by `registry_menu`, and every key of the Japanese table.
  Written clean-room from the English meaning, not from any Acrobat
  localisation.
- Tests: Czech covers every registered menu title and label, every
  `.tr("…")` literal found by scanning the crate's sources, and the
  Japanese keys; nothing is left identical except an explicit KEEP_AS_IS
  list ("OK"); ellipses match the source; keys are unique per language;
  `cs` round-trips through set_option, ui.set/ui.state and persistence.
- theme: the font setup is split into `font_definitions()`, and a test
  checks with skrifa (dev-dependency, already in the tree via egui) that
  Inter Regular/Medium/SemiBold and JetBrains Mono draw all Czech letters
  and every Czech translation, so nothing falls back to Shippori Mincho.
- The `language` error lists `cs`; docs/localization.md, the parity note
  for misc.prefs-language and the ROADMAP log mention Czech.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* M14: translation catalogs, same system as PhotoCraft

Move the interface translations to PhotoCraft's i18n system: one TSV
catalog per language (crates/ui-egui/src/i18n/ja.tsv), the tl! macro,
entries keyed by command id, context or plural forms, and catalog tests
(format, duplicates, placeholders, command ids).

The 49 existing Japanese strings move over unchanged, plus "Auto". The
language preference now defaults to "auto" and follows the system
language (English when it has no catalog); "en" and "ja" still persist
and unknown values are rejected.

Update docs/localization.md, ROADMAP.md and the misc.prefs-language
parity entry.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* M14: add Traditional Chinese (Taiwan) UI localization

Co-Authored-By: Codex <noreply@openai.com>

* M14: translate shortcuts and expose language preferences in Edit menu

Add command-comma and verify language switching through the actual selector.

Co-authored-by: Codex <noreply@openai.com>

* M14: expand Traditional Chinese dialogs, panels and diagnostics

Preserve opaque values in translated templates and keep application diagnostics at the UI boundary. Extend native control and template regression coverage.

Co-authored-by: Codex <noreply@openai.com>

* M14: finish Traditional Chinese signature prompts and history labels

Translate generated action labels without changing filenames or field names. Complete checkbox styles, resolution labels and native picker filters.

Co-authored-by: Codex <noreply@openai.com>

* M14: complete Japanese dialogs, panels, shortcuts and diagnostics

Expand Japanese from 49 to 1830 interface entries, expose language preferences in the Edit menu, preserve opaque template and history values, and localize known application diagnostics only at the UI boundary. Add control, persistence, template and desktop/web glyph regressions.

Co-authored-by: Codex <noreply@openai.com>

* i18n: add Brazilian Portuguese (pt-br) UI translation

Adds Language::PtBr (code pt-br, endonym Português (Brasil)) with serde rename so it persists as "pt-br", registers it in Language::ALL (Preferences ▸ Interface language and ui.set/ui.state) and translates the same 49 menu/command keys as the Japanese table. Extends the i18n tests (table parity, codes, persistence) and updates docs/localization.md.

* M14: strict catalog validation, one-pass fmt, translation assets

Fold in the infrastructure parts of #175:
- `fmt` fills placeholders in one pass, so inserted values (a file name
  containing `{n}`) are never substituted again.
- Catalog validation rejects unknown escapes, unknown `@` contexts,
  placeholder, ellipsis and plural-form mismatches and duplicates. The
  bundled catalogs must have no errors (tests); at run time a bad line is
  still only skipped and logged, so the rest of the catalog loads.
- `.tsv` files count as assets in `cargo xtask assets`, with a
  `translation` kind that may never come from Adobe; ja.tsv gets its
  ATTRIBUTION.toml entry.
- Control-channel test: switching the language keeps documents, their
  dirty state and command ids.

Also make the drawing language thread-local, as in PhotoCraft, so
parallel kittest harnesses can't change each other's language.

Co-Authored-By: 才倾梦华V <185041488+CQMHV@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: Brazilian Portuguese as a TSV catalog

Move #165's Portuguese table into crates/ui-egui/src/i18n/pt-br.tsv
(same 49 strings, plus Auto) and register it in LANGUAGES with
PhotoCraft's Portuguese plural rule (0 and 1 singular). Any Portuguese
locale (pt_BR, pt_PT, pt) follows the Brazilian catalog, as in
PhotoCraft. The catalog is an attributed asset (ATTRIBUTION.toml), and
the docs and parity notes list the new code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: Czech as a TSV catalog

Move #68's Czech table into crates/ui-egui/src/i18n/cs.tsv (PrintCraft
labels renamed PdfCraft, plus Auto) and register it with PhotoCraft's
Czech plural rule (one / few / other). #68's tests become catalog
tests: Czech covers every registered menu title and menu command label,
keeps ellipses, uses no three-dot ellipsis or stray whitespace, and only
leaves "OK" untranslated; the code persists and `cz` is rejected. The
source-scanning `.tr("…")` test is dropped: strings now go through tl!
and the catalog tests check consistency.

The font-coverage test moves to tests/fonts.rs and covers both Latin
catalogs (cs, pt-br) against Inter and JetBrains Mono. It keeps skrifa
as a dev-dependency (the version pdfcraft-fonts already uses): egui's
has_glyphs can't answer it, since a family with only the primary face
also uses that face as its replacement face.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: route every UI string through the catalog; Japanese as ja.tsv

Port #141's wiring to the catalog API from land/106:
- `crate::i18n::tr(ui, s)` becomes `tl!(s)`, `tr_fmt`/`tr_template`
  become `i18n::fmt(tl!(..), ..)`, and `Language::get`/`store` (the
  egui temp-data copy of the language) are gone: the drawing language
  is the per-thread `i18n::current()`, set from the preference at the
  start of each frame. Worker threads (export, OCR, batch actions) take
  the UI's language with them for their summaries.
- ja.rs (1,830 pairs) becomes ja.tsv, merged with the existing entries
  and renamed PrintCraft -> PdfCraft. The 29 diagnostic templates of
  errors.rs are dropped.
- `Language::diagnostic` and errors.rs are dropped: matching engine and
  OS messages against English templates breaks silently whenever the
  wording changes. Error details are shown as they are, inside the
  translated frame ("{label} failed: {e}").
- History labels (`command_label`/`action_label`) move into i18n and keep
  captured file and field names; registry menus prefer `@id` entries.
- Preferences: Auto plus every registered language, relabelled at once.
- Tests: Japanese covers every command and All tools entry; Japanese
  labels have glyphs with the desktop faces and with the web subset
  (with craft-fonts); history labels; #141's control tests, with the
  error-detail expectation updated.

Co-Authored-By: shuiyue-cmyk <291597411+shuiyue-cmyk@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: Preferences in the Edit menu, Cmd/Ctrl-comma

Split out of #141: register app.preferences in the Edit menu with the
platform's usual shortcut (Command-comma on macOS, Ctrl-comma
elsewhere), so the interface language can be found and changed with no
document open. Shortcut keys may now be punctuation (egui's key name
","). #141's control test drives the menu item, the language selector
and the shortcut in Japanese and English.

Co-Authored-By: sakamoto824 <sakamoto824@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: Traditional Chinese as zh-hant.tsv

Reduce #140 to its translations: zh_tw.rs becomes
crates/ui-egui/src/i18n/zh-hant.tsv (PrintCraft renamed PdfCraft; the
29 errors.rs diagnostic templates dropped, as for Japanese) and one
registry row, code `zh-hant` (Taiwan vocabulary). Locales zh_TW, zh_HK,
zh_MO and zh-Hant-* resolve to it. #140's own copy of the UI wiring and
its errors.rs diagnostics are not taken: land/141 carries the wiring.
Tests: registration, locale mapping, every command label translated.
The catalog is an attributed asset; docs, ROADMAP and parity list it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Petr Leo Compel <petrleocompel@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Simon Leblanc <contact@leblanc-simon.eu>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: RicSchonfelder <ricschonfelder@icloud.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: 才倾梦华V <185041488+CQMHV@users.noreply.github.com>
Co-authored-by: shuiyue-cmyk <291597411+shuiyue-cmyk@users.noreply.github.com>
2026-10-07 22:16:34 -04:00
a4340d34c8 M14: complete Japanese dialogs, panels, shortcuts and diagnostics (#141)
* i18n: Czech interface language

Adds Czech (Čeština, code `cs`) next to English and Japanese:
Preferences ▸ Interface language, `ui.set language cs`, `ui.state`
and persisted preferences all accept it.

- i18n: `Language::Cs`; `tr()` picks the language's table with a match
  (English has none), panic-free. The CZECH table (83 entries) covers
  every label passed to `.tr("…")` (main menu, View zoom/theme/side-panel
  entries, Preferences dialog), every registered File/Edit/Pages/View/Help
  command shown by `registry_menu`, and every key of the Japanese table.
  Written clean-room from the English meaning, not from any Acrobat
  localisation.
- Tests: Czech covers every registered menu title and label, every
  `.tr("…")` literal found by scanning the crate's sources, and the
  Japanese keys; nothing is left identical except an explicit KEEP_AS_IS
  list ("OK"); ellipses match the source; keys are unique per language;
  `cs` round-trips through set_option, ui.set/ui.state and persistence.
- theme: the font setup is split into `font_definitions()`, and a test
  checks with skrifa (dev-dependency, already in the tree via egui) that
  Inter Regular/Medium/SemiBold and JetBrains Mono draw all Czech letters
  and every Czech translation, so nothing falls back to Shippori Mincho.
- The `language` error lists `cs`; docs/localization.md, the parity note
  for misc.prefs-language and the ROADMAP log mention Czech.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* M14: translation catalogs, same system as PhotoCraft

Move the interface translations to PhotoCraft's i18n system: one TSV
catalog per language (crates/ui-egui/src/i18n/ja.tsv), the tl! macro,
entries keyed by command id, context or plural forms, and catalog tests
(format, duplicates, placeholders, command ids).

The 49 existing Japanese strings move over unchanged, plus "Auto". The
language preference now defaults to "auto" and follows the system
language (English when it has no catalog); "en" and "ja" still persist
and unknown values are rejected.

Update docs/localization.md, ROADMAP.md and the misc.prefs-language
parity entry.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* M14: complete Japanese dialogs, panels, shortcuts and diagnostics

Expand Japanese from 49 to 1830 interface entries, expose language preferences in the Edit menu, preserve opaque template and history values, and localize known application diagnostics only at the UI boundary. Add control, persistence, template and desktop/web glyph regressions.

Co-authored-by: Codex <noreply@openai.com>

* i18n: add Brazilian Portuguese (pt-br) UI translation

Adds Language::PtBr (code pt-br, endonym Português (Brasil)) with serde rename so it persists as "pt-br", registers it in Language::ALL (Preferences ▸ Interface language and ui.set/ui.state) and translates the same 49 menu/command keys as the Japanese table. Extends the i18n tests (table parity, codes, persistence) and updates docs/localization.md.

* M14: strict catalog validation, one-pass fmt, translation assets

Fold in the infrastructure parts of #175:
- `fmt` fills placeholders in one pass, so inserted values (a file name
  containing `{n}`) are never substituted again.
- Catalog validation rejects unknown escapes, unknown `@` contexts,
  placeholder, ellipsis and plural-form mismatches and duplicates. The
  bundled catalogs must have no errors (tests); at run time a bad line is
  still only skipped and logged, so the rest of the catalog loads.
- `.tsv` files count as assets in `cargo xtask assets`, with a
  `translation` kind that may never come from Adobe; ja.tsv gets its
  ATTRIBUTION.toml entry.
- Control-channel test: switching the language keeps documents, their
  dirty state and command ids.

Also make the drawing language thread-local, as in PhotoCraft, so
parallel kittest harnesses can't change each other's language.

Co-Authored-By: 才倾梦华V <185041488+CQMHV@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: Brazilian Portuguese as a TSV catalog

Move #165's Portuguese table into crates/ui-egui/src/i18n/pt-br.tsv
(same 49 strings, plus Auto) and register it in LANGUAGES with
PhotoCraft's Portuguese plural rule (0 and 1 singular). Any Portuguese
locale (pt_BR, pt_PT, pt) follows the Brazilian catalog, as in
PhotoCraft. The catalog is an attributed asset (ATTRIBUTION.toml), and
the docs and parity notes list the new code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: Czech as a TSV catalog

Move #68's Czech table into crates/ui-egui/src/i18n/cs.tsv (PrintCraft
labels renamed PdfCraft, plus Auto) and register it with PhotoCraft's
Czech plural rule (one / few / other). #68's tests become catalog
tests: Czech covers every registered menu title and menu command label,
keeps ellipses, uses no three-dot ellipsis or stray whitespace, and only
leaves "OK" untranslated; the code persists and `cz` is rejected. The
source-scanning `.tr("…")` test is dropped: strings now go through tl!
and the catalog tests check consistency.

The font-coverage test moves to tests/fonts.rs and covers both Latin
catalogs (cs, pt-br) against Inter and JetBrains Mono. It keeps skrifa
as a dev-dependency (the version pdfcraft-fonts already uses): egui's
has_glyphs can't answer it, since a family with only the primary face
also uses that face as its replacement face.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: route every UI string through the catalog; Japanese as ja.tsv

Port #141's wiring to the catalog API from land/106:
- `crate::i18n::tr(ui, s)` becomes `tl!(s)`, `tr_fmt`/`tr_template`
  become `i18n::fmt(tl!(..), ..)`, and `Language::get`/`store` (the
  egui temp-data copy of the language) are gone: the drawing language
  is the per-thread `i18n::current()`, set from the preference at the
  start of each frame. Worker threads (export, OCR, batch actions) take
  the UI's language with them for their summaries.
- ja.rs (1,830 pairs) becomes ja.tsv, merged with the existing entries
  and renamed PrintCraft -> PdfCraft. The 29 diagnostic templates of
  errors.rs are dropped.
- `Language::diagnostic` and errors.rs are dropped: matching engine and
  OS messages against English templates breaks silently whenever the
  wording changes. Error details are shown as they are, inside the
  translated frame ("{label} failed: {e}").
- History labels (`command_label`/`action_label`) move into i18n and keep
  captured file and field names; registry menus prefer `@id` entries.
- Preferences: Auto plus every registered language, relabelled at once.
- Tests: Japanese covers every command and All tools entry; Japanese
  labels have glyphs with the desktop faces and with the web subset
  (with craft-fonts); history labels; #141's control tests, with the
  error-detail expectation updated.

Co-Authored-By: shuiyue-cmyk <291597411+shuiyue-cmyk@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: Preferences in the Edit menu, Cmd/Ctrl-comma

Split out of #141: register app.preferences in the Edit menu with the
platform's usual shortcut (Command-comma on macOS, Ctrl-comma
elsewhere), so the interface language can be found and changed with no
document open. Shortcut keys may now be punctuation (egui's key name
","). #141's control test drives the menu item, the language selector
and the shortcut in Japanese and English.

Co-Authored-By: sakamoto824 <sakamoto824@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Petr Leo Compel <petrleocompel@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Simon Leblanc <contact@leblanc-simon.eu>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: RicSchonfelder <ricschonfelder@icloud.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: 才倾梦华V <185041488+CQMHV@users.noreply.github.com>
Co-authored-by: shuiyue-cmyk <291597411+shuiyue-cmyk@users.noreply.github.com>
2026-10-07 22:16:07 -04:00
f0f923b82e i18n: Czech interface language (#68)
* i18n: Czech interface language

Adds Czech (Čeština, code `cs`) next to English and Japanese:
Preferences ▸ Interface language, `ui.set language cs`, `ui.state`
and persisted preferences all accept it.

- i18n: `Language::Cs`; `tr()` picks the language's table with a match
  (English has none), panic-free. The CZECH table (83 entries) covers
  every label passed to `.tr("…")` (main menu, View zoom/theme/side-panel
  entries, Preferences dialog), every registered File/Edit/Pages/View/Help
  command shown by `registry_menu`, and every key of the Japanese table.
  Written clean-room from the English meaning, not from any Acrobat
  localisation.
- Tests: Czech covers every registered menu title and label, every
  `.tr("…")` literal found by scanning the crate's sources, and the
  Japanese keys; nothing is left identical except an explicit KEEP_AS_IS
  list ("OK"); ellipses match the source; keys are unique per language;
  `cs` round-trips through set_option, ui.set/ui.state and persistence.
- theme: the font setup is split into `font_definitions()`, and a test
  checks with skrifa (dev-dependency, already in the tree via egui) that
  Inter Regular/Medium/SemiBold and JetBrains Mono draw all Czech letters
  and every Czech translation, so nothing falls back to Shippori Mincho.
- The `language` error lists `cs`; docs/localization.md, the parity note
  for misc.prefs-language and the ROADMAP log mention Czech.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* M14: translation catalogs, same system as PhotoCraft

Move the interface translations to PhotoCraft's i18n system: one TSV
catalog per language (crates/ui-egui/src/i18n/ja.tsv), the tl! macro,
entries keyed by command id, context or plural forms, and catalog tests
(format, duplicates, placeholders, command ids).

The 49 existing Japanese strings move over unchanged, plus "Auto". The
language preference now defaults to "auto" and follows the system
language (English when it has no catalog); "en" and "ja" still persist
and unknown values are rejected.

Update docs/localization.md, ROADMAP.md and the misc.prefs-language
parity entry.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* i18n: add Brazilian Portuguese (pt-br) UI translation

Adds Language::PtBr (code pt-br, endonym Português (Brasil)) with serde rename so it persists as "pt-br", registers it in Language::ALL (Preferences ▸ Interface language and ui.set/ui.state) and translates the same 49 menu/command keys as the Japanese table. Extends the i18n tests (table parity, codes, persistence) and updates docs/localization.md.

* M14: strict catalog validation, one-pass fmt, translation assets

Fold in the infrastructure parts of #175:
- `fmt` fills placeholders in one pass, so inserted values (a file name
  containing `{n}`) are never substituted again.
- Catalog validation rejects unknown escapes, unknown `@` contexts,
  placeholder, ellipsis and plural-form mismatches and duplicates. The
  bundled catalogs must have no errors (tests); at run time a bad line is
  still only skipped and logged, so the rest of the catalog loads.
- `.tsv` files count as assets in `cargo xtask assets`, with a
  `translation` kind that may never come from Adobe; ja.tsv gets its
  ATTRIBUTION.toml entry.
- Control-channel test: switching the language keeps documents, their
  dirty state and command ids.

Also make the drawing language thread-local, as in PhotoCraft, so
parallel kittest harnesses can't change each other's language.

Co-Authored-By: 才倾梦华V <185041488+CQMHV@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: Brazilian Portuguese as a TSV catalog

Move #165's Portuguese table into crates/ui-egui/src/i18n/pt-br.tsv
(same 49 strings, plus Auto) and register it in LANGUAGES with
PhotoCraft's Portuguese plural rule (0 and 1 singular). Any Portuguese
locale (pt_BR, pt_PT, pt) follows the Brazilian catalog, as in
PhotoCraft. The catalog is an attributed asset (ATTRIBUTION.toml), and
the docs and parity notes list the new code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: Czech as a TSV catalog

Move #68's Czech table into crates/ui-egui/src/i18n/cs.tsv (PrintCraft
labels renamed PdfCraft, plus Auto) and register it with PhotoCraft's
Czech plural rule (one / few / other). #68's tests become catalog
tests: Czech covers every registered menu title and menu command label,
keeps ellipses, uses no three-dot ellipsis or stray whitespace, and only
leaves "OK" untranslated; the code persists and `cz` is rejected. The
source-scanning `.tr("…")` test is dropped: strings now go through tl!
and the catalog tests check consistency.

The font-coverage test moves to tests/fonts.rs and covers both Latin
catalogs (cs, pt-br) against Inter and JetBrains Mono. It keeps skrifa
as a dev-dependency (the version pdfcraft-fonts already uses): egui's
has_glyphs can't answer it, since a family with only the primary face
also uses that face as its replacement face.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Simon Leblanc <contact@leblanc-simon.eu>
Co-authored-by: RicSchonfelder <ricschonfelder@icloud.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: 才倾梦华V <185041488+CQMHV@users.noreply.github.com>
2026-10-07 22:15:39 -04:00
41734376be i18n: add Brazilian Portuguese (pt-br) UI translation (#165)
* M14: translation catalogs, same system as PhotoCraft

Move the interface translations to PhotoCraft's i18n system: one TSV
catalog per language (crates/ui-egui/src/i18n/ja.tsv), the tl! macro,
entries keyed by command id, context or plural forms, and catalog tests
(format, duplicates, placeholders, command ids).

The 49 existing Japanese strings move over unchanged, plus "Auto". The
language preference now defaults to "auto" and follows the system
language (English when it has no catalog); "en" and "ja" still persist
and unknown values are rejected.

Update docs/localization.md, ROADMAP.md and the misc.prefs-language
parity entry.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* i18n: add Brazilian Portuguese (pt-br) UI translation

Adds Language::PtBr (code pt-br, endonym Português (Brasil)) with serde rename so it persists as "pt-br", registers it in Language::ALL (Preferences ▸ Interface language and ui.set/ui.state) and translates the same 49 menu/command keys as the Japanese table. Extends the i18n tests (table parity, codes, persistence) and updates docs/localization.md.

* M14: strict catalog validation, one-pass fmt, translation assets

Fold in the infrastructure parts of #175:
- `fmt` fills placeholders in one pass, so inserted values (a file name
  containing `{n}`) are never substituted again.
- Catalog validation rejects unknown escapes, unknown `@` contexts,
  placeholder, ellipsis and plural-form mismatches and duplicates. The
  bundled catalogs must have no errors (tests); at run time a bad line is
  still only skipped and logged, so the rest of the catalog loads.
- `.tsv` files count as assets in `cargo xtask assets`, with a
  `translation` kind that may never come from Adobe; ja.tsv gets its
  ATTRIBUTION.toml entry.
- Control-channel test: switching the language keeps documents, their
  dirty state and command ids.

Also make the drawing language thread-local, as in PhotoCraft, so
parallel kittest harnesses can't change each other's language.

Co-Authored-By: 才倾梦华V <185041488+CQMHV@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M14: Brazilian Portuguese as a TSV catalog

Move #165's Portuguese table into crates/ui-egui/src/i18n/pt-br.tsv
(same 49 strings, plus Auto) and register it in LANGUAGES with
PhotoCraft's Portuguese plural rule (0 and 1 singular). Any Portuguese
locale (pt_BR, pt_PT, pt) follows the Brazilian catalog, as in
PhotoCraft. The catalog is an attributed asset (ATTRIBUTION.toml), and
the docs and parity notes list the new code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Simon Leblanc <contact@leblanc-simon.eu>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: 才倾梦华V <185041488+CQMHV@users.noreply.github.com>
2026-10-07 22:15:26 -04:00
a07243c8ff M14: translation catalogs, same system as PhotoCraft (#106)
* M14: translation catalogs, same system as PhotoCraft

Move the interface translations to PhotoCraft's i18n system: one TSV
catalog per language (crates/ui-egui/src/i18n/ja.tsv), the tl! macro,
entries keyed by command id, context or plural forms, and catalog tests
(format, duplicates, placeholders, command ids).

The 49 existing Japanese strings move over unchanged, plus "Auto". The
language preference now defaults to "auto" and follows the system
language (English when it has no catalog); "en" and "ja" still persist
and unknown values are rejected.

Update docs/localization.md, ROADMAP.md and the misc.prefs-language
parity entry.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* M14: strict catalog validation, one-pass fmt, translation assets

Fold in the infrastructure parts of #175:
- `fmt` fills placeholders in one pass, so inserted values (a file name
  containing `{n}`) are never substituted again.
- Catalog validation rejects unknown escapes, unknown `@` contexts,
  placeholder, ellipsis and plural-form mismatches and duplicates. The
  bundled catalogs must have no errors (tests); at run time a bad line is
  still only skipped and logged, so the rest of the catalog loads.
- `.tsv` files count as assets in `cargo xtask assets`, with a
  `translation` kind that may never come from Adobe; ja.tsv gets its
  ATTRIBUTION.toml entry.
- Control-channel test: switching the language keeps documents, their
  dirty state and command ids.

Also make the drawing language thread-local, as in PhotoCraft, so
parallel kittest harnesses can't change each other's language.

Co-Authored-By: 才倾梦华V <185041488+CQMHV@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: 才倾梦华V <185041488+CQMHV@users.noreply.github.com>
2026-10-07 22:14:50 -04:00
AyanandBrandon Thomas 1cf0d319e4 M13: exit cleanly when stdout pipe closes (#203)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-07 22:14:30 -04:00
AyanandBrandon Thomas 2f872f7e7d M10.5: add cut-and-stack page order for single-sided printing (#197)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-07 21:38:21 -04:00
9e0fcc1380 #143: Windows MSI desktop shortcut checkbox, Start Menu fix and install-complete dialog (#183)
* #143: Windows MSI desktop shortcut checkbox and install-complete dialog

Add native installer dialogs (installer-ui.wxs): a welcome screen with a
"Create a desktop shortcut" checkbox (ticked by default), repair/remove,
progress, and "Setup completed successfully" / failed / cancelled screens
with Finish. Unattended /qn and /qb installs never wait on a dialog and can
skip the desktop shortcut with INSTALLDESKTOPSHORTCUT=0.

Start Menu and desktop shortcuts are now plain links to pdfcraft.exe in
their own components (HKLM key paths, removed on uninstall) instead of
advertised MSI shortcuts.

test-msi.ps1 checks the compiled MSI's shortcut, checkbox and dialog tables
during packaging; the ARM64 install smoke test checks both shortcut
targets, their removal on uninstall, and the INSTALLDESKTOPSHORTCUT=0
opt-out.

Co-authored-by: ChatGPT <noreply@openai.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqiBTPWGWbhQDYNFcxFte6

* #143: run test-msi out of process before signing; add files-in-use dialog

test-msi.ps1 held the MSI open through a Windows Installer COM handle in
package.ps1's own process, so signtool could fail on signed release builds.
Run it in a child process and release the COM objects.

The hand-authored UI had no MsiRMFilesInUse dialog, so an upgrade or repair
while PdfCraft is running could not offer to close it. Add one (OK closes the
programs with MSIRMSHUTDOWN=2, Cancel stops setup) and check for it in
test-msi.ps1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqiBTPWGWbhQDYNFcxFte6

---------

Co-authored-by: ChatGPT <noreply@openai.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-07 21:38:02 -04:00
89896af68b Fix saved signature replacement and long-name clipping (#163) (#178)
* #163: allow replacing saved signatures and render long names fully

Add saved signature and initials previews with change/remove/add controls in
Fill & Sign. Preserve placed annotations and saved values on cancellation.
Use bounded line outlines for long names and fit typed placements to 150 pt.

Co-authored-by: Codex <noreply@openai.com>

* cargo fmt after the rename

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:37:28 -04:00
54df6b933e Persist default workspace mode for newly opened PDFs (#172)
* M14: persist the default PDF workspace mode

Keep the saved workspace preference separate from current mode and explicit session overrides. Preserve CLI ordering and PDF Initial View behavior, and cover persistence, Preferences, and control-channel use.

Co-authored-by: Codex <noreply@openai.com>

* Opening a PDF keeps a closed left panel and an unchanged workspace's tool panel

The default workspace is applied only when it differs from the current mode, and never
reopens a left panel the user or `--left closed` closed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: James B. Gower <gowerblake2012@gmail.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:36:47 -04:00
5387c346a5 M3: Add middle-click autoscroll on Linux (#111)
* M3: add middle-click autoscroll

Co-Authored-By: Codex <noreply@openai.com>

* M3: keep middle-click autoscroll toggled after release

Keep scrolling enabled after releasing the wheel, including when the
pointer moves before release. Anchor speed to the initial press event,
so movement later in the same frame cannot shift the starting point.

Cover toggle behavior and increasing speed with distance in both views.

Co-Authored-By: Codex <noreply@openai.com>

* M3: increase middle-click autoscroll speed

Double scrolling speed at the same pointer displacement and raise the
speed cap proportionally, preserving the dead zone and click toggle.
Keep the sustained-scroll fixture visible at the faster response.

Co-Authored-By: Codex <noreply@openai.com>

* M3: match Chromium middle-click scrolling

Use a 15-point dead zone and Chromium's nonlinear distance-to-speed curve
in the document viewer and Organize Pages. Request continuous redraws so
scrolling follows elapsed frame time and preserves fractional movement.
Keep click toggling, cancellation, and the existing marker unchanged.

Cover reference speeds, pathological inputs, pause/resume, and consistent
travel at 30/60/120/144 fps with different display scales and document zoom.

Co-Authored-By: Codex <noreply@openai.com>

* M3: leave README unchanged in autoscroll PR

Remove the feature bullet so README matches upstream main. Keep the
feature explanation in the pull request description.

Co-Authored-By: Codex <noreply@openai.com>

* M3: limit custom middle-click scrolling to Linux

Return before handling input on other targets so their existing
middle-button behavior, widgets, cursor, and Escape shortcuts stay intact.
Restrict the autoscroll UI regressions to Linux and add unsupported-platform
input coverage plus a non-Linux UI regression for the native CI matrix.

Co-Authored-By: Codex <noreply@openai.com>

* ROADMAP: drop the log line about merging the rename

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:16:26 -04:00
4454af3742 Select all pages with Ctrl+A in Organize Pages (#113)
* M4: select all pages in Organize with Ctrl+A

Route Select all to the page grid in Organize while preserving viewer text
selection and keyboard ownership for text inputs, dialogs and the palette.
Keep the current page as the selection anchor for subsequent range selection.

Co-Authored-By: Codex <noreply@openai.com>

* Use the pdfcraft crate names after the rename

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:14:41 -04:00
a2d9a9480c M1: validate object-number ranges before reading cross references (#92)
Reject invalid xref ranges before arithmetic or narrowing casts, allowing the existing reconstruction path to preserve intact objects and record the repair reason. Cover both tables and streams through Document::open.

Co-authored-by: storybored379 <storybored379@users.noreply.github.com>
Co-authored-by: OpenAI Codex <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-07 21:12:41 -04:00
Brandon ThomasandClaude Opus 5.5 d3db99818f Rename PrintCraft to PdfCraft (#174)
The app, crates, binaries, bundle id, packaging, icons, screenshots and docs are now
PdfCraft / pdfcraft (repo storytold/pdfcraft). On first launch the desktop app moves the
PrintCraft settings and crash-recovery folders to the new name, and both apps read settings
saved under the old storage key, so upgrades keep recent files, preferences and unsaved work.
The signing test fixtures keep their PrintCraft subject names (they are binary).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 16:03:57 -04:00
bflatasticandClaude Opus 5.5 5e74f95017 Docs: the automation README describes the tools and MCP resources that ship (#97)
Its Status line said 38 tools and listed form authoring, redaction tools and MCP page-image resources as planned; 123 tools and all three ship. It now names the areas the tools cover and points to printcraft-cli tools for the current list instead of a count that goes stale, and the MCP section lists the resources/* methods and resource templates. ROADMAP's M13 row said 91 tools.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 09:43:26 +07:00
bflatasticandClaude Opus 5.5 de3ab3e087 ROADMAP: session 15 log
The session's log line: issues #70, #72, #73, #74 and #76 fixed, and
#79, #80 and #81 noted as open. The parity tables are refreshed from
`cargo xtask parity` (805 features, 50.2% shipped, 53.7% weighted),
with the by-area shares and the 0.2.1 release. Docs only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 02:18:04 +07:00
Brandon ThomasandClaude Opus 5.5 282a12cc89 ROADMAP: session 14 log
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 14:56:31 -04:00
Brandon ThomasandClaude Opus 5.5 8703172692 ROADMAP: log session 13's later work (FreeBSD, fuzzing fixes, community PRs, Windows crash)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 18:24:32 -04:00
c9d6d39071 Add persisted English/Japanese interface language (#47)
* i18n: add persisted English and Japanese interface language

* ROADMAP: the language entry goes at the top of the log, dated

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: midasdf <205497066+midasdf@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 17:10:09 -04:00
Brandon ThomasandClaude Opus 5.5 f97684f0d8 Docs: honest parity assessment, gap list and direction (ROADMAP, README, CLAUDE.md)
ROADMAP gains an honest assessment by dimension (features, effort,
foundations, robustness, fidelity, product readiness) and by area, what
'shipped' does and doesn't mean, and a ranked list of where we're lacking
and where we're going. Numbers refreshed (804 features, 49.5% shipped,
effort ≈ 30–35%). README's stale 'What's next' becomes an honest status
summary; CLAUDE.md points every agent session at both sections.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 06:19:06 -04:00
Brandon ThomasandClaude Opus 5.5 2f248974ae M13: ROADMAP: session 12 later progress (compare, actions, PDF/A, Office export, forms)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 09:46:13 -04:00
Brandon ThomasandClaude Opus 5.5 9321864393 M13: ROADMAP: session 12 progress (OCR, JavaScript, in-place editing)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 04:42:32 -04:00
Brandon ThomasandClaude Opus 5.5 dab27f098c Roadmap: measured parity (45% of features, ≈35% of effort) and revised Opus 5.5 hour estimate (≈600–1,100 h remaining)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 00:30:22 -04:00
Brandon ThomasandClaude Opus 5.5 183eda77ca M9: Roadmap log
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 07:55:20 -04:00
Brandon ThomasandClaude Opus 5.5 9ba951dd93 M12: Roadmap log for session 11
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 05:06:57 -04:00
Brandon ThomasandClaude Opus 5.5 fe46d6fa3a M3/M4: Roadmap log
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 04:00:22 -04:00
Brandon ThomasandClaude Opus 5.5 65c3f84ea8 M11: Roadmap and status (≈ 27%)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 03:33:18 -04:00
Brandon ThomasandClaude Opus 5.5 dee7bef0ea M9: Roadmap and status (≈ 26%)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 03:00:04 -04:00
Brandon ThomasandClaude Opus 5.5 18b0532e61 M5: Roadmap and status for session 10 (≈ 23%)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 02:02:39 -04:00
Brandon ThomasandClaude Opus 5.5 a0bd0a85f0 Roadmap: session 9 later arcs (≈ 21%)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 01:18:52 -04:00