# How OfficeCLI Handles i18n and RTL Documents in Microsoft Word: A Complete Technical Guide

> Learn how OfficeCLI masters i18n and RTL documents in Word. Discover its cascade system for bidirectionality, preventing errors and bugs in your multilingual documents.

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

---

**OfficeCLI handles i18n and RTL word documents through a centralized cascade system in [`WordHandler.I18n.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/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`](https://github.com/iOfficeAI/OfficeCLI/blob/main/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:

1. **`<w:bidi/>` on paragraph properties** — signals the paragraph base direction
2. **`<w:rtl/>` on the paragraph-mark run properties** — sets direction for the paragraph marker itself
3. **`<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.

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

```csharp
// 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.

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

```bash

# CLI usage to force RTL on first paragraph

officecli set paragraph[1] direction=rtl

```

### Selectors ([`WordHandler.Selector.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Selector.cs))

Read-back operations expose computed effective direction through three keys:
- **`rtl`** — boolean indicating RTL presence
- **`direction`** — 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.

```csharp
bool contextIsRtl = handler.IsTableContextRtl(parentSection);
if (contextIsRtl) {
    tableProps.Append(new BiDiVisual());
}

```

### Section-Level RTL ([`WordHandler.Set.SectionLayout.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/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`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.I18n.cs) | Core cascade, inheritance, CS formatting | 13-73 |
| [`WordHandler.Set.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Set.cs) | CLI key parsing, routing to cascade | — |
| [`WordHandler.Selector.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Selector.cs) | Effective direction read-back | — |
| [`WordHandler.StyleList.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.StyleList.cs) | `effective.rtl` in style queries | — |
| [`WordHandler.Set.SectionLayout.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Set.SectionLayout.cs) | Section-level RTL gutter | — |

## Summary

- **OfficeCLI implements complete RTL handling** through `ApplyDirectionCascade` in [`WordHandler.I18n.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.I18n.cs), applying three-level markup required by Word's Open XML schema.

- **Inheritance detection** via `HasInheritedBidi` and `StyleChainHasBidi` prevents 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 `EnsureParagraphMarkRunPropertiesInSchemaOrder` to 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`](https://github.com/iOfficeAI/OfficeCLI/blob/main/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.