v1.0 Initial commit of project

This commit is contained in:
2026-01-01 10:54:18 +01:00
commit 768cf78b57
990 changed files with 241213 additions and 0 deletions

View File

@@ -0,0 +1,363 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\String\Tests\Inflector;
use PHPUnit\Framework\TestCase;
use Symfony\Component\String\Inflector\EnglishInflector;
class EnglishInflectorTest extends TestCase
{
public static function singularizeProvider()
{
// see http://english-zone.com/spelling/plurals.html
// see http://www.scribd.com/doc/3271143/List-of-100-Irregular-Plural-Nouns-in-English
return [
['accesses', 'access'],
['addresses', 'address'],
['agendas', 'agenda'],
['albums', 'album'],
['alumnae', 'alumna'],
['alumni', 'alumnus'],
['analyses', ['analys', 'analyse', 'analysis']],
['ankles', 'ankle'],
['antennae', 'antenna'],
['antennas', 'antenna'],
['appendices', ['appendex', 'appendix', 'appendice']],
['arches', ['arch', 'arche']],
['articles', 'article'],
['atlases', ['atlas', 'atlase', 'atlasis']],
['axes', ['ax', 'axe', 'axis']],
['babies', 'baby'],
['bacteria', 'bacterium'],
['bases', ['bas', 'base', 'basis']],
['batches', ['batch', 'batche']],
['beaux', 'beau'],
['bees', 'bee'],
['boxes', 'box'],
['boys', 'boy'],
['bureaus', 'bureau'],
['bureaux', 'bureau'],
['buses', ['bus', 'buse', 'busis']],
['bushes', ['bush', 'bushe']],
['buttons', 'button'],
['calves', ['calf', 'calve', 'calff']],
['cars', 'car'],
['cassettes', ['cassett', 'cassette']],
['caves', ['caf', 'cave', 'caff']],
['chateaux', 'chateau'],
['cheeses', ['chees', 'cheese', 'cheesis']],
['children', 'child'],
['circuses', ['circus', 'circuse', 'circusis']],
['cliffs', 'cliff'],
['codes', 'code'],
['committee', 'committee'],
['corpora', 'corpus'],
['coupons', 'coupon'],
['crises', ['cris', 'crise', 'crisis']],
['criteria', 'criterion'],
['cups', 'cup'],
['curricula', 'curriculum'],
['data', 'data'],
['days', 'day'],
['discos', 'disco'],
['devices', ['devex', 'devix', 'device']],
['drives', 'drive'],
['drivers', 'driver'],
['dwarves', ['dwarf', 'dwarve', 'dwarff']],
['echoes', ['echo', 'echoe']],
['edges', 'edge'],
['elves', ['elf', 'elve', 'elff']],
['emphases', ['emphas', 'emphase', 'emphasis']],
['employees', 'employee'],
['faxes', 'fax'],
['fees', 'fee'],
['feet', 'foot'],
['feedback', 'feedback'],
['foci', 'focus'],
['focuses', ['focus', 'focuse', 'focusis']],
['formulae', 'formula'],
['formulas', 'formula'],
['conspectuses', 'conspectus'],
['fungi', 'fungus'],
['funguses', ['fungus', 'funguse', 'fungusis']],
['garages', ['garag', 'garage']],
['geese', 'goose'],
['genera', 'genus'],
['halves', ['half', 'halve', 'halff']],
['hats', 'hat'],
['heroes', ['hero', 'heroe']],
['hippopotamuses', ['hippopotamus', 'hippopotamuse', 'hippopotamusis']], // hippopotami
['hoaxes', 'hoax'],
['hooves', ['hoof', 'hoove', 'hooff']],
['houses', ['hous', 'house', 'housis']],
['indexes', 'index'],
['indices', ['index', 'indix', 'indice']],
['ions', 'ion'],
['irises', ['iris', 'irise', 'irisis']],
['kisses', 'kiss'],
['knives', 'knife'],
['lamps', 'lamp'],
['lessons', 'lesson'],
['leaves', ['leaf', 'leave', 'leaff']],
['lice', 'louse'],
['lives', 'life'],
['matrices', ['matrex', 'matrix', 'matrice']],
['matrixes', 'matrix'],
['media', 'medium'],
['memoranda', 'memorandum'],
['men', 'man'],
['mice', 'mouse'],
['moves', 'move'],
['movies', 'movie'],
['names', 'name'],
['nebulae', 'nebula'],
['neuroses', ['neuros', 'neurose', 'neurosis']],
['news', 'news'],
['oases', ['oas', 'oase', 'oasis']],
['objectives', 'objective'],
['oxen', 'ox'],
['parties', 'party'],
['people', 'person'],
['persons', 'person'],
['phenomena', 'phenomenon'],
['photos', 'photo'],
['pianos', 'piano'],
['plateaux', 'plateau'],
['poisons', 'poison'],
['poppies', 'poppy'],
['prices', ['prex', 'prix', 'price']],
['quizzes', 'quiz'],
['quora', 'quorum'],
['quorums', 'quorum'],
['radii', 'radius'],
['roofs', 'roof'],
['roses', ['ros', 'rose', 'rosis']],
['sandwiches', ['sandwich', 'sandwiche']],
['scarves', ['scarf', 'scarve', 'scarff']],
['schemas', 'schema'], // schemata
['seasons', 'season'],
['selfies', 'selfie'],
['series', 'series'],
['services', 'service'],
['sheriffs', 'sheriff'],
['shoes', ['sho', 'shoe']],
['species', 'species'],
['spies', 'spy'],
['staves', ['staf', 'stave', 'staff']],
['status', 'status'],
['statuses', 'status'],
['stories', 'story'],
['strata', 'stratum'],
['suitcases', ['suitcas', 'suitcase', 'suitcasis']],
['syllabi', 'syllabus'],
['tags', 'tag'],
['teeth', 'tooth'],
['theses', ['thes', 'these', 'thesis']],
['thieves', ['thief', 'thieve', 'thieff']],
['treasons', 'treason'],
['trees', 'tree'],
['waltzes', ['waltz', 'waltze']],
['wives', 'wife'],
['zombies', 'zombie'],
// test casing: if the first letter was uppercase, it should remain so
['Men', 'Man'],
['GrandChildren', 'GrandChild'],
['SubTrees', 'SubTree'],
// Known issues
// ['insignia', 'insigne'],
// ['insignias', 'insigne'],
// ['rattles', 'rattle'],
];
}
public static function pluralizeProvider()
{
// see http://english-zone.com/spelling/plurals.html
// see http://www.scribd.com/doc/3271143/List-of-100-Irregular-Plural-Nouns-in-English
return [
['access', 'accesses'],
['address', 'addresses'],
['agenda', 'agendas'],
['aircraft', 'aircraft'],
['album', 'albums'],
['alumnus', 'alumni'],
['analysis', 'analyses'],
['ankle', 'ankles'],
['antenna', 'antennas'], // antennae
['appendix', ['appendices', 'appendixes']],
['arch', 'arches'],
['article', 'articles'],
['atlas', 'atlases'],
['axe', 'axes'],
['axis', 'axes'],
['baby', 'babies'],
['bacterium', 'bacteria'],
['base', 'bases'],
['batch', 'batches'],
['beau', ['beaus', 'beaux']],
['bee', 'bees'],
['box', 'boxes'],
['boy', 'boys'],
['bureau', ['bureaus', 'bureaux']],
['bus', 'buses'],
['bush', 'bushes'],
['button', 'buttons'],
['calf', ['calfs', 'calves']],
['campus', 'campuses'],
['car', 'cars'],
['cassette', 'cassettes'],
['cave', 'caves'],
['chateau', ['chateaus', 'chateaux']],
['cheese', 'cheeses'],
['child', 'children'],
['circus', 'circuses'],
['cliff', 'cliffs'],
['committee', 'committees'],
['coupon', 'coupons'],
['crisis', 'crises'],
['criterion', 'criteria'],
['cup', 'cups'],
['curriculum', 'curricula'],
['data', 'data'],
['day', 'days'],
['disco', 'discos'],
['device', 'devices'],
['drive', 'drives'],
['driver', 'drivers'],
['dwarf', ['dwarfs', 'dwarves']],
['echo', 'echoes'],
['edge', 'edges'],
['elf', ['elfs', 'elves']],
['emphasis', 'emphases'],
['fax', ['faxes', 'faxxes']],
['feedback', 'feedback'],
['focus', 'focuses'],
['foot', 'feet'],
['formula', 'formulas'], // formulae
['conspectus', 'conspectuses'],
['fungus', 'fungi'],
['garage', 'garages'],
['goose', 'geese'],
['half', ['halfs', 'halves']],
['hat', 'hats'],
['hero', 'heroes'],
['hippocampus', 'hippocampi'],
['hippopotamus', 'hippopotami'], // hippopotamuses
['hoax', 'hoaxes'],
['hoof', ['hoofs', 'hooves']],
['house', 'houses'],
['icon', 'icons'],
['index', ['indicies', 'indexes']],
['ion', 'ions'],
['iris', 'irises'],
['kiss', 'kisses'],
['knife', 'knives'],
['lamp', 'lamps'],
['leaf', ['leafs', 'leaves']],
['lesson', 'lessons'],
['life', 'lives'],
['louse', 'lice'],
['man', 'men'],
['matrix', ['matrices', 'matrixes']],
['medium', 'media'],
['memorandum', 'memoranda'],
['mouse', 'mice'],
['move', 'moves'],
['movie', 'movies'],
['nebula', 'nebulae'],
['neurosis', 'neuroses'],
['news', 'news'],
['oasis', 'oases'],
['objective', 'objectives'],
['ox', 'oxen'],
['party', 'parties'],
['person', ['persons', 'people']],
['phenomenon', 'phenomena'],
['photo', 'photos'],
['piano', 'pianos'],
['plateau', ['plateaus', 'plateaux']],
['poison', 'poisons'],
['poppy', 'poppies'],
['price', 'prices'],
['quiz', 'quizzes'],
['quorum', ['quora', 'quorums']],
['radius', 'radii'],
['roof', ['roofs', 'rooves']],
['rose', 'roses'],
['sandwich', 'sandwiches'],
['scarf', ['scarfs', 'scarves']],
['schema', 'schemas'], // schemata
['season', 'seasons'],
['selfie', 'selfies'],
['series', 'series'],
['service', 'services'],
['sheriff', 'sheriffs'],
['shoe', 'shoes'],
['species', 'species'],
['status', ['status', 'statuses']],
['stratum', 'strata'],
['spy', 'spies'],
['staff', 'staves'],
['story', 'stories'],
['stratum', 'strata'],
['suitcase', 'suitcases'],
['syllabus', 'syllabi'],
['tag', 'tags'],
['thief', ['thiefs', 'thieves']],
['tooth', 'teeth'],
['treason', 'treasons'],
['tree', 'trees'],
['waltz', 'waltzes'],
['wife', 'wives'],
['icon', 'icons'],
['hippocampus', 'hippocampi'],
['campus', 'campuses'],
['hardware', 'hardware'],
['alias', 'aliases'],
// test casing: if the first letter was uppercase, it should remain so
['Man', 'Men'],
['GrandChild', 'GrandChildren'],
['SubTree', 'SubTrees'],
];
}
/**
* @dataProvider singularizeProvider
*/
public function testSingularize(string $plural, $singular)
{
$this->assertSame(\is_array($singular) ? $singular : [$singular], (new EnglishInflector())->singularize($plural));
}
/**
* @dataProvider pluralizeProvider
*/
public function testPluralize(string $singular, $plural)
{
$this->assertSame(\is_array($plural) ? $plural : [$plural], (new EnglishInflector())->pluralize($singular));
}
public function testPluralizeEmptyString()
{
$plural = (new EnglishInflector())->pluralize('');
$this->assertSame([''], $plural);
}
public function testSingularizeEmptyString()
{
$singular = (new EnglishInflector())->singularize('');
$this->assertSame([''], $singular);
}
}

