2 // System.Globalization.CultureInfo.cs
5 // Miguel de Icaza (miguel@ximian.com)
6 // Dick Porter (dick@ximian.com)
7 // Marek Safar (marek.safar@gmail.com)
9 // (C) 2001, 2002, 2003 Ximian, Inc. (http://www.ximian.com)
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 // Copyright (C) 2012 Xamarin Inc (http://www.xamarin.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.Generic;
34 using System.Threading;
35 using System.Runtime.CompilerServices;
36 using System.Runtime.InteropServices;
37 using System.Diagnostics.Contracts;
39 namespace System.Globalization
41 [System.Runtime.InteropServices.ComVisible (true)]
43 [StructLayout (LayoutKind.Sequential)]
44 public class CultureInfo : ICloneable, IFormatProvider
46 static volatile CultureInfo invariant_culture_info = new CultureInfo (InvariantCultureId, false, true);
47 static object shared_table_lock = new object ();
48 static CultureInfo default_current_culture;
50 #pragma warning disable 169, 649
60 int default_calendar_type;
61 bool m_useUserOverride;
62 internal volatile NumberFormatInfo numInfo;
63 internal volatile DateTimeFormatInfo dateTimeInfo;
64 volatile TextInfo textInfo;
65 internal string m_name;
68 private string englishname;
70 private string nativename;
72 private string iso3lang;
74 private string iso2lang;
76 private string win3lang;
78 private string territory;
80 string[] native_calendar_names;
82 volatile CompareInfo compareInfo;
84 private unsafe readonly void *textinfo_data;
86 [StructLayout (LayoutKind.Sequential)]
92 public bool right_to_left;
96 int m_dataItem; // MS.NET serializes this.
97 #pragma warning restore 169, 649
102 CultureInfo parent_culture;
104 // Deserialized instances will set this to false
109 // Used by Thread.set_CurrentCulture
110 internal byte[] cached_serialized_form;
112 [NonSerialized]internal CultureData m_cultureData;
113 [NonSerialized]internal bool m_isInherited;
115 internal const int InvariantCultureId = 0x7F;
116 const int CalendarTypeBits = 8;
118 const string MSG_READONLY = "This instance is read only";
120 static volatile CultureInfo s_DefaultThreadCurrentUICulture;
121 static volatile CultureInfo s_DefaultThreadCurrentCulture;
123 public static CultureInfo InvariantCulture {
125 return invariant_culture_info;
129 public static CultureInfo CurrentCulture {
131 return Thread.CurrentThread.CurrentCulture;
134 Thread.CurrentThread.CurrentCulture = value;
138 public static CultureInfo CurrentUICulture {
140 return Thread.CurrentThread.CurrentUICulture;
143 Thread.CurrentThread.CurrentUICulture = value;
147 internal static CultureInfo ConstructCurrentCulture ()
149 if (default_current_culture != null)
150 return default_current_culture;
152 var locale_name = get_current_locale_name ();
153 CultureInfo ci = null;
155 if (locale_name != null) {
157 ci = CreateSpecificCulture (locale_name);
163 ci = InvariantCulture;
165 ci.m_isReadOnly = true;
166 ci.m_useUserOverride = true;
169 default_current_culture = ci;
173 internal static CultureInfo ConstructCurrentUICulture ()
175 return ConstructCurrentCulture ();
178 // it is used for RegionInfo.
179 internal string Territory {
180 get { return territory; }
183 // FIXME: It is implemented, but would be hell slow.
185 public CultureTypes CultureTypes {
187 CultureTypes ret = (CultureTypes) 0;
188 foreach (CultureTypes v in Enum.GetValues (typeof (CultureTypes)))
189 if (Array.IndexOf (GetCultures (v), this) >= 0)
196 public CultureInfo GetConsoleFallbackUICulture ()
198 // as documented in MSDN ...
200 case "ar": case "ar-BH": case "ar-EG": case "ar-IQ":
201 case "ar-JO": case "ar-KW": case "ar-LB": case "ar-LY":
202 case "ar-QA": case "ar-SA": case "ar-SY": case "ar-AE":
204 case "dv": case "dv-MV":
205 case "fa": case "fa-IR":
206 case "gu": case "gu-IN":
207 case "he": case "he-IL":
208 case "hi": case "hi-IN":
209 case "kn": case "kn-IN":
210 case "kok": case "kok-IN":
211 case "mr": case "mr-IN":
212 case "pa": case "pa-IN":
213 case "sa": case "sa-IN":
214 case "syr": case "syr-SY":
215 case "ta": case "ta-IN":
216 case "te": case "te-IN":
217 case "th": case "th-TH":
218 case "ur": case "ur-PK":
219 case "vi": case "vi-VN":
220 return GetCultureInfo ("en");
221 case "ar-DZ": case "ar-MA": case "ar-TN":
222 return GetCultureInfo ("fr");
224 return (CultureTypes & CultureTypes.WindowsOnlyCultures) != 0 ? CultureInfo.InvariantCulture : this;
228 public string IetfLanguageTag {
229 // There could be more consistent way to implement
230 // it, but right now it works just fine with this...
243 // For specific cultures it basically returns LCID.
244 // For neutral cultures it is mapped to the default(?) specific
245 // culture, where the LCID of the specific culture seems to be
246 // n + 1024 by default. zh-CHS is the only exception which is
247 // mapped to 2052, not 1028 (zh-CHT is mapped to 1028 instead).
248 // There are very few exceptions, here I simply list them here.
249 // It is Windows-specific property anyways, so no worthy of
250 // trying to do some complex things with locale-builder.
252 public virtual int KeyboardLayoutId {
255 case 4: // zh-CHS (neutral)
257 case 1034: // es-ES Spanish 2
259 case 31748: // zh-CHT (neutral)
261 case 31770: // sr (neutral)
264 return LCID < 1024 ? LCID + 1024 : LCID;
269 public virtual int LCID {
275 public virtual string Name {
281 public virtual string NativeName {
283 if (!constructed) Construct ();
288 internal string NativeCalendarName {
290 if (!constructed) Construct ();
291 return native_calendar_names[(default_calendar_type >> CalendarTypeBits) - 1];
295 public virtual Calendar Calendar {
297 if (calendar == null) {
298 if (!constructed) Construct ();
299 calendar = CreateCalendar (default_calendar_type);
306 [MonoLimitation ("Optional calendars are not supported only default calendar is returned")]
307 public virtual Calendar[] OptionalCalendars {
309 return new[] { Calendar };
313 public virtual CultureInfo Parent
316 if (parent_culture == null) {
319 if (parent_lcid == cultureID) {
321 // Parent lcid is same but culture info is not for legacy zh culture
323 if (parent_lcid == 0x7C04 && EnglishName [EnglishName.Length - 1] == 'y')
324 return parent_culture = new CultureInfo ("zh-Hant");
325 else if (parent_lcid == 0x0004 && EnglishName [EnglishName.Length -1] == 'y')
326 return parent_culture = new CultureInfo ("zh-Hans");
330 if (parent_lcid == InvariantCultureId)
331 parent_culture = InvariantCulture;
332 else if (cultureID == InvariantCultureId)
333 parent_culture = this;
334 else if (cultureID == 0x0404) {
335 // zh-tw has parent id 0x7C04 which is in this case zh-cht and not zh-hant
336 parent_culture = new CultureInfo ("zh-CHT");
338 parent_culture = new CultureInfo (parent_lcid);
340 return parent_culture;
344 public virtual TextInfo TextInfo
347 if (textInfo == null) {
348 if (!constructed) Construct ();
350 if(textInfo == null) {
351 textInfo = CreateTextInfo (m_isReadOnly);
360 public virtual string ThreeLetterISOLanguageName {
362 if (!constructed) Construct ();
367 public virtual string ThreeLetterWindowsLanguageName
370 if (!constructed) Construct ();
375 public virtual string TwoLetterISOLanguageName {
377 if (!constructed) Construct ();
382 public bool UseUserOverride
385 return m_useUserOverride;
389 public void ClearCachedData()
391 lock (shared_table_lock) {
392 shared_by_number = null;
393 shared_by_name = null;
397 // ClearCachedData method does not refresh the information in
398 // the Thread.CurrentCulture property for existing threads
400 default_current_culture = null;
402 RegionInfo.ClearCachedData ();
403 TimeZone.ClearCachedData ();
404 TimeZoneInfo.ClearCachedData ();
407 public virtual object Clone()
409 if (!constructed) Construct ();
410 CultureInfo ci=(CultureInfo)MemberwiseClone ();
411 ci.m_isReadOnly=false;
412 ci.cached_serialized_form=null;
413 if (!IsNeutralCulture) {
414 ci.NumberFormat = (NumberFormatInfo)NumberFormat.Clone ();
415 ci.DateTimeFormat = (DateTimeFormatInfo)DateTimeFormat.Clone ();
420 public override bool Equals (object value)
422 CultureInfo b = value as CultureInfo;
423 return b != null && b.cultureID == cultureID && b.m_name == m_name;
426 public static CultureInfo[] GetCultures(CultureTypes types)
428 bool neutral=((types & CultureTypes.NeutralCultures)!=0);
429 bool specific=((types & CultureTypes.SpecificCultures)!=0);
430 bool installed=((types & CultureTypes.InstalledWin32Cultures)!=0); // TODO
432 CultureInfo [] infos = internal_get_cultures (neutral, specific, installed);
433 // The runtime returns a NULL in the first position of the array when
434 // 'neutral' is true. We fill it in with a clone of InvariantCulture
435 // since it must not be read-only
437 if (neutral && infos.Length > 0 && infos [0] == null) {
438 infos [i++] = (CultureInfo) InvariantCulture.Clone ();
441 for (; i < infos.Length; ++i) {
443 var ti = ci.GetTextInfoData ();
444 infos [i].m_cultureData = CultureData.GetCultureData (ci.m_name, false, ci.datetime_index, ci.CalendarType, ci.number_index, ci.iso2lang,
445 ti.ansi, ti.oem, ti.mac, ti.ebcdic, ti.right_to_left, ((char)ti.list_sep).ToString ());
451 unsafe Data GetTextInfoData ()
453 return *(Data*) textinfo_data;
456 public override int GetHashCode ()
458 return cultureID.GetHashCode ();
461 public static CultureInfo ReadOnly(CultureInfo ci)
464 throw new ArgumentNullException("ci");
467 if(ci.m_isReadOnly) {
470 CultureInfo new_ci=(CultureInfo)ci.Clone ();
471 new_ci.m_isReadOnly=true;
472 if (new_ci.numInfo != null)
473 new_ci.numInfo = NumberFormatInfo.ReadOnly (new_ci.numInfo);
474 if (new_ci.dateTimeInfo != null)
475 new_ci.dateTimeInfo = DateTimeFormatInfo.ReadOnly (new_ci.dateTimeInfo);
476 if (new_ci.textInfo != null)
477 new_ci.textInfo = TextInfo.ReadOnly (new_ci.textInfo);
482 public override string ToString()
487 public virtual CompareInfo CompareInfo
490 if(compareInfo==null) {
495 if(compareInfo==null) {
496 compareInfo=new CompareInfo (this);
505 public virtual bool IsNeutralCulture {
507 if (cultureID == InvariantCultureId)
510 if (!constructed) Construct ();
511 return territory == null;
519 public virtual NumberFormatInfo NumberFormat {
521 if (numInfo == null) {
522 NumberFormatInfo temp = new NumberFormatInfo(this.m_cultureData);
523 temp.isReadOnly = m_isReadOnly;
531 if (!constructed) Construct ();
532 if (m_isReadOnly) throw new InvalidOperationException(MSG_READONLY);
535 throw new ArgumentNullException ("NumberFormat");
541 public virtual DateTimeFormatInfo DateTimeFormat {
543 if (dateTimeInfo != null)
546 if (!constructed) Construct ();
549 var temp = new DateTimeFormatInfo (m_cultureData, Calendar);
550 temp.m_isReadOnly = m_isReadOnly;
551 System.Threading.Thread.MemoryBarrier();
557 if (!constructed) Construct ();
558 if (m_isReadOnly) throw new InvalidOperationException(MSG_READONLY);
561 throw new ArgumentNullException ("DateTimeFormat");
563 dateTimeInfo = value;
567 public virtual string DisplayName {
569 // Mono is not localized and will always return english name regardless of OS locale
574 public virtual string EnglishName {
576 if (!constructed) Construct ();
581 public static CultureInfo InstalledUICulture {
583 return ConstructCurrentCulture ();
587 public bool IsReadOnly {
595 // IFormatProvider implementation
597 public virtual object GetFormat( Type formatType )
599 object format = null;
601 if ( formatType == typeof(NumberFormatInfo) )
602 format = NumberFormat;
603 else if ( formatType == typeof(DateTimeFormatInfo) )
604 format = DateTimeFormat;
611 construct_internal_locale_from_lcid (cultureID);
615 [MethodImplAttribute (MethodImplOptions.InternalCall)]
616 private extern bool construct_internal_locale_from_lcid (int lcid);
618 [MethodImplAttribute (MethodImplOptions.InternalCall)]
619 private extern bool construct_internal_locale_from_name (string name);
621 [MethodImplAttribute (MethodImplOptions.InternalCall)]
622 private extern static string get_current_locale_name ();
624 [MethodImplAttribute (MethodImplOptions.InternalCall)]
625 private extern static CultureInfo [] internal_get_cultures (bool neutral, bool specific, bool installed);
627 private void ConstructInvariant (bool read_only)
629 cultureID = InvariantCultureId;
631 /* NumberFormatInfo defaults to the invariant data */
632 numInfo=NumberFormatInfo.InvariantInfo;
635 numInfo = (NumberFormatInfo) numInfo.Clone ();
638 textInfo = TextInfo.Invariant;
642 nativename="Invariant Language (Invariant Country)";
646 default_calendar_type = 1 << CalendarTypeBits | (int) GregorianCalendarTypes.Localized;
649 private unsafe TextInfo CreateTextInfo (bool readOnly)
651 TextInfo tempTextInfo = new TextInfo (this.m_cultureData);
652 tempTextInfo.SetReadOnlyState (readOnly);
656 public CultureInfo (int culture) : this (culture, true) {}
658 public CultureInfo (int culture, bool useUserOverride) :
659 this (culture, useUserOverride, false) {}
661 private CultureInfo (int culture, bool useUserOverride, bool read_only)
664 throw new ArgumentOutOfRangeException ("culture", "Positive "
665 + "number required.");
668 m_isReadOnly = read_only;
669 m_useUserOverride = useUserOverride;
671 if (culture == InvariantCultureId) {
672 /* Short circuit the invariant culture */
673 m_cultureData = CultureData.Invariant;
674 ConstructInvariant (read_only);
678 if (!construct_internal_locale_from_lcid (culture)) {
680 // Be careful not to cause recursive CultureInfo initialization
682 var msg = string.Format (InvariantCulture, "Culture ID {0} (0x{1}) is not a supported culture.", culture.ToString (InvariantCulture), culture.ToString ("X4", InvariantCulture));
683 throw new CultureNotFoundException ("culture", msg);
686 var ti = GetTextInfoData ();
687 m_cultureData = CultureData.GetCultureData (m_name, m_useUserOverride, datetime_index, CalendarType, number_index, iso2lang,
688 ti.ansi, ti.oem, ti.mac, ti.ebcdic, ti.right_to_left, ((char)ti.list_sep).ToString ());
691 public CultureInfo (string name) : this (name, true) {}
693 public CultureInfo (string name, bool useUserOverride) :
694 this (name, useUserOverride, false) {}
696 private CultureInfo (string name, bool useUserOverride, bool read_only)
699 throw new ArgumentNullException ("name");
702 m_isReadOnly = read_only;
703 m_useUserOverride = useUserOverride;
704 m_isInherited = GetType() != typeof(System.Globalization.CultureInfo);
706 if (name.Length == 0) {
707 /* Short circuit the invariant culture */
708 m_cultureData = CultureData.Invariant;
709 ConstructInvariant (read_only);
713 if (!construct_internal_locale_from_name (name.ToLowerInvariant ())) {
714 throw CreateNotFoundException (name);
717 var ti = GetTextInfoData ();
718 m_cultureData = CultureData.GetCultureData (m_name, useUserOverride, datetime_index, CalendarType, number_index, iso2lang,
719 ti.ansi, ti.oem, ti.mac, ti.ebcdic, ti.right_to_left, ((char)ti.list_sep).ToString ());
722 // This is used when creating by specific name and creating by
723 // current locale so we can initialize the object without
724 // doing any member initialization
725 private CultureInfo () { constructed = true; }
726 static Dictionary<int, CultureInfo> shared_by_number;
727 static Dictionary<string, CultureInfo> shared_by_name;
729 static void insert_into_shared_tables (CultureInfo c)
731 if (shared_by_number == null){
732 shared_by_number = new Dictionary<int, CultureInfo> ();
733 shared_by_name = new Dictionary<string, CultureInfo> ();
735 shared_by_number [c.cultureID] = c;
736 shared_by_name [c.m_name] = c;
739 public static CultureInfo GetCultureInfo (int culture)
742 throw new ArgumentOutOfRangeException ("culture", "Positive number required.");
746 lock (shared_table_lock){
747 if (shared_by_number != null) {
748 if (shared_by_number.TryGetValue (culture, out c))
752 c = new CultureInfo (culture, false, true);
753 insert_into_shared_tables (c);
758 public static CultureInfo GetCultureInfo (string name)
761 throw new ArgumentNullException ("name");
764 lock (shared_table_lock){
765 if (shared_by_name != null){
766 if (shared_by_name.TryGetValue (name, out c))
769 c = new CultureInfo (name, false, true);
770 insert_into_shared_tables (c);
775 [MonoTODO ("Currently it ignores the altName parameter")]
776 public static CultureInfo GetCultureInfo (string name, string altName) {
778 throw new ArgumentNullException ("null");
780 throw new ArgumentNullException ("null");
782 return GetCultureInfo (name);
785 public static CultureInfo GetCultureInfoByIetfLanguageTag (string name)
787 // There could be more consistent way to implement
788 // it, but right now it works just fine with this...
791 return GetCultureInfo ("zh-CHS");
793 return GetCultureInfo ("zh-CHT");
795 return GetCultureInfo (name);
799 // used in runtime (icall.c) to construct CultureInfo for
800 // AssemblyName of assemblies
801 internal static CultureInfo CreateCulture (string name, bool reference)
804 bool use_user_override;
806 bool invariant = name.Length == 0;
808 use_user_override = invariant ? false : true;
812 use_user_override = invariant ? false : true;
815 return new CultureInfo (name, use_user_override, read_only);
818 public static CultureInfo CreateSpecificCulture (string name)
821 throw new ArgumentNullException ("name");
823 if (name.Length == 0)
824 return InvariantCulture;
827 name = name.ToLowerInvariant ();
828 CultureInfo ci = new CultureInfo ();
830 if (!ci.construct_internal_locale_from_name (name)) {
831 int idx = name.Length - 1;
833 while ((idx = name.LastIndexOf ('-', idx - 1)) > 0) {
834 if (ci.construct_internal_locale_from_name (name.Substring (0, idx)))
840 throw CreateNotFoundException (src_name);
843 if (ci.IsNeutralCulture)
844 ci = CreateSpecificCultureFromNeutral (ci.Name);
846 var ti = ci.GetTextInfoData ();
848 ci.m_cultureData = CultureData.GetCultureData (ci.m_name, false, ci.datetime_index, ci.CalendarType, ci.number_index, ci.iso2lang,
849 ti.ansi, ti.oem, ti.mac, ti.ebcdic, ti.right_to_left, ((char)ti.list_sep).ToString ());
854 // Creates specific culture from neutral culture. Used by CreateSpecificCulture
855 // only but using separate method we can delay switch underlying Dictionary
858 static CultureInfo CreateSpecificCultureFromNeutral (string name)
863 // For neutral cultures find predefined default specific culture
865 // Use managed switch because we need this for only some cultures
866 // and the method is not used frequently
868 // TODO: We could optimize for cultures with single specific culture
870 switch (name.ToLowerInvariant ()) {
871 case "af": id = 1078; break;
872 case "am": id = 1118; break;
873 case "ar": id = 1025; break;
874 case "arn": id = 1146; break;
875 case "as": id = 1101; break;
876 case "az": id = 1068; break;
877 case "az-cyrl": id = 2092; break;
878 case "az-latn": id = 1068; break;
879 case "ba": id = 1133; break;
880 case "be": id = 1059; break;
881 case "bg": id = 1026; break;
882 case "bn": id = 1093; break;
883 case "bo": id = 1105; break;
884 case "br": id = 1150; break;
885 case "bs": id = 5146; break;
886 case "bs-cyrl": id = 8218; break;
887 case "bs-latn": id = 5146; break;
888 case "ca": id = 1027; break;
889 case "co": id = 1155; break;
890 case "cs": id = 1029; break;
891 case "cy": id = 1106; break;
892 case "da": id = 1030; break;
893 case "de": id = 1031; break;
894 case "dsb": id = 2094; break;
895 case "dv": id = 1125; break;
896 case "el": id = 1032; break;
897 case "en": id = 1033; break;
898 case "es": id = 3082; break;
899 case "et": id = 1061; break;
900 case "eu": id = 1069; break;
901 case "fa": id = 1065; break;
902 case "fi": id = 1035; break;
903 case "fil": id = 1124; break;
904 case "fo": id = 1080; break;
905 case "fr": id = 1036; break;
906 case "fy": id = 1122; break;
907 case "ga": id = 2108; break;
908 case "gd": id = 1169; break;
909 case "gl": id = 1110; break;
910 case "gsw": id = 1156; break;
911 case "gu": id = 1095; break;
912 case "ha": id = 1128; break;
913 case "ha-latn": id = 1128; break;
914 case "he": id = 1037; break;
915 case "hi": id = 1081; break;
916 case "hr": id = 1050; break;
917 case "hsb": id = 1070; break;
918 case "hu": id = 1038; break;
919 case "hy": id = 1067; break;
920 case "id": id = 1057; break;
921 case "ig": id = 1136; break;
922 case "ii": id = 1144; break;
923 case "is": id = 1039; break;
924 case "it": id = 1040; break;
925 case "iu": id = 2141; break;
926 case "iu-cans": id = 1117; break;
927 case "iu-latn": id = 2141; break;
928 case "ja": id = 1041; break;
929 case "ka": id = 1079; break;
930 case "kk": id = 1087; break;
931 case "kl": id = 1135; break;
932 case "km": id = 1107; break;
933 case "kn": id = 1099; break;
934 case "ko": id = 1042; break;
935 case "kok": id = 1111; break;
936 case "ky": id = 1088; break;
937 case "lb": id = 1134; break;
938 case "lo": id = 1108; break;
939 case "lt": id = 1063; break;
940 case "lv": id = 1062; break;
941 case "mi": id = 1153; break;
942 case "mk": id = 1071; break;
943 case "ml": id = 1100; break;
944 case "mn": id = 1104; break;
945 case "mn-cyrl": id = 1104; break;
946 case "mn-mong": id = 2128; break;
947 case "moh": id = 1148; break;
948 case "mr": id = 1102; break;
949 case "ms": id = 1086; break;
950 case "mt": id = 1082; break;
951 case "nb": id = 1044; break;
952 case "ne": id = 1121; break;
953 case "nl": id = 1043; break;
954 case "nn": id = 2068; break;
955 case "no": id = 1044; break;
956 case "nso": id = 1132; break;
957 case "oc": id = 1154; break;
958 case "or": id = 1096; break;
959 case "pa": id = 1094; break;
960 case "pl": id = 1045; break;
961 case "prs": id = 1164; break;
962 case "ps": id = 1123; break;
963 case "pt": id = 1046; break;
964 case "qut": id = 1158; break;
965 case "quz": id = 1131; break;
966 case "rm": id = 1047; break;
967 case "ro": id = 1048; break;
968 case "ru": id = 1049; break;
969 case "rw": id = 1159; break;
970 case "sa": id = 1103; break;
971 case "sah": id = 1157; break;
972 case "se": id = 1083; break;
973 case "si": id = 1115; break;
974 case "sk": id = 1051; break;
975 case "sl": id = 1060; break;
976 case "sma": id = 7227; break;
977 case "smj": id = 5179; break;
978 case "smn": id = 9275; break;
979 case "sms": id = 8251; break;
980 case "sq": id = 1052; break;
981 case "sr": id = 9242; break;
982 case "sr-cyrl": id = 10266; break;
983 case "sr-latn": id = 9242; break;
984 case "sv": id = 1053; break;
985 case "sw": id = 1089; break;
986 case "syr": id = 1114; break;
987 case "ta": id = 1097; break;
988 case "te": id = 1098; break;
989 case "tg": id = 1064; break;
990 case "tg-cyrl": id = 1064; break;
991 case "th": id = 1054; break;
992 case "tk": id = 1090; break;
993 case "tn": id = 1074; break;
994 case "tr": id = 1055; break;
995 case "tt": id = 1092; break;
996 case "tzm": id = 2143; break;
997 case "tzm-latn": id = 2143; break;
998 case "ug": id = 1152; break;
999 case "uk": id = 1058; break;
1000 case "ur": id = 1056; break;
1001 case "uz": id = 1091; break;
1002 case "uz-cyrl": id = 2115; break;
1003 case "uz-latn": id = 1091; break;
1004 case "vi": id = 1066; break;
1005 case "wo": id = 1160; break;
1006 case "xh": id = 1076; break;
1007 case "yo": id = 1130; break;
1008 case "zh": id = 2052; break;
1015 case "zu": id = 1077; break;
1017 throw new NotImplementedException ("Mapping for neutral culture " + name);
1020 return new CultureInfo (id);
1023 internal int CalendarType {
1025 switch (default_calendar_type >> CalendarTypeBits) {
1027 return Calendar.CAL_GREGORIAN;
1029 return Calendar.CAL_THAI;
1031 return Calendar.CAL_UMALQURA;
1033 return Calendar.CAL_HIJRI;
1035 throw new NotImplementedException ("CalendarType");
1040 static Calendar CreateCalendar (int calendarType)
1043 switch (calendarType >> CalendarTypeBits) {
1045 GregorianCalendarTypes greg_type;
1046 greg_type = (GregorianCalendarTypes) (calendarType & 0xFF);
1047 return new GregorianCalendar (greg_type);
1049 name = "System.Globalization.ThaiBuddhistCalendar";
1052 name = "System.Globalization.UmAlQuraCalendar";
1055 name = "System.Globalization.HijriCalendar";
1058 throw new NotImplementedException ("Unknown calendar type: " + calendarType);
1061 Type type = Type.GetType (name, false);
1063 return new GregorianCalendar (GregorianCalendarTypes.Localized); // return invariant calendar if not found
1064 return (Calendar) Activator.CreateInstance (type);
1067 static Exception CreateNotFoundException (string name)
1069 return new CultureNotFoundException ("name", "Culture name " + name + " is not supported.");
1072 public static CultureInfo DefaultThreadCurrentCulture {
1074 return s_DefaultThreadCurrentCulture;
1077 s_DefaultThreadCurrentCulture = value;
1081 public static CultureInfo DefaultThreadCurrentUICulture {
1083 return s_DefaultThreadCurrentUICulture;
1086 s_DefaultThreadCurrentUICulture = value;
1090 internal string SortName {
1096 internal static CultureInfo UserDefaultUICulture {
1098 return ConstructCurrentUICulture ();
1102 internal static CultureInfo UserDefaultCulture {
1104 return ConstructCurrentCulture ();
1109 #region reference sources
1111 internal static readonly bool IsTaiwanSku;
1114 // CheckDomainSafetyObject throw if the object is customized object which cannot be attached to
1115 // other object (like CultureInfo or DateTimeFormatInfo).
1118 internal static void CheckDomainSafetyObject(Object obj, Object container)
1120 if (obj.GetType().Assembly != typeof(System.Globalization.CultureInfo).Assembly) {
1122 throw new InvalidOperationException(
1124 CultureInfo.CurrentCulture,
1125 Environment.GetResourceString("InvalidOperation_SubclassedObject"),
1127 container.GetType()));
1129 Contract.EndContractBlock();
1132 // For resource lookup, we consider a culture the invariant culture by name equality.
1133 // We perform this check frequently during resource lookup, so adding a property for
1134 // improved readability.
1135 internal bool HasInvariantCultureName
1137 get { return Name == CultureInfo.InvariantCulture.Name; }
1140 internal static bool VerifyCultureName(String cultureName, bool throwException)
1142 // This function is used by ResourceManager.GetResourceFileName().
1143 // ResourceManager searches for resource using CultureInfo.Name,
1144 // so we should check against CultureInfo.Name.
1146 for (int i=0; i<cultureName.Length; i++) {
1147 char c = cultureName[i];
1150 if (Char.IsLetterOrDigit(c) || c=='-' || c=='_') {
1153 if (throwException) {
1154 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidResourceCultureName", cultureName));
1161 internal static bool VerifyCultureName(CultureInfo culture, bool throwException) {
1162 Contract.Assert(culture!=null, "[CultureInfo.VerifyCultureName]culture!=null");
1164 //If we have an instance of one of our CultureInfos, the user can't have changed the
1165 //name and we know that all names are valid in files.
1166 if (!culture.m_isInherited) {
1170 return VerifyCultureName(culture.Name, throwException);