npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nepali-numbers-pro-max

v1.1.0

Published

नेपाली number / NPR currency library for the Nepali developer community. Devanagari ↔ ASCII digits, Indian-style lakh/crore/arab grouping, NPR formatting, number → words (एक करोड पच्चीस लाख…), words → number, ordinals, fractions, compact, paisa-safe BigIn

Readme

nepali-numbers-pro-max

नेपाली अंक र मुद्रा — pro-max edition

The complete Nepali number toolkit. Devanagari ↔ ASCII digits, Indian-style lakh/crore grouping, NPR currency formatting, number → words (एक करोड पच्चीस लाख), words → number, paisa-safe BigInt math, ordinals, fractions, percentages, compact notation.

npm version License: MIT TypeScript Zero deps ESM + CJS


📑 Table of Contents

  1. Highlights
  2. Install
  3. Quick Start
  4. Comparison
  5. Mental Model
  6. Currency Formatting
  7. Number → Words
  8. Words → Number
  9. Indian-style Grouping
  10. NepaliMoney Class
  11. Compact / Percent / Fractions / Ordinals
  12. Full API Reference
  13. Recipes
  14. Range & Accuracy
  15. Contributing

✨ Highlights

  • 🇳🇵 Nepal-first — NPR currency, paisa precision, Indian numbering, Devanagari I/O
  • 📜 Full word coverageएक to महाशंख (10²¹), one to mahashankh, in both languages
  • 🔁 Round-trip parsingtoNepaliWordsparseNepaliWords (no other npm package does this for Nepali)
  • 💰 Paisa-safe arithmetic — BigInt-backed, no 0.1 + 0.2 = 0.30000000000000004
  • 📐 Indian 3-2-2 grouping1,23,45,67,890 not 1,234,567,890
  • 🧮 6 rounding modes — half-up, half-even (banker's), half-down, ceil, floor, trunc
  • 📝 5 NPR symbolsRs., रु., रू, , NPR
  • 🪙 Cheque-style words"One thousand two hundred thirty-four rupees fifty-six paisa Only"
  • 🔢 Smart parser — accepts ASCII, Devanagari, mixed scripts, accounting parens, custom symbols
  • 📦 Tree-shakeable — pure ESM exports, sideEffects: false
  • 🎯 TypeScript-first — strict mode, full type exports, JSDoc on every function
  • 🪶 Zero dependencies — works in Node, Deno, Bun, the browser, and Workers

📦 Install

# npm
npm install nepali-numbers-pro-max

# pnpm
pnpm add nepali-numbers-pro-max

# yarn
yarn add nepali-numbers-pro-max

# bun
bun add nepali-numbers-pro-max

Works with Node ≥ 14, modern browsers, Deno, Bun, Cloudflare Workers, Vercel Edge.


⚡ Quick Start

import {
  toDevanagariDigits,
  groupNepali,
  formatNPR,
  formatNPRDevanagari,
  toNepaliWords,
  toNepaliCurrencyWords,
  parseNepaliWords,
  parseAmount,
  NepaliMoney,
} from "nepali-numbers-pro-max";

// Digits
toDevanagariDigits("Rs. 1,234.56");      // "Rs. १,२३४.५६"

// Indian grouping
groupNepali(12345678);                   // "1,23,45,678"

// NPR
formatNPR(1234567.89);                   // "Rs. 12,34,567.89"
formatNPRDevanagari(1234567.89);         // "रु. १२,३४,५६७.८९"

// Words
toNepaliWords(125_000_00);               // "एक करोड पच्चीस लाख"
toNepaliCurrencyWords(1234.56);
// "एक हजार दुई सय चौँतीस रुपैयाँ छपन्न पैसा मात्र"

// Words → number (round-trip)
parseNepaliWords("एक करोड पच्चीस लाख");   // 12500000n

// Smart amount parser (Devanagari, NPR symbol, Indian grouping)
parseAmount("रु. १२,३४,५६७.८९");
// { paisa: 123456789n, value: 1234567.89, raw: "रु. १२,३४,५६७.८९", negative: false }

// Money class with paisa-safe arithmetic
NepaliMoney.fromRupees(0.1).add(0.2).rupees;   // 0.3 (not 0.30000000000000004)
NepaliMoney.fromRupees(1000).multiply(1.13).formatNPR();   // "Rs. 1,130.00"

📊 Comparison with popular packages

| Capability | nepali-number | nepali-number-words | get-nepali-number | ngx-nepali-number-to-words | nepali-numbers-pro-max | |---|---|---|---|---|---| | Last published | 2019 | 2026 | 2020 | 2020 | 2026 | | TypeScript-first | partial | partial | no | yes (Angular) | ✅ strict | | Zero deps | ✅ | ✅ | ✅ | tslib | | | Devanagari ↔ ASCII | ✅ | ✅ | ✅ | partial | | | Indian 3-2-2 grouping | ✅ | partial | ✅ | no | | | NPR currency formatter | partial | partial | no | no | ✅ 5 symbols, accounting, compact | | Number → Nepali words | ✅ | ✅ | no | ✅ (buggy paisa) | ✅ up to महाशंख | | Number → English (Indian) words | ✅ | no | no | no | | | Words → number (parser) | no | experimental | no | no | ✅ first-class, both languages | | BigInt support | no | no | no | no | | | Banker's rounding / paisa-int math | no | no | no | no | ✅ 6 modes | | Compact (१.२ लाख / 1.5Cr) | partial | no | no | no | | | Fractions (आधा, चौथाइ, डेढ) | no | no | no | no | | | Ordinals (पहिलो, १०१st) | ✅ | no | no | no | ✅ irregular + suffix | | Smart amount parser | partial | no | no | no | ✅ Devanagari + parens + symbols | | Money class with chaining | no | no | no | no | ✅ NepaliMoney | | Tree-shakeable per-function | no | no | no | no | | | Tests | no | no | no | no | ✅ 105 passing |


🧠 Mental Model

| Rule | Why | |---|---| | Indian-style 3-2-2 grouping is the default (1,23,45,67,890). | Nepal/India use it; Western 3-3-3 is opt-in via groupWestern. | | Functions split per language*Nepali for Devanagari, *English…NepaliSystem for Roman. | Avoids { locale } option-bag noise. Each function has one job. | | Money uses BigInt paisa internally, exposes number rupees. | Sidesteps IEEE-754 drift. 0.1 + 0.2 always equals 0.3. | | English words use the Indian scale ladder (lakh/crore/arab), not Western (million/billion). | Mirrors how Nepali speakers express English numbers in everyday Nepal contexts. | | Parsers accept Devanagari, ASCII, mixed, parens, NPR symbols. | Real input is messy — handle it. | | NPR symbol presets: Rs., रु., रू, , NPR. | All five used in production banking software. |


💰 Currency Formatting

formatNPR(1234567.89);                       // "Rs. 12,34,567.89"
formatNPR(1234567.89, { symbol: "NPR" });    // "NPR 12,34,567.89"
formatNPR(1234567.89, { precision: 0 });     // "Rs. 12,34,568"
formatNPR(-500);                             // "-Rs. 500.00"

formatNPRDevanagari(1234567.89);             // "रु. १२,३४,५६७.८९"
formatNPRAccounting(-500);                   // "(Rs. 500.00)"
formatNPRCompact(2_50_00_000);               // "Rs. 2.5Cr"
formatNPRCompact(150_000);                   // "Rs. 1.5L"

| Function | Output | |---|---| | formatNPR(n) | Rs. 12,34,567.89 | | formatNPRDevanagari(n) | रु. १२,३४,५६७.८९ | | formatNPRAccounting(-n) | (Rs. 500.00) | | formatNPRCompact(n) | Rs. 2.5Cr, Rs. 1.5L, Rs. 1.2K | | stripNprSymbol(s) | strips Rs./रु./रू//NPR |


📝 Number → Words

Up to 10²¹ (महाशंख) via BigInt internally.

toNepaliWords(0);                           // "शून्य"
toNepaliWords(99);                          // "उनान्सय"
toNepaliWords(125);                         // "एक सय पच्चीस"
toNepaliWords(99999);                       // "उनान्सय हजार नौ सय उनान्सय"
toNepaliWords(125_000_00);                  // "एक करोड पच्चीस लाख"
toNepaliWords(1_00_00_00_000);              // "एक अर्ब"
toNepaliWords(-25);                         // "ऋणात्मक पच्चीस"
toNepaliWords(100000000000000000000n);      // "दश महाशंख"

toEnglishWordsNepaliSystem(125_000_00);     // "one crore twenty-five lakh"

// Currency words
toNepaliCurrencyWords(1234.56);
// "एक हजार दुई सय चौँतीस रुपैयाँ छपन्न पैसा मात्र"

toNepaliCurrencyWordsWithoutMatra(1234);    // "एक हजार दुई सय चौँतीस रुपैयाँ"
toNepaliCurrencyWordsBare(1234.5);          // "एक हजार दुई सय चौँतीस पचास"

toEnglishCurrencyWordsNepaliSystem(1234.56);
// "one thousand two hundred thirty-four rupees fifty-six paisa only"

toChequeStyleEnglish(1234.56);
// "One thousand two hundred thirty-four rupees fifty-six paisa Only"

The Indian scale ladder used: हजार (10³) → लाख (10⁵) → करोड (10⁷) → अर्ब (10⁹) → खर्ब (10¹¹) → नील (10¹³) → पद्म (10¹⁵) → शंख (10¹⁷) → महाशंख (10¹⁹).


🔁 Words → Number (parsing)

The headline reverse-direction feature. Round-trips with the words generators.

parseNepaliWords("एक करोड पच्चीस लाख");        // 12500000n
parseNepaliWords("दुई हजार र पच्चीस");          // 2025n  (र = "and" connector)
parseNepaliWords("ऋणात्मक पच्चीस");             // -25n

parseEnglishWordsNepaliSystem("one crore twenty-five lakh");   // 12500000n
parseEnglishWordsNepaliSystem("one hundred and twenty-five");  // 125n

parseNepaliCurrencyWords("एक हजार रुपैयाँ पच्चीस पैसा मात्र");
// { rupee: 1000n, paisa: 25, negative: false }

parseEnglishCurrencyWordsNepaliSystem(
  "one thousand rupees twenty-five paisa only",
);
// { rupee: 1000n, paisa: 25, negative: false }

// Smart string-amount parser
parseAmount("रु. १२,३४,५६७.८९");
// { paisa: 123456789n, value: 1234567.89, raw: "...", negative: false }

parseAmount("(Rs. 100.00)");           // { paisa: -10000n, negative: true, ... }
safeParseAmount("not a number");       // null
canonicalizeAmount("रु. १,२३४.५६");    // "1234.56"

📐 Indian-style Grouping

groupNepali(0);                       // "0"
groupNepali(1234);                    // "1,234"
groupNepali(12345);                   // "12,345"
groupNepali(123456);                  // "1,23,456"
groupNepali(12345678);                // "1,23,45,678"
groupNepali(1234567890);              // "1,23,45,67,890"
groupNepali(123456.789);              // "1,23,456.789"
groupNepali(-12345);                  // "-12,345"
groupNepali(123456789012345n);        // "12,34,56,78,90,12,345" (BigInt)

groupNepaliDevanagari(12345678);      // "१,२३,४५,६७८"
groupWestern(12345678);               // "12,345,678"
compareGrouping(12345678);
// { nepali: "1,23,45,678", western: "12,345,678" }

🪙 NepaliMoney Class

Immutable money object with paisa-precise arithmetic.

import { NepaliMoney } from "nepali-numbers-pro-max";

const total = NepaliMoney.fromRupees(1234.56)
  .add(NepaliMoney.fromRupees(100))
  .multiply(1.13)            // add 13% VAT
  .subtract(50);

total.formatNPR();           // "Rs. 1,458.05"
total.formatNPRDevanagari(); // "रु. १,४५८.०५"
total.toNepaliWords();       // "एक हजार चार सय अन्ठाउन्न रुपैयाँ पाँच पैसा मात्र"

// Allocate without losing rupees to rounding
NepaliMoney.fromRupees(10).allocate(3).map(p => p.rupees);
// [3.34, 3.33, 3.33] — sums to exactly 10

// Comparison
const a = NepaliMoney.fromRupees(100);
const b = NepaliMoney.fromRupees(200);
a.lessThan(b);    // true
a.compare(b);     // -1

// Parse straight from a formatted string
NepaliMoney.parse("रु. १,२३४.५६").rupees;   // 1234.56

Internal representation is signed BigInt paisa — no FP drift, supports values past Number.MAX_SAFE_INTEGER.


🎨 Compact / Percent / Fractions / Ordinals

// Compact
formatCompactEnglish(1234);              // "1.2K"
formatCompactEnglish(125000);            // "1.3L"
formatCompactEnglish(2_50_00_000);       // "2.5Cr"
formatCompactEnglish(2_50_00_000, { long: true }); // "2.5 crore"

formatCompactNepali(1234);               // "१.२ हजार"
formatCompactNepali(125000);             // "१.३ लाख"
formatCompactNepali(2_50_00_000);        // "२.५ करोड"

// Percent
formatPercent(25);                       // "25%"
formatPercent(25.5, { precision: 1 });   // "25.5%"
formatPercentDevanagari(25);             // "२५%"
percentToNepaliWords(25);                // "पच्चीस प्रतिशत"
percentToEnglishWords(25.5);             // "twenty-five point five percent"

// Fractions
fractionToNepaliWords(1, 2);             // "आधा"
fractionToNepaliWords(3, 4);             // "तीन चौथाइ"
fractionToNepaliWords(2, 3);             // "दुई तिहाइ"
fractionToEnglishWords(3, 4);            // "three quarters"
decimalToNepaliFraction(0.5);            // "आधा"
decimalToNepaliFraction(0.42);           // null

// Ordinals
toNepaliOrdinal(1);                      // "पहिलो"
toNepaliOrdinal(10);                     // "दशौँ"
toNepaliOrdinal(11);                     // "एघारऔँ"
toEnglishOrdinal(21);                    // "21st"
toEnglishOrdinal(113);                   // "113th"

🧰 Full API Reference

| Function | Description | |---|---| | toDevanagariDigits(input) | Convert digits in string to Devanagari (०-९). | | toAsciiDigits(input) | Convert digits in string to ASCII (0-9). | | toDevanagariChar(ch) | Single-char converter (throws if invalid). | | toAsciiChar(ch) | Single-char converter (throws if invalid). | | detectScript(s) | "ascii" \| "devanagari" \| "mixed" \| "none" | | normalizeDigits(s, "ascii" \| "devanagari") | Coerce mixed strings to one script. | | isAllAsciiDigits(s) | True if every char is 0-9. | | isAllDevanagariDigits(s) | True if every char is -. | | DEVANAGARI_DIGITS, ASCII_DIGITS | Constant lookup tables. |

| Function | Description | |---|---| | groupNepali(n, opts?) | Indian-style 3-2-2 grouping (1,23,45,678). | | groupNepaliDevanagari(n, opts?) | Same, in Devanagari digits. | | groupWestern(n, opts?) | Western 3-3-3 grouping (12,345,678). | | compareGrouping(n) | { nepali, western }. |

Options: { separator?: string, decimal?: string }.

| Function | Output style | |---|---| | formatNPR(n, opts?) | Rs. 12,34,567.89 | | formatNPRDevanagari(n, opts?) | रु. १२,३४,५६७.८९ | | formatNPRAccounting(n, opts?) | (Rs. 500.00) for negatives | | formatNPRCompact(n, opts?) | Rs. 2.5Cr, Rs. 1.5L, Rs. 1.2K | | stripNprSymbol(s) | Remove Rs., रु., रू, , NPR |

FormatNprOptions: { symbol, precision, rounding, symbolPosition, symbolSpacing, devanagari, separator, decimal }.

| Function | Example output | |---|---| | toNepaliWords(n) | "एक करोड पच्चीस लाख" | | toEnglishWordsNepaliSystem(n) | "one crore twenty-five lakh" | | toNepaliCurrencyWords(amount) | "… रुपैयाँ … पैसा मात्र" | | toNepaliCurrencyWordsWithoutMatra(amount) | drops मात्र suffix | | toNepaliCurrencyWordsBare(amount) | no रुपैयाँ/पैसा labels | | toEnglishCurrencyWordsNepaliSystem(amount) | "… rupees … paisa only" | | toEnglishCurrencyWordsWithoutOnly(amount) | drops only suffix | | toEnglishCurrencyWordsBare(amount) | no rupees/paisa labels | | toChequeStyleEnglish(amount) | capitalized cheque-style |

| Function | Returns | |---|---| | parseNepaliWords(s) | bigint | | parseEnglishWordsNepaliSystem(s) | bigint | | parseNepaliCurrencyWords(s) | { rupee, paisa, negative } | | parseEnglishCurrencyWordsNepaliSystem(s) | { rupee, paisa, negative } | | parseAmount(s) | { paisa, value, raw, negative } | | safeParseAmount(s) | ParsedAmount \| null | | canonicalizeAmount(s) | normalized "1234.56" form | | isValidAmount(s) | boolean | | isValidNepaliDigitString(s) | boolean | | isValidAsciiNumberString(s) | boolean |

| Function | Description | |---|---| | roundPaisa(n, mode?, precision?) | 6 rounding modes | | roundToScale(n, scale, mode?) | round to nearest 1000, 1L, 1Cr, etc. | | rupeeToPaisa(rupee) | number → bigint | | paisaToRupee(paisa) | bigint → number | | splitRupeePaisa(amount) | { rupee: bigint, paisa: 0-99, negative } | | addAmount(a, b) | FP-drift-free addition | | subtractAmount(a, b) | FP-drift-free subtraction | | multiplyAmount(a, factor, mode?) | rounded to paisa | | divideAmount(a, divisor, mode?) | rounded to paisa | | splitAmount(amount, n) | n-way split with remainder distribution | | toFixedAmount(n, decimals?) | drift-free toFixed |

Rounding modes: "half-up" \| "half-even" \| "half-down" \| "ceil" \| "floor" \| "trunc".

| Function | Example | |---|---| | formatCompactEnglish(n, opts?) | 1.2K, 1.5L, 2.5Cr | | formatCompactNepali(n, opts?) | १.२ हजार, १.५ लाख, २.५ करोड | | formatPercent(n, opts?) | 25% | | formatPercentDevanagari(n, opts?) | २५% | | percentToNepaliWords(n) | पच्चीस प्रतिशत | | percentToEnglishWords(n) | twenty-five percent | | fractionToNepaliWords(num, den) | आधा, तीन चौथाइ | | fractionToEnglishWords(num, den) | half, three quarters | | decimalToNepaliFraction(v, tol?) | आधा for 0.5, null if no match | | toNepaliOrdinal(n) | पहिलो, दोस्रो, एघारऔँ | | toEnglishOrdinal(n) | 1st, 2nd, 113th |

| Method | Description | |---|---| | NepaliMoney.fromRupees(n) | from rupees number | | NepaliMoney.fromPaisa(p) | from BigInt paisa | | NepaliMoney.parse(s) | parse formatted string | | NepaliMoney.zero() | zero instance | | .rupees, .paisa, .negative, .isZero | accessors | | .split() | { rupee, paisa, negative } | | .add(x) / .subtract(x) | x can be NepaliMoney or number | | .multiply(factor) / .divide(divisor) | scalar math, paisa-rounded | | .negate() / .abs() | sign helpers | | .allocate(n) | n-way split, no rupee lost | | .equals(o) / .greaterThan(o) / .lessThan(o) / .compare(o) | comparison | | .formatNPR(opts?), .formatNPRDevanagari(), .formatNPRAccounting(), .formatCompact() | formatting | | .toNepaliWords() / .toEnglishWords() | currency words | | .toString() | default formatNPR() | | .toJSON() | canonical "1234.56" |

| Constant | Description | |---|---| | DEVANAGARI_DIGITS, ASCII_DIGITS | digit tables | | SCALES | scale ladder up to महाशंख | | NEPALI_ONES | 0-99 lookup table | | ENGLISH_ONES, ENGLISH_TENS | English word tables | | NEPALI_HUNDRED | "सय" | | RUPEE_WORD_NE, RUPEE_WORD_EN | "रुपैयाँ" / "rupees" | | PAISA_WORD_NE, PAISA_WORD_EN | "पैसा" / "paisa" | | MATRA_NE, ONLY_EN | "मात्र" / "only" | | NEGATIVE_NE, NEGATIVE_EN | "ऋणात्मक" / "negative" | | AND_NE, AND_EN | "र" / "and" | | NEPALI_ORDINALS_LOW | irregular 1-10 | | NEPALI_FRACTIONS_TABLE | curated fraction words |


🎯 Recipes

Invoice line item with VAT

import { NepaliMoney } from "nepali-numbers-pro-max";

const subtotal = NepaliMoney.fromRupees(50000);
const vat = subtotal.multiply(0.13);
const total = subtotal.add(vat);

console.log(total.formatNPRDevanagari());   // "रु. ५६,५००.००"
console.log(total.toNepaliWords());
// "छपन्न हजार पाँच सय रुपैयाँ मात्र"

Cheque writing

import { toChequeStyleEnglish } from "nepali-numbers-pro-max";

const chequeText = toChequeStyleEnglish(1_25_000.50);
// "One lakh twenty-five thousand rupees fifty paisa Only"

Reading user-typed Nepali amounts

import { parseAmount, formatNPRDevanagari } from "nepali-numbers-pro-max";

const userInput = "रु. १,२३,४५६.७८";
const parsed = parseAmount(userInput);

console.log(parsed.value);                          // 123456.78
console.log(formatNPRDevanagari(parsed.value));     // "रु. १,२३,४५६.७८"

Splitting a bill

import { NepaliMoney } from "nepali-numbers-pro-max";

const dinner = NepaliMoney.fromRupees(2575.65);
const split = dinner.allocate(4);
// First person pays 1 paisa more (no rupee disappears)
console.log(split.map(p => p.formatNPR()));
// [ "Rs. 643.92", "Rs. 643.91", "Rs. 643.91", "Rs. 643.91" ]

Tally with paisa precision

import { NepaliMoney } from "nepali-numbers-pro-max";

const items = [49.99, 19.95, 4.50, 2.75];
const total = items.reduce(
  (sum, item) => sum.add(item),
  NepaliMoney.zero(),
);
total.formatNPR();   // "Rs. 77.19"  — exact, no FP error

📐 Range & Accuracy

  • Words generation supports up to 10²¹ (दश महाशंख) via BigInt internally.
  • Money arithmetic uses signed BigInt paisa — no precision loss.
  • number rupee accessor is lossy past Number.MAX_SAFE_INTEGER / 100 ≈ 90 trillion rupees. For larger values, use .paisa directly.
  • Rounding defaults to half-up (Nepali invoicing convention). Use "half-even" for accounting-grade tax math.
  • Devanagari digit range: U+0966 () to U+0966+9 (). Other Indic digit ranges (Tamil, Bengali, etc.) are not transliterated — Devanagari only.

🤝 Contributing

PRs welcome. Open an issue for:

  • New scale-name variants (regional Nepali / Maithili / Bhojpuri)
  • Additional fraction lookups
  • Operator/region-specific currency symbol presets
npm install
npm test
npm run typecheck
npm run build

📜 License

MIT © 2026 l3lackcurtains


Made with ❤️ for the Nepali developer community.

बनाइएको नेपाली डेभलपर समुदायको लागि।