UNPKG

levantinetransliterator

Version:
517 lines (396 loc) 14.4 kB
class TreeNode { constructor(value, parent) { this.value = value; this.children = []; this.parent = parent; } addChild(value) { this.children.push(new TreeNode(this.value + value, this)); } addChildren(values) { const t = this; values.map((value) => this.children.push(new TreeNode(this.value + value, t)) ); } addSiblings(values) { this.parent.addChildren(values); } addSibling(value) { this.parent.addChild(value, this); } } const ALEF = "ا"; const BAA2 = "ب"; const PAA2 = "پ"; const VAA2 = "ڤ"; const TAA2 = "ت"; const GAAL = "چ"; const TA2_MARBOUTA = "ة"; const THAA = "ط"; const ALEF_HAMZE = "أ"; const QAF = "ق"; const HAMZE_SEAT = "إ"; const KAAF = "ك"; const SHADDE = "\u0651"; const H7A2 = "ح"; const GHAYN = "غ"; const AAYN = "ع"; const YAA2 = "ي"; const FAT7A = "\u064E"; const KHA2 = "خ"; const SEEN = "س"; const SHEEN = "ش"; const DAAL = "د"; const DHAAD = "ض"; const SAAD = "ص"; const THA = "ط"; const NOON = "ن"; const FAA2 = "ف"; const JIIM = "ج"; const HAA2 = "ه"; const LAAM = "ل"; const MIIM = "م"; const WAAW = "و"; const DAMME = "\u064F"; const RAA2 = "ر"; const ZHAA2 = "ظ"; const ZHAAL = "ذ"; const ZAY = "ز"; const ALEF_MAKSOURA = "ى"; const HAMZE_SATER = "ء"; const KASRA = "\u0650"; const INITIAL = "ـ"; const TANWEEN_FAT7A = "اً"; const ABZ_TO_ARB = [ // S = start, M = 'middle', E = 'end' { rule: "S", l: "aa", a: [ALEF] }, { rule: "M", l: "aa", a: [ALEF] }, { rule: "S", l: "a", a: [ALEF_HAMZE, QAF] }, { rule: "S", l: "A", a: [ALEF_HAMZE] }, { rule: "M", l: "a", a: [FAT7A, ALEF] }, { rule: "S", l: "2", a: [ALEF] }, { rule: "M", l: "2", a: [QAF, ALEF_HAMZE] }, { rule: "E", l: "2", a: [QAF] }, { rule: "M", l: "22", a: [`${QAF}${SHADDE}`] }, { rule: "S", l: "2", a: [ALEF] }, { rule: "M", l: "2", a: [ALEF] }, { rule: "E", l: "an", a: [`${TANWEEN_FAT7A}`, `${FAT7A}${NOON}`] }, { rule: "A", l: "7", a: [H7A2] }, { rule: "A", l: "*", a: [SHADDE] }, { rule: "A", l: "77", a: [`${H7A2}${SHADDE}`] }, { rule: "A", l: "3", a: [AAYN] }, { rule: "E", l: " 3", a: [` ${AAYN}${INITIAL}`] }, { rule: "E", l: " 3a", a: [` ${AAYN}${FAT7A}${INITIAL}`] }, { rule: "E", l: " t", a: [` ${TAA2}${INITIAL}`] }, { rule: "E", l: " ta", a: [` ${TAA2}${FAT7A}${INITIAL}`] }, { rule: "E", l: " b", a: [` ${BAA2}${INITIAL}`] }, { rule: "E", l: " bi", a: [` ${BAA2}${KASRA}${INITIAL}`] }, { rule: "E", l: " l", a: [` ${LAAM}${INITIAL}`] }, { rule: "E", l: " la", a: [` ${LAAM}${FAT7A}${INITIAL}`] }, { rule: "E", l: " 7", a: [` ${H7A2}${INITIAL}`] }, { rule: "E", l: " 7a", a: [` ${H7A2}${FAT7A}${INITIAL}`] }, { rule: "A", l: "33", a: [`${GHAYN}${SHADDE}`] }, { rule: "A", l: " ", a: [" "] }, { rule: "A", l: "kh", a: [KHA2] }, { rule: "A", l: "5", a: [KHA2] }, { rule: "A", l: "55", a: [`${KHA2}${SHADDE}`] }, { rule: "A", l: "aa", a: [ALEF] }, { rule: "A", l: "b", a: [BAA2] }, { rule: "A", l: "bb", a: [`${BAA2}${SHADDE}`] }, { rule: "A", l: "c", a: [SEEN] }, { rule: "A", l: "d", a: [DAAL, DHAAD] }, { rule: "A", l: "D", a: [DHAAD] }, { rule: "A", l: "dd", a: [`${DAAL}${SHADDE}`, `${DHAAD}${SHADDE}`] }, { rule: "E", l: "e", a: [`${KASRA}${TA2_MARBOUTA}`, YAA2] }, { rule: "M", l: "e", a: [KASRA, `${KASRA}${ALEF}`] }, { rule: "A", l: "ee", a: [YAA2, `${ALEF}${KASRA}`] }, // { rule: "A", l: "ee", a: [YAA2] }, { rule: "S", l: "e", a: [HAMZE_SEAT, QAF] }, { rule: "A", l: " e", a: [` ${ALEF}`] }, { rule: "A", l: "f", a: [FAA2] }, { rule: "A", l: "g", a: [JIIM, GAAL] }, { rule: "A", l: "gg", a: [`${JIIM}${SHADDE}`, `${GAAL}${SHADDE}`] }, { rule: "A", l: "gh", a: [GHAYN] }, { rule: "A", l: "h", a: [HAA2] }, { rule: "A", l: "ii", a: [YAA2] }, { rule: "M", l: "i", a: [KASRA, YAA2] }, { rule: "E", l: "i", a: [YAA2] }, { rule: "S", l: "i", a: [HAMZE_SEAT] }, { rule: "A", l: "j", a: [JIIM] }, { rule: "A", l: "k", a: [KAAF, QAF] }, { rule: "A", l: "kk", a: [`${KAAF}${SHADDE}`] }, { rule: "A", l: "l", a: [LAAM] }, { rule: "A", l: "ll", a: [`${LAAM}${SHADDE}`] }, { rule: "A", l: "m", a: [MIIM] }, { rule: "A", l: "M", a: [MIIM] }, { rule: "A", l: "mm", a: [`${MIIM}${SHADDE}`] }, { rule: "A", l: "mmu", a: [`${MIIM}${MIIM}${DAMME}`] }, { rule: "A", l: "n", a: [NOON] }, { rule: "A", l: "nn", a: [`${NOON}${SHADDE}`] }, { rule: "M", l: "o", a: [DAMME, WAAW] }, { rule: "E", l: "o", a: [DAMME, WAAW] }, { rule: "M", l: "o", a: [WAAW] }, { rule: "E", l: "o", a: [WAAW] }, { rule: "S", l: "o", a: ["اُ"] }, { rule: "A", l: "p", a: [PAA2] }, { rule: "A", l: "pp", a: [`${PAA2}${SHADDE}`] }, { rule: "A", l: "q", a: [QAF] }, { rule: "A", l: "r", a: [RAA2] }, { rule: "A", l: "rr", a: [`${RAA2}${SHADDE}`] }, { rule: "A", l: "s", a: [SEEN, SAAD] }, { rule: "A", l: "S", a: [SAAD] }, { rule: "A", l: "ss", a: [`${SEEN}${SHADDE}`, `${SAAD}${SHADDE}`] }, { rule: "A", l: "t", a: [TAA2, THAA] }, { rule: "A", l: "T", a: [THAA] }, { rule: "A", l: "TT", a: [`${THAA}${SHADDE}`] }, { rule: "A", l: "tt", a: [`${TAA2}${SHADDE}`, THAA] }, { rule: "A", l: "v", a: [VAA2] }, { rule: "A", l: "vv", a: [`${VAA2}${SHADDE}`] }, { rule: "A", l: "u", a: [WAAW, DAMME] }, { rule: "A", l: "uu", a: [`${DAMME}${WAAW}`] }, { rule: "A", l: "ou", a: [WAAW] }, { rule: "A", l: "oo", a: [WAAW] }, { rule: "A", l: "w", a: [WAAW] }, { rule: "E", l: "u", a: [WAAW] }, { rule: "A", l: "ww", a: [`${WAAW}${SHADDE}`] }, { rule: "A", l: "x", a: [`${KAAF}${SEEN}`] }, { rule: "A", l: "y", a: [YAA2] }, { rule: "A", l: "yy", a: [`${YAA2}${SHADDE}`] }, { rule: "A", l: "z", a: [ZAY, ZHAA2, ZHAAL] }, { rule: "A", l: "Z", a: [ZHAA2] }, { rule: "A", l: "sh", a: [SHEEN] }, { rule: "A", l: `${SHEEN}${SHEEN}`, a: [`${SHEEN}${SHADDE}`] }, { rule: "A", l: "sh", a: [`${SEEN}${HAA2}`] }, { rule: "A", l: "ch", a: [SHEEN] }, { rule: "E", l: "aa", a: [ALEF_MAKSOURA] }, // ا // { rule: "A", l: "aa ", a: [ALEF_MAKSOURA, "ا "] }, // ا { rule: "E", l: "a", a: [TA2_MARBOUTA, ALEF_MAKSOURA, ALEF] }, // ا // { rule: "A", l: "a ", a: [ALEF, TA2_MARBOUTA, "ى ", ""] }, ]; const TO_PRON_RULES = [ // S = staart, M = 'middle', E = 'end' { rule: "A", l: "2", a: ["ʔ"] }, { rule: "A", l: "b", a: ["b"] }, { rule: "A", l: "t", a: ["t", "ṭ"] }, { rule: "A", l: "th", a: ["ṯ", "th"] }, { rule: "A", l: "TH", a: ["ṯ"] }, { rule: "A", l: "ث", a: ["ṯ"] }, { rule: "A", l: "j", a: ["ǧ"] }, { rule: "A", l: "g", a: ["ǧ", "g"] }, { rule: "A", l: JIIM, a: ["ǧ"] }, { rule: "A", l: "7", a: ["ḥ"] }, { rule: "A", l: H7A2, a: ["ḥ"] }, { rule: "A", l: "kh", a: ["ẖ", "kh"] }, { rule: "A", l: "KH", a: ["ẖ"] }, { rule: "A", l: "5", a: ["ẖ"] }, { rule: "A", l: KHA2, a: ["ẖ"] }, { rule: "A", l: "d", a: ["d"] }, { rule: "A", l: "z", a: ["ḏ"] }, { rule: "A", l: ZHAAL, a: ["ḏ"] }, { rule: "A", l: "r", a: ["r"] }, { rule: "A", l: "z", a: ["z"] }, { rule: "A", l: "s", a: ["s"] }, { rule: "A", l: "c", a: ["s"] }, { rule: "A", l: "s", a: ["ṣ"] }, { rule: "A", l: "S", a: ["ṣ"] }, { rule: "A", l: SAAD, a: ["ṣ"] }, { rule: "A", l: "sh", a: ["š", "sh"] }, { rule: "A", l: "SH", a: ["š"] }, { rule: "A", l: SHEEN, a: ["š"] }, { rule: "A", l: "d", a: ["ḍ"] }, { rule: "A", l: "D", a: ["ḏ"] }, // { rule: "A", l: "t", a: ["ṭ"] }, { rule: "A", l: "T", a: ["ṭ"] }, { rule: "A", l: THAA, a: ["ṭ"] }, { rule: "A", l: "z", a: ["ẓ"] }, { rule: "A", l: "Z", a: ["ẓ"] }, { rule: "A", l: "3", a: ["ʕ"] }, { rule: "A", l: "ʿ", a: ["ʕ"] }, { rule: "A", l: "gh", a: ["ġ"] }, { rule: "A", l: "f", a: ["f"] }, { rule: "A", l: "q", a: ["q"] }, { rule: "A", l: "k", a: ["k"] }, { rule: "A", l: "l", a: ["l"] }, { rule: "A", l: "m", a: ["m"] }, { rule: "A", l: "n", a: ["n"] }, { rule: "A", l: "h", a: ["h"] }, { rule: "A", l: "w", a: ["w"] }, { rule: "A", l: "y", a: ["y"] }, { rule: "A", l: "i", a: ["i"] }, { rule: "A", l: "ii", a: ["ī"] }, { rule: "A", l: "I", a: ["ī"] }, { rule: "A", l: "aa", a: ["ā"] }, { rule: "A", l: "ee", a: ["ē"] }, { rule: "A", l: "é", a: ["ē"] }, { rule: "A", l: "oo", a: ["ō"] }, { rule: "A", l: "e", a: ["ə", "e"] }, { rule: "A", l: "uu", a: ["ū"] }, { rule: "A", l: "y", a: ["y"] }, ]; const PRON_TO_ARB_RULES = [ // S = staart, M = 'middle', E = 'end' { rule: "A", l: "b", a: [BAA2] }, { rule: "A", l: "p", a: [PAA2] }, { rule: "A", l: "bb", a: [`${BAA2}${SHADDE}`] }, { rule: "A", l: "t", a: [TAA2] }, { rule: "A", l: "tt", a: ["تّ"] }, { rule: "A", l: "ṯ", a: ["ث"] }, { rule: "A", l: "ṯṯ", a: ["ثّ"] }, { rule: "A", l: "g", a: [GAAL] }, { rule: "A", l: "gg", a: [`${GAAL}${SHADDE}`] }, { rule: "A", l: "v", a: [VAA2] }, { rule: "A", l: "ǧ", a: [JIIM] }, { rule: "A", l: "ǧǧ", a: ["جّ"] }, { rule: "A", l: "ḥ", a: [H7A2] }, { rule: "A", l: "ẖ", a: [KHA2] }, { rule: "A", l: "ẖẖ", a: ["خّ"] }, { rule: "A", l: "d", a: [DAAL] }, { rule: "A", l: "dd", a: ["دّ"] }, { rule: "A", l: "ḏ", a: [ZHAAL] }, { rule: "A", l: "ḏḏ", a: ["ذّ"] }, { rule: "A", l: "r", a: [RAA2] }, { rule: "A", l: "rr", a: ["رّ"] }, { rule: "A", l: "z", a: [ZAY] }, { rule: "A", l: "zz", a: ["زّ"] }, { rule: "A", l: "s", a: [SEEN] }, { rule: "A", l: "ss", a: ["سّ"] }, { rule: "A", l: "š", a: [SHEEN] }, { rule: "A", l: "šš", a: ["شّ"] }, { rule: "A", l: "ṣ", a: [SAAD] }, { rule: "A", l: "ṣṣ", a: ["صّ"] }, { rule: "A", l: "ḍ", a: [DHAAD] }, { rule: "A", l: "ḍḍ", a: ["ضّ"] }, { rule: "A", l: "ṭ", a: [THAA] }, { rule: "A", l: "ṭṭ", a: ["طّ"] }, { rule: "A", l: "ẓ", a: ["ظ"] }, { rule: "A", l: "ẓẓ", a: ["ظّ"] }, { rule: "A", l: "ʕ", a: [AAYN] }, { rule: "A", l: "ʕʕ", a: ["عّ"] }, // { rule: "A", l: "ġ", a: [AAYN] }, { rule: "A", l: "ġ", a: [GHAYN] }, { rule: "A", l: "ġġ", a: ["غّ"] }, { rule: "A", l: "f", a: [FAA2] }, { rule: "A", l: "ff", a: ["فّ"] }, { rule: "A", l: "q", a: [QAF] }, { rule: "A", l: "qq", a: ["قّ"] }, { rule: "A", l: "k", a: [KAAF] }, { rule: "A", l: "kk", a: [`${KAAF}${SHADDE}`] }, { rule: "A", l: "l", a: [LAAM] }, { rule: "A", l: "ll", a: [`${LAAM}${SHADDE}`] }, { rule: "A", l: "m", a: [MIIM] }, { rule: "A", l: "mm", a: [`${MIIM}${SHADDE}`] }, { rule: "A", l: "n", a: [NOON] }, { rule: "A", l: "nn", a: [`${NOON}${SHADDE}`] }, { rule: "A", l: "h", a: [HAA2] }, { rule: "A", l: "hh", a: [`${HAA2}${SHADDE}`] }, { rule: "A", l: "w", a: [WAAW] }, { rule: "A", l: "ww", a: [`${WAAW}${SHADDE}`] }, { rule: "A", l: "y", a: [YAA2] }, { rule: "A", l: "yy", a: [`${YAA2}${SHADDE}`] }, { rule: "S", l: "a", a: [`${ALEF}${FAT7A}`] }, { rule: "M", l: "a", a: [FAT7A] }, { rule: "E", l: "a", a: [FAT7A] }, { rule: "S", l: "e", a: [`${ALEF}${KASRA}`] }, { rule: "M", l: "e", a: [KASRA] }, { rule: "E", l: "e", a: [KASRA] }, { rule: "A", l: "i", a: [KASRA] }, { rule: "S", l: "ə", a: [`${ALEF}${KASRA}`] }, { rule: "M", l: "ə", a: [KASRA] }, { rule: "E", l: "ə", a: [KASRA] }, { rule: "A", l: "o", a: [DAMME] }, { rule: "A", l: "u", a: [DAMME] }, { rule: "A", l: "ē", a: [`${KASRA}${ALEF}`] }, { rule: "A", l: "ā", a: [ALEF] }, { rule: "A", l: "ō", a: [WAAW] }, { rule: "A", l: "ū", a: [WAAW] }, { rule: "A", l: "ī", a: [YAA2] }, { rule: "A", l: "ʔ", a: [HAMZE_SATER] }, ]; function lToA(prev, prevPrev, current, cType, rules) { // const rules = const filt = rules.filter((r) => r.rule == cType || r.rule == "A"); let children = filt.filter((r) => r.l == current).flatMap((r) => r.a); if (children.length == 0) { children = [current]; } const siblings = filt .filter((r) => r.l == `${prev}${current}`) .flatMap((r) => r.a); const stepSiblings = filt .filter((r) => r.l == `${prevPrev}${prev}${current}`) .flatMap((r) => r.a); return { children, siblings: siblings, stepSiblings: stepSiblings }; } function toTree(wordSrc, rules, limit) { const word = wordSrc.replace(/(.)\1{2,}/g, "$1$1"); const root = new TreeNode("", null); let leaves = [root]; const startIndex = 0; const endIndex = word.length - 1; let prev = null; let prevPrev = null; [...word].forEach((current, i) => { let type; if (i == 0) { type = "S"; } else if (i == endIndex) { type = "E"; } else { type = "M"; } let sugg = lToA(prev, prevPrev, current, type, rules); if (sugg.stepSiblings.length > 0) { const parents = leaves.map((l) => l.parent); parents.forEach((p) => (p.children = [])); parents.forEach((l) => l.addChildren(sugg.stepSiblings)); leaves = parents.flatMap((l) => l.children); } else if (sugg.siblings.length > 0) { const parents = leaves.map((l) => l.parent); parents.forEach((p) => (p.children = [])); parents.forEach((l) => l.addChildren(sugg.siblings)); leaves = parents.flatMap((l) => l.children); } else { leaves.forEach((l) => l.addChildren(sugg.children)); const temp = leaves.flatMap((l) => l.children); leaves = temp; } prevPrev = prev; prev = current; leaves = uniqBy(leaves, function (e) { return e.value; }); if (leaves.length > limit) { leaves = leaves.filter((element, index) => { return index % 2 === 0; }); } }); let ss = leaves.map((l) => l.value).filter((l) => l.length > 0); // .sort((a, b) => a.length - b.length); return ss; } const uniqBy = (arr, predicate) => { const cb = typeof predicate === "function" ? predicate : (o) => o[predicate]; return [ ...arr .reduce((map, item) => { const key = item === null || item === undefined ? item : cb(item); map.has(key) || map.set(key, item); return map; }, new Map()) .values(), ]; }; exports.transliterate = function (word, limit = 100) { return toTree(word, ABZ_TO_ARB, limit); }; exports.pronunciate = function (word, limit = 100) { return toTree(word, TO_PRON_RULES, limit); }; exports.toArb = function (word, limit = 2) { return toTree(word, PRON_TO_ARB_RULES, limit); }; exports.custom = function (word, rules, limit = 100) { return toTree(word, rules, limit); };