mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-01 19:18:28 -04:00
i18n: term overhaul
- Delete ~160-ish useless terms - Add context to more terms - Add a mechanism to duplicate the same terms with different contexts - sync
This commit is contained in:
@@ -36,6 +36,14 @@ repos:
|
|||||||
language: system
|
language: system
|
||||||
files: ^quickshell/(.*\.qml|translations/(term_freeze\.json|check_term_freeze\.py|extract_translations\.py))$
|
files: ^quickshell/(.*\.qml|translations/(term_freeze\.json|check_term_freeze\.py|extract_translations\.py))$
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: i18n-term-variants
|
||||||
|
name: i18n term variants (no case/punctuation duplicates)
|
||||||
|
entry: python3 quickshell/translations/check_term_variants.py
|
||||||
|
language: system
|
||||||
|
files: ^quickshell/(.*\.qml|translations/(check_term_variants\.py|extract_translations\.py))$
|
||||||
|
pass_filenames: false
|
||||||
- repo: local
|
- repo: local
|
||||||
hooks:
|
hooks:
|
||||||
- id: no-console-in-qml
|
- id: no-console-in-qml
|
||||||
|
|||||||
@@ -117,12 +117,17 @@ Singleton {
|
|||||||
log.warn("Falling back to built-in English strings");
|
log.warn("Falling back to built-in English strings");
|
||||||
}
|
}
|
||||||
|
|
||||||
function tr(term, context) {
|
// isRealContext is consumed by translations/extract_translations.py only:
|
||||||
|
// pass a literal `true` (same line) to give (term, context) its own POEditor
|
||||||
|
// translation slot. Lookup ignores it -- a real context exists as a bucket
|
||||||
|
// in the export, a comment-only context does not.
|
||||||
|
function tr(term, context, isRealContext) {
|
||||||
if (!translationsLoaded || !translations)
|
if (!translationsLoaded || !translations)
|
||||||
return term;
|
return term;
|
||||||
const ctx = context || term;
|
if (context && translations[context] && translations[context][term])
|
||||||
if (translations[ctx] && translations[ctx][term])
|
return translations[context][term];
|
||||||
return translations[ctx][term];
|
if (translations[term] && translations[term][term])
|
||||||
|
return translations[term][term];
|
||||||
for (const c in translations) {
|
for (const c in translations) {
|
||||||
if (translations[c] && translations[c][term])
|
if (translations[c] && translations[c][term])
|
||||||
return translations[c][term];
|
return translations[c][term];
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ Singleton {
|
|||||||
_parseError = true;
|
_parseError = true;
|
||||||
const msg = e.message;
|
const msg = e.message;
|
||||||
log.error("Failed to parse session.json - file will not be overwritten.");
|
log.error("Failed to parse session.json - file will not be overwritten.");
|
||||||
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse session.json"), msg));
|
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse %1").arg("session.json"), msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,7 +371,7 @@ Singleton {
|
|||||||
_parseError = true;
|
_parseError = true;
|
||||||
const msg = e.message;
|
const msg = e.message;
|
||||||
log.error("Failed to parse session.json - file will not be overwritten.");
|
log.error("Failed to parse session.json - file will not be overwritten.");
|
||||||
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse session.json"), msg));
|
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse %1").arg("session.json"), msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1793,7 +1793,7 @@ Singleton {
|
|||||||
_parseError = true;
|
_parseError = true;
|
||||||
const msg = e.message;
|
const msg = e.message;
|
||||||
log.error("Failed to parse settings.json - file will not be overwritten. Error:", msg);
|
log.error("Failed to parse settings.json - file will not be overwritten. Error:", msg);
|
||||||
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse settings.json"), msg));
|
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse %1").arg("settings.json"), msg));
|
||||||
applyStoredTheme();
|
applyStoredTheme();
|
||||||
} finally {
|
} finally {
|
||||||
_loading = false;
|
_loading = false;
|
||||||
@@ -1891,7 +1891,7 @@ Singleton {
|
|||||||
_pluginParseError = true;
|
_pluginParseError = true;
|
||||||
const msg = e.message;
|
const msg = e.message;
|
||||||
log.error("Failed to parse plugin_settings.json - file will not be overwritten. Error:", msg);
|
log.error("Failed to parse plugin_settings.json - file will not be overwritten. Error:", msg);
|
||||||
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse plugin_settings.json"), msg));
|
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse %1").arg("plugin_settings.json"), msg));
|
||||||
pluginSettings = {};
|
pluginSettings = {};
|
||||||
} finally {
|
} finally {
|
||||||
_pluginSettingsLoading = false;
|
_pluginSettingsLoading = false;
|
||||||
@@ -3653,7 +3653,7 @@ Singleton {
|
|||||||
_parseError = true;
|
_parseError = true;
|
||||||
const msg = e.message;
|
const msg = e.message;
|
||||||
log.error("Failed to reload settings.json - file will not be overwritten. Error:", msg);
|
log.error("Failed to reload settings.json - file will not be overwritten. Error:", msg);
|
||||||
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse settings.json"), msg));
|
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse %1").arg("settings.json"), msg));
|
||||||
} finally {
|
} finally {
|
||||||
_loading = false;
|
_loading = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1956,7 +1956,7 @@ Singleton {
|
|||||||
function applyGtkColors() {
|
function applyGtkColors() {
|
||||||
if (!matugenAvailable) {
|
if (!matugenAvailable) {
|
||||||
if (typeof ToastService !== "undefined") {
|
if (typeof ToastService !== "undefined") {
|
||||||
ToastService.showError(I18n.tr("matugen not available or disabled - cannot apply GTK colors"));
|
ToastService.showError(I18n.tr("matugen not available or disabled - cannot apply %1 colors").arg("GTK"));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1969,7 +1969,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (typeof ToastService !== "undefined") {
|
if (typeof ToastService !== "undefined") {
|
||||||
ToastService.showError(I18n.tr("Failed to apply GTK colors"));
|
ToastService.showError(I18n.tr("Failed to apply %1 colors").arg("GTK"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1978,7 +1978,7 @@ Singleton {
|
|||||||
function applyQtColors() {
|
function applyQtColors() {
|
||||||
if (!matugenAvailable) {
|
if (!matugenAvailable) {
|
||||||
if (typeof ToastService !== "undefined") {
|
if (typeof ToastService !== "undefined") {
|
||||||
ToastService.showError(I18n.tr("matugen not available or disabled - cannot apply Qt colors"));
|
ToastService.showError(I18n.tr("matugen not available or disabled - cannot apply %1 colors").arg("Qt"));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1990,7 +1990,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (typeof ToastService !== "undefined") {
|
if (typeof ToastService !== "undefined") {
|
||||||
ToastService.showError(I18n.tr("Failed to apply Qt colors"));
|
ToastService.showError(I18n.tr("Failed to apply %1 colors").arg("Qt"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -646,7 +646,7 @@ Singleton {
|
|||||||
|
|
||||||
onExited: exitCode => {
|
onExited: exitCode => {
|
||||||
if (exitCode === 0) {
|
if (exitCode === 0) {
|
||||||
const message = root.authApplyTerminalFallbackFromPrecheck ? I18n.tr("Terminal opened. Complete authentication setup there; it will close automatically when done.") : I18n.tr("Terminal fallback opened. Complete authentication setup there; it will close automatically when done.");
|
const message = root.authApplyTerminalFallbackFromPrecheck ? I18n.tr("Terminal opened. Complete authentication there; it will close automatically when done.") : I18n.tr("Terminal fallback opened. Complete authentication there; it will close automatically when done.");
|
||||||
ToastService.showInfo(message, "", "", "auth-sync");
|
ToastService.showInfo(message, "", "", "auth-sync");
|
||||||
} else {
|
} else {
|
||||||
let details = (root.authApplyTerminalFallbackStderr || "").trim();
|
let details = (root.authApplyTerminalFallbackStderr || "").trim();
|
||||||
|
|||||||
@@ -323,7 +323,7 @@ Item {
|
|||||||
target: TrashService
|
target: TrashService
|
||||||
function onEmptyTrashConfirmRequested(itemCount) {
|
function onEmptyTrashConfirmRequested(itemCount) {
|
||||||
emptyTrashConfirm.showWithOptions({
|
emptyTrashConfirm.showWithOptions({
|
||||||
title: I18n.tr("Empty Trash?"),
|
title: I18n.tr("Empty Trash"),
|
||||||
message: I18n.tr("Permanently delete %1 item(s)? This cannot be undone.").arg(itemCount),
|
message: I18n.tr("Permanently delete %1 item(s)? This cannot be undone.").arg(itemCount),
|
||||||
confirmText: I18n.tr("Empty"),
|
confirmText: I18n.tr("Empty"),
|
||||||
cancelText: I18n.tr("Cancel"),
|
cancelText: I18n.tr("Cancel"),
|
||||||
|
|||||||
@@ -408,14 +408,14 @@ FocusScope {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: "↵ " + I18n.tr("open")
|
text: "↵ " + I18n.tr("Open")
|
||||||
font.pixelSize: Theme.fontSizeSmall - 1
|
font.pixelSize: Theme.fontSizeSmall - 1
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: "Tab " + I18n.tr("actions")
|
text: "Tab " + I18n.tr("Actions")
|
||||||
font.pixelSize: Theme.fontSizeSmall - 1
|
font.pixelSize: Theme.fontSizeSmall - 1
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
visible: actionPanel.hasActions
|
visible: actionPanel.hasActions
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ Item {
|
|||||||
|
|
||||||
function statusTitle() {
|
function statusTitle() {
|
||||||
if (root.controller?.isSearching || root.controller?.isFileSearching)
|
if (root.controller?.isSearching || root.controller?.isFileSearching)
|
||||||
return I18n.tr("Searching");
|
return I18n.tr("Searching...");
|
||||||
if ((root.controller?.searchMode ?? "") === "files" && !DSearchService.dsearchAvailable)
|
if ((root.controller?.searchMode ?? "") === "files" && !DSearchService.dsearchAvailable)
|
||||||
return I18n.tr("File search unavailable");
|
return I18n.tr("File search unavailable");
|
||||||
if ((root.controller?.searchMode ?? "") === "files" && (root.controller?.searchQuery?.length ?? 0) < 2)
|
if ((root.controller?.searchMode ?? "") === "files" && (root.controller?.searchQuery?.length ?? 0) < 2)
|
||||||
|
|||||||
@@ -294,7 +294,7 @@ FocusScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Authentication failed, please try again")
|
text: I18n.tr("Authentication failed - try again")
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.error
|
color: Theme.error
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|||||||
@@ -494,7 +494,7 @@ FloatingWindow {
|
|||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Processes:", "process count label in footer")
|
text: I18n.tr("Processes", "process count label in footer") + ":"
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
@@ -511,7 +511,7 @@ FloatingWindow {
|
|||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Uptime:", "uptime label in footer")
|
text: I18n.tr("Uptime", "uptime label in footer") + ":"
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ PluginComponent {
|
|||||||
ccWidgetPrimaryText: I18n.tr("Printers")
|
ccWidgetPrimaryText: I18n.tr("Printers")
|
||||||
ccWidgetSecondaryText: {
|
ccWidgetSecondaryText: {
|
||||||
if (CupsService.cupsAvailable && CupsService.getPrintersNum() > 0) {
|
if (CupsService.cupsAvailable && CupsService.getPrintersNum() > 0) {
|
||||||
return I18n.tr("Printers: ") + CupsService.getPrintersNum() + " - " + I18n.tr("Jobs: ") + CupsService.getTotalJobsNum();
|
return I18n.tr("Printers") + ": " + CupsService.getPrintersNum() + " - " + I18n.tr("Jobs") + ": " + CupsService.getTotalJobsNum();
|
||||||
} else {
|
} else {
|
||||||
if (!CupsService.cupsAvailable) {
|
if (!CupsService.cupsAvailable) {
|
||||||
return I18n.tr("Print Server not available");
|
return I18n.tr("Print Server not available");
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ PluginComponent {
|
|||||||
ccWidgetPrimaryText: I18n.tr("VPN")
|
ccWidgetPrimaryText: I18n.tr("VPN")
|
||||||
ccWidgetSecondaryText: {
|
ccWidgetSecondaryText: {
|
||||||
if (vpnActivating)
|
if (vpnActivating)
|
||||||
return I18n.tr("Connecting…");
|
return I18n.tr("Connecting...");
|
||||||
if (!vpnActivated)
|
if (!vpnActivated)
|
||||||
return I18n.tr("Disconnected");
|
return I18n.tr("Disconnected");
|
||||||
const names = DMSNetworkService.activeNames || [];
|
const names = DMSNetworkService.activeNames || [];
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: scanButton.isDiscovering ? I18n.tr("Scanning") : I18n.tr("Scan")
|
text: scanButton.isDiscovering ? I18n.tr("Scanning...") : I18n.tr("Scan")
|
||||||
color: scanButton.adapterEnabled ? Theme.primary : Theme.surfaceVariantText
|
color: scanButton.adapterEnabled ? Theme.primary : Theme.surfaceVariantText
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
|
|||||||
@@ -624,7 +624,7 @@ Rectangle {
|
|||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: wifiDelegate.isConnecting ? I18n.tr("Connecting...") + " \u2022" : (wifiDelegate.isConnected ? I18n.tr("Connected") + " \u2022" : (modelData.secured ? I18n.tr("Secured") + " \u2022" : I18n.tr("Open") + " \u2022"))
|
text: wifiDelegate.isConnecting ? I18n.tr("Connecting...") + " \u2022" : (wifiDelegate.isConnected ? I18n.tr("Connected") + " \u2022" : (modelData.secured ? I18n.tr("Secured") + " \u2022" : I18n.tr("Open", "network security type", true) + " \u2022"))
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: wifiDelegate.isConnecting ? Theme.warning : Theme.surfaceVariantText
|
color: wifiDelegate.isConnecting ? Theme.warning : Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ Item {
|
|||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
DankButton {
|
DankButton {
|
||||||
text: root.saving ? I18n.tr("Saving…") : I18n.tr("Save")
|
text: root.saving ? I18n.tr("Saving...") : I18n.tr("Save")
|
||||||
iconName: "check"
|
iconName: "check"
|
||||||
buttonHeight: 32
|
buttonHeight: 32
|
||||||
backgroundColor: Theme.primary
|
backgroundColor: Theme.primary
|
||||||
|
|||||||
@@ -692,14 +692,14 @@ Item {
|
|||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Unsaved Changes")
|
text: I18n.tr("Unsaved changes")
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: root.pendingAction === "new" ? I18n.tr("You have unsaved changes. Save before creating a new file?") : root.pendingAction.startsWith("close_tab_") ? I18n.tr("You have unsaved changes. Save before closing this tab?") : root.pendingAction === "load_file" || root.pendingAction === "open" ? I18n.tr("You have unsaved changes. Save before opening a file?") : I18n.tr("You have unsaved changes. Save before continuing?")
|
text: I18n.tr("You have unsaved changes. Save before continuing?")
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: Theme.surfaceTextMedium
|
color: Theme.surfaceTextMedium
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Notification Timeouts")
|
text: I18n.tr("Timeouts")
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
@@ -182,7 +182,6 @@ Rectangle {
|
|||||||
id: lowTimeoutDropdown
|
id: lowTimeoutDropdown
|
||||||
transientSurfaceTracker: root.transientSurfaceTracker
|
transientSurfaceTracker: root.transientSurfaceTracker
|
||||||
text: I18n.tr("Low Priority")
|
text: I18n.tr("Low Priority")
|
||||||
description: I18n.tr("Timeout for low priority notifications")
|
|
||||||
currentValue: getTimeoutText(SettingsData.notificationTimeoutLow)
|
currentValue: getTimeoutText(SettingsData.notificationTimeoutLow)
|
||||||
options: timeoutOptions.map(opt => opt.text)
|
options: timeoutOptions.map(opt => opt.text)
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
@@ -199,7 +198,6 @@ Rectangle {
|
|||||||
id: normalTimeoutDropdown
|
id: normalTimeoutDropdown
|
||||||
transientSurfaceTracker: root.transientSurfaceTracker
|
transientSurfaceTracker: root.transientSurfaceTracker
|
||||||
text: I18n.tr("Normal Priority")
|
text: I18n.tr("Normal Priority")
|
||||||
description: I18n.tr("Timeout for normal priority notifications")
|
|
||||||
currentValue: getTimeoutText(SettingsData.notificationTimeoutNormal)
|
currentValue: getTimeoutText(SettingsData.notificationTimeoutNormal)
|
||||||
options: timeoutOptions.map(opt => opt.text)
|
options: timeoutOptions.map(opt => opt.text)
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
@@ -216,7 +214,6 @@ Rectangle {
|
|||||||
id: criticalTimeoutDropdown
|
id: criticalTimeoutDropdown
|
||||||
transientSurfaceTracker: root.transientSurfaceTracker
|
transientSurfaceTracker: root.transientSurfaceTracker
|
||||||
text: I18n.tr("Critical Priority")
|
text: I18n.tr("Critical Priority")
|
||||||
description: I18n.tr("Timeout for critical priority notifications")
|
|
||||||
currentValue: getTimeoutText(SettingsData.notificationTimeoutCritical)
|
currentValue: getTimeoutText(SettingsData.notificationTimeoutCritical)
|
||||||
options: timeoutOptions.map(opt => opt.text)
|
options: timeoutOptions.map(opt => opt.text)
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
|
|||||||
@@ -48,8 +48,9 @@ done
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "battery_charging_full"
|
iconName: "battery_charging_full"
|
||||||
title: I18n.tr("Battery Status")
|
title: I18n.tr("Status")
|
||||||
settingKey: "batteryStatusCard"
|
settingKey: "batteryStatusCard"
|
||||||
|
tags: ["battery", "status", "charge", "health"]
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
width: parent.width - Theme.spacingM * 2
|
width: parent.width - Theme.spacingM * 2
|
||||||
@@ -167,8 +168,9 @@ done
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "tune"
|
iconName: "tune"
|
||||||
title: I18n.tr("Battery Protection")
|
title: I18n.tr("Protection")
|
||||||
settingKey: "batteryProtection"
|
settingKey: "batteryProtection"
|
||||||
|
tags: ["battery", "protection", "charge", "limit"]
|
||||||
|
|
||||||
SettingsSliderRow {
|
SettingsSliderRow {
|
||||||
settingKey: "batteryChargeLimit"
|
settingKey: "batteryChargeLimit"
|
||||||
@@ -230,8 +232,9 @@ done
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "notifications"
|
iconName: "notifications"
|
||||||
title: I18n.tr("Battery Alerts")
|
title: I18n.tr("Alerts")
|
||||||
settingKey: "batteryAlerts"
|
settingKey: "batteryAlerts"
|
||||||
|
tags: ["battery", "alerts", "low", "warning"]
|
||||||
|
|
||||||
SettingsSliderRow {
|
SettingsSliderRow {
|
||||||
settingKey: "batteryLowThreshold"
|
settingKey: "batteryLowThreshold"
|
||||||
@@ -332,7 +335,6 @@ done
|
|||||||
SettingsDropdownRow {
|
SettingsDropdownRow {
|
||||||
settingKey: "acProfileName"
|
settingKey: "acProfileName"
|
||||||
text: I18n.tr("Profile when Plugged In (AC)")
|
text: I18n.tr("Profile when Plugged In (AC)")
|
||||||
description: I18n.tr("Power profile to use when AC power is connected.")
|
|
||||||
options: [I18n.tr("Don't Change"), Theme.getPowerProfileLabel(0), Theme.getPowerProfileLabel(1), Theme.getPowerProfileLabel(2)]
|
options: [I18n.tr("Don't Change"), Theme.getPowerProfileLabel(0), Theme.getPowerProfileLabel(1), Theme.getPowerProfileLabel(2)]
|
||||||
currentValue: {
|
currentValue: {
|
||||||
const val = SettingsData.acProfileName;
|
const val = SettingsData.acProfileName;
|
||||||
@@ -350,7 +352,6 @@ done
|
|||||||
SettingsDropdownRow {
|
SettingsDropdownRow {
|
||||||
settingKey: "batteryProfileName"
|
settingKey: "batteryProfileName"
|
||||||
text: I18n.tr("Profile when on Battery")
|
text: I18n.tr("Profile when on Battery")
|
||||||
description: I18n.tr("Power profile to use when running on battery power.")
|
|
||||||
options: [I18n.tr("Don't Change"), Theme.getPowerProfileLabel(0), Theme.getPowerProfileLabel(1), Theme.getPowerProfileLabel(2)]
|
options: [I18n.tr("Don't Change"), Theme.getPowerProfileLabel(0), Theme.getPowerProfileLabel(1), Theme.getPowerProfileLabel(2)]
|
||||||
currentValue: {
|
currentValue: {
|
||||||
const val = SettingsData.batteryProfileName;
|
const val = SettingsData.batteryProfileName;
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ Item {
|
|||||||
]
|
]
|
||||||
|
|
||||||
readonly property var entryActionKeys: ["copy", "paste", "pin", "edit", "delete"]
|
readonly property var entryActionKeys: ["copy", "paste", "pin", "edit", "delete"]
|
||||||
readonly property var entryActionLabels: [I18n.tr("Copy"), I18n.tr("Paste"), I18n.tr("Pin"), I18n.tr("Edit"), I18n.tr("Delete")]
|
readonly property var entryActionLabels: [I18n.tr("Copy"), I18n.tr("Paste"), I18n.tr("Pin", "pin item action"), I18n.tr("Edit"), I18n.tr("Delete")]
|
||||||
|
|
||||||
function getMaxHistoryText(value) {
|
function getMaxHistoryText(value) {
|
||||||
if (value <= 0)
|
if (value <= 0)
|
||||||
@@ -341,7 +341,6 @@ Item {
|
|||||||
tags: ["clipboard", "entry", "size", "limit"]
|
tags: ["clipboard", "entry", "size", "limit"]
|
||||||
settingKey: "maxEntrySize"
|
settingKey: "maxEntrySize"
|
||||||
text: I18n.tr("Maximum Entry Size")
|
text: I18n.tr("Maximum Entry Size")
|
||||||
description: I18n.tr("Maximum size per clipboard entry")
|
|
||||||
options: root.maxEntrySizeOptions.map(opt => opt.text)
|
options: root.maxEntrySizeOptions.map(opt => opt.text)
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ Item {
|
|||||||
|
|
||||||
function fixLayoutInclude() {
|
function fixLayoutInclude() {
|
||||||
if (readOnly) {
|
if (readOnly) {
|
||||||
ToastService.showWarning(I18n.tr("Hyprland conf mode"), I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing layout settings."), "dms setup", "hyprland-migration");
|
ToastService.showWarning(I18n.tr("Hyprland conf mode"), I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before changing these settings."), "dms setup", "hyprland-migration");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const paths = getLayoutConfigPaths();
|
const paths = getLayoutConfigPaths();
|
||||||
@@ -208,7 +208,7 @@ awk '$1 == "xray" { print FILENAME ":" FNR; exit }' $files 2>/dev/null`;
|
|||||||
StyledText {
|
StyledText {
|
||||||
text: {
|
text: {
|
||||||
if (warningBox.showLegacy)
|
if (warningBox.showLegacy)
|
||||||
return I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing layout settings.");
|
return I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before changing these settings.");
|
||||||
if (warningBox.showSetup)
|
if (warningBox.showSetup)
|
||||||
return I18n.tr("Click 'Setup' to create %1 and add include to your compositor config.").arg("dms/layout");
|
return I18n.tr("Click 'Setup' to create %1 and add include to your compositor config.").arg("dms/layout");
|
||||||
return "";
|
return "";
|
||||||
@@ -270,7 +270,7 @@ awk '$1 == "xray" { print FILENAME ":" FNR; exit }' $files 2>/dev/null`;
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
tags: ["niri", "layout", "gaps", "radius", "window", "border"]
|
tags: ["niri", "layout", "gaps", "radius", "window", "border"]
|
||||||
title: I18n.tr("Niri Layout Overrides")
|
title: I18n.tr("%1 Layout Overrides").arg("niri")
|
||||||
settingKey: "niriLayout"
|
settingKey: "niriLayout"
|
||||||
iconName: "layers"
|
iconName: "layers"
|
||||||
visible: CompositorService.isNiri
|
visible: CompositorService.isNiri
|
||||||
@@ -279,7 +279,7 @@ awk '$1 == "xray" { print FILENAME ":" FNR; exit }' $files 2>/dev/null`;
|
|||||||
tags: ["niri", "gaps", "override", "unmanaged"]
|
tags: ["niri", "gaps", "override", "unmanaged"]
|
||||||
settingKey: "niriLayoutGapsMode"
|
settingKey: "niriLayoutGapsMode"
|
||||||
text: I18n.tr("Gaps")
|
text: I18n.tr("Gaps")
|
||||||
description: I18n.tr("Auto matches bar spacing; Off leaves gaps to your niri config")
|
description: I18n.tr("Auto matches bar spacing; Off leaves gaps to your %1 config").arg("niri")
|
||||||
model: [I18n.tr("Auto"), I18n.tr("Custom"), I18n.tr("Off")]
|
model: [I18n.tr("Auto"), I18n.tr("Custom"), I18n.tr("Off")]
|
||||||
currentIndex: {
|
currentIndex: {
|
||||||
if (SettingsData.niriLayoutGapsOverride === -2)
|
if (SettingsData.niriLayoutGapsOverride === -2)
|
||||||
@@ -399,7 +399,7 @@ awk '$1 == "xray" { print FILENAME ":" FNR; exit }' $files 2>/dev/null`;
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
tags: ["hyprland", "layout", "gaps", "radius", "window", "border", "rounding"]
|
tags: ["hyprland", "layout", "gaps", "radius", "window", "border", "rounding"]
|
||||||
title: I18n.tr("Hyprland Layout Overrides")
|
title: I18n.tr("%1 Layout Overrides").arg("Hyprland")
|
||||||
settingKey: "hyprlandLayout"
|
settingKey: "hyprlandLayout"
|
||||||
iconName: "crop_square"
|
iconName: "crop_square"
|
||||||
visible: CompositorService.isHyprland
|
visible: CompositorService.isHyprland
|
||||||
@@ -408,7 +408,7 @@ awk '$1 == "xray" { print FILENAME ":" FNR; exit }' $files 2>/dev/null`;
|
|||||||
tags: ["hyprland", "gaps", "override", "inner", "outer", "unmanaged"]
|
tags: ["hyprland", "gaps", "override", "inner", "outer", "unmanaged"]
|
||||||
settingKey: "hyprlandLayoutGapsMode"
|
settingKey: "hyprlandLayoutGapsMode"
|
||||||
text: I18n.tr("Gaps")
|
text: I18n.tr("Gaps")
|
||||||
description: I18n.tr("Auto matches bar spacing; Off leaves gaps to your Hyprland config")
|
description: I18n.tr("Auto matches bar spacing; Off leaves gaps to your %1 config").arg("Hyprland")
|
||||||
model: [I18n.tr("Auto"), I18n.tr("Custom"), I18n.tr("Off")]
|
model: [I18n.tr("Auto"), I18n.tr("Custom"), I18n.tr("Off")]
|
||||||
currentIndex: {
|
currentIndex: {
|
||||||
if (SettingsData.hyprlandLayoutGapsOverride === -2)
|
if (SettingsData.hyprlandLayoutGapsOverride === -2)
|
||||||
@@ -492,7 +492,6 @@ awk '$1 == "xray" { print FILENAME ":" FNR; exit }' $files 2>/dev/null`;
|
|||||||
tags: ["hyprland", "border", "override"]
|
tags: ["hyprland", "border", "override"]
|
||||||
settingKey: "hyprlandLayoutBorderSizeEnabled"
|
settingKey: "hyprlandLayoutBorderSizeEnabled"
|
||||||
text: I18n.tr("Override Border Size")
|
text: I18n.tr("Override Border Size")
|
||||||
description: I18n.tr("Use custom border size")
|
|
||||||
checked: SettingsData.hyprlandLayoutBorderSize >= 0
|
checked: SettingsData.hyprlandLayoutBorderSize >= 0
|
||||||
onToggled: checked => {
|
onToggled: checked => {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
@@ -551,7 +550,7 @@ awk '$1 == "xray" { print FILENAME ":" FNR; exit }' $files 2>/dev/null`;
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
tags: ["mangowc", "mango", "dwl", "layout", "gaps", "radius", "window", "border"]
|
tags: ["mangowc", "mango", "dwl", "layout", "gaps", "radius", "window", "border"]
|
||||||
title: I18n.tr("MangoWC Layout Overrides")
|
title: I18n.tr("%1 Layout Overrides").arg("MangoWC")
|
||||||
settingKey: "mangoLayout"
|
settingKey: "mangoLayout"
|
||||||
iconName: "crop_square"
|
iconName: "crop_square"
|
||||||
visible: CompositorService.isMango
|
visible: CompositorService.isMango
|
||||||
@@ -560,7 +559,7 @@ awk '$1 == "xray" { print FILENAME ":" FNR; exit }' $files 2>/dev/null`;
|
|||||||
tags: ["mangowc", "mango", "gaps", "override", "inner", "outer", "unmanaged"]
|
tags: ["mangowc", "mango", "gaps", "override", "inner", "outer", "unmanaged"]
|
||||||
settingKey: "mangoLayoutGapsMode"
|
settingKey: "mangoLayoutGapsMode"
|
||||||
text: I18n.tr("Gaps")
|
text: I18n.tr("Gaps")
|
||||||
description: I18n.tr("Auto matches bar spacing; Off leaves gaps to your MangoWC config")
|
description: I18n.tr("Auto matches bar spacing; Off leaves gaps to your %1 config").arg("MangoWC")
|
||||||
model: [I18n.tr("Auto"), I18n.tr("Custom"), I18n.tr("Off")]
|
model: [I18n.tr("Auto"), I18n.tr("Custom"), I18n.tr("Off")]
|
||||||
currentIndex: {
|
currentIndex: {
|
||||||
if (SettingsData.mangoLayoutGapsOverride === -2)
|
if (SettingsData.mangoLayoutGapsOverride === -2)
|
||||||
@@ -644,7 +643,6 @@ awk '$1 == "xray" { print FILENAME ":" FNR; exit }' $files 2>/dev/null`;
|
|||||||
tags: ["mangowc", "mango", "border", "override"]
|
tags: ["mangowc", "mango", "border", "override"]
|
||||||
settingKey: "mangoLayoutBorderSizeEnabled"
|
settingKey: "mangoLayoutBorderSizeEnabled"
|
||||||
text: I18n.tr("Override Border Size")
|
text: I18n.tr("Override Border Size")
|
||||||
description: I18n.tr("Use custom border size")
|
|
||||||
checked: SettingsData.mangoLayoutBorderSize >= 0
|
checked: SettingsData.mangoLayoutBorderSize >= 0
|
||||||
onToggled: checked => {
|
onToggled: checked => {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ Item {
|
|||||||
|
|
||||||
SettingsCard {
|
SettingsCard {
|
||||||
iconName: "dashboard"
|
iconName: "dashboard"
|
||||||
title: I18n.tr("Bar Configurations")
|
title: I18n.tr("Configurations")
|
||||||
settingKey: "barConfigurations"
|
settingKey: "barConfigurations"
|
||||||
visible: !dankBarTab.appearanceOnly
|
visible: !dankBarTab.appearanceOnly
|
||||||
|
|
||||||
@@ -490,7 +490,7 @@ Item {
|
|||||||
DankButtonGroup {
|
DankButtonGroup {
|
||||||
id: positionButtonGroup
|
id: positionButtonGroup
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
model: [I18n.tr("Top"), I18n.tr("Bottom"), I18n.tr("Left"), I18n.tr("Right")]
|
model: [I18n.tr("Top", "screen edge position"), I18n.tr("Bottom", "screen edge position"), I18n.tr("Left", "screen edge position"), I18n.tr("Right", "screen edge position")]
|
||||||
currentIndex: {
|
currentIndex: {
|
||||||
selectedBarId;
|
selectedBarId;
|
||||||
const config = SettingsData.getBarConfig(selectedBarId);
|
const config = SettingsData.getBarConfig(selectedBarId);
|
||||||
@@ -820,7 +820,6 @@ Item {
|
|||||||
id: barTransparencySlider
|
id: barTransparencySlider
|
||||||
visible: !SettingsData.frameEnabled
|
visible: !SettingsData.frameEnabled
|
||||||
text: I18n.tr("Bar Opacity")
|
text: I18n.tr("Bar Opacity")
|
||||||
description: I18n.tr("Controls opacity of the bar background")
|
|
||||||
value: (selectedBarConfig?.transparency ?? 1.0) * 100
|
value: (selectedBarConfig?.transparency ?? 1.0) * 100
|
||||||
minimum: 0
|
minimum: 0
|
||||||
maximum: 100
|
maximum: 100
|
||||||
@@ -843,7 +842,6 @@ Item {
|
|||||||
SettingsSliderRow {
|
SettingsSliderRow {
|
||||||
id: widgetTransparencySlider
|
id: widgetTransparencySlider
|
||||||
text: I18n.tr("Widget Opacity")
|
text: I18n.tr("Widget Opacity")
|
||||||
description: I18n.tr("Controls opacity of widget backgrounds")
|
|
||||||
value: (selectedBarConfig?.widgetTransparency ?? 1.0) * 100
|
value: (selectedBarConfig?.widgetTransparency ?? 1.0) * 100
|
||||||
minimum: 0
|
minimum: 0
|
||||||
maximum: 100
|
maximum: 100
|
||||||
@@ -1463,7 +1461,6 @@ Item {
|
|||||||
SettingsSliderRow {
|
SettingsSliderRow {
|
||||||
id: borderOpacitySlider
|
id: borderOpacitySlider
|
||||||
text: I18n.tr("Opacity")
|
text: I18n.tr("Opacity")
|
||||||
description: I18n.tr("Controls opacity of the border")
|
|
||||||
value: (selectedBarConfig?.borderOpacity ?? 1.0) * 100
|
value: (selectedBarConfig?.borderOpacity ?? 1.0) * 100
|
||||||
minimum: 0
|
minimum: 0
|
||||||
maximum: 100
|
maximum: 100
|
||||||
@@ -1558,7 +1555,6 @@ Item {
|
|||||||
SettingsSliderRow {
|
SettingsSliderRow {
|
||||||
id: widgetOutlineOpacitySlider
|
id: widgetOutlineOpacitySlider
|
||||||
text: I18n.tr("Opacity")
|
text: I18n.tr("Opacity")
|
||||||
description: I18n.tr("Controls opacity of the widget outline")
|
|
||||||
value: (selectedBarConfig?.widgetOutlineOpacity ?? 1.0) * 100
|
value: (selectedBarConfig?.widgetOutlineOpacity ?? 1.0) * 100
|
||||||
minimum: 0
|
minimum: 0
|
||||||
maximum: 100
|
maximum: 100
|
||||||
@@ -1667,7 +1663,6 @@ Item {
|
|||||||
SettingsSliderRow {
|
SettingsSliderRow {
|
||||||
visible: shadowCard.shadowActive
|
visible: shadowCard.shadowActive
|
||||||
text: I18n.tr("Opacity")
|
text: I18n.tr("Opacity")
|
||||||
description: I18n.tr("Controls opacity of the shadow layer")
|
|
||||||
minimum: 10
|
minimum: 10
|
||||||
maximum: 100
|
maximum: 100
|
||||||
unit: "%"
|
unit: "%"
|
||||||
|
|||||||
@@ -312,7 +312,6 @@ Item {
|
|||||||
text: I18n.tr("Calendar", "Calendar")
|
text: I18n.tr("Calendar", "Calendar")
|
||||||
category: root.appCategory.Calendar
|
category: root.appCategory.Calendar
|
||||||
tags: ["calendar", "events"]
|
tags: ["calendar", "events"]
|
||||||
description: I18n.tr("Manages calendar events", "Manages calendar events")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,7 +329,6 @@ Item {
|
|||||||
text: I18n.tr("PDF Reader", "PDF Reader")
|
text: I18n.tr("PDF Reader", "PDF Reader")
|
||||||
category: root.appCategory.PDFReader
|
category: root.appCategory.PDFReader
|
||||||
tags: ["pdf", "reader"]
|
tags: ["pdf", "reader"]
|
||||||
description: I18n.tr("For reading PDF files", "For reading PDF files")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,13 +339,11 @@ Item {
|
|||||||
text: I18n.tr("Image Viewer", "Image Viewer")
|
text: I18n.tr("Image Viewer", "Image Viewer")
|
||||||
category: root.appCategory.ImageViewer
|
category: root.appCategory.ImageViewer
|
||||||
tags: ["image", "viewer"]
|
tags: ["image", "viewer"]
|
||||||
description: I18n.tr("Opens image files", "Opens image files")
|
|
||||||
}
|
}
|
||||||
AppSelector {
|
AppSelector {
|
||||||
text: I18n.tr("Video Player", "Video Player")
|
text: I18n.tr("Video Player", "Video Player")
|
||||||
category: root.appCategory.VideoPlayer
|
category: root.appCategory.VideoPlayer
|
||||||
tags: ["video", "player"]
|
tags: ["video", "player"]
|
||||||
description: I18n.tr("Plays video files", "Plays video files")
|
|
||||||
}
|
}
|
||||||
AppSelector {
|
AppSelector {
|
||||||
text: I18n.tr("Music Player", "Music Player")
|
text: I18n.tr("Music Player", "Music Player")
|
||||||
|
|||||||
@@ -1518,7 +1518,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showHyprlandReadOnlyWarning() {
|
function showHyprlandReadOnlyWarning() {
|
||||||
ToastService.showWarning(I18n.tr("Hyprland conf mode"), I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing display settings."), "dms setup", "display-config");
|
ToastService.showWarning(I18n.tr("Hyprland conf mode"), I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before changing these settings."), "dms setup", "display-config");
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildOutputsMap() {
|
function buildOutputsMap() {
|
||||||
@@ -2639,7 +2639,7 @@ Singleton {
|
|||||||
function getTransformLabel(transform) {
|
function getTransformLabel(transform) {
|
||||||
switch (transform) {
|
switch (transform) {
|
||||||
case "Normal":
|
case "Normal":
|
||||||
return I18n.tr("Normal");
|
return I18n.tr("Normal", "display rotation option", true);
|
||||||
case "90":
|
case "90":
|
||||||
return I18n.tr("90°");
|
return I18n.tr("90°");
|
||||||
case "180":
|
case "180":
|
||||||
@@ -2655,12 +2655,12 @@ Singleton {
|
|||||||
case "Flipped270":
|
case "Flipped270":
|
||||||
return I18n.tr("Flipped 270°");
|
return I18n.tr("Flipped 270°");
|
||||||
default:
|
default:
|
||||||
return I18n.tr("Normal");
|
return I18n.tr("Normal", "display rotation option", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTransformValue(label) {
|
function getTransformValue(label) {
|
||||||
if (label === I18n.tr("Normal"))
|
if (label === I18n.tr("Normal", "display rotation option", true))
|
||||||
return "Normal";
|
return "Normal";
|
||||||
if (label === I18n.tr("90°"))
|
if (label === I18n.tr("90°"))
|
||||||
return "90";
|
return "90";
|
||||||
|
|||||||
@@ -60,9 +60,9 @@ StyledRect {
|
|||||||
StyledText {
|
StyledText {
|
||||||
text: {
|
text: {
|
||||||
if (root.showLegacy)
|
if (root.showLegacy)
|
||||||
return I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing display settings.");
|
return I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before changing these settings.");
|
||||||
if (root.showSetup)
|
if (root.showSetup)
|
||||||
return I18n.tr("Click 'Setup' to create the outputs config and add include to your compositor config.");
|
return I18n.tr("Click 'Setup' to create %1 and add include to your compositor config.").arg("dms/outputs");
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
|||||||
@@ -93,21 +93,21 @@ Column {
|
|||||||
|
|
||||||
currentValue: {
|
currentValue: {
|
||||||
if (!hotCornersData)
|
if (!hotCornersData)
|
||||||
return I18n.tr("Inherit");
|
return I18n.tr("Inherit", "inherit from global setting");
|
||||||
if (hotCornersData.off)
|
if (hotCornersData.off)
|
||||||
return I18n.tr("Off");
|
return I18n.tr("Off");
|
||||||
const corners = hotCornersData.corners || [];
|
const corners = hotCornersData.corners || [];
|
||||||
if (corners.length === 0)
|
if (corners.length === 0)
|
||||||
return I18n.tr("Inherit");
|
return I18n.tr("Inherit", "inherit from global setting");
|
||||||
if (corners.length === 4)
|
if (corners.length === 4)
|
||||||
return I18n.tr("All");
|
return I18n.tr("All");
|
||||||
return I18n.tr("Select...");
|
return I18n.tr("Select...");
|
||||||
}
|
}
|
||||||
options: [I18n.tr("Inherit"), I18n.tr("Off"), I18n.tr("All"), I18n.tr("Select...")]
|
options: [I18n.tr("Inherit", "inherit from global setting"), I18n.tr("Off"), I18n.tr("All"), I18n.tr("Select...")]
|
||||||
|
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case I18n.tr("Inherit"):
|
case I18n.tr("Inherit", "inherit from global setting"):
|
||||||
DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", null);
|
DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", null);
|
||||||
break;
|
break;
|
||||||
case I18n.tr("Off"):
|
case I18n.tr("Off"):
|
||||||
@@ -232,7 +232,7 @@ Column {
|
|||||||
DankTextField {
|
DankTextField {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 40
|
height: 40
|
||||||
placeholderText: I18n.tr("Inherit")
|
placeholderText: I18n.tr("Inherit", "inherit from global setting")
|
||||||
enabled: !settingsColumn.isDisabled
|
enabled: !settingsColumn.isDisabled
|
||||||
text: {
|
text: {
|
||||||
const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null);
|
const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null);
|
||||||
@@ -270,7 +270,7 @@ Column {
|
|||||||
DankTextField {
|
DankTextField {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 40
|
height: 40
|
||||||
placeholderText: I18n.tr("Inherit")
|
placeholderText: I18n.tr("Inherit", "inherit from global setting")
|
||||||
enabled: !settingsColumn.isDisabled
|
enabled: !settingsColumn.isDisabled
|
||||||
text: {
|
text: {
|
||||||
const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null);
|
const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null);
|
||||||
@@ -321,7 +321,7 @@ Column {
|
|||||||
DankTextField {
|
DankTextField {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 40
|
height: 40
|
||||||
placeholderText: I18n.tr("Inherit")
|
placeholderText: I18n.tr("Inherit", "inherit from global setting")
|
||||||
enabled: !settingsColumn.isDisabled
|
enabled: !settingsColumn.isDisabled
|
||||||
text: {
|
text: {
|
||||||
const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null);
|
const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null);
|
||||||
|
|||||||
@@ -308,7 +308,7 @@ StyledRect {
|
|||||||
return DisplayConfigState.getTransformLabel(pendingTransform);
|
return DisplayConfigState.getTransformLabel(pendingTransform);
|
||||||
return DisplayConfigState.getTransformLabel(root.outputData?.logical?.transform ?? "Normal");
|
return DisplayConfigState.getTransformLabel(root.outputData?.logical?.transform ?? "Normal");
|
||||||
}
|
}
|
||||||
options: [I18n.tr("Normal"), I18n.tr("90°"), I18n.tr("180°"), I18n.tr("270°"), I18n.tr("Flipped"), I18n.tr("Flipped 90°"), I18n.tr("Flipped 180°"), I18n.tr("Flipped 270°")]
|
options: [I18n.tr("Normal", "display rotation option", true), I18n.tr("90°"), I18n.tr("180°"), I18n.tr("270°"), I18n.tr("Flipped"), I18n.tr("Flipped 90°"), I18n.tr("Flipped 180°"), I18n.tr("Flipped 270°")]
|
||||||
onValueChanged: value => DisplayConfigState.setPendingChange(root.outputName, "transform", DisplayConfigState.getTransformValue(value))
|
onValueChanged: value => DisplayConfigState.setPendingChange(root.outputName, "transform", DisplayConfigState.getTransformValue(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -399,7 +399,6 @@ Item {
|
|||||||
DankToggle {
|
DankToggle {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: I18n.tr("All displays")
|
text: I18n.tr("All displays")
|
||||||
description: I18n.tr("Show on all connected displays")
|
|
||||||
checked: {
|
checked: {
|
||||||
var prefs = root.getScreenPreferences(parent.componentId);
|
var prefs = root.getScreenPreferences(parent.componentId);
|
||||||
return prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all");
|
return prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all");
|
||||||
@@ -420,7 +419,6 @@ Item {
|
|||||||
DankToggle {
|
DankToggle {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: I18n.tr("Focused Monitor Only")
|
text: I18n.tr("Focused Monitor Only")
|
||||||
description: I18n.tr("Show notifications only on the currently focused monitor")
|
|
||||||
visible: parent.componentId === "notifications"
|
visible: parent.componentId === "notifications"
|
||||||
checked: SettingsData.notificationFocusedMonitor
|
checked: SettingsData.notificationFocusedMonitor
|
||||||
onToggled: checked => SettingsData.set("notificationFocusedMonitor", checked)
|
onToggled: checked => SettingsData.set("notificationFocusedMonitor", checked)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "dock_to_bottom"
|
iconName: "dock_to_bottom"
|
||||||
title: I18n.tr("Dock Visibility")
|
title: I18n.tr("Visibility")
|
||||||
settingKey: "dockVisibility"
|
settingKey: "dockVisibility"
|
||||||
|
|
||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
@@ -228,7 +228,6 @@ Item {
|
|||||||
settingKey: "dockShowOverflowBadge"
|
settingKey: "dockShowOverflowBadge"
|
||||||
tags: ["dock", "overflow", "badge", "count", "indicator"]
|
tags: ["dock", "overflow", "badge", "count", "indicator"]
|
||||||
text: I18n.tr("Show Overflow Badge Count")
|
text: I18n.tr("Show Overflow Badge Count")
|
||||||
description: I18n.tr("Displays count when overflow is active")
|
|
||||||
checked: SettingsData.dockShowOverflowBadge
|
checked: SettingsData.dockShowOverflowBadge
|
||||||
onToggled: checked => SettingsData.set("dockShowOverflowBadge", checked)
|
onToggled: checked => SettingsData.set("dockShowOverflowBadge", checked)
|
||||||
}
|
}
|
||||||
@@ -461,7 +460,7 @@ Item {
|
|||||||
if (!PopoutService.colorPickerModal)
|
if (!PopoutService.colorPickerModal)
|
||||||
return;
|
return;
|
||||||
PopoutService.colorPickerModal.selectedColor = SettingsData.dockLauncherLogoColorOverride;
|
PopoutService.colorPickerModal.selectedColor = SettingsData.dockLauncherLogoColorOverride;
|
||||||
PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Dock Launcher Logo Color");
|
PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Launcher Logo Color");
|
||||||
PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) {
|
PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) {
|
||||||
SettingsData.set("dockLauncherLogoColorOverride", selectedColor);
|
SettingsData.set("dockLauncherLogoColorOverride", selectedColor);
|
||||||
};
|
};
|
||||||
@@ -683,7 +682,6 @@ Item {
|
|||||||
|
|
||||||
SettingsButtonGroupRow {
|
SettingsButtonGroupRow {
|
||||||
text: I18n.tr("Border Color")
|
text: I18n.tr("Border Color")
|
||||||
description: I18n.tr("Choose the border accent color")
|
|
||||||
visible: SettingsData.dockBorderEnabled
|
visible: SettingsData.dockBorderEnabled
|
||||||
model: [I18n.tr("Surface", "color option"), I18n.tr("Secondary", "color option"), I18n.tr("Primary", "color option")]
|
model: [I18n.tr("Surface", "color option"), I18n.tr("Secondary", "color option"), I18n.tr("Primary", "color option")]
|
||||||
buttonPadding: Theme.spacingS
|
buttonPadding: Theme.spacingS
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "frame_source"
|
iconName: "frame_source"
|
||||||
title: I18n.tr("Frame")
|
title: I18n.tr("General")
|
||||||
settingKey: "frameEnabled"
|
settingKey: "frameEnabled"
|
||||||
|
|
||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
|
|||||||
@@ -122,7 +122,6 @@ Item {
|
|||||||
tags: ["gamma", "day", "temperature", "kelvin", "color"]
|
tags: ["gamma", "day", "temperature", "kelvin", "color"]
|
||||||
width: parent.width - parent.leftPadding - parent.rightPadding
|
width: parent.width - parent.leftPadding - parent.rightPadding
|
||||||
text: I18n.tr("Day Temperature")
|
text: I18n.tr("Day Temperature")
|
||||||
description: I18n.tr("Color temperature for day time")
|
|
||||||
minimum: SessionData.nightModeTemperature
|
minimum: SessionData.nightModeTemperature
|
||||||
maximum: 10000
|
maximum: 10000
|
||||||
step: 100
|
step: 100
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ Item {
|
|||||||
onExited: exitCode => {
|
onExited: exitCode => {
|
||||||
root.greeterSyncRunning = false;
|
root.greeterSyncRunning = false;
|
||||||
if (exitCode === 0) {
|
if (exitCode === 0) {
|
||||||
var launched = root.greeterTerminalFallbackFromPrecheck ? I18n.tr("Terminal opened. Complete sync authentication there; it will close automatically when done.") : I18n.tr("Terminal fallback opened. Complete sync there; it will close automatically when done.");
|
var launched = root.greeterTerminalFallbackFromPrecheck ? I18n.tr("Terminal opened. Complete authentication there; it will close automatically when done.") : I18n.tr("Terminal fallback opened. Complete authentication there; it will close automatically when done.");
|
||||||
root.greeterStatusText = root.greeterStatusText ? root.greeterStatusText + "\n\n" + launched : launched;
|
root.greeterStatusText = root.greeterStatusText ? root.greeterStatusText + "\n\n" + launched : launched;
|
||||||
SettingsData.clearGreeterSyncPending();
|
SettingsData.clearGreeterSyncPending();
|
||||||
return;
|
return;
|
||||||
@@ -396,7 +396,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "info"
|
iconName: "info"
|
||||||
title: I18n.tr("Greeter Status")
|
title: I18n.tr("Status")
|
||||||
settingKey: "greeterStatus"
|
settingKey: "greeterStatus"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -470,7 +470,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "fingerprint"
|
iconName: "fingerprint"
|
||||||
title: I18n.tr("Login Authentication")
|
title: I18n.tr("Authentication")
|
||||||
settingKey: "greeterAuth"
|
settingKey: "greeterAuth"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -517,7 +517,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "palette"
|
iconName: "palette"
|
||||||
title: I18n.tr("Greeter Appearance")
|
title: I18n.tr("Appearance")
|
||||||
settingKey: "greeterAppearance"
|
settingKey: "greeterAppearance"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -558,7 +558,7 @@ Item {
|
|||||||
currentValue: {
|
currentValue: {
|
||||||
var current = (SettingsData.greeterLockDateFormat !== undefined && SettingsData.greeterLockDateFormat !== "") ? SettingsData.greeterLockDateFormat : SettingsData.lockDateFormat || "";
|
var current = (SettingsData.greeterLockDateFormat !== undefined && SettingsData.greeterLockDateFormat !== "") ? SettingsData.greeterLockDateFormat : SettingsData.lockDateFormat || "";
|
||||||
var match = root._lockDateFormatPresets.find(p => p.format === current);
|
var match = root._lockDateFormatPresets.find(p => p.format === current);
|
||||||
return match ? match.label : (current ? I18n.tr("Custom: ") + current : root._lockDateFormatPresets[0].label);
|
return match ? match.label : (current ? I18n.tr("Custom") + ": " + current : root._lockDateFormatPresets[0].label);
|
||||||
}
|
}
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
var preset = root._lockDateFormatPresets.find(p => p.label === value);
|
var preset = root._lockDateFormatPresets.find(p => p.label === value);
|
||||||
@@ -601,7 +601,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "history"
|
iconName: "history"
|
||||||
title: I18n.tr("Greeter Behavior")
|
title: I18n.tr("Behavior")
|
||||||
settingKey: "greeterBehavior"
|
settingKey: "greeterBehavior"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ Item {
|
|||||||
|
|
||||||
function confirmResetBind(key, remainingKey) {
|
function confirmResetBind(key, remainingKey) {
|
||||||
removeBindConfirm.showWithOptions({
|
removeBindConfirm.showWithOptions({
|
||||||
title: I18n.tr("Reset to Default?"),
|
title: I18n.tr("Reset to default"),
|
||||||
message: I18n.tr("Drop your override for %1 so the DMS default action re-applies?").arg(key),
|
message: I18n.tr("Drop your override for %1 so the DMS default action re-applies?").arg(key),
|
||||||
confirmText: I18n.tr("Reset"),
|
confirmText: I18n.tr("Reset"),
|
||||||
confirmColor: Theme.primary,
|
confirmColor: Theme.primary,
|
||||||
@@ -397,7 +397,7 @@ Item {
|
|||||||
StyledText {
|
StyledText {
|
||||||
text: {
|
text: {
|
||||||
if (warningBox.showLegacy)
|
if (warningBox.showLegacy)
|
||||||
return I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing shortcuts in Settings.");
|
return I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before changing these settings.");
|
||||||
if (warningBox.showSetup)
|
if (warningBox.showSetup)
|
||||||
return I18n.tr("Click 'Setup' to create %1 and add include to your compositor config.").arg("dms/binds");
|
return I18n.tr("Click 'Setup' to create %1 and add include to your compositor config.").arg("dms/binds");
|
||||||
if (warningBox.showWarning) {
|
if (warningBox.showWarning) {
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: !root.keybindsAvailable ? I18n.tr("Bind the spotlight IPC action in your compositor config.") : SettingsData.connectedFrameModeActive ? I18n.tr("Opens the connected launcher in Connected Frame Mode.") : I18n.tr("Follows the default launcher choice selected above.")
|
text: !root.keybindsAvailable ? I18n.tr("Bind the %1 IPC action in your compositor config.").arg("spotlight") : SettingsData.connectedFrameModeActive ? I18n.tr("Opens the connected launcher in Connected Frame Mode.") : I18n.tr("Follows the default launcher choice selected above.")
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -173,7 +173,6 @@ Item {
|
|||||||
settingKey: "launcherUseOverlayLayer"
|
settingKey: "launcherUseOverlayLayer"
|
||||||
tags: ["launcher", "fullscreen", "overlay", "layer"]
|
tags: ["launcher", "fullscreen", "overlay", "layer"]
|
||||||
text: I18n.tr("Use Overlay Layer", "launcher layer toggle: use Wayland overlay layer")
|
text: I18n.tr("Use Overlay Layer", "launcher layer toggle: use Wayland overlay layer")
|
||||||
description: I18n.tr("Use the overlay layer when opening the launcher")
|
|
||||||
checked: SettingsData.launcherUseOverlayLayer
|
checked: SettingsData.launcherUseOverlayLayer
|
||||||
onToggled: checked => SettingsData.set("launcherUseOverlayLayer", checked)
|
onToggled: checked => SettingsData.set("launcherUseOverlayLayer", checked)
|
||||||
}
|
}
|
||||||
@@ -233,7 +232,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: !root.keybindsAvailable ? I18n.tr("Bind the spotlight-bar IPC action in your compositor config.") : I18n.tr("Uses the spotlight-bar IPC action and always opens the minimal bar.")
|
text: !root.keybindsAvailable ? I18n.tr("Bind the %1 IPC action in your compositor config.").arg("spotlight-bar") : I18n.tr("Uses the spotlight-bar IPC action and always opens the minimal bar.")
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
tab: "locale"
|
tab: "locale"
|
||||||
tags: ["locale", "language", "country"]
|
tags: ["locale", "language", "country"]
|
||||||
title: I18n.tr("Locale Settings")
|
title: I18n.tr("General")
|
||||||
iconName: "language"
|
iconName: "language"
|
||||||
|
|
||||||
SettingsDropdownRow {
|
SettingsDropdownRow {
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "lock"
|
iconName: "lock"
|
||||||
title: I18n.tr("Lock Screen layout")
|
title: I18n.tr("Layout")
|
||||||
settingKey: "lockLayout"
|
settingKey: "lockLayout"
|
||||||
|
|
||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
@@ -345,7 +345,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "palette"
|
iconName: "palette"
|
||||||
title: I18n.tr("Lock Screen Appearance")
|
title: I18n.tr("Appearance")
|
||||||
settingKey: "lockAppearance"
|
settingKey: "lockAppearance"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -476,7 +476,6 @@ Item {
|
|||||||
settingKey: "lockPamExternallyManaged"
|
settingKey: "lockPamExternallyManaged"
|
||||||
tags: ["lock", "screen", "pam", "managed", "external", "authentication", "policy"]
|
tags: ["lock", "screen", "pam", "managed", "external", "authentication", "policy"]
|
||||||
text: I18n.tr("Use system PAM authentication", "system PAM policy toggle")
|
text: I18n.tr("Use system PAM authentication", "system PAM policy toggle")
|
||||||
description: I18n.tr("System PAM sets the authentication policy.", "system PAM policy toggle")
|
|
||||||
checked: SettingsData.lockPamExternallyManaged
|
checked: SettingsData.lockPamExternallyManaged
|
||||||
onToggled: checked => SettingsData.set("lockPamExternallyManaged", checked)
|
onToggled: checked => SettingsData.set("lockPamExternallyManaged", checked)
|
||||||
}
|
}
|
||||||
@@ -582,7 +581,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "lock"
|
iconName: "lock"
|
||||||
title: I18n.tr("Lock Screen behaviour")
|
title: I18n.tr("Behavior")
|
||||||
settingKey: "lockBehavior"
|
settingKey: "lockBehavior"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -721,7 +720,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "monitor"
|
iconName: "monitor"
|
||||||
title: I18n.tr("Lock Screen Display")
|
title: I18n.tr("Display Assignment")
|
||||||
settingKey: "lockDisplay"
|
settingKey: "lockDisplay"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "music_note"
|
iconName: "music_note"
|
||||||
title: I18n.tr("Media Player Settings")
|
title: I18n.tr("General")
|
||||||
settingKey: "mediaPlayer"
|
settingKey: "mediaPlayer"
|
||||||
|
|
||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
@@ -146,7 +146,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "do_not_disturb_on"
|
iconName: "do_not_disturb_on"
|
||||||
title: I18n.tr("Excluded Media Players")
|
title: I18n.tr("Excluded Players")
|
||||||
settingKey: "mediaExcludePlayers"
|
settingKey: "mediaExcludePlayers"
|
||||||
tags: ["media", "music", "exclude", "ignore", "player", "mpris"]
|
tags: ["media", "music", "exclude", "ignore", "player", "mpris"]
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
tab: "mux"
|
tab: "mux"
|
||||||
tags: ["mux", "multiplexer", "tmux", "zellij", "type"]
|
tags: ["mux", "multiplexer", "tmux", "zellij", "type"]
|
||||||
title: I18n.tr("Multiplexer")
|
title: I18n.tr("General")
|
||||||
iconName: "terminal"
|
iconName: "terminal"
|
||||||
|
|
||||||
SettingsDropdownRow {
|
SettingsDropdownRow {
|
||||||
@@ -33,7 +33,6 @@ Item {
|
|||||||
tags: ["mux", "multiplexer", "tmux", "zellij", "type", "backend"]
|
tags: ["mux", "multiplexer", "tmux", "zellij", "type", "backend"]
|
||||||
settingKey: "muxType"
|
settingKey: "muxType"
|
||||||
text: I18n.tr("Multiplexer Type")
|
text: I18n.tr("Multiplexer Type")
|
||||||
description: I18n.tr("Terminal multiplexer backend to use")
|
|
||||||
options: root.muxTypeOptions
|
options: root.muxTypeOptions
|
||||||
currentValue: SettingsData.muxType
|
currentValue: SettingsData.muxType
|
||||||
onValueChanged: value => SettingsData.set("muxType", value)
|
onValueChanged: value => SettingsData.set("muxType", value)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
title: I18n.tr("Network Status")
|
title: I18n.tr("Status")
|
||||||
iconName: "lan"
|
iconName: "lan"
|
||||||
settingKey: "networkStatus"
|
settingKey: "networkStatus"
|
||||||
tags: ["status", "network", "connectivity", "internet"]
|
tags: ["status", "network", "connectivity", "internet"]
|
||||||
@@ -128,7 +128,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Primary")
|
text: I18n.tr("Primary", "primary network connection label", true)
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
visible: NetworkService.primaryConnection.length > 0
|
visible: NetworkService.primaryConnection.length > 0
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ Item {
|
|||||||
visible: NetworkService.wifiConnected
|
visible: NetworkService.wifiConnected
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Signal:")
|
text: I18n.tr("Signal") + ":"
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
width: 100
|
width: 100
|
||||||
@@ -563,7 +563,7 @@ Item {
|
|||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: isConnecting ? I18n.tr("Connecting...") : (isConnected ? I18n.tr("Connected") : (modelData.secured ? I18n.tr("Secured") : I18n.tr("Open")))
|
text: isConnecting ? I18n.tr("Connecting...") : (isConnected ? I18n.tr("Connected") : (modelData.secured ? I18n.tr("Secured") : I18n.tr("Open", "network security type", true)))
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: isConnecting ? Theme.warning : (isConnected ? Theme.primary : Theme.surfaceVariantText)
|
color: isConnecting ? Theme.warning : (isConnected ? Theme.primary : Theme.surfaceVariantText)
|
||||||
}
|
}
|
||||||
@@ -770,7 +770,7 @@ Item {
|
|||||||
});
|
});
|
||||||
fields.push({
|
fields.push({
|
||||||
label: I18n.tr("Security"),
|
label: I18n.tr("Security"),
|
||||||
value: net.secured ? (net.enterprise ? I18n.tr("Enterprise") : I18n.tr("WPA/WPA2")) : I18n.tr("Open")
|
value: net.secured ? (net.enterprise ? I18n.tr("Enterprise") : I18n.tr("WPA/WPA2")) : I18n.tr("Open", "network security type", true)
|
||||||
});
|
});
|
||||||
|
|
||||||
return fields;
|
return fields;
|
||||||
@@ -966,7 +966,7 @@ Item {
|
|||||||
text: {
|
text: {
|
||||||
if (isConnecting)
|
if (isConnecting)
|
||||||
return I18n.tr("Connecting...");
|
return I18n.tr("Connecting...");
|
||||||
const parts = [isConnected ? I18n.tr("Connected") : (modelData.secured ? I18n.tr("Secured") : I18n.tr("Open"))];
|
const parts = [isConnected ? I18n.tr("Connected") : (modelData.secured ? I18n.tr("Secured") : I18n.tr("Open", "network security type", true))];
|
||||||
parts.push(isOutOfRange ? I18n.tr("Unavailable") : (modelData.signal || 0) + "%");
|
parts.push(isOutOfRange ? I18n.tr("Unavailable") : (modelData.signal || 0) + "%");
|
||||||
if (modelData.hidden || false)
|
if (modelData.hidden || false)
|
||||||
parts.push(I18n.tr("Hidden"));
|
parts.push(I18n.tr("Hidden"));
|
||||||
@@ -1131,7 +1131,7 @@ Item {
|
|||||||
});
|
});
|
||||||
fields.push({
|
fields.push({
|
||||||
label: I18n.tr("Security"),
|
label: I18n.tr("Security"),
|
||||||
value: net.secured ? (net.enterprise ? I18n.tr("Enterprise") : I18n.tr("WPA/WPA2")) : I18n.tr("Open")
|
value: net.secured ? (net.enterprise ? I18n.tr("Enterprise") : I18n.tr("WPA/WPA2")) : I18n.tr("Open", "network security type", true)
|
||||||
});
|
});
|
||||||
|
|
||||||
return fields;
|
return fields;
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "notifications"
|
iconName: "notifications"
|
||||||
title: I18n.tr("Notification Popups")
|
title: I18n.tr("Popups")
|
||||||
settingKey: "notificationPopups"
|
settingKey: "notificationPopups"
|
||||||
|
|
||||||
// Font size selectors for summary and body
|
// Font size selectors for summary and body
|
||||||
@@ -211,7 +211,6 @@ Item {
|
|||||||
settingKey: "notificationSummaryFontSize"
|
settingKey: "notificationSummaryFontSize"
|
||||||
tags: ["notification", "font", "summary", "size"]
|
tags: ["notification", "font", "summary", "size"]
|
||||||
text: I18n.tr("Summary Font Size")
|
text: I18n.tr("Summary Font Size")
|
||||||
description: I18n.tr("Set the font size for notification summary text")
|
|
||||||
options: [I18n.tr("Unset"), "10", "12", "14", "16", "18"]
|
options: [I18n.tr("Unset"), "10", "12", "14", "16", "18"]
|
||||||
currentValue: (SettingsData.notificationSummaryFontSize || I18n.tr("Unset")).toString()
|
currentValue: (SettingsData.notificationSummaryFontSize || I18n.tr("Unset")).toString()
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
@@ -340,7 +339,6 @@ Item {
|
|||||||
settingKey: "notificationFocusedMonitor"
|
settingKey: "notificationFocusedMonitor"
|
||||||
tags: ["notification", "popup", "focused", "monitor", "display", "screen", "active"]
|
tags: ["notification", "popup", "focused", "monitor", "display", "screen", "active"]
|
||||||
text: I18n.tr("Focused Monitor Only")
|
text: I18n.tr("Focused Monitor Only")
|
||||||
description: I18n.tr("Show notification popups only on the currently focused monitor")
|
|
||||||
checked: SettingsData.notificationFocusedMonitor
|
checked: SettingsData.notificationFocusedMonitor
|
||||||
onToggled: checked => SettingsData.set("notificationFocusedMonitor", checked)
|
onToggled: checked => SettingsData.set("notificationFocusedMonitor", checked)
|
||||||
}
|
}
|
||||||
@@ -445,7 +443,7 @@ Item {
|
|||||||
id: notificationRulesCard
|
id: notificationRulesCard
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "rule_settings"
|
iconName: "rule_settings"
|
||||||
title: I18n.tr("Notification Rules")
|
title: I18n.tr("Rules")
|
||||||
settingKey: "notificationRules"
|
settingKey: "notificationRules"
|
||||||
tags: ["notification", "rules", "mute", "ignore", "priority", "regex", "history"]
|
tags: ["notification", "rules", "mute", "ignore", "priority", "regex", "history"]
|
||||||
collapsible: true
|
collapsible: true
|
||||||
@@ -510,7 +508,7 @@ Item {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: ruleLabel
|
id: ruleLabel
|
||||||
text: I18n.tr("Rule") + " " + (index + 1)
|
text: I18n.tr("Rule %1").arg(index + 1)
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -785,7 +783,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "timer"
|
iconName: "timer"
|
||||||
title: I18n.tr("Notification Timeouts")
|
title: I18n.tr("Timeouts")
|
||||||
settingKey: "notificationTimeouts"
|
settingKey: "notificationTimeouts"
|
||||||
collapsible: true
|
collapsible: true
|
||||||
expanded: false
|
expanded: false
|
||||||
@@ -794,7 +792,6 @@ Item {
|
|||||||
settingKey: "notificationTimeoutLow"
|
settingKey: "notificationTimeoutLow"
|
||||||
tags: ["notification", "timeout", "low", "priority", "duration"]
|
tags: ["notification", "timeout", "low", "priority", "duration"]
|
||||||
text: I18n.tr("Low Priority")
|
text: I18n.tr("Low Priority")
|
||||||
description: I18n.tr("Timeout for low priority notifications")
|
|
||||||
currentValue: root.getTimeoutText(SettingsData.notificationTimeoutLow)
|
currentValue: root.getTimeoutText(SettingsData.notificationTimeoutLow)
|
||||||
options: root.timeoutOptions.map(opt => opt.text)
|
options: root.timeoutOptions.map(opt => opt.text)
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
@@ -811,7 +808,6 @@ Item {
|
|||||||
settingKey: "notificationTimeoutNormal"
|
settingKey: "notificationTimeoutNormal"
|
||||||
tags: ["notification", "timeout", "normal", "priority", "duration"]
|
tags: ["notification", "timeout", "normal", "priority", "duration"]
|
||||||
text: I18n.tr("Normal Priority")
|
text: I18n.tr("Normal Priority")
|
||||||
description: I18n.tr("Timeout for normal priority notifications")
|
|
||||||
currentValue: root.getTimeoutText(SettingsData.notificationTimeoutNormal)
|
currentValue: root.getTimeoutText(SettingsData.notificationTimeoutNormal)
|
||||||
options: root.timeoutOptions.map(opt => opt.text)
|
options: root.timeoutOptions.map(opt => opt.text)
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
@@ -828,7 +824,6 @@ Item {
|
|||||||
settingKey: "notificationTimeoutCritical"
|
settingKey: "notificationTimeoutCritical"
|
||||||
tags: ["notification", "timeout", "critical", "priority", "duration"]
|
tags: ["notification", "timeout", "critical", "priority", "duration"]
|
||||||
text: I18n.tr("Critical Priority")
|
text: I18n.tr("Critical Priority")
|
||||||
description: I18n.tr("Timeout for critical priority notifications")
|
|
||||||
currentValue: root.getTimeoutText(SettingsData.notificationTimeoutCritical)
|
currentValue: root.getTimeoutText(SettingsData.notificationTimeoutCritical)
|
||||||
options: root.timeoutOptions.map(opt => opt.text)
|
options: root.timeoutOptions.map(opt => opt.text)
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ Item {
|
|||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
settingKey: "osdVolumeEnabled"
|
settingKey: "osdVolumeEnabled"
|
||||||
text: I18n.tr("Volume")
|
text: I18n.tr("Volume")
|
||||||
description: I18n.tr("Show on-screen display when volume changes")
|
|
||||||
checked: SettingsData.osdVolumeEnabled
|
checked: SettingsData.osdVolumeEnabled
|
||||||
onToggled: checked => SettingsData.set("osdVolumeEnabled", checked)
|
onToggled: checked => SettingsData.set("osdVolumeEnabled", checked)
|
||||||
}
|
}
|
||||||
@@ -99,7 +98,6 @@ Item {
|
|||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
settingKey: "osdMediaVolumeEnabled"
|
settingKey: "osdMediaVolumeEnabled"
|
||||||
text: I18n.tr("Media Volume")
|
text: I18n.tr("Media Volume")
|
||||||
description: I18n.tr("Show on-screen display when media player volume changes")
|
|
||||||
checked: SettingsData.osdMediaVolumeEnabled
|
checked: SettingsData.osdMediaVolumeEnabled
|
||||||
onToggled: checked => SettingsData.set("osdMediaVolumeEnabled", checked)
|
onToggled: checked => SettingsData.set("osdMediaVolumeEnabled", checked)
|
||||||
}
|
}
|
||||||
@@ -107,7 +105,6 @@ Item {
|
|||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
settingKey: "osdMediaPlaybackEnabled"
|
settingKey: "osdMediaPlaybackEnabled"
|
||||||
text: I18n.tr("Media Playback")
|
text: I18n.tr("Media Playback")
|
||||||
description: I18n.tr("Show on-screen display when media player status changes")
|
|
||||||
checked: SettingsData.osdMediaPlaybackEnabled
|
checked: SettingsData.osdMediaPlaybackEnabled
|
||||||
onToggled: checked => SettingsData.set("osdMediaPlaybackEnabled", checked)
|
onToggled: checked => SettingsData.set("osdMediaPlaybackEnabled", checked)
|
||||||
}
|
}
|
||||||
@@ -115,7 +112,6 @@ Item {
|
|||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
settingKey: "osdBrightnessEnabled"
|
settingKey: "osdBrightnessEnabled"
|
||||||
text: I18n.tr("Brightness")
|
text: I18n.tr("Brightness")
|
||||||
description: I18n.tr("Show on-screen display when brightness changes")
|
|
||||||
checked: SettingsData.osdBrightnessEnabled
|
checked: SettingsData.osdBrightnessEnabled
|
||||||
onToggled: checked => SettingsData.set("osdBrightnessEnabled", checked)
|
onToggled: checked => SettingsData.set("osdBrightnessEnabled", checked)
|
||||||
}
|
}
|
||||||
@@ -123,7 +119,6 @@ Item {
|
|||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
settingKey: "osdIdleInhibitorEnabled"
|
settingKey: "osdIdleInhibitorEnabled"
|
||||||
text: I18n.tr("Idle Inhibitor")
|
text: I18n.tr("Idle Inhibitor")
|
||||||
description: I18n.tr("Show on-screen display when idle inhibitor state changes")
|
|
||||||
checked: SettingsData.osdIdleInhibitorEnabled
|
checked: SettingsData.osdIdleInhibitorEnabled
|
||||||
onToggled: checked => SettingsData.set("osdIdleInhibitorEnabled", checked)
|
onToggled: checked => SettingsData.set("osdIdleInhibitorEnabled", checked)
|
||||||
}
|
}
|
||||||
@@ -131,7 +126,6 @@ Item {
|
|||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
settingKey: "osdMicMuteEnabled"
|
settingKey: "osdMicMuteEnabled"
|
||||||
text: I18n.tr("Microphone Mute")
|
text: I18n.tr("Microphone Mute")
|
||||||
description: I18n.tr("Show on-screen display when microphone is muted/unmuted")
|
|
||||||
checked: SettingsData.osdMicMuteEnabled
|
checked: SettingsData.osdMicMuteEnabled
|
||||||
onToggled: checked => SettingsData.set("osdMicMuteEnabled", checked)
|
onToggled: checked => SettingsData.set("osdMicMuteEnabled", checked)
|
||||||
}
|
}
|
||||||
@@ -139,7 +133,6 @@ Item {
|
|||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
settingKey: "osdCapsLockEnabled"
|
settingKey: "osdCapsLockEnabled"
|
||||||
text: I18n.tr("Caps Lock")
|
text: I18n.tr("Caps Lock")
|
||||||
description: I18n.tr("Show on-screen display when caps lock state changes")
|
|
||||||
checked: SettingsData.osdCapsLockEnabled
|
checked: SettingsData.osdCapsLockEnabled
|
||||||
onToggled: checked => SettingsData.set("osdCapsLockEnabled", checked)
|
onToggled: checked => SettingsData.set("osdCapsLockEnabled", checked)
|
||||||
}
|
}
|
||||||
@@ -147,7 +140,6 @@ Item {
|
|||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
settingKey: "osdPowerProfileEnabled"
|
settingKey: "osdPowerProfileEnabled"
|
||||||
text: I18n.tr("Power Profile")
|
text: I18n.tr("Power Profile")
|
||||||
description: I18n.tr("Show on-screen display when power profile changes")
|
|
||||||
checked: SettingsData.osdPowerProfileEnabled
|
checked: SettingsData.osdPowerProfileEnabled
|
||||||
onToggled: checked => SettingsData.set("osdPowerProfileEnabled", checked)
|
onToggled: checked => SettingsData.set("osdPowerProfileEnabled", checked)
|
||||||
}
|
}
|
||||||
@@ -155,7 +147,6 @@ Item {
|
|||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
settingKey: "osdAudioOutputEnabled"
|
settingKey: "osdAudioOutputEnabled"
|
||||||
text: I18n.tr("Audio Output Switch")
|
text: I18n.tr("Audio Output Switch")
|
||||||
description: I18n.tr("Show on-screen display when cycling audio output devices")
|
|
||||||
checked: SettingsData.osdAudioOutputEnabled
|
checked: SettingsData.osdAudioOutputEnabled
|
||||||
onToggled: checked => SettingsData.set("osdAudioOutputEnabled", checked)
|
onToggled: checked => SettingsData.set("osdAudioOutputEnabled", checked)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ StyledRect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateSingle(plugin) {
|
function updateSingle(plugin) {
|
||||||
if (isUpdating) return;
|
if (isUpdating)
|
||||||
|
return;
|
||||||
isUpdating = true;
|
isUpdating = true;
|
||||||
currentUpdatingPlugin = plugin.name;
|
currentUpdatingPlugin = plugin.name;
|
||||||
|
|
||||||
@@ -68,7 +69,8 @@ StyledRect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateAll() {
|
function updateAll() {
|
||||||
if (isUpdating) return;
|
if (isUpdating)
|
||||||
|
return;
|
||||||
isUpdating = true;
|
isUpdating = true;
|
||||||
|
|
||||||
var list = updatesList.slice();
|
var list = updatesList.slice();
|
||||||
@@ -149,7 +151,9 @@ StyledRect {
|
|||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
Behavior on height {
|
Behavior on height {
|
||||||
NumberAnimation { duration: Theme.shortDuration }
|
NumberAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
@@ -220,7 +224,7 @@ StyledRect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: modelData.author ? I18n.tr("By %1").arg(modelData.author) : ""
|
text: modelData.author ? I18n.tr("by %1", "author attribution").arg(modelData.author) : ""
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ FocusScope {
|
|||||||
property var filteredPlugins: []
|
property var filteredPlugins: []
|
||||||
|
|
||||||
readonly property var pluginsWithUpdates: {
|
readonly property var pluginsWithUpdates: {
|
||||||
if (!DMSService.installedPlugins) return [];
|
if (!DMSService.installedPlugins)
|
||||||
|
return [];
|
||||||
return DMSService.installedPlugins.filter(p => p.hasUpdate === true);
|
return DMSService.installedPlugins.filter(p => p.hasUpdate === true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,7 +439,7 @@ FocusScope {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: I18n.tr("No plugins found.") + "\n" + I18n.tr("Place plugins in %1").arg(PluginService.pluginDirectory)
|
text: I18n.tr("No plugins found", "empty plugin list") + "\n" + I18n.tr("Place plugins in %1").arg(PluginService.pluginDirectory)
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ Item {
|
|||||||
tags: ["sound", "enable", "system"]
|
tags: ["sound", "enable", "system"]
|
||||||
settingKey: "soundsEnabled"
|
settingKey: "soundsEnabled"
|
||||||
text: I18n.tr("Enable System Sounds")
|
text: I18n.tr("Enable System Sounds")
|
||||||
description: I18n.tr("Play sounds for system events")
|
|
||||||
checked: SettingsData.soundsEnabled
|
checked: SettingsData.soundsEnabled
|
||||||
onToggled: checked => SettingsData.set("soundsEnabled", checked)
|
onToggled: checked => SettingsData.set("soundsEnabled", checked)
|
||||||
}
|
}
|
||||||
@@ -106,7 +105,6 @@ Item {
|
|||||||
visible: SettingsData.useSystemSoundTheme && AudioService.availableSoundThemes.length > 0
|
visible: SettingsData.useSystemSoundTheme && AudioService.availableSoundThemes.length > 0
|
||||||
enabled: SettingsData.useSystemSoundTheme && AudioService.availableSoundThemes.length > 0
|
enabled: SettingsData.useSystemSoundTheme && AudioService.availableSoundThemes.length > 0
|
||||||
text: I18n.tr("Sound Theme")
|
text: I18n.tr("Sound Theme")
|
||||||
description: I18n.tr("Select system sound theme")
|
|
||||||
options: AudioService.availableSoundThemes
|
options: AudioService.availableSoundThemes
|
||||||
currentValue: {
|
currentValue: {
|
||||||
const theme = AudioService.currentSoundTheme;
|
const theme = AudioService.currentSoundTheme;
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ Item {
|
|||||||
|
|
||||||
function fixCursorInclude() {
|
function fixCursorInclude() {
|
||||||
if (cursorReadOnly) {
|
if (cursorReadOnly) {
|
||||||
ToastService.showWarning(I18n.tr("Hyprland conf mode"), I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing cursor settings."), "dms setup", "hyprland-migration");
|
ToastService.showWarning(I18n.tr("Hyprland conf mode"), I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before changing these settings."), "dms setup", "hyprland-migration");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const paths = getCursorConfigPaths();
|
const paths = getCursorConfigPaths();
|
||||||
@@ -1626,7 +1626,6 @@ Item {
|
|||||||
tags: ["widget", "background", "color", "surface", "material"]
|
tags: ["widget", "background", "color", "surface", "material"]
|
||||||
settingKey: "widgetBackgroundColor"
|
settingKey: "widgetBackgroundColor"
|
||||||
text: I18n.tr("Widget Background Color")
|
text: I18n.tr("Widget Background Color")
|
||||||
description: I18n.tr("Choose the background color for widgets")
|
|
||||||
dropdownWidth: 220
|
dropdownWidth: 220
|
||||||
options: themeColorsTab.widgetBackgroundOptions
|
options: themeColorsTab.widgetBackgroundOptions
|
||||||
currentMode: SettingsData.widgetBackgroundColor
|
currentMode: SettingsData.widgetBackgroundColor
|
||||||
@@ -1943,7 +1942,6 @@ Item {
|
|||||||
tags: ["elevation", "shadow", "opacity", "transparency", "m3"]
|
tags: ["elevation", "shadow", "opacity", "transparency", "m3"]
|
||||||
settingKey: "m3ElevationOpacity"
|
settingKey: "m3ElevationOpacity"
|
||||||
text: I18n.tr("Shadow Opacity")
|
text: I18n.tr("Shadow Opacity")
|
||||||
description: I18n.tr("Controls the opacity of the shadow")
|
|
||||||
value: SettingsData.m3ElevationOpacity ?? 30
|
value: SettingsData.m3ElevationOpacity ?? 30
|
||||||
minimum: 0
|
minimum: 0
|
||||||
maximum: 100
|
maximum: 100
|
||||||
@@ -2220,7 +2218,7 @@ Item {
|
|||||||
StyledText {
|
StyledText {
|
||||||
text: {
|
text: {
|
||||||
if (cursorWarningBox.showLegacy)
|
if (cursorWarningBox.showLegacy)
|
||||||
return I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing cursor settings.");
|
return I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before changing these settings.");
|
||||||
if (cursorWarningBox.showSetup)
|
if (cursorWarningBox.showSetup)
|
||||||
return I18n.tr("Click 'Setup' to create %1 and add include to your compositor config.").arg("dms/cursor");
|
return I18n.tr("Click 'Setup' to create %1 and add include to your compositor config.").arg("dms/cursor");
|
||||||
return "";
|
return "";
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ Item {
|
|||||||
tags: ["time", "seconds", "clock"]
|
tags: ["time", "seconds", "clock"]
|
||||||
settingKey: "showSeconds"
|
settingKey: "showSeconds"
|
||||||
text: I18n.tr("Show Seconds")
|
text: I18n.tr("Show Seconds")
|
||||||
description: I18n.tr("Display seconds in the clock")
|
|
||||||
checked: SettingsData.showSeconds
|
checked: SettingsData.showSeconds
|
||||||
onToggled: checked => SettingsData.set("showSeconds", checked)
|
onToggled: checked => SettingsData.set("showSeconds", checked)
|
||||||
}
|
}
|
||||||
@@ -113,7 +112,6 @@ Item {
|
|||||||
tags: ["show", "week"]
|
tags: ["show", "week"]
|
||||||
settingKey: "showWeekNumber"
|
settingKey: "showWeekNumber"
|
||||||
text: I18n.tr("Show Week Number")
|
text: I18n.tr("Show Week Number")
|
||||||
description: I18n.tr("Show week number in the calendar")
|
|
||||||
checked: SettingsData.showWeekNumber
|
checked: SettingsData.showWeekNumber
|
||||||
onToggled: checked => SettingsData.set("showWeekNumber", checked)
|
onToggled: checked => SettingsData.set("showWeekNumber", checked)
|
||||||
}
|
}
|
||||||
@@ -218,7 +216,7 @@ Item {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
const match = presets.find(p => p.format === SettingsData.clockDateFormat);
|
const match = presets.find(p => p.format === SettingsData.clockDateFormat);
|
||||||
return match ? match.label : I18n.tr("Custom: ") + SettingsData.clockDateFormat;
|
return match ? match.label : I18n.tr("Custom") + ": " + SettingsData.clockDateFormat;
|
||||||
}
|
}
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
const formatMap = {};
|
const formatMap = {};
|
||||||
@@ -305,7 +303,7 @@ Item {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
const match = presets.find(p => p.format === SettingsData.lockDateFormat);
|
const match = presets.find(p => p.format === SettingsData.lockDateFormat);
|
||||||
return match ? match.label : I18n.tr("Custom: ") + SettingsData.lockDateFormat;
|
return match ? match.label : I18n.tr("Custom") + ": " + SettingsData.lockDateFormat;
|
||||||
}
|
}
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
const formatMap = {};
|
const formatMap = {};
|
||||||
|
|||||||
@@ -455,7 +455,7 @@ Item {
|
|||||||
buttonPadding: parent.width < 480 ? Theme.spacingXS : Theme.spacingS
|
buttonPadding: parent.width < 480 ? Theme.spacingXS : Theme.spacingS
|
||||||
minButtonWidth: parent.width < 480 ? 40 : 56
|
minButtonWidth: parent.width < 480 ? 40 : 56
|
||||||
textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium
|
textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium
|
||||||
model: [I18n.tr("Default"), I18n.tr("Low"), I18n.tr("Normal"), I18n.tr("High"), I18n.tr("Very High")]
|
model: [I18n.tr("Default"), I18n.tr("Low", "quality level option"), I18n.tr("Normal", "quality level option"), I18n.tr("High", "quality level option"), I18n.tr("Very High", "quality level option")]
|
||||||
selectionMode: "single"
|
selectionMode: "single"
|
||||||
currentIndex: SettingsData.textRenderQuality
|
currentIndex: SettingsData.textRenderQuality
|
||||||
onSelectionChanged: (index, selected) => {
|
onSelectionChanged: (index, selected) => {
|
||||||
@@ -622,7 +622,6 @@ Item {
|
|||||||
tags: ["animation", "duration", "custom", "speed", "popout"]
|
tags: ["animation", "duration", "custom", "speed", "popout"]
|
||||||
settingKey: "popoutCustomAnimationDuration"
|
settingKey: "popoutCustomAnimationDuration"
|
||||||
text: I18n.tr("Custom Duration")
|
text: I18n.tr("Custom Duration")
|
||||||
description: I18n.tr("%1 custom animation duration").arg(I18n.tr("Popouts"))
|
|
||||||
minimum: 0
|
minimum: 0
|
||||||
maximum: 1000
|
maximum: 1000
|
||||||
value: Theme.popoutAnimationDuration
|
value: Theme.popoutAnimationDuration
|
||||||
@@ -706,7 +705,6 @@ Item {
|
|||||||
tags: ["animation", "duration", "custom", "speed", "modal"]
|
tags: ["animation", "duration", "custom", "speed", "modal"]
|
||||||
settingKey: "modalCustomAnimationDuration"
|
settingKey: "modalCustomAnimationDuration"
|
||||||
text: I18n.tr("Custom Duration")
|
text: I18n.tr("Custom Duration")
|
||||||
description: I18n.tr("%1 custom animation duration").arg(I18n.tr("Modals"))
|
|
||||||
minimum: 0
|
minimum: 0
|
||||||
maximum: 1000
|
maximum: 1000
|
||||||
value: Theme.modalAnimationDuration
|
value: Theme.modalAnimationDuration
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ Item {
|
|||||||
return;
|
return;
|
||||||
const makeAdmin = !userRow.modelData.isAdmin;
|
const makeAdmin = !userRow.modelData.isAdmin;
|
||||||
adminToggleConfirm.showWithOptions({
|
adminToggleConfirm.showWithOptions({
|
||||||
title: makeAdmin ? I18n.tr("Grant admin?") : I18n.tr("Remove admin?"),
|
title: makeAdmin ? I18n.tr("Make admin") : I18n.tr("Remove admin"),
|
||||||
message: makeAdmin ? I18n.tr("Add \"%1\" to the %2 group?").arg(userRow.modelData.username).arg(UsersService.adminGroup) : I18n.tr("Remove \"%1\" from the %2 group?").arg(userRow.modelData.username).arg(UsersService.adminGroup),
|
message: makeAdmin ? I18n.tr("Add \"%1\" to the %2 group?").arg(userRow.modelData.username).arg(UsersService.adminGroup) : I18n.tr("Remove \"%1\" from the %2 group?").arg(userRow.modelData.username).arg(UsersService.adminGroup),
|
||||||
confirmText: makeAdmin ? I18n.tr("Grant") : I18n.tr("Remove"),
|
confirmText: makeAdmin ? I18n.tr("Grant") : I18n.tr("Remove"),
|
||||||
confirmColor: Theme.primary,
|
confirmColor: Theme.primary,
|
||||||
@@ -317,7 +317,7 @@ Item {
|
|||||||
if (actionBlocked)
|
if (actionBlocked)
|
||||||
return;
|
return;
|
||||||
deleteUserConfirm.showWithOptions({
|
deleteUserConfirm.showWithOptions({
|
||||||
title: I18n.tr("Delete user?"),
|
title: I18n.tr("Delete user"),
|
||||||
message: I18n.tr("Delete \"%1\" and remove the home directory? This cannot be undone.").arg(userRow.modelData.username),
|
message: I18n.tr("Delete \"%1\" and remove the home directory? This cannot be undone.").arg(userRow.modelData.username),
|
||||||
confirmText: I18n.tr("Delete"),
|
confirmText: I18n.tr("Delete"),
|
||||||
confirmColor: Theme.primary,
|
confirmColor: Theme.primary,
|
||||||
|
|||||||
@@ -804,7 +804,6 @@ Item {
|
|||||||
settingKey: "selectedMonitor"
|
settingKey: "selectedMonitor"
|
||||||
width: parent.width - Theme.spacingM * 2
|
width: parent.width - Theme.spacingM * 2
|
||||||
text: I18n.tr("Wallpaper Monitor")
|
text: I18n.tr("Wallpaper Monitor")
|
||||||
description: I18n.tr("Select monitor to configure wallpaper")
|
|
||||||
currentValue: {
|
currentValue: {
|
||||||
var screens = Quickshell.screens;
|
var screens = Quickshell.screens;
|
||||||
for (var i = 0; i < screens.length; i++) {
|
for (var i = 0; i < screens.length; i++) {
|
||||||
@@ -843,7 +842,7 @@ Item {
|
|||||||
currentValue: {
|
currentValue: {
|
||||||
var screens = Quickshell.screens;
|
var screens = Quickshell.screens;
|
||||||
if (!SettingsData.matugenTargetMonitor || SettingsData.matugenTargetMonitor === "") {
|
if (!SettingsData.matugenTargetMonitor || SettingsData.matugenTargetMonitor === "") {
|
||||||
return screens.length > 0 ? SettingsData.getScreenDisplayName(screens[0]) + " " + I18n.tr("(Default)", "default monitor label suffix") : I18n.tr("No monitors", "no monitors available label");
|
return screens.length > 0 ? SettingsData.getScreenDisplayName(screens[0]) + " " + "(" + I18n.tr("Default") + ")" : I18n.tr("No monitors", "no monitors available label");
|
||||||
}
|
}
|
||||||
for (var i = 0; i < screens.length; i++) {
|
for (var i = 0; i < screens.length; i++) {
|
||||||
if (screens[i].name === SettingsData.matugenTargetMonitor) {
|
if (screens[i].name === SettingsData.matugenTargetMonitor) {
|
||||||
@@ -858,14 +857,14 @@ Item {
|
|||||||
for (var i = 0; i < screens.length; i++) {
|
for (var i = 0; i < screens.length; i++) {
|
||||||
var label = SettingsData.getScreenDisplayName(screens[i]);
|
var label = SettingsData.getScreenDisplayName(screens[i]);
|
||||||
if (i === 0 && (!SettingsData.matugenTargetMonitor || SettingsData.matugenTargetMonitor === "")) {
|
if (i === 0 && (!SettingsData.matugenTargetMonitor || SettingsData.matugenTargetMonitor === "")) {
|
||||||
label += " " + I18n.tr("(Default)", "default monitor label suffix");
|
label += " " + "(" + I18n.tr("Default") + ")";
|
||||||
}
|
}
|
||||||
screenNames.push(label);
|
screenNames.push(label);
|
||||||
}
|
}
|
||||||
return screenNames;
|
return screenNames;
|
||||||
}
|
}
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
var cleanValue = value.replace(" " + I18n.tr("(Default)", "default monitor label suffix"), "");
|
var cleanValue = value.replace(" " + "(" + I18n.tr("Default") + ")", "");
|
||||||
var screens = Quickshell.screens;
|
var screens = Quickshell.screens;
|
||||||
for (var i = 0; i < screens.length; i++) {
|
for (var i = 0; i < screens.length; i++) {
|
||||||
if (SettingsData.getScreenDisplayName(screens[i]) === cleanValue) {
|
if (SettingsData.getScreenDisplayName(screens[i]) === cleanValue) {
|
||||||
@@ -924,7 +923,7 @@ Item {
|
|||||||
width: parent.width - Theme.spacingM * 2
|
width: parent.width - Theme.spacingM * 2
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Mode:")
|
text: I18n.tr("Mode") + ":"
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ Item {
|
|||||||
{
|
{
|
||||||
"id": "battery",
|
"id": "battery",
|
||||||
"text": I18n.tr("Battery"),
|
"text": I18n.tr("Battery"),
|
||||||
"description": I18n.tr("Battery level and power management"),
|
"description": I18n.tr("Battery and power management"),
|
||||||
"icon": "battery_std",
|
"icon": "battery_std",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ Item {
|
|||||||
"appId": I18n.tr("App ID"),
|
"appId": I18n.tr("App ID"),
|
||||||
"title": I18n.tr("Title"),
|
"title": I18n.tr("Title"),
|
||||||
"isFloating": I18n.tr("Floating"),
|
"isFloating": I18n.tr("Floating"),
|
||||||
"isActive": I18n.tr("Active"),
|
"isActive": I18n.tr("Active", "active state label"),
|
||||||
"isFocused": I18n.tr("Focused"),
|
"isFocused": I18n.tr("Focused"),
|
||||||
"isActiveInColumn": I18n.tr("Active in Column"),
|
"isActiveInColumn": I18n.tr("Active in Column"),
|
||||||
"isWindowCastTarget": I18n.tr("Cast Target"),
|
"isWindowCastTarget": I18n.tr("Cast Target"),
|
||||||
@@ -343,7 +343,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showHyprlandReadOnlyWarning() {
|
function showHyprlandReadOnlyWarning() {
|
||||||
ToastService.showWarning(I18n.tr("Hyprland conf mode"), I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing window rules in Settings."), "dms setup", "hyprland-migration");
|
ToastService.showWarning(I18n.tr("Hyprland conf mode"), I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before changing these settings."), "dms setup", "hyprland-migration");
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
@@ -509,7 +509,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: warningBox.showLegacy ? I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing window rules in Settings.") : I18n.tr("Click 'Setup' to create %1 and add include to your compositor config.").arg("dms/windowrules")
|
text: warningBox.showLegacy ? I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before changing these settings.") : I18n.tr("Click 'Setup' to create %1 and add include to your compositor config.").arg("dms/windowrules")
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ SettingsCard {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
iconName: "palette"
|
iconName: "palette"
|
||||||
title: I18n.tr("Workspace Appearance")
|
title: I18n.tr("Appearance")
|
||||||
settingKey: "workspaceAppearance"
|
settingKey: "workspaceAppearance"
|
||||||
tags: ["workspace", "focused", "color", "custom"]
|
tags: ["workspace", "focused", "color", "custom"]
|
||||||
collapsible: true
|
collapsible: true
|
||||||
@@ -200,10 +200,10 @@ SettingsCard {
|
|||||||
tabHeight: 44
|
tabHeight: 44
|
||||||
showIcons: false
|
showIcons: false
|
||||||
model: [({
|
model: [({
|
||||||
"text": I18n.tr("Focused Display", "workspace appearance tab")
|
"text": I18n.tr("Focused Display", "workspace appearance tab")
|
||||||
}), ({
|
}), ({
|
||||||
"text": I18n.tr("Unfocused Display(s)", "workspace appearance tab")
|
"text": I18n.tr("Unfocused Display(s)", "workspace appearance tab")
|
||||||
})]
|
})]
|
||||||
onTabClicked: index => currentIndex = index
|
onTabClicked: index => currentIndex = index
|
||||||
Component.onCompleted: Qt.callLater(updateIndicator)
|
Component.onCompleted: Qt.callLater(updateIndicator)
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "view_module"
|
iconName: "view_module"
|
||||||
title: I18n.tr("Workspace Settings")
|
title: I18n.tr("General")
|
||||||
settingKey: "workspaceSettings"
|
settingKey: "workspaceSettings"
|
||||||
|
|
||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
|
|||||||
@@ -547,7 +547,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showHyprlandReadOnlyWarning() {
|
function showHyprlandReadOnlyWarning() {
|
||||||
ToastService.showWarning(I18n.tr("Hyprland conf mode"), I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing shortcuts in Settings."), "dms setup", "hyprland-migration");
|
ToastService.showWarning(I18n.tr("Hyprland conf mode"), I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before changing these settings."), "dms setup", "hyprland-migration");
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeBind(key) {
|
function removeBind(key) {
|
||||||
|
|||||||
@@ -90,15 +90,20 @@ def json_changed(file_path, new_data):
|
|||||||
old_data = normalize_json(file_path)
|
old_data = normalize_json(file_path)
|
||||||
return json.dumps(old_data, sort_keys=True) != json.dumps(new_data, sort_keys=True)
|
return json.dumps(old_data, sort_keys=True) != json.dumps(new_data, sort_keys=True)
|
||||||
|
|
||||||
def upload_source_strings(api_token, project_id):
|
def upload_source_strings(api_token, project_id, prune=False):
|
||||||
if not EN_JSON.exists():
|
if not EN_JSON.exists():
|
||||||
warn("No en.json to upload")
|
warn("No en.json to upload")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
info("Uploading source strings to POEditor...")
|
info("Uploading source strings to POEditor..." + (" (pruning terms not in en.json)" if prune else ""))
|
||||||
|
|
||||||
with open(EN_JSON, 'rb') as f:
|
with open(EN_JSON, 'rb') as f:
|
||||||
boundary = '----WebKitFormBoundary7MA4YWxkTrZu0gW'
|
boundary = '----WebKitFormBoundary7MA4YWxkTrZu0gW'
|
||||||
|
sync_part = (
|
||||||
|
f'--{boundary}\r\n'
|
||||||
|
f'Content-Disposition: form-data; name="sync_terms"\r\n\r\n'
|
||||||
|
f'1\r\n'
|
||||||
|
) if prune else ''
|
||||||
body = (
|
body = (
|
||||||
f'--{boundary}\r\n'
|
f'--{boundary}\r\n'
|
||||||
f'Content-Disposition: form-data; name="api_token"\r\n\r\n'
|
f'Content-Disposition: form-data; name="api_token"\r\n\r\n'
|
||||||
@@ -109,6 +114,7 @@ def upload_source_strings(api_token, project_id):
|
|||||||
f'--{boundary}\r\n'
|
f'--{boundary}\r\n'
|
||||||
f'Content-Disposition: form-data; name="updating"\r\n\r\n'
|
f'Content-Disposition: form-data; name="updating"\r\n\r\n'
|
||||||
f'terms\r\n'
|
f'terms\r\n'
|
||||||
|
f'{sync_part}'
|
||||||
f'--{boundary}\r\n'
|
f'--{boundary}\r\n'
|
||||||
f'Content-Disposition: form-data; name="file"; filename="en.json"\r\n'
|
f'Content-Disposition: form-data; name="file"; filename="en.json"\r\n'
|
||||||
f'Content-Type: application/json\r\n\r\n'
|
f'Content-Type: application/json\r\n\r\n'
|
||||||
@@ -253,7 +259,7 @@ def save_sync_state():
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
error("Usage: i18nsync.py [check|sync|test|local]")
|
error("Usage: i18nsync.py [check|sync [--prune]|test|local]")
|
||||||
|
|
||||||
command = sys.argv[1]
|
command = sys.argv[1]
|
||||||
|
|
||||||
@@ -290,6 +296,10 @@ def main():
|
|||||||
elif command == "sync":
|
elif command == "sync":
|
||||||
api_token = get_env_or_error('POEDITOR_API_TOKEN')
|
api_token = get_env_or_error('POEDITOR_API_TOKEN')
|
||||||
project_id = get_env_or_error('POEDITOR_PROJECT_ID')
|
project_id = get_env_or_error('POEDITOR_PROJECT_ID')
|
||||||
|
prune = "--prune" in sys.argv[2:]
|
||||||
|
if prune:
|
||||||
|
warn("--prune deletes every POEditor term missing from the local en.json, including its translations.")
|
||||||
|
warn("Terms from dms-plugins/ are machine-dependent: make sure all official plugins are present before pruning.")
|
||||||
|
|
||||||
extract_strings()
|
extract_strings()
|
||||||
|
|
||||||
@@ -310,8 +320,8 @@ def main():
|
|||||||
|
|
||||||
strings_changed = json.dumps(current_en, sort_keys=True) != json.dumps(staged_en, sort_keys=True)
|
strings_changed = json.dumps(current_en, sort_keys=True) != json.dumps(staged_en, sort_keys=True)
|
||||||
|
|
||||||
if strings_changed:
|
if strings_changed or prune:
|
||||||
upload_source_strings(api_token, project_id)
|
upload_source_strings(api_token, project_id, prune)
|
||||||
else:
|
else:
|
||||||
info("No changes in source strings")
|
info("No changes in source strings")
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
While term_freeze.json exists, any I18n.tr()/qsTr() term not in it fails the check.
|
While term_freeze.json exists, any I18n.tr()/qsTr() term not in it fails the check.
|
||||||
Existing terms may be reused or moved freely.
|
Existing terms may be reused or moved freely.
|
||||||
|
|
||||||
|
The freeze is term-granular: adding a new real context to a frozen term via
|
||||||
|
I18n.tr(term, ctx, true) does not trip it (same English string, new slot).
|
||||||
|
|
||||||
--update re-snapshot the current terms into term_freeze.json
|
--update re-snapshot the current terms into term_freeze.json
|
||||||
(delete term_freeze.json to lift the freeze)
|
(delete term_freeze.json to lift the freeze)
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Block near-variant translation terms (case/trailing-punctuation duplicates).
|
||||||
|
|
||||||
|
Unlike a term freeze, new terms are always allowed. This only fails when two
|
||||||
|
terms collapse to the same string after lowercasing and stripping trailing
|
||||||
|
".:?! " punctuation - e.g. "Signal" vs "Signal:", "Reset to Default?" vs
|
||||||
|
"Reset to default". Build punctuation outside tr() instead:
|
||||||
|
I18n.tr("Signal") + ":"
|
||||||
|
|
||||||
|
"Term" vs "Term..." pairs are NOT flagged: a trailing ellipsis is meaningful
|
||||||
|
(progress states, opens-a-dialog affordances).
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
from extract_translations import extract_qstr_strings
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT_DIR = Path(__file__).parent.parent
|
||||||
|
|
||||||
|
# Intentional pairs that survive normalization on purpose.
|
||||||
|
ALLOWED = [
|
||||||
|
{"PIN", "Pin"}, # WPS PIN acronym vs the verb "pin"
|
||||||
|
{"Device", "device"}, # label vs inline generic-noun fallback
|
||||||
|
{"Until %1", "until %1"}, # sentence-initial vs mid-sentence position
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def normalize(term):
|
||||||
|
t = term.replace("…", "...")
|
||||||
|
ellipsis = t.rstrip().endswith("...")
|
||||||
|
t = t.lower().rstrip(".:?! ")
|
||||||
|
return t + "..." if ellipsis else t
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
translations = extract_qstr_strings(ROOT_DIR)
|
||||||
|
groups = defaultdict(set)
|
||||||
|
for term in translations:
|
||||||
|
groups[normalize(term)].add(term)
|
||||||
|
|
||||||
|
failures = []
|
||||||
|
for variants in groups.values():
|
||||||
|
if len(variants) < 2 or any(variants == a for a in ALLOWED):
|
||||||
|
continue
|
||||||
|
# term vs term+"..." is allowed; flag only same-ellipsis-class variants
|
||||||
|
plain = {v for v in variants if not v.replace("…", "...").rstrip().endswith("...")}
|
||||||
|
dotted = variants - plain
|
||||||
|
for cls in (plain, dotted):
|
||||||
|
if len(cls) > 1:
|
||||||
|
failures.append(sorted(cls))
|
||||||
|
|
||||||
|
if not failures:
|
||||||
|
print(f"No term variants ({len(translations)} terms checked)")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
print("Near-variant terms found - reuse one exact term (or add to ALLOWED "
|
||||||
|
"in check_term_variants.py if genuinely intentional):", file=sys.stderr)
|
||||||
|
for variants in sorted(failures):
|
||||||
|
print(f" {variants}", file=sys.stderr)
|
||||||
|
for v in variants:
|
||||||
|
for occ in translations[v]["occurrences"][:3]:
|
||||||
|
print(f" {v!r}: {occ['file']}:{occ['line']}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
+13188
-4427
File diff suppressed because it is too large
Load Diff
@@ -435,7 +435,7 @@ def parse_tabs_from_sidebar(sidebar_file):
|
|||||||
with open(sidebar_file, "r", encoding="utf-8") as f:
|
with open(sidebar_file, "r", encoding="utf-8") as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
|
|
||||||
pattern = r'"text"\s*:\s*I18n\.tr\("([^"]+)"(?:,\s*"[^"]+")?\).*?"icon"\s*:\s*"([^"]+)".*?"tabIndex"\s*:\s*(\d+)'
|
pattern = r'"text"\s*:\s*I18n\.tr\("([^"]+)"(?:,\s*"[^"]+"(?:,\s*true)?)?\).*?"icon"\s*:\s*"([^"]+)".*?"tabIndex"\s*:\s*(\d+)'
|
||||||
tabs = []
|
tabs = []
|
||||||
|
|
||||||
for match in re.finditer(pattern, content, re.DOTALL):
|
for match in re.finditer(pattern, content, re.DOTALL):
|
||||||
|
|||||||
@@ -18,11 +18,29 @@ def spans_overlap(a, b):
|
|||||||
|
|
||||||
|
|
||||||
def extract_qstr_strings(root_dir):
|
def extract_qstr_strings(root_dir):
|
||||||
translations = defaultdict(lambda: {'contexts': set(), 'occurrences': []})
|
translations = defaultdict(lambda: {
|
||||||
|
'contexts': set(),
|
||||||
|
'real_contexts': defaultdict(list),
|
||||||
|
'occurrences': [],
|
||||||
|
'plain_occurrences': []
|
||||||
|
})
|
||||||
qstr_patterns = [
|
qstr_patterns = [
|
||||||
(re.compile(r'qsTr\(\s*"((?:\\.|[^"\\])*)"\s*\)'), '"'),
|
(re.compile(r'qsTr\(\s*"((?:\\.|[^"\\])*)"\s*\)'), '"'),
|
||||||
(re.compile(r"qsTr\(\s*'((?:\\.|[^'\\])*)'\s*\)"), "'")
|
(re.compile(r"qsTr\(\s*'((?:\\.|[^'\\])*)'\s*\)"), "'")
|
||||||
]
|
]
|
||||||
|
# I18n.tr(term, context, true) -- the literal `true` flag uploads the
|
||||||
|
# context as a real POEditor context, giving (term, context) its own
|
||||||
|
# translation slot. Must be on one line with a literal `true`.
|
||||||
|
i18n_real_context_patterns = [
|
||||||
|
(
|
||||||
|
re.compile(r'I18n\.tr\(\s*"((?:\\.|[^"\\])*)"\s*,\s*"((?:\\.|[^"\\])*)"\s*,\s*true\s*\)'),
|
||||||
|
'"'
|
||||||
|
),
|
||||||
|
(
|
||||||
|
re.compile(r"I18n\.tr\(\s*'((?:\\.|[^'\\])*)'\s*,\s*'((?:\\.|[^'\\])*)'\s*,\s*true\s*\)"),
|
||||||
|
"'"
|
||||||
|
)
|
||||||
|
]
|
||||||
i18n_context_patterns = [
|
i18n_context_patterns = [
|
||||||
(
|
(
|
||||||
re.compile(r'I18n\.tr\(\s*"((?:\\.|[^"\\])*)"\s*,\s*"((?:\\.|[^"\\])*)"\s*\)'),
|
re.compile(r'I18n\.tr\(\s*"((?:\\.|[^"\\])*)"\s*,\s*"((?:\\.|[^"\\])*)"\s*\)'),
|
||||||
@@ -46,75 +64,96 @@ def extract_qstr_strings(root_dir):
|
|||||||
for pattern, quote in qstr_patterns:
|
for pattern, quote in qstr_patterns:
|
||||||
for match in pattern.finditer(line):
|
for match in pattern.finditer(line):
|
||||||
term = decode_string_literal(match.group(1), quote)
|
term = decode_string_literal(match.group(1), quote)
|
||||||
translations[term]['occurrences'].append({
|
occ = {'file': str(relative_path), 'line': line_num}
|
||||||
'file': str(relative_path),
|
translations[term]['occurrences'].append(occ)
|
||||||
'line': line_num
|
translations[term]['plain_occurrences'].append(occ)
|
||||||
})
|
|
||||||
|
real_spans = []
|
||||||
|
for pattern, quote in i18n_real_context_patterns:
|
||||||
|
for match in pattern.finditer(line):
|
||||||
|
term = decode_string_literal(match.group(1), quote)
|
||||||
|
context = decode_string_literal(match.group(2), quote)
|
||||||
|
occ = {'file': str(relative_path), 'line': line_num}
|
||||||
|
translations[term]['real_contexts'][context].append(occ)
|
||||||
|
translations[term]['occurrences'].append(occ)
|
||||||
|
real_spans.append(match.span())
|
||||||
|
|
||||||
context_spans = []
|
context_spans = []
|
||||||
for pattern, quote in i18n_context_patterns:
|
for pattern, quote in i18n_context_patterns:
|
||||||
for match in pattern.finditer(line):
|
for match in pattern.finditer(line):
|
||||||
|
if any(spans_overlap(match.span(), span) for span in real_spans):
|
||||||
|
continue
|
||||||
term = decode_string_literal(match.group(1), quote)
|
term = decode_string_literal(match.group(1), quote)
|
||||||
context = decode_string_literal(match.group(2), quote)
|
context = decode_string_literal(match.group(2), quote)
|
||||||
|
occ = {'file': str(relative_path), 'line': line_num}
|
||||||
translations[term]['contexts'].add(context)
|
translations[term]['contexts'].add(context)
|
||||||
translations[term]['occurrences'].append({
|
translations[term]['occurrences'].append(occ)
|
||||||
'file': str(relative_path),
|
translations[term]['plain_occurrences'].append(occ)
|
||||||
'line': line_num
|
|
||||||
})
|
|
||||||
context_spans.append(match.span())
|
context_spans.append(match.span())
|
||||||
|
|
||||||
for pattern, quote in i18n_simple_patterns:
|
for pattern, quote in i18n_simple_patterns:
|
||||||
for match in pattern.finditer(line):
|
for match in pattern.finditer(line):
|
||||||
if any(spans_overlap(match.span(), span) for span in context_spans):
|
if any(spans_overlap(match.span(), span) for span in real_spans + context_spans):
|
||||||
continue
|
continue
|
||||||
term = decode_string_literal(match.group(1), quote)
|
term = decode_string_literal(match.group(1), quote)
|
||||||
translations[term]['occurrences'].append({
|
occ = {'file': str(relative_path), 'line': line_num}
|
||||||
'file': str(relative_path),
|
translations[term]['occurrences'].append(occ)
|
||||||
'line': line_num
|
translations[term]['plain_occurrences'].append(occ)
|
||||||
})
|
|
||||||
|
|
||||||
return translations
|
return translations
|
||||||
|
|
||||||
|
def area_tags(occurrences):
|
||||||
|
tags = set()
|
||||||
|
for occ in occurrences:
|
||||||
|
path = occ['file']
|
||||||
|
if path.startswith('dms-plugins/'):
|
||||||
|
tags.add('plugin-' + path.split('/')[1].lower())
|
||||||
|
elif path.startswith(('Modules/Settings/', 'Modals/Settings/')):
|
||||||
|
tags.add('settings')
|
||||||
|
else:
|
||||||
|
tags.add('shell')
|
||||||
|
return sorted(tags)
|
||||||
|
|
||||||
def create_poeditor_json(translations):
|
def create_poeditor_json(translations):
|
||||||
poeditor_data = []
|
poeditor_data = []
|
||||||
|
|
||||||
for term, data in sorted(translations.items()):
|
for term, data in sorted(translations.items()):
|
||||||
references = []
|
if data['plain_occurrences']:
|
||||||
|
references = [f"{occ['file']}:{occ['line']}" for occ in data['plain_occurrences']]
|
||||||
|
contexts = sorted(data['contexts']) if data['contexts'] else []
|
||||||
|
comment = " | ".join(contexts) if contexts else ""
|
||||||
|
|
||||||
for occ in data['occurrences']:
|
poeditor_data.append({
|
||||||
ref = f"{occ['file']}:{occ['line']}"
|
"term": term,
|
||||||
references.append(ref)
|
"context": term,
|
||||||
|
"reference": ", ".join(references),
|
||||||
|
"comment": comment,
|
||||||
|
"tags": area_tags(data['plain_occurrences'])
|
||||||
|
})
|
||||||
|
|
||||||
contexts = sorted(data['contexts']) if data['contexts'] else []
|
for context in sorted(data['real_contexts']):
|
||||||
comment = " | ".join(contexts) if contexts else ""
|
references = [f"{occ['file']}:{occ['line']}" for occ in data['real_contexts'][context]]
|
||||||
|
poeditor_data.append({
|
||||||
entry = {
|
"term": term,
|
||||||
"term": term,
|
"context": context,
|
||||||
"context": term,
|
"reference": ", ".join(references),
|
||||||
"reference": ", ".join(references),
|
"comment": "",
|
||||||
"comment": comment
|
"tags": area_tags(data['real_contexts'][context])
|
||||||
}
|
})
|
||||||
poeditor_data.append(entry)
|
|
||||||
|
|
||||||
return poeditor_data
|
return poeditor_data
|
||||||
|
|
||||||
def create_template_json(translations):
|
def create_template_json(translations):
|
||||||
template_data = []
|
return [
|
||||||
|
{
|
||||||
for term, data in sorted(translations.items()):
|
"term": entry["term"],
|
||||||
contexts = sorted(data['contexts']) if data['contexts'] else []
|
|
||||||
context_str = " | ".join(contexts) if contexts else ""
|
|
||||||
|
|
||||||
entry = {
|
|
||||||
"term": term,
|
|
||||||
"translation": "",
|
"translation": "",
|
||||||
"context": context_str,
|
"context": entry["context"],
|
||||||
"reference": "",
|
"reference": "",
|
||||||
"comment": ""
|
"comment": entry["comment"]
|
||||||
}
|
}
|
||||||
template_data.append(entry)
|
for entry in create_poeditor_json(translations)
|
||||||
|
]
|
||||||
return template_data
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
script_dir = Path(__file__).parent
|
script_dir = Path(__file__).parent
|
||||||
@@ -142,6 +181,8 @@ def main():
|
|||||||
print(f" - Unique strings: {len(translations)}")
|
print(f" - Unique strings: {len(translations)}")
|
||||||
print(f" - Total occurrences: {sum(len(data['occurrences']) for data in translations.values())}")
|
print(f" - Total occurrences: {sum(len(data['occurrences']) for data in translations.values())}")
|
||||||
print(f" - Strings with contexts: {sum(1 for data in translations.values() if data['contexts'])}")
|
print(f" - Strings with contexts: {sum(1 for data in translations.values() if data['contexts'])}")
|
||||||
|
print(f" - Real-context entries: {sum(len(data['real_contexts']) for data in translations.values())}")
|
||||||
|
print(f" - POEditor entries: {len(poeditor_data)}")
|
||||||
print(f" - Source file: {en_json_path}")
|
print(f" - Source file: {en_json_path}")
|
||||||
print(f" - Template file: {template_json_path}")
|
print(f" - Template file: {template_json_path}")
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+3684
-4321
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user