Clever way to append 's' for plural form in .Net (syntactic sugar)

前端 未结 14 1622
抹茶落季
抹茶落季 2021-01-30 06:53

I want to be able to type something like:

Console.WriteLine(\"You have {0:life/lives} left.\", player.Lives);

instead of

Consol         


        
相关标签:
14条回答
  • 2021-01-30 07:15

    If your application is English on you can use all the solutions shown here. However if you plan to localize the application the plural enabled message must be done in a proper way. This means that you may need multiple patterns (from 1 to 6) depending on the language and the rule to choose what the pattern is used depends on the language.

    For example in English you would have two patterns

    "You have {0} live left" "You have {0} lives left"

    Then you would have a Format function where you pass these two patterns with the liveAmount variable.

    Format("You have {0} live left", "You have {0} lives left", liveAmount);
    

    In a real application you would not hard code the string but would use resource strings.

    Format would know what the active language is and if English it would use

    if (count == 1)
      useSingularPattern
    else
      usePluralPattern
    

    To implement this yourself is a bit complex bu you don't have to. You can you an open source project I have made

    https://github.com/jaska45/I18N

    By using it you can easily get the string

    var str = MultiPattern.Format("one;You have {0} live left;other;You have {0} lives left", liveAmount);
    

    That's it. The library knows what pattern to use depending on the passed liveAmount paramter. The rules have been extracted from CLDR into library .cs file.

    If you want to localize the application you just put the multi pattern string into .resx and let the translator to translate it. Depending on the target language the multi pattern string might contains 1, 2, 3, 4, 5 or 6 patterns.

    0 讨论(0)
  • 2021-01-30 07:17

    using @Darin Dimitrov solution, I would create an extention for string ....

    public static Extentions
    {
        public static string Pluralize(this string str,int n)
        {
            if ( n != 1 )
                return PluralizationService.CreateService(new CultureInfo("en-US"))
                .Pluralize(str);
            return str;
        }
    }
    
    string.format("you have {0} {1} remaining",liveCount,"life".Pluralize());
    
    0 讨论(0)
  • 2021-01-30 07:17

    I wrote an open-source library called SmartFormat that does exactly that! It's written in C# and is on GitHub: http://github.com/scottrippey/SmartFormat

    Although it supports several languages, English "plural rules" are the default. Here's the syntax:

    var output = Smart.Format("You have {0} {0:life:lives} left.", player.Lives);
    

    It also supports "zero" quantity, and nested placeholders, so you could do:

    var output = Smart.Format("You have {0:no lives:1 life:{0} lives} left.", player.Lives);
    
    0 讨论(0)
  • 2021-01-30 07:18

    A bit late to the party, but I wrote a library called MessageFormat.NET that handles this.

    var str = @"You have {lives, plural, 
                         zero {no lives} 
                          one {one life} 
                        other {# lives}
                } left.";
    var result = MessageFormatter.Format(str, new {
        lives = 1337
    });
    

    The whitespace in the string surrounding the text is not required, but merely for readability.

    This is great when translating, as languages have different rules when it comes to pluralization.

    0 讨论(0)
  • With the newfangled interpolated strings, I just use something like this:

    // n is the number of connection attempts
    Console.WriteLine($"Needed {n} attempt{(n!=1 ? "s" : "")} to connect...");
    

    EDIT: just ran across this answer again--since I originally posted this, I've been using an extension method that makes it even easier. This example is ordered by peculiarity:

    static class Extensions {
        /// <summary>
        /// Pluralize: takes a word, inserts a number in front, and makes the word plural if the number is not exactly 1.
        /// </summary>
        /// <example>"{n.Pluralize("maid")} a-milking</example>
        /// <param name="word">The word to make plural</param>
        /// <param name="number">The number of objects</param>
        /// <param name="pluralSuffix">An optional suffix; "s" is the default.</param>
        /// <param name="singularSuffix">An optional suffix if the count is 1; "" is the default.</param>
        /// <returns>Formatted string: "number word[suffix]", pluralSuffix (default "s") only added if the number is not 1, otherwise singularSuffix (default "") added</returns>
        internal static string Pluralize(this int number, string word, string pluralSuffix = "s", string singularSuffix = "")
        {
            return $@"{number} {word}{(number != 1 ? pluralSuffix : singularSuffix)}";
        }
    }
    
    void Main()
    {
        int lords = 0;
        int partridges = 1;
        int geese = 1;
        int ladies = 8;
        Console.WriteLine($@"Have {lords.Pluralize("lord")}, {partridges.Pluralize("partridge")}, {ladies.Pluralize("lad", "ies", "y")}, and {geese.Pluralize("", "geese", "goose")}");
        lords = 1;
        partridges = 2;
        geese = 6;
        ladies = 1;
        Console.WriteLine($@"Have {lords.Pluralize("lord")}, {partridges.Pluralize("partridge")}, {ladies.Pluralize("lad", "ies", "y")}, and {geese.Pluralize("", "geese", "goose")}");
    }
    

    (formats are the same). The output is:

    Have 0 lords, 1 partridge, 8 ladies, and 1 goose
    Have 1 lord, 2 partridges, 1 lady, and 6 geese
    
    0 讨论(0)
  • 2021-01-30 07:19

    I'm thinking the easiest way to do it is to create an Interface IPlural which has an method .ToString(int quantity) which returns the singular form when quantity == 1 an the plural form all other times.

    0 讨论(0)
提交回复
热议问题