-
Notifications
You must be signed in to change notification settings - Fork 0
Support for the euro currency #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
TonyTroeff
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that the documentation and tests are thorough!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request adds support for multiple currencies (BGN and EUR) and negative values to the number-to-words conversion library. The implementation introduces a currency descriptor pattern with vocabulary abstraction, replacing the previous hardcoded BGN-only approach.
Changes:
- Added multi-currency support through
CurrencyDescriptorandNumberWordsVocabularyclasses with built-in support for BGN and EUR - Implemented negative number handling with "Минус" prefix
- Refactored the
Convertmethod to accept aCurrencyDescriptorparameter (breaking API change)
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| src/OneBitSoftware.Slovom/Currencies/CurrencyDescriptor.cs | New file defining currency descriptors for BGN and EUR with gender-specific vocabularies |
| src/OneBitSoftware.Slovom/Currencies/NumberWordsVocabulary.cs | New file defining the vocabulary structure for number-to-word conversions |
| src/OneBitSoftware.Slovom/NumbersToWords.cs | Refactored to use currency descriptors and vocabularies; added negative number support |
| src/Tests/ConvertTests.cs | Added comprehensive test cases for BGN, EUR, and negative values |
| src/OneBitSoftware.Slovom/OneBitSoftware.Slovom.csproj | Version bumped from 1.1.0 to 1.2.0 |
| README.md | Updated with EUR examples, negative value support documentation, and corrected maximum value |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| [Theory] | ||
| [InlineData(-100000)] | ||
| public void Convert_WithNumberLessThanNegativeLimit_ShouldThrowArgumentOutOfRangeException(decimal number) | ||
| { | ||
| Assert.Throws<ArgumentOutOfRangeException>(() => NumbersToWords.Convert(number, CurrencyDescriptor.Bgn)); | ||
| Assert.Throws<ArgumentOutOfRangeException>(() => NumbersToWords.Convert(number, CurrencyDescriptor.Euro)); | ||
| } |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test suite only validates the lower bound exception (-100000) but does not test for the upper bound. Add a test case to verify that values above the maximum supported value (99999.99 or 999999.99) throw an ArgumentOutOfRangeException.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| dotnet add package OneBitSoftware.Slovom | ||
| ``` | ||
|
|
||
| ## Examples |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
|
||
| if (number == 1 && stotinki == 0) return under20[leva] + AppendLvMale; // един лев | ||
| var leva = (int)number; | ||
| var stotinki = (int)((number % 1.0m) * 100); |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable name 'stotinki' is specific to Bulgarian Lev currency (стотинки = cents in BGN), but this method now handles multiple currencies including Euro which uses евроценти. Consider renaming to a more generic name like 'minorUnit', 'fractionalPart', or 'cents' to better reflect its purpose across different currencies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| if (number == 1 && stotinki == 0) return AppendNegativePrefix(currencyDescriptor.Vocabulary.NumbersZeroToNineteen[leva] + currencyDescriptor.MajorCurrencyUnitSingular, isNegativeNumber); // един лев, едно евро | ||
|
|
||
| string stotinkiWords; | ||
| var levaWords = leva != 1 ? ConvertWholeNumber(leva, currencyDescriptor.Vocabulary) + currencyDescriptor.MajorCurrencyUnitPlural : currencyDescriptor.Vocabulary.NumbersZeroToNineteen[leva] + currencyDescriptor.MajorCurrencyUnitSingular; |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable name 'levaWords' is specific to Bulgarian Lev currency but this method now handles multiple currencies. Consider renaming to 'majorUnitWords' or 'wholePartWords' to better reflect its purpose across different currencies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| number = Math.Abs(number); // Convert negative number to positive | ||
| public static string Convert(decimal number, CurrencyDescriptor currencyDescriptor) | ||
| { | ||
| if (number < -99999.99m) throw new ArgumentOutOfRangeException(nameof(number), "Входното число не може да бъде по-малко от -99999.99"); |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The validation only checks for numbers less than -99999.99 but does not validate the upper bound. According to the README, the maximum supported value is 999999.99. Add validation to ensure the number is not greater than 99999.99 (or 999999.99 if that's the intended limit). Without this, values above the supported range will either produce incorrect results or potentially cause runtime errors.
| if (number < -99999.99m) throw new ArgumentOutOfRangeException(nameof(number), "Входното число не може да бъде по-малко от -99999.99"); | |
| if (number < -99999.99m || number > 99999.99m) | |
| throw new ArgumentOutOfRangeException(nameof(number), "Входното число трябва да бъде в интервала [-99999.99; 99999.99]"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| - 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`. |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
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.
| - 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`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| [InlineData(-1001, "Минус хиляда и един лева")] | ||
| [InlineData(-2000, "Минус две хиляди лева")] | ||
| [InlineData(-10000, "Минус десет хиляди лева")] | ||
| [InlineData(-21000, "Минус двадесет и една хиляди и нула лева")] |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The expected output "Минус двадесет и една хиляди и нула лева" includes "и нула лева" (and zero leva), which is grammatically awkward in Bulgarian. When the remainder after thousands is zero, the output should just be "Минус двадесет и една хиляди лева" without the "и нула" part. This issue occurs in the TensOfThousands method when b == 1 and e == 0 (line 100 in NumbersToWords.cs).
| [InlineData(-21000, "Минус двадесет и една хиляди и нула лева")] | |
| [InlineData(-21000, "Минус двадесет и една хиляди лева")] |
| number = Math.Abs(number); // Convert negative number to positive | ||
|
|
||
| if (number == 1 && stotinki == 0) return under20[leva] + AppendLvMale; // един лев | ||
| var leva = (int)number; |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable name 'leva' is specific to Bulgarian Lev currency, but this method now handles multiple currencies including Euro. Consider renaming to a more generic name like 'majorUnit', 'wholePart', or 'integerPart' to better reflect its purpose across different currencies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
This pull request introduces support for multiple currencies (specifically BGN and EUR) and negative values in the number-to-words conversion library. It refactors the codebase to use currency descriptors and vocabularies, making the system extensible and easier to maintain. The documentation and tests are updated to reflect these new features.
Major new features:
CurrencyDescriptorandNumberWordsVocabularyclasses, with built-in descriptors for Bulgarian Lev (BGN) and Euro (EUR). (src/OneBitSoftware.Slovom/Currencies/CurrencyDescriptor.cs,src/OneBitSoftware.Slovom/Currencies/NumberWordsVocabulary.cs) [1] [2]NumbersToWords.Convertmethod now accepts aCurrencyDescriptorparameter, enabling conversion for different currencies and supporting negative values. (src/OneBitSoftware.Slovom/NumbersToWords.cs)Documentation updates:
README.mdto document support for negative values, multiple currencies, and to provide example tables for both BGN and EUR conversions. (README.md) [1] [2] [3]Code and test improvements:
src/OneBitSoftware.Slovom/NumbersToWords.cs) [1] [2]src/Tests/ConvertTests.cs)1.2.0to reflect the new features. (src/OneBitSoftware.Slovom/OneBitSoftware.Slovom.csproj)