TOC

This article is currently in the process of being translated into Spanish (~24% done).

Working with Culture & Regions:

La clase CultureInfo

En el último par de artículos hemos hablado acerca de lo útil que es la clase CultureInfo cuando necesitas un control total de cómo se muestran los números y fechas en tu aplicación. También se ha hablado cómo se puede verificar y modificar qué cultura está usando tu aplicación. Teniendo todo eso en cuenta, vamos a profundizar en la clase CultureInfo para ver cómo aprovecharla al máximo.

Recuerda que la clase CultureInfo es parte del espacio de nombres System.Globalization, por lo que asegúrate de importarlo cada vez que vayas a usarlo:

using System.Globalization;

Culturas neutras y específicas

En los ejemplos anteriores de este capítulo, solo hemos utilizado culturas específicas,es decir una cultura que especifica tanto un idioma como un país / región. Un ejemplo de esto es la cultura en-US, Que establece claramente que el idioma deseado debe ser el inglés y la región es EE. UU. Una alternativa a eso es la cultura en-GB, que es el mismo idioma (inglés) pero con Gran Bretaña como la región en lugar de los EE. UU.

Habrá ocasiones en que estas diferencias son importantes, en cuyo caso debe usar estas versiones específicas de la región de la clase CultureInfo. Por otro lado, también habrá situaciones en las que el inglés es solo un idioma y no desea vincular este idioma a un país o región específicos. Para esto, el framework .NET define las llamadas culturas neutras, que solo especifican un lenguaje. De hecho, tanto en-US como en-GB heredan de una cultura neutral (¡lo cual tiene mucho sentido, ya que comparten el mismo idioma!) y puede acceder a él desde la propiedad Parent. Veámoslo con un ejemplo:

CultureInfo enGb = new CultureInfo("en-GB");
CultureInfo enUs = new CultureInfo("en-US");
Console.WriteLine(enGb.DisplayName);
Console.WriteLine(enUs.DisplayName);
Console.WriteLine(enGb.Parent.DisplayName);
Console.WriteLine(enUs.Parent.DisplayName);

No es un ejemplo muy útil, pero debería darle una mejor idea de la estructura interna de la clase CultureInfo. La salida debería verse así:

English (United Kingdom)
English (United States)
English
English

Getting the right CultureInfo

Con los ejemplos anteriores, ha visto que podemos obtener la clase CultureInfo deseada al pasar el identificador de idioma-país / región al constructor de la clase. Pero como podría estar buscando una cultura neutral, como se describió anteriormente, también podría pasar un identificador de idioma:

CultureInfo en = new CultureInfo("en");

The .NET framework will then return an English, region-neutral CultureInfo instance for you. For a full list of possible language and/or language-country/region identifiers, I suggest you check out the MSDN documentation.

Another way of identifying a specific culture is with the so-called LCID (LoCale ID). You will find it as a property on existing CultureInfo instances, but if you know the ID, you can also use it to instantiate a CultureInfo object. For instance, the LCID for en-US is 1033:

CultureInfo enUs = new CultureInfo(1033);

However, in most situations, it's much easier to use the language-country/region specifier, as previously demonstrated.

Getting a list of available Cultures

We can now get a specific culture and use it for various purposes, but perhaps you need a list of the available cultures, e.g. to allow the user to select a language and/or country/region. Fortunately, the .NET framework makes that easy for us as well - here's an example:

CultureInfo[] specificCultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures);
foreach (CultureInfo ci in specificCultures)
    Console.WriteLine(ci.DisplayName);
Console.WriteLine("Total: " + specificCultures.Length);

As you can tell from the first line of code, I use the GetCultures static method on the CultureInfo class to get a list of cultures. It requires the CultureTypes parameter, which specifies which kind of cultures you're looking for. In this case, I have asked for the specific cultures, which, as we talked about previously, are the cultures which are tied to both a language and a country/region. That's quite a long list, by the way - on this computer, I get a total of 563 available cultures!

But perhaps you're more interested in the neutral cultures? That would, for instance, make perfect sense if you were building a list of available languages, while not caring which country or region they were related to. Doing it is as simple as changing the CultureTypes parameter:

CultureInfo[] neutralCultures = CultureInfo.GetCultures(CultureTypes.NeutralCultures);
foreach (CultureInfo ci in neutralCultures)
    Console.WriteLine(ci.DisplayName);
Console.WriteLine("Total: " + neutralCultures.Length);

By doing so, you will also see that there not quite as many neutral cultures as there are specific cultures - on my computer/.NET framework version, the result is a total of 280 neutral cultures.

Important properties & methods of CultureInfo

Once you have an instance of the CultureInfo class, you immediately get access to a very wide range of usable properties and methods. These members can help you accomplish many useful things in regards to culture - let's have a look at some of them!

DateTimeFormat

With the DateTimeFormat property, you get access to information about how date and time should be formatted, as well as a lot of useful information about the calendar for the given culture. A nice example of this is the FirstDayOfWeek and CalendarWeekRule properties - they can tell you on which day a week starts (usually Sunday or Monday) and how the first calendar week of the year is decided (e.g. just the first day or the first full week):

