International text
The library shapes text by the rules of each script. You give it Unicode text in logical order (the order in which it is typed). The library finds the direction, picks the right glyph forms, and returns the glyphs in visual order.
Right-to-left and bidirectional text
The library always applies the Unicode Bidirectional Algorithm (UAX #9). It puts runs of left-to-right and right-to-left text in the right visual order. Brackets and numbers are handled by the algorithm's rules.
TextDirection sets the base direction of the paragraph, as the CSS direction property and the
HTML dir attribute do:
| Value | CSS and HTML | Base direction |
|---|---|---|
Auto (default) | dir="auto" | From the first strong character of the text. |
LeftToRight | direction: ltr | Left to right. |
RightToLeft | direction: rtl | Right to left. |
The base direction does not change the order of the characters in a word. With RightToLeft, the
English word abc stays abc, and it is placed at the right. The base direction sets:
- The order of the runs of each direction.
- The direction of numbers and punctuation between runs.
- The edge for
TextAlignment.Start.
using PinataLabs.Typography;
TextOptions options = new(arabicFont)
{
WrappingLength = 300,
TextAlignment = TextAlignment.Start, // Right edge for right-to-left text.
};
FontRectangle size = TextMeasurer.MeasureSize("مرحبا بالعالم 2026", options);
To force characters into one direction, as CSS unicode-bidi: bidi-override does, put Unicode
direction controls in the text. For example, "\u202Eabc\u202C" (RIGHT-TO-LEFT OVERRIDE, then POP
DIRECTIONAL FORMATTING) comes out as cba.
The whole text is one paragraph for the algorithm. Line breaks do not start a new paragraph, so
Auto finds one base direction for all of the lines.
Use TextAlignment.Start and TextAlignment.End rather than left and right. They follow the
direction of the text, so one set of options works for both directions. See
Wrapping and alignment.
Complex scripts
Some scripts need more than one glyph for each character, glyphs in a different order from the characters, or marks stacked above and below. The library has a shaper for each family of scripts:
| Shaper | Scripts |
|---|---|
| Arabic | Arabic, Syriac, N'Ko, Mongolian, Phags-pa, Mandaic, Manichaean and Psalter Pahlavi: the scripts that join letters. Picks the initial, medial, final and isolated form of each letter. |
| Indic | Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam and Khmer. Reorders vowel signs and forms conjuncts. |
| Myanmar | Burmese and the other languages written in the Myanmar script. Finds syllables, moves the kinzi, medial RA and vowel sign E, and adds a dotted circle to broken syllables. |
| Hangul | Korean. Composes and decomposes Hangul syllables from jamo. |
| Universal | About 40 other complex scripts, such as Balinese, Batak, Javanese, Sinhala, Sundanese, Tai Tham and Tibetan, by the model of the Universal Shaping Engine. |
| Default | Latin, Greek, Cyrillic, Hebrew, Chinese, Japanese and all other scripts. |
The library picks the shaper from the script of each run of text. You do not choose it.
Shaping uses the OpenType tables in the font. A font must support a script for the text to look right: a Latin-only font cannot show Devanagari, even with a correct shaper. Use fallback fonts to cover more scripts.
Line breaking
Lines break by the rules of UAX #14, for every script. That includes Chinese and Japanese, where a line can break between most characters, and the rules that stop punctuation from starting a line.
WordBreaking.KeepAll keeps Chinese, Japanese and Korean words together, which is what Korean
usually wants. WordBreaking.BreakAll lets lines break inside words of other scripts. See
Wrapping and alignment.
Justification for East Asian text
TextJustification.InterCharacter adds space between characters, not between words. Use it for
Chinese and Japanese, which do not put spaces between words.
Vertical text
Chinese, Japanese and Korean text can be set in vertical columns. See Vertical text.