views:

775

answers:

6

Hi all,

Can I with ASP.NET Resources/Localization translate strings to depend on one or other (the English grammar) in a easy way, like I pass number 1 in my translate, it return "You have one car" or with 0, 2 and higher, "You have %n cars"?

Or I'm forced to have logic in my view to see if it's singular or plural?

A: 

AFAIK, there's nothing built-in to the framework to do it..

Here's an example of one generalized solution for the problem:

http://dotnetperls.com/plural

Troy Howard
That link doesn't work.
J W
Looks like the site changed the url scheme.. score one for REST.
Troy Howard
A: 

There is nothing built in, we ended up coding something like this: Another solution can be:

use place holders like {CAR} in the resource file strings Maintain separate resource entries for singular and plural words for "car" : CAR_SINGULAR car
CAR_PLURAL cars

Develop a class with this logic:

class MyResource
 {

    private List<string> literals = new List<string>();
    public MyResource() { literals.Add("{CAR}") }
    public static string GetLocalizedString(string key,bool isPlural)
    {
       string val = rm.GetString(key);
       if(isPlural)
       {
          val = ReplaceLiteralWithPlural(val);
       }
       else
       {
          val = ReplaceLiteralWithSingular(val);   
       }     
    }  
}

string ReplaceLiteralWithPlural(string val)
{
   StringBuilder text = new StringBuilder(val)
   foreach(string literal in literals)
   {
      text = text.Replace(literal,GetPluralKey(literal));
   }
}

string GetPluralKey(string literal)
{
  return literal + "_PLURAL";
}
Ngm
+1  A: 

The logic needn't be in your view, but it's certainly not in the resource model the DotNet framework. Yours is a simple enough case that you can probably get away with creating a simple format string for singular, and one for plural. "You have 1 car."/"You have {0} cars." You then need to write a method that discriminates between the plural and singular case.

To the best of my knowledge, there isn't a language that requires something more complicated than singular/plural, but there may be some where expressing the equivalent of "you have 0 cars" doesn't sound right. There are also a number of languages where there's no distinction between singular and plural, but this just requires a little duplication in the resource strings. (edit to add: gender and sometimes endings change depending on number of units in many languages, but this should be fine as long as you distinguish between singular and plural sentences, rather than just words).

Microsoft mostly gave up on semantically clever localization because it's hard to generalize even something like pluralization to 30+ languages. This is why you see such boring presentation of numeric quantities in most applications that are translated to many languages, along the lines of "Cars: {0}". That sounds lame, but surprisingly, the last time I checked, usability studies didn't actually favor the verbose natural language presentation in most cases.

JasonTrue
+10  A: 

JasonTrue wrote:

To the best of my knowledge, there isn't a language 
that requires something more complicated than singular/plural

Such languages do exist. In my native Polish, for example, there are three forms: for 1, for 2-4 and for zero and numbers greater than 4. Then after you reach 20, the forms for 21, 22-24 and 25+ are again different (same grammatical forms as for numerals 0-9). And yes, "you have 0 things" sounds awkward, because you're not likely to see that used in real life.

As a localization specialist, here's what I would recommend:

If possible, use forms which put the numeral at the end:

a: Number of cars: %d

This means the form of the noun "car" does not depend on the numeral, and 0 is as natural as any other number.

If the above is not acceptable, at least always make a complete sentence a translatable resource. That is, do use

b: You have 1 car.    
c: You have %d cars.

But never split such units into smaller fragments such as

d: You have
e: car(s)

(Then somewhere else you have a non-localizable resource sch as "%s %d %s")

The difference is that while I cannot translate (c) directly, since the form of the noun will change, I can see the problem and I can change the sentence to form (a) in translation.

On the other hand, when I am faced with (d) and (e) fragments, there is no way to make sure the resulting sentence will be grammatical. Again: using fragments guarantees that in some languages the translation will be anything from grammatically awkward to completely broken.

This applies across the board, not just to numerals. For example, a fragment such as "%s was deleted" is also untranslatable, since the form of the verb will depend on the gender of the noun, which is unavailable here. The best I can do for Polish is the equivalent of "Deleted: %s", but I can only do it as long as the %s placeholder is included in the translatable resource. If all I have is "was deleted" with no clue to the referent noun, I can only startle my dog by cursing aloud and in the end I still have to produce garbage grammar.

moodforaday
Excellent answer! Bonus marks for humour!
Samuel Jack
Great suggestions and +1 for educating me on multiple plural forms.
Stimul8d
+1  A: 

moodforaday wrote:

This applies across the board, not just to numerals. For example, a fragment such as "%s was deleted" is also untranslatable, since the form of the verb will depend on the gender of the noun, which is unavailable here. The best I can do for Polish is the equivalent of "Deleted: %s", but I can only do it as long as the %s placeholder is included in the translatable resource. If all I have is "was deleted" with no clue to the referent noun, I can only startle my dog by cursing aloud and in the end I still have to produce garbage grammar.

The point I would like to make here, is never include a noun as a parameter. Many European languages modify the noun based on its gender, and in the case of German, whether it is the subject, object, or indirect object. Just use separate messages. Instead of, "%s was deleted.", use a separate translation string for each type: "The transaction was deleted." "The user was deleted." etc.

This way, each string can be translated properly.

The solution to handle plural forms in different languages can be found here: http://www.gnu.org/software/gettext/manual/html%5Fnode/Plural-forms.html

While you can't use the above software in a commercial application (it's covered under GPL), you can use the same concepts. Their plural form expressions fit perfectly with lambda expressions in .NET. There are a limited number of plural form expressions that cover a large number of languages. You can map a particular language to a lambda expression that calculates which plural form to use based on the language. Then, look up the appropriate plural form in a .NET resx file.

A: 

anvilis wrote:

The point I would like to make here, is never include a noun as a parameter. Many European languages modify the noun based on its gender, and in the case of German, whether it is the subject, object, or indirect object. Just use separate messages. Instead of, "%s was deleted.", use a separate translation string for each type: "The transaction was deleted." "The user was deleted." etc.

I was always curious what is the proper way to make things similar to above, but that include string that couldn't be included as part of translation, like "%s said:" or "%s wrote:" (which can be seen nowadays on facebook). In this case, %s is most likely user name, and verb depends on user's gender, for example.

(sorry for writing this as an answer instead of using comment - I can't find comment link)

mr.b