View File

@@ -0,0 +1,149 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\String\Tests\Inflector;
use PHPUnit\Framework\TestCase;
use Symfony\Component\String\Inflector\FrenchInflector;
class FrenchInflectorTest extends TestCase
{
public static function pluralizeProvider()
{
return [
// Le pluriel par défaut
['voiture', 'voitures'],
// special characters
['œuf', 'œufs'],
['oeuf', 'oeufs'],
// Les mots finissant par s, x, z sont invariables en nombre
['bois', 'bois'],
['fils', 'fils'],
['héros', 'héros'],
['nez', 'nez'],
['rictus', 'rictus'],
['sans', 'sans'],
['souris', 'souris'],
['tas', 'tas'],
['toux', 'toux'],
// Les mots finissant en eau prennent tous un x au pluriel
['eau', 'eaux'],
['sceau', 'sceaux'],
// Les mots finissant en au prennent tous un x au pluriel sauf landau
['noyau', 'noyaux'],
['landau', 'landaus'],
// Les mots finissant en eu prennent un x au pluriel sauf pneu, bleu et émeu
['pneu', 'pneus'],
['bleu', 'bleus'],
['émeu', 'émeus'],
['cheveu', 'cheveux'],
// Les mots finissant en al se terminent en aux au pluriel
['amiral', 'amiraux'],
['animal', 'animaux'],
['arsenal', 'arsenaux'],
['bocal', 'bocaux'],
['canal', 'canaux'],
['capital', 'capitaux'],
['caporal', 'caporaux'],
['cheval', 'chevaux'],
['cristal', 'cristaux'],
['général', 'généraux'],
['hopital', 'hopitaux'],
['hôpital', 'hôpitaux'],
['idéal', 'idéaux'],
['journal', 'journaux'],
['littoral', 'littoraux'],
['local', 'locaux'],
['mal', 'maux'],
['métal', 'métaux'],
['minéral', 'minéraux'],
['principal', 'principaux'],
['radical', 'radicaux'],
['terminal', 'terminaux'],
// sauf bal, carnaval, caracal, chacal, choral, corral, étal, festival, récital et val
['bal', 'bals'],
['carnaval', 'carnavals'],
['caracal', 'caracals'],
['chacal', 'chacals'],
['choral', 'chorals'],
['corral', 'corrals'],
['étal', 'étals'],
['festival', 'festivals'],
['récital', 'récitals'],
['val', 'vals'],
// Les noms terminés en -ail prennent un s au pluriel.
['portail', 'portails'],
['rail', 'rails'],
// SAUF aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail qui font leur pluriel en -aux
['aspirail', 'aspiraux'],
['bail', 'baux'],
['corail', 'coraux'],
['émail', 'émaux'],
['fermail', 'fermaux'],
['soupirail', 'soupiraux'],
['travail', 'travaux'],
['vantail', 'vantaux'],
['vitrail', 'vitraux'],
// Les noms terminés en -ou prennent un s au pluriel.
['trou', 'trous'],
['fou', 'fous'],
// SAUF Bijou, caillou, chou, genou, hibou, joujou et pou qui prennent un x au pluriel
['bijou', 'bijoux'],
['caillou', 'cailloux'],
['chou', 'choux'],
['genou', 'genoux'],
['hibou', 'hiboux'],
['joujou', 'joujoux'],
['pou', 'poux'],
// Inflected word
['cinquante', 'cinquante'],
['soixante', 'soixante'],
['mille', 'mille'],
// Titles
['monsieur', 'messieurs'],
['madame', 'mesdames'],
['mademoiselle', 'mesdemoiselles'],
['monseigneur', 'messeigneurs'],
];
}
/**
* @dataProvider pluralizeProvider
*/
public function testSingularize(string $singular, string $plural)
{
$this->assertSame([$singular], (new FrenchInflector())->singularize($plural));
// test casing: if the first letter was uppercase, it should remain so
$this->assertSame([ucfirst($singular)], (new FrenchInflector())->singularize(ucfirst($plural)));
}
/**
* @dataProvider pluralizeProvider
*/
public function testPluralize(string $singular, string $plural)
{
$this->assertSame([$plural], (new FrenchInflector())->pluralize($singular));
// test casing: if the first letter was uppercase, it should remain so
$this->assertSame([ucfirst($plural)], (new FrenchInflector())->pluralize(ucfirst($singular)));
}
}

