From 5375b4534d22ba147326babdb2cd8c4f05139a09 Mon Sep 17 00:00:00 2001 From: Dave Date: Mon, 27 Jul 2026 03:59:57 +0200 Subject: [PATCH 1/4] fix(startup): stop listing programs that are no longer installed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Startup entries could persist after the program was uninstalled, with no way for the user to clear them (#245). Disabling an item deletes its Run value and records it in disabled-startups.json, which is the only remaining trace of it. If the program was later uninstalled, that record kept re-creating the entry on every scan — surviving registry cleaning and even a Kudu reinstall, since the file lives in userData. Entries whose program is verifiably gone are now pruned from the file while the list is built. Registry, Task Scheduler and Startup-folder entries that point at a missing executable are flagged as stale so the leftovers Windows itself still honours are visible and can be removed. Detection is deliberately conservative: unresolvable commands, unknown environment variables, UNC paths, unmounted volumes and anything under the Windows directory are never treated as missing. Also: - deleting a scheduled task that is already gone now succeeds instead of failing and leaving the item stuck in the list - the Startup page re-reads its items on mount, so changes made outside the app are picked up instead of showing the previous visit's list --- src/main/ipc/startup-manager.ipc.test.ts | 200 +++++++++++++++++++++++ src/main/ipc/startup-manager.ipc.ts | 116 ++++++++++++- src/renderer/src/locales/en/startup.json | 4 +- src/renderer/src/pages/StartupPage.tsx | 18 +- src/shared/types.ts | 2 + 5 files changed, 327 insertions(+), 13 deletions(-) diff --git a/src/main/ipc/startup-manager.ipc.test.ts b/src/main/ipc/startup-manager.ipc.test.ts index a44b9a06..66f04c51 100644 --- a/src/main/ipc/startup-manager.ipc.test.ts +++ b/src/main/ipc/startup-manager.ipc.test.ts @@ -60,6 +60,7 @@ vi.mock('fs', () => ({ // ── Mock electron ─────────────────────────────────────────────────── const mockHandlers = new Map() +const mockReadShortcutLink = vi.fn() vi.mock('electron', () => ({ app: { isPackaged: false, @@ -74,6 +75,9 @@ vi.mock('electron', () => ({ mockHandlers.set(channel, handler) }, }, + shell: { + readShortcutLink: (...args: unknown[]) => mockReadShortcutLink(...args), + }, })) // ── Mock platform ─────────────────────────────────────────────────── @@ -170,6 +174,7 @@ beforeEach(() => { mockExistsSync.mockReturnValue(false) mockReadFileSync.mockReturnValue('[]') mockReaddirSync.mockReturnValue([]) + mockReadShortcutLink.mockReturnValue(undefined) // Default: all execFile calls fail (registry keys don't exist) mockExecFile.mockImplementation((_cmd: string, _args: string[], _opts: any, cb: Function) => { cb(new Error('not found'), '', '') @@ -611,6 +616,191 @@ describe('listStartupItems', () => { }) }) +// ===================================================================== +// Stale entries — programs that are no longer installed (issue #245) +// ===================================================================== + +describe('stale startup entries', () => { + const DISABLED_FILE = 'disabled-startups.json' + const GHOST_CMD = '"C:\\Users\\User\\AppData\\Local\\DuckDuckGo\\DuckDuckGo.exe"' + + /** existsSync mock where only the listed paths (plus the C: volume) exist */ + function onlyExisting(...paths: string[]) { + mockExistsSync.mockImplementation((p: string) => + p === 'C:\\' || paths.some((x) => p === x || (p as string).endsWith(x)) + ) + } + + function lastWrittenDisabledFile(): any[] { + const calls = mockWriteFileSync.mock.calls + return JSON.parse(calls[calls.length - 1][1] as string) + } + + describe('disabled-file pruning', () => { + it('drops a disabled entry whose program has been uninstalled', async () => { + onlyExisting(DISABLED_FILE) + mockReadFileSync.mockReturnValue(JSON.stringify([ + { name: 'DuckDuckGo', command: GHOST_CMD, location: HKCU_RUN, source: 'registry-hkcu' }, + ])) + + const items = await listStartupItems() + expect(items.find((i) => i.name === 'DuckDuckGo')).toBeUndefined() + // The stale record is removed from disk so it cannot come back + expect(lastWrittenDisabledFile()).toEqual([]) + }) + + it('keeps a disabled entry while its program is still installed', async () => { + onlyExisting(DISABLED_FILE, 'C:\\Users\\User\\AppData\\Local\\DuckDuckGo\\DuckDuckGo.exe') + mockReadFileSync.mockReturnValue(JSON.stringify([ + { name: 'DuckDuckGo', command: GHOST_CMD, location: HKCU_RUN, source: 'registry-hkcu' }, + ])) + + const items = await listStartupItems() + const ghost = items.find((i) => i.name === 'DuckDuckGo') + expect(ghost).toBeDefined() + expect(ghost!.enabled).toBe(false) + expect(mockWriteFileSync).not.toHaveBeenCalled() + }) + + it('keeps a disabled entry whose target cannot be resolved', async () => { + onlyExisting(DISABLED_FILE) + mockReadFileSync.mockReturnValue(JSON.stringify([ + { name: 'Helper', command: 'rundll32.exe C:\\App\\helper.dll,Start', location: HKCU_RUN, source: 'registry-hkcu' }, + ])) + + const items = await listStartupItems() + expect(items.find((i) => i.name === 'Helper')).toBeDefined() + expect(mockWriteFileSync).not.toHaveBeenCalled() + }) + + it('keeps a disabled entry when its volume is not mounted', async () => { + // Only the JSON file exists — the D: volume is absent, so "missing" is unknown + mockExistsSync.mockImplementation((p: string) => (p as string).endsWith(DISABLED_FILE)) + mockReadFileSync.mockReturnValue(JSON.stringify([ + { name: 'PortableApp', command: '"D:\\Portable\\app.exe"', location: HKCU_RUN, source: 'registry-hkcu' }, + ])) + + const items = await listStartupItems() + expect(items.find((i) => i.name === 'PortableApp')).toBeDefined() + expect(mockWriteFileSync).not.toHaveBeenCalled() + }) + + it('keeps a disabled entry that still has a live registry value', async () => { + onlyExisting(DISABLED_FILE) + mockReadFileSync.mockReturnValue(JSON.stringify([ + { name: 'Discord', command: '"C:\\Discord\\Discord.exe"', location: HKCU_RUN, source: 'registry-hkcu' }, + ])) + setupExecFileHandler((cmd, args) => { + if (cmd === 'reg' && args[1] === HKCU_RUN) { + return { stdout: regOutput([{ name: 'Discord', command: '"C:\\Discord\\Discord.exe"' }]) } + } + throw new Error('not found') + }) + + const items = await listStartupItems() + const discord = items.find((i) => i.name === 'Discord') + expect(discord).toBeDefined() + expect(discord!.enabled).toBe(false) + expect(mockWriteFileSync).not.toHaveBeenCalled() + }) + }) + + describe('stale flag', () => { + it('flags a registry item whose executable is gone', async () => { + onlyExisting() + setupExecFileHandler((cmd, args) => { + if (cmd === 'reg' && args[1] === HKCU_RUN) { + return { stdout: regOutput([{ name: 'Nahimic', command: '"C:\\Program Files\\Nahimic\\Nahimic.exe"' }]) } + } + throw new Error('not found') + }) + + const items = await listStartupItems() + expect(items.find((i) => i.name === 'Nahimic')!.stale).toBe(true) + }) + + it('does not flag a registry item whose executable is present', async () => { + onlyExisting('C:\\Program Files\\Nahimic\\Nahimic.exe') + setupExecFileHandler((cmd, args) => { + if (cmd === 'reg' && args[1] === HKCU_RUN) { + return { stdout: regOutput([{ name: 'Nahimic', command: '"C:\\Program Files\\Nahimic\\Nahimic.exe" -tray' }]) } + } + throw new Error('not found') + }) + + const items = await listStartupItems() + expect(items.find((i) => i.name === 'Nahimic')!.stale).toBe(false) + }) + + it('never flags entries under the Windows directory', async () => { + onlyExisting() + setupExecFileHandler((cmd, args) => { + if (cmd === 'reg' && args[1] === HKLM_RUN) { + return { stdout: regOutput([{ name: 'SecurityHealth', command: 'C:\\Windows\\system32\\SecurityHealthSystray.exe' }]) } + } + throw new Error('not found') + }) + + const items = await listStartupItems() + expect(items.find((i) => i.name === 'SecurityHealth')!.stale).toBe(false) + }) + + it('flags a scheduled task pointing at a removed executable', async () => { + onlyExisting() + setupExecFileHandler((cmd) => { + if (cmd === 'powershell') { + return { stdout: 'TASK|NahimicSvc32Run|C:\\Program Files\\Nahimic\\NahimicSvc32.exe /run|Ready\n' } + } + throw new Error('not found') + }) + + const items = await listStartupItems() + expect(items.find((i) => i.name === 'NahimicSvc32Run')!.stale).toBe(true) + }) + + it('flags a startup-folder shortcut whose target is gone', async () => { + mockExistsSync.mockImplementation((p: string) => (p as string).includes('Startup') || p === 'C:\\') + mockReaddirSync.mockReturnValue(['OldApp.lnk']) + mockReadShortcutLink.mockReturnValue({ target: 'C:\\Program Files\\OldApp\\OldApp.exe' }) + + const items = await listStartupItems() + expect(items.find((i) => i.name === 'OldApp.lnk')!.stale).toBe(true) + }) + + it('does not flag a shortcut whose target cannot be read', async () => { + mockExistsSync.mockImplementation((p: string) => (p as string).includes('Startup') || p === 'C:\\') + mockReaddirSync.mockReturnValue(['OldApp.lnk']) + mockReadShortcutLink.mockImplementation(() => { throw new Error('not a shortcut') }) + + const items = await listStartupItems() + expect(items.find((i) => i.name === 'OldApp.lnk')!.stale).toBe(false) + }) + + it('expands environment variables when resolving the target', async () => { + process.env.__KUDU_TEST_APPDIR = 'C:\\Apps' + onlyExisting('C:\\Apps\\present.exe') + setupExecFileHandler((cmd, args) => { + if (cmd === 'reg' && args[1] === HKCU_RUN) { + return { + stdout: regOutput([ + { name: 'Present', command: '%__KUDU_TEST_APPDIR%\\present.exe' }, + { name: 'Gone', command: '%__KUDU_TEST_APPDIR%\\gone.exe' }, + { name: 'UnknownVar', command: '%__KUDU_NOT_SET__%\\app.exe' }, + ]) + } + } + throw new Error('not found') + }) + + const items = await listStartupItems() + expect(items.find((i) => i.name === 'Present')!.stale).toBe(false) + expect(items.find((i) => i.name === 'Gone')!.stale).toBe(true) + expect(items.find((i) => i.name === 'UnknownVar')!.stale).toBe(false) + delete process.env.__KUDU_TEST_APPDIR + }) + }) +}) + // ===================================================================== // toggleStartupItem // ===================================================================== @@ -868,6 +1058,16 @@ describe('deleteStartupItem', () => { expect(psCall!.args.join(' ')).toContain('-Confirm:$false') }) + it('only unregisters when the task still exists (already-removed tasks succeed)', async () => { + const regCalls = collectRegCalls() + + const result = await deleteStartupItem('GhostTask', 'Task Scheduler', 'task-scheduler') + expect(result).toBe(true) + const script = regCalls.find((c) => c.cmd === 'powershell')!.args.join(' ') + expect(script).toContain("Get-ScheduledTask -TaskName 'GhostTask' -ErrorAction SilentlyContinue") + expect(script).toContain('if ($task) { Unregister-ScheduledTask') + }) + it('rejects unsafe task names', async () => { const result = await deleteStartupItem("evil'; DROP TABLE", 'Task Scheduler', 'task-scheduler') expect(result).toBe(false) diff --git a/src/main/ipc/startup-manager.ipc.ts b/src/main/ipc/startup-manager.ipc.ts index a1a7b388..24f2103e 100644 --- a/src/main/ipc/startup-manager.ipc.ts +++ b/src/main/ipc/startup-manager.ipc.ts @@ -1,4 +1,4 @@ -import { app, ipcMain } from 'electron' +import { app, ipcMain, shell } from 'electron' import { execFile } from 'child_process' import { promisify } from 'util' import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, unlinkSync } from 'fs' @@ -118,6 +118,81 @@ function friendlyExeName(name: string): string { .trim() } +// ── Stale target detection ── +// A startup entry whose program has been uninstalled can no longer launch +// anything. We surface those so the user can clear them, and we never let +// them linger in our own bookkeeping (see listStartupItems). + +/** + * Resolve the program a startup command launches. + * + * Returns `null` when the target cannot be determined with confidence — + * relative commands (`rundll32.exe …`), unresolved environment variables, + * and UNC paths (which can block for seconds when the host is offline). + * Callers must treat `null` as "unknown, assume present". + */ +function resolveCommandTarget(command: string): string | null { + if (!command) return null + const trimmed = command.trim() + const quoted = trimmed.match(/^"([^"]+)"/) + let target = quoted + ? quoted[1] + : trimmed.match(/^(.+?\.(?:exe|com|bat|cmd|scr|lnk))(?:\s|$)/i)?.[1] + || trimmed.match(/^(\S+)/)?.[1] + || '' + if (!target) return null + + // Expand %VAR% references; bail out when any of them is unknown to us + let unresolved = false + target = target.replace(/%([^%]+)%/g, (match, name: string) => { + const value = process.env[name] ?? process.env[name.toUpperCase()] + if (!value) { + unresolved = true + return match + } + return value + }) + if (unresolved) return null + + // Only drive-letter absolute paths can be checked cheaply and reliably + if (!/^[a-z]:[\\/]/i.test(target)) return null + return target +} + +/** Entries living under the Windows directory are never treated as stale. */ +function isSystemPath(target: string): boolean { + const winDir = process.env.SystemRoot || process.env.windir || 'C:\\Windows' + return target.toLowerCase().startsWith(winDir.toLowerCase().replace(/[\\/]+$/, '') + '\\') +} + +/** True only when the command's target is *known* to be gone from disk. */ +function isTargetMissing(command: string): boolean { + const target = resolveCommandTarget(command) + if (!target || isSystemPath(target)) return false + try { + // Trust a negative result only when the volume itself is mounted, so an + // unplugged drive is not mistaken for an uninstalled program. + if (!existsSync(target.slice(0, 3))) return false + return !existsSync(target) + } catch { + return false + } +} + +/** + * Resolve a Startup-folder shortcut to the program it launches so shortcuts + * left behind by uninstalled apps can be flagged. Falls back to the shortcut + * path itself when the link cannot be read. + */ +function resolveShortcutTarget(filePath: string): string { + if (extname(filePath).toLowerCase() !== '.lnk') return filePath + try { + return shell.readShortcutLink(filePath)?.target || filePath + } catch { + return filePath + } +} + function parseRegOutput(stdout: string, location: string, source: StartupItem['source']): StartupItem[] { const items: StartupItem[] = [] const lines = stdout.split('\n') @@ -135,7 +210,8 @@ function parseRegOutput(stdout: string, location: string, source: StartupItem['s source, enabled: true, publisher: extractPublisher(command), - impact: estimateImpact(name, command) + impact: estimateImpact(name, command), + stale: isTargetMissing(command) }) } } @@ -162,7 +238,8 @@ function getStartupFolderItems(): StartupItem[] { source: 'startup-folder', enabled: true, publisher: extractPublisher(filePath), - impact: estimateImpact(name, filePath) + impact: estimateImpact(name, filePath), + stale: isTargetMissing(resolveShortcutTarget(filePath)) }) } } catch { /* skip */ } @@ -258,7 +335,8 @@ async function getScheduledLogonTasks(): Promise { source: 'task-scheduler', enabled: state === 'Ready' || state === 'Running', publisher: extractPublisher(command), - impact: estimateImpact(name, command) + impact: estimateImpact(name, command), + stale: isTargetMissing(command) }) } } catch { /* task scheduler unavailable */ } @@ -337,8 +415,24 @@ export async function listStartupItems(): Promise { } } - // Merge disabled state: mark items found in disabled file, add missing ones - const disabled = readDisabledEntries() + // Merge disabled state: mark items found in disabled file, add missing ones. + // + // Disabling an item removes it from the Run key, so this file is the only + // record we have of it. If the program is uninstalled afterwards, nothing + // on the system references it any more and the entry would haunt the list + // forever — surviving registry cleaning and even a Kudu reinstall, since + // the file lives in userData. Prune entries whose program is verifiably + // gone before rebuilding the list from them. + const disabled = await withDisabledFileLock(() => { + const entries = readDisabledEntries() + const kept = entries.filter((entry) => { + const backed = items.some((i) => i.name === entry.name && i.source === entry.source) + return backed || !isTargetMissing(entry.command) + }) + if (kept.length !== entries.length) writeDisabledEntries(kept) + return kept + }) + for (const entry of disabled) { const existing = items.find((i) => i.name === entry.name && i.source === entry.source) if (existing) { @@ -353,7 +447,8 @@ export async function listStartupItems(): Promise { source: entry.source, enabled: false, publisher: extractPublisher(entry.command), - impact: estimateImpact(entry.name, entry.command) + impact: estimateImpact(entry.name, entry.command), + stale: false }) } } @@ -481,8 +576,13 @@ export async function deleteStartupItem( try { if (source === 'task-scheduler') { if (!isSafeTaskName(name)) return false + // Unregister only if the task is still there — a task that has + // already been removed elsewhere must not fail the delete, or the + // item stays listed with no way to clear it. + const taskName = name.replace(/'/g, "''") await execFileAsync('powershell', psArgs( - `Unregister-ScheduledTask -TaskName '${name.replace(/'/g, "''")}' -Confirm:$false -ErrorAction Stop` + `$task = Get-ScheduledTask -TaskName '${taskName}' -ErrorAction SilentlyContinue; ` + + `if ($task) { Unregister-ScheduledTask -TaskName '${taskName}' -Confirm:$false -ErrorAction Stop }` ), { timeout: 10000, windowsHide: true }) deletedSource = true } else if (source === 'startup-folder') { diff --git a/src/renderer/src/locales/en/startup.json b/src/renderer/src/locales/en/startup.json index 5ad02db4..0128a88a 100644 --- a/src/renderer/src/locales/en/startup.json +++ b/src/renderer/src/locales/en/startup.json @@ -63,5 +63,7 @@ "safetyTooltipLocked": "Link to Kudu Cloud for safety ratings", "safetyScore": "Safety: {{score}}/10", "safetyAnalyzed": "Analyzed {{date}}", - "sortBySafety": "Sort by Safety" + "sortBySafety": "Sort by Safety", + "staleBadge": "Not installed", + "staleTooltip": "The program this entry points to is missing, so it can no longer start. Removing the entry is safe." } diff --git a/src/renderer/src/pages/StartupPage.tsx b/src/renderer/src/pages/StartupPage.tsx index efd1e585..da92f3c6 100644 --- a/src/renderer/src/pages/StartupPage.tsx +++ b/src/renderer/src/pages/StartupPage.tsx @@ -1,6 +1,6 @@ import { useState, useEffect, useCallback, Fragment } from 'react' import { useTranslation } from 'react-i18next' -import { Zap, Shield, ShieldCheck, ShieldAlert, ShieldOff, RefreshCw, Clock, Activity, TrendingDown, ChevronDown, ChevronUp, BarChart3, Trash2, Lock } from 'lucide-react' +import { Zap, Shield, ShieldCheck, ShieldAlert, ShieldOff, RefreshCw, Clock, Activity, TrendingDown, ChevronDown, ChevronUp, BarChart3, Trash2, Lock, PackageX } from 'lucide-react' import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Cell, PieChart, Pie } from 'recharts' import { toast } from 'sonner' import { PageHeader } from '@/components/layout/PageHeader' @@ -329,9 +329,9 @@ export function StartupPage() { }, []) useEffect(() => { - if (items.length === 0) { - loadItems() - } + // Always re-read on mount: entries change outside the app (installs, + // uninstalls, Task Manager) and the store keeps the previous visit's list. + loadItems() if (!bootTrace) { loadBootTrace() } @@ -483,6 +483,16 @@ export function StartupPage() {
{item.displayName} {item.impact === 'none' && } + {item.stale && ( + + + {t('staleBadge')} + + )}
{item.publisher} diff --git a/src/shared/types.ts b/src/shared/types.ts index 77a2ba55..e0503306 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -134,6 +134,8 @@ export interface StartupItem { enabled: boolean publisher: string impact: 'high' | 'medium' | 'low' | 'none' + /** The program this entry launches is no longer installed. */ + stale?: boolean } export interface StartupBootEntry { From bfac702d75a0e334ad3d1da262b6e7655d5d5c73 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 27 Jul 2026 02:01:43 +0000 Subject: [PATCH 2/4] chore: auto-update translations --- src/renderer/src/locales/.checksums.json | 58 ++++++++++----------- src/renderer/src/locales/ar/startup.json | 20 +++---- src/renderer/src/locales/cs/startup.json | 26 ++++----- src/renderer/src/locales/da/startup.json | 10 ++-- src/renderer/src/locales/de/startup.json | 12 +++-- src/renderer/src/locales/el/startup.json | 14 ++--- src/renderer/src/locales/es/startup.json | 10 ++-- src/renderer/src/locales/fi/startup.json | 30 ++++++----- src/renderer/src/locales/fr/startup.json | 14 ++--- src/renderer/src/locales/he/startup.json | 16 +++--- src/renderer/src/locales/hi/startup.json | 26 ++++----- src/renderer/src/locales/hu/startup.json | 36 +++++++------ src/renderer/src/locales/id/startup.json | 8 +-- src/renderer/src/locales/it/startup.json | 10 ++-- src/renderer/src/locales/ja/startup.json | 10 ++-- src/renderer/src/locales/ko/startup.json | 30 ++++++----- src/renderer/src/locales/ms/startup.json | 12 +++-- src/renderer/src/locales/nl/startup.json | 16 +++--- src/renderer/src/locales/no/startup.json | 10 ++-- src/renderer/src/locales/pl/startup.json | 16 +++--- src/renderer/src/locales/pt/startup.json | 42 ++++++++------- src/renderer/src/locales/ro/startup.json | 20 +++---- src/renderer/src/locales/ru/startup.json | 8 +-- src/renderer/src/locales/sv/startup.json | 28 +++++----- src/renderer/src/locales/th/startup.json | 22 ++++---- src/renderer/src/locales/tr/startup.json | 8 +-- src/renderer/src/locales/uk/startup.json | 12 +++-- src/renderer/src/locales/vi/startup.json | 30 ++++++----- src/renderer/src/locales/zh-CN/startup.json | 24 +++++---- src/renderer/src/locales/zh-TW/startup.json | 10 ++-- 30 files changed, 323 insertions(+), 265 deletions(-) diff --git a/src/renderer/src/locales/.checksums.json b/src/renderer/src/locales/.checksums.json index f0ba3a87..53a73bec 100644 --- a/src/renderer/src/locales/.checksums.json +++ b/src/renderer/src/locales/.checksums.json @@ -14,7 +14,7 @@ "es/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "es/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "es/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", - "es/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "es/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "es/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "es/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", "es/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -33,7 +33,7 @@ "fr/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "fr/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "fr/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", - "fr/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "fr/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "fr/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "fr/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", "fr/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -51,7 +51,7 @@ "de/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "de/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "de/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", - "de/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "de/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "de/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", "de/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "de/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", @@ -71,7 +71,7 @@ "pt/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "pt/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "pt/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", - "pt/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "pt/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "pt/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "pt/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", "pt/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -90,7 +90,7 @@ "it/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "it/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "it/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", - "it/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "it/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "it/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "it/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", "it/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -107,7 +107,7 @@ "ja/registry": "f90e845b81e0d091a127ca4c1d18384bc9a8d398270f86426c8b73da5e05e20f", "ja/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "ja/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", - "ja/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "ja/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "ja/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", "ja/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "ja/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", @@ -126,7 +126,7 @@ "ko/registry": "f90e845b81e0d091a127ca4c1d18384bc9a8d398270f86426c8b73da5e05e20f", "ko/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "ko/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", - "ko/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "ko/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "ko/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "ko/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", "ko/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", @@ -147,7 +147,7 @@ "zh-CN/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "zh-CN/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "zh-CN/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", - "zh-CN/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "zh-CN/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "zh-CN/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "zh-CN/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", "zh-CN/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -164,7 +164,7 @@ "zh-TW/registry": "f90e845b81e0d091a127ca4c1d18384bc9a8d398270f86426c8b73da5e05e20f", "zh-TW/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "zh-TW/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", - "zh-TW/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "zh-TW/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "zh-TW/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", "zh-TW/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "zh-TW/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", @@ -185,7 +185,7 @@ "ru/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "ru/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "ru/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", - "ru/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "ru/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "ru/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "ru/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", "ru/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -203,7 +203,7 @@ "ar/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "ar/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "ar/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", - "ar/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "ar/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "ar/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", "ar/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "ar/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -223,7 +223,7 @@ "hi/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "hi/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "hi/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", - "hi/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "hi/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "hi/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "hi/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", "hi/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -242,7 +242,7 @@ "tr/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "tr/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "tr/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", - "tr/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "tr/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "tr/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "tr/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", "tr/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -261,7 +261,7 @@ "nl/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "nl/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "nl/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", - "nl/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "nl/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "nl/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "nl/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", "nl/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -280,7 +280,7 @@ "pl/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "pl/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "pl/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", - "pl/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "pl/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "pl/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "pl/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", "pl/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -299,7 +299,7 @@ "sv/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "sv/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "sv/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", - "sv/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "sv/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "sv/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "sv/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", "sv/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -318,7 +318,7 @@ "no/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "no/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "no/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", - "no/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "no/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "no/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "no/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", "no/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -337,7 +337,7 @@ "da/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "da/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "da/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", - "da/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "da/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "da/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "da/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", "da/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -355,7 +355,7 @@ "fi/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "fi/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "fi/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", - "fi/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "fi/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "fi/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", "fi/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "fi/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", @@ -374,7 +374,7 @@ "cs/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "cs/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "cs/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", - "cs/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "cs/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "cs/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", "cs/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "cs/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", @@ -393,7 +393,7 @@ "th/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "th/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "th/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", - "th/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "th/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "th/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", "th/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "th/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", @@ -412,7 +412,7 @@ "vi/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "vi/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "vi/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", - "vi/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "vi/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "vi/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", "vi/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "vi/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", @@ -430,7 +430,7 @@ "id/registry": "f90e845b81e0d091a127ca4c1d18384bc9a8d398270f86426c8b73da5e05e20f", "id/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "id/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", - "id/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "id/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "id/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", "id/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "id/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", @@ -449,7 +449,7 @@ "ms/registry": "f90e845b81e0d091a127ca4c1d18384bc9a8d398270f86426c8b73da5e05e20f", "ms/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "ms/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", - "ms/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "ms/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "ms/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "ms/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", "ms/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", @@ -470,7 +470,7 @@ "uk/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "uk/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "uk/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", - "uk/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "uk/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "uk/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "uk/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", "uk/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -487,7 +487,7 @@ "ro/registry": "f90e845b81e0d091a127ca4c1d18384bc9a8d398270f86426c8b73da5e05e20f", "ro/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "ro/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", - "ro/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "ro/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "ro/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", "ro/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "ro/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", @@ -508,7 +508,7 @@ "el/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "el/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "el/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", - "el/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "el/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "el/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "el/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", "el/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -526,7 +526,7 @@ "he/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "he/schedules": "6623688b8c1e450dc920109d065301c086e107f366da19eed916d6c9ebd58bd9", "he/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", - "he/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "he/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "he/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", "he/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "he/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", @@ -546,7 +546,7 @@ "hu/sidebar": "c92de0b741ca503ee66a54566f10f7a2e9fc5450b57bfb486e51f192f4820d23", "hu/threatMonitor": "7780e7602b68bdf94c8bf04f5b3b61e4addd88309cfd0f7198d970892060c17d", "hu/tray": "2796e0ab5cef3d6e48e77db8f1d3be4f9e28c43276d01034259cc399c3059a14", - "hu/startup": "1b42311344aaf427b6dca70dfde55270a9540544fd55487fda7cabcb258e80bf", + "hu/startup": "f853df14e66e1fcefe5a9aaa76b0c5893196dcba3c3f13df5a439f78baf6d5f2", "hu/settings": "0dc0f940306fb8ec609befe6e1b4e8f6822a5a27e3b0b3d4c5fb5848cef6dfea", "hu/uninstaller": "557dfc2f5580f17bcffba45d03e2c5eb6472592f2dafde3f4f9eecfe41aec3f6", "hu/updates": "a8f4fc03dede88d4597f3acab0b0f5aa737821cbe53d9bc29259cc6b097f9f70", diff --git a/src/renderer/src/locales/ar/startup.json b/src/renderer/src/locales/ar/startup.json index bb08219f..d4686729 100644 --- a/src/renderer/src/locales/ar/startup.json +++ b/src/renderer/src/locales/ar/startup.json @@ -11,15 +11,15 @@ "sourceSystemRegistry": "سجل النظام", "sourceStartupFolder": "مجلد بدء التشغيل", "sourceTaskScheduler": "جدولة المهام", - "sourceLaunchAgentUser": "Launch Agent للمستخدم", - "sourceLaunchAgentGlobal": "Launch Agent عام", + "sourceLaunchAgentUser": "عامل تشغيل المستخدم", + "sourceLaunchAgentGlobal": "عامل التشغيل العام", "sourceLoginItem": "عنصر تسجيل الدخول", "sourceSystemdUser": "خدمة مستخدم Systemd", "sourceAutostartDesktop": "بدء التشغيل التلقائي XDG", "sourceCron": "مهمة Cron", "bootTraceAnalyzing": "جارٍ تحليل بيانات تتبع الإقلاع...", "bootTraceNeedsAdmin": "تتطلب بيانات تتبع الإقلاع امتيازات المسؤول — أعد تشغيل التطبيق كمسؤول لعرض تحليل تأثير بدء التشغيل.", - "bootTraceNotAvailable": "تحليل تتبع الإقلاع غير متوفر على هذا النظام الأساسي.", + "bootTraceNotAvailable": "تحليل تتبع الإقلاع غير متوفر على هذه المنصة.", "bootTraceTitle": "تحليل تأثير بدء التشغيل", "bootTraceLastBoot": "آخر إقلاع: {{date}}", "bootTraceBasedOnLastBoot": "استنادًا إلى تتبع آخر إقلاع", @@ -49,19 +49,21 @@ "confirmRemoveTitle": "إزالة {{name}}؟", "confirmRemoveDescription": "سيؤدي هذا إلى إزالة إدخال بدء التشغيل هذا نهائيًا. لن يبدأ البرنامج بعد الآن مع Windows.", "confirmRemoveLabel": "إزالة", - "historyCategoryEnabled": "مُمكّن", - "historyCategoryDisabled": "مُعطّل", + "historyCategoryEnabled": "ممكّن", + "historyCategoryDisabled": "معطّل", "historyCategoryRemoved": "تمت الإزالة", "removeButtonTitle": "إزالة {{name}}", - "safetyLinkCloud": "اربط بـ Kudu Cloud لعرض تقييمات الأمان المدعومة بالذكاء الاصطناعي لبرامج بدء التشغيل لديك", + "safetyLinkCloud": "اربط Kudu Cloud لعرض تقييمات الأمان المعتمدة على AI لبرامج بدء التشغيل لديك", "safetyPending": "جارٍ تحليل الأمان...", "safetyTooltipSafe": "آمن — انقر لعرض التفاصيل", - "safetyTooltipCaution": "استخدم بحذر — انقر لعرض التفاصيل", + "safetyTooltipCaution": "توخَّ الحذر — انقر لعرض التفاصيل", "safetyTooltipWarning": "مريب — انقر لعرض التفاصيل", "safetyTooltipDanger": "قد يكون غير آمن — انقر لعرض التفاصيل", "safetyTooltipPending": "تحليل الأمان قيد التقدم", - "safetyTooltipLocked": "اربط بـ Kudu Cloud للحصول على تقييمات الأمان", + "safetyTooltipLocked": "اربط Kudu Cloud للحصول على تقييمات الأمان", "safetyScore": "الأمان: {{score}}/10", "safetyAnalyzed": "تم التحليل {{date}}", - "sortBySafety": "فرز حسب الأمان" + "sortBySafety": "فرز حسب الأمان", + "staleBadge": "غير مثبت", + "staleTooltip": "البرنامج الذي يشير إليه هذا الإدخال مفقود، لذلك لم يعد بإمكانه البدء. إزالة الإدخال آمنة." } diff --git a/src/renderer/src/locales/cs/startup.json b/src/renderer/src/locales/cs/startup.json index 7c39a51a..43f43b20 100644 --- a/src/renderer/src/locales/cs/startup.json +++ b/src/renderer/src/locales/cs/startup.json @@ -6,7 +6,7 @@ "filterDisabled": "Pouze zakázané", "sortByImpact": "Seřadit podle dopadu", "sortByName": "Seřadit podle názvu", - "impactLabel": "dopad: {{level}}", + "impactLabel": "Dopad: {{level}}", "sourceUserRegistry": "Registr uživatele", "sourceSystemRegistry": "Systémový registr", "sourceStartupFolder": "Složka Po spuštění", @@ -23,7 +23,7 @@ "bootTraceTitle": "Analýza dopadu po spuštění", "bootTraceLastBoot": "Poslední spuštění: {{date}}", "bootTraceBasedOnLastBoot": "Na základě trasování posledního spuštění", - "bootTraceTotalBoot": "Celková doba spuštění:", + "bootTraceTotalBoot": "Celkové spuštění:", "bootTraceHighImpactApp": "{{count}} aplikace s vysokým dopadem", "bootTraceHighImpactApps": "{{count}} aplikací s vysokým dopadem", "statTotalBootTime": "Celková doba spuštění", @@ -31,14 +31,14 @@ "statAppsMeasured": "Měřené aplikace", "statPotentialSavings": "Možná úspora", "chartBootTimeImpact": "Dopad aplikací na dobu spuštění", - "chartNoPerAppData": "Data o době spuštění jednotlivých aplikací nejsou k dispozici", - "chartBootTimeBreakdown": "Rozdělení doby spuštění", + "chartNoPerAppData": "Data o spuštění jednotlivých aplikací nejsou k dispozici", + "chartBootTimeBreakdown": "Rozpis doby spuštění", "chartTooltipDelay": "Zpoždění", "pieCoreBoot": "Základní spuštění", "pieStartupApps": "Aplikace po spuštění", "pieOther": "Ostatní", "emptyStateTitle": "Nebyly nalezeny žádné položky po spuštění", - "emptyStateDescription": "Nepodařilo se zjistit programy po spuštění.", + "emptyStateDescription": "Programy po spuštění se nepodařilo zjistit.", "toastFailedToEnable": "Nepodařilo se povolit {{name}}", "toastFailedToDisable": "Nepodařilo se zakázat {{name}}", "toastFailedToRemove": "Nepodařilo se odebrat {{name}}", @@ -53,15 +53,17 @@ "historyCategoryDisabled": "Zakázáno", "historyCategoryRemoved": "Odebráno", "removeButtonTitle": "Odebrat {{name}}", - "safetyLinkCloud": "Propojte s Kudu Cloud a zobrazte hodnocení bezpečnosti vašich programů po spuštění pomocí AI", + "safetyLinkCloud": "Propojte s Kudu Cloud a zobrazte hodnocení bezpečnosti AI pro své programy po spuštění", "safetyPending": "Analyzuje se bezpečnost...", - "safetyTooltipSafe": "Bezpečné — klikněte pro podrobnosti", - "safetyTooltipCaution": "Postupujte opatrně — klikněte pro podrobnosti", - "safetyTooltipWarning": "Podezřelé — klikněte pro podrobnosti", - "safetyTooltipDanger": "Potenciálně nebezpečné — klikněte pro podrobnosti", + "safetyTooltipSafe": "Bezpečné — kliknutím zobrazíte podrobnosti", + "safetyTooltipCaution": "Postupujte opatrně — kliknutím zobrazíte podrobnosti", + "safetyTooltipWarning": "Podezřelé — kliknutím zobrazíte podrobnosti", + "safetyTooltipDanger": "Potenciálně nebezpečné — kliknutím zobrazíte podrobnosti", "safetyTooltipPending": "Analýza bezpečnosti probíhá", "safetyTooltipLocked": "Pro hodnocení bezpečnosti propojte s Kudu Cloud", "safetyScore": "Bezpečnost: {{score}}/10", - "safetyAnalyzed": "Analyzováno {{date}}", - "sortBySafety": "Seřadit podle bezpečnosti" + "safetyAnalyzed": "Analyzováno: {{date}}", + "sortBySafety": "Seřadit podle bezpečnosti", + "staleBadge": "Není nainstalováno", + "staleTooltip": "Program, na který tato položka odkazuje, chybí, takže jej již nelze spustit. Odebrání položky je bezpečné." } diff --git a/src/renderer/src/locales/da/startup.json b/src/renderer/src/locales/da/startup.json index ababd9ff..3ffded8c 100644 --- a/src/renderer/src/locales/da/startup.json +++ b/src/renderer/src/locales/da/startup.json @@ -30,7 +30,7 @@ "statStartupAppsDelay": "Forsinkelse fra opstartsapps", "statAppsMeasured": "Målte apps", "statPotentialSavings": "Potentiel besparelse", - "chartBootTimeImpact": "Påvirkning på opstartstid efter program", + "chartBootTimeImpact": "Opstartstidspåvirkning efter program", "chartNoPerAppData": "Ingen opstartsdata pr. app tilgængelige", "chartBootTimeBreakdown": "Fordeling af opstartstid", "chartTooltipDelay": "Forsinkelse", @@ -47,7 +47,7 @@ "errorFailedToToggle": "Kunne ikke {{action}} {{name}}. Dette kan kræve administratorrettigheder.", "errorFailedToRemove": "Kunne ikke fjerne {{name}}. Dette kan kræve administratorrettigheder.", "confirmRemoveTitle": "Fjern {{name}}?", - "confirmRemoveDescription": "Dette vil permanent fjerne denne opstartspost. Programmet vil ikke længere starte sammen med Windows.", + "confirmRemoveDescription": "Dette vil permanent fjerne denne opstartspost. Programmet starter ikke længere sammen med Windows.", "confirmRemoveLabel": "Fjern", "historyCategoryEnabled": "Aktiveret", "historyCategoryDisabled": "Deaktiveret", @@ -59,9 +59,11 @@ "safetyTooltipCaution": "Vær forsigtig — klik for detaljer", "safetyTooltipWarning": "Mistænkelig — klik for detaljer", "safetyTooltipDanger": "Potentielt usikker — klik for detaljer", - "safetyTooltipPending": "Sikkerhedsanalyse i gang", + "safetyTooltipPending": "Sikkerhedsanalyse er i gang", "safetyTooltipLocked": "Forbind til Kudu Cloud for sikkerhedsvurderinger", "safetyScore": "Sikkerhed: {{score}}/10", "safetyAnalyzed": "Analyseret {{date}}", - "sortBySafety": "Sortér efter sikkerhed" + "sortBySafety": "Sortér efter sikkerhed", + "staleBadge": "Ikke installeret", + "staleTooltip": "Programmet, som denne post peger på, mangler, så det kan ikke længere starte. Det er sikkert at fjerne posten." } diff --git a/src/renderer/src/locales/de/startup.json b/src/renderer/src/locales/de/startup.json index 35be4426..13a6ef80 100644 --- a/src/renderer/src/locales/de/startup.json +++ b/src/renderer/src/locales/de/startup.json @@ -18,8 +18,8 @@ "sourceAutostartDesktop": "XDG-Autostart", "sourceCron": "Cron-Job", "bootTraceAnalyzing": "Startablaufdaten werden analysiert...", - "bootTraceNeedsAdmin": "Startablaufdaten erfordern Administratorrechte — starten Sie die App als Administrator neu, um die Analyse der Autostart-Auswirkungen anzuzeigen.", - "bootTraceNotAvailable": "Die Analyse der Startablaufdaten ist auf dieser Plattform nicht verfügbar.", + "bootTraceNeedsAdmin": "Für Startablaufdaten sind Administratorrechte erforderlich — starten Sie die App als Administrator neu, um die Analyse der Autostart-Auswirkungen anzuzeigen.", + "bootTraceNotAvailable": "Die Analyse des Startablaufs ist auf dieser Plattform nicht verfügbar.", "bootTraceTitle": "Analyse der Autostart-Auswirkungen", "bootTraceLastBoot": "Letzter Start: {{date}}", "bootTraceBasedOnLastBoot": "Basierend auf dem letzten Startablauf", @@ -56,12 +56,14 @@ "safetyLinkCloud": "Mit Kudu Cloud verknüpfen, um AI-Sicherheitsbewertungen für Ihre Autostart-Programme anzuzeigen", "safetyPending": "Sicherheit wird analysiert...", "safetyTooltipSafe": "Sicher — für Details klicken", - "safetyTooltipCaution": "Vorsicht empfohlen — für Details klicken", + "safetyTooltipCaution": "Vorsicht — für Details klicken", "safetyTooltipWarning": "Verdächtig — für Details klicken", "safetyTooltipDanger": "Potenziell unsicher — für Details klicken", - "safetyTooltipPending": "Sicherheitsanalyse läuft", + "safetyTooltipPending": "Sicherheitsanalyse wird durchgeführt", "safetyTooltipLocked": "Mit Kudu Cloud verknüpfen, um Sicherheitsbewertungen anzuzeigen", "safetyScore": "Sicherheit: {{score}}/10", "safetyAnalyzed": "Analysiert am {{date}}", - "sortBySafety": "Nach Sicherheit sortieren" + "sortBySafety": "Nach Sicherheit sortieren", + "staleBadge": "Nicht installiert", + "staleTooltip": "Das Programm, auf das dieser Eintrag verweist, fehlt und kann daher nicht mehr gestartet werden. Das Entfernen des Eintrags ist unbedenklich." } diff --git a/src/renderer/src/locales/el/startup.json b/src/renderer/src/locales/el/startup.json index a2da57a3..d12aa072 100644 --- a/src/renderer/src/locales/el/startup.json +++ b/src/renderer/src/locales/el/startup.json @@ -46,13 +46,13 @@ "errorFailedToLoad": "Αποτυχία φόρτωσης των στοιχείων εκκίνησης. Βεβαιωθείτε ότι η εφαρμογή εκτελείται σωστά.", "errorFailedToToggle": "Αποτυχία {{action}} του {{name}}. Αυτό μπορεί να απαιτεί δικαιώματα διαχειριστή.", "errorFailedToRemove": "Αποτυχία αφαίρεσης του {{name}}. Αυτό μπορεί να απαιτεί δικαιώματα διαχειριστή.", - "confirmRemoveTitle": "Αφαίρεση του {{name}};", - "confirmRemoveDescription": "Αυτό θα αφαιρέσει οριστικά αυτήν την καταχώρηση εκκίνησης. Το πρόγραμμα δεν θα εκκινείται πλέον μαζί με τα Windows.", - "confirmRemoveLabel": "Αφαίρεση", + "confirmRemoveTitle": "Κατάργηση του {{name}};", + "confirmRemoveDescription": "Αυτό θα καταργήσει οριστικά αυτήν την καταχώρηση εκκίνησης. Το πρόγραμμα δεν θα εκκινείται πλέον μαζί με τα Windows.", + "confirmRemoveLabel": "Κατάργηση", "historyCategoryEnabled": "Ενεργοποιήθηκε", "historyCategoryDisabled": "Απενεργοποιήθηκε", - "historyCategoryRemoved": "Αφαιρέθηκε", - "removeButtonTitle": "Αφαίρεση του {{name}}", + "historyCategoryRemoved": "Καταργήθηκε", + "removeButtonTitle": "Κατάργηση του {{name}}", "safetyLinkCloud": "Συνδέστε το με το Kudu Cloud για να δείτε αξιολογήσεις ασφάλειας AI για τα προγράμματα εκκίνησής σας", "safetyPending": "Ανάλυση ασφάλειας...", "safetyTooltipSafe": "Ασφαλές — κάντε κλικ για λεπτομέρειες", @@ -63,5 +63,7 @@ "safetyTooltipLocked": "Συνδεθείτε με το Kudu Cloud για αξιολογήσεις ασφάλειας", "safetyScore": "Ασφάλεια: {{score}}/10", "safetyAnalyzed": "Αναλύθηκε στις {{date}}", - "sortBySafety": "Ταξινόμηση κατά ασφάλεια" + "sortBySafety": "Ταξινόμηση κατά ασφάλεια", + "staleBadge": "Δεν είναι εγκατεστημένο", + "staleTooltip": "Το πρόγραμμα στο οποίο παραπέμπει αυτή η καταχώρηση λείπει, επομένως δεν μπορεί πλέον να εκκινηθεί. Η αφαίρεση της καταχώρησης είναι ασφαλής." } diff --git a/src/renderer/src/locales/es/startup.json b/src/renderer/src/locales/es/startup.json index 46c9d5bb..a38b008e 100644 --- a/src/renderer/src/locales/es/startup.json +++ b/src/renderer/src/locales/es/startup.json @@ -14,7 +14,7 @@ "sourceLaunchAgentUser": "Agente de inicio de usuario", "sourceLaunchAgentGlobal": "Agente de inicio global", "sourceLoginItem": "Elemento de inicio de sesión", - "sourceSystemdUser": "Servicio de usuario de Systemd", + "sourceSystemdUser": "Servicio de usuario de systemd", "sourceAutostartDesktop": "Inicio automático XDG", "sourceCron": "Tarea Cron", "bootTraceAnalyzing": "Analizando los datos de seguimiento del arranque...", @@ -31,7 +31,7 @@ "statAppsMeasured": "Aplicaciones medidas", "statPotentialSavings": "Ahorro potencial", "chartBootTimeImpact": "Impacto en el tiempo de arranque por aplicación", - "chartNoPerAppData": "No hay datos de arranque disponibles por aplicación", + "chartNoPerAppData": "No hay datos de arranque por aplicación disponibles", "chartBootTimeBreakdown": "Desglose del tiempo de arranque", "chartTooltipDelay": "Retraso", "pieCoreBoot": "Arranque principal", @@ -53,7 +53,7 @@ "historyCategoryDisabled": "Deshabilitado", "historyCategoryRemoved": "Quitado", "removeButtonTitle": "Quitar {{name}}", - "safetyLinkCloud": "Vincule con Kudu Cloud para ver las calificaciones de seguridad con IA de sus programas de inicio", + "safetyLinkCloud": "Vincule con Kudu Cloud para ver las calificaciones de seguridad con AI de sus programas de inicio", "safetyPending": "Analizando la seguridad...", "safetyTooltipSafe": "Seguro; haga clic para ver los detalles", "safetyTooltipCaution": "Use precaución; haga clic para ver los detalles", @@ -63,5 +63,7 @@ "safetyTooltipLocked": "Vincule con Kudu Cloud para ver las calificaciones de seguridad", "safetyScore": "Seguridad: {{score}}/10", "safetyAnalyzed": "Analizado el {{date}}", - "sortBySafety": "Ordenar por seguridad" + "sortBySafety": "Ordenar por seguridad", + "staleBadge": "No instalado", + "staleTooltip": "Falta el programa al que apunta esta entrada, por lo que ya no puede iniciarse. Es seguro quitar la entrada." } diff --git a/src/renderer/src/locales/fi/startup.json b/src/renderer/src/locales/fi/startup.json index 2347719d..ac2eb907 100644 --- a/src/renderer/src/locales/fi/startup.json +++ b/src/renderer/src/locales/fi/startup.json @@ -2,7 +2,7 @@ "pageTitle": "Käynnistyksen hallinta", "pageDescription": "Hallitse käynnistyksen yhteydessä suoritettavia ohjelmia", "filterAll": "Kaikki kohteet", - "filterActive": "Vain aktiiviset", + "filterActive": "Vain käytössä olevat", "filterDisabled": "Vain poistetut käytöstä", "sortByImpact": "Lajittele vaikutuksen mukaan", "sortByName": "Lajittele nimen mukaan", @@ -18,20 +18,20 @@ "sourceAutostartDesktop": "XDG Autostart", "sourceCron": "Cron-työ", "bootTraceAnalyzing": "Analysoidaan käynnistysjäljen tietoja...", - "bootTraceNeedsAdmin": "Käynnistysjäljen tiedot edellyttävät järjestelmänvalvojan oikeuksia — käynnistä sovellus uudelleen järjestelmänvalvojana nähdäksesi käynnistysvaikutuksen analyysin.", + "bootTraceNeedsAdmin": "Käynnistysjäljen tiedot edellyttävät järjestelmänvalvojan oikeuksia — käynnistä sovellus uudelleen järjestelmänvalvojana nähdäksesi käynnistysvaikutusanalyysin.", "bootTraceNotAvailable": "Käynnistysjäljen analyysi ei ole käytettävissä tällä alustalla.", - "bootTraceTitle": "Käynnistysvaikutuksen analyysi", + "bootTraceTitle": "Käynnistysvaikutusanalyysi", "bootTraceLastBoot": "Viimeisin käynnistys: {{date}}", "bootTraceBasedOnLastBoot": "Perustuu viimeisimpään käynnistysjälkeen", "bootTraceTotalBoot": "Kokonaiskäynnistysaika:", - "bootTraceHighImpactApp": "{{count}} paljon vaikuttava sovellus", - "bootTraceHighImpactApps": "{{count}} paljon vaikuttavaa sovellusta", + "bootTraceHighImpactApp": "{{count}} suuren vaikutuksen sovellus", + "bootTraceHighImpactApps": "{{count}} suuren vaikutuksen sovellusta", "statTotalBootTime": "Kokonaiskäynnistysaika", "statStartupAppsDelay": "Käynnistysohjelmien viive", "statAppsMeasured": "Mitatut sovellukset", "statPotentialSavings": "Mahdollinen säästö", "chartBootTimeImpact": "Sovellusten vaikutus käynnistysaikaan", - "chartNoPerAppData": "Sovelluskohtaista käynnistysdataa ei ole saatavilla", + "chartNoPerAppData": "Sovelluskohtaista käynnistystietoa ei ole saatavilla", "chartBootTimeBreakdown": "Käynnistysajan erittely", "chartTooltipDelay": "Viive", "pieCoreBoot": "Ydinkäynnistys", @@ -39,13 +39,13 @@ "pieOther": "Muu", "emptyStateTitle": "Käynnistyskohteita ei löytynyt", "emptyStateDescription": "Käynnistysohjelmia ei voitu tunnistaa.", - "toastFailedToEnable": "Kohteen {{name}} käyttöönotto epäonnistui", - "toastFailedToDisable": "Kohteen {{name}} poistaminen käytöstä epäonnistui", - "toastFailedToRemove": "Kohteen {{name}} poistaminen epäonnistui", + "toastFailedToEnable": "{{name}}-kohteen käyttöönotto epäonnistui", + "toastFailedToDisable": "{{name}}-kohteen poistaminen käytöstä epäonnistui", + "toastFailedToRemove": "{{name}}-kohteen poistaminen epäonnistui", "toastAdminRequired": "Tämä saattaa edellyttää järjestelmänvalvojan oikeuksia", "errorFailedToLoad": "Käynnistyskohteiden lataaminen epäonnistui. Varmista, että sovellus toimii oikein.", - "errorFailedToToggle": "Toiminnon {{action}} suorittaminen kohteelle {{name}} epäonnistui. Tämä saattaa edellyttää järjestelmänvalvojan oikeuksia.", - "errorFailedToRemove": "Kohteen {{name}} poistaminen epäonnistui. Tämä saattaa edellyttää järjestelmänvalvojan oikeuksia.", + "errorFailedToToggle": "Toiminto {{action}} epäonnistui kohteelle {{name}}. Tämä saattaa edellyttää järjestelmänvalvojan oikeuksia.", + "errorFailedToRemove": "{{name}}-kohteen poistaminen epäonnistui. Tämä saattaa edellyttää järjestelmänvalvojan oikeuksia.", "confirmRemoveTitle": "Poistetaanko {{name}}?", "confirmRemoveDescription": "Tämä poistaa tämän käynnistyskohteen pysyvästi. Ohjelma ei enää käynnisty Windowsin mukana.", "confirmRemoveLabel": "Poista", @@ -53,15 +53,17 @@ "historyCategoryDisabled": "Poistettu käytöstä", "historyCategoryRemoved": "Poistettu", "removeButtonTitle": "Poista {{name}}", - "safetyLinkCloud": "Yhdistä Kudu Cloudiin nähdäksesi käynnistysohjelmiesi AI-turvallisuusarviot", + "safetyLinkCloud": "Yhdistä Kudu Cloudiin nähdäksesi käynnistysohjelmiesi AI-turvallisuusluokitukset", "safetyPending": "Analysoidaan turvallisuutta...", "safetyTooltipSafe": "Turvallinen — napsauta nähdäksesi lisätiedot", "safetyTooltipCaution": "Noudata varovaisuutta — napsauta nähdäksesi lisätiedot", "safetyTooltipWarning": "Epäilyttävä — napsauta nähdäksesi lisätiedot", "safetyTooltipDanger": "Mahdollisesti vaarallinen — napsauta nähdäksesi lisätiedot", "safetyTooltipPending": "Turvallisuusanalyysi käynnissä", - "safetyTooltipLocked": "Yhdistä Kudu Cloudiin nähdäksesi turvallisuusarviot", + "safetyTooltipLocked": "Yhdistä Kudu Cloudiin nähdäksesi turvallisuusluokitukset", "safetyScore": "Turvallisuus: {{score}}/10", "safetyAnalyzed": "Analysoitu {{date}}", - "sortBySafety": "Lajittele turvallisuuden mukaan" + "sortBySafety": "Lajittele turvallisuuden mukaan", + "staleBadge": "Ei asennettu", + "staleTooltip": "Ohjelma, johon tämä kohde viittaa, puuttuu, joten sitä ei voi enää käynnistää. Kohteen poistaminen on turvallista." } diff --git a/src/renderer/src/locales/fr/startup.json b/src/renderer/src/locales/fr/startup.json index 1a0853c3..94aeafb9 100644 --- a/src/renderer/src/locales/fr/startup.json +++ b/src/renderer/src/locales/fr/startup.json @@ -1,6 +1,6 @@ { "pageTitle": "Gestionnaire de démarrage", - "pageDescription": "Gérer les programmes qui s’exécutent au démarrage", + "pageDescription": "Gérez les programmes qui s’exécutent au démarrage", "filterAll": "Tous les éléments", "filterActive": "Actifs uniquement", "filterDisabled": "Désactivés uniquement", @@ -14,7 +14,7 @@ "sourceLaunchAgentUser": "Agent de lancement utilisateur", "sourceLaunchAgentGlobal": "Agent de lancement global", "sourceLoginItem": "Élément de connexion", - "sourceSystemdUser": "Service utilisateur systemd", + "sourceSystemdUser": "Service utilisateur Systemd", "sourceAutostartDesktop": "Démarrage automatique XDG", "sourceCron": "Tâche Cron", "bootTraceAnalyzing": "Analyse des données de trace de démarrage...", @@ -23,7 +23,7 @@ "bootTraceTitle": "Analyse de l’impact au démarrage", "bootTraceLastBoot": "Dernier démarrage : {{date}}", "bootTraceBasedOnLastBoot": "Basé sur la dernière trace de démarrage", - "bootTraceTotalBoot": "Démarrage total :", + "bootTraceTotalBoot": "Temps de démarrage total :", "bootTraceHighImpactApp": "{{count}} application à fort impact", "bootTraceHighImpactApps": "{{count}} applications à fort impact", "statTotalBootTime": "Temps de démarrage total", @@ -56,12 +56,14 @@ "safetyLinkCloud": "Liez Kudu Cloud pour voir les évaluations de sécurité IA de vos programmes de démarrage", "safetyPending": "Analyse de la sécurité...", "safetyTooltipSafe": "Sûr — cliquez pour plus de détails", - "safetyTooltipCaution": "Soyez prudent — cliquez pour plus de détails", + "safetyTooltipCaution": "À utiliser avec prudence — cliquez pour plus de détails", "safetyTooltipWarning": "Suspect — cliquez pour plus de détails", "safetyTooltipDanger": "Potentiellement dangereux — cliquez pour plus de détails", "safetyTooltipPending": "Analyse de sécurité en cours", - "safetyTooltipLocked": "Liez Kudu Cloud pour obtenir les évaluations de sécurité", + "safetyTooltipLocked": "Liez Kudu Cloud pour les évaluations de sécurité", "safetyScore": "Sécurité : {{score}}/10", "safetyAnalyzed": "Analysé le {{date}}", - "sortBySafety": "Trier par sécurité" + "sortBySafety": "Trier par sécurité", + "staleBadge": "Non installé", + "staleTooltip": "Le programme vers lequel cette entrée pointe est introuvable et ne peut donc plus démarrer. Vous pouvez supprimer cette entrée sans risque." } diff --git a/src/renderer/src/locales/he/startup.json b/src/renderer/src/locales/he/startup.json index f1c69572..db85c9b8 100644 --- a/src/renderer/src/locales/he/startup.json +++ b/src/renderer/src/locales/he/startup.json @@ -18,13 +18,13 @@ "sourceAutostartDesktop": "הפעלה אוטומטית של XDG", "sourceCron": "משימת Cron", "bootTraceAnalyzing": "מנתח נתוני מעקב אתחול...", - "bootTraceNeedsAdmin": "נתוני מעקב האתחול דורשים הרשאות מנהל — הפעל מחדש את היישום כמנהל כדי להציג ניתוח השפעת ההפעלה.", + "bootTraceNeedsAdmin": "נתוני מעקב האתחול דורשים הרשאות מנהל — הפעל מחדש את היישום כמנהל כדי להציג את ניתוח השפעת ההפעלה.", "bootTraceNotAvailable": "ניתוח מעקב האתחול אינו זמין בפלטפורמה זו.", "bootTraceTitle": "ניתוח השפעת ההפעלה", "bootTraceLastBoot": "אתחול אחרון: {{date}}", "bootTraceBasedOnLastBoot": "מבוסס על מעקב האתחול האחרון", - "bootTraceTotalBoot": "סך כל זמן האתחול:", - "bootTraceHighImpactApp": "יישום אחד בעל השפעה גבוהה {{count}}", + "bootTraceTotalBoot": "סך זמן האתחול:", + "bootTraceHighImpactApp": "{{count}} יישום בעל השפעה גבוהה", "bootTraceHighImpactApps": "{{count}} יישומים בעלי השפעה גבוהה", "statTotalBootTime": "זמן אתחול כולל", "statStartupAppsDelay": "עיכוב של יישומי הפעלה", @@ -45,12 +45,12 @@ "toastAdminRequired": "ייתכן שנדרשות הרשאות מנהל", "errorFailedToLoad": "טעינת פריטי ההפעלה נכשלה. ודא שהיישום פועל כראוי.", "errorFailedToToggle": "הפעולה {{action}} עבור {{name}} נכשלה. ייתכן שנדרשות הרשאות מנהל.", - "errorFailedToRemove": "ההסרה של {{name}} נכשלה. ייתכן שנדרשות הרשאות מנהל.", + "errorFailedToRemove": "הסרת {{name}} נכשלה. ייתכן שנדרשות הרשאות מנהל.", "confirmRemoveTitle": "להסיר את {{name}}?", "confirmRemoveDescription": "פעולה זו תסיר לצמיתות את ערך ההפעלה הזה. התוכנית לא תופעל עוד עם Windows.", "confirmRemoveLabel": "הסר", - "historyCategoryEnabled": "מופעל", - "historyCategoryDisabled": "מושבת", + "historyCategoryEnabled": "הופעל", + "historyCategoryDisabled": "הושבת", "historyCategoryRemoved": "הוסר", "removeButtonTitle": "הסר את {{name}}", "safetyLinkCloud": "קשר אל Kudu Cloud כדי לראות דירוגי בטיחות מבוססי AI עבור תוכניות ההפעלה שלך", @@ -63,5 +63,7 @@ "safetyTooltipLocked": "קשר אל Kudu Cloud כדי לקבל דירוגי בטיחות", "safetyScore": "בטיחות: {{score}}/10", "safetyAnalyzed": "נותח ב-{{date}}", - "sortBySafety": "מיון לפי בטיחות" + "sortBySafety": "מיון לפי בטיחות", + "staleBadge": "לא מותקן", + "staleTooltip": "התוכנית שאליה ערך זה מפנה חסרה, ולכן היא כבר לא יכולה לפעול. בטוח להסיר את הערך." } diff --git a/src/renderer/src/locales/hi/startup.json b/src/renderer/src/locales/hi/startup.json index 2bfbe5e8..5fd4d109 100644 --- a/src/renderer/src/locales/hi/startup.json +++ b/src/renderer/src/locales/hi/startup.json @@ -4,21 +4,21 @@ "filterAll": "सभी आइटम", "filterActive": "केवल सक्रिय", "filterDisabled": "केवल अक्षम", - "sortByImpact": "प्रभाव के अनुसार क्रमित करें", - "sortByName": "नाम के अनुसार क्रमित करें", + "sortByImpact": "प्रभाव के अनुसार क्रमबद्ध करें", + "sortByName": "नाम के अनुसार क्रमबद्ध करें", "impactLabel": "{{level}} प्रभाव", "sourceUserRegistry": "उपयोगकर्ता Registry", "sourceSystemRegistry": "सिस्टम Registry", "sourceStartupFolder": "Startup फ़ोल्डर", "sourceTaskScheduler": "Task Scheduler", "sourceLaunchAgentUser": "उपयोगकर्ता Launch Agent", - "sourceLaunchAgentGlobal": "ग्लोबल Launch Agent", + "sourceLaunchAgentGlobal": "वैश्विक Launch Agent", "sourceLoginItem": "Login आइटम", "sourceSystemdUser": "Systemd उपयोगकर्ता सेवा", "sourceAutostartDesktop": "XDG Autostart", "sourceCron": "Cron जॉब", "bootTraceAnalyzing": "बूट ट्रेस डेटा का विश्लेषण किया जा रहा है...", - "bootTraceNeedsAdmin": "बूट ट्रेस डेटा के लिए administrator विशेषाधिकार आवश्यक हैं — Startup प्रभाव विश्लेषण देखने के लिए ऐप को administrator के रूप में पुनः प्रारंभ करें।", + "bootTraceNeedsAdmin": "बूट ट्रेस डेटा के लिए व्यवस्थापक विशेषाधिकार आवश्यक हैं — Startup प्रभाव विश्लेषण देखने के लिए ऐप को व्यवस्थापक के रूप में पुनः प्रारंभ करें।", "bootTraceNotAvailable": "इस प्लेटफ़ॉर्म पर बूट ट्रेस विश्लेषण उपलब्ध नहीं है।", "bootTraceTitle": "Startup प्रभाव विश्लेषण", "bootTraceLastBoot": "पिछला बूट: {{date}}", @@ -32,7 +32,7 @@ "statPotentialSavings": "संभावित बचत", "chartBootTimeImpact": "एप्लिकेशन के अनुसार बूट समय प्रभाव", "chartNoPerAppData": "प्रति-ऐप बूट डेटा उपलब्ध नहीं है", - "chartBootTimeBreakdown": "बूट समय विवरण", + "chartBootTimeBreakdown": "बूट समय का विवरण", "chartTooltipDelay": "विलंब", "pieCoreBoot": "कोर बूट", "pieStartupApps": "Startup ऐप्स", @@ -42,18 +42,18 @@ "toastFailedToEnable": "{{name}} को सक्षम करने में विफल", "toastFailedToDisable": "{{name}} को अक्षम करने में विफल", "toastFailedToRemove": "{{name}} को हटाने में विफल", - "toastAdminRequired": "इसके लिए administrator विशेषाधिकार आवश्यक हो सकते हैं", + "toastAdminRequired": "इसके लिए व्यवस्थापक विशेषाधिकार आवश्यक हो सकते हैं", "errorFailedToLoad": "Startup आइटम लोड करने में विफल। सुनिश्चित करें कि ऐप सही तरीके से चल रहा है।", - "errorFailedToToggle": "{{name}} को {{action}} करने में विफल। इसके लिए administrator विशेषाधिकार आवश्यक हो सकते हैं।", - "errorFailedToRemove": "{{name}} को हटाने में विफल। इसके लिए administrator विशेषाधिकार आवश्यक हो सकते हैं।", + "errorFailedToToggle": "{{name}} को {{action}} करने में विफल। इसके लिए व्यवस्थापक विशेषाधिकार आवश्यक हो सकते हैं।", + "errorFailedToRemove": "{{name}} को हटाने में विफल। इसके लिए व्यवस्थापक विशेषाधिकार आवश्यक हो सकते हैं।", "confirmRemoveTitle": "{{name}} को हटाएँ?", "confirmRemoveDescription": "यह इस Startup प्रविष्टि को स्थायी रूप से हटा देगा। प्रोग्राम अब Windows के साथ प्रारंभ नहीं होगा।", "confirmRemoveLabel": "हटाएँ", "historyCategoryEnabled": "सक्षम", "historyCategoryDisabled": "अक्षम", "historyCategoryRemoved": "हटाया गया", - "removeButtonTitle": "{{name}} हटाएँ", - "safetyLinkCloud": "अपने Startup प्रोग्रामों के लिए AI सुरक्षा रेटिंग देखने हेतु Kudu Cloud से लिंक करें", + "removeButtonTitle": "{{name}} को हटाएँ", + "safetyLinkCloud": "अपने Startup प्रोग्राम के लिए AI सुरक्षा रेटिंग देखने हेतु Kudu Cloud से लिंक करें", "safetyPending": "सुरक्षा का विश्लेषण किया जा रहा है...", "safetyTooltipSafe": "सुरक्षित — विवरण के लिए क्लिक करें", "safetyTooltipCaution": "सावधानी बरतें — विवरण के लिए क्लिक करें", @@ -62,6 +62,8 @@ "safetyTooltipPending": "सुरक्षा विश्लेषण प्रगति पर है", "safetyTooltipLocked": "सुरक्षा रेटिंग के लिए Kudu Cloud से लिंक करें", "safetyScore": "सुरक्षा: {{score}}/10", - "safetyAnalyzed": "विश्लेषण किया गया: {{date}}", - "sortBySafety": "सुरक्षा के अनुसार क्रमित करें" + "safetyAnalyzed": "विश्लेषित: {{date}}", + "sortBySafety": "सुरक्षा के अनुसार क्रमबद्ध करें", + "staleBadge": "इंस्टॉल नहीं है", + "staleTooltip": "जिस प्रोग्राम की ओर यह प्रविष्टि संकेत करती है, वह मौजूद नहीं है, इसलिए अब वह प्रारंभ नहीं हो सकता। इस प्रविष्टि को हटाना सुरक्षित है।" } diff --git a/src/renderer/src/locales/hu/startup.json b/src/renderer/src/locales/hu/startup.json index fabadf27..cad1f0f2 100644 --- a/src/renderer/src/locales/hu/startup.json +++ b/src/renderer/src/locales/hu/startup.json @@ -8,7 +8,7 @@ "sortByName": "Rendezés név szerint", "impactLabel": "{{level}} hatás", "sourceUserRegistry": "Felhasználói beállításjegyzék", - "sourceSystemRegistry": "Rendszerleíró adatbázis", + "sourceSystemRegistry": "Rendszer-beállításjegyzék", "sourceStartupFolder": "Automatikus indítás mappa", "sourceTaskScheduler": "Feladatütemező", "sourceLaunchAgentUser": "Felhasználói Launch Agent", @@ -16,14 +16,14 @@ "sourceLoginItem": "Bejelentkezési elem", "sourceSystemdUser": "Systemd felhasználói szolgáltatás", "sourceAutostartDesktop": "XDG automatikus indítás", - "sourceCron": "Cron feladat", + "sourceCron": "Cron-feladat", "bootTraceAnalyzing": "Rendszerindítási nyomkövetési adatok elemzése...", - "bootTraceNeedsAdmin": "A rendszerindítási nyomkövetési adatokhoz rendszergazdai jogosultság szükséges — indítsa újra az alkalmazást rendszergazdaként az indítási hatáselemzés megtekintéséhez.", + "bootTraceNeedsAdmin": "A rendszerindítási nyomkövetési adatok megtekintéséhez rendszergazdai jogosultság szükséges — az indítási hatáselemzés megtekintéséhez indítsa újra az alkalmazást rendszergazdaként.", "bootTraceNotAvailable": "A rendszerindítási nyomkövetés elemzése ezen a platformon nem érhető el.", "bootTraceTitle": "Indítási hatáselemzés", - "bootTraceLastBoot": "Legutóbbi indítás: {{date}}", - "bootTraceBasedOnLastBoot": "A legutóbbi indítás nyomkövetési adatai alapján", - "bootTraceTotalBoot": "Teljes indítás:", + "bootTraceLastBoot": "Utolsó indítás: {{date}}", + "bootTraceBasedOnLastBoot": "Az utolsó rendszerindítás nyomkövetése alapján", + "bootTraceTotalBoot": "Teljes indítási idő:", "bootTraceHighImpactApp": "{{count}} nagy hatású alkalmazás", "bootTraceHighImpactApps": "{{count}} nagy hatású alkalmazás", "statTotalBootTime": "Teljes indítási idő", @@ -34,18 +34,18 @@ "chartNoPerAppData": "Nem állnak rendelkezésre alkalmazásonkénti indítási adatok", "chartBootTimeBreakdown": "Indítási idő bontása", "chartTooltipDelay": "Késleltetés", - "pieCoreBoot": "Alapvető rendszerindítás", + "pieCoreBoot": "Alap rendszerindítás", "pieStartupApps": "Indítási alkalmazások", "pieOther": "Egyéb", "emptyStateTitle": "Nem találhatók automatikusan induló elemek", "emptyStateDescription": "Nem sikerült észlelni az automatikusan induló programokat.", - "toastFailedToEnable": "{{name}} engedélyezése sikertelen", - "toastFailedToDisable": "{{name}} letiltása sikertelen", - "toastFailedToRemove": "{{name}} eltávolítása sikertelen", - "toastAdminRequired": "Ehhez rendszergazdai jogosultság szükséges lehet", + "toastFailedToEnable": "Nem sikerült engedélyezni: {{name}}", + "toastFailedToDisable": "Nem sikerült letiltani: {{name}}", + "toastFailedToRemove": "Nem sikerült eltávolítani: {{name}}", + "toastAdminRequired": "Ehhez rendszergazdai jogosultság lehet szükséges", "errorFailedToLoad": "Nem sikerült betölteni az automatikusan induló elemeket. Győződjön meg arról, hogy az alkalmazás megfelelően fut.", - "errorFailedToToggle": "{{name}} elem {{action}} művelete sikertelen. Ehhez rendszergazdai jogosultság szükséges lehet.", - "errorFailedToRemove": "{{name}} eltávolítása sikertelen. Ehhez rendszergazdai jogosultság szükséges lehet.", + "errorFailedToToggle": "Nem sikerült a következő művelet: {{action}} — {{name}}. Ehhez rendszergazdai jogosultság lehet szükséges.", + "errorFailedToRemove": "Nem sikerült eltávolítani: {{name}}. Ehhez rendszergazdai jogosultság lehet szükséges.", "confirmRemoveTitle": "Eltávolítja ezt: {{name}}?", "confirmRemoveDescription": "Ez véglegesen eltávolítja ezt az automatikus indítási bejegyzést. A program többé nem indul el a Windows rendszerrel együtt.", "confirmRemoveLabel": "Eltávolítás", @@ -53,15 +53,17 @@ "historyCategoryDisabled": "Letiltva", "historyCategoryRemoved": "Eltávolítva", "removeButtonTitle": "{{name}} eltávolítása", - "safetyLinkCloud": "Kapcsolja össze a Kudu Cloud szolgáltatással az automatikusan induló programok AI biztonsági értékeléseinek megtekintéséhez", + "safetyLinkCloud": "Kapcsolja össze a Kudu Clouddal, hogy megtekinthesse az automatikusan induló programok AI biztonsági értékeléseit", "safetyPending": "Biztonsági elemzés folyamatban...", "safetyTooltipSafe": "Biztonságos — kattintson a részletekért", "safetyTooltipCaution": "Óvatosan használja — kattintson a részletekért", "safetyTooltipWarning": "Gyanús — kattintson a részletekért", - "safetyTooltipDanger": "Lehetségesen nem biztonságos — kattintson a részletekért", + "safetyTooltipDanger": "Potenciálisan nem biztonságos — kattintson a részletekért", "safetyTooltipPending": "A biztonsági elemzés folyamatban van", - "safetyTooltipLocked": "Kapcsolja össze a Kudu Cloud szolgáltatással a biztonsági értékelésekért", + "safetyTooltipLocked": "Kapcsolja össze a Kudu Clouddal a biztonsági értékelésekért", "safetyScore": "Biztonság: {{score}}/10", "safetyAnalyzed": "Elemezve: {{date}}", - "sortBySafety": "Rendezés biztonság szerint" + "sortBySafety": "Rendezés biztonság szerint", + "staleBadge": "Nincs telepítve", + "staleTooltip": "Az ehhez a bejegyzéshez tartozó program hiányzik, ezért már nem indítható el. A bejegyzés eltávolítása biztonságos." } diff --git a/src/renderer/src/locales/id/startup.json b/src/renderer/src/locales/id/startup.json index 18baadb9..8ae25fcf 100644 --- a/src/renderer/src/locales/id/startup.json +++ b/src/renderer/src/locales/id/startup.json @@ -15,7 +15,7 @@ "sourceLaunchAgentGlobal": "Launch Agent Global", "sourceLoginItem": "Item Login", "sourceSystemdUser": "Layanan Pengguna Systemd", - "sourceAutostartDesktop": "Autostart XDG", + "sourceAutostartDesktop": "XDG Autostart", "sourceCron": "Tugas Cron", "bootTraceAnalyzing": "Menganalisis data jejak boot...", "bootTraceNeedsAdmin": "Data jejak boot memerlukan hak administrator — mulai ulang aplikasi sebagai administrator untuk melihat analisis dampak startup.", @@ -31,7 +31,7 @@ "statAppsMeasured": "Aplikasi yang Diukur", "statPotentialSavings": "Potensi Penghematan", "chartBootTimeImpact": "Dampak Waktu Boot per Aplikasi", - "chartNoPerAppData": "Tidak ada data boot per aplikasi yang tersedia", + "chartNoPerAppData": "Data boot per aplikasi tidak tersedia", "chartBootTimeBreakdown": "Rincian Waktu Boot", "chartTooltipDelay": "Penundaan", "pieCoreBoot": "Boot Inti", @@ -63,5 +63,7 @@ "safetyTooltipLocked": "Tautkan ke Kudu Cloud untuk penilaian keamanan", "safetyScore": "Keamanan: {{score}}/10", "safetyAnalyzed": "Dianalisis {{date}}", - "sortBySafety": "Urutkan berdasarkan Keamanan" + "sortBySafety": "Urutkan berdasarkan Keamanan", + "staleBadge": "Tidak terpasang", + "staleTooltip": "Program yang dituju entri ini tidak ada, sehingga tidak dapat lagi dijalankan. Menghapus entri ini aman." } diff --git a/src/renderer/src/locales/it/startup.json b/src/renderer/src/locales/it/startup.json index 924a8c63..eada9519 100644 --- a/src/renderer/src/locales/it/startup.json +++ b/src/renderer/src/locales/it/startup.json @@ -16,7 +16,7 @@ "sourceLoginItem": "Elemento di login", "sourceSystemdUser": "Servizio utente Systemd", "sourceAutostartDesktop": "Avvio automatico XDG", - "sourceCron": "Attività Cron", + "sourceCron": "Operazione Cron", "bootTraceAnalyzing": "Analisi dei dati di traccia dell'avvio in corso...", "bootTraceNeedsAdmin": "I dati di traccia dell'avvio richiedono privilegi di amministratore — riavvia l'app come amministratore per visualizzare l'analisi dell'impatto all'avvio.", "bootTraceNotAvailable": "L'analisi della traccia dell'avvio non è disponibile su questa piattaforma.", @@ -34,7 +34,7 @@ "chartNoPerAppData": "Nessun dato di avvio disponibile per applicazione", "chartBootTimeBreakdown": "Suddivisione del tempo di avvio", "chartTooltipDelay": "Ritardo", - "pieCoreBoot": "Avvio di base", + "pieCoreBoot": "Avvio principale", "pieStartupApps": "App di avvio", "pieOther": "Altro", "emptyStateTitle": "Nessun elemento di avvio trovato", @@ -56,12 +56,14 @@ "safetyLinkCloud": "Collega Kudu Cloud per visualizzare le valutazioni di sicurezza AI dei tuoi programmi di avvio", "safetyPending": "Analisi della sicurezza in corso...", "safetyTooltipSafe": "Sicuro — fai clic per i dettagli", - "safetyTooltipCaution": "Usare cautela — fai clic per i dettagli", + "safetyTooltipCaution": "Usare con cautela — fai clic per i dettagli", "safetyTooltipWarning": "Sospetto — fai clic per i dettagli", "safetyTooltipDanger": "Potenzialmente non sicuro — fai clic per i dettagli", "safetyTooltipPending": "Analisi della sicurezza in corso", "safetyTooltipLocked": "Collega Kudu Cloud per le valutazioni di sicurezza", "safetyScore": "Sicurezza: {{score}}/10", "safetyAnalyzed": "Analizzato il {{date}}", - "sortBySafety": "Ordina per sicurezza" + "sortBySafety": "Ordina per sicurezza", + "staleBadge": "Non installato", + "staleTooltip": "Il programma a cui punta questa voce non è presente, quindi non può più essere avviato. È sicuro rimuovere la voce." } diff --git a/src/renderer/src/locales/ja/startup.json b/src/renderer/src/locales/ja/startup.json index 70799b4e..f1d9c051 100644 --- a/src/renderer/src/locales/ja/startup.json +++ b/src/renderer/src/locales/ja/startup.json @@ -30,7 +30,7 @@ "statStartupAppsDelay": "スタートアップ アプリの遅延", "statAppsMeasured": "測定済みアプリ数", "statPotentialSavings": "削減可能時間", - "chartBootTimeImpact": "アプリ別の起動時間への影響", + "chartBootTimeImpact": "アプリケーション別の起動時間への影響", "chartNoPerAppData": "アプリごとの起動データはありません", "chartBootTimeBreakdown": "起動時間の内訳", "chartTooltipDelay": "遅延", @@ -53,15 +53,17 @@ "historyCategoryDisabled": "無効", "historyCategoryRemoved": "削除済み", "removeButtonTitle": "{{name}} を削除", - "safetyLinkCloud": "Kudu Cloud にリンクして、スタートアップ プログラムの AI 安全性評価を確認します", + "safetyLinkCloud": "Kudu Cloud にリンクして、スタートアップ プログラムの AI 安全性評価を表示します", "safetyPending": "安全性を分析しています...", "safetyTooltipSafe": "安全 — クリックして詳細を表示", "safetyTooltipCaution": "注意して使用 — クリックして詳細を表示", "safetyTooltipWarning": "不審 — クリックして詳細を表示", "safetyTooltipDanger": "安全でない可能性があります — クリックして詳細を表示", "safetyTooltipPending": "安全性分析を実行中", - "safetyTooltipLocked": "安全性評価を確認するには Kudu Cloud にリンクしてください", + "safetyTooltipLocked": "安全性評価を表示するには Kudu Cloud にリンクしてください", "safetyScore": "安全性: {{score}}/10", "safetyAnalyzed": "分析日: {{date}}", - "sortBySafety": "安全性で並べ替え" + "sortBySafety": "安全性で並べ替え", + "staleBadge": "未インストール", + "staleTooltip": "このエントリが参照しているプログラムが見つからないため、起動できなくなっています。エントリを削除しても安全です。" } diff --git a/src/renderer/src/locales/ko/startup.json b/src/renderer/src/locales/ko/startup.json index 75f1e619..68e0e515 100644 --- a/src/renderer/src/locales/ko/startup.json +++ b/src/renderer/src/locales/ko/startup.json @@ -3,13 +3,13 @@ "pageDescription": "시작 시 실행되는 프로그램을 관리합니다", "filterAll": "모든 항목", "filterActive": "활성 항목만", - "filterDisabled": "사용 안 함 항목만", + "filterDisabled": "비활성 항목만", "sortByImpact": "영향도순 정렬", "sortByName": "이름순 정렬", "impactLabel": "{{level}} 영향", "sourceUserRegistry": "사용자 레지스트리", "sourceSystemRegistry": "시스템 레지스트리", - "sourceStartupFolder": "시작 프로그램 폴더", + "sourceStartupFolder": "시작프로그램 폴더", "sourceTaskScheduler": "작업 스케줄러", "sourceLaunchAgentUser": "사용자 Launch Agent", "sourceLaunchAgentGlobal": "전역 Launch Agent", @@ -18,50 +18,52 @@ "sourceAutostartDesktop": "XDG 자동 시작", "sourceCron": "Cron 작업", "bootTraceAnalyzing": "부팅 추적 데이터를 분석하는 중...", - "bootTraceNeedsAdmin": "부팅 추적 데이터를 보려면 관리자 권한이 필요합니다 — 시작 영향 분석을 보려면 앱을 관리자로 다시 시작하세요.", + "bootTraceNeedsAdmin": "부팅 추적 데이터를 보려면 관리자 권한이 필요합니다 — 시작 프로그램 영향 분석을 보려면 앱을 관리자 권한으로 다시 시작하세요.", "bootTraceNotAvailable": "이 플랫폼에서는 부팅 추적 분석을 사용할 수 없습니다.", - "bootTraceTitle": "시작 영향 분석", + "bootTraceTitle": "시작 프로그램 영향 분석", "bootTraceLastBoot": "마지막 부팅: {{date}}", "bootTraceBasedOnLastBoot": "마지막 부팅 추적 기준", "bootTraceTotalBoot": "총 부팅 시간:", "bootTraceHighImpactApp": "영향이 큰 앱 {{count}}개", "bootTraceHighImpactApps": "영향이 큰 앱 {{count}}개", "statTotalBootTime": "총 부팅 시간", - "statStartupAppsDelay": "시작 프로그램 지연 시간", + "statStartupAppsDelay": "시작 프로그램 지연", "statAppsMeasured": "측정된 앱 수", "statPotentialSavings": "예상 절감 시간", "chartBootTimeImpact": "앱별 부팅 시간 영향", "chartNoPerAppData": "앱별 부팅 데이터를 사용할 수 없습니다", "chartBootTimeBreakdown": "부팅 시간 구성", - "chartTooltipDelay": "지연 시간", + "chartTooltipDelay": "지연", "pieCoreBoot": "핵심 부팅", "pieStartupApps": "시작 프로그램", "pieOther": "기타", "emptyStateTitle": "시작 항목을 찾을 수 없습니다", "emptyStateDescription": "시작 프로그램을 감지할 수 없습니다.", - "toastFailedToEnable": "{{name}}을(를) 사용하도록 설정하지 못했습니다", - "toastFailedToDisable": "{{name}}을(를) 사용 안 함으로 설정하지 못했습니다", + "toastFailedToEnable": "{{name}}을(를) 활성화하지 못했습니다", + "toastFailedToDisable": "{{name}}을(를) 비활성화하지 못했습니다", "toastFailedToRemove": "{{name}}을(를) 제거하지 못했습니다", "toastAdminRequired": "관리자 권한이 필요할 수 있습니다", "errorFailedToLoad": "시작 항목을 불러오지 못했습니다. 앱이 정상적으로 실행 중인지 확인하세요.", "errorFailedToToggle": "{{name}}을(를) {{action}}하지 못했습니다. 관리자 권한이 필요할 수 있습니다.", "errorFailedToRemove": "{{name}}을(를) 제거하지 못했습니다. 관리자 권한이 필요할 수 있습니다.", "confirmRemoveTitle": "{{name}}을(를) 제거하시겠습니까?", - "confirmRemoveDescription": "이 시작 항목이 영구적으로 제거됩니다. 프로그램이 더 이상 Windows와 함께 시작되지 않습니다.", + "confirmRemoveDescription": "이 시작 항목이 영구적으로 제거됩니다. 프로그램은 더 이상 Windows와 함께 시작되지 않습니다.", "confirmRemoveLabel": "제거", - "historyCategoryEnabled": "사용", - "historyCategoryDisabled": "사용 안 함", + "historyCategoryEnabled": "활성화됨", + "historyCategoryDisabled": "비활성화됨", "historyCategoryRemoved": "제거됨", "removeButtonTitle": "{{name}} 제거", "safetyLinkCloud": "시작 프로그램의 AI 안전 등급을 보려면 Kudu Cloud에 연결하세요", "safetyPending": "안전성을 분석하는 중...", "safetyTooltipSafe": "안전함 — 자세히 보려면 클릭", "safetyTooltipCaution": "주의 필요 — 자세히 보려면 클릭", - "safetyTooltipWarning": "의심됨 — 자세히 보려면 클릭", + "safetyTooltipWarning": "의심스러움 — 자세히 보려면 클릭", "safetyTooltipDanger": "잠재적으로 안전하지 않음 — 자세히 보려면 클릭", "safetyTooltipPending": "안전성 분석 진행 중", "safetyTooltipLocked": "안전 등급을 보려면 Kudu Cloud에 연결하세요", "safetyScore": "안전성: {{score}}/10", - "safetyAnalyzed": "{{date}}에 분석됨", - "sortBySafety": "안전성순 정렬" + "safetyAnalyzed": "{{date}} 분석됨", + "sortBySafety": "안전성순 정렬", + "staleBadge": "설치되지 않음", + "staleTooltip": "이 항목이 가리키는 프로그램이 없어 더 이상 시작할 수 없습니다. 이 항목을 제거해도 안전합니다." } diff --git a/src/renderer/src/locales/ms/startup.json b/src/renderer/src/locales/ms/startup.json index 143bd604..52380106 100644 --- a/src/renderer/src/locales/ms/startup.json +++ b/src/renderer/src/locales/ms/startup.json @@ -1,6 +1,6 @@ { "pageTitle": "Pengurus Permulaan", - "pageDescription": "Urus program yang berjalan semasa permulaan", + "pageDescription": "Urus program yang dijalankan semasa permulaan", "filterAll": "Semua Item", "filterActive": "Aktif Sahaja", "filterDisabled": "Dilumpuhkan Sahaja", @@ -23,7 +23,7 @@ "bootTraceTitle": "Analisis Impak Permulaan", "bootTraceLastBoot": "But terakhir: {{date}}", "bootTraceBasedOnLastBoot": "Berdasarkan jejak but terakhir", - "bootTraceTotalBoot": "Jumlah but:", + "bootTraceTotalBoot": "Jumlah masa but:", "bootTraceHighImpactApp": "{{count}} aplikasi berimpak tinggi", "bootTraceHighImpactApps": "{{count}} aplikasi berimpak tinggi", "statTotalBootTime": "Jumlah Masa But", @@ -53,15 +53,17 @@ "historyCategoryDisabled": "Dilumpuhkan", "historyCategoryRemoved": "Dibuang", "removeButtonTitle": "Buang {{name}}", - "safetyLinkCloud": "Pautkan ke Kudu Cloud untuk melihat penilaian keselamatan AI bagi program permulaan anda", + "safetyLinkCloud": "Pautkan ke Kudu Cloud untuk melihat penarafan keselamatan AI bagi program permulaan anda", "safetyPending": "Menganalisis keselamatan...", "safetyTooltipSafe": "Selamat — klik untuk butiran", "safetyTooltipCaution": "Gunakan dengan berhati-hati — klik untuk butiran", "safetyTooltipWarning": "Mencurigakan — klik untuk butiran", "safetyTooltipDanger": "Berpotensi tidak selamat — klik untuk butiran", "safetyTooltipPending": "Analisis keselamatan sedang dijalankan", - "safetyTooltipLocked": "Pautkan ke Kudu Cloud untuk penilaian keselamatan", + "safetyTooltipLocked": "Pautkan ke Kudu Cloud untuk penarafan keselamatan", "safetyScore": "Keselamatan: {{score}}/10", "safetyAnalyzed": "Dianalisis pada {{date}}", - "sortBySafety": "Isih mengikut Keselamatan" + "sortBySafety": "Isih mengikut Keselamatan", + "staleBadge": "Tidak dipasang", + "staleTooltip": "Program yang dirujuk oleh entri ini tiada, jadi ia tidak lagi boleh dimulakan. Membuang entri ini adalah selamat." } diff --git a/src/renderer/src/locales/nl/startup.json b/src/renderer/src/locales/nl/startup.json index def58ea5..792f82b8 100644 --- a/src/renderer/src/locales/nl/startup.json +++ b/src/renderer/src/locales/nl/startup.json @@ -1,6 +1,6 @@ { "pageTitle": "Opstartbeheer", - "pageDescription": "Programma's beheren die bij het opstarten worden uitgevoerd", + "pageDescription": "Beheer programma's die bij het opstarten worden uitgevoerd", "filterAll": "Alle items", "filterActive": "Alleen actief", "filterDisabled": "Alleen uitgeschakeld", @@ -17,11 +17,11 @@ "sourceSystemdUser": "Systemd-gebruikersservice", "sourceAutostartDesktop": "XDG Autostart", "sourceCron": "Cron-taak", - "bootTraceAnalyzing": "Opstarttracegegevens analyseren...", - "bootTraceNeedsAdmin": "Voor opstarttracegegevens zijn beheerdersrechten vereist — start de app opnieuw als administrator om de analyse van de opstartimpact te bekijken.", + "bootTraceAnalyzing": "Opstarttracegegevens worden geanalyseerd...", + "bootTraceNeedsAdmin": "Opstarttracegegevens vereisen beheerdersrechten — start de app opnieuw als administrator om de analyse van de opstartimpact te bekijken.", "bootTraceNotAvailable": "Analyse van de opstarttrace is niet beschikbaar op dit platform.", "bootTraceTitle": "Analyse van opstartimpact", - "bootTraceLastBoot": "Laatste keer opstarten: {{date}}", + "bootTraceLastBoot": "Laatste opstart: {{date}}", "bootTraceBasedOnLastBoot": "Gebaseerd op de laatste opstarttrace", "bootTraceTotalBoot": "Totale opstarttijd:", "bootTraceHighImpactApp": "{{count}} app met hoge impact", @@ -29,7 +29,7 @@ "statTotalBootTime": "Totale opstarttijd", "statStartupAppsDelay": "Vertraging door opstartapps", "statAppsMeasured": "Gemeten apps", - "statPotentialSavings": "Mogelijke tijdswinst", + "statPotentialSavings": "Mogelijke besparing", "chartBootTimeImpact": "Impact op opstarttijd per toepassing", "chartNoPerAppData": "Geen opstartgegevens per app beschikbaar", "chartBootTimeBreakdown": "Verdeling van opstarttijd", @@ -54,7 +54,7 @@ "historyCategoryRemoved": "Verwijderd", "removeButtonTitle": "{{name}} verwijderen", "safetyLinkCloud": "Koppel aan Kudu Cloud om AI-veiligheidsbeoordelingen voor uw opstartprogramma's te bekijken", - "safetyPending": "Veiligheid analyseren...", + "safetyPending": "Veiligheid wordt geanalyseerd...", "safetyTooltipSafe": "Veilig — klik voor details", "safetyTooltipCaution": "Voorzichtig gebruiken — klik voor details", "safetyTooltipWarning": "Verdacht — klik voor details", @@ -63,5 +63,7 @@ "safetyTooltipLocked": "Koppel aan Kudu Cloud voor veiligheidsbeoordelingen", "safetyScore": "Veiligheid: {{score}}/10", "safetyAnalyzed": "Geanalyseerd op {{date}}", - "sortBySafety": "Sorteren op veiligheid" + "sortBySafety": "Sorteren op veiligheid", + "staleBadge": "Niet geïnstalleerd", + "staleTooltip": "Het programma waarnaar dit item verwijst ontbreekt, waardoor het niet meer kan worden gestart. Het item verwijderen is veilig." } diff --git a/src/renderer/src/locales/no/startup.json b/src/renderer/src/locales/no/startup.json index 39330762..3108a1ef 100644 --- a/src/renderer/src/locales/no/startup.json +++ b/src/renderer/src/locales/no/startup.json @@ -30,8 +30,8 @@ "statStartupAppsDelay": "Forsinkelse fra oppstartsapper", "statAppsMeasured": "Målte apper", "statPotentialSavings": "Potensiell besparelse", - "chartBootTimeImpact": "Oppstartstidspåvirkning per program", - "chartNoPerAppData": "Ingen oppstartsdata tilgjengelig per app", + "chartBootTimeImpact": "Påvirkning på oppstartstid per program", + "chartNoPerAppData": "Ingen oppstartsdata per app tilgjengelig", "chartBootTimeBreakdown": "Fordeling av oppstartstid", "chartTooltipDelay": "Forsinkelse", "pieCoreBoot": "Kjerneoppstart", @@ -47,7 +47,7 @@ "errorFailedToToggle": "Kunne ikke {{action}} {{name}}. Dette kan kreve administratorrettigheter.", "errorFailedToRemove": "Kunne ikke fjerne {{name}}. Dette kan kreve administratorrettigheter.", "confirmRemoveTitle": "Fjerne {{name}}?", - "confirmRemoveDescription": "Dette vil fjerne denne oppstartsoppføringen permanent. Programmet vil ikke lenger starte med Windows.", + "confirmRemoveDescription": "Dette vil permanent fjerne denne oppstartsoppføringen. Programmet vil ikke lenger starte med Windows.", "confirmRemoveLabel": "Fjern", "historyCategoryEnabled": "Aktivert", "historyCategoryDisabled": "Deaktivert", @@ -63,5 +63,7 @@ "safetyTooltipLocked": "Koble til Kudu Cloud for sikkerhetsvurderinger", "safetyScore": "Sikkerhet: {{score}}/10", "safetyAnalyzed": "Analysert {{date}}", - "sortBySafety": "Sorter etter sikkerhet" + "sortBySafety": "Sorter etter sikkerhet", + "staleBadge": "Ikke installert", + "staleTooltip": "Programmet denne oppføringen peker til mangler, så det kan ikke lenger starte. Det er trygt å fjerne oppføringen." } diff --git a/src/renderer/src/locales/pl/startup.json b/src/renderer/src/locales/pl/startup.json index ef91aea3..679ba2b4 100644 --- a/src/renderer/src/locales/pl/startup.json +++ b/src/renderer/src/locales/pl/startup.json @@ -14,13 +14,13 @@ "sourceLaunchAgentUser": "Agent uruchamiania użytkownika", "sourceLaunchAgentGlobal": "Globalny agent uruchamiania", "sourceLoginItem": "Element logowania", - "sourceSystemdUser": "Usługa użytkownika systemd", + "sourceSystemdUser": "Usługa użytkownika Systemd", "sourceAutostartDesktop": "Autostart XDG", "sourceCron": "Zadanie Cron", "bootTraceAnalyzing": "Analizowanie danych śledzenia rozruchu...", - "bootTraceNeedsAdmin": "Dane śledzenia rozruchu wymagają uprawnień administratora — uruchom ponownie aplikację jako administrator, aby wyświetlić analizę wpływu uruchamiania.", + "bootTraceNeedsAdmin": "Dane śledzenia rozruchu wymagają uprawnień administratora — uruchom ponownie aplikację jako administrator, aby wyświetlić analizę wpływu na uruchamianie.", "bootTraceNotAvailable": "Analiza śledzenia rozruchu nie jest dostępna na tej platformie.", - "bootTraceTitle": "Analiza wpływu uruchamiania", + "bootTraceTitle": "Analiza wpływu na uruchamianie", "bootTraceLastBoot": "Ostatni rozruch: {{date}}", "bootTraceBasedOnLastBoot": "Na podstawie śledzenia ostatniego rozruchu", "bootTraceTotalBoot": "Łączny czas rozruchu:", @@ -43,8 +43,8 @@ "toastFailedToDisable": "Nie udało się wyłączyć {{name}}", "toastFailedToRemove": "Nie udało się usunąć {{name}}", "toastAdminRequired": "To może wymagać uprawnień administratora", - "errorFailedToLoad": "Nie udało się załadować elementów uruchamiania. Upewnij się, że aplikacja działa prawidłowo.", - "errorFailedToToggle": "Nie udało się wykonać akcji {{action}} dla {{name}}. To może wymagać uprawnień administratora.", + "errorFailedToLoad": "Nie udało się wczytać elementów uruchamiania. Upewnij się, że aplikacja działa prawidłowo.", + "errorFailedToToggle": "Nie udało się wykonać akcji „{{action}}” dla {{name}}. To może wymagać uprawnień administratora.", "errorFailedToRemove": "Nie udało się usunąć {{name}}. To może wymagać uprawnień administratora.", "confirmRemoveTitle": "Usunąć {{name}}?", "confirmRemoveDescription": "Spowoduje to trwałe usunięcie tego wpisu uruchamiania. Program nie będzie już uruchamiany wraz z Windows.", @@ -53,7 +53,7 @@ "historyCategoryDisabled": "Wyłączone", "historyCategoryRemoved": "Usunięte", "removeButtonTitle": "Usuń {{name}}", - "safetyLinkCloud": "Połącz z Kudu Cloud, aby zobaczyć oceny bezpieczeństwa AI dla swoich programów uruchamianych przy starcie systemu", + "safetyLinkCloud": "Połącz z Kudu Cloud, aby zobaczyć oceny bezpieczeństwa AI dla swoich programów uruchamianych przy starcie", "safetyPending": "Analizowanie bezpieczeństwa...", "safetyTooltipSafe": "Bezpieczne — kliknij, aby zobaczyć szczegóły", "safetyTooltipCaution": "Zachowaj ostrożność — kliknij, aby zobaczyć szczegóły", @@ -63,5 +63,7 @@ "safetyTooltipLocked": "Połącz z Kudu Cloud, aby uzyskać oceny bezpieczeństwa", "safetyScore": "Bezpieczeństwo: {{score}}/10", "safetyAnalyzed": "Przeanalizowano: {{date}}", - "sortBySafety": "Sortuj według bezpieczeństwa" + "sortBySafety": "Sortuj według bezpieczeństwa", + "staleBadge": "Nie zainstalowano", + "staleTooltip": "Program, do którego odwołuje się ten wpis, nie istnieje, więc nie może już zostać uruchomiony. Usunięcie wpisu jest bezpieczne." } diff --git a/src/renderer/src/locales/pt/startup.json b/src/renderer/src/locales/pt/startup.json index 2949dcae..b0cd0200 100644 --- a/src/renderer/src/locales/pt/startup.json +++ b/src/renderer/src/locales/pt/startup.json @@ -1,6 +1,6 @@ { - "pageTitle": "Gestor de Inicialização", - "pageDescription": "Gerir programas executados na inicialização", + "pageTitle": "Gestor de Arranque", + "pageDescription": "Gerir programas executados no arranque", "filterAll": "Todos os itens", "filterActive": "Apenas ativos", "filterDisabled": "Apenas desativados", @@ -9,25 +9,25 @@ "impactLabel": "impacto {{level}}", "sourceUserRegistry": "Registo do utilizador", "sourceSystemRegistry": "Registo do sistema", - "sourceStartupFolder": "Pasta de Inicialização", + "sourceStartupFolder": "Pasta de arranque", "sourceTaskScheduler": "Agendador de Tarefas", "sourceLaunchAgentUser": "Agente de arranque do utilizador", "sourceLaunchAgentGlobal": "Agente de arranque global", "sourceLoginItem": "Item de início de sessão", - "sourceSystemdUser": "Serviço de utilizador do systemd", + "sourceSystemdUser": "Serviço de utilizador Systemd", "sourceAutostartDesktop": "Arranque automático XDG", "sourceCron": "Tarefa Cron", "bootTraceAnalyzing": "A analisar dados de rastreio do arranque...", - "bootTraceNeedsAdmin": "Os dados de rastreio do arranque requerem privilégios de administrador — reinicie a aplicação como administrador para ver a análise do impacto na inicialização.", + "bootTraceNeedsAdmin": "Os dados de rastreio do arranque requerem privilégios de administrador — reinicie a aplicação como administrador para ver a análise do impacto no arranque.", "bootTraceNotAvailable": "A análise do rastreio do arranque não está disponível nesta plataforma.", - "bootTraceTitle": "Análise do impacto na inicialização", + "bootTraceTitle": "Análise do impacto no arranque", "bootTraceLastBoot": "Último arranque: {{date}}", - "bootTraceBasedOnLastBoot": "Com base no rastreio do último arranque", + "bootTraceBasedOnLastBoot": "Com base no último rastreio de arranque", "bootTraceTotalBoot": "Arranque total:", "bootTraceHighImpactApp": "{{count}} aplicação de elevado impacto", "bootTraceHighImpactApps": "{{count}} aplicações de elevado impacto", "statTotalBootTime": "Tempo total de arranque", - "statStartupAppsDelay": "Atraso das aplicações de inicialização", + "statStartupAppsDelay": "Atraso das aplicações de arranque", "statAppsMeasured": "Aplicações medidas", "statPotentialSavings": "Poupança potencial", "chartBootTimeImpact": "Impacto no tempo de arranque por aplicação", @@ -35,33 +35,35 @@ "chartBootTimeBreakdown": "Detalhe do tempo de arranque", "chartTooltipDelay": "Atraso", "pieCoreBoot": "Arranque principal", - "pieStartupApps": "Aplicações de inicialização", + "pieStartupApps": "Aplicações de arranque", "pieOther": "Outros", - "emptyStateTitle": "Não foram encontrados itens de inicialização", - "emptyStateDescription": "Não foi possível detetar programas de inicialização.", + "emptyStateTitle": "Nenhum item de arranque encontrado", + "emptyStateDescription": "Não foi possível detetar programas de arranque.", "toastFailedToEnable": "Falha ao ativar {{name}}", "toastFailedToDisable": "Falha ao desativar {{name}}", "toastFailedToRemove": "Falha ao remover {{name}}", "toastAdminRequired": "Isto pode requerer privilégios de administrador", - "errorFailedToLoad": "Falha ao carregar os itens de inicialização. Certifique-se de que a aplicação está a funcionar corretamente.", + "errorFailedToLoad": "Falha ao carregar os itens de arranque. Certifique-se de que a aplicação está a funcionar corretamente.", "errorFailedToToggle": "Falha ao {{action}} {{name}}. Isto pode requerer privilégios de administrador.", "errorFailedToRemove": "Falha ao remover {{name}}. Isto pode requerer privilégios de administrador.", "confirmRemoveTitle": "Remover {{name}}?", - "confirmRemoveDescription": "Isto irá remover permanentemente esta entrada de inicialização. O programa deixará de iniciar com o Windows.", + "confirmRemoveDescription": "Isto irá remover permanentemente esta entrada de arranque. O programa deixará de iniciar com o Windows.", "confirmRemoveLabel": "Remover", "historyCategoryEnabled": "Ativado", "historyCategoryDisabled": "Desativado", "historyCategoryRemoved": "Removido", "removeButtonTitle": "Remover {{name}}", - "safetyLinkCloud": "Ligue ao Kudu Cloud para ver classificações de segurança com IA para os seus programas de inicialização", + "safetyLinkCloud": "Ligue ao Kudu Cloud para ver classificações de segurança por IA para os seus programas de arranque", "safetyPending": "A analisar a segurança...", - "safetyTooltipSafe": "Seguro — clique para ver detalhes", - "safetyTooltipCaution": "Use com cautela — clique para ver detalhes", - "safetyTooltipWarning": "Suspeito — clique para ver detalhes", - "safetyTooltipDanger": "Potencialmente inseguro — clique para ver detalhes", + "safetyTooltipSafe": "Seguro — clique para ver os detalhes", + "safetyTooltipCaution": "Utilize com cautela — clique para ver os detalhes", + "safetyTooltipWarning": "Suspeito — clique para ver os detalhes", + "safetyTooltipDanger": "Potencialmente inseguro — clique para ver os detalhes", "safetyTooltipPending": "Análise de segurança em curso", - "safetyTooltipLocked": "Ligue ao Kudu Cloud para ver classificações de segurança", + "safetyTooltipLocked": "Ligue ao Kudu Cloud para ver as classificações de segurança", "safetyScore": "Segurança: {{score}}/10", "safetyAnalyzed": "Analisado em {{date}}", - "sortBySafety": "Ordenar por segurança" + "sortBySafety": "Ordenar por segurança", + "staleBadge": "Não instalado", + "staleTooltip": "O programa para o qual esta entrada aponta está em falta, pelo que já não pode iniciar. É seguro remover a entrada." } diff --git a/src/renderer/src/locales/ro/startup.json b/src/renderer/src/locales/ro/startup.json index 1b2e308d..64fb6e13 100644 --- a/src/renderer/src/locales/ro/startup.json +++ b/src/renderer/src/locales/ro/startup.json @@ -11,8 +11,8 @@ "sourceSystemRegistry": "Registry sistem", "sourceStartupFolder": "Folder de pornire", "sourceTaskScheduler": "Planificator de activități", - "sourceLaunchAgentUser": "Agent de lansare utilizator", - "sourceLaunchAgentGlobal": "Agent de lansare global", + "sourceLaunchAgentUser": "Launch Agent utilizator", + "sourceLaunchAgentGlobal": "Launch Agent global", "sourceLoginItem": "Element de autentificare", "sourceSystemdUser": "Serviciu Systemd utilizator", "sourceAutostartDesktop": "Autostart XDG", @@ -27,7 +27,7 @@ "bootTraceHighImpactApp": "{{count}} aplicație cu impact ridicat", "bootTraceHighImpactApps": "{{count}} aplicații cu impact ridicat", "statTotalBootTime": "Timp total de pornire", - "statStartupAppsDelay": "Întârziere cauzată de aplicațiile de pornire", + "statStartupAppsDelay": "Întârziere aplicații de pornire", "statAppsMeasured": "Aplicații măsurate", "statPotentialSavings": "Economii potențiale", "chartBootTimeImpact": "Impactul asupra timpului de pornire după aplicație", @@ -48,20 +48,22 @@ "errorFailedToRemove": "Eliminarea {{name}} a eșuat. Acest lucru poate necesita privilegii de administrator.", "confirmRemoveTitle": "Eliminați {{name}}?", "confirmRemoveDescription": "Aceasta va elimina definitiv această intrare de pornire. Programul nu va mai porni odată cu Windows.", - "confirmRemoveLabel": "Elimină", + "confirmRemoveLabel": "Eliminare", "historyCategoryEnabled": "Activat", "historyCategoryDisabled": "Dezactivat", "historyCategoryRemoved": "Eliminat", - "removeButtonTitle": "Elimină {{name}}", - "safetyLinkCloud": "Conectați la Kudu Cloud pentru a vedea evaluările AI de siguranță pentru programele dvs. de pornire", + "removeButtonTitle": "Eliminați {{name}}", + "safetyLinkCloud": "Conectați-vă la Kudu Cloud pentru a vedea evaluările AI de siguranță pentru programele dvs. de pornire", "safetyPending": "Se analizează siguranța...", "safetyTooltipSafe": "Sigur — faceți clic pentru detalii", - "safetyTooltipCaution": "Folosiți cu prudență — faceți clic pentru detalii", + "safetyTooltipCaution": "Utilizați cu prudență — faceți clic pentru detalii", "safetyTooltipWarning": "Suspect — faceți clic pentru detalii", "safetyTooltipDanger": "Potențial nesigur — faceți clic pentru detalii", "safetyTooltipPending": "Analiza de siguranță este în curs", - "safetyTooltipLocked": "Conectați la Kudu Cloud pentru evaluări de siguranță", + "safetyTooltipLocked": "Conectați-vă la Kudu Cloud pentru evaluări de siguranță", "safetyScore": "Siguranță: {{score}}/10", "safetyAnalyzed": "Analizat la {{date}}", - "sortBySafety": "Sortare după siguranță" + "sortBySafety": "Sortare după siguranță", + "staleBadge": "Neinstalat", + "staleTooltip": "Programul către care indică această intrare lipsește, astfel încât nu mai poate porni. Eliminarea intrării este sigură." } diff --git a/src/renderer/src/locales/ru/startup.json b/src/renderer/src/locales/ru/startup.json index 24bfafcb..31d6a9e1 100644 --- a/src/renderer/src/locales/ru/startup.json +++ b/src/renderer/src/locales/ru/startup.json @@ -13,7 +13,7 @@ "sourceTaskScheduler": "Планировщик заданий", "sourceLaunchAgentUser": "Агент запуска пользователя", "sourceLaunchAgentGlobal": "Глобальный агент запуска", - "sourceLoginItem": "Объект входа", + "sourceLoginItem": "Элемент входа", "sourceSystemdUser": "Пользовательская служба Systemd", "sourceAutostartDesktop": "Автозапуск XDG", "sourceCron": "Задание Cron", @@ -60,8 +60,10 @@ "safetyTooltipWarning": "Подозрительно — нажмите для подробностей", "safetyTooltipDanger": "Потенциально небезопасно — нажмите для подробностей", "safetyTooltipPending": "Выполняется анализ безопасности", - "safetyTooltipLocked": "Подключите Kudu Cloud для получения оценок безопасности", + "safetyTooltipLocked": "Подключите Kudu Cloud для оценок безопасности", "safetyScore": "Безопасность: {{score}}/10", "safetyAnalyzed": "Проанализировано: {{date}}", - "sortBySafety": "Сортировать по безопасности" + "sortBySafety": "Сортировать по безопасности", + "staleBadge": "Не установлено", + "staleTooltip": "Программа, на которую указывает эта запись, отсутствует, поэтому она больше не может запускаться. Удаление этой записи безопасно." } diff --git a/src/renderer/src/locales/sv/startup.json b/src/renderer/src/locales/sv/startup.json index 282042d5..3e2396d6 100644 --- a/src/renderer/src/locales/sv/startup.json +++ b/src/renderer/src/locales/sv/startup.json @@ -18,27 +18,27 @@ "sourceAutostartDesktop": "XDG Autostart", "sourceCron": "Cron-jobb", "bootTraceAnalyzing": "Analyserar startspårningsdata...", - "bootTraceNeedsAdmin": "Startspårningsdata kräver administratörsbehörighet — starta om appen som administratör för att visa analys av autostartspåverkan.", + "bootTraceNeedsAdmin": "Startspårningsdata kräver administratörsbehörighet — starta om appen som administratör för att visa analys av startpåverkan.", "bootTraceNotAvailable": "Analys av startspårning är inte tillgänglig på den här plattformen.", - "bootTraceTitle": "Analys av autostartspåverkan", + "bootTraceTitle": "Analys av startpåverkan", "bootTraceLastBoot": "Senaste start: {{date}}", - "bootTraceBasedOnLastBoot": "Baserad på senaste startspårning", - "bootTraceTotalBoot": "Total start:", + "bootTraceBasedOnLastBoot": "Baserat på senaste startspårning", + "bootTraceTotalBoot": "Total starttid:", "bootTraceHighImpactApp": "{{count}} app med hög påverkan", "bootTraceHighImpactApps": "{{count}} appar med hög påverkan", "statTotalBootTime": "Total starttid", - "statStartupAppsDelay": "Fördröjning från autostartsappar", + "statStartupAppsDelay": "Fördröjning från startappar", "statAppsMeasured": "Uppmätta appar", "statPotentialSavings": "Potentiell besparing", "chartBootTimeImpact": "Påverkan på starttid per program", "chartNoPerAppData": "Inga startdata per app tillgängliga", - "chartBootTimeBreakdown": "Fördelning av starttid", + "chartBootTimeBreakdown": "Uppdelning av starttid", "chartTooltipDelay": "Fördröjning", - "pieCoreBoot": "Grundläggande start", - "pieStartupApps": "Autostartsappar", + "pieCoreBoot": "Kärnstart", + "pieStartupApps": "Startappar", "pieOther": "Övrigt", "emptyStateTitle": "Inga autostartsobjekt hittades", - "emptyStateDescription": "Det gick inte att identifiera autostartsprogram.", + "emptyStateDescription": "Det gick inte att identifiera autostartprogram.", "toastFailedToEnable": "Det gick inte att aktivera {{name}}", "toastFailedToDisable": "Det gick inte att inaktivera {{name}}", "toastFailedToRemove": "Det gick inte att ta bort {{name}}", @@ -47,21 +47,23 @@ "errorFailedToToggle": "Det gick inte att {{action}} {{name}}. Detta kan kräva administratörsbehörighet.", "errorFailedToRemove": "Det gick inte att ta bort {{name}}. Detta kan kräva administratörsbehörighet.", "confirmRemoveTitle": "Ta bort {{name}}?", - "confirmRemoveDescription": "Detta tar permanent bort den här autostartsposten. Programmet kommer inte längre att starta med Windows.", + "confirmRemoveDescription": "Detta tar bort den här autostartposten permanent. Programmet kommer inte längre att starta med Windows.", "confirmRemoveLabel": "Ta bort", "historyCategoryEnabled": "Aktiverad", "historyCategoryDisabled": "Inaktiverad", "historyCategoryRemoved": "Borttagen", "removeButtonTitle": "Ta bort {{name}}", - "safetyLinkCloud": "Anslut till Kudu Cloud för att se AI-säkerhetsbetyg för dina autostartsprogram", + "safetyLinkCloud": "Länka till Kudu Cloud för att se AI-säkerhetsbetyg för dina autostartprogram", "safetyPending": "Analyserar säkerhet...", "safetyTooltipSafe": "Säker — klicka för detaljer", "safetyTooltipCaution": "Var försiktig — klicka för detaljer", "safetyTooltipWarning": "Misstänkt — klicka för detaljer", "safetyTooltipDanger": "Potentiellt osäker — klicka för detaljer", "safetyTooltipPending": "Säkerhetsanalys pågår", - "safetyTooltipLocked": "Anslut till Kudu Cloud för säkerhetsbetyg", + "safetyTooltipLocked": "Länka till Kudu Cloud för säkerhetsbetyg", "safetyScore": "Säkerhet: {{score}}/10", "safetyAnalyzed": "Analyserad {{date}}", - "sortBySafety": "Sortera efter säkerhet" + "sortBySafety": "Sortera efter säkerhet", + "staleBadge": "Inte installerad", + "staleTooltip": "Programmet som den här posten pekar på saknas, så det kan inte längre starta. Det är säkert att ta bort posten." } diff --git a/src/renderer/src/locales/th/startup.json b/src/renderer/src/locales/th/startup.json index feb9321c..071e1fd6 100644 --- a/src/renderer/src/locales/th/startup.json +++ b/src/renderer/src/locales/th/startup.json @@ -14,15 +14,15 @@ "sourceLaunchAgentUser": "Launch Agent ของผู้ใช้", "sourceLaunchAgentGlobal": "Launch Agent ส่วนกลาง", "sourceLoginItem": "รายการเข้าสู่ระบบ", - "sourceSystemdUser": "บริการ Systemd ของผู้ใช้", + "sourceSystemdUser": "บริการผู้ใช้ Systemd", "sourceAutostartDesktop": "XDG Autostart", "sourceCron": "งาน Cron", "bootTraceAnalyzing": "กำลังวิเคราะห์ข้อมูลการติดตามการบูต...", - "bootTraceNeedsAdmin": "ข้อมูลการติดตามการบูตต้องใช้สิทธิ์ผู้ดูแลระบบ — โปรดเริ่มแอปใหม่ในฐานะผู้ดูแลระบบเพื่อดูการวิเคราะห์ผลกระทบของโปรแกรมเริ่มต้นระบบ", + "bootTraceNeedsAdmin": "ข้อมูลการติดตามการบูตต้องใช้สิทธิ์ผู้ดูแลระบบ — โปรดเริ่มแอปใหม่ในฐานะผู้ดูแลระบบเพื่อดูการวิเคราะห์ผลกระทบต่อการเริ่มต้นระบบ", "bootTraceNotAvailable": "การวิเคราะห์การติดตามการบูตไม่พร้อมใช้งานบนแพลตฟอร์มนี้", - "bootTraceTitle": "การวิเคราะห์ผลกระทบของโปรแกรมเริ่มต้นระบบ", - "bootTraceLastBoot": "การบูตล่าสุด: {{date}}", - "bootTraceBasedOnLastBoot": "อ้างอิงจากการติดตามการบูตครั้งล่าสุด", + "bootTraceTitle": "การวิเคราะห์ผลกระทบต่อการเริ่มต้นระบบ", + "bootTraceLastBoot": "บูตล่าสุด: {{date}}", + "bootTraceBasedOnLastBoot": "อ้างอิงจากการติดตามการบูตล่าสุด", "bootTraceTotalBoot": "เวลาบูตรวม:", "bootTraceHighImpactApp": "แอปที่มีผลกระทบสูง {{count}} รายการ", "bootTraceHighImpactApps": "แอปที่มีผลกระทบสูง {{count}} รายการ", @@ -46,14 +46,14 @@ "errorFailedToLoad": "ไม่สามารถโหลดรายการเริ่มต้นระบบได้ โปรดตรวจสอบว่าแอปทำงานอย่างถูกต้อง", "errorFailedToToggle": "ไม่สามารถ{{action}} {{name}} ได้ การดำเนินการนี้อาจต้องใช้สิทธิ์ผู้ดูแลระบบ", "errorFailedToRemove": "ไม่สามารถลบ {{name}} ได้ การดำเนินการนี้อาจต้องใช้สิทธิ์ผู้ดูแลระบบ", - "confirmRemoveTitle": "ลบ {{name}} ใช่หรือไม่?", + "confirmRemoveTitle": "ลบ {{name}} หรือไม่?", "confirmRemoveDescription": "การดำเนินการนี้จะลบรายการเริ่มต้นระบบนี้อย่างถาวร โปรแกรมจะไม่เริ่มทำงานพร้อมกับ Windows อีกต่อไป", "confirmRemoveLabel": "ลบ", - "historyCategoryEnabled": "เปิดใช้งานแล้ว", - "historyCategoryDisabled": "ปิดใช้งานแล้ว", + "historyCategoryEnabled": "เปิดใช้งาน", + "historyCategoryDisabled": "ปิดใช้งาน", "historyCategoryRemoved": "ลบแล้ว", "removeButtonTitle": "ลบ {{name}}", - "safetyLinkCloud": "เชื่อมโยงกับ Kudu Cloud เพื่อดูคะแนนความปลอดภัยด้วย AI สำหรับโปรแกรมเริ่มต้นระบบของคุณ", + "safetyLinkCloud": "เชื่อมโยงกับ Kudu Cloud เพื่อดูคะแนนความปลอดภัยจาก AI สำหรับโปรแกรมเริ่มต้นระบบของคุณ", "safetyPending": "กำลังวิเคราะห์ความปลอดภัย...", "safetyTooltipSafe": "ปลอดภัย — คลิกเพื่อดูรายละเอียด", "safetyTooltipCaution": "ควรใช้ความระมัดระวัง — คลิกเพื่อดูรายละเอียด", @@ -63,5 +63,7 @@ "safetyTooltipLocked": "เชื่อมโยงกับ Kudu Cloud เพื่อดูคะแนนความปลอดภัย", "safetyScore": "ความปลอดภัย: {{score}}/10", "safetyAnalyzed": "วิเคราะห์เมื่อ {{date}}", - "sortBySafety": "เรียงตามความปลอดภัย" + "sortBySafety": "เรียงตามความปลอดภัย", + "staleBadge": "ไม่ได้ติดตั้ง", + "staleTooltip": "ไม่พบโปรแกรมที่รายการนี้อ้างอิงอยู่ จึงไม่สามารถเริ่มทำงานได้อีกต่อไป การลบรายการนี้มีความปลอดภัย" } diff --git a/src/renderer/src/locales/tr/startup.json b/src/renderer/src/locales/tr/startup.json index 3f518c59..52080048 100644 --- a/src/renderer/src/locales/tr/startup.json +++ b/src/renderer/src/locales/tr/startup.json @@ -4,7 +4,7 @@ "filterAll": "Tüm Öğeler", "filterActive": "Yalnızca Etkin", "filterDisabled": "Yalnızca Devre Dışı", - "sortByImpact": "Etkisine Göre Sırala", + "sortByImpact": "Etkiye Göre Sırala", "sortByName": "Ada Göre Sırala", "impactLabel": "{{level}} etki", "sourceUserRegistry": "Kullanıcı Kayıt Defteri", @@ -47,7 +47,7 @@ "errorFailedToToggle": "{{name}} için {{action}} işlemi başarısız oldu. Bu işlem yönetici ayrıcalıkları gerektirebilir.", "errorFailedToRemove": "{{name}} kaldırılamadı. Bu işlem yönetici ayrıcalıkları gerektirebilir.", "confirmRemoveTitle": "{{name}} kaldırılsın mı?", - "confirmRemoveDescription": "Bu işlem bu başlangıç girdisini kalıcı olarak kaldıracaktır. Program artık Windows ile başlamayacaktır.", + "confirmRemoveDescription": "Bu işlem bu başlangıç girdisini kalıcı olarak kaldıracaktır. Program artık Windows ile birlikte başlamayacaktır.", "confirmRemoveLabel": "Kaldır", "historyCategoryEnabled": "Etkinleştirildi", "historyCategoryDisabled": "Devre Dışı Bırakıldı", @@ -63,5 +63,7 @@ "safetyTooltipLocked": "Güvenlik derecelendirmeleri için Kudu Cloud'a bağlanın", "safetyScore": "Güvenlik: {{score}}/10", "safetyAnalyzed": "Analiz tarihi: {{date}}", - "sortBySafety": "Güvenliğe Göre Sırala" + "sortBySafety": "Güvenliğe Göre Sırala", + "staleBadge": "Yüklü değil", + "staleTooltip": "Bu girdinin işaret ettiği program eksik olduğundan artık başlatılamaz. Girdiyi kaldırmak güvenlidir." } diff --git a/src/renderer/src/locales/uk/startup.json b/src/renderer/src/locales/uk/startup.json index b03ee72a..323b7729 100644 --- a/src/renderer/src/locales/uk/startup.json +++ b/src/renderer/src/locales/uk/startup.json @@ -23,12 +23,12 @@ "bootTraceTitle": "Аналіз впливу автозапуску", "bootTraceLastBoot": "Останнє завантаження: {{date}}", "bootTraceBasedOnLastBoot": "На основі трасування останнього завантаження", - "bootTraceTotalBoot": "Загальний час завантаження:", + "bootTraceTotalBoot": "Загальне завантаження:", "bootTraceHighImpactApp": "{{count}} програма з високим впливом", "bootTraceHighImpactApps": "{{count}} програм із високим впливом", "statTotalBootTime": "Загальний час завантаження", "statStartupAppsDelay": "Затримка програм автозапуску", - "statAppsMeasured": "Оцінено програм", + "statAppsMeasured": "Виміряно програм", "statPotentialSavings": "Потенційна економія", "chartBootTimeImpact": "Вплив програм на час завантаження", "chartNoPerAppData": "Дані завантаження для окремих програм недоступні", @@ -53,15 +53,17 @@ "historyCategoryDisabled": "Вимкнено", "historyCategoryRemoved": "Видалено", "removeButtonTitle": "Видалити {{name}}", - "safetyLinkCloud": "Підключіть Kudu Cloud, щоб переглянути AI-оцінки безпеки для ваших програм автозапуску", + "safetyLinkCloud": "Підключіться до Kudu Cloud, щоб переглянути AI-оцінки безпеки для ваших програм автозапуску", "safetyPending": "Аналіз безпеки...", "safetyTooltipSafe": "Безпечно — натисніть, щоб переглянути подробиці", "safetyTooltipCaution": "Будьте обережні — натисніть, щоб переглянути подробиці", "safetyTooltipWarning": "Підозріло — натисніть, щоб переглянути подробиці", "safetyTooltipDanger": "Потенційно небезпечно — натисніть, щоб переглянути подробиці", "safetyTooltipPending": "Триває аналіз безпеки", - "safetyTooltipLocked": "Підключіть Kudu Cloud для оцінок безпеки", + "safetyTooltipLocked": "Підключіться до Kudu Cloud, щоб переглянути оцінки безпеки", "safetyScore": "Безпека: {{score}}/10", "safetyAnalyzed": "Проаналізовано: {{date}}", - "sortBySafety": "Сортувати за безпекою" + "sortBySafety": "Сортувати за безпекою", + "staleBadge": "Не встановлено", + "staleTooltip": "Програма, на яку вказує цей запис, відсутня, тому більше не може запускатися. Видалення цього запису є безпечним." } diff --git a/src/renderer/src/locales/vi/startup.json b/src/renderer/src/locales/vi/startup.json index dff5a7b8..890d0f49 100644 --- a/src/renderer/src/locales/vi/startup.json +++ b/src/renderer/src/locales/vi/startup.json @@ -2,8 +2,8 @@ "pageTitle": "Trình quản lý khởi động", "pageDescription": "Quản lý các chương trình chạy khi khởi động", "filterAll": "Tất cả mục", - "filterActive": "Chỉ đang bật", - "filterDisabled": "Chỉ đã tắt", + "filterActive": "Chỉ mục đang bật", + "filterDisabled": "Chỉ mục đã tắt", "sortByImpact": "Sắp xếp theo mức ảnh hưởng", "sortByName": "Sắp xếp theo tên", "impactLabel": "Mức ảnh hưởng {{level}}", @@ -17,20 +17,20 @@ "sourceSystemdUser": "Dịch vụ người dùng Systemd", "sourceAutostartDesktop": "Tự khởi động XDG", "sourceCron": "Tác vụ Cron", - "bootTraceAnalyzing": "Đang phân tích dữ liệu theo dõi khởi động...", - "bootTraceNeedsAdmin": "Dữ liệu theo dõi khởi động yêu cầu quyền quản trị viên — hãy khởi động lại ứng dụng với quyền quản trị viên để xem phân tích ảnh hưởng khởi động.", - "bootTraceNotAvailable": "Phân tích theo dõi khởi động không khả dụng trên nền tảng này.", + "bootTraceAnalyzing": "Đang phân tích dữ liệu dấu vết khởi động...", + "bootTraceNeedsAdmin": "Dữ liệu dấu vết khởi động yêu cầu quyền quản trị viên — hãy khởi động lại ứng dụng với quyền quản trị viên để xem phân tích ảnh hưởng khởi động.", + "bootTraceNotAvailable": "Phân tích dấu vết khởi động không khả dụng trên nền tảng này.", "bootTraceTitle": "Phân tích ảnh hưởng khởi động", "bootTraceLastBoot": "Lần khởi động gần nhất: {{date}}", - "bootTraceBasedOnLastBoot": "Dựa trên dữ liệu theo dõi của lần khởi động gần nhất", + "bootTraceBasedOnLastBoot": "Dựa trên dấu vết của lần khởi động gần nhất", "bootTraceTotalBoot": "Tổng thời gian khởi động:", "bootTraceHighImpactApp": "{{count}} ứng dụng ảnh hưởng cao", "bootTraceHighImpactApps": "{{count}} ứng dụng ảnh hưởng cao", "statTotalBootTime": "Tổng thời gian khởi động", - "statStartupAppsDelay": "Độ trễ do ứng dụng khởi động", + "statStartupAppsDelay": "Độ trễ ứng dụng khởi động", "statAppsMeasured": "Ứng dụng đã đo", "statPotentialSavings": "Mức tiết kiệm tiềm năng", - "chartBootTimeImpact": "Ảnh hưởng đến thời gian khởi động theo ứng dụng", + "chartBootTimeImpact": "Ảnh hưởng thời gian khởi động theo ứng dụng", "chartNoPerAppData": "Không có dữ liệu khởi động theo từng ứng dụng", "chartBootTimeBreakdown": "Phân tích thời gian khởi động", "chartTooltipDelay": "Độ trễ", @@ -55,13 +55,15 @@ "removeButtonTitle": "Xóa {{name}}", "safetyLinkCloud": "Liên kết với Kudu Cloud để xem xếp hạng an toàn bằng AI cho các chương trình khởi động của bạn", "safetyPending": "Đang phân tích độ an toàn...", - "safetyTooltipSafe": "An toàn — nhấp để xem chi tiết", - "safetyTooltipCaution": "Cần thận trọng — nhấp để xem chi tiết", - "safetyTooltipWarning": "Đáng ngờ — nhấp để xem chi tiết", - "safetyTooltipDanger": "Có khả năng không an toàn — nhấp để xem chi tiết", + "safetyTooltipSafe": "An toàn — bấm để xem chi tiết", + "safetyTooltipCaution": "Cần thận trọng — bấm để xem chi tiết", + "safetyTooltipWarning": "Đáng ngờ — bấm để xem chi tiết", + "safetyTooltipDanger": "Có khả năng không an toàn — bấm để xem chi tiết", "safetyTooltipPending": "Đang phân tích độ an toàn", "safetyTooltipLocked": "Liên kết với Kudu Cloud để xem xếp hạng an toàn", "safetyScore": "Độ an toàn: {{score}}/10", - "safetyAnalyzed": "Đã phân tích vào {{date}}", - "sortBySafety": "Sắp xếp theo độ an toàn" + "safetyAnalyzed": "Đã phân tích {{date}}", + "sortBySafety": "Sắp xếp theo độ an toàn", + "staleBadge": "Chưa được cài đặt", + "staleTooltip": "Chương trình mà mục này trỏ tới không còn tồn tại, nên không thể khởi động nữa. Có thể xóa mục này một cách an toàn." } diff --git a/src/renderer/src/locales/zh-CN/startup.json b/src/renderer/src/locales/zh-CN/startup.json index d9e4e605..e3704561 100644 --- a/src/renderer/src/locales/zh-CN/startup.json +++ b/src/renderer/src/locales/zh-CN/startup.json @@ -1,9 +1,9 @@ { "pageTitle": "启动项管理器", "pageDescription": "管理开机时运行的程序", - "filterAll": "所有项目", - "filterActive": "仅显示已启用", - "filterDisabled": "仅显示已禁用", + "filterAll": "全部项目", + "filterActive": "仅活动项", + "filterDisabled": "仅已禁用项", "sortByImpact": "按影响排序", "sortByName": "按名称排序", "impactLabel": "{{level}} 影响", @@ -18,7 +18,7 @@ "sourceAutostartDesktop": "XDG 自动启动", "sourceCron": "Cron 任务", "bootTraceAnalyzing": "正在分析启动跟踪数据...", - "bootTraceNeedsAdmin": "启动跟踪数据需要管理员权限——请以管理员身份重新启动应用以查看启动影响分析。", + "bootTraceNeedsAdmin": "启动跟踪数据需要管理员权限 — 请以管理员身份重新启动应用以查看启动影响分析。", "bootTraceNotAvailable": "此平台不支持启动跟踪分析。", "bootTraceTitle": "启动影响分析", "bootTraceLastBoot": "上次启动:{{date}}", @@ -29,8 +29,8 @@ "statTotalBootTime": "总启动时间", "statStartupAppsDelay": "启动应用延迟", "statAppsMeasured": "已测量应用数", - "statPotentialSavings": "潜在节省时间", - "chartBootTimeImpact": "各应用对启动时间的影响", + "statPotentialSavings": "可节省时间", + "chartBootTimeImpact": "各应用的启动时间影响", "chartNoPerAppData": "没有可用的单个应用启动数据", "chartBootTimeBreakdown": "启动时间明细", "chartTooltipDelay": "延迟", @@ -55,13 +55,15 @@ "removeButtonTitle": "移除 {{name}}", "safetyLinkCloud": "关联到 Kudu Cloud 以查看启动程序的 AI 安全评级", "safetyPending": "正在分析安全性...", - "safetyTooltipSafe": "安全——点击查看详情", - "safetyTooltipCaution": "请谨慎使用——点击查看详情", - "safetyTooltipWarning": "可疑——点击查看详情", - "safetyTooltipDanger": "可能不安全——点击查看详情", + "safetyTooltipSafe": "安全 — 点击查看详情", + "safetyTooltipCaution": "请谨慎使用 — 点击查看详情", + "safetyTooltipWarning": "可疑 — 点击查看详情", + "safetyTooltipDanger": "可能不安全 — 点击查看详情", "safetyTooltipPending": "安全分析进行中", "safetyTooltipLocked": "关联到 Kudu Cloud 以查看安全评级", "safetyScore": "安全性:{{score}}/10", "safetyAnalyzed": "分析时间:{{date}}", - "sortBySafety": "按安全性排序" + "sortBySafety": "按安全性排序", + "staleBadge": "未安装", + "staleTooltip": "此项指向的程序已丢失,因此无法再启动。移除此项是安全的。" } diff --git a/src/renderer/src/locales/zh-TW/startup.json b/src/renderer/src/locales/zh-TW/startup.json index f7188f75..851c317e 100644 --- a/src/renderer/src/locales/zh-TW/startup.json +++ b/src/renderer/src/locales/zh-TW/startup.json @@ -19,7 +19,7 @@ "sourceCron": "Cron 工作", "bootTraceAnalyzing": "正在分析開機追蹤資料...", "bootTraceNeedsAdmin": "開機追蹤資料需要系統管理員權限 — 請以系統管理員身分重新啟動應用程式,以檢視啟動影響分析。", - "bootTraceNotAvailable": "此平台不提供開機追蹤分析。", + "bootTraceNotAvailable": "此平台不支援開機追蹤分析。", "bootTraceTitle": "啟動影響分析", "bootTraceLastBoot": "上次開機:{{date}}", "bootTraceBasedOnLastBoot": "根據上次開機追蹤", @@ -47,7 +47,7 @@ "errorFailedToToggle": "無法{{action}} {{name}}。這可能需要系統管理員權限。", "errorFailedToRemove": "無法移除 {{name}}。這可能需要系統管理員權限。", "confirmRemoveTitle": "要移除 {{name}} 嗎?", - "confirmRemoveDescription": "這將永久移除此啟動項目。該程式將不再隨 Windows 啟動。", + "confirmRemoveDescription": "這將永久移除此啟動項目。此程式將不再隨 Windows 啟動。", "confirmRemoveLabel": "移除", "historyCategoryEnabled": "已啟用", "historyCategoryDisabled": "已停用", @@ -60,8 +60,10 @@ "safetyTooltipWarning": "可疑 — 按一下以查看詳細資料", "safetyTooltipDanger": "可能不安全 — 按一下以查看詳細資料", "safetyTooltipPending": "安全性分析進行中", - "safetyTooltipLocked": "連結至 Kudu Cloud 以查看安全評等", + "safetyTooltipLocked": "連結至 Kudu Cloud 以取得安全評等", "safetyScore": "安全性:{{score}}/10", "safetyAnalyzed": "分析時間:{{date}}", - "sortBySafety": "依安全性排序" + "sortBySafety": "依安全性排序", + "staleBadge": "未安裝", + "staleTooltip": "此項目所指向的程式已不存在,因此無法再啟動。移除此項目是安全的。" } From 6c923faf9222b605cb6cd864815a7f26a0a5c5d0 Mon Sep 17 00:00:00 2001 From: Dave Date: Mon, 27 Jul 2026 04:20:28 +0200 Subject: [PATCH 3/4] fix(startup): clear the StartupApproved marker when pruning an entry Dropping our disabled-startups.json record left Windows' own "03" marker behind. Reinstalling the program would then bring back a Run value that Windows keeps suppressed, while toggling it on in Kudu failed because the stored command was gone. Pruning now removes the marker as well, and keeps the record when that cleanup fails (HKLM without elevation) so the item can still be re-enabled. Also drops the unused Lock import flagged on the Startup page. --- src/main/ipc/startup-manager.ipc.test.ts | 46 +++++++++++++++++++ src/main/ipc/startup-manager.ipc.ts | 58 ++++++++++++++++++++---- src/renderer/src/pages/StartupPage.tsx | 2 +- 3 files changed, 95 insertions(+), 11 deletions(-) diff --git a/src/main/ipc/startup-manager.ipc.test.ts b/src/main/ipc/startup-manager.ipc.test.ts index 66f04c51..988d0c11 100644 --- a/src/main/ipc/startup-manager.ipc.test.ts +++ b/src/main/ipc/startup-manager.ipc.test.ts @@ -649,6 +649,52 @@ describe('stale startup entries', () => { expect(lastWrittenDisabledFile()).toEqual([]) }) + it('clears the StartupApproved marker for the entry it drops', async () => { + onlyExisting(DISABLED_FILE) + mockReadFileSync.mockReturnValue(JSON.stringify([ + { name: 'DuckDuckGo', command: GHOST_CMD, location: HKCU_RUN, source: 'registry-hkcu' }, + ])) + const regCalls: Array<{ cmd: string; args: string[] }> = [] + mockExecFile.mockImplementation((cmd: string, args: string[], _opts: any, cb: Function) => { + regCalls.push({ cmd, args }) + // Only the StartupApproved lookup returns anything + if (args[0] === 'query' && args[1].includes('StartupApproved')) { + cb(null, ' DuckDuckGo REG_BINARY 030000000000000000000000\n', '') + return + } + if (args[0] === 'delete') return cb(null, '', '') + cb(new Error('not found'), '', '') + }) + + const items = await listStartupItems() + expect(items.find((i) => i.name === 'DuckDuckGo')).toBeUndefined() + const markerDelete = regCalls.find( + (c) => c.args[0] === 'delete' && c.args[1].includes('StartupApproved') && c.args.includes('DuckDuckGo') + ) + expect(markerDelete).toBeDefined() + expect(lastWrittenDisabledFile()).toEqual([]) + }) + + it('keeps the entry when the StartupApproved marker cannot be cleared', async () => { + // Without the stored command a reinstalled program could never be + // re-enabled, so the record has to survive a failed marker cleanup. + onlyExisting(DISABLED_FILE) + mockReadFileSync.mockReturnValue(JSON.stringify([ + { name: 'Nahimic', command: '"C:\\Program Files\\Nahimic\\Nahimic.exe"', location: HKLM_RUN, source: 'registry-hklm' }, + ])) + mockExecFile.mockImplementation((_cmd: string, args: string[], _opts: any, cb: Function) => { + if (args[0] === 'query' && args[1].includes('StartupApproved')) { + cb(null, ' Nahimic REG_BINARY 030000000000000000000000\n', '') + return + } + cb(new Error('Access is denied'), '', '') + }) + + const items = await listStartupItems() + expect(items.find((i) => i.name === 'Nahimic')).toBeDefined() + expect(mockWriteFileSync).not.toHaveBeenCalled() + }) + it('keeps a disabled entry while its program is still installed', async () => { onlyExisting(DISABLED_FILE, 'C:\\Users\\User\\AppData\\Local\\DuckDuckGo\\DuckDuckGo.exe') mockReadFileSync.mockReturnValue(JSON.stringify([ diff --git a/src/main/ipc/startup-manager.ipc.ts b/src/main/ipc/startup-manager.ipc.ts index 24f2103e..6bef0ac7 100644 --- a/src/main/ipc/startup-manager.ipc.ts +++ b/src/main/ipc/startup-manager.ipc.ts @@ -356,6 +356,40 @@ const ALLOWED_STARTUP_LOCATIONS = new Set([ 'HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Run', ]) +/** The StartupApproved key Windows consults for a given item source. */ +function approvedKeyFor(source: StartupItem['source']): string { + return source === 'registry-hkcu' + ? 'HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\Run' + : 'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\Run' +} + +/** + * Drop the "disabled by user" marker written to StartupApproved when the item + * was disabled, so nothing is left behind once we forget an entry. + * + * Returns false only when a marker is still present afterwards: the caller + * must then keep its record, otherwise reinstalling the program would leave + * it silently blocked by the stale marker with no stored command to re-enable + * it from. + */ +async function clearStartupApprovedMarker(name: string, source: StartupItem['source']): Promise { + if (source !== 'registry-hkcu' && source !== 'registry-hklm') return true + const approvedKey = approvedKeyFor(source) + + try { + await execNativeUtf8('reg', ['query', approvedKey, '/v', name], { timeout: 5000 }) + } catch { + return true // nothing recorded there — safe to forget + } + + try { + await execNativeUtf8('reg', ['delete', approvedKey, '/v', name, '/f'], { timeout: 5000 }) + return true + } catch { + return false // e.g. HKLM without elevation + } +} + // ── Exported core logic ── export async function listStartupItems(): Promise { @@ -423,12 +457,20 @@ export async function listStartupItems(): Promise { // forever — surviving registry cleaning and even a Kudu reinstall, since // the file lives in userData. Prune entries whose program is verifiably // gone before rebuilding the list from them. - const disabled = await withDisabledFileLock(() => { + const disabled = await withDisabledFileLock(async () => { const entries = readDisabledEntries() - const kept = entries.filter((entry) => { + const kept: DisabledEntry[] = [] + for (const entry of entries) { const backed = items.some((i) => i.name === entry.name && i.source === entry.source) - return backed || !isTargetMissing(entry.command) - }) + if (backed || !isTargetMissing(entry.command)) { + kept.push(entry) + continue + } + // Forget the entry only once Windows' own disable marker is gone too + if (!(await clearStartupApprovedMarker(entry.name, entry.source))) { + kept.push(entry) + } + } if (kept.length !== entries.length) writeDisabledEntries(kept) return kept }) @@ -483,9 +525,7 @@ export async function toggleStartupItem( // Determine the matching StartupApproved key so Windows itself // honours the enable/disable state (same mechanism Task Manager uses). - const approvedKey = source === 'registry-hkcu' - ? 'HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\Run' - : 'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\Run' + const approvedKey = approvedKeyFor(source) if (!enabled) { // Write a "disabled by user" marker (first byte 03) to StartupApproved. @@ -612,9 +652,7 @@ export async function deleteStartupItem( deletedSource = true } // Also clean up StartupApproved entry if it exists - const approvedKey = source === 'registry-hkcu' - ? 'HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\Run' - : 'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\Run' + const approvedKey = approvedKeyFor(source) try { await execNativeUtf8('reg',['delete', approvedKey, '/v', name, '/f'], { timeout: 5000 }) } catch { /* may not exist */ } diff --git a/src/renderer/src/pages/StartupPage.tsx b/src/renderer/src/pages/StartupPage.tsx index da92f3c6..3d69caaf 100644 --- a/src/renderer/src/pages/StartupPage.tsx +++ b/src/renderer/src/pages/StartupPage.tsx @@ -1,6 +1,6 @@ import { useState, useEffect, useCallback, Fragment } from 'react' import { useTranslation } from 'react-i18next' -import { Zap, Shield, ShieldCheck, ShieldAlert, ShieldOff, RefreshCw, Clock, Activity, TrendingDown, ChevronDown, ChevronUp, BarChart3, Trash2, Lock, PackageX } from 'lucide-react' +import { Zap, Shield, ShieldCheck, ShieldAlert, ShieldOff, RefreshCw, Clock, Activity, TrendingDown, ChevronDown, ChevronUp, BarChart3, Trash2, PackageX } from 'lucide-react' import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Cell, PieChart, Pie } from 'recharts' import { toast } from 'sonner' import { PageHeader } from '@/components/layout/PageHeader' From 7b41259b28582cbb6153c3a9dafca38ebcbd3b78 Mon Sep 17 00:00:00 2001 From: Dave Date: Mon, 27 Jul 2026 04:37:23 +0200 Subject: [PATCH 4/4] fix(startup): require confirmed absence before forgetting an entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pruning acted on a single observation, which is not enough evidence to throw away the only copy of a disabled item's command: an updater that briefly removes its executable would lose the entry for good. A missing program is now stamped and flagged as stale on first sight — the user gets the "Not installed" badge and can clear it in one click — and the record is only dropped once the program has stayed missing for 24 hours. It comes back to normal by itself if the program reappears. Marker cleanup no longer treats a failed StartupApproved lookup as proof that no marker exists. mergeStartupApproved already reads those keys, so it now reports which values it saw and whether the read succeeded; an unreadable key keeps the record and retries on the next scan. Entries retained because cleanup could not finish are flagged stale too, instead of being indistinguishable from working disabled programs. --- src/main/ipc/startup-manager.ipc.test.ts | 107 ++++++++++++++++++----- src/main/ipc/startup-manager.ipc.ts | 95 +++++++++++++++----- 2 files changed, 158 insertions(+), 44 deletions(-) diff --git a/src/main/ipc/startup-manager.ipc.test.ts b/src/main/ipc/startup-manager.ipc.test.ts index 988d0c11..966534ee 100644 --- a/src/main/ipc/startup-manager.ipc.test.ts +++ b/src/main/ipc/startup-manager.ipc.test.ts @@ -636,12 +636,48 @@ describe('stale startup entries', () => { return JSON.parse(calls[calls.length - 1][1] as string) } + const DAY_MS = 24 * 60 * 60 * 1000 + const longGone = () => Date.now() - DAY_MS - 60_000 + + /** reg mock where the StartupApproved key holds a disabled marker for `name` */ + function withApprovedMarker(name: string, opts: { deleteFails?: boolean } = {}) { + const regCalls: Array<{ cmd: string; args: string[] }> = [] + mockExecFile.mockImplementation((cmd: string, args: string[], _opts: any, cb: Function) => { + regCalls.push({ cmd, args }) + if (args[0] === 'query' && args[1].includes('StartupApproved')) { + return cb(null, ` ${name} REG_BINARY 030000000000000000000000\n`, '') + } + if (args[0] === 'delete') { + return opts.deleteFails ? cb(new Error('Access is denied'), '', '') : cb(null, '', '') + } + cb(new Error('not found'), '', '') + }) + return regCalls + } + describe('disabled-file pruning', () => { - it('drops a disabled entry whose program has been uninstalled', async () => { + it('flags — but keeps — an entry the first time its program is missing', async () => { + // A single missing-file observation could just be an updater mid-replace onlyExisting(DISABLED_FILE) mockReadFileSync.mockReturnValue(JSON.stringify([ { name: 'DuckDuckGo', command: GHOST_CMD, location: HKCU_RUN, source: 'registry-hkcu' }, ])) + withApprovedMarker('DuckDuckGo') + + const items = await listStartupItems() + const ghost = items.find((i) => i.name === 'DuckDuckGo') + expect(ghost).toBeDefined() + expect(ghost!.stale).toBe(true) + // The record is stamped so the grace period can start running + expect(lastWrittenDisabledFile()[0].missingSince).toBeTypeOf('number') + }) + + it('drops an entry whose program has stayed uninstalled', async () => { + onlyExisting(DISABLED_FILE) + mockReadFileSync.mockReturnValue(JSON.stringify([ + { name: 'DuckDuckGo', command: GHOST_CMD, location: HKCU_RUN, source: 'registry-hkcu', missingSince: longGone() }, + ])) + withApprovedMarker('DuckDuckGo') const items = await listStartupItems() expect(items.find((i) => i.name === 'DuckDuckGo')).toBeUndefined() @@ -652,19 +688,9 @@ describe('stale startup entries', () => { it('clears the StartupApproved marker for the entry it drops', async () => { onlyExisting(DISABLED_FILE) mockReadFileSync.mockReturnValue(JSON.stringify([ - { name: 'DuckDuckGo', command: GHOST_CMD, location: HKCU_RUN, source: 'registry-hkcu' }, + { name: 'DuckDuckGo', command: GHOST_CMD, location: HKCU_RUN, source: 'registry-hkcu', missingSince: longGone() }, ])) - const regCalls: Array<{ cmd: string; args: string[] }> = [] - mockExecFile.mockImplementation((cmd: string, args: string[], _opts: any, cb: Function) => { - regCalls.push({ cmd, args }) - // Only the StartupApproved lookup returns anything - if (args[0] === 'query' && args[1].includes('StartupApproved')) { - cb(null, ' DuckDuckGo REG_BINARY 030000000000000000000000\n', '') - return - } - if (args[0] === 'delete') return cb(null, '', '') - cb(new Error('not found'), '', '') - }) + const regCalls = withApprovedMarker('DuckDuckGo') const items = await listStartupItems() expect(items.find((i) => i.name === 'DuckDuckGo')).toBeUndefined() @@ -675,26 +701,63 @@ describe('stale startup entries', () => { expect(lastWrittenDisabledFile()).toEqual([]) }) + it('restarts the clock when the program comes back', async () => { + onlyExisting(DISABLED_FILE, 'C:\\Users\\User\\AppData\\Local\\DuckDuckGo\\DuckDuckGo.exe') + mockReadFileSync.mockReturnValue(JSON.stringify([ + { name: 'DuckDuckGo', command: GHOST_CMD, location: HKCU_RUN, source: 'registry-hkcu', missingSince: longGone() }, + ])) + + const items = await listStartupItems() + const ghost = items.find((i) => i.name === 'DuckDuckGo') + expect(ghost).toBeDefined() + expect(ghost!.stale).toBe(false) + expect(lastWrittenDisabledFile()[0].missingSince).toBeUndefined() + }) + it('keeps the entry when the StartupApproved marker cannot be cleared', async () => { // Without the stored command a reinstalled program could never be // re-enabled, so the record has to survive a failed marker cleanup. onlyExisting(DISABLED_FILE) mockReadFileSync.mockReturnValue(JSON.stringify([ - { name: 'Nahimic', command: '"C:\\Program Files\\Nahimic\\Nahimic.exe"', location: HKLM_RUN, source: 'registry-hklm' }, + { name: 'Nahimic', command: '"C:\\Program Files\\Nahimic\\Nahimic.exe"', location: HKLM_RUN, source: 'registry-hklm', missingSince: longGone() }, ])) - mockExecFile.mockImplementation((_cmd: string, args: string[], _opts: any, cb: Function) => { - if (args[0] === 'query' && args[1].includes('StartupApproved')) { - cb(null, ' Nahimic REG_BINARY 030000000000000000000000\n', '') - return - } - cb(new Error('Access is denied'), '', '') - }) + withApprovedMarker('Nahimic', { deleteFails: true }) + + const items = await listStartupItems() + const retained = items.find((i) => i.name === 'Nahimic') + expect(retained).toBeDefined() + // Retained because we could not clean up — still flagged so the user can + expect(retained!.stale).toBe(true) + expect(mockWriteFileSync).not.toHaveBeenCalled() + }) + + it('keeps the entry when the StartupApproved key cannot be read', async () => { + // A failed lookup is not evidence that no marker exists + onlyExisting(DISABLED_FILE) + mockReadFileSync.mockReturnValue(JSON.stringify([ + { name: 'DuckDuckGo', command: GHOST_CMD, location: HKCU_RUN, source: 'registry-hkcu', missingSince: longGone() }, + ])) + // Default execFile mock fails every call, including the approved query const items = await listStartupItems() - expect(items.find((i) => i.name === 'Nahimic')).toBeDefined() + expect(items.find((i) => i.name === 'DuckDuckGo')).toBeDefined() expect(mockWriteFileSync).not.toHaveBeenCalled() }) + it('drops the entry when the key is readable and holds no marker', async () => { + onlyExisting(DISABLED_FILE) + mockReadFileSync.mockReturnValue(JSON.stringify([ + { name: 'DuckDuckGo', command: GHOST_CMD, location: HKCU_RUN, source: 'registry-hkcu', missingSince: longGone() }, + ])) + const regCalls = withApprovedMarker('SomethingElse') + + const items = await listStartupItems() + expect(items.find((i) => i.name === 'DuckDuckGo')).toBeUndefined() + // Nothing to delete — no marker was there + expect(regCalls.some((c) => c.args[0] === 'delete')).toBe(false) + expect(lastWrittenDisabledFile()).toEqual([]) + }) + it('keeps a disabled entry while its program is still installed', async () => { onlyExisting(DISABLED_FILE, 'C:\\Users\\User\\AppData\\Local\\DuckDuckGo\\DuckDuckGo.exe') mockReadFileSync.mockReturnValue(JSON.stringify([ diff --git a/src/main/ipc/startup-manager.ipc.ts b/src/main/ipc/startup-manager.ipc.ts index 6bef0ac7..3aa910d3 100644 --- a/src/main/ipc/startup-manager.ipc.ts +++ b/src/main/ipc/startup-manager.ipc.ts @@ -20,8 +20,18 @@ interface DisabledEntry { command: string location: string source: StartupItem['source'] + /** Epoch ms when the program was first seen to be gone from disk. */ + missingSince?: number } +/** + * How long a disabled program must stay missing before we forget it. A single + * scan is not enough evidence: an updater that replaces its executable makes + * the program briefly disappear, and these records are the only copy of the + * command we have. + */ +const MISSING_GRACE_MS = 24 * 60 * 60 * 1000 + function getDisabledFilePath(): string { const dir = app.isPackaged ? app.getPath('userData') @@ -252,23 +262,32 @@ function getStartupFolderItems(): StartupItem[] { * disabled via Task Manager. These items have a REG_BINARY value where the * first byte indicates status: 02 = enabled, 03 = disabled by user, * 06 = disabled by OS/policy. + * + * Returns which value names each key holds, so callers can tell "no marker" + * apart from "could not read the key". */ -async function mergeStartupApproved(items: StartupItem[]): Promise { +async function mergeStartupApproved(items: StartupItem[]): Promise { const approvedKeys = [ { key: 'HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\Run', source: 'registry-hkcu' as const }, { key: 'HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\StartupFolder', source: 'startup-folder' as const }, { key: 'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\Run', source: 'registry-hklm' as const }, ] + const markers: ApprovedMarkers = new Map() + for (const { key, source } of approvedKeys) { + const state: ApprovedKeyState = { read: false, names: new Set() } + markers.set(source, state) try { const { stdout } = await execNativeUtf8('reg',['query', key], { timeout: 10000 }) + state.read = true const lines = stdout.split('\n') for (const line of lines) { const match = line.match(/^\s+(.+?)\s{4,}REG_BINARY\s{4,}(\S+)/i) if (!match) continue const name = match[1].trim() const hexData = match[2].trim() + state.names.add(name) // First byte: 02=enabled, 03=disabled by user, 06=disabled by policy const firstByte = parseInt(hexData.substring(0, 2), 16) const isDisabledByUser = firstByte === 0x03 || firstByte === 0x06 @@ -285,6 +304,8 @@ async function mergeStartupApproved(items: StartupItem[]): Promise { } } catch { /* key may not exist */ } } + + return markers } /** @@ -356,6 +377,15 @@ const ALLOWED_STARTUP_LOCATIONS = new Set([ 'HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Run', ]) +/** Value names found under one StartupApproved key. */ +interface ApprovedKeyState { + /** false when the key could not be read — presence is then unknown */ + read: boolean + names: Set +} + +type ApprovedMarkers = Map + /** The StartupApproved key Windows consults for a given item source. */ function approvedKeyFor(source: StartupItem['source']): string { return source === 'registry-hkcu' @@ -367,23 +397,24 @@ function approvedKeyFor(source: StartupItem['source']): string { * Drop the "disabled by user" marker written to StartupApproved when the item * was disabled, so nothing is left behind once we forget an entry. * - * Returns false only when a marker is still present afterwards: the caller - * must then keep its record, otherwise reinstalling the program would leave - * it silently blocked by the stale marker with no stored command to re-enable - * it from. + * Returns false unless the marker is known to be gone: the caller must then + * keep its record, otherwise reinstalling the program would leave it silently + * blocked by the stale marker with no stored command to re-enable it from. + * A key we failed to read is not evidence of absence — the next scan retries. */ -async function clearStartupApprovedMarker(name: string, source: StartupItem['source']): Promise { +async function clearStartupApprovedMarker( + name: string, + source: StartupItem['source'], + markers: ApprovedMarkers +): Promise { if (source !== 'registry-hkcu' && source !== 'registry-hklm') return true - const approvedKey = approvedKeyFor(source) - try { - await execNativeUtf8('reg', ['query', approvedKey, '/v', name], { timeout: 5000 }) - } catch { - return true // nothing recorded there — safe to forget - } + const state = markers.get(source) + if (!state?.read) return false + if (!state.names.has(name)) return true try { - await execNativeUtf8('reg', ['delete', approvedKey, '/v', name, '/f'], { timeout: 5000 }) + await execNativeUtf8('reg', ['delete', approvedKeyFor(source), '/v', name, '/f'], { timeout: 5000 }) return true } catch { return false // e.g. HKLM without elevation @@ -439,7 +470,7 @@ export async function listStartupItems(): Promise { // Check StartupApproved\Run — items disabled via Task Manager are removed // from Run but kept here with a 03 byte prefix. Merge their enabled state // and add any missing items that exist only in the approved list. - await mergeStartupApproved(items) + const approvedMarkers = await mergeStartupApproved(items) // Read Task Scheduler logon-trigger tasks (user-facing apps like Spotify) const scheduledItems = await getScheduledLogonTasks() @@ -455,23 +486,43 @@ export async function listStartupItems(): Promise { // record we have of it. If the program is uninstalled afterwards, nothing // on the system references it any more and the entry would haunt the list // forever — surviving registry cleaning and even a Kudu reinstall, since - // the file lives in userData. Prune entries whose program is verifiably - // gone before rebuilding the list from them. + // the file lives in userData. + // + // Such an entry is flagged as stale straight away so the user can clear it + // in one click, and is forgotten automatically once its program has stayed + // missing for MISSING_GRACE_MS and Windows' own disable marker is gone too. + const now = Date.now() const disabled = await withDisabledFileLock(async () => { const entries = readDisabledEntries() const kept: DisabledEntry[] = [] + let changed = false + for (const entry of entries) { const backed = items.some((i) => i.name === entry.name && i.source === entry.source) if (backed || !isTargetMissing(entry.command)) { - kept.push(entry) + // Present again — restart the clock + if (entry.missingSince !== undefined) changed = true + kept.push({ + name: entry.name, + command: entry.command, + location: entry.location, + source: entry.source + }) continue } - // Forget the entry only once Windows' own disable marker is gone too - if (!(await clearStartupApprovedMarker(entry.name, entry.source))) { - kept.push(entry) + + const missingSince = entry.missingSince ?? now + if (missingSince !== entry.missingSince) changed = true + + const expired = now - missingSince >= MISSING_GRACE_MS + if (expired && await clearStartupApprovedMarker(entry.name, entry.source, approvedMarkers)) { + changed = true + continue } + kept.push({ ...entry, missingSince }) } - if (kept.length !== entries.length) writeDisabledEntries(kept) + + if (changed) writeDisabledEntries(kept) return kept }) @@ -490,7 +541,7 @@ export async function listStartupItems(): Promise { enabled: false, publisher: extractPublisher(entry.command), impact: estimateImpact(entry.name, entry.command), - stale: false + stale: entry.missingSince !== undefined }) } }