1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 ////////////////////////////////////////////////////////////////////////////
9 // Purpose: This class represents the software preferences of a particular
10 // culture or community. It includes information such as the
11 // language, writing system, and a calendar used by the culture
12 // as well as methods for common operations such as printing
13 // dates and sorting strings.
17 // !!!! NOTE WHEN CHANGING THIS CLASS !!!!
19 // If adding or removing members to this class, please update CultureInfoBaseObject
20 // in ndp/clr/src/vm/object.h. Note, the "actual" layout of the class may be
21 // different than the order in which members are declared. For instance, all
22 // reference types will come first in the class before value types (like ints, bools, etc)
23 // regardless of the order in which they are declared. The best way to see the
24 // actual order of the class is to do a !dumpobj on an instance of the managed
25 // object inside of the debugger.
27 ////////////////////////////////////////////////////////////////////////////
29 namespace System.Globalization {
31 using System.Security;
32 using System.Threading;
33 using System.Collections;
35 using System.Runtime.CompilerServices;
36 using System.Runtime.InteropServices;
37 using System.Runtime.Serialization;
38 using System.Runtime.Versioning;
39 using System.Security.Permissions;
40 using System.Reflection;
41 using Microsoft.Win32;
42 using System.Diagnostics.Contracts;
43 using System.Resources;
46 [System.Runtime.InteropServices.ComVisible(true)]
47 public partial class CultureInfo : ICloneable, IFormatProvider {
48 //--------------------------------------------------------------------//
49 // Internal Information //
50 //--------------------------------------------------------------------//
52 //--------------------------------------------------------------------//
53 // Data members to be serialized:
54 //--------------------------------------------------------------------//
56 // We use an RFC4646 type string to construct CultureInfo.
57 // This string is stored in m_name and is authoritative.
58 // We use the m_cultureData to get the data for our object
61 // WARNING: All member fields declared here must also be in ndp/clr/src/vm/object.h
62 // WARNING: They aren't really private because object.h can access them, but other C# stuff cannot
63 // WARNING: The type loader will rearrange class member offsets so the mscorwks!CultureInfoBaseObject
64 // WARNING: must be manually structured to match the true loaded class layout
66 internal bool m_isReadOnly;
67 internal CompareInfo compareInfo;
68 internal TextInfo textInfo;
69 // Not serialized for now since we only build it privately for use in the CARIB (so rebuilding is OK)
71 [NonSerialized]internal RegionInfo regionInfo;
73 internal NumberFormatInfo numInfo;
74 internal DateTimeFormatInfo dateTimeInfo;
75 internal Calendar calendar;
76 [OptionalField(VersionAdded = 1)]
77 internal int m_dataItem; // NEVER USED, DO NOT USE THIS! (Serialized in Whidbey/Everett)
78 [OptionalField(VersionAdded = 1)]
79 internal int cultureID = 0x007f; // NEVER USED, DO NOT USE THIS! (Serialized in Whidbey/Everett)
81 // The CultureData instance that we are going to read data from.
82 // For supported culture, this will be the CultureData instance that read data from mscorlib assembly.
83 // For customized culture, this will be the CultureData instance that read data from user customized culture binary file.
85 [NonSerialized]internal CultureData m_cultureData;
87 [NonSerialized]internal bool m_isInherited;
88 #if FEATURE_LEAK_CULTURE_INFO
89 [NonSerialized]private bool m_isSafeCrossDomain;
90 [NonSerialized]private int m_createdDomainID;
91 #endif // !FEATURE_CORECLR
93 [NonSerialized]private CultureInfo m_consoleFallbackCulture;
94 #endif // !FEATURE_CORECLR
96 // Names are confusing. Here are 3 names we have:
98 // new CultureInfo() m_name m_nonSortName m_sortName
99 // en-US en-US en-US en-US
100 // de-de_phoneb de-DE_phoneb de-DE de-DE_phoneb
101 // fj-fj (custom) fj-FJ fj-FJ en-US (if specified sort is en-US)
104 // Note that in Silverlight we ask the OS for the text and sort behavior, so the
105 // textinfo and compareinfo names are the same as the name
107 // Note that the name used to be serialized for Everett; it is now serialized
108 // because alernate sorts can have alternate names.
109 // This has a de-DE, de-DE_phoneb or fj-FJ style name
110 internal string m_name;
112 // This will hold the non sorting name to be returned from CultureInfo.Name property.
113 // This has a de-DE style name even for de-DE_phoneb type cultures
114 [NonSerialized]private string m_nonSortName;
116 // This will hold the sorting name to be returned from CultureInfo.SortName property.
117 // This might be completely unrelated to the culture name if a custom culture. Ie en-US for fj-FJ.
118 // Otherwise its the sort name, ie: de-DE or de-DE_phoneb
119 [NonSerialized]private string m_sortName;
122 //--------------------------------------------------------------------//
124 // Static data members
126 //--------------------------------------------------------------------//
128 //Get the current user default culture. This one is almost always used, so we create it by default.
129 private static volatile CultureInfo s_userDefaultCulture;
132 // All of the following will be created on demand.
135 //The Invariant culture;
136 private static volatile CultureInfo s_InvariantCultureInfo;
138 //The culture used in the user interface. This is mostly used to load correct localized resources.
139 private static volatile CultureInfo s_userDefaultUICulture;
141 //This is the UI culture used to install the OS.
142 private static volatile CultureInfo s_InstalledUICultureInfo;
144 //These are defaults that we use if a thread has not opted into having an explicit culture
145 private static volatile CultureInfo s_DefaultThreadCurrentUICulture;
146 private static volatile CultureInfo s_DefaultThreadCurrentCulture;
148 //This is a cache of all previously created cultures. Valid keys are LCIDs or the name. We use two hashtables to track them,
149 // depending on how they are called.
150 private static volatile Hashtable s_LcidCachedCultures;
151 private static volatile Hashtable s_NameCachedCultures;
154 // When running under AppX, we use this to get some information about the language list
156 private static volatile WindowsRuntimeResourceManagerBase s_WindowsRuntimeResourceManager;
159 private static bool ts_IsDoingAppXCultureInfoLookup;
162 //The parent culture.
163 [NonSerialized]private CultureInfo m_parent;
165 // LOCALE constants of interest to us internally and privately for LCID functions
166 // (ie: avoid using these and use names if possible)
167 internal const int LOCALE_NEUTRAL = 0x0000;
168 private const int LOCALE_USER_DEFAULT = 0x0400;
169 private const int LOCALE_SYSTEM_DEFAULT = 0x0800;
170 internal const int LOCALE_CUSTOM_DEFAULT = 0x0c00;
171 internal const int LOCALE_CUSTOM_UNSPECIFIED = 0x1000;
172 internal const int LOCALE_INVARIANT = 0x007F;
173 private const int LOCALE_TRADITIONAL_SPANISH = 0x040a;
176 // The CultureData instance that reads the data provided by our CultureData class.
178 //Using a field initializer rather than a static constructor so that the whole class can be lazy
180 private static readonly bool init = Init();
181 private static bool Init()
184 if (s_InvariantCultureInfo == null)
186 CultureInfo temp = new CultureInfo("", false);
187 temp.m_isReadOnly = true;
188 s_InvariantCultureInfo = temp;
190 // First we set it to Invariant in case someone needs it before we're done finding it.
191 // For example, if we throw an exception in InitUserDefaultCulture, we will still need an valid
192 // s_userDefaultCulture to be used in Thread.CurrentCulture.
193 s_userDefaultCulture = s_userDefaultUICulture = s_InvariantCultureInfo;
195 s_userDefaultCulture = InitUserDefaultCulture();
196 s_userDefaultUICulture = InitUserDefaultUICulture();
200 [System.Security.SecuritySafeCritical] // auto-generated
201 static CultureInfo InitUserDefaultCulture()
203 String strDefault = GetDefaultLocaleName(LOCALE_USER_DEFAULT);
204 if (strDefault == null)
206 strDefault = GetDefaultLocaleName(LOCALE_SYSTEM_DEFAULT);
208 if (strDefault == null)
210 // If system default doesn't work, keep using the invariant
211 return (CultureInfo.InvariantCulture);
214 CultureInfo temp = GetCultureByName(strDefault, true);
216 temp.m_isReadOnly = true;
221 static CultureInfo InitUserDefaultUICulture()
223 String strDefault = GetUserDefaultUILanguage();
225 // In most of cases, UserDefaultCulture == UserDefaultUICulture, so we should use the same instance if possible.
226 if (strDefault == UserDefaultCulture.Name)
228 return (UserDefaultCulture);
231 CultureInfo temp = GetCultureByName( strDefault, true);
235 return (CultureInfo.InvariantCulture);
238 temp.m_isReadOnly = true;
244 [SecuritySafeCritical]
245 internal static CultureInfo GetCultureInfoForUserPreferredLanguageInAppX()
247 // If a call to GetCultureInfoForUserPreferredLanguageInAppX() generated a recursive
248 // call to itself, return null, since we don't want to stack overflow. For example,
249 // this can happen if some code in this method ends up calling CultureInfo.CurrentCulture
250 // (which is common on check'd build because of BCLDebug logging which calls Int32.ToString()).
251 // In this case, returning null will mean CultureInfo.CurrentCulture gets the default Win32
252 // value, which should be fine.
253 if(ts_IsDoingAppXCultureInfoLookup)
258 // If running within a compilation process (mscorsvw.exe, for example), it is illegal to
259 // load any non-mscorlib assembly for execution. Since WindowsRuntimeResourceManager lives
260 // in System.Runtime.WindowsRuntime, caller will need to fall back to default Win32 value,
261 // which should be fine because we should only ever need to access FX resources during NGEN.
262 // FX resources are always loaded from satellite assemblies - even in AppX processes (see the
263 // comments in code:System.Resources.ResourceManager.SetAppXConfiguration for more details).
264 if (AppDomain.IsAppXNGen)
269 CultureInfo toReturn = null;
273 ts_IsDoingAppXCultureInfoLookup = true;
275 if(s_WindowsRuntimeResourceManager == null)
277 s_WindowsRuntimeResourceManager = ResourceManager.GetWinRTResourceManager();
280 toReturn = s_WindowsRuntimeResourceManager.GlobalResourceContextBestFitCultureInfo;
284 ts_IsDoingAppXCultureInfoLookup = false;
290 [SecuritySafeCritical]
291 internal static bool SetCultureInfoForUserPreferredLanguageInAppX(CultureInfo ci)
293 // If running within a compilation process (mscorsvw.exe, for example), it is illegal to
294 // load any non-mscorlib assembly for execution. Since WindowsRuntimeResourceManager lives
295 // in System.Runtime.WindowsRuntime, caller will need to fall back to default Win32 value,
296 // which should be fine because we should only ever need to access FX resources during NGEN.
297 // FX resources are always loaded from satellite assemblies - even in AppX processes (see the
298 // comments in code:System.Resources.ResourceManager.SetAppXConfiguration for more details).
299 if (AppDomain.IsAppXNGen)
304 if (s_WindowsRuntimeResourceManager == null)
306 s_WindowsRuntimeResourceManager = ResourceManager.GetWinRTResourceManager();
309 return s_WindowsRuntimeResourceManager.SetGlobalResourceContextDefaultCulture(ci);
313 ////////////////////////////////////////////////////////////////////////
315 // CultureInfo Constructors
317 ////////////////////////////////////////////////////////////////////////
320 public CultureInfo(String name) : this(name, true) {
324 public CultureInfo(String name, bool useUserOverride) {
326 throw new ArgumentNullException("name",
327 Environment.GetResourceString("ArgumentNull_String"));
329 Contract.EndContractBlock();
331 // Get our data providing record
332 this.m_cultureData = CultureData.GetCultureData(name, useUserOverride);
334 if (this.m_cultureData == null) {
335 throw new CultureNotFoundException("name", name, Environment.GetResourceString("Argument_CultureNotSupported"));
338 this.m_name = this.m_cultureData.CultureName;
339 this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
344 public CultureInfo(int culture) : this(culture, true) {
347 public CultureInfo(int culture, bool useUserOverride) {
348 // We don't check for other invalid LCIDS here...
350 throw new ArgumentOutOfRangeException("culture",
351 Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
353 Contract.EndContractBlock();
355 InitializeFromCultureId(culture, useUserOverride);
358 private void InitializeFromCultureId(int culture, bool useUserOverride)
362 case LOCALE_CUSTOM_DEFAULT:
363 case LOCALE_SYSTEM_DEFAULT:
365 case LOCALE_USER_DEFAULT:
366 case LOCALE_CUSTOM_UNSPECIFIED:
367 // Can't support unknown custom cultures and we do not support neutral or
368 // non-custom user locales.
369 throw new CultureNotFoundException(
370 "culture", culture, Environment.GetResourceString("Argument_CultureNotSupported"));
373 // Now see if this LCID is supported in the system default CultureData table.
374 this.m_cultureData = CultureData.GetCultureData(culture, useUserOverride);
377 this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
378 this.m_name = this.m_cultureData.CultureName;
380 #endif // FEATURE_USE_LCID
383 // CheckDomainSafetyObject throw if the object is customized object which cannot be attached to
384 // other object (like CultureInfo or DateTimeFormatInfo).
387 internal static void CheckDomainSafetyObject(Object obj, Object container)
389 if (obj.GetType().Assembly != typeof(System.Globalization.CultureInfo).Assembly) {
391 throw new InvalidOperationException(
393 CultureInfo.CurrentCulture,
394 Environment.GetResourceString("InvalidOperation_SubclassedObject"),
396 container.GetType()));
398 Contract.EndContractBlock();
401 #region Serialization
402 // We need to store the override from the culture data record.
403 private bool m_useUserOverride;
406 private void OnDeserialized(StreamingContext ctx)
409 // Whidbey+ should remember our name
410 // but v1 and v1.1 did not store name -- only lcid
411 // Whidbey did not store actual alternate sort name in m_name
412 // like we do in v4 so we can't use name for alternate sort
413 // e.g. for es-ES_tradnl: v2 puts es-ES in m_name; v4 puts es-ES_tradnl
414 if (m_name == null || IsAlternateSortLcid(cultureID))
416 Contract.Assert(cultureID >=0, "[CultureInfo.OnDeserialized] cultureID >= 0");
417 InitializeFromCultureId(cultureID, m_useUserOverride);
422 Contract.Assert(m_name != null, "[CultureInfo.OnDeserialized] m_name != null");
424 this.m_cultureData = CultureData.GetCultureData(m_name, m_useUserOverride);
425 if (this.m_cultureData == null)
426 throw new CultureNotFoundException(
427 "m_name", m_name, Environment.GetResourceString("Argument_CultureNotSupported"));
432 m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
434 // in case we have non customized CultureInfo object we shouldn't allow any customized object
435 // to be attached to it for cross app domain safety.
436 if (this.GetType().Assembly == typeof(System.Globalization.CultureInfo).Assembly)
438 if (textInfo != null)
440 CheckDomainSafetyObject(textInfo, this);
443 if (compareInfo != null)
445 CheckDomainSafetyObject(compareInfo, this);
451 // A locale ID is a 32 bit value which is the combination of a
452 // language ID, a sort ID, and a reserved area. The bits are
453 // allocated as follows:
455 // +------------------------+-------+--------------------------------+
456 // | Reserved |Sort ID| Language ID |
457 // +------------------------+-------+--------------------------------+
458 // 31 20 19 16 15 0 bit
459 private const int LOCALE_SORTID_MASK = 0x000f0000;
461 static private bool IsAlternateSortLcid(int lcid)
463 if(lcid == LOCALE_TRADITIONAL_SPANISH)
468 return (lcid & LOCALE_SORTID_MASK) != 0;
473 private void OnSerializing(StreamingContext ctx)
475 this.m_name = this.m_cultureData.CultureName;
476 this.m_useUserOverride = this.m_cultureData.UseUserOverride;
478 // for compatibility with v2 serialize cultureID
479 this.cultureID = this.m_cultureData.ILANGUAGE;
482 #endregion Serialization
484 #if FEATURE_LEAK_CULTURE_INFO
485 // Is it safe to send this CultureInfo as an instance member of a Thread cross AppDomain boundaries?
486 // For Silverlight, the answer is always no.
487 internal bool IsSafeCrossDomain {
489 Contract.Assert(m_createdDomainID != 0, "[CultureInfo.IsSafeCrossDomain] m_createdDomainID != 0");
490 return m_isSafeCrossDomain;
494 internal int CreatedDomainID {
496 Contract.Assert(m_createdDomainID != 0, "[CultureInfo.CreatedDomain] m_createdDomainID != 0");
497 return m_createdDomainID;
501 internal void StartCrossDomainTracking() {
503 // If we have decided about cross domain safety of this instance, we are done
504 if (m_createdDomainID != 0)
507 // If FEATURE_LEAK_CULTURE_INFO isn't enabled, we never want to pass
508 // CultureInfo as an instance member of a Thread.
509 if (CanSendCrossDomain())
511 m_isSafeCrossDomain = true;
514 // m_createdDomainID has to be assigned last. We use it to signal that we have
515 // completed the check.
516 System.Threading.Thread.MemoryBarrier();
517 m_createdDomainID = Thread.GetDomainID();
519 #endif // FEATURE_LEAK_CULTURE_INFO
521 // Is it safe to pass the CultureInfo cross AppDomain boundaries, not necessarily as an instance
522 // member of Thread. This is different from IsSafeCrossDomain, which implies passing the CultureInfo
523 // as a Thread instance member.
524 internal bool CanSendCrossDomain()
527 if (this.GetType() == typeof(System.Globalization.CultureInfo))
534 // Constructor called by SQL Server's special munged culture - creates a culture with
535 // a TextInfo and CompareInfo that come from a supplied alternate source. This object
536 // is ALWAYS read-only.
537 // Note that we really cannot use an LCID version of this override as the cached
538 // name we create for it has to include both names, and the logic for this is in
539 // the GetCultureInfo override *only*.
540 internal CultureInfo(String cultureName, String textAndCompareCultureName)
542 if (cultureName==null) {
543 throw new ArgumentNullException("cultureName",
544 Environment.GetResourceString("ArgumentNull_String"));
546 Contract.EndContractBlock();
548 this.m_cultureData = CultureData.GetCultureData(cultureName, false);
549 if (this.m_cultureData == null)
550 throw new CultureNotFoundException(
551 "cultureName", cultureName, Environment.GetResourceString("Argument_CultureNotSupported"));
553 this.m_name = this.m_cultureData.CultureName;
555 CultureInfo altCulture = GetCultureInfo(textAndCompareCultureName);
556 this.compareInfo = altCulture.CompareInfo;
557 this.textInfo = altCulture.TextInfo;
560 // We do this to try to return the system UI language and the default user languages
561 // The callers should have a fallback if this fails (like Invariant)
562 private static CultureInfo GetCultureByName(String name, bool userOverride)
564 // Try to get our culture
567 return userOverride ? new CultureInfo(name) : CultureInfo.GetCultureInfo(name);
569 catch (ArgumentException)
577 // Return a specific culture. A tad irrelevent now since we always return valid data
578 // for neutral locales.
580 // Note that there's interesting behavior that tries to find a smaller name, ala RFC4647,
581 // if we can't find a bigger name. That doesn't help with things like "zh" though, so
582 // the approach is of questionable value
585 public static CultureInfo CreateSpecificCulture(String name) {
586 Contract.Ensures(Contract.Result<CultureInfo>() != null);
591 culture = new CultureInfo(name);
592 } catch(ArgumentException) {
593 // When CultureInfo throws this exception, it may be because someone passed the form
594 // like "az-az" because it came out of an http accept lang. We should try a little
595 // parsing to perhaps fall back to "az" here and use *it* to create the neutral.
600 for(idx = 0; idx < name.Length; idx++) {
601 if('-' == name[idx]) {
603 culture = new CultureInfo(name.Substring(0, idx));
605 } catch(ArgumentException) {
606 // throw the original exception so the name in the string will be right
612 if(null == culture) {
613 // nothing to save here; throw the original exception
618 //In the most common case, they've given us a specific culture, so we'll just return that.
619 if (!(culture.IsNeutralCulture)) {
623 return (new CultureInfo(culture.m_cultureData.SSPECIFICCULTURE));
625 #endif // !FEATURE_CORECLR
627 internal static bool VerifyCultureName(String cultureName, bool throwException)
629 // This function is used by ResourceManager.GetResourceFileName().
630 // ResourceManager searches for resource using CultureInfo.Name,
631 // so we should check against CultureInfo.Name.
633 for (int i=0; i<cultureName.Length; i++) {
634 char c = cultureName[i];
636 if (Char.IsLetterOrDigit(c) || c=='-' || c=='_') {
639 if (throwException) {
640 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidResourceCultureName", cultureName));
648 internal static bool VerifyCultureName(CultureInfo culture, bool throwException) {
649 Contract.Assert(culture!=null, "[CultureInfo.VerifyCultureName]culture!=null");
651 //If we have an instance of one of our CultureInfos, the user can't have changed the
652 //name and we know that all names are valid in files.
653 if (!culture.m_isInherited) {
657 return VerifyCultureName(culture.Name, throwException);
661 ////////////////////////////////////////////////////////////////////////
665 // This instance provides methods based on the current user settings.
666 // These settings are volatile and may change over the lifetime of the
669 ////////////////////////////////////////////////////////////////////////
672 public static CultureInfo CurrentCulture
675 Contract.Ensures(Contract.Result<CultureInfo>() != null);
678 return Thread.CurrentThread.CurrentCulture;
680 // In the case of CoreCLR, Thread.m_CurrentCulture and
681 // Thread.m_CurrentUICulture are thread static so as not to let
682 // CultureInfo objects leak across AppDomain boundaries. The
683 // fact that these fields are thread static introduces overhead
684 // in accessing them (through Thread.CurrentCulture). There is
685 // also overhead in accessing Thread.CurrentThread. In this
686 // case, we can avoid the overhead of Thread.CurrentThread
687 // because these fields are thread static, and so do not
688 // require a Thread instance to be accessed.
690 if(AppDomain.IsAppXModel()) {
691 CultureInfo culture = GetCultureInfoForUserPreferredLanguageInAppX();
696 return Thread.m_CurrentCulture ??
697 s_DefaultThreadCurrentCulture ??
698 s_userDefaultCulture ??
706 throw new ArgumentNullException("value");
709 if (AppDomain.IsAppXModel()) {
710 if (SetCultureInfoForUserPreferredLanguageInAppX(value)) {
711 // successfully set the culture, otherwise fallback to legacy path
716 Thread.CurrentThread.CurrentCulture = value;
721 // This is the equivalence of the Win32 GetUserDefaultLCID()
723 internal static CultureInfo UserDefaultCulture {
726 Contract.Ensures(Contract.Result<CultureInfo>() != null);
728 CultureInfo temp = s_userDefaultCulture;
732 // setting the s_userDefaultCulture with invariant culture before intializing it is a protection
733 // against recursion problem just in case if somebody called CurrentCulture from the CultureInfo
734 // creation path. the recursion can happen if the current user culture is a replaced custom culture.
737 s_userDefaultCulture = CultureInfo.InvariantCulture;
738 temp = InitUserDefaultCulture();
739 s_userDefaultCulture = temp;
746 // This is the equivalence of the Win32 GetUserDefaultUILanguage()
748 internal static CultureInfo UserDefaultUICulture {
750 Contract.Ensures(Contract.Result<CultureInfo>() != null);
752 CultureInfo temp = s_userDefaultUICulture;
756 // setting the s_userDefaultCulture with invariant culture before intializing it is a protection
757 // against recursion problem just in case if somebody called CurrentUICulture from the CultureInfo
758 // creation path. the recursion can happen if the current user culture is a replaced custom culture.
761 s_userDefaultUICulture = CultureInfo.InvariantCulture;
763 temp = InitUserDefaultUICulture();
764 s_userDefaultUICulture = temp;
771 public static CultureInfo CurrentUICulture {
773 Contract.Ensures(Contract.Result<CultureInfo>() != null);
776 return Thread.CurrentThread.CurrentUICulture;
778 // In the case of CoreCLR, Thread.m_CurrentCulture and
779 // Thread.m_CurrentUICulture are thread static so as not to let
780 // CultureInfo objects leak across AppDomain boundaries. The
781 // fact that these fields are thread static introduces overhead
782 // in accessing them (through Thread.CurrentCulture). There is
783 // also overhead in accessing Thread.CurrentThread. In this
784 // case, we can avoid the overhead of Thread.CurrentThread
785 // because these fields are thread static, and so do not
786 // require a Thread instance to be accessed.
788 if(AppDomain.IsAppXModel()) {
789 CultureInfo culture = GetCultureInfoForUserPreferredLanguageInAppX();
794 return Thread.m_CurrentUICulture ??
795 s_DefaultThreadCurrentUICulture ??
796 s_userDefaultUICulture ??
797 UserDefaultUICulture;
804 throw new ArgumentNullException("value");
807 if (AppDomain.IsAppXModel()) {
808 if (SetCultureInfoForUserPreferredLanguageInAppX(value)) {
809 // successfully set the culture, otherwise fallback to legacy path
814 Thread.CurrentThread.CurrentUICulture = value;
820 // This is the equivalence of the Win32 GetSystemDefaultUILanguage()
822 public static CultureInfo InstalledUICulture {
824 Contract.Ensures(Contract.Result<CultureInfo>() != null);
826 CultureInfo temp = s_InstalledUICultureInfo;
828 String strDefault = GetSystemDefaultUILanguage();
829 temp = GetCultureByName(strDefault, true);
833 temp = InvariantCulture;
836 temp.m_isReadOnly = true;
837 s_InstalledUICultureInfo = temp;
843 public static CultureInfo DefaultThreadCurrentCulture {
845 return s_DefaultThreadCurrentCulture;
848 [System.Security.SecuritySafeCritical] // auto-generated
849 #pragma warning disable 618
850 [SecurityPermission(SecurityAction.Demand, ControlThread = true)]
851 #pragma warning restore 618
854 // If you add pre-conditions to this method, check to see if you also need to
855 // add them to Thread.CurrentCulture.set.
857 s_DefaultThreadCurrentCulture = value;
861 public static CultureInfo DefaultThreadCurrentUICulture {
863 return s_DefaultThreadCurrentUICulture;
866 [System.Security.SecuritySafeCritical] // auto-generated
867 #pragma warning disable 618
868 [SecurityPermission(SecurityAction.Demand, ControlThread = true)]
869 #pragma warning restore 618
872 //If they're trying to use a Culture with a name that we can't use in resource lookup,
873 //don't even let them set it on the thread.
875 // If you add more pre-conditions to this method, check to see if you also need to
876 // add them to Thread.CurrentUICulture.set.
880 CultureInfo.VerifyCultureName(value, true);
883 s_DefaultThreadCurrentUICulture = value;
887 ////////////////////////////////////////////////////////////////////////
891 // This instance provides methods, for example for casing and sorting,
892 // that are independent of the system and current user settings. It
893 // should be used only by processes such as some system services that
894 // require such invariant results (eg. file systems). In general,
895 // the results are not linguistically correct and do not match any
898 ////////////////////////////////////////////////////////////////////////
901 public static CultureInfo InvariantCulture {
904 Contract.Ensures(Contract.Result<CultureInfo>() != null);
905 return (s_InvariantCultureInfo);
910 ////////////////////////////////////////////////////////////////////////
914 // Return the parent CultureInfo for the current instance.
916 ////////////////////////////////////////////////////////////////////////
918 public virtual CultureInfo Parent
920 [System.Security.SecuritySafeCritical] // auto-generated
923 Contract.Ensures(Contract.Result<CultureInfo>() != null);
925 if (null == m_parent)
929 string parentName = this.m_cultureData.SPARENT;
931 if (String.IsNullOrEmpty(parentName))
933 m_parent = InvariantCulture;
937 m_parent = new CultureInfo(parentName, this.m_cultureData.UseUserOverride);
940 catch (ArgumentException)
942 // For whatever reason our IPARENT or SPARENT wasn't correct, so use invariant
943 // We can't allow ourselves to fail. In case of custom cultures the parent of the
944 // current custom culture isn't installed.
945 m_parent = InvariantCulture;
952 ////////////////////////////////////////////////////////////////////////
956 // Returns a properly formed culture identifier for the current
959 ////////////////////////////////////////////////////////////////////////
962 public virtual int LCID {
964 return (this.m_cultureData.ILANGUAGE);
969 ////////////////////////////////////////////////////////////////////////
973 // Essentially an LCID, though one that may be different than LCID in the case
974 // of a customized culture (LCID == LOCALE_CUSTOM_UNSPECIFIED).
976 ////////////////////////////////////////////////////////////////////////
978 [System.Runtime.InteropServices.ComVisible(false)]
979 public virtual int KeyboardLayoutId
983 int keyId = this.m_cultureData.IINPUTLANGUAGEHANDLE;
985 // Not a customized culture, return the default Keyboard layout ID, which is the same as the language ID.
992 public static CultureInfo[] GetCultures(CultureTypes types) {
993 Contract.Ensures(Contract.Result<CultureInfo[]>() != null);
994 // internally we treat UserCustomCultures as Supplementals but v2
995 // treats as Supplementals and Replacements
996 if((types & CultureTypes.UserCustomCulture) == CultureTypes.UserCustomCulture)
998 types |= CultureTypes.ReplacementCultures;
1000 return (CultureData.GetCultures(types));
1004 ////////////////////////////////////////////////////////////////////////
1008 // Returns the full name of the CultureInfo. The name is in format like
1009 // "en-US" This version does NOT include sort information in the name.
1011 ////////////////////////////////////////////////////////////////////////
1012 public virtual String Name {
1014 Contract.Ensures(Contract.Result<String>() != null);
1016 // We return non sorting name here.
1017 if (this.m_nonSortName == null) {
1018 this.m_nonSortName = this.m_cultureData.SNAME;
1019 if (this.m_nonSortName == null) {
1020 this.m_nonSortName = String.Empty;
1023 return this.m_nonSortName;
1027 // This one has the sort information (ie: de-DE_phoneb)
1028 internal String SortName
1032 if (this.m_sortName == null)
1034 this.m_sortName = this.m_cultureData.SCOMPAREINFO;
1037 return this.m_sortName;
1041 #if !FEATURE_CORECLR
1042 [System.Runtime.InteropServices.ComVisible(false)]
1043 public String IetfLanguageTag
1047 Contract.Ensures(Contract.Result<String>() != null);
1049 // special case the compatibility cultures
1063 ////////////////////////////////////////////////////////////////////////
1067 // Returns the full name of the CultureInfo in the localized language.
1068 // For example, if the localized language of the runtime is Spanish and the CultureInfo is
1069 // US English, "Ingles (Estados Unidos)" will be returned.
1071 ////////////////////////////////////////////////////////////////////////
1072 public virtual String DisplayName
1074 [System.Security.SecuritySafeCritical] // auto-generated
1077 Contract.Ensures(Contract.Result<String>() != null);
1078 Contract.Assert(m_name != null, "[CultureInfo.DisplayName]Always expect m_name to be set");
1080 return m_cultureData.SLOCALIZEDDISPLAYNAME;
1084 ////////////////////////////////////////////////////////////////////////
1088 // Returns the full name of the CultureInfo in the native language.
1089 // For example, if the CultureInfo is US English, "English
1090 // (United States)" will be returned.
1092 ////////////////////////////////////////////////////////////////////////
1093 public virtual String NativeName {
1094 [System.Security.SecuritySafeCritical] // auto-generated
1096 Contract.Ensures(Contract.Result<String>() != null);
1097 return (this.m_cultureData.SNATIVEDISPLAYNAME);
1101 ////////////////////////////////////////////////////////////////////////
1105 // Returns the full name of the CultureInfo in English.
1106 // For example, if the CultureInfo is US English, "English
1107 // (United States)" will be returned.
1109 ////////////////////////////////////////////////////////////////////////
1110 public virtual String EnglishName {
1111 [System.Security.SecuritySafeCritical] // auto-generated
1113 Contract.Ensures(Contract.Result<String>() != null);
1114 return (this.m_cultureData.SENGDISPLAYNAME);
1119 public virtual String TwoLetterISOLanguageName {
1120 [System.Security.SecuritySafeCritical] // auto-generated
1122 Contract.Ensures(Contract.Result<String>() != null);
1123 return (this.m_cultureData.SISO639LANGNAME);
1127 #if !FEATURE_CORECLR
1129 public virtual String ThreeLetterISOLanguageName {
1130 [System.Security.SecuritySafeCritical] // auto-generated
1132 Contract.Ensures(Contract.Result<String>() != null);
1133 return (this.m_cultureData.SISO639LANGNAME2);
1137 ////////////////////////////////////////////////////////////////////////
1139 // ThreeLetterWindowsLanguageName
1141 // Returns the 3 letter windows language name for the current instance. eg: "ENU"
1142 // The ISO names are much preferred
1144 ////////////////////////////////////////////////////////////////////////
1145 public virtual String ThreeLetterWindowsLanguageName {
1146 [System.Security.SecuritySafeCritical] // auto-generated
1148 Contract.Ensures(Contract.Result<String>() != null);
1149 return (this.m_cultureData.SABBREVLANGNAME);
1154 ////////////////////////////////////////////////////////////////////////
1156 // CompareInfo Read-Only Property
1158 // Gets the CompareInfo for this culture.
1160 ////////////////////////////////////////////////////////////////////////
1161 public virtual CompareInfo CompareInfo
1165 Contract.Ensures(Contract.Result<CompareInfo>() != null);
1167 if (this.compareInfo == null)
1169 // Since CompareInfo's don't have any overrideable properties, get the CompareInfo from
1170 // the Non-Overridden CultureInfo so that we only create one CompareInfo per culture
1171 CompareInfo temp = UseUserOverride
1172 ? GetCultureInfo(this.m_name).CompareInfo
1173 : new CompareInfo(this);
1174 if (CompatibilitySwitches.IsCompatibilityBehaviorDefined)
1176 this.compareInfo = temp;
1183 return (compareInfo);
1187 #if !FEATURE_CORECLR
1188 ////////////////////////////////////////////////////////////////////////
1192 // Gets the RegionInfo for this culture.
1194 ////////////////////////////////////////////////////////////////////////
1195 private RegionInfo Region
1199 if (regionInfo==null)
1201 // Make a new regionInfo
1202 RegionInfo tempRegionInfo = new RegionInfo(this.m_cultureData);
1203 regionInfo = tempRegionInfo;
1205 return (regionInfo);
1208 #endif // FEATURE_CORECLR
1212 ////////////////////////////////////////////////////////////////////////
1216 // Gets the TextInfo for this culture.
1218 ////////////////////////////////////////////////////////////////////////
1221 public virtual TextInfo TextInfo {
1223 Contract.Ensures(Contract.Result<TextInfo>() != null);
1227 // Make a new textInfo
1228 TextInfo tempTextInfo = new TextInfo(this.m_cultureData);
1229 tempTextInfo.SetReadOnlyState(m_isReadOnly);
1231 if (CompatibilitySwitches.IsCompatibilityBehaviorDefined)
1233 textInfo = tempTextInfo;
1237 return tempTextInfo;
1244 ////////////////////////////////////////////////////////////////////////
1248 // Implements Object.Equals(). Returns a boolean indicating whether
1249 // or not object refers to the same CultureInfo as the current instance.
1251 ////////////////////////////////////////////////////////////////////////
1254 public override bool Equals(Object value)
1256 if (Object.ReferenceEquals(this, value))
1259 CultureInfo that = value as CultureInfo;
1263 // using CompareInfo to verify the data passed through the constructor
1264 // CultureInfo(String cultureName, String textAndCompareCultureName)
1266 return (this.Name.Equals(that.Name) && this.CompareInfo.Equals(that.CompareInfo));
1273 ////////////////////////////////////////////////////////////////////////
1277 // Implements Object.GetHashCode(). Returns the hash code for the
1278 // CultureInfo. The hash code is guaranteed to be the same for CultureInfo A
1279 // and B where A.Equals(B) is true.
1281 ////////////////////////////////////////////////////////////////////////
1283 public override int GetHashCode()
1285 return (this.Name.GetHashCode() + this.CompareInfo.GetHashCode());
1289 ////////////////////////////////////////////////////////////////////////
1293 // Implements Object.ToString(). Returns the name of the CultureInfo,
1294 // eg. "de-DE_phoneb", "en-US", or "fj-FJ".
1296 ////////////////////////////////////////////////////////////////////////
1299 public override String ToString()
1301 Contract.Ensures(Contract.Result<String>() != null);
1303 Contract.Assert(m_name != null, "[CultureInfo.ToString]Always expect m_name to be set");
1308 public virtual Object GetFormat(Type formatType) {
1309 if (formatType == typeof(NumberFormatInfo)) {
1310 return (NumberFormat);
1312 if (formatType == typeof(DateTimeFormatInfo)) {
1313 return (DateTimeFormat);
1318 public virtual bool IsNeutralCulture {
1320 return this.m_cultureData.IsNeutralCulture;
1324 #if !FEATURE_CORECLR
1325 [System.Runtime.InteropServices.ComVisible(false)]
1326 public CultureTypes CultureTypes
1330 CultureTypes types = 0;
1332 if (m_cultureData.IsNeutralCulture)
1333 types |= CultureTypes.NeutralCultures;
1335 types |= CultureTypes.SpecificCultures;
1337 types |= m_cultureData.IsWin32Installed ? CultureTypes.InstalledWin32Cultures : 0;
1339 // Disable warning 618: System.Globalization.CultureTypes.FrameworkCultures' is obsolete
1340 #pragma warning disable 618
1341 types |= m_cultureData.IsFramework ? CultureTypes.FrameworkCultures : 0;
1343 #pragma warning restore 618
1344 types |= m_cultureData.IsSupplementalCustomCulture ? CultureTypes.UserCustomCulture : 0;
1345 types |= m_cultureData.IsReplacementCulture ? CultureTypes.ReplacementCultures | CultureTypes.UserCustomCulture : 0;
1352 public virtual NumberFormatInfo NumberFormat {
1355 Contract.Ensures(Contract.Result<NumberFormatInfo>() != null);
1357 if (numInfo == null) {
1358 NumberFormatInfo temp = new NumberFormatInfo(this.m_cultureData);
1359 temp.isReadOnly = m_isReadOnly;
1365 if (value == null) {
1366 throw new ArgumentNullException("value",
1367 Environment.GetResourceString("ArgumentNull_Obj"));
1369 Contract.EndContractBlock();
1375 ////////////////////////////////////////////////////////////////////////
1377 // GetDateTimeFormatInfo
1379 // Create a DateTimeFormatInfo, and fill in the properties according to
1382 ////////////////////////////////////////////////////////////////////////
1385 public virtual DateTimeFormatInfo DateTimeFormat {
1387 Contract.Ensures(Contract.Result<DateTimeFormatInfo>() != null);
1389 if (dateTimeInfo == null) {
1390 // Change the calendar of DTFI to the specified calendar of this CultureInfo.
1391 DateTimeFormatInfo temp = new DateTimeFormatInfo(
1392 this.m_cultureData, this.Calendar);
1393 temp.m_isReadOnly = m_isReadOnly;
1394 System.Threading.Thread.MemoryBarrier();
1395 dateTimeInfo = temp;
1397 return (dateTimeInfo);
1401 if (value == null) {
1402 throw new ArgumentNullException("value",
1403 Environment.GetResourceString("ArgumentNull_Obj"));
1405 Contract.EndContractBlock();
1407 dateTimeInfo = value;
1413 public void ClearCachedData() {
1414 s_userDefaultUICulture = null;
1415 s_userDefaultCulture = null;
1417 RegionInfo.s_currentRegionInfo = null;
1418 #if !FEATURE_CORECLR // System.TimeZone does not exist in CoreCLR
1419 TimeZone.ResetTimeZone();
1420 #endif // FEATURE_CORECLR
1421 TimeZoneInfo.ClearCachedData();
1422 // Delete the cached cultures.
1423 s_LcidCachedCultures = null;
1424 s_NameCachedCultures = null;
1426 CultureData.ClearCachedData();
1429 /*=================================GetCalendarInstance==========================
1430 **Action: Map a Win32 CALID to an instance of supported calendar.
1431 **Returns: An instance of calendar.
1432 **Arguments: calType The Win32 CALID
1434 ** Shouldn't throw exception since the calType value is from our data table or from Win32 registry.
1435 ** If we are in trouble (like getting a weird value from Win32 registry), just return the GregorianCalendar.
1436 ============================================================================*/
1437 internal static Calendar GetCalendarInstance(int calType) {
1438 if (calType==Calendar.CAL_GREGORIAN) {
1439 return (new GregorianCalendar());
1441 return GetCalendarInstanceRare(calType);
1444 //This function exists as a shortcut to prevent us from loading all of the non-gregorian
1445 //calendars unless they're required.
1446 internal static Calendar GetCalendarInstanceRare(int calType) {
1447 Contract.Assert(calType!=Calendar.CAL_GREGORIAN, "calType!=Calendar.CAL_GREGORIAN");
1450 case Calendar.CAL_GREGORIAN_US: // Gregorian (U.S.) calendar
1451 case Calendar.CAL_GREGORIAN_ME_FRENCH: // Gregorian Middle East French calendar
1452 case Calendar.CAL_GREGORIAN_ARABIC: // Gregorian Arabic calendar
1453 case Calendar.CAL_GREGORIAN_XLIT_ENGLISH: // Gregorian Transliterated English calendar
1454 case Calendar.CAL_GREGORIAN_XLIT_FRENCH: // Gregorian Transliterated French calendar
1455 return (new GregorianCalendar((GregorianCalendarTypes)calType));
1456 case Calendar.CAL_TAIWAN: // Taiwan Era calendar
1457 return (new TaiwanCalendar());
1458 case Calendar.CAL_JAPAN: // Japanese Emperor Era calendar
1459 return (new JapaneseCalendar());
1460 case Calendar.CAL_KOREA: // Korean Tangun Era calendar
1461 return (new KoreanCalendar());
1462 case Calendar.CAL_THAI: // Thai calendar
1463 return (new ThaiBuddhistCalendar());
1464 case Calendar.CAL_HIJRI: // Hijri (Arabic Lunar) calendar
1465 return (new HijriCalendar());
1466 case Calendar.CAL_HEBREW: // Hebrew (Lunar) calendar
1467 return (new HebrewCalendar());
1468 case Calendar.CAL_UMALQURA:
1469 return (new UmAlQuraCalendar());
1470 case Calendar.CAL_PERSIAN:
1471 return (new PersianCalendar());
1472 case Calendar.CAL_CHINESELUNISOLAR:
1473 return (new ChineseLunisolarCalendar());
1474 case Calendar.CAL_JAPANESELUNISOLAR:
1475 return (new JapaneseLunisolarCalendar());
1476 case Calendar.CAL_KOREANLUNISOLAR:
1477 return (new KoreanLunisolarCalendar());
1478 case Calendar.CAL_TAIWANLUNISOLAR:
1479 return (new TaiwanLunisolarCalendar());
1481 return (new GregorianCalendar());
1485 /*=================================Calendar==========================
1486 **Action: Return/set the default calendar used by this culture.
1487 ** This value can be overridden by regional option if this is a current culture.
1491 ** ArgumentNull_Obj if the set value is null.
1492 ============================================================================*/
1495 public virtual Calendar Calendar {
1497 Contract.Ensures(Contract.Result<Calendar>() != null);
1498 if (calendar == null) {
1499 Contract.Assert(this.m_cultureData.CalendarIds.Length > 0, "this.m_cultureData.CalendarIds.Length > 0");
1500 // Get the default calendar for this culture. Note that the value can be
1501 // from registry if this is a user default culture.
1502 Calendar newObj = this.m_cultureData.DefaultCalendar;
1504 System.Threading.Thread.MemoryBarrier();
1505 newObj.SetReadOnlyState(m_isReadOnly);
1512 /*=================================OptionCalendars==========================
1513 **Action: Return an array of the optional calendar for this culture.
1514 **Returns: an array of Calendar.
1517 ============================================================================*/
1520 public virtual Calendar[] OptionalCalendars {
1522 Contract.Ensures(Contract.Result<Calendar[]>() != null);
1525 // This property always returns a new copy of the calendar array.
1527 int[] calID = this.m_cultureData.CalendarIds;
1528 Calendar [] cals = new Calendar[calID.Length];
1529 for (int i = 0; i < cals.Length; i++) {
1530 cals[i] = GetCalendarInstance(calID[i]);
1537 public bool UseUserOverride {
1539 return (this.m_cultureData.UseUserOverride);
1543 #if !FEATURE_CORECLR
1544 [System.Security.SecuritySafeCritical] // auto-generated
1545 [System.Runtime.InteropServices.ComVisible(false)]
1546 public CultureInfo GetConsoleFallbackUICulture()
1548 Contract.Ensures(Contract.Result<CultureInfo>() != null);
1550 CultureInfo temp = m_consoleFallbackCulture;
1553 temp = CreateSpecificCulture(this.m_cultureData.SCONSOLEFALLBACKNAME);
1554 temp.m_isReadOnly = true;
1555 m_consoleFallbackCulture = temp;
1561 public virtual Object Clone()
1563 Contract.Ensures(Contract.Result<Object>() != null);
1565 CultureInfo ci = (CultureInfo)MemberwiseClone();
1566 ci.m_isReadOnly = false;
1568 //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
1569 //they've already been allocated. If this is a derived type, we'll take a more generic codepath.
1572 if (this.dateTimeInfo != null)
1574 ci.dateTimeInfo = (DateTimeFormatInfo)this.dateTimeInfo.Clone();
1576 if (this.numInfo != null)
1578 ci.numInfo = (NumberFormatInfo)this.numInfo.Clone();
1584 ci.DateTimeFormat = (DateTimeFormatInfo)this.DateTimeFormat.Clone();
1585 ci.NumberFormat = (NumberFormatInfo)this.NumberFormat.Clone();
1588 if (textInfo != null)
1590 ci.textInfo = (TextInfo) textInfo.Clone();
1593 if (calendar != null)
1595 ci.calendar = (Calendar) calendar.Clone();
1602 public static CultureInfo ReadOnly(CultureInfo ci) {
1604 throw new ArgumentNullException("ci");
1606 Contract.Ensures(Contract.Result<CultureInfo>() != null);
1607 Contract.EndContractBlock();
1609 if (ci.IsReadOnly) {
1612 CultureInfo newInfo = (CultureInfo)(ci.MemberwiseClone());
1614 if (!ci.IsNeutralCulture)
1616 //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
1617 //they've already been allocated. If this is a derived type, we'll take a more generic codepath.
1618 if (!ci.m_isInherited) {
1619 if (ci.dateTimeInfo != null) {
1620 newInfo.dateTimeInfo = DateTimeFormatInfo.ReadOnly(ci.dateTimeInfo);
1622 if (ci.numInfo != null) {
1623 newInfo.numInfo = NumberFormatInfo.ReadOnly(ci.numInfo);
1627 newInfo.DateTimeFormat = DateTimeFormatInfo.ReadOnly(ci.DateTimeFormat);
1628 newInfo.NumberFormat = NumberFormatInfo.ReadOnly(ci.NumberFormat);
1632 if (ci.textInfo != null)
1634 newInfo.textInfo = TextInfo.ReadOnly(ci.textInfo);
1637 if (ci.calendar != null)
1639 newInfo.calendar = Calendar.ReadOnly(ci.calendar);
1642 // Don't set the read-only flag too early.
1643 // We should set the read-only flag here. Otherwise, info.DateTimeFormat will not be able to set.
1644 newInfo.m_isReadOnly = true;
1650 public bool IsReadOnly {
1652 return (m_isReadOnly);
1656 private void VerifyWritable() {
1658 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
1660 Contract.EndContractBlock();
1663 // For resource lookup, we consider a culture the invariant culture by name equality.
1664 // We perform this check frequently during resource lookup, so adding a property for
1665 // improved readability.
1666 internal bool HasInvariantCultureName
1668 get { return Name == CultureInfo.InvariantCulture.Name; }
1671 // Helper function both both overloads of GetCachedReadOnlyCulture. If lcid is 0, we use the name.
1672 // If lcid is -1, use the altName and create one of those special SQL cultures.
1673 internal static CultureInfo GetCultureInfoHelper(int lcid, string name, string altName)
1675 // There is a race condition in this code with the side effect that the second thread's value
1676 // clobbers the first in the dictionary. This is an acceptable race condition since the CultureInfo objects
1677 // are content equal (but not reference equal). Since we make no guarantees there, this race condition is
1679 // See code:Dictionary#DictionaryVersusHashtableThreadSafety for details on Dictionary versus
1680 // Hashtable thread safety.
1682 // retval is our return value.
1685 // Temporary hashtable for the names.
1686 Hashtable tempNameHT = s_NameCachedCultures;
1690 name = CultureData.AnsiToLower(name);
1693 if (altName != null)
1695 altName = CultureData.AnsiToLower(altName);
1698 // We expect the same result for both hashtables, but will test individually for added safety.
1699 if (tempNameHT == null)
1701 tempNameHT = Hashtable.Synchronized(new Hashtable());
1705 // If we are called by name, check if the object exists in the hashtable. If so, return it.
1708 retval = (CultureInfo)tempNameHT[name + '\xfffd' + altName];
1716 retval = (CultureInfo)tempNameHT[name];
1723 #if FEATURE_USE_LCID
1724 // Next, the Lcid table.
1725 Hashtable tempLcidHT = s_LcidCachedCultures;
1727 if (tempLcidHT == null)
1729 // Case insensitive is not an issue here, save the constructor call.
1730 tempLcidHT = Hashtable.Synchronized(new Hashtable());
1734 // If we were called by Lcid, check if the object exists in the table. If so, return it.
1737 retval = (CultureInfo) tempLcidHT[lcid];
1745 // We now have two temporary hashtables and the desired object was not found.
1746 // We'll construct it. We catch any exceptions from the constructor call and return null.
1752 // call the private constructor
1753 retval = new CultureInfo(name, altName);
1757 retval = new CultureInfo(name, false);
1761 #if FEATURE_USE_LCID
1762 retval = new CultureInfo(lcid, false);
1769 catch(ArgumentException)
1774 // Set it to read-only
1775 retval.m_isReadOnly = true;
1779 // This new culture will be added only to the name hash table.
1780 tempNameHT[name + '\xfffd' + altName] = retval;
1782 // when lcid == -1 then TextInfo object is already get created and we need to set it as read only.
1783 retval.TextInfo.SetReadOnlyState(true);
1787 // Remember our name (as constructed). Do NOT use alternate sort name versions because
1788 // we have internal state representing the sort. (So someone would get the wrong cached version)
1789 string newName = CultureData.AnsiToLower(retval.m_name);
1791 // We add this new culture info object to both tables.
1792 tempNameHT[newName] = retval;
1793 #if FEATURE_USE_LCID
1794 const int LCID_ZH_CHS_HANS = 0x0004;
1795 const int LCID_ZH_CHT_HANT = 0x7c04;
1797 if ((retval.LCID == LCID_ZH_CHS_HANS && newName == "zh-hans")
1798 || (retval.LCID == LCID_ZH_CHT_HANT && newName == "zh-hant"))
1800 // do nothing because we only want zh-CHS and zh-CHT to cache
1805 tempLcidHT[retval.LCID] = retval;
1811 #if FEATURE_USE_LCID
1812 // Copy the two hashtables to the corresponding member variables. This will potentially overwrite
1813 // new tables simultaneously created by a new thread, but maximizes thread safety.
1816 // Only when we modify the lcid hash table, is there a need to overwrite.
1817 s_LcidCachedCultures = tempLcidHT;
1821 s_NameCachedCultures = tempNameHT;
1823 // Finally, return our new CultureInfo object.
1827 #if FEATURE_USE_LCID
1828 // Gets a cached copy of the specified culture from an internal hashtable (or creates it
1829 // if not found). (LCID version)... use named version
1830 public static CultureInfo GetCultureInfo(int culture)
1832 // Must check for -1 now since the helper function uses the value to signal
1833 // the altCulture code path for SQL Server.
1834 // Also check for zero as this would fail trying to add as a key to the hash.
1836 throw new ArgumentOutOfRangeException("culture",
1837 Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
1839 Contract.Ensures(Contract.Result<CultureInfo>() != null);
1840 Contract.EndContractBlock();
1841 CultureInfo retval = GetCultureInfoHelper(culture, null, null);
1844 throw new CultureNotFoundException(
1845 "culture", culture, Environment.GetResourceString("Argument_CultureNotSupported"));
1851 // Gets a cached copy of the specified culture from an internal hashtable (or creates it
1852 // if not found). (Named version)
1853 public static CultureInfo GetCultureInfo(string name)
1855 // Make sure we have a valid, non-zero length string as name
1858 throw new ArgumentNullException("name");
1860 Contract.Ensures(Contract.Result<CultureInfo>() != null);
1861 Contract.EndContractBlock();
1863 CultureInfo retval = GetCultureInfoHelper(0, name, null);
1866 throw new CultureNotFoundException(
1867 "name", name, Environment.GetResourceString("Argument_CultureNotSupported"));
1873 // Gets a cached copy of the specified culture from an internal hashtable (or creates it
1875 public static CultureInfo GetCultureInfo(string name, string altName)
1877 // Make sure we have a valid, non-zero length string as name
1880 throw new ArgumentNullException("name");
1883 if (null == altName)
1885 throw new ArgumentNullException("altName");
1887 Contract.Ensures(Contract.Result<CultureInfo>() != null);
1888 Contract.EndContractBlock();
1890 CultureInfo retval = GetCultureInfoHelper(-1, name, altName);
1893 throw new CultureNotFoundException("name or altName",
1895 CultureInfo.CurrentCulture,
1896 Environment.GetResourceString("Argument_OneOfCulturesNotSupported"),
1904 #if !FEATURE_CORECLR
1905 // This function is deprecated, we don't like it
1906 public static CultureInfo GetCultureInfoByIetfLanguageTag(string name)
1908 Contract.Ensures(Contract.Result<CultureInfo>() != null);
1910 // Disallow old zh-CHT/zh-CHS names
1911 if (name == "zh-CHT" || name == "zh-CHS")
1913 throw new CultureNotFoundException(
1915 String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_CultureIetfNotSupported"), name)
1919 CultureInfo ci = GetCultureInfo(name);
1921 // Disallow alt sorts and es-es_TS
1922 if (ci.LCID > 0xffff || ci.LCID == 0x040a)
1924 throw new CultureNotFoundException(
1926 String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_CultureIetfNotSupported"), name)
1933 private static volatile bool s_isTaiwanSku;
1934 private static volatile bool s_haveIsTaiwanSku;
1935 internal static bool IsTaiwanSku
1939 if (!s_haveIsTaiwanSku)
1941 s_isTaiwanSku = (GetSystemDefaultUILanguage() == "zh-TW");
1942 s_haveIsTaiwanSku = true;
1944 return (bool)s_isTaiwanSku;
1952 // Get Locale Info Ex calls. So we don't have to muck with the different int/string return types we declared two of these:
1953 [System.Security.SecurityCritical] // auto-generated
1954 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1955 internal static extern String nativeGetLocaleInfoEx(String localeName, uint field);
1957 [System.Security.SecuritySafeCritical] // auto-generated
1958 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1959 internal static extern int nativeGetLocaleInfoExInt(String localeName, uint field);
1961 [System.Security.SecurityCritical] // auto-generated
1962 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1963 internal static extern bool nativeSetThreadLocale(String localeName);
1965 [System.Security.SecurityCritical]
1966 private static String GetDefaultLocaleName(int localeType)
1968 Contract.Assert(localeType == LOCALE_USER_DEFAULT || localeType == LOCALE_SYSTEM_DEFAULT, "[CultureInfo.GetDefaultLocaleName] localeType must be LOCALE_USER_DEFAULT or LOCALE_SYSTEM_DEFAULT");
1970 string localeName = null;
1971 if(InternalGetDefaultLocaleName(localeType, JitHelpers.GetStringHandleOnStack(ref localeName)))
1975 return string.Empty;
1978 // Get the default locale name
1979 [System.Security.SecurityCritical] // auto-generated
1980 [SuppressUnmanagedCodeSecurity]
1981 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
1982 [return: MarshalAs(UnmanagedType.Bool)]
1983 private static extern bool InternalGetDefaultLocaleName(int localetype, StringHandleOnStack localeString);
1985 [System.Security.SecuritySafeCritical] // auto-generated
1986 private static String GetUserDefaultUILanguage()
1988 string userDefaultUiLanguage = null;
1989 if(InternalGetUserDefaultUILanguage(JitHelpers.GetStringHandleOnStack(ref userDefaultUiLanguage)))
1991 return userDefaultUiLanguage;
1993 return String.Empty;
1996 // Get the user's default UI language, return locale name
1997 [System.Security.SecurityCritical] // auto-generated
1998 [SuppressUnmanagedCodeSecurity]
1999 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
2000 [return: MarshalAs(UnmanagedType.Bool)]
2001 private static extern bool InternalGetUserDefaultUILanguage(StringHandleOnStack userDefaultUiLanguage);
2003 [System.Security.SecuritySafeCritical] // auto-generated
2004 private static String GetSystemDefaultUILanguage()
2006 string systemDefaultUiLanguage = null;
2007 if(InternalGetSystemDefaultUILanguage(JitHelpers.GetStringHandleOnStack(ref systemDefaultUiLanguage)))
2009 return systemDefaultUiLanguage;
2011 return String.Empty;
2015 [System.Security.SecurityCritical] // auto-generated
2016 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2017 [SuppressUnmanagedCodeSecurity]
2018 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
2019 [return: MarshalAs(UnmanagedType.Bool)]
2020 private static extern bool InternalGetSystemDefaultUILanguage(StringHandleOnStack systemDefaultUiLanguage);
2022 // Added but disabled from desktop in .NET 4.0, stayed disabled in .NET 4.5
2024 [System.Security.SecurityCritical] // auto-generated
2025 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2026 internal static extern String[] nativeGetResourceFallbackArray();