Add Romanian support (#215)

* romanian-support: start implementation

* romanian-support: implement basic merge and to_ordinal

* romanian-support: fix linting error

* romaniansupport: fix spacing for linter

* romanian-support: correct indent of error message

* romanian-support: add encoding to test file

* romanian-support: python2 fix: make strings in test unicode

* romanian-support: complete rough implementation

* romanian-support: pylint fixes

* romanian-support: fix tests for python2

* romanian-support: small fixes

* romanian-support: add romanian to readme

* ensure alphabetical order in readme
This commit is contained in:
mariaS210
2018-10-17 16:56:40 +03:00
committed by Ernesto Rodriguez Ortiz
parent 3544e49376
commit ca61c77f3b
5 changed files with 314 additions and 1 deletions

View File

@@ -97,8 +97,9 @@ Besides the numerical argument, there are two main optional arguments.
* ``no`` (Norwegian) * ``no`` (Norwegian)
* ``pl`` (Polish) * ``pl`` (Polish)
* ``pt_BR`` (Portuguese - Brazilian) * ``pt_BR`` (Portuguese - Brazilian)
* ``sl`` (Slovene) * ``ro`` (Romanian)
* ``ru`` (Russian) * ``ru`` (Russian)
* ``sl`` (Slovene)
* ``tr`` (Turkish) * ``tr`` (Turkish)
* ``th`` (Thai) * ``th`` (Thai)
* ``vi`` (Vietnamese) * ``vi`` (Vietnamese)

View File

@@ -30,6 +30,7 @@ from . import lang_FI
from . import lang_LT from . import lang_LT
from . import lang_LV from . import lang_LV
from . import lang_PL from . import lang_PL
from . import lang_RO
from . import lang_RU from . import lang_RU
from . import lang_ID from . import lang_ID
from . import lang_JA from . import lang_JA
@@ -66,6 +67,7 @@ CONVERTER_CLASSES = {
'lt': lang_LT.Num2Word_LT(), 'lt': lang_LT.Num2Word_LT(),
'lv': lang_LV.Num2Word_LV(), 'lv': lang_LV.Num2Word_LV(),
'pl': lang_PL.Num2Word_PL(), 'pl': lang_PL.Num2Word_PL(),
'ro': lang_RO.Num2Word_RO(),
'ru': lang_RU.Num2Word_RU(), 'ru': lang_RU.Num2Word_RU(),
'sl': lang_SL.Num2Word_SL(), 'sl': lang_SL.Num2Word_SL(),
'no': lang_NO.Num2Word_NO(), 'no': lang_NO.Num2Word_NO(),

View File

@@ -41,6 +41,7 @@ class Num2Word_EU(Num2Word_Base):
'NOK': (('krone', 'kroner'), ('øre', 'øre')), 'NOK': (('krone', 'kroner'), ('øre', 'øre')),
'PLN': (('zloty', 'zlotys', 'zlotu'), ('grosz', 'groszy')), 'PLN': (('zloty', 'zlotys', 'zlotu'), ('grosz', 'groszy')),
'MXN': (('peso', 'pesos'), GENERIC_CENTS), 'MXN': (('peso', 'pesos'), GENERIC_CENTS),
'RON': (('leu', 'lei'), ('ban', 'bani')),
} }
CURRENCY_ADJECTIVES = { CURRENCY_ADJECTIVES = {
@@ -51,6 +52,7 @@ class Num2Word_EU(Num2Word_Base):
'RUB': 'Russian', 'RUB': 'Russian',
'NOK': 'Norwegian', 'NOK': 'Norwegian',
'MXN': 'Mexican', 'MXN': 'Mexican',
'RON': 'Romanian',
} }
GIGA_SUFFIX = "illiard" GIGA_SUFFIX = "illiard"

136
num2words/lang_RO.py Normal file
View File

@@ -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

172
tests/test_ro.py Normal file
View File

@@ -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.')