UNPKG

jslingua

Version:
1,737 lines (1,542 loc) 56.1 kB
import Morpho from "../morpho.mjs"; class FraMorpho extends Morpho { //These static members must be overriden in extended classes; //otherwise, the class won't function properly //Contains stemmers static stemmers = {}; //Contains PoS conversions static converters = {}; static cstemmer = "";//current stemmer static cconverter = "";//current converter static langCode = "fra"; //========================================== // CONJUGATION PROTECTED FUNCTIONS //========================================== static _conj(verb, _opts){ return __conj(verb, _opts); } //========================================== // CONJUGATION OPTIONS PUBLIC FUNCTIONS //========================================== //https://en.wikipedia.org/wiki/French_conjugation static lform() { return { //Indicative "pres": { desc: "Indicative Present (présent)", mood: Morpho.Mood.Ind, tense: Morpho.Tense.Pr, aspect: Morpho.Aspect.S }, "pres_perf": { desc: "Indicative Present perfect (passé composé)", mood: Morpho.Mood.Ind, tense: Morpho.Tense.Pr, aspect: Morpho.Aspect.P }, "imperf": { desc: "Indicative Imperfect (imparfait)", mood: Morpho.Mood.Ind, tense: Morpho.Tense.Pr, aspect: Morpho.Aspect.I }, //Exprime une action passée, achevée, d'une durée plutôt longue et antérieure à une autre action passée: //https://www.francaisfacile.com/exercices/exercice-francais-2/exercice-francais-8681.php "pluperf": { desc: "Indicative Pluperfect (plus-que-parfait)", mood: Morpho.Mood.Ind, tense: Morpho.Tense.Pa, aspect: Morpho.Aspect.P, period: "long" }, "past": { desc: "Indicative Simple past (passé simple)", mood: Morpho.Mood.Ind, tense: Morpho.Tense.Pa, aspect: Morpho.Aspect.S }, //Exprime une action passée, achevée, d'une durée assez brève et antérieure à une autre action passée: //https://www.francaisfacile.com/exercices/exercice-francais-2/exercice-francais-8681.php "past_perf": { desc: "Indicative Past perfect (passé antérieur)", mood: Morpho.Mood.Ind, tense: Morpho.Tense.Pa, aspect: Morpho.Aspect.P, period: "short" }, "fut": { desc: "Indicative Simple future (futur simple)", mood: Morpho.Mood.Ind, tense: Morpho.Tense.Fu, aspect: Morpho.Aspect.S }, "fut_perf": { desc: "Indicative Future perfect (futur antérieur)", mood: Morpho.Mood.Ind, tense: Morpho.Tense.Fu, aspect: Morpho.Aspect.P }, //Subjunctive "subj_pres": { desc: "Subjunctive Present", mood: Morpho.Mood.Sub, tense: Morpho.Tense.Pr, aspect: Morpho.Aspect.S }, "subj_past": { desc: "Subjunctive Past (passé)", mood: Morpho.Mood.Sub, tense: Morpho.Tense.Pa, aspect: Morpho.Aspect.S }, "subj_imperf": { desc: "Subjunctive Imperfect", mood: Morpho.Mood.Sub, tense: Morpho.Tense.Pr, aspect: Morpho.Aspect.I }, "subj_pluperf": { desc: "Subjunctive Pluperfect", mood: Morpho.Mood.Sub, tense: Morpho.Tense.Pa, aspect: Morpho.Aspect.P }, //Imperative "imp_pres": { desc: "Imperative Present", mood: Morpho.Mood.Imp, tense: Morpho.Tense.Pr }, "imp_past": { desc: "Imperative Past", mood: Morpho.Mood.Imp, tense: Morpho.Tense.Pa }, //Conditional "cond_pres": { desc: "Conditional Present", mood: Morpho.Mood.Cnd, tense: Morpho.Tense.Pr }, "cond_past1": { desc: "Conditional Past (form 1)", mood: Morpho.Mood.Cnd, tense: Morpho.Tense.Pa, form: 1 }, "cond_past2": { desc: "Conditional Past (form 2)", mood: Morpho.Mood.Cnd, tense: Morpho.Tense.Pa, form: 2 } }; } /** * Each language has a conjugation table model. * For example, in English, Arabic and French, we put pronouns in rows. * As for Japanese, the conjugation doesn't follow that pattern. * * @method jconjmod * @override * @memberof FraMorpho * @return {Object} Conjugation model */ static jconjmod(){ //Past and Present are defaults return { rows: ["Pronoun"], cols: ["Negation"] //Conj }; } /* Me.getOptName = function(optLabel, opts){ switch (optLabel) { case "Pronoun": return this.getPronounName(opts); case "Conj": return "Conjugation"; default: } return ""; }; */ //========================================== // CONJUGATION OPTIONS PROTECTED FUNCTIONS //========================================== static _gPpOpts() { return [ {person:Morpho.Person.F, number: Morpho.GNumber.S}, //Je {person:Morpho.Person.S, number: Morpho.GNumber.S},//Tu {person:Morpho.Person.T, number: Morpho.GNumber.S, gender: Morpho.Gender.M},//Il {person:Morpho.Person.T, number: Morpho.GNumber.S, gender: Morpho.Gender.F},//Elle {person:Morpho.Person.F, number: Morpho.GNumber.P}, //Nous {person:Morpho.Person.S, number: Morpho.GNumber.P},//Vous {person:Morpho.Person.T, number: Morpho.GNumber.P, gender: Morpho.Gender.M},//Ils {person:Morpho.Person.T, number: Morpho.GNumber.P, gender: Morpho.Gender.F}//Elles ]; } static _gPpName(opts) { switch (opts.person) { case Morpho.Person.F: if (opts.number === Morpho.GNumber.S) return "Je"; else return "Nous"; case Morpho.Person.S: if (opts.number === Morpho.GNumber.S) return "Tu"; return "Vous"; case Morpho.Person.T: { let pl = (opts.number === Morpho.GNumber.S)? "": "s"; if (opts.gender === Morpho.Gender.M) return "Il" + pl; return "Elle" + pl; } } return ""; } //========================================== // NORMALIZATION FUNCTIONS //========================================== //TODO normalization of words static norm = function(word, _opts){ return word; } //========================================== // SEGMENTATION FUNCTIONS //========================================== //========================================== // HELPER FUNCTIONS //========================================== } //========================================== // CONSTANTS //========================================== //Second group verbs //https://en.wiktionary.org/w/index.php?title=Category:French_second_group_verbs&pageuntil=MURIR%0Amurir#mw-pages const verbs2g = { // A // ========== "ab": { "asourd": 1, "âtard": 1, "êt": 1, "ol": 1, "onn": 1, "out": 1, "réag": 1, "rout": 1, "rut": 1 }, "ac": { "calm": 1, "compl": 1, "courc": 1, "croup": 1 }, "ad": { "ouc": 1, "vert": 1 }, "af": { "fad": 1, "faibl": 1, "ferm": 1, "franch": 1 }, "ag": { "": 1, "on": 1, "rand": 1, "uerr": 1 }, "ah": { "ur": 1 }, "ai": { "gr": 1 }, "al": { "angu": 1, "ent": 1, "lot": 1, "ourd": 1, "un": 1 }, "am": { "aigr": 1, "ars": 1, "at": 1, "enu": 1, "err": 1, "eubl": 1, "inc": 1, "oindr": 1, "oll": 1, "ort": 1, "ui": 1 }, "an": { "éant": 1, "obl": 1, "ord": 1 }, "ap": { "lan": 1, "lat": 1, "pauvr": 1, "pesant": 1, "plaud": 1, "profond": 1 }, "ar": { "rond": 1 }, "as": { "sag": 1, "sain": 1, "serv": 1, "s": 1, "sombr": 1, "sort": 1, "soup": 1, "soupl": 1, "sourd": 1, "souv": 1, "sujett": 1 }, "at": { "tendr": 1, "tér": 1, "terr": 1, "tiéd": 1 }, "av": { "ach": 1, "ert": 1, "eul": 1, "il": 1 }, // B // ============ "ba": { "nn": 1, "rr": 1, "ud": 1 }, "bâ": { "t": 1 }, "bé": { "n": 1 }, "bl": { "anch": 1, "êm": 1, "ett": 1, "eu": 1, "ond": 1, "ott": 1 }, "bo": { "nd": 1, "uff": 1 }, "br": { "and": 1, "un": 1 //"uire": 1, }, // C // ======== "ca": { "nd": 1 }, "ch": { "auv": 1, "ér": 1, "ois": 1 }, "co": { "mpat": 1, "nvert": 1, "sais": 1, "t": 1 }, "cr": { "ép": 1, "oup": 1 }, // D // ========== "dé": { "crép": 1, "fin": 1, "fléch": 1, "fraîch": 1, "garn": 1, "gauch": 1, "glut": 1, "gourd": 1, "gross": 1, "guerp": 1, "mol": 1, "mun": 1, "pér": 1, "roug": 1, "sempl": 1, "sinvest": 1, "sobé": 1, "sun": 1 }, "de": { "ssais": 1, "ssert": 1 }, "di": { "vert": 1 }, "du": { "rc": 1 }, // E // ========== "éb": { "ah": 1, "aub": 1, "aud": 1, "lou": 1 }, "éc": { "lairc": 1, "rapout": 1 }, "ef": { "fleur": 1 }, "él": { "arg": 1 }, "em": { "bell": 1, "bout": 1, "pl": 1, "puant": 1 }, "en": { "chér": 1, "durc": 1, "fou": 1, "glout": 1, "gourd": 1, "hard": 1, "laid": 1, "nobl": 1, "orgueill": 1, "rich": 1, "sevel": 1, "vah": 1 }, "ép": { "aiss": 1, "anou": 1 }, "éq": { "uarr": 1 }, "es": { "tourb": 1 }, "ét": { "abl": 1, "ourd": 1, "réc": 1 }, "év": { "anou": 1 }, // F // =========== "fa": { "ibl": 1, "ill": 1, "rc": 1 }, "fi": { "n": 1 }, "fl": { "éch": 1, "étr": 1, "eur": 1, "or": 1 }, "fo": { "rc": 1, "u": 1, "urb": 1, "urn": 1 }, "fr": { "aîch": 1, "anch": 1, "ém": 1, "oid": 1 }, // G // ============ "ga": { "rant": 1, "rn": 1, "uch": 1, "ud": 1 }, "gé": { "m": 1 }, "gl": { "ap": 1 }, "gr": { "and": 1, "av": 1, "oss": 1 }, "gu": { "ér": 1 }, // H // ========== "ha": { "v": 1 }, "he": { "nn": 1 }, "ho": { "nn": 1 }, // I // ========= "im": { "part": 1 }, "in": { "fléch": 1, "terag": 1, "terconvert": 1, "tervert": 1, "vert": 1, "vest": 1 }, // J // ========= "ja": { "ill": 1, "un": 1 }, "jo": { "u": 1 }, // L // ========= "la": { "id": 1, "ngu": 1 }, "lo": { "t": 1 }, // M // ======== "ma": { "igr": 1 }, "me": { "urtr": 1 }, "mi": { "nc": 1 }, "mo": { "is": 1, "ll": 1 }, "mu": { "g": 1, "n": 1, "r": 1 }, "mû": { "r": 1 }, "na": { "nt": 1 }, "no": { "irc": 1, "urr": 1 }, "ob": { "é": 1, "scurc": 1 }, "ou": { "rd": 1 }, // P // ========= "pâ": { "l": 1, "t": 1 }, "pé": { "r": 1, "tr": 1 }, "pe": { "rvert": 1 }, "po": { "l": 1, "urr": 1 }, "pr": { "æmun": 1, "édéfin": 1, "émun": 1 }, "pu": { "n": 1 }, // R // ========= "ra": { "ccourc": 1, "corn": 1, "douc": 1, "fferm": 1, "fraich": 1, "fraîch": 1, "gaillard": 1, "id": 1, "jeun": 1, "lent": 1, "moll": 1, "nc": 1, "ss": 1, "ssort": 1, "v": 1 }, "ré": { "ag": 1, "assort": 1, "enchér": 1, "fléch": 1, "g": 1, "invest": 1, "jou": 1, "part": 1, "tabl": 1, "tréc": 1, "un": 1, "uss": 1 }, "re": { "bât": 1, "bond": 1, "ço": 1, "convert": 1, "crép": 1, "défin": 1, "fleur": 1, "froid": 1, "garn": 1, "mbrun": 1, "mpl": 1, "nchér": 1, "nforc": 1, "pétr": 1, "pun": 1, "splend": 1, "ssais": 1, "ssort": 1, "ssurg": 1, "surg": 1, "tent": 1, "verd": 1, "vern": 1 }, "ro": { "id": 1, "s": 1, "ug": 1, "uss": 1 }, "rô": { "t": 1 }, "ru": { "g": 1 }, // S // =========== "sa": { "is": 1, "l": 1, "ur": 1 }, "se": { "rt": 1 }, "sé": { "v": 1 }, "su": { "b": 1, "bvert": 1, "renchér": 1, "rg": 1, "rinvest": 1 }, // T // ========= "ta": { "p": 1, "r": 1 }, "te": { "rn": 1 }, "ti": { "éd": 1 }, "tr": { "ah": 1, "ans": 1, "avest": 1 }, // U // ========= "un": { "": 1 }, // V // ========= "va": { "g": 1 }, "ve": { "rd": 1, "rn": 1 }, "vi": { "eill": 1 }, "vo": { "m": 1 }, "vr": { "omb": 1 } }; const g1Suffix = { [Morpho.Mood.Ind]: { present: ["e", "es", "e", "ons", "ez", "ent"], past: ["ai", "as", "a", "âmes", "âtes", "èrent"], imperfect: ["ais", "ais", "ait", "ions", "iez", "aient"], future: ["erai", "eras", "era", "erons", "erez", "eront"] }, [Morpho.Mood.Sub]: { present: ["e", "es", "e", "ions", "iez", "ent"], imperfect: ["asse", "asses", "ât", "assions", "assiez", "assent"] }, [Morpho.Mood.Cnd]: { present: ["erais", "erais", "erait", "erions", "eriez", "eraient"] }, [Morpho.Mood.Imp]: { present: ["$", "e", "", "ons", "ez", "$"] } }, g2Suffix = { [Morpho.Mood.Ind]: { [Morpho.Tense.Pr]: ["is", "is", "it", "issons", "issez", "issent"], [Morpho.Tense.Pa]: ["is", "is", "it", "îmes", "îtes", "irent"], [Morpho.Aspect.I]: ["issais", "issais", "issait", "issions", "issiez", "issaient"], [Morpho.Tense.Fu]: ["irai", "iras", "ira", "irons", "irez", "iront"] }, [Morpho.Mood.Sub]: { [Morpho.Tense.Pr]: ["isse", "isses", "isse", "issions", "issiez", "issent"], [Morpho.Aspect.I]: ["isse", "isses", "ît", "issions", "issiez", "issent"] }, [Morpho.Mood.Cnd]: { [Morpho.Tense.Pr]: ["irais", "irais", "irait", "irions", "iriez", "iraient"] }, [Morpho.Mood.Imp]: { [Morpho.Tense.Pr]: ["$", "is", "", "issons", "issez", "$"] } }, g3Suffix = { [Morpho.Mood.Ind]: { [Morpho.Tense.Pr]: ["<s1>s", "<s1>s", "<s1>t", "<p1>ons", "<p1>ez", "<p3>ent"], [Morpho.Tense.Pa]: ["<p>s", "<p>s", "<p>t", "<p>^mes", "<p>^tes", "<p>rent"], [Morpho.Aspect.I]: ["<p1>ais", "<p1>ais", "<p1>ait", "<p1>ions", "<p1>iez", "<p1>aient"], [Morpho.Tense.Fu]: ["<f>ai", "<f>as", "<f>a", "<f>ons", "<f>ez", "<f>ont"] }, [Morpho.Mood.Sub]: { [Morpho.Tense.Pr]: ["<p3>e", "<p3>es", "<p3>e", "<p1>ions", "<p1>iez", "<p3>ent"], [Morpho.Aspect.I]: ["<p>sse", "<p>sses", "<p>^t", "<p>ssions", "<p>ssiez", "<p>ssent"] }, [Morpho.Mood.Cnd]: { [Morpho.Tense.Pr]: ["<f>ais", "<f>ais", "<f>ait", "<f>ions", "<f>iez", "<f>aient"] }, [Morpho.Mood.Imp]: { [Morpho.Tense.Pr]: ["$", "<s1>s", "", "<p1>ons", "<p1>ez", "$"] //TODO Imperative: <s1>t if ends with vowel, else <s1>s } }, irregular = { "être": { pp: "été", [Morpho.Mood.Ind]: { [Morpho.Tense.Pr]: ["suis", "es", "est", "sommes", "êtes", "sont"], [Morpho.Tense.Pa]: ["fus", "fus", "fut", "fûmes", "fûtes", "furent"], [Morpho.Aspect.I]: ["étais", "étais", "était", "étions", "étiez", "étaient"], [Morpho.Tense.Fu]: ["serai", "seras", "sera", "serons", "serez", "seront"] }, [Morpho.Mood.Sub]: { [Morpho.Tense.Pr]: ["sois", "sois", "soit", "soyons", "soyez", "soient"], [Morpho.Aspect.I]: ["fusse", "fusses", "fût", "fussions", "fussiez", "fussent"] }, [Morpho.Mood.Cnd]: { [Morpho.Tense.Pr]: ["serais", "serais", "serait", "serions", "seriez", "seraient"] }, [Morpho.Mood.Imp]: { [Morpho.Tense.Pr]: ["$", "sois", "", "soyons", "soyez", "$"] } }, "avoir": { pp: "eu", [Morpho.Mood.Ind]: { [Morpho.Tense.Pr]: ["ai", "as", "a", "avons", "avez", "ont"], [Morpho.Tense.Pa]: ["eus", "eus", "eut", "eûmes", "eûtes", "eurent"], [Morpho.Aspect.I]: ["avais", "avais", "avait", "avions", "aviez", "avaient"], [Morpho.Tense.Fu]: ["aurai", "auras", "aura", "aurons", "aurez", "auront"] }, [Morpho.Mood.Sub]: { [Morpho.Tense.Pr]: ["aie", "aies", "ait", "ayons", "ayez", "aient"], [Morpho.Aspect.I]: ["eusse", "eusses", "eût", "eussions", "eussiez", "eussent"] }, [Morpho.Mood.Cnd]: { [Morpho.Tense.Pr]: ["aurais", "aurais", "aurait", "aurions", "auriez", "auraient"] }, [Morpho.Mood.Imp]: { [Morpho.Tense.Pr]: ["$", "aie", "", "ayons", "ayez", "$"] } }, "aller": { pp: "allé", [Morpho.Mood.Ind]: { [Morpho.Tense.Pr]: ["vais", "vas", "va", "allons", "allez", "vont"], [Morpho.Tense.Pa]: ["allai", "allas", "alla", "allâmes", "allâtes", "allèrent"], [Morpho.Aspect.I]: ["allais", "allais", "allait", "allions", "alliez", "allaient"], [Morpho.Tense.Fu]: ["irai", "iras", "ira", "irons", "irez", "iront"] }, [Morpho.Mood.Sub]: { [Morpho.Tense.Pr]: ["aille", "ailles", "aille", "allions", "alliez", "aillent"], [Morpho.Aspect.I]: ["allasse", "allasses", "allât", "allassions", "allassiez", "allassent"] }, [Morpho.Mood.Cnd]: { [Morpho.Tense.Pr]: ["irais", "irais", "irait", "irions", "iriez", "iraient"] }, [Morpho.Mood.Imp]: { [Morpho.Tense.Pr]: ["$", "va", "", "allons", "allez", "$"] } }, "pouvoir": { pp: "pu", [Morpho.Mood.Ind]: { [Morpho.Tense.Pr]: ["peux", "peux", "peut", "pouvons", "pouvez", "peuvent"], [Morpho.Tense.Pa]: ["pus", "pus", "put", "pûmes", "pûtes", "purent"], [Morpho.Aspect.I]: ["pouvais", "pouvais", "pouvait", "pouvions", "pouviez", "pouvaient"], [Morpho.Tense.Fu]: ["pourrai", "pourras", "pourra", "pourrons", "pourrez", "pourront"] }, [Morpho.Mood.Sub]: { [Morpho.Tense.Pr]: ["puisse", "puisses", "puisse", "puissions", "puissiez", "puissent"], [Morpho.Aspect.I]: ["pusse", "pusses", "pût", "pussions", "pussiez", "pussent"] }, [Morpho.Mood.Cnd]: { [Morpho.Tense.Pr]: ["pourrais", "pourrais", "pourrait", "pourrions", "pourriez", "pourraient"] }, [Morpho.Mood.Imp]: { [Morpho.Tense.Pr]: ["$", "$", "$", "$", "$", "$"] } }, "savoir": { pp: "su", [Morpho.Mood.Ind]: { [Morpho.Tense.Pr]: ["sais", "sais", "sait", "savons", "savez", "savent"], [Morpho.Tense.Pa]: ["sus", "sus", "sut", "sûmes", "sûtes", "surent"], [Morpho.Aspect.I]: ["savais", "savais", "savait", "savions", "saviez", "savaient"], [Morpho.Tense.Fu]: ["saurai", "sauras", "saura", "saurons", "saurez", "sauront"] }, [Morpho.Mood.Sub]: { [Morpho.Tense.Pr]: ["sache", "saches", "sache", "sachions", "sachiez", "sachent"], [Morpho.Aspect.I]: ["susse", "susses", "sût", "sussions", "sussiez", "sussent"] }, [Morpho.Mood.Cnd]: { [Morpho.Tense.Pr]: ["saurais", "saurais", "saurait", "saurions", "sauriez", "sauraient"] }, [Morpho.Mood.Imp]: { [Morpho.Tense.Pr]: ["$", "sache", "$", "sachons", "sachez", "$"] } }, "vouloir": { pp: "voulu", [Morpho.Mood.Ind]: { [Morpho.Tense.Pr]: ["veux", "veux", "veut", "voulons", "voulez", "veulent"], [Morpho.Tense.Pa]: ["voulus", "voulus", "voulut", "voulûmes", "voulûtes", "voulurent"], [Morpho.Aspect.I]: ["voulais", "voulais", "voulait", "voulions", "vouliez", "voulaient"], [Morpho.Tense.Fu]: ["voudrai", "voudras", "voudra", "voudrons", "voudrez", "voudront"] }, [Morpho.Mood.Sub]: { [Morpho.Tense.Pr]: ["veuille", "veuilles", "veuille", "veulions", "veuliez", "veuillent"], [Morpho.Aspect.I]: ["voulusse", "voulusses", "voulût", "voulussions", "voulussiez", "voulussent"] }, [Morpho.Mood.Cnd]: { [Morpho.Tense.Pr]: ["voudrais", "voudrais", "voudrait", "voudrions", "voudriez", "voudraient"] }, [Morpho.Mood.Imp]: { [Morpho.Tense.Pr]: ["$", "veuille", "$", "voulons", "veuillez", "$"] } }, "valoir": { pp: "valu", [Morpho.Mood.Ind]: { [Morpho.Tense.Pr]: ["vaux", "vaux", "vaut", "valons", "valez", "valent"], [Morpho.Tense.Pa]: ["valus", "valus", "valut", "valûmes", "valûtes", "valurent"], [Morpho.Aspect.I]: ["valais", "valais", "valait", "valions", "valiez", "valaient"], [Morpho.Tense.Fu]: ["vaudrai", "vaudras", "vaudra", "vaudrons", "vaudrez", "vaudront"] }, [Morpho.Mood.Sub]: { [Morpho.Tense.Pr]: ["vaille", "vailles", "vaille", "valions", "valiez", "vaillent"], [Morpho.Aspect.I]: ["valusse", "valusses", "valût", "valussions", "valussiez", "valussent"] }, [Morpho.Mood.Cnd]: { [Morpho.Tense.Pr]: ["vaudrais", "vaudrais", "vaudrait", "vaudrions", "vaudriez", "vaudraient"] }, [Morpho.Mood.Imp]: { [Morpho.Tense.Pr]: ["$", "vaux", "$", "valons", "valez", "$"] } }, "falloir": { pp: "fallu", [Morpho.Mood.Ind]: { [Morpho.Tense.Pr]: ["$", "$", "faut", "$", "$", "$"], [Morpho.Tense.Pa]: ["$", "$", "falut", "$", "$", "$"], [Morpho.Aspect.I]: ["$", "$", "falait", "$", "$", "$"], [Morpho.Tense.Fu]: ["$", "$", "faudra", "$", "$", "$"] }, [Morpho.Mood.Sub]: { [Morpho.Tense.Pr]: ["$", "$", "faille", "$", "$", "$"], [Morpho.Aspect.I]: ["$", "$", "falût", "$", "$", "$"] }, [Morpho.Mood.Cnd]: { [Morpho.Tense.Pr]: ["$", "$", "faudrait", "$", "$", "$"] }, [Morpho.Mood.Imp]: { [Morpho.Tense.Pr]: ["$", "$", "$", "$", "$", "$"] } }, "faire": { pp: "fait", [Morpho.Mood.Ind]: { [Morpho.Tense.Pr]: ["fais", "fais", "fait", "faisons", "faites", "font"], [Morpho.Tense.Pa]: ["fis", "fis", "fit", "fîmes", "fîtes", "firent"], [Morpho.Aspect.I]: ["faisais", "faisais", "faisait", "faisions", "faisiez", "faisaient"], [Morpho.Tense.Fu]: ["ferai", "feras", "fera", "ferons", "ferez", "feront"] }, [Morpho.Mood.Sub]: { [Morpho.Tense.Pr]: ["fasse", "fasses", "fasse", "fassions", "fassiez", "fassent"], [Morpho.Aspect.I]: ["fisse", "fisses", "fît", "fissions", "fissiez", "fissent"] }, [Morpho.Mood.Cnd]: { [Morpho.Tense.Pr]: ["ferais", "ferais", "ferait", "ferions", "feriez", "feraient"] }, [Morpho.Mood.Imp]: { [Morpho.Tense.Pr]: ["$", "fais", "$", "faisons", "faites", "$"] } } }; //Verbs which are conjugated with auxilary verb: être //https://en.wiktionary.org/wiki/Category:French_verbs_taking_être_as_auxiliary const etreVerbs = { "advenir": 1, "aller": 1, "apparaitre": 1, "apparaître": 1, "arriver": 1, "bienvenir": 1, "débrayer": 1, "décéder": 1, "descendre": 1, "devenir": 1, "disparaître": 1, "entrer": 1, "impartir": 1, "intervenir": 1, "marrer": 1, "monter": 1, "mourir": 1, "naitre": 1, "naître": 1, "obvenir": 1, "paraître": 1, "paralyser": 1, "partir": 1, "parvenir": 1, "passer": 1, "provenir": 1, "réapparaître": 1, "redescendre": 1, "redevenir": 1, "remonter": 1, "renaitre": 1, "renaître": 1, "rentrer": 1, "repartir": 1, "repasser": 1, "ressortir": 1, "ressusciter": 1, "rester": 1, "retomber": 1, "retourner": 1, "revenir": 1, "sortir": 1, "surmener": 1, "survenir": 1, "tomber": 1, "vader": 1, "venir": 1 }; /** * Verbs of goup 1 which ends with either eler or eter; and don't * double the t or l when meeting a silent e in conjugation \\ * Source: http://www.ortholud.com/code/les-verbes.php?terminaison=eler,%20eter * @type {Object} */ const notDoubleLT = { "cel": 1, "décel": 1, "recel": 1, "cisel": 1, "démantel": 1, "écartel": 1, "encastel": 1, "gel": 1, "dégel": 1, "congel": 1, "surgel": 1, "martel": 1, "model": 1, "pel": 1, "achet": 1, "rachet": 1, "béguet": 1, "corset": 1, "crochet": 1, "filet": 1, "furet": 1, "halet": 1 }; const CHAPEAU = { "a": "â", "e": "ê", "i": "î", "o": "ô", "u": "û" }; const vowels = "aeiouyâàëéêèïîôûù"; //========================================== // INNER VARIABLES //========================================== /** * An object to be a midium between different functions * @type {Object} */ let verbInfo = { /** * The verb * @type {String} */ verb: "", /** * The group of the verb * @type {Number} */ group: 0, inf: "", irr: {} }; const abbreviation = { //https://en.wiktionary.org/wiki/Category:French_abbreviations "all": 1, "art": 1, "auj": 1, "av": 1, "bar": 1, "bd": 1, "bn": 1, "boul": 1, "c": 1, "cam": 1, "cart": 1, "cb": 1, "ch": 1, "ci": 1, "coll": 1, "cymb": 1, "dr": 1, "dre": 1, "éd": 1, "ép": 1, "ex": 1, "fig": 1, "fi": 1, "gén": 1, "hb": 1, "hon": 1, "hpe": 1, "lal": 1, "Ltée": 1, "m": 1, "me": 1, "mlle": 1, "mm": 1, "mme": 1, "mmes": 1, "ms": 1, "mtl": 1, "néerl": 1, "qc": 1, "resp": 1, "rte": 1, "sask": 1, "sax": 1, "st": 1, "ste": 1, "surt": 1, "tbn": 1, "trb": 1, "trgl": 1, "vc": 1, "vl": 1, "vlc": 1, "vn": 1, "voy": 1, //https://fr.wikipedia.org/wiki/Mois#Abr.C3.A9viations "janv": 1, "févr": 1, "avr": 1, "juil": 1, "juill": 1, "sept": 1, "oct": 1, "nov": 1, "déc": 1, }; const STOP_WORDS = { "afin": 1, "au": 1, "aux": 1, "avec": 1, "ce": 1, "ces": 1, "comme": 1, "dans": 1, "de": 1, "des": 1, "du": 1, "elle": 1, "en": 1, "et": 1, "eux": 1, "il": 1, "je": 1, "la": 1, "le": 1, "leur": 1, "les": 1, "lui": 1, "ma": 1, "mais": 1, "me": 1, "même": 1, "mes": 1, "moi": 1, "mon": 1, "ne": 1, "nos": 1, "notre": 1, "nous": 1, "on": 1, "ou": 1, "par": 1, "pas": 1, "pour": 1, "qu": 1, "que": 1, "qui": 1, "sa": 1, "se": 1, "ses": 1, "son": 1, "sur": 1, "ta": 1, "te": 1, "tes": 1, "toi": 1, "ton": 1, "tu": 1, "un": 1, "une": 1, "vos": 1, "votre": 1, "vous": 1, "c": 1, "d": 1, "j": 1, "l": 1, "à": 1, "m": 1, "n": 1, "s": 1, "t": 1, "y": 1, "été": 1, "étée": 1, "étées": 1, "étés": 1, "étant": 1, "étante": 1, "étants": 1, "étantes": 1, "suis": 1, "es": 1, "est": 1, "sommes": 1, "êtes": 1, "sont": 1, "serai": 1, "seras": 1, "sera": 1, "serons": 1, "serez": 1, "seront": 1, "serais": 1, "serait": 1, "serions": 1, "seriez": 1, "seraient": 1, "étais": 1, "était": 1, "étions": 1, "étiez": 1, "étaient": 1, "fus": 1, "fut": 1, "fûmes": 1, "fûtes": 1, "furent": 1, "sois": 1, "soit": 1, "soyons": 1, "soyez": 1, "soient": 1, "fusse": 1, "fusses": 1, "fût": 1, "fussions": 1, "fussiez": 1, "fussent": 1, "ayant": 1, "ayante": 1, "ayantes": 1, "ayants": 1, "eu": 1, "eue": 1, "eues": 1, "eus": 1, "ai": 1, "as": 1, "avons": 1, "avez": 1, "ont": 1, "aurai": 1, "auras": 1, "aura": 1, "aurons": 1, "aurez": 1, "auront": 1, "aurais": 1, "aurait": 1, "aurions": 1, "auriez": 1, "auraient": 1, "avais": 1, "avait": 1, "avions": 1, "aviez": 1, "avaient": 1, "eut": 1, "eûmes": 1, "eûtes": 1, "eurent": 1, "aie": 1, "aies": 1, "ait": 1, "ayons": 1, "ayez": 1, "aient": 1, "eusse": 1, "eusses": 1, "eût": 1, "eussions": 1, "eussiez": 1, "eussent": 1 }; //========================================== // STEMMING FUNCTIONS //========================================== //http://snowball.tartarus.org/algorithms/french/stemmer.html function __snowballStemmer(word) { //The word must be lower case //============================ word = word.toLowerCase(); //vowel marking: considering some vowels as cosonents //=================================================== //TODO these are in conflict; fix may be using a loop rather than regexp word = word.replace("qu", "qU"); word = word.replace(new RegExp("([" + vowels + "])([ui])([" + vowels + "])", "g"), function(match, p1, p2, p3) { return p1 + p2.toUpperCase() + p3; } ); word = word.replace(new RegExp("([" + vowels + "])y", "g"), "$1Y"); word = word.replace(new RegExp("y([" + vowels + "])", "g"), "Y$1"); //mark regions //============ let rv = "", r1 = "", r2 = ""; let m; let reg = new RegExp("^[" + vowels + "]{2}.(.*)$"); if ((m = reg.exec(word)) != null) { //the word starts with two vowels rv = m[1]; } else { //The word don't start with two vowels reg = new RegExp("^(par|col|tap)(.*)$"); if ((m = reg.exec(word)) != null) rv = m[2];//if it starts with par, col or tap else { //otherwise, it's the string after the first vowel with is not a starting one reg = new RegExp("^.[^" + vowels + "]*" + "[" + vowels + "]" + "(.*)$"); if ((m = reg.exec(word)) != null) rv = m[1]; } } //R1 is the region after the first non-vowel following a vowel, //or the end of the word if there is no such non-vowel. reg = new RegExp("^[^" + vowels + "]*[" + vowels + "]+[^" + vowels + "](.*)$"); if ((m = reg.exec(word)) != null) r1 = m[1]; //R2 is the region after the first non-vowel following a vowel in R1, //or the end of the word if there is no such non-vowel if ((m = reg.exec(r1)) != null) r2 = m[1]; //console.log("rv= " + rv + ", r1= " + r1 + ", r2= " + r2); let pastWord = word; //Step 1 let processed = __snowballStep1(word, rv, r1, r2); //console.log(processed); word = processed.stem; //console.log("step1 word= " + word); if (processed.next) { word = __snowballStep2(word, rv, r2); } //console.log("step2 word= " + word); if (word != pastWord) { //step3 word = __snowballStep3(word); } //console.log("step3 word= " + word); //The word hasn't been altered in any step if (word === pastWord) { //step4 word = __snowballStep4(word, rv, r2); } //console.log("step4 word= " + word); //Step 5: Undouble //If the word ends enn, onn, ett, ell or eill, delete the last letter if (/(?:enn|onn|ett|ei?ll)$/.test(word)) word = word.slice(0, -1); //Step 6: Un-accent //If the words ends é or è followed by at least one non-vowel, remove the accent from the e. word = word.replace(new RegExp("[éè]([^" + vowels + "]+)$"), "e$1"); return word.toLowerCase(); } function __snowballStep4(word, rv, r2) { //If the word ends s, not preceded by a, i, o, u, è or s, delete it. if(/[^aiouès]s$/.test(word)) word = word.slice(0, -1); //ion if (r2.endsWith("ion") && /ion[st]$/.test(rv)) return word.slice(0, -3); //ier ière Ier Ière { let m, reg = new RegExp("^.*([iI](?:er|ère))$"); if ((m = reg.exec(word)) != null && rv.endsWith(m[1])) return word.slice(0, -m[1].length) + "i"; } //e in rv too if (word.endsWith("e")) return word.slice(0, -1); //&& rv.endsWith("e") if (word.endsWith("gue")) return word.slice(0, -1); return word; } function __snowballStep3(word) { if (word.endsWith("Y")) return word.slice(0, -1) + "i"; if (word.endsWith("ç")) return word.slice(0, -1) + "c"; return word; } //Verb suffixes removal function __snowballStep2(word, rv, r2) { let m, reg; //Step 2a: Verb suffixes beginning i //Search for the longest among the following suffixes and if found, delete if preceded by a non-vowel. //îmes ît îtes i ie ies ir ira irai iraIent irais // irait iras irent irez iriez irions irons iront is // issaIent issais issait issant issante issantes issants // isse issent isses issez issiez issions issons it reg = new RegExp("(îmes|ît|it|îtes|ie?s?|i[rst]|ir(?:as?|ai|ont)|iss(?:ante?s?|es?)|(ir|iss)(?:ai[st]|aIent|i?ons|i?ez|ent))$"); if ((m = reg.exec(word)) != null) { if ((new RegExp("[^" + vowels + "]" + m[1])).test(rv)) return word.slice(0, -m[1].length); } //Step 2b: Other verb suffixes //ions: delete if in R2 if (word.endsWith("ions") && r2.endsWith("ions")) return word.slice(0, -4); //é ée ées és èrent er era erai eraIent erais erait //eras erez eriez erions erons eront ez iez reg = new RegExp("^.*(er|i?ez|èrent|ée?s?|er(?:as?|ai[st]?|i?ez|i?ons|ont|aIent))$"); if ((m = reg.exec(word)) != null) { if (rv.indexOf(m[1]) > -1) return word.slice(0, -m[1].length); } //âmes ât âtes a ai aIent ais ait ant ante antes ants //as asse assent asses assiez assions reg = new RegExp("^.*(ât|â[tm]es|as?|ai[st]?|ante?s?|aIent|ass(?:es?|ent|iez|ions))$"); if ((m = reg.exec(word)) != null && rv.indexOf(m[1]) > -1) { word = word.slice(0, -m[1].length); //if preceded by e, delete if (word.endsWith("e") && rv.indexOf("e" + m[1]) > -1) return word.slice(0, -1); return word; } return word; } //Standard suffix removal function __snowballStep1(word, rv, r1, r2) { let m, reg; //ance iqUe isme able iste eux ances iqUes ismes ables istes reg = new RegExp("^.*(eux|ances?|iqUes?|ismes?|ables?|istes?)$"); if ((m = reg.exec(word)) != null) { if (r2.endsWith(m[1])) return {stem:word.slice(0, -m[1].length), next:false}; } //atrice ateur ation atrices ateurs ations reg = new RegExp("^.*(atrices?|ateurs?|ations?)$"); if ((m = reg.exec(word)) != null) { if (r2.endsWith(m[1])) { word = word.slice(0, -m[1].length); if (!word.endsWith("ic")) return {stem:word, next:false}; if (r2.endsWith("ic" + m[1])) return {stem:word.slice(0, -2), next:false}; return {stem:word.slice(0, -1) + "qU", next:false}; } } //logie logies reg = new RegExp("^.*log(ies?)$"); if ((m = reg.exec(word)) != null) { if (r2.endsWith("log" + m[1])) return {stem:word.slice(0, -m[1].length), next:false}; } //usion ution usions utions reg = new RegExp("^.*u(sions?|tions?)$"); if ((m = reg.exec(word)) != null) { if (r2.endsWith("u" + m[1])) return {stem:word.slice(0, -m[1].length), next:false}; } //ence ences reg = new RegExp("^.*en(ces?)$"); if ((m = reg.exec(word)) != null) { if (r2.endsWith("en" + m[1])) return {stem:word.slice(0, -m[1].length) + "t", next:false}; } //ement ements reg = new RegExp("^.*(ements?)$"); if ((m = reg.exec(word)) != null && rv.endsWith(m[1])) { //delete if in RV word = word.slice(0, -m[1].length); //if preceded by iv, delete if in R2 (and if further preceded by at, delete if in R2) if (r2.endsWith("iv" + m[1])) {//here word.endsWith("iv") ommited since r2 is the end word = word.slice(0, -2); if (r2.endsWith("ivat" + m[1])) return {stem:word.slice(0, -2), next:false}; return {stem:word, next:false}; } //if preceded by eus, delete if in R2, else replace by eux if in R1, otherwise, if (word.endsWith("eus")) { if (r2.endsWith("eus" + m[1])) return {stem:word.slice(0, -3), next:false}; if (r2.endsWith("eus" + m[1])) return {stem:word.slice(0, -1) + "x", next:false}; } //if preceded by abl or iqU, delete if in R2, otherwise, if ( (new RegExp("^.*(abl|iqU)" + m[1] + "$")).test(r2)) { return {stem:word.slice(0, -3), next:false}; } //if preceded by ièr or Ièr, replace by i if in RV if ( (new RegExp("^.*[iI]èr" + m[1] + "$")).test(rv)) { return {stem:word.slice(0, -3) + "i", next:false}; } //otherwise return {stem:word, next:false}; }//end ement(s) //ité ités reg = new RegExp("^.*(ités?)$"); if ((m = reg.exec(word)) != null && r2.endsWith(m[1])) { //delete if in R2 word = word.slice(0, -m[1].length); //if preceded by abil, delete if in R2, else replace by abl if (word.endsWith("abil")){ if (r2.endsWith("abil" + m[1])) return {stem:word.slice(0, -4), next:false}; return {stem:word.slice(0, -2) + "l", next:false}; } //if preceded by ic, delete if in R2, else replace by iqU if (word.endsWith("ic")){ word = word.slice(0, -2); if (r2.endsWith("ic" + m[1])) return {stem:word, next:false}; return {stem:word + "iqU", next:false}; } //if preceded by iv, delete if in R2 if (r2.endsWith("iv" + m[1])) return {stem:word.slice(0, -2), next:false}; //otherwise return {stem:word, next:false}; } //if ive ifs ives reg = new RegExp("^.*(ifs?|ives?)$"); if ((m = reg.exec(word)) != null && r2.endsWith(m[1])) { //delete if in R2 word = word.slice(0, -m[1].length); //if preceded by at, delete if in R2 if (r2.endsWith("at" + m[1])) { word = word.slice(0, 2); if (! word.endsWith("ic")) return {stem:word, next:false}; //and if further preceded by ic, delete if in R2, else replace by iqU word = word.slice(0, 2); if (r2.endsWith("icat" + m[1])) return {stem:word, next:false}; return {stem:word + "iqU", next:false}; } } //eaux if (word.endsWith("eaux")) return {stem:word.slice(0, -1), next:false}; //aux replace with al if in R1 if (r1.endsWith("aux")) return {stem:word.slice(0, -2) + "l", next:false}; //euse euses reg = new RegExp("^.*(euses?)$"); if ((m = reg.exec(word)) != null) { //delete if in R2 if (r2.endsWith(m[1])) return {stem:word.slice(0, -m[1].length), next:false}; //else replace by eux if in R1 if (r1.endsWith(m[1])) return {stem:word.slice(0, 2-m[1].length) + "x", next:false}; } //issement issements reg = new RegExp("^.*[^" + vowels + "](issements?)$"); if ((m = reg.exec(word)) != null) { //delete if in R1 and preceded by a non-vowel if (r1.endsWith(m[1])) return {stem:word.slice(0, -m[1].length), next:false}; } // amment, emment reg = new RegExp("^.*([ae])mment$"); if ((m = reg.exec(word)) != null) { //replace with ant, ent if in RV if (rv.endsWith(m[1] + "mment")) return {stem:word.slice(0, -5) + "nt", next:false}; } // ment ments reg = new RegExp("^.*(ments?)$"); if ((m = reg.exec(word)) != null) { //delete if preceded by a vowel in RV if ((new RegExp("^.*[" + vowels + "]" + m[1]) + "$").test(rv)) return {stem:word.slice(0, -m[1].length), next:false}; } return {stem:word, next:true}; } //========================================== // CONVERTION FUNCTIONS //========================================== /** * Transforms a singular noun to plural * * @method __singular2plural * @private * @static * @memberof FraMorpho * @param {String} noun The noun to be transformed to plural * @return {String} Plural form of the given noun */ function __singular2plural(noun) { //https://www.francaisfacile.com/exercices/exercice-francais-2/exercice-francais-15114.php if (/[sxz]$/.test(noun)) return noun; if (/^(bij|caill|ch|gen|hib|jouj|p)ou$/.test(noun)) return noun + "x"; if (noun.endsWith("al") && ! /^(b|carnav|festiv|chac|rég|c)al$/.test(noun)) return noun.slice(0, -1) + "ux"; if (/^(b|cor|ém|soupir|trav|vent|vitr)ail$/.test(noun)) return noun.slice(0, -2) + "ux"; if (/[ae]u$/.test(noun)) { return noun + (/^(sarrau|landau|pneu)$/.test(noun)? "s": "x"); } return noun + "s"; } //========================================== // CONJUGATION FUNCTIONS //========================================== function __conj(verb, opts) { //will be used for dé-faire, re-faire, satis-faire //to carry the first part before the hyphen //----------------------------------------- //Also, will be used for negation let begin = ""; if (verb === "falloir") { if (opts.person != Morpho.Person.T || opts.number != Morpho.GNumber.S) return ""; } else if (/^(dé|re|satis)faire/.test(verb)) { begin = verb.slice(0, -5); verb = "faire"; } __preProcessVerb(verb); //past Participal //also, will be used for negation; to carry the word "pas" let pp = "", //conjugation table, in case of irrugular verbs conjTab; if (opts.negated) pp = " pas"; if (opts.aspect === Morpho.Aspect.P || (opts.mood != Morpho.Mood.Ind && opts.tense === Morpho.Tense.Pa)) { pp += " " + begin + verbInfo.pp; begin = ""; verb = verbInfo.aux; conjTab = irregular[verb]; if (verb === "être") { pp += (opts.gender === Morpho.Gender.F)? "e": ""; pp += (opts.number === Morpho.GNumber.S)? "": "s"; } if (opts.aspect === Morpho.Aspect.P) { if (opts.period === "long" || opts.mood === Morpho.Mood.Sub) opts.aspect = Morpho.Aspect.I; else opts.aspect = Morpho.Aspect.S; } else { opts.tense = Morpho.Tense.Pr; if (opts.mood === Morpho.Mood.Cnd && opts.form === 2){ opts.aspect = Morpho.Aspect.I; opts.mood = Morpho.Mood.Sub; } } } if (opts.negated) begin = "ne " + begin; if (!conjTab && verbInfo.group === 4) conjTab = verbInfo.irr; //Irregular verbs and composed conjugations if (conjTab) { let conj = __getSuffix(opts, conjTab); if (!conj || conj === "$") return ""; if (begin === "ne " && /[haeuio]/.test(conj.charAt(0))) begin = "n'"; return begin + conj + pp; } let suffix = __getSuffix(opts); if (!suffix || suffix === "$") return ""; let inf = verbInfo.inf; //verbs 1 irregularities if (verbInfo.group === 1) { if (inf === "envoy" && opts.mood === Morpho.Mood.Ind && opts.tense === Morpho.Tense.Fu) { inf = "enverr"; suffix = suffix.slice(2); } else if (verbInfo.irr.reg.test(suffix)) inf = verbInfo.irr.rep; } else if (verbInfo.group === 3) { { //irregularities let irr = __getG3IrregularInfSuff(inf, suffix, opts); suffix = irr.suff; inf = irr.inf; } if (suffix === "t" && /[dt]$/.test(inf)) suffix = ""; else if (suffix.startsWith("^")) { suffix = suffix.slice(1); let end = inf.slice(-1); if (CHAPEAU[end]) inf = inf.slice(0, -1) + CHAPEAU[end]; else {//venir //vînmes for (let i = inf.length - 1; i > 0; i--) { let idx = "aiuo".indexOf(inf.charAt(i)); if ( idx > -1 ) { inf = inf.slice(0, idx) + CHAPEAU[inf.charAt(i)] + inf.slice(idx+1); break; } } } } else if (/^(ons|ez)$/.test(suffix) && /[ao]i$/.test(inf)) { inf = inf.slice(0, -1) + "y"; } } else {//group 2 if (inf === "haï") { suffix = suffix.slice(1); if ( opts.mood === Morpho.Mood.Ind && opts.aspect === Morpho.Aspect.S && opts.tense === Morpho.Tense.Pr && opts.number === Morpho.GNumber.S) { inf = inf.slice(0, -1) + "i"; } else if (opts.mood === Morpho.Mood.Imp && opts.number === Morpho.GNumber.S) { if (inf.length > 0) inf = inf.slice(0, -1) + "i"; } } } if (begin === "ne " && /[haeuio]/.test(inf.charAt(0))) begin = "n'"; return begin + inf + suffix + pp; }; function __getSuffix(opts, irrTab) { let groupTab; if (irrTab) groupTab = irrTab; else switch (verbInfo.group) { case 1: groupTab = g1Suffix; break; case 2: groupTab = g2Suffix; break; case 3: groupTab = g3Suffix; break; default: return "$"; } let moodTab = groupTab[opts.mood]; if (! moodTab) return "$"; if (opts.aspect === Morpho.Aspect.P) return "$"; let key = (opts.aspect === Morpho.Aspect.I)? Morpho.Aspect.I: opts.tense; let pronounTab = moodTab[key]; if (! pronounTab) return "$"; return pronounTab[__getPronounIndex(opts)]; } function __getG3IrregularInfSuff(inf, suff, opts) { let res = {}; let p = suff; let m = /^<([^>]+)>(.*)$/.exec(suff); if (m != null && verbInfo.irr[m[1]]) { inf = verbInfo.irr[m[1]]; suff = m[2]; } m = /^(.*)\[(.*)\]$/.exec(inf); if (m != null) { inf = m[1]; //console.log(inf); let rep = m[2].split(","); let i = 0; for (; i < rep.length; i++) { let rep2 = rep[i].split(":"); let r = new RegExp(rep2[0]); if (r.test(p)) { if (rep2[1] === "G1") suff = __getSuffix(opts, g1Suffix); else suff = rep2[1]; break; } } } res.inf = inf; res.suff = suff; return res; } /** * A function that gives the pronoun index in conjugation table * * @method __getPronounIndex * @private * @memberof FraMorpho * @param {Object} opts contains person and number * @return {Number} a number from 0 to 5 */ function __getPronounIndex(opts) { let numberIdx = (opts.number === Morpho.GNumber.S)? 0: 3; let personIdx = Object.values(Morpho.Person).indexOf(opts.person); return personIdx + numberIdx; } //========================================== // CONJUGATION PREPROCESSING FUNCTIONS //========================================== /** * Get the verbs group: 1, 2 or 3. * * @method __preProcessVerb * @private * @memberof FraMorpho * @param {String} verb the verb */ function __preProcessVerb(verb) { if (verbInfo.verb === verb) return; verbInfo.verb = verb; verbInfo.irr = {}; verbInfo.pp = null; //auxilary verbInfo.aux = (etreVerbs[verb])? "être": "avoir"; if (irregular[verb]) { verbInfo.irr = irregular[verb]; verbInfo.pp = verbInfo.irr.pp; verbInfo.group = 4;//irregular return; } if (verb.endsWith("er")) { verbInfo.group = 1; __extractG1Irr(); return; } if (verb.endsWith("ir") && verb.length > 3) { let idx = verbs2g[verb.slice(0, 2)]; let ref = verb.slice(2, -2); if (idx && idx[ref]) { verbInfo.group = 2; verbInfo.inf = verb.slice(0, -2); verbInfo.pp = verb.slice(0, -1); return; } } if (verb === "haïr") { verbInfo.group = 2; verbInfo.inf = verb.slice(0, -1); verbInfo.pp = verb.slice(0, -1); return; } verbInfo.group = 3; __extractG3Irr(); } function __extractG1Irr() { //infinitive let inf = verbInfo.verb.slice(0, -2); //infinitive replacement let rep = inf; //suffix test let reg = /^$/; if(/[cg]$/.test(inf)) { if (inf.endsWith("c")) rep = inf.slice(0, -1) + "ç"; else rep = inf + "e"; reg = /^[aoâ]/; } else { // not ending with -cer|-ger OR suffix not starting with a|o //Here we work just with silent endings (those suffixes starting with e) reg = /^e[^z]*$/; if (/[ou]y$/.test(inf)) rep = inf.slice(0, -1) + "i"; else { let m; if ((m = /([eé])(.)$/.exec(inf))) { // e or é followed by a char then er rep = inf.slice(0, -2); if (m[1] === "é" || ! "lt".includes(m[2]) || notDoubleLT[rep + "e" + m[2]]) rep += "è"; //verb ends with "eter"|"eler" and double lt //It can be ignored according to http://www.ortholud.com/code/les-verbes.php?terminaison=eler,%20eter else rep += "e" + m[2];//double the l or t rep += m[2]; } } } verbInfo.inf = inf; verbInfo.pp = inf + "é"; verbInfo.irr = {}; verbInfo.irr.reg = reg; verbInfo.irr.rep = rep; //past participle } function __extractG3IrrS1 (irr, ending) { //================================= //First singular present indicative //================================= let inf = verbInfo.inf; if (ending === "re") { // ======== -re irregularities if (/[aeo]ind$/.test(inf)) {//----- indre (craindre, etc.) ------ verbInfo.pp = irr.s1 = inf.slice(0, -1); verbInfo.pp += "t"; irr.p1 = irr.p3 = irr.p = inf.slice(0, -2) + "gn"; irr.p += "i"; } else if (/^(?:n|conn|reconn|par|appar|repar|dispar)aît$/.test(inf)) { let inf2 = inf.slice(0, -2); irr.s1 = inf2 + "[<s1>s:is,<s1>t:ît]"; irr.p1 = inf2 + "iss"; if (inf2 !== "na") verbInfo.pp = inf2.slice(0, -1) + "u"; else { verbInfo.pp = "né"; irr.p = "naqui"; } } else if (/^(viv|poursuiv|suiv|batt|(pro|per|compro|sou|trans)?mett|(ré|ab)soud)$/.test(inf)) { irr.s1 = inf.slice(0, -1); //mettre, permettre, etc. if (inf.endsWith("mett")) verbInfo.pp = inf.slice(0, -3) + "is"; else if (inf.endsWith("d")) { //résoudre, absoudre irr.p1 = inf.slice(0, -2) + "lv"; if (inf.startsWith("r")) {//résoudre irr.p = verbInfo.pp = "résolu"; } else { verbInfo.pp = "absous"; irr.p = "absolu"; } } else if ( inf === "viv") verbInfo.pp = "vécu";//vivre else {//suivre, battre irr.p = inf + "i"; if (inf.endsWith("v")) verbInfo.pp = irr.p; } } else if (/^(plai|clo)$/.test(inf)) {//plaire, clore irr.p1 = inf + "s"; if (inf === "clo") { irr.s1 = "cl[<s1>s:os,<s1>t:ôt]"; verbInfo.pp = "clos"; irr.p = "$";//clos doesn't have past } else { irr.s1 = "pla[<s1>s:is,<s1>t:ît]"; verbInfo.pp = "plu"; } } else if (/^(con)?vainc$/.test(inf)) {//vaincre, convaincre irr.s1 = inf + "[<s1>s:s,<s1>t:]"; irr.p1 = inf.slice(0, -1) + "qu"; irr.p = irr.p1 + "i"; } } else if (ending === "oir") { // ======== -oir irregularities if (/^(dev|.*cev)$/.test(inf)) {//devoir, -cevoir let inf2 = inf.slice(0, -2); if (inf2.endsWith("c")) inf2 = inf2.slice(0, -1) + "ç"; irr.s1 = inf2 + "oi"; irr.p3 = inf2 + "oiv"; irr.p = inf2 + "u"; verbInfo.pp = inf2 + (inf2.endsWith("c")? "u": "û"); //TODO devoir pp = dû (sing. masculine), others u } else if (/^(v|rev|ch|éch)$/.test(inf)) {//voir, revoir, choir, échoir irr.p3 = irr.s1 = inf + "oi"; irr.p1 = inf + "oy"; verbInfo.pp = inf + "u"; if (inf.endsWith("v")) irr.p = inf + "i"; } else if (/^(é|pro)?mouv$/.test(inf)) {//mouvoir, émouvoir, promouvoir let inf2 = inf.slice(0, -3); irr.s1 = inf2 + "eu"; irr.p3 = irr.s1 + "v"; verbInfo.pp = inf2 + "û"; //TODO mevoir pp = mû (sing. masculine) others u } else if (inf === "asse") { //aseoir irr.p3 = irr.s1 = "assoi"; irr.p1 = "assoy"; verbInfo.pp = "assis"; } else if (inf === "pleuv") { irr.s1 = "[<s1>s:$,<s1>t:pleut]"; irr.p3 = irr.p1 = "$"; verbInfo.pp = "plu"; //TODO fix pleuvoir } /* Will be treated as irregular let m; if ((m = /^(.*)(val|pouv|voul)$/.exec(inf)) != null) { irr.s1 = m[1] + m[2].charAt(0) + ((m[2].charAt(1) === "o")? "e": "a") + "u[x|t]"; } */ } else { // ======== -ir irregularities if (/^.*[tv]en$/.test(inf)){// -venir, -tenir let inf2 = inf.slice(0, -2); irr.s1 = inf2 + "ien"; irr.p3 = irr.s1 + "n"; verbInfo.pp = inf + "u"; irr.p = inf2 + "in"; } else if (/^((dé|re)?part|(en|ren)?dorm|ment|dément|(con|pres|res)?sent|(des|res)?serv|(res)?sort|(dé|re)?vêt)$/.test(inf)) { irr.s1 = inf.slice(0, -1); if (inf.endsWith("êt")) verbInfo.pp = irr.s1 + "u"; } else if (/^(cueill|(c|déc)?ouvr|offr|souffr)$/.test(inf)) { irr.s1 = inf + "[<s1>.*:G1]"; if (inf !== "cueill") { irr.p1 = inf; verbInfo.pp = inf.slice(0, -1) + "ert"; } } else if (inf === "requér") { irr.s1 = "requier"; irr.p3 = "req