2 // System.Globalization.CultureInfo.cs
4 // Miguel de Icaza (miguel@ximian.com)
5 // Dick Porter (dick@ximian.com)
7 // (C) 2001, 2002, 2003 Ximian, Inc. (http://www.ximian.com)
10 using System.Collections;
11 using System.Threading;
12 using System.Runtime.CompilerServices;
14 namespace System.Globalization
17 public class CultureInfo : ICloneable, IFormatProvider
19 static CultureInfo invariant_culture_info;
21 const int NumOptionalCalendars = 5;
22 const int CalendarTypeMask = 0xFF;
23 const int CalendarTypeBits = 24;
35 bool m_useUserOverride;
36 NumberFormatInfo numInfo;
37 DateTimeFormatInfo dateTimeInfo;
39 private string m_name;
42 private string displayname;
44 private string englishname;
46 private string nativename;
48 private string iso3lang;
50 private string iso2lang;
52 private string icu_name;
54 private string win3lang;
55 CompareInfo compareInfo;
57 private unsafe int *calendar_data;
59 private Calendar [] optional_calendars;
61 int m_dataItem; // MS.NET serializes this.
63 // Deserialized instances will set this to false
67 private static readonly string MSG_READONLY = "This instance is read only";
69 static public CultureInfo InvariantCulture {
71 if (invariant_culture_info == null) {
72 lock (typeof (CultureInfo)) {
73 if (invariant_culture_info == null) {
74 invariant_culture_info = new CultureInfo (0x7f, false);
75 invariant_culture_info.m_isReadOnly = true;
80 return(invariant_culture_info);
84 public static CultureInfo CreateSpecificCulture (string name)
87 throw new ArgumentNullException ("name");
90 if (name == String.Empty)
91 return InvariantCulture;
93 CultureInfo ci = new CultureInfo ();
94 if (!ConstructInternalLocaleFromSpecificName (ci, name.ToLowerInvariant ()))
95 throw new ArgumentException ("Culture name " + name +
96 " is not supported.", name);
101 public static CultureInfo CurrentCulture
104 return Thread.CurrentThread.CurrentCulture;
108 public static CultureInfo CurrentUICulture
111 return Thread.CurrentThread.CurrentUICulture;
115 internal static CultureInfo ConstructCurrentCulture ()
117 CultureInfo ci = new CultureInfo ();
118 if (!ConstructInternalLocaleFromCurrentLocale (ci))
119 ci = InvariantCulture;
123 internal static CultureInfo ConstructCurrentUICulture ()
125 return ConstructCurrentCulture ();
128 public virtual int LCID {
134 public virtual string Name {
140 public virtual string NativeName
143 if (!constructed) Construct ();
148 public virtual Calendar Calendar
150 get { return DateTimeFormat.Calendar; }
153 public virtual Calendar[] OptionalCalendars
156 return optional_calendars;
160 public virtual CultureInfo Parent
163 if (cultureID == 0x7f)
165 if (!constructed) Construct ();
166 if (parent_lcid == cultureID)
168 return new CultureInfo (parent_lcid);
172 public virtual TextInfo TextInfo
175 if (textInfo == null) {
177 if(textInfo == null) {
178 textInfo = new TextInfo (cultureID);
187 public virtual string ThreeLetterISOLanguageName
190 if (!constructed) Construct ();
195 public virtual string ThreeLetterWindowsLanguageName
198 if (!constructed) Construct ();
203 public virtual string TwoLetterISOLanguageName
206 if (!constructed) Construct ();
211 public bool UseUserOverride
214 return m_useUserOverride;
218 internal string IcuName {
220 if (!constructed) Construct ();
225 public void ClearCachedData()
227 Thread.CurrentThread.CurrentCulture = null;
228 Thread.CurrentThread.CurrentUICulture = null;
231 public virtual object Clone()
233 if (!constructed) Construct ();
234 CultureInfo ci=(CultureInfo)MemberwiseClone ();
235 ci.m_isReadOnly=false;
239 public override bool Equals (object value)
241 CultureInfo b = value as CultureInfo;
244 return b.cultureID == cultureID;
248 public static CultureInfo[] GetCultures(CultureTypes types)
250 bool neutral=((types & CultureTypes.NeutralCultures)!=0);
251 bool specific=((types & CultureTypes.SpecificCultures)!=0);
252 bool installed=((types & CultureTypes.InstalledWin32Cultures)!=0); // TODO
254 return internal_get_cultures (neutral, specific, installed);
257 public override int GetHashCode()
262 public static CultureInfo ReadOnly(CultureInfo ci)
265 throw new ArgumentNullException("ci");
268 if(ci.m_isReadOnly) {
271 CultureInfo new_ci=(CultureInfo)ci.Clone ();
272 new_ci.m_isReadOnly=true;
277 public override string ToString()
282 public virtual CompareInfo CompareInfo
285 if (!constructed) Construct ();
286 if(compareInfo==null) {
288 if(compareInfo==null) {
289 compareInfo=new CompareInfo (this);
298 internal static bool IsIDNeutralCulture (int lcid)
301 if (!internal_is_lcid_neutral (lcid, out ret))
302 throw new ArgumentException (String.Format ("Culture id 0x{:x4} is not supported.", lcid));
307 public virtual bool IsNeutralCulture {
309 if (!constructed) Construct ();
310 return ((cultureID & 0xff00) == 0 || specific_lcid == 0);
314 public virtual NumberFormatInfo NumberFormat {
316 if (!constructed) Construct ();
317 if (IsNeutralCulture && cultureID != 0x7f) {
318 throw new NotSupportedException ("Culture \"" + m_name + "\" is " +
319 "a neutral culture. It can not be used in formatting " +
320 "and parsing and therefore cannot be set as the thread's " +
323 if (numInfo == null){
325 if (numInfo == null) {
326 numInfo = new NumberFormatInfo ();
327 construct_number_format ();
336 if (!constructed) Construct ();
337 if (m_isReadOnly) throw new InvalidOperationException(MSG_READONLY);
340 throw new ArgumentNullException ("NumberFormat");
346 public virtual DateTimeFormatInfo DateTimeFormat
350 if (!constructed) Construct ();
351 if (IsNeutralCulture && cultureID != 0x7f) {
352 throw new NotSupportedException ("Culture \"" + m_name + "\" is " +
353 "a neutral culture. It can not be used in formatting " +
354 "and parsing and therefore cannot be set as the thread's " +
357 if (dateTimeInfo == null)
361 if (dateTimeInfo == null) {
362 dateTimeInfo = new DateTimeFormatInfo();
363 construct_datetime_format ();
364 if (optional_calendars != null)
365 dateTimeInfo.Calendar = optional_calendars [0];
375 if (!constructed) Construct ();
376 if (m_isReadOnly) throw new InvalidOperationException(MSG_READONLY);
379 throw new ArgumentNullException ("DateTimeFormat");
381 dateTimeInfo = value;
385 public virtual string DisplayName
388 if (!constructed) Construct ();
393 public virtual string EnglishName
396 if (!constructed) Construct ();
402 public static CultureInfo InstalledUICulture
409 public bool IsReadOnly
412 return(m_isReadOnly);
418 // IFormatProvider implementation
420 public virtual object GetFormat( Type formatType )
422 object format = null;
424 if ( formatType == typeof(NumberFormatInfo) )
425 format = NumberFormat;
426 else if ( formatType == typeof(DateTimeFormatInfo) )
427 format = DateTimeFormat;
434 construct_internal_locale_from_lcid (cultureID);
438 bool ConstructInternalLocaleFromName (string locale)
440 if (!construct_internal_locale_from_name (locale))
442 ConstructCalendars ();
446 bool ConstructInternalLocaleFromLcid (int lcid)
448 if (!construct_internal_locale_from_lcid (lcid))
450 ConstructCalendars ();
454 static bool ConstructInternalLocaleFromSpecificName (CultureInfo ci, string name)
456 if (!construct_internal_locale_from_specific_name (ci, name))
458 ci.ConstructCalendars ();
462 static bool ConstructInternalLocaleFromCurrentLocale (CultureInfo ci)
464 if (!construct_internal_locale_from_current_locale (ci))
466 ci.ConstructCalendars ();
470 static CultureInfo [] GetCultures (bool neutral, bool specific, bool installed)
472 CultureInfo [] cis = internal_get_cultures (neutral, specific, installed);
473 foreach (CultureInfo ci in cis)
474 ci.ConstructCalendars ();
478 [MethodImplAttribute (MethodImplOptions.InternalCall)]
479 private extern bool construct_internal_locale_from_lcid (int lcid);
481 [MethodImplAttribute (MethodImplOptions.InternalCall)]
482 private extern bool construct_internal_locale_from_name (string name);
484 [MethodImplAttribute (MethodImplOptions.InternalCall)]
485 private extern static bool construct_internal_locale_from_specific_name (CultureInfo ci,
488 [MethodImplAttribute (MethodImplOptions.InternalCall)]
489 private extern static bool construct_internal_locale_from_current_locale (CultureInfo ci);
491 [MethodImplAttribute (MethodImplOptions.InternalCall)]
492 private extern static CultureInfo [] internal_get_cultures (bool neutral, bool specific, bool installed);
494 [MethodImplAttribute (MethodImplOptions.InternalCall)]
495 private extern void construct_datetime_format ();
497 [MethodImplAttribute (MethodImplOptions.InternalCall)]
498 private extern void construct_number_format ();
500 // Returns false if the culture can not be found, sets is_neutral if it is
501 [MethodImplAttribute (MethodImplOptions.InternalCall)]
502 private extern static bool internal_is_lcid_neutral (int lcid, out bool is_neutral);
504 private void ConstructInvariant (bool use_user_override)
508 this.m_useUserOverride=use_user_override;
510 /* NumberFormatInfo defaults to the invariant data */
511 numInfo=NumberFormatInfo.InvariantInfo;
513 /* DateTimeFormatInfo defaults to the invariant data */
514 dateTimeInfo=DateTimeFormatInfo.InvariantInfo;
516 textInfo=new TextInfo ();
519 displayname="Invariant Language (Invariant Country)";
520 englishname="Invariant Language (Invariant Country)";
521 nativename="Invariant Language (Invariant Country)";
524 icu_name="en_US_POSIX";
528 public CultureInfo (int culture, bool use_user_override)
531 throw new ArgumentOutOfRangeException ("Positive number required.",
536 if(culture==0x007f) {
537 /* Short circuit the invariant culture */
538 ConstructInvariant (use_user_override);
542 if (!ConstructInternalLocaleFromLcid (culture))
543 throw new ArgumentException (
544 String.Format ("Culture ID {0} (0x{0:X4}) is not a " +
545 "supported culture.", culture), "culture");
548 public CultureInfo (int culture) : this (culture, false) {}
550 public CultureInfo (string name, bool use_user_override)
553 throw new ArgumentNullException ();
558 /* Short circuit the invariant culture */
559 ConstructInvariant (use_user_override);
563 if (!ConstructInternalLocaleFromName (name.ToLowerInvariant ()))
564 throw new ArgumentException ("Culture name " + name +
565 " is not supported.", "name");
566 ConstructCalendars ();
569 public CultureInfo (string name) : this (name, false) {}
571 // This is used when creating by specific name and creating by
572 // current locale so we can initialize the object without
573 // doing any member initialization
574 private CultureInfo () { constructed = true; }
576 unsafe internal void ConstructCalendars ()
578 if (calendar_data == null)
581 optional_calendars = new Calendar [NumOptionalCalendars];
583 for (int i=0; i<NumOptionalCalendars; i++) {
585 switch (*(calendar_data + i) & CalendarTypeMask >> CalendarTypeBits) {
587 int gt = (*(calendar_data + i) & CalendarTypeMask);
588 GregorianCalendarTypes type = (GregorianCalendarTypes) gt;
589 cal = new GregorianCalendar (type);
592 cal = new HijriCalendar ();
595 cal = new ThaiBuddhistCalendar ();
598 throw new Exception ("invalid calendar type: " + *(calendar_data + i));
600 optional_calendars [i] = cal;