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

Initial changes for globalization hybrid mode #81470

Merged
merged 28 commits into from
Mar 28, 2023
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f8e72d8
Initial changes for GetLocaleInfoString
mkhamoyan Feb 1, 2023
a82743d
Remove CompareInfo changes
mkhamoyan Feb 1, 2023
954ed0f
Updated more cases
mkhamoyan Feb 1, 2023
1362d45
updated hybrid mode property
mkhamoyan Feb 8, 2023
cb23688
update
mkhamoyan Feb 10, 2023
af32324
working version of NativeGetLocaleInfoString
mkhamoyan Feb 13, 2023
83f4e7b
update
mkhamoyan Feb 14, 2023
4ac3e6b
Refactored and added more cases
mkhamoyan Mar 2, 2023
60e090a
Removed comments
mkhamoyan Mar 2, 2023
26ce9a9
updated
mkhamoyan Mar 2, 2023
a10f09d
Merge branch 'main' into ios_hybrid_globalization
mkhamoyan Mar 2, 2023
dc347f5
native functions only for apple platforms
mkhamoyan Mar 2, 2023
09d599e
Native functions only for apple
mkhamoyan Mar 2, 2023
bacc227
build native functions only for ios
mkhamoyan Mar 2, 2023
e844a40
Include ios file only for ios
mkhamoyan Mar 2, 2023
f7f730a
Merge branch 'main' into ios_hybrid_globalization
mkhamoyan Mar 15, 2023
46c9e68
refactored
mkhamoyan Mar 15, 2023
1b7aa37
Run hybrid tests only for ioslike platforms
mkhamoyan Mar 16, 2023
789613b
done updates requested by review
mkhamoyan Mar 16, 2023
0b9f32d
space refactoring
mkhamoyan Mar 16, 2023
1aee1e0
Fix osx build issue
mkhamoyan Mar 17, 2023
b382101
fix osx build
mkhamoyan Mar 17, 2023
1556d17
Changes requested by review
mkhamoyan Mar 20, 2023
5ab240a
Merge branch 'main' into ios_hybrid_globalization
mkhamoyan Mar 20, 2023
5028045
Rename .iOS files to OSX
mkhamoyan Mar 20, 2023
ad4c98b
Remove logging
mkhamoyan Mar 20, 2023
3eb5cae
Removed not used code lines
mkhamoyan Mar 21, 2023
27424bf
Remove from linker hybrid mode
mkhamoyan Mar 24, 2023
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
1 change: 1 addition & 0 deletions docs/workflow/trimming/feature-switches.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ configurations but their defaults might vary as any SDK can set the defaults dif
| EnableUnsafeBinaryFormatterSerialization | System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization | BinaryFormatter serialization support is trimmed when set to false |
| EventSourceSupport | System.Diagnostics.Tracing.EventSource.IsSupported | Any EventSource related code or logic is trimmed when set to false |
| InvariantGlobalization | System.Globalization.Invariant | All globalization specific code and data is trimmed when set to true |
| HybridGlobalization | System.Globalization.Hybrid | Loading ICU + native implementations |
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we still planning to add the feature switch HybridGlobalization? Reading up on https://github.com/dotnet/designs/blob/main/accepted/2020/feature-switch.md a bit more, it seems like feature switches primarily help control the size of libraries by trimming out areas we know will not be reached under certain conditions (when a particular feature switch is on). For example, when the InvariantGlobalization feature switch is on (true), the GlobalizationMode/Settings class is trimmed out.

So for HybridGlobalization, is there anything we want to/can trim out if its known that HybridGlobalization is being used? From what I am understanding, HybridGlobalization is to help reduce the reliance on ICU. When its true, it doesn't make any other code completely unreachable right now does it? Or is IcuGetLocaleInfo(..., LocalStringData ..., ...) all supposed to be unreachable now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to have feature switch HybridGlobalization as without it we will not understand to load fully icu or no. In ideal case IcuGetLocaleInfo should not be used in HybridGlobalization when all functionalities will be implemented by native functions. Also for HybridGlobalization we will load smaller icu files (trimmed out the functionalities that are implemented by native functions), this will be done in upcoming PRs.

Copy link
Member

@akoeplinger akoeplinger Mar 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mkhamoyan the feature switches listed here are linker feature switches, i.e. where the linker replaces/hardcodes the value of the corresponding AppContext switch so that unused code can be trimmed out.

We don't need that, we have a regular AppContext switch that is unaffected by trimming so having it listed in this doc is confusing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will remove it from here. Do we have doc for regular AppContext switches?

