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
JavaScript
;
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;