How to Debug GNOME Applications with Locale Issues?

I’m encountering a strange issue with GNOME Weather and GNOME Clock. In my native locale (ko_KR.UTF-8), my home city (Seoul, Korea’s capital) is displayed in English, while other well-known cities, like Los Angeles (로스앤젤레스) and Brussels (브뤼셀), appear in Korean. I’m at a loss as to why this happens, and I’d like to debug this problem.

Here’s my understanding:

  • Both GNOME Weather and GNOME Clock rely on libgweather to retrieve location information.
  • GNOME Weather utilizes GJS, while GNOME Clock employs Vala.
  • libgweather maintains a location database, and translations for country/city names are provided through po files.
  • I’ve confirmed that the Korean translation includes numerous city names, including Seoul.
  • Both GNOME Weather and GNOME Clock call gweather_location_get_name to fetch the city name.

To verify libgweather’s functionality across locales, I wrote a C++ test program. It functioned as expected:

// A simple program that accepts latitude and longitude as arguments,
// and prints the name of the nearest city.
// Compile with -std=c++17, and link against libgweather4.
#include <iostream>
#include <libgweather/gweather.h>
#include <sstream>

namespace {

// locale-independent string to double conversion
double parse_double(const char *str) {
  std::stringstream stream;
  stream.imbue(std::locale::classic());
  stream << str;
  double result;
  stream >> result;
  return result;
}

} // namespace

int main(int argc, char **argv) {
  if (argc != 3) {
    std::cerr << "Usage: " << argv[0] << " <latitude> <longitude>\n";
    return 1;
  }

  setlocale (LC_ALL, "");

  const double lat = parse_double(argv[1]);
  const double lon = parse_double(argv[2]);

  GWeatherLocation *world = gweather_location_get_world();
  if (world == nullptr) {
    std::cerr << "Failed to get world location\n";
    return 1;
  }

  GWeatherLocation *loc = gweather_location_find_nearest_city(world, lat, lon);
  if (loc == nullptr) {
    std::cerr << "Failed to find nearest city\n";
    return 1;
  }
  const char *english_name = gweather_location_get_english_name(loc);
  const char *name = gweather_location_get_name(loc);
  std::cout << "Name: " << (name ? name : "null")
            << ", English name: " << (english_name ? english_name : "null")
            << '\n';
  return 0;
}

Here’s the test script:

#!/bin/bash

set -e

dump_gweather_city_name="$1"
if [[ -z "$dump_gweather_city_name" ]]; then
    echo "Usage: $0 <dump_gweather_city_name>"
    exit 1
fi

if [[ ! -f "$dump_gweather_city_name" ]]; then
    echo "Error: $dump_gweather_city_name not found"
    exit 1
fi

locales=("en_US.utf8" "ko_KR.utf8" "ja_JP.utf8" "fr_FR.utf8")
# Test Seoul, Los Angeles, Brussels
# Seoul: 37.56, 126.99
# Los Angeles: 34.05, -118.25
# Brussels: 50.85, 4.35
latitudes=(37.56 34.05 50.85)
longitudes=(126.99 -118.25 4.35)
num_cities=${#latitudes[@]}
for locale in "${locales[@]}"; do
    unset LANG LANGUAGE LC_ALL LC_ADDRESS LC_COLLATE LC_CTYPE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGE LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE LC_TIME
    set +e
    locale -a | grep -q "$locale"
    ret=$?
    set -e
    if [[ $ret -ne 0 ]]; then
       echo "Error: $locale not found."
       exit 1
    fi
    export LC_ALL="${locale//.utf8/.UTF-8}"
    echo "Testing locale: $locale"
    env | grep -E "^(LANG|LC_)"
    for i in $(seq 0 $((num_cities - 1))); do
        latitude=${latitudes[$i]}
        longitude=${longitudes[$i]}
        "$dump_gweather_city_name" "$latitude" "$longitude"
    done
done

The test script’s output demonstrates that the C++ program works flawlessly in all locales.

Testing locale: en_US.utf8
LC_ALL=en_US.UTF-8
Name: Seoul, English name: Seoul
Name: Los Angeles, English name: Los Angeles
Name: Brussels, English name: Brussels
Testing locale: ko_KR.utf8
LC_ALL=ko_KR.UTF-8
Name: 서울, English name: Seoul
Name: 로스앤젤레스, English name: Los Angeles
Name: 브뤼셀, English name: Brussels
Testing locale: ja_JP.utf8
LC_ALL=ja_JP.UTF-8
Name: ソウル, English name: Seoul
Name: ロサンジェルス, English name: Los Angeles
Name: ブリュッセル, English name: Brussels
Testing locale: fr_FR.utf8
LC_ALL=fr_FR.UTF-8
Name: Séoul, English name: Seoul
Name: Los Angeles, English name: Los Angeles
Name: Bruxelles, English name: Brussels

In contrast, testing with GNOME Weather and GNOME Clock reveals that libgweather returns city names in English for Seoul but in Korean for other locations.

Since I’m unfamiliar with Vala coding, I’m focusing on debugging GNOME Weather. I’ve examined environment variables related to locale and internationalization, but I can’t pinpoint why GNOME Weather displays my home city in English. Even using GDB and breakpoints, I’ve verified that the locale settings used in setlocale, g_dpgettext2, and g_dgettext are ko_KR.UTF-8. The cause of GNOME Weather displaying Seoul in English remains unclear.

Could someone offer assistance in debugging this issue? I’m currently using Fedora 40 with GNOME 46, and I’ve observed this behavior on Debian Bookworm with GNOME 43 as well.

It’s noteworthy that this problem only exists when GNOME’s location service is disabled ($ gsettings get org.gnome.system.location enabled returns false). With the location service enabled, my home city is displayed correctly in Korean. (When I tested this issue on a Debian Bookworm Live CD, the location service was enabled by default, so I didn’t encounter this problem until I disabled it.)

How did you inject the translations? I see that Damned Lies is still untranslated.

Ugh, actually they are there. Never mind.