README.md

June 2, 2026 · View on GitHub

PersianTools logo

🇮🇷 Persian Tools — The Complete TypeScript Toolkit for Persian (Farsi) Apps

A comprehensive, library-agnostic TypeScript toolkit for Persian (Farsi) text, numbers, validation, and locale utilities — runs in Node.js, Bun, and the browser.

CI/CD codecov npm version npm downloads bundle size GitHub license PRs Welcome CodeFactor GitHub contributors


✨ Features

Persian Tools provides 27+ utilities for Persian language processing:

🔢 Numbers & Text

🏛️ Validation & Verification

  • National ID: Validate & generate Iranian national codes (کد ملی)
  • Legal ID: Validate Iranian legal entity IDs (شناسه حقوقی)
  • Phone Numbers: Validate & extract operator info
  • Bank Cards: Validate & identify bank names
  • Extract Card Numbers: Advanced card extraction with fuzzy matching & performance optimization
  • IBAN/Sheba: Validate Iranian bank account numbers

🌍 Geographic & Location

💰 Financial & Utilities

📝 Text Processing


🚀 Quick Start

📦 Installation

# npm
npm install @persian-tools/persian-tools

# yarn  
yarn add @persian-tools/persian-tools

# pnpm
pnpm add @persian-tools/persian-tools

# bun (recommended)
bun add @persian-tools/persian-tools

💻 Usage

ES Modules (Recommended)

import { numberToWords, digitsEnToFa, verifyIranianNationalId } from '@persian-tools/persian-tools';

numberToWords(1234); // "یک هزار و دویست و سی و چهار"
digitsEnToFa("123"); // "۱۲۳"
verifyIranianNationalId("0499370899"); // true

CommonJS

const { numberToWords } = require('@persian-tools/persian-tools');

Browser CDN

<script src="https://cdn.jsdelivr.net/npm/@persian-tools/persian-tools/build/index.js"></script>
<script>
  console.log(PersianTools.numberToWords(1234));
</script>

🧠 AI Agent Skills

Persian Tools ships first-class Agent Skills — focused, retrievable instruction files that let Claude Code, Cursor, Copilot, and other AI coding assistants understand the library's modules, conventions, and Persian-language nuances without you having to paste context every time.

Install the skills into your editor

# Bun
bunx skills add @persian-tools/persian-tools

# npm
npx skills add @persian-tools/persian-tools

# pnpm
pnpm dlx skills add @persian-tools/persian-tools

Each command pulls the skills/ directory into your project's local skills folder so your AI agent retrieves them automatically when you ask about a Persian Tools utility.


📖 API Reference

🔢 Number Conversion

numberToWords - Convert numbers to Persian words
import { numberToWords } from '@persian-tools/persian-tools';

// Basic usage
numberToWords(1234); // "یک هزار و دویست و سی و چهار"
numberToWords("12,345"); // "دوازده هزار و سیصد و چهل و پنج"

// Ordinal numbers
numberToWords(3, { ordinal: true }); // "سوم"
numberToWords(21, { ordinal: true }); // "بیست و یکم"

// Supports up to MAX_SAFE_INTEGER ($2^{53}$ - 1)
numberToWords(9007199254740991); // Works perfectly!
wordsToNumber - Convert Persian words to numbers
import { wordsToNumber } from '@persian-tools/persian-tools';

// Basic conversion
wordsToNumber("سه هزار دویست و دوازده"); // 3212
wordsToNumber("منفی یک میلیون"); // -1000000

// Advanced options
wordsToNumber("دوازده هزار", { 
  digits: "fa",      // Return Persian digits: "۱۲۰۰۰"
  addCommas: true    // Add commas: "12,000"
});

// Fuzzy matching (fixes typos)
wordsToNumber("یگصد و بنجاه هزار", { fuzzy: true }); // 150000

🏛️ Validation

National ID Validation - Validate Iranian national codes
import { verifyIranianNationalId, getPlaceByIranNationalId, createIranianNationalId } from '@persian-tools/persian-tools';

// Validation
verifyIranianNationalId("0499370899"); // true
verifyIranianNationalId("1234567890"); // false

