From 3f9f59ed8eafe5aeb25e231fc8e07932d30edf09 Mon Sep 17 00:00:00 2001 From: Dan Rosser Date: Sun, 18 Oct 2026 17:12:57 +1300 Subject: [PATCH 1/2] ofToLower / ofToUpper: use a UTF-8 locale when the environment has none MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With no locale argument these use the environment's locale. When LANG is unset (Docker images, chroots, some services) that is "C", which only maps ASCII case, so ofToLower("É") returned "É" and the strings test failed on a bare Ubuntu 24.04 container. If the locale maps no non-ASCII case, fall back to C.UTF-8 (part of glibc's libc-bin), C.utf8 or en_US.UTF-8. A locale passed explicitly is still used as is. --- libs/openFrameworks/utils/ofUtils.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libs/openFrameworks/utils/ofUtils.cpp b/libs/openFrameworks/utils/ofUtils.cpp index c362239b6c3..a5fa01f15f8 100644 --- a/libs/openFrameworks/utils/ofUtils.cpp +++ b/libs/openFrameworks/utils/ofUtils.cpp @@ -781,6 +781,17 @@ static std::locale getLocale(const string & locale) { } catch (...) { ofLogWarning("ofUtils") << "Couldn't create locale " << locale << " using default, " << loc.name(); } + // no locale asked for and the environment's locale only maps ASCII case (LANG unset, + // e.g. in a container, gives "C"): use a UTF-8 one for the UTF-8 strings these take + if (locale.empty() && std::tolower(L'\u00C9', loc) == L'\u00C9') { + for (const char * name : { "C.UTF-8", "C.utf8", "en_US.UTF-8" }) { + try { + loc = std::locale(name); + break; + } catch (...) { + } + } + } #endif return loc; } From 0591059a532af58406c236c824a668458d5e9429 Mon Sep 17 00:00:00 2001 From: Dan Rosser Date: Mon, 19 Oct 2026 11:30:07 +1300 Subject: [PATCH 2/2] Shorten the getLocale fallback comment --- libs/openFrameworks/utils/ofUtils.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/openFrameworks/utils/ofUtils.cpp b/libs/openFrameworks/utils/ofUtils.cpp index a5fa01f15f8..0c4af11c9e6 100644 --- a/libs/openFrameworks/utils/ofUtils.cpp +++ b/libs/openFrameworks/utils/ofUtils.cpp @@ -781,8 +781,7 @@ static std::locale getLocale(const string & locale) { } catch (...) { ofLogWarning("ofUtils") << "Couldn't create locale " << locale << " using default, " << loc.name(); } - // no locale asked for and the environment's locale only maps ASCII case (LANG unset, - // e.g. in a container, gives "C"): use a UTF-8 one for the UTF-8 strings these take + // default locale only maps ASCII case (e.g. LANG unset): use a UTF-8 one if (locale.empty() && std::tolower(L'\u00C9', loc) == L'\u00C9') { for (const char * name : { "C.UTF-8", "C.utf8", "en_US.UTF-8" }) { try {