# How OfficeCLI Handles Word i18n and RTL Text Direction: Implementation Guide

> Learn how OfficeCLI implements Word i18n and RTL text direction with a three-level cascade for paragraphs, marks, and runs. Discover its efficient RTL handling.

- Repository: [OfficeAI/OfficeCLI](https://github.com/iofficeai/OfficeCLI)
- Tags: implementation-guide
- Published: 2026-08-07

---

**OfficeCLI centralizes Word internationalization in [`WordHandler.I18n.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.I18n.cs), implementing a three-level RTL cascade that adds `<w:bidi/>` to paragraphs, `<w:rtl/>` to paragraph marks, and `<w:rtl/>` to every run, while detecting inherited direction and preserving complex-script formatting.**

OfficeCLI, the open-source document automation toolkit from iOfficeAI, provides robust support for right-to-left (RTL) scripts and internationalization (i18n) in Word documents. The implementation ensures that Arabic, Hebrew, and other RTL languages render correctly by manipulating the underlying Open XML markup with precision. Understanding these internals helps developers generate valid, localized Word documents programmatically without producing mixed-bidi or validator-rejected files.

## The RTL Cascade Architecture

The core RTL logic resides in [`src/officecli/Handlers/Word/WordHandler.I18n.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Word/WordHandler.I18n.cs). This file implements a cascade system that applies directional markup at multiple levels to satisfy Word's strict requirements for bidirectional text.

### Paragraph-Level Direction with `ApplyDirectionCascade`

When switching a paragraph to RTL, OfficeCLI applies three distinct XML elements through the `ApplyDirectionCascade` method (lines 33-46):

1. `<w:bidi/>` on the paragraph properties (`pPr`)
2. `<w:rtl/>` on the paragraph-mark run properties
3. `<w:rtl/>` on **every** run inside the paragraph

The method is idempotent; passing `rtl: false` removes the cascade entirely. If higher-level sources still force RTL, the method emits `<w:bidi w:val="false"/>` to override inheritance explicitly.

```csharp
// Assume `handler` is an instance of WordHandler and `para` is a Paragraph.
handler.ApplyDirectionCascade(para, rtl: true);

```

*This adds `<w:bidi/>`, `<w:rtl/>` on the paragraph-mark, and `<w:rtl/>` on every run.*

To force LTR and clear any inherited RTL:

```csharp
handler.ApplyDirectionCascade(para, rtl: false);

```

*This removes the cascade and emits `<w:bidi w:val="false"/>` if any inherited RTL exists.*

### Inheritance Detection via `HasInheritedBidi`

To determine whether explicit LTR markup is needed to cancel inherited settings, `HasInheritedBidi` (lines 24-30) walks all possible RTL sources. The method checks section properties, paragraph-style chains, `docDefaults`, and numbering levels. This detection prevents mixed-direction artifacts by identifying when an inherited RTL state requires explicit cancellation.

### Style-Chain Resolution with `StyleChainHasBidi`

The `StyleChainHasBidi` method (lines 67-73) follows the `basedOn` chain of paragraph styles, stopping at the first explicit `bidi` true or false value. This mirrors Word's internal style resolver, ensuring that direction changes propagate correctly through inherited styles without creating invalid override conflicts.

### Schema-Correct XML Insertion

When adding `<w:rtl/>` to paragraph marks, `EnsureParagraphMarkRunPropertiesInSchemaOrder` (lines 13-22) inserts the `<w:rPr>` element at the proper location within the `pPr` tree. This strict schema compliance prevents validation errors that occur when run properties are placed out of sequence relative to other paragraph properties.

## Complex-Script (CS) Run Formatting

RTL documents often require complex-script formatting distinct from Latin (Ascii) text. The `ReadComplexScriptRunFormatting` method (lines 34-44) extracts CS-specific properties from runs:

- [`font.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/font.cs) from `<w:rFonts cs/>`
- [`size.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/size.cs) from `<w:szCs/>`
- [`bold.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/bold.cs) from `<w:bCs/>`
- [`italic.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/italic.cs) from `<w:iCs/>`

Crucially, the method respects explicit off-toggles (e.g., `<w:bCs w:val="0"/>`), ensuring round-trip fidelity for documents where complex-script formatting must be explicitly disabled to prevent unwanted inheritance from Latin text settings.

```csharp
var format = new Dictionary<string, object?>();
WordHandler.ReadComplexScriptRunFormatting(run, null, format);
// `format` now contains keys: "font.cs", "size.cs", "bold.cs", "italic.cs"

```

## CLI Integration and Usage Patterns

OfficeCLI exposes these internal mechanisms through simple command-line interfaces while maintaining the integrity of the underlying XML manipulation.

### Setting Direction via the CLI

The `Set` command in [`WordHandler.Set.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Set.cs) parses direction keywords (`rtl`, `ltr`, `direction`) and forwards them to `ApplyDirectionCascade`:

```bash
officecli set paragraph[1] direction=rtl

```

The CLI resolves the target paragraph and internally calls `ApplyDirectionCascade`, abstracting the complex XML generation.

### Reading Direction State

Selectors in [`WordHandler.Selector.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Selector.cs) expose `rtl`, `direction`, and `bidi` keys that return the effective direction computed by the cascade logic. This enables scripts to query document state before modification, ensuring conditional logic based on the current text direction.

### Automatic RTL Context for Tables

When inserting tables, `IsTableContextRtl` determines whether the surrounding section or document defaults specify RTL. If the context is RTL, the implementation automatically stamps `<w:bidiVisual/>` on table properties to maintain visual consistency with the text direction.

```csharp
// `parent` can be a Section, Body, etc.
bool contextIsRtl = handler.IsTableContextRtl(parent);
if (contextIsRtl)
{
    // Auto-stamp BiDiVisual on the table properties.
    tableProperties.BidiVisual = new BiDiVisual();
}

```

## Summary

- **OfficeCLI** implements Word i18n through a centralized RTL cascade in [`WordHandler.I18n.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.I18n.cs)
- **`ApplyDirectionCascade`** applies three XML elements (`<w:bidi/>`, paragraph-mark `<w:rtl/>`, and run-level `<w:rtl/>`) to ensure proper RTL rendering
- **`HasInheritedBidi`** and **`StyleChainHasBidi`** detect style-based direction inheritance to prevent conflicting markup
- **Complex-script formatting** preserves explicit off-toggles for [`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) to ensure round-trip accuracy
- **CLI commands** abstract the XML manipulation, allowing simple `direction=rtl` syntax while maintaining schema compliance

## Frequently Asked Questions

### How does OfficeCLI ensure Word documents remain valid when adding RTL markup?

By using `EnsureParagraphMarkRunPropertiesInSchemaOrder` to insert XML elements at schema-compliant positions within the paragraph properties tree, avoiding validation errors that occur with out-of-order elements according to the Open XML standard.

### Can OfficeCLI handle mixed-direction documents where some paragraphs are RTL and others LTR?

Yes. The `ApplyDirectionCascade` method is idempotent and context-aware; it removes RTL markup when `rtl: false` is specified and emits `<w:bidi w:val="false"/>` to override inherited RTL from styles or sections, enabling precise per-paragraph direction control without affecting neighboring content.

### What complex-script formatting properties does OfficeCLI preserve for RTL text?

OfficeCLI preserves [`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) properties through `ReadComplexScriptRunFormatting`, including explicit off-toggles (`w:val="0"`), ensuring that complex-script formatting does not inherit incorrectly from Latin text settings and maintains round-trip fidelity.

### Does OfficeCLI automatically detect RTL context when inserting tables?

Yes. The `IsTableContextRtl` method checks section properties and document defaults to determine if the surrounding context is RTL, automatically applying `<w:bidiVisual/>` to table properties when necessary to maintain proper visual layout alignment with the text direction.