1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-12 16:52:10 -04:00

feat: add setting to change and hotreload locale (#1817)

* feat: add setting to change and hotreload locale

* fix: typo in component id

* feat: add persistent locale setting

* feat: wrap useLocale in a settings set hook, enable locale hotreload when editing settings file

* chore: update translation and settings file

* feat: enable fuzzy search in locale setting

* fix: regenerate translations with official plugins cloned

* fix: revert back to system's locale for displaying certain time formats
This commit is contained in:
Jonas Bloch
2026-02-26 22:00:17 +01:00
committed by GitHub
parent f82d7610e3
commit 1fe72e1a66
21 changed files with 819 additions and 536 deletions

View File

@@ -8,7 +8,7 @@ import Quickshell.Io
Singleton {
id: root
readonly property string _rawLocale: Qt.locale().name
readonly property string _rawLocale: SettingsData.locale === "" ? Qt.locale().name : SettingsData.locale
readonly property string _lang: _rawLocale.split(/[_-]/)[0]
readonly property var _candidates: {
const fullUnderscore = _rawLocale;
@@ -21,7 +21,8 @@ Singleton {
readonly property url translationsFolder: Qt.resolvedUrl("../translations/poexports")
property string currentLocale: "en"
readonly property alias folder: dir.folder
property var presentLocales: ({ "en": Qt.locale("en") })
property var translations: ({})
property bool translationsLoaded: false
@@ -34,8 +35,10 @@ Singleton {
showDirs: false
showDotAndDotDot: false
onStatusChanged: if (status === FolderListModel.Ready)
root._pickTranslation()
onStatusChanged: if (status === FolderListModel.Ready) {
root._loadPresentLocales();
root._pickTranslation();
}
}
FileView {
@@ -46,32 +49,42 @@ Singleton {
try {
root.translations = JSON.parse(text());
root.translationsLoaded = true;
console.info(`I18n: Loaded translations for '${root.currentLocale}' ` + `(${Object.keys(root.translations).length} contexts)`);
console.info(`I18n: Loaded translations for '${SettingsData.locale}' (${Object.keys(root.translations).length} contexts)`);
} catch (e) {
console.warn(`I18n: Error parsing '${root.currentLocale}':`, e, "- falling back to English");
console.warn(`I18n: Error parsing '${SettingsData.locale}':`, e, "- falling back to English");
root._fallbackToEnglish();
}
}
onLoadFailed: error => {
console.warn(`I18n: Failed to load '${root.currentLocale}' (${error}), ` + "falling back to English");
console.warn(`I18n: Failed to load '${SettingsData.locale}' (${error}), ` + "falling back to English");
root._fallbackToEnglish();
}
}
function _pickTranslation() {
const present = new Set();
// for replacing Qt.locale()
function locale() {
return presentLocales[SettingsData.locale] ?? presentLocales["en"];
}
function _loadPresentLocales() {
if (Object.keys(presentLocales).length > 1) {
return; // already loaded
}
for (let i = 0; i < dir.count; i++) {
const name = dir.get(i, "fileName"); // e.g. "zh_CN.json"
if (name && name.endsWith(".json")) {
present.add(name.slice(0, -5));
const shortName = name.slice(0, -5);
presentLocales[shortName] = Qt.locale(shortName);
}
}
}
function _pickTranslation() {
for (let i = 0; i < _candidates.length; i++) {
const cand = _candidates[i];
if (present.has(cand)) {
_useLocale(cand, dir.folder + "/" + cand + ".json");
if (presentLocales[cand] !== undefined) {
SettingsData.set("locale", cand);
return;
}
}
@@ -79,8 +92,7 @@ Singleton {
_fallbackToEnglish();
}
function _useLocale(localeTag, fileUrl) {
currentLocale = localeTag;
function useLocale(localeTag, fileUrl) {
_selectedPath = fileUrl;
translationsLoaded = false;
translations = ({});
@@ -88,7 +100,6 @@ Singleton {
}
function _fallbackToEnglish() {
currentLocale = "en";
_selectedPath = "";
translationsLoaded = false;
translations = ({});

View File

@@ -149,6 +149,7 @@ Singleton {
property int mangoLayoutRadiusOverride: -1
property int mangoLayoutBorderSize: -1
property string locale: ""
property bool use24HourClock: true
property bool showSeconds: false
property bool padHours12Hour: false
@@ -1130,13 +1131,18 @@ 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,
"updateCompositorLayout": updateCompositorLayout,
"applyStoredIconTheme": applyStoredIconTheme,
"updateBarConfigs": updateBarConfigs,
"updateCompositorCursor": updateCompositorCursor
"updateCompositorCursor": updateCompositorCursor,
"updateLocale": updateLocale,
})
function set(key, value) {
@@ -2640,6 +2646,7 @@ Singleton {
_hasLoaded = true;
applyStoredTheme();
updateCompositorCursor();
updateLocale();
} catch (e) {
_parseError = true;
const msg = e.message;

View File

@@ -32,6 +32,7 @@ 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 },