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.
| Value | Behavior |
|---|---|
wml.ST_JcLeft, wml.ST_JcRight | Absolute. Right stays right no matter the text direction. |
wml.ST_JcStart, wml.ST_JcEnd | Relative 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_JcBoth | Justified, 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.goIf this is your first time using UniOffice, follow the getting started guide to create an API key and set up your development environment.