Skip to content

Commit 86308dc

Browse files
github-actions[bot]Steve Pfister
andauthored
[release/6.0] Detect the default locale name during startup on Apple platforms (#68934)
* Detect the default locale name during startup on Apple platforms This change adds a function to lookup the current NSLocale and extract the language + country code to load into ICU by default. Previously, we would defer to uloc_getDefault in ICU, which would return a value we would ignore (en_US_POSIX) and result in falling back to invariant mode. Fixes #68321 * Link in foundation and address feedback * Link in foundation in coreclr * Check LANG env variable first * Defer to icu first, since it's looking for LANG and certain values. * #ifdef not #if * PR feedback * Remove redundant string replace * pal_locale.m needs to be in a different location than upstream * cmake tweak to make sure foundation gets linked in Co-authored-by: Steve Pfister <[email protected]>
1 parent 6a2204c commit 86308dc

File tree

7 files changed

+115
-10
lines changed

7 files changed

+115
-10
lines changed

src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,15 @@ if(FEATURE_MERGE_JIT_AND_ENGINE)
167167
set(CLRJIT_STATIC clrjit_static)
168168
endif(FEATURE_MERGE_JIT_AND_ENGINE)
169169

170+
if (CLR_CMAKE_TARGET_OSX OR CLR_CMAKE_TARGET_MACCATALYST)
171+
include(CMakeFindFrameworks)
172+
find_library(FOUNDATION Foundation REQUIRED)
173+
endif()
174+
170175
target_sources(coreclr PUBLIC $<TARGET_OBJECTS:cee_wks_core>)
171-
target_link_libraries(coreclr PUBLIC ${CORECLR_LIBRARIES} ${CLRJIT_STATIC} cee_wks)
176+
target_link_libraries(coreclr PUBLIC ${CORECLR_LIBRARIES} ${CLRJIT_STATIC} cee_wks ${FOUNDATION})
172177
target_sources(coreclr_static PUBLIC $<TARGET_OBJECTS:cee_wks_core>)
173-
target_link_libraries(coreclr_static PUBLIC ${CORECLR_LIBRARIES} clrjit_static cee_wks_mergeable)
178+
target_link_libraries(coreclr_static PUBLIC ${CORECLR_LIBRARIES} clrjit_static cee_wks_mergeable ${FOUNDATION})
174179
target_compile_definitions(coreclr_static PUBLIC CORECLR_EMBEDDED)
175180

176181
if(CLR_CMAKE_TARGET_WIN32)

src/libraries/Native/Unix/System.Globalization.Native/CMakeLists.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ set(NATIVEGLOBALIZATION_SOURCES
6464
pal_icushim.c
6565
)
6666

67+
if (CLR_CMAKE_TARGET_OSX OR CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
68+
set(NATIVEGLOBALIZATION_SOURCES ${NATIVEGLOBALIZATION_SOURCES} pal_locale.m)
69+
endif()
70+
6771
# time zone names are filtered out of icu data for the browser and associated functionality is disabled
6872
if (NOT CLR_CMAKE_TARGET_BROWSER)
6973
set(NATIVEGLOBALIZATION_SOURCES ${NATIVEGLOBALIZATION_SOURCES} pal_timeZoneInfo.c)
@@ -80,6 +84,11 @@ endif()
8084
include_directories("../Common")
8185

8286
if (GEN_SHARED_LIB)
87+
if (CLR_CMAKE_TARGET_OSX OR CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
88+
include(CMakeFindFrameworks)
89+
find_library(FOUNDATION Foundation REQUIRED)
90+
endif()
91+
8392
add_library(System.Globalization.Native
8493
SHARED
8594
${NATIVEGLOBALIZATION_SOURCES}
@@ -88,12 +97,12 @@ if (GEN_SHARED_LIB)
8897

8998
target_link_libraries(System.Globalization.Native
9099
dl
100+
${FOUNDATION}
91101
)
92102

93103
install_with_stripped_symbols (System.Globalization.Native PROGRAMS .)
94104
endif()
95105

96-
97106
add_library(System.Globalization.Native-Static
98107
STATIC
99108
${NATIVEGLOBALIZATION_SOURCES}

src/libraries/Native/Unix/System.Globalization.Native/pal_locale.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,15 @@ int32_t FixupLocaleName(UChar* value, int32_t valueLength)
129129
return i;
130130
}
131131

132-
// We use whatever ICU give us as the default locale except if it is en_US_POSIX. We'll map
133-
// this POSIX locale to Invariant instead. The reason is POSIX locale collation behavior
134-
// is not desirable at all because it doesn't support case insensitive string comparisons.
132+
// We use whatever ICU give us as the default locale except if it is en_US_POSIX.
133+
//
134+
// On Apple related platforms (OSX, iOS, tvOS, MacCatalyst), we'll take what the system locale is.
135+
// On all other platforms we'll map this POSIX locale to Invariant instead.
136+
// The reason is POSIX locale collation behavior is not desirable at all because it doesn't support case insensitive string comparisons.
135137
const char* DetectDefaultLocaleName()
136138
{
137139
const char* icuLocale = uloc_getDefault();
140+
138141
if (strcmp(icuLocale, "en_US_POSIX") == 0)
139142
{
140143
return "";
@@ -216,6 +219,16 @@ int32_t GlobalizationNative_GetDefaultLocaleName(UChar* value, int32_t valueLeng
216219

217220
const char* defaultLocale = DetectDefaultLocaleName();
218221

222+
#ifdef __APPLE__
223+
char* appleLocale = NULL;
224+
225+
if (strcmp(defaultLocale, "") == 0)
226+
{
227+
appleLocale = DetectDefaultAppleLocaleName();
228+
defaultLocale = appleLocale;
229+
}
230+
#endif
231+
219232
uloc_getBaseName(defaultLocale, localeNameBuffer, ULOC_FULLNAME_CAPACITY, &status);
220233
u_charsToUChars_safe(localeNameBuffer, value, valueLength, &status);
221234

@@ -236,6 +249,11 @@ int32_t GlobalizationNative_GetDefaultLocaleName(UChar* value, int32_t valueLeng
236249
}
237250
}
238251

252+
#ifdef __APPLE__
253+
if (appleLocale)
254+
free(appleLocale);
255+
#endif
256+
239257
return UErrorCodeToBool(status);
240258
}
241259

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
#include <stdlib.h>
5+
#include "pal_locale_internal.h"
6+
7+
#import <Foundation/Foundation.h>
8+
9+
char* DetectDefaultAppleLocaleName()
10+
{
11+
NSLocale *currentLocale = [NSLocale currentLocale];
12+
NSString *localeName = @"";
13+
14+
if (!currentLocale)
15+
{
16+
return strdup([localeName UTF8String]);
17+
}
18+
19+
if ([currentLocale.languageCode length] > 0 && [currentLocale.countryCode length] > 0)
20+
{
21+
localeName = [NSString stringWithFormat:@"%@-%@", currentLocale.languageCode, currentLocale.countryCode];
22+
}
23+
else
24+
{
25+
localeName = currentLocale.localeIdentifier;
26+
}
27+
28+
return strdup([localeName UTF8String]);
29+
}
30+

src/libraries/Native/Unix/System.Globalization.Native/pal_locale_internal.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,13 @@ Detect the default locale for the machine, defaulting to Invaraint if
5151
we can't compute one (different from uloc_getDefault()) would do.
5252
*/
5353
const char* DetectDefaultLocaleName(void);
54+
55+
#ifdef __APPLE__
56+
/*
57+
Function:
58+
DetectDefaultSystemLocaleName
59+
60+
Detects the default locale string for Apple platforms
61+
*/
62+
char* DetectDefaultAppleLocaleName(void);
63+
#endif

src/libraries/System.Globalization/tests/CultureInfo/CultureInfoCurrentCulture.cs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ public void CurrentCulture()
3333
}
3434
}
3535

36+
[Fact]
37+
[PlatformSpecific(TestPlatforms.OSX | TestPlatforms.iOS | TestPlatforms.MacCatalyst | TestPlatforms.tvOS)]
38+
public void CurrentCulture_Default_Not_Invariant()
39+
{
40+
// On OSX-like platforms, it should default to what the default system culture is
41+
// set to. Since we shouldn't assume en-US, we just test if it's not the invariant
42+
// culture.
43+
Assert.NotEqual(CultureInfo.CurrentCulture, CultureInfo.InvariantCulture);
44+
Assert.NotEqual(CultureInfo.CurrentUICulture, CultureInfo.InvariantCulture);
45+
}
46+
3647
[Fact]
3748
public void CurrentCulture_Set_Null_ThrowsArgumentNullException()
3849
{
@@ -125,7 +136,7 @@ public void CurrentCulture_BasedOnLangEnvVar(string langEnvVar, string expectedC
125136
}, expectedCultureName, new RemoteInvokeOptions { StartInfo = psi }).Dispose();
126137
}
127138

128-
[PlatformSpecific(TestPlatforms.AnyUnix)] // When LANG is empty or unset, should default to the invariant culture on Unix.
139+
[PlatformSpecific(TestPlatforms.AnyUnix)]
129140
[ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
130141
[InlineData("")]
131142
[InlineData(null)]
@@ -141,13 +152,28 @@ public void CurrentCulture_DefaultWithNoLang(string langEnvVar)
141152
psi.Environment["LANG"] = langEnvVar;
142153
}
143154

155+
// When LANG is empty or unset, on Unix it should default to the invariant culture.
156+
// On OSX-like platforms, it should default to what the default system culture is
157+
// set to. Since we shouldn't assume en-US, we just test if it's not the invariant
158+
// culture.
144159
RemoteExecutor.Invoke(() =>
145160
{
146161
Assert.NotNull(CultureInfo.CurrentCulture);
147162
Assert.NotNull(CultureInfo.CurrentUICulture);
148163

149-
Assert.Equal("", CultureInfo.CurrentCulture.Name);
150-
Assert.Equal("", CultureInfo.CurrentUICulture.Name);
164+
if (PlatformDetection.IsOSXLike)
165+
{
166+
Assert.NotEqual("", CultureInfo.CurrentCulture.Name);
167+
Assert.NotEqual("", CultureInfo.CurrentUICulture.Name);
168+
169+
Assert.NotEqual(CultureInfo.CurrentCulture, CultureInfo.InvariantCulture);
170+
Assert.NotEqual(CultureInfo.CurrentUICulture, CultureInfo.InvariantCulture);
171+
}
172+
else
173+
{
174+
Assert.Equal("", CultureInfo.CurrentCulture.Name);
175+
Assert.Equal("", CultureInfo.CurrentUICulture.Name);
176+
}
151177
}, new RemoteInvokeOptions { StartInfo = psi }).Dispose();
152178
}
153179

src/mono/mono/mini/CMakeLists.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ if(HOST_DARWIN)
2323
set(OS_LIBS "-framework CoreFoundation" "-framework Foundation")
2424

2525
if(CMAKE_SYSTEM_VARIANT STREQUAL "MacCatalyst")
26-
set(OS_LIBS "-lobjc" "-lc++")
26+
set(OS_LIBS ${OS_LIBS} "-lobjc" "-lc++")
2727
endif()
2828
elseif(HOST_IOS)
2929
set(OS_LIBS "-framework CoreFoundation" "-lobjc" "-lc++")
@@ -79,6 +79,13 @@ if(HAVE_SYS_ICU)
7979
pal_timeZoneInfo.c
8080
entrypoints.c
8181
${pal_icushim_sources_base})
82+
83+
if (TARGET_DARWIN)
84+
set(icu_shim_sources_base
85+
${icu_shim_sources_base}
86+
pal_locale.m)
87+
endif()
88+
8289
addprefix(icu_shim_sources "${ICU_SHIM_PATH}" "${icu_shim_sources_base}")
8390
set_source_files_properties(${icu_shim_sources} PROPERTIES COMPILE_DEFINITIONS OSX_ICU_LIBRARY_PATH="${OSX_ICU_LIBRARY_PATH}")
8491
set_source_files_properties(${icu_shim_sources} PROPERTIES COMPILE_FLAGS "-I\"${ICU_INCLUDEDIR}\" -I\"${CMAKE_CURRENT_SOURCE_DIR}/../../../libraries/Native/Unix/System.Globalization.Native/\" -I\"${CMAKE_CURRENT_SOURCE_DIR}/../../../libraries/Native/Unix/Common/\" ${ICU_FLAGS}")

0 commit comments

Comments
 (0)