You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: Right-to-left text that starts with a Latin word is laid out left-to-right #32511
Since 3.11, text is shaped with libraqm, but the paragraph direction is always auto-detected from
the first strong character. An Urdu (or Arabic, Hebrew) sentence that starts with a Latin word, a
product name or a version number is therefore laid out left-to-right, so its words and punctuation
come out in the wrong order. There is currently no way to set the direction.
Code for reproduction
importmatplotlib.pyplotasplttext="Python اور matplotlib میں اردو؟"# Urdu sentence that starts with an English wordfig=plt.figure(figsize=(6, 1.6))
fig.text(0.95, 0.70, text, ha="right", fontsize=18, language="ur")
fig.text(0.95, 0.25, ""+text, ha="right", fontsize=18, language="ur") # RLM prefixfig.savefig("repro_direction.png", dpi=100)
Actual outcome
The top line is laid out left-to-right: "Python" is on the left and the Urdu question mark ؟ ends up
in the middle of the line instead of at the end of the sentence.
Expected outcome
The bottom line, where the only change is a U+200F RIGHT-TO-LEFT MARK prefix: the sentence reads
right-to-left, "Python" is on the right where the sentence starts, and ؟ is at the end.
Additional information
FT2Font::layout in src/ft2font.cpp sets the text, face, features and language on the raqm
object but never calls raqm_set_par_direction, so libraqm uses RAQM_DIRECTION_DEFAULT. The
libraqm documentation for that function notes that this default "has problems when a mainly
right-to-left paragraph starts with a left-to-right character and vice versa as the detected
paragraph direction will be the wrong one". The same is true on main.
Passing language="ur" does not change the direction.
The reverse also happens: a left-to-right label whose first letter is Urdu is laid out
right-to-left.
Workaround: prefix the string with U+200F (RLM) or U+061C (ALM), or wrap it in U+2067 ... U+2069
(RLI ... PDI).
This is common in Urdu text: technical terms, names and numbers are often written in Latin script
at the start of a sentence.
A second image shows the same sentence in Noto Nastaliq Urdu, as is, with each direction mark,
and an Urdu-first sentence for comparison.
Possible fix: a direction text property ("auto" by default, "rtl", "ltr"), passed down to raqm_set_par_direction the same way language is passed to raqm_set_language. I would be
happy to work on a PR if that approach sounds acceptable.
There're 2 orders of magnitude more possible language codes, and they also support subtags extending it even more, so it didn't make sense to use an Enum there. There are only 4 options for the direction setting, so an Enum works better.
In the past, we have used StrEnum mostly for compatibility with previous code where we used a plain string. For completely new ones, it's been a bit of a mixed bag, but I think it depended on the underlying use case (BlendMode was string originally, and remained so, while ft2font Enums are translations of FreeType API and are ints). At the lower level, it definitely doesn't need to be a string, but I'm not sure how we wish to expose it in. e.g., text.
Activity
QuLogic commentedon Oct 21, 2026
That seems reasonable, but I think we would use an
Enum, not arbitrary strings.iccir commentedon Oct 21, 2026
Wouldn't we want a string to match existing APIs such as matplotlib.text or the text.language rcparam? Maybe a
StrEnum?I'd imagine that each API which accepts an optional
languageparameter would need adirectionparameter as well. A search for BCP47 shows several.QuLogic commentedon Oct 21, 2026
There're 2 orders of magnitude more possible language codes, and they also support subtags extending it even more, so it didn't make sense to use an
Enumthere. There are only 4 options for the direction setting, so anEnumworks better.In the past, we have used
StrEnummostly for compatibility with previous code where we used a plain string. For completely new ones, it's been a bit of a mixed bag, but I think it depended on the underlying use case (BlendModewas string originally, and remained so, whileft2fontEnums are translations of FreeType API and areints). At the lower level, it definitely doesn't need to be a string, but I'm not sure how we wish to expose it in. e.g.,text.