# How OfficeCLI Implements Word i18n and RTL Support with Per-Script Font Slots

> Discover how OfficeCLI supports Word internationalization and RTL with per-script font slots. Learn about cascading direction markers and dedicated font keys for seamless multilingual text.

- Repository: [OfficeAI/OfficeCLI](https://github.com/iofficeai/OfficeCLI)
- Tags: internals
- Published: 2026-08-09

---

**OfficeCLI handles Word internationalization by cascading RTL direction markers through paragraphs and runs while maintaining separate font slots for Latin, East Asian, and Complex Script text via dedicated keys like [`font.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/font.cs).**

The iOfficeAI/OfficeCLI repository provides a dedicated internationalization module for Word documents that bridges OpenXML complexity with a simple CLI interface. Located in [`WordHandler.I18n.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.I18n.cs), this module manages bidirectional text layout and multi-script typography without affecting PowerPoint or Excel handlers. Understanding how these features work enables precise control over documents containing Arabic, Hebrew, Japanese, or mixed-script content.

## The RTL Cascade: Handling Right-to-Left Text Direction

When a paragraph requires right-to-left layout, OfficeCLI must inject three specific OpenXML elements to ensure proper rendering across different Word processors. The `ApplyDirectionCascade` method in [`src/officecli/Handlers/Word/WordHandler.I18n.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Word/WordHandler.I18n.cs) (lines 33‑44) orchestrates this process.

The method adds:
- `<w:bidi/>` on the paragraph properties
- `<w:rtl/>` on the paragraph-mark run
- `<w:rtl/>` on every individual run within the paragraph

This cascade ensures that both the paragraph container and its textual content inherit the correct directionality. The dispatcher in [`WordHandler.Set.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Set.cs) detects paragraph-level keys such as `direction` or `bidi` and routes them to this cascade function. Header and footer sections receive identical treatment through the same code path.

## Complex Script Formatting and Per-Script Font Slots

Word stores distinct formatting attributes for complex scripts (Arabic, Hebrew, Japanese, Korean) separate from Latin text. OfficeCLI exposes these through canonical keys: **[`font.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/font.cs)**, **[`size.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/size.cs)**, **[`bold.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/bold.cs)**, and **[`italic.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/italic.cs)**, alongside **`font.latin`** and **`font.ea`** (East Asian).

### Reading Complex Script Values

The `ReadComplexScriptRunFormatting` method in [`WordHandler.I18n.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.I18n.cs) (lines 50‑95) extracts values from OpenXML elements including `<w:rFonts cs="…">`, `<w:szCs>`, `<w:bCs>`, and `<w:iCs>`. It merges these into the format dictionary using the canonical key names, allowing subsequent commands to inspect the current complex script state.

### Writing Per-Script Fonts

When updating a run, `ApplyRunFormatting` (defined in [`WordHandler.Helpers.RunFormat.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Helpers.RunFormat.cs)) writes the `<w:rFonts>` element with separate attributes for each script type: `ascii` and `hAnsi` for Latin, `eastAsia` for East Asian, and `cs` for complex script. The dispatcher in [`WordHandler.Set.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Set.cs) (lines 753‑754) treats [`font.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/font.cs) and its aliases as run-level properties, ensuring they pass through to the formatting routine.

## Header and Footer i18n Support

Headers and footers participate fully in the internationalization pipeline. Inside `SetHeaderFooter` ([`WordHandler.Set.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Set.cs), lines 86‑88), the code checks for `direction` or `bidi` properties after applying paragraph-level formatting and invokes `ApplyDirectionCascade` when needed. The same block handles per-script font keys (lines 47‑58), ensuring that [`font.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/font.cs) updates propagate to every run and the paragraph-mark run within headers and footers.

## Practical Usage Examples

Set a paragraph to right-to-left, automatically applying the RTL cascade to all nested runs:

```bash
officecli set /body/p[3] --prop direction=rtl

```

Assign a complex-script font to a specific run while preserving other font slots:

```bash
officecli set /body/p[2]/r[1] --prop font.cs=ＭＳゴシック

```

Combine RTL direction with per-script formatting in a document header:

```bash
officecli set /header[1] \
  --prop direction=rtl \
  --prop font.cs=Arabic\ Typesetting \
  --prop size=12pt

```

Query the complex-script font currently applied to a run:

```bash
officecli get /body/p[2]/r[1] --prop font.cs

```

New runs inherit existing per-script font slots automatically when created, as implemented in [`WordHandler.Add.Text.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Add.Text.cs) (lines 348‑362), ensuring consistent typography when appending text to existing paragraphs.

## Summary

- **RTL directionality** requires three OpenXML elements (`<w:bidi/>` and dual `<w:rtl/>` tags) that OfficeCLI injects via `ApplyDirectionCascade` in [`WordHandler.I18n.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.I18n.cs).
- **Per-script font slots** (`font.latin`, `font.ea`, [`font.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/font.cs)) map to OpenXML `rFonts` attributes and are managed through `ApplyRunFormatting` with read-back support via `ReadComplexScriptRunFormatting`.
- **Headers and footers** receive the same i18n treatment as body paragraphs, including RTL cascades and complex script formatting.
- **Complex script properties** use the `.cs` suffix (e.g., [`size.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/size.cs), [`bold.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/bold.cs)) to distinguish them from Latin formatting in the CLI interface.

## Frequently Asked Questions

### What OpenXML elements does OfficeCLI add for RTL support?

OfficeCLI adds `<w:bidi/>` to the paragraph properties and `<w:rtl/>` to both the paragraph-mark run and every individual run within the paragraph. The `ApplyDirectionCascade` method in [`WordHandler.I18n.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.I18n.cs) manages these insertions to ensure consistent right-to-left rendering.

### How do I set a different font for Arabic text versus English text in the same document?

Use the per-script font slots: specify `--prop font.latin=Calibri` for English text and `--prop font.cs=Arabic Typesetting` for Arabic text. OfficeCLI writes these to separate `rFonts` attributes (`ascii`/`hAnsi` versus `cs`) within the same run, allowing Word to render each script with its appropriate typeface.

### Does RTL support apply to headers and footers automatically?

Yes. When you set `direction=rtl` on a header or footer path, the `SetHeaderFooter` method in [`WordHandler.Set.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Set.cs) detects this property and calls `ApplyDirectionCascade`, ensuring the entire section—including all runs and paragraph marks—receives the correct bidirectional markers.

### Where does OfficeCLI store complex script formatting values when reading a document?

The `ReadComplexScriptRunFormatting` method extracts values from elements like `<w:szCs>`, `<w:bCs>`, and `<w:rFonts cs="…">` and stores them under canonical keys ([`size.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/size.cs), [`bold.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/bold.cs), [`font.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/font.cs)) in the format dictionary. This allows the `get` command to return complex script properties using the same key names used for writing.