locale_money_field 0.1.0 copy "locale_money_field: ^0.1.0" to clipboard
locale_money_field: ^0.1.0 copied to clipboard

Locale-aware money and number input for Flutter with a precision-safe value model and a significant-character caret that never jumps on mid-string edits.

locale_money_field #

Locale-aware money and number input for Flutter, with a precision-safe value model and a significant-character caret that never jumps on mid-string edits.

Type 12345 in en-US and you get $12,345; switch the locale to de-DE and the same keystrokes give 12.345 €; in hi-IN they group as ₹12,345 with the Indian lakh system; in ar-EG they render in Arabic-Indic digits. Grouping separators appear as you type, the caret stays put when you edit in the middle, and backspacing a separator removes the digit in front of it.

iOS Android
iOS demo Android demo

Features #

  • Locale-aware formatting powered by CLDR data from package:intl: grouping, decimal marks, digit shapes (Latin, Arabic-Indic), and currency symbol placement all follow the locale.
  • Precision-safe value model. Amounts are an exact BigInt count of minor units plus a scale, never a double, so they stay correct even on the web where int is a 53-bit float.
  • Significant-character caret. The cursor tracks the digit you were editing instead of snapping to the end, even when grouping shifts the surrounding text.
  • Smart separator backspace. Deleting a grouping separator removes the digit before it, matching what users expect.
  • Live bounds. Optional inclusive min / max reject out-of-range edits as they happen.
  • Layered, extensible API. Use the batteries-included MoneyField widget, drop a MoneyInputFormatter onto a plain TextField, or call the pure formatMoney / parseMoney functions directly. Swap in your own MoneyFormatter to change behaviour without forking.

Getting started #

Add the dependency:

dependencies:
  locale_money_field: ^0.1.0

Then import it:

import 'package:locale_money_field/locale_money_field.dart';

Usage #

The MoneyField widget #

For the common case, give it a config and listen with onChanged. The parsed amount arrives as a MoneyValue? (null when the field is empty):

MoneyField(
  config: const MoneyConfig(locale: 'de-DE', currency: 'EUR'),
  decoration: const InputDecoration(
    labelText: 'Amount',
    border: OutlineInputBorder(),
  ),
  onChanged: (value) => print(value?.decimalString), // canonical "1234.56"
)

Reading and setting the value with a controller #

MoneyEditingController is a TextEditingController that understands money. It keeps the text formatted for its config and exposes the parsed amount as moneyValue:

final controller = MoneyEditingController(
  config: const MoneyConfig(locale: 'en-US', currency: 'USD'),
);

// Set the field programmatically.
controller.moneyValue = MoneyValue.fromDecimalString('1234.56'); // shows $1,234.56

// Read what the user entered.
final amount = controller.moneyValue; // MoneyValue? or null when empty

// Reformat live by swapping the locale / currency.
controller.config = const MoneyConfig(locale: 'de-DE', currency: 'EUR');

MoneyField(controller: controller);

Dropping a formatter onto a plain TextField #

When you want full control over the field, use MoneyInputFormatter directly:

TextField(
  keyboardType: const TextInputType.numberWithOptions(decimal: true),
  inputFormatters: [
    MoneyInputFormatter(config: const MoneyConfig(currency: 'USD')),
  ],
)

Pure formatting and parsing, no widgets #

The engine is available as plain functions for validation, display, or tests:

const config = MoneyConfig(locale: 'hi-IN', currency: 'INR');

final text = formatMoney(MoneyValue.fromDecimalString('1234567.89'), config);
// "₹12,34,567.89"

final value = parseMoney('₹12,34,567.89', config);
// MoneyValue(minorUnits: 123456789, scale: 2)

The MoneyValue model #

MoneyValue is the exact, locale-independent amount that flows in and out of the field:

final a = MoneyValue.fromDecimalString('19.99'); // minorUnits 1999, scale 2
final b = MoneyValue.fromMinorUnits(BigInt.from(2500), scale: 2); // 25.00

print(a.decimalString); // "19.99"  (always '.' decimal, no grouping)
print(a < b);           // true
print(a == MoneyValue.fromDecimalString('19.990')); // true (trailing zeros ignored)

Store and transmit the decimalString (or minorUnits + scale); never round a money value through double.

Configuration #

MoneyConfig is immutable and every field is optional:

Field Default Purpose
locale ambient locale BCP-47 / ICU locale id, e.g. en-US, de-DE, ar.
currency none ISO 4217 code, e.g. USD. Null means plain number mode.
fractionDigits currency default Force a fixed number of fraction digits.
allowNegative true Accept a leading sign and negative values.
min / max none Inclusive bounds; out-of-range edits are rejected.
symbolPosition locale default Override SymbolPosition.prefix / suffix.
groupingEnabled true Toggle grouping separators.
currencySymbol locale default Override the symbol glyph.
const MoneyConfig(
  locale: 'en-US',
  currency: 'USD',
  max: null,             // pass a MoneyValue to cap input
  groupingEnabled: true,
)

Extending #

Behaviour is pluggable through the MoneyFormatter interface. The default IntlMoneyFormatter is backed by package:intl; implement your own to change formatting, parsing, or edit handling, and pass it to any of the field, the controller, or the formatter:

class MyFormatter implements MoneyFormatter {
  // format / parse / applyEdit ...
}

MoneyField(formatter: const MyFormatter());

Additional information #

Issues and pull requests are welcome at https://github.com/NadeemIqbal/locale_money_field. See the example/ app for a runnable demo that types across several locales.

0
likes
160
points
14
downloads
screenshot

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Locale-aware money and number input for Flutter with a precision-safe value model and a significant-character caret that never jumps on mid-string edits.

Repository (GitHub)
View/report issues

Topics

#money #currency #input #formatter #intl

License

Apache-2.0 (license)

Dependencies

flutter, intl

More

Packages that depend on locale_money_field