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:
ZacharyZhang-NY committed 2026-10-12 02:56:40 -04:00
1 parent defbf90e89
commit a9b39710a2
138 files changed
+1986 -558

No files matched your search

+67 -63
View File
@@ -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