diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml
index fda48d398..793eeef7e 100644
--- a/js/js-resources.gresource.xml
+++ b/js/js-resources.gresource.xml
@@ -30,6 +30,7 @@
misc/introspect.js
misc/jsParse.js
misc/keyboardManager.js
+ misc/languageManager.js
misc/loginManager.js
misc/modemManager.js
misc/objectManager.js
diff --git a/js/misc/languageManager.js b/js/misc/languageManager.js
new file mode 100644
index 000000000..a8c7ca4e3
--- /dev/null
+++ b/js/misc/languageManager.js
@@ -0,0 +1,34 @@
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+
+import AccountsService from 'gi://AccountsService';
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import * as Signals from './signals.js';
+import * as Gettext from 'gettext';
+
+export class LanguageManager extends Signals.EventEmitter {
+ constructor() {
+ super();
+
+ this._userManager = AccountsService.UserManager.get_default();
+ this._user = this._userManager.get_user(GLib.get_user_name());
+
+ this._user.connectObject('changed', this._onLanguageUpdated.bind(this));
+ }
+
+ _onLanguageUpdated() {
+ if (this.language === this._user.language)
+ return;
+
+ this.language = this._user.language;
+ this.emit('language-changed', this._user.language);
+ }
+
+ get language() {
+ return Gettext.setlocale(Gettext.LocaleCategory.ALL, null);
+ }
+
+ set language(newLanguage) {
+ Gettext.setlocale(Gettext.LocaleCategory.ALL, newLanguage)
+ }
+}
diff --git a/js/ui/main.js b/js/ui/main.js
index ad0ea962f..d92a85307 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -18,6 +18,7 @@ import * as ExtensionSystem from './extensionSystem.js';
import * as ExtensionDownloader from './extensionDownloader.js';
import * as InputMethod from '../misc/inputMethod.js';
import * as Introspect from '../misc/introspect.js';
+import * as LanguageManager from '../misc/languageManager.js';
import * as Keyboard from './keyboard.js';
import * as MessageTray from './messageTray.js';
import * as ModalDialog from './modalDialog.js';
@@ -57,6 +58,7 @@ const GNOMESHELL_STARTED_MESSAGE_ID = 'f3ea493c22934e26811cd62abe8e203a';
export let componentManager = null;
export let extensionManager = null;
+export let languageManager = null;
export let panel = null;
export let overview = null;
export let runDialog = null;
@@ -163,6 +165,8 @@ export async function start() {
if (!currentDesktop || !currentDesktop.split(':').includes('GNOME'))
Gio.DesktopAppInfo.set_desktop_env('GNOME');
+ languageManager = new LanguageManager.LanguageManager();
+
sessionMode = new SessionMode.SessionMode();
sessionMode.connect('updated', _sessionUpdated);
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 62c8ebb31..b5a29a4ac 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -680,6 +680,8 @@ class Panel extends St.Widget {
_('Top Bar'), 'shell-focus-top-bar-symbolic',
{sortGroup: CtrlAltTab.SortGroup.TOP});
+ Main.languageManager.connect('language-changed', this._updateLanguage.bind(this));
+
Main.sessionMode.connect('updated', this._updatePanel.bind(this));
global.display.connect('workareas-changed', () => this.queue_relayout());
@@ -854,6 +856,13 @@ class Panel extends St.Widget {
return this._leftBox.opacity;
}
+ _updateLanguage() {
+ this._leftBox.destroy_all_children();
+ this._centerBox.destroy_all_children();
+ this._rightBox.destroy_all_children();
+ this._updatePanel();
+ }
+
_updatePanel() {
let panel = Main.sessionMode.panel;
this._hideIndicators();