Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Revert "Support GetCultureInfo with predefinedOnly flag"" #1261

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/coreclr/src/System.Private.CoreLib/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,9 @@
<data name="Argument_InvalidCultureName" xml:space="preserve">
<value>Culture name '{0}' is not supported.</value>
</data>
<data name="Argument_InvalidPredefinedCultureName" xml:space="preserve">
<value>Culture name '{0}' is not a predefined culture.</value>
</data>
<data name="Argument_InvalidDateTimeKind" xml:space="preserve">
<value>Invalid DateTimeKind value.</value>
</data>
Expand Down
21 changes: 21 additions & 0 deletions src/libraries/Native/Unix/System.Globalization.Native/pal_locale.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,24 @@ int32_t GlobalizationNative_GetDefaultLocaleName(UChar* value, int32_t valueLeng

return UErrorCodeToBool(status);
}

// GlobalizationNative_IsPredefinedLocale returns TRUE if ICU has a real data for the locale.
// Otherwise it returns FALSE;

int32_t GlobalizationNative_IsPredefinedLocale(const UChar* localeName)
{
UErrorCode err = U_ZERO_ERROR;
char locale[ULOC_FULLNAME_CAPACITY];
GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, FALSE, &err);

if (U_FAILURE(err))
return FALSE;

// ures_open returns err = U_ZERO_ERROR when ICU has data for localeName.
// If it is fake locale, it will return err = U_USING_FALLBACK_WARNING || err = U_USING_DEFAULT_WARNING.
// Other err values would be just a failure.
UResourceBundle* uresb = ures_open(NULL, locale, &err);
ures_close(uresb);

