Skip to content

Repository files navigation

Yamli — Modern Arabic Transliteration Engine

version ts license node

Type Arabic with Latin letters — intelligently.
Rebuilt from the original Yamli 5523 (2010) engine in clean, modern TypeScript.
Dual package: headless Node.js library + drop-in browser/CDN script.

العربية · API Docs · Architecture · Business Logic


✨ What it does

You type salam 3alaykom → Yamli offers سلام عليكم in a popup. Press Space to accept the best guess, / to cycle, click to pick.

  • Smart word detection — finds the word under the caret, ignoring punctuation and markup.
  • Arabic-aware punctuation,، , ;؛ , ?؟ automatically.
  • Hindi digits123١٢٣ with locale toggle.
  • Excluded tokenshttp:, www., AND/OR, emails never transliterated.
  • Dashed compoundsal-kitab handled as connected Arabic words.
  • Caching & dedup — one network request per unique word, LRU + arabic→roman index.
  • RTL/LTR aware — auto-switches direction, popup clamps to viewport.

📦 Install

bun add @plground/yamli
# or
npm i @plground/yamli
# or
pnpm add @plground/yamli
# also available as `@1t_na/yamli-js` — same build
# GitHub: github.com/abdou-da0wew/yamli

CDN — drop-in (no build)

<!-- jsDelivr (auto-updates on npm publish) -->
<script src="https://cdn.jsdelivr.net/npm/@plground/yamli/dist/web.min.js"></script>
<script>
  Yamli.init({ apiBase: "https://api.yamli.com" });
  Yamli.yamlify("myTextarea");
  Yamli.yamlifyClass("yamli-input");
  Yamli.yamlifyType("any");
</script>

<!-- unpkg alternative -->
<!-- <script src="https://unpkg.com/@plground/yamli/dist/web.min.js"></script> -->

🚀 Quick Start

Browser (ESM)

import { Yamli } from "@plground/yamli/web";

const mgr = Yamli.init({
  apiBase: "https://api.yamli.com",
  uiLanguage: "en", // en | fr | ar
  startMode: "onOrUserDefault",
});

mgr.yamlify("editor");               // by id
mgr.yamlifyClass("arabic-field");    // by class
mgr.yamlifyType("any");              // all text inputs

Node.js (headless)

import { YamliNode } from "@plground/yamli/node";

const yamli = new YamliNode({ apiBase: "https://api.yamli.com" });

// one word → ranked Arabic candidates
const candidates = await yamli.transliterate("salam");
console.log(candidates);
// [{ trans: "سلام", type: 1 }, { trans: "سالم", type: 2 }, ...]

yamli.classify("hello");      // "pure_roman"
yamli.classify("123");        // "pure_number"
yamli.classify("مرحبا");     // "pure_arabic"
yamli.classify("http://x");  // "excluded"

Direct API

import { fetchTransliterations } from "@plground/yamli";

const { roman, items } = await fetchTransliterations("kitab", {
  apiBase: "https://api.yamli.com",
  tool: "api",
});

🎛️ Options

Option Default Description
apiBase https://api.yamli.com Transliteration endpoint
uiLanguage "en" en / fr / ar
startMode "onOrUserDefault" on / off / onOrUserDefault / offOrUserDefault
toggleAffectsAll true Toggle affects every instance
maxResults undefined Cap popup items
showHint false Show onboarding hint
zIndexBase 1000 Stacking base
settingsPlacement "bottomRight" 12 placement presets
popupDirection "down" up / down
disableInMarkup true Skip words inside <tag / [
generateOnChangeEvent false Fire change on replace

Full table → docs/API.md


⌨️ Keyboard

Key Action
Space Accept top candidate
Cycle candidates
Enter Accept highlighted
Esc Dismiss popup
Shift+Space Force commit

🏗️ Architecture

yamli/
├── src/constants/   — word types, regex, punctuation & digit maps, i18n
├── src/utils/       — classifier, text expansion, DOM & positioning
├── src/api/         — fetch + JSONP client, response parser
├── src/core/        — cache, engine, dashed-words, instance, manager
├── src/ui/          — menu, settings, hint, draggable, styles
├── src/index.ts     — ESM re-exports
├── src/node.ts      — Node headless entry
└── src/web.ts       — CDN / window.Yamli entry

Deep dive → docs/ARCHITECTURE.md Business rules → docs/BUSINESS_LOGIC.md


🔬 Business Logic (summary)

  1. Caret → word — expand left/right to nearest space, then to nearest punctuation (HasPunctuationRegexp). Validate word isn't inside markup tail (<[^<>]*$).
  2. Classifyemptyexcludedpure_numberpure_arabicpure_romanroman_arabicmixed.
  3. Gate — only pure_roman / roman_arabic hit the API. pure_number maps digits locally. excluded/mixed ignored.
  4. FetchGET /transliterate.ashx?word=...{ w, r: "سلام/0|سالم/1" }. Deduped + cached (roman→set, arabic→roman, dashed→parts).
  5. Replace — swap word with picked at [start,end), move caret, fire change/yamliStateChange, register arabic→roman.

🌐 i18n

Built-in en / fr / ar strings. RTL layout flips automatically when dir="rtl". Add a locale in src/constants/i18n.ts:

import { I18N } from "@plground/yamli";
I18N.de = { dir: "ltr", show_more: "mehr …", /* … */ };

🧪 Development

bun install
bun run typecheck
bun run build        # → dist/{index,node,web}.{js,cjs,d.ts} + dist/yamli.min.js
bun test

📄 License

MIT — original engine © 2010 Language Analytics LLC, modern port © 2026 contributors.


Made with care for everyone who types Arabic with Latin letters.

About

Modern Arabic transliteration engine — Yamli 5523 rebuilt as dual Node.js + browser/CDN library (TypeScript). Type Arabic with Latin letters — intelligently.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages