diff --git a/README.rst b/README.rst index 86a8002..5b76fcf 100644 --- a/README.rst +++ b/README.rst @@ -96,6 +96,7 @@ Besides the numerical argument, there are two main optional arguments. * ``lv`` (Latvian) * ``no`` (Norwegian) * ``pl`` (Polish) +* ``pt`` (Portuguese) * ``pt_BR`` (Portuguese - Brazilian) * ``ro`` (Romanian) * ``ru`` (Russian) diff --git a/num2words/__init__.py b/num2words/__init__.py index e06c19c..aaf40df 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -36,6 +36,7 @@ from . import lang_ID from . import lang_JA from . import lang_NO from . import lang_DK +from . import lang_PT from . import lang_PT_BR from . import lang_HE from . import lang_IT @@ -72,6 +73,7 @@ CONVERTER_CLASSES = { 'sl': lang_SL.Num2Word_SL(), 'no': lang_NO.Num2Word_NO(), 'dk': lang_DK.Num2Word_DK(), + 'pt': lang_PT.Num2Word_PT(), 'pt_BR': lang_PT_BR.Num2Word_PT_BR(), 'he': lang_HE.Num2Word_HE(), 'it': lang_IT.Num2Word_IT(), diff --git a/num2words/lang_PT.py b/num2words/lang_PT.py new file mode 100644 index 0000000..ef523b5 --- /dev/null +++ b/num2words/lang_PT.py @@ -0,0 +1,247 @@ +# -*- 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 + +from __future__ import division, unicode_literals + +import re + +from .lang_EU import Num2Word_EU + +DOLLAR = ('dólar', 'dólares') +CENTS = ('cêntimo', 'cêntimos') + + +class Num2Word_PT(Num2Word_EU): + + CURRENCY_FORMS = { + 'AUD': (DOLLAR, CENTS), + 'CAD': (DOLLAR, CENTS), + 'EUR': (('euro', 'euros'), CENTS), + 'GBP': (('libra', 'libras'), ('péni', 'pence')), + 'USD': (DOLLAR, CENTS), + } + + GIGA_SUFFIX = None + MEGA_SUFFIX = "ilião" + + def setup(self): + super(Num2Word_PT, self).setup() + lows = ["quatr", "tr", "b", "m"] + self.high_numwords = self.gen_high_numwords([], [], lows) + self.negword = "menos " + self.pointword = "vírgula" + self.exclude_title = ["e", "vírgula", "menos"] + + self.mid_numwords = [ + (1000, "mil"), (100, "cem"), (90, "noventa"), + (80, "oitenta"), (70, "setenta"), (60, "sessenta"), + (50, "cinquenta"), (40, "quarenta"), (30, "trinta") + ] + self.low_numwords = [ + "vinte", "dezanove", "dezoito", "dezassete", "dezasseis", + "quinze", "catorze", "treze", "doze", "onze", "dez", + "nove", "oito", "sete", "seis", "cinco", "quatro", "três", "dois", + "um", "zero" + ] + self.ords = [ + { + 0: "", + 1: "primeiro", + 2: "segundo", + 3: "terceiro", + 4: "quarto", + 5: "quinto", + 6: "sexto", + 7: "sétimo", + 8: "oitavo", + 9: "nono", + }, + { + 0: "", + 1: "décimo", + 2: "vigésimo", + 3: "trigésimo", + 4: "quadragésimo", + 5: "quinquagésimo", + 6: "sexagésimo", + 7: "septuagésimo", + 8: "octogésimo", + 9: "nonagésimo", + }, + { + 0: "", + 1: "centésimo", + 2: "ducentésimo", + 3: "tricentésimo", + 4: "quadrigentésimo", + 5: "quingentésimo", + 6: "seiscentésimo", + 7: "septigentésimo", + 8: "octigentésimo", + 9: "nongentésimo", + }, + ] + self.thousand_separators = { + 3: "milésimo", + 6: "milionésimo", + 9: "milésimo milionésimo", + 12: "bilionésimo", + 15: "milésimo bilionésimo" + } + self.hundreds = { + 1: "cento", + 2: "duzentos", + 3: "trezentos", + 4: "quatrocentos", + 5: "quinhentos", + 6: "seiscentos", + 7: "setecentos", + 8: "oitocentos", + 9: "novecentos", + } + + def merge(self, curr, next): + ctext, cnum, ntext, nnum = curr + next + + if cnum == 1: + if nnum < 1000000: + return next + ctext = "um" + elif cnum == 100 and not nnum % 1000 == 0: + ctext = "cento" + + if nnum < cnum: + if cnum < 100: + return ("%s e %s" % (ctext, ntext), cnum + nnum) + return ("%s e %s" % (ctext, ntext), cnum + nnum) + + elif (not nnum % 1000000000) and cnum > 1: + ntext = ntext[:-4] + "liões" + elif (not nnum % 1000000) and cnum > 1: + ntext = ntext[:-4] + "lhões" + # correct "milião" to "milhão" + if ntext == 'milião': + ntext = 'milhão' + if nnum == 100: + ctext = self.hundreds[cnum] + ntext = "" + + else: + ntext = " " + ntext + + return (ctext + ntext, cnum * nnum) + + def to_cardinal(self, value): + result = super(Num2Word_PT, self).to_cardinal(value) + + # Transforms "mil e cento e catorze" into "mil cento e catorze" + # Transforms "cem milhões e duzentos mil e duzentos e dez" em "cem + # milhões duzentos mil duzentos e dez" but "cem milhões e duzentos + # mil e duzentos" in "cem milhões duzentos mil e duzentos" and not in + # "cem milhões duzentos mil duzentos" + for ext in ( + 'mil', 'milhão', 'milhões', 'mil milhões', + 'bilião', 'biliões', 'mil biliões'): + if re.match('.*{} e \w*entos? (?=.*e)'.format(ext), result): + result = result.replace( + '{} e'.format(ext), '{}'.format(ext) + ) + + return result + + # for the ordinal conversion the code is similar to pt_BR code, + # although there are other rules that are probably more correct in + # Portugal. Concerning numbers from 2000th on, saying "dois + # milésimos" instead of "segundo milésimo" (the first number + # would be used in the cardinal form instead of the ordinal) is better. + # This was not implemented. + # source: + # https://ciberduvidas.iscte-iul.pt/consultorio/perguntas/a-forma-por-extenso-de-2000-e-de-outros-ordinais/16428 + def to_ordinal(self, value): + # Before changing this function remember this is used by pt-BR + # so act accordingly + self.verify_ordinal(value) + + result = [] + value = str(value) + thousand_separator = '' + + for idx, char in enumerate(value[::-1]): + if idx and idx % 3 == 0: + thousand_separator = self.thousand_separators[idx] + + if char != '0' and thousand_separator: + # avoiding "segundo milionésimo milésimo" for 6000000, + # for instance + result.append(thousand_separator) + thousand_separator = '' + + result.append(self.ords[idx % 3][int(char)]) + + result = ' '.join(result[::-1]) + result = result.strip() + result = re.sub('\s+', ' ', result) + + if result.startswith('primeiro') and value != '1': + # avoiding "primeiro milésimo", "primeiro milionésimo" and so on + result = result[9:] + + return result + + def to_ordinal_num(self, value): + # Before changing this function remember this is used by pt-BR + # so act accordingly + self.verify_ordinal(value) + return "%sº" % (value) + + def to_year(self, val, longval=True): + # Before changing this function remember this is used by pt-BR + # so act accordingly + if val < 0: + return self.to_cardinal(abs(val)) + ' antes de Cristo' + return self.to_cardinal(val) + + def to_currency(self, val, currency='EUR', cents=True, seperator=' e', + adjective=False): + # change negword because base.to_currency() does not need space after + backup_negword = self.negword + self.negword = self.negword[:-1] + result = super(Num2Word_PT, self).to_currency( + val, currency=currency, cents=cents, seperator=seperator, + adjective=adjective) + # undo the change on negword + self.negword = backup_negword + + # transforms "milhões euros" em "milhões de euros" + try: + cr1, _ = self.CURRENCY_FORMS[currency] + except KeyError: + raise NotImplementedError( + 'Currency code "%s" not implemented for "%s"' % + (currency, self.__class__.__name__)) + + for ext in ( + 'milhão', 'milhões', 'bilião', + 'biliões', 'trilião', 'triliões'): + if re.match('.*{} (?={})'.format(ext, cr1[1]), result): + result = result.replace( + '{}'.format(ext), '{} de'.format(ext), 1 + ) + # do not print "e zero cêntimos" + result = result.replace(' e zero cêntimos', '') + return result diff --git a/num2words/lang_PT_BR.py b/num2words/lang_PT_BR.py index 8899a65..7515e28 100644 --- a/num2words/lang_PT_BR.py +++ b/num2words/lang_PT_BR.py @@ -20,10 +20,10 @@ from __future__ import division, unicode_literals import re -from . import lang_EU +from . import lang_PT -class Num2Word_PT_BR(lang_EU.Num2Word_EU): +class Num2Word_PT_BR(lang_PT.Num2Word_PT): def set_high_numwords(self, high): max = 3 + 3*len(high) for word, n in zip(high, range(max, 3, -3)): @@ -32,59 +32,10 @@ class Num2Word_PT_BR(lang_EU.Num2Word_EU): def setup(self): super(Num2Word_PT_BR, self).setup() - self.negword = "menos " - self.pointword = "vírgula" - self.exclude_title = ["e", "vírgula", "menos"] + self.low_numwords[1] = 'dezenove' + self.low_numwords[3] = 'dezessete' + self.low_numwords[4] = 'dezesseis' - self.mid_numwords = [ - (1000, "mil"), (100, "cem"), (90, "noventa"), - (80, "oitenta"), (70, "setenta"), (60, "sessenta"), - (50, "cinquenta"), (40, "quarenta"), (30, "trinta") - ] - self.low_numwords = [ - "vinte", "dezenove", "dezoito", "dezessete", "dezesseis", - "quinze", "catorze", "treze", "doze", "onze", "dez", - "nove", "oito", "sete", "seis", "cinco", "quatro", "três", "dois", - "um", "zero" - ] - self.ords = [ - { - 0: "", - 1: "primeiro", - 2: "segundo", - 3: "terceiro", - 4: "quarto", - 5: "quinto", - 6: "sexto", - 7: "sétimo", - 8: "oitavo", - 9: "nono", - }, - { - 0: "", - 1: "décimo", - 2: "vigésimo", - 3: "trigésimo", - 4: "quadragésimo", - 5: "quinquagésimo", - 6: "sexagésimo", - 7: "septuagésimo", - 8: "octogésimo", - 9: "nonagésimo", - }, - { - 0: "", - 1: "centésimo", - 2: "ducentésimo", - 3: "tricentésimo", - 4: "quadrigentésimo", - 5: "quingentésimo", - 6: "seiscentésimo", - 7: "septigentésimo", - 8: "octigentésimo", - 9: "nongentésimo", - }, - ] self.thousand_separators = { 3: "milésimo", 6: "milionésimo", @@ -92,17 +43,6 @@ class Num2Word_PT_BR(lang_EU.Num2Word_EU): 12: "trilionésimo", 15: "quadrilionésimo" } - self.hundreds = { - 1: "cento", - 2: "duzentos", - 3: "trezentos", - 4: "quatrocentos", - 5: "quinhentos", - 6: "seiscentos", - 7: "setecentos", - 8: "oitocentos", - 9: "novecentos", - } def merge(self, curr, next): ctext, cnum, ntext, nnum = curr + next @@ -132,7 +72,7 @@ class Num2Word_PT_BR(lang_EU.Num2Word_EU): return (ctext + ntext, cnum * nnum) def to_cardinal(self, value): - result = super(Num2Word_PT_BR, self).to_cardinal(value) + result = lang_PT.Num2Word_EU.to_cardinal(self, value) # Transforms "mil E cento e catorze reais" into "mil, cento e catorze # reais" @@ -146,44 +86,6 @@ class Num2Word_PT_BR(lang_EU.Num2Word_EU): return result - def to_ordinal(self, value): - self.verify_ordinal(value) - - result = [] - value = str(value) - thousand_separator = '' - - for idx, char in enumerate(value[::-1]): - if idx and idx % 3 == 0: - thousand_separator = self.thousand_separators[idx] - - if char != '0' and thousand_separator: - # avoiding "segundo milionésimo milésimo" for 6000000, - # for instance - result.append(thousand_separator) - thousand_separator = '' - - result.append(self.ords[idx % 3][int(char)]) - - result = ' '.join(result[::-1]) - result = result.strip() - result = re.sub('\s+', ' ', result) - - if result.startswith('primeiro') and value != '1': - # avoiding "primeiro milésimo", "primeiro milionésimo" and so on - result = result[9:] - - 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 de Cristo' - return self.to_cardinal(val) - def to_currency(self, val, longval=True): integer_part, decimal_part = ('%.2f' % val).split('.') diff --git a/tests/test_pt.py b/tests/test_pt.py new file mode 100644 index 0000000..b23f40a --- /dev/null +++ b/tests/test_pt.py @@ -0,0 +1,454 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2015, 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 __future__ import unicode_literals + +from decimal import Decimal +from unittest import TestCase + +from num2words import num2words +from num2words.lang_PT import Num2Word_PT + + +class Num2WordsPTTest(TestCase): + def setUp(self): + super(Num2WordsPTTest, self).setUp() + self.n2w = Num2Word_PT() + + def test_cardinal_integer(self): + self.assertEqual(num2words(1, lang='pt'), 'um') + self.assertEqual(num2words(2, lang='pt'), 'dois') + self.assertEqual(num2words(3, lang='pt'), 'três') + self.assertEqual(num2words(4, lang='pt'), 'quatro') + self.assertEqual(num2words(5, lang='pt'), 'cinco') + self.assertEqual(num2words(6, lang='pt'), 'seis') + self.assertEqual(num2words(7, lang='pt'), 'sete') + self.assertEqual(num2words(8, lang='pt'), 'oito') + self.assertEqual(num2words(9, lang='pt'), 'nove') + self.assertEqual(num2words(10, lang='pt'), 'dez') + self.assertEqual(num2words(11, lang='pt'), 'onze') + self.assertEqual(num2words(12, lang='pt'), 'doze') + self.assertEqual(num2words(13, lang='pt'), 'treze') + self.assertEqual(num2words(14, lang='pt'), 'catorze') + self.assertEqual(num2words(15, lang='pt'), 'quinze') + self.assertEqual(num2words(16, lang='pt'), 'dezasseis') + self.assertEqual(num2words(17, lang='pt'), 'dezassete') + self.assertEqual(num2words(18, lang='pt'), 'dezoito') + self.assertEqual(num2words(19, lang='pt'), 'dezanove') + self.assertEqual(num2words(20, lang='pt'), 'vinte') + + self.assertEqual(num2words(21, lang='pt'), 'vinte e um') + self.assertEqual(num2words(22, lang='pt'), 'vinte e dois') + self.assertEqual(num2words(35, lang='pt'), 'trinta e cinco') + self.assertEqual(num2words(99, lang='pt'), 'noventa e nove') + + self.assertEqual(num2words(100, lang='pt'), 'cem') + self.assertEqual(num2words(101, lang='pt'), 'cento e um') + self.assertEqual(num2words(128, lang='pt'), 'cento e vinte e oito') + self.assertEqual(num2words(713, lang='pt'), 'setecentos e treze') + + self.assertEqual(num2words(1000, lang='pt'), 'mil') + self.assertEqual(num2words(1001, lang='pt'), 'mil e um') + self.assertEqual(num2words(1111, lang='pt'), 'mil cento e onze') + self.assertEqual( + num2words(2114, lang='pt'), 'dois mil cento e catorze' + ) + self.assertEqual( + num2words(2200, lang='pt'), + 'dois mil e duzentos' + ) + self.assertEqual( + num2words(2230, lang='pt'), + 'dois mil duzentos e trinta' + ) + self.assertEqual( + num2words(73400, lang='pt'), + 'setenta e três mil e quatrocentos' + ) + self.assertEqual( + num2words(73421, lang='pt'), + 'setenta e três mil quatrocentos e vinte e um' + ) + self.assertEqual(num2words(100000, lang='pt'), 'cem mil') + self.assertEqual( + num2words(250050, lang='pt'), + 'duzentos e cinquenta mil e cinquenta' + ) + self.assertEqual( + num2words(6000000, lang='pt'), 'seis milhões' + ) + self.assertEqual( + num2words(100000000, lang='pt'), 'cem milhões' + ) + self.assertEqual( + num2words(19000000000, lang='pt'), 'dezanove mil milhões' + ) + self.assertEqual( + num2words(145000000002, lang='pt'), + 'cento e quarenta e cinco mil milhões e dois' + ) + self.assertEqual( + num2words(4635102, lang='pt'), + 'quatro milhões seiscentos e trinta e cinco mil cento e dois' + ) + self.assertEqual( + num2words(145254635102, lang='pt'), + 'cento e quarenta e cinco mil duzentos e cinquenta e quatro ' + 'milhões seiscentos e trinta e cinco mil cento e dois' + ) + self.assertEqual( + num2words(1000000000000, lang='pt'), + 'um bilião' + ) + self.assertEqual( + num2words(2000000000000, lang='pt'), + 'dois biliões' + ) + self.assertEqual( + num2words(1000000000000000, lang='pt'), + 'mil biliões' + ) + self.assertEqual( + num2words(2000000000000000, lang='pt'), + 'dois mil biliões' + ) + self.assertEqual( + num2words(1000000000000000000, lang='pt'), + 'um trilião' + ) + self.assertEqual( + num2words(2000000000000000000, lang='pt'), + 'dois triliões' + ) + + def test_cardinal_integer_negative(self): + self.assertEqual(num2words(-1, lang='pt'), 'menos um') + self.assertEqual( + num2words(-256, lang='pt'), 'menos duzentos e cinquenta e seis' + ) + self.assertEqual(num2words(-1000, lang='pt'), 'menos mil') + self.assertEqual(num2words(-1000000, lang='pt'), 'menos um milhão') + self.assertEqual( + num2words(-1234567, lang='pt'), + 'menos um milhão duzentos e trinta e quatro mil quinhentos e ' + 'sessenta e sete' + ) + + def test_cardinal_float(self): + self.assertEqual(num2words(Decimal('1.00'), lang='pt'), 'um') + self.assertEqual(num2words( + Decimal('1.01'), lang='pt'), 'um vírgula zero um') + self.assertEqual(num2words( + Decimal('1.035'), lang='pt'), 'um vírgula zero três cinco' + ) + self.assertEqual(num2words( + Decimal('1.35'), lang='pt'), 'um vírgula três cinco' + ) + self.assertEqual( + num2words(Decimal('3.14159'), lang='pt'), + 'três vírgula um quatro um cinco nove' + ) + self.assertEqual( + num2words(Decimal('101.22'), lang='pt'), + 'cento e um vírgula dois dois' + ) + self.assertEqual( + num2words(Decimal('2345.75'), lang='pt'), + 'dois mil trezentos e quarenta e cinco vírgula sete cinco') + + def test_cardinal_float_negative(self): + self.assertEqual( + num2words(Decimal('-2.34'), lang='pt'), + 'menos dois vírgula três quatro' + ) + self.assertEqual( + num2words(Decimal('-9.99'), lang='pt'), + 'menos nove vírgula nove nove' + ) + self.assertEqual( + num2words(Decimal('-7.01'), lang='pt'), + 'menos sete vírgula zero um' + ) + self.assertEqual( + num2words(Decimal('-222.22'), lang='pt'), + 'menos duzentos e vinte e dois vírgula dois dois' + ) + + def test_ordinal(self): + self.assertEqual(num2words(1, lang='pt', ordinal=True), 'primeiro') + self.assertEqual(num2words(2, lang='pt', ordinal=True), 'segundo') + self.assertEqual(num2words(3, lang='pt', ordinal=True), 'terceiro') + self.assertEqual(num2words(4, lang='pt', ordinal=True), 'quarto') + self.assertEqual(num2words(5, lang='pt', ordinal=True), 'quinto') + self.assertEqual(num2words(6, lang='pt', ordinal=True), 'sexto') + self.assertEqual(num2words(7, lang='pt', ordinal=True), 'sétimo') + self.assertEqual(num2words(8, lang='pt', ordinal=True), 'oitavo') + self.assertEqual(num2words(9, lang='pt', ordinal=True), 'nono') + self.assertEqual(num2words(10, lang='pt', ordinal=True), 'décimo') + self.assertEqual( + num2words(11, lang='pt', ordinal=True), 'décimo primeiro' + ) + self.assertEqual( + num2words(12, lang='pt', ordinal=True), 'décimo segundo' + ) + self.assertEqual( + num2words(13, lang='pt', ordinal=True), 'décimo terceiro' + ) + self.assertEqual( + num2words(14, lang='pt', ordinal=True), 'décimo quarto' + ) + self.assertEqual( + num2words(15, lang='pt', ordinal=True), 'décimo quinto' + ) + self.assertEqual( + num2words(16, lang='pt', ordinal=True), 'décimo sexto' + ) + self.assertEqual( + num2words(17, lang='pt', ordinal=True), 'décimo sétimo' + ) + self.assertEqual( + num2words(18, lang='pt', ordinal=True), 'décimo oitavo' + ) + self.assertEqual( + num2words(19, lang='pt', ordinal=True), 'décimo nono' + ) + self.assertEqual( + num2words(20, lang='pt', ordinal=True), 'vigésimo' + ) + + self.assertEqual( + num2words(21, lang='pt', ordinal=True), 'vigésimo primeiro' + ) + self.assertEqual( + num2words(22, lang='pt', ordinal=True), 'vigésimo segundo' + ) + self.assertEqual( + num2words(35, lang='pt', ordinal=True), 'trigésimo quinto' + ) + self.assertEqual( + num2words(99, lang='pt', ordinal=True), 'nonagésimo nono' + ) + + self.assertEqual( + num2words(100, lang='pt', ordinal=True), 'centésimo' + ) + self.assertEqual( + num2words(101, lang='pt', ordinal=True), 'centésimo primeiro' + ) + self.assertEqual( + num2words(128, lang='pt', ordinal=True), + 'centésimo vigésimo oitavo' + ) + self.assertEqual( + num2words(713, lang='pt', ordinal=True), + 'septigentésimo décimo terceiro' + ) + + self.assertEqual( + num2words(1000, lang='pt', ordinal=True), 'milésimo' + ) + self.assertEqual( + num2words(1001, lang='pt', ordinal=True), 'milésimo primeiro' + ) + self.assertEqual( + num2words(1111, lang='pt', ordinal=True), + 'milésimo centésimo décimo primeiro' + ) + self.assertEqual( + num2words(2114, lang='pt', ordinal=True), + 'segundo milésimo centésimo décimo quarto' + ) + self.assertEqual( + num2words(73421, lang='pt', ordinal=True), + 'septuagésimo terceiro milésimo quadrigentésimo vigésimo primeiro' + ) + + self.assertEqual( + num2words(100000, lang='pt', ordinal=True), + 'centésimo milésimo' + ) + self.assertEqual( + num2words(250050, lang='pt', ordinal=True), + 'ducentésimo quinquagésimo milésimo quinquagésimo' + ) + self.assertEqual( + num2words(6000000, lang='pt', ordinal=True), 'sexto milionésimo' + ) + self.assertEqual( + num2words(19000000000, lang='pt', ordinal=True), + 'décimo nono milésimo milionésimo' + ) + self.assertEqual( + num2words(145000000002, lang='pt', ordinal=True), + 'centésimo quadragésimo quinto milésimo milionésimo segundo' + ) + + def test_currency_integer(self): + self.assertEqual(self.n2w.to_currency(1.00), 'um euro') + self.assertEqual(self.n2w.to_currency(2.00), 'dois euros') + self.assertEqual(self.n2w.to_currency(3.00), 'três euros') + self.assertEqual(self.n2w.to_currency(4.00), 'quatro euros') + self.assertEqual(self.n2w.to_currency(5.00), 'cinco euros') + self.assertEqual(self.n2w.to_currency(6.00), 'seis euros') + self.assertEqual(self.n2w.to_currency(7.00), 'sete euros') + self.assertEqual(self.n2w.to_currency(8.00), 'oito euros') + self.assertEqual(self.n2w.to_currency(9.00), 'nove euros') + self.assertEqual(self.n2w.to_currency(10.00), 'dez euros') + self.assertEqual(self.n2w.to_currency(11.00), 'onze euros') + self.assertEqual(self.n2w.to_currency(12.00), 'doze euros') + self.assertEqual(self.n2w.to_currency(13.00), 'treze euros') + self.assertEqual(self.n2w.to_currency(14.00), 'catorze euros') + self.assertEqual(self.n2w.to_currency(15.00), 'quinze euros') + self.assertEqual(self.n2w.to_currency(16.00), 'dezasseis euros') + self.assertEqual(self.n2w.to_currency(17.00), 'dezassete euros') + self.assertEqual(self.n2w.to_currency(18.00), 'dezoito euros') + self.assertEqual(self.n2w.to_currency(19.00), 'dezanove euros') + self.assertEqual(self.n2w.to_currency(20.00), 'vinte euros') + + self.assertEqual(self.n2w.to_currency(21.00), 'vinte e um euros') + self.assertEqual(self.n2w.to_currency(22.00), 'vinte e dois euros') + self.assertEqual(self.n2w.to_currency(35.00), 'trinta e cinco euros') + self.assertEqual(self.n2w.to_currency(99.00), 'noventa e nove euros') + + self.assertEqual(self.n2w.to_currency(100.00), 'cem euros') + self.assertEqual(self.n2w.to_currency(101.00), 'cento e um euros') + self.assertEqual( + self.n2w.to_currency(128.00), 'cento e vinte e oito euros' + ) + self.assertEqual( + self.n2w.to_currency(713.00), 'setecentos e treze euros') + + self.assertEqual(self.n2w.to_currency(1000.00), 'mil euros') + self.assertEqual(self.n2w.to_currency(1001.00), 'mil e um euros') + self.assertEqual( + self.n2w.to_currency(1111.00), 'mil cento e onze euros') + self.assertEqual( + self.n2w.to_currency(2114.00), 'dois mil cento e catorze euros' + ) + self.assertEqual( + self.n2w.to_currency(73421.00), + 'setenta e três mil quatrocentos e vinte e um euros' + ) + + self.assertEqual(self.n2w.to_currency(100000.00), 'cem mil euros') + self.assertEqual( + self.n2w.to_currency(250050.00), + 'duzentos e cinquenta mil e cinquenta euros' + ) + self.assertEqual( + self.n2w.to_currency(6000000.00), 'seis milhões de euros' + ) + self.assertEqual( + self.n2w.to_currency(19000000000.00), + 'dezanove mil milhões de euros' + ) + self.assertEqual( + self.n2w.to_currency(145000000002.00), + 'cento e quarenta e cinco mil milhões e dois euros' + ) + self.assertEqual(self.n2w.to_currency(1.00, currency='USD'), + 'um dólar') + self.assertEqual(self.n2w.to_currency(1.50, currency='USD'), + 'um dólar e cinquenta cêntimos') + 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), 'menos um euro') + self.assertEqual( + self.n2w.to_currency(-256.00), + 'menos duzentos e cinquenta e seis euros' + ) + self.assertEqual(self.n2w.to_currency(-1000.00), 'menos mil euros') + self.assertEqual( + self.n2w.to_currency(-1000000.00), 'menos um milhão de euros' + ) + self.assertEqual( + self.n2w.to_currency(-1234567.00), + 'menos um milhão duzentos e trinta e quatro mil quinhentos e ' + 'sessenta e sete euros' + ) + + def test_currency_float(self): + self.assertEqual(self.n2w.to_currency(Decimal('1.00')), 'um euro') + self.assertEqual( + self.n2w.to_currency(Decimal('1.01')), 'um euro e um cêntimo' + ) + self.assertEqual( + self.n2w.to_currency(Decimal('1.03')), 'um euro e três cêntimos' + ) + self.assertEqual( + self.n2w.to_currency(Decimal('1.35')), + 'um euro e trinta e cinco cêntimos' + ) + self.assertEqual( + self.n2w.to_currency(Decimal('3.14')), + 'três euros e catorze cêntimos' + ) + self.assertEqual( + self.n2w.to_currency(Decimal('101.22')), + 'cento e um euros e vinte e dois cêntimos' + ) + self.assertEqual( + self.n2w.to_currency(Decimal('2345.75')), + 'dois mil trezentos e quarenta e cinco euros e setenta e cinco ' + 'cêntimos' + ) + + def test_currency_float_negative(self): + self.assertEqual( + self.n2w.to_currency(Decimal('-2.34')), + 'menos dois euros e trinta e quatro cêntimos' + ) + self.assertEqual( + self.n2w.to_currency(Decimal('-9.99')), + 'menos nove euros e noventa e nove cêntimos' + ) + self.assertEqual( + self.n2w.to_currency(Decimal('-7.01')), + 'menos sete euros e um cêntimo' + ) + self.assertEqual( + self.n2w.to_currency(Decimal('-222.22')), + 'menos duzentos e vinte e dois euros e vinte e dois cêntimos' + ) + + def test_year(self): + self.assertEqual(self.n2w.to_year(1001), 'mil e um') + self.assertEqual( + self.n2w.to_year(1789), 'mil setecentos e oitenta e nove' + ) + self.assertEqual( + self.n2w.to_year(1942), 'mil novecentos e quarenta e dois' + ) + self.assertEqual( + self.n2w.to_year(1984), 'mil novecentos e oitenta e quatro' + ) + self.assertEqual(self.n2w.to_year(2000), 'dois mil') + self.assertEqual(self.n2w.to_year(2001), 'dois mil e um') + self.assertEqual(self.n2w.to_year(2016), 'dois mil e dezasseis') + + def test_year_negative(self): + self.assertEqual(self.n2w.to_year(-30), 'trinta antes de Cristo') + self.assertEqual( + self.n2w.to_year(-744), + 'setecentos e quarenta e quatro antes de Cristo' + ) + self.assertEqual(self.n2w.to_year(-10000), 'dez mil antes de Cristo') + + def test_to_ordinal_num(self): + self.assertEqual(self.n2w.to_ordinal_num(1), '1º') + self.assertEqual(self.n2w.to_ordinal_num(100), '100º')