The line's em box top is measured at the unshifted baseline; the shift
moves only the drawn glyphs. CJK character alignment still counts. The
Ascent, Cap Height and x Height offsets keep counting a raised baseline.
8806a223 (next, for #392) drew a slanted glyph with run while a
right-to-left line span was open, so its tagged span would not nest in
the line span. pdf-rtl-text (8f30ba1c) removes the line span and its
line_span flag, so the glyph always goes through tagged_run. The
regression test keeps its export of tagged and untagged PDFs with shatai
Hebrew and checks what the branch's tests check: reading-order text,
no marked content opened inside an ActualText span, and no ActualText
wider than a word.
Conflict: ROADMAP.md: status line lists both changes (the PR's review date); progress log both lines, the PR's first
Conflict: crates/ui-egui/src/i18n/ja.rs (auto-merged, edited): the PR's ("All", "すべて") row dropped, next already has it
Conflict: crates/doc/src/build.rs: next's parent_page_for (it calls Spread::parent_page_for_side); the PR's test kept
Conflict: crates/tools/src/snap.rs: shown_parent_page_index no longer exists (snap calls Spread::parent_page_for_side); the PR's test kept, calling parent_page_for_side on a two-page and a one-page parent
Conflict: crates/doc/src/page.rs (auto-merged, edited): parent_page_for_side picks the parent's first page for PageSide::Single, the PR's rule moved to where next makes the choice
Conflict: crates/doc/src/edit.rs: next's thread_frames (append_story); every rev += 1 is rev.wrapping_add(1)
Conflict: crates/engine/src/cmd/fonts.rs: next's replace (the local-formatting pass moved out of this hunk)
Conflict: crates/engine/src/cmd/text.rs: next's format_chars (apply_char_attrs, typing format); rev += 1 is rev.wrapping_add(1)
Conflict: Cargo.lock: next's (the PR's dependency is already on next)
Conflict: ROADMAP.md: next's (the PR's earlier head is already merged)
Conflict: docs/gaps.md: next's (the PR's earlier head is already merged)
Conflict: docs/typography-parity.md: next's, test count 170 -> 172 as in d0120bf6
Conflict: crates/compose/src/optical.rs: next's plus d0120bf6's kernable() dash and fullwidth exclusion and its unit test
Conflict: crates/compose/src/tests.rs: next's plus d0120bf6's optical_kerning_leaves_dash_pairs_alone
Changes from an independent review pass over the Czech catalog:
- meaning: "Fit Text" resizes the frame to the text, not the text; the nested
style "New Line Style" is a style for lines of text, not for strokes;
"Liquid Settings", "Nonbreaking Space/Hyphen" and "Discretionary Hyphen" use
the common Czech terms
- consistency: a story is "text" and an article is "clanek" (they were both
"clanek"); "Tags" matches "Novy tag"/"Odebrat tag"; "Float Panel" matches
"Float panel"; Image = "Obrazek" like the other image labels; Remove =
"Odebrat"; one name for the Utilities menu that no longer clashes with Tools
- grammar and shape: command-like labels (Essentials, Wavy, Metrics, Optical,
Both, Restart Numbering, Output All Blacks...) and a stray "(" fixed
Strings that need a code change to be right in every place (digit set names
that share keys with languages, nested-style units after a number, the
Crop/Trim/Media combo) are left as they are.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Own entry only, as AGENTS.md describes: credited by the name on my public
GitHub profile (sync_github_name), otherwise by @username.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ROADMAP.md ("Also shipped") and docs/localization-parity.md (language
table, count of shipped languages, revision history), as AGENTS.md asks
when an interface language is added.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Every Czech row is looked up through the cached tr(), and an unknown
label passes through unchanged.
- No duplicate or empty rows; placeholders, trailing ellipses and colons
and padded captions match the English key. Only stale rows fail: keys
that no catalog, command label, menu name or UI command knows any
more. A new English string falls back to English, as in #294.
- count_label("cs", ..) gives the one / few / other form for 0, 1, 2,
4, 5, 11 and 22, and the Group selection title uses its context row.
- Czech is selectable from the menu, persisted in UiState and leaves
document data untouched; it joins the language switch geometry test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Register "Čeština" (cs) in LANGUAGES, the Interface Language menu and
the app.language parameter doc, and look it up in tr() like the other
single-language tables. tr_context() uses the Czech CONTEXT rows.
count_label() picks the Czech plural form for the number (1 chyba,
3 chyby, 5 chyb; 1 stránka, 3 stránky, 5 stránek), so the info panel,
the Preflight panel and the status bar read grammatically for every
count. Nouns without plural forms keep the existing "{count} {noun}"
caption; other languages are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add crates/ui-egui/src/i18n/cs.rs in the shape of ar.rs, it.rs, ja.rs and
uk.rs. It has a row for every key of the shared table and of the Arabic,
Brazilian Portuguese, Italian, Japanese and Ukrainian tables (1,697
strings), plus 25 labels the code passes to tr() that no catalog had yet
(data merge and composite font commands, panel docking, the unsaved
changes dialog, W:/H: in the control bar).
Translated from the meaning of the English strings with ordinary Czech
desktop-publishing vocabulary; no other product's localization was used.
Phrases that the MIT OR Apache-2.0 Czech catalogs of VectorCraft and
PhotoCraft already use are kept identical for consistency across
ArtCraft and credited in ASSETS.md.
The file also holds PLURALS (one / few / other forms for the count
captions) and CONTEXT (the Properties panel title "Group" is a noun,
the menu command is a verb). The next commit wires them in.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The wheel turned over a document view with Alt (Option) held scrolled
the view like the plain wheel. It now zooms at the pointer, exactly as
Ctrl/Cmd + wheel does. As with that zoom, a wheel motion keeps its key
to its end: letting Alt go while a trackpad swipe coasts on does not
turn the rest into scrolling.
`run --pdf-options '[1]' --export a.pdf` panicked when the PDF's path
was added to the options (exit status 101). The value is now checked
where it is read.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
--export knew .pdf, .epub, .idml and .designcraft and saved a PNG of
the page under every other name: out.html, out.txt, OUT.PDF, and
out.designcraft from `script`. The exit status was 0.
.html and .htm now run file.exportHtml, .rtf and .txt run
file.exportText (the story being edited or of the selected frame), and
extensions match in any case. A name with another extension is an
error before anything runs; one with no extension is still a PNG.
`run` and `script` share one list, and `script` saves a copy for
.designcraft.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two dashes end to end have no ink gap to measure, so -- and the double
em dash opened up by the loosen cap; Chinese sets —— as one continuous
rule. Fullwidth Latin (U+FF21–FF5A) was kernable through its Latin
script and moved CJK text off its em grid. Both are now excluded from
kernable(), with a unit test and a compose test that failed before.
Text is composed in the box around a frame's path in the frame's own
coordinates. A sheared then rotated frame turns that box past its path's
bounds, which was all a move repainted, so its text left trails behind.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Optical kerning was treated exactly like Metrics: the font's kern pairs
and nothing else, so text set with Optical in InDesign came out wider,
rewrapped and went overset in tightly fitted frames.
Now the font's pairs are turned off for Optical text and each pair is
spaced from its outlines (crates/compose/src/optical.rs): every glyph's
ink is sampled into 28 bands across the em, the pair's mean and smallest
ink gap over the bands both glyphs ink are compared with the font's
stem-to-stem gap (the pair nn, or HH then oo), and the pair moves 60% of
the way towards it, keeping 30% of that gap and moving at most -0.12 or
+0.06 em. Latin, Greek and Cyrillic letters, digits and Western
punctuation take part; spaces, marks, missing glyphs, right-to-left
runs, upright and tate-chu-yoko glyphs and pairs across a fallback font
keep their font spacing. Profiles and references are cached, bounded.
Tests: AV, To and r. close up and nn stays; HH closes up under Optical
but not Metrics (fails on main); every change on a pangram stays within
the bounds and spaces keep their width; profile, gap, adjustment and
character-class unit tests.
Docs: typography parity Kerning row and remaining effort, gap 4,
ROADMAP milestone 6 and progress log.
Fixes#181.
Command descriptions left the new-text hyphenation default and image fitting outcomes implicit. State the default and each fitting mode's semantics, and add an MCP example that disables hyphenation. No behavior changes.
Route visible labels through the existing translation and RTL helpers.
Keep document commands, stored options and user-defined style names intact.
Update the localization status and roadmap progress log.
atomic-say brings upstream's shared panel docking (#409), which sends
float_panel and dock_panel through the docking registry; next's Tabs panel
is float-only and not registered there, so Type > Tabs failed with "panel
must name a registered panel". Float-only panels keep the legacy floating
list: they float and close without the registry, a customized layout
keeps them in that list, and dock::floating still draws them then.
poppler positions an ActualText with the transform in force where its
span ends; a line span closes outside the runs' transforms, so pdftotext
placed the line text off the page and dropped it. An ActualText per run
fares no better: poppler reverses its characters in a right-to-left
line. Without them, poppler orders the glyphs of right-to-left lines
itself and extracts whole lines in reading order, and the content stream
keeps listing them in reading order. With no line span left, glyphs in
it no longer need to avoid krilla's cluster spans, so that workaround
goes too. The tests that read the line span's ActualText now check that
ActualText never spans more than a cluster.
Conflict: crates/compose/src/tests.rs: next's baseline-fit and keep tests, then the branch's OS/2 offset doc and code-page constant
Conflict: crates/fonts/src/tests_vertical.rs: testing imports from both (with_base, with_code_pages)