// Location lookup
getPlaceByIranNationalId("0084575948"); 
// { city: "تهران مرکزی", province: "تهران" }

// Generation
createIranianNationalId(); // "0499370899"
createIranianNationalId({ preventRepeatedDigits: true }); // "1234567890"

National ID Generation - Generate valid Iranian national codes
import { 
  createIranianNationalId, 
  createIranianNationalIdDetailed,
  validateNationalIdChecksum 
} from '@persian-tools/persian-tools';

// Basic generation
createIranianNationalId(); // "0499370899"

// Generate without repeated digits
createIranianNationalId({ preventRepeatedDigits: true }); // "1234567890"

// Detailed generation with metadata
const result = createIranianNationalIdDetailed({
  preventRepeatedDigits: true,
  maxRetries: 50
});

console.log(result.nationalId);         // "1234567890"  
console.log(result.checkDigit);         // 0
console.log(result.attempts);           // 1
console.log(result.hasRepeatedDigits);  // false
console.log(result.digits);             // [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]

// Validate generated IDs
validateNationalIdChecksum(result.nationalId); // true

// Custom random generator (for testing)
createIranianNationalId({
  randomGenerator: () => 0.5 // Always returns 0.5
});

Phone Number Validation - Iranian mobile numbers
import { isPhoneNumberValid, phoneNumberDetail } from '@persian-tools/persian-tools';

// Validation
isPhoneNumberValid("09123456789"); // true
isPhoneNumberValid("+989123456789"); // true

// Operator detection
phoneNumberDetail("09123456789");
// {
//   province: ["البرز", "تهران", ...],
//   operator: "همراه اول",
//   type: ["permanent"]
// }

💰 Banking & Finance

Bank Card Validation - Validate and identify Iranian bank cards
import { verifyCardNumber, getBankNameFromCardNumber } from '@persian-tools/persian-tools';

// Card validation
verifyCardNumber("6037701689095443"); // true

// Bank identification  
getBankNameFromCardNumber("6219861034529007"); // "بانک سامان"

Extract Card Numbers - Advanced card extraction with performance optimization
import { extractCardNumber, extractCardNumberWithMetrics } from '@persian-tools/persian-tools';

// Basic extraction with validation
const text = "Payment cards: 6037701689095443 and 6219-8610-3452-9007";
const cards = extractCardNumber(text, {
  checkValidation: true,
  detectBankNumber: true
});

console.log(cards);
// [
//   {
//     index: 1,
//     base: "6037701689095443",
//     pure: "6037701689095443",
//     startIndex: 15,
//     endIndex: 31,
//     isValid: true,
//     bankName: "بانک کشاورزی"
//   },
//   {
//     index: 2,
//     base: "6219-8610-3452-9007", 
//     pure: "6219861034529007",
//     startIndex: 36,
//     endIndex: 55,
//     isValid: true,
//     bankName: "بانک سامان"
//   }
// ]

// TypeScript function overloads for type safety
const validatedCards = extractCardNumber(text, {
  checkValidation: true,
  detectBankNumber: false
}); // Returns ExtractCardNumberWithValidation[]

// Multi-format support (Persian, Arabic, separators)
const multiFormat = "Cards: ۶۰۳۷۷۰۱۶۸۹۰۹۵۴۴۳ and 6037_7016_8909_5443";
const results = extractCardNumber(multiFormat);
// Automatically normalizes all formats to: "6037701689095443"

// Fuzzy matching for masked cards
const maskedText = "My card: 6037-****-8909-5443";
const fuzzyResults = extractCardNumber(maskedText, {
  enableFuzzyMatching: true,
  checkValidation: false
});

// Large document optimization (1MB+ texts)
const hugeDocument = "Large document content...".repeat(10000);
const optimizedResults = extractCardNumber(hugeDocument, {
  optimizeForLargeText: true,
  maxResults: 10
});

// Performance monitoring with metrics
const { cardNumbers, metrics } = extractCardNumberWithMetrics(text, {
  includeContext: true,
  contextLength: 20
});

