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 (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;
262 public override bool Equals (object value)
264 CultureInfo b = value as CultureInfo;
267 return b.cultureID == cultureID;
271 public static CultureInfo[] GetCultures(CultureTypes types)
273 bool neutral=((types & CultureTypes.NeutralCultures)!=0);
274 bool specific=((types & CultureTypes.SpecificCultures)!=0);
275 bool installed=((types & CultureTypes.InstalledWin32Cultures)!=0); // TODO
277 return internal_get_cultures (neutral, specific, installed);
280 public override int GetHashCode()
285 public static CultureInfo ReadOnly(CultureInfo ci)
288 throw new ArgumentNullException("ci");
291 if(ci.m_isReadOnly) {
294 CultureInfo new_ci=(CultureInfo)ci.Clone ();
295 new_ci.m_isReadOnly=true;
300 public override string ToString()
305 public virtual CompareInfo CompareInfo
308 if (!constructed) Construct ();
309 if(compareInfo==null) {
311 if(compareInfo==null) {
312 compareInfo=new CompareInfo (this);
321 internal static bool IsIDNeutralCulture (int lcid)
324 if (!internal_is_lcid_neutral (lcid, out ret))
325 throw new ArgumentException (String.Format ("Culture id 0x{:x4} is not supported.", lcid));
330 public virtual bool IsNeutralCulture {
332 if (!constructed) Construct ();
333 return ((cultureID & 0xff00) == 0 || specific_lcid == 0);
337 public virtual NumberFormatInfo NumberFormat {
339 if (!constructed) Construct ();
340 if (IsNeutralCulture && cultureID != 0x7f) {
341 throw new NotSupportedException ("Culture \"" + m_name + "\" is " +
342 "a neutral culture. It can not be used in formatting " +
343 "and parsing and therefore cannot be set as the thread's " +
346 if (numInfo == null){
348 if (numInfo == null) {
349 numInfo = new NumberFormatInfo ();
350 construct_number_format ();
359 if (!constructed) Construct ();
360 if (m_isReadOnly) throw new InvalidOperationException(MSG_READONLY);
363 throw new ArgumentNullException ("NumberFormat");
369 public virtual DateTimeFormatInfo DateTimeFormat
373 if (!constructed) Construct ();
374 if (IsNeutralCulture && cultureID != 0x7f) {
375 throw new NotSupportedException ("Culture \"" + m_name + "\" is " +
376 "a neutral culture. It can not be used in formatting " +
377 "and parsing and therefore cannot be set as the thread's " +
380 if (dateTimeInfo == null)
384 if (dateTimeInfo == null) {
385 dateTimeInfo = new DateTimeFormatInfo();
386 construct_datetime_format ();
387 if (optional_calendars != null)
388 dateTimeInfo.Calendar = optional_calendars [0];
398 if (!constructed) Construct ();
399 if (m_isReadOnly) throw new InvalidOperationException(MSG_READONLY);
402 throw new ArgumentNullException ("DateTimeFormat");
404 dateTimeInfo = value;
408 public virtual string DisplayName
411 if (!constructed) Construct ();
416 public virtual string EnglishName
419 if (!constructed) Construct ();
425 public static CultureInfo InstalledUICulture
432 public bool IsReadOnly
435 return(m_isReadOnly);
441 // IFormatProvider implementation
443 public virtual object GetFormat( Type formatType )
445 object format = null;
447 if ( formatType == typeof(NumberFormatInfo) )
448 format = NumberFormat;
449 else if ( formatType == typeof(DateTimeFormatInfo) )
450 format = DateTimeFormat;
457 construct_internal_locale_from_lcid (cultureID);
461 bool ConstructInternalLocaleFromName (string locale)
463 if (!construct_internal_locale_from_name (locale))
465 ConstructCalendars ();
469 bool ConstructInternalLocaleFromLcid (int lcid)
471 if (!construct_internal_locale_from_lcid (lcid))
473 ConstructCalendars ();
477 static bool ConstructInternalLocaleFromSpecificName (CultureInfo ci, string name)
479 if (!construct_internal_locale_from_specific_name (ci, name))
481 ci.ConstructCalendars ();
485 static bool ConstructInternalLocaleFromCurrentLocale (CultureInfo ci)
487 if (!construct_internal_locale_from_current_locale (ci))
489 ci.ConstructCalendars ();
493 static CultureInfo [] GetCultures (bool neutral, bool specific, bool installed)
495 CultureInfo [] cis = internal_get_cultures (neutral, specific, installed);
496 foreach (CultureInfo ci in cis)
497 ci.ConstructCalendars ();
501 [MethodImplAttribute (MethodImplOptions.InternalCall)]
502 private extern bool construct_internal_locale_from_lcid (int lcid);
504 [MethodImplAttribute (MethodImplOptions.InternalCall)]
505 private extern bool construct_internal_locale_from_name (string name);
507 [MethodImplAttribute (MethodImplOptions.InternalCall)]
508 private extern static bool construct_internal_locale_from_specific_name (CultureInfo ci,
511 [MethodImplAttribute (MethodImplOptions.InternalCall)]
512 private extern static bool construct_internal_locale_from_current_locale (CultureInfo ci);
514 [MethodImplAttribute (MethodImplOptions.InternalCall)]
515 private extern static CultureInfo [] internal_get_cultures (bool neutral, bool specific, bool installed);
517 [MethodImplAttribute (MethodImplOptions.InternalCall)]
518 private extern void construct_datetime_format ();
520 [MethodImplAttribute (MethodImplOptions.InternalCall)]
521 private extern void construct_number_format ();
523 // Returns false if the culture can not be found, sets is_neutral if it is
524 [MethodImplAttribute (MethodImplOptions.InternalCall)]
525 private extern static bool internal_is_lcid_neutral (int lcid, out bool is_neutral);
527 private void ConstructInvariant (bool use_user_override)
531 this.m_useUserOverride=use_user_override;
533 /* NumberFormatInfo defaults to the invariant data */
534 numInfo=NumberFormatInfo.InvariantInfo;
536 /* DateTimeFormatInfo defaults to the invariant data */
537 dateTimeInfo=DateTimeFormatInfo.InvariantInfo;
539 textInfo=new TextInfo ();
542 displayname="Invariant Language (Invariant Country)";
543 englishname="Invariant Language (Invariant Country)";
544 nativename="Invariant Language (Invariant Country)";
547 icu_name="en_US_POSIX";
551 public CultureInfo (int culture, bool use_user_override)
554 throw new ArgumentOutOfRangeException ("Positive number required.",
559 if(culture==0x007f) {
560 /* Short circuit the invariant culture */
561 ConstructInvariant (use_user_override);
565 if (!ConstructInternalLocaleFromLcid (culture))
566 throw new ArgumentException (
567 String.Format ("Culture ID {0} (0x{0:X4}) is not a " +
568 "supported culture.", culture), "culture");
571 public CultureInfo (int culture) : this (culture, false) {}
573 public CultureInfo (string name, bool use_user_override)
576 throw new ArgumentNullException ();
581 /* Short circuit the invariant culture */
582 ConstructInvariant (use_user_override);
586 if (!ConstructInternalLocaleFromName (name.ToLowerInvariant ()))
587 throw new ArgumentException ("Culture name " + name +
588 " is not supported.", "name");
589 ConstructCalendars ();
592 public CultureInfo (string name) : this (name, false) {}
594 // This is used when creating by specific name and creating by
595 // current locale so we can initialize the object without
596 // doing any member initialization
597 private CultureInfo () { constructed = true; }
599 unsafe internal void ConstructCalendars ()
601 if (calendar_data == null)
604 optional_calendars = new Calendar [NumOptionalCalendars];
606 for (int i=0; i<NumOptionalCalendars; i++) {
608 switch (*(calendar_data + i) & CalendarTypeMask >> CalendarTypeBits) {
610 int gt = (*(calendar_data + i) & CalendarTypeMask);
611 GregorianCalendarTypes type = (GregorianCalendarTypes) gt;
612 cal = new GregorianCalendar (type);
615 cal = new HijriCalendar ();
618 cal = new ThaiBuddhistCalendar ();
621 throw new Exception ("invalid calendar type: " + *(calendar_data + i));
623 optional_calendars [i] = cal;