Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <inflection/dialog/NumberConcept.hpp>
#include <inflection/dialog/SemanticFeatureConceptBase.hpp>
#include <inflection/dialog/SpeakableString.hpp>
#include <inflection/grammar/synthesis/GrammemeConstants.hpp>
#include <inflection/util/Validate.hpp>
#include <inflection/npc.hpp>
#include <cmath>
Expand Down Expand Up @@ -44,4 +45,16 @@ ::inflection::dialog::SpeakableString* SerboCroatianCommonConceptFactory::quanti
return result;
}

void SerboCroatianCommonConceptFactory::applyGatedGenitive(
SemanticFeatureConceptBase& clone, std::u16string_view baseCase, Agreement mode) const
{
if (mode == Agreement::GOVERNED_PLURAL) {
// In Serbo-Croatian, integers 5+ (and indeclinable numerals like "пет") always govern the Genitive Plural ("бродова"),
// even inside an oblique case context (e.g., Locative, Instrumental, Dative).
clone.putConstraint(semanticFeatureCase, ::inflection::grammar::synthesis::GrammemeConstants::CASE_GENITIVE);
} else {
super::applyGatedGenitive(clone, baseCase, mode);
}
}

} // namespace inflection::dialog::language
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ class inflection::dialog::language::SerboCroatianCommonConceptFactory
const SemanticFeatureConceptBase* semanticConcept) const override;

explicit SerboCroatianCommonConceptFactory(const ::inflection::util::ULocale& language);

protected:
void applyGatedGenitive(SemanticFeatureConceptBase& clone, std::u16string_view baseCase, Agreement mode) const override;
};
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ bool SlavicCommonConceptFactory::isDirectCase(std::u16string_view baseCase, std:
return baseCase == GrammemeConstants::CASE_ACCUSATIVE && animacy == GrammemeConstants::ANIMACY_INANIMATE;
}

void SlavicCommonConceptFactory::applyGatedGenitive(SemanticFeatureConceptBase& clone, std::u16string_view baseCase) const
void SlavicCommonConceptFactory::applyGatedGenitive(SemanticFeatureConceptBase& clone, std::u16string_view baseCase, Agreement) const
{
if (baseCase.empty() || baseCase == GrammemeConstants::CASE_NOMINATIVE || baseCase == GrammemeConstants::CASE_ACCUSATIVE) {
clone.putConstraint(semanticFeatureCase, GrammemeConstants::CASE_GENITIVE);
Expand Down Expand Up @@ -118,7 +118,7 @@ ::inflection::dialog::SpeakableString SlavicCommonConceptFactory::resolveQuantit
// Animacy is needed here to tell the direct (singular paucal) case from the oblique plural.
const std::u16string animacy(getFeature(semanticConcept, semanticFeatureAnimacy));
numberConstraint = isDirectCase(baseCase, animacy) ? GrammemeConstants::NUMBER_SINGULAR : GrammemeConstants::NUMBER_PLURAL;
applyGatedGenitive(*clone, baseCase);
applyGatedGenitive(*clone, baseCase, mode);
break;
}
case Agreement::PAUCAL_PLURAL: {
Expand All @@ -130,7 +130,7 @@ ::inflection::dialog::SpeakableString SlavicCommonConceptFactory::resolveQuantit
}
case Agreement::GOVERNED_PLURAL: {
numberConstraint = GrammemeConstants::NUMBER_PLURAL;
applyGatedGenitive(*clone, baseCase);
applyGatedGenitive(*clone, baseCase, mode);
break;
}
case Agreement::FRACTION_GENITIVE_SG: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class inflection::dialog::language::SlavicCommonConceptFactory
static std::u16string getFeature(const SemanticFeatureConceptBase& semanticConcept, const SemanticFeature& semanticFeature);
Agreement agreementForCount(Plurality::Rule countType) const;
bool isDirectCase(std::u16string_view baseCase, std::u16string_view animacy) const;
void applyGatedGenitive(SemanticFeatureConceptBase& clone, std::u16string_view baseCase) const;
virtual void applyGatedGenitive(SemanticFeatureConceptBase& clone, std::u16string_view baseCase, Agreement mode) const;

virtual std::optional<std::u16string> adjustCase(Plurality::Rule countType,
const SemanticFeatureConceptBase& semanticConcept, std::u16string_view baseCase) const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ TEST_CASE("QuantifyTest#testSerboCroatian")
assertQuantity(conceptFactory, ::inflection::dialog::SpeakableString(u"3 брода", u"три брода"), 3, ::inflection::dialog::SpeakableString(u"брод"));
assertQuantity(conceptFactory, ::inflection::dialog::SpeakableString(u"4 брода", u"четири брода"), 4, ::inflection::dialog::SpeakableString(u"брод"));
assertQuantity(conceptFactory, ::inflection::dialog::SpeakableString(u"5 бродова", u"пет бродова"), 5, ::inflection::dialog::SpeakableString(u"брод"));
// A fraction falls in the CLDR "one" bucket yet must take the genitive singular.
// A fraction falls in the CLDR "other" bucket yet must take the genitive singular.
#if U_ICU_VERSION_MAJOR_NUM <= 78
// TODO remove this version check after version 79 is released, and update versions.mk with the new minimum version.
WARN("U_ICU_VERSION_MAJOR_NUM <= 78. Please test with a newer version of ICU.");
Expand All @@ -602,5 +602,12 @@ TEST_CASE("QuantifyTest#testSerboCroatian")
#else
assertQuantity(conceptFactory, ::inflection::dialog::SpeakableString(u"1,1 земље", u"једна зарез једна земље"), 1.1, ::inflection::dialog::SpeakableString(u"земља"));
#endif

// Verify oblique cases for 5+ (always genitive plural: бродова / земаља)
assertQuantity(conceptFactory, u"5 бродова", u"пет бродова", 5, u"брод", u"locative");
assertQuantity(conceptFactory, u"5 бродова", u"пет бродова", 5, u"брод", u"instrumental");
assertQuantity(conceptFactory, u"5 бродова", u"пет бродова", 5, u"брод", u"dative");
assertQuantity(conceptFactory, u"5 земаља", u"пет земаља", 5, u"земља", u"locative");
assertQuantity(conceptFactory, u"5 земаља", u"пет земаља", 5, u"земља", u"instrumental");
}

Loading