Hussain Alsharman
About
Arabic formatting MCP server: currency for all 22 Arab League countries (Saudi riyal U+20C1), Umm al-Qura Hijri dates, طيقفت, RTL/bidi fixes
Details
- Author
- cc1a2b
- Categories
- Developer Tools, Other
Jump to
Setup
Install Hussain Alsharman in your MCP client (Claude Desktop, Cursor, Windsurf, and others).
Repository: https://github.com/cc1a2b/arabicfmt
Follow the installation instructions in the repository README, then restart your MCP client.
Arabic formatting MCP server: currency for all 22 Arab League countries (Saudi riyal U+20C1), Umm al-Qura Hijri dates, طيقفت, RTL/bidi fixes
Arabic-first formatting for JavaScript & TypeScript
Currency symbols · Hijri/Islamic calendar · number-to-words · تفقيط · 6 plural forms · RTL/bidi —
correct for all22 Arab League countries, withzero dependenciesand full TypeScript types.
أرقامٌ وعملاتٌ وتواريخُ هجريةٌ ولغةٌ عربيةٌ سليمة — في سطرٍ واحد.
arabicfmtis the only JavaScript library that handles the entire Arabic formatting stack in one zero-dependency package — currency symbols, number precision, Hijri/Islamic calendar dates, RTL bidirectional text, Arabic number-to-words and تفقيط — with full TypeScript types. Works inNode, the browser, Deno, Bun and React Native.
npm install arabicfmt # or yarn add arabicfmt # or pnpm add arabicfmt
Requirements:Node.js ≥ 18 · TypeScript ≥ 4.7 (optional) · zero runtime dependencies.
Every release is mirrored on thejsDelivrandunpkgCDNs automatically. Import the browser-ready ESM bundle straight from a URL — no install, no bundler:
<script type="module"> import { formatCurrency, formatHijri } from "https://cdn.jsdelivr.net/npm/arabicfmt/+esm"; console.log(formatCurrency(1234.5, { currency: "SAR", numerals: "arab" })); // ١٬٢٣٤٫٥٠ ر.س console.log(formatHijri(new Date(), { numerals: "arab" })); // ٢٧ ذو الحجة ١٤٤٧ هـ </script>
Subpaths work too — e.g.https://cdn.jsdelivr.net/npm/arabicfmt/dist/currency/index.jsfor just the currency module. Pin a version for production, e.g.arabicfmt@0.1.
import { formatCurrency, // correct symbol + precision for every Arab currency formatCompact, // 1,200,000 → "1.2M" / "١٫٢ مليون" arabicToWords, // 1234 → "ألف ومئتان وأربعة وثلاثون" spellCurrency, // تفقيط: 1234.5 SAR → "...ريالاً وخمسون هللةً" arabicOrdinal, // 25 → "الخامس والعشرون" formatDuration, // 7_500_000ms → "ساعتان وخمس دقائق" formatFileSize, // 1536 → "1.5 كيلوبايت" formatRelativeTime, // "منذ ٣ أيام" formatList, // ["أحمد","علي"] → "أحمد وعلي" parseCurrency, // "١٬٢٣٤٫٥٠ ر.س" → 1234.5 arabicPlural, // full 6-form Arabic plural selection sortArabic, // Arabic-locale collation slugify, // "مدينة جدة" → "mdynh-jdh" (URL slugs) isValidIBAN, // ISO 7064 mod-97 IBAN checksum isValidSaudiId, // Saudi national ID / Iqama check digit isolateForeign, // fix broken RTL sentences normalizeForSearch, // search-key normalization detectLocale, // auto-detect from browser / Node environment } from "arabicfmt"; import { formatHijri, toHijri } from "arabicfmt/umalqura"; // deterministic Hijri calendar // Currency formatCurrency(1.2, { currency: "KWD" }); // "1.200 د.ك" formatCurrency(1234, { locale: "ar-SA", numerals: "arab" }); // "١٬٢٣٤٫٠٠ ر.س" formatCurrency(-500, { currency: "SAR", accounting: true }); // "(500.00 ر.س)" formatCompact(1_500_000, { locale: "ar", numerals: "arab" }); // "١٫٥ مليون" // Number to Arabic words arabicToWords(1234); // "ألف ومئتان وأربعة وثلاثون" arabicToWords(1_000_000); // "مليون" arabicToWords(5, { gender: "female" }); // "خمس" // Spell money for invoices & cheques (التفقيط) spellCurrency(1234.5, { currency: "SAR" }); // "ألف ومئتان وأربعة وثلاثون ريالاً وخمسون هللةً" spellCurrency(100, { currency: "SAR", suffix: true }); // "مئة ريال فقط لا غير" // Ordinals — gender-aware arabicOrdinal(1); // "الأول" arabicOrdinal(25); // "الخامس والعشرون" arabicOrdinal(1, { gender: "female" }); // "الأولى" // Duration & file size formatDuration(7_500_000); // "ساعتان وخمس دقائق" formatFileSize(1536); // "1.5 كيلوبايت" // Lists formatList(["أحمد", "محمد", "علي"]); // "أحمد ومحمد وعلي" formatList(["تفاح", "موز"], { type: "disjunction" }); // "تفاح أو موز" // Hijri dates (deterministic — same output on Node, Chrome, Safari, Hermes) formatHijri(new Date("2025-09-23")); // "1 ربيع الآخر 1447 هـ" formatHijri(new Date("2025-09-23"), { numerals: "arab" }); // "١ ربيع الآخر ١٤٤٧ هـ" toHijri(new Date("2025-09-23")); // { year: 1447, month: 4, day: 1 } // Relative time formatRelativeTime(new Date(Date.now() - 3 86400_000)); // "منذ 3 أيام" // Parse formatted strings back to numbers parseCurrency("١٬٢٣٤٫٥٠ ر.س"); // 1234.5 parseCurrency("(500.00 SAR)"); // -500 // RTL isolateForeign("اتصل على +1 (555) 234-5678 الآن"); // phone stays intact in RTL // Locale auto-detection detectLocale(); // "ar-SA" in a Saudi browser, "ar-EG" in Node with LANG=ar_EG
TheSaudi riyalreceived its own Unicode symbol (U+20C1) in September 2025. Most libraries either emit the wrong ligature (U+FDFC, the Iranian rial) or fall back toSAR. arabicfmt gives you full control:
import { formatCurrency, resolveCurrencySymbol, getCurrencyInfo } from "arabicfmt/currency"; formatCurrency(1234.5, { currency: "SAR" }); // → "1,234.50 ر.س" (auto: safe text symbol, renders everywhere today) formatCurrency(1234.5, { currency: "SAR", symbolMode: "new" }); // → "1,234.50 " (U+20C1 — use with a webfont; see webfont guide below) formatCurrency(1234.5, { currency: "SAR", symbolMode: "code" }); // → "1,234.50 SAR" (ISO code — for accounting tables)
Unicode 18.0 (September 2026):the AED (U+20C3) and OMR (U+20C4) signs are nowlive, andautoprefers them. Need maximum compatibility today? UsesymbolMode: "text". The Saudi riyal keeps its safe text default by design.
Correct decimal precision — all 22 Arab League countries
Generated from CLDR 48.2.0 at build time andverified on every build:
formatCurrency(1.2, { currency: "KWD" }); // "1.200 د.ك" ← 3 decimals formatCurrency(1.2, { currency: "BHD" }); // "1.200 د.ب" ← 3 decimals formatCurrency(1.2, { currency: "IQD" }); // "1.200 ع.د" ← 3 decimals (ISO 4217, not CLDR's 0) formatCurrency(500, { currency: "KMF" }); // "500 ف.ج.ق" ← 0 decimals formatCurrency(500, { currency: "SAR" }); // "500.00 ر.س" ← 2 decimals
// Resolve from locale region — no need to know the currency code formatCurrency(99.9, { locale: "ar-BH" }); // "99.900 د.ب" formatCurrency(1234, { locale: "ar-AE", numerals: "arab", symbolMode: "text" }); // "١٬٢٣٤٫٠٠ د.إ" (auto → U+20C3 sign) // Accounting notation (negatives in parentheses) formatCurrency(-1234.5, { currency: "SAR", accounting: true }); // "(1,234.50 ر.س)" // Hide/override formatCurrency(100, { currency: "SAR", showSymbol: false, fractionDigits: 0 }); // "100" // Currency metadata getCurrencyInfo("SAR"); // { // code: "SAR", digits: 2, // symbols: { auto: "ر.س", text: "ر.س", code: "SAR", new: "" }, // unicode: { codepoint: "U+20C1", unicodeVersion: "17.0", live: true, autoDefault: false }, // displayName: "ريال سعودي" // }
/ Scope the Saudi Riyal font to just that codepoint — zero impact on body text / @font-face { font-family: "Riyal"; src: url("/fonts/saudi-riyal.woff2") format("woff2"); unicode-range: U+20C1; } :root { font-family: "Riyal", "Noto Naskh Arabic", sans-serif; }
import { formatNumber, formatCompact, formatPercent, toArabicDigits, toLatinDigits, parseNumber, parseCurrency, arabicToWords, formatRelativeTime, } from "arabicfmt/number"; // Standard formatNumber(1_234_567.89, { locale: "en" }); // "1,234,567.89" formatNumber(1234.5, { numerals: "arab" }); // "١٬٢٣٤٫٥" // Compact / short notation — dashboards and data cards formatCompact(1_500_000); // "1.5M" formatCompact(1_500_000, { locale: "ar" }); // "1.5 مليون" formatCompact(1_500_000, { locale: "ar", numerals: "arab" }); // "١٫٥ مليون" // Percent formatPercent(0.853, { locale: "en" }); // "85.3%" // Transliteration toArabicDigits("Order #2026"); // "Order #٢٠٢٦" toLatinDigits("٢٠٢٦"); // "2026" (handles Persian ۰–۹ too) // Parsing — round-trip support parseNumber("١٬٢٣٤٫٥٦"); // 1234.56 (Eastern Arabic digits + separators) parseNumber("1,234.56"); // 1234.56 (Western) parseCurrency("١٬٢٣٤٫٥٠ ر.س"); // 1234.5 parseCurrency("(500.00 SAR)"); // -500 (accounting notation) // Relative time formatRelativeTime(new Date(Date.now() - 3 86400_000)); // "منذ 3 أيام" formatRelativeTime(new Date(Date.now() + 3600_000), new Date(), { locale: "en" }); // "in 1 hour"
Number to Arabic words (arabicToWords)
Convert integers to their Arabic word representation — handles gender agreement and all six scale levels.
import { arabicToWords } from "arabicfmt"; // Basic arabicToWords(0) // "صفر" arabicToWords(1) // "واحد" arabicToWords(2) // "اثنان" arabicToWords(11) // "أحد عشر" arabicToWords(25) // "خمسة وعشرون" arabicToWords(100) // "مئة" arabicToWords(350) // "ثلاثمئة وخمسون" // Thousands arabicToWords(1000) // "ألف" arabicToWords(2000) // "ألفان" arabicToWords(5000) // "خمسة آلاف" arabicToWords(11000) // "أحد عشر ألفاً" arabicToWords(100000) // "مئة ألف" // Millions / billions arabicToWords(1_000_000) // "مليون" arabicToWords(2_000_000) // "مليونان" arabicToWords(5_000_000) // "خمسة ملايين" arabicToWords(1_000_000_000)// "مليار" // Large composite arabicToWords(1_234_567) // "مليون ومئتان وأربعة وثلاثون ألفاً وخمسمئة وسبعة وستون" // Gender agreement — feminine noun (ليرة، روبية…) arabicToWords(3, { gender: "female" }) // "ثلاث" arabicToWords(5, { gender: "female" }) // "خمس" // Negative arabicToWords(-42) // "سالب اثنان وأربعون" // Decimals — opt in (default truncates, stays backward compatible) arabicToWords(3.14, { fraction: "digits" }) // "ثلاثة فاصلة واحد أربعة" arabicToWords(3.14, { fraction: "number" }) // "ثلاثة فاصلة أربعة عشر" // Common fractions (denominators 2–10) import { arabicFraction } from "arabicfmt"; arabicFraction(1, 2) // "نصف" arabicFraction(3, 4) // "ثلاثة أرباع" arabicFraction(2, 3) // "ثلثان"
spellCurrencyis thetafqitevery Arabic invoice, cheque and contract needs: it turns a numeric amount into its full legal Arabic wording, splitting major and minor units and inflecting every noun for correct grammatical agreement (singular / dual / plural / accusative).
import { spellCurrency } from "arabicfmt"; spellCurrency(1234.5, { currency: "SAR" }) // "ألف ومئتان وأربعة وثلاثون ريالاً وخمسون هللةً" // Unit agreement is automatic (العدد والمعدود) spellCurrency(1, { currency: "SAR" }) // "ريال واحد" (singular) spellCurrency(2, { currency: "SAR" }) // "ريالان" (dual) spellCurrency(3, { currency: "SAR" }) // "ثلاثة ريالات" (plural, 3–10) spellCurrency(11, { currency: "SAR" }) // "أحد عشر ريالاً" (accusative, 11–99) spellCurrency(100, { currency: "SAR" }) // "مئة ريال" (genitive singular) // Minor-unit precision comes from CLDR — KWD = 1000 fils, SAR = 100 halalas spellCurrency(1.5, { currency: "KWD" }) // "دينار واحد وخمسمئة فلس" spellCurrency(0.75, { currency: "SAR" }) // "خمس وسبعون هللةً" // Cheque-ready ending and locale-derived currency spellCurrency(100, { currency: "SAR", suffix: true }) // "مئة ريال فقط لا غير" spellCurrency(-5, { locale: "ar-AE" }) // "سالب خمسة دراهم"
Full Arabic noun paradigms are bundled for all 22 Arab League currencies (SAR, AED, KWD, BHD, QAR, OMR, JOD, EGP, IQD, LYD, TND, DZD, MAD, SDG, LBP, SYP, YER, SOS, DJF, KMF, MRU). Inspect or extend them via the exportedCURRENCY_WORDStable.
import { arabicOrdinal } from "arabicfmt"; arabicOrdinal(1) // "الأول" arabicOrdinal(2) // "الثاني" arabicOrdinal(10) // "العاشر" arabicOrdinal(11) // "الحادي عشر" arabicOrdinal(25) // "الخامس والعشرون" // Gender agreement arabicOrdinal(1, { gender: "female" }) // "الأولى" arabicOrdinal(25, { gender: "female" }) // "الخامسة والعشرون" // Indefinite (drop the article ال) arabicOrdinal(3, { definite: false }) // "ثالث" arabicOrdinal(25, { definite: false }) // "خامس وعشرون"
formatDurationturns a time span into its spoken Arabic form, with correct dual/plural/accusative agreement on every unit — somethingIntl.DurationFormat(still barely supported) does not give you.
import { formatDuration } from "arabicfmt"; formatDuration(7_500_000) // "ساعتان وخمس دقائق" (2h 5m) formatDuration(90, { input: "s" }) // "دقيقة واحدة وثلاثون ثانيةً" formatDuration(3_600_000, { largest: 1 }) // "ساعة واحدة" formatDuration(2 86_400_000) // "يومان" formatDuration(500) // "أقل من ثانية" // Restrict the units considered formatDuration(125 60_000, { units: ["minute"], largest: 1 }) // "مئة وخمس وعشرون دقيقةً"
largest(default2) caps how many units appear, biggest first. Want to drive the noun agreement yourself?countedNoun(n, forms)is exported for any custom counted noun.
import { formatFileSize } from "arabicfmt"; formatFileSize(0) // "0 بايت" formatFileSize(1536) // "1.5 كيلوبايت" formatFileSize(5 1024 1024) // "5 ميجابايت" formatFileSize(1_500_000, { base: 1000 }) // "1.5 ميجابايت" (decimal/SI) formatFileSize(2048, { numerals: "arab" }) // "٢ كيلوبايت" formatFileSize(2048, { unitStyle: "latin" })// "2 KB"
Units scale through بايت · كيلوبايت · ميجابايت · جيجابايت · تيرابايت · بيتابايت, withbase: 1024(binary, default) orbase: 1000(decimal).
Arabic has six plural forms — more than any other major language. Standard i18n libraries handle 1–2 forms and break for Arabic.
import { arabicPluralForm, arabicPlural } from "arabicfmt"; // Get the CLDR form name arabicPluralForm(0) // "zero" arabicPluralForm(1) // "one" arabicPluralForm(2) // "two" arabicPluralForm(5) // "few" (3–10) arabicPluralForm(15) // "many" (11–99) arabicPluralForm(100) // "other" // Select the right string const forms = { zero: "لا كتب", one: "كتاب واحد", two: "كتابان", few: "كتب", // 3–10 many: "كتاباً", // 11–99 other: "كتاب", }; arabicPlural(0, forms) // "لا كتب" arabicPlural(1, forms) // "كتاب واحد" arabicPlural(2, forms) // "كتابان" arabicPlural(5, forms) // "كتب" arabicPlural(25, forms) // "كتاباً" arabicPlural(100, forms) // "كتاب"
import { toHijri, fromHijri, formatHijri, umalquraToGregorian } from "arabicfmt/umalqura"; // Convert toHijri(new Date("2025-09-23")) // { year: 1447, month: 4, day: 1 } umalquraToGregorian(1447, 9, 1) // JavaScript Date — first day of Ramadan 1447 // Format — Arabic formatHijri(new Date("2025-09-23")) // "1 ربيع الآخر 1447 هـ" formatHijri(new Date("2025-09-23"), { numerals: "arab" }) // "١ ربيع الآخر ١٤٤٧ هـ" // Format — English formatHijri(new Date("2025-09-23"), { locale: "en" }) // "1 Rabi al-Thani 1447 AH" // Format — ISO-style numeric formatHijri(new Date("2025-09-23"), { locale: "en", month: "2-digit", day: "2-digit", order: "ymd", era: false, }) // "1447/04/01"
import { HIJRI_MONTHS_AR, // Arabic Hijri month names HIJRI_MONTHS_EN, // English Hijri month names GREGORIAN_MONTHS_AR, // Arabic Gregorian month names (يناير، فبراير…) GREGORIAN_MONTHS_EN, ARABIC_WEEKDAYS_AR, // Arabic weekday names (الأحد، الاثنين…) ARABIC_WEEKDAYS_EN, } from "arabicfmt/date"; HIJRI_MONTHS_AR[8] // "رمضان" (index 0 = Muharram) GREGORIAN_MONTHS_AR[0] // "يناير" (index 0 = January) ARABIC_WEEKDAYS_AR[5] // "الجمعة" (index 0 = Sunday)
Stop phone numbers and English words from scrambling Arabic sentences:
import { detectDirection, isolate, isolateForeign, stripBidi } from "arabicfmt/bidi"; // Before fix: "+1 (555) 234-5678" flips the area code in RTL context // After fix: the phone number is wrapped in Unicode isolates — sentence intact isolateForeign("اتصل على +1 (555) 234-5678 الآن"); detectDirection("مرحبا"); // "rtl" detectDirection("Hello"); // "ltr" isolate("9:41 AM"); // FSI … PDI isolate around a mixed run stripBidi(dirtyStr); // remove every Unicode bidi control character
Match Arabic text despite diacritics, alef variants, hamza and taa marbuta differences:
import { stripTashkeel, normalizeArabic, normalizeForSearch, sortArabic, compareArabic, } from "arabicfmt/text"; stripTashkeel("مُحَمَّد") // "محمد" normalizeArabic("الأحمد") // "الاحمد" (alef variants unified) // Robust search — these two strings produce the same key: normalizeForSearch("مُؤسَّسة") === normalizeForSearch("موسسه") // true // Arabic-locale collation sortArabic(["ياسر", "أحمد", "بسام"]) // ["أحمد", "بسام", "ياسر"] ["ج", "أ", "ب"].sort(compareArabic) // ["أ", "ب", "ج"]
Join values into a grammatical Arabic list. WrapsIntl.ListFormatand degrades gracefully on runtimes without it.
import { formatList } from "arabicfmt"; formatList(["أحمد", "محمد", "علي"]) // "أحمد ومحمد وعلي" formatList(["تفاح", "موز", "برتقال"], { type: "disjunction" }) // "تفاح أو موز أو برتقال" formatList([1, 2, 3], { numerals: "arab" }) // "١ و٢ و٣"
Romanize Arabic script to readable Latin, or turn it into URL-safe slugs for routes, filenames and CMS permalinks. Deterministic — short vowels appear only when the text is vowelled (carries tashkeel).
import { transliterate, slugify } from "arabicfmt"; transliterate("مُحَمَّد") // "muhammad" (vowelled) transliterate("محمد") // "mhmd" (bare → consonant-only) transliterate("الرياض") // "alryad" transliterate("غرفة ٢٠١") // "ghrfh 201" (digits converted) slugify("مدينة جدة") // "mdynh-jdh" slugify("الرياض 2026") // "alryad-2026" slugify("Hello العالم", { separator: "_" }) // "hello_alalm" slugify("Hello World", { lowercase: false }) // "Hello-World"
Note: this is a pragmatic, reversible-ish romanization, not a strict academic transliteration (DIN 31635 / ISO 233). It is built for slugs, search keys and readable IDs.
Real checksums, not regex guesses.isValidIBANruns the ISO 7064mod-97algorithm with SWIFT-registry length checks;isValidSaudiIdruns the Luhn check digit and classifies citizen vs. resident.
import { isValidIBAN, formatIBAN, isValidSaudiId, saudiIdType } from "arabicfmt"; isValidIBAN("SA03 8000 0000 6080 1016 7519") // true isValidIBAN("SA03 8000 0000 6080 1016 7510") // false (bad checksum) formatIBAN("SA0380000000608010167519") // "SA03 8000 0000 6080 1016 7519" isValidSaudiId("1012345672") // true saudiIdType("1012345672") // "citizen" saudiIdType("2100000005") // "resident" (Iqama)
Registry lengths are enforced for SA, AE, KW, BH, QA, JO, LB, EG, IQ, PS, TN, MR, LY (plus common partners). Unknown-country IBANs are validated by checksum and the general 15–34 length bound, never accepted on structure alone.
import { formatCurrency, detectLocale } from "arabicfmt"; import { formatHijri } from "arabicfmt/umalqura"; export function PriceTag({ amount, currency }: { amount: number; currency: string }) { const locale = detectLocale(); return ( <span dir="rtl"> {formatCurrency(amount, { currency, locale })} </span> ); } export function HijriDate({ date }: { date: Date }) { return <time>{formatHijri(date, { numerals: "arab" })}</time>; }
import { formatCurrency } from "arabicfmt"; // composable export function useArabicCurrency(currency: string) { return (amount: number) => formatCurrency(amount, { currency, numerals: "arab" }); }
import { formatCurrency, detectLocale } from "arabicfmt"; import { formatHijri } from "arabicfmt/umalqura"; app.get("/invoice/:id", (req, res) => { const locale = req.headers["accept-language"]?.split(",")[0] ?? "ar-SA"; const total = formatCurrency(order.total, { locale }); const date = formatHijri(order.date, { locale: "ar" }); res.json({ total, date }); });
import { detectLocale } from "arabicfmt"; // Browser: reads navigator.language // Node.js: reads LANG / LANGUAGE / LC_ALL / LC_MESSAGES env vars // Fallback: "ar" const locale = detectLocale(); // "ar-SA", "ar-EG", "en-US", … formatCurrency(1234, { locale });
Pick only what you need for the smallest possible bundle:
import { formatCurrency, spellCurrency } from "arabicfmt/currency"; import { formatNumber, arabicToWords, formatDuration, formatFileSize } from "arabicfmt/number"; import { formatHijri, toHijri } from "arabicfmt/date"; // tabular core (tiny) import { formatHijri, toHijri } from "arabicfmt/umalqura"; // accurate, opt-in import { isolateForeign } from "arabicfmt/bidi"; import { normalizeForSearch, arabicPlural, slugify } from "arabicfmt/text"; import { isValidIBAN, isValidSaudiId } from "arabicfmt/validate";
Measured cost of each entry point (esbuild--bundle --minify, gzipped — v0.1.0):
The complete Arabic formatting stack costs less than a single small image.
Every public function, by module. Full signatures and options are in the sections above and in the bundled TypeScript types.
MCP server — use arabicfmt from AI agents
AI agents (Claude Desktop, Claude Code, Cursor) can call arabicfmt directly through thearabicfmt-mcpModel Context Protocol server — 17 tools (format_currency,spell_currency,format_hijri,arabic_to_words,isolate_foreign,validate_iban, …). Add it to your client'smcpServersconfig:
{ "mcpServers": { "arabicfmt": { "command": "npx", "args": ["-y", "arabicfmt-mcp"] } } }
Runnable scripts for every feature live inexamples/:
cd examples && npm install node currency.mjs # or numbers / words / dates / text / bidi / validate
Live since Unicode 18.0 (September 2026)
The UAE dirham (U+20C3) and Omani rial (U+20C4) signs are nowlive, andsymbolMode: "auto"prefers them — completing the transition that began with the Saudi riyal sign (U+20C1) in Unicode 17.0. Because system-font coverage for brand-new signs still varies,symbolMode: "text"always returns the safe Arabic abbreviation (د.إ,ر.ع.), and the Saudi riyal keeps the text symbol as itsautodefault by design.
arabicfmt.vercel.app— the whole library, interactive and computed live in your browser. Change any input and watch the Arabic update in real time: currency studio, تفقيط, Hijri converter, plurals, RTL fixes and more.
cd demo && npm install && npm run dev
Issues and pull requests are welcome onGitHub.
MIT— free for commercial and personal use.
If arabicfmt saves you time, pleasestar it on GitHub— it helps other Arabic developers find it. Explore myother open-source projects, or open anissuewith ideas, bugs and feature requests.
This is a web browser that enables your coding agent, such as Claude Code, to visit websites on your behalf and assist you in identifying bugs or creating UI test cases.
Extentos is a multi-vendor development platform for adding smart-glasses capabilities to existing iOS and Android apps. The simplest analogy is Stripe for smart glasses
An MCP server tailored for React Native–first development using Gluestack UI
Create and read feature flags, review experiments, generate flag types, search docs, and interact with GrowthBook's feature flagging and experimentation platform.
Gives AI agents public URLs (tunnels) for localhost, live HTTP traffic inspection, snapshot publishing, and access control.
Understand, develop, and debug authorization policies in Oso Cloud.
Up-to-date documentation for your coding agent. Covers 1000s of public repos and sites. Built by ref.tools
Points agents to the canonical Agentry install docs for errors, product analytics, and deploy attribution.
Gives coding agents deterministic, read-only documentation handoffs with edit boundaries, ownership, and required checks before repository changes.
Deterministic JSON checks with signed evidence and x402-paid execution
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.





