locked
CurrentCulture and CurrentCultureUI RRS feed

  • Question

  • User630885590 posted

    I would like to know the difference between CurrentThread.CurrentCulture and CurrentThread.CurrentCultureUI. I would like to know what the difference is where each of these effect the .NET runtime in relation to ASP.NET. I googled and couldn't find an article that really describes the difference. Could just be a brain dead day though.

    Thursday, September 29, 2005 9:07 AM

Answers

  • User1424575140 posted
    http://msdn.microsoft.com/en-us/library/441487wx

    The CultureInfo.CurrentUICulture property is a per-thread setting that returns the current user interface culture. This property is used by the ResourceManager class to look up culture-specific resources at run time. You can use a neutral or specific culture, or the InvariantCulture to set the CurrentUICulture property. You can use the Thread.CurrentThread property to set CurrentCulture. For more information, see the examples provided later in this topic.

    http://msdn.microsoft.com/en-us/library/se513yha(en-US,VS.80).aspx

    The CultureInfo.CurrentCulture property is a per-thread setting that determines the default formats for dates, times, currency, and numbers, the sorting order of text, string comparisons, and casing. The CurrentCulture property is not a language setting. It contains only data related to the standard settings for a geographical region. Therefore, the CurrentCulture property can only be set to a specific culture or to the InvariantCulture. You can use the Thread.CurrentThread property to set CurrentCulture. For more information, see the examples provided later in this topic.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, October 7, 2005 2:12 PM
  • User1183903743 posted
    You are correct. The msdn docs make a mess of the explanation.

    First of all the CultureInfo class is in System.Globalization. As such, it has NOTHING to do with threads at all and that is where the confusion comes from. It can hold info about (and BOTH) culture specific and neutral and even invariant culture and even non-existing cultures if you set up some custom ones.

    On the other hand BOTH CurrentCulture and CurrentUICulture are props of the CurrentThread and that is NOT what differentiates them. They are both props of type System.Globalization.CultureInfo.

    Now all this bucket of info has to be sorted out because in some situations only a subset of these data are needed. For that there is an enumeration called CultureTypes.

    However let's keep it simple and look at two such subsets Neutral and Specific cultures. Without using the enumeration we could do a rule of thumb that 2-chars("en", "fr", "es") are neutral and 5-chars ("en-US","es-ES","pt-BR") are specific. There are some exceptions where there are extra chars but they are very obscure and you should look at them if they affect you.

    Contrary to intuition, the name CurrentCulture has nothing to do with language, per se, but with formatting of dates and currency etc. For this reason it must be specific. A more appropriate self-descriptive name like CurrentFormattingCulture would have prevented millions of questions but they didn't let me make that decision.

    On the other hand the property of the thread that has to do with language/translations etc is CurrentUICulture. This is the one the ResourceManager object takes to look up resources by culture(either neutral or specific) . Again, a wrong impression is conveyed by the UI which, at least to me, should imply exactly formatting. However the functionality is exactly the opposite. It has to do with multi-versioning of resources by culture. A more appropriate self-explanatory and less counter-intuitive name would have been CurrentResourcingCulture but, again, it wasn't up to me.

    Asp.net controls with built-in localization cannot use neutral cultures because there could be a formatting difference in "pt-BR" and "pt-PT" which just "pt" couldn't account for. There may be a different religion and different calendar etc. Classic example is the 12h date-time formatting that only en-US and en-PH use. So such controls need the CurrentCulture set in the thread with 5-char SPECIFIC VALUE for culture name when you instantiate a CultureInfo object or auto detect it from the client browser.

    For this reason there is a bool method IsNeutralCulture which can help you prevent exceptions(instead of primitively parsing the number of chars, which again includes most but not all scenarios, and not all constructor overloads - some take an LCID instead of culture name).

    //never throws but your user may never get the UI culture changed either, and never know why. 
    CultureInfo ci=new CultureInfo(SomeDynamicCultureNameStringOrLCID);
    if(!ci.IsNeutralCulture)
       Thread.CurrentThread.CurrentCulture=ci;

    //throws but you can find out at design time, or catch and implement your own fallback.
    Thread.CurrentThread.CurrentCulture=CultureInfo.GetCultureInfo("fr");

    //another way is to let the framework pick a specific culture for you via the static method.
    Thread.CurrentThread.CurrentCulture=CultureInfo.CreateSpecificCulture("fr");

    You can get into a ton of political incorrectness with this method. There are many specific cultures with the same neutral parent, but the logic used to return the default specific culture is completely HAPHAZARD. Sometimes it is the most populous nation within the group. For example en returns en-US, pt returns pt-BR. This should placate any chauvinistic Brits and Potuguese.

    However, es returns es-ES which is not the most populous Spanish speaking nation (it should be es-MX). Likewise, ar return ar-SA, but it should be ar-EG. The static CultureInfo.CreateSpecificCulture should really only be used when not throwing an error is more important than the other issues.
     
    Another point of interest is that the executing thread needs to be set with every request. The CultureInfo or culture name be persisted across different requests in the Session collection and retrieved in the new request (not just postbacks of the same page).

    The code can be globalized in the Application_AcquireRequestState(object sender, EventArgs e) event handler in Global.asax. Then all you need do is assign a CultureInfo to the session. In the new page you do not even have to retrieve it. You can directly access the Thread.CurrentThread.CurrentUICulture and print it out or whatever and it works nice. The code generator does not even bother to stub out an Application_AcquireRequestState handler when creating a new Global.asax, but the HttpApplication.AcquireRequestState event does exist.

    Actually the new static read-only properties of CultureInfo which return the executing thread's state are perfect for that.
    They don't even require the Threading namespace at all so it is all simplified, but only once you've suffered sorting it all out.

    //identical to Thread.CurrentThread.CurrentCulture but read-only
    CultureInfo.CurrentCulture

    //identical to Thread.CurrentThread.CurrentUICulture but read-only

    CultureInfo.CurrentUICulture


    There are some limitations to using Session - InProc, out of proc etc. There are also other performance issues, which are beyond the scope of this topic, so in v2.0 personalization profile is now recommended as the store.

    I had my own localization controls which didn't have to have a specific culture. I figured as long as the language was accounted for between "en" and "fr" it was good enough for my readers. That was a bad idea because I couldn't inherit from existing controls among many other problems.

    It turns out I could get the best of both worlds, because there is a hierarchy too. "en" is a Parent of "en-US" and "en-GB" and "en-CA". The parent of "en" is the invariant culture. The parent of invariant culture is invariant culture, but it should have been null to allow testing for root level. So instead of testing for null of the parent you should always check for invariant in the self. The invariant, should not, but does have a parent: the invariant one. This kind of gets too religious for me. That alone can really bloat your code. Again the hierarchy is only for CurrentUICulture. Really the two collections are apples and oranges and are defined in separate independent RFCs. The idea of hierarchy is terrific, it should have been done at the RFC level. Microsoft did an OK job but there are still many irregularities. The good news is the irregularities are not for the popular cultures and are easily discoverable and predictable and can be accounted for in code. You better be an accomplished linguist before you set out to implement your own hierarchy, which is now possible via the provider model.

    The fallback mechanism of the framework steps up this hierarchy, instead of skipping up straight to the root invariant culture as most samples show. Unfortunately I have seen no good discussion of this important feature. So out of the box you can assign en-ZW culture to the thread (both CurrentCulture and CurrentUICulture props). However you don't have to bother having a resx file for en-ZW if you don't expect many readers from Zimbabwe, and there really are not that many differences in the language. Still the Zimbabwian readers would get the data in the YourResource.en.resx for language AND still show the correct date-time formatting for Zimbabwe that is all done for you in the control. Isn't that nice!

    You cannot step down the one-to-many hierarchy. Many specific en-XX have the same neutral parent en but not always vice-versa - sr is not the parent of sr-BS-Latn. So data integrity would be affected. If you need en-ZW then just say so from the start.

    BTW, the CultureTypes enum is not much more helpful because it includes the invariant as neutral, which it is not, and in v2.0 there is a new undocumented CultureTypes.FrameworkCulturesCultureTypes.AllCultures includes the rest of the options. So the enum as a tool for navigating the the hierarchy is worthless. The Asp.Net team said they would fix it in Orcas but you never know. Meantime I did my own wrapper which includes one most important subset - cultures supported by my app - much smaller universe of values. The data is persisted in (what else) a resx file but it could be any data store and read into the Application object on App_Start in Global.asax

    Maybe there should have been a derived class UICultureInfo: CultureInfo which would have reflected the difference, but years into the framework there would be too much legacy to contend with.

    Now why couldn't they explain all that in msdn instead of going around in a vicious circle?
    It is a good thing msdn2 has feedback and rating so you can tell them what you think.

    I am going to make a blog or an article out of this because I can't stand how many people are confused about one of the nicest features of the framework, all because of the knucklehead docs.

    So any feedback corrections are appreciated.
    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, October 12, 2005 9:34 AM

