Hide flag emoji on the web target, where they render as empty boxes

Compose for Web (js/wasmJs) draws everything through Skia onto a
<canvas> rather than through the browser's own text stack, so it has
no color-emoji font to fall back to — a flag's regional-indicator
codepoints render as empty tofu boxes instead of a flag. Reproduced
via a headless-Chrome screenshot of the running dev server.

Adds a per-platform supportsFlagEmoji() (true everywhere except
js/wasmJs) that currencyFlagEmoji() now checks first, so currency
rows on web just show the plain code/name with no flag rather than a
broken glyph.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FXcrACM5sok3M1KQJ8kByy
This commit is contained in:
2026-09-10 09:49:12 +03:00
co-authored by Claude Sonnet 5
parent fc68985b2d
commit e5b31f3750
6 changed files with 23 additions and 2 deletions
@@ -43,3 +43,5 @@ actual fun regionDisplayName(regionCode: String): String? {
if (regionCode !in Locale.getISOCountries()) return null
return Locale("", regionCode).getDisplayCountry(Locale.getDefault())
}
actual fun supportsFlagEmoji(): Boolean = true
@@ -37,3 +37,5 @@ actual fun currencyDecimalDigits(code: String): Int {
actual fun regionDisplayName(regionCode: String): String? =
NSLocale.currentLocale.localizedStringForCountryCode(regionCode)
actual fun supportsFlagEmoji(): Boolean = true
@@ -34,10 +34,13 @@ internal fun issuingCountryCodes(code: String): List<String> {
/**
* A country flag emoji for [code], or null when there's no flag to show — either because [code]
* isn't tied to any country, or because it's shared by more than [MAX_FLAGS_PER_CURRENCY]
* countries, which would be too visually noisy to show side by side.
* isn't tied to any country, because it's shared by more than [MAX_FLAGS_PER_CURRENCY] countries
* (too visually noisy to show side by side), or because [supportsFlagEmoji] says the platform
* can't render one anyway (Compose for Web's canvas-based text renderer has no color-emoji font
* to fall back to, so a flag's regional-indicator codepoints draw as empty boxes there).
*/
fun currencyFlagEmoji(code: String): String? {
if (!supportsFlagEmoji()) return null
val regionCodes = issuingCountryCodes(code)
if (regionCodes.isEmpty() || regionCodes.size > MAX_FLAGS_PER_CURRENCY) return null
return regionCodes.joinToString(" ") { regionFlagEmoji(it) }
@@ -45,3 +45,10 @@ expect fun localeCurrencyCode(): String?
/** The conventional number of decimal places for [code] (e.g. 2 for USD, 0 for JPY, 3 for BHD). */
expect fun currencyDecimalDigits(code: String): Int
/**
* Whether the current platform's text renderer can draw flag emoji. False on Compose for Web
* (js/wasmJs): its canvas-based Skia renderer has no bundled or system color-emoji font to draw a
* flag's regional-indicator codepoints with, so they'd otherwise render as empty boxes.
*/
expect fun supportsFlagEmoji(): Boolean
@@ -43,3 +43,5 @@ actual fun regionDisplayName(regionCode: String): String? {
if (regionCode !in Locale.getISOCountries()) return null
return Locale("", regionCode).getDisplayCountry(Locale.getDefault())
}
actual fun supportsFlagEmoji(): Boolean = true
@@ -53,3 +53,8 @@ private fun jsRegionDisplayName(regionCode: String): String = js(
actual fun regionDisplayName(regionCode: String): String? =
jsRegionDisplayName(regionCode).takeIf { it != regionCode }
// Compose for Web renders everything through Skia onto a <canvas> rather than through the
// browser's own text stack, so it can't fall back to the browser/OS's color-emoji font the way
// native targets can — a flag's regional-indicator codepoints draw as empty boxes instead.
actual fun supportsFlagEmoji(): Boolean = false