Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Inflectors for French counters and nouns (singular <-> plural) #56

Merged
merged 9 commits into from

2 participants

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
66 lib/natural/inflectors/fr/count_inflector.js
@@ -0,0 +1,66 @@
+/*
+Copyright (c) 2012, Guillaume Marty
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/**
+ * Numeral inflector for French.
+ * @see http://66.46.185.79/bdl/gabarit_bdl.asp?t1=1&id=4271
+ * @see http://fr.wikipedia.org/wiki/Ier_si%C3%A8cle
+ *
+ * Also handles roman numerals as a bonus. The rules are the same than for their
+ * arabic numerals equivalent.
+ *
+ * \@todo Add inflector for gender and number. Ex:
+ * * CountInflector(1, MASCULINE, SINGULAR); // "1er" (Default)
+ * * CountInflector(1, MASCULINE, PLURAL); // "1ers"
+ * * CountInflector(1, FEMINIE, SINGULAR); // "1re"
+ * * CountInflector(1, FEMINIE, PLURAL); // "1res"
+ * \@todo add alternative form for 2. Ex:
+ * * CountInflector(2, undefined, undefined, ALTERNATIVE); // "2nd"
+ */
+
+
+var CountInflector = function() {
+};
+
+
+/**
+ * @param {number|string} i
+ * @return {string}
+ */
+CountInflector.nth = function(i) {
+ return i.toString() + nthForm(i);
+};
+
+
+/**
+ * @param {number|string} i
+ * @return {string}
+ */
+function nthForm(i) {
+ if (i == 1 || i == 'I') {
+ return 'er';
+ }
+
+ return 'e';
+}
+
+module.exports = CountInflector;
View
235 lib/natural/inflectors/fr/noun_inflector.js
@@ -0,0 +1,235 @@
+/*
+ Copyright (c) 2012, Guillaume Marty
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+/**
+ * A noun inflector for French.
+ * Compiled from:
+ * \@see http://fr.wiktionary.org/wiki/Annexe:Pluriels_irr%C3%A9guliers_en_fran%C3%A7ais
+ * \@see http://fr.wikipedia.org/wiki/Pluriels_irr%C3%A9guliers_en_fran%C3%A7ais
+ *
+ * \@todo Take compounded noun into account (eaux-fortes, pique-nique...).
+ * \@todo General note: French also requires AdjectiveInflector (femininize...).
+ */
+
+var SingularPluralInflector = require('../singular_plural_inflector'),
+ util = require('util'),
+ FormSet = require('../form_set');
+
+function attach() {
+ var inflector = this;
+
+ String.prototype.singularizeNoun = function() {
+ return inflector.singularize(this);
+ };
+
+ String.prototype.pluralizeNoun = function() {
+ return inflector.pluralize(this);
+ };
+}
+
+
+
+/**
+ * @constructor
+ */
+var NounInflector = function() {
+ // Ambiguous a.k.a. invariant.
+ // \@todo Expand this list to be as comprehensive as possible.
+ this.ambiguous = [
+ // Nouns ending by -s
+ 'à-peu-près', 'à-propos', 'abattis', 'abcès', 'abois', 'abribus', 'abus',
+ 'accès', 'acquis', 'adénovirus', 'adonis', 'ados', 'agrès', 'aguets',
+ 'ailleurs', 'ais', 'albatros', 'albinos', 'alias', 'aloès', 'amaryllis',
+ 'amas', 'ampélopsis', 'ananas', 'anchois', 'angélus', 'anis', 'anticorps',
+ 'antihéros', 'antirides', 'anus', 'appas', 'appentis', 'appui-bras',
+ 'appuie-bras', 'arcanes', 'argus', 'arrérages', 'arrière-pays', 'as',
+ 'ascaris', 'asparagus', 'atlas', 'atours', 'aurochs', 'autobus',
+ 'autofocus', 'avant-bras', 'avant-corps', 'avant-propos', 'avers', 'avis',
+ 'axis', 'barbouillis', 'bas', 'beaujolais', 'beaux-arts', 'biais',
+ 'bibliobus', 'biceps', 'bicross', 'bien-fonds', 'bloc-notes', 'blockhaus',
+ 'blocus', 'blues', 'bois', 'bonus', 'bout-dehors', 'bouts-rimés',
+ 'branle-bas', 'bras', 'brebis', 'bris', 'brise-lames', 'brise-mottes',
+ 'brûlis', 'buis', 'burnous', 'bus', 'business', 'cabas', 'cacatoès',
+ 'cacatois', 'cactus', 'cadenas', 'cafouillis', 'caillebotis', 'calvados',
+ 'cambouis', 'campus', 'canevas', 'cannabis', 'carquois', 'cas',
+ 'casse-noisettes', 'casse-pieds', 'cassis', 'caucus', 'cens', 'cervelas',
+ 'chablis', 'chamois', 'chaos', 'chas', 'chasselas', 'châssis',
+ 'chatouillis', 'chauffe-assiettes', 'chauve-souris', 'chorus', 'choucas',
+ 'circoncis', 'cirrus', 'clafoutis', 'clapotis', 'cliquetis', 'clos',
+ 'cochylis', 'colis', 'coloris', 'commis', 'compas', 'compromis',
+ 'compte-chèques', 'compte-gouttes', 'compte-tours', 'concours', 'confins',
+ 'congrès', 'consensus', 'contrepoids', 'contresens', 'contretemps',
+ 'corn flakes', 'corps', 'corps-à-corps', 'corpus', 'cosinus', 'cosmos',
+ 'coulis', 'coupe-ongles', 'cours', 'court-jus', 'couscous', 'coutelas',
+ 'crocus', 'croquis', 'cross', 'cubitus', 'cumulus', 'cure-dents',
+ 'cure-ongles', 'cure-pipes', 'cursus', 'cyclo-cross', 'cyprès', 'dais',
+ 'damas', 'débarras', 'débours', 'débris', 'décès', 'dedans', 'dehors',
+ 'delirium tremens', 'demi-gros', 'dépens', 'dessous', 'dessus', 'détritus',
+ 'deux-mâts', 'deux-pièces', 'deux-points', 'deux-roues', 'deux-temps',
+ 'dévers', 'devis', 'diplodocus', 'discours', 'dos', 'ébats', 'éboulis',
+ 'échalas', 'edelweiss', 'élaeis', 'éleis', 'éléphantiasis', 'embarras',
+ 'empois', 'en-cas', 'encens', 'enclos', 'endos', 'engrais', 'entrelacs',
+ 'entremets', 'envers', 'épluche-légumes', 'ers', 'espace-temps',
+ 'essuie-mains', 'eucalyptus', 'ex-libris', 'excès', 'express', 'extrados',
+ 'faciès', 'fait-divers', 'fatras', 'faux-sens', 'favoris', 'ficus',
+ 'fier-à-bras', 'finnois', 'florès', 'focus', 'fœtus', 'fois', 'forceps',
+ 'fouillis', 'fracas', 'frais', 'français', 'franglais', 'frimas',
+ 'friselis', 'frisottis', 'froncis', 'frottis', 'fucus', 'gâchis', 'galetas',
+ 'galimatias', 'garde-à-vous', 'garde-corps', 'gargouillis', 'gars',
+ 'gâte-bois', 'gazouillis', 'génois', 'gibus', 'glacis', 'glas', 'gneiss',
+ 'gobe-mouches', 'grès', 'gribouillis', 'guet-apens', 'habeas corpus',
+ 'hachis', 'haras', 'hardes', 'harnais', 'haut-le-corps', 'hautbois',
+ 'herbe-aux-chats', 'héros', 'herpès', 'hiatus', 'hibiscus', 'hors-concours',
+ 'hors-pistes', 'hourdis', 'huis-clos', 'humérus', 'humus', 'ibis', 'iléus',
+ 'indique-fuites', 'infarctus', 'inlandsis', 'insuccès', 'intercours',
+ 'intrados', 'intrus', 'iris', 'isatis', 'jais', 'jars', 'jeans',
+ 'jeuconcours', 'judas', 'juliénas', 'jus', 'justaucorps', 'kakatoès',
+ 'kermès', 'kriss', 'lacis', 'laïus', 'lambris', 'lapis', 'laps', 'lapsus',
+ 'laquais', 'las', 'lattis', 'lave-mains', 'lavis', 'lèche-bottes',
+ 'lèche-vitrines', 'legs', 'lias', 'liégeois', 'lilas', 'lis', 'lœss',
+ 'logis', 'loris', 'lotus', 'louis', 'lupus', 'lys', 'mâchicoulis', 'madras',
+ 'maïs', 'malappris', 'malus', 'mânes', 'maquis', 'marais', 'maroilles',
+ 'marquis', 'mas', 'mass-médias', 'matelas', 'matois', 'médius', 'mépris',
+ 'mérinos', 'mess', 'mets', 'mi-bas', 'micro-ondes', 'mille-pattes',
+ 'millepertuis', 'minibus', 'minois', 'minus', 'mirabilis', 'mois',
+ 'monocorps', 'monte-plats', 'mors', 'motocross', 'mots-croisés', 'motus',
+ 'mouchetis', 'mucus', 'myosotis', 'nævus', 'négus', 'niais',
+ 'nimbo-stratus', 'nimbus', 'norois', 'nounours', 'nu-pieds', 'oasis',
+ 'obus', 'olibrius', 'omnibus', 'opus', 'os', 'ours', 'ouvre-boîtes',
+ 'ouvre-bouteilles', 'palais', 'palis', 'palmarès', 'palus', 'panais',
+ 'panaris', 'pancréas', 'papyrus', 'par-dehors', 'paradis', 'parcours',
+ 'pardessus', 'pare-balles', 'pare-chocs', 'parvis', 'pas', 'passe-temps',
+ 'pataquès', 'pathos', 'patois', 'pavois', 'pays', 'permis',
+ 'petit-bourgeois', 'petit-gris', 'petit-pois', 'phallus', 'phimosis',
+ 'pickles', 'pilotis', 'pique-fleurs', 'pis', 'pithiviers', 'pityriasis',
+ 'plateau-repas', 'plâtras', 'plein-temps', 'plexiglas', 'plexus', 'plus',
+ 'poids', 'pois', 'pont-levis', 'porte-avions', 'porte-bagages',
+ 'porte-billets', 'porte-bouteilles', 'porte-clés', 'porte-hélicoptères',
+ 'porte-jarretelles', 'porte-revues', 'pouls', 'préavis', 'presse-fruits',
+ 'presse-papiers', 'princeps', 'printemps', 'procès', 'processus', 'progrès',
+ 'propos', 'prospectus', 'protège-dents', 'psoriasis', 'pubis', 'puits',
+ 'pus', 'putois', 'quatre-épices', 'quatre-feuilles', 'quatre-heures',
+ 'quatre-mâts', 'quatre-quarts', 'quatre-temps', 'quitus', 'rabais',
+ 'rachis', 'radis', 'radius', 'raïs', 'ramassis', 'rébus', 'reclus',
+ 'recours', 'refus', 'relais', 'remords', 'remous', 'remue-méninges',
+ 'rendez-vous', 'repas', 'répons', 'repos', 'repris', 'reps', 'rétrovirus',
+ 'revers', 'rhinocéros', 'rictus', 'rince-doigts', 'ris', 'rollmops',
+ 'rosé-des-prés', 'roulis', 'rubis', 'salmigondis', 'salsifis', 'sans-logis',
+ 'sas', 'sassafras', 'sauternes', 'schnaps', 'schuss', 'secours', 'semis',
+ 'sens', 'serre-fils', 'serre-livres', 'sévices', 'sinus', 'skunks',
+ 'souris', 'sournois', 'sous-bois', 'stradivarius', 'stras', 'strass',
+ 'strato-cumulus', 'stratus', 'stress', 'succès', 'surdos', 'surplus',
+ 'surpoids', 'sursis', 'suspens', 'synopsis', 'syphilis', 'taffetas',
+ 'taillis', 'talus', 'tamaris', 'tamis', 'tapis', 'tas', 'taudis', 'temps',
+ 'tennis', 'terminus', 'terre-neuvas', 'tétanos', 'tétras', 'thalamus',
+ 'thermos', 'thesaurus', 'thésaurus', 'thymus', 'tire-fesses', 'tonus',
+ 'torchis', 'torticolis', 'tournedos', 'tournevis', 'tournis', 'tracas',
+ 'traîne-savates', 'travers', 'tréfonds', 'treillis', 'trépas', 'trias',
+ 'triceps', 'trichomonas', 'trois-étoiles', 'trois-mâts', 'trois-quarts',
+ 'trolleybus', 'tumulus', 'typhus', 'univers', 'us', 'utérus', 'vasistas',
+ 'vélocross', 'velours', 'verglas', 'verjus', 'vernis', 'vers',
+ 'vert-de-gris', 'vide-ordures', 'vide-poches', 'villageois', 'virus',
+ 'vis-à-vis', 'volubilis', 'vulgum pecus', 'waters', 'williams', 'xérès',
+
+ // Nouns ending by -x
+ 'abat-voix', 'afflux', 'alpax', 'anthrax', 'apex', 'aptéryx',
+ 'archéoptéryx', 'arrière-faix', 'bombyx', 'borax', 'bordeaux', 'bouseux',
+ 'box', 'carex', 'casse-noix', 'cedex', 'céphalothorax', 'cérambyx', 'chaux',
+ 'choix', 'coccyx', 'codex', 'contumax', 'coqueleux', 'cortex', 'courroux',
+ 'croix', 'crucifix', 'culex', 'demodex', 'duplex', 'entre-deux', 'époux',
+ 'équivaux', 'eux', 'ex', 'faix', 'faucheux', 'faux', 'fax', 'ferreux',
+ 'flux', 'fox', 'freux', 'furax', 'hapax', 'harengueux', 'hélix',
+ 'horse-pox', 'houx', 'index', 'influx', 'inox', 'juke-box', 'kleenex',
+ 'lagothrix', 'larynx', 'lastex', 'latex', 'lux', 'lynx', 'macareux', 'max',
+ 'mésothorax', 'mi-voix', 'mirepoix', 'motteux', 'multiplex', 'murex',
+ 'narthex', 'noix', 'onyx', 'opopanax', 'oropharynx', 'paix', 'panax',
+ 'perdrix', 'pharynx', 'phénix', 'phlox', 'phoenix', 'pneumothorax', 'poix',
+ 'portefaix', 'pousse-cailloux', 'preux', 'prix', 'prothorax', 'pucheux',
+ 'pyrex', 'pyroligneux', 'quadruplex', 'queux', 'redoux', 'reflex', 'reflux',
+ 'relax', 'rhinopharynx', 'rose-croix', 'rouvieux', 'roux', 'rumex',
+ 'saindoux', 'sardonyx', 'scolex', 'sèche-cheveux', 'silex', 'simplex',
+ 'sioux', 'sirex', 'smilax', 'solex', 'songe-creux', 'spalax', 'sphex',
+ 'sphinx', 'storax', 'strix', 'styrax', 'surfaix', 'surtaux', 'syrinx',
+ 'tamarix', 'taux', 'télex', 'thorax', 'tord-boyaux', 'toux', 'trionyx',
+ 'tripoux', 'tubifex', 'vertex', 'vidéotex', 'vielleux', 'vieux',
+ 'violoneux', 'voix', 'volvox', 'vortex',
+
+ // Nouns ending by -z
+ 'allume-gaz', 'assez', 'biogaz', 'cache-nez', 'camping-gaz', 'chez',
+ 'chintz', 'ersatz', 'fez', 'free-jazz', 'fritz', 'gaz', 'gin-fizz', 'hertz',
+ 'jazz', 'jerez', 'kibboutz', 'kilohertz', 'kolkhoz', 'kronprinz', 'lapiaz',
+ 'lez', 'mégahertz', 'merguez', 'nez', 'pince-nez', 'quartz', 'quiz', 'ranz',
+ 'raz', 'recez', 'rémiz', 'rez', 'riz', 'ruolz', 'seltz', 'serre-nez'
+ ];
+
+ this.customPluralForms = [];
+ this.customSingularForms = [];
+ this.singularForms = new FormSet();
+ this.pluralForms = new FormSet();
+
+ this.attach = attach;
+
+ this.addIrregular('ail', 'aulx');
+ this.addIrregular('bétail', 'bestiaux');
+ this.addIrregular('bonhomme', 'bonshommes');
+ this.addIrregular('ciel', 'cieux');
+ this.addIrregular('monsieur', 'messieurs');
+ this.addIrregular('mafioso', 'mafiosi');
+ this.addIrregular('œil', 'yeux');
+ this.addIrregular('putto', 'putti');
+ this.addIrregular('targui', 'touareg'); // touareg -> touaregs is also OK.
+
+ // Singularize
+ this.pluralForms.regularForms.push([/^(av|b|c|carnav|cérémoni|chac|corr|emment|emmenth|festiv|fut|gavi|gra|narv|p|récit|rég|rit|rorqu|st)al$/i, '$1als']);
+ this.pluralForms.regularForms.push([/^(aspir|b|cor|ém|ferm|gemm|soupir|trav|vant|vent|vitr)ail$/i, '$1aux']);
+ this.pluralForms.regularForms.push([/^(bij|caill|ch|gen|hib|jouj|p|rip|chouch)ou$/i, '$1oux']);
+ this.pluralForms.regularForms.push([/^(gr|berimb|don|karb|land|pil|rest|sarr|un)au$/i, '$1aus']);
+ this.pluralForms.regularForms.push([/^(bl|ém|enf|pn)eu$/i, '$1eus']);
+ this.pluralForms.regularForms.push([/(au|eau|eu|œu)$/i, '$1x']);
+ this.pluralForms.regularForms.push([/al$/i, 'aux']);
+ this.pluralForms.regularForms.push([/(s|x)$/i, '$1']);
+ this.pluralForms.regularForms.push([/(.*)$/i, '$1s']);
+
+ // Pluralize
+ this.singularForms.regularForms.push([/^(aspir|b|cor|ém|ferm|gemm|soupir|trav|vant|vent|vitr)aux$/i, '$1ail']);
+ this.singularForms.regularForms.push([/^(aloy|b|bouc|boy|burg|conoy|coy|cr|esquim|ét|fabli|flé|flûti|glu|gr|gru|hoy|joy|kérab|matéri|nobli|noy|pré|sen|sén|t|touch|tuss|tuy|v|ypré)aux$/i, '$1au']);
+ this.singularForms.regularForms.push([/^(bij|caill|ch|gen|hib|jouj|p|rip|chouch)oux$/i, '$1ou']);
+ this.singularForms.regularForms.push([/^(bis)?aïeux$/i, '$1aïeul']);
+ this.singularForms.regularForms.push([/^apparaux$/i, 'appareil']); // One way transform, don't put on irregular list.
+ this.singularForms.regularForms.push([/^ciels$/i, 'ciel']);
+ this.singularForms.regularForms.push([/^œils$/i, 'œil']);
+ this.singularForms.regularForms.push([/(eau|eu|œu)x$/i, '$1']);
+ this.singularForms.regularForms.push([/aux$/i, 'al']);
+ this.singularForms.regularForms.push([/(.*)s$/i, '$1']);
+
+ this.pluralize = function(token) {
+ return this.ize(token, this.pluralForms, this.customPluralForms);
+ };
+
+ this.singularize = function(token) {
+ return this.ize(token, this.singularForms, this.customSingularForms);
+ };
+};
+
+util.inherits(NounInflector, SingularPluralInflector);
+
+module.exports = NounInflector;
View
44 spec/count_inflector_fr_spec.js
@@ -0,0 +1,44 @@
+/*
+Copyright (c) 2012, Guillaume Marty
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+var CountInflector = (require('lib/natural/inflectors/fr/count_inflector'));
+
+describe('count_inflector', function() {
+ it('should handle 1er cases', function() {
+ expect(CountInflector.nth(1)).toBe('1er');
+ });
+
+ it('should handle the 2e cases', function() {
+ expect(CountInflector.nth(0)).toBe('0e');
+ expect(CountInflector.nth(2)).toBe('2e');
+ expect(CountInflector.nth(3)).toBe('3e');
+ expect(CountInflector.nth(5)).toBe('5e');
+ expect(CountInflector.nth(11)).toBe('11e');
+ expect(CountInflector.nth(100)).toBe('100e');
+ expect(CountInflector.nth(999)).toBe('999e');
+ });
+
+ it('should handle roman numerals', function() {
+ expect(CountInflector.nth('I')).toBe('Ier');
+ expect(CountInflector.nth('XX')).toBe('XXe');
+ });
+});
View
476 spec/noun_inflector_fr_spec.js
@@ -0,0 +1,476 @@
+/*
+ Copyright (c) 2012, Guillaume Marty
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+var NounInflector = require('lib/natural/inflectors/fr/noun_inflector'),
+ inflector = new NounInflector();
+
+describe('NounInflector', function() {
+ describe('.pluralize()', function() {
+ describe('should pluralize exception nouns ending by -al', function() {
+ expect(inflector.pluralize('carnaval')).toBe('carnavals');
+ expect(inflector.pluralize('narval')).toBe('narvals');
+ expect(inflector.pluralize('récital')).toBe('récitals');
+ });
+
+ describe('should pluralize regular nouns ending by -al', function() {
+ expect(inflector.pluralize('amiral')).toBe('amiraux');
+ expect(inflector.pluralize('cheval')).toBe('chevaux');
+ expect(inflector.pluralize('général')).toBe('généraux');
+ });
+
+ describe('should pluralize exception nouns ending by -ail', function() {
+ expect(inflector.pluralize('bail')).toBe('baux');
+ expect(inflector.pluralize('vitrail')).toBe('vitraux');
+ expect(inflector.pluralize('émail')).toBe('émaux');
+ });
+
+ describe('should pluralize regular nouns ending by -ail', function() {
+ expect(inflector.pluralize('détail')).toBe('détails');
+ expect(inflector.pluralize('poitrail')).toBe('poitrails');
+ expect(inflector.pluralize('chandail')).toBe('chandails');
+ });
+
+ describe('should pluralize exception nouns ending by -il', function() {
+ expect(inflector.pluralize('ciel')).toBe('cieux');
+ expect(inflector.pluralize('œil')).toBe('yeux');
+ });
+
+ describe('should pluralize exception nouns ending by -ou', function() {
+ expect(inflector.pluralize('bijou')).toBe('bijoux');
+ expect(inflector.pluralize('joujou')).toBe('joujoux');
+ expect(inflector.pluralize('hibou')).toBe('hiboux');
+ });
+
+ describe('should pluralize regular nouns ending by -ou', function() {
+ expect(inflector.pluralize('trou')).toBe('trous');
+ expect(inflector.pluralize('bambou')).toBe('bambous');
+ expect(inflector.pluralize('toutou')).toBe('toutous');
+ });
+
+ describe('should pluralize exception nouns ending by -au', function() {
+ expect(inflector.pluralize('berimbau')).toBe('berimbaus');
+ expect(inflector.pluralize('landau')).toBe('landaus');
+ expect(inflector.pluralize('pilau')).toBe('pilaus');
+ });
+
+ describe('should pluralize regular nouns ending by -au', function() {
+ expect(inflector.pluralize('cadeau')).toBe('cadeaux');
+ expect(inflector.pluralize('beau')).toBe('beaux');
+ expect(inflector.pluralize('étau')).toBe('étaux');
+ });
+
+ describe('should pluralize exception nouns ending by -eu', function() {
+ expect(inflector.pluralize('bleu')).toBe('bleus');
+ expect(inflector.pluralize('émeu')).toBe('émeus');
+ expect(inflector.pluralize('pneu')).toBe('pneus');
+ });
+
+ describe('should pluralize regular nouns ending by -eu', function() {
+ expect(inflector.pluralize('pieu')).toBe('pieux');
+ expect(inflector.pluralize('lieu')).toBe('lieux');
+ expect(inflector.pluralize('feu')).toBe('feux');
+ });
+
+ describe('should pluralize regular nouns ending by -eau', function() {
+ expect(inflector.pluralize('eau')).toBe('eaux');
+ expect(inflector.pluralize('manteau')).toBe('manteaux');
+ expect(inflector.pluralize('arbrisseau')).toBe('arbrisseaux');
+ });
+
+ describe('should pluralize regular nouns ending by -œu', function() {
+ expect(inflector.pluralize('vœu')).toBe('vœux');
+ });
+
+ describe('should pluralize regular nouns ending by -s, -x or -z', function() {
+ expect(inflector.pluralize('os')).toBe('os');
+ expect(inflector.pluralize('cas')).toBe('cas');
+ expect(inflector.pluralize('rhinocéros')).toBe('rhinocéros');
+
+ expect(inflector.pluralize('houx')).toBe('houx');
+ expect(inflector.pluralize('lynx')).toBe('lynx');
+ expect(inflector.pluralize('roux')).toBe('roux');
+
+ expect(inflector.pluralize('gaz')).toBe('gaz');
+ expect(inflector.pluralize('quartz')).toBe('quartz');
+ expect(inflector.pluralize('quiz')).toBe('quiz');
+ });
+
+ describe('should pluralize exception nouns', function() {
+ expect(inflector.pluralize('ail')).toBe('aulx');
+ expect(inflector.pluralize('bétail')).toBe('bestiaux');
+ });
+
+ describe('should pluralize regular nouns', function() {
+ expect(inflector.pluralize('chai')).toBe('chais');
+ expect(inflector.pluralize('vérité')).toBe('vérités');
+ expect(inflector.pluralize('orange')).toBe('oranges');
+ });
+ });
+
+ describe('.singularize()', function() {
+ describe('should singularize regular nouns ending by -aux', function() {
+ expect(inflector.singularize('amiraux')).toBe('amiral');
+ expect(inflector.singularize('chevaux')).toBe('cheval');
+ expect(inflector.singularize('généraux')).toBe('général');
+ });
+
+ describe('should singularize exception nouns ending by -aux', function() {
+ expect(inflector.singularize('baux')).toBe('bail');
+ expect(inflector.singularize('vitraux')).toBe('vitrail');
+ expect(inflector.singularize('émaux')).toBe('émail');
+ });
+
+ describe('should singularize regular nouns ending by -aux', function() {
+ expect(inflector.singularize('cadeaux')).toBe('cadeau');
+ expect(inflector.singularize('beaux')).toBe('beau');
+ expect(inflector.singularize('étaux')).toBe('étau');
+ });
+
+ describe('should singularize nouns with multiple plural forms', function() {
+ expect(inflector.singularize('ails')).toBe('ail');
+ expect(inflector.singularize('aulx')).toBe('ail');
+ expect(inflector.singularize('ciels')).toBe('ciel');
+ expect(inflector.singularize('cieux')).toBe('ciel');
+ expect(inflector.singularize('œils')).toBe('œil');
+ expect(inflector.singularize('yeux')).toBe('œil');
+ expect(inflector.singularize('aïeuls')).toBe('aïeul'); // Regular
+ expect(inflector.singularize('aïeux')).toBe('aïeul');
+ expect(inflector.singularize('bisaïeuls')).toBe('bisaïeul'); // Regular
+ expect(inflector.singularize('bisaïeux')).toBe('bisaïeul');
+ expect(inflector.singularize('craus')).toBe('crau');
+ expect(inflector.singularize('craux')).toBe('crau');
+ expect(inflector.singularize('graus')).toBe('grau');
+ expect(inflector.singularize('graux')).toBe('grau');
+ expect(inflector.singularize('sénaus')).toBe('sénau');
+ expect(inflector.singularize('sénaux')).toBe('sénau');
+ expect(inflector.singularize('tussaus')).toBe('tussau');
+ expect(inflector.singularize('tussaux')).toBe('tussau');
+ expect(inflector.singularize('emposieus')).toBe('emposieu');
+ expect(inflector.singularize('emposieux')).toBe('emposieu');
+ expect(inflector.singularize('richelieus')).toBe('richelieu');
+ expect(inflector.singularize('richelieux')).toBe('richelieu');
+ //expect(inflector.singularize('feus')).toBe('feu'); // This one is an adjective.
+ expect(inflector.singularize('feux')).toBe('feu');
+ expect(inflector.singularize('lieus')).toBe('lieu'); // Fish
+ expect(inflector.singularize('lieux')).toBe('lieu');
+ expect(inflector.singularize('corails')).toBe('corail');
+ expect(inflector.singularize('coraux')).toBe('corail');
+ });
+
+ describe('should singularize exception nouns ending by -oux', function() {
+ expect(inflector.singularize('bijoux')).toBe('bijou');
+ expect(inflector.singularize('joujoux')).toBe('joujou');
+ expect(inflector.singularize('hiboux')).toBe('hibou');
+ });
+
+ describe('should singularize exception nouns ending by -eus', function() {
+ expect(inflector.singularize('bleus')).toBe('bleu');
+ expect(inflector.singularize('émeus')).toBe('émeu');
+ expect(inflector.singularize('pneus')).toBe('pneu');
+ });
+
+ describe('should singularize regular nouns ending by -eux', function() {
+ expect(inflector.singularize('pieux')).toBe('pieu');
+ expect(inflector.singularize('lieux')).toBe('lieu');
+ expect(inflector.singularize('feux')).toBe('feu');
+ });
+
+ describe('should singularize regular nouns ending by -eaux', function() {
+ expect(inflector.singularize('eaux')).toBe('eau');
+ expect(inflector.singularize('manteaux')).toBe('manteau');
+ expect(inflector.singularize('arbrisseaux')).toBe('arbrisseau');
+ });
+
+ describe('should singularize regular nouns ending by -œux', function() {
+ expect(inflector.singularize('vœux')).toBe('vœu');
+ });
+
+ describe('should singularize regular nouns ending by -s, -x or -z', function() {
+ expect(inflector.singularize('cas')).toBe('cas');
+ expect(inflector.singularize('os')).toBe('os');
+ expect(inflector.singularize('rhinocéros')).toBe('rhinocéros');
+
+ expect(inflector.singularize('houx')).toBe('houx');
+ expect(inflector.singularize('lynx')).toBe('lynx');
+ expect(inflector.singularize('roux')).toBe('roux');
+
+ expect(inflector.singularize('gaz')).toBe('gaz');
+ expect(inflector.singularize('quartz')).toBe('quartz');
+ expect(inflector.singularize('quiz')).toBe('quiz');
+ });
+
+ describe('should singularize exception nouns', function() {
+ expect(inflector.singularize('bestiaux')).toBe('bétail');
+ });
+
+ describe('should singularize regular nouns', function() {
+ expect(inflector.singularize('chais')).toBe('chai');
+ expect(inflector.singularize('vérités')).toBe('vérité');
+ expect(inflector.singularize('oranges')).toBe('orange');
+
+ // Exception nouns ending by -als
+ expect(inflector.singularize('carnavals')).toBe('carnaval');
+ expect(inflector.singularize('narvals')).toBe('narval');
+ expect(inflector.singularize('récitals')).toBe('récital');
+
+ // Regular nouns ending by -ails
+ expect(inflector.singularize('détails')).toBe('détail');
+ expect(inflector.singularize('poitrails')).toBe('poitrail');
+ expect(inflector.singularize('chandails')).toBe('chandail');
+
+ // Regular nouns ending by -ous
+ expect(inflector.singularize('trous')).toBe('trou');
+ expect(inflector.singularize('bambous')).toBe('bambou');
+ expect(inflector.singularize('toutous')).toBe('toutou');
+
+ // Exception nouns ending by -aus
+ expect(inflector.singularize('berimbaus')).toBe('berimbau');
+ expect(inflector.singularize('landaus')).toBe('landau');
+ expect(inflector.singularize('pilaus')).toBe('pilau');
+ });
+ });
+
+ /*
+ These tests ensure pluralizing plurals or singularizing singulars
+ won't lead to wrong results.
+ */
+ describe('should pluralize exception nouns ending by -al', function() {
+ describe('should pluralize exception nouns ending by -al', function() {
+ expect(inflector.pluralize('carnavals')).toBe('carnavals');
+ expect(inflector.pluralize('narvals')).toBe('narvals');
+ expect(inflector.pluralize('récitals')).toBe('récitals');
+ });
+
+ describe('should pluralize regular nouns ending by -al', function() {
+ expect(inflector.pluralize('amiraux')).toBe('amiraux');
+ expect(inflector.pluralize('chevaux')).toBe('chevaux');
+ expect(inflector.pluralize('généraux')).toBe('généraux');
+ });
+
+ describe('should pluralize exception nouns ending by -ail', function() {
+ expect(inflector.pluralize('baux')).toBe('baux');
+ expect(inflector.pluralize('vitraux')).toBe('vitraux');
+ expect(inflector.pluralize('émaux')).toBe('émaux');
+ });
+
+ describe('should pluralize regular nouns ending by -ail', function() {
+ expect(inflector.pluralize('détails')).toBe('détails');
+ expect(inflector.pluralize('poitrails')).toBe('poitrails');
+ expect(inflector.pluralize('chandails')).toBe('chandails');
+ });
+
+ describe('should pluralize exception nouns ending by -il', function() {
+ expect(inflector.pluralize('cieux')).toBe('cieux');
+ expect(inflector.pluralize('yeux')).toBe('yeux');
+ });
+
+ describe('should pluralize exception nouns ending by -ou', function() {
+ expect(inflector.pluralize('bijoux')).toBe('bijoux');
+ expect(inflector.pluralize('joujoux')).toBe('joujoux');
+ expect(inflector.pluralize('hiboux')).toBe('hiboux');
+ });
+
+ describe('should pluralize regular nouns ending by -ou', function() {
+ expect(inflector.pluralize('trous')).toBe('trous');
+ expect(inflector.pluralize('bambous')).toBe('bambous');
+ expect(inflector.pluralize('toutous')).toBe('toutous');
+ });
+
+ describe('should pluralize exception nouns ending by -au', function() {
+ expect(inflector.pluralize('berimbaus')).toBe('berimbaus');
+ expect(inflector.pluralize('landaus')).toBe('landaus');
+ expect(inflector.pluralize('pilaus')).toBe('pilaus');
+ });
+
+ describe('should pluralize regular nouns ending by -au', function() {
+ expect(inflector.pluralize('cadeaux')).toBe('cadeaux');
+ expect(inflector.pluralize('beaux')).toBe('beaux');
+ expect(inflector.pluralize('étaux')).toBe('étaux');
+ });
+
+ describe('should pluralize exception nouns ending by -eu', function() {
+ expect(inflector.pluralize('bleus')).toBe('bleus');
+ expect(inflector.pluralize('émeus')).toBe('émeus');
+ expect(inflector.pluralize('pneus')).toBe('pneus');
+ });
+
+ describe('should pluralize regular nouns ending by -eu', function() {
+ expect(inflector.pluralize('pieux')).toBe('pieux');
+ expect(inflector.pluralize('lieux')).toBe('lieux');
+ expect(inflector.pluralize('feux')).toBe('feux');
+ });
+
+ describe('should pluralize regular nouns ending by -eau', function() {
+ expect(inflector.pluralize('eaux')).toBe('eaux');
+ expect(inflector.pluralize('manteaux')).toBe('manteaux');
+ expect(inflector.pluralize('arbrisseaux')).toBe('arbrisseaux');
+ });
+
+ describe('should pluralize regular nouns ending by -œu', function() {
+ expect(inflector.pluralize('vœux')).toBe('vœux');
+ });
+
+ describe('should pluralize regular nouns ending by -s, -x or -z', function() {
+ expect(inflector.pluralize('os')).toBe('os');
+ expect(inflector.pluralize('cas')).toBe('cas');
+ expect(inflector.pluralize('rhinocéros')).toBe('rhinocéros');
+
+ expect(inflector.pluralize('houx')).toBe('houx');
+ expect(inflector.pluralize('lynx')).toBe('lynx');
+ expect(inflector.pluralize('roux')).toBe('roux');
+
+ expect(inflector.pluralize('gaz')).toBe('gaz');
+ expect(inflector.pluralize('quartz')).toBe('quartz');
+ expect(inflector.pluralize('quiz')).toBe('quiz');
+ });
+
+ describe('should pluralize exception nouns', function() {
+ expect(inflector.pluralize('aulx')).toBe('aulx');
+ expect(inflector.pluralize('bestiaux')).toBe('bestiaux');
+ });
+
+ describe('should pluralize regular nouns', function() {
+ expect(inflector.pluralize('chais')).toBe('chais');
+ expect(inflector.pluralize('vérités')).toBe('vérités');
+ expect(inflector.pluralize('oranges')).toBe('oranges');
+ });
+ });
+
+ describe('.singularize()', function() {
+ describe('should singularize regular nouns ending by -aux', function() {
+ expect(inflector.singularize('amiral')).toBe('amiral');
+ expect(inflector.singularize('cheval')).toBe('cheval');
+ expect(inflector.singularize('général')).toBe('général');
+ });
+
+ describe('should singularize exception nouns ending by -aux', function() {
+ expect(inflector.singularize('bail')).toBe('bail');
+ expect(inflector.singularize('vitrail')).toBe('vitrail');
+ expect(inflector.singularize('émail')).toBe('émail');
+ });
+
+ describe('should singularize regular nouns ending by -aux', function() {
+ expect(inflector.singularize('cadeau')).toBe('cadeau');
+ expect(inflector.singularize('beau')).toBe('beau');
+ expect(inflector.singularize('étau')).toBe('étau');
+ });
+
+ describe('should singularize nouns with multiple plural forms', function() {
+ expect(inflector.singularize('ail')).toBe('ail');
+ expect(inflector.singularize('ciel')).toBe('ciel');
+ expect(inflector.singularize('œil')).toBe('œil');
+ expect(inflector.singularize('aïeul')).toBe('aïeul');
+ expect(inflector.singularize('bisaïeul')).toBe('bisaïeul');
+ expect(inflector.singularize('crau')).toBe('crau');
+ expect(inflector.singularize('grau')).toBe('grau');
+ expect(inflector.singularize('sénau')).toBe('sénau');
+ expect(inflector.singularize('tussau')).toBe('tussau');
+ expect(inflector.singularize('emposieu')).toBe('emposieu');
+ expect(inflector.singularize('richelieu')).toBe('richelieu');
+ expect(inflector.singularize('feu')).toBe('feu');
+ expect(inflector.singularize('lieu')).toBe('lieu'); // Fish
+ expect(inflector.singularize('corail')).toBe('corail');
+ });
+
+ describe('should singularize exception nouns ending by -oux', function() {
+ expect(inflector.singularize('bijou')).toBe('bijou');
+ expect(inflector.singularize('joujou')).toBe('joujou');
+ expect(inflector.singularize('hibou')).toBe('hibou');
+ });
+
+ describe('should singularize exception nouns ending by -eus', function() {
+ expect(inflector.singularize('bleu')).toBe('bleu');
+ expect(inflector.singularize('émeu')).toBe('émeu');
+ expect(inflector.singularize('pneu')).toBe('pneu');
+ });
+
+ describe('should singularize regular nouns ending by -eux', function() {
+ expect(inflector.singularize('pieu')).toBe('pieu');
+ expect(inflector.singularize('lieu')).toBe('lieu');
+ expect(inflector.singularize('feu')).toBe('feu');
+ });
+
+ describe('should singularize regular nouns ending by -eaux', function() {
+ expect(inflector.singularize('eau')).toBe('eau');
+ expect(inflector.singularize('manteau')).toBe('manteau');
+ expect(inflector.singularize('arbrisseau')).toBe('arbrisseau');
+ });
+
+ describe('should singularize regular nouns ending by -œux', function() {
+ expect(inflector.singularize('vœu')).toBe('vœu');
+ });
+
+ describe('should singularize regular nouns ending by -s, -x or -z', function() {
+ expect(inflector.singularize('cas')).toBe('cas');
+ expect(inflector.singularize('os')).toBe('os');
+ expect(inflector.singularize('rhinocéros')).toBe('rhinocéros');
+
+ expect(inflector.singularize('houx')).toBe('houx');
+ expect(inflector.singularize('lynx')).toBe('lynx');
+ expect(inflector.singularize('roux')).toBe('roux');
+
+ expect(inflector.singularize('gaz')).toBe('gaz');
+ expect(inflector.singularize('quartz')).toBe('quartz');
+ expect(inflector.singularize('quiz')).toBe('quiz');
+ });
+
+ describe('should singularize exception nouns', function() {
+ expect(inflector.singularize('bétail')).toBe('bétail');
+ });
+
+ describe('should singularize regular nouns', function() {
+ expect(inflector.singularize('chai')).toBe('chai');
+ expect(inflector.singularize('vérité')).toBe('vérité');
+ expect(inflector.singularize('orange')).toBe('orange');
+
+ // Exception nouns ending by -als
+ expect(inflector.singularize('carnaval')).toBe('carnaval');
+ expect(inflector.singularize('narval')).toBe('narval');
+ expect(inflector.singularize('récital')).toBe('récital');
+
+ // Regular nouns ending by -ails
+ expect(inflector.singularize('détail')).toBe('détail');
+ expect(inflector.singularize('poitrail')).toBe('poitrail');
+ expect(inflector.singularize('chandail')).toBe('chandail');
+
+ // Regular nouns ending by -ous
+ expect(inflector.singularize('trou')).toBe('trou');
+ expect(inflector.singularize('bambou')).toBe('bambou');
+ expect(inflector.singularize('toutou')).toBe('toutou');
+
+ // Exception nouns ending by -aus
+ expect(inflector.singularize('berimbau')).toBe('berimbau');
+ expect(inflector.singularize('landau')).toBe('landau');
+ expect(inflector.singularize('pilau')).toBe('pilau');
+ });
+ });
+
+ describe('.attach()', function() {
+ describe('should attach new methods to String', function() {
+ inflector.attach();
+ expect('corail'.pluralizeNoun()).toBe('coraux');
+ expect('coraux'.singularizeNoun()).toBe('corail');
+ expect('récital'.pluralizeNoun()).toBe('récitals');
+ expect('récitals'.singularizeNoun()).toBe('récital');
+ });
+ });
+});
Something went wrong with that request. Please try again.