Skip to content

feat(docx): CJK typography presets (typography.preset=zh-body/zh-first-indent) - #378

Open
ylz92871-dotcom wants to merge 1 commit into
iOfficeAI:mainfrom
ylz92871-dotcom:pr/cjk-typography-preset
Open

ylz92871-dotcom wants to merge 1 commit into
iOfficeAI:mainfrom
ylz92871-dotcom:pr/cjk-typography-preset

Conversation

@ylz92871-dotcom

@ylz92871-dotcom ylz92871-dotcom commented Sep 10, 2026

Copy link
Copy Markdown

What

Adds two named CJK typography presets for DOCX paragraph set:

  • typography.preset=zh-body — pins an East Asian body face (SimSun/宋体) on every run and the paragraph mark, and sets a CJK-friendly body rhythm: lineRule=atLeast, single line (240), spaceAfter=0.
  • typography.preset=zh-first-indent — sets w:ind/@w:firstLineChars=200 (exactly 2 characters, regardless of font size) and clears any hard w:firstLine so the char-relative rule is the only indent source.

Unknown values throw with the supported list (zh-body, zh-first-indent).

Why

Chinese-language documents need these two settings on essentially every body paragraph:

  • CJK glyphs resolve through the OOXML East Asian font slot, which is currently left unset — mixed Chinese/Latin text renders with a fallback EA face (等线 from docDefaults) instead of a deterministic 宋体, and there is no one-key way to pin it.
  • First-line indent in Chinese typography is measured in characters (首行缩进 2 字符), not points. w:firstLine in twips drifts whenever the font size changes, while w:firstLineChars stays correct at any size.

Today this requires raw OOXML edits (raw-set); this makes it a single paragraph Set key with the same ergonomics as the existing indent/lineSpacing props.

How to verify

officecli create demo.docx
officecli add demo.docx /body --type paragraph --prop "text=这是中文正文示例"
officecli add demo.docx /body --type paragraph --prop "text=需要缩进的段落"
officecli set demo.docx "/body/p[1]" --prop "typography.preset=zh-body"
officecli set demo.docx "/body/p[2]" --prop "typography.preset=zh-first-indent"
officecli get demo.docx "/body/p[1]"
officecli get demo.docx "/body/p[2]"
officecli close demo.docx

Actual terminal output (before any preset — East Asia font falls back to docDefaults 等线):

/body/p[@paraId=00100000] (paragraph) "这是中文正文示例" style=Normal effective.size=11pt effective.size.src=/docDefaults effective.font.eastAsia=等线 effective.font.eastAsia.src=/docDefaults ...
/body/p[@paraId=00100000]/r[1] (run) "这是中文正文示例" effective.font.eastAsia=等线 effective.font.eastAsia.src=/docDefaults ...

After typography.preset=zh-body on p[1] — eastAsia explicitly pinned to SimSun on the paragraph mark and the run, rhythm switched to atLeast/single/no-space-after:

Updated /body/p[1]: typography.preset=zh-body
  WARNING: zh-body preset: eastAsia font set to 'SimSun' on all runs of this paragraph

/body/p[@paraId=00100000] (paragraph) "这是中文正文示例" style=Normal spaceAfter=0pt lineSpacing=12pt lineRule=atLeast font.ea=SimSun effective.font.eastAsia=SimSun ...
/body/p[@paraId=00100000]/r[1] (run) "这是中文正文示例" font.ea=SimSun effective.font.eastAsia=SimSun ...

After typography.preset=zh-first-indent on p[2] — char-relative 2-char first-line indent:

/body/p[@paraId=00100002] (paragraph) "需要缩进的段落" style=Normal firstLineChars=200 ...

Opening the resulting demo.docx in Word shows the body paragraph in 宋体 with single spacing and the second paragraph indented exactly 2 characters.

Implementation

  • src/officecli/Handlers/Word/WordHandler.Set.Element.cs — new case "typography.preset" next to ind.hanging. The presets are compound (they need both the paragraph's runs and the paragraph mark in hand), so they live at the Set.Element level rather than ApplyParagraphLevelProperty.
  • src/officecli/Handlers/Word/WordHandler.Helpers.Style.csApplyTypography_Body_Zh helper: run-level rFonts/@w:eastAsia="SimSun" (respecting CT_RPr child order), the same face on the paragraph-mark rPr, w:spacing = atLeast/240/after 0, plus a warning noting the font change so the set reports applied-with-notice.
  • src/officecli/CommandBuilder.cs"typography.preset" added to KnownProps so suggestion/error paths recognize the key.

No other behavior changes; nothing else touched.

Tests

Verified with a local test harness (kept repo-untracked, matching d8e7630's "local-only test project" policy):

  • CJK preset suite: eastAsia=SimSun on runs, lineRule=atLeast + spaceAfter=0, firstLineChars=200 with a hard w:firstLine cleared — all green (CJK DOCX typography-preset tests passed.).
  • XLSX numeric-fit regression suite — green (XLSX numeric-fit issue tests passed.).
  • dotnet build -c Release — 0 errors.
  • dotnet publish -c Release — single-file exe smoke OK (runs, reports version).

…t-indent)

zh-body: eastAsia SimSun on runs + mark, atLeast single rhythm, spaceAfter 0.
zh-first-indent: w:firstLineChars=200 (2 chars), clears w:firstLine.

Tests: CJK preset suite green (eastAsia SimSun, atLeast/0, firstLineChars 200); XLSX numeric-fit regression green; publish single-file smoke.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant