I hope you will consider this one even if I introduce the locale here...
Using intl package
Here's what I've done to achieve currency formatting in my program before:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
class CurrencyTest extends StatefulWidget {
const CurrencyTest({super.key});
@override
State<CurrencyTest> createState() => _CurrencyTestState();
}
class _CurrencyTestState extends State<CurrencyTest> {
final NumberFormat _dollarCurrency =
NumberFormat.simpleCurrency(locale: 'en_US', decimalDigits: 2);
final NumberFormat _euroCurrency =
NumberFormat.simpleCurrency(locale: 'de-DE', decimalDigits: 2);
final _dollar = TextEditingController();
final _euro = TextEditingController();
double _dollarValue = 0.00;
double _euroValue = 0.00;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Currency Test'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(_dollarCurrency.format(_dollarValue)),
TextFormField(
controller: _dollar,
),
ElevatedButton(
onPressed: () {
setState(() {
_dollarValue = double.parse(_dollar.text);
});
},
child: Text('Format Dollar')),
SizedBox(
height: 8.0,
),
Divider(),
SizedBox(
height: 8.0,
),
Text(_euroCurrency.format(_euroValue)),
TextFormField(
controller: _euro,
),
ElevatedButton(
onPressed: () {
setState(() {
_euroValue = double.parse(_euro.text);
});
},
child: Text('Format Euro')),
],
)),
);
}
}
This is the output from the given code snippet:

However, if you have any other currency symbols to use in your project, you may find it difficult to represent some of the currency symbols. The root cause is the font limitations.
According to my research, Noto Sans font is one of the best examples that has a wide range of currency
symbol compatibility.
But for me, I did it in a way to achieve more currency range compatibility.
Here's what I've done to achieve the solution against the possible given case issues:
I download and integrate the font into my project's assets:

Of course, I added it in pubspec.yaml file:
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
assets:
- assets/
- assets/images/
fonts: #Popularity based on total views as of 10/15/2024 from Google fonts
- family: roboto #Christian Robertson designer; #27,862,326,785,287 total views
fonts:
- asset: assets/fonts/Roboto-Regular.ttf
- family: open-sans #Steve Matteson designer; #15,397,682,424,627 total views
fonts:
- asset: assets/fonts/OpenSans-Regular.ttf
- family: lato #Łukasz Dziedzic designer; #4,283,458,136,657 total views
fonts:
- asset: assets/fonts/Lato-Regular.ttf
- family: montserrat #Julieta Ulanovsky, Sol Matas, Juan Pablo del Peral, Jacques Le Bailly designer; #3,270,167,111,315 total views
fonts:
- asset: assets/fonts/Montserrat-Regular.ttf
- family: roboto-condensed #Christian Robertson designer; #2,222,596,609,812 total views
fonts:
- asset: assets/fonts/RobotoCondensed-Regular.ttf
- family: oswald #Vernon Adams, Kalapi Gajjar, Cyreal designer; #2,015,317,760,078 total views
fonts:
- asset: assets/fonts/Oswald-Regular.ttf
- family: poppins #Indian Type Foundry, Jonny Pinhorn, Ninad Kale designer; #1,581,285,338,851 total views
fonts:
- asset: assets/fonts/Poppins-Regular.ttf
- family: slabo-27px #John Hudson designer; #1,093,631,502,304 total views
fonts:
- asset: assets/fonts/Slabo27px-Regular.ttf
- family: noto-sans #Google designer; #899,099,900,620 total views
fonts:
- asset: assets/fonts/NotoSans-Regular.ttf
- family: roboto-mono #Christian Robertson designer; #896,237,217,528 total views
fonts:
- asset: assets/fonts/RobotoMono-Regular.ttf
- family: merriweather #Sorkin Type designer; #768,745,849,669 total views
fonts:
- asset: assets/fonts/Merriweather-Regular.ttf
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/to/asset-from-package
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/to/font-from-package
I've included the comments from it to serve as guidelines.
Then, I've applied the added fonts based on my use-case conditions.
If I am using these configurations in my main.dart file,
themeMode: ThemeMode.system,
theme: lightTheme, // Light theme
darkTheme: darkTheme, // Dark theme
So I set this up (in my case, I use roboto in fontFamily property):
final ThemeData lightTheme = ThemeData(
fontFamily: 'roboto',
fontFamilyFallback: const [
'lato',
'montserrat',
'roboto-condensed',
'noto-sans',
'merriweather'
],
useMaterial3: true,
// other theme data
);
final ThemeData darkTheme = ThemeData(
fontFamily: 'roboto',
fontFamilyFallback: const [
'lato',
'montserrat',
'roboto-condensed',
'noto-sans',
'merriweather'
],
useMaterial3: true,
// other theme data
);
Or if I want to directly apply the font in the parent widget:
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
fontFamily: 'roboto',
fontFamilyFallback: const [
'lato',
'montserrat',
'roboto-condensed',
'noto-sans',
'merriweather'
],
),
home: Scaffold(
appBar: AppBar(
title: Text('Currency Test'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(_dollarCurrency.format(_dollarValue)),
TextFormField(
controller: _dollar,
),
ElevatedButton(
onPressed: () {
setState(() {
_dollarValue = double.parse(_dollar.text);
});
},
child: Text('Format Dollar')),
SizedBox(
height: 8.0,
),
Divider(),
SizedBox(
height: 8.0,
),
Text(_euroCurrency.format(_euroValue)),
TextFormField(
controller: _euro,
),
ElevatedButton(
onPressed: () {
setState(() {
_euroValue = double.parse(_euro.text);
});
},
child: Text('Format Euro')),
],
)),
),
);
}
For simplified removal of the leading and trailing currency symbols:
for dollar:
setState(() {
_dollarValue = double.parse(_dollar.text);
debugPrint('Dollar: ${_dollarCurrency.format(_dollarValue).replaceAll('\$', '')}'); // using of replaceAll
debugPrint('Dollar: ${_dollarCurrency.format(_dollarValue).substring(1)}'); // using of substring for dollar
});
for euro:
setState(() {
_euroValue = double.parse(_euro.text);
debugPrint(
'Euro: ${_euroCurrency.format(_euroValue).replaceAll('€', '')}'); // using of replaceAll
debugPrint(
'Euro: ${_euroCurrency.format(_euroValue).substring(0, _euroCurrency.format(_euroValue).length - 1)}'); // using of substring for euro
});
I am hoping that you could use these guidelines to support your debugging process.
I hope it helps!
font limitation