Skip to content

Commit 2eb46eb

Browse files
committed
bug #54634 [String] Fix #54611 pluralization of -on ending words + singularization of -a ending foreign words (Geordie, DesLynx)
This PR was squashed before being merged into the 5.4 branch. Discussion ---------- [String] Fix #54611 pluralization of -on ending words + singularization of -a ending foreign words | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | Fix #54611 | License | MIT * fix the pluralization of -on ending words as -ons (with exception for "criterion" and "phenomenon") * fix singularization of -a ending foreign words (see https://english-zone.com/spelling/plurals.html) ![image](https://github.com/symfony/symfony/assets/72632819/ee32d12d-63b6-49ef-a815-4d9f1dc2d405) note: I left "data" uninflected because it seems to me that changing it to the datum/data inflection could cause side effects as "data" is a widely used word (especially in the coding world). * update the test suites (String component + deprecated Inflector component) according to the changes Commits ------- 91325ea [String] Fix #54611 pluralization of -on ending words + singularization of -a ending foreign words
2 parents 82bb267 + 91325ea commit 2eb46eb

File tree

4 files changed

+76
-40
lines changed

4 files changed

+76
-40
lines changed

src/Symfony/Component/Inflector/Tests/InflectorTest.php

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public static function singularizeProvider()
3737
['atlases', ['atlas', 'atlase', 'atlasis']],
3838
['axes', ['ax', 'axe', 'axis']],
3939
['babies', 'baby'],
40-
['bacteria', ['bacterion', 'bacterium']],
40+
['bacteria', 'bacterium'],
4141
['bases', ['bas', 'base', 'basis']],
4242
['batches', ['batch', 'batche']],
4343
['beaux', 'beau'],
@@ -48,6 +48,7 @@ public static function singularizeProvider()
4848
['bureaux', 'bureau'],
4949
['buses', ['bus', 'buse', 'busis']],
5050
['bushes', ['bush', 'bushe']],
51+
['buttons', 'button'],
5152
['calves', ['calf', 'calve', 'calff']],
5253
['cars', 'car'],
5354
['cassettes', ['cassett', 'cassette']],
@@ -58,10 +59,12 @@ public static function singularizeProvider()
5859
['circuses', ['circus', 'circuse', 'circusis']],
5960
['cliffs', 'cliff'],
6061
['committee', 'committee'],
62+
['corpora', 'corpus'],
63+
['coupons', 'coupon'],
6164
['crises', ['cris', 'crise', 'crisis']],
62-
['criteria', ['criterion', 'criterium']],
65+
['criteria', 'criterion'],
6366
['cups', 'cup'],
64-
['coupons', 'coupon'],
67+
['curricula', 'curriculum'],
6568
['data', 'data'],
6669
['days', 'day'],
6770
['discos', 'disco'],
@@ -87,6 +90,7 @@ public static function singularizeProvider()
8790
['funguses', ['fungus', 'funguse', 'fungusis']],
8891
['garages', ['garag', 'garage']],
8992
['geese', 'goose'],
93+
['genera', 'genus'],
9094
['halves', ['half', 'halve', 'halff']],
9195
['hats', 'hat'],
9296
['heroes', ['hero', 'heroe']],
@@ -107,6 +111,8 @@ public static function singularizeProvider()
107111
['lives', 'life'],
108112
['matrices', ['matrex', 'matrix', 'matrice']],
109113
['matrixes', 'matrix'],
114+
['media', 'medium'],
115+
['memoranda', 'memorandum'],
110116
['men', 'man'],
111117
['mice', 'mouse'],
112118
['moves', 'move'],
@@ -120,7 +126,7 @@ public static function singularizeProvider()
120126
['parties', 'party'],
121127
['people', 'person'],
122128
['persons', 'person'],
123-
['phenomena', ['phenomenon', 'phenomenum']],
129+
['phenomena', 'phenomenon'],
124130
['photos', 'photo'],
125131
['pianos', 'piano'],
126132
['plateaux', 'plateau'],
@@ -144,7 +150,7 @@ public static function singularizeProvider()
144150
['spies', 'spy'],
145151
['staves', ['staf', 'stave', 'staff']],
146152
['stories', 'story'],
147-
['strata', ['straton', 'stratum']],
153+
['strata', 'stratum'],
148154
['suitcases', ['suitcas', 'suitcase', 'suitcasis']],
149155
['syllabi', 'syllabus'],
150156
['tags', 'tag'],
@@ -195,7 +201,9 @@ public static function pluralizeProvider()
195201
['bureau', ['bureaus', 'bureaux']],
196202
['bus', 'buses'],
197203
['bush', 'bushes'],
204+
['button', 'buttons'],
198205
['calf', ['calfs', 'calves']],
206+
['campus', 'campuses'],
199207
['car', 'cars'],
200208
['cassette', 'cassettes'],
201209
['cave', 'caves'],
@@ -205,10 +213,11 @@ public static function pluralizeProvider()
205213
['circus', 'circuses'],
206214
['cliff', 'cliffs'],
207215
['committee', 'committees'],
216+
['coupon', 'coupons'],
208217
['crisis', 'crises'],
209-
['criteria', 'criterion'],
218+
['criterion', 'criteria'],
210219
['cup', 'cups'],
211-
['coupon', 'coupons'],
220+
['curriculum', 'curricula'],
212221
['data', 'data'],
213222
['day', 'days'],
214223
['disco', 'discos'],
@@ -232,10 +241,12 @@ public static function pluralizeProvider()
232241
['half', ['halfs', 'halves']],
233242
['hat', 'hats'],
234243
['hero', 'heroes'],
244+
['hippocampus', 'hippocampi'],
235245
['hippopotamus', 'hippopotami'], // hippopotamuses
236246
['hoax', 'hoaxes'],
237247
['hoof', ['hoofs', 'hooves']],
238248
['house', 'houses'],
249+
['icon', 'icons'],
239250
['index', ['indicies', 'indexes']],
240251
['ion', 'ions'],
241252
['iris', 'irises'],
@@ -248,6 +259,8 @@ public static function pluralizeProvider()
248259
['louse', 'lice'],
249260
['man', 'men'],
250261
['matrix', ['matricies', 'matrixes']],
262+
['medium', 'media'],
263+
['memorandum', 'memoranda'],
251264
['mouse', 'mice'],
252265
['move', 'moves'],
253266
['movie', 'movies'],