CultureInfo enUs = new CultureInfo("en-US");
Console.WriteLine("First day of the: " + enUs.DateTimeFormat.FirstDayOfWeek.ToString());
Console.WriteLine("First calendar week starts with: " + enUs.DateTimeFormat.CalendarWeekRule.ToString());

Try changing the CultureInfo instance to your own culture or another culture you know, to see how these properties vary!

Another cool thing is that you can get information about the month and day names for the specific culture using properties like MonthNames and methods like GetMonthName(). Here's a quick example:

CultureInfo enUs = new CultureInfo("en-US");

foreach (string monthName in enUs.DateTimeFormat.MonthNames)
    Console.WriteLine(monthName);
Console.WriteLine("Current month: " + enUs.DateTimeFormat.GetMonthName(DateTime.Now.Month));

And the exact same thing can be accomplished for days, using the DayNames property and the GetDayName() method:

CultureInfo enUs = new CultureInfo("en-US");

foreach (string dayName in enUs.DateTimeFormat.DayNames)
    Console.WriteLine(dayName);
Console.WriteLine("Today is: " + enUs.DateTimeFormat.GetDayName(DateTime.Now.DayOfWeek));

There are many more useful properties and methods on the DateTimeFormat property, e.g. DateSeparator, YearMonthPattern and so on. Have a look for your self - there might very well be a solution to your date/time related problem hidden in there: DateTimeFormatInfo documentation.

NumberFormat

Just like the DateTimeFormat has information about dates, you can access information on how the specific culture treats numbers from the NumberFormat property. This information is used each time you ask for a visual representation of a number, e.g. when converting it to a string and writing it to the console, but you can also access the information yourself, by using the properties and methods on the NumberFormat property - here's an example:

CultureInfo enUs = new CultureInfo("en-US");  
Console.WriteLine(enUs.DisplayName + ":");  
Console.WriteLine("NumberGroupSeparator: " + enUs.NumberFormat.NumberGroupSeparator);  
Console.WriteLine("NumberDecimalSeparator: " + enUs.NumberFormat.NumberDecimalSeparator);  

CultureInfo deDe = new CultureInfo("de-DE");  
Console.WriteLine(deDe.DisplayName + ":");  
Console.WriteLine("NumberGroupSeparator: " + deDe.NumberFormat.NumberGroupSeparator);  
Console.WriteLine("NumberDecimalSeparator: " + deDe.NumberFormat.NumberDecimalSeparator);

We use the NumberGroupSeparator and the NumberDecimalSeparator properties to get information about how a number is displayed (e.g. 1,000.00 or 1.000,00) for the English and German cultures. If you have a look, you will find matching properties for currencies (CurrencyGroupSeparator and CurrencyDecimalSeparator) as well as percentages (PercentGroupSeparator and PercentDecimalSeparator).

Speaking of currency, the NumberFormat property can also tell you which symbol a given culture uses to display a monetary amount - simply use the CurrencySymbol property:

CultureInfo enUs = new CultureInfo("en-US");
Console.WriteLine(enUs.DisplayName + " - currency symbol: " + enUs.NumberFormat.CurrencySymbol);
CultureInfo deDe = new CultureInfo("de-DE");
Console.WriteLine(deDe.DisplayName + " - currency symbol: " + deDe.NumberFormat.CurrencySymbol);
CultureInfo ruRu = new CultureInfo("ru-RU");
Console.WriteLine(ruRu.DisplayName + " - currency symbol: " + ruRu.NumberFormat.CurrencySymbol);

All these properties are nice to know about, but in most situations, you won't have to deal with them, since C# will silently use the information to format numbers, percentages and currencies for you, as long as you specify the right format string when you turn the number into a string.

Names & identifiers

Lastly, let's have a look at the properties which represents the CultureInfo instance. We have already used some of them, e.g. Name and DisplayName, but how do they actually work? First, here's a list of available properties used to identify a CultureInfo:

  • Name will identify a CultureInfo in the languagecode-country/region-code format, e.g. "en-US" for English in the US, en-GB for English in Great Britain and so on. If no country/region is specified, only the first part will be returned, e.g. "en" for English.
  • TwoLetterISOLanguageName will do pretty much the same as Name, but it will only return the language code, no matter if a country/region has been specified or not. For instance, "en" will be returned for both "en-US" and "en-GB". The letters returned are specified in the ISO 639-1 standard.
  • ThreeLetterISOLanguageName works much like TwoLetterISOLanguageName, but it returns three letters instead of two, as specified by the ISO 639-2 standard.
  • EnglishName will return the name of the language (in English). If a country/region has been specified, this will be appended to the result, within a set of parentheses.
  • NativeName will return the name of the language (in the language specified by the CultureInfo instance). If a country/region has been specified, this will be appended to the result, within a set of parentheses.

Summary

As you can gather from the length of this article, dealing with culture in general is not a simple task. Fortunately for us, the .NET framework makes it a whole lot easier with the CultureInfo class. It's used silently all across your application when formatting numbers and dates, but it's good for you to know how it works so that you can modify the behavior if needed. Hopefully this article has taught you most of what you need to know about the CultureInfo class.

This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!