UNPKG

arabicfmt

Version:

Arabic-first formatting for numbers, currency, dates and bidirectional text across all 22 Arab League countries — with correct handling of the 2025–2026 Unicode currency-symbol transition (Saudi Riyal U+20C1, UAE Dirham U+20C3, Omani Rial U+20C4).

284 lines (276 loc) 6.98 kB
'use strict'; var chunkQ4F4Q7IO_cjs = require('./chunk-Q4F4Q7IO.cjs'); var chunk3NAF2S6Y_cjs = require('./chunk-3NAF2S6Y.cjs'); // src/text/normalize.ts var cc = String.fromCharCode; var ALEF = cc(1575); var YAA = cc(1610); var HAA = cc(1607); var WAW = cc(1608); var TASHKEEL = new RegExp( `[${cc(1552)}-${cc(1562)}${cc(1611)}-${cc(1631)}${cc(1648)}${cc(1750)}-${cc(1756)}${cc(1759)}-${cc(1768)}${cc(1770)}-${cc(1773)}]`, "g" ); var TATWEEL = new RegExp(cc(1600), "g"); var ALEF_VARIANTS = new RegExp( `[${cc(1570)}${cc(1571)}${cc(1573)}${cc(1649)}]`, "g" ); var TAA_MARBUTA = new RegExp(cc(1577), "g"); var ALEF_MAKSURA = new RegExp(cc(1609), "g"); var HAMZA_ON_WAW = new RegExp(cc(1572), "g"); var HAMZA_ON_YAA = new RegExp(cc(1574), "g"); var STANDALONE_HAMZA = new RegExp(cc(1569), "g"); function stripTashkeel(text) { return text.replace(TASHKEEL, ""); } function removeTatweel(text) { return text.replace(TATWEEL, ""); } function normalizeAlef(text) { return text.replace(ALEF_VARIANTS, ALEF); } function normalizeAlefMaksura(text) { return text.replace(ALEF_MAKSURA, YAA); } function normalizeTaaMarbuta(text) { return text.replace(TAA_MARBUTA, HAA); } function normalizeArabic(text, options = {}) { let out = text; if (options.tatweel ?? true) out = removeTatweel(out); if (options.tashkeel ?? true) out = stripTashkeel(out); if (options.alef ?? true) out = normalizeAlef(out); if (options.alefMaksura ?? true) out = normalizeAlefMaksura(out); if (options.taaMarbuta ?? false) out = normalizeTaaMarbuta(out); if (options.hamza ?? false) { out = out.replace(HAMZA_ON_WAW, WAW).replace(HAMZA_ON_YAA, YAA).replace(STANDALONE_HAMZA, ""); } if (options.digits ?? false) out = chunk3NAF2S6Y_cjs.toLatinDigits(out); return out; } function normalizeForSearch(text) { return normalizeArabic(text, { taaMarbuta: true, hamza: true, digits: true }).toLowerCase().replace(/\s+/g, " ").trim(); } // src/text/plural.ts function arabicPluralForm(n) { const abs = Math.abs(Math.trunc(n)); if (abs === 0) return "zero"; if (abs === 1) return "one"; if (abs === 2) return "two"; const mod100 = abs % 100; if (mod100 >= 3 && mod100 <= 10) return "few"; if (mod100 >= 11 && mod100 <= 99) return "many"; return "other"; } function arabicPlural(n, forms) { const form = arabicPluralForm(n); switch (form) { case "zero": return forms.zero ?? forms.other; case "one": return forms.one; case "two": return forms.two ?? forms.many; case "few": return forms.few; case "many": return forms.many; case "other": return forms.other; } } // src/text/collation.ts function compareArabic(a, b) { return arabicCollator.compare(a, b); } var arabicCollator = new Intl.Collator("ar", { sensitivity: "base", ignorePunctuation: true }); function createArabicCollator(options) { return new Intl.Collator("ar", { sensitivity: "base", ignorePunctuation: true, ...options }); } function sortArabic(strings) { return [...strings].sort(compareArabic); } // src/text/list.ts function fallback(items, type) { if (items.length === 0) return ""; if (items.length === 1) return items[0] ?? ""; if (type === "disjunction") return items.join(" \u0623\u0648 "); return items.join(" \u0648"); } function formatList(items, options = {}) { const arr = Array.from(items, (x) => String(x)); const locale = options.locale ?? chunkQ4F4Q7IO_cjs.DEFAULT_LOCALE; const type = options.type ?? "conjunction"; const style = options.style ?? "long"; let out; const LF = Intl.ListFormat; if (LF) { try { out = new LF(locale, { type, style }).format(arr); } catch { out = fallback(arr, type); } } else { out = fallback(arr, type); } return options.numerals === "arab" ? chunk3NAF2S6Y_cjs.toArabicDigits(out) : out; } // src/text/transliterate.ts var cc2 = String.fromCharCode; var LETTERS = { [cc2(1575)]: "a", // ا [cc2(1571)]: "a", // أ [cc2(1573)]: "i", // إ [cc2(1570)]: "aa", // آ [cc2(1649)]: "a", // ٱ [cc2(1576)]: "b", // ب [cc2(1578)]: "t", // ت [cc2(1579)]: "th", // ث [cc2(1580)]: "j", // ج [cc2(1581)]: "h", // ح [cc2(1582)]: "kh", // خ [cc2(1583)]: "d", // د [cc2(1584)]: "dh", // ذ [cc2(1585)]: "r", // ر [cc2(1586)]: "z", // ز [cc2(1587)]: "s", // س [cc2(1588)]: "sh", // ش [cc2(1589)]: "s", // ص [cc2(1590)]: "d", // ض [cc2(1591)]: "t", // ط [cc2(1592)]: "z", // ظ [cc2(1593)]: "'", // ع [cc2(1594)]: "gh", // غ [cc2(1601)]: "f", // ف [cc2(1602)]: "q", // ق [cc2(1603)]: "k", // ك [cc2(1604)]: "l", // ل [cc2(1605)]: "m", // م [cc2(1606)]: "n", // ن [cc2(1607)]: "h", // ه [cc2(1608)]: "w", // و [cc2(1610)]: "y", // ي [cc2(1609)]: "a", // ى alef maksura [cc2(1577)]: "h", // ة taa marbuta [cc2(1569)]: "'", // ء hamza [cc2(1572)]: "w", // ؤ [cc2(1574)]: "y" // ئ }; var HARAKAT = { [cc2(1614)]: "a", // fatha [cc2(1615)]: "u", // damma [cc2(1616)]: "i", // kasra [cc2(1611)]: "an", // fathatan [cc2(1612)]: "un", // dammatan [cc2(1613)]: "in", // kasratan [cc2(1618)]: "" // sukun }; var SHADDA = cc2(1617); var TATWEEL2 = cc2(1600); function transliterate(text) { const normalized = chunk3NAF2S6Y_cjs.toLatinDigits(text).replace( /([ًٌٍَُِْ])ّ/g, `\u0651$1` ); let out = ""; let lastLetter = ""; for (const ch of normalized) { if (ch === TATWEEL2) continue; if (ch === SHADDA) { out += lastLetter; continue; } const letter = LETTERS[ch]; if (letter !== void 0) { out += letter; lastLetter = letter; continue; } const haraka = HARAKAT[ch]; if (haraka !== void 0) { out += haraka; continue; } out += ch; } return out; } function slugify(text, options = {}) { const separator = options.separator ?? "-"; const lowercase = options.lowercase ?? true; let s = transliterate(text); if (lowercase) s = s.toLowerCase(); const sep = separator.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); return s.replace(/['']/g, "").replace(/[^a-zA-Z0-9]+/g, separator).replace(new RegExp(`${sep}{2,}`, "g"), separator).replace(new RegExp(`^${sep}|${sep}$`, "g"), ""); } exports.arabicPlural = arabicPlural; exports.arabicPluralForm = arabicPluralForm; exports.compareArabic = compareArabic; exports.createArabicCollator = createArabicCollator; exports.formatList = formatList; exports.normalizeAlef = normalizeAlef; exports.normalizeAlefMaksura = normalizeAlefMaksura; exports.normalizeArabic = normalizeArabic; exports.normalizeForSearch = normalizeForSearch; exports.normalizeTaaMarbuta = normalizeTaaMarbuta; exports.removeTatweel = removeTatweel; exports.slugify = slugify; exports.sortArabic = sortArabic; exports.stripTashkeel = stripTashkeel; exports.transliterate = transliterate;