OfficeCLI i18n and RTL Support for Word Documents: Per-Script Fonts and Language Tags Explained
OfficeCLI implements full internationalization for Word documents by applying a three-level RTL cascade, mapping four per-script font slots, and managing three language tag variants to ensure perfect round-trip fidelity with OOXML.
The iOfficeAI/OfficeCLI repository provides robust internationalization (i18n) and right-to-left (RTL) support for Word documents through a granular approach to OOXML manipulation. By treating reading direction, per-script fonts, and language tags as separate orthogonal concerns, OfficeCLI ensures that Arabic, Hebrew, CJK, and Latin scripts render correctly while maintaining document integrity across edit cycles.
The RTL Direction Cascade
OfficeCLI handles text direction through a cascading application of OOXML elements defined in WordHandler.I18n.cs. When you set direction=rtl on a paragraph, the ApplyDirectionCascade method executes a three-step process that mirrors Microsoft Word's internal behavior.
Three-Level Element Application
The cascade applies RTL markers at distinct hierarchy levels:
- Paragraph container – Inserts
<w:bidi/>into<w:pPr>to force RTL layout for the entire paragraph - Paragraph mark – Adds
<w:rtl/>toParagraphMarkRunProperties(the invisible paragraph marker that Word's UI targets) - Run level – Applies
<w:rtl/>to every<w:r>element within the paragraph to reverse character order
This ensures visual consistency whether the document opens in Word, LibreOffice, or OfficeCLI's HTML preview.
Inheritance and Reversibility
The cascade is idempotent and reversible. When rtl=false or direction=ltr is set, ApplyDirectionCascade removes explicit <w:rtl/> elements from runs and clears the paragraph mark. It emits <w:bidi w:val="0"/> only when the paragraph would otherwise inherit RTL from styles, sections, or docDefaults.
Helper methods HasInheritedBidi and StyleChainHasBidi walk the inheritance chain (section → paragraph-style chain → docDefaults → numbering level) to determine whether an explicit override is necessary. This prevents unnecessary markup while preserving explicit user intent.
Per-Script Font Slots
OfficeCLI manages typography across writing systems through four distinct font slots defined in WordHandler.Helpers.RunFormat.cs. The ApplyRunFormatting method handles the <w:rFonts> element attributes: ascii, hAnsi, eastAsia, and cs (Complex Script).
Mapping Font Commands to OOXML
The CLI exposes these slots through intuitive key names:
font=– Setsascii,hAnsi, andeastAsiasimultaneously (Latin and CJK compatibility)font.cs=– Targets the Complex Script slot used for Arabic and Hebrew glyph shapingfont.latinandfont.ea– Provide granular access to Latin and East Asian slots
Theme font slots (asciiTheme, hAnsiTheme, eastAsiaTheme, csTheme) are mapped to <w:rFonts> theme attributes, enabling automatic font substitution when documents switch themes.
# Set a dedicated Arabic font for Complex Script text
officecli set /body/p[3] font.cs="Traditional Arabic"
# Apply a Japanese font to East Asian slot while keeping Latin unchanged
officecli set /body/p[3] font.ea="MS Mincho"
Language Tags and Localization
Language identification in OfficeCLI follows the OOXML <w:lang> specification with three distinct slots. The implementation in WordHandler.Helpers.RunFormat.cs stores these as separate keys in the format dictionary: lang.latin, lang.ea (East Asia), and lang.cs (Complex Script).
The Three Language Slots
Each slot serves a specific script category:
lang.latin(aliased aslang.val) – Primary language for Latin runs (e.g.,en-US)lang.ea(aliased aslang.eastasia) – Language for East Asian scripts (e.g.,zh-CN)lang.cs(aliased aslang.bidi) – Language for Complex Scripts like Arabic and Hebrew (e.g.,ar-SA)
When any slot is empty, the <w:lang> element is removed entirely to prevent stray markup. This preserves round-trip fidelity—exporting and re-importing the document yields identical OOXML structure.
# Assign per-script language tags to a paragraph
officecli set /body/p[3] \
lang.latin=en-US \
lang.ea=zh-CN \
lang.cs=ar-SA
HTML Preview Language Detection
OfficeCLI generates HTML previews with appropriate language attributes through WordHandler.HtmlPreview.cs. The htmlLang value derives from the document's theme font language (specifically the first non-empty eastAsia language) or explicit lang.latin settings.
The HTML output includes <html lang="..."> and <body dir="rtl"> attributes based on the document's detected language and direction, ensuring browsers apply correct text shaping and layout algorithms.
Practical Implementation Examples
Combining direction, fonts, and language tags requires understanding how WordHandler.Set.cs routes commands to specialized helpers:
# Complete RTL paragraph setup for Arabic text
officecli set /body/p[3] \
direction=rtl \
font.cs="Traditional Arabic" \
lang.cs=ar-SA
# Mixed-script document with specific fonts per slot
officecli set /body/p[4] \
font="Calibri" \
font.ea="SimSun" \
font.cs="Arial" \
lang.latin=en-US \
lang.ea=zh-CN \
lang.cs=he-IL
Behind the scenes, these commands invoke ApplyDirectionCascade for RTL handling and ApplyRunFormatting for font and language properties. All setters funnel through these centralized methods, guaranteeing consistent behavior across the Set command, Add helpers, and internal mutations.
Summary
- RTL cascade applies
<w:bidi>, paragraph-mark<w:rtl>, and run-level<w:rtl>elements throughApplyDirectionCascadeinWordHandler.I18n.cs - Per-script fonts map to four OOXML slots (
ascii,hAnsi,eastAsia,cs) with theme support viaApplyRunFormatting - Language tags use three distinct slots (
lang.latin,lang.ea,lang.cs) that correspond to OOXML<w:lang>attributes - Inheritance handling via
HasInheritedBidiensures explicit overrides only when necessary, maintaining clean markup - Round-trip fidelity eliminates empty elements and preserves exact structure between CLI commands and OOXML output
Frequently Asked Questions
How does OfficeCLI determine when to apply explicit LTR overrides?
OfficeCLI applies <w:bidi w:val="0"/> only when HasInheritedBidi detects that a paragraph would otherwise inherit RTL from parent styles, sections, or document defaults. This check walks the full inheritance chain including basedOn style relationships and numbering levels, ensuring explicit overrides appear solely to cancel inherited RTL values.
What is the difference between font.cs and the standard font command in OfficeCLI?
The font command sets the ascii, hAnsi, and eastAsia attributes simultaneously for broad compatibility, while font.cs specifically targets the Complex Script slot used by Arabic, Hebrew, and other RTL scripts requiring contextual glyph shaping. For multilingual documents, you typically set font for the base Latin typeface and font.cs for the Arabic or Hebrew typeface.
Can OfficeCLI remove language tags or RTL formatting completely?
Yes. Setting any language slot to an empty value removes the entire <w:lang> element, while setting direction=ltr or rtl=false triggers ApplyDirectionCascade to strip all <w:rtl/> elements from runs and the paragraph mark. If no inherited RTL exists, the method emits no direction markup, resulting in clean, minimal OOXML.
How does OfficeCLI handle theme fonts versus explicit font names?
OfficeCLI supports theme font slots through keys like font.csTheme, font.eaTheme, and font.latinTheme. These map directly to <w:rFonts> attributes such as csTheme, eastAsiaTheme, and asciiTheme, allowing documents to reference the theme font registry rather than hardcoded font names. When themes change in Word, text automatically updates to the new theme's designated fonts for each script slot.
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 →