creating custom CultureInfo for country, language combination - c#

I am working on a .net 4.5 application that needs to be mult lingual supporting multi cultures etc.
The following is sample list of Countries/Languages
Russia / Russian
Belgium / French
Belgium / Dutch
For all the above, there is a CultureInfo object that can be created based upon the above culture names
ru-RU
fr-BE
nl-BE
When the user enters the site, I set Thread.CurrentThread.CurrentCulture and Thread.CurrentThread.CurrentUICulture to the culture created with the above names eg.
Thread.CurrentThread.CurrentCulture = new CultureInfo("nl-BE", false)
Thread.CurrentThread.CurrentUICulture = new CultureInfo("nl-BE", false)
All the above names are valid culture names.
No however I need to added another culture name, language of English in Russia. But the problem is the code en-RU is not valid so when I create new CultureInfo("en-RU", false) I get a CultureNotFoundException as en-RU is not valid.
With this culture, I want the formatting etc of Russia around numbers, dates etc, but I want the language on the site to be English. Is it possbile to create custom CultureInfo objects for invalid culture names with the behaviour of the country (Russia)?

Is it possbile to create custom CultureInfo objects for invalid culture name
Yes.
Make use of CultureAndRegionInfoBuilder to help create the custom CultureInfo. (NB. once you have code to create a culture, the settings to do this can be saved to XML and then loaded, eg. from a resource, which should need less code at runtime.)
An example project how to do that, plus downloadable code, can be found at CodeProject. An important note from the article is that, even though this class sits in the System.Globalization namespace, it is not available by default, quote:
We’ll start by referencing the assembly sysglobl.dll and add a using statement for the namespace System.Globalization.

You may have to mix and mix and match - have a culture object for English which you use for English text but a culture object of ru-Ru (Russian) for numeric formatting.
Or even better create a custom culture combining the two
Create custom culture in ASP.NET

You should use CultureInfo.InvariantCulture Property
The invariant culture is culture-insensitive; it is associated with
the English language but not with any country/region. You specify the
invariant culture by name by using an empty string ("") in the call to
a CultureInfo instantiation method. CultureInfo.InvariantCulture also
retrieves an instance of the invariant culture. It can be used in
almost any method in the System.Globalization namespace that requires
a culture. The objects returned by properties such as CompareInfo,
DateTimeFormat, and NumberFormat also reflect the string comparison
and formatting conventions of the invariant culture.
CultureInfo.InvariantCulture Property
This is other option Custom Global Application Culture

Related

DateTime format and neutral culture

According to documentation Formatting Date and Time for a Specific Culture
The DateTime structure provides methods that allow your applications to perform culture-sensitive operations on a DateTime type. An application can use the DateTimeFormatInfo class to format and display a DateTime type based on culture. For example, using DateTimeFormatInfo.ShortDatePattern, the date February 1, 2001 can be formatted as 2/1/2001 for the English (United States), "en-US", culture and 01/02/2001 for the English (United Kingdom), "en-GB", culture.
An DateTimeFormatInfo object can be created for a specific culture or for the invariant culture, but not for a neutral culture. A neutral culture does not provide enough information to display the correct date format. An exception is thrown if the application attempts to create a DateTimeFormatInfo object using a neutral culture.
But how come the following does not throw an exception? And where does it get information on how to format date, since specific culture was not specified?
Console.WriteLine(DateTime.Now.ToString("d", new CultureInfo("fr")));
Update:
You can create instances of specific culture or neutral culture,
for example new CultureInfo("fr-FR") or new CultureInfo("fr").
In DateTime.ToString method it says
The ToString(String) method returns the string representation of a date and time value in a specific format that uses the formatting conventions of the current culture; for more information, see CultureInfo.CurrentCulture.
And CultureInfo documentation says
The CultureInfo object that is returned by this property and its associated objects determine the default format for dates, times, numbers, currency values, the sorting order of text, casing conventions, and string comparisons.
Update 2
Yes, so the MSDN page referenced above is outdated and the framework behaviour has changed.
I have the following code
var culture = new CultureInfo("en");
Console.WriteLine(DateTime.Now.ToString("d", culture));
When I run this code targeting .NET 3.0 I get the following exception. But it works well on .NET 4.6.2.
An unhandled exception of type 'System.NotSupportedException' occurred in mscorlib.dll
Additional information: Culture 'en' is a neutral culture. It cannot be used in formatting and parsing and therefore cannot be set as the thread's current culture.
So, going back to my original question. When I use neutral culture, where does the information about DateTime format come from?
From the most recent version of the MSDN doc on DateTimeFormatInfo:
However, a neutral culture lacks culture-specific formatting information, because it is independent of a specific country/region. Instead of populating the DateTimeFormatInfo object with generic values, the .NET Framework returns a DateTimeFormatInfo object that reflects the formatting conventions of a specific culture that is a child of the neutral culture. For example, the DateTimeFormatInfo object for the neutral en culture reflects the formatting conventions of the en-US culture, and the DateTimeFormatInfo object for the fr culture reflects the formatting conventions of the fr-FR culture.
This is also described in the What's New in Globalization and Localization article for .NET 4:
Previous versions of the .NET Framework threw an exception if applications tried to access neutral culture properties such as DateTimeFormatInfo.FirstDayOfWeek. In the .NET Framework 4, neutral culture properties return values that reflect the specific culture that is most dominant for that neutral culture. For example, the French neutral locale retrieves the values of most of its properties from French (France). The FirstDayOfWeek property returns DayOfWeek.Monday, which reflects the value of that property in the French (France) culture.

