indian_formatters

pub package License: MIT Platform

A comprehensive Flutter/Dart package for India-specific formatting, validation, and parsing. Now with tree-shaking support, deep checksum validation, and reverse parsing!

What's New in v0.0.2 🚀

🌳 Tree-Shaking Support - Reduce your bundle size by up to 80%!

// 🌳 Granular imports for optimal tree-shaking (up to 80% smaller bundle!)
import 'package:indian_formatters/validators/upi.dart';
import 'package:indian_formatters/validators/pan.dart';
// Only UPI and PAN validators included - everything else tree-shaken away!

📍 Pincode Mapper - Accurate state detection using official India Post logic

// 📍 Pincode mapping with first 2-digit logic
String state = PincodeMapper.getState('411001');     // "Maharashtra"
String region = PincodeMapper.getRegionName('411001'); // "Pune Region"
bool isUT = PincodeMapper.isUnionTerritory('110001'); // true (Delhi)

🔐 Deep Checksum Validation - Mathematical validation for PAN and GST

// 🔐 Deep mathematical checksum validation
bool isValid = PANValidator.isPAN('ABCDE1234F');  // Validates 10th character checksum
String checksum = PANValidator.calculateChecksum('ABCDE1234'); // Calculate checksum
String pan = GSTValidator.extractPAN('27AAPFU0939F1ZV'); // Extract PAN from GST

🔄 Reverse Parsing - Parse formatted strings back to numbers

// 🔄 Reverse parsing back to raw numbers
num value = "12,34,567".parseIndianNumber();     // 1234567
num compactValue = "12L".parseIndianCompact();   // 1200000
num currency = "₹12,34,567.89".parseIndianCurrency(); // 1234567.89
List<num> range = "1L - 5L".parseIndianRange();  // [100000, 500000]

Features

Number Formatting

  • Indian numbering system (lakhs, crores, arabs)
  • Number to words (English and Hindi)
  • Compact notation (12L, 1Cr)
  • NEW: Reverse parsing from formatted strings

💰 Currency Formatting

  • ₹ symbol with Indian comma grouping
  • Amount in words (for cheques)
  • Compact currency notation
  • NEW: Parse currency strings back to numbers

Validators

  • NEW: Tree-shaking support - import only what you need!
  • NEW: Deep mathematical checksum validation for PAN & GST
  • PAN Card (with holder type detection + checksum validation)
  • Aadhaar (with Verhoeff algorithm)
  • GST Number (with state extraction + checksum validation)
  • Mobile Number (with operator detection)
  • IFSC Code (with bank name)
  • PIN Code (NEW: accurate state/region mapping)
  • Driving License
  • Voter ID (EPIC)
  • UPI ID (with provider detection)

📅 Date Formatting

  • Indian date format
  • Hindi numerals and month names
  • Fiscal year and financial quarter
  • Hindu calendar month names

🗺️ Address Utilities

  • All 28 states + 8 UTs
  • GST codes, capitals, Hindi names
  • Address formatting with copyWith support
  • NEW: Pincode to state/region mapping with 70+ regions

🌳 Tree-Shaking & Bundle Optimization

  • NEW: Granular imports reduce bundle size by up to 80%
  • Import only validators, only formatters, or individual components
  • Zero bloat - only include what you use

Installation

Add this to your pubspec.yaml:

dependencies:
  indian_formatters: ^0.0.2

Or install via command line:

flutter pub add indian_formatters

Quick Start

// 🌳 Tree-shaking imports (recommended for smaller bundle size)
import 'package:indian_formatters/validators/pan.dart';
import 'package:indian_formatters/validators/upi.dart';
import 'package:indian_formatters/formatters.dart';

// OR full import (convenience)
import 'package:indian_formatters/indian_formatters.dart';

// Number formatting
print(1234567.toIndian());              // "12,34,567"
print(1234567.toIndianWords());         // "12 Lakh 34 Thousand 5 Hundred 67"
print(1234567.toIndianWordsHindi());    // "बारह लाख चौंतीस हज़ार..."
print(1200000.toIndianCompact());       // "12L"

// 🔄 NEW: Reverse parsing
print("12,34,567".parseIndianNumber());     // 1234567
print("12L".parseIndianCompact());          // 1200000
print("₹12,34,567.89".parseIndianCurrency()); // 1234567.89

