Skip to content
Merged
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# verbecc Changelog

- 1.11.6 [TBR]
- 1.11.6 [26 October 2025]
- Fixed Voseo conjugation for irregular verb `ser` for the subjuntivo (no vowel accents)
- Misc. cleanup
- Promoted applicable `Inflector` methods to public

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ Examples:
>>> conj_es('ser')['moods']['indicativo']['presente']
['yo soy', 'tú eres', 'él es', 'nosotros somos', 'vosotros sois', 'ellos son']
>>> conj_es_voseo('ser')['moods']['indicativo']['presente']
['yo soy', 'vos sois', 'él es', 'nosotros somos', 'vosotros sois', 'ellos son']
['yo soy', 'vos sos', 'él es', 'nosotros somos', 'vosotros sois', 'ellos son']

```

Expand Down Expand Up @@ -1236,7 +1236,7 @@ In this example, we will conjugate a verb that `verbecc` doesn't explicitly know
"indicativo": {
"presente": [
"yo soy",
"vos sois",
"vos sos",
"él es",
"nosotros somos",
"vosotros sois",
Expand Down Expand Up @@ -1302,7 +1302,7 @@ In this example, we will conjugate a verb that `verbecc` doesn't explicitly know
"subjuntivo": {
"presente": [
"yo sea",
"vos seáis",
"vos seas",
"él sea",
"nosotros seamos",
"vosotros seáis",
Expand Down
58 changes: 58 additions & 0 deletions tests/test_inflectors/test_inflector_es.py
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,64 @@ def test_inflector_es_conjugate_mood_indicativo_tense_presente_ir_voseo_tipo_3()
]


def test_inflector_es_conjugate_mood_indicativo_tense_presente_ser_no_voseo():
assert cg.conjugate_mood_tense("ser", Mood.es.Indicativo, Tense.es.Presente) == [
"yo soy",
"tú eres",
"él es",
"nosotros somos",
"vosotros sois",
"ellos son",
]


def test_inflector_es_conjugate_mood_indicativo_tense_presente_ser_voseo_tipo_3():
assert cg.conjugate_mood_tense(
"ser",
Mood.es.Indicativo,
Tense.es.Presente,
lang_specific_options=LangSpecificOptionsEs(
voseo_options=VoseoOptions.VoseoTipo3
),
) == [
"yo soy",
"vos sos",
"él es",
"nosotros somos",
"vosotros sois",
"ellos son",
]


def test_inflector_es_conjugate_mood_subjuntivo_tense_presente_ser_no_voseo():
assert cg.conjugate_mood_tense("ser", Mood.es.Subjuntivo, Tense.es.Presente) == [
"yo sea",
"tú seas",
"él sea",
"nosotros seamos",
"vosotros seáis",
"ellos sean",
]


def test_inflector_es_conjugate_mood_subjuntivo_tense_presente_ser_voseo_tipo_3():
assert cg.conjugate_mood_tense(
"ser",
Mood.es.Subjuntivo,
Tense.es.Presente,
lang_specific_options=LangSpecificOptionsEs(
voseo_options=VoseoOptions.VoseoTipo3
),
) == [
"yo sea",
"vos seas",
"él sea",
"nosotros seamos",
"vosotros seáis",
"ellos sean",
]


def test_inflector_es_conjugate_mood_imperativo_tense_afirmativo_ar_no_voseo():
assert cg.conjugate_mood_tense(
"hablar", Mood.es.Imperativo, Tense.es.Afirmativo
Expand Down
85 changes: 55 additions & 30 deletions verbecc/src/inflectors/lang/inflector_es.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from verbecc.src.conjugator.conjugation_object import ConjugationObjects
from verbecc.src.parsers.tense_template import TenseTemplate
from verbecc.src.parsers.person_ending import PersonEnding
from verbecc.src.utils.string_utils import strip_accents


class InflectorEs(Inflector):
Expand Down Expand Up @@ -171,32 +172,35 @@ def modify_person_ending_if_applicable(
with corresponding changes to verb endings.
The verb endings for vos are different from those for tú in
the present indicative, present subjunctive, and imperative moods.
Vos is conjugated like the vosotros form but without the 'i' in the ending.
Vos is conjugated like the vosotros form but without the 'i'
as the second-to-last letter in the ending and with the vowel
accented.
For example, the present indicative forms are:

vosotros bebéis -> vos bebés
vosotros habláis -> vos hablás
vosotros dormís -> vos dormís
Regular (indictive):
vosotros bebéis -> vos bebés
vosotros habláis -> vos hablás
vosotros dormís -> vos dormís
Regular (subjunctive):
vosotros seáis -> vos seas
Irregular:
vosotors sois -> vos sos

"éis" -> "és"
"áis" -> "ás"
"ís" -> "ís"
Regular:
"éis" -> "és"
"áis" -> "ás"
"ís" -> "ís"
Irregular:
"oís" -> "os"

For the imperativo affirmativo we just drop the 'd' and accent the vowel e.g.
(vosotros) hablad -> (vos) hablá
(vosotros) hablad -> (vos) hablá
(vosotros) sed -> (vos) sé
The imperativo negativo is the same as tú.

"""
# map of vosotros endings to vos endings
# for the present indicative, present subjunctive
VOSEO_ENDINGS_MAP_INDICATIVE_OR_SUBJUNCTIVE_PRESENT: Dict[str, str] = {
"as": "ás",
"es": "és",
"ís": "ís",
"áis": "ás",
"éis": "és",
}
VOSEO_ENDINGS_MAP_IMPERATIVE: Dict[str, str] = {"ad": "á", "id": "í", "ed": "é"}
# only need to accent 'a', 'e' and 'i', AFAIK
VOWEL_ACCENT_MAP = {"a": "á", "e": "é", "i": "í"}
lang_opts = None
if lang_specific_options is not None:
lang_opts = cast(LangSpecificOptionsEs, lang_specific_options)
Expand All @@ -222,19 +226,40 @@ def modify_person_ending_if_applicable(
# change replacement PersonEnding Person from second person plural to singular
replacement_person_ending.person = Person.SecondPersonSingular

# modify the endings for voseo
# modify the endings for voseo to form the vos endings
for i, ending in enumerate(replacement_person_ending.get_endings()):
endings_map = (
VOSEO_ENDINGS_MAP_INDICATIVE_OR_SUBJUNCTIVE_PRESENT
)

if mood in (Mood.Indicativo, Mood.Subjuntivo):
# step one for indicativo and subjuntivo presente:
# remove 'i' in the second-to-last letter position
if ending[-2] == "i":
ending = ending[:-2] + ending[-1]
if mood == Mood.Imperativo:
endings_map = VOSEO_ENDINGS_MAP_IMPERATIVE
for e in endings_map:
# e.g. if ending is "sed", it endswith "ed", so "s" + "é" -> "sé"
if ending.endswith(e):
replacement_person_ending.endings[i] = (
ending[: -len(e)] + endings_map[e]
)
break
# step one for imperativo: remove the trailing 'd'
if ending[-1] == "d":
ending = ending[:-1]

if mood == Mood.Subjuntivo:
# step two for subjunctivo is to strip any accents from vowels
# e.g. vosotros seáis -> vos seas
ending = strip_accents(ending)
else:
# step two for indicativo and imperativo is to accent the vowel which
# is now in the second-to-last or last letter position (if not already accented)

# accent second-to-last letter, if vowel
if len(ending) > 1:
if ending[-2] in VOWEL_ACCENT_MAP:
ending = (
ending[:-2]
+ VOWEL_ACCENT_MAP[ending[-2]]
+ ending[-1]
)
# accent last letter, if vowel
if ending[-1] in VOWEL_ACCENT_MAP:
ending = ending[:-1] + VOWEL_ACCENT_MAP[ending[-1]]

# update the replacement person ending with the modified ending
replacement_person_ending.endings[i] = ending
return replacement_person_ending
return person_ending