Skip to content

Commit

Permalink
For Russian language fixed noun pluralization for words with "-ка" en…
Browse files Browse the repository at this point in the history
…ding and noun pluralization in nominative case for words with "-ж/-ш" ending.

Rearrange test cases by declension for NounPluralization class.

Some codestyle fixes.
  • Loading branch information
alex-storchak committed Oct 9, 2024
1 parent d228767 commit ec784ef
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 60 deletions.
16 changes: 11 additions & 5 deletions src/Russian/NounDeclension.php
Original file line number Diff line number Diff line change
Expand Up @@ -377,11 +377,17 @@ public static function getDeclension($word, $animateness = false)

if (in_array($last, ['а', 'я'], true) && S::slice($word, -2) != 'мя') {
return self::FIRST_DECLENSION;
} elseif (RussianLanguage::isConsonant($last) || in_array($last, ['о', 'е', 'ё'], true)
|| ($last == 'ь' && RussianLanguage::isConsonant(S::slice($word, -2,
-1)) && !RussianLanguage::isHissingConsonant(S::slice($word, -2, -1))
&& (in_array($word, static::$masculineWithSoft,
true)) /*|| in_array($word, static::$masculineWithSoftAndRunAwayVowels, true)*/)) {
} elseif (
RussianLanguage::isConsonant($last)
|| in_array($last, ['о', 'е', 'ё'], true)
|| (
$last == 'ь'
&& RussianLanguage::isConsonant(S::slice($word, -2, -1))
&& !RussianLanguage::isHissingConsonant(S::slice($word, -2, -1))
&& (in_array($word, static::$masculineWithSoft, true))
/*|| in_array($word, static::$masculineWithSoftAndRunAwayVowels, true)*/
)
) {
return self::SECOND_DECLENSION;
} else {
return self::THIRD_DECLENSION;
Expand Down
58 changes: 33 additions & 25 deletions src/Russian/NounPluralization.php
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,17 @@ protected static function declinateSubstative($word, $animateness)
$last = S::slice($word, -1);

if (($declension = NounDeclension::getDeclension($word)) == NounDeclension::SECOND_DECLENSION) {
$soft_last = $last == 'й' || (in_array($last, ['ь', 'е', 'ё', 'ю', 'я'], true)
&& ((
RussianLanguage::isConsonant(S::slice($word, -2,
-1)) && !RussianLanguage::isHissingConsonant(S::slice($word, -2, -1)))
|| S::slice($word, -2, -1) == 'и'));
$prefix = NounDeclension::getPrefixOfSecondDeclension($word, $last);
$soft_last = $last === 'й' || (
in_array($last, ['ь', 'е', 'ё', 'ю', 'я'], true)
&& (
(
RussianLanguage::isConsonant(S::slice($word, -2, -1))
&& !RussianLanguage::isHissingConsonant(S::slice($word, -2, -1))
)
|| S::slice($word, -2, -1) == 'и'
)
);
$prefix = NounDeclension::getPrefixOfSecondDeclension($word, $last);
} elseif ($declension == NounDeclension::FIRST_DECLENSION) {
$soft_last = RussianLanguage::checkLastConsonantSoftness($word);
} else {
Expand All @@ -218,16 +223,17 @@ protected static function declinateSubstative($word, $animateness)

$forms = [];

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

// RODIT
Expand All @@ -242,25 +248,27 @@ protected static function declinateSubstative($word, $animateness)
} else {
$forms[Cases::RODIT] = $prefix;
}
} elseif (S::slice($word, -2) == 'ка' && S::slice($word, -3,
-2) !== 'и') { // words ending with -ка: чашка, вилка, ложка, тарелка, копейка, батарейка, аптека
if (S::slice($word, -3, -2) == 'л') {
} elseif (S::slice($word, -2) == 'ка') { // words ending with -ка: чашка, вилка, ложка, тарелка, копейка, батарейка, аптека
if (in_array(S::slice($word, -3, -2), ['б', 'в', 'д', 'з', 'л', 'м', 'н', 'п', 'р', 'с', 'т', 'ф'], true)) {
$forms[Cases::RODIT] = S::slice($word, 0, -2) . 'ок';
} elseif (in_array(S::slice($word, -3, -2), ['й', 'е'], true)) {
} elseif (in_array(S::slice($word, -3, -2), ['ц', 'ч', 'ш', 'щ', 'ж'], true)) {
$forms[Cases::RODIT] = S::slice($word, 0, -2) . 'ек';
} elseif (S::slice($word, -3, -2) === 'й') {
$forms[Cases::RODIT] = S::slice($word, 0, -3) . 'ек';
} elseif (in_array(S::slice($word, -3, -2), array_merge(['е', 'к'], RussianLanguage::$vowels), true)) {
$forms[Cases::RODIT] = $prefix;
} else {
if ($word === 'штука') {
$forms[Cases::RODIT] = S::slice($word, 0, -2) . 'к';
} else {
$forms[Cases::RODIT] = S::slice($word, 0, -2) . 'ек';
}
$forms[Cases::RODIT] = S::slice($word, 0, -2) . 'ек';
}
} elseif (in_array($last, ['а'], true)) { // обида, ябеда
} elseif ($last === 'а') { // обида, ябеда
$forms[Cases::RODIT] = $prefix;
} elseif (in_array($last, ['я'], true)) { // молния
} elseif ($last === 'я') { // молния
$forms[Cases::RODIT] = $prefix . 'й';
} elseif (RussianLanguage::isHissingConsonant($last) || ($soft_last && $last != 'й') || in_array(S::slice($word,
-2), ['чь', 'сь', 'ть', 'нь', 'дь'], true)) {
} elseif (
RussianLanguage::isHissingConsonant($last)
|| ($soft_last && $last != 'й')
|| in_array(S::slice($word, -2), ['чь', 'сь', 'ть', 'нь', 'дь'], true)
) {
$forms[Cases::RODIT] = $prefix . 'ей';
} elseif ($last == 'й' || S::slice($word, -2) == 'яц') { // месяц
$forms[Cases::RODIT] = $prefix . 'ев';
Expand Down
6 changes: 4 additions & 2 deletions src/Russian/RussianLanguage.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,10 @@ public static function checkLastConsonantSoftness($word)
return true;
}

if (S::length($substring) > 1 && in_array(S::slice($substring, 1, 2), ['е', 'ё', 'и', 'ю', 'я', 'ь'],
true)) { // consonants are soft if they are trailed with these vowels
if (
S::length($substring) > 1
&& in_array(S::slice($substring, 1, 2), ['е', 'ё', 'и', 'ю', 'я', 'ь'], true) // consonants are soft if they are trailed with these vowels
) {
return true;
}
}
Expand Down
Loading

0 comments on commit ec784ef

Please sign in to comment.