Skip to content

Punctuation problems in Arabic and English text

Learn why punctuation moves in mixed Arabic and English text, how to isolate complete phrases, and when to use Arabic punctuation characters.

By , Founder of Ritla

Guide13 min read

A document-conversion console preserves an English engine message inside an Arabic interface. The message is Render complete!, but its exclamation mark appears before the English words. The string is correct in the response and in the DOM. Its directional boundary is missing.

Another screen ends an Arabic confirmation question with ?. That is a different defect: the copy uses the Latin question-mark character where the Arabic question mark is intended. Moving the existing character cannot correct that choice.

Diagnose these separately. First decide which phrase owns the punctuation and which character that phrase requires. Then describe the phrase's direction. The page language alone does not answer either question, especially when the interface preserves filenames, product names or verbatim diagnostics.

Reproduce a punctuation mark at the wrong end#

The conversion console intentionally exposes the engine's original message for troubleshooting. Its surrounding label is translated:

Problem

html
<p lang="ar" dir="rtl">رسالة المحوّل: Render complete!</p>

The English part displays as !Render complete. An Arabic reader should read the label in Arabic, then the English diagnostic with its exclamation mark at the end of the English phrase. There is no reason for the engine's message to acquire Arabic sentence direction merely because the label is Arabic.

Better

html
<p lang="ar" dir="rtl">  رسالة المحوّل: <span lang="en" dir="ltr">Render complete!</span></p>

The diagnostic now displays as Render complete!. The complete phrase, including its terminal mark, has its own LTR context. The colon belongs to the Arabic label and stays outside that context.

The same pattern applies to a full stop. Unisolated Render complete. in the RTL paragraph displays as .Render complete; wrapping the complete English message with dir="ltr" retains its final full stop.

These display patterns were measured in Chromium 151 on September 24, 2026. Firefox and Safari were not included in those measurements, so verify the fixtures in the browsers your application supports.

The English diagnostic is deliberate foreign-language content, not a model for leaving ordinary customer-facing status messages untranslated. If the message is your own interface copy, translate it as a complete message. Isolation protects a phrase's display; it does not make an untranslated interface appropriate.

Why the character moves without changing the string#

Latin and Arabic letters establish strong directional runs. A full stop or exclamation mark does not establish an equivalent strong direction for itself. At a boundary, surrounding text and the paragraph's base direction influence where the mark is displayed.

The browser knows that there are English letters followed by punctuation. It does not know that your application considers the punctuation part of an engine response. An explicit phrase boundary supplies that missing information. Unicode's Bidirectional Algorithm defines the directional resolution and display ordering.

The stored sequence can remain unchanged throughout the failure. A text assertion can find the exclamation mark at the end while the rendered English phrase shows it at the other end. Copying text and inspecting the accessibility tree likewise do not establish the visual order.

Do not generalize this explanation to every punctuation character. Some marks have different bidi properties, and paired brackets have additional processing. A claim that all punctuation is neutral hides the distinctions needed to debug mixed text.

Also avoid testing only an English message without punctuation. The words may look correct while their eventual terminal mark exposes the missing boundary. Keep punctuation in your actual fixture instead of simplifying away the part that fails.

Choose Arabic punctuation for Arabic prose#

Arabic has distinct characters for its comma, semicolon and question mark. It also shares punctuation characters with English, including the ordinary full stop and exclamation mark. The Unicode Standard's Arabic discussion distinguishes the separately encoded Arabic marks from shared punctuation.

FunctionEnglish characterArabic prose character
Question mark?, U+003F؟, U+061F
Comma,, U+002C،, U+060C
Semicolon;, U+003B؛, U+061B
Full stop., U+002E., U+002E
Exclamation mark!, U+0021!, U+0021

For the console's Arabic confirmation question, the content repair is straightforward:

html
<!-- Wrong character for this Arabic interface question --><p lang="ar" dir="rtl">هل تريد إعادة التصدير?</p> <!-- Arabic question mark in the translated sentence --><p lang="ar" dir="rtl">هل تريد إعادة التصدير؟</p>

The two question marks are different characters, not one character that CSS should flip. A direction declaration does not translate punctuation or change one code point into another.

These choices concern Arabic prose. An embedded English question should keep English punctuation. A quoted diagnostic, a filename or a configuration string may also need exact characters that differ from the surrounding prose. Use the phrase's language and purpose to make the choice, then have the Arabic wording reviewed in context.

The Unicode Arabic character list provides the identities of the Arabic-specific marks when you need to distinguish similar-looking source characters.

A question after an English name may still be Arabic#