Copy link
Member

@akoeplinger akoeplinger Mar 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know we just have the public docs where we could add it: https://learn.microsoft.com/en-us/dotnet/core/runtime-config/globalization

Note that in our case we'd just have runtimeconfig.json and environment variable options since the MSBuild property would need wiring up in the dotnet/sdk.

| PredefinedCulturesOnly | System.Globalization.PredefinedCulturesOnly | Don't allow creating a culture for which the platform does not have data |
| UseSystemResourceKeys | System.Resources.UseSystemResourceKeys | Any localizable resources for system assemblies is trimmed when set to true |
| HttpActivityPropagationSupport | System.Net.Http.EnableActivityPropagation | Any dependency related to diagnostics support for System.Net.Http is trimmed when set to false |
Expand Down
1 change: 1 addition & 0 deletions eng/testing/tests.ioslike.targets
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
library test project. Eg. $(InvariantGlobalization) -->
<ItemGroup>
<_ApplePropertyNames Include="InvariantGlobalization" />
<_ApplePropertyNames Include="HybridGlobalization" />
<_ApplePropertyNames Include="AssemblyName" />
<_ApplePropertyNames Include="MonoEnableLLVM" />

Expand Down
16 changes: 16 additions & 0 deletions src/libraries/Common/src/Interop/Interop.Locale.OSX.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Globalization
{
[LibraryImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetLocaleNameNative", StringMarshalling = StringMarshalling.Utf8)]
internal static unsafe partial string GetLocaleNameNative(string localeName);

[LibraryImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetLocaleInfoStringNative", StringMarshalling = StringMarshalling.Utf8)]
internal static unsafe partial string GetLocaleInfoStringNative(string localeName, uint localeStringData);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-maccatalyst;$(NetCoreAppCurrent)-osx</TargetFrameworks>
<TestRuntime>true</TestRuntime>
<HybridGlobalization>true</HybridGlobalization>
</PropertyGroup>
<ItemGroup>
<Compile Include="HybridMode.cs" />
</ItemGroup>
</Project>
48 changes: 48 additions & 0 deletions src/libraries/System.Globalization/tests/Hybrid/HybridMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using Xunit;

namespace System.Globalization.Tests
{
public class HybridModeTests
{
public static IEnumerable<object[]> EnglishName_TestData()
{
yield return new object[] { "en-US", "English (United States)" };
yield return new object[] { "fr-FR", "French (France)" };
}

public static IEnumerable<object[]> NativeName_TestData()
{
yield return new object[] { "en-US", "English (United States)" };
yield return new object[] { "fr-FR", "français (France)" };
yield return new object[] { "en-CA", "English (Canada)" };
}

[Theory]
[MemberData(nameof(EnglishName_TestData))]
public void TestEnglishName(string cultureName, string expected)
{
CultureInfo myTestCulture = new CultureInfo(cultureName);
Assert.Equal(expected, myTestCulture.EnglishName);
}

[Theory]
[MemberData(nameof(NativeName_TestData))]
public void TestNativeName(string cultureName, string expected)
{
CultureInfo myTestCulture = new CultureInfo(cultureName);
Assert.Equal(expected, myTestCulture.NativeName);
}

[Theory]
[InlineData("de-DE", "de")]
[InlineData("en-US", "en")]
public void TwoLetterISOLanguageName(string name, string expected)
{
Assert.Equal(expected, new CultureInfo(name).TwoLetterISOLanguageName);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
to be trimmed when Invariant=true, and allows for the Settings static cctor (on Unix) to be preserved when Invariant=false. -->
<type fullname="System.Globalization.GlobalizationMode">
<method signature="System.Boolean get_Invariant()" body="stub" value="true" feature="System.Globalization.Invariant" featurevalue="true" />
<method signature="System.Boolean get_Hybrid()" body="stub" value="true" feature="System.Globalization.Hybrid" featurevalue="true" />
<method signature="System.Boolean get_PredefinedCulturesOnly()" body="stub" value="true" feature="System.Globalization.PredefinedCulturesOnly" featurevalue="true" />
</type>
<type fullname="System.Globalization.GlobalizationMode/Settings">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareOptions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Icu.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.OSX.cs" Condition="'$(IsOSXLike)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Nls.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureNotFoundException.cs" />
Expand Down Expand Up @@ -1278,6 +1279,9 @@
<Compile Include="$(CommonPath)Interop\Interop.Locale.cs">
<Link>Common\Interop\Interop.Locale.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Interop.Locale.OSX.cs" Condition="'$(IsOSXLike)' == 'true'">
<Link>Common\Interop\Interop.Locale.OSX.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Interop.Normalization.cs">
<Link>Common\Interop\Interop.Normalization.cs</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;

namespace System.Globalization
{
internal sealed partial class CultureData
{
/// <summary>
/// This method uses the sRealName field (which is initialized by the constructor before this is called) to
/// initialize the rest of the state of CultureData based on the underlying OS globalization library.
/// </summary>
private bool InitNativeCultureDataCore()
{
Debug.Assert(_sRealName != null);
Debug.Assert(!GlobalizationMode.Invariant);
string realNameBuffer = _sRealName;

_sWindowsName = GetLocaleNameNative(realNameBuffer);
return true;
}

internal static unsafe string GetLocaleNameNative(string localeName)
{
return Interop.Globalization.GetLocaleNameNative(localeName);
}

private string GetLocaleInfoNative(LocaleStringData type)
{
Debug.Assert(!GlobalizationMode.Invariant);
Debug.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfoNative] Expected _sWindowsName to be populated already");

return GetLocaleInfoNative(_sWindowsName, type);
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved
}

// 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.
private static unsafe string GetLocaleInfoNative(string localeName, LocaleStringData type)
{
Debug.Assert(localeName != null, "[CultureData.GetLocaleInfoNative] Expected localeName to be not be null");

return Interop.Globalization.GetLocaleInfoStringNative(localeName, (uint)type);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2304,7 +2304,11 @@ private string GetLocaleInfoCoreUserOverride(LocaleStringData type)
if (GlobalizationMode.Invariant)
return null!;

#if TARGET_OSX || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
return GlobalizationMode.Hybrid ? GetLocaleInfoNative(type) : IcuGetLocaleInfo(type);
#else
return ShouldUseUserOverrideNlsData ? NlsGetLocaleInfo(type) : IcuGetLocaleInfo(type);
#endif
}

private string GetLocaleInfoCore(LocaleStringData type, string? uiCultureName = null)
Expand All @@ -2313,7 +2317,11 @@ private string GetLocaleInfoCore(LocaleStringData type, string? uiCultureName =
if (GlobalizationMode.Invariant)
return null!;

#if TARGET_OSX || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
return GlobalizationMode.Hybrid ? GetLocaleInfoNative(type) : IcuGetLocaleInfo(type, uiCultureName);
#else
return GlobalizationMode.UseNls ? NlsGetLocaleInfo(type) : IcuGetLocaleInfo(type, uiCultureName);
#endif
}

private string GetLocaleInfoCore(string localeName, LocaleStringData type, string? uiCultureName = null)
Expand All @@ -2322,7 +2330,11 @@ private string GetLocaleInfoCore(string localeName, LocaleStringData type, strin
if (GlobalizationMode.Invariant)
return null!;

#if TARGET_OSX || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
return GlobalizationMode.Hybrid ? GetLocaleInfoNative(localeName, type) : IcuGetLocaleInfo(localeName, type, uiCultureName);
#else
return GlobalizationMode.UseNls ? NlsGetLocaleInfo(localeName, type) : IcuGetLocaleInfo(localeName, type, uiCultureName);
#endif
}

private int[] GetLocaleInfoCoreUserOverride(LocaleGroupingData type)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,19 @@ internal static partial class GlobalizationMode
private static partial class Settings
{
internal static bool Invariant { get; } = AppContextConfigHelper.GetBooleanConfig("System.Globalization.Invariant", "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT");
#if TARGET_OSX || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
internal static bool Hybrid { get; } = AppContextConfigHelper.GetBooleanConfig("System.Globalization.Hybrid", "DOTNET_SYSTEM_GLOBALIZATION_HYBRID");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be under iOS ifdef - since all uses are under iOS ifdef as well?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, plus wasm and wasi as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now I will put under ioslike platforms. For wasm we have seperate PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If HybridGlobalization is not going to be a feature switch, should this be using AppContextConfigHelper.GetBooleanConfig? Will the switch System.Globalization.Hybrid ever be set? I think System.Globalization.Invariant and System.Globalization.PredefinedCulturesOnly switches are probably set in the TrimmingTests

<DisabledFeatureSwitches>System.Globalization.Invariant</DisabledFeatureSwitches>
</TestConsoleAppSourceFiles>
<TestConsoleAppSourceFiles Include="InvariantGlobalizationTrue.cs">
<EnabledFeatureSwitches>System.Globalization.Invariant;System.Globalization.PredefinedCulturesOnly</EnabledFeatureSwitches>
.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once more functionalities will be implemented this will be used and we can have tests in TrimmingTests for hybrid mode.

#endif
internal static bool PredefinedCulturesOnly { get; } = AppContextConfigHelper.GetBooleanConfig("System.Globalization.PredefinedCulturesOnly", "DOTNET_SYSTEM_GLOBALIZATION_PREDEFINED_CULTURES_ONLY", GlobalizationMode.Invariant);
}

// Note: Invariant=true and Invariant=false are substituted at different levels in the ILLink.Substitutions file.
// This allows for the whole Settings nested class to be trimmed when Invariant=true, and allows for the Settings
// static cctor (on Unix) to be preserved when Invariant=false.
internal static bool Invariant => Settings.Invariant;
#if TARGET_OSX || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
internal static bool Hybrid => Settings.Hybrid;
#endif
internal static bool PredefinedCulturesOnly => Settings.PredefinedCulturesOnly;

private static bool TryGetAppLocalIcuSwitchValue([NotNullWhen(true)] out string? value) =>
Expand Down
1 change: 1 addition & 0 deletions src/mono/msbuild/apple/build/AppleBuild.targets
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@
GenerateCMakeProject="$(GenerateCMakeProject)"
GenerateXcodeProject="$(GenerateXcodeProject)"
InvariantGlobalization="$(InvariantGlobalization)"
HybridGlobalization="$(HybridGlobalization)"
MainLibraryFileName="$(MainLibraryFileName)"
MonoRuntimeHeaders="$(_MonoHeaderPath)"
NativeMainSource="$(NativeMainSource)"
Expand Down
4 changes: 4 additions & 0 deletions src/native/libs/System.Globalization.Native/entrypoints.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ static const Entry s_globalizationNative[] =
DllImportEntry(GlobalizationNative_ToAscii)
DllImportEntry(GlobalizationNative_ToUnicode)
DllImportEntry(GlobalizationNative_WindowsIdToIanaId)
#ifdef __APPLE__
DllImportEntry(GlobalizationNative_GetLocaleNameNative)
DllImportEntry(GlobalizationNative_GetLocaleInfoStringNative)
#endif
};

EXTERN_C const void* GlobalizationResolveDllImport(const char* name);
Expand Down
4 changes: 4 additions & 0 deletions src/native/libs/System.Globalization.Native/pal_locale.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ PALEXPORT int32_t GlobalizationNative_GetLocales(UChar *value, int32_t valueLeng

PALEXPORT int32_t GlobalizationNative_GetLocaleName(const UChar* localeName, UChar* value, int32_t valueLength);

#ifdef __APPLE__
PALEXPORT const char* GlobalizationNative_GetLocaleNameNative(const char* localeName);
#endif

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

PALEXPORT int32_t GlobalizationNative_IsPredefinedLocale(const UChar* localeName);
125 changes: 125 additions & 0 deletions src/native/libs/System.Globalization.Native/pal_locale.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@

#include <stdlib.h>
#include "pal_locale_internal.h"
#include "pal_localeStringData.h"

#import <Foundation/Foundation.h>
#import <Foundation/NSFormatter.h>

char* DetectDefaultAppleLocaleName()
{
Expand All @@ -28,6 +30,129 @@
return strdup([localeName UTF8String]);
}

#if defined(TARGET_OSX) || defined(TARGET_MACCATALYST) || defined(TARGET_IOS) || defined(TARGET_TVOS)

const char* GlobalizationNative_GetLocaleNameNative(const char* localeName)
{
NSString *locName = [NSString stringWithFormat:@"%s", localeName];
NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName];
const char* value = [currentLocale.localeIdentifier UTF8String];
return strdup(value);
}

const char* GlobalizationNative_GetLocaleInfoStringNative(const char* localeName, LocaleStringData localeStringData)
{
const char* value;
NSString *locName = [NSString stringWithFormat:@"%s", localeName];
NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName];
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
numberFormatter.locale = currentLocale;
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:currentLocale];
NSLocale *gbLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_GB"];


switch (localeStringData)
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved
{
///// <summary>localized name of locale, eg "German (Germany)" in UI language (corresponds to LOCALE_SLOCALIZEDDISPLAYNAME)</summary>
case LocaleString_LocalizedDisplayName:
/// <summary>Display name (language + country usually) in English, eg "German (Germany)" (corresponds to LOCALE_SENGLISHDISPLAYNAME)</summary>
case LocaleString_EnglishDisplayName:
value = [[gbLocale displayNameForKey:NSLocaleIdentifier value:currentLocale.localeIdentifier] UTF8String];
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved
break;
/// <summary>Display name in native locale language, eg "Deutsch (Deutschland) (corresponds to LOCALE_SNATIVEDISPLAYNAME)</summary>
case LocaleString_NativeDisplayName:
value = [[currentLocale displayNameForKey:NSLocaleIdentifier value:currentLocale.localeIdentifier] UTF8String];
break;
/// <summary>Language Display Name for a language, eg "German" in UI language (corresponds to LOCALE_SLOCALIZEDLANGUAGENAME)</summary>
case LocaleString_LocalizedLanguageName:
/// <summary>English name of language, eg "German" (corresponds to LOCALE_SENGLISHLANGUAGENAME)</summary>
case LocaleString_EnglishLanguageName:
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved
value = [[gbLocale localizedStringForLanguageCode:currentLocale.languageCode] UTF8String];
break;
/// <summary>native name of language, eg "Deutsch" (corresponds to LOCALE_SNATIVELANGUAGENAME)</summary>
case LocaleString_NativeLanguageName:
value = [[currentLocale localizedStringForLanguageCode:currentLocale.languageCode] UTF8String];
break;
/// <summary>English name of country, eg "Germany" (corresponds to LOCALE_SENGLISHCOUNTRYNAME)</summary>
case LocaleString_EnglishCountryName:
value = [[gbLocale localizedStringForCountryCode:currentLocale.countryCode] UTF8String];
break;
/// <summary>native name of country, eg "Deutschland" (corresponds to LOCALE_SNATIVECOUNTRYNAME)</summary>
case LocaleString_NativeCountryName:
value = [[currentLocale localizedStringForCountryCode:currentLocale.countryCode] UTF8String];
break;
case LocaleString_ThousandSeparator:
value = [currentLocale.groupingSeparator UTF8String];
break;
case LocaleString_DecimalSeparator:
value = [currentLocale.decimalSeparator UTF8String];
// or value = [[currentLocale objectForKey:NSLocaleDecimalSeparator] UTF8String];
break;
case LocaleString_MonetarySymbol:
value = [currentLocale.currencySymbol UTF8String];
break;
case LocaleString_Iso4217MonetarySymbol:
// check if this is correct, check currencyISOCode
value = [currentLocale.currencySymbol UTF8String];
break;
case LocaleString_CurrencyEnglishName:
value = [[gbLocale localizedStringForCurrencyCode:currentLocale.currencyCode] UTF8String];
break;
case LocaleString_CurrencyNativeName:
value = [[currentLocale localizedStringForCurrencyCode:currentLocale.currencyCode] UTF8String];
break;
case LocaleString_AMDesignator:
value = [dateFormatter.AMSymbol UTF8String];
break;
case LocaleString_PMDesignator:
value = [dateFormatter.PMSymbol UTF8String];
break;
case LocaleString_PositiveSign:
value = [numberFormatter.plusSign UTF8String];
break;
case LocaleString_NegativeSign:
value = [numberFormatter.minusSign UTF8String];
break;
case LocaleString_Iso639LanguageTwoLetterName:
// check if this is correct
value = [[currentLocale objectForKey:NSLocaleLanguageCode] UTF8String];
break;
case LocaleString_Iso3166CountryName:
value = [currentLocale.countryCode UTF8String];
break;
case LocaleString_NaNSymbol:
value = [numberFormatter.notANumberSymbol UTF8String];
break;
case LocaleString_PositiveInfinitySymbol:
value = [numberFormatter.positiveInfinitySymbol UTF8String];
break;
case LocaleString_NegativeInfinitySymbol:
value = [numberFormatter.negativeInfinitySymbol UTF8String];
break;
case LocaleString_PercentSymbol:
value = [numberFormatter.percentSymbol UTF8String];
break;
case LocaleString_PerMilleSymbol:
value = [numberFormatter.perMillSymbol UTF8String];
break;
// TODO find mapping for below cases
// https://github.com/dotnet/runtime/issues/83514
case LocaleString_Digits:
case LocaleString_MonetaryDecimalSeparator:
case LocaleString_MonetaryThousandSeparator:
case LocaleString_Iso639LanguageThreeLetterName:
case LocaleString_ParentName:
case LocaleString_Iso3166CountryName2:
default:
value = "";
break;
}

return strdup(value);
}
#endif

#if defined(TARGET_MACCATALYST) || defined(TARGET_IOS) || defined(TARGET_TVOS)
const char* GlobalizationNative_GetICUDataPathFallback(void)
{
Expand Down
Loading