# How OfficeCLI Handles i18n and RTL Text Direction for Word Documents

> Learn how OfficeCLI manages i18n and RTL text direction in Word documents by cascading bidirectional XML elements and preserving complex-script formatting.

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

---

**OfficeCLI implements comprehensive internationalization support by cascading bidirectional XML elements through paragraph properties, paragraph marks, and individual runs, while preserving complex-script formatting via the [`WordHandler.I18n.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.I18n.cs) module.**

OfficeCLI is an open-source command-line interface for automating Microsoft Office document generation and modification. When processing right-to-left scripts such as Arabic or Hebrew, the tool must generate schema-compliant WordprocessingML that respects both explicit direction settings and inherited style properties. The library centralizes all bidirectional logic in [`WordHandler.I18n.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.I18n.cs), ensuring that RTL documents validate correctly and render properly in Microsoft Word.

## RTL Cascade Architecture in WordHandler.I18n.cs

### Paragraph-Level Direction Control

The `ApplyDirectionCascade` method (lines 33-46 in [`src/officecli/Handlers/Word/WordHandler.I18n.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Word/WordHandler.I18n.cs)) implements the three-tier XML structure required for RTL paragraphs:

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

This method is idempotent; calling it with `rtl: false` removes the cascade and emits `<w:bidi w:val="false"/>` when inherited RTL needs cancellation.

```csharp
// Apply RTL to a paragraph
handler.ApplyDirectionCascade(para, rtl: true);

```

```csharp
// Force LTR by clearing RTL cascade
handler.ApplyDirectionCascade(para, rtl: false);

```

### Inheritance Detection and Style Resolution

To handle Word's complex inheritance model, `HasInheritedBidi` (lines 24-30) walks all possible RTL sources including section properties, paragraph-style chains, `docDefaults`, and numbering levels. This determines whether explicit LTR markup is required to override inherited RTL settings.

The `StyleChainHasBidi` helper (lines 67-73) follows the `basedOn` chain of paragraph styles, stopping at the first explicit `bidi` value to mirror Word's internal resolver.

### Schema-Compliant XML Insertion

The helper `EnsureParagraphMarkRunPropertiesInSchemaOrder` (lines 13-22) inserts `<w:rPr>` elements at the correct location within the `pPr` tree, preventing validation errors that occur when RTL properties are misplaced in the XML hierarchy.

## Complex-Script Formatting Preservation

### Extracting CS Run Properties

The `ReadComplexScriptRunFormatting` method (lines 34-44) extracts complex-script variants from run properties:

- [`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/>`

This method respects explicit off-toggles (e.g., `<w:bCs w:val="0"/>`), ensuring that formatting overrides preventing unwanted inheritance are preserved during round-tripping.

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

```

## CLI Integration and Command Handling

### Setting Direction via Commands

The `Set` command implementation in [`WordHandler.Set.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Set.cs) parses keys like `rtl`, `ltr`, and `direction`, forwarding them to `ApplyDirectionCascade`. Users can invoke this via:

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

```

### Reading Effective Direction

Selectors defined 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, allowing scripts to query document state without parsing XML manually.

### RTL-Aware Table Insertion

When inserting tables, `IsTableContextRtl` detects whether the surrounding section or document defaults specify RTL direction. This automatically triggers the insertion of `<w:bidiVisual/>` on table properties to ensure proper visual ordering.

```csharp
bool contextIsRtl = handler.IsTableContextRtl(parent);
if (contextIsRtl)
{
    tableProperties.BidiVisual = new BiDiVisual();
}

```

## Summary

- OfficeCLI centralizes RTL logic in [`WordHandler.I18n.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.I18n.cs) with cascade-aware methods like `ApplyDirectionCascade`
- The implementation handles three levels of bidirectional markup: paragraph properties, paragraph marks, and individual runs
- Complex-script formatting (fonts, sizing, bold, italic) is preserved via `ReadComplexScriptRunFormatting` with explicit toggle support
- Inheritance detection through `HasInheritedBidi` and `StyleChainHasBidi` ensures accurate override of style-based RTL settings
- CLI commands and programmatic APIs both leverage these helpers to produce validation-compliant WordprocessingML

## Frequently Asked Questions

### How does OfficeCLI ensure Word documents remain valid when applying RTL formatting?

OfficeCLI uses `EnsureParagraphMarkRunPropertiesInSchemaOrder` to insert RTL properties at schema-compliant positions within the XML tree. The `ApplyDirectionCascade` method ensures all three required elements (`<w:bidi/>`, paragraph-mark `<w:rtl/>`, and run-level `<w:rtl/>`) are present simultaneously, preventing the mixed-bidi states that cause Word validation errors.

### Can OfficeCLI override inherited RTL settings from document styles?

Yes. When `ApplyDirectionCascade` is called with `rtl: false`, it invokes `HasInheritedBidi` to detect RTL values inherited from section properties, style chains, or document defaults. If inheritance is detected, the method emits `<w:bidi w:val="false"/>` to explicitly cancel the inherited direction, ensuring LTR rendering regardless of style hierarchy.

### What complex-script formatting properties does OfficeCLI preserve during document processing?

OfficeCLI preserves four complex-script variants through `ReadComplexScriptRunFormatting`: [`font.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/font.cs) (complex-script font), [`size.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/size.cs) (complex-script size), [`bold.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/bold.cs) (complex-script bold), and [`italic.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/italic.cs) (complex-script italic). The method explicitly handles off-toggles (values of "0") to prevent unwanted formatting inheritance in multilingual documents.

### How do I programmatically detect if a table should use RTL layout in OfficeCLI?

Use the `IsTableContextRtl` method to inspect the surrounding section or document defaults before table insertion. This helper returns `true` when the context requires right-to-left layout, allowing your code to automatically set `tableProperties.BidiVisual` and ensure the table renders with correct visual ordering for Arabic or Hebrew content.