summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Globalization/CultureData.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Globalization/CultureData.cs')
-rw-r--r--src/mscorlib/src/System/Globalization/CultureData.cs2503
1 files changed, 1106 insertions, 1397 deletions
diff --git a/src/mscorlib/src/System/Globalization/CultureData.cs b/src/mscorlib/src/System/Globalization/CultureData.cs
index a93b7d43bb..0dcebf484b 100644
--- a/src/mscorlib/src/System/Globalization/CultureData.cs
+++ b/src/mscorlib/src/System/Globalization/CultureData.cs
@@ -2,20 +2,23 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+using System.Threading;
+
namespace System.Globalization
{
-
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
- using System.Runtime.Versioning;
- using System.Diagnostics;
- using System.Diagnostics.Contracts;
- using System.Security;
+#if CORECLR
+ using StringStringDictionary = Dictionary<string, string>;
+ using StringCultureDataDictionary = Dictionary<string, CultureData>;
+ using LcidToCultureNameDictionary = Dictionary<int, string>;
+ using Lock = Object;
+#else
+ using StringStringDictionary = LowLevelDictionary<string, string>;
+ using StringCultureDataDictionary = LowLevelDictionary<string, CultureData>;
+ using LcidToCultureNameDictionary = LowLevelDictionary<int, string>;
+#endif
//
// List of culture data
@@ -48,504 +51,263 @@ namespace System.Globalization
// en if you pass in en
// de-DE if you pass in de-DE_phoneb
//
-
- // StructLayout is needed here otherwise compiler can re-arrange the fields.
- // We have to keep this in-sync with the definition in comnlsinfo.h
- //
- // WARNING WARNING WARNING
- //
- // WARNING: Anything changed here also needs to be updated on the native side (object.h see type CultureDataBaseObject)
- // WARNING: The type loader will rearrange class member offsets so the mscorwks!CultureDataBaseObject
- // WARNING: must be manually structured to match the true loaded class layout
- //
- [FriendAccessAllowed]
- internal class CultureData
+ internal partial class CultureData
{
- const int undef = -1;
+ private const int LOCALE_NAME_MAX_LENGTH = 85;
+ private const int undef = -1;
// Override flag
- private String sRealName; // Name you passed in (ie: en-US, en, or de-DE_phoneb)
- private String sWindowsName; // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in))
+ private String _sRealName; // Name you passed in (ie: en-US, en, or de-DE_phoneb)
+ private String _sWindowsName; // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in))
// Identity
- private String sName; // locale name (ie: en-us, NO sort info, but could be neutral)
- private String sParent; // Parent name (which may be a custom locale/culture)
- private String sLocalizedDisplayName; // Localized pretty name for this locale
- private String sEnglishDisplayName; // English pretty name for this locale
- private String sNativeDisplayName; // Native pretty name for this locale
- private String sSpecificCulture; // The culture name to be used in CultureInfo.CreateSpecificCulture(), en-US form if neutral, sort name if sort
+ private String _sName; // locale name (ie: en-us, NO sort info, but could be neutral)
+ private String _sParent; // Parent name (which may be a custom locale/culture)
+ private String _sLocalizedDisplayName; // Localized pretty name for this locale
+ private String _sEnglishDisplayName; // English pretty name for this locale
+ private String _sNativeDisplayName; // Native pretty name for this locale
+ private String _sSpecificCulture; // The culture name to be used in CultureInfo.CreateSpecificCulture(), en-US form if neutral, sort name if sort
// Language
- private String sISO639Language; // ISO 639 Language Name
- private String sLocalizedLanguage; // Localized name for this language
- private String sEnglishLanguage; // English name for this language
- private String sNativeLanguage; // Native name of this language
+ private String _sISO639Language; // ISO 639 Language Name
+ private String _sISO639Language2; // ISO 639 Language Name
+ private String _sLocalizedLanguage; // Localized name for this language
+ private String _sEnglishLanguage; // English name for this language
+ private String _sNativeLanguage; // Native name of this language
+ private String _sAbbrevLang; // abbreviated language name (Windows Language Name) ex: ENU
+ private string _sConsoleFallbackName; // The culture name for the console fallback UI culture
+ private int _iInputLanguageHandle=undef;// input language handle
// Region
- private String sRegionName; // (RegionInfo)
- private int iGeoId = undef; // GeoId
- private String sLocalizedCountry; // localized country name
- private String sEnglishCountry; // english country name (RegionInfo)
- private String sNativeCountry; // native country name
- private String sISO3166CountryName; // ISO 3166 (RegionInfo), ie: US
+ private String _sRegionName; // (RegionInfo)
+ private String _sLocalizedCountry; // localized country name
+ private String _sEnglishCountry; // english country name (RegionInfo)
+ private String _sNativeCountry; // native country name
+ private String _sISO3166CountryName; // ISO 3166 (RegionInfo), ie: US
+ private String _sISO3166CountryName2; // 3 char ISO 3166 country name 2 2(RegionInfo) ex: USA (ISO)
+ private int _iGeoId = undef; // GeoId
// Numbers
- private String sPositiveSign; // (user can override) positive sign
- private String sNegativeSign; // (user can override) negative sign
- private String[] saNativeDigits; // (user can override) native characters for digits 0-9
+ private String _sPositiveSign; // (user can override) positive sign
+ private String _sNegativeSign; // (user can override) negative sign
// (nfi populates these 5, don't have to be = undef)
- private int iDigitSubstitution; // (user can override) Digit substitution 0=context, 1=none/arabic, 2=Native/national (2 seems to be unused)
- private int iLeadingZeros; // (user can override) leading zeros 0 = no leading zeros, 1 = leading zeros
- private int iDigits; // (user can override) number of fractional digits
- private int iNegativeNumber; // (user can override) negative number format
- private int[] waGrouping; // (user can override) grouping of digits
- private String sDecimalSeparator; // (user can override) decimal separator
- private String sThousandSeparator; // (user can override) thousands separator
- private String sNaN; // Not a Number
- private String sPositiveInfinity; // + Infinity
- private String sNegativeInfinity; // - Infinity
+ private int _iDigits; // (user can override) number of fractional digits
+ private int _iNegativeNumber; // (user can override) negative number format
+ private int[] _waGrouping; // (user can override) grouping of digits
+ private String _sDecimalSeparator; // (user can override) decimal separator
+ private String _sThousandSeparator; // (user can override) thousands separator
+ private String _sNaN; // Not a Number
+ private String _sPositiveInfinity; // + Infinity
+ private String _sNegativeInfinity; // - Infinity
// Percent
- private int iNegativePercent = undef; // Negative Percent (0-3)
- private int iPositivePercent = undef; // Positive Percent (0-11)
- private String sPercent; // Percent (%) symbol
- private String sPerMille; // PerMille (‰) symbol
+ private int _iNegativePercent = undef; // Negative Percent (0-3)
+ private int _iPositivePercent = undef; // Positive Percent (0-11)
+ private String _sPercent; // Percent (%) symbol
+ private String _sPerMille; // PerMille symbol
// Currency
- private String sCurrency; // (user can override) local monetary symbol
- private String sIntlMonetarySymbol; // international monetary symbol (RegionInfo)
- private String sEnglishCurrency; // English name for this currency
- private String sNativeCurrency; // Native name for this currency
+ private String _sCurrency; // (user can override) local monetary symbol
+ private String _sIntlMonetarySymbol; // international monetary symbol (RegionInfo)
+ private String _sEnglishCurrency; // English name for this currency
+ private String _sNativeCurrency; // Native name for this currency
// (nfi populates these 4, don't have to be = undef)
- private int iCurrencyDigits; // (user can override) # local monetary fractional digits
- private int iCurrency; // (user can override) positive currency format
- private int iNegativeCurrency; // (user can override) negative currency format
- private int[] waMonetaryGrouping; // (user can override) monetary grouping of digits
- private String sMonetaryDecimal; // (user can override) monetary decimal separator
- private String sMonetaryThousand; // (user can override) monetary thousands separator
+ private int _iCurrencyDigits; // (user can override) # local monetary fractional digits
+ private int _iCurrency; // (user can override) positive currency format
+ private int _iNegativeCurrency; // (user can override) negative currency format
+ private int[] _waMonetaryGrouping; // (user can override) monetary grouping of digits
+ private String _sMonetaryDecimal; // (user can override) monetary decimal separator
+ private String _sMonetaryThousand; // (user can override) monetary thousands separator
// Misc
- private int iMeasure = undef; // (user can override) system of measurement 0=metric, 1=US (RegionInfo)
- private String sListSeparator; // (user can override) list separator
- // private int iPaperSize ; // default paper size (RegionInfo)
+ private int _iMeasure = undef; // (user can override) system of measurement 0=metric, 1=US (RegionInfo)
+ private String _sListSeparator; // (user can override) list separator
// Time
- private String sAM1159; // (user can override) AM designator
- private String sPM2359; // (user can override) PM designator
- private String sTimeSeparator;
- private volatile String[] saLongTimes; // (user can override) time format
- private volatile String[] saShortTimes; // short time format
- private volatile String[] saDurationFormats; // time duration format
+ private String _sAM1159; // (user can override) AM designator
+ private String _sPM2359; // (user can override) PM designator
+ private String _sTimeSeparator;
+ private volatile String[] _saLongTimes; // (user can override) time format
+ private volatile String[] _saShortTimes; // short time format
+ private volatile String[] _saDurationFormats; // time duration format
// Calendar specific data
- private int iFirstDayOfWeek = undef; // (user can override) first day of week (gregorian really)
- private int iFirstWeekOfYear = undef; // (user can override) first week of year (gregorian really)
- private volatile int[] waCalendars; // all available calendar type(s). The first one is the default calendar
+ private int _iFirstDayOfWeek = undef; // (user can override) first day of week (gregorian really)
+ private int _iFirstWeekOfYear = undef; // (user can override) first week of year (gregorian really)
+ private volatile CalendarId[] _waCalendars; // all available calendar type(s). The first one is the default calendar
// Store for specific data about each calendar
- private CalendarData[] calendars; // Store for specific calendar data
+ private CalendarData[] _calendars; // Store for specific calendar data
// Text information
- private int iReadingLayout = undef; // Reading layout data
+ private int _iReadingLayout = undef; // Reading layout data
// 0 - Left to right (eg en-US)
// 1 - Right to left (eg arabic locales)
// 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
// 3 - Vertical top to bottom with columns proceeding to the right
- private String sTextInfo; // Text info name to use for custom
- private String sCompareInfo; // Compare info name (including sorting key) to use if custom
- private String sScripts; // Typical Scripts for this locale (latn;cyrl; etc)
-
- private int iDefaultAnsiCodePage = undef; // default ansi code page ID (ACP)
- private int iDefaultOemCodePage = undef; // default oem code page ID (OCP or OEM)
- private int iDefaultMacCodePage = undef; // default macintosh code page
- private int iDefaultEbcdicCodePage = undef; // default EBCDIC code page
-
- // These are desktop only, not coreclr
- private int iLanguage; // locale ID (0409) - NO sort information
- private String sAbbrevLang; // abbreviated language name (Windows Language Name) ex: ENU
- private String sAbbrevCountry; // abbreviated country name (RegionInfo) (Windows Region Name) ex: USA
- private String sISO639Language2; // 3 char ISO 639 lang name 2 ex: eng
- private String sISO3166CountryName2; // 3 char ISO 3166 country name 2 2(RegionInfo) ex: USA (ISO)
- private int iInputLanguageHandle=undef;// input language handle
- private String sConsoleFallbackName; // The culture name for the console fallback UI culture
- private String sKeyboardsToInstall; // Keyboard installation string.
- private String fontSignature; // Font signature (16 WORDS)
-
- // The bools all need to be in one spot
- private bool bUseOverrides; // use user overrides?
- private bool bNeutral; // Flags for the culture (ie: neutral or not right now)
- private bool bWin32Installed; // Flags indicate if the culture is Win32 installed
- private bool bFramework; // Flags for indicate if the culture is one of Whidbey cultures
+ // CoreCLR depends on this even though its not exposed publicly.
+
+ private int _iDefaultAnsiCodePage = undef; // default ansi code page ID (ACP)
+ private int _iDefaultOemCodePage = undef; // default oem code page ID (OCP or OEM)
+ private int _iDefaultMacCodePage = undef; // default macintosh code page
+ private int _iDefaultEbcdicCodePage = undef; // default EBCDIC code page
+
+ private int _iLanguage; // locale ID (0409) - NO sort information
+ private bool _bUseOverrides; // use user overrides?
+ private bool _bNeutral; // Flags for the culture (ie: neutral or not right now)
// Region Name to Culture Name mapping table
// (In future would be nice to be in registry or something)
- //Using a property so we avoid creating the dictionary untill we need it
- private static Dictionary<string, string> RegionNames
+ //Using a property so we avoid creating the dictionary until we need it
+ private static StringStringDictionary RegionNames
{
- get
+ get
{
if (s_RegionNames == null)
{
- var regionNames = new Dictionary<string, string> {
- { "029", "en-029" },
- { "AE", "ar-AE" },
- { "AF", "prs-AF" },
- { "AL", "sq-AL" },
- { "AM", "hy-AM" },
- { "AR", "es-AR" },
- { "AT", "de-AT" },
- { "AU", "en-AU" },
- { "AZ", "az-Cyrl-AZ" },
- { "BA", "bs-Latn-BA" },
- { "BD", "bn-BD" },
- { "BE", "nl-BE" },
- { "BG", "bg-BG" },
- { "BH", "ar-BH" },
- { "BN", "ms-BN" },
- { "BO", "es-BO" },
- { "BR", "pt-BR" },
- { "BY", "be-BY" },
- { "BZ", "en-BZ" },
- { "CA", "en-CA" },
- { "CH", "it-CH" },
- { "CL", "es-CL" },
- { "CN", "zh-CN" },
- { "CO", "es-CO" },
- { "CR", "es-CR" },
- { "CS", "sr-Cyrl-CS" },
- { "CZ", "cs-CZ" },
- { "DE", "de-DE" },
- { "DK", "da-DK" },
- { "DO", "es-DO" },
- { "DZ", "ar-DZ" },
- { "EC", "es-EC" },
- { "EE", "et-EE" },
- { "EG", "ar-EG" },
- { "ES", "es-ES" },
- { "ET", "am-ET" },
- { "FI", "fi-FI" },
- { "FO", "fo-FO" },
- { "FR", "fr-FR" },
- { "GB", "en-GB" },
- { "GE", "ka-GE" },
- { "GL", "kl-GL" },
- { "GR", "el-GR" },
- { "GT", "es-GT" },
- { "HK", "zh-HK" },
- { "HN", "es-HN" },
- { "HR", "hr-HR" },
- { "HU", "hu-HU" },
- { "ID", "id-ID" },
- { "IE", "en-IE" },
- { "IL", "he-IL" },
- { "IN", "hi-IN" },
- { "IQ", "ar-IQ" },
- { "IR", "fa-IR" },
- { "IS", "is-IS" },
- { "IT", "it-IT" },
- { "IV", "" },
- { "JM", "en-JM" },
- { "JO", "ar-JO" },
- { "JP", "ja-JP" },
- { "KE", "sw-KE" },
- { "KG", "ky-KG" },
- { "KH", "km-KH" },
- { "KR", "ko-KR" },
- { "KW", "ar-KW" },
- { "KZ", "kk-KZ" },
- { "LA", "lo-LA" },
- { "LB", "ar-LB" },
- { "LI", "de-LI" },
- { "LK", "si-LK" },
- { "LT", "lt-LT" },
- { "LU", "lb-LU" },
- { "LV", "lv-LV" },
- { "LY", "ar-LY" },
- { "MA", "ar-MA" },
- { "MC", "fr-MC" },
- { "ME", "sr-Latn-ME" },
- { "MK", "mk-MK" },
- { "MN", "mn-MN" },
- { "MO", "zh-MO" },
- { "MT", "mt-MT" },
- { "MV", "dv-MV" },
- { "MX", "es-MX" },
- { "MY", "ms-MY" },
- { "NG", "ig-NG" },
- { "NI", "es-NI" },
- { "NL", "nl-NL" },
- { "NO", "nn-NO" },
- { "NP", "ne-NP" },
- { "NZ", "en-NZ" },
- { "OM", "ar-OM" },
- { "PA", "es-PA" },
- { "PE", "es-PE" },
- { "PH", "en-PH" },
- { "PK", "ur-PK" },
- { "PL", "pl-PL" },
- { "PR", "es-PR" },
- { "PT", "pt-PT" },
- { "PY", "es-PY" },
- { "QA", "ar-QA" },
- { "RO", "ro-RO" },
- { "RS", "sr-Latn-RS" },
- { "RU", "ru-RU" },
- { "RW", "rw-RW" },
- { "SA", "ar-SA" },
- { "SE", "sv-SE" },
- { "SG", "zh-SG" },
- { "SI", "sl-SI" },
- { "SK", "sk-SK" },
- { "SN", "wo-SN" },
- { "SV", "es-SV" },
- { "SY", "ar-SY" },
- { "TH", "th-TH" },
- { "TJ", "tg-Cyrl-TJ" },
- { "TM", "tk-TM" },
- { "TN", "ar-TN" },
- { "TR", "tr-TR" },
- { "TT", "en-TT" },
- { "TW", "zh-TW" },
- { "UA", "uk-UA" },
- { "US", "en-US" },
- { "UY", "es-UY" },
- { "UZ", "uz-Cyrl-UZ" },
- { "VE", "es-VE" },
- { "VN", "vi-VN" },
- { "YE", "ar-YE" },
- { "ZA", "af-ZA" },
- { "ZW", "en-ZW" }
- };
- s_RegionNames = regionNames;
- }
- return s_RegionNames;
- }
- }
- private volatile static Dictionary<string, string> s_RegionNames;
-
- /////////////////////////////////////////////////////////////////////////
- // Build our invariant information
- //
- // We need an invariant instance, which we build hard-coded
- /////////////////////////////////////////////////////////////////////////
- internal static CultureData Invariant
- {
- get
- {
- if (s_Invariant == null)
- {
- // Make a new culturedata
- CultureData invariant = new CultureData();
-
- // Call the native code to get the value of bWin32Installed.
- // For versions <= Vista, we set this to false for compatibility with v2.
- // For Windows 7, the flag is true.
- invariant.bUseOverrides = false;
- invariant.sRealName = "";
-
- // Ask the native code to fill it out for us, we only need the field IsWin32Installed
- nativeInitCultureData(invariant);
-
- // Basics
- // Note that we override the resources since this IS NOT supposed to change (by definition)
- invariant.bUseOverrides = false;
- invariant.sRealName = ""; // Name you passed in (ie: en-US, en, or de-DE_phoneb)
- invariant.sWindowsName = ""; // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in))
-
- // Identity
- invariant.sName = ""; // locale name (ie: en-us)
- invariant.sParent = ""; // Parent name (which may be a custom locale/culture)
- invariant.bNeutral = false; // Flags for the culture (ie: neutral or not right now)
- // Don't set invariant.bWin32Installed, we used nativeInitCultureData for that.
- invariant.bFramework = true;
-
- invariant.sEnglishDisplayName = "Invariant Language (Invariant Country)"; // English pretty name for this locale
- invariant.sNativeDisplayName = "Invariant Language (Invariant Country)"; // Native pretty name for this locale
- invariant.sSpecificCulture = ""; // The culture name to be used in CultureInfo.CreateSpecificCulture()
-
- // Language
- invariant.sISO639Language = "iv"; // ISO 639 Language Name
- invariant.sLocalizedLanguage = "Invariant Language"; // Display name for this Language
- invariant.sEnglishLanguage = "Invariant Language"; // English name for this language
- invariant.sNativeLanguage = "Invariant Language"; // Native name of this language
-
- // Region
- invariant.sRegionName = "IV"; // (RegionInfo)
- // Unused for now:
- // invariant.iCountry =1; // country code (RegionInfo)
- invariant.iGeoId = 244; // GeoId (Windows Only)
- invariant.sEnglishCountry = "Invariant Country"; // english country name (RegionInfo)
- invariant.sNativeCountry = "Invariant Country"; // native country name (Windows Only)
- invariant.sISO3166CountryName = "IV"; // (RegionInfo), ie: US
-
- // Numbers
- invariant.sPositiveSign = "+"; // positive sign
- invariant.sNegativeSign = "-"; // negative sign
- invariant.saNativeDigits = new String[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; // native characters for digits 0-9
- invariant.iDigitSubstitution = 1; // Digit substitution 0=context, 1=none/arabic, 2=Native/national (2 seems to be unused) (Windows Only)
- invariant.iLeadingZeros = 1; // leading zeros 0=no leading zeros, 1=leading zeros
- invariant.iDigits = 2; // number of fractional digits
- invariant.iNegativeNumber = 1; // negative number format
- invariant.waGrouping = new int[] { 3 }; // grouping of digits
- invariant.sDecimalSeparator = "."; // decimal separator
- invariant.sThousandSeparator = ","; // thousands separator
- invariant.sNaN = "NaN"; // Not a Number
- invariant.sPositiveInfinity = "Infinity"; // + Infinity
- invariant.sNegativeInfinity = "-Infinity"; // - Infinity
-
- // Percent
- invariant.iNegativePercent = 0; // Negative Percent (0-3)
- invariant.iPositivePercent = 0; // Positive Percent (0-11)
- invariant.sPercent = "%"; // Percent (%) symbol
- invariant.sPerMille = "\x2030"; // PerMille(‰) symbol
-
- // Currency
- invariant.sCurrency = "\x00a4"; // local monetary symbol "¤: for international monetary symbol
- invariant.sIntlMonetarySymbol = "XDR"; // international monetary symbol (RegionInfo)
- invariant.sEnglishCurrency = "International Monetary Fund"; // English name for this currency (Windows Only)
- invariant.sNativeCurrency = "International Monetary Fund"; // Native name for this currency (Windows Only)
- invariant.iCurrencyDigits = 2; // # local monetary fractional digits
- invariant.iCurrency = 0; // positive currency format
- invariant.iNegativeCurrency = 0; // negative currency format
- invariant.waMonetaryGrouping = new int[] { 3 }; // monetary grouping of digits
- invariant.sMonetaryDecimal = "."; // monetary decimal separator
- invariant.sMonetaryThousand = ","; // monetary thousands separator
-
- // Misc
- invariant.iMeasure = 0; // system of measurement 0=metric, 1=US (RegionInfo)
- invariant.sListSeparator = ","; // list separator
- // Unused for now:
- // invariant.iPaperSize =9; // default paper size (RegionInfo)
- // invariant.waFontSignature ="\x0002\x0000\x0000\x0000\x0000\x0000\x0000\x8000\x0001\x0000\x0000\x8000\x0001\x0000\x0000\x8000"; // Font signature (16 WORDS) (Windows Only)
-
- // Time
- invariant.sAM1159 = "AM"; // AM designator
- invariant.sPM2359 = "PM"; // PM designator
- invariant.saLongTimes = new String[] { "HH:mm:ss" }; // time format
- invariant.saShortTimes = new String[] { "HH:mm", "hh:mm tt", "H:mm", "h:mm tt" }; // short time format
- invariant.saDurationFormats = new String[] { "HH:mm:ss" }; // time duration format
-
- // Calendar specific data
- invariant.iFirstDayOfWeek = 0; // first day of week
- invariant.iFirstWeekOfYear = 0; // first week of year
- invariant.waCalendars = new int[] { (int)CalendarId.GREGORIAN }; // all available calendar type(s). The first one is the default calendar
-
- // Store for specific data about each calendar
- invariant.calendars = new CalendarData[CalendarData.MAX_CALENDARS];
- invariant.calendars[0] = CalendarData.Invariant;
-
- // Text information
- invariant.iReadingLayout = 0; // Reading Layout = RTL
-
- invariant.sTextInfo = ""; // Text info name to use for custom
- invariant.sCompareInfo = ""; // Compare info name (including sorting key) to use if custom
- invariant.sScripts = "Latn;"; // Typical Scripts for this locale (latn,cyrl, etc)
-
- invariant.iLanguage = 0x007f; // locale ID (0409) - NO sort information
- invariant.iDefaultAnsiCodePage = 1252; // default ansi code page ID (ACP)
- invariant.iDefaultOemCodePage = 437; // default oem code page ID (OCP or OEM)
- invariant.iDefaultMacCodePage = 10000; // default macintosh code page
- invariant.iDefaultEbcdicCodePage = 037; // default EBCDIC code page
- invariant.sAbbrevLang = "IVL"; // abbreviated language name (Windows Language Name)
- invariant.sAbbrevCountry = "IVC"; // abbreviated country name (RegionInfo) (Windows Region Name)
- invariant.sISO639Language2 = "ivl"; // 3 char ISO 639 lang name 2
- invariant.sISO3166CountryName2 = "ivc"; // 3 char ISO 3166 country name 2 2(RegionInfo)
- invariant.iInputLanguageHandle = 0x007f; // input language handle
- invariant.sConsoleFallbackName = ""; // The culture name for the console fallback UI culture
- invariant.sKeyboardsToInstall = "0409:00000409"; // Keyboard installation string.
- // Remember it
- s_Invariant = invariant;
+ StringStringDictionary regionNames = new StringStringDictionary(211 /* prime */);
+
+ regionNames.Add("029", "en-029");
+ regionNames.Add("AE", "ar-AE");
+ regionNames.Add("AF", "prs-AF");
+ regionNames.Add("AL", "sq-AL");
+ regionNames.Add("AM", "hy-AM");
+ regionNames.Add("AR", "es-AR");
+ regionNames.Add("AT", "de-AT");
+ regionNames.Add("AU", "en-AU");
+ regionNames.Add("AZ", "az-Cyrl-AZ");
+ regionNames.Add("BA", "bs-Latn-BA");
+ regionNames.Add("BD", "bn-BD");
+ regionNames.Add("BE", "nl-BE");
+ regionNames.Add("BG", "bg-BG");
+ regionNames.Add("BH", "ar-BH");
+ regionNames.Add("BN", "ms-BN");
+ regionNames.Add("BO", "es-BO");
+ regionNames.Add("BR", "pt-BR");
+ regionNames.Add("BY", "be-BY");
+ regionNames.Add("BZ", "en-BZ");
+ regionNames.Add("CA", "en-CA");
+ regionNames.Add("CH", "it-CH");
+ regionNames.Add("CL", "es-CL");
+ regionNames.Add("CN", "zh-CN");
+ regionNames.Add("CO", "es-CO");
+ regionNames.Add("CR", "es-CR");
+ regionNames.Add("CS", "sr-Cyrl-CS");
+ regionNames.Add("CZ", "cs-CZ");
+ regionNames.Add("DE", "de-DE");
+ regionNames.Add("DK", "da-DK");
+ regionNames.Add("DO", "es-DO");
+ regionNames.Add("DZ", "ar-DZ");
+ regionNames.Add("EC", "es-EC");
+ regionNames.Add("EE", "et-EE");
+ regionNames.Add("EG", "ar-EG");
+ regionNames.Add("ES", "es-ES");
+ regionNames.Add("ET", "am-ET");
+ regionNames.Add("FI", "fi-FI");
+ regionNames.Add("FO", "fo-FO");
+ regionNames.Add("FR", "fr-FR");
+ regionNames.Add("GB", "en-GB");
+ regionNames.Add("GE", "ka-GE");
+ regionNames.Add("GL", "kl-GL");
+ regionNames.Add("GR", "el-GR");
+ regionNames.Add("GT", "es-GT");
+ regionNames.Add("HK", "zh-HK");
+ regionNames.Add("HN", "es-HN");
+ regionNames.Add("HR", "hr-HR");
+ regionNames.Add("HU", "hu-HU");
+ regionNames.Add("ID", "id-ID");
+ regionNames.Add("IE", "en-IE");
+ regionNames.Add("IL", "he-IL");
+ regionNames.Add("IN", "hi-IN");
+ regionNames.Add("IQ", "ar-IQ");
+ regionNames.Add("IR", "fa-IR");
+ regionNames.Add("IS", "is-IS");
+ regionNames.Add("IT", "it-IT");
+ regionNames.Add("IV", "");
+ regionNames.Add("JM", "en-JM");
+ regionNames.Add("JO", "ar-JO");
+ regionNames.Add("JP", "ja-JP");
+ regionNames.Add("KE", "sw-KE");
+ regionNames.Add("KG", "ky-KG");
+ regionNames.Add("KH", "km-KH");
+ regionNames.Add("KR", "ko-KR");
+ regionNames.Add("KW", "ar-KW");
+ regionNames.Add("KZ", "kk-KZ");
+ regionNames.Add("LA", "lo-LA");
+ regionNames.Add("LB", "ar-LB");
+ regionNames.Add("LI", "de-LI");
+ regionNames.Add("LK", "si-LK");
+ regionNames.Add("LT", "lt-LT");
+ regionNames.Add("LU", "lb-LU");
+ regionNames.Add("LV", "lv-LV");
+ regionNames.Add("LY", "ar-LY");
+ regionNames.Add("MA", "ar-MA");
+ regionNames.Add("MC", "fr-MC");
+ regionNames.Add("ME", "sr-Latn-ME");
+ regionNames.Add("MK", "mk-MK");
+ regionNames.Add("MN", "mn-MN");
+ regionNames.Add("MO", "zh-MO");
+ regionNames.Add("MT", "mt-MT");
+ regionNames.Add("MV", "dv-MV");
+ regionNames.Add("MX", "es-MX");
+ regionNames.Add("MY", "ms-MY");
+ regionNames.Add("NG", "ig-NG");
+ regionNames.Add("NI", "es-NI");
+ regionNames.Add("NL", "nl-NL");
+ regionNames.Add("NO", "nn-NO");
+ regionNames.Add("NP", "ne-NP");
+ regionNames.Add("NZ", "en-NZ");
+ regionNames.Add("OM", "ar-OM");
+ regionNames.Add("PA", "es-PA");
+ regionNames.Add("PE", "es-PE");
+ regionNames.Add("PH", "en-PH");
+ regionNames.Add("PK", "ur-PK");
+ regionNames.Add("PL", "pl-PL");
+ regionNames.Add("PR", "es-PR");
+ regionNames.Add("PT", "pt-PT");
+ regionNames.Add("PY", "es-PY");
+ regionNames.Add("QA", "ar-QA");
+ regionNames.Add("RO", "ro-RO");
+ regionNames.Add("RS", "sr-Latn-RS");
+ regionNames.Add("RU", "ru-RU");
+ regionNames.Add("RW", "rw-RW");
+ regionNames.Add("SA", "ar-SA");
+ regionNames.Add("SE", "sv-SE");
+ regionNames.Add("SG", "zh-SG");
+ regionNames.Add("SI", "sl-SI");
+ regionNames.Add("SK", "sk-SK");
+ regionNames.Add("SN", "wo-SN");
+ regionNames.Add("SV", "es-SV");
+ regionNames.Add("SY", "ar-SY");
+ regionNames.Add("TH", "th-TH");
+ regionNames.Add("TJ", "tg-Cyrl-TJ");
+ regionNames.Add("TM", "tk-TM");
+ regionNames.Add("TN", "ar-TN");
+ regionNames.Add("TR", "tr-TR");
+ regionNames.Add("TT", "en-TT");
+ regionNames.Add("TW", "zh-TW");
+ regionNames.Add("UA", "uk-UA");
+ regionNames.Add("US", "en-US");
+ regionNames.Add("UY", "es-UY");
+ regionNames.Add("UZ", "uz-Cyrl-UZ");
+ regionNames.Add("VE", "es-VE");
+ regionNames.Add("VN", "vi-VN");
+ regionNames.Add("YE", "ar-YE");
+ regionNames.Add("ZA", "af-ZA");
+ regionNames.Add("ZW", "en-ZW");
+
+ s_RegionNames = regionNames;
}
- return s_Invariant;
- }
- }
- private volatile static CultureData s_Invariant;
- ///////////////
- // Constructors //
- ///////////////
- // Cache of cultures we've already looked up
- private static volatile Dictionary<String, CultureData> s_cachedCultures;
-
- [FriendAccessAllowed]
- internal static CultureData GetCultureData(String cultureName, bool useUserOverride)
- {
- // First do a shortcut for Invariant
- if (String.IsNullOrEmpty(cultureName))
- {
- return CultureData.Invariant;
- }
-
- // Try the hash table first
- String hashName = AnsiToLower(useUserOverride ? cultureName : cultureName + '*');
- Dictionary<String, CultureData> tempHashTable = s_cachedCultures;
- if (tempHashTable == null)
- {
- // No table yet, make a new one
- tempHashTable = new Dictionary<String, CultureData>();
- }
- else
- {
- // Check the hash table
- CultureData retVal;
- lock (((ICollection)tempHashTable).SyncRoot)
- {
- tempHashTable.TryGetValue(hashName, out retVal);
- }
- if (retVal != null)
- {
- return retVal;
- }
- }
-
- // Not found in the hash table, need to see if we can build one that works for us
- CultureData culture = CreateCultureData(cultureName, useUserOverride);
- if (culture == null)
- {
- return null;
- }
-
- // Found one, add it to the cache
- lock (((ICollection)tempHashTable).SyncRoot)
- {
- tempHashTable[hashName] = culture;
- }
-
- // Copy the hashtable to the corresponding member variables. This will potentially overwrite
- // new tables simultaneously created by a new thread, but maximizes thread safety.
- s_cachedCultures = tempHashTable;
-
- return culture;
- }
-
- private static CultureData CreateCultureData(string cultureName, bool useUserOverride)
- {
- CultureData culture = new CultureData();
- culture.bUseOverrides = useUserOverride;
- culture.sRealName = cultureName;
-
- // Ask native code if that one's real
- if (culture.InitCultureData() == false)
- {
- return null;
- }
-
- return culture;
- }
-
- private bool InitCultureData()
- {
- if (nativeInitCultureData(this) == false)
- {
- return false;
+ return s_RegionNames;
}
- return true;
}
// Cache of regions we've already looked up
- private static volatile Dictionary<String, CultureData> s_cachedRegions;
+ private static volatile StringCultureDataDictionary s_cachedRegions;
+ private static volatile StringStringDictionary s_RegionNames;
internal static CultureData GetCultureDataForRegion(String cultureName, bool useUserOverride)
{
@@ -571,16 +333,16 @@ namespace System.Globalization
// Try the hash table next
String hashName = AnsiToLower(useUserOverride ? cultureName : cultureName + '*');
- Dictionary<String, CultureData> tempHashTable = s_cachedRegions;
+ StringCultureDataDictionary tempHashTable = s_cachedRegions;
if (tempHashTable == null)
{
// No table yet, make a new one
- tempHashTable = new Dictionary<String, CultureData>();
+ tempHashTable = new StringCultureDataDictionary();
}
else
{
// Check the hash table
- lock (((ICollection)tempHashTable).SyncRoot)
+ lock (s_lock)
{
tempHashTable.TryGetValue(hashName, out retVal);
}
@@ -598,36 +360,25 @@ namespace System.Globalization
if (retVal == null || (retVal.IsNeutralCulture == true))
{
// Not a valid mapping, try the hard coded table
- if (RegionNames.ContainsKey(cultureName))
+ string name;
+ if (RegionNames.TryGetValue(cultureName, out name))
{
// Make sure we can get culture data for it
- retVal = GetCultureData(RegionNames[cultureName], useUserOverride);
+ retVal = GetCultureData(name, useUserOverride);
}
}
// If not found in the hard coded table we'll have to find a culture that works for us
if (retVal == null || (retVal.IsNeutralCulture == true))
{
- // Not found in the hard coded table, need to see if we can find a culture that works for us
- // Not a real culture name, see if it matches a region name
- // (we just return the first culture we match)
- CultureInfo[] specifics = SpecificCultures;
- for (int i = 0; i < specifics.Length; i++)
- {
- if (String.Compare(specifics[i].m_cultureData.SREGIONNAME, cultureName, StringComparison.OrdinalIgnoreCase) == 0)
- {
- // Matched, use this culture
- retVal = specifics[i].m_cultureData;
- break;
- }
- }
+ retVal = GetCultureDataFromRegionName(cultureName);
}
- // If we found one we can use, then cash it for next time
+ // If we found one we can use, then cache it for next time
if (retVal != null && (retVal.IsNeutralCulture == false))
{
// first add it to the cache
- lock (((ICollection)tempHashTable).SyncRoot)
+ lock (s_lock)
{
tempHashTable[hashName] = retVal;
}
@@ -647,54 +398,11 @@ namespace System.Globalization
return retVal;
}
-#if FEATURE_USE_LCID
- // Obtain locale name from LCID
- // NOTE: This will get neutral names, unlike the OS API
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern String LCIDToLocaleName(int lcid);
-
- // We'd rather people use the named version since this doesn't allow custom locales
- internal static CultureData GetCultureData(int culture, bool bUseUserOverride)
- {
- String localeName = null;
- CultureData retVal = null;
-
- if (localeName == null)
- {
- // Convert the lcid to a name, then use that
- // Note that this'll return neutral names (unlike Vista native API)
- localeName = LCIDToLocaleName(culture);
- }
-
- // If its not valid, then throw
- if (String.IsNullOrEmpty(localeName))
- {
- // Could be valid for Invariant
- if (culture == 0x007f)
- return Invariant;
- }
- else
- {
- // Valid name, use it
- retVal = GetCultureData(localeName, bUseUserOverride);
- }
-
- // If not successful, throw
- if (retVal == null)
- throw new CultureNotFoundException(
- nameof(culture), culture, Environment.GetResourceString("Argument_CultureNotSupported"));
-
- // Return the one we found
- return retVal;
- }
-#endif
-
// Clear our internal caches
internal static void ClearCachedData()
{
s_cachedCultures = null;
s_cachedRegions = null;
- s_replacementCultureNames = null;
}
internal static CultureInfo[] GetCultures(CultureTypes types)
@@ -703,23 +411,16 @@ namespace System.Globalization
#pragma warning disable 618
// Validate flags
if ((int)types <= 0 || ((int)types & (int)~(CultureTypes.NeutralCultures | CultureTypes.SpecificCultures |
- CultureTypes.InstalledWin32Cultures | CultureTypes.UserCustomCulture |
- CultureTypes.ReplacementCultures | CultureTypes.WindowsOnlyCultures |
- CultureTypes.FrameworkCultures)) != 0)
+ CultureTypes.InstalledWin32Cultures | CultureTypes.UserCustomCulture |
+ CultureTypes.ReplacementCultures | CultureTypes.WindowsOnlyCultures |
+ CultureTypes.FrameworkCultures)) != 0)
{
- throw new ArgumentOutOfRangeException(
- nameof(types),
- String.Format(
- CultureInfo.CurrentCulture,
- Environment.GetResourceString("ArgumentOutOfRange_Range"), CultureTypes.NeutralCultures, CultureTypes.FrameworkCultures));
+ throw new ArgumentOutOfRangeException(nameof(types),
+ SR.Format(SR.ArgumentOutOfRange_Range, CultureTypes.NeutralCultures, CultureTypes.FrameworkCultures));
}
- //
- // CHANGE FROM Whidbey
- //
// We have deprecated CultureTypes.FrameworkCultures.
// When this enum is used, we will enumerate Whidbey framework cultures (for compatibility).
- //
// We have deprecated CultureTypes.WindowsOnlyCultures.
// When this enum is used, we will return an empty array for this enum.
@@ -728,85 +429,349 @@ namespace System.Globalization
// Remove the enum as it is an no-op.
types &= (~CultureTypes.WindowsOnlyCultures);
}
+
+ if (GlobalizationMode.Invariant)
+ {
+ // in invariant mode we always return invariant culture only from the enumeration
+ return new CultureInfo[1] { new CultureInfo("") };
+ }
- String[] cultureNames = null;
+#pragma warning restore 618
+ return EnumCultures(types);
+ }
+
+ private static CultureData CreateCultureWithInvariantData()
+ {
+ // Make a new culturedata
+ CultureData invariant = new CultureData();
+
+ // Basics
+ // Note that we override the resources since this IS NOT supposed to change (by definition)
+ invariant._bUseOverrides = false;
+ invariant._sRealName = ""; // Name you passed in (ie: en-US, en, or de-DE_phoneb)
+ invariant._sWindowsName = ""; // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in))
+
+ // Identity
+ invariant._sName = ""; // locale name (ie: en-us)
+ invariant._sParent = ""; // Parent name (which may be a custom locale/culture)
+ invariant._bNeutral = false; // Flags for the culture (ie: neutral or not right now)
+ invariant._sEnglishDisplayName = "Invariant Language (Invariant Country)"; // English pretty name for this locale
+ invariant._sNativeDisplayName = "Invariant Language (Invariant Country)"; // Native pretty name for this locale
+ invariant._sSpecificCulture = ""; // The culture name to be used in CultureInfo.CreateSpecificCulture()
+
+ // Language
+ invariant._sISO639Language = "iv"; // ISO 639 Language Name
+ invariant._sISO639Language2 = "ivl"; // 3 char ISO 639 lang name 2
+ invariant._sLocalizedLanguage = "Invariant Language"; // Display name for this Language
+ invariant._sEnglishLanguage = "Invariant Language"; // English name for this language
+ invariant._sNativeLanguage = "Invariant Language"; // Native name of this language
+ invariant._sAbbrevLang = "IVL"; // abbreviated language name (Windows Language Name)
+ invariant._sConsoleFallbackName = ""; // The culture name for the console fallback UI culture
+ invariant._iInputLanguageHandle = 0x07F; // input language handle
+
+ // Region
+ invariant._sRegionName = "IV"; // (RegionInfo)
+ invariant._sEnglishCountry = "Invariant Country"; // english country name (RegionInfo)
+ invariant._sNativeCountry = "Invariant Country"; // native country name (Windows Only)
+ invariant._sISO3166CountryName = "IV"; // (RegionInfo), ie: US
+ invariant._sISO3166CountryName2 = "ivc"; // 3 char ISO 3166 country name 2 2(RegionInfo)
+ invariant._iGeoId = 244; // GeoId (Windows Only)
+
+ // Numbers
+ invariant._sPositiveSign = "+"; // positive sign
+ invariant._sNegativeSign = "-"; // negative sign
+ invariant._iDigits = 2; // number of fractional digits
+ invariant._iNegativeNumber = 1; // negative number format
+ invariant._waGrouping = new int[] { 3 }; // grouping of digits
+ invariant._sDecimalSeparator = "."; // decimal separator
+ invariant._sThousandSeparator = ","; // thousands separator
+ invariant._sNaN = "NaN"; // Not a Number
+ invariant._sPositiveInfinity = "Infinity"; // + Infinity
+ invariant._sNegativeInfinity = "-Infinity"; // - Infinity
+
+ // Percent
+ invariant._iNegativePercent = 0; // Negative Percent (0-3)
+ invariant._iPositivePercent = 0; // Positive Percent (0-11)
+ invariant._sPercent = "%"; // Percent (%) symbol
+ invariant._sPerMille = "\x2030"; // PerMille symbol
+
+ // Currency
+ invariant._sCurrency = "\x00a4"; // local monetary symbol: for international monetary symbol
+ invariant._sIntlMonetarySymbol = "XDR"; // international monetary symbol (RegionInfo)
+ invariant._sEnglishCurrency = "International Monetary Fund"; // English name for this currency (Windows Only)
+ invariant._sNativeCurrency = "International Monetary Fund"; // Native name for this currency (Windows Only)
+ invariant._iCurrencyDigits = 2; // # local monetary fractional digits
+ invariant._iCurrency = 0; // positive currency format
+ invariant._iNegativeCurrency = 0; // negative currency format
+ invariant._waMonetaryGrouping = new int[] { 3 }; // monetary grouping of digits
+ invariant._sMonetaryDecimal = "."; // monetary decimal separator
+ invariant._sMonetaryThousand = ","; // monetary thousands separator
+
+ // Misc
+ invariant._iMeasure = 0; // system of measurement 0=metric, 1=US (RegionInfo)
+ invariant._sListSeparator = ","; // list separator
+
+ // Time
+ invariant._sTimeSeparator = ":";
+ invariant._sAM1159 = "AM"; // AM designator
+ invariant._sPM2359 = "PM"; // PM designator
+ invariant._saLongTimes = new String[] { "HH:mm:ss" }; // time format
+ invariant._saShortTimes = new String[] { "HH:mm", "hh:mm tt", "H:mm", "h:mm tt" }; // short time format
+ invariant._saDurationFormats = new String[] { "HH:mm:ss" }; // time duration format
+
+
+ // Calendar specific data
+ invariant._iFirstDayOfWeek = 0; // first day of week
+ invariant._iFirstWeekOfYear = 0; // first week of year
+ invariant._waCalendars = new CalendarId[] { CalendarId.GREGORIAN }; // all available calendar type(s). The first one is the default calendar
+
+ // Store for specific data about each calendar
+ invariant._calendars = new CalendarData[CalendarData.MAX_CALENDARS];
+ invariant._calendars[0] = CalendarData.Invariant;
+
+ // Text information
+ invariant._iReadingLayout = 0;
+
+ // These are desktop only, not coreclr
+
+ invariant._iLanguage = CultureInfo.LOCALE_INVARIANT; // locale ID (0409) - NO sort information
+ invariant._iDefaultAnsiCodePage = 1252; // default ansi code page ID (ACP)
+ invariant._iDefaultOemCodePage = 437; // default oem code page ID (OCP or OEM)
+ invariant._iDefaultMacCodePage = 10000; // default macintosh code page
+ invariant._iDefaultEbcdicCodePage = 037; // default EBCDIC code page
+
+ if (GlobalizationMode.Invariant)
+ {
+ invariant._sLocalizedDisplayName = invariant._sNativeDisplayName;
+ invariant._sLocalizedCountry = invariant._sNativeCountry;
+ }
+
+ return invariant;
+ }
- //
- // Call nativeEnumCultureNames() to get a string array of culture names based on the specified
- // enumeration type.
- //
- // nativeEnumCultureNames is a QCall. We need to use a reference to return the string array
- // allocated from the QCall. That ref has to be wrapped as object handle.
- // See vm\qcall.h for details in QCall.
- //
+ /////////////////////////////////////////////////////////////////////////
+ // Build our invariant information
+ //
+ // We need an invariant instance, which we build hard-coded
+ /////////////////////////////////////////////////////////////////////////
+ internal static CultureData Invariant
+ {
+ get
+ {
+ if (s_Invariant == null)
+ {
+ // Remember it
+ s_Invariant = CreateCultureWithInvariantData();
+ }
+ return s_Invariant;
+ }
+ }
+ private volatile static CultureData s_Invariant;
- if (nativeEnumCultureNames((int)types, JitHelpers.GetObjectHandleOnStack(ref cultureNames)) == 0)
+ ///////////////
+ // Constructors //
+ ///////////////
+ // Cache of cultures we've already looked up
+ private static volatile StringCultureDataDictionary s_cachedCultures;
+ private static readonly Lock s_lock = new Lock();
+
+ internal static CultureData GetCultureData(String cultureName, bool useUserOverride)
+ {
+ // First do a shortcut for Invariant
+ if (String.IsNullOrEmpty(cultureName))
{
- return new CultureInfo[0];
+ return CultureData.Invariant;
}
- int arrayLength = cultureNames.Length;
+ // Try the hash table first
+ String hashName = AnsiToLower(useUserOverride ? cultureName : cultureName + '*');
+ StringCultureDataDictionary tempHashTable = s_cachedCultures;
+ if (tempHashTable == null)
+ {
+ // No table yet, make a new one
+ tempHashTable = new StringCultureDataDictionary();
+ }
+ else
+ {
+ // Check the hash table
+ bool ret;
+ CultureData retVal;
+ lock (s_lock)
+ {
+ ret = tempHashTable.TryGetValue(hashName, out retVal);
+ }
+ if (ret && retVal != null)
+ {
+ return retVal;
+ }
+ }
- CultureInfo[] cultures = new CultureInfo[arrayLength];
+ // Not found in the hash table, need to see if we can build one that works for us
+ CultureData culture = CreateCultureData(cultureName, useUserOverride);
+ if (culture == null)
+ {
+ return null;
+ }
- for (int i = 0; i < cultureNames.Length; i++)
+ // Found one, add it to the cache
+ lock (s_lock)
{
- cultures[i] = new CultureInfo(cultureNames[i]);
+ tempHashTable[hashName] = culture;
}
-#pragma warning restore 618
- return cultures;
- }
+ // Copy the hashtable to the corresponding member variables. This will potentially overwrite
+ // new tables simultaneously created by a new thread, but maximizes thread safety.
+ s_cachedCultures = tempHashTable;
- internal static volatile CultureInfo[] specificCultures;
+ return culture;
+ }
- private static CultureInfo[] SpecificCultures
+ private static unsafe string NormalizeCultureName(string name, out bool isNeutralName)
{
- get
+ isNeutralName = true;
+ int i = 0;
+
+ Debug.Assert(name.Length <= LOCALE_NAME_MAX_LENGTH);
+
+ char *pName = stackalloc char[LOCALE_NAME_MAX_LENGTH];
+ bool changed = false;
+
+ while (i < name.Length && name[i] != '-' && name[i] != '_')
{
- if (specificCultures == null)
- specificCultures = GetCultures(CultureTypes.SpecificCultures);
+ if (name[i] >= 'A' && name[i] <= 'Z')
+ {
+ // lowercase characters before '-'
+ pName[i] = (char) (((int)name[i]) + 0x20);
+ changed = true;
+ }
+ else
+ {
+ pName[i] = name[i];
+ }
+ i++;
+ }
- return specificCultures;
+ if (i < name.Length)
+ {
+ // this is not perfect to detect the non neutral cultures but it is good enough when we are running in invariant mode
+ isNeutralName = false;
}
+
+ while (i < name.Length)
+ {
+ if (name[i] >= 'a' && name[i] <= 'z')
+ {
+ pName[i] = (char) (((int)name[i]) - 0x20);
+ changed = true;
+ }
+ else
+ {
+ pName[i] = name[i];
+ }
+ i++;
+ }
+
+ if (changed)
+ return new string(pName, 0, name.Length);
+
+ return name;
}
- internal bool IsReplacementCulture
+ private static CultureData CreateCultureData(string cultureName, bool useUserOverride)
{
- get
+ if (GlobalizationMode.Invariant)
{
- return IsReplacementCultureName(this.SNAME);
+ CultureInfo.VerifyCultureName(cultureName, true);
+ CultureData cd = CreateCultureWithInvariantData();
+ cd._bUseOverrides = useUserOverride;
+ cd._sName = NormalizeCultureName(cultureName, out cd._bNeutral);
+ cd._sRealName = cd._sName;
+ cd._sWindowsName = cd._sName;
+ cd._iLanguage = CultureInfo.LOCALE_CUSTOM_UNSPECIFIED;
+
+ return cd;
}
- }
- internal static volatile String[] s_replacementCultureNames;
+ CultureData culture = new CultureData();
+ culture._bUseOverrides = useUserOverride;
+ culture._sRealName = cultureName;
- ////////////////////////////////////////////////////////////////////////
- //
- // Cache for the known replacement cultures.
- // This is used by CultureInfo.CultureType to check if a culture is a
- // replacement culture.
- //
- ////////////////////////////////////////////////////////////////////////
+ // Ask native code if that one's real
+ if (culture.InitCultureData() == false)
+ {
+ if (culture.InitCompatibilityCultureData() == false)
+ {
+ return null;
+ }
+ }
+ return culture;
+ }
- private static bool IsReplacementCultureName(String name)
+ private bool InitCompatibilityCultureData()
{
- Debug.Assert(name != null, "IsReplacementCultureName(): name should not be null");
- String[] replacementCultureNames = s_replacementCultureNames;
- if (replacementCultureNames == null)
+ // for compatibility handle the deprecated ids: zh-chs, zh-cht
+ string cultureName = _sRealName;
+
+ string fallbackCultureName;
+ string realCultureName;
+ switch (AnsiToLower(cultureName))
{
- if (nativeEnumCultureNames((int)CultureTypes.ReplacementCultures, JitHelpers.GetObjectHandleOnStack(ref replacementCultureNames)) == 0)
- {
+ case "zh-chs":
+ fallbackCultureName = "zh-Hans";
+ realCultureName = "zh-CHS";
+ break;
+ case "zh-cht":
+ fallbackCultureName = "zh-Hant";
+ realCultureName = "zh-CHT";
+ break;
+ default:
return false;
- }
+ }
+
+ _sRealName = fallbackCultureName;
+ if (InitCultureData() == false)
+ {
+ return false;
+ }
+ // fixup our data
+ _sName = realCultureName; // the name that goes back to the user
+ _sParent = fallbackCultureName;
+
+ return true;
+ }
+
+ // We'd rather people use the named version since this doesn't allow custom locales
+ internal static CultureData GetCultureData(int culture, bool bUseUserOverride)
+ {
+ string localeName = null;
+ CultureData retVal = null;
+
+ if (culture == CultureInfo.LOCALE_INVARIANT)
+ return Invariant;
+
+ if (GlobalizationMode.Invariant)
+ {
+ // LCID is not supported in the InvariantMode
+ throw new CultureNotFoundException(nameof(culture), culture, SR.Argument_CultureNotSupported);
+ }
+
+ // Convert the lcid to a name, then use that
+ // Note that this will return neutral names (unlike Vista native API)
+ localeName = LCIDToLocaleName(culture);
- // Even if we don't have any replacement cultures, the returned replacementCultureNames will still an empty string array, not null.
- Debug.Assert(name != null, "IsReplacementCultureName(): replacementCultureNames should not be null");
- Array.Sort(replacementCultureNames);
- s_replacementCultureNames = replacementCultureNames;
+ if (!String.IsNullOrEmpty(localeName))
+ {
+ // Valid name, use it
+ retVal = GetCultureData(localeName, bUseUserOverride);
}
- return Array.BinarySearch(replacementCultureNames, name) >= 0;
+
+ // If not successful, throw
+ if (retVal == null)
+ throw new CultureNotFoundException(nameof(culture), culture, SR.Argument_CultureNotSupported);
+
+ // Return the one we found
+ return retVal;
}
////////////////////////////////////////////////////////////////////////
@@ -826,17 +791,17 @@ namespace System.Globalization
{
get
{
- Debug.Assert(this.sRealName != null, "[CultureData.CultureName] Expected this.sRealName to be populated by COMNlsInfo::nativeInitCultureData already");
+ Debug.Assert(_sRealName != null, "[CultureData.CultureName] Expected _sRealName to be populated by already");
// since windows doesn't know about zh-CHS and zh-CHT,
// we leave sRealName == zh-Hanx but we still need to
// pretend that it was zh-CHX.
- switch (this.sName)
+ switch (_sName)
{
case "zh-CHS":
case "zh-CHT":
- return this.sName;
+ return _sName;
}
- return this.sRealName;
+ return _sRealName;
}
}
@@ -845,7 +810,7 @@ namespace System.Globalization
{
get
{
- return this.bUseOverrides;
+ return _bUseOverrides;
}
}
@@ -854,13 +819,11 @@ namespace System.Globalization
{
get
{
- // Debug.Assert(this.sName != null,
- // "[CultureData.SNAME] Expected this.sName to be populated by COMNlsInfo::nativeInitCultureData already");
- if (this.sName == null)
+ if (_sName == null)
{
- this.sName = String.Empty;
+ _sName = String.Empty;
}
- return this.sName;
+ return _sName;
}
}
@@ -869,12 +832,12 @@ namespace System.Globalization
{
get
{
- if (this.sParent == null)
+ if (_sParent == null)
{
// Ask using the real name, so that we get parents of neutrals
- this.sParent = DoGetLocaleInfo(this.sRealName, LOCALE_SPARENT);
+ _sParent = GetLocaleInfo(_sRealName, LocaleStringData.ParentName);
}
- return this.sParent;
+ return _sParent;
}
}
@@ -883,31 +846,73 @@ namespace System.Globalization
{
get
{
- if (this.sLocalizedDisplayName == null)
+ if (_sLocalizedDisplayName == null)
{
+ if (this.IsSupplementalCustomCulture)
+ {
+ if (this.IsNeutralCulture)
+ {
+ _sLocalizedDisplayName = this.SNATIVELANGUAGE;
+ }
+ else
+ {
+ _sLocalizedDisplayName = this.SNATIVEDISPLAYNAME;
+ }
+ }
+ else
+ {
+ try
+ {
+ const string ZH_CHT = "zh-CHT";
+ const string ZH_CHS = "zh-CHS";
+
+ if (SNAME.Equals(ZH_CHT, StringComparison.OrdinalIgnoreCase))
+ {
+ _sLocalizedDisplayName = GetLanguageDisplayName("zh-Hant");
+ }
+ else if (SNAME.Equals(ZH_CHS, StringComparison.OrdinalIgnoreCase))
+ {
+ _sLocalizedDisplayName = GetLanguageDisplayName("zh-Hans");
+ }
+ else
+ {
+ _sLocalizedDisplayName = GetLanguageDisplayName(SNAME);
+ }
+ }
+ catch (Exception)
+ {
+ // do nothing
+ }
+ }
// If it hasn't been found (Windows 8 and up), fallback to the system
- if (String.IsNullOrEmpty(this.sLocalizedDisplayName))
+ if (String.IsNullOrEmpty(_sLocalizedDisplayName))
{
// If its neutral use the language name
if (this.IsNeutralCulture)
{
- this.sLocalizedDisplayName = this.SLOCALIZEDLANGUAGE;
+ _sLocalizedDisplayName = this.SLOCALIZEDLANGUAGE;
}
else
{
- // We have to make the neutral distinction in case the OS returns a specific name
- if (CultureInfo.UserDefaultUICulture.Name.Equals(Thread.CurrentThread.CurrentUICulture.Name))
+ // Usually the UI culture shouldn't be different than what we got from WinRT except
+ // if DefaultThreadCurrentUICulture was set
+ CultureInfo ci;
+
+ if (CultureInfo.DefaultThreadCurrentUICulture != null &&
+ ((ci = GetUserDefaultCulture()) != null) &&
+ !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name))
{
- this.sLocalizedDisplayName = DoGetLocaleInfo(LOCALE_SLOCALIZEDDISPLAYNAME);
+ _sLocalizedDisplayName = this.SNATIVEDISPLAYNAME;
}
- if (String.IsNullOrEmpty(this.sLocalizedDisplayName))
+ else
{
- this.sLocalizedDisplayName = this.SNATIVEDISPLAYNAME;
+ _sLocalizedDisplayName = GetLocaleInfo(LocaleStringData.LocalizedDisplayName);
}
}
}
}
- return this.sLocalizedDisplayName;
+
+ return _sLocalizedDisplayName;
}
}
@@ -916,39 +921,47 @@ namespace System.Globalization
{
get
{
- if (this.sEnglishDisplayName == null)
+ if (_sEnglishDisplayName == null)
{
// If its neutral use the language name
if (this.IsNeutralCulture)
{
- this.sEnglishDisplayName = this.SENGLISHLANGUAGE;
+ _sEnglishDisplayName = this.SENGLISHLANGUAGE;
+ // differentiate the legacy display names
+ switch (_sName)
+ {
+ case "zh-CHS":
+ case "zh-CHT":
+ _sEnglishDisplayName += " Legacy";
+ break;
+ }
}
else
{
- this.sEnglishDisplayName = DoGetLocaleInfo(LOCALE_SENGLISHDISPLAYNAME);
+ _sEnglishDisplayName = GetLocaleInfo(LocaleStringData.EnglishDisplayName);
// if it isn't found build one:
- if (String.IsNullOrEmpty(this.sEnglishDisplayName))
+ if (String.IsNullOrEmpty(_sEnglishDisplayName))
{
// Our existing names mostly look like:
// "English" + "United States" -> "English (United States)"
// "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)"
- if (this.SENGLISHLANGUAGE.EndsWith(')'))
+ if (this.SENGLISHLANGUAGE[this.SENGLISHLANGUAGE.Length - 1] == ')')
{
// "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)"
- this.sEnglishDisplayName =
- this.SENGLISHLANGUAGE.Substring(0, this.sEnglishLanguage.Length - 1) +
+ _sEnglishDisplayName =
+ this.SENGLISHLANGUAGE.Substring(0, _sEnglishLanguage.Length - 1) +
", " + this.SENGCOUNTRY + ")";
}
else
{
// "English" + "United States" -> "English (United States)"
- this.sEnglishDisplayName = this.SENGLISHLANGUAGE + " (" + this.SENGCOUNTRY + ")";
+ _sEnglishDisplayName = this.SENGLISHLANGUAGE + " (" + this.SENGCOUNTRY + ")";
}
}
}
}
- return this.sEnglishDisplayName;
+ return _sEnglishDisplayName;
}
}
@@ -957,37 +970,47 @@ namespace System.Globalization
{
get
{
- if (this.sNativeDisplayName == null)
+ if (_sNativeDisplayName == null)
{
// If its neutral use the language name
if (this.IsNeutralCulture)
{
- this.sNativeDisplayName = this.SNATIVELANGUAGE;
+ _sNativeDisplayName = this.SNATIVELANGUAGE;
+ // differentiate the legacy display names
+ switch (_sName)
+ {
+ case "zh-CHS":
+ _sNativeDisplayName += " \u65E7\u7248";
+ break;
+ case "zh-CHT":
+ _sNativeDisplayName += " \u820A\u7248";
+ break;
+ }
}
else
{
- this.sNativeDisplayName = DoGetLocaleInfo(LOCALE_SNATIVEDISPLAYNAME);
+ _sNativeDisplayName = GetLocaleInfo(LocaleStringData.NativeDisplayName);
// if it isn't found build one:
- if (String.IsNullOrEmpty(this.sNativeDisplayName))
+ if (String.IsNullOrEmpty(_sNativeDisplayName))
{
// These should primarily be "Deutsch (Deutschland)" type names
- this.sNativeDisplayName = this.SNATIVELANGUAGE + " (" + this.SNATIVECOUNTRY + ")";
+ _sNativeDisplayName = this.SNATIVELANGUAGE + " (" + this.SNATIVECOUNTRY + ")";
}
}
}
- return this.sNativeDisplayName;
+ return _sNativeDisplayName;
}
}
// The culture name to be used in CultureInfo.CreateSpecificCulture()
- internal String SSPECIFICCULTURE
+ internal string SSPECIFICCULTURE
{
get
{
- // This got populated when ComNlsInfo::nativeInitCultureData told us we had a culture
- Debug.Assert(this.sSpecificCulture != null, "[CultureData.SSPECIFICCULTURE] Expected this.sSpecificCulture to be populated by COMNlsInfo::nativeInitCultureData already");
- return this.sSpecificCulture;
+ // This got populated during the culture initialization
+ Debug.Assert(_sSpecificCulture != null, "[CultureData.SSPECIFICCULTURE] Expected this.sSpecificCulture to be populated by culture data initialization already");
+ return _sSpecificCulture;
}
}
@@ -1000,37 +1023,37 @@ namespace System.Globalization
{
get
{
- if (this.sISO639Language == null)
+ if (_sISO639Language == null)
{
- this.sISO639Language = DoGetLocaleInfo(LOCALE_SISO639LANGNAME);
+ _sISO639Language = GetLocaleInfo(LocaleStringData.Iso639LanguageTwoLetterName);
}
- return this.sISO639Language;
+ return _sISO639Language;
}
}
// iso 639 language name, ie: eng
- internal String SISO639LANGNAME2
+ internal string SISO639LANGNAME2
{
get
{
- if (this.sISO639Language2 == null)
+ if (_sISO639Language2 == null)
{
- this.sISO639Language2 = DoGetLocaleInfo(LOCALE_SISO639LANGNAME2);
+ _sISO639Language2 = GetLocaleInfo(LocaleStringData.Iso639LanguageThreeLetterName);
}
- return this.sISO639Language2;
+ return _sISO639Language2;
}
}
// abbreviated windows language name (ie: enu) (non-standard, avoid this)
- internal String SABBREVLANGNAME
+ internal string SABBREVLANGNAME
{
get
{
- if (this.sAbbrevLang == null)
+ if (_sAbbrevLang == null)
{
- this.sAbbrevLang = DoGetLocaleInfo(LOCALE_SABBREVLANGNAME);
+ _sAbbrevLang = GetThreeLetterWindowsLanguageName(_sRealName);
}
- return this.sAbbrevLang;
+ return _sAbbrevLang;
}
}
@@ -1040,20 +1063,25 @@ namespace System.Globalization
{
get
{
- if (this.sLocalizedLanguage == null)
+ if (_sLocalizedLanguage == null)
{
- if (CultureInfo.UserDefaultUICulture.Name.Equals(Thread.CurrentThread.CurrentUICulture.Name))
+ // Usually the UI culture shouldn't be different than what we got from WinRT except
+ // if DefaultThreadCurrentUICulture was set
+ CultureInfo ci;
+
+ if (CultureInfo.DefaultThreadCurrentUICulture != null &&
+ ((ci = GetUserDefaultCulture()) != null) &&
+ !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name))
{
- this.sLocalizedLanguage = DoGetLocaleInfo(LOCALE_SLOCALIZEDLANGUAGENAME);
+ _sLocalizedLanguage = SNATIVELANGUAGE;
}
- // Some OS's might not have this resource or LCTYPE
- if (String.IsNullOrEmpty(this.sLocalizedLanguage))
+ else
{
- this.sLocalizedLanguage = SNATIVELANGUAGE;
+ _sLocalizedLanguage = GetLocaleInfo(LocaleStringData.LocalizedLanguageName);
}
}
- return this.sLocalizedLanguage;
+ return _sLocalizedLanguage;
}
}
@@ -1062,11 +1090,11 @@ namespace System.Globalization
{
get
{
- if (this.sEnglishLanguage == null)
+ if (_sEnglishLanguage == null)
{
- this.sEnglishLanguage = DoGetLocaleInfo(LOCALE_SENGLISHLANGUAGENAME);
+ _sEnglishLanguage = GetLocaleInfo(LocaleStringData.EnglishLanguageName);
}
- return this.sEnglishLanguage;
+ return _sEnglishLanguage;
}
}
@@ -1075,13 +1103,11 @@ namespace System.Globalization
{
get
{
- if (this.sNativeLanguage == null)
+ if (_sNativeLanguage == null)
{
- {
- this.sNativeLanguage = DoGetLocaleInfo(LOCALE_SNATIVELANGUAGENAME);
- }
+ _sNativeLanguage = GetLocaleInfo(LocaleStringData.NativeLanguageName);
}
- return this.sNativeLanguage;
+ return _sNativeLanguage;
}
}
@@ -1094,24 +1120,23 @@ namespace System.Globalization
{
get
{
- if (this.sRegionName == null)
+ if (_sRegionName == null)
{
- this.sRegionName = DoGetLocaleInfo(LOCALE_SISO3166CTRYNAME);
+ _sRegionName = GetLocaleInfo(LocaleStringData.Iso3166CountryName);
}
- return this.sRegionName;
+ return _sRegionName;
}
}
- // GeoId
internal int IGEOID
{
get
{
- if (this.iGeoId == undef)
+ if (_iGeoId == undef)
{
- this.iGeoId = DoGetLocaleInfoInt(LOCALE_IGEOID);
+ _iGeoId = GetGeoId(_sRealName);
}
- return this.iGeoId;
+ return _iGeoId;
}
}
@@ -1120,23 +1145,23 @@ namespace System.Globalization
{
get
{
- if (this.sLocalizedCountry == null)
+ if (_sLocalizedCountry == null)
{
- // If it hasn't been found (Windows 8 and up), fallback to the system
- if (String.IsNullOrEmpty(this.sLocalizedCountry))
+ try
{
- // We have to make the neutral distinction in case the OS returns a specific name
- if (CultureInfo.UserDefaultUICulture.Name.Equals(Thread.CurrentThread.CurrentUICulture.Name))
- {
- this.sLocalizedCountry = DoGetLocaleInfo(LOCALE_SLOCALIZEDCOUNTRYNAME);
- }
- if (String.IsNullOrEmpty(this.sLocalizedDisplayName))
- {
- this.sLocalizedCountry = SNATIVECOUNTRY;
- }
+ _sLocalizedCountry = GetRegionDisplayName(SISO3166CTRYNAME);
+ }
+ catch (Exception)
+ {
+ // do nothing. we'll fallback
+ }
+
+ if (_sLocalizedCountry == null)
+ {
+ _sLocalizedCountry = SNATIVECOUNTRY;
}
}
- return this.sLocalizedCountry;
+ return _sLocalizedCountry;
}
}
@@ -1145,11 +1170,11 @@ namespace System.Globalization
{
get
{
- if (this.sEnglishCountry == null)
+ if (_sEnglishCountry == null)
{
- this.sEnglishCountry = DoGetLocaleInfo(LOCALE_SENGLISHCOUNTRYNAME);
+ _sEnglishCountry = GetLocaleInfo(LocaleStringData.EnglishCountryName);
}
- return this.sEnglishCountry;
+ return _sEnglishCountry;
}
}
@@ -1158,11 +1183,11 @@ namespace System.Globalization
{
get
{
- if (this.sNativeCountry == null)
+ if (_sNativeCountry == null)
{
- this.sNativeCountry = DoGetLocaleInfo(LOCALE_SNATIVECOUNTRYNAME);
+ _sNativeCountry = GetLocaleInfo(LocaleStringData.NativeCountryName);
}
- return this.sNativeCountry;
+ return _sNativeCountry;
}
}
@@ -1171,90 +1196,70 @@ namespace System.Globalization
{
get
{
- if (this.sISO3166CountryName == null)
+ if (_sISO3166CountryName == null)
{
- this.sISO3166CountryName = DoGetLocaleInfo(LOCALE_SISO3166CTRYNAME);
+ _sISO3166CountryName = GetLocaleInfo(LocaleStringData.Iso3166CountryName);
}
- return this.sISO3166CountryName;
+ return _sISO3166CountryName;
}
}
- // ISO 3166 Country Name
+ // 3 letter ISO 3166 country code
internal String SISO3166CTRYNAME2
{
get
{
- if (this.sISO3166CountryName2 == null)
+ if (_sISO3166CountryName2 == null)
{
- this.sISO3166CountryName2 = DoGetLocaleInfo(LOCALE_SISO3166CTRYNAME2);
+ _sISO3166CountryName2 = GetLocaleInfo(LocaleStringData.Iso3166CountryName2);
}
- return this.sISO3166CountryName2;
+ return _sISO3166CountryName2;
}
}
- // abbreviated Country Name (windows version, non-standard, avoid)
- internal String SABBREVCTRYNAME
- {
- get
- {
- if (this.sAbbrevCountry == null)
- {
- this.sAbbrevCountry = DoGetLocaleInfo(LOCALE_SABBREVCTRYNAME);
- }
- return this.sAbbrevCountry;
- }
- }
-
- // Console fallback name (ie: locale to use for console apps for unicode-only locales)
internal int IINPUTLANGUAGEHANDLE
{
get
{
- if (this.iInputLanguageHandle == undef)
+ if (_iInputLanguageHandle == undef)
{
if (IsSupplementalCustomCulture)
{
- this.iInputLanguageHandle = 0x0409;
+ _iInputLanguageHandle = 0x0409;
}
else
{
// Input Language is same as LCID for built-in cultures
- this.iInputLanguageHandle = this.ILANGUAGE;
+ _iInputLanguageHandle = this.ILANGUAGE;
}
}
- return this.iInputLanguageHandle;
+ return _iInputLanguageHandle;
}
}
// Console fallback name (ie: locale to use for console apps for unicode-only locales)
- internal String SCONSOLEFALLBACKNAME
+ internal string SCONSOLEFALLBACKNAME
{
get
{
- if (this.sConsoleFallbackName == null)
+ if (_sConsoleFallbackName == null)
{
- string consoleFallbackName = DoGetLocaleInfo(LOCALE_SCONSOLEFALLBACKNAME);
- if (consoleFallbackName == "es-ES_tradnl")
- {
- consoleFallbackName = "es-ES";
- }
- this.sConsoleFallbackName = consoleFallbackName;
+ _sConsoleFallbackName = GetConsoleFallbackName(_sRealName);
}
- return this.sConsoleFallbackName;
+ return _sConsoleFallbackName;
}
}
-
// (user can override) grouping of digits
internal int[] WAGROUPING
{
get
{
- if (this.waGrouping == null || UseUserOverride)
+ if (_waGrouping == null)
{
- this.waGrouping = ConvertWin32GroupString(DoGetLocaleInfo(LOCALE_SGROUPING));
+ _waGrouping = GetLocaleInfo(LocaleGroupingData.Digit);
}
- return this.waGrouping;
+ return _waGrouping;
}
}
@@ -1267,11 +1272,11 @@ namespace System.Globalization
{
get
{
- if (this.sNaN == null)
+ if (_sNaN == null)
{
- this.sNaN = DoGetLocaleInfo(LOCALE_SNAN);
+ _sNaN = GetLocaleInfo(LocaleStringData.NaNSymbol);
}
- return this.sNaN;
+ return _sNaN;
}
}
@@ -1280,11 +1285,11 @@ namespace System.Globalization
{
get
{
- if (this.sPositiveInfinity == null)
+ if (_sPositiveInfinity == null)
{
- this.sPositiveInfinity = DoGetLocaleInfo(LOCALE_SPOSINFINITY);
+ _sPositiveInfinity = GetLocaleInfo(LocaleStringData.PositiveInfinitySymbol);
}
- return this.sPositiveInfinity;
+ return _sPositiveInfinity;
}
}
@@ -1293,11 +1298,11 @@ namespace System.Globalization
{
get
{
- if (this.sNegativeInfinity == null)
+ if (_sNegativeInfinity == null)
{
- this.sNegativeInfinity = DoGetLocaleInfo(LOCALE_SNEGINFINITY);
+ _sNegativeInfinity = GetLocaleInfo(LocaleStringData.NegativeInfinitySymbol);
}
- return this.sNegativeInfinity;
+ return _sNegativeInfinity;
}
}
@@ -1311,12 +1316,12 @@ namespace System.Globalization
{
get
{
- if (this.iNegativePercent == undef)
+ if (_iNegativePercent == undef)
{
// Note that <= Windows Vista this is synthesized by native code
- this.iNegativePercent = DoGetLocaleInfoInt(LOCALE_INEGATIVEPERCENT);
+ _iNegativePercent = GetLocaleInfo(LocaleNumberData.NegativePercentFormat);
}
- return this.iNegativePercent;
+ return _iNegativePercent;
}
}
@@ -1325,12 +1330,12 @@ namespace System.Globalization
{
get
{
- if (this.iPositivePercent == undef)
+ if (_iPositivePercent == undef)
{
// Note that <= Windows Vista this is synthesized by native code
- this.iPositivePercent = DoGetLocaleInfoInt(LOCALE_IPOSITIVEPERCENT);
+ _iPositivePercent = GetLocaleInfo(LocaleNumberData.PositivePercentFormat);
}
- return this.iPositivePercent;
+ return _iPositivePercent;
}
}
@@ -1339,26 +1344,24 @@ namespace System.Globalization
{
get
{
- if (this.sPercent == null)
+ if (_sPercent == null)
{
- // Note that <= Windows Vista this is synthesized by native code
- this.sPercent = DoGetLocaleInfo(LOCALE_SPERCENT);
+ _sPercent = GetLocaleInfo(LocaleStringData.PercentSymbol);
}
- return this.sPercent;
+ return _sPercent;
}
}
- // PerMille (‰) symbol
+ // PerMille symbol
internal String SPERMILLE
{
get
{
- if (this.sPerMille == null)
+ if (_sPerMille == null)
{
- // Note that <= Windows Vista this is synthesized by native code
- this.sPerMille = DoGetLocaleInfo(LOCALE_SPERMILLE);
+ _sPerMille = GetLocaleInfo(LocaleStringData.PerMilleSymbol);
}
- return this.sPerMille;
+ return _sPerMille;
}
}
@@ -1371,11 +1374,11 @@ namespace System.Globalization
{
get
{
- if (this.sCurrency == null || UseUserOverride)
+ if (_sCurrency == null)
{
- this.sCurrency = DoGetLocaleInfo(LOCALE_SCURRENCY);
+ _sCurrency = GetLocaleInfo(LocaleStringData.MonetarySymbol);
}
- return this.sCurrency;
+ return _sCurrency;
}
}
@@ -1384,11 +1387,11 @@ namespace System.Globalization
{
get
{
- if (this.sIntlMonetarySymbol == null)
+ if (_sIntlMonetarySymbol == null)
{
- this.sIntlMonetarySymbol = DoGetLocaleInfo(LOCALE_SINTLSYMBOL);
+ _sIntlMonetarySymbol = GetLocaleInfo(LocaleStringData.Iso4217MonetarySymbol);
}
- return this.sIntlMonetarySymbol;
+ return _sIntlMonetarySymbol;
}
}
@@ -1397,11 +1400,11 @@ namespace System.Globalization
{
get
{
- if (this.sEnglishCurrency == null)
+ if (_sEnglishCurrency == null)
{
- this.sEnglishCurrency = DoGetLocaleInfo(LOCALE_SENGCURRNAME);
+ _sEnglishCurrency = GetLocaleInfo(LocaleStringData.CurrencyEnglishName);
}
- return this.sEnglishCurrency;
+ return _sEnglishCurrency;
}
}
@@ -1410,11 +1413,11 @@ namespace System.Globalization
{
get
{
- if (this.sNativeCurrency == null)
+ if (_sNativeCurrency == null)
{
- this.sNativeCurrency = DoGetLocaleInfo(LOCALE_SNATIVECURRNAME);
+ _sNativeCurrency = GetLocaleInfo(LocaleStringData.CurrencyNativeName);
}
- return this.sNativeCurrency;
+ return _sNativeCurrency;
}
}
@@ -1427,31 +1430,24 @@ namespace System.Globalization
{
get
{
- if (this.waMonetaryGrouping == null || UseUserOverride)
+ if (_waMonetaryGrouping == null)
{
- this.waMonetaryGrouping = ConvertWin32GroupString(DoGetLocaleInfo(LOCALE_SMONGROUPING));
+ _waMonetaryGrouping = GetLocaleInfo(LocaleGroupingData.Monetary);
}
- return this.waMonetaryGrouping;
+ return _waMonetaryGrouping;
}
}
- // internal String sMonetaryDecimal ; // (user can override) monetary decimal separator
- // internal String sMonetaryThousand ; // (user can override) monetary thousands separator
-
- /////////
- // Misc //
- /////////
-
// (user can override) system of measurement 0=metric, 1=US (RegionInfo)
internal int IMEASURE
{
get
{
- if (this.iMeasure == undef || UseUserOverride)
+ if (_iMeasure == undef)
{
- this.iMeasure = DoGetLocaleInfoInt(LOCALE_IMEASURE);
+ _iMeasure = GetLocaleInfo(LocaleNumberData.MeasurementSystem);
}
- return this.iMeasure;
+ return _iMeasure;
}
}
@@ -1460,14 +1456,15 @@ namespace System.Globalization
{
get
{
- if (this.sListSeparator == null || UseUserOverride)
+ if (_sListSeparator == null)
{
- this.sListSeparator = DoGetLocaleInfo(LOCALE_SLIST);
+ _sListSeparator = GetLocaleInfo(LocaleStringData.ListSeparator);
}
- return this.sListSeparator;
+ return _sListSeparator;
}
}
+
////////////////////////////
// Calendar/Time (Gregorian) //
////////////////////////////
@@ -1477,11 +1474,11 @@ namespace System.Globalization
{
get
{
- if (this.sAM1159 == null || UseUserOverride)
+ if (_sAM1159 == null)
{
- this.sAM1159 = DoGetLocaleInfo(LOCALE_S1159);
+ _sAM1159 = GetLocaleInfo(LocaleStringData.AMDesignator);
}
- return this.sAM1159;
+ return _sAM1159;
}
}
@@ -1490,11 +1487,11 @@ namespace System.Globalization
{
get
{
- if (this.sPM2359 == null || UseUserOverride)
+ if (_sPM2359 == null)
{
- this.sPM2359 = DoGetLocaleInfo(LOCALE_S2359);
+ _sPM2359 = GetLocaleInfo(LocaleStringData.PMDesignator);
}
- return this.sPM2359;
+ return _sPM2359;
}
}
@@ -1503,32 +1500,38 @@ namespace System.Globalization
{
get
{
- if (this.saLongTimes == null || UseUserOverride)
+ if (_saLongTimes == null)
{
- String[] longTimes = DoEnumTimeFormats();
+ Debug.Assert(!GlobalizationMode.Invariant);
+
+ String[] longTimes = GetTimeFormats();
if (longTimes == null || longTimes.Length == 0)
{
- this.saLongTimes = Invariant.saLongTimes;
+ _saLongTimes = Invariant._saLongTimes;
}
else
{
- this.saLongTimes = longTimes;
+ _saLongTimes = longTimes;
}
}
- return this.saLongTimes;
+ return _saLongTimes;
}
}
// short time format
// Short times (derived from long times format)
+ // TODO: NLS Arrowhead - On Windows 7 we should have short times so this isn't necessary
internal String[] ShortTimes
{
get
{
- if (this.saShortTimes == null || UseUserOverride)
+ if (_saShortTimes == null)
{
+ Debug.Assert(!GlobalizationMode.Invariant);
+
// Try to get the short times from the OS/culture.dll
- String[] shortTimes = DoEnumShortTimeFormats();
+ String[] shortTimes = null;
+ shortTimes = GetShortTimeFormats();
if (shortTimes == null || shortTimes.Length == 0)
{
@@ -1539,13 +1542,24 @@ namespace System.Globalization
shortTimes = DeriveShortTimesFromLong();
}
+ /* The above logic doesn't make sense on Mac, since the OS can provide us a "short time pattern".
+ * currently this is the 4th element in the array returned by LongTimes. We'll add this to our array
+ * if it doesn't exist.
+ */
+ shortTimes = AdjustShortTimesForMac(shortTimes);
+
// Found short times, use them
- this.saShortTimes = shortTimes;
+ _saShortTimes = shortTimes;
}
- return this.saShortTimes;
+ return _saShortTimes;
}
}
+ private string[] AdjustShortTimesForMac(string[] shortTimes)
+ {
+ return shortTimes;
+ }
+
private string[] DeriveShortTimesFromLong()
{
// Our logic is to look for h,H,m,s,t. If we find an s, then we check the string
@@ -1611,13 +1625,19 @@ namespace System.Globalization
bool containsSpace;
int endIndex = GetIndexOfNextTokenAfterSeconds(time, j, out containsSpace);
- StringBuilder sb = new StringBuilder(time.Substring(0, j));
+
+ string sep;
+
if (containsSpace)
{
- sb.Append(' ');
+ sep = " ";
}
- sb.Append(time.Substring(endIndex));
- time = sb.ToString();
+ else
+ {
+ sep = "";
+ }
+
+ time = time.Substring(0, j) + sep + time.Substring(endIndex);
break;
case 'm':
case 'H':
@@ -1670,12 +1690,11 @@ namespace System.Globalization
{
get
{
- if (this.iFirstDayOfWeek == undef || UseUserOverride)
+ if (_iFirstDayOfWeek == undef)
{
- // Have to convert it from windows to .Net formats
- this.iFirstDayOfWeek = ConvertFirstDayOfWeekMonToSun(DoGetLocaleInfoInt(LOCALE_IFIRSTDAYOFWEEK));
+ _iFirstDayOfWeek = GetFirstDayOfWeek();
}
- return this.iFirstDayOfWeek;
+ return _iFirstDayOfWeek;
}
}
@@ -1684,71 +1703,71 @@ namespace System.Globalization
{
get
{
- if (this.iFirstWeekOfYear == undef || UseUserOverride)
+ if (_iFirstWeekOfYear == undef)
{
- this.iFirstWeekOfYear = DoGetLocaleInfoInt(LOCALE_IFIRSTWEEKOFYEAR);
+ _iFirstWeekOfYear = GetLocaleInfo(LocaleNumberData.FirstWeekOfYear);
}
- return this.iFirstWeekOfYear;
+ return _iFirstWeekOfYear;
}
}
// (user can override default only) short date format
- internal String[] ShortDates(int calendarId)
+ internal String[] ShortDates(CalendarId calendarId)
{
return GetCalendar(calendarId).saShortDates;
}
// (user can override default only) long date format
- internal String[] LongDates(int calendarId)
+ internal String[] LongDates(CalendarId calendarId)
{
return GetCalendar(calendarId).saLongDates;
}
// (user can override) date year/month format.
- internal String[] YearMonths(int calendarId)
+ internal String[] YearMonths(CalendarId calendarId)
{
return GetCalendar(calendarId).saYearMonths;
}
// day names
- internal string[] DayNames(int calendarId)
+ internal string[] DayNames(CalendarId calendarId)
{
return GetCalendar(calendarId).saDayNames;
}
// abbreviated day names
- internal string[] AbbreviatedDayNames(int calendarId)
+ internal string[] AbbreviatedDayNames(CalendarId calendarId)
{
// Get abbreviated day names for this calendar from the OS if necessary
return GetCalendar(calendarId).saAbbrevDayNames;
}
// The super short day names
- internal string[] SuperShortDayNames(int calendarId)
+ internal string[] SuperShortDayNames(CalendarId calendarId)
{
return GetCalendar(calendarId).saSuperShortDayNames;
}
// month names
- internal string[] MonthNames(int calendarId)
+ internal string[] MonthNames(CalendarId calendarId)
{
return GetCalendar(calendarId).saMonthNames;
}
// Genitive month names
- internal string[] GenitiveMonthNames(int calendarId)
+ internal string[] GenitiveMonthNames(CalendarId calendarId)
{
return GetCalendar(calendarId).saMonthGenitiveNames;
}
// month names
- internal string[] AbbreviatedMonthNames(int calendarId)
+ internal string[] AbbreviatedMonthNames(CalendarId calendarId)
{
return GetCalendar(calendarId).saAbbrevMonthNames;
}
// Genitive month names
- internal string[] AbbreviatedGenitiveMonthNames(int calendarId)
+ internal string[] AbbreviatedGenitiveMonthNames(CalendarId calendarId)
{
return GetCalendar(calendarId).saAbbrevMonthGenitiveNames;
}
@@ -1756,13 +1775,13 @@ namespace System.Globalization
// Leap year month names
// Note: This only applies to Hebrew, and it basically adds a "1" to the 6th month name
// the non-leap names skip the 7th name in the normal month name array
- internal string[] LeapYearMonthNames(int calendarId)
+ internal string[] LeapYearMonthNames(CalendarId calendarId)
{
return GetCalendar(calendarId).saLeapYearMonthNames;
}
// month/day format (single string, no override)
- internal String MonthDay(int calendarId)
+ internal String MonthDay(CalendarId calendarId)
{
return GetCalendar(calendarId).sMonthDay;
}
@@ -1774,29 +1793,30 @@ namespace System.Globalization
/////////////
// all available calendar type(s), The first one is the default calendar.
- internal int[] CalendarIds
+ internal CalendarId[] CalendarIds
{
get
{
- if (this.waCalendars == null)
+ if (_waCalendars == null)
{
// We pass in an array of ints, and native side fills it up with count calendars.
// We then have to copy that list to a new array of the right size.
// Default calendar should be first
- int[] calendarInts = new int[23];
- Debug.Assert(this.sWindowsName != null, "[CultureData.CalendarIds] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
- int count = CalendarData.nativeGetCalendars(this.sWindowsName, this.bUseOverrides, calendarInts);
+ CalendarId[] calendars = new CalendarId[23];
+ Debug.Assert(_sWindowsName != null, "[CultureData.CalendarIds] Expected _sWindowsName to be populated by already");
+ int count = CalendarData.GetCalendars(_sWindowsName, _bUseOverrides, calendars);
// See if we had a calendar to add.
if (count == 0)
{
// Failed for some reason, just grab Gregorian from Invariant
- this.waCalendars = Invariant.waCalendars;
+ _waCalendars = Invariant._waCalendars;
}
else
{
// The OS may not return calendar 4 for zh-TW, but we've always allowed it.
- if (this.sWindowsName == "zh-TW")
+ // TODO: Is this hack necessary long-term?
+ if (_sWindowsName == "zh-TW")
{
bool found = false;
@@ -1804,7 +1824,7 @@ namespace System.Globalization
for (int i = 0; i < count; i++)
{
// Stop if we found calendar four
- if (calendarInts[i] == Calendar.CAL_TAIWAN)
+ if (calendars[i] == CalendarId.TAIWAN)
{
found = true;
break;
@@ -1817,21 +1837,20 @@ namespace System.Globalization
// Insert it as the 2nd calendar
count++;
// Copy them from the 2nd position to the end, -1 for skipping 1st, -1 for one being added.
- Array.Copy(calendarInts, 1, calendarInts, 2, 23 - 1 - 1);
- calendarInts[1] = Calendar.CAL_TAIWAN;
+ Array.Copy(calendars, 1, calendars, 2, 23 - 1 - 1);
+ calendars[1] = CalendarId.TAIWAN;
}
}
// It worked, remember the list
- int[] temp = new int[count];
- Array.Copy(calendarInts, temp, count);
+ CalendarId[] temp = new CalendarId[count];
+ Array.Copy(calendars, temp, count);
// Want 1st calendar to be default
// Prior to Vista the enumeration didn't have default calendar first
- // Only a coreclr concern, culture.dll does the right thing.
if (temp.Length > 1)
{
- int i = DoGetLocaleInfoInt(LOCALE_ICALENDARTYPE);
+ CalendarId i = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType);
if (temp[1] == i)
{
temp[1] = temp[0];
@@ -1839,45 +1858,45 @@ namespace System.Globalization
}
}
- this.waCalendars = temp;
+ _waCalendars = temp;
}
}
- return this.waCalendars;
+ return _waCalendars;
}
}
// Native calendar names. index of optional calendar - 1, empty if no optional calendar at that number
- internal String CalendarName(int calendarId)
+ internal string CalendarName(CalendarId calendarId)
{
// Get the calendar
return GetCalendar(calendarId).sNativeName;
}
- internal CalendarData GetCalendar(int calendarId)
+ internal CalendarData GetCalendar(CalendarId calendarId)
{
- Debug.Assert(calendarId > 0 && calendarId <= CalendarData.MAX_CALENDARS,
+ Debug.Assert(calendarId > 0 && calendarId <= CalendarId.LAST_CALENDAR,
"[CultureData.GetCalendar] Expect calendarId to be in a valid range");
// arrays are 0 based, calendarIds are 1 based
- int calendarIndex = calendarId - 1;
+ int calendarIndex = (int)calendarId - 1;
// Have to have calendars
- if (calendars == null)
+ if (_calendars == null)
{
- calendars = new CalendarData[CalendarData.MAX_CALENDARS];
+ _calendars = new CalendarData[CalendarData.MAX_CALENDARS];
}
// we need the following local variable to avoid returning null
// when another thread creates a new array of CalendarData (above)
// right after we insert the newly created CalendarData (below)
- CalendarData calendarData = calendars[calendarIndex];
+ CalendarData calendarData = _calendars[calendarIndex];
// Make sure that calendar has data
- if (calendarData == null || UseUserOverride)
+ if (calendarData == null)
{
- Debug.Assert(this.sWindowsName != null, "[CultureData.GetCalendar] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
- calendarData = new CalendarData(this.sWindowsName, calendarId, this.UseUserOverride);
- calendars[calendarIndex] = calendarData;
+ Debug.Assert(_sWindowsName != null, "[CultureData.GetCalendar] Expected _sWindowsName to be populated by already");
+ calendarData = new CalendarData(_sWindowsName, calendarId, this.UseUserOverride);
+ _calendars[calendarIndex] = calendarData;
}
return calendarData;
@@ -1913,13 +1932,13 @@ namespace System.Globalization
{
get
{
- if (this.iReadingLayout == undef)
+ if (_iReadingLayout == undef)
{
- Debug.Assert(this.sRealName != null, "[CultureData.IsRightToLeft] Expected this.sRealName to be populated by COMNlsInfo::nativeInitCultureData already");
- this.iReadingLayout = DoGetLocaleInfoInt(LOCALE_IREADINGLAYOUT);
+ Debug.Assert(_sRealName != null, "[CultureData.IsRightToLeft] Expected _sRealName to be populated by already");
+ _iReadingLayout = GetLocaleInfo(LocaleNumberData.ReadingLayout);
}
- return (this.iReadingLayout);
+ return (_iReadingLayout);
}
}
@@ -1934,23 +1953,10 @@ namespace System.Globalization
{
get
{
- if (this.sTextInfo == null)
- {
- // LOCALE_SSORTLOCALE is broken in Win7 for Alt sorts.
- // It is also not supported downlevel without culture.dll.
- if (IsNeutralCulture || IsSupplementalCustomCulture)
- {
- string sortLocale = DoGetLocaleInfo(LOCALE_SSORTLOCALE);
- this.sTextInfo = GetCultureData(sortLocale, bUseOverrides).SNAME;
- }
-
- if (this.sTextInfo == null)
- {
- this.sTextInfo = this.SNAME; // removes alternate sort
- }
- }
-
- return this.sTextInfo;
+ // Note: Custom cultures might point at another culture's textinfo, however windows knows how
+ // to redirect it to the desired textinfo culture, so this is OK.
+ Debug.Assert(_sRealName != null, "[CultureData.STEXTINFO] Expected _sRealName to be populated by already");
+ return (_sRealName);
}
}
@@ -1959,24 +1965,8 @@ namespace System.Globalization
{
get
{
- if (this.sCompareInfo == null)
- {
- // LOCALE_SSORTLOCALE is broken in Win7 for Alt sorts.
- // It is also not supported downlevel without culture.dll.
- // We really only need it for the custom locale case though
- // since for all other cases, it is the same as sWindowsName
- if (IsSupplementalCustomCulture)
- {
- this.sCompareInfo = DoGetLocaleInfo(LOCALE_SSORTLOCALE);
- }
-
- if (this.sCompareInfo == null)
- {
- this.sCompareInfo = this.sWindowsName;
- }
- }
-
- return this.sCompareInfo;
+ Debug.Assert(_sRealName != null, "[CultureData.SCOMPAREINFO] Expected _sRealName to be populated by already");
+ return (_sRealName);
}
}
@@ -1988,16 +1978,15 @@ namespace System.Globalization
}
}
-
internal int IDEFAULTANSICODEPAGE // default ansi code page ID (ACP)
{
get
{
- if (this.iDefaultAnsiCodePage == undef)
+ if (_iDefaultAnsiCodePage == undef)
{
- this.iDefaultAnsiCodePage = DoGetLocaleInfoInt(LOCALE_IDEFAULTANSICODEPAGE);
+ _iDefaultAnsiCodePage = GetAnsiCodePage(_sRealName);
}
- return this.iDefaultAnsiCodePage;
+ return _iDefaultAnsiCodePage;
}
}
@@ -2005,11 +1994,11 @@ namespace System.Globalization
{
get
{
- if (this.iDefaultOemCodePage == undef)
+ if (_iDefaultOemCodePage == undef)
{
- this.iDefaultOemCodePage = DoGetLocaleInfoInt(LOCALE_IDEFAULTCODEPAGE);
+ _iDefaultOemCodePage = GetOemCodePage(_sRealName);
}
- return this.iDefaultOemCodePage;
+ return _iDefaultOemCodePage;
}
}
@@ -2017,11 +2006,11 @@ namespace System.Globalization
{
get
{
- if (this.iDefaultMacCodePage == undef)
+ if (_iDefaultMacCodePage == undef)
{
- this.iDefaultMacCodePage = DoGetLocaleInfoInt(LOCALE_IDEFAULTMACCODEPAGE);
+ _iDefaultMacCodePage = GetMacCodePage(_sRealName);
}
- return this.iDefaultMacCodePage;
+ return _iDefaultMacCodePage;
}
}
@@ -2029,54 +2018,33 @@ namespace System.Globalization
{
get
{
- if (this.iDefaultEbcdicCodePage == undef)
+ if (_iDefaultEbcdicCodePage == undef)
{
- this.iDefaultEbcdicCodePage = DoGetLocaleInfoInt(LOCALE_IDEFAULTEBCDICCODEPAGE);
+ _iDefaultEbcdicCodePage = GetEbcdicCodePage(_sRealName);
}
- return this.iDefaultEbcdicCodePage;
+ return _iDefaultEbcdicCodePage;
}
}
- // Obtain locale name from LCID
- // NOTE: This will get neutral names, unlike the OS API
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern int LocaleNameToLCID(String localeName);
-
- // These are desktop only, not coreclr
- // locale ID (0409), including sort information
internal int ILANGUAGE
{
get
{
- if (this.iLanguage == 0)
+ if (_iLanguage == 0)
{
- Debug.Assert(this.sRealName != null, "[CultureData.ILANGUAGE] Expected this.sRealName to be populated by COMNlsInfo::nativeInitCultureData already");
- this.iLanguage = LocaleNameToLCID(this.sRealName);
+ Debug.Assert(_sRealName != null, "[CultureData.ILANGUAGE] Expected this.sRealName to be populated already");
+ _iLanguage = LocaleNameToLCID(_sRealName);
}
- return this.iLanguage;
+ return _iLanguage;
}
}
- internal bool IsWin32Installed
- {
- get { return this.bWin32Installed; }
- }
-
- internal bool IsFramework
- {
- get { return this.bFramework; }
- }
-
- ////////////////////
- // Derived properties //
- ////////////////////
-
internal bool IsNeutralCulture
{
get
{
- // NlsInfo::nativeInitCultureData told us if we're neutral or not
- return this.bNeutral;
+ // InitCultureData told us if we're neutral or not
+ return _bNeutral;
}
}
@@ -2093,7 +2061,13 @@ namespace System.Globalization
{
get
{
- int defaultCalId = DoGetLocaleInfoInt(LOCALE_ICALENDARTYPE);
+ if (GlobalizationMode.Invariant)
+ {
+ return CultureInfo.GetCalendarInstance(CalendarIds[0]);
+ }
+
+ CalendarId defaultCalId = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType);
+
if (defaultCalId == 0)
{
defaultCalId = this.CalendarIds[0];
@@ -2104,29 +2078,29 @@ namespace System.Globalization
}
// All of our era names
- internal String[] EraNames(int calendarId)
+ internal String[] EraNames(CalendarId calendarId)
{
Debug.Assert(calendarId > 0, "[CultureData.saEraNames] Expected Calendar.ID > 0");
return this.GetCalendar(calendarId).saEraNames;
}
- internal String[] AbbrevEraNames(int calendarId)
+ internal String[] AbbrevEraNames(CalendarId calendarId)
{
Debug.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0");
return this.GetCalendar(calendarId).saAbbrevEraNames;
}
- internal String[] AbbreviatedEnglishEraNames(int calendarId)
+ internal String[] AbbreviatedEnglishEraNames(CalendarId calendarId)
{
Debug.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0");
return this.GetCalendar(calendarId).saAbbrevEnglishEraNames;
}
- // String array DEFAULTS
- // Note: GetDTFIOverrideValues does the user overrides for these, so we don't have to.
+ //// String array DEFAULTS
+ //// Note: GetDTFIOverrideValues does the user overrides for these, so we don't have to.
// Time separator (derived from time format)
@@ -2134,23 +2108,23 @@ namespace System.Globalization
{
get
{
- if (sTimeSeparator == null || UseUserOverride)
+ if (_sTimeSeparator == null)
{
- string longTimeFormat = ReescapeWin32String(DoGetLocaleInfo(LOCALE_STIMEFORMAT));
+ string longTimeFormat = GetTimeFormatString();
if (String.IsNullOrEmpty(longTimeFormat))
{
longTimeFormat = LongTimes[0];
}
// Compute STIME from time format
- sTimeSeparator = GetTimeSeparator(longTimeFormat);
+ _sTimeSeparator = GetTimeSeparator(longTimeFormat);
}
- return sTimeSeparator;
+ return _sTimeSeparator;
}
}
// Date separator (derived from short date format)
- internal String DateSeparator(int calendarId)
+ internal String DateSeparator(CalendarId calendarId)
{
return GetDateSeparator(ShortDates(calendarId)[0]);
}
@@ -2178,11 +2152,11 @@ namespace System.Globalization
// always build a stringbuilder because we need to remove the ' or \.
//
////////////////////////////////////////////////////////////////////////////
- static private String UnescapeNlsString(String str, int start, int end)
+ private static String UnescapeNlsString(String str, int start, int end)
{
- Contract.Requires(str != null);
- Contract.Requires(start >= 0);
- Contract.Requires(end >= 0);
+ Debug.Assert(str != null);
+ Debug.Assert(start >= 0);
+ Debug.Assert(end >= 0);
StringBuilder result = null;
for (int i = start; i < str.Length && i <= end; i++)
@@ -2221,102 +2195,7 @@ namespace System.Globalization
return (result.ToString());
}
- ////////////////////////////////////////////////////////////////////////////
- //
- // Reescape a Win32 style quote string as a NLS+ style quoted string
- //
- // This is also the escaping style used by custom culture data files
- //
- // NLS+ uses \ to escape the next character, whether in a quoted string or
- // not, so we always have to change \ to \\.
- //
- // NLS+ uses \' to escape a quote inside a quoted string so we have to change
- // '' to \' (if inside a quoted string)
- //
- // We don't build the stringbuilder unless we find something to change
- ////////////////////////////////////////////////////////////////////////////
- static internal String ReescapeWin32String(String str)
- {
- // If we don't have data, then don't try anything
- if (str == null)
- return null;
-
- StringBuilder result = null;
-
- bool inQuote = false;
- for (int i = 0; i < str.Length; i++)
- {
- // Look for quote
- if (str[i] == '\'')
- {
- // Already in quote?
- if (inQuote)
- {
- // See another single quote. Is this '' of 'fred''s' or '''', or is it an ending quote?
- if (i + 1 < str.Length && str[i + 1] == '\'')
- {
- // Found another ', so we have ''. Need to add \' instead.
- // 1st make sure we have our stringbuilder
- if (result == null)
- result = new StringBuilder(str, 0, i, str.Length * 2);
-
- // Append a \' and keep going (so we don't turn off quote mode)
- result.Append("\\'");
- i++;
- continue;
- }
-
- // Turning off quote mode, fall through to add it
- inQuote = false;
- }
- else
- {
- // Found beginning quote, fall through to add it
- inQuote = true;
- }
- }
- // Is there a single \ character?
- else if (str[i] == '\\')
- {
- // Found a \, need to change it to \\
- // 1st make sure we have our stringbuilder
- if (result == null)
- result = new StringBuilder(str, 0, i, str.Length * 2);
-
- // Append our \\ to the string & continue
- result.Append("\\\\");
- continue;
- }
-
- // If we have a builder we need to add our character
- if (result != null)
- result.Append(str[i]);
- }
-
- // Unchanged string? , just return input string
- if (result == null)
- return str;
-
- // String changed, need to use the builder
- return result.ToString();
- }
-
- static internal String[] ReescapeWin32Strings(String[] array)
- {
- if (array != null)
- {
- for (int i = 0; i < array.Length; i++)
- {
- array[i] = ReescapeWin32String(array[i]);
- }
- }
-
- return array;
- }
-
- // NOTE: this method is used through reflection by System.Globalization.CultureXmlParser.ReadDateElement()
- // and breaking changes here will not show up at build time, only at run time.
- static private String GetTimeSeparator(String format)
+ private static String GetTimeSeparator(String format)
{
// Time format separator (ie: : in 12:39:00)
//
@@ -2329,9 +2208,7 @@ namespace System.Globalization
return GetSeparator(format, "Hhms");
}
- // NOTE: this method is used through reflection by System.Globalization.CultureXmlParser.ReadDateElement()
- // and breaking changes here will not show up at build time, only at run time.
- static private String GetDateSeparator(String format)
+ private static String GetDateSeparator(String format)
{
// Date format separator (ie: / in 9/1/03)
//
@@ -2413,128 +2290,61 @@ namespace System.Globalization
return -1;
}
- string DoGetLocaleInfo(uint lctype)
- {
- Debug.Assert(this.sWindowsName != null, "[CultureData.DoGetLocaleInfo] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
- return DoGetLocaleInfo(this.sWindowsName, lctype);
- }
-
- // For LOCALE_SPARENT we need the option of using the "real" name (forcing neutral names) instead of the
- // "windows" name, which can be specific for downlevel (< windows 7) os's.
- string DoGetLocaleInfo(string localeName, uint lctype)
- {
- // Fix lctype if we don't want overrides
- if (!UseUserOverride)
- {
- lctype |= LOCALE_NOUSEROVERRIDE;
- }
-
- // Ask OS for data
- Debug.Assert(localeName != null, "[CultureData.DoGetLocaleInfo] Expected localeName to be not be null");
- string result = CultureInfo.nativeGetLocaleInfoEx(localeName, lctype);
- if (result == null)
- {
- // Failed, just use empty string
- result = String.Empty;
- }
-
- return result;
- }
-
- int DoGetLocaleInfoInt(uint lctype)
- {
- // Fix lctype if we don't want overrides
- if (!UseUserOverride)
- {
- lctype |= LOCALE_NOUSEROVERRIDE;
- }
-
- // Ask OS for data, note that we presume it returns success, so we have to know that
- // sWindowsName is valid before calling.
- Debug.Assert(this.sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
- int result = CultureInfo.nativeGetLocaleInfoExInt(this.sWindowsName, lctype);
-
- return result;
- }
-
- String[] DoEnumTimeFormats()
- {
- // Note that this gets overrides for us all the time
- Debug.Assert(this.sWindowsName != null, "[CultureData.DoEnumTimeFormats] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
- String[] result = ReescapeWin32Strings(nativeEnumTimeFormats(this.sWindowsName, 0, UseUserOverride));
-
- return result;
- }
-
- String[] DoEnumShortTimeFormats()
- {
- // Note that this gets overrides for us all the time
- Debug.Assert(this.sWindowsName != null, "[CultureData.DoEnumShortTimeFormats] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
- String[] result = ReescapeWin32Strings(nativeEnumTimeFormats(this.sWindowsName, TIME_NOSECONDS, UseUserOverride));
-
- return result;
- }
-
- /////////////////
- // Static Helpers //
- ////////////////
internal static bool IsCustomCultureId(int cultureId)
{
- if (cultureId == CultureInfo.LOCALE_CUSTOM_DEFAULT || cultureId == CultureInfo.LOCALE_CUSTOM_UNSPECIFIED)
- return true;
-
- return false;
+ return (cultureId == CultureInfo.LOCALE_CUSTOM_DEFAULT || cultureId == CultureInfo.LOCALE_CUSTOM_UNSPECIFIED);
}
- ////////////////////////////////////////////////////////////////////////////
- //
- // Parameters:
- // calendarValueOnly Retrieve the values which are affected by the calendar change of DTFI.
- // This will cause values like longTimePattern not be retrieved since it is
- // not affected by the Calendar property in DTFI.
- //
- ////////////////////////////////////////////////////////////////////////////
internal void GetNFIValues(NumberFormatInfo nfi)
{
- if (this.IsInvariantCulture)
+ if (GlobalizationMode.Invariant || this.IsInvariantCulture)
{
- nfi.positiveSign = this.sPositiveSign;
- nfi.negativeSign = this.sNegativeSign;
-
- nfi.nativeDigits = this.saNativeDigits;
- nfi.digitSubstitution = this.iDigitSubstitution;
+ // FUTURE: NumberFormatInfo already has default values for many of these fields. Can we not do this?
+ nfi.positiveSign = _sPositiveSign;
+ nfi.negativeSign = _sNegativeSign;
- nfi.numberGroupSeparator = this.sThousandSeparator;
- nfi.numberDecimalSeparator = this.sDecimalSeparator;
- nfi.numberDecimalDigits = this.iDigits;
- nfi.numberNegativePattern = this.iNegativeNumber;
+ nfi.numberGroupSeparator = _sThousandSeparator;
+ nfi.numberDecimalSeparator = _sDecimalSeparator;
+ nfi.numberDecimalDigits = _iDigits;
+ nfi.numberNegativePattern = _iNegativeNumber;
- nfi.currencySymbol = this.sCurrency;
- nfi.currencyGroupSeparator = this.sMonetaryThousand;
- nfi.currencyDecimalSeparator = this.sMonetaryDecimal;
- nfi.currencyDecimalDigits = this.iCurrencyDigits;
- nfi.currencyNegativePattern = this.iNegativeCurrency;
- nfi.currencyPositivePattern = this.iCurrency;
+ nfi.currencySymbol = _sCurrency;
+ nfi.currencyGroupSeparator = _sMonetaryThousand;
+ nfi.currencyDecimalSeparator = _sMonetaryDecimal;
+ nfi.currencyDecimalDigits = _iCurrencyDigits;
+ nfi.currencyNegativePattern = _iNegativeCurrency;
+ nfi.currencyPositivePattern = _iCurrency;
}
else
{
- //
- // We don't have information for the following four. All cultures use
- // the same value of the number formatting values.
- //
- // PercentDecimalDigits
- // PercentDecimalSeparator
- // PercentGroupSize
- // PercentGroupSeparator
- //
+ Debug.Assert(_sWindowsName != null, "[CultureData.GetNFIValues] Expected _sWindowsName to be populated by already");
+ // String values
+ nfi.positiveSign = GetLocaleInfo(LocaleStringData.PositiveSign);
+ nfi.negativeSign = GetLocaleInfo(LocaleStringData.NegativeSign);
- //
- // Ask native side for our data.
- //
- Debug.Assert(this.sWindowsName != null, "[CultureData.GetNFIValues] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
- CultureData.nativeGetNumberFormatInfoValues(this.sWindowsName, nfi, UseUserOverride);
- }
+ nfi.numberDecimalSeparator = GetLocaleInfo(LocaleStringData.DecimalSeparator);
+ nfi.numberGroupSeparator = GetLocaleInfo(LocaleStringData.ThousandSeparator);
+ nfi.currencyGroupSeparator = GetLocaleInfo(LocaleStringData.MonetaryThousandSeparator);
+ nfi.currencyDecimalSeparator = GetLocaleInfo(LocaleStringData.MonetaryDecimalSeparator);
+ nfi.currencySymbol = GetLocaleInfo(LocaleStringData.MonetarySymbol);
+
+ // Numeric values
+ nfi.numberDecimalDigits = GetLocaleInfo(LocaleNumberData.FractionalDigitsCount);
+ nfi.currencyDecimalDigits = GetLocaleInfo(LocaleNumberData.MonetaryFractionalDigitsCount);
+ nfi.currencyPositivePattern = GetLocaleInfo(LocaleNumberData.PositiveMonetaryNumberFormat);
+ nfi.currencyNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeMonetaryNumberFormat);
+ nfi.numberNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeNumberFormat);
+ // LOCALE_SNATIVEDIGITS (array of 10 single character strings).
+ string digits = GetLocaleInfo(LocaleStringData.Digits);
+ nfi.nativeDigits = new string[10];
+ for (int i = 0; i < nfi.nativeDigits.Length; i++)
+ {
+ nfi.nativeDigits[i] = new string(digits[i], 1);
+ }
+
+ nfi.digitSubstitution = GetDigitSubstitution(_sRealName);
+ }
//
// Gather additional data
@@ -2569,289 +2379,188 @@ namespace System.Globalization
//Special case for Italian. The currency decimal separator in the control panel is the empty string. When the user
//specifies C4 as the currency format, this results in the number apparently getting multiplied by 10000 because the
- //decimal point doesn't show up. We'll just workaround this here because our default currency format will never use nfi.
+ //decimal point doesn't show up. We'll just hack this here because our default currency format will never use nfi.
if (nfi.currencyDecimalSeparator == null || nfi.currencyDecimalSeparator.Length == 0)
{
nfi.currencyDecimalSeparator = nfi.numberDecimalSeparator;
}
}
- static private int ConvertFirstDayOfWeekMonToSun(int iTemp)
- {
- // Convert Mon-Sun to Sun-Sat format
- iTemp++;
- if (iTemp > 6)
- {
- // Wrap Sunday and convert invalid data to Sunday
- iTemp = 0;
- }
- return iTemp;
- }
-
// Helper
// This is ONLY used for caching names and shouldn't be used for anything else
internal static string AnsiToLower(string testString)
{
- StringBuilder sb = new StringBuilder(testString.Length);
-
- for (int ich = 0; ich < testString.Length; ich++)
+ int index = 0;
+
+ while (index<testString.Length && (testString[index]<'A' || testString[index]>'Z' ))
{
- char ch = testString[ich];
- sb.Append(ch <= 'Z' && ch >= 'A' ? (char)(ch - 'A' + 'a') : ch);
+ index++;
}
-
- return (sb.ToString());
- }
-
- // If we get a group from windows, then its in 3;0 format with the 0 backwards
- // of how NLS+ uses it (ie: if the string has a 0, then the int[] shouldn't and vice versa)
- // EXCEPT in the case where the list only contains 0 in which NLS and NLS+ have the same meaning.
- static private int[] ConvertWin32GroupString(String win32Str)
- {
- // None of these cases make any sense
- if (win32Str == null || win32Str.Length == 0)
+ if (index >= testString.Length)
{
- return (new int[] { 3 });
+ return testString; // we didn't really change the string
}
-
- if (win32Str[0] == '0')
+
+ StringBuilder sb = new StringBuilder(testString.Length);
+ for (int i=0; i<index; i++)
{
- return (new int[] { 0 });
+ sb.Append(testString[i]);
}
- // Since its in n;n;n;n;n format, we can always get the length quickly
- int[] values;
- if (win32Str[win32Str.Length - 1] == '0')
- {
- // Trailing 0 gets dropped. 1;0 -> 1
- values = new int[(win32Str.Length / 2)];
- }
- else
- {
- // Need extra space for trailing zero 1 -> 1;0
- values = new int[(win32Str.Length / 2) + 2];
- values[values.Length - 1] = 0;
- }
+ sb.Append((char) (testString[index] -'A' + 'a'));
- int i;
- int j;
- for (i = 0, j = 0; i < win32Str.Length && j < values.Length; i += 2, j++)
+ for (int ich = index+1; ich < testString.Length; ich++)
{
- // Note that this # shouldn't ever be zero, 'cause 0 is only at end
- // But we'll test because its registry that could be anything
- if (win32Str[i] < '1' || win32Str[i] > '9')
- return new int[] { 3 };
-
- values[j] = (int)(win32Str[i] - '0');
+ char ch = testString[ich];
+ sb.Append(ch <= 'Z' && ch >= 'A' ? (char)(ch - 'A' + 'a') : ch);
}
- return (values);
+ return (sb.ToString());
}
- // LCTYPES for GetLocaleInfo
- private const uint LOCALE_NOUSEROVERRIDE = 0x80000000; // do not use user overrides
- private const uint LOCALE_RETURN_NUMBER = 0x20000000; // return number instead of string
-
- // Modifier for genitive names
- private const uint LOCALE_RETURN_GENITIVE_NAMES = 0x10000000; //Flag to return the Genitive forms of month names
-
- //
- // The following LCTypes are mutually exclusive in that they may NOT
- // be used in combination with each other.
- //
-
- //
- // These are the various forms of the name of the locale:
- //
- private const uint LOCALE_SLOCALIZEDDISPLAYNAME = 0x00000002; // localized name of locale, eg "German (Germany)" in UI language
- private const uint LOCALE_SENGLISHDISPLAYNAME = 0x00000072; // Display name (language + country usually) in English, eg "German (Germany)"
- private const uint LOCALE_SNATIVEDISPLAYNAME = 0x00000073; // Display name in native locale language, eg "Deutsch (Deutschland)
-
- private const uint LOCALE_SLOCALIZEDLANGUAGENAME = 0x0000006f; // Language Display Name for a language, eg "German" in UI language
- private const uint LOCALE_SENGLISHLANGUAGENAME = 0x00001001; // English name of language, eg "German"
- private const uint LOCALE_SNATIVELANGUAGENAME = 0x00000004; // native name of language, eg "Deutsch"
-
- private const uint LOCALE_SLOCALIZEDCOUNTRYNAME = 0x00000006; // localized name of country, eg "Germany" in UI language
- private const uint LOCALE_SENGLISHCOUNTRYNAME = 0x00001002; // English name of country, eg "Germany"
- private const uint LOCALE_SNATIVECOUNTRYNAME = 0x00000008; // native name of country, eg "Deutschland"
-
-
- // private const uint LOCALE_ILANGUAGE =0x00000001; // language id // Don't use, use NewApis::LocaleNameToLCID instead (GetLocaleInfo doesn't return neutrals)
-
- // private const uint LOCALE_SLANGUAGE =LOCALE_SLOCALIZEDDISPLAYNAME; // localized name of language (use LOCALE_SLOCALIZEDDISPLAYNAME instead)
- // private const uint LOCALE_SENGLANGUAGE =LOCALE_SENGLISHLANGUAGENAME; // English name of language (use LOCALE_SENGLISHLANGUAGENAME instead)
- private const uint LOCALE_SABBREVLANGNAME = 0x00000003; // abbreviated language name
- // private const uint LOCALE_SNATIVELANGNAME =LOCALE_SNATIVELANGUAGENAME; // native name of language (use LOCALE_SNATIVELANGUAGENAME instead)
-
- private const uint LOCALE_ICOUNTRY = 0x00000005; // country code
- // private const uint LOCALE_SCOUNTRY =LOCALE_SLOCALIZEDCOUNTRYNAME; // localized name of country (use LOCALE_SLOCALIZEDCOUNTRYNAME instead)
- // private const uint LOCALE_SENGCOUNTRY =LOCALE_SENGLISHCOUNTRYNAME; // English name of country (use LOCALE_SENGLISHCOUNTRYNAME instead)
- private const uint LOCALE_SABBREVCTRYNAME = 0x00000007; // abbreviated country name
- // private const uint LOCALE_SNATIVECTRYNAME =LOCALE_SNATIVECOUNTRYNAME; // native name of country ( use LOCALE_SNATIVECOUNTRYNAME instead)
- private const uint LOCALE_IGEOID = 0x0000005B; // geographical location id
-
- private const uint LOCALE_IDEFAULTLANGUAGE = 0x00000009; // default language id
- private const uint LOCALE_IDEFAULTCOUNTRY = 0x0000000A; // default country code
- private const uint LOCALE_IDEFAULTCODEPAGE = 0x0000000B; // default oem code page
- private const uint LOCALE_IDEFAULTANSICODEPAGE = 0x00001004; // default ansi code page
- private const uint LOCALE_IDEFAULTMACCODEPAGE = 0x00001011; // default mac code page
-
- private const uint LOCALE_SLIST = 0x0000000C; // list item separator
- private const uint LOCALE_IMEASURE = 0x0000000D; // 0 = metric, 1 = US
-
- private const uint LOCALE_SDECIMAL = 0x0000000E; // decimal separator
- private const uint LOCALE_STHOUSAND = 0x0000000F; // thousand separator
- private const uint LOCALE_SGROUPING = 0x00000010; // digit grouping
- private const uint LOCALE_IDIGITS = 0x00000011; // number of fractional digits
- private const uint LOCALE_ILZERO = 0x00000012; // leading zeros for decimal
- private const uint LOCALE_INEGNUMBER = 0x00001010; // negative number mode
- private const uint LOCALE_SNATIVEDIGITS = 0x00000013; // native digits for 0-9
-
- private const uint LOCALE_SCURRENCY = 0x00000014; // local monetary symbol
- private const uint LOCALE_SINTLSYMBOL = 0x00000015; // uintl monetary symbol
- private const uint LOCALE_SMONDECIMALSEP = 0x00000016; // monetary decimal separator
- private const uint LOCALE_SMONTHOUSANDSEP = 0x00000017; // monetary thousand separator
- private const uint LOCALE_SMONGROUPING = 0x00000018; // monetary grouping
- private const uint LOCALE_ICURRDIGITS = 0x00000019; // # local monetary digits
- private const uint LOCALE_IINTLCURRDIGITS = 0x0000001A; // # uintl monetary digits
- private const uint LOCALE_ICURRENCY = 0x0000001B; // positive currency mode
- private const uint LOCALE_INEGCURR = 0x0000001C; // negative currency mode
-
- private const uint LOCALE_SDATE = 0x0000001D; // date separator (derived from LOCALE_SSHORTDATE, use that instead)
- private const uint LOCALE_STIME = 0x0000001E; // time separator (derived from LOCALE_STIMEFORMAT, use that instead)
- private const uint LOCALE_SSHORTDATE = 0x0000001F; // short date format string
- private const uint LOCALE_SLONGDATE = 0x00000020; // long date format string
- private const uint LOCALE_STIMEFORMAT = 0x00001003; // time format string
- private const uint LOCALE_IDATE = 0x00000021; // short date format ordering (derived from LOCALE_SSHORTDATE, use that instead)
- private const uint LOCALE_ILDATE = 0x00000022; // long date format ordering (derived from LOCALE_SLONGDATE, use that instead)
- private const uint LOCALE_ITIME = 0x00000023; // time format specifier (derived from LOCALE_STIMEFORMAT, use that instead)
- private const uint LOCALE_ITIMEMARKPOSN = 0x00001005; // time marker position (derived from LOCALE_STIMEFORMAT, use that instead)
- private const uint LOCALE_ICENTURY = 0x00000024; // century format specifier (short date, LOCALE_SSHORTDATE is preferred)
- private const uint LOCALE_ITLZERO = 0x00000025; // leading zeros in time field (derived from LOCALE_STIMEFORMAT, use that instead)
- private const uint LOCALE_IDAYLZERO = 0x00000026; // leading zeros in day field (short date, LOCALE_SSHORTDATE is preferred)
- private const uint LOCALE_IMONLZERO = 0x00000027; // leading zeros in month field (short date, LOCALE_SSHORTDATE is preferred)
- private const uint LOCALE_S1159 = 0x00000028; // AM designator
- private const uint LOCALE_S2359 = 0x00000029; // PM designator
-
- private const uint LOCALE_ICALENDARTYPE = 0x00001009; // type of calendar specifier
- private const uint LOCALE_IOPTIONALCALENDAR = 0x0000100B; // additional calendar types specifier
- private const uint LOCALE_IFIRSTDAYOFWEEK = 0x0000100C; // first day of week specifier
- private const uint LOCALE_IFIRSTWEEKOFYEAR = 0x0000100D; // first week of year specifier
-
- private const uint LOCALE_SDAYNAME1 = 0x0000002A; // long name for Monday
- private const uint LOCALE_SDAYNAME2 = 0x0000002B; // long name for Tuesday
- private const uint LOCALE_SDAYNAME3 = 0x0000002C; // long name for Wednesday
- private const uint LOCALE_SDAYNAME4 = 0x0000002D; // long name for Thursday
- private const uint LOCALE_SDAYNAME5 = 0x0000002E; // long name for Friday
- private const uint LOCALE_SDAYNAME6 = 0x0000002F; // long name for Saturday
- private const uint LOCALE_SDAYNAME7 = 0x00000030; // long name for Sunday
- private const uint LOCALE_SABBREVDAYNAME1 = 0x00000031; // abbreviated name for Monday
- private const uint LOCALE_SABBREVDAYNAME2 = 0x00000032; // abbreviated name for Tuesday
- private const uint LOCALE_SABBREVDAYNAME3 = 0x00000033; // abbreviated name for Wednesday
- private const uint LOCALE_SABBREVDAYNAME4 = 0x00000034; // abbreviated name for Thursday
- private const uint LOCALE_SABBREVDAYNAME5 = 0x00000035; // abbreviated name for Friday
- private const uint LOCALE_SABBREVDAYNAME6 = 0x00000036; // abbreviated name for Saturday
- private const uint LOCALE_SABBREVDAYNAME7 = 0x00000037; // abbreviated name for Sunday
- private const uint LOCALE_SMONTHNAME1 = 0x00000038; // long name for January
- private const uint LOCALE_SMONTHNAME2 = 0x00000039; // long name for February
- private const uint LOCALE_SMONTHNAME3 = 0x0000003A; // long name for March
- private const uint LOCALE_SMONTHNAME4 = 0x0000003B; // long name for April
- private const uint LOCALE_SMONTHNAME5 = 0x0000003C; // long name for May
- private const uint LOCALE_SMONTHNAME6 = 0x0000003D; // long name for June
- private const uint LOCALE_SMONTHNAME7 = 0x0000003E; // long name for July
- private const uint LOCALE_SMONTHNAME8 = 0x0000003F; // long name for August
- private const uint LOCALE_SMONTHNAME9 = 0x00000040; // long name for September
- private const uint LOCALE_SMONTHNAME10 = 0x00000041; // long name for October
- private const uint LOCALE_SMONTHNAME11 = 0x00000042; // long name for November
- private const uint LOCALE_SMONTHNAME12 = 0x00000043; // long name for December
- private const uint LOCALE_SMONTHNAME13 = 0x0000100E; // long name for 13th month (if exists)
- private const uint LOCALE_SABBREVMONTHNAME1 = 0x00000044; // abbreviated name for January
- private const uint LOCALE_SABBREVMONTHNAME2 = 0x00000045; // abbreviated name for February
- private const uint LOCALE_SABBREVMONTHNAME3 = 0x00000046; // abbreviated name for March
- private const uint LOCALE_SABBREVMONTHNAME4 = 0x00000047; // abbreviated name for April
- private const uint LOCALE_SABBREVMONTHNAME5 = 0x00000048; // abbreviated name for May
- private const uint LOCALE_SABBREVMONTHNAME6 = 0x00000049; // abbreviated name for June
- private const uint LOCALE_SABBREVMONTHNAME7 = 0x0000004A; // abbreviated name for July
- private const uint LOCALE_SABBREVMONTHNAME8 = 0x0000004B; // abbreviated name for August
- private const uint LOCALE_SABBREVMONTHNAME9 = 0x0000004C; // abbreviated name for September
- private const uint LOCALE_SABBREVMONTHNAME10 = 0x0000004D; // abbreviated name for October
- private const uint LOCALE_SABBREVMONTHNAME11 = 0x0000004E; // abbreviated name for November
- private const uint LOCALE_SABBREVMONTHNAME12 = 0x0000004F; // abbreviated name for December
- private const uint LOCALE_SABBREVMONTHNAME13 = 0x0000100F; // abbreviated name for 13th month (if exists)
-
- private const uint LOCALE_SPOSITIVESIGN = 0x00000050; // positive sign
- private const uint LOCALE_SNEGATIVESIGN = 0x00000051; // negative sign
- private const uint LOCALE_IPOSSIGNPOSN = 0x00000052; // positive sign position (derived from INEGCURR)
- private const uint LOCALE_INEGSIGNPOSN = 0x00000053; // negative sign position (derived from INEGCURR)
- private const uint LOCALE_IPOSSYMPRECEDES = 0x00000054; // mon sym precedes pos amt (derived from ICURRENCY)
- private const uint LOCALE_IPOSSEPBYSPACE = 0x00000055; // mon sym sep by space from pos amt (derived from ICURRENCY)
- private const uint LOCALE_INEGSYMPRECEDES = 0x00000056; // mon sym precedes neg amt (derived from INEGCURR)
- private const uint LOCALE_INEGSEPBYSPACE = 0x00000057; // mon sym sep by space from neg amt (derived from INEGCURR)
-
- private const uint LOCALE_FONTSIGNATURE = 0x00000058; // font signature
- private const uint LOCALE_SISO639LANGNAME = 0x00000059; // ISO abbreviated language name
- private const uint LOCALE_SISO3166CTRYNAME = 0x0000005A; // ISO abbreviated country name
-
- private const uint LOCALE_IDEFAULTEBCDICCODEPAGE = 0x00001012; // default ebcdic code page
- private const uint LOCALE_IPAPERSIZE = 0x0000100A; // 1 = letter, 5 = legal, 8 = a3, 9 = a4
- private const uint LOCALE_SENGCURRNAME = 0x00001007; // english name of currency
- private const uint LOCALE_SNATIVECURRNAME = 0x00001008; // native name of currency
- private const uint LOCALE_SYEARMONTH = 0x00001006; // year month format string
- private const uint LOCALE_SSORTNAME = 0x00001013; // sort name
- private const uint LOCALE_IDIGITSUBSTITUTION = 0x00001014; // 0 = context, 1 = none, 2 = national
-
- private const uint LOCALE_SNAME = 0x0000005c; // locale name (with sort info) (ie: de-DE_phoneb)
- private const uint LOCALE_SDURATION = 0x0000005d; // time duration format
- private const uint LOCALE_SKEYBOARDSTOINSTALL = 0x0000005e; // (windows only) keyboards to install
- private const uint LOCALE_SSHORTESTDAYNAME1 = 0x00000060; // Shortest day name for Monday
- private const uint LOCALE_SSHORTESTDAYNAME2 = 0x00000061; // Shortest day name for Tuesday
- private const uint LOCALE_SSHORTESTDAYNAME3 = 0x00000062; // Shortest day name for Wednesday
- private const uint LOCALE_SSHORTESTDAYNAME4 = 0x00000063; // Shortest day name for Thursday
- private const uint LOCALE_SSHORTESTDAYNAME5 = 0x00000064; // Shortest day name for Friday
- private const uint LOCALE_SSHORTESTDAYNAME6 = 0x00000065; // Shortest day name for Saturday
- private const uint LOCALE_SSHORTESTDAYNAME7 = 0x00000066; // Shortest day name for Sunday
- private const uint LOCALE_SISO639LANGNAME2 = 0x00000067; // 3 character ISO abbreviated language name
- private const uint LOCALE_SISO3166CTRYNAME2 = 0x00000068; // 3 character ISO country name
- private const uint LOCALE_SNAN = 0x00000069; // Not a Number
- private const uint LOCALE_SPOSINFINITY = 0x0000006a; // + Infinity
- private const uint LOCALE_SNEGINFINITY = 0x0000006b; // - Infinity
- private const uint LOCALE_SSCRIPTS = 0x0000006c; // Typical scripts in the locale
- private const uint LOCALE_SPARENT = 0x0000006d; // Fallback name for resources
- private const uint LOCALE_SCONSOLEFALLBACKNAME = 0x0000006e; // Fallback name for within the console
- // private const uint LOCALE_SLANGDISPLAYNAME =LOCALE_SLOCALIZEDLANGUAGENAME; // Language Display Name for a language (use LOCALE_SLOCALIZEDLANGUAGENAME instead)
-
- // Windows 7 LCTYPES
- private const uint LOCALE_IREADINGLAYOUT = 0x00000070; // Returns one of the following 4 reading layout values:
- // 0 - Left to right (eg en-US)
- // 1 - Right to left (eg arabic locales)
- // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
- // 3 - Vertical top to bottom with columns proceeding to the right
- private const uint LOCALE_INEUTRAL = 0x00000071; // Returns 0 for specific cultures, 1 for neutral cultures.
- private const uint LOCALE_INEGATIVEPERCENT = 0x00000074; // Returns 0-11 for the negative percent format
- private const uint LOCALE_IPOSITIVEPERCENT = 0x00000075; // Returns 0-3 for the positive percent formatIPOSITIVEPERCENT
- private const uint LOCALE_SPERCENT = 0x00000076; // Returns the percent symbol
- private const uint LOCALE_SPERMILLE = 0x00000077; // Returns the permille (U+2030) symbol
- private const uint LOCALE_SMONTHDAY = 0x00000078; // Returns the preferred month/day format
- private const uint LOCALE_SSHORTTIME = 0x00000079; // Returns the preferred short time format (ie: no seconds, just h:mm)
- private const uint LOCALE_SOPENTYPELANGUAGETAG = 0x0000007a; // Open type language tag, eg: "latn" or "dflt"
- private const uint LOCALE_SSORTLOCALE = 0x0000007b; // Name of locale to use for sorting/collation/casing behavior.
-
- // Time formats enumerations
- internal const uint TIME_NOSECONDS = 0x00000002; // Don't use seconds (get short time format for enumtimeformats on win7+)
-
- // Get our initial minimal culture data (name, parent, etc.)
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern bool nativeInitCultureData(CultureData cultureData);
-
- // Grab the NumberFormatInfo data
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern bool nativeGetNumberFormatInfoValues(String localeName, NumberFormatInfo nfi, bool useUserOverride);
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private static extern String[] nativeEnumTimeFormats(String localeName, uint dwFlags, bool useUserOverride);
-
- [SuppressUnmanagedCodeSecurityAttribute()]
- [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
- internal static extern int nativeEnumCultureNames(int cultureTypes, ObjectHandleOnStack retStringArray);
+ /// <remarks>
+ /// The numeric values of the enum members match their Win32 counterparts. The CultureData Win32 PAL implementation
+ /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes.
+ /// </remarks>
+ private enum LocaleStringData : uint
+ {
+ /// <summary>localized name of locale, eg "German (Germany)" in UI language (coresponds to LOCALE_SLOCALIZEDDISPLAYNAME)</summary>
+ LocalizedDisplayName = 0x00000002,
+ /// <summary>Display name (language + country usually) in English, eg "German (Germany)" (coresponds to LOCALE_SENGLISHDISPLAYNAME)</summary>
+ EnglishDisplayName = 0x00000072,
+ /// <summary>Display name in native locale language, eg "Deutsch (Deutschland) (coresponds to LOCALE_SNATIVEDISPLAYNAME)</summary>
+ NativeDisplayName = 0x00000073,
+ /// <summary>Language Display Name for a language, eg "German" in UI language (coresponds to LOCALE_SLOCALIZEDLANGUAGENAME)</summary>
+ LocalizedLanguageName = 0x0000006f,
+ /// <summary>English name of language, eg "German" (coresponds to LOCALE_SENGLISHLANGUAGENAME)</summary>
+ EnglishLanguageName = 0x00001001,
+ /// <summary>native name of language, eg "Deutsch" (coresponds to LOCALE_SNATIVELANGUAGENAME)</summary>
+ NativeLanguageName = 0x00000004,
+ /// <summary>localized name of country, eg "Germany" in UI language (coresponds to LOCALE_SLOCALIZEDCOUNTRYNAME)</summary>
+ LocalizedCountryName = 0x00000006,
+ /// <summary>English name of country, eg "Germany" (coresponds to LOCALE_SENGLISHCOUNTRYNAME)</summary>
+ EnglishCountryName = 0x00001002,
+ /// <summary>native name of country, eg "Deutschland" (coresponds to LOCALE_SNATIVECOUNTRYNAME)</summary>
+ NativeCountryName = 0x00000008,
+ /// <summary>abbreviated language name (coresponds to LOCALE_SABBREVLANGNAME)</summary>
+ AbbreviatedWindowsLanguageName = 0x00000003,
+ /// <summary>list item separator (coresponds to LOCALE_SLIST)</summary>
+ ListSeparator = 0x0000000C,
+ /// <summary>decimal separator (coresponds to LOCALE_SDECIMAL)</summary>
+ DecimalSeparator = 0x0000000E,
+ /// <summary>thousand separator (coresponds to LOCALE_STHOUSAND)</summary>
+ ThousandSeparator = 0x0000000F,
+ /// <summary>digit grouping (coresponds to LOCALE_SGROUPING)</summary>
+ Digits = 0x00000013,
+ /// <summary>local monetary symbol (coresponds to LOCALE_SCURRENCY)</summary>
+ MonetarySymbol = 0x00000014,
+ /// <summary>English currency name (coresponds to LOCALE_SENGCURRNAME)</summary>
+ CurrencyEnglishName = 0x00001007,
+ /// <summary>Native currency name (coresponds to LOCALE_SNATIVECURRNAME)</summary>
+ CurrencyNativeName = 0x00001008,
+ /// <summary>uintl monetary symbol (coresponds to LOCALE_SINTLSYMBOL)</summary>
+ Iso4217MonetarySymbol = 0x00000015,
+ /// <summary>monetary decimal separator (coresponds to LOCALE_SMONDECIMALSEP)</summary>
+ MonetaryDecimalSeparator = 0x00000016,
+ /// <summary>monetary thousand separator (coresponds to LOCALE_SMONTHOUSANDSEP)</summary>
+ MonetaryThousandSeparator = 0x00000017,
+ /// <summary>AM designator (coresponds to LOCALE_S1159)</summary>
+ AMDesignator = 0x00000028,
+ /// <summary>PM designator (coresponds to LOCALE_S2359)</summary>
+ PMDesignator = 0x00000029,
+ /// <summary>positive sign (coresponds to LOCALE_SPOSITIVESIGN)</summary>
+ PositiveSign = 0x00000050,
+ /// <summary>negative sign (coresponds to LOCALE_SNEGATIVESIGN)</summary>
+ NegativeSign = 0x00000051,
+ /// <summary>ISO abbreviated language name (coresponds to LOCALE_SISO639LANGNAME)</summary>
+ Iso639LanguageTwoLetterName = 0x00000059,
+ /// <summary>ISO abbreviated country name (coresponds to LOCALE_SISO639LANGNAME2)</summary>
+ Iso639LanguageThreeLetterName = 0x00000067,
+ /// <summary>ISO abbreviated language name (coresponds to LOCALE_SISO639LANGNAME)</summary>
+ Iso639LanguageName = 0x00000059,
+ /// <summary>ISO abbreviated country name (coresponds to LOCALE_SISO3166CTRYNAME)</summary>
+ Iso3166CountryName = 0x0000005A,
+ /// <summary>3 letter ISO country code (coresponds to LOCALE_SISO3166CTRYNAME2)</summary>
+ Iso3166CountryName2 = 0x00000068, // 3 character ISO country name
+ /// <summary>Not a Number (coresponds to LOCALE_SNAN)</summary>
+ NaNSymbol = 0x00000069,
+ /// <summary>+ Infinity (coresponds to LOCALE_SPOSINFINITY)</summary>
+ PositiveInfinitySymbol = 0x0000006a,
+ /// <summary>- Infinity (coresponds to LOCALE_SNEGINFINITY)</summary>
+ NegativeInfinitySymbol = 0x0000006b,
+ /// <summary>Fallback name for resources (coresponds to LOCALE_SPARENT)</summary>
+ ParentName = 0x0000006d,
+ /// <summary>Fallback name for within the console (coresponds to LOCALE_SCONSOLEFALLBACKNAME)</summary>
+ ConsoleFallbackName = 0x0000006e,
+ /// <summary>Returns the percent symbol (coresponds to LOCALE_SPERCENT)</summary>
+ PercentSymbol = 0x00000076,
+ /// <summary>Returns the permille (U+2030) symbol (coresponds to LOCALE_SPERMILLE)</summary>
+ PerMilleSymbol = 0x00000077
+ }
+
+ /// <remarks>
+ /// The numeric values of the enum members match their Win32 counterparts. The CultureData Win32 PAL implementation
+ /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes.
+ /// </remarks>
+ private enum LocaleGroupingData : uint
+ {
+ /// <summary>digit grouping (coresponds to LOCALE_SGROUPING)</summary>
+ Digit = 0x00000010,
+ /// <summary>monetary grouping (coresponds to LOCALE_SMONGROUPING)</summary>
+ Monetary = 0x00000018,
+ }
+
+ /// <remarks>
+ /// The numeric values of the enum members match their Win32 counterparts. The CultureData Win32 PAL implementation
+ /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes.
+ /// </remarks>
+ private enum LocaleNumberData : uint
+ {
+ /// <summary>language id (coresponds to LOCALE_ILANGUAGE)</summary>
+ LanguageId = 0x00000001,
+ /// <summary>geographical location id, (coresponds to LOCALE_IGEOID)</summary>
+ GeoId = 0x0000005B,
+ /// <summary>0 = context, 1 = none, 2 = national (coresponds to LOCALE_IDIGITSUBSTITUTION)</summary>
+ DigitSubstitution = 0x00001014,
+ /// <summary>0 = metric, 1 = US (coresponds to LOCALE_IMEASURE)</summary>
+ MeasurementSystem = 0x0000000D,
+ /// <summary>number of fractional digits (coresponds to LOCALE_IDIGITS)</summary>
+ FractionalDigitsCount = 0x00000011,
+ /// <summary>negative number mode (coresponds to LOCALE_INEGNUMBER)</summary>
+ NegativeNumberFormat = 0x00001010,
+ /// <summary># local monetary digits (coresponds to LOCALE_ICURRDIGITS)</summary>
+ MonetaryFractionalDigitsCount = 0x00000019,
+ /// <summary>positive currency mode (coresponds to LOCALE_ICURRENCY)</summary>
+ PositiveMonetaryNumberFormat = 0x0000001B,
+ /// <summary>negative currency mode (coresponds to LOCALE_INEGCURR)</summary>
+ NegativeMonetaryNumberFormat = 0x0000001C,
+ /// <summary>type of calendar specifier (coresponds to LOCALE_ICALENDARTYPE)</summary>
+ CalendarType = 0x00001009,
+ /// <summary>first day of week specifier (coresponds to LOCALE_IFIRSTDAYOFWEEK)</summary>
+ FirstDayOfWeek = 0x0000100C,
+ /// <summary>first week of year specifier (coresponds to LOCALE_IFIRSTWEEKOFYEAR)</summary>
+ FirstWeekOfYear = 0x0000100D,
+ /// <summary>
+ /// Returns one of the following 4 reading layout values:
+ /// 0 - Left to right (eg en-US)
+ /// 1 - Right to left (eg arabic locales)
+ /// 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
+ /// 3 - Vertical top to bottom with columns proceeding to the right
+ /// (coresponds to LOCALE_IREADINGLAYOUT)
+ /// </summary>
+ ReadingLayout = 0x00000070,
+ /// <summary>Returns 0-11 for the negative percent format (coresponds to LOCALE_INEGATIVEPERCENT)</summary>
+ NegativePercentFormat = 0x00000074,
+ /// <summary>Returns 0-3 for the positive percent format (coresponds to LOCALE_IPOSITIVEPERCENT)</summary>
+ PositivePercentFormat = 0x00000075,
+ /// <summary>default ansi code page (coresponds to LOCALE_IDEFAULTCODEPAGE)</summary>
+ OemCodePage = 0x0000000B,
+ /// <summary>default ansi code page (coresponds to LOCALE_IDEFAULTANSICODEPAGE)</summary>
+ AnsiCodePage = 0x00001004,
+ /// <summary>default mac code page (coresponds to LOCALE_IDEFAULTMACCODEPAGE)</summary>
+ MacCodePage = 0x00001011,
+ /// <summary>default ebcdic code page (coresponds to LOCALE_IDEFAULTEBCDICCODEPAGE)</summary>
+ EbcdicCodePage = 0x00001012,
+ }
}
}