Culture is not supported. Parameter name: name US is an invalid culture identifier

I tried to use a ISO-3166 two letter country code to create my C# culture info object to format my datetime objects according to the locale.
If I try:
var cultureInfo = new CultureInfo("FR");
it works fine, if I try:
var cultureInfo = new CultureInfo("US");
it throws an exception:
Culture is not supported. Parameter name: name US is an invalid
culture identifier.
The funny thing is that "US" is a valid ISO-3166 country code.
From CultureInfo(string) constructor documentation;
For a list of predefined culture names, see the National Language
Support (NLS) API Reference
Also from CultureInfo.TwoLetterISOLanguageName Property
For example, the two-letter abbreviation for English is en.
There is no US defined but there is en (if you really have to use two letter name) which you can use it. All of them defined in ISO 639-1 standard.
var cultureInfo = new CultureInfo("en");
Because US is not a valid culture name whereas FR is. CultureInfo's constructor doesn't accepts country code as parameter. It expects the "Culture Name".
Refer the table in this msdn page for valid culture names.
Argument of CultureInfo constructor is not a ISO-3166 code, but predefined culture name
From MSDN article concerning CultureInfo:
For a list of predefined culture names, see the National Language
Support (NLS) API Reference at the Go Global Developer Center.
In the reference mentioned there is no us culture, but there is en-US, so you have to use ut.

CultureInfo.InvariantCulture in .ToString()

I am currently fixing FxCop issues so I encountered issue where I have to provide cultureinfo when converting a string using ToString() .
Currently in my code nothing we are passing as IFormatProvider so I have read some msdn articles saying that when you don't pass any value for cultureinfo it will assign a default value and when you specify CultureInfo as InvariantCulture it will be independent of any culture.
My question is, "Are default and CultureInfo.InvariantCulture one and the same? Can I replace all my code from default to InvariantCulture?"
Ex :
int st = 123;
String s = st.ToString(123); // this will be taken as default
String s = st.ToString(123, CultureInfo.InvariantCulture); // culture is specified externally
Are the second and third lines equivalent?
Is default and CultureInfo.InvariantCulture are one and the same?
No, absolutely not. The default culture depends (initially) on the operating system settings. The invariant culture is meant to be a "neutral" culture.
Your example of 123 isn't a great one, because most (all?) cultures will represent integers the same way - at least until you get into formats with grouping separators etc. (I don't think .NET supports non-Arabic numerals when formatting integers.)
Compare that with formatting a decimal value, for example:
decimal x = 123.45m;
Console.WriteLine(x.ToString()); // Might be 123,45
Console.WriteLine(x.ToString(CultureInfo.InvariantCulture)); // Always 123.45
If you run the above code in (say) France, the default culture will be French, which uses a comma as a decimal separator - so it will print out "123,45".
The rule of thumb to remember is that the invariant culture is suitable for machine-to-machine communications (e.g. formatting values in JSON or XML) whereas other cultures are more suitable for displaying information directly to users.
Although the default culture is originally based on the operating system settings, it can be changed using Thread.CurrentCulture and Thread.CurrentUICulture; the latter is used for looking up translated resources, whereas the former is used for formatting decisions like the above. You can set these properties on any thread, but typically you'd use Thread.CurrentThread.CurrentCulture = ...
No, they are not the same.
The first will take the regional settings from the computer or the culture settings from the application thread running.
The second one will take the English language, according to MSDN:
The invariant culture is culture-insensitive; it is associated with the English language but not with any country/region.

