diff --git a/.gitignore b/.gitignore index 2a9b1bf8..8f01013f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ dist /.tox .eggs/ /venv/ +.venv/ diff --git a/README.rst b/README.rst index 46b0485b..2dd46e0a 100644 --- a/README.rst +++ b/README.rst @@ -79,8 +79,11 @@ Besides the numerical argument, there are two main optional arguments, ``to:`` a * ``am`` (Amharic) * ``ar`` (Arabic) * ``az`` (Azerbaijani) -* ``by`` (Belarusian) -* ``cz`` (Czech) +* ``be`` (Belarusian) +* ``bn`` (Bangladeshi) +* ``ce`` (Chechen) +* ``cs`` (Czech) +* ``cy`` (Welsh) * ``de`` (German) * ``dk`` (Danish) * ``en_GB`` (English - Great Britain) @@ -89,6 +92,7 @@ Besides the numerical argument, there are two main optional arguments, ``to:`` a * ``en_NP`` (English - Nepal) * ``es`` (Spanish) * ``es_CO`` (Spanish - Colombia) +* ``es_CR`` (Spanish - Costa Rica) * ``es_VE`` (Spanish - Venezuela) * ``es_GT`` (Spanish - Guatemala) * ``eu`` (EURO) @@ -119,6 +123,7 @@ Besides the numerical argument, there are two main optional arguments, ``to:`` a * ``ro`` (Romanian) * ``ru`` (Russian) * ``te`` (Telugu) +* ``tet`` (Tetum) * ``tg`` (Tajik) * ``tr`` (Turkish) * ``th`` (Thai) diff --git a/num2words/README.md b/num2words/README.md new file mode 100644 index 00000000..b7e2e0fa --- /dev/null +++ b/num2words/README.md @@ -0,0 +1,70 @@ +# Add new language + +for each new language you must create a file `lang_NN.py` where `NN` is the +ISO 639-1 or ISO 639-3 [language code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes). + +This class must be a subclass of `Num2Word_EU` and implement at least the following methods + +``` +to_cardinal(self, number) +to_ordinal(self, number) +`` + +To integrate your language into the `num2words` module, add the name of your file +to the import list in [num2words/__init__.py](num2words/__init__.py) (top of the file), +and `'nn': lang_NN.Num2Word_NN()` to the `CONVERTER_CLASSES` list in the same file. +Do not forget to remplace `NN` by the appropriate ISO 639 language code. + +The following is a template for a new language class + +``` +from .lang_EU import Num2Word_EU + +class Num2Word_CY(Num2Word_EU): + def setup(self): + Num2Word_EU.setup(self) + + def __init__(self): + pass + + def to_ordinal(self, number): + # implement here your code. number is the integer to be transformed into an ordinal + # as a word (str) + # which is returned + return "NOT IMPLEMENTED" + + def to_cardinal(self, number): + # implement here your code. number is the integer to be transformed into an cardinal + # as a word (str) + # which is returned + return "NOT IMPLEMENTED" +``` + +You can use as manu auxiliary methods as you need to make your code efficient and readable. +If you need further options like Gender, Formal/Informal, add those parameters to the methods, +e.g. + +``` + def to_ordinal(self, number, gender="fem", informal=True) + # your code + pass +``` + +More inspiration can be found in existing `num2words/lang_NN.py` files + +## Code validation + +In order to get your contribution merged into the main project, your code must test the validation tests. +For this install the packages needed to test + +``` +pip install -r requirements-test.txt +``` + +run `tox` and `coverage` to check that the code is well formated and all parts of the code are tested + +``` +tox +python3 -m coverage report -m +``` + diff --git a/num2words/__init__.py b/num2words/__init__.py index 1df531d9..4761c607 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -17,21 +17,27 @@ from __future__ import unicode_literals -from . import (lang_AM, lang_AR, lang_AZ, lang_BY, lang_CZ, lang_DE, lang_DK, - lang_EN, lang_EN_IN, lang_EN_NG, lang_EN_NP, lang_EO, lang_ES, lang_ES_CO, + +from . import (lang_AM, lang_AR, lang_AZ, lang_BE, lang_BN, lang_CA, lang_CE, + lang_CS, lang_CY, lang_DE, lang_DK, lang_EN, lang_EN_IN,lang_EN_NP, + lang_EN_NG, lang_EO, lang_ES, lang_ES_CO, lang_ES_CR, lang_ES_GT, lang_ES_NI, lang_ES_VE, lang_FA, lang_FI, lang_FR, lang_FR_BE, lang_FR_CH, lang_FR_DZ, lang_HE, lang_HU, lang_ID, lang_IS, lang_IT, lang_JA, lang_KN, lang_KO, lang_KZ, lang_LT, lang_LV, 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_TG, lang_TH, lang_TR, lang_UK, lang_VI) + lang_TET, lang_TG, lang_TH, lang_TR, lang_UK, lang_VI) CONVERTER_CLASSES = { 'am': lang_AM.Num2Word_AM(), 'ar': lang_AR.Num2Word_AR(), 'az': lang_AZ.Num2Word_AZ(), - 'by': lang_BY.Num2Word_BY(), - 'cz': lang_CZ.Num2Word_CZ(), + 'be': lang_BE.Num2Word_BE(), + 'bn': lang_BN.Num2Word_BN(), + 'ca': lang_CA.Num2Word_CA(), + 'ce': lang_CE.Num2Word_CE(), + 'cs': lang_CS.Num2Word_CS(), + 'cy': lang_CY.Num2Word_CY(), 'en': lang_EN.Num2Word_EN(), 'en_IN': lang_EN_IN.Num2Word_EN_IN(), 'en_NG': lang_EN_NG.Num2Word_EN_NG(), @@ -46,6 +52,7 @@ 'eo': lang_EO.Num2Word_EO(), 'es': lang_ES.Num2Word_ES(), 'es_CO': lang_ES_CO.Num2Word_ES_CO(), + 'es_CR': lang_ES_CR.Num2Word_ES_CR(), 'es_GT': lang_ES_GT.Num2Word_ES_GT(), 'es_NI': lang_ES_NI.Num2Word_ES_NI(), 'es_VE': lang_ES_VE.Num2Word_ES_VE(), @@ -76,8 +83,9 @@ 'nl': lang_NL.Num2Word_NL(), 'uk': lang_UK.Num2Word_UK(), 'te': lang_TE.Num2Word_TE(), + 'tet': lang_TET.Num2Word_TET(), 'hu': lang_HU.Num2Word_HU(), - 'is': lang_IS.Num2Word_IS() + 'is': lang_IS.Num2Word_IS(), } CONVERTES_TYPES = ['cardinal', 'ordinal', 'ordinal_num', 'year', 'currency'] diff --git a/num2words/lang_BY.py b/num2words/lang_BE.py similarity index 89% rename from num2words/lang_BY.py rename to num2words/lang_BE.py index ec825fd0..c41d6e4e 100644 --- a/num2words/lang_BY.py +++ b/num2words/lang_BE.py @@ -94,6 +94,17 @@ 9: "дзевяноста", } +TWENTIES_ORD = ( + ("дваццаць", "дваццаці"), + ("трыццаць", "трыццаці"), + ("сорак", "сарака"), + ("пяцьдзясят", "пяцідзясяці"), + ("шэсцьдзясят", "шaсцідзясяці"), + ("семдзесят", "сямідзесяці"), + ("восемдзесят", "васьмідзесяці"), + ("дзевяноста", "дзевяноста"), +) + HUNDREDS = { 1: "сто", 2: "дзвесце", @@ -120,7 +131,7 @@ } -class Num2Word_BY(Num2Word_Base): +class Num2Word_BE(Num2Word_Base): CURRENCY_FORMS = { "RUB": ( ("расійскі рубель", "расійскія рублі", "расійскіх рублёў"), @@ -138,6 +149,7 @@ class Num2Word_BY(Num2Word_Base): ("капейка", "капейкі", "капеек"), ), "UZS": (("сум", "сумы", "сумаў"), ("тыйін", "тыйіны", "тыйінаў")), + "PLN": (("злоты", "злотых", "злотых"), ("грош", "грошы", "грошаў")), } def setup(self): @@ -204,6 +216,8 @@ def pluralize(self, n, forms): def to_ordinal(self, number, gender="m"): self.verify_ordinal(number) + if isinstance(gender, bool) and gender: + gender = "f" outwords = self.to_cardinal(number, gender).split(" ") lastword = outwords[-1].lower() try: @@ -223,8 +237,6 @@ def to_ordinal(self, number, gender="m"): lastword = ( self.ords_adjective.get(lastword[:-3], lastword) + "соты" ) - elif lastword[-5:] == "шэсць": - lastword = "шосты" elif lastword[-7:] == "дзесяць": lastword = "дзясяты" elif lastword[-9:] == "семдзесят": @@ -242,6 +254,8 @@ def to_ordinal(self, number, gender="m"): elif lastword[-1] == "н" or lastword[-2] == "н": lastword = lastword[: lastword.rfind("н") + 1] + "ны" + elif lastword[-3:] == "наў": + lastword = lastword[: lastword.rfind("н") + 1] + "ны" elif lastword[-1] == "д" or lastword[-2] == "д": lastword = lastword[: lastword.rfind("д") + 1] + "ны" @@ -254,9 +268,7 @@ def to_ordinal(self, number, gender="m"): lastword = lastword[:-1] + "ая" if gender == "n": - if lastword[-2:] in [ - "ці", "ца" - ]: + if lastword[-2:] in ["ці", "ца"]: lastword = lastword[:-2] + "цяе" else: lastword = lastword[:-1] + "ае" @@ -266,16 +278,20 @@ def to_ordinal(self, number, gender="m"): outwords[-2] = outwords[-1] del outwords[-1] - if len(outwords) > 2 and "тысяч" in outwords[-1]: - if 'сорак' in outwords[-3]: - outwords[-3] = outwords[-3].replace('сорак', 'сарака') - outwords[-3] = outwords[-3] + outwords[-2] + outwords[-1] - del outwords[-1] - del outwords[-1] + if len(outwords) > 1 and ( + (any(x[0] in outwords[-1] for x in THOUSANDS.values())) + or "тысяч" in outwords[-1] + ): + new_outwords = [] + for _w in outwords: + replacement = next( + (x for x in TWENTIES_ORD if x[0] in _w), None + ) + if replacement: + _w = _w.replace(replacement[0], replacement[1]) + new_outwords.append(_w) + outwords = ["".join(new_outwords)] - elif len(outwords) > 1 and "тысяч" in outwords[-1]: - outwords[-2] = outwords[-2] + outwords[-1] - del outwords[-1] return " ".join(outwords).strip() def _money_verbose(self, number, currency): @@ -294,8 +310,6 @@ def _cents_verbose(self, number, currency): return self._int2word(number, gender) def _int2word(self, n, gender="m"): - if isinstance(gender, bool) and gender: - gender = "f" if n < 0: return " ".join([self.negword, self._int2word(abs(n), gender)]) diff --git a/num2words/lang_BN.py b/num2words/lang_BN.py new file mode 100644 index 00000000..ef86ed71 --- /dev/null +++ b/num2words/lang_BN.py @@ -0,0 +1,203 @@ +# -*- coding: utf-8 -*- +# Author: Mehedi Hasan Khondoker +# Email: mehedihasankhondoker [at] gmail.com +# Copyright (c) 2024, Mehedi Hasan Khondoker. All Rights Reserved. + +# This library is build for Bangladesh format Number to Word conversion. +# You are welcome as contributor to the library. + +# 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. + + +from decimal import Decimal + +RANKING = ['', 'প্রথম', 'দ্বিতীয়', 'তৃতীয়', 'চতুর্থ', 'পঞ্চম', 'ষষ্ঠ', + 'সপ্তম', 'অষ্টম', 'নবম', 'দশম'] # pragma: no cover + +AKOK = ['', 'এক', 'দুই', 'তিন', 'চার', 'পাঁচ', 'ছয়', + 'সাত', 'আট', 'নয়'] # pragma: no cover + +DOSOK = [ + 'দশ', 'এগারো', 'বারো', 'তেরো', 'চৌদ্দ', 'পনের', + 'ষোল', 'সতের', 'আঠারো', 'উনিশ', + 'বিশ', 'একুশ', 'বাইশ', 'তেইশ', 'চব্বিশ', 'পঁচিশ', + 'ছাব্বিশ', 'সাতাশ', 'আটাশ', 'উনত্রিশ', + 'ত্রিশ', 'একত্রিশ', 'বত্রিশ', 'তেত্রিশ', 'চৌত্রিশ', 'পঁইত্রিশ', + 'ছত্রিশ', 'সাতত্রিশ', 'আটত্রিশ', 'উনচল্লিশ', 'চল্লিশ', + 'একচল্লিশ', 'বিয়াল্লিশ', 'তেতাল্লিশ', 'চৌচল্লিশ', + 'পঁয়তাল্লিশ', 'ছেচল্লিশ', 'সাতচল্লিশ', 'আটচল্লিশ', 'উনপঞ্চাশ', + 'পঞ্চাশ', 'একান্ন', 'বাহান্ন', 'তিপ্পান্ন', 'চুয়ান্ন', 'পঞ্চান্ন', + 'ছাপ্পান্ন', 'সাতান্ন', 'আটান্ন', 'উনষাট', 'ষাট', + 'একষট্টি', 'বাষট্টি', 'তেষট্টি', 'চৌষট্টি', 'পঁয়ষট্টি', + 'ছিষট্টি', 'সাতষট্টি', 'আটষট্টি', 'উনসত্তর', 'সত্তর', + 'একাত্তর ', 'বাহাত্তর', 'তিয়াত্তর', 'চুয়াত্তর', 'পঁচাত্তর', + 'ছিয়াত্তর', 'সাতাত্তর', 'আটাত্তর', 'উনআশি', 'আশি', + 'একাশি', 'বিরাশি', 'তিরাশি', 'চুরাশি', 'পঁচাশি', + 'ছিয়াশি', 'সাতাশি', 'আটাশি', 'উননব্বই', 'নব্বই', + 'একানব্বই', 'বিরানব্বই', 'তিরানব্বই', 'চুরানব্বই', 'পঁচানব্বই', + 'ছিয়ানব্বই', 'সাতানব্বই', 'আটানব্বই', 'নিরানব্বই' +] # pragma: no cover +HAZAR = ' হাজার ' # pragma: no cover +LAKH = ' লাখ ' # pragma: no cover +KOTI = ' কোটি ' # pragma: no cover +MAX_NUMBER = 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 # noqa: E501 # pragma: no cover + + +class NumberTooLargeError(Exception): + """Custom exception for numbers that are too large.""" + pass + + +class Num2Word_BN: + + @staticmethod + def str_to_number(number): + return abs(Decimal(str(number))) # pragma: no cover + + @staticmethod + def parse_number(number: Decimal): + dosomik = str(number - int(number)).split('.')[1:] + dosomik_str = ''.join(dosomik) if dosomik else 0 + return int(number), int(dosomik_str) + + @staticmethod + def parse_paisa(number: Decimal): + # 1-99 for paisa count so two digits are valid. + paisa = str(number - int(number)).split('.')[1:] + paisa_str = ''.join(paisa) if paisa else 0 + + # this is need, when we parse to decimal it removes trailing 0 . + if paisa_str: + paisa_str = str(int(paisa_str) * 100)[:2] + return int(number), int(paisa_str) + + def _is_smaller_than_max_number(self, number): + if MAX_NUMBER >= number: + return True + raise NumberTooLargeError(f'Too Large number maximum ' + f'value={MAX_NUMBER}') + + def _dosomik_to_bengali_word(self, number): + word = '' + for i in str(number): + word += ' ' + AKOK[int(i)] + return word + + def _number_to_bengali_word(self, number): + if number == 0: + return 'শূন্য' + + words = '' + + if number >= 10 ** 7: + words += self._number_to_bengali_word(number // 10 ** 7) + KOTI + number %= 10 ** 7 + + if number >= 10 ** 5: + words += self._number_to_bengali_word(number // 10 ** 5) + LAKH + number %= 10 ** 5 + + if number >= 1000: + words += self._number_to_bengali_word(number // 1000) + HAZAR + number %= 1000 + + if number >= 100: + words += AKOK[number // 100] + 'শত ' + number %= 100 + + if 10 <= number <= 99: + words += DOSOK[number - 10] + ' ' + number = 0 + + if 0 < number < 10: + words += AKOK[number] + ' ' + + return words.strip() + + def to_currency(self, val): + """ + This function represent a number to word in bangla taka and paisa. + example: + 1 = এক টাকা, + 101 = একশত এক টাকা, + 9999.15 = নয় হাজার নয়শত নিরানব্বই টাকা পনের পয়সা + and so on. + """ + + dosomik_word = None + number = self.str_to_number(val) + number, decimal_part = self.parse_paisa(number) + self._is_smaller_than_max_number(number) + + if decimal_part > 0: + dosomik_word = f' {self._number_to_bengali_word(decimal_part)} পয়সা' # noqa: E501 + + words = f'{self._number_to_bengali_word(number)} টাকা' + + if dosomik_word: + return (words + dosomik_word).strip() + return words.strip() + + def to_cardinal(self, number): + """ + This function represent a number to word in bangla. + example: + 1 = এক, + 101 = একশত এক, + 9999 = নয় হাজার নয়শত নিরানব্বই + and so on. + """ + + dosomik_word = None + number = self.str_to_number(number) + number, decimal_part = self.parse_number(number) + self._is_smaller_than_max_number(number) + + if decimal_part > 0: + dosomik_word = f' দশমিক{self._dosomik_to_bengali_word(decimal_part)}' # noqa: E501 + + words = self._number_to_bengali_word(number) + + if dosomik_word: + return (words + dosomik_word).strip() + return words.strip() + + def to_ordinal(self, number): + return self.to_cardinal(number) + + def to_ordinal_num(self, number): + """ + This function represent a number to ranking in bangla. + example: + 1 = প্রথম, + 2 = দ্বিতীয়, + 1001 = এক হাজার একতম + and so on. + """ + self._is_smaller_than_max_number(number) + + if number in range(1, 11): + return RANKING[number] + else: + rank = self.to_cardinal(int(abs(number))) + if rank.endswith('ত'): + return rank + 'ম' + return rank + 'তম' + + def to_year(self, number): + """ + This function represent a number to year in bangla. + example: + 2002 = দুই হাজার দুই সাল, + 2024 = দুই হাজার চব্বিশ সাল + and so on. + """ + self._is_smaller_than_max_number(number) + return self.to_cardinal(int(abs(number))) + ' সাল' diff --git a/num2words/lang_CA.py b/num2words/lang_CA.py new file mode 100644 index 00000000..97d0f29e --- /dev/null +++ b/num2words/lang_CA.py @@ -0,0 +1,476 @@ +from __future__ import division, print_function, unicode_literals + +import math + +from .lang_EU import Num2Word_EU + +GENERIC_DOLLARS = ('dòlar', 'dòlars') +GENERIC_CENTS = ('centau', 'centaus') +CURRENCIES_UNA = ( + 'SLL', + 'SEK', + 'NOK', + 'CZK', + 'DKK', + 'ISK', + 'SKK', + 'GBP', + 'CYP', + 'EGP', + 'FKP', + 'GIP', + 'LBP', + 'SDG', + 'SHP', + 'SSP', + 'SYP', + 'INR', + 'IDR', + 'LKR', + 'MUR', + 'NPR', + 'PKR', + 'SCR', + 'ESP', + 'TRY', + 'ITL', +) +CENTS_UNA = ('EGP', 'JOD', 'LBP', 'SDG', 'SSP', 'SYP') + + +class Num2Word_CA(Num2Word_EU): + CURRENCY_FORMS = { + 'EUR': (('euro', 'euros'), ('cèntim', 'cèntims')), + 'ESP': (('pesseta', 'pessetes'), ('cèntim', 'cèntims')), + 'USD': (GENERIC_DOLLARS, ('centau', 'centaus')), + 'PEN': (('sol', 'sols'), ('cèntim', 'cèntims')), + 'CRC': (('colón', 'colons'), GENERIC_CENTS), + 'AUD': (GENERIC_DOLLARS, GENERIC_CENTS), + 'CAD': (GENERIC_DOLLARS, GENERIC_CENTS), + 'GBP': (('lliura', 'lliures'), ('penic', 'penics')), + 'RUB': (('ruble', 'rubles'), ('copec', 'copecs')), + 'SEK': (('corona', 'corones'), ('öre', 'öre')), + 'NOK': (('corona', 'corones'), ('øre', 'øre')), + 'PLN': (('zloty', 'zlotys'), ('grosz', 'groszy')), + 'MXN': (('peso', 'pesos'), GENERIC_CENTS), + 'RON': (('leu', 'lei'), ('ban', 'bani')), + 'INR': (('rupia', 'rupies'), ('paisa', 'paise')), + 'HUF': (('fòrint', 'fòrints'), ('fillér', 'fillérs')), + 'FRF': (('franc', 'francs'), ('cèntim', 'cèntims')), + 'CNY': (('iuan', 'iuans'), ('fen', 'jiao')), + 'CZK': (('corona', 'corones'), ('haléř', 'haléřů')), + 'NIO': (('córdoba', 'córdobas'), GENERIC_CENTS), + 'VES': (('bolívar', 'bolívars'), ('cèntim', 'cèntims')), + 'BRL': (('real', 'reals'), GENERIC_CENTS), + 'CHF': (('franc', 'francs'), ('cèntim', 'cèntims')), + 'JPY': (('ien', 'iens'), ('sen', 'sen')), + 'KRW': (('won', 'wons'), ('jeon', 'jeon')), + 'KPW': (('won', 'wons'), ('chŏn', 'chŏn')), + 'TRY': (('lira', 'lires'), ('kuruş', 'kuruş')), + 'ZAR': (('rand', 'rands'), ('cèntim', 'cèntims')), + 'KZT': (('tenge', 'tenge'), ('tin', 'tin')), + 'UAH': (('hrívnia', 'hrívnies'), ('kopiika', 'kopíok')), + 'THB': (('baht', 'bahts'), ('satang', 'satang')), + 'AED': (('dirham', 'dirhams'), ('fils', 'fulūs')), + 'AFN': (('afgani', 'afganis'), ('puli', 'puls')), + 'ALL': (('lek', 'lekë'), ('qqindarka', 'qindarkë')), + 'AMD': (('dram', 'drams'), ('luma', 'lumas')), + 'ANG': (('florí', 'florins'), ('cèntim', 'cèntims')), + 'AOA': (('kwanza', 'kwanzes'), ('cèntim', 'cèntims')), + 'ARS': (('peso', 'pesos'), GENERIC_CENTS), + 'AWG': (('florí', 'florins'), GENERIC_CENTS), + 'AZN': (('manat', 'manats'), ('qəpik', 'qəpik')), + 'BBD': (GENERIC_DOLLARS, GENERIC_CENTS), + 'BDT': (('taka', 'taka'), ('poisha', 'poisha')), + 'BGN': (('lev', 'leva'), ('stotinka', 'stotinki')), + 'BHD': (('dinar', 'dinars'), ('fils', 'fulūs')), + 'BIF': (('franc', 'francs'), ('cèntim', 'cèntims')), + 'BMD': (GENERIC_DOLLARS, GENERIC_CENTS), + 'BND': (GENERIC_DOLLARS, GENERIC_CENTS), + 'BOB': (('boliviano', 'bolivianos'), GENERIC_CENTS), + 'BSD': (GENERIC_DOLLARS, GENERIC_CENTS), + 'BTN': (('ngultrum', 'ngultrums'), ('chetrum', 'chetrums')), + 'BWP': (('pula', 'pula'), ('thebe', 'thebe')), + 'BYN': (('ruble', 'rubles'), ('copec', 'copecs')), + 'BYR': (('ruble', 'rubles'), ('copec', 'copecs')), + 'BZD': (GENERIC_DOLLARS, ('cèntim', 'cèntims')), + 'CDF': (('franc', 'francs'), ('cèntim', 'cèntims')), + 'CLP': (('peso', 'pesos'), GENERIC_CENTS), + 'COP': (('peso', 'pesos'), GENERIC_CENTS), + 'CUP': (('peso', 'pesos'), GENERIC_CENTS), + 'CVE': (('escut', 'escuts'), GENERIC_CENTS), + 'CYP': (('lliura', 'lliures'), ('cèntim', 'cèntims')), + 'DJF': (('franc', 'francs'), ('cèntim', 'cèntims')), + 'DKK': (('corona', 'corones'), ('øre', 'øre')), + 'DOP': (('peso', 'pesos'), GENERIC_CENTS), + 'DZD': (('dinar', 'dinars'), ('cèntim', 'cèntims')), + 'ECS': (('sucre', 'sucres'), GENERIC_CENTS), + 'EGP': (('lliura', 'lliures'), ('piastre', 'piastres')), + 'ERN': (('nakfa', 'nakfes'), ('cèntim', 'cèntims')), + 'ETB': (('birr', 'birr'), ('cèntim', 'cèntims')), + 'FJD': (GENERIC_DOLLARS, GENERIC_CENTS), + 'FKP': (('lliura', 'lliures'), ('penic', 'penics')), + 'GEL': (('lari', 'laris'), ('tetri', 'tetri')), + 'GHS': (('cedi', 'cedis'), ('pesewa', 'pesewas')), + 'GIP': (('lliura', 'lliures'), ('penic', 'penics')), + 'GMD': (('dalasi', 'dalasis'), ('butut', 'bututs')), + 'GNF': (('franc', 'francs'), ('cèntim', 'cèntims')), + 'GTQ': (('quetzal', 'quetzals'), GENERIC_CENTS), + 'GYD': (GENERIC_DOLLARS, GENERIC_CENTS), + 'HKD': (GENERIC_DOLLARS, GENERIC_CENTS), + 'HNL': (('lempira', 'lempires'), GENERIC_CENTS), + 'HRK': (('kuna', 'kuna'), ('lipa', 'lipa')), + 'HTG': (('gourde', 'gourdes'), ('cèntim', 'cèntims')), + 'IDR': (('rúpia', 'rúpies'), ('cèntim', 'cèntims')), + 'ILS': (('xéquel', 'xéquels'), ('agorà', 'agorot')), + 'IQD': (('dinar', 'dinars'), ('fils', 'fils')), + 'IRR': (('rial', 'rials'), ('dinar', 'dinars')), + 'ISK': (('corona', 'corones'), ('eyrir', 'aurar')), + 'ITL': (('lira', 'lires'), ('cèntim', 'cèntims')), + 'JMD': (GENERIC_DOLLARS, ('cèntim', 'cèntims')), + 'JOD': (('dinar', 'dinars'), ('piastra', 'piastres')), + 'KES': (('xiling', 'xílings'), ('cèntim', 'cèntims')), + 'KGS': (('som', 'som'), ('tyiyn', 'tyiyn')), + 'KHR': (('riel', 'riels'), ('cèntim', 'cèntims')), + 'KMF': (('franc', 'francs'), ('cèntim', 'cèntims')), + 'KWD': (('dinar', 'dinars'), ('fils', 'fils')), + 'KYD': (GENERIC_DOLLARS, ('cèntim', 'cèntims')), + 'LAK': (('kip', 'kips'), ('at', 'at')), + 'LBP': (('lliura', 'lliures'), ('piastra', 'piastres')), + 'LKR': (('rúpia', 'rúpies'), ('cèntim', 'cèntims')), + 'LRD': (GENERIC_DOLLARS, ('cèntim', 'cèntims')), + 'LSL': (('loti', 'maloti'), ('sente', 'lisente')), + 'LTL': (('lita', 'litai'), ('cèntim', 'cèntims')), + 'LYD': (('dinar', 'dinars'), ('dírham', 'dírhams')), + 'MAD': (('dírham', 'dirhams'), ('cèntim', 'cèntims')), + 'MDL': (('leu', 'lei'), ('ban', 'bani')), + 'MGA': (('ariary', 'ariary'), ('iraimbilanja', 'iraimbilanja')), + 'MKD': (('denar', 'denari'), ('deni', 'deni')), + 'MMK': (('kyat', 'kyats'), ('pya', 'pyas')), + 'MNT': (('tögrög', 'tögrög'), ('möngö', 'möngö')), + 'MOP': (('pataca', 'pataques'), ('avo', 'avos')), + 'MRO': (('ouguiya', 'ouguiya'), ('khoums', 'khoums')), + 'MRU': (('ouguiya', 'ouguiya'), ('khoums', 'khoums')), + 'MUR': (('rupia', 'rúpies'), ('cèntim', 'cèntims')), + 'MVR': (('rufiyaa', 'rufiyaa'), ('laari', 'laari')), + 'MWK': (('kwacha', 'kwacha'), ('tambala', 'tambala')), + 'MYR': (('ringgit', 'ringgits'), ('sen', 'sens')), + 'MZN': (('metical', 'meticals'), GENERIC_CENTS), + 'NAD': (GENERIC_DOLLARS, ('cèntim', 'cèntims')), + 'NGN': (('naira', 'naires'), ('kobo', 'kobos')), + 'NPR': (('rupia', 'rupies'), ('paisa', 'paises')), + 'NZD': (GENERIC_DOLLARS, GENERIC_CENTS), + 'OMR': (('rial', 'rials'), ('baisa', 'baisa')), + 'PAB': (GENERIC_DOLLARS, ('centésimo', 'centésimos')), + 'PGK': (('kina', 'kina'), ('toea', 'toea')), + 'PHP': (('peso', 'pesos'), GENERIC_CENTS), + 'PKR': (('rupia', 'rupies'), ('paisa', 'paise')), + 'PLZ': (('zloty', 'zlotys'), ('grosz', 'groszy')), + 'PYG': (('guaraní', 'guaranís'), ('cèntim', 'cèntims')), + 'QAR': (('rial', 'rials'), ('dírham', 'dírhams')), + 'QTQ': (('quetzal', 'quetzals'), GENERIC_CENTS), + 'RSD': (('dinar', 'dinars'), ('para', 'para')), + 'RUR': (('ruble', 'rubles'), ('copec', 'copecs')), + 'RWF': (('franc', 'francs'), ('cèntim', 'cèntims')), + 'SAR': (('riyal', 'riyals'), ('hàl·lala', 'hàl·lalat')), + 'SBD': (GENERIC_DOLLARS, ('cèntim', 'cèntims')), + 'SCR': (('rupia', 'rupies'), ('cèntim', 'cèntims')), + 'SDG': (('lliura', 'lliures'), ('piastre', 'piastres')), + 'SGD': (GENERIC_DOLLARS, ('cèntim', 'cèntims')), + 'SHP': (('lliura', 'lliures'), ('penic', 'penics')), + 'SLL': (('leonE', 'leones'), ('cèntim', 'cèntims')), + 'SRD': (GENERIC_DOLLARS, ('cèntim', 'cèntims')), + 'SSP': (('lliura', 'lliures'), ('piastre', 'piastres')), + 'STD': (('dobra', 'dobrAs'), ('cèntim', 'cèntims')), + 'SVC': (('colón', 'colons'), GENERIC_CENTS), + 'SYP': (('lliura', 'lliures'), ('piastre', 'piastres')), + 'SZL': (('lilangeni', 'emalangeni'), ('cèntim', 'cèntims')), + 'TJS': (('somoni', 'somoni'), ('diram', 'diram')), + 'TMT': (('manat', 'manats'), ('teňňesi', 'teňňesi')), + 'TND': (('dinar', 'dinars'), ('mil·lim', 'mil·limat')), + 'TOP': (('paanga', 'paangas'), ('seniti', 'seniti')), + 'TTD': (GENERIC_DOLLARS, ('cèntim', 'cèntims')), + 'TWD': (('nou dòlar', 'nous dòlars'), ('fen', 'fen')), + 'TZS': (('xíling', 'xílings'), ('cèntim', 'cèntims')), + 'UGX': (('xíling', 'xílings'), ('cèntim', 'cèntims')), + 'UYU': (('peso', 'pesos'), ('centèsim', 'centèsims')), + 'UZS': (('som', 'som'), ('tiyin', 'tiyin')), + 'VND': (('dong', 'dongs'), ('xu', 'xu')), + 'VUV': (('vatu', 'vatus'), ('cèntim', 'cèntims')), + 'WST': (('tala', 'tala'), ('sene', 'sene')), + 'XAF': (('franc CFA', 'francs CFA'), ('cèntim', 'cèntims')), + 'XCD': (GENERIC_DOLLARS, ('cèntim', 'cèntims')), + 'XOF': (('franc CFA', 'francs CFA'), ('cèntim', 'cèntims')), + 'XPF': (('franc CFP', 'francs CFP'), ('cèntim', 'cèntims')), + 'YER': (('rial', 'rials'), ('fils', 'fils')), + 'YUM': (('dinar', 'dinars'), ('para', 'para')), + 'ZMW': (('kwacha', 'kwacha'), ('ngwee', 'ngwee')), + 'ZWL': (GENERIC_DOLLARS, ('cèntim', 'cèntims')), + 'ZWL': (GENERIC_DOLLARS, ('cèntim', 'cèntims')), + } + + GIGA_SUFFIX = None + MEGA_SUFFIX = "ilió" + + def setup(self): + lows = ["quadr", "tr", "b", "m"] + self.high_numwords = self.gen_high_numwords([], [], lows) + self.negword = "menys " + self.pointword = "punt" + self.errmsg_nonnum = "type(%s) no és [long, int, float]" + self.errmsg_floatord = "El float %s no pot ser tractat com un" \ + " ordinal." + self.errmsg_negord = "El número negatiu %s no pot ser tractat" \ + " com un ordinal." + self.errmsg_toobig = "abs(%s) ha de ser inferior a %s." + self.gender_stem = "è" + self.exclude_title = ["i", "menys", "punt"] + + self.mid_numwords = [ + (1000, "mil"), + (100, "cent"), + (90, "noranta"), + (80, "vuitanta"), + (70, "setanta"), + (60, "seixanta"), + (50, "cinquanta"), + (40, "quaranta"), + (30, "trenta"), + ] + self.low_numwords = [ + "vint-i-nou", + "vint-i-vuit", + "vint-i-set", + "vint-i-sis", + "vint-i-cinc", + "vint-i-quatre", + "vint-i-tres", + "vint-i-dos", + "vint-i-un", + "vint", + "dinou", + "divuit", + "disset", + "setze", + "quinze", + "catorze", + "tretze", + "dotze", + "onze", + "deu", + "nou", + "vuit", + "set", + "sis", + "cinc", + "quatre", + "tres", + "dos", + "un", + "zero", + ] + self.mid_num = { + 1000: "mil", + 100: "cent", + 90: "noranta", + 80: "vuitanta", + 70: "setanta", + 60: "seixanta", + 50: "cinquanta", + 40: "quaranta", + 30: "trenta", + 20: "vint", + 10: "deu", + } + self.low_num = { + 0: "zero", + 1: "un", + 2: "dos", + 3: "tres", + 4: "quatre", + 5: "cinc", + 6: "sis", + 7: "set", + 8: "vuit", + 9: "nou", + 10: "deu", + 11: "onze", + 12: "dotze", + 13: "tretze", + 14: "catorze", + 15: "quinze", + 16: "setze", + 17: "disset", + 18: "divuit", + 19: "dinou", + 20: "vint", + 21: "vint-i-un", + 22: "vint-i-dos", + 23: "vint-i-tres", + 24: "vint-i-quatre", + 25: "vint-i-cinc", + 26: "vint-i-sis", + 27: "vint-i-set", + 28: "vint-i-vuit", + 29: "vint-i-nou", + } + self.ords = { + 1: "primer", + 2: "segon", + 3: "tercer", + 4: "quart", + 5: "cinqu", + 6: "sis", + 7: "set", + 8: "vuit", + 9: "nov", + 10: "des", + 11: "onz", + 12: "dotz", + 13: "tretz", + 14: "catorz", + 15: "quinz", + 16: "setz", + 17: "disset", + 18: "divuit", + 19: "dinov", + 20: "vint", + 30: "trent", + 40: "quarant", + 50: "cinquant", + 60: "seixant", + 70: "setant", + 80: "vuitant", + 90: "norant", + 100: "cent", + 200: "dos-cent", + 300: "tres-cent", + 400: "quatre-cent", + 500: "cinc-cent", + 600: "sis-cent", + 700: "set-cent", + 800: "vuit-cent", + 900: "nou-cent", + 1e3: "mil", + 1e6: "milion", + 1e9: "mil milion", + 1e12: "bilion", + 1e15: "mil bilion", + } + + self.ords_2 = {1: "1r", 2: "2n", 3: "3r", 4: "4t"} + self.ords_3 = { + 1: "unè", + 2: "dosè", + 3: "tresè", + 4: "quatrè", + 5: "cinquè", + 6: "sisè", + 7: "setè", + 8: "vuitè", + 9: "novè", + } + + def merge(self, curr, next): + ctext, cnum, ntext, nnum = curr + next + if cnum == 1: + if nnum < 1000000: + return next + ctext = "un" + + if nnum < cnum: + if cnum < 100: + return "%s-%s" % (ctext, ntext), cnum + nnum + elif nnum == 1: + return "%s %s" % (ctext, ntext), cnum + nnum + elif cnum == 100: + return "%s %s" % (ctext, ntext), cnum + nnum + else: + return "%s %s" % (ctext, ntext), cnum + nnum + elif (not nnum % 1000000) and cnum > 1: + ntext = ntext[:-3] + "lions" + if nnum == 100: + ntext += "s" + ctext += "-" + else: + ntext = " " + ntext + return (ctext + ntext, cnum * nnum) + + def to_ordinal(self, value): + self.verify_ordinal(value) + if value == 0: + text = "" + elif value < 5: + text = self.ords[value] + elif value <= 20: + text = "%s%s" % (self.ords[value], self.gender_stem) + elif value <= 30: + frac = value % 10 + text = "%s%s%s" % (self.ords[20], "-i-", self.ords_3[frac]) + elif value < 100: + dec = (value // 10) * 10 + text = "%s%s%s%s" % (self.ords[dec], "a", + "-", self.ords_3[value - dec]) + elif value == 1e2: + text = "%s%s" % (self.ords[value], self.gender_stem) + elif value < 2e2: + cen = (value // 100) * 100 + text = "%s %s" % (self.ords[cen], self.to_ordinal(value - cen)) + elif value < 1e3: + cen = (value // 100) * 100 + text = "%s%s %s" % (self.ords[cen], "s", + self.to_ordinal(value - cen)) + elif value == 1e3: + text = "%s%s" % (self.ords[value], self.gender_stem) + elif value < 1e6: + dec = 1000 ** int(math.log(int(value), 1000)) + high_part, low_part = divmod(value, dec) + cardinal = self.to_cardinal(high_part) if high_part != 1 else "" + text = "%s %s %s" % (cardinal, self.ords[dec], + self.to_ordinal(low_part)) + elif value < 1e18: + dec = 1000 ** int(math.log(int(value), 1000)) + high_part, low_part = divmod(value, dec) + cardinal = self.to_cardinal(high_part) if high_part != 1 else "" + text = "%s%s%s %s" % (cardinal, self.ords[dec], + self.gender_stem, self.to_ordinal(low_part)) + else: + part1 = self.to_cardinal(value) + text = "%s%s" % (part1[:-1], "onè") + return text.strip() + + def to_ordinal_num(self, value): + self.verify_ordinal(value) + if value not in self.ords_2: + return "%s%s" % (value, "è" if self.gender_stem == "è" else "a") + else: + return self.ords_2[value] + + def to_currency(self, val, currency="EUR", cents=True, + separator=" amb", adjective=False): + result = super(Num2Word_CA, self).to_currency( + val, currency=currency, cents=cents, + separator=separator, adjective=adjective + ) + list_result = result.split(separator + " ") + + if currency in CURRENCIES_UNA: + list_result[0] = list_result[0].replace("un", "una") + list_result[0] = list_result[0].replace("dos", "dues") + list_result[0] = list_result[0].replace("cents", "centes") + + list_result[0] = list_result[0].replace("vint-i-un", "vint-i-un") + list_result[0] = list_result[0].replace(" i un", "-un") + list_result[0] = list_result[0].replace("un", "un") + + if currency in CENTS_UNA: + list_result[1] = list_result[1].replace("un", "una") + list_result[1] = list_result[1].replace("dos", "dues") + + list_result[1] = list_result[1].replace("vint-i-un", "vint-i-una") + + list_result[1] = list_result[1].replace("un", "un") + + result = (separator + " ").join(list_result) + + return result diff --git a/num2words/lang_CE.py b/num2words/lang_CE.py new file mode 100644 index 00000000..abf8e5f0 --- /dev/null +++ b/num2words/lang_CE.py @@ -0,0 +1,522 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2023, Johannes Heinecke. 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 + +from __future__ import unicode_literals + +from .currency import parse_currency_parts +from .lang_EU import Num2Word_EU + +# Chechen numbers inflect in case if without noun or +# use a special oblique ending when followed by a counted noun +# 4, 14, 40 and composites thereof agree in class (gender) with the +# noun. Chechen has 6 classes which are indicated by the initial +# letter of 4, 14 and 40. By default it is "д" but +# it can also be "б", "й" or "в". +# Indicate the needed class prefix as follows +# num2words(4, lang='ce', case="abs", clazz="б") + + +CARDINALS = { + "casenames": { + "abs": "Им.", + "gen": "Род.", + "dat": "Дат.", + "erg": "Эрг;", + "instr": "Твор.", + "mat": "Вещ.", + "comp": "Сравнит.", + "all": "Местн.", + }, + "casesuffix_cons": { # to be added to numerals with final consonant + "gen": "аннан", + "dat": "анна", + "erg": "амма", + "instr": "анца", + "mat": "аннах", + "comp": "аннал", + "all": "анга", + "obl": "ан", + "ORD": "алгӀа", + }, + "casesuffix_voc": { # to be added to numerals with final vowel + "gen": "ннан", + "dat": "нна", + "erg": "мма", + "instr": "нца", + "mat": "ннах", + "comp": "ннал", + "all": "нга", + "obl": "н", + "ORD": "лгӀа", + }, + 0: { + "attr": "ноль", + "abs": "ноль", + "gen": "нолан", + "dat": "нолана", + "erg": "ноло", + "instr": "ноланца", + "mat": "ноланах", + "comp": "ноланал", + "all": "ноланга", + }, + 1: { + "attr": "цхьа", # in front of nouns in ABS + "obl": "цхьана", # with nouns in other cases than ABS + "abs": "цхьаъ", + "gen": "цхьаннан", + "dat": "цхьанна", + "erg": "цхьамма", + "instr": "цхьаьнца", + "mat": "цхьаннах", + "comp": "цхьаннал", + "all": "цхаьнга", + "ORD": "цхьалгӀа", + }, + 2: { + "attr": "ши", # in front of 100, 1000 + "obl": "шина", + "abs": "шиъ", + "gen": "шиннан", + "dat": "шинна", + "erg": "шимма", + "instr": "шинца", + "mat": "шиннах", + "comp": "шиннал", + "all": "шинга", + "ORD": "шолгӀа", + }, + 3: { + "attr": "кхо", + "obl": "кхона", + "abs": "кхоъ", + "gen": "кхааннан", + "dat": "кхаанна", + "erg": "кхаамма", + "instr": "кхаанца", + "mat": "кхааннах", + "comp": "кхааннал", + "all": "кхаанга", + "ORD": "кхоалгӀа", + }, + 4: { + "attr": "д*и", + "obl": "д*еа", + "abs": "д*иъ", + "gen": "д*еаннан", + "dat": "д*еанна", + "erg": "д*еамма", + "instr": "д*еанца", + "mat": "д*еаннах", + "comp": "д*еаннал", + "all": "д*еанга", + "ORD": "д*оьалгӀа", + }, + 5: { + "attr": "пхи", + "obl": "пхеа", + "abs": "пхиъ", + "gen": "пхеаннан", + "dat": "пхеанна", + "erg": "пхеамма", + "instr": "нхеанца", + "mat": "пхеаннах", + "comp": "пхеаннал", + "all": "пхеанга", + "ORD": "пхоьалгӀа", + }, + 6: { + "abs": "ялх", + "attr": "ялх", + "ORD": "йолхалгӀа", + }, + 7: { + "abs": "ворхӀ", + "attr": "ворхӀ", + "ORD": "ворхӀалгӀа", + }, + 8: { + "abs": "бархӀ", + "attr": "бархӀ", + "ORD": "борхӀалӀа", + }, + 9: { + "abs": "исс", + "attr": "исс", + "ORD": "уьссалгӀа", + }, + 10: { + "attr": "итт", + "abs": "итт", + "gen": "иттаннан", + "dat": "иттанна", + "erg": "иттамма", + "instr": "иттанца", + "mat": "иттаннах", + "comp": "иттаннал", + "all": "иттанга", + "ORD": "уьтталгӀа", + }, + 11: { + "abs": "цхьайтта", + "attr": "цхьайтта", + "ORD": "цхьайтталгӀа", + }, + 12: { + "abs": "шийтта", + "attr": "шийтта", + "ORD": "шийтталга", + }, + 13: { + "abs": "кхойтта", + "attr": "кхойтта", + "ORD": "кхойтталгӀа", + }, + 14: { + "abs": "д*ейтта", + "attr": "д*ейтта", + "ORD": "д*ейтталгӀа", + }, + 15: { + "abs": "пхийтта", + "attr": "пхийтта", + "ORD": "пхийтталгӀа", + }, + 16: { + "abs": "ялхитта", + "attr": "ялхитта", + "ORD": "ялхитталгӀа", + }, + 17: { + "abs": "вуьрхӀитта", + "attr": "вуьрхӀитта", + "ORD": "вуьрхӀитталгӀа", + }, + 18: { + "abs": "берхӀитта", + "attr": "берхӀитта", + "ORD": "берхитталӀа", + }, + 19: { + "abs": "ткъайесна", + "attr": "ткъайесна", + "ORD": "ткъаесналгӀа", + }, + 20: { + "abs": "ткъа", + "gen": "ткъаннан", + "dat": "ткъанна", + "erg": "ткъамма", + "instr": "ткъанца", + "mat": "ткъаннах", + "comp": "ткъаннал", + "all": "ткъанга", + "attr": "ткъе", + "ORD": "ткъолгӀа", + }, + 40: { + "abs": "шовзткъа", + "attr": "шовзткъе", + "ORD": "шовзткъалгІа", + }, + 60: { + "abs": "кхузткъа", + "attr": "кхузткъе", + "ORD": "кхузткъалгІа", + }, + 80: { + "abs": "дезткъа", + "attr": "дезткъе", + "ORD": "дезткъалгІа", + }, + 100: { + "attr": "бӀе", + "abs": "бӀе", + "obl": "бӀен", + "gen": "бӀеннан", + "dat": "бӀенна", + "erg": "бӀемма", + "instr": "бӀенца", + "mat": "бӀеннах", + "comp": "бӀеннал", + "all": "бӀенга", + "ORD": "бІолгІа", + }, + 1000: { + "attr": "эзар", + "abs": "эзар", + "obl": "эзаран", + "gen": "эзарнан", + "dat": "эзарна", + "erg": "эзарно", + "instr": "эзарнаца", + "mat": "эзарнах", + "comp": "эзарнал", + "all": "эзаранга", + "ORD": "эзарлагІа", + }, + 1000000: { + "attr": "миллион", + "abs": "миллион", + "ORD": "миллионалгІа", + }, +} + +ILLIONS = { + 6: { + "attr": "миллион", + "abs": "миллион", + "ORD": "миллионалгІа", + }, + 9: { + "attr": "миллиард", + "abs": "миллиард", + "ORD": "миллиардалгІа", + }, + 12: { + "attr": "биллион", + "abs": "биллион", + "ORD": "биллионалгІа", + }, + 15: { + "attr": "биллиард", + "abs": "биллиард", + "ORD": "биллиардалгІа", + }, + 18: { + "attr": "триллион", + "abs": "триллион", + "ORD": "триллионалгІа", + }, + 21: { + "attr": "триллиард", + "abs": "триллиард", + "ORD": "триллиардалгІа", + }, + 24: { + "attr": "квадриллион", + "abs": "квадриллион", + "ORD": "квадриллионалгІа", + }, + 27: { + "attr": "квадриллиард", + "abs": "квадриллиард", + "ORD": "квадриллиардалгІа", + }, + 30: { + "attr": "квинтиллион", + "abs": "квинтиллион", + "ORD": "квинтиллионалгІа", + }, + 33: { + "attr": "квинтиллиард", + "abs": "квинтиллиард", + "ORD": "квинтиллиардалгІа", + }, +} + + +MINUS = "минус" +# DECIMALPOINT = "запятая" # check ! +DECIMALPOINT = "а" + + +class Num2Word_CE(Num2Word_EU): + CURRENCY_FORMS = { + # currency code: (sg, pl), (sg, pl) + "EUR": (("Евро", "Евро"), ("Сент", "Сенташ")), + "RUB": (("Сом", "Сомаш"), ("Кепек", "Кепекаш")), + "USD": (("Доллар", "Доллараш"), ("Сент", "Сенташ")), + "GBP": (("Фунт", "Фунташ"), ("Пенни", "Пенни")), + } + + def setup(self): + Num2Word_EU.setup(self) + self.negword = "минус" + self.pointword = "запятая" # check ! + # self.errmsg_nonnum = ( + # u"Seulement des nombres peuvent être convertis en mots." + # ) + # self.errmsg_toobig = ( + # u"Nombre trop grand pour être converti en mots (abs(%s) > %s)." + # ) + # self.exclude_title = ["et", "virgule", "moins"] + self.mid_numwords = [] + self.low_numwords = [] + self.ords = {} + + def to_ordinal(self, number, clazz="д"): + # implement here your code. number is the integer to + # be transformed into an ordinal as a word (str) + # which is returned + return self.to_cardinal(number, clazz=clazz, case="ORD") + + def to_cardinal(self, number, clazz="д", case="abs"): + if isinstance(number, float): + entires = self.to_cardinal(int(number)) + float_part = str(number).split(".")[1] + postfix = " ".join( + # Drops the trailing zero and comma + [self.to_cardinal(int(c)) for c in float_part] + ) + return entires + " " + DECIMALPOINT + " " + postfix + + elif number < 20: + return self.makecase(number, case, clazz) + elif number < 100: + twens = number // 20 + units = number % 20 + base = twens * 20 + if units == 0: + return self.makecase(number, case, clazz) + else: + twenties = self.makecase(base, "attr", clazz) + rest = self.to_cardinal(units, clazz=clazz, case=case) + return twenties + " " + rest.replace("д*", clazz) + elif number < 1000: + hundreds = number // 100 + tens = number % 100 + if hundreds > 1: + hundert = ( + CARDINALS[hundreds]["attr"].replace("д*", clazz) + " " + ) + else: + hundert = "" + if tens != 0: + rest = self.to_cardinal(tens, clazz=clazz, case=case) + return hundert + CARDINALS[100]["abs"] + " " + rest + else: + return hundert + self.makecase(100, case, clazz) + elif number < 1000000: + thousands = number // 1000 + hundert = number % 1000 + if hundert > 0: + tcase = "attr" + else: + tcase = case + if thousands > 1: + tausend = ( + self.to_cardinal(thousands, clazz=clazz, case="attr") + + " " + + CARDINALS[1000][tcase] + ) + else: + tausend = self.makecase(1000, tcase, clazz) + + if hundert != 0: + rest = " " + self.to_cardinal(hundert, clazz=clazz, case=case) + else: + rest = "" + return tausend + rest + + elif number < 10**34: + out = [] + for pot in reversed([6, 9, 12, 15, 18, 21, 24, 27, 30, 33]): + # 3 digits of billion, trillion etc + step = number // 10**pot % 1000 + if step > 0: + words = self.to_cardinal(step, clazz=clazz, case="attr") + out.append(words + " " + ILLIONS[pot]["attr"]) + rest = number % 10**6 + if rest: + out.append(self.to_cardinal(rest, clazz=clazz, case=case)) + return " ".join(out) + + return "NOT IMPLEMENTED" + + def _money_verbose(self, number, currency, case): + mcase = "attr" + if case != "abs": + mcase = "obl" + return self.to_cardinal(number, case=mcase) + + def _cents_verbose(self, number, currency, case): + mcase = "attr" + if case != "abs": + mcase = "obl" + return self.to_cardinal(number, case=mcase) + + def to_currency( + self, + val, + currency="RUB", + cents=True, + separator=",", + adjective=False, + case="abs", + ): + """ + Args: + val: Numeric value + currency (str): Currency code + cents (bool): Verbose cents + separator (str): Cent separator + adjective (bool): Prefix currency name with adjective + Returns: + str: Formatted string + + """ + left, right, is_negative = parse_currency_parts(val) + + try: + cr1, cr2 = self.CURRENCY_FORMS[currency] + devise = cr1[0] + centime = cr2[0] + except KeyError: + raise NotImplementedError( + 'Currency code "%s" not implemented for "%s"' + % (currency, self.__class__.__name__) + ) + + minus_str = "%s " % self.negword.strip() if is_negative else "" + money_str = self._money_verbose(left, currency, case) + cents_str = ( + self._cents_verbose(right, currency, case) + if cents + else self._cents_terse(right, currency) + ) + + return "%s%s %s%s %s %s" % ( + minus_str, + money_str, + devise, # always singular + separator, + cents_str, + centime, + ) + + def to_ordinal_num(self, number): + self.verify_ordinal(number) + return str(number) + "-й" + + def to_year(self, year, case="abs"): + return self.to_cardinal(year, case=case) + + def makecase(self, number, case, clazz): + # print("ZZZZ", number, CARDINALS[number]) + if case in CARDINALS[number]: + return CARDINALS[number][case].replace("д*", clazz) + else: + if CARDINALS[number]["abs"][-1] in "а": + return ( + CARDINALS[number]["abs"].replace("д*", clazz) + + CARDINALS["casesuffix_voc"][case] + ) + else: + return ( + CARDINALS[number]["abs"].replace("д*", clazz) + + CARDINALS["casesuffix_cons"][case] + ) diff --git a/num2words/lang_CZ.py b/num2words/lang_CS.py similarity index 99% rename from num2words/lang_CZ.py rename to num2words/lang_CS.py index 04c44a07..6024b77d 100644 --- a/num2words/lang_CZ.py +++ b/num2words/lang_CS.py @@ -84,7 +84,7 @@ } -class Num2Word_CZ(Num2Word_Base): +class Num2Word_CS(Num2Word_Base): CURRENCY_FORMS = { 'CZK': ( ('koruna', 'koruny', 'korun'), ('halíř', 'halíře', 'haléřů') diff --git a/num2words/lang_CY.py b/num2words/lang_CY.py new file mode 100644 index 00000000..e5045129 --- /dev/null +++ b/num2words/lang_CY.py @@ -0,0 +1,607 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2023, Johannes Heinecke. 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 + +from __future__ import unicode_literals + +from .currency import parse_currency_parts +from .lang_EU import Num2Word_EU + +# Welsh numerals differs to many other languages since the counted +# object does not follow the numeral but is inserted between +# e.g. "23 hours" is +# tri awr ar hugain +# 3 hour on twenty +# in addition to that some numeral trigger a mutation on the following word +# either another numeral or the counted object +# (https://en.wikipedia.org/wiki/Consonant_mutation#Welsh) +# e.g. "23 dogs" (aspirated mutation, c -> ch) +# tri chi ar hugain +# 3 dog on twenty +# but "22 dogs" (soft mutation, c -> g) +# dau gi ar hugain +# 2 dog on twenty +# and "24 dogs" (no mutation) +# pedwar ci ar hugain +# 4 dog on twenty +# (BTW, the counted word is always in singular when following a numeral) +# numerals are mutated as well +# e.g. "300" +# tri chant +# 3 hundred +# "200" +# dau gant +# 2 hundred +# "500" +# pump cant +# 5 hundreds +# the numerals for 2, 3 and 4 are different in function of gender (MASC, FEM) +# 2 cats +# dwy gath + +# 2 dogs +# dau gi + +# 2000 +# dwy fil + +# 3000 +# tair mil + +# to add the counted object in the correct position use +# num2words(17, lang="cy", counted="ci", gender="masc") +# num2words(17, lang="cy", counted="cath", gender="fem") +# if the number is > 99, use plural form of counted object +# num2words(117, lang="cy", counted="cathod", gender="fem") + + +# Globals +# ------- + +OBJ = "__OBJECT__" + +CARDINAL_WORDS = { + # masc, fem, triggers mutation + 0: [("dim", None), (OBJ, None)], + 1: [("un", None), (OBJ, None)], + 2: [("dau", "SM"), (OBJ, None)], + 3: [("tri", "AM"), (OBJ, None)], + 4: [("pedwar", None), (OBJ, None)], + 5: [("pump", None), (OBJ, None)], + 6: [("chwech", "AM"), (OBJ, None)], + 7: [("saith", None), (OBJ, None)], + 8: [("wyth", None), (OBJ, None)], + 9: [("naw", None), (OBJ, None)], + 10: [("deg", None), (OBJ, None)], + 11: [("un", None), (OBJ, None), ("ar ddeg", None)], + 12: [("deuddeg", None), (OBJ, None)], + 13: [("tri", "AM"), (OBJ, None), ("ar ddeg", None)], + 14: [("pedwar", None), (OBJ, None), ("ar ddeg", None)], + 15: [("pymtheg", None), (OBJ, None)], + 16: [("un", None), (OBJ, None), ("ar bymtheg", None)], + 17: [("dau", "SM"), (OBJ, None), ("ar bymtheg", None)], + 18: [("deunaw", None), (OBJ, None)], + 19: [("pedwar", None), ("ar bymtheg", None)], +} + +CARDINAL_WORDS_FEM = { + # masc, fem, triggers mutation + 0: [("dim", None), (OBJ, None)], + 1: [("un", None), (OBJ, None)], + 2: [("dwy", "SM"), (OBJ, None)], + 3: [("tair", None), (OBJ, None)], + 4: [("pedair", None), (OBJ, None)], + 5: [("pump", None), (OBJ, None)], + 6: [("chwech", "AM"), (OBJ, None)], + 7: [("saith", None), (OBJ, None)], + 8: [("wyth", None), (OBJ, None)], + 9: [("naw", None), (OBJ, None)], + 10: [("deg", None), (OBJ, None)], + 11: [("un", None), (OBJ, None), ("ar ddeg", None)], + 12: [("deuddeg", None), (OBJ, None)], + 13: [("tair", None), (OBJ, None), ("ar ddeg", None)], + 14: [("pedair", None), (OBJ, None), ("ar ddeg", None)], + 15: [("pymtheg", None), (OBJ, None)], + 16: [("un", None), (OBJ, None), ("ar bymtheg", None)], + 17: [("dwy", "SM"), (OBJ, None), ("ar bymtheg", None)], + 18: [("deunaw", None), (OBJ, None)], + 19: [("pedair", None), ("ar bymtheg", None)], +} + +MILLION_WORDS = { + 3: ("mil", None), + 6: ("miliwn", None), + 9: ("biliwn", None), + 12: ("triliwn", None), + 15: ("cwadriliwn", None), + 18: ("cwintiliwn", None), + 21: ("secsttiliwn", None), + 24: ("septiliwn", None), + 27: ("octiliwn", None), + 30: ("noniliwn", None), + 33: ("dengiliwn", None), +} + +ORDINAL_WORDS = { + 0: [("dimfed", None), (OBJ, None)], + 1: [(OBJ, None), ("cyntaf", None)], + 2: [("ail", "SM"), (OBJ, None)], + 3: [("trydydd", None), (OBJ, None)], + 4: [("pedwerydd", None), (OBJ, None)], + 5: [("pumed", None), (OBJ, None)], + 6: [("chweched", None), (OBJ, None)], + 7: [("saithfed", None), (OBJ, None)], + 8: [("wythfed", None), (OBJ, None)], + 9: [("nawfed", None), (OBJ, None)], + 10: [("degfed", None), (OBJ, None)], + 11: [("unfed", "SM"), (OBJ, None), ("ar ddeg", None)], + 12: [("deuddegfed", None), (OBJ, None)], + 13: [("trydydd", None), (OBJ, None), ("ar ddeg", None)], + 14: [("pedwerydd", None), (OBJ, None), ("ar ddeg", None)], + 15: [("pymthegfed", None), (OBJ, None)], + 16: [("unfed", None), (OBJ, None), ("ar bymtheg", None)], + 17: [("ail", "SM"), (OBJ, None), ("ar bymtheg", None)], + 18: [("deunawfed", None), (OBJ, None)], + 19: [("pedwerydd", None), (OBJ, None), ("ar bymtheg", None)], +} +ORDINAL_WORDS_FEM = { + 0: [("dimfed", None), (OBJ, None)], + 1: [(OBJ, None), ("gyntaf", None)], + 2: [("ail", "SM"), (OBJ, None)], + 3: [("trydedd", "SM"), (OBJ, None)], + 4: [("pedwaredd", "SM"), (OBJ, None)], + 5: [("pumed", None), (OBJ, None)], + 6: [("chweched", None), (OBJ, None)], + 7: [("saithfed", None), (OBJ, None)], + 8: [("wythfed", None), (OBJ, None)], + 9: [("nawfed", None), (OBJ, None)], + 10: [("degfed", None), (OBJ, None)], + 11: [("unfed", "SM"), (OBJ, None), ("ar ddeg", None)], + 12: [("deuddegfed", None), (OBJ, None)], + 13: [("trydedd", "SM"), (OBJ, None), ("ar ddeg", None)], + 14: [("pedwaredd", "SM"), (OBJ, None), ("ar ddeg", None)], + 15: [("pymthegfed", None), (OBJ, None)], + 16: [("unfed", None), (OBJ, None), ("ar bymtheg", None)], + 17: [("ail", "SM"), (OBJ, None), ("ar bymtheg", None)], + 18: [("deunawfed", None), (OBJ, None)], + 19: [("pedwaredd", None), (OBJ, None), ("ar bymtheg", None)], +} + +# The script can extrapolate the missing numbers from the base forms. +STR_TENS = { + 1: [("ugain", None), (OBJ, None)], + 2: [("deugain", None), (OBJ, None)], + 3: [("trigain", None), (OBJ, None)], + 4: [("pedwar ugain", None), (OBJ, None)], +} + +ORD_STR_TENS = { + 1: [("ugainfed", None), (OBJ, None)], + 2: [("deugainfed", None), (OBJ, None)], + 3: [("trigainfed", None), (OBJ, None)], + 4: [("pedwar ugainfed", None), (OBJ, None)], +} + +STR_TENS_INFORMAL = { + 1: ("undeg", None), + 2: ("dauddeg", None), + 3: ("trideg", None), + 4: ("pedwardeg", None), + 5: ("pumdeg", None), + 6: ("chwedeg", None), + 7: ("saithdeg", None), + 8: ("wythdeg", None), + 9: ("nawdeg", None), +} + + +GENERIC_DOLLARS = ("dolar", "dolarau") +GENERIC_CENTS = ("ceiniog", "ceiniogau") + +CURRENCIES_FEM = ["GBP"] + + +class Num2Word_CY(Num2Word_EU): + CURRENCY_FORMS = { + # currency code: (sg, pl), (sg, pl) + # in Welsh a noun after a numeral is ALWAYS in the singular + "EUR": (("euro", "euros"), GENERIC_CENTS), + "USD": (GENERIC_DOLLARS, GENERIC_CENTS), + "GBP": (("punt", "punnoedd"), ("ceiniog", "ceiniogau")), + "CNY": (("yuan", "yuans"), ("ffen", "ffens")), + } + + MINUS_PREFIX_WORD = "meinws " + FLOAT_INFIX_WORD = " pwynt " + +# def setup(self): +# Num2Word_EU.setup(self) + + def __init__(self): + pass + + def float_to_words(self, float_number): + # if ordinal: + # prefix = self.to_ordinal(int(float_number)) + # else: + prefix = self.to_cardinal(int(float_number)) + float_part = str(float_number).split(".")[1] + postfix = " ".join( + # Drops the trailing zero and comma + [self.to_cardinal(int(c)) for c in float_part] + ) + return prefix + Num2Word_CY.FLOAT_INFIX_WORD + postfix + + def hundred_group( + self, number, informal=False, gender="masc", ordinal=False + ): + hundreds = number // 100 + until100 = number % 100 # 0 - 99 + # list group of number words and mutation info (for the following word) + result = ( + [] + ) + if gender == "fem": + CW = CARDINAL_WORDS_FEM + else: + if ordinal: + CW = ORDINAL_WORDS + else: + CW = CARDINAL_WORDS + + if hundreds > 0: + if hundreds > 1: + result.extend((CARDINAL_WORDS[hundreds])) + result.extend([("cant", None), (OBJ, None)]) + if until100: + if until100 in [ + 1, + 8, + 11, + 16, + 20, + 21, + 31, + 36, + 41, + 48, + 61, + 68, + 71, + 81, + 88, + 91, + ]: + result.append(("ac", None)) + else: + result.append(("a", "AM")) + if until100: + # if informal: + # pass + if not ordinal and until100 >= 50 and until100 <= 59: + units = number % 10 + if hundreds > 0: + if units == 0: + result.append(("hanner", None)) + elif units == 1: + result.extend([("hanner ac un", None), (OBJ, None)]) + else: + result.append(("hanner a", "AM")) + result.extend(CW[units]) + else: + if units == 0: + result.extend([("hanner cant", None), (OBJ, None)]) + elif units == 1: + result.extend( + [("hanner cant ac un", None), (OBJ, None)] + ) + else: + result.append(("hanner cant a", "AM")) + result.extend(CW[units]) + else: + if (number < 20 and number > 0) or ( + number == 0 and hundreds == 0 + ): + if gender == "fem": + result.extend(CARDINAL_WORDS_FEM[int(number)]) + else: + result.extend(CARDINAL_WORDS[int(number)]) + + else: + tens = until100 // 20 + units = number % 20 + if ordinal and units == 0: + degau = ORD_STR_TENS.get(tens) + else: + degau = STR_TENS.get(tens) + + if units != 0: + if tens > 1: + result.extend(CW[units]) + if degau: + result.append(("a", "AM")) + result.extend(degau) + else: + result.extend(CW[units]) + if degau: + result.append(("ar", "SM")) + result.extend(degau) + elif degau: + result.extend(degau) + return result + + def to_ordinal(self, number, informal=False, gender="masc"): + if number < 20: + return makestring(ORDINAL_WORDS[number]) + if number == 100: + return "canfed" + elif number > 100: + raise NotImplementedError("The given number is too large.") + + return self.to_cardinal( + number, informal=False, gender=gender, ordinal=True + ) + + def to_cardinal( + self, + number, + informal=False, + gender="masc", + ordinal=False, + counted=None, + raw=False, + ): + negative = False + if number < 0: + negative = True + number = -1 * number + if number == 0: + if raw: + return CARDINAL_WORDS[0] + else: + return makestring(CARDINAL_WORDS[0]) + elif not number < 999 * 10**33: + raise NotImplementedError("The given number is too large.") + + elif isinstance(number, float): + return self.float_to_words(number) + + # split in groups of 10**3 + # groups of three digits starting from right (units (1 - 999), + # thousands, millions, ...) + groups = ( + [] + ) + lowestgroup = ( + None # find the lowest group of 3 digits > 0 for the ordinals + ) + for pot in [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36]: + gr = (number % 10**pot) // 10 ** (pot - 3) + groups.append((gr, pot)) + if gr and not lowestgroup: + lowestgroup = gr + # print("groups", groups) + + result = [] + if negative: + result.append(("meinws", None)) + + for gr, pot in reversed(groups): + if gr: + # print("AAAA", gr, pot, gender) + if pot == 6: + g = "fem" # mil (1000) is feminine + elif pot == 3: + g = gender # units depend on the following noun + else: + g = "masc" # millions etc are masculine + # "mil" is feminine + if gr > 1 or pot == 3: + words = self.hundred_group( + gr, + informal=informal, + gender=g, + ordinal=ordinal and (lowestgroup == gr), + ) + result += words + # print(">>>> ", words) + if pot > 3: + result.append(MILLION_WORDS[pot - 3]) + if raw: + # need to be able trigger correct mutation on currencies + return result + else: + if number < 100: + return makestring(result, counted=counted) + else: + if counted: + result.extend([("o", "SM"), (counted, None)]) + return makestring(result) + + def to_currency( + self, val, currency="EUR", cents=True, separator=",", adjective=False + ): + """ + Args: + val: Numeric value + currency (str): Currency code + cents (bool): Verbose cents + separator (str): Cent separator + adjective (bool): Prefix currency name with adjective + Returns: + str: Formatted string + + """ + left, right, is_negative = parse_currency_parts(val) + try: + cr1, cr2 = self.CURRENCY_FORMS[currency] + + except KeyError: + raise NotImplementedError( + 'Currency code "%s" not implemented for "%s"' + % (currency, self.__class__.__name__) + ) + + # if adjective and currency in self.CURRENCY_ADJECTIVES: + # cr1 = prefix_currency(self.CURRENCY_ADJECTIVES[currency], cr1) + + minus_str = "%s " % self.negword.strip() if is_negative else "" + money_str = self._money_verbose(left, currency) + cents_str = ( + self._cents_verbose(right, currency) + if cents + else self._cents_terse(right, currency) + ) + + if right == 0: + # no pence + return "%s%s" % ( + minus_str, + money_str, + # self.pluralize(right, cr2) + ) + elif left == 0: + # no pounds + return "%s%s" % ( + minus_str, + cents_str, + # self.pluralize(right, cr2) + ) + + return "%s%s%s %s" % ( + minus_str, + money_str, + # self.pluralize(left, cr1), + separator, + cents_str, + # self.pluralize(right, cr2) + ) + + def _money_verbose(self, number, currency): + # used in super().to_currency(), we need to add gender + # here for feminine currencies + # if currency in CURRENCIES_FEM: # always true in this context + if number > 100: + m = self.to_cardinal(number, gender="fem", raw=True) + # if currency in self.CURRENCY_FORMS: + c = self.CURRENCY_FORMS[currency][0][1] + m.append(("o", "SM")) + m.append((c, None)) + # else: + # c = currency + # m.append((c, None)) + return makestring(m) + else: + # if number > 1: + m = self.to_cardinal(number, gender="fem", raw=True) + # elif number == 0: + # m = self.to_cardinal(number, gender="fem", raw=True) + # else: + # m = [(OBJ, None)] + # if currency in self.CURRENCY_FORMS: + c = self.CURRENCY_FORMS[currency][0][0] + # else: + # c = currency + # print("eeeeeeeee", m) + # m.append((c, None)) + # print("fffffffff", m) + return makestring(m, counted=c) + # else: + # return self.to_cardinal(number, raw=True) + + def _cents_verbose(self, number, currency): + if number == 0: + return "" + # elif number > 100: + # m = self.to_cardinal(number, raw=True) + # # if currency in self.CURRENCY_FORMS: + # c = self.CURRENCY_FORMS[currency][0][1] + # m.append(("o", "SM")) + # m.append((c, None)) + # # else: + # # c = currency + # # m.append((c, None)) + # return makestring(m) + else: + if number > 1: + m = self.to_cardinal(number, raw=True) + else: + m = [(OBJ, None)] + # if currency in self.CURRENCY_FORMS: + c = self.CURRENCY_FORMS[currency][1][0] + # else: + # c = currency + return makestring(m, counted=c) + + +def makestring(result, counted=None): + # concatenate numberwords with correct mutation + out = [] + lastmut = None + for w, mut in result: + if w == OBJ: + if not counted: + continue + else: + w = counted + counted = None # only first position + if lastmut: + out.append(mutate(w, lastmut)) + else: + out.append(w) + lastmut = mut + return " ".join(out) + + +def mutate(word, mutation): + # print("uuu", word, mutation) + if mutation == "SM": + return softmutation(word) + elif mutation == "AM": + return aspiratedmutation(word) + # return word # does not occur + + +def softmutation(word): + # print("SM<<<<%s>" % word) + if word[0] == "p" and word[1] != "h": + return "b" + word[1:] + elif word[0] == "t" and word[1] != "h": + return "d" + word[1:] + elif word[0] == "c" and word[1] != "h": + return "g" + word[1:] + elif word[0] == "b" or word[0] == "m": + return "f" + word[1:] + elif word[0] == "d" and word[1] != "d": + return "d" + word + elif word.startswith("ll"): + return word[1:] + elif word.startswith("rh"): + return "r" + word[2:] + elif word == "ugain": + return "hugain" + else: + return word + + +def aspiratedmutation(word): + if word[0] == "p" and word[1] != "h": + return "ph" + word[1:] + elif word[0] == "t" and word[1] != "h": + return "th" + word[1:] + elif word[0] == "c" and word[1] != "h": + return "ch" + word[1:] + else: + return word diff --git a/num2words/lang_ES_CR.py b/num2words/lang_ES_CR.py new file mode 100644 index 00000000..ee1d4440 --- /dev/null +++ b/num2words/lang_ES_CR.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2003, Taro Ogawa. All Rights Reserved. +# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. +# Copyright (c) 2024, Randall Castro. 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 + +from __future__ import print_function, unicode_literals + +from .lang_ES import Num2Word_ES + + +class Num2Word_ES_CR(Num2Word_ES): + + def to_currency(self, val, longval=True, old=False): + result = self.to_splitnum(val, hightxt="colón/es", lowtxt="céntimo/s", + divisor=1, jointxt="y", longval=longval) + # Handle exception, in spanish is "un euro" and not "uno euro" + return result.replace("uno", "un") diff --git a/num2words/lang_EU.py b/num2words/lang_EU.py index 7c07bb56..0ff74ab2 100644 --- a/num2words/lang_EU.py +++ b/num2words/lang_EU.py @@ -53,7 +53,7 @@ class Num2Word_EU(Num2Word_Base): CURRENCY_ADJECTIVES = { 'AUD': 'Australian', - 'BYN': 'Belarussian', + 'BYN': 'Belarusian', 'CAD': 'Canadian', 'EEK': 'Estonian', 'USD': 'US', diff --git a/num2words/lang_TET.py b/num2words/lang_TET.py new file mode 100644 index 00000000..141a8c66 --- /dev/null +++ b/num2words/lang_TET.py @@ -0,0 +1,251 @@ +# -*- coding: utf-8 -*-Num2Word_TET +# 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 + + +from num2words.currency import parse_currency_parts + +from .lang_EU import Num2Word_EU + +DOLLAR = ('dolar', 'dolar') +CENTS = ('sentavu', 'sentavu') + + +class Num2Word_TET(Num2Word_EU): + + CURRENCY_FORMS = { + 'AUD': (DOLLAR, CENTS), + 'CAD': (DOLLAR, CENTS), + 'EUR': (('euro', 'euros'), CENTS), + 'GBP': (('pound sterling', 'pound sterling'), ('pence', 'pence')), + 'USD': (DOLLAR, CENTS), + } + + GIGA_SUFFIX = None + MEGA_SUFFIX = "iliaun" + + def setup(self): + super().setup() + lows = ["kuatr", "tr", "b", "m"] + self.high_numwords = self.gen_high_numwords([], [], lows) + self.negword = "menus " + self.pointword = "vírgula" + self.exclude_title = ["resin", "vírgula", "menus"] + self.count = 0 + + self.mid_numwords = [ + (1000, "rihun"), (100, "atus"), (90, "sianulu"), + (80, "ualunulu"), (70, "hitunulu"), (60, "neenulu"), + (50, "limanulu"), (40, "haatnulu"), (30, "tolunulu"), + (20, "ruanulu") + ] + self.low_numwords = [ + "sanulu", + "sia", "ualu", "hitu", "neen", "lima", "haat", "tolu", "rua", + "ida", "mamuk" + ] + self.hundreds = { + 1: "atus", + 2: "atus rua", + 3: "atus tolu", + 4: "atus haat", + 5: "atus lima", + 6: "atus neen", + 7: "atus hitu", + 8: "atus ualu", + 9: "atus sia", + } + + def merge(self, curr, next): + ctext, cnum, ntext, nnum = curr + next + + if cnum == 1 and nnum < 100: + return next + + if nnum < cnum: + if nnum < 10: + value_str = str(cnum + nnum) + if int(value_str) > 100: + zero_list = value_str[1:-1] + all_zero = all(element == '0' for element in zero_list) + if all_zero: + if self.count >= 1: + self.count += 0 + return ( + "ho %s %s" % (ctext, ntext), + cnum + nnum + ) + self.count += 1 + return ("%s %s" % (ctext, ntext), cnum + nnum) + + return ("%s resin %s" % (ctext, ntext), cnum + nnum) + else: + return ("%s %s" % (ctext, ntext), cnum + nnum) + + return (ntext + " " + ctext, cnum * nnum) + + def ho_result(self, result, value): + index = result.find('ho') + count_ho = result.count('ho') + + if index != -1 and count_ho >= 1: + index_rihun = result.find('rihun') + value_str = len(str(value)) + if index_rihun != -1 and value_str > 7: + result = result.replace("rihun ho", "ho rihun") + lows = ["kuatr", "tr", "b", "m"] + MEGA_SUFFIX = "iliaun" + for low in lows: + result = result.replace( + low + MEGA_SUFFIX + " ho", "ho " + low + MEGA_SUFFIX) + remove_first_ho = result.startswith('ho') + if remove_first_ho: + result = result[3:] + return result + + def remove_ho(self, result, value): + value_str = str(value) + result = self.ho_result(result, value) + end_value = value_str[:-4] + end_true = end_value.endswith('0') + if end_true is False: + if value > 100: + if value_str[-1] != '0' and value_str[-2] == '0': + result = result.replace("ho", "") + result = result.replace(" ", " ") + + return result + + def to_cardinal(self, value): + result = super().to_cardinal(value) + + results = self.remove_ho(result, value) + return results + + def to_ordinal(self, value): + self.verify_ordinal(value) + out = "" + val = self.splitnum(value) + outs = val + while len(val) != 1: + outs = [] + left, right = val[:2] + if isinstance(left, tuple) and isinstance(right, tuple): + outs.append(self.merge(left, right)) + if val[2:]: + outs.append(val[2:]) + else: + for elem in val: + if isinstance(elem, list): + if len(elem) == 1: + outs.append(elem[0]) + else: + outs.append(self.clean(elem)) + else: + outs.append(elem) + val = outs + + words, num = outs[0] + + words = self.remove_ho(words, value) + + if num in [90, 80, 70, 60, 50, 40, 30, 20, 10, 9, 8, 7, 5, 3, 2]: + words = 'da'+words+'k' + if num in [6, 4]: + words = 'da'+words + if num == 1: + words = 'dahuluk' + if num in [900, 800, 700, 500, 300, 200, 100]: + words = 'dah'+words+'k' + if num in [600, 400]: + words = 'dah'+words + + words_split = words.split() + if len(words_split) >= 3 and num < 100: + first_word = 'da'+words_split[0] + second_word = " ".join(words_split[1:]) + if 'haat' in second_word or 'neen' in second_word: + words = first_word+" "+second_word + else: + words = first_word+" "+second_word+'k' + + word_first = 'dah'+words_split[0] + if word_first == 'dahatus' and len(words_split) >= 3: + word_second = " ".join(words_split[1:]) + if 'haat' in word_second or 'neen' in word_second: + words = word_first+" "+word_second + else: + words = word_first+" "+word_second+'k' + + if len(str(num)) > 3: + if 'haat' in words_split[-1:] or 'neen' in words_split[-1:]: + words = 'da'+words + else: + words = 'da'+words+'k' + + result = self.title(out + words) + + return result + + def to_ordinal_num(self, value): + self.verify_ordinal(value) + return "%sº" % (value) + + def to_year(self, val, longval=True): + if val < 0: + return self.to_cardinal(abs(val)) + ' antes Kristu' + return self.to_cardinal(val) + + def to_currency(self, val, currency='USD', cents=True): + """ + Args: + val: Numeric value + currency (str): Currency code + cents (bool): Verbose cents + adjective (bool): Prefix currency name with adjective + Returns: + str: Formatted string + + """ + left, right, is_negative = parse_currency_parts(val) + + try: + cr1, cr2 = self.CURRENCY_FORMS[currency] + + except KeyError: + raise NotImplementedError( + 'Currency code "%s" not implemented for "%s"' % + (currency, self.__class__.__name__)) + + minus_str = "%s " % self.negword.strip() if is_negative else "" + money_str = self._money_verbose(left, currency) + cents_str = self._cents_verbose(right, currency) \ + if cents else self._cents_terse(right, currency) + + if right == 0: + return u'%s%s %s' % ( + minus_str, + self.pluralize(left, cr1), + money_str + ) + else: + return u'%s%s %s %s %s' % ( + minus_str, + self.pluralize(left, cr1), + money_str, + self.pluralize(right, cr2), + cents_str + ) diff --git a/tests/test_base.py b/tests/test_base.py index efa1bc81..c9abe14d 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -62,3 +62,27 @@ def test_is_title(self): self.base.title("one"), "one" ) + + def test_set_high_numwords_not_implemented(self): + with self.assertRaises(NotImplementedError): + self.base.set_high_numwords() + + def test_to_ordinal_num(self): + from num2words.base import Num2Word_Base + self.base = Num2Word_Base() + self.assertEqual( + self.base.to_ordinal_num(1), + 1 + ) + self.assertEqual( + self.base.to_ordinal_num(100), + 100 + ) + self.assertEqual( + self.base.to_ordinal_num(1000), + 1000 + ) + + def test_pluralize_not_implemented(self): + with self.assertRaises(NotImplementedError): + self.base.pluralize(n=None, forms=None) diff --git a/tests/test_by.py b/tests/test_be.py similarity index 61% rename from tests/test_by.py rename to tests/test_be.py index 087c0c11..c674e98b 100644 --- a/tests/test_by.py +++ b/tests/test_be.py @@ -25,25 +25,25 @@ class Num2WordsBYTest(TestCase): def test_cardinal(self): - self.assertEqual(num2words(100, lang="by"), "сто") - self.assertEqual(num2words(101, lang="by"), "сто адзін") - self.assertEqual(num2words(110, lang="by"), "сто дзесяць") - self.assertEqual(num2words(115, lang="by"), "сто пятнаццаць") - self.assertEqual(num2words(123, lang="by"), "сто дваццаць тры") - self.assertEqual(num2words(1000, lang="by"), "адна тысяча") - self.assertEqual(num2words(1001, lang="by"), "адна тысяча адзін") - self.assertEqual(num2words(2012, lang="by"), "дзве тысячы дванаццаць") - self.assertEqual( - num2words(12519.85, lang="by"), + self.assertEqual(num2words(100, lang="be"), "сто") + self.assertEqual(num2words(101, lang="be"), "сто адзін") + self.assertEqual(num2words(110, lang="be"), "сто дзесяць") + self.assertEqual(num2words(115, lang="be"), "сто пятнаццаць") + self.assertEqual(num2words(123, lang="be"), "сто дваццаць тры") + self.assertEqual(num2words(1000, lang="be"), "адна тысяча") + self.assertEqual(num2words(1001, lang="be"), "адна тысяча адзін") + self.assertEqual(num2words(2012, lang="be"), "дзве тысячы дванаццаць") + self.assertEqual( + num2words(12519.85, lang="be"), "дванаццаць тысяч пяцьсот дзевятнаццаць коска восемдзесят пяць", ) self.assertEqual( - num2words(1234567890, lang="by"), + num2words(1234567890, lang="be"), "адзін мільярд дзвесце трыццаць чатыры мільёны пяцьсот " "шэсцьдзясят сем тысяч восемсот дзевяноста", ) self.assertEqual( - num2words(461407892039002157189883901676, lang="by"), + num2words(461407892039002157189883901676, lang="be"), "чатырыста шэсцьдзясят адзін " "актыльён чатырыста сем сэптыльёнаў восемсот дзевяноста " "два секстыльёны трыццаць дзевяць квінтыльёнаў два квадрыльёны " @@ -52,7 +52,7 @@ def test_cardinal(self): "шэсцьсот семдзесят шэсць", ) self.assertEqual( - num2words(94234693663034822824384220291, lang="by"), + num2words(94234693663034822824384220291, lang="be"), "дзевяноста чатыры актыльёны " "дзвесце трыццаць чатыры сэптыльёны шэсцьсот дзевяноста тры " "секстыльёны шэсцьсот шэсцьдзясят тры квінтыльёны трыццаць " @@ -60,250 +60,280 @@ def test_cardinal(self): "дваццаць чатыры мільярды трыста восемдзесят чатыры мільёны " "дзвесце дваццаць тысяч дзвесце дзевяноста адзін", ) - self.assertEqual(num2words(5, lang="by"), "пяць") - self.assertEqual(num2words(15, lang="by"), "пятнаццаць") - self.assertEqual(num2words(154, lang="by"), "сто пяцьдзясят чатыры") + self.assertEqual(num2words(5, lang="be"), "пяць") + self.assertEqual(num2words(15, lang="be"), "пятнаццаць") + self.assertEqual(num2words(154, lang="be"), "сто пяцьдзясят чатыры") self.assertEqual( - num2words(1135, lang="by"), "адна тысяча сто трыццаць пяць" + num2words(1135, lang="be"), "адна тысяча сто трыццаць пяць" ) self.assertEqual( - num2words(418531, lang="by"), + num2words(418531, lang="be"), "чатырыста васямнаццаць тысяч пяцьсот трыццаць адзін", ) self.assertEqual( - num2words(1000139, lang="by"), "адзін мільён сто трыццаць дзевяць" + num2words(1000139, lang="be"), "адзін мільён сто трыццаць дзевяць" ) - self.assertEqual(num2words(-1, lang="by"), "мінус адзін") - self.assertEqual(num2words(-15, lang="by"), "мінус пятнаццаць") - self.assertEqual(num2words(-100, lang="by"), "мінус сто") + self.assertEqual(num2words(-1, lang="be"), "мінус адзін") + self.assertEqual(num2words(-15, lang="be"), "мінус пятнаццаць") + self.assertEqual(num2words(-100, lang="be"), "мінус сто") def test_floating_point(self): - self.assertEqual(num2words(5.2, lang="by"), "пяць коска два") - self.assertEqual(num2words(10.02, lang="by"), "дзесяць коска нуль два") + self.assertEqual(num2words(5.2, lang="be"), "пяць коска два") + self.assertEqual(num2words(10.02, lang="be"), "дзесяць коска нуль два") self.assertEqual( - num2words(15.007, lang="by"), "пятнаццаць коска нуль нуль сем" + num2words(15.007, lang="be"), "пятнаццаць коска нуль нуль сем" ) self.assertEqual( - num2words(561.42, lang="by"), + num2words(561.42, lang="be"), "пяцьсот шэсцьдзясят адзін коска сорак два", ) self.assertEqual( - num2words(561.0, lang="by"), "пяцьсот шэсцьдзясят адзін коска нуль" + num2words(561.0, lang="be"), "пяцьсот шэсцьдзясят адзін коска нуль" ) def test_to_ordinal(self): - self.assertEqual(num2words(1, lang="by", to="ordinal"), "першы") - self.assertEqual(num2words(5, lang="by", to="ordinal"), "пяты") - self.assertEqual(num2words(6, lang="by", to="ordinal"), "шосты") - self.assertEqual(num2words(10, lang="by", to="ordinal"), "дзясяты") + self.assertEqual(num2words(1, lang="be", to="ordinal"), "першы") + self.assertEqual(num2words(5, lang="be", to="ordinal"), "пяты") + self.assertEqual(num2words(6, lang="be", to="ordinal"), "шосты") + self.assertEqual(num2words(10, lang="be", to="ordinal"), "дзясяты") - self.assertEqual(num2words(13, lang="by", to="ordinal"), "трынаццаты") - self.assertEqual(num2words(20, lang="by", to="ordinal"), "дваццаты") + self.assertEqual(num2words(13, lang="be", to="ordinal"), "трынаццаты") + self.assertEqual(num2words(20, lang="be", to="ordinal"), "дваццаты") self.assertEqual( - num2words(23, lang="by", to="ordinal"), "дваццаць трэці" + num2words(23, lang="be", to="ordinal"), "дваццаць трэці" ) self.assertEqual( - num2words(23, lang="by", to="ordinal", gender="f"), + num2words(23, lang="be", to="ordinal", gender="f"), "дваццаць трэцяя", ) self.assertEqual( - num2words(23, lang="by", to="ordinal", gender="n"), + num2words(23, lang="be", to="ordinal", gender=True), + "дваццаць трэцяя", + ) + self.assertEqual( + num2words(23, lang="be", to="ordinal", gender="n"), "дваццаць трэцяе", ) - self.assertEqual(num2words(40, lang="by", to="ordinal"), "саракавы") self.assertEqual( - num2words(61, lang="by", to="ordinal"), "шэсцьдзясят першы" + num2words(46, lang="be", to="ordinal", gender="m"), + "сорак шосты", + ) + self.assertEqual(num2words(40, lang="be", to="ordinal"), "саракавы") + self.assertEqual( + num2words(61, lang="be", to="ordinal"), "шэсцьдзясят першы" + ) + self.assertEqual(num2words(70, lang="be", to="ordinal"), "сямідзясяты") + self.assertEqual(num2words(100, lang="be", to="ordinal"), "соты") + self.assertEqual( + num2words(136, lang="be", to="ordinal"), "сто трыццаць шосты" ) - self.assertEqual(num2words(70, lang="by", to="ordinal"), "сямідзясяты") - self.assertEqual(num2words(100, lang="by", to="ordinal"), "соты") + self.assertEqual(num2words(500, lang="be", to="ordinal"), "пяцісоты") + self.assertEqual( - num2words(136, lang="by", to="ordinal"), "сто трыццаць шосты" + num2words(500, lang="be", to="ordinal", gender="f"), "пяцісотая" ) - self.assertEqual(num2words(500, lang="by", to="ordinal"), "пяцісоты") self.assertEqual( - num2words(500, lang="by", to="ordinal", gender="f"), "пяцісотая" + num2words(500, lang="be", to="ordinal", gender="n"), "пяцісотае" ) + self.assertEqual(num2words(1000, lang="be", to="ordinal"), "тысячны") + self.assertEqual( - num2words(500, lang="by", to="ordinal", gender="n"), "пяцісотае" + num2words(1000, lang="be", to="ordinal", gender="f"), "тысячная" ) - self.assertEqual(num2words(1000, lang="by", to="ordinal"), "тысячны") + self.assertEqual( + num2words(1000, lang="be", to="ordinal", gender="n"), "тысячнае" + ) self.assertEqual( - num2words(1000, lang="by", to="ordinal", gender="f"), "тысячная" + num2words(1001, lang="be", to="ordinal"), "тысяча першы" + ) + self.assertEqual( + num2words(3000, lang="be", to="ordinal"), "трохтысячны" + ) + self.assertEqual( + num2words(10000, lang="be", to="ordinal"), "дзесяцітысячны" + ) + self.assertEqual( + num2words(30000, lang="be", to="ordinal"), "трыццацітысячны" + ) + self.assertEqual( + num2words(42000, lang="be", to="ordinal"), "саракадвухтысячны" ) self.assertEqual( - num2words(1000, lang="by", to="ordinal", gender="n"), "тысячнае" + num2words(75000, lang="be", to="ordinal"), "сямідзесяціпяцітысячны" ) self.assertEqual( - num2words(1001, lang="by", to="ordinal"), "тысяча першы" + num2words(1000000, lang="be", to="ordinal"), "мільённы" ) self.assertEqual( - num2words(2000, lang="by", to="ordinal"), "двухтысячны" + num2words(30000000, lang="be", to="ordinal"), "трыццацімільённы" ) self.assertEqual( - num2words(10000, lang="by", to="ordinal"), "дзесяцітысячны" + num2words(1000000000, lang="be", to="ordinal"), "мільярдны" ) self.assertEqual( - num2words(42000, lang="by", to="ordinal"), "саракадвухтысячны" + num2words(3000000000, lang="be", to="ordinal"), "трохмільярдны" ) self.assertEqual( - num2words(1000000, lang="by", to="ordinal"), "мільённы" + num2words(43000000000, lang="be", to="ordinal"), + "саракатрохмільярдны", ) self.assertEqual( - num2words(1000000000, lang="by", to="ordinal"), "мільярдны" + num2words(333000000000, lang="be", to="ordinal"), + "трыстатрыццацітрохмільярдны", ) def test_to_currency(self): self.assertEqual( - num2words(1.0, lang="by", to="currency", currency="EUR"), + num2words(1.0, lang="be", to="currency", currency="EUR"), "адзін еўра, нуль цэнтаў", ) self.assertEqual( - num2words(1.0, lang="by", to="currency", currency="RUB"), + num2words(1.0, lang="be", to="currency", currency="RUB"), "адзін расійскі рубель, нуль капеек", ) self.assertEqual( - num2words(1.0, lang="by", to="currency", currency="BYN"), + num2words(1.0, lang="be", to="currency", currency="BYN"), "адзін беларускі рубель, нуль капеек", ) self.assertEqual( - num2words(1.0, lang="by", to="currency", currency="UAH"), + num2words(1.0, lang="be", to="currency", currency="UAH"), "адна грыўна, нуль капеек", ) self.assertEqual( - num2words(1234.56, lang="by", to="currency", currency="EUR"), + num2words(1234.56, lang="be", to="currency", currency="EUR"), "адна тысяча дзвесце трыццаць чатыры еўра, " "пяцьдзясят шэсць цэнтаў", ) self.assertEqual( - num2words(1234.56, lang="by", to="currency", currency="RUB"), + num2words(1234.56, lang="be", to="currency", currency="RUB"), "адна тысяча дзвесце трыццаць чатыры расійскія рублі, " "пяцьдзясят шэсць капеек", ) self.assertEqual( - num2words(1234.56, lang="by", to="currency", currency="BYN"), + num2words(1234.56, lang="be", to="currency", currency="BYN"), "адна тысяча дзвесце трыццаць чатыры беларускія рублі, " "пяцьдзясят шэсць капеек", ) self.assertEqual( - num2words(1234.56, lang="by", to="currency", currency="UAH"), + num2words(1234.56, lang="be", to="currency", currency="UAH"), "адна тысяча дзвесце трыццаць чатыры грыўны, " "пяцьдзясят шэсць капеек", ) self.assertEqual( num2words( - 10111, lang="by", to="currency", currency="EUR", separator=" і" + 10111, lang="be", to="currency", currency="EUR", separator=" і" ), "сто адзін еўра і адзінаццаць цэнтаў", ) self.assertEqual( num2words( - 10111, lang="by", to="currency", currency="RUB", separator=" і" + 10111, lang="be", to="currency", currency="RUB", separator=" і" ), "сто адзін расійскі рубель і адзінаццаць капеек", ) self.assertEqual( num2words( - 10111, lang="by", to="currency", currency="BYN", separator=" і" + 10111, lang="be", to="currency", currency="BYN", separator=" і" ), "сто адзін беларускі рубель і адзінаццаць капеек", ) self.assertEqual( num2words( - 10111, lang="by", to="currency", currency="UAH", separator=" і" + 10111, lang="be", to="currency", currency="UAH", separator=" і" ), "сто адна грыўна і адзінаццаць капеек", ) self.assertEqual( num2words( - 10121, lang="by", to="currency", currency="EUR", separator=" і" + 10121, lang="be", to="currency", currency="EUR", separator=" і" ), "сто адзін еўра і дваццаць адзін цэнт", ) self.assertEqual( num2words( - 10121, lang="by", to="currency", currency="RUB", separator=" і" + 10121, lang="be", to="currency", currency="RUB", separator=" і" ), "сто адзін расійскі рубель і дваццаць адна капейка", ) self.assertEqual( num2words( - 10121, lang="by", to="currency", currency="BYN", separator=" і" + 10121, lang="be", to="currency", currency="BYN", separator=" і" ), "сто адзін беларускі рубель і дваццаць адна капейка", ) self.assertEqual( num2words( - 10121, lang="by", to="currency", currency="UAH", separator=" і" + 10121, lang="be", to="currency", currency="UAH", separator=" і" ), "сто адна грыўна і дваццаць адна капейка", ) self.assertEqual( num2words( - 10122, lang="by", to="currency", currency="EUR", separator=" і" + 10122, lang="be", to="currency", currency="EUR", separator=" і" ), "сто адзін еўра і дваццаць два цэнты", ) self.assertEqual( num2words( - 10122, lang="by", to="currency", currency="RUB", separator=" і" + 10122, lang="be", to="currency", currency="RUB", separator=" і" ), "сто адзін расійскі рубель і дваццаць дзве капейкі", ) self.assertEqual( num2words( - 10122, lang="by", to="currency", currency="BYN", separator=" і" + 10122, lang="be", to="currency", currency="BYN", separator=" і" ), "сто адзін беларускі рубель і дваццаць дзве капейкі", ) self.assertEqual( num2words( - 10122, lang="by", to="currency", currency="UAH", separator=" і" + 10122, lang="be", to="currency", currency="UAH", separator=" і" ), "сто адна грыўна і дваццаць дзве капейкі", ) self.assertEqual( num2words( - 10122, lang="by", to="currency", currency="KZT", separator=" і" + 10122, lang="be", to="currency", currency="KZT", separator=" і" ), "сто адзін тэнге і дваццаць два тыйіны", ) self.assertEqual( num2words( - -1251985, lang="by", to="currency", currency="EUR", cents=False + -1251985, lang="be", to="currency", currency="EUR", cents=False ), "мінус дванаццаць тысяч пяцьсот дзевятнаццаць еўра, 85 цэнтаў", ) self.assertEqual( num2words( - -1251985, lang="by", to="currency", currency="RUB", cents=False + -1251985, lang="be", to="currency", currency="RUB", cents=False ), "мінус дванаццаць тысяч пяцьсот дзевятнаццаць " "расійскіх рублёў, 85 капеек", ) self.assertEqual( num2words( - -1251985, lang="by", to="currency", currency="BYN", cents=False + -1251985, lang="be", to="currency", currency="BYN", cents=False ), "мінус дванаццаць тысяч пяцьсот дзевятнаццаць " "беларускіх рублёў, 85 капеек", ) self.assertEqual( num2words( - -1251985, lang="by", to="currency", currency="UAH", cents=False + -1251985, lang="be", to="currency", currency="UAH", cents=False ), "мінус дванаццаць тысяч пяцьсот дзевятнаццаць грыўнаў, 85 капеек", ) self.assertEqual( num2words( "38.4", - lang="by", + lang="be", to="currency", separator=" і", cents=False, @@ -314,7 +344,7 @@ def test_to_currency(self): self.assertEqual( num2words( "38.4", - lang="by", + lang="be", to="currency", separator=" і", cents=False, @@ -325,7 +355,7 @@ def test_to_currency(self): self.assertEqual( num2words( "38.4", - lang="by", + lang="be", to="currency", separator=" і", cents=False, @@ -334,22 +364,38 @@ def test_to_currency(self): "трыццаць восем грыўнаў і 40 капеек", ) self.assertEqual( - num2words("1230.56", lang="by", to="currency", currency="USD"), + num2words("1230.56", lang="be", to="currency", currency="USD"), "адна тысяча дзвесце трыццаць долараў, пяцьдзясят шэсць цэнтаў", ) self.assertEqual( - num2words("1231.56", lang="by", to="currency", currency="USD"), + num2words("1231.56", lang="be", to="currency", currency="USD"), "адна тысяча дзвесце трыццаць адзін долар, " "пяцьдзясят шэсць цэнтаў", ) self.assertEqual( - num2words("1234.56", lang="by", to="currency", currency="USD"), + num2words("1234.56", lang="be", to="currency", currency="USD"), "адна тысяча дзвесце трыццаць чатыры долары, пяцьдзясят шэсць " "цэнтаў", ) self.assertEqual( num2words( - 10122, lang="by", to="currency", currency="UZS", separator=" і" + 10122, lang="be", to="currency", currency="UZS", separator=" і" ), "сто адзін сум і дваццаць два тыйіны", ) + + self.assertEqual( + num2words(1.0, lang="be", to="currency", currency="PLN"), + "адзін злоты, нуль грошаў", + ) + + self.assertEqual( + num2words(23.40, lang="be", to="currency", currency="PLN"), + "дваццаць тры злотых, сорак грошаў", + ) + + self.assertEqual( + num2words(9999.39, lang="be", to="currency", currency="PLN"), + "дзевяць тысяч дзевяцьсот дзевяноста дзевяць злотых, " + "трыццаць дзевяць грошаў", + ) diff --git a/tests/test_bn.py b/tests/test_bn.py new file mode 100644 index 00000000..9147916c --- /dev/null +++ b/tests/test_bn.py @@ -0,0 +1,365 @@ +# -*- coding: utf-8 -*- +# Author: Mehedi Hasan Khondoker +# Email: mehedihasankhondoker [at] gmail.com +# Copyright (c) 2024, Mehedi Hasan Khondoker. All Rights Reserved. + +# This library is build for Bangladesh format Number to Word conversion. +# You are welcome as contributor to the library. + +# 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. + +from __future__ import unicode_literals + +from decimal import Decimal +from unittest import TestCase + +from num2words import num2words +from num2words.lang_BN import Num2Word_BN, NumberTooLargeError + + +class Num2WordsBNTest(TestCase): + maxDiff = None + + def test_negative(self): + self.assertEqual(num2words(-1, lang="bn"), u'এক') + + def test_0(self): + self.assertEqual(num2words(0, lang="bn"), u'শূন্য') + + def test_1_to_10(self): + self.assertEqual(num2words(1, lang="bn"), u'এক') + self.assertEqual(num2words(2, lang="bn"), u'দুই') + self.assertEqual(num2words(7, lang="bn"), u'সাত') + self.assertEqual(num2words(10, lang="bn"), u'দশ') + + def test_11_to_19(self): + self.assertEqual(num2words(11, lang="bn"), u'এগারো') + self.assertEqual(num2words(13, lang="bn"), u'তেরো') + self.assertEqual(num2words(15, lang="bn"), u'পনের') + self.assertEqual(num2words(16, lang="bn"), u'ষোল') + self.assertEqual(num2words(19, lang="bn"), u'উনিশ') + + def test_20_to_99(self): + self.assertEqual(num2words(20, lang="bn"), u'বিশ') + self.assertEqual(num2words(23, lang="bn"), u'তেইশ') + self.assertEqual(num2words(28, lang="bn"), u'আটাশ') + self.assertEqual(num2words(31, lang="bn"), u'একত্রিশ') + self.assertEqual(num2words(40, lang="bn"), u'চল্লিশ') + self.assertEqual(num2words(66, lang="bn"), u'ছিষট্টি') + self.assertEqual(num2words(92, lang="bn"), u'বিরানব্বই') + + def test_100_to_999(self): + self.assertEqual(num2words(100, lang="bn"), u'একশত') + self.assertEqual(num2words(111, lang="bn"), u'একশত এগারো') + self.assertEqual(num2words(150, lang="bn"), u'একশত পঞ্চাশ') + self.assertEqual(num2words(196, lang="bn"), u'একশত ছিয়ানব্বই') + self.assertEqual(num2words(200, lang="bn"), u'দুইশত') + self.assertEqual(num2words(210, lang="bn"), u'দুইশত দশ') + self.assertEqual(num2words(701, lang="bn"), u'সাতশত এক') + self.assertEqual(num2words(999, lang="bn"), u'নয়শত নিরানব্বই') + + def test_1000_to_9999(self): + self.assertEqual(num2words(1000, lang="bn"), u'এক হাজার') + self.assertEqual(num2words(1001, lang="bn"), u'এক হাজার এক') + self.assertEqual(num2words(1002, lang="bn"), u'এক হাজার দুই') + self.assertEqual(num2words(1010, lang="bn"), u'এক হাজার দশ') + self.assertEqual(num2words(1110, lang="bn"), u'এক হাজার একশত দশ') + self.assertEqual(num2words(1111, lang="bn"), u'এক হাজার একশত এগারো') + self.assertEqual(num2words(1500, lang="bn"), u'এক হাজার পাঁচশত') + self.assertEqual(num2words(2000, lang="bn"), u'দুই হাজার') + self.assertEqual(num2words(2042, lang="bn"), u'দুই হাজার বিয়াল্লিশ') + self.assertEqual(num2words(3000, lang="bn"), u'তিন হাজার') + self.assertEqual(num2words(3301, lang="bn"), u'তিন হাজার তিনশত এক') + self.assertEqual(num2words(3108, lang="bn"), u'তিন হাজার একশত আট') + self.assertEqual(num2words(6870, lang="bn"), u'ছয় হাজার আটশত সত্তর') + self.assertEqual(num2words(7378, lang="bn"), + u'সাত হাজার তিনশত আটাত্তর') + self.assertEqual(num2words(9999, lang="bn"), + u'নয় হাজার নয়শত নিরানব্বই') + + def test_10000_to_99999(self): + self.assertEqual(num2words(10000, lang="bn"), + u'দশ হাজার') + self.assertEqual(num2words(10501, lang="bn"), + u'দশ হাজার পাঁচশত এক') + self.assertEqual(num2words(10999, lang="bn"), + u'দশ হাজার নয়শত নিরানব্বই') + self.assertEqual(num2words(13000, lang="bn"), u'তেরো হাজার') + self.assertEqual(num2words(15333, lang="bn"), + u'পনের হাজার তিনশত তেত্রিশ') + self.assertEqual(num2words(21111, lang="bn"), u'একুশ হাজার একশত এগারো') + self.assertEqual(num2words(21003, lang="bn"), u'একুশ হাজার তিন') + self.assertEqual(num2words(25020, lang="bn"), u'পঁচিশ হাজার বিশ') + self.assertEqual(num2words(68700, lang="bn"), + u'আটষট্টি হাজার সাতশত') + self.assertEqual(num2words(73781, lang="bn"), + u'তিয়াত্তর হাজার সাতশত একাশি') + self.assertEqual(num2words(99999, lang="bn"), + u'নিরানব্বই হাজার নয়শত নিরানব্বই') + + def test_100000_to_999999(self): + self.assertEqual(num2words(100000, lang="bn"), u'এক লাখ') + self.assertEqual(num2words('100000', lang="bn"), u'এক লাখ') + self.assertEqual(num2words(199999, lang="bn"), + u'এক লাখ নিরানব্বই হাজার নয়শত নিরানব্বই') + self.assertEqual(num2words(110000, lang="bn"), u'এক লাখ দশ হাজার') + self.assertEqual(num2words(150010, lang="bn"), + u'এক লাখ পঞ্চাশ হাজার দশ') + self.assertEqual(num2words('200200', lang="bn"), u'দুই লাখ দুইশত') + self.assertEqual(num2words(737812, lang="bn"), + u'সাত লাখ সাতত্রিশ হাজার আটশত বারো') + self.assertEqual(num2words('999999', lang="bn"), + u'নয় লাখ নিরানব্বই হাজার নয়শত নিরানব্বই') + + def test_1000000_to_9999999999999999(self): + self.assertEqual(num2words(1000000, lang="bn"), u'দশ লাখ') + self.assertEqual(num2words(20000000, lang="bn"), u'দুই কোটি') + self.assertEqual(num2words(300000000, lang="bn"), u'ত্রিশ কোটি') + self.assertEqual(num2words(4000000000, lang="bn"), u'চারশত কোটি') + self.assertEqual(num2words(50000000000, lang="bn"), u'পাঁচ হাজার কোটি') + self.assertEqual(num2words(600000000000, lang="bn"), u'ষাট হাজার কোটি') + self.assertEqual(num2words(7000000000000, lang="bn"), u'সাত লাখ কোটি') + self.assertEqual(num2words(80000000000000, lang="bn"), u'আশি লাখ কোটি') + self.assertEqual(num2words + (900000000000000, lang="bn"), u'নয় কোটি কোটি') + self.assertEqual(num2words(999999999999999, lang="bn"), + u'নয় কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই') # noqa: E501 + self.assertEqual(num2words(9999999999999999, lang="bn"), + u'নিরানব্বই কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই') # noqa: E501 + + def test_dosomik_0_to_999999999999999999(self): + self.assertEqual(num2words(0.56, lang="bn"), u'শূন্য দশমিক পাঁচ ছয়') + self.assertEqual(num2words(1.11, lang="bn"), u'এক দশমিক এক এক') + self.assertEqual(num2words(2.66, lang="bn"), u'দুই দশমিক ছয় ছয়') + self.assertEqual(num2words(7.68, lang="bn"), u'সাত দশমিক ছয় আট') + self.assertEqual(num2words('10.35', lang="bn"), u'দশ দশমিক তিন পাঁচ') + self.assertEqual(num2words('11.47', lang="bn"), u'এগারো দশমিক চার সাত') + self.assertEqual(num2words(13.69, lang="bn"), u'তেরো দশমিক ছয় নয়') + self.assertEqual(num2words(15.96, lang="bn"), u'পনের দশমিক নয় ছয়') + self.assertEqual(num2words(16.9999, lang="bn"), + u'ষোল দশমিক নয় নয় নয় নয়') + self.assertEqual(num2words(19.56587, lang="bn"), + u'উনিশ দশমিক পাঁচ ছয় পাঁচ আট সাত') + self.assertEqual(num2words(31.31, lang="bn"), u'একত্রিশ দশমিক তিন এক') + self.assertEqual(num2words(40.85, lang="bn"), u'চল্লিশ দশমিক আট পাঁচ') + self.assertEqual(num2words(66.66, lang="bn"), u'ছিষট্টি দশমিক ছয় ছয়') + self.assertEqual(num2words(92.978, lang="bn"), + u'বিরানব্বই দশমিক নয় সাত আট') + self.assertEqual(num2words(1000001.10, lang="bn"), + u'দশ লাখ এক দশমিক এক') + self.assertEqual(num2words(20000000.22, lang="bn"), + u'দুই কোটি দশমিক দুই দুই') + self.assertEqual(num2words(300030000.33, lang="bn"), + u'ত্রিশ কোটি ত্রিশ হাজার দশমিক তিন তিন') + self.assertEqual(num2words('4004000444.44', lang="bn"), + u'চারশত কোটি চল্লিশ লাখ চারশত চৌচল্লিশ দশমিক চার চার') + self.assertEqual(num2words(50000000001.50, lang="bn"), + u'পাঁচ হাজার কোটি এক দশমিক পাঁচ') + self.assertEqual(num2words(600000000600.66, lang="bn"), + u'ষাট হাজার কোটি ছয়শত দশমিক ছয় ছয়') + self.assertEqual(num2words(7000000000000.77, lang="bn"), + u'সাত লাখ কোটি দশমিক সাত সাত') + self.assertEqual(num2words(80000000000888.88, lang="bn"), + u'আশি লাখ কোটি আটশত আটাশি দশমিক আট আট') + self.assertEqual(num2words(900000000000000.9, lang="bn"), + u'নয় কোটি কোটি দশমিক নয়') + self.assertEqual(num2words(999999999999999.9, lang="bn"), + u'নয় কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই দশমিক নয়') # noqa: E501 + self.assertEqual(num2words(9999999999999999.99, lang="bn"), + u'একশত কোটি কোটি') + self.assertEqual(num2words(99999999999999999.99, lang="bn"), + u'এক হাজার কোটি কোটি') + self.assertEqual(num2words('999999999999999999.9', lang="bn"), + u'নয় হাজার নয়শত নিরানব্বই কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই দশমিক নয়') # noqa: E501 + + def test_to_currency(self): + n = Num2Word_BN() + self.assertEqual(n.to_currency(20.0), u'বিশ টাকা') + self.assertEqual(n.to_currency(20.50), u'বিশ টাকা পঞ্চাশ পয়সা') + self.assertEqual(n.to_currency(33.51), u'তেত্রিশ টাকা একান্ন পয়সা') + self.assertEqual(n.to_currency(99.99), + u'নিরানব্বই টাকা নিরানব্বই পয়সা') + self.assertEqual(n.to_currency(10000.1), + u'দশ হাজার টাকা দশ পয়সা') + self.assertEqual(n.to_currency(555555.50), + u'পাঁচ লাখ পঞ্চান্ন হাজার পাঁচশত পঞ্চান্ন টাকা পঞ্চাশ পয়সা') # noqa: E501 + self.assertEqual(n.to_currency(6666676), + u'ছিষট্টি লাখ ছিষট্টি হাজার ছয়শত ছিয়াত্তর টাকা') + self.assertEqual(n.to_currency(777777777), + u'সাতাত্তর কোটি সাতাত্তর লাখ সাতাত্তর হাজার সাতশত সাতাত্তর টাকা') # noqa: E501 + self.assertEqual(n.to_currency(7777777778), + u'সাতশত সাতাত্তর কোটি সাতাত্তর লাখ সাতাত্তর হাজার সাতশত আটাত্তর টাকা') # noqa: E501 + self.assertEqual(n.to_currency(97777777778), + u'নয় হাজার সাতশত সাতাত্তর কোটি সাতাত্তর লাখ সাতাত্তর হাজার সাতশত আটাত্তর টাকা') # noqa: E501 + self.assertEqual(n.to_currency(977777777781), + u'সাতানব্বই হাজার সাতশত সাতাত্তর কোটি সাতাত্তর লাখ সাতাত্তর হাজার সাতশত একাশি টাকা') # noqa: E501 + self.assertEqual(n.to_currency(9777777779781), + u'নয় লাখ সাতাত্তর হাজার সাতশত সাতাত্তর কোটি সাতাত্তর লাখ উনআশি হাজার সাতশত একাশি টাকা') # noqa: E501 + + def test_to_cardinal(self): + n = Num2Word_BN() + self.assertEqual(n.to_cardinal(0.56), u'শূন্য দশমিক পাঁচ ছয়') + self.assertEqual(n.to_cardinal(1.11), u'এক দশমিক এক এক') + self.assertEqual(n.to_cardinal(2.66), u'দুই দশমিক ছয় ছয়') + self.assertEqual(n.to_cardinal(7.68), u'সাত দশমিক ছয় আট') + self.assertEqual(n.to_cardinal('10.35'), u'দশ দশমিক তিন পাঁচ') + self.assertEqual(n.to_cardinal('11.47'), u'এগারো দশমিক চার সাত') + self.assertEqual(n.to_cardinal(13.69), u'তেরো দশমিক ছয় নয়') + self.assertEqual(n.to_cardinal(15.96), u'পনের দশমিক নয় ছয়') + self.assertEqual(n.to_cardinal(16.9999), u'ষোল দশমিক নয় নয় নয় নয়') + self.assertEqual(n.to_cardinal(19.56587), + u'উনিশ দশমিক পাঁচ ছয় পাঁচ আট সাত') + self.assertEqual(n.to_cardinal(31.31), u'একত্রিশ দশমিক তিন এক') + self.assertEqual(n.to_cardinal(40.85), u'চল্লিশ দশমিক আট পাঁচ') + self.assertEqual(n.to_cardinal(66.66), u'ছিষট্টি দশমিক ছয় ছয়') + self.assertEqual(n.to_cardinal(92.978), u'বিরানব্বই দশমিক নয় সাত আট') + self.assertEqual(n.to_cardinal(1000001.10), u'দশ লাখ এক দশমিক এক') + self.assertEqual(n.to_cardinal(20000000.22), u'দুই কোটি দশমিক দুই দুই') + self.assertEqual(n.to_cardinal(300030000.33), + u'ত্রিশ কোটি ত্রিশ হাজার দশমিক তিন তিন') + self.assertEqual(n.to_cardinal('4004000444.44'), + u'চারশত কোটি চল্লিশ লাখ চারশত চৌচল্লিশ দশমিক চার চার') + self.assertEqual(n.to_cardinal(50000000001.50), + u'পাঁচ হাজার কোটি এক দশমিক পাঁচ') + self.assertEqual(n.to_cardinal(600000000600.66), + u'ষাট হাজার কোটি ছয়শত দশমিক ছয় ছয়') + self.assertEqual(n.to_cardinal(7000000000000.77), + u'সাত লাখ কোটি দশমিক সাত সাত') + self.assertEqual(n.to_cardinal(80000000000888.88), + u'আশি লাখ কোটি আটশত আটাশি দশমিক আট আট') + self.assertEqual(n.to_cardinal(900000000000000.9), + u'নয় কোটি কোটি দশমিক নয়') + self.assertEqual(n.to_cardinal(999999999999999.9), + u'নয় কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই দশমিক নয়') # noqa: E501 + self.assertEqual(n.to_cardinal(9999999999999999.99), + u'একশত কোটি কোটি') + self.assertEqual(n.to_cardinal(99999999999999999.99), + u'এক হাজার কোটি কোটি') + self.assertEqual(n.to_cardinal('999999999999999999.99'), + u'নয় হাজার নয়শত নিরানব্বই কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই দশমিক নয় নয়') # noqa: E501 + + def test_to_ordinal(self): + n = Num2Word_BN() + self.assertEqual(n.to_ordinal(0.56), u'শূন্য দশমিক পাঁচ ছয়') + self.assertEqual(n.to_ordinal(1.11), u'এক দশমিক এক এক') + self.assertEqual(n.to_ordinal(2.66), u'দুই দশমিক ছয় ছয়') + self.assertEqual(n.to_ordinal(7.68), u'সাত দশমিক ছয় আট') + self.assertEqual(n.to_ordinal('10.35'), u'দশ দশমিক তিন পাঁচ') + self.assertEqual(n.to_ordinal('11.47'), u'এগারো দশমিক চার সাত') + self.assertEqual(n.to_ordinal(13.69), u'তেরো দশমিক ছয় নয়') + self.assertEqual(n.to_ordinal(15.96), u'পনের দশমিক নয় ছয়') + self.assertEqual(n.to_ordinal(16.9999), u'ষোল দশমিক নয় নয় নয় নয়') + self.assertEqual(n.to_ordinal(19.56587), + u'উনিশ দশমিক পাঁচ ছয় পাঁচ আট সাত') + self.assertEqual(n.to_ordinal(31.31), u'একত্রিশ দশমিক তিন এক') + self.assertEqual(n.to_ordinal(40.85), u'চল্লিশ দশমিক আট পাঁচ') + self.assertEqual(n.to_ordinal(66.66), u'ছিষট্টি দশমিক ছয় ছয়') + self.assertEqual(n.to_ordinal(92.978), u'বিরানব্বই দশমিক নয় সাত আট') + self.assertEqual(n.to_ordinal(1000001.10), u'দশ লাখ এক দশমিক এক') + self.assertEqual(n.to_ordinal(20000000.22), u'দুই কোটি দশমিক দুই দুই') + self.assertEqual(n.to_ordinal(300030000.33), + u'ত্রিশ কোটি ত্রিশ হাজার দশমিক তিন তিন') + self.assertEqual(n.to_ordinal('4004000444.44'), + u'চারশত কোটি চল্লিশ লাখ চারশত চৌচল্লিশ দশমিক চার চার') + self.assertEqual(n.to_ordinal(50000000001.50), + u'পাঁচ হাজার কোটি এক দশমিক পাঁচ') + self.assertEqual(n.to_ordinal(600000000600.66), + u'ষাট হাজার কোটি ছয়শত দশমিক ছয় ছয়') + self.assertEqual(n.to_ordinal(7000000000000.77), + u'সাত লাখ কোটি দশমিক সাত সাত') + self.assertEqual(n.to_ordinal(80000000000888.88), + u'আশি লাখ কোটি আটশত আটাশি দশমিক আট আট') + self.assertEqual(n.to_ordinal(900000000000000.9), + u'নয় কোটি কোটি দশমিক নয়') + self.assertEqual(n.to_ordinal(999999999999999.9), + u'নয় কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই দশমিক নয়') # noqa: E501 + self.assertEqual(n.to_ordinal(9999999999999999.99), + u'একশত কোটি কোটি') + self.assertEqual(n.to_ordinal(99999999999999999.99), + u'এক হাজার কোটি কোটি') + self.assertEqual(n.to_ordinal('999999999999999999.99'), + u'নয় হাজার নয়শত নিরানব্বই কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই দশমিক নয় নয়') # noqa: E501 + + def test_to_year(self): + n = Num2Word_BN() + self.assertEqual(n.to_year(1), u'এক সাল') + self.assertEqual(n.to_year(1000), u'এক হাজার সাল') + self.assertEqual(n.to_year(1500), u'এক হাজার পাঁচশত সাল') + self.assertEqual(n.to_year(1820), u'এক হাজার আটশত বিশ সাল') + self.assertEqual(n.to_year(1920), u'এক হাজার নয়শত বিশ সাল') + self.assertEqual(n.to_year(2024), u'দুই হাজার চব্বিশ সাল') + self.assertEqual(n.to_year(2004), u'দুই হাজার চার সাল') + + def test_to_ordinal_num(self): + n = Num2Word_BN() + self.assertEqual(n.to_ordinal_num(1), u'প্রথম') + self.assertEqual(n.to_ordinal_num(1000), u'এক হাজারতম') + self.assertEqual(n.to_ordinal_num(1500), u'এক হাজার পাঁচশতম') + self.assertEqual(n.to_ordinal_num(1820), u'এক হাজার আটশত বিশতম') + self.assertEqual(n.to_ordinal_num(1920), u'এক হাজার নয়শত বিশতম') + self.assertEqual(n.to_ordinal_num(2024), u'দুই হাজার চব্বিশতম') + self.assertEqual(n.to_ordinal_num(2004), u'দুই হাজার চারতম') + + def test_max_number_error(self): + n = Num2Word_BN() + + with self.assertRaises(NumberTooLargeError): + n.to_ordinal( + 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999991) # noqa: E501 + + with self.assertRaises(NumberTooLargeError): + n.to_cardinal( + 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999991) # noqa: E501 + + with self.assertRaises(NumberTooLargeError): + n.to_year( + 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999991) # noqa: E501 + + with self.assertRaises(NumberTooLargeError): + n.to_ordinal_num( + 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999991) # noqa: E501 + + with self.assertRaises(NumberTooLargeError): + n.to_currency( + 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999991) # noqa: E501 + + with self.assertRaises(NumberTooLargeError): + num2words( + 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999991, # noqa: E501 + lang="bn") + + def test_is_smaller_than_max_number(self): + n = Num2Word_BN() + self.assertEqual(n._is_smaller_than_max_number(55555), True) + + def test_is_smaller_than_max_number_error(self): + with self.assertRaises(NumberTooLargeError): + n = Num2Word_BN() + n._is_smaller_than_max_number(99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999) # noqa: E501 + + def test_parse_number(self): + n = Num2Word_BN() + self.assertEqual(n.parse_number(Decimal(3.25)), (3, 25)) + self.assertEqual(n.parse_number(Decimal(300.2550)), + (300, 2549999999999954525264911353588104248046875)) + + def test_parse_paisa(self): + n = Num2Word_BN() + self.assertEqual(n.parse_paisa(Decimal(3.25)), (3, 25)) + self.assertEqual(n.parse_paisa(300.2550), (300, 25)) + self.assertEqual(n.parse_paisa(100.5), (100, 50)) + + def test_number_to_bengali_word(self): + n = Num2Word_BN() + self.assertEqual(n._number_to_bengali_word(3), "তিন") + self.assertEqual(n._number_to_bengali_word(2550), + "দুই হাজার পাঁচশত পঞ্চাশ") + self.assertEqual(n._number_to_bengali_word(9999999999999999), + "নিরানব্বই কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই কোটি নিরানব্বই লাখ নিরানব্বই হাজার নয়শত নিরানব্বই") # noqa: E501 diff --git a/tests/test_ca.py b/tests/test_ca.py new file mode 100644 index 00000000..ab5be158 --- /dev/null +++ b/tests/test_ca.py @@ -0,0 +1,186 @@ +from __future__ import unicode_literals + +from unittest import TestCase + +from num2words import num2words + +TEST_CASES_CARDINAL = ( + (1, "un"), + (2, "dos"), + (3, "tres"), + (5.5, "cinc punt cinc"), + (11, "onze"), + (12, "dotze"), + (16, "setze"), + (17.42, "disset punt quatre dos"), + (19, "dinou"), + (20, "vint"), + (21, "vint-i-un"), + (26, "vint-i-sis"), + (27.312, "vint-i-set punt tres un dos"), + (28, "vint-i-vuit"), + (30, "trenta"), + (31, "trenta-un"), + (40, "quaranta"), + (44, "quaranta-quatre"), + (50, "cinquanta"), + (53.486, "cinquanta-tres punt quatre vuit sis"), + (55, "cinquanta-cinc"), + (60, "seixanta"), + (67, "seixanta-set"), + (70, "setanta"), + (79, "setanta-nou"), + (89, "vuitanta-nou"), + (95, "noranta-cinc"), + (100, "cent"), + (101, "cent un"), + (199, "cent noranta-nou"), + (203, "dos-cents tres"), + (287, "dos-cents vuitanta-set"), + (300.42, "tres-cents punt quatre dos"), + (356, "tres-cents cinquanta-sis"), + (400, "quatre-cents"), + (434, "quatre-cents trenta-quatre"), + (555, "cinc-cents cinquanta-cinc"), + (578, "cinc-cents setanta-vuit"), + (666, "sis-cents seixanta-sis"), + (689, "sis-cents vuitanta-nou"), + (729, "set-cents vint-i-nou"), + (777, "set-cents setanta-set"), + (888, "vuit-cents vuitanta-vuit"), + (894, "vuit-cents noranta-quatre"), + (999, "nou-cents noranta-nou"), + (1000, "mil"), + (1001, "mil un"), + (1097, "mil noranta-set"), + (1104, "mil cent quatre"), + (1243, "mil dos-cents quaranta-tres"), + (2385, "dos mil tres-cents vuitanta-cinc"), + (3766, "tres mil set-cents seixanta-sis"), + (4196, "quatre mil cent noranta-sis"), + (4196.42, "quatre mil cent noranta-sis punt quatre dos"), + (5846, "cinc mil vuit-cents quaranta-sis"), + (6459, "sis mil quatre-cents cinquanta-nou"), + (7232, "set mil dos-cents trenta-dos"), + (8569, "vuit mil cinc-cents seixanta-nou"), + (9539, "nou mil cinc-cents trenta-nou"), + (1000000, "un milió"), + (1000001, "un milió un"), + (4000000, "quatre milions"), + (10000000000000, "deu bilions"), + (100000000000000, "cent bilions"), + (1000000000000000000, "un trilió"), + (1000000000000000000000, "mil trilions"), + (10000000000000000000000000, "deu quadrilions"), +) + +TEST_CASES_ORDINAL = ( + (1, "primer"), + (2, "segon"), + (8, "vuitè"), + (12, "dotzè"), + (14, "catorzè"), + (28, "vint-i-vuitè"), + (33, "trenta-tresè"), + (88, "vuitanta-vuitè"), + (100, "centè"), + (128, "cent vint-i-vuitè"), + (199, "cent noranta-novè"), + (1000, "milè"), + (1827, "mil vuit-cents vint-i-setè"), + (12345, "dotze mil tres-cents quaranta-cinquè"), + (1000000, "milionè"), + (1000000000000000, "mil bilionè"), + (1000000000000000, "mil bilionè"), + (1000000000000000000, "un trilionè"), # over 1e18 is not supported +) + +TEST_CASES_ORDINAL_NUM = ( + (1, "1r"), + (8, "8è"), + (12, "12è"), + (14, "14è"), + (28, "28è"), + (100, "100è"), + (1000, "1000è"), + (1000000, "1000000è"), +) + +TEST_CASES_TO_CURRENCY = ( + (1.00, "un euro amb zero cèntims"), + (1.01, "un euro amb un cèntim"), + (2.00, "dos euros amb zero cèntims"), + (8.00, "vuit euros amb zero cèntims"), + (12.00, "dotze euros amb zero cèntims"), + (21.00, "vint-i-un euros amb zero cèntims"), + (81.25, "vuitanta-un euros amb vint-i-cinc cèntims"), + (350.90, "tres-cents cinquanta euros amb noranta cèntims"), + (100.00, "cent euros amb zero cèntims"), +) + +TEST_CASES_TO_CURRENCY_ESP = ( + (1.00, "una pesseta amb zero cèntims"), + (1.01, "una pesseta amb un cèntim"), + (2.00, "dues pessetes amb zero cèntims"), + (8.00, "vuit pessetes amb zero cèntims"), + (12.00, "dotze pessetes amb zero cèntims"), + (21.00, "vint-i-una pessetes amb zero cèntims"), + (81.25, "vuitanta-una pessetes amb vint-i-cinc cèntims"), + (350.90, "tres-centes cinquanta pessetes amb noranta cèntims"), + (100.00, "cent pessetes amb zero cèntims"), +) + +TEST_CASES_TO_CURRENCY_USD = ( + (1.00, "un dòlar amb zero centaus"), + (2.00, "dos dòlars amb zero centaus"), + (8.00, "vuit dòlars amb zero centaus"), + (12.00, "dotze dòlars amb zero centaus"), + (21.00, "vint-i-un dòlars amb zero centaus"), + (81.25, "vuitanta-un dòlars amb vint-i-cinc centaus"), + (350.90, "tres-cents cinquanta dòlars amb noranta centaus"), + (100.00, "cent dòlars amb zero centaus"), +) + + +TEST_CASES_TO_CURRENCY_GBP = ( + (1.00, "una lliura amb zero penics"), + (1.01, "una lliura amb un penic"), + (2.00, "dues lliures amb zero penics"), + (8.00, "vuit lliures amb zero penics"), + (12.00, "dotze lliures amb zero penics"), + (21.00, "vint-i-una lliures amb zero penics"), + (81.25, "vuitanta-una lliures amb vint-i-cinc penics"), + (350.90, "tres-centes cinquanta lliures amb noranta penics"), + (100.00, "cent lliures amb zero penics"), +) + + +class TestNum2WordsCA(TestCase): + def _test_cases(self, cases, lang="ca", to="cardinal", **kwargs): + for case in cases: + self.assertEqual(num2words(case[0], lang=lang, + to=to, **kwargs), case[1]) + + def test_cardinal(self): + self._test_cases(TEST_CASES_CARDINAL) + + def test_ordinal(self): + self._test_cases(TEST_CASES_ORDINAL, to="ordinal") + + def test_ordinal_num(self): + self._test_cases(TEST_CASES_ORDINAL_NUM, to="ordinal_num") + + def test_currency(self): + self._test_cases(TEST_CASES_TO_CURRENCY, to="currency", currency="EUR") + + def test_currency_esp(self): + self._test_cases(TEST_CASES_TO_CURRENCY_ESP, + to="currency", currency="ESP") + + def test_currency_usd(self): + self._test_cases(TEST_CASES_TO_CURRENCY_USD, + to="currency", currency="USD") + + def test_currency_gbp(self): + self._test_cases(TEST_CASES_TO_CURRENCY_GBP, + to="currency", currency="GBP") diff --git a/tests/test_ce.py b/tests/test_ce.py new file mode 100644 index 00000000..7deddfe6 --- /dev/null +++ b/tests/test_ce.py @@ -0,0 +1,414 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2023, Johannes Heinecke. 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 +from __future__ import unicode_literals + +from unittest import TestCase + +from num2words import num2words + +TEST_CASES_CARDINAL = [ + (1, "obl", "б", "цхьана"), + (2, "comp", "в", "шиннал"), + (3, "mat", "д", "кхааннах"), + (4, "mat", "в", "веаннах"), + (5, "abs", "й", "пхиъ"), + (6, "dat", "д", "ялханна"), + (7, "erg", "в", "ворхӀамма"), + (8, "comp", "й", "бархӀаннал"), + (9, "dat", "й", "иссанна"), + (10, "erg", "б", "иттамма"), + (11, "dat", "б", "цхьайттанна"), + (12, "instr", "й", "шийттанца"), + (13, "erg", "б", "кхойттамма"), + (14, "all", "в", "вейттанга"), + (15, "dat", "б", "пхийттанна"), + (16, "dat", "й", "ялхиттанна"), + (17, "dat", "в", "вуьрхӀиттанна"), + (18, "attr", "й", "берхӀитта"), + (19, "all", "й", "ткъайеснанга"), + (20, "attr", "б", "ткъе"), + (21, "all", "в", "ткъе цхаьнга"), + (22, "obl", "в", "ткъе шина"), + (23, "attr", "б", "ткъе кхо"), + (24, "dat", "й", "ткъе йеанна"), + (25, "attr", "й", "ткъе пхи"), + (26, "abs", "б", "ткъе ялх"), + (27, "abs", "в", "ткъе ворхӀ"), + (28, "all", "б", "ткъе бархӀанга"), + (29, "mat", "д", "ткъе иссаннах"), + (30, "gen", "й", "ткъе иттаннан"), + (31, "dat", "в", "ткъе цхьайттанна"), + (32, "comp", "й", "ткъе шийттаннал"), + (33, "instr", "в", "ткъе кхойттанца"), + (34, "instr", "в", "ткъе вейттанца"), + (35, "comp", "в", "ткъе пхийттаннал"), + (36, "dat", "й", "ткъе ялхиттанна"), + (37, "obl", "в", "ткъе вуьрхӀиттан"), + (38, "dat", "й", "ткъе берхӀиттанна"), + (39, "mat", "й", "ткъе ткъайеснаннах"), + (40, "all", "д", "шовзткъанга"), + (41, "obl", "в", "шовзткъе цхьана"), + (42, "dat", "в", "шовзткъе шинна"), + (43, "erg", "й", "шовзткъе кхаамма"), + (44, "erg", "й", "шовзткъе йеамма"), + (45, "comp", "д", "шовзткъе пхеаннал"), + (46, "mat", "б", "шовзткъе ялханнах"), + (47, "erg", "б", "шовзткъе ворхӀамма"), + (48, "erg", "в", "шовзткъе бархӀамма"), + (49, "all", "б", "шовзткъе иссанга"), + (50, "mat", "й", "шовзткъе иттаннах"), + (51, "comp", "в", "шовзткъе цхьайттаннал"), + (52, "erg", "в", "шовзткъе шийттамма"), + (53, "attr", "д", "шовзткъе кхойтта"), + (54, "gen", "б", "шовзткъе бейттаннан"), + (55, "attr", "д", "шовзткъе пхийтта"), + (56, "instr", "й", "шовзткъе ялхиттанца"), + (57, "obl", "б", "шовзткъе вуьрхӀиттан"), + (58, "attr", "б", "шовзткъе берхӀитта"), + (59, "all", "й", "шовзткъе ткъайеснанга"), + (60, "all", "й", "кхузткъанга"), + (61, "gen", "й", "кхузткъе цхьаннан"), + (62, "all", "б", "кхузткъе шинга"), + (63, "instr", "б", "кхузткъе кхаанца"), + (64, "dat", "й", "кхузткъе йеанна"), + (65, "instr", "й", "кхузткъе нхеанца"), + (66, "all", "б", "кхузткъе ялханга"), + (67, "erg", "д", "кхузткъе ворхӀамма"), + (68, "instr", "д", "кхузткъе бархӀанца"), + (69, "mat", "й", "кхузткъе иссаннах"), + (70, "attr", "б", "кхузткъе итт"), + (71, "gen", "б", "кхузткъе цхьайттаннан"), + (72, "abs", "й", "кхузткъе шийтта"), + (73, "mat", "д", "кхузткъе кхойттаннах"), + (74, "instr", "й", "кхузткъе йейттанца"), + (75, "mat", "в", "кхузткъе пхийттаннах"), + (76, "instr", "б", "кхузткъе ялхиттанца"), + (77, "dat", "в", "кхузткъе вуьрхӀиттанна"), + (78, "erg", "д", "кхузткъе берхӀиттамма"), + (79, "gen", "б", "кхузткъе ткъайеснаннан"), + (80, "dat", "б", "дезткъанна"), + (81, "gen", "б", "дезткъе цхьаннан"), + (82, "dat", "б", "дезткъе шинна"), + (83, "obl", "д", "дезткъе кхона"), + (84, "erg", "в", "дезткъе веамма"), + (85, "all", "в", "дезткъе пхеанга"), + (86, "erg", "д", "дезткъе ялхамма"), + (87, "comp", "б", "дезткъе ворхӀаннал"), + (88, "dat", "д", "дезткъе бархӀанна"), + (89, "erg", "б", "дезткъе иссамма"), + (90, "obl", "й", "дезткъе иттан"), + (91, "obl", "б", "дезткъе цхьайттан"), + (92, "abs", "б", "дезткъе шийтта"), + (93, "gen", "в", "дезткъе кхойттаннан"), + (94, "comp", "б", "дезткъе бейттаннал"), + (95, "all", "б", "дезткъе пхийттанга"), + (96, "instr", "д", "дезткъе ялхиттанца"), + (97, "erg", "д", "дезткъе вуьрхӀиттамма"), + (98, "instr", "й", "дезткъе берхӀиттанца"), + (99, "instr", "б", "дезткъе ткъайеснанца"), + (0, "gen", "б", "нолан"), + (100, "mat", "б", "бӀеннах"), + (200, "attr", "д", "ши бӀе"), + (300, "obl", "в", "кхо бӀен"), + (400, "abs", "в", "ви бӀе"), + (500, "all", "й", "пхи бӀенга"), + (600, "abs", "й", "ялх бӀе"), + (700, "mat", "й", "ворхӀ бӀеннах"), + (800, "gen", "б", "бархӀ бӀеннан"), + (900, "mat", "в", "исс бӀеннах"), + (1000, "gen", "д", "эзарнан"), + (1100, "instr", "д", "эзар бӀенца"), + (1200, "instr", "д", "эзар ши бӀенца"), + (1300, "comp", "б", "эзар кхо бӀеннал"), + (1400, "instr", "д", "эзар ди бӀенца"), + (1500, "comp", "б", "эзар пхи бӀеннал"), + (1600, "erg", "б", "эзар ялх бӀемма"), + (1700, "attr", "д", "эзар ворхӀ бӀе"), + (1800, "obl", "д", "эзар бархӀ бӀен"), + (1900, "gen", "й", "эзар исс бӀеннан"), + (2000, "comp", "д", "ши эзарнал"), + (2022, "comp", "д", "ши эзар ткъе шиннал"), + (2100, "obl", "в", "ши эзар бӀен"), + (423000, "erg", "в", "ви бӀе ткъе кхо эзарно"), +] + +TEST_CASES_ORDINAL = [ + (1, "all", "б", "цхьалгӀа"), + (2, "dat", "в", "шолгӀа"), + (3, "obl", "й", "кхоалгӀа"), + (4, "dat", "б", "боьалгӀа"), + (5, "dat", "в", "пхоьалгӀа"), + (6, "abs", "в", "йолхалгӀа"), + (7, "abs", "в", "ворхӀалгӀа"), + (8, "abs", "д", "борхӀалӀа"), + (9, "comp", "д", "уьссалгӀа"), + (10, "erg", "д", "уьтталгӀа"), + (11, "all", "б", "цхьайтталгӀа"), + (12, "abs", "й", "шийтталга"), + (13, "gen", "в", "кхойтталгӀа"), + (14, "gen", "в", "вейтталгӀа"), + (15, "mat", "й", "пхийтталгӀа"), + (16, "dat", "й", "ялхитталгӀа"), + (17, "erg", "д", "вуьрхӀитталгӀа"), + (18, "erg", "й", "берхитталӀа"), + (19, "obl", "в", "ткъаесналгӀа"), + (20, "abs", "в", "ткъолгӀа"), + (21, "mat", "б", "ткъе цхьалгӀа"), + (22, "erg", "б", "ткъе шолгӀа"), + (23, "mat", "й", "ткъе кхоалгӀа"), + (24, "obl", "б", "ткъе боьалгӀа"), + (25, "abs", "д", "ткъе пхоьалгӀа"), + (26, "all", "й", "ткъе йолхалгӀа"), + (27, "mat", "в", "ткъе ворхӀалгӀа"), + (28, "instr", "д", "ткъе борхӀалӀа"), + (29, "obl", "б", "ткъе уьссалгӀа"), + (30, "dat", "б", "ткъе уьтталгӀа"), + (31, "obl", "й", "ткъе цхьайтталгӀа"), + (32, "comp", "д", "ткъе шийтталга"), + (33, "attr", "д", "ткъе кхойтталгӀа"), + (34, "gen", "в", "ткъе вейтталгӀа"), + (35, "erg", "д", "ткъе пхийтталгӀа"), + (36, "all", "в", "ткъе ялхитталгӀа"), + (37, "attr", "й", "ткъе вуьрхӀитталгӀа"), + (38, "erg", "б", "ткъе берхитталӀа"), + (39, "gen", "д", "ткъе ткъаесналгӀа"), + (40, "abs", "й", "шовзткъалгІа"), + (41, "erg", "й", "шовзткъе цхьалгӀа"), + (42, "comp", "й", "шовзткъе шолгӀа"), + (43, "obl", "д", "шовзткъе кхоалгӀа"), + (44, "all", "й", "шовзткъе йоьалгӀа"), + (45, "abs", "д", "шовзткъе пхоьалгӀа"), + (46, "comp", "д", "шовзткъе йолхалгӀа"), + (47, "comp", "й", "шовзткъе ворхӀалгӀа"), + (48, "attr", "б", "шовзткъе борхӀалӀа"), + (49, "comp", "й", "шовзткъе уьссалгӀа"), + (50, "abs", "д", "шовзткъе уьтталгӀа"), + (51, "dat", "б", "шовзткъе цхьайтталгӀа"), + (52, "comp", "в", "шовзткъе шийтталга"), + (53, "mat", "б", "шовзткъе кхойтталгӀа"), + (54, "all", "д", "шовзткъе дейтталгӀа"), + (55, "dat", "в", "шовзткъе пхийтталгӀа"), + (56, "erg", "б", "шовзткъе ялхитталгӀа"), + (57, "comp", "й", "шовзткъе вуьрхӀитталгӀа"), + (58, "instr", "в", "шовзткъе берхитталӀа"), + (59, "mat", "б", "шовзткъе ткъаесналгӀа"), + (60, "all", "в", "кхузткъалгІа"), + (61, "obl", "д", "кхузткъе цхьалгӀа"), + (62, "instr", "д", "кхузткъе шолгӀа"), + (63, "erg", "й", "кхузткъе кхоалгӀа"), + (64, "dat", "д", "кхузткъе доьалгӀа"), + (65, "gen", "д", "кхузткъе пхоьалгӀа"), + (66, "mat", "в", "кхузткъе йолхалгӀа"), + (67, "gen", "в", "кхузткъе ворхӀалгӀа"), + (68, "attr", "б", "кхузткъе борхӀалӀа"), + (69, "all", "д", "кхузткъе уьссалгӀа"), + (70, "mat", "в", "кхузткъе уьтталгӀа"), + (71, "gen", "й", "кхузткъе цхьайтталгӀа"), + (72, "obl", "й", "кхузткъе шийтталга"), + (73, "attr", "в", "кхузткъе кхойтталгӀа"), + (74, "dat", "б", "кхузткъе бейтталгӀа"), + (75, "instr", "в", "кхузткъе пхийтталгӀа"), + (76, "gen", "в", "кхузткъе ялхитталгӀа"), + (77, "erg", "д", "кхузткъе вуьрхӀитталгӀа"), + (78, "all", "й", "кхузткъе берхитталӀа"), + (79, "instr", "д", "кхузткъе ткъаесналгӀа"), + (80, "dat", "в", "дезткъалгІа"), + (81, "mat", "в", "дезткъе цхьалгӀа"), + (82, "abs", "д", "дезткъе шолгӀа"), + (83, "abs", "д", "дезткъе кхоалгӀа"), + (84, "erg", "в", "дезткъе воьалгӀа"), + (85, "obl", "й", "дезткъе пхоьалгӀа"), + (86, "instr", "д", "дезткъе йолхалгӀа"), + (87, "all", "в", "дезткъе ворхӀалгӀа"), + (88, "dat", "д", "дезткъе борхӀалӀа"), + (89, "obl", "б", "дезткъе уьссалгӀа"), + (90, "instr", "в", "дезткъе уьтталгӀа"), + (91, "abs", "й", "дезткъе цхьайтталгӀа"), + (92, "comp", "в", "дезткъе шийтталга"), + (93, "erg", "д", "дезткъе кхойтталгӀа"), + (94, "obl", "й", "дезткъе йейтталгӀа"), + (95, "comp", "б", "дезткъе пхийтталгӀа"), + (96, "obl", "б", "дезткъе ялхитталгӀа"), + (97, "gen", "й", "дезткъе вуьрхӀитталгӀа"), + (98, "dat", "б", "дезткъе берхитталӀа"), + (99, "abs", "д", "дезткъе ткъаесналгӀа"), + (100, "abs", "в", "бІолгІа"), + (200, "obl", "й", "ши бІолгІа"), + (300, "mat", "в", "кхо бІолгІа"), + (400, "gen", "б", "би бІолгІа"), + (500, "erg", "й", "пхи бІолгІа"), + (600, "gen", "д", "ялх бІолгІа"), + (700, "instr", "й", "ворхӀ бІолгІа"), + (800, "all", "б", "бархӀ бІолгІа"), + (900, "comp", "б", "исс бІолгІа"), + (1000, "dat", "д", "эзарлагІа"), + (107, "gen", "в", "бӀе ворхӀалгӀа"), + (214, "attr", "д", "ши бӀе дейтталгӀа"), + (321, "comp", "д", "кхо бӀе ткъе цхьалгӀа"), + (428, "dat", "в", "ви бӀе ткъе борхӀалӀа"), + (535, "erg", "й", "пхи бӀе ткъе пхийтталгӀа"), + (642, "all", "й", "ялх бӀе шовзткъе шолгӀа"), + (749, "mat", "в", "ворхӀ бӀе шовзткъе уьссалгӀа"), + (856, "attr", "й", "бархӀ бӀе шовзткъе ялхитталгӀа"), + (963, "mat", "б", "исс бӀе кхузткъе кхоалгӀа"), + (1070, "comp", "в", "эзар кхузткъе уьтталгӀа"), + (1177, "dat", "в", "эзар бӀе кхузткъе вуьрхӀитталгӀа"), + (1284, "abs", "д", "эзар ши бӀе дезткъе доьалгӀа"), + (1391, "dat", "в", "эзар кхо бӀе дезткъе цхьайтталгӀа"), + (1498, "abs", "в", "эзар ви бӀе дезткъе берхитталӀа"), + (1605, "obl", "б", "эзар ялх бӀе пхоьалгӀа"), + (1712, "erg", "й", "эзар ворхӀ бӀе шийтталга"), + (1819, "all", "б", "эзар бархӀ бӀе ткъаесналгӀа"), + (1926, "abs", "б", "эзар исс бӀе ткъе йолхалгӀа"), + (2033, "all", "д", "ши эзар ткъе кхойтталгӀа"), + (2140, "dat", "б", "ши эзар бӀе шовзткъалгІа"), + (423000, "dat", "д", "ди бӀе ткъе кхо эзарлагІа"), +] + +TEST_CASES_YEAR = [ + (1719, "abs", "эзар ворхӀ бӀе ткъайесна"), + (1812, "abs", "эзар бархӀ бӀе шийтта"), + (1926, "abs", "эзар исс бӀе ткъе ялх"), +] + +TEST_CASES_DECIMALS = [(123.4567, "бӀе ткъе кхоъ а диъ пхиъ ялх ворхӀ")] + +TEST_CASES_MILLIONS = [ + (200020, "ши бӀе эзар ткъа"), + (4000400, "ди миллион ди бӀе"), + (60006000, "кхузткъе миллион ялх эзар"), + (800080000, "бархӀ бӀе миллион дезткъе эзар"), + (10001000000, "итт миллиард цхьа миллион"), + (120012000000, "бӀе ткъе миллиард шийтта миллион"), + (1400140000000, "цхьа биллион ди бӀе миллиард бӀе шовзткъе миллион"), + (16001600000000, "ялхитта биллион цхьа миллиард ялх бӀе миллион"), + (180018000000000, "бӀе дезткъе биллион берхӀитта миллиард"), + (2000200000000000, "ши биллиард ши бӀе миллиард"), + (22002200000000000, "ткъе ши биллиард ши биллион ши бӀе миллиард"), + (240024000000000000, "ши бӀе шовзткъе биллиард ткъе ди биллион"), + ( + 2600260000000000000, + "ши триллион ялх бӀе биллиард ши бӀе кхузткъе биллион", + ), + ( + 28002800000000000000, + "ткъе бархӀ триллион ши биллиард бархӀ бӀе биллион", + ), + (300030000000000000000, "кхо бӀе триллион ткъе итт биллиард"), + ( + 3200320000000000000000, + "кхо триллиард ши бӀе триллион кхо бӀе ткъе биллиард", + ), + ( + 34003400000000000000000, + "ткъе дейтта триллиард кхо триллион ди бӀе биллиард", + ), + ( + 360036000000000000000000, + "кхо бӀе кхузткъе триллиард ткъе ялхитта триллион", + ), + ( + 3800380000000000000000000, + "кхо квадриллион бархӀ бӀе триллиард кхо бӀе дезткъе триллион", + ), + (40004000000000000000000000, "шовзткъе квадриллион ди триллиард"), + ( + 420042000000000000000000000, + "ди бӀе ткъе квадриллион шовзткъе ши триллиард", + ), + ( + 4400440000000000000000000000, + "ди квадриллиард ди бӀе квадриллион ди бӀе шовзткъе триллиард", + ), + ( + 46004600000000000000000000000, + "шовзткъе ялх квадриллиард ди квадриллион ялх бӀе триллиард", + ), + ( + 480048000000000000000000000000, + "ди бӀе дезткъе квадриллиард шовзткъе бархӀ квадриллион", + ), + (5000500000000000000000000000000, "пхи квинтиллион пхи бӀе квадриллион"), + ( + 52005200000000000000000000000000, + "шовзткъе шийтта квинтиллион пхи квадриллиард ши бӀе квадриллион", + ), + ( + 540054000000000000000000000000000, + "пхи бӀе шовзткъе квинтиллион шовзткъе дейтта квадриллиард", + ), + ( + 5600560000000000000000000000000000, + "пхи квинтиллиард ялх бӀе квинтиллион пхи бӀе кхузткъе квадриллиард", + ), + (10**56, "NOT IMPLEMENTED") +] + +TEST_CURRENCY = [ + (143.55, "abs", "RUB", "бӀе шовзткъе кхо Сом, шовзткъе пхийтта Кепек"), + (243.15, "dat", "RUB", "ши бӀе шовзткъе кхона Сом, пхийттан Кепек"), +] + + +class Num2WordsCETest(TestCase): + def test_number(self): + for test in TEST_CASES_CARDINAL: + self.assertEqual( + num2words(test[0], lang="ce", case=test[1], clazz=test[2]), + test[3], + ) + + def test_millions(self): + for test in TEST_CASES_MILLIONS: + self.assertEqual(num2words(test[0], lang="ce"), test[1]) + + def test_ordinal_number(self): + for test in TEST_CASES_ORDINAL: + self.assertEqual( + num2words(test[0], lang="ce", to="ordinal", clazz=test[2]), + test[3], + ) + self.assertEqual(num2words(3, to="ordinal_num", lang='ce'), "3-й") + self.assertEqual(num2words(5, to="ordinal_num", lang='ce'), "5-й") + self.assertEqual(num2words(82, to="ordinal_num", lang='ce'), "82-й") + + def test_year(self): + for test in TEST_CASES_YEAR: + self.assertEqual( + num2words(test[0], lang="ce", to="year", case=test[1]), test[2] + ) + + def test_currency(self): + for test in TEST_CURRENCY: + self.assertEqual( + num2words( + test[0], + lang="ce", + to="currency", + currency=test[2], + case=test[1], + ), + test[3], + ) + + def test_currency_missing(self): + with self.assertRaises(NotImplementedError): + num2words(2.45, to="currency", lang='cy', currency="DEM") + + def test_decimals(self): + for test in TEST_CASES_DECIMALS: + self.assertEqual(num2words(test[0], lang="ce"), test[1]) diff --git a/tests/test_cz.py b/tests/test_cs.py similarity index 72% rename from tests/test_cz.py rename to tests/test_cs.py index 1801e8f7..2c2b0e5f 100644 --- a/tests/test_cz.py +++ b/tests/test_cs.py @@ -22,39 +22,39 @@ from num2words import num2words -class Num2WordsCZTest(TestCase): +class Num2WordsCSTest(TestCase): def test_cardinal(self): - self.assertEqual(num2words(100, lang='cz'), "sto") - self.assertEqual(num2words(101, lang='cz'), "sto jedna") - self.assertEqual(num2words(110, lang='cz'), "sto deset") - self.assertEqual(num2words(115, lang='cz'), "sto patnáct") - self.assertEqual(num2words(123, lang='cz'), "sto dvacet tři") - self.assertEqual(num2words(1000, lang='cz'), "tisíc") - self.assertEqual(num2words(1001, lang='cz'), "tisíc jedna") - self.assertEqual(num2words(2012, lang='cz'), "dva tisíce dvanáct") - self.assertEqual( - num2words(10.02, lang='cz'), + self.assertEqual(num2words(100, lang='cs'), "sto") + self.assertEqual(num2words(101, lang='cs'), "sto jedna") + self.assertEqual(num2words(110, lang='cs'), "sto deset") + self.assertEqual(num2words(115, lang='cs'), "sto patnáct") + self.assertEqual(num2words(123, lang='cs'), "sto dvacet tři") + self.assertEqual(num2words(1000, lang='cs'), "tisíc") + self.assertEqual(num2words(1001, lang='cs'), "tisíc jedna") + self.assertEqual(num2words(2012, lang='cs'), "dva tisíce dvanáct") + self.assertEqual( + num2words(10.02, lang='cs'), "deset celá nula dva" ) self.assertEqual( - num2words(15.007, lang='cz'), + num2words(15.007, lang='cs'), "patnáct celá nula nula sedm" ) self.assertEqual( - num2words(12519.85, lang='cz'), + num2words(12519.85, lang='cs'), "dvanáct tisíc pětset devatenáct celá osmdesát pět" ) self.assertEqual( - num2words(123.50, lang='cz'), + num2words(123.50, lang='cs'), "sto dvacet tři celá pět" ) self.assertEqual( - num2words(1234567890, lang='cz'), + num2words(1234567890, lang='cs'), "miliarda dvěstě třicet čtyři miliony pětset šedesát " "sedm tisíc osmset devadesát" ) self.assertEqual( - num2words(215461407892039002157189883901676, lang='cz'), + num2words(215461407892039002157189883901676, lang='cs'), "dvěstě patnáct quintillionů čtyřista šedesát jedna kvadriliard " "čtyřista sedm kvadrilionů osmset devadesát dva triliardy třicet " "devět trilionů dva biliardy sto padesát sedm bilionů sto " @@ -62,7 +62,7 @@ def test_cardinal(self): "devětset jedna tisíc šestset sedmdesát šest" ) self.assertEqual( - num2words(719094234693663034822824384220291, lang='cz'), + num2words(719094234693663034822824384220291, lang='cs'), "sedmset devatenáct quintillionů devadesát " "čtyři kvadriliardy dvěstě třicet čtyři " "kvadriliony šestset devadesát tři triliardy " @@ -75,40 +75,40 @@ def test_cardinal(self): def test_to_ordinal(self): # @TODO: implement to_ordinal with self.assertRaises(NotImplementedError): - num2words(1, lang='cz', to='ordinal') + num2words(1, lang='cs', to='ordinal') def test_currency(self): self.assertEqual( - num2words(10.0, lang='cz', to='currency', currency='EUR'), + num2words(10.0, lang='cs', to='currency', currency='EUR'), "deset euro, nula centů") self.assertEqual( - num2words(1.0, lang='cz', to='currency', currency='CZK'), + num2words(1.0, lang='cs', to='currency', currency='CZK'), "jedna koruna, nula haléřů") self.assertEqual( - num2words(1234.56, lang='cz', to='currency', currency='EUR'), + num2words(1234.56, lang='cs', to='currency', currency='EUR'), "tisíc dvěstě třicet čtyři euro, padesát šest centů") self.assertEqual( - num2words(1234.56, lang='cz', to='currency', currency='CZK'), + num2words(1234.56, lang='cs', to='currency', currency='CZK'), "tisíc dvěstě třicet čtyři koruny, padesát šest haléřů") self.assertEqual( - num2words(101.11, lang='cz', to='currency', currency='EUR', + num2words(101.11, lang='cs', to='currency', currency='EUR', separator=' a'), "sto jedna euro a jedenáct centů") self.assertEqual( - num2words(101.21, lang='cz', to='currency', currency='CZK', + num2words(101.21, lang='cs', to='currency', currency='CZK', separator=' a'), "sto jedna korun a dvacet jedna haléřů" ) self.assertEqual( - num2words(-12519.85, lang='cz', to='currency', cents=False), + num2words(-12519.85, lang='cs', to='currency', cents=False), "mínus dvanáct tisíc pětset devatenáct euro, 85 centů" ) self.assertEqual( - num2words(123.50, lang='cz', to='currency', currency='CZK', + num2words(123.50, lang='cs', to='currency', currency='CZK', separator=' a'), "sto dvacet tři koruny a padesát haléřů" ) self.assertEqual( - num2words(19.50, lang='cz', to='currency', cents=False), + num2words(19.50, lang='cs', to='currency', cents=False), "devatenáct euro, 50 centů" ) diff --git a/tests/test_cy.py b/tests/test_cy.py new file mode 100644 index 00000000..3f7ee038 --- /dev/null +++ b/tests/test_cy.py @@ -0,0 +1,475 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2023, Johannes Heinecke. 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 +from __future__ import unicode_literals + +from unittest import TestCase + +from num2words import num2words + +TEST_CASES_CARDINAL = ( + (0, "dim"), + (1, "un"), + (1, "un"), + (2, "dau"), + (3, "tri"), + (4, "pedwar"), + (5, "pump"), + (6, "chwech"), + (7, "saith"), + (8, "wyth"), + (9, "naw"), + (10, "deg"), + (11, "un ar ddeg"), + (12, "deuddeg"), + (13, "tri ar ddeg"), + (14, "pedwar ar ddeg"), + (15, "pymtheg"), + (16, "un ar bymtheg"), + (17, "dau ar bymtheg"), + (18, "deunaw"), + (19, "pedwar ar bymtheg"), + (20, "ugain"), + (21, "un ar hugain"), + (22, "dau ar hugain"), + (23, "tri ar hugain"), + (24, "pedwar ar hugain"), + (25, "pump ar hugain"), + (26, "chwech ar hugain"), + (27, "saith ar hugain"), + (28, "wyth ar hugain"), + (29, "naw ar hugain"), + (30, "deg ar hugain"), + (31, "un ar ddeg ar hugain"), + (32, "deuddeg ar hugain"), + (33, "tri ar ddeg ar hugain"), + (34, "pedwar ar ddeg ar hugain"), + (35, "pymtheg ar hugain"), + (36, "un ar bymtheg ar hugain"), + (37, "dau ar bymtheg ar hugain"), + (38, "deunaw ar hugain"), + (39, "pedwar ar bymtheg ar hugain"), + (40, "deugain"), + (41, "un a deugain"), + (42, "dau a deugain"), + (43, "tri a deugain"), + (44, "pedwar a deugain"), + (45, "pump a deugain"), + (46, "chwech a deugain"), + (47, "saith a deugain"), + (48, "wyth a deugain"), + (49, "naw a deugain"), + (50, "hanner cant"), + (51, "hanner cant ac un"), + (52, "hanner cant a dau"), + (53, "hanner cant a thri"), + (54, "hanner cant a phedwar"), + (55, "hanner cant a phump"), + (56, "hanner cant a chwech"), + (57, "hanner cant a saith"), + (58, "hanner cant a wyth"), + (59, "hanner cant a naw"), + (60, "trigain"), + (61, "un a thrigain"), + (62, "dau a thrigain"), + (63, "tri a thrigain"), + (64, "pedwar a thrigain"), + (65, "pump a thrigain"), + (66, "chwech a thrigain"), + (67, "saith a thrigain"), + (68, "wyth a thrigain"), + (69, "naw a thrigain"), + (70, "deg a thrigain"), + (71, "un ar ddeg a thrigain"), + (72, "deuddeg a thrigain"), + (73, "tri ar ddeg a thrigain"), + (74, "pedwar ar ddeg a thrigain"), + (75, "pymtheg a thrigain"), + (76, "un ar bymtheg a thrigain"), + (77, "dau ar bymtheg a thrigain"), + (78, "deunaw a thrigain"), + (79, "pedwar ar bymtheg a thrigain"), + (80, "pedwar ugain"), + (81, "un a phedwar ugain"), + (82, "dau a phedwar ugain"), + (83, "tri a phedwar ugain"), + (84, "pedwar a phedwar ugain"), + (85, "pump a phedwar ugain"), + (86, "chwech a phedwar ugain"), + (87, "saith a phedwar ugain"), + (88, "wyth a phedwar ugain"), + (89, "naw a phedwar ugain"), + (90, "deg a phedwar ugain"), + (91, "un ar ddeg a phedwar ugain"), + (92, "deuddeg a phedwar ugain"), + (93, "tri ar ddeg a phedwar ugain"), + (94, "pedwar ar ddeg a phedwar ugain"), + (95, "pymtheg a phedwar ugain"), + (96, "un ar bymtheg a phedwar ugain"), + (97, "dau ar bymtheg a phedwar ugain"), + (98, "deunaw a phedwar ugain"), + (99, "pedwar ar bymtheg a phedwar ugain"), + (100, "cant"), + (101, "cant ac un"), + (102, "cant a dau"), + (103, "cant a thri"), + (104, "cant a phedwar"), + (105, "cant a phump"), + (106, "cant a chwech"), + (107, "cant a saith"), + (108, "cant ac wyth"), + (109, "cant a naw"), + (110, "cant a deg"), + (111, "cant ac un ar ddeg"), + (112, "cant a deuddeg"), + (113, "cant a thri ar ddeg"), + (114, "cant a phedwar ar ddeg"), + (115, "cant a phymtheg"), + (116, "cant ac un ar bymtheg"), + (117, "cant a dau ar bymtheg"), + (118, "cant a deunaw"), + (119, "cant a phedwar ar bymtheg"), + (120, "cant ac ugain"), + (121, "cant ac un ar hugain"), + (122, "cant a dau ar hugain"), + (100, "cant"), + (217, "dau gant a dau ar bymtheg"), + (334, "tri chant a phedwar ar ddeg ar hugain"), + (451, "pedwar cant a hanner ac un"), + (568, "pump cant ac wyth a thrigain"), + (685, "chwech chant a phump a phedwar ugain"), + (802, "wyth cant a dau"), + (919, "naw cant a phedwar ar bymtheg"), + (100, "cant"), + (150, "cant a hanner"), + (200, "dau gant"), + (300, "tri chant"), + (400, "pedwar cant"), + (500, "pump cant"), + (600, "chwech chant"), + (700, "saith cant"), + (800, "wyth cant"), + (900, "naw cant"), + (1000, "mil"), + (1000, "mil"), + (12111, "deuddeg mil cant ac un ar ddeg"), + (23222, "tair ar hugain mil dau gant a dau ar hugain"), + ( + 34333, + "pedair ar ddeg ar hugain mil tri chant a thri ar ddeg ar hugain", + ), + (45444, "pump a deugain mil pedwar cant a phedwar a deugain"), + (56555, "hanner cant a chwech mil pump cant a hanner a phump"), + (67666, "saith a thrigain mil chwech chant a chwech a thrigain"), + (78777, "deunaw a thrigain mil saith cant a dau ar bymtheg a thrigain"), + (89888, "naw a phedwar ugain mil wyth cant ac wyth a phedwar ugain"), + (100999, "cant mil naw cant a phedwar ar bymtheg a phedwar ugain"), + (112110, "cant a deuddeg mil cant a deg"), + (123221, "cant a thair ar hugain mil dau gant ac un ar hugain"), + ( + 134332, + "cant a phedair ar ddeg ar hugain mil tri chant a deuddeg ar hugain", + ), + (145443, "cant a phump a deugain mil pedwar cant a thri a deugain"), + (156554, "cant a hanner a chwech mil pump cant a hanner a phedwar"), + (123, "cant a thri ar hugain"), + (2345, "dwy fil tri chant a phump a deugain"), + (34567, "pedair ar ddeg ar hugain mil pump cant a saith a thrigain"), + (654321, "chwech chant a hanner a phedair mil tri chant ac un ar hugain"), + ( + 7654321, + "saith miliwn chwech chant a hanner a " + "phedair mil tri chant ac un ar hugain", + ), + ( + 987654321, + "naw cant a saith a phedwar ugain miliwn chwech chant a " + "hanner a phedair mil tri chant ac un ar hugain", + ), + ( + 123456789012, + "cant a thri ar hugain biliwn pedwar cant a hanner a chwech miliwn " + "saith cant a naw a phedwar ugain mil deuddeg", + ), + (2023, "dwy fil tri ar hugain"), + (-40123, "meinws deugain mil cant a thri ar hugain"), + (12340000000000000, "deuddeg cwadriliwn tri chant a deugain triliwn"), + (3000000000000000, "tri chwadriliwn"), + (2500000000000000000000000000000000, "dau ddengiliwn pump cant noniliwn"), +) + + +TEST_CASES_CARDINAL_FEM = ( + (2, "dwy"), + (3, "tair"), + (4, "pedair"), + (5, "pump"), + (6, "chwech"), + (7, "saith"), + (8, "wyth"), + (9, "naw"), + (10, "deg"), + (11, "un ar ddeg"), + (12, "deuddeg"), + (13, "tair ar ddeg"), + (14, "pedair ar ddeg"), + (15, "pymtheg"), + (16, "un ar bymtheg"), + (17, "dwy ar bymtheg"), + (18, "deunaw"), + (19, "pedair ar bymtheg"), + (20, "ugain"), + (21, "un ar hugain"), + (22, "dwy ar hugain"), + (23, "tair ar hugain"), + (24, "pedair ar hugain"), + (25, "pump ar hugain"), + (26, "chwech ar hugain"), + (27, "saith ar hugain"), + (28, "wyth ar hugain"), + (29, "naw ar hugain"), + (30, "deg ar hugain"), + (31, "un ar ddeg ar hugain"), + (32, "deuddeg ar hugain"), + (33, "tair ar ddeg ar hugain"), + (34, "pedair ar ddeg ar hugain"), + (35, "pymtheg ar hugain"), + (36, "un ar bymtheg ar hugain"), + (37, "dwy ar bymtheg ar hugain"), + (38, "deunaw ar hugain"), + (39, "pedair ar bymtheg ar hugain"), + (40, "deugain"), + (41, "un a deugain"), + (42, "dwy a deugain"), + (43, "tair a deugain"), + (44, "pedair a deugain"), + (45, "pump a deugain"), + (46, "chwech a deugain"), + (47, "saith a deugain"), + (48, "wyth a deugain"), + (49, "naw a deugain"), + (50, "hanner cant"), + (51, "hanner cant ac un"), + (52, "hanner cant a dwy"), + (53, "hanner cant a thair"), + (54, "hanner cant a phedair"), + (55, "hanner cant a phump"), + (56, "hanner cant a chwech"), + (57, "hanner cant a saith"), + (58, "hanner cant a wyth"), + (59, "hanner cant a naw"), + (60, "trigain"), + (61, "un a thrigain"), + (62, "dwy a thrigain"), +) + +TEST_CASES_ORDINAL = ( + (0, "dimfed"), + (1, "cyntaf"), + (2, "ail"), + (3, "trydydd"), + (4, "pedwerydd"), + (5, "pumed"), + (6, "chweched"), + (7, "saithfed"), + (8, "wythfed"), + (9, "nawfed"), + (10, "degfed"), + (11, "unfed ar ddeg"), + (12, "deuddegfed"), + (13, "trydydd ar ddeg"), + (14, "pedwerydd ar ddeg"), + (15, "pymthegfed"), + (16, "unfed ar bymtheg"), + (17, "ail ar bymtheg"), + (18, "deunawfed"), + (19, "pedwerydd ar bymtheg"), + (20, "ugainfed"), + (21, "cyntaf ar hugain"), + (22, "ail ar hugain"), + (23, "trydydd ar hugain"), + (24, "pedwerydd ar hugain"), + (25, "pumed ar hugain"), + (26, "chweched ar hugain"), + (27, "saithfed ar hugain"), + (28, "wythfed ar hugain"), + (29, "nawfed ar hugain"), + (30, "degfed ar hugain"), + (31, "unfed ar ddeg ar hugain"), + (32, "deuddegfed ar hugain"), + (33, "trydydd ar ddeg ar hugain"), + (34, "pedwerydd ar ddeg ar hugain"), + (35, "pymthegfed ar hugain"), + (36, "unfed ar bymtheg ar hugain"), + (37, "ail ar bymtheg ar hugain"), + (38, "deunawfed ar hugain"), + (39, "pedwerydd ar bymtheg ar hugain"), + (40, "deugainfed"), + (41, "cyntaf a deugain"), + (42, "ail a deugain"), + (43, "trydydd a deugain"), + (44, "pedwerydd a deugain"), + (45, "pumed a deugain"), + (46, "chweched a deugain"), + (47, "saithfed a deugain"), + (48, "wythfed a deugain"), + (49, "nawfed a deugain"), + (50, "degfed a deugain"), + (51, "unfed ar ddeg a deugain"), + (52, "deuddegfed a deugain"), + (53, "trydydd ar ddeg a deugain"), + (54, "pedwerydd ar ddeg a deugain"), + (55, "pymthegfed a deugain"), + (56, "unfed ar bymtheg a deugain"), + (57, "ail ar bymtheg a deugain"), + (58, "deunawfed a deugain"), + (59, "pedwerydd ar bymtheg a deugain"), + (60, "trigainfed"), + (61, "cyntaf a thrigain"), + (62, "ail a thrigain"), + (63, "trydydd a thrigain"), + (64, "pedwerydd a thrigain"), + (65, "pumed a thrigain"), + (66, "chweched a thrigain"), + (67, "saithfed a thrigain"), + (68, "wythfed a thrigain"), + (69, "nawfed a thrigain"), + (70, "degfed a thrigain"), + (71, "unfed ar ddeg a thrigain"), + (72, "deuddegfed a thrigain"), + (73, "trydydd ar ddeg a thrigain"), + (74, "pedwerydd ar ddeg a thrigain"), + (75, "pymthegfed a thrigain"), + (76, "unfed ar bymtheg a thrigain"), + (77, "ail ar bymtheg a thrigain"), + (78, "deunawfed a thrigain"), + (79, "pedwerydd ar bymtheg a thrigain"), + (80, "pedwar ugainfed"), + (81, "cyntaf a phedwar ugain"), + (82, "ail a phedwar ugain"), + (83, "trydydd a phedwar ugain"), + (84, "pedwerydd a phedwar ugain"), + (85, "pumed a phedwar ugain"), + (86, "chweched a phedwar ugain"), + (87, "saithfed a phedwar ugain"), + (88, "wythfed a phedwar ugain"), + (89, "nawfed a phedwar ugain"), + (90, "degfed a phedwar ugain"), + (91, "unfed ar ddeg a phedwar ugain"), + (92, "deuddegfed a phedwar ugain"), + (93, "trydydd ar ddeg a phedwar ugain"), + (94, "pedwerydd ar ddeg a phedwar ugain"), + (95, "pymthegfed a phedwar ugain"), + (96, "unfed ar bymtheg a phedwar ugain"), + (97, "ail ar bymtheg a phedwar ugain"), + (98, "deunawfed a phedwar ugain"), + (99, "pedwerydd ar bymtheg a phedwar ugain"), + (100, "canfed"), +) + +TEST_CASES_YEAR = [ + (1922, "mil naw dau dau"), + (1989, "mil naw wyth naw"), + (1812, "mil wyth un dau"), + (2012, "dwy fil deuddeg"), + (2023, "dwy fil tri ar hugain") + ] + +TEST_CASES_DECIMALS = [ + (123.4567, "cant a thri ar hugain pwynt pedwar pump chwech saith") +] + +TEST_CASES_TO_CURRENCY_GBP = ( + (0.00, "dim punt"), + (0.23, "tri cheiniog ar hugain"), + (2.04, "dwy bunt, pedwar ceiniog"), + (3.50, "tair punt, hanner cant ceiniog"), + (2002.15, "dwy fil dwy o bunnoedd, pymtheg ceiniog"), + (100.01, "cant punt, ceiniog"), + (50.00, "hanner cant punt"), + (51.00, "hanner cant ac un punt"), + (152.50, "cant a hanner a dwy o bunnoedd, hanner cant ceiniog"), +) + +TEST_CASES_COUNTED = [ + (2, "ci", "masc", "dau gi"), + (2, "ty", "masc", "dau dy"), + (2, "llwy", "fem", "dwy lwy"), + (2, "rhaglen", "masc", "dau raglen"), + (11, "ci", "masc", "un ci ar ddeg"), + (13, "ci", "masc", "tri chi ar ddeg"), + (26, "ci", "masc", "chwech chi ar hugain"), + (56, "ci", "masc", "hanner cant a chwech chi"), + (100, "cwn", "masc", "cant o gwn"), + (2000, "cathod", "fem", "dwy fil o gathod"), + (11, "cath", "fem", "un cath ar ddeg"), + (13, "cath", "fem", "tair cath ar ddeg"), + (26, "cath", "fem", "chwech chath ar hugain"), + (42, "cath", "fem", "dwy gath a deugain"), + (56, "cath", "fem", "hanner cant a chwech chath"), +] + + +class Num2WordsCYTest(TestCase): + def test_number(self): + for test in TEST_CASES_CARDINAL: + self.assertEqual(num2words(test[0], lang="cy"), test[1]) + + def test_number_fem(self): + for test in TEST_CASES_CARDINAL_FEM: + self.assertEqual( + num2words(test[0], lang="cy", gender="fem"), test[1] + ) + + def test_number_not_implemented(self): + with self.assertRaises(NotImplementedError): + num2words(10**66, lang='cy') + + def test_decimals(self): + for test in TEST_CASES_DECIMALS: + self.assertEqual(num2words(test[0], lang="cy"), test[1]) + + def test_ordinals(self): + for test in TEST_CASES_ORDINAL: + self.assertEqual( + num2words(test[0], lang="cy", to="ordinal"), test[1] + ) + + def test_ordinal_not_implemented(self): + with self.assertRaises(NotImplementedError): + num2words(101, lang='cy', to="ordinal") + + def test_pounds(self): + for test in TEST_CASES_TO_CURRENCY_GBP: + self.assertEqual( + num2words(test[0], lang="cy", to="currency", currency="GBP"), + test[1], + ) + + def test_other_cur(self): + with self.assertRaises(NotImplementedError): + num2words(10.23, lang="cy", to="currency", currency="DEM"), + + def test_counted(self): + for test in TEST_CASES_COUNTED: + self.assertEqual( + num2words( + test[0], lang="cy", counted=test[1], gender=test[2] + ), + test[3], + ) + +# TODO 'ordinal_num', 'year' diff --git a/tests/test_dk.py b/tests/test_dk.py index 889e9d8e..4c2e6ce3 100644 --- a/tests/test_dk.py +++ b/tests/test_dk.py @@ -20,6 +20,7 @@ from unittest import TestCase from num2words import num2words +from num2words.lang_DK import Num2Word_DK class Num2WordsDKTest(TestCase): @@ -35,3 +36,10 @@ def test_cardinal(self): self.assertEqual(num2words(8, to="cardinal", lang="dk"), "otte") self.assertEqual(num2words(18, to="cardinal", lang="dk"), "atten") self.assertEqual(num2words(45, to="cardinal", lang="dk"), "femogfyrre") + + def test_to_ordinal_num(self): + num2words_dk = Num2Word_DK() + self.assertEqual(num2words_dk.to_ordinal_num(1), "1te") + self.assertEqual(num2words_dk.to_ordinal_num(2), "2en") + self.assertEqual(num2words_dk.to_ordinal_num(5), "5te") + self.assertEqual(num2words_dk.to_ordinal_num(10), "10ende") diff --git a/tests/test_es_cr.py b/tests/test_es_cr.py new file mode 100644 index 00000000..a6a451b8 --- /dev/null +++ b/tests/test_es_cr.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2003, Taro Ogawa. All Rights Reserved. +# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. +# Copyright (c) 2024, Randall Castro. 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 + +from __future__ import unicode_literals + +from num2words import num2words + +from . import test_es + +TEST_CASES_TO_CURRENCY = ( + (1, 'un colón'), + (2, 'dos colónes'), + (8, 'ocho colónes'), + (12, 'doce colónes'), + (21, 'veintiun colónes'), + (81.25, 'ochenta y un colónes y veinticinco céntimos'), + (100, 'cien colónes'), +) + + +class Num2WordsESCOTest(test_es.Num2WordsESTest): + + def test_number(self): + for test in test_es.TEST_CASES_CARDINAL: + self.assertEqual(num2words(test[0], lang='es_CR'), test[1]) + + def test_ordinal(self): + for test in test_es.TEST_CASES_ORDINAL: + self.assertEqual( + num2words(test[0], lang='es_CR', ordinal=True), + test[1] + ) + + def test_ordinal_num(self): + for test in test_es.TEST_CASES_ORDINAL_NUM: + self.assertEqual( + num2words(test[0], lang='es', to='ordinal_num'), + test[1] + ) + + def test_currency(self): + for test in TEST_CASES_TO_CURRENCY: + self.assertEqual( + num2words(test[0], lang='es_CR', to='currency'), + test[1] + ) diff --git a/tests/test_ja.py b/tests/test_ja.py index 42da1445..18c3482f 100644 --- a/tests/test_ja.py +++ b/tests/test_ja.py @@ -20,6 +20,7 @@ from unittest import TestCase from num2words import num2words +from num2words.lang_JA import rendaku_merge_pairs def n2j(*args, **kwargs): @@ -196,3 +197,20 @@ def test_year(self): "きげんぜんきゅうじゅうくねん") self.assertEqual(n2j(1375, to="year"), "天授元年") self.assertEqual(n2j(1375, to="year", prefer=["えいわ"]), "永和元年") + + def test_rendaku_merge_pairs(self): + self.assertEqual(rendaku_merge_pairs(("はち", 8), ("ちょう", 10**12)), + ("はっちょう", 8 * 10**12)) + self.assertEqual(rendaku_merge_pairs(("じゅう", 10), ("ちょう", 10**12)), + ("じゅっちょう", 10 * 10**12)) + + self.assertEqual(rendaku_merge_pairs(("いち", 1), ("けい", 10**16)), + ("いっけい", 1 * 10**16)) + self.assertEqual(rendaku_merge_pairs(("ろく", 6), ("けい", 10**16)), + ("ろっけい", 6 * 10**16)) + self.assertEqual(rendaku_merge_pairs(("はち", 8), ("けい", 10**16)), + ("はっけい", 8 * 10**16)) + self.assertEqual(rendaku_merge_pairs(("じゅう", 10), ("けい", 10**16)), + ("じゅっけい", 10 * 10**16)) + self.assertEqual(rendaku_merge_pairs(("ひゃく", 100), ("けい", 10**16)), + ("ひゃっけい", 100 * 10**16)) diff --git a/tests/test_tet.py b/tests/test_tet.py new file mode 100644 index 00000000..7f005fd5 --- /dev/null +++ b/tests/test_tet.py @@ -0,0 +1,541 @@ +# -*- 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 + +import decimal +from decimal import Decimal +from unittest import TestCase + +from num2words import num2words +from num2words.lang_TET import Num2Word_TET + + +class Num2WordsTETTest(TestCase): + def setUp(self): + super().setUp() + self.n2w = Num2Word_TET() + + def test_cardinal_integer(self): + self.assertEqual(num2words(1, lang='tet'), 'ida') + self.assertEqual(num2words(2, lang='tet'), 'rua') + self.assertEqual(num2words(3, lang='tet'), 'tolu') + self.assertEqual(num2words(4, lang='tet'), 'haat') + self.assertEqual(num2words(5, lang='tet'), 'lima') + self.assertEqual(num2words(6, lang='tet'), 'neen') + self.assertEqual(num2words(7, lang='tet'), 'hitu') + self.assertEqual(num2words(8, lang='tet'), 'ualu') + self.assertEqual(num2words(9, lang='tet'), 'sia') + self.assertEqual(num2words(10, lang='tet'), 'sanulu') + self.assertEqual(num2words(11, lang='tet'), 'sanulu resin ida') + self.assertEqual(num2words(12, lang='tet'), 'sanulu resin rua') + self.assertEqual(num2words(13, lang='tet'), 'sanulu resin tolu') + self.assertEqual(num2words(14, lang='tet'), 'sanulu resin haat') + self.assertEqual(num2words(15, lang='tet'), 'sanulu resin lima') + self.assertEqual(num2words(16, lang='tet'), 'sanulu resin neen') + self.assertEqual(num2words(17, lang='tet'), 'sanulu resin hitu') + self.assertEqual(num2words(18, lang='tet'), 'sanulu resin ualu') + self.assertEqual(num2words(19, lang='tet'), 'sanulu resin sia') + self.assertEqual(num2words(20, lang='tet'), 'ruanulu') + + self.assertEqual(num2words(21, lang='tet'), 'ruanulu resin ida') + self.assertEqual(num2words(22, lang='tet'), 'ruanulu resin rua') + self.assertEqual(num2words(35, lang='tet'), 'tolunulu resin lima') + self.assertEqual(num2words(99, lang='tet'), 'sianulu resin sia') + + self.assertEqual(num2words(100, lang='tet'), 'atus ida') + self.assertEqual(num2words(101, lang='tet'), 'atus ida ida') + self.assertEqual(num2words(107, lang='tet'), 'atus ida hitu') + self.assertEqual(num2words(110, lang='tet'), 'atus ida sanulu') + self.assertEqual( + num2words(114, lang='tet'), + 'atus ida sanulu resin haat' + ) + self.assertEqual( + num2words(128, lang='tet'), + 'atus ida ruanulu resin ualu' + ) + self.assertEqual( + num2words(151, lang='tet'), + 'atus ida limanulu resin ida' + ) + self.assertEqual( + num2words(713, lang='tet'), + 'atus hitu sanulu resin tolu' + ) + self.assertEqual( + num2words(999, lang='tet'), + 'atus sia sianulu resin sia' + ) + + self.assertEqual(num2words(1000, lang='tet'), 'rihun ida') + self.assertEqual(num2words(1001, lang='tet'), 'rihun ida ida') + self.assertEqual( + num2words(1011, lang='tet'), + 'rihun ida sanulu resin ida' + ) + self.assertEqual( + num2words(1111, lang='tet'), + 'rihun ida atus ida sanulu resin ida' + ) + self.assertEqual( + num2words(2357, lang='tet'), + 'rihun rua atus tolu limanulu resin hitu' + ) + self.assertEqual( + num2words(2200, lang='tet'), + 'rihun rua atus rua' + ) + self.assertEqual( + num2words(2230, lang='tet'), + 'rihun rua atus rua tolunulu' + ) + self.assertEqual( + num2words(73400, lang='tet'), + 'rihun hitunulu resin tolu atus haat' + ) + self.assertEqual( + num2words(73421, lang='tet'), + 'rihun hitunulu resin tolu atus haat ruanulu resin ida' + ) + self.assertEqual(num2words(100000, lang='tet'), 'rihun atus ida') + self.assertEqual( + num2words(250050, lang='tet'), + 'rihun atus rua limanulu limanulu' + ) + self.assertEqual( + num2words(6000000, lang='tet'), 'miliaun neen' + ) + self.assertEqual( + num2words(100000000, lang='tet'), 'miliaun atus ida' + ) + self.assertEqual( + num2words(19000000000, lang='tet'), + 'miliaun rihun sanulu resin sia' + ) + self.assertEqual( + num2words(145000000002, lang='tet'), + 'miliaun rihun atus ida haatnulu resin lima resin rua' + ) + self.assertEqual( + num2words(4635102, lang='tet'), + 'miliaun haat rihun atus neen tolunulu resin lima atus ida rua' + ) + self.assertEqual( + num2words(145254635102, lang='tet'), + "miliaun rihun atus ida haatnulu resin lima atus rua limanulu \ +resin haat rihun atus neen tolunulu resin lima atus ida rua" + ) + self.assertEqual( + num2words(1000000000000, lang='tet'), + 'biliaun ida' + ) + self.assertEqual( + num2words(2000000000000, lang='tet'), + 'biliaun rua' + ) + self.assertEqual( + num2words(1000000000000000, lang='tet'), + 'biliaun rihun ida' + ) + self.assertEqual( + num2words(2000000000000000, lang='tet'), + 'biliaun rihun rua' + ) + self.assertEqual( + num2words(1000000000000000000, lang='tet'), + 'triliaun ida' + ) + self.assertEqual( + num2words(2000000000000000000, lang='tet'), + 'triliaun rua' + ) + + def test_cardinal_integer_negative(self): + self.assertEqual(num2words(-1, lang='tet'), 'menus ida') + self.assertEqual( + num2words(-256, lang='tet'), 'menus atus rua limanulu resin neen' + ) + self.assertEqual(num2words(-1000, lang='tet'), 'menus rihun ida') + self.assertEqual(num2words(-1000000, lang='tet'), 'menus miliaun ida') + self.assertEqual( + num2words(-1234567, lang='tet'), + 'menus miliaun ida rihun atus rua tolunulu resin \ +haat atus lima neenulu resin hitu' + ) + + def test_cardinal_float(self): + self.assertEqual(num2words(Decimal('1.00'), lang='tet'), 'ida') + self.assertEqual(num2words( + Decimal('1.01'), lang='tet'), 'ida vírgula mamuk ida') + self.assertEqual(num2words( + Decimal('1.035'), lang='tet'), 'ida vírgula mamuk tolu lima' + ) + self.assertEqual(num2words( + Decimal('1.35'), lang='tet'), 'ida vírgula tolu lima' + ) + self.assertEqual( + num2words(Decimal('3.14159'), lang='tet'), + 'tolu vírgula ida haat ida lima sia' + ) + self.assertEqual( + num2words(Decimal('101.22'), lang='tet'), + 'atus ida ida vírgula rua rua' + ) + self.assertEqual( + num2words(Decimal('2345.75'), lang='tet'), + 'rihun rua atus tolu haatnulu resin lima vírgula hitu lima' + ) + + def test_cardinal_float_negative(self): + self.assertEqual( + num2words(Decimal('-2.34'), lang='tet'), + 'menus rua vírgula tolu haat' + ) + self.assertEqual( + num2words(Decimal('-9.99'), lang='tet'), + 'menus sia vírgula sia sia' + ) + self.assertEqual( + num2words(Decimal('-7.01'), lang='tet'), + 'menus hitu vírgula mamuk ida' + ) + self.assertEqual( + num2words(Decimal('-222.22'), lang='tet'), + 'menus atus rua ruanulu resin rua vírgula rua rua' + ) + + def test_ordinal(self): + with self.assertRaises(decimal.InvalidOperation): + num2words("hello", lang='tet', ordinal=True) + with self.assertRaises(TypeError): + num2words(5.1, lang='tet', ordinal=True) + self.assertEqual(num2words(1, lang='tet', ordinal=True), 'dahuluk') + self.assertEqual(num2words(2, lang='tet', ordinal=True), 'daruak') + self.assertEqual(num2words(3, lang='tet', ordinal=True), 'datoluk') + self.assertEqual(num2words(4, lang='tet', ordinal=True), 'dahaat') + self.assertEqual(num2words(5, lang='tet', ordinal=True), 'dalimak') + self.assertEqual(num2words(6, lang='tet', ordinal=True), 'daneen') + self.assertEqual(num2words(7, lang='tet', ordinal=True), 'dahituk') + self.assertEqual(num2words(8, lang='tet', ordinal=True), 'daualuk') + self.assertEqual(num2words(9, lang='tet', ordinal=True), 'dasiak') + self.assertEqual(num2words(10, lang='tet', ordinal=True), 'dasanuluk') + self.assertEqual( + num2words(11, lang='tet', ordinal=True), 'dasanulu resin idak' + ) + self.assertEqual( + num2words(12, lang='tet', ordinal=True), 'dasanulu resin ruak' + ) + self.assertEqual( + num2words(13, lang='tet', ordinal=True), 'dasanulu resin toluk' + ) + self.assertEqual( + num2words(14, lang='tet', ordinal=True), 'dasanulu resin haat' + ) + self.assertEqual( + num2words(15, lang='tet', ordinal=True), 'dasanulu resin limak' + ) + self.assertEqual( + num2words(16, lang='tet', ordinal=True), 'dasanulu resin neen' + ) + self.assertEqual( + num2words(17, lang='tet', ordinal=True), 'dasanulu resin hituk' + ) + self.assertEqual( + num2words(18, lang='tet', ordinal=True), 'dasanulu resin ualuk' + ) + self.assertEqual( + num2words(19, lang='tet', ordinal=True), 'dasanulu resin siak' + ) + self.assertEqual( + num2words(20, lang='tet', ordinal=True), 'daruanuluk' + ) + + self.assertEqual( + num2words(21, lang='tet', ordinal=True), 'daruanulu resin idak' + ) + self.assertEqual( + num2words(22, lang='tet', ordinal=True), 'daruanulu resin ruak' + ) + self.assertEqual( + num2words(35, lang='tet', ordinal=True), 'datolunulu resin limak' + ) + self.assertEqual( + num2words(99, lang='tet', ordinal=True), 'dasianulu resin siak' + ) + + self.assertEqual( + num2words(100, lang='tet', ordinal=True), 'dahatus idak' + ) + self.assertEqual( + num2words(101, lang='tet', ordinal=True), 'dahatus ida idak' + ) + self.assertEqual( + num2words(106, lang='tet', ordinal=True), 'dahatus ida neen' + ) + self.assertEqual( + num2words(128, lang='tet', ordinal=True), + 'dahatus ida ruanulu resin ualuk' + ) + self.assertEqual( + num2words(600, lang='tet', ordinal=True), + 'dahatus neen' + ) + self.assertEqual( + num2words(713, lang='tet', ordinal=True), + 'dahatus hitu sanulu resin toluk' + ) + + self.assertEqual( + num2words(1000, lang='tet', ordinal=True), 'darihun idak' + ) + self.assertEqual( + num2words(1001, lang='tet', ordinal=True), 'darihun ida idak' + ) + self.assertEqual( + num2words(1111, lang='tet', ordinal=True), + 'darihun ida atus ida sanulu resin idak' + ) + self.assertEqual( + num2words(2114, lang='tet', ordinal=True), + 'darihun rua atus ida sanulu resin haat' + ) + self.assertEqual( + num2words(73421, lang='tet', ordinal=True), + 'darihun hitunulu resin tolu atus haat ruanulu resin idak' + ) + + self.assertEqual( + num2words(100000, lang='tet', ordinal=True), + 'darihun atus idak' + ) + self.assertEqual( + num2words(250050, lang='tet', ordinal=True), + 'darihun atus rua limanulu limanuluk' + ) + self.assertEqual( + num2words(6000000, lang='tet', ordinal=True), 'damiliaun neen' + ) + self.assertEqual( + num2words(19000000000, lang='tet', ordinal=True), + 'damiliaun rihun sanulu resin siak' + ) + self.assertEqual( + num2words(145000000002, lang='tet', ordinal=True), + 'damiliaun rihun atus ida haatnulu resin lima resin ruak' + ) + + def test_currency_integer(self): + self.assertEqual(self.n2w.to_currency(1.00), 'dolar ida') + self.assertEqual(self.n2w.to_currency(2.00), 'dolar rua') + self.assertEqual(self.n2w.to_currency(3.00), 'dolar tolu') + self.assertEqual(self.n2w.to_currency(4.00), 'dolar haat') + self.assertEqual(self.n2w.to_currency(5.00), 'dolar lima') + self.assertEqual(self.n2w.to_currency(6.00), 'dolar neen') + self.assertEqual(self.n2w.to_currency(7.00), 'dolar hitu') + self.assertEqual(self.n2w.to_currency(8.00), 'dolar ualu') + self.assertEqual(self.n2w.to_currency(9.00), 'dolar sia') + self.assertEqual(self.n2w.to_currency(10.00), 'dolar sanulu') + self.assertEqual(self.n2w.to_currency(11.00), 'dolar sanulu resin ida') + self.assertEqual(self.n2w.to_currency(12.00), 'dolar sanulu resin rua') + self.assertEqual( + self.n2w.to_currency(13.00), + 'dolar sanulu resin tolu' + ) + self.assertEqual( + self.n2w.to_currency(14.00), + 'dolar sanulu resin haat' + ) + self.assertEqual( + self.n2w.to_currency(15.00), + 'dolar sanulu resin lima' + ) + self.assertEqual( + self.n2w.to_currency(16.00), + 'dolar sanulu resin neen' + ) + self.assertEqual( + self.n2w.to_currency(17.00), + 'dolar sanulu resin hitu' + ) + self.assertEqual( + self.n2w.to_currency(18.00), + 'dolar sanulu resin ualu' + ) + self.assertEqual( + self.n2w.to_currency(19.00), + 'dolar sanulu resin sia' + ) + self.assertEqual(self.n2w.to_currency(20.00), 'dolar ruanulu') + + self.assertEqual( + self.n2w.to_currency(21.00), + 'dolar ruanulu resin ida' + ) + self.assertEqual( + self.n2w.to_currency(22.00), + 'dolar ruanulu resin rua' + ) + self.assertEqual( + self.n2w.to_currency(35.00), + 'dolar tolunulu resin lima' + ) + self.assertEqual( + self.n2w.to_currency(99.00), + 'dolar sianulu resin sia' + ) + + self.assertEqual(self.n2w.to_currency(100.00), 'dolar atus ida') + self.assertEqual(self.n2w.to_currency(101.00), 'dolar atus ida ida') + self.assertEqual( + self.n2w.to_currency(128.00), 'dolar atus ida ruanulu resin ualu' + ) + self.assertEqual( + self.n2w.to_currency(713.00), 'dolar atus hitu sanulu resin tolu') + + self.assertEqual(self.n2w.to_currency(1000.00), 'dolar rihun ida') + self.assertEqual(self.n2w.to_currency(1001.00), 'dolar rihun ida ida') + self.assertEqual( + self.n2w.to_currency(1111.00), + 'dolar rihun ida atus ida sanulu resin ida' + ) + self.assertEqual( + self.n2w.to_currency(2114.00), + 'dolar rihun rua atus ida sanulu resin haat' + ) + self.assertEqual( + self.n2w.to_currency(73421.00), + 'dolar rihun hitunulu resin tolu atus haat ruanulu resin ida' + ) + + self.assertEqual( + self.n2w.to_currency(100000.00), + 'dolar rihun atus ida' + ) + self.assertEqual( + self.n2w.to_currency(250050.00), + 'dolar rihun atus rua limanulu limanulu' + ) + self.assertEqual( + self.n2w.to_currency(6000000.00), + 'dolar miliaun neen' + ) + self.assertEqual( + self.n2w.to_currency(19000000000.00), + 'dolar miliaun rihun sanulu resin sia' + ) + self.assertEqual( + self.n2w.to_currency(145000000002.00), + 'dolar miliaun rihun atus ida haatnulu resin lima resin rua' + ) + self.assertEqual(self.n2w.to_currency(1.00, currency='USD'), + 'dolar ida') + self.assertEqual(self.n2w.to_currency(1.50, currency='USD'), + 'dolar ida sentavu limanulu') + with self.assertRaises(NotImplementedError): + self.n2w.to_currency(1.00, currency='CHF') + + def test_currency_integer_negative(self): + self.assertEqual(self.n2w.to_currency(-1.00), 'menus dolar ida') + self.assertEqual( + self.n2w.to_currency(-256.00), + 'menus dolar atus rua limanulu resin neen' + ) + self.assertEqual( + self.n2w.to_currency(-1000.00), + 'menus dolar rihun ida' + ) + self.assertEqual( + self.n2w.to_currency(-1000000.00), 'menus dolar miliaun ida' + ) + self.assertEqual( + self.n2w.to_currency(-1234567.00), + 'menus dolar miliaun ida rihun atus rua tolunulu \ +resin haat atus lima neenulu resin hitu' + ) + + def test_currency_float(self): + self.assertEqual(self.n2w.to_currency(Decimal('1.00')), 'dolar ida') + self.assertEqual( + self.n2w.to_currency(Decimal('1.01')), 'dolar ida sentavu ida' + ) + self.assertEqual( + self.n2w.to_currency(Decimal('1.03')), 'dolar ida sentavu tolu' + ) + self.assertEqual( + self.n2w.to_currency(Decimal('1.35')), + 'dolar ida sentavu tolunulu resin lima' + ) + self.assertEqual( + self.n2w.to_currency(Decimal('3.14')), + 'dolar tolu sentavu sanulu resin haat' + ) + self.assertEqual( + self.n2w.to_currency(Decimal('101.22')), + 'dolar atus ida ida sentavu ruanulu resin rua' + ) + self.assertEqual( + self.n2w.to_currency(Decimal('2345.75')), + 'dolar rihun rua atus tolu haatnulu resin \ +lima sentavu hitunulu resin lima' + ) + + def test_currency_float_negative(self): + self.assertEqual( + self.n2w.to_currency(Decimal('-2.34')), + 'menus dolar rua sentavu tolunulu resin haat' + ) + self.assertEqual( + self.n2w.to_currency(Decimal('-9.99')), + 'menus dolar sia sentavu sianulu resin sia' + ) + self.assertEqual( + self.n2w.to_currency(Decimal('-7.01')), + 'menus dolar hitu sentavu ida' + ) + self.assertEqual( + self.n2w.to_currency(Decimal('-222.22')), + 'menus dolar atus rua ruanulu resin rua sentavu ruanulu resin rua' + ) + + def test_year(self): + self.assertEqual(self.n2w.to_year(1001), 'rihun ida ida') + self.assertEqual( + self.n2w.to_year(1789), 'rihun ida atus hitu ualunulu resin sia' + ) + self.assertEqual( + self.n2w.to_year(1942), 'rihun ida atus sia haatnulu resin rua' + ) + self.assertEqual( + self.n2w.to_year(1984), 'rihun ida atus sia ualunulu resin haat' + ) + self.assertEqual(self.n2w.to_year(2000), 'rihun rua') + self.assertEqual(self.n2w.to_year(2001), 'rihun rua ida') + self.assertEqual(self.n2w.to_year(2016), 'rihun rua sanulu resin neen') + + def test_year_negative(self): + self.assertEqual(self.n2w.to_year(-30), 'tolunulu antes Kristu') + self.assertEqual( + self.n2w.to_year(-744), + 'atus hitu haatnulu resin haat antes Kristu' + ) + self.assertEqual( + self.n2w.to_year(-10000), + 'rihun sanulu antes Kristu' + ) + + def test_to_ordinal_num(self): + self.assertEqual(self.n2w.to_ordinal_num(1), '1º') + self.assertEqual(self.n2w.to_ordinal_num(100), '100º')