From 1ed09f511da4bfcfce9e8414b0e2f2b7417dd1c2 Mon Sep 17 00:00:00 2001 From: fatkaratekid <2835130+fatkaratekid@users.noreply.github.com> Date: Sun, 11 Nov 2018 00:36:51 +0100 Subject: [PATCH 01/23] Add support for Serbian (Latin) (#207) * Add support for Serbian language * Fix the billion strings for short scale Used the long scale name instead of the short one. Simplified the scale and the ones geneder definition. * Adds Serbian to README --- README.rst | 2 + num2words/__init__.py | 2 + num2words/lang_SR.py | 215 +++++++++++++++++++++++++++++++++++++ tests/test_sr.py | 241 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 460 insertions(+) create mode 100644 num2words/lang_SR.py create mode 100644 tests/test_sr.py diff --git a/README.rst b/README.rst index f50823f..0cdaf08 100644 --- a/README.rst +++ b/README.rst @@ -103,6 +103,8 @@ Besides the numerical argument, there are two main optional arguments. * ``pl`` (Polish) * ``pt`` (Portuguese) * ``pt_BR`` (Portuguese - Brazilian) +* ``sl`` (Slovene) +* ``sr`` (Serbian) * ``ro`` (Romanian) * ``ru`` (Russian) * ``sl`` (Slovene) diff --git a/num2words/__init__.py b/num2words/__init__.py index aaf40df..8188d46 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -47,6 +47,7 @@ from . import lang_TR from . import lang_NL from . import lang_UK from . import lang_SL +from . import lang_SR from . import lang_TH CONVERTER_CLASSES = { @@ -71,6 +72,7 @@ CONVERTER_CLASSES = { 'ro': lang_RO.Num2Word_RO(), 'ru': lang_RU.Num2Word_RU(), 'sl': lang_SL.Num2Word_SL(), + 'sr': lang_SR.Num2Word_SR(), 'no': lang_NO.Num2Word_NO(), 'dk': lang_DK.Num2Word_DK(), 'pt': lang_PT.Num2Word_PT(), diff --git a/num2words/lang_SR.py b/num2words/lang_SR.py new file mode 100644 index 0000000..29265ae --- /dev/null +++ b/num2words/lang_SR.py @@ -0,0 +1,215 @@ +# -*- encoding: 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 unicode_literals + +from .base import Num2Word_Base +from .currency import parse_currency_parts, prefix_currency +from .utils import get_digits, splitbyx + +ZERO = ('nula',) + +ONES = { + 1: ('jedan', 'jedna'), + 2: ('dva', 'dve'), + 3: ('tri', 'tri'), + 4: ('četiri', 'četiri'), + 5: ('pet', 'pet'), + 6: ('šest', 'šest'), + 7: ('sedam', 'sedam'), + 8: ('osam', 'osam'), + 9: ('devet', 'devet'), +} + +TENS = { + 0: ('deset',), + 1: ('jedanaest',), + 2: ('dvanaest',), + 3: ('trinaest',), + 4: ('četrnaest',), + 5: ('petnaest',), + 6: ('šesnaest',), + 7: ('sedamnaest',), + 8: ('osamnaest',), + 9: ('devetnaest',), +} + +TWENTIES = { + 2: ('dvadeset',), + 3: ('trideset',), + 4: ('četrdeset',), + 5: ('pedeset',), + 6: ('šezdeset',), + 7: ('sedamdeset',), + 8: ('osamdeset',), + 9: ('devedeset',), +} + +HUNDREDS = { + 1: ('sto',), + 2: ('dvesta',), + 3: ('trista',), + 4: ('četristo',), + 5: ('petsto',), + 6: ('šesto',), + 7: ('sedamsto',), + 8: ('osamsto',), + 9: ('devetsto',), +} + +SCALE = { + 0: ('', '', '', False), + 1: ('hiljada', 'hiljade', 'hiljada', True), # 10^3 + 2: ('milion', 'miliona', 'miliona', False), # 10^6 + 3: ('bilion', 'biliona', 'biliona', False), # 10^9 + 4: ('trilion', 'triliona', 'triliona', False), # 10^12 + 5: ('kvadrilion', 'kvadriliona', 'kvadriliona', False), # 10^15 + 6: ('kvintilion', 'kvintiliona', 'kvintiliona', False), # 10^18 + 7: ('sekstilion', 'sekstiliona', 'sekstiliona', False), # 10^21 + 8: ('septilion', 'septiliona', 'septiliona', False), # 10^24 + 9: ('oktilion', 'oktiliona', 'oktiliona', False), # 10^27 + 10: ('nonilion', 'noniliona', 'noniliona', False), # 10^30 +} + + +class Num2Word_SR(Num2Word_Base): + CURRENCY_FORMS = { + 'RUB': ( + ('rublja', 'rublje', 'rublji', True), + ('kopejka', 'kopejke', 'kopejki', True) + ), + 'EUR': ( + ('evro', 'evra', 'evra', False), + ('cent', 'centa', 'centi', False) + ), + 'RSD': ( + ('dinar', 'dinara', 'dinara', False), + ('para', 'pare', 'para', True) + ), + } + + def setup(self): + self.negword = "minus" + self.pointword = "zapeta" + + def to_cardinal(self, number, feminine=False): + n = str(number).replace(',', '.') + if '.' in n: + left, right = n.split('.') + return u'%s %s %s' % ( + self._int2word(int(left), feminine), + self.pointword, + self._int2word(int(right), feminine) + ) + else: + return self._int2word(int(n), feminine) + + def pluralize(self, number, forms): + if number % 100 < 10 or number % 100 > 20: + if number % 10 == 1: + form = 0 + elif 1 < number % 10 < 5: + form = 1 + else: + form = 2 + else: + form = 2 + return forms[form] + + def to_ordinal(self, number): + raise NotImplementedError() + + def _cents_verbose(self, number, currency): + return self._int2word( + number, + self.CURRENCY_FORMS[currency][1][-1] + ) + + def _int2word(self, number, feminine=False): + if number < 0: + return ' '.join([self.negword, self._int2word(abs(number))]) + + if number == 0: + return ZERO[0] + + words = [] + chunks = list(splitbyx(str(number), 3)) + chunk_len = len(chunks) + for chunk in chunks: + chunk_len -= 1 + digit_right, digit_mid, digit_left = get_digits(chunk) + + if digit_left > 0: + words.append(HUNDREDS[digit_left][0]) + + if digit_mid > 1: + words.append(TWENTIES[digit_mid][0]) + + if digit_mid == 1: + words.append(TENS[digit_right][0]) + elif digit_right > 0: + is_feminine = feminine or SCALE[chunk_len][-1] + gender_idx = int(is_feminine) + words.append( + ONES[digit_right][gender_idx] + ) + + if chunk_len > 0 and chunk != 0: + words.append(self.pluralize(chunk, SCALE[chunk_len])) + + return ' '.join(words) + + def to_currency(self, val, currency='EUR', cents=True, seperator=',', + adjective=False): + """ + Args: + val: Numeric value + currency (str): Currency code + cents (bool): Verbose cents + seperator (str): Cent seperator + 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 if is_negative else "" + cents_str = self._cents_verbose(right, currency) \ + if cents else self._cents_terse(right, currency) + + return u'%s%s %s%s %s %s' % ( + minus_str, + self.to_cardinal(left, feminine=cr1[-1]), + self.pluralize(left, cr1), + seperator, + cents_str, + self.pluralize(right, cr2) + ) diff --git a/tests/test_sr.py b/tests/test_sr.py new file mode 100644 index 0000000..aa8899b --- /dev/null +++ b/tests/test_sr.py @@ -0,0 +1,241 @@ +# -*- encoding: utf-8 -*- +# 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 unicode_literals + +from unittest import TestCase + +from num2words import num2words + + +class Num2WordsSRTest(TestCase): + + def test_cardinal(self): + self.assertEqual("sto", num2words(100, lang='sr')) + self.assertEqual("sto jedan", num2words(101, lang='sr')) + self.assertEqual("sto deset", num2words(110, lang='sr')) + self.assertEqual("sto petnaest", num2words(115, lang='sr')) + self.assertEqual( + "sto dvadeset tri", num2words(123, lang='sr') + ) + self.assertEqual( + "jedna hiljada", num2words(1000, lang='sr') + ) + self.assertEqual( + "jedna hiljada jedan", num2words(1001, lang='sr') + ) + self.assertEqual( + "dve hiljade dvanaest", num2words(2012, lang='sr') + ) + self.assertEqual( + "dvanaest hiljada petsto devetnaest zapeta osamdeset pet", + num2words(12519.85, lang='sr') + ) + self.assertEqual( + "jedan bilion dvesta trideset četiri miliona petsto " + "šezdeset sedam hiljada osamsto devedeset", + num2words(1234567890, lang='sr') + ) + self.assertEqual( + "dvesta petnaest noniliona četristo šezdeset jedan " + "oktilion četristo sedam septiliona osamsto devedeset " + "dva sekstiliona trideset devet kvintiliona dva kvadriliona " + "sto pedeset sedam triliona sto osamdeset devet biliona " + "osamsto osamdeset tri miliona devetsto jedna hiljada " + "šesto sedamdeset šest", + num2words(215461407892039002157189883901676, lang='sr') + ) + self.assertEqual( + "sedamsto devetnaest noniliona devedeset četiri oktiliona " + "dvesta trideset četiri septiliona šesto devedeset tri " + "sekstiliona šesto šezdeset tri kvintiliona trideset " + "četiri kvadriliona osamsto dvadeset dva triliona osamsto " + "dvadeset četiri biliona trista osamdeset četiri miliona " + "dvesta dvadeset hiljada dvesta devedeset jedan", + num2words(719094234693663034822824384220291, lang='sr') + ) + self.assertEqual("pet", num2words(5, lang='sr')) + self.assertEqual("petnaest", num2words(15, lang='sr')) + self.assertEqual("sto pedeset četiri", num2words(154, lang='sr')) + self.assertEqual( + "jedna hiljada sto trideset pet", + num2words(1135, lang='sr') + ) + self.assertEqual( + "četristo osamnaest hiljada petsto trideset jedan", + num2words(418531, lang='sr'), + ) + self.assertEqual( + "jedan milion sto trideset devet", + num2words(1000139, lang='sr') + ) + + def test_floating_point(self): + self.assertEqual("pet zapeta dva", num2words(5.2, lang='sr')) + self.assertEqual( + "petsto šezdeset jedan zapeta četrdeset dva", + num2words(561.42, lang='sr') + ) + + def test_to_ordinal(self): + # @TODO: implement to_ordinal + with self.assertRaises(NotImplementedError): + num2words(1, lang='sr', to='ordinal') + + def test_to_currency(self): + self.assertEqual( + 'jedan evro, nula centi', + num2words(1.0, lang='sr', to='currency', currency='EUR') + + ) + self.assertEqual( + 'dva evra, nula centi', + num2words(2.0, lang='sr', to='currency', currency='EUR') + + ) + self.assertEqual( + 'pet evra, nula centi', + num2words(5.0, lang='sr', to='currency', currency='EUR') + + ) + self.assertEqual( + 'dva evra, jedan cent', + num2words(2.01, lang='sr', to='currency', currency='EUR') + + ) + + self.assertEqual( + 'dva evra, dva centa', + num2words(2.02, lang='sr', to='currency', currency='EUR') + + ) + self.assertEqual( + 'dva evra, pet centi', + num2words(2.05, lang='sr', to='currency', currency='EUR') + + ) + self.assertEqual( + 'dve rublje, nula kopejki', + num2words(2.0, lang='sr', to='currency', currency='RUB') + + ) + self.assertEqual( + 'dve rublje, jedna kopejka', + num2words(2.01, lang='sr', to='currency', currency='RUB') + + ) + self.assertEqual( + 'dve rublje, dve kopejke', + num2words(2.02, lang='sr', to='currency', currency='RUB') + + ) + self.assertEqual( + 'dve rublje, pet kopejki', + num2words(2.05, lang='sr', to='currency', currency='RUB') + + ) + self.assertEqual( + 'jedan dinar, nula para', + num2words(1.0, lang='sr', to='currency', currency='RSD') + ) + self.assertEqual( + 'dva dinara, dve pare', + num2words(2.02, lang='sr', to='currency', currency='RSD') + + ) + self.assertEqual( + 'pet dinara, pet para', + num2words(5.05, lang='sr', to='currency', currency='RSD') + + ) + self.assertEqual( + 'jedanaest dinara, jedanaest para', + num2words(11.11, lang='sr', to='currency', currency='RSD') + + ) + self.assertEqual( + 'dvadeset jedan dinar, dvadeset jedna para', + num2words(21.21, lang='sr', to='currency', currency='RSD') + + ) + self.assertEqual( + 'dvadeset jedan evro, dvadeset jedan cent', + num2words(21.21, lang='sr', to='currency', currency='EUR') + + ) + self.assertEqual( + 'dvadeset jedna rublja, dvadeset jedna kopejka', + num2words(21.21, lang='sr', to='currency', currency='RUB') + + ) + self.assertEqual( + 'jedna hiljada dvesta trideset četiri evra, ' + 'pedeset šest centi', + num2words( + 1234.56, lang='sr', to='currency', currency='EUR' + ) + ) + self.assertEqual( + 'jedna hiljada dvesta trideset četiri rublje, ' + 'pedeset šest kopejki', + num2words( + 1234.56, lang='sr', to='currency', currency='RUB' + ) + ) + self.assertEqual( + 'sto jedan evro i jedanaest centi', + num2words( + 10111, + lang='sr', + to='currency', + currency='EUR', + seperator=' i' + ) + ) + self.assertEqual( + 'sto jedna rublja i dvadeset jedna kopejka', + num2words( + 10121, + lang='sr', + to='currency', + currency='RUB', + seperator=' i' + ) + ) + self.assertEqual( + 'sto jedna rublja i dvadeset dve kopejke', + num2words(10122, lang='sr', to='currency', currency='RUB', + seperator=' i') + ) + self.assertEqual( + 'sto jedan evro i dvadeset jedan cent', + num2words(10121, lang='sr', to='currency', currency='EUR', + seperator=' i'), + ) + self.assertEqual( + 'minus dvanaest hiljada petsto devetnaest evra, 85 centi', + num2words( + -1251985, + lang='sr', + to='currency', + currency='EUR', + cents=False + ) + ) + self.assertEqual( + "trideset osam evra i 40 centi", + num2words('38.4', lang='sr', to='currency', seperator=' i', + cents=False, currency='EUR'), + ) From 4d8c93847cad53180585e07ff90c4df5d8bb0f41 Mon Sep 17 00:00:00 2001 From: Sangbum Kim Date: Sun, 11 Nov 2018 08:44:02 +0900 Subject: [PATCH 02/23] Add: Korean support (#219) * Add: lang_KO support Added Korean language support and tests * Remove commented code --- README.rst | 1 + num2words/__init__.py | 2 + num2words/lang_KO.py | 148 ++++++++++++++++++++++++++++++++++++++++++ tests/test_ko.py | 92 ++++++++++++++++++++++++++ 4 files changed, 243 insertions(+) create mode 100644 num2words/lang_KO.py create mode 100644 tests/test_ko.py diff --git a/README.rst b/README.rst index 0cdaf08..d9f4cd2 100644 --- a/README.rst +++ b/README.rst @@ -97,6 +97,7 @@ Besides the numerical argument, there are two main optional arguments. * ``id`` (Indonesian) * ``it`` (Italian) * ``ja`` (Japanese) +* ``ko`` (Korean) * ``lt`` (Lithuanian) * ``lv`` (Latvian) * ``no`` (Norwegian) diff --git a/num2words/__init__.py b/num2words/__init__.py index 8188d46..2db3100 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -49,6 +49,7 @@ from . import lang_UK from . import lang_SL from . import lang_SR from . import lang_TH +from . import lang_KO CONVERTER_CLASSES = { 'ar': lang_AR.Num2Word_AR(), @@ -66,6 +67,7 @@ CONVERTER_CLASSES = { 'es_VE': lang_ES_VE.Num2Word_ES_VE(), 'id': lang_ID.Num2Word_ID(), 'ja': lang_JA.Num2Word_JA(), + 'ko': lang_KO.Num2Word_KO(), 'lt': lang_LT.Num2Word_LT(), 'lv': lang_LV.Num2Word_LV(), 'pl': lang_PL.Num2Word_PL(), diff --git a/num2words/lang_KO.py b/num2words/lang_KO.py new file mode 100644 index 0000000..e192cc6 --- /dev/null +++ b/num2words/lang_KO.py @@ -0,0 +1,148 @@ +# -*- 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, print_function, unicode_literals + +from .base import Num2Word_Base +from .currency import parse_currency_parts + + +class Num2Word_KO(Num2Word_Base): + CURRENCY_FORMS = { + 'KRW': ('원', None), + 'USD': ('달러', '센트'), + 'JPY': ('엔', None) + } + + def set_high_numwords(self, high): + max = 4 * len(high) + for word, n in zip(high, range(max, 0, -4)): + self.cards[10 ** n] = word + + def setup(self): + super(Num2Word_KO, self).setup() + + self.negword = "마이너스 " + self.pointword = "점" + + self.high_numwords = [ + '무량대수', + '불가사의', + '나유타', + '아승기', + '항하사', + '극', + '재', + '정', + '간', + '구', + '양', + '자', + '해', + '경', + '조', + '억', + '만'] + self.mid_numwords = [(1000, "천"), (100, "백")] + self.low_numwords = ["십", "구", "팔", "칠", "육", "오", "사", "삼", "이", + "일", "영"] + self.ords = {"일": "한", + "이": "두", + "삼": "세", + "사": "네", + "오": "다섯", + "육": "여섯", + "칠": "일곱", + "팔": "여덟", + "구": "아홉", + "십": "열", + "이십": "스물", + "삼십": "서른", + "사십": "마흔", + "오십": "쉰", + "육십": "예순", + "칠십": "일흔", + "팔십": "여든", + "구십": "아흔"} + + def merge(self, lpair, rpair): + ltext, lnum = lpair + rtext, rnum = rpair + if lnum == 1 and rnum <= 10000: + return rpair + elif 10000 > lnum > rnum: + return ("%s%s" % (ltext, rtext), lnum + rnum) + elif lnum >= 10000 and lnum > rnum: + return ("%s %s" % (ltext, rtext), lnum + rnum) + else: + return ("%s%s" % (ltext, rtext), lnum * rnum) + + def to_ordinal(self, value): + self.verify_ordinal(value) + if(value == 1): + return "첫 번째" + outwords = self.to_cardinal(value).split(" ") + lastwords = outwords[-1].split("백") + if "십" in lastwords[-1]: + ten_one = lastwords[-1].split("십") + ten_one[0] = self.ords[ten_one[0] + "십"] + try: + ten_one[1] = self.ords[ten_one[1]] + ten_one[0] = ten_one[0].replace("스무", "스물") + except KeyError: + pass + lastwords[-1] = ''.join(ten_one) + else: + lastwords[-1] = self.ords[lastwords[-1]] + outwords[-1] = "백 ".join(lastwords) + return " ".join(outwords) + " 번째" + + def to_ordinal_num(self, value): + self.verify_ordinal(value) + return "%s 번째" % (value) + + def to_year(self, val, suffix=None, longval=True): + if val < 0: + val = abs(val) + suffix = '기원전' if not suffix else suffix + valtext = self.to_cardinal(val) + return ("%s년" % valtext if not suffix + else "%s %s년" % (suffix, valtext)) + + def to_currency(self, val, currency="KRW", cents=False, seperator="", + adjective=False): + left, right, is_negative = parse_currency_parts( + val, is_int_with_cents=cents) + + try: + cr1, cr2 = self.CURRENCY_FORMS[currency] + if (cents or right) and not cr2: + raise ValueError('Decimals not supported for "%s"' % currency) + except KeyError: + raise NotImplementedError( + 'Currency code "%s" not implemented for "%s"' % + (currency, self.__class__.__name__)) + + minus_str = self.negword if is_negative else "" + return '%s%s%s%s%s' % ( + minus_str, + ''.join(self.to_cardinal(left).split()), + cr1, + ' ' + self.to_cardinal(right) + if cr2 else '', + cr2 if cr2 else '', + ) diff --git a/tests/test_ko.py b/tests/test_ko.py new file mode 100644 index 0000000..401ecb8 --- /dev/null +++ b/tests/test_ko.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +# 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, print_function, unicode_literals + +from unittest import TestCase + +from num2words import num2words + + +def n2k(*args, **kwargs): + return num2words(*args, lang='ko', **kwargs) + + +class Num2WordsKOTest(TestCase): + def test_low(self): + cases = [(0, "영"), (1, "일"), (2, "이"), (3, "삼"), (4, "사"), (5, "오"), + (6, "육"), (7, "칠"), (8, "팔"), (9, "구"), (10, "십"), + (11, "십일"), (12, "십이"), (13, "십삼"), (14, "십사"), + (15, "십오"), (16, "십육"), (17, "십칠"), + (18, "십팔"), (19, "십구"), (20, "이십"), (25, "이십오"), + (31, "삼십일"), (42, "사십이"), (54, "오십사"), (63, "육십삼"), + (76, "칠십육"), (89, "팔십구"), (98, "구십팔")] + for num, out in cases: + self.assertEqual(n2k(num), out) + + def test_mid(self): + cases = [(100, "백"), (121, "백이십일"), (160, "백육십"), (256, "이백오십육"), + (285, "이백팔십오"), (486, "사백팔십육"), (627, "육백이십칠"), + (808, "팔백팔"), (999, "구백구십구"), (1004, "천사"), + (2018, "이천십팔"), (7063, "칠천육십삼")] + for num, out in cases: + self.assertEqual(n2k(num), out) + + def test_high(self): + cases = [(10000, "만"), (11020, "만 천이십"), (25891, "이만 오천팔백구십일"), + (64237, "육만 사천이백삼십칠"), (241572, "이십사만 천오백칠십이"), + (100000000, "일억"), (5000500000000, "오조 오억")] + for num, out in cases: + self.assertEqual(n2k(num), out) + + def test_negative(self): + cases = [(-11, "마이너스 십일"), (-15, "마이너스 십오"), + (-18, "마이너스 십팔"), (-241572, "마이너스 이십사만 천오백칠십이")] + for num, out in cases: + self.assertEqual(n2k(num), out) + + def test_year(self): + cases = [(2000, "이천년"), (2002, "이천이년"), (2018, "이천십팔년"), + (1954, "천구백오십사년"), (1910, "천구백십년"), (-1000, "기원전 천년")] + for num, out in cases: + self.assertEqual(n2k(num, to="year"), out) + + def test_currency(self): + cases_krw = [(8350, "팔천삼백오십원"), (14980, "만사천구백팔십원"), + (250004000, "이억오천만사천원")] + cases_usd = [(4, "사달러 영센트"), (19.55, "십구달러 오십오센트")] + cases_jpy = [(15, "십오엔"), (50, "오십엔")] + for num, out in cases_krw: + self.assertEqual(n2k(num, to="currency"), out) + for num, out in cases_usd: + self.assertEqual(n2k(num, to="currency", currency="USD"), out) + for num, out in cases_jpy: + self.assertEqual(n2k(num, to="currency", currency="JPY"), out) + with self.assertRaises(ValueError): + n2k(190.55, to="currency") + with self.assertRaises(NotImplementedError): + n2k(4, to="currency", currency="EUR") + + def test_ordinal(self): + cases = [(1, "첫 번째"), (101, "백 한 번째"), (2, "두 번째"), (5, "다섯 번째"), + (10, "열 번째"), (25, "스물다섯 번째"), (137, "백 서른일곱 번째")] + for num, out in cases: + self.assertEqual(n2k(num, to="ordinal"), out) + + def test_ordinal_num(self): + cases = [(1, "1 번째"), (101, "101 번째"), (25, "25 번째")] + for num, out in cases: + self.assertEqual(n2k(num, to="ordinal_num"), out) From 66a47e24234fa09692836db66abc37595a666928 Mon Sep 17 00:00:00 2001 From: Hugo Lefeuvre Date: Fri, 16 Nov 2018 22:19:36 +0100 Subject: [PATCH 03/23] Improve german support (#222) * german: fix case in currency names Also, add more tests for german language. * german: default to amount of euros, not cents If a non-float number is provided, interpret it as a quantity in euros, not cents. * german: handle "ein Euro" vs "eins Euro" exception * german: prefer "einhundert" over "hundert" "hundert" is usually colloquial (even if widely used). Exception: "eintausendste" and "hundertste" are special cases, here "hundertste" and "tausendste" are usually preferred (see Duden). --- num2words/lang_DE.py | 32 ++++++++++++++++++++++++-------- tests/test_de.py | 25 +++++++++++++++++++++---- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/num2words/lang_DE.py b/num2words/lang_DE.py index ca993bb..f681697 100644 --- a/num2words/lang_DE.py +++ b/num2words/lang_DE.py @@ -78,7 +78,9 @@ class Num2Word_DE(Num2Word_EU): ctext, cnum, ntext, nnum = curr + next if cnum == 1: - if nnum < 10 ** 6: + if nnum == 100 or nnum == 1000: + return ("ein" + ntext, nnum) + elif nnum < 10 ** 6: return next ctext = "eine" @@ -110,21 +112,35 @@ class Num2Word_DE(Num2Word_EU): if outword.endswith(key): outword = outword[:len(outword) - len(key)] + self.ords[key] break - return outword + "te" + + res = outword + "te" + + # Exception: "hundertste" is usually preferred over "einhundertste" + if res == "eintausendste" or res == "einhundertste": + res = res.replace("ein", "", 1) + + return res def to_ordinal_num(self, value): self.verify_ordinal(value) return str(value) + "." def to_currency(self, val, longval=True, old=False): - hightxt = "euro" - lowtxt = "cent" + hightxt = "Euro" + lowtxt = "Cent" if old: - hightxt = "mark" - lowtxt = "pfennig/e" + hightxt = "Mark" + lowtxt = "Pfennig/e" - return self.to_splitnum(val, hightxt=hightxt, lowtxt=lowtxt, - jointxt="und", longval=longval) + cents = int(round(val*100)) + res = self.to_splitnum(cents, hightxt=hightxt, lowtxt=lowtxt, + jointxt="und", longval=longval) + + # Handle exception, in german is "ein Euro" and not "eins Euro" + if res.startswith("eins "): + res = res.replace("eins ", "ein ", 1) + + return res def to_year(self, val, longval=True): if not (val // 100) % 10: diff --git a/tests/test_de.py b/tests/test_de.py index 0388b21..3c30dd8 100644 --- a/tests/test_de.py +++ b/tests/test_de.py @@ -52,6 +52,7 @@ class Num2WordsDETest(TestCase): ) def test_cardinal_at_some_numbers(self): + self.assertEqual(num2words(100, lang='de'), "einhundert") self.assertEqual(num2words(2000000, lang='de'), "zwei millionen") self.assertEqual(num2words(4000000000, lang='de'), "vier milliarden") self.assertEqual(num2words(1000000000, lang='de'), "eine milliarde") @@ -65,7 +66,7 @@ class Num2WordsDETest(TestCase): self.assertEqual( num2words(4500072900000111, lang='de'), "vier billiarden fünfhundert billionen " + - "zweiundsiebzig milliarden neunhundert millionen hundertelf" + "zweiundsiebzig milliarden neunhundert millionen einhundertelf" ) def test_ordinal_num(self): @@ -79,12 +80,28 @@ class Num2WordsDETest(TestCase): self.assertRaises(TypeError, num2words, 2.453, ordinal=True, lang='de') def test_currency(self): - self.assertEqual(num2words(12.00, to='currency', lang='de'), - 'zwölf euro') + self.assertEqual(num2words(1, lang='de', to='currency'), + 'ein Euro') + self.assertEqual(num2words(12, lang='de', to='currency'), + 'zwölf Euro') + self.assertEqual(num2words(12.00, lang='de', to='currency'), + 'zwölf Euro') + self.assertEqual(num2words(100.0, lang='de', to='currency'), + "einhundert Euro") + self.assertEqual(num2words(190, lang='de', to='currency'), + "einhundertneunzig Euro") + self.assertEqual(num2words(1.90, lang='de', to='currency'), + "ein Euro und neunzig Cent") + self.assertEqual(num2words(3.4, lang='de', to='currency'), + "drei Euro und vierzig Cent") + self.assertEqual(num2words(20.18, lang='de', to='currency'), + "zwanzig Euro und achtzehn Cent") + self.assertEqual(num2words(3.04, lang='de', to='currency'), + "drei Euro und vier Cent") def test_old_currency(self): self.assertEqual(num2words(12.00, to='currency', lang='de', old=True), - 'zwölf mark') + 'zwölf Mark') def test_year(self): self.assertEqual(num2words(2002, to='year', lang='de'), From fffb5c2dcfc42a1941575f99dfef8b3477e97550 Mon Sep 17 00:00:00 2001 From: Ernesto Rodriguez Ortiz Date: Sat, 17 Nov 2018 14:38:49 -0500 Subject: [PATCH 04/23] Release 0.5.8 --- CHANGES.rst | 19 +++++++++++++++++++ bin/num2words | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 9d3015d..0f15372 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,25 @@ Changelog ========= +Version 0.5.8 -- 2018/11/17 +--------------------------- + +* Add Portuguese (Portugal) localization (#198) +* Add a command line tool to use num2words +* Use language iso code for Vietnamese +* Improve Korean localization (#219) +* Improve Serbian (Latin) localization (#207) +* Improve testing setup (#220) +* Improve German localization (#214) (#222) +* Improve Romanian localization (#215) +* Improve Spanish localization (#187) (#200) +* Improve Russian localization (#211) (#212) +* Improve French localization (23902ab) +* Improve Arabic localization (#176) +* Improve Lithuanian and Latvian localization (#185) +* Improve Ukrainian localization (#183) + + Version 0.5.7 -- 2018/06/27 --------------------------- diff --git a/bin/num2words b/bin/num2words index 9c6df8a..e5268ad 100755 --- a/bin/num2words +++ b/bin/num2words @@ -41,7 +41,7 @@ import sys from docopt import docopt import num2words -__version__ = "0.5.7" +__version__ = "0.5.8" __license__ = "LGPL" From 562e4467168b70a8325415ee0ee4821ed879b679 Mon Sep 17 00:00:00 2001 From: Marek Madejski Date: Fri, 30 Nov 2018 09:42:15 +0100 Subject: [PATCH 05/23] Update lang_PL.py - typo in "kwadryliard" - expanded long scale up to decilliard (10^63) --- num2words/lang_PL.py | 53 ++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/num2words/lang_PL.py b/num2words/lang_PL.py index 4289177..b70d4f6 100644 --- a/num2words/lang_PL.py +++ b/num2words/lang_PL.py @@ -70,16 +70,27 @@ HUNDREDS = { } THOUSANDS = { - 1: ('tysiąc', 'tysiące', 'tysięcy'), # 10^3 - 2: ('milion', 'miliony', 'milionów'), # 10^6 - 3: ('miliard', 'miliardy', 'miliardów'), # 10^9 - 4: ('bilion', 'biliony', 'bilionów'), # 10^12 - 5: ('biliard', 'biliardy', 'biliardów'), # 10^15 - 6: ('trylion', 'tryliony', 'trylionów'), # 10^18 - 7: ('tryliard', 'tryliardy', 'tryliardów'), # 10^21 - 8: ('kwadrylion', 'kwadryliony', 'kwadrylionów'), # 10^24 - 9: ('kwaryliard', 'kwadryliardy', 'kwadryliardów'), # 10^27 - 10: ('kwintylion', 'kwintyliony', 'kwintylionów'), # 10^30 + 1: ('tysiąc', 'tysiące', 'tysięcy'), # 10^3 + 2: ('milion', 'miliony', 'milionów'), # 10^6 + 3: ('miliard', 'miliardy', 'miliardów'), # 10^9 + 4: ('bilion', 'biliony', 'bilionów'), # 10^12 + 5: ('biliard', 'biliardy', 'biliardów'), # 10^15 + 6: ('trylion', 'tryliony', 'trylionów'), # 10^18 + 7: ('tryliard', 'tryliardy', 'tryliardów'), # 10^21 + 8: ('kwadrylion', 'kwadryliony', 'kwadrylionów'), # 10^24 + 9: ('kwadryliard', 'kwadryliardy', 'kwadryliardów'), # 10^27 + 10: ('kwintylion', 'kwintyliony', 'kwintylionów'), # 10^30 + 11: ('kwintyliard', 'kwintyliardy', 'kwintyliardów'), # 10^33 + 12: ('sekstylion', 'sekstyliony', 'sekstylionów'), # 10^36 + 13: ('sekstyliard', 'sekstyliardy', 'sekstyliardów'), # 10^39 + 14: ('septylion', 'septyliony', 'septylionów'), # 10^42 + 15: ('septyliard', 'septyliardy', 'septyliardów'), # 10^45 + 16: ('oktylion', 'oktyliony', 'oktylionów'), # 10^48 + 17: ('oktyliard', 'oktyliardy', 'oktyliardów'), # 10^51 + 18: ('nonylion', 'nonyliony', 'nonylionów'), # 10^54 + 19: ('nonyliard', 'nonyliardy', 'nonyliardów'), # 10^57 + 20: ('decylion', 'decyliony', 'decylionów'), # 10^60 + 21: ('decyliard', 'decyliardy', 'decyliardów'), # 10^63 } @@ -92,11 +103,11 @@ class Num2Word_PL(Num2Word_Base): ('euro', 'euro', 'euro'), ('cent', 'centy', 'centów') ), } - + def setup(self): self.negword = "minus" self.pointword = "przecinek" - + def to_cardinal(self, number): n = str(number).replace(',', '.') if '.' in n: @@ -108,7 +119,7 @@ class Num2Word_PL(Num2Word_Base): ) else: return self._int2word(int(n)) - + def pluralize(self, n, forms): if n == 1: form = 0 @@ -117,33 +128,33 @@ class Num2Word_PL(Num2Word_Base): else: form = 2 return forms[form] - + def to_ordinal(self, number): raise NotImplementedError() - + def _int2word(self, n): if n == 0: return ZERO[0] - + words = [] chunks = list(splitbyx(str(n), 3)) i = len(chunks) for x in chunks: i -= 1 n1, n2, n3 = get_digits(x) - + if n3 > 0: words.append(HUNDREDS[n3][0]) - + if n2 > 1: words.append(TWENTIES[n2][0]) - + if n2 == 1: words.append(TENS[n1][0]) elif n1 > 0 and not (i > 0 and x == 1): words.append(ONES[n1][0]) - + if i > 0: words.append(self.pluralize(x, THOUSANDS[i])) - + return ' '.join(words) From 8fde057760575b1b62f281ce1330e01f2a22b316 Mon Sep 17 00:00:00 2001 From: Marek Madejski Date: Mon, 3 Dec 2018 09:57:37 +0100 Subject: [PATCH 06/23] Update lang_PL.py - typo in "kwadryliard" - expanded long scale up to decilliard (10^63) - PEP8 compliance --- num2words/lang_PL.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/num2words/lang_PL.py b/num2words/lang_PL.py index 4289177..f9377c4 100644 --- a/num2words/lang_PL.py +++ b/num2words/lang_PL.py @@ -70,16 +70,27 @@ HUNDREDS = { } THOUSANDS = { - 1: ('tysiąc', 'tysiące', 'tysięcy'), # 10^3 - 2: ('milion', 'miliony', 'milionów'), # 10^6 - 3: ('miliard', 'miliardy', 'miliardów'), # 10^9 - 4: ('bilion', 'biliony', 'bilionów'), # 10^12 - 5: ('biliard', 'biliardy', 'biliardów'), # 10^15 - 6: ('trylion', 'tryliony', 'trylionów'), # 10^18 - 7: ('tryliard', 'tryliardy', 'tryliardów'), # 10^21 - 8: ('kwadrylion', 'kwadryliony', 'kwadrylionów'), # 10^24 - 9: ('kwaryliard', 'kwadryliardy', 'kwadryliardów'), # 10^27 - 10: ('kwintylion', 'kwintyliony', 'kwintylionów'), # 10^30 + 1: ('tysiąc', 'tysiące', 'tysięcy'), # 10^3 + 2: ('milion', 'miliony', 'milionów'), # 10^6 + 3: ('miliard', 'miliardy', 'miliardów'), # 10^9 + 4: ('bilion', 'biliony', 'bilionów'), # 10^12 + 5: ('biliard', 'biliardy', 'biliardów'), # 10^15 + 6: ('trylion', 'tryliony', 'trylionów'), # 10^18 + 7: ('tryliard', 'tryliardy', 'tryliardów'), # 10^21 + 8: ('kwadrylion', 'kwadryliony', 'kwadrylionów'), # 10^24 + 9: ('kwadryliard', 'kwadryliardy', 'kwadryliardów'), # 10^27 + 10: ('kwintylion', 'kwintyliony', 'kwintylionów'), # 10^30 + 11: ('kwintyliard', 'kwintyliardy', 'kwintyliardów'), # 10^33 + 12: ('sekstylion', 'sekstyliony', 'sekstylionów'), # 10^36 + 13: ('sekstyliard', 'sekstyliardy', 'sekstyliardów'), # 10^39 + 14: ('septylion', 'septyliony', 'septylionów'), # 10^42 + 15: ('septyliard', 'septyliardy', 'septyliardów'), # 10^45 + 16: ('oktylion', 'oktyliony', 'oktylionów'), # 10^48 + 17: ('oktyliard', 'oktyliardy', 'oktyliardów'), # 10^51 + 18: ('nonylion', 'nonyliony', 'nonylionów'), # 10^54 + 19: ('nonyliard', 'nonyliardy', 'nonyliardów'), # 10^57 + 20: ('decylion', 'decyliony', 'decylionów'), # 10^60 + 21: ('decyliard', 'decyliardy', 'decyliardów'), # 10^63 } From a147dc3d34a5f0265e9534cd0838f9243b4d2e1d Mon Sep 17 00:00:00 2001 From: Marek Madejski Date: Mon, 3 Dec 2018 09:59:53 +0100 Subject: [PATCH 07/23] Update lang_PL.py PEP8 compliance --- num2words/lang_PL.py | 64 ++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/num2words/lang_PL.py b/num2words/lang_PL.py index b70d4f6..f9377c4 100644 --- a/num2words/lang_PL.py +++ b/num2words/lang_PL.py @@ -70,27 +70,27 @@ HUNDREDS = { } THOUSANDS = { - 1: ('tysiąc', 'tysiące', 'tysięcy'), # 10^3 - 2: ('milion', 'miliony', 'milionów'), # 10^6 - 3: ('miliard', 'miliardy', 'miliardów'), # 10^9 - 4: ('bilion', 'biliony', 'bilionów'), # 10^12 - 5: ('biliard', 'biliardy', 'biliardów'), # 10^15 - 6: ('trylion', 'tryliony', 'trylionów'), # 10^18 - 7: ('tryliard', 'tryliardy', 'tryliardów'), # 10^21 - 8: ('kwadrylion', 'kwadryliony', 'kwadrylionów'), # 10^24 - 9: ('kwadryliard', 'kwadryliardy', 'kwadryliardów'), # 10^27 - 10: ('kwintylion', 'kwintyliony', 'kwintylionów'), # 10^30 - 11: ('kwintyliard', 'kwintyliardy', 'kwintyliardów'), # 10^33 - 12: ('sekstylion', 'sekstyliony', 'sekstylionów'), # 10^36 - 13: ('sekstyliard', 'sekstyliardy', 'sekstyliardów'), # 10^39 - 14: ('septylion', 'septyliony', 'septylionów'), # 10^42 - 15: ('septyliard', 'septyliardy', 'septyliardów'), # 10^45 - 16: ('oktylion', 'oktyliony', 'oktylionów'), # 10^48 - 17: ('oktyliard', 'oktyliardy', 'oktyliardów'), # 10^51 - 18: ('nonylion', 'nonyliony', 'nonylionów'), # 10^54 - 19: ('nonyliard', 'nonyliardy', 'nonyliardów'), # 10^57 - 20: ('decylion', 'decyliony', 'decylionów'), # 10^60 - 21: ('decyliard', 'decyliardy', 'decyliardów'), # 10^63 + 1: ('tysiąc', 'tysiące', 'tysięcy'), # 10^3 + 2: ('milion', 'miliony', 'milionów'), # 10^6 + 3: ('miliard', 'miliardy', 'miliardów'), # 10^9 + 4: ('bilion', 'biliony', 'bilionów'), # 10^12 + 5: ('biliard', 'biliardy', 'biliardów'), # 10^15 + 6: ('trylion', 'tryliony', 'trylionów'), # 10^18 + 7: ('tryliard', 'tryliardy', 'tryliardów'), # 10^21 + 8: ('kwadrylion', 'kwadryliony', 'kwadrylionów'), # 10^24 + 9: ('kwadryliard', 'kwadryliardy', 'kwadryliardów'), # 10^27 + 10: ('kwintylion', 'kwintyliony', 'kwintylionów'), # 10^30 + 11: ('kwintyliard', 'kwintyliardy', 'kwintyliardów'), # 10^33 + 12: ('sekstylion', 'sekstyliony', 'sekstylionów'), # 10^36 + 13: ('sekstyliard', 'sekstyliardy', 'sekstyliardów'), # 10^39 + 14: ('septylion', 'septyliony', 'septylionów'), # 10^42 + 15: ('septyliard', 'septyliardy', 'septyliardów'), # 10^45 + 16: ('oktylion', 'oktyliony', 'oktylionów'), # 10^48 + 17: ('oktyliard', 'oktyliardy', 'oktyliardów'), # 10^51 + 18: ('nonylion', 'nonyliony', 'nonylionów'), # 10^54 + 19: ('nonyliard', 'nonyliardy', 'nonyliardów'), # 10^57 + 20: ('decylion', 'decyliony', 'decylionów'), # 10^60 + 21: ('decyliard', 'decyliardy', 'decyliardów'), # 10^63 } @@ -103,11 +103,11 @@ class Num2Word_PL(Num2Word_Base): ('euro', 'euro', 'euro'), ('cent', 'centy', 'centów') ), } - + def setup(self): self.negword = "minus" self.pointword = "przecinek" - + def to_cardinal(self, number): n = str(number).replace(',', '.') if '.' in n: @@ -119,7 +119,7 @@ class Num2Word_PL(Num2Word_Base): ) else: return self._int2word(int(n)) - + def pluralize(self, n, forms): if n == 1: form = 0 @@ -128,33 +128,33 @@ class Num2Word_PL(Num2Word_Base): else: form = 2 return forms[form] - + def to_ordinal(self, number): raise NotImplementedError() - + def _int2word(self, n): if n == 0: return ZERO[0] - + words = [] chunks = list(splitbyx(str(n), 3)) i = len(chunks) for x in chunks: i -= 1 n1, n2, n3 = get_digits(x) - + if n3 > 0: words.append(HUNDREDS[n3][0]) - + if n2 > 1: words.append(TWENTIES[n2][0]) - + if n2 == 1: words.append(TENS[n1][0]) elif n1 > 0 and not (i > 0 and x == 1): words.append(ONES[n1][0]) - + if i > 0: words.append(self.pluralize(x, THOUSANDS[i])) - + return ' '.join(words) From f26c3a139aeadd74a2608d8c760181399aa97d68 Mon Sep 17 00:00:00 2001 From: Marek Madejski Date: Mon, 3 Dec 2018 11:05:36 +0100 Subject: [PATCH 08/23] Update test_pl.py test for really big number's Polish name --- tests/test_pl.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/test_pl.py b/tests/test_pl.py index c8a8462..0dbd97d 100644 --- a/tests/test_pl.py +++ b/tests/test_pl.py @@ -64,6 +64,22 @@ class Num2WordsPLTest(TestCase): "osiemdziesiąt cztery miliony dwieście dwadzieścia " "tysięcy dwieście dziewięćdzisiąt jeden" ) + self.assertEqual( + num2words( + 963301000001918264129471042047146102350812074235000101020000120324, + lang='pl' + ), + "dziewięćset sześćdziesiąt trzy decyliardy trzysta jeden " + "decylionów nonylion dziewięćset osiemnaście oktyliardów dwieście " + "sześćdziesiąt cztery oktyliony sto dwadzieścia dziewięć " + "septyliardów czterysta siedemdziesiąt jeden septylionów " + "czterdzieści dwa sekstyliardy czterdzieści siedem sekstylionów " + "sto czterdzieści sześć kwintyliardów sto dwa kwintyliony trzysta " + "pięćdziesiąt kwadryliardów osiemset dwanaście kwadrylionów " + "siedemdziesiąt cztery tryliardy dwieście trzydzieści pięć " + "trylionów sto jeden bilionów dwadzieścia miliardów sto " + "dwadzieścia tysięcy trzysta dwadzieścia cztery" + ) def test_to_ordinal(self): # @TODO: implement to_ordinal From efde954697cb4798da050f72c9924eef3cc893bf Mon Sep 17 00:00:00 2001 From: Marek Madejski Date: Mon, 3 Dec 2018 11:14:55 +0100 Subject: [PATCH 09/23] Update test_pl.py added test for a really big number in Polish --- tests/test_pl.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/test_pl.py b/tests/test_pl.py index c8a8462..0dbd97d 100644 --- a/tests/test_pl.py +++ b/tests/test_pl.py @@ -64,6 +64,22 @@ class Num2WordsPLTest(TestCase): "osiemdziesiąt cztery miliony dwieście dwadzieścia " "tysięcy dwieście dziewięćdzisiąt jeden" ) + self.assertEqual( + num2words( + 963301000001918264129471042047146102350812074235000101020000120324, + lang='pl' + ), + "dziewięćset sześćdziesiąt trzy decyliardy trzysta jeden " + "decylionów nonylion dziewięćset osiemnaście oktyliardów dwieście " + "sześćdziesiąt cztery oktyliony sto dwadzieścia dziewięć " + "septyliardów czterysta siedemdziesiąt jeden septylionów " + "czterdzieści dwa sekstyliardy czterdzieści siedem sekstylionów " + "sto czterdzieści sześć kwintyliardów sto dwa kwintyliony trzysta " + "pięćdziesiąt kwadryliardów osiemset dwanaście kwadrylionów " + "siedemdziesiąt cztery tryliardy dwieście trzydzieści pięć " + "trylionów sto jeden bilionów dwadzieścia miliardów sto " + "dwadzieścia tysięcy trzysta dwadzieścia cztery" + ) def test_to_ordinal(self): # @TODO: implement to_ordinal From 518ce0b606f61e470b2717cbc5eebe21c9681391 Mon Sep 17 00:00:00 2001 From: Marek Madejski Date: Mon, 3 Dec 2018 11:30:45 +0100 Subject: [PATCH 10/23] Update lang_PL.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit typo in "dziewięćset" (900) fix --- num2words/lang_PL.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/num2words/lang_PL.py b/num2words/lang_PL.py index f9377c4..25b1a3e 100644 --- a/num2words/lang_PL.py +++ b/num2words/lang_PL.py @@ -66,7 +66,7 @@ HUNDREDS = { 6: ('sześćset',), 7: ('siedemset',), 8: ('osiemset',), - 9: ('dziewęćset',), + 9: ('dziewięćset',), } THOUSANDS = { From b8cd4ba181ebca8613f10f2685f09114f4561b9f Mon Sep 17 00:00:00 2001 From: Marek Madejski Date: Mon, 3 Dec 2018 12:03:16 +0100 Subject: [PATCH 11/23] no word for zero value of thousand's power; PL unit test fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before: 1_000_000_000 = "miliard milionów tysięcy" (with words for zero millions and thousands) After: "miliard" (no words if value for given power of 1000 is 0) --- num2words/lang_CZ.py | 2 +- num2words/lang_HE.py | 2 +- num2words/lang_LT.py | 2 +- num2words/lang_LV.py | 2 +- num2words/lang_PL.py | 2 +- num2words/lang_RU.py | 2 +- num2words/lang_UK.py | 2 +- tests/test_pl.py | 4 ++++ 8 files changed, 11 insertions(+), 7 deletions(-) diff --git a/num2words/lang_CZ.py b/num2words/lang_CZ.py index 0a29049..d0db8a8 100644 --- a/num2words/lang_CZ.py +++ b/num2words/lang_CZ.py @@ -143,7 +143,7 @@ class Num2Word_CZ(Num2Word_Base): elif n1 > 0 and not (i > 0 and x == 1): words.append(ONES[n1][0]) - if i > 0: + if x > 0 and i > 0: words.append(self.pluralize(x, THOUSANDS[i])) return ' '.join(words) diff --git a/num2words/lang_HE.py b/num2words/lang_HE.py index 3789cc5..ca4efd9 100644 --- a/num2words/lang_HE.py +++ b/num2words/lang_HE.py @@ -113,7 +113,7 @@ def int2word(n): elif n1 > 0 and not (i > 0 and x == 1): words.append(ONES[n1][0]) - if i > 0: + if x > 0 and i > 0: if i <= 2: words.append(THOUSANDS[i][0]) else: diff --git a/num2words/lang_LT.py b/num2words/lang_LT.py index ddd003e..162f499 100644 --- a/num2words/lang_LT.py +++ b/num2words/lang_LT.py @@ -169,7 +169,7 @@ class Num2Word_LT(Num2Word_Base): else: words.append(ONES[n1][0]) - if i > 0: + if x > 0 and i > 0: words.append(self.pluralize(x, THOUSANDS[i])) return ' '.join(words) diff --git a/num2words/lang_LV.py b/num2words/lang_LV.py index d1bd934..213eae5 100644 --- a/num2words/lang_LV.py +++ b/num2words/lang_LV.py @@ -176,7 +176,7 @@ class Num2Word_LV(Num2Word_Base): elif n1 > 0 and not (i > 0 and x == 1): words.append(ONES[n1][0]) - if i > 0 and x != 0: + if x > 0 and i > 0: words.append(self.pluralize(x, THOUSANDS[i])) return ' '.join(words) diff --git a/num2words/lang_PL.py b/num2words/lang_PL.py index 25b1a3e..b73b9b1 100644 --- a/num2words/lang_PL.py +++ b/num2words/lang_PL.py @@ -154,7 +154,7 @@ class Num2Word_PL(Num2Word_Base): elif n1 > 0 and not (i > 0 and x == 1): words.append(ONES[n1][0]) - if i > 0: + if x > 0 and i > 0: words.append(self.pluralize(x, THOUSANDS[i])) return ' '.join(words) diff --git a/num2words/lang_RU.py b/num2words/lang_RU.py index 349657a..a204487 100644 --- a/num2words/lang_RU.py +++ b/num2words/lang_RU.py @@ -223,7 +223,7 @@ class Num2Word_RU(Num2Word_Base): ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES words.append(ones[n1][0]) - if i > 0 and x != 0: + if x > 0 and i > 0: words.append(self.pluralize(x, THOUSANDS[i])) return ' '.join(words) diff --git a/num2words/lang_UK.py b/num2words/lang_UK.py index b751bed..e9a0a20 100644 --- a/num2words/lang_UK.py +++ b/num2words/lang_UK.py @@ -162,7 +162,7 @@ class Num2Word_UK(Num2Word_Base): ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES words.append(ones[n1][0]) - if i > 0 and ((n1 + n2 + n3) > 0): + if x > 0 and i > 0: words.append(self.pluralize(x, THOUSANDS[i])) return ' '.join(words) diff --git a/tests/test_pl.py b/tests/test_pl.py index 0dbd97d..8f2edec 100644 --- a/tests/test_pl.py +++ b/tests/test_pl.py @@ -45,6 +45,10 @@ class Num2WordsPLTest(TestCase): "miliard dwieście trzydzieści cztery miliony pięćset " "sześćdziesiąt siedem tysięcy osiemset dziewięćdzisiąt" ) + self.assertEqual( + num2words(10000000001000000100000, lang='pl'), + "dziesięć tryliardów bilion sto tysięcy" + ) self.assertEqual( num2words(215461407892039002157189883901676, lang='pl'), "dwieście piętnaście kwintylionów czterysta sześćdziesiąt jeden " From d78add4c3abcd18a3e51a6d73cc3ee6553fe7d07 Mon Sep 17 00:00:00 2001 From: Marek Madejski Date: Mon, 3 Dec 2018 12:40:04 +0100 Subject: [PATCH 12/23] Update test_pl.py unit test fix --- tests/test_pl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_pl.py b/tests/test_pl.py index 8f2edec..48e7e2c 100644 --- a/tests/test_pl.py +++ b/tests/test_pl.py @@ -56,7 +56,7 @@ class Num2WordsPLTest(TestCase): "dziewięćdzisiąt dwa tryliardy trzydzieści dziewięć trylionów " "dwa biliardy sto pięćdziesiąt siedem bilionów sto osiemdziesiąt " "dziewięć miliardów osiemset osiemdziesiąt trzy miliony " - "dziewęćset jeden tysięcy sześćset siedemdziesiąt sześć" + "dziewięćset jeden tysięcy sześćset siedemdziesiąt sześć" ) self.assertEqual( num2words(719094234693663034822824384220291, lang='pl'), From 4a0b323fa94f26bea82d5188eddd9539bb6539b3 Mon Sep 17 00:00:00 2001 From: Marek Madejski Date: Mon, 3 Dec 2018 16:07:15 +0100 Subject: [PATCH 13/23] early continue skip processing given power of thousand if it is 0 --- num2words/lang_CZ.py | 6 +++++- num2words/lang_HE.py | 8 +++++--- num2words/lang_LT.py | 6 +++++- num2words/lang_LV.py | 6 +++++- num2words/lang_PL.py | 6 +++++- num2words/lang_RU.py | 6 +++++- num2words/lang_UK.py | 6 +++++- tests/test_lt.py | 3 --- tests/test_lv.py | 3 --- 9 files changed, 35 insertions(+), 15 deletions(-) diff --git a/num2words/lang_CZ.py b/num2words/lang_CZ.py index d0db8a8..7cfa1f6 100644 --- a/num2words/lang_CZ.py +++ b/num2words/lang_CZ.py @@ -130,6 +130,10 @@ class Num2Word_CZ(Num2Word_Base): i = len(chunks) for x in chunks: i -= 1 + + if x == 0: + continue + n1, n2, n3 = get_digits(x) if n3 > 0: @@ -143,7 +147,7 @@ class Num2Word_CZ(Num2Word_Base): elif n1 > 0 and not (i > 0 and x == 1): words.append(ONES[n1][0]) - if x > 0 and i > 0: + if i > 0: words.append(self.pluralize(x, THOUSANDS[i])) return ' '.join(words) diff --git a/num2words/lang_HE.py b/num2words/lang_HE.py index ca4efd9..1c59e1e 100644 --- a/num2words/lang_HE.py +++ b/num2words/lang_HE.py @@ -94,9 +94,11 @@ def int2word(n): i = len(chunks) for x in chunks: i -= 1 - n1, n2, n3 = get_digits(x) - # print str(n3) + str(n2) + str(n1) + if x == 0: + continue + + n1, n2, n3 = get_digits(x) if n3 > 0: if n3 <= 2: @@ -113,7 +115,7 @@ def int2word(n): elif n1 > 0 and not (i > 0 and x == 1): words.append(ONES[n1][0]) - if x > 0 and i > 0: + if i > 0: if i <= 2: words.append(THOUSANDS[i][0]) else: diff --git a/num2words/lang_LT.py b/num2words/lang_LT.py index 162f499..1d13824 100644 --- a/num2words/lang_LT.py +++ b/num2words/lang_LT.py @@ -149,6 +149,10 @@ class Num2Word_LT(Num2Word_Base): for x in chunks: i -= 1 + + if x == 0: + continue + n1, n2, n3 = get_digits(x) if n3 > 0: @@ -169,7 +173,7 @@ class Num2Word_LT(Num2Word_Base): else: words.append(ONES[n1][0]) - if x > 0 and i > 0: + if i > 0: words.append(self.pluralize(x, THOUSANDS[i])) return ' '.join(words) diff --git a/num2words/lang_LV.py b/num2words/lang_LV.py index 213eae5..cd88472 100644 --- a/num2words/lang_LV.py +++ b/num2words/lang_LV.py @@ -157,6 +157,10 @@ class Num2Word_LV(Num2Word_Base): i = len(chunks) for x in chunks: i -= 1 + + if x == 0: + continue + n1, n2, n3 = get_digits(x) if n3 > 0: @@ -176,7 +180,7 @@ class Num2Word_LV(Num2Word_Base): elif n1 > 0 and not (i > 0 and x == 1): words.append(ONES[n1][0]) - if x > 0 and i > 0: + if i > 0: words.append(self.pluralize(x, THOUSANDS[i])) return ' '.join(words) diff --git a/num2words/lang_PL.py b/num2words/lang_PL.py index b73b9b1..34249cc 100644 --- a/num2words/lang_PL.py +++ b/num2words/lang_PL.py @@ -141,6 +141,10 @@ class Num2Word_PL(Num2Word_Base): i = len(chunks) for x in chunks: i -= 1 + + if x == 0: + continue + n1, n2, n3 = get_digits(x) if n3 > 0: @@ -154,7 +158,7 @@ class Num2Word_PL(Num2Word_Base): elif n1 > 0 and not (i > 0 and x == 1): words.append(ONES[n1][0]) - if x > 0 and i > 0: + if i > 0: words.append(self.pluralize(x, THOUSANDS[i])) return ' '.join(words) diff --git a/num2words/lang_RU.py b/num2words/lang_RU.py index a204487..032ddcf 100644 --- a/num2words/lang_RU.py +++ b/num2words/lang_RU.py @@ -209,6 +209,10 @@ class Num2Word_RU(Num2Word_Base): i = len(chunks) for x in chunks: i -= 1 + + if x == 0: + continue + n1, n2, n3 = get_digits(x) if n3 > 0: @@ -223,7 +227,7 @@ class Num2Word_RU(Num2Word_Base): ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES words.append(ones[n1][0]) - if x > 0 and i > 0: + if i > 0: words.append(self.pluralize(x, THOUSANDS[i])) return ' '.join(words) diff --git a/num2words/lang_UK.py b/num2words/lang_UK.py index e9a0a20..9672a88 100644 --- a/num2words/lang_UK.py +++ b/num2words/lang_UK.py @@ -147,6 +147,10 @@ class Num2Word_UK(Num2Word_Base): i = len(chunks) for x in chunks: i -= 1 + + if x == 0: + continue + n1, n2, n3 = get_digits(x) if n3 > 0: @@ -162,7 +166,7 @@ class Num2Word_UK(Num2Word_Base): ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES words.append(ones[n1][0]) - if x > 0 and i > 0: + if i > 0: words.append(self.pluralize(x, THOUSANDS[i])) return ' '.join(words) diff --git a/tests/test_lt.py b/tests/test_lt.py index 3424548..81e8938 100644 --- a/tests/test_lt.py +++ b/tests/test_lt.py @@ -53,9 +53,6 @@ class Num2WordsLTTest(TestCase): 'minus penki tūkstančiai kablelis dvidešimt du', ) - # print(fill(n2w(1000000000000000000000000000000))) - # naintilijonas - def test_to_ordinal(self): # @TODO: implement to_ordinal with self.assertRaises(NotImplementedError): diff --git a/tests/test_lv.py b/tests/test_lv.py index df3b679..ef265c0 100644 --- a/tests/test_lv.py +++ b/tests/test_lv.py @@ -48,9 +48,6 @@ class Num2WordsLVTest(TestCase): 'mīnus pieci tūkstoši komats divdesmit divi', ) - # >>> print(fill(n2w(1000000000000000000000000000000))) - # nontiljons - self.assertEqual(num2words(0, lang='lv'), 'nulle') self.assertEqual(num2words(5, lang='lv'), "pieci") self.assertEqual(num2words(15, lang='lv'), "piecpadsmit") From 9bd1bebb0eb3ea02be6181028aeeb0a795d891ff Mon Sep 17 00:00:00 2001 From: Marek Madejski Date: Wed, 5 Dec 2018 10:40:43 +0100 Subject: [PATCH 14/23] Shortened one test number for PEP8 compliance - smaller number parts are already tested. --- tests/test_pl.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/test_pl.py b/tests/test_pl.py index 48e7e2c..9be1314 100644 --- a/tests/test_pl.py +++ b/tests/test_pl.py @@ -70,19 +70,15 @@ class Num2WordsPLTest(TestCase): ) self.assertEqual( num2words( - 963301000001918264129471042047146102350812074235000101020000120324, + 963301000001918264129471001047146102 * 10**30 + 1007, lang='pl' ), "dziewięćset sześćdziesiąt trzy decyliardy trzysta jeden " "decylionów nonylion dziewięćset osiemnaście oktyliardów dwieście " "sześćdziesiąt cztery oktyliony sto dwadzieścia dziewięć " "septyliardów czterysta siedemdziesiąt jeden septylionów " - "czterdzieści dwa sekstyliardy czterdzieści siedem sekstylionów " - "sto czterdzieści sześć kwintyliardów sto dwa kwintyliony trzysta " - "pięćdziesiąt kwadryliardów osiemset dwanaście kwadrylionów " - "siedemdziesiąt cztery tryliardy dwieście trzydzieści pięć " - "trylionów sto jeden bilionów dwadzieścia miliardów sto " - "dwadzieścia tysięcy trzysta dwadzieścia cztery" + "sekstyliard czterdzieści siedem sekstylionów sto czterdzieści " + "sześć kwintyliardów sto dwa kwintyliony tysiąc siedem" ) def test_to_ordinal(self): From 53b4518afb534b94b608dc046f4f198856f7e8d1 Mon Sep 17 00:00:00 2001 From: Ernesto Rodriguez Ortiz Date: Wed, 5 Dec 2018 09:43:45 -0500 Subject: [PATCH 15/23] Issue 229: Add explicit encoding, license and unix line separators. Some maintainers for different linux distribution are having some problems with the encoding on different python versions. This change intents to make all python files define explicitly the encoding, license and unix line separators. Remove one example of the README.rst file where a possible non UTF-8 character is used. --- README.rst | 2 - bin/num2words | 20 +- docker-compose.yml | 7 + num2words/__init__.py | 1 + num2words/base.py | 1 + num2words/compat.py | 3 +- num2words/currency.py | 17 ++ num2words/lang_CZ.py | 3 +- num2words/lang_DK.py | 1 + num2words/lang_EN.py | 1 + num2words/lang_EN_IN.py | 1 + num2words/lang_ES.py | 3 +- num2words/lang_ES_CO.py | 3 +- num2words/lang_ES_VE.py | 3 +- num2words/lang_EU.py | 2 +- num2words/lang_FR.py | 2 +- num2words/lang_FR_BE.py | 2 +- num2words/lang_FR_CH.py | 3 +- num2words/lang_FR_DZ.py | 1 + num2words/lang_HE.py | 300 +++++++++++++------------- num2words/lang_ID.py | 1 + num2words/lang_IT.py | 6 +- num2words/lang_LT.py | 358 +++++++++++++++--------------- num2words/lang_LV.py | 372 ++++++++++++++++---------------- num2words/lang_NO.py | 1 + num2words/lang_PL.py | 329 ++++++++++++++-------------- num2words/lang_PT.py | 1 - num2words/lang_PT_BR.py | 2 - num2words/lang_RO.py | 2 +- num2words/lang_RU.py | 467 ++++++++++++++++++++-------------------- num2words/lang_SL.py | 2 - num2words/lang_SR.py | 3 +- num2words/lang_TH.py | 367 ++++++++++++++++--------------- num2words/lang_TR.py | 2 +- num2words/lang_UK.py | 357 +++++++++++++++--------------- num2words/utils.py | 52 +++-- setup.py | 24 ++- tests/test_ar.py | 4 +- tests/test_base.py | 17 ++ tests/test_cli.py | 15 ++ tests/test_currency.py | 17 ++ tests/test_cz.py | 5 +- tests/test_de.py | 5 +- tests/test_en.py | 2 + tests/test_en_in.py | 2 + tests/test_es.py | 4 +- tests/test_es_co.py | 3 +- tests/test_es_ve.py | 4 +- tests/test_fi.py | 1 + tests/test_fr.py | 22 +- tests/test_fr_be.py | 6 +- tests/test_fr_ch.py | 5 +- tests/test_fr_dz.py | 5 +- tests/test_id.py | 2 + tests/test_it.py | 5 +- tests/test_ja.py | 1 + tests/test_ko.py | 1 + tests/test_lt.py | 18 +- tests/test_lv.py | 18 +- tests/test_nl.py | 5 +- tests/test_pl.py | 5 +- tests/test_pt.py | 5 +- tests/test_pt_BR.py | 5 +- tests/test_ro.py | 3 +- tests/test_ru.py | 4 +- tests/test_sl.py | 5 +- tests/test_sr.py | 4 +- tests/test_th.py | 401 +++++++++++++++++----------------- tests/test_tr.py | 4 +- tests/test_uk.py | 4 +- tests/test_utils.py | 65 +++--- tests/test_vi.py | 5 +- 72 files changed, 1810 insertions(+), 1589 deletions(-) create mode 100644 docker-compose.yml diff --git a/README.rst b/README.rst index d9f4cd2..8e509c1 100644 --- a/README.rst +++ b/README.rst @@ -46,8 +46,6 @@ Command line:: $ num2words 10001 ten thousand and one - $ num2words 10123123 --lang es - diez millones ciento veintitrés mil ciento veintitrés $ num2words 24,120.10 twenty-four thousand, one hundred and twenty point one $ num2words 24,120.10 -l es diff --git a/bin/num2words b/bin/num2words index e5268ad..18e70a3 100755 --- a/bin/num2words +++ b/bin/num2words @@ -1,5 +1,21 @@ #!/usr/bin/env python # -*- 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 + """num2words: convert numbers into words. Usage: @@ -22,9 +38,6 @@ Options: Examples: $ num2words 10001 ten thousand and one - - $ num2words 10123123 --lang es - diez millones ciento veintitrés mil ciento veintitrés $ num2words 24,120.10 twenty-four thousand, one hundred and twenty point one @@ -35,6 +48,7 @@ Examples: $num2words 2.14 -l es --to currency dos euros con catorce centimos """ + from __future__ import print_function, unicode_literals import os import sys diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d2b033f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,7 @@ +version: '3.0' +services: + web: + image: python:3-alpine + command: python3 -m http.server 8080 + volumes: + - .:/num2words diff --git a/num2words/__init__.py b/num2words/__init__.py index 2db3100..ac84888 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. diff --git a/num2words/base.py b/num2words/base.py index 3b990e3..4397381 100644 --- a/num2words/base.py +++ b/num2words/base.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. diff --git a/num2words/compat.py b/num2words/compat.py index 56c594b..321cd2e 100644 --- a/num2words/compat.py +++ b/num2words/compat.py @@ -1,5 +1,6 @@ +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. -# Copyright (c) 2016, Savoir-faire Linux inc. 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 diff --git a/num2words/currency.py b/num2words/currency.py index 8b49fe0..4982251 100644 --- a/num2words/currency.py +++ b/num2words/currency.py @@ -1,3 +1,20 @@ +# -*- 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 from decimal import ROUND_HALF_UP, Decimal diff --git a/num2words/lang_CZ.py b/num2words/lang_CZ.py index 7cfa1f6..548c48b 100644 --- a/num2words/lang_CZ.py +++ b/num2words/lang_CZ.py @@ -1,4 +1,4 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. @@ -14,6 +14,7 @@ # 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 .base import Num2Word_Base diff --git a/num2words/lang_DK.py b/num2words/lang_DK.py index c1a8bb3..1a09094 100644 --- a/num2words/lang_DK.py +++ b/num2words/lang_DK.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. diff --git a/num2words/lang_EN.py b/num2words/lang_EN.py index fe7a92a..87ce02e 100644 --- a/num2words/lang_EN.py +++ b/num2words/lang_EN.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. diff --git a/num2words/lang_EN_IN.py b/num2words/lang_EN_IN.py index 5911805..3ef55ba 100644 --- a/num2words/lang_EN_IN.py +++ b/num2words/lang_EN_IN.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. diff --git a/num2words/lang_ES.py b/num2words/lang_ES.py index d370f91..482a414 100644 --- a/num2words/lang_ES.py +++ b/num2words/lang_ES.py @@ -1,5 +1,4 @@ -# encoding: UTF-8 - +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. diff --git a/num2words/lang_ES_CO.py b/num2words/lang_ES_CO.py index 6ed0a4b..955ac7e 100644 --- a/num2words/lang_ES_CO.py +++ b/num2words/lang_ES_CO.py @@ -1,5 +1,4 @@ -# encoding: UTF-8 - +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. diff --git a/num2words/lang_ES_VE.py b/num2words/lang_ES_VE.py index bb93b87..54100a0 100644 --- a/num2words/lang_ES_VE.py +++ b/num2words/lang_ES_VE.py @@ -1,5 +1,4 @@ -# encoding: UTF-8 - +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. diff --git a/num2words/lang_EU.py b/num2words/lang_EU.py index c0af59a..4a301af 100644 --- a/num2words/lang_EU.py +++ b/num2words/lang_EU.py @@ -1,4 +1,4 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. diff --git a/num2words/lang_FR.py b/num2words/lang_FR.py index 5eff2db..4524cb5 100644 --- a/num2words/lang_FR.py +++ b/num2words/lang_FR.py @@ -1,4 +1,4 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. diff --git a/num2words/lang_FR_BE.py b/num2words/lang_FR_BE.py index 5c73a0e..9083c2a 100644 --- a/num2words/lang_FR_BE.py +++ b/num2words/lang_FR_BE.py @@ -1,4 +1,4 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. diff --git a/num2words/lang_FR_CH.py b/num2words/lang_FR_CH.py index 1058946..da150db 100644 --- a/num2words/lang_FR_CH.py +++ b/num2words/lang_FR_CH.py @@ -1,4 +1,4 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. @@ -14,7 +14,6 @@ # 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_FR import Num2Word_FR diff --git a/num2words/lang_FR_DZ.py b/num2words/lang_FR_DZ.py index 0473c73..928520e 100644 --- a/num2words/lang_FR_DZ.py +++ b/num2words/lang_FR_DZ.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. diff --git a/num2words/lang_HE.py b/num2words/lang_HE.py index 1c59e1e..d98a84a 100644 --- a/num2words/lang_HE.py +++ b/num2words/lang_HE.py @@ -1,150 +1,150 @@ -# -*- encoding: 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 print_function, unicode_literals - -from .utils import get_digits, splitbyx - -ZERO = (u'אפס',) - -ONES = { - 1: (u'אחד',), - 2: (u'שנים',), - 3: (u'שלש',), - 4: (u'ארבע',), - 5: (u'חמש',), - 6: (u'שש',), - 7: (u'שבע',), - 8: (u'שמנה',), - 9: (u'תשע',), -} - -TENS = { - 0: (u'עשר',), - 1: (u'אחד עשרה',), - 2: (u'שנים עשרה',), - 3: (u'שלש עשרה',), - 4: (u'ארבע עשרה',), - 5: (u'חמש עשרה',), - 6: (u'שש עשרה',), - 7: (u'שבע עשרה',), - 8: (u'שמנה עשרה',), - 9: (u'תשע עשרה',), -} - -TWENTIES = { - 2: (u'עשרים',), - 3: (u'שלשים',), - 4: (u'ארבעים',), - 5: (u'חמישים',), - 6: (u'ששים',), - 7: (u'שבעים',), - 8: (u'שמנים',), - 9: (u'תשעים',), -} - -HUNDRED = { - 1: (u'מאה',), - 2: (u'מאתיים',), - 3: (u'מאות',) -} - -THOUSANDS = { - 1: (u'אלף',), - 2: (u'אלפיים',), -} - -AND = u'ו' - - -def pluralize(n, forms): - # gettext implementation: - # (n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2) - - form = 0 if (n % 10 == 1 and n % 100 != 11) else 1 if n != 0 else 2 - - return forms[form] - - -def int2word(n): - if n > 9999: # doesn't yet work for numbers this big - raise NotImplementedError() - - if n == 0: - return ZERO[0] - - words = [] - - chunks = list(splitbyx(str(n), 3)) - i = len(chunks) - for x in chunks: - i -= 1 - - if x == 0: - continue - - n1, n2, n3 = get_digits(x) - - if n3 > 0: - if n3 <= 2: - words.append(HUNDRED[n3][0]) - else: - words.append(ONES[n3][0]) - words.append(HUNDRED[3][0]) - - if n2 > 1: - words.append(TWENTIES[n2][0]) - - if n2 == 1: - words.append(TENS[n1][0]) - elif n1 > 0 and not (i > 0 and x == 1): - words.append(ONES[n1][0]) - - if i > 0: - if i <= 2: - words.append(THOUSANDS[i][0]) - else: - words.append(ONES[i][0]) - words.append(THOUSANDS[1][0]) - - if len(words) > 1: - words[-1] = AND + words[-1] - return ' '.join(words) - - -def n2w(n): - return int2word(int(n)) - - -def to_currency(n, currency='EUR', cents=True, seperator=','): - raise NotImplementedError() - - -class Num2Word_HE(object): - def to_cardinal(self, number): - return n2w(number) - - def to_ordinal(self, number): - raise NotImplementedError() - - -if __name__ == '__main__': - yo = Num2Word_HE() - nums = [1, 11, 21, 24, 99, 100, 101, 200, 211, 345, 1000, 1011] - for num in nums: - print(num, yo.to_cardinal(num)) +# -*- 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 print_function, unicode_literals + +from .utils import get_digits, splitbyx + +ZERO = (u'אפס',) + +ONES = { + 1: (u'אחד',), + 2: (u'שנים',), + 3: (u'שלש',), + 4: (u'ארבע',), + 5: (u'חמש',), + 6: (u'שש',), + 7: (u'שבע',), + 8: (u'שמנה',), + 9: (u'תשע',), +} + +TENS = { + 0: (u'עשר',), + 1: (u'אחד עשרה',), + 2: (u'שנים עשרה',), + 3: (u'שלש עשרה',), + 4: (u'ארבע עשרה',), + 5: (u'חמש עשרה',), + 6: (u'שש עשרה',), + 7: (u'שבע עשרה',), + 8: (u'שמנה עשרה',), + 9: (u'תשע עשרה',), +} + +TWENTIES = { + 2: (u'עשרים',), + 3: (u'שלשים',), + 4: (u'ארבעים',), + 5: (u'חמישים',), + 6: (u'ששים',), + 7: (u'שבעים',), + 8: (u'שמנים',), + 9: (u'תשעים',), +} + +HUNDRED = { + 1: (u'מאה',), + 2: (u'מאתיים',), + 3: (u'מאות',) +} + +THOUSANDS = { + 1: (u'אלף',), + 2: (u'אלפיים',), +} + +AND = u'ו' + + +def pluralize(n, forms): + # gettext implementation: + # (n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2) + + form = 0 if (n % 10 == 1 and n % 100 != 11) else 1 if n != 0 else 2 + + return forms[form] + + +def int2word(n): + if n > 9999: # doesn't yet work for numbers this big + raise NotImplementedError() + + if n == 0: + return ZERO[0] + + words = [] + + chunks = list(splitbyx(str(n), 3)) + i = len(chunks) + for x in chunks: + i -= 1 + + if x == 0: + continue + + n1, n2, n3 = get_digits(x) + + if n3 > 0: + if n3 <= 2: + words.append(HUNDRED[n3][0]) + else: + words.append(ONES[n3][0]) + words.append(HUNDRED[3][0]) + + if n2 > 1: + words.append(TWENTIES[n2][0]) + + if n2 == 1: + words.append(TENS[n1][0]) + elif n1 > 0 and not (i > 0 and x == 1): + words.append(ONES[n1][0]) + + if i > 0: + if i <= 2: + words.append(THOUSANDS[i][0]) + else: + words.append(ONES[i][0]) + words.append(THOUSANDS[1][0]) + + if len(words) > 1: + words[-1] = AND + words[-1] + return ' '.join(words) + + +def n2w(n): + return int2word(int(n)) + + +def to_currency(n, currency='EUR', cents=True, seperator=','): + raise NotImplementedError() + + +class Num2Word_HE(object): + def to_cardinal(self, number): + return n2w(number) + + def to_ordinal(self, number): + raise NotImplementedError() + + +if __name__ == '__main__': + yo = Num2Word_HE() + nums = [1, 11, 21, 24, 99, 100, 101, 200, 211, 345, 1000, 1011] + for num in nums: + print(num, yo.to_cardinal(num)) diff --git a/num2words/lang_ID.py b/num2words/lang_ID.py index 85c5f01..9a2bbfc 100644 --- a/num2words/lang_ID.py +++ b/num2words/lang_ID.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. diff --git a/num2words/lang_IT.py b/num2words/lang_IT.py index 3b223c3..f1eb023 100644 --- a/num2words/lang_IT.py +++ b/num2words/lang_IT.py @@ -1,5 +1,7 @@ -# -*- encoding: utf-8 -*- -# +# -*- 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 diff --git a/num2words/lang_LT.py b/num2words/lang_LT.py index 1d13824..8c6623e 100644 --- a/num2words/lang_LT.py +++ b/num2words/lang_LT.py @@ -1,179 +1,179 @@ -# -*- encoding: 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 -# TODO: replace WINDOWS line endings to UNIX? -from __future__ import unicode_literals - -from .base import Num2Word_Base -from .utils import get_digits, splitbyx - -ZERO = ('nulis',) - -ONES_FEMININE = { - 1: ('viena',), - 2: ('dvi',), - 3: ('trys',), - 4: ('keturios',), - 5: ('penkios',), - 6: ('šešios',), - 7: ('septynios',), - 8: ('aštuonios',), - 9: ('devynios',), -} - -ONES = { - 1: ('vienas',), - 2: ('du',), - 3: ('trys',), - 4: ('keturi',), - 5: ('penki',), - 6: ('šeši',), - 7: ('septyni',), - 8: ('aštuoni',), - 9: ('devyni',), -} - -TENS = { - 0: ('dešimt',), - 1: ('vienuolika',), - 2: ('dvylika',), - 3: ('trylika',), - 4: ('keturiolika',), - 5: ('penkiolika',), - 6: ('šešiolika',), - 7: ('septyniolika',), - 8: ('aštuoniolika',), - 9: ('devyniolika',), -} - -TWENTIES = { - 2: ('dvidešimt',), - 3: ('trisdešimt',), - 4: ('keturiasdešimt',), - 5: ('penkiasdešimt',), - 6: ('šešiasdešimt',), - 7: ('septyniasdešimt',), - 8: ('aštuoniasdešimt',), - 9: ('devyniasdešimt',), -} - -HUNDRED = ('šimtas', 'šimtai') - -THOUSANDS = { - 1: ('tūkstantis', 'tūkstančiai', 'tūkstančių'), - 2: ('milijonas', 'milijonai', 'milijonų'), - 3: ('milijardas', 'milijardai', 'milijardų'), - 4: ('trilijonas', 'trilijonai', 'trilijonų'), - 5: ('kvadrilijonas', 'kvadrilijonai', 'kvadrilijonų'), - 6: ('kvintilijonas', 'kvintilijonai', 'kvintilijonų'), - 7: ('sikstilijonas', 'sikstilijonai', 'sikstilijonų'), - 8: ('septilijonas', 'septilijonai', 'septilijonų'), - 9: ('oktilijonas', 'oktilijonai', 'oktilijonų'), - 10: ('naintilijonas', 'naintilijonai', 'naintilijonų'), -} - -GENERIC_CENTS = ('centas', 'centai', 'centų') - - -class Num2Word_LT(Num2Word_Base): - CURRENCY_FORMS = { - 'LTL': (('litas', 'litai', 'litų'), GENERIC_CENTS), - 'EUR': (('euras', 'eurai', 'eurų'), GENERIC_CENTS), - 'USD': (('doleris', 'doleriai', 'dolerių'), GENERIC_CENTS), - 'GBP': ( - ('svaras sterlingų', 'svarai sterlingų', 'svarų sterlingų'), - ('pensas', 'pensai', 'pensų') - ), - 'PLN': ( - ('zlotas', 'zlotai', 'zlotų'), - ('grašis', 'grašiai', 'grašių')), - 'RUB': ( - ('rublis', 'rubliai', 'rublių'), - ('kapeika', 'kapeikos', 'kapeikų') - ), - } - - def setup(self): - self.negword = "minus" - self.pointword = "kablelis" - - def pluralize(self, n, forms): - n1, n2, n3 = get_digits(n) - if n2 == 1 or n1 == 0 or n == 0: - return forms[2] - elif n1 == 1: - return forms[0] - else: - return forms[1] - - def to_cardinal(self, number): - n = str(number).replace(',', '.') - base_str, n = self.parse_minus(n) - if '.' in n: - left, right = n.split('.') - return '%s%s %s %s' % ( - base_str, - self._int2word(int(left)), - self.pointword, - self._int2word(int(right)) - ) - else: - return "%s%s" % (base_str, self._int2word(int(n))) - - def to_ordinal(self, number): - raise NotImplementedError() - - def _cents_verbose(self, number, currency): - return self._int2word(number, currency == 'RUB') - - def _int2word(self, n, feminine=False): - if n == 0: - return ZERO[0] - - words = [] - chunks = list(splitbyx(str(n), 3)) - i = len(chunks) - - for x in chunks: - i -= 1 - - if x == 0: - continue - - n1, n2, n3 = get_digits(x) - - if n3 > 0: - words.append(ONES[n3][0]) - if n3 > 1: - words.append(HUNDRED[1]) - else: - words.append(HUNDRED[0]) - - if n2 > 1: - words.append(TWENTIES[n2][0]) - - if n2 == 1: - words.append(TENS[n1][0]) - elif n1 > 0: - if (i == 1 or feminine and i == 0) and n < 1000: - words.append(ONES_FEMININE[n1][0]) - else: - words.append(ONES[n1][0]) - - if i > 0: - words.append(self.pluralize(x, THOUSANDS[i])) - - return ' '.join(words) +# -*- 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 unicode_literals + +from .base import Num2Word_Base +from .utils import get_digits, splitbyx + +ZERO = ('nulis',) + +ONES_FEMININE = { + 1: ('viena',), + 2: ('dvi',), + 3: ('trys',), + 4: ('keturios',), + 5: ('penkios',), + 6: ('šešios',), + 7: ('septynios',), + 8: ('aštuonios',), + 9: ('devynios',), +} + +ONES = { + 1: ('vienas',), + 2: ('du',), + 3: ('trys',), + 4: ('keturi',), + 5: ('penki',), + 6: ('šeši',), + 7: ('septyni',), + 8: ('aštuoni',), + 9: ('devyni',), +} + +TENS = { + 0: ('dešimt',), + 1: ('vienuolika',), + 2: ('dvylika',), + 3: ('trylika',), + 4: ('keturiolika',), + 5: ('penkiolika',), + 6: ('šešiolika',), + 7: ('septyniolika',), + 8: ('aštuoniolika',), + 9: ('devyniolika',), +} + +TWENTIES = { + 2: ('dvidešimt',), + 3: ('trisdešimt',), + 4: ('keturiasdešimt',), + 5: ('penkiasdešimt',), + 6: ('šešiasdešimt',), + 7: ('septyniasdešimt',), + 8: ('aštuoniasdešimt',), + 9: ('devyniasdešimt',), +} + +HUNDRED = ('šimtas', 'šimtai') + +THOUSANDS = { + 1: ('tūkstantis', 'tūkstančiai', 'tūkstančių'), + 2: ('milijonas', 'milijonai', 'milijonų'), + 3: ('milijardas', 'milijardai', 'milijardų'), + 4: ('trilijonas', 'trilijonai', 'trilijonų'), + 5: ('kvadrilijonas', 'kvadrilijonai', 'kvadrilijonų'), + 6: ('kvintilijonas', 'kvintilijonai', 'kvintilijonų'), + 7: ('sikstilijonas', 'sikstilijonai', 'sikstilijonų'), + 8: ('septilijonas', 'septilijonai', 'septilijonų'), + 9: ('oktilijonas', 'oktilijonai', 'oktilijonų'), + 10: ('naintilijonas', 'naintilijonai', 'naintilijonų'), +} + +GENERIC_CENTS = ('centas', 'centai', 'centų') + + +class Num2Word_LT(Num2Word_Base): + CURRENCY_FORMS = { + 'LTL': (('litas', 'litai', 'litų'), GENERIC_CENTS), + 'EUR': (('euras', 'eurai', 'eurų'), GENERIC_CENTS), + 'USD': (('doleris', 'doleriai', 'dolerių'), GENERIC_CENTS), + 'GBP': ( + ('svaras sterlingų', 'svarai sterlingų', 'svarų sterlingų'), + ('pensas', 'pensai', 'pensų') + ), + 'PLN': ( + ('zlotas', 'zlotai', 'zlotų'), + ('grašis', 'grašiai', 'grašių')), + 'RUB': ( + ('rublis', 'rubliai', 'rublių'), + ('kapeika', 'kapeikos', 'kapeikų') + ), + } + + def setup(self): + self.negword = "minus" + self.pointword = "kablelis" + + def pluralize(self, n, forms): + n1, n2, n3 = get_digits(n) + if n2 == 1 or n1 == 0 or n == 0: + return forms[2] + elif n1 == 1: + return forms[0] + else: + return forms[1] + + def to_cardinal(self, number): + n = str(number).replace(',', '.') + base_str, n = self.parse_minus(n) + if '.' in n: + left, right = n.split('.') + return '%s%s %s %s' % ( + base_str, + self._int2word(int(left)), + self.pointword, + self._int2word(int(right)) + ) + else: + return "%s%s" % (base_str, self._int2word(int(n))) + + def to_ordinal(self, number): + raise NotImplementedError() + + def _cents_verbose(self, number, currency): + return self._int2word(number, currency == 'RUB') + + def _int2word(self, n, feminine=False): + if n == 0: + return ZERO[0] + + words = [] + chunks = list(splitbyx(str(n), 3)) + i = len(chunks) + + for x in chunks: + i -= 1 + + if x == 0: + continue + + n1, n2, n3 = get_digits(x) + + if n3 > 0: + words.append(ONES[n3][0]) + if n3 > 1: + words.append(HUNDRED[1]) + else: + words.append(HUNDRED[0]) + + if n2 > 1: + words.append(TWENTIES[n2][0]) + + if n2 == 1: + words.append(TENS[n1][0]) + elif n1 > 0: + if (i == 1 or feminine and i == 0) and n < 1000: + words.append(ONES_FEMININE[n1][0]) + else: + words.append(ONES[n1][0]) + + if i > 0: + words.append(self.pluralize(x, THOUSANDS[i])) + + return ' '.join(words) diff --git a/num2words/lang_LV.py b/num2words/lang_LV.py index cd88472..289c37f 100644 --- a/num2words/lang_LV.py +++ b/num2words/lang_LV.py @@ -1,186 +1,186 @@ -# -*- encoding: 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 -# TODO: replace WINDOWS line endings to UNIX? -from __future__ import unicode_literals - -from .base import Num2Word_Base -from .utils import get_digits, splitbyx - -ZERO = ('nulle',) - -ONES = { - 1: ('viens',), - 2: ('divi',), - 3: ('trīs',), - 4: ('četri',), - 5: ('pieci',), - 6: ('seši',), - 7: ('septiņi',), - 8: ('astoņi',), - 9: ('deviņi',), -} - -TENS = { - 0: ('desmit',), - 1: ('vienpadsmit',), - 2: ('divpadsmit',), - 3: ('trīspadsmit',), - 4: ('četrpadsmit',), - 5: ('piecpadsmit',), - 6: ('sešpadsmit',), - 7: ('septiņpadsmit',), - 8: ('astoņpadsmit',), - 9: ('deviņpadsmit',), -} - -TWENTIES = { - 2: ('divdesmit',), - 3: ('trīsdesmit',), - 4: ('četrdesmit',), - 5: ('piecdesmit',), - 6: ('sešdesmit',), - 7: ('septiņdesmit',), - 8: ('astoņdesmit',), - 9: ('deviņdesmit',), -} - -HUNDRED = ('simts', 'simti', 'simtu') - -THOUSANDS = { - 1: ('tūkstotis', 'tūkstoši', 'tūkstošu'), - 2: ('miljons', 'miljoni', 'miljonu'), - 3: ('miljards', 'miljardi', 'miljardu'), - 4: ('triljons', 'triljoni', 'triljonu'), - 5: ('kvadriljons', 'kvadriljoni', 'kvadriljonu'), - 6: ('kvintiljons', 'kvintiljoni', 'kvintiljonu'), - 7: ('sikstiljons', 'sikstiljoni', 'sikstiljonu'), - 8: ('septiljons', 'septiljoni', 'septiljonu'), - 9: ('oktiljons', 'oktiljoni', 'oktiljonu'), - 10: ('nontiljons', 'nontiljoni', 'nontiljonu'), -} - -GENERIC_DOLLARS = ('dolārs', 'dolāri', 'dolāru') -GENERIC_CENTS = ('cents', 'centi', 'centu') - -GENERIC_KRONA = ('krona', 'kronas', 'kronu') -GENERIC_ERA = ('ēre', 'ēras', 'ēru') - - -class Num2Word_LV(Num2Word_Base): - """ - Sadly we have a legal form (used in legal and finance documents): - http://www.eiro.lv/files/upload/files/Eiro_rakstiba-1.pdf - https://likumi.lv/doc.php?id=254741 - http://eur-lex.europa.eu/legal-content/LV/TXT/HTML/?uri=CELEX:31998R0974&from=LV - - Source: http://publications.europa.eu/code/lv/lv-5000500.htm - """ - CURRENCY_FORMS = { - 'AUD': (GENERIC_DOLLARS, GENERIC_CENTS), - 'CAD': (GENERIC_DOLLARS, GENERIC_CENTS), - # repalced by EUR - 'EEK': (GENERIC_KRONA, GENERIC_CENTS), - 'EUR': (('eiro', 'eiro', 'eiro'), GENERIC_CENTS), - 'EUR_LEGAL': (('euro', 'euro', 'euro'), GENERIC_CENTS), - 'GBP': ( - ('sterliņu mārciņa', 'sterliņu mārciņas', 'sterliņu mārciņu'), - ('penss', 'pensi', 'pensu')), - # replaced by EUR - 'LTL': (('lits', 'liti', 'litu'), GENERIC_CENTS), - # replaced by EUR - 'LVL': (('lats', 'lati', 'latu'), - ('santīms', 'santīmi', 'santīmu')), - 'USD': (GENERIC_DOLLARS, GENERIC_CENTS), - 'RUB': (('rublis', 'rubļi', 'rubļu'), - ('kapeika', 'kapeikas', 'kapeiku')), - 'SEK': (GENERIC_KRONA, GENERIC_ERA), - 'NOK': (GENERIC_KRONA, GENERIC_ERA), - 'PLN': (('zlots', 'zloti', 'zlotu'), - ('grasis', 'graši', 'grašu')), - } - - CURRENCY_ADJECTIVES = { - 'AUD': 'Austrālijas', - 'CAD': 'Kanādas', - 'EEK': 'Igaunijas', - 'USD': 'ASV', - 'RUB': 'Kreivijas', - 'SEK': 'Zviedrijas', - 'NOK': 'Norvēģijas', - } - - def setup(self): - self.negword = "mīnus" - self.pointword = "komats" - - def to_cardinal(self, number): - n = str(number).replace(',', '.') - base_str, n = self.parse_minus(n) - if '.' in n: - left, right = n.split('.') - return '%s%s %s %s' % ( - base_str, - self._int2word(int(left)), - self.pointword, - self._int2word(int(right)) - ) - else: - return "%s%s" % (base_str, self._int2word(int(n))) - - def pluralize(self, n, forms): - form = 0 if (n % 10 == 1 and n % 100 != 11) else 1 if n != 0 else 2 - return forms[form] - - def to_ordinal(self, number): - raise NotImplementedError() - - def _int2word(self, n): - if n == 0: - return ZERO[0] - - words = [] - chunks = list(splitbyx(str(n), 3)) - i = len(chunks) - for x in chunks: - i -= 1 - - if x == 0: - continue - - n1, n2, n3 = get_digits(x) - - if n3 > 0: - if n3 == 1 and n2 == 0 and n1 > 0: - words.append(HUNDRED[2]) - elif n3 > 1: - words.append(ONES[n3][0]) - words.append(HUNDRED[1]) - else: - words.append(HUNDRED[0]) - - if n2 > 1: - words.append(TWENTIES[n2][0]) - - if n2 == 1: - words.append(TENS[n1][0]) - elif n1 > 0 and not (i > 0 and x == 1): - words.append(ONES[n1][0]) - - if i > 0: - words.append(self.pluralize(x, THOUSANDS[i])) - - return ' '.join(words) +# -*- 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 unicode_literals + +from .base import Num2Word_Base +from .utils import get_digits, splitbyx + +ZERO = ('nulle',) + +ONES = { + 1: ('viens',), + 2: ('divi',), + 3: ('trīs',), + 4: ('četri',), + 5: ('pieci',), + 6: ('seši',), + 7: ('septiņi',), + 8: ('astoņi',), + 9: ('deviņi',), +} + +TENS = { + 0: ('desmit',), + 1: ('vienpadsmit',), + 2: ('divpadsmit',), + 3: ('trīspadsmit',), + 4: ('četrpadsmit',), + 5: ('piecpadsmit',), + 6: ('sešpadsmit',), + 7: ('septiņpadsmit',), + 8: ('astoņpadsmit',), + 9: ('deviņpadsmit',), +} + +TWENTIES = { + 2: ('divdesmit',), + 3: ('trīsdesmit',), + 4: ('četrdesmit',), + 5: ('piecdesmit',), + 6: ('sešdesmit',), + 7: ('septiņdesmit',), + 8: ('astoņdesmit',), + 9: ('deviņdesmit',), +} + +HUNDRED = ('simts', 'simti', 'simtu') + +THOUSANDS = { + 1: ('tūkstotis', 'tūkstoši', 'tūkstošu'), + 2: ('miljons', 'miljoni', 'miljonu'), + 3: ('miljards', 'miljardi', 'miljardu'), + 4: ('triljons', 'triljoni', 'triljonu'), + 5: ('kvadriljons', 'kvadriljoni', 'kvadriljonu'), + 6: ('kvintiljons', 'kvintiljoni', 'kvintiljonu'), + 7: ('sikstiljons', 'sikstiljoni', 'sikstiljonu'), + 8: ('septiljons', 'septiljoni', 'septiljonu'), + 9: ('oktiljons', 'oktiljoni', 'oktiljonu'), + 10: ('nontiljons', 'nontiljoni', 'nontiljonu'), +} + +GENERIC_DOLLARS = ('dolārs', 'dolāri', 'dolāru') +GENERIC_CENTS = ('cents', 'centi', 'centu') + +GENERIC_KRONA = ('krona', 'kronas', 'kronu') +GENERIC_ERA = ('ēre', 'ēras', 'ēru') + + +class Num2Word_LV(Num2Word_Base): + """ + Sadly we have a legal form (used in legal and finance documents): + http://www.eiro.lv/files/upload/files/Eiro_rakstiba-1.pdf + https://likumi.lv/doc.php?id=254741 + http://eur-lex.europa.eu/legal-content/LV/TXT/HTML/?uri=CELEX:31998R0974&from=LV + + Source: http://publications.europa.eu/code/lv/lv-5000500.htm + """ + CURRENCY_FORMS = { + 'AUD': (GENERIC_DOLLARS, GENERIC_CENTS), + 'CAD': (GENERIC_DOLLARS, GENERIC_CENTS), + # repalced by EUR + 'EEK': (GENERIC_KRONA, GENERIC_CENTS), + 'EUR': (('eiro', 'eiro', 'eiro'), GENERIC_CENTS), + 'EUR_LEGAL': (('euro', 'euro', 'euro'), GENERIC_CENTS), + 'GBP': ( + ('sterliņu mārciņa', 'sterliņu mārciņas', 'sterliņu mārciņu'), + ('penss', 'pensi', 'pensu')), + # replaced by EUR + 'LTL': (('lits', 'liti', 'litu'), GENERIC_CENTS), + # replaced by EUR + 'LVL': (('lats', 'lati', 'latu'), + ('santīms', 'santīmi', 'santīmu')), + 'USD': (GENERIC_DOLLARS, GENERIC_CENTS), + 'RUB': (('rublis', 'rubļi', 'rubļu'), + ('kapeika', 'kapeikas', 'kapeiku')), + 'SEK': (GENERIC_KRONA, GENERIC_ERA), + 'NOK': (GENERIC_KRONA, GENERIC_ERA), + 'PLN': (('zlots', 'zloti', 'zlotu'), + ('grasis', 'graši', 'grašu')), + } + + CURRENCY_ADJECTIVES = { + 'AUD': 'Austrālijas', + 'CAD': 'Kanādas', + 'EEK': 'Igaunijas', + 'USD': 'ASV', + 'RUB': 'Kreivijas', + 'SEK': 'Zviedrijas', + 'NOK': 'Norvēģijas', + } + + def setup(self): + self.negword = "mīnus" + self.pointword = "komats" + + def to_cardinal(self, number): + n = str(number).replace(',', '.') + base_str, n = self.parse_minus(n) + if '.' in n: + left, right = n.split('.') + return '%s%s %s %s' % ( + base_str, + self._int2word(int(left)), + self.pointword, + self._int2word(int(right)) + ) + else: + return "%s%s" % (base_str, self._int2word(int(n))) + + def pluralize(self, n, forms): + form = 0 if (n % 10 == 1 and n % 100 != 11) else 1 if n != 0 else 2 + return forms[form] + + def to_ordinal(self, number): + raise NotImplementedError() + + def _int2word(self, n): + if n == 0: + return ZERO[0] + + words = [] + chunks = list(splitbyx(str(n), 3)) + i = len(chunks) + for x in chunks: + i -= 1 + + if x == 0: + continue + + n1, n2, n3 = get_digits(x) + + if n3 > 0: + if n3 == 1 and n2 == 0 and n1 > 0: + words.append(HUNDRED[2]) + elif n3 > 1: + words.append(ONES[n3][0]) + words.append(HUNDRED[1]) + else: + words.append(HUNDRED[0]) + + if n2 > 1: + words.append(TWENTIES[n2][0]) + + if n2 == 1: + words.append(TENS[n1][0]) + elif n1 > 0 and not (i > 0 and x == 1): + words.append(ONES[n1][0]) + + if i > 0: + words.append(self.pluralize(x, THOUSANDS[i])) + + return ' '.join(words) diff --git a/num2words/lang_NO.py b/num2words/lang_NO.py index 5f252f4..0fb43e4 100644 --- a/num2words/lang_NO.py +++ b/num2words/lang_NO.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. diff --git a/num2words/lang_PL.py b/num2words/lang_PL.py index 34249cc..92da65d 100644 --- a/num2words/lang_PL.py +++ b/num2words/lang_PL.py @@ -1,164 +1,165 @@ -# -*- encoding: 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 unicode_literals - -from .base import Num2Word_Base -from .utils import get_digits, splitbyx - -ZERO = ('zero',) - -ONES = { - 1: ('jeden',), - 2: ('dwa',), - 3: ('trzy',), - 4: ('cztery',), - 5: ('pięć',), - 6: ('sześć',), - 7: ('siedem',), - 8: ('osiem',), - 9: ('dziewięć',), -} - -TENS = { - 0: ('dziesięć',), - 1: ('jedenaście',), - 2: ('dwanaście',), - 3: ('trzynaście',), - 4: ('czternaście',), - 5: ('piętnaście',), - 6: ('szesnaście',), - 7: ('siedemnaście',), - 8: ('osiemnaście',), - 9: ('dziewiętnaście',), -} - -TWENTIES = { - 2: ('dwadzieścia',), - 3: ('trzydzieści',), - 4: ('czterdzieści',), - 5: ('pięćdziesiąt',), - 6: ('sześćdziesiąt',), - 7: ('siedemdziesiąt',), - 8: ('osiemdziesiąt',), - 9: ('dziewięćdzisiąt',), -} - -HUNDREDS = { - 1: ('sto',), - 2: ('dwieście',), - 3: ('trzysta',), - 4: ('czterysta',), - 5: ('pięćset',), - 6: ('sześćset',), - 7: ('siedemset',), - 8: ('osiemset',), - 9: ('dziewięćset',), -} - -THOUSANDS = { - 1: ('tysiąc', 'tysiące', 'tysięcy'), # 10^3 - 2: ('milion', 'miliony', 'milionów'), # 10^6 - 3: ('miliard', 'miliardy', 'miliardów'), # 10^9 - 4: ('bilion', 'biliony', 'bilionów'), # 10^12 - 5: ('biliard', 'biliardy', 'biliardów'), # 10^15 - 6: ('trylion', 'tryliony', 'trylionów'), # 10^18 - 7: ('tryliard', 'tryliardy', 'tryliardów'), # 10^21 - 8: ('kwadrylion', 'kwadryliony', 'kwadrylionów'), # 10^24 - 9: ('kwadryliard', 'kwadryliardy', 'kwadryliardów'), # 10^27 - 10: ('kwintylion', 'kwintyliony', 'kwintylionów'), # 10^30 - 11: ('kwintyliard', 'kwintyliardy', 'kwintyliardów'), # 10^33 - 12: ('sekstylion', 'sekstyliony', 'sekstylionów'), # 10^36 - 13: ('sekstyliard', 'sekstyliardy', 'sekstyliardów'), # 10^39 - 14: ('septylion', 'septyliony', 'septylionów'), # 10^42 - 15: ('septyliard', 'septyliardy', 'septyliardów'), # 10^45 - 16: ('oktylion', 'oktyliony', 'oktylionów'), # 10^48 - 17: ('oktyliard', 'oktyliardy', 'oktyliardów'), # 10^51 - 18: ('nonylion', 'nonyliony', 'nonylionów'), # 10^54 - 19: ('nonyliard', 'nonyliardy', 'nonyliardów'), # 10^57 - 20: ('decylion', 'decyliony', 'decylionów'), # 10^60 - 21: ('decyliard', 'decyliardy', 'decyliardów'), # 10^63 -} - - -class Num2Word_PL(Num2Word_Base): - CURRENCY_FORMS = { - 'PLN': ( - ('złoty', 'złote', 'złotych'), ('grosz', 'grosze', 'groszy') - ), - 'EUR': ( - ('euro', 'euro', 'euro'), ('cent', 'centy', 'centów') - ), - } - - def setup(self): - self.negword = "minus" - self.pointword = "przecinek" - - def to_cardinal(self, number): - n = str(number).replace(',', '.') - if '.' in n: - left, right = n.split('.') - return u'%s %s %s' % ( - self._int2word(int(left)), - self.pointword, - self._int2word(int(right)) - ) - else: - return self._int2word(int(n)) - - def pluralize(self, n, forms): - if n == 1: - form = 0 - elif 5 > n % 10 > 1 and (n % 100 < 10 or n % 100 > 20): - form = 1 - else: - form = 2 - return forms[form] - - def to_ordinal(self, number): - raise NotImplementedError() - - def _int2word(self, n): - if n == 0: - return ZERO[0] - - words = [] - chunks = list(splitbyx(str(n), 3)) - i = len(chunks) - for x in chunks: - i -= 1 - - if x == 0: - continue - - n1, n2, n3 = get_digits(x) - - if n3 > 0: - words.append(HUNDREDS[n3][0]) - - if n2 > 1: - words.append(TWENTIES[n2][0]) - - if n2 == 1: - words.append(TENS[n1][0]) - elif n1 > 0 and not (i > 0 and x == 1): - words.append(ONES[n1][0]) - - if i > 0: - words.append(self.pluralize(x, THOUSANDS[i])) - - return ' '.join(words) +# -*- 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 unicode_literals + +from .base import Num2Word_Base +from .utils import get_digits, splitbyx + +ZERO = ('zero',) + +ONES = { + 1: ('jeden',), + 2: ('dwa',), + 3: ('trzy',), + 4: ('cztery',), + 5: ('pięć',), + 6: ('sześć',), + 7: ('siedem',), + 8: ('osiem',), + 9: ('dziewięć',), +} + +TENS = { + 0: ('dziesięć',), + 1: ('jedenaście',), + 2: ('dwanaście',), + 3: ('trzynaście',), + 4: ('czternaście',), + 5: ('piętnaście',), + 6: ('szesnaście',), + 7: ('siedemnaście',), + 8: ('osiemnaście',), + 9: ('dziewiętnaście',), +} + +TWENTIES = { + 2: ('dwadzieścia',), + 3: ('trzydzieści',), + 4: ('czterdzieści',), + 5: ('pięćdziesiąt',), + 6: ('sześćdziesiąt',), + 7: ('siedemdziesiąt',), + 8: ('osiemdziesiąt',), + 9: ('dziewięćdzisiąt',), +} + +HUNDREDS = { + 1: ('sto',), + 2: ('dwieście',), + 3: ('trzysta',), + 4: ('czterysta',), + 5: ('pięćset',), + 6: ('sześćset',), + 7: ('siedemset',), + 8: ('osiemset',), + 9: ('dziewięćset',), +} + +THOUSANDS = { + 1: ('tysiąc', 'tysiące', 'tysięcy'), # 10^3 + 2: ('milion', 'miliony', 'milionów'), # 10^6 + 3: ('miliard', 'miliardy', 'miliardów'), # 10^9 + 4: ('bilion', 'biliony', 'bilionów'), # 10^12 + 5: ('biliard', 'biliardy', 'biliardów'), # 10^15 + 6: ('trylion', 'tryliony', 'trylionów'), # 10^18 + 7: ('tryliard', 'tryliardy', 'tryliardów'), # 10^21 + 8: ('kwadrylion', 'kwadryliony', 'kwadrylionów'), # 10^24 + 9: ('kwadryliard', 'kwadryliardy', 'kwadryliardów'), # 10^27 + 10: ('kwintylion', 'kwintyliony', 'kwintylionów'), # 10^30 + 11: ('kwintyliard', 'kwintyliardy', 'kwintyliardów'), # 10^33 + 12: ('sekstylion', 'sekstyliony', 'sekstylionów'), # 10^36 + 13: ('sekstyliard', 'sekstyliardy', 'sekstyliardów'), # 10^39 + 14: ('septylion', 'septyliony', 'septylionów'), # 10^42 + 15: ('septyliard', 'septyliardy', 'septyliardów'), # 10^45 + 16: ('oktylion', 'oktyliony', 'oktylionów'), # 10^48 + 17: ('oktyliard', 'oktyliardy', 'oktyliardów'), # 10^51 + 18: ('nonylion', 'nonyliony', 'nonylionów'), # 10^54 + 19: ('nonyliard', 'nonyliardy', 'nonyliardów'), # 10^57 + 20: ('decylion', 'decyliony', 'decylionów'), # 10^60 + 21: ('decyliard', 'decyliardy', 'decyliardów'), # 10^63 +} + + +class Num2Word_PL(Num2Word_Base): + CURRENCY_FORMS = { + 'PLN': ( + ('złoty', 'złote', 'złotych'), ('grosz', 'grosze', 'groszy') + ), + 'EUR': ( + ('euro', 'euro', 'euro'), ('cent', 'centy', 'centów') + ), + } + + def setup(self): + self.negword = "minus" + self.pointword = "przecinek" + + def to_cardinal(self, number): + n = str(number).replace(',', '.') + if '.' in n: + left, right = n.split('.') + return u'%s %s %s' % ( + self._int2word(int(left)), + self.pointword, + self._int2word(int(right)) + ) + else: + return self._int2word(int(n)) + + def pluralize(self, n, forms): + if n == 1: + form = 0 + elif 5 > n % 10 > 1 and (n % 100 < 10 or n % 100 > 20): + form = 1 + else: + form = 2 + return forms[form] + + def to_ordinal(self, number): + raise NotImplementedError() + + def _int2word(self, n): + if n == 0: + return ZERO[0] + + words = [] + chunks = list(splitbyx(str(n), 3)) + i = len(chunks) + for x in chunks: + i -= 1 + + if x == 0: + continue + + n1, n2, n3 = get_digits(x) + + if n3 > 0: + words.append(HUNDREDS[n3][0]) + + if n2 > 1: + words.append(TWENTIES[n2][0]) + + if n2 == 1: + words.append(TENS[n1][0]) + elif n1 > 0 and not (i > 0 and x == 1): + words.append(ONES[n1][0]) + + if i > 0: + words.append(self.pluralize(x, THOUSANDS[i])) + + return ' '.join(words) diff --git a/num2words/lang_PT.py b/num2words/lang_PT.py index 44bd4d0..3c47b17 100644 --- a/num2words/lang_PT.py +++ b/num2words/lang_PT.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. diff --git a/num2words/lang_PT_BR.py b/num2words/lang_PT_BR.py index cc8c45c..4c73cac 100644 --- a/num2words/lang_PT_BR.py +++ b/num2words/lang_PT_BR.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. @@ -15,7 +14,6 @@ # 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 diff --git a/num2words/lang_RO.py b/num2words/lang_RO.py index 8ab3c3a..d4693b8 100644 --- a/num2words/lang_RO.py +++ b/num2words/lang_RO.py @@ -1,4 +1,4 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. diff --git a/num2words/lang_RU.py b/num2words/lang_RU.py index 032ddcf..3b02526 100644 --- a/num2words/lang_RU.py +++ b/num2words/lang_RU.py @@ -1,233 +1,234 @@ -# -*- encoding: 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 unicode_literals - -from .base import Num2Word_Base -from .utils import get_digits, splitbyx - -ZERO = ('ноль',) - -ONES_FEMININE = { - 1: ('одна',), - 2: ('две',), - 3: ('три',), - 4: ('четыре',), - 5: ('пять',), - 6: ('шесть',), - 7: ('семь',), - 8: ('восемь',), - 9: ('девять',), -} - -ONES = { - 1: ('один',), - 2: ('два',), - 3: ('три',), - 4: ('четыре',), - 5: ('пять',), - 6: ('шесть',), - 7: ('семь',), - 8: ('восемь',), - 9: ('девять',), -} - -TENS = { - 0: ('десять',), - 1: ('одиннадцать',), - 2: ('двенадцать',), - 3: ('тринадцать',), - 4: ('четырнадцать',), - 5: ('пятнадцать',), - 6: ('шестнадцать',), - 7: ('семнадцать',), - 8: ('восемнадцать',), - 9: ('девятнадцать',), -} - -TWENTIES = { - 2: ('двадцать',), - 3: ('тридцать',), - 4: ('сорок',), - 5: ('пятьдесят',), - 6: ('шестьдесят',), - 7: ('семьдесят',), - 8: ('восемьдесят',), - 9: ('девяносто',), -} - -HUNDREDS = { - 1: ('сто',), - 2: ('двести',), - 3: ('триста',), - 4: ('четыреста',), - 5: ('пятьсот',), - 6: ('шестьсот',), - 7: ('семьсот',), - 8: ('восемьсот',), - 9: ('девятьсот',), -} - -THOUSANDS = { - 1: ('тысяча', 'тысячи', 'тысяч'), # 10^3 - 2: ('миллион', 'миллиона', 'миллионов'), # 10^6 - 3: ('миллиард', 'миллиарда', 'миллиардов'), # 10^9 - 4: ('триллион', 'триллиона', 'триллионов'), # 10^12 - 5: ('квадриллион', 'квадриллиона', 'квадриллионов'), # 10^15 - 6: ('квинтиллион', 'квинтиллиона', 'квинтиллионов'), # 10^18 - 7: ('секстиллион', 'секстиллиона', 'секстиллионов'), # 10^21 - 8: ('септиллион', 'септиллиона', 'септиллионов'), # 10^24 - 9: ('октиллион', 'октиллиона', 'октиллионов'), # 10^27 - 10: ('нониллион', 'нониллиона', 'нониллионов'), # 10^30 -} - - -class Num2Word_RU(Num2Word_Base): - CURRENCY_FORMS = { - 'RUB': ( - ('рубль', 'рубля', 'рублей'), ('копейка', 'копейки', 'копеек') - ), - 'EUR': ( - ('евро', 'евро', 'евро'), ('цент', 'цента', 'центов') - ), - 'USD': ( - ('доллар', 'доллара', 'долларов'), ('цент', 'цента', 'центов') - ), - } - - def setup(self): - self.negword = "минус" - self.pointword = "запятая" - self.ords = {"ноль": "нулевой", - "один": "первый", - "два": "второй", - "три": "третий", - "четыре": "четвертый", - "пять": "пятый", - "шесть": "шестой", - "семь": "седьмой", - "восемь": "восьмой", - "девять": "девятый", - "сто": "сотый"} - self.ords_feminine = {"один": "", - "одна": "", - "две": "двух", - "три": "трёх", - "четыре": "четырёх", - "пять": "пяти", - "шесть": "шести", - "семь": "семи", - "восемь": "восьми", - "девять": "девяти"} - - def to_cardinal(self, number): - n = str(number).replace(',', '.') - if '.' in n: - left, right = n.split('.') - return u'%s %s %s' % ( - self._int2word(int(left)), - self.pointword, - self._int2word(int(right)) - ) - else: - return self._int2word(int(n)) - - def pluralize(self, n, forms): - if n % 100 < 10 or n % 100 > 20: - if n % 10 == 1: - form = 0 - elif 5 > n % 10 > 1: - form = 1 - else: - form = 2 - else: - form = 2 - return forms[form] - - def to_ordinal(self, number): - self.verify_ordinal(number) - outwords = self.to_cardinal(number).split(" ") - lastword = outwords[-1].lower() - try: - if len(outwords) > 1: - if outwords[-2] in self.ords_feminine: - outwords[-2] = self.ords_feminine.get( - outwords[-2], outwords[-2]) - elif outwords[-2] == 'десять': - outwords[-2] = outwords[-2][:-1] + 'и' - if len(outwords) == 3: - if outwords[-3] in ['один', 'одна']: - outwords[-3] = '' - lastword = self.ords[lastword] - except KeyError: - if lastword[:-3] in self.ords_feminine: - lastword = self.ords_feminine.get( - lastword[:-3], lastword) + "сотый" - elif lastword[-1] == "ь" or lastword[-2] == "т": - lastword = lastword[:-1] + "ый" - elif lastword[-1] == "к": - lastword = lastword + "овой" - elif lastword[-5:] == "десят": - lastword = lastword.replace('ь', 'и') + 'ый' - elif lastword[-2] == "ч" or lastword[-1] == "ч": - if lastword[-2] == "ч": - lastword = lastword[:-1] + "ный" - if lastword[-1] == "ч": - lastword = lastword + "ный" - elif lastword[-1] == "н" or lastword[-2] == "н": - lastword = lastword[:lastword.rfind('н') + 1] + "ный" - elif lastword[-1] == "д" or lastword[-2] == "д": - lastword = lastword[:lastword.rfind('д') + 1] + "ный" - outwords[-1] = self.title(lastword) - return " ".join(outwords).strip() - - def _cents_verbose(self, number, currency): - return self._int2word(number, currency == 'RUB') - - def _int2word(self, n, feminine=False): - if n < 0: - return ' '.join([self.negword, self._int2word(abs(n))]) - - if n == 0: - return ZERO[0] - - words = [] - chunks = list(splitbyx(str(n), 3)) - i = len(chunks) - for x in chunks: - i -= 1 - - if x == 0: - continue - - n1, n2, n3 = get_digits(x) - - if n3 > 0: - words.append(HUNDREDS[n3][0]) - - if n2 > 1: - words.append(TWENTIES[n2][0]) - - if n2 == 1: - words.append(TENS[n1][0]) - elif n1 > 0: - ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES - words.append(ones[n1][0]) - - if i > 0: - words.append(self.pluralize(x, THOUSANDS[i])) - - return ' '.join(words) +# -*- 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 unicode_literals + +from .base import Num2Word_Base +from .utils import get_digits, splitbyx + +ZERO = ('ноль',) + +ONES_FEMININE = { + 1: ('одна',), + 2: ('две',), + 3: ('три',), + 4: ('четыре',), + 5: ('пять',), + 6: ('шесть',), + 7: ('семь',), + 8: ('восемь',), + 9: ('девять',), +} + +ONES = { + 1: ('один',), + 2: ('два',), + 3: ('три',), + 4: ('четыре',), + 5: ('пять',), + 6: ('шесть',), + 7: ('семь',), + 8: ('восемь',), + 9: ('девять',), +} + +TENS = { + 0: ('десять',), + 1: ('одиннадцать',), + 2: ('двенадцать',), + 3: ('тринадцать',), + 4: ('четырнадцать',), + 5: ('пятнадцать',), + 6: ('шестнадцать',), + 7: ('семнадцать',), + 8: ('восемнадцать',), + 9: ('девятнадцать',), +} + +TWENTIES = { + 2: ('двадцать',), + 3: ('тридцать',), + 4: ('сорок',), + 5: ('пятьдесят',), + 6: ('шестьдесят',), + 7: ('семьдесят',), + 8: ('восемьдесят',), + 9: ('девяносто',), +} + +HUNDREDS = { + 1: ('сто',), + 2: ('двести',), + 3: ('триста',), + 4: ('четыреста',), + 5: ('пятьсот',), + 6: ('шестьсот',), + 7: ('семьсот',), + 8: ('восемьсот',), + 9: ('девятьсот',), +} + +THOUSANDS = { + 1: ('тысяча', 'тысячи', 'тысяч'), # 10^3 + 2: ('миллион', 'миллиона', 'миллионов'), # 10^6 + 3: ('миллиард', 'миллиарда', 'миллиардов'), # 10^9 + 4: ('триллион', 'триллиона', 'триллионов'), # 10^12 + 5: ('квадриллион', 'квадриллиона', 'квадриллионов'), # 10^15 + 6: ('квинтиллион', 'квинтиллиона', 'квинтиллионов'), # 10^18 + 7: ('секстиллион', 'секстиллиона', 'секстиллионов'), # 10^21 + 8: ('септиллион', 'септиллиона', 'септиллионов'), # 10^24 + 9: ('октиллион', 'октиллиона', 'октиллионов'), # 10^27 + 10: ('нониллион', 'нониллиона', 'нониллионов'), # 10^30 +} + + +class Num2Word_RU(Num2Word_Base): + CURRENCY_FORMS = { + 'RUB': ( + ('рубль', 'рубля', 'рублей'), ('копейка', 'копейки', 'копеек') + ), + 'EUR': ( + ('евро', 'евро', 'евро'), ('цент', 'цента', 'центов') + ), + 'USD': ( + ('доллар', 'доллара', 'долларов'), ('цент', 'цента', 'центов') + ), + } + + def setup(self): + self.negword = "минус" + self.pointword = "запятая" + self.ords = {"ноль": "нулевой", + "один": "первый", + "два": "второй", + "три": "третий", + "четыре": "четвертый", + "пять": "пятый", + "шесть": "шестой", + "семь": "седьмой", + "восемь": "восьмой", + "девять": "девятый", + "сто": "сотый"} + self.ords_feminine = {"один": "", + "одна": "", + "две": "двух", + "три": "трёх", + "четыре": "четырёх", + "пять": "пяти", + "шесть": "шести", + "семь": "семи", + "восемь": "восьми", + "девять": "девяти"} + + def to_cardinal(self, number): + n = str(number).replace(',', '.') + if '.' in n: + left, right = n.split('.') + return u'%s %s %s' % ( + self._int2word(int(left)), + self.pointword, + self._int2word(int(right)) + ) + else: + return self._int2word(int(n)) + + def pluralize(self, n, forms): + if n % 100 < 10 or n % 100 > 20: + if n % 10 == 1: + form = 0 + elif 5 > n % 10 > 1: + form = 1 + else: + form = 2 + else: + form = 2 + return forms[form] + + def to_ordinal(self, number): + self.verify_ordinal(number) + outwords = self.to_cardinal(number).split(" ") + lastword = outwords[-1].lower() + try: + if len(outwords) > 1: + if outwords[-2] in self.ords_feminine: + outwords[-2] = self.ords_feminine.get( + outwords[-2], outwords[-2]) + elif outwords[-2] == 'десять': + outwords[-2] = outwords[-2][:-1] + 'и' + if len(outwords) == 3: + if outwords[-3] in ['один', 'одна']: + outwords[-3] = '' + lastword = self.ords[lastword] + except KeyError: + if lastword[:-3] in self.ords_feminine: + lastword = self.ords_feminine.get( + lastword[:-3], lastword) + "сотый" + elif lastword[-1] == "ь" or lastword[-2] == "т": + lastword = lastword[:-1] + "ый" + elif lastword[-1] == "к": + lastword = lastword + "овой" + elif lastword[-5:] == "десят": + lastword = lastword.replace('ь', 'и') + 'ый' + elif lastword[-2] == "ч" or lastword[-1] == "ч": + if lastword[-2] == "ч": + lastword = lastword[:-1] + "ный" + if lastword[-1] == "ч": + lastword = lastword + "ный" + elif lastword[-1] == "н" or lastword[-2] == "н": + lastword = lastword[:lastword.rfind('н') + 1] + "ный" + elif lastword[-1] == "д" or lastword[-2] == "д": + lastword = lastword[:lastword.rfind('д') + 1] + "ный" + outwords[-1] = self.title(lastword) + return " ".join(outwords).strip() + + def _cents_verbose(self, number, currency): + return self._int2word(number, currency == 'RUB') + + def _int2word(self, n, feminine=False): + if n < 0: + return ' '.join([self.negword, self._int2word(abs(n))]) + + if n == 0: + return ZERO[0] + + words = [] + chunks = list(splitbyx(str(n), 3)) + i = len(chunks) + for x in chunks: + i -= 1 + + if x == 0: + continue + + n1, n2, n3 = get_digits(x) + + if n3 > 0: + words.append(HUNDREDS[n3][0]) + + if n2 > 1: + words.append(TWENTIES[n2][0]) + + if n2 == 1: + words.append(TENS[n1][0]) + elif n1 > 0: + ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES + words.append(ones[n1][0]) + + if i > 0: + words.append(self.pluralize(x, THOUSANDS[i])) + + return ' '.join(words) diff --git a/num2words/lang_SL.py b/num2words/lang_SL.py index 7b73304..5472a61 100644 --- a/num2words/lang_SL.py +++ b/num2words/lang_SL.py @@ -16,8 +16,6 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA -# -*- coding: utf-8 -*- - from __future__ import unicode_literals from .lang_EU import Num2Word_EU diff --git a/num2words/lang_SR.py b/num2words/lang_SR.py index 29265ae..919cad0 100644 --- a/num2words/lang_SR.py +++ b/num2words/lang_SR.py @@ -1,4 +1,4 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. @@ -14,6 +14,7 @@ # 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 .base import Num2Word_Base diff --git a/num2words/lang_TH.py b/num2words/lang_TH.py index 6949c3c..42811ea 100644 --- a/num2words/lang_TH.py +++ b/num2words/lang_TH.py @@ -1,184 +1,183 @@ -# -*- 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 unicode_literals - -from num2words.base import Num2Word_Base -from num2words.currency import parse_currency_parts -from num2words.utils import splitbyx - - -class Num2Word_TH(Num2Word_Base): - - def setup(self): - self.negword = 'ติดลบ' - self.pointword = 'จุด' - - self.CURRENCY_FORMS = { - 'THB': (('บาท', 'บาท'), ('สตางค์', 'สตางค์')), - 'USD': (('ดอลลาร์', 'ดอลลาร์'), ('เซนต์', 'เซนต์')), - 'EUR': (('ยูโร', 'ยูโร'), ('เซนต์', 'เซนต์')), - } - - self.high_numwords = [] - - self.mid_numwords = ['', 'สิบ', 'ร้อย', 'พัน', 'หมื่น', 'แสน', 'ล้าน'] - - self.low_numwords = [ - 'ศูนย์', 'หนึ่ง', 'สอง', 'สาม', 'สี่', - 'ห้า', 'หก', 'เจ็ด', 'แปด', 'เก้า' - ] - - def set_high_numwords(self, high_numwords): - pass - - def set_mid_numwords(self, mid_numwords): - pass - - def splitnum(self, six_num): - length = len(six_num) > 1 - word_num = '' - - for index, num in enumerate(map(int, six_num)): - if num: - if index: - word_num = self.mid_numwords[index] + word_num - - if length and num == 1 and index == 0: - word_num += 'เอ็ด' - elif index == 1 and num == 2: - word_num = 'ยี่' + word_num - elif index != 1 or num != 1: - word_num = self.low_numwords[num] + word_num - - elif num == 0 and index == 0 and length == 0: - word_num = self.low_numwords[0] - - return word_num - - def split_six(self, num_txt): - result = splitbyx(num_txt, 6, format_int=False) - result = list(result)[::-1] - number_list = [] - for i in result: - number_list.append(i[::-1]) - return number_list - - def add_text_million(self, word_num): - result = '' - - for index, t in enumerate(reversed(word_num)): - if index == 0: - result = t - else: - result = result + 'ล้าน' + t - - return result - - def round_2_decimal(self, number): - integer, cents, negative = parse_currency_parts( - number, is_int_with_cents=False - ) - integer = '{}'.format(integer) - cents = '{}'.format(cents) - - if len(cents) < 2: - add_zero = 2 - len(cents) - cents = ('0' * add_zero) + cents - - text_num = integer + '.' + cents - - return text_num, negative - - def left_num_to_text(self, number): - - left_num_list = self.split_six(number) - - left_text_list = [] - for i in left_num_list: - left_text_list.append(self.splitnum(i)) - - left_text = self.add_text_million(left_text_list) - return left_text - - def to_cardinal(self, number): - negative = number < 0 - - pre, post = self.float2tuple(number) - precision = self.precision - pre = '{}'.format(pre) - post = '{}'.format(post) - - if negative: - pre = pre.lstrip('-') - - if len(post) < precision: - add_zero = precision - len(post) - post = ('0' * add_zero) + post - - result = self.left_num_to_text(pre) - - right_text = '' - if not post == '0': - for i in map(int, post): - right_text = right_text + self.low_numwords[i] - result = result + 'จุด' + right_text - - if negative: - result = 'ติดลบ' + result - - return result - - def to_ordinal(self, number): - return self.to_cardinal(number) - - def to_currency(self, number, currency='THB'): - - number, negative = self.round_2_decimal(number) - - split_num = number.split('.') - - left_num = split_num[0] - left_text = self.left_num_to_text(left_num) - - right_num = split_num[1] - right_text = self.splitnum(right_num[::-1].rstrip('0')) - - try: - cr1, cr2 = self.CURRENCY_FORMS[currency] - - except KeyError: - raise NotImplementedError( - 'Currency code "%s" not implemented for "%s"' % - (currency, self.__class__.__name__)) - - if right_num == '00': - if currency == 'THB': - result = left_text + cr1[0] + 'ถ้วน' - else: - result = left_text + cr1[0] - else: - if left_num == '0': - result = right_text + cr2[0] - else: - result = left_text + cr1[0] + right_text + cr2[0] - - if negative: - result = self.negword + result - - return result +# -*- 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 unicode_literals + +from num2words.base import Num2Word_Base +from num2words.currency import parse_currency_parts +from num2words.utils import splitbyx + + +class Num2Word_TH(Num2Word_Base): + + def setup(self): + self.negword = 'ติดลบ' + self.pointword = 'จุด' + + self.CURRENCY_FORMS = { + 'THB': (('บาท', 'บาท'), ('สตางค์', 'สตางค์')), + 'USD': (('ดอลลาร์', 'ดอลลาร์'), ('เซนต์', 'เซนต์')), + 'EUR': (('ยูโร', 'ยูโร'), ('เซนต์', 'เซนต์')), + } + + self.high_numwords = [] + + self.mid_numwords = ['', 'สิบ', 'ร้อย', 'พัน', 'หมื่น', 'แสน', 'ล้าน'] + + self.low_numwords = [ + 'ศูนย์', 'หนึ่ง', 'สอง', 'สาม', 'สี่', + 'ห้า', 'หก', 'เจ็ด', 'แปด', 'เก้า' + ] + + def set_high_numwords(self, high_numwords): + pass + + def set_mid_numwords(self, mid_numwords): + pass + + def splitnum(self, six_num): + length = len(six_num) > 1 + word_num = '' + + for index, num in enumerate(map(int, six_num)): + if num: + if index: + word_num = self.mid_numwords[index] + word_num + + if length and num == 1 and index == 0: + word_num += 'เอ็ด' + elif index == 1 and num == 2: + word_num = 'ยี่' + word_num + elif index != 1 or num != 1: + word_num = self.low_numwords[num] + word_num + + elif num == 0 and index == 0 and length == 0: + word_num = self.low_numwords[0] + + return word_num + + def split_six(self, num_txt): + result = splitbyx(num_txt, 6, format_int=False) + result = list(result)[::-1] + number_list = [] + for i in result: + number_list.append(i[::-1]) + return number_list + + def add_text_million(self, word_num): + result = '' + + for index, t in enumerate(reversed(word_num)): + if index == 0: + result = t + else: + result = result + 'ล้าน' + t + + return result + + def round_2_decimal(self, number): + integer, cents, negative = parse_currency_parts( + number, is_int_with_cents=False + ) + integer = '{}'.format(integer) + cents = '{}'.format(cents) + + if len(cents) < 2: + add_zero = 2 - len(cents) + cents = ('0' * add_zero) + cents + + text_num = integer + '.' + cents + + return text_num, negative + + def left_num_to_text(self, number): + + left_num_list = self.split_six(number) + + left_text_list = [] + for i in left_num_list: + left_text_list.append(self.splitnum(i)) + + left_text = self.add_text_million(left_text_list) + return left_text + + def to_cardinal(self, number): + negative = number < 0 + + pre, post = self.float2tuple(number) + precision = self.precision + pre = '{}'.format(pre) + post = '{}'.format(post) + + if negative: + pre = pre.lstrip('-') + + if len(post) < precision: + add_zero = precision - len(post) + post = ('0' * add_zero) + post + + result = self.left_num_to_text(pre) + + right_text = '' + if not post == '0': + for i in map(int, post): + right_text = right_text + self.low_numwords[i] + result = result + 'จุด' + right_text + + if negative: + result = 'ติดลบ' + result + + return result + + def to_ordinal(self, number): + return self.to_cardinal(number) + + def to_currency(self, number, currency='THB'): + + number, negative = self.round_2_decimal(number) + + split_num = number.split('.') + + left_num = split_num[0] + left_text = self.left_num_to_text(left_num) + + right_num = split_num[1] + right_text = self.splitnum(right_num[::-1].rstrip('0')) + + try: + cr1, cr2 = self.CURRENCY_FORMS[currency] + + except KeyError: + raise NotImplementedError( + 'Currency code "%s" not implemented for "%s"' % + (currency, self.__class__.__name__)) + + if right_num == '00': + if currency == 'THB': + result = left_text + cr1[0] + 'ถ้วน' + else: + result = left_text + cr1[0] + else: + if left_num == '0': + result = right_text + cr2[0] + else: + result = left_text + cr1[0] + right_text + cr2[0] + + if negative: + result = self.negword + result + + return result diff --git a/num2words/lang_TR.py b/num2words/lang_TR.py index 68d364b..3f43fed 100644 --- a/num2words/lang_TR.py +++ b/num2words/lang_TR.py @@ -1,4 +1,4 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. # Copyright (c) 2017, Tufan Kaynak, Framras. All Rights Reserved. diff --git a/num2words/lang_UK.py b/num2words/lang_UK.py index 9672a88..45f8712 100644 --- a/num2words/lang_UK.py +++ b/num2words/lang_UK.py @@ -1,178 +1,179 @@ -# -*- encoding: 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 unicode_literals - -from .base import Num2Word_Base -from .utils import get_digits, splitbyx - -ZERO = ('нуль',) - -ONES_FEMININE = { - 1: ('одна',), - 2: ('двi',), - 3: ('три',), - 4: ('чотири',), - 5: ('п\'ять',), - 6: ('шiсть',), - 7: ('сiм',), - 8: ('вiсiм',), - 9: ('дев\'ять',), -} - -ONES = { - 1: ('один',), - 2: ('два',), - 3: ('три',), - 4: ('чотири',), - 5: ('п\'ять',), - 6: ('шiсть',), - 7: ('сiм',), - 8: ('вiсiм',), - 9: ('дев\'ять',), -} - -TENS = { - 0: ('десять',), - 1: ('одинадцять',), - 2: ('дванадцять',), - 3: ('тринадцять',), - 4: ('чотирнадцять',), - 5: ('п\'ятнадцять',), - 6: ('шiстнадцять',), - 7: ('сiмнадцять',), - 8: ('вiсiмнадцять',), - 9: ('дев\'ятнадцять',), -} - -TWENTIES = { - 2: ('двадцять',), - 3: ('тридцять',), - 4: ('сорок',), - 5: ('п\'ятдесят',), - 6: ('шiстдесят',), - 7: ('сiмдесят',), - 8: ('вiсiмдесят',), - 9: ('дев\'яносто',), -} - -HUNDREDS = { - 1: ('сто',), - 2: ('двiстi',), - 3: ('триста',), - 4: ('чотириста',), - 5: ('п\'ятсот',), - 6: ('шiстсот',), - 7: ('сiмсот',), - 8: ('вiсiмсот',), - 9: ('дев\'ятсот',), -} - -THOUSANDS = { - 1: ('тисяча', 'тисячi', 'тисяч'), # 10^3 - 2: ('мiльйон', 'мiльйони', 'мiльйонiв'), # 10^6 - 3: ('мiльярд', 'мiльярди', 'мiльярдiв'), # 10^9 - 4: ('трильйон', 'трильйони', 'трильйонiв'), # 10^12 - 5: ('квадрильйон', 'квадрильйони', 'квадрильйонiв'), # 10^15 - 6: ('квiнтильйон', 'квiнтильйони', 'квiнтильйонiв'), # 10^18 - 7: ('секстильйон', 'секстильйони', 'секстильйонiв'), # 10^21 - 8: ('септильйон', 'септильйони', 'септильйонiв'), # 10^24 - 9: ('октильйон', 'октильйони', 'октильйонiв'), # 10^27 - 10: ('нонiльйон', 'нонiльйони', 'нонiльйонiв'), # 10^30 -} - - -class Num2Word_UK(Num2Word_Base): - CURRENCY_FORMS = { - 'UAH': ( - ('гривня', 'гривнi', 'гривень'), - ('копiйка', 'копiйки', 'копiйок') - ), - 'EUR': ( - ('євро', 'євро', 'євро'), ('цент', 'центи', 'центiв') - ), - } - - def setup(self): - self.negword = "мiнус" - self.pointword = "кома" - - def to_cardinal(self, number): - n = str(number).replace(',', '.') - if '.' in n: - left, right = n.split('.') - return '%s %s %s' % ( - self._int2word(int(left)), - self.pointword, - self._int2word(int(right)) - ) - else: - return self._int2word(int(n)) - - def pluralize(self, n, forms): - if n % 100 < 10 or n % 100 > 20: - if n % 10 == 1: - form = 0 - elif 5 > n % 10 > 1: - form = 1 - else: - form = 2 - else: - form = 2 - - return forms[form] - - def _int2word(self, n, feminine=True): - if n < 0: - return ' '.join([self.negword, self._int2word(abs(n))]) - - if n == 0: - return ZERO[0] - - words = [] - chunks = list(splitbyx(str(n), 3)) - i = len(chunks) - for x in chunks: - i -= 1 - - if x == 0: - continue - - n1, n2, n3 = get_digits(x) - - if n3 > 0: - words.append(HUNDREDS[n3][0]) - - if n2 > 1: - words.append(TWENTIES[n2][0]) - - if n2 == 1: - words.append(TENS[n1][0]) - # elif n1 > 0 and not (i > 0 and x == 1): - elif n1 > 0: - ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES - words.append(ones[n1][0]) - - if i > 0: - words.append(self.pluralize(x, THOUSANDS[i])) - - return ' '.join(words) - - def _cents_verbose(self, number, currency): - return self._int2word(number, currency == 'UAH') - - def to_ordinal(self, number): - raise NotImplementedError() +# -*- 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 unicode_literals + +from .base import Num2Word_Base +from .utils import get_digits, splitbyx + +ZERO = ('нуль',) + +ONES_FEMININE = { + 1: ('одна',), + 2: ('двi',), + 3: ('три',), + 4: ('чотири',), + 5: ('п\'ять',), + 6: ('шiсть',), + 7: ('сiм',), + 8: ('вiсiм',), + 9: ('дев\'ять',), +} + +ONES = { + 1: ('один',), + 2: ('два',), + 3: ('три',), + 4: ('чотири',), + 5: ('п\'ять',), + 6: ('шiсть',), + 7: ('сiм',), + 8: ('вiсiм',), + 9: ('дев\'ять',), +} + +TENS = { + 0: ('десять',), + 1: ('одинадцять',), + 2: ('дванадцять',), + 3: ('тринадцять',), + 4: ('чотирнадцять',), + 5: ('п\'ятнадцять',), + 6: ('шiстнадцять',), + 7: ('сiмнадцять',), + 8: ('вiсiмнадцять',), + 9: ('дев\'ятнадцять',), +} + +TWENTIES = { + 2: ('двадцять',), + 3: ('тридцять',), + 4: ('сорок',), + 5: ('п\'ятдесят',), + 6: ('шiстдесят',), + 7: ('сiмдесят',), + 8: ('вiсiмдесят',), + 9: ('дев\'яносто',), +} + +HUNDREDS = { + 1: ('сто',), + 2: ('двiстi',), + 3: ('триста',), + 4: ('чотириста',), + 5: ('п\'ятсот',), + 6: ('шiстсот',), + 7: ('сiмсот',), + 8: ('вiсiмсот',), + 9: ('дев\'ятсот',), +} + +THOUSANDS = { + 1: ('тисяча', 'тисячi', 'тисяч'), # 10^3 + 2: ('мiльйон', 'мiльйони', 'мiльйонiв'), # 10^6 + 3: ('мiльярд', 'мiльярди', 'мiльярдiв'), # 10^9 + 4: ('трильйон', 'трильйони', 'трильйонiв'), # 10^12 + 5: ('квадрильйон', 'квадрильйони', 'квадрильйонiв'), # 10^15 + 6: ('квiнтильйон', 'квiнтильйони', 'квiнтильйонiв'), # 10^18 + 7: ('секстильйон', 'секстильйони', 'секстильйонiв'), # 10^21 + 8: ('септильйон', 'септильйони', 'септильйонiв'), # 10^24 + 9: ('октильйон', 'октильйони', 'октильйонiв'), # 10^27 + 10: ('нонiльйон', 'нонiльйони', 'нонiльйонiв'), # 10^30 +} + + +class Num2Word_UK(Num2Word_Base): + CURRENCY_FORMS = { + 'UAH': ( + ('гривня', 'гривнi', 'гривень'), + ('копiйка', 'копiйки', 'копiйок') + ), + 'EUR': ( + ('євро', 'євро', 'євро'), ('цент', 'центи', 'центiв') + ), + } + + def setup(self): + self.negword = "мiнус" + self.pointword = "кома" + + def to_cardinal(self, number): + n = str(number).replace(',', '.') + if '.' in n: + left, right = n.split('.') + return '%s %s %s' % ( + self._int2word(int(left)), + self.pointword, + self._int2word(int(right)) + ) + else: + return self._int2word(int(n)) + + def pluralize(self, n, forms): + if n % 100 < 10 or n % 100 > 20: + if n % 10 == 1: + form = 0 + elif 5 > n % 10 > 1: + form = 1 + else: + form = 2 + else: + form = 2 + + return forms[form] + + def _int2word(self, n, feminine=True): + if n < 0: + return ' '.join([self.negword, self._int2word(abs(n))]) + + if n == 0: + return ZERO[0] + + words = [] + chunks = list(splitbyx(str(n), 3)) + i = len(chunks) + for x in chunks: + i -= 1 + + if x == 0: + continue + + n1, n2, n3 = get_digits(x) + + if n3 > 0: + words.append(HUNDREDS[n3][0]) + + if n2 > 1: + words.append(TWENTIES[n2][0]) + + if n2 == 1: + words.append(TENS[n1][0]) + # elif n1 > 0 and not (i > 0 and x == 1): + elif n1 > 0: + ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES + words.append(ones[n1][0]) + + if i > 0: + words.append(self.pluralize(x, THOUSANDS[i])) + + return ' '.join(words) + + def _cents_verbose(self, number, currency): + return self._int2word(number, currency == 'UAH') + + def to_ordinal(self, number): + raise NotImplementedError() diff --git a/num2words/utils.py b/num2words/utils.py index 34e41e8..b5e4611 100644 --- a/num2words/utils.py +++ b/num2words/utils.py @@ -1,17 +1,35 @@ -def splitbyx(n, x, format_int=True): - length = len(n) - if length > x: - start = length % x - if start > 0: - result = n[:start] - yield int(result) if format_int else result - for i in range(start, length, x): - result = n[i:i+x] - yield int(result) if format_int else result - else: - yield int(n) if format_int else n - - -def get_digits(n): - a = [int(x) for x in reversed(list(('%03d' % n)[-3:]))] - return a +# -*- 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 + + +def splitbyx(n, x, format_int=True): + length = len(n) + if length > x: + start = length % x + if start > 0: + result = n[:start] + yield int(result) if format_int else result + for i in range(start, length, x): + result = n[i:i+x] + yield int(result) if format_int else result + else: + yield int(n) if format_int else n + + +def get_digits(n): + a = [int(x) for x in reversed(list(('%03d' % n)[-3:]))] + return a diff --git a/setup.py b/setup.py index 291b868..fbc34f7 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,22 @@ +# -*- 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 re +from io import open from setuptools import find_packages, setup @@ -17,8 +35,8 @@ CLASSIFIERS = [ 'Topic :: Text Processing :: Linguistic', ] -LONG_DESC = open('README.rst', 'rt').read() + '\n\n' + \ - open('CHANGES.rst', 'rt').read() +LONG_DESC = open('README.rst', 'rt', encoding="utf-8").read() + '\n\n' + \ + open('CHANGES.rst', 'rt', encoding="utf-8").read() def find_version(fname): @@ -26,7 +44,7 @@ def find_version(fname): Returns str or raises RuntimeError """ version = '' - with open(fname, 'r') as fp: + with open(fname, 'r', encoding="utf-8") as fp: reg = re.compile(r'__version__ = [\'"]([^\'"]*)[\'"]') for line in fp: m = reg.match(line) diff --git a/tests/test_ar.py b/tests/test_ar.py index b7337c4..5e1ea41 100644 --- a/tests/test_ar.py +++ b/tests/test_ar.py @@ -1,4 +1,5 @@ -# -*- encoding: utf-8 -*- +# -*- 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 @@ -13,7 +14,6 @@ # 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 diff --git a/tests/test_base.py b/tests/test_base.py index 7cdc1ee..ea7701c 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -1,3 +1,20 @@ +# -*- 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 unicode_literals from decimal import Decimal diff --git a/tests/test_cli.py b/tests/test_cli.py index 3e1d3ab..484a8dc 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,5 +1,20 @@ #!/usr/bin/env python # -*- 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 unicode_literals diff --git a/tests/test_currency.py b/tests/test_currency.py index e23daf0..88c444d 100644 --- a/tests/test_currency.py +++ b/tests/test_currency.py @@ -1,3 +1,20 @@ +# -*- 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 decimal import Decimal from unittest import TestCase diff --git a/tests/test_cz.py b/tests/test_cz.py index c092edb..4d237a7 100644 --- a/tests/test_cz.py +++ b/tests/test_cz.py @@ -1,5 +1,6 @@ -# -*- encoding: utf-8 -*- -# Copyright (c) 2015, Savoir-faire Linux inc. All Rights Reserved. +# -*- 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 diff --git a/tests/test_de.py b/tests/test_de.py index 3c30dd8..d20794d 100644 --- a/tests/test_de.py +++ b/tests/test_de.py @@ -1,5 +1,6 @@ -# -*- encoding: utf-8 -*- -# Copyright (c) 2015, Savoir-faire Linux inc. All Rights Reserved. +# -*- 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 diff --git a/tests/test_en.py b/tests/test_en.py index b3b2bc0..b477c5f 100644 --- a/tests/test_en.py +++ b/tests/test_en.py @@ -1,3 +1,5 @@ +# -*- 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 diff --git a/tests/test_en_in.py b/tests/test_en_in.py index 580bcf4..1599d59 100644 --- a/tests/test_en_in.py +++ b/tests/test_en_in.py @@ -1,3 +1,5 @@ +# -*- 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 diff --git a/tests/test_es.py b/tests/test_es.py index 43a5179..3c576d1 100644 --- a/tests/test_es.py +++ b/tests/test_es.py @@ -1,4 +1,5 @@ -# encoding: UTF-8 +# -*- 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 @@ -13,6 +14,7 @@ # 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 diff --git a/tests/test_es_co.py b/tests/test_es_co.py index 5df2bf7..81c789f 100644 --- a/tests/test_es_co.py +++ b/tests/test_es_co.py @@ -1,4 +1,5 @@ -# encoding: UTF-8 +# -*- 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 diff --git a/tests/test_es_ve.py b/tests/test_es_ve.py index 42f35f6..d7fec74 100644 --- a/tests/test_es_ve.py +++ b/tests/test_es_ve.py @@ -1,4 +1,5 @@ -# encoding: UTF-8 +# -*- 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 @@ -13,7 +14,6 @@ # 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 diff --git a/tests/test_fi.py b/tests/test_fi.py index 1698a96..882b093 100644 --- a/tests/test_fi.py +++ b/tests/test_fi.py @@ -1,4 +1,5 @@ # -*- 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 diff --git a/tests/test_fr.py b/tests/test_fr.py index deeec22..1299dcc 100644 --- a/tests/test_fr.py +++ b/tests/test_fr.py @@ -1,19 +1,19 @@ -# -*- encoding: utf-8 -*- -# Copetright (c) 2015, Savoir-faire Linux inc. All Rights Reserved. +# -*- coding: utf-8 -*- +# Copyright (c) 2003, Taro Ogawa. All Rights Reserved. +# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. -# This libraret is free software; etou can redistribute it and/or -# modifet it under the terms of the GNU Lesser General Public -# License as published bet the Free Software Foundation; either -# version 2.1 of the License, or (at etour option) anet later version. -# This libraret is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warrantet of +# 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 copet of the GNU Lesser General Public -# License along with this libraret; if not, write to the Free Software +# 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 diff --git a/tests/test_fr_be.py b/tests/test_fr_be.py index 560d433..d084ac4 100644 --- a/tests/test_fr_be.py +++ b/tests/test_fr_be.py @@ -1,5 +1,6 @@ -# -*- encoding: utf-8 -*- -# Copyright (c) 2015, Savoir-faire Linux inc. All Rights Reserved. +# -*- 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 @@ -13,7 +14,6 @@ # 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 diff --git a/tests/test_fr_ch.py b/tests/test_fr_ch.py index 56a21ed..ad0f3b1 100644 --- a/tests/test_fr_ch.py +++ b/tests/test_fr_ch.py @@ -1,5 +1,6 @@ -# -*- encoding: utf-8 -*- -# Copyright (c) 2015, Savoir-faire Linux inc. All Rights Reserved. +# -*- 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 diff --git a/tests/test_fr_dz.py b/tests/test_fr_dz.py index 6c48a76..6c467cb 100644 --- a/tests/test_fr_dz.py +++ b/tests/test_fr_dz.py @@ -1,5 +1,6 @@ -# -*- encoding: utf-8 -*- -# Copyright (c) 2015, Savoir-faire Linux inc. All Rights Reserved. +# -*- 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 diff --git a/tests/test_id.py b/tests/test_id.py index 7fc46b6..0390757 100644 --- a/tests/test_id.py +++ b/tests/test_id.py @@ -1,3 +1,5 @@ +# -*- 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 diff --git a/tests/test_it.py b/tests/test_it.py index d358bac..23c79ce 100644 --- a/tests/test_it.py +++ b/tests/test_it.py @@ -1,5 +1,6 @@ -# -*- encoding: utf-8 -*- -# Copyright (c) 2015, Savoir-faire Linux inc. All Rights Reserved. +# -*- 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 diff --git a/tests/test_ja.py b/tests/test_ja.py index ea24a7c..eaac20b 100644 --- a/tests/test_ja.py +++ b/tests/test_ja.py @@ -1,4 +1,5 @@ # -*- 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 diff --git a/tests/test_ko.py b/tests/test_ko.py index 401ecb8..c98ad88 100644 --- a/tests/test_ko.py +++ b/tests/test_ko.py @@ -1,4 +1,5 @@ # -*- 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 diff --git a/tests/test_lt.py b/tests/test_lt.py index 81e8938..3c11e4a 100644 --- a/tests/test_lt.py +++ b/tests/test_lt.py @@ -1,4 +1,20 @@ -# -*- encoding: utf-8 -*- +# -*- 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 unicode_literals from unittest import TestCase diff --git a/tests/test_lv.py b/tests/test_lv.py index ef265c0..a0bffe9 100644 --- a/tests/test_lv.py +++ b/tests/test_lv.py @@ -1,4 +1,20 @@ -# -*- encoding: utf-8 -*- +# -*- 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 unicode_literals from unittest import TestCase diff --git a/tests/test_nl.py b/tests/test_nl.py index e93c0f2..b301062 100644 --- a/tests/test_nl.py +++ b/tests/test_nl.py @@ -1,5 +1,6 @@ -# -*- encoding: utf-8 -*- -# Copyright (c) 2015, Savoir-faire Linux inc. All Rights Reserved. +# -*- 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 diff --git a/tests/test_pl.py b/tests/test_pl.py index 9be1314..abc34b9 100644 --- a/tests/test_pl.py +++ b/tests/test_pl.py @@ -1,5 +1,6 @@ -# -*- encoding: utf-8 -*- -# Copyright (c) 2015, Savoir-faire Linux inc. All Rights Reserved. +# -*- 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 diff --git a/tests/test_pt.py b/tests/test_pt.py index b23f40a..bc49d45 100644 --- a/tests/test_pt.py +++ b/tests/test_pt.py @@ -1,5 +1,6 @@ -# -*- encoding: utf-8 -*- -# Copyright (c) 2015, Savoir-faire Linux inc. All Rights Reserved. +# -*- 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 diff --git a/tests/test_pt_BR.py b/tests/test_pt_BR.py index e968f14..bbf9e8d 100644 --- a/tests/test_pt_BR.py +++ b/tests/test_pt_BR.py @@ -1,5 +1,6 @@ -# -*- encoding: utf-8 -*- -# Copyright (c) 2015, Savoir-faire Linux inc. All Rights Reserved. +# -*- 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 diff --git a/tests/test_ro.py b/tests/test_ro.py index 4422ca2..b5e6c51 100644 --- a/tests/test_ro.py +++ b/tests/test_ro.py @@ -1,4 +1,5 @@ -# -*- encoding: utf-8 -*- +# -*- 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 diff --git a/tests/test_ru.py b/tests/test_ru.py index 6343bbc..9c35b76 100644 --- a/tests/test_ru.py +++ b/tests/test_ru.py @@ -1,4 +1,5 @@ -# -*- encoding: utf-8 -*- +# -*- 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 @@ -13,6 +14,7 @@ # 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 diff --git a/tests/test_sl.py b/tests/test_sl.py index 02351f2..cc78168 100644 --- a/tests/test_sl.py +++ b/tests/test_sl.py @@ -1,5 +1,6 @@ -# -*- encoding: utf-8 -*- -# Copyright (c) 2015, Savoir-faire Linux inc. All Rights Reserved. +# -*- 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 diff --git a/tests/test_sr.py b/tests/test_sr.py index aa8899b..8547325 100644 --- a/tests/test_sr.py +++ b/tests/test_sr.py @@ -1,4 +1,5 @@ -# -*- encoding: utf-8 -*- +# -*- 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 @@ -13,6 +14,7 @@ # 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 diff --git a/tests/test_th.py b/tests/test_th.py index e0f4a49..4468ec5 100644 --- a/tests/test_th.py +++ b/tests/test_th.py @@ -1,193 +1,208 @@ -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - -from unittest import TestCase - -from num2words import num2words -from num2words.lang_TH import Num2Word_TH - - -class TestNumWord(TestCase): - - def test_0(self): - self.assertEqual(num2words(0, lang='th'), "ศูนย์") - - def test_end_with_1(self): - self.assertEqual(num2words(21, lang='th'), "ยี่สิบเอ็ด") - self.assertEqual(num2words(11, lang='th'), "สิบเอ็ด") - self.assertEqual(num2words(101, lang='th'), "หนึ่งร้อยเอ็ด") - self.assertEqual(num2words(1201, lang='th'), "หนึ่งพันสองร้อยเอ็ด") - - def test_start_20(self): - self.assertEqual(num2words(22, lang='th'), "ยี่สิบสอง") - self.assertEqual(num2words(27, lang='th'), "ยี่สิบเจ็ด") - - def test_start_10(self): - self.assertEqual(num2words(10, lang='th'), "สิบ") - self.assertEqual(num2words(18, lang='th'), "สิบแปด") - - def test_1_to_9(self): - self.assertEqual(num2words(1, lang='th'), "หนึ่ง") - self.assertEqual(num2words(5, lang='th'), "ห้า") - self.assertEqual(num2words(9, lang='th'), "เก้า") - - def test_31_to_99(self): - self.assertEqual(num2words(31, lang='th'), "สามสิบเอ็ด") - self.assertEqual(num2words(48, lang='th'), "สี่สิบแปด") - self.assertEqual(num2words(76, lang='th'), "เจ็ดสิบหก") - - def test_100_to_999(self): - self.assertEqual(num2words(100, lang='th'), "หนึ่งร้อย") - self.assertEqual(num2words(123, lang='th'), "หนึ่งร้อยยี่สิบสาม") - self.assertEqual(num2words(456, lang='th'), "สี่ร้อยห้าสิบหก") - self.assertEqual(num2words(721, lang='th'), "เจ็ดร้อยยี่สิบเอ็ด") - - def test_1000_to_9999(self): - self.assertEqual(num2words(1000, lang='th'), "หนึ่งพัน") - self.assertEqual( - num2words(2175, lang='th'), "สองพันหนึ่งร้อยเจ็ดสิบห้า" - ) - self.assertEqual(num2words(4582, lang='th'), "สี่พันห้าร้อยแปดสิบสอง") - self.assertEqual(num2words(9346, lang='th'), "เก้าพันสามร้อยสี่สิบหก") - - def test_10000_to_99999(self): - self.assertEqual( - num2words(11111, lang='th'), "หนึ่งหมื่นหนึ่งพันหนึ่งร้อยสิบเอ็ด" - ) - self.assertEqual( - num2words(22222, lang='th'), "สองหมื่นสองพันสองร้อยยี่สิบสอง" - ) - self.assertEqual( - num2words(84573, lang='th'), "แปดหมื่นสี่พันห้าร้อยเจ็ดสิบสาม" - ) - - def test_100000_to_999999(self): - self.assertEqual( - num2words(153247, lang='th'), - "หนึ่งแสนห้าหมื่นสามพันสองร้อยสี่สิบเจ็ด" - ) - self.assertEqual( - num2words(562442, lang='th'), - "ห้าแสนหกหมื่นสองพันสี่ร้อยสี่สิบสอง" - ) - self.assertEqual( - num2words(999999, lang='th'), - "เก้าแสนเก้าหมื่นเก้าพันเก้าร้อยเก้าสิบเก้า" - ) - - def test_more_than_million(self): - self.assertEqual( - num2words(1000000, lang='th'), - "หนึ่งล้าน" - ) - self.assertEqual( - num2words(1000001, lang='th'), - "หนึ่งล้านเอ็ด" - ) - self.assertEqual( - num2words(42478941, lang='th'), - "สี่สิบสองล้านสี่แสนเจ็ดหมื่นแปดพันเก้าร้อยสี่สิบเอ็ด" - ) - self.assertEqual( - num2words(712696969, lang='th'), - "เจ็ดร้อยสิบสองล้านหกแสนเก้าหมื่นหกพันเก้าร้อยหกสิบเก้า" - ) - self.assertEqual( - num2words(1000000000000000001, lang='th'), - "หนึ่งล้านล้านล้านเอ็ด" - ) - - def test_decimal(self): - self.assertEqual( - num2words(0.0, lang='th'), "ศูนย์" - ) - self.assertEqual( - num2words(0.0038, lang='th'), "ศูนย์จุดศูนย์ศูนย์สามแปด" - ) - self.assertEqual( - num2words(0.01, lang='th'), "ศูนย์จุดศูนย์หนึ่ง" - ) - self.assertEqual( - num2words(1.123, lang='th'), "หนึ่งจุดหนึ่งสองสาม" - ) - self.assertEqual( - num2words(35.37, lang='th'), "สามสิบห้าจุดสามเจ็ด" - ) - self.assertEqual( - num2words(1000000.01, lang='th'), "หนึ่งล้านจุดศูนย์หนึ่ง" - ) - - def test_currency(self): - self.assertEqual( - num2words(100, lang='th', to='currency', currency='THB'), - "หนึ่งร้อยบาทถ้วน" - ) - self.assertEqual( - num2words(100, lang='th', to='currency', currency='USD'), - "หนึ่งร้อยดอลลาร์" - ) - self.assertEqual( - num2words(100, lang='th', to='currency', currency='EUR'), - "หนึ่งร้อยยูโร" - ) - - def test_currency_decimal(self): - self.assertEqual( - num2words(0.00, lang='th', to='currency'), "ศูนย์บาทถ้วน" - ) - self.assertEqual( - num2words(0.05, lang='th', to='currency'), "ห้าสตางค์" - ) - self.assertEqual( - num2words(0.50, lang='th', to='currency'), "ห้าสิบสตางค์" - ) - self.assertEqual( - num2words(0.99, lang='th', to='currency'), "เก้าสิบเก้าสตางค์" - ) - self.assertEqual( - num2words(100.00, lang='th', to='currency'), "หนึ่งร้อยบาทถ้วน" - ) - self.assertEqual( - num2words(100.23, lang='th', to='currency', currency='USD'), - "หนึ่งร้อยดอลลาร์ยี่สิบสามเซนต์" - ) - self.assertEqual( - num2words(100.24, lang='th', to='currency', currency='EUR'), - "หนึ่งร้อยยูโรยี่สิบสี่เซนต์" - ) - - def test_negative(self): - self.assertEqual(num2words(-10, lang='th'), "ติดลบสิบ") - self.assertEqual(num2words(-10.50, lang='th'), "ติดลบสิบจุดห้า") - self.assertEqual( - num2words(-100.00, lang='th', to='currency'), - "ติดลบหนึ่งร้อยบาทถ้วน" - ) - - def test_round_2_decimal(self): - n2wTH = Num2Word_TH() - self.assertEqual(n2wTH.round_2_decimal(0.004), ('0.00', False)) - self.assertEqual(n2wTH.round_2_decimal(0.005), ('0.01', False)) - self.assertEqual(n2wTH.round_2_decimal(0.006), ('0.01', False)) - self.assertEqual(n2wTH.round_2_decimal(0.0005), - ('0.00', False)) - self.assertEqual(n2wTH.round_2_decimal(0.984), ('0.98', False)) - self.assertEqual(n2wTH.round_2_decimal(0.989), ('0.99', False)) - self.assertEqual(n2wTH.round_2_decimal(0.994), ('0.99', False)) - self.assertEqual(n2wTH.round_2_decimal(0.999), ('1.00', False)) - self.assertEqual(n2wTH.round_2_decimal(-0.994), ('0.99', True)) - self.assertEqual(n2wTH.round_2_decimal(-0.999), ('1.00', True)) - # self.assertEqual(n2wTH.round_2_decimal(0.985), ('0.99', False)) - # Expect 0.99 get 0.98 - # self.assertEqual(n2wTH.round_2_decimal(0.995), ('1.00', False)) - # Expect 1.00 get 0.99 - - def test_split_six(self): - n2wTH = Num2Word_TH() - self.assertEqual(n2wTH.split_six(str(123456789)), - ['987654', '321']) - self.assertEqual(n2wTH.split_six(str(12345)), - ['54321']) - self.assertEqual(n2wTH.split_six(str(1234567)), - ['765432', '1']) +# -*- 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 unicode_literals + +from unittest import TestCase + +from num2words import num2words +from num2words.lang_TH import Num2Word_TH + + +class TestNumWord(TestCase): + + def test_0(self): + self.assertEqual(num2words(0, lang='th'), "ศูนย์") + + def test_end_with_1(self): + self.assertEqual(num2words(21, lang='th'), "ยี่สิบเอ็ด") + self.assertEqual(num2words(11, lang='th'), "สิบเอ็ด") + self.assertEqual(num2words(101, lang='th'), "หนึ่งร้อยเอ็ด") + self.assertEqual(num2words(1201, lang='th'), "หนึ่งพันสองร้อยเอ็ด") + + def test_start_20(self): + self.assertEqual(num2words(22, lang='th'), "ยี่สิบสอง") + self.assertEqual(num2words(27, lang='th'), "ยี่สิบเจ็ด") + + def test_start_10(self): + self.assertEqual(num2words(10, lang='th'), "สิบ") + self.assertEqual(num2words(18, lang='th'), "สิบแปด") + + def test_1_to_9(self): + self.assertEqual(num2words(1, lang='th'), "หนึ่ง") + self.assertEqual(num2words(5, lang='th'), "ห้า") + self.assertEqual(num2words(9, lang='th'), "เก้า") + + def test_31_to_99(self): + self.assertEqual(num2words(31, lang='th'), "สามสิบเอ็ด") + self.assertEqual(num2words(48, lang='th'), "สี่สิบแปด") + self.assertEqual(num2words(76, lang='th'), "เจ็ดสิบหก") + + def test_100_to_999(self): + self.assertEqual(num2words(100, lang='th'), "หนึ่งร้อย") + self.assertEqual(num2words(123, lang='th'), "หนึ่งร้อยยี่สิบสาม") + self.assertEqual(num2words(456, lang='th'), "สี่ร้อยห้าสิบหก") + self.assertEqual(num2words(721, lang='th'), "เจ็ดร้อยยี่สิบเอ็ด") + + def test_1000_to_9999(self): + self.assertEqual(num2words(1000, lang='th'), "หนึ่งพัน") + self.assertEqual( + num2words(2175, lang='th'), "สองพันหนึ่งร้อยเจ็ดสิบห้า" + ) + self.assertEqual(num2words(4582, lang='th'), "สี่พันห้าร้อยแปดสิบสอง") + self.assertEqual(num2words(9346, lang='th'), "เก้าพันสามร้อยสี่สิบหก") + + def test_10000_to_99999(self): + self.assertEqual( + num2words(11111, lang='th'), "หนึ่งหมื่นหนึ่งพันหนึ่งร้อยสิบเอ็ด" + ) + self.assertEqual( + num2words(22222, lang='th'), "สองหมื่นสองพันสองร้อยยี่สิบสอง" + ) + self.assertEqual( + num2words(84573, lang='th'), "แปดหมื่นสี่พันห้าร้อยเจ็ดสิบสาม" + ) + + def test_100000_to_999999(self): + self.assertEqual( + num2words(153247, lang='th'), + "หนึ่งแสนห้าหมื่นสามพันสองร้อยสี่สิบเจ็ด" + ) + self.assertEqual( + num2words(562442, lang='th'), + "ห้าแสนหกหมื่นสองพันสี่ร้อยสี่สิบสอง" + ) + self.assertEqual( + num2words(999999, lang='th'), + "เก้าแสนเก้าหมื่นเก้าพันเก้าร้อยเก้าสิบเก้า" + ) + + def test_more_than_million(self): + self.assertEqual( + num2words(1000000, lang='th'), + "หนึ่งล้าน" + ) + self.assertEqual( + num2words(1000001, lang='th'), + "หนึ่งล้านเอ็ด" + ) + self.assertEqual( + num2words(42478941, lang='th'), + "สี่สิบสองล้านสี่แสนเจ็ดหมื่นแปดพันเก้าร้อยสี่สิบเอ็ด" + ) + self.assertEqual( + num2words(712696969, lang='th'), + "เจ็ดร้อยสิบสองล้านหกแสนเก้าหมื่นหกพันเก้าร้อยหกสิบเก้า" + ) + self.assertEqual( + num2words(1000000000000000001, lang='th'), + "หนึ่งล้านล้านล้านเอ็ด" + ) + + def test_decimal(self): + self.assertEqual( + num2words(0.0, lang='th'), "ศูนย์" + ) + self.assertEqual( + num2words(0.0038, lang='th'), "ศูนย์จุดศูนย์ศูนย์สามแปด" + ) + self.assertEqual( + num2words(0.01, lang='th'), "ศูนย์จุดศูนย์หนึ่ง" + ) + self.assertEqual( + num2words(1.123, lang='th'), "หนึ่งจุดหนึ่งสองสาม" + ) + self.assertEqual( + num2words(35.37, lang='th'), "สามสิบห้าจุดสามเจ็ด" + ) + self.assertEqual( + num2words(1000000.01, lang='th'), "หนึ่งล้านจุดศูนย์หนึ่ง" + ) + + def test_currency(self): + self.assertEqual( + num2words(100, lang='th', to='currency', currency='THB'), + "หนึ่งร้อยบาทถ้วน" + ) + self.assertEqual( + num2words(100, lang='th', to='currency', currency='USD'), + "หนึ่งร้อยดอลลาร์" + ) + self.assertEqual( + num2words(100, lang='th', to='currency', currency='EUR'), + "หนึ่งร้อยยูโร" + ) + + def test_currency_decimal(self): + self.assertEqual( + num2words(0.00, lang='th', to='currency'), "ศูนย์บาทถ้วน" + ) + self.assertEqual( + num2words(0.05, lang='th', to='currency'), "ห้าสตางค์" + ) + self.assertEqual( + num2words(0.50, lang='th', to='currency'), "ห้าสิบสตางค์" + ) + self.assertEqual( + num2words(0.99, lang='th', to='currency'), "เก้าสิบเก้าสตางค์" + ) + self.assertEqual( + num2words(100.00, lang='th', to='currency'), "หนึ่งร้อยบาทถ้วน" + ) + self.assertEqual( + num2words(100.23, lang='th', to='currency', currency='USD'), + "หนึ่งร้อยดอลลาร์ยี่สิบสามเซนต์" + ) + self.assertEqual( + num2words(100.24, lang='th', to='currency', currency='EUR'), + "หนึ่งร้อยยูโรยี่สิบสี่เซนต์" + ) + + def test_negative(self): + self.assertEqual(num2words(-10, lang='th'), "ติดลบสิบ") + self.assertEqual(num2words(-10.50, lang='th'), "ติดลบสิบจุดห้า") + self.assertEqual( + num2words(-100.00, lang='th', to='currency'), + "ติดลบหนึ่งร้อยบาทถ้วน" + ) + + def test_round_2_decimal(self): + n2wTH = Num2Word_TH() + self.assertEqual(n2wTH.round_2_decimal(0.004), ('0.00', False)) + self.assertEqual(n2wTH.round_2_decimal(0.005), ('0.01', False)) + self.assertEqual(n2wTH.round_2_decimal(0.006), ('0.01', False)) + self.assertEqual(n2wTH.round_2_decimal(0.0005), + ('0.00', False)) + self.assertEqual(n2wTH.round_2_decimal(0.984), ('0.98', False)) + self.assertEqual(n2wTH.round_2_decimal(0.989), ('0.99', False)) + self.assertEqual(n2wTH.round_2_decimal(0.994), ('0.99', False)) + self.assertEqual(n2wTH.round_2_decimal(0.999), ('1.00', False)) + self.assertEqual(n2wTH.round_2_decimal(-0.994), ('0.99', True)) + self.assertEqual(n2wTH.round_2_decimal(-0.999), ('1.00', True)) + # self.assertEqual(n2wTH.round_2_decimal(0.985), ('0.99', False)) + # Expect 0.99 get 0.98 + # self.assertEqual(n2wTH.round_2_decimal(0.995), ('1.00', False)) + # Expect 1.00 get 0.99 + + def test_split_six(self): + n2wTH = Num2Word_TH() + self.assertEqual(n2wTH.split_six(str(123456789)), + ['987654', '321']) + self.assertEqual(n2wTH.split_six(str(12345)), + ['54321']) + self.assertEqual(n2wTH.split_six(str(1234567)), + ['765432', '1']) diff --git a/tests/test_tr.py b/tests/test_tr.py index f7f7dc6..02073e0 100644 --- a/tests/test_tr.py +++ b/tests/test_tr.py @@ -1,6 +1,6 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- +# Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. -# Copyright (c) 2017, Tufan Kaynak, Framras. 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 diff --git a/tests/test_uk.py b/tests/test_uk.py index 8b40e8e..ff17103 100644 --- a/tests/test_uk.py +++ b/tests/test_uk.py @@ -1,4 +1,5 @@ -# -*- encoding: utf-8 -*- +# -*- 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 @@ -13,6 +14,7 @@ # 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 diff --git a/tests/test_utils.py b/tests/test_utils.py index 9352023..a6cfc3a 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,24 +1,41 @@ -from unittest import TestCase - -from num2words.utils import splitbyx - - -class TestUtils(TestCase): - def test_splitbyx(self): - self.assertEqual(list(splitbyx(str(12), 3)), [12]) - self.assertEqual(list(splitbyx(str(1234), 3)), [1, 234]) - self.assertEqual(list(splitbyx(str(12345678900), 3)), - [12, 345, 678, 900] - ) - self.assertEqual(list(splitbyx(str(1000000), 6)), [1, 0]) - - self.assertEqual(list(splitbyx(str(12), 3, format_int=False)), ['12']) - self.assertEqual(list(splitbyx(str(1234), 3, format_int=False)), - ['1', '234'] - ) - self.assertEqual(list(splitbyx(str(12345678900), 3, format_int=False)), - ['12', '345', '678', '900'] - ) - self.assertEqual(list(splitbyx(str(1000000), 6, format_int=False)), - ['1', '000000'] - ) +# -*- 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 unittest import TestCase + +from num2words.utils import splitbyx + + +class TestUtils(TestCase): + def test_splitbyx(self): + self.assertEqual(list(splitbyx(str(12), 3)), [12]) + self.assertEqual(list(splitbyx(str(1234), 3)), [1, 234]) + self.assertEqual(list(splitbyx(str(12345678900), 3)), + [12, 345, 678, 900] + ) + self.assertEqual(list(splitbyx(str(1000000), 6)), [1, 0]) + + self.assertEqual(list(splitbyx(str(12), 3, format_int=False)), ['12']) + self.assertEqual(list(splitbyx(str(1234), 3, format_int=False)), + ['1', '234'] + ) + self.assertEqual(list(splitbyx(str(12345678900), 3, format_int=False)), + ['12', '345', '678', '900'] + ) + self.assertEqual(list(splitbyx(str(1000000), 6, format_int=False)), + ['1', '000000'] + ) diff --git a/tests/test_vi.py b/tests/test_vi.py index 51500d8..bba78ec 100644 --- a/tests/test_vi.py +++ b/tests/test_vi.py @@ -1,5 +1,6 @@ -# -*- encoding: utf-8 -*- -# Copyright (c) 2015, Savoir-faire Linux inc. All Rights Reserved. +# -*- 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 From 52fb935d8cf9570b977dbb2970f51356656b27dd Mon Sep 17 00:00:00 2001 From: Marek Madejski Date: Fri, 28 Dec 2018 11:57:12 +0100 Subject: [PATCH 16/23] PL: regular names for powers of thousand Names for powers of thousand are now built instead of being hardcoded - less error-prone and more concise. --- num2words/lang_PL.py | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/num2words/lang_PL.py b/num2words/lang_PL.py index 4b97a5f..2fa52f7 100644 --- a/num2words/lang_PL.py +++ b/num2words/lang_PL.py @@ -17,6 +17,8 @@ from __future__ import unicode_literals +import itertools + from .base import Num2Word_Base from .utils import get_digits, splitbyx @@ -71,29 +73,27 @@ HUNDREDS = { } THOUSANDS = { - 1: ('tysiąc', 'tysiące', 'tysięcy'), # 10^3 - 2: ('milion', 'miliony', 'milionów'), # 10^6 - 3: ('miliard', 'miliardy', 'miliardów'), # 10^9 - 4: ('bilion', 'biliony', 'bilionów'), # 10^12 - 5: ('biliard', 'biliardy', 'biliardów'), # 10^15 - 6: ('trylion', 'tryliony', 'trylionów'), # 10^18 - 7: ('tryliard', 'tryliardy', 'tryliardów'), # 10^21 - 8: ('kwadrylion', 'kwadryliony', 'kwadrylionów'), # 10^24 - 9: ('kwadryliard', 'kwadryliardy', 'kwadryliardów'), # 10^27 - 10: ('kwintylion', 'kwintyliony', 'kwintylionów'), # 10^30 - 11: ('kwintyliard', 'kwintyliardy', 'kwintyliardów'), # 10^33 - 12: ('sekstylion', 'sekstyliony', 'sekstylionów'), # 10^36 - 13: ('sekstyliard', 'sekstyliardy', 'sekstyliardów'), # 10^39 - 14: ('septylion', 'septyliony', 'septylionów'), # 10^42 - 15: ('septyliard', 'septyliardy', 'septyliardów'), # 10^45 - 16: ('oktylion', 'oktyliony', 'oktylionów'), # 10^48 - 17: ('oktyliard', 'oktyliardy', 'oktyliardów'), # 10^51 - 18: ('nonylion', 'nonyliony', 'nonylionów'), # 10^54 - 19: ('nonyliard', 'nonyliardy', 'nonyliardów'), # 10^57 - 20: ('decylion', 'decyliony', 'decylionów'), # 10^60 - 21: ('decyliard', 'decyliardy', 'decyliardów'), # 10^63 + 1: ('tysiąc', 'tysiące', 'tysięcy'), # 10^3 } +prefixes = ( # 10^(6*x) + "mi", # 10^6 + "bi", # 10^12 + "try", # 10^18 + "kwadry", # 10^24 + "kwinty", # 10^30 + "seksty", # 10^36 + "septy", # 10^42 + "okty", # 10^48 + "nony", # 10^54 + "decy" # 10^60 +) +suffixes = ("lion", "liard") # 10^x or 10^(x+3) + +for idx, (p, s) in enumerate(itertools.product(prefixes, suffixes)): + name = p + s + THOUSANDS[idx+2] = (name, name + 'y', name + 'ów') + class Num2Word_PL(Num2Word_Base): CURRENCY_FORMS = { From f2fb5bc67f2eb5f419f08b508dcb37da1500a545 Mon Sep 17 00:00:00 2001 From: Ernesto Rodriguez Ortiz Date: Thu, 10 Jan 2019 20:09:08 -0500 Subject: [PATCH 17/23] Release 0.5.9 --- CHANGES.rst | 7 +++++++ bin/num2words | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 0f15372..0cbd250 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,13 @@ Changelog ========= +Version 0.5.9 -- 2019/01/10 +--------------------------- + +* Fix encoding issue on release 0.5.8 (#229) +* Improve Polish localization (#228) + + Version 0.5.8 -- 2018/11/17 --------------------------- diff --git a/bin/num2words b/bin/num2words index 18e70a3..7c9d595 100755 --- a/bin/num2words +++ b/bin/num2words @@ -55,7 +55,7 @@ import sys from docopt import docopt import num2words -__version__ = "0.5.8" +__version__ = "0.5.9" __license__ = "LGPL" From 778786b65b5468f60a36d24394125893dfc643be Mon Sep 17 00:00:00 2001 From: Zeno Gantner Date: Sat, 12 Jan 2019 19:10:31 +0100 Subject: [PATCH 18/23] fix ordinal_num for French numbers ending with 1 (#236) --- num2words/lang_FR.py | 2 +- tests/test_fr.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/num2words/lang_FR.py b/num2words/lang_FR.py index 4524cb5..85ef87e 100644 --- a/num2words/lang_FR.py +++ b/num2words/lang_FR.py @@ -89,7 +89,7 @@ class Num2Word_FR(Num2Word_EU): def to_ordinal_num(self, value): self.verify_ordinal(value) out = str(value) - out += {"1": "er"}.get(out[-1], "me") + out += "er" if value == 1 else "me" return out def to_currency(self, val, longval=True, old=False): diff --git a/tests/test_fr.py b/tests/test_fr.py index 1299dcc..6170cb7 100644 --- a/tests/test_fr.py +++ b/tests/test_fr.py @@ -107,10 +107,13 @@ TEST_CASES_ORDINAL = ( TEST_CASES_ORDINAL_NUM = ( (1, '1er'), (8, '8me'), + (11, '11me'), (12, '12me'), (14, '14me'), + (21, '21me'), (28, '28me'), (100, '100me'), + (101, '101me'), (1000, '1000me'), (1000000, '1000000me') ) From 0398d164600c57e48f41697d588ef4150c40a9bb Mon Sep 17 00:00:00 2001 From: Zeno Gantner Date: Sun, 13 Jan 2019 23:04:10 +0100 Subject: [PATCH 19/23] German: 2 more ordinal tests --- tests/test_de.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_de.py b/tests/test_de.py index d20794d..2715e7f 100644 --- a/tests/test_de.py +++ b/tests/test_de.py @@ -23,7 +23,10 @@ from num2words import num2words class Num2WordsDETest(TestCase): + def test_ordinal_less_than_twenty(self): + self.assertEqual(num2words(0, ordinal=True, lang='de'), "nullte") + self.assertEqual(num2words(1, ordinal=True, lang='de'), "erste") self.assertEqual(num2words(7, ordinal=True, lang='de'), "siebte") self.assertEqual(num2words(8, ordinal=True, lang='de'), "achte") self.assertEqual(num2words(12, ordinal=True, lang='de'), "zwölfte") From df65296a80140ab645a251e8ab6f04cefeb04ca9 Mon Sep 17 00:00:00 2001 From: Zeno Gantner Date: Sun, 13 Jan 2019 23:18:51 +0100 Subject: [PATCH 20/23] German: similar rule for million as for 100 and 1000; 2 more ordinal tests --- num2words/lang_DE.py | 2 ++ tests/test_de.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/num2words/lang_DE.py b/num2words/lang_DE.py index f681697..23c6f68 100644 --- a/num2words/lang_DE.py +++ b/num2words/lang_DE.py @@ -118,6 +118,8 @@ class Num2Word_DE(Num2Word_EU): # Exception: "hundertste" is usually preferred over "einhundertste" if res == "eintausendste" or res == "einhundertste": res = res.replace("ein", "", 1) + if res == "eine millionste": + res = res.replace("eine ", "", 1) return res diff --git a/tests/test_de.py b/tests/test_de.py index 2715e7f..3b451af 100644 --- a/tests/test_de.py +++ b/tests/test_de.py @@ -47,6 +47,9 @@ class Num2WordsDETest(TestCase): self.assertEqual( num2words(4000, ordinal=True, lang='de'), "viertausendste" ) + self.assertEqual( + num2words(1000000, ordinal=True, lang='de'), "millionste" + ) self.assertEqual( num2words(2000000, ordinal=True, lang='de'), "zwei millionste" ) @@ -57,6 +60,7 @@ class Num2WordsDETest(TestCase): def test_cardinal_at_some_numbers(self): self.assertEqual(num2words(100, lang='de'), "einhundert") + self.assertEqual(num2words(1000000, lang='de'), "eine million") self.assertEqual(num2words(2000000, lang='de'), "zwei millionen") self.assertEqual(num2words(4000000000, lang='de'), "vier milliarden") self.assertEqual(num2words(1000000000, lang='de'), "eine milliarde") From e321caf392ac9c61b89301c33926068deb046ff5 Mon Sep 17 00:00:00 2001 From: Zeno Gantner Date: Sun, 13 Jan 2019 23:25:54 +0100 Subject: [PATCH 21/23] Million etc. are upper case in German --- num2words/lang_DE.py | 4 ++-- tests/test_de.py | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/num2words/lang_DE.py b/num2words/lang_DE.py index 23c6f68..ced8312 100644 --- a/num2words/lang_DE.py +++ b/num2words/lang_DE.py @@ -45,7 +45,7 @@ class Num2Word_DE(Num2Word_EU): self.errmsg_toobig = "Die Zahl %s muss kleiner als %s sein." self.exclude_title = [] - lows = ["non", "okt", "sept", "sext", "quint", "quadr", "tr", "b", "m"] + lows = ["Non", "Okt", "Sept", "Sext", "Quint", "Quadr", "Tr", "B", "M"] units = ["", "un", "duo", "tre", "quattuor", "quin", "sex", "sept", "okto", "novem"] tens = ["dez", "vigint", "trigint", "quadragint", "quinquagint", @@ -118,7 +118,7 @@ class Num2Word_DE(Num2Word_EU): # Exception: "hundertste" is usually preferred over "einhundertste" if res == "eintausendste" or res == "einhundertste": res = res.replace("ein", "", 1) - if res == "eine millionste": + if res == "eine Millionste": res = res.replace("eine ", "", 1) return res diff --git a/tests/test_de.py b/tests/test_de.py index 3b451af..f8ab13e 100644 --- a/tests/test_de.py +++ b/tests/test_de.py @@ -48,22 +48,22 @@ class Num2WordsDETest(TestCase): num2words(4000, ordinal=True, lang='de'), "viertausendste" ) self.assertEqual( - num2words(1000000, ordinal=True, lang='de'), "millionste" + num2words(1000000, ordinal=True, lang='de'), "Millionste" ) self.assertEqual( - num2words(2000000, ordinal=True, lang='de'), "zwei millionste" + num2words(2000000, ordinal=True, lang='de'), "zwei Millionste" ) self.assertEqual( num2words(5000000000, ordinal=True, lang='de'), - "fünf milliardste" + "fünf Milliardste" ) def test_cardinal_at_some_numbers(self): self.assertEqual(num2words(100, lang='de'), "einhundert") - self.assertEqual(num2words(1000000, lang='de'), "eine million") - self.assertEqual(num2words(2000000, lang='de'), "zwei millionen") - self.assertEqual(num2words(4000000000, lang='de'), "vier milliarden") - self.assertEqual(num2words(1000000000, lang='de'), "eine milliarde") + self.assertEqual(num2words(1000000, lang='de'), "eine Million") + self.assertEqual(num2words(2000000, lang='de'), "zwei Millionen") + self.assertEqual(num2words(4000000000, lang='de'), "vier Milliarden") + self.assertEqual(num2words(1000000000, lang='de'), "eine Milliarde") def test_cardinal_for_decimal_number(self): self.assertEqual( @@ -73,8 +73,8 @@ class Num2WordsDETest(TestCase): def test_giant_cardinal_for_merge(self): self.assertEqual( num2words(4500072900000111, lang='de'), - "vier billiarden fünfhundert billionen " + - "zweiundsiebzig milliarden neunhundert millionen einhundertelf" + "vier Billiarden fünfhundert Billionen " + + "zweiundsiebzig Milliarden neunhundert Millionen einhundertelf" ) def test_ordinal_num(self): From b71facf3ea377ed8bdc1278ea010f3af05f3dd2c Mon Sep 17 00:00:00 2001 From: Zeno Gantner Date: Sun, 13 Jan 2019 23:55:34 +0100 Subject: [PATCH 22/23] German: ordinals involving 'Million' etc. are written without space, and lower case --- num2words/lang_DE.py | 13 ++++++++++--- tests/test_de.py | 9 ++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/num2words/lang_DE.py b/num2words/lang_DE.py index ced8312..348b44f 100644 --- a/num2words/lang_DE.py +++ b/num2words/lang_DE.py @@ -17,6 +17,8 @@ from __future__ import print_function, unicode_literals +import re + from .lang_EU import Num2Word_EU @@ -107,7 +109,7 @@ class Num2Word_DE(Num2Word_EU): def to_ordinal(self, value): self.verify_ordinal(value) - outword = self.to_cardinal(value) + outword = self.to_cardinal(value).lower() for key in self.ords: if outword.endswith(key): outword = outword[:len(outword) - len(key)] + self.ords[key] @@ -118,8 +120,13 @@ class Num2Word_DE(Num2Word_EU): # Exception: "hundertste" is usually preferred over "einhundertste" if res == "eintausendste" or res == "einhundertste": res = res.replace("ein", "", 1) - if res == "eine Millionste": - res = res.replace("eine ", "", 1) + # ... similarly for "millionste" etc. + res = re.sub(r'eine ([a-z]+(illion|illiard)ste)$', + lambda m: m.group(1), res) + # Ordinals involving "Million" etc. are written without a space. + # see https://de.wikipedia.org/wiki/Million#Sprachliches + res = re.sub(r' ([a-z]+(illion|illiard)ste)$', + lambda m: m.group(1), res) return res diff --git a/tests/test_de.py b/tests/test_de.py index f8ab13e..7635cfb 100644 --- a/tests/test_de.py +++ b/tests/test_de.py @@ -48,14 +48,17 @@ class Num2WordsDETest(TestCase): num2words(4000, ordinal=True, lang='de'), "viertausendste" ) self.assertEqual( - num2words(1000000, ordinal=True, lang='de'), "Millionste" + num2words(1000000, ordinal=True, lang='de'), "millionste" ) self.assertEqual( - num2words(2000000, ordinal=True, lang='de'), "zwei Millionste" + num2words(2000000, ordinal=True, lang='de'), "zweimillionste" + ) + self.assertEqual( + num2words(1000000000, ordinal=True, lang='de'), "milliardste" ) self.assertEqual( num2words(5000000000, ordinal=True, lang='de'), - "fünf Milliardste" + "fünfmilliardste" ) def test_cardinal_at_some_numbers(self): From 67d58e708131cb12de2d2f1df46d614696123342 Mon Sep 17 00:00:00 2001 From: Zeno Gantner Date: Sun, 13 Jan 2019 23:57:57 +0100 Subject: [PATCH 23/23] German: add 3 more test cases for thousands --- tests/test_de.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_de.py b/tests/test_de.py index 7635cfb..2e50e5c 100644 --- a/tests/test_de.py +++ b/tests/test_de.py @@ -63,6 +63,9 @@ class Num2WordsDETest(TestCase): def test_cardinal_at_some_numbers(self): self.assertEqual(num2words(100, lang='de'), "einhundert") + self.assertEqual(num2words(1000, lang='de'), "eintausend") + self.assertEqual(num2words(5000, lang='de'), "fünftausend") + self.assertEqual(num2words(10000, lang='de'), "zehntausend") self.assertEqual(num2words(1000000, lang='de'), "eine Million") self.assertEqual(num2words(2000000, lang='de'), "zwei Millionen") self.assertEqual(num2words(4000000000, lang='de'), "vier Milliarden")