console.log(`Processed ${metrics.textLength} chars in ${metrics.processingTime}ms`);
console.log(`Found ${metrics.validCardNumbers} valid cards`);
console.log(cardNumbers[0].context?.before); // "Payment cards: "

IBAN/Sheba Validation - Iranian bank account validation
import { isShebaValid, getShebaInfo } from '@persian-tools/persian-tools';

// IBAN validation
isShebaValid("IR820540102680020817909002"); // true

// Bank info extraction
getShebaInfo("IR820540102680020817909002");
// {
//   nickname: "parsian",
//   name: "Parsian Bank", 
//   persianName: "بانک پارسیان",
//   accountNumber: "020817909002"
// }

📝 Text Processing

Persian Text Validation - Validate and clean Persian text
import { isPersian, hasPersian, toPersianChars } from '@persian-tools/persian-tools';

// Persian detection
isPersian("سلام دنیا"); // true
isPersian("Hello World"); // false
hasPersian("This has فارسی text"); // true

// Character cleanup
toPersianChars("علي"); // "علی" (fixes Arabic chars)

Digit Conversion - Convert between number systems
import { digitsEnToFa, digitsFaToEn, digitsArToFa } from '@persian-tools/persian-tools';

// English to Persian
digitsEnToFa("123456"); // "۱۲۳۴۵۶"

// Persian to English  
digitsFaToEn("۱۲۳۴۵۶"); // "123456"

// Arabic to Persian
digitsArToFa("٧٨٩"); // "۷۸۹"

🌍 Geographic & Utilities

Vehicle Plates - Parse Iranian license plates
import { getNumberPlateInfo } from '@persian-tools/persian-tools';

// Car plates
getNumberPlateInfo("12D45147").info;
// {
//   template: "12 D 451 ایران 47",
//   province: "مرکزی", 
//   type: "Car",
//   category: "دیپلمات"
// }

// Motorcycle plates  
getNumberPlateInfo(12345678).info;
// {
//   template: "123-45678",
//   province: "مرکز تهران",
//   type: "Motorcycle"
// }

Time Utilities - Persian time formatting
import { timeAgo, remainingTime } from '@persian-tools/persian-tools';

// Time ago (Jalali calendar)
timeAgo("1400/03/17 17:55:00"); // "5 دقیقه قبل"

// Remaining time
remainingTime("2025-12-31T23:59:59Z").toString(); 
// "۱ سال و ۲ ماه و ۱۵ روز"

Slugify - Generate URL-safe slugs from Persian text
import { slugify, createSlug, slugifySimple } from '@persian-tools/persian-tools';

// Basic usage
slugify("سلام دنیا"); // "سلام-دنیا"
slugify("چگونه برنامه‌نویسی یاد بگیریم؟"); // "چگونه-برنامه-نویسی-یاد-بگیریم"

// Custom options
slugify("سلام دنیا", {
  separator: "_",     // Use underscore instead of dash
  maxLength: 20,      // Limit length
  lowercase: false    // Don't convert to lowercase
}); // "سلام_دنیا"

// Preserve numbers
slugify("سال ۱۴۰۰", { preserveNumbers: true }); // "سال-۱۴۰۰"

// Helper functions
createSlug("مقاله جدید"); // "مقاله-جدید"
slugifySimple("تست ساده"); // "تست-ساده"

Text Analysis - Comprehensive Persian text analysis
import { analyzeText, getTextSummary, getTextComplexity, cleanText } from '@persian-tools/persian-tools';

// Full analysis
const analysis = analyzeText("این یک متن فارسی است.");
// {
//   statistics: {
//     totalWords: 5,
//     totalCharacters: 20,
//     persianCharacters: 15,
//     // ... more stats
//   },
//   language: {
//     primaryLanguage: "persian",
//     confidence: 95,
//     isPurePersian: true
//   },
//   readability: {
//     complexity: "ساده",
//     readingTime: 1,
//     averageWordsPerSentence: 5
//   },
//   suggestions: [...]
// }

// Quick helpers
getTextSummary("سلام دنیا"); 
// "متن شامل 2 کلمه در 1 جمله است. زبان اصلی: فارسی (100% اطمینان). زمان مطالعه تقریبی: 1 دقیقه."

