diff --git a/src/Humanizer/Inflections/Vocabularies.cs b/src/Humanizer/Inflections/Vocabularies.cs index 1107672ab..2aaaec8e2 100644 --- a/src/Humanizer/Inflections/Vocabularies.cs +++ b/src/Humanizer/Inflections/Vocabularies.cs @@ -20,6 +20,94 @@ internal static string ApplyAcronyms(string input) => internal static string NormalizeAcronyms(string input) => Instance.IsValueCreated ? Instance.Value.NormalizeAcronyms(input) : input; + /// + /// Element names ending in -ium (and aluminum) are most often uncountable + /// + internal static readonly string[] UncountableChemicalElementNames = + [ + "actinium", + "aluminium", + "aluminum", + "americium", + "barium", + "berkelium", + "beryllium", + "bohrium", + "cadmium", + "caesium", + "californium", + "calcium", + "cerium", + "cesium", + "chromium", + "copernicium", + "curium", + "darmstadtium", + "dubnium", + "dysprosium", + "einsteinium", + "erbium", + "europium", + "fermium", + "flerovium", + "francium", + "gadolinium", + "gallium", + "germanium", + "hafnium", + "hassium", + "helium", + "holmium", + "indium", + "iridium", + "lawrencium", + "lithium", + "livermorium", + "lutetium", + "magnesium", + "meitnerium", + "mendelevium", + "moscovium", + "neodymium", + "neptunium", + "nihonium", + "niobium", + "nobelium", + "osmium", + "palladium", + "plutonium", + "polonium", + "potassium", + "praseodymium", + "promethium", + "protactinium", + "radium", + "rhenium", + "rhodium", + "roentgenium", + "rubidium", + "ruthenium", + "rutherfordium", + "samarium", + "scandium", + "seaborgium", + "selenium", + "sodium", + "strontium", + "technetium", + "tellurium", + "terbium", + "thallium", + "thorium", + "thulium", + "titanium", + "uranium", + "vanadium", + "ytterbium", + "yttrium", + "zirconium", + ]; + static Vocabulary BuildDefault() { var _default = new Vocabulary(); @@ -27,8 +115,8 @@ static Vocabulary BuildDefault() _default.AddPlural("$", "s"); _default.AddPlural("s$", "s"); _default.AddPlural("(ax|test)is$", "$1es"); - _default.AddPlural("(octop|vir|alumn|fung|cact|foc|hippopotam|radi|stimul|syllab|nucle)us$", "$1i"); - _default.AddPlural("(alias|bias|iris|status|campus|apparatus|virus|walrus|trellis)$", "$1es"); + _default.AddPlural("(vir|alumn|fung|cact|foc|radi|stimul|syllab|nucle)us$", "$1i"); + _default.AddPlural("(alias|bias|iris|status|campus|apparatus|virus|walrus|trellis|octopus|hippopotamus)$", "$1es"); _default.AddPlural("(buffal|tomat|volcan|ech|embarg|her|mosquit|potat|torped|vet)o$", "$1oes"); _default.AddPlural("([dti])um$", "$1a"); _default.AddPlural("sis$", "ses"); @@ -50,6 +138,7 @@ static Vocabulary BuildDefault() _default.AddSingular("([dti])a$", "$1um"); _default.AddSingular("(analy|ba|diagno|parenthe|progno|synop|the|ellip|empha|neuro|oa|paraly)ses$", "$1sis"); _default.AddSingular("(.+)ves$", "$1ve"); + _default.AddSingular("(him|her|it|my|one)selves$", "$1self"); _default.AddSingular("(hive)s$", "$1"); _default.AddSingular("(tive)s$", "$1"); _default.AddSingular("(cal|dwar|el|hal|hoo|lea|loa|scar|sel|shel|thie|tur|whar|wol)ves$", "$1f"); @@ -63,9 +152,11 @@ static Vocabulary BuildDefault() _default.AddSingular("(shoe)s$", "$1"); _default.AddSingular("((? Assert.Equal(expected, plural.Singularize()); + [Theory] + [InlineData("octopuses", "octopus")] + [InlineData("octopi", "octopus")] + [InlineData("octopodes", "octopus")] + [InlineData("hippopotamuses", "hippopotamus")] + [InlineData("hippopotami", "hippopotamus")] + [InlineData("premiums", "premium")] + [InlineData("premia", "premium")] + [InlineData("stadiums", "stadium")] + [InlineData("stadia", "stadium")] + [InlineData("podiums", "podium")] + [InlineData("podia", "podium")] + [InlineData("ultimatums", "ultimatum")] + [InlineData("ultimata", "ultimatum")] + [InlineData("condominiums", "condominium")] + [InlineData("condominia", "condominium")] + [InlineData("euphoniums", "euphonium")] + [InlineData("euphonia", "euphonium")] + [InlineData("harmoniums", "harmonium")] + [InlineData("harmonia", "harmonium")] + [InlineData("criteriums", "criterium")] + [InlineData("spandexes", "spandex")] + [InlineData("spandices", "spandex")] + [InlineData("himselves", "himself")] + [InlineData("herselves", "herself")] + [InlineData("itselves", "itself")] + [InlineData("myselves", "myself")] + [InlineData("oneselves", "oneself")] + [InlineData("yourselves", "yourself")] + [InlineData("aquariums", "aquarium")] + [InlineData("auditoriums", "auditorium")] + [InlineData("consortiums", "consortium")] + [InlineData("symposiums", "symposium")] + public void SingularizeRecognizesAlternatePlurals(string plural, string singular) + { + Assert.Equal(singular, plural.Singularize()); + Assert.Equal(singular, plural.Singularize(inputIsKnownToBePlural: false)); + } + + [Fact] + public void ChemicalElementNamesEndingInIumAreUncountable() + { + foreach (var element in Vocabularies.UncountableChemicalElementNames) + { + Assert.Equal(element, element.Pluralize()); + Assert.Equal(element, element.Singularize()); + Assert.Equal(element, element.Pluralize(inputIsKnownToBeSingular: false)); + Assert.Equal(element, element.Singularize(inputIsKnownToBePlural: false)); + } + } + [Theory] [InlineData("a")] [InlineData("A")] @@ -495,7 +546,7 @@ public IEnumerator GetEnumerator() yield return ["louse", "lice"]; yield return ["house", "houses"]; - yield return ["octopus", "octopi"]; + yield return ["octopus", "octopuses"]; yield return ["alias", "aliases"]; yield return ["portfolio", "portfolios"]; yield return ["criterion", "criteria"]; @@ -567,7 +618,7 @@ public IEnumerator GetEnumerator() yield return ["grass", "grass"]; yield return ["hair", "hair"]; yield return ["hero", "heroes"]; - yield return ["hippopotamus", "hippopotami"]; + yield return ["hippopotamus", "hippopotamuses"]; yield return ["hoof", "hooves"]; yield return ["iris", "irises"]; yield return ["larva", "larvae"]; @@ -656,6 +707,28 @@ public IEnumerator GetEnumerator() //Issue #1042 yield return ["database", "databases"]; + + //Issue #1962 + yield return ["premium", "premiums"]; + yield return ["stadium", "stadiums"]; + yield return ["podium", "podiums"]; + yield return ["ultimatum", "ultimatums"]; + yield return ["condominium", "condominiums"]; + yield return ["euphonium", "euphoniums"]; + yield return ["harmonium", "harmoniums"]; + yield return ["criterium", "criteriums"]; + yield return ["spandex", "spandexes"]; + yield return ["himself", "himself"]; + yield return ["herself", "herself"]; + yield return ["itself", "itself"]; + yield return ["myself", "myself"]; + yield return ["oneself", "oneself"]; + yield return ["yourself", "yourselves"]; + yield return ["self", "selves"]; + yield return ["aquarium", "aquaria"]; + yield return ["auditorium", "auditoria"]; + yield return ["consortium", "consortia"]; + yield return ["symposium", "symposia"]; } IEnumerator IEnumerable.GetEnumerator() =>