From edc9ed33801c2afaf64b26d2a77a501e6feae5f1 Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Sat, 1 Aug 2026 10:05:23 +0000 Subject: [PATCH] Intl: route canonicalizeLocaleIDWithoutNullTerminator through Bun__canonicalizeLocaleID uloc_canonicalize is documented as "does NOT map aliased names in any way", so Intl.Locale and Intl.getCanonicalLocales skip CLDR language/region alias replacement on Bun builds (fre -> fr, en-UK -> en-GB, sh -> sr-Latn, SU -> RU/AM). Safari avoids this via Apple's ualoc_canonicalForm SPI, gated behind USE(APPLE_INTERNAL_SDK). The CLDR-aware canonicalization lives in icu::Locale::createCanonical (runs ICU's AliasReplacer since ICU 68), but WebKit compiles with U_SHOW_CPLUSPLUS_API=0 so the ICU C++ API is not reachable from JSC. Instead, forward-declare a C wrapper with the uloc_canonicalize signature and let Bun implement it: on macOS Bun forwards to ualoc_canonicalForm (exported from libicucore on every supported macOS version), and elsewhere Bun statically links ICU and can safely call icu::Locale::createCanonical. Fixes oven-sh/bun#14713. --- Source/JavaScriptCore/runtime/IntlObject.cpp | 21 ++++++++++++++++---- Source/cmake/WebKitCompilerFlags.cmake | 2 ++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Source/JavaScriptCore/runtime/IntlObject.cpp b/Source/JavaScriptCore/runtime/IntlObject.cpp index a7c1c25b97347..0b511d7ecc40d 100644 --- a/Source/JavaScriptCore/runtime/IntlObject.cpp +++ b/Source/JavaScriptCore/runtime/IntlObject.cpp @@ -1632,6 +1632,18 @@ bool isWellFormedCurrencyCode(StringView currency) return currency.length() == 3 && currency.containsOnly(); } +#if USE(BUN_JSC_ADDITIONS) && !USE(APPLE_INTERNAL_SDK) +// uloc_canonicalize is documented to not map aliased names (ICU-21506), so +// Intl.Locale / Intl.getCanonicalLocales miss CLDR alias replacements like +// fre -> fr, en-UK -> en-GB, sh -> sr-Latn, SU -> RU/AM on Bun builds. The +// fix lives in icu::Locale::createCanonical (runs the CLDR AliasReplacer +// since ICU 68) / Apple's ualoc_canonicalForm SPI, neither of which is +// reachable here because Platform.h sets U_SHOW_CPLUSPLUS_API=0. Bun provides +// a C wrapper with the uloc_canonicalize signature instead. Weak so the jsc +// shell still links. +extern "C" __attribute__((weak)) int32_t Bun__canonicalizeLocaleID(const char*, char*, int32_t, UErrorCode*); +#endif + std::optional> canonicalizeLocaleIDWithoutNullTerminator(const char* localeID) { ASSERT(localeID); @@ -1641,15 +1653,16 @@ std::optional> canonicalizeLocaleIDWithoutNullTerminator(const // ICU-21506 is a bug upstreaming this SPI to ICU. // https://unicode-org.atlassian.net/browse/ICU-21506 auto status = callBufferProducingFunction(ualoc_canonicalForm, localeID, buffer); - if (U_FAILURE(status)) - return std::nullopt; - return buffer; +#elif USE(BUN_JSC_ADDITIONS) + auto status = Bun__canonicalizeLocaleID + ? callBufferProducingFunction(Bun__canonicalizeLocaleID, localeID, buffer) + : callBufferProducingFunction(uloc_canonicalize, localeID, buffer); #else auto status = callBufferProducingFunction(uloc_canonicalize, localeID, buffer); +#endif if (U_FAILURE(status)) return std::nullopt; return buffer; -#endif } std::optional mapICUCalendarKeywordToBCP47(const String& calendar) diff --git a/Source/cmake/WebKitCompilerFlags.cmake b/Source/cmake/WebKitCompilerFlags.cmake index 824ab8fdf54d7..ea7b704a1aa35 100644 --- a/Source/cmake/WebKitCompilerFlags.cmake +++ b/Source/cmake/WebKitCompilerFlags.cmake @@ -333,6 +333,7 @@ if (COMPILER_IS_GCC_OR_CLANG) -Wl,-U,_WTFTimer__secondsUntilTimer -Wl,-U,_WTFTimer__cancel -Wl,-U,_Bun__errorInstance__finalize + -Wl,-U,_Bun__canonicalizeLocaleID -Wl,-U,_Bun__reportUnhandledError) else() WEBKIT_PREPEND_GLOBAL_COMPILER_FLAGS(-Wl,-u,_WTFTimer__create @@ -342,6 +343,7 @@ if (COMPILER_IS_GCC_OR_CLANG) -Wl,-u,_WTFTimer__secondsUntilTimer -Wl,-u,_WTFTimer__cancel -Wl,-u,_Bun__errorInstance__finalize + -Wl,-u,_Bun__canonicalizeLocaleID -Wl,-u,_Bun__reportUnhandledError) endif() endif ()