1994 lines
77 KiB
C#
1994 lines
77 KiB
C#
// ==++==
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// ==--==
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Class: CultureInfo
|
|
//
|
|
//
|
|
// Purpose: This class represents the software preferences of a particular
|
|
// culture or community. It includes information such as the
|
|
// language, writing system, and a calendar used by the culture
|
|
// as well as methods for common operations such as printing
|
|
// dates and sorting strings.
|
|
//
|
|
// Date: [....] 31, 1999
|
|
//
|
|
//
|
|
// !!!! NOTE WHEN CHANGING THIS CLASS !!!!
|
|
//
|
|
// If adding or removing members to this class, please update CultureInfoBaseObject
|
|
// in ndp/clr/src/vm/object.h. Note, the "actual" layout of the class may be
|
|
// different than the order in which members are declared. For instance, all
|
|
// reference types will come first in the class before value types (like ints, bools, etc)
|
|
// regardless of the order in which they are declared. The best way to see the
|
|
// actual order of the class is to do a !dumpobj on an instance of the managed
|
|
// object inside of the debugger.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace System.Globalization {
|
|
using System;
|
|
using System.Security;
|
|
using System.Threading;
|
|
using System.Collections;
|
|
using System.Runtime;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
using System.Runtime.Serialization;
|
|
using System.Runtime.Versioning;
|
|
using System.Security.Permissions;
|
|
using System.Reflection;
|
|
using Microsoft.Win32;
|
|
using System.Diagnostics.Contracts;
|
|
using System.Resources;
|
|
|
|
[Serializable]
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public class CultureInfo : ICloneable, IFormatProvider {
|
|
//--------------------------------------------------------------------//
|
|
// Internal Information //
|
|
//--------------------------------------------------------------------//
|
|
|
|
//--------------------------------------------------------------------//
|
|
// Data members to be serialized:
|
|
//--------------------------------------------------------------------//
|
|
|
|
// We use an RFC4646 type string to construct CultureInfo.
|
|
// This string is stored in m_name and is authoritative.
|
|
// We use the m_cultureData to get the data for our object
|
|
|
|
// WARNING
|
|
// WARNING: All member fields declared here must also be in ndp/clr/src/vm/object.h
|
|
// WARNING: They aren't really private because object.h can access them, but other C# stuff cannot
|
|
// WARNING: The type loader will rearrange class member offsets so the mscorwks!CultureInfoBaseObject
|
|
// WARNING: must be manually structured to match the true loaded class layout
|
|
// WARNING
|
|
internal bool m_isReadOnly;
|
|
internal CompareInfo compareInfo;
|
|
internal TextInfo textInfo;
|
|
// Not serialized for now since we only build it privately for use in the CARIB (so rebuilding is OK)
|
|
#if !FEATURE_CORECLR
|
|
[NonSerialized]internal RegionInfo regionInfo;
|
|
#endif
|
|
internal NumberFormatInfo numInfo;
|
|
internal DateTimeFormatInfo dateTimeInfo;
|
|
internal Calendar calendar;
|
|
#if !FEATURE_CORECLR
|
|
[OptionalField(VersionAdded = 1)]
|
|
internal int m_dataItem; // NEVER USED, DO NOT USE THIS! (Serialized in Whidbey/Everett)
|
|
[OptionalField(VersionAdded = 1)]
|
|
internal int cultureID = 0x007f; // NEVER USED, DO NOT USE THIS! (Serialized in Whidbey/Everett)
|
|
#endif // !FEATURE_CORECLR
|
|
//
|
|
// The CultureData instance that we are going to read data from.
|
|
// For supported culture, this will be the CultureData instance that read data from mscorlib assembly.
|
|
// For customized culture, this will be the CultureData instance that read data from user customized culture binary file.
|
|
//
|
|
[NonSerialized]internal CultureData m_cultureData;
|
|
|
|
[NonSerialized]internal bool m_isInherited;
|
|
#if FEATURE_LEAK_CULTURE_INFO
|
|
[NonSerialized]private bool m_isSafeCrossDomain;
|
|
[NonSerialized]private int m_createdDomainID;
|
|
#endif // !FEATURE_CORECLR
|
|
#if !FEATURE_CORECLR
|
|
[NonSerialized]private CultureInfo m_consoleFallbackCulture;
|
|
#endif // !FEATURE_CORECLR
|
|
|
|
// Names are confusing. Here are 3 names we have:
|
|
//
|
|
// new CultureInfo() m_name m_nonSortName m_sortName
|
|
// en-US en-US en-US en-US
|
|
// de-de_phoneb de-DE_phoneb de-DE de-DE_phoneb
|
|
// fj-fj (custom) fj-FJ fj-FJ en-US (if specified sort is en-US)
|
|
// en en
|
|
//
|
|
// Note that in Silverlight we ask the OS for the text and sort behavior, so the
|
|
// textinfo and compareinfo names are the same as the name
|
|
|
|
// Note that the name used to be serialized for Everett; it is now serialized
|
|
// because alernate sorts can have alternate names.
|
|
// This has a de-DE, de-DE_phoneb or fj-FJ style name
|
|
internal string m_name;
|
|
|
|
// This will hold the non sorting name to be returned from CultureInfo.Name property.
|
|
// This has a de-DE style name even for de-DE_phoneb type cultures
|
|
[NonSerialized]private string m_nonSortName;
|
|
|
|
// This will hold the sorting name to be returned from CultureInfo.SortName property.
|
|
// This might be completely unrelated to the culture name if a custom culture. Ie en-US for fj-FJ.
|
|
// Otherwise its the sort name, ie: de-DE or de-DE_phoneb
|
|
[NonSerialized]private string m_sortName;
|
|
|
|
|
|
//--------------------------------------------------------------------//
|
|
//
|
|
// Static data members
|
|
//
|
|
//--------------------------------------------------------------------//
|
|
|
|
//Get the current user default culture. This one is almost always used, so we create it by default.
|
|
private static volatile CultureInfo s_userDefaultCulture;
|
|
|
|
//
|
|
// All of the following will be created on demand.
|
|
//
|
|
|
|
//The Invariant culture;
|
|
private static volatile CultureInfo s_InvariantCultureInfo;
|
|
|
|
//The culture used in the user interface. This is mostly used to load correct localized resources.
|
|
private static volatile CultureInfo s_userDefaultUICulture;
|
|
|
|
//This is the UI culture used to install the OS.
|
|
private static volatile CultureInfo s_InstalledUICultureInfo;
|
|
|
|
//These are defaults that we use if a thread has not opted into having an explicit culture
|
|
private static volatile CultureInfo s_DefaultThreadCurrentUICulture;
|
|
private static volatile CultureInfo s_DefaultThreadCurrentCulture;
|
|
|
|
//This is a cache of all previously created cultures. Valid keys are LCIDs or the name. We use two hashtables to track them,
|
|
// depending on how they are called.
|
|
private static volatile Hashtable s_LcidCachedCultures;
|
|
private static volatile Hashtable s_NameCachedCultures;
|
|
|
|
#if !FEATURE_CORECLR
|
|
// When running under AppX, we use this to get some information about the language list
|
|
[SecurityCritical]
|
|
private static volatile WindowsRuntimeResourceManagerBase s_WindowsRuntimeResourceManager;
|
|
|
|
[ThreadStatic]
|
|
private static bool ts_IsDoingAppXCultureInfoLookup;
|
|
#endif
|
|
|
|
//The parent culture.
|
|
[NonSerialized]private CultureInfo m_parent;
|
|
|
|
// LOCALE constants of interest to us internally and privately for LCID functions
|
|
// (ie: avoid using these and use names if possible)
|
|
internal const int LOCALE_NEUTRAL = 0x0000;
|
|
private const int LOCALE_USER_DEFAULT = 0x0400;
|
|
private const int LOCALE_SYSTEM_DEFAULT = 0x0800;
|
|
internal const int LOCALE_CUSTOM_DEFAULT = 0x0c00;
|
|
internal const int LOCALE_CUSTOM_UNSPECIFIED = 0x1000;
|
|
internal const int LOCALE_INVARIANT = 0x007F;
|
|
private const int LOCALE_TRADITIONAL_SPANISH = 0x040a;
|
|
|
|
//
|
|
// The CultureData instance that reads the data provided by our CultureData class.
|
|
//
|
|
//Using a field initializer rather than a static constructor so that the whole class can be lazy
|
|
//init.
|
|
private static readonly bool init = Init();
|
|
private static bool Init()
|
|
{
|
|
|
|
if (s_InvariantCultureInfo == null)
|
|
{
|
|
CultureInfo temp = new CultureInfo("", false);
|
|
temp.m_isReadOnly = true;
|
|
s_InvariantCultureInfo = temp;
|
|
}
|
|
// First we set it to Invariant in case someone needs it before we're done finding it.
|
|
// For example, if we throw an exception in InitUserDefaultCulture, we will still need an valid
|
|
// s_userDefaultCulture to be used in Thread.CurrentCulture.
|
|
s_userDefaultCulture = s_userDefaultUICulture = s_InvariantCultureInfo;
|
|
|
|
s_userDefaultCulture = InitUserDefaultCulture();
|
|
s_userDefaultUICulture = InitUserDefaultUICulture();
|
|
return true;
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
static CultureInfo InitUserDefaultCulture()
|
|
{
|
|
String strDefault = GetDefaultLocaleName(LOCALE_USER_DEFAULT);
|
|
if (strDefault == null)
|
|
{
|
|
strDefault = GetDefaultLocaleName(LOCALE_SYSTEM_DEFAULT);
|
|
|
|
if (strDefault == null)
|
|
{
|
|
// If system default doesn't work, keep using the invariant
|
|
return (CultureInfo.InvariantCulture);
|
|
}
|
|
}
|
|
CultureInfo temp = GetCultureByName(strDefault, true);
|
|
|
|
temp.m_isReadOnly = true;
|
|
|
|
return (temp);
|
|
}
|
|
|
|
static CultureInfo InitUserDefaultUICulture()
|
|
{
|
|
String strDefault = GetUserDefaultUILanguage();
|
|
|
|
// In most of cases, UserDefaultCulture == UserDefaultUICulture, so we should use the same instance if possible.
|
|
if (strDefault == UserDefaultCulture.Name)
|
|
{
|
|
return (UserDefaultCulture);
|
|
}
|
|
|
|
CultureInfo temp = GetCultureByName( strDefault, true);
|
|
|
|
if (temp == null)
|
|
{
|
|
return (CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
temp.m_isReadOnly = true;
|
|
|
|
return (temp);
|
|
}
|
|
|
|
#if !FEATURE_CORECLR
|
|
[SecuritySafeCritical]
|
|
internal static CultureInfo GetCultureInfoForUserPreferredLanguageInAppX()
|
|
{
|
|
// If a call to GetCultureInfoForUserPreferredLanguageInAppX() generated a recursive
|
|
// call to itself, return null, since we don't want to stack overflow. For example,
|
|
// this can happen if some code in this method ends up calling CultureInfo.CurrentCulture
|
|
// (which is common on check'd build because of BCLDebug logging which calls Int32.ToString()).
|
|
// In this case, returning null will mean CultureInfo.CurrentCulture gets the default Win32
|
|
// value, which should be fine.
|
|
if(ts_IsDoingAppXCultureInfoLookup)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
// If running within a compilation process (mscorsvw.exe, for example), it is illegal to
|
|
// load any non-mscorlib assembly for execution. Since WindowsRuntimeResourceManager lives
|
|
// in System.Runtime.WindowsRuntime, caller will need to fall back to default Win32 value,
|
|
// which should be fine because we should only ever need to access FX resources during NGEN.
|
|
// FX resources are always loaded from satellite assemblies - even in AppX processes (see the
|
|
// comments in code:System.Resources.ResourceManager.SetAppXConfiguration for more details).
|
|
if (AppDomain.IsAppXNGen)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
CultureInfo toReturn = null;
|
|
|
|
try
|
|
{
|
|
ts_IsDoingAppXCultureInfoLookup = true;
|
|
|
|
if(s_WindowsRuntimeResourceManager == null)
|
|
{
|
|
s_WindowsRuntimeResourceManager = ResourceManager.GetWinRTResourceManager();
|
|
}
|
|
|
|
toReturn = s_WindowsRuntimeResourceManager.GlobalResourceContextBestFitCultureInfo;
|
|
}
|
|
finally
|
|
{
|
|
ts_IsDoingAppXCultureInfoLookup = false;
|
|
}
|
|
|
|
return toReturn;
|
|
}
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CultureInfo Constructors
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
#if !FEATURE_CORECLR
|
|
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
|
#endif
|
|
public CultureInfo(String name) : this(name, true) {
|
|
}
|
|
|
|
|
|
public CultureInfo(String name, bool useUserOverride) {
|
|
if (name==null) {
|
|
throw new ArgumentNullException("name",
|
|
Environment.GetResourceString("ArgumentNull_String"));
|
|
}
|
|
Contract.EndContractBlock();
|
|
|
|
#if FEATURE_LEGACYNETCF
|
|
// Windows Phone 7 and 7.1 do not support Bengali. When running on Windows Phone 8,
|
|
// WinPhone 7.x apps get the old Mango text stack, not the Apollo text stack. The Mango
|
|
// text stack cannot display characters in Bengali, such as the culture's native name.
|
|
// Phone apps are already written to catch an exception here and bypass this culture.
|
|
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8 &&
|
|
(name == "bn" || name == "bn-BD" || name == "bn-IN" || name == "ml" || name == "or"))
|
|
throw new ArgumentException(Environment.GetResourceString("Argument_CultureNotSupported"));
|
|
#endif
|
|
|
|
// Get our data providing record
|
|
this.m_cultureData = CultureData.GetCultureData(name, useUserOverride);
|
|
|
|
if (this.m_cultureData == null) {
|
|
#if FEATURE_LEGACYNETCF
|
|
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
|
|
throw new PlatformNotSupportedException(Environment.GetResourceString("Argument_CultureNotSupported"));
|
|
#endif
|
|
throw new CultureNotFoundException("name", name, Environment.GetResourceString("Argument_CultureNotSupported"));
|
|
}
|
|
|
|
this.m_name = this.m_cultureData.CultureName;
|
|
this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
|
|
}
|
|
|
|
|
|
#if FEATURE_USE_LCID
|
|
public CultureInfo(int culture) : this(culture, true) {
|
|
}
|
|
|
|
public CultureInfo(int culture, bool useUserOverride) {
|
|
// We don't check for other invalid LCIDS here...
|
|
if (culture < 0) {
|
|
throw new ArgumentOutOfRangeException("culture",
|
|
Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
|
|
}
|
|
Contract.EndContractBlock();
|
|
|
|
InitializeFromCultureId(culture, useUserOverride);
|
|
}
|
|
|
|
private void InitializeFromCultureId(int culture, bool useUserOverride)
|
|
{
|
|
switch (culture)
|
|
{
|
|
case LOCALE_CUSTOM_DEFAULT:
|
|
case LOCALE_SYSTEM_DEFAULT:
|
|
case LOCALE_NEUTRAL:
|
|
case LOCALE_USER_DEFAULT:
|
|
case LOCALE_CUSTOM_UNSPECIFIED:
|
|
// Can't support unknown custom cultures and we do not support neutral or
|
|
// non-custom user locales.
|
|
throw new CultureNotFoundException(
|
|
"culture", culture, Environment.GetResourceString("Argument_CultureNotSupported"));
|
|
|
|
default:
|
|
// Now see if this LCID is supported in the system default CultureData table.
|
|
this.m_cultureData = CultureData.GetCultureData(culture, useUserOverride);
|
|
break;
|
|
}
|
|
this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
|
|
this.m_name = this.m_cultureData.CultureName;
|
|
}
|
|
#endif // FEATURE_USE_LCID
|
|
|
|
//
|
|
// CheckDomainSafetyObject throw if the object is customized object which cannot be attached to
|
|
// other object (like CultureInfo or DateTimeFormatInfo).
|
|
//
|
|
|
|
internal static void CheckDomainSafetyObject(Object obj, Object container)
|
|
{
|
|
if (obj.GetType().Assembly != typeof(System.Globalization.CultureInfo).Assembly) {
|
|
|
|
throw new InvalidOperationException(
|
|
String.Format(
|
|
CultureInfo.CurrentCulture,
|
|
Environment.GetResourceString("InvalidOperation_SubclassedObject"),
|
|
obj.GetType(),
|
|
container.GetType()));
|
|
}
|
|
Contract.EndContractBlock();
|
|
}
|
|
|
|
#region Serialization
|
|
// We need to store the override from the culture data record.
|
|
private bool m_useUserOverride;
|
|
|
|
[OnDeserialized]
|
|
private void OnDeserialized(StreamingContext ctx)
|
|
{
|
|
#if FEATURE_USE_LCID
|
|
// Whidbey+ should remember our name
|
|
// but v1 and v1.1 did not store name -- only lcid
|
|
// Whidbey did not store actual alternate sort name in m_name
|
|
// like we do in v4 so we can't use name for alternate sort
|
|
// e.g. for es-ES_tradnl: v2 puts es-ES in m_name; v4 puts es-ES_tradnl
|
|
if (m_name == null || IsAlternateSortLcid(cultureID))
|
|
{
|
|
Contract.Assert(cultureID >=0, "[CultureInfo.OnDeserialized] cultureID >= 0");
|
|
InitializeFromCultureId(cultureID, m_useUserOverride);
|
|
}
|
|
else
|
|
{
|
|
#endif
|
|
Contract.Assert(m_name != null, "[CultureInfo.OnDeserialized] m_name != null");
|
|
//
|
|
|
|
this.m_cultureData = CultureData.GetCultureData(m_name, m_useUserOverride);
|
|
if (this.m_cultureData == null)
|
|
throw new CultureNotFoundException(
|
|
"m_name", m_name, Environment.GetResourceString("Argument_CultureNotSupported"));
|
|
|
|
#if FEATURE_USE_LCID
|
|
}
|
|
#endif
|
|
m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
|
|
|
|
// in case we have non customized CultureInfo object we shouldn't allow any customized object
|
|
// to be attached to it for cross app domain safety.
|
|
if (this.GetType().Assembly == typeof(System.Globalization.CultureInfo).Assembly)
|
|
{
|
|
if (textInfo != null)
|
|
{
|
|
CheckDomainSafetyObject(textInfo, this);
|
|
}
|
|
|
|
if (compareInfo != null)
|
|
{
|
|
CheckDomainSafetyObject(compareInfo, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if FEATURE_USE_LCID
|
|
// A locale ID is a 32 bit value which is the combination of a
|
|
// language ID, a sort ID, and a reserved area. The bits are
|
|
// allocated as follows:
|
|
//
|
|
// +------------------------+-------+--------------------------------+
|
|
// | Reserved |Sort ID| Language ID |
|
|
// +------------------------+-------+--------------------------------+
|
|
// 31 20 19 16 15 0 bit
|
|
private const int LOCALE_SORTID_MASK = 0x000f0000;
|
|
|
|
static private bool IsAlternateSortLcid(int lcid)
|
|
{
|
|
if(lcid == LOCALE_TRADITIONAL_SPANISH)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return (lcid & LOCALE_SORTID_MASK) != 0;
|
|
}
|
|
#endif
|
|
|
|
[OnSerializing]
|
|
private void OnSerializing(StreamingContext ctx)
|
|
{
|
|
this.m_name = this.m_cultureData.CultureName;
|
|
this.m_useUserOverride = this.m_cultureData.UseUserOverride;
|
|
#if FEATURE_USE_LCID
|
|
// for compatibility with v2 serialize cultureID
|
|
this.cultureID = this.m_cultureData.ILANGUAGE;
|
|
#endif
|
|
}
|
|
#endregion Serialization
|
|
|
|
#if FEATURE_LEAK_CULTURE_INFO
|
|
// Is it safe to send this CultureInfo as an instance member of a Thread cross AppDomain boundaries?
|
|
// For Silverlight, the answer is always no.
|
|
internal bool IsSafeCrossDomain {
|
|
get {
|
|
Contract.Assert(m_createdDomainID != 0, "[CultureInfo.IsSafeCrossDomain] m_createdDomainID != 0");
|
|
return m_isSafeCrossDomain;
|
|
}
|
|
}
|
|
|
|
internal int CreatedDomainID {
|
|
get {
|
|
Contract.Assert(m_createdDomainID != 0, "[CultureInfo.CreatedDomain] m_createdDomainID != 0");
|
|
return m_createdDomainID;
|
|
}
|
|
}
|
|
|
|
internal void StartCrossDomainTracking() {
|
|
|
|
// If we have decided about cross domain safety of this instance, we are done
|
|
if (m_createdDomainID != 0)
|
|
return;
|
|
|
|
// If FEATURE_LEAK_CULTURE_INFO isn't enabled, we never want to pass
|
|
// CultureInfo as an instance member of a Thread.
|
|
if (CanSendCrossDomain())
|
|
{
|
|
m_isSafeCrossDomain = true;
|
|
}
|
|
|
|
// m_createdDomainID has to be assigned last. We use it to signal that we have
|
|
// completed the check.
|
|
System.Threading.Thread.MemoryBarrier();
|
|
m_createdDomainID = Thread.GetDomainID();
|
|
}
|
|
#endif // FEATURE_LEAK_CULTURE_INFO
|
|
|
|
// Is it safe to pass the CultureInfo cross AppDomain boundaries, not necessarily as an instance
|
|
// member of Thread. This is different from IsSafeCrossDomain, which implies passing the CultureInfo
|
|
// as a Thread instance member.
|
|
internal bool CanSendCrossDomain()
|
|
{
|
|
bool isSafe = false;
|
|
if (this.GetType() == typeof(System.Globalization.CultureInfo))
|
|
{
|
|
isSafe = true;
|
|
}
|
|
return isSafe;
|
|
}
|
|
|
|
// Constructor called by SQL Server's special munged culture - creates a culture with
|
|
// a TextInfo and CompareInfo that come from a supplied alternate source. This object
|
|
// is ALWAYS read-only.
|
|
// Note that we really cannot use an LCID version of this override as the cached
|
|
// name we create for it has to include both names, and the logic for this is in
|
|
// the GetCultureInfo override *only*.
|
|
internal CultureInfo(String cultureName, String textAndCompareCultureName)
|
|
{
|
|
if (cultureName==null) {
|
|
throw new ArgumentNullException("cultureName",
|
|
Environment.GetResourceString("ArgumentNull_String"));
|
|
}
|
|
Contract.EndContractBlock();
|
|
|
|
this.m_cultureData = CultureData.GetCultureData(cultureName, false);
|
|
if (this.m_cultureData == null)
|
|
throw new CultureNotFoundException(
|
|
"cultureName", cultureName, Environment.GetResourceString("Argument_CultureNotSupported"));
|
|
|
|
this.m_name = this.m_cultureData.CultureName;
|
|
|
|
CultureInfo altCulture = GetCultureInfo(textAndCompareCultureName);
|
|
this.compareInfo = altCulture.CompareInfo;
|
|
this.textInfo = altCulture.TextInfo;
|
|
}
|
|
|
|
// We do this to try to return the system UI language and the default user languages
|
|
// The callers should have a fallback if this fails (like Invariant)
|
|
private static CultureInfo GetCultureByName(String name, bool userOverride)
|
|
{
|
|
// Try to get our culture
|
|
try
|
|
{
|
|
return userOverride ? new CultureInfo(name) : CultureInfo.GetCultureInfo(name);
|
|
}
|
|
catch (ArgumentException)
|
|
{
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
//
|
|
// Return a specific culture. A tad irrelevent now since we always return valid data
|
|
// for neutral locales.
|
|
//
|
|
// Note that there's interesting behavior that tries to find a smaller name, ala RFC4647,
|
|
// if we can't find a bigger name. That doesn't help with things like "zh" though, so
|
|
// the approach is of questionable value
|
|
//
|
|
#if !FEATURE_CORECLR
|
|
public static CultureInfo CreateSpecificCulture(String name) {
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
|
|
CultureInfo culture;
|
|
|
|
try {
|
|
culture = new CultureInfo(name);
|
|
} catch(ArgumentException) {
|
|
// When CultureInfo throws this exception, it may be because someone passed the form
|
|
// like "az-az" because it came out of an http accept lang. We should try a little
|
|
// parsing to perhaps fall back to "az" here and use *it* to create the neutral.
|
|
|
|
int idx;
|
|
|
|
culture = null;
|
|
for(idx = 0; idx < name.Length; idx++) {
|
|
if('-' == name[idx]) {
|
|
try {
|
|
culture = new CultureInfo(name.Substring(0, idx));
|
|
break;
|
|
} catch(ArgumentException) {
|
|
// throw the original exception so the name in the string will be right
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(null == culture) {
|
|
// nothing to save here; throw the original exception
|
|
throw;
|
|
}
|
|
}
|
|
|
|
//In the most common case, they've given us a specific culture, so we'll just return that.
|
|
if (!(culture.IsNeutralCulture)) {
|
|
return culture;
|
|
}
|
|
|
|
return (new CultureInfo(culture.m_cultureData.SSPECIFICCULTURE));
|
|
}
|
|
#endif // !FEATURE_CORECLR
|
|
|
|
internal static bool VerifyCultureName(String cultureName, bool throwException)
|
|
{
|
|
// This function is used by ResourceManager.GetResourceFileName().
|
|
// ResourceManager searches for resource using CultureInfo.Name,
|
|
// so we should check against CultureInfo.Name.
|
|
|
|
for (int i=0; i<cultureName.Length; i++) {
|
|
char c = cultureName[i];
|
|
//
|
|
|
|
if (Char.IsLetterOrDigit(c) || c=='-' || c=='_') {
|
|
continue;
|
|
}
|
|
if (throwException) {
|
|
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidResourceCultureName", cultureName));
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
|
|
}
|
|
|
|
internal static bool VerifyCultureName(CultureInfo culture, bool throwException) {
|
|
Contract.Assert(culture!=null, "[CultureInfo.VerifyCultureName]culture!=null");
|
|
|
|
//If we have an instance of one of our CultureInfos, the user can't have changed the
|
|
//name and we know that all names are valid in files.
|
|
if (!culture.m_isInherited) {
|
|
return true;
|
|
}
|
|
|
|
return VerifyCultureName(culture.Name, throwException);
|
|
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CurrentCulture
|
|
//
|
|
// This instance provides methods based on the current user settings.
|
|
// These settings are volatile and may change over the lifetime of the
|
|
// thread.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
public static CultureInfo CurrentCulture
|
|
{
|
|
#if !FEATURE_CORECLR
|
|
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
|
#endif
|
|
get {
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
return Thread.CurrentThread.CurrentCulture;
|
|
}
|
|
}
|
|
|
|
//
|
|
// This is the equivalence of the Win32 GetUserDefaultLCID()
|
|
//
|
|
internal static CultureInfo UserDefaultCulture {
|
|
get
|
|
{
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
|
|
CultureInfo temp = s_userDefaultCulture;
|
|
if (temp == null)
|
|
{
|
|
//
|
|
// setting the s_userDefaultCulture with invariant culture before intializing it is a protection
|
|
// against recursion problem just in case if somebody called CurrentCulture from the CultureInfo
|
|
// creation path. the recursion can happen if the current user culture is a replaced custom culture.
|
|
//
|
|
|
|
s_userDefaultCulture = CultureInfo.InvariantCulture;
|
|
temp = InitUserDefaultCulture();
|
|
s_userDefaultCulture = temp;
|
|
}
|
|
return (temp);
|
|
}
|
|
}
|
|
|
|
//
|
|
// This is the equivalence of the Win32 GetUserDefaultUILanguage()
|
|
//
|
|
internal static CultureInfo UserDefaultUICulture {
|
|
get {
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
|
|
CultureInfo temp = s_userDefaultUICulture;
|
|
if (temp == null)
|
|
{
|
|
//
|
|
// setting the s_userDefaultCulture with invariant culture before intializing it is a protection
|
|
// against recursion problem just in case if somebody called CurrentUICulture from the CultureInfo
|
|
// creation path. the recursion can happen if the current user culture is a replaced custom culture.
|
|
//
|
|
|
|
s_userDefaultUICulture = CultureInfo.InvariantCulture;
|
|
|
|
temp = InitUserDefaultUICulture();
|
|
s_userDefaultUICulture = temp;
|
|
}
|
|
return (temp);
|
|
}
|
|
}
|
|
|
|
|
|
public static CultureInfo CurrentUICulture {
|
|
#if !FEATURE_CORECLR
|
|
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
|
#endif
|
|
get {
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
return Thread.CurrentThread.CurrentUICulture;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// This is the equivalence of the Win32 GetSystemDefaultUILanguage()
|
|
//
|
|
//
|
|
public static CultureInfo InstalledUICulture {
|
|
get {
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
|
|
CultureInfo temp = s_InstalledUICultureInfo;
|
|
if (temp == null) {
|
|
String strDefault = GetSystemDefaultUILanguage();
|
|
temp = GetCultureByName(strDefault, true);
|
|
|
|
if (temp == null)
|
|
{
|
|
temp = InvariantCulture;
|
|
}
|
|
|
|
temp.m_isReadOnly = true;
|
|
s_InstalledUICultureInfo = temp;
|
|
}
|
|
return (temp);
|
|
}
|
|
}
|
|
|
|
public static CultureInfo DefaultThreadCurrentCulture {
|
|
get {
|
|
return s_DefaultThreadCurrentCulture;
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
#pragma warning disable 618
|
|
[SecurityPermission(SecurityAction.Demand, ControlThread = true)]
|
|
#pragma warning restore 618
|
|
set {
|
|
|
|
// If you add pre-conditions to this method, check to see if you also need to
|
|
// add them to Thread.CurrentCulture.set.
|
|
|
|
s_DefaultThreadCurrentCulture = value;
|
|
}
|
|
}
|
|
|
|
public static CultureInfo DefaultThreadCurrentUICulture {
|
|
get {
|
|
return s_DefaultThreadCurrentUICulture;
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
#pragma warning disable 618
|
|
[SecurityPermission(SecurityAction.Demand, ControlThread = true)]
|
|
#pragma warning restore 618
|
|
set {
|
|
|
|
//If they're trying to use a Culture with a name that we can't use in resource lookup,
|
|
//don't even let them set it on the thread.
|
|
|
|
// If you add more pre-conditions to this method, check to see if you also need to
|
|
// add them to Thread.CurrentUICulture.set.
|
|
|
|
if (value != null)
|
|
{
|
|
CultureInfo.VerifyCultureName(value, true);
|
|
}
|
|
|
|
s_DefaultThreadCurrentUICulture = value;
|
|
}
|
|
}
|
|
|
|
#if FEATURE_LEGACYNETCF
|
|
//
|
|
// Helper methods to set default thread culture without security demand. Used
|
|
// by NetCF compatibility quirk. See comment in Thread.CurrentUICulture setter for details.
|
|
//
|
|
internal static void SetCurrentUICultureQuirk(CultureInfo value) {
|
|
s_DefaultThreadCurrentUICulture = value;
|
|
}
|
|
|
|
internal static void SetCurrentCultureQuirk(CultureInfo value) {
|
|
s_DefaultThreadCurrentCulture = value;
|
|
}
|
|
#endif
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// InvariantCulture
|
|
//
|
|
// This instance provides methods, for example for casing and sorting,
|
|
// that are independent of the system and current user settings. It
|
|
// should be used only by processes such as some system services that
|
|
// require such invariant results (eg. file systems). In general,
|
|
// the results are not linguistically correct and do not match any
|
|
// culture info.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
public static CultureInfo InvariantCulture {
|
|
[Pure]
|
|
#if !FEATURE_CORECLR
|
|
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
|
#endif
|
|
get {
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
return (s_InvariantCultureInfo);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Parent
|
|
//
|
|
// Return the parent CultureInfo for the current instance.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
public virtual CultureInfo Parent
|
|
{
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get
|
|
{
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
|
|
if (null == m_parent)
|
|
{
|
|
try
|
|
{
|
|
string parentName = this.m_cultureData.SPARENT;
|
|
|
|
if (String.IsNullOrEmpty(parentName))
|
|
{
|
|
m_parent = InvariantCulture;
|
|
}
|
|
else
|
|
{
|
|
m_parent = new CultureInfo(parentName, this.m_cultureData.UseUserOverride);
|
|
}
|
|
}
|
|
catch (ArgumentException)
|
|
{
|
|
// For whatever reason our IPARENT or SPARENT wasn't correct, so use invariant
|
|
// We can't allow ourselves to fail. In case of custom cultures the parent of the
|
|
// current custom culture isn't installed.
|
|
m_parent = InvariantCulture;
|
|
}
|
|
}
|
|
return m_parent;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LCID
|
|
//
|
|
// Returns a properly formed culture identifier for the current
|
|
// culture info.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
#if FEATURE_USE_LCID
|
|
public virtual int LCID {
|
|
#if !FEATURE_CORECLR
|
|
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
|
#endif
|
|
get {
|
|
return (this.m_cultureData.ILANGUAGE);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// BaseInputLanguage
|
|
//
|
|
// Essentially an LCID, though one that may be different than LCID in the case
|
|
// of a customized culture (LCID == LOCALE_CUSTOM_UNSPECIFIED).
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
#if FEATURE_USE_LCID
|
|
[System.Runtime.InteropServices.ComVisible(false)]
|
|
public virtual int KeyboardLayoutId
|
|
{
|
|
get
|
|
{
|
|
int keyId = this.m_cultureData.IINPUTLANGUAGEHANDLE;
|
|
|
|
// Not a customized culture, return the default Keyboard layout ID, which is the same as the language ID.
|
|
return (keyId);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if !FEATURE_CORECLR
|
|
public static CultureInfo[] GetCultures(CultureTypes types) {
|
|
Contract.Ensures(Contract.Result<CultureInfo[]>() != null);
|
|
// internally we treat UserCustomCultures as Supplementals but v2
|
|
// treats as Supplementals and Replacements
|
|
if((types & CultureTypes.UserCustomCulture) == CultureTypes.UserCustomCulture)
|
|
{
|
|
types |= CultureTypes.ReplacementCultures;
|
|
}
|
|
return (CultureData.GetCultures(types));
|
|
}
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Name
|
|
//
|
|
// Returns the full name of the CultureInfo. The name is in format like
|
|
// "en-US" This version does NOT include sort information in the name.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
public virtual String Name {
|
|
get {
|
|
Contract.Ensures(Contract.Result<String>() != null);
|
|
|
|
// We return non sorting name here.
|
|
if (this.m_nonSortName == null) {
|
|
this.m_nonSortName = this.m_cultureData.SNAME;
|
|
if (this.m_nonSortName == null) {
|
|
this.m_nonSortName = String.Empty;
|
|
}
|
|
}
|
|
return this.m_nonSortName;
|
|
}
|
|
}
|
|
|
|
// This one has the sort information (ie: de-DE_phoneb)
|
|
internal String SortName
|
|
{
|
|
get
|
|
{
|
|
if (this.m_sortName == null)
|
|
{
|
|
this.m_sortName = this.m_cultureData.SCOMPAREINFO;
|
|
}
|
|
|
|
return this.m_sortName;
|
|
}
|
|
}
|
|
|
|
//
|
|
#if !FEATURE_CORECLR
|
|
[System.Runtime.InteropServices.ComVisible(false)]
|
|
public String IetfLanguageTag
|
|
{
|
|
get
|
|
{
|
|
Contract.Ensures(Contract.Result<String>() != null);
|
|
|
|
// special case the compatibility cultures
|
|
switch (this.Name)
|
|
{
|
|
case "zh-CHT":
|
|
return "zh-Hant";
|
|
case "zh-CHS":
|
|
return "zh-Hans";
|
|
default:
|
|
return this.Name;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DisplayName
|
|
//
|
|
// Returns the full name of the CultureInfo in the localized language.
|
|
// For example, if the localized language of the runtime is Spanish and the CultureInfo is
|
|
// US English, "Ingles (Estados Unidos)" will be returned.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
public virtual String DisplayName
|
|
{
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get
|
|
{
|
|
Contract.Ensures(Contract.Result<String>() != null);
|
|
Contract.Assert(m_name != null, "[CultureInfo.DisplayName]Always expect m_name to be set");
|
|
|
|
return m_cultureData.SLOCALIZEDDISPLAYNAME;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetNativeName
|
|
//
|
|
// Returns the full name of the CultureInfo in the native language.
|
|
// For example, if the CultureInfo is US English, "English
|
|
// (United States)" will be returned.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
public virtual String NativeName {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get {
|
|
Contract.Ensures(Contract.Result<String>() != null);
|
|
return (this.m_cultureData.SNATIVEDISPLAYNAME);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetEnglishName
|
|
//
|
|
// Returns the full name of the CultureInfo in English.
|
|
// For example, if the CultureInfo is US English, "English
|
|
// (United States)" will be returned.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
public virtual String EnglishName {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get {
|
|
Contract.Ensures(Contract.Result<String>() != null);
|
|
return (this.m_cultureData.SENGDISPLAYNAME);
|
|
}
|
|
}
|
|
|
|
// ie: en
|
|
public virtual String TwoLetterISOLanguageName {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get {
|
|
Contract.Ensures(Contract.Result<String>() != null);
|
|
return (this.m_cultureData.SISO639LANGNAME);
|
|
}
|
|
}
|
|
|
|
#if !FEATURE_CORECLR
|
|
// ie: eng
|
|
public virtual String ThreeLetterISOLanguageName {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get {
|
|
Contract.Ensures(Contract.Result<String>() != null);
|
|
return (this.m_cultureData.SISO639LANGNAME2);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ThreeLetterWindowsLanguageName
|
|
//
|
|
// Returns the 3 letter windows language name for the current instance. eg: "ENU"
|
|
// The ISO names are much preferred
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
public virtual String ThreeLetterWindowsLanguageName {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get {
|
|
Contract.Ensures(Contract.Result<String>() != null);
|
|
return (this.m_cultureData.SABBREVLANGNAME);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CompareInfo Read-Only Property
|
|
//
|
|
// Gets the CompareInfo for this culture.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
public virtual CompareInfo CompareInfo
|
|
{
|
|
get
|
|
{
|
|
Contract.Ensures(Contract.Result<CompareInfo>() != null);
|
|
|
|
if (this.compareInfo == null)
|
|
{
|
|
// Since CompareInfo's don't have any overrideable properties, get the CompareInfo from
|
|
// the Non-Overridden CultureInfo so that we only create one CompareInfo per culture
|
|
CompareInfo temp = UseUserOverride
|
|
? GetCultureInfo(this.m_name).CompareInfo
|
|
: new CompareInfo(this);
|
|
if (CompatibilitySwitches.IsCompatibilityBehaviorDefined)
|
|
{
|
|
this.compareInfo = temp;
|
|
}
|
|
else
|
|
{
|
|
return temp;
|
|
}
|
|
}
|
|
return (compareInfo);
|
|
}
|
|
}
|
|
|
|
#if !FEATURE_CORECLR
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// RegionInfo
|
|
//
|
|
// Gets the RegionInfo for this culture.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
private RegionInfo Region
|
|
{
|
|
get
|
|
{
|
|
if (regionInfo==null)
|
|
{
|
|
// Make a new regionInfo
|
|
RegionInfo tempRegionInfo = new RegionInfo(this.m_cultureData);
|
|
regionInfo = tempRegionInfo;
|
|
}
|
|
return (regionInfo);
|
|
}
|
|
}
|
|
#endif // FEATURE_CORECLR
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// TextInfo
|
|
//
|
|
// Gets the TextInfo for this culture.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
public virtual TextInfo TextInfo {
|
|
get {
|
|
Contract.Ensures(Contract.Result<TextInfo>() != null);
|
|
|
|
if (textInfo==null)
|
|
{
|
|
// Make a new textInfo
|
|
TextInfo tempTextInfo = new TextInfo(this.m_cultureData);
|
|
tempTextInfo.SetReadOnlyState(m_isReadOnly);
|
|
|
|
if (CompatibilitySwitches.IsCompatibilityBehaviorDefined)
|
|
{
|
|
textInfo = tempTextInfo;
|
|
}
|
|
else
|
|
{
|
|
return tempTextInfo;
|
|
}
|
|
}
|
|
return (textInfo);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Equals
|
|
//
|
|
// Implements Object.Equals(). Returns a boolean indicating whether
|
|
// or not object refers to the same CultureInfo as the current instance.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
public override bool Equals(Object value)
|
|
{
|
|
if (Object.ReferenceEquals(this, value))
|
|
return true;
|
|
|
|
CultureInfo that = value as CultureInfo;
|
|
|
|
if (that != null)
|
|
{
|
|
// using CompareInfo to verify the data passed through the constructor
|
|
// CultureInfo(String cultureName, String textAndCompareCultureName)
|
|
|
|
return (this.Name.Equals(that.Name) && this.CompareInfo.Equals(that.CompareInfo));
|
|
}
|
|
|
|
return (false);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetHashCode
|
|
//
|
|
// Implements Object.GetHashCode(). Returns the hash code for the
|
|
// CultureInfo. The hash code is guaranteed to be the same for CultureInfo A
|
|
// and B where A.Equals(B) is true.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
#if !FEATURE_CORECLR
|
|
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
|
#endif
|
|
public override int GetHashCode()
|
|
{
|
|
return (this.Name.GetHashCode() + this.CompareInfo.GetHashCode());
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ToString
|
|
//
|
|
// Implements Object.ToString(). Returns the name of the CultureInfo,
|
|
// eg. "de-DE_phoneb", "en-US", or "fj-FJ".
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
public override String ToString()
|
|
{
|
|
Contract.Ensures(Contract.Result<String>() != null);
|
|
|
|
Contract.Assert(m_name != null, "[CultureInfo.ToString]Always expect m_name to be set");
|
|
return m_name;
|
|
}
|
|
|
|
|
|
public virtual Object GetFormat(Type formatType) {
|
|
if (formatType == typeof(NumberFormatInfo)) {
|
|
return (NumberFormat);
|
|
}
|
|
if (formatType == typeof(DateTimeFormatInfo)) {
|
|
return (DateTimeFormat);
|
|
}
|
|
return (null);
|
|
}
|
|
|
|
public virtual bool IsNeutralCulture {
|
|
get {
|
|
return this.m_cultureData.IsNeutralCulture;
|
|
}
|
|
}
|
|
|
|
#if !FEATURE_CORECLR
|
|
[System.Runtime.InteropServices.ComVisible(false)]
|
|
public CultureTypes CultureTypes
|
|
{
|
|
get
|
|
{
|
|
CultureTypes types = 0;
|
|
|
|
if (m_cultureData.IsNeutralCulture)
|
|
types |= CultureTypes.NeutralCultures;
|
|
else
|
|
types |= CultureTypes.SpecificCultures;
|
|
|
|
types |= m_cultureData.IsWin32Installed ? CultureTypes.InstalledWin32Cultures : 0;
|
|
|
|
// Disable warning 618: System.Globalization.CultureTypes.FrameworkCultures' is obsolete
|
|
#pragma warning disable 618
|
|
types |= m_cultureData.IsFramework ? CultureTypes.FrameworkCultures : 0;
|
|
|
|
#pragma warning restore 618
|
|
types |= m_cultureData.IsSupplementalCustomCulture ? CultureTypes.UserCustomCulture : 0;
|
|
types |= m_cultureData.IsReplacementCulture ? CultureTypes.ReplacementCultures | CultureTypes.UserCustomCulture : 0;
|
|
|
|
return types;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
public virtual NumberFormatInfo NumberFormat {
|
|
get
|
|
{
|
|
Contract.Ensures(Contract.Result<NumberFormatInfo>() != null);
|
|
|
|
if (numInfo == null) {
|
|
NumberFormatInfo temp = new NumberFormatInfo(this.m_cultureData);
|
|
temp.isReadOnly = m_isReadOnly;
|
|
numInfo = temp;
|
|
}
|
|
return (numInfo);
|
|
}
|
|
set {
|
|
if (value == null) {
|
|
throw new ArgumentNullException("value",
|
|
Environment.GetResourceString("ArgumentNull_Obj"));
|
|
}
|
|
Contract.EndContractBlock();
|
|
VerifyWritable();
|
|
numInfo = value;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetDateTimeFormatInfo
|
|
//
|
|
// Create a DateTimeFormatInfo, and fill in the properties according to
|
|
// the CultureID.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
public virtual DateTimeFormatInfo DateTimeFormat {
|
|
get {
|
|
Contract.Ensures(Contract.Result<DateTimeFormatInfo>() != null);
|
|
|
|
if (dateTimeInfo == null) {
|
|
// Change the calendar of DTFI to the specified calendar of this CultureInfo.
|
|
DateTimeFormatInfo temp = new DateTimeFormatInfo(
|
|
this.m_cultureData, this.Calendar);
|
|
temp.m_isReadOnly = m_isReadOnly;
|
|
System.Threading.Thread.MemoryBarrier();
|
|
dateTimeInfo = temp;
|
|
}
|
|
return (dateTimeInfo);
|
|
}
|
|
|
|
set {
|
|
if (value == null) {
|
|
throw new ArgumentNullException("value",
|
|
Environment.GetResourceString("ArgumentNull_Obj"));
|
|
}
|
|
Contract.EndContractBlock();
|
|
VerifyWritable();
|
|
dateTimeInfo = value;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public void ClearCachedData() {
|
|
s_userDefaultUICulture = null;
|
|
s_userDefaultCulture = null;
|
|
|
|
RegionInfo.s_currentRegionInfo = null;
|
|
#if !FEATURE_CORECLR && !FEATURE_PAL // System.TimeZone does not exist in CoreCLR
|
|
TimeZone.ResetTimeZone();
|
|
#endif // FEATURE_CORECLR
|
|
TimeZoneInfo.ClearCachedData();
|
|
// Delete the cached cultures.
|
|
s_LcidCachedCultures = null;
|
|
s_NameCachedCultures = null;
|
|
|
|
CultureData.ClearCachedData();
|
|
}
|
|
|
|
/*=================================GetCalendarInstance==========================
|
|
**Action: Map a Win32 CALID to an instance of supported calendar.
|
|
**Returns: An instance of calendar.
|
|
**Arguments: calType The Win32 CALID
|
|
**Exceptions:
|
|
** Shouldn't throw exception since the calType value is from our data table or from Win32 registry.
|
|
** If we are in trouble (like getting a weird value from Win32 registry), just return the GregorianCalendar.
|
|
============================================================================*/
|
|
internal static Calendar GetCalendarInstance(int calType) {
|
|
if (calType==Calendar.CAL_GREGORIAN) {
|
|
return (new GregorianCalendar());
|
|
}
|
|
return GetCalendarInstanceRare(calType);
|
|
}
|
|
|
|
//This function exists as a shortcut to prevent us from loading all of the non-gregorian
|
|
//calendars unless they're required.
|
|
internal static Calendar GetCalendarInstanceRare(int calType) {
|
|
Contract.Assert(calType!=Calendar.CAL_GREGORIAN, "calType!=Calendar.CAL_GREGORIAN");
|
|
|
|
switch (calType) {
|
|
case Calendar.CAL_GREGORIAN_US: // Gregorian (U.S.) calendar
|
|
case Calendar.CAL_GREGORIAN_ME_FRENCH: // Gregorian Middle East French calendar
|
|
case Calendar.CAL_GREGORIAN_ARABIC: // Gregorian Arabic calendar
|
|
case Calendar.CAL_GREGORIAN_XLIT_ENGLISH: // Gregorian Transliterated English calendar
|
|
case Calendar.CAL_GREGORIAN_XLIT_FRENCH: // Gregorian Transliterated French calendar
|
|
return (new GregorianCalendar((GregorianCalendarTypes)calType));
|
|
case Calendar.CAL_TAIWAN: // Taiwan Era calendar
|
|
return (new TaiwanCalendar());
|
|
case Calendar.CAL_JAPAN: // Japanese Emperor Era calendar
|
|
return (new JapaneseCalendar());
|
|
case Calendar.CAL_KOREA: // Korean Tangun Era calendar
|
|
return (new KoreanCalendar());
|
|
case Calendar.CAL_THAI: // Thai calendar
|
|
return (new ThaiBuddhistCalendar());
|
|
case Calendar.CAL_HIJRI: // Hijri (Arabic Lunar) calendar
|
|
return (new HijriCalendar());
|
|
case Calendar.CAL_HEBREW: // Hebrew (Lunar) calendar
|
|
return (new HebrewCalendar());
|
|
case Calendar.CAL_UMALQURA:
|
|
return (new UmAlQuraCalendar());
|
|
#if !FEATURE_ONLY_CORE_CALENDARS
|
|
case Calendar.CAL_PERSIAN:
|
|
return (new PersianCalendar());
|
|
case Calendar.CAL_CHINESELUNISOLAR:
|
|
return (new ChineseLunisolarCalendar());
|
|
case Calendar.CAL_JAPANESELUNISOLAR:
|
|
return (new JapaneseLunisolarCalendar());
|
|
case Calendar.CAL_KOREANLUNISOLAR:
|
|
return (new KoreanLunisolarCalendar());
|
|
case Calendar.CAL_TAIWANLUNISOLAR:
|
|
return (new TaiwanLunisolarCalendar());
|
|
#endif // !FEATURE_ONLY_CORE_CALENDARS
|
|
}
|
|
return (new GregorianCalendar());
|
|
}
|
|
|
|
|
|
/*=================================Calendar==========================
|
|
**Action: Return/set the default calendar used by this culture.
|
|
** This value can be overridden by regional option if this is a current culture.
|
|
**Returns:
|
|
**Arguments:
|
|
**Exceptions:
|
|
** ArgumentNull_Obj if the set value is null.
|
|
============================================================================*/
|
|
|
|
|
|
public virtual Calendar Calendar {
|
|
get {
|
|
Contract.Ensures(Contract.Result<Calendar>() != null);
|
|
if (calendar == null) {
|
|
Contract.Assert(this.m_cultureData.CalendarIds.Length > 0, "this.m_cultureData.CalendarIds.Length > 0");
|
|
// Get the default calendar for this culture. Note that the value can be
|
|
// from registry if this is a user default culture.
|
|
Calendar newObj = this.m_cultureData.DefaultCalendar;
|
|
|
|
System.Threading.Thread.MemoryBarrier();
|
|
newObj.SetReadOnlyState(m_isReadOnly);
|
|
calendar = newObj;
|
|
}
|
|
return (calendar);
|
|
}
|
|
}
|
|
|
|
/*=================================OptionCalendars==========================
|
|
**Action: Return an array of the optional calendar for this culture.
|
|
**Returns: an array of Calendar.
|
|
**Arguments:
|
|
**Exceptions:
|
|
============================================================================*/
|
|
|
|
|
|
public virtual Calendar[] OptionalCalendars {
|
|
get {
|
|
Contract.Ensures(Contract.Result<Calendar[]>() != null);
|
|
|
|
//
|
|
// This property always returns a new copy of the calendar array.
|
|
//
|
|
int[] calID = this.m_cultureData.CalendarIds;
|
|
Calendar [] cals = new Calendar[calID.Length];
|
|
for (int i = 0; i < cals.Length; i++) {
|
|
cals[i] = GetCalendarInstance(calID[i]);
|
|
}
|
|
return (cals);
|
|
}
|
|
}
|
|
|
|
|
|
public bool UseUserOverride {
|
|
get {
|
|
return (this.m_cultureData.UseUserOverride);
|
|
}
|
|
}
|
|
|
|
#if !FEATURE_CORECLR
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[System.Runtime.InteropServices.ComVisible(false)]
|
|
public CultureInfo GetConsoleFallbackUICulture()
|
|
{
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
|
|
CultureInfo temp = m_consoleFallbackCulture;
|
|
if (temp == null)
|
|
{
|
|
temp = CreateSpecificCulture(this.m_cultureData.SCONSOLEFALLBACKNAME);
|
|
temp.m_isReadOnly = true;
|
|
m_consoleFallbackCulture = temp;
|
|
}
|
|
return (temp);
|
|
}
|
|
#endif
|
|
|
|
public virtual Object Clone()
|
|
{
|
|
Contract.Ensures(Contract.Result<Object>() != null);
|
|
|
|
CultureInfo ci = (CultureInfo)MemberwiseClone();
|
|
ci.m_isReadOnly = false;
|
|
|
|
//If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
|
|
//they've already been allocated. If this is a derived type, we'll take a more generic codepath.
|
|
if (!m_isInherited)
|
|
{
|
|
if (this.dateTimeInfo != null)
|
|
{
|
|
ci.dateTimeInfo = (DateTimeFormatInfo)this.dateTimeInfo.Clone();
|
|
}
|
|
if (this.numInfo != null)
|
|
{
|
|
ci.numInfo = (NumberFormatInfo)this.numInfo.Clone();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
ci.DateTimeFormat = (DateTimeFormatInfo)this.DateTimeFormat.Clone();
|
|
ci.NumberFormat = (NumberFormatInfo)this.NumberFormat.Clone();
|
|
}
|
|
|
|
if (textInfo != null)
|
|
{
|
|
ci.textInfo = (TextInfo) textInfo.Clone();
|
|
}
|
|
|
|
if (calendar != null)
|
|
{
|
|
ci.calendar = (Calendar) calendar.Clone();
|
|
}
|
|
|
|
return (ci);
|
|
}
|
|
|
|
|
|
public static CultureInfo ReadOnly(CultureInfo ci) {
|
|
if (ci == null) {
|
|
throw new ArgumentNullException("ci");
|
|
}
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
Contract.EndContractBlock();
|
|
|
|
if (ci.IsReadOnly) {
|
|
return (ci);
|
|
}
|
|
CultureInfo newInfo = (CultureInfo)(ci.MemberwiseClone());
|
|
|
|
if (!ci.IsNeutralCulture)
|
|
{
|
|
//If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
|
|
//they've already been allocated. If this is a derived type, we'll take a more generic codepath.
|
|
if (!ci.m_isInherited) {
|
|
if (ci.dateTimeInfo != null) {
|
|
newInfo.dateTimeInfo = DateTimeFormatInfo.ReadOnly(ci.dateTimeInfo);
|
|
}
|
|
if (ci.numInfo != null) {
|
|
newInfo.numInfo = NumberFormatInfo.ReadOnly(ci.numInfo);
|
|
}
|
|
|
|
} else {
|
|
newInfo.DateTimeFormat = DateTimeFormatInfo.ReadOnly(ci.DateTimeFormat);
|
|
newInfo.NumberFormat = NumberFormatInfo.ReadOnly(ci.NumberFormat);
|
|
}
|
|
}
|
|
|
|
if (ci.textInfo != null)
|
|
{
|
|
newInfo.textInfo = TextInfo.ReadOnly(ci.textInfo);
|
|
}
|
|
|
|
if (ci.calendar != null)
|
|
{
|
|
newInfo.calendar = Calendar.ReadOnly(ci.calendar);
|
|
}
|
|
|
|
// Don't set the read-only flag too early.
|
|
// We should set the read-only flag here. Otherwise, info.DateTimeFormat will not be able to set.
|
|
newInfo.m_isReadOnly = true;
|
|
|
|
return (newInfo);
|
|
}
|
|
|
|
|
|
public bool IsReadOnly {
|
|
get {
|
|
return (m_isReadOnly);
|
|
}
|
|
}
|
|
|
|
private void VerifyWritable() {
|
|
if (m_isReadOnly) {
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
|
|
}
|
|
Contract.EndContractBlock();
|
|
}
|
|
|
|
// For resource lookup, we consider a culture the invariant culture by name equality.
|
|
// We perform this check frequently during resource lookup, so adding a property for
|
|
// improved readability.
|
|
internal bool HasInvariantCultureName
|
|
{
|
|
get { return Name == CultureInfo.InvariantCulture.Name; }
|
|
}
|
|
|
|
// Helper function both both overloads of GetCachedReadOnlyCulture. If lcid is 0, we use the name.
|
|
// If lcid is -1, use the altName and create one of those special SQL cultures.
|
|
internal static CultureInfo GetCultureInfoHelper(int lcid, string name, string altName)
|
|
{
|
|
// There is a race condition in this code with the side effect that the second thread's value
|
|
// clobbers the first in the dictionary. This is an acceptable ---- since the CultureInfo objects
|
|
// are content equal (but not reference equal). Since we make no guarantees there, this ---- is
|
|
// acceptable.
|
|
// See code:Dictionary#DictionaryVersusHashtableThreadSafety for details on Dictionary versus
|
|
// Hashtable thread safety.
|
|
|
|
// retval is our return value.
|
|
CultureInfo retval;
|
|
|
|
// Temporary hashtable for the names.
|
|
Hashtable tempNameHT = s_NameCachedCultures;
|
|
|
|
if (name != null)
|
|
{
|
|
name = CultureData.AnsiToLower(name);
|
|
}
|
|
|
|
if (altName != null)
|
|
{
|
|
altName = CultureData.AnsiToLower(altName);
|
|
}
|
|
|
|
// We expect the same result for both hashtables, but will test individually for added safety.
|
|
if (tempNameHT == null)
|
|
{
|
|
tempNameHT = Hashtable.Synchronized(new Hashtable());
|
|
}
|
|
else
|
|
{
|
|
// If we are called by name, check if the object exists in the hashtable. If so, return it.
|
|
if (lcid == -1)
|
|
{
|
|
retval = (CultureInfo)tempNameHT[name + '\xfffd' + altName];
|
|
if (retval != null)
|
|
{
|
|
return retval;
|
|
}
|
|
}
|
|
else if (lcid == 0)
|
|
{
|
|
retval = (CultureInfo)tempNameHT[name];
|
|
if (retval != null)
|
|
{
|
|
return retval;
|
|
}
|
|
}
|
|
}
|
|
#if FEATURE_USE_LCID
|
|
// Next, the Lcid table.
|
|
Hashtable tempLcidHT = s_LcidCachedCultures;
|
|
|
|
if (tempLcidHT == null)
|
|
{
|
|
// Case insensitive is not an issue here, save the constructor call.
|
|
tempLcidHT = Hashtable.Synchronized(new Hashtable());
|
|
}
|
|
else
|
|
{
|
|
// If we were called by Lcid, check if the object exists in the table. If so, return it.
|
|
if (lcid > 0)
|
|
{
|
|
retval = (CultureInfo) tempLcidHT[lcid];
|
|
if (retval != null)
|
|
{
|
|
return retval;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
// We now have two temporary hashtables and the desired object was not found.
|
|
// We'll construct it. We catch any exceptions from the constructor call and return null.
|
|
try
|
|
{
|
|
switch(lcid)
|
|
{
|
|
case -1:
|
|
// call the private constructor
|
|
retval = new CultureInfo(name, altName);
|
|
break;
|
|
|
|
case 0:
|
|
retval = new CultureInfo(name, false);
|
|
break;
|
|
|
|
default:
|
|
#if FEATURE_USE_LCID
|
|
retval = new CultureInfo(lcid, false);
|
|
break;
|
|
#else
|
|
return null;
|
|
#endif
|
|
}
|
|
}
|
|
catch(ArgumentException)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
// Set it to read-only
|
|
retval.m_isReadOnly = true;
|
|
|
|
if (lcid == -1)
|
|
{
|
|
// This new culture will be added only to the name hash table.
|
|
tempNameHT[name + '\xfffd' + altName] = retval;
|
|
|
|
// when lcid == -1 then TextInfo object is already get created and we need to set it as read only.
|
|
retval.TextInfo.SetReadOnlyState(true);
|
|
}
|
|
else
|
|
{
|
|
// Remember our name (as constructed). Do NOT use alternate sort name versions because
|
|
// we have internal state representing the sort. (So someone would get the wrong cached version)
|
|
string newName = CultureData.AnsiToLower(retval.m_name);
|
|
|
|
// We add this new culture info object to both tables.
|
|
tempNameHT[newName] = retval;
|
|
#if FEATURE_USE_LCID
|
|
const int LCID_ZH_CHS_HANS = 0x0004;
|
|
const int LCID_ZH_CHT_HANT = 0x7c04;
|
|
|
|
if ((retval.LCID == LCID_ZH_CHS_HANS && newName == "zh-hans")
|
|
|| (retval.LCID == LCID_ZH_CHT_HANT && newName == "zh-hant"))
|
|
{
|
|
// do nothing because we only want zh-CHS and zh-CHT to cache
|
|
// by lcid
|
|
}
|
|
else
|
|
{
|
|
tempLcidHT[retval.LCID] = retval;
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
#if FEATURE_USE_LCID
|
|
// Copy the two hashtables to the corresponding member variables. This will potentially overwrite
|
|
// new tables simultaneously created by a new thread, but maximizes thread safety.
|
|
if(-1 != lcid)
|
|
{
|
|
// Only when we modify the lcid hash table, is there a need to overwrite.
|
|
s_LcidCachedCultures = tempLcidHT;
|
|
}
|
|
#endif
|
|
|
|
s_NameCachedCultures = tempNameHT;
|
|
|
|
// Finally, return our new CultureInfo object.
|
|
return retval;
|
|
}
|
|
|
|
#if FEATURE_USE_LCID
|
|
// Gets a cached copy of the specified culture from an internal hashtable (or creates it
|
|
// if not found). (LCID version)... use named version
|
|
public static CultureInfo GetCultureInfo(int culture)
|
|
{
|
|
// Must check for -1 now since the helper function uses the value to signal
|
|
// the altCulture code path for SQL Server.
|
|
// Also check for zero as this would fail trying to add as a key to the hash.
|
|
if (culture <= 0) {
|
|
throw new ArgumentOutOfRangeException("culture",
|
|
Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
|
|
}
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
Contract.EndContractBlock();
|
|
CultureInfo retval = GetCultureInfoHelper(culture, null, null);
|
|
if (null == retval)
|
|
{
|
|
throw new CultureNotFoundException(
|
|
"culture", culture, Environment.GetResourceString("Argument_CultureNotSupported"));
|
|
}
|
|
return retval;
|
|
}
|
|
#endif
|
|
|
|
// Gets a cached copy of the specified culture from an internal hashtable (or creates it
|
|
// if not found). (Named version)
|
|
public static CultureInfo GetCultureInfo(string name)
|
|
{
|
|
// Make sure we have a valid, non-zero length string as name
|
|
if (name == null)
|
|
{
|
|
throw new ArgumentNullException("name");
|
|
}
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
Contract.EndContractBlock();
|
|
|
|
CultureInfo retval = GetCultureInfoHelper(0, name, null);
|
|
if (retval == null)
|
|
{
|
|
throw new CultureNotFoundException(
|
|
"name", name, Environment.GetResourceString("Argument_CultureNotSupported"));
|
|
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
// Gets a cached copy of the specified culture from an internal hashtable (or creates it
|
|
// if not found).
|
|
public static CultureInfo GetCultureInfo(string name, string altName)
|
|
{
|
|
// Make sure we have a valid, non-zero length string as name
|
|
if (null == name)
|
|
{
|
|
throw new ArgumentNullException("name");
|
|
}
|
|
|
|
if (null == altName)
|
|
{
|
|
throw new ArgumentNullException("altName");
|
|
}
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
Contract.EndContractBlock();
|
|
|
|
CultureInfo retval = GetCultureInfoHelper(-1, name, altName);
|
|
if (retval == null)
|
|
{
|
|
throw new CultureNotFoundException("name or altName",
|
|
String.Format(
|
|
CultureInfo.CurrentCulture,
|
|
Environment.GetResourceString("Argument_OneOfCulturesNotSupported"),
|
|
name,
|
|
altName));
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
|
|
#if !FEATURE_CORECLR
|
|
// This function is deprecated, we don't like it
|
|
public static CultureInfo GetCultureInfoByIetfLanguageTag(string name)
|
|
{
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
|
|
// Disallow old zh-CHT/zh-CHS names
|
|
if (name == "zh-CHT" || name == "zh-CHS")
|
|
{
|
|
throw new CultureNotFoundException(
|
|
"name",
|
|
String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_CultureIetfNotSupported"), name)
|
|
);
|
|
}
|
|
|
|
CultureInfo ci = GetCultureInfo(name);
|
|
|
|
// Disallow alt sorts and es-es_TS
|
|
if (ci.LCID > 0xffff || ci.LCID == 0x040a)
|
|
{
|
|
throw new CultureNotFoundException(
|
|
"name",
|
|
String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_CultureIetfNotSupported"), name)
|
|
);
|
|
}
|
|
|
|
return ci;
|
|
}
|
|
#endif
|
|
private static volatile bool s_isTaiwanSku;
|
|
private static volatile bool s_haveIsTaiwanSku;
|
|
internal static bool IsTaiwanSku
|
|
{
|
|
get
|
|
{
|
|
if (!s_haveIsTaiwanSku)
|
|
{
|
|
s_isTaiwanSku = (GetSystemDefaultUILanguage() == "zh-TW");
|
|
s_haveIsTaiwanSku = true;
|
|
}
|
|
return (bool)s_isTaiwanSku;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Helper Methods.
|
|
//
|
|
|
|
// Get Locale Info Ex calls. So we don't have to muck with the different int/string return types we declared two of these:
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal static extern String nativeGetLocaleInfoEx(String localeName, uint field);
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal static extern int nativeGetLocaleInfoExInt(String localeName, uint field);
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal static extern bool nativeSetThreadLocale(String localeName);
|
|
|
|
[System.Security.SecurityCritical]
|
|
private static String GetDefaultLocaleName(int localeType)
|
|
{
|
|
Contract.Assert(localeType == LOCALE_USER_DEFAULT || localeType == LOCALE_SYSTEM_DEFAULT, "[CultureInfo.GetDefaultLocaleName] localeType must be LOCALE_USER_DEFAULT or LOCALE_SYSTEM_DEFAULT");
|
|
|
|
string localeName = null;
|
|
if(InternalGetDefaultLocaleName(localeType, JitHelpers.GetStringHandleOnStack(ref localeName)))
|
|
{
|
|
return localeName;
|
|
}
|
|
return string.Empty;
|
|
}
|
|
|
|
// Get the default locale name
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
private static extern bool InternalGetDefaultLocaleName(int localetype, StringHandleOnStack localeString);
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
private static String GetUserDefaultUILanguage()
|
|
{
|
|
string userDefaultUiLanguage = null;
|
|
if(InternalGetUserDefaultUILanguage(JitHelpers.GetStringHandleOnStack(ref userDefaultUiLanguage)))
|
|
{
|
|
return userDefaultUiLanguage;
|
|
}
|
|
return String.Empty;
|
|
}
|
|
|
|
// Get the user's default UI language, return locale name
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
private static extern bool InternalGetUserDefaultUILanguage(StringHandleOnStack userDefaultUiLanguage);
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
private static String GetSystemDefaultUILanguage()
|
|
{
|
|
string systemDefaultUiLanguage = null;
|
|
if(InternalGetSystemDefaultUILanguage(JitHelpers.GetStringHandleOnStack(ref systemDefaultUiLanguage)))
|
|
{
|
|
return systemDefaultUiLanguage;
|
|
}
|
|
return String.Empty;
|
|
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
private static extern bool InternalGetSystemDefaultUILanguage(StringHandleOnStack systemDefaultUiLanguage);
|
|
|
|
// Added but disabled from desktop in .NET 4.0, stayed disabled in .NET 4.5
|
|
#if FEATURE_CORECLR
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal static extern String[] nativeGetResourceFallbackArray();
|
|
#endif
|
|
}
|
|
}
|
|
|