Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to localize or string format a list of words with commas and conjunctions in C#?

In C# I use resource strings and string.Format for localization. Sometimes I need to generate a message from an arbitrarily-sized list of terms. (Example: "You must select one of Dog, Cat, or Monkey" from list ["Dog", "Cat", "Monkey"])

I can write code to produce that message, but it undermines the flexibility of the format strings (the ability for translators to rearrange where arguments show up in a format string) and their clarity (example: "You must select one of {0}") .

What better can I do in my code and resource files to avoid those drawbacks?

Example of current code:

// assuming all string literals are in a Resource file somewhere...

string message = string.Format(
  "You must select one of {0}.", 
  Conjoin(new []{ "Dog", "Cat", "Monkey" }));
  // produces "You must select one of Dog, Cat, or Monkey

string Conjoin(string[] items)
{
  if (items.Length == 1) return items[0];
  if (items.Length == 2) return string.Format("{0} or {1}", items[0], items[1]);
  if (items.Length >= 3)
  {
    string result = items[0];
    for (int i = 1; i < items.Length - 1; i++)
    {
      result = string.Format("{0}, {1}", result, items[i]);
    }
    result = string.Format("{0}, or {1}", result, items[items.Length - 1]);
    return result;
  }
  return "";
}
like image 707
Nathan Schubkegel Avatar asked Dec 28 '25 09:12

Nathan Schubkegel


1 Answers

If you have a low max size on the list it's easy enough to just localize the list formatters:

ListFormatter[1]   "{0}"
ListFormatter[2]   "{0} or {1}"
ListFormatter[3]   "{0}, {1}, or {2}"
etc...

To generalize it to arbitrary list sizes, a method I have used in similar situations is to have individual formatters for list sizes with irregular formatters, and then a regular formatter for everything else. That formatter could be split into three sections, a prefix, suffix, and middle repeating section. So:

ListFormatter[1]      "{0}"
ListFormatter[2]      "{0} or {1}"
ListFormatterNStart   "{0}, "
ListFormatterNMid     "{{0}}, "
ListFormatterNEnd     "or {{0}}"

For English the Prefix and Mid are the same but maybe in other languages it won't be. Note the double bracket {{0}} parameters, which allow you to format a formatter.

In usage you'd do something like this, where N is the list size (psuedo-code)

if List[N] exists
    formatter = ListFormatter[N]
else
    formatter = ListFormatterNStart
    for i = 1 to N-2
        formatter += String.Format(ListFormatterNMid,i)
    formatter += String.Format(ListFormatterNEnd, N-1)
like image 55
smead Avatar answered Dec 30 '25 23:12

smead



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!