worldmoneywords 2.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- worldmoneywords-2.5.0/PKG-INFO +40 -0
- worldmoneywords-2.5.0/README.md +21 -0
- worldmoneywords-2.5.0/pyproject.toml +31 -0
- worldmoneywords-2.5.0/setup.cfg +4 -0
- worldmoneywords-2.5.0/src/amount_to_words/__init__.py +3 -0
- worldmoneywords-2.5.0/src/amount_to_words/converter.py +185 -0
- worldmoneywords-2.5.0/src/amount_to_words/countries.py +2 -0
- worldmoneywords-2.5.0/src/worldmoneywords.egg-info/PKG-INFO +40 -0
- worldmoneywords-2.5.0/src/worldmoneywords.egg-info/SOURCES.txt +10 -0
- worldmoneywords-2.5.0/src/worldmoneywords.egg-info/dependency_links.txt +1 -0
- worldmoneywords-2.5.0/src/worldmoneywords.egg-info/top_level.txt +1 -0
- worldmoneywords-2.5.0/tests/test_converter.py +48 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: worldmoneywords
|
|
3
|
+
Version: 2.5.0
|
|
4
|
+
Summary: Convert monetary amounts to English, Hindi, or Arabic words using ISO country and currency codes
|
|
5
|
+
Author: Md Ikram
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/3mdikram/WorldMoneyWords
|
|
8
|
+
Project-URL: Repository, https://github.com/3mdikram/WorldMoneyWords
|
|
9
|
+
Project-URL: Issues, https://github.com/3mdikram/WorldMoneyWords/issues
|
|
10
|
+
Keywords: amount,currency,money,numbers,words,iso-3166,iso-4217
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# WorldMoneyWords for Python
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install worldmoneywords
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from amount_to_words import AmountToWords
|
|
28
|
+
|
|
29
|
+
converter = AmountToWords()
|
|
30
|
+
print(converter.convert("1234.50", "IN", "INR"))
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
An optional fourth `ConversionOptions` argument controls the suffix, zero minor units, conjunction, short currency names, and output `language` (`en`, `hi`, `ar`, or a registered language code). Set `short_currency_name=True` to output `Dollars` instead of `US Dollars`.
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
converter.convert("1234.50", "IN", "INR", ConversionOptions(language="hi"))
|
|
37
|
+
converter.convert("1234.50", "US", "USD", ConversionOptions(language="ar"))
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The arguments are amount, ISO 3166-1 Alpha-2 or Alpha-3 country code, and ISO 4217 currency code.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# WorldMoneyWords for Python
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
pip install worldmoneywords
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from amount_to_words import AmountToWords
|
|
9
|
+
|
|
10
|
+
converter = AmountToWords()
|
|
11
|
+
print(converter.convert("1234.50", "IN", "INR"))
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
An optional fourth `ConversionOptions` argument controls the suffix, zero minor units, conjunction, short currency names, and output `language` (`en`, `hi`, `ar`, or a registered language code). Set `short_currency_name=True` to output `Dollars` instead of `US Dollars`.
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
converter.convert("1234.50", "IN", "INR", ConversionOptions(language="hi"))
|
|
18
|
+
converter.convert("1234.50", "US", "USD", ConversionOptions(language="ar"))
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The arguments are amount, ISO 3166-1 Alpha-2 or Alpha-3 country code, and ISO 4217 currency code.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "worldmoneywords"
|
|
7
|
+
version = "2.5.0"
|
|
8
|
+
description = "Convert monetary amounts to English, Hindi, or Arabic words using ISO country and currency codes"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Md Ikram"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["amount", "currency", "money", "numbers", "words", "iso-3166", "iso-4217"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 5 - Production/Stable",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
22
|
+
"Topic :: Software Development :: Libraries :: Python Modules"
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Homepage = "https://github.com/3mdikram/WorldMoneyWords"
|
|
27
|
+
Repository = "https://github.com/3mdikram/WorldMoneyWords"
|
|
28
|
+
Issues = "https://github.com/3mdikram/WorldMoneyWords/issues"
|
|
29
|
+
|
|
30
|
+
[tool.setuptools.packages.find]
|
|
31
|
+
where = ["src"]
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from decimal import Decimal, InvalidOperation, ROUND_HALF_UP
|
|
3
|
+
import re
|
|
4
|
+
from typing import Callable
|
|
5
|
+
from .countries import ISO_COUNTRY_CODES
|
|
6
|
+
|
|
7
|
+
ONES = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"]
|
|
8
|
+
TENS = ["", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"]
|
|
9
|
+
SCALES = ["", "Thousand", "Million", "Billion", "Trillion", "Quadrillion"]
|
|
10
|
+
|
|
11
|
+
@dataclass(frozen=True)
|
|
12
|
+
class Currency:
|
|
13
|
+
major_singular: str
|
|
14
|
+
major_plural: str
|
|
15
|
+
minor_singular: str
|
|
16
|
+
minor_plural: str
|
|
17
|
+
fraction_digits: int = 2
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True)
|
|
20
|
+
class ConversionOptions:
|
|
21
|
+
include_only: bool = True
|
|
22
|
+
include_zero_minor: bool = False
|
|
23
|
+
conjunction: str = "and"
|
|
24
|
+
language: str = "en"
|
|
25
|
+
short_currency_name: bool = False
|
|
26
|
+
|
|
27
|
+
def __post_init__(self):
|
|
28
|
+
if not self.conjunction.strip():
|
|
29
|
+
raise ValueError("Conjunction cannot be empty")
|
|
30
|
+
if not self.language.strip():
|
|
31
|
+
raise ValueError("Language cannot be empty")
|
|
32
|
+
|
|
33
|
+
@dataclass(frozen=True)
|
|
34
|
+
class LanguagePack:
|
|
35
|
+
code: str
|
|
36
|
+
spell: Callable[[int], str]
|
|
37
|
+
currency_name: Callable[[str, bool], str]
|
|
38
|
+
minus: str
|
|
39
|
+
conjunction: str
|
|
40
|
+
only: str
|
|
41
|
+
minor_singular: str
|
|
42
|
+
minor_plural: str
|
|
43
|
+
|
|
44
|
+
def __post_init__(self):
|
|
45
|
+
normalized = self.code.strip().lower()
|
|
46
|
+
if not re.fullmatch(r"[a-z]{2,8}(?:-[a-z0-9]{2,8})*", normalized):
|
|
47
|
+
raise ValueError("Language pack code must be a valid language tag")
|
|
48
|
+
for value in (self.minus, self.conjunction, self.only, self.minor_singular, self.minor_plural):
|
|
49
|
+
if not value.strip(): raise ValueError("Language pack labels cannot be empty")
|
|
50
|
+
object.__setattr__(self, "code", normalized)
|
|
51
|
+
|
|
52
|
+
CURRENCIES = {
|
|
53
|
+
"INR": Currency("Rupee", "Rupees", "Paisa", "Paise"),
|
|
54
|
+
"USD": Currency("US Dollar", "US Dollars", "Cent", "Cents"),
|
|
55
|
+
"GBP": Currency("Pound", "Pounds", "Penny", "Pence"),
|
|
56
|
+
"EUR": Currency("Euro", "Euros", "Cent", "Cents"),
|
|
57
|
+
"AED": Currency("Dirham", "Dirhams", "Fil", "Fils"),
|
|
58
|
+
"JPY": Currency("Yen", "Yen", "", "", 0),
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
def _under_thousand(value: int) -> str:
|
|
62
|
+
words = []
|
|
63
|
+
if value >= 100:
|
|
64
|
+
words += [ONES[value // 100], "Hundred"]
|
|
65
|
+
value %= 100
|
|
66
|
+
if value >= 20:
|
|
67
|
+
words.append(TENS[value // 10])
|
|
68
|
+
if value % 10:
|
|
69
|
+
words.append(ONES[value % 10])
|
|
70
|
+
elif value:
|
|
71
|
+
words.append(ONES[value])
|
|
72
|
+
return " ".join(words)
|
|
73
|
+
|
|
74
|
+
def _spell(value: int) -> str:
|
|
75
|
+
if value == 0:
|
|
76
|
+
return "Zero"
|
|
77
|
+
chunks = []
|
|
78
|
+
scale = 0
|
|
79
|
+
while value:
|
|
80
|
+
chunk = value % 1000
|
|
81
|
+
if chunk:
|
|
82
|
+
part = _under_thousand(chunk)
|
|
83
|
+
if SCALES[scale]:
|
|
84
|
+
part += " " + SCALES[scale]
|
|
85
|
+
chunks.append(part)
|
|
86
|
+
value //= 1000
|
|
87
|
+
scale += 1
|
|
88
|
+
if scale >= len(SCALES) and value:
|
|
89
|
+
raise ValueError("Amount is outside the supported range")
|
|
90
|
+
return " ".join(reversed(chunks))
|
|
91
|
+
|
|
92
|
+
HI_0_99 = "शून्य|एक|दो|तीन|चार|पाँच|छह|सात|आठ|नौ|दस|ग्यारह|बारह|तेरह|चौदह|पन्द्रह|सोलह|सत्रह|अठारह|उन्नीस|बीस|इक्कीस|बाईस|तेईस|चौबीस|पच्चीस|छब्बीस|सत्ताईस|अट्ठाईस|उनतीस|तीस|इकतीस|बत्तीस|तैंतीस|चौंतीस|पैंतीस|छत्तीस|सैंतीस|अड़तीस|उनतालीस|चालीस|इकतालीस|बयालीस|तैंतालीस|चौवालीस|पैंतालीस|छियालीस|सैंतालीस|अड़तालीस|उनचास|पचास|इक्यावन|बावन|तिरेपन|चौवन|पचपन|छप्पन|सत्तावन|अट्ठावन|उनसठ|साठ|इकसठ|बासठ|तिरेसठ|चौंसठ|पैंसठ|छियासठ|सड़सठ|अड़सठ|उनहत्तर|सत्तर|इकहत्तर|बहत्तर|तिहत्तर|चौहत्तर|पचहत्तर|छिहत्तर|सतहत्तर|अठहत्तर|उनासी|अस्सी|इक्यासी|बयासी|तिरासी|चौरासी|पचासी|छियासी|सत्तासी|अट्ठासी|नवासी|नब्बे|इक्यानबे|बानबे|तिरानबे|चौरानबे|पंचानबे|छियानबे|सत्तानबे|अट्ठानबे|निन्यानबे".split("|")
|
|
93
|
+
AR_0_19 = "صفر|واحد|اثنان|ثلاثة|أربعة|خمسة|ستة|سبعة|ثمانية|تسعة|عشرة|أحد عشر|اثنا عشر|ثلاثة عشر|أربعة عشر|خمسة عشر|ستة عشر|سبعة عشر|ثمانية عشر|تسعة عشر".split("|")
|
|
94
|
+
AR_TENS = ["", "", "عشرون", "ثلاثون", "أربعون", "خمسون", "ستون", "سبعون", "ثمانون", "تسعون"]
|
|
95
|
+
|
|
96
|
+
def _under_100_localized(value: int, language: str) -> str:
|
|
97
|
+
if language == "hi": return HI_0_99[value]
|
|
98
|
+
if value < 20: return AR_0_19[value]
|
|
99
|
+
return AR_TENS[value // 10] if value % 10 == 0 else f"{AR_0_19[value % 10]} و{AR_TENS[value // 10]}"
|
|
100
|
+
|
|
101
|
+
def _under_1000_localized(value: int, language: str) -> str:
|
|
102
|
+
parts = []
|
|
103
|
+
if value >= 100:
|
|
104
|
+
hundreds = value // 100
|
|
105
|
+
if language == "hi": parts.append(("एक" if hundreds == 1 else HI_0_99[hundreds]) + " सौ")
|
|
106
|
+
else: parts.append({1:"مائة",2:"مائتان"}.get(hundreds, AR_0_19[hundreds] + " مائة"))
|
|
107
|
+
value %= 100
|
|
108
|
+
if value: parts.append(_under_100_localized(value, language))
|
|
109
|
+
return (" و" if language == "ar" else " ").join(parts)
|
|
110
|
+
|
|
111
|
+
def _spell_localized(value: int, language: str) -> str:
|
|
112
|
+
if language == "en": return _spell(value)
|
|
113
|
+
if value == 0: return HI_0_99[0] if language == "hi" else AR_0_19[0]
|
|
114
|
+
scales = ["", "हज़ार", "मिलियन", "बिलियन", "ट्रिलियन", "क्वाड्रिलियन"] if language == "hi" else ["", "ألف", "مليون", "مليار", "تريليون", "كوادريليون"]
|
|
115
|
+
chunks, scale = [], 0
|
|
116
|
+
while value:
|
|
117
|
+
chunk = value % 1000
|
|
118
|
+
if chunk:
|
|
119
|
+
part = "" if language == "ar" and chunk == 1 and scale > 0 else _under_1000_localized(chunk, language)
|
|
120
|
+
if scales[scale]: part = (part + " " if part else "") + scales[scale]
|
|
121
|
+
chunks.append(part)
|
|
122
|
+
value //= 1000; scale += 1
|
|
123
|
+
if scale >= len(scales) and value: raise ValueError("Amount is outside the supported range")
|
|
124
|
+
return (" و" if language == "ar" else " ").join(reversed(chunks))
|
|
125
|
+
|
|
126
|
+
LOCALIZED_CURRENCIES = {
|
|
127
|
+
"hi": {"INR":"भारतीय रुपया", "USD":"अमेरिकी डॉलर", "GBP":"ब्रिटिश पाउंड", "EUR":"यूरो", "AED":"यूएई दिरहम", "JPY":"जापानी येन"},
|
|
128
|
+
"ar": {"INR":"روبية هندية", "USD":"دولار أمريكي", "GBP":"جنيه إسترليني", "EUR":"يورو", "AED":"درهم إماراتي", "JPY":"ين ياباني"},
|
|
129
|
+
}
|
|
130
|
+
SHORT_CURRENCIES = {
|
|
131
|
+
"en": {"INR":("Rupee","Rupees"), "USD":("Dollar","Dollars"), "GBP":("Pound","Pounds"), "EUR":("Euro","Euros"), "AED":("Dirham","Dirhams"), "JPY":("Yen","Yen")},
|
|
132
|
+
"hi": {"INR":("रुपया","रुपये"), "USD":("डॉलर","डॉलर"), "GBP":("पाउंड","पाउंड"), "EUR":("यूरो","यूरो"), "AED":("दिरहम","दिरहम"), "JPY":("येन","येन")},
|
|
133
|
+
"ar": {"INR":("روبية","روبية"), "USD":("دولار","دولار"), "GBP":("جنيه","جنيه"), "EUR":("يورو","يورو"), "AED":("درهم","درهم"), "JPY":("ين","ين")},
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
class AmountToWords:
|
|
137
|
+
def __init__(self, currencies: dict[str, Currency] | None = None, language_packs: list[LanguagePack] | None = None):
|
|
138
|
+
self.currencies = {**CURRENCIES, **(currencies or {})}
|
|
139
|
+
self.language_packs = {pack.code: pack for pack in (language_packs or [])}
|
|
140
|
+
|
|
141
|
+
def add_language_pack(self, pack: LanguagePack) -> "AmountToWords":
|
|
142
|
+
return AmountToWords(self.currencies, [*self.language_packs.values(), pack])
|
|
143
|
+
|
|
144
|
+
def convert(self, amount: int | float | str | Decimal, country_code: str, currency_code: str, options: ConversionOptions | None = None) -> str:
|
|
145
|
+
options = options or ConversionOptions()
|
|
146
|
+
country_input = country_code.strip().upper()
|
|
147
|
+
country = ISO_COUNTRY_CODES.get(country_input)
|
|
148
|
+
code = currency_code.strip().upper()
|
|
149
|
+
if country is None:
|
|
150
|
+
raise ValueError("Unknown ISO 3166-1 Alpha-2 or Alpha-3 country code")
|
|
151
|
+
language = _resolve_language(options.language, self.language_packs)
|
|
152
|
+
pack = self.language_packs.get(language)
|
|
153
|
+
if not re.fullmatch(r"[A-Z]{3}", code):
|
|
154
|
+
raise ValueError("Currency code must be a three-letter ISO 4217 code")
|
|
155
|
+
currency = self.currencies.get(code, Currency(code, code, "Minor Unit", "Minor Units"))
|
|
156
|
+
try:
|
|
157
|
+
value = Decimal(str(amount))
|
|
158
|
+
except InvalidOperation as error:
|
|
159
|
+
raise ValueError("Amount must be numeric") from error
|
|
160
|
+
quantum = Decimal(1).scaleb(-currency.fraction_digits)
|
|
161
|
+
value = value.quantize(quantum, rounding=ROUND_HALF_UP)
|
|
162
|
+
negative = value < 0
|
|
163
|
+
value = abs(value)
|
|
164
|
+
major = int(value)
|
|
165
|
+
minor = int((value - major) * (10 ** currency.fraction_digits))
|
|
166
|
+
labels = (pack.minus, pack.conjunction, pack.only, pack.minor_singular, pack.minor_plural) if pack else {"en": ("Minus", "and", "Only", "Minor Unit", "Minor Units"), "hi": ("ऋण", "और", "मात्र", "उप-इकाई", "उप-इकाइयाँ"), "ar": ("سالب", "و", "فقط", "وحدة فرعية", "وحدات فرعية")}[language]
|
|
167
|
+
parts = [labels[0]] if negative else []
|
|
168
|
+
major_name = currency.major_singular if major == 1 else currency.major_plural
|
|
169
|
+
if pack: major_name = pack.currency_name(code, major == 1)
|
|
170
|
+
elif language != "en": major_name = LOCALIZED_CURRENCIES[language].get(code, code)
|
|
171
|
+
if options.short_currency_name: major_name = SHORT_CURRENCIES.get(language, {}).get(code, (major_name, major_name))[0 if major == 1 else 1]
|
|
172
|
+
parts += [pack.spell(major) if pack else _spell_localized(major, language), major_name]
|
|
173
|
+
if minor or (currency.fraction_digits > 0 and options.include_zero_minor):
|
|
174
|
+
conjunction = labels[1] if options.conjunction == "and" else options.conjunction
|
|
175
|
+
minor_name = currency.minor_singular if minor == 1 else currency.minor_plural
|
|
176
|
+
if language != "en": minor_name = labels[3] if minor == 1 else labels[4]
|
|
177
|
+
parts += [conjunction, pack.spell(minor) if pack else _spell_localized(minor, language), minor_name]
|
|
178
|
+
if options.include_only:
|
|
179
|
+
parts.append(labels[2])
|
|
180
|
+
return " ".join(filter(None, parts))
|
|
181
|
+
|
|
182
|
+
def _resolve_language(requested: str, language_packs: dict[str, LanguagePack] | None = None) -> str:
|
|
183
|
+
language = requested.strip().lower()
|
|
184
|
+
if language in {"en", "hi", "ar"} or language in (language_packs or {}): return language
|
|
185
|
+
return "en"
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
ALPHA2_TO_ALPHA3 = dict(pair.split(":") for pair in "AF:AFG AO:AGO AL:ALB AD:AND AE:ARE AR:ARG AM:ARM AG:ATG AU:AUS AT:AUT AZ:AZE BI:BDI BE:BEL BJ:BEN BF:BFA BD:BGD BG:BGR BH:BHR BS:BHS BA:BIH BY:BLR BZ:BLZ BO:BOL BR:BRA BB:BRB BN:BRN BT:BTN BW:BWA CF:CAF CA:CAN CH:CHE CL:CHL CN:CHN CI:CIV CM:CMR CD:COD CG:COG CO:COL KM:COM CV:CPV CR:CRI CU:CUB CY:CYP CZ:CZE DE:DEU DJ:DJI DM:DMA DK:DNK DO:DOM DZ:DZA EC:ECU EG:EGY ER:ERI EH:ESH ES:ESP EE:EST ET:ETH FI:FIN FJ:FJI FR:FRA FM:FSM GA:GAB GB:GBR GE:GEO GH:GHA GN:GIN GM:GMB GW:GNB GQ:GNQ GR:GRC GD:GRD GT:GTM GY:GUY HK:HKG HN:HND HR:HRV HT:HTI HU:HUN ID:IDN IN:IND IE:IRL IR:IRN IQ:IRQ IS:ISL IL:ISR IT:ITA JM:JAM JO:JOR JP:JPN KZ:KAZ KE:KEN KG:KGZ KH:KHM KI:KIR KN:KNA KR:KOR KW:KWT LA:LAO LB:LBN LR:LBR LY:LBY LC:LCA LI:LIE LK:LKA LS:LSO LT:LTU LU:LUX LV:LVA MO:MAC MA:MAR MC:MCO MD:MDA MG:MDG MV:MDV MX:MEX MH:MHL MK:MKD ML:MLI MT:MLT MM:MMR ME:MNE MN:MNG MZ:MOZ MR:MRT MU:MUS MW:MWI MY:MYS NA:NAM NE:NER NG:NGA NI:NIC NL:NLD NO:NOR NP:NPL NR:NRU NZ:NZL OM:OMN PK:PAK PA:PAN PE:PER PH:PHL PW:PLW PG:PNG PL:POL KP:PRK PT:PRT PY:PRY PS:PSE QA:QAT RO:ROU RU:RUS RW:RWA SA:SAU SD:SDN SN:SEN SG:SGP SB:SLB SL:SLE SV:SLV SM:SMR SO:SOM RS:SRB SS:SSD ST:STP SR:SUR SK:SVK SI:SVN SE:SWE SZ:SWZ SC:SYC SY:SYR TD:TCD TG:TGO TH:THA TJ:TJK TM:TKM TL:TLS TO:TON TT:TTO TN:TUN TR:TUR TV:TUV TW:TWN TZ:TZA UG:UGA UA:UKR UY:URY US:USA UZ:UZB VA:VAT VC:VCT VE:VEN VN:VNM VU:VUT WS:WSM XK:XKX YE:YEM ZA:ZAF ZM:ZMB ZW:ZWE".split())
|
|
2
|
+
ISO_COUNTRY_CODES = {**{code: code for code in ALPHA2_TO_ALPHA3.values()}, **ALPHA2_TO_ALPHA3}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: worldmoneywords
|
|
3
|
+
Version: 2.5.0
|
|
4
|
+
Summary: Convert monetary amounts to English, Hindi, or Arabic words using ISO country and currency codes
|
|
5
|
+
Author: Md Ikram
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/3mdikram/WorldMoneyWords
|
|
8
|
+
Project-URL: Repository, https://github.com/3mdikram/WorldMoneyWords
|
|
9
|
+
Project-URL: Issues, https://github.com/3mdikram/WorldMoneyWords/issues
|
|
10
|
+
Keywords: amount,currency,money,numbers,words,iso-3166,iso-4217
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# WorldMoneyWords for Python
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install worldmoneywords
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from amount_to_words import AmountToWords
|
|
28
|
+
|
|
29
|
+
converter = AmountToWords()
|
|
30
|
+
print(converter.convert("1234.50", "IN", "INR"))
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
An optional fourth `ConversionOptions` argument controls the suffix, zero minor units, conjunction, short currency names, and output `language` (`en`, `hi`, `ar`, or a registered language code). Set `short_currency_name=True` to output `Dollars` instead of `US Dollars`.
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
converter.convert("1234.50", "IN", "INR", ConversionOptions(language="hi"))
|
|
37
|
+
converter.convert("1234.50", "US", "USD", ConversionOptions(language="ar"))
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The arguments are amount, ISO 3166-1 Alpha-2 or Alpha-3 country code, and ISO 4217 currency code.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/amount_to_words/__init__.py
|
|
4
|
+
src/amount_to_words/converter.py
|
|
5
|
+
src/amount_to_words/countries.py
|
|
6
|
+
src/worldmoneywords.egg-info/PKG-INFO
|
|
7
|
+
src/worldmoneywords.egg-info/SOURCES.txt
|
|
8
|
+
src/worldmoneywords.egg-info/dependency_links.txt
|
|
9
|
+
src/worldmoneywords.egg-info/top_level.txt
|
|
10
|
+
tests/test_converter.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
amount_to_words
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from amount_to_words import AmountToWords, ConversionOptions, LanguagePack
|
|
3
|
+
from amount_to_words.countries import ALPHA2_TO_ALPHA3
|
|
4
|
+
|
|
5
|
+
class ConverterTest(unittest.TestCase):
|
|
6
|
+
def test_custom_official_language_pack(self):
|
|
7
|
+
pack = LanguagePack("xx", lambda number: f"number-{number}", lambda code, singular: code.lower() + ("-unit" if singular else "-units"), "negative", "with", "complete", "part", "parts")
|
|
8
|
+
converter = AmountToWords().add_language_pack(pack)
|
|
9
|
+
self.assertEqual("number-2 usd-units with number-50 parts complete", converter.convert("2.50", "US", "USD", ConversionOptions(language="xx")))
|
|
10
|
+
|
|
11
|
+
def test_inr(self):
|
|
12
|
+
self.assertEqual("One Thousand Two Hundred Thirty Four Rupees and Fifty Paise Only", AmountToWords().convert("1234.50", "IND", "INR"))
|
|
13
|
+
|
|
14
|
+
def test_negative_gbp(self):
|
|
15
|
+
self.assertEqual("Minus Ten Pounds and Twenty Five Pence Only", AmountToWords().convert("-10.25", "GBR", "GBP"))
|
|
16
|
+
|
|
17
|
+
def test_alpha2_country(self):
|
|
18
|
+
self.assertEqual("Ten Rupees Only", AmountToWords().convert("10", "IN", "INR"))
|
|
19
|
+
|
|
20
|
+
def test_minor_territory_is_not_supported(self):
|
|
21
|
+
with self.assertRaises(ValueError):
|
|
22
|
+
AmountToWords().convert("10", "AI", "USD")
|
|
23
|
+
|
|
24
|
+
def test_options(self):
|
|
25
|
+
options = ConversionOptions(include_only=False, include_zero_minor=True, conjunction="plus")
|
|
26
|
+
self.assertEqual("Ten US Dollars plus Zero Cents", AmountToWords().convert("10", "US", "USD", options))
|
|
27
|
+
|
|
28
|
+
def test_short_currency_name_option(self):
|
|
29
|
+
options = ConversionOptions(include_only=False, include_zero_minor=True, conjunction="plus", short_currency_name=True)
|
|
30
|
+
self.assertEqual("Ten Dollars plus Zero Cents", AmountToWords().convert("10", "US", "USD", options))
|
|
31
|
+
|
|
32
|
+
def test_hindi_and_arabic(self):
|
|
33
|
+
self.assertEqual("एक हज़ार दो सौ चौंतीस भारतीय रुपया और पचास उप-इकाइयाँ मात्र", AmountToWords().convert("1234.50", "IN", "INR", ConversionOptions(language="hi")))
|
|
34
|
+
self.assertEqual("ألف ومائتان وأربعة وثلاثون دولار أمريكي و خمسون وحدات فرعية فقط", AmountToWords().convert("1234.50", "US", "USD", ConversionOptions(language="ar")))
|
|
35
|
+
|
|
36
|
+
def test_all_languages_work_for_all_200_countries(self):
|
|
37
|
+
self.assertEqual(200, len(ALPHA2_TO_ALPHA3))
|
|
38
|
+
converter = AmountToWords()
|
|
39
|
+
for country in ALPHA2_TO_ALPHA3:
|
|
40
|
+
for language in ("en", "hi", "ar"):
|
|
41
|
+
self.assertTrue(converter.convert("42.50", country, "USD", ConversionOptions(language=language)))
|
|
42
|
+
|
|
43
|
+
def test_unavailable_language_falls_back_to_english(self):
|
|
44
|
+
converter = AmountToWords()
|
|
45
|
+
self.assertTrue(converter.convert("10", "PK", "PKR", ConversionOptions(language="ur")).startswith("Ten"))
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
unittest.main()
|