Paragraph dialog: mirror indents, same-style spacing, suppress line numbers, don't hyphenate (#512) (#519)

- Model: `ParaProps::mirror_indents` (`w:mirrorIndents`, ECMA-376 §17.3.1.18), read and
  written in DOCX; resolved `mirror_indents` and `suppress_line_numbers` (so styles count).
- Layout: a paragraph with mirrored indents moves over by its indents' difference on even
  (left-hand) pages, so its left (inside) indent is on the right there.
- Paragraph dialog: Mirror indents (Left/Right become Inside/Outside), Don't add space between
  paragraphs of the same style, and Formatting exceptions (Suppress line numbers, Don't
  hyphenate) on Line and Page Breaks; OK sends only the options that changed, in the same
  `para.set` as the indents and spacing.
- Strings in all nine catalogs; Reveal Formatting names mirrorIndents.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
Valentin Klein
2026-10-11 18:50:28 -04:00
committed by GitHub
co-authored by Claude Opus 5.5 Brandon Thomas
parent ee04e2b7f8
commit b0431eadc2
23 changed files with 195 additions and 21 deletions
+2
View File
@@ -131,6 +131,7 @@ Ranked, to beta (detail and remaining milestones in [docs/roadmap.md](docs/roadm
| Date | What landed |
|---|---|
| 2026-10-11 | Paragraph dialog options (#512): mirror indents (`w:mirrorIndents`, laid out on even pages), same-style spacing, suppress line numbers, don't hyphenate |
| 2026-10-11 | Screen readers can read the document canvas (#488): paragraphs, headings, lists, tables, links, pictures and the caret exposed through AccessKit |
| 2026-10-11 | Compare / Combine dialog with comparison settings, Restrict Editing pane (exceptions, SHA-512 password, locked styles; DOCX round trip), AutoCorrect Options dialog saved per user (#412) |
| 2026-10-11 | WordArt (#416): text fill/outline/shadow/glow/reflection, Transform warps, our own styles; straight/elbow/curved connectors glued to shapes that re-route; DOCX round trip |
@@ -171,6 +172,7 @@ Ranked, to beta (detail and remaining milestones in [docs/roadmap.md](docs/roadm
| Date | Change | Summary |
|---|---|---|
| 2026-10-11 | trivial | Progress log: Paragraph dialog options, mirror indents (#512) |
| 2026-10-11 | trivial | Progress log: content controls (#381) |
| 2026-10-11 | trivial | Progress log: Insert › Chart (#409); catalog 408/439 (92.9%) |
| 2026-10-11 | trivial | Progress log: Line Numbers, Hyphenation, Language, Envelopes and Labels dialogs (#407) |
+5 -1
View File
@@ -664,6 +664,10 @@ pub struct ParaProps {
/// Ignore space before/after between paragraphs of the same style.
#[serde(skip_serializing_if = "Option::is_none")]
pub contextual_spacing: Option<bool>,
/// `w:mirrorIndents` (ECMA-376 §17.3.1.18): the left and right indents are the inside and
/// outside ones, so they swap sides on even (left-hand) pages.
#[serde(skip_serializing_if = "Option::is_none")]
pub mirror_indents: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keep_next: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
@@ -728,7 +732,7 @@ pub struct ParaProps {
impl ParaProps {
pub fn overlay(&mut self, patch: &ParaProps) {
overlay_fields!(self, patch; style, align, indent_left, indent_right, indent_first, space_before, space_after, line_spacing,
contextual_spacing, keep_next, keep_lines, page_break_before, widow_control, outline_level, numbering, tabs, shading, borders,
contextual_spacing, mirror_indents, keep_next, keep_lines, page_break_before, widow_control, outline_level, numbering, tabs, shading, borders,
suppress_hyphens, suppress_line_numbers, bidi, drop_cap, kinsoku, word_wrap, overflow_punct, top_line_punct, auto_space_de, auto_space_dn,
snap_to_grid);
}
+5
View File
@@ -140,6 +140,8 @@ pub struct ResolvedPara {
pub space_after: f32,
pub line_spacing: LineSpacing,
pub contextual_spacing: bool,
/// Left/right indents are inside/outside: they swap on even pages.
pub mirror_indents: bool,
pub keep_next: bool,
pub keep_lines: bool,
pub page_break_before: bool,
@@ -152,6 +154,7 @@ pub struct ResolvedPara {
pub bidi: bool,
pub drop_cap: u8,
pub suppress_hyphens: bool,
pub suppress_line_numbers: bool,
/// Asian typography (see `ParaProps`): East Asian line-breaking rules.
pub kinsoku: bool,
/// Latin words wrap whole (`false`: they may break at any character).
@@ -195,6 +198,7 @@ impl ResolvedPara {
LineSpacing::Exactly(v) => LineSpacing::Exactly(if v.is_finite() { v.clamp(0.7, 1584.0) } else { 12.0 }),
},
contextual_spacing: p.contextual_spacing.unwrap_or(false),
mirror_indents: p.mirror_indents.unwrap_or(false),
keep_next: p.keep_next.unwrap_or(false),
keep_lines: p.keep_lines.unwrap_or(false),
page_break_before: p.page_break_before.unwrap_or(false),
@@ -207,6 +211,7 @@ impl ResolvedPara {
bidi: p.bidi.unwrap_or(false),
drop_cap: p.drop_cap.unwrap_or(0).min(10),
suppress_hyphens: p.suppress_hyphens.unwrap_or(false),
suppress_line_numbers: p.suppress_line_numbers.unwrap_or(false),
kinsoku: p.kinsoku.unwrap_or(true),
word_wrap: p.word_wrap.unwrap_or(true),
overflow_punct: p.overflow_punct.unwrap_or(true),
+1
View File
@@ -155,6 +155,7 @@ impl PropCtx {
"w:pageBreakBefore" => p.page_break_before = Some(on_off(k)),
"w:widowControl" => p.widow_control = Some(on_off(k)),
"w:contextualSpacing" => p.contextual_spacing = Some(on_off(k)),
"w:mirrorIndents" => p.mirror_indents = Some(on_off(k)),
"w:suppressAutoHyphens" => p.suppress_hyphens = Some(on_off(k)),
"w:suppressLineNumbers" => p.suppress_line_numbers = Some(on_off(k)),
"w:bidi" => p.bidi = Some(on_off(k)),
+1
View File
@@ -306,6 +306,7 @@ pub fn ppr_inner(w: &mut W, p: &ParaProps, framed: bool, num_change: Option<&Cha
w.empty("w:ind", &a);
}
toggle(w, "w:contextualSpacing", p.contextual_spacing);
toggle(w, "w:mirrorIndents", p.mirror_indents);
if let Some(a) = p.align {
w.val("w:jc", align_val(a));
}
+1
View File
@@ -140,6 +140,7 @@ fn every_para_prop_round_trips() {
space_after: Some(12.0),
line_spacing: Some(LineSpacing::Multiple(1.5)),
contextual_spacing: Some(true),
mirror_indents: Some(true),
keep_next: Some(true),
keep_lines: Some(false),
page_break_before: Some(true),
+14 -2
View File
@@ -2449,7 +2449,9 @@ fn place_para(ctx: &mut Ctx, pb: &mut PageBuilder, p: &Paragraph, block: usize,
// Relative, so a bottom moved down for notes continuing on the next page stays put.
pb.bottom -= pb.notes_h() - before;
}
let x = pb.col_x();
// Mirror indents: on an even (left-hand) page the inside indent is on the right, so the
// paragraph's lines (broken for the same width) move over by the indents' difference.
let x = pb.col_x() + mirror_shift(&pl.rp, pb.number, pb.web);
let y = pb.y + lead;
// Notes that no longer fit below the text (a long one, or the rest of one continued from
// the page before) get what's left under it and continue on the next page.
@@ -2472,7 +2474,7 @@ fn place_para(ctx: &mut Ctx, pb: &mut PageBuilder, p: &Paragraph, block: usize,
let (behind, front) = place_objects(ctx, StoryRef::Body, &[block as u32], p, &pl, (l0, l1), (x, y), &at, &float_rects, 0);
items.extend(front);
// Line numbers in the left margin.
if let Some(ln) = pb.sect.line_numbers.clone().filter(|_| !pb.web && pl.rp.style != "Header" && p.props.suppress_line_numbers != Some(true))
if let Some(ln) = pb.sect.line_numbers.clone().filter(|_| !pb.web && pl.rp.style != "Header" && !pl.rp.suppress_line_numbers)
&& let Some(first) = pl.lines.get(l0)
{
for li in l0..l1 {
@@ -2527,6 +2529,16 @@ fn place_para(ctx: &mut Ctx, pb: &mut PageBuilder, p: &Paragraph, block: usize,
pb.prev = Some((pl.rp.style.clone(), pl.rp.contextual_spacing, pl.rp.space_after));
}
/// How far a paragraph with mirrored indents (`w:mirrorIndents`) moves right on page `number`:
/// its left and right indents are the inside and outside ones, which swap sides on even pages.
fn mirror_shift(rp: &wordcraft_doc::resolve::ResolvedPara, number: u32, web: bool) -> f32 {
if !rp.mirror_indents || web || !number.is_multiple_of(2) {
return 0.0;
}
let (left, right) = rp.visual_indents();
right - left
}
/// Height of the first line of the block after `block` (for keep-with-next).
fn next_first_line(ctx: &mut Ctx, block: usize, width: f32) -> f32 {
match ctx.doc.body.get(block + 1).map(|b| &**b) {
+20
View File
@@ -3397,6 +3397,26 @@ fn rotated_canvas_draws_its_clipped_members_inside_the_turn() {
}
}
#[test]
fn mirror_indents_swap_sides_on_even_pages() {
// #512: with mirrored indents the left indent is the inside one, on the right of an even page.
let mut d = Document::from_text("odd page\neven page");
let last = Pos::body(1, 0);
d.format_paragraphs(&Pos::body(0, 0), &last, &|p| {
p.indent_left = Some(72.0);
p.mirror_indents = Some(true);
})
.unwrap();
d.format_paragraphs(&last, &last, &|p| p.page_break_before = Some(true)).unwrap();
let l = lay(&d);
assert_eq!(l.pages.len(), 2);
let odd = l.caret(&Pos::body(0, 0)).unwrap();
let even = l.caret(&last).unwrap();
assert_eq!(even.page, 1);
assert!((odd.x - 144.0).abs() < 0.5, "odd page: inside indent on the left, {odd:?}");
assert!((even.x - 72.0).abs() < 0.5, "even page: the left side has the outside indent (0), {even:?}");
}
/// Ten short paragraphs in a two-column section (`widths`: unequal columns), then one paragraph
/// in a one-column section starting `start`.
fn two_column_section(start: wordcraft_doc::section::SectionStart, widths: Vec<(f32, f32)>) -> Document {
+97 -18
View File
@@ -63,6 +63,12 @@ pub enum Dialog {
/// `asian` when the dialog opened: OK sets only the flags that changed.
#[serde(skip)]
asian_was: [bool; 6],
/// Mirror indents, don't add space between paragraphs of the same style, suppress line
/// numbers, don't hyphenate (#512).
opts: [bool; 4],
/// `opts` when the dialog opened: OK sets only the ones that changed.
#[serde(skip)]
opts_was: [bool; 4],
},
/// Tabs (#320).
Tabs {
@@ -834,6 +840,8 @@ impl Dialog {
tab: if name == "asianTypography" { 2 } else { 0 },
asian: [rp.kinsoku, rp.word_wrap, rp.overflow_punct, rp.top_line_punct, rp.auto_space_de, rp.auto_space_dn],
asian_was: [rp.kinsoku, rp.word_wrap, rp.overflow_punct, rp.top_line_punct, rp.auto_space_de, rp.auto_space_dn],
opts: [rp.mirror_indents, rp.contextual_spacing, rp.suppress_line_numbers, rp.suppress_hyphens],
opts_was: [rp.mirror_indents, rp.contextual_spacing, rp.suppress_line_numbers, rp.suppress_hyphens],
}
}
"tabs" => Dialog::Tabs { form: Box::new(crate::dialogs_para::TabsForm::read(app)?) },
@@ -1316,6 +1324,8 @@ fn body(app: &mut WordApp, ui: &mut Ui, d: &mut Dialog) -> bool {
tab,
asian,
asian_was,
opts,
opts_was,
} => {
ui.horizontal(|ui| {
for (k, name) in ["Indents and Spacing", "Line and Page Breaks", "Asian Typography"].into_iter().enumerate() {
@@ -1344,16 +1354,19 @@ fn body(app: &mut WordApp, ui: &mut Ui, d: &mut Dialog) -> bool {
});
});
ui.label(egui::RichText::new(tl!("Indentation")).font(semibold(12.5)));
// Mirrored indents are the inside and outside ones (they swap on even pages).
let (l_label, r_label) = if opts[0] { ("Inside:", "Outside:") } else { ("Left:", "Right:") };
egui::Grid::new("ind").num_columns(4).show(ui, |ui| {
ui.label(tl!("Left:"));
ui.label(tl!(l_label));
ui.add(egui::DragValue::new(left).speed(0.05).suffix("\"").max_decimals(2));
ui.label(tl!("Right:"));
ui.label(tl!(r_label));
ui.add(egui::DragValue::new(right).speed(0.05).suffix("\"").max_decimals(2));
ui.end_row();
ui.label(tl!("First line:"));
ui.add(egui::DragValue::new(first).speed(0.05).suffix("\"").max_decimals(2));
ui.end_row();
});
ui.checkbox(&mut opts[0], tl!("Mirror indents"));
ui.label(egui::RichText::new(tl!("Spacing")).font(semibold(12.5)));
egui::Grid::new("sp").num_columns(4).show(ui, |ui| {
ui.label(tl!("Before:"));
@@ -1365,6 +1378,7 @@ fn body(app: &mut WordApp, ui: &mut Ui, d: &mut Dialog) -> bool {
ui.add(egui::DragValue::new(after).speed(1.0).range(0.0..=1584.0).suffix(format!(" {}", tl!("pt"))));
ui.end_row();
});
ui.checkbox(&mut opts[1], tl!("Don't add space between paragraphs of the same style"));
}
1 => {
ui.label(egui::RichText::new(tl!("Line and Page Breaks")).font(semibold(12.5)));
@@ -1372,6 +1386,9 @@ fn body(app: &mut WordApp, ui: &mut Ui, d: &mut Dialog) -> bool {
ui.checkbox(keep_next, tl!("Keep with next"));
ui.checkbox(keep_lines, tl!("Keep lines together"));
ui.checkbox(page_break, tl!("Page break before"));
ui.label(egui::RichText::new(tl!("Formatting exceptions")).font(semibold(12.5)));
ui.checkbox(&mut opts[2], tl!("Suppress line numbers"));
ui.checkbox(&mut opts[3], tl!("Don't hyphenate"));
}
_ => {
let [kinsoku, word_wrap, overflow, top_line, de, dn] = asian;
@@ -1393,7 +1410,19 @@ fn body(app: &mut WordApp, ui: &mut Ui, d: &mut Dialog) -> bool {
let tabs = ui.button(tl!("Tabs…")).clicked();
let (ok, cancel) = buttons(ui, tl!("OK"));
if ok || tabs {
apply_paragraph(app, *rtl, align, *left, *right, *first, *before, *after, *line, [*keep_next, *keep_lines, *page_break, *widow]);
apply_paragraph(
app,
*rtl,
align,
*left,
*right,
*first,
*before,
*after,
*line,
[*keep_next, *keep_lines, *page_break, *widow],
(*opts, *opts_was),
);
apply_asian(app, *asian, *asian_was);
}
// Tabs… keeps what was set here and moves on to the Tabs dialog.
@@ -2388,9 +2417,6 @@ fn recipient_list(app: &mut WordApp, ui: &mut Ui, fields: &mut Vec<String>, rows
}
}
/// The Paragraph dialog's OK. `align`, `left` and `right` are as seen on the page; `flags` are
/// keep with next, keep lines together, page break before, widow/orphan control.
#[allow(clippy::too_many_arguments)]
/// The Table Properties dialog's fields: Table, Row, Column and Cell sections.
fn table_properties(ui: &mut Ui, f: &mut TableForm) {
let unit = wordcraft_geom::Unit::default();
@@ -2460,6 +2486,11 @@ fn table_properties(ui: &mut Ui, f: &mut TableForm) {
});
}
/// The Paragraph dialog's OK. `align`, `left` and `right` are as seen on the page; `flags` are
/// keep with next, keep lines together, page break before, widow/orphan control; `opts` (now,
/// when opened) are mirror indents, contextual spacing, suppress line numbers and don't
/// hyphenate, of which only the changed ones are set.
#[allow(clippy::too_many_arguments)]
fn apply_paragraph(
app: &mut WordApp,
rtl: bool,
@@ -2471,6 +2502,7 @@ fn apply_paragraph(
after: f32,
line: f32,
flags: [bool; 4],
opts: ([bool; 4], [bool; 4]),
) {
let [keep_next, keep_lines, page_break, widow] = flags;
// Direction first: the alignment and indents are as seen on the page, and their logical
@@ -2478,14 +2510,21 @@ fn apply_paragraph(
let _ = app.run(if rtl { "para.rtl" } else { "para.ltr" }, json!({}));
let _ = app.run("para.align", json!({"value": align}));
let (start, end) = if rtl { (right, left) } else { (left, right) };
let _ = app.run(
"para.set",
json!({"props": {
"indentLeft": start * 72.0, "indentRight": end * 72.0, "indentFirst": first * 72.0,
"spaceBefore": before, "spaceAfter": after, "lineSpacing": {"rule": "multiple", "value": line},
"keepNext": keep_next, "keepLines": keep_lines, "pageBreakBefore": page_break, "widowControl": widow,
}}),
);
let mut props = json!({
"indentLeft": start * 72.0, "indentRight": end * 72.0, "indentFirst": first * 72.0,
"spaceBefore": before, "spaceAfter": after, "lineSpacing": {"rule": "multiple", "value": line},
"keepNext": keep_next, "keepLines": keep_lines, "pageBreakBefore": page_break, "widowControl": widow,
});
let (now, was) = opts;
for (key, (on, was)) in ["mirrorIndents", "contextualSpacing", "suppressLineNumbers", "suppressHyphens"].into_iter().zip(now.into_iter().zip(was))
{
if on != was
&& let Some(m) = props.as_object_mut()
{
m.insert(key.into(), json!(on));
}
}
let _ = app.run("para.set", json!({ "props": props }));
}
/// The Paragraph dialog's Asian Typography: sets the flags that changed since it opened, so an
@@ -2827,12 +2866,40 @@ mod tests {
/// Open the Paragraph dialog and press OK without changing anything.
fn ok_unchanged(app: &mut WordApp) {
let Some(Dialog::Paragraph { rtl, align, left, right, first, before, after, line, keep_next, keep_lines, page_break, widow, .. }) =
Dialog::open("paragraph", app)
ok_with(app, |_| {});
}
/// Open the Paragraph dialog, change its options (`opts`) with `edit` and press OK.
fn ok_with(app: &mut WordApp, edit: impl FnOnce(&mut [bool; 4])) {
let Some(Dialog::Paragraph {
rtl, align, left, right, first, before, after, line, keep_next, keep_lines, page_break, widow, mut opts, ..
}) = Dialog::open("paragraph", app)
else {
panic!("no paragraph dialog")
};
apply_paragraph(app, rtl, &align, left, right, first, before, after, line, [keep_next, keep_lines, page_break, widow]);
let was = opts;
edit(&mut opts);
apply_paragraph(app, rtl, &align, left, right, first, before, after, line, [keep_next, keep_lines, page_break, widow], (opts, was));
}
#[test]
fn paragraph_dialog_sets_only_the_options_that_changed() {
// #512: mirror indents, same-style spacing, suppress line numbers, don't hyphenate.
let mut app = app_with("Hello");
ok_unchanged(&mut app);
let p = props(&app);
assert_eq!((p.mirror_indents, p.contextual_spacing, p.suppress_line_numbers, p.suppress_hyphens), (None, None, None, None));
ok_with(&mut app, |o| *o = [true; 4]);
let p = props(&app);
assert_eq!(
(p.mirror_indents, p.contextual_spacing, p.suppress_line_numbers, p.suppress_hyphens),
(Some(true), Some(true), Some(true), Some(true))
);
let Some(Dialog::Paragraph { opts, .. }) = Dialog::open("paragraph", &mut app) else { panic!() };
assert_eq!(opts, [true; 4], "the dialog shows what is set");
ok_with(&mut app, |o| o[3] = false);
assert_eq!(props(&app).suppress_hyphens, Some(false));
assert_eq!(props(&app).mirror_indents, Some(true));
}
#[test]
@@ -2870,7 +2937,19 @@ mod tests {
panic!()
};
// Right to left, aligned right on the page, 1" from the right edge.
apply_paragraph(&mut app, true, "right", left, right + 1.0, first, before, after, line, [keep_next, keep_lines, page_break, widow]);
apply_paragraph(
&mut app,
true,
"right",
left,
right + 1.0,
first,
before,
after,
line,
[keep_next, keep_lines, page_break, widow],
([false; 4], [false; 4]),
);
let _ = align;
let p = props(&app);
assert_eq!(p.bidi, Some(true));
+4
View File
@@ -84,19 +84,23 @@
Enter formatting for number: Formato del número:
Follow number with: Después del número:
Formatting Formato
Formatting exceptions Excepciones de formato
Include level number from: Incluir número de nivel de:
Ink Entrada de lápiz
Insertions and Deletions Inserciones y eliminaciones
Insertions: Inserciones:
Inside: Interior:
Left border Borde izquierdo
Legal style numbering Numeración de estilo legal
Link level to style: Vincular nivel con estilo:
List Definition Definición de lista
Mirror indents Sangrías simétricas
Nothing Nada
Number alignment: Alineación del número:
Number format Formato de número
Number style for this level: Estilo de número para este nivel:
Outside border Borde exterior
Outside: Exterior:
Restart list after: Reiniciar lista después de:
Right border Borde derecho
Save the document to turn on AutoSave Guarda el documento para activar el autoguardado
Can't render this file because it contains an unexpected character in line 6 and column 25.
+4
View File
@@ -276,6 +276,7 @@
Format Painter Vormingupintsel
Formatted Text Vormindatud tekst
Formatting at Selection Valiku vormindus
Formatting exceptions Vormindamise erandid
Formula Valem
General Üldine
Go To Mine
@@ -347,6 +348,7 @@
Insert\nCitation Lisa\nviide
Insert\nFootnote Lisa\nallmärkus
Inside Borders Siseäärised
Inside: Sisemine:
Inspect Document Kontrolli dokumenti
Inspect Styles at Selection Kontrolli valiku stiile
Interface language: Kasutajaliidese keel:
@@ -390,6 +392,7 @@
Link to Previous Seo eelmisega
Links Lingid
Location: {path} Asukoht: {path}
Mirror indents Peegelda taanded
MIT OR Apache-2.0. Copyright (c) 2026 ArtCraft Team and the WordCraft contributors. MIT OR Apache-2.0. Autoriõigus (c) 2026 ArtCrafti meeskond ja WordCrafti kaasautorid.
Macros Makrod
Mailings Postitused
@@ -469,6 +472,7 @@
Outline Liigendus
Outline Level Liigendustase
Outside Borders Välisäärised
Outside: Välimine:
Oval Ovaal
PDF document (*.pdf) PDF-dokument (*.pdf)
Page Leht
Can't render this file because it contains an unexpected character in line 424 and column 13.
+4
View File
@@ -81,10 +81,12 @@
Enter formatting for number: 番号の書式:
Follow number with: 番号に続く文字:
Formatting 書式
Formatting exceptions 書式の例外
Include level number from: 含めるレベルの番号:
Ink インク
Insertions and Deletions 挿入と削除
Insertions: 挿入された箇所:
Inside: 内側:
Left border 左罫線
Left Margin 左余白
Indents and Spacing インデントと間隔
@@ -92,6 +94,7 @@
Line breaking 行の分割
Link level to style: レベルに対応付けるスタイル:
List Definition リストの定義
Mirror indents 左右対称のインデント
More templates → その他のテンプレート →
No templates match your search. 検索に一致するテンプレートはありません。
Nothing なし
@@ -99,6 +102,7 @@
Number format 番号書式
Number style for this level: このレベルの番号の種類:
Outside border 外側の罫線
Outside: 外側:
Reopen 再度開く
Restart list after: リストを振り直すレベル:
Right border 右罫線
1 # Japanese (ja) interface catalog. Same format and clean-room rules as zh-hans.tsv.
81
82
83
84
85
86
87
88
89
90
91
92
94
95
96
97
98
99
100
102
103
104
105
106
107
108
+4
View File
@@ -85,19 +85,23 @@
Enter formatting for number: Formatação do número:
Follow number with: Após o número:
Formatting Formatação
Formatting exceptions Exceções de formatação
Include level number from: Incluir número do nível:
Ink Tinta
Insertions and Deletions Inserções e exclusões
Insertions: Inserções:
Inside: Interno:
Left border Borda esquerda
Legal style numbering Numeração no estilo legal
Link level to style: Vincular nível ao estilo:
List Definition Definição da lista
Mirror indents Recuos espelhados
Nothing Nada
Number alignment: Alinhamento do número:
Number format Formato do número
Number style for this level: Estilo de número deste nível:
Outside border Borda externa
Outside: Externo:
Restart list after: Reiniciar lista após:
Right border Borda direita
Save the document to turn on AutoSave Salve o documento para ativar o salvamento automático
Can't render this file because it contains an unexpected character in line 6 and column 25.
+5
View File
@@ -2100,6 +2100,11 @@ preview Title Пример
Apply Применить
Convert Notes Преобразовать сноски
# Paragraph dialog options (#512).
Formatting exceptions Исключения форматирования
Inside: Внутри:
Mirror indents Зеркальные отступы
Outside: Снаружи:
# WordArt and connectors (#416).
WordArt Styles Стили WordArt
Text Fill Заливка текста
Can't render this file because it contains an unexpected character in line 7 and column 25.
+4
View File
@@ -108,20 +108,24 @@
Enter formatting for number: Oblik broja:
Follow number with: Posle broja:
Formatting Oblikovanje
Formatting exceptions Izuzeci formatiranja
Include level number from: Uključi broj nivoa:
Ink Mastilo
Insertions and Deletions Umetanja i brisanja
Insertions: Umetanja:
Inside: Unutra:
Left border Leva ivica
Left Margin Leva margina
Legal style numbering Pravno numerisanje
Link level to style: Poveži nivo sa stilom:
List Definition Definicija liste
Mirror indents Preslikaj uvlačenja
Nothing Ništa
Number alignment: Poravnanje broja:
Number format Format broja
Number style for this level: Stil broja za ovaj nivo:
Outside border Spoljna ivica
Outside: Spolja:
Reopen Ponovo otvori
Restart list after: Ponovo počni listu posle:
Right border Desna ivica
Can't render this file because it contains an unexpected character in line 6 and column 25.
+4
View File
@@ -112,20 +112,24 @@
Enter formatting for number: Облик броја:
Follow number with: После броја:
Formatting Обликовање
Formatting exceptions Изузеци форматирања
Include level number from: Укључи број нивоа:
Ink Мастило
Insertions and Deletions Уметања и брисања
Insertions: Уметања:
Inside: Унутра:
Left border Лева ивица
Left Margin Лева маргина
Legal style numbering Правно нумерисање
Link level to style: Повежи ниво са стилом:
List Definition Дефиниција листе
Mirror indents Пресликај увлачења
Nothing Ништа
Number alignment: Поравнање броја:
Number format Формат броја
Number style for this level: Стил броја за овај ниво:
Outside border Спољна ивица
Outside: Споља:
Reopen Поново отвори
Restart list after: Поново почни листу после:
Right border Десна ивица
Can't render this file because it contains an unexpected character in line 11 and column 25.
+5
View File
@@ -1722,6 +1722,11 @@
Apply Uygula
Convert Notes Notları Dönüştür
# Paragraph dialog options (#512).
Formatting exceptions Biçimlendirme özel durumları
Inside: İç:
Mirror indents Ayna girintiler
Outside: Dış:
# WordArt and connectors (#416).
WordArt Styles WordArt Stilleri
Text Fill Metin Dolgusu
Can't render this file because it contains an unexpected character in line 430 and column 13.
+4
View File
@@ -87,19 +87,23 @@
Enter formatting for number: Вигляд номера:
Follow number with: Після номера:
Formatting Форматування
Formatting exceptions Винятки форматування
Include level number from: Додати номер рівня:
Ink Рукописні примітки
Insertions and Deletions Вставлення й видалення
Insertions: Вставлення:
Inside: Усередині:
Left border Ліва межа
Legal style numbering Юридична нумерація
Link level to style: Зв'язати рівень зі стилем:
List Definition Визначення списку
Mirror indents Дзеркальні відступи
Nothing Нічого
Number alignment: Вирівнювання номера:
Number format Формат номера
Number style for this level: Стиль номера для цього рівня:
Outside border Зовнішня межа
Outside: Зовні:
Restart list after: Почати список знову після:
Right border Права межа
Save the document to turn on AutoSave Збережіть документ, щоб увімкнути автозбереження
Can't render this file because it contains an unexpected character in line 6 and column 31.
+4
View File
@@ -93,10 +93,12 @@
Enter formatting for number: 输入编号的格式:
Follow number with: 编号之后:
Formatting 格式
Formatting exceptions 格式例外
Include level number from: 包含的级别编号来自:
Ink 墨迹
Insertions and Deletions 插入和删除
Insertions: 插入内容:
Inside: 内侧:
Left border 左框线
Left Margin 左边距
Indents and Spacing 缩进和间距
@@ -104,6 +106,7 @@
Line breaking 断行
Link level to style: 将级别链接到样式:
List Definition 列表定义
Mirror indents 对称缩进
More templates → 更多模板 →
No templates match your search. 没有与搜索匹配的模板。
Nothing 无
@@ -111,6 +114,7 @@
Number format 编号格式
Number style for this level: 此级别的编号样式:
Outside border 外侧框线
Outside: 外侧:
Reopen 重新打开
Restart list after: 重新开始列表的级别:
Right border 右框线
Can't render this file because it contains an unexpected character in line 7 and column 25.
+4
View File
@@ -82,10 +82,12 @@
Enter formatting for number: 輸入編號的格式:
Follow number with: 編號之後:
Formatting 格式設定
Formatting exceptions 格式例外
Include level number from: 包含的層級編號來自:
Ink 筆跡
Insertions and Deletions 插入和刪除
Insertions: 插入內容:
Inside: 內側:
Left border 左框線
Left Margin 左邊界
Indents and Spacing 縮排和間距
@@ -93,6 +95,7 @@
Line breaking 斷行
Link level to style: 將層級連結到樣式:
List Definition 清單定義
Mirror indents 對稱縮排
More templates → 更多範本 →
No templates match your search. 沒有符合搜尋的範本。
Nothing 無
@@ -100,6 +103,7 @@
Number format 編號格式
Number style for this level: 此層級的編號樣式:
Outside border 外側框線
Outside: 外側:
Reopen 重新開啟
Restart list after: 重新開始清單的層級:
Right border 右框線
1 # Traditional Chinese (zh-hant, Taiwan vocabulary) interface catalog. Same format and clean-room
82
83
84
85
86
87
88
89
90
91
92
93
95
96
97
98
99
100
101
103
104
105
106
107
108
109
+1
View File
@@ -594,6 +594,7 @@ fn describe(prop: &str, v: &Value) -> String {
"spaceAfter" => "Space after",
"lineSpacing" => "Line spacing",
"contextualSpacing" => "Don't add space between paragraphs of the same style",
"mirrorIndents" => "Mirror indents",
"keepNext" => "Keep with next",
"keepLines" => "Keep lines together",
"pageBreakBefore" => "Page break before",
+1
View File
@@ -72,6 +72,7 @@ font can't match Word's metrics.
| Date | Change | Summary |
|---|---|---|
| 2026-10-11 | trivial | Mirror indents (`w:mirrorIndents`): left/right indents swap on even pages; suppress line numbers inherited from styles (#512) |
| 2026-10-11 | trivial | NUMPAGES/SECTIONPAGES in the body show the real totals (the body is laid out again once the page count is known, at most three extra passes, #451); footnotes referenced in table cells go to the page bottom (#450); PDF links to a bookmark go to the page its start is on, not its paragraph's first page (#455) |
| 2026-10-11 | trivial | Mirrored margins on even pages, tall and linked footers/headers push the body, long endnotes continue, caret in continued notes (#452, #453, #454, #456, #457) |
| 2026-10-11 | trivial | Hyphenation zone, words in capitals and consecutive-hyphen limit follow the document settings; Manual Hyphenation (#407) |
+1
View File
@@ -37,6 +37,7 @@ own (`AGENTS.md`: no Microsoft iconography, ever).
| Date | Change | Summary |
|---|---|---|
| 2026-10-11 | trivial | Paragraph dialog: Mirror indents (Inside/Outside labels), Don't add space between paragraphs of the same style, Formatting exceptions (Suppress line numbers, Don't hyphenate) (#512) |
| 2026-10-11 | trivial | Screen readers: the document canvas exposes paragraphs, headings, lists, tables, links, pictures and the caret through AccessKit (#488); 25% → 50% |
| 2026-10-11 | trivial | Compare / Combine Documents (original and revised document, label changes with, comparison settings, word or character level, show changes in) and AutoCorrect Options (replacement list, capitalization, exceptions, AutoFormat As You Type, Math AutoCorrect) dialogs; Restrict Editing pane (formatting and editing restrictions, exceptions for everyone, password); modal dialog rows merged into one (#412) |
| 2026-10-11 | trivial | Line Numbers, Hyphenation (with Manual Hyphenation), Language, Envelopes and Labels dialogs (#407); the three duplicated modal-dialog rows merged into one |