View File

@@ -0,0 +1,158 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\String\Tests\Inflector;
use PHPUnit\Framework\TestCase;
use Symfony\Component\String\Inflector\SpanishInflector;
class SpanishInflectorTest extends TestCase
{
public static function singularizeProvider(): array
{
return [
// vowels (RAE 3.2a, 3.2c)
['peras', 'pera'],
['especies', 'especie'],
['álcalis', 'álcali'],
['códigos', 'código'],
['espíritus', 'espíritu'],
// accented (RAE 3.2a, 3.2c)
['papás', 'papá'],
['cafés', 'café'],
['isrealís', 'isrealí'],
['burós', 'buró'],
['tisús', 'tisú'],
// ending in -ión
['aviones', 'avión'],
['camiones', 'camión'],
// ending in some letters (RAE 3.2k)
['amores', 'amor'],
['antifaces', 'antifaz'],
['atriles', 'atril'],
['fácsimiles', 'fácsimil'],
['vides', 'vid'],
['reyes', 'rey'],
['relojes', 'reloj'],
['faxes', 'fax'],
['sándwiches', 'sándwich'],
['cánones', 'cánon'],
// (RAE 3.2n)
['adioses', 'adiós'],
['aguarrases', 'aguarrás'],
['arneses', 'arnés'],
['autobuses', 'autobús'],
['kermeses', 'kermés'],
['palmareses', 'palmarés'],
['toses', 'tos'],
// Special
['síes', 'sí'],
['noes', 'no'],
];
}
public static function pluralizeProvider(): array
{
return [
// vowels (RAE 3.2a, 3.2c)
['pera', 'peras'],
['especie', 'especies'],
['álcali', 'álcalis'],
['código', 'códigos'],
['espíritu', 'espíritus'],
// accented (RAE 3.2a, 3.2c)
['papá', 'papás'],
['café', 'cafés'],
['isrealí', 'isrealís'],
['buró', 'burós'],
['tisú', 'tisús'],
// ending in -ión
['avión', 'aviones'],
['camión', 'camiones'],
// ending in some letters (RAE 3.2k)
['amor', 'amores'],
['antifaz', 'antifaces'],
['atril', 'atriles'],
['fácsimil', 'fácsimiles'],
['vid', 'vides'],
['rey', 'reyes'],
['reloj', 'relojes'],
['fax', 'faxes'],
['sándwich', 'sándwiches'],
['cánon', 'cánones'],
// (RAE 3.2n)
['adiós', 'adioses'],
['aguarrás', 'aguarrases'],
['arnés', 'arneses'],
['autobús', 'autobuses'],
['kermés', 'kermeses'],
['palmarés', 'palmareses'],
['tos', 'toses'],
// Specials
['sí', 'síes'],
['no', 'noes'],
];
}
public static function uninflectedProvider(): array
{
return [
['lunes'],
['rodapiés'],
['reposapiés'],
['miércoles'],
['pies'],
];
}
/**
* @dataProvider singularizeProvider
*/
public function testSingularize(string $plural, $singular)
{
$this->assertSame(
\is_array($singular) ? $singular : [$singular],
(new SpanishInflector())->singularize($plural)
);
}
/**
* @dataProvider pluralizeProvider
*/
public function testPluralize(string $singular, $plural)
{
$this->assertSame(
\is_array($plural) ? $plural : [$plural],
(new SpanishInflector())->pluralize($singular)
);
}
/**
* @dataProvider uninflectedProvider
*/
public function testUninflected(string $word)
{
$this->assertSame(
[$word],
(new SpanishInflector())->pluralize($word)
);
}
}