// Currency formatting
print(1234567.89.toRupees());           // "₹12,34,567.89"
print(1234567.89.toRupeesWords());      // "Twelve Lakh... Rupees and Eighty-Nine Paise"
print(1234567.89.toChequeFormat());     // "... Rupees and Eighty-Nine Paise Only"

// 🔐 NEW: Enhanced validators with checksum validation
print(PANValidator.isPAN("ABCDE1234F"));           // true (with checksum validation)
print(GSTValidator.isGST("27AAPFU0939F1ZV"));      // true (with checksum validation)
print(IndianValidators.validateAadhaar("234567890123")); // null (valid)

// 📍 NEW: Accurate pincode mapping
print(PincodeMapper.getState("411001"));         // "Maharashtra"
print(PincodeMapper.getRegionName("411001"));    // "Pune Region"
print(PincodeMapper.isUnionTerritory("110001")); // true (Delhi)

// Date formatting
print(DateTime.now().toIndianFormat());     // "24 April 2026"
print(DateTime.now().fiscalYear());         // "FY 2026-27"
print(DateTime.now().financialQuarter());   // "Q1 FY27"

// States and address
final mh = IndianStates.byCode("MH");
print(mh?.gstCode);  // 27
print(mh?.capital);  // "Mumbai"

🌳 Tree-Shaking & Import Strategies

Optimize your bundle size with granular imports!

Option 1: Full Import (Convenience)

import 'package:indian_formatters/indian_formatters.dart';
// Everything included - formatters, validators, utilities

Option 2: Validators Only (~40% smaller)

import 'package:indian_formatters/validators.dart';
// Only validators - formatters tree-shaken away

Option 3: Formatters Only (~35% smaller)

import 'package:indian_formatters/formatters.dart';
// Only formatters - validators tree-shaken away

Option 4: Individual Imports (~70-80% smaller)

import 'package:indian_formatters/validators/pan.dart';
import 'package:indian_formatters/validators/upi.dart';
// Only PAN and UPI validators - everything else tree-shaken away!

Available Individual Imports:

  • validators/pan.dart - PAN validation with checksum
  • validators/aadhaar.dart - Aadhaar with Verhoeff algorithm
  • validators/gst.dart - GST validation with checksum
  • validators/upi.dart - UPI ID validation
  • validators/mobile.dart - Mobile number validation
  • validators/ifsc.dart - IFSC code validation
  • validators/pincode.dart - PIN code validation
  • validators/driving_license.dart - Driving license validation
  • validators/voter_id.dart - Voter ID validation

API Reference

Number Formatting

IndianNumberFormatter

// Static methods
IndianNumberFormatter.format(1234567)           // "12,34,567"
IndianNumberFormatter.formatWords(1234567)      // "12 Lakh 34 Thousand..."
IndianNumberFormatter.formatWordsHindi(1234567) // "बारह लाख..."
IndianNumberFormatter.toWords(100)              // "One Hundred"
IndianNumberFormatter.compact(1200000)          // "12L"
IndianNumberFormatter.compactFull(1200000)      // "12 Lakh"
IndianNumberFormatter.compactCrore(10000000)    // "1Cr"

Extension on num

1234567.toIndian()              // "12,34,567"
1234567.toIndianWords()         // "12 Lakh 34 Thousand..."
1234567.toIndianWordsHindi()    // "बारह लाख..."
1234567.toIndianCompact()       // "12L"
1234567.toIndianCompactFull()   // "12 Lakh"
100.toWords()                   // "One Hundred"
100.toWordsHindi()              // "एक सौ"

Currency Formatting

IndianCurrencyFormatter

IndianCurrencyFormatter.format(1234567.89)              // "₹12,34,567.89"
IndianCurrencyFormatter.format(1234567, symbol: 'Rs. ') // "Rs. 12,34,567"
IndianCurrencyFormatter.formatWords(1234567.89)         // "Twelve Lakh... Rupees and Eighty-Nine Paise"
IndianCurrencyFormatter.formatCompact(1234567)          // "₹12L"
IndianCurrencyFormatter.forCheque(1234567.89)           // "... Rupees and Eighty-Nine Paise Only"
IndianCurrencyFormatter.parseCurrency("₹12,34,567")     // 1234567.0

Extension on num

1234567.89.toRupees()               // "₹12,34,567.89"
1234567.89.toRupeesWords()          // "Twelve Lakh... Rupees and Eighty-Nine Paise"
1234567.toRupeesCompact()           // "₹12L"
1234567.89.toChequeFormat()         // "... Rupees and Eighty-Nine Paise Only"

