Plasma/KDE ignores LANG variable for new user accounts

For new user accounts, Plasma/KDE ignores the environment variable LANG, but falls back to C.UTF-8. Moreover it creates a file ~/.config/plasma-localerc with LANG=C.utf8.

Users can open the system settings and change their locale which updates plasma-localerc to the correct value, but it is annoying. Moreover the system settings greet the user with the warning that C.utf8 was not a valid locale.

Where does KDE take that value C.utf8 (or C.UTF-8) from?

I already found a work-around. If I put .config/plasma-localerc into /etc/skel (or in any home directory for users which haven’t yet logged in) with the desired value, Plasma/KDE uses that value. But I am really more interested where Plasma/KDE initially takes the wrong value C.UTF-8 from, if plasma-localerc doesn’t exist yet and Plasma/KDE generates it automatically.


Here is my setup which is a little bit more complex than usual, because I want all system daemons to run with C.UTF-8 (for untranslated log messages), but all user-facing daemons and all UI should be de_DE.UTF-8.

  • Localization for System
    • /etc/locale.conf sets LANG=C.UTF-8
    • /etc/env.d/02locale is a symbolic link to /etc/locale.conf (I am a Genoo user.)
    • /etc/profile.env is a generated file (from /etc/locale.conf and hence also sets LANG=C.UTF-8 .
    • /etc/environment.d/10-gentoo-env.conf, see previous point
  • Localization for User-Facing Services and User Default
    • /etc/locale-users.conf sets
      LANG=de_DE.UTF-8
      GDM_LANG=de_DE.UTF-8
      LANGUAGE=de_DE:en_US
      
    • /etc/environment.d/20-locale.conf is a symbolic link to /etc/locale-users.conf; as it is lexicographically later, it overrides /etc/environment.d/10-gentoo-env.conf
      The SystemD User Service Manager parses the directory /etc/environment.d/ for each user service it starts.
    • For the SystemD User Service Manager itself, I have a service drop-in via /etc/systemd/system/user@.service.d/override.conf with:
      [Service]
      EnvironmentFile=-/etc/locale-users.conf
      
      (The idea for that is from Arch Wiki: SystemD User - Environment Variables.)
  • Localization for Individual Users
    • In /etc/skel and home directory of each user the file .config/environment.d/20-locale.conf sets
      LANG=de_DE.UTF-8
      

I can confirm that the setup generally works as it should. For any other environment variable than LANG the command systemctl --user show-environment outputs the value as set in locale-users.conf. However, for LANG Plasma/KDE somehow seems to overwrite it and fall back to C.UTF-8. Why?

My only explanation so far is that Plasma/KDE explicitly parses /etc/locale.conf (or some other system-wide configurtion file) and overwrites the environment variables with those values instead honoring what is already set.

Hi - this is definitely not an area of expertise of mine, but just to rule one thing out - do you notice the same thing in the resulting environment if you create a new user account outside of Plasma, then log in to it via TTY?

Of course the plasma-localerc file might not have been created yet, but using systemctl --user show-environment as you did might show whether or not the big sequence of files you have setup there is being parsed as you expect for that variable.

Just thinking that if you see the same undesired result even in a TTY, what you’re experiencing wouldn’t be a result of something unique to Plasma / a GUI session. If the same thing doesn’t happen in a TTY, then there’s something unique happening with the user account creation from Plasma/from the GUI.

Haven’t thought about that as a test case. I tried it and it works as expected.
I switched to a (non-graphical) virtual console, logged in as root, run useradd john.doe, logged out, logged in as john.doe and systemctl --user show-environment as well as env returned the correct settings for LANG.

On a TTY and via SSH, it works indeed as expected. And sorry for the long list of files. There’s a lot of noise due to the many indirections and symbolic which are set up by the distros nowadays. But I thought I should present the entire picture and not keep something back, just in case the error was there.

Essentially, there are three relevant files /etc/locale.conf for the system setting, /etc/environment.d/20-locale.conf to define the default for all users and ~/.config/environment.d/20-locale.conf for each individual user.

Using a virtual console on TTY I was able to confirm that the three files also interact as expected. The individual setting in ~/.config/environment.d/20-locale.conf takes precedence over /etc/environment.d/20-locale.conf for all users, which in turn takes precedence over /etc/locale.conf.

I assume we can now confirm that this behavior is unique to Plasma/KDE. Also note that the only problematic variable is LANG. The three files ( /etc/locale.conf, /etc/environment.d/20-locale.conf and ~/.config/environment.d/20-locale.conf) set more than just LANG, for example GDM_LANG and LANGUAGE. For any other variable than LANG, the settings and their precedence over each other work as expected even within a Plasma/KDE session.

So it really seems as if Plasma/KDE falls back to a wrong initial value for LANG if ~/.config/plasma-localerc does not exist, exports that wrong value to the user session (therewith overriding the correct setting for LANG) and stores that value in ~/.config/plasma-localerc.

I guess it is time to investigate some source code to see how Plasma/KDE obtains the initial value for LANG if ~/.config/plasma-localerc does not exist. Obviously, Plasma/KDE doesn’t take the value from the already set environment variable.

I guess I found the the cause for the problem. It is not entirely Plasma/KDE’s own fault, but shared responsibility of SDDM (my display manager), the timing when which environment variable is read and startplasma.

For the Plasma/KDE part the relevant code snippet is: GitHub: Plasma Workspace - startkde/startplasma.cpp:Backend::openSession() (lines 177-217). As you can see at the end of that method, the LANG variable gets a special treatment: If the variable is not set in formatsConfig (aka plasma-localerc), but set as an environment variable, then the current value of that environment variable is written to plasma-localerc and synced. So far nothing suspicious. I stress the workd “current”, because timing will be crucial. However, this code snippet explains, why I only see the problems with the LANG variable and no other variable.

For the SDDM part I haven’t been able to pin point the exact code location, but it is somewhere in the sddm-helper application. When you look around at GitHub: SDDM - src/helper one sees that they do a lot of crazy stuff with the environment variables like clearing them all, and then re-constructing a “cleansed” environment, etc.

Here is what happens. A typical pstree looks like

systemd,1 --switched-root --system --deserialize=50 splash
  ├─sddm,711
  │   └─sddm-helper,886 --socket /tmp/sddm-auth-65c418cf-f7c6-4130-8213-9d60d6c82829 --id 1 --start /usr/libexec/plasma-dbus-run-session-if-needed /usr/bin/startplasma-wayland --user matthias
  │       └─startplasma-wayland,935
  └─systemd,908 --user
      └─plasmashell,1221 --no-respawn

sddm (PID 711) creates the initial login screen. Although this process runs as a child of the system systemd (PID 1), the environment is fine:

/proc # cat 711/environ | tr '\0' '\n' | egrep LANG
LANG=de_DE.UTF-8
GDM_LANG=de_DE.UTF-8
LANGUAGE=de_DE:en_US

(Because I have the that service drop-in for sddm.service.) When the user attempts to authenticate, sddm spawns sddm-helper. This sddm-helper clears the environment and creates a “cleansed” one:

/proc # cat 886/environ | tr '\0' '\n'
LANG="C.UTF-8"

(Note: I did not even use egrep here to filter for LANG. That is everything which is set.) sddm-helper spawns startplasma-wayland. Now, this is the unlucky moment in time, when startplasma-wayland picks up the wrong initial value for LANG due to the code in void runStartupConfig() which I have linked above.

The environment for the user’s systemd (PID 908) is fine again:

/proc # cat 908/environ | tr '\0' '\n' | egrep LANG
LANG=de_DE.UTF-8
GDM_LANG=de_DE.UTF-8
LANGUAGE=de_DE:en_US

Unfortunately, this is too late, because Plasma has already read and written the wrong value for LANG.

IMHO, this is definitely a bug in either SDDM or Plasma or both. I do not know, why SDDM clears the environment. Maybe as a safety measure to clear any potentially harmful environment variables a user might have been set. But in doing so, SDDM goes a little over the edge. Or it is a bug in Plasma, because Plasma tries to read LANG at the wrong moment in time. Maybe Plasma should do within the user’s SystemD session after everything is “proper” again.

I posted two bug reports: