How OfficeCLI Handles i18n and RTL Documents in Microsoft Word: A Complete Technical Guide
OfficeCLI handles i18n and RTL word documents through a centralized cascade system in WordHandler.I18n.cs that applies three-level RTL markup (<w:bidi/>, <w:rtl/> on paragraph-marks, and <w:rtl/> on every run) while detecting inheritance from styles, sections, and defaults to prevent validation errors and mixed-direction bugs.
Internationalization support in command-line document tools is often an afterthought, but OfficeCLI treats right-to-left scripts as a first-class concern. The implementation ensures Arabic, Hebrew, and other RTL documents maintain proper formatting without producing invalid Word XML. This article breaks down the exact mechanisms the tool uses to handle directionality, complex-script formatting, and inheritance detection.
RTL Cascade Architecture
The core of OfficeCLI's RTL handling lives in src/officecli/Handlers/Word/WordHandler.I18n.cs. The cascade architecture applies directionality at three distinct levels to match Word's internal expectations.
Three-Level Markup Application
The ApplyDirectionCascade method implements the complete markup pattern required for proper RTL rendering:
<w:bidi/>on paragraph properties — signals the paragraph base direction<w:rtl/>on the paragraph-mark run properties — sets direction for the paragraph marker itself<w:rtl/>on every run inside the paragraph — ensures consistent character-level direction
This triple application prevents the "mixed bidi" scenario where paragraph direction conflicts with run direction, which causes unpredictable cursor behavior and layout bugs in Word.
// Apply complete RTL cascade to a paragraph
handler.ApplyDirectionCascade(para, rtl: true);
When setting rtl: false, the method becomes idempotent: it strips existing RTL markup and, critically, emits <w:bidi w:val="false"/> when any higher-level source still forces RTL. This explicit override prevents silent inheritance that would otherwise surprise users.
Schema-Correct XML Insertion
Word's Open XML schema is strict about element order. The helper EnsureParagraphMarkRunPropertiesInSchemaOrder (lines 13-22 of WordHandler.I18n.cs) inserts <w:rPr> at the exact required location in the pPr tree. Without this, documents fail validation against the Office Open XML strict schema.
Inheritance Detection System
RTL direction in Word can originate from multiple sources: section properties, paragraph styles, document defaults, or numbering levels. OfficeCLI traces all of them.
HasInheritedBidi: The Source Walker
The HasInheritedBidi method (lines 24-30) walks every possible RTL source to determine whether an explicit LTR setting needs to cancel inherited RTL. This powers both the cascade logic and the direction=ltr handler in the CLI.
StyleChainHasBidi: Following the basedOn Chain
Paragraph styles in Word form inheritance chains through the basedOn attribute. StyleChainHasBidi (lines 67-73) follows this chain recursively, stopping at the first explicit bidi true or false value—mirroring Word's own resolver exactly.
// Checking if a style chain forces RTL inheritance
bool hasBidiInChain = StyleChainHasBidi(styleId, stylesPart);
Complex-Script (CS) Run Formatting
RTL languages require distinct font, size, and emphasis properties. OfficeCLI preserves these through ReadComplexScriptRunFormatting, which extracts:
- Font:
<w:rFonts cs/>→"font.cs" - Size:
<w:szCs/>→"size.cs" - Bold:
<w:bCs/>→"bold.cs" - Italic:
<w:iCs/>→"italic.cs"
The implementation respects explicit off-toggles like <w:bCs w:val="0"/>. This ensures round-tripping preserves intentional overrides that prevent unwanted inheritance in mixed-script documents.
var format = new Dictionary<string, object?>();
WordHandler.ReadComplexScriptRunFormatting(run, null, format);
// format["bold.cs"] will be false if <w:bCs w:val="0"/> exists,
// null if absent, or true if <w:bCs/> or <w:bCs w:val="1"/>
Integration Points Across the Codebase
Set Command (WordHandler.Set.cs)
The CLI's set command parses direction keywords and routes to the cascade:
| User Input | Internal Action |
|---|---|
rtl, direction=rtl |
ApplyDirectionCascade(para, rtl: true) |
ltr, direction=ltr |
ApplyDirectionCascade(para, rtl: false) with inheritance check |
# CLI usage to force RTL on first paragraph
officecli set paragraph[1] direction=rtl
Selectors (WordHandler.Selector.cs)
Read-back operations expose computed effective direction through three keys:
rtl— boolean indicating RTL presencedirection— string"rtl"or"ltr"bidi— raw<w:bidi/>element state
These respect the same inheritance chain used for writing, ensuring consistency between read and write operations.
Table Context Detection (IsTableContextRtl)
When inserting tables, IsTableContextRtl checks whether the surrounding section carries RTL defaults. If so, the table implementation auto-stamps <w:bidiVisual/> on table properties—required for proper cell ordering in RTL contexts.
bool contextIsRtl = handler.IsTableContextRtl(parentSection);
if (contextIsRtl) {
tableProps.Append(new BiDiVisual());
}
Section-Level RTL (WordHandler.Set.SectionLayout.cs)
For document-level RTL control, the implementation handles <w:rtlGutter/> in section properties, affecting page layout margins in RTL locales.
File Reference Map
| File | Responsibility | Lines of Interest |
|---|---|---|
WordHandler.I18n.cs |
Core cascade, inheritance, CS formatting | 13-73 |
WordHandler.Set.cs |
CLI key parsing, routing to cascade | — |
WordHandler.Selector.cs |
Effective direction read-back | — |
WordHandler.StyleList.cs |
effective.rtl in style queries |
— |
WordHandler.Set.SectionLayout.cs |
Section-level RTL gutter | — |
Summary
-
OfficeCLI implements complete RTL handling through
ApplyDirectionCascadeinWordHandler.I18n.cs, applying three-level markup required by Word's Open XML schema. -
Inheritance detection via
HasInheritedBidiandStyleChainHasBidiprevents silent RTL propagation and enables explicit LTR overrides. -
Complex-script formatting preserves explicit off-toggles for fonts, sizes, and emphasis to maintain round-trip fidelity.
-
Integration across the codebase ensures tables, sections, styles, and runs all respect consistent directionality rules.
-
Schema-correct output uses
EnsureParagraphMarkRunPropertiesInSchemaOrderto place XML elements in valid order, avoiding validation failures.
Frequently Asked Questions
What happens if I set direction=ltr on a paragraph that inherits RTL from its style?
OfficeCLI detects the inherited RTL via HasInheritedBidi, then emits <w:bidi w:val="false"/> explicitly to override the style, rather than simply removing local markup. This forces LTR appearance regardless of upstream direction settings.
Does OfficeCLI handle mixed RTL/LTR documents correctly?
Yes. The per-run <w:rtl/> application ensures individual runs maintain their specified direction even within paragraphs of opposite base direction. The CLI preserves explicit directional overrides at the run level while managing paragraph defaults through the cascade.
How does the tool prevent invalid Open XML when modifying RTL properties?
The EnsureParagraphMarkRunPropertiesInSchemaOrder helper inserts <w:rPr> elements at schema-mandated positions within <w:pPr> trees. Additionally, all XML mutations go through the OpenXml SDK's DOM rather than string manipulation, ensuring structural validity.
Can I query the effective RTL direction of a paragraph through the CLI?
Yes. The selector system in WordHandler.Selector.cs exposes rtl, direction, and bidi keys that compute effective direction by walking the same inheritance chain used for writing—section properties, style chains, document defaults, and local overrides.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →