# OfficeCLI i18n and RTL Support for Word Documents: Per-Script Fonts and Language Tags Explained

> Understand OfficeCLI i18n and RTL support for Word documents. Learn about per-script fonts and language tags for perfect OOXML round-trip fidelity. Explore the three-level RTL cascade and font slot mapping.

- Repository: [OfficeAI/OfficeCLI](https://github.com/iofficeai/OfficeCLI)
- Tags: deep-dive
- Published: 2026-08-01

---

**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`](https://github.com/iOfficeAI/OfficeCLI/blob/main/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:

1. **Paragraph container** – Inserts `<w:bidi/>` into `<w:pPr>` to force RTL layout for the entire paragraph
2. **Paragraph mark** – Adds `<w:rtl/>` to `ParagraphMarkRunProperties` (the invisible paragraph marker that Word's UI targets)
3. **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`](https://github.com/iOfficeAI/OfficeCLI/blob/main/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=` – Sets `ascii`, `hAnsi`, and `eastAsia` simultaneously (Latin and CJK compatibility)
- `font.cs=` – Targets the Complex Script slot used for Arabic and Hebrew glyph shaping
- `font.latin` and `font.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.

```bash

# 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`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Helpers.RunFormat.cs) stores these as separate keys in the format dictionary: `lang.latin`, `lang.ea` (East Asia), and [`lang.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/lang.cs) (Complex Script).

### The Three Language Slots

Each slot serves a specific script category:

- `lang.latin` (aliased as `lang.val`) – Primary language for Latin runs (e.g., `en-US`)
- `lang.ea` (aliased as `lang.eastasia`) – Language for East Asian scripts (e.g., `zh-CN`)
- [`lang.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/lang.cs) (aliased as `lang.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.

```bash

# 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`](https://github.com/iOfficeAI/OfficeCLI/blob/main/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`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Set.cs) routes commands to specialized helpers:

```bash

# 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 through `ApplyDirectionCascade` in [`WordHandler.I18n.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.I18n.cs)
- **Per-script fonts** map to four OOXML slots (`ascii`, `hAnsi`, `eastAsia`, `cs`) with theme support via `ApplyRunFormatting`
- **Language tags** use three distinct slots (`lang.latin`, `lang.ea`, [`lang.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/lang.cs)) that correspond to OOXML `<w:lang>` attributes
- **Inheritance handling** via `HasInheritedBidi` ensures 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`](https://github.com/iOfficeAI/OfficeCLI/blob/main/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`](https://github.com/iOfficeAI/OfficeCLI/blob/main/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`](https://github.com/iOfficeAI/OfficeCLI/blob/main/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.