* Font: a selected text box's Font commands format all its text
With a text box selected as an object (its frame, not text in it), Word's
Font group formats all the box's text. WordCraft formatted only the box's
anchor character in the paragraph around it, so the box's text kept its
font. Select All doesn't reach a floating box's text either (as in Word),
which left no way to change a box's font short of editing inside it, and
none when the box sits behind text, where a click goes to the text over it.
format::apply and the toggles' reading of the current formatting now take
a selected text box's whole story, as the WordArt commands already do.
* Contributors: pakiat's display name
* Font: Change Case, Clear and Reset on a selected text box work on its text
With a text box selected as an object, Word's Change Case, Clear All
Formatting and Reset Character Formatting work on the box's text and leave
the body text around it alone (observed black-box). format.changeCase,
format.clear and format.resetChar used the box's anchor in the body
instead, so Clear could reset the surrounding paragraph while the box kept
its formatting.
They now take a selected text box's whole story, as the other Font
commands do since the previous commit. An empty selected box also reads
its paragraph mark for the toggles' current state (it read the anchor's
run around it), so Bold on an empty box in bold body text turns Bold on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Font: a selected text box shows its own paragraph style
With a text box selected as an object, format.state reported the box's
character formatting but the style of the body paragraph the box is
anchored in. Word shows the box's own style then (observed black-box: a
Heading 1 box in a Normal paragraph shows Heading 1). The style and its
name now come from the box's first paragraph.
Also doc comments for format.changeCase and format.clear.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
ROADMAP.md: the PR's status entry prepended to main's first status line. docs/parity-checklist.md: main's side, regenerated after the merges. ko.tsv: union.
In crates/engine/src/cmd/format.rs, convert_chars treated any period as a sentence boundary, causing numbers with decimal points (e.g. 3.14, 2.5) to capitalize the subsequent word in Sentence case.
Check if a period is surrounded by ASCII digits, and do not trigger uppercase capitalization when encountering a decimal point.
Closes#3485
Each underline style in the drop-down is now a sample of its own line,
drawn in code in the theme's text colour (Single, Double, Thick, Dotted,
Dashed, Dot-dash, the missing Dot-dot-dash, Wave), named for tooltips and
assistive technology. Words only uses format.wordUnderline (its own
Ctrl+Shift+W); None removes the underline and shows no shortcut; More
Underlines… opens the Font dialog; Underline Color › offers Automatic and
the theme/standard colours with More Colors….
- engine: format.underlineColor {"color": "RRGGBB" | "auto"} sets or
clears CharProps::underline_color and leaves the style alone;
format.state reports underlineColor; catalog row Home|Font|Underline
Color (parity checklist regenerated: 490/505).
- i18n: Dot-dot-dash, More Underlines… and Underline Color in all 22
catalogs (Underline Color reuses each catalog's "Underline color").
- Tests: underline_color_sets_and_clears_the_underlines_own_colour (engine,
DOCX round trip, undo, junk params), underline_menu_entries_apply_their_style
(UI: every sample is a named entry that applies its style; Words only,
None, Underline Color › Automatic).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A field begin marker flagged w:dirty by a producer that couldn't compute
its result (pandoc-style TOC placeholders) lost the flag on save, so Word
no longer refreshed the field on open. Mirror w:fldLock end to end:
FieldState, InlineObject::Field/FieldStart, the reader (fldChar and
fldSimple) and the writer (buffered, range and TOC-spanning begins).
Update Field/Update Table clear it on the fields they compute, like
Word's F9; untouched fields keep it. Round-trip and engine regression
tests, incl. a pin for #878 (imported TOC placeholder replaced in place,
fixed earlier by #617).
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Word forms keep their legacy form fields and rows' skipped grid columns when saved (part of #1174)
* Tests: field initializers name the new form field
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A character colour given as a string now reads the way format.color reads it: RRGGBB, #RRGGBB, or auto/automatic in any case. The serialized forms ("Auto", {"Rgb": [r, g, b]}) read as before and are still what gets written, so documents and settings on disk round-trip unchanged. A colour that isn't one of these is still a parameter error.
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Tables: select, insert and move with the mouse; double-click a border to AutoFit
Like Word, on top of the border resizing:
- Selection areas: just above a column the pointer becomes a down arrow,
left of a row the row arrow, along a cell's left edge (inside it) the
cell arrow. A click selects the column, row or cell; a drag selects every
one up to the pointer. Selected cells are shaded as cells, empty ones too.
- Insert buttons: left of a row border and above a column border a "+"
shows with the border marked; a click adds a row or column there and puts
the caret in it.
- Move handle past the table's top-left corner: a click selects the table;
a drag shows a dashed outline and, on release, the table floats where it
is dropped with the text wrapping around it (Word's behaviour). One undo
step. Nested tables and tables outside the main text are only selected.
- A double-click on a column border fits the column left of it to its
contents (the right neighbour gives or takes the room; on the right edge
the table's width changes, up to the right margin).
- Table Layout > Select > Select Column (catalog 418/449).
Whole-cell selection: a column (or a rectangle of cells over several rows)
is not one run of the text, so selecting it makes a block of its cells'
paragraphs (`CellRange` on the existing `ColumnBlock`). Bold, alignment,
Delete, typing, copy and numbering act on those cells only (a numbered
column is one list); table commands (shading, merge, delete columns) take
the rectangle; Tab moves on without clearing it; Undo brings the selection
back. Cells of one row, or whole rows, stay an ordinary stream selection.
The format painter no longer clears a block's text (edit.pasteFormat was
handled like a paste). The mini toolbar stays hidden over whole-cell
selections and during these drags: pinned above the selection it covered
the column areas, the "+" buttons and the move handle.
Engine: crates/engine/src/cmd/table_mouse.rs - table.selectAt,
table.insertAt, table.moveDrag, table.fitColumn (page coordinates, so
agents and the control channel can do the same) and table.selectColumn;
hit testing reuses table_resize's drawn geometry, and borders keep priority
for resizing. 10 engine tests (areas, a column edited cell by cell,
numbering, rows/cells/drags, insert buttons, move, fit, format painter,
hostile params).
UI: crates/ui-egui/src/table_mouse.rs, wired into the existing canvas mouse
handler (no extra ui.interact areas, so clicks in a cell's text still place
the caret); kittest tests with real pointer events: column click, row drag,
"+" button, move-handle drag in one undo step, double-click fit.
New labels translated in all eleven catalogs. Progress docs updated: gaps,
ui-parity, target-app-parity, ROADMAP, parity checklist.
`cargo xtask ci` passes (fmt, clippy, test, assets, layers, wasm).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Tables: a selected column's word count is its cells'; merged cells shade once
With whole cells selected (a column, or a rectangle that isn't one run of
the text) the status bar said "12 of 23 words": `Session::selected_text`
took everything between the selection's ends. It now takes each piece's
own text, a line each, for a column block too, so the status bar, Word
Count and the other callers see what is selected.
Since #669 a vertically merged cell is one box as tall as its rows, with a
`covered` box for each continuation row; shading selected cells skips
those, so a merged cell isn't shaded twice. `selected_paths` follows
main's `para_paths_in` (#418): a selection ending at the start of the next
paragraph doesn't take it.
- Test: a selected column's text is its three cells' and Word Count says
three words.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Tables: double-click AutoFit and the "+" buttons work as in Word
Checked against Word (2019, Windows):
- A double-click on a column border fits the column left of it to its
contents and the columns right of it keep their widths, moving with the
border, so the table narrows or widens (up to the right margin). The
right neighbour used to give or take the difference.
- A "+" insert button selects the new row or column (the caret used to
go into it); typing then goes into its first cell. If the table can't
take another row or column, nothing changes.
- A double-click along a cell's left edge (the cell selection area)
selects its row.
- Tests: engine (fit keeps the columns on the right; insert selects the
new row or column, typing lands in its first cell) and kittest (real
double-click on a border; "+" selects the row; double-click by a cell's
edge selects the row).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: rabis <340973947+rabis7575@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Keep inherited complex-script size, bold and italic independent from Latin
properties and retain explicit values during DOCX round trips. Preserve
ordinary formatting-command behavior and add regression coverage.
Resolve eight existing Clippy warnings without changing behavior so all
six required CI gates pass.
Co-authored-by: ChatGPT <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* M15: Polish interface, and Polish spelling, grammar and hyphenation
Interface
- Polish is the tenth interface language ("Polski", pl.tsv, 1,045 entries);
pl, pl-PL and pl_PL.UTF-8 system locales select it automatically.
- Right-click menu labels now go through translation in every language.
- Review > Language is a menu (English US/UK, Polski, Do not check spelling
or grammar); the status bar shows the language at the caret.
- With a Polish interface, new blank documents and opened .txt/.md files
default to pl-PL.
Proofing
- Each run is checked in its own language (w:lang, resolved through
styles): squiggles, F7, review.issues, suggestions and hyphenation.
Text in languages without proofing tools is no longer flagged as English.
- Polish spelling from the SJP.PL Hunspell dictionary (Apache-2.0 option),
read by a new Rust affix engine (crates/proof/src/affix.rs); 875 KB asset,
~4.5M word forms. Regenerate with the pl_dictionary example.
- Polish suggestions: case, missing diacritics, rz/ż, ó/u, ch/h confusions,
missing spaces (napewno -> na pewno), edit distance.
- Conservative Polish grammar rules: repeated words, spacing, doubled
punctuation, sentence capitals, missing comma before że/który/ponieważ/
aby/żeby/jeśli…, we/ze forms.
- Polish hyphenation with the hyph-utf8 hyph-pl.tex patterns (MIT option);
pattern keys widened to 20 letters, TeX exceptions parsed; the heuristic
no longer treats ł, ż, ś… as vowels.
review.language validates and normalizes tags, can set noProof alone and
the document default; format.state reports lang and noProof.
Tests for every part, docs and ATTRIBUTION.md/NOTICE updated;
cargo xtask ci passes (fmt, clippy, test, assets, layers, wasm).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Layout: rustfmt the test module order left unformatted by #391
cargo fmt --check failed on main after #391 added mod tests_grid.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Review fixes for #346: read Polish spelling from the installed Hunspell dictionary
- Polish spelling uses the Hunspell pl_PL dictionary installed on the
system (OS packages, Homebrew, LibreOffice, ~/.local/share/hunspell, or
WORDCRAFT_DICTIONARIES) instead of a bundled 870 KB SJP.PL file;
without one, Polish text gets no spelling marks, like Word without the
language's proofing tools. .aff/.dic are size-capped and decoded from
UTF-8 or ISO 8859-2 (crates/proof/src/hunspell.rs).
- The dictionary can be replaced at runtime (install_dictionary) or
re-searched (reload_dictionary); an empty one accepts every word.
- Tests use small synthetic dictionaries written for them, so they don't
depend on what the machine has installed.
- The bundled pl.dic, its ATTRIBUTION/NOTICE entries and the generator
example are removed; docs describe the installed dictionary.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* M15: Polish catalog covers the interface text merged from main
The merge of main (98456ac) brought ~575 new interface strings (charts,
SmartArt, content controls, Developer tab, AutoCorrect, outline view,
protection, compare, print, accessibility, references and Language/
Hyphenation dialogs, Draw additions). pl.tsv lacked them, so
polish_covers_every_key_of_every_other_catalog and
every_tab_and_command_is_translated failed. All are now translated.
cargo xtask ci: all 6 steps pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Font list: installed Chinese fonts are listed, by their Chinese names in a Chinese interface (#505)
The font database read only the English family name of each font, so a
Chinese interface listed SimSun, Microsoft YaHei and WenQuanYi Zen Hei
by their English names and never as 宋体, 微软雅黑 or 文泉驿正黑, and a
document naming a font by its Chinese name fell back to another font.
- fonts: keep each face's localized family names (name IDs 16 and 1,
every face of a collection, read during the scan without loading the
file); FontDb::families_in(lang) lists them in place of the English
names for a matching interface language (zh-hans, zh-hant, ja, ko);
face, has_family and styles accept either name.
- ui: the ribbon and mini toolbar font boxes show the interface
language's names and store the English name.
- East Asian font: choosing a Chinese, Japanese or Korean font also sets
it as the East Asian font (w:eastAsia), read and written in DOCX;
layout draws CJK text in a run's installed East Asian font.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Font dialog: separate Asian and Latin text fonts (#505)
Word's Font dialog sets the font of Chinese, Japanese and Korean text
apart from the font of Latin text; WordCraft's had one font box.
- Font dialog: an "Asian text font" box (the installed Chinese, Japanese
and Korean fonts, by their interface-language names, type to find)
above the "Latin text font" box, shown for a Chinese or Japanese
interface, East Asian text in the selection or a selection with an
Asian font. OK sets only the fonts changed, in one undo step.
- format.font takes "eastAsia" (w:eastAsia) besides "name"; either or
both; format.state reports fontEastAsia.
- fonts: the scan reads each font's OS/2 code pages, so
FontDb::east_asian_families lists CJK fonts without loading them.
- Tests: dialog sets each font on its own; layout sets CJK text in the
run's Asian font and Latin text in its Latin font (skipped without an
installed CJK font); command and undo; the scan finds a CJK font.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
The font database read only the English family name of each font, so a
Chinese interface listed SimSun, Microsoft YaHei and WenQuanYi Zen Hei
by their English names and never as 宋体, 微软雅黑 or 文泉驿正黑, and a
document naming a font by its Chinese name fell back to another font.
- fonts: keep each face's localized family names (name IDs 16 and 1,
every face of a collection, read during the scan without loading the
file); FontDb::families_in(lang) lists them in place of the English
names for a matching interface language (zh-hans, zh-hant, ja, ko);
face, has_family and styles accept either name.
- ui: the ribbon and mini toolbar font boxes show the interface
language's names and store the English name.
- East Asian font: choosing a Chinese, Japanese or Korean font also sets
it as the East Asian font (w:eastAsia), read and written in DOCX;
layout draws CJK text in a run's installed East Asian font.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
- Paste under Track Changes marks the paragraph marks it adds as inserted, so Reject All
joins the paragraphs again (#417).
- Keep Text Only / Paste Special text paste treat paragraph separators as text, not Enter:
an empty list item between them no longer ends the list (#422).
- Untracked Replace All splits paragraphs at CR / U+2029 in the replacement like a single
Replace does (#423).
- Delete Columns deletes every grid column the selected cells cover (#431).
- Split Cells refines the grid inside the split cell only; other rows' cells widen over the
new grid columns, keeping the table width (#432).
- Font dialog sends only the properties the user changed and shows small caps, all caps,
hidden and spacing from the selection (format.state reports them) (#466).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
- Paragraph formatting skips the paragraph a non-empty selection ends at the start of
(Select Paragraph's end), via Document::para_paths_in (#418).
- A non-mutating command that moves the selection closes the typing group (#419).
- Change Case converts char by char and replaces only changed stretches inside one run,
keeping each run's formatting (#421) and mapping the selection to the new offsets (#420).
- Undo/redo steps carry the pending caret formatting (#424).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Home › Font › Enclose Characters: circle, square, triangle or diamond around a character (#297)
New command format.enclose {"shape": "circle|square|triangle|diamond" | null,
"style"?: "shrink|enlarge", "text"?: string} puts one full-width or up to two
half-width characters in an enclosure, changes its shape, or (null) takes the
text back out. It is stored the way ECMA-376 describes it: an EQ field with the
overstrike switch, eq \o\ac(○,字), with the text as its plain-text result.
Layout now draws EQ \o fields: the arguments overstruck as one cluster
(centred, \al or \ar). An enclosure symbol among them is drawn as a vector
shape around the text in the text's colour, so it never depends on the font
having ○ □ △ ◇; "shrink text" scales the text into a one-em shape, "enlarge
symbol" grows the shape around text at its own size. Screen and PDF both get
it through the display list. Imported Word documents with enclosed characters
used to show nothing (the field has no result); they now render.
.docx: written as Word stores enclosed characters (begin, the code split so the
symbol and the text have their own run sizes, end, no result); the reader
recovers the style from those sizes. The style lives in the model as a trailing
\* enlarge on the code, never written to a file.
Home › Font gets an Enclose Characters button that opens a dialog (Style:
None / Shrink text / Enlarge symbol, Text, Enclosure list, a drawn preview);
scripts with a shape never see it. Strings in every interface catalog.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Merge fix: keep both sides (enclosures and ruby; tests); regenerate parity checklist
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Bind Word's documented default shortcuts that were missing to existing
commands, plus a few small new commands: Reset Paragraph Formatting
(Ctrl+Q), Reset Character Formatting (Ctrl+Space, which used to clear all
formatting), em dash, copyright, registered, trademark and ellipsis, DATE /
TIME / PAGE fields (Alt+Shift+D/T/P), Print Layout / Outline / Draft /
Split views, Word Count (Ctrl+Shift+G), Bookmark, Alt+F7, Ctrl+Page Up/Down
find browsing, Shift+F12 / Ctrl+F12 / Ctrl+Shift+F12 / Ctrl+F2 / Ctrl+F4,
Mark Index Entry, Mark Citation and the mail merge keys.
Where macOS claims Word's key (Cmd+Q quits, Cmd+Space is Spotlight, Cmd+Shift+G
is Find Previous, Option+letter types symbols), the binding follows Word for
Mac or is left off there. F4 Repeat, Q and F2 now reach the registry from the
keyboard, and an Alt shortcut no longer also types its key's character.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
select.column (Mod+Shift+F8) selects the same x range on a run of lines,
from two positions, two page points (Alt+drag), or by toggling column
mode where the arrow keys extend the block. Copy/Cut give one line per
row, Delete/Backspace remove only the block, character formatting and
Change Case apply per row, typing/paste replace the block. Any ordinary
caret move drops it. F8 keys now reach their shortcuts in the UI.
Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* feat(doc,docx): complex-script run properties and RTL OOXML round-trip
Model the formatting Word applies to Persian, Arabic and Hebrew text:
cs, font_cs, size_cs, bold_cs, italic_cs and lang_bidi on CharProps,
resolved with Word's fallbacks (ResolvedChar::complex). Size, bold and
italic pair with their complex-script values so a run's size or bold
also covers its Persian characters. Add doc::bidi script helpers, and
keep ZWNJ and Arabic marks inside words for word selection.
DOCX: read and write w:rFonts/@w:cs, w:szCs, w:bCs, w:iCs, w:cs and
w:lang/@w:bidi in schema order; stop using the cs font as the Latin font.
Tests round-trip Persian text with ZWNJ, digits and mixed Latin.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(fonts): directional shaping and Persian font fallback
Add shape_run to shape a run in a known bidi direction (Arabic joining,
mirrored brackets). Prefer Persian-capable fonts (Vazirmatn, Noto Naskh/
Sans Arabic…) for right-to-left fallback, pick bold/italic fallback faces,
and map common Persian document fonts (B Nazanin, B Lotus, B Titr,
IRANSans…) to open substitutes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(layout): Unicode Bidirectional Algorithm and right-to-left paragraphs
Run UAX #9 per paragraph (unicode-bidi), shape each level run in its
direction, keep marks and ZWNJ with their letter and a word in one
fallback face. After line breaking, apply rules L1/L2 per line and give
each cluster a visual box; right-to-left paragraphs are laid out from
their start edge and mirrored, so indents, tabs, alignment, list labels,
drop caps, floats and borders sit on the right.
Caret, hit testing and selection use visual geometry (split selections,
caret at bidi boundaries, DocLayout::visual_step for arrow keys). Display
items carry glyph-to-text ranges, which the PDF writer now uses. Plain
left-to-right lines are unchanged. No hyphenation of RTL words.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(engine,ui): paragraph direction commands and RTL editing
Add para.ltr / para.rtl (Word's text direction buttons) that change only
the reading order, and make the alignment buttons visual in right-to-left
paragraphs (para.align also takes start/end). Arrow keys move visually in
bidirectional text, Ctrl+arrows follow reading order, and Bold/Italic/
Size/Font cover complex-script text. Ribbon buttons with code-drawn
icons, a mirrored ruler for RTL paragraphs, translations, catalog,
parity and roadmap updates.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore(contributors): add Saeed Azarehgar to people.toml
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(engine): para.align with an explicit value sets it, without toggling
Only the alignment buttons toggle back to the start edge when pressed
again. para.align (used by the Paragraph dialog, scripts and agents) now
sets the requested alignment, as seen on the page, in each selected
paragraph's own direction. Previously pressing OK in the dialog with
Center or Right selected reset the paragraph to the start edge.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(ui): Direction option in the Paragraph dialog
Add Word's Direction (Right-to-left / Left-to-right) to the Paragraph
dialog's General section. The dialog now shows alignment and Left/Right
indents as seen on the page, mapping them to the paragraph's logical
start/end values on OK, so an unchanged OK no longer flips a
right-to-left paragraph. OK logic moved to apply_paragraph, with tests;
ja/zh translations.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(layout): allow hanging trailing spaces in the RTL display test
A wrapped right-to-left line's trailing spaces hang past its end edge
(the left margin), as left-to-right lines hang them past the right. The
test failed whenever the loaded fallback fonts made a line end there;
it now checks only visible glyphs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Character border (format.border): w:bdr run property, toggle command, boxed rendering
* Character border: Home > Font ribbon button and icon
* Character border: address review (plain notes), translate ribbon label, fix flaky layout test and clippy nonminimal_bool
* Tests: merge the fixture imports after merging main
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n: Spanish and Brazilian Portuguese labels for Character Border
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: WordCraft agent <agent@localhost>
Co-authored-by: 999sian <999sian@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>