Tawfir.Tafqit 1.1.2

dotnet add package Tawfir.Tafqit --version 1.1.2
                    
NuGet\Install-Package Tawfir.Tafqit -Version 1.1.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Tawfir.Tafqit" Version="1.1.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Tawfir.Tafqit" Version="1.1.2" />
                    
Directory.Packages.props
<PackageReference Include="Tawfir.Tafqit" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Tawfir.Tafqit --version 1.1.2
                    
#r "nuget: Tawfir.Tafqit, 1.1.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Tawfir.Tafqit@1.1.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Tawfir.Tafqit&version=1.1.2
                    
Install as a Cake Addin
#tool nuget:?package=Tawfir.Tafqit&version=1.1.2
                    
Install as a Cake Tool

Tawfir.Tafqit

تفقيط — Numbers, money amounts, and ages in words, with correct Arabic grammar.

NuGet Downloads .NET 10 Languages Currencies License

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

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: ToWords and ToAge. 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.00 has 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.005 SAR → ريال سعودي واحد وهللة واحدة
  • A zero main part is left out: 0.13 SAR → ثلاث عشرة هللةً
  • A zero minor part is left out: 15000.00 SAR → خمسة عشر ألف ريال سعودي
  • 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 فلس)
  • Fraction is padded to the currency's decimal places: 154.005 BHD → و005/1000, 0.05 SAR → 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 to asOf (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; asOf defaults 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, throws ArgumentOutOfRangeException

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; TargetFramework net10.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.txt in the package for the full terms

Support and Contact

Questions, bugs, a new currency or language, or custom work — get in touch:

Email Website WhatsApp KSA WhatsApp Bahrain WhatsApp Egypt

Channel Details
📧 Email 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • 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.

Version Downloads Last Updated
1.1.2 47 10/27/2026
1.1.1 58 10/27/2026
1.0.3 58 10/27/2026
1.0.2 50 10/27/2026

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.