Skip to content

Commit a49d1e7

Browse files
committed
Merge remote-tracking branch 'alex-storchak/fix-russian-noun-pluralization-with-ka-ending'
2 parents fa84bd7 + ec784ef commit a49d1e7

4 files changed

Lines changed: 107 additions & 60 deletions

File tree

src/Russian/NounDeclension.php

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -378,11 +378,17 @@ public static function getDeclension($word, $animateness = false)
378378

379379
if (in_array($last, ['а', 'я'], true) && S::slice($word, -2) != 'мя') {
380380
return self::FIRST_DECLENSION;
381-
} elseif (RussianLanguage::isConsonant($last) || in_array($last, ['о', 'е', 'ё'], true)
382-
|| ($last == 'ь' && RussianLanguage::isConsonant(S::slice($word, -2,
383-
-1)) && !RussianLanguage::isHissingConsonant(S::slice($word, -2, -1))
384-
&& (in_array($word, static::$masculineWithSoft,
385-
true)) /*|| in_array($word, static::$masculineWithSoftAndRunAwayVowels, true)*/)) {
381+
} elseif (
382+
RussianLanguage::isConsonant($last)
383+
|| in_array($last, ['о', 'е', 'ё'], true)
384+
|| (
385+
$last == 'ь'
386+
&& RussianLanguage::isConsonant(S::slice($word, -2, -1))
387+
&& !RussianLanguage::isHissingConsonant(S::slice($word, -2, -1))
388+
&& (in_array($word, static::$masculineWithSoft, true))
389+
/*|| in_array($word, static::$masculineWithSoftAndRunAwayVowels, true)*/
390+
)
391+
) {
386392
return self::SECOND_DECLENSION;
387393
} else {
388394
return self::THIRD_DECLENSION;

src/Russian/NounPluralization.php

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,17 @@ protected static function declinateSubstative($word, $animateness)
204204
$last = S::slice($word, -1);
205205

206206
if (($declension = NounDeclension::getDeclension($word)) == NounDeclension::SECOND_DECLENSION) {
207-
$soft_last = $last == 'й' || (in_array($last, ['ь', 'е', 'ё', 'ю', 'я'], true)
208-
&& ((
209-
RussianLanguage::isConsonant(S::slice($word, -2,
210-
-1)) && !RussianLanguage::isHissingConsonant(S::slice($word, -2, -1)))
211-
|| S::slice($word, -2, -1) == 'и'));
212-
$prefix = NounDeclension::getPrefixOfSecondDeclension($word, $last);
207+
$soft_last = $last === 'й' || (
208+
in_array($last, ['ь', 'е', 'ё', 'ю', 'я'], true)
209+
&& (
210+
(
211+
RussianLanguage::isConsonant(S::slice($word, -2, -1))
212+
&& !RussianLanguage::isHissingConsonant(S::slice($word, -2, -1))
213+
)
214+
|| S::slice($word, -2, -1) == 'и'
215+
)
216+
);
217+
$prefix = NounDeclension::getPrefixOfSecondDeclension($word, $last);
213218
} elseif ($declension == NounDeclension::FIRST_DECLENSION) {
214219
$soft_last = RussianLanguage::checkLastConsonantSoftness($word);
215220
} else {
@@ -218,16 +223,17 @@ protected static function declinateSubstative($word, $animateness)
218223

219224
$forms = [];
220225

221-
if (in_array($last, ['ч', 'г'], true)
226+
if (
227+
in_array($last, ['ч', 'г', 'ж', 'ш'], true)
222228
|| in_array(S::slice($word, -2), ['чь', 'сь', 'ть', 'нь', 'рь', 'дь', 'ль'], true)
223-
|| (RussianLanguage::isVowel($last) && in_array(S::slice($word, -2, -1), ['ч', 'к'],
224-
true))) { // before ч, чь, сь, ч+vowel, к+vowel
229+
|| (RussianLanguage::isVowel($last) && in_array(S::slice($word, -2, -1), ['ч', 'к'], true))
230+
) { // before ч, чь, сь, ч+vowel, к+vowel
225231
$forms[Cases::IMENIT] = $prefix . 'и';
226-
} elseif (in_array($last, ['н', 'ц', 'р', 'т', 'с', 'ж'], true)) {
232+
} elseif (in_array($last, ['н', 'ц', 'р', 'т', 'с'], true)) {
227233
$forms[Cases::IMENIT] = $prefix . 'ы';
228234
} else {
229-
$forms[Cases::IMENIT] = RussianLanguage::chooseVowelAfterConsonant($last, $soft_last, $prefix . 'я',
230-
$prefix . 'а');
235+
// TODO: fix first declension (depends on animateness and gender, see test cases)
236+
$forms[Cases::IMENIT] = RussianLanguage::chooseVowelAfterConsonant($last, $soft_last, $prefix . 'я', $prefix . 'а');
231237
}
232238

233239
// RODIT
@@ -242,25 +248,27 @@ protected static function declinateSubstative($word, $animateness)
242248
} else {
243249
$forms[Cases::RODIT] = $prefix;
244250
}
245-
} elseif (S::slice($word, -2) == 'ка' && S::slice($word, -3,
246-
-2) !== 'и') { // words ending with -ка: чашка, вилка, ложка, тарелка, копейка, батарейка, аптека
247-
if (S::slice($word, -3, -2) == 'л') {
251+
} elseif (S::slice($word, -2) == 'ка') { // words ending with -ка: чашка, вилка, ложка, тарелка, копейка, батарейка, аптека
252+
if (in_array(S::slice($word, -3, -2), ['б', 'в', 'д', 'з', 'л', 'м', 'н', 'п', 'р', 'с', 'т', 'ф'], true)) {
248253
$forms[Cases::RODIT] = S::slice($word, 0, -2) . 'ок';
249-
} elseif (in_array(S::slice($word, -3, -2), ['й', 'е'], true)) {
254+
} elseif (in_array(S::slice($word, -3, -2), ['ц', 'ч', 'ш', 'щ', 'ж'], true)) {
255+
$forms[Cases::RODIT] = S::slice($word, 0, -2) . 'ек';
256+
} elseif (S::slice($word, -3, -2) === 'й') {
250257
$forms[Cases::RODIT] = S::slice($word, 0, -3) . 'ек';
258+
} elseif (in_array(S::slice($word, -3, -2), array_merge(['е', 'к'], RussianLanguage::$vowels), true)) {
259+
$forms[Cases::RODIT] = $prefix;
251260
} else {
252-
if ($word === 'штука') {
253-
$forms[Cases::RODIT] = S::slice($word, 0, -2) . 'к';
254-
} else {
255-
$forms[Cases::RODIT] = S::slice($word, 0, -2) . 'ек';
256-
}
261+
$forms[Cases::RODIT] = S::slice($word, 0, -2) . 'ек';
257262
}
258-
} elseif (in_array($last, ['а'], true)) { // обида, ябеда
263+
} elseif ($last === 'а') { // обида, ябеда
259264
$forms[Cases::RODIT] = $prefix;
260-
} elseif (in_array($last, ['я'], true)) { // молния
265+
} elseif ($last === 'я') { // молния
261266
$forms[Cases::RODIT] = $prefix . 'й';
262-
} elseif (RussianLanguage::isHissingConsonant($last) || ($soft_last && $last != 'й') || in_array(S::slice($word,
263-
-2), ['чь', 'сь', 'ть', 'нь', 'дь'], true)) {
267+
} elseif (
268+
RussianLanguage::isHissingConsonant($last)
269+
|| ($soft_last && $last != 'й')
270+
|| in_array(S::slice($word, -2), ['чь', 'сь', 'ть', 'нь', 'дь'], true)
271+
) {
264272
$forms[Cases::RODIT] = $prefix . 'ей';
265273
} elseif ($last == 'й' || S::slice($word, -2) == 'яц') { // месяц
266274
$forms[Cases::RODIT] = $prefix . 'ев';

src/Russian/RussianLanguage.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,10 @@ public static function checkLastConsonantSoftness($word)
139139
return true;
140140
}
141141

142-
if (S::length($substring) > 1 && in_array(S::slice($substring, 1, 2), ['е', 'ё', 'и', 'ю', 'я', 'ь'],
143-
true)) { // consonants are soft if they are trailed with these vowels
142+
if (
143+
S::length($substring) > 1
144+
&& in_array(S::slice($substring, 1, 2), ['е', 'ё', 'и', 'ю', 'я', 'ь'], true) // consonants are soft if they are trailed with these vowels
145+
) {
144146
return true;
145147
}
146148
}

0 commit comments

Comments
 (0)