From 5c371183c406f2bb32c9c1aa8d7b10b95863a212 Mon Sep 17 00:00:00 2001 From: mtlcl410 <2368091+mtlcl410@users.noreply.github.com> Date: Sat, 31 Oct 2026 00:37:00 +0800 Subject: [PATCH 1/4] M3: documents that hide the toolbar, menu bar or window controls open that way; FitWindow and CenterWindow, ported onto main A single squashed port of the branch's five commits onto current main, which split ui-egui's lib.rs (app.rs, app/files.rs), canvas.rs (canvas/zoom.rs, canvas/tests.rs) and control.rs (control/host.rs), replaced the Menu button with a menu bar and moved the rail and panels into panels/side_panels.rs. The behaviour and tests are the branch's (ISO 32000-2 Table 147): - HideToolbar, HideMenubar and HideWindowUI apply in the document's tab, and F8 (view.toggle_interface) brings them back; on main the toggle is listed in the View menu beside Full Screen and Read Mode, HideMenubar hides the menu bar, and HideWindowUI skips the side panels; - FitWindow measures the spread the view shows, and FitWindow and CenterWindow wait only while the document is the window's only one; - a reloaded document keeps its tab's hidden interface; one-page-at-a-time layouts open at fit page; - the two strings are in every catalog, fa.tsv (added on main since) too. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Pq7HyCfwzyRXj4VfQAVVdv --- ATTRIBUTION.md | 68 ++--- ATTRIBUTION.toml | 68 ++--- crates/engine/src/commands.rs | 10 + crates/ui-egui/src/app.rs | 16 +- crates/ui-egui/src/app/files.rs | 6 +- crates/ui-egui/src/canvas.rs | 14 +- crates/ui-egui/src/canvas/tests.rs | 29 ++ crates/ui-egui/src/canvas/zoom.rs | 25 ++ crates/ui-egui/src/chrome.rs | 9 +- crates/ui-egui/src/commands.rs | 1 + crates/ui-egui/src/control/host.rs | 1 + crates/ui-egui/src/i18n/ar.tsv | 4 + crates/ui-egui/src/i18n/bg.tsv | 4 + crates/ui-egui/src/i18n/ca.tsv | 4 + crates/ui-egui/src/i18n/ckb.tsv | 4 + crates/ui-egui/src/i18n/cs.tsv | 4 + crates/ui-egui/src/i18n/de.tsv | 4 + crates/ui-egui/src/i18n/el.tsv | 4 + crates/ui-egui/src/i18n/es.tsv | 4 + crates/ui-egui/src/i18n/fa.tsv | 4 + crates/ui-egui/src/i18n/fi.tsv | 4 + crates/ui-egui/src/i18n/fr.tsv | 4 + crates/ui-egui/src/i18n/hi.tsv | 4 + crates/ui-egui/src/i18n/hu.tsv | 4 + crates/ui-egui/src/i18n/id.tsv | 4 + crates/ui-egui/src/i18n/it.tsv | 4 + crates/ui-egui/src/i18n/ja.tsv | 4 + crates/ui-egui/src/i18n/kk.tsv | 4 + crates/ui-egui/src/i18n/ko.tsv | 4 + crates/ui-egui/src/i18n/lo.tsv | 4 + crates/ui-egui/src/i18n/lt.tsv | 4 + crates/ui-egui/src/i18n/nb.tsv | 4 + crates/ui-egui/src/i18n/pl.tsv | 4 + crates/ui-egui/src/i18n/pt-br.tsv | 4 + crates/ui-egui/src/i18n/ro.tsv | 4 + crates/ui-egui/src/i18n/ru.tsv | 4 + crates/ui-egui/src/i18n/sl.tsv | 4 + crates/ui-egui/src/i18n/sq.tsv | 4 + crates/ui-egui/src/i18n/te.tsv | 4 + crates/ui-egui/src/i18n/th.tsv | 4 + crates/ui-egui/src/i18n/tr.tsv | 4 + crates/ui-egui/src/i18n/uk.tsv | 4 + crates/ui-egui/src/i18n/vi.tsv | 4 + crates/ui-egui/src/i18n/zh-hans.tsv | 4 + crates/ui-egui/src/i18n/zh-hant.tsv | 4 + crates/ui-egui/src/lib.rs | 4 + crates/ui-egui/src/menus.rs | 2 +- crates/ui-egui/src/viewer_prefs.rs | 358 ++++++++++++++++++++++++ crates/ui-egui/tests/it/main.rs | 1 + crates/ui-egui/tests/it/viewer_prefs.rs | 335 ++++++++++++++++++++++ parity/acrobat-features.toml | 6 +- 51 files changed, 1009 insertions(+), 80 deletions(-) create mode 100644 crates/ui-egui/src/viewer_prefs.rs create mode 100644 crates/ui-egui/tests/it/viewer_prefs.rs diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md index 23ebcbbe82..1d65771bf1 100644 --- a/ATTRIBUTION.md +++ b/ATTRIBUTION.md @@ -8,34 +8,34 @@ Every asset PdfCraft includes, bundles or uses to build its published material, | Asset | Title | Author | Licence | Source | Used for | |---|---|---|---|---|---| -| `crates/ui-egui/src/i18n/el.tsv` | Greek interface translation catalog | Camthalion77 and contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft English UI labels; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Greek UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/zh-hans.tsv` | Simplified Chinese interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Simplified Chinese UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/zh-hant.tsv` | Traditional Chinese (Taiwan) interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Traditional Chinese UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/cs.tsv` | Czech interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check and standard-identification wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Czech UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/pt-br.tsv` | Brazilian Portuguese interface translation catalog | André Cardoso (andrecards), PdfCraft contributors | MIT OR Apache-2.0 | Clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources: the ~1,826-entry gist posted in issue #288 (https://gist.github.com/andrecards/ac388c25fba17312ce83207f8b7b467e), completed and reviewed by PdfCraft contributors; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table limit messages are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Brazilian Portuguese UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/es.tsv` | Spanish interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; the 2026-10-20 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Spanish UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/fr.tsv` | French interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | French UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/de.tsv` | German interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | German UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/lo.tsv` | Lao interface translation catalog | @bounkirdni-2025 | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Lao UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/te.tsv` | Telugu interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Telugu UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/it.tsv` | Italian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Italian UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/pl.tsv` | Polish interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Polish UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/ru.tsv` | Russian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Russian UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/hu.tsv` | Hungarian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Hungarian UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/bg.tsv` | Bulgarian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Bulgarian UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/kk.tsv` | Kazakh interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of the English UI labels into Kazakh, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Kazakh UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/ja.tsv` | Japanese interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Japanese UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/uk.tsv` | Ukrainian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Ukrainian UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/ar.tsv` | Arabic interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Arabic UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/ckb.tsv` | Central Kurdish (Sorani) interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Central Kurdish UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/fa.tsv` | Persian (Farsi) interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-25 initial catalog covering the current 2,776-entry key union, AI-assisted translations from English, not separately native-reviewed | Persian UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/tr.tsv` | Turkish interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Turkish UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/lt.tsv` | Lithuanian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels and user-facing messages; original catalog reviewed by a native Lithuanian-speaking contributor; 2026-10-15 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Lithuanian UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/hi.tsv` | Hindi interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Hindi UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/id.tsv` | Indonesian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Indonesian UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/ko.tsv` | Korean interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Korean UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/ro.tsv` | Romanian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels and user-facing messages; AI-assisted and not yet reviewed line by line by a native Romanian speaker; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Romanian UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/fi.tsv` | Finnish interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: AI-assisted (Claude Code) clean-room translations of PdfCraft's English UI labels and user-facing messages; not yet proofread by a native Finnish speaker; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 calculation-order, text-format, print, thumbnail, layer, comment-reshape and signature labels (previously English placeholders) are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Finnish UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/el.tsv` | Greek interface translation catalog | Camthalion77 and contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft English UI labels; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Greek UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/zh-hans.tsv` | Simplified Chinese interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Simplified Chinese UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/zh-hant.tsv` | Traditional Chinese (Taiwan) interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, reviewed by a native speaker | Traditional Chinese UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/cs.tsv` | Czech interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check and standard-identification wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Czech UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/pt-br.tsv` | Brazilian Portuguese interface translation catalog | André Cardoso (andrecards), PdfCraft contributors | MIT OR Apache-2.0 | Clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources: the ~1,826-entry gist posted in issue #288 (https://gist.github.com/andrecards/ac388c25fba17312ce83207f8b7b467e), completed and reviewed by PdfCraft contributors; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table limit messages are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Brazilian Portuguese UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/es.tsv` | Spanish interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; the 2026-10-20 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Spanish UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/fr.tsv` | French interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | French UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/de.tsv` | German interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | German UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/lo.tsv` | Lao interface translation catalog | @bounkirdni-2025 | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Lao UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/te.tsv` | Telugu interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Telugu UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/it.tsv` | Italian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Italian UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/pl.tsv` | Polish interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Polish UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/ru.tsv` | Russian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Russian UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/hu.tsv` | Hungarian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Hungarian UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/bg.tsv` | Bulgarian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Bulgarian UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/kk.tsv` | Kazakh interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of the English UI labels into Kazakh, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Kazakh UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/ja.tsv` | Japanese interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Japanese UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/uk.tsv` | Ukrainian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Ukrainian UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/ar.tsv` | Arabic interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Arabic UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/ckb.tsv` | Central Kurdish (Sorani) interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Central Kurdish UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/fa.tsv` | Persian (Farsi) interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-25 initial catalog covering the current 2,776-entry key union, AI-assisted translations from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Persian UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/tr.tsv` | Turkish interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Turkish UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/lt.tsv` | Lithuanian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels and user-facing messages; original catalog reviewed by a native Lithuanian-speaking contributor; 2026-10-15 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Lithuanian UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/hi.tsv` | Hindi interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Hindi UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/id.tsv` | Indonesian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Indonesian UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/ko.tsv` | Korean interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Korean UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/ro.tsv` | Romanian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels and user-facing messages; AI-assisted and not yet reviewed line by line by a native Romanian speaker; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Romanian UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/fi.tsv` | Finnish interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: AI-assisted (Claude Code) clean-room translations of PdfCraft's English UI labels and user-facing messages; not yet proofread by a native Finnish speaker; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 calculation-order, text-format, print, thumbnail, layer, comment-reshape and signature labels (previously English placeholders) are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Finnish UI strings, compiled in by crates/ui-egui/src/i18n.rs | | `assets/icons/accessibility.svg` | Lucide icon "accessibility" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/accessibility.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs | | `assets/icons/align-left.svg` | Lucide icon "align-left" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/align-left.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs | | `assets/icons/align-center.svg` | Lucide icon "align-center" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/align-center.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs | @@ -286,17 +286,17 @@ Every asset PdfCraft includes, bundles or uses to build its published material, | `packaging/macos/dmg/background.tiff` | PdfCraft macOS DMG window background (rendered) | @XusBadia | MIT OR Apache-2.0 | Rendered from packaging/macos/dmg/background.svg by packaging/macos/dmg/generate.py | 1x + 2x HiDPI 16-colour palette TIFF copied into the macOS DMG by packaging/macos/package.sh; includes the app icon and the free LittleCMS built-in sRGB profile | | `crates/sign/tests/data/x509-rsa-sha1.pdf` | One-page PDF with a legacy adbe.x509.rsa_sha1 signature by the RSA test key | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: hand-written PDF objects; signature made with `openssl dgst -sha1 -sign` over its byte ranges (see crates/sign/tests/data/README.md) | Signature validation tests (crates/sign/tests/it/pdf.rs): the legacy adbe.x509.rsa_sha1 format | | `assets/icons/monitor.svg` | Lucide icon "monitor" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/monitor.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs | -| `crates/ui-egui/src/i18n/vi.tsv` | Vietnamese interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels; PhotoCraft and VectorCraft Vietnamese catalogs used only as translation memory when English source and semantic context matched; original catalog reviewed by a native Vietnamese-speaking contributor; 2026-10-15 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Vietnamese UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/sl.tsv` | Slovene interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Slovene UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/vi.tsv` | Vietnamese interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels; PhotoCraft and VectorCraft Vietnamese catalogs used only as translation memory when English source and semantic context matched; original catalog reviewed by a native Vietnamese-speaking contributor; 2026-10-15 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Vietnamese UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/sl.tsv` | Slovene interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Slovene UI strings, compiled in by crates/ui-egui/src/i18n.rs | | `vendor/vello_common/assets/probe.png` | vello_common probe reference image (rendered from probe.rgba) | Linebender vello contributors | MIT OR Apache-2.0 | vello_common 0.0.8 (crates.io), vendored in vendor/vello_common; regenerated by its vello_sparse_tests regenerate_probe_reference binary | Reference picture of the vendored vello_common probe module, for people only; the build reads probe.rgba, not this file | -| `crates/ui-egui/src/i18n/nb.tsv` | Norwegian Bokmål interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Norwegian Bokmål UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/nb.tsv` | Norwegian Bokmål interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Norwegian Bokmål UI strings, compiled in by crates/ui-egui/src/i18n.rs | | `assets/icons/superscript.svg` | Lucide icon "superscript" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/superscript.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs | | `assets/icons/subscript.svg` | Lucide icon "subscript" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/subscript.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs | | `assets/icons/pilcrow.svg` | Lucide icon "pilcrow" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/pilcrow.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs | | `assets/icons/move-horizontal.svg` | Lucide icon "move-horizontal" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/move-horizontal.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs | -| `crates/ui-egui/src/i18n/sq.tsv` | Albanian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-appearance labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Albanian UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/th.tsv` | Thai interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Thai UI strings, compiled in by crates/ui-egui/src/i18n.rs | -| `crates/ui-egui/src/i18n/ca.tsv` | Catalan interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, written from their meaning; no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Catalan UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/sq.tsv` | Albanian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-appearance labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Albanian UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/th.tsv` | Thai interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Thai UI strings, compiled in by crates/ui-egui/src/i18n.rs | +| `crates/ui-egui/src/i18n/ca.tsv` | Catalan interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, written from their meaning; no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed | Catalan UI strings, compiled in by crates/ui-egui/src/i18n.rs | ## Compiled in through dependencies (6) diff --git a/ATTRIBUTION.toml b/ATTRIBUTION.toml index 7dcd882f84..685b4463f9 100644 --- a/ATTRIBUTION.toml +++ b/ATTRIBUTION.toml @@ -2,7 +2,7 @@ path = "crates/ui-egui/src/i18n/el.tsv" title = "Greek interface translation catalog" author = "Camthalion77 and contributors" -source = "Contributor-original: clean-room translations of PdfCraft English UI labels; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft English UI labels; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -26,7 +26,7 @@ usage = "Greek UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/zh-hans.tsv" title = "Simplified Chinese interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -36,7 +36,7 @@ usage = "Simplified Chinese UI strings, compiled in by crates/ui-egui/src/i18n.r path = "crates/ui-egui/src/i18n/zh-hant.tsv" title = "Traditional Chinese (Taiwan) interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, reviewed by a native speaker" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -46,7 +46,7 @@ usage = "Traditional Chinese UI strings, compiled in by crates/ui-egui/src/i18n. path = "crates/ui-egui/src/i18n/cs.tsv" title = "Czech interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check and standard-identification wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check and standard-identification wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -56,7 +56,7 @@ usage = "Czech UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/pt-br.tsv" title = "Brazilian Portuguese interface translation catalog" author = "André Cardoso (andrecards), PdfCraft contributors" -source = "Clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources: the ~1,826-entry gist posted in issue #288 (https://gist.github.com/andrecards/ac388c25fba17312ce83207f8b7b467e), completed and reviewed by PdfCraft contributors; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table limit messages are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources: the ~1,826-entry gist posted in issue #288 (https://gist.github.com/andrecards/ac388c25fba17312ce83207f8b7b467e), completed and reviewed by PdfCraft contributors; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table limit messages are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -66,7 +66,7 @@ usage = "Brazilian Portuguese UI strings, compiled in by crates/ui-egui/src/i18n path = "crates/ui-egui/src/i18n/es.tsv" title = "Spanish interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; the 2026-10-20 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; the 2026-10-20 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -76,7 +76,7 @@ usage = "Spanish UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/fr.tsv" title = "French interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -86,7 +86,7 @@ usage = "French UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/de.tsv" title = "German interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -96,7 +96,7 @@ usage = "German UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/lo.tsv" title = "Lao interface translation catalog" author = "@bounkirdni-2025" -source = "Contributor-original: clean-room translations of PdfCraft English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -106,7 +106,7 @@ usage = "Lao UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/te.tsv" title = "Telugu interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -116,7 +116,7 @@ usage = "Telugu UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/it.tsv" title = "Italian interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -126,7 +126,7 @@ usage = "Italian UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/pl.tsv" title = "Polish interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -136,7 +136,7 @@ usage = "Polish UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/ru.tsv" title = "Russian interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -146,7 +146,7 @@ usage = "Russian UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/hu.tsv" title = "Hungarian interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -156,7 +156,7 @@ usage = "Hungarian UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/bg.tsv" title = "Bulgarian interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -166,7 +166,7 @@ usage = "Bulgarian UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/kk.tsv" title = "Kazakh interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of the English UI labels into Kazakh, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of the English UI labels into Kazakh, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -176,7 +176,7 @@ usage = "Kazakh UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/ja.tsv" title = "Japanese interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -186,7 +186,7 @@ usage = "Japanese UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/uk.tsv" title = "Ukrainian interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -196,7 +196,7 @@ usage = "Ukrainian UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/ar.tsv" title = "Arabic interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -206,7 +206,7 @@ usage = "Arabic UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/ckb.tsv" title = "Central Kurdish (Sorani) interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -216,7 +216,7 @@ usage = "Central Kurdish UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/fa.tsv" title = "Persian (Farsi) interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-25 initial catalog covering the current 2,776-entry key union, AI-assisted translations from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-25 initial catalog covering the current 2,776-entry key union, AI-assisted translations from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -226,7 +226,7 @@ usage = "Persian UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/tr.tsv" title = "Turkish interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -236,7 +236,7 @@ usage = "Turkish UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/lt.tsv" title = "Lithuanian interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels and user-facing messages; original catalog reviewed by a native Lithuanian-speaking contributor; 2026-10-15 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels and user-facing messages; original catalog reviewed by a native Lithuanian-speaking contributor; 2026-10-15 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -246,7 +246,7 @@ usage = "Lithuanian UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/hi.tsv" title = "Hindi interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -255,7 +255,7 @@ usage = "Hindi UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/id.tsv" title = "Indonesian interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -264,7 +264,7 @@ usage = "Indonesian UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/ko.tsv" title = "Korean interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -274,7 +274,7 @@ usage = "Korean UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/ro.tsv" title = "Romanian interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels and user-facing messages; AI-assisted and not yet reviewed line by line by a native Romanian speaker; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels and user-facing messages; AI-assisted and not yet reviewed line by line by a native Romanian speaker; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -285,7 +285,7 @@ usage = "Romanian UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/fi.tsv" title = "Finnish interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: AI-assisted (Claude Code) clean-room translations of PdfCraft's English UI labels and user-facing messages; not yet proofread by a native Finnish speaker; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 calculation-order, text-format, print, thumbnail, layer, comment-reshape and signature labels (previously English placeholders) are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: AI-assisted (Claude Code) clean-room translations of PdfCraft's English UI labels and user-facing messages; not yet proofread by a native Finnish speaker; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 calculation-order, text-format, print, thumbnail, layer, comment-reshape and signature labels (previously English placeholders) are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -3418,7 +3418,7 @@ sha256 = "d1a443233345724859de8e4fb48968ba91e885e12ddbd710701548bd91b39428" path = "crates/ui-egui/src/i18n/vi.tsv" title = "Vietnamese interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels; PhotoCraft and VectorCraft Vietnamese catalogs used only as translation memory when English source and semantic context matched; original catalog reviewed by a native Vietnamese-speaking contributor; 2026-10-15 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels; PhotoCraft and VectorCraft Vietnamese catalogs used only as translation memory when English source and semantic context matched; original catalog reviewed by a native Vietnamese-speaking contributor; 2026-10-15 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -3428,7 +3428,7 @@ usage = "Vietnamese UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/sl.tsv" title = "Slovene interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -3450,7 +3450,7 @@ sha256 = "78c59a0cfd2c829909d77006f94e34dac1ae5d1f90e7f10f72e84de541fef697" path = "crates/ui-egui/src/i18n/nb.tsv" title = "Norwegian Bokmål interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -3504,7 +3504,7 @@ sha256 = "864ab2f19254e6ac7240bc6a98323197332e8f714d4d3f94831f41309e5ef2f7" path = "crates/ui-egui/src/i18n/sq.tsv" title = "Albanian interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-appearance labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-appearance labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -3514,7 +3514,7 @@ usage = "Albanian UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/th.tsv" title = "Thai interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" @@ -3524,7 +3524,7 @@ usage = "Thai UI strings, compiled in by crates/ui-egui/src/i18n.rs" path = "crates/ui-egui/src/i18n/ca.tsv" title = "Catalan interface translation catalog" author = "PdfCraft contributors" -source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, written from their meaning; no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed" +source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, written from their meaning; no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed; the 2026-10-25 hidden toolbars-and-panels labels are AI-assisted translations from English, not separately native-reviewed" licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" diff --git a/crates/engine/src/commands.rs b/crates/engine/src/commands.rs index 6bfe9fa826..35538e173f 100644 --- a/crates/engine/src/commands.rs +++ b/crates/engine/src/commands.rs @@ -222,6 +222,16 @@ pub const COMMANDS: &[CommandSpec] = &[ c("edit.snapshot", "Take a snapshot", EDIT, None, Copying, "camera"), c("view.full_screen", "Full screen mode", VIEW, Some(Shortcut::cmd("L")), Document, "maximize"), c("view.read_mode", "Read mode", VIEW, Some(Shortcut { command: true, shift: false, mac_ctrl: true, key: "H" }), Document, "book-open"), + // A document can hide the toolbars, menu and panels (ISO 32000-2 Table 147); this brings them + // back for its tab, and with nothing hidden hides them. + c( + "view.toggle_interface", + "Show or hide toolbars and panels", + VIEW, + Some(Shortcut { command: false, shift: false, mac_ctrl: false, key: "F8" }), + Document, + "panel-left", + ), // Browsers' tab keys (#1542): Ctrl+Tab on every platform, ⌃Tab rather than ⌘Tab on macOS, // where the system takes ⌘Tab. They follow the tabs' order on screen and wrap around, and // also run from Combine files, which has no document open. diff --git a/crates/ui-egui/src/app.rs b/crates/ui-egui/src/app.rs index 425c2e26ce..b867059332 100644 --- a/crates/ui-egui/src/app.rs +++ b/crates/ui-egui/src/app.rs @@ -253,6 +253,7 @@ impl PdfCraftApp { community_card_closed: false, pending_link: None, pending_full_screen: None, + pending_window: None, pending_remote_link: None, protect_draft: Default::default(), text_style_draft: Default::default(), @@ -611,15 +612,22 @@ impl eframe::App for PdfCraftApp { window_controls::resize_edges(&ctx); } chrome::tab_strip(self, ui); - chrome::mode_bar(self, ui); + // A document can hide the toolbars, the menu and the panels around it in its tab (ISO + // 32000-2 Table 147); the tab strip stays, and F8 brings the rest back (`viewer_prefs`). + let hidden = self.hidden_interface(); + if !hidden.mode_bar() { + chrome::mode_bar(self, ui); + } // Whichever way another tab came to the front, it shows instead of the expanded view. if self.all_tools_full && self.all_tools_tab != self.shown_tab() { self.all_tools_full = false; } - side_panels::show(self, ui); + if !hidden.window_ui { + side_panels::show(self, ui); + } let t = theme::Tokens::get(&ctx); egui::CentralPanel::default().frame(egui::Frame::NONE.fill(t.pasteboard)).show(ui, |ui| { - if self.mode == Mode::AllTools && self.all_tools_full { + if self.mode == Mode::AllTools && self.all_tools_full && !hidden.window_ui { all_tools_ui::show(self, ui); } else { match self.active { @@ -632,6 +640,8 @@ impl eframe::App for PdfCraftApp { } } }); + // FitWindow and CenterWindow, once the document just opened is laid out. + self.window_preferences_frame(&ctx); self.process_pending_edits(); palette::show(self, &ctx); dialogs::show(self, &ctx); diff --git a/crates/ui-egui/src/app/files.rs b/crates/ui-egui/src/app/files.rs index 3c68dc5619..687122e07c 100644 --- a/crates/ui-egui/src/app/files.rs +++ b/crates/ui-egui/src/app/files.rs @@ -284,9 +284,11 @@ impl PdfCraftApp { self.active = Some(self.views.len() - 1); } self.apply_initial_view(self.views.len() - 1, &initial); - // Where the reader left off wins over the file's own initial view (#1767). + self.apply_viewer_preferences(self.views.len() - 1, &initial, activate); + // Where the reader left off wins over the file's own initial view and the zoom its + // viewer preferences open at (#1767). self.apply_last_view(self.views.len() - 1); - // After both, so full screen shows one fitted page and leaving it comes back to them. + // After all of them, so full screen shows one fitted page and leaving it comes back to them. if self.full_screen && let Some(view) = self.views.last_mut() { diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index 8b280ba75d..9b244a4933 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -319,6 +319,9 @@ pub struct DocView { pub flash: Option<(usize, [f32; 4], f64)>, /// Compare files: differences shaded on this document's pages (page, user-space box, colour). pub compare_marks: Vec<(usize, [f32; 4], Color32)>, + /// The interface the document hid in this tab, and what is hidden now (ISO 32000-2 Table 147 + /// `HideToolbar`, `HideMenubar`, `HideWindowUI`). Never saved. + pub interface: crate::viewer_prefs::TabInterface, /// Full screen (Acrobat's Full Screen Mode): the display saved on entering it, while the view /// shows one page or spread at a time, fitted to the screen. `None` outside full screen. presentation: Option, @@ -635,6 +638,7 @@ impl DocView { single_edges: None, flash: None, compare_marks: Vec::new(), + interface: Default::default(), presentation: None, pages: HashMap::new(), errors: HashMap::new(), @@ -793,6 +797,8 @@ impl DocView { fresh.snapshot = self.snapshot.clone(); fresh.close_requested = self.close_requested; fresh.cover = self.cover; + // What the document asked to hide, and what is hidden now (F8), belong to the tab. + fresh.interface = self.interface; // Still presenting, with the display to go back to on leaving. fresh.presentation = self.presentation.take(); fresh.back = std::mem::take(&mut self.back); @@ -2619,6 +2625,11 @@ fn page_scroll_area(ui: &egui::Ui, view: &mut DocView, geometry: &ScrollGeometry // Every scroll here asks for no animation. An animated area would still queue a zero-length // offset target for the next frame, which overwrites the jump a page turn just set. scroll = scroll.animated(false); + // A document that hides the window's interface (`HideWindowUI`) hides the scroll bars too; + // the wheel, keys and Hand tool still scroll. + if view.interface.hidden.window_ui { + scroll = scroll.scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::AlwaysHidden); + } // A newly opened document starts at the top. eframe saves egui's memory with the settings // and document ids start again at 1 every launch, so the offset stored under this id can be // where an earlier session left another document. @@ -3478,7 +3489,8 @@ fn apply_frame_requests(app: &mut PdfCraftApp, index: usize, ui: &mut egui::Ui, } // Read mode hides the tools (#2646), and full screen is the page and nothing else (#1459); // the quick tools come back with the window. - if app.mode != crate::Mode::Read && !app.full_screen { + // A document that hides the toolbars (`HideToolbar`) hides this one too. + if app.mode != crate::Mode::Read && !app.full_screen && !app.views.get(index).is_some_and(|v| v.interface.hidden.toolbar) { quick_bar(app, avail, ui); } if let Some((source, file, destination)) = remote_open { diff --git a/crates/ui-egui/src/canvas/tests.rs b/crates/ui-egui/src/canvas/tests.rs index 634a885111..4044f54b08 100644 --- a/crates/ui-egui/src/canvas/tests.rs +++ b/crates/ui-egui/src/canvas/tests.rs @@ -2002,3 +2002,32 @@ fn a_moved_picture_is_drawn_from_the_fresh_raster_while_a_tile_is_still_stale() h.state_mut().views[0].stale_tiles.clear(); h.state_mut().views[0].tiles.clear(); } + +/// Review on #4378: `FitWindow` measures the spread the view shows, its pages side by side +/// and as tall as the taller one, with one page in a spread that has only one. +#[test] +fn first_page_now_measures_the_pages_in_the_spread() { + let page = + |width: f32, height: f32| pdfcraft_render::PageInfo { width, height, label: String::new(), crop: [0.0, 0.0, width, height], rotation: 0 }; + let info = DocInfo { pages: vec![page(300.0, 400.0), page(600.0, 800.0), page(200.0, 500.0)], ..Default::default() }; + let mut v = DocView::new(DocId(1), &info, ViewDefaults::default()); + let one = v.first_page_now(&info).expect("a page"); + assert_eq!((one.size, one.margins.x), (vec2(300.0 * PT, 400.0 * PT), 2.0 * SIDE)); + v.set_display(PageLayout::TwoUp, false); + let gap = v.page_gap(); + // [0, 1]: 300 + 600 wide, 800 high, one gap between them. + let spread = v.first_page_now(&info).expect("a spread"); + assert_eq!((spread.size, spread.margins.x), (vec2(900.0 * PT, 800.0 * PT), 2.0 * SIDE + gap)); + // [2] on its own at the end: one page, no gap. + v.current = 2; + let last = v.first_page_now(&info).expect("the last page"); + assert_eq!((last.size, last.margins.x), (vec2(200.0 * PT, 500.0 * PT), 2.0 * SIDE)); + // With a cover page: [0] alone, then [1, 2]. + v.set_cover(true); + assert_eq!(v.first_page_now(&info).expect("a spread").size, vec2(800.0 * PT, 800.0 * PT)); + v.current = 0; + let cover = v.first_page_now(&info).expect("the cover"); + assert_eq!((cover.size, cover.margins.x), (vec2(300.0 * PT, 400.0 * PT), 2.0 * SIDE)); + v.current = 9; + assert!(v.first_page_now(&info).is_none()); +} diff --git a/crates/ui-egui/src/canvas/zoom.rs b/crates/ui-egui/src/canvas/zoom.rs index 91bc4feac8..c11f9bf7eb 100644 --- a/crates/ui-egui/src/canvas/zoom.rs +++ b/crates/ui-egui/src/canvas/zoom.rs @@ -140,6 +140,31 @@ impl DocView { self.layout == PageLayout::TwoUp } + /// The page (or spread) the view shows first, as `FitWindow` sizes the window to it + /// ([`crate::viewer_prefs::window_commands`]). `None` when there is no such page. + pub(crate) fn first_page_now(&self, info: &DocInfo) -> Option { + info.pages.get(self.current)?; + // Two-page view shows the spread the page is in (a cover page on its own); the spread + // is as wide as its pages side by side and as tall as the taller one, as `layout` + // places it. The last spread of an odd page count has one page. + let (first, last) = if self.layout == PageLayout::TwoUp { + let first = self.spread_first(self.current); + (first, if self.cover && first == 0 { 0 } else { first.saturating_add(1) }) + } else { + (self.current, self.current) + }; + let sizes: Vec<(f32, f32)> = + info.pages.iter().skip(first).take(last.saturating_sub(first).saturating_add(1)).map(|p| self.display_size(p)).collect(); + let w: f32 = sizes.iter().map(|s| s.0).sum(); + let h = sizes.iter().map(|s| s.1).fold(0.0, f32::max); + let gap = self.page_gap() * sizes.len().saturating_sub(1) as f32; + Some(crate::viewer_prefs::PageNow { + size: vec2(w * PT, h * PT), + margins: vec2(2.0 * SIDE + gap, 2.0 * MARGIN), + zoom: (self.fit == Fit::None).then_some(self.zoom), + }) + } + /// Displayed page size in points for this view rotation. pub(super) fn display_size(&self, p: &pdfcraft_render::PageInfo) -> (f32, f32) { if self.rotation % 180 == 90 { (p.height, p.width) } else { (p.width, p.height) } diff --git a/crates/ui-egui/src/chrome.rs b/crates/ui-egui/src/chrome.rs index aa6233c133..61a0435f66 100644 --- a/crates/ui-egui/src/chrome.rs +++ b/crates/ui-egui/src/chrome.rs @@ -479,19 +479,24 @@ fn tab(ui: &mut egui::Ui, spec: TabSpec<'_>, close: &mut Option) -> egui: pub fn mode_bar(app: &mut PdfCraftApp, ui: &mut egui::Ui) { let t = Tokens::get(ui.ctx()); + // The document in the active tab may hide the menu or the tools (`crate::viewer_prefs`). + let hidden = app.hidden_interface(); egui::Panel::top("mode_bar") .exact_size(48.0) .frame(egui::Frame::NONE.fill(t.chrome).inner_margin(egui::Margin::symmetric(10, 0)).stroke(Stroke::new(1.0, t.divider))) .show(ui, |ui| { ui.horizontal_centered(|ui| { ui.spacing_mut().item_spacing.x = 2.0; - // The menus, unless the native macOS menu bar has them. - if app.native_menu.is_none() { + // The menus, unless the native macOS menu bar has them or the document hides them. + if app.native_menu.is_none() && !hidden.menubar { app.menu_bar_ui(ui); ui.add_space(6.0); ui.painter().vline(ui.cursor().left(), ui.max_rect().y_range().shrink(12.0), Stroke::new(1.0, t.divider)); ui.add_space(10.0); } + if hidden.toolbar { + return; + } // Acrobat's mode bar has no Read tab: reading is what the viewer does with no tool // in use. Read mode (the panes hidden) stays a View command and a default workspace. for (mode, label) in [(Mode::AllTools, "All tools"), (Mode::Edit, "Edit"), (Mode::Convert, "Convert"), (Mode::Sign, "E-Sign")] { diff --git a/crates/ui-egui/src/commands.rs b/crates/ui-egui/src/commands.rs index 08d2040e23..dd5edc19d5 100644 --- a/crates/ui-egui/src/commands.rs +++ b/crates/ui-egui/src/commands.rs @@ -319,6 +319,7 @@ impl PdfCraftApp { } } "view.read_mode" => self.switch_mode(if self.mode == Mode::Read { Mode::AllTools } else { Mode::Read }, false), + crate::viewer_prefs::TOGGLE => self.toggle_interface(), "view.previous_view" | "view.next_view" => { if let Some(v) = active.and_then(|i| self.views.get_mut(i)) { return Some(v.view_history(id == "view.next_view")); diff --git a/crates/ui-egui/src/control/host.rs b/crates/ui-egui/src/control/host.rs index 1166c0e7ec..a55699b375 100644 --- a/crates/ui-egui/src/control/host.rs +++ b/crates/ui-egui/src/control/host.rs @@ -137,6 +137,7 @@ impl Host for crate::PdfCraftApp { "left_panel": if self.left_open { json!(format!("{:?}", self.left)) } else { Value::Null }, "tools_side": if self.side_panels.tools_on_right() { "right" } else { "left" }, "right_panel": self.right.map(|r| format!("{r:?}")), + "hidden_interface": self.hidden_interface().to_json(), "dialog": self.dialog.map(|d| format!("{d:?}")), "palette_open": self.palette_open, "theme": format!("{:?}", self.theme), diff --git a/crates/ui-egui/src/i18n/ar.tsv b/crates/ui-egui/src/i18n/ar.tsv index ce5bf387be..19b39149fb 100644 --- a/crates/ui-egui/src/i18n/ar.tsv +++ b/crates/ui-egui/src/i18n/ar.tsv @@ -2859,3 +2859,7 @@ certificate Version الإصدار # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply خيارات هذا الرد Export value قيمة التصدير + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels إظهار أشرطة الأدوات واللوحات أو إخفاؤها + This document hides the toolbars and panels. Press {key} to show them. يُخفي هذا المستند أشرطة الأدوات واللوحات. اضغط {key} لإظهارها. diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index eb37bdd775..8975ca2980 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -2546,3 +2546,7 @@ animation effects Off Изключени # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Опции за този отговор Export value Стойност за експортиране + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Покажи или скрий лентите с инструменти и панелите + This document hides the toolbars and panels. Press {key} to show them. Този документ скрива лентите с инструменти и панелите. Натиснете {key}, за да ги покажете. diff --git a/crates/ui-egui/src/i18n/ca.tsv b/crates/ui-egui/src/i18n/ca.tsv index 513016faf4..3fb46d023f 100644 --- a/crates/ui-egui/src/i18n/ca.tsv +++ b/crates/ui-egui/src/i18n/ca.tsv @@ -2843,3 +2843,7 @@ theme Appearance Aspecte # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Opcions d'aquesta resposta + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Mostra o amaga les barres d'eines i els taulers + This document hides the toolbars and panels. Press {key} to show them. Aquest document amaga les barres d'eines i els taulers. Prem {key} per mostrar-los. diff --git a/crates/ui-egui/src/i18n/ckb.tsv b/crates/ui-egui/src/i18n/ckb.tsv index 645f174416..ab7364af4c 100644 --- a/crates/ui-egui/src/i18n/ckb.tsv +++ b/crates/ui-egui/src/i18n/ckb.tsv @@ -2775,3 +2775,7 @@ certificate Version وەشان @plural {n} more formula reads a missing field.|{n} more formulas read missing fields. {n} more formula reads a missing field.|{n} more formulas read missing fields. @plural {fields} builds some field names as it runs, so those reads aren't checked.|{fields} build some field names as they run, so those reads aren't checked. {fields} builds some field names as it runs, so those reads aren't checked.|{fields} build some field names as they run, so those reads aren't checked. @plural {fields} is missing|{fields} are missing {fields} is missing|{fields} are missing + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels پیشاندان یان شاردنەوەی شریتەکانی ئامراز و پانێڵەکان + This document hides the toolbars and panels. Press {key} to show them. ئەم بەڵگەنامەیە شریتەکانی ئامراز و پانێڵەکان دەشارێتەوە. {key} دابگرە بۆ پیشاندانیان. diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 4ab47a4c3c..178a3a2eb1 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -2890,3 +2890,7 @@ certificate Version Verze # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Možnosti této odpovědi Export value Exportní hodnota + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Zobrazit nebo skrýt panely nástrojů a postranní panely + This document hides the toolbars and panels. Press {key} to show them. Tento dokument skrývá panely nástrojů a postranní panely. Stisknutím {key} je zobrazíte. diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index fab8b0bff5..1d37ab7855 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -2584,3 +2584,7 @@ animation effects Off Aus # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Optionen für diese Antwort Export value Exportwert + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Werkzeugleisten und Bereiche ein- oder ausblenden + This document hides the toolbars and panels. Press {key} to show them. Dieses Dokument blendet die Werkzeugleisten und Bereiche aus. Mit {key} blenden Sie sie ein. diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index 707f15f99a..f67f7e17a7 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -2589,3 +2589,7 @@ animation effects Off Ανενεργά # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Επιλογές για αυτήν την απάντηση Export value Τιμή εξαγωγής + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Εμφάνιση ή απόκρυψη γραμμών εργαλείων και πλαισίων + This document hides the toolbars and panels. Press {key} to show them. Αυτό το έγγραφο αποκρύπτει τις γραμμές εργαλείων και τα πλαίσια. Πατήστε {key} για να εμφανιστούν. diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index a465e5a1f8..06c4120154 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -2906,3 +2906,7 @@ theme Appearance Aspecto # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Opciones de esta respuesta Export value Valor de exportación + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Mostrar u ocultar las barras de herramientas y los paneles + This document hides the toolbars and panels. Press {key} to show them. Este documento oculta las barras de herramientas y los paneles. Pulse {key} para mostrarlos. diff --git a/crates/ui-egui/src/i18n/fa.tsv b/crates/ui-egui/src/i18n/fa.tsv index 99a156bc58..650ea5bad5 100644 --- a/crates/ui-egui/src/i18n/fa.tsv +++ b/crates/ui-egui/src/i18n/fa.tsv @@ -2821,3 +2821,7 @@ theme Appearance ظاهر # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply گزینه‌های این پاسخ + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels نمایش یا پنهان کردن نوارابزارها و پانل‌ها + This document hides the toolbars and panels. Press {key} to show them. این سند نوارابزارها و پانل‌ها را پنهان می‌کند. برای نمایش آن‌ها {key} را فشار دهید. diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index b1dbaffc1e..742e675c43 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -2852,3 +2852,7 @@ theme Appearance Teema # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Tämän vastauksen asetukset + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Näytä tai piilota työkalurivit ja paneelit + This document hides the toolbars and panels. Press {key} to show them. Tämä asiakirja piilottaa työkalurivit ja paneelit. Näytä ne painamalla {key}. diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 513ba27b3f..2705e25af8 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -2849,3 +2849,7 @@ certificate Version Version # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Options de cette réponse Export value Valeur d’exportation + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Afficher ou masquer les barres d'outils et les panneaux + This document hides the toolbars and panels. Press {key} to show them. Ce document masque les barres d'outils et les panneaux. Appuyez sur {key} pour les afficher. diff --git a/crates/ui-egui/src/i18n/hi.tsv b/crates/ui-egui/src/i18n/hi.tsv index fa59df3a15..963cb4dfeb 100644 --- a/crates/ui-egui/src/i18n/hi.tsv +++ b/crates/ui-egui/src/i18n/hi.tsv @@ -2814,3 +2814,7 @@ theme Appearance स्वरूप # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply इस जवाब के विकल्प + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels टूलबार और पैनल दिखाएँ या छिपाएँ + This document hides the toolbars and panels. Press {key} to show them. यह दस्तावेज़ टूलबार और पैनल छिपाता है। उन्हें दिखाने के लिए {key} दबाएँ। diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index bc4614e104..968dab4ef0 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -2582,3 +2582,7 @@ animation effects Off Ki # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply A válasz beállításai Export value Exportérték + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Eszköztárak és panelek megjelenítése vagy elrejtése + This document hides the toolbars and panels. Press {key} to show them. Ez a dokumentum elrejti az eszköztárakat és a paneleket. Megjelenítésükhöz nyomja meg ezt: {key}. diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index 52b2dfbe4f..57339972f0 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -2815,3 +2815,7 @@ theme Appearance Tampilan # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Opsi untuk balasan ini + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Tampilkan atau sembunyikan bilah alat dan panel + This document hides the toolbars and panels. Press {key} to show them. Dokumen ini menyembunyikan bilah alat dan panel. Tekan {key} untuk menampilkannya. diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 3228312cca..311d1ed96c 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -2815,3 +2815,7 @@ certificate SHA-256 digest Impronta SHA-256 # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Opzioni per questa risposta Export value Valore di esportazione + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Mostra o nascondi barre degli strumenti e pannelli + This document hides the toolbars and panels. Press {key} to show them. Questo documento nasconde le barre degli strumenti e i pannelli. Premi {key} per mostrarli. diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 37ddfd4c58..60ecd70e44 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -2583,3 +2583,7 @@ animation effects Off オフ # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply この返信のオプション Export value 書き出し値 + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels ツールバーとパネルの表示/非表示 + This document hides the toolbars and panels. Press {key} to show them. この文書はツールバーとパネルを非表示にしています。{key} キーで表示できます。 diff --git a/crates/ui-egui/src/i18n/kk.tsv b/crates/ui-egui/src/i18n/kk.tsv index a28d532498..a410a30ecd 100644 --- a/crates/ui-egui/src/i18n/kk.tsv +++ b/crates/ui-egui/src/i18n/kk.tsv @@ -2581,3 +2581,7 @@ animation effects Off Өшірулі # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Осы жауаптың параметрлері Export value Экспорт мәні + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Құралдар тақталары мен панельдерді көрсету немесе жасыру + This document hides the toolbars and panels. Press {key} to show them. Бұл құжат құралдар тақталары мен панельдерді жасырады. Оларды көрсету үшін {key} басыңыз. diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index ecf2b20faa..e4d33556ff 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -2814,3 +2814,7 @@ theme Appearance 모양 # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply 이 답글의 옵션 + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels 도구 모음 및 패널 표시/숨기기 + This document hides the toolbars and panels. Press {key} to show them. 이 문서는 도구 모음과 패널을 숨깁니다. {key} 키를 눌러 표시할 수 있습니다. diff --git a/crates/ui-egui/src/i18n/lo.tsv b/crates/ui-egui/src/i18n/lo.tsv index ca2d8bc7ea..f1cf87dbba 100644 --- a/crates/ui-egui/src/i18n/lo.tsv +++ b/crates/ui-egui/src/i18n/lo.tsv @@ -2486,3 +2486,7 @@ animation effects Off ປິດ Unchecked reads Unchecked reads {field} reads fields named as it runs {field} reads fields named as it runs Some names are built as it runs Some names are built as it runs + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels ສະແດງ ຫຼື ເຊື່ອງແຖບເຄື່ອງມື ແລະ ແຜງ + This document hides the toolbars and panels. Press {key} to show them. ເອກະສານນີ້ເຊື່ອງແຖບເຄື່ອງມື ແລະ ແຜງ. ກົດ {key} ເພື່ອສະແດງພວກມັນ. diff --git a/crates/ui-egui/src/i18n/lt.tsv b/crates/ui-egui/src/i18n/lt.tsv index b2e588c48a..6fe7fcc306 100644 --- a/crates/ui-egui/src/i18n/lt.tsv +++ b/crates/ui-egui/src/i18n/lt.tsv @@ -2844,3 +2844,7 @@ theme Appearance Išvaizda # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Šio atsakymo parinktys Export value Eksporto reikšmė + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Rodyti arba slėpti įrankių juostas ir skydelius + This document hides the toolbars and panels. Press {key} to show them. Šis dokumentas slepia įrankių juostas ir skydelius. Norėdami juos parodyti, paspauskite {key}. diff --git a/crates/ui-egui/src/i18n/nb.tsv b/crates/ui-egui/src/i18n/nb.tsv index c196fd2394..ff32ea358a 100644 --- a/crates/ui-egui/src/i18n/nb.tsv +++ b/crates/ui-egui/src/i18n/nb.tsv @@ -2759,3 +2759,7 @@ key Space Mellomrom @plural {n} more formula reads a missing field.|{n} more formulas read missing fields. {n} more formula reads a missing field.|{n} more formulas read missing fields. @plural {fields} builds some field names as it runs, so those reads aren't checked.|{fields} build some field names as they run, so those reads aren't checked. {fields} builds some field names as it runs, so those reads aren't checked.|{fields} build some field names as they run, so those reads aren't checked. @plural {fields} is missing|{fields} are missing {fields} is missing|{fields} are missing + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Vis eller skjul verktøylinjer og paneler + This document hides the toolbars and panels. Press {key} to show them. Dette dokumentet skjuler verktøylinjene og panelene. Trykk {key} for å vise dem. diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index ae6463a156..4bcc04cd3d 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -2679,3 +2679,7 @@ animation effects Off Wyłączone # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Opcje tej odpowiedzi Export value Wartość eksportowa + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Pokaż lub ukryj paski narzędzi i panele + This document hides the toolbars and panels. Press {key} to show them. Ten dokument ukrywa paski narzędzi i panele. Naciśnij {key}, aby je pokazać. diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 70309ffc15..5082962f2c 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -2868,3 +2868,7 @@ theme Appearance Aparência # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Opções desta resposta Export value Valor de exportação + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Mostrar ou ocultar barras de ferramentas e painéis + This document hides the toolbars and panels. Press {key} to show them. Este documento oculta as barras de ferramentas e os painéis. Pressione {key} para mostrá-los. diff --git a/crates/ui-egui/src/i18n/ro.tsv b/crates/ui-egui/src/i18n/ro.tsv index f8a2deb83e..6cd490fad6 100644 --- a/crates/ui-egui/src/i18n/ro.tsv +++ b/crates/ui-egui/src/i18n/ro.tsv @@ -2843,3 +2843,7 @@ theme Appearance Aspect # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Opțiuni pentru acest răspuns + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Afișare sau ascundere bare de instrumente și panouri + This document hides the toolbars and panels. Press {key} to show them. Acest document ascunde barele de instrumente și panourile. Apăsați {key} pentru a le afișa. diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 87042f7bd9..c39e5992f9 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -2496,3 +2496,7 @@ animation effects Off Выкл # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Параметры этого ответа Export value Значение экспорта + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Показать или скрыть панели инструментов и боковые панели + This document hides the toolbars and panels. Press {key} to show them. Этот документ скрывает панели инструментов и боковые панели. Нажмите {key}, чтобы показать их. diff --git a/crates/ui-egui/src/i18n/sl.tsv b/crates/ui-egui/src/i18n/sl.tsv index 57d31bd66e..75a2d6e998 100644 --- a/crates/ui-egui/src/i18n/sl.tsv +++ b/crates/ui-egui/src/i18n/sl.tsv @@ -2588,3 +2588,7 @@ animation effects Off Izklopljeni # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Možnosti tega odgovora Export value Izvozna vrednost + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Pokaži ali skrij orodne vrstice in razdelke + This document hides the toolbars and panels. Press {key} to show them. Ta dokument skrije orodne vrstice in razdelke. Za prikaz pritisnite {key}. diff --git a/crates/ui-egui/src/i18n/sq.tsv b/crates/ui-egui/src/i18n/sq.tsv index 4b1769c0f3..8f555253d4 100644 --- a/crates/ui-egui/src/i18n/sq.tsv +++ b/crates/ui-egui/src/i18n/sq.tsv @@ -2569,3 +2569,7 @@ animation effects Off Joaktiv # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Opsionet për këtë përgjigje + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Shfaq ose fshih shiritat e mjeteve dhe panelet + This document hides the toolbars and panels. Press {key} to show them. Ky dokument fsheh shiritat e mjeteve dhe panelet. Shtyp {key} për t'i shfaqur. diff --git a/crates/ui-egui/src/i18n/te.tsv b/crates/ui-egui/src/i18n/te.tsv index 5b4ba64345..8717abb304 100644 --- a/crates/ui-egui/src/i18n/te.tsv +++ b/crates/ui-egui/src/i18n/te.tsv @@ -2492,3 +2492,7 @@ animation effects Off ఆఫ్ # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply ఈ ప్రత్యుత్తరం ఎంపికలు Export value ఎగుమతి విలువ + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels టూల్‌బార్‌లు మరియు ప్యానెల్‌లను చూపించు లేదా దాచు + This document hides the toolbars and panels. Press {key} to show them. ఈ పత్రం టూల్‌బార్‌లను మరియు ప్యానెల్‌లను దాచుతుంది. వాటిని చూపించడానికి {key} నొక్కండి. diff --git a/crates/ui-egui/src/i18n/th.tsv b/crates/ui-egui/src/i18n/th.tsv index 71c7d38fe8..7694f63b9f 100644 --- a/crates/ui-egui/src/i18n/th.tsv +++ b/crates/ui-egui/src/i18n/th.tsv @@ -2741,3 +2741,7 @@ theme Appearance ลักษณะที่ปรากฏ Unchecked reads Unchecked reads {field} reads fields named as it runs {field} reads fields named as it runs Some names are built as it runs Some names are built as it runs + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels แสดงหรือซ่อนแถบเครื่องมือและแผง + This document hides the toolbars and panels. Press {key} to show them. เอกสารนี้ซ่อนแถบเครื่องมือและแผง กด {key} เพื่อแสดง diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index f76f7f5cd0..f3ae806791 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -2579,3 +2579,7 @@ animation effects Off Kapalı # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Bu yanıtın seçenekleri Export value Dışa aktarma değeri + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Araç çubuklarını ve panelleri göster veya gizle + This document hides the toolbars and panels. Press {key} to show them. Bu belge araç çubuklarını ve panelleri gizliyor. Göstermek için {key} tuşuna basın. diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index eb7bb2ec4b..a950785904 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -2605,3 +2605,7 @@ animation effects Off Вимкнено # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Параметри цієї відповіді Export value Значення експорту + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Показати або приховати панелі інструментів і бічні панелі + This document hides the toolbars and panels. Press {key} to show them. Цей документ приховує панелі інструментів і бічні панелі. Натисніть {key}, щоб показати їх. diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 860884ae48..b6858c0a98 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -2850,3 +2850,7 @@ key Space Space # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply Tùy chọn cho câu trả lời này Export value Giá trị xuất + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels Hiện hoặc ẩn thanh công cụ và bảng + This document hides the toolbars and panels. Press {key} to show them. Tài liệu này ẩn thanh công cụ và bảng. Nhấn {key} để hiện lại. diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 995acc78e6..0b034558dd 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -2547,3 +2547,7 @@ animation effects Off 关 # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply 此回复的选项 Export value 导出值 + +# Toolbars and panels a document hides (#4378) (AI-assisted, not separately native-reviewed) + Show or hide toolbars and panels 显示或隐藏工具栏和面板 + This document hides the toolbars and panels. Press {key} to show them. 此文档隐藏了工具栏和面板。按 {key} 可以显示。 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 79b67e6e70..64dbf75c6b 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -2533,3 +2533,7 @@ animation effects Off 關 # Comments panel: each reply's own "…" menu (AI-assisted, not separately native-reviewed) Options for this reply 此回覆的選項 Export value 匯出值 + +# Toolbars and panels a document hides (#4378) (AI-assisted, reviewed by a native speaker) + Show or hide toolbars and panels 顯示或隱藏工具列和面板 + This document hides the toolbars and panels. Press {key} to show them. 這份文件隱藏了工具列和面板。按 {key} 可以顯示。 diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 222bb988e4..0449b0725d 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -59,6 +59,7 @@ pub use print_ui::{Handling as PrintHandling, OptionsSource, PrintDraft, Printer pub use redact_ui::{HiddenDraft, PagesDraft as RedactPagesDraft, RedactPrefs, SearchDraft as RedactSearchDraft, SearchMode as RedactSearchMode}; pub mod i18n; pub mod theme; +pub mod viewer_prefs; mod widgets; use pdfcraft_engine::{DocId, Session}; @@ -642,6 +643,9 @@ pub struct PdfCraftApp { /// A document just opened asks to be shown in Full Screen mode (`/PageMode /FullScreen`): /// the person is asked first, as in Acrobat, and this is the document waiting for the answer. pub pending_full_screen: Option, + /// A document just opened asks for its window to fit its first page or to be centred + /// (`FitWindow`, `CenterWindow`): done once the page is laid out. + pub pending_window: Option, /// An absolute GoToR target waiting for approval, before any target-file I/O (#1364). pub pending_remote_link: Option, } diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs index 49f2aeba1a..2d4f2f708a 100644 --- a/crates/ui-egui/src/menus.rs +++ b/crates/ui-egui/src/menus.rs @@ -170,7 +170,7 @@ const DISPLAY: &[&str] = &[ const THEMES: &[&str] = &["view.theme.system", "view.theme.light", "view.theme.dark"]; const PANES: &[&str] = &["view.side_panel", "view.tools_pane"]; const PANE_COMMANDS: &[&str] = &["comment.list", "form.fields", "ui.dock.reset"]; -const MODES: &[&str] = &["view.full_screen", "view.read_mode"]; +const MODES: &[&str] = &["view.full_screen", "view.read_mode", crate::viewer_prefs::TOGGLE]; const PAGES: &[&str] = &[ "page.organize", SEP, diff --git a/crates/ui-egui/src/viewer_prefs.rs b/crates/ui-egui/src/viewer_prefs.rs new file mode 100644 index 0000000000..067a81bcea --- /dev/null +++ b/crates/ui-egui/src/viewer_prefs.rs @@ -0,0 +1,358 @@ +//! Viewer preferences that change the window and its interface when a document opens +//! (ISO 32000-2 §12.2, Table 147): `HideToolbar`, `HideMenubar` and `HideWindowUI` hide parts of +//! the interface for that document's tab, and `FitWindow` and `CenterWindow` size and place the +//! window around its first page. +//! +//! The hidden interface is the tab's own and is never saved: another tab shows the usual +//! interface, and the command [`TOGGLE`] (F8) brings it back, so a document can't leave the user +//! without the toolbar, menu or panels. + +use egui::{Pos2, Rect, Vec2, ViewportCommand, vec2}; + +/// The command that shows the interface a document hid, and hides it again. +pub const TOGGLE: &str = "view.toggle_interface"; + +/// Which parts of the interface are hidden in a document's tab. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub struct HiddenInterface { + /// The mode bar's tools: the mode tabs, Save, Print, Properties and the command search, and + /// the floating quick-action bar (`HideToolbar`). + pub toolbar: bool, + /// The menu bar (`HideMenubar`). + pub menubar: bool, + /// The right rail with its page navigation, the side panels and the document's scroll bars, + /// "leaving only the document's contents displayed" (`HideWindowUI`). + pub window_ui: bool, +} + +impl HiddenInterface { + pub const NONE: Self = Self { toolbar: false, menubar: false, window_ui: false }; + pub const ALL: Self = Self { toolbar: true, menubar: true, window_ui: true }; + + /// What a document's viewer preferences ask to hide. + pub fn asked_by(v: &pdfcraft_engine::InitialView) -> Self { + Self { toolbar: v.hide_toolbar, menubar: v.hide_menubar, window_ui: v.hide_window_ui } + } + + pub fn any(self) -> bool { + self.toolbar || self.menubar || self.window_ui + } + + /// The mode bar has nothing left to show. + pub fn mode_bar(self) -> bool { + self.toolbar && self.menubar + } + + /// For the control channel's `ui.state`. + pub fn to_json(self) -> serde_json::Value { + serde_json::json!({ "toolbar": self.toolbar, "menubar": self.menubar, "window_ui": self.window_ui }) + } +} + +/// A tab's interface: what its document asked to hide, and what is hidden now. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub struct TabInterface { + pub asked: HiddenInterface, + pub hidden: HiddenInterface, +} + +impl TabInterface { + /// The interface a document opens with: what it asks to hide, unless the user's preference + /// is to open every document their own way. + pub fn opening(asked: HiddenInterface, ignore_document: bool) -> Self { + if ignore_document { Self::default() } else { Self { asked, hidden: asked } } + } + + /// [`TOGGLE`]: show everything that is hidden; with nothing hidden, hide what the document + /// asked to hide, or everything when it asked for nothing. Returns whether it is now hidden. + pub fn toggle(&mut self) -> bool { + self.hidden = if self.hidden.any() { + HiddenInterface::NONE + } else if self.asked.any() { + self.asked + } else { + HiddenInterface::ALL + }; + self.hidden.any() + } +} + +/// `FitWindow` and `CenterWindow`, waiting for the document's first frame (the size of its page +/// on screen is known only once it is laid out). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct PendingWindow { + pub doc: pdfcraft_engine::DocId, + pub fit: bool, + pub center: bool, + /// Frames left to wait for the document to be laid out before giving up. + pub frames_left: u8, +} + +/// What the window looks like now, as the windowing layer reports it (points). +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct WindowNow { + /// The window's content area. + pub inner: Vec2, + /// The window with its frame, where the windowing layer knows it. + pub outer: Option, + pub monitor: Option, + /// The document area inside the window. + pub document_area: Vec2, + pub maximized: bool, + pub fullscreen: bool, +} + +/// The first displayed page (or spread) as the view lays it out. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct PageNow { + /// Its width and height on screen at 100%, in points. + pub size: Vec2, + /// The space the view keeps around it (gutters, margins, the gap in a spread), in points. + pub margins: Vec2, + /// The view's set zoom (1.0 = 100%); `None` when the view fits the page to the window. + pub zoom: Option, +} + +/// Smallest window the fit makes, so a tiny page doesn't leave a sliver of a window. +const MIN_INNER: Vec2 = vec2(480.0, 360.0); +/// Share of the monitor the fitted window may take, leaving room for the desktop's own bars. +const MONITOR_SHARE: f32 = 0.9; + +/// The viewport commands for `FitWindow` / `CenterWindow`. None for a maximized or full-screen +/// window (resizing it would fight the user's choice), or when the sizes are unusable. +/// +/// `FitWindow` keeps the document area's height and makes the window as wide as the page needs +/// at that height when the view fits the page to the window, and makes the document area the +/// page's size on screen when the view has a set zoom; either way within the monitor. +/// `CenterWindow` centres the window on the monitor when the window is on the monitor at the +/// desktop's origin (the windowing layer reports the monitor's size but not where it is). +pub fn window_commands(now: WindowNow, page: PageNow, fit: bool, center: bool) -> Vec { + let mut out = Vec::new(); + if now.maximized || now.fullscreen || !usable(now.inner) || !usable(now.document_area) { + return out; + } + let chrome = (now.inner - now.document_area).max(Vec2::ZERO); + let mut inner = now.inner; + let zoom_ok = page.zoom.is_none_or(|z| z.is_finite() && z > 0.0); + if fit && zoom_ok && usable(page.size) && page.margins.x.is_finite() && page.margins.y.is_finite() { + let area = match page.zoom { + // Fitted to the window: keep the document area's height, and make the area as wide + // as the page is at the zoom that height gives it. + None => { + let zoom = ((now.document_area.y - page.margins.y) / page.size.y).max(0.0); + vec2(page.size.x * zoom + page.margins.x, now.document_area.y) + } + Some(zoom) => page.size * zoom + page.margins, + }; + let mut target = area + chrome; + if let Some(monitor) = now.monitor.filter(|m| usable(*m)) { + target = target.min(monitor * MONITOR_SHARE); + } + target = target.max(MIN_INNER).round(); + if usable(target) && (target - now.inner).length() >= 1.0 { + out.push(ViewportCommand::InnerSize(target)); + inner = target; + } + } + if center + && let (Some(outer), Some(monitor)) = (now.outer, now.monitor.filter(|m| usable(*m))) + && Rect::from_min_size(Pos2::ZERO, monitor).contains(outer.min) + { + // The frame around the content area stays the size it is. + let frame = (outer.size() - now.inner).max(Vec2::ZERO); + let size = inner + frame; + let at = ((monitor - size) / 2.0).max(Vec2::ZERO).round(); + if at.x.is_finite() && at.y.is_finite() && (at - outer.min.to_vec2()).length() >= 1.0 { + out.push(ViewportCommand::OuterPosition(at.to_pos2())); + } + } + out +} + +fn usable(v: Vec2) -> bool { + v.x.is_finite() && v.y.is_finite() && v.x >= 1.0 && v.y >= 1.0 +} + +impl crate::PdfCraftApp { + /// The window and interface preferences of the document opening in tab `index` + /// ([`Self::apply_initial_view`] has applied its navigation, layout, zoom and page). + /// + /// - `HideToolbar`, `HideMenubar`, `HideWindowUI` hide those parts of the interface in its tab, + /// unless Always use my default zoom and page layout is on, with a notice of the key that + /// brings them back. + /// - A document that shows one page or one spread at a time (`/PageLayout /SinglePage`, + /// `/TwoPageLeft`, `/TwoPageRight`) and names no zoom opens at fit page instead of the + /// default zoom. ISO 32000-2 doesn't say which zoom such a layout opens at. + /// - `FitWindow`, `CenterWindow` wait for the page to be laid out + /// ([`Self::window_preferences_frame`]), and only for the window's only document: a + /// document opened in a tab beside others doesn't resize or move their window. + pub(crate) fn apply_viewer_preferences(&mut self, index: usize, v: &pdfcraft_engine::InitialView, activate: bool) { + use pdfcraft_engine::{InitialLayout as L, Magnification as M}; + let own_view = self.always_default_view; + let only_document = self.views.len() == 1 && !self.combine_tab.open; + let Some(view) = self.views.get_mut(index) else { return }; + view.interface = TabInterface::opening(HiddenInterface::asked_by(v), own_view); + if !own_view && v.magnification == M::Default && matches!(v.layout, L::SinglePage | L::TwoUp | L::TwoUpCoverPage) { + view.fit = crate::canvas::Fit::Page; + } + let (doc, hidden) = (view.id, view.interface.hidden.any()); + if activate && hidden { + self.notify_interface_hidden(); + } + // A browser page can't resize or move its window. + if !cfg!(target_arch = "wasm32") && activate && only_document && !self.full_screen && (v.fit_window || v.center_window) { + self.pending_window = Some(PendingWindow { doc, fit: v.fit_window, center: v.center_window, frames_left: 30 }); + } + } + + /// The parts of the interface hidden in the active tab. + pub fn hidden_interface(&self) -> HiddenInterface { + self.active.and_then(|i| self.views.get(i)).map_or(HiddenInterface::NONE, |v| v.interface.hidden) + } + + /// [`TOGGLE`] in the active tab. + pub(crate) fn toggle_interface(&mut self) { + let Some(view) = self.active.and_then(|i| self.views.get_mut(i)) else { return }; + if view.interface.toggle() { + self.notify_interface_hidden(); + } + } + + fn notify_interface_hidden(&mut self) { + let key = pdfcraft_engine::commands::command(TOGGLE).and_then(|c| c.shortcut).map(|s| s.label(cfg!(target_os = "macos"))).unwrap_or_default(); + self.notify_fmt("This document hides the toolbars and panels. Press {key} to show them.", &[("key", &key)]); + } + + /// `FitWindow` and `CenterWindow` for the document just opened, once its first page is laid + /// out. Dropped when another tab shows first, when another tab has opened behind it (it is no + /// longer the window's only document), or after a few frames without a layout. + pub(crate) fn window_preferences_frame(&mut self, ctx: &egui::Context) { + let Some(mut pending) = self.pending_window.take() else { return }; + let Some((index, id)) = self.active_ids() else { return }; + if id != pending.doc || self.views.len() != 1 || self.combine_tab.open { + return; + } + let Some(view) = self.views.get(index) else { return }; + let area = view.viewport_rect(); + let page = self.session.get(id).and_then(|d| view.first_page_now(&d.info)); + let Some(page) = page.filter(|_| area.is_positive()) else { + if let Some(left) = pending.frames_left.checked_sub(1) { + pending.frames_left = left; + self.pending_window = Some(pending); + ctx.request_repaint(); + } + return; + }; + let content = ctx.content_rect().size(); + let now = ctx.input(|i| { + let vp = i.viewport(); + WindowNow { + inner: vp.inner_rect.map_or(content, |r| r.size()), + outer: vp.outer_rect, + monitor: vp.monitor_size, + document_area: area.size(), + maximized: vp.maximized.unwrap_or(false), + fullscreen: vp.fullscreen.unwrap_or(false), + } + }); + for command in window_commands(now, page, pending.fit, pending.center) { + ctx.send_viewport_cmd(command); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn now() -> WindowNow { + WindowNow { + inner: vec2(1400.0, 900.0), + outer: Some(Rect::from_min_size(Pos2::new(50.0, 40.0), vec2(1400.0, 930.0))), + monitor: Some(vec2(1920.0, 1080.0)), + document_area: vec2(1300.0, 800.0), + maximized: false, + fullscreen: false, + } + } + + const FITTED: PageNow = PageNow { size: vec2(200.0, 300.0), margins: vec2(140.0, 56.0), zoom: None }; + + #[test] + fn a_fitted_page_gets_a_window_of_its_shape() { + // An 800-point-high area fits the 300-point page at 248%: 496 points wide plus margins, + // and the 100 points of interface beside the document area. + let c = window_commands(now(), FITTED, true, false); + assert_eq!(c, vec![ViewportCommand::InnerSize(vec2(736.0, 900.0))]); + } + + #[test] + fn a_set_zoom_gets_the_page_size_within_the_monitor() { + let page = PageNow { size: vec2(400.0, 500.0), margins: vec2(100.0, 100.0), zoom: Some(1.0) }; + assert_eq!(window_commands(now(), page, true, false), vec![ViewportCommand::InnerSize(vec2(600.0, 700.0))]); + // Too tall for the monitor: the window stops at the share of the monitor it may take. + let page = PageNow { size: vec2(1000.0, 2000.0), margins: Vec2::ZERO, zoom: Some(1.0) }; + assert_eq!(window_commands(now(), page, true, false), vec![ViewportCommand::InnerSize(vec2(1100.0, 972.0))]); + // A tiny page doesn't make a sliver of a window. + let page = PageNow { size: vec2(10.0, 10.0), margins: Vec2::ZERO, zoom: Some(1.0) }; + assert_eq!(window_commands(now(), page, true, false), vec![ViewportCommand::InnerSize(MIN_INNER)]); + } + + #[test] + fn a_maximized_or_full_screen_window_is_left_alone() { + assert!(window_commands(WindowNow { maximized: true, ..now() }, FITTED, true, true).is_empty()); + assert!(window_commands(WindowNow { fullscreen: true, ..now() }, FITTED, true, true).is_empty()); + // Nothing asked, nothing done. + assert!(window_commands(now(), FITTED, false, false).is_empty()); + } + + #[test] + fn centring_uses_the_new_size_and_the_frame() { + let c = window_commands(now(), FITTED, true, true); + // 736 wide and 900 + 30 of frame high, on 1920 × 1080. + assert_eq!(c.get(1), Some(&ViewportCommand::OuterPosition(Pos2::new(592.0, 75.0)))); + // Centre alone keeps the size. + let c = window_commands(now(), FITTED, false, true); + assert_eq!(c, vec![ViewportCommand::OuterPosition(Pos2::new(260.0, 75.0))]); + // A window on another monitor (outside the one at the origin) isn't moved. + let away = WindowNow { outer: Some(Rect::from_min_size(Pos2::new(2000.0, 40.0), vec2(1400.0, 930.0))), ..now() }; + assert!(window_commands(away, FITTED, false, true).is_empty()); + // Nor is one whose monitor or frame is unknown. + assert!(window_commands(WindowNow { monitor: None, ..now() }, FITTED, false, true).is_empty()); + assert!(window_commands(WindowNow { outer: None, ..now() }, FITTED, false, true).is_empty()); + } + + #[test] + fn unusable_sizes_do_nothing() { + for bad in [Vec2::ZERO, vec2(f32::NAN, 10.0), vec2(f32::INFINITY, 10.0), vec2(-5.0, 10.0)] { + let page = PageNow { size: bad, ..FITTED }; + assert!(window_commands(now(), page, true, false).is_empty(), "{bad:?}"); + assert!(window_commands(WindowNow { inner: bad, ..now() }, FITTED, true, true).is_empty(), "{bad:?}"); + assert!(window_commands(WindowNow { document_area: bad, ..now() }, FITTED, true, true).is_empty(), "{bad:?}"); + assert!(window_commands(WindowNow { monitor: Some(bad), ..now() }, FITTED, false, true).is_empty(), "{bad:?}"); + } + for zoom in [f32::NAN, 0.0, -1.0, f32::INFINITY] { + assert!(window_commands(now(), PageNow { zoom: Some(zoom), ..FITTED }, true, false).is_empty(), "{zoom}"); + } + let page = PageNow { margins: vec2(f32::NAN, 0.0), ..FITTED }; + assert!(window_commands(now(), page, true, false).is_empty()); + } + + #[test] + fn toggling_restores_and_rehides() { + let asked = HiddenInterface { toolbar: true, ..HiddenInterface::NONE }; + let mut tab = TabInterface::opening(asked, false); + assert_eq!(tab.hidden, asked); + assert!(!tab.toggle()); + assert_eq!(tab.hidden, HiddenInterface::NONE); + assert!(tab.toggle()); + assert_eq!(tab.hidden, asked); + // The user's preference to open documents their own way hides nothing. + let mut own = TabInterface::opening(asked, true); + assert_eq!(own.hidden, HiddenInterface::NONE); + // A tab whose document asked for nothing hides everything, and shows it again. + assert!(own.toggle()); + assert_eq!(own.hidden, HiddenInterface::ALL); + assert!(!own.toggle()); + } +} diff --git a/crates/ui-egui/tests/it/main.rs b/crates/ui-egui/tests/it/main.rs index a5c3192358..3196d16ce6 100644 --- a/crates/ui-egui/tests/it/main.rs +++ b/crates/ui-egui/tests/it/main.rs @@ -79,4 +79,5 @@ mod ui; mod updates; mod view; mod viewer; +mod viewer_prefs; mod xfa; diff --git a/crates/ui-egui/tests/it/viewer_prefs.rs b/crates/ui-egui/tests/it/viewer_prefs.rs new file mode 100644 index 0000000000..781e461668 --- /dev/null +++ b/crates/ui-egui/tests/it/viewer_prefs.rs @@ -0,0 +1,335 @@ +//! Viewer preferences applied when a document opens (ISO 32000-2 §12.2, Table 147): hiding the +//! toolbars, menu and window controls in its tab, with F8 to bring them back; fitting and +//! centring the window; and the zoom a one-page-at-a-time layout opens at. + +use egui_kittest::Harness; +use egui_kittest::kittest::Queryable; +use pdfcraft_ui_egui::PdfCraftApp; +use pdfcraft_ui_egui::canvas::Fit; +use pdfcraft_ui_egui::viewer_prefs::HiddenInterface; + +/// Two 200 × 300 pages; `catalog` is added to the catalog dictionary. +fn fixture(catalog: &str) -> Vec { + let objs = [ + format!("<< /Type /Catalog /Pages 2 0 R {catalog} >>"), + "<< /Type /Pages /Kids [3 0 R 4 0 R] /Count 2 /MediaBox [0 0 200 300] >>".into(), + "<< /Type /Page /Parent 2 0 R >>".into(), + "<< /Type /Page /Parent 2 0 R >>".into(), + ]; + let mut out = b"%PDF-1.7\n".to_vec(); + let mut offs = Vec::new(); + for (i, o) in objs.iter().enumerate() { + offs.push(out.len()); + out.extend_from_slice(format!("{} 0 obj\n{o}\nendobj\n", i + 1).as_bytes()); + } + let x = out.len(); + out.extend_from_slice(format!("xref\n0 {}\n0000000000 65535 f \n", objs.len() + 1).as_bytes()); + for o in offs { + out.extend_from_slice(format!("{o:010} 00000 n \n").as_bytes()); + } + out.extend_from_slice(format!("trailer\n<< /Size {} /Root 1 0 R >>\nstartxref\n{x}\n%%EOF\n", objs.len() + 1).as_bytes()); + out +} + +const HIDE_ALL: &str = "/ViewerPreferences << /HideToolbar true /HideMenubar true /HideWindowUI true >>"; + +/// A plain document in the first tab and `files` after it, the last one active. +fn harness(setup: impl FnOnce(&mut PdfCraftApp) + 'static, files: &'static [&'static str]) -> Harness<'static, PdfCraftApp> { + let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).build_eframe(move |_cc| { + let mut app = PdfCraftApp::new(); + app.set_option("language", "en").unwrap(); + setup(&mut app); + for (i, catalog) in files.iter().enumerate() { + app.open_bytes(&format!("{i}.pdf"), None, fixture(catalog)).unwrap(); + } + app + }); + settle(&mut h); + h +} + +fn settle(h: &mut Harness<'static, PdfCraftApp>) { + for _ in 0..3000 { + h.run_steps(2); + if !h.state().render_pending() { + break; + } + std::thread::sleep(std::time::Duration::from_millis(5)); + } + h.run_steps(2); +} + +/// Which of the toolbar (the command search), the menu (the menu bar's File menu) and the window +/// controls (the rail's fit button) are on screen. +fn shown(h: &Harness<'static, PdfCraftApp>) -> (bool, bool, bool) { + ( + h.query_by_label("Find tools and commands").is_some(), + h.query_by(|n| n.role() == egui::accesskit::Role::MenuItem && n.label().as_deref() == Some("File")).is_some(), + h.query_by_label("Toggle fit page / fit width").is_some(), + ) +} + +#[test] +fn a_document_that_hides_the_interface_opens_without_it_and_f8_brings_it_back() { + let mut h = harness(|_| {}, &["", HIDE_ALL]); + assert_eq!(shown(&h), (false, false, false), "the toolbar, menu and rail are hidden"); + assert_eq!(h.state().hidden_interface(), HiddenInterface::ALL); + // The quick-action bar is a toolbar too. + assert!(h.query_by_label_contains("Hand (H)").is_none()); + // The tab strip stays: the tabs and Home are still there. + h.get_by_label("Home"); + + h.key_press(egui::Key::F8); + h.run_steps(3); + assert_eq!(shown(&h), (true, true, true), "F8 shows them"); + h.get_by_label_contains("Hand (H)"); + h.key_press(egui::Key::F8); + h.run_steps(3); + assert_eq!(shown(&h), (false, false, false), "and hides them again"); + + // Another tab, whose document asks for nothing, has the usual interface. + h.state_mut().active = Some(0); + h.run_steps(3); + assert_eq!(shown(&h), (true, true, true)); + h.state_mut().active = Some(1); + h.run_steps(3); + assert_eq!(shown(&h), (false, false, false)); + + // The command (palette, menus, automation) does what F8 does. + assert!(h.state_mut().execute("view.toggle_interface")); + h.run_steps(3); + assert_eq!(shown(&h), (true, true, true)); +} + +/// Reloading a file changed on disk keeps the tab's interface: hidden stays hidden, and F8 still +/// hides only what the document asked for. +#[test] +fn a_reloaded_document_keeps_its_interface() { + let mut h = harness(|_| {}, &["/ViewerPreferences << /HideToolbar true >>"]); + let reload = |h: &mut Harness<'static, PdfCraftApp>| { + let info = h.state().session.get(h.state().views[0].id).unwrap().info.clone(); + h.state_mut().views[0].document_replaced(&info); + h.run_steps(3); + }; + reload(&mut h); + assert_eq!(shown(&h), (false, true, true), "still hidden after the reload"); + h.key_press(egui::Key::F8); + h.run_steps(3); + assert_eq!(shown(&h), (true, true, true)); + reload(&mut h); + assert_eq!(shown(&h), (true, true, true), "still shown after the reload"); + h.key_press(egui::Key::F8); + h.run_steps(3); + assert_eq!(shown(&h), (false, true, true), "F8 hides only what the document asked for"); +} + +#[test] +fn each_preference_hides_its_own_part() { + let top = |h: &Harness<'static, PdfCraftApp>| h.state().views[0].viewport_rect().top(); + let mut h = harness(|_| {}, &["/ViewerPreferences << /HideToolbar true >>"]); + assert_eq!(shown(&h), (false, true, true), "HideToolbar"); + // Shown and hidden again, F8 hides only what the document asked for. + h.key_press(egui::Key::F8); + h.run_steps(3); + assert_eq!(shown(&h), (true, true, true)); + h.key_press(egui::Key::F8); + h.run_steps(3); + assert_eq!(shown(&h), (false, true, true)); + let h = harness(|_| {}, &["/ViewerPreferences << /HideMenubar true >>"]); + assert_eq!(shown(&h), (true, false, true), "HideMenubar"); + let h = harness(|_| {}, &["/ViewerPreferences << /HideWindowUI true >>"]); + assert_eq!(shown(&h), (true, true, false), "HideWindowUI"); + assert!(h.state().hidden_interface().window_ui); + // False is the default, and is nothing to hide. + let h = harness(|_| {}, &["/ViewerPreferences << /HideToolbar false /HideMenubar false /HideWindowUI false >>"]); + assert_eq!(shown(&h), (true, true, true)); + let with_bar = top(&h); + // With both the tools and the menu hidden, the mode bar goes and the document moves up. + let h = harness(|_| {}, &["/ViewerPreferences << /HideToolbar true /HideMenubar true >>"]); + assert_eq!(shown(&h), (false, false, true)); + assert!(top(&h) < with_bar - 40.0, "{} against {with_bar}", top(&h)); +} + +#[test] +fn hiding_the_window_controls_leaves_the_document_the_whole_width() { + // The document also asks for the page thumbnails panel, which is hidden with the rest. + let mut h = harness(|_| {}, &["/PageMode /UseThumbs /ViewerPreferences << /HideWindowUI true >>"]); + let width = |h: &Harness<'static, PdfCraftApp>| h.state().views[0].viewport_rect().width(); + assert!(width(&h) > 1390.0, "{}", width(&h)); + h.key_press(egui::Key::F8); + settle(&mut h); + // The rail and the Pages panel are back beside the document. + assert!(width(&h) < 1400.0 - 48.0 - 200.0, "{}", width(&h)); +} + +#[test] +fn the_preference_to_ignore_document_views_keeps_the_interface() { + let h = harness(|app| app.always_default_view = true, &[HIDE_ALL]); + assert_eq!(shown(&h), (true, true, true)); + assert_eq!(h.state().hidden_interface(), HiddenInterface::NONE); +} + +#[test] +fn f8_hides_the_interface_of_any_document_and_shows_it_again() { + let mut h = harness(|_| {}, &[""]); + assert_eq!(shown(&h), (true, true, true)); + h.key_press(egui::Key::F8); + h.run_steps(3); + assert_eq!(shown(&h), (false, false, false)); + h.get_by_label_contains("Press F8 to show them"); + h.key_press(egui::Key::F8); + h.run_steps(3); + assert_eq!(shown(&h), (true, true, true)); +} + +#[test] +fn hiding_the_interface_is_never_saved() { + let h = harness(|_| {}, &[HIDE_ALL]); + let settings = h.state().persist(); + assert!(!settings.contains("interface"), "{settings}"); +} + +/// The fit a document with `catalog` opens at, with the user's defaults (fit width). +fn opening_fit(catalog: &str, own_view: bool) -> Fit { + let mut app = PdfCraftApp::new(); + app.always_default_view = own_view; + app.open_bytes("x.pdf", None, fixture(catalog)).unwrap(); + app.views[0].fit +} + +#[test] +fn one_page_at_a_time_opens_at_fit_page() { + let default = opening_fit("", false); + assert_eq!(default, Fit::Width, "the default zoom"); + for layout in ["SinglePage", "TwoPageLeft", "TwoPageRight"] { + assert_eq!(opening_fit(&format!("/PageLayout /{layout}"), false), Fit::Page, "{layout}"); + // The user's preference keeps their zoom. + assert_eq!(opening_fit(&format!("/PageLayout /{layout}"), true), default, "{layout}"); + } + // Scrolling layouts keep the default zoom. + for layout in ["OneColumn", "TwoColumnLeft", "TwoColumnRight"] { + assert_eq!(opening_fit(&format!("/PageLayout /{layout}"), false), default, "{layout}"); + } + // A zoom the document names wins. + assert_eq!(opening_fit("/PageLayout /SinglePage /OpenAction [3 0 R /FitH 300]", false), Fit::Width); + let mut app = PdfCraftApp::new(); + app.open_bytes("x.pdf", None, fixture("/PageLayout /SinglePage /OpenAction [3 0 R /XYZ 0 300 2]")).unwrap(); + assert_eq!((app.views[0].fit, app.views[0].zoom), (Fit::None, 2.0)); +} + +/// Review on #4378: where the reader left off wins over the fit page a one-page-at-a-time +/// layout opens at. +#[test] +fn a_remembered_zoom_wins_over_the_layouts_fit_page() { + let path = std::env::temp_dir().join(format!("pdfcraft-viewer-prefs-last-view-{}.pdf", std::process::id())).to_string_lossy().into_owned(); + let mut app = PdfCraftApp::new(); + let json_path = serde_json::to_string(&path).unwrap(); + app.restore(&format!(r#"{{"last_views": [{{"path": {json_path}, "page": 1, "zoom": "62.5%", "display": "single"}}]}}"#)); + assert!(app.restore_last_view); + app.open_bytes("x.pdf", Some(path), fixture("/PageLayout /SinglePage")).unwrap(); + let v = &app.views[0]; + assert_eq!((v.fit, v.zoom, v.current), (Fit::None, 0.625, 1)); +} + +/// The last `InnerSize` and `OuterPosition` asked for over `frames` frames. +fn window_commands(h: &mut Harness<'static, PdfCraftApp>, frames: usize) -> (Option, Option) { + let (mut size, mut at) = (None, None); + for _ in 0..frames { + h.run_steps(1); + for c in &h.output().viewport_output[&egui::ViewportId::ROOT].commands { + match c { + egui::ViewportCommand::InnerSize(s) => size = Some(*s), + egui::ViewportCommand::OuterPosition(p) => at = Some(*p), + _ => {} + } + } + } + (size, at) +} + +fn on_monitor(h: &mut Harness<'static, PdfCraftApp>) { + let vp = h.input_mut().viewports.entry(egui::ViewportId::ROOT).or_default(); + vp.monitor_size = Some(egui::vec2(1920.0, 1080.0)); + vp.inner_rect = Some(egui::Rect::from_min_size(egui::pos2(50.0, 70.0), egui::vec2(1400.0, 900.0))); + vp.outer_rect = Some(egui::Rect::from_min_size(egui::pos2(50.0, 40.0), egui::vec2(1400.0, 930.0))); +} + +/// A harness whose window is on a 1920 × 1080 monitor, with one document opened in the first +/// frames. +fn windowed(files: &'static [&'static str]) -> Harness<'static, PdfCraftApp> { + let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).build_eframe(|_cc| { + let mut app = PdfCraftApp::new(); + app.set_option("language", "en").unwrap(); + app + }); + on_monitor(&mut h); + h.run_steps(2); + for (i, catalog) in files.iter().enumerate() { + h.state_mut().open_bytes(&format!("{i}.pdf"), None, fixture(catalog)).unwrap(); + } + h +} + +#[test] +fn fit_window_sizes_the_window_to_the_first_page() { + let mut h = windowed(&["/ViewerPreferences << /FitWindow true >> /OpenAction [3 0 R /Fit]"]); + let (size, at) = window_commands(&mut h, 12); + let size = size.expect("the window is resized"); + assert_eq!(at, None, "not moved"); + // A 2:3 portrait page fitted to the window's height makes a narrower window. + assert!(size.x < 1000.0 && (size.y - 900.0).abs() < 1.0, "{size:?}"); + // Asked once. + assert_eq!(window_commands(&mut h, 6), (None, None)); + // The page now fills the document area's height and nearly its width. + let v = &h.state().views[0]; + let (page, area) = (v.page_screen_rect(0).expect("shown"), v.viewport_rect()); + assert!(area.width() - page.width() < 160.0, "page {page:?} in {area:?}"); +} + +#[test] +fn center_window_centres_the_window_on_the_monitor() { + let mut h = windowed(&["/ViewerPreferences << /CenterWindow true >>"]); + // 1400 × 930 on 1920 × 1080. + assert_eq!(window_commands(&mut h, 12), (None, Some(egui::pos2(260.0, 75.0)))); + let mut h = windowed(&["/ViewerPreferences << /FitWindow true /CenterWindow true >>"]); + let (size, at) = window_commands(&mut h, 12); + let (size, at) = (size.expect("resized"), at.expect("moved")); + assert!(((1920.0 - size.x) / 2.0 - at.x).abs() <= 0.5, "{size:?} at {at:?}"); +} + +#[test] +fn a_maximized_window_or_a_second_tab_is_left_alone() { + let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).build_eframe(|_cc| PdfCraftApp::new()); + on_monitor(&mut h); + h.input_mut().viewports.entry(egui::ViewportId::ROOT).or_default().maximized = Some(true); + h.run_steps(2); + h.state_mut().open_bytes("0.pdf", None, fixture("/ViewerPreferences << /FitWindow true /CenterWindow true >>")).unwrap(); + assert_eq!(window_commands(&mut h, 12), (None, None), "maximized"); + + let mut h = windowed(&["", "/ViewerPreferences << /FitWindow true /CenterWindow true >>"]); + assert_eq!(window_commands(&mut h, 12), (None, None), "beside another document"); + + // A tab opened behind the document before its page is laid out (a late startup file) leaves + // the window alone too, though the document stays active. + let mut h = windowed(&["/ViewerPreferences << /FitWindow true /CenterWindow true >>"]); + h.state_mut().open_bytes("1.pdf", None, fixture("")).unwrap(); + h.state_mut().active = Some(0); + assert_eq!(window_commands(&mut h, 12), (None, None), "a tab opened behind it"); +} + +#[test] +fn the_user_is_told_which_key_brings_the_interface_back() { + let mut h = windowed(&[HIDE_ALL]); + h.run_steps(3); + h.get_by_label_contains("This document hides the toolbars and panels. Press F8 to show them."); + // Not when nothing is hidden. + let mut h = windowed(&["/ViewerPreferences << /HideToolbar false /HideMenubar false /HideWindowUI false >>"]); + h.run_steps(3); + assert!(h.query_by_label_contains("Press F8").is_none()); + // Nor when the user opens documents their own way. + let mut h = windowed(&[]); + h.state_mut().always_default_view = true; + h.state_mut().open_bytes("0.pdf", None, fixture(HIDE_ALL)).unwrap(); + h.run_steps(3); + assert!(h.query_by_label_contains("Press F8").is_none()); +} diff --git a/parity/acrobat-features.toml b/parity/acrobat-features.toml index 1404247cd7..7a6cccab87 100644 --- a/parity/acrobat-features.toml +++ b/parity/acrobat-features.toml @@ -3517,10 +3517,10 @@ area = "D" tier = "P1" milestone = "M4" status = "shipped" -commands = ["file.properties"] +commands = ["file.properties", "view.toggle_interface"] tools = ["doc_initial_view"] -evidence = ["crates/organize/src/view.rs::initial_view_resolves_indirect_boolean_preferences", "crates/ui-egui/tests/it/ui.rs::a_document_asking_for_full_screen_is_asked_about_first", "crates/organize/src/tests.rs::initial_view_round_trips_and_keeps_scripts", "crates/ui-egui/tests/it/viewer.rs::initial_view_is_edited_and_honoured_on_open", "crates/automation/tests/it/automation.rs::initial_view_through_tools", "crates/render/src/inspect/navigation.rs::a_go_to_action_opens_at_its_destination_explicit_or_named", "crates/ui-egui/tests/it/open_action.rs::an_xyz_open_action_puts_its_point_at_the_window_top_left", "crates/ui-egui/tests/it/open_action.rs::a_fith_open_action_puts_its_top_at_the_window_top", "crates/ui-egui/tests/it/open_action.rs::a_named_open_destination_opens_its_page", "crates/ui-egui/tests/it/open_action.rs::a_full_screen_document_shows_its_non_full_screen_panel_outside_full_screen", "crates/organize/src/tests.rs::an_unchanged_opening_destination_keeps_its_position_and_name", "crates/automation/tests/it/automation.rs::doc_info_reports_the_open_destination", "crates/organize/src/tests.rs::choosing_page_one_replaces_a_named_opening_destination", "crates/organize/src/tests.rs::a_named_opening_destination_is_kept_while_it_still_holds"] -notes = "navigation panel, layout, magnification, page, window and interface options; honoured on open; script open actions kept. Open in Full Screen mode (/PageMode /FullScreen) asks first (Full Screen / Not now), as Acrobat does, instead of taking the screen. Window and interface options also read indirect boolean ViewerPreferences values. Missing: Acrobat's Full Screen preference to turn that alert off and its \"remember my choice for this document\" (misc.prefs-full-screen). On open the /OpenAction destination places the view as ISO 32000-2 Table 149 says (the /XYZ point at the window's top-left, /FitH and /FitV top or left at the edge), and a named destination (name or string, /Names /Dests tree or catalog /Dests, §12.3.2.4) resolves; Always use my default zoom keeps only the page. A full-screen document shows its /NonFullScreenPageMode panel outside full screen (Table 147). doc_info reports the opening destination. Document Properties keeps an opening action whose page and magnification are left alone, but still edits only those two; it shows a named destination's page and magnification, and choosing another page or magnification replaces the name with an explicit destination, except that page 1 at the default magnification removes /OpenAction so the first page opens. A name that resolves nowhere reads as page 1 and is kept until another page is chosen" +evidence = ["crates/organize/src/view.rs::initial_view_resolves_indirect_boolean_preferences", "crates/ui-egui/tests/it/ui.rs::a_document_asking_for_full_screen_is_asked_about_first", "crates/organize/src/tests.rs::initial_view_round_trips_and_keeps_scripts", "crates/ui-egui/tests/it/viewer.rs::initial_view_is_edited_and_honoured_on_open", "crates/automation/tests/it/automation.rs::initial_view_through_tools", "crates/render/src/inspect/navigation.rs::a_go_to_action_opens_at_its_destination_explicit_or_named", "crates/ui-egui/tests/it/open_action.rs::an_xyz_open_action_puts_its_point_at_the_window_top_left", "crates/ui-egui/tests/it/open_action.rs::a_fith_open_action_puts_its_top_at_the_window_top", "crates/ui-egui/tests/it/open_action.rs::a_named_open_destination_opens_its_page", "crates/ui-egui/tests/it/open_action.rs::a_full_screen_document_shows_its_non_full_screen_panel_outside_full_screen", "crates/organize/src/tests.rs::an_unchanged_opening_destination_keeps_its_position_and_name", "crates/automation/tests/it/automation.rs::doc_info_reports_the_open_destination", "crates/organize/src/tests.rs::choosing_page_one_replaces_a_named_opening_destination", "crates/organize/src/tests.rs::a_named_opening_destination_is_kept_while_it_still_holds", "crates/ui-egui/tests/it/viewer_prefs.rs::a_document_that_hides_the_interface_opens_without_it_and_f8_brings_it_back", "crates/ui-egui/tests/it/viewer_prefs.rs::one_page_at_a_time_opens_at_fit_page", "crates/ui-egui/tests/it/viewer_prefs.rs::fit_window_sizes_the_window_to_the_first_page"] +notes = "navigation panel, layout, magnification, page, window and interface options; honoured on open; script open actions kept. Open in Full Screen mode (/PageMode /FullScreen) asks first (Full Screen / Not now), as Acrobat does, instead of taking the screen. Window and interface options also read indirect boolean ViewerPreferences values. Missing: Acrobat's Full Screen preference to turn that alert off and its \"remember my choice for this document\" (misc.prefs-full-screen). On open the /OpenAction destination places the view as ISO 32000-2 Table 149 says (the /XYZ point at the window's top-left, /FitH and /FitV top or left at the edge), and a named destination (name or string, /Names /Dests tree or catalog /Dests, §12.3.2.4) resolves; Always use my default zoom keeps only the page. A full-screen document shows its /NonFullScreenPageMode panel outside full screen (Table 147). doc_info reports the opening destination. Document Properties keeps an opening action whose page and magnification are left alone, but still edits only those two; it shows a named destination's page and magnification, and choosing another page or magnification replaces the name with an explicit destination, except that page 1 at the default magnification removes /OpenAction so the first page opens. A name that resolves nowhere reads as page 1 and is kept until another page is chosen. HideToolbar, HideMenubar and HideWindowUI are applied in the document's tab only (the mode bar's tools and quick-action bar, the menu bar, the rail, side panels and scroll bars; the tab strip stays), never saved, skipped with Always use my default zoom and page layout, and F8 (view.toggle_interface) brings them back. FitWindow and CenterWindow apply to the window's only document when the window is neither maximized nor full screen; centring needs the window on the monitor at the desktop origin, and Wayland and the browser ignore both. SinglePage, TwoPageLeft and TwoPageRight without a named zoom open at fit page" [[feature]] id = "organize.custom-properties" From 726024143f2503ede36805aa5e2ecd351539030b Mon Sep 17 00:00:00 2001 From: mtlcl410 <2368091+mtlcl410@users.noreply.github.com> Date: Sat, 31 Oct 2026 08:27:02 +0800 Subject: [PATCH 2/4] M3: a document that hides only the toolbar leaves no empty mode bar under the macOS menu bar Review follow-up on #4378: HiddenInterface::mode_bar skipped the bar only when both the toolbar and the menu bar were hidden. With the native macOS menu bar the bar never draws the menus, so a document setting only HideToolbar (ISO 32000-2 Table 147) left an empty 48 px bar above the page. The bar now goes when the tools are hidden and the menus are hidden or native. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Pq7HyCfwzyRXj4VfQAVVdv --- crates/ui-egui/src/app.rs | 2 +- crates/ui-egui/src/viewer_prefs.rs | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/crates/ui-egui/src/app.rs b/crates/ui-egui/src/app.rs index b867059332..a713c1d576 100644 --- a/crates/ui-egui/src/app.rs +++ b/crates/ui-egui/src/app.rs @@ -615,7 +615,7 @@ impl eframe::App for PdfCraftApp { // A document can hide the toolbars, the menu and the panels around it in its tab (ISO // 32000-2 Table 147); the tab strip stays, and F8 brings the rest back (`viewer_prefs`). let hidden = self.hidden_interface(); - if !hidden.mode_bar() { + if !hidden.mode_bar(self.native_menu.is_some()) { chrome::mode_bar(self, ui); } // Whichever way another tab came to the front, it shows instead of the expanded view. diff --git a/crates/ui-egui/src/viewer_prefs.rs b/crates/ui-egui/src/viewer_prefs.rs index 067a81bcea..8b6f023b6d 100644 --- a/crates/ui-egui/src/viewer_prefs.rs +++ b/crates/ui-egui/src/viewer_prefs.rs @@ -38,9 +38,10 @@ impl HiddenInterface { self.toolbar || self.menubar || self.window_ui } - /// The mode bar has nothing left to show. - pub fn mode_bar(self) -> bool { - self.toolbar && self.menubar + /// The mode bar has nothing left to show: the tools are hidden, and so are the menus, by the + /// document or because the native macOS menu bar (`native_menu`) has them instead. + pub fn mode_bar(self, native_menu: bool) -> bool { + self.toolbar && (self.menubar || native_menu) } /// For the control channel's `ui.state`. @@ -355,4 +356,19 @@ mod tests { assert_eq!(own.hidden, HiddenInterface::ALL); assert!(!own.toggle()); } + + #[test] + fn the_mode_bar_goes_when_nothing_is_left_on_it() { + let toolbar = HiddenInterface { toolbar: true, ..HiddenInterface::NONE }; + // The in-window menus are still there. + assert!(!toolbar.mode_bar(false)); + // #4378 review: on macOS the native menu bar has the menus, so hiding the tools leaves an + // empty bar, which goes too. + assert!(toolbar.mode_bar(true)); + let both = HiddenInterface { menubar: true, ..toolbar }; + assert!(both.mode_bar(false) && both.mode_bar(true)); + // Menus hidden, tools shown: the bar has the tools. + let menubar = HiddenInterface { menubar: true, ..HiddenInterface::NONE }; + assert!(!menubar.mode_bar(false) && !menubar.mode_bar(true)); + } } From 6b1d42d43fbf5daba6bd311923c84208a8247a79 Mon Sep 17 00:00:00 2001 From: mtlcl410 Date: Mon, 9 Nov 2026 01:08:50 +0800 Subject: [PATCH 3/4] M4: the OCR Verify screen keeps F8 for the next word to review (doc.initial-view) Main's OCR Verify screen walks the words to review with F8 and Shift+F8; the registry's view.toggle_interface shortcut now skips while that screen is open, so both keep working after the merge. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA --- crates/ui-egui/src/commands.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/ui-egui/src/commands.rs b/crates/ui-egui/src/commands.rs index 9484e709b2..9de9f6d34e 100644 --- a/crates/ui-egui/src/commands.rs +++ b/crates/ui-egui/src/commands.rs @@ -819,6 +819,11 @@ impl PdfCraftApp { if matches!(spec.id, "view.previous_view" | "view.next_view") && !self.command_enabled(spec) { continue; } + // The OCR Verify screen keeps the window's toolbars and owns F8 and Shift+F8 (the next + // and previous word to review), so they don't show or hide the interface there. + if spec.id == crate::viewer_prefs::TOGGLE && self.ocr_verify.open { + continue; + } // A box typed into on the page (a paragraph being edited, added text) keeps Undo and // Redo only while it holds typing the page doesn't have, or Redo has typing to put // back; then they reach the document. ⌘⇧Z is also ⌘Z to the Undo shortcut, so a From 690bd7549a6686b2caf2ad0dddedee53e6f904e8 Mon Sep 17 00:00:00 2001 From: mtlcl410 Date: Mon, 9 Nov 2026 01:23:37 +0800 Subject: [PATCH 4/4] Re-run CI (flaky Fill & Sign test, #6066) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA