* Fix Links panel stalls on network paths
* Fix Links review findings
* Fix Links worker gating and wasm build
A link check blocked on another document's unreachable share no longer
holds back the document now shown: after 200 ms a fresh worker takes
over (at most four alive at once) and the stale result is dropped.
relinked_asset used the native-only fingerprint_from, breaking the
wasm build; it now uses fingerprint_of. The EPS relink and IDML link
reach tests build Windows paths correctly.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Fix Links worker repaint and graphic read retry
Switching documents before the 200 ms takeover now schedules a repaint
for it: a blocked worker never asks for one, so without other input the
panel kept waiting. A failed graphic read is no longer cached as
missing, so the next check reads again. The legacy EPS fixture clears
its source fingerprint, as documents from before fingerprints have
none, so the test no longer depends on running within two seconds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Keep touched links OK and poll Links within seconds
Only a new size now marks a graphic Modified from its fingerprint. A
file with the same size but a new time (saved again, copied, restored
or checked out) is compared byte for byte, once per new time, and stays
OK when unchanged.
External changes are polled every two seconds instead of every five
minutes. The next check waits at least as long as the last one took
(up to five minutes), so a slow share stays idle half the time.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Wake Links when a worker slot frees; translate check strings
A worker thread asks for a repaint when it ends, so a document waiting
at the four-worker limit gets a worker as soon as a superseded one
returns from its blocked call, without other input.
Rows from a check keep a weak reference to their document. The key
names it by address, which a later document can't reuse while the
allocation is kept.
The Links panel's new strings ("Checking", "Checking links…", "Link
status is unavailable.") use the UI's ellipsis and are translated in
every interface language. The comments on Session::text_link_checks and
on the byte comparison in links::status describe what they do now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Links: rows from the document, statuses from a check that can stop
The panel lists links from the document on the UI thread (no file is
looked at) and fills in the statuses a worker check last found, kept
per document. An edit shows at once, and a check of an earlier edit
still supplies statuses instead of being discarded.
- A check of another document is told to stop and ends before its next
file; only one blocked in a file system call is replaced, so blocked
workers no longer hold their slots for a whole document.
- Checks are timed on the worker, and what they remember passes to the
worker that replaces them.
- A fingerprint is kept only for a file whose time was settled when it
was read, as for linked text. A file found unchanged by its bytes
gets its current size and time stored with the document
(remember_link_files), without marking a saved document as changed.
- Asset::set_link keeps link and fingerprint together; copies made by
Package and Copy Links To carry none.
- The Session holds one LinkListChecks. Update Link lists files only
when a linked story was edited in the layout.
- The unused "Checking links..." caption is removed.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
* pt-BR: translate the 634 interface strings added since the catalog was completed
Covers the strings the catalog lacked after #495: tool names, menu
paths (Edit > Menus), Japanese typesetting dialogs (ruby, kinsoku,
mojikumi, warichu, kenten), special characters, Load Styles, Text
Frame auto-size, Data Merge, preflight, font replacement and About.
Tools are "Ferramenta X", parent pages "página principal", stories
"artigo"; menu paths reuse the existing menu names. IT, VA and Y:
stay as they are, as in every other language.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* pt-BR: one term per feature, the unit names, a catalog test and the docs
Review fixes for the new rows: Gradient Feather, stroke styles and type
on a path use the catalog's existing terms; warichu's Line Spacing no
longer reads as Leading; em/en dash, hair space, nonbreaking space and
hyphen and paragraph return take their Brazilian typographic names; the
file and word counts read correctly for one. File > New's unit names,
which reach tr at run time, are translated too.
The new test checks every pt-BR row's placeholders, padding and
ellipsis, and that each menu path is made of the menu names.
Docs: pt-BR re-measured at 2,416 of 2,419 strings (61% before) in
localization-parity.md, gaps.md (gap 21), target-app-parity.md and the
ROADMAP languages table and progress log. Readiness is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Docs: trace each localization count to its commit; list Russian
The 1,724 baseline was counted at a127c6d5 (#355); recounting that
commit by the same rule gives 1,723, with pt-BR at the same 1,057. The
2,419 strings are main at 438d7b6d. The 2,021 figure is gone: it was
the same rule at the last commit of 2026-10-10, not another scale.
Russian (ru, 1,705 of 2,419) joins the other shipped languages, which
makes six beyond the twelve; ROADMAP's two "Also shipped" lines become
one that includes it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* pt-BR: the 12 strings main added since; docs re-measured at 2e36dcf9
Merging main brought window and guide commands, the InDesign shortcut-set
import and the credits' PRs column, which pt-BR didn't translate yet. Its
button label and result message reach tr as literals no other catalog
has, so they join the shared test's list of UI strings.
Re-measured at main 2e36dcf9: pt-BR translates 2,431 of 2,434 strings
(the Control panel's IT, VA and Y: stay English) and the unit names;
Russian 1,709 of 2,434. The PR adds 645 strings and 7 unit names.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Docs: pt-BR at 2,574 of 2,941 strings by i18n-report; Russian listed
Re-measured on main f3bcc886 with `cargo xtask i18n-report`: pt-BR
translates 2,574 of 2,941 interface strings (1,933 before); the 367 it
lacks are mostly strings main added since 2026-10-23. pt-BR to full is
4-6 h. localization-parity.md, gaps.md (gap 21), target-app-parity.md
and the ROADMAP languages table and progress log say so, each with its
revision row; the ROADMAP entry is dated today, as the review asked.
Russian (1,855 of 2,941) joins the other shipped languages, eight beyond
the twelve, and ROADMAP's two "Also shipped" lines become one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* pt-BR: drop two rows main removed; the test lists eight live labels
`cargo xtask i18n-report` flagged ten pt-BR rows whose keys its
interface list lacks. "/1000 em" and "Import InDesign Set…" are gone
from the code, so their rows go. The other eight still reach tr
(Auto-Sizing, Color Theme, Minimum Height/Width, No Line Breaks,
Reference Point, the shortcut-import result and the unavailable-fonts
message) and join the test's list of UI strings.
The report now counts 2,939 strings; pt-BR translates 2,572 of them
(88%), Russian 1,853. The docs say so; the PR adds 632 strings and the
7 unit names.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* pt-BR: the 364 strings main added since 2026-10-23
Keyboard Shortcuts sets (craft-keymap's dialog, import messages and
counts), panel docking, OpenType features, page presets, the Package
summary and the command dialog's parameter names. "Atalho", "conjunto"
and "escopo" for shortcut, set and scope; tab groups stay "grupo de
guias" and inks "de escala"/"especial", as in the catalog. Key names
stay as printed on keyboards.
`cargo xtask i18n-report` now lists only the Control panel's IT, VA and
Y: for pt-BR: 2,936 of 2,939 strings. The docs say so; pt-BR to full is
1-2 h (an in-app check and the older parent-page and story terms).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* pt-BR review fixes: Affix in, Dir, End, Pathfinder and three clashes; doc scales
- "Affix in" (where footnote prefix and suffix appear) is "Afixos em".
- "Dir" is a folder in file.save, recovery save and links.copyTo and a
direction in text.move: "Pasta/direção".
- The End key is "Fim", as Home is "Início".
- Pathfinder keeps its name ("Objeto/Pathfinder"), as "Pathfinder:"
already did, instead of "Localizador de caminhos" beside "demarcador".
- Pattern (stroke dashes) is "Padrão de traço", apart from Default
("Padrão"); Skipped is "Pulados", apart from "ignoradas"; Heading is
"Intertítulo", apart from Title and Section headings.
ROADMAP's "Also shipped" line now uses one scale (today's i18n-report of
2,939 strings); the pt-BR note names main ef6c3686, and Russian reads
1,855 of 2,939.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
A fill, stroke or stroke gap set to overprint in [Paper] or in a process
colour that lays down no ink (C=0 M=0 Y=0 K=0, gray 0, RGB white, a 0%
tint) disappears on press. Preflight now reports it as whiteOverprint, and
ruby and kenten set to overprint in such a colour too. A spot ink (a white
ink or a varnish) prints whatever colour stands in for it, so it isn't
reported. Text has no overprint of its own, so white text knocks out and
prints, and isn't reported. The old Preflight note that PDF export drops
ruby and kenten overprint is gone: export writes it.
Esperanto in Character › Language (panel, Properties, style options),
mapped to the BCP 47 tag eo, with English-style typographer's quotes.
IDML keeps the name as written ($ID/Esperanto). Not hyphenated yet:
morpheme-based hyphenation follows in #1201.
Claude-Session: https://claude.ai/code/session_01Y9j7XJDCmPc8UZLs9cTxtu
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Pages: more parents and alternate layouts as columns in the Pages panel
Parents
- layout.parents.duplicate copies a parent spread (pages and items) under the next free prefix.
- layout.parents.options also renames the prefix (1-4 characters, no "-") and the name; basedOn is now optional.
- layout.parents.new validates prefix and name and takes basedOn.
- Pages panel: a "+ New Parent" row adds B, C… in one click. The parents' context menu and the panel menu have New Parent…, Duplicate Parent Spread, Parent Options… and Delete Parent, named after the selected parent, or a submenu of the parents when none is selected. A new Parent Options dialog has Prefix, Name and Based on Parent.
Alternate layouts
- Section.layout marks the section that starts a layout; Document::layouts() lists them.
- layout.createAlternate copies one layout (from), not every page; new layout.alternate.duplicate, .delete and .options (rename, resize).
- Each layout starts a spread of its own; sections now follow their pages when pages are inserted or deleted.
- Pages panel: with more than one layout, each is a column side by side with a header (name, size, ▾ menu: create, duplicate, options, delete) and a + column to add one.
Tests cover the commands' happy and error paths, undo, serde, and the panel's menus and columns.
* Pages: address review of parents and alternate layouts
- Deleting a layout's first page keeps the layout's name when another section lands on the same page.
- A parent's full label (prefix-name) must be unique; parents may still share a prefix.
- Alternate layout names round-trip through IDML (Section AlternateLayout / AlternateLayoutLength).
- The Pages panel's selected parent is per document and no longer saved in ui.json.
- Layout ▸ Parent Options… and Alternate Layout Options… open the Pages panel's dialogs.
- The Pages panel computes the layouts once per frame.
* Export: layouts and versions in one export, with presets; print chosen layouts
- file.exportBatch writes the chosen alternate layouts (a file per layout, or all in one PDF) in several versions at once: PDF with any marks, bleed and standard, PNG or JPEG at a resolution. Each version goes in a folder of its own, and file names come from a template ({document}, {layout}, {version}, {date}). Names are made safe and unique. dryRun lists the files; without a dir the files come back as base64 (web).
- Export presets: file.exportPresets, file.saveExportPreset, file.deleteExportPreset, kept in prefs.json. Built-ins: Print + Screen, Press PDF per Layout, Images per Layout, All Layouts in One PDF.
- file.print takes layouts and separateJobs (a job per layout, titled after it).
- File ▸ Export Layouts and Versions… dialog: preset, layouts, versions (add from templates, duplicate, remove, quick PDF choices or custom marks), name template, and a live list of the files it will write. It opens from a layout column's ▾ menu as "Export Layout…". The desktop asks for a folder; the web downloads each file.
- The Print dialog prints chosen layouts, together or separately; the Export PDF dialog fills the page range from a layout.
- crate::io::create_dir_all keeps folder creation inside the automation write root.
* Export: address review of layouts and versions
- An exported image is capped at 80 million pixels, the limit EPUB page images already use.
- The Print dialog stays open and says why when no layout is chosen.
- Clicking a layout column's header leaves Edit Parents before going to the layout's first page.
* Pages, Export: address maintainer review of layouts and versions
- Sections (and the layouts they start) follow a moved page, as they do inserted and deleted
ones: moving a page across a layout boundary no longer moves the other pages between layouts.
Delete and move share `settle_sections`.
- Alternate Layout Options resizes only pages whose size changes: renaming a layout no longer
forces every page to the first page's size.
- Export file and folder names that are Windows device names (CON, NUL, COM1…) get a leading `_`.
- An export without `dir` refuses past 512 MB of files instead of building them all in memory.
- A file that fails partway through an export to a folder says how many were already written.
- Parent Options and Print keep the dialog open, with what was typed and why, when the engine
refuses.
- A duplicated layout's default name stays within the 100-character limit.
- rustfmt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Pages: Alternate Layout Options sends the size only when it changed
The dialog starts at the layout's first page's size, so the engine couldn't tell a rename from a
resize to that size. The dialog now leaves out a width or height still at its starting value, and
`layout.alternate.options` resizes every page of the layout when a size is given, as before.
The test moves to the UI, where the size was coming from.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* M5: preserve out-and-back cubics in striped strokes
A cubic can travel out and back when its endpoints and first control point coincide. Include the second control point in the zero-length guard and cover its offset extent and both stripe bands.
* M5: record striped cubic regression coverage
Record the scoped cubic stroke correction without changing readiness estimates or other progress entries.
Split out of #2073. winit sends no pointer events during a drag from another
application on macOS, so a Finder drop had no pointer and never found the frame
under it. The host now gives the pointer's place on the screen
(`Services::pointer`, `PointerFn`: the system's points before the UI scale,
from `NSEvent.mouseLocation`), and `take_pending_drops` uses it for the files
that came without a pointer, divided by egui's zoom factor and made relative
to the window.
Include the PDF export warnings in the package result and report. Cover
shadow and feather output in packaged PDFs with a synthetic regression test.
Preserve frame and text-range hyperlinks on rasterized frames, including
inside groups, at their original source bounds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Placing an image or media with no placement parameters used the selected
item as the frame, and so did a click of the loaded place cursor. On a
line that made a zero-height frame that kept its stroke. All three now
skip items that enclose no area (PathData::encloses_area): lines and
paths whose points all lie on one line get a new frame instead. Frames,
and open paths that enclose an area, take the content as before.
An explicit frame, x, y, spread or width behave as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A fontFamily the app doesn't have was applied with a null result, so a
script that asked for Courier Prime exported the PDF in the substitute
and exited 0. The font is still applied, since documents can carry
missing fonts and Find Font and preflight list them, but type.char now
returns {"warnings": ["Missing font: Courier Prime (using Source Sans 3)"]},
or "Missing font style: ..." for a style the family doesn't have, in
preflight's words. Other calls still return null.
A Cover Image field with a Choose… button (PNG or JPEG) in the EPUB Export Options dialog; left empty, the first page stays the cover. The three labels are translated; a dialogs test exports with a chosen file and checks the EPUB's cover image and manifest.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
winit 0.30 gives an undecorated window WS_CAPTION and WS_BORDER; on some systems the compositor
reserves that frame, so the content is drawn offset (black bars at the top and left) while the
pointer keeps the client coordinates. A per-frame guard strips the styles again after every
winit flag change and keeps a maximized window clear of the taskbar. Fixes#1295.
Merge origin/main at a288a87b. Preserve the font.list progress entry and the content-first routing note. The feature diff remains the same four reviewed files.
Co-Authored-By: OpenAI Codex <noreply@openai.com>
Keep native ZIP, legacy JSON and IDML bytes out of the INDD converter even when a browser supplies a misleading .indd or .indt name. Preserve signature and unknown-data routing to the converter. Check that every browser delivery adds a document before asserting its title.
Co-Authored-By: OpenAI Codex <noreply@openai.com>
Pass the original filename to file.openBytes so the engine removes one native extension. Cover Open and Drop, repeated suffixes, Unicode, bare and missing extensions, and IDML through the import inbox. Keep the full filename in import warnings.
Co-Authored-By: OpenAI Codex <noreply@openai.com>
A font with no readable OS/2 table doesn't say what its licence allows,
and reporting fsType 0 made it look installable. FontFace::fs_type() now
returns None for it, and font.list reports fsType and the five flags as
null. restricted_licence() and bitmap_only() still treat it as
unrestricted, so export behaviour doesn't change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ApvpyStzzHbKyDBNxpzn2Y
Adds Swedish (Svenska) as an interface language: 1850 strings, written from the English source.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
file.openBytes used the name it was given as the document's title as is. The
IDML path strips .idml/.indd/.indt, but a native document opened as
"Brochure.designcraft" kept the extension, and everything that adds it back
doubled it: Save in the browser downloaded Brochure.designcraft.designcraft,
Save As suggested that name, and the File Name variable showed it. The app's
own drop and open paths strip the extension before calling, so only hosts and
scripts that pass a file name hit it.
The title now drops one trailing .designcraft (any case). Other names are
unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ApvpyStzzHbKyDBNxpzn2Y