src/Symfony/Component/Inflector/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"php": ">=7.2.5",
2727
"symfony/deprecation-contracts": "^2.1|^3",
2828
"symfony/polyfill-php80": "^1.16",
29-
"symfony/string": "^5.3.10|^6.0"
29+
"symfony/string": "^5.4.41|^6.4.9"
3030
},
3131
"autoload": {
3232
"psr-4": { "Symfony\\Component\\Inflector\\": "" },

src/Symfony/Component/String/Inflector/EnglishInflector.php

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,32 @@ final class EnglishInflector implements InflectorInterface
2525
// Fourth entry: Whether the suffix may succeed a consonant
2626
// Fifth entry: singular suffix, normal
2727

28-
// bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
29-
['a', 1, true, true, ['on', 'um']],
28+
// bacteria (bacterium)
29+
['airetcab', 8, true, true, 'bacterium'],
30+
31+
// corpora (corpus)
32+
['aroproc', 7, true, true, 'corpus'],
33+
34+
// criteria (criterion)
35+
['airetirc', 8, true, true, 'criterion'],
36+
37+
// curricula (curriculum)
38+
['alucirruc', 9, true, true, 'curriculum'],
39+
40+
// genera (genus)
41+
['areneg', 6, true, true, 'genus'],
42+
43+
// media (medium)
44+
['aidem', 5, true, true, 'medium'],
45+
46+
// memoranda (memorandum)
47+
['adnaromem', 9, true, true, 'memorandum'],
48+
49+
// phenomena (phenomenon)
50+
['anemonehp', 9, true, true, 'phenomenon'],
51+
52+
// strata (stratum)
53+
['atarts', 6, true, true, 'stratum'],
3054

3155
// nebulae (nebula)
3256
['ea', 2, true, true, 'a'],
@@ -141,7 +165,7 @@ final class EnglishInflector implements InflectorInterface
141165
// shoes (shoe)
142166
['se', 2, true, true, ['', 'e']],
143167

144-
// status (status)
168+
// status (status)
145169
['sutats', 6, true, true, 'status'],
146170

147171
// tags (tag)
@@ -241,7 +265,7 @@ final class EnglishInflector implements InflectorInterface
241265
// albums (album)
242266
['mubla', 5, true, true, 'albums'],
243267

244-
// bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
268+
// bacteria (bacterium), curricula (curriculum), media (medium), memoranda (memorandum), phenomena (phenomenon), strata (stratum)
245269
['mu', 2, true, true, 'a'],
246270

247271
// men (man), women (woman)
@@ -250,20 +274,11 @@ final class EnglishInflector implements InflectorInterface
250274
// people (person)
251275
['nosrep', 6, true, true, ['persons', 'people']],
252276

253-
// bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
254-
['noi', 3, true, true, 'ions'],
255-
256-
// coupon (coupons)
257-
['nop', 3, true, true, 'pons'],
258-
259-
// seasons (season), treasons (treason), poisons (poison), lessons (lesson)
260-
['nos', 3, true, true, 'sons'],
261-
262-
// icons (icon)
263-
['noc', 3, true, true, 'cons'],
277+
// criteria (criterion)
278+
['noiretirc', 9, true, true, 'criteria'],
264279

265-
// bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
266-
['no', 2, true, true, 'a'],
280+
// phenomena (phenomenon)
281+
['nonemonehp', 10, true, true, 'phenomena'],
267282

268283
// echoes (echo)
269284
['ohce', 4, true, true, 'echoes'],
@@ -404,9 +419,6 @@ final class EnglishInflector implements InflectorInterface
404419
'erawdrah',
405420
];
406421