The last word before a question mark does not necessarily determine its language. The conversion console offers an integration named FlowDeck+. An Arabic question about running that integration is still an Arabic sentence:

html
<p lang="ar" dir="rtl">  هل تريد تشغيل <bdi>FlowDeck+</bdi>؟</p>

The plus sign belongs to the integration name and stays inside its boundary. The Arabic question mark belongs to the surrounding question and stays outside. The fact that the adjacent name is Latin does not turn the question into English.

Compare that with an English question preserved from the engine:

html
<p lang="ar" dir="rtl">  سؤال المحوّل: <span lang="en" dir="ltr">Retry render?</span></p>

Here the English question mark is part of the English diagnostic and belongs inside the LTR span. Test its placement in your supported browsers. Replacing it with the Arabic question mark merely because the page is Arabic changes the diagnostic rather than defining its direction.

This distinction is useful when reviewing reports such as “the question mark after the English word is wrong.” Determine whether that word is a name within an Arabic question or part of a complete English question. Those cases require different source characters and different boundaries.

Do not implement a rule that looks only at the preceding character's script. It would misclassify the Arabic question containing the Latin integration name. Store punctuation with the translated sentence or verbatim message that owns it.

Include the phrase's punctuation inside its isolate#

An isolate around only the English words leaves their terminal mark exposed to the Arabic paragraph:

html
<p lang="ar" dir="rtl">  رسالة المحوّل: <span lang="en" dir="ltr">Render complete</span>!</p>

This markup describes an English phrase followed by punctuation owned by the surrounding context. That is not the engine message's contract. Move the exclamation mark inside the same span as the words, as in the repaired example.

Conversely, do not pull the Arabic sentence's punctuation into an English name just to make the name's wrapper longer. Consider a simple Arabic statement:

html
<p lang="ar" dir="rtl">  تم اختيار <bdi>FlowDeck+</bdi>.</p>

Its full stop ends the Arabic statement. The integration name does not own that full stop. The name's plus sign is internal; the sentence's full stop is external. Exact boundary placement follows the meaning, not a rule that all nearby punctuation must go inside a wrapper.

The W3C guidance on inline bidi markup recommends tightly wrapping complete opposite-direction phrases. For this page, “complete” includes punctuation belonging to the phrase and excludes punctuation belonging to the host sentence.

When a sentence quotes a complete English message and then continues in Arabic, keep the message's terminal punctuation with the message. The surrounding sentence may also require punctuation under your editorial style. Review both layers rather than deleting one mark automatically or adding a second full stop to every translation.

Protect punctuation that is part of a name or token#

Terminal punctuation is not always sentence punctuation. The plus sign in FlowDeck+ identifies an integration. Removing it or replacing it changes the name.

Without isolation, the name between Arabic words exposes the issue:

html
<p lang="ar" dir="rtl">اختر FlowDeck+ للتصدير.</p>

The name's displayed sequence becomes +FlowDeck. The repaired component keeps the full name together:

html
<p lang="ar" dir="rtl">اختر <bdi>FlowDeck+</bdi> للتصدير.</p>

The plus sign stays with the name in its intended sequence, FlowDeck+. A plain span without a direction declaration would not provide the same isolation.

Use the same reasoning for punctuation inside exact values such as file extensions or configuration keys. Those characters can be part of a format, not grammatical marks available for localization. Preserve the value, isolate the complete unit where appropriate, and test its actual shape rather than predicting every complex string from this one example.

Do not strip punctuation from data to make a screenshot look simpler. A punctuation-free title might conceal the missing boundary, but the next integration name or diagnostic can reintroduce it. Put the directional contract on the value component instead of maintaining a list of characters to remove.

Keep list separators in the language of the list#

An Arabic list can contain English operation names. Its separators belong to the Arabic sentence, while each operation name is its own phrase:

html
<p lang="ar" dir="rtl">  العمليات المتاحة:  <span lang="en" dir="ltr">Inspect</span>،  <span lang="en" dir="ltr">Render</span>،  <span lang="en" dir="ltr">Archive</span>.</p>

The comma choice comes from the Arabic list. The operation labels stay separate because they are separate items. Check that the visual reading order matches the intended operation sequence and that each separator reads between the appropriate items.

Do not fix a list by wrapping the entire Arabic sentence in LTR. Also avoid treating a whole Arabic enumeration as one English phrase simply because its item labels happen to be English. That loses the distinction between the list's ordering context and the items' internal direction.

An English diagnostic containing its own comma-separated sequence has a different contract. If the complete diagnostic is preserved verbatim, its commas belong inside that English message's boundary. Do not replace those commas using the host page's locale.

