Skip to content

Commit

Permalink
Support GetCultureInfo with predefinedOnly flag (#654)
Browse files Browse the repository at this point in the history
* Support GetCultureInfo with predefinedOnly flag
  • Loading branch information
tarekgh authored Jan 2, 2020
1 parent 90a8dfc commit 5272637
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 0 deletions.
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

0 comments on commit 5272637

Please sign in to comment.