< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 385
Coverable lines: 385
Total lines: 1218
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 247
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4////////////////////////////////////////////////////////////////////////////
 5//
 6//
 7//
 8//  Purpose:  This class represents the software preferences of a particular
 9//            culture or community.  It includes information such as the
 10//            language, writing system, and a calendar used by the culture
 11//            as well as methods for common operations such as printing
 12//            dates and sorting strings.
 13//
 14//
 15//
 16//  !!!! NOTE WHEN CHANGING THIS CLASS !!!!
 17//
 18//  If adding or removing members to this class, please update CultureInfoBaseObject
 19//  in ndp/clr/src/vm/object.h. Note, the "actual" layout of the class may be
 20//  different than the order in which members are declared. For instance, all
 21//  reference types will come first in the class before value types (like ints, bools, etc)
 22//  regardless of the order in which they are declared. The best way to see the
 23//  actual order of the class is to do a !dumpobj on an instance of the managed
 24//  object inside of the debugger.
 25//
 26////////////////////////////////////////////////////////////////////////////
 27
 28using System.Collections.Generic;
 29using System.Diagnostics;
 30using System.Diagnostics.CodeAnalysis;
 31using System.Threading;
 32
 33namespace System.Globalization
 34{
 35    /// <summary>
 36    /// This class represents the software preferences of a particular culture
 37    /// or community. It includes information such as the language, writing
 38    /// system and a calendar used by the culture as well as methods for
 39    /// common operations such as printing dates and sorting strings.
 40    /// </summary>
 41    /// <remarks>
 42    /// !!!! NOTE WHEN CHANGING THIS CLASS !!!!
 43    /// If adding or removing members to this class, please update
 44    /// CultureInfoBaseObject in ndp/clr/src/vm/object.h. Note, the "actual"
 45    /// layout of the class may be different than the order in which members
 46    /// are declared. For instance, all reference types will come first in the
 47    /// class before value types (like ints, bools, etc) regardless of the
 48    /// order in which they are declared. The best way to see the actual
 49    /// order of the class is to do a !dumpobj on an instance of the managed
 50    /// object inside of the debugger.
 51    /// </remarks>
 52    public partial class CultureInfo : IFormatProvider, ICloneable
 53    {
 54        // We use an RFC4646 type string to construct CultureInfo.
 55        // This string is stored in _name and is authoritative.
 56        // We use the _cultureData to get the data for our object
 57
 58        private bool _isReadOnly;
 59        private CompareInfo? _compareInfo;
 60        private TextInfo? _textInfo;
 61        internal NumberFormatInfo? _numInfo;
 62        internal DateTimeFormatInfo? _dateTimeInfo;
 63        private Calendar? _calendar;
 64        //
 65        // The CultureData instance that we are going to read data from.
 66        // For supported culture, this will be the CultureData instance that read data from mscorlib assembly.
 67        // For customized culture, this will be the CultureData instance that read data from user customized culture bin
 68        //
 69        internal CultureData _cultureData;
 70
 71        internal bool _isInherited;
 72
 73        private CultureInfo? _consoleFallbackCulture;
 74
 75        // Names are confusing.  Here are 3 names we have:
 76        //
 77        //  new CultureInfo()   _name          _nonSortName    _sortName
 78        //      en-US           en-US           en-US           en-US
 79        //      de-de_phoneb    de-DE_phoneb    de-DE           de-DE_phoneb
 80        //      fj-fj (custom)  fj-FJ           fj-FJ           en-US (if specified sort is en-US)
 81        //      en              en
 82        //
 83        // Note that in Silverlight we ask the OS for the text and sort behavior, so the
 84        // textinfo and compareinfo names are the same as the name
 85
 86        // This has a de-DE, de-DE_phoneb or fj-FJ style name
 87        internal string _name;
 88
 89        // This will hold the non sorting name to be returned from CultureInfo.Name property.
 90        // This has a de-DE style name even for de-DE_phoneb type cultures
 91        private string? _nonSortName;
 92
 93        // This will hold the sorting name to be returned from CultureInfo.SortName property.
 94        // This might be completely unrelated to the culture name if a custom culture.  Ie en-US for fj-FJ.
 95        // Otherwise its the sort name, ie: de-DE or de-DE_phoneb
 96        private string? _sortName;
 97
 98        // Get the current user default culture. This one is almost always used, so we create it by default.
 99        private static CultureInfo? s_userDefaultCulture;
 100
 101        // The culture used in the user interface. This is mostly used to load correct localized resources.
 102        private static CultureInfo? s_userDefaultUICulture;
 103
 104        // The Invariant culture;
 0105        private static readonly CultureInfo s_InvariantCultureInfo = new CultureInfo(CultureData.Invariant, isReadOnly: 
 106
 107        // These are defaults that we use if a thread has not opted into having an explicit culture
 108        private static volatile CultureInfo? s_DefaultThreadCurrentUICulture;
 109        private static volatile CultureInfo? s_DefaultThreadCurrentCulture;
 110
 111        [ThreadStatic]
 112        private static CultureInfo? s_currentThreadCulture;
 113        [ThreadStatic]
 114        private static CultureInfo? s_currentThreadUICulture;
 115
 116        private static AsyncLocal<CultureInfo>? s_asyncLocalCurrentCulture;
 117        private static AsyncLocal<CultureInfo>? s_asyncLocalCurrentUICulture;
 118
 119        private static void AsyncLocalSetCurrentCulture(AsyncLocalValueChangedArgs<CultureInfo> args)
 120        {
 0121            s_currentThreadCulture = args.CurrentValue;
 0122        }
 123
 124        private static void AsyncLocalSetCurrentUICulture(AsyncLocalValueChangedArgs<CultureInfo> args)
 125        {
 0126            s_currentThreadUICulture = args.CurrentValue;
 0127        }
 128
 129        private static Dictionary<string, CultureInfo>? s_cachedCulturesByName;
 130        private static Dictionary<int, CultureInfo>? s_cachedCulturesByLcid;
 131
 132        // The parent culture.
 133        private CultureInfo? _parent;
 134
 135        // LOCALE constants of interest to us internally and privately for LCID functions
 136        // (ie: avoid using these and use names if possible)
 137        internal const int LOCALE_NEUTRAL        = 0x0000;
 138        private  const int LOCALE_USER_DEFAULT   = 0x0400;
 139        private  const int LOCALE_SYSTEM_DEFAULT = 0x0800;
 140        internal const int LOCALE_CUSTOM_UNSPECIFIED = 0x1000;
 141        internal const int LOCALE_CUSTOM_DEFAULT  = 0x0c00;
 142        internal const int LOCALE_INVARIANT       = 0x007F;
 143
 144        private static CultureInfo InitializeUserDefaultCulture()
 145        {
 0146            Interlocked.CompareExchange(ref s_userDefaultCulture, GetUserDefaultCulture(), null);
 0147            return s_userDefaultCulture;
 148        }
 149
 150        private static CultureInfo InitializeUserDefaultUICulture()
 151        {
 0152            Interlocked.CompareExchange(ref s_userDefaultUICulture, GetUserDefaultUICulture(), null);
 0153            return s_userDefaultUICulture;
 154        }
 155
 0156        private static string GetCultureNotSupportedExceptionMessage() => GlobalizationMode.Invariant ? SR.Argument_Cult
 157
 0158        public CultureInfo(string name) : this(name, true)
 159        {
 0160        }
 161
 0162        public CultureInfo(string name, bool useUserOverride)
 163        {
 0164            ArgumentNullException.ThrowIfNull(name);
 165
 166            // Get our data providing record
 0167            _cultureData = CultureData.GetCultureData(name, useUserOverride) ??
 0168                throw new CultureNotFoundException(nameof(name), name, GetCultureNotSupportedExceptionMessage());
 0169            _name = _cultureData.CultureName;
 0170            _isInherited = GetType() != typeof(CultureInfo);
 0171        }
 172
 0173        private CultureInfo(CultureData cultureData, bool isReadOnly = false)
 174        {
 0175            Debug.Assert(cultureData != null);
 0176            _cultureData = cultureData;
 0177            _name = cultureData.CultureName;
 0178            _isReadOnly = isReadOnly;
 0179        }
 180
 181        private static CultureInfo? CreateCultureInfoNoThrow(string name, bool useUserOverride)
 182        {
 0183            Debug.Assert(name != null);
 0184            CultureData? cultureData = CultureData.GetCultureData(name, useUserOverride);
 0185            if (cultureData == null)
 186            {
 0187                return null;
 188            }
 189
 0190            return new CultureInfo(cultureData);
 191        }
 192
 0193        public CultureInfo(int culture) : this(culture, true)
 194        {
 0195        }
 196
 0197        public CultureInfo(int culture, bool useUserOverride)
 198        {
 199            // We don't check for other invalid LCIDS here...
 0200            ArgumentOutOfRangeException.ThrowIfNegative(culture);
 201
 0202            if (culture is LOCALE_CUSTOM_DEFAULT or LOCALE_SYSTEM_DEFAULT or LOCALE_NEUTRAL or LOCALE_USER_DEFAULT or LO
 203            {
 204                // Can't support unknown custom cultures and we do not support neutral or
 0205                throw new CultureNotFoundException(nameof(culture), culture, SR.Argument_CultureNotSupported);
 206            }
 207
 208            // Now see if this LCID is supported in the system default CultureData table.
 0209            _cultureData = CultureData.GetCultureData(culture, useUserOverride);
 210
 0211            _isInherited = GetType() != typeof(CultureInfo);
 0212            _name = _cultureData.CultureName;
 0213        }
 214
 215        /// <summary>
 216        /// Constructor called by SQL Server's special munged culture - creates a culture with
 217        /// a TextInfo and CompareInfo that come from a supplied alternate source. This object
 218        /// is ALWAYS read-only.
 219        /// Note that we really cannot use an LCID version of this override as the cached
 220        /// name we create for it has to include both names, and the logic for this is in
 221        /// the GetCultureInfo override *only*.
 222        /// </summary>
 0223        internal CultureInfo(string cultureName, string textAndCompareCultureName)
 224        {
 0225            ArgumentNullException.ThrowIfNull(textAndCompareCultureName);
 226
 0227            CultureData? cultureData = CultureData.GetCultureData(cultureName, false) ??
 0228                throw new CultureNotFoundException(nameof(cultureName), cultureName, GetCultureNotSupportedExceptionMess
 229
 0230            _cultureData = cultureData;
 231
 0232            _name = _cultureData.CultureName;
 233
 0234            CultureInfo altCulture = GetCultureInfo(textAndCompareCultureName);
 0235            _compareInfo = altCulture.CompareInfo;
 0236            _textInfo = altCulture.TextInfo;
 0237        }
 238
 239        /// <summary>
 240        /// We do this to try to return the system UI language and the default user languages
 241        /// This method will fallback if this fails (like Invariant)
 242        /// </summary>
 243        private static CultureInfo GetCultureByName(string name)
 244        {
 245            try
 246            {
 0247                return new CultureInfo(name)
 0248                {
 0249                    _isReadOnly = true
 0250                };
 251            }
 0252            catch (ArgumentException)
 253            {
 0254                return InvariantCulture;
 255            }
 0256        }
 257
 258        /// <summary>
 259        /// Return a specific culture. A tad irrelevant now since we always
 260        /// return valid data for neutral locales.
 261        ///
 262        /// Note that there's interesting behavior that tries to find a
 263        /// smaller name, ala RFC4647, if we can't find a bigger name.
 264        /// That doesn't help with things like "zh" though, so the approach
 265        /// is of questionable value
 266        /// </summary>
 267        public static CultureInfo CreateSpecificCulture(string name)
 268        {
 269            CultureInfo? culture;
 270
 271            try
 272            {
 0273                culture = new CultureInfo(name);
 0274            }
 0275            catch (ArgumentException)
 276            {
 277                // When CultureInfo throws this exception, it may be because someone passed the form
 278                // like "az-az" because it came out of an http accept lang. We should try a little
 279                // parsing to perhaps fall back to "az" here and use *it* to create the neutral.
 0280                int idx = name.IndexOf('-');
 0281                if (idx >= 0)
 282                {
 283                    try
 284                    {
 0285                        culture = new CultureInfo(name.Substring(0, idx));
 0286                    }
 0287                    catch (ArgumentException)
 288                    {
 289                        // throw the original exception so the name in the string will be right
 0290                        throw;
 291                    }
 292                }
 293                else
 294                {
 295                    // nothing to save here; throw the original exception
 0296                    throw;
 297                }
 0298            }
 299
 300            // In the most common case, they've given us a specific culture, so we'll just return that.
 0301            if (!culture.IsNeutralCulture)
 302            {
 0303                return culture;
 304            }
 305
 0306            return new CultureInfo(culture._cultureData.SpecificCultureName);
 307        }
 308
 309        internal static bool VerifyCultureName(string cultureName, bool throwException)
 310        {
 311            // This function is used by ResourceManager.GetResourceFileName().
 312            // ResourceManager searches for resource using CultureInfo.Name,
 313            // so we should check against CultureInfo.Name.
 0314            for (int i = 0; i < cultureName.Length; i++)
 315            {
 0316                char c = cultureName[i];
 317                // TODO: Names can only be RFC4646 names (ie: a-zA-Z0-9) while this allows any unicode letter/digit
 0318                if (char.IsLetterOrDigit(c) || c == '-' || c == '_')
 319                {
 320                    continue;
 321                }
 0322                if (throwException)
 323                {
 0324                    throw new ArgumentException(SR.Format(SR.Argument_InvalidResourceCultureName, cultureName));
 325                }
 0326                return false;
 327            }
 0328            return true;
 329        }
 330
 331        internal static bool VerifyCultureName(CultureInfo culture, bool throwException)
 332        {
 333            // If we have an instance of one of our CultureInfos, the user can't have changed the
 334            // name and we know that all names are valid in files.
 0335            if (!culture._isInherited)
 336            {
 0337                return true;
 338            }
 339
 0340            return VerifyCultureName(culture.Name, throwException);
 341        }
 342
 343        /// <summary>
 344        /// This instance provides methods based on the current user settings.
 345        /// These settings are volatile and may change over the lifetime of the
 346        /// thread.
 347        /// </summary>
 348        /// <remarks>
 349        /// We use the following order to return CurrentCulture and CurrentUICulture
 350        ///      o   Use WinRT to return the current user profile language
 351        ///      o   use current thread culture if the user already set one using CurrentCulture/CurrentUICulture
 352        ///      o   use thread culture if the user already set one using DefaultThreadCurrentCulture
 353        ///          or DefaultThreadCurrentUICulture
 354        ///      o   Use NLS default user culture
 355        ///      o   Use NLS default system culture
 356        ///      o   Use Invariant culture
 357        /// </remarks>
 358        public static CultureInfo CurrentCulture
 359        {
 360            get
 361            {
 0362                return s_currentThreadCulture ??
 0363                    s_DefaultThreadCurrentCulture ??
 0364                    s_userDefaultCulture ??
 0365                    InitializeUserDefaultCulture();
 366            }
 367            set
 368            {
 0369                ArgumentNullException.ThrowIfNull(value);
 370
 0371                if (s_asyncLocalCurrentCulture == null)
 372                {
 0373                    Interlocked.CompareExchange(ref s_asyncLocalCurrentCulture, new AsyncLocal<CultureInfo>(AsyncLocalSe
 374                }
 0375                s_asyncLocalCurrentCulture.Value = value;
 0376            }
 377        }
 378
 379        public static CultureInfo CurrentUICulture
 380        {
 381            get
 382            {
 0383                return s_currentThreadUICulture ??
 0384                    s_DefaultThreadCurrentUICulture ??
 0385                    UserDefaultUICulture;
 386            }
 387            set
 388            {
 0389                ArgumentNullException.ThrowIfNull(value);
 390
 0391                VerifyCultureName(value, true);
 392
 0393                if (s_asyncLocalCurrentUICulture == null)
 394                {
 0395                    Interlocked.CompareExchange(ref s_asyncLocalCurrentUICulture, new AsyncLocal<CultureInfo>(AsyncLocal
 396                }
 397
 398                // this one will set s_currentThreadUICulture too
 0399                s_asyncLocalCurrentUICulture.Value = value;
 0400            }
 401        }
 402
 0403        internal static CultureInfo UserDefaultUICulture => s_userDefaultUICulture ?? InitializeUserDefaultUICulture();
 404
 0405        public static CultureInfo InstalledUICulture => s_userDefaultCulture ?? InitializeUserDefaultCulture();
 406
 407        public static CultureInfo? DefaultThreadCurrentCulture
 408        {
 0409            get => s_DefaultThreadCurrentCulture;
 410            set =>
 411                // If you add pre-conditions to this method, check to see if you also need to
 412                // add them to Thread.CurrentCulture.set.
 0413                s_DefaultThreadCurrentCulture = value;
 414        }
 415
 416        public static CultureInfo? DefaultThreadCurrentUICulture
 417        {
 0418            get => s_DefaultThreadCurrentUICulture;
 419            set
 420            {
 421                // If they're trying to use a Culture with a name that we can't use in resource lookup,
 422                // don't even let them set it on the thread.
 423
 424                // If you add more pre-conditions to this method, check to see if you also need to
 425                // add them to Thread.CurrentUICulture.set.
 426
 0427                if (value != null)
 428                {
 0429                    VerifyCultureName(value, true);
 430                }
 431
 0432                s_DefaultThreadCurrentUICulture = value;
 0433            }
 434        }
 435
 436        /// <summary>
 437        /// This instance provides methods, for example for casing and sorting,
 438        /// that are independent of the system and current user settings.  It
 439        /// should be used only by processes such as some system services that
 440        /// require such invariant results (eg. file systems).  In general,
 441        /// the results are not linguistically correct and do not match any
 442        /// culture info.
 443        /// </summary>
 444        public static CultureInfo InvariantCulture
 445        {
 446            get
 447            {
 0448                Debug.Assert(s_InvariantCultureInfo != null, "[CultureInfo.InvariantCulture] s_InvariantCultureInfo is n
 0449                return s_InvariantCultureInfo;
 450            }
 451        }
 452
 453        /// <summary>
 454        /// Return the parent CultureInfo for the current instance.
 455        /// </summary>
 456        public virtual CultureInfo Parent
 457        {
 458            get
 459            {
 0460                if (_parent == null)
 461                {
 462                    CultureInfo culture;
 0463                    string parentName = _cultureData.ParentName;
 464
 0465                    if (parentName == "zh")
 466                    {
 0467                        if (_name.Length == 5 && _name[2] == '-')
 468                        {
 469                            // We need to keep the parent chain for the zh cultures as follows to preserve the resource 
 470                            //      zh-CN -> zh-Hans -> zh -> Invariant
 471                            //      zh-HK -> zh-Hant -> zh -> Invariant
 472                            //      zh-MO -> zh-Hant -> zh -> Invariant
 473                            //      zh-SG -> zh-Hans -> zh -> Invariant
 474                            //      zh-TW -> zh-Hant -> zh -> Invariant
 475
 0476                            if ((_name[3] == 'C' && _name[4] == 'N') || // zh-CN
 0477                                (_name[3] == 'S' && _name[4] == 'G'))   // zh-SG
 478                            {
 0479                                parentName = "zh-Hans";
 480                            }
 0481                            else if ((_name[3] == 'H' && _name[4] == 'K') ||   // zh-HK
 0482                                    (_name[3] == 'M' && _name[4] == 'O') ||    // zh-MO
 0483                                    (_name[3] == 'T' && _name[4] == 'W'))      // zh-TW
 484                            {
 0485                                parentName = "zh-Hant";
 486                            }
 487                        }
 0488                        else if (_name.Length > 8 && _name.AsSpan(2, 4) is "-Han" && _name[7] == '-') // cultures like z
 489                        {
 0490                            if (_name[6] == 't') // zh-Hant-*
 491                            {
 0492                                parentName = "zh-Hant";
 493                            }
 0494                            else if (_name[6] == 's') // zh-Hans-*
 495                            {
 0496                                parentName = "zh-Hans";
 497                            }
 498                        }
 499                    }
 500
 0501                    if (string.IsNullOrEmpty(parentName))
 502                    {
 0503                        culture = InvariantCulture;
 504                    }
 505                    else
 506                    {
 0507                        culture = CreateCultureInfoNoThrow(parentName, _cultureData.UseUserOverride) ??
 0508                            // For whatever reason our IPARENT or SPARENT wasn't correct, so use invariant
 0509                            // We can't allow ourselves to fail.  In case of custom cultures the parent of the
 0510                            // current custom culture isn't installed.
 0511                            InvariantCulture;
 512                    }
 513
 0514                    Interlocked.CompareExchange<CultureInfo?>(ref _parent, culture, null);
 515                }
 0516                return _parent!;
 517            }
 518        }
 519
 0520        public virtual int LCID => _cultureData.LCID;
 521
 0522        public virtual int KeyboardLayoutId => _cultureData.KeyboardLayoutId;
 523
 524        public static CultureInfo[] GetCultures(CultureTypes types)
 525        {
 526            // internally we treat UserCustomCultures as Supplementals but v2
 527            // treats as Supplementals and Replacements
 0528            if ((types & CultureTypes.UserCustomCulture) == CultureTypes.UserCustomCulture)
 529            {
 0530                types |= CultureTypes.ReplacementCultures;
 531            }
 0532            return CultureData.GetCultures(types);
 533        }
 534
 535        /// <summary>
 536        /// Returns the full name of the CultureInfo. The name is in format like
 537        /// "en-US" This version does NOT include sort information in the name.
 538        /// </summary>
 0539        public virtual string Name => _nonSortName ??= (_cultureData.Name ?? string.Empty);
 540
 541        /// <summary>
 542        /// This one has the sort information (ie: de-DE_phoneb)
 543        /// </summary>
 0544        internal string SortName => _sortName ??= _cultureData.SortName;
 545
 546        /// <summary>
 547        /// The culture name to use to interop with the underlying native globalization libraries like ICU or Windows NL
 548        /// For example, we can have the name de_DE@collation=phonebook when using ICU for the German culture de-DE with
 549        /// </summary>
 0550        internal string? InteropName => _cultureData.InteropName;
 551
 552        public string IetfLanguageTag =>
 553                // special case the compatibility cultures
 0554                Name switch
 0555                {
 0556                    "zh-CHT" => "zh-Hant",
 0557                    "zh-CHS" => "zh-Hans",
 0558                    _ => Name,
 0559                };
 560
 561        /// <summary>
 562        /// Returns the full name of the CultureInfo in the localized language.
 563        /// For example, if the localized language of the runtime is Spanish and the CultureInfo is
 564        /// US English, "Ingles (Estados Unidos)" will be returned.
 565        /// </summary>
 566        public virtual string DisplayName
 567        {
 568            get
 569            {
 0570                Debug.Assert(_name != null, "[CultureInfo.DisplayName] Always expect _name to be set");
 0571                return _cultureData.DisplayName;
 572            }
 573        }
 574
 575        /// <summary>
 576        /// Returns the full name of the CultureInfo in the native language.
 577        /// For example, if the CultureInfo is US English, "English
 578        /// (United States)" will be returned.
 579        /// </summary>
 0580        public virtual string NativeName => _cultureData.NativeName;
 581
 582        /// <summary>
 583        /// Returns the full name of the CultureInfo in English.
 584        /// For example, if the CultureInfo is US English, "English
 585        /// (United States)" will be returned.
 586        /// </summary>
 0587        public virtual string EnglishName => _cultureData.EnglishName;
 588
 589        /// <summary>
 590        /// ie: en
 591        /// </summary>
 0592        public virtual string TwoLetterISOLanguageName => _cultureData.TwoLetterISOLanguageName;
 593
 594        /// <summary>
 595        /// ie: eng
 596        /// </summary>
 0597        public virtual string ThreeLetterISOLanguageName => _cultureData.ThreeLetterISOLanguageName;
 598
 599        /// <summary>
 600        /// Returns the 3 letter windows language name for the current instance.  eg: "ENU"
 601        /// The ISO names are much preferred
 602        /// </summary>
 0603        public virtual string ThreeLetterWindowsLanguageName => _cultureData.ThreeLetterWindowsLanguageName;
 604
 605        /// <summary>
 606        /// Gets the CompareInfo for this culture.
 607        /// </summary>
 0608        public virtual CompareInfo CompareInfo => _compareInfo ??=
 0609            // Since CompareInfo's don't have any overrideable properties, get the CompareInfo from
 0610            // the Non-Overridden CultureInfo so that we only create one CompareInfo per culture
 0611            (UseUserOverride ? GetCultureInfo(_name).CompareInfo : new CompareInfo(this));
 612
 613        /// <summary>
 614        /// Gets the TextInfo for this culture.
 615        /// </summary>
 616        public virtual TextInfo TextInfo
 617        {
 618            get
 619            {
 0620                if (_textInfo == null)
 621                {
 622                    // Make a new textInfo
 0623                    TextInfo tempTextInfo = new TextInfo(_cultureData);
 0624                    tempTextInfo.SetReadOnlyState(_isReadOnly);
 0625                    _textInfo = tempTextInfo;
 626                }
 0627                return _textInfo;
 628            }
 629        }
 630
 631        public override bool Equals([NotNullWhen(true)] object? value)
 632        {
 0633            if (ReferenceEquals(this, value))
 634            {
 0635                return true;
 636            }
 637
 0638            if (value is CultureInfo that)
 639            {
 640                // using CompareInfo to verify the data passed through the constructor
 641                // CultureInfo(String cultureName, String textAndCompareCultureName)
 0642                return Name.Equals(that.Name) && CompareInfo.Equals(that.CompareInfo);
 643            }
 644
 0645            return false;
 646        }
 647
 648        public override int GetHashCode()
 649        {
 0650            return Name.GetHashCode() + CompareInfo.GetHashCode();
 651        }
 652
 653        /// <summary>
 654        /// Implements object.ToString(). Returns the name of the CultureInfo,
 655        /// eg. "de-DE_phoneb", "en-US", or "fj-FJ".
 656        /// </summary>
 0657        public override string ToString() => _name;
 658
 659        public virtual object? GetFormat(Type? formatType)
 660        {
 0661            if (formatType == typeof(NumberFormatInfo))
 662            {
 0663                return NumberFormat;
 664            }
 0665            if (formatType == typeof(DateTimeFormatInfo))
 666            {
 0667                return DateTimeFormat;
 668            }
 669
 0670            return null;
 671        }
 672
 0673        public virtual bool IsNeutralCulture => _cultureData.IsNeutralCulture;
 674
 675        public CultureTypes CultureTypes
 676        {
 677            get
 678            {
 0679                CultureTypes types = _cultureData.IsNeutralCulture ?
 0680                    CultureTypes.NeutralCultures :
 0681                    CultureTypes.SpecificCultures;
 682
 683                if (CultureData.IsWin32Installed)
 684                {
 0685                    types |= CultureTypes.InstalledWin32Cultures;
 686                }
 687
 0688                if (_cultureData.IsSupplementalCustomCulture)
 689                {
 0690                    types |= CultureTypes.UserCustomCulture;
 691                }
 692
 0693                if (_cultureData.IsReplacementCulture)
 694                {
 0695                    types |= CultureTypes.ReplacementCultures;
 696                }
 697
 0698                return types;
 699            }
 700        }
 701
 702        public virtual NumberFormatInfo NumberFormat
 703        {
 704            get
 705            {
 0706                if (_numInfo == null)
 707                {
 0708                    NumberFormatInfo temp = new NumberFormatInfo(_cultureData);
 0709                    temp._isReadOnly = _isReadOnly;
 0710                    Interlocked.CompareExchange(ref _numInfo, temp, null);
 711                }
 0712                return _numInfo!;
 713            }
 714            set
 715            {
 0716                ArgumentNullException.ThrowIfNull(value);
 717
 0718                VerifyWritable();
 0719                _numInfo = value;
 0720            }
 721        }
 722
 723        /// <summary>
 724        /// Create a DateTimeFormatInfo, and fill in the properties according to
 725        /// the CultureID.
 726        /// </summary>
 727        public virtual DateTimeFormatInfo DateTimeFormat
 728        {
 729            get
 730            {
 0731                if (_dateTimeInfo == null)
 732                {
 733                    // Change the calendar of DTFI to the specified calendar of this CultureInfo.
 0734                    DateTimeFormatInfo temp = new DateTimeFormatInfo(_cultureData, this.Calendar);
 0735                    temp._isReadOnly = _isReadOnly;
 0736                    Interlocked.CompareExchange(ref _dateTimeInfo, temp, null);
 737                }
 0738                return _dateTimeInfo!;
 739            }
 740
 741            set
 742            {
 0743                ArgumentNullException.ThrowIfNull(value);
 744
 0745                VerifyWritable();
 0746                _dateTimeInfo = value;
 0747            }
 748        }
 749
 750        public void ClearCachedData()
 751        {
 752            // reset the default culture values
 753#if TARGET_WINDOWS
 0754            UserDefaultLocaleName = GetUserDefaultLocaleName();
 755#endif
 0756            s_userDefaultCulture = GetUserDefaultCulture();
 0757            s_userDefaultUICulture = GetUserDefaultUICulture();
 758
 0759            RegionInfo.s_currentRegionInfo = null;
 760#pragma warning disable 0618 // disable the obsolete warning
 0761            TimeZone.ResetTimeZone();
 762#pragma warning restore 0618
 0763            TimeZoneInfo.ClearCachedData();
 0764            s_cachedCulturesByLcid = null;
 0765            s_cachedCulturesByName = null;
 766
 0767            CultureData.ClearCachedData();
 0768        }
 769
 770        /// <summary>
 771        /// Map a Win32 CALID to an instance of supported calendar.
 772        /// </summary>
 773        /// <remarks>
 774        /// Shouldn't throw exception since the calType value is from our data
 775        /// table or from Win32 registry.
 776        /// If we are in trouble (like getting a weird value from Win32
 777        /// registry), just return the GregorianCalendar.
 778        /// </remarks>
 779        internal static Calendar GetCalendarInstance(CalendarId calType)
 780        {
 0781            Debug.Assert(!GlobalizationMode.Invariant);
 782
 0783            if (calType == CalendarId.GREGORIAN)
 784            {
 0785                return new GregorianCalendar();
 786            }
 787
 0788            return GetCalendarInstanceRare(calType);
 789        }
 790
 791        /// <summary>
 792        /// This function exists as a shortcut to prevent us from loading all of the non-gregorian
 793        /// calendars unless they're required.
 794        /// </summary>
 795        internal static Calendar GetCalendarInstanceRare(CalendarId calType)
 796        {
 0797            Debug.Assert(calType != CalendarId.GREGORIAN, "calType!=CalendarId.GREGORIAN");
 798
 0799            return calType switch
 0800            {
 0801                CalendarId.GREGORIAN_US or CalendarId.GREGORIAN_ME_FRENCH or CalendarId.GREGORIAN_ARABIC or CalendarId.G
 0802                CalendarId.TAIWAN => new TaiwanCalendar(),
 0803                CalendarId.JAPAN => new JapaneseCalendar(),
 0804                CalendarId.KOREA => new KoreanCalendar(),
 0805                CalendarId.THAI => new ThaiBuddhistCalendar(),
 0806                CalendarId.HIJRI => new HijriCalendar(),
 0807                CalendarId.HEBREW => new HebrewCalendar(),
 0808                CalendarId.UMALQURA => new UmAlQuraCalendar(),
 0809                CalendarId.PERSIAN => new PersianCalendar(),
 0810                _ => new GregorianCalendar(),
 0811            };
 812        }
 813
 814        /// <summary>
 815        /// Return/set the default calendar used by this culture.
 816        /// This value can be overridden by regional option if this is a current culture.
 817        /// </summary>
 818        public virtual Calendar Calendar
 819        {
 820            get
 821            {
 0822                if (_calendar == null)
 823                {
 824                    // Get the default calendar for this culture.  Note that the value can be
 825                    // from registry if this is a user default culture.
 0826                    Calendar newObj = _cultureData.DefaultCalendar;
 827
 0828                    Interlocked.MemoryBarrier();
 0829                    newObj.SetReadOnlyState(_isReadOnly);
 0830                    _calendar = newObj;
 831                }
 0832                return _calendar;
 833            }
 834        }
 835
 836        /// <summary>
 837        /// Return an array of the optional calendar for this culture.
 838        /// </summary>
 839        public virtual Calendar[] OptionalCalendars
 840        {
 841            get
 842            {
 843                // This property always returns a new copy of the calendar array.
 0844                if (GlobalizationMode.Invariant)
 845                {
 0846                    return new[] { new GregorianCalendar() };
 847                }
 848
 0849                CalendarId[] calID = _cultureData.CalendarIds;
 0850                Calendar[] cals = new Calendar[calID.Length];
 0851                for (int i = 0; i < cals.Length; i++)
 852                {
 0853                    cals[i] = GetCalendarInstance(calID[i]);
 854                }
 0855                return cals;
 856            }
 857        }
 858
 0859        public bool UseUserOverride => _cultureData.UseUserOverride;
 860
 861        public CultureInfo GetConsoleFallbackUICulture()
 862        {
 0863            CultureInfo? temp = _consoleFallbackCulture;
 0864            if (temp == null)
 865            {
 0866                temp = CreateSpecificCulture(_cultureData.SCONSOLEFALLBACKNAME);
 0867                temp._isReadOnly = true;
 0868                _consoleFallbackCulture = temp;
 869            }
 0870            return temp;
 871        }
 872
 873        public virtual object Clone()
 874        {
 0875            CultureInfo ci = (CultureInfo)MemberwiseClone();
 0876            ci._isReadOnly = false;
 877
 878            // If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo
 879            // they've already been allocated.  If this is a derived type, we'll take a more generic codepath.
 0880            if (!_isInherited)
 881            {
 0882                if (_dateTimeInfo != null)
 883                {
 0884                    ci._dateTimeInfo = (DateTimeFormatInfo)_dateTimeInfo.Clone();
 885                }
 0886                if (_numInfo != null)
 887                {
 0888                    ci._numInfo = (NumberFormatInfo)_numInfo.Clone();
 889                }
 890            }
 891            else
 892            {
 0893                ci.DateTimeFormat = (DateTimeFormatInfo)this.DateTimeFormat.Clone();
 0894                ci.NumberFormat = (NumberFormatInfo)this.NumberFormat.Clone();
 895            }
 896
 0897            if (_textInfo != null)
 898            {
 0899                ci._textInfo = (TextInfo)_textInfo.Clone();
 900            }
 901
 0902            if (_dateTimeInfo != null && _dateTimeInfo.Calendar == _calendar)
 903            {
 904                // Usually when we access CultureInfo.DateTimeFormat first time, we create the DateTimeFormatInfo object
 905                // using CultureInfo.Calendar. i.e. CultureInfo.DateTimeInfo.Calendar == CultureInfo.calendar.
 906                // When cloning CultureInfo, if we know it's still the case that CultureInfo.DateTimeInfo.Calendar == Cu
 907                // then we can keep the same behavior for the cloned object and no need to create another calendar objec
 0908                ci._calendar = ci.DateTimeFormat.Calendar;
 909            }
 0910            else if (_calendar != null)
 911            {
 0912                ci._calendar = (Calendar)_calendar.Clone();
 913            }
 914
 0915            return ci;
 916        }
 917
 918        public static CultureInfo ReadOnly(CultureInfo ci)
 919        {
 0920            ArgumentNullException.ThrowIfNull(ci);
 921
 0922            if (ci.IsReadOnly)
 923            {
 0924                return ci;
 925            }
 0926            CultureInfo newInfo = (CultureInfo)(ci.MemberwiseClone());
 927
 0928            if (!ci.IsNeutralCulture)
 929            {
 930                // If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormat
 931                // they've already been allocated.  If this is a derived type, we'll take a more generic codepath.
 0932                if (!ci._isInherited)
 933                {
 0934                    if (ci._dateTimeInfo != null)
 935                    {
 0936                        newInfo._dateTimeInfo = DateTimeFormatInfo.ReadOnly(ci._dateTimeInfo);
 937                    }
 0938                    if (ci._numInfo != null)
 939                    {
 0940                        newInfo._numInfo = NumberFormatInfo.ReadOnly(ci._numInfo);
 941                    }
 942                }
 943                else
 944                {
 0945                    newInfo.DateTimeFormat = DateTimeFormatInfo.ReadOnly(ci.DateTimeFormat);
 0946                    newInfo.NumberFormat = NumberFormatInfo.ReadOnly(ci.NumberFormat);
 947                }
 948            }
 949
 0950            if (ci._textInfo != null)
 951            {
 0952                newInfo._textInfo = TextInfo.ReadOnly(ci._textInfo);
 953            }
 954
 0955            if (ci._calendar != null)
 956            {
 0957                newInfo._calendar = Calendar.ReadOnly(ci._calendar);
 958            }
 959
 960            // Don't set the read-only flag too early.
 961            // We should set the read-only flag here.  Otherwise, info.DateTimeFormat will not be able to set.
 0962            newInfo._isReadOnly = true;
 963
 0964            return newInfo;
 965        }
 966
 0967        public bool IsReadOnly => _isReadOnly;
 968
 969        private void VerifyWritable()
 970        {
 0971            if (_isReadOnly)
 972            {
 0973                throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
 974            }
 0975        }
 976
 977        /// <summary>
 978        /// For resource lookup, we consider a culture the invariant culture by name equality.
 979        /// We perform this check frequently during resource lookup, so adding a property for
 980        /// improved readability.
 981        /// </summary>
 0982        internal bool HasInvariantCultureName => Name == InvariantCulture.Name;
 983
 984        /// <summary>
 985        /// Gets a cached copy of the specified culture from an internal
 986        /// hashtable (or creates it if not found). (LCID version)
 987        /// </summary>
 988        public static CultureInfo GetCultureInfo(int culture)
 989        {
 0990            ArgumentOutOfRangeException.ThrowIfNegativeOrZero(culture);
 991
 0992            Dictionary<int, CultureInfo> lcidTable = CachedCulturesByLcid;
 993            CultureInfo? result;
 994
 0995            lock (lcidTable)
 996            {
 0997                if (lcidTable.TryGetValue(culture, out result))
 998                {
 0999                    return result;
 1000                }
 01001            }
 1002
 1003            try
 1004            {
 01005                result = new CultureInfo(culture, useUserOverride: false) { _isReadOnly = true };
 01006            }
 01007            catch (ArgumentException)
 1008            {
 01009                throw new CultureNotFoundException(nameof(culture), culture, GetCultureNotSupportedExceptionMessage());
 1010            }
 1011
 01012            lock (lcidTable)
 1013            {
 01014                lcidTable[culture] = result;
 01015            }
 1016
 01017            return result;
 01018        }
 1019
 1020        /// <summary>
 1021        /// Gets a cached copy of the specified culture from an internal
 1022        /// hashtable (or creates it if not found). (Named version)
 1023        /// </summary>
 1024        public static CultureInfo GetCultureInfo(string name)
 1025        {
 01026            ArgumentNullException.ThrowIfNull(name);
 1027
 01028            name = CultureData.AnsiToLower(name);
 01029            Dictionary<string, CultureInfo> nameTable = CachedCulturesByName;
 1030            CultureInfo? result;
 1031
 01032            lock (nameTable)
 1033            {
 01034                if (nameTable.TryGetValue(name, out result))
 1035                {
 01036                    return result;
 1037                }
 01038            }
 1039
 01040            result = CreateCultureInfoNoThrow(name, useUserOverride: false) ??
 01041                throw new CultureNotFoundException(nameof(name), name, GetCultureNotSupportedExceptionMessage());
 01042            result._isReadOnly = true;
 1043
 1044            // Remember our name as constructed.  Do NOT use alternate sort name versions because
 1045            // we have internal state representing the sort (so someone would get the wrong cached version).
 01046            name = CultureData.AnsiToLower(result._name);
 1047
 01048            lock (nameTable)
 1049            {
 1050                // add only if it wasn't already added
 01051                nameTable.TryAdd(name, result);
 01052            }
 1053
 01054            return result;
 01055        }
 1056
 1057        /// <summary>
 1058        /// Gets a cached copy of the specified culture from an internal
 1059        /// hashtable (or creates it if not found).
 1060        /// </summary>
 1061        public static CultureInfo GetCultureInfo(string name, string altName)
 1062        {
 01063            ArgumentNullException.ThrowIfNull(name);
 01064            ArgumentNullException.ThrowIfNull(altName);
 1065
 01066            name = CultureData.AnsiToLower(name);
 01067            altName = CultureData.AnsiToLower(altName);
 01068            string nameAndAltName = name + "\xfffd" + altName;
 01069            Dictionary<string, CultureInfo> nameTable = CachedCulturesByName;
 1070            CultureInfo? result;
 1071
 01072            lock (nameTable)
 1073            {
 01074                if (nameTable.TryGetValue(nameAndAltName, out result))
 1075                {
 01076                    return result;
 1077                }
 01078            }
 1079
 1080            try
 1081            {
 01082                result = new CultureInfo(name, altName) { _isReadOnly = true };
 01083                result.TextInfo.SetReadOnlyState(readOnly: true); // TextInfo object is already created; we need to set 
 01084            }
 01085            catch (ArgumentException)
 1086            {
 1087#pragma warning disable CA2208 // Instantiate argument exceptions correctly, combination of arguments used
 01088                throw new CultureNotFoundException("name/altName", SR.Format(SR.Argument_OneOfCulturesNotSupported, name
 1089#pragma warning restore CA2208
 1090            }
 1091
 01092            lock (nameTable)
 1093            {
 01094                nameTable[nameAndAltName] = result;
 01095            }
 1096
 01097            return result;
 01098        }
 1099
 1100        public static CultureInfo GetCultureInfo(string name, bool predefinedOnly)
 1101        {
 01102            ArgumentNullException.ThrowIfNull(name);
 1103
 01104            if (predefinedOnly && !GlobalizationMode.Invariant)
 1105            {
 01106                if (GlobalizationMode.UseNls ? !CultureData.NlsIsEnsurePredefinedLocaleName(name) : !CultureData.IcuIsEn
 1107                {
 01108                    throw new CultureNotFoundException(nameof(name), name, SR.Format(SR.Argument_InvalidPredefinedCultur
 1109                }
 1110            }
 1111
 01112            return GetCultureInfo(name);
 1113        }
 1114
 1115        private static Dictionary<string, CultureInfo> CachedCulturesByName
 1116        {
 1117            get
 1118            {
 01119                Dictionary<string, CultureInfo>? cache = s_cachedCulturesByName;
 01120                if (cache is null)
 1121                {
 01122                    cache = new Dictionary<string, CultureInfo>();
 01123                    cache = Interlocked.CompareExchange(ref s_cachedCulturesByName, cache, null) ?? cache;
 1124                }
 1125
 01126                return cache;
 1127            }
 1128        }
 1129
 1130        private static Dictionary<int, CultureInfo> CachedCulturesByLcid
 1131        {
 1132            get
 1133            {
 01134                Dictionary<int, CultureInfo>? cache = s_cachedCulturesByLcid;
 01135                if (cache is null)
 1136                {
 01137                    cache = new Dictionary<int, CultureInfo>();
 01138                    cache = Interlocked.CompareExchange(ref s_cachedCulturesByLcid, cache, null) ?? cache;
 1139                }
 1140
 01141                return cache;
 1142            }
 1143        }
 1144
 1145        public static CultureInfo GetCultureInfoByIetfLanguageTag(string name)
 1146        {
 1147            // Disallow old zh-CHT/zh-CHS names
 01148            if (name is "zh-CHT" or "zh-CHS")
 1149            {
 01150                throw new CultureNotFoundException(nameof(name), SR.Format(SR.Argument_CultureIetfNotSupported, name));
 1151            }
 1152
 01153            CultureInfo ci = GetCultureInfo(name);
 1154
 1155            // Disallow alt sorts and es-es_TS
 01156            if (ci.LCID > 0xffff || ci.LCID == 0x040a)
 1157            {
 01158                throw new CultureNotFoundException(nameof(name), SR.Format(SR.Argument_CultureIetfNotSupported, name));
 1159            }
 1160
 01161            return ci;
 1162        }
 1163    }
 1164}
 1165

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.Windows.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4namespace System.Globalization
 5{
 6    public partial class CultureInfo : IFormatProvider
 7    {
 8        internal static CultureInfo GetUserDefaultCulture()
 9        {
 010            if (GlobalizationMode.Invariant)
 011                return InvariantCulture;
 12
 013            string? strDefault = UserDefaultLocaleName;
 14
 015            return strDefault != null ?
 016                GetCultureByName(strDefault) :
 017                InvariantCulture;
 18        }
 19
 20        private static unsafe CultureInfo GetUserDefaultUICulture()
 21        {
 022            if (GlobalizationMode.Invariant)
 023                return InvariantCulture;
 24
 25            const uint MUI_LANGUAGE_NAME = 0x8;    // Use ISO language (culture) name convention
 026            uint langCount = 0;
 027            uint bufLen = 0;
 28
 029            if (Interop.Kernel32.GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &langCount, null, &bufLen) != Interop.BO
 30            {
 031                Span<char> languages = bufLen <= 256 ? stackalloc char[(int)bufLen] : new char[bufLen];
 032                fixed (char* pLanguages = languages)
 33                {
 034                    if (Interop.Kernel32.GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &langCount, pLanguages, &bufLen)
 35                    {
 036                        return GetCultureByName(languages.ToString());
 37                    }
 38                }
 39            }
 40
 041            return InitializeUserDefaultCulture();
 42        }
 43
 044        internal static string? UserDefaultLocaleName { get; set; } = GetUserDefaultLocaleName();
 45
 46        private static string? GetUserDefaultLocaleName() =>
 047            GlobalizationMode.Invariant ?
 048                InvariantCulture.Name :
 049                CultureData.GetLocaleInfoEx(Interop.Kernel32.LOCALE_NAME_USER_DEFAULT, Interop.Kernel32.LOCALE_SNAME) ??
 050                CultureData.GetLocaleInfoEx(Interop.Kernel32.LOCALE_NAME_SYSTEM_DEFAULT, Interop.Kernel32.LOCALE_SNAME);
 51    }
 52}
 53

Methods/Properties

.cctor()
AsyncLocalSetCurrentCulture(System.Threading.AsyncLocalValueChangedArgs`1<System.Globalization.CultureInfo>)
AsyncLocalSetCurrentUICulture(System.Threading.AsyncLocalValueChangedArgs`1<System.Globalization.CultureInfo>)
InitializeUserDefaultCulture()
InitializeUserDefaultUICulture()
GetCultureNotSupportedExceptionMessage()
.ctor(System.String)
.ctor(System.String,System.Boolean)
.ctor(System.Globalization.CultureData,System.Boolean)
CreateCultureInfoNoThrow(System.String,System.Boolean)
.ctor(System.Int32)
.ctor(System.Int32,System.Boolean)
.ctor(System.String,System.String)
GetCultureByName(System.String)
CreateSpecificCulture(System.String)
VerifyCultureName(System.String,System.Boolean)
VerifyCultureName(System.Globalization.CultureInfo,System.Boolean)
CurrentCulture()
CurrentCulture(System.Globalization.CultureInfo)
CurrentUICulture()
CurrentUICulture(System.Globalization.CultureInfo)
UserDefaultUICulture()
InstalledUICulture()
DefaultThreadCurrentCulture()
DefaultThreadCurrentCulture(System.Globalization.CultureInfo)
DefaultThreadCurrentUICulture()
DefaultThreadCurrentUICulture(System.Globalization.CultureInfo)
InvariantCulture()
Parent()
LCID()
KeyboardLayoutId()
GetCultures(System.Globalization.CultureTypes)
Name()
SortName()
InteropName()
IetfLanguageTag()
DisplayName()
NativeName()
EnglishName()
TwoLetterISOLanguageName()
ThreeLetterISOLanguageName()
ThreeLetterWindowsLanguageName()
CompareInfo()
TextInfo()
Equals(System.Object)
GetHashCode()
ToString()
GetFormat(System.Type)
IsNeutralCulture()
CultureTypes()
NumberFormat()
NumberFormat(System.Globalization.NumberFormatInfo)
DateTimeFormat()
DateTimeFormat(System.Globalization.DateTimeFormatInfo)
ClearCachedData()
GetCalendarInstance(System.Globalization.CalendarId)
GetCalendarInstanceRare(System.Globalization.CalendarId)
Calendar()
OptionalCalendars()
UseUserOverride()
GetConsoleFallbackUICulture()
Clone()
ReadOnly(System.Globalization.CultureInfo)
IsReadOnly()
VerifyWritable()
HasInvariantCultureName()
GetCultureInfo(System.Int32)
GetCultureInfo(System.String)
GetCultureInfo(System.String,System.String)
GetCultureInfo(System.String,System.Boolean)
CachedCulturesByName()
CachedCulturesByLcid()
GetCultureInfoByIetfLanguageTag(System.String)
GetUserDefaultCulture()
GetUserDefaultUICulture()
UserDefaultLocaleName()
GetUserDefaultLocaleName()