return err == U_ZERO_ERROR;
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,5 @@ DLLEXPORT int32_t GlobalizationNative_GetLocales(UChar *value, int32_t valueLeng
DLLEXPORT int32_t GlobalizationNative_GetLocaleName(const UChar* localeName, UChar* value, int32_t valueLength);

DLLEXPORT int32_t GlobalizationNative_GetDefaultLocaleName(UChar* value, int32_t valueLength);

DLLEXPORT int32_t GlobalizationNative_IsPredefinedLocale(const UChar* localeName);
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Licensed to the .NET Foundation under one or more agreements.
// 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 Xunit;

namespace System.Globalization.Tests
{
public class GetCultureInfoTests
{
public static bool PlatformSupportsFakeCulture => !PlatformDetection.IsWindows || (PlatformDetection.WindowsVersion >= 10 && !PlatformDetection.IsFullFramework);

[ConditionalTheory(nameof(PlatformSupportsFakeCulture))]
[InlineData("en")]
[InlineData("en-US")]
[InlineData("ja-JP")]
[InlineData("ar-SA")]
[InlineData("xx-XX")]
public void GetCultureInfo(string name)
{
Assert.Equal(name, CultureInfo.GetCultureInfo(name).Name);
Assert.Equal(name, CultureInfo.GetCultureInfo(name, predefinedOnly: false).Name);
}

[ConditionalTheory(nameof(PlatformSupportsFakeCulture))]
[InlineData("en@US")]
[InlineData("\uFFFF")]
public void TestInvalidCultureNames(string name)
{
Assert.Throws<CultureNotFoundException>(() => CultureInfo.GetCultureInfo(name));
Assert.Throws<CultureNotFoundException>(() => CultureInfo.GetCultureInfo(name, predefinedOnly: false));
Assert.Throws<CultureNotFoundException>(() => CultureInfo.GetCultureInfo(name, predefinedOnly: true));
}

[ConditionalTheory(nameof(PlatformSupportsFakeCulture))]
[InlineData("xx")]
[InlineData("xx-XX")]
[InlineData("xx-YY")]
public void TestFakeCultureNames(string name)
{
Assert.Equal(name, CultureInfo.GetCultureInfo(name).Name);
Assert.Equal(name, CultureInfo.GetCultureInfo(name, predefinedOnly: false).Name);
Assert.Throws<CultureNotFoundException>(() => CultureInfo.GetCultureInfo(name, predefinedOnly: true));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
<Compile Include="CultureInfo\CultureInfoReadOnly.cs" />
<Compile Include="CultureInfo\CultureInfoTwoLetterISOLanguageName.cs" />
<Compile Include="CultureInfo\CultureInfoCurrentCulture.cs" />
<Compile Include="CultureInfo\GetCultureInfo.cs" />
<Compile Include="DateTimeFormatInfo\DateTimeFormatInfoAbbreviatedDayNames.cs" />
<Compile Include="DateTimeFormatInfo\DateTimeFormatInfoAbbreviatedMonthGenitiveNames.cs" />
<Compile Include="DateTimeFormatInfo\DateTimeFormatInfoAbbreviatedMonthNames.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ internal static partial class Globalization
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern unsafe bool GetDefaultLocaleName(char* value, int valueLength);

[DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IsPredefinedLocale")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern unsafe bool IsPredefinedLocale(string localeName);

[DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleTimeFormat")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern unsafe bool GetLocaleTimeFormat(string localeName, bool shortFormat, char* value, int valueLength);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ internal static CultureInfo GetUserDefaultCulture()
return cultureInfo;
}

private static CultureInfo GetPredefinedCultureInfo(string name)
{
if (!Interop.Globalization.IsPredefinedLocale(name))
{
throw new CultureNotFoundException(nameof(name), SR.Format(SR.Argument_InvalidPredefinedCultureName, name));
}

return GetCultureInfo(name);
}

private static CultureInfo GetUserDefaultUICulture()
{
return InitializeUserDefaultCulture();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,24 @@ internal static CultureInfo GetUserDefaultCulture()
return GetCultureByName(strDefault);
}

private static CultureInfo GetPredefinedCultureInfo(string name)
{
CultureInfo culture = GetCultureInfo(name);
string englishName = culture.EnglishName;

// Check if the English Name starts with "Unknown Locale" or "Unknown Language" terms.
const int SecondTermIndex = 8;

if (englishName.StartsWith("Unknown ", StringComparison.Ordinal) && englishName.Length > SecondTermIndex &&
(englishName.IndexOf("Locale", SecondTermIndex, StringComparison.Ordinal) == SecondTermIndex ||
englishName.IndexOf("Language", SecondTermIndex, StringComparison.Ordinal) == SecondTermIndex))
{
throw new CultureNotFoundException(nameof(name), SR.Format(SR.Argument_InvalidPredefinedCultureName, name));
}

return culture;
}

private static unsafe CultureInfo GetUserDefaultUICulture()
{
if (GlobalizationMode.Invariant)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,21 @@ public static CultureInfo GetCultureInfo(string name, string altName)
return result;
}

public static CultureInfo GetCultureInfo(string name, bool predefinedOnly)
{
if (name is null)
{
throw new ArgumentNullException(nameof(name));
}

if (predefinedOnly)
{
return GetPredefinedCultureInfo(name);
}

return GetCultureInfo(name);
}

private static Dictionary<string, CultureInfo> CachedCulturesByName
{
get
Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4432,6 +4432,7 @@ public void ClearCachedData() { }
public System.Globalization.CultureInfo GetConsoleFallbackUICulture() { throw null; }
public static System.Globalization.CultureInfo GetCultureInfo(int culture) { throw null; }
public static System.Globalization.CultureInfo GetCultureInfo(string name) { throw null; }
public static System.Globalization.CultureInfo GetCultureInfo(string name, bool predefinedOnly) { throw null; }
public static System.Globalization.CultureInfo GetCultureInfo(string name, string altName) { throw null; }
public static System.Globalization.CultureInfo GetCultureInfoByIetfLanguageTag(string name) { throw null; }
public static System.Globalization.CultureInfo[] GetCultures(System.Globalization.CultureTypes types) { throw null; }
Expand Down