All replies

  • User-1280723201 posted
    hi

    one of them will change the data being entered whereas other being the controls like calendar control will be changed
    accroding to the language we select.

    currentuiculture being gets/sets teh culture used by res mgr for culture specific resources at runtime, whereas cultureinfo represents teh culture for current thread.

    hope it gives you an idea. for better understanding, work with an example by changing both or one or so and find the difference.



    Friday, September 30, 2005 9:41 AM
  • User1424575140 posted
    http://msdn.microsoft.com/en-us/library/441487wx

    The CultureInfo.CurrentUICulture property is a per-thread setting that returns the current user interface culture. This property is used by the ResourceManager class to look up culture-specific resources at run time. You can use a neutral or specific culture, or the InvariantCulture to set the CurrentUICulture property. You can use the Thread.CurrentThread property to set CurrentCulture. For more information, see the examples provided later in this topic.

    http://msdn.microsoft.com/en-us/library/se513yha(en-US,VS.80).aspx

    The CultureInfo.CurrentCulture property is a per-thread setting that determines the default formats for dates, times, currency, and numbers, the sorting order of text, string comparisons, and casing. The CurrentCulture property is not a language setting. It contains only data related to the standard settings for a geographical region. Therefore, the CurrentCulture property can only be set to a specific culture or to the InvariantCulture. You can use the Thread.CurrentThread property to set CurrentCulture. For more information, see the examples provided later in this topic.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, October 7, 2005 2:12 PM
  • User1183903743 posted
    You are correct. The msdn docs make a mess of the explanation.

    First of all the CultureInfo class is in System.Globalization. As such, it has NOTHING to do with threads at all and that is where the confusion comes from. It can hold info about (and BOTH) culture specific and neutral and even invariant culture and even non-existing cultures if you set up some custom ones.

    On the other hand BOTH CurrentCulture and CurrentUICulture are props of the CurrentThread and that is NOT what differentiates them. They are both props of type System.Globalization.CultureInfo.

    Now all this bucket of info has to be sorted out because in some situations only a subset of these data are needed. For that there is an enumeration called CultureTypes.

    However let's keep it simple and look at two such subsets Neutral and Specific cultures. Without using the enumeration we could do a rule of thumb that 2-chars("en", "fr", "es") are neutral and 5-chars ("en-US","es-ES","pt-BR") are specific. There are some exceptions where there are extra chars but they are very obscure and you should look at them if they affect you.

    Contrary to intuition, the name CurrentCulture has nothing to do with language, per se, but with formatting of dates and currency etc. For this reason it must be specific. A more appropriate self-descriptive name like CurrentFormattingCulture would have prevented millions of questions but they didn't let me make that decision.

    On the other hand the property of the thread that has to do with language/translations etc is CurrentUICulture. This is the one the ResourceManager object takes to look up resources by culture(either neutral or specific) . Again, a wrong impression is conveyed by the UI which, at least to me, should imply exactly formatting. However the functionality is exactly the opposite. It has to do with multi-versioning of resources by culture. A more appropriate self-explanatory and less counter-intuitive name would have been CurrentResourcingCulture but, again, it wasn't up to me.

    Asp.net controls with built-in localization cannot use neutral cultures because there could be a formatting difference in "pt-BR" and "pt-PT" which just "pt" couldn't account for. There may be a different religion and different calendar etc. Classic example is the 12h date-time formatting that only en-US and en-PH use. So such controls need the CurrentCulture set in the thread with 5-char SPECIFIC VALUE for culture name when you instantiate a CultureInfo object or auto detect it from the client browser.

    For this reason there is a bool method IsNeutralCulture which can help you prevent exceptions(instead of primitively parsing the number of chars, which again includes most but not all scenarios, and not all constructor overloads - some take an LCID instead of culture name).

    //never throws but your user may never get the UI culture changed either, and never know why. 
    CultureInfo ci=new CultureInfo(SomeDynamicCultureNameStringOrLCID);
    if(!ci.IsNeutralCulture)
       Thread.CurrentThread.CurrentCulture=ci;

    //throws but you can find out at design time, or catch and implement your own fallback.
    Thread.CurrentThread.CurrentCulture=CultureInfo.GetCultureInfo("fr");

    //another way is to let the framework pick a specific culture for you via the static method.
    Thread.CurrentThread.CurrentCulture=CultureInfo.CreateSpecificCulture("fr");

    You can get into a ton of political incorrectness with this method. There are many specific cultures with the same neutral parent, but the logic used to return the default specific culture is completely HAPHAZARD. Sometimes it is the most populous nation within the group. For example en returns en-US, pt returns pt-BR. This should placate any chauvinistic Brits and Potuguese.

    However, es returns es-ES which is not the most populous Spanish speaking nation (it should be es-MX). Likewise, ar return ar-SA, but it should be ar-EG. The static CultureInfo.CreateSpecificCulture should really only be used when not throwing an error is more important than the other issues.
     
    Another point of interest is that the executing thread needs to be set with every request. The CultureInfo or culture name be persisted across different requests in the Session collection and retrieved in the new request (not just postbacks of the same page).

    The code can be globalized in the Application_AcquireRequestState(object sender, EventArgs e) event handler in Global.asax. Then all you need do is assign a CultureInfo to the session. In the new page you do not even have to retrieve it. You can directly access the Thread.CurrentThread.CurrentUICulture and print it out or whatever and it works nice. The code generator does not even bother to stub out an Application_AcquireRequestState handler when creating a new Global.asax, but the HttpApplication.AcquireRequestState event does exist.

    Actually the new static read-only properties of CultureInfo which return the executing thread's state are perfect for that.
    They don't even require the Threading namespace at all so it is all simplified, but only once you've suffered sorting it all out.

    //identical to Thread.CurrentThread.CurrentCulture but read-only
    CultureInfo.CurrentCulture

    //identical to Thread.CurrentThread.CurrentUICulture but read-only

    CultureInfo.CurrentUICulture


    There are some limitations to using Session - InProc, out of proc etc. There are also other performance issues, which are beyond the scope of this topic, so in v2.0 personalization profile is now recommended as the store.

    I had my own localization controls which didn't have to have a specific culture. I figured as long as the language was accounted for between "en" and "fr" it was good enough for my readers. That was a bad idea because I couldn't inherit from existing controls among many other problems.

    It turns out I could get the best of both worlds, because there is a hierarchy too. "en" is a Parent of "en-US" and "en-GB" and "en-CA". The parent of "en" is the invariant culture. The parent of invariant culture is invariant culture, but it should have been null to allow testing for root level. So instead of testing for null of the parent you should always check for invariant in the self. The invariant, should not, but does have a parent: the invariant one. This kind of gets too religious for me. That alone can really bloat your code. Again the hierarchy is only for CurrentUICulture. Really the two collections are apples and oranges and are defined in separate independent RFCs. The idea of hierarchy is terrific, it should have been done at the RFC level. Microsoft did an OK job but there are still many irregularities. The good news is the irregularities are not for the popular cultures and are easily discoverable and predictable and can be accounted for in code. You better be an accomplished linguist before you set out to implement your own hierarchy, which is now possible via the provider model.

    The fallback mechanism of the framework steps up this hierarchy, instead of skipping up straight to the root invariant culture as most samples show. Unfortunately I have seen no good discussion of this important feature. So out of the box you can assign en-ZW culture to the thread (both CurrentCulture and CurrentUICulture props). However you don't have to bother having a resx file for en-ZW if you don't expect many readers from Zimbabwe, and there really are not that many differences in the language. Still the Zimbabwian readers would get the data in the YourResource.en.resx for language AND still show the correct date-time formatting for Zimbabwe that is all done for you in the control. Isn't that nice!

    You cannot step down the one-to-many hierarchy. Many specific en-XX have the same neutral parent en but not always vice-versa - sr is not the parent of sr-BS-Latn. So data integrity would be affected. If you need en-ZW then just say so from the start.

    BTW, the CultureTypes enum is not much more helpful because it includes the invariant as neutral, which it is not, and in v2.0 there is a new undocumented CultureTypes.FrameworkCulturesCultureTypes.AllCultures includes the rest of the options. So the enum as a tool for navigating the the hierarchy is worthless. The Asp.Net team said they would fix it in Orcas but you never know. Meantime I did my own wrapper which includes one most important subset - cultures supported by my app - much smaller universe of values. The data is persisted in (what else) a resx file but it could be any data store and read into the Application object on App_Start in Global.asax

    Maybe there should have been a derived class UICultureInfo: CultureInfo which would have reflected the difference, but years into the framework there would be too much legacy to contend with.

    Now why couldn't they explain all that in msdn instead of going around in a vicious circle?
    It is a good thing msdn2 has feedback and rating so you can tell them what you think.

    I am going to make a blog or an article out of this because I can't stand how many people are confused about one of the nicest features of the framework, all because of the knucklehead docs.

    So any feedback corrections are appreciated.
    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, October 12, 2005 9:34 AM
  • User-1225738063 posted

    rmprimo did a pretty good job of explaining it.

    The first part of the culture is the language, the second is how to format stuff.
    Like with en-us, our language is english with a mm/dd/yy format.
    With en-gb, the language is english with a dd/mm/yy format.

    At any rate, don't assume that the language is two characters, some are not.  The dash is in there for a reason, use it if you must break it out manually.  "Syr" is the only 3 letter language I know of, but there are problably others, or may be more in the future that are 3+ characters.

    Monday, October 17, 2005 11:30 AM
  • User1183903743 posted
    The dash is in there for a reason, use it if you must break it out manually. 
    No the dash is not a good way to parse.

    There are neutral cultures with a dash:
     
      
    zh-CHS
        zh-CHT

    There could be more than one dashes. Taking the first dash is not reliable either:

       bs-SP-Latn  //no such neutral culture
    bs
      sr-BA-Latn
    and
     sr-BA-Cyrl  //the neutral culture for these is NOT sr

    That is why you should use the CultureInfo API parent culture. Then you don't have to be a super linguist to write code for Serbians. Unfortunately, the API also has some flaws in its hierarchical design but they can be accounted for and you are still better off than doing your own parsing.
    Tuesday, October 18, 2005 11:09 AM