From 2da1f924dfd49c57a9fa841bd39a6583564badbd Mon Sep 17 00:00:00 2001 From: Michal Juranyi Date: Sun, 3 Sep 2023 20:39:47 +0200 Subject: [PATCH] Add Slovak language support Signed-off-by: Michal Juranyi --- num2words/__init__.py | 5 +- num2words/lang_SK.py | 160 ++++++++++++++++++++++++++++++++++++++++++ tests/test_sk.py | 98 ++++++++++++++++++++++++++ 3 files changed, 261 insertions(+), 2 deletions(-) create mode 100644 num2words/lang_SK.py create mode 100644 tests/test_sk.py diff --git a/num2words/__init__.py b/num2words/__init__.py index 0942928f..53a28591 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -23,8 +23,8 @@ lang_FR_BE, lang_FR_CH, lang_FR_DZ, lang_HE, lang_HU, lang_ID, lang_IS, lang_IT, lang_JA, lang_KN, lang_KO, lang_KZ, lang_LT, lang_LV, lang_NL, lang_NO, lang_PL, lang_PT, lang_PT_BR, - lang_RO, lang_RU, lang_SL, lang_SR, lang_SV, lang_TE, lang_TG, - lang_TH, lang_TR, lang_UK, lang_VI) + lang_RO, lang_RU, lang_SK, lang_SL, lang_SR, lang_SV, lang_TE, + lang_TG, lang_TH, lang_TR, lang_UK, lang_VI) CONVERTER_CLASSES = { 'am': lang_AM.Num2Word_AM(), @@ -57,6 +57,7 @@ 'pl': lang_PL.Num2Word_PL(), 'ro': lang_RO.Num2Word_RO(), 'ru': lang_RU.Num2Word_RU(), + 'sk': lang_SK.Num2Word_SK(), 'sl': lang_SL.Num2Word_SL(), 'sr': lang_SR.Num2Word_SR(), 'sv': lang_SV.Num2Word_SV(), diff --git a/num2words/lang_SK.py b/num2words/lang_SK.py new file mode 100644 index 00000000..35ece024 --- /dev/null +++ b/num2words/lang_SK.py @@ -0,0 +1,160 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA + +from __future__ import unicode_literals + +from .base import Num2Word_Base +from .utils import get_digits, splitbyx + +ZERO = ('nula',) + +ONES = { + 1: ('jeden', 'jeden', set()), + 2: ('dva', 'dve', {1, 3, 5, 7, 9}), + 3: ('tri', 'tri', set()), + 4: ('štyri', 'štyri', set()), + 5: ('päť', 'päť', set()), + 6: ('šesť', 'šesť', set()), + 7: ('sedem', 'sedem', set()), + 8: ('osem', 'osem', set()), + 9: ('deväť', 'deväť', set()), +} + +TENS = { + 0: ('desať',), + 1: ('jedenásť',), + 2: ('dvanásť',), + 3: ('trinásť',), + 4: ('štrnásť',), + 5: ('pätnásť',), + 6: ('šestnásť',), + 7: ('sedemnásť',), + 8: ('osemnásť',), + 9: ('devätnásť',), +} + +TWENTIES = { + 2: ('dvadsať',), + 3: ('tridsať',), + 4: ('štyridsať',), + 5: ('päťdesiat',), + 6: ('šesťdesiat',), + 7: ('sedemdesiat',), + 8: ('osemdesiat',), + 9: ('deväťdesiat',), +} + +HUNDREDS = { + 1: ('sto',), + 2: ('dvesto',), + 3: ('tristo',), + 4: ('štyristo',), + 5: ('päťsto',), + 6: ('šesťsto',), + 7: ('sedemsto',), + 8: ('osemsto',), + 9: ('deväťsto',), +} + +THOUSANDS = { + 1: ('tisíc', 'tisíc', 'tisíc'), # 10^3 + 2: ('milión', 'milióny', 'miliónov'), # 10^6 + 3: ('miliarda', 'miliardy', 'miliárd'), # 10^9 + 4: ('bilión', 'bilióny', 'biliónov'), # 10^12 + 5: ('biliarda', 'biliardy', 'biliárd'), # 10^15 + 6: ('trilión', 'trilióny', 'triliónov'), # 10^18 + 7: ('triliarda', 'triliardy', 'triliárd'), # 10^21 + 8: ('kvadrilión', 'kvadrilióny', 'kvadriliónov'), # 10^24 + 9: ('kvadriliarda', 'kvadriliardy', 'kvadriliárd'), # 10^27 + 10: ('kvintilión', 'kvintillióny', 'kvintiliónov'), # 10^30 +} + + +class Num2Word_SK(Num2Word_Base): + CURRENCY_FORMS = { + 'EUR': ( + ('euro', 'eurá', 'eur'), ('cent', 'centy', 'centov') + ), + } + + def setup(self): + self.negword = "mínus" + self.pointword = "celých" + + def to_cardinal(self, number): + n = str(number).replace(',', '.') + if '.' in n: + left, right = n.split('.') + leading_zero_count = len(right) - len(right.lstrip('0')) + decimal_part = ((ZERO[0] + ' ') * leading_zero_count + + self._int2word(int(right))) + return u'%s %s %s' % ( + self._int2word(int(left)), + self.pointword, + decimal_part + ) + else: + return self._int2word(int(n)) + + def pluralize(self, n, forms): + if n == 1: + form = 0 + elif 0 < n < 5: + form = 1 + else: + form = 2 + return forms[form] + + def to_ordinal(self, value): + 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) + + word_chunk = [] + + if n3 > 0: + word_chunk.append(HUNDREDS[n3][0]) + + if n2 > 1: + word_chunk.append(TWENTIES[n2][0]) + + if n2 == 1: + word_chunk.append(TENS[n1][0]) + elif n1 > 0 and not (i > 0 and x == 1): + if n2 == 0 and n3 == 0 and i in ONES[n1][2]: + word_chunk.append(ONES[n1][1]) + else: + word_chunk.append(ONES[n1][0]) + if i > 1 and word_chunk: + word_chunk.append(' ') + if i > 0: + word_chunk.append(self.pluralize(x, THOUSANDS[i])) + words.append(''.join(word_chunk)) + + return ' '.join(words[:-1]) + ''.join(words[-1:]) diff --git a/tests/test_sk.py b/tests/test_sk.py new file mode 100644 index 00000000..314a7c2b --- /dev/null +++ b/tests/test_sk.py @@ -0,0 +1,98 @@ + +# -*- 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 Num2WordsSKTest(TestCase): + def test_cardinal(self): + self.assertEqual(num2words(100, lang='sk'), "sto") + self.assertEqual(num2words(101, lang='sk'), "stojeden") + self.assertEqual(num2words(110, lang='sk'), "stodesať") + self.assertEqual(num2words(115, lang='sk'), "stopätnásť") + self.assertEqual(num2words(123, lang='sk'), "stodvadsaťtri") + self.assertEqual(num2words(1000, lang='sk'), "tisíc") + self.assertEqual(num2words(1001, lang='sk'), "tisícjeden") + self.assertEqual(num2words(2012, lang='sk'), "dvetisícdvanásť") + self.assertEqual( + num2words(10.02, lang='sk'), + "desať celých nula dva" + ) + self.assertEqual( + num2words(15.007, lang='sk'), + "pätnásť celých nula nula sedem" + ) + self.assertEqual( + num2words(12519.85, lang='sk'), + "dvanásťtisícpäťstodevätnásť celých osemdesiatpäť" + ) + self.assertEqual( + num2words(123.50, lang='sk'), + "stodvadsaťtri celých päť" + ) + self.assertEqual( + num2words(1234567890, lang='sk'), + "miliarda dvestotridsaťštyri miliónov päťstošesťdesiat" + "sedemtisícosemstodeväťdesiat" + ) + self.assertEqual( + num2words(215461407892039002157189883901676, lang='sk'), + "dvestopätnásť kvintiliónov štyristošesťdesiatjeden kvadriliárd " + "štyristosedem kvadriliónov osemstodeväťdesiatdva triliárd " + "tridsaťdeväť triliónov dve biliardy stopäťdesiatsedem biliónov " + "stoosemdesiatdeväť miliárd osemstoosemdesiattri miliónov " + "deväťstojedentisícšesťstosedemdesiatšesť" + ) + self.assertEqual( + num2words(719094234693663034822824384220291, lang='sk'), + "sedemstodevätnásť kvintiliónov deväťdesiatštyri kvadriliárd " + "dvestotridsaťštyri kvadriliónov šesťstodeväťdesiattri triliárd " + "šesťstošesťdesiattri triliónov tridsaťštyri biliárd " + "osemstodvadsaťdva biliónov osemstodvadsaťštyri miliárd " + "tristoosemdesiatštyri miliónov " + "dvestodvadsaťtisícdvestodeväťdesiatjeden" + ) + + def test_to_ordinal(self): + # @TODO: implement to_ordinal + with self.assertRaises(NotImplementedError): + num2words(1, lang='sk', to='ordinal') + + def test_currency(self): + self.assertEqual( + num2words(10.0, lang='sk', to='currency', currency='EUR'), + "desať eur, nula centov") + self.assertEqual( + num2words(1234.56, lang='sk', to='currency', currency='EUR'), + "tisícdvestotridsaťštyri eur, päťdesiatšesť centov") + self.assertEqual( + num2words(101.11, lang='sk', to='currency', currency='EUR', + separator=' a'), + "stojeden eur a jedenásť centov") + self.assertEqual( + num2words(-12519.85, lang='sk', to='currency', cents=False), + "mínus dvanásťtisícpäťstodevätnásť eur, 85 centov" + ) + self.assertEqual( + num2words(19.50, lang='sk', to='currency', cents=False), + "devätnásť eur, 50 centov" + )