getTextComplexity("این جمله ساده است"); // "ساده"

// Text cleaning
cleanText("سَلامٌ   123   دنیا"); // "سلام ۱۲۳ دنیا"

🏗️ Development

Prerequisites

  • Bun ≥ 1.3 (as runtime and package manager)

Setup

git clone https://github.com/persian-tools/persian-tools.git
cd persian-tools
bun install

Scripts

bun run build        # Build the library
bun run test         # Run tests
bun run test:watch   # Watch mode testing
bun run lint         # Lint code
bun run format       # Format code
bun run lint:fix     # Fix linting issues

Architecture

  • TypeScript: Full type safety with strict mode
  • Build: Unbuild (dual ESM/CJS output)
  • Testing: Vitest with comprehensive coverage
  • Quality: ESLint + Prettier + Husky hooks

🌟 Who's Using Persian Tools?

Maani
Maani
Pooleno
Pooleno Exchange
Bank Maskan
Bank Maskan PWA
MyDong
MyDong
Melkba
Melkba

Using Persian Tools in your project? Add it here!


In Memory of @mediv0 🕊️

This project is dedicated to the memory of @mediv0,
a valued contributor whose passion and work helped shape Persian Tools.
Your code lives on, and you will always be remembered in our community. ❤️


🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

Quick Contribution Steps:

  1. Install Bun (from https://bun.sh)
  2. Fork & Clone the repository
  3. Create a feature branch: git checkout -b my-feature
  4. Make your changes with tests
  5. Run bun run test and bun run lint and bun run format to ensure everything passes
  6. Commit with conventional commits (e.g. feat: add new utility function)
  7. Submit a pull request

👨‍💻 Contributors

Ali Torki
Ali Torki

🚇 ⚠️ 💻 🐛 🖋 📖
mssoheil
mssoheil

⚠️ 💻
Mohsen
Mohsen

⚠️ 💻
Hesam pourghazian
Hesam pourghazian

💻
Amir Hossien Qasemi Moqaddam
Amir Hossien Qasemi Moqaddam

💻
SeyyedKhandon
SeyyedKhandon

💻
msdDaliriyan
msdDaliriyan

💻 ⚠️
Mahdi
Mahdi

💻 ⚠️ 📖
PS-PARSA
PS-PARSA

⚠️ 💻 🤔
Amirhossein Douzandeh Zenoozi
Amirhossein Douzandeh Zenoozi

💻 ⚠️ 🤔
M0rteza-M
M0rteza-M

💻 ⚠️
mediv0
mediv0

💻 ⚠️ 🤔
Poorshad Shaddel
Poorshad Shaddel

💻 ⚠️ 🤔
Seyed Masih Sajadi
Seyed Masih Sajadi

💻 ⚠️
Mohammad Ghonchesefidi
Mohammad Ghonchesefidi

💻 ⚠️
Saeed Hasani Borzadaran
Saeed Hasani Borzadaran

💻 ⚠️
Ali Madihi
Ali Madihi

💻
Amir
Amir

📖
Kaveh Karami
Kaveh Karami

💻
Mehdi Shah abbasian
Mehdi Shah abbasian

📖
amirali yavari
amirali yavari

💻
Taha Namdar
Taha Namdar

💻
Alireza Sariri
Alireza Sariri

💻
Sajad Sohrabi
Sajad Sohrabi

💻
Pouriya Babaali
Pouriya Babaali

💻
Mohammad norouzi
Mohammad norouzi

💻
Mohamad Amin Mirzaei
Mohamad Amin Mirzaei

💻
Moein Moeinnia
Moein Moeinnia

💻
Mostafa Ahangarha
Mostafa Ahangarha

💻
Hamid Nasr
Hamid Nasr

💻 🖋
Sina Bayandorian
Sina Bayandorian

💻

📄 License

MIT License - see LICENSE for details.


Made with ❤️ by the Persian developer community

📚 Documentation⭐ Star us on GitHub🐦 Share on Twitter📦 View on NPM