noctalia-plugin: captures as streams (no 5 s timeout), valw's error message in notifications, full state on every --set
This commit is contained in:
1 parent
9fa71fd399
commit
619eab9dc9
11 files changed
+234
-81
No files matched your search
@@ -1247,7 +1247,7 @@ noctalia msg plugins enable elars/valw
|
||||
noctalia msg panel-toggle elars/valw:toolbar
|
||||
```
|
||||
|
||||
Expected: the panel appears near the bar with the four modes, the timer and three toggles, in Noctalia's style. Ask the user to confirm what they see, then close it (`noctalia msg panel-close`). Check `grep -i valw ~/.cache/noctalia/noctalia.log | tail -20` for Luau errors (unknown glyph names, bad props); fix any in the plugin, rerun Task 3's tests, and commit (`jj commit -m "noctalia-plugin: fixes from the live Noctalia" noctalia-plugin`).
|
||||
Expected: the panel appears near the bar with the four modes, the timer and three toggles, in Noctalia's style. Ask the user to confirm what they see, then close it (`noctalia msg panel-close`). With the user's go-ahead, also take two real shots from the panel: one with the timer at 5 s (the countdown runs, the shot lands, no error notification) and one Region shot held open for more than 6 s before selecting (it must not be killed). Check that nothing is clipped at 360×220 (the "Play sound" row, the four mode buttons in Turkish); adjust `width`/`height` in `plugin.toml` if needed. Check `grep -i valw ~/.cache/noctalia/noctalia.log | tail -20` for Luau errors (unknown glyph names, bad props); fix any in the plugin, rerun Task 3's tests, and commit (`jj commit -m "noctalia-plugin: fixes from the live Noctalia" noctalia-plugin`).
|
||||
|
||||
- [ ] **Step 4: Undo the dev install**
|
||||
|
||||
|
||||
@@ -89,18 +89,23 @@ about 360 × 220.
|
||||
- On open (`onOpen`): `valw toolbar --state` → `noctalia.json.decode` →
|
||||
render. If valw is missing (`noctalia.commandExists`) or the call fails:
|
||||
a single label "valw is not available" and `noctalia.notifyError` with
|
||||
the stderr's last line.
|
||||
valw's error message (its `error:` line).
|
||||
- A row of four buttons with glyphs and labels: Screen (`device-desktop`),
|
||||
Region (`crop`), Window (`app-window`), Zoom (`zoom-in`). The
|
||||
remembered mode is `variant = "primary"`, the others `"outline"`.
|
||||
- A click on a mode: `panel.close()`, then
|
||||
`sleep 0.3 && valw toolbar --run <mode>` (the wait lets the panel
|
||||
disappear before the screen is frozen or captured). A non-zero exit
|
||||
other than 3 → `noctalia.notifyError("valw", <stderr's last line>)`.
|
||||
disappear before the screen is frozen or captured). Captures run with
|
||||
`noctalia.runStream` (stderr folded in, the exit status echoed last):
|
||||
`runAsync` with a callback kills its command after 5 s, and a region,
|
||||
a zoom or the timer can take longer. A non-zero exit other than 3 →
|
||||
`noctalia.notifyError("valw", <valw's error: line>)`.
|
||||
- Below: "Timer" `ui.select` with `Off`, `5 s`, `10 s` (from `timers`),
|
||||
and three `ui.toggle`s: "Show cursor", "Show preview", "Play sound".
|
||||
A change re-renders at once and runs `valw toolbar --set <key>=<value>`;
|
||||
a failure → `notifyError`.
|
||||
A change re-renders at once and runs `valw toolbar --set` with every
|
||||
choice (so two quick changes can't undo each other); a failure →
|
||||
`notifyError`. `--state` and `--set` start no run log (they would push
|
||||
the capture logs out).
|
||||
- Colours only by Noctalia role names (`primary`, `on_surface`,
|
||||
`outline`, …); no hex colours anywhere in the plugin.
|
||||
|
||||
|
||||
+25
-10
@@ -5,18 +5,33 @@
|
||||
|
||||
local PANEL = "elars/valw:toolbar"
|
||||
|
||||
local function lastLine(text)
|
||||
local last = ""
|
||||
for line in string.gmatch(text or "", "[^\n]+") do
|
||||
last = line
|
||||
-- valw's stderr on an error starts with "error: <message>", then cause,
|
||||
-- hint and log lines.
|
||||
local function errorMessage(lines)
|
||||
for _, line in ipairs(lines) do
|
||||
local message = string.match(line, "^error: (.+)$")
|
||||
if message then
|
||||
return message
|
||||
end
|
||||
return last
|
||||
end
|
||||
return noctalia.tr("error.failed")
|
||||
end
|
||||
|
||||
-- Exit 3 is a cancel (Esc): not an error.
|
||||
local function report(result)
|
||||
if result.exitCode ~= 0 and result.exitCode ~= 3 then
|
||||
noctalia.notifyError("valw", lastLine(result.stderr))
|
||||
-- A capture lasts as long as the user takes (a region, a zoom, the timer),
|
||||
-- so it runs as a stream: runAsync with a callback kills its command after
|
||||
-- 5 s. stderr joins the stream and the exit status comes last.
|
||||
local function capture(command)
|
||||
local lines = {}
|
||||
local started = noctalia.runStream("(" .. command .. ") 2>&1; echo valw-exit:$?", function(line)
|
||||
local code = string.match(line, "^valw%-exit:(%d+)$")
|
||||
if code == nil then
|
||||
table.insert(lines, line)
|
||||
elseif code ~= "0" and code ~= "3" then
|
||||
noctalia.notifyError("valw", errorMessage(lines))
|
||||
end
|
||||
end)
|
||||
if not started then
|
||||
noctalia.notifyError("valw", noctalia.tr("error.failed"))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -32,5 +47,5 @@ function onClick()
|
||||
end
|
||||
|
||||
function onRightClick()
|
||||
noctalia.runAsync("valw region", report)
|
||||
capture("valw region")
|
||||
end
|
||||
+49
-15
@@ -11,38 +11,71 @@ local MODES = {
|
||||
{ id = "zoom", glyph = "zoom-in" },
|
||||
}
|
||||
local OPTIONS = { "cursor", "preview", "sound" }
|
||||
local KEYS = { "mode", "timer", "cursor", "preview", "sound" }
|
||||
|
||||
-- The decoded `--state` JSON; nil until it arrives.
|
||||
local state = nil
|
||||
local unavailable = false
|
||||
|
||||
local function lastLine(text)
|
||||
local last = ""
|
||||
for line in string.gmatch(text or "", "[^\n]+") do
|
||||
last = line
|
||||
-- valw's stderr on an error starts with "error: <message>", then cause,
|
||||
-- hint and log lines.
|
||||
local function errorMessage(lines)
|
||||
for _, line in ipairs(lines) do
|
||||
local message = string.match(line, "^error: (.+)$")
|
||||
if message then
|
||||
return message
|
||||
end
|
||||
return last
|
||||
end
|
||||
return noctalia.tr("error.failed")
|
||||
end
|
||||
|
||||
local function linesOf(text)
|
||||
local lines = {}
|
||||
for line in string.gmatch(text or "", "[^\n]+") do
|
||||
table.insert(lines, line)
|
||||
end
|
||||
return lines
|
||||
end
|
||||
|
||||
-- Exit 3 is a cancel (Esc): not an error.
|
||||
local function report(result)
|
||||
if result.exitCode ~= 0 and result.exitCode ~= 3 then
|
||||
noctalia.notifyError("valw", lastLine(result.stderr))
|
||||
noctalia.notifyError("valw", errorMessage(linesOf(result.stderr)))
|
||||
end
|
||||
end
|
||||
|
||||
-- A capture lasts as long as the user takes (a region, a zoom, the timer),
|
||||
-- so it runs as a stream: runAsync with a callback kills its command after
|
||||
-- 5 s. stderr joins the stream and the exit status comes last.
|
||||
local function capture(command)
|
||||
local lines = {}
|
||||
local started = noctalia.runStream("(" .. command .. ") 2>&1; echo valw-exit:$?", function(line)
|
||||
local code = string.match(line, "^valw%-exit:(%d+)$")
|
||||
if code == nil then
|
||||
table.insert(lines, line)
|
||||
elseif code ~= "0" and code ~= "3" then
|
||||
noctalia.notifyError("valw", errorMessage(lines))
|
||||
end
|
||||
end)
|
||||
if not started then
|
||||
noctalia.notifyError("valw", noctalia.tr("error.failed"))
|
||||
end
|
||||
end
|
||||
|
||||
local render
|
||||
|
||||
local function capture(mode)
|
||||
panel.close()
|
||||
noctalia.runAsync("sleep 0.3 && valw toolbar --run " .. mode, report)
|
||||
end
|
||||
|
||||
-- `key` and `value` are always one of our own tokens, never user text.
|
||||
-- Every choice goes with every --set, not just the changed one: each
|
||||
-- --set loads, changes and saves the file, so two quick changes sending
|
||||
-- one key each could undo each other. The values are valw's own tokens
|
||||
-- (from --state or our lists), never user text.
|
||||
local function remember(key, value)
|
||||
state[key] = value
|
||||
render()
|
||||
noctalia.runAsync("valw toolbar --set " .. key .. "=" .. tostring(value), report)
|
||||
local sets = {}
|
||||
for _, k in ipairs(KEYS) do
|
||||
table.insert(sets, "--set " .. k .. "=" .. tostring(state[k]))
|
||||
end
|
||||
noctalia.runAsync("valw toolbar " .. table.concat(sets, " "), report)
|
||||
end
|
||||
|
||||
local function modeButton(m)
|
||||
@@ -51,7 +84,8 @@ local function modeButton(m)
|
||||
glyph = m.glyph,
|
||||
variant = if state.mode == m.id then "primary" else "outline",
|
||||
onClick = function()
|
||||
capture(m.id)
|
||||
panel.close()
|
||||
capture("sleep 0.3 && valw toolbar --run " .. m.id)
|
||||
end,
|
||||
})
|
||||
end
|
||||
@@ -123,7 +157,7 @@ function onOpen(_context)
|
||||
end
|
||||
noctalia.runAsync("valw toolbar --state", function(result)
|
||||
if result.exitCode ~= 0 then
|
||||
fail(lastLine(result.stderr))
|
||||
fail(errorMessage(linesOf(result.stderr)))
|
||||
return
|
||||
end
|
||||
local decoded = noctalia.json.decode(result.stdout)
|
||||
|
||||
@@ -4,18 +4,33 @@
|
||||
|
||||
local PANEL = "elars/valw:toolbar"
|
||||
|
||||
local function lastLine(text)
|
||||
local last = ""
|
||||
for line in string.gmatch(text or "", "[^\n]+") do
|
||||
last = line
|
||||
-- valw's stderr on an error starts with "error: <message>", then cause,
|
||||
-- hint and log lines.
|
||||
local function errorMessage(lines)
|
||||
for _, line in ipairs(lines) do
|
||||
local message = string.match(line, "^error: (.+)$")
|
||||
if message then
|
||||
return message
|
||||
end
|
||||
return last
|
||||
end
|
||||
return noctalia.tr("error.failed")
|
||||
end
|
||||
|
||||
-- Exit 3 is a cancel (Esc): not an error.
|
||||
local function report(result)
|
||||
if result.exitCode ~= 0 and result.exitCode ~= 3 then
|
||||
noctalia.notifyError("valw", lastLine(result.stderr))
|
||||
-- A capture lasts as long as the user takes (a region, a zoom, the timer),
|
||||
-- so it runs as a stream: runAsync with a callback kills its command after
|
||||
-- 5 s. stderr joins the stream and the exit status comes last.
|
||||
local function capture(command)
|
||||
local lines = {}
|
||||
local started = noctalia.runStream("(" .. command .. ") 2>&1; echo valw-exit:$?", function(line)
|
||||
local code = string.match(line, "^valw%-exit:(%d+)$")
|
||||
if code == nil then
|
||||
table.insert(lines, line)
|
||||
elseif code ~= "0" and code ~= "3" then
|
||||
noctalia.notifyError("valw", errorMessage(lines))
|
||||
end
|
||||
end)
|
||||
if not started then
|
||||
noctalia.notifyError("valw", noctalia.tr("error.failed"))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -23,7 +38,7 @@ shortcut.setLabel(noctalia.tr("tile.label"))
|
||||
shortcut.setIcon("camera", "camera")
|
||||
|
||||
function onClick()
|
||||
noctalia.runAsync("noctalia msg panel-close; sleep 0.3 && valw region", report)
|
||||
capture("noctalia msg panel-close >/dev/null 2>&1; sleep 0.3 && valw region")
|
||||
end
|
||||
|
||||
function onRightClick()
|
||||
|
||||
@@ -7,18 +7,19 @@ ok("renders")
|
||||
|
||||
onClick()
|
||||
assert(calls.toggled[1] == "elars/valw:toolbar", "left click toggles the panel")
|
||||
assert(#calls.run == 0)
|
||||
assert(#calls.run == 0 and #calls.stream == 0)
|
||||
ok("left click")
|
||||
|
||||
reset()
|
||||
onRightClick()
|
||||
assert(calls.run[1] == "valw region", calls.run[1])
|
||||
assert(calls.stream[1] == "(valw region) 2>&1; echo valw-exit:$?", calls.stream[1])
|
||||
assert(#calls.run == 0, "never through runAsync's timeout")
|
||||
reset()
|
||||
fake.answers["valw region"] = { exitCode = 1, stdout = "", stderr = "error: busy\n" }
|
||||
fake.streams["(valw region)"] = valwFailure("busy", 1)
|
||||
onRightClick()
|
||||
assert(calls.notify[1][2] == "error: busy", "failure notified")
|
||||
assert(calls.notify[1][2] == "busy", "failure notified")
|
||||
reset()
|
||||
fake.answers["valw region"] = { exitCode = 3, stdout = "", stderr = "" }
|
||||
fake.streams["(valw region)"] = { "valw-exit:3" }
|
||||
onRightClick()
|
||||
assert(#calls.notify == 0, "cancel is silent")
|
||||
ok("right click")
|
||||
@@ -12,13 +12,13 @@ assert(#calls.notify == 1, "notified once")
|
||||
assert(#calls.run == 0, "nothing run")
|
||||
ok("valw missing")
|
||||
|
||||
-- --state failing: the same.
|
||||
-- --state failing: the same, with valw's error message (not its log line).
|
||||
reset()
|
||||
fake.exists = true
|
||||
fake.answers["valw toolbar --state"] = { exitCode = 1, stdout = "", stderr = "warn\nerror: broken\n" }
|
||||
fake.answers["valw toolbar --state"] = { exitCode = 1, stdout = "", stderr = valwError("broken config") }
|
||||
onOpen(nil)
|
||||
assert(findAll(rendered, function(n) return n.kind == "label" and n.props.text == "panel.unavailable" end)[1], "label")
|
||||
assert(calls.notify[1][2] == "error: broken", "the stderr's last line: " .. tostring(calls.notify[1][2]))
|
||||
assert(calls.notify[1][2] == "broken config", "valw's message: " .. tostring(calls.notify[1][2]))
|
||||
ok("--state failing")
|
||||
|
||||
-- A working valw: the remembered mode is primary, the timer selected.
|
||||
@@ -46,42 +46,56 @@ end)
|
||||
assert(#hex == 0, "no hex colours")
|
||||
ok("renders the state")
|
||||
|
||||
-- A mode click closes the panel first, then captures after the wait.
|
||||
-- A mode click closes the panel first, then captures after the wait, as a
|
||||
-- stream (no timeout: a region or a timer can take longer than 5 s).
|
||||
reset()
|
||||
button("mode.region").props.onClick()
|
||||
assert(calls.order[1] == "close" and calls.order[2] == "run", "close, then run")
|
||||
assert(calls.run[1] == "sleep 0.3 && valw toolbar --run region", calls.run[1])
|
||||
assert(calls.order[1] == "close" and calls.order[2] == "stream", "close, then capture")
|
||||
assert(calls.stream[1] == "(sleep 0.3 && valw toolbar --run region) 2>&1; echo valw-exit:$?", calls.stream[1])
|
||||
assert(#calls.run == 0, "never through runAsync's timeout")
|
||||
assert(#calls.notify == 0, "success is silent")
|
||||
ok("mode click")
|
||||
|
||||
-- A failed capture notifies; a cancelled one doesn't.
|
||||
-- A failed capture notifies with valw's message; a cancel doesn't; a
|
||||
-- failure without a message gets a generic one.
|
||||
reset()
|
||||
fake.answers["sleep 0.3 && valw toolbar --run"] = { exitCode = 1, stdout = "", stderr = "error: no outputs\n" }
|
||||
fake.streams["(sleep 0.3 && valw toolbar --run"] = valwFailure("no outputs", 1)
|
||||
button("mode.screen").props.onClick()
|
||||
assert(calls.notify[1][2] == "error: no outputs", "failure notified")
|
||||
assert(calls.notify[1][2] == "no outputs", "failure notified: " .. tostring(calls.notify[1][2]))
|
||||
reset()
|
||||
fake.answers["sleep 0.3 && valw toolbar --run"] = { exitCode = 3, stdout = "", stderr = "" }
|
||||
fake.streams["(sleep 0.3 && valw toolbar --run"] = { "valw-exit:3" }
|
||||
button("mode.window").props.onClick()
|
||||
assert(#calls.notify == 0, "cancel is silent")
|
||||
reset()
|
||||
fake.streams["(sleep 0.3 && valw toolbar --run"] = { "valw-exit:143" }
|
||||
button("mode.window").props.onClick()
|
||||
assert(calls.notify[1][2] == "error.failed", "a generic message")
|
||||
fake.streams["(sleep 0.3 && valw toolbar --run"] = nil
|
||||
ok("capture results")
|
||||
|
||||
-- The timer and the toggles write through --set and re-render at once.
|
||||
-- The timer and the toggles re-render at once and send every choice, so
|
||||
-- two quick changes can't undo each other.
|
||||
reset()
|
||||
fake.answers["sleep 0.3 && valw toolbar --run"] = nil
|
||||
select = findAll(rendered, function(n) return n.kind == "select" end)[1]
|
||||
select.props.onChange("2")
|
||||
assert(calls.run[1] == "valw toolbar --set timer=10", calls.run[1])
|
||||
assert(
|
||||
calls.run[1] == "valw toolbar --set mode=zoom --set timer=10 --set cursor=false --set preview=true --set sound=true",
|
||||
calls.run[1]
|
||||
)
|
||||
select = findAll(rendered, function(n) return n.kind == "select" end)[1]
|
||||
assert(select.props.selectedIndex == 2, "re-rendered with 10 s")
|
||||
reset()
|
||||
toggles = findAll(rendered, function(n) return n.kind == "toggle" end)
|
||||
toggles[3].props.onChange("false")
|
||||
assert(calls.run[1] == "valw toolbar --set sound=false", calls.run[1])
|
||||
assert(
|
||||
calls.run[1] == "valw toolbar --set mode=zoom --set timer=10 --set cursor=false --set preview=true --set sound=false",
|
||||
calls.run[1]
|
||||
)
|
||||
toggles = findAll(rendered, function(n) return n.kind == "toggle" end)
|
||||
assert(toggles[3].props.checked == false, "re-rendered with sound off")
|
||||
reset()
|
||||
fake.answers["valw toolbar --set"] = { exitCode = 1, stdout = "", stderr = "error: read-only\n" }
|
||||
fake.answers["valw toolbar --set"] = { exitCode = 1, stdout = "", stderr = valwError("read-only file system") }
|
||||
toggles[1].props.onChange("true")
|
||||
assert(calls.run[1] == "valw toolbar --set cursor=true", calls.run[1])
|
||||
assert(calls.notify[1][2] == "error: read-only", "a failed --set notifies")
|
||||
assert(string.find(calls.run[1], "--set cursor=true", 1, true), calls.run[1])
|
||||
assert(calls.notify[1][2] == "read-only file system", "a failed --set notifies")
|
||||
ok("timer and toggles")
|
||||
@@ -2,13 +2,17 @@
|
||||
-- The control-center tile. Runs after stubs.luau and shortcut.luau.
|
||||
|
||||
onClick()
|
||||
assert(calls.run[1] == "noctalia msg panel-close; sleep 0.3 && valw region", calls.run[1])
|
||||
assert(
|
||||
calls.stream[1] == "(noctalia msg panel-close >/dev/null 2>&1; sleep 0.3 && valw region) 2>&1; echo valw-exit:$?",
|
||||
calls.stream[1]
|
||||
)
|
||||
assert(#calls.run == 0, "never through runAsync's timeout")
|
||||
reset()
|
||||
fake.answers["noctalia msg panel-close"] = { exitCode = 1, stdout = "", stderr = "error: busy\n" }
|
||||
fake.streams["(noctalia msg panel-close"] = valwFailure("busy", 1)
|
||||
onClick()
|
||||
assert(calls.notify[1][2] == "error: busy", "failure notified")
|
||||
assert(calls.notify[1][2] == "busy", "failure notified")
|
||||
reset()
|
||||
fake.answers["noctalia msg panel-close"] = { exitCode = 3, stdout = "", stderr = "" }
|
||||
fake.streams["(noctalia msg panel-close"] = { "valw-exit:3" }
|
||||
onClick()
|
||||
assert(#calls.notify == 0, "cancel is silent")
|
||||
ok("click")
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
-- Stand-ins for Noctalia's globals. Each test is run as one chunk:
|
||||
-- these stubs, then the entry script, then the test (see run.sh).
|
||||
|
||||
calls = { run = {}, notify = {}, toggled = {}, closed = 0, order = {} }
|
||||
calls = { run = {}, stream = {}, notify = {}, toggled = {}, closed = 0, order = {} }
|
||||
fake = {
|
||||
exists = true,
|
||||
-- runAsync answers by command prefix: { exitCode, stdout, stderr }
|
||||
answers = {},
|
||||
-- runStream lines by command prefix; default: a clean exit
|
||||
streams = {},
|
||||
decoded = nil,
|
||||
}
|
||||
rendered = nil
|
||||
@@ -38,6 +40,17 @@ noctalia = {
|
||||
end
|
||||
return true
|
||||
end,
|
||||
-- No timeout here (runAsync with a callback kills after 5 s): captures.
|
||||
runStream = function(command, onLine)
|
||||
table.insert(calls.stream, command)
|
||||
table.insert(calls.order, "stream")
|
||||
local lines = { "valw-exit:0" }
|
||||
for prefix, l in pairs(fake.streams) do
|
||||
if string.sub(command, 1, #prefix) == prefix then lines = l end
|
||||
end
|
||||
for _, line in ipairs(lines) do onLine(line) end
|
||||
return true
|
||||
end,
|
||||
notifyError = function(title, body) table.insert(calls.notify, { title, body }) end,
|
||||
togglePanel = function(id) table.insert(calls.toggled, id) end,
|
||||
json = { decode = function(_text) return fake.decoded end },
|
||||
@@ -77,7 +90,17 @@ function button(text)
|
||||
end
|
||||
|
||||
function reset()
|
||||
calls = { run = {}, notify = {}, toggled = {}, closed = 0, order = {} }
|
||||
calls = { run = {}, stream = {}, notify = {}, toggled = {}, closed = 0, order = {} }
|
||||
end
|
||||
|
||||
-- valw's stderr on an error: the message first, then cause, hint and log.
|
||||
function valwError(message)
|
||||
return "error: " .. message .. "\n cause: something\n log: /home/u/.local/state/valw/logs/x.log\n"
|
||||
end
|
||||
|
||||
-- The same as stream lines, ending with the exit status.
|
||||
function valwFailure(message, code)
|
||||
return { "error: " .. message, " log: /home/u/.local/state/valw/logs/x.log", "valw-exit:" .. code }
|
||||
end
|
||||
|
||||
function ok(name)
|
||||
|
||||
@@ -1,8 +1,29 @@
|
||||
{
|
||||
"bar": { "tooltip": "Screenshot" },
|
||||
"tile": { "label": "Screenshot" },
|
||||
"panel": { "unavailable": "valw is not available" },
|
||||
"mode": { "screen": "Screen", "region": "Region", "window": "Window", "zoom": "Zoom" },
|
||||
"timer": { "label": "Timer", "off": "Off" },
|
||||
"option": { "cursor": "Show cursor", "preview": "Show preview", "sound": "Play sound" }
|
||||
"bar": {
|
||||
"tooltip": "Screenshot"
|
||||
},
|
||||
"tile": {
|
||||
"label": "Screenshot"
|
||||
},
|
||||
"panel": {
|
||||
"unavailable": "valw is not available"
|
||||
},
|
||||
"mode": {
|
||||
"screen": "Screen",
|
||||
"region": "Region",
|
||||
"window": "Window",
|
||||
"zoom": "Zoom"
|
||||
},
|
||||
"timer": {
|
||||
"label": "Timer",
|
||||
"off": "Off"
|
||||
},
|
||||
"option": {
|
||||
"cursor": "Show cursor",
|
||||
"preview": "Show preview",
|
||||
"sound": "Play sound"
|
||||
},
|
||||
"error": {
|
||||
"failed": "valw failed"
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,29 @@
|
||||
{
|
||||
"bar": { "tooltip": "Ekran görüntüsü" },
|
||||
"tile": { "label": "Ekran görüntüsü" },
|
||||
"panel": { "unavailable": "valw bulunamadı" },
|
||||
"mode": { "screen": "Ekran", "region": "Bölge", "window": "Pencere", "zoom": "Yakınlaştır" },
|
||||
"timer": { "label": "Zamanlayıcı", "off": "Kapalı" },
|
||||
"option": { "cursor": "İmleci göster", "preview": "Önizlemeyi göster", "sound": "Ses çal" }
|
||||
"bar": {
|
||||
"tooltip": "Ekran görüntüsü"
|
||||
},
|
||||
"tile": {
|
||||
"label": "Ekran görüntüsü"
|
||||
},
|
||||
"panel": {
|
||||
"unavailable": "valw bulunamadı"
|
||||
},
|
||||
"mode": {
|
||||
"screen": "Ekran",
|
||||
"region": "Bölge",
|
||||
"window": "Pencere",
|
||||
"zoom": "Yakınlaştır"
|
||||
},
|
||||
"timer": {
|
||||
"label": "Zamanlayıcı",
|
||||
"off": "Kapalı"
|
||||
},
|
||||
"option": {
|
||||
"cursor": "İmleci göster",
|
||||
"preview": "Önizlemeyi göster",
|
||||
"sound": "Ses çal"
|
||||
},
|
||||
"error": {
|
||||
"failed": "valw başarısız oldu"
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user