Home > Articles > Programming > Windows Programming

This chapter is from the book

Supplemental Custom Cultures

A supplemental culture is a culture that is new to the .NET Framework and the operating system. A number of examples of supplemental custom cultures are presented in this chapter. We start with the greatest challenge: to create a supplemental custom culture from scratch without any existing CultureInfo or RegionInfo to draw from. For this example, we create a culture for Bengali (also called Bangla) in Bangladesh. The second example, which creates a supplemental custom culture from scratch, is a pseudo translation custom culture.

Bengali (Bangladesh) Custom Culture

At the time of writing, the Bengali (Bangladesh) culture, which we label as "bn-BD", is not known to the .NET Framework or any version of Windows. Windows Vista, however, includes the culture-neutral Bengali culture, but this is available only in Windows Vista and is not a specific culture. However, as has already been mentioned, it is entirely possible that this situation won't last and the "bn-BD" culture will arrive in some version of Windows in the future. Despite this, these future events do not invalidate this example. Consider that at such a time you will have a choice between forcing all of your users to upgrade to the new version of Windows (not necessarily possible) and using a custom culture that will work on all versions of Windows. The latter choice is the more practical choice. The same caveats regarding your culture-naming convention apply in this scenario, so although you might want to "personalize" your bn-BD culture name (e.g., "bn-BD-Acme"), I use "bn-BD" in this example for simplicity. Finally, if you run this example in any version of Windows before Windows Vista, you should install support for complex scripts to be able to see the Bengali script.

The following code creates the Bengali (Bangladesh) custom culture:

chapter 09 Program 01

The bn-BD parent is the invariant culture. You might want to consider creating this culture in two steps, first creating a neutral Bengali culture and then creating a specific Bengali (Bangladesh) culture. There are a few values for which you should seek out a standard:

The CultureAndRegionInfoBuilder.NumberFormatInfo is assigned from the CreateBangladeshNumberFormatInfo method:

chapter 09 Program 02

The CultureAndRegionInfoBuilder.DateTimeFormatInfo is assigned from the CreateBangladeshDateTimeFormatInfo method:

chapter 09 Program 03

The Bengali (Bangladesh) culture can now be used like any other .NET Framework culture.

Pseudo Translation Custom Culture

The Pseudo Translation custom culture is another custom culture that is created without drawing upon any existing culture or region information. The purpose of this custom culture is to provide support for the pseudo translation described in Chapter 9, in which developers and testers can use a culture other than the developer's own culture, can test that the application is globalized and localized, and still can be able to use the application without having to learn another language. The complete code for the pseudo translation custom culture is not shown here because it is identical to the previous example, except that the values are different.

The pseudo translation custom culture values themselves are important only because they must not be the same as those of an existing culture. This allows developers and testers to observe that globalization and localization are occurring. This is a little trickier than it might at first seem. The first problem is that, in choosing suitable language and region codes for the pseudo translation culture, you should avoid existing codes. You might think of using "ps-PS" (for Pseudo (Pseudo)), but the "ps" language code and "PS" region code have already been taken. Refer to the links in the Bengali (Bangladesh) custom culture to avoid choosing identifiers that are already taken. I have chosen "pd-PD" because these are still free at the time of writing. However, to ensure future safety of your choice, the safest solution is to choose a code that does not conform to the ISO specifications (e.g., "p1-P1" uses a number, which is not acceptable in these specifications). Using this approach, you can be sure that if it doesn't conform to the specification, the code will never be used by anyone else.

Many of the pseudo culture's values are easy to invent:

builder.CultureEnglishName = "PseudoLanguage (PseudoRegion)";
builder.CultureNativeName =
   "[!!! PŠĕICON TYPEICON TYPEŏICON TYPEäICON TYPEICON TYPEICON TYPEäICON TYPEĕ  (PŠĕICON TYPEICON TYPEŏICON TYPEĕICON TYPEǐŏICON TYPE) !!!]";
builder.ThreeLetterISOLanguageName = "psd";
builder.ThreeLetterWindowsLanguageName = "psd";
builder.TwoLetterISOLanguageName = "pd";

builder.RegionEnglishName = "PseudoRegion";
builder.RegionNativeName = "[!!! PŠĕICON TYPEICON TYPEŏICON TYPEĕICON TYPEǐŏICON TYPE !!!]";
builder.ThreeLetterISORegionName = "PSD";
builder.ThreeLetterWindowsRegionName = "PSD";
builder.TwoLetterISORegionName = "PD";

builder.IetfLanguageTag = "pd-PD";

However, you need to find the right balance: You must use values that are sufficiently different from English, to be clear that the application is not using the default culture, yet you must use values that are sufficiently understandable, to make the application still usable. Consider the following two currency strings, which were converted to a string using 123456789.123456.ToString("C"):

$123,456,789.12
1'2'3'4'5'6'7'8'9@1235 ~

The first uses the "en-US" culture, and the second uses the "pd-PD" culture. The second clearly shows that the application is globalized, but is it still recognizable as currency? The decimal separator is "@" instead of "."; the group separator is "'" instead of ","; the group size is 1 instead of 3; the number of decimals is 4 instead of 2; the currency symbol is "~" instead of "$"; and the currency symbol is placed to the right instead of to the left. In terms of testing globalization, this scores a 10, but is the application still usable?

I have also taken the attitude that the day and month names used in the DateTimeFormatInfo should not be pseudo-ized. For example:

dateTimeFormatInfo.DayNames = new string[] {
    "*Sunday*", "*Monday*", "*Tuesday*", "*Wednesday*",
    "*Thursday*", "*Friday*", "*Saturday*" };

(The names are delimited with asterisks, however.) You might have expected the names to have been "pseudo-ized," like this:

dateTimeFormatInfo.DayNames = new string[] {
    "ŠICON TYPEICON TYPEICON TYPEäICON TYPE", "MŏICON TYPEICON TYPEäICON TYPE", "ICON TYPEICON TYPEĕšICON TYPEäICON TYPE", "ICON TYPEĕICON TYPEICON TYPEĕšICON TYPEäICON TYPE",
    "ICON TYPEICON TYPEICON TYPEICON TYPEšICON TYPEäICON TYPE", "FICON TYPEǐICON TYPEäICON TYPE", "ŠäICON TYPEICON TYPEICON TYPEICON TYPEäICON TYPE" };

The reason behind this is that I want to be able to see clearly that day and month names are taken from the appropriate DateTimeFormatInfo object instead of from a resource assembly. In other words, if the user is presented with "ŠICON TYPEICON TYPEICON TYPEäICON TYPE", you can be sure that the application has been localized, but you don't know how it has been localized. The text could have come just as easily from a call to Resource Manager.GetString("Sunday"), and there is no way to make this distinction visually if the text in the DateTimeFormatInfo is the same as a pseudo-ized resource.

With the pseudo translation culture in place, you might want to update the PseudoTranslation class introduced in Chapter 9 to use the new culture instead of the previously hijacked culture:

public class PseudoTranslation
{
    private static CultureInfo cultureInfo =
        new CultureInfo("pd-PD");
    public static CultureInfo CultureInfo
    {
        get {return cultureInfo;}
        set {cultureInfo = value;}
    }
}
  • + Share This
  • 🔖 Save To Your Account