diff --git a/quickshell/Common/I18n.qml b/quickshell/Common/I18n.qml index 9e01b656..1b770f16 100644 --- a/quickshell/Common/I18n.qml +++ b/quickshell/Common/I18n.qml @@ -8,7 +8,9 @@ import Quickshell.Io Singleton { id: root - readonly property string _rawLocale: SettingsData.locale === "" ? Qt.locale().name : SettingsData.locale + property string _resolvedLocale: "en" + + readonly property string _rawLocale: SessionData.locale === "" ? Qt.locale().name : SessionData.locale readonly property string _lang: _rawLocale.split(/[_-]/)[0] readonly property var _candidates: { const fullUnderscore = _rawLocale; @@ -49,22 +51,21 @@ Singleton { try { root.translations = JSON.parse(text()); root.translationsLoaded = true; - console.info(`I18n: Loaded translations for '${SettingsData.locale}' (${Object.keys(root.translations).length} contexts)`); + console.info(`I18n: Loaded translations for '${root._resolvedLocale}' (${Object.keys(root.translations).length} contexts)`); } catch (e) { - console.warn(`I18n: Error parsing '${SettingsData.locale}':`, e, "- falling back to English"); + console.warn(`I18n: Error parsing '${root._resolvedLocale}':`, e, "- falling back to English"); root._fallbackToEnglish(); } } onLoadFailed: error => { - console.warn(`I18n: Failed to load '${SettingsData.locale}' (${error}), ` + "falling back to English"); + console.warn(`I18n: Failed to load '${root._resolvedLocale}' (${error}), ` + "falling back to English"); root._fallbackToEnglish(); } } - // for replacing Qt.locale() function locale() { - return presentLocales[SettingsData.locale] ?? presentLocales["en"]; + return presentLocales[_resolvedLocale] ?? presentLocales["en"]; } function _loadPresentLocales() { @@ -83,16 +84,18 @@ Singleton { function _pickTranslation() { for (let i = 0; i < _candidates.length; i++) { const cand = _candidates[i]; - if (presentLocales[cand] !== undefined) { - SettingsData.set("locale", cand); - return; - } + if (presentLocales[cand] === undefined) continue; + _resolvedLocale = cand; + useLocale(cand, cand.startsWith("en") ? "" : translationsFolder + "/" + cand + ".json"); + return; } + _resolvedLocale = "en"; _fallbackToEnglish(); } function useLocale(localeTag, fileUrl) { + _resolvedLocale = localeTag || "en"; _selectedPath = fileUrl; translationsLoaded = false; translations = ({}); diff --git a/quickshell/Common/SessionData.qml b/quickshell/Common/SessionData.qml index 62df4fa3..4ca0fa8a 100644 --- a/quickshell/Common/SessionData.qml +++ b/quickshell/Common/SessionData.qml @@ -21,7 +21,9 @@ Singleton { property bool _isReadOnly: false property bool _hasUnsavedChanges: false property var _loadedSessionSnapshot: null - readonly property var _hooks: ({}) + readonly property var _hooks: ({ + "updateLocale": updateLocale + }) readonly property string _stateUrl: StandardPaths.writableLocation(StandardPaths.GenericStateLocation) readonly property string _stateDir: Paths.strip(_stateUrl) @@ -126,6 +128,8 @@ Singleton { property var hiddenOutputDeviceNames: [] property var hiddenInputDeviceNames: [] + property string locale: "" + property string launcherLastMode: "all" property string appDrawerLastMode: "apps" property string niriOverviewLastMode: "apps" @@ -1104,6 +1108,14 @@ Singleton { saveSettings(); } + function updateLocale() { + if (!locale) { + I18n._pickTranslation(); + return; + } + I18n.useLocale(locale, locale.startsWith("en") ? "" : I18n.folder + "/" + locale + ".json"); + } + function setLauncherLastMode(mode) { launcherLastMode = mode; saveSettings(); diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index 8bdd40b2..7b585ff9 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -149,7 +149,6 @@ Singleton { property int mangoLayoutRadiusOverride: -1 property int mangoLayoutBorderSize: -1 - property string locale: "" property bool use24HourClock: true property bool showSeconds: false property bool padHours12Hour: false @@ -1131,10 +1130,6 @@ Singleton { Quickshell.execDetached(["sh", "-lc", script]); } - function updateLocale() { - I18n.useLocale(locale, locale.startsWith("en") ? "" : I18n.folder + "/" + locale + ".json"); - } - readonly property var _hooks: ({ "applyStoredTheme": applyStoredTheme, "regenSystemThemes": regenSystemThemes, @@ -1142,7 +1137,6 @@ Singleton { "applyStoredIconTheme": applyStoredIconTheme, "updateBarConfigs": updateBarConfigs, "updateCompositorCursor": updateCompositorCursor, - "updateLocale": updateLocale, }) function set(key, value) { @@ -2646,7 +2640,6 @@ Singleton { _hasLoaded = true; applyStoredTheme(); updateCompositorCursor(); - updateLocale(); } catch (e) { _parseError = true; const msg = e.message; diff --git a/quickshell/Common/settings/SessionSpec.js b/quickshell/Common/settings/SessionSpec.js index 9797e45e..b9805ede 100644 --- a/quickshell/Common/settings/SessionSpec.js +++ b/quickshell/Common/settings/SessionSpec.js @@ -79,6 +79,8 @@ var SPEC = { hiddenOutputDeviceNames: { def: [] }, hiddenInputDeviceNames: { def: [] }, + locale: { def: "", onChange: "updateLocale" }, + launcherLastMode: { def: "all" }, appDrawerLastMode: { def: "apps" }, niriOverviewLastMode: { def: "apps" } diff --git a/quickshell/Common/settings/SettingsSpec.js b/quickshell/Common/settings/SettingsSpec.js index 50958679..9a94d6e2 100644 --- a/quickshell/Common/settings/SettingsSpec.js +++ b/quickshell/Common/settings/SettingsSpec.js @@ -32,7 +32,6 @@ var SPEC = { mangoLayoutRadiusOverride: { def: -1, onChange: "updateCompositorLayout" }, mangoLayoutBorderSize: { def: -1, onChange: "updateCompositorLayout" }, - locale: { def: "", onChange: "updateLocale" }, use24HourClock: { def: true }, showSeconds: { def: false }, padHours12Hour: { def: false }, diff --git a/quickshell/Modules/Settings/LocaleTab.qml b/quickshell/Modules/Settings/LocaleTab.qml index 18c79c7c..f0b23d4b 100644 --- a/quickshell/Modules/Settings/LocaleTab.qml +++ b/quickshell/Modules/Settings/LocaleTab.qml @@ -5,7 +5,9 @@ import qs.Widgets import qs.Modules.Settings.Widgets Item { - id: root + id: localeTab + + readonly property string _systemDefaultLabel: I18n.tr("System Default") function capitalizeNativeLanguageName(localeCode) { if (I18n.presentLocales[localeCode] == undefined) { @@ -15,6 +17,11 @@ Item { return nativeName[0].toUpperCase() + nativeName.slice(1); } + function _displayValue() { + if (!SessionData.locale) return _systemDefaultLabel; + return capitalizeNativeLanguageName(SessionData.locale); + } + DankFlickable { anchors.fill: parent clip: true @@ -41,17 +48,21 @@ Item { settingKey: "locale" text: I18n.tr("Current Locale") description: I18n.tr("Change the locale used by the DMS interface.") - options: Object.keys(I18n.presentLocales).map(root.capitalizeNativeLanguageName) + options: [localeTab._systemDefaultLabel].concat(Object.keys(I18n.presentLocales).map(localeTab.capitalizeNativeLanguageName)) enableFuzzySearch: true Component.onCompleted: { - currentValue = root.capitalizeNativeLanguageName(SettingsData.locale); + currentValue = localeTab._displayValue(); } onValueChanged: value => { + if (value === localeTab._systemDefaultLabel) { + SessionData.set("locale", ""); + return; + } for (let code of Object.keys(I18n.presentLocales)) { - if (root.capitalizeNativeLanguageName(code) === value) { - SettingsData.set("locale", code); + if (localeTab.capitalizeNativeLanguageName(code) === value) { + SessionData.set("locale", code); return; } }