3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 ////////////////////////////////////////////////////////////////////////////
11 // Purpose: This class represents the software preferences of a particular
12 // culture or community. It includes information such as the
13 // language, writing system, and a calendar used by the culture
14 // as well as methods for common operations such as printing
15 // dates and sorting strings.
17 // Date: Microsoft 31, 1999
20 // !!!! NOTE WHEN CHANGING THIS CLASS !!!!
22 // If adding or removing members to this class, please update CultureInfoBaseObject
23 // in ndp/clr/src/vm/object.h. Note, the "actual" layout of the class may be
24 // different than the order in which members are declared. For instance, all
25 // reference types will come first in the class before value types (like ints, bools, etc)
26 // regardless of the order in which they are declared. The best way to see the
27 // actual order of the class is to do a !dumpobj on an instance of the managed
28 // object inside of the debugger.
30 ////////////////////////////////////////////////////////////////////////////
32 namespace System.Globalization {
34 using System.Security;
35 using System.Threading;
36 using System.Collections;
38 using System.Runtime.CompilerServices;
39 using System.Runtime.InteropServices;
40 using System.Runtime.Serialization;
41 using System.Runtime.Versioning;
42 using System.Security.Permissions;
43 using System.Reflection;
44 using Microsoft.Win32;
45 using System.Diagnostics.Contracts;
46 using System.Resources;
49 [System.Runtime.InteropServices.ComVisible(true)]
50 public class CultureInfo : ICloneable, IFormatProvider {
51 //--------------------------------------------------------------------//
52 // Internal Information //
53 //--------------------------------------------------------------------//
55 //--------------------------------------------------------------------//
56 // Data members to be serialized:
57 //--------------------------------------------------------------------//
59 // We use an RFC4646 type string to construct CultureInfo.
60 // This string is stored in m_name and is authoritative.
61 // We use the m_cultureData to get the data for our object
64 // WARNING: All member fields declared here must also be in ndp/clr/src/vm/object.h
65 // WARNING: They aren't really private because object.h can access them, but other C# stuff cannot
66 // WARNING: The type loader will rearrange class member offsets so the mscorwks!CultureInfoBaseObject
67 // WARNING: must be manually structured to match the true loaded class layout
69 internal bool m_isReadOnly;
70 internal CompareInfo compareInfo;
71 internal TextInfo textInfo;
72 // Not serialized for now since we only build it privately for use in the CARIB (so rebuilding is OK)
74 [NonSerialized]internal RegionInfo regionInfo;
76 internal NumberFormatInfo numInfo;
77 internal DateTimeFormatInfo dateTimeInfo;
78 internal Calendar calendar;
80 [OptionalField(VersionAdded = 1)]
81 internal int m_dataItem; // NEVER USED, DO NOT USE THIS! (Serialized in Whidbey/Everett)
82 [OptionalField(VersionAdded = 1)]
83 internal int cultureID = 0x007f; // NEVER USED, DO NOT USE THIS! (Serialized in Whidbey/Everett)
84 #endif // !FEATURE_CORECLR
86 // The CultureData instance that we are going to read data from.
87 // For supported culture, this will be the CultureData instance that read data from mscorlib assembly.
88 // For customized culture, this will be the CultureData instance that read data from user customized culture binary file.
90 [NonSerialized]internal CultureData m_cultureData;
92 [NonSerialized]internal bool m_isInherited;
93 #if FEATURE_LEAK_CULTURE_INFO
94 [NonSerialized]private bool m_isSafeCrossDomain;
95 [NonSerialized]private int m_createdDomainID;
96 #endif // !FEATURE_CORECLR
98 [NonSerialized]private CultureInfo m_consoleFallbackCulture;
99 #endif // !FEATURE_CORECLR
101 // Names are confusing. Here are 3 names we have:
103 // new CultureInfo() m_name m_nonSortName m_sortName
104 // en-US en-US en-US en-US
105 // de-de_phoneb de-DE_phoneb de-DE de-DE_phoneb
106 // fj-fj (custom) fj-FJ fj-FJ en-US (if specified sort is en-US)
109 // Note that in Silverlight we ask the OS for the text and sort behavior, so the
110 // textinfo and compareinfo names are the same as the name
112 // Note that the name used to be serialized for Everett; it is now serialized
113 // because alernate sorts can have alternate names.
114 // This has a de-DE, de-DE_phoneb or fj-FJ style name
115 internal string m_name;
117 // This will hold the non sorting name to be returned from CultureInfo.Name property.
118 // This has a de-DE style name even for de-DE_phoneb type cultures
119 [NonSerialized]private string m_nonSortName;
121 // This will hold the sorting name to be returned from CultureInfo.SortName property.
122 // This might be completely unrelated to the culture name if a custom culture. Ie en-US for fj-FJ.
123 // Otherwise its the sort name, ie: de-DE or de-DE_phoneb
124 [NonSerialized]private string m_sortName;
127 //--------------------------------------------------------------------//
129 // Static data members
131 //--------------------------------------------------------------------//
133 //Get the current user default culture. This one is almost always used, so we create it by default.
134 private static volatile CultureInfo s_userDefaultCulture;
137 // All of the following will be created on demand.
140 //The Invariant culture;
141 private static volatile CultureInfo s_InvariantCultureInfo;
143 //The culture used in the user interface. This is mostly used to load correct localized resources.
144 private static volatile CultureInfo s_userDefaultUICulture;
146 //This is the UI culture used to install the OS.
147 private static volatile CultureInfo s_InstalledUICultureInfo;
149 //These are defaults that we use if a thread has not opted into having an explicit culture
150 private static volatile CultureInfo s_DefaultThreadCurrentUICulture;
151 private static volatile CultureInfo s_DefaultThreadCurrentCulture;
153 //This is a cache of all previously created cultures. Valid keys are LCIDs or the name. We use two hashtables to track them,
154 // depending on how they are called.
155 private static volatile Hashtable s_LcidCachedCultures;
156 private static volatile Hashtable s_NameCachedCultures;
159 // When running under AppX, we use this to get some information about the language list
161 private static volatile WindowsRuntimeResourceManagerBase s_WindowsRuntimeResourceManager;
164 private static bool ts_IsDoingAppXCultureInfoLookup;
167 //The parent culture.
168 [NonSerialized]private CultureInfo m_parent;
170 // LOCALE constants of interest to us internally and privately for LCID functions
171 // (ie: avoid using these and use names if possible)
172 internal const int LOCALE_NEUTRAL = 0x0000;
173 private const int LOCALE_USER_DEFAULT = 0x0400;
174 private const int LOCALE_SYSTEM_DEFAULT = 0x0800;
175 internal const int LOCALE_CUSTOM_DEFAULT = 0x0c00;
176 internal const int LOCALE_CUSTOM_UNSPECIFIED = 0x1000;
177 internal const int LOCALE_INVARIANT = 0x007F;
178 private const int LOCALE_TRADITIONAL_SPANISH = 0x040a;
181 // The CultureData instance that reads the data provided by our CultureData class.
183 //Using a field initializer rather than a static constructor so that the whole class can be lazy
185 private static readonly bool init = Init();
186 private static bool Init()
189 if (s_InvariantCultureInfo == null)
191 CultureInfo temp = new CultureInfo("", false);
192 temp.m_isReadOnly = true;
193 s_InvariantCultureInfo = temp;
195 // First we set it to Invariant in case someone needs it before we're done finding it.
196 // For example, if we throw an exception in InitUserDefaultCulture, we will still need an valid
197 // s_userDefaultCulture to be used in Thread.CurrentCulture.
198 s_userDefaultCulture = s_userDefaultUICulture = s_InvariantCultureInfo;
200 s_userDefaultCulture = InitUserDefaultCulture();
201 s_userDefaultUICulture = InitUserDefaultUICulture();
205 [System.Security.SecuritySafeCritical] // auto-generated
206 static CultureInfo InitUserDefaultCulture()
208 String strDefault = GetDefaultLocaleName(LOCALE_USER_DEFAULT);
209 if (strDefault == null)
211 strDefault = GetDefaultLocaleName(LOCALE_SYSTEM_DEFAULT);
213 if (strDefault == null)
215 // If system default doesn't work, keep using the invariant
216 return (CultureInfo.InvariantCulture);
219 CultureInfo temp = GetCultureByName(strDefault, true);
221 temp.m_isReadOnly = true;
226 static CultureInfo InitUserDefaultUICulture()
228 String strDefault = GetUserDefaultUILanguage();
230 // In most of cases, UserDefaultCulture == UserDefaultUICulture, so we should use the same instance if possible.
231 if (strDefault == UserDefaultCulture.Name)
233 return (UserDefaultCulture);
236 CultureInfo temp = GetCultureByName( strDefault, true);
240 return (CultureInfo.InvariantCulture);
243 temp.m_isReadOnly = true;
249 [SecuritySafeCritical]
250 internal static CultureInfo GetCultureInfoForUserPreferredLanguageInAppX()
252 // If a call to GetCultureInfoForUserPreferredLanguageInAppX() generated a recursive
253 // call to itself, return null, since we don't want to stack overflow. For example,
254 // this can happen if some code in this method ends up calling CultureInfo.CurrentCulture
255 // (which is common on check'd build because of BCLDebug logging which calls Int32.ToString()).
256 // In this case, returning null will mean CultureInfo.CurrentCulture gets the default Win32
257 // value, which should be fine.
258 if(ts_IsDoingAppXCultureInfoLookup)
263 // If running within a compilation process (mscorsvw.exe, for example), it is illegal to
264 // load any non-mscorlib assembly for execution. Since WindowsRuntimeResourceManager lives
265 // in System.Runtime.WindowsRuntime, caller will need to fall back to default Win32 value,
266 // which should be fine because we should only ever need to access FX resources during NGEN.
267 // FX resources are always loaded from satellite assemblies - even in AppX processes (see the
268 // comments in code:System.Resources.ResourceManager.SetAppXConfiguration for more details).
269 if (AppDomain.IsAppXNGen)
274 CultureInfo toReturn = null;
278 ts_IsDoingAppXCultureInfoLookup = true;
280 if(s_WindowsRuntimeResourceManager == null)
282 s_WindowsRuntimeResourceManager = ResourceManager.GetWinRTResourceManager();
285 toReturn = s_WindowsRuntimeResourceManager.GlobalResourceContextBestFitCultureInfo;
289 ts_IsDoingAppXCultureInfoLookup = false;
295 [SecuritySafeCritical]
296 internal static bool SetCultureInfoForUserPreferredLanguageInAppX(CultureInfo ci)
298 // If running within a compilation process (mscorsvw.exe, for example), it is illegal to
299 // load any non-mscorlib assembly for execution. Since WindowsRuntimeResourceManager lives
300 // in System.Runtime.WindowsRuntime, caller will need to fall back to default Win32 value,
301 // which should be fine because we should only ever need to access FX resources during NGEN.
302 // FX resources are always loaded from satellite assemblies - even in AppX processes (see the
303 // comments in code:System.Resources.ResourceManager.SetAppXConfiguration for more details).
304 if (AppDomain.IsAppXNGen)
309 if (s_WindowsRuntimeResourceManager == null)
311 s_WindowsRuntimeResourceManager = ResourceManager.GetWinRTResourceManager();
314 return s_WindowsRuntimeResourceManager.SetGlobalResourceContextDefaultCulture(ci);
318 ////////////////////////////////////////////////////////////////////////
320 // CultureInfo Constructors
322 ////////////////////////////////////////////////////////////////////////
325 public CultureInfo(String name) : this(name, true) {
329 public CultureInfo(String name, bool useUserOverride) {
331 throw new ArgumentNullException("name",
332 Environment.GetResourceString("ArgumentNull_String"));
334 Contract.EndContractBlock();
336 #if FEATURE_LEGACYNETCF
337 // Windows Phone 7 and 7.1 do not support Bengali. When running on Windows Phone 8,
338 // WinPhone 7.x apps get the old Mango text stack, not the Apollo text stack. The Mango
339 // text stack cannot display characters in Bengali, such as the culture's native name.
340 // Phone apps are already written to catch an exception here and bypass this culture.
341 if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8 &&
342 (name == "bn" || name == "bn-BD" || name == "bn-IN" || name == "ml" || name == "or"))
343 throw new ArgumentException(Environment.GetResourceString("Argument_CultureNotSupported"));
346 // Get our data providing record
347 this.m_cultureData = CultureData.GetCultureData(name, useUserOverride);
349 if (this.m_cultureData == null) {
350 #if FEATURE_LEGACYNETCF
351 if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
352 throw new PlatformNotSupportedException(Environment.GetResourceString("Argument_CultureNotSupported"));
354 throw new CultureNotFoundException("name", name, Environment.GetResourceString("Argument_CultureNotSupported"));
357 this.m_name = this.m_cultureData.CultureName;
358 this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
363 public CultureInfo(int culture) : this(culture, true) {
366 public CultureInfo(int culture, bool useUserOverride) {
367 // We don't check for other invalid LCIDS here...
369 throw new ArgumentOutOfRangeException("culture",
370 Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
372 Contract.EndContractBlock();
374 InitializeFromCultureId(culture, useUserOverride);
377 private void InitializeFromCultureId(int culture, bool useUserOverride)
381 case LOCALE_CUSTOM_DEFAULT:
382 case LOCALE_SYSTEM_DEFAULT:
384 case LOCALE_USER_DEFAULT:
385 case LOCALE_CUSTOM_UNSPECIFIED:
386 // Can't support unknown custom cultures and we do not support neutral or
387 // non-custom user locales.
388 throw new CultureNotFoundException(
389 "culture", culture, Environment.GetResourceString("Argument_CultureNotSupported"));
392 // Now see if this LCID is supported in the system default CultureData table.
393 this.m_cultureData = CultureData.GetCultureData(culture, useUserOverride);
396 this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
397 this.m_name = this.m_cultureData.CultureName;
399 #endif // FEATURE_USE_LCID
402 // CheckDomainSafetyObject throw if the object is customized object which cannot be attached to
403 // other object (like CultureInfo or DateTimeFormatInfo).
406 internal static void CheckDomainSafetyObject(Object obj, Object container)
408 if (obj.GetType().Assembly != typeof(System.Globalization.CultureInfo).Assembly) {
410 throw new InvalidOperationException(
412 CultureInfo.CurrentCulture,
413 Environment.GetResourceString("InvalidOperation_SubclassedObject"),
415 container.GetType()));
417 Contract.EndContractBlock();
420 #region Serialization
421 // We need to store the override from the culture data record.
422 private bool m_useUserOverride;
425 private void OnDeserialized(StreamingContext ctx)
428 // Whidbey+ should remember our name
429 // but v1 and v1.1 did not store name -- only lcid
430 // Whidbey did not store actual alternate sort name in m_name
431 // like we do in v4 so we can't use name for alternate sort
432 // e.g. for es-ES_tradnl: v2 puts es-ES in m_name; v4 puts es-ES_tradnl
433 if (m_name == null || IsAlternateSortLcid(cultureID))
435 Contract.Assert(cultureID >=0, "[CultureInfo.OnDeserialized] cultureID >= 0");
436 InitializeFromCultureId(cultureID, m_useUserOverride);
441 Contract.Assert(m_name != null, "[CultureInfo.OnDeserialized] m_name != null");
444 this.m_cultureData = CultureData.GetCultureData(m_name, m_useUserOverride);
445 if (this.m_cultureData == null)
446 throw new CultureNotFoundException(
447 "m_name", m_name, Environment.GetResourceString("Argument_CultureNotSupported"));
452 m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
454 // in case we have non customized CultureInfo object we shouldn't allow any customized object
455 // to be attached to it for cross app domain safety.
456 if (this.GetType().Assembly == typeof(System.Globalization.CultureInfo).Assembly)
458 if (textInfo != null)
460 CheckDomainSafetyObject(textInfo, this);
463 if (compareInfo != null)
465 CheckDomainSafetyObject(compareInfo, this);
471 // A locale ID is a 32 bit value which is the combination of a
472 // language ID, a sort ID, and a reserved area. The bits are
473 // allocated as follows:
475 // +------------------------+-------+--------------------------------+
476 // | Reserved |Sort ID| Language ID |
477 // +------------------------+-------+--------------------------------+
478 // 31 20 19 16 15 0 bit
479 private const int LOCALE_SORTID_MASK = 0x000f0000;
481 static private bool IsAlternateSortLcid(int lcid)
483 if(lcid == LOCALE_TRADITIONAL_SPANISH)
488 return (lcid & LOCALE_SORTID_MASK) != 0;
493 private void OnSerializing(StreamingContext ctx)
495 this.m_name = this.m_cultureData.CultureName;
496 this.m_useUserOverride = this.m_cultureData.UseUserOverride;
498 // for compatibility with v2 serialize cultureID
499 this.cultureID = this.m_cultureData.ILANGUAGE;
502 #endregion Serialization
504 #if FEATURE_LEAK_CULTURE_INFO
505 // Is it safe to send this CultureInfo as an instance member of a Thread cross AppDomain boundaries?
506 // For Silverlight, the answer is always no.
507 internal bool IsSafeCrossDomain {
509 Contract.Assert(m_createdDomainID != 0, "[CultureInfo.IsSafeCrossDomain] m_createdDomainID != 0");
510 return m_isSafeCrossDomain;
514 internal int CreatedDomainID {
516 Contract.Assert(m_createdDomainID != 0, "[CultureInfo.CreatedDomain] m_createdDomainID != 0");
517 return m_createdDomainID;
521 internal void StartCrossDomainTracking() {
523 // If we have decided about cross domain safety of this instance, we are done
524 if (m_createdDomainID != 0)
527 // If FEATURE_LEAK_CULTURE_INFO isn't enabled, we never want to pass
528 // CultureInfo as an instance member of a Thread.
529 if (CanSendCrossDomain())
531 m_isSafeCrossDomain = true;
534 // m_createdDomainID has to be assigned last. We use it to signal that we have
535 // completed the check.
536 System.Threading.Thread.MemoryBarrier();
537 m_createdDomainID = Thread.GetDomainID();
539 #endif // FEATURE_LEAK_CULTURE_INFO
541 // Is it safe to pass the CultureInfo cross AppDomain boundaries, not necessarily as an instance
542 // member of Thread. This is different from IsSafeCrossDomain, which implies passing the CultureInfo
543 // as a Thread instance member.
544 internal bool CanSendCrossDomain()
547 if (this.GetType() == typeof(System.Globalization.CultureInfo))
554 // Constructor called by SQL Server's special munged culture - creates a culture with
555 // a TextInfo and CompareInfo that come from a supplied alternate source. This object
556 // is ALWAYS read-only.
557 // Note that we really cannot use an LCID version of this override as the cached
558 // name we create for it has to include both names, and the logic for this is in
559 // the GetCultureInfo override *only*.
560 internal CultureInfo(String cultureName, String textAndCompareCultureName)
562 if (cultureName==null) {
563 throw new ArgumentNullException("cultureName",
564 Environment.GetResourceString("ArgumentNull_String"));
566 Contract.EndContractBlock();
568 this.m_cultureData = CultureData.GetCultureData(cultureName, false);
569 if (this.m_cultureData == null)
570 throw new CultureNotFoundException(
571 "cultureName", cultureName, Environment.GetResourceString("Argument_CultureNotSupported"));
573 this.m_name = this.m_cultureData.CultureName;
575 CultureInfo altCulture = GetCultureInfo(textAndCompareCultureName);
576 this.compareInfo = altCulture.CompareInfo;
577 this.textInfo = altCulture.TextInfo;
580 // We do this to try to return the system UI language and the default user languages
581 // The callers should have a fallback if this fails (like Invariant)
582 private static CultureInfo GetCultureByName(String name, bool userOverride)
584 // Try to get our culture
587 return userOverride ? new CultureInfo(name) : CultureInfo.GetCultureInfo(name);
589 catch (ArgumentException)
597 // Return a specific culture. A tad irrelevent now since we always return valid data
598 // for neutral locales.
600 // Note that there's interesting behavior that tries to find a smaller name, ala RFC4647,
601 // if we can't find a bigger name. That doesn't help with things like "zh" though, so
602 // the approach is of questionable value
605 public static CultureInfo CreateSpecificCulture(String name) {
606 Contract.Ensures(Contract.Result<CultureInfo>() != null);
611 culture = new CultureInfo(name);
612 } catch(ArgumentException) {
613 // When CultureInfo throws this exception, it may be because someone passed the form
614 // like "az-az" because it came out of an http accept lang. We should try a little
615 // parsing to perhaps fall back to "az" here and use *it* to create the neutral.
620 for(idx = 0; idx < name.Length; idx++) {
621 if('-' == name[idx]) {
623 culture = new CultureInfo(name.Substring(0, idx));
625 } catch(ArgumentException) {
626 // throw the original exception so the name in the string will be right
632 if(null == culture) {
633 // nothing to save here; throw the original exception
638 //In the most common case, they've given us a specific culture, so we'll just return that.
639 if (!(culture.IsNeutralCulture)) {
643 return (new CultureInfo(culture.m_cultureData.SSPECIFICCULTURE));
645 #endif // !FEATURE_CORECLR
647 internal static bool VerifyCultureName(String cultureName, bool throwException)
649 // This function is used by ResourceManager.GetResourceFileName().
650 // ResourceManager searches for resource using CultureInfo.Name,
651 // so we should check against CultureInfo.Name.
653 for (int i=0; i<cultureName.Length; i++) {
654 char c = cultureName[i];
657 if (Char.IsLetterOrDigit(c) || c=='-' || c=='_') {
660 if (throwException) {
661 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidResourceCultureName", cultureName));
669 internal static bool VerifyCultureName(CultureInfo culture, bool throwException) {
670 Contract.Assert(culture!=null, "[CultureInfo.VerifyCultureName]culture!=null");
672 //If we have an instance of one of our CultureInfos, the user can't have changed the
673 //name and we know that all names are valid in files.
674 if (!culture.m_isInherited) {
678 return VerifyCultureName(culture.Name, throwException);
682 ////////////////////////////////////////////////////////////////////////
686 // This instance provides methods based on the current user settings.
687 // These settings are volatile and may change over the lifetime of the
690 ////////////////////////////////////////////////////////////////////////
693 public static CultureInfo CurrentCulture
696 Contract.Ensures(Contract.Result<CultureInfo>() != null);
699 return Thread.CurrentThread.CurrentCulture;
701 // In the case of CoreCLR, Thread.m_CurrentCulture and
702 // Thread.m_CurrentUICulture are thread static so as not to let
703 // CultureInfo objects leak across AppDomain boundaries. The
704 // fact that these fields are thread static introduces overhead
705 // in accessing them (through Thread.CurrentCulture). There is
706 // also overhead in accessing Thread.CurrentThread. In this
707 // case, we can avoid the overhead of Thread.CurrentThread
708 // because these fields are thread static, and so do not
709 // require a Thread instance to be accessed.
711 if(AppDomain.IsAppXModel()) {
712 CultureInfo culture = GetCultureInfoForUserPreferredLanguageInAppX();
717 return Thread.m_CurrentCulture ??
718 s_DefaultThreadCurrentCulture ??
719 s_userDefaultCulture ??
727 throw new ArgumentNullException("value");
730 if (AppDomain.IsAppXModel()) {
731 if (SetCultureInfoForUserPreferredLanguageInAppX(value)) {
732 // successfully set the culture, otherwise fallback to legacy path
737 Thread.CurrentThread.CurrentCulture = value;
742 // This is the equivalence of the Win32 GetUserDefaultLCID()
744 internal static CultureInfo UserDefaultCulture {
747 Contract.Ensures(Contract.Result<CultureInfo>() != null);
749 CultureInfo temp = s_userDefaultCulture;
753 // setting the s_userDefaultCulture with invariant culture before intializing it is a protection
754 // against recursion problem just in case if somebody called CurrentCulture from the CultureInfo
755 // creation path. the recursion can happen if the current user culture is a replaced custom culture.
758 s_userDefaultCulture = CultureInfo.InvariantCulture;
759 temp = InitUserDefaultCulture();
760 s_userDefaultCulture = temp;
767 // This is the equivalence of the Win32 GetUserDefaultUILanguage()
769 internal static CultureInfo UserDefaultUICulture {
771 Contract.Ensures(Contract.Result<CultureInfo>() != null);
773 CultureInfo temp = s_userDefaultUICulture;
777 // setting the s_userDefaultCulture with invariant culture before intializing it is a protection
778 // against recursion problem just in case if somebody called CurrentUICulture from the CultureInfo
779 // creation path. the recursion can happen if the current user culture is a replaced custom culture.
782 s_userDefaultUICulture = CultureInfo.InvariantCulture;
784 temp = InitUserDefaultUICulture();
785 s_userDefaultUICulture = temp;
792 public static CultureInfo CurrentUICulture {
794 Contract.Ensures(Contract.Result<CultureInfo>() != null);
797 return Thread.CurrentThread.CurrentUICulture;
799 // In the case of CoreCLR, Thread.m_CurrentCulture and
800 // Thread.m_CurrentUICulture are thread static so as not to let
801 // CultureInfo objects leak across AppDomain boundaries. The
802 // fact that these fields are thread static introduces overhead
803 // in accessing them (through Thread.CurrentCulture). There is
804 // also overhead in accessing Thread.CurrentThread. In this
805 // case, we can avoid the overhead of Thread.CurrentThread
806 // because these fields are thread static, and so do not
807 // require a Thread instance to be accessed.
809 if(AppDomain.IsAppXModel()) {
810 CultureInfo culture = GetCultureInfoForUserPreferredLanguageInAppX();
815 return Thread.m_CurrentUICulture ??
816 s_DefaultThreadCurrentUICulture ??
817 s_userDefaultUICulture ??
818 UserDefaultUICulture;
825 throw new ArgumentNullException("value");
828 if (AppDomain.IsAppXModel()) {
829 if (SetCultureInfoForUserPreferredLanguageInAppX(value)) {
830 // successfully set the culture, otherwise fallback to legacy path
835 Thread.CurrentThread.CurrentUICulture = value;
841 // This is the equivalence of the Win32 GetSystemDefaultUILanguage()
844 public static CultureInfo InstalledUICulture {
846 Contract.Ensures(Contract.Result<CultureInfo>() != null);
848 CultureInfo temp = s_InstalledUICultureInfo;
850 String strDefault = GetSystemDefaultUILanguage();
851 temp = GetCultureByName(strDefault, true);
855 temp = InvariantCulture;
858 temp.m_isReadOnly = true;
859 s_InstalledUICultureInfo = temp;
865 public static CultureInfo DefaultThreadCurrentCulture {
867 return s_DefaultThreadCurrentCulture;
870 [System.Security.SecuritySafeCritical] // auto-generated
871 #pragma warning disable 618
872 [SecurityPermission(SecurityAction.Demand, ControlThread = true)]
873 #pragma warning restore 618
876 // If you add pre-conditions to this method, check to see if you also need to
877 // add them to Thread.CurrentCulture.set.
879 s_DefaultThreadCurrentCulture = value;
883 public static CultureInfo DefaultThreadCurrentUICulture {
885 return s_DefaultThreadCurrentUICulture;
888 [System.Security.SecuritySafeCritical] // auto-generated
889 #pragma warning disable 618
890 [SecurityPermission(SecurityAction.Demand, ControlThread = true)]
891 #pragma warning restore 618
894 //If they're trying to use a Culture with a name that we can't use in resource lookup,
895 //don't even let them set it on the thread.
897 // If you add more pre-conditions to this method, check to see if you also need to
898 // add them to Thread.CurrentUICulture.set.
902 CultureInfo.VerifyCultureName(value, true);
905 s_DefaultThreadCurrentUICulture = value;
909 #if FEATURE_LEGACYNETCF
911 // Helper methods to set default thread culture without security demand. Used
912 // by NetCF compatibility quirk. See comment in Thread.CurrentUICulture setter for details.
914 internal static void SetCurrentUICultureQuirk(CultureInfo value) {
915 s_DefaultThreadCurrentUICulture = value;
918 internal static void SetCurrentCultureQuirk(CultureInfo value) {
919 s_DefaultThreadCurrentCulture = value;
924 ////////////////////////////////////////////////////////////////////////
928 // This instance provides methods, for example for casing and sorting,
929 // that are independent of the system and current user settings. It
930 // should be used only by processes such as some system services that
931 // require such invariant results (eg. file systems). In general,
932 // the results are not linguistically correct and do not match any
935 ////////////////////////////////////////////////////////////////////////
938 public static CultureInfo InvariantCulture {
941 Contract.Ensures(Contract.Result<CultureInfo>() != null);
942 return (s_InvariantCultureInfo);
947 ////////////////////////////////////////////////////////////////////////
951 // Return the parent CultureInfo for the current instance.
953 ////////////////////////////////////////////////////////////////////////
955 public virtual CultureInfo Parent
957 [System.Security.SecuritySafeCritical] // auto-generated
960 Contract.Ensures(Contract.Result<CultureInfo>() != null);
962 if (null == m_parent)
966 string parentName = this.m_cultureData.SPARENT;
968 if (String.IsNullOrEmpty(parentName))
970 m_parent = InvariantCulture;
974 m_parent = new CultureInfo(parentName, this.m_cultureData.UseUserOverride);
977 catch (ArgumentException)
979 // For whatever reason our IPARENT or SPARENT wasn't correct, so use invariant
980 // We can't allow ourselves to fail. In case of custom cultures the parent of the
981 // current custom culture isn't installed.
982 m_parent = InvariantCulture;
989 ////////////////////////////////////////////////////////////////////////
993 // Returns a properly formed culture identifier for the current
996 ////////////////////////////////////////////////////////////////////////
999 public virtual int LCID {
1001 return (this.m_cultureData.ILANGUAGE);
1006 ////////////////////////////////////////////////////////////////////////
1008 // BaseInputLanguage
1010 // Essentially an LCID, though one that may be different than LCID in the case
1011 // of a customized culture (LCID == LOCALE_CUSTOM_UNSPECIFIED).
1013 ////////////////////////////////////////////////////////////////////////
1014 #if FEATURE_USE_LCID
1015 [System.Runtime.InteropServices.ComVisible(false)]
1016 public virtual int KeyboardLayoutId
1020 int keyId = this.m_cultureData.IINPUTLANGUAGEHANDLE;
1022 // Not a customized culture, return the default Keyboard layout ID, which is the same as the language ID.
1028 #if !FEATURE_CORECLR
1029 public static CultureInfo[] GetCultures(CultureTypes types) {
1030 Contract.Ensures(Contract.Result<CultureInfo[]>() != null);
1031 // internally we treat UserCustomCultures as Supplementals but v2
1032 // treats as Supplementals and Replacements
1033 if((types & CultureTypes.UserCustomCulture) == CultureTypes.UserCustomCulture)
1035 types |= CultureTypes.ReplacementCultures;
1037 return (CultureData.GetCultures(types));
1041 ////////////////////////////////////////////////////////////////////////
1045 // Returns the full name of the CultureInfo. The name is in format like
1046 // "en-US" This version does NOT include sort information in the name.
1048 ////////////////////////////////////////////////////////////////////////
1049 public virtual String Name {
1051 Contract.Ensures(Contract.Result<String>() != null);
1053 // We return non sorting name here.
1054 if (this.m_nonSortName == null) {
1055 this.m_nonSortName = this.m_cultureData.SNAME;
1056 if (this.m_nonSortName == null) {
1057 this.m_nonSortName = String.Empty;
1060 return this.m_nonSortName;
1064 // This one has the sort information (ie: de-DE_phoneb)
1065 internal String SortName
1069 if (this.m_sortName == null)
1071 this.m_sortName = this.m_cultureData.SCOMPAREINFO;
1074 return this.m_sortName;
1079 #if !FEATURE_CORECLR
1080 [System.Runtime.InteropServices.ComVisible(false)]
1081 public String IetfLanguageTag
1085 Contract.Ensures(Contract.Result<String>() != null);
1087 // special case the compatibility cultures
1101 ////////////////////////////////////////////////////////////////////////
1105 // Returns the full name of the CultureInfo in the localized language.
1106 // For example, if the localized language of the runtime is Spanish and the CultureInfo is
1107 // US English, "Ingles (Estados Unidos)" will be returned.
1109 ////////////////////////////////////////////////////////////////////////
1110 public virtual String DisplayName
1112 [System.Security.SecuritySafeCritical] // auto-generated
1115 Contract.Ensures(Contract.Result<String>() != null);
1116 Contract.Assert(m_name != null, "[CultureInfo.DisplayName]Always expect m_name to be set");
1118 return m_cultureData.SLOCALIZEDDISPLAYNAME;
1122 ////////////////////////////////////////////////////////////////////////
1126 // Returns the full name of the CultureInfo in the native language.
1127 // For example, if the CultureInfo is US English, "English
1128 // (United States)" will be returned.
1130 ////////////////////////////////////////////////////////////////////////
1131 public virtual String NativeName {
1132 [System.Security.SecuritySafeCritical] // auto-generated
1134 Contract.Ensures(Contract.Result<String>() != null);
1135 return (this.m_cultureData.SNATIVEDISPLAYNAME);
1139 ////////////////////////////////////////////////////////////////////////
1143 // Returns the full name of the CultureInfo in English.
1144 // For example, if the CultureInfo is US English, "English
1145 // (United States)" will be returned.
1147 ////////////////////////////////////////////////////////////////////////
1148 public virtual String EnglishName {
1149 [System.Security.SecuritySafeCritical] // auto-generated
1151 Contract.Ensures(Contract.Result<String>() != null);
1152 return (this.m_cultureData.SENGDISPLAYNAME);
1157 public virtual String TwoLetterISOLanguageName {
1158 [System.Security.SecuritySafeCritical] // auto-generated
1160 Contract.Ensures(Contract.Result<String>() != null);
1161 return (this.m_cultureData.SISO639LANGNAME);
1165 #if !FEATURE_CORECLR
1167 public virtual String ThreeLetterISOLanguageName {
1168 [System.Security.SecuritySafeCritical] // auto-generated
1170 Contract.Ensures(Contract.Result<String>() != null);
1171 return (this.m_cultureData.SISO639LANGNAME2);
1175 ////////////////////////////////////////////////////////////////////////
1177 // ThreeLetterWindowsLanguageName
1179 // Returns the 3 letter windows language name for the current instance. eg: "ENU"
1180 // The ISO names are much preferred
1182 ////////////////////////////////////////////////////////////////////////
1183 public virtual String ThreeLetterWindowsLanguageName {
1184 [System.Security.SecuritySafeCritical] // auto-generated
1186 Contract.Ensures(Contract.Result<String>() != null);
1187 return (this.m_cultureData.SABBREVLANGNAME);
1192 ////////////////////////////////////////////////////////////////////////
1194 // CompareInfo Read-Only Property
1196 // Gets the CompareInfo for this culture.
1198 ////////////////////////////////////////////////////////////////////////
1199 public virtual CompareInfo CompareInfo
1203 Contract.Ensures(Contract.Result<CompareInfo>() != null);
1205 if (this.compareInfo == null)
1207 // Since CompareInfo's don't have any overrideable properties, get the CompareInfo from
1208 // the Non-Overridden CultureInfo so that we only create one CompareInfo per culture
1209 CompareInfo temp = UseUserOverride
1210 ? GetCultureInfo(this.m_name).CompareInfo
1211 : new CompareInfo(this);
1212 if (CompatibilitySwitches.IsCompatibilityBehaviorDefined)
1214 this.compareInfo = temp;
1221 return (compareInfo);
1225 #if !FEATURE_CORECLR
1226 ////////////////////////////////////////////////////////////////////////
1230 // Gets the RegionInfo for this culture.
1232 ////////////////////////////////////////////////////////////////////////
1233 private RegionInfo Region
1237 if (regionInfo==null)
1239 // Make a new regionInfo
1240 RegionInfo tempRegionInfo = new RegionInfo(this.m_cultureData);
1241 regionInfo = tempRegionInfo;
1243 return (regionInfo);
1246 #endif // FEATURE_CORECLR
1250 ////////////////////////////////////////////////////////////////////////
1254 // Gets the TextInfo for this culture.
1256 ////////////////////////////////////////////////////////////////////////
1259 public virtual TextInfo TextInfo {
1261 Contract.Ensures(Contract.Result<TextInfo>() != null);
1265 // Make a new textInfo
1266 TextInfo tempTextInfo = new TextInfo(this.m_cultureData);
1267 tempTextInfo.SetReadOnlyState(m_isReadOnly);
1269 if (CompatibilitySwitches.IsCompatibilityBehaviorDefined)
1271 textInfo = tempTextInfo;
1275 return tempTextInfo;
1282 ////////////////////////////////////////////////////////////////////////
1286 // Implements Object.Equals(). Returns a boolean indicating whether
1287 // or not object refers to the same CultureInfo as the current instance.
1289 ////////////////////////////////////////////////////////////////////////
1292 public override bool Equals(Object value)
1294 if (Object.ReferenceEquals(this, value))
1297 CultureInfo that = value as CultureInfo;
1301 // using CompareInfo to verify the data passed through the constructor
1302 // CultureInfo(String cultureName, String textAndCompareCultureName)
1304 return (this.Name.Equals(that.Name) && this.CompareInfo.Equals(that.CompareInfo));
1311 ////////////////////////////////////////////////////////////////////////
1315 // Implements Object.GetHashCode(). Returns the hash code for the
1316 // CultureInfo. The hash code is guaranteed to be the same for CultureInfo A
1317 // and B where A.Equals(B) is true.
1319 ////////////////////////////////////////////////////////////////////////
1321 public override int GetHashCode()
1323 return (this.Name.GetHashCode() + this.CompareInfo.GetHashCode());
1327 ////////////////////////////////////////////////////////////////////////
1331 // Implements Object.ToString(). Returns the name of the CultureInfo,
1332 // eg. "de-DE_phoneb", "en-US", or "fj-FJ".
1334 ////////////////////////////////////////////////////////////////////////
1337 public override String ToString()
1339 Contract.Ensures(Contract.Result<String>() != null);
1341 Contract.Assert(m_name != null, "[CultureInfo.ToString]Always expect m_name to be set");
1346 public virtual Object GetFormat(Type formatType) {
1347 if (formatType == typeof(NumberFormatInfo)) {
1348 return (NumberFormat);
1350 if (formatType == typeof(DateTimeFormatInfo)) {
1351 return (DateTimeFormat);
1356 public virtual bool IsNeutralCulture {
1358 return this.m_cultureData.IsNeutralCulture;
1362 #if !FEATURE_CORECLR
1363 [System.Runtime.InteropServices.ComVisible(false)]
1364 public CultureTypes CultureTypes
1368 CultureTypes types = 0;
1370 if (m_cultureData.IsNeutralCulture)
1371 types |= CultureTypes.NeutralCultures;
1373 types |= CultureTypes.SpecificCultures;
1375 types |= m_cultureData.IsWin32Installed ? CultureTypes.InstalledWin32Cultures : 0;
1377 // Disable warning 618: System.Globalization.CultureTypes.FrameworkCultures' is obsolete
1378 #pragma warning disable 618
1379 types |= m_cultureData.IsFramework ? CultureTypes.FrameworkCultures : 0;
1381 #pragma warning restore 618
1382 types |= m_cultureData.IsSupplementalCustomCulture ? CultureTypes.UserCustomCulture : 0;
1383 types |= m_cultureData.IsReplacementCulture ? CultureTypes.ReplacementCultures | CultureTypes.UserCustomCulture : 0;
1390 public virtual NumberFormatInfo NumberFormat {
1393 Contract.Ensures(Contract.Result<NumberFormatInfo>() != null);
1395 if (numInfo == null) {
1396 NumberFormatInfo temp = new NumberFormatInfo(this.m_cultureData);
1397 temp.isReadOnly = m_isReadOnly;
1403 if (value == null) {
1404 throw new ArgumentNullException("value",
1405 Environment.GetResourceString("ArgumentNull_Obj"));
1407 Contract.EndContractBlock();
1413 ////////////////////////////////////////////////////////////////////////
1415 // GetDateTimeFormatInfo
1417 // Create a DateTimeFormatInfo, and fill in the properties according to
1420 ////////////////////////////////////////////////////////////////////////
1423 public virtual DateTimeFormatInfo DateTimeFormat {
1425 Contract.Ensures(Contract.Result<DateTimeFormatInfo>() != null);
1427 if (dateTimeInfo == null) {
1428 // Change the calendar of DTFI to the specified calendar of this CultureInfo.
1429 DateTimeFormatInfo temp = new DateTimeFormatInfo(
1430 this.m_cultureData, this.Calendar);
1431 temp.m_isReadOnly = m_isReadOnly;
1432 System.Threading.Thread.MemoryBarrier();
1433 dateTimeInfo = temp;
1435 return (dateTimeInfo);
1439 if (value == null) {
1440 throw new ArgumentNullException("value",
1441 Environment.GetResourceString("ArgumentNull_Obj"));
1443 Contract.EndContractBlock();
1445 dateTimeInfo = value;
1451 public void ClearCachedData() {
1452 s_userDefaultUICulture = null;
1453 s_userDefaultCulture = null;
1455 RegionInfo.s_currentRegionInfo = null;
1456 #if !FEATURE_CORECLR && !FEATURE_PAL // System.TimeZone does not exist in CoreCLR
1457 TimeZone.ResetTimeZone();
1458 #endif // FEATURE_CORECLR
1459 TimeZoneInfo.ClearCachedData();
1460 // Delete the cached cultures.
1461 s_LcidCachedCultures = null;
1462 s_NameCachedCultures = null;
1464 CultureData.ClearCachedData();
1467 /*=================================GetCalendarInstance==========================
1468 **Action: Map a Win32 CALID to an instance of supported calendar.
1469 **Returns: An instance of calendar.
1470 **Arguments: calType The Win32 CALID
1472 ** Shouldn't throw exception since the calType value is from our data table or from Win32 registry.
1473 ** If we are in trouble (like getting a weird value from Win32 registry), just return the GregorianCalendar.
1474 ============================================================================*/
1475 internal static Calendar GetCalendarInstance(int calType) {
1476 if (calType==Calendar.CAL_GREGORIAN) {
1477 return (new GregorianCalendar());
1479 return GetCalendarInstanceRare(calType);
1482 //This function exists as a shortcut to prevent us from loading all of the non-gregorian
1483 //calendars unless they're required.
1484 internal static Calendar GetCalendarInstanceRare(int calType) {
1485 Contract.Assert(calType!=Calendar.CAL_GREGORIAN, "calType!=Calendar.CAL_GREGORIAN");
1488 case Calendar.CAL_GREGORIAN_US: // Gregorian (U.S.) calendar
1489 case Calendar.CAL_GREGORIAN_ME_FRENCH: // Gregorian Middle East French calendar
1490 case Calendar.CAL_GREGORIAN_ARABIC: // Gregorian Arabic calendar
1491 case Calendar.CAL_GREGORIAN_XLIT_ENGLISH: // Gregorian Transliterated English calendar
1492 case Calendar.CAL_GREGORIAN_XLIT_FRENCH: // Gregorian Transliterated French calendar
1493 return (new GregorianCalendar((GregorianCalendarTypes)calType));
1494 case Calendar.CAL_TAIWAN: // Taiwan Era calendar
1495 return (new TaiwanCalendar());
1496 case Calendar.CAL_JAPAN: // Japanese Emperor Era calendar
1497 return (new JapaneseCalendar());
1498 case Calendar.CAL_KOREA: // Korean Tangun Era calendar
1499 return (new KoreanCalendar());
1500 case Calendar.CAL_THAI: // Thai calendar
1501 return (new ThaiBuddhistCalendar());
1502 case Calendar.CAL_HIJRI: // Hijri (Arabic Lunar) calendar
1503 return (new HijriCalendar());
1504 case Calendar.CAL_HEBREW: // Hebrew (Lunar) calendar
1505 return (new HebrewCalendar());
1506 case Calendar.CAL_UMALQURA:
1507 return (new UmAlQuraCalendar());
1508 case Calendar.CAL_PERSIAN:
1509 return (new PersianCalendar());
1510 case Calendar.CAL_CHINESELUNISOLAR:
1511 return (new ChineseLunisolarCalendar());
1512 case Calendar.CAL_JAPANESELUNISOLAR:
1513 return (new JapaneseLunisolarCalendar());
1514 case Calendar.CAL_KOREANLUNISOLAR:
1515 return (new KoreanLunisolarCalendar());
1516 case Calendar.CAL_TAIWANLUNISOLAR:
1517 return (new TaiwanLunisolarCalendar());
1519 return (new GregorianCalendar());
1523 /*=================================Calendar==========================
1524 **Action: Return/set the default calendar used by this culture.
1525 ** This value can be overridden by regional option if this is a current culture.
1529 ** ArgumentNull_Obj if the set value is null.
1530 ============================================================================*/
1533 public virtual Calendar Calendar {
1535 Contract.Ensures(Contract.Result<Calendar>() != null);
1536 if (calendar == null) {
1537 Contract.Assert(this.m_cultureData.CalendarIds.Length > 0, "this.m_cultureData.CalendarIds.Length > 0");
1538 // Get the default calendar for this culture. Note that the value can be
1539 // from registry if this is a user default culture.
1540 Calendar newObj = this.m_cultureData.DefaultCalendar;
1542 System.Threading.Thread.MemoryBarrier();
1543 newObj.SetReadOnlyState(m_isReadOnly);
1550 /*=================================OptionCalendars==========================
1551 **Action: Return an array of the optional calendar for this culture.
1552 **Returns: an array of Calendar.
1555 ============================================================================*/
1558 public virtual Calendar[] OptionalCalendars {
1560 Contract.Ensures(Contract.Result<Calendar[]>() != null);
1563 // This property always returns a new copy of the calendar array.
1565 int[] calID = this.m_cultureData.CalendarIds;
1566 Calendar [] cals = new Calendar[calID.Length];
1567 for (int i = 0; i < cals.Length; i++) {
1568 cals[i] = GetCalendarInstance(calID[i]);
1575 public bool UseUserOverride {
1577 return (this.m_cultureData.UseUserOverride);
1581 #if !FEATURE_CORECLR
1582 [System.Security.SecuritySafeCritical] // auto-generated
1583 [System.Runtime.InteropServices.ComVisible(false)]
1584 public CultureInfo GetConsoleFallbackUICulture()
1586 Contract.Ensures(Contract.Result<CultureInfo>() != null);
1588 CultureInfo temp = m_consoleFallbackCulture;
1591 temp = CreateSpecificCulture(this.m_cultureData.SCONSOLEFALLBACKNAME);
1592 temp.m_isReadOnly = true;
1593 m_consoleFallbackCulture = temp;
1599 public virtual Object Clone()
1601 Contract.Ensures(Contract.Result<Object>() != null);
1603 CultureInfo ci = (CultureInfo)MemberwiseClone();
1604 ci.m_isReadOnly = false;
1606 //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
1607 //they've already been allocated. If this is a derived type, we'll take a more generic codepath.
1610 if (this.dateTimeInfo != null)
1612 ci.dateTimeInfo = (DateTimeFormatInfo)this.dateTimeInfo.Clone();
1614 if (this.numInfo != null)
1616 ci.numInfo = (NumberFormatInfo)this.numInfo.Clone();
1622 ci.DateTimeFormat = (DateTimeFormatInfo)this.DateTimeFormat.Clone();
1623 ci.NumberFormat = (NumberFormatInfo)this.NumberFormat.Clone();
1626 if (textInfo != null)
1628 ci.textInfo = (TextInfo) textInfo.Clone();
1631 if (calendar != null)
1633 ci.calendar = (Calendar) calendar.Clone();
1640 public static CultureInfo ReadOnly(CultureInfo ci) {
1642 throw new ArgumentNullException("ci");
1644 Contract.Ensures(Contract.Result<CultureInfo>() != null);
1645 Contract.EndContractBlock();
1647 if (ci.IsReadOnly) {
1650 CultureInfo newInfo = (CultureInfo)(ci.MemberwiseClone());
1652 if (!ci.IsNeutralCulture)
1654 //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
1655 //they've already been allocated. If this is a derived type, we'll take a more generic codepath.
1656 if (!ci.m_isInherited) {
1657 if (ci.dateTimeInfo != null) {
1658 newInfo.dateTimeInfo = DateTimeFormatInfo.ReadOnly(ci.dateTimeInfo);
1660 if (ci.numInfo != null) {
1661 newInfo.numInfo = NumberFormatInfo.ReadOnly(ci.numInfo);
1665 newInfo.DateTimeFormat = DateTimeFormatInfo.ReadOnly(ci.DateTimeFormat);
1666 newInfo.NumberFormat = NumberFormatInfo.ReadOnly(ci.NumberFormat);
1670 if (ci.textInfo != null)
1672 newInfo.textInfo = TextInfo.ReadOnly(ci.textInfo);
1675 if (ci.calendar != null)
1677 newInfo.calendar = Calendar.ReadOnly(ci.calendar);
1680 // Don't set the read-only flag too early.
1681 // We should set the read-only flag here. Otherwise, info.DateTimeFormat will not be able to set.
1682 newInfo.m_isReadOnly = true;
1688 public bool IsReadOnly {
1690 return (m_isReadOnly);
1694 private void VerifyWritable() {
1696 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
1698 Contract.EndContractBlock();
1701 // For resource lookup, we consider a culture the invariant culture by name equality.
1702 // We perform this check frequently during resource lookup, so adding a property for
1703 // improved readability.
1704 internal bool HasInvariantCultureName
1706 get { return Name == CultureInfo.InvariantCulture.Name; }
1709 // Helper function both both overloads of GetCachedReadOnlyCulture. If lcid is 0, we use the name.
1710 // If lcid is -1, use the altName and create one of those special SQL cultures.
1711 internal static CultureInfo GetCultureInfoHelper(int lcid, string name, string altName)
1713 // There is a race condition in this code with the side effect that the second thread's value
1714 // clobbers the first in the dictionary. This is an acceptable ---- since the CultureInfo objects
1715 // are content equal (but not reference equal). Since we make no guarantees there, this ---- is
1717 // See code:Dictionary#DictionaryVersusHashtableThreadSafety for details on Dictionary versus
1718 // Hashtable thread safety.
1720 // retval is our return value.
1723 // Temporary hashtable for the names.
1724 Hashtable tempNameHT = s_NameCachedCultures;
1728 name = CultureData.AnsiToLower(name);
1731 if (altName != null)
1733 altName = CultureData.AnsiToLower(altName);
1736 // We expect the same result for both hashtables, but will test individually for added safety.
1737 if (tempNameHT == null)
1739 tempNameHT = Hashtable.Synchronized(new Hashtable());
1743 // If we are called by name, check if the object exists in the hashtable. If so, return it.
1746 retval = (CultureInfo)tempNameHT[name + '\xfffd' + altName];
1754 retval = (CultureInfo)tempNameHT[name];
1761 #if FEATURE_USE_LCID
1762 // Next, the Lcid table.
1763 Hashtable tempLcidHT = s_LcidCachedCultures;
1765 if (tempLcidHT == null)
1767 // Case insensitive is not an issue here, save the constructor call.
1768 tempLcidHT = Hashtable.Synchronized(new Hashtable());
1772 // If we were called by Lcid, check if the object exists in the table. If so, return it.
1775 retval = (CultureInfo) tempLcidHT[lcid];
1783 // We now have two temporary hashtables and the desired object was not found.
1784 // We'll construct it. We catch any exceptions from the constructor call and return null.
1790 // call the private constructor
1791 retval = new CultureInfo(name, altName);
1795 retval = new CultureInfo(name, false);
1799 #if FEATURE_USE_LCID
1800 retval = new CultureInfo(lcid, false);
1807 catch(ArgumentException)
1812 // Set it to read-only
1813 retval.m_isReadOnly = true;
1817 // This new culture will be added only to the name hash table.
1818 tempNameHT[name + '\xfffd' + altName] = retval;
1820 // when lcid == -1 then TextInfo object is already get created and we need to set it as read only.
1821 retval.TextInfo.SetReadOnlyState(true);
1825 // Remember our name (as constructed). Do NOT use alternate sort name versions because
1826 // we have internal state representing the sort. (So someone would get the wrong cached version)
1827 string newName = CultureData.AnsiToLower(retval.m_name);
1829 // We add this new culture info object to both tables.
1830 tempNameHT[newName] = retval;
1831 #if FEATURE_USE_LCID
1832 const int LCID_ZH_CHS_HANS = 0x0004;
1833 const int LCID_ZH_CHT_HANT = 0x7c04;
1835 if ((retval.LCID == LCID_ZH_CHS_HANS && newName == "zh-hans")
1836 || (retval.LCID == LCID_ZH_CHT_HANT && newName == "zh-hant"))
1838 // do nothing because we only want zh-CHS and zh-CHT to cache
1843 tempLcidHT[retval.LCID] = retval;
1849 #if FEATURE_USE_LCID
1850 // Copy the two hashtables to the corresponding member variables. This will potentially overwrite
1851 // new tables simultaneously created by a new thread, but maximizes thread safety.
1854 // Only when we modify the lcid hash table, is there a need to overwrite.
1855 s_LcidCachedCultures = tempLcidHT;
1859 s_NameCachedCultures = tempNameHT;
1861 // Finally, return our new CultureInfo object.
1865 #if FEATURE_USE_LCID
1866 // Gets a cached copy of the specified culture from an internal hashtable (or creates it
1867 // if not found). (LCID version)... use named version
1868 public static CultureInfo GetCultureInfo(int culture)
1870 // Must check for -1 now since the helper function uses the value to signal
1871 // the altCulture code path for SQL Server.
1872 // Also check for zero as this would fail trying to add as a key to the hash.
1874 throw new ArgumentOutOfRangeException("culture",
1875 Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
1877 Contract.Ensures(Contract.Result<CultureInfo>() != null);
1878 Contract.EndContractBlock();
1879 CultureInfo retval = GetCultureInfoHelper(culture, null, null);
1882 throw new CultureNotFoundException(
1883 "culture", culture, Environment.GetResourceString("Argument_CultureNotSupported"));
1889 // Gets a cached copy of the specified culture from an internal hashtable (or creates it
1890 // if not found). (Named version)
1891 public static CultureInfo GetCultureInfo(string name)
1893 // Make sure we have a valid, non-zero length string as name
1896 throw new ArgumentNullException("name");
1898 Contract.Ensures(Contract.Result<CultureInfo>() != null);
1899 Contract.EndContractBlock();
1901 CultureInfo retval = GetCultureInfoHelper(0, name, null);
1904 throw new CultureNotFoundException(
1905 "name", name, Environment.GetResourceString("Argument_CultureNotSupported"));
1911 // Gets a cached copy of the specified culture from an internal hashtable (or creates it
1913 public static CultureInfo GetCultureInfo(string name, string altName)
1915 // Make sure we have a valid, non-zero length string as name
1918 throw new ArgumentNullException("name");
1921 if (null == altName)
1923 throw new ArgumentNullException("altName");
1925 Contract.Ensures(Contract.Result<CultureInfo>() != null);
1926 Contract.EndContractBlock();
1928 CultureInfo retval = GetCultureInfoHelper(-1, name, altName);
1931 throw new CultureNotFoundException("name or altName",
1933 CultureInfo.CurrentCulture,
1934 Environment.GetResourceString("Argument_OneOfCulturesNotSupported"),
1942 #if !FEATURE_CORECLR
1943 // This function is deprecated, we don't like it
1944 public static CultureInfo GetCultureInfoByIetfLanguageTag(string name)
1946 Contract.Ensures(Contract.Result<CultureInfo>() != null);
1948 // Disallow old zh-CHT/zh-CHS names
1949 if (name == "zh-CHT" || name == "zh-CHS")
1951 throw new CultureNotFoundException(
1953 String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_CultureIetfNotSupported"), name)
1957 CultureInfo ci = GetCultureInfo(name);
1959 // Disallow alt sorts and es-es_TS
1960 if (ci.LCID > 0xffff || ci.LCID == 0x040a)
1962 throw new CultureNotFoundException(
1964 String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_CultureIetfNotSupported"), name)
1971 private static volatile bool s_isTaiwanSku;
1972 private static volatile bool s_haveIsTaiwanSku;
1973 internal static bool IsTaiwanSku
1977 if (!s_haveIsTaiwanSku)
1979 s_isTaiwanSku = (GetSystemDefaultUILanguage() == "zh-TW");
1980 s_haveIsTaiwanSku = true;
1982 return (bool)s_isTaiwanSku;
1990 // Get Locale Info Ex calls. So we don't have to muck with the different int/string return types we declared two of these:
1991 [System.Security.SecurityCritical] // auto-generated
1992 [ResourceExposure(ResourceScope.None)]
1993 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1994 internal static extern String nativeGetLocaleInfoEx(String localeName, uint field);
1996 [System.Security.SecuritySafeCritical] // auto-generated
1997 [ResourceExposure(ResourceScope.None)]
1998 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1999 internal static extern int nativeGetLocaleInfoExInt(String localeName, uint field);
2001 [System.Security.SecurityCritical] // auto-generated
2002 [ResourceExposure(ResourceScope.None)]
2003 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2004 internal static extern bool nativeSetThreadLocale(String localeName);
2006 [System.Security.SecurityCritical]
2007 private static String GetDefaultLocaleName(int localeType)
2009 Contract.Assert(localeType == LOCALE_USER_DEFAULT || localeType == LOCALE_SYSTEM_DEFAULT, "[CultureInfo.GetDefaultLocaleName] localeType must be LOCALE_USER_DEFAULT or LOCALE_SYSTEM_DEFAULT");
2011 string localeName = null;
2012 if(InternalGetDefaultLocaleName(localeType, JitHelpers.GetStringHandleOnStack(ref localeName)))
2016 return string.Empty;
2019 // Get the default locale name
2020 [System.Security.SecurityCritical] // auto-generated
2021 [ResourceExposure(ResourceScope.None)]
2022 [SuppressUnmanagedCodeSecurity]
2023 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
2024 [return: MarshalAs(UnmanagedType.Bool)]
2025 private static extern bool InternalGetDefaultLocaleName(int localetype, StringHandleOnStack localeString);
2027 [System.Security.SecuritySafeCritical] // auto-generated
2028 private static String GetUserDefaultUILanguage()
2030 string userDefaultUiLanguage = null;
2031 if(InternalGetUserDefaultUILanguage(JitHelpers.GetStringHandleOnStack(ref userDefaultUiLanguage)))
2033 return userDefaultUiLanguage;
2035 return String.Empty;
2038 // Get the user's default UI language, return locale name
2039 [System.Security.SecurityCritical] // auto-generated
2040 [ResourceExposure(ResourceScope.None)]
2041 [SuppressUnmanagedCodeSecurity]
2042 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
2043 [return: MarshalAs(UnmanagedType.Bool)]
2044 private static extern bool InternalGetUserDefaultUILanguage(StringHandleOnStack userDefaultUiLanguage);
2046 [System.Security.SecuritySafeCritical] // auto-generated
2047 private static String GetSystemDefaultUILanguage()
2049 string systemDefaultUiLanguage = null;
2050 if(InternalGetSystemDefaultUILanguage(JitHelpers.GetStringHandleOnStack(ref systemDefaultUiLanguage)))
2052 return systemDefaultUiLanguage;
2054 return String.Empty;
2058 [System.Security.SecurityCritical] // auto-generated
2059 [ResourceExposure(ResourceScope.None)]
2060 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2061 [SuppressUnmanagedCodeSecurity]
2062 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
2063 [return: MarshalAs(UnmanagedType.Bool)]
2064 private static extern bool InternalGetSystemDefaultUILanguage(StringHandleOnStack systemDefaultUiLanguage);
2066 // Added but disabled from desktop in .NET 4.0, stayed disabled in .NET 4.5
2068 [System.Security.SecurityCritical] // auto-generated
2069 [ResourceExposure(ResourceScope.None)]
2070 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2071 internal static extern String[] nativeGetResourceFallbackArray();