Laravel localization in Arabic العربية
Everything you need to ship Arabic in a Laravel app: the right locale codes,
the exact plural forms trans_choice() expects,
real localized Carbon output and Arabic-script considerations.
Every value on this page was generated by running ICU, CLDR and Carbon — not copied from another article.
ISO 639-1
ar
Script / Direction
Arabic · RTL
Plural forms (Laravel)
6
Text vs English
Contracts
Locale codes
Set the base locale in config/app.php. For regional variants,
Arabic commonly uses:
ar_SA, ar_EG, ar_AE, ar_MA, ar_DZ
// config/app.php
'locale' => 'ar',
'fallback_locale' => 'en',
// Or switch at runtime
App::setLocale('ar');
Plural rules: what Arabic actually needs
CLDR defines 6 cardinal categories for Arabic. The sample numbers below were computed by ICU for this exact locale:
| CLDR category | Numbers that select it |
|---|---|
| zero | 0 |
| one | 1 |
| two | 2 |
| few | 3–10, 103–110 |
| many | 11–99, 111–130 |
| other | 100–102, 200, 1000, 1000000, 1.5 |
Laravel's trans_choice() maps numbers to
6 pipe-separated
forms for this locale:
| Form index | Numbers that select it |
|---|---|
| 0 | 0 |
| 1 | 1 |
| 2 | 2 |
| 3 | 3–10, 103–110 |
| 4 | 11–99, 111–130 |
| 5 | 100–102, 200, 1000 |
// lang/ar/messages.php
'items' => ':count item|:count items'
// Usage
trans_choice('messages.items', $count, ['count' => $count]);
This language uses 6 plural forms. Laravel's built-in trans_choice only resolves two, so for grammatically correct output use an ICU MessageFormat package or handle the extra forms explicitly against the CLDR categories above.
Try any number live in the pluralization tester.
Localized dates with Carbon
Real output for Arabic (ar locale),
generated by Carbon for March 21, 2026:
$date = now()->locale('ar');
$date->translatedFormat('l, j F Y');
// "السبت, 21 مارس 2026"
$date->isoFormat('LLLL');
// "السبت 21 مارس 2026 14:30"
$date->isoFormat('L');
// "21/3/2026"
$date->subDays(3)->diffForHumans();
// "منذ 3 أشهر"
What to watch out for in Arabic
- Right-to-left script: mirror layouts, icons with direction, and set dir="rtl" on rendered pages.
- CLDR defines six plural categories (zero, one, two, few, many, other); pluralization strings need all of them.
- Nouns and adjectives are gendered and verbs agree with the subject gender.
- Some regions use Eastern Arabic digits (٠١٢٣) while others use Western digits; number formatting varies by locale.
-
Right-to-left script: set
dir="rtl"on the<html>element and use CSS logical properties (or Tailwind's rtl: variant) instead of left/right.
Right-to-left is a layout problem, not a text problem
Arabic reads right to left, and the mistake teams make is treating that as something the font handles. Browsers do render the characters in the correct order automatically. What they do not do is mirror your interface: the sidebar stays on the left, the back arrow still points left, progress still flows left to right, and the whole product reads as though it were assembled backwards.
Setting direction at the document root is the first step and gets you most of the way.
Declaring direction
<html lang="ar" dir="rtl">
<!-- In Blade -->
<html lang="{{ app()->getLocale() }}"
dir="{{ in_array(app()->getLocale(), ['ar', 'he', 'fa', 'ur']) ? 'rtl' : 'ltr' }}">
The second step is removing every physical direction from your CSS. Properties such as margin-left, padding-right, left and text-align: left are absolute, so they keep pointing the same way when the document flips. Logical properties follow the reading direction instead and need no per-locale overrides.
| Physical (breaks in RTL) | Logical (adapts) | Tailwind |
|---|---|---|
margin-left |
margin-inline-start |
ms-4 |
padding-right |
padding-inline-end |
pe-4 |
text-align: left |
text-align: start |
text-start |
border-left |
border-inline-start |
border-s |
left: 0 |
inset-inline-start: 0 |
start-0 |
Icons need mirroring too, but only those that carry direction. Back and forward arrows, undo and redo, indentation controls and progress indicators should flip. Icons representing real objects should not: a clock still runs clockwise, a play button still points right by universal convention, and a mirrored logo is simply wrong.
Test with real Arabic rather than with a reversed English string. Pseudo-localisation that reverses Latin characters exercises none of the shaping, bidirectional or numeral behaviour that actually breaks.
Bidirectional text and the numbers that jump around
Arabic text routinely contains left-to-right runs: numbers, Latin brand names, URLs, code identifiers, email addresses. The Unicode bidirectional algorithm decides how to lay these out, and it gets the common cases right and the boundary cases spectacularly wrong.
The classic failure is punctuation at the edge of a mixed run. A sentence ending in a Latin product name followed by a full stop can render with the stop on the wrong side, and a phone number adjacent to a parenthesis can appear to have swapped its brackets. Nothing is corrupt — the algorithm resolved the direction of a neutral character differently from how you intended.
Isolating an embedded LTR run
<!-- Let the browser scope the direction of untrusted
or mixed content instead of guessing -->
<p>مرحبا <bdi>{{ $username }}</bdi> في التطبيق</p>
<!-- Or in CSS -->
.mixed { unicode-bidi: isolate; }
The <bdi> element exists precisely for this: it isolates a run whose direction you do not control, such as a user-supplied name, so it cannot reorder the text around it. Any interface that displays user input inside Arabic copy should use it.
Digits are a separate decision. Arabic-Indic numerals (٠١٢٣٤٥٦٧٨٩) are used in much of the Middle East, while Western digits are standard across North Africa and increasingly common everywhere in technical contexts. CLDR defaults to Western digits for ar and Arabic-Indic for some regional variants, so the numeral system your users see depends on the exact locale you pass.
Regardless of which digits are displayed, numbers themselves read left to right inside right-to-left text. A phone number, a price and a date all keep their internal order; only their position in the line flips.
Six plural forms, and why two is not close enough
Arabic has the most elaborate plural system CLDR describes: six categories, against two in English. A translation that supplies only a singular and a plural will produce grammatically wrong text across most of the number range, and it will do so silently.
| Category | Selected by | Example |
|---|---|---|
| zero | 0 | لا كتب |
| one | 1 | كتاب واحد |
| two | 2 | كتابان |
| few | 3–10, 103–110… | 3 كتب |
| many | 11–99, 111–199… | 11 كتابًا |
| other | 100–102, 200–202, fractions | 100 كتاب |
The two category is genuinely distinct — Arabic has a dual grammatical number, not just singular and plural — and the few and many categories key off the last two digits, so they recur cyclically rather than applying only to small numbers.
Laravel's trans_choice() selects among pipe-separated forms in CLDR order, so an Arabic string needs six segments. Getting the order or the count wrong shifts every form by one and produces text that is wrong for almost every input.
Six forms in one string
// lang/ar/messages.php — order matters:
// zero|one|two|few|many|other
'books' => 'لا كتب|كتاب واحد|كتابان|:count كتب|:count كتابًا|:count كتاب',
trans_choice('messages.books', $count, ['count' => $count]);
Verify the boundaries with the pluralization tester rather than assuming. The cases that catch people out are 0, 2, 11 and 100, none of which behave like their English equivalents.
Script shaping, fonts and the diacritics you will not see
Arabic letters change shape according to their position in a word — isolated, initial, medial or final — and connect to their neighbours. This is handled by the font's shaping tables, not by your code, but it has two practical consequences.
First, you cannot manipulate Arabic strings character by character. Truncating at a fixed character count can cut a word in a way that changes which glyphs render, and reversing or slicing a string will produce nonsense. Truncate on word boundaries, and let the browser handle overflow with CSS rather than PHP.
Second, font choice matters more than in Latin scripts. A font lacking proper Arabic shaping tables renders disconnected letters that a reader sees as broken rather than merely ugly. Test with the fonts you actually ship, and verify that your icon or fallback font does not silently win for Arabic ranges.
Arabic script also runs taller than Latin. Ascenders, descenders and diacritical marks need more vertical space, so line heights tuned for English will clip. Increase line height for Arabic rather than assuming a shared value works — a common symptom is marks above letters being cut off by an overflow rule.
Short vowels are normally unwritten in modern Arabic, which means the same written form can represent several words distinguished by context. This is a reason machine translation of short, contextless interface strings performs particularly poorly in Arabic, and a reason to give translators the screen context rather than a bare key.
Text length is unpredictable in both directions: Arabic often runs shorter than English because short vowels are omitted, while the script's greater height and different letterforms mean the visual footprint may still be larger. Do not assume the German rule of thumb applies.
Calendars, dates and regional variation
Arabic-speaking markets span more than twenty countries with genuinely divergent conventions, and the calendar is the most significant difference. The Hijri (Islamic lunar) calendar is used alongside the Gregorian one across the Gulf, and Saudi Arabia uses it officially.
A Hijri year is about eleven days shorter than a Gregorian one, so the two drift continuously against each other. Any feature involving dates for a Gulf audience — billing periods, deadlines, reporting — may need to display both, and cannot compute one from the other with a fixed offset.
| Egypt (ar_EG) | Saudi Arabia (ar_SA) | Morocco (ar_MA) | |
|---|---|---|---|
| Digits | Arabic-Indic | Arabic-Indic | Western |
| Calendar | Gregorian | Hijri + Gregorian | Gregorian |
| First day of week | Saturday | Sunday | Monday |
| Currency | ج.م | ر.س | د.م. |
The first day of the week varies by country, which affects every calendar and date-picker component. Defaulting to Monday, or to Sunday, will be wrong for a large part of your Arabic-speaking audience unless the component reads it from the locale.
Modern Standard Arabic, often abbreviated MSA, is the written register everywhere and is what interface copy should use. Regional dialects differ enormously in speech but are rarely written in formal contexts, so one Arabic translation genuinely does serve all markets. The variation you must handle sits in formatting, numerals and calendars rather than in the copy itself, which makes Arabic cheaper to maintain than its reputation suggests once the layout work is done.
Set the full locale so these differences resolve correctly. Passing a bare ar applies one set of defaults to every market, and the numeral system in particular is visible on every screen.
What ships broken most often
-
Layout not mirrored.
dir="rtl"set, but the CSS still uses physical properties, so the interface reads backwards. - Two plural forms instead of six. Grammatically wrong for most numbers, and invisible to anyone who does not read Arabic.
- Directional icons not flipped. Back arrows pointing the wrong way; or object icons mirrored when they should not be.
-
Mixed-direction text scrambled. User names or brand names inside Arabic copy reordering punctuation, fixed by
<bdi>. - Clipped diacritics. Line heights inherited from the Latin design cutting marks off the tops of letters.
- Character-level truncation. Slicing Arabic strings by character count, breaking letter shaping.
- Wrong first day of week. A calendar component that ignores the locale.
Arabic is the most demanding locale most products will add, and it is worth sequencing deliberately: fix the CSS to use logical properties first, then add the translations. Doing it the other way round means reviewing Arabic copy inside a layout that is itself broken, and neither problem can be judged clearly.
Install the Laravel-Lang Arabic files for framework strings rather than translating them yourself. Validation messages alone involve the full six-form plural system across dozens of rules, and getting that right by hand is a substantial piece of linguistic work that has already been done and reviewed by native speakers.
Budget review time with an actual Arabic reader rather than relying on coverage metrics. Every failure mode listed above is invisible to a reviewer who does not read the script: a mirrored layout looks plausible, a wrong plural form looks like text, and scrambled bidirectional punctuation looks like a font issue. Coverage percentages will report a fully translated locale in all of these cases.
Framework strings already translated
Laravel's own validation, auth and pagination strings are maintained in Arabic by the open-source Laravel-Lang project (MIT). Install them, then manage your app's own strings live:
composer require laravel-lang/common --dev
php artisan lang:add ar
php artisan lang:update
Translate your app into Arabic today
Import your lang files, translate every key into Arabic with one AI click, and publish changes live — no deploy. Set up in 5 minutes.