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 {