Show the desktop shell in Chinese under zh_CN

This commit is contained in:
ZacharyZhang-NY committed 2026-10-06 21:29:39 -04:00
1 parent e590f22de6
commit e236713d9f
55 files changed
+867 -331

No files matched your search

+12
View File
@@ -0,0 +1,12 @@
pragma Singleton
import QtQuick
import "Tr.js" as Tr
// tr("English %1", arg) returns the Chinese entry under zh_CN; plain JS imports Tr.js for the same.
QtObject {
readonly property bool chinese: Tr.chinese
function tr() {
return Tr.tr.apply(null, arguments)
}
}
+455
View File
@@ -0,0 +1,455 @@
// Chinese for the shell, keyed by the English text each I18n.tr() call passes; %1, %2 are arguments.
.pragma library
var table = {
// Agents panel
"Agents": "AI 代理",
"Monthly": "每月",
"Weekly": "每周",
"Session": "会话",
"Limit": "额度",
"now": "现在",
"%1d %2h": "%1天 %2小时",
"%1h %2m": "%1小时 %2分",
"%1m": "%1分钟",
"%1 free reset": "%1 次免费重置",
"%1 free resets": "%1 次免费重置",
"%1 spent of %2 funded": "已用 %1,共充值 %2",
"estimated": "估算",
"%1 tokens this week": "本周 %1 tokens",
"%1 tokens today": "今天 %1 tokens",
"Mostly %1": "主要使用 %1",
"Busiest day: %1": "最忙的一天:%1",
"%1 prompt today": "今天 %1 条提示",
"%1 prompts today": "今天 %1 条提示",
"%1 session today": "今天 %1 个会话",
"%1 sessions today": "今天 %1 个会话",
"Merged from %1 device": "合并自 %1 台设备",
"Merged from %1 devices": "合并自 %1 台设备",
"Add an account": "添加账户",
"Add an %1 account": "添加 %1 账户",
"Add a %1 account": "添加 %1 账户",
"The sign-in didn't finish.": "登录没有完成。",
"Back to the limits": "返回额度",
"Add a subscription": "添加订阅",
"Start the default agent": "启动默认 AI 代理",
"MAKE SOMETHING COOL": "做点有意思的",
"Sign in to an AI coding subscription, and this panel keeps track of how much of it you have left.": "登录一个 AI 编程订阅,这个面板会记录剩余额度。",
"Name this account. It signs in through a private window, so your browser's current account isn't picked up.": "给这个账户起个名字。登录在隐私窗口中进行,不会用到浏览器当前登录的账户。",
"Work": "工作",
"Confirm this code in your browser": "在浏览器中确认这个代码",
"If the page shows a code instead of finishing, paste it here.": "如果页面显示代码而没有完成,把代码粘贴到这里。",
"Code": "代码",
"Open the sign-in page again": "重新打开登录页",
"Sign in to %1 again": "重新登录 %1",
"Balance": "余额",
"Start your default agent on a new %1": "用默认 AI 代理新建一个%1",
"Sign in to this account again": "重新登录这个账户",
"ACTIVE": "使用中",
"Autoswitch": "自动切换",
"Stop switching automatically": "停止自动切换",
"Switch here automatically at %1%": "用到 %1% 时自动切换到这里",
"Use": "使用",
"Usage unavailable": "用量不可用",
"Usage has not been updated yet.": "用量还没有更新。",
"%1: %2% used": "%1:已用 %2%",
"resets in %1": "%1后重置",
"Last updated %1 ago": "%1前更新",
"Last updated less than a minute ago": "不到一分钟前更新",
"Last updated time unavailable": "更新时间不可用",
"Theme": "主题",
"Plugin": "插件",
"App": "应用",
"Sunday": "星期日",
"Monday": "星期一",
"Tuesday": "星期二",
"Wednesday": "星期三",
"Thursday": "星期四",
"Friday": "星期五",
"Saturday": "星期六",
"%1: %2% of its %3 allowance": "%1:占%3额度的 %2%",
"Subscriptions": "订阅",
// Network panel
"Wiring bits": "接线中",
"Handling packets": "处理数据包",
"Sorting frames": "整理数据帧",
"Hauling bytes": "搬运字节",
"Routing crumbs": "转发碎片",
"Counting collisions": "清点冲突",
"Bending light": "弯折光线",
"Turn Wi-Fi off": "关闭 Wi-Fi",
"Turn Wi-Fi on": "打开 Wi-Fi",
"WI-FI BAND": "WI-FI 频段",
"WI-FI BAND: %1": "WI-FI 频段:%1",
"Auto": "自动",
"Let Wi-Fi pick the band": "由 Wi-Fi 自动选择频段",
"Stay on %1": "固定在 %1",
"Timeout": "超时",
"KNOWN NETWORKS": "已知网络",
"OTHER NETWORKS": "其他网络",
"Ethernet": "有线网络",
"Passphrase required": "需要密码",
"Wrong password": "密码错误",
"Network lost": "网络丢失",
"Disconnected": "已断开",
"Connection failed": "连接失败",
"Failed to connect": "无法连接",
"Timed out connecting": "连接超时",
"Timed out disconnecting": "断开超时",
"Timed out forgetting": "忘记网络超时",
"Sign in to this network": "登录这个网络",
"Limited internet access": "互联网访问受限",
"Show QR code": "显示二维码",
"Run a speed test": "测速",
"No connection": "无连接",
"SIGN-IN REQUIRED": "需要登录",
"LIMITED INTERNET ACCESS": "互联网访问受限",
"NOT CONNECTED": "未连接",
"Open Captive Portal": "打开认证页面",
"Sign in or accept this network’s terms to access the internet.": "登录或接受这个网络的条款后才能上网。",
"AUTOMATIC": "自动",
"DNS PROVIDER": "DNS 服务商",
"Use DNS from DHCP": "使用 DHCP 提供的 DNS",
"Set DNS to %1": "DNS 设为 %1",
"Set custom DNS servers": "设置自定义 DNS 服务器",
"Custom": "自定义",
"SCANNING WI-FI…": "正在扫描 WI-FI…",
"Connecting…": "正在连接…",
"Disconnecting…": "正在断开…",
"Forgetting…": "正在忘记…",
"Failed": "失败",
"Sign-in required": "需要登录",
"Connected": "已连接",
"Forget network": "忘记网络",
"Hidden": "隐藏网络",
"Identity (user@domain)": "身份(user@domain)",
"Passphrase": "密码",
"Connect": "连接",
"Copy to clipboard": "复制到剪贴板",
"Ping": "延迟",
"Packet Loss": "丢包",
"Receiving": "接收",
"Sending": "发送",
"Downloaded": "已下载",
"Uploaded": "已上传",
"IP Address": "IP 地址",
"Gateway": "网关",
"Copy IP": "复制 IP",
"Copy gateway": "复制网关",
"Connecting...": "正在连接…",
// Display panel
"Display": "显示",
"FIXED BRIGHTNESS": "亮度固定",
"BRIGHTNESS": "亮度",
"TEXT SIZE": "文字大小",
"SCALE": "缩放",
"DISPLAYS": "显示器",
"Sun blast": "烈日当空",
"Solar flare": "耀眼",
"Golden hour": "黄金时刻",
"Even day": "白昼",
"Soft glow": "柔光",
"Lamp light": "灯光",
"Candlelit": "烛光",
"Night owl": "夜猫子",
// Audio panel
"Audio": "音频",
"OUTPUT": "输出",
"INPUT": "输入",
"SOURCES": "音源",
"Mute": "静音",
"Unmute": "取消静音",
"Muted": "已静音",
"Silenced": "无声",
"Concert hall": "音乐厅",
"Party mode": "派对模式",
"Cranked up": "开大了",
"Steady groove": "稳稳的节奏",
"Easy listening": "轻松聆听",
"Murmur": "低语",
"Whisper": "耳语",
// Bluetooth panel
"Untangling wires": "理顺线缆",
"Streaming vikings": "维京人在传输",
"Pairing mysteries": "配对谜题",
"Herding headsets": "召集耳机",
"Taming radios": "驯服无线电",
"Summoning speakers": "召唤音箱",
"Wrangling codecs": "摆弄编解码器",
"Polishing packets": "打磨数据包",
"Bluetooth": "蓝牙",
"CONNECTED": "已连接",
"Forget": "忘记",
"No adapter": "没有适配器",
"Turned Off": "已关闭",
"Turn Bluetooth off": "关闭蓝牙",
"Turn Bluetooth on": "打开蓝牙",
"PAIRED": "已配对",
"AVAILABLE": "可用",
"No Bluetooth adapter": "没有蓝牙适配器",
"Turn Bluetooth on to scan": "打开蓝牙后扫描",
"Scanning for devices…": "正在扫描设备…",
"Disconnect": "断开",
"Pair": "配对",
"Device": "设备",
// Power panel
"Pumping power": "注入电力",
"Injecting electrons": "注入电子",
"Pouring juice": "倒入电量",
"Amassing watts": "积攒瓦特",
"Hoarding joules": "囤积焦耳",
"Sucking volts": "吸收伏特",
"Topping reserves": "补满储备",
"Soaking amps": "吸饱安培",
"Inhaling kilowatts": "吸入千瓦",
"Slurping power": "啜饮电力",
"Spending joules": "花费焦耳",
"Draining watts": "消耗瓦特",
"Burning electrons": "燃烧电子",
"Sipping juice": "小口用电",
"Spending coulombs": "花费库仑",
"Bleeding amps": "流失安培",
"Guzzling volts": "狂饮伏特",
"Munching reserves": "啃食储备",
"Battery": "电池",
"POWER PROFILE": "电源模式",
"Fully charged": "已充满",
"Threshold": "充电上限",
"On battery": "使用电池",
"Charging": "正在充电",
"Battery size": "电池容量",
"Charge cycles": "充电次数",
"Charge limit": "充电上限",
"Time left": "剩余时间",
"Time to full": "充满还需",
"Battery state": "电池状态",
"Discharging": "正在放电",
"Holding": "保持中",
// Tailscale panel
"Encrypting connections": "加密连接",
"Sending secrets": "传递秘密",
"Guarding wires": "守护线路",
"Braiding packets": "编织数据包",
"Polishing tunnels": "打磨隧道",
"Hiding routes": "隐藏路由",
"Sealing ports": "封好端口",
"Sorting tailnets": "整理 tailnet",
"Shuffling keys": "洗牌密钥",
"Watching machines": "照看机器",
"Tailscale CLI is not installed or not on PATH.": "没有安装 Tailscale 命令行,或它不在 PATH 中。",
"CONNECTIONS": "连接",
"EXIT NODES": "出口节点",
"Search regions": "搜索地区",
"No Mullvad regions found.": "没有找到 Mullvad 地区。",
"MACHINES": "机器",
"No machines found on this tailnet.": "这个 tailnet 上没有机器。",
"Authorize Tailscale operator": "授权 Tailscale 操作员",
"Allow this user to operate this Tailscale profile": "允许这个用户操作这个 Tailscale 配置",
"Send files": "发送文件",
"Turn Tailscale off": "关闭 Tailscale",
"Authorize this device": "授权这台设备",
"Turn Tailscale on": "打开 Tailscale",
"Choose Mullvad region": "选择 Mullvad 地区",
"Tailscale is disconnected": "Tailscale 已断开",
"Account": "账户",
"Starting Tailscale login…": "正在开始 Tailscale 登录…",
"Authorizing Tailscale operator...": "正在授权 Tailscale 操作员…",
"Tailscale login link not available yet": "Tailscale 登录链接还不可用",
"Authorize Tailscale operator to show connections": "授权 Tailscale 操作员后显示连接",
"Could not list Tailscale connections": "无法列出 Tailscale 连接",
"Tailscale command failed": "Tailscale 命令失败",
"Account switch failed": "切换账户失败",
"Exit node selection failed": "选择出口节点失败",
"Tailscale authorization failed": "Tailscale 授权失败",
"Tailscale operator authorized": "Tailscale 操作员已授权",
"Unknown": "未知",
// Dropbox panel
"Filing files": "归档文件",
"Distributing data": "分发数据",
"Shuffling folders": "整理文件夹",
"Boxing bytes": "装箱字节",
"Sorting stuff": "分拣东西",
"Syncing secrets": "同步秘密",
"Packing packets": "打包数据包",
"Moving memories": "搬运回忆",
"Wrangling revisions": "整理修订",
"Cataloging chaos": "编目混乱",
"RECENT FILES": "最近文件",
"No synced files found.": "没有找到同步的文件。",
"Pause syncing": "暂停同步",
"Resume syncing": "继续同步",
"Syncing paused": "同步已暂停",
"Stored": "已存储",
"Login to Dropbox": "登录 Dropbox",
"Dropbox CLI is not installed": "没有安装 Dropbox 命令行",
"Start the authentication flow": "开始认证",
"Install Dropbox from the service menu": "从服务菜单安装 Dropbox",
"Untitled": "未命名",
// Weather panel
"Search city": "搜索城市",
"FEELS": "体感",
"WIND": "风",
"HUMID": "湿度",
"Fetching forecast…": "正在获取天气预报…",
// Wi-Fi QR panel
"Generating QR code…": "正在生成二维码…",
"Scan to join this network": "扫码加入这个网络",
"Could not generate the Wi-Fi QR code": "无法生成 Wi-Fi 二维码",
"Could not read the Wi-Fi password": "无法读取 Wi-Fi 密码",
"Show password": "显示密码",
// Speed tests
"Speed test failed": "测速失败",
"DOWNLOAD": "下载",
"UPLOAD": "上传",
"Measure again via fast.com": "通过 fast.com 重新测速",
"Disk speed test failed": "磁盘测速失败",
"READ": "读取",
"WRITE": "写入",
"Measure again": "重新测速",
"Run Again": "再测一次",
// Lock screen
"Enter Password": "输入密码",
"Checking…": "正在验证…",
"Fingerprint reader unavailable": "指纹识别器不可用",
"Authentication failed (%1)": "认证失败(%1)",
// Authentication prompt
"Authentication is needed...": "需要认证…",
"Wrong": "错误",
"Checking...": "正在验证…",
"Enter password": "输入密码",
// Reminders
"Reminder message": "提醒内容",
"Remind in minutes": "几分钟后提醒",
// Notifications
"No recent notifications": "没有最近的通知",
// Bar
"Microphone muted": "麦克风已静音",
"Microphone in use": "麦克风使用中",
"Microphone live": "麦克风已开启",
"Pending Omarchy Updates": "有待安装的 Omarchy 更新",
"Tray icons": "托盘图标",
"Pinned icons stay visible. Hidden icons never show.": "固定的图标一直显示,隐藏的图标不再显示。",
"No tray items reporting.": "没有托盘项目。",
"Unpin": "取消固定",
"Pin": "固定",
"Show": "显示",
"Hide": "隐藏",
"Dictate": "语音输入",
"Allow Notifications": "允许通知",
"Silence Notifications": "静默通知",
"Day Light": "日间光线",
"Night Light": "夜间光线",
"Stop recording": "停止录屏",
"Screen Recording": "录屏",
"Allow Idle Lock & Screensaver": "允许空闲锁屏和屏保",
"Stay Awake": "保持唤醒",
// Shared controls
"Cancel": "取消",
"Confirm": "确认",
"Search...": "搜索…",
"No options": "没有选项",
"None selected": "未选择",
"Loading…": "正在加载…",
"No matches": "没有匹配项",
// Notifications and on-screen messages
"Learn Keybindings": "了解快捷键",
"Super + K for cheatsheet.\nSuper + Space for Omarchy Menu.": "Super + K 查看快捷键速查表。\nSuper + Space 打开 Omarchy 菜单。",
"Update System": "更新系统",
"Click to update the system.": "点击更新系统。",
"Setup Wi-Fi": "设置 Wi-Fi",
"Click to configure the wireless network.": "点击配置无线网络。",
"All reminders have been cleared": "所有提醒已清除",
"Animations disabled": "动画已关闭",
"Animations enabled": "动画已开启",
"Can't disable the only active display": "不能关闭唯一的显示器",
"Copied text from selection to clipboard": "已把选中文字复制到剪贴板",
"Could not complete shutdown. Please try again.": "无法完成关机,请重试。",
"Could not share": "无法分享",
"Crash capture disabled": "崩溃捕获已关闭",
"Crash capture enabled": "崩溃捕获已开启",
"Disable single-window square aspect ratio": "关闭单窗口方形比例",
"Enable single-window square aspect ratio": "开启单窗口方形比例",
"Download failed": "下载失败",
"Editing config file": "正在编辑配置文件",
"Extended mode restored": "已恢复扩展模式",
"FIDO2 authfile needs attention": "FIDO2 认证文件需要处理",
"Failed to start Windows VM": "无法启动 Windows 虚拟机",
"Herdr theme sync disabled": "Herdr 主题同步已关闭",
"Herdr theme sync enabled": "Herdr 主题同步已开启",
"Hold F9 to dictate (or toggle with Super + Ctrl + X).": "按住 F9 语音输入(或用 Super + Ctrl + X 切换)。",
"Laptop display disabled": "笔记本屏幕已关闭",
"Laptop display enabled": "笔记本屏幕已开启",
"Logging out": "正在注销",
"Microphone on": "麦克风已开启",
"No QR code found": "没有找到二维码",
"No RetroArch cores found": "没有找到 RetroArch 核心",
"No audio devices found": "没有找到音频设备",
"No background was found for theme": "这个主题没有壁纸",
"No external monitors found for mirror": "没有可镜像的外接显示器",
"No laptop display found": "没有找到笔记本屏幕",
"No laptop monitor found to mirror": "没有可镜像的笔记本屏幕",
"No outstanding reminders": "没有待办提醒",
"No video found for download": "没有可下载的视频",
"No webcam devices found": "没有找到摄像头",
"QR code copied to clipboard": "二维码已复制到剪贴板",
"Rebooting": "正在重启",
"Recording process had to be force-killed. Video may be corrupted.": "录屏进程被强制结束,视频可能已损坏。",
"Refusing unsafe monitor name": "拒绝不安全的显示器名称",
"Reminder": "提醒",
"Restore using Super + Home on this workspace.": "在这个工作区用 Super + Home 恢复。",
"Saved and copied to clipboard.": "已保存并复制到剪贴板。",
"Screen recording error": "录屏出错",
"Screensaver disabled": "屏保已关闭",
"Screensaver enabled": "屏保已开启",
"Screensaver only runs in Alacritty, Foot, Ghostty, or Kitty": "屏保只能在 Alacritty、Foot、Ghostty 或 Kitty 中运行",
"Select a region containing a QR code": "框选包含二维码的区域",
"Shutdown failed": "关机失败",
"Shutting down": "正在关机",
"Start it with Super + Space": "用 Super + Space 启动",
"Suspend now available in system menu": "系统菜单中已加入挂起",
"Suspend removed from system menu": "系统菜单中已移除挂起",
"TUI removed": "TUI 已移除",
"The file chooser did not open": "文件选择器没有打开",
"Theme removed": "主题已移除",
"Time to recharge!": "该充电了!",
"Transcoding video…": "正在转码视频…",
"URL copied to clipboard": "链接已复制到剪贴板",
"Upcoming reminders": "即将到来的提醒",
"Use Super + Alt + Home to save one for this workspace.": "用 Super + Alt + Home 为这个工作区保存一个。",
"Voxtype Dictation Ready": "Voxtype 语音输入就绪",
"Web app removed": "网页应用已移除",
"Windows VM": "Windows 虚拟机",
// Clock
"Right-click to toggle format": "右键切换格式",
"Back to today": "回到今天",
"BORN": "出生",
"LIVE TO": "活到",
"LIFE": "人生",
"Start weeks on %1": "每周从%1开始",
"Previous month": "上个月",
"Next month": "下个月",
// Menu
"Go": "前往",
"Input": "输入",
"Select": "选择",
"Do you want to uninstall %1?": "要卸载 %1 吗?",
"Uninstall": "卸载",
"No matches for “%1”": "没有匹配“%1”的结果",
"Nothing here yet": "这里还没有内容",
// World clock, emojis, clipboard
"Search cities…": "搜索城市…",
"World": "世界",
"Clock": "时钟",
"Remove": "移除",
"World clock": "世界时钟",
"Delete entire clipboard history?": "删除全部剪贴板历史?",
"Delete": "删除",
"Clipboard is empty": "剪贴板是空的",
"Sunrise": "日出",
"Sunset": "日落",
"It's %1 here": "这里现在是 %1",
"Jump to a city": "跳到一个城市",
// Media
"Pause": "暂停",
"Play": "播放"
}
+11
View File
@@ -0,0 +1,11 @@
.pragma library
.import "I18nZh.js" as Zh
// Shell text in the session's language; QML reaches this through the I18n singleton, plain JS imports it.
var chinese = Qt.locale().name.indexOf("zh_CN") === 0
function tr(text) {
var out = chinese && Zh.table[text] !== undefined ? Zh.table[text] : text
for (var i = 1; i < arguments.length; i++) out = out.split("%" + i).join(String(arguments[i]))
return out
}
+1
View File
@@ -1,6 +1,7 @@
module qs.Commons
singleton Border 1.0 Border.qml
singleton Color 1.0 Color.qml
singleton I18n 1.0 I18n.qml
singleton IpcRegistry 1.0 IpcRegistry.qml
singleton Style 1.0 Style.qml
singleton Util 1.0 Util.qml
+2 -2
View File
@@ -6,8 +6,8 @@ Item {
property bool opened: false
property string message: ""
property string cancelText: "Cancel"
property string confirmText: "Confirm"
property string cancelText: I18n.tr("Cancel")
property string confirmText: I18n.tr("Confirm")
property int selectedIndex: 1
property color background: Color.background
property color foreground: Color.foreground
+4 -4
View File
@@ -27,9 +27,9 @@ Item {
property var options: []
property var optionsCommand: []
property string optionsCommandCwd: ""
property string placeholderText: "Search..."
property string emptyText: "No options"
property string noSelectionText: "None selected"
property string placeholderText: I18n.tr("Search...")
property string emptyText: I18n.tr("No options")
property string noSelectionText: I18n.tr("None selected")
property string triggerLabel: ""
property bool showLabel: true
@@ -492,7 +492,7 @@ Item {
textFormat: Text.PlainText
anchors.centerIn: parent
visible: resultList.count === 0
text: root.loadingOptions ? "Loading…" : (root.optionsError !== "" ? root.optionsError : root.emptyText)
text: root.loadingOptions ? I18n.tr("Loading…") : (root.optionsError !== "" ? root.optionsError : root.emptyText)
color: Qt.darker(root.foreground, 1.6)
font.family: root.fontFamily
font.pixelSize: Style.font.body
+2 -2
View File
@@ -21,8 +21,8 @@ Item {
property string label: ""
property string value: ""
property var options: []
property string placeholderText: "Search..."
property string emptyText: "No matches"
property string placeholderText: I18n.tr("Search...")
property string emptyText: I18n.tr("No matches")
property string triggerLabel: ""
property color foreground: Color.popups.text
+2 -2
View File
@@ -22,7 +22,7 @@ PanelWindow {
property string unit: "Mbps"
property string title: ""
property string layerNamespace: "omarchy-speed-test"
property string runAgainTooltip: "Measure again"
property string runAgainTooltip: I18n.tr("Measure again")
property real leftValue: 0
property real rightValue: 0
property bool leftLive: false
@@ -164,7 +164,7 @@ PanelWindow {
// Centered on the dial pair. Fades rather than unmounts while a run
// is in flight, so the cluster never shifts.
Button {
text: "Run Again"
text: I18n.tr("Run Again")
tooltipText: root.runAgainTooltip
bordered: true
enabled: !root.running
+56 -56
View File
@@ -338,9 +338,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) {
@@ -406,7 +406,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(" · ")
}
@@ -491,11 +491,11 @@ Panel {
function windowTitle(label) {
var text = String(label || "").toLowerCase()
if (text.indexOf("month") >= 0) return "Monthly"
if (windowIsLong(text)) return "Weekly"
if (text.indexOf("session") >= 0 || windowSpanMs(label) > 0) return "Session"
if (text.indexOf("month") >= 0) return I18n.tr("Monthly")
if (windowIsLong(text)) return I18n.tr("Weekly")
if (text.indexOf("session") >= 0 || windowSpanMs(label) > 0) return I18n.tr("Session")
var plain = String(label || "").replace(/\s*\(.*\)\s*/, "").trim()
return plain === "" ? "Limit" : plain
return plain === "" ? I18n.tr("Limit") : plain
}
// A collector that already knows which window a limit belongs to says so,
@@ -575,13 +575,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
@@ -611,8 +611,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
}
@@ -653,16 +653,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
@@ -672,7 +672,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
@@ -684,7 +684,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.
@@ -693,7 +693,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 ""
}
@@ -743,8 +743,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
@@ -803,7 +803,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"
}
}
@@ -938,7 +938,7 @@ Panel {
PanelHero {
id: hero
width: parent.width
title: "Agents"
title: I18n.tr("Agents")
meta: root.heroPhrase
foreground: root.foreground
fontFamily: root.fontFamily
@@ -964,7 +964,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()
}
@@ -973,7 +973,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()
}
}
@@ -1010,7 +1010,7 @@ Panel {
spacing: Style.space(12)
PanelSectionHeader {
text: "MAKE SOMETHING COOL"
text: I18n.tr("MAKE SOMETHING COOL")
foreground: root.foreground
fontFamily: root.fontFamily
}
@@ -1064,7 +1064,7 @@ 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."
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
@@ -1136,7 +1136,7 @@ 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."
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
@@ -1146,7 +1146,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
@@ -1178,7 +1178,7 @@ Panel {
spacing: Style.space(4)
Text {
text: "Confirm this code in your browser"
text: I18n.tr("Confirm this code in your browser")
color: root.dim
font.family: root.fontFamily
font.pixelSize: Style.font.caption
@@ -1202,7 +1202,7 @@ Panel {
Text {
width: parent.width
text: "If the page shows a code instead of finishing, paste it here."
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
@@ -1212,7 +1212,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
@@ -1223,7 +1223,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()
}
}
@@ -1329,9 +1329,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)
}
@@ -1397,7 +1397,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
@@ -1567,7 +1567,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())
}
}
@@ -1771,9 +1771,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)
}
}
@@ -1809,7 +1809,7 @@ Panel {
id: headActive
visible: head.isActive
anchors.right: parent.right
text: "ACTIVE"
text: I18n.tr("ACTIVE")
color: Color.accent
font.family: root.fontFamily
font.pixelSize: Style.font.caption
@@ -1828,19 +1828,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)
}
@@ -1857,7 +1857,7 @@ Panel {
Text {
id: unavailableLabel
text: "Usage unavailable"
text: I18n.tr("Usage unavailable")
color: root.dim
font.family: root.fontFamily
font.pixelSize: Style.font.bodySmall
@@ -1867,7 +1867,7 @@ Panel {
PanelToolTip {
visible: unavailableHover.hovered && unavailable.visible
text: unavailable.record ? String(unavailable.record.authHelpText || "Usage has not been updated yet.") : ""
text: unavailable.record ? String(unavailable.record.authHelpText || I18n.tr("Usage has not been updated yet.")) : ""
}
}
@@ -1892,16 +1892,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", 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", compact.scoped[i].title, Math.round(compact.scoped[i].percent * 100),
String(compact.window ? compact.window.title : "").toLowerCase()))
return lines.join("\n")
}
}
+2 -1
View File
@@ -1,5 +1,6 @@
import QtQuick
import Quickshell.Io
import qs.Commons
import qs.Ui
BarIndicator {
@@ -12,7 +13,7 @@ BarIndicator {
activeText: icon
inactiveText: "󰍬"
activeTooltipText: state
inactiveTooltipText: "Dictate"
inactiveTooltipText: I18n.tr("Dictate")
function update(raw) {
var data = extractData(raw)
+2 -2
View File
@@ -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) {
+3 -2
View File
@@ -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,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
+3 -2
View File
@@ -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)
+2 -1
View File
@@ -1,6 +1,7 @@
import QtQuick
import Quickshell
import Quickshell.Services.Pipewire
import qs.Commons
import qs.Ui
BarWidget {
@@ -40,7 +41,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()
+1 -1
View File
@@ -59,7 +59,7 @@ BarWidget {
text: "\uf021"
slotSize: Style.bar.statusSlot
fontSize: Style.font.caption
tooltipText: "Pending Omarchy Updates"
tooltipText: I18n.tr("Pending Omarchy Updates")
onPressed: root.runUpdate()
}
}
+5 -5
View File
@@ -410,7 +410,7 @@ BarWidget {
spacing: Style.space(8)
Text {
text: "Tray icons"
text: I18n.tr("Tray icons")
color: root.foreground
font.family: root.fontFamily
font.pixelSize: Style.font.body
@@ -418,7 +418,7 @@ BarWidget {
}
Text {
text: "Pinned icons stay visible. Hidden icons never show."
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
@@ -428,7 +428,7 @@ BarWidget {
Text {
visible: root.allItems.length === 0
text: "No tray items reporting."
text: I18n.tr("No tray items reporting.")
color: Qt.darker(root.foreground, 1.5)
font.family: root.fontFamily
font.pixelSize: Style.font.bodySmall
@@ -485,7 +485,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
@@ -500,7 +500,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
+3 -3
View File
@@ -398,8 +398,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
@@ -592,7 +592,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
+1 -1
View File
@@ -324,7 +324,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
+1 -1
View File
@@ -91,7 +91,7 @@ Item {
function currentLabel() {
var path = currentPath()
if (!path) return filterText ? "No matches" : ""
if (!path) return filterText ? I18n.tr("No matches") : ""
return labelForPath(path)
}
+3 -3
View File
@@ -24,7 +24,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
@@ -222,7 +222,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 ? Color.lock.text : (root.failureMessage.length > 0 ? Color.lock.textError : Color.lock.placeholder)
font.family: Style.font.family
@@ -265,7 +265,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: Color.lock.textError
font.family: Style.font.family
font.pixelSize: Style.font.heading
+1 -1
View File
@@ -350,7 +350,7 @@ Item {
enteredPassword = ""
pendingPassword = ""
failedAttempts += 1
failureMessage = "Authentication failed (" + failedAttempts + ")"
failureMessage = I18n.tr("Authentication failed (%1)", failedAttempts)
runWake()
}
+6 -6
View File
@@ -50,7 +50,7 @@ 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: (Quickshell.env("LANG") || "").startsWith("zh_CN") ? omarchyPath + "/default/omarchy/omarchy-menu.zh-cn.jsonc" : ""
property string localeMenuPath: I18n.chinese ? omarchyPath + "/default/omarchy/omarchy-menu.zh-cn.jsonc" : ""
property var defaultMenuItems: []
property var localeMenuItems: []
property var userMenuItems: []
@@ -867,7 +867,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 : []
selectionFile = String(payload.selectionFile || "")
doneFile = String(payload.doneFile || "")
@@ -1182,8 +1182,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
@@ -1215,7 +1215,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
@@ -1471,7 +1471,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
+1 -1
View File
@@ -721,7 +721,7 @@ Item {
originalId: -1,
app: "omarchy-action",
appIcon: "",
summary: "No recent notifications",
summary: I18n.tr("No recent notifications"),
body: "",
image: "",
glyph: "󰂚",
@@ -44,7 +44,7 @@ BorderSurface {
readonly property bool singleLineToast: sanitizedBody.length === 0
readonly property bool collapseRedundantIcon: singleLineToast && !hasGlyph && summaryStartsWithGlyph
readonly property string sanitizedBody: sanitizeBody(body)
readonly property string styledBody: NotificationLogic.styledBody(body, app, appIcon)
readonly property string styledBody: NotificationLogic.styledBody(I18n.tr(body), app, appIcon)
readonly property color dimColor: Qt.darker(Color.notifications.text, 1.4)
readonly property color bodyColor: Qt.darker(Color.notifications.text, 1.15)
@@ -168,7 +168,7 @@ BorderSurface {
textFormat: Text.PlainText
Layout.fillWidth: true
visible: root.summary.length > 0
text: root.summary
text: I18n.tr(root.summary)
font.family: "Liberation Sans"
color: Color.notifications.text
font.pixelSize: Style.font.title
+2 -2
View File
@@ -90,7 +90,7 @@ Item {
font.family: Style.font.family
font.bold: true
font.pixelSize: Style.font.title
text: root.message
text: I18n.tr(root.message)
}
TextMetrics {
@@ -190,7 +190,7 @@ Item {
// a hole in the padding; the slack lands in the gap after the bar.
horizontalAlignment: root.hasProgress ? Text.AlignRight : Text.AlignLeft
anchors.verticalCenter: parent.verticalCenter
text: root.message
text: I18n.tr(root.message)
font: messageMetrics.font
color: Color.popups.text
elide: Text.ElideRight
+6 -6
View File
@@ -176,7 +176,7 @@ Panel {
readonly property bool hasOutput: !!(volumeSink && volumeSink.audio)
readonly property bool hasInput: !!(source && source.audio)
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, Color.accent)
@@ -434,7 +434,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) {
@@ -768,7 +768,7 @@ Panel {
spacing: Style.space(2)
Text {
text: "Audio"
text: I18n.tr("Audio")
color: root.bar.foreground
font.family: root.bar.fontFamily
font.pixelSize: Style.font.title
@@ -810,7 +810,7 @@ Panel {
PanelSectionHeader {
id: outputHeader
text: "OUTPUT"
text: I18n.tr("OUTPUT")
foreground: root.bar.foreground
fontFamily: root.bar.fontFamily
anchors.left: parent.left
@@ -897,7 +897,7 @@ Panel {
PanelSectionHeader {
id: microphoneHeader
text: "INPUT"
text: I18n.tr("INPUT")
foreground: root.bar.foreground
fontFamily: root.bar.fontFamily
anchors.left: parent.left
@@ -1000,7 +1000,7 @@ Panel {
visible: root.displayAudioStreams.length > 0
PanelSectionHeader {
text: "SOURCES"
text: I18n.tr("SOURCES")
foreground: root.bar.foreground
fontFamily: root.bar.fontFamily
}
+26 -26
View File
@@ -64,19 +64,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]
}
@@ -101,7 +101,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, Color.accent)
@@ -183,7 +183,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() {
@@ -738,7 +738,7 @@ Panel {
spacing: Style.space(2)
Text {
text: "Bluetooth"
text: I18n.tr("Bluetooth")
color: root.bar.foreground
font.family: root.bar.fontFamily
font.pixelSize: Style.font.title
@@ -775,7 +775,7 @@ Panel {
spacing: Style.space(10)
PanelSectionHeader {
text: "CONNECTED"
text: I18n.tr("CONNECTED")
foreground: root.bar.foreground
fontFamily: root.bar.fontFamily
}
@@ -867,9 +867,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
@@ -894,9 +894,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
@@ -911,13 +911,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 ""
}
@@ -994,7 +994,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
@@ -1019,7 +1019,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
+5 -3
View File
@@ -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()
+11 -13
View File
@@ -64,10 +64,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)
@@ -315,7 +313,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, Color.accent)
: root.contentForeground
@@ -338,7 +336,7 @@ Panel {
PanelToolTip {
visible: heroMouse.containsMouse
text: "Back to today"
text: I18n.tr("Back to today")
fontFamily: root.contentFontFamily
}
}
@@ -371,7 +369,7 @@ Panel {
Text {
anchors.verticalCenter: parent.verticalCenter
text: "BORN"
text: I18n.tr("BORN")
color: Qt.darker(root.contentForeground, 1.5)
font.family: root.contentFontFamily
font.pixelSize: Style.font.bodySmall
@@ -394,7 +392,7 @@ Panel {
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 0
leftPadding: Style.space(6)
text: "LIVE TO"
text: I18n.tr("LIVE TO")
color: Qt.darker(root.contentForeground, 1.5)
font.family: root.contentFontFamily
font.pixelSize: Style.font.bodySmall
@@ -481,7 +479,7 @@ Panel {
id: lifeLabel
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
text: "LIFE"
text: I18n.tr("LIFE")
color: Qt.darker(root.contentForeground, 1.5)
font.family: root.contentFontFamily
font.pixelSize: Style.font.bodySmall
@@ -600,7 +598,7 @@ Panel {
PanelToolTip {
visible: weekStartMouse.containsMouse
text: "Start weeks on " + root.nextWeekStartLabel
text: I18n.tr("Start weeks on %1", root.nextWeekStartLabel)
fontFamily: root.contentFontFamily
}
}
@@ -723,7 +721,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
@@ -737,7 +735,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)
@@ -748,7 +746,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)
+18 -18
View File
@@ -20,16 +20,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 : Color.foreground
@@ -37,7 +37,7 @@ 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"
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.
@@ -244,7 +244,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
@@ -304,7 +304,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: Model.usageText(dropbox.usedBytes, dropbox.quotaBytes, dropbox.quotaKnown) }
}
}
@@ -319,7 +319,7 @@ Panel {
spacing: Style.space(10)
PanelSectionHeader {
text: "RECENT FILES"
text: I18n.tr("RECENT FILES")
foreground: root.foreground
fontFamily: root.fontFamily
}
@@ -327,7 +327,7 @@ Panel {
Text {
visible: dropbox.files.length === 0
width: parent.width
text: "No synced files found."
text: I18n.tr("No synced files found.")
color: root.dim
font.family: root.fontFamily
font.pixelSize: Style.font.body
@@ -424,7 +424,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
@@ -434,7 +434,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
@@ -457,7 +457,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
@@ -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
}
+1 -1
View File
@@ -300,7 +300,7 @@ Rectangle {
color: Model.mix(Color.popups.background, row.foreground, _hot ? 0.24 : 0.14)
borderSpec: Border.flat(Model.mix(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
+1 -1
View File
@@ -17,7 +17,7 @@ Column {
property var offsetLabel: function(zoneId) { return "" }
property bool loading: false
property string buttonText: "+ Add a city"
property string placeholderText: "Search cities\u2026"
property string placeholderText: I18n.tr("Search cities…")
property string loadingText: "Loading zones\u2026"
property real fontSize: Style.font.bodySmall
property color foreground: Color.foreground
@@ -65,8 +65,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
}
+1 -1
View File
@@ -584,7 +584,7 @@ Item {
limit: 5
inlineResults: false
loading: root.jumpOptions.length === 0
buttonText: "Jump to a city"
buttonText: I18n.tr("Jump to a city")
loadingText: "Loading cities\u2026"
offsetLabel: function(zoneId) { return Model.utcOffsetLabel(root.offsets[zoneId]) }
foreground: root.foreground
+2 -2
View File
@@ -72,7 +72,7 @@ Column {
anchors.horizontalCenter: parent.horizontalCenter
spacing: Style.space(9)
TitleWord { text: "World" }
TitleWord { text: I18n.tr("World") }
Item {
id: heroIcon
@@ -150,7 +150,7 @@ Column {
}
}
TitleWord { text: "Clock" }
TitleWord { text: I18n.tr("Clock") }
}
component TitleWord: Text {
+2 -2
View File
@@ -334,7 +334,7 @@ Panel {
}
// No full stop: a period hanging off the arc reads as a speck.
readonly property string hereLine: "It's " + localTime + " here"
readonly property string hereLine: I18n.tr("It's %1 here", localTime)
+ (homeCity !== "" ? " in " + homeCity : "")
+ (scrubLabel !== "" ? " " + scrubLabel : "")
@@ -714,7 +714,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()
+7 -7
View File
@@ -555,7 +555,7 @@ Panel {
spacing: Style.space(2)
Text {
text: "Display"
text: I18n.tr("Display")
color: root.bar.foreground
font.family: root.bar.fontFamily
font.pixelSize: Style.font.title
@@ -569,9 +569,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
@@ -601,7 +601,7 @@ Panel {
PanelSectionHeader {
id: brightnessHeader
text: "BRIGHTNESS"
text: I18n.tr("BRIGHTNESS")
foreground: root.bar.foreground
fontFamily: root.bar.fontFamily
anchors.left: parent.left
@@ -674,7 +674,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
@@ -746,7 +746,7 @@ Panel {
PanelSectionHeader {
id: scaleHeader
text: "SCALE"
text: I18n.tr("SCALE")
foreground: root.bar.foreground
fontFamily: root.bar.fontFamily
anchors.left: parent.left
@@ -808,7 +808,7 @@ Panel {
visible: root.displays.length > 1
PanelSectionHeader {
text: "DISPLAYS"
text: I18n.tr("DISPLAYS")
foreground: root.bar.foreground
fontFamily: root.bar.fontFamily
}
+67 -63
View File
@@ -56,13 +56,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
@@ -137,7 +137,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.
@@ -159,7 +159,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.
@@ -279,11 +282,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
@@ -662,7 +666,7 @@ Panel {
}
function formatPingLatency(ms) {
return Model.formatPingLatency(ms, hasInternetPing)
return I18n.tr(Model.formatPingLatency(ms, hasInternetPing))
}
function formatPacketLoss(percent) {
@@ -709,7 +713,7 @@ Panel {
}
function wifiSectionTitle(index) {
return Model.wifiSectionTitle(wifiNetworks, index)
return I18n.tr(Model.wifiSectionTitle(wifiNetworks, index))
}
function wifiIconFor(strength) {
@@ -754,7 +758,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 }) : "{}")
}
@@ -835,7 +839,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()
@@ -1062,9 +1066,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 = ""
@@ -1079,8 +1083,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()
@@ -1249,7 +1253,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
iconSize: Style.font.subtitle * 1.5
@@ -1265,7 +1269,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
iconSize: Style.font.subtitle * 1.5
@@ -1316,8 +1320,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()
@@ -1334,15 +1338,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 !== ""
@@ -1365,7 +1369,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
@@ -1384,7 +1388,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
@@ -1410,38 +1414,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")
}
}
}
@@ -1482,7 +1486,7 @@ Panel {
PanelSectionHeader {
id: bandAutoLabel
text: "AUTOMATIC"
text: I18n.tr("AUTOMATIC")
foreground: root.bar.foreground
fontFamily: root.bar.fontFamily
anchors.verticalCenter: parent.verticalCenter
@@ -1515,8 +1519,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
}
}
@@ -1587,7 +1591,7 @@ Panel {
spacing: Style.space(10)
PanelSectionHeader {
text: "DNS PROVIDER"
text: I18n.tr("DNS PROVIDER")
foreground: root.bar.foreground
fontFamily: root.bar.fontFamily
}
@@ -1603,7 +1607,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)
}
@@ -1611,7 +1615,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)
}
@@ -1619,7 +1623,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)
}
@@ -1627,7 +1631,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)
}
@@ -1643,7 +1647,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
}
@@ -1746,7 +1750,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
@@ -1829,12 +1833,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 ""
}
@@ -1951,7 +1955,7 @@ Panel {
PanelToolTip {
visible: rightMouse.containsMouse || row.forgetFocused
text: "Forget network"
text: I18n.tr("Forget network")
fontFamily: root.bar.fontFamily
}
}
@@ -1967,7 +1971,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
@@ -2027,7 +2031,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
@@ -2053,7 +2057,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
@@ -2086,7 +2090,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
@@ -2103,7 +2107,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()
@@ -2114,7 +2118,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
+27 -27
View File
@@ -54,7 +54,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) {
@@ -94,26 +94,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
@@ -127,7 +127,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,7 @@ Panel {
spacing: Style.space(2)
Text {
text: "Battery"
text: I18n.tr("Battery")
color: root.bar.foreground
font.family: root.bar.fontFamily
font.pixelSize: Style.font.title
@@ -433,20 +433,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 +461,7 @@ Panel {
spacing: Style.space(10)
PanelSectionHeader {
text: "POWER PROFILE"
text: I18n.tr("POWER PROFILE")
foreground: root.bar.foreground
fontFamily: root.bar.fontFamily
}
+5 -5
View File
@@ -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
+30 -30
View File
@@ -24,16 +24,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]
@@ -52,7 +52,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, Color.accent) : "transparent"
readonly property color selectedFill: bar ? Style.selectedFillFor(bar.foreground, Color.accent) : "transparent"
@@ -76,7 +76,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
}
@@ -132,7 +132,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")
@@ -458,7 +458,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
@@ -501,7 +501,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
@@ -520,7 +520,7 @@ Panel {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.margins: Style.space(12)
text: "Tailscale CLI is not installed or not on PATH."
text: I18n.tr("Tailscale CLI is not installed or not on PATH.")
color: root.dim
font.family: root.fontFamily
font.pixelSize: Style.font.body
@@ -539,7 +539,7 @@ Panel {
spacing: Style.space(10)
PanelSectionHeader {
text: "CONNECTIONS"
text: I18n.tr("CONNECTIONS")
foreground: root.foreground
fontFamily: root.fontFamily
}
@@ -572,7 +572,7 @@ Panel {
spacing: Style.space(10)
PanelSectionHeader {
text: "EXIT NODES"
text: I18n.tr("EXIT NODES")
foreground: root.foreground
fontFamily: root.fontFamily
}
@@ -602,7 +602,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
@@ -638,7 +638,7 @@ Panel {
Text {
visible: root.filteredMullvadRegions.length === 0
width: parent.width
text: "No Mullvad regions found."
text: I18n.tr("No Mullvad regions found.")
color: root.dim
font.family: root.fontFamily
font.pixelSize: Style.font.bodySmall
@@ -676,7 +676,7 @@ Panel {
spacing: Style.space(10)
PanelSectionHeader {
text: "MACHINES"
text: I18n.tr("MACHINES")
foreground: root.foreground
fontFamily: root.fontFamily
}
@@ -684,7 +684,7 @@ Panel {
Text {
visible: tailscale.installed && tailscale.active && tailscale.peers.length === 0
width: parent.width
text: "No machines found on this tailnet."
text: I18n.tr("No machines found on this tailnet.")
color: root.dim
font.family: root.fontFamily
font.pixelSize: Style.font.body
@@ -777,7 +777,7 @@ Panel {
Text {
Layout.fillWidth: true
text: "Authorize Tailscale operator"
text: I18n.tr("Authorize Tailscale operator")
color: root.foreground
font.family: root.fontFamily
font.pixelSize: Style.font.body
@@ -786,7 +786,7 @@ Panel {
Text {
Layout.fillWidth: true
text: "Allow this user to operate this Tailscale profile"
text: I18n.tr("Allow this user to operate this Tailscale profile")
color: root.dim
font.family: root.fontFamily
font.pixelSize: Style.font.caption
@@ -803,7 +803,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
@@ -867,7 +867,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 ""
@@ -978,7 +978,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
@@ -1118,8 +1118,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)
@@ -1199,7 +1199,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
+5 -5
View File
@@ -616,7 +616,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
@@ -683,7 +683,7 @@ Panel {
Column {
spacing: Style.space(5)
Text {
text: "FEELS"
text: I18n.tr("FEELS")
color: Qt.darker(root.bar.foreground, 1.5)
font.family: root.bar.fontFamily
font.pixelSize: Style.font.bodySmall
@@ -701,7 +701,7 @@ Panel {
Column {
spacing: Style.space(5)
Text {
text: "WIND"
text: I18n.tr("WIND")
color: Qt.darker(root.bar.foreground, 1.5)
font.family: root.bar.fontFamily
font.pixelSize: Style.font.bodySmall
@@ -719,7 +719,7 @@ Panel {
Column {
spacing: Style.space(5)
Text {
text: "HUMID"
text: I18n.tr("HUMID")
color: Qt.darker(root.bar.foreground, 1.5)
font.family: root.bar.fontFamily
font.pixelSize: Style.font.bodySmall
@@ -792,7 +792,7 @@ Panel {
Text {
visible: !root.current
text: "Fetching forecast…"
text: I18n.tr("Fetching forecast…")
color: Qt.darker(root.bar.foreground, 1.5)
font.family: root.bar.fontFamily
font.pixelSize: Style.font.bodySmall
+5 -5
View File
@@ -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,7 @@ Item {
Text {
visible: root.loading
text: "Generating QR code…"
text: I18n.tr("Generating QR code…")
color: root.onScrimDim
font.family: root.fontFamily
font.pixelSize: Style.font.bodySmall
@@ -328,7 +328,7 @@ Item {
Text {
visible: root.showingQr
text: "Scan to join this network"
text: I18n.tr("Scan to join this network")
color: root.onScrimDim
font.family: root.fontFamily
font.pixelSize: Style.font.bodySmall
@@ -341,7 +341,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
+2 -2
View File
@@ -78,7 +78,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
@@ -336,7 +336,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 ? Color.polkit.textError : root.foreground
opacity: root.errorFlash ? 1 : 0.36
font.family: root.fontFamily
+1 -1
View File
@@ -28,7 +28,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 = ({})
+1 -1
View File
@@ -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()