Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/en/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ you want to create an inflector for to the ``createForLanguage()`` method:

The supported languages are as follows:

- ``Language::DUTCH``
- ``Language::ENGLISH``
- ``Language::FRENCH``
- ``Language::NORWEGIAN_BOKMAL``
Expand Down
4 changes: 4 additions & 0 deletions lib/Doctrine/Inflector/InflectorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Doctrine\Inflector;

use Doctrine\Inflector\Rules\Dutch;
use Doctrine\Inflector\Rules\English;
use Doctrine\Inflector\Rules\French;
use Doctrine\Inflector\Rules\NorwegianBokmal;
Expand All @@ -24,6 +25,9 @@ public static function create(): LanguageInflectorFactory
public static function createForLanguage(string $language): LanguageInflectorFactory
{
switch ($language) {
case Language::DUTCH:
return new Dutch\InflectorFactory();

case Language::ENGLISH:
return new English\InflectorFactory();

Expand Down
1 change: 1 addition & 0 deletions lib/Doctrine/Inflector/Language.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

final class Language
{
public const DUTCH = 'dutch';
public const ENGLISH = 'english';
public const FRENCH = 'french';
public const NORWEGIAN_BOKMAL = 'norwegian-bokmal';
Expand Down
168 changes: 168 additions & 0 deletions lib/Doctrine/Inflector/Rules/Dutch/Inflectible.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
<?php

declare(strict_types=1);

namespace Doctrine\Inflector\Rules\Dutch;

use Doctrine\Inflector\Rules\Pattern;
use Doctrine\Inflector\Rules\Substitution;
use Doctrine\Inflector\Rules\Transformation;
use Doctrine\Inflector\Rules\Word;

/**
* // http://nl.wikipedia.org/wiki/Klinker_(klank)
* private $klinker = '(a|e|i|o|u|ij)';
* private $korteKlinker = '(u|i|e|a|o)'; // @todo '(ie|oe)'. $plofKlank
*
* // http://nl.wikipedia.org/wiki/Medeklinker
* private $plofKlank = '(p|t|k|b|d)';
* private $wrijfKlank = '(f|s|ch|sj|v|z|g|j)'; // journaal
* private $neusKlank = '(m|n|ng)';
* private $vloeiKlank = '(l|r)';
* private $glijKlank = '(j|w)'; // jaar
* private $affricate = '(ts|zz|tsj|g)'; // /d3/ gin
* private $missingFromWiki = '(c|h|p|q|x|y|z)';
*
* public function __construct()
* {
* $this->medeklinker = '(' . $this->missingFromWiki . '|' . $this->plofKlank . '|' . $this->wrijfKlank . '|' . $this->neusKlank . '|' . $this->vloeiKlank . '|' . $this->glijKlank . '|' . $this->affricate . ')';
* $this->medeklinker = '((c|h|p|q|x|y|z)|(p|t|k|b|d)|(f|s|ch|sj|v|z|g|j)|(m|n|ng)|(l|r)|(j|w)|(ts|zz|tsj|g))';
* }
*/
class Inflectible
{
/**
* @return iterable<Transformation>
*/
public static function getSingular(): iterable
{
// http://nl.wikipedia.org/wiki/Meervoud_(Nederlands)#Klinkerverandering
yield new Transformation(new Pattern('()heden$'), '\1heid');

// http://nl.wikipedia.org/wiki/Meervoud_(Nederlands)#Beroepen_eindigend_op_-man
yield new Transformation(new Pattern('()mannen$'), '\1man');

// http://nl.wikipedia.org/wiki/Meervoud_(Nederlands)#Latijnse_meervoudsvormen
yield new Transformation(new Pattern('()ices$'), '\1ex');

// http://nl.wikipedia.org/wiki/Meervoud_(Nederlands)#Stapelmeervoud
yield new Transformation(new Pattern('^(ei|gemoed|goed|hoen|kind|lied|rad|rund)eren$'), '\1');

// http://nl.wikipedia.org/wiki/Nederlandse_grammatica
yield new Transformation(new Pattern('()ijen$'), '\1ij');

yield new Transformation(new Pattern('()ieen$'), '\1ie'); // ën

yield new Transformation(new Pattern('()((a|e|i|o|u|ij))s$'), '\1\2');

yield new Transformation(new Pattern('()((s)s)en$'), '\1s');

yield new Transformation(new Pattern('()((c|h|p|q|x|y|z)|(p|t|k|b|d)|(f|s|ch|sj|v|z|g|j)|(m|n|ng)|(l|r)|(j|w)|(ts|zz|tsj|g))en$'), '\1\2');
}

/**
* @return iterable<Transformation>
*/
public static function getPlural(): iterable
{
// @todo already in plural (?)
// @todo refine
yield new Transformation(new Pattern('()(e)(s)$'), '\1\2\3\3en');

// http://nl.wikipedia.org/wiki/Meervoud_(Nederlands)#Klinkerverandering
yield new Transformation(new Pattern('()heid$'), '\1heden');

// http://nl.wikipedia.org/wiki/Meervoud_(Nederlands)#Beroepen_eindigend_op_-man
yield new Transformation(new Pattern('()man$'), '\1mannen');

// http://nl.wikipedia.org/wiki/Meervoud_(Nederlands)#Latijnse_meervoudsvormen
yield new Transformation(new Pattern('()ix$'), '\1ices');

yield new Transformation(new Pattern('()ex$'), '\1ices');

// http://nl.wikipedia.org/wiki/Meervoud_(Nederlands)#Stapelmeervoud
yield new Transformation(new Pattern('^(ei|gemoed|goed|hoen|kind|lied|rad|rund)$'), '\1eren');

// http://nl.wikipedia.org/wiki/Nederlandse_grammatica
yield new Transformation(new Pattern('()ij$'), '\1ijen');

yield new Transformation(new Pattern('()orie$'), '\1orieen'); // ën klemtoon

yield new Transformation(new Pattern('()io$'), '\1io\'s');

yield new Transformation(new Pattern('()(a|e|i|o|u|ij)$'), '\1\2s');

yield new Transformation(new Pattern('()(((c|h|p|q|x|y|z)|(p|t|k|b|d)|(f|s|ch|sj|v|z|g|j)|(m|n|ng)|(l|r)|(j|w)|(ts|zz|tsj|g))e((c|h|p|q|x|y|z)|(p|t|k|b|d)|(f|s|ch|sj|v|z|g|j)|(m|n|ng)|(l|r)|(j|w)|(ts|zz|tsj|g)))$'), '\1\2s');

yield new Transformation(new Pattern('()(((c|h|p|q|x|y|z)|(p|t|k|b|d)|(f|s|ch|sj|v|z|g|j)|(m|n|ng)|(l|r)|(j|w)|(ts|zz|tsj|g))(u|i|e|a|o)s)$'), '\1\2sen');

yield new Transformation(new Pattern('()(((c|h|p|q|x|y|z)|(p|t|k|b|d)|(f|s|ch|sj|v|z|g|j)|(m|n|ng)|(l|r)|(j|w)|(ts|zz|tsj|g))s)$'), '\1\2en');

yield new Transformation(new Pattern('()s$'), '\1zen');

yield new Transformation(new Pattern('()((c|h|p|q|x|y|z)|(p|t|k|b|d)|(f|s|ch|sj|v|z|g|j)|(m|n|ng)|(l|r)|(j|w)|(ts|zz|tsj|g))$'), '\1\2en');
}

/**
* @return iterable<Substitution>
*/
public static function getIrregular(): iterable
{
// http://nl.wikipedia.org/wiki/Klemtoon
yield new Substitution(new Word('olie'), new Word('oliën'));

yield new Substitution(new Word('industrie'), new Word('industrieën'));

yield new Substitution(new Word('idee'), new Word('ideeën'));

// @todo: above 3 examples maybe could be compacted into a rule
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This indeed needs to be a rule instead of specific exceptions for these words, for example wee, zee, twee, drie, theorie etc.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for now i see 2 rules:

  • wee, zee, twee
  • drie, theorie
    but did not make it into rules yet, given i do not know yet if that does conflict other words.


// http://nl.wikipedia.org/wiki/Meervoud_(Nederlands)#Klinkerverandering
yield new Substitution(new Word('lid'), new Word('leden'));

yield new Substitution(new Word('smid'), new Word('smeden'));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and the word above should be a rule. Also includes words like ooglid (and other samples of ~lid)


yield new Substitution(new Word('schip'), new Word('schepen'));

yield new Substitution(new Word('stad'), new Word('steden'));

yield new Substitution(new Word('gelid'), new Word('gelederen'));

// http://nl.wikipedia.org/wiki/Meervoud_(Nederlands)#Stapelmeervoud
yield new Substitution(new Word('gelid'), new Word('gelederen'));

yield new Substitution(new Word('kalf'), new Word('kalveren'));

yield new Substitution(new Word('lam'), new Word('lammeren'));

// http://nl.wikipedia.org/wiki/Meervoud_(Nederlands)#Onregelmatige_meervoudsvorming
yield new Substitution(new Word('koe'), new Word('koeien'));

yield new Substitution(new Word('vlo'), new Word('vlooien'));

yield new Substitution(new Word('leerrede'), new Word('leerredenen'));

yield new Substitution(new Word('lende'), new Word('lendenen'));

yield new Substitution(new Word('epos'), new Word('epen'));

yield new Substitution(new Word('genius'), new Word('geniën'));

yield new Substitution(new Word('aanbod'), new Word('aanbiedingen'));

yield new Substitution(new Word('beleg'), new Word('belegeringen'));

yield new Substitution(new Word('dank'), new Word('dankbetuigingen'));

yield new Substitution(new Word('gedrag'), new Word('gedragingen'));

yield new Substitution(new Word('genot'), new Word('genietingen'));

yield new Substitution(new Word('lof'), new Word('lofbetuigingen'));

// http://nl.wikipedia.org/wiki/Meervoud_(Nederlands)#Latijnse_meervoudsvormen
yield new Substitution(new Word('quaestrix'), new Word('qaestrices'));

yield new Substitution(new Word('matrix'), new Word('matrices'));
}
}
21 changes: 21 additions & 0 deletions lib/Doctrine/Inflector/Rules/Dutch/InflectorFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Doctrine\Inflector\Rules\Dutch;

use Doctrine\Inflector\GenericLanguageInflectorFactory;
use Doctrine\Inflector\Rules\Ruleset;

final class InflectorFactory extends GenericLanguageInflectorFactory
{
protected function getSingularRuleset(): Ruleset
{
return Rules::getSingularRuleset();
}

protected function getPluralRuleset(): Ruleset
{
return Rules::getPluralRuleset();
}
}
31 changes: 31 additions & 0 deletions lib/Doctrine/Inflector/Rules/Dutch/Rules.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Doctrine\Inflector\Rules\Dutch;

use Doctrine\Inflector\Rules\Patterns;
use Doctrine\Inflector\Rules\Ruleset;
use Doctrine\Inflector\Rules\Substitutions;
use Doctrine\Inflector\Rules\Transformations;

final class Rules
{
public static function getSingularRuleset(): Ruleset
{
return new Ruleset(
new Transformations(...Inflectible::getSingular()),
new Patterns(...Uninflected::getSingular()),
(new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()
);
}

public static function getPluralRuleset(): Ruleset
{
return new Ruleset(
new Transformations(...Inflectible::getPlural()),
new Patterns(...Uninflected::getPlural()),
new Substitutions(...Inflectible::getIrregular())
);
}
}
66 changes: 66 additions & 0 deletions lib/Doctrine/Inflector/Rules/Dutch/Uninflected.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

declare(strict_types=1);

namespace Doctrine\Inflector\Rules\Dutch;

use Doctrine\Inflector\Rules\Pattern;

final class Uninflected
{
/**
* @return iterable<Pattern>
*/
public static function getSingular(): iterable
{
yield from self::getDefault();

// http://nl.wikipedia.org/wiki/Plurale_tantum
yield new Pattern('hersenen');
yield new Pattern('ingewanden');
yield new Pattern('mazelen');
yield new Pattern('pokken');
yield new Pattern('waterpokken');
yield new Pattern('financiën');
yield new Pattern('activa');
yield new Pattern('passiva');
yield new Pattern('onkosten');
yield new Pattern('kosten');
yield new Pattern('bescheiden');
yield new Pattern('paperassen');
yield new Pattern('notulen');
yield new Pattern('Roma');
yield new Pattern('Sinti');
yield new Pattern('Inuit');
yield new Pattern('taliban');
yield new Pattern('illuminati');
yield new Pattern('aanstalten');
yield new Pattern('hurken');
yield new Pattern('lurven');
yield new Pattern('luren');
}

/**
* @return iterable<Pattern>
*/
public static function getPlural(): iterable
{
yield from self::getDefault();

// http://nl.wikipedia.org/wiki/Singulare_tantum
yield new Pattern('letterkunde');
yield new Pattern('muziek');
yield new Pattern('heelal');
yield new Pattern('vastgoed');
yield new Pattern('have');
yield new Pattern('nageslacht');
}

/**
* @return iterable<Pattern>
*/
private static function getDefault(): iterable
{
yield new Pattern('twitter');
}
}
2 changes: 2 additions & 0 deletions tests/Doctrine/Tests/Inflector/InflectorFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Doctrine\Inflector\InflectorFactory;
use Doctrine\Inflector\Language;
use Doctrine\Inflector\LanguageInflectorFactory;
use Doctrine\Inflector\Rules\Dutch\InflectorFactory as DutchInflectorFactory;
use Doctrine\Inflector\Rules\English\InflectorFactory as EnglishInflectorFactory;
use Doctrine\Inflector\Rules\French\InflectorFactory as FrenchInflectorFactory;
use Doctrine\Inflector\Rules\NorwegianBokmal\InflectorFactory as NorwegianBokmalInflectorFactory;
Expand Down Expand Up @@ -38,6 +39,7 @@ public function testCreateForLanguageWithCustomLanguage(string $expectedClass, s
*/
public static function provideLanguages(): Generator
{
yield 'Dutch' => [DutchInflectorFactory::class, Language::DUTCH];
yield 'English' => [EnglishInflectorFactory::class, Language::ENGLISH];
yield 'French' => [FrenchInflectorFactory::class, Language::FRENCH];
yield 'Norwegian Bokmal' => [NorwegianBokmalInflectorFactory::class, Language::NORWEGIAN_BOKMAL];
Expand Down
Loading