Understanding locale & culture "display" names

Between Microsoft.Net's CultureInfo and the Window's NLS GetLocaleInfoEx() APIs locales/cultures have several names intended for human display.  Note that these names are intended for human use, for machine readable names the "en-US" type name should be used.

Basically we have 3 localizations of 3 types of names.  We have the "language" name, the "region" name, and the "display" name.  Each name can be available in one of 3 forms: the "english" name, the "native" name, and the "localized" name.  Note that the localized name isn't always available, in which case one of the other forms is used.

Here's a list of the potential names you'd see (assuming your User Interface language is set to French and the French resources are available)

Display Name

Language Name

Region Name

English Name

German (Switzerland)

German

Switzerland

Native Name

Deutsch (Schweiz)

Deutsch

Schweiz

Localized Name (if UI language is French)

Allemand (Suisse)

Allemand

Suisse

To get those values, these are the APIs you'd use. Top is the GetLocaleInfoEx() LCTYPE, bottom is the .Net class and property:

 

Display Name

Language Name

Region Name

English Name

n/a in NLS

CultureInfo.EnglishName

LOCALE_SENGLANGUAGE

CultureInfo.Parent.EnglishName

LOCALE_SENGCOUNTRY

RegionInfo.EnglishName

Native Name

n/a in NLS

CultureInfo.NativeName

LOCALE_SNATIVELANGNAME CultureInfo.Parent.NativeName

LOCALE_SNATIVECTRYNAME

RegionInfo.NativeName

Localized Name

LOCALE_SLANGUAGE

CultureInfo.DisplayName

LOCALE_SLANGDISPLAYNAME

CultureInfo.Parent.DisplayName

LOCALE_SCOUNTRY RegionInfo.DisplayName

Notice that .Net doesn't directly have the concept of a Language Name, but generally the Neutral culture that is the parent of a specific culture is named after the language (since it is region neutral), so we can use that.

 

Also in Windows the DisplayName (LOCALE_SLANGUAGE) is intended for display, so English and Native versions are not normally available.  The one exception is that for a custom locale the resources will not be available, so in that case the system will use the native name provided by the custom locale, or the english name if the UI language is English.

 

Sample C# code retrieving these names in .Net follows: 

 using System;
using System.Globalization;
using System.IO;

public class Sample
{
    public static void Main()
    {
        StreamWriter writer = new StreamWriter("out.txt");

        foreach (CultureInfo culture in CultureInfo.GetCultures(CultureTypes.AllCultures))
        {
            writer.WriteLine("{0} ({1})", culture.DisplayName, culture.Name);
            writer.WriteLine("Name: {0}", culture.Name);
            writer.WriteLine("Native Name: {0}", culture.NativeName);
            writer.WriteLine("English Name: {0}", culture.EnglishName);
            writer.WriteLine("Display Name: {0}", culture.DisplayName);

            if ((culture.CultureTypes & CultureTypes.SpecificCultures) != 0)
            {
                writer.WriteLine("Parent Name: {0}", culture.Parent.Name);
                writer.WriteLine("Parent Native Name: {0}", culture.Parent.NativeName);
                writer.WriteLine("Parent English Name: {0}", culture.Parent.EnglishName);
                writer.WriteLine("Parent Display Name: {0}", culture.Parent.DisplayName);
            }
            else
            {
                writer.WriteLine("Neutral Culture");
            }

            try
            {
                RegionInfo region = new RegionInfo(culture.Name);
                writer.WriteLine("Region Name: {0}", region.Name);
                writer.WriteLine("Region Native Name: {0}", region.NativeName);
                writer.WriteLine("Region English Name: {0}", region.EnglishName);
                writer.WriteLine("Region Display Name: {0}", region.DisplayName);
            }
            catch
            {
                // For geopolitical reasons we cannot create regions from some neutral culture names
                writer.WriteLine("Unable to create region for {0}", culture.Name);
            }

            writer.WriteLine();
        }

        writer.Flush();
    }
}