diff --git a/.config/quickshell/ii/Translation.qml b/.config/quickshell/ii/Translation.qml index f579cef65..473a2426e 100644 --- a/.config/quickshell/ii/Translation.qml +++ b/.config/quickshell/ii/Translation.qml @@ -4,172 +4,100 @@ import QtQuick import Quickshell import Quickshell.Io import qs.modules.common +import qs.modules.common.functions Singleton { id: root - + property var translations: ({}) - property string currentLanguage: "en_US" property var availableLanguages: ["en_US"] - property bool isScanning: false + property bool isScanning: scanLanguagesProcess.running property bool isLoading: false - + property string translationKeepSuffix: "/*keep*/" + + property string languageCode: { + var configLang = Config?.options.language.ui ?? "auto"; + + if (configLang !== "auto") + return configLang; + + return Qt.locale().name; + } + Process { id: scanLanguagesProcess - command: ["find", Qt.resolvedUrl(Directories.config + "/quickshell/translations/").toString().replace("file://", ""), "-name", "*.json", "-exec", "basename", "{}", ".json", ";"] - running: false - + command: ["find", FileUtils.trimFileProtocol(Qt.resolvedUrl(Directories.config + "/quickshell/translations/").toString()), "-name", "*.json", "-exec", "basename", "{}", ".json", ";"] + running: true + stdout: SplitParser { onRead: data => { - if (data.trim().length === 0) return - - var files = data.trim().split('\n') - + if (data.trim().length === 0) + return; + var files = data.trim().split('\n'); + for (var i = 0; i < files.length; i++) { - var lang = files[i].trim() + var lang = files[i].trim(); if (lang.length > 0 && root.availableLanguages.indexOf(lang) === -1) { - root.availableLanguages.push(lang) + root.availableLanguages.push(lang); } } } } - + onExited: (exitCode, exitStatus) => { - root.isScanning = false + root.availableLanguages = [...root.availableLanguages] // Forcibly emit change + if (exitCode !== 0) { - root.availableLanguages = ["en_US"] + root.availableLanguages = ["en_US"]; } - root.loadTranslations() + // TODO: notify and offer to translate when translation not available } } - + + onLanguageCodeChanged: { + translationFileView.reload(); + } + FileView { id: translationFileView + path: root.languageCode?.length > 0 ? Qt.resolvedUrl(Directories.config + "/quickshell/translations/" + root.languageCode + ".json") : "" + onLoaded: { - var textContent = "" + var textContent = ""; try { - textContent = text() + textContent = text(); + var jsonData = JSON.parse(textContent); + root.translations = jsonData; } catch (e) { - root.translations = {} - root.isLoading = false - return - } - - if (textContent.length === 0) { - root.translations = {} - root.isLoading = false - return - } - - try { - var jsonData = JSON.parse(textContent) - root.translations = jsonData - root.isLoading = false - } catch (e) { - root.translations = {} - root.isLoading = false + console.log("[Translation] Failed to load translations:", e); + root.translations = {}; } + root.isLoading = false; } - onLoadFailed: (error) => { - root.translations = {} - root.isLoading = false + onLoadFailed: error => { + root.translations = {}; + root.isLoading = false; } } - - function detectSystemLanguage() { - var locale = Qt.locale().name - return locale - } - - function getLanguageCode() { - var configLang = "auto" - try { - configLang = Config.options.language.ui - } catch (e) { - configLang = "auto" - } - - if (configLang === "auto") { - return detectSystemLanguage() - } else { - if (root.availableLanguages.indexOf(configLang) !== -1) { - return configLang - } else { - return detectSystemLanguage() - } - } - } - - function loadTranslations() { - if (root.isScanning) { - return - } - - var targetLang = getLanguageCode() - root.currentLanguage = targetLang - - // Use empty translations for English (default language) - if (targetLang === "en_US" || targetLang === "en") { - root.translations = {} - return - } - - // Check if target language is available - if (root.availableLanguages.indexOf(targetLang) === -1) { - root.currentLanguage = "en_US" - root.translations = {} - return - } - - // Load translation file - root.isLoading = true - var translationsPath = Qt.resolvedUrl(Directories.config + "/quickshell/translations/" + targetLang + ".json") - translationFileView.path = translationsPath - } - + function tr(text) { - if (!text) { - return "" - } - - var key = text.toString() - - if (root.isLoading) { - return key - } - - if (root.currentLanguage === "en_US" || root.currentLanguage === "en" || !root.translations) { - return key - } - + if (!text) + return ""; + var key = text.toString(); + if (root.isLoading) + return key; + if (root.translations.hasOwnProperty(key)) { - var translation = root.translations[key] - if (translation && translation.toString().trim().length > 0) { - var str = translation.toString().trim() - if (str.endsWith("/*keep*/")) { - return str.substring(0, str.length - 8).trim() - } else { - return str - } - } else { - return translation.toString() + var translation = root.translations[key].toString().trim(); + if (translation.length === 0) + return key; + + if (translation.endsWith(root.translationKeepSuffix)) { + translation = translation.substring(0, translation.length - root.translationKeepSuffix.length).trim(); } + return translation; } - return key // Fallback to key name - } - - function reloadTranslations() { - root.scanLanguages() - } - - function scanLanguages() { - var translationsDir = Qt.resolvedUrl(Directories.config + "/quickshell/translations/").toString().replace("file://", "") - root.isScanning = true - scanLanguagesProcess.running = true - } - - Component.onCompleted: { - root.scanLanguages() + return key; // Fallback to key name } } diff --git a/.config/quickshell/ii/modules/settings/InterfaceConfig.qml b/.config/quickshell/ii/modules/settings/InterfaceConfig.qml index eace76294..11e6811b4 100644 --- a/.config/quickshell/ii/modules/settings/InterfaceConfig.qml +++ b/.config/quickshell/ii/modules/settings/InterfaceConfig.qml @@ -115,7 +115,6 @@ ContentPage { to: 150 stepSize: 1 onValueChanged: { - console.log(value/100) Config.options.background.parallax.workspaceZoom = value / 100; } } @@ -403,38 +402,19 @@ ContentPage { currentValue: Config.options.language.ui onSelected: newValue => { Config.options.language.ui = newValue; - reloadNotice.visible = true; } - options: { - var baseOptions = [ - { - displayName: Translation.tr("Auto (System)"), - value: "auto" - } - ]; - - // Generate language options from available languages - // Intl.DisplayNames is not used. Show the language code with underscore replaced by hyphen. - for (var i = 0; i < Translation.availableLanguages.length; i++) { - var lang = Translation.availableLanguages[i]; - var displayName = lang.replace('_', '-'); - baseOptions.push({ - displayName: displayName, + options: [ + { + displayName: Translation.tr("Auto (System)"), + value: "auto" + }, + ...Translation.availableLanguages.map(lang => { + return { + displayName: lang.replace('_', '-'), value: lang - }); - } - - return baseOptions; - } - } - - NoticeBox { - id: reloadNotice - visible: false - Layout.topMargin: 8 - Layout.fillWidth: true - - text: Translation.tr("Language setting saved. Please restart Quickshell (Ctrl+Super+R) to apply the new language.") + }; + }) + ] } } } diff --git a/.config/quickshell/ii/settings.qml b/.config/quickshell/ii/settings.qml index 0d77b1fa5..9994c7609 100644 --- a/.config/quickshell/ii/settings.qml +++ b/.config/quickshell/ii/settings.qml @@ -211,7 +211,9 @@ ApplicationWindow { opacity: 1.0 active: Config.ready - source: root.pages[0].component + Component.onCompleted: { + source = root.pages[0].component + } Connections { target: root diff --git a/.config/quickshell/ii/welcome.qml b/.config/quickshell/ii/welcome.qml index 0380ef448..63b6787c8 100644 --- a/.config/quickshell/ii/welcome.qml +++ b/.config/quickshell/ii/welcome.qml @@ -12,7 +12,6 @@ import QtQuick.Layouts import QtQuick.Window import Quickshell import Quickshell.Io -import Quickshell.Hyprland import qs import qs.services import qs.modules.common @@ -27,13 +26,8 @@ ApplicationWindow { property bool showNextTime: false visible: true onClosing: { - Quickshell.execDetached([ - "notify-send", - Translation.tr("Welcome app"), - Translation.tr("Enjoy! You can reopen the welcome app any time with Super+Shift+Alt+/. To open the settings app, hit Super+I"), - "-a", "Shell" - ]) - Qt.quit() + Quickshell.execDetached(["notify-send", Translation.tr("Welcome app"), Translation.tr("Enjoy! You can reopen the welcome app any time with Super+Shift+Alt+/. To open the settings app, hit Super+I"), "-a", "Shell"]); + Qt.quit(); } title: Translation.tr("illogical-impulse Welcome") @@ -118,6 +112,7 @@ ApplicationWindow { } } } + Rectangle { // Content container color: Appearance.m3colors.m3surfaceContainerLow @@ -132,11 +127,69 @@ ApplicationWindow { anchors.fill: parent ContentSection { + Layout.fillWidth: true + icon: "language" + title: Translation.tr("Language") + + ConfigSelectionArray { + id: languageSelector + currentValue: Config.options.language.ui + onSelected: newValue => { + Config.options.language.ui = newValue; + } + options: [ + { + displayName: Translation.tr("Auto (System)"), + value: "auto" + }, + ...Translation.availableLanguages.map(lang => { + return { + displayName: lang.replace('_', '-'), + value: lang + }; + })] + } + } + + ContentSection { + icon: "screenshot_monitor" title: Translation.tr("Bar") ConfigRow { ContentSubsection { - title: "Corner style" + title: Translation.tr("Bar position") + ConfigSelectionArray { + currentValue: (Config.options.bar.bottom ? 1 : 0) | (Config.options.bar.vertical ? 2 : 0) + onSelected: newValue => { + Config.options.bar.bottom = (newValue & 1) !== 0; + Config.options.bar.vertical = (newValue & 2) !== 0; + } + options: [ + { + displayName: Translation.tr("Top"), + icon: "arrow_upward", + value: 0 // bottom: false, vertical: false + }, + { + displayName: Translation.tr("Left"), + icon: "arrow_back", + value: 2 // bottom: false, vertical: true + }, + { + displayName: Translation.tr("Bottom"), + icon: "arrow_downward", + value: 1 // bottom: true, vertical: false + }, + { + displayName: Translation.tr("Right"), + icon: "arrow_forward", + value: 3 // bottom: true, vertical: true + } + ] + } + } + ContentSubsection { + title: Translation.tr("Bar style") ConfigSelectionArray { currentValue: Config.options.bar.cornerStyle @@ -146,64 +199,31 @@ ApplicationWindow { options: [ { displayName: Translation.tr("Hug"), + icon: "line_curve", value: 0 }, { displayName: Translation.tr("Float"), + icon: "page_header", value: 1 }, { - displayName: Translation.tr("Plain rectangle"), + displayName: Translation.tr("Rect"), + icon: "toolbar", value: 2 } ] } } - - ContentSubsection { - title: "Bar layout" - ConfigSelectionArray { - currentValue: Config.options.bar.vertical - onSelected: newValue => { - Config.options.bar.vertical = newValue; - } - options: [ - { - displayName: Translation.tr("Horizontal"), - value: false - }, - { - displayName: Translation.tr("Vertical"), - value: true - }, - ] - } - } - } - - ConfigRow { - ConfigSwitch { - text: Translation.tr("Automatically hide") - checked: Config.options.bar.autoHide.enable - onCheckedChanged: { - Config.options.bar.autoHide.enable = checked; - } - } - ConfigSwitch { - text: Translation.tr("Place at the bottom/right") - checked: Config.options.bar.bottom - onCheckedChanged: { - Config.options.bar.bottom = checked; - } - } } } ContentSection { + icon: "format_paint" title: Translation.tr("Style & wallpaper") ButtonGroup { - Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter LightDarkPreferenceButton { dark: false } @@ -272,6 +292,7 @@ ApplicationWindow { } ContentSection { + icon: "rule" title: Translation.tr("Policies") ConfigRow { @@ -330,6 +351,7 @@ ApplicationWindow { } ContentSection { + icon: "info" title: Translation.tr("Info") Flow { @@ -384,6 +406,7 @@ ApplicationWindow { } ContentSection { + icon: "monitoring" title: Translation.tr("Useless buttons") Flow {