diff --git a/num2words/__init__.py b/num2words/__init__.py index b6969060..3328f81e 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -26,7 +26,7 @@ lang_KZ, lang_LT, lang_LV, lang_MN, lang_NL, lang_NO, lang_PL, lang_PT, lang_PT_BR, lang_RO, lang_RU, lang_SK, lang_SL, lang_SR, lang_SV, lang_TE, lang_TET, lang_TG, lang_TH, lang_TR, - lang_UK, lang_VI, lang_ZH, lang_ZH_CN, lang_ZH_HK, lang_ZH_TW) + lang_UK,lang_UZ, lang_VI, lang_ZH, lang_ZH_CN, lang_ZH_HK, lang_ZH_TW) CONVERTER_CLASSES = { 'am': lang_AM.Num2Word_AM(), @@ -87,6 +87,7 @@ 'th': lang_TH.Num2Word_TH(), 'tr': lang_TR.Num2Word_TR(), 'uk': lang_UK.Num2Word_UK(), + 'uz': lang_UZ.Num2Word_UZ(), 'vi': lang_VI.Num2Word_VI(), 'zh': lang_ZH.Num2Word_ZH(), 'zh_CN': lang_ZH_CN.Num2Word_ZH_CN(), diff --git a/num2words/lang_UZ.py b/num2words/lang_UZ.py new file mode 100644 index 00000000..2825306b --- /dev/null +++ b/num2words/lang_UZ.py @@ -0,0 +1,273 @@ +# -*- coding: utf-8 -*- +# Uzbek (Latin script) number-to-words +# Supports: cardinal, ordinal, currency +# Uzbek morphology notes: +# - No grammatical gender +# - Agglutinative: ordinals formed with suffix "-inchi" / "-nchi" +# - Plural: suffix "-lar" / "-lar" (not needed for num2words) +# - Negative: "minus" +# - Decimal separator word: "butun" (whole) + fraction part +# e.g. 3.5 → "uch butun beshdan bir" but for simple reading: "uch vergul besh" + +from __future__ import unicode_literals +from .base import Num2Word_Base +from .utils import get_digits, splitbyx + +ZERO = "nol" + +# Ones (1–9) +ONES = { + 1: "bir", + 2: "ikki", + 3: "uch", + 4: "to'rt", + 5: "besh", + 6: "olti", + 7: "yetti", + 8: "sakkiz", + 9: "to'qqiz", +} + +# Teens (10–19) — in Uzbek these are formed regularly: +# 10=o'n, 11=o'n bir, 12=o'n ikki … but the word for 10 itself is special +TENS_PREFIX = { + 1: "o'n", # 10 + 2: "yigirma", # 20 + 3: "o'ttiz", # 30 + 4: "qirq", # 40 + 5: "ellik", # 50 + 6: "oltmish", # 60 + 7: "yetmish", # 70 + 8: "sakson", # 80 + 9: "to'qson", # 90 +} + +HUNDREDS = { + 1: "bir yuz", # 100 + 2: "ikki yuz", # 200 + 3: "uch yuz", # 300 + 4: "to'rt yuz", # 400 + 5: "besh yuz", # 500 + 6: "olti yuz", # 600 + 7: "yetti yuz", # 700 + 8: "sakkiz yuz", # 800 + 9: "to'qqiz yuz",# 900 +} + +# Scale words: index = power group (1=thousands, 2=millions, …) +SCALE = { + 1: "ming", # 10^3 + 2: "million", # 10^6 + 3: "milliard", # 10^9 (Uzbek uses "milliard", not "billion") + 4: "trillion", # 10^12 + 5: "kvadrillion", # 10^15 + 6: "kvintillion", # 10^18 + 7: "sekstillion", # 10^21 + 8: "septillion", # 10^24 + 9: "oktillion", # 10^27 + 10: "nonillion", # 10^30 +} + +# Ordinal suffix rules (vowel harmony simplified for Uzbek Latin): +# After a vowel → "-nchi" +# After a consonant → "-inchi" +VOWELS = set("aeiouoʻaʼ") +# Actually in Uzbek Latin: a, e, i, o, u, oʻ, gʻ doesn't matter — last letter check: +UZBEK_VOWELS = {'a', 'e', 'i', 'o', 'u'} + + +def _ordinal_suffix(word: str) -> str: + """Return the ordinal suffix appropriate for the last character of word.""" + last = word[-1].lower() + if last in UZBEK_VOWELS: + return "nchi" + else: + return "inchi" + + +def _chunk_to_words(n: int) -> str: + """Convert a number 1–999 to Uzbek words.""" + if n <= 0: + return "" + words = [] + n1, n2, n3 = get_digits(n) # units, tens, hundreds + + if n3 > 0: + words.append(HUNDREDS[n3]) + + if n2 > 0: + tens_word = TENS_PREFIX[n2] + if n1 > 0: + words.append(tens_word + " " + ONES[n1]) + else: + words.append(tens_word) + elif n1 > 0: + words.append(ONES[n1]) + + return " ".join(words) + + +class Num2Word_UZ(Num2Word_Base): + """ + Uzbek (O'zbek) number-to-words converter. + Uses Latin script as standardised since 1995. + + Supports: + - Cardinal numbers: to_cardinal(n) + - Ordinal numbers: to_ordinal(n) → e.g. 1→"birinchi", 5→"beshinchi" + - Currency: to_currency(n, currency='UZS') + """ + + CURRENCY_FORMS = { + # (major_unit_forms, minor_unit_forms) + # Uzbek doesn't inflect for count, so single form is reused. + 'UZS': ( + ("so'm", "so'm", "so'm"), + ("tiyin", "tiyin", "tiyin"), + ), + 'USD': ( + ("dollar", "dollar", "dollar"), + ("sent", "sent", "sent"), + ), + 'EUR': ( + ("evro", "evro", "evro"), + ("sent", "sent", "sent"), + ), + 'RUB': ( + ("rubl", "rubl", "rubl"), + ("tiyin", "tiyin", "tiyin"), + ), + 'GBP': ( + ("funt", "funt", "funt"), + ("pens", "pens", "pens"), + ), + 'KZT': ( + ("tenge", "tenge", "tenge"), + ("tiyin", "tiyin", "tiyin"), + ), + 'CNY': ( + ("yuan", "yuan", "yuan"), + ("fen", "fen", "fen"), + ), + 'JPY': ( + ("iyena", "iyena", "iyena"), + ("sen", "sen", "sen"), + ), + 'TRY': ( + ("lira", "lira", "lira"), + ("qurush", "qurush", "qurush"), + ), + 'AED': ( + ("dirham", "dirham", "dirham"), + ("fils", "fils", "fils"), + ), + 'SAR': ( + ("riyal", "riyal", "riyal"), + ("halala", "halala", "halala"), + ), + 'INR': ( + ("rupiya", "rupiya", "rupiya"), + ("paysa", "paysa", "paysa"), + ), + 'CHF': ( + ("frank", "frank", "frank"), + ("santim", "santim", "santim"), + ), + 'CAD': ( + ("kanada dollari", "kanada dollari", "kanada dollari"), + ("sent", "sent", "sent"), + ), + 'AUD': ( + ("avstraliya dollari", "avstraliya dollari", "avstraliya dollari"), + ("sent", "sent", "sent"), + ), + } + + def setup(self): + self.negword = "minus" + self.pointword = "butun" # "butun" means "whole" (for decimals) + + # ------------------------------------------------------------------ + # Cardinal + # ------------------------------------------------------------------ + + def to_cardinal(self, number, **kwargs): + n = str(number).replace(',', '.') + if '.' in n: + left, right = n.split('.') + leading_zeros = len(right) - len(right.lstrip('0')) + right_words = self._int2word(int(right)) if int(right) != 0 else ZERO + decimal_part = (ZERO + ' ') * leading_zeros + right_words + return '{} {} {}'.format( + self._int2word(int(left)), + self.pointword, + decimal_part, + ) + else: + return self._int2word(int(n)) + + def _int2word(self, n: int) -> str: + if n < 0: + return self.negword + ' ' + self._int2word(-n) + if n == 0: + return ZERO + if n == 1000000000000: + return "trillion" + if n == 1000000000: + return "milliard" + if n == 1000000: + return "million" + if n == 1000: + return "ming" # special case: "bir ming" is just "ming" + if n ==100: + return "yuz" # special case: "bir yuz" is just "yuz" + words = [] + chunks = list(splitbyx(str(n), 3)) # e.g. 1_234_567 → [1, 234, 567] + i = len(chunks) + + for chunk in chunks: + i -= 1 + if chunk == 0: + continue + + # Special case: "bir ming" → just "ming" in Uzbek + # (one thousand = ming, not "bir ming" — but "ikki ming" = two thousand) + # Actually standard Uzbek does say "bir ming" for emphasis, but + # colloquially just "ming". We follow the formal written standard: "bir ming". + chunk_words = _chunk_to_words(chunk) + + if i > 0: + scale_word = SCALE[i] + words.append(chunk_words + " " + scale_word) + else: + words.append(chunk_words) + return ' '.join(words) + + # ------------------------------------------------------------------ + # Ordinal + # ------------------------------------------------------------------ + + def to_ordinal(self, number): + self.verify_ordinal(number) + cardinal = self._int2word(number) + suffix = _ordinal_suffix(cardinal) + return cardinal + suffix + + # ------------------------------------------------------------------ + # Pluralize helper (Uzbek doesn't change currency word by count, + # but the base class expects a 3-form tuple) + # ------------------------------------------------------------------ + + def pluralize(self, n, forms): + # Uzbek nouns don't inflect for number in this context — return form[0] + return forms[0] + + # ------------------------------------------------------------------ + # Currency helpers + # ------------------------------------------------------------------ + + def _money_verbose(self, number, currency): + return self._int2word(number) + + def _cents_verbose(self, number, currency): + return self._int2word(number) \ No newline at end of file diff --git a/tests/demo.py b/tests/demo.py new file mode 100644 index 00000000..1de1f3a1 --- /dev/null +++ b/tests/demo.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- +"""Demo script for manually testing every supported num2words language.""" + +from __future__ import unicode_literals + +import argparse +import os +import sys + +# Ensure the demo loads the local source tree when run from tests/. +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) + +from num2words import CONVERTER_CLASSES, num2words + +SAMPLE_CARDINALS = [0, 1, 5, 11, 21, 103, 1000000, 1234567, 3.14] +SAMPLE_ORDINALS = [1, 2, 11, 21, 101] +SAMPLE_YEARS = [1999, 2024] +SAMPLE_CURRENCY = 1.23 +CURRENCY_CODE = 'USD' + + +def format_result(value, converter, lang, to, **kwargs): + try: + return num2words(value, lang=lang, to=to, **kwargs) + except Exception as exc: + return "".format(exc) + + +def demo_language(lang): + print('=' * 72) + print('Language:', lang) + print('-' * 72) + + print('cardinal examples:') + for value in SAMPLE_CARDINALS: + text = format_result(value, num2words, lang, 'cardinal') + print(' {:>10} -> {}'.format(value, text)) + + print('\nordinal examples:') + for value in SAMPLE_ORDINALS: + text = format_result(value, num2words, lang, 'ordinal') + print(' {:>10} -> {}'.format(value, text)) + + print('\nyear examples:') + for value in SAMPLE_YEARS: + text = format_result(value, num2words, lang, 'year') + print(' {:>10} -> {}'.format(value, text)) + + print('\ncurrency example:') + currency_text = format_result(SAMPLE_CURRENCY, num2words, lang, 'currency', currency=CURRENCY_CODE) + print(' {:>10} {} -> {}'.format(SAMPLE_CURRENCY, CURRENCY_CODE, currency_text)) + + +def parse_args(argv=None): + parser = argparse.ArgumentParser(description='Manual demo for num2words languages.') + parser.add_argument('-l', '--lang', help='Language code to test (default: all languages)') + parser.add_argument('-a', '--all', action='store_true', help='Test all supported languages') + parser.add_argument('-q', '--quiet', action='store_true', help='Only print language names and success/failure statuses') + return parser.parse_args(argv) + + +def main(argv=None): + args = parse_args(argv) + languages = sorted(CONVERTER_CLASSES.keys()) + + if args.lang: + langs_to_test = [args.lang] + elif args.all: + langs_to_test = languages + else: + langs_to_test = languages + + if args.quiet: + for lang in langs_to_test: + try: + _ = format_result(1, num2words, lang, 'cardinal') + print('OK -', lang) + except Exception as exc: + print('FAIL -', lang, exc) + return 0 + + for lang in langs_to_test: + demo_language(lang) + + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tests/test_uz.py b/tests/test_uz.py new file mode 100644 index 00000000..e72d1bfe --- /dev/null +++ b/tests/test_uz.py @@ -0,0 +1,322 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2003, Taro Ogawa. All Rights Reserved. +# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA + +""" +Test suite for Num2Word_UZ (O'zbek tili, lotin yozuvi). + +Struktura test_en_ng.py asosida qurilgan: + - test_to_cardinal : butun va o'nli sonlar + - test_negative : manfiy sonlar + - test_to_ordinal : tartib sonlar (-inchi / -nchi) + - test_to_currency : valyuta (UZS, USD) +""" + +from unittest import TestCase + +# ------------------------------------------------------------------- +# To run standalone (without installing lang_UZ into num2words package): +# +# python -m pytest test_uz.py -v +# +# To run after installing: +# from num2words import num2words +# and replace uz.to_cardinal(x) with num2words(x, lang='uz') +# ------------------------------------------------------------------- + +import sys +import os +import importlib.util + +# --------------- bootstrap: resolve lang_UZ.py location ------------- +# Folder layout inside the num2words source tree: +# +# num2words-0.5.14/ +# ├── num2words/ +# │ ├── __init__.py +# │ ├── base.py +# │ ├── lang_UZ.py ← place the file here +# │ └── ... +# └── tests/ +# └── test_uz.py ← this file +# +# We locate num2words/ relative to this test file's directory. + +_tests_dir = os.path.dirname(os.path.abspath(__file__)) +_pkg_dir = os.path.join(_tests_dir, '..', 'num2words') +_lang_path = os.path.normpath(os.path.join(_pkg_dir, 'lang_UZ.py')) + +if not os.path.isfile(_lang_path): + raise FileNotFoundError( + f"\n\nCould not find lang_UZ.py at:\n {_lang_path}\n\n" + "Please copy lang_UZ.py into the num2words/ package folder " + "(next to base.py, lang_DE.py, etc.) and try again." + ) + +import num2words.base as _base +import num2words.utils as _utils + +_spec = importlib.util.spec_from_file_location("num2words.lang_UZ", _lang_path) +_mod = importlib.util.module_from_spec(_spec) +_spec.loader.exec_module(_mod) + +_uz = _mod.Num2Word_UZ() +# -------------------------------------------------------------------- + + +class Num2WordsUZCardinalTest(TestCase): + """to_cardinal() — kardinal (miqdor) sonlar""" + + def setUp(self): + self.n = _uz + + # --- nol --- + def test_zero(self): + self.assertEqual(self.n.to_cardinal(0), "nol") + + # --- birliklar (1–9) --- + def test_ones(self): + self.assertEqual(self.n.to_cardinal(1), "bir") + self.assertEqual(self.n.to_cardinal(5), "besh") + self.assertEqual(self.n.to_cardinal(9), "to'qqiz") + + # --- o'nliklar (10–19) --- + def test_ten(self): + self.assertEqual(self.n.to_cardinal(10), "o'n") + + def test_teens(self): + self.assertEqual(self.n.to_cardinal(11), "o'n bir") + self.assertEqual(self.n.to_cardinal(12), "o'n ikki") + self.assertEqual(self.n.to_cardinal(15), "o'n besh") + self.assertEqual(self.n.to_cardinal(19), "o'n to'qqiz") + + # --- yigirma–to'qson --- + def test_tens(self): + self.assertEqual(self.n.to_cardinal(20), "yigirma") + self.assertEqual(self.n.to_cardinal(21), "yigirma bir") + self.assertEqual(self.n.to_cardinal(30), "o'ttiz") + self.assertEqual(self.n.to_cardinal(40), "qirq") + self.assertEqual(self.n.to_cardinal(50), "ellik") + self.assertEqual(self.n.to_cardinal(60), "oltmish") + self.assertEqual(self.n.to_cardinal(70), "yetmish") + self.assertEqual(self.n.to_cardinal(80), "sakson") + self.assertEqual(self.n.to_cardinal(90), "to'qson") + self.assertEqual(self.n.to_cardinal(99), "to'qson to'qqiz") + + # --- yuzliklar --- + def test_hundreds(self): + self.assertEqual(self.n.to_cardinal(100), "yuz") + self.assertEqual(self.n.to_cardinal(101), "bir yuz bir") + self.assertEqual(self.n.to_cardinal(111), "bir yuz o'n bir") + self.assertEqual(self.n.to_cardinal(200), "ikki yuz") + self.assertEqual(self.n.to_cardinal(500), "besh yuz") + self.assertEqual( + self.n.to_cardinal(999), + "to'qqiz yuz to'qson to'qqiz" + ) + + # --- mingliklar --- + def test_thousands(self): + self.assertEqual(self.n.to_cardinal(1000), "ming") + self.assertEqual(self.n.to_cardinal(1001), "bir ming bir") + self.assertEqual(self.n.to_cardinal(1100), "bir ming bir yuz") + self.assertEqual( + self.n.to_cardinal(1999), + "bir ming to'qqiz yuz to'qson to'qqiz" + ) + self.assertEqual(self.n.to_cardinal(2000), "ikki ming") + self.assertEqual(self.n.to_cardinal(10000), "o'n ming") + self.assertEqual(self.n.to_cardinal(100000), "bir yuz ming") + + # --- millionlar va undan katta --- + def test_large_numbers(self): + self.assertEqual(self.n.to_cardinal(1_000_000), "million") + self.assertEqual(self.n.to_cardinal(1_000_000_000), "milliard") + self.assertEqual( + self.n.to_cardinal(1_234_567), + "bir million ikki yuz o'ttiz to'rt ming besh yuz oltmish yetti" + ) + + # --- o'nli kasrlar --- + def test_decimal(self): + self.assertEqual(self.n.to_cardinal(3.14), "uch butun o'n to'rt") + self.assertEqual(self.n.to_cardinal(0.5), "nol butun besh") + self.assertEqual(self.n.to_cardinal(0.05), "nol butun nol besh") + self.assertEqual(self.n.to_cardinal(10.001),"o'n butun nol nol bir") + + +class Num2WordsUZNegativeTest(TestCase): + """Manfiy sonlar""" + + def setUp(self): + self.n = _uz + + def test_negative_small(self): + self.assertEqual(self.n.to_cardinal(-3), "minus uch") + self.assertEqual(self.n.to_cardinal(-1), "minus bir") + + def test_negative_hundred(self): + self.assertEqual(self.n.to_cardinal(-100), "minus yuz") + + def test_negative_large(self): + self.assertEqual( + self.n.to_cardinal(-1234), + "minus bir ming ikki yuz o'ttiz to'rt" + ) + + +class Num2WordsUZOrdinalTest(TestCase): + """to_ordinal() — tartib sonlar""" + + def setUp(self): + self.n = _uz + + # Undosh bilan tugagan so'zlarga "-inchi" + def test_ordinal_consonant_ending(self): + self.assertEqual(self.n.to_ordinal(1), "birinchi") # bir → birinchi + self.assertEqual(self.n.to_ordinal(2), "ikkinchi") # ikki → ikkinchi + self.assertEqual(self.n.to_ordinal(3), "uchinchi") # uch → uchinchi + self.assertEqual(self.n.to_ordinal(4), "to'rtinchi") # to'rt → to'rtinchi + self.assertEqual(self.n.to_ordinal(8), "sakkizinchi") # sakkiz → sakkizinchi + self.assertEqual(self.n.to_ordinal(10), "o'ninchi") # o'n → o'ninchi + self.assertEqual(self.n.to_ordinal(30), "o'ttizinchi") # o'ttiz → o'ttizinchi + self.assertEqual(self.n.to_ordinal(40), "qirqinchi") # qirq → qirqinchi + self.assertEqual(self.n.to_ordinal(100),"yuzinchi") # yuz → yuzinchi + + # Unli bilan tugagan so'zlarga "-nchi" + def test_ordinal_vowel_ending(self): + self.assertEqual(self.n.to_ordinal(5), "beshinchi") # besh → beshinchi + self.assertEqual(self.n.to_ordinal(20), "yigirmanchi") # yigirma → yigirmanchi + self.assertEqual(self.n.to_ordinal(50), "ellikinchi") # ellik → ellikinchi + + # Qo'shma tartib sonlar + def test_ordinal_compound(self): + self.assertEqual(self.n.to_ordinal(11), "o'n birinchi") + self.assertEqual(self.n.to_ordinal(15), "o'n beshinchi") + self.assertEqual(self.n.to_ordinal(19), "o'n to'qqizinchi") + self.assertEqual(self.n.to_ordinal(21), "yigirma birinchi") + self.assertEqual(self.n.to_ordinal(101),"bir yuz birinchi") + + def test_ordinal_thousands(self): + self.assertEqual(self.n.to_ordinal(1000), "minginchi") + self.assertEqual(self.n.to_ordinal(1_000_000),"millioninchi") + + +class Num2WordsUZCurrencyTest(TestCase): + """ + to_currency() — valyuta. + + Ingliz test_en_ng.py bilan bir xil tuzilma: + UZS (so'm / tiyin) va USD (dollar / sent) testlari. + """ + + def setUp(self): + self.n = _uz + + # ---------------------------------------------------------------- + # UZS — so'm va tiyin + # ---------------------------------------------------------------- + + def test_uzs_zero(self): + self.assertEqual( + self.n.to_currency(0, currency='UZS'), + "nol so'm, nol tiyin" + ) + + def test_uzs_whole(self): + self.assertEqual( + self.n.to_currency(1.00, currency='UZS'), + "bir so'm, nol tiyin" + ) + self.assertEqual( + self.n.to_currency(2000.00, currency='UZS'), + "ikki ming so'm, nol tiyin" + ) + + def test_uzs_one_tiyin(self): + self.assertEqual( + self.n.to_currency(1.01, currency='UZS'), + "bir so'm, bir tiyin" + ) + self.assertEqual( + self.n.to_currency(4.01, currency='UZS'), + "to'rt so'm, bir tiyin" + ) + + def test_uzs_ten_tiyin(self): + self.assertEqual( + self.n.to_currency(1.10, currency='UZS'), + "bir so'm, o'n tiyin" + ) + + def test_uzs_partial_tiyin(self): + # 38.4 → 38 so'm, 40 tiyin + self.assertEqual( + self.n.to_currency(38.40, currency='UZS'), + "o'ttiz sakkiz so'm, qirq tiyin" + ) + # 158.3 → 158 so'm, 30 tiyin + self.assertEqual( + self.n.to_currency(158.30, currency='UZS'), + "bir yuz ellik sakkiz so'm, o'ttiz tiyin" + ) + # 0.50 → nol so'm, ellik tiyin + self.assertEqual( + self.n.to_currency(0.50, currency='UZS'), + "nol so'm, ellik tiyin" + ) + + def test_uzs_large_amount(self): + self.assertEqual( + self.n.to_currency(4778.00, currency='UZS'), + "to'rt ming yetti yuz yetmish sakkiz so'm, nol tiyin" + ) + self.assertEqual( + self.n.to_currency(999999.99, currency='UZS'), + "to'qqiz yuz to'qson to'qqiz ming to'qqiz yuz to'qson to'qqiz " + "so'm, to'qson to'qqiz tiyin" + ) + + # ---------------------------------------------------------------- + # USD — dollar va sent + # ---------------------------------------------------------------- + + def test_usd_whole(self): + self.assertEqual( + self.n.to_currency(1.00, currency='USD'), + "bir dollar, nol sent" + ) + self.assertEqual( + self.n.to_currency(100.00, currency='USD'), + "yuz dollar, nol sent" + ) + + def test_usd_with_cents(self): + self.assertEqual( + self.n.to_currency(1.01, currency='USD'), + "bir dollar, bir sent" + ) + + def test_usd_large(self): + self.assertEqual( + self.n.to_currency(4778.00, currency='USD'), + "to'rt ming yetti yuz yetmish sakkiz dollar, nol sent" + ) + + +if __name__ == "__main__": + import unittest + unittest.main()