🔄 String Parsing (NEW in v0.0.2)

IndianStringParser

// Parse various Indian number formats back to numbers
IndianStringParser.parseNumber("12,34,567")      // 1234567
IndianStringParser.parseCurrency("₹12,34,567.89") // 1234567.89
IndianStringParser.parseInt("12,34,567")         // 1234567
IndianStringParser.parseCompact("12L")           // 1200000
IndianStringParser.parseAny("₹12L")             // 1200000
IndianStringParser.canParse("12,34,567")        // true
IndianStringParser.parseRange("1L - 5L")        // [100000, 500000]

Extension on String

"12,34,567".parseIndianNumber()        // 1234567
"₹12,34,567.89".parseIndianCurrency()  // 1234567.89
"12,34,567".parseIndianInt()           // 1234567
"12L".parseIndianCompact()             // 1200000
"₹12L".parseIndianAny()                // 1200000
"12,34,567".canParseIndian()           // true
"1L - 5L".parseIndianRange()           // [100000, 500000]

Supported Formats:

  • Indian comma grouping: "12,34,567"1234567
  • Currency symbols: "₹12,34,567.89", "Rs 1234" → numbers
  • Compact notation: "12L", "1.5Cr", "50K" → full numbers
  • Negative numbers: "-12,34,567"-1234567
  • Ranges: "10,000 - 50,000"[10000, 50000]

Validators

IndianValidators

All validators provide two methods:

  • isX() → returns bool
  • validateX() → returns String? (null = valid, string = error message)

PAN Card (🔐 NEW: Deep checksum validation)

PANValidator.isPAN("ABCPE1234F")          // true (validates 10th character checksum)
PANValidator.isPAN("ABCPE1234F", verifyChecksum: false) // Skip checksum validation
IndianValidators.validatePAN("ABCPE1234F")    // null (valid)
IndianValidators.getPANType("ABCPE1234F")     // PANType.individual

// NEW: Checksum utilities
PANValidator.calculateChecksum("ABCPE1234")    // Returns calculated checksum character
IndianValidators.calculatePANChecksum("ABCPE1234") // Same via IndianValidators

Aadhaar

IndianValidators.isAadhaar("234567890123")    // true (with Verhoeff validation)
IndianValidators.validateAadhaar("234567...")  // null or error
IndianValidators.maskAadhaar("234567890123")   // "XXXX XXXX 0123"

GST Number (🔐 NEW: Deep checksum validation)

GSTValidator.isGST("27AAPFU0939F1ZV")       // true (validates 15th character checksum)
GSTValidator.isGST("27AAPFU0939F1ZV", verifyChecksum: false) // Skip checksum validation
IndianValidators.validateGST("27AAPFU0939F1ZV") // null
IndianValidators.getGSTState("27AAPFU0939F1ZV") // "Maharashtra"
IndianValidators.getGSTStateCode("27...")        // 27

// NEW: Checksum and PAN extraction utilities
GSTValidator.calculateChecksum("27AAPFU0939F1Z") // Returns calculated checksum character
GSTValidator.extractPAN("27AAPFU0939F1ZV")       // "AAPFU0939F"
IndianValidators.calculateGSTChecksum("27AAPFU0939F1Z") // Same via IndianValidators
IndianValidators.extractPANFromGST("27AAPFU0939F1ZV")   // Same via IndianValidators

Mobile Number

IndianValidators.isMobile("9876543210")          // true
IndianValidators.isMobile("+919876543210")       // true
IndianValidators.validateMobile("9876543210")    // null
IndianValidators.formatMobile("9876543210")      // "+91 98765 43210"
IndianValidators.getOperatorSeries("9876543210") // "Airtel (approx)"

IFSC Code

IndianValidators.isIFSC("SBIN0001234")          // true
IndianValidators.validateIFSC("SBIN0001234")    // null
IndianValidators.getBankFromIFSC("SBIN0001234") // "State Bank of India"

PIN Code (📍 NEW: Accurate state/region mapping)

IndianValidators.isPincode("411001")            // true
IndianValidators.validatePincode("411001")      // null

