Skip to main content

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:

ValueCSS and HTMLBase direction
Auto (default)dir="auto"From the first strong character of the text.
LeftToRightdirection: ltrLeft to right.
RightToLeftdirection: rtlRight 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:

ShaperScripts
ArabicArabic, 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.
IndicDevanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam and Khmer. Reorders vowel signs and forms conjuncts.
MyanmarBurmese 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.
HangulKorean. Composes and decomposes Hangul syllables from jamo.
UniversalAbout 40 other complex scripts, such as Balinese, Batak, Javanese, Sinhala, Sundanese, Tai Tham and Tibetan, by the model of the Universal Shaping Engine.
DefaultLatin, 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.