Tawfir.Tafqit
1.1.2
dotnet add package Tawfir.Tafqit --version 1.1.2
NuGet\Install-Package Tawfir.Tafqit -Version 1.1.2
<PackageReference Include="Tawfir.Tafqit" Version="1.1.2" />
<PackageVersion Include="Tawfir.Tafqit" Version="1.1.2" />
<PackageReference Include="Tawfir.Tafqit" />
paket add Tawfir.Tafqit --version 1.1.2
#r "nuget: Tawfir.Tafqit, 1.1.2"
#:package Tawfir.Tafqit@1.1.2
#addin nuget:?package=Tawfir.Tafqit&version=1.1.2
#tool nuget:?package=Tawfir.Tafqit&version=1.1.2
Tawfir.Tafqit
تفقيط — Numbers, money amounts, and ages in words, with correct Arabic grammar.
Turn 1234.50 into ألف ومائتان وأربعة وثلاثون ريالاً سعودياً وخمسون هللةً — for invoices, receipts, cheques, contracts, and HR letters across the GCC and Egypt. Arabic by default, plus English, Persian, and Turkish.
TafqitConverter.ToWords(1234.50m, TafqitCurrency.Sar);
// ألف ومائتان وأربعة وثلاثون ريالاً سعودياً وخمسون هللةً
Contents
- Installation
- Quick Start
- Features
- Which Method Do I Need?
- Plain Numbers
- Currency Amounts
- Age
- All Languages at a Glance
- Common Use Cases
- Arabic Grammar Handled for You
- Error Handling
- API Reference
- FAQ
- Requirements
- License
- Support and Contact
Installation
dotnet add package Tawfir.Tafqit
Or in Visual Studio: Manage NuGet Packages → search for Tawfir.Tafqit → Install.
Quick Start
using Tawfir.Tafqit;
string words = TafqitConverter.ToWords(1234); // ألف ومائتان وأربعة وثلاثون
string amount = TafqitConverter.ToWords(1234.50m, TafqitCurrency.Sar); // ألف ومائتان وأربعة وثلاثون ريالاً سعودياً وخمسون هللةً
string age = TafqitConverter.ToAge(25, 3, 2); // خمسة وعشرون عاماً وثلاثة أشهر ويومان
💡 Everything is in one static class,
TafqitConverter, with two methods:ToWordsandToAge. No setup, no dependency injection, no configuration.
Features
| Feature | What you get | |
|---|---|---|
| 🔢 | Plain numbers | Any long or decimal, including negatives and decimal fractions |
| 💰 | Currency amounts | SAR, AED, BHD, KWD, OMR, QAR, and EGP with their correct minor units |
| 🧾 | Formal closing | فقط … لا غير for cheques and official documents |
| 🎂 | Age | From years/months/days, or calculated from a date of birth |
| 🌍 | Four languages | Arabic (default), English, Persian, and Turkish |
| ✍️ | Correct Arabic grammar | Gender agreement, dual, plural for 3–10, accusative for 11–99, thousands and millions |
| 🎯 | Precise | decimal and big-integer arithmetic — no floating-point rounding errors, up to decimal.MaxValue |
| 🌐 | Culture-safe | Output never depends on the server's culture or regional settings |
| 🧵 | Thread-safe | Static and stateless — call it from anywhere, in parallel |
| 💡 | IntelliSense | Every public method, parameter, and enum value is documented in your IDE |
| 📦 | No dependencies | Pure .NET, nothing else to install |
Which Method Do I Need?
| I want to… | Use | Example | Result |
|---|---|---|---|
| Spell a number | ToWords(number) |
ToWords(21) |
واحد وعشرون |
| Spell a number in another language | ToWords(number, language) |
ToWords(21, TafqitLanguage.English) |
twenty-one |
| Spell a money amount | ToWords(amount, currency) |
ToWords(11m, TafqitCurrency.Sar) |
أحد عشر ريالاً سعودياً |
| Write the amount on a cheque | ToWords(amount, currency, formalClosing: true) |
ToWords(1m, TafqitCurrency.Sar, formalClosing: true) |
فقط ريال سعودي واحد لا غير |
| Choose the layout (currency name, fils as digits or a fraction) | ToWords(amount, currency, options) |
ToWords(1.5m, TafqitCurrency.Sar, new TafqitMoneyOptions { MinorUnits = TafqitMinorUnitStyle.Digits }) |
ريال سعودي واحد و50 هللةً |
| Spell an age | ToAge(years, months, days) |
ToAge(25, 3, 2) |
خمسة وعشرون عاماً وثلاثة أشهر ويومان |
| Spell an age from a birth date | ToAge(dateOfBirth) |
ToAge(new DateOnly(2000, 1, 15)) |
(age as of today) |
Plain Numbers
Use ToWords with a long or decimal to spell a number with no currency or unit.
using Tawfir.Tafqit;
TafqitConverter.ToWords(21); // واحد وعشرون
TafqitConverter.ToWords(1234); // ألف ومائتان وأربعة وثلاثون
TafqitConverter.ToWords(11000); // أحد عشر ألفاً
TafqitConverter.ToWords(15500); // خمسة عشر ألفاً وخمسمائة
TafqitConverter.ToWords(103000); // مائة وثلاثة آلاف
TafqitConverter.ToWords(1000000); // مليون
TafqitConverter.ToWords(-21); // سالب واحد وعشرون
TafqitConverter.ToWords(12.04m); // اثنا عشر فاصلة صفر أربعة
TafqitConverter.ToWords(12.00m); // اثنا عشر
In other languages — pass a TafqitLanguage:
TafqitConverter.ToWords(1234, TafqitLanguage.English); // one thousand two hundred and thirty-four
TafqitConverter.ToWords(1234, TafqitLanguage.Persian); // هزار و دویست و سی و چهار
TafqitConverter.ToWords(1234, TafqitLanguage.Turkish); // bin iki yüz otuz dört
TafqitConverter.ToWords(12.04m, TafqitLanguage.English); // twelve point zero four
📌 Rules
- Digits after the decimal point are read one by one:
12.04→ twelve point zero four - A whole value such as
12.00has no decimal part - English uses British style: one hundred and five
| Language | Decimal word | Negative word |
|---|---|---|
| Arabic | فاصلة | سالب |
| English | point | minus |
| Persian | ممیز | منفی |
| Turkish | virgül | eksi |
Currency Amounts
Use ToWords with a TafqitCurrency to spell an amount with its main and minor units.
using Tawfir.Tafqit;
TafqitConverter.ToWords(1m, TafqitCurrency.Sar); // ريال سعودي واحد
TafqitConverter.ToWords(2m, TafqitCurrency.Sar); // ريالان سعوديان
TafqitConverter.ToWords(5m, TafqitCurrency.Sar); // خمسة ريالات سعودية
TafqitConverter.ToWords(11m, TafqitCurrency.Sar); // أحد عشر ريالاً سعودياً
TafqitConverter.ToWords(15000m, TafqitCurrency.Sar); // خمسة عشر ألف ريال سعودي
TafqitConverter.ToWords(1234.50m, TafqitCurrency.Sar); // ألف ومائتان وأربعة وثلاثون ريالاً سعودياً وخمسون هللةً
TafqitConverter.ToWords(0.13m, TafqitCurrency.Sar); // ثلاث عشرة هللةً
TafqitConverter.ToWords(1.250m, TafqitCurrency.Bhd); // دينار بحريني واحد ومائتان وخمسون فلساً
TafqitConverter.ToWords(0.750m, TafqitCurrency.Kwd); // سبعمائة وخمسون فلساً
Supported Currencies
| Currency | Enum value | Arabic | Minor unit | Decimals | |
|---|---|---|---|---|---|
| 🇸🇦 | Saudi riyal | TafqitCurrency.Sar |
ريال سعودي | هللة · halala | 2 |
| 🇦🇪 | UAE dirham | TafqitCurrency.Aed |
درهم إماراتي | فلس · fils | 2 |
| 🇧🇭 | Bahraini dinar | TafqitCurrency.Bhd |
دينار بحريني | فلس · fils | 3 |
| 🇰🇼 | Kuwaiti dinar | TafqitCurrency.Kwd |
دينار كويتي | فلس · fils | 3 |
| 🇴🇲 | Omani rial | TafqitCurrency.Omr |
ريال عماني | بيسة · baisa | 3 |
| 🇶🇦 | Qatari riyal | TafqitCurrency.Qar |
ريال قطري | درهم · dirham | 2 |
| 🇪🇬 | Egyptian pound | TafqitCurrency.Egp |
جنيه مصري | قرش · piastre | 2 |
Formal Closing for Cheques and Official Documents
Set formalClosing: true to wrap the amount in the standard closing phrase:
TafqitConverter.ToWords(1234.50m, TafqitCurrency.Sar, formalClosing: true);
// فقط ألف ومائتان وأربعة وثلاثون ريالاً سعودياً وخمسون هللةً لا غير
TafqitConverter.ToWords(1234.50m, TafqitCurrency.Sar, TafqitLanguage.English, formalClosing: true);
// one thousand two hundred and thirty-four Saudi riyals and fifty halalas only
| Language | Format | Example |
|---|---|---|
| Arabic | فقط … لا غير | فقط ريال سعودي واحد لا غير |
| English | … only | one Saudi riyal only |
| Persian | فقط … لاغیر | فقط یک ریال سعودی لاغیر |
| Turkish | yalnız … | yalnız bir Suudi riyali |
📌 Rules
- The minor unit is rounded to the currency's decimal places (midpoint away from zero):
1.005SAR → ريال سعودي واحد وهللة واحدة - A zero main part is left out:
0.13SAR → ثلاث عشرة هللةً - A zero minor part is left out:
15000.00SAR → خمسة عشر ألف ريال سعودي - A negative amount throws
ArgumentOutOfRangeException— an amount in words should never be negative
Choosing the Layout: Currency Name, Minor Unit, Closing
Pass a TafqitMoneyOptions to decide how the amount looks — for example from a per-company or per-invoice-type setting:
var options = new TafqitMoneyOptions
{
Language = TafqitLanguage.Arabic, // default
IncludeCurrency = true, // default: write ريال / دينار and هللة / فلس
MinorUnits = TafqitMinorUnitStyle.Digits, // Words (default), Digits, or Fraction
FormalClosing = false, // default
};
TafqitConverter.ToWords(154.212m, TafqitCurrency.Bhd, options);
// مائة وأربعة وخمسون ديناراً بحرينياً و212 فلساً
| Options | 154.212 BHD |
|---|---|
(defaults) — MinorUnits = Words |
مائة وأربعة وخمسون ديناراً بحرينياً ومائتان واثنا عشر فلساً |
MinorUnits = Digits |
مائة وأربعة وخمسون ديناراً بحرينياً و212 فلساً |
MinorUnits = Fraction |
مائة وأربعة وخمسون ديناراً بحرينياً و212/1000 |
IncludeCurrency = false |
مائة وأربعة وخمسون و212/1000 |
IncludeCurrency = false, FormalClosing = true |
فقط مائة وأربعة وخمسون و212/1000 لا غير |
Language = English, MinorUnits = Digits |
one hundred and fifty-four Bahraini dinars and 212 fils |
📌 Rules
- The defaults give exactly the same text as
ToWords(amount, currency, language, formalClosing) Digits: the unit follows Arabic counting rules (5 فلوس، 12 فلساً، 212 فلساً); 1 and 2 take the singular (2 فلس)Fractionis padded to the currency's decimal places:154.005BHD → و005/1000,0.05SAR → 05/100- Without the currency name, the minor unit is always a fraction — "و212" alone would not say what it counts
Age
From Years, Months, and Days
using Tawfir.Tafqit;
TafqitConverter.ToAge(1); // عام واحد
TafqitConverter.ToAge(2); // عامان
TafqitConverter.ToAge(7); // سبعة أعوام
TafqitConverter.ToAge(25, 3, 2); // خمسة وعشرون عاماً وثلاثة أشهر ويومان
TafqitConverter.ToAge(0, 1, 0); // شهر واحد
TafqitConverter.ToAge(0, 0, 10); // عشرة أيام
TafqitConverter.ToAge(0); // أقل من يوم
From a Date of Birth
// Age as of today
string age = TafqitConverter.ToAge(new DateOnly(1990, 5, 20));
// Age as of a specific date
TafqitConverter.ToAge(new DateOnly(2000, 1, 15), asOf: new DateOnly(2026, 3, 10));
// ستة وعشرون عاماً وشهر واحد وثلاثة وعشرون يوماً
TafqitConverter.ToAge(new DateOnly(1990, 5, 20), TafqitLanguage.English, asOf: new DateOnly(2026, 10, 27));
// thirty-six years, five months, and seven days
Arabic Year Word: عام or سنة
Choose the Arabic word for "year" with yearWord. The default is عام. This option only changes Arabic output.
TafqitConverter.ToAge(7); // سبعة أعوام
TafqitConverter.ToAge(7, yearWord: TafqitYearWord.Sanah); // سبع سنوات
TafqitConverter.ToAge(25, 3, 2, yearWord: TafqitYearWord.Sanah); // خمس وعشرون سنةً وثلاثة أشهر ويومان
| Enum value | Word | 1 | 2 | 7 |
|---|---|---|---|---|
TafqitYearWord.Aam (default) |
عام | عام واحد | عامان | سبعة أعوام |
TafqitYearWord.Sanah |
سنة | سنة واحدة | سنتان | سبع سنوات |
📌 Rules
- Zero parts are left out:
ToAge(0, 1, 0)→ شهر واحد - A zero age —
ToAge(0), or a date of birth equal toasOf(a newborn) — is أقل من يوم / less than a day / کمتر از یک روز / bir günden az - Parts are spelled as given: 18 months stays eighteen months
- From a date of birth, the age is counted in completed years, months, and days;
asOfdefaults to today - Born on the 29th–31st: when that day does not exist in a month, the month is completed on its last day — born 31 January, the age on 1 March is شهر واحد ويوم واحد
- Born on 29 February: the year is completed on 28 February in non-leap years
- A negative part, or a date of birth after
asOf, throwsArgumentOutOfRangeException
All Languages at a Glance
| Arabic (default) | English | Persian | Turkish | |
|---|---|---|---|---|
| Enum | TafqitLanguage.Arabic |
TafqitLanguage.English |
TafqitLanguage.Persian |
TafqitLanguage.Turkish |
| 1234 | ألف ومائتان وأربعة وثلاثون | one thousand two hundred and thirty-four | هزار و دویست و سی و چهار | bin iki yüz otuz dört |
| 1.50 SAR | ريال سعودي واحد وخمسون هللةً | one Saudi riyal and fifty halalas | یک ریال سعودی و پنجاه هلله | bir Suudi riyali ve elli halala |
| Age 25, 3, 2 | خمسة وعشرون عاماً وثلاثة أشهر ويومان | twenty-five years, three months, and two days | بیست و پنج سال و سه ماه و دو روز | yirmi beş yıl, üç ay ve iki gün |
Common Use Cases
🧾 Invoices and receipts — amount in words
public class InvoiceModel
{
public decimal Total { get; set; }
public string TotalInWordsAr => TafqitConverter.ToWords(Total, TafqitCurrency.Sar);
public string TotalInWordsEn => TafqitConverter.ToWords(Total, TafqitCurrency.Sar, TafqitLanguage.English);
}
🏦 Cheques and payment vouchers
string chequeLine = TafqitConverter.ToWords(15000.500m, TafqitCurrency.Bhd, formalClosing: true);
// فقط خمسة عشر ألف دينار بحريني وخمسمائة فلس لا غير
📄 Contracts and HR letters — age
string age = TafqitConverter.ToAge(employee.DateOfBirth, yearWord: TafqitYearWord.Sanah);
🌍 Multilingual apps — language from the user's profile
TafqitLanguage language = user.LanguageCode switch
{
"en" => TafqitLanguage.English,
"fa" => TafqitLanguage.Persian,
"tr" => TafqitLanguage.Turkish,
_ => TafqitLanguage.Arabic
};
string text = TafqitConverter.ToWords(order.Total, TafqitCurrency.Sar, language);
Arabic Grammar Handled for You
✅ Gender agreement — the number takes the opposite gender for 3–10: خمسة ريالات, but ثلاث هللات
✅ One and two — the noun comes first for one, and the dual is used for two: ريال سعودي واحد، ريالان سعوديان
✅ Plural for 3–10 — خمسة دنانير بحرينية، ثماني سنوات
✅ Accusative for 11–99 — أحد عشر ريالاً سعودياً، ثلاث عشرة هللةً
✅ Thousands and millions — ثلاثة آلاف، أحد عشر ألفاً، مائة وثلاثة آلاف، أحد عشر مليوناً
✅ Before a noun — the scale word drops its accusative ending before the currency: خمسة عشر ألف ريال سعودي
✅ Feminine units — هللة, بيسة, and سنة take feminine numbers: إحدى عشرة سنةً، ثماني هللات
Error Handling
Invalid input always throws ArgumentOutOfRangeException — you never get an empty or partial string.
| Input | Result |
|---|---|
| Negative currency amount | ArgumentOutOfRangeException (amount) |
| Negative years, months, or days | ArgumentOutOfRangeException |
Date of birth after asOf |
ArgumentOutOfRangeException (dateOfBirth) |
Undefined enum value, e.g. (TafqitCurrency)99 |
ArgumentOutOfRangeException |
try
{
string words = TafqitConverter.ToWords(amount, TafqitCurrency.Sar);
}
catch (ArgumentOutOfRangeException ex)
{
logger.LogWarning(ex, "Cannot spell amount {Amount}", amount);
}
API Reference
namespace Tawfir.Tafqit;
public static class TafqitConverter
{
// Plain numbers
string ToWords(long number, TafqitLanguage language = TafqitLanguage.Arabic);
string ToWords(decimal number, TafqitLanguage language = TafqitLanguage.Arabic);
// Currency amounts
string ToWords(decimal amount, TafqitCurrency currency,
TafqitLanguage language = TafqitLanguage.Arabic, bool formalClosing = false);
string ToWords(decimal amount, TafqitCurrency currency, TafqitMoneyOptions options);
// Age
string ToAge(int years, int months = 0, int days = 0,
TafqitLanguage language = TafqitLanguage.Arabic, TafqitYearWord yearWord = TafqitYearWord.Aam);
string ToAge(DateOnly dateOfBirth,
TafqitLanguage language = TafqitLanguage.Arabic, TafqitYearWord yearWord = TafqitYearWord.Aam,
DateOnly? asOf = null);
}
| Enum | Values |
|---|---|
TafqitLanguage |
Arabic (default), English, Persian, Turkish |
TafqitCurrency |
Sar, Aed, Bhd, Kwd, Omr, Qar, Egp |
TafqitYearWord |
Aam — عام (default), Sanah — سنة |
TafqitMinorUnitStyle |
Words (default), Digits, Fraction |
TafqitMoneyOptions properties: Language (Arabic), IncludeCurrency (true), MinorUnits (Words), FormalClosing (false).
All types are in the Tawfir.Tafqit namespace.
FAQ
Is it free?
Yes. Tawfir.Tafqit is free to use in your own applications, including commercial ones. See License.
Does it need internet access or a database?
No. Everything runs in memory inside your application.
Can I use it from several threads at once?
Yes. TafqitConverter is static and keeps no state, so it is safe to call in parallel.
Will the output change if my server's language or region changes?
No. The output is the same on every machine and culture.
My currency or language is not listed. Can it be added?
Contact us — see Support and Contact.
Requirements
- .NET 10.0 or higher (SDK-style projects;
TargetFrameworknet10.0)
License
Proprietary — Free to Use
- ✅ Free to use in your own applications, including commercial applications
- 🔒 Closed source — decompiling, modifying, or redistributing the library on its own is not permitted
- 📄 See
LICENSE.txtin the package for the full terms
Support and Contact
Questions, bugs, a new currency or language, or custom work — get in touch:
| Channel | Details | |
|---|---|---|
| 📧 | info@waelelazizy.com | |
| 🌐 | Website | waelelazizy.com |
| 🇸🇦 | Saudi Arabia | +966 55 337 3500 · WhatsApp |
| 🇧🇭 | Bahrain | +973 3303 0730 · WhatsApp |
| 🇪🇬 | Egypt | +20 110 811 9130 · WhatsApp |
Author
Wael El Azizy — waelelazizy.com
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
1.1: TafqitMoneyOptions to choose how an amount is written: with or without the currency name, the minor unit in words, digits (212 فلساً) or as a fraction (212/1000), and the formal closing. Existing calls give the same text. 1.0: plain numbers, GCC and EGP currency amounts, and age (including date of birth) in Arabic, English, Persian, and Turkish.