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)
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
34 using System.Threading;
35 using System.Runtime.CompilerServices;
37 namespace System.Globalization
40 public class CultureInfo : ICloneable, IFormatProvider
42 static CultureInfo invariant_culture_info;
44 const int NumOptionalCalendars = 5;
45 const int CalendarTypeMask = 0xFF;
46 const int CalendarTypeBits = 24;
58 bool m_useUserOverride;
59 NumberFormatInfo numInfo;
60 DateTimeFormatInfo dateTimeInfo;
62 private string m_name;
65 private string displayname;
67 private string englishname;
69 private string nativename;
71 private string iso3lang;
73 private string iso2lang;
75 private string icu_name;
77 private string win3lang;
78 CompareInfo compareInfo;
80 private unsafe readonly int *calendar_data;
82 private Calendar [] optional_calendars;
84 int m_dataItem; // MS.NET serializes this.
86 // Deserialized instances will set this to false
90 private static readonly string MSG_READONLY = "This instance is read only";
92 static public CultureInfo InvariantCulture {
94 if (invariant_culture_info == null) {
95 lock (typeof (CultureInfo)) {
96 if (invariant_culture_info == null) {
97 invariant_culture_info = new CultureInfo (0x7f, false);
98 invariant_culture_info.m_isReadOnly = true;
103 return(invariant_culture_info);
107 public static CultureInfo CreateSpecificCulture (string name)
110 throw new ArgumentNullException ("name");
113 if (name == String.Empty)
114 return InvariantCulture;
116 CultureInfo ci = new CultureInfo ();
117 if (!ConstructInternalLocaleFromSpecificName (ci, name.ToLowerInvariant ()))
118 throw new ArgumentException ("Culture name " + name +
119 " is not supported.", name);
124 public static CultureInfo CurrentCulture
127 return Thread.CurrentThread.CurrentCulture;
131 public static CultureInfo CurrentUICulture
134 return Thread.CurrentThread.CurrentUICulture;
138 internal static CultureInfo ConstructCurrentCulture ()
140 CultureInfo ci = new CultureInfo ();
141 if (!ConstructInternalLocaleFromCurrentLocale (ci))
142 ci = InvariantCulture;
146 internal static CultureInfo ConstructCurrentUICulture ()
148 return ConstructCurrentCulture ();
151 public virtual int LCID {
157 public virtual string Name {
163 public virtual string NativeName
166 if (!constructed) Construct ();
171 public virtual Calendar Calendar
173 get { return DateTimeFormat.Calendar; }
176 public virtual Calendar[] OptionalCalendars
179 return optional_calendars;
183 public virtual CultureInfo Parent
186 if (cultureID == 0x7f)
188 if (!constructed) Construct ();
189 if (parent_lcid == cultureID)
191 return new CultureInfo (parent_lcid);
195 public virtual TextInfo TextInfo
198 if (textInfo == null) {
200 if(textInfo == null) {
201 textInfo = new TextInfo (this, cultureID);
210 public virtual string ThreeLetterISOLanguageName
213 if (!constructed) Construct ();
218 public virtual string ThreeLetterWindowsLanguageName
221 if (!constructed) Construct ();
226 public virtual string TwoLetterISOLanguageName
229 if (!constructed) Construct ();
234 public bool UseUserOverride
237 return m_useUserOverride;
241 internal string IcuName {
243 if (!constructed) Construct ();
248 public void ClearCachedData()
250 Thread.CurrentThread.CurrentCulture = null;
251 Thread.CurrentThread.CurrentUICulture = null;
254 public virtual object Clone()
256 if (!constructed) Construct ();
257 CultureInfo ci=(CultureInfo)MemberwiseClone ();
258 ci.m_isReadOnly=false;
259 ci.NumberFormat = (NumberFormatInfo)NumberFormat.Clone ();
260 ci.DateTimeFormat = (DateTimeFormatInfo)DateTimeFormat.Clone ();
264 public override bool Equals (object value)
266 CultureInfo b = value as CultureInfo;
269 return b.cultureID == cultureID;
273 public static CultureInfo[] GetCultures(CultureTypes types)
275 bool neutral=((types & CultureTypes.NeutralCultures)!=0);
276 bool specific=((types & CultureTypes.SpecificCultures)!=0);
277 bool installed=((types & CultureTypes.InstalledWin32Cultures)!=0); // TODO
279 return internal_get_cultures (neutral, specific, installed);
282 public override int GetHashCode()
287 public static CultureInfo ReadOnly(CultureInfo ci)
290 throw new ArgumentNullException("ci");
293 if(ci.m_isReadOnly) {
296 CultureInfo new_ci=(CultureInfo)ci.Clone ();
297 new_ci.m_isReadOnly=true;
302 public override string ToString()
307 public virtual CompareInfo CompareInfo
310 if (!constructed) Construct ();
311 if(compareInfo==null) {
313 if(compareInfo==null) {
314 compareInfo=new CompareInfo (this);
323 internal static bool IsIDNeutralCulture (int lcid)
326 if (!internal_is_lcid_neutral (lcid, out ret))
327 throw new ArgumentException (String.Format ("Culture id 0x{:x4} is not supported.", lcid));
332 public virtual bool IsNeutralCulture {
334 if (!constructed) Construct ();
335 return ((cultureID & 0xff00) == 0 || specific_lcid == 0);
339 public virtual NumberFormatInfo NumberFormat {
341 if (!constructed) Construct ();
342 if (IsNeutralCulture && cultureID != 0x7f) {
343 throw new NotSupportedException ("Culture \"" + m_name + "\" is " +
344 "a neutral culture. It can not be used in formatting " +
345 "and parsing and therefore cannot be set as the thread's " +
348 if (numInfo == null){
350 if (numInfo == null) {
351 numInfo = new NumberFormatInfo ();
352 construct_number_format ();
361 if (!constructed) Construct ();
362 if (m_isReadOnly) throw new InvalidOperationException(MSG_READONLY);
365 throw new ArgumentNullException ("NumberFormat");
371 public virtual DateTimeFormatInfo DateTimeFormat
375 if (!constructed) Construct ();
376 if (IsNeutralCulture && cultureID != 0x7f) {
377 throw new NotSupportedException ("Culture \"" + m_name + "\" is " +
378 "a neutral culture. It can not be used in formatting " +
379 "and parsing and therefore cannot be set as the thread's " +
382 if (dateTimeInfo == null)
386 if (dateTimeInfo == null) {
387 dateTimeInfo = new DateTimeFormatInfo();
388 construct_datetime_format ();
389 if (optional_calendars != null)
390 dateTimeInfo.Calendar = optional_calendars [0];
400 if (!constructed) Construct ();
401 if (m_isReadOnly) throw new InvalidOperationException(MSG_READONLY);
404 throw new ArgumentNullException ("DateTimeFormat");
406 dateTimeInfo = value;
410 public virtual string DisplayName
413 if (!constructed) Construct ();
418 public virtual string EnglishName
421 if (!constructed) Construct ();
427 public static CultureInfo InstalledUICulture
434 public bool IsReadOnly
437 return(m_isReadOnly);
443 // IFormatProvider implementation
445 public virtual object GetFormat( Type formatType )
447 object format = null;
449 if ( formatType == typeof(NumberFormatInfo) )
450 format = NumberFormat;
451 else if ( formatType == typeof(DateTimeFormatInfo) )
452 format = DateTimeFormat;
459 construct_internal_locale_from_lcid (cultureID);
463 bool ConstructInternalLocaleFromName (string locale)
465 if (!construct_internal_locale_from_name (locale))
467 ConstructCalendars ();
471 bool ConstructInternalLocaleFromLcid (int lcid)
473 if (!construct_internal_locale_from_lcid (lcid))
475 ConstructCalendars ();
479 static bool ConstructInternalLocaleFromSpecificName (CultureInfo ci, string name)
481 if (!construct_internal_locale_from_specific_name (ci, name))
483 ci.ConstructCalendars ();
487 static bool ConstructInternalLocaleFromCurrentLocale (CultureInfo ci)
489 if (!construct_internal_locale_from_current_locale (ci))
491 ci.ConstructCalendars ();
495 static CultureInfo [] GetCultures (bool neutral, bool specific, bool installed)
497 CultureInfo [] cis = internal_get_cultures (neutral, specific, installed);
498 foreach (CultureInfo ci in cis)
499 ci.ConstructCalendars ();
503 [MethodImplAttribute (MethodImplOptions.InternalCall)]
504 private extern bool construct_internal_locale_from_lcid (int lcid);
506 [MethodImplAttribute (MethodImplOptions.InternalCall)]
507 private extern bool construct_internal_locale_from_name (string name);
509 [MethodImplAttribute (MethodImplOptions.InternalCall)]
510 private extern static bool construct_internal_locale_from_specific_name (CultureInfo ci,
513 [MethodImplAttribute (MethodImplOptions.InternalCall)]
514 private extern static bool construct_internal_locale_from_current_locale (CultureInfo ci);
516 [MethodImplAttribute (MethodImplOptions.InternalCall)]
517 private extern static CultureInfo [] internal_get_cultures (bool neutral, bool specific, bool installed);
519 [MethodImplAttribute (MethodImplOptions.InternalCall)]
520 private extern void construct_datetime_format ();
522 [MethodImplAttribute (MethodImplOptions.InternalCall)]
523 private extern void construct_number_format ();
525 // Returns false if the culture can not be found, sets is_neutral if it is
526 [MethodImplAttribute (MethodImplOptions.InternalCall)]
527 private extern static bool internal_is_lcid_neutral (int lcid, out bool is_neutral);
529 private void ConstructInvariant (bool use_user_override)
533 this.m_useUserOverride=use_user_override;
535 /* NumberFormatInfo defaults to the invariant data */
536 numInfo=NumberFormatInfo.InvariantInfo;
538 /* DateTimeFormatInfo defaults to the invariant data */
539 dateTimeInfo=DateTimeFormatInfo.InvariantInfo;
541 textInfo=new TextInfo (this, cultureID);
544 displayname="Invariant Language (Invariant Country)";
545 englishname="Invariant Language (Invariant Country)";
546 nativename="Invariant Language (Invariant Country)";
549 icu_name="en_US_POSIX";
553 public CultureInfo (int culture, bool use_user_override)
556 throw new ArgumentOutOfRangeException ("Positive number required.",
561 if(culture==0x007f) {
562 /* Short circuit the invariant culture */
563 ConstructInvariant (use_user_override);
567 if (!ConstructInternalLocaleFromLcid (culture))
568 throw new ArgumentException (
569 String.Format ("Culture ID {0} (0x{0:X4}) is not a " +
570 "supported culture.", culture), "culture");
573 public CultureInfo (int culture) : this (culture, false) {}
575 public CultureInfo (string name, bool use_user_override)
578 throw new ArgumentNullException ();
583 /* Short circuit the invariant culture */
584 ConstructInvariant (use_user_override);
588 if (!ConstructInternalLocaleFromName (name.ToLowerInvariant ()))
589 throw new ArgumentException ("Culture name " + name +
590 " is not supported.", "name");
591 ConstructCalendars ();
594 public CultureInfo (string name) : this (name, false) {}
596 // This is used when creating by specific name and creating by
597 // current locale so we can initialize the object without
598 // doing any member initialization
599 private CultureInfo () { constructed = true; }
601 unsafe internal void ConstructCalendars ()
603 if (calendar_data == null)
606 optional_calendars = new Calendar [NumOptionalCalendars];
608 for (int i=0; i<NumOptionalCalendars; i++) {
610 switch (*(calendar_data + i) & CalendarTypeMask >> CalendarTypeBits) {
612 int gt = (*(calendar_data + i) & CalendarTypeMask);
613 GregorianCalendarTypes type = (GregorianCalendarTypes) gt;
614 cal = new GregorianCalendar (type);
617 cal = new HijriCalendar ();
620 cal = new ThaiBuddhistCalendar ();
623 throw new Exception ("invalid calendar type: " + *(calendar_data + i));
625 optional_calendars [i] = cal;