gnucash stable: Bug 799821 - £ symbol across whole UI shows as £

John Ralls jralls at code.gnucash.org
Tue Sep 29 18:36:27 EDT 2026


Updated	 via  https://github.com/Gnucash/gnucash/commit/56ccad9a (commit)
	from  https://github.com/Gnucash/gnucash/commit/55ed9d2e (commit)



commit 56ccad9a66af75ae3cc3ded43d1aef329ca06c94
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Sep 29 15:32:35 2026 -0700

    Bug 799821 - £ symbol across whole UI shows as £
    
    Windows: Get UTF16 localization strings and convert them thus bypassing
    the code page problem entirely.

diff --git a/libgnucash/core-utils/gnc-locale-utils.c b/libgnucash/core-utils/gnc-locale-utils.c
index 966e67b98f..b1e33fa5cf 100644
--- a/libgnucash/core-utils/gnc-locale-utils.c
+++ b/libgnucash/core-utils/gnc-locale-utils.c
@@ -26,8 +26,54 @@
 
 #include <glib.h>
 #include <glib/gi18n.h>
-#include <stdlib.h> /* for mbstowcs() */
 
+#ifdef G_OS_WIN32
+#include <windows.h>
+
+static void
+gnc_lconv_set_utf8 (char **p_value, wchar_t *w_value, const char *default_value)
+{
+    g_return_if_fail (p_value != NULL);
+    if (w_value && *w_value)
+        *p_value = g_utf16_to_utf8 (w_value, -1, NULL, NULL, NULL);
+    else
+        *p_value = g_strdup (default_value);
+}
+
+static LPCWSTR
+get_locale_name ()
+{
+    char* locale = setlocale(LC_MONETARY, NULL);
+    int len = 0;
+    len = strchr (locale, '.') - locale;
+    locale[2] = '-';
+    wchar_t *wlocale = g_utf8_to_utf16 (locale, len, NULL, NULL, NULL);
+    if (IsValidLocaleName(wlocale))
+        return wlocale;
+    return LOCALE_NAME_USER_DEFAULT;
+}
+
+#define BUFSIZE 10 //Max size used by LOCALE_SGROUPING.
+static wchar_t*
+get_lconv_wide_val (LCTYPE lctype)
+{
+    static wchar_t buffer[BUFSIZE];
+    LPCWSTR locale = get_locale_name ();
+    memset (buffer, 0, BUFSIZE * sizeof(wchar_t));
+    int count =  GetLocaleInfoEx (locale, lctype, buffer, BUFSIZE);
+    if (!count)
+    {
+        g_error("GetLocaleInfo failed for %ld, %ld", lctype, GetLastError());
+        return NULL;
+    }
+    if (lctype == LOCALE_SGROUPING || lctype == LOCALE_SMONGROUPING)
+    {
+        buffer[0] &= 0x0f; // The standard localeconv is a single uint8
+        buffer[1] = '\0';
+    }
+    return buffer;
+}
+#else
 static void
 gnc_lconv_set_utf8 (char **p_value, char *default_value)
 {
@@ -37,25 +83,7 @@ gnc_lconv_set_utf8 (char **p_value, char *default_value)
     if ((value == NULL) || (value[0] == 0))
         value = default_value;
 
-#ifdef G_OS_WIN32
-    {
-        /* get number of resulting wide characters */
-        size_t count = mbstowcs (NULL, value, 0);
-        if (count > 0)
-        {
-            /* malloc and convert */
-            wchar_t *wvalue = g_malloc ((count + 1) * sizeof(wchar_t));
-            count = mbstowcs (wvalue, value, count + 1);
-            if (count > 0)
-            {
-                *p_value = g_utf16_to_utf8 (wvalue, -1, NULL, NULL, NULL);
-            }
-            g_free (wvalue);
-        }
-    }
-#else /* !G_OS_WIN32 */
     *p_value = g_locale_to_utf8 (value, -1, NULL, NULL, NULL);
-#endif
 
     if (*p_value == NULL)
     {
@@ -65,6 +93,7 @@ gnc_lconv_set_utf8 (char **p_value, char *default_value)
     }
 }
 
+#endif
 static void
 gnc_lconv_set_char (char *p_value, char default_value)
 {
@@ -82,7 +111,28 @@ gnc_localeconv (void)
         return &lc;
 
     lc = *localeconv();
-
+#ifdef G_OS_WIN32
+    gnc_lconv_set_utf8(&lc.decimal_point,
+                       get_lconv_wide_val (LOCALE_SDECIMAL), ".");
+    gnc_lconv_set_utf8(&lc.thousands_sep,
+                       get_lconv_wide_val (LOCALE_STHOUSAND),",");
+    gnc_lconv_set_utf8(&lc.grouping,
+                       get_lconv_wide_val (LOCALE_SGROUPING), "\003");
+    gnc_lconv_set_utf8(&lc.int_curr_symbol,
+                       get_lconv_wide_val (LOCALE_SINTLSYMBOL), "USD ");
+    gnc_lconv_set_utf8(&lc.currency_symbol,
+                       get_lconv_wide_val (LOCALE_SCURRENCY), "$");
+    gnc_lconv_set_utf8(&lc.mon_decimal_point,
+                       get_lconv_wide_val (LOCALE_SMONDECIMALSEP), ".");
+    gnc_lconv_set_utf8(&lc.mon_thousands_sep,
+                       get_lconv_wide_val (LOCALE_SMONTHOUSANDSEP), ",");
+    gnc_lconv_set_utf8(&lc.mon_grouping,
+                       get_lconv_wide_val (LOCALE_SMONGROUPING), "\003");
+    gnc_lconv_set_utf8(&lc.negative_sign,
+                       get_lconv_wide_val (LOCALE_SNEGATIVESIGN), "-");
+    gnc_lconv_set_utf8(&lc.positive_sign,
+                       get_lconv_wide_val (LOCALE_SPOSITIVESIGN), "");
+#else
     gnc_lconv_set_utf8(&lc.decimal_point, ".");
     gnc_lconv_set_utf8(&lc.thousands_sep, ",");
     gnc_lconv_set_utf8(&lc.grouping, "\003");
@@ -93,7 +143,7 @@ gnc_localeconv (void)
     gnc_lconv_set_utf8(&lc.mon_grouping, "\003");
     gnc_lconv_set_utf8(&lc.negative_sign, "-");
     gnc_lconv_set_utf8(&lc.positive_sign, "");
-
+#endif
     gnc_lconv_set_char(&lc.frac_digits, 2);
     gnc_lconv_set_char(&lc.int_frac_digits, 2);
     gnc_lconv_set_char(&lc.p_cs_precedes, 1);



Summary of changes:
 libgnucash/core-utils/gnc-locale-utils.c | 92 ++++++++++++++++++++++++--------
 1 file changed, 71 insertions(+), 21 deletions(-)



More information about the gnucash-changes mailing list