diff --git a/README.rst b/README.rst index 7e7902b..86a8002 100644 --- a/README.rst +++ b/README.rst @@ -97,8 +97,9 @@ Besides the numerical argument, there are two main optional arguments. * ``no`` (Norwegian) * ``pl`` (Polish) * ``pt_BR`` (Portuguese - Brazilian) -* ``sl`` (Slovene) +* ``ro`` (Romanian) * ``ru`` (Russian) +* ``sl`` (Slovene) * ``tr`` (Turkish) * ``th`` (Thai) * ``vi`` (Vietnamese) diff --git a/num2words/__init__.py b/num2words/__init__.py index bd5af2a..e06c19c 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -30,6 +30,7 @@ from . import lang_FI from . import lang_LT from . import lang_LV from . import lang_PL +from . import lang_RO from . import lang_RU from . import lang_ID from . import lang_JA @@ -66,6 +67,7 @@ CONVERTER_CLASSES = { '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(), 'no': lang_NO.Num2Word_NO(), diff --git a/num2words/lang_EU.py b/num2words/lang_EU.py index fc804f3..c0af59a 100644 --- a/num2words/lang_EU.py +++ b/num2words/lang_EU.py @@ -41,6 +41,7 @@ class Num2Word_EU(Num2Word_Base): 'NOK': (('krone', 'kroner'), ('øre', 'øre')), 'PLN': (('zloty', 'zlotys', 'zlotu'), ('grosz', 'groszy')), 'MXN': (('peso', 'pesos'), GENERIC_CENTS), + 'RON': (('leu', 'lei'), ('ban', 'bani')), } CURRENCY_ADJECTIVES = { @@ -51,6 +52,7 @@ class Num2Word_EU(Num2Word_Base): 'RUB': 'Russian', 'NOK': 'Norwegian', 'MXN': 'Mexican', + 'RON': 'Romanian', } GIGA_SUFFIX = "illiard" diff --git a/num2words/lang_RO.py b/num2words/lang_RO.py new file mode 100644 index 0000000..8ab3c3a --- /dev/null +++ b/num2words/lang_RO.py @@ -0,0 +1,136 @@ +# -*- 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 division, print_function, unicode_literals + +from . import lang_EU + + +class Num2Word_RO(lang_EU.Num2Word_EU): + GIGA_SUFFIX = "iliard/e" + MEGA_SUFFIX = "ilion" + # inflection for million follows different rule + MEGA_SUFFIX_I = "ilioane" + + def setup(self): + super(Num2Word_RO, self).setup() + + self.negword = "minus " + self.pointword = "virgulă" + self.exclude_title = ["și", "virgulă", "minus"] + self.errmsg_toobig = ( + "Numărul e prea mare pentru a fi convertit în cuvinte." + ) + self.mid_numwords = [(1000, "mie/i"), (100, "sută/e"), + (90, "nouăzeci"), (80, "optzeci"), + (70, "șaptezeci"), (60, "șaizeci"), + (50, "cincizeci"), (40, "patruzeci"), + (30, "treizeci")] + self.low_numwords = ["douăzeci", "nouăsprezece", "optsprezece", + "șaptesprezece", "șaisprezece", "cincisprezece", + "paisprezece", "treisprezece", "doisprezece", + "unsprezece", "zece", "nouă", "opt", "șapte", + "șase", "cinci", "patru", "trei", "doi", + "unu", "zero"] + self.gen_numwords = ["", "o", "două", "trei", "patru", "cinci", + "șase", "șapte", "opt", "nouă"] + self.gen_numwords_m = ["", "un", "două", "trei", "patru", "cinci", + "șase", "șapte", "opt", "nouă"] + self.numwords_inflections = { + 100: self.gen_numwords, + 1000: self.gen_numwords, + 1000000: self.gen_numwords_m, + 1000000000: self.gen_numwords_m + } + self.ords = {"unu": "primul", + "doi": "al doilea", + "three": "al treilea", + "cinci": "al cincilea", + "opt": "al optulea", + "nouă": "al nouălea", + "doisprezece": "al doisprezecelea"} + + def merge(self, lpair, rpair): + ltext, lnum = lpair + rtext, rnum = rpair + rtext_i = self.inflect(rnum, rtext) + if lnum > 1 and rtext_i.endswith(self.MEGA_SUFFIX): + rtext_i = rtext_i.replace(self.MEGA_SUFFIX, self.MEGA_SUFFIX_I) + if 1 <= lnum < 10: + if rnum not in self.numwords_inflections: + return (rtext, rnum) + else: + rtext_i = self.inflect(lnum * rnum, rtext) + lresult = (self.numwords_inflections[rnum][lnum], rtext_i) + return ("%s %s" % lresult, rnum) + elif 10 < lnum < 100: + if lnum % 10 == 0: + return ("%s și %s" % (ltext, rtext), lnum + rnum) + else: + return ("%s %s" % (ltext, rtext_i), lnum * rnum) + else: + if rnum in self.numwords_inflections: + rtext_i = self.inflect(lnum * rnum, rtext) + return ("%s %s" % (ltext, rtext_i), lnum * rnum) + + def to_ordinal(self, value): + self.verify_ordinal(value) + if value == 1: + return "primul" + else: + value = self.to_cardinal(value) + return "al %slea" % (value) + + def to_ordinal_num(self, value): + self.verify_ordinal(value) + if value == 1: + return "1-ul" + return "al %s-lea" % (value) + + def inflect(self, value, text): + text = text.split("/") + if value in (1, 100, 1000, 100000, 1000000000): + return text[0] + if len(text) > 1 and text[0][-1] in "aăeiou": + text[0] = text[0][:-1] + return "".join(text) + + def to_currency(self, val, longval=True, old=False): + cents = int(round(val*100)) + result = self.to_splitnum(cents, hightxt="leu/i", lowtxt="ban/i", + divisor=100, jointxt="și", longval=longval) + return result.replace( + "unu leu", "un leu" + ).replace("unu ban", "un ban") + + def to_year(self, val, suffix=None, longval=True): + result = super(Num2Word_RO, self).to_year( + val, + longval=longval + ) + # for years we want the era negation e.g. B.C., in our case + # it's î.Hr. or î.e.n + if result.startswith(self.negword): + result = result.replace(self.negword, "") + suffix = "î.Hr." if not suffix else suffix + if suffix: + result = "".join([ + result, + " ", + suffix + ]) + return result diff --git a/tests/test_ro.py b/tests/test_ro.py new file mode 100644 index 0000000..4422ca2 --- /dev/null +++ b/tests/test_ro.py @@ -0,0 +1,172 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA + +from unittest import TestCase + +from num2words import num2words + + +class Num2WordsROTest(TestCase): + + def test_ordinal(self): + self.assertEqual( + num2words(1, lang='ro', to='ordinal'), + 'primul' + ) + self.assertEqual( + num2words(22, lang='ro', to='ordinal'), + u'al douăzeci și doilea' + ) + self.assertEqual( + num2words(21, lang='ro', to='ordinal'), + u'al douăzeci și unulea' + ) + self.assertEqual( + num2words(12, lang='ro', to='ordinal'), + u'al doisprezecelea' + ) + self.assertEqual( + num2words(130, lang='ro', to='ordinal'), + u'al o sută treizecilea' + ) + self.assertEqual( + num2words(1003, lang='ro', to='ordinal'), + u'al o mie treilea' + ) + + def test_ordinal_num(self): + self.assertEqual( + num2words(1, lang='ro', to='ordinal_num'), + '1-ul' + ) + self.assertEqual( + num2words(10, lang='ro', to='ordinal_num'), + 'al 10-lea' + ) + self.assertEqual(num2words( + 21, lang='ro', to='ordinal_num'), + 'al 21-lea' + ) + self.assertEqual( + num2words(102, lang='ro', to='ordinal_num'), + 'al 102-lea' + ) + self.assertEqual( + num2words(73, lang='ro', to='ordinal_num'), + 'al 73-lea' + ) + + def test_cardinal_for_float_number(self): + self.assertEqual( + num2words(12.5, lang='ro'), + u'doisprezece virgulă cinci' + ) + self.assertEqual( + num2words(12.51, lang='ro'), + u'doisprezece virgulă cinci unu' + ) + self.assertEqual( + num2words(12.53, lang='ro'), + u'doisprezece virgulă cinci trei' + ) + self.assertEqual( + num2words(12.59, lang='ro'), + u'doisprezece virgulă cinci nouă' + ) + + def test_big_numbers(self): + self.assertEqual( + num2words(1000000, lang="ro"), + u"un milion" + ) + self.assertEqual( + num2words(1000000000, lang="ro"), + u"un miliard" + ) + self.assertEqual( + num2words(33000000, lang="ro"), + u"treizeci și trei milioane" + ) + self.assertEqual( + num2words(247000000000, lang="ro"), + u"două sute patruzeci și șapte miliarde" + ) + + def test_overflow(self): + with self.assertRaises(OverflowError): + num2words("100000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000") + + def test_to_currency(self): + self.assertEqual( + num2words(38.4, lang='ro', to='currency'), + u'treizeci și opt lei și patruzeci bani' + ) + + self.assertEqual( + num2words(1.01, lang='ro', to='currency'), + u'un leu și un ban' + ) + + self.assertEqual( + num2words(4778.00, lang='ro', to='currency'), + u'patru mii șapte sute șaptezeci și opt lei') + + self.assertEqual( + num2words(4778.32, lang='ro', to='currency'), + u'patru mii șapte sute șaptezeci și opt lei' + u' și treizeci și doi bani') + + def test_to_year(self): + self.assertEqual(num2words(1989, lang='ro', to='year'), + u'o mie nouă sute optzeci și nouă') + self.assertEqual(num2words(1984, lang='ro', to='year'), + u'o mie nouă sute optzeci și patru') + self.assertEqual(num2words(2018, lang='ro', to='year'), + u'două mii optsprezece') + self.assertEqual(num2words(1066, lang='ro', to='year'), + u'o mie șaizeci și șase') + self.assertEqual(num2words(5000, lang='ro', to='year'), + u'cinci mii') + self.assertEqual(num2words(2001, lang='ro', to='year'), + u'două mii unu') + self.assertEqual(num2words(905, lang='ro', to='year'), + u'nouă sute cinci') + self.assertEqual(num2words(6600, lang='ro', to='year'), + u'șase mii șase sute') + self.assertEqual(num2words(1600, lang='ro', to='year'), + u'o mie șase sute') + self.assertEqual(num2words(700, lang='ro', to='year'), + u'șapte sute') + self.assertEqual(num2words(50, lang='ro', to='year'), + u'cincizeci') + self.assertEqual(num2words(0, lang='ro', to='year'), + u'zero') + self.assertEqual(num2words(10, lang='ro', to='year'), + u'zece') + # suffixes + self.assertEqual(num2words(-44, lang='ro', to='year'), + u'patruzeci și patru î.Hr.') + self.assertEqual(num2words(-44, lang='ro', to='year', + suffix=u'î.e.n.'), u'patruzeci și patru î.e.n.') + self.assertEqual(num2words(1, lang='ro', to='year', suffix='d.Hr.'), + u'unu d.Hr.') + self.assertEqual(num2words(-66000000, lang='ro', to='year'), + u'șaizeci și șase milioane î.Hr.')