CultureInfo.InvariantCulture in plain english

I know that culture rules for dates/numbers is enough for an entire book, I think I have a simple question though..
Does using InvariantCulture basically mean that you explicitly define what culture the value (date/number/whatever) will be inputted/displayed as? And it overrides any other culture setting (such as the user agent's setting)?
If an app is built for an audience of one and only one culture, would it make sense to use InvariantCulture and define how you want values inputted/displayed each time?
Does using InvariantCulture basically mean that you explicitly define what culture the value (date/number/whatever) will be inputted/displayed as?
No. It's just a culture which is a bit like US English, except for a few things like currency sign. It's usually used to format/consume text which is to be understood or was produced by another computer rather than a human.
If an app is built for an audience of one and only one culture, would it make sense to use InvariantCulture and define how you want values inputted/displayed each time?
No, you would use the relevant CultureInfo for that culture. You could also explicitly define the format for dates etc, but that's an orthogonal concern. It may well be best to use one of the predefined standard formats for that culture, but if none of those meet your needs you can always be explicit.
InvariantCulture is Independent of any culture or any factor.
For example if you're using new CultureInfo("en-US") it will get you US English Culture(Which may not be actual US English Culture because OS gives you option to change these setting in Control Panel) it will return the modified version of Culture of "en-US" if any custom formatting applied to it.
In other words InvariantCulture will always gives you a Culture which can never be changed across Systems.
Let's assume you want to serialize some value(say double) and pass to another application or some other thread which is running in different culture leads to serious problems.
Consider the following code
Thread.CurrentThread.CurrentCulture = new CultureInfo("fr");
double source = 455.62d;
string serialized = source.ToString();//455,62 since `, is the decimal seperator` in "fr"
Thread t = new Thread((x) =>
{
double deserialized = double.Parse(((string)x));
Console.WriteLine(string.Format("Deserialized value is {0}", deserialized));//outputs 45562
});
t.CurrentCulture = new CultureInfo("en-US");
t.Start(serialized);
numbers matters more right? consider this string denotes AccountBalance?
Hope this helps
With specific regard to DateTime, the best advice I can give is to use CultureInfo.InvariantCulture for ParseExact and ToString when you have an exact format in mind. (You can also use it with Parse if you happen to know that your input format matches the invariant culture's formats, but I typically avoid this.)
Don't use the invariant culture when interacting with a user.
Keep in mind that the culture contains several items, including the ordering of day/month/year parts, the date and time part separator characters, the character encoding, and the language-specific names of the days of the week, months of the year, and abbreviations including am/pm.
Some examples of when you should use the invariant culture:
Files on disk, especially text files of a predefined format
External APIs, especially JSON or XML
Unit tests, unless you are specifically testing culture issues
Some examples of when you should use a specific culture such as en-US:
User Interface
Reports

Formatting Currency to ALWAYS use USD regardless of users culture

This should be simple but I cannot find the answer anywhere.
On our asp.net MVC site, we show currency values and I need these currency values to Always be in USD regardless of the users culture settings.
If I use string.format("{0:C}",value) then it shows the value in what ever culture the use has set.
This is incorrect for us as $1000.00 is not the same thing as 1000.00 euro
I still need to use the language side of this, meaning if they are in France I want to use the French localization resource, so I don't want to completely disregard their culture settings, but how can I make sure the currency is always shown in USD?
Explicitly pass culture to the Format call:
string.Format(new CultureInfo("en-US"), "{0:C}",value)
If you have to mix it with other languages - save result of formatting currency value and insert into other places as string.
Side note: using "en-US" (or any other hard-coded culture) will lead to potentially mismatched representation of negative values i.e. some cultures use -100, while other (100) for negative amounts.
You would have to specify CurrentCulture to be en-US and leave CurrentUICulture as is.
I usually do this in global.asax.cs in the Application_BeginRequest event
System.Threading.Thread.CurrentThread.CurrentCulture =
new System.Globalization.CultureInfo("en-US", false);
It is possible to specify the culture in web.config file but that has one drawback - it takes into account the customized regional settings of the server (if the administrator changed the currency or date format on the server for the en-US culture, it would get picked up this way) - so you can't ever be sure that the application will behave exactly the same as when you created/tested it.

Categories