For generated lists, use a locale-aware message or list-formatting facility with support for the markup you need. Preserve item boundaries through that formatting step. Test the empty, single-item and multiple-item cases because separators should not survive after their neighbouring item disappears.

This is a content composition problem as well as a bidi problem. Correctly placed Arabic commas cannot fix a generator that emits an extra separator for an absent operation.

Direction and language describe different things#

The repaired diagnostic uses both lang="en" and dir="ltr". Language metadata identifies the language of the phrase. Direction establishes its base direction and isolation. Setting the language alone does not supply the directional boundary.

For a known English engine response, explicit LTR is appropriate. If an imported comment can be Arabic or English, automatic isolation can be useful instead:

html
<p lang="ar" dir="rtl">  تعليق المراجع: <bdi>Ready for archive.</bdi></p>

The comment establishes its direction from its first strong character. Keep its punctuation inside the same wrapper. If reliable language metadata accompanies the comment, apply that metadata as well; automatic direction is not language detection. See MDN's bdi reference.

Do not include the Arabic field label inside the automatic wrapper. Its first Arabic letter can select RTL for the whole label-and-value string. An arbitrary span also does not become automatic merely because its content is dynamic. MDN's dir reference documents the explicit choices.

A comment that itself contains Arabic and English phrases may need nested boundaries. One outer automatic wrapper is useful isolation from the interface, but it does not identify every phrase inside arbitrary text. Test those comments as content of their own.

Apply the same boundary rule to Arabic inside English#

The console's English route may display an Arabic reviewer comment. The host direction changes, but punctuation ownership does not: the comment's terminal mark still belongs to the comment.

Start with an unisolated version when reproducing that case:

html
<p lang="en" dir="ltr">Reviewer wrote: اكتملت المراجعة!</p>

Inspect which phrase the exclamation mark appears to end. If it is pulled into the English context, establish an RTL boundary around the complete Arabic comment:

html
<p lang="en" dir="ltr">  Reviewer wrote: <span lang="ar" dir="rtl">اكتملت المراجعة!</span></p>

The intended reading starts with the English introduction, then reads the comment in Arabic with the exclamation mark at the end of that Arabic phrase. That end is on the comment's left. A test that assumes terminal punctuation always belongs on the right would reject the intended result. The W3C discussion of punctuation at directional boundaries explains this reverse-direction case too.

Keep the English introduction outside the RTL wrapper. Making the whole paragraph RTL to protect the Arabic comment would change the host sentence's contract. If reviewer comments can use either language, use automatic isolation on the comment value instead of selecting its direction from the route.

This matters for reusable message components. The same stored comment can appear in an Arabic review panel and an English activity stream. Preserve its characters in both places and let each host describe its own direction. Test those two renderings separately; a successful Arabic-route screenshot does not establish the English-route behavior.

Give one layer responsibility for terminal punctuation#

The console should preserve the engine's message exactly, including its punctuation. A component that adds a full stop after every message can create duplicate or contradictory endings. A component that removes every final mark can damage a question or warning.

Use an explicit distinction between a complete message and a bare label. A complete translated sentence owns its ending. A verbatim diagnostic also owns its ending. A bare operation label can be inserted into a larger translated sentence whose punctuation belongs to that sentence.

Here is a small renderer for complete English diagnostics:

html
<p lang="ar" dir="rtl">  رسالة المحوّل: <span id="engine-message" lang="en" dir="ltr"></span></p>

Run this after the markup:

js
function renderEngineMessage(message) {  if (typeof message !== "string") {    throw new TypeError("Expected an engine message string");  }   const output = document.getElementById("engine-message");  if (!output) throw new Error("Engine message element is missing");  output.textContent = message;} renderEngineMessage("Render complete!");

The wrapper remains while the text changes. The renderer neither appends punctuation nor modifies the message's characters. textContent inserts the response as text rather than interpreting it as markup. Use your framework's escaped text binding for the equivalent operation.

Test a statement, question and exclamation through the same renderer. Then test an empty string and an update after initial rendering. The server-rendered version and later client updates should preserve the same boundary. Do not replace the protected element with an unisolated string during a status transition.

Language switching deserves a separate assertion for your translated interface messages. Replace the complete sentence, including its terminal punctuation, from the new locale's resource. Do not retain an English question mark in a separate component node while replacing only the question's words with Arabic.

For example, a confirmation dialog can have a translated sentence slot and separate action buttons. The sentence resource should own the question mark. The button component should own neither the dialog's punctuation nor an extra mark appended to every label. This keeps the grammatical question independent of the visual placement of its actions.

