Add Simplified Chinese as a system language
The installer asks for the language before the keyboard, and Setup > Language (omarchy language en|zh) switches it later. Under zh_CN the menu reads its labels from omarchy-menu.zh-cn.jsonc, the shell from I18nZh.js through I18n.tr, and notifications are worded by their sender through omarchy-text, which reads the same table. User text is never translated.
This commit is contained in:
138 files changed
+1986
-558
No files matched your search
@@ -339,9 +339,9 @@ Panel {
|
||||
|
||||
// A few ways into making Omarchy your own, handed to the default agent.
|
||||
readonly property var starterPrompts: [
|
||||
{ glyph: "", label: "Theme", prompt: "Make me a new Omarchy theme. Ask me what look or inspiration I have in mind, then build it following the Omarchy skill's theming guide and switch to it." },
|
||||
{ glyph: "", label: "Plugin", prompt: "Make me a new Omarchy shell plugin. Ask me what I'd like it to do, then build it following the Omarchy skill's plugin guide and enable it." },
|
||||
{ glyph: "", label: "App", prompt: "Make me a new app for my Omarchy desktop. Ask me what it should do, then build it following the omarchy-app skill and install it so it shows up in the app launcher." }
|
||||
{ glyph: "", label: I18n.tr("Theme"), prompt: "Make me a new Omarchy theme. Ask me what look or inspiration I have in mind, then build it following the Omarchy skill's theming guide and switch to it." },
|
||||
{ glyph: "", label: I18n.tr("Plugin"), prompt: "Make me a new Omarchy shell plugin. Ask me what I'd like it to do, then build it following the Omarchy skill's plugin guide and enable it." },
|
||||
{ glyph: "", label: I18n.tr("App"), prompt: "Make me a new app for my Omarchy desktop. Ask me what it should do, then build it following the omarchy-app skill and install it so it shows up in the app launcher." }
|
||||
]
|
||||
|
||||
function startPrompt(prompt) {
|
||||
@@ -407,7 +407,7 @@ Panel {
|
||||
var parts = []
|
||||
if (String(account.plan || "") !== "") parts.push(account.plan)
|
||||
if (account.resetCredits && Number(account.resetCredits.available) > 0)
|
||||
parts.push(account.resetCredits.available + " free reset" + (Number(account.resetCredits.available) === 1 ? "" : "s"))
|
||||
parts.push(I18n.tr(Number(account.resetCredits.available) === 1 ? "%1 free reset" : "%1 free resets", account.resetCredits.available))
|
||||
return parts.join(" · ")
|
||||
}
|
||||
|
||||
@@ -450,12 +450,18 @@ Panel {
|
||||
function resetCreditsText(credits) {
|
||||
if (!credits || !(Number(credits.available) > 0)) return ""
|
||||
var count = Number(credits.available)
|
||||
var text = count + " free reset" + (count === 1 ? "" : "s")
|
||||
var text = I18n.tr(count === 1 ? "%1 free reset" : "%1 free resets", count)
|
||||
var expires = new Date(String(credits.nextExpiresAt || "")).getTime()
|
||||
if (isFinite(expires) && expires > nowMs) text += " · next expires in " + formatDuration(expires - nowMs)
|
||||
if (isFinite(expires) && expires > nowMs) text += " · " + I18n.tr("next expires in %1", formatDuration(expires - nowMs))
|
||||
return text
|
||||
}
|
||||
|
||||
// A model-scoped title ("Opus Monthly") keeps the model and translates the window.
|
||||
function windowLabel(title) {
|
||||
var match = String(title || "").match(/^(.*\S)\s+(Monthly|Weekly|Session|Limit)$/)
|
||||
return match ? match[1] + " " + I18n.tr(match[2]) : I18n.tr(String(title || ""))
|
||||
}
|
||||
|
||||
function planLabel(p) {
|
||||
var tier = String(p && p.tierLabel || "")
|
||||
return tier === "" ? "" : tier.charAt(0).toUpperCase() + tier.slice(1)
|
||||
@@ -576,13 +582,13 @@ Panel {
|
||||
}
|
||||
|
||||
function formatDuration(ms) {
|
||||
if (!(ms > 0)) return "now"
|
||||
if (!(ms > 0)) return I18n.tr("now")
|
||||
var minutes = Math.floor(ms / 60000)
|
||||
var hours = Math.floor(minutes / 60)
|
||||
var days = Math.floor(hours / 24)
|
||||
if (days > 0) return days + "d " + (hours % 24) + "h"
|
||||
if (hours > 0) return hours + "h " + (minutes % 60) + "m"
|
||||
return Math.max(1, minutes) + "m"
|
||||
if (days > 0) return I18n.tr("%1d %2h", days, hours % 24)
|
||||
if (hours > 0) return I18n.tr("%1h %2m", hours, minutes % 60)
|
||||
return I18n.tr("%1m", Math.max(1, minutes))
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- balance
|
||||
@@ -612,8 +618,8 @@ Panel {
|
||||
|
||||
function balanceDetailText(b) {
|
||||
if (!b || !(b.funded > 0)) return ""
|
||||
var text = formatMoney(b.spent, b.currency) + " spent of " + formatMoney(b.funded, b.currency) + " funded"
|
||||
if (b.estimated) text += " · estimated"
|
||||
var text = I18n.tr("%1 spent of %2 funded", formatMoney(b.spent, b.currency), formatMoney(b.funded, b.currency))
|
||||
if (b.estimated) text += " · " + I18n.tr("estimated")
|
||||
return text
|
||||
}
|
||||
|
||||
@@ -654,16 +660,16 @@ Panel {
|
||||
}
|
||||
|
||||
var phrases = []
|
||||
if (week > 0) phrases.push(usage.formatTokenCount(week) + " tokens this week")
|
||||
if (today > 0) phrases.push(usage.formatTokenCount(today) + " tokens today")
|
||||
if (week > 0) phrases.push(I18n.tr("%1 tokens this week", usage.formatTokenCount(week)))
|
||||
if (today > 0) phrases.push(I18n.tr("%1 tokens today", usage.formatTokenCount(today)))
|
||||
var topModel = ""
|
||||
for (var model in byModel) if (topModel === "" || byModel[model] > byModel[topModel]) topModel = model
|
||||
if (topModel !== "" && byModel[topModel] > 0) phrases.push("Mostly " + topModel)
|
||||
if (topModel !== "" && byModel[topModel] > 0) phrases.push(I18n.tr("Mostly %1", topModel))
|
||||
var busiest = ""
|
||||
for (var date in byDay) if (busiest === "" || byDay[date] > byDay[busiest]) busiest = date
|
||||
if (busiest !== "" && byDay[busiest] > 0) phrases.push("Busiest day: " + dayName(busiest))
|
||||
if (prompts > 0) phrases.push(prompts + " prompt" + (prompts === 1 ? "" : "s") + " today")
|
||||
if (sessions > 0) phrases.push(sessions + " session" + (sessions === 1 ? "" : "s") + " today")
|
||||
if (busiest !== "" && byDay[busiest] > 0) phrases.push(I18n.tr("Busiest day: %1", dayName(busiest)))
|
||||
if (prompts > 0) phrases.push(I18n.tr(prompts === 1 ? "%1 prompt today" : "%1 prompts today", prompts))
|
||||
if (sessions > 0) phrases.push(I18n.tr(sessions === 1 ? "%1 session today" : "%1 sessions today", sessions))
|
||||
return phrases
|
||||
}
|
||||
property int phraseIndex: 0
|
||||
@@ -673,7 +679,7 @@ Panel {
|
||||
property string shownPhrase: ""
|
||||
readonly property string heroPhrase: addStage !== "" || blankSlate
|
||||
? addHeading
|
||||
: (shownPhrase !== "" ? shownPhrase : "Subscriptions")
|
||||
: (shownPhrase !== "" ? shownPhrase : I18n.tr("Subscriptions"))
|
||||
|
||||
function showPhrase() {
|
||||
var n = summaryPhrases.length
|
||||
@@ -685,7 +691,7 @@ Panel {
|
||||
function dayName(date) {
|
||||
var parsed = new Date(String(date || "") + "T00:00:00")
|
||||
if (isNaN(parsed.getTime())) return String(date || "")
|
||||
return ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][parsed.getDay()]
|
||||
return I18n.tr(["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][parsed.getDay()])
|
||||
}
|
||||
|
||||
// Only speaks up when the numbers cover more than this machine.
|
||||
@@ -694,7 +700,7 @@ Panel {
|
||||
for (var i = 0; i < providers.length; i++) {
|
||||
var count = Number(providers[i].syncDeviceCount || 0)
|
||||
if (providers[i].syncEnabled && count > 0)
|
||||
return "Merged from " + count + " device" + (count === 1 ? "" : "s")
|
||||
return I18n.tr(count === 1 ? "Merged from %1 device" : "Merged from %1 devices", count)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -744,8 +750,8 @@ Panel {
|
||||
|
||||
// Adding takes over the hero's line, and the cursor starts over.
|
||||
readonly property string addHeading: picking || addProvider === ""
|
||||
? "Add an account"
|
||||
: "Add " + (/^[AEIOU]/.test(addProviderName(addProvider)) ? "an " : "a ") + addProviderName(addProvider) + " account"
|
||||
? I18n.tr("Add an account")
|
||||
: I18n.tr(/^[AEIOU]/.test(addProviderName(addProvider)) ? "Add an %1 account" : "Add a %1 account", addProviderName(addProvider))
|
||||
onAddStageChanged: {
|
||||
phraseSwap.stop()
|
||||
hero.metaOpacity = 1.0
|
||||
@@ -804,7 +810,7 @@ Panel {
|
||||
stdout: SplitParser { onRead: function(line) { root.handleAddLine(line) } }
|
||||
onExited: {
|
||||
if (root.addStage === "running") {
|
||||
root.addResult = "The sign-in didn't finish."
|
||||
root.addResult = I18n.tr("The sign-in didn't finish.")
|
||||
root.addStage = "error"
|
||||
}
|
||||
}
|
||||
@@ -939,7 +945,7 @@ Panel {
|
||||
PanelHero {
|
||||
id: hero
|
||||
width: parent.width
|
||||
title: "Agents"
|
||||
title: I18n.tr("Agents")
|
||||
meta: root.heroPhrase
|
||||
foreground: root.foreground
|
||||
fontFamily: root.fontFamily
|
||||
@@ -965,7 +971,7 @@ Panel {
|
||||
onHovered: root.pointAt("add")
|
||||
readonly property bool adding: root.addStage !== ""
|
||||
glyph: adding ? "" : ""
|
||||
tooltip: adding ? "Back to the limits" : "Add a subscription"
|
||||
tooltip: adding ? I18n.tr("Back to the limits") : I18n.tr("Add a subscription")
|
||||
onClicked: adding ? root.cancelAdd() : root.addAccount()
|
||||
}
|
||||
|
||||
@@ -974,7 +980,7 @@ Panel {
|
||||
hasCursor: root.hasKey("launch")
|
||||
onHovered: root.pointAt("launch")
|
||||
glyph: ""
|
||||
tooltip: "Start the default agent"
|
||||
tooltip: I18n.tr("Start the default agent")
|
||||
onClicked: root.launchAgent()
|
||||
}
|
||||
}
|
||||
@@ -1011,7 +1017,7 @@ Panel {
|
||||
spacing: Style.space(12)
|
||||
|
||||
PanelSectionHeader {
|
||||
text: "MAKE SOMETHING COOL"
|
||||
text: I18n.tr("MAKE SOMETHING COOL")
|
||||
foreground: root.foreground
|
||||
fontFamily: root.fontFamily
|
||||
}
|
||||
@@ -1065,7 +1071,8 @@ Panel {
|
||||
Text {
|
||||
visible: root.blankSlate && root.picking
|
||||
width: parent.width
|
||||
text: "Sign in to an AI coding subscription, and this panel keeps track of how much of it you have left."
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("Sign in to an AI coding subscription, and this panel keeps track of how much of it you have left.")
|
||||
color: root.dim
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.caption
|
||||
@@ -1137,7 +1144,8 @@ Panel {
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
text: "Name this account. It signs in through a private window, so your browser's current account isn't picked up."
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("Name this account. It signs in through a private window, so your browser's current account isn't picked up.")
|
||||
color: root.dim
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.caption
|
||||
@@ -1147,7 +1155,7 @@ Panel {
|
||||
TextField {
|
||||
id: addNameField
|
||||
width: parent.width
|
||||
placeholderText: "Work"
|
||||
placeholderText: I18n.tr("Work")
|
||||
foreground: root.foreground
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.body
|
||||
@@ -1166,7 +1174,7 @@ Panel {
|
||||
Text {
|
||||
width: parent.width
|
||||
textFormat: Text.PlainText
|
||||
text: root.addStatus
|
||||
text: I18n.tr(root.addStatus)
|
||||
color: root.foreground
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -1179,7 +1187,8 @@ Panel {
|
||||
spacing: Style.space(4)
|
||||
|
||||
Text {
|
||||
text: "Confirm this code in your browser"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("Confirm this code in your browser")
|
||||
color: root.dim
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.caption
|
||||
@@ -1203,7 +1212,8 @@ Panel {
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
text: "If the page shows a code instead of finishing, paste it here."
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("If the page shows a code instead of finishing, paste it here.")
|
||||
color: root.dim
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.caption
|
||||
@@ -1213,7 +1223,7 @@ Panel {
|
||||
TextField {
|
||||
id: pasteField
|
||||
width: parent.width
|
||||
placeholderText: "Code"
|
||||
placeholderText: I18n.tr("Code")
|
||||
foreground: root.foreground
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.body
|
||||
@@ -1224,7 +1234,7 @@ Panel {
|
||||
|
||||
TextLink {
|
||||
visible: root.addUrl !== ""
|
||||
text: "Open the sign-in page again"
|
||||
text: I18n.tr("Open the sign-in page again")
|
||||
onClicked: root.reopenSignIn()
|
||||
}
|
||||
}
|
||||
@@ -1234,7 +1244,7 @@ Panel {
|
||||
visible: root.addStage === "done" || root.addStage === "error"
|
||||
width: parent.width
|
||||
textFormat: Text.PlainText
|
||||
text: root.addResult
|
||||
text: I18n.tr(root.addResult)
|
||||
color: root.addStage === "error" ? root.urgent : root.foreground
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -1330,9 +1340,9 @@ Panel {
|
||||
TextLink {
|
||||
visible: !section.multi && root.needsSignIn(section.provider)
|
||||
picked: root.hasKey("providerSignin", section.providerIndex)
|
||||
text: "Sign-in required"
|
||||
text: I18n.tr("Sign-in required")
|
||||
idleColor: root.urgent
|
||||
tooltip: "Sign in to " + (section.provider ? section.provider.providerName : "") + " again"
|
||||
tooltip: I18n.tr("Sign in to %1 again", section.provider ? section.provider.providerName : "")
|
||||
onClicked: root.signInAgain(section.provider, null)
|
||||
}
|
||||
|
||||
@@ -1341,7 +1351,7 @@ Panel {
|
||||
width: parent.width
|
||||
textFormat: Text.PlainText
|
||||
// Shown for the status, so a record with no help to offer says the status rather than nothing.
|
||||
text: section.provider ? String(section.provider.authHelpText || section.provider.usageStatusText || "") : ""
|
||||
text: section.provider ? I18n.tr(String(section.provider.authHelpText || section.provider.usageStatusText || "")) : ""
|
||||
color: root.urgent
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.caption
|
||||
@@ -1398,7 +1408,7 @@ Panel {
|
||||
textFormat: Text.PlainText
|
||||
width: parent.width * 0.3
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "Balance"
|
||||
text: I18n.tr("Balance")
|
||||
color: root.foreground
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.caption
|
||||
@@ -1568,7 +1578,7 @@ Panel {
|
||||
|
||||
PanelToolTip {
|
||||
visible: tileMouse.containsMouse
|
||||
text: "Start your default agent on a new " + tile.title.toLowerCase()
|
||||
text: I18n.tr("Start your default agent on a new %1", tile.title.toLowerCase())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1772,9 +1782,9 @@ Panel {
|
||||
id: signInLink
|
||||
visible: root.needsSignIn(head.account)
|
||||
picked: head.pickedKind === "signin"
|
||||
text: "Sign-in required"
|
||||
text: I18n.tr("Sign-in required")
|
||||
idleColor: root.urgent
|
||||
tooltip: "Sign in to this account again"
|
||||
tooltip: I18n.tr("Sign in to this account again")
|
||||
onClicked: root.signInAgain(head.owner, head.account)
|
||||
}
|
||||
}
|
||||
@@ -1810,7 +1820,8 @@ Panel {
|
||||
id: headActive
|
||||
visible: head.isActive
|
||||
anchors.right: parent.right
|
||||
text: "ACTIVE"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("ACTIVE")
|
||||
color: Commons.Color.accent
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.caption
|
||||
@@ -1829,19 +1840,19 @@ Panel {
|
||||
|
||||
TextLink {
|
||||
visible: head.autoOn || useHover.hovered || head.picked
|
||||
text: head.pickedKind === "autoswitch" ? "Autoswitch ⏎" : "Autoswitch"
|
||||
text: I18n.tr("Autoswitch") + (head.pickedKind === "autoswitch" ? " ⏎" : "")
|
||||
picked: head.pickedKind === "autoswitch"
|
||||
current: head.autoOn
|
||||
tooltip: head.autoOn
|
||||
? "Stop switching automatically"
|
||||
: "Switch here automatically at " + root.switchThreshold(head.owner) + "%"
|
||||
? I18n.tr("Stop switching automatically")
|
||||
: I18n.tr("Switch here automatically at %1%", root.switchThreshold(head.owner))
|
||||
onClicked: root.setSwitchMode(head.owner, head.autoOn ? "manual" : "auto")
|
||||
}
|
||||
|
||||
// With Autoswitch on, Use waits until the line is hovered or picked.
|
||||
TextLink {
|
||||
visible: !head.autoOn || useHover.hovered || head.picked
|
||||
text: head.pickedKind === "account" ? "Use ⏎" : "Use"
|
||||
text: I18n.tr("Use") + (head.pickedKind === "account" ? " ⏎" : "")
|
||||
picked: head.pickedKind === "account"
|
||||
onClicked: root.useAccount(head.owner, head.account)
|
||||
}
|
||||
@@ -1858,7 +1869,8 @@ Panel {
|
||||
|
||||
Text {
|
||||
id: unavailableLabel
|
||||
text: "Usage unavailable"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("Usage unavailable")
|
||||
color: root.dim
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -1868,7 +1880,7 @@ Panel {
|
||||
|
||||
PanelToolTip {
|
||||
visible: unavailableHover.hovered && unavailable.visible
|
||||
text: unavailable.record ? String(unavailable.record.authHelpText || "Usage has not been updated yet.") : ""
|
||||
text: unavailable.record ? I18n.tr(String(unavailable.record.authHelpText || "Usage has not been updated yet.")) : ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1893,16 +1905,16 @@ Panel {
|
||||
text: {
|
||||
var lines = []
|
||||
if (compact.window) {
|
||||
lines.push(compact.window.title + ": " + Math.round(compact.window.percent * 100) + "% used"
|
||||
+ (compact.resetMs > 0 ? " · resets in " + root.formatDuration(compact.resetMs) : ""))
|
||||
lines.push(I18n.tr("%1: %2% used", root.windowLabel(compact.window.title), Math.round(compact.window.percent * 100))
|
||||
+ (compact.resetMs > 0 ? " · " + I18n.tr("resets in %1", root.formatDuration(compact.resetMs)) : ""))
|
||||
}
|
||||
if (compact.stale)
|
||||
lines.push(compact.fetchedAt > 0 && root.nowMs - compact.fetchedAt > 60000
|
||||
? "Last updated " + root.formatDuration(root.nowMs - compact.fetchedAt) + " ago"
|
||||
: compact.fetchedAt > 0 ? "Last updated less than a minute ago" : "Last updated time unavailable")
|
||||
? I18n.tr("Last updated %1 ago", root.formatDuration(root.nowMs - compact.fetchedAt))
|
||||
: compact.fetchedAt > 0 ? I18n.tr("Last updated less than a minute ago") : I18n.tr("Last updated time unavailable"))
|
||||
for (var i = 0; i < compact.scoped.length; i++)
|
||||
lines.push(compact.scoped[i].title + ": " + Math.round(compact.scoped[i].percent * 100) + "% of its "
|
||||
+ String(compact.window ? compact.window.title : "").toLowerCase() + " allowance")
|
||||
lines.push(I18n.tr("%1: %2% of its %3 allowance", root.windowLabel(compact.scoped[i].title), Math.round(compact.scoped[i].percent * 100),
|
||||
root.windowLabel(compact.window ? compact.window.title : "").toLowerCase()))
|
||||
return lines.join("\n")
|
||||
}
|
||||
}
|
||||
@@ -1912,7 +1924,7 @@ Panel {
|
||||
textFormat: Text.PlainText
|
||||
width: parent.width * 0.3
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: compact.window ? compact.window.title : ""
|
||||
text: compact.window ? root.windowLabel(compact.window.title) : ""
|
||||
color: root.foreground
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
|
||||
@@ -11,8 +11,8 @@ BarIndicator {
|
||||
active: dnd
|
||||
activeText: ""
|
||||
inactiveText: ""
|
||||
activeTooltipText: "Allow Notifications"
|
||||
inactiveTooltipText: "Silence Notifications"
|
||||
activeTooltipText: I18n.tr("Allow Notifications")
|
||||
inactiveTooltipText: I18n.tr("Silence Notifications")
|
||||
|
||||
onPressed: function() {
|
||||
if (root.notificationService) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import QtQuick
|
||||
import qs.Commons
|
||||
import qs.Ui
|
||||
|
||||
BarIndicator {
|
||||
@@ -9,8 +10,8 @@ BarIndicator {
|
||||
active: nightlightService ? nightlightService.enabled : false
|
||||
activeText: ""
|
||||
inactiveText: ""
|
||||
activeTooltipText: "Day Light"
|
||||
inactiveTooltipText: "Night Light"
|
||||
activeTooltipText: I18n.tr("Day Light")
|
||||
inactiveTooltipText: I18n.tr("Night Light")
|
||||
|
||||
function toggle() {
|
||||
if (root.nightlightService) root.nightlightService.setNightlight(!root.active)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Commons
|
||||
import qs.Commons as Commons
|
||||
@@ -13,8 +14,8 @@ BarIndicator {
|
||||
active: granted
|
||||
activeText: ""
|
||||
inactiveText: ""
|
||||
activeTooltipText: "Disable Passwordless Sudo"
|
||||
inactiveTooltipText: "Passwordless Sudo"
|
||||
activeTooltipText: I18n.tr("Disable Passwordless Sudo")
|
||||
inactiveTooltipText: I18n.tr("Passwordless Sudo")
|
||||
useActiveColor: true
|
||||
activeColor: Commons.Color.urgent
|
||||
|
||||
@@ -54,7 +55,7 @@ BarIndicator {
|
||||
command: ["omarchy-sudo-passwordless", "--disable"]
|
||||
onExited: function(exitCode, exitStatus) {
|
||||
if ((exitCode !== 0 || exitStatus !== 0) && root.bar)
|
||||
root.bar.run('omarchy-notification-send "Could not disable passwordless sudo" "Check the sudo configuration and try again."')
|
||||
Quickshell.execDetached([Quickshell.env("OMARCHY_PATH") + "/bin/omarchy-notification-send", I18n.tr("Could not disable passwordless sudo"), I18n.tr("Check the sudo configuration and try again.")])
|
||||
if (root.indicatorHost) root.indicatorHost.refresh()
|
||||
else root.refresh()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import QtQuick
|
||||
import Quickshell.Io
|
||||
import qs.Commons
|
||||
import qs.Ui
|
||||
|
||||
BarIndicator {
|
||||
@@ -10,8 +11,8 @@ BarIndicator {
|
||||
active: recording
|
||||
activeText: ""
|
||||
inactiveText: ""
|
||||
activeTooltipText: "Stop recording"
|
||||
inactiveTooltipText: "Screen Recording"
|
||||
activeTooltipText: I18n.tr("Stop recording")
|
||||
inactiveTooltipText: I18n.tr("Screen Recording")
|
||||
|
||||
function refresh() {
|
||||
if (!root.bar || statusProc.running) return
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import QtQuick
|
||||
import qs.Commons
|
||||
import qs.Ui
|
||||
|
||||
BarIndicator {
|
||||
@@ -9,8 +10,8 @@ BarIndicator {
|
||||
active: idleService ? idleService.stayAwake : false
|
||||
activeText: ""
|
||||
inactiveText: ""
|
||||
activeTooltipText: "Allow Idle Lock & Screensaver"
|
||||
inactiveTooltipText: "Stay Awake"
|
||||
activeTooltipText: I18n.tr("Allow Idle Lock & Screensaver")
|
||||
inactiveTooltipText: I18n.tr("Stay Awake")
|
||||
|
||||
function toggle() {
|
||||
if (root.idleService) root.idleService.setIdleEnabled(root.active)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Services.Pipewire
|
||||
import qs.Commons
|
||||
import qs.Ui
|
||||
import qs.Commons
|
||||
|
||||
@@ -57,7 +58,7 @@ BarWidget {
|
||||
bar: root.bar
|
||||
text: root.muted ? "" : ""
|
||||
active: root.inUse
|
||||
tooltipText: root.muted ? "Microphone muted" : (root.inUse ? "Microphone in use" : "Microphone live")
|
||||
tooltipText: root.muted ? I18n.tr("Microphone muted") : (root.inUse ? I18n.tr("Microphone in use") : I18n.tr("Microphone live"))
|
||||
onPressed: function(b) {
|
||||
if (b === Qt.MiddleButton) root.bar.run("omarchy-shell shell toggle omarchy.audio")
|
||||
else root.toggleMute()
|
||||
|
||||
@@ -58,7 +58,7 @@ BarWidget {
|
||||
bar: root.bar
|
||||
text: "\uf021"
|
||||
slotSize: Style.bar.statusSlot
|
||||
tooltipText: "Pending Omarchy Updates"
|
||||
tooltipText: I18n.tr("Pending Omarchy Updates")
|
||||
onPressed: root.runUpdate()
|
||||
}
|
||||
}
|
||||
@@ -411,7 +411,8 @@ BarWidget {
|
||||
spacing: Style.space(8)
|
||||
|
||||
Text {
|
||||
text: "Tray icons"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("Tray icons")
|
||||
color: root.foreground
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.body
|
||||
@@ -419,7 +420,8 @@ BarWidget {
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Pinned icons stay visible. Hidden icons never show."
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("Pinned icons stay visible. Hidden icons never show.")
|
||||
color: Qt.darker(root.foreground, 1.4)
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.caption
|
||||
@@ -429,7 +431,8 @@ BarWidget {
|
||||
|
||||
Text {
|
||||
visible: root.allItems.length === 0
|
||||
text: "No tray items reporting."
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("No tray items reporting.")
|
||||
color: Qt.darker(root.foreground, 1.5)
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -486,7 +489,7 @@ BarWidget {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
iconText: "\uf08d"
|
||||
text: rowRoot.isPinned ? "Unpin" : "Pin"
|
||||
text: rowRoot.isPinned ? I18n.tr("Unpin") : I18n.tr("Pin")
|
||||
foreground: root.foreground
|
||||
horizontalPadding: 8
|
||||
verticalPadding: 3
|
||||
@@ -501,7 +504,7 @@ BarWidget {
|
||||
anchors.right: rowPinBtn.left
|
||||
anchors.rightMargin: Style.space(6)
|
||||
iconText: "\uf06e"
|
||||
text: rowRoot.isHidden ? "Show" : "Hide"
|
||||
text: rowRoot.isHidden ? I18n.tr("Show") : I18n.tr("Hide")
|
||||
foreground: root.foreground
|
||||
horizontalPadding: 8
|
||||
verticalPadding: 3
|
||||
|
||||
@@ -399,8 +399,8 @@ Item {
|
||||
anchors.fill: parent
|
||||
opened: root.clearConfirmOpen
|
||||
z: 10
|
||||
message: "Delete entire clipboard history?"
|
||||
confirmText: "Delete"
|
||||
message: I18n.tr("Delete entire clipboard history?")
|
||||
confirmText: I18n.tr("Delete")
|
||||
background: root.background
|
||||
foreground: root.foreground
|
||||
scrim: root.scrim
|
||||
@@ -432,7 +432,7 @@ Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: root.filterText || "Search clipboard…"
|
||||
text: root.filterText || I18n.tr("Search clipboard…")
|
||||
color: root.foreground
|
||||
opacity: root.filterText ? 1 : 0.58
|
||||
font.family: root.fontFamily
|
||||
@@ -593,7 +593,7 @@ Item {
|
||||
|
||||
Text {
|
||||
textFormat: Text.PlainText
|
||||
text: root.history.length === 0 ? "Clipboard is empty" : "No matches for “" + root.filterText + "”"
|
||||
text: root.history.length === 0 ? I18n.tr("Clipboard is empty") : I18n.tr("No matches for “%1”", root.filterText)
|
||||
color: root.foreground
|
||||
opacity: 0.7
|
||||
font.family: root.fontFamily
|
||||
|
||||
@@ -247,7 +247,7 @@ Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: root.filterText || "Search emojis…"
|
||||
text: root.filterText || I18n.tr("Search emojis…")
|
||||
color: root.foreground
|
||||
opacity: root.filterText ? 1 : 0.58
|
||||
font.family: root.fontFamily
|
||||
@@ -325,7 +325,7 @@ Item {
|
||||
|
||||
Text {
|
||||
textFormat: Text.PlainText
|
||||
text: "No matches for “" + root.filterText + "”"
|
||||
text: I18n.tr("No matches for “%1”", root.filterText)
|
||||
color: root.foreground
|
||||
opacity: 0.7
|
||||
font.family: root.fontFamily
|
||||
|
||||
@@ -126,7 +126,7 @@ Item {
|
||||
|
||||
function currentLabel() {
|
||||
var path = currentPath()
|
||||
if (!path) return filterText ? "No matches" : ""
|
||||
if (!path) return filterText ? I18n.tr("No matches") : ""
|
||||
|
||||
return labelForPath(path)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ Item {
|
||||
property string passwordText: ""
|
||||
property bool syncingPasswordText: false
|
||||
|
||||
readonly property string placeholderText: "Enter Password"
|
||||
readonly property string placeholderText: I18n.tr("Enter Password")
|
||||
readonly property int fieldWidth: 381
|
||||
readonly property int fieldHeight: 67
|
||||
readonly property int outlineThickness: 3
|
||||
@@ -223,7 +223,7 @@ Item {
|
||||
Text {
|
||||
textFormat: Text.PlainText
|
||||
anchors.fill: passwordInput
|
||||
text: root.authenticatingPassword ? "Checking…" : (root.failureMessage.length > 0 ? root.failureMessage : root.placeholderText)
|
||||
text: root.authenticatingPassword ? I18n.tr("Checking…") : (root.failureMessage.length > 0 ? root.failureMessage : root.placeholderText)
|
||||
visible: passwordInput.text.length === 0
|
||||
color: root.authenticatingPassword ? Commons.Color.lock.text : (root.failureMessage.length > 0 ? Commons.Color.lock.textError : Commons.Color.lock.placeholder)
|
||||
font.family: Style.font.family
|
||||
@@ -266,7 +266,7 @@ Item {
|
||||
anchors.topMargin: 18
|
||||
anchors.horizontalCenter: inputField.horizontalCenter
|
||||
visible: root.fingerprintConfigured && root.fingerprintUnavailable
|
||||
text: "Fingerprint reader unavailable"
|
||||
text: I18n.tr("Fingerprint reader unavailable")
|
||||
color: Commons.Color.lock.textError
|
||||
font.family: Style.font.family
|
||||
font.pixelSize: Style.font.heading
|
||||
|
||||
@@ -361,7 +361,7 @@ Item {
|
||||
enteredPassword = ""
|
||||
pendingPassword = ""
|
||||
failedAttempts += 1
|
||||
failureMessage = "Authentication failed (" + failedAttempts + ")"
|
||||
failureMessage = I18n.tr("Authentication failed (%1)", failedAttempts)
|
||||
runWake()
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ Item {
|
||||
|
||||
function refresh() {
|
||||
defaultMenuFile.reload()
|
||||
localeMenuFile.reload()
|
||||
userMenuFile.reload()
|
||||
return "ok"
|
||||
}
|
||||
@@ -50,7 +51,9 @@ Item {
|
||||
// path doesn't have to shell out to bash + jq on every open.
|
||||
property string defaultMenuPath: omarchyPath + "/default/omarchy/omarchy-menu.jsonc"
|
||||
property string userMenuPath: Quickshell.env("HOME") + "/.config/omarchy/extensions/omarchy-menu.jsonc"
|
||||
property string localeMenuPath: I18n.chinese ? omarchyPath + "/default/omarchy/omarchy-menu.zh-cn.jsonc" : ""
|
||||
property var defaultMenuItems: []
|
||||
property var localeMenuItems: []
|
||||
property var userMenuItems: []
|
||||
property bool opened: false
|
||||
property string mode: "menu"
|
||||
@@ -254,7 +257,7 @@ Item {
|
||||
// on a per-key basis (so the user can tweak label/icon/action without
|
||||
// re-declaring the whole row).
|
||||
function rebuildItemsFromSources() {
|
||||
var mergedMenu = MenuModel.mergeMenuSources(root.defaultMenuItems, root.userMenuItems)
|
||||
var mergedMenu = MenuModel.mergeMenuSources(root.defaultMenuItems, root.localeMenuItems.concat(root.userMenuItems))
|
||||
root.providerRevision += 1
|
||||
root.providersLoaded = ({})
|
||||
root.providerQueue = []
|
||||
@@ -572,8 +575,8 @@ Item {
|
||||
if (root.dmenuMultiple && root.dmenuOnChange.length === 0) {
|
||||
displayModel.append({
|
||||
itemId: "dmenu.apply", disabled: false, kind: "dmenu", icon: "", iconFont: "",
|
||||
appIcon: "", appId: "", label: "Apply", target: "",
|
||||
detail: root.dmenuSelected.length + " selected", path: "", childCount: 0,
|
||||
appIcon: "", appId: "", label: I18n.tr("Apply"), target: "",
|
||||
detail: I18n.tr("%1 selected", root.dmenuSelected.length), path: "", childCount: 0,
|
||||
action: "", provider: "", score: -1, section: ""
|
||||
})
|
||||
}
|
||||
@@ -624,7 +627,7 @@ Item {
|
||||
for (var i = 0; i < displayModel.count; i++) {
|
||||
var row = displayModel.get(i)
|
||||
if (row.itemId === "dmenu.apply") {
|
||||
displayModel.setProperty(i, "detail", root.dmenuSelected.length + " selected")
|
||||
displayModel.setProperty(i, "detail", I18n.tr("%1 selected", root.dmenuSelected.length))
|
||||
} else if (row.kind === "dmenu") {
|
||||
var value = MenuModel.dmenuValue(root.dmenuOptions[Number(row.itemId.substring(6))])
|
||||
displayModel.setProperty(i, "icon", root.dmenuSelected.indexOf(value) !== -1 ? "✓" : "○")
|
||||
@@ -906,7 +909,7 @@ Item {
|
||||
function openDmenu(payload) {
|
||||
requestSerial += 1
|
||||
mode = payload.mode === "input" ? "input" : "select"
|
||||
dmenuPrompt = String(payload.prompt || (mode === "input" ? "Input" : "Select"))
|
||||
dmenuPrompt = String(payload.prompt || (mode === "input" ? I18n.tr("Input") : I18n.tr("Select")))
|
||||
dmenuOptions = Array.isArray(payload.options) ? payload.options : []
|
||||
dmenuMultiple = mode === "select" && payload.multiple === true
|
||||
dmenuOnChange = dmenuMultiple && Array.isArray(payload.onChange)
|
||||
@@ -1084,6 +1087,16 @@ Item {
|
||||
onFileChanged: reload()
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: localeMenuFile
|
||||
path: root.localeMenuPath
|
||||
watchChanges: true
|
||||
printErrors: false
|
||||
onLoaded: { root.localeMenuItems = root.parseMenuJsonc(text()); root.rebuildItemsFromSources() }
|
||||
onLoadFailed: { root.localeMenuItems = []; root.rebuildItemsFromSources() }
|
||||
onFileChanged: reload()
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: userMenuFile
|
||||
path: root.userMenuPath
|
||||
@@ -1279,8 +1292,8 @@ Item {
|
||||
anchors.fill: parent
|
||||
opened: root.deleteConfirmOpen
|
||||
z: 10
|
||||
message: "Do you want to uninstall " + ((root.deleteTarget && root.deleteTarget.label) || "") + "?"
|
||||
confirmText: "Uninstall"
|
||||
message: I18n.tr("Do you want to uninstall %1?", (root.deleteTarget && root.deleteTarget.label) || "")
|
||||
confirmText: I18n.tr("Uninstall")
|
||||
background: root.background
|
||||
foreground: root.foreground
|
||||
scrim: root.scrim
|
||||
@@ -1312,7 +1325,7 @@ Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: root.filterText || (root.dmenuActive ? (root.dmenuPrompt + "…") : ((root.item(root.activeMenu) ? (root.item(root.activeMenu).title || root.item(root.activeMenu).label) : "Go") + "…"))
|
||||
text: root.filterText || (root.dmenuActive ? (root.dmenuPrompt + "…") : ((root.item(root.activeMenu) ? I18n.tr(root.item(root.activeMenu).title || root.item(root.activeMenu).label) : I18n.tr("Go")) + "…"))
|
||||
color: root.foreground
|
||||
opacity: root.filterText ? 1 : 0.58
|
||||
font.family: root.fontFamily
|
||||
@@ -1578,7 +1591,7 @@ Item {
|
||||
|
||||
Text {
|
||||
textFormat: Text.PlainText
|
||||
text: root.filterText ? "No matches for “" + root.filterText + "”" : "Nothing here yet"
|
||||
text: root.filterText ? I18n.tr("No matches for “%1”", root.filterText) : I18n.tr("Nothing here yet")
|
||||
color: root.foreground
|
||||
opacity: 0.7
|
||||
font.family: root.fontFamily
|
||||
|
||||
@@ -58,7 +58,9 @@ function parseMenuJsonc(raw) {
|
||||
for (var id in source) {
|
||||
var entry = source[id]
|
||||
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue
|
||||
out.push(normalizeItem(id, entry))
|
||||
var item = normalizeItem(id, entry)
|
||||
item.declared = Object.keys(entry)
|
||||
out.push(item)
|
||||
}
|
||||
return out
|
||||
}
|
||||
@@ -74,11 +76,24 @@ function mergeMenuSources(defaultItems, userItems) {
|
||||
var entry = src[i]
|
||||
if (!entry || !entry.id) continue
|
||||
if (!nextItems[entry.id]) nextOrder.push(entry.id)
|
||||
var prior = nextItems[entry.id] || {}
|
||||
var prior = nextItems[entry.id]
|
||||
var merged = {}
|
||||
for (var k in prior) merged[k] = prior[k]
|
||||
for (var k2 in entry) merged[k2] = entry[k2]
|
||||
// An override replaces only the fields its file declared.
|
||||
if (prior && entry.declared) {
|
||||
for (var k in prior) merged[k] = prior[k]
|
||||
for (var d = 0; d < entry.declared.length; d++) {
|
||||
var key = entry.declared[d]
|
||||
if (key in entry) merged[key] = entry[key]
|
||||
}
|
||||
if (entry.declared.indexOf("action") >= 0 || entry.declared.indexOf("target") >= 0)
|
||||
merged.kind = merged.action ? "action" : (merged.target ? "link" : "menu")
|
||||
} else {
|
||||
prior = prior || {}
|
||||
for (var k1 in prior) merged[k1] = prior[k1]
|
||||
for (var k2 in entry) merged[k2] = entry[k2]
|
||||
}
|
||||
merged.id = entry.id
|
||||
delete merged.declared
|
||||
nextItems[entry.id] = merged
|
||||
}
|
||||
}
|
||||
@@ -406,7 +421,8 @@ var GUARD_READERS = [
|
||||
"omarchy-dns",
|
||||
"omarchy-hyprland-corners",
|
||||
"omarchy-hyprland-window-transparency",
|
||||
"omarchy-hyprland-workspace-layout-default"
|
||||
"omarchy-hyprland-workspace-layout-default",
|
||||
"omarchy-language"
|
||||
]
|
||||
|
||||
// Package and command presence account for most of what the guards ask, and
|
||||
|
||||
@@ -725,7 +725,7 @@ Item {
|
||||
originalId: -1,
|
||||
app: "omarchy-action",
|
||||
appIcon: "",
|
||||
summary: "No recent notifications",
|
||||
summary: I18n.tr("No recent notifications"),
|
||||
body: "",
|
||||
image: "",
|
||||
glyph: "",
|
||||
|
||||
@@ -200,7 +200,7 @@ Panel {
|
||||
readonly property bool hasOutput: !!(volumeSink && volumeSink.audio)
|
||||
readonly property bool hasInput: !!(source && source.audio) || (inputViaWpctl && UntypedInput.known)
|
||||
readonly property bool anyAudible: (hasOutput && !outputMuted) || (hasInput && !inputMuted)
|
||||
readonly property string toggleHint: anyAudible ? "Mute" : "Unmute"
|
||||
readonly property string toggleHint: anyAudible ? I18n.tr("Mute") : I18n.tr("Unmute")
|
||||
|
||||
readonly property color hoverFill: bar
|
||||
? Style.hoverFillFor(bar.foreground, Commons.Color.accent)
|
||||
@@ -458,7 +458,7 @@ Panel {
|
||||
// panel's brightnessName ladder; bands are wide enough that small
|
||||
// tweaks don't rename the room you're in.
|
||||
function outputVolumeName(volume, muted) {
|
||||
return Model.outputVolumeName(volume, muted)
|
||||
return I18n.tr(Model.outputVolumeName(volume, muted))
|
||||
}
|
||||
|
||||
function setOutputVolume(v) {
|
||||
@@ -813,7 +813,8 @@ Panel {
|
||||
spacing: Style.space(2)
|
||||
|
||||
Text {
|
||||
text: "Audio"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("Audio")
|
||||
color: root.bar.foreground
|
||||
font.family: root.bar.fontFamily
|
||||
font.pixelSize: Style.font.title
|
||||
@@ -855,7 +856,7 @@ Panel {
|
||||
|
||||
PanelSectionHeader {
|
||||
id: outputHeader
|
||||
text: "OUTPUT"
|
||||
text: I18n.tr("OUTPUT")
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
anchors.left: parent.left
|
||||
@@ -942,7 +943,7 @@ Panel {
|
||||
|
||||
PanelSectionHeader {
|
||||
id: microphoneHeader
|
||||
text: "INPUT"
|
||||
text: I18n.tr("INPUT")
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
anchors.left: parent.left
|
||||
@@ -1050,7 +1051,7 @@ Panel {
|
||||
visible: root.displayAudioStreams.length > 0
|
||||
|
||||
PanelSectionHeader {
|
||||
text: "SOURCES"
|
||||
text: I18n.tr("SOURCES")
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
}
|
||||
|
||||
@@ -65,19 +65,19 @@ Panel {
|
||||
|
||||
property int phraseIndex: 0
|
||||
readonly property var activePhrases: [
|
||||
"Untangling wires",
|
||||
"Streaming vikings",
|
||||
"Pairing mysteries",
|
||||
"Herding headsets",
|
||||
"Taming radios",
|
||||
"Summoning speakers",
|
||||
"Wrangling codecs",
|
||||
"Polishing packets"
|
||||
I18n.tr("Untangling wires"),
|
||||
I18n.tr("Streaming vikings"),
|
||||
I18n.tr("Pairing mysteries"),
|
||||
I18n.tr("Herding headsets"),
|
||||
I18n.tr("Taming radios"),
|
||||
I18n.tr("Summoning speakers"),
|
||||
I18n.tr("Wrangling codecs"),
|
||||
I18n.tr("Polishing packets")
|
||||
]
|
||||
readonly property bool rotatingPhrases: adapter && adapter.enabled
|
||||
readonly property string heroStatusText: {
|
||||
if (!adapter) return "No adapter"
|
||||
if (!adapter.enabled) return "Turned Off"
|
||||
if (!adapter) return I18n.tr("No adapter")
|
||||
if (!adapter.enabled) return I18n.tr("Turned Off")
|
||||
return activePhrases[phraseIndex % activePhrases.length]
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ Panel {
|
||||
// sits above the device sections so the adapter can be toggled by keyboard
|
||||
// even when it is off and no device rows exist.
|
||||
readonly property bool headerHasCursor: cursorActive && focusSection === "header"
|
||||
readonly property string toggleHint: root.adapter && root.adapter.enabled ? "Turn Bluetooth off" : "Turn Bluetooth on"
|
||||
readonly property string toggleHint: root.adapter && root.adapter.enabled ? I18n.tr("Turn Bluetooth off") : I18n.tr("Turn Bluetooth on")
|
||||
|
||||
readonly property color hoverFill: bar
|
||||
? Style.hoverFillFor(bar.foreground, Commons.Color.accent)
|
||||
@@ -184,7 +184,7 @@ Panel {
|
||||
var rows = scrollRows
|
||||
if (index < 0 || index >= rows.length) return ""
|
||||
if (index > 0 && rows[index - 1].section === rows[index].section) return ""
|
||||
return rows[index].section === "known" ? "PAIRED" : "AVAILABLE"
|
||||
return rows[index].section === "known" ? I18n.tr("PAIRED") : I18n.tr("AVAILABLE")
|
||||
}
|
||||
|
||||
function audioSinks() {
|
||||
@@ -739,7 +739,8 @@ Panel {
|
||||
spacing: Style.space(2)
|
||||
|
||||
Text {
|
||||
text: "Bluetooth"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("Bluetooth")
|
||||
color: root.bar.foreground
|
||||
font.family: root.bar.fontFamily
|
||||
font.pixelSize: Style.font.title
|
||||
@@ -776,7 +777,7 @@ Panel {
|
||||
spacing: Style.space(10)
|
||||
|
||||
PanelSectionHeader {
|
||||
text: "CONNECTED"
|
||||
text: I18n.tr("CONNECTED")
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
}
|
||||
@@ -868,9 +869,9 @@ Panel {
|
||||
Text {
|
||||
textFormat: Text.PlainText
|
||||
visible: root.connectedDevices.length === 0 && root.scrollRows.length === 0
|
||||
text: !root.adapter ? "No Bluetooth adapter"
|
||||
: !root.adapter.enabled ? "Turn Bluetooth on to scan"
|
||||
: "Scanning for devices…"
|
||||
text: !root.adapter ? I18n.tr("No Bluetooth adapter")
|
||||
: !root.adapter.enabled ? I18n.tr("Turn Bluetooth on to scan")
|
||||
: I18n.tr("Scanning for devices…")
|
||||
color: Qt.darker(root.bar.foreground, 1.5)
|
||||
font.family: root.bar.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -895,9 +896,9 @@ Panel {
|
||||
readonly property string action: root.pendingAction(dev ? dev.address : "")
|
||||
readonly property string actionTooltip: {
|
||||
if (!dev) return ""
|
||||
if (isConnected) return "Disconnect"
|
||||
if (isDiscovered) return "Pair"
|
||||
return "Connect"
|
||||
if (isConnected) return I18n.tr("Disconnect")
|
||||
if (isDiscovered) return I18n.tr("Pair")
|
||||
return I18n.tr("Connect")
|
||||
}
|
||||
|
||||
readonly property bool rowSelected: root.cursorActive && root.focusSection === sectionName && root.selectedIndex === rowIndex
|
||||
@@ -912,13 +913,13 @@ Panel {
|
||||
|
||||
readonly property string statusText: {
|
||||
if (!dev) return ""
|
||||
if (action === "forgetting") return "Forgetting…"
|
||||
if (action === "disconnecting" || devState === 2) return "Disconnecting…"
|
||||
if (action === "forgetting") return I18n.tr("Forgetting…")
|
||||
if (action === "disconnecting" || devState === 2) return I18n.tr("Disconnecting…")
|
||||
if (isConnected) {
|
||||
if (dev.batteryAvailable) return Math.round(dev.battery * 100) + "%"
|
||||
return sectionName === "connected" ? "" : "Connected"
|
||||
return sectionName === "connected" ? "" : I18n.tr("Connected")
|
||||
}
|
||||
if (action === "connecting" || devState === 3 || dev.pairing === true) return "Connecting…"
|
||||
if (action === "connecting" || devState === 3 || dev.pairing === true) return I18n.tr("Connecting…")
|
||||
if (isDiscovered) return ""
|
||||
return ""
|
||||
}
|
||||
@@ -995,7 +996,7 @@ Panel {
|
||||
|
||||
Text {
|
||||
textFormat: Text.PlainText
|
||||
text: root.deviceLabel(row.dev) || "Device"
|
||||
text: root.deviceLabel(row.dev) || I18n.tr("Device")
|
||||
color: root.bar.foreground
|
||||
font.family: root.bar.fontFamily
|
||||
font.pixelSize: Style.font.body
|
||||
@@ -1020,7 +1021,7 @@ Panel {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: row.showForgetButton
|
||||
iconText: ""
|
||||
tooltipText: "Forget"
|
||||
tooltipText: I18n.tr("Forget")
|
||||
foreground: root.bar.foreground
|
||||
hoverColor: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
|
||||
@@ -21,7 +21,7 @@ BarWidget {
|
||||
: setting("format", "dddd HH:mm")
|
||||
readonly property string configuredAltFormat: vertical
|
||||
? setting("verticalFormatAlt", "dd\nMMM\n'W'ww\n''yy")
|
||||
: setting("formatAlt", "d MMMM 'W'ww yyyy")
|
||||
: setting("formatAlt", I18n.chinese ? "yyyy年M月d日 'W'ww" : "d MMMM 'W'ww yyyy")
|
||||
|
||||
readonly property var formatRing: Model.clockFormatRing(configuredFormat, configuredAltFormat, Model.clockFormats(vertical))
|
||||
|
||||
@@ -56,8 +56,10 @@ BarWidget {
|
||||
root.bar.shell.updateEntryInline(root.moduleName, entry)
|
||||
}
|
||||
|
||||
// Qt.formatDateTime is always English; a Chinese session takes day and month names from its locale.
|
||||
function formatted(date) {
|
||||
return Qt.formatDateTime(date, activeFormat.replace(/ww/g, Model.isoWeekLiteral(date.getFullYear(), date.getMonth(), date.getDate())))
|
||||
var format = activeFormat.replace(/ww/g, Model.isoWeekLiteral(date.getFullYear(), date.getMonth(), date.getDate()))
|
||||
return I18n.chinese ? Qt.locale().toString(date, format) : Qt.formatDateTime(date, format)
|
||||
}
|
||||
|
||||
// ---- Calendar popup. Shape contract for shell.summon/hide/toggle
|
||||
@@ -153,7 +155,7 @@ BarWidget {
|
||||
fixedHeight: root.vertical ? root.verticalLines.length * Style.bar.iconSlot : -1
|
||||
horizontalMargin: 8.75
|
||||
verticalPadding: 8.75
|
||||
tooltipText: "Right-click to toggle format"
|
||||
tooltipText: I18n.tr("Right-click to toggle format")
|
||||
|
||||
onPressed: function(b) {
|
||||
if (b === Qt.RightButton) root.cycleFormat()
|
||||
|
||||
@@ -67,10 +67,8 @@ Panel {
|
||||
// convention. Clicking the grid's "W" heading writes the choice back to
|
||||
// shell.json.
|
||||
readonly property int weekStart: Model.normalizedWeekStart(setting("weekStartDay", null), Qt.locale().firstDayOfWeek)
|
||||
// The interface is English throughout, so day names are not taken from the
|
||||
// system locale. Where the week starts still is: that is a regional
|
||||
// convention rather than a translation, and it stays overridable above.
|
||||
readonly property var labelLocale: Qt.locale("en_US")
|
||||
// Day names follow the interface language, not the system locale; the week start above is a regional convention.
|
||||
readonly property var labelLocale: I18n.chinese ? Qt.locale("zh_CN") : Qt.locale("en_US")
|
||||
readonly property string nextWeekStartLabel: labelLocale.dayName(Model.toggledWeekStart(weekStart), Locale.LongFormat)
|
||||
readonly property var weekdays: Model.weekdayOrder(weekStart)
|
||||
readonly property var weeks: Model.monthGrid(viewYear, viewMonth, weekStart, todayKey)
|
||||
@@ -318,7 +316,7 @@ Panel {
|
||||
id: heroDate
|
||||
textFormat: Text.PlainText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: Qt.formatDate(root.today, "MMMM d")
|
||||
text: I18n.chinese ? root.labelLocale.toString(root.today, "M月d日") : Qt.formatDate(root.today, "MMMM d")
|
||||
color: heroMouse.containsMouse
|
||||
? Style.hoverStateColor(root.contentForeground, Commons.Color.accent)
|
||||
: root.contentForeground
|
||||
@@ -341,7 +339,7 @@ Panel {
|
||||
|
||||
PanelToolTip {
|
||||
visible: heroMouse.containsMouse
|
||||
text: "Back to today"
|
||||
text: I18n.tr("Back to today")
|
||||
fontFamily: root.contentFontFamily
|
||||
}
|
||||
}
|
||||
@@ -374,7 +372,8 @@ Panel {
|
||||
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "BORN"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("BORN")
|
||||
color: Qt.darker(root.contentForeground, 1.5)
|
||||
font.family: root.contentFontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -385,7 +384,7 @@ Panel {
|
||||
id: bornField
|
||||
width: Style.space(70)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
placeholderText: "year"
|
||||
placeholderText: I18n.tr("year")
|
||||
foreground: root.contentForeground
|
||||
font.family: root.contentFontFamily
|
||||
inputMethodHints: Qt.ImhDigitsOnly
|
||||
@@ -397,7 +396,8 @@ Panel {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.verticalCenterOffset: 0
|
||||
leftPadding: Style.space(6)
|
||||
text: "LIVE TO"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("LIVE TO")
|
||||
color: Qt.darker(root.contentForeground, 1.5)
|
||||
font.family: root.contentFontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -484,7 +484,8 @@ Panel {
|
||||
id: lifeLabel
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "LIFE"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("LIFE")
|
||||
color: Qt.darker(root.contentForeground, 1.5)
|
||||
font.family: root.contentFontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -603,7 +604,7 @@ Panel {
|
||||
|
||||
PanelToolTip {
|
||||
visible: weekStartMouse.containsMouse
|
||||
text: "Start weeks on " + root.nextWeekStartLabel
|
||||
text: I18n.tr("Start weeks on %1", root.nextWeekStartLabel)
|
||||
fontFamily: root.contentFontFamily
|
||||
}
|
||||
}
|
||||
@@ -726,7 +727,7 @@ Panel {
|
||||
// "MAY 2026" and a "SEPTEMBER 2026".
|
||||
width: Style.space(130)
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: Qt.formatDate(root.viewDate, "MMMM yyyy").toUpperCase()
|
||||
text: I18n.chinese ? root.labelLocale.toString(root.viewDate, "yyyy年M月") : Qt.formatDate(root.viewDate, "MMMM yyyy").toUpperCase()
|
||||
color: Qt.darker(root.contentForeground, 1.4)
|
||||
font.family: root.contentFontFamily
|
||||
font.pixelSize: Style.font.body
|
||||
@@ -740,7 +741,7 @@ Panel {
|
||||
anchors.leftMargin: -Style.space(8)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
iconText: ""
|
||||
tooltipText: "Previous month"
|
||||
tooltipText: I18n.tr("Previous month")
|
||||
foreground: root.contentForeground
|
||||
fontFamily: root.contentFontFamily
|
||||
onClicked: root.moveMonth(-1)
|
||||
@@ -751,7 +752,7 @@ Panel {
|
||||
anchors.rightMargin: -Style.space(8)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
iconText: ""
|
||||
tooltipText: "Next month"
|
||||
tooltipText: I18n.tr("Next month")
|
||||
foreground: root.contentForeground
|
||||
fontFamily: root.contentFontFamily
|
||||
onClicked: root.moveMonth(1)
|
||||
|
||||
@@ -117,7 +117,7 @@ Item {
|
||||
}
|
||||
|
||||
if (!root.expectedStop && exitCode !== 0) {
|
||||
root.error = root.stderrText || "Disk speed test failed"
|
||||
root.error = root.stderrText || I18n.tr("Disk speed test failed")
|
||||
root.phase = ""
|
||||
root.running = false
|
||||
return
|
||||
@@ -133,10 +133,10 @@ Item {
|
||||
fontFamily: Style.font.family
|
||||
layerNamespace: "omarchy-disk-speedtest"
|
||||
title: root.diskName
|
||||
leftLabel: "READ"
|
||||
rightLabel: "WRITE"
|
||||
leftLabel: I18n.tr("READ")
|
||||
rightLabel: I18n.tr("WRITE")
|
||||
unit: "MB/s"
|
||||
runAgainTooltip: "Measure again"
|
||||
runAgainTooltip: I18n.tr("Measure again")
|
||||
running: root.running
|
||||
leftValue: root.toRate(root.readMBps)
|
||||
rightValue: root.toRate(root.writeMBps)
|
||||
|
||||
@@ -21,16 +21,16 @@ Panel {
|
||||
property int phraseIndex: 0
|
||||
|
||||
readonly property var activePhrases: [
|
||||
"Filing files",
|
||||
"Distributing data",
|
||||
"Shuffling folders",
|
||||
"Boxing bytes",
|
||||
"Sorting stuff",
|
||||
"Syncing secrets",
|
||||
"Packing packets",
|
||||
"Moving memories",
|
||||
"Wrangling revisions",
|
||||
"Cataloging chaos"
|
||||
I18n.tr("Filing files"),
|
||||
I18n.tr("Distributing data"),
|
||||
I18n.tr("Shuffling folders"),
|
||||
I18n.tr("Boxing bytes"),
|
||||
I18n.tr("Sorting stuff"),
|
||||
I18n.tr("Syncing secrets"),
|
||||
I18n.tr("Packing packets"),
|
||||
I18n.tr("Moving memories"),
|
||||
I18n.tr("Wrangling revisions"),
|
||||
I18n.tr("Cataloging chaos")
|
||||
]
|
||||
readonly property string heroPhraseText: activePhrases[phraseIndex % activePhrases.length]
|
||||
readonly property color foreground: bar ? bar.foreground : Commons.Color.foreground
|
||||
@@ -38,7 +38,14 @@ Panel {
|
||||
readonly property color dim: Qt.darker(foreground, 1.55)
|
||||
readonly property string fontFamily: bar ? bar.fontFamily : Style.font.family
|
||||
readonly property color iconColor: dropbox.authenticated && dropbox.active ? foreground : dim
|
||||
readonly property string toggleHint: dropbox.active ? "Pause syncing" : "Resume syncing"
|
||||
// Model.fileMeta reads "5m ago · Folder"; the age is translated, the folder name kept.
|
||||
function fileMetaText(file) {
|
||||
var parts = Model.fileMeta(file).split(" · ")
|
||||
parts[0] = I18n.trMatch(parts[0], ["Just now", "Unknown time", "%1mo ago", "%1m ago", "%1h ago", "%1d ago", "%1y ago"])
|
||||
return parts.join(" · ")
|
||||
}
|
||||
|
||||
readonly property string toggleHint: dropbox.active ? I18n.tr("Pause syncing") : I18n.tr("Resume syncing")
|
||||
readonly property color barIconColor: dropbox.authenticated && dropbox.active ? barForeground : Qt.darker(barForeground, 1.55)
|
||||
// Only claim the header cursor when the switch is actually on screen —
|
||||
// "header" stays navigable, but an absent CLI leaves nothing to highlight.
|
||||
@@ -247,7 +254,7 @@ Panel {
|
||||
id: hero
|
||||
width: parent.width
|
||||
title: "Dropbox"
|
||||
meta: dropbox.active ? root.heroPhraseText : "Syncing paused"
|
||||
meta: dropbox.active ? root.heroPhraseText : I18n.tr("Syncing paused")
|
||||
foreground: root.foreground
|
||||
fontFamily: root.fontFamily
|
||||
iconOpacity: dropbox.active ? 1.0 : 0.5
|
||||
@@ -287,7 +294,7 @@ Panel {
|
||||
textFormat: Text.PlainText
|
||||
visible: dropbox.actionStatus !== "" || dropbox.lastError !== ""
|
||||
width: parent.width
|
||||
text: dropbox.actionStatus !== "" ? dropbox.actionStatus : dropbox.lastError
|
||||
text: I18n.tr(dropbox.actionStatus !== "" ? dropbox.actionStatus : dropbox.lastError)
|
||||
color: dropbox.lastError !== "" && dropbox.actionStatus === "" ? root.urgent : root.dim
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -307,7 +314,7 @@ Panel {
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Style.spacing.labelGap
|
||||
InfoPair { label: "Stored"; value: Model.usageText(dropbox.usedBytes, dropbox.quotaBytes, dropbox.quotaKnown) }
|
||||
InfoPair { label: I18n.tr("Stored"); value: I18n.trMatch(Model.usageText(dropbox.usedBytes, dropbox.quotaBytes, dropbox.quotaKnown), ["%1 of %2"]) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,7 +329,7 @@ Panel {
|
||||
spacing: Style.space(10)
|
||||
|
||||
PanelSectionHeader {
|
||||
text: "RECENT FILES"
|
||||
text: I18n.tr("RECENT FILES")
|
||||
foreground: root.foreground
|
||||
fontFamily: root.fontFamily
|
||||
}
|
||||
@@ -330,7 +337,8 @@ Panel {
|
||||
Text {
|
||||
visible: dropbox.files.length === 0
|
||||
width: parent.width
|
||||
text: "No synced files found."
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("No synced files found.")
|
||||
color: root.dim
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.body
|
||||
@@ -427,7 +435,7 @@ Panel {
|
||||
Text {
|
||||
textFormat: Text.PlainText
|
||||
Layout.fillWidth: true
|
||||
text: dropbox.installed ? "Login to Dropbox" : "Dropbox CLI is not installed"
|
||||
text: dropbox.installed ? I18n.tr("Login to Dropbox") : I18n.tr("Dropbox CLI is not installed")
|
||||
color: root.foreground
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.body
|
||||
@@ -437,7 +445,7 @@ Panel {
|
||||
Text {
|
||||
textFormat: Text.PlainText
|
||||
Layout.fillWidth: true
|
||||
text: dropbox.installed ? "Start the authentication flow" : "Install Dropbox from the service menu"
|
||||
text: dropbox.installed ? I18n.tr("Start the authentication flow") : I18n.tr("Install Dropbox from the service menu")
|
||||
color: root.dim
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.caption
|
||||
@@ -460,7 +468,7 @@ Panel {
|
||||
id: fileRow
|
||||
property var file: null
|
||||
property int rowIndex: 0
|
||||
readonly property string fileName: file ? String(file.name || "Untitled") : "Untitled"
|
||||
readonly property string fileName: file ? String(file.name || I18n.tr("Untitled")) : I18n.tr("Untitled")
|
||||
|
||||
hasCursor: root.cursorActive && root.focusSection === "files" && root.fileIndex === rowIndex
|
||||
foreground: root.foreground
|
||||
@@ -510,7 +518,7 @@ Panel {
|
||||
Text {
|
||||
textFormat: Text.PlainText
|
||||
Layout.fillWidth: true
|
||||
text: Model.fileMeta(fileRow.file)
|
||||
text: root.fileMetaText(fileRow.file)
|
||||
color: root.dim
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.caption
|
||||
|
||||
@@ -73,7 +73,7 @@ Column {
|
||||
width: parent.width
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
topPadding: Style.spacing.md
|
||||
text: list.citySearch.loading ? list.citySearch.loadingText : "No matches"
|
||||
text: list.citySearch.loading ? list.citySearch.loadingText : I18n.tr("No matches")
|
||||
color: list.citySearch.fainter
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,16 @@ import "Greetings.js" as Greet
|
||||
Rectangle {
|
||||
id: row
|
||||
|
||||
// Model.formatDate reads "Tue Oct 6"; a Chinese session reads 10月6日 周二.
|
||||
function dateText(date) {
|
||||
var match = String(date).match(/^(\w{3}) (\w{3}) (\d+)$/)
|
||||
if (!I18n.chinese || !match) return date
|
||||
var month = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"].indexOf(match[2]) + 1
|
||||
var weekday = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"].indexOf(match[1])
|
||||
if (month < 1 || weekday < 0) return date
|
||||
return month + "月" + match[3] + "日 " + ["周日", "周一", "周二", "周三", "周四", "周五", "周六"][weekday]
|
||||
}
|
||||
|
||||
required property var modelData
|
||||
required property int index
|
||||
// The owning Panel: the row reads its clock, facts and drag state.
|
||||
@@ -223,7 +233,7 @@ Rectangle {
|
||||
Behavior on opacity { NumberAnimation { duration: Style.duration(110) } }
|
||||
|
||||
Caption {
|
||||
text: row.ready ? row.rowData.date : "\u2026"
|
||||
text: row.ready ? row.dateText(row.rowData.date) : "\u2026"
|
||||
color: row.ready && row.rowData.dayLabel !== "" ? row.dim : row.fainter
|
||||
}
|
||||
|
||||
@@ -234,7 +244,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
Caption {
|
||||
text: row.ready ? row.rowData.dayLabel : ""
|
||||
text: row.ready ? I18n.trMatch(row.rowData.dayLabel, ["Tomorrow", "Yesterday", "+%1 days", "%1 days"]) : ""
|
||||
visible: text !== ""
|
||||
}
|
||||
}
|
||||
@@ -301,7 +311,7 @@ Rectangle {
|
||||
color: Model.mix(Commons.Color.popups.background, row.foreground, _hot ? 0.24 : 0.14)
|
||||
borderSpec: Border.flat(Model.mix(Commons.Color.popups.background, row.foreground, _hot ? 0.65 : 0.35), Style.space(1))
|
||||
iconText: "\u00d7"
|
||||
tooltipText: "Remove"
|
||||
tooltipText: I18n.tr("Remove")
|
||||
foreground: row.dim
|
||||
hoverColor: row.foreground
|
||||
fontFamily: row.fontFamily
|
||||
|
||||
@@ -17,9 +17,9 @@ Column {
|
||||
// Zone id -> offset text; read inside a binding, so its dependencies track.
|
||||
property var offsetLabel: function(zoneId) { return "" }
|
||||
property bool loading: false
|
||||
property string buttonText: "+ Add a city"
|
||||
property string placeholderText: "Search cities\u2026"
|
||||
property string loadingText: "Loading zones\u2026"
|
||||
property string buttonText: "+ " + I18n.tr("Add a city")
|
||||
property string placeholderText: I18n.tr("Search cities…")
|
||||
property string loadingText: I18n.tr("Loading zones…")
|
||||
property real fontSize: Style.font.bodySmall
|
||||
property color foreground: Commons.Color.foreground
|
||||
property color dim: Qt.darker(foreground, 1.55)
|
||||
|
||||
@@ -66,8 +66,8 @@ Item {
|
||||
var out = []
|
||||
var up = Sun.eventMark(sun.riseMinutes)
|
||||
var down = Sun.eventMark(sun.setMinutes)
|
||||
if (up !== null) out.push({ x: up, minutes: sun.riseMinutes, rising: true, name: "Sunrise" })
|
||||
if (down !== null) out.push({ x: down, minutes: sun.setMinutes, rising: false, name: "Sunset" })
|
||||
if (up !== null) out.push({ x: up, minutes: sun.riseMinutes, rising: true, name: I18n.tr("Sunrise") })
|
||||
if (down !== null) out.push({ x: down, minutes: sun.setMinutes, rising: false, name: I18n.tr("Sunset") })
|
||||
return out
|
||||
}
|
||||
|
||||
|
||||
@@ -585,8 +585,8 @@ Item {
|
||||
limit: 5
|
||||
inlineResults: false
|
||||
loading: root.jumpOptions.length === 0
|
||||
buttonText: "Jump to a city"
|
||||
loadingText: "Loading cities\u2026"
|
||||
buttonText: I18n.tr("Jump to a city")
|
||||
loadingText: I18n.tr("Loading cities…")
|
||||
offsetLabel: function(zoneId) { return Model.utcOffsetLabel(root.offsets[zoneId]) }
|
||||
foreground: root.foreground
|
||||
dim: root.dim
|
||||
|
||||
@@ -73,7 +73,7 @@ Column {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Style.space(9)
|
||||
|
||||
TitleWord { text: "World" }
|
||||
TitleWord { text: I18n.tr("World") }
|
||||
|
||||
Item {
|
||||
id: heroIcon
|
||||
@@ -151,7 +151,7 @@ Column {
|
||||
}
|
||||
}
|
||||
|
||||
TitleWord { text: "Clock" }
|
||||
TitleWord { text: I18n.tr("Clock") }
|
||||
}
|
||||
|
||||
component TitleWord: Text {
|
||||
|
||||
@@ -335,8 +335,8 @@ Panel {
|
||||
}
|
||||
|
||||
// No full stop: a period hanging off the arc reads as a speck.
|
||||
readonly property string hereLine: "It's " + localTime + " here"
|
||||
+ (homeCity !== "" ? " in " + homeCity : "")
|
||||
readonly property string hereLine: I18n.tr("It's %1 here", localTime)
|
||||
+ (homeCity !== "" ? I18n.tr(" in %1", homeCity) : "")
|
||||
+ (scrubLabel !== "" ? " " + scrubLabel : "")
|
||||
|
||||
// A capital's line box has empty space above it; the row's top pad drops by it.
|
||||
@@ -715,7 +715,7 @@ Panel {
|
||||
bar: root.bar
|
||||
slotSize: Style.bar.statusSlot
|
||||
text: ""
|
||||
tooltipText: "World clock"
|
||||
tooltipText: I18n.tr("World clock")
|
||||
onPressed: function(buttonCode) {
|
||||
if (buttonCode === Qt.RightButton || buttonCode === Qt.MiddleButton) root.refresh()
|
||||
else root.toggle()
|
||||
|
||||
@@ -556,7 +556,8 @@ Panel {
|
||||
spacing: Style.space(2)
|
||||
|
||||
Text {
|
||||
text: "Display"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("Display")
|
||||
color: root.bar.foreground
|
||||
font.family: root.bar.fontFamily
|
||||
font.pixelSize: Style.font.title
|
||||
@@ -570,9 +571,9 @@ Panel {
|
||||
textFormat: Text.PlainText
|
||||
text: {
|
||||
if (root.brightnessAvailable) {
|
||||
return root.brightnessName(brightnessSlider.dragging ? brightnessSlider.liveValue : root.brightnessPercent).toUpperCase()
|
||||
return I18n.tr(root.brightnessName(brightnessSlider.dragging ? brightnessSlider.liveValue : root.brightnessPercent)).toUpperCase()
|
||||
}
|
||||
return "FIXED BRIGHTNESS"
|
||||
return I18n.tr("FIXED BRIGHTNESS")
|
||||
}
|
||||
color: Qt.darker(root.bar.foreground, 1.4)
|
||||
font.family: root.bar.fontFamily
|
||||
@@ -602,7 +603,7 @@ Panel {
|
||||
|
||||
PanelSectionHeader {
|
||||
id: brightnessHeader
|
||||
text: "BRIGHTNESS"
|
||||
text: I18n.tr("BRIGHTNESS")
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
anchors.left: parent.left
|
||||
@@ -675,7 +676,7 @@ Panel {
|
||||
|
||||
PanelSectionHeader {
|
||||
id: textSizeHeader
|
||||
text: "TEXT SIZE"
|
||||
text: I18n.tr("TEXT SIZE")
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
anchors.left: parent.left
|
||||
@@ -747,7 +748,7 @@ Panel {
|
||||
|
||||
PanelSectionHeader {
|
||||
id: scaleHeader
|
||||
text: "SCALE"
|
||||
text: I18n.tr("SCALE")
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
anchors.left: parent.left
|
||||
@@ -809,7 +810,7 @@ Panel {
|
||||
visible: root.displays.length > 1
|
||||
|
||||
PanelSectionHeader {
|
||||
text: "DISPLAYS"
|
||||
text: I18n.tr("DISPLAYS")
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
}
|
||||
@@ -900,7 +901,7 @@ Panel {
|
||||
|
||||
Text {
|
||||
textFormat: Text.PlainText
|
||||
text: monitorRow.display.name + (monitorRow.display.focused ? " · focused" : "")
|
||||
text: monitorRow.display.name + (monitorRow.display.focused ? " · " + I18n.tr("focused") : "")
|
||||
color: root.bar.foreground
|
||||
font.family: root.bar.fontFamily
|
||||
font.pixelSize: Style.font.body
|
||||
|
||||
@@ -57,13 +57,13 @@ Panel {
|
||||
readonly property bool hasTransferStats: info.rx_bytes !== undefined
|
||||
property int connectionPhraseIndex: 0
|
||||
readonly property var connectionPhrases: [
|
||||
"Wiring bits",
|
||||
"Handling packets",
|
||||
"Sorting frames",
|
||||
"Hauling bytes",
|
||||
"Routing crumbs",
|
||||
"Counting collisions",
|
||||
"Bending light",
|
||||
I18n.tr("Wiring bits"),
|
||||
I18n.tr("Handling packets"),
|
||||
I18n.tr("Sorting frames"),
|
||||
I18n.tr("Hauling bytes"),
|
||||
I18n.tr("Routing crumbs"),
|
||||
I18n.tr("Counting collisions"),
|
||||
I18n.tr("Bending light"),
|
||||
]
|
||||
readonly property string connectionPhrase: connectionPhrases[connectionPhraseIndex % connectionPhrases.length]
|
||||
readonly property bool networkManagerAvailable: Networking.backend === NetworkBackendType.NetworkManager
|
||||
@@ -138,7 +138,7 @@ Panel {
|
||||
readonly property bool qrHeaderHasCursor: cursorActive && focusSection === "header" && headerIndex === qrHeaderIndex
|
||||
readonly property bool speedHeaderHasCursor: cursorActive && focusSection === "header" && headerIndex === speedHeaderIndex
|
||||
readonly property bool toggleHeaderHasCursor: cursorActive && focusSection === "header" && headerIndex === toggleHeaderIndex
|
||||
readonly property string toggleHint: Networking.wifiEnabled ? "Turn Wi-Fi off" : "Turn Wi-Fi on"
|
||||
readonly property string toggleHint: Networking.wifiEnabled ? I18n.tr("Turn Wi-Fi off") : I18n.tr("Turn Wi-Fi on")
|
||||
readonly property var dnsProviders: ["DHCP", "Cloudflare", "Google", "Custom"]
|
||||
property int dnsIndex: 0
|
||||
// ["2.4", "5", ...], or empty when there is nothing to choose between.
|
||||
@@ -160,7 +160,10 @@ Panel {
|
||||
// Under Automatic there is nothing to pick, so the pills collapse away and
|
||||
// the header states the live band instead.
|
||||
readonly property bool bandPillsVisible: canSelectBand && bandPinned
|
||||
readonly property string bandSectionTitle: Model.bandSectionTitle(bandEffective, bandCurrent)
|
||||
readonly property string bandSectionTitle: {
|
||||
var title = Model.bandSectionTitle(bandEffective, bandCurrent)
|
||||
return title.indexOf("WI-FI BAND: ") === 0 ? I18n.tr("WI-FI BAND: %1", title.slice(12)) : I18n.tr(title)
|
||||
}
|
||||
readonly property bool bandBusy: pendingBand !== ""
|
||||
// The speed test needs an interface to test, so its hero action only
|
||||
// appears once there is one.
|
||||
@@ -280,11 +283,12 @@ Panel {
|
||||
}
|
||||
|
||||
function bandLabel(band) {
|
||||
return Model.bandLabel(band)
|
||||
return I18n.tr(Model.bandLabel(band))
|
||||
}
|
||||
|
||||
function bandTooltip(band) {
|
||||
return Model.bandTooltip(band)
|
||||
var tip = Model.bandTooltip(band)
|
||||
return tip.indexOf("Stay on ") === 0 ? I18n.tr("Stay on %1", bandLabel(band)) : I18n.tr(tip)
|
||||
}
|
||||
|
||||
// Single cursor model: exactly one highlighted spot across the whole
|
||||
@@ -663,7 +667,7 @@ Panel {
|
||||
}
|
||||
|
||||
function formatPingLatency(ms) {
|
||||
return Model.formatPingLatency(ms, hasInternetPing)
|
||||
return I18n.tr(Model.formatPingLatency(ms, hasInternetPing))
|
||||
}
|
||||
|
||||
function formatPacketLoss(percent) {
|
||||
@@ -710,7 +714,7 @@ Panel {
|
||||
}
|
||||
|
||||
function wifiSectionTitle(index) {
|
||||
return Model.wifiSectionTitle(wifiNetworks, index)
|
||||
return I18n.tr(Model.wifiSectionTitle(wifiNetworks, index))
|
||||
}
|
||||
|
||||
function wifiIconFor(strength) {
|
||||
@@ -755,7 +759,7 @@ Panel {
|
||||
cancelPasswordPrompt()
|
||||
var connection = ""
|
||||
if (info.type === "wifi") connection = info.ssid || "Wi-Fi"
|
||||
else if (info.type === "ethernet") connection = "Ethernet"
|
||||
else if (info.type === "ethernet") connection = I18n.tr("Ethernet")
|
||||
bar.shell.summon("omarchy.speedtest", connection ? JSON.stringify({ connection: connection }) : "{}")
|
||||
}
|
||||
|
||||
@@ -836,7 +840,7 @@ Panel {
|
||||
if (!network || actionKind === "" || actionSsid !== (network.name || "")) return
|
||||
actionTimeout.stop()
|
||||
failureSsid = actionSsid
|
||||
failureReason = networkFailureReason(reason, requiresCredentials(network.security))
|
||||
failureReason = I18n.tr(networkFailureReason(reason, requiresCredentials(network.security)))
|
||||
actionSsid = ""
|
||||
actionKind = ""
|
||||
refresh()
|
||||
@@ -1063,9 +1067,9 @@ Panel {
|
||||
onTriggered: {
|
||||
if (!root.actionKind) return
|
||||
var reason
|
||||
if (root.actionKind === "connect") reason = "Timed out connecting"
|
||||
else if (root.actionKind === "disconnect") reason = "Timed out disconnecting"
|
||||
else reason = "Timed out forgetting"
|
||||
if (root.actionKind === "connect") reason = I18n.tr("Timed out connecting")
|
||||
else if (root.actionKind === "disconnect") reason = I18n.tr("Timed out disconnecting")
|
||||
else reason = I18n.tr("Timed out forgetting")
|
||||
root.failureSsid = root.actionSsid
|
||||
root.failureReason = reason
|
||||
root.actionSsid = ""
|
||||
@@ -1080,8 +1084,8 @@ Panel {
|
||||
bar: root.bar
|
||||
text: root.icon
|
||||
active: root.restricted
|
||||
tooltipText: root.hasCaptivePortal ? "Sign in to this network"
|
||||
: (root.restricted ? "Limited internet access" : "")
|
||||
tooltipText: root.hasCaptivePortal ? I18n.tr("Sign in to this network")
|
||||
: (root.restricted ? I18n.tr("Limited internet access") : "")
|
||||
|
||||
onPressed: function(b) {
|
||||
if (root.opened) root.close()
|
||||
@@ -1250,7 +1254,7 @@ Panel {
|
||||
id: qrAction
|
||||
visible: root.canShareWifi
|
||||
iconText: ""
|
||||
tooltipText: "Show QR code"
|
||||
tooltipText: I18n.tr("Show QR code")
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
fontSize: Style.font.subtitle * 1.5
|
||||
@@ -1264,7 +1268,7 @@ Panel {
|
||||
id: speedAction
|
||||
visible: root.canRunSpeedTest
|
||||
iconText: ""
|
||||
tooltipText: "Run a speed test"
|
||||
tooltipText: I18n.tr("Run a speed test")
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
fontSize: Style.font.subtitle * 1.5
|
||||
@@ -1313,8 +1317,8 @@ Panel {
|
||||
// SSID even before route/details polling has returned anything.
|
||||
if (root.kind === "wifi" && root.connectedWifiNetwork) return root.connectedWifiNetwork.name || "Wi-Fi"
|
||||
if (root.info.type === "wifi") return root.info.ssid || "Wi-Fi"
|
||||
if (root.info.type === "ethernet") return "Ethernet"
|
||||
return root.info.iface || (root.kind === "disconnected" ? "Disconnected" : "No connection")
|
||||
if (root.info.type === "ethernet") return I18n.tr("Ethernet")
|
||||
return root.info.iface || (root.kind === "disconnected" ? I18n.tr("Disconnected") : I18n.tr("No connection"))
|
||||
}
|
||||
readonly property string detail: root.headerDetail()
|
||||
|
||||
@@ -1331,15 +1335,15 @@ Panel {
|
||||
textFormat: Text.PlainText
|
||||
width: parent.width
|
||||
text: {
|
||||
if (root.hasCaptivePortal) return "SIGN-IN REQUIRED"
|
||||
if (root.restricted) return "LIMITED INTERNET ACCESS"
|
||||
if (root.hasCaptivePortal) return I18n.tr("SIGN-IN REQUIRED")
|
||||
if (root.restricted) return I18n.tr("LIMITED INTERNET ACCESS")
|
||||
if (root.info.type === "wifi") {
|
||||
if (root.canDisconnect) return root.connectionPhrase.toUpperCase()
|
||||
if (root.kind === "disconnected") return "NOT CONNECTED"
|
||||
if (root.kind === "disconnected") return I18n.tr("NOT CONNECTED")
|
||||
return ""
|
||||
}
|
||||
if (root.info.type === "ethernet") return root.connectionPhrase.toUpperCase()
|
||||
if (root.kind === "disconnected") return "NOT CONNECTED"
|
||||
if (root.kind === "disconnected") return I18n.tr("NOT CONNECTED")
|
||||
return ""
|
||||
}
|
||||
visible: text !== ""
|
||||
@@ -1362,7 +1366,7 @@ Panel {
|
||||
Button {
|
||||
id: portalAction
|
||||
width: parent.width
|
||||
text: "Open Captive Portal"
|
||||
text: I18n.tr("Open Captive Portal")
|
||||
iconText: ""
|
||||
foreground: root.bar.urgent
|
||||
accent: root.bar.urgent
|
||||
@@ -1381,7 +1385,7 @@ Panel {
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
text: "Sign in or accept this network’s terms to access the internet."
|
||||
text: I18n.tr("Sign in or accept this network’s terms to access the internet.")
|
||||
textFormat: Text.PlainText
|
||||
wrapMode: Text.WordWrap
|
||||
color: root.bar.foreground
|
||||
@@ -1407,38 +1411,38 @@ Panel {
|
||||
// opened, once the first probe returned, shoving everything below
|
||||
// them down. They now hold their place and read "--" until there is
|
||||
// a sample.
|
||||
InfoLabel { text: "Ping" }
|
||||
InfoLabel { text: I18n.tr("Ping") }
|
||||
DetailValue {
|
||||
text: root.formatPingLatency(root.internetPingLatency)
|
||||
color: root.internetPingPacketLoss > 0 ? root.bar.urgent : root.bar.foreground
|
||||
}
|
||||
InfoLabel { text: "Packet Loss" }
|
||||
InfoLabel { text: I18n.tr("Packet Loss") }
|
||||
DetailValue {
|
||||
text: root.formatPacketLoss(root.internetPingPacketLoss)
|
||||
color: root.internetPingPacketLoss > 0 ? root.bar.urgent : root.bar.foreground
|
||||
}
|
||||
|
||||
InfoLabel { text: "Receiving" }
|
||||
InfoLabel { text: I18n.tr("Receiving") }
|
||||
DetailValue { text: root.hasTransferStats ? root.formatRate(root.downloadRate) : "--" }
|
||||
InfoLabel { text: "Sending" }
|
||||
InfoLabel { text: I18n.tr("Sending") }
|
||||
DetailValue { text: root.hasTransferStats ? root.formatRate(root.uploadRate) : "--" }
|
||||
|
||||
InfoLabel { text: "Downloaded" }
|
||||
InfoLabel { text: I18n.tr("Downloaded") }
|
||||
DetailValue { text: root.hasTransferStats ? root.formatBytes(parseFloat(root.info.rx_bytes || "0")) : "--" }
|
||||
InfoLabel { text: "Uploaded" }
|
||||
InfoLabel { text: I18n.tr("Uploaded") }
|
||||
DetailValue { text: root.hasTransferStats ? root.formatBytes(parseFloat(root.info.tx_bytes || "0")) : "--" }
|
||||
|
||||
InfoLabel { text: "IP Address" }
|
||||
InfoLabel { text: I18n.tr("IP Address") }
|
||||
DetailValue {
|
||||
text: root.info.ip || "--"
|
||||
copyable: !!root.info.ip
|
||||
tooltipText: "Copy IP"
|
||||
tooltipText: I18n.tr("Copy IP")
|
||||
}
|
||||
InfoLabel { text: "Gateway" }
|
||||
InfoLabel { text: I18n.tr("Gateway") }
|
||||
DetailValue {
|
||||
text: root.info.gateway || "--"
|
||||
copyable: !!root.info.gateway
|
||||
tooltipText: "Copy gateway"
|
||||
tooltipText: I18n.tr("Copy gateway")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1479,7 +1483,7 @@ Panel {
|
||||
|
||||
PanelSectionHeader {
|
||||
id: bandAutoLabel
|
||||
text: "AUTOMATIC"
|
||||
text: I18n.tr("AUTOMATIC")
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -1512,8 +1516,8 @@ Panel {
|
||||
PanelToolTip {
|
||||
visible: bandAutoSwitch.containsMouse
|
||||
text: root.bandPinned
|
||||
? "Let Wi-Fi pick the band"
|
||||
: "Stay on " + root.bandLabel(root.bandCurrent)
|
||||
? I18n.tr("Let Wi-Fi pick the band")
|
||||
: I18n.tr("Stay on %1", root.bandLabel(root.bandCurrent))
|
||||
fontFamily: root.bar.fontFamily
|
||||
}
|
||||
}
|
||||
@@ -1584,7 +1588,7 @@ Panel {
|
||||
spacing: Style.space(10)
|
||||
|
||||
PanelSectionHeader {
|
||||
text: "DNS PROVIDER"
|
||||
text: I18n.tr("DNS PROVIDER")
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
}
|
||||
@@ -1600,7 +1604,7 @@ Panel {
|
||||
DnsProviderPill {
|
||||
provider: "DHCP"
|
||||
index: 0
|
||||
tooltipText: "Use DNS from DHCP"
|
||||
tooltipText: I18n.tr("Use DNS from DHCP")
|
||||
width: dnsRow.cellWidth
|
||||
onClicked: root.setDns(provider)
|
||||
}
|
||||
@@ -1608,7 +1612,7 @@ Panel {
|
||||
DnsProviderPill {
|
||||
provider: "Cloudflare"
|
||||
index: 1
|
||||
tooltipText: "Set DNS to Cloudflare"
|
||||
tooltipText: I18n.tr("Set DNS to %1", "Cloudflare")
|
||||
width: dnsRow.cellWidth
|
||||
onClicked: root.setDns(provider)
|
||||
}
|
||||
@@ -1616,7 +1620,7 @@ Panel {
|
||||
DnsProviderPill {
|
||||
provider: "Google"
|
||||
index: 2
|
||||
tooltipText: "Set DNS to Google"
|
||||
tooltipText: I18n.tr("Set DNS to %1", "Google")
|
||||
width: dnsRow.cellWidth
|
||||
onClicked: root.setDns(provider)
|
||||
}
|
||||
@@ -1624,7 +1628,7 @@ Panel {
|
||||
DnsProviderPill {
|
||||
provider: "Custom"
|
||||
index: 3
|
||||
tooltipText: "Set custom DNS servers"
|
||||
tooltipText: I18n.tr("Set custom DNS servers")
|
||||
width: dnsRow.cellWidth
|
||||
onClicked: root.setDns(provider)
|
||||
}
|
||||
@@ -1640,7 +1644,7 @@ Panel {
|
||||
|
||||
PanelSectionHeader {
|
||||
visible: root.wifiStationAvailable && root.scanning
|
||||
text: "SCANNING WI-FI…"
|
||||
text: I18n.tr("SCANNING WI-FI…")
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
}
|
||||
@@ -1743,7 +1747,7 @@ Panel {
|
||||
required property string provider
|
||||
required property int index
|
||||
|
||||
text: provider
|
||||
text: I18n.tr(provider)
|
||||
fontSize: Style.font.bodySmall
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
@@ -1826,12 +1830,12 @@ Panel {
|
||||
readonly property string statusText: {
|
||||
if (!net) return ""
|
||||
if (isPasswordOpen) return ""
|
||||
if (isBusy && root.actionKind === "connect") return "Connecting…"
|
||||
if (isBusy && root.actionKind === "disconnect") return "Disconnecting…"
|
||||
if (isBusy && root.actionKind === "forget") return "Forgetting…"
|
||||
if (isFailed) return root.failureReason || "Failed"
|
||||
if (isConnected && root.kind === "wifi" && root.hasCaptivePortal) return "Sign-in required"
|
||||
if (isConnected) return "Connected"
|
||||
if (isBusy && root.actionKind === "connect") return I18n.tr("Connecting…")
|
||||
if (isBusy && root.actionKind === "disconnect") return I18n.tr("Disconnecting…")
|
||||
if (isBusy && root.actionKind === "forget") return I18n.tr("Forgetting…")
|
||||
if (isFailed) return root.failureReason || I18n.tr("Failed")
|
||||
if (isConnected && root.kind === "wifi" && root.hasCaptivePortal) return I18n.tr("Sign-in required")
|
||||
if (isConnected) return I18n.tr("Connected")
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -1948,7 +1952,7 @@ Panel {
|
||||
|
||||
PanelToolTip {
|
||||
visible: rightMouse.containsMouse || row.forgetFocused
|
||||
text: "Forget network"
|
||||
text: I18n.tr("Forget network")
|
||||
fontFamily: root.bar.fontFamily
|
||||
}
|
||||
}
|
||||
@@ -1964,7 +1968,7 @@ Panel {
|
||||
|
||||
Text {
|
||||
textFormat: Text.PlainText
|
||||
text: row.net ? (row.net.ssid || "Hidden") : ""
|
||||
text: row.net ? (row.net.ssid || I18n.tr("Hidden")) : ""
|
||||
color: root.bar.foreground
|
||||
font.family: root.bar.fontFamily
|
||||
font.pixelSize: Style.font.body
|
||||
@@ -2024,7 +2028,7 @@ Panel {
|
||||
anchors.right: connectPwBtn.left
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: Style.space(6)
|
||||
placeholderText: "Identity (user@domain)"
|
||||
placeholderText: I18n.tr("Identity (user@domain)")
|
||||
font.family: Style.font.family
|
||||
font.pixelSize: Style.font.body
|
||||
foreground: root.bar.foreground
|
||||
@@ -2050,7 +2054,7 @@ Panel {
|
||||
anchors.bottomMargin: Style.spacing.rowGap / 2
|
||||
anchors.rightMargin: Style.space(6)
|
||||
password: true
|
||||
placeholderText: "Passphrase"
|
||||
placeholderText: I18n.tr("Passphrase")
|
||||
font.family: Style.font.family
|
||||
font.pixelSize: Style.font.body
|
||||
foreground: root.bar.foreground
|
||||
@@ -2083,7 +2087,7 @@ Panel {
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
text: row.isFailed ? "Wrong password" : "Connecting..."
|
||||
text: row.isFailed ? I18n.tr("Wrong password") : I18n.tr("Connecting...")
|
||||
color: row.isFailed ? root.bar.urgent : root.bar.foreground
|
||||
font.family: root.bar.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -2100,7 +2104,7 @@ Panel {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
enabled: row.net && pwField.text.length > 0 && (!row.isEnterprise || idField.text.length > 0)
|
||||
iconText: ""
|
||||
tooltipText: "Connect"
|
||||
tooltipText: I18n.tr("Connect")
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
onClicked: row.submitCredentials()
|
||||
@@ -2111,7 +2115,7 @@ Panel {
|
||||
|
||||
component DetailValue: InfoValue {
|
||||
property bool copyable: false
|
||||
property string tooltipText: "Copy to clipboard"
|
||||
property string tooltipText: I18n.tr("Copy to clipboard")
|
||||
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignRight
|
||||
|
||||
@@ -55,7 +55,7 @@ Panel {
|
||||
|
||||
function modeLabel() {
|
||||
var device = UPower.displayDevice
|
||||
return Model.modeLabel(device, root.discharging, upowerStates())
|
||||
return I18n.tr(Model.modeLabel(device, root.discharging, upowerStates()))
|
||||
}
|
||||
|
||||
function profileIcon(name) {
|
||||
@@ -95,26 +95,26 @@ Panel {
|
||||
// Cute agent-flavored phrases shown in the hero status line, rotated on a
|
||||
// timer so the panel feels alive when current is flowing (either direction).
|
||||
readonly property var chargingPhrases: [
|
||||
"Pumping power",
|
||||
"Injecting electrons",
|
||||
"Pouring juice",
|
||||
"Amassing watts",
|
||||
"Hoarding joules",
|
||||
"Sucking volts",
|
||||
"Topping reserves",
|
||||
"Soaking amps",
|
||||
"Inhaling kilowatts"
|
||||
I18n.tr("Pumping power"),
|
||||
I18n.tr("Injecting electrons"),
|
||||
I18n.tr("Pouring juice"),
|
||||
I18n.tr("Amassing watts"),
|
||||
I18n.tr("Hoarding joules"),
|
||||
I18n.tr("Sucking volts"),
|
||||
I18n.tr("Topping reserves"),
|
||||
I18n.tr("Soaking amps"),
|
||||
I18n.tr("Inhaling kilowatts")
|
||||
]
|
||||
readonly property var onBatteryPhrases: [
|
||||
"Slurping power",
|
||||
"Spending joules",
|
||||
"Draining watts",
|
||||
"Burning electrons",
|
||||
"Sipping juice",
|
||||
"Spending coulombs",
|
||||
"Bleeding amps",
|
||||
"Guzzling volts",
|
||||
"Munching reserves"
|
||||
I18n.tr("Slurping power"),
|
||||
I18n.tr("Spending joules"),
|
||||
I18n.tr("Draining watts"),
|
||||
I18n.tr("Burning electrons"),
|
||||
I18n.tr("Sipping juice"),
|
||||
I18n.tr("Spending coulombs"),
|
||||
I18n.tr("Bleeding amps"),
|
||||
I18n.tr("Guzzling volts"),
|
||||
I18n.tr("Munching reserves")
|
||||
]
|
||||
property int phraseIndex: 0
|
||||
|
||||
@@ -128,7 +128,7 @@ Panel {
|
||||
readonly property bool rotatingPhrases: activePhrases.length > 0
|
||||
|
||||
readonly property string heroStatusText: {
|
||||
if (fullyCharged) return "Fully charged"
|
||||
if (fullyCharged) return I18n.tr("Fully charged")
|
||||
if (rotatingPhrases) return activePhrases[phraseIndex % activePhrases.length]
|
||||
return modeLabel()
|
||||
}
|
||||
@@ -346,7 +346,8 @@ Panel {
|
||||
spacing: Style.space(2)
|
||||
|
||||
Text {
|
||||
text: "Battery"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("Battery")
|
||||
color: root.bar.foreground
|
||||
font.family: root.bar.fontFamily
|
||||
font.pixelSize: Style.font.title
|
||||
@@ -433,20 +434,20 @@ Panel {
|
||||
Column {
|
||||
width: (parent.width - parent.spacing) / 2
|
||||
spacing: Style.spacing.labelGap
|
||||
InfoPair { label: "Battery size"; value: root.batteryInfo.size || "" }
|
||||
InfoPair { label: "Charge cycles"; value: root.batteryInfo.cycles || "—" }
|
||||
InfoPair { label: I18n.tr("Battery size"); value: root.batteryInfo.size || "" }
|
||||
InfoPair { label: I18n.tr("Charge cycles"); value: root.batteryInfo.cycles || "—" }
|
||||
}
|
||||
|
||||
Column {
|
||||
width: (parent.width - parent.spacing) / 2
|
||||
spacing: Style.spacing.labelGap
|
||||
InfoPair {
|
||||
label: root.chargeThresholdActive ? "Charge limit" : (root.discharging ? "Time left" : "Time to full")
|
||||
label: root.chargeThresholdActive ? I18n.tr("Charge limit") : (root.discharging ? I18n.tr("Time left") : I18n.tr("Time to full"))
|
||||
value: root.chargeThresholdActive ? (root.batteryInfo.threshold || "-") : (root.batteryFlowIdle ? "-" : (root.batteryInfo.time || "—"))
|
||||
}
|
||||
InfoPair {
|
||||
label: root.chargeThresholdActive ? "Battery state" : (root.discharging ? "Discharging" : "Charging")
|
||||
value: root.chargeThresholdActive ? "Holding" : (root.batteryFull ? "-" : (root.batteryInfo.rate || ""))
|
||||
label: root.chargeThresholdActive ? I18n.tr("Battery state") : (root.discharging ? I18n.tr("Discharging") : I18n.tr("Charging"))
|
||||
value: root.chargeThresholdActive ? I18n.tr("Holding") : (root.batteryFull ? "-" : (root.batteryInfo.rate || ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -461,7 +462,7 @@ Panel {
|
||||
spacing: Style.space(10)
|
||||
|
||||
PanelSectionHeader {
|
||||
text: "POWER PROFILE"
|
||||
text: I18n.tr("POWER PROFILE")
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
}
|
||||
@@ -483,7 +484,7 @@ Panel {
|
||||
width: profileRow.cellWidth
|
||||
iconText: root.profileIcon(String(modelData))
|
||||
iconSize: Style.font.title
|
||||
text: String(modelData).charAt(0).toUpperCase() + String(modelData).slice(1)
|
||||
text: I18n.tr(String(modelData).charAt(0).toUpperCase() + String(modelData).slice(1))
|
||||
fontSize: Style.font.bodySmall
|
||||
foreground: root.bar.foreground
|
||||
fontFamily: root.bar.fontFamily
|
||||
|
||||
@@ -149,7 +149,7 @@ Item {
|
||||
}
|
||||
|
||||
if (!root.expectedStop && exitCode !== 0) {
|
||||
root.error = root.stderrText || "Speed test failed"
|
||||
root.error = root.stderrText || I18n.tr("Speed test failed")
|
||||
root.phase = ""
|
||||
root.running = false
|
||||
return
|
||||
@@ -177,7 +177,7 @@ Item {
|
||||
onStreamFinished: {
|
||||
var fields = String(text || "").trim().split("\t")
|
||||
if (fields[0] === "wifi") root.connectionName = fields[1] || "Wi-Fi"
|
||||
else if (fields[0] === "ethernet") root.connectionName = "Ethernet"
|
||||
else if (fields[0] === "ethernet") root.connectionName = I18n.tr("Ethernet")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,9 +186,9 @@ Item {
|
||||
fontFamily: Style.font.family
|
||||
layerNamespace: "omarchy-network-speedtest"
|
||||
title: root.connectionName
|
||||
leftLabel: "DOWNLOAD"
|
||||
rightLabel: "UPLOAD"
|
||||
runAgainTooltip: "Measure again via fast.com"
|
||||
leftLabel: I18n.tr("DOWNLOAD")
|
||||
rightLabel: I18n.tr("UPLOAD")
|
||||
runAgainTooltip: I18n.tr("Measure again via fast.com")
|
||||
running: root.running
|
||||
leftValue: root.downloadValue
|
||||
rightValue: root.uploadValue
|
||||
|
||||
@@ -25,16 +25,16 @@ Panel {
|
||||
property string mullvadQuery: ""
|
||||
property int phraseIndex: 0
|
||||
readonly property var activePhrases: [
|
||||
"Encrypting connections",
|
||||
"Sending secrets",
|
||||
"Guarding wires",
|
||||
"Braiding packets",
|
||||
"Polishing tunnels",
|
||||
"Hiding routes",
|
||||
"Sealing ports",
|
||||
"Sorting tailnets",
|
||||
"Shuffling keys",
|
||||
"Watching machines"
|
||||
I18n.tr("Encrypting connections"),
|
||||
I18n.tr("Sending secrets"),
|
||||
I18n.tr("Guarding wires"),
|
||||
I18n.tr("Braiding packets"),
|
||||
I18n.tr("Polishing tunnels"),
|
||||
I18n.tr("Hiding routes"),
|
||||
I18n.tr("Sealing ports"),
|
||||
I18n.tr("Sorting tailnets"),
|
||||
I18n.tr("Shuffling keys"),
|
||||
I18n.tr("Watching machines")
|
||||
]
|
||||
readonly property string heroPhraseText: activePhrases[phraseIndex % activePhrases.length]
|
||||
|
||||
@@ -53,7 +53,7 @@ Panel {
|
||||
// "header" stays navigable, but an absent CLI leaves nothing to highlight.
|
||||
readonly property bool headerHasCursor: cursorActive && focusSection === "header" && tailscale.installed
|
||||
readonly property color iconColor: tailscale.active ? foreground : dim
|
||||
readonly property string toggleHint: tailscale.active ? "Turn Tailscale off" : (tailscale.needsLogin ? "Authorize this device" : "Turn Tailscale on")
|
||||
readonly property string toggleHint: tailscale.active ? I18n.tr("Turn Tailscale off") : (tailscale.needsLogin ? I18n.tr("Authorize this device") : I18n.tr("Turn Tailscale on"))
|
||||
readonly property color barIconColor: tailscale.active ? barForeground : Qt.darker(barForeground, 1.55)
|
||||
readonly property color hoverFill: bar ? Style.hoverFillFor(bar.foreground, Commons.Color.accent) : "transparent"
|
||||
readonly property color selectedFill: bar ? Style.selectedFillFor(bar.foreground, Commons.Color.accent) : "transparent"
|
||||
@@ -77,7 +77,7 @@ Panel {
|
||||
var nodes = []
|
||||
for (var i = 0; i < tailscale.tailnetExitNodes.length; i++) nodes.push(tailscale.tailnetExitNodes[i])
|
||||
for (var j = 0; j < recentMullvadExitNodes.length; j++) nodes.push(recentMullvadExitNodes[j])
|
||||
if (tailscale.mullvadRegions.length > 0) nodes.push({ id: "mullvad:add", AddMullvad: true, DisplayName: "Choose Mullvad region" })
|
||||
if (tailscale.mullvadRegions.length > 0) nodes.push({ id: "mullvad:add", AddMullvad: true, DisplayName: I18n.tr("Choose Mullvad region") })
|
||||
return nodes
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ Panel {
|
||||
}
|
||||
|
||||
function mullvadRegionTitle(peer) {
|
||||
if (!peer) return "Unknown"
|
||||
if (!peer) return I18n.tr("Unknown")
|
||||
var city = String(peer.City || "").trim()
|
||||
var country = String(peer.Country || "").trim()
|
||||
if (city === "" || city === "Any") return country || String(peer.DisplayName || "Unknown")
|
||||
@@ -460,7 +460,7 @@ Panel {
|
||||
id: hero
|
||||
width: parent.width
|
||||
title: tailscale.installed ? (tailscale.selfName || "Tailscale") : "Tailscale"
|
||||
meta: tailscale.active ? root.heroPhraseText : "Tailscale is disconnected"
|
||||
meta: tailscale.active ? root.heroPhraseText : I18n.tr("Tailscale is disconnected")
|
||||
foreground: root.foreground
|
||||
fontFamily: root.fontFamily
|
||||
iconOpacity: tailscale.active ? 1.0 : 0.5
|
||||
@@ -503,7 +503,7 @@ Panel {
|
||||
textFormat: Text.PlainText
|
||||
visible: tailscale.actionStatus !== "" || tailscale.lastError !== ""
|
||||
width: parent.width
|
||||
text: tailscale.actionStatus !== "" ? tailscale.actionStatus : tailscale.lastError
|
||||
text: I18n.tr(tailscale.actionStatus !== "" ? tailscale.actionStatus : tailscale.lastError)
|
||||
color: tailscale.lastError !== "" && tailscale.actionStatus === "" ? root.urgent : root.dim
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -522,7 +522,8 @@ Panel {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.margins: Style.space(12)
|
||||
text: "Tailscale CLI is not installed or not on PATH."
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("Tailscale CLI is not installed or not on PATH.")
|
||||
color: root.dim
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.body
|
||||
@@ -541,7 +542,7 @@ Panel {
|
||||
spacing: Style.space(10)
|
||||
|
||||
PanelSectionHeader {
|
||||
text: "CONNECTIONS"
|
||||
text: I18n.tr("CONNECTIONS")
|
||||
foreground: root.foreground
|
||||
fontFamily: root.fontFamily
|
||||
}
|
||||
@@ -574,7 +575,7 @@ Panel {
|
||||
spacing: Style.space(10)
|
||||
|
||||
PanelSectionHeader {
|
||||
text: "EXIT NODES"
|
||||
text: I18n.tr("EXIT NODES")
|
||||
foreground: root.foreground
|
||||
fontFamily: root.fontFamily
|
||||
}
|
||||
@@ -604,7 +605,7 @@ Panel {
|
||||
id: mullvadSearch
|
||||
width: parent.width
|
||||
foreground: root.foreground
|
||||
placeholderText: "Search regions"
|
||||
placeholderText: I18n.tr("Search regions")
|
||||
text: root.mullvadQuery
|
||||
onTextChanged: {
|
||||
root.mullvadQuery = text
|
||||
@@ -640,7 +641,8 @@ Panel {
|
||||
Text {
|
||||
visible: root.filteredMullvadRegions.length === 0
|
||||
width: parent.width
|
||||
text: "No Mullvad regions found."
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("No Mullvad regions found.")
|
||||
color: root.dim
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -678,7 +680,7 @@ Panel {
|
||||
spacing: Style.space(10)
|
||||
|
||||
PanelSectionHeader {
|
||||
text: "MACHINES"
|
||||
text: I18n.tr("MACHINES")
|
||||
foreground: root.foreground
|
||||
fontFamily: root.fontFamily
|
||||
}
|
||||
@@ -686,7 +688,8 @@ Panel {
|
||||
Text {
|
||||
visible: tailscale.installed && tailscale.active && tailscale.peers.length === 0
|
||||
width: parent.width
|
||||
text: "No machines found on this tailnet."
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("No machines found on this tailnet.")
|
||||
color: root.dim
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.body
|
||||
@@ -779,7 +782,8 @@ Panel {
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: "Authorize Tailscale operator"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("Authorize Tailscale operator")
|
||||
color: root.foreground
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.body
|
||||
@@ -788,7 +792,8 @@ Panel {
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: "Allow this user to operate this Tailscale profile"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("Allow this user to operate this Tailscale profile")
|
||||
color: root.dim
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.caption
|
||||
@@ -805,7 +810,7 @@ Panel {
|
||||
property int rowIndex: 0
|
||||
readonly property bool selectedAccount: account && account.selected === true
|
||||
readonly property bool switchingAccount: account && tailscale.switchingAccountId === String(account.id || "")
|
||||
readonly property string accountText: account ? tailscale.accountLabel(account) : "Account"
|
||||
readonly property string accountText: account ? tailscale.accountLabel(account) : I18n.tr("Account")
|
||||
|
||||
hasCursor: root.cursorActive && root.focusSection === "accounts" && root.accountIndex === rowIndex
|
||||
current: selectedAccount
|
||||
@@ -869,7 +874,7 @@ Panel {
|
||||
id: peerRow
|
||||
property var peer: null
|
||||
property int rowIndex: 0
|
||||
readonly property string peerName: peer ? String(peer.DisplayName || peer.HostName || "Unknown") : "Unknown"
|
||||
readonly property string peerName: peer ? String(peer.DisplayName || peer.HostName || I18n.tr("Unknown")) : I18n.tr("Unknown")
|
||||
readonly property string peerIp: peer && peer.TailscaleIPs && peer.TailscaleIPs.length > 0 ? String(peer.TailscaleIPs[0]) : ""
|
||||
readonly property string peerIpv6: {
|
||||
if (!peer || !peer.TailscaleIPv6 || peer.TailscaleIPv6.length === 0) return ""
|
||||
@@ -980,7 +985,7 @@ Panel {
|
||||
id: sendButton
|
||||
visible: tailscale.canSendFiles(peerRow.peer)
|
||||
iconText: ""
|
||||
tooltipText: "Send files"
|
||||
tooltipText: I18n.tr("Send files")
|
||||
foreground: root.foreground
|
||||
fontFamily: root.fontFamily
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
@@ -1120,8 +1125,8 @@ Panel {
|
||||
readonly property bool addMullvad: peer && peer.AddMullvad === true
|
||||
readonly property bool activeExitNode: peer && peer.ExitNode === true
|
||||
readonly property bool settingExitNode: peer && tailscale.settingExitNodeId === String(peer.id || "")
|
||||
readonly property string peerName: peer ? String(peer.DisplayName || peer.HostName || "Unknown") : "Unknown"
|
||||
readonly property string actionTooltip: addMullvad ? "" : (activeExitNode ? "Disconnect" : "Connect")
|
||||
readonly property string peerName: peer ? String(peer.DisplayName || peer.HostName || I18n.tr("Unknown")) : I18n.tr("Unknown")
|
||||
readonly property string actionTooltip: addMullvad ? "" : (activeExitNode ? I18n.tr("Disconnect") : I18n.tr("Connect"))
|
||||
|
||||
hasCursor: root.cursorActive && root.focusSection === "exitNodes" && root.exitNodeIndex === rowIndex
|
||||
current: activeExitNode || settingExitNode || (addMullvad && root.mullvadPickerOpen)
|
||||
@@ -1201,7 +1206,7 @@ Panel {
|
||||
readonly property bool activeExitNode: peer && peer.ExitNode === true
|
||||
readonly property bool settingExitNode: peer && tailscale.settingExitNodeId === String(peer.id || "")
|
||||
readonly property bool selectedRegion: root.mullvadPickerOpen && root.mullvadRegionIndex === rowIndex
|
||||
readonly property string actionTooltip: activeExitNode ? "Disconnect" : "Connect"
|
||||
readonly property string actionTooltip: activeExitNode ? I18n.tr("Disconnect") : I18n.tr("Connect")
|
||||
|
||||
foreground: root.foreground
|
||||
fill: root.hoverFill
|
||||
|
||||
@@ -309,7 +309,7 @@ Panel {
|
||||
}
|
||||
|
||||
function dayName(dateString) {
|
||||
return Model.dayName(dateString, function(date) { return Qt.formatDate(date, "dddd") })
|
||||
return Model.dayName(dateString, function(date) { return I18n.chinese ? Qt.locale().toString(date, "dddd") : Qt.formatDate(date, "dddd") })
|
||||
}
|
||||
|
||||
// Bare degree value (no unit letter), used in the forecast row.
|
||||
@@ -617,7 +617,7 @@ Panel {
|
||||
id: locationField
|
||||
width: Style.space(190)
|
||||
enabled: !root.savingLocation
|
||||
placeholderText: "Search city"
|
||||
placeholderText: I18n.tr("Search city")
|
||||
foreground: root.bar.foreground
|
||||
font.family: root.bar.fontFamily
|
||||
|
||||
@@ -684,7 +684,8 @@ Panel {
|
||||
Column {
|
||||
spacing: Style.space(5)
|
||||
Text {
|
||||
text: "FEELS"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("FEELS")
|
||||
color: Qt.darker(root.bar.foreground, 1.5)
|
||||
font.family: root.bar.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -702,7 +703,8 @@ Panel {
|
||||
Column {
|
||||
spacing: Style.space(5)
|
||||
Text {
|
||||
text: "WIND"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("WIND")
|
||||
color: Qt.darker(root.bar.foreground, 1.5)
|
||||
font.family: root.bar.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -720,7 +722,8 @@ Panel {
|
||||
Column {
|
||||
spacing: Style.space(5)
|
||||
Text {
|
||||
text: "HUMID"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("HUMID")
|
||||
color: Qt.darker(root.bar.foreground, 1.5)
|
||||
font.family: root.bar.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -793,7 +796,8 @@ Panel {
|
||||
|
||||
Text {
|
||||
visible: !root.current
|
||||
text: "Fetching forecast…"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("Fetching forecast…")
|
||||
color: Qt.darker(root.bar.foreground, 1.5)
|
||||
font.family: root.bar.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
|
||||
@@ -183,7 +183,7 @@ Item {
|
||||
if (exitCode !== 0 || root.qrSize === 0) {
|
||||
root.qrSize = 0
|
||||
root.qrRows = []
|
||||
if (root.error === "") root.error = "Could not generate the Wi-Fi QR code"
|
||||
if (root.error === "") root.error = I18n.tr("Could not generate the Wi-Fi QR code")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -206,7 +206,7 @@ Item {
|
||||
if (root.pwExpectedStop) return
|
||||
if (!root.opened) return
|
||||
if (exitCode === 0 && root.password !== "") root.passwordVisible = true
|
||||
else root.passwordError = "Could not read the Wi-Fi password"
|
||||
else root.passwordError = I18n.tr("Could not read the Wi-Fi password")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +305,8 @@ Item {
|
||||
|
||||
Text {
|
||||
visible: root.loading
|
||||
text: "Generating QR code…"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("Generating QR code…")
|
||||
color: root.onScrimDim
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -328,7 +329,8 @@ Item {
|
||||
|
||||
Text {
|
||||
visible: root.showingQr
|
||||
text: "Scan to join this network"
|
||||
textFormat: Text.PlainText
|
||||
text: I18n.tr("Scan to join this network")
|
||||
color: root.onScrimDim
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
@@ -341,7 +343,7 @@ Item {
|
||||
visible: root.showingQr && root.secured
|
||||
text: root.passwordError !== "" ? root.passwordError
|
||||
: root.passwordVisible ? root.password
|
||||
: "Show password"
|
||||
: I18n.tr("Show password")
|
||||
color: root.passwordError !== "" ? root.onScrimUrgent : root.onScrim
|
||||
opacity: root.passwordVisible || root.passwordError !== "" ? 1 : 0.6
|
||||
font.family: root.fontFamily
|
||||
|
||||
@@ -79,7 +79,7 @@ Item {
|
||||
var flow = polkitAgent.flow
|
||||
if (!flow) return
|
||||
|
||||
currentMessage = String(flow.message || "Authentication is needed...")
|
||||
currentMessage = String(flow.message || I18n.tr("Authentication is needed..."))
|
||||
currentPrompt = String(flow.inputPrompt || "")
|
||||
currentSupplementary = String(flow.supplementaryMessage || "")
|
||||
responseRequired = !!flow.isResponseRequired
|
||||
@@ -337,7 +337,7 @@ Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: root.errorFlash ? "Wrong" : (root.submitted ? "Checking..." : "Enter password")
|
||||
text: root.errorFlash ? I18n.tr("Wrong") : (root.submitted ? I18n.tr("Checking...") : I18n.tr("Enter password"))
|
||||
color: root.errorFlash ? Commons.Color.polkit.textError : root.foreground
|
||||
opacity: root.errorFlash ? 1 : 0.36
|
||||
font.family: root.fontFamily
|
||||
|
||||
@@ -29,7 +29,7 @@ Item {
|
||||
property int headerHeight: Math.max(Style.space(34), Style.font.title + Style.spacing.controlPaddingY * 2)
|
||||
property int cardWidth: Math.min(Style.space(300), panel.width - Style.gapsOut * 2)
|
||||
property int cardHeight: Math.min(contentMargin * 2 + headerHeight, panel.height - Style.gapsOut * 2)
|
||||
readonly property string promptText: root.step === "message" ? "Reminder message" : "Remind in minutes"
|
||||
readonly property string promptText: root.step === "message" ? I18n.tr("Reminder message") : I18n.tr("Remind in minutes")
|
||||
|
||||
function open(payloadJson) {
|
||||
var payload = ({})
|
||||
@@ -75,7 +75,7 @@ Item {
|
||||
}
|
||||
|
||||
if (!nextMinutes) {
|
||||
Quickshell.execDetached([root.omarchyPath + "/bin/omarchy-notification-send", "Invalid reminder", "Enter the number of minutes"])
|
||||
Quickshell.execDetached([root.omarchyPath + "/bin/omarchy-notification-send", I18n.tr("Invalid reminder"), I18n.tr("Enter the number of minutes")])
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -411,7 +411,7 @@ Item {
|
||||
handled = true
|
||||
}
|
||||
} else if (action === "playPause") {
|
||||
actionLabel = player && player.isPlaying ? "Pause" : "Play"
|
||||
actionLabel = player && player.isPlaying ? I18n.tr("Pause") : I18n.tr("Play")
|
||||
iconName = player && player.isPlaying ? "media-pause" : "media-play"
|
||||
if (player && player.isPlaying && player.canPause) {
|
||||
player.pause()
|
||||
|
||||
Reference in new issue
Block a user