407-
/**
408-
* {@inheritdoc}
409-
*/
410422
public function singularize(string $plural): array
411423
{
412424
$pluralRev = strrev($plural);
@@ -438,7 +450,7 @@ public function singularize(string $plural): array
438450
if ($j === $suffixLength) {
439451
// Is there any character preceding the suffix in the plural string?
440452
if ($j < $pluralLength) {
441-
$nextIsVowel = false !== strpos('aeiou', $lowerPluralRev[$j]);
453+
$nextIsVowel = str_contains('aeiou', $lowerPluralRev[$j]);
442454

443455
if (!$map[2] && $nextIsVowel) {
444456
// suffix may not succeed a vowel but next char is one
@@ -483,9 +495,6 @@ public function singularize(string $plural): array
483495
return [$plural];
484496
}
485497

486-
/**
487-
* {@inheritdoc}
488-
*/
489498
public function pluralize(string $singular): array
490499
{
491500
$singularRev = strrev($singular);
@@ -518,7 +527,7 @@ public function pluralize(string $singular): array
518527
if ($j === $suffixLength) {
519528
// Is there any character preceding the suffix in the plural string?
520529
if ($j < $singularLength) {
521-
$nextIsVowel = false !== strpos('aeiou', $lowerSingularRev[$j]);
530+
$nextIsVowel = str_contains('aeiou', $lowerSingularRev[$j]);
522531

523532
if (!$map[2] && $nextIsVowel) {
524533
// suffix may not succeed a vowel but next char is one

src/Symfony/Component/String/Tests/Inflector/EnglishInflectorTest.php

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public static function singularizeProvider()
3535
['atlases', ['atlas', 'atlase', 'atlasis']],
3636
['axes', ['ax', 'axe', 'axis']],
3737
['babies', 'baby'],
38-
['bacteria', ['bacterion', 'bacterium']],
38+
['bacteria', 'bacterium'],
3939
['bases', ['bas', 'base', 'basis']],
4040
['batches', ['batch', 'batche']],
4141
['beaux', 'beau'],
@@ -46,6 +46,7 @@ public static function singularizeProvider()
4646
['bureaux', 'bureau'],
4747
['buses', ['bus', 'buse', 'busis']],
4848
['bushes', ['bush', 'bushe']],
49+
['buttons', 'button'],
4950
['calves', ['calf', 'calve', 'calff']],
5051
['cars', 'car'],
5152
['cassettes', ['cassett', 'cassette']],
@@ -57,10 +58,12 @@ public static function singularizeProvider()
5758
['cliffs', 'cliff'],
5859
['codes', 'code'],
5960
['committee', 'committee'],
61+
['corpora', 'corpus'],
62+
['coupons', 'coupon'],
6063
['crises', ['cris', 'crise', 'crisis']],
61-
['criteria', ['criterion', 'criterium']],
64+
['criteria', 'criterion'],
6265
['cups', 'cup'],
63-
['coupons', 'coupon'],
66+
['curricula', 'curriculum'],
6467
['data', 'data'],
6568
['days', 'day'],
6669
['discos', 'disco'],
@@ -86,6 +89,7 @@ public static function singularizeProvider()
8689
['funguses', ['fungus', 'funguse', 'fungusis']],
8790
['garages', ['garag', 'garage']],
8891
['geese', 'goose'],
92+
['genera', 'genus'],
8993
['halves', ['half', 'halve', 'halff']],
9094
['hats', 'hat'],
9195
['heroes', ['hero', 'heroe']],
@@ -106,6 +110,8 @@ public static function singularizeProvider()
106110
['lives', 'life'],
107111
['matrices', ['matrex', 'matrix', 'matrice']],
108112
['matrixes', 'matrix'],
113+
['media', 'medium'],
114+
['memoranda', 'memorandum'],
109115
['men', 'man'],
110116
['mice', 'mouse'],
111117
['moves', 'move'],
@@ -120,7 +126,7 @@ public static function singularizeProvider()
120126
['parties', 'party'],
121127
['people', 'person'],
122128
['persons', 'person'],
123-
['phenomena', ['phenomenon', 'phenomenum']],
129+
['phenomena', 'phenomenon'],
124130
['photos', 'photo'],
125131
['pianos', 'piano'],
126132
['plateaux', 'plateau'],
@@ -146,7 +152,7 @@ public static function singularizeProvider()
146152
['status', 'status'],
147153
['statuses', 'status'],
148154
['stories', 'story'],
149-
['strata', ['straton', 'stratum']],
155+
['strata', 'stratum'],
150156
['suitcases', ['suitcas', 'suitcase', 'suitcasis']],
151157
['syllabi', 'syllabus'],
152158
['tags', 'tag'],
@@ -200,7 +206,9 @@ public static function pluralizeProvider()
200206
['bureau', ['bureaus', 'bureaux']],
201207
['bus', 'buses'],
202208
['bush', 'bushes'],
209+
['button', 'buttons'],
203210
['calf', ['calfs', 'calves']],
211+
['campus', 'campuses'],
204212
['car', 'cars'],
205213
['cassette', 'cassettes'],
206214
['cave', 'caves'],
@@ -210,10 +218,11 @@ public static function pluralizeProvider()
210218
['circus', 'circuses'],
211219
['cliff', 'cliffs'],
212220
['committee', 'committees'],
221+
['coupon', 'coupons'],
213222
['crisis', 'crises'],
214-
['criteria', 'criterion'],
223+
['criterion', 'criteria'],
215224
['cup', 'cups'],
216-
['coupon', 'coupons'],
225+
['curriculum', 'curricula'],
217226
['data', 'data'],
218227
['day', 'days'],
219228
['disco', 'discos'],
@@ -237,10 +246,12 @@ public static function pluralizeProvider()
237246
['half', ['halfs', 'halves']],
238247
['hat', 'hats'],
239248
['hero', 'heroes'],
249+
['hippocampus', 'hippocampi'],
240250
['hippopotamus', 'hippopotami'], // hippopotamuses
241251
['hoax', 'hoaxes'],
242252
['hoof', ['hoofs', 'hooves']],
243253
['house', 'houses'],
254+
['icon', 'icons'],
244255
['index', ['indicies', 'indexes']],
245256
['ion', 'ions'],
246257
['iris', 'irises'],
@@ -253,6 +264,8 @@ public static function pluralizeProvider()
253264
['louse', 'lice'],
254265
['man', 'men'],
255266
['matrix', ['matricies', 'matrixes']],
267+
['medium', 'media'],
268+
['memorandum', 'memoranda'],
256269
['mouse', 'mice'],
257270
['move', 'moves'],
258271
['movie', 'movies'],
@@ -286,6 +299,7 @@ public static function pluralizeProvider()
286299
['shoe', 'shoes'],
287300
['species', 'species'],
288301
['status', ['status', 'statuses']],
302+
['stratum', 'strata'],
289303
['spy', 'spies'],
290304
['staff', 'staves'],
291305
['story', 'stories'],

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy