diff --git a/CHANGES.rst b/CHANGES.rst index 9d3015d..0cbd250 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,32 @@ 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 +--------------------------- + +* 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/README.rst b/README.rst index f50823f..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 @@ -97,12 +95,15 @@ Besides the numerical argument, there are two main optional arguments. * ``id`` (Indonesian) * ``it`` (Italian) * ``ja`` (Japanese) +* ``ko`` (Korean) * ``lt`` (Lithuanian) * ``lv`` (Latvian) * ``no`` (Norwegian) * ``pl`` (Polish) * ``pt`` (Portuguese) * ``pt_BR`` (Portuguese - Brazilian) +* ``sl`` (Slovene) +* ``sr`` (Serbian) * ``ro`` (Romanian) * ``ru`` (Russian) * ``sl`` (Slovene) diff --git a/bin/num2words b/bin/num2words index 9c6df8a..7c9d595 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,13 +48,14 @@ Examples: $num2words 2.14 -l es --to currency dos euros con catorce centimos """ + from __future__ import print_function, unicode_literals import os import sys from docopt import docopt import num2words -__version__ = "0.5.7" +__version__ = "0.5.9" __license__ = "LGPL" 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 a2c18b6..6df724c 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. @@ -47,7 +48,9 @@ from . import lang_TR from . import lang_NL 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(), @@ -65,12 +68,14 @@ 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(), '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/base.py b/num2words/base.py index c73f741..de28116 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 0a29049..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 @@ -130,6 +131,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: diff --git a/num2words/lang_DE.py b/num2words/lang_DE.py index ca993bb..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 @@ -45,7 +47,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", @@ -78,7 +80,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" @@ -105,26 +109,47 @@ 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] 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) + # ... 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 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/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..85ef87e 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. @@ -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/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 3789cc5..d98a84a 100644 --- a/num2words/lang_HE.py +++ b/num2words/lang_HE.py @@ -1,148 +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 - n1, n2, n3 = get_digits(x) - - # print str(n3) + str(n2) + str(n1) - - 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_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/num2words/lang_LT.py b/num2words/lang_LT.py index ddd003e..8c6623e 100644 --- a/num2words/lang_LT.py +++ b/num2words/lang_LT.py @@ -1,175 +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 - 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 d1bd934..289c37f 100644 --- a/num2words/lang_LV.py +++ b/num2words/lang_LV.py @@ -1,182 +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 - 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 and x != 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 4289177..2fa52f7 100644 --- a/num2words/lang_PL.py +++ b/num2words/lang_PL.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,8 +14,11 @@ # 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 +import itertools + from .base import Num2Word_Base from .utils import get_digits, splitbyx @@ -66,22 +69,31 @@ HUNDREDS = { 6: ('sześćset',), 7: ('siedemset',), 8: ('osiemset',), - 9: ('dziewęćset',), + 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: ('kwaryliard', 'kwadryliardy', 'kwadryliardów'), # 10^27 - 10: ('kwintylion', 'kwintyliony', 'kwintylionów'), # 10^30 } +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 = { @@ -130,6 +142,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: 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 349657a..3b02526 100644 --- a/num2words/lang_RU.py +++ b/num2words/lang_RU.py @@ -1,229 +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 - 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 and x != 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 new file mode 100644 index 0000000..919cad0 --- /dev/null +++ b/num2words/lang_SR.py @@ -0,0 +1,216 @@ +# -*- 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 .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/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 b751bed..45f8712 100644 --- a/num2words/lang_UK.py +++ b/num2words/lang_UK.py @@ -1,174 +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 - 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 and ((n1 + n2 + n3) > 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 638331a..00fc50c 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 0388b21..2e50e5c 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 @@ -22,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") @@ -44,17 +48,28 @@ class Num2WordsDETest(TestCase): num2words(4000, ordinal=True, lang='de'), "viertausendste" ) self.assertEqual( - num2words(2000000, ordinal=True, lang='de'), "zwei millionste" + num2words(1000000, ordinal=True, lang='de'), "millionste" + ) + self.assertEqual( + 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): - 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(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") + self.assertEqual(num2words(1000000000, lang='de'), "eine Milliarde") def test_cardinal_for_decimal_number(self): self.assertEqual( @@ -64,8 +79,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 hundertelf" + "vier Billiarden fünfhundert Billionen " + + "zweiundsiebzig Milliarden neunhundert Millionen einhundertelf" ) def test_ordinal_num(self): @@ -79,12 +94,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'), 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..6170cb7 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 @@ -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') ) 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 new file mode 100644 index 0000000..c98ad88 --- /dev/null +++ b/tests/test_ko.py @@ -0,0 +1,93 @@ +# -*- 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 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) diff --git a/tests/test_lt.py b/tests/test_lt.py index 3424548..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 @@ -53,9 +69,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..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 @@ -48,9 +64,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") 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 c8a8462..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 @@ -45,6 +46,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 " @@ -52,7 +57,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'), @@ -64,6 +69,18 @@ class Num2WordsPLTest(TestCase): "osiemdziesiąt cztery miliony dwieście dwadzieścia " "tysięcy dwieście dziewięćdzisiąt jeden" ) + self.assertEqual( + num2words( + 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 " + "sekstyliard czterdzieści siedem sekstylionów sto czterdzieści " + "sześć kwintyliardów sto dwa kwintyliony tysiąc siedem" + ) def test_to_ordinal(self): # @TODO: implement to_ordinal 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 new file mode 100644 index 0000000..8547325 --- /dev/null +++ b/tests/test_sr.py @@ -0,0 +1,243 @@ +# -*- 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 + + +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'), + ) 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