internal CultureInfo GetCompatibleCulture() { if (_compatibleCulture == null) { CultureInfo culture = null; if (!TryGetEquivalentCulture(out culture)) { string languageTag = IetfLanguageTag; do { languageTag = Shorten(languageTag); if (languageTag == null) { // Should never happen, because GetCultureinfoByIetfLanguageTag("") should // return InvariantCulture! culture = CultureInfo.InvariantCulture; } else { try { culture = SafeSecurityHelper.GetCultureInfoByIetfLanguageTag(languageTag); } catch (ArgumentException) { } } } while (culture == null); } _compatibleCulture = culture; } return(_compatibleCulture); }
/// <summary> /// Returns a CultureInfo if and only if one is registered matching IetfLanguageTag /// </summary> /// <exception cref="InvalidOperationException"> /// There is no registered CultureInfo with given IetfLanguageTag. /// </exception> public CultureInfo GetEquivalentCulture() { if (_equivalentCulture == null) { string lowerCaseTag = _lowerCaseTag; // xml:lang="und" // see http://www.w3.org/International/questions/qa-no-language // // Just treat it the same as xml:lang="" if (String.CompareOrdinal(lowerCaseTag, "und") == 0) { lowerCaseTag = String.Empty; } try { // Even if we previously failed to find an EquivalentCulture, we retry, if only to // capture inner exception. _equivalentCulture = SafeSecurityHelper.GetCultureInfoByIetfLanguageTag(lowerCaseTag); } catch (ArgumentException e) { _equivalentCultureFailed = true; throw new InvalidOperationException(SR.Get(SRID.XmlLangGetCultureFailure, lowerCaseTag), e); } } return(_equivalentCulture); }
/// <summary> /// Returns a specific culture given an arbitrary CultureInfo, which may be null, the invariant /// culture, or a neutral culture. /// </summary> public static CultureInfo GetSpecificCulture(CultureInfo runCulture) { // Assume default culture unless we can do better. CultureInfo specificCulture = TypeConverterHelper.InvariantEnglishUS; if (runCulture != null) { // Assign _cachedCultureMap to a local variable for thread safety. The reference assignment // is atomic and the CachedCultureMap class is immutable. CachedCultureMap cachedCultureMap = _cachedCultureMap; if (cachedCultureMap != null && object.ReferenceEquals(cachedCultureMap.OriginalCulture, runCulture)) { return(cachedCultureMap.SpecificCulture); } // Unfortunately we cannot use reference comparison here because, for example, new CultureInfo("") // creates an invariant culture which (being a new object) is obviously not the same instance as // CultureInfo.InvariantCulture. if (runCulture != CultureInfo.InvariantCulture) { if (!runCulture.IsNeutralCulture) { // It's already a specific culture (neither neutral nor InvariantCulture) specificCulture = runCulture; } else { // Get the culture name. Note that the string expected by CreateSpecificCulture corresponds // to the Name property, not IetfLanguageTag, so that's what we use. string cultureName = runCulture.Name; if (!string.IsNullOrEmpty(cultureName)) { try { CultureInfo culture = CultureInfo.CreateSpecificCulture(cultureName); specificCulture = SafeSecurityHelper.GetCultureInfoByIetfLanguageTag(culture.IetfLanguageTag); } catch (ArgumentException) { // This exception occurs if the culture name is invalid or has no corresponding specific // culture. we can safely ignore the exception and fall back to TypeConverterHelper.InvariantEnglishUS. specificCulture = TypeConverterHelper.InvariantEnglishUS; } } } } // Save the mapping so the next call will be fast if we're given the same runCulture. // Again, the reference assignment is atomic so this is thread safe. _cachedCultureMap = new CachedCultureMap(runCulture, specificCulture); } return(specificCulture); }
/// <summary> /// Finds the most-closely-related non-neutral registered CultureInfo, if one is available. /// </summary> /// <returns> /// A non-Neutral CultureInfo. /// </returns> /// <exception cref="InvalidOperationException"> /// There is no related non-Neutral CultureInfo registered. /// </exception> /// <remarks> /// Will return CultureInfo.InvariantCulture if-and-only-if this.Equals(XmlLanguage.Empty). /// Finds the registered CultureInfo matching the longest-possible prefix of this XmlLanguage. /// If that registered CultureInfo is Neutral, then relies on /// CultureInfo.CreateSpecificCulture() to map from a Neutral CultureInfo to a Specific one. /// </remarks> public CultureInfo GetSpecificCulture() { if (_specificCulture == null) { if (_lowerCaseTag.Length == 0 || String.CompareOrdinal(_lowerCaseTag, "und") == 0) { _specificCulture = GetEquivalentCulture(); } else { CultureInfo culture = GetCompatibleCulture(); if (culture.IetfLanguageTag.Length == 0) { throw new InvalidOperationException(SR.Get(SRID.XmlLangGetSpecificCulture, _lowerCaseTag)); } if (!culture.IsNeutralCulture) { _specificCulture = culture; } else { try { // note that it's important that we use culture.Name, not culture.IetfLanguageTag, here culture = CultureInfo.CreateSpecificCulture(culture.Name); _specificCulture = SafeSecurityHelper.GetCultureInfoByIetfLanguageTag(culture.IetfLanguageTag); } catch (ArgumentException e) { throw new InvalidOperationException(SR.Get(SRID.XmlLangGetSpecificCulture, _lowerCaseTag), e); } } } } return(_specificCulture); }