Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 48 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,23 @@

A .NET library that converts currency values into words in Bulgarian for accounting purposes.

Example: Input: `32048.27` Outpud: `тридесет и две хиляди и четиридесет и осем лева и 27 ст.`
Example BGN: Input: `32048.27` Output: `тридесет и две хиляди и четиридесет и осем лева и 27 ст.`
Example EUR: Input: `32048.27` Output: `тридесет и две хиляди и четиридесет и осем евро и 27 ц.`

## Functionality
- It takes into consideration the [grammatical gender](https://en.wikipedia.org/wiki/Grammatical_gender).
- It supports negative values.
- It writes decimal fractions in the short form: `X лева и ст.` when the value is above zero, and the full word when it is under the value of `1`: `девет стотинки`.
- The current maximum value is `999999.99` and the minimum is `0.`.
- The current maximum value is `999999.99` and the minimum is `-999999.99`.
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README states that the maximum supported value is 999999.99, but the code only handles numbers less than 100000 (line 14). Numbers between 100000 and 999999 will return "Числото е твърде голямо" (the number is too large). Either update the README to reflect the actual maximum of 99999.99, or implement support for numbers up to 999999.99.

Suggested change
- The current maximum value is `999999.99` and the minimum is `-999999.99`.
- The current maximum value is `99999.99` and the minimum is `-99999.99`.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


## Supported currencies

The library supports the following currencies through predefined descriptors:

| Currency | Code | Major Unit | Minor Unit | Usage |
|----------|------|------------|------------|-------|
| Bulgarian Lev | BGN | лев/лева | стотинка/стотинки | `CurrencyDescriptor.Bgn` |
| Euro | EUR | евро | евроцент/евроцента | `CurrencyDescriptor.Euro` |

## AI Story
This project is my first attempt to build something with GitHub Copilot, with as little intervention as possible.
Expand All @@ -31,8 +42,28 @@ Or via the .NET Core command line interface:
dotnet add package OneBitSoftware.Slovom
```

## Usage

To use the library, call the `NumbersToWords.Convert` method, passing the amount and the desired currency descriptor.

```csharp
using OneBitSoftware.Slovom;
using OneBitSoftware.Slovom.Currencies;

// Convert BGN
decimal amountBgn = 1234.56m;
string resultBgn = NumbersToWords.Convert(amountBgn, CurrencyDescriptor.Bgn);
// Result: "хиляда двеста тридесет и четири лева и 56 ст."

// Convert EUR
decimal amountEur = 1234.56m;
string resultEur = NumbersToWords.Convert(amountEur, CurrencyDescriptor.Euro);
// Result: "хиляда двеста тридесет и четири евро и 56 ц."
```

## Examples
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README does not include a code usage example showing how to call the Convert method with the required CurrencyDescriptor parameter. Add a usage section with code examples like: NumbersToWords.Convert(32048.27m, CurrencyDescriptor.Bgn) or NumbersToWords.Convert(32048.27m, CurrencyDescriptor.Euro).

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


## BGN examples
|Input|Output|
|--------|-------|
|0|нула лева|
Expand All @@ -46,6 +77,21 @@ dotnet add package OneBitSoftware.Slovom
|2014.78|две хиляди и четиринадесет лева и 78 ст.|
|32478.27|тридесет и две хиляди четиристотин седемдесет и осем лева и 27 ст.|


## EURO examples
|Input| Output |
|--------|-------------------------------------------------------------------|
|0| нула евро |
|1| едно евро |
|2| две евро |
|19| деветнадесет евро |
|0.1| десет евроцента |
|1.20| едно евро и 20 ц. |
|1019.78| хиляда и деветнадесет евро и 78 ц. |
|1119.78| хиляда сто и деветнадесет евро и 78 ц. |
|2014.78| две хиляди и четиринадесет евро и 78 ц. |
|32478.27| тридесет и две хиляди четиристотин седемдесет и осем евро и 27 ц. |

## Contributing
Feel free to raise a PR to improve the code quality or add new features.

Expand Down
82 changes: 82 additions & 0 deletions src/OneBitSoftware.Slovom/Currencies/CurrencyDescriptor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
namespace OneBitSoftware.Slovom.Currencies;

/// <summary>
/// Represents a descriptor for a currency, providing information about major and minor currency units
/// in both singular and plural forms, as well as an abbreviated symbol for minor currency units.
/// </summary>
public sealed record CurrencyDescriptor
{
private CurrencyDescriptor() { }

/// <summary>
/// Gets the singular form of the major currency unit.
/// </summary>
public required string MajorCurrencyUnitSingular { get; init; }

/// <summary>
/// Gets the plural form of the major currency unit.
/// </summary>
public required string MajorCurrencyUnitPlural { get; init; }

/// <summary>
/// Gets the plural form of the minor currency unit.
/// </summary>
public required string MinorCurrencyUnitPlural { get; init; }

/// <summary>
/// Gets the singular form of the minor currency unit.
/// </summary>
public required string MinorCurrencyUnitSingular { get; init; }

/// <summary>
/// Gets the abbreviated form of the minor currency unit.
/// </summary>
public required string MinorCurrencyUnitAbbreviated { get; init; }

/// <summary>
/// Gets the vocabulary containing word representations for numbers and units in a specific language or currency context.
/// </summary>
public required NumberWordsVocabulary Vocabulary { get; init; }

/// <summary>
/// Gets the currency descriptor for Bulgarian Lev (BGN).
/// </summary>
public static CurrencyDescriptor Bgn => new()
{
MajorCurrencyUnitSingular = " лев",
MajorCurrencyUnitPlural = " лева",
MinorCurrencyUnitPlural = " стотинки",
MinorCurrencyUnitSingular = " стотинка",
MinorCurrencyUnitAbbreviated = "ст.",
Vocabulary = new NumberWordsVocabulary
{
MinorCurrencyUnitSingular = "една",
NumbersZeroToNineteen = ["нула", "един", "два", "три", "четири", "пет", "шест", "седем", "осем", "девет", "десет", "единадесет", "дванадесет", "тринадесет", "четиринадесет", "петнадесет", "шестнадесет", "седемнадесет", "осемнадесет", "деветнадесет"],
SingleDigitsNeutral = ["нула", "едно", "две", "три", "четири", "пет", "шест", "седем", "осем", "девет"],
NumbersTenToNineteen = ["десет", "единадесет", "дванадесет", "тринадесет", "четиринадесет", "петнадесет", "шестнадесет", "седемнадесет", "осемнадесет", "деветнадесет"],
TensMultiples = ["", "десет", "двадесет", "тридесет", "четиридесет", "петдесет", "шестдесет", "седемдесет", "осемдесет", "деветдесет"],
HundredsMultiples = ["", "сто", "двеста", "триста", "четиристотин", "петстотин", "шестстотин", "седемстотин", "осемстотин", "деветстотин"]
}
};

/// <summary>
/// Gets the currency descriptor for Euro (EUR).
/// </summary>
public static CurrencyDescriptor Euro => new()
{
MajorCurrencyUnitSingular = " евро",
MajorCurrencyUnitPlural = " евро",
MinorCurrencyUnitPlural = " евроцента",
MinorCurrencyUnitSingular = " евроцент",
MinorCurrencyUnitAbbreviated = "ц.",
Vocabulary = new NumberWordsVocabulary
{
MinorCurrencyUnitSingular = "един",
NumbersZeroToNineteen = ["нула", "едно", "две", "три", "четири", "пет", "шест", "седем", "осем", "девет", "десет", "единадесет", "дванадесет", "тринадесет", "четиринадесет", "петнадесет", "шестнадесет", "седемнадесет", "осемнадесет", "деветнадесет"],
SingleDigitsNeutral = ["нула", "едно", "две", "три", "четири", "пет", "шест", "седем", "осем", "девет"],
NumbersTenToNineteen = ["десет", "единадесет", "дванадесет", "тринадесет", "четиринадесет", "петнадесет", "шестнадесет", "седемнадесет", "осемнадесет", "деветнадесет"],
TensMultiples = ["", "десет", "двадесет", "тридесет", "четиридесет", "петдесет", "шестдесет", "седемдесет", "осемдесет", "деветдесет"],
HundredsMultiples = ["", "сто", "двеста", "триста", "четиристотин", "петстотин", "шестстотин", "седемстотин", "осемстотин", "деветстотин"]
}
};
}
44 changes: 44 additions & 0 deletions src/OneBitSoftware.Slovom/Currencies/NumberWordsVocabulary.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
namespace OneBitSoftware.Slovom.Currencies;

/// <summary>
/// Represents a vocabulary collection for converting numbers and currency into words.
/// </summary>
/// <remarks>
/// This class defines the language-specific words used for numbers, single digits, tens,
/// hundreds, and numbers between zero and nineteen. It is intended to support currency and
/// numeric transformation into word representations.
/// </remarks>
public sealed record NumberWordsVocabulary
{
internal NumberWordsVocabulary() { }

/// <summary>
/// Gets or inits the word representation for the singular form of the minor currency unit.
/// </summary>
public required string MinorCurrencyUnitSingular { get; init; }

/// <summary>
/// Gets or inits the words for numbers from zero to nineteen.
/// </summary>
public required string[] NumbersZeroToNineteen { get; init; }

/// <summary>
/// Gets or inits the words for single digits in neutral form.
/// </summary>
public required string[] SingleDigitsNeutral { get; init; }

/// <summary>
/// Gets or inits the words for numbers from ten to nineteen.
/// </summary>
public required string[] NumbersTenToNineteen { get; init; }

/// <summary>
/// Gets or inits the words for multiples of ten.
/// </summary>
public required string[] TensMultiples { get; init; }

/// <summary>
/// Gets or inits the words for multiples of a hundred.
/// </summary>
public required string[] HundredsMultiples { get; init; }
}
Loading