A verbatim engine diagnostic behaves differently during the same switch. Its surrounding label changes language, while the diagnostic retains its exact source text and known language boundary. Test that contrast explicitly: one message is translated as a unit, the other is preserved as a unit. This prevents a locale change from becoming a character-replacement pass over every message visible in the panel.

Avoid page-wide punctuation conversion#

A replacement such as “change every question mark on the Arabic route” has no knowledge of sentence ownership. It can alter an English diagnostic, a quoted question or an exact technical value along with the Arabic copy it was intended to fix.

The same problem applies to commas and semicolons. Their grammatical forms in Arabic prose do not authorize editing punctuation inside numbers, source snippets or engine responses. Correct the translation resource or the content-specific formatter responsible for the phrase.

Do not reverse a message's characters, move its final mark to the start of storage or mirror its glyph with a transform. Those approaches make the source depend on one visual context. A later change of surrounding language or component direction can expose the modified string elsewhere.

Adding spaces around the mark is also a poor substitute for a phrase boundary. It changes the copy while leaving the browser to infer ownership. Use spacing appropriate to the language, then declare the direction of the complete inserted phrase.

Prefer visible markup for HTML boundaries over accumulating invisible direction marks in translation entries. Plain-text destinations cannot use the same span, so design and test their representation separately. W3C guidance on Unicode bidi controls covers that situation. Keep raw diagnostic data separate from any display-specific formatting you add for a particular destination.

Diagnose character choice, boundaries and visibility separately#

When a report says “the punctuation is backwards,” ask what the reader expected: a different mark, the same mark at the other end of a phrase, or a mark that is currently missing from view. Those are different repair paths.

For the diagnostic component, inspect its actual characters:

js
const output = document.getElementById("engine-message");if (!output) throw new Error("Engine message element is missing"); console.table(Array.from(output.textContent, (character, index) => ({  index,  character,  codePoint: "U+" + character.codePointAt(0)    .toString(16).toUpperCase().padStart(4, "0")})));

This establishes whether the source contains the expected character and whether it follows the message in logical order. It does not prove its visible location. Inspect the phrase's dir and computed directional styles next, then look at the rendered result.

If the punctuation belongs to a different element from its phrase, inspect the template that created that split. If it is absent from the text entirely, check the response, translation resource and any shortening logic before changing CSS. Also inspect stylesheet-generated content when the visible punctuation has no corresponding text character.

Use narrow widths and supported zoom settings to distinguish clipping from reordering. A hidden terminal mark is not automatically at the wrong end. Temporarily reveal the full string and repeat the comparison. For more involved directional context, continue with how browsers render mixed-direction text.

Test punctuation ownership across the actual message states#

Keep a fixture set tied to the conversion console's content contracts:

FixtureWhat the review must establish
English diagnostic with an exclamation markMark remains at the end of the English phrase
Same diagnostic with a full stopPunctuation is inside the same protected value
Arabic confirmation questionCorrect Arabic question-mark character and sentence reading
Arabic question containing the integration nameName's plus sign and sentence's question mark have separate owners
Preserved English questionEnglish question mark remains part of the verbatim response
Arabic operation listItem order, Arabic separators and absent-item behavior
Reviewer comment in either languageAutomatic isolation is applied to the comment alone

Compare each response or translation with the element's logical text, then review a browser screenshot. For an Arabic sentence, the expected end follows its RTL reading. For an embedded English message, the expected end follows its internal LTR reading. Avoid a test oracle that simply requires every terminal mark to appear on one physical side of the page.

Exercise status updates, language switching and compact message panels. Review the complete phrase after every transition, including its punctuation, rather than asserting only the words. Repeat visual checks in supported browsers; the measured examples are a starting point, not evidence for untested engines.

Have Arabic copy reviewed for character choice and meaning. Keep that review distinct from checks of exact engine output. Translating the former and preserving the latter are both intentional product decisions.

For misplaced marks, a free Ritla scan can report R024: Punctuation rendering at the wrong visual end of Arabic text. For character-choice issues, R064 reports Latin punctuation, or wrong-script letterforms, inside Arabic text. Phrase ownership and preserved diagnostics still need the targeted review above; continue with Arabic and English mixed text or bidi isolation in HTML to apply those boundaries in shared components.

Checks in this guide

See what your Arabic pages are hiding

Paste a URL. Ritla renders the page on desktop and mobile, runs every check, and shows the top issues with screenshot evidence.

Scan a page freeBrowse the checks