OfficeCLI Word Internationalization: Managing RTL Languages and Per-Script Font Slots

OfficeCLI handles Word internationalization through a coordinated dual-layer system that maps locales to three distinct font slots while automatically detecting RTL languages and applying directional markup cascades to ensure proper text rendering.

OfficeCLI, the open-source document automation tool maintained by iOfficeAI, provides enterprise-grade Word internationalization support that handles complex writing systems through per-script font slot management and intelligent text direction detection. The implementation ensures that right-to-left (RTL) languages like Arabic, Hebrew, and Persian render correctly by manipulating the underlying Open XML markup according to the Office Open XML specification.

The Three-Font-Slot Architecture

OfficeCLI manages font substitution through three distinct slots: Latin, East-Asian, and Complex-Script. In src/officecli/Core/LocaleFontRegistry.cs, the Resolve method (lines 28-63) supplies sensible defaults for these slots based on the effective locale. This architecture allows a single document to contain mixed-script content where each run references the appropriate font slot for its specific character set.

The Complex-Script slot specifically handles Arabic, Hebrew, Thai, and other non-Latin scripts that require contextual shaping or bidirectional layout. When a locale maps to a complex script, OfficeCLI ensures that runs use the .cs (complex script) font properties rather than the default Latin properties.

Detecting RTL Locales and Direction Cascading

OfficeCLI treats text direction as a cascading property that must be applied consistently at multiple levels of the document structure to prevent rendering inconsistencies.

IsRightToLeft Detection Logic

In src/officecli/Core/LocaleFontRegistry.cs, the IsRightToLeft method examines the language part of a locale tag to determine bidirectional requirements. The implementation recognizes 14 distinct RTL language codes:

public static bool IsRightToLeft(string? locale) {
    if (string.IsNullOrWhiteSpace(locale)) return false;
    var lang = locale.Replace('_','-').ToLowerInvariant().Split('-')[0];
    return lang switch {
        "ar" or "he" or "yi" or "ur" or "fa" or "ps" or "sd"
        or "ks" or "ug" or "ku" or "ckb" or "dv" or "syr"
        or "nqo" => true,
        _ => false
    };
}

This detection drives two critical behaviors: blank document creation and command-level paragraph handling.

Applying the RTL Cascade

In src/officecli/Handlers/Word/WordHandler.I18n.cs (lines 32-61), the ApplyDirectionCascade method guarantees that RTL paragraphs are fully functional by manipulating three distinct XML elements:

  • <w:bidi/> on the paragraph properties to enable bidirectional layout
  • <w:rtl/> on the paragraph mark to set the paragraph base direction
  • <w:rtl/> on every run within the paragraph to ensure consistent character ordering

The method also clears the cascade cleanly when switching back to LTR, removing directional properties to prevent layout pollution.

Managing Complex-Script Run Formatting

Per-script font properties require reading and writing the Complex-Script attributes that live in a separate namespace within the run properties. In src/officecli/Handlers/Word/WordHandler.I18n.cs (lines 33-50), the ReadComplexScriptRunFormatting method handles the .cs suffix properties: font.cs, size.cs, bold.cs, and italic.cs.

These properties operate independently from their Latin counterparts, allowing a single run to display Latin text in Arial while rendering Arabic text in Arial (Arabic) using the same run structure. OfficeCLI maintains this separation to ensure that complex-script text renders with the correct glyph variants and spacing.

Effective Locale Resolution and Document Defaults

OfficeCLI determines the active locale through LocaleFontRegistry.ResolveEffectiveLocale, which implements a fallback chain:

  1. Explicit --locale flag provided by the user
  2. OS-level locale detection via OsLocaleSnapshot (capturing macOS CFLocale, Linux $LANG/$LC_ALL, or Windows UI culture)
  3. Null return for generic Western locales (en, fr, de, es, it, pt) that require no special handling

When creating blank documents, the BlankDocCreator checks IsRightToLeft against the effective locale. If the locale is RTL, it stamps <w:bidi/> on the document’s default paragraph properties, ensuring that the first paragraph inserted follows the correct text direction without requiring manual configuration.

Summary

  • Triple font slot system: OfficeCLI manages Latin, East-Asian, and Complex-Script slots independently through LocaleFontRegistry.Resolve.
  • 14 RTL language codes: Automatic detection covers Arabic (ar), Hebrew (he), Yiddish (yi), Urdu (ur), Persian (fa), Pashto (ps), Sindhi (sd), Kashmiri (ks), Uyghur (ug), Kurdish (ku), Central Kurdish (ckb), Divehi (dv), Syriac (syr), and N’Ko (nqo).
  • Directional cascade: The ApplyDirectionCascade method ensures RTL paragraphs contain <w:bidi/> and <w:rtl/> elements at the paragraph, paragraph-mark, and run levels.
  • Per-script properties: Complex-script runs use independent .cs properties for font, size, bold, and italic formatting.
  • OS-aware fallback: Locale resolution respects macOS CFLocale, Linux environment variables, and Windows culture settings while filtering out generic Western locales.

Frequently Asked Questions

How does OfficeCLI determine which font slot to use for a given language?

OfficeCLI uses the LocaleFontRegistry.Resolve method to map locale identifiers to specific fonts for each of the three slots: Latin, East-Asian, and Complex-Script. The registry contains predefined mappings that ensure Arabic text uses the Complex-Script slot while English text uses the Latin slot, allowing mixed-script documents to render correctly.

What happens when I create a blank document with an RTL locale?

When the effective locale passes the IsRightToLeft check, the BlankDocCreator automatically injects <w:bidi/> into the document’s default paragraph properties. This ensures that the first paragraph you add will flow right-to-left without requiring explicit direction flags, preventing the common issue of punctuation appearing on the wrong side of RTL text.

How are complex-script font properties stored in the Word XML?

OfficeCLI reads and writes properties with the .cs suffix within the run properties element. According to the source code in WordHandler.I18n.cs, these include font.cs (rFonts), size.cs (sz), bold.cs (b), and italic.cs (i). These properties exist alongside standard Latin properties but only activate when the run contains complex-script characters.

Why does OfficeCLI apply <w:rtl/> to every run rather than just the paragraph?

The ApplyDirectionCascade method adds <w:rtl/> to individual runs to ensure consistent character ordering at the run level, independent of paragraph properties. This prevents rendering bugs where nested runs with different formatting might inherit conflicting directions, and ensures that the paragraph mark itself maintains the correct base direction for cursor positioning and alignment calculations.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →