Skip to content
Right-to-Left Text

Right-to-Left Text

Putting Hebrew or Arabic into a document takes two settings that are easy to confuse. The run needs w:rtl so Word orders the characters right to left, and the paragraph needs an alignment that puts the text against the correct margin. Setting only one of them produces text that reads correctly but sits on the wrong side of the page, or text flush right that still runs left to right.

Storing the characters is not the problem. UniOffice writes UTF-8 throughout, so the string literal goes in unchanged.

Alignment values that follow the direction

SetAlignment takes a wml.ST_Jc, and the enum has two overlapping sets.

ValueBehavior
wml.ST_JcLeft, wml.ST_JcRightAbsolute. Right stays right no matter the text direction.
wml.ST_JcStart, wml.ST_JcEndRelative to the reading direction. End is the right margin for left-to-right text and the left margin for right-to-left text.
wml.ST_JcBothJustified, in whichever direction applies.

Use ST_JcEnd rather than ST_JcRight for right-to-left paragraphs. It is what the example does, and it means the same paragraph keeps working if the document direction changes.

Doing it

para := doc.AddParagraph()
para.SetAlignment(wml.ST_JcEnd)
para.SetAfterSpacing(measurement.Point * 12)

run := para.AddRun()
run.AddText(arabicText) // a plain UTF-8 string literal, nothing to escape
run.Properties().SetRightToLeft(true)

SetRightToLeft(true) adds w:rtl to the run. Passing false removes the element rather than writing an explicit off, so it cancels the run’s own setting but cannot override a right-to-left setting inherited from a style.

The order does not matter. Properties can be set before or after the text is added, because they live in a different part of the run.

Bold, italic and font size need no special handling. SetBold, SetItalic and SetSize write both the Latin attribute and the complex-script one (w:b with w:bCs, w:i with w:iCs, w:sz with w:szCs), so a right-to-left run picks up the formatting from a single call.

A new document’s defaults already declare ar-SA as the complex-script language, which is where Word looks when deciding how to shape and spell-check right-to-left text.

Limitations

There is no exported setter for the paragraph-level w:bidi flag, which is what Word’s “right-to-left paragraph” button toggles. Alignment plus run-level w:rtl covers the common cases; a paragraph that needs its bullet, numbering and indentation mirrored as well has to be reached through para.X().PPr.

The DOCX to PDF converter treats a line as entirely right-to-left as soon as any run on it is marked so. A line mixing an English phrase with a Hebrew one will convert with the whole line reversed. This affects conversion only; Word itself handles the mix correctly.

Arabic glyph shaping during PDF conversion is applied only when the text contains a character in the U+0600 to U+06E0 range. Text made up entirely of characters above U+06E0, such as some extended Arabic and Arabic presentation forms, is passed through unshaped. Hebrew needs no shaping and is unaffected.

Run the example

The example builds a short document with a title, a Hebrew paragraph and an Arabic one, each aligned with ST_JcEnd and each with SetRightToLeft(true) on its run.

Two of its paragraphs call SetStyle("Heading 2"). That ID does not exist; the built-in headings are Heading1 through Heading9 with no space, so the two labels render with default paragraph formatting rather than as headings. Nothing about the right-to-left behavior depends on it.

git clone https://github.com/unidoc/unioffice-examples.git
cd unioffice-examples/document/paragraph-rtl
go run main.go

If this is your first time using UniOffice, follow the getting started guide to create an API key and set up your development environment.

View the full source
Last updated on