// NEW: Enhanced pincode mapping
PincodeMapper.getState("411001")                // "Maharashtra" (accurate)
PincodeMapper.getRegionName("411001")           // "Pune Region"
PincodeMapper.getRegion("411001")               // PostalRegion object
PincodeMapper.isUnionTerritory("110001")        // true (Delhi)
PincodeMapper.searchByState("Maharashtra")      // List<PostalRegion>

// Legacy method (less accurate)
IndianValidators.getStateFromPincode("411001")  // "Maharashtra, Goa..." (approximate)

Driving License

IndianValidators.isDrivingLicense("MH01-2023-0012345")  // true
IndianValidators.validateDrivingLicense("MH01...")       // null

Voter ID

IndianValidators.isVoterID("ABC1234567")        // true
IndianValidators.validateVoterID("ABC1234567")  // null

UPI ID

IndianValidators.isUPI("someone@upi")           // true
IndianValidators.validateUPI("someone@upi")     // null
IndianValidators.getUPIProvider("someone@okaxis") // "Axis Bank"

Date Formatting

IndianDateFormatter

IndianDateFormatter.format(DateTime.now())          // "16 April 2026"
IndianDateFormatter.formatHindi(DateTime.now())     // "१६ अप्रैल २०२६"
IndianDateFormatter.toHindiNumerals("2026")         // "२०२६"
IndianDateFormatter.toDevanagari(DateTime.now())    // "१६/०४/२०२६"
IndianDateFormatter.fiscalYear(DateTime.now())      // "FY 2025-26"
IndianDateFormatter.financialQuarter(DateTime.now()) // "Q1 FY26"
IndianDateFormatter.hinduMonthName(DateTime.now())  // "Chaitra"
IndianDateFormatter.hindiMonthName(DateTime.now())  // "अप्रैल"

Extension on DateTime

DateTime.now().toIndianFormat()        // "16 April 2026"
DateTime.now().toHindiFormat()         // "१६ अप्रैल २०२६"
DateTime.now().fiscalYear()            // "FY 2025-26"
DateTime.now().financialQuarter()      // "Q1 FY27"
DateTime.now().hinduMonthName()        // "Chaitra"

Address & States

IndianStates

IndianStates.all                        // List of all 36 states/UTs
IndianStates.byCode("MH")              // IndianState object
IndianStates.byGSTCode(27)             // IndianState object
IndianStates.search("maha")            // [Maharashtra]

// IndianState properties
state.name          // "Maharashtra"
state.code          // "MH"
state.gstCode       // 27
state.capital       // "Mumbai"
state.isUT          // false
state.hindiName     // "महाराष्ट्र"

IndianAddressFormatter

final address = IndianAddressFormatter.format(
  line1: "123 Main St",
  line2: "Koregaon Park",
  city: "Pune",
  state: "Maharashtra",
  pincode: "411001",
);

print(address.formatted);  // Multi-line formatted address
print(address.city);       // "Pune"

// Copy with modifications
final newAddress = address.copyWith(city: "Mumbai");

Use in Flutter Forms

All validators return String? making them perfect for TextFormField:

TextFormField(
  decoration: InputDecoration(labelText: 'PAN Card'),
  validator: IndianValidators.validatePAN,
  autovalidateMode: AutovalidateMode.onUserInteraction,
)

Platform Support

This package supports all Dart platforms:

  • ✅ Android
  • ✅ iOS
  • ✅ Web
  • ✅ macOS
  • ✅ Windows
  • ✅ Linux

Dependencies

Zero external dependencies (except meta for annotations). Pure Dart implementation.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Author

Created by vivekTemp250602

Acknowledgments

  • Indian numbering system standards
  • TRAI mobile number series allocation
  • GST state codes from GSTN
  • Verhoeff algorithm for Aadhaar validation

Note: Mobile operator detection and PIN code to state mapping are approximate. For production use cases requiring exact data, consider integrating with official APIs.

Libraries

formatters
Formatters-only export for tree-shaking optimization.
indian_formatters
A comprehensive Flutter/Dart package for India-specific formatting, validation, and parsing.
validators
Validators-only export for tree-shaking optimization.
validators/aadhaar
Aadhaar validator only.
validators/driving_license
Driving License validator only.
validators/gst
GST validator only.
validators/ifsc
IFSC code validator only.
validators/mobile
Mobile number validator only.
validators/pan
PAN Card validator only.
validators/pincode
PIN code validator only.
validators/upi
UPI validator only.
validators/voter_id
Voter ID validator only.