digitaltunnel / arabic-toolkit
Arabic name transliteration and money-to-words conversion for Laravel.
Requires
- php: ^8.2
- illuminate/support: ^11.0|^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^9.0|^10.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
README
Arabic Toolkit
The definitive Arabic language toolkit for Laravel -- transliteration, money-to-words, Hijri dates, and 9 more services for building Arabic applications.
1,200+ curated Arabic names, 12 currencies, 3 dialects, smart vowel insertion, and zero external dependencies.
Table of Contents
- Requirements
- Installation
- Quick Start
- Configuration
- Services
- API Reference
- Real-World Examples
- Architecture
- Testing
- Security
- License
Requirements
| Dependency | Version |
|---|---|
| PHP | ^8.2 |
| Laravel | 11.x, 12.x, 13.x |
Installation
composer require digitaltunnel/arabic-toolkit
The package auto-discovers its service provider and facade. No manual registration needed.
Publish Configuration (optional)
php artisan vendor:publish --tag=arabic-toolkit-config
This publishes config/arabic-toolkit.php where you can set application-wide defaults.
Quick Start
use DigitalTunnel\ArabicToolkit\Facades\ArabicToolkit; // Transliterate Arabic names to English ArabicToolkit::transliterate('حسام الشهري'); // "Hossam Al Shehri" // Convert money to words ArabicToolkit::moneyToWords(1500.50, 'EGP'); // "One Thousand Five Hundred Egyptian Pounds and Fifty Piastres" // Convert to Arabic words ArabicToolkit::moneyToWords(1500, 'EGP', locale: 'ar'); // "ألف وخمسمائة جنيه مصري" // Hijri date ArabicToolkit::toHijri('2026-04-04')->format('j F Y', 'ar'); // "١٦ شوال ١٤٤٧" // Arabic slug for URLs ArabicToolkit::slug('مقالة عن البرمجة'); // "مقالة-عن-البرمجة" // Detect gender from name ArabicToolkit::detectGender('فاطمة'); // "female"
Configuration
After publishing, edit config/arabic-toolkit.php:
return [ 'dialect' => 'egyptian', // 'egyptian', 'levantine', 'gulf' 'capitalize' => true, 'default_currency' => 'EGP', 'ta_marbuta' => 'a', // 'a', 'ah', 'et' 'money' => [ 'append_only' => false, // Add "Only" / "فقط" suffix 'locale' => 'en', // 'en' or 'ar' ], ];
All options can be overridden per-call via method parameters.
Services
1. Arabic Name Transliteration
Convert Arabic names to their English phonetic equivalents using a hybrid two-tier system:
- Tier 1: Dictionary of 1,200+ curated common names
- Tier 2: Smart character-by-character fallback with vowel insertion
// Dictionary matches (exact + fuzzy) ArabicToolkit::transliterate('حسام'); // "Hossam" ArabicToolkit::transliterate('محمد أحمد'); // "Mohammed Ahmed" ArabicToolkit::transliterate('عبدالله'); // "Abdullah" ArabicToolkit::transliterate('عبد الله'); // "Abdullah" (space variant) // Family names with "ال" prefix ArabicToolkit::transliterate('الشهري'); // "Al Shehri" ArabicToolkit::transliterate('القحطاني'); // "Al Qahtani" ArabicToolkit::transliterate('حسام الشهري'); // "Hossam Al Shehri" // Particle words ArabicToolkit::transliterate('محمد بن علي'); // "Mohammed Bin Ali" ArabicToolkit::transliterate('أبو بكر'); // "Abu Bakr" // Dialect support ArabicToolkit::transliterate('جمال', 'levantine'); // "Jamal" (not "Gamal")
Smart features:
| Feature | Example |
|---|---|
| Fuzzy matching (ى ↔ ي) | مصطفي → Mostafa (finds مصطفى) |
| Fuzzy matching (أ ↔ ا) | احمد → Ahmed (finds أحمد) |
| Compound joining | عبد + الله → Abdullah |
| Smart vowel insertion | الشهري → Al Shehri (not "Alshhry") |
| "ال" prefix handling | Always "Al " for names (no sun-letter assimilation) |
Supported dialects:
| Dialect | ج | ق | Example |
|---|---|---|---|
| Egyptian (default) | g | q | جمال → Gamal |
| Levantine | j | ' | جمال → Jamal |
| Gulf | j | g | جمال → Jamal |
2. Money to Words
Convert numeric amounts to written words with full currency support:
// English output ArabicToolkit::moneyToWords(1500.50, 'EGP'); // "One Thousand Five Hundred Egyptian Pounds and Fifty Piastres" ArabicToolkit::moneyToWords(1, 'USD'); // "One US Dollar" ArabicToolkit::moneyToWords(2500, 'SAR'); // "Two Thousand Five Hundred Saudi Riyals" // Arabic output ArabicToolkit::moneyToWords(1500.50, 'EGP', locale: 'ar'); // "ألف وخمسمائة جنيه مصري وخمسون قرش" // "Only" suffix for checks and invoices ArabicToolkit::moneyToWords(1500, 'EGP', appendOnly: true); // "One Thousand Five Hundred Egyptian Pounds Only" ArabicToolkit::moneyToWords(1500, 'EGP', appendOnly: true, locale: 'ar'); // "ألف وخمسمائة جنيه مصري فقط" // 3-decimal currencies ArabicToolkit::moneyToWords(1.001, 'KWD'); // "One Kuwaiti Dinar and One Fils"
Supported currencies (12):
| Code | Currency | Fractional Unit | Decimals |
|---|---|---|---|
| EGP | Egyptian Pound | Piastre | 2 |
| SAR | Saudi Riyal | Halala | 2 |
| AED | UAE Dirham | Fils | 2 |
| USD | US Dollar | Cent | 2 |
| EUR | Euro | Cent | 2 |
| GBP | British Pound | Penny/Pence | 2 |
| KWD | Kuwaiti Dinar | Fils | 3 |
| QAR | Qatari Riyal | Dirham | 2 |
| BHD | Bahraini Dinar | Fils | 3 |
| OMR | Omani Rial | Baisa | 3 |
| JOD | Jordanian Dinar | Fils | 3 |
| LBP | Lebanese Pound | Piastre | 2 |
All currencies include Arabic names with proper grammar (singular/dual/plural).
3. Text Utilities
Essential Arabic text processing operations:
// Remove diacritics (harakat) ArabicToolkit::removeHarakat('الحَمْدُ لِلَّهِ'); // "الحمد لله" // Normalize alef variants (أ إ آ → ا) ArabicToolkit::normalizeAlef('أحمد إبراهيم آدم'); // "احمد ابراهيم ادم" // Convert digits (Western ↔ Eastern) ArabicToolkit::toEasternDigits('2026'); // "٢٠٢٦" ArabicToolkit::toWesternDigits('٢٠٢٦'); // "2026" // Detect Arabic text ArabicToolkit::isArabic('حسام'); // true ArabicToolkit::isArabic('Hello'); // false // Remove tatweel/kashida ArabicToolkit::removeTatweel('حـــسام'); // "حسام"
4. Arabic Slug Generator
Generate URL-friendly slugs from Arabic text -- unlike Laravel's Str::slug() which destroys Arabic characters:
ArabicToolkit::slug('مقالة عن البرمجة'); // "مقالة-عن-البرمجة" ArabicToolkit::slug('أحمد إبراهيم'); // "احمد-ابراهيم" (normalizes alef variants) ArabicToolkit::slug('مقالة عن PHP'); // "مقالة-عن-php" (mixed Arabic/English) // Transliterated slug (Latin characters) ArabicToolkit::slug('مقالة عن البرمجة', transliterate: true); // "maqala-an-albarmaja"
Automatically removes harakat, normalizes alef, removes tatweel, collapses whitespace, and handles mixed-language text.
5. Search Normalization
Full normalization pipeline for Arabic text search indexing. Ensures that "أحمد", "احمد", "أَحْمَد" all match:
ArabicToolkit::normalizeForSearch('أحمد مُحَمَّد'); // "احمد محمد"
The pipeline applies (in order):
- Remove harakat (diacritics)
- Normalize alef variants (أ إ آ → ا)
- Normalize ta marbuta (ة → ه)
- Normalize ya maqsura (ى → ي)
- Remove tatweel
- Normalize digits (Eastern → Western)
- Collapse whitespace
Individual steps are also available:
ArabicToolkit::normalizeTaMarbuta('فاطمة'); // "فاطمه" ArabicToolkit::normalizeYaMaqsura('مصطفى'); // "مصطفي"
Laravel Scout integration:
// In your model's toSearchableArray() public function toSearchableArray() { return [ 'name' => ArabicToolkit::normalizeForSearch($this->name), 'bio' => ArabicToolkit::normalizeForSearch($this->bio), ]; }
6. Arabic Pluralization
Arabic has one of the most complex pluralization systems: singular, dual, plural (3-10), and singular again (11+). This service handles it:
ArabicToolkit::pluralize(0, 'ملف', 'ملفان', 'ملفات'); // "٠ ملفات" ArabicToolkit::pluralize(1, 'رسالة', 'رسالتان', 'رسائل'); // "رسالة" ArabicToolkit::pluralize(2, 'ملف', 'ملفان', 'ملفات'); // "ملفان" ArabicToolkit::pluralize(5, 'ملف', 'ملفان', 'ملفات'); // "٥ ملفات" ArabicToolkit::pluralize(15, 'ملف', 'ملفان', 'ملفات'); // "١٥ ملف"
Get just the word form without the number:
ArabicToolkit::pluralForm(5, 'ملف', 'ملفان', 'ملفات'); // "ملفات"
Arabic pluralization rules:
| Count | Form Used |
|---|---|
| 0 | Plural |
| 1 | Singular (no number shown) |
| 2 | Dual (no number shown) |
| 3-10 | Plural (جمع قلة) |
| 11+ | Singular (تمييز) |
7. Hijri Date Converter
Convert between Gregorian and Hijri (Islamic) calendar dates:
// Gregorian → Hijri $hijri = ArabicToolkit::toHijri('2026-04-04'); $hijri->format('j F Y'); // "16 Shawwal 1447" $hijri->format('j F Y', 'ar'); // "١٦ شوال ١٤٤٧" $hijri->format('d/m/Y'); // "16/10/1447" // Access components $hijri->day; // 16 $hijri->month; // 10 $hijri->year; // 1447 $hijri->monthName('en'); // "Shawwal" $hijri->monthName('ar'); // "شوال" // Hijri → Gregorian $gregorian = ArabicToolkit::fromHijri(16, 10, 1447); // ['year' => 2026, 'month' => 4, 'day' => 4] // Today in Hijri $today = ArabicToolkit::hijriToday();
Format tokens:
| Token | Output | Example |
|---|---|---|
j |
Day (1-30) | 7 |
d |
Day with leading zero | 07 |
n |
Month (1-12) | 10 |
m |
Month with leading zero | 10 |
F |
Month name | Shawwal / شوال |
Y |
Year (4 digits) | 1447 |
Hijri month names:
| # | English | Arabic |
|---|---|---|
| 1 | Muharram | محرم |
| 2 | Safar | صفر |
| 3 | Rabi al-Awwal | ربيع الأول |
| 4 | Rabi al-Thani | ربيع الثاني |
| 5 | Jumada al-Ula | جمادى الأولى |
| 6 | Jumada al-Thani | جمادى الآخرة |
| 7 | Rajab | رجب |
| 8 | Sha'ban | شعبان |
| 9 | Ramadan | رمضان |
| 10 | Shawwal | شوال |
| 11 | Dhul Qi'dah | ذو القعدة |
| 12 | Dhul Hijjah | ذو الحجة |
8. Gender Detection
Detect the gender of an Arabic name using dictionary lookup + morphological analysis:
ArabicToolkit::detectGender('محمد'); // "male" ArabicToolkit::detectGender('فاطمة'); // "female" ArabicToolkit::detectGender('إحسان'); // "unisex" ArabicToolkit::detectGender('نور'); // "unisex"
Detection layers:
- Dictionary lookup -- checks against known male/female/unisex names
- Morphological rules:
- Ta marbuta (ة) ending → female
- Alef maqsura (ى) ending → female
- اء ending → female (أسماء, شيماء, زهراء)
- Default → male
9. Number Formatting
Format numbers with Eastern Arabic digits, separators, and ordinals:
// Eastern Arabic digit formatting ArabicToolkit::formatNumber(1234567.89); // "١٬٢٣٤٬٥٦٧٫٨٩" ArabicToolkit::formatNumber(1234567.89, decimals: 0); // "١٬٢٣٤٬٥٦٨" // Percentage ArabicToolkit::formatPercentage(0.157); // "١٥٫٧٪" // Ordinals (1st-10th with gender) ArabicToolkit::ordinal(1); // "الأول" ArabicToolkit::ordinal(3); // "الثالث" ArabicToolkit::ordinal(1, 'female'); // "الأولى" ArabicToolkit::ordinal(3, 'female'); // "الثالثة"
Ordinals (masculine/feminine):
| # | Male | Female |
|---|---|---|
| 1 | الأول | الأولى |
| 2 | الثاني | الثانية |
| 3 | الثالث | الثالثة |
| 4 | الرابع | الرابعة |
| 5 | الخامس | الخامسة |
| 6 | السادس | السادسة |
| 7 | السابع | السابعة |
| 8 | الثامن | الثامنة |
| 9 | التاسع | التاسعة |
| 10 | العاشر | العاشرة |
10. Keyboard Layout Converter
Fix text typed with the wrong keyboard layout active -- a very common issue in Arabic applications:
// English keys typed on Arabic keyboard → Arabic ArabicToolkit::fixKeyboard('pshl'); // "حسام" // Arabic keys typed on English keyboard → English ArabicToolkit::fixKeyboard('حسام', 'ar_to_en'); // "pshl" // Auto-detect direction ArabicToolkit::fixKeyboard('pshl'); // Arabic detected → "حسام" ArabicToolkit::fixKeyboard('حسام'); // English detected → "pshl" // Get both variants for search ArabicToolkit::searchVariants('pshl'); // ['original' => 'pshl', 'swapped' => 'حسام']
Useful for search boxes where users forget to switch keyboard layout.
11. BiDi Text Helpers
Handle bidirectional text issues when mixing Arabic (RTL) and English (LTR):
// Detect text direction ArabicToolkit::textDirection('مرحبا بالعالم'); // "rtl" ArabicToolkit::textDirection('Hello World'); // "ltr" // Fix BiDi display issues (wraps LTR segments with Unicode marks) ArabicToolkit::bidi('اتصل على 0501234567'); // Wraps phone number with LRM marks to prevent reversal
12. Arabic Greeting Generator
Generate contextually correct, gender-aware Arabic greetings:
// Time-aware greeting (morning/evening) ArabicToolkit::greeting('محمد'); // "صباح الخير يا محمد" (morning) or "مساء الخير يا محمد" (evening) // Formal salutation for letters/emails ArabicToolkit::salutation('محمد', 'male'); // "السيد محمد المحترم" ArabicToolkit::salutation('فاطمة', 'female'); // "السيدة فاطمة المحترمة" // Welcome message with gender-correct pronoun ArabicToolkit::welcome('أحمد', 'male'); // "أهلاً بك يا أحمد" ArabicToolkit::welcome('سارة', 'female'); // "أهلاً بكِ يا سارة"
Gender is auto-detected using the Gender Detection service when not specified.
API Reference
ArabicToolkit Facade
| Method | Returns | Service |
|---|---|---|
transliterate(string, ?string) |
string |
Transliteration |
moneyToWords(float|int, ?string, bool, ?string) |
string |
Money to Words |
removeHarakat(string) |
string |
Text Utilities |
normalizeAlef(string) |
string |
Text Utilities |
toEasternDigits(string) |
string |
Text Utilities |
toWesternDigits(string) |
string |
Text Utilities |
isArabic(string) |
bool |
Text Utilities |
removeTatweel(string) |
string |
Text Utilities |
normalizeForSearch(string) |
string |
Search Normalization |
normalizeTaMarbuta(string) |
string |
Search Normalization |
normalizeYaMaqsura(string) |
string |
Search Normalization |
slug(string, bool) |
string |
Slug Generator |
pluralize(int, string, string, string) |
string |
Pluralization |
pluralForm(int, string, string, string) |
string |
Pluralization |
toHijri(string) |
HijriDate |
Hijri Date |
fromHijri(int, int, int) |
array |
Hijri Date |
hijriToday() |
HijriDate |
Hijri Date |
detectGender(string) |
string |
Gender Detection |
formatNumber(float|int, int) |
string |
Number Formatting |
formatPercentage(float, int) |
string |
Number Formatting |
ordinal(int, string) |
string |
Number Formatting |
fixKeyboard(string, ?string) |
string |
Keyboard Layout |
searchVariants(string) |
array |
Keyboard Layout |
bidi(string) |
string |
BiDi Helpers |
textDirection(string) |
string |
BiDi Helpers |
greeting(string, ?string) |
string |
Greeting Generator |
salutation(string, ?string) |
string |
Greeting Generator |
welcome(string, ?string) |
string |
Greeting Generator |
Real-World Examples
Invoice Generator
$amount = 15750.50; $hijri = ArabicToolkit::toHijri(now()->format('Y-m-d')); echo ArabicToolkit::moneyToWords($amount, 'SAR', appendOnly: true, locale: 'ar'); // "خمسة عشر ألف وسبعمائة وخمسون ريال سعودي وخمسون هللة فقط" echo $hijri->format('d/m/Y', 'ar'); // "١٦/١٠/١٤٤٧"
Blog Post URL
$post = Post::create(['title' => 'مقالة عن الذكاء الاصطناعي']); $post->slug = ArabicToolkit::slug($post->title); // "مقالة-عن-الذكاء-الاصطناعي"
Search with Arabic Normalization
// Index $product->search_name = ArabicToolkit::normalizeForSearch($product->name); // Query (user types "أحمد" or "احمد" -- both match) $query = ArabicToolkit::normalizeForSearch($request->q); $results = Product::where('search_name', 'LIKE', "%{$query}%")->get();
Personalized Email
$gender = ArabicToolkit::detectGender($user->first_name); $salutation = ArabicToolkit::salutation($user->first_name, $gender); $name_en = ArabicToolkit::transliterate($user->first_name); Mail::to($user)->send(new WelcomeMail($salutation, $name_en));
Smart Search Box
// User types "pshl" (forgot to switch keyboard) $variants = ArabicToolkit::searchVariants($request->q); $results = User::where('name', 'LIKE', "%{$variants['original']}%") ->orWhere('name', 'LIKE', "%{$variants['swapped']}%") ->get();
Arabic Dashboard Numbers
$stats = [ 'revenue' => ArabicToolkit::formatNumber($totalRevenue), // "١٬٢٣٤٬٥٦٧٫٨٩" 'growth' => ArabicToolkit::formatPercentage($growthRate), // "١٥٫٧٪" 'rank' => ArabicToolkit::ordinal($rank), // "الثالث" 'files' => ArabicToolkit::pluralize($count, 'ملف', 'ملفان', 'ملفات'), ];
Architecture
src/
├── ArabicToolkit.php # Main entry point (28 public methods)
├── config/
│ └── arabic-toolkit.php # Configuration
├── Contracts/
│ ├── TransliteratorInterface.php
│ └── MoneyConverterInterface.php
├── Currency/
│ ├── CurrencyRegistry.php # 12 currencies (EN + AR names)
│ ├── MoneyToWords.php # Bilingual money converter
│ ├── NumberToWords.php # English number engine
│ └── NumberToWordsArabic.php # Arabic number engine
├── Facades/
│ └── ArabicToolkit.php # Laravel Facade
├── Hijri/
│ ├── HijriConverter.php # Kuwaiti algorithm
│ └── HijriDate.php # Value object with formatting
├── Providers/
│ └── ArabicToolkitServiceProvider.php
├── Support/
│ ├── ArabicBidi.php # BiDi text handling
│ ├── ArabicGreeting.php # Gender-aware greetings
│ ├── ArabicNumber.php # Number formatting & ordinals
│ ├── ArabicPlural.php # Arabic pluralization rules
│ ├── ArabicSlug.php # URL slug generator
│ ├── ArabicText.php # Text normalization utilities
│ ├── GenderDetector.php # Name gender detection
│ └── KeyboardLayout.php # QWERTY ↔ Arabic mapping
└── Transliteration/
├── ArabicTransliterator.php # Two-tier transliteration engine
├── CharacterMap.php # Dialect-aware letter mappings
└── NameDictionary.php # 1,200+ curated names
Zero dependencies beyond Laravel's Illuminate Support.
Key design decisions:
- All utility classes use static methods for simple direct usage
- The Facade delegates everything to the main
ArabicToolkitclass - Name dictionary is a PHP constant array (no database, no JSON files)
- Float-safe money conversion using integer math
- Fuzzy name matching handles common Arabic typos automatically
Testing
The package ships with 175 Pest tests covering every service:
cd packages/digitaltunnel/arabic-toolkit
./vendor/bin/pest
PASS Tests\Unit\ArabicTextTest ............... 17 tests
PASS Tests\Unit\GenderTest .................... 8 tests
PASS Tests\Unit\HijriTest ..................... 8 tests
PASS Tests\Unit\KeyboardAndBidiTest .......... 16 tests
PASS Tests\Unit\MoneyToWordsTest ............. 63 tests
PASS Tests\Unit\NumberFormatTest .............. 7 tests
PASS Tests\Unit\PluralTest .................... 7 tests
PASS Tests\Unit\SlugTest ...................... 7 tests
PASS Tests\Unit\TransliterationTest .......... 42 tests
Tests: 175 passed (253 assertions)
Security
If you discover a security vulnerability, please send an email to hey@digitaltunnel.net instead of opening a public issue.
See SECURITY.md for full details on our security policy, supported versions, and best practices.
License
The MIT License (MIT). See LICENSE for details.