Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spanish: add support to grammatical gender / spelling #617

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 28 additions & 20 deletions num2words/lang_ES.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ def setup(self):
" como un ordinal."
self.errmsg_toobig = (
"abs(%s) deber ser inferior a %s."
)
)
self.gender_stem = "o"
self.exclude_title = ["y", "menos", "punto"]
self.mid_numwords = [(1000, "mil"), (100, "cien"), (90, "noventa"),
Expand All @@ -250,7 +250,7 @@ def setup(self):
10: "décim",
20: "vigésim",
30: "trigésim",
40: "quadragésim",
40: "cuadragésim",
50: "quincuagésim",
60: "sexagésim",
70: "septuagésim",
Expand Down Expand Up @@ -302,29 +302,35 @@ def merge(self, curr, next):

return (ctext + ntext, cnum * nnum)

def to_ordinal(self, value):
def to_ordinal(self, value, gender='m'):
gender_stem = 'a' if gender == 'f' else 'o'

self.verify_ordinal(value)
if value == 0:
text = ""
elif value <= 10:
text = "%s%s" % (self.ords[value], self.gender_stem)
elif value <= 12:
text = "%s%s" % (self.ords[value], gender_stem)
# According to RAE recommendations, simple forms are preferred up to 30
# Ortography for sobreesdrújulas
elif value <= 29:
gender_stem = 'o'
dec = (value // 10) * 10
text = (
"%s%s%s" % (self.ords[10], self.gender_stem,
self.to_ordinal(value - 10))
)
"%s%s%s" % (self.ords[dec].replace('é', 'e'), gender_stem,
self.to_ordinal(value % 10, gender))
)
elif value <= 100:
dec = (value // 10) * 10
text = (
"%s%s %s" % (self.ords[dec], self.gender_stem,
self.to_ordinal(value - dec))
)
"%s%s %s" % (self.ords[dec], gender_stem,
self.to_ordinal(value - dec, gender))
)
elif value <= 1e3:
cen = (value // 100) * 100
text = (
"%s%s %s" % (self.ords[cen], self.gender_stem,
self.to_ordinal(value - cen))
)
"%s%s %s" % (self.ords[cen], gender_stem,
self.to_ordinal(value - cen, gender))
)
elif value < 1e18:
# Round down to the nearest 1e(3n)
# dec contains the following:
Expand All @@ -341,16 +347,18 @@ def to_ordinal(self, value):

cardinal = self.to_cardinal(high_part) if high_part != 1 else ""
text = (
"%s%s%s %s" % (cardinal, self.ords[dec], self.gender_stem,
self.to_ordinal(low_part))
)
"%s%s%s %s" % (cardinal, self.ords[dec], gender_stem,
self.to_ordinal(low_part, gender=gender))
)
else:
text = self.to_cardinal(value)
return text.strip()
# Handle exception: it's not "decimooctavo" but "decimoctavo"
return text.strip().replace('oo', 'o')

def to_ordinal_num(self, value):
def to_ordinal_num(self, value, gender='m'):
gender_stem = 'a' if gender == 'f' else 'o'
self.verify_ordinal(value)
return "%s%s" % (value, "º" if self.gender_stem == 'o' else "ª")
return "%s%s" % (value, "º" if gender_stem == 'o' else "ª")

def to_currency(self, val, currency='EUR', cents=True, separator=' con',
adjective=False):
Expand Down
31 changes: 27 additions & 4 deletions tests/test_es.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,33 @@
TEST_CASES_ORDINAL = (
(1, 'primero'),
(8, 'octavo'),
(12, 'décimosegundo'),
(14, 'décimo cuarto'),
(28, 'vigésimo octavo'),
(12, 'decimosegundo'),
(14, 'decimocuarto'),
(28, 'vigesimoctavo'),
(48, 'cuadragésimo octavo'),
(100, 'centésimo'),
(1000, 'milésimo'),
(12345, 'docemilésimo tricentésimo quadragésimo quinto'),
(12345, 'docemilésimo tricentésimo cuadragésimo quinto'),
(1000000, 'millonésimo'),
(1000000000000000, 'cuadrillonésimo'),
(1000000000000000000, 'un trillón') # over 1e18 is not supported
)

TEST_CASES_ORDINAL_FEM = (
(1, 'primera'),
(8, 'octava'),
(12, 'decimosegunda'),
(14, 'decimocuarta'),
(28, 'vigesimoctava'),
(48, 'cuadragésima octava'),
(100, 'centésima'),
(1000, 'milésima'),
(12345, 'docemilésima tricentésima cuadragésima quinta'),
(1000000, 'millonésima'),
(1000000000000000, 'cuadrillonésima'),
(1000000000000000000, 'un trillón') # over 1e18 is not supported
)

TEST_CASES_ORDINAL_NUM = (
(1, '1º'),
(8, '8º'),
Expand Down Expand Up @@ -1829,6 +1845,13 @@ def test_ordinal(self):
test[1]
)

def test_ordinal_fem(self):
for test in TEST_CASES_ORDINAL_FEM:
self.assertEqual(
num2words(test[0], lang='es', ordinal=True, gender='f'),
test[1]
)

def test_ordinal_num(self):
for test in TEST_CASES_ORDINAL_NUM:
self.assertEqual(
Expand Down