A per-direction acceptance condition is a pass/fail statement about a feature that is written twice, once for left-to-right (LTR) and once for right-to-left (RTL), and can be checked by looking at the running product. It replaces “add Arabic support”, which nobody can fail. It is for engineers, QA and product owners shipping bilingual Arabic/English software.
I’m Daniel Awde, an Engineering Manager. This is the checklist I use when a ticket says “Arabic support”. I argued for writing conditions per direction in why your team’s estimates are wrong. This post is the how.
Updated for 2026.
How to write the criterion: observable, per direction
A criterion is good when a second person can run it without asking you what you meant. Three rules cover most of it.
One observable outcome per line. “The form works in Arabic” is a hope. “With the interface in Arabic, submitting a name containing no Latin letters saves and displays that name unchanged” is a test.
Name the direction. Write the condition for LTR and again for RTL, even when the two are identical. The identical ones are the cheap ones to verify, and writing them down stops someone assuming the RTL case is covered by the LTR one.
Say what must not change. Some things do not mirror. Writing “the play button keeps pointing right” prevents a well-meaning global flip from breaking it.
| Vague ticket wording | Per-direction condition |
|---|---|
| Add Arabic support | Every screen in scope renders in dir="rtl" with no clipped, overlapping or LTR-anchored elements |
| Names must be validated | Names in Arabic script and Latin script both pass; a name is never split into first and last by the code |
| Sort the list | In Arabic, the list is ordered by the Arabic collation rules, and the same input always gives the same order |
| Show the date | The date appears in the calendar and digit style the product owner chose, in both directions |
Every row is something you can demonstrate. If you can’t describe the demonstration, the line isn’t finished.
Layout and mirroring
Layout is the criterion people remember and the one that is easiest to check, so start here.
- Reading order starts at the right edge. Navigation, table columns, form labels and step indicators begin at the right in RTL.
- Directional icons mirror. Back, forward, “next step” and progress arrows flip. Icons that depict a real object do not: a clock, a phone handset, a logo.
- Media controls do not flip. Timelines and play controls conventionally keep their direction. State it in the ticket.
- No physical left/right in the CSS. The code uses logical properties (
margin-inline-start,padding-inline-end,inset-inline-start) rather thanmargin-left. The MDN reference on logical properties lists the mapping. A grep forleft:,right:,margin-leftandpadding-rightin the diff is a fast review check. - Direction is set once, on the document.
dirandlangare on the root element and switch with the locale. The W3C guide to setting the base direction in HTML covers the attribute. - Truncation and overflow work from the correct end. Ellipsis and scroll position start at the right in RTL.
For the layout section of a ticket, the evidence is a screenshot pair, LTR and RTL, of each screen in scope.
Names, text and validation
This is where “renders Arabic characters” and “works in Arabic” come apart.
Names are not first name plus last name. The safe criterion is that the product stores and displays a name as entered. If your data model needs separate fields, ask for them explicitly and let users leave the split empty. Never write code that derives initials, a surname or a greeting from an Arabic name by splitting on spaces.
Validation accepts the script. A pattern like [A-Za-z ]+ rejects every Arabic name. The condition should read: “A name in Arabic script, a name in Latin script, and a name mixing both, each save successfully”. Length limits count characters the user sees, not bytes.
Mixed direction text stays readable. An Arabic sentence containing a Latin brand name, a number or a URL is bidirectional text, and the Unicode bidirectional algorithm decides how it is ordered. The failure to test for is punctuation drifting to the wrong end of a line. User-supplied strings inside a template should be isolated with <bdi> or the dir="auto" attribute, so one string’s direction can’t reorder the sentence around it. The W3C article on inline bidi markup explains why.
Some inputs stay LTR. Email addresses, URLs, and phone numbers are entered left to right even in an Arabic interface. Set their direction explicitly and write it as a criterion.
Error messages. Each validation message is in the interface language, sits next to the field it belongs to, and reads correctly when it contains a field name in another script.
Search treats variants as the same. Arabic has optional diacritics and several letter forms that users type interchangeably. The criterion is behavioural: “searching for a name typed without diacritics finds the stored name with them”. Whether to fold letter variants is a product decision. Make it, write it down, and test it. Do not stem names: a stemmer can merge unrelated people.
Sort, search, dates and numbers
These are the criteria that get skipped because the default looks plausible.
Sort. Code-point order is not the order an Arabic reader expects. Use locale-aware collation in the app, with Intl.Collator, and check what your database collation does for the same column. The condition: “the list is in the same order on the server-rendered page, after client-side sorting, and in the export”. Three surfaces, one order. Also fix the tie-break, or pagination will repeat and skip rows.
Calendars. Decide which calendar or calendars the product shows, and who chooses. It is a product decision with a per-market answer, and the answer is not mine to assume. The criterion names it: “dates display in the Gregorian calendar; the Hijri date shows only where the ticket says so”. If two calendars appear, decide which one is stored. Store one, in UTC, and format on output.
Digits. Arabic text can use Western digits or Arabic-Indic digits. Pick one per product, per surface if you must, and write it down. A mix on one screen is the failure. Format through the platform’s Intl APIs rather than string-building.
Week start, currency and units. The first day of the week is a locale setting, not a constant. Currency symbol placement, decimal and thousands separators come from the locale, so the criterion is “no hand-formatted numbers or dates in the code”.
Exports and documents. PDFs, emails and CSV files are where direction is forgotten. Each one gets its own line: the email template sets direction, the PDF shapes Arabic letters and orders text correctly, and the CSV opens with the right characters in the spreadsheet software your users actually have. Open it there and look.
Proving it: evidence per criterion
A checklist without evidence is a list of opinions. For each criterion, decide what the reviewer will look at before the work starts.
- Screenshot pairs for layout: same screen, LTR and RTL, same data.
- A fixed set of test strings stored in the repo: an Arabic-only name, a Latin-only name, a mixed name, a name with diacritics, a long name, an Arabic sentence containing a Latin brand and a number. Every form and every list is exercised with the same set.
- A pseudo-locale or forced
dir="rtl"in the development build, so RTL failures show up before a translation exists. - An automated check where it is cheap: a test that loads each route with
dir="rtl"and fails on horizontal overflow, and a lint rule against physical left/right properties. - A named reviewer who reads Arabic. Automated checks find overflow and not awkward phrasing. If nobody on the team reads Arabic, the ticket is not shippable, whatever the screenshots show.
Two habits keep the list honest. The author of the condition is the person doing the work, and someone else confirms they would recognise a pass. That catches the terms two people use differently. And nothing goes into a sprint until every line has its evidence named.
If you turn this into a template for your team, keep the sections above as headings on the ticket: layout, names and text, sort and search, dates and numbers, exports, evidence. Delete lines that don’t apply and say why, so “not applicable” is a recorded decision.
More on the wider argument that “done” has to be observable is in the engineering category, and my bilingual delivery work is summarised under work.
Frequently asked questions
What is an acceptance criterion for an RTL feature?
It is a pass/fail statement, checkable in the running product, about how one feature behaves in right-to-left mode. For example: “With the interface in Arabic, the back arrow points right and the primary navigation starts at the right edge.” It is written separately from the LTR version so neither direction is assumed.
Is RTL support just mirroring the layout?
No. Mirroring layout is one item on the list. Names, validation, mixed-direction text, sort order, calendars, digits, exports and email templates each behave differently in Arabic and each needs its own condition. A product can be fully mirrored and still reject valid Arabic names or sort them in the wrong order.
How do I test Arabic names in a form?
Keep a fixed set of test strings in the repo: Arabic only, Latin only, mixed, with diacritics, and a long one. Submit each through every form, then confirm that it saves, displays unchanged, and appears correctly in lists, search results and exports. The code must not split the name or apply a Latin-only pattern.
Which things should not be mirrored in RTL?
Icons that depict real objects, such as clocks and phone handsets, brand logos, and media playback controls usually keep their orientation. Numbers and Latin text inside Arabic sentences keep their own reading order. Write these exceptions into the ticket so a global flip doesn’t break them.
Do I need a native Arabic reader to sign off RTL work?
Yes. Automated checks catch overflow and physical left/right CSS, but not awkward phrasing, broken punctuation placement or a misleading translation. A reviewer who reads Arabic should sign off every screen in scope. If nobody on the team does, treat that as a gap in the definition of done.
Related reading
- Why your team’s estimates are wrong: the case for observable acceptance conditions
- All posts
- Engineering leadership category
By Daniel Awde, Engineering Manager. Updated for 2026. References: W3C Internationalization guides on base direction and inline bidi markup; Unicode Standard Annex 9 (bidirectional algorithm); MDN on CSS logical properties and Intl.Collator.
Related reading
- Why Your Team’s Estimates Are Wrong
- Requirements for an AI Automation: Template
- Budget Tracker: An Immutable-Ledger Design, a bilingual app with an Arabic right-to-left interface