// morphology-de.el - German morphology: articles, adjective endings, noun // plurals, and verb conjugation. // // German is a fusional language with: // - 4 grammatical cases: nominative, accusative, dative, genitive // - 3 genders: masculine (m), feminine (f), neuter (n) // - 2 numbers: singular, plural // - Strong and weak verb classes // // Conventions used throughout: // gender: "m" | "f" | "n" // case: "nom" | "acc" | "dat" | "gen" // number: "sg" | "pl" // person: "1" | "2" | "3" // tense: "present" | "past" | "future" // article_type: "def" | "indef" | "none" // // Depends on: language-profile (str_eq, str_len, str_slice, str_drop_last, // str_ends_with) // ── Definite articles (der-words) ───────────────────────────────────────────── // // Masc Fem Neut Plural // Nom: der die das die // Acc: den die das die // Dat: dem der dem den // Gen: des der des der fn de_article_def(gender: String, gram_case: String, number: String) -> String { if str_eq(number, "pl") { if str_eq(gram_case, "nom") { return "die" } if str_eq(gram_case, "acc") { return "die" } if str_eq(gram_case, "dat") { return "den" } if str_eq(gram_case, "gen") { return "der" } return "die" } if str_eq(gender, "m") { if str_eq(gram_case, "nom") { return "der" } if str_eq(gram_case, "acc") { return "den" } if str_eq(gram_case, "dat") { return "dem" } if str_eq(gram_case, "gen") { return "des" } return "der" } if str_eq(gender, "f") { if str_eq(gram_case, "nom") { return "die" } if str_eq(gram_case, "acc") { return "die" } if str_eq(gram_case, "dat") { return "der" } if str_eq(gram_case, "gen") { return "der" } return "die" } // neuter if str_eq(gram_case, "nom") { return "das" } if str_eq(gram_case, "acc") { return "das" } if str_eq(gram_case, "dat") { return "dem" } if str_eq(gram_case, "gen") { return "des" } return "das" } // ── Indefinite articles (ein-words) ────────────────────────────────────────── // // Masc Fem Neut Plural // Nom: ein eine ein — // Acc: einen eine ein — // Dat: einem einer einem — // Gen: eines einer eines — fn de_article_indef(gender: String, gram_case: String, number: String) -> String { if str_eq(number, "pl") { // Indefinite article has no plural form return "" } if str_eq(gender, "m") { if str_eq(gram_case, "nom") { return "ein" } if str_eq(gram_case, "acc") { return "einen" } if str_eq(gram_case, "dat") { return "einem" } if str_eq(gram_case, "gen") { return "eines" } return "ein" } if str_eq(gender, "f") { if str_eq(gram_case, "nom") { return "eine" } if str_eq(gram_case, "acc") { return "eine" } if str_eq(gram_case, "dat") { return "einer" } if str_eq(gram_case, "gen") { return "einer" } return "eine" } // neuter if str_eq(gram_case, "nom") { return "ein" } if str_eq(gram_case, "acc") { return "ein" } if str_eq(gram_case, "dat") { return "einem" } if str_eq(gram_case, "gen") { return "eines" } return "ein" } // de_article: unified article dispatch. // definite: "def" | "indef" | "none" fn de_article(gender: String, gram_case: String, number: String, definite: String) -> String { if str_eq(definite, "def") { return de_article_def(gender, gram_case, number) } if str_eq(definite, "indef") { return de_article_indef(gender, gram_case, number) } return "" } // ── Adjective endings ───────────────────────────────────────────────────────── // // Weak endings (after a definite article or der-word): // // Masc Fem Neut Plural // Nom: -e -e -e -en // Acc: -en -e -e -en // Dat: -en -en -en -en // Gen: -en -en -en -en // // Mixed endings (after ein-words with no marking, i.e. indef article): // // Masc Fem Neut Plural // Nom: -er -e -es -en // Acc: -en -e -es -en // Dat: -en -en -en -en // Gen: -en -en -en -en // // Strong endings (no preceding article): // // Masc Fem Neut Plural // Nom: -er -e -es -e // Acc: -en -e -es -e // Dat: -em -er -em -en // Gen: -en -er -en -er // // article_type: "def" | "indef" | "none" fn de_adj_ending(gender: String, gram_case: String, number: String, article_type: String) -> String { if str_eq(article_type, "def") { // Weak declension if str_eq(number, "pl") { return "en" } if str_eq(gender, "m") { if str_eq(gram_case, "nom") { return "e" } return "en" } if str_eq(gender, "f") { if str_eq(gram_case, "nom") { return "e" } if str_eq(gram_case, "acc") { return "e" } return "en" } // neuter if str_eq(gram_case, "nom") { return "e" } if str_eq(gram_case, "acc") { return "e" } return "en" } if str_eq(article_type, "indef") { // Mixed declension if str_eq(number, "pl") { return "en" } if str_eq(gender, "m") { if str_eq(gram_case, "nom") { return "er" } return "en" } if str_eq(gender, "f") { if str_eq(gram_case, "nom") { return "e" } if str_eq(gram_case, "acc") { return "e" } return "en" } // neuter if str_eq(gram_case, "nom") { return "es" } if str_eq(gram_case, "acc") { return "es" } return "en" } // Strong declension (no article) if str_eq(number, "pl") { if str_eq(gram_case, "nom") { return "e" } if str_eq(gram_case, "acc") { return "e" } if str_eq(gram_case, "dat") { return "en" } if str_eq(gram_case, "gen") { return "er" } return "e" } if str_eq(gender, "m") { if str_eq(gram_case, "nom") { return "er" } if str_eq(gram_case, "acc") { return "en" } if str_eq(gram_case, "dat") { return "em" } if str_eq(gram_case, "gen") { return "en" } return "er" } if str_eq(gender, "f") { if str_eq(gram_case, "nom") { return "e" } if str_eq(gram_case, "acc") { return "e" } if str_eq(gram_case, "dat") { return "er" } if str_eq(gram_case, "gen") { return "er" } return "e" } // neuter if str_eq(gram_case, "nom") { return "es" } if str_eq(gram_case, "acc") { return "es" } if str_eq(gram_case, "dat") { return "em" } if str_eq(gram_case, "gen") { return "en" } return "es" } // ── Noun plural formation ───────────────────────────────────────────────────── // // Major patterns, keyed on lemma. Where a noun is known irregular, the full // plural is returned. Otherwise a productive heuristic by gender and ending // is applied: // // Masculine hard nouns → +e (der Tag → Tage) // Feminine nouns in -e → +n (die Katze → Katzen) // Feminine nouns → +en (die Frau → Frauen) // Neuter nouns in -chen/-lein → ∅ (das Mädchen → Mädchen) // Neuter nouns in -um → -um +en (das Zentrum → Zentren) // Loanwords in -a,-o,-i → +s (das Auto → Autos) // Default → +e fn de_noun_plural(noun: String, gender: String) -> String { // ── Lexical irregulars ────────────────────────────────────────────────── if str_eq(noun, "Mann") { return "Männer" } if str_eq(noun, "Kind") { return "Kinder" } if str_eq(noun, "Haus") { return "Häuser" } if str_eq(noun, "Buch") { return "Bücher" } if str_eq(noun, "Mutter") { return "Mütter" } if str_eq(noun, "Vater") { return "Väter" } if str_eq(noun, "Bruder") { return "Brüder" } if str_eq(noun, "Tochter") { return "Töchter" } if str_eq(noun, "Nacht") { return "Nächte" } if str_eq(noun, "Stadt") { return "Städte" } if str_eq(noun, "Wort") { return "Wörter" } if str_eq(noun, "Gott") { return "Götter" } if str_eq(noun, "Wald") { return "Wälder" } if str_eq(noun, "Band") { return "Bände" } if str_eq(noun, "Hund") { return "Hunde" } if str_eq(noun, "Baum") { return "Bäume" } if str_eq(noun, "Raum") { return "Räume" } if str_eq(noun, "Traum") { return "Träume" } if str_eq(noun, "Zug") { return "Züge" } if str_eq(noun, "Flug") { return "Flüge" } if str_eq(noun, "Fuß") { return "Füße" } if str_eq(noun, "Gruß") { return "Grüße" } if str_eq(noun, "Geist") { return "Geister" } if str_eq(noun, "Schwanz") { return "Schwänze" } if str_eq(noun, "Stuhl") { return "Stühle" } if str_eq(noun, "Stuhl") { return "Stühle" } if str_eq(noun, "Sohn") { return "Söhne" } if str_eq(noun, "Ton") { return "Töne" } if str_eq(noun, "Fluss") { return "Flüsse" } if str_eq(noun, "Frau") { return "Frauen" } if str_eq(noun, "Straße") { return "Straßen" } if str_eq(noun, "Schule") { return "Schulen" } if str_eq(noun, "Blume") { return "Blumen" } if str_eq(noun, "Katze") { return "Katzen" } if str_eq(noun, "Sprache") { return "Sprachen" } if str_eq(noun, "Kirche") { return "Kirchen" } if str_eq(noun, "Tür") { return "Türen" } if str_eq(noun, "Uhr") { return "Uhren" } if str_eq(noun, "Zahl") { return "Zahlen" } if str_eq(noun, "Wahl") { return "Wahlen" } if str_eq(noun, "Bahn") { return "Bahnen" } if str_eq(noun, "Zahn") { return "Zähne" } if str_eq(noun, "Nase") { return "Nasen" } if str_eq(noun, "Maus") { return "Mäuse" } if str_eq(noun, "Mädchen") { return "Mädchen" } if str_eq(noun, "Messer") { return "Messer" } if str_eq(noun, "Fenster") { return "Fenster" } if str_eq(noun, "Zimmer") { return "Zimmer" } if str_eq(noun, "Wasser") { return "Wasser" } if str_eq(noun, "Bett") { return "Betten" } if str_eq(noun, "Auto") { return "Autos" } if str_eq(noun, "Kino") { return "Kinos" } if str_eq(noun, "Radio") { return "Radios" } if str_eq(noun, "Foto") { return "Fotos" } if str_eq(noun, "Cafe") { return "Cafes" } if str_eq(noun, "Zentrum") { return "Zentren" } if str_eq(noun, "Museum") { return "Museen" } if str_eq(noun, "Gymnasium") { return "Gymnasien" } if str_eq(noun, "Studium") { return "Studien" } if str_eq(noun, "Datum") { return "Daten" } // ── Productive heuristics ─────────────────────────────────────────────── // Nouns ending in -chen or -lein: no change (diminutives) if str_ends_with(noun, "chen") { return noun } if str_ends_with(noun, "lein") { return noun } // Nouns ending in -um: replace with -en if str_ends_with(noun, "um") { return str_drop_last(noun, 2) + "en" } // Loanwords ending in vowel or -s: add -s if str_ends_with(noun, "a") { return noun + "s" } if str_ends_with(noun, "o") { return noun + "s" } if str_ends_with(noun, "i") { return noun + "s" } if str_ends_with(noun, "u") { return noun + "s" } if str_ends_with(noun, "y") { return noun + "s" } // Feminine nouns ending in -e: add -n if str_eq(gender, "f") { if str_ends_with(noun, "e") { return noun + "n" } // Feminine nouns ending in -in: add -nen if str_ends_with(noun, "in") { return noun + "nen" } // Most other feminines: add -en return noun + "en" } // Neuter and masculine: default to +e return noun + "e" } // ── Noun case endings ───────────────────────────────────────────────────────── // // In German, noun case inflection is mostly carried by the article and // adjective. The noun itself only changes in two regular situations: // - Genitive singular masculine/neuter: -(e)s // - Dative plural: -n (if not already ending in -n or -s) // // Irregular genitive forms (e.g. N-declension: Herr → Herrn) are // handled per-lemma in de_case_ending. fn de_case_ending(noun: String, gender: String, gram_case: String, number: String) -> String { // N-declension masculines (weak nouns): all non-nominative singular forms + all plural add -(e)n if str_eq(noun, "Herr") { if str_eq(number, "sg") { if str_eq(gram_case, "nom") { return "Herr" } return "Herrn" } return "Herren" } if str_eq(noun, "Mensch") { if str_eq(number, "sg") { if str_eq(gram_case, "nom") { return "Mensch" } return "Menschen" } return "Menschen" } if str_eq(noun, "Student") { if str_eq(number, "sg") { if str_eq(gram_case, "nom") { return "Student" } return "Studenten" } return "Studenten" } if str_eq(noun, "Kollege") { if str_eq(number, "sg") { if str_eq(gram_case, "nom") { return "Kollege" } return "Kollegen" } return "Kollegen" } if str_eq(noun, "Name") { if str_eq(number, "sg") { if str_eq(gram_case, "nom") { return "Name" } if str_eq(gram_case, "gen") { return "Namens" } return "Namen" } return "Namen" } // Regular masculine/neuter: genitive singular gets -(e)s if str_eq(number, "sg") { if str_eq(gram_case, "gen") { if str_eq(gender, "m") { if str_ends_with(noun, "s") { return noun + "es" } if str_ends_with(noun, "x") { return noun + "es" } if str_ends_with(noun, "z") { return noun + "es" } if str_ends_with(noun, "sch") { return noun + "es" } return noun + "s" } if str_eq(gender, "n") { if str_ends_with(noun, "s") { return noun + "es" } if str_ends_with(noun, "x") { return noun + "es" } if str_ends_with(noun, "z") { return noun + "es" } return noun + "s" } } // All other singular cases: noun unchanged return noun } // Plural dative: add -n unless already ending in -n or -s if str_eq(gram_case, "dat") { let pl: String = de_noun_plural(noun, gender) if str_ends_with(pl, "n") { return pl } if str_ends_with(pl, "s") { return pl } return pl + "n" } // All other plural cases: return the standard plural form return de_noun_plural(noun, gender) } // ── Weak verb conjugation ───────────────────────────────────────────────────── // // Model: machen (mach-) // // Present: // 1sg ich mache 2sg du machst 3sg er/sie/es macht // 1pl wir machen 2pl ihr macht 3pl sie machen // // Past (Präteritum): // 1sg ich machte 2sg du machtest 3sg er/sie/es machte // 1pl wir machten 2pl ihr machtet 3pl sie machten fn de_conjugate_weak(stem: String, tense: String, person: String, number: String) -> String { if str_eq(tense, "present") { if str_eq(number, "sg") { if str_eq(person, "1") { return stem + "e" } if str_eq(person, "2") { // Stems ending in -t or -d insert -e- before -st if str_ends_with(stem, "t") { return stem + "est" } if str_ends_with(stem, "d") { return stem + "est" } return stem + "st" } // 3sg if str_ends_with(stem, "t") { return stem + "et" } if str_ends_with(stem, "d") { return stem + "et" } return stem + "t" } // plural if str_eq(person, "1") { return stem + "en" } if str_eq(person, "2") { if str_ends_with(stem, "t") { return stem + "et" } if str_ends_with(stem, "d") { return stem + "et" } return stem + "t" } // 3pl return stem + "en" } if str_eq(tense, "past") { if str_eq(number, "sg") { if str_eq(person, "1") { return stem + "te" } if str_eq(person, "2") { return stem + "test" } return stem + "te" } if str_eq(person, "1") { return stem + "ten" } if str_eq(person, "2") { return stem + "tet" } return stem + "ten" } // Future: werden + infinitive — caller must prepend the auxiliary return stem + "en" } // ── Strong / irregular verb present-tense forms ─────────────────────────────── // // Returns the correct surface form if the verb is irregular, or "" if unknown. // Only present-tense irregulars are encoded here because past tense for strong // verbs is stored as a separate stem (Ablaut) — see de_conjugate. fn de_irregular_present(verb: String, person: String, number: String) -> String { // sein — fully irregular if str_eq(verb, "sein") { if str_eq(number, "sg") { if str_eq(person, "1") { return "bin" } if str_eq(person, "2") { return "bist" } return "ist" } if str_eq(person, "1") { return "sind" } if str_eq(person, "2") { return "seid" } return "sind" } // haben if str_eq(verb, "haben") { if str_eq(number, "sg") { if str_eq(person, "1") { return "habe" } if str_eq(person, "2") { return "hast" } return "hat" } if str_eq(person, "1") { return "haben" } if str_eq(person, "2") { return "habt" } return "haben" } // werden if str_eq(verb, "werden") { if str_eq(number, "sg") { if str_eq(person, "1") { return "werde" } if str_eq(person, "2") { return "wirst" } return "wird" } if str_eq(person, "1") { return "werden" } if str_eq(person, "2") { return "werdet" } return "werden" } // gehen if str_eq(verb, "gehen") { if str_eq(number, "sg") { if str_eq(person, "1") { return "gehe" } if str_eq(person, "2") { return "gehst" } return "geht" } if str_eq(person, "1") { return "gehen" } if str_eq(person, "2") { return "geht" } return "gehen" } // kommen if str_eq(verb, "kommen") { if str_eq(number, "sg") { if str_eq(person, "1") { return "komme" } if str_eq(person, "2") { return "kommst" } return "kommt" } if str_eq(person, "1") { return "kommen" } if str_eq(person, "2") { return "kommt" } return "kommen" } // sehen — vowel change e→ie in 2sg/3sg if str_eq(verb, "sehen") { if str_eq(number, "sg") { if str_eq(person, "1") { return "sehe" } if str_eq(person, "2") { return "siehst" } return "sieht" } if str_eq(person, "1") { return "sehen" } if str_eq(person, "2") { return "seht" } return "sehen" } // essen — vowel change e→i in 2sg/3sg if str_eq(verb, "essen") { if str_eq(number, "sg") { if str_eq(person, "1") { return "esse" } if str_eq(person, "2") { return "isst" } return "isst" } if str_eq(person, "1") { return "essen" } if str_eq(person, "2") { return "esst" } return "essen" } // geben — vowel change e→i in 2sg/3sg if str_eq(verb, "geben") { if str_eq(number, "sg") { if str_eq(person, "1") { return "gebe" } if str_eq(person, "2") { return "gibst" } return "gibt" } if str_eq(person, "1") { return "geben" } if str_eq(person, "2") { return "gebt" } return "geben" } // nehmen — vowel change e→i + consonant change in 2sg/3sg if str_eq(verb, "nehmen") { if str_eq(number, "sg") { if str_eq(person, "1") { return "nehme" } if str_eq(person, "2") { return "nimmst" } return "nimmt" } if str_eq(person, "1") { return "nehmen" } if str_eq(person, "2") { return "nehmt" } return "nehmen" } // fahren — vowel change a→ä in 2sg/3sg if str_eq(verb, "fahren") { if str_eq(number, "sg") { if str_eq(person, "1") { return "fahre" } if str_eq(person, "2") { return "fährst" } return "fährt" } if str_eq(person, "1") { return "fahren" } if str_eq(person, "2") { return "fahrt" } return "fahren" } // laufen — vowel change au→äu in 2sg/3sg if str_eq(verb, "laufen") { if str_eq(number, "sg") { if str_eq(person, "1") { return "laufe" } if str_eq(person, "2") { return "läufst" } return "läuft" } if str_eq(person, "1") { return "laufen" } if str_eq(person, "2") { return "lauft" } return "laufen" } // wissen — irregular throughout if str_eq(verb, "wissen") { if str_eq(number, "sg") { if str_eq(person, "1") { return "weiß" } if str_eq(person, "2") { return "weißt" } return "weiß" } if str_eq(person, "1") { return "wissen" } if str_eq(person, "2") { return "wisst" } return "wissen" } // können — modal if str_eq(verb, "können") { if str_eq(number, "sg") { if str_eq(person, "1") { return "kann" } if str_eq(person, "2") { return "kannst" } return "kann" } if str_eq(person, "1") { return "können" } if str_eq(person, "2") { return "könnt" } return "können" } // müssen — modal if str_eq(verb, "müssen") { if str_eq(number, "sg") { if str_eq(person, "1") { return "muss" } if str_eq(person, "2") { return "musst" } return "muss" } if str_eq(person, "1") { return "müssen" } if str_eq(person, "2") { return "müsst" } return "müssen" } // wollen — modal if str_eq(verb, "wollen") { if str_eq(number, "sg") { if str_eq(person, "1") { return "will" } if str_eq(person, "2") { return "willst" } return "will" } if str_eq(person, "1") { return "wollen" } if str_eq(person, "2") { return "wollt" } return "wollen" } // Unknown: signal caller to fall through to weak conjugation return "" } // ── Strong verb past-tense (Präteritum) Ablaut stems ───────────────────────── // // Returns the past stem for strong verbs (Ablaut form), or "" if unknown/weak. // The past-tense endings for strong verbs differ from weak: // 1sg/3sg: bare stem (no ending) // 2sg: stem + -st // 1pl/3pl: stem + -en // 2pl: stem + -t fn de_strong_past_stem(verb: String) -> String { if str_eq(verb, "gehen") { return "ging" } if str_eq(verb, "kommen") { return "kam" } if str_eq(verb, "sehen") { return "sah" } if str_eq(verb, "geben") { return "gab" } if str_eq(verb, "nehmen") { return "nahm" } if str_eq(verb, "fahren") { return "fuhr" } if str_eq(verb, "laufen") { return "lief" } if str_eq(verb, "schreiben") { return "schrieb" } if str_eq(verb, "bleiben") { return "blieb" } if str_eq(verb, "steigen") { return "stieg" } if str_eq(verb, "lesen") { return "las" } if str_eq(verb, "sprechen") { return "sprach" } if str_eq(verb, "treffen") { return "traf" } if str_eq(verb, "essen") { return "aß" } if str_eq(verb, "trinken") { return "trank" } if str_eq(verb, "finden") { return "fand" } if str_eq(verb, "denken") { return "dachte" } if str_eq(verb, "bringen") { return "brachte" } if str_eq(verb, "stehen") { return "stand" } if str_eq(verb, "liegen") { return "lag" } if str_eq(verb, "sitzen") { return "saß" } if str_eq(verb, "fallen") { return "fiel" } if str_eq(verb, "halten") { return "hielt" } if str_eq(verb, "rufen") { return "rief" } if str_eq(verb, "tragen") { return "trug" } if str_eq(verb, "schlagen") { return "schlug" } if str_eq(verb, "ziehen") { return "zog" } if str_eq(verb, "wachsen") { return "wuchs" } if str_eq(verb, "helfen") { return "half" } if str_eq(verb, "werfen") { return "warf" } return "" } // ── Normalization helpers ───────────────────────────────────────────────────── // // The realizer sends long-form labels ("singular", "first"). // German morphology uses short forms ("sg", "1"). Normalize on entry. fn de_norm_number(number: String) -> String { if str_eq(number, "singular") { return "sg" } if str_eq(number, "plural") { return "pl" } return number } fn de_norm_person(person: String) -> String { if str_eq(person, "first") { return "1" } if str_eq(person, "second") { return "2" } if str_eq(person, "third") { return "3" } return person } // ── Unified German verb conjugation ────────────────────────────────────────── // // tense: "present" | "past" | "future" // person: "1" | "2" | "3" (also accepts "first" | "second" | "third") // number: "sg" | "pl" (also accepts "singular" | "plural") fn de_conjugate(verb: String, tense: String, person: String, number: String) -> String { let number = de_norm_number(number) let person = de_norm_person(person) // Future tense: werden (conjugated) + infinitive if str_eq(tense, "future") { let aux: String = de_irregular_present("werden", person, number) return aux + " " + verb } // sein — past is also fully irregular if str_eq(verb, "sein") { if str_eq(tense, "present") { return de_irregular_present("sein", person, number) } // Past (war) if str_eq(number, "sg") { if str_eq(person, "1") { return "war" } if str_eq(person, "2") { return "warst" } return "war" } if str_eq(person, "1") { return "waren" } if str_eq(person, "2") { return "wart" } return "waren" } // haben — past: hatte if str_eq(verb, "haben") { if str_eq(tense, "present") { return de_irregular_present("haben", person, number) } if str_eq(number, "sg") { if str_eq(person, "1") { return "hatte" } if str_eq(person, "2") { return "hattest" } return "hatte" } if str_eq(person, "1") { return "hatten" } if str_eq(person, "2") { return "hattet" } return "hatten" } // wissen — past: wusste (mixed/irregular) if str_eq(verb, "wissen") { if str_eq(tense, "present") { return de_irregular_present("wissen", person, number) } if str_eq(number, "sg") { if str_eq(person, "1") { return "wusste" } if str_eq(person, "2") { return "wusstest" } return "wusste" } if str_eq(person, "1") { return "wussten" } if str_eq(person, "2") { return "wusstet" } return "wussten" } // Modals: können, müssen, wollen — past uses weak -te suffix on preterite stem if str_eq(verb, "können") { if str_eq(tense, "present") { return de_irregular_present("können", person, number) } return de_conjugate_weak("konnt", "past", person, number) } if str_eq(verb, "müssen") { if str_eq(tense, "present") { return de_irregular_present("müssen", person, number) } return de_conjugate_weak("musst", "past", person, number) } if str_eq(verb, "wollen") { if str_eq(tense, "present") { return de_irregular_present("wollen", person, number) } return de_conjugate_weak("wollt", "past", person, number) } // Present: try irregular table first if str_eq(tense, "present") { let irr: String = de_irregular_present(verb, person, number) if !str_eq(irr, "") { return irr } // Fall through to weak conjugation using infinitive stem (drop -en) let stem: String = str_drop_last(verb, 2) return de_conjugate_weak(stem, "present", person, number) } // Past: try strong Ablaut first if str_eq(tense, "past") { let ps: String = de_strong_past_stem(verb) if !str_eq(ps, "") { // Strong past endings: 1sg/3sg bare, 2sg+st, 1pl/3pl+en, 2pl+t if str_eq(number, "sg") { if str_eq(person, "1") { return ps } if str_eq(person, "2") { return ps + "st" } return ps } if str_eq(person, "1") { return ps + "en" } if str_eq(person, "2") { return ps + "t" } return ps + "en" } // Weak past let stem: String = str_drop_last(verb, 2) return de_conjugate_weak(stem, "past", person, number) } // Fallback: return infinitive return verb }