diff --git a/AGENTS.md b/AGENTS.md index c89653ba95..d6bd72d4b0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -19,6 +19,8 @@ Valid types are `feat`, `fix`, `docs`, `chore`, `refactor`, and `test`. Scopes a Examples: `fix(tui): simplify thinking toggle styling`, `docs: update contributing guide`, `chore(sdk): regenerate types`. +Never bypass Git hooks. Do not use `--no-verify` or otherwise disable, skip, or circumvent commit or push hooks. If a hook fails, fix the failure or stop and report it to the user. + ## Style Guide ### General Principles diff --git a/bun.lock b/bun.lock index 491dbd1679..707302aa91 100644 --- a/bun.lock +++ b/bun.lock @@ -30,7 +30,7 @@ }, "packages/app": { "name": "@opencode-ai/app", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@dnd-kit/abstract": "0.5.0", "@dnd-kit/dom": "0.5.0", @@ -94,7 +94,7 @@ }, "packages/cli": { "name": "@opencode-ai/cli", - "version": "1.17.14", + "version": "1.17.15", "bin": { "opencode2": "./bin/opencode2.cjs", }, @@ -114,10 +114,12 @@ "effect": "catalog:", "fuzzysort": "catalog:", "jsonc-parser": "3.3.1", + "open": "10.1.2", "opentui-spinner": "catalog:", "semver": "catalog:", "solid-js": "catalog:", "strip-ansi": "7.1.2", + "uqr": "0.1.3", }, "devDependencies": { "@opencode-ai/script": "workspace:*", @@ -151,7 +153,7 @@ }, "packages/codemode": { "name": "@opencode-ai/codemode", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "acorn": "8.15.0", "effect": "catalog:", @@ -165,7 +167,7 @@ }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@ibm/plex": "6.4.1", @@ -201,7 +203,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -228,7 +230,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@ai-sdk/anthropic": "3.0.82", "@ai-sdk/openai": "3.0.48", @@ -250,7 +252,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -274,7 +276,7 @@ }, "packages/console/support": { "name": "@opencode-ai/console-support", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@opencode-ai/console-core": "workspace:*", @@ -294,7 +296,7 @@ }, "packages/core": { "name": "@opencode-ai/core", - "version": "1.17.14", + "version": "1.17.15", "bin": { "opencode": "./bin/opencode", }, @@ -390,7 +392,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@zip.js/zip.js": "2.7.62", "effect": "catalog:", @@ -450,7 +452,7 @@ }, "packages/effect-drizzle-sqlite": { "name": "@opencode-ai/effect-drizzle-sqlite", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "drizzle-orm": "catalog:", "effect": "catalog:", @@ -464,7 +466,7 @@ }, "packages/effect-sqlite-node": { "name": "@opencode-ai/effect-sqlite-node", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "effect": "catalog:", }, @@ -476,7 +478,7 @@ }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@hono/standard-validator": "catalog:", "@opencode-ai/core": "workspace:*", @@ -508,7 +510,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "catalog:", @@ -524,12 +526,12 @@ }, "packages/http-recorder": { "name": "@opencode-ai/http-recorder", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { - "@effect/platform-node": "4.0.0-beta.83", "@effect/platform-node-shared": "4.0.0-beta.83", }, "devDependencies": { + "@effect/platform-node": "catalog:", "@tsconfig/node22": "catalog:", "@types/bun": "catalog:", "@types/node": "catalog:", @@ -538,7 +540,7 @@ "typescript": "catalog:", }, "peerDependencies": { - "effect": "4.0.0-beta.83", + "effect": "catalog:", }, }, "packages/httpapi-codegen": { @@ -556,7 +558,7 @@ }, "packages/llm": { "name": "@opencode-ai/llm", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@opencode-ai/schema": "workspace:*", "@smithy/eventstream-codec": "4.2.14", @@ -575,7 +577,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.17.14", + "version": "1.17.15", "bin": { "opencode": "./bin/opencode", }, @@ -708,7 +710,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@ai-sdk/provider": "3.0.8", "@opencode-ai/client": "workspace:*", @@ -795,7 +797,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "cross-spawn": "catalog:", }, @@ -810,7 +812,7 @@ }, "packages/server": { "name": "@opencode-ai/server", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@effect/platform-node": "catalog:", "@opencode-ai/core": "workspace:*", @@ -827,7 +829,7 @@ }, "packages/session-ui": { "name": "@opencode-ai/session-ui", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/core": "workspace:*", @@ -873,6 +875,7 @@ "name": "@opencode-ai/simulation", "version": "1.17.13", "dependencies": { + "@fontsource/adwaita-mono": "5.2.1", "@napi-rs/canvas": "1.0.2", "@opencode-ai/core": "workspace:*", "@opencode-ai/llm": "workspace:*", @@ -887,7 +890,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -900,7 +903,7 @@ }, "packages/stats/app": { "name": "@opencode-ai/stats-app", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@ibm/plex": "6.4.1", "@opencode-ai/stats-core": "workspace:*", @@ -933,7 +936,7 @@ }, "packages/stats/core": { "name": "@opencode-ai/stats-core", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@aws-sdk/client-athena": "3.933.0", "@planetscale/database": "1.19.0", @@ -952,7 +955,7 @@ }, "packages/stats/server": { "name": "@opencode-ai/stats-server", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@aws-sdk/client-firehose": "3.933.0", "@effect/platform-node": "catalog:", @@ -993,7 +996,7 @@ }, "packages/tui": { "name": "@opencode-ai/tui", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@opencode-ai/client": "workspace:*", "@opencode-ai/core": "workspace:*", @@ -1014,6 +1017,7 @@ "remeda": "catalog:", "solid-js": "catalog:", "strip-ansi": "7.1.2", + "uqr": "0.1.3", }, "devDependencies": { "@tsconfig/bun": "catalog:", @@ -1023,7 +1027,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@kobalte/core": "catalog:", "@pierre/diffs": "catalog:", @@ -1074,7 +1078,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.17.14", + "version": "1.17.15", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", @@ -1724,6 +1728,8 @@ "@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="], + "@fontsource/adwaita-mono": ["@fontsource/adwaita-mono@5.2.1", "", {}, "sha512-6+Q1UIvklJ9REijs6kv7YlRNt6yktRj0iW8H69YIugdD9P2h3eIX1AB8/9ICMfpVyVeywlsrCXg82y/LfRrjyg=="], + "@fontsource/ibm-plex-mono": ["@fontsource/ibm-plex-mono@5.2.5", "", {}, "sha512-G09N3GfuT9qj3Ax2FDZvKqZttzM3v+cco2l8uXamhKyXLdmlaUDH5o88/C3vtTHj2oT7yRKsvxz9F+BXbWKMYA=="], "@fontsource/inter": ["@fontsource/inter@5.2.8", "", {}, "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg=="], @@ -5946,6 +5952,8 @@ "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], + "uqr": ["uqr@0.1.3", "", {}, "sha512-0rjE8iEJe4YmT9TOhwsZtqCMRLc5DXZUI2UEYUUg63ikBkqqE5EYWaI0etFe/5KUcmcYwLih2RND1kq+hrUJXA=="], + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], "urijs": ["urijs@1.19.11", "", {}, "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ=="], diff --git a/github/index.ts b/github/index.ts index 4e1af9cf55..e8acd9a9ce 100644 --- a/github/index.ts +++ b/github/index.ts @@ -495,7 +495,6 @@ async function subscribeSessionEvents() { console.log("Subscribing to session events...") const TOOL: Record = { - todowrite: ["Todo", "\x1b[33m\x1b[1m"], bash: ["Bash", "\x1b[31m\x1b[1m"], edit: ["Edit", "\x1b[32m\x1b[1m"], glob: ["Glob", "\x1b[34m\x1b[1m"], diff --git a/package.json b/package.json index e427ceb127..721af00009 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "prepare": "husky", "random": "echo 'Random script'", "sso": "aws sso login --sso-session=opencode --no-browser", + "translate:app": "bun run script/translate-app.ts", "test": "echo 'do not run tests from root' && exit 1" }, "workspaces": { diff --git a/packages/app/e2e/performance/timeline-stability/file-matrix.spec.ts b/packages/app/e2e/performance/timeline-stability/file-matrix.spec.ts index e0f0d72233..0690f02706 100644 --- a/packages/app/e2e/performance/timeline-stability/file-matrix.spec.ts +++ b/packages/app/e2e/performance/timeline-stability/file-matrix.spec.ts @@ -20,7 +20,7 @@ const profiles = [ { name: "edit", tool: "edit", input: { filePath: "src/edit.ts" } }, { name: "multi patch", - tool: "apply_patch", + tool: "patch", input: { files: ["src/a.ts", "src/b.ts", "src/old.ts", "src/moved.ts"] }, }, ] as const diff --git a/packages/app/e2e/performance/timeline-stability/file-mutation.spec.ts b/packages/app/e2e/performance/timeline-stability/file-mutation.spec.ts index 798bf0df3b..f411339adb 100644 --- a/packages/app/e2e/performance/timeline-stability/file-mutation.spec.ts +++ b/packages/app/e2e/performance/timeline-stability/file-mutation.spec.ts @@ -25,7 +25,7 @@ test("adds patch files incrementally without resetting outer expansion", async ( userMessage(), assistantMessage( [ - toolPart(patchID, "apply_patch", "running", { files: [first.filePath] }, { metadata: { files: [first] } }), + toolPart(patchID, "patch", "running", { files: [first.filePath] }, { metadata: { files: [first] } }), textPart(followingID, "Following incremental patch"), ], { completed: false }, @@ -49,7 +49,7 @@ test("adds patch files incrementally without resetting outer expansion", async ( partUpdated( toolPart( patchID, - "apply_patch", + "patch", "running", { files: [first.filePath, second.filePath] }, { metadata: { files: [first, second] } }, @@ -61,7 +61,7 @@ test("adds patch files incrementally without resetting outer expansion", async ( partUpdated( toolPart( patchID, - "apply_patch", + "patch", "completed", { files: [first.filePath, second.filePath, third.filePath] }, { metadata: { files: [first, second, third] } }, diff --git a/packages/app/e2e/performance/timeline-stability/tools.spec.ts b/packages/app/e2e/performance/timeline-stability/tools.spec.ts index d28fdaa65f..d26968e1cb 100644 --- a/packages/app/e2e/performance/timeline-stability/tools.spec.ts +++ b/packages/app/e2e/performance/timeline-stability/tools.spec.ts @@ -33,11 +33,9 @@ test.describe("timeline tool state stability", () => { } const names = { webfetch: "webfetch", websearch: "websearch", task: "task", skill: "skill", custom: "mcp_probe" } const questionID = "prt_state_question" - const todoID = "prt_state_todo" const initial = [ ...ids.map((id) => toolPart(`prt_state_${id}`, names[id], "pending", inputs[id])), toolPart(questionID, "question", "pending", questionInput()), - toolPart(todoID, "todowrite", "pending", { todos: [{ content: "Hidden", status: "pending" }] }), textPart("prt_state_following", "Following lightweight tools"), ] const childID = "ses_timeline_child" @@ -49,7 +47,6 @@ test.describe("timeline tool state stability", () => { await timeline.send(status("busy"), 120) for (const id of ids) await timeline.waitForPart(`prt_state_${id}`) await expect(page.locator(`[data-timeline-part-id="${questionID}"]`)).toHaveCount(0) - await expect(page.locator(`[data-timeline-part-id="${todoID}"]`)).toHaveCount(0) const regionIDs = [ "prt_state_webfetch", @@ -105,7 +102,6 @@ test.describe("timeline tool state stability", () => { ]), ) await expect(page.locator(`[data-timeline-part-id="${questionID}"]`)).toContainText("Keep it stable") - await expect(page.locator(`[data-timeline-part-id="${todoID}"]`)).toHaveCount(0) await expect( page.locator(`a[href$="/session/${childID}"]`, { has: page.locator('[data-component="task-tool-card"]') }), ).toBeVisible() diff --git a/packages/app/e2e/performance/timeline/session-timeline-benchmark.fixture.ts b/packages/app/e2e/performance/timeline/session-timeline-benchmark.fixture.ts index a86a55cff2..a22d5cc331 100644 --- a/packages/app/e2e/performance/timeline/session-timeline-benchmark.fixture.ts +++ b/packages/app/e2e/performance/timeline/session-timeline-benchmark.fixture.ts @@ -295,7 +295,7 @@ function performanceTurn(index: number) { messageID: assistantID, type: "tool", callID: `call_0000_${suffix}_patch`, - tool: "apply_patch", + tool: "patch", state: { status: "completed", input: { patchText: realisticPatch(index) }, diff --git a/packages/app/e2e/performance/timeline/session-timeline-stress.fixture.ts b/packages/app/e2e/performance/timeline/session-timeline-stress.fixture.ts index 529081a1d9..2e20d98415 100644 --- a/packages/app/e2e/performance/timeline/session-timeline-stress.fixture.ts +++ b/packages/app/e2e/performance/timeline/session-timeline-stress.fixture.ts @@ -131,7 +131,7 @@ function toolPart( ): MessagePart { const metadata = metadataOverride ?? - (tool === "apply_patch" + (tool === "patch" ? { files: [patchFile(index, "update"), patchFile(index + 1, index % 2 === 0 ? "add" : "delete")] } : tool === "edit" || tool === "write" ? { @@ -219,7 +219,7 @@ function turn(index: number): Message[] { ? [toolPart(index, 7, "write", { filePath: `src/generated/write-${index}.ts`, content: code(index, 28) }, 560)] : []), ...(index % 8 === 0 - ? [toolPart(index, 8, "apply_patch", { files: [`src/generated/patch-${index}.ts`] }, 620)] + ? [toolPart(index, 8, "patch", { files: [`src/generated/patch-${index}.ts`] }, 620)] : []), ...(index % 7 === 0 ? [toolPart(index, 4, "bash", { command: "bun typecheck", description: "Verify generated output" }, 620)] @@ -269,7 +269,6 @@ const childMessages = Array.from({ length: 4 }, (_, index) => [ ]).flat() function renderable(part: MessagePart) { - if (part.type === "tool" && part.tool === "todowrite") return false if (part.type === "text") return !!part.text.trim() if (part.type === "reasoning") return !!part.text.trim() return part.type !== "step-start" && part.type !== "step-finish" && part.type !== "patch" diff --git a/packages/app/e2e/regression/cross-server-tab-close.spec.ts b/packages/app/e2e/regression/cross-server-tab-close.spec.ts index 159b5a5067..9fd7991437 100644 --- a/packages/app/e2e/regression/cross-server-tab-close.spec.ts +++ b/packages/app/e2e/regression/cross-server-tab-close.spec.ts @@ -90,7 +90,7 @@ async function mockServers(page: Page, requests: string[]) { if (url.pathname === `/session/${current.id}`) return json(route, current) if (/^\/session\/[^/]+$/.test(url.pathname)) return json(route, { name: "NotFoundError" }, 404) if (url.pathname === `/session/${current.id}/message`) return json(route, []) - if (/^\/session\/[^/]+\/(children|todo|diff)$/.test(url.pathname)) return json(route, []) + if (/^\/session\/[^/]+\/(children|diff)$/.test(url.pathname)) return json(route, []) if (["/skill", "/command", "/lsp", "/formatter", "/permission", "/question", "/vcs/diff"].includes(url.pathname)) return json(route, []) if (["/global/config", "/config", "/provider/auth", "/mcp", "/session/status"].includes(url.pathname)) diff --git a/packages/app/e2e/regression/remote-tab-busy.spec.ts b/packages/app/e2e/regression/remote-tab-busy.spec.ts index 119fc7ee2d..ad7e2e1d99 100644 --- a/packages/app/e2e/regression/remote-tab-busy.spec.ts +++ b/packages/app/e2e/regression/remote-tab-busy.spec.ts @@ -65,7 +65,7 @@ async function mockServers(page: Page) { if (url.pathname === `/session/${current.id}`) return json(route, current) if (/^\/session\/[^/]+$/.test(url.pathname)) return json(route, { name: "NotFoundError" }, 404) if (url.pathname === `/session/${current.id}/message`) return json(route, []) - if (/^\/session\/[^/]+\/(children|todo|diff)$/.test(url.pathname)) return json(route, []) + if (/^\/session\/[^/]+\/(children|diff)$/.test(url.pathname)) return json(route, []) if (["/skill", "/command", "/lsp", "/formatter", "/permission", "/question", "/vcs/diff"].includes(url.pathname)) return json(route, []) if (["/global/config", "/config", "/provider/auth", "/mcp"].includes(url.pathname)) return json(route, {}) diff --git a/packages/app/e2e/regression/session-timeline-file-projection.spec.ts b/packages/app/e2e/regression/session-timeline-file-projection.spec.ts index f07da121c6..a591ff9470 100644 --- a/packages/app/e2e/regression/session-timeline-file-projection.spec.ts +++ b/packages/app/e2e/regression/session-timeline-file-projection.spec.ts @@ -24,7 +24,7 @@ test("renders a completed single-file patch", async ({ page }) => { assistantMessage([ toolPart( id, - "apply_patch", + "patch", "completed", { files: ["src/a.ts"] }, { diff --git a/packages/app/e2e/regression/session-timeline-file-state.spec.ts b/packages/app/e2e/regression/session-timeline-file-state.spec.ts index cb228c13c7..f0871a0da3 100644 --- a/packages/app/e2e/regression/session-timeline-file-state.spec.ts +++ b/packages/app/e2e/regression/session-timeline-file-state.spec.ts @@ -35,7 +35,7 @@ test("preserves nested patch file state through outer collapse and reopen", asyn assistantMessage([ toolPart( patchID, - "apply_patch", + "patch", "completed", { files: files.map((file) => file.filePath) }, { metadata: { files } }, diff --git a/packages/app/e2e/regression/session-timeline-projection.spec.ts b/packages/app/e2e/regression/session-timeline-projection.spec.ts index 9fd2ca8d0b..45304df365 100644 --- a/packages/app/e2e/regression/session-timeline-projection.spec.ts +++ b/packages/app/e2e/regression/session-timeline-projection.spec.ts @@ -35,7 +35,6 @@ test.describe("session timeline projection", () => { editPart("prt_edit"), toolPart("prt_write", "write", "completed", { filePath: "src/new.ts", content: "export const stable = true\n" }), patchPart("prt_patch"), - toolPart("prt_todo", "todowrite", "completed", { todos: [{ content: "Hidden", status: "pending" }] }), toolPart( "prt_question", "question", @@ -65,7 +64,6 @@ test.describe("session timeline projection", () => { ]) { await expect(page.locator(`[data-timeline-part-id="${id}"]`).first(), id).toBeVisible() } - await expect(page.locator('[data-timeline-part-id="prt_todo"]')).toHaveCount(0) }) test("projects gaps, dividers, assistant parts, and errors together", async ({ page }) => { @@ -246,7 +244,7 @@ function editPart(id: string) { function patchPart(id: string) { return toolPart( id, - "apply_patch", + "patch", "completed", { files: ["src/a.ts", "src/b.ts"] }, { diff --git a/packages/app/e2e/regression/session-timeline-tool-projection.spec.ts b/packages/app/e2e/regression/session-timeline-tool-projection.spec.ts index 99f1acf270..4c2c1c4ead 100644 --- a/packages/app/e2e/regression/session-timeline-tool-projection.spec.ts +++ b/packages/app/e2e/regression/session-timeline-tool-projection.spec.ts @@ -8,7 +8,7 @@ import { } from "../performance/timeline-stability/fixture" test("renders every tool error outcome without leaking hidden tools", async ({ page }) => { - const ordinary = ["bash", "edit", "write", "apply_patch", "webfetch", "websearch", "task", "skill", "mcp_probe"] + const ordinary = ["bash", "edit", "write", "patch", "webfetch", "websearch", "task", "skill", "mcp_probe"] const parts = ordinary.map((tool, index) => toolPart(`prt_error_${index}`, tool, "error", errorInput(tool), { error: `${tool} failed visibly` }), ) @@ -17,13 +17,11 @@ test("renders every tool error outcome without leaking hidden tools", async ({ p error: "The user dismissed this question", }), toolPart("prt_question_error", "question", "error", questionInput(), { error: "Question transport failed" }), - toolPart("prt_todo_error", "todowrite", "error", { todos: [] }, { error: "Hidden todo failure" }), ) await setupTimeline(page, { messages: [userMessage(), assistantMessage(parts)] }) await expect(page.locator('[data-kind="tool-error-card"]')).toHaveCount(ordinary.length + 1) await expect(page.getByText(/dismissed/i)).toBeVisible() - await expect(page.locator('[data-timeline-part-id="prt_todo_error"]')).toHaveCount(0) for (let index = 0; index < ordinary.length; index++) { await expect(page.locator(`[data-timeline-part-id="prt_error_${index}"]`)).toBeVisible() } @@ -90,7 +88,7 @@ function questionInput() { function errorInput(tool: string) { if (tool === "bash") return { command: "exit 1" } if (["edit", "write"].includes(tool)) return { filePath: "src/error.ts", content: "" } - if (tool === "apply_patch") return { files: ["src/error.ts"] } + if (tool === "patch") return { files: ["src/error.ts"] } if (tool === "webfetch") return { url: "https://example.com" } if (tool === "websearch") return { query: "failure" } if (tool === "task") return { description: "Fail task", subagent_type: "explore" } diff --git a/packages/app/e2e/regression/session-todo-dock-navigation.spec.ts b/packages/app/e2e/regression/session-todo-dock-navigation.spec.ts deleted file mode 100644 index 603c411d55..0000000000 --- a/packages/app/e2e/regression/session-todo-dock-navigation.spec.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { base64Encode } from "@opencode-ai/core/util/encode" -import { expect, test, type Page } from "@playwright/test" -import { mockOpenCodeServer } from "../utils/mock-server" -import { expectSessionTitle } from "../utils/waits" - -const directory = "C:/OpenCode/TodoDockNavigation" -const projectID = "proj_todo_dock_navigation" -const sourceID = "ses_todo_dock_source" -const otherID = "ses_todo_dock_other" -const sourceTitle = "Todo dock animation" -const otherTitle = "Separate session" - -const activeTodos = [ - { id: "todo-1", content: "Receive todos in the active session", status: "completed", priority: "high" }, - { id: "todo-2", content: "Keep the dock visible across tabs", status: "completed", priority: "high" }, - { id: "todo-3", content: "Close after the final todo", status: "in_progress", priority: "high" }, -] - -type EventPayload = { - directory: string - payload: Record -} - -test.use({ viewport: { width: 1440, height: 900 }, reducedMotion: "no-preference" }) - -test("animates todo lifecycle without replaying it across session tabs", async ({ page }) => { - test.setTimeout(90_000) - const events: EventPayload[] = [] - const todos: Record = { [sourceID]: [], [otherID]: [] } - - await mockOpenCodeServer(page, { - directory, - project: { - id: projectID, - worktree: directory, - vcs: "git", - name: "todo-dock-navigation", - time: { created: 1700000000000, updated: 1700000000000 }, - sandboxes: [], - }, - provider: { - all: [ - { - id: "opencode", - name: "OpenCode", - models: { - "claude-opus-4-6": { - id: "claude-opus-4-6", - name: "Claude Opus 4.6", - limit: { context: 200_000 }, - }, - }, - }, - ], - connected: ["opencode"], - default: { providerID: "opencode", modelID: "claude-opus-4-6" }, - }, - sessions: [session(sourceID, sourceTitle, 1700000000000), session(otherID, otherTitle, 1700000001000)], - pageMessages: () => ({ items: [] }), - events: () => events.splice(0, 1), - eventRetry: 16, - todos: (sessionID) => todos[sessionID] ?? [], - }) - await configurePage(page) - - await page.goto(sessionHref(sourceID)) - await expectSessionTitle(page, sourceTitle) - const dock = page.locator('[data-component="session-todo-dock"]') - await expect(dock).toHaveCount(0) - - events.push(statusEvent(sourceID, "busy")) - await expect(page.getByRole("button", { name: "Stop" })).toBeVisible() - - await page.waitForTimeout(700) - const opening = sampleDock(page, 1_000) - todos[sourceID] = activeTodos - events.push(todoEvent(sourceID, activeTodos)) - await expect(dock).toBeVisible() - await expect(dock.locator('[data-state="in_progress"]')).toHaveCount(1) - expect((await opening).some((sample) => sample.opacity > 0.05 && sample.opacity < 0.95)).toBe(true) - - await switchSession(page, otherID, otherTitle) - await expect(dock).toHaveCount(0) - - const returningOpen = sampleDock(page, 700) - await switchSession(page, sourceID, sourceTitle) - const openSamples = (await returningOpen).filter((sample) => sample.present) - expect(openSamples.length).toBeGreaterThan(0) - expect(openSamples[0]!.opacity).toBeGreaterThan(0.98) - expect(openSamples[0]!.height).toBeGreaterThan(70) - await expect(dock.locator('[data-state="in_progress"]')).toHaveCount(1) - - const completedTodos = activeTodos.map((todo) => ({ ...todo, status: "completed" })) - const closing = sampleDock(page, 1_000) - todos[sourceID] = completedTodos - events.push(todoEvent(sourceID, completedTodos)) - await expect(dock).toHaveCount(0) - expect((await closing).some((sample) => sample.opacity > 0.05 && sample.opacity < 0.95)).toBe(true) - todos[sourceID] = [] - events.push(todoEvent(sourceID, [])) - - await switchSession(page, otherID, otherTitle) - const returningEmpty = sampleDock(page, 700) - await switchSession(page, sourceID, sourceTitle) - await expect(dock).toHaveCount(0) - expect((await returningEmpty).every((sample) => !sample.present)).toBe(true) -}) - -function session(id: string, title: string, created: number) { - return { - id, - slug: id, - projectID, - directory, - title, - version: "dev", - time: { created, updated: created }, - } -} - -function statusEvent(sessionID: string, type: "busy" | "idle"): EventPayload { - return { - directory, - payload: { type: "session.status", properties: { sessionID, status: { type } } }, - } -} - -function todoEvent(sessionID: string, next: typeof activeTodos): EventPayload { - return { - directory, - payload: { type: "todo.updated", properties: { sessionID, todos: next } }, - } -} - -async function configurePage(page: Page) { - const server = `http://${process.env.PLAYWRIGHT_SERVER_HOST ?? "127.0.0.1"}:${process.env.PLAYWRIGHT_SERVER_PORT ?? "4096"}` - await page.addInitScript( - ({ directory, dirBase64, server, sessionIDs }) => { - localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: true } })) - localStorage.setItem( - "opencode.global.dat:server", - JSON.stringify({ - projects: { local: [{ worktree: directory, expanded: true }] }, - lastProject: { local: directory }, - }), - ) - localStorage.setItem( - "opencode.window.browser.dat:tabs", - JSON.stringify(sessionIDs.map((sessionId) => ({ type: "session", server, dirBase64, sessionId }))), - ) - }, - { directory, dirBase64: base64Encode(directory), server, sessionIDs: [sourceID, otherID] }, - ) -} - -function sessionHref(sessionID: string) { - const server = `http://${process.env.PLAYWRIGHT_SERVER_HOST ?? "127.0.0.1"}:${process.env.PLAYWRIGHT_SERVER_PORT ?? "4096"}` - return `/server/${base64Encode(server)}/session/${sessionID}` -} - -async function switchSession(page: Page, sessionID: string, title: string) { - const href = sessionHref(sessionID) - const tab = page.locator(`[data-slot="titlebar-tabs"] a[href="${href}"]`).first() - await expect(tab).toBeVisible() - await tab.click() - await expectSessionTitle(page, title) -} - -function sampleDock(page: Page, duration: number) { - return page.evaluate(async (duration) => { - const samples: { present: boolean; height: number; opacity: number }[] = [] - const start = performance.now() - while (performance.now() - start < duration) { - const dock = document.querySelector('[data-component="session-todo-dock"]') - const clip = dock?.parentElement?.parentElement - const label = dock?.querySelector('[data-action="session-todo-toggle"] span[aria-label]') - samples.push({ - present: !!dock, - height: clip?.getBoundingClientRect().height ?? 0, - opacity: label ? Number.parseFloat(getComputedStyle(label).opacity) : 0, - }) - await new Promise(requestAnimationFrame) - } - return samples - }, duration) -} diff --git a/packages/app/e2e/regression/tab-navigate-mousedown.spec.ts b/packages/app/e2e/regression/tab-navigate-mousedown.spec.ts index 94afbc9a9d..6bc417af80 100644 --- a/packages/app/e2e/regression/tab-navigate-mousedown.spec.ts +++ b/packages/app/e2e/regression/tab-navigate-mousedown.spec.ts @@ -63,7 +63,7 @@ async function mockServer(page: Page) { if (byId) return json(route, byId) if (/^\/session\/[^/]+$/.test(url.pathname)) return json(route, { name: "NotFoundError" }, 404) if (/^\/session\/[^/]+\/message$/.test(url.pathname)) return json(route, []) - if (/^\/session\/[^/]+\/(children|todo|diff)$/.test(url.pathname)) return json(route, []) + if (/^\/session\/[^/]+\/(children|diff)$/.test(url.pathname)) return json(route, []) if (["/skill", "/command", "/lsp", "/formatter", "/permission", "/question", "/vcs/diff"].includes(url.pathname)) return json(route, []) if (["/global/config", "/config", "/provider/auth", "/mcp", "/session/status"].includes(url.pathname)) diff --git a/packages/app/e2e/smoke/session-timeline.fixture.ts b/packages/app/e2e/smoke/session-timeline.fixture.ts index 3dce37cafd..beb2d7cf75 100644 --- a/packages/app/e2e/smoke/session-timeline.fixture.ts +++ b/packages/app/e2e/smoke/session-timeline.fixture.ts @@ -120,7 +120,7 @@ function toolPart( outputLength = 160, ): MessagePart { const metadata = - tool === "apply_patch" + tool === "patch" ? { files: [patchFile(index, "update"), patchFile(index + 1, index % 2 === 0 ? "add" : "delete")] } : tool === "edit" || tool === "write" ? { @@ -199,7 +199,7 @@ function turn(index: number): Message[] { ? [toolPart(index, 7, "write", { filePath: `src/generated/write-${index}.ts`, content: code(index, 28) }, 560)] : []), ...(index % 8 === 0 - ? [toolPart(index, 8, "apply_patch", { files: [`src/generated/patch-${index}.ts`] }, 620)] + ? [toolPart(index, 8, "patch", { files: [`src/generated/patch-${index}.ts`] }, 620)] : []), ...(index % 7 === 0 ? [toolPart(index, 4, "bash", { command: "bun typecheck" }, 620)] : []), ...(index % 10 === 0 ? [toolPart(index, 9, "webfetch", { url: "https://example.com/docs/sample" }, 120)] : []), @@ -229,7 +229,6 @@ const sourceMessages = Array.from({ length: 12 }, (_, index) => [ ]).flat() function renderable(part: MessagePart) { - if (part.type === "tool" && part.tool === "todowrite") return false if (part.type === "text") return !!part.text.trim() if (part.type === "reasoning") return !!part.text.trim() return part.type !== "step-start" && part.type !== "step-finish" && part.type !== "patch" diff --git a/packages/app/e2e/utils/mock-server.ts b/packages/app/e2e/utils/mock-server.ts index e5df40c7d2..c69382bba3 100644 --- a/packages/app/e2e/utils/mock-server.ts +++ b/packages/app/e2e/utils/mock-server.ts @@ -17,7 +17,6 @@ export interface MockServerConfig { onMessage?: (input: { sessionID: string; messageID: string }) => void events?: () => unknown[] eventRetry?: number - todos?: (sessionID: string) => unknown[] permissions?: unknown[] | (() => unknown[]) questions?: unknown[] | (() => unknown[]) fileList?: (path: string) => unknown | Promise @@ -55,7 +54,7 @@ export async function mockOpenCodeServer(page: Page, config: MockServerConfig) { const path = url.pathname if (path === "/global/event" || path === "/event") return sse(route, config.events?.(), config.eventRetry) if (path === "/global/health") return json(route, { healthy: true }) - if (path === "/experimental/capabilities") return json(route, { backgroundSubagents: false }) + if (path === "/experimental/capabilities") return json(route, { backgroundSubagents: true }) if (path === "/permission") return json(route, typeof config.permissions === "function" ? config.permissions() : (config.permissions ?? [])) if (path === "/question") @@ -96,8 +95,6 @@ export async function mockOpenCodeServer(page: Page, config: MockServerConfig) { return json(route, message) } - const todoMatch = path.match(/^\/session\/([^/]+)\/todo$/) - if (todoMatch) return json(route, config.todos?.(todoMatch[1]!) ?? []) if (/^\/session\/[^/]+\/(children|diff)$/.test(path)) return json(route, []) const messagesMatch = path.match(/^\/session\/([^/]+)\/message$/) diff --git a/packages/app/package.json b/packages/app/package.json index 739dfc5ba0..7430a614bf 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "1.17.14", + "version": "1.17.15", "description": "", "type": "module", "exports": { diff --git a/packages/app/src/app.tsx b/packages/app/src/app.tsx index 9c2e7d6a1f..b7f87a09cd 100644 --- a/packages/app/src/app.tsx +++ b/packages/app/src/app.tsx @@ -9,7 +9,7 @@ import { Font } from "@opencode-ai/ui/font" import { Splash } from "@opencode-ai/ui/logo" import { ThemeProvider } from "@opencode-ai/ui/theme/context" import { MetaProvider } from "@solidjs/meta" -import { type BaseRouterProps, Navigate, Route, Router, useParams, useSearchParams } from "@solidjs/router" +import { type BaseRouterProps, Navigate, Route, Router, useNavigate, useParams, useSearchParams } from "@solidjs/router" import { QueryClient, QueryClientProvider } from "@tanstack/solid-query" import { Effect } from "effect" import { @@ -32,7 +32,7 @@ import { CommandProvider, useCommand, type CommandOption } from "@/context/comma import { CommentsProvider } from "@/context/comments" import { FileProvider } from "@/context/file" import { ServerSDKProvider } from "@/context/server-sdk" -import { ServerSyncProvider } from "@/context/server-sync" +import { ServerSyncProvider, useServerSync } from "@/context/server-sync" import { GlobalProvider, useGlobal } from "@/context/global" import { HighlightsProvider } from "@/context/highlights" import { LanguageProvider, type Locale, useLanguage } from "@/context/language" @@ -52,9 +52,10 @@ import LegacyLayout from "@/pages/layout" import NewLayout from "@/pages/layout-new" import { ErrorPage } from "./pages/error" import { useCheckServerHealth } from "./utils/server-health" -import { legacySessionServer, requireServerKey, sessionHref } from "./utils/session-route" +import { legacySessionHref, legacySessionServer, requireServerKey, sessionHref } from "./utils/session-route" +import { createSessionLineage } from "@/pages/session/session-lineage" -import { SessionPage, TargetSessionRouteContent } from "@/pages/session" +import { SessionPage, SessionRouteErrorBoundary, TargetSessionRouteContent } from "@/pages/session" import { NewHome, LegacyHome } from "@/pages/home" const NewSession = lazy(() => import("@/pages/new-session")) @@ -88,10 +89,14 @@ const SessionRoute = () => { tabs.newDraft({ server: server.key, directory: sdk().directory }, search.prompt) }) - return + return ( + + + + ) } -const TargetSessionRoute = () => { +function TargetServerRoute(props: ParentProps) { const params = useParams<{ serverKey: string; id: string }>() const global = useGlobal() const conn = createMemo(() => { @@ -105,14 +110,47 @@ const TargetSessionRoute = () => { // re-resolves reactively instead); both rely on this key for server changes. - - - + {props.children} ) } +const TargetSessionRoute = () => ( + + + +) + +function LegacyTargetSessionRoute() { + const params = useParams<{ serverKey: string; id: string }>() + return ( + + + + + + ) +} + +function LegacyTargetSessionRedirect() { + const params = useParams<{ id: string }>() + const navigate = useNavigate() + const sync = useServerSync() + const current = createSessionLineage( + () => params.id, + () => sync().session.lineage, + ) + + createEffect(() => { + const directory = current()?.session.directory + if (!directory) return + navigate(legacySessionHref(directory, params.id), { replace: true }) + }) + + return null +} + // Wraps the non-draft routes. They are gated on (and keyed to) the globally selected // server via ServerKey, then provide the server-scoped shell (Permission/Layout/ // Notification/Models + the visual Layout) for that server. @@ -186,7 +224,7 @@ declare global { deepLinks?: string[] } api?: { - setTitlebar?: (theme: { mode: "light" | "dark" }) => Promise + setTitlebar?: (theme: { mode: "light" | "dark"; scheme?: "system" | "light" | "dark" }) => Promise exportDebugLogs?: () => Promise } } @@ -320,8 +358,8 @@ export function AppBaseProviders(props: ParentProps<{ locale?: Locale }>) { { - void window.api?.setTitlebar?.({ mode }) + onThemeApplied={(_, mode, scheme) => { + void window.api?.setTitlebar?.({ mode, scheme }) }} > @@ -542,7 +580,14 @@ function Routes(props: { serverScoped?: JSX.Element }) { {routeProps.children} )} > - {} + + { + <> + + + + } + } /> @@ -550,15 +595,15 @@ function Routes(props: { serverScoped?: JSX.Element }) { - + + - ) } -function LegacyTargetSessionRoute() { +function NewLayoutLegacySessionRedirect() { const server = useServer() const tabs = useTabs() const params = useParams<{ id: string }>() diff --git a/packages/app/src/components/command-palette.ts b/packages/app/src/components/command-palette.ts new file mode 100644 index 0000000000..b61a61977e --- /dev/null +++ b/packages/app/src/components/command-palette.ts @@ -0,0 +1,325 @@ +import { base64Encode } from "@opencode-ai/core/util/encode" +import { getFilename } from "@opencode-ai/core/util/path" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { useNavigate } from "@solidjs/router" +import { createMemo, onCleanup } from "solid-js" +import { useCommand, type CommandOption } from "@/context/command" +import { useFile } from "@/context/file" +import { useLanguage } from "@/context/language" +import { useLayout } from "@/context/layout" +import { useServerSDK, type ServerSDK } from "@/context/server-sdk" +import { useServerSync } from "@/context/server-sync" +import { createSessionTabs } from "@/pages/session/helpers" +import { useSessionLayout } from "@/pages/session/session-layout" +import { decode64 } from "@/utils/base64" + +export type CommandPaletteEntry = { + id: string + type: "command" | "file" | "session" + title: string + description?: string + keybind?: string + category: string + option?: CommandOption + path?: string + directory?: string + sessionID?: string + archived?: number + updated?: number +} + +const ENTRY_LIMIT = 5 +const COMMON_COMMAND_IDS = [ + "session.new", + "workspace.new", + "session.previous", + "session.next", + "terminal.toggle", + "review.toggle", +] as const + +export function uniqueCommandPaletteEntries(items: CommandPaletteEntry[]) { + const seen = new Set() + return items.filter((item) => { + if (seen.has(item.id)) return false + seen.add(item.id) + return true + }) +} + +export function createCommandPaletteFileEntry(path: string, category: string): CommandPaletteEntry { + return { + id: "file:" + path, + type: "file", + title: path, + category, + path, + } +} + +export function createCommandPaletteFileOpener(onOpenFile?: (path: string) => void) { + const file = useFile() + const layout = useLayout() + const { tabs, view } = useSessionLayout() + + return (path: string) => { + const value = file.tab(path) + void tabs().open(value) + void file.load(path) + if (!view().reviewPanel.opened()) view().reviewPanel.open() + layout.fileTree.setTab("all") + onOpenFile?.(path) + tabs().setActive(value) + } +} + +export function createCommandPaletteModel(props: { filesOnly?: () => boolean; onOpenFile?: (path: string) => void }) { + const command = useCommand() + const language = useLanguage() + const layout = useLayout() + const file = useFile() + const dialog = useDialog() + const navigate = useNavigate() + const serverSDK = useServerSDK()() + const serverSync = useServerSync() + const { params, tabs } = useSessionLayout() + const openFile = createCommandPaletteFileOpener(props.onOpenFile) + const state = { cleanup: undefined as (() => void) | void, committed: false } + const filesOnly = () => props.filesOnly?.() ?? false + + const allowedCommands = createMemo(() => { + if (filesOnly()) return [] + return command.options.filter( + (option) => + !option.disabled && !option.hidden && !option.id.startsWith("suggested.") && option.id !== "file.open", + ) + }) + const commandEntries = createMemo(() => { + const category = language.t("palette.group.commands") + return allowedCommands().map((option) => createCommandEntry(option, category)) + }) + const preferredCommandEntries = createMemo(() => { + const all = allowedCommands() + const order = new Map(COMMON_COMMAND_IDS.map((id, index) => [id, index])) + const picked = all.filter((option) => order.has(option.id)) + const base = picked.length ? picked : all.slice(0, ENTRY_LIMIT) + const sorted = picked.length ? [...base].sort((a, b) => (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0)) : base + const category = language.t("palette.group.commands") + return sorted.map((option) => createCommandEntry(option, category)) + }) + + const tabState = createSessionTabs({ + tabs, + pathFromTab: file.pathFromTab, + normalizeTab: (tab) => (tab.startsWith("file://") ? file.tab(tab) : tab), + }) + const recentFileEntries = createMemo(() => { + const all = tabState.openedTabs() + const active = tabState.activeFileTab() + const order = active ? [active, ...all.filter((item) => item !== active)] : all + const seen = new Set() + const category = language.t("palette.group.files") + return order + .map((item) => file.pathFromTab(item)) + .filter((path): path is string => { + if (!path || seen.has(path)) return false + seen.add(path) + return true + }) + .slice(0, ENTRY_LIMIT) + .map((path) => createCommandPaletteFileEntry(path, category)) + }) + const rootFileEntries = createMemo(() => { + const category = language.t("palette.group.files") + return file.tree + .children("") + .filter((node) => node.type === "file") + .map((node) => node.path) + .sort((a, b) => a.localeCompare(b)) + .slice(0, ENTRY_LIMIT) + .map((path) => createCommandPaletteFileEntry(path, category)) + }) + + const projectDirectory = createMemo(() => decode64(params.dir) ?? "") + const project = createMemo(() => { + const directory = projectDirectory() + if (!directory) return undefined + return layout.projects.list().find((item) => item.worktree === directory || item.sandboxes?.includes(directory)) + }) + const workspaces = createMemo(() => { + const directory = projectDirectory() + const current = project() + if (!current) return directory ? [directory] : [] + const dirs = [current.worktree, ...(current.sandboxes ?? [])] + if (directory && !dirs.includes(directory)) return [...dirs, directory] + return dirs + }) + const homedir = createMemo(() => serverSync().data.path.home) + const sessions = createSessionEntries({ + workspaces, + label: (directory) => { + const current = project() + const kind = + current && directory === current.worktree + ? language.t("workspace.type.local") + : language.t("workspace.type.sandbox") + const [store] = serverSync().child(directory, { bootstrap: false }) + const home = homedir() + const path = home ? directory.replace(home, "~") : directory + const name = store.vcs?.branch ?? getFilename(directory) + return `${kind} : ${name || path}` + }, + load: (directory) => serverSDK.client.session.list({ directory, roots: true }), + untitled: () => language.t("command.session.new"), + category: () => language.t("command.category.session"), + }) + + const highlight = (item: CommandPaletteEntry | undefined) => { + state.cleanup?.() + state.cleanup = undefined + if (item?.type !== "command") return + state.cleanup = item.option?.onHighlight?.() + } + + const select = (item: CommandPaletteEntry | undefined) => { + if (!item) return + state.committed = true + state.cleanup = undefined + dialog.close() + if (item.type === "command") { + item.option?.onSelect?.("palette") + return + } + if (item.type === "session") { + if (!item.directory || !item.sessionID) return + navigate(`/${base64Encode(item.directory)}/session/${item.sessionID}`) + return + } + if (!item.path) return + openFile(item.path) + } + + onCleanup(() => { + if (state.committed) return + state.cleanup?.() + }) + + return { + language, + file, + commandEntries, + preferredCommandEntries, + recentFileEntries, + rootFileEntries, + sessions, + highlight, + select, + close: () => dialog.close(), + } +} + +function createCommandEntry(option: CommandOption, category: string): CommandPaletteEntry { + return { + id: "command:" + option.id, + type: "command", + title: option.title, + description: option.description, + keybind: option.keybind, + category, + option, + } +} + +function createSessionEntries(props: { + workspaces: () => string[] + label: (directory: string) => string + load: (directory: string) => ReturnType + untitled: () => string + category: () => string +}) { + const state: { + token: number + inflight: Promise | undefined + cached: CommandPaletteEntry[] | undefined + } = { token: 0, inflight: undefined, cached: undefined } + + return (text: string) => { + if (!text.trim()) { + state.token += 1 + state.inflight = undefined + state.cached = undefined + return [] as CommandPaletteEntry[] + } + if (state.cached) return state.cached + if (state.inflight) return state.inflight + + const current = state.token + const dirs = props.workspaces() + if (dirs.length === 0) return [] as CommandPaletteEntry[] + + state.inflight = Promise.all( + dirs.map((directory) => { + const description = props.label(directory) + return props + .load(directory) + .then((result) => + (result.data ?? []) + .filter((session) => !!session?.id) + .map((session) => ({ + id: session.id, + title: session.title ?? props.untitled(), + description, + directory, + archived: session.time?.archived, + updated: session.time?.updated, + })), + ) + .catch(() => [] as SessionEntryInput[]) + }), + ) + .then((results) => { + if (state.token !== current) return [] as CommandPaletteEntry[] + const seen = new Set() + const next = results + .flat() + .filter((item) => { + const key = `${item.directory}:${item.id}` + if (seen.has(key)) return false + seen.add(key) + return true + }) + .map((item) => createSessionEntry(item, props.category())) + state.cached = next + return next + }) + .catch(() => [] as CommandPaletteEntry[]) + .finally(() => { + state.inflight = undefined + }) + + return state.inflight + } +} + +type SessionEntryInput = { + directory: string + id: string + title: string + description: string + archived?: number + updated?: number +} + +function createSessionEntry(input: SessionEntryInput, category: string): CommandPaletteEntry { + return { + id: `session:${input.directory}:${input.id}`, + type: "session", + title: input.title, + description: input.description, + category, + directory: input.directory, + sessionID: input.id, + archived: input.archived, + updated: input.updated, + } +} diff --git a/packages/app/src/components/dialog-command-palette-v2.css b/packages/app/src/components/dialog-command-palette-v2.css new file mode 100644 index 0000000000..a4019928aa --- /dev/null +++ b/packages/app/src/components/dialog-command-palette-v2.css @@ -0,0 +1,220 @@ +.command-palette-v2 { + overflow: hidden; +} + +/* Anchor to the top edge of where a centered 480px-tall dialog would sit, so the + top stays put while the content-driven height grows and shrinks. */ +[data-component="dialog-v2"]:has(.command-palette-v2) { + align-items: flex-start; +} + +[data-component="dialog-v2"]:has(.command-palette-v2) [data-slot="dialog-container"] { + width: min(calc(100vw - 24px), 640px); + height: auto; + min-height: 280px; + max-height: min(calc(100vh - 96px), 480px); + margin-top: max(48px, calc((100vh - 480px) / 2)); + border-radius: 12px; + background: var(--v2-background-bg-base); + box-shadow: var(--v2-elevation-floating); +} + +.command-palette-v2-body { + display: flex; + min-height: 0; + flex: 1; + flex-direction: column; + gap: 0; + padding: 0; +} + +.command-palette-v2-search { + flex-shrink: 0; + padding: 6px; +} + +.command-palette-v2-search [data-component="text-input-v2"] { + width: 100%; + height: 36px; + border-radius: 6px; + outline: 0; + background: color-mix(in srgb, var(--v2-background-bg-layer-02) 60%, transparent); + box-shadow: none; + transition: + background-color 120ms ease-in-out, + box-shadow 120ms ease-in-out; +} + +.command-palette-v2-search [data-component="text-input-v2"]:where(:hover):not([data-disabled], [data-invalid]), +.command-palette-v2-search [data-component="text-input-v2"]:where(:focus-within):not([data-disabled], [data-invalid]) { + background: var(--v2-background-bg-layer-02); + box-shadow: none; +} + +.command-palette-v2-search [data-component="text-input-v2"] [data-slot="text-input-v2-value"] { + border-radius: 6px; + background: transparent; + gap: 8px; +} + +.command-palette-v2-search [data-component="text-input-v2"] [data-slot="text-input-v2-leading-icon"] { + padding-left: 12px; +} + +.command-palette-v2-search [data-component="text-input-v2"] [data-slot="text-input-v2-input"] { + border-radius: 6px; + background: transparent; +} + +.command-palette-v2-scroll { + min-height: 0; + flex: 1; +} + +.command-palette-v2-results { + display: flex; + flex-direction: column; + gap: 16px; + padding: 6px 6px 8px; +} + +.command-palette-v2-group { + display: flex; + flex-direction: column; + gap: 1px; +} + +.command-palette-v2-group-title { + margin: 6px 0; + padding: 0 12px; + color: var(--v2-text-text-muted); + font-size: 13px; + font-weight: 440; + line-height: 16px; + letter-spacing: -0.04px; + user-select: none; +} + +.command-palette-v2-row { + display: flex; + width: 100%; + height: 36px; + flex-shrink: 0; + align-items: center; + justify-content: space-between; + gap: 8px; + padding: 0 12px; + border: 0; + border-radius: 6px; + background: transparent; + color: var(--v2-text-text-base); + text-align: left; + cursor: default; + scroll-margin: 6px 0; +} + +.command-palette-v2-row[data-active] { + background: var(--v2-overlay-simple-overlay-hover); +} + +.command-palette-v2-row:focus-visible { + background: var(--v2-overlay-simple-overlay-hover); + outline: none; +} + +.command-palette-v2-row-main { + display: flex; + min-width: 0; + flex: 1; + align-items: center; + gap: 8px; +} + +.command-palette-v2-row-icon { + flex-shrink: 0; + color: var(--v2-icon-icon-muted); +} + +.command-palette-v2-row-text { + display: flex; + min-width: 0; + align-items: center; + gap: 6px; +} + +.command-palette-v2-title { + min-width: 0; + overflow: hidden; + color: var(--v2-text-text-base); + font-size: 13px; + font-weight: 530; + line-height: 16px; + letter-spacing: -0.04px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.command-palette-v2-description, +.command-palette-v2-meta { + min-width: 0; + overflow: hidden; + color: var(--v2-text-text-muted); + font-size: 13px; + font-weight: 440; + line-height: 16px; + letter-spacing: -0.04px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.command-palette-v2-meta { + flex-shrink: 0; +} + +.command-palette-v2-file-path { + display: flex; + min-width: 0; + align-items: baseline; + font-size: 13px; + line-height: 16px; + letter-spacing: -0.04px; +} + +.command-palette-v2-file-dir { + min-width: 0; + overflow: hidden; + color: var(--v2-text-text-muted); + font-weight: 440; + text-overflow: ellipsis; + white-space: nowrap; +} + +.command-palette-v2-file-name { + flex-shrink: 0; + color: var(--v2-text-text-base); + font-weight: 530; + white-space: nowrap; +} + +.command-palette-v2-state { + display: grid; + min-height: 120px; + place-items: center; + color: var(--v2-text-text-muted); + font-size: 13px; + font-weight: 440; + line-height: 16px; + letter-spacing: -0.04px; +} + +@media (max-width: 640px) { + .command-palette-v2-row-text { + flex-direction: column; + align-items: flex-start; + gap: 1px; + } + + .command-palette-v2-description { + max-width: 100%; + } +} diff --git a/packages/app/src/components/dialog-command-palette-v2.tsx b/packages/app/src/components/dialog-command-palette-v2.tsx new file mode 100644 index 0000000000..b1cafe1e7a --- /dev/null +++ b/packages/app/src/components/dialog-command-palette-v2.tsx @@ -0,0 +1,221 @@ +import { getDirectory, getFilename } from "@opencode-ai/core/util/path" +import { FileIcon } from "@opencode-ai/ui/file-icon" +import { ScrollView } from "@opencode-ai/ui/scroll-view" +import { Dialog, DialogBody } from "@opencode-ai/ui/v2/dialog-v2" +import { Icon } from "@opencode-ai/ui/v2/icon" +import { KeybindV2 } from "@opencode-ai/ui/v2/keybind-v2" +import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2" +import { createEffect, createMemo, createResource, createSignal, For, Match, Show, Switch } from "solid-js" +import { formatKeybindParts } from "@/context/command" +import { useLanguage } from "@/context/language" +import { getRelativeTime } from "@/utils/time" +import { + createCommandPaletteFileEntry, + createCommandPaletteModel, + uniqueCommandPaletteEntries, + type CommandPaletteEntry, +} from "./command-palette" +import "./dialog-command-palette-v2.css" + +function groups(entries: CommandPaletteEntry[]) { + const map = new Map() + for (const entry of entries) map.set(entry.category, [...(map.get(entry.category) ?? []), entry]) + return Array.from(map.entries()).map(([category, entries]) => ({ category, entries })) +} + +function matchesEntry(entry: CommandPaletteEntry, query: string) { + const value = query.toLowerCase() + return [entry.title, entry.description, entry.category].some((text) => text?.toLowerCase().includes(value)) +} + +export function DialogCommandPaletteV2(props: { onOpenFile?: (path: string) => void }) { + const palette = createCommandPaletteModel(props) + const [query, setQuery] = createSignal("") + const [active, setActive] = createSignal(0) + + const loadItems = async (text: string) => { + const q = text.trim() + if (!q) return [...palette.preferredCommandEntries(), ...palette.recentFileEntries()] + + const [files, nextSessions] = await Promise.all([palette.file.searchFiles(q), Promise.resolve(palette.sessions(q))]) + const category = palette.language.t("palette.group.files") + return [ + ...palette.commandEntries().filter((entry) => matchesEntry(entry, q)), + ...nextSessions.filter((entry) => matchesEntry(entry, q)), + ...files.map((path) => createCommandPaletteFileEntry(path, category)), + ] + } + + const [entries] = createResource(query, loadItems, { initialValue: [] as CommandPaletteEntry[] }) + // Render stale results while a new query loads to avoid flashing "Loading" per keystroke. + const visibleEntries = createMemo(() => uniqueCommandPaletteEntries(entries.latest ?? [])) + const groupedEntries = createMemo(() => groups(visibleEntries())) + const activeEntry = createMemo(() => visibleEntries()[active()]) + + createEffect(() => { + query() + visibleEntries() + setActive(0) + }) + + createEffect(() => { + palette.highlight(activeEntry()) + }) + + let resultsRef: HTMLDivElement | undefined + + const move = (delta: -1 | 1) => { + const count = visibleEntries().length + if (count === 0) return + setActive((index) => (index + delta + count) % count) + requestAnimationFrame(() => { + resultsRef?.querySelector("[data-active]")?.scrollIntoView({ block: "nearest" }) + }) + } + + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === "ArrowDown") { + event.preventDefault() + move(1) + return + } + if (event.key === "ArrowUp") { + event.preventDefault() + move(-1) + return + } + if (event.key === "Enter") { + event.preventDefault() + palette.select(activeEntry()) + return + } + if (event.key === "Escape") { + event.preventDefault() + palette.close() + } + } + + return ( + + + + (resultsRef = el)}> +
+ 0} + fallback={ +
+ {entries.loading ? palette.language.t("common.loading") : palette.language.t("palette.empty")} +
+ } + > + + {(group) => ( +
+ +
{group.category}
+
+ + {(item) => ( + setActive(visibleEntries().findIndex((entry) => entry.id === item.id))} + onSelect={() => palette.select(item)} + /> + )} + +
+ )} +
+
+
+
+
+
+ ) +} + +function PaletteRow(props: { + item: CommandPaletteEntry + active: boolean + language: ReturnType + onActive: () => void + onSelect: () => void +}) { + return ( + + ) +} diff --git a/packages/app/src/components/dialog-select-file.tsx b/packages/app/src/components/dialog-select-file.tsx index 49a0d5961a..d7c6c2a84f 100644 --- a/packages/app/src/components/dialog-select-file.tsx +++ b/packages/app/src/components/dialog-select-file.tsx @@ -1,329 +1,84 @@ -import { useDialog } from "@opencode-ai/ui/context/dialog" import { Dialog } from "@opencode-ai/ui/dialog" import { FileIcon } from "@opencode-ai/ui/file-icon" import { Icon } from "@opencode-ai/ui/icon" import { Keybind } from "@opencode-ai/ui/keybind" import { List } from "@opencode-ai/ui/list" -import { base64Encode } from "@opencode-ai/core/util/encode" import { getDirectory, getFilename } from "@opencode-ai/core/util/path" -import { useNavigate } from "@solidjs/router" -import { createMemo, createSignal, lazy, Match, onCleanup, Show, Switch } from "solid-js" -import { formatKeybind, useCommand, type CommandOption } from "@/context/command" -import { useServerSDK, type ServerSDK } from "@/context/server-sdk" -import { useServerSync } from "@/context/server-sync" -import { useLayout } from "@/context/layout" -import { useFile } from "@/context/file" +import { createMemo, createSignal, lazy, Match, Show, Switch } from "solid-js" +import { formatKeybind } from "@/context/command" +import { useServerSDK } from "@/context/server-sdk" import { useLanguage } from "@/context/language" import { usePlatform } from "@/context/platform" import { useSettings } from "@/context/settings" import { useSessionLayout } from "@/pages/session/session-layout" -import { createSessionTabs } from "@/pages/session/helpers" import { decode64 } from "@/utils/base64" import { getRelativeTime } from "@/utils/time" +import { + createCommandPaletteFileEntry, + createCommandPaletteFileOpener, + createCommandPaletteModel, + uniqueCommandPaletteEntries, + type CommandPaletteEntry, +} from "./command-palette" const DialogSelectFileV2 = lazy(() => import("./dialog-select-directory-v2").then((module) => ({ default: module.DialogSelectDirectoryV2 })), ) - -type EntryType = "command" | "file" | "session" - -type Entry = { - id: string - type: EntryType - title: string - description?: string - keybind?: string - category: string - option?: CommandOption - path?: string - directory?: string - sessionID?: string - archived?: number - updated?: number -} +const DialogCommandPaletteV2 = lazy(() => + import("./dialog-command-palette-v2").then((module) => ({ default: module.DialogCommandPaletteV2 })), +) type DialogSelectFileMode = "all" | "files" -const ENTRY_LIMIT = 5 -const COMMON_COMMAND_IDS = [ - "session.new", - "workspace.new", - "session.previous", - "session.next", - "terminal.toggle", - "review.toggle", -] as const - -const uniqueEntries = (items: Entry[]) => { - const seen = new Set() - const out: Entry[] = [] - for (const item of items) { - if (seen.has(item.id)) continue - seen.add(item.id) - out.push(item) - } - return out -} - -const createCommandEntry = (option: CommandOption, category: string): Entry => ({ - id: "command:" + option.id, - type: "command", - title: option.title, - description: option.description, - keybind: option.keybind, - category, - option, -}) - -const createFileEntry = (path: string, category: string): Entry => ({ - id: "file:" + path, - type: "file", - title: path, - category, - path, -}) - -const createSessionEntry = ( - input: { - directory: string - id: string - title: string - description: string - archived?: number - updated?: number - }, - category: string, -): Entry => ({ - id: `session:${input.directory}:${input.id}`, - type: "session", - title: input.title, - description: input.description, - category, - directory: input.directory, - sessionID: input.id, - archived: input.archived, - updated: input.updated, -}) - -function createCommandEntries(props: { - filesOnly: () => boolean - command: ReturnType - language: ReturnType -}) { - const allowed = createMemo(() => { - if (props.filesOnly()) return [] - return props.command.options.filter( - (option) => - !option.disabled && !option.hidden && !option.id.startsWith("suggested.") && option.id !== "file.open", - ) - }) - - const list = createMemo(() => { - const category = props.language.t("palette.group.commands") - return allowed().map((option) => createCommandEntry(option, category)) - }) - - const picks = createMemo(() => { - const all = allowed() - const order = new Map(COMMON_COMMAND_IDS.map((id, index) => [id, index])) - const picked = all.filter((option) => order.has(option.id)) - const base = picked.length ? picked : all.slice(0, ENTRY_LIMIT) - const sorted = picked.length ? [...base].sort((a, b) => (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0)) : base - const category = props.language.t("palette.group.commands") - return sorted.map((option) => createCommandEntry(option, category)) - }) - - return { allowed, list, picks } -} - -function createFileEntries(props: { - file: ReturnType - tabs: () => ReturnType["tabs"]> - language: ReturnType -}) { - const tabState = createSessionTabs({ - tabs: props.tabs, - pathFromTab: props.file.pathFromTab, - normalizeTab: (tab) => (tab.startsWith("file://") ? props.file.tab(tab) : tab), - }) - const recent = createMemo(() => { - const all = tabState.openedTabs() - const active = tabState.activeFileTab() - const order = active ? [active, ...all.filter((item) => item !== active)] : all - const seen = new Set() - const category = props.language.t("palette.group.files") - const items: Entry[] = [] - - for (const item of order) { - const path = props.file.pathFromTab(item) - if (!path) continue - if (seen.has(path)) continue - seen.add(path) - items.push(createFileEntry(path, category)) - } - - return items.slice(0, ENTRY_LIMIT) - }) - - const root = createMemo(() => { - const category = props.language.t("palette.group.files") - const nodes = props.file.tree.children("") - const paths = nodes - .filter((node) => node.type === "file") - .map((node) => node.path) - .sort((a, b) => a.localeCompare(b)) - return paths.slice(0, ENTRY_LIMIT).map((path) => createFileEntry(path, category)) - }) - - return { recent, root } -} - -function createSessionEntries(props: { - workspaces: () => string[] - label: (directory: string) => string - serverSDK: ServerSDK - language: ReturnType -}) { - const state: { - token: number - inflight: Promise | undefined - cached: Entry[] | undefined - } = { - token: 0, - inflight: undefined, - cached: undefined, - } - - const sessions = (text: string) => { - const query = text.trim() - if (!query) { - state.token += 1 - state.inflight = undefined - state.cached = undefined - return [] as Entry[] - } - - if (state.cached) return state.cached - if (state.inflight) return state.inflight - - const current = state.token - const dirs = props.workspaces() - if (dirs.length === 0) return [] as Entry[] - - state.inflight = Promise.all( - dirs.map((directory) => { - const description = props.label(directory) - return props.serverSDK.client.session - .list({ directory, roots: true }) - .then((x) => - (x.data ?? []) - .filter((s) => !!s?.id) - .map((s) => ({ - id: s.id, - title: s.title ?? props.language.t("command.session.new"), - description, - directory, - archived: s.time?.archived, - updated: s.time?.updated, - })), - ) - .catch( - () => - [] as { - id: string - title: string - description: string - directory: string - archived?: number - updated?: number - }[], - ) - }), - ) - .then((results) => { - if (state.token !== current) return [] as Entry[] - const seen = new Set() - const category = props.language.t("command.category.session") - const next = results - .flat() - .filter((item) => { - const key = `${item.directory}:${item.id}` - if (seen.has(key)) return false - seen.add(key) - return true - }) - .map((item) => createSessionEntry(item, category)) - state.cached = next - return next - }) - .catch(() => [] as Entry[]) - .finally(() => { - state.inflight = undefined - }) - - return state.inflight - } - - return { sessions } -} - export function DialogSelectFile(props: { mode?: DialogSelectFileMode; onOpenFile?: (path: string) => void }) { - const command = useCommand() - const language = useLanguage() const platform = usePlatform() const settings = useSettings() - const layout = useLayout() - const file = useFile() - const dialog = useDialog() - const navigate = useNavigate() - const serverSDK = useServerSDK() - const serverSync = useServerSync() - const { params, tabs, view } = useSessionLayout() const filesOnly = () => props.mode === "files" - const state = { cleanup: undefined as (() => void) | void, committed: false } - const [grouped, setGrouped] = createSignal(false) - const commandEntries = createCommandEntries({ filesOnly, command, language }) - const fileEntries = createFileEntries({ file, tabs, language }) - const projectDirectory = createMemo(() => decode64(params.dir) ?? "") - const project = createMemo(() => { - const directory = projectDirectory() - if (!directory) return - return layout.projects.list().find((p) => p.worktree === directory || p.sandboxes?.includes(directory)) - }) - const workspaces = createMemo(() => { - const directory = projectDirectory() - const current = project() - if (!current) return directory ? [directory] : [] - - const dirs = [current.worktree, ...(current.sandboxes ?? [])] - if (directory && !dirs.includes(directory)) return [...dirs, directory] - return dirs - }) - const homedir = createMemo(() => serverSync().data.path.home) - const label = (directory: string) => { - const current = project() - const kind = - current && directory === current.worktree - ? language.t("workspace.type.local") - : language.t("workspace.type.sandbox") - const [store] = serverSync().child(directory, { bootstrap: false }) - const home = homedir() - const path = home ? directory.replace(home, "~") : directory - const name = store.vcs?.branch ?? getFilename(directory) - return `${kind} : ${name || path}` + if (!filesOnly() && settings.general.newLayoutDesigns()) { + return } - const { sessions } = createSessionEntries({ workspaces, label, serverSDK: serverSDK(), language }) + if (filesOnly() && platform.platform === "desktop" && settings.general.newLayoutDesigns()) { + return + } + + return +} + +function DialogSelectFileDesktopV2(props: { onOpenFile?: (path: string) => void }) { + const language = useLanguage() + const serverSDK = useServerSDK() + const { params } = useSessionLayout() + const projectDirectory = createMemo(() => decode64(params.dir) ?? "") + const openFile = createCommandPaletteFileOpener(props.onOpenFile) + + return ( + { + if (typeof result !== "string") return + openFile(result) + }} + /> + ) +} + +function DialogSelectFileLegacy(props: { filesOnly: () => boolean; onOpenFile?: (path: string) => void }) { + const palette = createCommandPaletteModel(props) + const [grouped, setGrouped] = createSignal(false) const items = async (text: string) => { const query = text.trim() setGrouped(query.length > 0) - if (!query && filesOnly()) { - const loaded = file.tree.state("")?.loaded - const pending = loaded ? Promise.resolve() : file.tree.list("") - const next = uniqueEntries([...fileEntries.recent(), ...fileEntries.root()]) + if (!query && props.filesOnly()) { + const loaded = palette.file.tree.state("")?.loaded + const pending = loaded ? Promise.resolve() : palette.file.tree.list("") + const next = uniqueCommandPaletteEntries([...palette.recentFileEntries(), ...palette.rootFileEntries()]) if (loaded || next.length > 0) { void pending @@ -331,79 +86,24 @@ export function DialogSelectFile(props: { mode?: DialogSelectFileMode; onOpenFil } await pending - return uniqueEntries([...fileEntries.recent(), ...fileEntries.root()]) + return uniqueCommandPaletteEntries([...palette.recentFileEntries(), ...palette.rootFileEntries()]) } - if (!query) return [...commandEntries.picks(), ...fileEntries.recent()] + if (!query) return [...palette.preferredCommandEntries(), ...palette.recentFileEntries()] - if (filesOnly()) { - const files = await file.searchFiles(query) - const category = language.t("palette.group.files") - return files.map((path) => createFileEntry(path, category)) + if (props.filesOnly()) { + const files = await palette.file.searchFiles(query) + const category = palette.language.t("palette.group.files") + return files.map((path) => createCommandPaletteFileEntry(path, category)) } - const [files, nextSessions] = await Promise.all([file.searchFiles(query), Promise.resolve(sessions(query))]) - const category = language.t("palette.group.files") - const entries = files.map((path) => createFileEntry(path, category)) - return [...commandEntries.list(), ...nextSessions, ...entries] - } - - const handleMove = (item: Entry | undefined) => { - state.cleanup?.() - if (!item) return - if (item.type !== "command") return - state.cleanup = item.option?.onHighlight?.() - } - - const open = (path: string) => { - const value = file.tab(path) - void tabs().open(value) - void file.load(path) - if (!view().reviewPanel.opened()) view().reviewPanel.open() - layout.fileTree.setTab("all") - props.onOpenFile?.(path) - tabs().setActive(value) - } - - const handleSelect = (item: Entry | undefined) => { - if (!item) return - state.committed = true - state.cleanup = undefined - dialog.close() - - if (item.type === "command") { - item.option?.onSelect?.("palette") - return - } - - if (item.type === "session") { - if (!item.directory || !item.sessionID) return - navigate(`/${base64Encode(item.directory)}/session/${item.sessionID}`) - return - } - - if (!item.path) return - open(item.path) - } - - onCleanup(() => { - if (state.committed) return - state.cleanup?.() - }) - - if (filesOnly() && platform.platform === "desktop" && settings.general.newLayoutDesigns()) { - return ( - { - if (typeof result !== "string") return - open(result) - }} - /> - ) + const [files, nextSessions] = await Promise.all([ + palette.file.searchFiles(query), + Promise.resolve(palette.sessions(query)), + ]) + const category = palette.language.t("palette.group.files") + const entries = files.map((path) => createCommandPaletteFileEntry(path, category)) + return [...palette.commandEntries(), ...nextSessions, ...entries] } return ( @@ -411,21 +111,21 @@ export function DialogSelectFile(props: { mode?: DialogSelectFileMode; onOpenFil item.id} filterKeys={["title", "description", "category"]} skipFilter={(item) => item.type === "file"} groupBy={grouped() ? (item) => item.category : () => ""} - onMove={handleMove} - onSelect={handleSelect} + onMove={(item: CommandPaletteEntry | undefined) => palette.highlight(item)} + onSelect={(item: CommandPaletteEntry | undefined) => palette.select(item)} > {(item) => ( - {formatKeybind(item.keybind ?? "", language.t)} + {formatKeybind(item.keybind ?? "", palette.language.t)} @@ -479,7 +179,7 @@ export function DialogSelectFile(props: { mode?: DialogSelectFileMode; onOpenFil - {getRelativeTime(new Date(item.updated!).toISOString(), language.t)} + {getRelativeTime(new Date(item.updated!).toISOString(), palette.language.t)} diff --git a/packages/app/src/components/dialog-select-model.tsx b/packages/app/src/components/dialog-select-model.tsx index cea5f34d0d..23857946d0 100644 --- a/packages/app/src/components/dialog-select-model.tsx +++ b/packages/app/src/components/dialog-select-model.tsx @@ -24,6 +24,7 @@ import { Tooltip } from "@opencode-ai/ui/tooltip" import { Icon } from "@opencode-ai/ui/v2/icon" import { Tag as TagV2 } from "@opencode-ai/ui/v2/badge-v2" import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2" +import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2" import { ModelTooltip } from "./model-tooltip" import { useLanguage } from "@/context/language" import { decode64 } from "@/utils/base64" @@ -92,6 +93,7 @@ const ModelList: Component<{ class="w-full" placement="right-start" gutter={12} + openDelay={0} value={} > {node} @@ -446,26 +448,41 @@ export function ModelSelectorPopoverV2(props: { {(item) => ( - { - setStore("active", modelKey(item)) - setTimeout(() => searchRef?.focus()) - }} - onSelect={() => selectModel(item)} + + } > - {item.name} - - {language.t("model.tag.free")} - - - {language.t("model.tag.latest")} - - + { + setStore("active", modelKey(item)) + setTimeout(() => searchRef?.focus()) + }} + onSelect={() => selectModel(item)} + > + {item.name} + + {language.t("model.tag.free")} + + + {language.t("model.tag.latest")} + + + )} diff --git a/packages/app/src/components/model-tooltip.tsx b/packages/app/src/components/model-tooltip.tsx index 53164dae85..7253c06917 100644 --- a/packages/app/src/components/model-tooltip.tsx +++ b/packages/app/src/components/model-tooltip.tsx @@ -1,4 +1,4 @@ -import { Show, type Component } from "solid-js" +import { Show, type Component, type JSX } from "solid-js" import { useLanguage } from "@/context/language" type InputKey = "text" | "image" | "audio" | "video" | "pdf" @@ -23,7 +23,18 @@ type ModelInfo = { } } -export const ModelTooltip: Component<{ model: ModelInfo; latest?: boolean; free?: boolean }> = (props) => { +function ModelTooltipRow(props: { name: JSX.Element; value: JSX.Element }) { + return ( +
+ {props.name} + {props.value} +
+ ) +} + +export const ModelTooltip: Component<{ model: ModelInfo; latest?: boolean; free?: boolean; v2?: boolean }> = ( + props, +) => { const language = useLanguage() const sourceName = (model: ModelInfo) => { const value = `${model.id} ${model.name}`.toLowerCase() @@ -51,6 +62,13 @@ export const ModelTooltip: Component<{ model: ModelInfo; latest?: boolean; free? const suffix = tags.length ? ` (${tags.join(", ")})` : "" return `${sourceName(props.model)} ${props.model.name}${suffix}` } + const name = () => { + const tags: Array = [] + if (props.latest) tags.push(language.t("model.tag.latest")) + if (props.free) tags.push(language.t("model.tag.free")) + const suffix = tags.length ? ` (${tags.join(", ")})` : "" + return `${props.model.name}${suffix}` + } const inputs = () => { if (props.model.capabilities) { const input = props.model.capabilities.input @@ -73,6 +91,21 @@ export const ModelTooltip: Component<{ model: ModelInfo; latest?: boolean; free? : language.t("model.tooltip.reasoning.none") } const context = () => language.t("model.tooltip.context", { limit: props.model.limit.context.toLocaleString() }) + const contextLimit = () => props.model.limit.context.toLocaleString(language.intl()) + + if (props.v2) { + return ( +
+ + + + {(value) => } + + + +
+ ) + } return (
diff --git a/packages/app/src/components/prompt-input.stories.tsx b/packages/app/src/components/prompt-input.stories.tsx index 362a741401..272079e106 100644 --- a/packages/app/src/components/prompt-input.stories.tsx +++ b/packages/app/src/components/prompt-input.stories.tsx @@ -1,8 +1,6 @@ // @ts-nocheck import { createStore } from "solid-js/store" -import type { Todo } from "@opencode-ai/sdk/v2" import { createPromptState } from "@/context/prompt" -import { SessionComposerRegion, createSessionComposerRegionController } from "@/pages/session/composer" import { createPromptInputHistory, PromptInput } from "./prompt-input" function createPromptInputStoryRuntime() { @@ -104,94 +102,6 @@ function PromptInputExample() { ) } -const todos: Todo[] = [ - { id: "todo-1", content: "Inspect the session composer animation", status: "completed" }, - { id: "todo-2", content: "Keep the dock settled on initial render", status: "in_progress" }, - { id: "todo-3", content: "Verify session navigation behavior", status: "pending" }, -] - -function PromptInputWithOpenDock() { - const input = createPromptInputStoryRuntime() - const [controls, setControls] = createStore({ - agent: "build", - activeTab: undefined as string | undefined, - todoCollapsed: false, - }) - const inputControls = { - agents: { - available: [], - options: ["build"], - get current() { - return controls.agent - }, - loading: false, - visible: true, - select: (agent?: string) => setControls("agent", agent ?? "build"), - }, - model: { - selection: { - current: () => ({ id: "claude-3-7-sonnet", name: "Claude 3.7 Sonnet", provider: { id: "anthropic" } }), - variant: { list: () => [], current: () => undefined, set: () => {} }, - }, - paid: true, - loading: false, - }, - session: { - id: "story-session", - tabs: { - active: () => controls.activeTab, - all: () => [], - open: () => {}, - setActive: (tab: string) => setControls("activeTab", tab), - }, - reviewPanel: { opened: () => false, open: () => {} }, - }, - newLayoutDesigns: true, - } - const state = { - blocked: () => false, - questionRequest: () => undefined, - permissionRequest: () => undefined, - permissionResponding: () => false, - decide: () => {}, - todos: () => todos, - dock: () => true, - closing: () => false, - opening: () => false, - } - return ( - "story-session", - sessionID: () => "story-session", - prompt: input.state, - ready: () => true, - centered: () => false, - todo: { - collapsed: () => controls.todoCollapsed, - onToggle: () => setControls("todoCollapsed", (collapsed) => !collapsed), - }, - followup: () => undefined, - revert: () => undefined, - onResponseSubmit: () => {}, - openParent: () => {}, - setPromptRef: () => {}, - setDockRef: () => {}, - })} - promptInput={ - {}} - newSessionWorktree="" - onNewSessionWorktreeReset={() => {}} - /> - } - /> - ) -} - export default { title: "App/PromptInput", id: "app-prompt-input", @@ -206,12 +116,3 @@ export const Basic = {
), } - -export const DockAlreadyOpen = { - render: () => ( -
-

Prompt Input with open Todo dock

- -
- ), -} diff --git a/packages/app/src/components/prompt-input/submit.ts b/packages/app/src/components/prompt-input/submit.ts index 05d978a947..cba1e4c885 100644 --- a/packages/app/src/components/prompt-input/submit.ts +++ b/packages/app/src/components/prompt-input/submit.ts @@ -221,8 +221,6 @@ export function createPromptSubmit(input: PromptSubmitInput) { const sessionID = params.id if (!sessionID) return Promise.resolve() - serverSync().session.set("todo", sessionID, []) - input.onAbort?.() const key = pendingKey(sessionID) diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx index cbbf33d2b1..c424a62a89 100644 --- a/packages/app/src/components/settings-general.tsx +++ b/packages/app/src/components/settings-general.tsx @@ -440,11 +440,6 @@ export const SettingsGeneral: Component = () => { value={(o) => o.value} label={(o) => o.label} onSelect={(option) => option && theme.setColorScheme(option.value)} - onHighlight={(option) => { - if (!option) return - theme.previewColorScheme(option.value) - return () => theme.cancelPreview() - }} variant="secondary" size="small" triggerVariant="settings" @@ -471,11 +466,6 @@ export const SettingsGeneral: Component = () => { if (!option) return theme.setTheme(option.id) }} - onHighlight={(option) => { - if (!option) return - theme.previewTheme(option.id) - return () => theme.cancelPreview() - }} variant="secondary" size="small" triggerVariant="settings" diff --git a/packages/app/src/components/settings-v2/general.tsx b/packages/app/src/components/settings-v2/general.tsx index 0dd48a5523..69dfb77fb0 100644 --- a/packages/app/src/components/settings-v2/general.tsx +++ b/packages/app/src/components/settings-v2/general.tsx @@ -422,11 +422,6 @@ export const SettingsGeneralV2: Component<{ value={(o) => o.value} label={(o) => o.label} onSelect={(option) => option && theme.setColorScheme(option.value)} - onHighlight={(option) => { - if (!option) return - theme.previewColorScheme(option.value) - return () => theme.cancelPreview() - }} /> @@ -454,11 +449,6 @@ export const SettingsGeneralV2: Component<{ if (!option) return theme.setTheme(option.id) }} - onHighlight={(option) => { - if (!option) return - theme.previewTheme(option.id) - return () => theme.cancelPreview() - }} /> diff --git a/packages/app/src/components/titlebar-tab-nav.tsx b/packages/app/src/components/titlebar-tab-nav.tsx index 7f064932bc..a397046f9b 100644 --- a/packages/app/src/components/titlebar-tab-nav.tsx +++ b/packages/app/src/components/titlebar-tab-nav.tsx @@ -246,18 +246,23 @@ export function TabNavItem(props: { }} class="flex h-full min-w-0 flex-1 flex-row items-center gap-1.5 text-[13px] font-medium text-v2-text-text-faint group-data-[active='true']:text-v2-text-text-base group-data-[editing='true']:text-v2-text-text-base [-webkit-user-drag:none]" > - - {(session) => ( - + + - )} - + )} + + { titleEl = el diff --git a/packages/app/src/components/titlebar-tab-strip.tsx b/packages/app/src/components/titlebar-tab-strip.tsx index 6705ac1919..7ef53324cd 100644 --- a/packages/app/src/components/titlebar-tab-strip.tsx +++ b/packages/app/src/components/titlebar-tab-strip.tsx @@ -40,6 +40,7 @@ function SessionTabSlot(props: { let ref!: HTMLDivElement const sdk = createMemo(() => props.serverCtx()?.sdk ?? null) const cachedSession = createMemo(() => props.serverCtx()?.sync.session.peek(props.tab.sessionId)) + const persisted = createMemo(() => tabs.info[props.id]) const [loadedSession] = createResource( () => { const ctx = props.serverCtx() @@ -71,8 +72,10 @@ function SessionTabSlot(props: { createEffect(() => { const value = session() + if (!value) return + tabs.rememberSessionInfo(props.tab, value) const current = sdk() - if (!value || !current) return + if (!current) return createTabPromptState(tabs, props.tab, current.scope, { dir: base64Encode(value.directory), id: value.id, @@ -86,7 +89,7 @@ function SessionTabSlot(props: { data-tab-key={props.id} data-active={props.active()} class="relative flex w-56 min-w-7 max-w-56 flex-shrink" - classList={{ hidden: !session() && !missingSession() }} + classList={{ hidden: !session() && !missingSession() && !persisted()?.title }} > { @@ -95,7 +98,7 @@ function SessionTabSlot(props: { href={tabHref(props.tab)} server={props.tab.server} session={session} - fallbackTitle={missingSession() ? language.t("session.tab.unknown") : undefined} + fallbackTitle={persisted()?.title ?? (missingSession() ? language.t("session.tab.unknown") : undefined)} onTitleChange={(title) => { const value = session() const ctx = props.serverCtx() diff --git a/packages/app/src/context/command.test.ts b/packages/app/src/context/command.test.ts index 2b956287c5..4297dd89bd 100644 --- a/packages/app/src/context/command.test.ts +++ b/packages/app/src/context/command.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test" -import { upsertCommandRegistration } from "./command" +import { resolveKeybindOption, upsertCommandRegistration } from "./command" describe("upsertCommandRegistration", () => { test("replaces keyed registrations", () => { @@ -23,3 +23,19 @@ describe("upsertCommandRegistration", () => { expect(next[1]?.options).toBe(one) }) }) + +describe("resolveKeybindOption", () => { + test("prefers a matching contextual command over the global fallback", () => { + const fallback = { id: "tab.close", title: "Close tab" } + const contextual = { id: "terminal.close", title: "Close terminal", when: () => true } + + expect(resolveKeybindOption([fallback, contextual], new KeyboardEvent("keydown"))).toBe(contextual) + }) + + test("uses the global fallback outside the command context", () => { + const fallback = { id: "tab.close", title: "Close tab" } + const contextual = { id: "terminal.close", title: "Close terminal", when: () => false } + + expect(resolveKeybindOption([fallback, contextual], new KeyboardEvent("keydown"))).toBe(fallback) + }) +}) diff --git a/packages/app/src/context/command.tsx b/packages/app/src/context/command.tsx index 0c935307ad..467a1115b5 100644 --- a/packages/app/src/context/command.tsx +++ b/packages/app/src/context/command.tsx @@ -82,10 +82,15 @@ export interface CommandOption { suggested?: boolean disabled?: boolean hidden?: boolean + when?: (event: KeyboardEvent) => boolean onSelect?: (source?: "palette" | "keybind" | "slash") => void onHighlight?: () => (() => void) | void } +export function resolveKeybindOption(candidates: CommandOption[] | undefined, event: KeyboardEvent) { + return candidates?.find((option) => option.when?.(event)) ?? candidates?.find((option) => !option.when) +} + type CommandSource = "palette" | "keybind" | "slash" export type CommandCatalogItem = { @@ -334,7 +339,7 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex }) const keymap = createMemo(() => { - const map = new Map() + const map = new Map() for (const option of options()) { if (option.id.startsWith(SUGGESTED_PREFIX)) continue if (option.disabled) continue @@ -344,8 +349,12 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex for (const kb of keybinds) { if (!kb.key) continue const sig = signature(kb.key, kb.ctrl, kb.meta, kb.shift, kb.alt) - if (map.has(sig)) continue - map.set(sig, option) + const existing = map.get(sig) + if (existing) { + existing.push(option) + continue + } + map.set(sig, [option]) } } return map @@ -374,7 +383,7 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex const sig = signatureFromEvent(event) const isPalette = palette().has(sig) - const option = keymap().get(sig) + const option = resolveKeybindOption(keymap().get(sig), event) const modified = event.ctrlKey || event.metaKey || event.altKey const isTab = event.key === "Tab" @@ -383,17 +392,19 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex if (isPalette) { event.preventDefault() + event.stopPropagation() showPalette() return } if (!option) return event.preventDefault() + event.stopPropagation() option.onSelect?.("keybind") } onMount(() => { - makeEventListener(document, "keydown", handleKeyDown) + makeEventListener(document, "keydown", handleKeyDown, { capture: true }) }) function register(cb: () => CommandOption[]): void diff --git a/packages/app/src/context/directory-sync.ts b/packages/app/src/context/directory-sync.ts index 68e6b19cef..7ccd6e975e 100644 --- a/packages/app/src/context/directory-sync.ts +++ b/packages/app/src/context/directory-sync.ts @@ -11,7 +11,6 @@ const sessionFields = new Set([ "session_status", "session_working", "session_diff", - "todo", "permission", "question", "message", @@ -115,7 +114,6 @@ export const createDirSyncContext = ( index(sessionID) }, diff: serverSync.session.diff, - todo: serverSync.session.todo, history: serverSync.session.history, evict(sessionID: string) { serverSync.session.evict(sessionID) diff --git a/packages/app/src/context/global-sync/bootstrap.test.ts b/packages/app/src/context/global-sync/bootstrap.test.ts index 40735fb822..872f0929c8 100644 --- a/packages/app/src/context/global-sync/bootstrap.test.ts +++ b/packages/app/src/context/global-sync/bootstrap.test.ts @@ -30,7 +30,6 @@ function directoryState() { return this.session_status[id]?.type !== "idle" }, session_diff: {}, - todo: {}, permission: {}, question: {}, mcp_ready: true, diff --git a/packages/app/src/context/global-sync/child-store.ts b/packages/app/src/context/global-sync/child-store.ts index 53b9536182..66e40f66ec 100644 --- a/packages/app/src/context/global-sync/child-store.ts +++ b/packages/app/src/context/global-sync/child-store.ts @@ -223,7 +223,6 @@ export function createChildStoreManager(input: { return (type ?? "idle") !== "idle" }, session_diff: {}, - todo: {}, permission: {}, question: {}, get mcp_ready() { diff --git a/packages/app/src/context/global-sync/event-reducer.test.ts b/packages/app/src/context/global-sync/event-reducer.test.ts index 2811e6e3c6..8e2113709b 100644 --- a/packages/app/src/context/global-sync/event-reducer.test.ts +++ b/packages/app/src/context/global-sync/event-reducer.test.ts @@ -72,7 +72,6 @@ const baseState = (input: Partial = {}) => sessionTotal: 0, session_status: {}, session_diff: {}, - todo: {}, permission: {}, question: {}, mcp: {}, @@ -216,7 +215,6 @@ describe("applyDirectoryEvent", () => { message: { ses_1: [message] }, part: { [message.id]: [textPart("prt_1", "ses_1", message.id)] }, session_diff: { ses_1: [] }, - todo: { ses_1: [] }, permission: { ses_1: [] }, question: { ses_1: [] }, session_status: { ses_1: { type: "busy" } }, @@ -237,7 +235,6 @@ describe("applyDirectoryEvent", () => { expect(store.message.ses_1).toBeUndefined() expect(store.part[message.id]).toBeUndefined() expect(store.session_diff.ses_1).toBeUndefined() - expect(store.todo.ses_1).toBeUndefined() expect(store.permission.ses_1).toBeUndefined() expect(store.question.ses_1).toBeUndefined() expect(store.session_status.ses_1).toBeUndefined() @@ -262,7 +259,6 @@ describe("applyDirectoryEvent", () => { message: { [item.info.id]: [message] }, part: { [message.id]: [textPart("prt_1", item.info.id, message.id)] }, session_diff: { [item.info.id]: [] }, - todo: { [item.info.id]: [] }, permission: { [item.info.id]: [] }, question: { [item.info.id]: [] }, session_status: { [item.info.id]: { type: "busy" } }, @@ -283,7 +279,6 @@ describe("applyDirectoryEvent", () => { expect(store.message[item.info.id]).toBeUndefined() expect(store.part[message.id]).toBeUndefined() expect(store.session_diff[item.info.id]).toBeUndefined() - expect(store.todo[item.info.id]).toBeUndefined() expect(store.permission[item.info.id]).toBeUndefined() expect(store.question[item.info.id]).toBeUndefined() expect(store.session_status[item.info.id]).toBeUndefined() @@ -294,7 +289,6 @@ describe("applyDirectoryEvent", () => { const dropped = rootSession({ id: "ses_b" }) const kept = rootSession({ id: "ses_a" }) const message = userMessage("msg_1", dropped.id) - const todos: string[] = [] const [store, setStore] = createStore( baseState({ limit: 1, @@ -302,7 +296,6 @@ describe("applyDirectoryEvent", () => { message: { [dropped.id]: [message] }, part: { [message.id]: [textPart("prt_1", dropped.id, message.id)] }, session_diff: { [dropped.id]: [] }, - todo: { [dropped.id]: [] }, permission: { [dropped.id]: [] }, question: { [dropped.id]: [] }, session_status: { [dropped.id]: { type: "busy" } }, @@ -316,21 +309,15 @@ describe("applyDirectoryEvent", () => { push() {}, directory: "/tmp", loadLsp() {}, - setSessionTodo(sessionID, value) { - if (value !== undefined) return - todos.push(sessionID) - }, }) expect(store.session.map((x) => x.id)).toEqual([kept.id]) expect(store.message[dropped.id]).toBeUndefined() expect(store.part[message.id]).toBeUndefined() expect(store.session_diff[dropped.id]).toBeUndefined() - expect(store.todo[dropped.id]).toBeUndefined() expect(store.permission[dropped.id]).toBeUndefined() expect(store.question[dropped.id]).toBeUndefined() expect(store.session_status[dropped.id]).toBeUndefined() - expect(todos).toEqual([dropped.id]) }) test("cleanupDroppedSessionCaches clears part-only orphan state", () => { diff --git a/packages/app/src/context/global-sync/event-reducer.ts b/packages/app/src/context/global-sync/event-reducer.ts index 15d125df39..935fc14e33 100644 --- a/packages/app/src/context/global-sync/event-reducer.ts +++ b/packages/app/src/context/global-sync/event-reducer.ts @@ -8,8 +8,7 @@ import type { QuestionRequest, Session, SessionStatus, - SnapshotFileDiff, - Todo, + FileDiffInfo, } from "@opencode-ai/sdk/v2/client" import type { State, VcsCache } from "./types" import { trimSessions } from "./session-trim" @@ -19,7 +18,6 @@ import { diffs as list, message as clean } from "@/utils/diffs" const SKIP_PARTS = new Set(["patch", "step-start", "step-finish"]) const SESSION_CONTENT_EVENTS = new Set([ "session.diff", - "todo.updated", "session.status", "message.updated", "message.removed", @@ -62,13 +60,8 @@ export function applyGlobalEvent(input: { ) } -function cleanupSessionCaches( - setStore: SetStoreFunction, - sessionID: string, - setSessionTodo?: (sessionID: string, todos: Todo[] | undefined) => void, -) { +function cleanupSessionCaches(setStore: SetStoreFunction, sessionID: string) { if (!sessionID) return - setSessionTodo?.(sessionID, undefined) setStore( produce((draft) => { dropSessionCaches(draft, [sessionID]) @@ -76,17 +69,11 @@ function cleanupSessionCaches( ) } -export function cleanupDroppedSessionCaches( - store: Store, - setStore: SetStoreFunction, - next: Session[], - setSessionTodo?: (sessionID: string, todos: Todo[] | undefined) => void, -) { +export function cleanupDroppedSessionCaches(store: Store, setStore: SetStoreFunction, next: Session[]) { const keep = new Set(next.map((item) => item.id)) const stale = [ ...Object.keys(store.message), ...Object.keys(store.session_diff), - ...Object.keys(store.todo), ...Object.keys(store.permission), ...Object.keys(store.question), ...Object.keys(store.session_status), @@ -95,9 +82,6 @@ export function cleanupDroppedSessionCaches( .filter((sessionID): sessionID is string => !!sessionID), ].filter((sessionID, index, list) => !keep.has(sessionID) && list.indexOf(sessionID) === index) if (stale.length === 0) return - for (const sessionID of stale) { - setSessionTodo?.(sessionID, undefined) - } setStore( produce((draft) => { dropSessionCaches(draft, stale) @@ -114,7 +98,6 @@ export function applyDirectoryEvent(input: { loadLsp: () => void loadReferences?: () => void vcsCache?: VcsCache - setSessionTodo?: (sessionID: string, todos: Todo[] | undefined) => void retainedLimit?: number sessionContent?: boolean permission?: State["permission"] @@ -138,7 +121,7 @@ export function applyDirectoryEvent(input: { next.splice(result.index, 0, info) const trimmed = trimSessions(next, { limit, permission: input.permission ?? input.store.permission }) input.setStore("session", reconcile(trimmed, { key: "id" })) - cleanupDroppedSessionCaches(input.store, input.setStore, trimmed, input.setSessionTodo) + cleanupDroppedSessionCaches(input.store, input.setStore, trimmed) if (!info.parentID) input.setStore("sessionTotal", (value) => value + 1) break } @@ -155,7 +138,7 @@ export function applyDirectoryEvent(input: { }), ) } - cleanupSessionCaches(input.setStore, info.id, input.setSessionTodo) + cleanupSessionCaches(input.setStore, info.id) if (info.parentID) break input.setStore("sessionTotal", (value) => Math.max(0, value - 1)) break @@ -168,7 +151,7 @@ export function applyDirectoryEvent(input: { next.splice(result.index, 0, info) const trimmed = trimSessions(next, { limit, permission: input.permission ?? input.store.permission }) input.setStore("session", reconcile(trimmed, { key: "id" })) - cleanupDroppedSessionCaches(input.store, input.setStore, trimmed, input.setSessionTodo) + cleanupDroppedSessionCaches(input.store, input.setStore, trimmed) break } case "session.deleted": { @@ -182,22 +165,16 @@ export function applyDirectoryEvent(input: { }), ) } - cleanupSessionCaches(input.setStore, info.id, input.setSessionTodo) + cleanupSessionCaches(input.setStore, info.id) if (info.parentID) break input.setStore("sessionTotal", (value) => Math.max(0, value - 1)) break } case "session.diff": { - const props = event.properties as { sessionID: string; diff: SnapshotFileDiff[] } + const props = event.properties as { sessionID: string; diff: FileDiffInfo[] } input.setStore("session_diff", props.sessionID, reconcile(list(props.diff), { key: "file" })) break } - case "todo.updated": { - const props = event.properties as { sessionID: string; todos: Todo[] } - input.setStore("todo", props.sessionID, reconcile(props.todos, { key: "id" })) - input.setSessionTodo?.(props.sessionID, props.todos) - break - } case "session.status": { const props = event.properties as { sessionID: string; status: SessionStatus } input.setStore("session_status", props.sessionID, reconcile(props.status)) diff --git a/packages/app/src/context/global-sync/session-cache.test.ts b/packages/app/src/context/global-sync/session-cache.test.ts index 4b2be505ea..41034186e6 100644 --- a/packages/app/src/context/global-sync/session-cache.test.ts +++ b/packages/app/src/context/global-sync/session-cache.test.ts @@ -5,8 +5,7 @@ import type { PermissionRequest, QuestionRequest, SessionStatus, - SnapshotFileDiff, - Todo, + FileDiffInfo, } from "@opencode-ai/sdk/v2/client" import { dropSessionCaches, pickSessionCacheEvictions } from "./session-cache" @@ -33,8 +32,7 @@ describe("app session cache", () => { test("dropSessionCaches clears orphaned parts without message rows", () => { const store: { session_status: Record - session_diff: Record - todo: Record + session_diff: Record message: Record part: Record permission: Record @@ -43,7 +41,6 @@ describe("app session cache", () => { } = { session_status: { ses_1: { type: "busy" } as SessionStatus }, session_diff: { ses_1: [] }, - todo: { ses_1: [] as Todo[] }, message: {}, part: { msg_1: [part("prt_1", "ses_1", "msg_1")] }, permission: { ses_1: [] as PermissionRequest[] }, @@ -56,7 +53,6 @@ describe("app session cache", () => { expect(store.message.ses_1).toBeUndefined() expect(store.part.msg_1).toBeUndefined() expect(store.part_text_accum_delta.prt_1).toBeUndefined() - expect(store.todo.ses_1).toBeUndefined() expect(store.session_diff.ses_1).toBeUndefined() expect(store.session_status.ses_1).toBeUndefined() expect(store.permission.ses_1).toBeUndefined() @@ -67,8 +63,7 @@ describe("app session cache", () => { const m = msg("msg_1", "ses_1") const store: { session_status: Record - session_diff: Record - todo: Record + session_diff: Record message: Record part: Record permission: Record @@ -77,7 +72,6 @@ describe("app session cache", () => { } = { session_status: {}, session_diff: {}, - todo: {}, message: { ses_1: [m] }, part: { [m.id]: [part("prt_1", "ses_1", m.id)] }, permission: {}, diff --git a/packages/app/src/context/global-sync/session-cache.ts b/packages/app/src/context/global-sync/session-cache.ts index 05cdc84643..6f2c3dc540 100644 --- a/packages/app/src/context/global-sync/session-cache.ts +++ b/packages/app/src/context/global-sync/session-cache.ts @@ -4,16 +4,14 @@ import type { PermissionRequest, QuestionRequest, SessionStatus, - SnapshotFileDiff, - Todo, + FileDiffInfo, } from "@opencode-ai/sdk/v2/client" export const SESSION_CACHE_LIMIT = 40 type SessionCache = { session_status: Record - session_diff: Record - todo: Record + session_diff: Record message: Record part: Record permission: Record @@ -36,7 +34,6 @@ export function dropSessionCaches(store: SessionCache, sessionIDs: Iterable s().todoCollapsed ?? false, - set(collapsed: boolean) { - const session = key() - const current = store.sessionView[session] - if (!current) { - setStore("sessionView", session, { scroll: {}, todoCollapsed: collapsed }) - } else { - setStore("sessionView", session, "todoCollapsed", collapsed) - } - }, - }, terminal: { opened: terminalOpened, open() { diff --git a/packages/app/src/context/server-session.test.ts b/packages/app/src/context/server-session.test.ts index 46a0dc8266..fb4443a3ef 100644 --- a/packages/app/src/context/server-session.test.ts +++ b/packages/app/src/context/server-session.test.ts @@ -151,7 +151,6 @@ function setup(sessions: Record) { return response() }, diff: async () => ({ data: [] }), - todo: async () => ({ data: [] }), }, } as unknown as OpencodeClient return { get, messages, store: createServerSession(client) } diff --git a/packages/app/src/context/server-session.ts b/packages/app/src/context/server-session.ts index 6898cc2304..12c3d8abb8 100644 --- a/packages/app/src/context/server-session.ts +++ b/packages/app/src/context/server-session.ts @@ -8,8 +8,7 @@ import type { QuestionRequest, Session, SessionStatus, - SnapshotFileDiff, - Todo, + FileDiffInfo, } from "@opencode-ai/sdk/v2/client" import { batch } from "solid-js" import { createStore, produce, reconcile } from "solid-js/store" @@ -139,8 +138,7 @@ export function createServerSession(client: OpencodeClient, options?: { retry?: const [data, setData] = createStore({ info: {} as Record, session_status: {} as Record, - session_diff: {} as Record, - todo: {} as Record, + session_diff: {} as Record, permission: {} as Record, question: {} as Record, message: {} as Record, @@ -153,7 +151,6 @@ export function createServerSession(client: OpencodeClient, options?: { retry?: const requests = new Map>() const inflight = new Map>() const inflightDiff = new Map>() - const inflightTodo = new Map>() const optimistic = new Map>() const messageLoads = new Map() const pendingParts = new Map>>() @@ -199,7 +196,6 @@ export function createServerSession(client: OpencodeClient, options?: { retry?: ...requests.keys(), ...inflight.keys(), ...inflightDiff.keys(), - ...inflightTodo.keys(), ...messageLoads.keys(), ...optimistic.keys(), ...Object.entries(data.permission) @@ -254,8 +250,7 @@ export function createServerSession(client: OpencodeClient, options?: { retry?: !requests.has(sessionID) && !messageLoads.has(sessionID) && !inflight.has(sessionID) && - !inflightDiff.has(sessionID) && - !inflightTodo.has(sessionID) + !inflightDiff.has(sessionID) ) generations.delete(sessionID) } @@ -418,7 +413,6 @@ export function createServerSession(client: OpencodeClient, options?: { retry?: requests.delete(sessionID) inflight.delete(sessionID) inflightDiff.delete(sessionID) - inflightTodo.delete(sessionID) messageLoads.delete(sessionID) pendingParts.delete(sessionID) orphanParts.delete(sessionID) @@ -448,7 +442,6 @@ export function createServerSession(client: OpencodeClient, options?: { retry?: ...requests.keys(), ...inflight.keys(), ...inflightDiff.keys(), - ...inflightTodo.keys(), ...messageLoads.keys(), ...optimistic.keys(), ...Object.entries(data.permission) @@ -769,15 +762,10 @@ export function createServerSession(client: OpencodeClient, options?: { retry?: return } case "session.diff": { - const props = event.properties as { sessionID: string; diff: SnapshotFileDiff[] } + const props = event.properties as { sessionID: string; diff: FileDiffInfo[] } setData("session_diff", props.sessionID, reconcile(cleanDiffs(props.diff), { key: "file" })) return } - case "todo.updated": { - const props = event.properties as { sessionID: string; todos: Todo[] } - setData("todo", props.sessionID, reconcile(props.todos, { key: "id" })) - return - } case "session.status": { const props = event.properties as { sessionID: string; status: SessionStatus } setData("session_status", props.sessionID, reconcile(props.status)) @@ -1140,17 +1128,6 @@ export function createServerSession(client: OpencodeClient, options?: { retry?: }) }) }, - todo(sessionID: string, options?: { force?: boolean }) { - touch(sessionID) - if (data.todo[sessionID] !== undefined && !options?.force) return Promise.resolve() - return runInflight(inflightTodo, sessionID, () => { - const active = generation(sessionID) - return retry(() => client.session.todo({ sessionID })).then((result) => { - if (generations.get(sessionID) !== active) return - setData("todo", sessionID, reconcile(result.data ?? [], { key: "id" })) - }) - }) - }, history: { more: (sessionID: string) => data.message[sessionID] !== undefined && diff --git a/packages/app/src/context/tabs.tsx b/packages/app/src/context/tabs.tsx index 11155d2ca4..47ed77e781 100644 --- a/packages/app/src/context/tabs.tsx +++ b/packages/app/src/context/tabs.tsx @@ -28,6 +28,11 @@ export type DraftTab = { export type Tab = SessionTab | DraftTab +export type TabInfo = { + title?: string + directory?: string +} + type RecentTab = { key?: string } @@ -64,6 +69,7 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({ createStore([]), ) const [recent, setRecent, , recentReady] = persisted(Persist.window("tabs.recent"), createStore({})) + const [info, setInfo] = persisted(Persist.window("tabs.info"), createStore>({})) const [closed, setClosed, , closedReady] = persisted(Persist.window("tabs.closed"), createStore([])) const params = useParams() @@ -102,6 +108,15 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({ for (const key of draftPersistedKeys()) removePersisted(Persist.draft(draftID, key), platform) } + const removeInfo = (key: string) => { + if (!info[key]) return + setInfo( + produce((draft) => { + delete draft[key] + }), + ) + } + onCleanup(memory.dispose) createEffect(() => { @@ -110,11 +125,19 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({ const next = store.filter((tab) => servers.has(tab.server)) if (next.length !== store.length) { for (const tab of store) { - if (!servers.has(tab.server)) memory.remove(tabKey(tab)) + if (!servers.has(tab.server)) { + const key = tabKey(tab) + memory.remove(key) + removeInfo(key) + } } setStore(() => next) } if (recent.key && !next.some((tab) => tabKey(tab) === recent.key)) setRecentKey(undefined) + const keys = new Set(next.map(tabKey)) + for (const key of Object.keys(info)) { + if (!keys.has(key)) removeInfo(key) + } }) createEffect(() => { @@ -150,6 +173,7 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({ if (nextTab) navigateTab(nextTab) }).finally(() => closing.delete(key)) memory.remove(key) + removeInfo(key) if (draftID) removeDraftPersisted(draftID) } @@ -264,6 +288,7 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({ const removed = store.filter((tab) => tab.server === key).map(tabKey) setStore((tabs) => tabs.filter((tab) => tab.server !== key)) for (const key of removed) memory.remove(key) + for (const key of removed) removeInfo(key) if (recent.key && removed.includes(recent.key)) setRecentKey(undefined) for (const draftID of drafts) removeDraftPersisted(draftID) if (server.key === key) navigate("/") @@ -318,6 +343,14 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({ if (recent.key && removed.includes(recent.key)) setRecentKey(undefined) }) for (const key of removed) memory.remove(key) + for (const key of removed) removeInfo(key) + }, + rememberSessionInfo(tab: SessionTab, session: Session) { + const key = tabKey(tab) + const next = { title: session.title, directory: session.directory } + const current = info[key] + if (current?.title === next.title && current.directory === next.directory) return + setInfo(key, next) }, select: navigateTab, remember(tab: Tab) { @@ -342,6 +375,6 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({ }, } - return { ...actions, store, ready, recentReady } + return { ...actions, store, info, ready, recentReady } }, }) diff --git a/packages/app/src/i18n/ar.ts b/packages/app/src/i18n/ar.ts index a5174a5900..b824354401 100644 --- a/packages/app/src/i18n/ar.ts +++ b/packages/app/src/i18n/ar.ts @@ -21,6 +21,9 @@ export const dict = { "theme.scheme.dark": "داكن", "command.sidebar.toggle": "تبديل الشريط الجانبي", "command.project.open": "فتح مشروع", + "command.project.previous": "المشروع السابق", + "command.project.next": "المشروع التالي", + "command.project.index": "التبديل إلى المشروع {{index}}", "command.provider.connect": "اتصال بموفر", "command.server.switch": "تبديل الخادم", "command.settings.open": "فتح الإعدادات", @@ -39,6 +42,7 @@ export const dict = { "command.session.new": "جلسة جديدة", "command.file.open": "فتح ملف", "command.tab.close": "إغلاق علامة التبويب", + "command.tab.reopenClosed": "إعادة فتح علامة التبويب المغلقة", "command.context.addSelection": "إضافة التحديد إلى السياق", "command.context.addSelection.description": "إضافة الأسطر المحددة من الملف الحالي", "command.input.focus": "التركيز على حقل الإدخال", @@ -193,6 +197,11 @@ export const dict = { "model.input.video": "فيديو", "model.input.pdf": "pdf", "model.tooltip.allows": "يسمح: {{inputs}}", + "model.tooltip.context.label": "السياق", + "model.tooltip.inputs": "المدخلات", + "model.tooltip.model": "النموذج", + "model.tooltip.provider": "الموفر", + "model.tooltip.reasoning": "الاستنتاج", "model.tooltip.reasoning.allowed": "يسمح بالاستنتاج", "model.tooltip.reasoning.none": "بدون استنتاج", "model.tooltip.context": "حد السياق {{limit}}", @@ -202,6 +211,7 @@ export const dict = { "common.loading": "جارٍ التحميل", "common.loading.ellipsis": "...", "common.cancel": "إلغاء", + "common.clear": "مسح", "common.connect": "اتصال", "common.disconnect": "قطع الاتصال", "common.continue": "إرسال", @@ -218,6 +228,8 @@ export const dict = { "prompt.mode.shell": "Shell", "prompt.mode.normal": "Prompt", "prompt.mode.shell.exit": "esc للخروج", + "session.child.promptDisabled": "لا يمكن إرسال موجّهات إلى جلسات الوكلاء الفرعيين.", + "session.child.backToParent": "العودة إلى الجلسة الرئيسية.", "prompt.example.1": "إصلاح TODO في قاعدة التعليمات البرمجية", "prompt.example.2": "ما هو المكدس التقني لهذا المشروع؟", "prompt.example.3": "إصلاح الاختبارات المعطلة", @@ -314,6 +326,74 @@ export const dict = { "dialog.server.menu.delete": "حذف", "dialog.server.current": "الخادم الحالي", "dialog.server.status.default": "افتراضي", + "wsl.server.add": "إضافة خادم WSL", + "wsl.server.addShort": "إضافة WSL", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "خادم WSL", + "wsl.server.retryStart": "إعادة محاولة التشغيل", + "wsl.server.updating": "جارٍ التحديث...", + "wsl.onboarding.step.distro": "اختر توزيعة", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "جارٍ التحقق من WSL...", + "wsl.onboarding.restartRequired": "يحتاج Windows إلى إعادة التشغيل لإكمال تثبيت WSL.", + "wsl.onboarding.ready": "WSL جاهز.", + "wsl.onboarding.required": "يلزم WSL للمتابعة.", + "wsl.onboarding.checkingDistros": "جارٍ التحقق من التوزيعات...", + "wsl.onboarding.installingDistro": "جارٍ تثبيت {{distro}}...", + "wsl.onboarding.checkingDistro": "جارٍ التحقق من {{distro}}...", + "wsl.onboarding.listingDistros": "جارٍ سرد التوزيعات...", + "wsl.onboarding.distroReady": "{{distro}} جاهزة.", + "wsl.onboarding.distroNotInstalled": "لم يتم تثبيت {{distro}} بعد.", + "wsl.onboarding.openDistroOnce": "افتح {{distro}} مرة واحدة لإكمال الإعداد.", + "wsl.onboarding.finishingDistro": "جارٍ إكمال إعداد {{distro}}.", + "wsl.onboarding.pickDistro": "اختر توزيعة أو ثبّت واحدة أدناه.", + "wsl.onboarding.checkingOpencode": "جارٍ التحقق من OpenCode...", + "wsl.onboarding.checkingOpencodeIn": "جارٍ التحقق من OpenCode في {{distro}}...", + "wsl.onboarding.updatingOpencode": "جارٍ تحديث OpenCode...", + "wsl.onboarding.updatingOpencodeIn": "جارٍ تحديث OpenCode في {{distro}}...", + "wsl.onboarding.updateOpencodeIn": "حدّث OpenCode في {{distro}}.", + "wsl.onboarding.updateOpencode": "تحديث OpenCode", + "wsl.onboarding.opencodeReadyIn": "OpenCode جاهز في {{distro}}.", + "wsl.onboarding.opencodeReady": "OpenCode جاهز.", + "wsl.onboarding.installOpencodeIn": "ثبّت OpenCode في {{distro}}.", + "wsl.onboarding.installOpencode": "تثبيت OpenCode", + "wsl.onboarding.chooseDistroFirst": "اختر توزيعة أولاً.", + "wsl.onboarding.loadFailed": "فشل تحميل حالة WSL.", + "wsl.onboarding.loading": "جارٍ التحميل...", + "wsl.onboarding.installedDistros": "التوزيعات المثبتة", + "wsl.onboarding.checkAgain": "تحقق مجددًا", + "wsl.onboarding.distroStatus.ready": "جاهزة", + "wsl.onboarding.distroStatus.checking": "جارٍ التحقق...", + "wsl.onboarding.distroStatus.opencodeMissing": "OpenCode غير مثبت", + "wsl.onboarding.distroStatus.missingTools": "bash و curl مفقودان", + "wsl.onboarding.distroStatus.unsupported": "غير مدعومة · استخدم WSL 2", + "wsl.onboarding.needAnotherDistro": "هل تحتاج إلى توزيعة أخرى؟", + "wsl.onboarding.needAnotherDistroHint": "ثبّت توزيعة Linux من كتالوج WSL", + "wsl.onboarding.wslNotInstalled.title": "WSL غير مثبت", + "wsl.onboarding.wslNotInstalled.description": + "يلزم WSL (نظام Windows الفرعي لـ Linux) قبل أن يتمكن OpenCode من إضافة خادم WSL", + "wsl.onboarding.wslUnavailable.title": "WSL غير متاح", + "wsl.onboarding.wslUnavailable.description": "تعذر على OpenCode التحقق من WSL على هذا الجهاز.", + "wsl.onboarding.installWsl": "تثبيت WSL", + "wsl.onboarding.windowsRestartRequired": "أعد تشغيل Windows لإكمال تثبيت WSL، ثم أعد فتح OpenCode.", + "wsl.onboarding.next": "التالي", + "wsl.onboarding.refresh": "تحديث", + "wsl.onboarding.allDistrosAdded": "تمت إضافة جميع التوزيعات المثبتة بالفعل.", + "wsl.onboarding.noDistros": "لم يتم اكتشاف أي توزيعات بعد.", + "wsl.onboarding.install": "تثبيت", + "wsl.onboarding.installing": "جارٍ التثبيت...", + "wsl.onboarding.installDistro": "تثبيت توزيعة", + "wsl.onboarding.searchDistros": "البحث عن توزيعات", + "wsl.onboarding.wsl2Required": "يلزم WSL 2.", + "wsl.onboarding.toolsRequired": "تحتاج هذه التوزيعة إلى bash و curl.", + "wsl.onboarding.openTerminal": "فتح المحطة الطرفية", + "wsl.onboarding.path": "المسار: {{path}}", + "wsl.onboarding.notFound": "غير موجود", + "wsl.onboarding.version": "الإصدار: {{version}}", + "wsl.onboarding.unknown": "غير معروف", + "wsl.onboarding.desktopVersion": "سطح المكتب {{version}}", + "wsl.onboarding.versionMismatch": "لا يتطابق الإصدار المثبت مع إصدار تطبيق سطح المكتب.", + "wsl.onboarding.adding": "جارٍ الإضافة...", "dialog.project.edit.title": "تحرير المشروع", "dialog.project.edit.name": "الاسم", "dialog.project.edit.icon": "أيقونة", @@ -370,6 +450,7 @@ export const dict = { "language.no": "Norsk", "language.br": "Português (Brasil)", "language.bs": "Bosanski", + "language.uk": "Українська", "language.th": "ไทย", "language.tr": "Türkçe", "toast.language.title": "لغة", @@ -406,10 +487,12 @@ export const dict = { "toast.update.action.notYet": "ليس الآن", "error.page.title": "حدث خطأ ما", "error.page.description": "حدث خطأ أثناء تحميل التطبيق.", + "error.page.description.localServerStartup": "حدث خطأ أثناء بدء تشغيل الخادم المحلي.", "error.page.details.label": "تفاصيل الخطأ", "error.page.action.restart": "إعادة تشغيل", "error.page.action.report": "الإبلاغ عن الخطأ", "error.page.action.reported": "تم الإبلاغ عن الخطأ", + "error.page.action.exportLogs": "تصدير السجلات", "error.page.action.checking": "جارٍ التحقق...", "error.page.action.checkUpdates": "التحقق من وجود تحديثات", "error.page.action.updateTo": "تحديث إلى {{version}}", @@ -450,16 +533,38 @@ export const dict = { "home.recentProjects": "المشاريع الحديثة", "home.empty.title": "لا توجد مشاريع حديثة", "home.empty.description": "ابدأ بفتح مشروع محلي", + "home.title": "الرئيسية", + "home.projects": "المشاريع", + "home.project.add": "إضافة مشروع", + "home.recentlyClosed": "المغلقة مؤخرًا", + "home.server.collapse": "طي مشاريع الخادم", + "home.server.expand": "توسيع مشاريع الخادم", + "home.sessions.search.placeholder": "البحث في الجلسات", + "home.sessions.search.placeholder.scoped": "البحث في جلسات {{scope}}", + "home.sessions.search.sessions": "الجلسات", + "home.sessions.search.noResults": "لم يتم العثور على جلسات لـ {{query}}", + "home.sessions.empty": "لا يوجد شيء هنا بعد", + "home.sessions.empty.description": "أنشئ جلسة للبدء", + "home.sessions.group.today": "اليوم", + "home.sessions.group.yesterday": "أمس", + "home.sessions.group.older": "الأقدم", "session.tab.session": "جلسة", "session.tab.review": "مراجعة", "session.tab.context": "سياق", + "session.tab.unknown": "جلسة غير معروفة", "session.panel.reviewAndFiles": "المراجعة والملفات", + "session.error.notFound": "لا يمكن العثور على هذه الجلسة", + "session.error.notFound.description": "يشير هذا التبويب إلى جلسة لم تعد موجودة على هذا الخادم.", + "session.error.notFound.closeTab": "إغلاق علامة التبويب", + "session.error.serverConnection": "تعذر الاتصال بهذا الخادم", "session.review.filesChanged": "تم تغيير {{count}} ملفات", "session.review.change.one": "تغيير", "session.review.change.other": "تغييرات", "session.review.loadingChanges": "جارٍ تحميل التغييرات...", "session.review.empty": "لا توجد تغييرات في هذه الجلسة بعد", "session.review.noChanges": "لا توجد تغييرات", + "session.review.noUncommittedChanges": "لا توجد تغييرات غير مُودَعة بعد", + "session.review.noBranchChanges": "لا توجد تغييرات في الفرع بعد", "session.review.noVcs": "لم يتم اكتشاف نظام التحكم في الإصدار Git، لن يتم عرض التغييرات", "session.review.noSnapshot": "تم تعطيل تتبع اللقطات في التكوين، لذا فإن تغييرات الجلسة غير متوفرة", "session.files.selectToOpen": "اختر ملفًا لفتحه", @@ -472,9 +577,10 @@ export const dict = { "session.messages.loading": "جارٍ تحميل الرسائل...", "session.messages.jumpToLatest": "الانتقال إلى الأحدث", "session.context.addToContext": "إضافة {{selection}} إلى السياق", - "session.todo.title": "المهام", - "session.todo.collapse": "طي", - "session.todo.expand": "توسيع", + "session.question.minimize": "تصغير السؤال", + "session.question.restore": "استعادة السؤال", + "session.question.pending.one": "{{count}} سؤال معلق", + "session.question.pending.other": "الأسئلة المعلقة: {{count}}", "session.followupDock.summary.one": "{{count}} رسالة في الانتظار", "session.followupDock.summary.other": "{{count}} رسائل في الانتظار", "session.followupDock.sendNow": "إرسال الآن", @@ -487,9 +593,16 @@ export const dict = { "session.revertDock.expand": "توسيع الرسائل التي تم التراجع عنها", "session.revertDock.restore": "استعادة الرسالة", "session.new.title": "ابنِ أي شيء", + "session.new.project.new": "مشروع جديد", + "session.new.project.search": "البحث عن المشاريع", + "session.new.project.add": "إضافة مشروع", "session.new.worktree.main": "الفرع الرئيسي", "session.new.worktree.mainWithBranch": "الفرع الرئيسي ({{branch}})", "session.new.worktree.create": "إنشاء شجرة عمل جديدة", + "session.new.workspace.runIn": "تشغيل الجلسة في", + "session.new.workspace.triggerLocal": "محلي", + "session.new.workspace.local": "المستودع المحلي", + "session.new.workspace.existing": "مساحة عمل…", "session.new.lastModified": "آخر تعديل", "session.header.search.placeholder": "بحث {{project}}", "session.header.searchFiles": "بحث عن الملفات", @@ -550,6 +663,8 @@ export const dict = { "sidebar.project.recentSessions": "الجلسات الحديثة", "sidebar.project.viewAllSessions": "عرض جميع الجلسات", "sidebar.project.clearNotifications": "مسح الإشعارات", + "sidebar.empty.title": "لا توجد مشاريع مفتوحة", + "sidebar.empty.description": "افتح مشروعًا للبدء", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "سطح المكتب", "settings.section.server": "الخادم", @@ -559,6 +674,7 @@ export const dict = { "settings.desktop.wsl.title": "تكامل WSL", "settings.desktop.wsl.description": "تشغيل خادم OpenCode داخل WSL على Windows.", "settings.general.section.appearance": "المظهر", + "settings.general.section.advanced": "متقدم", "settings.general.section.notifications": "إشعارات النظام", "settings.general.section.updates": "التحديثات", "settings.general.section.sounds": "المؤثرات الصوتية", @@ -566,6 +682,11 @@ export const dict = { "settings.general.section.display": "شاشة العرض", "settings.general.row.language.title": "اللغة", "settings.general.row.language.description": "تغيير لغة العرض لـ OpenCode", + "settings.general.row.shell.title": "Shell المحطة الطرفية", + "settings.general.row.shell.description": + "اختر shell المستخدم في المحطة الطرفية. تُستخدم واجهات shell المتوافقة أيضًا في استدعاءات أدوات الوكيل.", + "settings.general.row.shell.autoDefault": "تلقائي (افتراضي)", + "settings.general.row.shell.terminalOnly": "المحطة الطرفية فقط", "settings.general.row.appearance.title": "المظهر", "settings.general.row.appearance.description": "تخصيص كيفية ظهور OpenCode على جهازك", "settings.general.row.colorScheme.title": "مخطط الألوان", @@ -574,14 +695,29 @@ export const dict = { "settings.general.row.theme.description": "تخصيص سمة OpenCode.", "settings.general.row.font.title": "خط الكود", "settings.general.row.font.description": "خصّص الخط المستخدم في كتل التعليمات البرمجية", - "settings.general.row.terminalFont.title": "Terminal Font", - "settings.general.row.terminalFont.description": "Customise the font used in the terminal", + "settings.general.row.terminalFont.title": "خط الطرفية", + "settings.general.row.terminalFont.description": "خصّص الخط المستخدم في الطرفية", "settings.general.row.uiFont.title": "خط الواجهة", "settings.general.row.uiFont.description": "خصّص الخط المستخدم في الواجهة بأكملها", "settings.general.row.followup.title": "سلوك المتابعة", "settings.general.row.followup.description": "اختر ما إذا كانت طلبات المتابعة توجه فورًا أو تنتظر في قائمة انتظار", "settings.general.row.followup.option.queue": "قائمة انتظار", "settings.general.row.followup.option.steer": "توجيه", + "settings.general.row.showFileTree.title": "شجرة الملفات", + "settings.general.row.showFileTree.description": "إظهار لوحة شجرة الملفات في الجلسات", + "settings.general.row.showNavigation.title": "عناصر التحكم في التنقل", + "settings.general.row.showNavigation.description": "إظهار زري الرجوع والتقدم في شريط عنوان سطح المكتب", + "settings.general.row.showSearch.title": "لوحة الأوامر", + "settings.general.row.showSearch.description": "إظهار زر البحث ولوحة الأوامر في شريط العنوان", + "settings.general.row.showTerminal.title": "المحطة الطرفية", + "settings.general.row.showTerminal.description": "إظهار زر المحطة الطرفية في شريط عنوان سطح المكتب", + "settings.general.row.showStatus.title": "حالة الخادم", + "settings.general.row.showStatus.description": "إظهار زر حالة الخادم في شريط العنوان", + "settings.general.row.mobileTitlebarBottom.title": "التنقل السفلي", + "settings.general.row.mobileTitlebarBottom.description": + "وضع شريط العنوان وعلامات تبويب الجلسات أسفل الشاشة على الأجهزة المحمولة", + "settings.general.row.showCustomAgents.title": "الوكلاء المخصصون", + "settings.general.row.showCustomAgents.description": "إظهار محدد الوكلاء في محرر الرسائل", "settings.general.row.reasoningSummaries.title": "إظهار ملخصات الاستنتاج", "settings.general.row.reasoningSummaries.description": "عرض ملخصات استنتاج النموذج في الشريط الزمني", "settings.general.row.shellToolPartsExpanded.title": "توسيع أجزاء أداة shell", @@ -590,6 +726,11 @@ export const dict = { "settings.general.row.editToolPartsExpanded.title": "توسيع أجزاء أداة edit", "settings.general.row.editToolPartsExpanded.description": "إظهار أجزاء أدوات edit و write و patch موسعة بشكل افتراضي في الشريط الزمني", + "settings.general.row.newLayoutDesigns.title": "التخطيط والتصاميم الجديدة", + "settings.general.row.newLayoutDesigns.description": + "تمكين التخطيط والصفحة الرئيسية ومحرر الرسائل وواجهة الجلسة المعاد تصميمها", + "settings.general.row.pinchZoom.title": "التكبير بإيماءة القرص", + "settings.general.row.pinchZoom.description": "السماح بإيماءة القرص على لوحة اللمس وإيماءة Ctrl-scroll للتكبير", "settings.general.row.wayland.title": "استخدام Wayland الأصلي", "settings.general.row.wayland.description": "تعطيل التراجع إلى X11 على Wayland. يتطلب إعادة التشغيل.", "settings.general.row.wayland.tooltip": @@ -602,6 +743,8 @@ export const dict = { "settings.updates.row.check.description": "التحقق يدويًا من التحديثات وتثبيتها إذا كانت متاحة", "settings.updates.action.checkNow": "تحقق الآن", "settings.updates.action.checking": "جارٍ التحقق...", + "settings.updates.action.downloading": "جارٍ التنزيل...", + "settings.updates.action.installing": "جارٍ التثبيت...", "settings.updates.toast.latest.title": "أنت على آخر إصدار", "settings.updates.toast.latest.description": "أنت تستخدم أحدث إصدار من OpenCode.", "sound.option.none": "بلا", @@ -721,8 +864,6 @@ export const dict = { "settings.permissions.tool.skill.description": "تحميل مهارة بالاسم", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "تشغيل استعلامات خادم اللغة", - "settings.permissions.tool.todowrite.title": "كتابة المهام", - "settings.permissions.tool.todowrite.description": "تحديث قائمة المهام", "settings.permissions.tool.webfetch.title": "جلب الويب", "settings.permissions.tool.webfetch.description": "جلب محتوى من عنوان URL", "settings.permissions.tool.websearch.title": "بحث الويب", @@ -785,7 +926,6 @@ export const dict = { "session.review.noVcs.createGit.description": "تتبع ومراجعة والتراجع عن التغييرات في هذا المشروع", "session.review.noVcs.createGit.actionLoading": "جاري إنشاء مستودع Git...", "session.review.noVcs.createGit.action": "إنشاء مستودع Git", - "session.todo.progress": "تم إكمال {{done}} من {{total}} مهام", "session.question.progress": "{{current}} من {{total}} أسئلة", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "مستكشف الملفات", diff --git a/packages/app/src/i18n/br.ts b/packages/app/src/i18n/br.ts index 2e53bb1af0..f431dbc8fc 100644 --- a/packages/app/src/i18n/br.ts +++ b/packages/app/src/i18n/br.ts @@ -21,6 +21,9 @@ export const dict = { "theme.scheme.dark": "Escuro", "command.sidebar.toggle": "Alternar barra lateral", "command.project.open": "Abrir projeto", + "command.project.previous": "Projeto anterior", + "command.project.next": "Próximo projeto", + "command.project.index": "Alternar para o projeto {{index}}", "command.provider.connect": "Conectar provedor", "command.server.switch": "Trocar servidor", "command.settings.open": "Abrir configurações", @@ -39,6 +42,7 @@ export const dict = { "command.session.new": "Nova sessão", "command.file.open": "Abrir arquivo", "command.tab.close": "Fechar aba", + "command.tab.reopenClosed": "Reabrir aba fechada", "command.context.addSelection": "Adicionar seleção ao contexto", "command.context.addSelection.description": "Adicionar as linhas selecionadas do arquivo atual", "command.input.focus": "Focar entrada", @@ -193,6 +197,11 @@ export const dict = { "model.input.video": "vídeo", "model.input.pdf": "pdf", "model.tooltip.allows": "Permite: {{inputs}}", + "model.tooltip.context.label": "Contexto", + "model.tooltip.inputs": "Entradas", + "model.tooltip.model": "Modelo", + "model.tooltip.provider": "Provedor", + "model.tooltip.reasoning": "Raciocínio", "model.tooltip.reasoning.allowed": "Permite raciocínio", "model.tooltip.reasoning.none": "Sem raciocínio", "model.tooltip.context": "Limite de contexto {{limit}}", @@ -202,6 +211,7 @@ export const dict = { "common.loading": "Carregando", "common.loading.ellipsis": "...", "common.cancel": "Cancelar", + "common.clear": "Limpar", "common.connect": "Conectar", "common.disconnect": "Desconectar", "common.continue": "Enviar", @@ -218,6 +228,8 @@ export const dict = { "prompt.mode.shell": "Shell", "prompt.mode.normal": "Prompt", "prompt.mode.shell.exit": "esc para sair", + "session.child.promptDisabled": "Não é possível enviar prompts em sessões de subagentes.", + "session.child.backToParent": "Voltar à sessão principal.", "prompt.example.1": "Corrigir um TODO no código", "prompt.example.2": "Qual é a stack tecnológica deste projeto?", "prompt.example.3": "Corrigir testes quebrados", @@ -314,6 +326,75 @@ export const dict = { "dialog.server.menu.delete": "Excluir", "dialog.server.current": "Servidor atual", "dialog.server.status.default": "Padrão", + "wsl.server.add": "Adicionar servidor WSL", + "wsl.server.addShort": "Adicionar WSL", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "Servidor WSL", + "wsl.server.retryStart": "Tentar iniciar novamente", + "wsl.server.updating": "Atualizando...", + "wsl.onboarding.step.distro": "Escolher distribuição", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "Verificando o WSL...", + "wsl.onboarding.restartRequired": "O Windows precisa ser reiniciado para concluir a instalação do WSL.", + "wsl.onboarding.ready": "O WSL está pronto.", + "wsl.onboarding.required": "O WSL é necessário para continuar.", + "wsl.onboarding.checkingDistros": "Verificando distribuições...", + "wsl.onboarding.installingDistro": "Instalando {{distro}}...", + "wsl.onboarding.checkingDistro": "Verificando {{distro}}...", + "wsl.onboarding.listingDistros": "Listando distribuições...", + "wsl.onboarding.distroReady": "{{distro}} está pronta.", + "wsl.onboarding.distroNotInstalled": "{{distro}} ainda não está instalada.", + "wsl.onboarding.openDistroOnce": "Abra {{distro}} uma vez para concluir a configuração.", + "wsl.onboarding.finishingDistro": "Concluindo a configuração de {{distro}}.", + "wsl.onboarding.pickDistro": "Escolha uma distribuição ou instale uma abaixo.", + "wsl.onboarding.checkingOpencode": "Verificando o OpenCode...", + "wsl.onboarding.checkingOpencodeIn": "Verificando o OpenCode em {{distro}}...", + "wsl.onboarding.updatingOpencode": "Atualizando o OpenCode...", + "wsl.onboarding.updatingOpencodeIn": "Atualizando o OpenCode em {{distro}}...", + "wsl.onboarding.updateOpencodeIn": "Atualize o OpenCode em {{distro}}.", + "wsl.onboarding.updateOpencode": "Atualizar o OpenCode", + "wsl.onboarding.opencodeReadyIn": "O OpenCode está pronto em {{distro}}.", + "wsl.onboarding.opencodeReady": "O OpenCode está pronto.", + "wsl.onboarding.installOpencodeIn": "Instale o OpenCode em {{distro}}.", + "wsl.onboarding.installOpencode": "Instalar o OpenCode", + "wsl.onboarding.chooseDistroFirst": "Escolha primeiro uma distribuição.", + "wsl.onboarding.loadFailed": "Falha ao carregar o estado do WSL.", + "wsl.onboarding.loading": "Carregando...", + "wsl.onboarding.installedDistros": "Distribuições instaladas", + "wsl.onboarding.checkAgain": "Verificar novamente", + "wsl.onboarding.distroStatus.ready": "Pronta", + "wsl.onboarding.distroStatus.checking": "Verificando...", + "wsl.onboarding.distroStatus.opencodeMissing": "OpenCode não instalado", + "wsl.onboarding.distroStatus.missingTools": "bash e curl ausentes", + "wsl.onboarding.distroStatus.unsupported": "Sem suporte · Use o WSL 2", + "wsl.onboarding.needAnotherDistro": "Precisa de outra distribuição?", + "wsl.onboarding.needAnotherDistroHint": "Instale uma distribuição Linux pelo catálogo do WSL", + "wsl.onboarding.wslNotInstalled.title": "WSL não instalado", + "wsl.onboarding.wslNotInstalled.description": + "O WSL (Windows Subsystem for Linux) é necessário para que o OpenCode possa adicionar um servidor WSL", + "wsl.onboarding.wslUnavailable.title": "WSL indisponível", + "wsl.onboarding.wslUnavailable.description": "O OpenCode não conseguiu verificar o WSL neste computador.", + "wsl.onboarding.installWsl": "Instalar o WSL", + "wsl.onboarding.windowsRestartRequired": + "Reinicie o Windows para concluir a instalação do WSL e abra o OpenCode novamente.", + "wsl.onboarding.next": "Próximo", + "wsl.onboarding.refresh": "Atualizar", + "wsl.onboarding.allDistrosAdded": "Todas as distribuições instaladas já foram adicionadas.", + "wsl.onboarding.noDistros": "Nenhuma distribuição detectada ainda.", + "wsl.onboarding.install": "Instalar", + "wsl.onboarding.installing": "Instalando...", + "wsl.onboarding.installDistro": "Instalar distribuição", + "wsl.onboarding.searchDistros": "Buscar distribuições", + "wsl.onboarding.wsl2Required": "O WSL 2 é necessário.", + "wsl.onboarding.toolsRequired": "Esta distribuição precisa do bash e do curl.", + "wsl.onboarding.openTerminal": "Abrir terminal", + "wsl.onboarding.path": "Caminho: {{path}}", + "wsl.onboarding.notFound": "não encontrado", + "wsl.onboarding.version": "Versão: {{version}}", + "wsl.onboarding.unknown": "desconhecido", + "wsl.onboarding.desktopVersion": "desktop {{version}}", + "wsl.onboarding.versionMismatch": "A versão instalada não corresponde à versão do aplicativo para desktop.", + "wsl.onboarding.adding": "Adicionando...", "dialog.project.edit.title": "Editar projeto", "dialog.project.edit.name": "Nome", "dialog.project.edit.icon": "Ícone", @@ -371,6 +452,7 @@ export const dict = { "language.no": "Norsk", "language.br": "Português (Brasil)", "language.bs": "Bosanski", + "language.uk": "Українська", "language.th": "ไทย", "language.tr": "Türkçe", "toast.language.title": "Idioma", @@ -407,10 +489,12 @@ export const dict = { "toast.update.action.notYet": "Agora não", "error.page.title": "Algo deu errado", "error.page.description": "Ocorreu um erro ao carregar a aplicação.", + "error.page.description.localServerStartup": "Ocorreu um erro ao iniciar o servidor local.", "error.page.details.label": "Detalhes do Erro", "error.page.action.restart": "Reiniciar", "error.page.action.report": "Reportar erro", "error.page.action.reported": "Erro reportado", + "error.page.action.exportLogs": "Exportar logs", "error.page.action.checking": "Verificando...", "error.page.action.checkUpdates": "Verificar atualizações", "error.page.action.updateTo": "Atualizar para {{version}}", @@ -453,10 +537,30 @@ export const dict = { "home.recentProjects": "Projetos recentes", "home.empty.title": "Nenhum projeto recente", "home.empty.description": "Comece abrindo um projeto local", + "home.title": "Início", + "home.projects": "Projetos", + "home.project.add": "Adicionar projeto", + "home.recentlyClosed": "Projetos fechados recentemente", + "home.server.collapse": "Recolher projetos do servidor", + "home.server.expand": "Expandir projetos do servidor", + "home.sessions.search.placeholder": "Buscar sessões", + "home.sessions.search.placeholder.scoped": "Buscar sessões em {{scope}}", + "home.sessions.search.sessions": "Sessões", + "home.sessions.search.noResults": "Nenhuma sessão encontrada para {{query}}", + "home.sessions.empty": "Nada por aqui ainda", + "home.sessions.empty.description": "Crie uma sessão para começar", + "home.sessions.group.today": "Hoje", + "home.sessions.group.yesterday": "Ontem", + "home.sessions.group.older": "Mais antigas", "session.tab.session": "Sessão", "session.tab.review": "Revisão", "session.tab.context": "Contexto", + "session.tab.unknown": "Sessão desconhecida", "session.panel.reviewAndFiles": "Revisão e arquivos", + "session.error.notFound": "Esta sessão não foi encontrada", + "session.error.notFound.description": "Esta aba aponta para uma sessão que não existe mais neste servidor.", + "session.error.notFound.closeTab": "Fechar aba", + "session.error.serverConnection": "Não é possível conectar a este servidor", "session.review.filesChanged": "{{count}} Arquivos Alterados", "session.review.change.one": "Alteração", "session.review.change.other": "Alterações", @@ -466,6 +570,8 @@ export const dict = { "session.review.noSnapshot": "O rastreamento de snapshot está desabilitado na configuração, então as alterações da sessão estão indisponíveis", "session.review.noChanges": "Sem alterações", + "session.review.noUncommittedChanges": "Ainda não há alterações sem commit", + "session.review.noBranchChanges": "Ainda não há alterações na branch", "session.files.selectToOpen": "Selecione um arquivo para abrir", "session.files.all": "Todos os arquivos", "session.files.empty": "Nenhum arquivo", @@ -476,9 +582,10 @@ export const dict = { "session.messages.loading": "Carregando mensagens...", "session.messages.jumpToLatest": "Ir para a mais recente", "session.context.addToContext": "Adicionar {{selection}} ao contexto", - "session.todo.title": "Tarefas", - "session.todo.collapse": "Recolher", - "session.todo.expand": "Expandir", + "session.question.minimize": "Minimizar pergunta", + "session.question.restore": "Restaurar pergunta", + "session.question.pending.one": "{{count}} pergunta pendente", + "session.question.pending.other": "{{count}} perguntas pendentes", "session.followupDock.summary.one": "{{count}} mensagem na fila", "session.followupDock.summary.other": "{{count}} mensagens na fila", "session.followupDock.sendNow": "Enviar agora", @@ -491,9 +598,16 @@ export const dict = { "session.revertDock.expand": "Expandir mensagens revertidas", "session.revertDock.restore": "Restaurar mensagem", "session.new.title": "Crie qualquer coisa", + "session.new.project.new": "Novo projeto", + "session.new.project.search": "Buscar projetos", + "session.new.project.add": "Adicionar projeto", "session.new.worktree.main": "Branch principal", "session.new.worktree.mainWithBranch": "Branch principal ({{branch}})", "session.new.worktree.create": "Criar novo worktree", + "session.new.workspace.runIn": "Executar sessão em", + "session.new.workspace.triggerLocal": "Local", + "session.new.workspace.local": "Repositório local", + "session.new.workspace.existing": "Espaço de trabalho…", "session.new.lastModified": "Última modificação", "session.header.search.placeholder": "Buscar {{project}}", "session.header.searchFiles": "Buscar arquivos", @@ -557,15 +671,18 @@ export const dict = { "sidebar.project.recentSessions": "Sessões recentes", "sidebar.project.viewAllSessions": "Ver todas as sessões", "sidebar.project.clearNotifications": "Limpar notificações", + "sidebar.empty.title": "Nenhum projeto aberto", + "sidebar.empty.description": "Abra um projeto para começar", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "Desktop", "settings.section.server": "Servidor", "settings.tab.general": "Geral", "settings.tab.shortcuts": "Atalhos", "settings.desktop.section.wsl": "WSL", - "settings.desktop.wsl.title": "WSL integration", + "settings.desktop.wsl.title": "Integração com WSL", "settings.desktop.wsl.description": "Executar o servidor OpenCode dentro do WSL no Windows.", "settings.general.section.appearance": "Aparência", + "settings.general.section.advanced": "Avançado", "settings.general.section.notifications": "Notificações do sistema", "settings.general.section.updates": "Atualizações", "settings.general.section.sounds": "Efeitos sonoros", @@ -573,6 +690,11 @@ export const dict = { "settings.general.section.display": "Tela", "settings.general.row.language.title": "Idioma", "settings.general.row.language.description": "Alterar o idioma de exibição do OpenCode", + "settings.general.row.shell.title": "Shell do terminal", + "settings.general.row.shell.description": + "Escolha o shell usado no terminal. Os shells compatíveis também são usados nas chamadas de ferramentas do agente.", + "settings.general.row.shell.autoDefault": "Automático (Padrão)", + "settings.general.row.shell.terminalOnly": "somente no terminal", "settings.general.row.appearance.title": "Aparência", "settings.general.row.appearance.description": "Personalize como o OpenCode aparece no seu dispositivo", "settings.general.row.colorScheme.title": "Esquema de cores", @@ -581,8 +703,8 @@ export const dict = { "settings.general.row.theme.description": "Personalize como o OpenCode é tematizado.", "settings.general.row.font.title": "Fonte de código", "settings.general.row.font.description": "Personalize a fonte usada em blocos de código", - "settings.general.row.terminalFont.title": "Terminal Font", - "settings.general.row.terminalFont.description": "Customise the font used in the terminal", + "settings.general.row.terminalFont.title": "Fonte do terminal", + "settings.general.row.terminalFont.description": "Personalize a fonte usada no terminal", "settings.general.row.uiFont.title": "Fonte da interface", "settings.general.row.uiFont.description": "Personalize a fonte usada em toda a interface", "settings.general.row.followup.title": "Comportamento de acompanhamento", @@ -590,6 +712,22 @@ export const dict = { "Escolha se os prompts de acompanhamento orientam imediatamente ou esperam na fila", "settings.general.row.followup.option.queue": "Fila", "settings.general.row.followup.option.steer": "Orientar", + "settings.general.row.showFileTree.title": "Árvore de arquivos", + "settings.general.row.showFileTree.description": "Mostrar o painel da árvore de arquivos nas sessões", + "settings.general.row.showNavigation.title": "Controles de navegação", + "settings.general.row.showNavigation.description": + "Mostrar os botões de voltar e avançar na barra de título do desktop", + "settings.general.row.showSearch.title": "Paleta de comandos", + "settings.general.row.showSearch.description": "Mostrar o botão de busca e paleta de comandos na barra de título", + "settings.general.row.showTerminal.title": "Terminal", + "settings.general.row.showTerminal.description": "Mostrar o botão do terminal na barra de título do desktop", + "settings.general.row.showStatus.title": "Status do servidor", + "settings.general.row.showStatus.description": "Mostrar o botão de status do servidor na barra de título", + "settings.general.row.mobileTitlebarBottom.title": "Navegação inferior", + "settings.general.row.mobileTitlebarBottom.description": + "Posicionar a barra de título e as abas da sessão na parte inferior da tela em dispositivos móveis", + "settings.general.row.showCustomAgents.title": "Agentes personalizados", + "settings.general.row.showCustomAgents.description": "Mostrar o seletor de agentes na área de composição", "settings.general.row.reasoningSummaries.title": "Mostrar resumos de raciocínio", "settings.general.row.reasoningSummaries.description": "Exibir resumos de raciocínio do modelo na linha do tempo", "settings.general.row.shellToolPartsExpanded.title": "Expandir partes da ferramenta shell", @@ -598,6 +736,12 @@ export const dict = { "settings.general.row.editToolPartsExpanded.title": "Expandir partes da ferramenta de edição", "settings.general.row.editToolPartsExpanded.description": "Mostrar partes das ferramentas de edição, escrita e patch expandidas por padrão na linha do tempo", + "settings.general.row.newLayoutDesigns.title": "Novo layout e design", + "settings.general.row.newLayoutDesigns.description": + "Ativar o layout, a página inicial, a área de composição e a interface de sessão reformulados", + "settings.general.row.pinchZoom.title": "Zoom com gesto de pinça", + "settings.general.row.pinchZoom.description": + "Permitir gestos de pinça no trackpad e de Ctrl+rolagem para aplicar zoom", "settings.general.row.wayland.title": "Usar Wayland nativo", "settings.general.row.wayland.description": "Desabilitar fallback X11 no Wayland. Requer reinicialização.", "settings.general.row.wayland.tooltip": @@ -610,6 +754,8 @@ export const dict = { "settings.updates.row.check.description": "Verificar atualizações manualmente e instalar se houver", "settings.updates.action.checkNow": "Verificar agora", "settings.updates.action.checking": "Verificando...", + "settings.updates.action.downloading": "Baixando...", + "settings.updates.action.installing": "Instalando...", "settings.updates.toast.latest.title": "Você está atualizado", "settings.updates.toast.latest.description": "Você está usando a versão mais recente do OpenCode.", "sound.option.none": "Nenhum", @@ -731,8 +877,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Carregar uma habilidade por nome", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Executar consultas de servidor de linguagem", - "settings.permissions.tool.todowrite.title": "Escrever Tarefas", - "settings.permissions.tool.todowrite.description": "Atualizar a lista de tarefas", "settings.permissions.tool.webfetch.title": "Buscar Web", "settings.permissions.tool.webfetch.description": "Buscar conteúdo de uma URL", "settings.permissions.tool.websearch.title": "Pesquisa Web", @@ -795,7 +939,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Rastreie, revise e desfaça alterações neste projeto", "session.review.noVcs.createGit.actionLoading": "Criando repositório Git...", "session.review.noVcs.createGit.action": "Criar repositório Git", - "session.todo.progress": "{{done}} de {{total}} tarefas concluídas", "session.question.progress": "{{current}} de {{total}} perguntas", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Explorador de Arquivos", diff --git a/packages/app/src/i18n/bs.ts b/packages/app/src/i18n/bs.ts index c5b9e1a6d8..e5d48e5d19 100644 --- a/packages/app/src/i18n/bs.ts +++ b/packages/app/src/i18n/bs.ts @@ -23,6 +23,9 @@ export const dict = { "command.sidebar.toggle": "Prikaži/sakrij bočnu traku", "command.project.open": "Otvori projekat", + "command.project.previous": "Prethodni projekat", + "command.project.next": "Sljedeći projekat", + "command.project.index": "Prebaci na projekat {{index}}", "command.provider.connect": "Poveži provajdera", "command.server.switch": "Promijeni server", "command.settings.open": "Otvori postavke", @@ -45,6 +48,7 @@ export const dict = { "command.session.new": "Nova sesija", "command.file.open": "Otvori datoteku", "command.tab.close": "Zatvori karticu", + "command.tab.reopenClosed": "Ponovo otvori zatvorenu karticu", "command.context.addSelection": "Dodaj odabir u kontekst", "command.context.addSelection.description": "Dodaj odabrane linije iz trenutne datoteke", "command.input.focus": "Fokusiraj polje za unos", @@ -209,6 +213,11 @@ export const dict = { "model.input.video": "video", "model.input.pdf": "pdf", "model.tooltip.allows": "Podržava: {{inputs}}", + "model.tooltip.context.label": "Kontekst", + "model.tooltip.inputs": "Ulazi", + "model.tooltip.model": "Model", + "model.tooltip.provider": "Provajder", + "model.tooltip.reasoning": "Rasuđivanje", "model.tooltip.reasoning.allowed": "Podržava rasuđivanje", "model.tooltip.reasoning.none": "Bez rasuđivanja", "model.tooltip.context": "Limit konteksta {{limit}}", @@ -219,6 +228,7 @@ export const dict = { "common.loading": "Učitavanje", "common.loading.ellipsis": "...", "common.cancel": "Otkaži", + "common.clear": "Očisti", "common.connect": "Poveži", "common.disconnect": "Prekini vezu", "common.continue": "Pošalji", @@ -236,6 +246,8 @@ export const dict = { "prompt.mode.shell": "Shell", "prompt.mode.normal": "Prompt", "prompt.mode.shell.exit": "esc za izlaz", + "session.child.promptDisabled": "Sesijama podagenta nije moguće slati upite.", + "session.child.backToParent": "Nazad na glavnu sesiju.", "prompt.example.1": "Popravi TODO u bazi koda", "prompt.example.2": "Koji je tehnološki stack ovog projekta?", @@ -342,6 +354,75 @@ export const dict = { "dialog.server.menu.delete": "Izbriši", "dialog.server.current": "Trenutni server", "dialog.server.status.default": "Podrazumijevano", + "wsl.server.add": "Dodaj WSL server", + "wsl.server.addShort": "Dodaj WSL", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "WSL server", + "wsl.server.retryStart": "Ponovi pokretanje", + "wsl.server.updating": "Ažuriranje...", + "wsl.onboarding.step.distro": "Odaberi distribuciju", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "Provjera WSL-a...", + "wsl.onboarding.restartRequired": "Potrebno je ponovo pokrenuti Windows da bi se završila instalacija WSL-a.", + "wsl.onboarding.ready": "WSL je spreman.", + "wsl.onboarding.required": "WSL je potreban za nastavak.", + "wsl.onboarding.checkingDistros": "Provjera distribucija...", + "wsl.onboarding.installingDistro": "Instaliranje {{distro}}...", + "wsl.onboarding.checkingDistro": "Provjera {{distro}}...", + "wsl.onboarding.listingDistros": "Učitavanje liste distribucija...", + "wsl.onboarding.distroReady": "Distribucija {{distro}} je spremna.", + "wsl.onboarding.distroNotInstalled": "Distribucija {{distro}} još nije instalirana.", + "wsl.onboarding.openDistroOnce": "Otvori {{distro}} jednom da završiš postavljanje.", + "wsl.onboarding.finishingDistro": "Završavanje postavljanja za {{distro}}.", + "wsl.onboarding.pickDistro": "Odaberi distribuciju ili instaliraj jednu ispod.", + "wsl.onboarding.checkingOpencode": "Provjera OpenCode...", + "wsl.onboarding.checkingOpencodeIn": "Provjera OpenCode u distribuciji {{distro}}...", + "wsl.onboarding.updatingOpencode": "Ažuriranje OpenCode...", + "wsl.onboarding.updatingOpencodeIn": "Ažuriranje OpenCode u distribuciji {{distro}}...", + "wsl.onboarding.updateOpencodeIn": "Ažuriraj OpenCode u distribuciji {{distro}}.", + "wsl.onboarding.updateOpencode": "Ažuriraj OpenCode", + "wsl.onboarding.opencodeReadyIn": "OpenCode je spreman u distribuciji {{distro}}.", + "wsl.onboarding.opencodeReady": "OpenCode je spreman.", + "wsl.onboarding.installOpencodeIn": "Instaliraj OpenCode u distribuciji {{distro}}.", + "wsl.onboarding.installOpencode": "Instaliraj OpenCode", + "wsl.onboarding.chooseDistroFirst": "Prvo odaberi distribuciju.", + "wsl.onboarding.loadFailed": "Nije uspjelo učitavanje WSL stanja.", + "wsl.onboarding.loading": "Učitavanje...", + "wsl.onboarding.installedDistros": "Instalirane distribucije", + "wsl.onboarding.checkAgain": "Provjeri ponovo", + "wsl.onboarding.distroStatus.ready": "Spremno", + "wsl.onboarding.distroStatus.checking": "Provjera...", + "wsl.onboarding.distroStatus.opencodeMissing": "OpenCode nije instaliran", + "wsl.onboarding.distroStatus.missingTools": "Nedostaju bash i curl", + "wsl.onboarding.distroStatus.unsupported": "Nije podržano · Koristi WSL 2", + "wsl.onboarding.needAnotherDistro": "Treba ti druga distribucija?", + "wsl.onboarding.needAnotherDistroHint": "Instaliraj Linux distribuciju iz WSL kataloga", + "wsl.onboarding.wslNotInstalled.title": "WSL nije instaliran", + "wsl.onboarding.wslNotInstalled.description": + "WSL (Windows Subsystem for Linux) je potreban da bi OpenCode mogao dodati WSL server", + "wsl.onboarding.wslUnavailable.title": "WSL nije dostupan", + "wsl.onboarding.wslUnavailable.description": "OpenCode nije mogao provjeriti WSL na ovom uređaju.", + "wsl.onboarding.installWsl": "Instaliraj WSL", + "wsl.onboarding.windowsRestartRequired": + "Ponovo pokreni Windows da završiš instalaciju WSL-a, zatim ponovo otvori OpenCode.", + "wsl.onboarding.next": "Dalje", + "wsl.onboarding.refresh": "Osvježi", + "wsl.onboarding.allDistrosAdded": "Sve instalirane distribucije su već dodane.", + "wsl.onboarding.noDistros": "Još nema otkrivenih distribucija.", + "wsl.onboarding.install": "Instaliraj", + "wsl.onboarding.installing": "Instaliranje...", + "wsl.onboarding.installDistro": "Instaliraj distribuciju", + "wsl.onboarding.searchDistros": "Pretraži distribucije", + "wsl.onboarding.wsl2Required": "Potreban je WSL 2.", + "wsl.onboarding.toolsRequired": "Ovoj distribuciji su potrebni bash i curl.", + "wsl.onboarding.openTerminal": "Otvori terminal", + "wsl.onboarding.path": "Putanja: {{path}}", + "wsl.onboarding.notFound": "nije pronađeno", + "wsl.onboarding.version": "Verzija: {{version}}", + "wsl.onboarding.unknown": "nepoznato", + "wsl.onboarding.desktopVersion": "desktop {{version}}", + "wsl.onboarding.versionMismatch": "Instalirana verzija ne odgovara verziji desktop aplikacije.", + "wsl.onboarding.adding": "Dodavanje...", "dialog.project.edit.title": "Uredi projekat", "dialog.project.edit.name": "Naziv", @@ -405,6 +486,7 @@ export const dict = { "language.no": "Norsk", "language.br": "Português (Brasil)", "language.bs": "Bosanski", + "language.uk": "Українська", "language.th": "ไทย", "language.tr": "Türkçe", @@ -453,10 +535,12 @@ export const dict = { "error.page.title": "Nešto je pošlo po zlu", "error.page.description": "Došlo je do greške prilikom učitavanja aplikacije.", + "error.page.description.localServerStartup": "Došlo je do greške pri pokretanju lokalnog servera.", "error.page.details.label": "Detalji greške", "error.page.action.restart": "Restartuj", "error.page.action.report": "Prijavi grešku", "error.page.action.reported": "Greška prijavljena", + "error.page.action.exportLogs": "Izvezi logove", "error.page.action.checking": "Provjera...", "error.page.action.checkUpdates": "Provjeri ažuriranja", "error.page.action.updateTo": "Ažuriraj na {{version}}", @@ -504,11 +588,31 @@ export const dict = { "home.recentProjects": "Nedavni projekti", "home.empty.title": "Nema nedavnih projekata", "home.empty.description": "Kreni tako što ćeš otvoriti lokalni projekat", + "home.title": "Početna", + "home.projects": "Projekti", + "home.project.add": "Dodaj projekat", + "home.recentlyClosed": "Nedavno zatvoreni projekti", + "home.server.collapse": "Sažmi projekte servera", + "home.server.expand": "Proširi projekte servera", + "home.sessions.search.placeholder": "Pretraži sesije", + "home.sessions.search.placeholder.scoped": "Pretraži sesije u {{scope}}", + "home.sessions.search.sessions": "Sesije", + "home.sessions.search.noResults": "Nema pronađenih sesija za {{query}}", + "home.sessions.empty": "Ovdje još nema ničega", + "home.sessions.empty.description": "Kreiraj sesiju za početak", + "home.sessions.group.today": "Danas", + "home.sessions.group.yesterday": "Jučer", + "home.sessions.group.older": "Starije", "session.tab.session": "Sesija", "session.tab.review": "Pregled", "session.tab.context": "Kontekst", + "session.tab.unknown": "Nepoznata sesija", "session.panel.reviewAndFiles": "Pregled i datoteke", + "session.error.notFound": "Ova sesija nije pronađena", + "session.error.notFound.description": "Ova kartica upućuje na sesiju koja više ne postoji na ovom serveru.", + "session.error.notFound.closeTab": "Zatvori karticu", + "session.error.serverConnection": "Nije moguće povezati se s ovim serverom", "session.review.filesChanged": "Izmijenjeno {{count}} datoteka", "session.review.change.one": "Izmjena", "session.review.change.other": "Izmjene", @@ -518,6 +622,8 @@ export const dict = { "session.review.noSnapshot": "Praćenje snimaka (snapshot) je onemogućeno u konfiguraciji, pa promjene sesije nisu dostupne", "session.review.noChanges": "Nema izmjena", + "session.review.noUncommittedChanges": "Još nema nepotvrđenih promjena", + "session.review.noBranchChanges": "Još nema promjena na grani", "session.files.selectToOpen": "Odaberi datoteku za otvaranje", "session.files.all": "Sve datoteke", @@ -531,9 +637,10 @@ export const dict = { "session.messages.jumpToLatest": "Idi na najnovije", "session.context.addToContext": "Dodaj {{selection}} u kontekst", - "session.todo.title": "Zadaci", - "session.todo.collapse": "Sažmi", - "session.todo.expand": "Proširi", + "session.question.minimize": "Minimiziraj pitanje", + "session.question.restore": "Vrati pitanje", + "session.question.pending.one": "{{count}} pitanje na čekanju", + "session.question.pending.other": "{{count}} pitanja na čekanju", "session.followupDock.summary.one": "{{count}} poruka na čekanju", "session.followupDock.summary.other": "{{count}} poruka na čekanju", "session.followupDock.sendNow": "Pošalji sada", @@ -547,9 +654,16 @@ export const dict = { "session.revertDock.restore": "Vrati poruku", "session.new.title": "Napravi bilo šta", + "session.new.project.new": "Novi projekat", + "session.new.project.search": "Pretraži projekte", + "session.new.project.add": "Dodaj projekat", "session.new.worktree.main": "Glavna grana", "session.new.worktree.mainWithBranch": "Glavna grana ({{branch}})", "session.new.worktree.create": "Kreiraj novi worktree", + "session.new.workspace.runIn": "Pokreni sesiju u", + "session.new.workspace.triggerLocal": "Lokalno", + "session.new.workspace.local": "Lokalni repozitorij", + "session.new.workspace.existing": "Radni prostor…", "session.new.lastModified": "Posljednja izmjena", "session.header.search.placeholder": "Pretraži {{project}}", @@ -618,6 +732,8 @@ export const dict = { "sidebar.project.recentSessions": "Nedavne sesije", "sidebar.project.viewAllSessions": "Prikaži sve sesije", "sidebar.project.clearNotifications": "Očisti obavijesti", + "sidebar.empty.title": "Nema otvorenih projekata", + "sidebar.empty.description": "Otvori projekat za početak", "app.name.desktop": "OpenCode Desktop", @@ -630,6 +746,7 @@ export const dict = { "settings.desktop.wsl.description": "Pokreni OpenCode server unutar WSL-a na Windowsu.", "settings.general.section.appearance": "Izgled", + "settings.general.section.advanced": "Napredno", "settings.general.section.notifications": "Sistemske obavijesti", "settings.general.section.updates": "Ažuriranja", "settings.general.section.sounds": "Zvučni efekti", @@ -638,6 +755,11 @@ export const dict = { "settings.general.row.language.title": "Jezik", "settings.general.row.language.description": "Promijeni jezik prikaza u OpenCode-u", + "settings.general.row.shell.title": "Shell terminala", + "settings.general.row.shell.description": + "Odaberi shell koji se koristi za terminal. Kompatibilni shellovi koriste se i za pozive alata agenta.", + "settings.general.row.shell.autoDefault": "Automatski (podrazumijevano)", + "settings.general.row.shell.terminalOnly": "samo terminal", "settings.general.row.appearance.title": "Izgled", "settings.general.row.appearance.description": "Prilagodi kako OpenCode izgleda na tvom uređaju", "settings.general.row.colorScheme.title": "Šema boja", @@ -646,14 +768,30 @@ export const dict = { "settings.general.row.theme.description": "Prilagodi temu OpenCode-a.", "settings.general.row.font.title": "Font za kod", "settings.general.row.font.description": "Prilagodi font koji se koristi u blokovima koda", - "settings.general.row.terminalFont.title": "Terminal Font", - "settings.general.row.terminalFont.description": "Customise the font used in the terminal", + "settings.general.row.terminalFont.title": "Font terminala", + "settings.general.row.terminalFont.description": "Prilagodite font koji se koristi u terminalu", "settings.general.row.uiFont.title": "UI font", "settings.general.row.uiFont.description": "Prilagodi font koji se koristi u cijelom interfejsu", "settings.general.row.followup.title": "Ponašanje nadovezivanja", "settings.general.row.followup.description": "Odaberi da li upiti nadovezivanja usmjeravaju odmah ili čekaju u redu", "settings.general.row.followup.option.queue": "Red čekanja", "settings.general.row.followup.option.steer": "Usmjeri", + "settings.general.row.showFileTree.title": "Stablo datoteka", + "settings.general.row.showFileTree.description": "Prikaži stablo datoteka u sesijama", + "settings.general.row.showNavigation.title": "Kontrole navigacije", + "settings.general.row.showNavigation.description": + "Prikaži dugmad za nazad i naprijed u naslovnoj traci desktop aplikacije", + "settings.general.row.showSearch.title": "Paleta komandi", + "settings.general.row.showSearch.description": "Prikaži dugme za pretragu i paletu komandi u naslovnoj traci", + "settings.general.row.showTerminal.title": "Terminal", + "settings.general.row.showTerminal.description": "Prikaži dugme terminala u naslovnoj traci desktop aplikacije", + "settings.general.row.showStatus.title": "Status servera", + "settings.general.row.showStatus.description": "Prikaži dugme statusa servera u naslovnoj traci", + "settings.general.row.mobileTitlebarBottom.title": "Donja navigacija", + "settings.general.row.mobileTitlebarBottom.description": + "Postavi naslovnu traku i kartice sesije na dno ekrana na mobilnim uređajima", + "settings.general.row.showCustomAgents.title": "Prilagođeni agenti", + "settings.general.row.showCustomAgents.description": "Prikaži izbor agenta u uređivaču poruke", "settings.general.row.reasoningSummaries.title": "Prikaži sažetke rasuđivanja", "settings.general.row.reasoningSummaries.description": "Prikaži sažetke rasuđivanja modela na vremenskoj traci", @@ -663,6 +801,12 @@ export const dict = { "settings.general.row.editToolPartsExpanded.title": "Proširi dijelove alata za uređivanje", "settings.general.row.editToolPartsExpanded.description": "Prikaži dijelove alata za uređivanje, pisanje i patch podrazumijevano proširene na vremenskoj traci", + "settings.general.row.newLayoutDesigns.title": "Novi raspored i dizajn", + "settings.general.row.newLayoutDesigns.description": + "Omogući redizajnirani raspored, početnu stranicu, uređivač poruke i interfejs sesije", + "settings.general.row.pinchZoom.title": "Zumiranje štipanjem", + "settings.general.row.pinchZoom.description": + "Dozvoli zumiranje gestom štipanja na dodirnoj ploči i pomoću Ctrl-pomjeranja", "settings.general.row.wayland.title": "Koristi nativni Wayland", "settings.general.row.wayland.description": "Onemogući X11 fallback na Waylandu. Zahtijeva restart.", "settings.general.row.wayland.tooltip": @@ -677,6 +821,8 @@ export const dict = { "settings.updates.row.check.description": "Ručno provjeri ažuriranja i instaliraj ako su dostupna", "settings.updates.action.checkNow": "Provjeri sada", "settings.updates.action.checking": "Provjera...", + "settings.updates.action.downloading": "Preuzimanje...", + "settings.updates.action.installing": "Instaliranje...", "settings.updates.toast.latest.title": "Sve je ažurno", "settings.updates.toast.latest.description": "Koristiš najnoviju verziju OpenCode-a.", "sound.option.none": "Nijedan", @@ -805,8 +951,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Učitaj vještinu po nazivu", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Pokreni upite jezičnog servera", - "settings.permissions.tool.todowrite.title": "Ažuriranje liste zadataka", - "settings.permissions.tool.todowrite.description": "Ažuriraj listu zadataka", "settings.permissions.tool.webfetch.title": "Web preuzimanje", "settings.permissions.tool.webfetch.description": "Preuzmi sadržaj sa URL-a", "settings.permissions.tool.websearch.title": "Web pretraga", @@ -871,7 +1015,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Pratite, pregledajte i poništite promjene u ovom projektu", "session.review.noVcs.createGit.actionLoading": "Kreiranje Git repozitorija...", "session.review.noVcs.createGit.action": "Kreiraj Git repozitorij", - "session.todo.progress": "{{done}} od {{total}} zadataka završeno", "session.question.progress": "{{current}} od {{total}} pitanja", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "File Explorer", diff --git a/packages/app/src/i18n/da.ts b/packages/app/src/i18n/da.ts index ad43c1d111..8435d9e378 100644 --- a/packages/app/src/i18n/da.ts +++ b/packages/app/src/i18n/da.ts @@ -23,6 +23,9 @@ export const dict = { "command.sidebar.toggle": "Skift sidebjælke", "command.project.open": "Åbn projekt", + "command.project.previous": "Forrige projekt", + "command.project.next": "Næste projekt", + "command.project.index": "Skift til projekt {{index}}", "command.provider.connect": "Tilslut udbyder", "command.server.switch": "Skift server", "command.settings.open": "Åbn indstillinger", @@ -45,6 +48,7 @@ export const dict = { "command.session.new": "Ny session", "command.file.open": "Åbn fil", "command.tab.close": "Luk fane", + "command.tab.reopenClosed": "Åbn lukket fane igen", "command.context.addSelection": "Tilføj markering til kontekst", "command.context.addSelection.description": "Tilføj markerede linjer fra den aktuelle fil", "command.input.focus": "Fokuser inputfelt", @@ -208,6 +212,11 @@ export const dict = { "model.input.video": "video", "model.input.pdf": "pdf", "model.tooltip.allows": "Tillader: {{inputs}}", + "model.tooltip.context.label": "Kontekst", + "model.tooltip.inputs": "Input", + "model.tooltip.model": "Model", + "model.tooltip.provider": "Udbyder", + "model.tooltip.reasoning": "Tænkning", "model.tooltip.reasoning.allowed": "Tillader tænkning", "model.tooltip.reasoning.none": "Ingen tænkning", "model.tooltip.context": "Kontekstgrænse {{limit}}", @@ -217,6 +226,7 @@ export const dict = { "common.loading": "Indlæser", "common.loading.ellipsis": "...", "common.cancel": "Annuller", + "common.clear": "Ryd", "common.connect": "Forbind", "common.disconnect": "Frakobl", "common.continue": "Indsend", @@ -234,6 +244,8 @@ export const dict = { "prompt.mode.shell": "Shell", "prompt.mode.normal": "Prompt", "prompt.mode.shell.exit": "esc for at afslutte", + "session.child.promptDisabled": "Der kan ikke sendes prompts til underagentsessioner.", + "session.child.backToParent": "Tilbage til hovedsessionen.", "prompt.example.1": "Ret en TODO i koden", "prompt.example.2": "Hvad er teknologistakken for dette projekt?", @@ -340,6 +352,75 @@ export const dict = { "dialog.server.menu.delete": "Slet", "dialog.server.current": "Nuværende server", "dialog.server.status.default": "Standard", + "wsl.server.add": "Tilføj WSL-server", + "wsl.server.addShort": "Tilføj WSL", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "WSL-server", + "wsl.server.retryStart": "Prøv at starte igen", + "wsl.server.updating": "Opdaterer...", + "wsl.onboarding.step.distro": "Vælg distribution", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "Tjekker WSL...", + "wsl.onboarding.restartRequired": "Windows skal genstartes for at fuldføre installationen af WSL.", + "wsl.onboarding.ready": "WSL er klar.", + "wsl.onboarding.required": "WSL er påkrævet for at fortsætte.", + "wsl.onboarding.checkingDistros": "Tjekker distributioner...", + "wsl.onboarding.installingDistro": "Installerer {{distro}}...", + "wsl.onboarding.checkingDistro": "Tjekker {{distro}}...", + "wsl.onboarding.listingDistros": "Henter liste over distributioner...", + "wsl.onboarding.distroReady": "{{distro}} er klar.", + "wsl.onboarding.distroNotInstalled": "{{distro}} er ikke installeret endnu.", + "wsl.onboarding.openDistroOnce": "Åbn {{distro}} én gang for at fuldføre opsætningen.", + "wsl.onboarding.finishingDistro": "Fuldfører opsætningen af {{distro}}.", + "wsl.onboarding.pickDistro": "Vælg en distribution, eller installer en nedenfor.", + "wsl.onboarding.checkingOpencode": "Tjekker OpenCode...", + "wsl.onboarding.checkingOpencodeIn": "Tjekker OpenCode i {{distro}}...", + "wsl.onboarding.updatingOpencode": "Opdaterer OpenCode...", + "wsl.onboarding.updatingOpencodeIn": "Opdaterer OpenCode i {{distro}}...", + "wsl.onboarding.updateOpencodeIn": "Opdater OpenCode i {{distro}}.", + "wsl.onboarding.updateOpencode": "Opdater OpenCode", + "wsl.onboarding.opencodeReadyIn": "OpenCode er klar i {{distro}}.", + "wsl.onboarding.opencodeReady": "OpenCode er klar.", + "wsl.onboarding.installOpencodeIn": "Installer OpenCode i {{distro}}.", + "wsl.onboarding.installOpencode": "Installer OpenCode", + "wsl.onboarding.chooseDistroFirst": "Vælg først en distribution.", + "wsl.onboarding.loadFailed": "Kunne ikke indlæse WSL-status.", + "wsl.onboarding.loading": "Indlæser...", + "wsl.onboarding.installedDistros": "Installerede distributioner", + "wsl.onboarding.checkAgain": "Tjek igen", + "wsl.onboarding.distroStatus.ready": "Klar", + "wsl.onboarding.distroStatus.checking": "Tjekker...", + "wsl.onboarding.distroStatus.opencodeMissing": "OpenCode er ikke installeret", + "wsl.onboarding.distroStatus.missingTools": "Mangler bash, curl", + "wsl.onboarding.distroStatus.unsupported": "Ikke understøttet · Brug WSL 2", + "wsl.onboarding.needAnotherDistro": "Har du brug for en anden distribution?", + "wsl.onboarding.needAnotherDistroHint": "Installer en Linux-distribution fra WSL-kataloget", + "wsl.onboarding.wslNotInstalled.title": "WSL er ikke installeret", + "wsl.onboarding.wslNotInstalled.description": + "WSL (Windows Subsystem for Linux) er påkrævet, før OpenCode kan tilføje en WSL-server", + "wsl.onboarding.wslUnavailable.title": "WSL er ikke tilgængelig", + "wsl.onboarding.wslUnavailable.description": "OpenCode kunne ikke bekræfte WSL på denne maskine.", + "wsl.onboarding.installWsl": "Installer WSL", + "wsl.onboarding.windowsRestartRequired": + "Genstart Windows for at fuldføre installationen af WSL, og åbn derefter OpenCode igen.", + "wsl.onboarding.next": "Næste", + "wsl.onboarding.refresh": "Opdater", + "wsl.onboarding.allDistrosAdded": "Alle installerede distributioner er allerede tilføjet.", + "wsl.onboarding.noDistros": "Ingen distributioner fundet endnu.", + "wsl.onboarding.install": "Installer", + "wsl.onboarding.installing": "Installerer...", + "wsl.onboarding.installDistro": "Installer distribution", + "wsl.onboarding.searchDistros": "Søg efter distributioner", + "wsl.onboarding.wsl2Required": "WSL 2 er påkrævet.", + "wsl.onboarding.toolsRequired": "Denne distribution kræver bash og curl.", + "wsl.onboarding.openTerminal": "Åbn terminal", + "wsl.onboarding.path": "Sti: {{path}}", + "wsl.onboarding.notFound": "ikke fundet", + "wsl.onboarding.version": "Version: {{version}}", + "wsl.onboarding.unknown": "ukendt", + "wsl.onboarding.desktopVersion": "desktop {{version}}", + "wsl.onboarding.versionMismatch": "Den installerede version matcher ikke desktopappens version.", + "wsl.onboarding.adding": "Tilføjer...", "dialog.project.edit.title": "Rediger projekt", "dialog.project.edit.name": "Navn", @@ -403,6 +484,7 @@ export const dict = { "language.no": "Norsk", "language.br": "Português (Brasil)", "language.bs": "Bosanski", + "language.uk": "Українська", "language.th": "ไทย", "language.tr": "Türkçe", @@ -450,10 +532,12 @@ export const dict = { "error.page.title": "Noget gik galt", "error.page.description": "Der opstod en fejl under indlæsning af applikationen.", + "error.page.description.localServerStartup": "Der opstod en fejl under start af den lokale server.", "error.page.details.label": "Fejldetaljer", "error.page.action.restart": "Genstart", "error.page.action.report": "Rapportér fejl", "error.page.action.reported": "Fejl rapporteret", + "error.page.action.exportLogs": "Eksportér logfiler", "error.page.action.checking": "Tjekker...", "error.page.action.checkUpdates": "Tjek for opdateringer", "error.page.action.updateTo": "Opdater til {{version}}", @@ -501,11 +585,31 @@ export const dict = { "home.recentProjects": "Seneste projekter", "home.empty.title": "Ingen seneste projekter", "home.empty.description": "Kom i gang ved at åbne et lokalt projekt", + "home.title": "Hjem", + "home.projects": "Projekter", + "home.project.add": "Tilføj projekt", + "home.recentlyClosed": "Lukket for nylig", + "home.server.collapse": "Skjul serverprojekter", + "home.server.expand": "Udvid serverprojekter", + "home.sessions.search.placeholder": "Søg i sessioner", + "home.sessions.search.placeholder.scoped": "Søg i sessioner i {{scope}}", + "home.sessions.search.sessions": "Sessioner", + "home.sessions.search.noResults": "Ingen sessioner fundet for {{query}}", + "home.sessions.empty": "Intet her endnu", + "home.sessions.empty.description": "Opret en session for at komme i gang", + "home.sessions.group.today": "I dag", + "home.sessions.group.yesterday": "I går", + "home.sessions.group.older": "Ældre", "session.tab.session": "Session", "session.tab.review": "Gennemgang", "session.tab.context": "Kontekst", + "session.tab.unknown": "Ukendt session", "session.panel.reviewAndFiles": "Gennemgang og filer", + "session.error.notFound": "Denne session kan ikke findes", + "session.error.notFound.description": "Denne fane henviser til en session, der ikke længere findes på denne server.", + "session.error.notFound.closeTab": "Luk fane", + "session.error.serverConnection": "Kan ikke oprette forbindelse til denne server", "session.review.filesChanged": "{{count}} Filer ændret", "session.review.change.one": "Ændring", "session.review.change.other": "Ændringer", @@ -515,6 +619,8 @@ export const dict = { "session.review.noSnapshot": "Snapshot-sporing er deaktiveret i konfigurationen, så sessionsændringer er ikke tilgængelige", "session.review.noChanges": "Ingen ændringer", + "session.review.noUncommittedChanges": "Ingen ændringer uden commit endnu", + "session.review.noBranchChanges": "Ingen grenændringer endnu", "session.files.selectToOpen": "Vælg en fil at åbne", "session.files.all": "Alle filer", "session.files.empty": "Ingen filer", @@ -526,9 +632,10 @@ export const dict = { "session.messages.jumpToLatest": "Gå til seneste", "session.context.addToContext": "Tilføj {{selection}} til kontekst", - "session.todo.title": "Opgaver", - "session.todo.collapse": "Skjul", - "session.todo.expand": "Udvid", + "session.question.minimize": "Minimer spørgsmål", + "session.question.restore": "Gendan spørgsmål", + "session.question.pending.one": "{{count}} afventende spørgsmål", + "session.question.pending.other": "{{count}} afventende spørgsmål", "session.followupDock.summary.one": "{{count}} besked i kø", "session.followupDock.summary.other": "{{count}} beskeder i kø", "session.followupDock.sendNow": "Send nu", @@ -542,9 +649,16 @@ export const dict = { "session.revertDock.restore": "Gendan besked", "session.new.title": "Byg hvad som helst", + "session.new.project.new": "Nyt projekt", + "session.new.project.search": "Søg efter projekter", + "session.new.project.add": "Tilføj projekt", "session.new.worktree.main": "Hovedgren", "session.new.worktree.mainWithBranch": "Hovedgren ({{branch}})", "session.new.worktree.create": "Opret nyt worktree", + "session.new.workspace.runIn": "Kør session i", + "session.new.workspace.triggerLocal": "Lokal", + "session.new.workspace.local": "Lokalt repository", + "session.new.workspace.existing": "Arbejdsområde…", "session.new.lastModified": "Sidst ændret", "session.header.search.placeholder": "Søg {{project}}", @@ -614,6 +728,8 @@ export const dict = { "sidebar.project.recentSessions": "Seneste sessioner", "sidebar.project.viewAllSessions": "Vis alle sessioner", "sidebar.project.clearNotifications": "Ryd notifikationer", + "sidebar.empty.title": "Ingen åbne projekter", + "sidebar.empty.description": "Åbn et projekt for at komme i gang", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "Desktop", @@ -625,6 +741,7 @@ export const dict = { "settings.desktop.wsl.description": "Kør OpenCode-serveren inde i WSL på Windows.", "settings.general.section.appearance": "Udseende", + "settings.general.section.advanced": "Avanceret", "settings.general.section.notifications": "Systemmeddelelser", "settings.general.section.updates": "Opdateringer", "settings.general.section.sounds": "Lydeffekter", @@ -633,6 +750,11 @@ export const dict = { "settings.general.row.language.title": "Sprog", "settings.general.row.language.description": "Ændr visningssproget for OpenCode", + "settings.general.row.shell.title": "Terminalshell", + "settings.general.row.shell.description": + "Vælg den shell, der bruges i din terminal. Kompatible shells bruges også til agentens værktøjskald.", + "settings.general.row.shell.autoDefault": "Automatisk (standard)", + "settings.general.row.shell.terminalOnly": "kun terminal", "settings.general.row.appearance.title": "Udseende", "settings.general.row.appearance.description": "Tilpas hvordan OpenCode ser ud på din enhed", "settings.general.row.colorScheme.title": "Farveskema", @@ -641,14 +763,29 @@ export const dict = { "settings.general.row.theme.description": "Tilpas hvordan OpenCode er temabestemt.", "settings.general.row.font.title": "Kode-skrifttype", "settings.general.row.font.description": "Tilpas skrifttypen, der bruges i kodeblokke", - "settings.general.row.terminalFont.title": "Terminal Font", - "settings.general.row.terminalFont.description": "Customise the font used in the terminal", + "settings.general.row.terminalFont.title": "Terminalskrifttype", + "settings.general.row.terminalFont.description": "Tilpas den skrifttype, der bruges i terminalen", "settings.general.row.uiFont.title": "UI-skrifttype", "settings.general.row.uiFont.description": "Tilpas skrifttypen, der bruges i hele brugerfladen", "settings.general.row.followup.title": "Opfølgningsadfærd", "settings.general.row.followup.description": "Vælg om opfølgende forespørgsler skal styre straks eller vente i kø", "settings.general.row.followup.option.queue": "Kø", "settings.general.row.followup.option.steer": "Styr", + "settings.general.row.showFileTree.title": "Filtræ", + "settings.general.row.showFileTree.description": "Vis filtræspanelet i sessioner", + "settings.general.row.showNavigation.title": "Navigationsknapper", + "settings.general.row.showNavigation.description": "Vis tilbage- og frem-knapperne i desktopappens titellinje", + "settings.general.row.showSearch.title": "Kommandopalette", + "settings.general.row.showSearch.description": "Vis knappen til søgning og kommandopaletten i titellinjen", + "settings.general.row.showTerminal.title": "Terminal", + "settings.general.row.showTerminal.description": "Vis terminalknappen i desktopappens titellinje", + "settings.general.row.showStatus.title": "Serverstatus", + "settings.general.row.showStatus.description": "Vis serverstatusknappen i titellinjen", + "settings.general.row.mobileTitlebarBottom.title": "Navigation nederst", + "settings.general.row.mobileTitlebarBottom.description": + "Placer titellinjen og sessionsfanerne nederst på skærmen på mobilenheder", + "settings.general.row.showCustomAgents.title": "Brugerdefinerede agenter", + "settings.general.row.showCustomAgents.description": "Vis agentvælgeren i promptfeltet", "settings.general.row.reasoningSummaries.title": "Vis tænkeoversigter", "settings.general.row.reasoningSummaries.description": "Vis model tænkeoversigter i tidslinjen", @@ -657,6 +794,11 @@ export const dict = { "settings.general.row.editToolPartsExpanded.title": "Udvid edit-værktøjsdele", "settings.general.row.editToolPartsExpanded.description": "Vis edit-, write- og patch-værktøjsdele udvidet som standard i tidslinjen", + "settings.general.row.newLayoutDesigns.title": "Nyt layout og design", + "settings.general.row.newLayoutDesigns.description": + "Aktivér det nydesignede layout, startsiden, promptfeltet og sessionsbrugerfladen", + "settings.general.row.pinchZoom.title": "Knib for at zoome", + "settings.general.row.pinchZoom.description": "Tillad knibebevægelser på pegefeltet og Ctrl-rulning for at zoome", "settings.general.row.wayland.title": "Brug native Wayland", "settings.general.row.wayland.description": "Deaktiver X11-fallback på Wayland. Kræver genstart.", "settings.general.row.wayland.tooltip": @@ -671,6 +813,8 @@ export const dict = { "settings.updates.row.check.description": "Tjek manuelt for opdateringer og installer, hvis tilgængelig", "settings.updates.action.checkNow": "Tjek nu", "settings.updates.action.checking": "Tjekker...", + "settings.updates.action.downloading": "Downloader...", + "settings.updates.action.installing": "Installerer...", "settings.updates.toast.latest.title": "Du er opdateret", "settings.updates.toast.latest.description": "Du kører den nyeste version af OpenCode.", @@ -799,8 +943,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Indlæs en færdighed efter navn", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Kør sprogserverforespørgsler", - "settings.permissions.tool.todowrite.title": "Skriv To-do", - "settings.permissions.tool.todowrite.description": "Opdater to-do listen", "settings.permissions.tool.webfetch.title": "Webhentning", "settings.permissions.tool.webfetch.description": "Hent indhold fra en URL", "settings.permissions.tool.websearch.title": "Websøgning", @@ -865,7 +1007,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Spor, gennemgå og fortryd ændringer i dette projekt", "session.review.noVcs.createGit.actionLoading": "Opretter Git-repository...", "session.review.noVcs.createGit.action": "Opret Git-repository", - "session.todo.progress": "{{done}} af {{total}} opgaver fuldført", "session.question.progress": "{{current}} af {{total}} spørgsmål", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Stifinder", diff --git a/packages/app/src/i18n/de.ts b/packages/app/src/i18n/de.ts index d0ec9507e0..2895f57837 100644 --- a/packages/app/src/i18n/de.ts +++ b/packages/app/src/i18n/de.ts @@ -25,6 +25,9 @@ export const dict = { "theme.scheme.dark": "Dunkel", "command.sidebar.toggle": "Seitenleiste umschalten", "command.project.open": "Projekt öffnen", + "command.project.previous": "Vorheriges Projekt", + "command.project.next": "Nächstes Projekt", + "command.project.index": "Zu Projekt {{index}} wechseln", "command.provider.connect": "Anbieter verbinden", "command.server.switch": "Server wechseln", "command.settings.open": "Einstellungen öffnen", @@ -43,6 +46,7 @@ export const dict = { "command.session.new": "Neue Sitzung", "command.file.open": "Datei öffnen", "command.tab.close": "Tab schließen", + "command.tab.reopenClosed": "Geschlossenen Tab wieder öffnen", "command.context.addSelection": "Auswahl zum Kontext hinzufügen", "command.context.addSelection.description": "Ausgewählte Zeilen aus der aktuellen Datei hinzufügen", "command.input.focus": "Eingabefeld fokussieren", @@ -198,6 +202,11 @@ export const dict = { "model.input.video": "Video", "model.input.pdf": "PDF", "model.tooltip.allows": "Erlaubt: {{inputs}}", + "model.tooltip.context.label": "Kontext", + "model.tooltip.inputs": "Eingaben", + "model.tooltip.model": "Modell", + "model.tooltip.provider": "Anbieter", + "model.tooltip.reasoning": "Reasoning", "model.tooltip.reasoning.allowed": "Erlaubt Reasoning", "model.tooltip.reasoning.none": "Kein Reasoning", "model.tooltip.context": "Kontextlimit {{limit}}", @@ -207,6 +216,7 @@ export const dict = { "common.loading": "Laden", "common.loading.ellipsis": "...", "common.cancel": "Abbrechen", + "common.clear": "Leeren", "common.connect": "Verbinden", "common.disconnect": "Trennen", "common.continue": "Absenden", @@ -223,6 +233,8 @@ export const dict = { "prompt.mode.shell": "Shell", "prompt.mode.normal": "Prompt", "prompt.mode.shell.exit": "esc zum Verlassen", + "session.child.promptDisabled": "Unteragenten-Sitzungen können keine Prompts erhalten.", + "session.child.backToParent": "Zurück zur Hauptsitzung.", "prompt.example.1": "Ein TODO in der Codebasis beheben", "prompt.example.2": "Was ist der Tech-Stack dieses Projekts?", "prompt.example.3": "Fehlerhafte Tests beheben", @@ -320,6 +332,75 @@ export const dict = { "dialog.server.menu.delete": "Löschen", "dialog.server.current": "Aktueller Server", "dialog.server.status.default": "Standard", + "wsl.server.add": "WSL-Server hinzufügen", + "wsl.server.addShort": "WSL hinzufügen", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "WSL-Server", + "wsl.server.retryStart": "Start erneut versuchen", + "wsl.server.updating": "Wird aktualisiert...", + "wsl.onboarding.step.distro": "Distribution auswählen", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "WSL wird geprüft...", + "wsl.onboarding.restartRequired": "Windows muss neu gestartet werden, um die WSL-Installation abzuschließen.", + "wsl.onboarding.ready": "WSL ist bereit.", + "wsl.onboarding.required": "WSL ist erforderlich, um fortzufahren.", + "wsl.onboarding.checkingDistros": "Distributionen werden geprüft...", + "wsl.onboarding.installingDistro": "{{distro}} wird installiert...", + "wsl.onboarding.checkingDistro": "{{distro}} wird geprüft...", + "wsl.onboarding.listingDistros": "Distributionen werden aufgelistet...", + "wsl.onboarding.distroReady": "{{distro}} ist bereit.", + "wsl.onboarding.distroNotInstalled": "{{distro}} ist noch nicht installiert.", + "wsl.onboarding.openDistroOnce": "Öffnen Sie {{distro}} einmal, um die Einrichtung abzuschließen.", + "wsl.onboarding.finishingDistro": "Einrichtung von {{distro}} wird abgeschlossen.", + "wsl.onboarding.pickDistro": "Wählen Sie eine Distribution aus oder installieren Sie unten eine.", + "wsl.onboarding.checkingOpencode": "OpenCode wird geprüft...", + "wsl.onboarding.checkingOpencodeIn": "OpenCode in {{distro}} wird geprüft...", + "wsl.onboarding.updatingOpencode": "OpenCode wird aktualisiert...", + "wsl.onboarding.updatingOpencodeIn": "OpenCode in {{distro}} wird aktualisiert...", + "wsl.onboarding.updateOpencodeIn": "Aktualisieren Sie OpenCode in {{distro}}.", + "wsl.onboarding.updateOpencode": "OpenCode aktualisieren", + "wsl.onboarding.opencodeReadyIn": "OpenCode ist in {{distro}} bereit.", + "wsl.onboarding.opencodeReady": "OpenCode ist bereit.", + "wsl.onboarding.installOpencodeIn": "Installieren Sie OpenCode in {{distro}}.", + "wsl.onboarding.installOpencode": "OpenCode installieren", + "wsl.onboarding.chooseDistroFirst": "Wählen Sie zuerst eine Distribution aus.", + "wsl.onboarding.loadFailed": "WSL-Status konnte nicht geladen werden.", + "wsl.onboarding.loading": "Wird geladen...", + "wsl.onboarding.installedDistros": "Installierte Distributionen", + "wsl.onboarding.checkAgain": "Erneut prüfen", + "wsl.onboarding.distroStatus.ready": "Bereit", + "wsl.onboarding.distroStatus.checking": "Wird geprüft...", + "wsl.onboarding.distroStatus.opencodeMissing": "OpenCode nicht installiert", + "wsl.onboarding.distroStatus.missingTools": "Fehlend: bash, curl", + "wsl.onboarding.distroStatus.unsupported": "Nicht unterstützt · WSL 2 verwenden", + "wsl.onboarding.needAnotherDistro": "Andere Distribution benötigt?", + "wsl.onboarding.needAnotherDistroHint": "Installieren Sie eine Linux-Distribution aus dem WSL-Katalog", + "wsl.onboarding.wslNotInstalled.title": "WSL nicht installiert", + "wsl.onboarding.wslNotInstalled.description": + "WSL (Windows Subsystem for Linux) ist erforderlich, bevor OpenCode einen WSL-Server hinzufügen kann", + "wsl.onboarding.wslUnavailable.title": "WSL nicht verfügbar", + "wsl.onboarding.wslUnavailable.description": "OpenCode konnte WSL auf diesem Computer nicht überprüfen.", + "wsl.onboarding.installWsl": "WSL installieren", + "wsl.onboarding.windowsRestartRequired": + "Starten Sie Windows neu, um die WSL-Installation abzuschließen, und öffnen Sie dann OpenCode erneut.", + "wsl.onboarding.next": "Weiter", + "wsl.onboarding.refresh": "Aktualisieren", + "wsl.onboarding.allDistrosAdded": "Alle installierten Distributionen wurden bereits hinzugefügt.", + "wsl.onboarding.noDistros": "Noch keine Distributionen erkannt.", + "wsl.onboarding.install": "Installieren", + "wsl.onboarding.installing": "Wird installiert...", + "wsl.onboarding.installDistro": "Distribution installieren", + "wsl.onboarding.searchDistros": "Distributionen durchsuchen", + "wsl.onboarding.wsl2Required": "WSL 2 ist erforderlich.", + "wsl.onboarding.toolsRequired": "Diese Distribution benötigt bash und curl.", + "wsl.onboarding.openTerminal": "Terminal öffnen", + "wsl.onboarding.path": "Pfad: {{path}}", + "wsl.onboarding.notFound": "nicht gefunden", + "wsl.onboarding.version": "Version: {{version}}", + "wsl.onboarding.unknown": "unbekannt", + "wsl.onboarding.desktopVersion": "Desktop {{version}}", + "wsl.onboarding.versionMismatch": "Die installierte Version entspricht nicht der Version der Desktop-App.", + "wsl.onboarding.adding": "Wird hinzugefügt...", "dialog.project.edit.title": "Projekt bearbeiten", "dialog.project.edit.name": "Name", "dialog.project.edit.icon": "Icon", @@ -378,6 +459,7 @@ export const dict = { "language.no": "Norsk", "language.br": "Português (Brasil)", "language.bs": "Bosanski", + "language.uk": "Українська", "language.th": "ไทย", "language.tr": "Türkçe", "toast.language.title": "Sprache", @@ -414,10 +496,12 @@ export const dict = { "toast.update.action.notYet": "Noch nicht", "error.page.title": "Etwas ist schiefgelaufen", "error.page.description": "Beim Laden der Anwendung ist ein Fehler aufgetreten.", + "error.page.description.localServerStartup": "Beim Starten des lokalen Servers ist ein Fehler aufgetreten.", "error.page.details.label": "Fehlerdetails", "error.page.action.restart": "Neustart", "error.page.action.report": "Fehler melden", "error.page.action.reported": "Fehler gemeldet", + "error.page.action.exportLogs": "Protokolle exportieren", "error.page.action.checking": "Prüfen...", "error.page.action.checkUpdates": "Nach Updates suchen", "error.page.action.updateTo": "Auf {{version}} aktualisieren", @@ -461,10 +545,31 @@ export const dict = { "home.recentProjects": "Letzte Projekte", "home.empty.title": "Keine letzten Projekte", "home.empty.description": "Starten Sie, indem Sie ein lokales Projekt öffnen", + "home.title": "Startseite", + "home.projects": "Projekte", + "home.project.add": "Projekt hinzufügen", + "home.recentlyClosed": "Kürzlich geschlossen", + "home.server.collapse": "Serverprojekte einklappen", + "home.server.expand": "Serverprojekte ausklappen", + "home.sessions.search.placeholder": "Sitzungen durchsuchen", + "home.sessions.search.placeholder.scoped": "Sitzungen in {{scope}} durchsuchen", + "home.sessions.search.sessions": "Sitzungen", + "home.sessions.search.noResults": "Keine Sitzungen für {{query}} gefunden", + "home.sessions.empty": "Hier ist noch nichts", + "home.sessions.empty.description": "Erstellen Sie eine Sitzung, um loszulegen", + "home.sessions.group.today": "Heute", + "home.sessions.group.yesterday": "Gestern", + "home.sessions.group.older": "Älter", "session.tab.session": "Sitzung", "session.tab.review": "Überprüfung", "session.tab.context": "Kontext", + "session.tab.unknown": "Unbekannte Sitzung", "session.panel.reviewAndFiles": "Überprüfung und Dateien", + "session.error.notFound": "Diese Sitzung wurde nicht gefunden", + "session.error.notFound.description": + "Dieser Tab verweist auf eine Sitzung, die auf diesem Server nicht mehr existiert.", + "session.error.notFound.closeTab": "Tab schließen", + "session.error.serverConnection": "Verbindung zu diesem Server nicht möglich", "session.review.filesChanged": "{{count}} Dateien geändert", "session.review.change.one": "Änderung", "session.review.change.other": "Änderungen", @@ -474,6 +579,8 @@ export const dict = { "session.review.noSnapshot": "Snapshot-Tracking ist in der Konfiguration deaktiviert, daher sind Sitzungsänderungen nicht verfügbar", "session.review.noChanges": "Keine Änderungen", + "session.review.noUncommittedChanges": "Noch keine nicht committeten Änderungen", + "session.review.noBranchChanges": "Noch keine Branch-Änderungen", "session.files.selectToOpen": "Datei zum Öffnen auswählen", "session.files.all": "Alle Dateien", "session.files.empty": "Keine Dateien", @@ -484,9 +591,10 @@ export const dict = { "session.messages.loading": "Lade Nachrichten...", "session.messages.jumpToLatest": "Zum neuesten springen", "session.context.addToContext": "{{selection}} zum Kontext hinzufügen", - "session.todo.title": "Aufgaben", - "session.todo.collapse": "Einklappen", - "session.todo.expand": "Ausklappen", + "session.question.minimize": "Frage minimieren", + "session.question.restore": "Frage wiederherstellen", + "session.question.pending.one": "{{count}} ausstehende Frage", + "session.question.pending.other": "{{count}} ausstehende Fragen", "session.followupDock.summary.one": "{{count}} Nachricht in der Warteschlange", "session.followupDock.summary.other": "{{count}} Nachrichten in der Warteschlange", "session.followupDock.sendNow": "Jetzt senden", @@ -499,9 +607,16 @@ export const dict = { "session.revertDock.expand": "Zurückgesetzte Nachrichten ausklappen", "session.revertDock.restore": "Nachricht wiederherstellen", "session.new.title": "Baue, was du willst", + "session.new.project.new": "Neues Projekt", + "session.new.project.search": "Projekte durchsuchen", + "session.new.project.add": "Projekt hinzufügen", "session.new.worktree.main": "Haupt-Branch", "session.new.worktree.mainWithBranch": "Haupt-Branch ({{branch}})", "session.new.worktree.create": "Neuen Worktree erstellen", + "session.new.workspace.runIn": "Sitzung ausführen in", + "session.new.workspace.triggerLocal": "Lokal", + "session.new.workspace.local": "Lokales Repository", + "session.new.workspace.existing": "Arbeitsbereich…", "session.new.lastModified": "Zuletzt geändert", "session.header.search.placeholder": "{{project}} durchsuchen", "session.header.searchFiles": "Dateien suchen", @@ -566,6 +681,8 @@ export const dict = { "sidebar.project.recentSessions": "Letzte Sitzungen", "sidebar.project.viewAllSessions": "Alle Sitzungen anzeigen", "sidebar.project.clearNotifications": "Benachrichtigungen löschen", + "sidebar.empty.title": "Keine Projekte geöffnet", + "sidebar.empty.description": "Öffnen Sie ein Projekt, um loszulegen", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "Desktop", "settings.section.server": "Server", @@ -575,6 +692,7 @@ export const dict = { "settings.desktop.wsl.title": "WSL-Integration", "settings.desktop.wsl.description": "OpenCode-Server innerhalb von WSL unter Windows ausführen.", "settings.general.section.appearance": "Erscheinungsbild", + "settings.general.section.advanced": "Erweitert", "settings.general.section.notifications": "Systembenachrichtigungen", "settings.general.section.updates": "Updates", "settings.general.section.sounds": "Soundeffekte", @@ -582,6 +700,11 @@ export const dict = { "settings.general.section.display": "Anzeige", "settings.general.row.language.title": "Sprache", "settings.general.row.language.description": "Die Anzeigesprache für OpenCode ändern", + "settings.general.row.shell.title": "Terminal-Shell", + "settings.general.row.shell.description": + "Wählen Sie die Shell für Ihr Terminal aus. Kompatible Shells werden auch für Tool-Aufrufe von Agenten verwendet.", + "settings.general.row.shell.autoDefault": "Automatisch (Standard)", + "settings.general.row.shell.terminalOnly": "nur Terminal", "settings.general.row.appearance.title": "Erscheinungsbild", "settings.general.row.appearance.description": "Anpassen, wie OpenCode auf Ihrem Gerät aussieht", "settings.general.row.colorScheme.title": "Farbschema", @@ -591,8 +714,8 @@ export const dict = { "settings.general.row.theme.description": "Das Thema von OpenCode anpassen.", "settings.general.row.font.title": "Code-Schriftart", "settings.general.row.font.description": "Die in Codeblöcken verwendete Schriftart anpassen", - "settings.general.row.terminalFont.title": "Terminal Font", - "settings.general.row.terminalFont.description": "Customise the font used in the terminal", + "settings.general.row.terminalFont.title": "Terminalschriftart", + "settings.general.row.terminalFont.description": "Passe die im Terminal verwendete Schriftart an", "settings.general.row.uiFont.title": "UI-Schriftart", "settings.general.row.uiFont.description": "Die im gesamten Interface verwendete Schriftart anpassen", "settings.general.row.followup.title": "Verhalten bei Folgefragen", @@ -600,6 +723,23 @@ export const dict = { "Wählen Sie, ob Folgefragen sofort steuern oder in einer Warteschlange warten", "settings.general.row.followup.option.queue": "Warteschlange", "settings.general.row.followup.option.steer": "Steuern", + "settings.general.row.showFileTree.title": "Dateibaum", + "settings.general.row.showFileTree.description": "Dateibaum in Sitzungen anzeigen", + "settings.general.row.showNavigation.title": "Navigationssteuerung", + "settings.general.row.showNavigation.description": + "Schaltflächen zum Vor- und Zurücknavigieren in der Desktop-Titelleiste anzeigen", + "settings.general.row.showSearch.title": "Befehlspalette", + "settings.general.row.showSearch.description": + "Schaltfläche für Suche und Befehlspalette in der Titelleiste anzeigen", + "settings.general.row.showTerminal.title": "Terminal", + "settings.general.row.showTerminal.description": "Terminal-Schaltfläche in der Desktop-Titelleiste anzeigen", + "settings.general.row.showStatus.title": "Serverstatus", + "settings.general.row.showStatus.description": "Serverstatus-Schaltfläche in der Titelleiste anzeigen", + "settings.general.row.mobileTitlebarBottom.title": "Navigation unten", + "settings.general.row.mobileTitlebarBottom.description": + "Titelleiste und Sitzungs-Tabs auf Mobilgeräten am unteren Bildschirmrand platzieren", + "settings.general.row.showCustomAgents.title": "Benutzerdefinierte Agenten", + "settings.general.row.showCustomAgents.description": "Agentenauswahl im Eingabebereich anzeigen", "settings.general.row.reasoningSummaries.title": "Reasoning-Zusammenfassungen anzeigen", "settings.general.row.reasoningSummaries.description": "Zusammenfassungen des Modell-Reasonings in der Timeline anzeigen", @@ -609,6 +749,11 @@ export const dict = { "settings.general.row.editToolPartsExpanded.title": "Edit-Tool-Abschnitte ausklappen", "settings.general.row.editToolPartsExpanded.description": "Edit-, Write- und Patch-Tool-Abschnitte standardmäßig in der Timeline ausgeklappt anzeigen", + "settings.general.row.newLayoutDesigns.title": "Neues Layout und Design", + "settings.general.row.newLayoutDesigns.description": + "Neu gestaltetes Layout, Startseite, Eingabebereich und Sitzungsoberfläche aktivieren", + "settings.general.row.pinchZoom.title": "Zoom per Fingergeste", + "settings.general.row.pinchZoom.description": "Zoomen per Zwei-Finger- und Ctrl-Scroll-Geste erlauben", "settings.general.row.wayland.title": "Natives Wayland verwenden", "settings.general.row.wayland.description": "X11-Fallback unter Wayland deaktivieren. Erfordert Neustart.", "settings.general.row.wayland.tooltip": @@ -621,6 +766,8 @@ export const dict = { "settings.updates.row.check.description": "Manuell nach Updates suchen und installieren, wenn verfügbar", "settings.updates.action.checkNow": "Jetzt prüfen", "settings.updates.action.checking": "Wird geprüft...", + "settings.updates.action.downloading": "Wird heruntergeladen...", + "settings.updates.action.installing": "Wird installiert...", "settings.updates.toast.latest.title": "Du bist auf dem neuesten Stand", "settings.updates.toast.latest.description": "Du verwendest die aktuelle Version von OpenCode.", "sound.option.none": "Keine", @@ -742,8 +889,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Eine Fähigkeit nach Namen laden", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Language-Server-Abfragen ausführen", - "settings.permissions.tool.todowrite.title": "Todo schreiben", - "settings.permissions.tool.todowrite.description": "Die Todo-Liste aktualisieren", "settings.permissions.tool.webfetch.title": "Web-Abruf", "settings.permissions.tool.webfetch.description": "Inhalt von einer URL abrufen", "settings.permissions.tool.websearch.title": "Web-Suche", @@ -807,7 +952,6 @@ export const dict = { "Änderungen in diesem Projekt verfolgen, überprüfen und rückgängig machen", "session.review.noVcs.createGit.actionLoading": "Git-Repository wird erstellt...", "session.review.noVcs.createGit.action": "Git-Repository erstellen", - "session.todo.progress": "{{done}} von {{total}} Aufgaben erledigt", "session.question.progress": "{{current}} von {{total}} Fragen", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Datei-Explorer", diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts index 66e60df30e..559c6ba17b 100644 --- a/packages/app/src/i18n/en.ts +++ b/packages/app/src/i18n/en.ts @@ -212,6 +212,11 @@ export const dict = { "model.input.video": "video", "model.input.pdf": "pdf", "model.tooltip.allows": "Allows: {{inputs}}", + "model.tooltip.context.label": "Context", + "model.tooltip.inputs": "Inputs", + "model.tooltip.model": "Model", + "model.tooltip.provider": "Provider", + "model.tooltip.reasoning": "Reasoning", "model.tooltip.reasoning.allowed": "Allows reasoning", "model.tooltip.reasoning.none": "No reasoning", "model.tooltip.context": "Context limit {{limit}}", @@ -654,10 +659,6 @@ export const dict = { "session.messages.jumpToLatest": "Jump to latest", "session.context.addToContext": "Add {{selection}} to context", - "session.todo.title": "Todos", - "session.todo.collapse": "Collapse", - "session.todo.expand": "Expand", - "session.todo.progress": "{{done}} of {{total}} todos completed", "session.question.progress": "{{current}} of {{total}} questions", "session.question.minimize": "Minimize question", "session.question.restore": "Restore question", @@ -1035,8 +1036,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Load a skill by name", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Run language server queries", - "settings.permissions.tool.todowrite.title": "Todo Write", - "settings.permissions.tool.todowrite.description": "Update the todo list", "settings.permissions.tool.webfetch.title": "Web Fetch", "settings.permissions.tool.webfetch.description": "Fetch content from a URL", "settings.permissions.tool.websearch.title": "Web Search", diff --git a/packages/app/src/i18n/es.ts b/packages/app/src/i18n/es.ts index a6371d7312..ec6205cf99 100644 --- a/packages/app/src/i18n/es.ts +++ b/packages/app/src/i18n/es.ts @@ -23,6 +23,9 @@ export const dict = { "command.sidebar.toggle": "Alternar barra lateral", "command.project.open": "Abrir proyecto", + "command.project.previous": "Proyecto anterior", + "command.project.next": "Siguiente proyecto", + "command.project.index": "Cambiar al proyecto {{index}}", "command.provider.connect": "Conectar proveedor", "command.server.switch": "Cambiar servidor", "command.settings.open": "Abrir ajustes", @@ -45,6 +48,7 @@ export const dict = { "command.session.new": "Nueva sesión", "command.file.open": "Abrir archivo", "command.tab.close": "Cerrar pestaña", + "command.tab.reopenClosed": "Reabrir pestaña cerrada", "command.context.addSelection": "Añadir selección al contexto", "command.context.addSelection.description": "Añadir las líneas seleccionadas del archivo actual", "command.input.focus": "Enfocar entrada", @@ -208,6 +212,11 @@ export const dict = { "model.input.video": "video", "model.input.pdf": "pdf", "model.tooltip.allows": "Permite: {{inputs}}", + "model.tooltip.context.label": "Contexto", + "model.tooltip.inputs": "Entradas", + "model.tooltip.model": "Modelo", + "model.tooltip.provider": "Proveedor", + "model.tooltip.reasoning": "Razonamiento", "model.tooltip.reasoning.allowed": "Permite razonamiento", "model.tooltip.reasoning.none": "Sin razonamiento", "model.tooltip.context": "Límite de contexto {{limit}}", @@ -218,6 +227,7 @@ export const dict = { "common.loading": "Cargando", "common.loading.ellipsis": "...", "common.cancel": "Cancelar", + "common.clear": "Limpiar", "common.connect": "Conectar", "common.disconnect": "Desconectar", "common.continue": "Enviar", @@ -235,6 +245,8 @@ export const dict = { "prompt.mode.shell": "Shell", "prompt.mode.normal": "Prompt", "prompt.mode.shell.exit": "esc para salir", + "session.child.promptDisabled": "No se pueden enviar prompts a las sesiones de subagentes.", + "session.child.backToParent": "Volver a la sesión principal.", "prompt.example.1": "Arreglar un TODO en el código", "prompt.example.2": "¿Cuál es el stack tecnológico de este proyecto?", @@ -341,6 +353,75 @@ export const dict = { "dialog.server.menu.delete": "Eliminar", "dialog.server.current": "Servidor actual", "dialog.server.status.default": "Predeterminado", + "wsl.server.add": "Añadir servidor WSL", + "wsl.server.addShort": "Añadir WSL", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "Servidor WSL", + "wsl.server.retryStart": "Reintentar el inicio", + "wsl.server.updating": "Actualizando...", + "wsl.onboarding.step.distro": "Elegir distribución", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "Comprobando WSL...", + "wsl.onboarding.restartRequired": "Es necesario reiniciar Windows para terminar de instalar WSL.", + "wsl.onboarding.ready": "WSL está listo.", + "wsl.onboarding.required": "Se necesita WSL para continuar.", + "wsl.onboarding.checkingDistros": "Comprobando distribuciones...", + "wsl.onboarding.installingDistro": "Instalando {{distro}}...", + "wsl.onboarding.checkingDistro": "Comprobando {{distro}}...", + "wsl.onboarding.listingDistros": "Listando distribuciones...", + "wsl.onboarding.distroReady": "La distribución {{distro}} está lista.", + "wsl.onboarding.distroNotInstalled": "La distribución {{distro}} aún no está instalada.", + "wsl.onboarding.openDistroOnce": "Abre {{distro}} una vez para completar la configuración.", + "wsl.onboarding.finishingDistro": "Completando la configuración de {{distro}}.", + "wsl.onboarding.pickDistro": "Elige una distribución o instala una abajo.", + "wsl.onboarding.checkingOpencode": "Comprobando OpenCode...", + "wsl.onboarding.checkingOpencodeIn": "Comprobando OpenCode en {{distro}}...", + "wsl.onboarding.updatingOpencode": "Actualizando OpenCode...", + "wsl.onboarding.updatingOpencodeIn": "Actualizando OpenCode en {{distro}}...", + "wsl.onboarding.updateOpencodeIn": "Actualiza OpenCode en {{distro}}.", + "wsl.onboarding.updateOpencode": "Actualizar OpenCode", + "wsl.onboarding.opencodeReadyIn": "OpenCode está listo en {{distro}}.", + "wsl.onboarding.opencodeReady": "OpenCode está listo.", + "wsl.onboarding.installOpencodeIn": "Instala OpenCode en {{distro}}.", + "wsl.onboarding.installOpencode": "Instalar OpenCode", + "wsl.onboarding.chooseDistroFirst": "Elige primero una distribución.", + "wsl.onboarding.loadFailed": "No se pudo cargar el estado de WSL.", + "wsl.onboarding.loading": "Cargando...", + "wsl.onboarding.installedDistros": "Distribuciones instaladas", + "wsl.onboarding.checkAgain": "Comprobar de nuevo", + "wsl.onboarding.distroStatus.ready": "Lista", + "wsl.onboarding.distroStatus.checking": "Comprobando...", + "wsl.onboarding.distroStatus.opencodeMissing": "OpenCode no está instalado", + "wsl.onboarding.distroStatus.missingTools": "Faltan bash y curl", + "wsl.onboarding.distroStatus.unsupported": "No compatible · Usa WSL 2", + "wsl.onboarding.needAnotherDistro": "¿Necesitas otra distribución?", + "wsl.onboarding.needAnotherDistroHint": "Instala una distribución de Linux desde el catálogo de WSL", + "wsl.onboarding.wslNotInstalled.title": "WSL no está instalado", + "wsl.onboarding.wslNotInstalled.description": + "Se necesita WSL (Subsistema de Windows para Linux) para que OpenCode pueda añadir un servidor WSL", + "wsl.onboarding.wslUnavailable.title": "WSL no disponible", + "wsl.onboarding.wslUnavailable.description": "OpenCode no pudo comprobar WSL en este equipo.", + "wsl.onboarding.installWsl": "Instalar WSL", + "wsl.onboarding.windowsRestartRequired": + "Reinicia Windows para terminar de instalar WSL y, después, vuelve a abrir OpenCode.", + "wsl.onboarding.next": "Siguiente", + "wsl.onboarding.refresh": "Actualizar", + "wsl.onboarding.allDistrosAdded": "Ya se han añadido todas las distribuciones instaladas.", + "wsl.onboarding.noDistros": "Aún no se han detectado distribuciones.", + "wsl.onboarding.install": "Instalar", + "wsl.onboarding.installing": "Instalando...", + "wsl.onboarding.installDistro": "Instalar distribución", + "wsl.onboarding.searchDistros": "Buscar distribuciones", + "wsl.onboarding.wsl2Required": "Se necesita WSL 2.", + "wsl.onboarding.toolsRequired": "Esta distribución necesita bash y curl.", + "wsl.onboarding.openTerminal": "Abrir terminal", + "wsl.onboarding.path": "Ruta: {{path}}", + "wsl.onboarding.notFound": "no encontrado", + "wsl.onboarding.version": "Versión: {{version}}", + "wsl.onboarding.unknown": "desconocida", + "wsl.onboarding.desktopVersion": "escritorio {{version}}", + "wsl.onboarding.versionMismatch": "La versión instalada no coincide con la versión de la aplicación de escritorio.", + "wsl.onboarding.adding": "Añadiendo...", "dialog.project.edit.title": "Editar proyecto", "dialog.project.edit.name": "Nombre", @@ -405,6 +486,7 @@ export const dict = { "language.no": "Norsk", "language.br": "Português (Brasil)", "language.bs": "Bosanski", + "language.uk": "Українська", "language.th": "ไทย", "language.tr": "Türkçe", @@ -453,10 +535,12 @@ export const dict = { "error.page.title": "Algo salió mal", "error.page.description": "Ocurrió un error al cargar la aplicación.", + "error.page.description.localServerStartup": "Ocurrió un error al iniciar el servidor local.", "error.page.details.label": "Detalles del error", "error.page.action.restart": "Reiniciar", "error.page.action.report": "Informar error", "error.page.action.reported": "Error informado", + "error.page.action.exportLogs": "Exportar registros", "error.page.action.checking": "Comprobando...", "error.page.action.checkUpdates": "Buscar actualizaciones", "error.page.action.updateTo": "Actualizar a {{version}}", @@ -505,11 +589,31 @@ export const dict = { "home.recentProjects": "Proyectos recientes", "home.empty.title": "Sin proyectos recientes", "home.empty.description": "Empieza abriendo un proyecto local", + "home.title": "Inicio", + "home.projects": "Proyectos", + "home.project.add": "Añadir proyecto", + "home.recentlyClosed": "Proyectos cerrados recientemente", + "home.server.collapse": "Contraer proyectos del servidor", + "home.server.expand": "Expandir proyectos del servidor", + "home.sessions.search.placeholder": "Buscar sesiones", + "home.sessions.search.placeholder.scoped": "Buscar sesiones en {{scope}}", + "home.sessions.search.sessions": "Sesiones", + "home.sessions.search.noResults": "No se encontraron sesiones para {{query}}", + "home.sessions.empty": "Aún no hay nada", + "home.sessions.empty.description": "Crea una sesión para empezar", + "home.sessions.group.today": "Hoy", + "home.sessions.group.yesterday": "Ayer", + "home.sessions.group.older": "Anteriores", "session.tab.session": "Sesión", "session.tab.review": "Revisión", "session.tab.context": "Contexto", + "session.tab.unknown": "Sesión desconocida", "session.panel.reviewAndFiles": "Revisión y archivos", + "session.error.notFound": "No se encuentra esta sesión", + "session.error.notFound.description": "Esta pestaña apunta a una sesión que ya no existe en este servidor.", + "session.error.notFound.closeTab": "Cerrar pestaña", + "session.error.serverConnection": "No se puede conectar a este servidor", "session.review.filesChanged": "{{count}} Archivos Cambiados", "session.review.change.one": "Cambio", "session.review.change.other": "Cambios", @@ -519,6 +623,8 @@ export const dict = { "session.review.noSnapshot": "El seguimiento de instantáneas está deshabilitado en la configuración, por lo que los cambios de sesión no están disponibles", "session.review.noChanges": "Sin cambios", + "session.review.noUncommittedChanges": "Aún no hay cambios sin confirmar", + "session.review.noBranchChanges": "Aún no hay cambios en la rama", "session.files.selectToOpen": "Selecciona un archivo para abrir", "session.files.all": "Todos los archivos", @@ -532,9 +638,10 @@ export const dict = { "session.messages.jumpToLatest": "Ir al último", "session.context.addToContext": "Añadir {{selection}} al contexto", - "session.todo.title": "Tareas", - "session.todo.collapse": "Contraer", - "session.todo.expand": "Expandir", + "session.question.minimize": "Minimizar pregunta", + "session.question.restore": "Restaurar pregunta", + "session.question.pending.one": "{{count}} pregunta pendiente", + "session.question.pending.other": "{{count}} preguntas pendientes", "session.followupDock.summary.one": "{{count}} mensaje en cola", "session.followupDock.summary.other": "{{count}} mensajes en cola", "session.followupDock.sendNow": "Enviar ahora", @@ -548,9 +655,16 @@ export const dict = { "session.revertDock.restore": "Restaurar mensaje", "session.new.title": "Construye lo que quieras", + "session.new.project.new": "Nuevo proyecto", + "session.new.project.search": "Buscar proyectos", + "session.new.project.add": "Añadir proyecto", "session.new.worktree.main": "Rama principal", "session.new.worktree.mainWithBranch": "Rama principal ({{branch}})", "session.new.worktree.create": "Crear nuevo árbol de trabajo", + "session.new.workspace.runIn": "Ejecutar sesión en", + "session.new.workspace.triggerLocal": "Local", + "session.new.workspace.local": "Repositorio local", + "session.new.workspace.existing": "Espacio de trabajo…", "session.new.lastModified": "Última modificación", "session.header.search.placeholder": "Buscar {{project}}", @@ -621,6 +735,8 @@ export const dict = { "sidebar.project.recentSessions": "Sesiones recientes", "sidebar.project.viewAllSessions": "Ver todas las sesiones", "sidebar.project.clearNotifications": "Borrar notificaciones", + "sidebar.empty.title": "No hay proyectos abiertos", + "sidebar.empty.description": "Abre un proyecto para empezar", "app.name.desktop": "OpenCode Desktop", @@ -633,6 +749,7 @@ export const dict = { "settings.desktop.wsl.description": "Ejecutar el servidor OpenCode dentro de WSL en Windows.", "settings.general.section.appearance": "Apariencia", + "settings.general.section.advanced": "Avanzado", "settings.general.section.notifications": "Notificaciones del sistema", "settings.general.section.updates": "Actualizaciones", "settings.general.section.sounds": "Efectos de sonido", @@ -641,6 +758,11 @@ export const dict = { "settings.general.row.language.title": "Idioma", "settings.general.row.language.description": "Cambiar el idioma de visualización para OpenCode", + "settings.general.row.shell.title": "Shell del terminal", + "settings.general.row.shell.description": + "Elige el shell que se usará en el terminal. Los shells compatibles también se usarán para las llamadas a herramientas del agente.", + "settings.general.row.shell.autoDefault": "Automático (Predeterminado)", + "settings.general.row.shell.terminalOnly": "solo en el terminal", "settings.general.row.appearance.title": "Apariencia", "settings.general.row.appearance.description": "Personaliza cómo se ve OpenCode en tu dispositivo", "settings.general.row.colorScheme.title": "Esquema de color", @@ -649,8 +771,8 @@ export const dict = { "settings.general.row.theme.description": "Personaliza el tema de OpenCode.", "settings.general.row.font.title": "Fuente de código", "settings.general.row.font.description": "Personaliza la fuente usada en bloques de código", - "settings.general.row.terminalFont.title": "Terminal Font", - "settings.general.row.terminalFont.description": "Customise the font used in the terminal", + "settings.general.row.terminalFont.title": "Fuente del terminal", + "settings.general.row.terminalFont.description": "Personaliza la fuente utilizada en el terminal", "settings.general.row.uiFont.title": "Fuente de la interfaz", "settings.general.row.uiFont.description": "Personaliza la fuente usada en toda la interfaz", "settings.general.row.followup.title": "Comportamiento de seguimiento", @@ -658,6 +780,23 @@ export const dict = { "Elige si los prompts de seguimiento se dirigen inmediatamente o esperan en una cola", "settings.general.row.followup.option.queue": "Cola", "settings.general.row.followup.option.steer": "Dirigir", + "settings.general.row.showFileTree.title": "Árbol de archivos", + "settings.general.row.showFileTree.description": "Mostrar el panel del árbol de archivos en las sesiones", + "settings.general.row.showNavigation.title": "Controles de navegación", + "settings.general.row.showNavigation.description": + "Mostrar los botones para retroceder y avanzar en la barra de título de la aplicación de escritorio", + "settings.general.row.showSearch.title": "Paleta de comandos", + "settings.general.row.showSearch.description": + "Mostrar el botón de búsqueda y paleta de comandos en la barra de título", + "settings.general.row.showTerminal.title": "Terminal", + "settings.general.row.showTerminal.description": "Mostrar el botón del terminal en la barra de título", + "settings.general.row.showStatus.title": "Estado del servidor", + "settings.general.row.showStatus.description": "Mostrar el botón de estado del servidor en la barra de título", + "settings.general.row.mobileTitlebarBottom.title": "Navegación inferior", + "settings.general.row.mobileTitlebarBottom.description": + "Colocar la barra de título y las pestañas de sesión en la parte inferior de la pantalla en dispositivos móviles", + "settings.general.row.showCustomAgents.title": "Agentes personalizados", + "settings.general.row.showCustomAgents.description": "Mostrar el selector de agentes en el editor", "settings.general.row.reasoningSummaries.title": "Mostrar resúmenes de razonamiento", "settings.general.row.reasoningSummaries.description": "Mostrar resúmenes del razonamiento del modelo en la línea de tiempo", @@ -667,6 +806,12 @@ export const dict = { "settings.general.row.editToolPartsExpanded.title": "Expandir partes de la herramienta de edición", "settings.general.row.editToolPartsExpanded.description": "Mostrar las partes de las herramientas de edición, escritura y parcheado expandidas por defecto en la línea de tiempo", + "settings.general.row.newLayoutDesigns.title": "Nuevo diseño y estilos", + "settings.general.row.newLayoutDesigns.description": + "Activar el nuevo diseño de la interfaz, la página de inicio, el editor y las sesiones", + "settings.general.row.pinchZoom.title": "Pellizcar para ampliar", + "settings.general.row.pinchZoom.description": + "Permitir ampliar con el gesto de pellizco del panel táctil y con Ctrl-scroll", "settings.general.row.wayland.title": "Usar Wayland nativo", "settings.general.row.wayland.description": "Deshabilitar fallback a X11 en Wayland. Requiere reinicio.", "settings.general.row.wayland.tooltip": @@ -682,6 +827,8 @@ export const dict = { "settings.updates.row.check.description": "Buscar actualizaciones manualmente e instalarlas si hay alguna", "settings.updates.action.checkNow": "Buscar ahora", "settings.updates.action.checking": "Buscando...", + "settings.updates.action.downloading": "Descargando...", + "settings.updates.action.installing": "Instalando...", "settings.updates.toast.latest.title": "Estás al día", "settings.updates.toast.latest.description": "Estás usando la última versión de OpenCode.", "sound.option.none": "Ninguno", @@ -812,8 +959,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Cargar una habilidad por nombre", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Ejecutar consultas de servidor de lenguaje", - "settings.permissions.tool.todowrite.title": "Escribir Todo", - "settings.permissions.tool.todowrite.description": "Actualizar la lista de tareas", "settings.permissions.tool.webfetch.title": "Web Fetch", "settings.permissions.tool.webfetch.description": "Obtener contenido de una URL", "settings.permissions.tool.websearch.title": "Búsqueda Web", @@ -878,7 +1023,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Rastrea, revisa y deshaz cambios en este proyecto", "session.review.noVcs.createGit.actionLoading": "Creando repositorio Git...", "session.review.noVcs.createGit.action": "Crear repositorio Git", - "session.todo.progress": "{{done}} de {{total}} tareas completadas", "session.question.progress": "{{current}} de {{total}} preguntas", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Explorador de archivos", diff --git a/packages/app/src/i18n/fr.ts b/packages/app/src/i18n/fr.ts index 7ebd34e66b..c5da265344 100644 --- a/packages/app/src/i18n/fr.ts +++ b/packages/app/src/i18n/fr.ts @@ -21,6 +21,9 @@ export const dict = { "theme.scheme.dark": "Sombre", "command.sidebar.toggle": "Basculer la barre latérale", "command.project.open": "Ouvrir un projet", + "command.project.previous": "Projet précédent", + "command.project.next": "Projet suivant", + "command.project.index": "Passer au projet {{index}}", "command.provider.connect": "Connecter un fournisseur", "command.server.switch": "Changer de serveur", "command.settings.open": "Ouvrir les paramètres", @@ -39,6 +42,7 @@ export const dict = { "command.session.new": "Nouvelle session", "command.file.open": "Ouvrir un fichier", "command.tab.close": "Fermer l'onglet", + "command.tab.reopenClosed": "Rouvrir l'onglet fermé", "command.context.addSelection": "Ajouter la sélection au contexte", "command.context.addSelection.description": "Ajouter les lignes sélectionnées du fichier actuel", "command.input.focus": "Focus sur l'entrée", @@ -193,6 +197,11 @@ export const dict = { "model.input.video": "vidéo", "model.input.pdf": "pdf", "model.tooltip.allows": "Autorise : {{inputs}}", + "model.tooltip.context.label": "Contexte", + "model.tooltip.inputs": "Entrées", + "model.tooltip.model": "Modèle", + "model.tooltip.provider": "Fournisseur", + "model.tooltip.reasoning": "Raisonnement", "model.tooltip.reasoning.allowed": "Autorise le raisonnement", "model.tooltip.reasoning.none": "Sans raisonnement", "model.tooltip.context": "Limite de contexte {{limit}}", @@ -202,6 +211,7 @@ export const dict = { "common.loading": "Chargement", "common.loading.ellipsis": "...", "common.cancel": "Annuler", + "common.clear": "Effacer", "common.connect": "Connecter", "common.disconnect": "Déconnecter", "common.continue": "Soumettre", @@ -218,6 +228,8 @@ export const dict = { "prompt.mode.shell": "Shell", "prompt.mode.normal": "Prompt", "prompt.mode.shell.exit": "esc pour quitter", + "session.child.promptDisabled": "Les sessions de sous-agents ne peuvent pas recevoir de messages.", + "session.child.backToParent": "Revenir à la session principale.", "prompt.example.1": "Corriger un TODO dans la base de code", "prompt.example.2": "Quelle est la pile technique de ce projet ?", "prompt.example.3": "Réparer les tests échoués", @@ -315,6 +327,75 @@ export const dict = { "dialog.server.menu.delete": "Supprimer", "dialog.server.current": "Serveur actuel", "dialog.server.status.default": "Défaut", + "wsl.server.add": "Ajouter un serveur WSL", + "wsl.server.addShort": "Ajouter WSL", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "Serveur WSL", + "wsl.server.retryStart": "Réessayer de démarrer", + "wsl.server.updating": "Mise à jour...", + "wsl.onboarding.step.distro": "Choisir une distribution", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "Vérification de WSL...", + "wsl.onboarding.restartRequired": "Windows doit redémarrer pour terminer l'installation de WSL.", + "wsl.onboarding.ready": "WSL est prêt.", + "wsl.onboarding.required": "WSL est requis pour continuer.", + "wsl.onboarding.checkingDistros": "Vérification des distributions...", + "wsl.onboarding.installingDistro": "Installation de {{distro}}...", + "wsl.onboarding.checkingDistro": "Vérification de {{distro}}...", + "wsl.onboarding.listingDistros": "Récupération de la liste des distributions...", + "wsl.onboarding.distroReady": "{{distro}} est prête.", + "wsl.onboarding.distroNotInstalled": "{{distro}} n'est pas encore installée.", + "wsl.onboarding.openDistroOnce": "Ouvrez {{distro}} une fois pour terminer la configuration.", + "wsl.onboarding.finishingDistro": "Finalisation de la configuration de {{distro}}.", + "wsl.onboarding.pickDistro": "Choisissez une distribution ou installez-en une ci-dessous.", + "wsl.onboarding.checkingOpencode": "Vérification d'OpenCode...", + "wsl.onboarding.checkingOpencodeIn": "Vérification d'OpenCode dans {{distro}}...", + "wsl.onboarding.updatingOpencode": "Mise à jour d'OpenCode...", + "wsl.onboarding.updatingOpencodeIn": "Mise à jour d'OpenCode dans {{distro}}...", + "wsl.onboarding.updateOpencodeIn": "Mettez à jour OpenCode dans {{distro}}.", + "wsl.onboarding.updateOpencode": "Mettre à jour OpenCode", + "wsl.onboarding.opencodeReadyIn": "OpenCode est prêt dans {{distro}}.", + "wsl.onboarding.opencodeReady": "OpenCode est prêt.", + "wsl.onboarding.installOpencodeIn": "Installez OpenCode dans {{distro}}.", + "wsl.onboarding.installOpencode": "Installer OpenCode", + "wsl.onboarding.chooseDistroFirst": "Choisissez d'abord une distribution.", + "wsl.onboarding.loadFailed": "Impossible de charger l'état de WSL.", + "wsl.onboarding.loading": "Chargement...", + "wsl.onboarding.installedDistros": "Distributions installées", + "wsl.onboarding.checkAgain": "Vérifier à nouveau", + "wsl.onboarding.distroStatus.ready": "Prête", + "wsl.onboarding.distroStatus.checking": "Vérification...", + "wsl.onboarding.distroStatus.opencodeMissing": "OpenCode non installé", + "wsl.onboarding.distroStatus.missingTools": "bash et curl manquants", + "wsl.onboarding.distroStatus.unsupported": "Non prise en charge · Utilisez WSL 2", + "wsl.onboarding.needAnotherDistro": "Besoin d'une autre distribution ?", + "wsl.onboarding.needAnotherDistroHint": "Installez une distribution Linux depuis le catalogue WSL", + "wsl.onboarding.wslNotInstalled.title": "WSL n'est pas installé", + "wsl.onboarding.wslNotInstalled.description": + "WSL (Windows Subsystem for Linux) est requis avant qu'OpenCode puisse ajouter un serveur WSL", + "wsl.onboarding.wslUnavailable.title": "WSL indisponible", + "wsl.onboarding.wslUnavailable.description": "OpenCode n'a pas pu vérifier WSL sur cet appareil.", + "wsl.onboarding.installWsl": "Installer WSL", + "wsl.onboarding.windowsRestartRequired": + "Redémarrez Windows pour terminer l'installation de WSL, puis rouvrez OpenCode.", + "wsl.onboarding.next": "Suivant", + "wsl.onboarding.refresh": "Actualiser", + "wsl.onboarding.allDistrosAdded": "Toutes les distributions installées ont déjà été ajoutées.", + "wsl.onboarding.noDistros": "Aucune distribution détectée pour l'instant.", + "wsl.onboarding.install": "Installer", + "wsl.onboarding.installing": "Installation...", + "wsl.onboarding.installDistro": "Installer une distribution", + "wsl.onboarding.searchDistros": "Rechercher des distributions", + "wsl.onboarding.wsl2Required": "WSL 2 est requis.", + "wsl.onboarding.toolsRequired": "Cette distribution nécessite bash et curl.", + "wsl.onboarding.openTerminal": "Ouvrir le terminal", + "wsl.onboarding.path": "Chemin : {{path}}", + "wsl.onboarding.notFound": "introuvable", + "wsl.onboarding.version": "Version : {{version}}", + "wsl.onboarding.unknown": "inconnue", + "wsl.onboarding.desktopVersion": "desktop {{version}}", + "wsl.onboarding.versionMismatch": "La version installée ne correspond pas à celle de l'application desktop.", + "wsl.onboarding.adding": "Ajout...", "dialog.project.edit.title": "Modifier le projet", "dialog.project.edit.name": "Nom", "dialog.project.edit.icon": "Icône", @@ -373,6 +454,7 @@ export const dict = { "language.no": "Norsk", "language.br": "Português (Brasil)", "language.bs": "Bosanski", + "language.uk": "Українська", "language.th": "ไทย", "language.tr": "Türkçe", "toast.language.title": "Langue", @@ -410,10 +492,12 @@ export const dict = { "toast.update.action.notYet": "Pas encore", "error.page.title": "Quelque chose s'est mal passé", "error.page.description": "Une erreur s'est produite lors du chargement de l'application.", + "error.page.description.localServerStartup": "Une erreur s'est produite lors du démarrage du serveur local.", "error.page.details.label": "Détails de l'erreur", "error.page.action.restart": "Redémarrer", "error.page.action.report": "Signaler l'erreur", "error.page.action.reported": "Erreur signalée", + "error.page.action.exportLogs": "Exporter les journaux", "error.page.action.checking": "Vérification...", "error.page.action.checkUpdates": "Vérifier les mises à jour", "error.page.action.updateTo": "Mettre à jour vers {{version}}", @@ -458,16 +542,38 @@ export const dict = { "home.recentProjects": "Projets récents", "home.empty.title": "Aucun projet récent", "home.empty.description": "Commencez par ouvrir un projet local", + "home.title": "Accueil", + "home.projects": "Projets", + "home.project.add": "Ajouter un projet", + "home.recentlyClosed": "Récemment fermés", + "home.server.collapse": "Réduire les projets du serveur", + "home.server.expand": "Développer les projets du serveur", + "home.sessions.search.placeholder": "Rechercher des sessions", + "home.sessions.search.placeholder.scoped": "Rechercher les sessions dans {{scope}}", + "home.sessions.search.sessions": "Sessions", + "home.sessions.search.noResults": "Aucune session trouvée pour {{query}}", + "home.sessions.empty": "Rien ici pour l'instant", + "home.sessions.empty.description": "Créez une session pour commencer", + "home.sessions.group.today": "Aujourd'hui", + "home.sessions.group.yesterday": "Hier", + "home.sessions.group.older": "Plus anciennes", "session.tab.session": "Session", "session.tab.review": "Revue", "session.tab.context": "Contexte", + "session.tab.unknown": "Session inconnue", "session.panel.reviewAndFiles": "Revue et fichiers", + "session.error.notFound": "Cette session est introuvable", + "session.error.notFound.description": "Cet onglet pointe vers une session qui n'existe plus sur ce serveur.", + "session.error.notFound.closeTab": "Fermer l'onglet", + "session.error.serverConnection": "Impossible de se connecter à ce serveur", "session.review.filesChanged": "{{count}} fichiers modifiés", "session.review.change.one": "Modification", "session.review.change.other": "Modifications", "session.review.loadingChanges": "Chargement des modifications...", "session.review.empty": "Aucune modification dans cette session pour l'instant", "session.review.noChanges": "Aucune modification", + "session.review.noUncommittedChanges": "Aucune modification non validée pour l'instant", + "session.review.noBranchChanges": "Aucune modification de branche pour l'instant", "session.review.noVcs": "Aucun système de contrôle de version Git détecté, modifications non affichées", "session.review.noSnapshot": "Le suivi des instantanés est désactivé dans la configuration, les modifications de session sont donc indisponibles", @@ -481,9 +587,10 @@ export const dict = { "session.messages.loading": "Chargement des messages...", "session.messages.jumpToLatest": "Aller au dernier", "session.context.addToContext": "Ajouter {{selection}} au contexte", - "session.todo.title": "Tâches", - "session.todo.collapse": "Réduire", - "session.todo.expand": "Développer", + "session.question.minimize": "Réduire la question", + "session.question.restore": "Restaurer la question", + "session.question.pending.one": "{{count}} question en attente", + "session.question.pending.other": "{{count}} questions en attente", "session.followupDock.summary.one": "{{count}} message en file d'attente", "session.followupDock.summary.other": "{{count}} messages en file d'attente", "session.followupDock.sendNow": "Envoyer maintenant", @@ -496,9 +603,16 @@ export const dict = { "session.revertDock.expand": "Développer les messages annulés", "session.revertDock.restore": "Restaurer le message", "session.new.title": "Créez ce que vous voulez", + "session.new.project.new": "Nouveau projet", + "session.new.project.search": "Rechercher des projets", + "session.new.project.add": "Ajouter un projet", "session.new.worktree.main": "Branche principale", "session.new.worktree.mainWithBranch": "Branche principale ({{branch}})", "session.new.worktree.create": "Créer un nouvel arbre de travail", + "session.new.workspace.runIn": "Exécuter la session dans", + "session.new.workspace.triggerLocal": "Local", + "session.new.workspace.local": "Dépôt local", + "session.new.workspace.existing": "Espace de travail…", "session.new.lastModified": "Dernière modification", "session.header.search.placeholder": "Rechercher {{project}}", "session.header.searchFiles": "Rechercher des fichiers", @@ -564,6 +678,8 @@ export const dict = { "sidebar.project.recentSessions": "Sessions récentes", "sidebar.project.viewAllSessions": "Voir toutes les sessions", "sidebar.project.clearNotifications": "Effacer les notifications", + "sidebar.empty.title": "Aucun projet ouvert", + "sidebar.empty.description": "Ouvrez un projet pour commencer", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "Bureau", "settings.section.server": "Serveur", @@ -573,6 +689,7 @@ export const dict = { "settings.desktop.wsl.title": "Intégration WSL", "settings.desktop.wsl.description": "Exécuter le serveur OpenCode dans WSL sur Windows.", "settings.general.section.appearance": "Apparence", + "settings.general.section.advanced": "Avancé", "settings.general.section.notifications": "Notifications système", "settings.general.section.updates": "Mises à jour", "settings.general.section.sounds": "Effets sonores", @@ -580,6 +697,11 @@ export const dict = { "settings.general.section.display": "Affichage", "settings.general.row.language.title": "Langue", "settings.general.row.language.description": "Changer la langue d'affichage pour OpenCode", + "settings.general.row.shell.title": "Shell du terminal", + "settings.general.row.shell.description": + "Choisissez le shell utilisé par votre terminal. Les shells compatibles sont également utilisés pour les appels d'outils de l'agent.", + "settings.general.row.shell.autoDefault": "Auto (par défaut)", + "settings.general.row.shell.terminalOnly": "terminal uniquement", "settings.general.row.appearance.title": "Apparence", "settings.general.row.appearance.description": "Personnaliser l'apparence d'OpenCode sur votre appareil", "settings.general.row.colorScheme.title": "Schéma de couleurs", @@ -588,8 +710,8 @@ export const dict = { "settings.general.row.theme.description": "Personnaliser le thème d'OpenCode.", "settings.general.row.font.title": "Police de code", "settings.general.row.font.description": "Personnaliser la police utilisée dans les blocs de code", - "settings.general.row.terminalFont.title": "Terminal Font", - "settings.general.row.terminalFont.description": "Customise the font used in the terminal", + "settings.general.row.terminalFont.title": "Police du terminal", + "settings.general.row.terminalFont.description": "Personnalisez la police utilisée dans le terminal", "settings.general.row.uiFont.title": "Police de l'interface", "settings.general.row.uiFont.description": "Personnaliser la police utilisée dans toute l'interface", "settings.general.row.followup.title": "Comportement de suivi", @@ -597,6 +719,24 @@ export const dict = { "Choisissez si les messages de suivi dirigent immédiatement ou attendent dans une file d'attente", "settings.general.row.followup.option.queue": "File d'attente", "settings.general.row.followup.option.steer": "Diriger", + "settings.general.row.showFileTree.title": "Arborescence des fichiers", + "settings.general.row.showFileTree.description": "Afficher le panneau d'arborescence des fichiers dans les sessions", + "settings.general.row.showNavigation.title": "Commandes de navigation", + "settings.general.row.showNavigation.description": + "Afficher les boutons précédent et suivant dans la barre de titre de l'application desktop", + "settings.general.row.showSearch.title": "Palette de commandes", + "settings.general.row.showSearch.description": + "Afficher le bouton de recherche et de palette de commandes dans la barre de titre", + "settings.general.row.showTerminal.title": "Terminal", + "settings.general.row.showTerminal.description": + "Afficher le bouton du terminal dans la barre de titre de l'application desktop", + "settings.general.row.showStatus.title": "État du serveur", + "settings.general.row.showStatus.description": "Afficher le bouton d'état du serveur dans la barre de titre", + "settings.general.row.mobileTitlebarBottom.title": "Navigation en bas", + "settings.general.row.mobileTitlebarBottom.description": + "Placer la barre de titre et les onglets de session en bas de l'écran sur mobile", + "settings.general.row.showCustomAgents.title": "Agents personnalisés", + "settings.general.row.showCustomAgents.description": "Afficher le sélecteur d'agent dans la zone de saisie", "settings.general.row.reasoningSummaries.title": "Afficher les résumés de raisonnement", "settings.general.row.reasoningSummaries.description": "Afficher les résumés de raisonnement du modèle dans la chronologie", @@ -606,6 +746,12 @@ export const dict = { "settings.general.row.editToolPartsExpanded.title": "Développer les parties de l'outil edit", "settings.general.row.editToolPartsExpanded.description": "Afficher les parties des outils edit, write et patch développées par défaut dans la chronologie", + "settings.general.row.newLayoutDesigns.title": "Nouvelle mise en page et nouveaux designs", + "settings.general.row.newLayoutDesigns.description": + "Activer la nouvelle mise en page et les nouvelles interfaces d'accueil, de saisie et de session", + "settings.general.row.pinchZoom.title": "Pincer pour zoomer", + "settings.general.row.pinchZoom.description": + "Autoriser les gestes de pincement du pavé tactile et Ctrl-défilement pour zoomer", "settings.general.row.wayland.title": "Utiliser Wayland natif", "settings.general.row.wayland.description": "Désactiver le repli X11 sur Wayland. Nécessite un redémarrage.", "settings.general.row.wayland.tooltip": @@ -618,6 +764,8 @@ export const dict = { "settings.updates.row.check.description": "Vérifier manuellement les mises à jour et installer si disponible", "settings.updates.action.checkNow": "Vérifier maintenant", "settings.updates.action.checking": "Vérification...", + "settings.updates.action.downloading": "Téléchargement...", + "settings.updates.action.installing": "Installation...", "settings.updates.toast.latest.title": "Vous êtes à jour", "settings.updates.toast.latest.description": "Vous utilisez la dernière version d'OpenCode.", "sound.option.none": "Aucun", @@ -740,8 +888,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Charger une compétence par son nom", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Exécuter des requêtes de serveur de langage", - "settings.permissions.tool.todowrite.title": "Écrire Todo", - "settings.permissions.tool.todowrite.description": "Mettre à jour la liste de tâches", "settings.permissions.tool.webfetch.title": "Récupération Web", "settings.permissions.tool.webfetch.description": "Récupérer le contenu d'une URL", "settings.permissions.tool.websearch.title": "Recherche Web", @@ -804,7 +950,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Suivre, examiner et annuler les modifications dans ce projet", "session.review.noVcs.createGit.actionLoading": "Création du dépôt Git...", "session.review.noVcs.createGit.action": "Créer un dépôt Git", - "session.todo.progress": "{{done}} tâches sur {{total}} terminées", "session.question.progress": "{{current}} questions sur {{total}}", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Explorateur de fichiers", diff --git a/packages/app/src/i18n/ja.ts b/packages/app/src/i18n/ja.ts index ad5dcf5387..435def9b19 100644 --- a/packages/app/src/i18n/ja.ts +++ b/packages/app/src/i18n/ja.ts @@ -21,6 +21,9 @@ export const dict = { "theme.scheme.dark": "ダーク", "command.sidebar.toggle": "サイドバーの切り替え", "command.project.open": "プロジェクトを開く", + "command.project.previous": "前のプロジェクト", + "command.project.next": "次のプロジェクト", + "command.project.index": "プロジェクト{{index}}に切り替え", "command.provider.connect": "プロバイダーに接続", "command.server.switch": "サーバーの切り替え", "command.settings.open": "設定を開く", @@ -39,6 +42,7 @@ export const dict = { "command.session.new": "新しいセッション", "command.file.open": "ファイルを開く", "command.tab.close": "タブを閉じる", + "command.tab.reopenClosed": "閉じたタブを再度開く", "command.context.addSelection": "選択範囲をコンテキストに追加", "command.context.addSelection.description": "現在のファイルから選択した行を追加", "command.input.focus": "入力欄にフォーカス", @@ -149,7 +153,7 @@ export const dict = { "provider.custom.field.providerID.placeholder": "myprovider", "provider.custom.field.providerID.description": "小文字、数字、ハイフン、アンダースコア", "provider.custom.field.name.label": "表示名", - "provider.custom.field.name.placeholder": "My AI Provider", + "provider.custom.field.name.placeholder": "マイAIプロバイダー", "provider.custom.field.baseURL.label": "ベースURL", "provider.custom.field.baseURL.placeholder": "https://api.myprovider.com/v1", "provider.custom.field.apiKey.label": "APIキー", @@ -192,6 +196,11 @@ export const dict = { "model.input.video": "動画", "model.input.pdf": "pdf", "model.tooltip.allows": "対応: {{inputs}}", + "model.tooltip.context.label": "コンテキスト", + "model.tooltip.inputs": "入力", + "model.tooltip.model": "モデル", + "model.tooltip.provider": "プロバイダー", + "model.tooltip.reasoning": "推論", "model.tooltip.reasoning.allowed": "推論を許可", "model.tooltip.reasoning.none": "推論なし", "model.tooltip.context": "コンテキスト上限 {{limit}}", @@ -201,6 +210,7 @@ export const dict = { "common.loading": "読み込み中", "common.loading.ellipsis": "...", "common.cancel": "キャンセル", + "common.clear": "クリア", "common.connect": "接続", "common.disconnect": "切断", "common.continue": "送信", @@ -217,6 +227,8 @@ export const dict = { "prompt.mode.shell": "シェル", "prompt.mode.normal": "プロンプト", "prompt.mode.shell.exit": "escで終了", + "session.child.promptDisabled": "サブエージェントのセッションにはプロンプトを送信できません。", + "session.child.backToParent": "メインセッションに戻る。", "prompt.example.1": "コードベースのTODOを修正", "prompt.example.2": "このプロジェクトの技術スタックは何ですか?", "prompt.example.3": "壊れたテストを修正", @@ -313,6 +325,75 @@ export const dict = { "dialog.server.menu.delete": "削除", "dialog.server.current": "現在のサーバー", "dialog.server.status.default": "デフォルト", + "wsl.server.add": "WSLサーバーを追加", + "wsl.server.addShort": "WSLを追加", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "WSLサーバー", + "wsl.server.retryStart": "起動を再試行", + "wsl.server.updating": "更新中...", + "wsl.onboarding.step.distro": "ディストリビューションを選択", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "WSLを確認中...", + "wsl.onboarding.restartRequired": "WSLのインストールを完了するにはWindowsの再起動が必要です。", + "wsl.onboarding.ready": "WSLの準備ができました。", + "wsl.onboarding.required": "続行するにはWSLが必要です。", + "wsl.onboarding.checkingDistros": "ディストリビューションを確認中...", + "wsl.onboarding.installingDistro": "{{distro}}をインストール中...", + "wsl.onboarding.checkingDistro": "{{distro}}を確認中...", + "wsl.onboarding.listingDistros": "ディストリビューションの一覧を取得中...", + "wsl.onboarding.distroReady": "{{distro}}の準備ができました。", + "wsl.onboarding.distroNotInstalled": "{{distro}}はまだインストールされていません。", + "wsl.onboarding.openDistroOnce": "セットアップを完了するには、{{distro}}を一度開いてください。", + "wsl.onboarding.finishingDistro": "{{distro}}のセットアップを完了しています。", + "wsl.onboarding.pickDistro": "ディストリビューションを選択するか、以下からインストールしてください。", + "wsl.onboarding.checkingOpencode": "OpenCodeを確認中...", + "wsl.onboarding.checkingOpencodeIn": "{{distro}}内のOpenCodeを確認中...", + "wsl.onboarding.updatingOpencode": "OpenCodeを更新中...", + "wsl.onboarding.updatingOpencodeIn": "{{distro}}内のOpenCodeを更新中...", + "wsl.onboarding.updateOpencodeIn": "{{distro}}内のOpenCodeを更新してください。", + "wsl.onboarding.updateOpencode": "OpenCodeを更新", + "wsl.onboarding.opencodeReadyIn": "{{distro}}内のOpenCodeの準備ができました。", + "wsl.onboarding.opencodeReady": "OpenCodeの準備ができました。", + "wsl.onboarding.installOpencodeIn": "{{distro}}にOpenCodeをインストールしてください。", + "wsl.onboarding.installOpencode": "OpenCodeをインストール", + "wsl.onboarding.chooseDistroFirst": "先にディストリビューションを選択してください。", + "wsl.onboarding.loadFailed": "WSLの状態を読み込めませんでした。", + "wsl.onboarding.loading": "読み込み中...", + "wsl.onboarding.installedDistros": "インストール済みのディストリビューション", + "wsl.onboarding.checkAgain": "再確認", + "wsl.onboarding.distroStatus.ready": "準備完了", + "wsl.onboarding.distroStatus.checking": "確認中...", + "wsl.onboarding.distroStatus.opencodeMissing": "OpenCodeがインストールされていません", + "wsl.onboarding.distroStatus.missingTools": "bash、curlがありません", + "wsl.onboarding.distroStatus.unsupported": "非対応 · WSL 2を使用してください", + "wsl.onboarding.needAnotherDistro": "別のディストリビューションが必要ですか?", + "wsl.onboarding.needAnotherDistroHint": "WSLカタログからLinuxディストリビューションをインストール", + "wsl.onboarding.wslNotInstalled.title": "WSLがインストールされていません", + "wsl.onboarding.wslNotInstalled.description": + "OpenCodeでWSLサーバーを追加するには、WSL (Windows Subsystem for Linux) が必要です", + "wsl.onboarding.wslUnavailable.title": "WSLを利用できません", + "wsl.onboarding.wslUnavailable.description": "このマシンのWSLを確認できませんでした。", + "wsl.onboarding.installWsl": "WSLをインストール", + "wsl.onboarding.windowsRestartRequired": + "WSLのインストールを完了するにはWindowsを再起動し、OpenCodeをもう一度開いてください。", + "wsl.onboarding.next": "次へ", + "wsl.onboarding.refresh": "更新", + "wsl.onboarding.allDistrosAdded": "インストール済みのディストリビューションはすべて追加済みです。", + "wsl.onboarding.noDistros": "ディストリビューションはまだ検出されていません。", + "wsl.onboarding.install": "インストール", + "wsl.onboarding.installing": "インストール中...", + "wsl.onboarding.installDistro": "ディストリビューションをインストール", + "wsl.onboarding.searchDistros": "ディストリビューションを検索", + "wsl.onboarding.wsl2Required": "WSL 2が必要です。", + "wsl.onboarding.toolsRequired": "このディストリビューションにはbashとcurlが必要です。", + "wsl.onboarding.openTerminal": "ターミナルを開く", + "wsl.onboarding.path": "パス: {{path}}", + "wsl.onboarding.notFound": "見つかりません", + "wsl.onboarding.version": "バージョン: {{version}}", + "wsl.onboarding.unknown": "不明", + "wsl.onboarding.desktopVersion": "デスクトップ {{version}}", + "wsl.onboarding.versionMismatch": "インストールされているバージョンがデスクトップアプリのバージョンと一致しません。", + "wsl.onboarding.adding": "追加中...", "dialog.project.edit.title": "プロジェクトを編集", "dialog.project.edit.name": "名前", "dialog.project.edit.icon": "アイコン", @@ -370,6 +451,7 @@ export const dict = { "language.no": "Norsk", "language.br": "Português (Brasil)", "language.bs": "Bosanski", + "language.uk": "Українська", "language.th": "ไทย", "language.tr": "Türkçe", "toast.language.title": "言語", @@ -406,10 +488,12 @@ export const dict = { "toast.update.action.notYet": "今はしない", "error.page.title": "問題が発生しました", "error.page.description": "アプリケーションの読み込み中にエラーが発生しました。", + "error.page.description.localServerStartup": "ローカルサーバーの起動中にエラーが発生しました。", "error.page.details.label": "エラー詳細", "error.page.action.restart": "再起動", "error.page.action.report": "エラーを報告", "error.page.action.reported": "エラーを報告しました", + "error.page.action.exportLogs": "ログをエクスポート", "error.page.action.checking": "確認中...", "error.page.action.checkUpdates": "アップデートを確認", "error.page.action.updateTo": "{{version}}にアップデート", @@ -451,10 +535,30 @@ export const dict = { "home.recentProjects": "最近のプロジェクト", "home.empty.title": "最近のプロジェクトはありません", "home.empty.description": "ローカルプロジェクトを開いて始めましょう", + "home.title": "ホーム", + "home.projects": "プロジェクト", + "home.project.add": "プロジェクトを追加", + "home.recentlyClosed": "最近閉じたプロジェクト", + "home.server.collapse": "サーバーのプロジェクトを折りたたむ", + "home.server.expand": "サーバーのプロジェクトを展開", + "home.sessions.search.placeholder": "セッションを検索", + "home.sessions.search.placeholder.scoped": "{{scope}}のセッションを検索", + "home.sessions.search.sessions": "セッション", + "home.sessions.search.noResults": "{{query}}に一致するセッションが見つかりません", + "home.sessions.empty": "まだ何もありません", + "home.sessions.empty.description": "セッションを作成して始めましょう", + "home.sessions.group.today": "今日", + "home.sessions.group.yesterday": "昨日", + "home.sessions.group.older": "それ以前", "session.tab.session": "セッション", "session.tab.review": "レビュー", "session.tab.context": "コンテキスト", + "session.tab.unknown": "不明なセッション", "session.panel.reviewAndFiles": "レビューとファイル", + "session.error.notFound": "このセッションが見つかりません", + "session.error.notFound.description": "このタブが参照するセッションは、このサーバーには存在しません。", + "session.error.notFound.closeTab": "タブを閉じる", + "session.error.serverConnection": "このサーバーに接続できません", "session.review.filesChanged": "{{count}} ファイル変更", "session.review.change.one": "変更", "session.review.change.other": "変更", @@ -463,6 +567,8 @@ export const dict = { "session.review.noVcs": "Gitバージョン管理システムが検出されないため、変更は表示されません", "session.review.noSnapshot": "設定でスナップショット追跡が無効になっているため、セッションの変更は利用できません", "session.review.noChanges": "変更なし", + "session.review.noUncommittedChanges": "コミットされていない変更はまだありません", + "session.review.noBranchChanges": "ブランチの変更はまだありません", "session.files.selectToOpen": "開くファイルを選択", "session.files.all": "すべてのファイル", "session.files.empty": "ファイルなし", @@ -473,9 +579,10 @@ export const dict = { "session.messages.loading": "メッセージを読み込み中...", "session.messages.jumpToLatest": "最新へジャンプ", "session.context.addToContext": "{{selection}}をコンテキストに追加", - "session.todo.title": "ToDo", - "session.todo.collapse": "折りたたむ", - "session.todo.expand": "展開", + "session.question.minimize": "質問を最小化", + "session.question.restore": "質問を復元", + "session.question.pending.one": "{{count}}件の保留中の質問", + "session.question.pending.other": "{{count}}件の保留中の質問", "session.followupDock.summary.one": "{{count}} 件のメッセージが待機中", "session.followupDock.summary.other": "{{count}} 件のメッセージが待機中", "session.followupDock.sendNow": "今すぐ送信", @@ -488,9 +595,16 @@ export const dict = { "session.revertDock.expand": "ロールバックされたメッセージを展開", "session.revertDock.restore": "メッセージを復元", "session.new.title": "何でも作る", + "session.new.project.new": "新しいプロジェクト", + "session.new.project.search": "プロジェクトを検索", + "session.new.project.add": "プロジェクトを追加", "session.new.worktree.main": "メインブランチ", "session.new.worktree.mainWithBranch": "メインブランチ ({{branch}})", "session.new.worktree.create": "新しいワークツリーを作成", + "session.new.workspace.runIn": "セッションの実行先", + "session.new.workspace.triggerLocal": "ローカル", + "session.new.workspace.local": "ローカルリポジトリ", + "session.new.workspace.existing": "ワークスペース…", "session.new.lastModified": "最終更新", "session.header.search.placeholder": "{{project}}を検索", "session.header.searchFiles": "ファイルを検索", @@ -554,6 +668,8 @@ export const dict = { "sidebar.project.recentSessions": "最近のセッション", "sidebar.project.viewAllSessions": "すべてのセッションを表示", "sidebar.project.clearNotifications": "通知をクリア", + "sidebar.empty.title": "開いているプロジェクトはありません", + "sidebar.empty.description": "プロジェクトを開いて始めましょう", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "デスクトップ", "settings.section.server": "サーバー", @@ -563,6 +679,7 @@ export const dict = { "settings.desktop.wsl.title": "WSL連携", "settings.desktop.wsl.description": "WindowsのWSL環境でOpenCodeサーバーを実行します。", "settings.general.section.appearance": "外観", + "settings.general.section.advanced": "詳細設定", "settings.general.section.notifications": "システム通知", "settings.general.section.updates": "アップデート", "settings.general.section.sounds": "効果音", @@ -570,6 +687,11 @@ export const dict = { "settings.general.section.display": "ディスプレイ", "settings.general.row.language.title": "言語", "settings.general.row.language.description": "OpenCodeの表示言語を変更します", + "settings.general.row.shell.title": "ターミナルシェル", + "settings.general.row.shell.description": + "ターミナルで使用するシェルを選択します。互換性のあるシェルはエージェントのツール呼び出しにも使用されます。", + "settings.general.row.shell.autoDefault": "自動 (デフォルト)", + "settings.general.row.shell.terminalOnly": "ターミナルのみ", "settings.general.row.appearance.title": "外観", "settings.general.row.appearance.description": "デバイスでのOpenCodeの表示をカスタマイズします", "settings.general.row.colorScheme.title": "配色", @@ -578,8 +700,8 @@ export const dict = { "settings.general.row.theme.description": "OpenCodeのテーマをカスタマイズします。", "settings.general.row.font.title": "コードフォント", "settings.general.row.font.description": "コードブロックで使用するフォントをカスタマイズします", - "settings.general.row.terminalFont.title": "Terminal Font", - "settings.general.row.terminalFont.description": "Customise the font used in the terminal", + "settings.general.row.terminalFont.title": "ターミナルのフォント", + "settings.general.row.terminalFont.description": "ターミナルで使用するフォントをカスタマイズ", "settings.general.row.uiFont.title": "UIフォント", "settings.general.row.uiFont.description": "インターフェース全体で使用するフォントをカスタマイズします", "settings.general.row.followup.title": "フォローアップの動作", @@ -587,6 +709,21 @@ export const dict = { "フォローアッププロンプトを即座に実行するか、キューで待機させるかを選択します", "settings.general.row.followup.option.queue": "キューに追加", "settings.general.row.followup.option.steer": "即座に実行 (Steer)", + "settings.general.row.showFileTree.title": "ファイルツリー", + "settings.general.row.showFileTree.description": "セッションにファイルツリーパネルを表示します", + "settings.general.row.showNavigation.title": "ナビゲーションコントロール", + "settings.general.row.showNavigation.description": "デスクトップのタイトルバーに戻るボタンと進むボタンを表示します", + "settings.general.row.showSearch.title": "コマンドパレット", + "settings.general.row.showSearch.description": "タイトルバーに検索とコマンドパレットのボタンを表示します", + "settings.general.row.showTerminal.title": "ターミナル", + "settings.general.row.showTerminal.description": "デスクトップのタイトルバーにターミナルボタンを表示します", + "settings.general.row.showStatus.title": "サーバーステータス", + "settings.general.row.showStatus.description": "タイトルバーにサーバーステータスボタンを表示します", + "settings.general.row.mobileTitlebarBottom.title": "下部ナビゲーション", + "settings.general.row.mobileTitlebarBottom.description": + "モバイルではタイトルバーとセッションタブを画面下部に配置します", + "settings.general.row.showCustomAgents.title": "カスタムエージェント", + "settings.general.row.showCustomAgents.description": "コンポーザーにエージェント選択を表示します", "settings.general.row.reasoningSummaries.title": "推論の要約を表示", "settings.general.row.reasoningSummaries.description": "タイムラインにモデルの推論の要約を表示します", "settings.general.row.shellToolPartsExpanded.title": "shell ツールパーツを展開", @@ -595,6 +732,12 @@ export const dict = { "settings.general.row.editToolPartsExpanded.title": "edit ツールパーツを展開", "settings.general.row.editToolPartsExpanded.description": "タイムラインで edit、write、patch ツールパーツをデフォルトで展開して表示します", + "settings.general.row.newLayoutDesigns.title": "新しいレイアウトとデザイン", + "settings.general.row.newLayoutDesigns.description": + "刷新されたレイアウト、ホーム、コンポーザー、セッションUIを有効にします", + "settings.general.row.pinchZoom.title": "ピンチでズーム", + "settings.general.row.pinchZoom.description": + "トラックパッドのピンチ操作とCtrl+スクロール操作によるズームを許可します", "settings.general.row.wayland.title": "ネイティブWaylandを使用", "settings.general.row.wayland.description": "WaylandでのX11フォールバックを無効にします。再起動が必要です。", "settings.general.row.wayland.tooltip": @@ -607,6 +750,8 @@ export const dict = { "settings.updates.row.check.description": "手動でアップデートを確認し、利用可能ならインストールします", "settings.updates.action.checkNow": "今すぐ確認", "settings.updates.action.checking": "確認中...", + "settings.updates.action.downloading": "ダウンロード中...", + "settings.updates.action.installing": "インストール中...", "settings.updates.toast.latest.title": "最新です", "settings.updates.toast.latest.description": "OpenCode は最新バージョンです。", "sound.option.none": "なし", @@ -726,8 +871,6 @@ export const dict = { "settings.permissions.tool.skill.description": "名前によるスキルの読み込み", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "言語サーバークエリの実行", - "settings.permissions.tool.todowrite.title": "Todo書き込み", - "settings.permissions.tool.todowrite.description": "Todoリストの更新", "settings.permissions.tool.webfetch.title": "Web取得", "settings.permissions.tool.webfetch.description": "URLからコンテンツを取得", "settings.permissions.tool.websearch.title": "Web検索", @@ -790,7 +933,6 @@ export const dict = { "session.review.noVcs.createGit.description": "このプロジェクトの変更を追跡、レビュー、元に戻す", "session.review.noVcs.createGit.actionLoading": "Git リポジトリを作成中...", "session.review.noVcs.createGit.action": "Git リポジトリを作成", - "session.todo.progress": "{{done}} 個中 {{total}} 個の Todo が完了", "session.question.progress": "{{total}} 問中 {{current}} 問", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "エクスプローラー", diff --git a/packages/app/src/i18n/ko.ts b/packages/app/src/i18n/ko.ts index 15f1f28013..c6e7f142bc 100644 --- a/packages/app/src/i18n/ko.ts +++ b/packages/app/src/i18n/ko.ts @@ -471,9 +471,6 @@ export const dict = { "session.messages.loading": "메시지 로드 중...", "session.messages.jumpToLatest": "최신으로 이동", "session.context.addToContext": "컨텍스트에 {{selection}} 추가", - "session.todo.title": "할 일", - "session.todo.collapse": "접기", - "session.todo.expand": "펼치기", "session.followupDock.summary.one": "{{count}}개의 대기 중인 메시지", "session.followupDock.summary.other": "{{count}}개의 대기 중인 메시지", "session.followupDock.sendNow": "지금 전송", @@ -575,8 +572,8 @@ export const dict = { "settings.general.row.theme.description": "OpenCode 테마 사용자 지정", "settings.general.row.font.title": "코드 글꼴", "settings.general.row.font.description": "코드 블록에 사용되는 글꼴을 사용자 지정", - "settings.general.row.terminalFont.title": "Terminal Font", - "settings.general.row.terminalFont.description": "Customise the font used in the terminal", + "settings.general.row.terminalFont.title": "터미널 글꼴", + "settings.general.row.terminalFont.description": "터미널에서 사용할 글꼴을 설정합니다", "settings.general.row.uiFont.title": "UI 글꼴", "settings.general.row.uiFont.description": "인터페이스 전반에 사용되는 글꼴을 사용자 지정", "settings.general.row.followup.title": "후속 조치 동작", @@ -721,8 +718,6 @@ export const dict = { "settings.permissions.tool.skill.description": "이름으로 기술 로드", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "언어 서버 쿼리 실행", - "settings.permissions.tool.todowrite.title": "할 일 쓰기", - "settings.permissions.tool.todowrite.description": "할 일 목록 업데이트", "settings.permissions.tool.webfetch.title": "웹 가져오기", "settings.permissions.tool.webfetch.description": "URL에서 콘텐츠 가져오기", "settings.permissions.tool.websearch.title": "웹 검색", @@ -785,7 +780,6 @@ export const dict = { "session.review.noVcs.createGit.description": "이 프로젝트의 변경 사항을 추적, 검토 및 실행 취소", "session.review.noVcs.createGit.actionLoading": "Git 저장소 생성 중...", "session.review.noVcs.createGit.action": "Git 저장소 생성", - "session.todo.progress": "{{total}}개의 할 일 중 {{done}}개 완료", "session.question.progress": "{{total}}개의 질문 중 {{current}}개", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "파일 탐색기", @@ -848,4 +842,155 @@ export const dict = { "error.childStore.persistedProjectIconCreateFailed": "영구 프로젝트 아이콘 생성 실패", "error.childStore.storeCreateFailed": "저장소 생성 실패", "terminal.connectionLost.abnormalClose": "WebSocket이 비정상적으로 닫힘: {{code}}", + + "command.project.previous": "이전 프로젝트", + "command.project.next": "다음 프로젝트", + "command.project.index": "{{index}}번 프로젝트로 전환", + "command.tab.reopenClosed": "닫은 탭 다시 열기", + "model.tooltip.context.label": "컨텍스트", + "model.tooltip.inputs": "입력", + "model.tooltip.model": "모델", + "model.tooltip.provider": "공급자", + "model.tooltip.reasoning": "추론", + "common.clear": "지우기", + "session.child.promptDisabled": "하위 에이전트 세션에는 프롬프트를 입력할 수 없습니다.", + "session.child.backToParent": "메인 세션으로 돌아가기.", + + "wsl.server.add": "WSL 서버 추가", + "wsl.server.addShort": "WSL 추가", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "WSL 서버", + "wsl.server.retryStart": "시작 재시도", + "wsl.server.updating": "업데이트 중...", + "wsl.onboarding.step.distro": "배포판 선택", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "WSL 확인 중...", + "wsl.onboarding.restartRequired": "WSL 설치를 완료하려면 Windows를 다시 시작해야 합니다.", + "wsl.onboarding.ready": "WSL이 준비되었습니다.", + "wsl.onboarding.required": "계속하려면 WSL이 필요합니다.", + "wsl.onboarding.checkingDistros": "배포판 확인 중...", + "wsl.onboarding.installingDistro": "{{distro}} 배포판 설치 중...", + "wsl.onboarding.checkingDistro": "{{distro}} 배포판 확인 중...", + "wsl.onboarding.listingDistros": "배포판 목록 확인 중...", + "wsl.onboarding.distroReady": "{{distro}} 배포판이 준비되었습니다.", + "wsl.onboarding.distroNotInstalled": "{{distro}} 배포판이 아직 설치되지 않았습니다.", + "wsl.onboarding.openDistroOnce": "설정을 완료하려면 {{distro}} 배포판을 한 번 여세요.", + "wsl.onboarding.finishingDistro": "{{distro}} 배포판 설정을 마무리하는 중입니다.", + "wsl.onboarding.pickDistro": "배포판을 선택하거나 아래에서 설치하세요.", + "wsl.onboarding.checkingOpencode": "OpenCode 확인 중...", + "wsl.onboarding.checkingOpencodeIn": "{{distro}}에서 OpenCode 확인 중...", + "wsl.onboarding.updatingOpencode": "OpenCode 업데이트 중...", + "wsl.onboarding.updatingOpencodeIn": "{{distro}}에서 OpenCode 업데이트 중...", + "wsl.onboarding.updateOpencodeIn": "{{distro}}에서 OpenCode를 업데이트하세요.", + "wsl.onboarding.updateOpencode": "OpenCode 업데이트", + "wsl.onboarding.opencodeReadyIn": "{{distro}}에서 OpenCode를 사용할 준비가 되었습니다.", + "wsl.onboarding.opencodeReady": "OpenCode가 준비되었습니다.", + "wsl.onboarding.installOpencodeIn": "{{distro}}에 OpenCode를 설치하세요.", + "wsl.onboarding.installOpencode": "OpenCode 설치", + "wsl.onboarding.chooseDistroFirst": "먼저 배포판을 선택하세요.", + "wsl.onboarding.loadFailed": "WSL 상태를 불러오지 못했습니다.", + "wsl.onboarding.loading": "로딩 중...", + "wsl.onboarding.installedDistros": "설치된 배포판", + "wsl.onboarding.checkAgain": "다시 확인", + "wsl.onboarding.distroStatus.ready": "준비됨", + "wsl.onboarding.distroStatus.checking": "확인 중...", + "wsl.onboarding.distroStatus.opencodeMissing": "OpenCode가 설치되지 않음", + "wsl.onboarding.distroStatus.missingTools": "bash, curl 없음", + "wsl.onboarding.distroStatus.unsupported": "지원되지 않음 · WSL 2 사용", + "wsl.onboarding.needAnotherDistro": "다른 배포판이 필요하신가요?", + "wsl.onboarding.needAnotherDistroHint": "WSL 카탈로그에서 Linux 배포판을 설치하세요", + "wsl.onboarding.wslNotInstalled.title": "WSL이 설치되지 않음", + "wsl.onboarding.wslNotInstalled.description": + "OpenCode에서 WSL 서버를 추가하려면 WSL (Windows Subsystem for Linux)이 필요합니다", + "wsl.onboarding.wslUnavailable.title": "WSL을 사용할 수 없음", + "wsl.onboarding.wslUnavailable.description": "OpenCode에서 이 컴퓨터의 WSL을 확인할 수 없습니다.", + "wsl.onboarding.installWsl": "WSL 설치", + "wsl.onboarding.windowsRestartRequired": "WSL 설치를 완료하려면 Windows를 다시 시작한 다음 OpenCode를 다시 여세요.", + "wsl.onboarding.next": "다음", + "wsl.onboarding.refresh": "새로 고침", + "wsl.onboarding.allDistrosAdded": "설치된 모든 배포판이 이미 추가되었습니다.", + "wsl.onboarding.noDistros": "아직 감지된 배포판이 없습니다.", + "wsl.onboarding.install": "설치", + "wsl.onboarding.installing": "설치 중...", + "wsl.onboarding.installDistro": "배포판 설치", + "wsl.onboarding.searchDistros": "배포판 검색", + "wsl.onboarding.wsl2Required": "WSL 2가 필요합니다.", + "wsl.onboarding.toolsRequired": "이 배포판에는 bash와 curl이 필요합니다.", + "wsl.onboarding.openTerminal": "터미널 열기", + "wsl.onboarding.path": "경로: {{path}}", + "wsl.onboarding.notFound": "찾을 수 없음", + "wsl.onboarding.version": "버전: {{version}}", + "wsl.onboarding.unknown": "알 수 없음", + "wsl.onboarding.desktopVersion": "데스크톱 {{version}}", + "wsl.onboarding.versionMismatch": "설치된 버전이 데스크톱 앱 버전과 일치하지 않습니다.", + "wsl.onboarding.adding": "추가 중...", + + "language.uk": "Українська", + "error.page.description.localServerStartup": "로컬 서버를 시작하는 동안 오류가 발생했습니다.", + "error.page.action.exportLogs": "로그 내보내기", + + "home.title": "홈", + "home.projects": "프로젝트", + "home.project.add": "프로젝트 추가", + "home.recentlyClosed": "최근에 닫은 항목", + "home.server.collapse": "서버 프로젝트 접기", + "home.server.expand": "서버 프로젝트 펼치기", + "home.sessions.search.placeholder": "세션 검색", + "home.sessions.search.placeholder.scoped": "{{scope}}에서 세션 검색", + "home.sessions.search.sessions": "세션", + "home.sessions.search.noResults": "{{query}}에 해당하는 세션을 찾을 수 없습니다", + "home.sessions.empty": "아직 아무것도 없습니다", + "home.sessions.empty.description": "세션을 생성하여 시작하세요", + "home.sessions.group.today": "오늘", + "home.sessions.group.yesterday": "어제", + "home.sessions.group.older": "이전", + + "session.tab.unknown": "알 수 없는 세션", + "session.error.notFound": "이 세션을 찾을 수 없습니다", + "session.error.notFound.description": "이 탭은 이 서버에 더 이상 존재하지 않는 세션을 가리킵니다.", + "session.error.notFound.closeTab": "탭 닫기", + "session.error.serverConnection": "이 서버에 연결할 수 없습니다", + "session.review.noUncommittedChanges": "아직 커밋되지 않은 변경 사항이 없습니다", + "session.review.noBranchChanges": "아직 브랜치 변경 사항이 없습니다", + "session.question.minimize": "질문 최소화", + "session.question.restore": "질문 복원", + "session.question.pending.one": "{{count}}개의 대기 중인 질문", + "session.question.pending.other": "{{count}}개의 대기 중인 질문", + "session.new.project.new": "새 프로젝트", + "session.new.project.search": "프로젝트 검색", + "session.new.project.add": "프로젝트 추가", + "session.new.workspace.runIn": "세션 실행 위치", + "session.new.workspace.triggerLocal": "로컬", + "session.new.workspace.local": "로컬 저장소", + "session.new.workspace.existing": "작업 공간…", + + "sidebar.empty.title": "열린 프로젝트 없음", + "sidebar.empty.description": "프로젝트를 열어 시작하세요", + + "settings.general.section.advanced": "고급", + "settings.general.row.shell.title": "터미널 셸", + "settings.general.row.shell.description": + "터미널에서 사용할 셸을 선택하세요. 호환되는 셸은 에이전트 도구 호출에도 사용됩니다.", + "settings.general.row.shell.autoDefault": "자동 (기본값)", + "settings.general.row.shell.terminalOnly": "터미널 전용", + "settings.general.row.showFileTree.title": "파일 트리", + "settings.general.row.showFileTree.description": "세션에 파일 트리 패널 표시", + "settings.general.row.showNavigation.title": "탐색 컨트롤", + "settings.general.row.showNavigation.description": "데스크톱 제목 표시줄에 뒤로 및 앞으로 버튼 표시", + "settings.general.row.showSearch.title": "명령 팔레트", + "settings.general.row.showSearch.description": "제목 표시줄에 검색 및 명령 팔레트 버튼 표시", + "settings.general.row.showTerminal.title": "터미널", + "settings.general.row.showTerminal.description": "데스크톱 제목 표시줄에 터미널 버튼 표시", + "settings.general.row.showStatus.title": "서버 상태", + "settings.general.row.showStatus.description": "제목 표시줄에 서버 상태 버튼 표시", + "settings.general.row.mobileTitlebarBottom.title": "하단 탐색", + "settings.general.row.mobileTitlebarBottom.description": "모바일에서 제목 표시줄과 세션 탭을 화면 하단에 배치", + "settings.general.row.showCustomAgents.title": "사용자 지정 에이전트", + "settings.general.row.showCustomAgents.description": "입력창에 에이전트 선택기 표시", + "settings.general.row.newLayoutDesigns.title": "새 레이아웃 및 디자인", + "settings.general.row.newLayoutDesigns.description": "새롭게 디자인된 레이아웃, 홈, 입력창 및 세션 UI 활성화", + "settings.general.row.pinchZoom.title": "핀치 줌", + "settings.general.row.pinchZoom.description": "트랙패드 핀치 및 Ctrl-스크롤 제스처로 확대/축소 허용", + "settings.updates.action.downloading": "다운로드 중...", + "settings.updates.action.installing": "설치 중...", } diff --git a/packages/app/src/i18n/no.ts b/packages/app/src/i18n/no.ts index 8ec11de192..e066ff379b 100644 --- a/packages/app/src/i18n/no.ts +++ b/packages/app/src/i18n/no.ts @@ -77,7 +77,7 @@ export const dict = { "command.permissions.autoaccept.enable": "Aksepter tillatelser automatisk", "command.permissions.autoaccept.disable": "Stopp automatisk akseptering av tillatelser", "command.workspace.toggle": "Veksle arbeidsområder", - "command.workspace.toggle.description": "Enable or disable multiple workspaces in the sidebar", + "command.workspace.toggle.description": "Aktiver eller deaktiver flere arbeidsområder i sidefeltet", "command.session.undo": "Angre", "command.session.undo.description": "Angre siste melding", "command.session.redo": "Gjør om", @@ -469,7 +469,7 @@ export const dict = { "Rotelement ikke funnet. Glemte du å legge det til i index.html? Eller kanskje id-attributten er feilstavet?", "error.serverSync.connectFailed": "Kunne ikke koble til server. Kjører det en server på `{{url}}`?", - "directory.error.invalidUrl": "Invalid directory in URL.", + "directory.error.invalidUrl": "Ugyldig mappe i URL-en.", "error.chain.unknown": "Ukjent feil", "error.chain.causedBy": "Forårsaket av:", @@ -532,9 +532,6 @@ export const dict = { "session.messages.jumpToLatest": "Hopp til nyeste", "session.context.addToContext": "Legg til {{selection}} i kontekst", - "session.todo.title": "Oppgaver", - "session.todo.collapse": "Skjul", - "session.todo.expand": "Utvid", "session.followupDock.summary.one": "{{count}} melding i kø", "session.followupDock.summary.other": "{{count}} meldinger i kø", "session.followupDock.sendNow": "Send nå", @@ -649,8 +646,8 @@ export const dict = { "settings.general.row.theme.description": "Tilpass hvordan OpenCode er tematisert.", "settings.general.row.font.title": "Kodefont", "settings.general.row.font.description": "Tilpass skrifttypen som brukes i kodeblokker", - "settings.general.row.terminalFont.title": "Terminal Font", - "settings.general.row.terminalFont.description": "Customise the font used in the terminal", + "settings.general.row.terminalFont.title": "Terminalskrift", + "settings.general.row.terminalFont.description": "Tilpass skrifttypen som brukes i terminalen", "settings.general.row.uiFont.title": "UI-skrift", "settings.general.row.uiFont.description": "Tilpass skrifttypen som brukes i hele grensesnittet", "settings.general.row.followup.title": "Oppfølgingsadferd", @@ -806,8 +803,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Last en ferdighet etter navn", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Kjør språkserverforespørsler", - "settings.permissions.tool.todowrite.title": "Skriv gjøremål", - "settings.permissions.tool.todowrite.description": "Oppdater gjøremålslisten", "settings.permissions.tool.webfetch.title": "Webhenting", "settings.permissions.tool.webfetch.description": "Hent innhold fra en URL", "settings.permissions.tool.websearch.title": "Websøk", @@ -872,7 +867,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Spor, gjennomgå og angre endringer i dette prosjektet", "session.review.noVcs.createGit.actionLoading": "Oppretter Git-depot...", "session.review.noVcs.createGit.action": "Opprett Git-depot", - "session.todo.progress": "{{done}} av {{total}} oppgaver fullført", "session.question.progress": "{{current}} av {{total}} spørsmål", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Filutforsker", @@ -936,4 +930,163 @@ export const dict = { "error.childStore.persistedProjectIconCreateFailed": "Kunne ikke opprette vedvarende prosjektikon", "error.childStore.storeCreateFailed": "Kunne ikke opprette lager", "terminal.connectionLost.abnormalClose": "WebSocket lukket unormalt: {{code}}", + + "command.project.previous": "Forrige prosjekt", + "command.project.next": "Neste prosjekt", + "command.project.index": "Bytt til prosjekt {{index}}", + "command.tab.reopenClosed": "Åpne lukket fane på nytt", + + "model.tooltip.context.label": "Kontekst", + "model.tooltip.inputs": "Inndata", + "model.tooltip.model": "Modell", + "model.tooltip.provider": "Leverandør", + "model.tooltip.reasoning": "Resonnering", + + "common.clear": "Tøm", + + "session.child.promptDisabled": "Underagentsesjoner kan ikke motta forespørsler.", + "session.child.backToParent": "Tilbake til hovedsesjonen.", + + "wsl.server.add": "Legg til WSL-server", + "wsl.server.addShort": "Legg til WSL", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "WSL-server", + "wsl.server.retryStart": "Prøv å starte på nytt", + "wsl.server.updating": "Oppdaterer...", + "wsl.onboarding.step.distro": "Velg distribusjon", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "Sjekker WSL...", + "wsl.onboarding.restartRequired": "Windows må startes på nytt for å fullføre installasjonen av WSL.", + "wsl.onboarding.ready": "WSL er klart.", + "wsl.onboarding.required": "WSL kreves for å fortsette.", + "wsl.onboarding.checkingDistros": "Sjekker distribusjoner...", + "wsl.onboarding.installingDistro": "Installerer {{distro}}...", + "wsl.onboarding.checkingDistro": "Sjekker {{distro}}...", + "wsl.onboarding.listingDistros": "Lister distribusjoner...", + "wsl.onboarding.distroReady": "{{distro}} er klar.", + "wsl.onboarding.distroNotInstalled": "{{distro}} er ikke installert ennå.", + "wsl.onboarding.openDistroOnce": "Åpne {{distro}} én gang for å fullføre oppsettet.", + "wsl.onboarding.finishingDistro": "Fullfører oppsettet for {{distro}}.", + "wsl.onboarding.pickDistro": "Velg en distribusjon eller installer en nedenfor.", + "wsl.onboarding.checkingOpencode": "Sjekker OpenCode...", + "wsl.onboarding.checkingOpencodeIn": "Sjekker OpenCode i {{distro}}...", + "wsl.onboarding.updatingOpencode": "Oppdaterer OpenCode...", + "wsl.onboarding.updatingOpencodeIn": "Oppdaterer OpenCode i {{distro}}...", + "wsl.onboarding.updateOpencodeIn": "Oppdater OpenCode i {{distro}}.", + "wsl.onboarding.updateOpencode": "Oppdater OpenCode", + "wsl.onboarding.opencodeReadyIn": "OpenCode er klar i {{distro}}.", + "wsl.onboarding.opencodeReady": "OpenCode er klar.", + "wsl.onboarding.installOpencodeIn": "Installer OpenCode i {{distro}}.", + "wsl.onboarding.installOpencode": "Installer OpenCode", + "wsl.onboarding.chooseDistroFirst": "Velg en distribusjon først.", + "wsl.onboarding.loadFailed": "Kunne ikke laste inn WSL-status.", + "wsl.onboarding.loading": "Laster...", + "wsl.onboarding.installedDistros": "Installerte distribusjoner", + "wsl.onboarding.checkAgain": "Sjekk på nytt", + "wsl.onboarding.distroStatus.ready": "Klar", + "wsl.onboarding.distroStatus.checking": "Sjekker...", + "wsl.onboarding.distroStatus.opencodeMissing": "OpenCode er ikke installert", + "wsl.onboarding.distroStatus.missingTools": "Mangler bash, curl", + "wsl.onboarding.distroStatus.unsupported": "Ikke støttet · Bruk WSL 2", + "wsl.onboarding.needAnotherDistro": "Trenger du en annen distribusjon?", + "wsl.onboarding.needAnotherDistroHint": "Installer en Linux-distribusjon fra WSL-katalogen", + "wsl.onboarding.wslNotInstalled.title": "WSL er ikke installert", + "wsl.onboarding.wslNotInstalled.description": + "WSL (Windows Subsystem for Linux) kreves før OpenCode kan legge til en WSL-server", + "wsl.onboarding.wslUnavailable.title": "WSL er utilgjengelig", + "wsl.onboarding.wslUnavailable.description": "OpenCode kunne ikke bekrefte WSL på denne maskinen.", + "wsl.onboarding.installWsl": "Installer WSL", + "wsl.onboarding.windowsRestartRequired": + "Start Windows på nytt for å fullføre installasjonen av WSL, og åpne deretter OpenCode på nytt.", + "wsl.onboarding.next": "Neste", + "wsl.onboarding.refresh": "Oppdater", + "wsl.onboarding.allDistrosAdded": "Alle installerte distribusjoner er allerede lagt til.", + "wsl.onboarding.noDistros": "Ingen distribusjoner oppdaget ennå.", + "wsl.onboarding.install": "Installer", + "wsl.onboarding.installing": "Installerer...", + "wsl.onboarding.installDistro": "Installer distribusjon", + "wsl.onboarding.searchDistros": "Søk etter distribusjoner", + "wsl.onboarding.wsl2Required": "WSL 2 er påkrevd.", + "wsl.onboarding.toolsRequired": "Denne distribusjonen trenger bash og curl.", + "wsl.onboarding.openTerminal": "Åpne terminal", + "wsl.onboarding.path": "Bane: {{path}}", + "wsl.onboarding.notFound": "ikke funnet", + "wsl.onboarding.version": "Versjon: {{version}}", + "wsl.onboarding.unknown": "ukjent", + "wsl.onboarding.desktopVersion": "skrivebordsapp {{version}}", + "wsl.onboarding.versionMismatch": "Den installerte versjonen samsvarer ikke med versjonen av skrivebordsappen.", + "wsl.onboarding.adding": "Legger til...", + + "language.uk": "Українська", + + "error.page.description.localServerStartup": "Det oppstod en feil under oppstart av den lokale serveren.", + "error.page.action.exportLogs": "Eksporter logger", + + "home.title": "Hjem", + "home.projects": "Prosjekter", + "home.project.add": "Legg til prosjekt", + "home.recentlyClosed": "Nylig lukket", + "home.server.collapse": "Fold sammen serverprosjekter", + "home.server.expand": "Utvid serverprosjekter", + "home.sessions.search.placeholder": "Søk etter sesjoner", + "home.sessions.search.placeholder.scoped": "Søk etter sesjoner i {{scope}}", + "home.sessions.search.sessions": "Sesjoner", + "home.sessions.search.noResults": "Ingen sesjoner funnet for {{query}}", + "home.sessions.empty": "Ingenting her ennå", + "home.sessions.empty.description": "Opprett en sesjon for å komme i gang", + "home.sessions.group.today": "I dag", + "home.sessions.group.yesterday": "I går", + "home.sessions.group.older": "Eldre", + + "session.tab.unknown": "Ukjent sesjon", + "session.error.notFound": "Denne sesjonen finnes ikke", + "session.error.notFound.description": "Denne fanen peker til en sesjon som ikke lenger finnes på denne serveren.", + "session.error.notFound.closeTab": "Lukk fane", + "session.error.serverConnection": "Kan ikke koble til denne serveren", + "session.review.noUncommittedChanges": "Ingen ucommittede endringer ennå", + "session.review.noBranchChanges": "Ingen grenendringer ennå", + "session.question.minimize": "Minimer spørsmål", + "session.question.restore": "Gjenopprett spørsmål", + "session.question.pending.one": "{{count}} ventende spørsmål", + "session.question.pending.other": "{{count}} ventende spørsmål", + "session.new.project.new": "Nytt prosjekt", + "session.new.project.search": "Søk etter prosjekter", + "session.new.project.add": "Legg til prosjekt", + "session.new.workspace.runIn": "Kjør sesjonen i", + "session.new.workspace.triggerLocal": "Lokalt", + "session.new.workspace.local": "Lokalt depot", + "session.new.workspace.existing": "Arbeidsområde…", + + "sidebar.empty.title": "Ingen åpne prosjekter", + "sidebar.empty.description": "Åpne et prosjekt for å komme i gang", + + "settings.general.section.advanced": "Avansert", + "settings.general.row.shell.title": "Terminalskall", + "settings.general.row.shell.description": + "Velg skallet som skal brukes i terminalen. Kompatible skall brukes også til agentens verktøykall.", + "settings.general.row.shell.autoDefault": "Automatisk (standard)", + "settings.general.row.shell.terminalOnly": "kun terminal", + "settings.general.row.showFileTree.title": "Filtre", + "settings.general.row.showFileTree.description": "Vis filtrepanelet i sesjoner", + "settings.general.row.showNavigation.title": "Navigasjonskontroller", + "settings.general.row.showNavigation.description": + "Vis tilbake- og fremoverknappene på tittellinjen i skrivebordsappen", + "settings.general.row.showSearch.title": "Kommandopalett", + "settings.general.row.showSearch.description": "Vis knappen for søk og kommandopalett på tittellinjen", + "settings.general.row.showTerminal.title": "Terminal", + "settings.general.row.showTerminal.description": "Vis terminalknappen på tittellinjen i skrivebordsappen", + "settings.general.row.showStatus.title": "Serverstatus", + "settings.general.row.showStatus.description": "Vis serverstatusknappen på tittellinjen", + "settings.general.row.mobileTitlebarBottom.title": "Navigasjon nederst", + "settings.general.row.mobileTitlebarBottom.description": + "Plasser tittellinjen og sesjonsfanene nederst på mobilskjermen", + "settings.general.row.showCustomAgents.title": "Egendefinerte agenter", + "settings.general.row.showCustomAgents.description": "Vis agentvelgeren i skrivefeltet", + "settings.general.row.newLayoutDesigns.title": "Ny layout og utforming", + "settings.general.row.newLayoutDesigns.description": + "Aktiver ny layout og utforming for startsiden, skrivefeltet og sesjonsgrensesnittet", + "settings.general.row.pinchZoom.title": "Knip for å zoome", + "settings.general.row.pinchZoom.description": "Tillat knipebevegelser på styreflaten og Ctrl-rulling for å zoome", + "settings.updates.action.downloading": "Laster ned...", + "settings.updates.action.installing": "Installerer...", } satisfies Partial> diff --git a/packages/app/src/i18n/parity.test.ts b/packages/app/src/i18n/parity.test.ts index 8ad1beb56b..725b5f68a0 100644 --- a/packages/app/src/i18n/parity.test.ts +++ b/packages/app/src/i18n/parity.test.ts @@ -1,33 +1,118 @@ import { describe, expect, test } from "bun:test" -import { dict as en } from "./en" -import { dict as ar } from "./ar" -import { dict as br } from "./br" -import { dict as bs } from "./bs" -import { dict as da } from "./da" -import { dict as de } from "./de" -import { dict as es } from "./es" -import { dict as fr } from "./fr" -import { dict as ja } from "./ja" -import { dict as ko } from "./ko" -import { dict as no } from "./no" -import { dict as pl } from "./pl" -import { dict as ru } from "./ru" -import { dict as uk } from "./uk" -import { dict as th } from "./th" -import { dict as zh } from "./zh" -import { dict as zht } from "./zht" -import { dict as tr } from "./tr" -const locales = [ar, br, bs, da, de, es, fr, ja, ko, no, pl, ru, uk, th, tr, zh, zht] -const keys = ["command.session.previous.unseen", "command.session.next.unseen"] as const +const appLocales = [ + "ar", + "br", + "bs", + "da", + "de", + "es", + "fr", + "ja", + "ko", + "no", + "pl", + "ru", + "uk", + "th", + "tr", + "zh", + "zht", +] as const +const desktopLocales = appLocales.filter((locale) => locale !== "th" && locale !== "tr") + +const domains = [ + { + name: "app", + source: "./en.ts", + target: (locale: string) => `./${locale}.ts`, + locales: appLocales, + }, + { + name: "ui", + source: "../../../ui/src/i18n/en.ts", + target: (locale: string) => `../../../ui/src/i18n/${locale}.ts`, + locales: appLocales, + }, + { + name: "desktop", + source: "../../../desktop/src/renderer/i18n/en.ts", + target: (locale: string) => `../../../desktop/src/renderer/i18n/${locale}.ts`, + locales: desktopLocales, + }, +] as const describe("i18n parity", () => { - test("non-English locales translate targeted unseen session keys", () => { - for (const locale of locales) { - for (const key of keys) { - expect(locale[key]).toBeDefined() - expect(locale[key]).not.toBe(en[key]) + test("non-English locales have every English key", async () => { + for (const domain of domains) { + const source = await dictionary(domain.source) + for (const locale of domain.locales) { + const target = await dictionary(domain.target(locale)) + const missing = Object.keys(source).filter((key) => !Object.hasOwn(target, key)) + const extra = Object.keys(target).filter((key) => !Object.hasOwn(source, key)) + expect({ domain: domain.name, locale, missing, extra }).toEqual({ + domain: domain.name, + locale, + missing: [], + extra: [], + }) + } + } + }) + + test("non-English locales preserve English placeholders", async () => { + for (const domain of domains) { + const source = await dictionary(domain.source) + for (const locale of domain.locales) { + const target = await dictionary(domain.target(locale)) + const mismatched = Object.keys(source).filter( + (key) => Object.hasOwn(target, key) && placeholders(source[key]).join() !== placeholders(target[key]).join(), + ) + expect({ domain: domain.name, locale, mismatched }).toEqual({ domain: domain.name, locale, mismatched: [] }) + } + } + }) + + test("non-English locales translate targeted unseen session keys", async () => { + const source = await dictionary("./en.ts") + for (const locale of appLocales) { + const target = await dictionary(`./${locale}.ts`) + for (const key of ["command.session.previous.unseen", "command.session.next.unseen"]) { + expect(target[key]).toBeDefined() + expect(target[key]).not.toBe(source[key]) + } + } + }) + + test("changed-file summary keys preserve rendered English copy and localize complete phrases", async () => { + const source = await dictionary("../../../ui/src/i18n/en.ts") + expect(source["ui.sessionTurn.diffs.changed.one"].replace("{{count}}", "1")).toBe("1 Changed file") + expect(source["ui.sessionTurn.diffs.changed.other"].replace("{{count}}", "2")).toBe("2 Changed files") + expect(source["ui.sessionTurn.diffs.changed"]).toBeUndefined() + + for (const locale of appLocales) { + const target = await dictionary(`../../../ui/src/i18n/${locale}.ts`) + for (const key of ["ui.sessionTurn.diffs.changed.one", "ui.sessionTurn.diffs.changed.other"]) { + expect(target[key].trim()).not.toBe("") + expect(placeholders(target[key])).toEqual(["count"]) } } }) }) + +async function dictionary(file: string) { + const module: unknown = await import(file) + if (typeof module !== "object" || module === null || !("dict" in module) || !isDictionary(module.dict)) { + throw new Error(`Invalid translation dictionary: ${file}`) + } + return module.dict +} + +function isDictionary(value: unknown): value is Record { + if (typeof value !== "object" || value === null || Array.isArray(value)) return false + return Object.values(value).every((item) => typeof item === "string") +} + +function placeholders(value: string) { + return Array.from(value.matchAll(/{{\s*([^}]+?)\s*}}/g), (match) => match[1]).sort() +} diff --git a/packages/app/src/i18n/pl.ts b/packages/app/src/i18n/pl.ts index fcf9927da0..9bc10269fa 100644 --- a/packages/app/src/i18n/pl.ts +++ b/packages/app/src/i18n/pl.ts @@ -21,6 +21,9 @@ export const dict = { "theme.scheme.dark": "Ciemny", "command.sidebar.toggle": "Przełącz pasek boczny", "command.project.open": "Otwórz projekt", + "command.project.previous": "Poprzedni projekt", + "command.project.next": "Następny projekt", + "command.project.index": "Przełącz na projekt {{index}}", "command.provider.connect": "Połącz dostawcę", "command.server.switch": "Przełącz serwer", "command.settings.open": "Otwórz ustawienia", @@ -39,6 +42,7 @@ export const dict = { "command.session.new": "Nowa sesja", "command.file.open": "Otwórz plik", "command.tab.close": "Zamknij kartę", + "command.tab.reopenClosed": "Otwórz ponownie zamkniętą kartę", "command.context.addSelection": "Dodaj zaznaczenie do kontekstu", "command.context.addSelection.description": "Dodaj zaznaczone linie z bieżącego pliku", "command.input.focus": "Fokus na pole wejściowe", @@ -194,6 +198,11 @@ export const dict = { "model.input.video": "wideo", "model.input.pdf": "pdf", "model.tooltip.allows": "Obsługuje: {{inputs}}", + "model.tooltip.context.label": "Kontekst", + "model.tooltip.inputs": "Dane wejściowe", + "model.tooltip.model": "Model", + "model.tooltip.provider": "Dostawca", + "model.tooltip.reasoning": "Wnioskowanie", "model.tooltip.reasoning.allowed": "Obsługuje wnioskowanie", "model.tooltip.reasoning.none": "Brak wnioskowania", "model.tooltip.context": "Limit kontekstu {{limit}}", @@ -203,6 +212,7 @@ export const dict = { "common.loading": "Ładowanie", "common.loading.ellipsis": "...", "common.cancel": "Anuluj", + "common.clear": "Wyczyść", "common.connect": "Połącz", "common.disconnect": "Rozłącz", "common.continue": "Prześlij", @@ -219,6 +229,8 @@ export const dict = { "prompt.mode.shell": "Terminal", "prompt.mode.normal": "Prompt", "prompt.mode.shell.exit": "esc aby wyjść", + "session.child.promptDisabled": "Nie można wysyłać promptów w sesjach podagentów.", + "session.child.backToParent": "Wróć do głównej sesji.", "prompt.example.1": "Napraw TODO w bazie kodu", "prompt.example.2": "Jaki jest stos technologiczny tego projektu?", "prompt.example.3": "Napraw zepsute testy", @@ -315,6 +327,75 @@ export const dict = { "dialog.server.menu.delete": "Usuń", "dialog.server.current": "Obecny serwer", "dialog.server.status.default": "Domyślny", + "wsl.server.add": "Dodaj serwer WSL", + "wsl.server.addShort": "Dodaj WSL", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "Serwer WSL", + "wsl.server.retryStart": "Ponów uruchamianie", + "wsl.server.updating": "Aktualizowanie...", + "wsl.onboarding.step.distro": "Wybierz dystrybucję", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "Sprawdzanie WSL...", + "wsl.onboarding.restartRequired": "Aby dokończyć instalację WSL, uruchom ponownie system Windows.", + "wsl.onboarding.ready": "WSL jest gotowy.", + "wsl.onboarding.required": "Aby kontynuować, wymagany jest WSL.", + "wsl.onboarding.checkingDistros": "Sprawdzanie dystrybucji...", + "wsl.onboarding.installingDistro": "Instalowanie {{distro}}...", + "wsl.onboarding.checkingDistro": "Sprawdzanie {{distro}}...", + "wsl.onboarding.listingDistros": "Pobieranie listy dystrybucji...", + "wsl.onboarding.distroReady": "Dystrybucja {{distro}} jest gotowa.", + "wsl.onboarding.distroNotInstalled": "Dystrybucja {{distro}} nie jest jeszcze zainstalowana.", + "wsl.onboarding.openDistroOnce": "Uruchom raz {{distro}}, aby dokończyć konfigurację.", + "wsl.onboarding.finishingDistro": "Kończenie konfiguracji {{distro}}.", + "wsl.onboarding.pickDistro": "Wybierz dystrybucję lub zainstaluj jedną z poniższych.", + "wsl.onboarding.checkingOpencode": "Sprawdzanie OpenCode...", + "wsl.onboarding.checkingOpencodeIn": "Sprawdzanie OpenCode w dystrybucji {{distro}}...", + "wsl.onboarding.updatingOpencode": "Aktualizowanie OpenCode...", + "wsl.onboarding.updatingOpencodeIn": "Aktualizowanie OpenCode w dystrybucji {{distro}}...", + "wsl.onboarding.updateOpencodeIn": "Zaktualizuj OpenCode w dystrybucji {{distro}}.", + "wsl.onboarding.updateOpencode": "Zaktualizuj OpenCode", + "wsl.onboarding.opencodeReadyIn": "OpenCode jest gotowy w dystrybucji {{distro}}.", + "wsl.onboarding.opencodeReady": "OpenCode jest gotowy.", + "wsl.onboarding.installOpencodeIn": "Zainstaluj OpenCode w dystrybucji {{distro}}.", + "wsl.onboarding.installOpencode": "Zainstaluj OpenCode", + "wsl.onboarding.chooseDistroFirst": "Najpierw wybierz dystrybucję.", + "wsl.onboarding.loadFailed": "Nie udało się załadować stanu WSL.", + "wsl.onboarding.loading": "Ładowanie...", + "wsl.onboarding.installedDistros": "Zainstalowane dystrybucje", + "wsl.onboarding.checkAgain": "Sprawdź ponownie", + "wsl.onboarding.distroStatus.ready": "Gotowa", + "wsl.onboarding.distroStatus.checking": "Sprawdzanie...", + "wsl.onboarding.distroStatus.opencodeMissing": "OpenCode nie jest zainstalowany", + "wsl.onboarding.distroStatus.missingTools": "Brak bash i curl", + "wsl.onboarding.distroStatus.unsupported": "Nieobsługiwana · Użyj WSL 2", + "wsl.onboarding.needAnotherDistro": "Potrzebujesz innej dystrybucji?", + "wsl.onboarding.needAnotherDistroHint": "Zainstaluj dystrybucję systemu Linux z katalogu WSL", + "wsl.onboarding.wslNotInstalled.title": "WSL nie jest zainstalowany", + "wsl.onboarding.wslNotInstalled.description": + "WSL (Podsystem Windows dla systemu Linux) jest wymagany, zanim OpenCode będzie mógł dodać serwer WSL", + "wsl.onboarding.wslUnavailable.title": "WSL jest niedostępny", + "wsl.onboarding.wslUnavailable.description": "OpenCode nie mógł zweryfikować WSL na tym komputerze.", + "wsl.onboarding.installWsl": "Zainstaluj WSL", + "wsl.onboarding.windowsRestartRequired": + "Uruchom ponownie system Windows, aby dokończyć instalację WSL, a następnie ponownie otwórz OpenCode.", + "wsl.onboarding.next": "Dalej", + "wsl.onboarding.refresh": "Odśwież", + "wsl.onboarding.allDistrosAdded": "Wszystkie zainstalowane dystrybucje zostały już dodane.", + "wsl.onboarding.noDistros": "Nie wykryto jeszcze żadnych dystrybucji.", + "wsl.onboarding.install": "Zainstaluj", + "wsl.onboarding.installing": "Instalowanie...", + "wsl.onboarding.installDistro": "Zainstaluj dystrybucję", + "wsl.onboarding.searchDistros": "Szukaj dystrybucji", + "wsl.onboarding.wsl2Required": "Wymagany jest WSL 2.", + "wsl.onboarding.toolsRequired": "Ta dystrybucja wymaga bash i curl.", + "wsl.onboarding.openTerminal": "Otwórz terminal", + "wsl.onboarding.path": "Ścieżka: {{path}}", + "wsl.onboarding.notFound": "nie znaleziono", + "wsl.onboarding.version": "Wersja: {{version}}", + "wsl.onboarding.unknown": "nieznana", + "wsl.onboarding.desktopVersion": "aplikacja komputerowa {{version}}", + "wsl.onboarding.versionMismatch": "Zainstalowana wersja nie jest zgodna z wersją aplikacji komputerowej.", + "wsl.onboarding.adding": "Dodawanie...", "dialog.project.edit.title": "Edytuj projekt", "dialog.project.edit.name": "Nazwa", "dialog.project.edit.icon": "Ikona", @@ -324,7 +405,8 @@ export const dict = { "dialog.project.edit.color": "Kolor", "dialog.project.edit.color.select": "Wybierz kolor {{color}}", "dialog.project.edit.worktree.startup": "Skrypt uruchamiania przestrzeni roboczej", - "dialog.project.edit.worktree.startup.description": "Runs after creating a new workspace (worktree).", + "dialog.project.edit.worktree.startup.description": + "Uruchamiany po utworzeniu nowej przestrzeni roboczej (worktree).", "dialog.project.edit.worktree.startup.placeholder": "np. bun install", "context.breakdown.title": "Podział kontekstu", "context.breakdown.note": 'Przybliżony podział tokenów wejściowych. "Inne" obejmuje definicje narzędzi i narzut.', @@ -371,6 +453,7 @@ export const dict = { "language.no": "Norsk", "language.br": "Português (Brasil)", "language.bs": "Bosanski", + "language.uk": "Українська", "language.th": "ไทย", "language.tr": "Türkçe", "toast.language.title": "Język", @@ -407,10 +490,12 @@ export const dict = { "toast.update.action.notYet": "Jeszcze nie", "error.page.title": "Coś poszło nie tak", "error.page.description": "Wystąpił błąd podczas ładowania aplikacji.", + "error.page.description.localServerStartup": "Wystąpił błąd podczas uruchamiania serwera lokalnego.", "error.page.details.label": "Szczegóły błędu", "error.page.action.restart": "Restartuj", "error.page.action.report": "Zgłoś błąd", "error.page.action.reported": "Błąd zgłoszony", + "error.page.action.exportLogs": "Eksportuj dzienniki", "error.page.action.checking": "Sprawdzanie...", "error.page.action.checkUpdates": "Sprawdź aktualizacje", "error.page.action.updateTo": "Zaktualizuj do {{version}}", @@ -430,7 +515,8 @@ export const dict = { "error.chain.didYouMean": "Czy miałeś na myśli: {{suggestions}}", "error.chain.modelNotFound": "Model nie znaleziony: {{provider}}/{{model}}", "error.chain.checkConfig": "Sprawdź swoją konfigurację (opencode.json) nazwy dostawców/modeli", - "error.chain.mcpFailed": 'MCP server "{{name}}" failed. Note, OpenCode does not support MCP authentication yet.', + "error.chain.mcpFailed": + "Serwer MCP „{{name}}” nie uruchomił się. Uwaga: OpenCode nie obsługuje jeszcze uwierzytelniania MCP.", "error.chain.providerAuthFailed": "Uwierzytelnianie dostawcy nie powiodło się ({{provider}}): {{message}}", "error.chain.providerInitFailed": 'Nie udało się zainicjować dostawcy "{{provider}}". Sprawdź poświadczenia i konfigurację.', @@ -452,10 +538,30 @@ export const dict = { "home.recentProjects": "Ostatnie projekty", "home.empty.title": "Brak ostatnich projektów", "home.empty.description": "Zacznij od otwarcia lokalnego projektu", + "home.title": "Strona główna", + "home.projects": "Projekty", + "home.project.add": "Dodaj projekt", + "home.recentlyClosed": "Ostatnio zamknięte", + "home.server.collapse": "Zwiń projekty serwera", + "home.server.expand": "Rozwiń projekty serwera", + "home.sessions.search.placeholder": "Szukaj sesji", + "home.sessions.search.placeholder.scoped": "Szukaj sesji w {{scope}}", + "home.sessions.search.sessions": "Sesje", + "home.sessions.search.noResults": "Nie znaleziono sesji dla {{query}}", + "home.sessions.empty": "Jeszcze nic tu nie ma", + "home.sessions.empty.description": "Utwórz sesję, aby rozpocząć", + "home.sessions.group.today": "Dzisiaj", + "home.sessions.group.yesterday": "Wczoraj", + "home.sessions.group.older": "Starsze", "session.tab.session": "Sesja", "session.tab.review": "Przegląd", "session.tab.context": "Kontekst", + "session.tab.unknown": "Nieznana sesja", "session.panel.reviewAndFiles": "Przegląd i pliki", + "session.error.notFound": "Nie można znaleźć tej sesji", + "session.error.notFound.description": "Ta karta wskazuje sesję, która nie istnieje już na tym serwerze.", + "session.error.notFound.closeTab": "Zamknij kartę", + "session.error.serverConnection": "Nie można połączyć się z tym serwerem", "session.review.filesChanged": "Zmieniono {{count}} plików", "session.review.change.one": "Zmiana", "session.review.change.other": "Zmiany", @@ -464,6 +570,8 @@ export const dict = { "session.review.noVcs": "Nie wykryto systemu kontroli wersji Git, zmiany nie są wyświetlane", "session.review.noSnapshot": "Śledzenie migawek jest wyłączone w konfiguracji, więc zmiany w sesji są niedostępne", "session.review.noChanges": "Brak zmian", + "session.review.noUncommittedChanges": "Brak jeszcze niezatwierdzonych zmian", + "session.review.noBranchChanges": "Brak jeszcze zmian w gałęzi", "session.files.selectToOpen": "Wybierz plik do otwarcia", "session.files.all": "Wszystkie pliki", "session.files.empty": "Brak plików", @@ -474,9 +582,10 @@ export const dict = { "session.messages.loading": "Ładowanie wiadomości...", "session.messages.jumpToLatest": "Przejdź do najnowszych", "session.context.addToContext": "Dodaj {{selection}} do kontekstu", - "session.todo.title": "Zadania", - "session.todo.collapse": "Zwiń", - "session.todo.expand": "Rozwiń", + "session.question.minimize": "Zminimalizuj pytanie", + "session.question.restore": "Przywróć pytanie", + "session.question.pending.one": "{{count}} oczekujące pytanie", + "session.question.pending.other": "Pytania oczekujące: {{count}}", "session.followupDock.summary.one": "{{count}} wiadomość w kolejce", "session.followupDock.summary.other": "{{count}} wiadomości w kolejce", "session.followupDock.sendNow": "Wyślij teraz", @@ -489,9 +598,16 @@ export const dict = { "session.revertDock.expand": "Rozwiń cofnięte wiadomości", "session.revertDock.restore": "Przywróć wiadomość", "session.new.title": "Zbuduj cokolwiek", + "session.new.project.new": "Nowy projekt", + "session.new.project.search": "Szukaj projektów", + "session.new.project.add": "Dodaj projekt", "session.new.worktree.main": "Główna gałąź", "session.new.worktree.mainWithBranch": "Główna gałąź ({{branch}})", "session.new.worktree.create": "Utwórz nowe drzewo robocze", + "session.new.workspace.runIn": "Uruchom sesję w", + "session.new.workspace.triggerLocal": "Lokalnie", + "session.new.workspace.local": "Lokalne repozytorium", + "session.new.workspace.existing": "Przestrzeń robocza…", "session.new.lastModified": "Ostatnio zmodyfikowano", "session.header.search.placeholder": "Szukaj {{project}}", "session.header.searchFiles": "Szukaj plików", @@ -555,15 +671,18 @@ export const dict = { "sidebar.project.recentSessions": "Ostatnie sesje", "sidebar.project.viewAllSessions": "Zobacz wszystkie sesje", "sidebar.project.clearNotifications": "Wyczyść powiadomienia", + "sidebar.empty.title": "Brak otwartych projektów", + "sidebar.empty.description": "Otwórz projekt, aby rozpocząć", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "Pulpit", "settings.section.server": "Serwer", "settings.tab.general": "Ogólne", "settings.tab.shortcuts": "Skróty", "settings.desktop.section.wsl": "WSL", - "settings.desktop.wsl.title": "WSL integration", - "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.", + "settings.desktop.wsl.title": "Integracja z WSL", + "settings.desktop.wsl.description": "Uruchamiaj serwer OpenCode wewnątrz WSL w systemie Windows.", "settings.general.section.appearance": "Wygląd", + "settings.general.section.advanced": "Zaawansowane", "settings.general.section.notifications": "Powiadomienia systemowe", "settings.general.section.updates": "Aktualizacje", "settings.general.section.sounds": "Efekty dźwiękowe", @@ -571,6 +690,11 @@ export const dict = { "settings.general.section.display": "Ekran", "settings.general.row.language.title": "Język", "settings.general.row.language.description": "Zmień język wyświetlania dla OpenCode", + "settings.general.row.shell.title": "Powłoka terminala", + "settings.general.row.shell.description": + "Wybierz powłokę używaną w terminalu. Zgodne powłoki są również używane przez wywołania narzędzi agenta.", + "settings.general.row.shell.autoDefault": "Automatycznie (domyślna)", + "settings.general.row.shell.terminalOnly": "tylko terminal", "settings.general.row.appearance.title": "Wygląd", "settings.general.row.appearance.description": "Dostosuj wygląd OpenCode na swoim urządzeniu", "settings.general.row.colorScheme.title": "Schemat kolorów", @@ -580,14 +704,30 @@ export const dict = { "settings.general.row.theme.description": "Dostosuj motyw OpenCode.", "settings.general.row.font.title": "Czcionka kodu", "settings.general.row.font.description": "Dostosuj czcionkę używaną w blokach kodu", - "settings.general.row.terminalFont.title": "Terminal Font", - "settings.general.row.terminalFont.description": "Customise the font used in the terminal", + "settings.general.row.terminalFont.title": "Czcionka terminala", + "settings.general.row.terminalFont.description": "Dostosuj czcionkę używaną w terminalu", "settings.general.row.uiFont.title": "Czcionka interfejsu", "settings.general.row.uiFont.description": "Dostosuj czcionkę używaną w całym interfejsie", "settings.general.row.followup.title": "Zachowanie kontynuacji", "settings.general.row.followup.description": "Wybierz, czy kontynuacja ma być natychmiastowa, czy czekać w kolejce", "settings.general.row.followup.option.queue": "Kolejka", "settings.general.row.followup.option.steer": "Sterowanie", + "settings.general.row.showFileTree.title": "Drzewo plików", + "settings.general.row.showFileTree.description": "Pokaż panel drzewa plików w sesjach", + "settings.general.row.showNavigation.title": "Elementy nawigacji", + "settings.general.row.showNavigation.description": + "Pokaż przyciski Wstecz i Dalej na pasku tytułu aplikacji komputerowej", + "settings.general.row.showSearch.title": "Paleta poleceń", + "settings.general.row.showSearch.description": "Pokaż przycisk wyszukiwania i palety poleceń na pasku tytułu", + "settings.general.row.showTerminal.title": "Terminal", + "settings.general.row.showTerminal.description": "Pokaż przycisk terminala na pasku tytułu aplikacji komputerowej", + "settings.general.row.showStatus.title": "Status serwera", + "settings.general.row.showStatus.description": "Pokaż przycisk statusu serwera na pasku tytułu", + "settings.general.row.mobileTitlebarBottom.title": "Dolna nawigacja", + "settings.general.row.mobileTitlebarBottom.description": + "Umieść pasek tytułu i karty sesji u dołu ekranu na urządzeniach mobilnych", + "settings.general.row.showCustomAgents.title": "Agenci niestandardowi", + "settings.general.row.showCustomAgents.description": "Pokaż wybór agenta w edytorze wiadomości", "settings.general.row.reasoningSummaries.title": "Pokaż podsumowania wnioskowania", "settings.general.row.reasoningSummaries.description": "Wyświetlaj podsumowania wnioskowania modelu na osi czasu", "settings.general.row.shellToolPartsExpanded.title": "Rozwijaj elementy narzędzia shell", @@ -596,6 +736,12 @@ export const dict = { "settings.general.row.editToolPartsExpanded.title": "Rozwijaj elementy narzędzia edit", "settings.general.row.editToolPartsExpanded.description": "Domyślnie pokazuj rozwinięte elementy narzędzi edit, write i patch na osi czasu", + "settings.general.row.newLayoutDesigns.title": "Nowy układ i wygląd", + "settings.general.row.newLayoutDesigns.description": + "Włącz przeprojektowany układ, stronę główną, edytor wiadomości i interfejs sesji", + "settings.general.row.pinchZoom.title": "Powiększanie gestem szczypania", + "settings.general.row.pinchZoom.description": + "Zezwalaj na powiększanie gestem szczypania na gładziku i przewijaniem z klawiszem Ctrl", "settings.general.row.wayland.title": "Użyj natywnego Wayland", "settings.general.row.wayland.description": "Wyłącz fallback X11 na Wayland. Wymaga restartu.", "settings.general.row.wayland.tooltip": @@ -608,6 +754,8 @@ export const dict = { "settings.updates.row.check.description": "Ręcznie sprawdź aktualizacje i zainstaluj, jeśli są dostępne", "settings.updates.action.checkNow": "Sprawdź teraz", "settings.updates.action.checking": "Sprawdzanie...", + "settings.updates.action.downloading": "Pobieranie...", + "settings.updates.action.installing": "Instalowanie...", "settings.updates.toast.latest.title": "Masz najnowszą wersję", "settings.updates.toast.latest.description": "Korzystasz z najnowszej wersji OpenCode.", "sound.option.none": "Brak", @@ -728,8 +876,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Ładowanie umiejętności według nazwy", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Uruchamianie zapytań serwera językowego", - "settings.permissions.tool.todowrite.title": "Zapis Todo", - "settings.permissions.tool.todowrite.description": "Aktualizacja listy zadań", "settings.permissions.tool.webfetch.title": "Pobieranie z sieci", "settings.permissions.tool.webfetch.description": "Pobieranie zawartości z adresu URL", "settings.permissions.tool.websearch.title": "Wyszukiwanie w sieci", @@ -792,7 +938,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Śledź, przeglądaj i cofaj zmiany w tym projekcie", "session.review.noVcs.createGit.actionLoading": "Tworzenie repozytorium Git...", "session.review.noVcs.createGit.action": "Utwórz repozytorium Git", - "session.todo.progress": "Ukończono {{done}} z {{total}} zadań", "session.question.progress": "{{current}} z {{total}} pytań", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Eksplorator plików", diff --git a/packages/app/src/i18n/ru.ts b/packages/app/src/i18n/ru.ts index b2f58b101b..466f18b1c0 100644 --- a/packages/app/src/i18n/ru.ts +++ b/packages/app/src/i18n/ru.ts @@ -23,6 +23,9 @@ export const dict = { "command.sidebar.toggle": "Переключить боковую панель", "command.project.open": "Открыть проект", + "command.project.previous": "Предыдущий проект", + "command.project.next": "Следующий проект", + "command.project.index": "Переключиться на проект {{index}}", "command.provider.connect": "Подключить провайдера", "command.server.switch": "Переключить сервер", "command.settings.open": "Открыть настройки", @@ -45,6 +48,7 @@ export const dict = { "command.session.new": "Новая сессия", "command.file.open": "Открыть файл", "command.tab.close": "Закрыть вкладку", + "command.tab.reopenClosed": "Повторно открыть закрытую вкладку", "command.context.addSelection": "Добавить выделение в контекст", "command.context.addSelection.description": "Добавить выбранные строки из текущего файла", "command.input.focus": "Фокус на поле ввода", @@ -208,6 +212,11 @@ export const dict = { "model.input.video": "видео", "model.input.pdf": "pdf", "model.tooltip.allows": "Разрешено: {{inputs}}", + "model.tooltip.context.label": "Контекст", + "model.tooltip.inputs": "Входные данные", + "model.tooltip.model": "Модель", + "model.tooltip.provider": "Провайдер", + "model.tooltip.reasoning": "Рассуждение", "model.tooltip.reasoning.allowed": "Разрешает рассуждение", "model.tooltip.reasoning.none": "Без рассуждения", "model.tooltip.context": "Лимит контекста {{limit}}", @@ -218,6 +227,7 @@ export const dict = { "common.loading": "Загрузка", "common.loading.ellipsis": "...", "common.cancel": "Отмена", + "common.clear": "Очистить", "common.connect": "Подключить", "common.disconnect": "Отключить", "common.continue": "Отправить", @@ -235,6 +245,8 @@ export const dict = { "prompt.mode.shell": "Оболочка", "prompt.mode.normal": "Промпт", "prompt.mode.shell.exit": "esc для выхода", + "session.child.promptDisabled": "В сессиях субагентов нельзя отправлять запросы.", + "session.child.backToParent": "Вернуться к основной сессии.", "prompt.example.1": "Исправить TODO в коде", "prompt.example.2": "Какой технологический стек этого проекта?", @@ -341,6 +353,75 @@ export const dict = { "dialog.server.menu.delete": "Удалить", "dialog.server.current": "Текущий сервер", "dialog.server.status.default": "По умолч.", + "wsl.server.add": "Добавить сервер WSL", + "wsl.server.addShort": "Добавить WSL", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "Сервер WSL", + "wsl.server.retryStart": "Повторить запуск", + "wsl.server.updating": "Обновление...", + "wsl.onboarding.step.distro": "Выбрать дистрибутив", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "Проверка WSL...", + "wsl.onboarding.restartRequired": "Чтобы завершить установку WSL, перезапустите Windows.", + "wsl.onboarding.ready": "WSL готова к работе.", + "wsl.onboarding.required": "Для продолжения требуется WSL.", + "wsl.onboarding.checkingDistros": "Проверка дистрибутивов...", + "wsl.onboarding.installingDistro": "Установка {{distro}}...", + "wsl.onboarding.checkingDistro": "Проверка {{distro}}...", + "wsl.onboarding.listingDistros": "Получение списка дистрибутивов...", + "wsl.onboarding.distroReady": "Дистрибутив {{distro}} готов к работе.", + "wsl.onboarding.distroNotInstalled": "Дистрибутив {{distro}} пока не установлен.", + "wsl.onboarding.openDistroOnce": "Откройте {{distro}} один раз, чтобы завершить настройку.", + "wsl.onboarding.finishingDistro": "Завершение настройки {{distro}}.", + "wsl.onboarding.pickDistro": "Выберите дистрибутив или установите его ниже.", + "wsl.onboarding.checkingOpencode": "Проверка OpenCode...", + "wsl.onboarding.checkingOpencodeIn": "Проверка OpenCode в {{distro}}...", + "wsl.onboarding.updatingOpencode": "Обновление OpenCode...", + "wsl.onboarding.updatingOpencodeIn": "Обновление OpenCode в {{distro}}...", + "wsl.onboarding.updateOpencodeIn": "Обновите OpenCode в {{distro}}.", + "wsl.onboarding.updateOpencode": "Обновить OpenCode", + "wsl.onboarding.opencodeReadyIn": "OpenCode в {{distro}} готов к работе.", + "wsl.onboarding.opencodeReady": "OpenCode готов к работе.", + "wsl.onboarding.installOpencodeIn": "Установите OpenCode в {{distro}}.", + "wsl.onboarding.installOpencode": "Установить OpenCode", + "wsl.onboarding.chooseDistroFirst": "Сначала выберите дистрибутив.", + "wsl.onboarding.loadFailed": "Не удалось загрузить состояние WSL.", + "wsl.onboarding.loading": "Загрузка...", + "wsl.onboarding.installedDistros": "Установленные дистрибутивы", + "wsl.onboarding.checkAgain": "Проверить снова", + "wsl.onboarding.distroStatus.ready": "Готов", + "wsl.onboarding.distroStatus.checking": "Проверка...", + "wsl.onboarding.distroStatus.opencodeMissing": "OpenCode не установлен", + "wsl.onboarding.distroStatus.missingTools": "Отсутствуют bash и curl", + "wsl.onboarding.distroStatus.unsupported": "Не поддерживается · Используйте WSL 2", + "wsl.onboarding.needAnotherDistro": "Нужен другой дистрибутив?", + "wsl.onboarding.needAnotherDistroHint": "Установите дистрибутив Linux из каталога WSL", + "wsl.onboarding.wslNotInstalled.title": "WSL не установлена", + "wsl.onboarding.wslNotInstalled.description": + "Для добавления сервера WSL в OpenCode требуется WSL (Windows Subsystem for Linux)", + "wsl.onboarding.wslUnavailable.title": "WSL недоступна", + "wsl.onboarding.wslUnavailable.description": "OpenCode не смог проверить WSL на этом компьютере.", + "wsl.onboarding.installWsl": "Установить WSL", + "wsl.onboarding.windowsRestartRequired": + "Перезапустите Windows, чтобы завершить установку WSL, затем снова откройте OpenCode.", + "wsl.onboarding.next": "Далее", + "wsl.onboarding.refresh": "Обновить", + "wsl.onboarding.allDistrosAdded": "Все установленные дистрибутивы уже добавлены.", + "wsl.onboarding.noDistros": "Дистрибутивы пока не обнаружены.", + "wsl.onboarding.install": "Установить", + "wsl.onboarding.installing": "Установка...", + "wsl.onboarding.installDistro": "Установить дистрибутив", + "wsl.onboarding.searchDistros": "Поиск дистрибутивов", + "wsl.onboarding.wsl2Required": "Требуется WSL 2.", + "wsl.onboarding.toolsRequired": "Для этого дистрибутива нужны bash и curl.", + "wsl.onboarding.openTerminal": "Открыть терминал", + "wsl.onboarding.path": "Путь: {{path}}", + "wsl.onboarding.notFound": "не найден", + "wsl.onboarding.version": "Версия: {{version}}", + "wsl.onboarding.unknown": "неизвестно", + "wsl.onboarding.desktopVersion": "приложение {{version}}", + "wsl.onboarding.versionMismatch": "Установленная версия не соответствует версии приложения.", + "wsl.onboarding.adding": "Добавление...", "dialog.project.edit.title": "Редактировать проект", "dialog.project.edit.name": "Название", @@ -405,6 +486,7 @@ export const dict = { "language.no": "Norsk", "language.br": "Português (Brasil)", "language.bs": "Bosanski", + "language.uk": "Українська", "language.th": "ไทย", "language.tr": "Türkçe", @@ -452,10 +534,12 @@ export const dict = { "error.page.title": "Что-то пошло не так", "error.page.description": "Произошла ошибка при загрузке приложения.", + "error.page.description.localServerStartup": "Произошла ошибка при запуске локального сервера.", "error.page.details.label": "Детали ошибки", "error.page.action.restart": "Перезапустить", "error.page.action.report": "Сообщить об ошибке", "error.page.action.reported": "Об ошибке сообщено", + "error.page.action.exportLogs": "Экспортировать журналы", "error.page.action.checking": "Проверка...", "error.page.action.checkUpdates": "Проверить обновления", "error.page.action.updateTo": "Обновить до {{version}}", @@ -505,11 +589,31 @@ export const dict = { "home.recentProjects": "Недавние проекты", "home.empty.title": "Нет недавних проектов", "home.empty.description": "Начните с открытия локального проекта", + "home.title": "Главная", + "home.projects": "Проекты", + "home.project.add": "Добавить проект", + "home.recentlyClosed": "Недавно закрытые", + "home.server.collapse": "Свернуть проекты сервера", + "home.server.expand": "Развернуть проекты сервера", + "home.sessions.search.placeholder": "Поиск сессий", + "home.sessions.search.placeholder.scoped": "Поиск сессий в {{scope}}", + "home.sessions.search.sessions": "Сессии", + "home.sessions.search.noResults": "Сессии по запросу {{query}} не найдены", + "home.sessions.empty": "Здесь пока ничего нет", + "home.sessions.empty.description": "Создайте сессию, чтобы начать", + "home.sessions.group.today": "Сегодня", + "home.sessions.group.yesterday": "Вчера", + "home.sessions.group.older": "Ранее", "session.tab.session": "Сессия", "session.tab.review": "Обзор", "session.tab.context": "Контекст", + "session.tab.unknown": "Неизвестная сессия", "session.panel.reviewAndFiles": "Обзор и файлы", + "session.error.notFound": "Эта сессия не найдена", + "session.error.notFound.description": "Эта вкладка указывает на сессию, которой больше нет на этом сервере.", + "session.error.notFound.closeTab": "Закрыть вкладку", + "session.error.serverConnection": "Не удаётся подключиться к этому серверу", "session.review.filesChanged": "{{count}} файлов изменено", "session.review.change.one": "Изменение", "session.review.change.other": "Изменения", @@ -518,6 +622,8 @@ export const dict = { "session.review.noVcs": "Система контроля версий Git не обнаружена, изменения не отображаются", "session.review.noSnapshot": "Отслеживание снимков отключено в настройках, поэтому изменения сессии недоступны", "session.review.noChanges": "Нет изменений", + "session.review.noUncommittedChanges": "Пока нет незафиксированных изменений", + "session.review.noBranchChanges": "Пока нет изменений в ветке", "session.files.selectToOpen": "Выберите файл, чтобы открыть", "session.files.all": "Все файлы", "session.files.empty": "Нет файлов", @@ -529,9 +635,10 @@ export const dict = { "session.messages.jumpToLatest": "Перейти к последнему", "session.context.addToContext": "Добавить {{selection}} в контекст", - "session.todo.title": "Задачи", - "session.todo.collapse": "Свернуть", - "session.todo.expand": "Развернуть", + "session.question.minimize": "Свернуть вопрос", + "session.question.restore": "Восстановить вопрос", + "session.question.pending.one": "{{count}} вопрос без ответа", + "session.question.pending.other": "Вопросы без ответа: {{count}}", "session.followupDock.summary.one": "{{count}} сообщение в очереди", "session.followupDock.summary.other": "{{count}} сообщений в очереди", "session.followupDock.sendNow": "Отправить сейчас", @@ -545,9 +652,16 @@ export const dict = { "session.revertDock.restore": "Восстановить сообщение", "session.new.title": "Создавайте что угодно", + "session.new.project.new": "Новый проект", + "session.new.project.search": "Поиск проектов", + "session.new.project.add": "Добавить проект", "session.new.worktree.main": "Основная ветка", "session.new.worktree.mainWithBranch": "Основная ветка ({{branch}})", "session.new.worktree.create": "Создать новый worktree", + "session.new.workspace.runIn": "Запустить сессию в", + "session.new.workspace.triggerLocal": "Локально", + "session.new.workspace.local": "Локальный репозиторий", + "session.new.workspace.existing": "Рабочее пространство…", "session.new.lastModified": "Последнее изменение", "session.header.search.placeholder": "Поиск {{project}}", @@ -619,6 +733,8 @@ export const dict = { "sidebar.project.recentSessions": "Недавние сессии", "sidebar.project.viewAllSessions": "Посмотреть все сессии", "sidebar.project.clearNotifications": "Очистить уведомления", + "sidebar.empty.title": "Нет открытых проектов", + "sidebar.empty.description": "Откройте проект, чтобы начать", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "Приложение", @@ -630,6 +746,7 @@ export const dict = { "settings.desktop.wsl.description": "Запускать сервер OpenCode внутри WSL на Windows.", "settings.general.section.appearance": "Внешний вид", + "settings.general.section.advanced": "Дополнительно", "settings.general.section.notifications": "Системные уведомления", "settings.general.section.updates": "Обновления", "settings.general.section.sounds": "Звуковые эффекты", @@ -638,6 +755,11 @@ export const dict = { "settings.general.row.language.title": "Язык", "settings.general.row.language.description": "Изменить язык отображения OpenCode", + "settings.general.row.shell.title": "Оболочка терминала", + "settings.general.row.shell.description": + "Выберите оболочку для терминала. Совместимые оболочки также используются агентом при вызове инструментов.", + "settings.general.row.shell.autoDefault": "Авто (по умолчанию)", + "settings.general.row.shell.terminalOnly": "только терминал", "settings.general.row.appearance.title": "Внешний вид", "settings.general.row.appearance.description": "Настройте как OpenCode выглядит на вашем устройстве", "settings.general.row.colorScheme.title": "Цветовая схема", @@ -646,8 +768,8 @@ export const dict = { "settings.general.row.theme.description": "Настройте оформление OpenCode.", "settings.general.row.font.title": "Шрифт кода", "settings.general.row.font.description": "Настройте шрифт, используемый в блоках кода", - "settings.general.row.terminalFont.title": "Terminal Font", - "settings.general.row.terminalFont.description": "Customise the font used in the terminal", + "settings.general.row.terminalFont.title": "Шрифт терминала", + "settings.general.row.terminalFont.description": "Настройте шрифт, используемый в терминале", "settings.general.row.uiFont.title": "Шрифт интерфейса", "settings.general.row.uiFont.description": "Настройте шрифт, используемый во всем интерфейсе", "settings.general.row.followup.title": "Поведение уточняющих вопросов", @@ -655,6 +777,22 @@ export const dict = { "Выберите, отправлять ли уточняющие вопросы сразу или помещать их в очередь", "settings.general.row.followup.option.queue": "Очередь", "settings.general.row.followup.option.steer": "Направлять", + "settings.general.row.showFileTree.title": "Дерево файлов", + "settings.general.row.showFileTree.description": "Показывать панель дерева файлов в сессиях", + "settings.general.row.showNavigation.title": "Элементы навигации", + "settings.general.row.showNavigation.description": + "Показывать кнопки «Назад» и «Вперёд» в строке заголовка приложения", + "settings.general.row.showSearch.title": "Палитра команд", + "settings.general.row.showSearch.description": "Показывать кнопку поиска и палитры команд в строке заголовка", + "settings.general.row.showTerminal.title": "Терминал", + "settings.general.row.showTerminal.description": "Показывать кнопку терминала в строке заголовка приложения", + "settings.general.row.showStatus.title": "Состояние сервера", + "settings.general.row.showStatus.description": "Показывать кнопку состояния сервера в строке заголовка", + "settings.general.row.mobileTitlebarBottom.title": "Нижняя навигация", + "settings.general.row.mobileTitlebarBottom.description": + "На мобильных устройствах размещать строку заголовка и вкладки сессии внизу экрана", + "settings.general.row.showCustomAgents.title": "Пользовательские агенты", + "settings.general.row.showCustomAgents.description": "Показывать выбор агента в редакторе запросов", "settings.general.row.reasoningSummaries.title": "Показывать сводки рассуждений", "settings.general.row.reasoningSummaries.description": "Отображать сводки рассуждений модели в ленте", @@ -664,6 +802,12 @@ export const dict = { "settings.general.row.editToolPartsExpanded.title": "Разворачивать элементы инструмента edit", "settings.general.row.editToolPartsExpanded.description": "Показывать элементы инструментов edit, write и patch в ленте развернутыми по умолчанию", + "settings.general.row.newLayoutDesigns.title": "Новая компоновка и оформление", + "settings.general.row.newLayoutDesigns.description": + "Включить обновлённую компоновку, главную страницу, редактор запросов и интерфейс сессии", + "settings.general.row.pinchZoom.title": "Масштабирование щипком", + "settings.general.row.pinchZoom.description": + "Разрешить масштабирование жестом щипка на трекпаде и прокруткой с Ctrl", "settings.general.row.wayland.title": "Использовать нативный Wayland", "settings.general.row.wayland.description": "Отключить X11 fallback на Wayland. Требуется перезапуск.", "settings.general.row.wayland.tooltip": @@ -678,6 +822,8 @@ export const dict = { "settings.updates.row.check.description": "Проверить обновления вручную и установить, если доступны", "settings.updates.action.checkNow": "Проверить сейчас", "settings.updates.action.checking": "Проверка...", + "settings.updates.action.downloading": "Загрузка...", + "settings.updates.action.installing": "Установка...", "settings.updates.toast.latest.title": "У вас последняя версия", "settings.updates.toast.latest.description": "Вы используете последнюю версию OpenCode.", "sound.option.none": "Нет", @@ -807,8 +953,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Загрузка навыка по имени", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Запросы к языковому серверу", - "settings.permissions.tool.todowrite.title": "Todo Write", - "settings.permissions.tool.todowrite.description": "Обновление списка задач", "settings.permissions.tool.webfetch.title": "Web Fetch", "settings.permissions.tool.webfetch.description": "Получение контента по URL", "settings.permissions.tool.websearch.title": "Web Search", @@ -874,7 +1018,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Отслеживайте, просматривайте и отменяйте изменения в этом проекте", "session.review.noVcs.createGit.actionLoading": "Создание репозитория Git...", "session.review.noVcs.createGit.action": "Создать репозиторий Git", - "session.todo.progress": "Выполнено {{done}} из {{total}} задач", "session.question.progress": "{{current}} из {{total}} вопросов", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Проводник", diff --git a/packages/app/src/i18n/th.ts b/packages/app/src/i18n/th.ts index d066f3c616..cd42cc46d3 100644 --- a/packages/app/src/i18n/th.ts +++ b/packages/app/src/i18n/th.ts @@ -23,6 +23,9 @@ export const dict = { "command.sidebar.toggle": "สลับแถบข้าง", "command.project.open": "เปิดโปรเจกต์", + "command.project.previous": "โปรเจกต์ก่อนหน้า", + "command.project.next": "โปรเจกต์ถัดไป", + "command.project.index": "สลับไปยังโปรเจกต์ {{index}}", "command.provider.connect": "เชื่อมต่อผู้ให้บริการ", "command.server.switch": "สลับเซิร์ฟเวอร์", "command.settings.open": "เปิดการตั้งค่า", @@ -32,7 +35,7 @@ export const dict = { "command.session.next.unseen": "เซสชันที่ยังไม่ได้อ่านถัดไป", "command.session.archive": "จัดเก็บเซสชัน", - "command.palette": "คำสั่งค้นหา", + "command.palette": "ชุดคำสั่ง", "command.theme.cycle": "เปลี่ยนธีม", "command.theme.set": "ใช้ธีม: {{theme}}", @@ -45,6 +48,7 @@ export const dict = { "command.session.new": "เซสชันใหม่", "command.file.open": "เปิดไฟล์", "command.tab.close": "ปิดแท็บ", + "command.tab.reopenClosed": "เปิดแท็บที่ปิดไปอีกครั้ง", "command.context.addSelection": "เพิ่มส่วนที่เลือกไปยังบริบท", "command.context.addSelection.description": "เพิ่มบรรทัดที่เลือกจากไฟล์ปัจจุบัน", "command.input.focus": "โฟกัสช่องป้อนข้อมูล", @@ -163,7 +167,7 @@ export const dict = { "provider.custom.field.providerID.placeholder": "myprovider", "provider.custom.field.providerID.description": "ตัวอักษรพิมพ์เล็ก ตัวเลข ยัติภังค์ หรือขีดล่าง", "provider.custom.field.name.label": "ชื่อที่แสดง", - "provider.custom.field.name.placeholder": "My AI Provider", + "provider.custom.field.name.placeholder": "ผู้ให้บริการ AI ของฉัน", "provider.custom.field.baseURL.label": "URL พื้นฐาน", "provider.custom.field.baseURL.placeholder": "https://api.myprovider.com/v1", "provider.custom.field.apiKey.label": "คีย์ API", @@ -208,6 +212,11 @@ export const dict = { "model.input.video": "วิดีโอ", "model.input.pdf": "PDF", "model.tooltip.allows": "อนุญาต: {{inputs}}", + "model.tooltip.context.label": "บริบท", + "model.tooltip.inputs": "ข้อมูลนำเข้า", + "model.tooltip.model": "โมเดล", + "model.tooltip.provider": "ผู้ให้บริการ", + "model.tooltip.reasoning": "การใช้เหตุผล", "model.tooltip.reasoning.allowed": "อนุญาตการใช้เหตุผล", "model.tooltip.reasoning.none": "ไม่มีการใช้เหตุผล", "model.tooltip.context": "ขีดจำกัดบริบท {{limit}}", @@ -218,6 +227,7 @@ export const dict = { "common.loading": "กำลังโหลด", "common.loading.ellipsis": "...", "common.cancel": "ยกเลิก", + "common.clear": "ล้าง", "common.connect": "เชื่อมต่อ", "common.disconnect": "ยกเลิกการเชื่อมต่อ", "common.continue": "ส่ง", @@ -235,6 +245,8 @@ export const dict = { "prompt.mode.shell": "เชลล์", "prompt.mode.normal": "พรอมต์", "prompt.mode.shell.exit": "กด esc เพื่อออก", + "session.child.promptDisabled": "ไม่สามารถส่งพรอมต์ในเซสชันเอเจนต์ย่อยได้.", + "session.child.backToParent": "กลับไปยังเซสชันหลัก.", "prompt.example.1": "แก้ไข TODO ในโค้ดเบส", "prompt.example.2": "เทคโนโลยีของโปรเจกต์นี้คืออะไร?", @@ -341,6 +353,75 @@ export const dict = { "dialog.server.menu.delete": "ลบ", "dialog.server.current": "เซิร์ฟเวอร์ปัจจุบัน", "dialog.server.status.default": "ค่าเริ่มต้น", + "wsl.server.add": "เพิ่มเซิร์ฟเวอร์ WSL", + "wsl.server.addShort": "เพิ่ม WSL", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "เซิร์ฟเวอร์ WSL", + "wsl.server.retryStart": "ลองเริ่มอีกครั้ง", + "wsl.server.updating": "กำลังอัปเดต...", + "wsl.onboarding.step.distro": "เลือกดิสโทร", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "กำลังตรวจสอบ WSL...", + "wsl.onboarding.restartRequired": "ต้องรีสตาร์ท Windows เพื่อให้การติดตั้ง WSL เสร็จสมบูรณ์.", + "wsl.onboarding.ready": "WSL พร้อมใช้งานแล้ว.", + "wsl.onboarding.required": "ต้องมี WSL เพื่อดำเนินการต่อ.", + "wsl.onboarding.checkingDistros": "กำลังตรวจสอบดิสโทร...", + "wsl.onboarding.installingDistro": "กำลังติดตั้ง {{distro}}...", + "wsl.onboarding.checkingDistro": "กำลังตรวจสอบ {{distro}}...", + "wsl.onboarding.listingDistros": "กำลังแสดงรายการดิสโทร...", + "wsl.onboarding.distroReady": "{{distro}} พร้อมใช้งานแล้ว.", + "wsl.onboarding.distroNotInstalled": "ยังไม่ได้ติดตั้ง {{distro}}.", + "wsl.onboarding.openDistroOnce": "เปิด {{distro}} หนึ่งครั้งเพื่อให้การตั้งค่าเสร็จสมบูรณ์.", + "wsl.onboarding.finishingDistro": "กำลังตั้งค่า {{distro}} ให้เสร็จสมบูรณ์.", + "wsl.onboarding.pickDistro": "เลือกดิสโทรหรือติดตั้งจากรายการด้านล่าง.", + "wsl.onboarding.checkingOpencode": "กำลังตรวจสอบ OpenCode...", + "wsl.onboarding.checkingOpencodeIn": "กำลังตรวจสอบ OpenCode ใน {{distro}}...", + "wsl.onboarding.updatingOpencode": "กำลังอัปเดต OpenCode...", + "wsl.onboarding.updatingOpencodeIn": "กำลังอัปเดต OpenCode ใน {{distro}}...", + "wsl.onboarding.updateOpencodeIn": "อัปเดต OpenCode ใน {{distro}}.", + "wsl.onboarding.updateOpencode": "อัปเดต OpenCode", + "wsl.onboarding.opencodeReadyIn": "OpenCode พร้อมใช้งานใน {{distro}} แล้ว.", + "wsl.onboarding.opencodeReady": "OpenCode พร้อมใช้งานแล้ว.", + "wsl.onboarding.installOpencodeIn": "ติดตั้ง OpenCode ใน {{distro}}.", + "wsl.onboarding.installOpencode": "ติดตั้ง OpenCode", + "wsl.onboarding.chooseDistroFirst": "เลือกดิสโทรก่อน.", + "wsl.onboarding.loadFailed": "ไม่สามารถโหลดสถานะ WSL ได้.", + "wsl.onboarding.loading": "กำลังโหลด...", + "wsl.onboarding.installedDistros": "ดิสโทรที่ติดตั้งแล้ว", + "wsl.onboarding.checkAgain": "ตรวจสอบอีกครั้ง", + "wsl.onboarding.distroStatus.ready": "พร้อมใช้งาน", + "wsl.onboarding.distroStatus.checking": "กำลังตรวจสอบ...", + "wsl.onboarding.distroStatus.opencodeMissing": "ยังไม่ได้ติดตั้ง OpenCode", + "wsl.onboarding.distroStatus.missingTools": "ไม่มี bash, curl", + "wsl.onboarding.distroStatus.unsupported": "ไม่รองรับ · ใช้ WSL 2", + "wsl.onboarding.needAnotherDistro": "ต้องการดิสโทรอื่น?", + "wsl.onboarding.needAnotherDistroHint": "ติดตั้งดิสทริบิวชัน Linux จากแค็ตตาล็อก WSL", + "wsl.onboarding.wslNotInstalled.title": "ยังไม่ได้ติดตั้ง WSL", + "wsl.onboarding.wslNotInstalled.description": + "ต้องมี WSL (Windows Subsystem for Linux) ก่อนที่ OpenCode จะเพิ่มเซิร์ฟเวอร์ WSL ได้", + "wsl.onboarding.wslUnavailable.title": "WSL ไม่พร้อมใช้งาน", + "wsl.onboarding.wslUnavailable.description": "OpenCode ไม่สามารถตรวจสอบ WSL บนเครื่องนี้ได้.", + "wsl.onboarding.installWsl": "ติดตั้ง WSL", + "wsl.onboarding.windowsRestartRequired": + "รีสตาร์ท Windows เพื่อให้การติดตั้ง WSL เสร็จสมบูรณ์ แล้วเปิด OpenCode อีกครั้ง.", + "wsl.onboarding.next": "ถัดไป", + "wsl.onboarding.refresh": "รีเฟรช", + "wsl.onboarding.allDistrosAdded": "เพิ่มดิสโทรที่ติดตั้งไว้ทั้งหมดแล้ว.", + "wsl.onboarding.noDistros": "ยังไม่พบดิสโทร.", + "wsl.onboarding.install": "ติดตั้ง", + "wsl.onboarding.installing": "กำลังติดตั้ง...", + "wsl.onboarding.installDistro": "ติดตั้งดิสโทร", + "wsl.onboarding.searchDistros": "ค้นหาดิสโทร", + "wsl.onboarding.wsl2Required": "ต้องใช้ WSL 2.", + "wsl.onboarding.toolsRequired": "ดิสโทรนี้ต้องมี bash และ curl.", + "wsl.onboarding.openTerminal": "เปิดเทอร์มินัล", + "wsl.onboarding.path": "เส้นทาง: {{path}}", + "wsl.onboarding.notFound": "ไม่พบ", + "wsl.onboarding.version": "เวอร์ชัน: {{version}}", + "wsl.onboarding.unknown": "ไม่ทราบ", + "wsl.onboarding.desktopVersion": "เดสก์ท็อป {{version}}", + "wsl.onboarding.versionMismatch": "เวอร์ชันที่ติดตั้งไม่ตรงกับเวอร์ชันของแอปเดสก์ท็อป.", + "wsl.onboarding.adding": "กำลังเพิ่ม...", "dialog.project.edit.title": "แก้ไขโปรเจกต์", "dialog.project.edit.name": "ชื่อ", @@ -403,6 +484,7 @@ export const dict = { "language.no": "Norsk", "language.br": "Português (Brasil)", "language.bs": "Bosanski", + "language.uk": "Українська", "language.th": "ไทย", "language.tr": "Türkçe", @@ -451,10 +533,12 @@ export const dict = { "error.page.title": "เกิดข้อผิดพลาด", "error.page.description": "เกิดข้อผิดพลาดระหว่างการโหลดแอปพลิเคชัน", + "error.page.description.localServerStartup": "เกิดข้อผิดพลาดขณะเริ่มเซิร์ฟเวอร์ในเครื่อง.", "error.page.details.label": "รายละเอียดข้อผิดพลาด", "error.page.action.restart": "รีสตาร์ท", "error.page.action.report": "รายงานข้อผิดพลาด", "error.page.action.reported": "รายงานข้อผิดพลาดแล้ว", + "error.page.action.exportLogs": "ส่งออกบันทึก", "error.page.action.checking": "กำลังตรวจสอบ...", "error.page.action.checkUpdates": "ตรวจสอบการอัปเดต", "error.page.action.updateTo": "อัปเดตเป็น {{version}}", @@ -500,11 +584,31 @@ export const dict = { "home.recentProjects": "โปรเจกต์ล่าสุด", "home.empty.title": "ไม่มีโปรเจกต์ล่าสุด", "home.empty.description": "เริ่มต้นโดยเปิดโปรเจกต์ในเครื่อง", + "home.title": "หน้าหลัก", + "home.projects": "โปรเจกต์", + "home.project.add": "เพิ่มโปรเจกต์", + "home.recentlyClosed": "ที่ปิดไปล่าสุด", + "home.server.collapse": "ย่อโปรเจกต์ของเซิร์ฟเวอร์", + "home.server.expand": "ขยายโปรเจกต์ของเซิร์ฟเวอร์", + "home.sessions.search.placeholder": "ค้นหาเซสชัน", + "home.sessions.search.placeholder.scoped": "ค้นหาเซสชันใน {{scope}}", + "home.sessions.search.sessions": "เซสชัน", + "home.sessions.search.noResults": "ไม่พบเซสชันสำหรับ {{query}}", + "home.sessions.empty": "ยังไม่มีอะไรที่นี่", + "home.sessions.empty.description": "สร้างเซสชันเพื่อเริ่มต้น", + "home.sessions.group.today": "วันนี้", + "home.sessions.group.yesterday": "เมื่อวาน", + "home.sessions.group.older": "ก่อนหน้านี้", "session.tab.session": "เซสชัน", "session.tab.review": "ตรวจสอบ", "session.tab.context": "บริบท", + "session.tab.unknown": "เซสชันที่ไม่รู้จัก", "session.panel.reviewAndFiles": "ตรวจสอบและไฟล์", + "session.error.notFound": "ไม่พบเซสชันนี้", + "session.error.notFound.description": "แท็บนี้อ้างถึงเซสชันที่ไม่มีอยู่บนเซิร์ฟเวอร์นี้แล้ว.", + "session.error.notFound.closeTab": "ปิดแท็บ", + "session.error.serverConnection": "ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์นี้", "session.review.filesChanged": "{{count}} ไฟล์ที่เปลี่ยนแปลง", "session.review.change.one": "การเปลี่ยนแปลง", "session.review.change.other": "การเปลี่ยนแปลง", @@ -513,6 +617,8 @@ export const dict = { "session.review.noVcs": "ไม่ตรวจพบระบบควบคุมเวอร์ชัน Git การเปลี่ยนแปลงจะไม่แสดง", "session.review.noSnapshot": "การติดตามสแนปชอตถูกปิดใช้งานในการกำหนดค่า ดังนั้นการเปลี่ยนแปลงเซสชันจึงไม่พร้อมใช้งาน", "session.review.noChanges": "ไม่มีการเปลี่ยนแปลง", + "session.review.noUncommittedChanges": "ยังไม่มีการเปลี่ยนแปลงที่รอคอมมิต", + "session.review.noBranchChanges": "ยังไม่มีการเปลี่ยนแปลงในสาขา", "session.files.selectToOpen": "เลือกไฟล์เพื่อเปิด", "session.files.empty": "ไม่มีไฟล์", @@ -526,9 +632,10 @@ export const dict = { "session.messages.jumpToLatest": "ไปที่ล่าสุด", "session.context.addToContext": "เพิ่ม {{selection}} ไปยังบริบท", - "session.todo.title": "สิ่งที่ต้องทำ", - "session.todo.collapse": "ย่อ", - "session.todo.expand": "ขยาย", + "session.question.minimize": "ย่อคำถาม", + "session.question.restore": "คืนค่าคำถาม", + "session.question.pending.one": "คำถามที่รอดำเนินการ {{count}} ข้อ", + "session.question.pending.other": "คำถามที่รอดำเนินการ {{count}} ข้อ", "session.followupDock.summary.one": "{{count}} ข้อความในคิว", "session.followupDock.summary.other": "{{count}} ข้อความในคิว", "session.followupDock.sendNow": "ส่งทันที", @@ -542,9 +649,16 @@ export const dict = { "session.revertDock.restore": "กู้คืนข้อความ", "session.new.title": "สร้างอะไรก็ได้", + "session.new.project.new": "โปรเจกต์ใหม่", + "session.new.project.search": "ค้นหาโปรเจกต์", + "session.new.project.add": "เพิ่มโปรเจกต์", "session.new.worktree.main": "สาขาหลัก", "session.new.worktree.mainWithBranch": "สาขาหลัก ({{branch}})", "session.new.worktree.create": "สร้าง worktree ใหม่", + "session.new.workspace.runIn": "เรียกใช้เซสชันใน", + "session.new.workspace.triggerLocal": "ในเครื่อง", + "session.new.workspace.local": "รีโพซิทอรีในเครื่อง", + "session.new.workspace.existing": "พื้นที่ทำงาน…", "session.new.lastModified": "แก้ไขล่าสุด", "session.header.search.placeholder": "ค้นหา {{project}}", @@ -612,6 +726,8 @@ export const dict = { "sidebar.project.recentSessions": "เซสชันล่าสุด", "sidebar.project.viewAllSessions": "ดูเซสชันทั้งหมด", "sidebar.project.clearNotifications": "ล้างการแจ้งเตือน", + "sidebar.empty.title": "ไม่มีโปรเจกต์ที่เปิดอยู่", + "sidebar.empty.description": "เปิดโปรเจกต์เพื่อเริ่มต้น", "app.name.desktop": "OpenCode Desktop", @@ -624,6 +740,7 @@ export const dict = { "settings.desktop.wsl.description": "เรียกใช้เซิร์ฟเวอร์ OpenCode ภายใน WSL บน Windows", "settings.general.section.appearance": "รูปลักษณ์", + "settings.general.section.advanced": "ขั้นสูง", "settings.general.section.notifications": "การแจ้งเตือนระบบ", "settings.general.section.updates": "การอัปเดต", "settings.general.section.sounds": "เสียงเอฟเฟกต์", @@ -632,6 +749,11 @@ export const dict = { "settings.general.row.language.title": "ภาษา", "settings.general.row.language.description": "เปลี่ยนภาษาที่แสดงสำหรับ OpenCode", + "settings.general.row.shell.title": "เชลล์เทอร์มินัล", + "settings.general.row.shell.description": + "เลือกเชลล์ที่จะใช้กับเทอร์มินัล เชลล์ที่เข้ากันได้จะใช้สำหรับการเรียกเครื่องมือของเอเจนต์ด้วย", + "settings.general.row.shell.autoDefault": "อัตโนมัติ (ค่าเริ่มต้น)", + "settings.general.row.shell.terminalOnly": "เทอร์มินัลเท่านั้น", "settings.general.row.appearance.title": "รูปลักษณ์", "settings.general.row.appearance.description": "ปรับแต่งวิธีการที่ OpenCode มีลักษณะบนอุปกรณ์ของคุณ", "settings.general.row.colorScheme.title": "โทนสี", @@ -640,14 +762,29 @@ export const dict = { "settings.general.row.theme.description": "ปรับแต่งวิธีการที่ OpenCode มีธีม", "settings.general.row.font.title": "ฟอนต์โค้ด", "settings.general.row.font.description": "ปรับแต่งฟอนต์ที่ใช้ในบล็อกโค้ด", - "settings.general.row.terminalFont.title": "Terminal Font", - "settings.general.row.terminalFont.description": "Customise the font used in the terminal", + "settings.general.row.terminalFont.title": "ฟอนต์เทอร์มินัล", + "settings.general.row.terminalFont.description": "ปรับแต่งฟอนต์ที่ใช้ในเทอร์มินัล", "settings.general.row.uiFont.title": "ฟอนต์ UI", "settings.general.row.uiFont.description": "ปรับแต่งฟอนต์ที่ใช้ทั่วทั้งอินเทอร์เฟซ", "settings.general.row.followup.title": "พฤติกรรมการติดตามผล", "settings.general.row.followup.description": "เลือกว่าจะให้พร้อมท์ติดตามผลทำงานทันทีหรือรอในคิว", "settings.general.row.followup.option.queue": "คิว", "settings.general.row.followup.option.steer": "นำทาง", + "settings.general.row.showFileTree.title": "ต้นไม้ไฟล์", + "settings.general.row.showFileTree.description": "แสดงแผงต้นไม้ไฟล์ในเซสชัน", + "settings.general.row.showNavigation.title": "ตัวควบคุมการนำทาง", + "settings.general.row.showNavigation.description": "แสดงปุ่มย้อนกลับและไปข้างหน้าในแถบชื่อเรื่องเดสก์ท็อป", + "settings.general.row.showSearch.title": "ชุดคำสั่ง", + "settings.general.row.showSearch.description": "แสดงปุ่มค้นหาและชุดคำสั่งในแถบชื่อเรื่อง", + "settings.general.row.showTerminal.title": "เทอร์มินัล", + "settings.general.row.showTerminal.description": "แสดงปุ่มเทอร์มินัลในแถบชื่อเรื่องเดสก์ท็อป", + "settings.general.row.showStatus.title": "สถานะเซิร์ฟเวอร์", + "settings.general.row.showStatus.description": "แสดงปุ่มสถานะเซิร์ฟเวอร์ในแถบชื่อเรื่อง", + "settings.general.row.mobileTitlebarBottom.title": "การนำทางด้านล่าง", + "settings.general.row.mobileTitlebarBottom.description": + "วางแถบชื่อเรื่องและแท็บเซสชันไว้ด้านล่างของหน้าจอบนอุปกรณ์เคลื่อนที่", + "settings.general.row.showCustomAgents.title": "เอเจนต์ที่กำหนดเอง", + "settings.general.row.showCustomAgents.description": "แสดงตัวเลือกเอเจนต์ในช่องเขียนข้อความ", "settings.general.row.reasoningSummaries.title": "แสดงสรุปการใช้เหตุผล", "settings.general.row.reasoningSummaries.description": "แสดงสรุปการใช้เหตุผลของโมเดลในไทม์ไลน์", "settings.general.row.shellToolPartsExpanded.title": "ขยายส่วนเครื่องมือ shell", @@ -655,6 +792,11 @@ export const dict = { "settings.general.row.editToolPartsExpanded.title": "ขยายส่วนเครื่องมือ edit", "settings.general.row.editToolPartsExpanded.description": "แสดงส่วนเครื่องมือ edit, write และ patch แบบขยายตามค่าเริ่มต้นในไทม์ไลน์", + "settings.general.row.newLayoutDesigns.title": "เลย์เอาต์และดีไซน์ใหม่", + "settings.general.row.newLayoutDesigns.description": + "เปิดใช้เลย์เอาต์ หน้าแรก ช่องเขียนข้อความ และ UI เซสชันที่ออกแบบใหม่", + "settings.general.row.pinchZoom.title": "บีบนิ้วเพื่อซูม", + "settings.general.row.pinchZoom.description": "อนุญาตให้ใช้ท่าบีบนิ้วบนแทร็คแพดและ Ctrl-scroll เพื่อซูม", "settings.general.row.wayland.title": "ใช้ Wayland แบบเนทีฟ", "settings.general.row.wayland.description": "ปิดใช้งาน X11 fallback บน Wayland ต้องรีสตาร์ท", "settings.general.row.wayland.tooltip": "บน Linux ที่มีจอภาพรีเฟรชเรตแบบผสม Wayland แบบเนทีฟอาจเสถียรกว่า", @@ -668,6 +810,8 @@ export const dict = { "settings.updates.row.check.description": "ตรวจสอบการอัปเดตด้วยตนเองและติดตั้งหากมี", "settings.updates.action.checkNow": "ตรวจสอบทันที", "settings.updates.action.checking": "กำลังตรวจสอบ...", + "settings.updates.action.downloading": "กำลังดาวน์โหลด...", + "settings.updates.action.installing": "กำลังติดตั้ง...", "settings.updates.toast.latest.title": "คุณเป็นเวอร์ชันล่าสุดแล้ว", "settings.updates.toast.latest.description": "คุณกำลังใช้งาน OpenCode เวอร์ชันล่าสุด", @@ -795,8 +939,6 @@ export const dict = { "settings.permissions.tool.skill.description": "โหลดทักษะตามชื่อ", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "เรียกใช้การสืบค้นเซิร์ฟเวอร์ภาษา", - "settings.permissions.tool.todowrite.title": "เขียนรายการงาน", - "settings.permissions.tool.todowrite.description": "อัปเดตรายการงาน", "settings.permissions.tool.webfetch.title": "ดึงข้อมูลจากเว็บ", "settings.permissions.tool.webfetch.description": "ดึงเนื้อหาจาก URL", "settings.permissions.tool.websearch.title": "ค้นหาเว็บ", @@ -857,11 +999,10 @@ export const dict = { "dialog.server.add.usernamePlaceholder": "ชื่อผู้ใช้", "dialog.server.add.passwordPlaceholder": "รหัสผ่าน", "server.row.noUsername": "ไม่มีชื่อผู้ใช้", - "session.review.noVcs.createGit.title": "สร้าง Git repository", + "session.review.noVcs.createGit.title": "สร้าง Git รีโพซิทอรี", "session.review.noVcs.createGit.description": "ติดตาม ตรวจสอบ และเลิกทำสิ่งเปลี่ยนแปลงในโปรเจกต์นี้", - "session.review.noVcs.createGit.actionLoading": "กำลังสร้าง Git repository...", - "session.review.noVcs.createGit.action": "สร้าง Git repository", - "session.todo.progress": "เสร็จสิ้น {{done}} จาก {{total}} รายการ", + "session.review.noVcs.createGit.actionLoading": "กำลังสร้าง Git รีโพซิทอรี...", + "session.review.noVcs.createGit.action": "สร้าง Git รีโพซิทอรี", "session.question.progress": "{{current}} จาก {{total}} คำถาม", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "File Explorer", diff --git a/packages/app/src/i18n/tr.ts b/packages/app/src/i18n/tr.ts index 9053173599..c3cc62c942 100644 --- a/packages/app/src/i18n/tr.ts +++ b/packages/app/src/i18n/tr.ts @@ -27,6 +27,9 @@ export const dict = { "command.sidebar.toggle": "Kenar çubuğunu aç/kapat", "command.project.open": "Proje aç", + "command.project.previous": "Önceki proje", + "command.project.next": "Sonraki proje", + "command.project.index": "{{index}} numaralı projeye geç", "command.provider.connect": "Sağlayıcı bağla", "command.server.switch": "Sunucu değiştir", "command.settings.open": "Ayarları aç", @@ -49,6 +52,7 @@ export const dict = { "command.session.new": "Yeni oturum", "command.file.open": "Dosya aç", "command.tab.close": "Sekmeyi kapat", + "command.tab.reopenClosed": "Kapatılan sekmeyi yeniden aç", "command.context.addSelection": "Seçimi bağlama ekle", "command.context.addSelection.description": "Mevcut dosyadan seçili satırları ekle", "command.input.focus": "Girişi odakla", @@ -132,7 +136,7 @@ export const dict = { "provider.connect.status.waiting": "Yetkilendirme bekleniyor...", "provider.connect.status.failed": "Yetkilendirme başarısız: {{error}}", "provider.connect.apiKey.description": - "{{provider}} hesabınızı bağlamak ve OpenCode'da {{provider}} modellerini kullanmak için {{provider}} API anahtarınızı girin.", + "{{provider}} hesabınızı bağlamak ve OpenCode'da {{provider}} modellerini kullanmak için API anahtarınızı girin.", "provider.connect.apiKey.label": "{{provider}} API anahtarı", "provider.connect.apiKey.placeholder": "API anahtarı", "provider.connect.apiKey.required": "API anahtarı gerekli", @@ -143,10 +147,10 @@ export const dict = { "provider.connect.opencodeZen.visit.prefix": "", "provider.connect.opencodeZen.visit.link": "opencode.ai/zen", "provider.connect.opencodeZen.visit.suffix": " adresini ziyaret ederek API anahtarınızı alın.", - "provider.connect.oauth.code.visit.prefix": - "Hesabınızı bağlamak ve OpenCode'da {{provider}} modellerini kullanmak için ", + "provider.connect.oauth.code.visit.prefix": "Yetkilendirme kodunuzu almak için ", "provider.connect.oauth.code.visit.link": "bu bağlantıya", - "provider.connect.oauth.code.visit.suffix": " tıklayarak yetkilendirme kodunuzu alın.", + "provider.connect.oauth.code.visit.suffix": + " gidin; ardından hesabınızı bağlayarak OpenCode'da {{provider}} modellerini kullanın.", "provider.connect.oauth.code.label": "{{method}} yetkilendirme kodu", "provider.connect.oauth.code.placeholder": "Yetkilendirme kodu", "provider.connect.oauth.code.required": "Yetkilendirme kodu gerekli", @@ -213,6 +217,11 @@ export const dict = { "model.input.video": "video", "model.input.pdf": "pdf", "model.tooltip.allows": "Kabul eder: {{inputs}}", + "model.tooltip.context.label": "Bağlam", + "model.tooltip.inputs": "Girdiler", + "model.tooltip.model": "Model", + "model.tooltip.provider": "Sağlayıcı", + "model.tooltip.reasoning": "Akıl yürütme", "model.tooltip.reasoning.allowed": "Akıl yürütme destekler", "model.tooltip.reasoning.none": "Akıl yürütme yok", "model.tooltip.context": "Bağlam limiti {{limit}}", @@ -223,6 +232,7 @@ export const dict = { "common.loading": "Yükleniyor", "common.loading.ellipsis": "...", "common.cancel": "İptal", + "common.clear": "Temizle", "common.connect": "Bağlan", "common.disconnect": "Bağlantı Kes", "common.continue": "Gönder", @@ -240,6 +250,8 @@ export const dict = { "prompt.mode.shell": "Kabuk", "prompt.mode.normal": "Komut", "prompt.mode.shell.exit": "çıkmak için esc", + "session.child.promptDisabled": "Alt ajan oturumlarına istem gönderilemez.", + "session.child.backToParent": "Ana oturuma dön.", "prompt.example.1": "Kod tabanındaki bir TODO'yu düzelt", "prompt.example.2": "Bu projenin teknoloji yığını nedir?", @@ -346,6 +358,75 @@ export const dict = { "dialog.server.menu.delete": "Sil", "dialog.server.current": "Mevcut Sunucu", "dialog.server.status.default": "Varsayılan", + "wsl.server.add": "WSL sunucusu ekle", + "wsl.server.addShort": "WSL ekle", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "WSL sunucusu", + "wsl.server.retryStart": "Başlatmayı yeniden dene", + "wsl.server.updating": "Güncelleniyor...", + "wsl.onboarding.step.distro": "Dağıtım seç", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "WSL kontrol ediliyor...", + "wsl.onboarding.restartRequired": "WSL kurulumunu tamamlamak için Windows'un yeniden başlatılması gerekiyor.", + "wsl.onboarding.ready": "WSL hazır.", + "wsl.onboarding.required": "Devam etmek için WSL gerekli.", + "wsl.onboarding.checkingDistros": "Dağıtımlar kontrol ediliyor...", + "wsl.onboarding.installingDistro": "{{distro}} kuruluyor...", + "wsl.onboarding.checkingDistro": "{{distro}} kontrol ediliyor...", + "wsl.onboarding.listingDistros": "Dağıtımlar listeleniyor...", + "wsl.onboarding.distroReady": "{{distro}} hazır.", + "wsl.onboarding.distroNotInstalled": "{{distro}} henüz kurulu değil.", + "wsl.onboarding.openDistroOnce": "Kurulumu tamamlamak için {{distro}} dağıtımını bir kez açın.", + "wsl.onboarding.finishingDistro": "{{distro}} kurulumu tamamlanıyor.", + "wsl.onboarding.pickDistro": "Bir dağıtım seçin veya aşağıdan bir dağıtım kurun.", + "wsl.onboarding.checkingOpencode": "OpenCode kontrol ediliyor...", + "wsl.onboarding.checkingOpencodeIn": "{{distro}} içinde OpenCode kontrol ediliyor...", + "wsl.onboarding.updatingOpencode": "OpenCode güncelleniyor...", + "wsl.onboarding.updatingOpencodeIn": "{{distro}} içinde OpenCode güncelleniyor...", + "wsl.onboarding.updateOpencodeIn": "{{distro}} içindeki OpenCode'u güncelleyin.", + "wsl.onboarding.updateOpencode": "OpenCode'u güncelle", + "wsl.onboarding.opencodeReadyIn": "{{distro}} içinde OpenCode hazır.", + "wsl.onboarding.opencodeReady": "OpenCode hazır.", + "wsl.onboarding.installOpencodeIn": "OpenCode'u {{distro}} içine kurun.", + "wsl.onboarding.installOpencode": "OpenCode'u kur", + "wsl.onboarding.chooseDistroFirst": "Önce bir dağıtım seçin.", + "wsl.onboarding.loadFailed": "WSL durumu yüklenemedi.", + "wsl.onboarding.loading": "Yükleniyor...", + "wsl.onboarding.installedDistros": "Kurulu dağıtımlar", + "wsl.onboarding.checkAgain": "Tekrar kontrol et", + "wsl.onboarding.distroStatus.ready": "Hazır", + "wsl.onboarding.distroStatus.checking": "Kontrol ediliyor...", + "wsl.onboarding.distroStatus.opencodeMissing": "OpenCode kurulu değil", + "wsl.onboarding.distroStatus.missingTools": "bash ve curl eksik", + "wsl.onboarding.distroStatus.unsupported": "Desteklenmiyor · WSL 2 kullanın", + "wsl.onboarding.needAnotherDistro": "Başka bir dağıtım mı gerekiyor?", + "wsl.onboarding.needAnotherDistroHint": "WSL kataloğundan bir Linux dağıtımı kurun", + "wsl.onboarding.wslNotInstalled.title": "WSL kurulu değil", + "wsl.onboarding.wslNotInstalled.description": + "OpenCode'un WSL sunucusu ekleyebilmesi için önce WSL (Linux için Windows Alt Sistemi) kurulmalıdır", + "wsl.onboarding.wslUnavailable.title": "WSL kullanılamıyor", + "wsl.onboarding.wslUnavailable.description": "OpenCode bu makinede WSL'yi doğrulayamadı.", + "wsl.onboarding.installWsl": "WSL'yi kur", + "wsl.onboarding.windowsRestartRequired": + "WSL kurulumunu tamamlamak için Windows'u yeniden başlatın, ardından OpenCode'u tekrar açın.", + "wsl.onboarding.next": "İleri", + "wsl.onboarding.refresh": "Yenile", + "wsl.onboarding.allDistrosAdded": "Kurulu tüm dağıtımlar zaten eklenmiş.", + "wsl.onboarding.noDistros": "Henüz dağıtım algılanmadı.", + "wsl.onboarding.install": "Kur", + "wsl.onboarding.installing": "Kuruluyor...", + "wsl.onboarding.installDistro": "Dağıtım kur", + "wsl.onboarding.searchDistros": "Dağıtım ara", + "wsl.onboarding.wsl2Required": "WSL 2 gerekli.", + "wsl.onboarding.toolsRequired": "Bu dağıtım için bash ve curl gerekli.", + "wsl.onboarding.openTerminal": "Terminali aç", + "wsl.onboarding.path": "Yol: {{path}}", + "wsl.onboarding.notFound": "bulunamadı", + "wsl.onboarding.version": "Sürüm: {{version}}", + "wsl.onboarding.unknown": "bilinmiyor", + "wsl.onboarding.desktopVersion": "masaüstü {{version}}", + "wsl.onboarding.versionMismatch": "Kurulu sürüm masaüstü uygulamasının sürümüyle eşleşmiyor.", + "wsl.onboarding.adding": "Ekleniyor...", "dialog.project.edit.title": "Projeyi düzenle", "dialog.project.edit.name": "Ad", @@ -408,6 +489,7 @@ export const dict = { "language.no": "Norsk", "language.br": "Português (Brasil)", "language.bs": "Bosanski", + "language.uk": "Українська", "language.th": "ไทย", "language.tr": "Türkçe", @@ -456,10 +538,12 @@ export const dict = { "error.page.title": "Bir şeyler yanlış gitti", "error.page.description": "Uygulama yüklenirken bir hata oluştu.", + "error.page.description.localServerStartup": "Yerel sunucu başlatılırken bir hata oluştu.", "error.page.details.label": "Hata Detayları", "error.page.action.restart": "Yeniden Başlat", "error.page.action.report": "Hatayı Bildir", "error.page.action.reported": "Hata Bildirildi", + "error.page.action.exportLogs": "Günlükleri Dışa Aktar", "error.page.action.checking": "Kontrol ediliyor...", "error.page.action.checkUpdates": "Güncellemeleri kontrol et", "error.page.action.updateTo": "{{version}} sürümüne güncelle", @@ -509,11 +593,31 @@ export const dict = { "home.recentProjects": "Son projeler", "home.empty.title": "Son proje yok", "home.empty.description": "Yerel bir proje açarak başlayın", + "home.title": "Ana Sayfa", + "home.projects": "Projeler", + "home.project.add": "Proje ekle", + "home.recentlyClosed": "Yakın zamanda kapatılanlar", + "home.server.collapse": "Sunucu projelerini daralt", + "home.server.expand": "Sunucu projelerini genişlet", + "home.sessions.search.placeholder": "Oturum ara", + "home.sessions.search.placeholder.scoped": "{{scope}} kapsamında oturum ara", + "home.sessions.search.sessions": "Oturumlar", + "home.sessions.search.noResults": "{{query}} için oturum bulunamadı", + "home.sessions.empty": "Henüz burada bir şey yok", + "home.sessions.empty.description": "Başlamak için bir oturum oluşturun", + "home.sessions.group.today": "Bugün", + "home.sessions.group.yesterday": "Dün", + "home.sessions.group.older": "Daha eski", "session.tab.session": "Oturum", "session.tab.review": "İnceleme", "session.tab.context": "Bağlam", + "session.tab.unknown": "Bilinmeyen Oturum", "session.panel.reviewAndFiles": "İnceleme ve dosyalar", + "session.error.notFound": "Bu oturum bulunamıyor", + "session.error.notFound.description": "Bu sekme, artık bu sunucuda bulunmayan bir oturuma yönlendiriyor.", + "session.error.notFound.closeTab": "Sekmeyi Kapat", + "session.error.serverConnection": "Bu sunucuya bağlanılamıyor", "session.review.filesChanged": "{{count}} Dosya Değişti", "session.review.change.one": "Değişiklik", "session.review.change.other": "Değişiklik", @@ -523,6 +627,8 @@ export const dict = { "session.review.noSnapshot": "Yapılandırmada anlık görüntü takibi devre dışı bırakıldı, bu nedenle oturum değişiklikleri kullanılamıyor", "session.review.noChanges": "Değişiklik yok", + "session.review.noUncommittedChanges": "Henüz commit edilmemiş değişiklik yok", + "session.review.noBranchChanges": "Henüz dal değişikliği yok", "session.files.selectToOpen": "Açmak için bir dosya seçin", "session.files.all": "Tüm dosyalar", @@ -536,9 +642,10 @@ export const dict = { "session.messages.jumpToLatest": "En sona atla", "session.context.addToContext": "{{selection}} bağlama ekle", - "session.todo.title": "Görevler", - "session.todo.collapse": "Daralt", - "session.todo.expand": "Genişlet", + "session.question.minimize": "Soruyu küçült", + "session.question.restore": "Soruyu geri yükle", + "session.question.pending.one": "{{count}} bekleyen soru", + "session.question.pending.other": "{{count}} bekleyen soru", "session.followupDock.summary.one": "{{count}} sıradaki mesaj", "session.followupDock.summary.other": "{{count}} sıradaki mesaj", "session.followupDock.sendNow": "Şimdi gönder", @@ -552,9 +659,16 @@ export const dict = { "session.revertDock.restore": "Mesajı geri yükle", "session.new.title": "İstediğini yap", + "session.new.project.new": "Yeni proje", + "session.new.project.search": "Proje ara", + "session.new.project.add": "Proje ekle", "session.new.worktree.main": "Ana dal", "session.new.worktree.mainWithBranch": "Ana dal ({{branch}})", "session.new.worktree.create": "Yeni çalışma ağacı oluştur", + "session.new.workspace.runIn": "Oturumu şurada çalıştır", + "session.new.workspace.triggerLocal": "Yerel", + "session.new.workspace.local": "Yerel depo", + "session.new.workspace.existing": "Çalışma alanı…", "session.new.lastModified": "Son değişiklik", "session.header.search.placeholder": "{{project}} ara", @@ -624,6 +738,8 @@ export const dict = { "sidebar.project.recentSessions": "Son oturumlar", "sidebar.project.viewAllSessions": "Tüm oturumları görüntüle", "sidebar.project.clearNotifications": "Bildirimleri temizle", + "sidebar.empty.title": "Açık proje yok", + "sidebar.empty.description": "Başlamak için bir proje açın", "app.name.desktop": "OpenCode Masaüstü", @@ -636,6 +752,7 @@ export const dict = { "settings.desktop.wsl.description": "OpenCode sunucusunu Windows'ta WSL içinde çalıştırın.", "settings.general.section.appearance": "Görünüm", + "settings.general.section.advanced": "Gelişmiş", "settings.general.section.notifications": "Sistem bildirimleri", "settings.general.section.updates": "Güncellemeler", "settings.general.section.sounds": "Ses efektleri", @@ -644,6 +761,11 @@ export const dict = { "settings.general.row.language.title": "Dil", "settings.general.row.language.description": "OpenCode'un görünüm dilini değiştirin", + "settings.general.row.shell.title": "Terminal Kabuğu", + "settings.general.row.shell.description": + "Terminalinizde kullanılacak kabuğu seçin. Uyumlu kabuklar, ajan araç çağrılarında da kullanılır.", + "settings.general.row.shell.autoDefault": "Otomatik (Varsayılan)", + "settings.general.row.shell.terminalOnly": "yalnızca terminal", "settings.general.row.appearance.title": "Görünüm", "settings.general.row.appearance.description": "OpenCode'un cihazınızdaki görünümünü özelleştirin", "settings.general.row.colorScheme.title": "Renk şeması", @@ -653,8 +775,8 @@ export const dict = { "settings.general.row.theme.description": "OpenCode'un temasını özelleştirin.", "settings.general.row.font.title": "Kod Yazı Tipi", "settings.general.row.font.description": "Kod bloklarında kullanılan yazı tipini özelleştirin", - "settings.general.row.terminalFont.title": "Terminal Font", - "settings.general.row.terminalFont.description": "Customise the font used in the terminal", + "settings.general.row.terminalFont.title": "Terminal yazı tipi", + "settings.general.row.terminalFont.description": "Terminalde kullanılan yazı tipini özelleştirin", "settings.general.row.uiFont.title": "Arayüz Yazı Tipi", "settings.general.row.uiFont.description": "Arayüz genelinde kullanılan yazı tipini özelleştirin", "settings.general.row.followup.title": "Takip davranışı", @@ -662,6 +784,21 @@ export const dict = { "Takip komutlarının hemen yönlendirilmesini mi yoksa sırada beklemesini mi istediğinizi seçin", "settings.general.row.followup.option.queue": "Sıra", "settings.general.row.followup.option.steer": "Yönlendir", + "settings.general.row.showFileTree.title": "Dosya ağacı", + "settings.general.row.showFileTree.description": "Oturumlarda dosya ağacı panelini göster", + "settings.general.row.showNavigation.title": "Gezinme denetimleri", + "settings.general.row.showNavigation.description": "Masaüstü başlık çubuğunda geri ve ileri düğmelerini göster", + "settings.general.row.showSearch.title": "Komut paleti", + "settings.general.row.showSearch.description": "Başlık çubuğunda arama ve komut paleti düğmesini göster", + "settings.general.row.showTerminal.title": "Terminal", + "settings.general.row.showTerminal.description": "Masaüstü başlık çubuğunda terminal düğmesini göster", + "settings.general.row.showStatus.title": "Sunucu durumu", + "settings.general.row.showStatus.description": "Başlık çubuğunda sunucu durumu düğmesini göster", + "settings.general.row.mobileTitlebarBottom.title": "Alt gezinme", + "settings.general.row.mobileTitlebarBottom.description": + "Mobil cihazlarda başlık çubuğunu ve oturum sekmelerini ekranın altına yerleştir", + "settings.general.row.showCustomAgents.title": "Özel ajanlar", + "settings.general.row.showCustomAgents.description": "Yazma alanında ajan seçiciyi göster", "settings.general.row.reasoningSummaries.title": "Akıl yürütme özetlerini göster", "settings.general.row.reasoningSummaries.description": "Zaman çizelgesinde model akıl yürütme özetlerini görüntüle", "settings.general.row.shellToolPartsExpanded.title": "Kabuk araç bileşenlerini genişlet", @@ -670,6 +807,12 @@ export const dict = { "settings.general.row.editToolPartsExpanded.title": "Düzenleme araç bileşenlerini genişlet", "settings.general.row.editToolPartsExpanded.description": "Zaman çizelgesinde düzenleme, yazma ve yama araç bileşenlerini varsayılan olarak genişletilmiş göster", + "settings.general.row.newLayoutDesigns.title": "Yeni düzen ve tasarımlar", + "settings.general.row.newLayoutDesigns.description": + "Yeniden tasarlanan düzeni, ana sayfayı, yazma alanını ve oturum arayüzünü etkinleştir", + "settings.general.row.pinchZoom.title": "Sıkıştırarak yakınlaştır", + "settings.general.row.pinchZoom.description": + "İzleme dörtgeninde sıkıştırma ve Ctrl-kaydırma hareketleriyle yakınlaştırmaya izin ver", "settings.general.row.wayland.title": "Yerel Wayland kullan", "settings.general.row.wayland.description": @@ -686,6 +829,8 @@ export const dict = { "settings.updates.row.check.description": "Elle güncelleme kontrolü yap ve varsa yükle", "settings.updates.action.checkNow": "Şimdi kontrol et", "settings.updates.action.checking": "Kontrol ediliyor...", + "settings.updates.action.downloading": "İndiriliyor...", + "settings.updates.action.installing": "Kuruluyor...", "settings.updates.toast.latest.title": "Güncelsiniz", "settings.updates.toast.latest.description": "OpenCode'un en son sürümünü kullanıyorsunuz.", @@ -814,8 +959,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Ada göre bir beceri yükle", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Dil sunucusu sorguları çalıştır", - "settings.permissions.tool.todowrite.title": "Görev Yaz", - "settings.permissions.tool.todowrite.description": "Görev listesini güncelle", "settings.permissions.tool.webfetch.title": "Web Getir", "settings.permissions.tool.webfetch.description": "Bir URL'den içerik getir", "settings.permissions.tool.websearch.title": "Web Ara", @@ -880,7 +1023,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Bu projedeki değişiklikleri takip et, incele ve geri al", "session.review.noVcs.createGit.actionLoading": "Git deposu oluşturuluyor...", "session.review.noVcs.createGit.action": "Git deposu oluştur", - "session.todo.progress": "{{total}} görevin {{done}} tanesi tamamlandı", "session.question.progress": "{{total}} sorunun {{current}} tanesi", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Dosya Gezgini", diff --git a/packages/app/src/i18n/uk.ts b/packages/app/src/i18n/uk.ts index d875766e88..f4bc44eb23 100644 --- a/packages/app/src/i18n/uk.ts +++ b/packages/app/src/i18n/uk.ts @@ -48,6 +48,7 @@ export const dict = { "command.session.new": "Нова сесія", "command.file.open": "Відкрити файл", "command.tab.close": "Закрити вкладку", + "command.tab.reopenClosed": "Повторно відкрити закриту вкладку", "command.context.addSelection": "Додати виділення до контексту", "command.context.addSelection.description": "Додати вибрані рядки з поточного файлу", "command.input.focus": "Фокус на полі введення", @@ -212,6 +213,11 @@ export const dict = { "model.input.video": "відео", "model.input.pdf": "pdf", "model.tooltip.allows": "Дозволяє: {{inputs}}", + "model.tooltip.context.label": "Контекст", + "model.tooltip.inputs": "Вхідні дані", + "model.tooltip.model": "Модель", + "model.tooltip.provider": "Провайдер", + "model.tooltip.reasoning": "Мислення", "model.tooltip.reasoning.allowed": "Підтримує мислення", "model.tooltip.reasoning.none": "Без мислення", "model.tooltip.context": "Ліміт контексту {{limit}}", @@ -222,6 +228,7 @@ export const dict = { "common.loading": "Завантаження", "common.loading.ellipsis": "...", "common.cancel": "Скасувати", + "common.clear": "Очистити", "common.open": "Відкрити", "common.connect": "Підключити", "common.disconnect": "Відключити", @@ -354,6 +361,75 @@ export const dict = { "dialog.server.menu.delete": "Видалити", "dialog.server.current": "Поточний сервер", "dialog.server.status.default": "За замовчуванням", + "wsl.server.add": "Додати сервер WSL", + "wsl.server.addShort": "Додати WSL", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "Сервер WSL", + "wsl.server.retryStart": "Повторити запуск", + "wsl.server.updating": "Оновлення...", + "wsl.onboarding.step.distro": "Вибрати дистрибутив", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "Перевірка WSL...", + "wsl.onboarding.restartRequired": "Щоб завершити встановлення WSL, потрібно перезапустити Windows.", + "wsl.onboarding.ready": "WSL готова до роботи.", + "wsl.onboarding.required": "Для продовження потрібна WSL.", + "wsl.onboarding.checkingDistros": "Перевірка дистрибутивів...", + "wsl.onboarding.installingDistro": "Встановлення {{distro}}...", + "wsl.onboarding.checkingDistro": "Перевірка {{distro}}...", + "wsl.onboarding.listingDistros": "Отримання списку дистрибутивів...", + "wsl.onboarding.distroReady": "{{distro}} готовий до роботи.", + "wsl.onboarding.distroNotInstalled": "{{distro}} ще не встановлено.", + "wsl.onboarding.openDistroOnce": "Відкрийте {{distro}} один раз, щоб завершити налаштування.", + "wsl.onboarding.finishingDistro": "Завершення налаштування {{distro}}.", + "wsl.onboarding.pickDistro": "Виберіть дистрибутив або встановіть один із наведених нижче.", + "wsl.onboarding.checkingOpencode": "Перевірка OpenCode...", + "wsl.onboarding.checkingOpencodeIn": "Перевірка OpenCode у {{distro}}...", + "wsl.onboarding.updatingOpencode": "Оновлення OpenCode...", + "wsl.onboarding.updatingOpencodeIn": "Оновлення OpenCode у {{distro}}...", + "wsl.onboarding.updateOpencodeIn": "Оновіть OpenCode у {{distro}}.", + "wsl.onboarding.updateOpencode": "Оновити OpenCode", + "wsl.onboarding.opencodeReadyIn": "OpenCode готовий до роботи у {{distro}}.", + "wsl.onboarding.opencodeReady": "OpenCode готовий до роботи.", + "wsl.onboarding.installOpencodeIn": "Встановіть OpenCode у {{distro}}.", + "wsl.onboarding.installOpencode": "Встановити OpenCode", + "wsl.onboarding.chooseDistroFirst": "Спочатку виберіть дистрибутив.", + "wsl.onboarding.loadFailed": "Не вдалося завантажити стан WSL.", + "wsl.onboarding.loading": "Завантаження...", + "wsl.onboarding.installedDistros": "Встановлені дистрибутиви", + "wsl.onboarding.checkAgain": "Перевірити ще раз", + "wsl.onboarding.distroStatus.ready": "Готовий", + "wsl.onboarding.distroStatus.checking": "Перевірка...", + "wsl.onboarding.distroStatus.opencodeMissing": "OpenCode не встановлено", + "wsl.onboarding.distroStatus.missingTools": "Немає bash і curl", + "wsl.onboarding.distroStatus.unsupported": "Не підтримується · Використовуйте WSL 2", + "wsl.onboarding.needAnotherDistro": "Потрібен інший дистрибутив?", + "wsl.onboarding.needAnotherDistroHint": "Встановіть дистрибутив Linux із каталогу WSL", + "wsl.onboarding.wslNotInstalled.title": "WSL не встановлено", + "wsl.onboarding.wslNotInstalled.description": + "Для додавання сервера WSL в OpenCode потрібна WSL (Підсистема Windows для Linux)", + "wsl.onboarding.wslUnavailable.title": "WSL недоступна", + "wsl.onboarding.wslUnavailable.description": "OpenCode не вдалося перевірити WSL на цьому комп'ютері.", + "wsl.onboarding.installWsl": "Встановити WSL", + "wsl.onboarding.windowsRestartRequired": + "Перезапустіть Windows, щоб завершити встановлення WSL, а потім знову відкрийте OpenCode.", + "wsl.onboarding.next": "Далі", + "wsl.onboarding.refresh": "Оновити", + "wsl.onboarding.allDistrosAdded": "Усі встановлені дистрибутиви вже додано.", + "wsl.onboarding.noDistros": "Дистрибутивів поки не виявлено.", + "wsl.onboarding.install": "Встановити", + "wsl.onboarding.installing": "Встановлення...", + "wsl.onboarding.installDistro": "Встановити дистрибутив", + "wsl.onboarding.searchDistros": "Пошук дистрибутивів", + "wsl.onboarding.wsl2Required": "Для роботи потрібна WSL 2.", + "wsl.onboarding.toolsRequired": "Для цього дистрибутива потрібні bash і curl.", + "wsl.onboarding.openTerminal": "Відкрити термінал", + "wsl.onboarding.path": "Шлях: {{path}}", + "wsl.onboarding.notFound": "не знайдено", + "wsl.onboarding.version": "Версія: {{version}}", + "wsl.onboarding.unknown": "невідомо", + "wsl.onboarding.desktopVersion": "десктопний застосунок {{version}}", + "wsl.onboarding.versionMismatch": "Встановлена версія не відповідає версії десктопного застосунку.", + "wsl.onboarding.adding": "Додавання...", "server.row.noUsername": "без імені користувача", "dialog.project.edit.title": "Редагувати проєкт", @@ -473,10 +549,12 @@ export const dict = { "error.page.title": "Щось пішло не так", "error.page.description": "Під час завантаження програми сталася помилка.", + "error.page.description.localServerStartup": "Під час запуску локального сервера сталася помилка.", "error.page.details.label": "Деталі помилки", "error.page.action.restart": "Перезапустити", "error.page.action.report": "Повідомити про помилку", "error.page.action.reported": "Помилку повідомлено", + "error.page.action.exportLogs": "Експортувати журнали", "error.page.action.checking": "Перевірка...", "error.page.action.checkUpdates": "Перевірити оновлення", "error.page.action.updateTo": "Оновити до {{version}}", @@ -533,11 +611,31 @@ export const dict = { "home.recentProjects": "Нещодавні проєкти", "home.empty.title": "Немає нещодавніх проєктів", "home.empty.description": "Почніть, відкривши локальний проєкт", + "home.title": "Головна", + "home.projects": "Проєкти", + "home.project.add": "Додати проєкт", + "home.recentlyClosed": "Нещодавно закриті", + "home.server.collapse": "Згорнути проєкти сервера", + "home.server.expand": "Розгорнути проєкти сервера", + "home.sessions.search.placeholder": "Пошук сесій", + "home.sessions.search.placeholder.scoped": "Пошук сесій у {{scope}}", + "home.sessions.search.sessions": "Сесії", + "home.sessions.search.noResults": "Сесій за запитом {{query}} не знайдено", + "home.sessions.empty": "Тут поки нічого немає", + "home.sessions.empty.description": "Створіть сесію, щоб почати", + "home.sessions.group.today": "Сьогодні", + "home.sessions.group.yesterday": "Учора", + "home.sessions.group.older": "Раніше", "session.tab.session": "Сесія", "session.tab.review": "Огляд", "session.tab.context": "Контекст", + "session.tab.unknown": "Невідома сесія", "session.panel.reviewAndFiles": "Огляд і файли", + "session.error.notFound": "Цю сесію не знайдено", + "session.error.notFound.description": "Ця вкладка посилається на сесію, якої більше немає на цьому сервері.", + "session.error.notFound.closeTab": "Закрити вкладку", + "session.error.serverConnection": "Не вдається підключитися до цього сервера", "session.review.filesChanged": "Змінено файлів: {{count}}", "session.review.change.one": "Зміна", "session.review.change.other": "Зміни", @@ -565,11 +663,11 @@ export const dict = { "session.messages.jumpToLatest": "Перейти до останніх", "session.context.addToContext": "Додати {{selection}} до контексту", - "session.todo.title": "Завдання", - "session.todo.collapse": "Згорнути", - "session.todo.expand": "Розгорнути", - "session.todo.progress": "Виконано {{done}} з {{total}} завдань", "session.question.progress": "{{current}} з {{total}} запитань", + "session.question.minimize": "Згорнути запитання", + "session.question.restore": "Відновити запитання", + "session.question.pending.one": "{{count}} запитання очікує відповіді", + "session.question.pending.other": "Запитання, що очікують відповіді: {{count}}", "session.followupDock.summary.one": "{{count}} повідомлення в черзі", "session.followupDock.summary.other": "{{count}} повідомлень у черзі", "session.followupDock.sendNow": "Надіслати зараз", @@ -583,9 +681,16 @@ export const dict = { "session.revertDock.restore": "Відновити повідомлення", "session.new.title": "Створити що завгодно", + "session.new.project.new": "Новий проєкт", + "session.new.project.search": "Пошук проєктів", + "session.new.project.add": "Додати проєкт", "session.new.worktree.main": "Основна гілка", "session.new.worktree.mainWithBranch": "Основна гілка ({{branch}})", "session.new.worktree.create": "Створити нове робоче дерево", + "session.new.workspace.runIn": "Запустити сесію в", + "session.new.workspace.triggerLocal": "Локально", + "session.new.workspace.local": "Локальний репозиторій", + "session.new.workspace.existing": "Робоча область…", "session.new.lastModified": "Востаннє змінено", "session.header.search.placeholder": "Пошук {{project}}", @@ -773,6 +878,11 @@ export const dict = { "settings.general.row.showTerminal.description": "Показувати кнопку термінала в заголовку робочого столу", "settings.general.row.showStatus.title": "Статус сервера", "settings.general.row.showStatus.description": "Показувати кнопку статусу сервера в заголовку", + "settings.general.row.mobileTitlebarBottom.title": "Нижня навігація", + "settings.general.row.mobileTitlebarBottom.description": + "Розмістити заголовок і вкладки сесії внизу екрана на мобільних пристроях", + "settings.general.row.showCustomAgents.title": "Користувацькі агенти", + "settings.general.row.showCustomAgents.description": "Показувати вибір агента в редакторі запиту", "settings.general.row.reasoningSummaries.title": "Показувати підсумки мислення", "settings.general.row.reasoningSummaries.description": "Відображати підсумки мислення моделі на часовій шкалі", "settings.general.row.shellToolPartsExpanded.title": "Розгортати частини інструменту оболонки", @@ -781,6 +891,12 @@ export const dict = { "settings.general.row.editToolPartsExpanded.title": "Розгортати частини інструменту редагування", "settings.general.row.editToolPartsExpanded.description": "Показувати частини інструментів редагування, запису та патчів розгорнутими за замовчуванням на часовій шкалі", + "settings.general.row.newLayoutDesigns.title": "Новий макет і дизайн", + "settings.general.row.newLayoutDesigns.description": + "Увімкнути оновлений макет та інтерфейси головної сторінки, редактора запитів і сесії", + "settings.general.row.pinchZoom.title": "Масштабування щипком", + "settings.general.row.pinchZoom.description": + "Дозволити масштабування жестом щипка на трекпаді та прокручуванням із Ctrl", "settings.general.row.wayland.title": "Використовувати нативний Wayland", "settings.general.row.wayland.description": "Вимкнути резервний X11 на Wayland. Потребує перезапуску.", @@ -796,6 +912,8 @@ export const dict = { "settings.updates.row.check.description": "Вручну перевірити наявність оновлень і встановити, якщо доступні", "settings.updates.action.checkNow": "Перевірити зараз", "settings.updates.action.checking": "Перевірка...", + "settings.updates.action.downloading": "Завантаження...", + "settings.updates.action.installing": "Встановлення...", "settings.updates.toast.latest.title": "У вас актуальна версія", "settings.updates.toast.latest.description": "Ви використовуєте останню версію OpenCode.", "sound.option.none": "Немає", @@ -925,8 +1043,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Завантаження навички за назвою", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Виконання запитів мовного сервера", - "settings.permissions.tool.todowrite.title": "Todo Write", - "settings.permissions.tool.todowrite.description": "Оновлення списку завдань", "settings.permissions.tool.webfetch.title": "Web Fetch", "settings.permissions.tool.webfetch.description": "Отримання вмісту з URL", "settings.permissions.tool.websearch.title": "Web Search", diff --git a/packages/app/src/i18n/zh.ts b/packages/app/src/i18n/zh.ts index 15d873ee04..bd12a9dba2 100644 --- a/packages/app/src/i18n/zh.ts +++ b/packages/app/src/i18n/zh.ts @@ -28,6 +28,9 @@ export const dict = { "command.sidebar.toggle": "切换侧边栏", "command.project.open": "打开项目", + "command.project.previous": "上一个项目", + "command.project.next": "下一个项目", + "command.project.index": "切换到项目 {{index}}", "command.provider.connect": "连接提供商", @@ -56,6 +59,7 @@ export const dict = { "command.file.open": "打开文件", "command.tab.close": "关闭标签页", + "command.tab.reopenClosed": "重新打开已关闭的标签页", "command.context.addSelection": "将所选内容添加到上下文", "command.context.addSelection.description": "添加当前文件中选中的行", @@ -230,6 +234,11 @@ export const dict = { "model.input.video": "视频", "model.input.pdf": "pdf", "model.tooltip.allows": "支持:{{inputs}}", + "model.tooltip.context.label": "上下文", + "model.tooltip.inputs": "输入", + "model.tooltip.model": "模型", + "model.tooltip.provider": "提供商", + "model.tooltip.reasoning": "推理", "model.tooltip.reasoning.allowed": "支持推理", "model.tooltip.reasoning.none": "不支持推理", "model.tooltip.context": "上下文上限 {{limit}}", @@ -240,6 +249,7 @@ export const dict = { "common.loading": "加载中", "common.loading.ellipsis": "...", "common.cancel": "取消", + "common.clear": "清除", "common.connect": "连接", "common.disconnect": "断开连接", "common.continue": "提交", @@ -257,6 +267,8 @@ export const dict = { "prompt.mode.shell": "Shell", "prompt.mode.normal": "Prompt", "prompt.mode.shell.exit": "按 esc 退出", + "session.child.promptDisabled": "无法向子智能体会话发送提示词。", + "session.child.backToParent": "返回主会话。", "prompt.example.1": "修复代码库中的一个 TODO", "prompt.example.2": "这个项目的技术栈是什么?", "prompt.example.3": "修复失败的测试", @@ -359,6 +371,73 @@ export const dict = { "dialog.server.menu.delete": "删除", "dialog.server.current": "当前服务器", "dialog.server.status.default": "默认", + "wsl.server.add": "添加 WSL 服务器", + "wsl.server.addShort": "添加 WSL", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "WSL 服务器", + "wsl.server.retryStart": "重试启动", + "wsl.server.updating": "正在更新...", + "wsl.onboarding.step.distro": "选择发行版", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "正在检查 WSL...", + "wsl.onboarding.restartRequired": "Windows 需要重启才能完成 WSL 安装。", + "wsl.onboarding.ready": "WSL 已就绪。", + "wsl.onboarding.required": "需要 WSL 才能继续。", + "wsl.onboarding.checkingDistros": "正在检查发行版...", + "wsl.onboarding.installingDistro": "正在安装 {{distro}}...", + "wsl.onboarding.checkingDistro": "正在检查 {{distro}}...", + "wsl.onboarding.listingDistros": "正在列出发行版...", + "wsl.onboarding.distroReady": "{{distro}} 已就绪。", + "wsl.onboarding.distroNotInstalled": "{{distro}} 尚未安装。", + "wsl.onboarding.openDistroOnce": "打开一次 {{distro}} 以完成设置。", + "wsl.onboarding.finishingDistro": "正在完成 {{distro}} 的设置。", + "wsl.onboarding.pickDistro": "选择一个发行版,或在下方安装。", + "wsl.onboarding.checkingOpencode": "正在检查 OpenCode...", + "wsl.onboarding.checkingOpencodeIn": "正在检查 {{distro}} 中的 OpenCode...", + "wsl.onboarding.updatingOpencode": "正在更新 OpenCode...", + "wsl.onboarding.updatingOpencodeIn": "正在更新 {{distro}} 中的 OpenCode...", + "wsl.onboarding.updateOpencodeIn": "更新 {{distro}} 中的 OpenCode。", + "wsl.onboarding.updateOpencode": "更新 OpenCode", + "wsl.onboarding.opencodeReadyIn": "{{distro}} 中的 OpenCode 已就绪。", + "wsl.onboarding.opencodeReady": "OpenCode 已就绪。", + "wsl.onboarding.installOpencodeIn": "在 {{distro}} 中安装 OpenCode。", + "wsl.onboarding.installOpencode": "安装 OpenCode", + "wsl.onboarding.chooseDistroFirst": "请先选择发行版。", + "wsl.onboarding.loadFailed": "加载 WSL 状态失败。", + "wsl.onboarding.loading": "加载中...", + "wsl.onboarding.installedDistros": "已安装的发行版", + "wsl.onboarding.checkAgain": "重新检查", + "wsl.onboarding.distroStatus.ready": "已就绪", + "wsl.onboarding.distroStatus.checking": "检查中...", + "wsl.onboarding.distroStatus.opencodeMissing": "未安装 OpenCode", + "wsl.onboarding.distroStatus.missingTools": "缺少 bash、curl", + "wsl.onboarding.distroStatus.unsupported": "不支持 · 请使用 WSL 2", + "wsl.onboarding.needAnotherDistro": "需要其他发行版?", + "wsl.onboarding.needAnotherDistroHint": "从 WSL 目录安装 Linux 发行版", + "wsl.onboarding.wslNotInstalled.title": "未安装 WSL", + "wsl.onboarding.wslNotInstalled.description": "OpenCode 需要 WSL(Windows Subsystem for Linux)才能添加 WSL 服务器", + "wsl.onboarding.wslUnavailable.title": "WSL 不可用", + "wsl.onboarding.wslUnavailable.description": "OpenCode 无法验证此设备上的 WSL。", + "wsl.onboarding.installWsl": "安装 WSL", + "wsl.onboarding.windowsRestartRequired": "重启 Windows 以完成 WSL 安装,然后重新打开 OpenCode。", + "wsl.onboarding.next": "下一步", + "wsl.onboarding.refresh": "刷新", + "wsl.onboarding.allDistrosAdded": "所有已安装的发行版均已添加。", + "wsl.onboarding.noDistros": "尚未检测到发行版。", + "wsl.onboarding.install": "安装", + "wsl.onboarding.installing": "正在安装...", + "wsl.onboarding.installDistro": "安装发行版", + "wsl.onboarding.searchDistros": "搜索发行版", + "wsl.onboarding.wsl2Required": "需要 WSL 2。", + "wsl.onboarding.toolsRequired": "此发行版需要 bash 和 curl。", + "wsl.onboarding.openTerminal": "打开终端", + "wsl.onboarding.path": "路径:{{path}}", + "wsl.onboarding.notFound": "未找到", + "wsl.onboarding.version": "版本:{{version}}", + "wsl.onboarding.unknown": "未知", + "wsl.onboarding.desktopVersion": "桌面版 {{version}}", + "wsl.onboarding.versionMismatch": "已安装版本与桌面应用版本不一致。", + "wsl.onboarding.adding": "正在添加...", "dialog.project.edit.title": "编辑项目", "dialog.project.edit.name": "名称", @@ -418,6 +497,7 @@ export const dict = { "language.no": "Norsk", "language.br": "Português (Brasil)", "language.bs": "Bosanski", + "language.uk": "Українська", "language.th": "ไทย", "language.tr": "Türkçe", @@ -456,10 +536,12 @@ export const dict = { "error.page.title": "出了点问题", "error.page.description": "加载应用程序时发生错误。", + "error.page.description.localServerStartup": "启动本地服务器时发生错误。", "error.page.details.label": "错误详情", "error.page.action.restart": "重启", "error.page.action.report": "上报错误", "error.page.action.reported": "错误已上报", + "error.page.action.exportLogs": "导出日志", "error.page.action.checking": "检查中...", "error.page.action.checkUpdates": "检查更新", "error.page.action.updateTo": "更新到 {{version}}", @@ -506,6 +588,9 @@ export const dict = { "home.title": "主页", "home.projects": "项目", "home.project.add": "添加项目", + "home.recentlyClosed": "最近关闭", + "home.server.collapse": "折叠服务器项目", + "home.server.expand": "展开服务器项目", "home.sessions.search.placeholder": "搜索会话", "home.sessions.search.placeholder.scoped": "在 {{scope}} 中搜索会话", "home.sessions.search.sessions": "会话", @@ -519,7 +604,12 @@ export const dict = { "session.tab.session": "会话", "session.tab.review": "审查", "session.tab.context": "上下文", + "session.tab.unknown": "未知会话", "session.panel.reviewAndFiles": "审查和文件", + "session.error.notFound": "找不到此会话", + "session.error.notFound.description": "此标签页指向的会话已不存在于此服务器上。", + "session.error.notFound.closeTab": "关闭标签页", + "session.error.serverConnection": "无法连接到此服务器", "session.review.filesChanged": "{{count}} 个文件变更", "session.review.change.one": "更改", "session.review.change.other": "更改", @@ -528,6 +618,8 @@ export const dict = { "session.review.noVcs": "未检测到 Git 版本控制系统,无法显示更改", "session.review.noSnapshot": "配置中已禁用快照跟踪,因此会话更改不可用", "session.review.noChanges": "无更改", + "session.review.noUncommittedChanges": "尚无未提交的更改", + "session.review.noBranchChanges": "尚无分支更改", "session.files.selectToOpen": "选择要打开的文件", "session.files.all": "所有文件", "session.files.empty": "无文件", @@ -538,9 +630,10 @@ export const dict = { "session.messages.loading": "正在加载消息...", "session.messages.jumpToLatest": "跳转到最新", "session.context.addToContext": "将 {{selection}} 添加到上下文", - "session.todo.title": "待办事项", - "session.todo.collapse": "折叠", - "session.todo.expand": "展开", + "session.question.minimize": "最小化问题", + "session.question.restore": "恢复问题", + "session.question.pending.one": "{{count}} 个待处理问题", + "session.question.pending.other": "{{count}} 个待处理问题", "session.followupDock.summary.one": "{{count}} 条排队消息", "session.followupDock.summary.other": "{{count}} 条排队消息", "session.followupDock.sendNow": "立即发送", @@ -553,9 +646,16 @@ export const dict = { "session.revertDock.expand": "展开已回滚消息", "session.revertDock.restore": "恢复消息", "session.new.title": "构建任何东西", + "session.new.project.new": "新建项目", + "session.new.project.search": "搜索项目", + "session.new.project.add": "添加项目", "session.new.worktree.main": "主分支", "session.new.worktree.mainWithBranch": "主分支({{branch}})", "session.new.worktree.create": "创建新的 worktree", + "session.new.workspace.runIn": "运行会话的位置", + "session.new.workspace.triggerLocal": "本地", + "session.new.workspace.local": "本地仓库", + "session.new.workspace.existing": "工作区…", "session.new.lastModified": "最后修改", "session.header.search.placeholder": "搜索 {{project}}", "session.header.searchFiles": "搜索文件", @@ -623,6 +723,8 @@ export const dict = { "sidebar.project.recentSessions": "最近会话", "sidebar.project.viewAllSessions": "查看全部会话", "sidebar.project.clearNotifications": "清除通知", + "sidebar.empty.title": "没有打开的项目", + "sidebar.empty.description": "打开一个项目以开始使用", "app.name.desktop": "OpenCode Desktop", @@ -637,6 +739,7 @@ export const dict = { "settings.desktop.wsl.description": "在 Windows 的 WSL 环境中运行 OpenCode 服务器。", "settings.general.section.appearance": "外观", + "settings.general.section.advanced": "高级", "settings.general.section.notifications": "系统通知", "settings.general.section.updates": "更新", "settings.general.section.sounds": "音效", @@ -644,6 +747,10 @@ export const dict = { "settings.general.section.display": "显示", "settings.general.row.language.title": "语言", "settings.general.row.language.description": "更改 OpenCode 的显示语言", + "settings.general.row.shell.title": "终端 Shell", + "settings.general.row.shell.description": "选择终端使用的 shell。兼容的 shell 也会用于智能体工具调用。", + "settings.general.row.shell.autoDefault": "自动(默认)", + "settings.general.row.shell.terminalOnly": "仅终端", "settings.general.row.appearance.title": "外观", "settings.general.row.appearance.description": "自定义 OpenCode 在你的设备上的外观", "settings.general.row.colorScheme.title": "配色方案", @@ -652,20 +759,38 @@ export const dict = { "settings.general.row.theme.description": "自定义 OpenCode 的主题。", "settings.general.row.font.title": "代码字体", "settings.general.row.font.description": "自定义代码块使用的字体", - "settings.general.row.terminalFont.title": "Terminal Font", - "settings.general.row.terminalFont.description": "Customise the font used in the terminal", + "settings.general.row.terminalFont.title": "终端字体", + "settings.general.row.terminalFont.description": "自定义终端使用的字体", "settings.general.row.uiFont.title": "界面字体", "settings.general.row.uiFont.description": "自定义整个界面使用的字体", "settings.general.row.followup.title": "跟进消息行为", "settings.general.row.followup.description": "选择跟进提示是立即引导还是在队列中等待", "settings.general.row.followup.option.queue": "排队", "settings.general.row.followup.option.steer": "引导", + "settings.general.row.showFileTree.title": "文件树", + "settings.general.row.showFileTree.description": "在会话中显示文件树面板", + "settings.general.row.showNavigation.title": "导航控件", + "settings.general.row.showNavigation.description": "在桌面版标题栏中显示前进和后退按钮", + "settings.general.row.showSearch.title": "命令面板", + "settings.general.row.showSearch.description": "在标题栏中显示搜索和命令面板按钮", + "settings.general.row.showTerminal.title": "终端", + "settings.general.row.showTerminal.description": "在桌面版标题栏中显示终端按钮", + "settings.general.row.showStatus.title": "服务器状态", + "settings.general.row.showStatus.description": "在标题栏中显示服务器状态按钮", + "settings.general.row.mobileTitlebarBottom.title": "底部导航", + "settings.general.row.mobileTitlebarBottom.description": "在移动设备上将标题栏和会话标签页置于屏幕底部", + "settings.general.row.showCustomAgents.title": "自定义智能体", + "settings.general.row.showCustomAgents.description": "在输入框中显示智能体选择器", "settings.general.row.reasoningSummaries.title": "显示推理摘要", "settings.general.row.reasoningSummaries.description": "在时间线中显示模型推理摘要", "settings.general.row.shellToolPartsExpanded.title": "展开 shell 工具部分", "settings.general.row.shellToolPartsExpanded.description": "默认在时间线中展开 shell 工具部分", "settings.general.row.editToolPartsExpanded.title": "展开编辑工具部分", "settings.general.row.editToolPartsExpanded.description": "默认在时间线中展开 edit、write 和 patch 工具部分", + "settings.general.row.newLayoutDesigns.title": "新版布局和设计", + "settings.general.row.newLayoutDesigns.description": "启用重新设计的布局、主页、输入框和会话界面", + "settings.general.row.pinchZoom.title": "双指缩放", + "settings.general.row.pinchZoom.description": "允许使用触控板双指捏合和 Ctrl-scroll 手势缩放", "settings.general.row.wayland.title": "使用原生 Wayland", "settings.general.row.wayland.description": "在 Wayland 上禁用 X11 回退。需要重启。", "settings.general.row.wayland.tooltip": "在混合刷新率显示器的 Linux 系统上,原生 Wayland 可能更稳定。", @@ -678,6 +803,8 @@ export const dict = { "settings.updates.row.check.description": "手动检查更新并在有更新时安装", "settings.updates.action.checkNow": "立即检查", "settings.updates.action.checking": "正在检查...", + "settings.updates.action.downloading": "正在下载...", + "settings.updates.action.installing": "正在安装...", "settings.updates.toast.latest.title": "已是最新版本", "settings.updates.toast.latest.description": "你正在使用最新版本的 OpenCode。", @@ -805,8 +932,6 @@ export const dict = { "settings.permissions.tool.skill.description": "按名称加载技能", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "运行语言服务器查询", - "settings.permissions.tool.todowrite.title": "更新待办", - "settings.permissions.tool.todowrite.description": "更新待办列表", "settings.permissions.tool.webfetch.title": "网页获取", "settings.permissions.tool.webfetch.description": "从 URL 获取内容", "settings.permissions.tool.websearch.title": "网页搜索", @@ -871,7 +996,6 @@ export const dict = { "session.review.noVcs.createGit.description": "在此项目中跟踪、审查和撤消更改", "session.review.noVcs.createGit.actionLoading": "正在创建 Git 仓库...", "session.review.noVcs.createGit.action": "创建 Git 仓库", - "session.todo.progress": "已完成 {{done}} 个任务(共 {{total}} 个)", "session.question.progress": "{{current}}/{{total}} 个问题", "session.header.open.finder": "访达", "session.header.open.fileExplorer": "文件资源管理器", diff --git a/packages/app/src/i18n/zht.ts b/packages/app/src/i18n/zht.ts index 7998dde3ef..b2a1a6f3ad 100644 --- a/packages/app/src/i18n/zht.ts +++ b/packages/app/src/i18n/zht.ts @@ -27,6 +27,9 @@ export const dict = { "command.sidebar.toggle": "切換側邊欄", "command.project.open": "開啟專案", + "command.project.previous": "上一個專案", + "command.project.next": "下一個專案", + "command.project.index": "切換至專案 {{index}}", "command.provider.connect": "連接提供者", "command.server.switch": "切換伺服器", "command.settings.open": "開啟設定", @@ -49,6 +52,7 @@ export const dict = { "command.session.new": "新增工作階段", "command.file.open": "開啟檔案", "command.tab.close": "關閉分頁", + "command.tab.reopenClosed": "重新開啟已關閉的分頁", "command.context.addSelection": "將選取內容加入上下文", "command.context.addSelection.description": "加入目前檔案中選取的行", "command.input.focus": "聚焦輸入框", @@ -209,6 +213,11 @@ export const dict = { "model.input.video": "影片", "model.input.pdf": "pdf", "model.tooltip.allows": "支援: {{inputs}}", + "model.tooltip.context.label": "上下文", + "model.tooltip.inputs": "輸入", + "model.tooltip.model": "模型", + "model.tooltip.provider": "供應商", + "model.tooltip.reasoning": "推理", "model.tooltip.reasoning.allowed": "支援推理", "model.tooltip.reasoning.none": "不支援推理", "model.tooltip.context": "上下文上限 {{limit}}", @@ -218,6 +227,7 @@ export const dict = { "common.loading": "載入中", "common.loading.ellipsis": "...", "common.cancel": "取消", + "common.clear": "清除", "common.connect": "連線", "common.disconnect": "中斷連線", "common.continue": "提交", @@ -235,6 +245,8 @@ export const dict = { "prompt.mode.shell": "Shell", "prompt.mode.normal": "Prompt", "prompt.mode.shell.exit": "按 esc 退出", + "session.child.promptDisabled": "無法在子代理程式工作階段中輸入提示詞。", + "session.child.backToParent": "返回主要工作階段。", "prompt.example.1": "修復程式碼庫中的一個 TODO", "prompt.example.2": "這個專案的技術堆疊是什麼?", @@ -340,6 +352,73 @@ export const dict = { "dialog.server.menu.delete": "刪除", "dialog.server.current": "目前伺服器", "dialog.server.status.default": "預設", + "wsl.server.add": "新增 WSL 伺服器", + "wsl.server.addShort": "新增 WSL", + "wsl.server.label": "WSL", + "wsl.server.menu.label": "WSL 伺服器", + "wsl.server.retryStart": "重試啟動", + "wsl.server.updating": "更新中...", + "wsl.onboarding.step.distro": "選擇發行版", + "wsl.onboarding.step.opencode": "OpenCode", + "wsl.onboarding.checkingRuntime": "正在檢查 WSL...", + "wsl.onboarding.restartRequired": "Windows 需要重新啟動,才能完成 WSL 安裝。", + "wsl.onboarding.ready": "WSL 已就緒。", + "wsl.onboarding.required": "需要 WSL 才能繼續。", + "wsl.onboarding.checkingDistros": "正在檢查發行版...", + "wsl.onboarding.installingDistro": "正在安裝 {{distro}}...", + "wsl.onboarding.checkingDistro": "正在檢查 {{distro}}...", + "wsl.onboarding.listingDistros": "正在列出發行版...", + "wsl.onboarding.distroReady": "{{distro}} 已就緒。", + "wsl.onboarding.distroNotInstalled": "尚未安裝 {{distro}}。", + "wsl.onboarding.openDistroOnce": "開啟 {{distro}} 一次以完成設定。", + "wsl.onboarding.finishingDistro": "正在完成 {{distro}} 的設定。", + "wsl.onboarding.pickDistro": "選擇發行版,或在下方安裝。", + "wsl.onboarding.checkingOpencode": "正在檢查 OpenCode...", + "wsl.onboarding.checkingOpencodeIn": "正在檢查 {{distro}} 中的 OpenCode...", + "wsl.onboarding.updatingOpencode": "正在更新 OpenCode...", + "wsl.onboarding.updatingOpencodeIn": "正在更新 {{distro}} 中的 OpenCode...", + "wsl.onboarding.updateOpencodeIn": "更新 {{distro}} 中的 OpenCode。", + "wsl.onboarding.updateOpencode": "更新 OpenCode", + "wsl.onboarding.opencodeReadyIn": "{{distro}} 中的 OpenCode 已就緒。", + "wsl.onboarding.opencodeReady": "OpenCode 已就緒。", + "wsl.onboarding.installOpencodeIn": "在 {{distro}} 中安裝 OpenCode。", + "wsl.onboarding.installOpencode": "安裝 OpenCode", + "wsl.onboarding.chooseDistroFirst": "請先選擇發行版。", + "wsl.onboarding.loadFailed": "無法載入 WSL 狀態。", + "wsl.onboarding.loading": "載入中...", + "wsl.onboarding.installedDistros": "已安裝的發行版", + "wsl.onboarding.checkAgain": "再次檢查", + "wsl.onboarding.distroStatus.ready": "就緒", + "wsl.onboarding.distroStatus.checking": "檢查中...", + "wsl.onboarding.distroStatus.opencodeMissing": "未安裝 OpenCode", + "wsl.onboarding.distroStatus.missingTools": "缺少 bash、curl", + "wsl.onboarding.distroStatus.unsupported": "不支援 · 請使用 WSL 2", + "wsl.onboarding.needAnotherDistro": "需要其他發行版?", + "wsl.onboarding.needAnotherDistroHint": "從 WSL 目錄安裝 Linux 發行版", + "wsl.onboarding.wslNotInstalled.title": "未安裝 WSL", + "wsl.onboarding.wslNotInstalled.description": "新增 WSL 伺服器前,必須先安裝 WSL(Windows Subsystem for Linux)", + "wsl.onboarding.wslUnavailable.title": "WSL 無法使用", + "wsl.onboarding.wslUnavailable.description": "OpenCode 無法確認此電腦上的 WSL。", + "wsl.onboarding.installWsl": "安裝 WSL", + "wsl.onboarding.windowsRestartRequired": "重新啟動 Windows 以完成 WSL 安裝,然後重新開啟 OpenCode。", + "wsl.onboarding.next": "下一步", + "wsl.onboarding.refresh": "重新整理", + "wsl.onboarding.allDistrosAdded": "所有已安裝的發行版都已新增。", + "wsl.onboarding.noDistros": "尚未偵測到發行版。", + "wsl.onboarding.install": "安裝", + "wsl.onboarding.installing": "安裝中...", + "wsl.onboarding.installDistro": "安裝發行版", + "wsl.onboarding.searchDistros": "搜尋發行版", + "wsl.onboarding.wsl2Required": "需要 WSL 2。", + "wsl.onboarding.toolsRequired": "此發行版需要 bash 和 curl。", + "wsl.onboarding.openTerminal": "開啟終端機", + "wsl.onboarding.path": "路徑: {{path}}", + "wsl.onboarding.notFound": "找不到", + "wsl.onboarding.version": "版本: {{version}}", + "wsl.onboarding.unknown": "未知", + "wsl.onboarding.desktopVersion": "桌面版 {{version}}", + "wsl.onboarding.versionMismatch": "已安裝版本與桌面應用程式版本不符。", + "wsl.onboarding.adding": "新增中...", "dialog.project.edit.title": "編輯專案", "dialog.project.edit.name": "名稱", @@ -402,6 +481,7 @@ export const dict = { "language.no": "Norsk", "language.br": "Português (Brasil)", "language.bs": "Bosanski", + "language.uk": "Українська", "language.th": "ไทย", "language.tr": "Türkçe", @@ -449,10 +529,12 @@ export const dict = { "error.page.title": "出了點問題", "error.page.description": "載入應用程式時發生錯誤。", + "error.page.description.localServerStartup": "啟動本機伺服器時發生錯誤。", "error.page.details.label": "錯誤詳情", "error.page.action.restart": "重新啟動", "error.page.action.report": "回報錯誤", "error.page.action.reported": "已回報錯誤", + "error.page.action.exportLogs": "匯出日誌", "error.page.action.checking": "檢查中...", "error.page.action.checkUpdates": "檢查更新", "error.page.action.updateTo": "更新到 {{version}}", @@ -498,17 +580,39 @@ export const dict = { "home.recentProjects": "最近專案", "home.empty.title": "沒有最近專案", "home.empty.description": "透過開啟本地專案開始使用", + "home.title": "首頁", + "home.projects": "專案", + "home.project.add": "新增專案", + "home.recentlyClosed": "最近關閉", + "home.server.collapse": "收合伺服器專案", + "home.server.expand": "展開伺服器專案", + "home.sessions.search.placeholder": "搜尋工作階段", + "home.sessions.search.placeholder.scoped": "在 {{scope}} 中搜尋工作階段", + "home.sessions.search.sessions": "工作階段", + "home.sessions.search.noResults": "找不到符合 {{query}} 的工作階段", + "home.sessions.empty": "這裡還沒有內容", + "home.sessions.empty.description": "建立工作階段以開始使用", + "home.sessions.group.today": "今天", + "home.sessions.group.yesterday": "昨天", + "home.sessions.group.older": "更早", "session.tab.session": "工作階段", "session.tab.review": "審查", "session.tab.context": "上下文", + "session.tab.unknown": "未知的工作階段", "session.panel.reviewAndFiles": "審查與檔案", + "session.error.notFound": "找不到此工作階段", + "session.error.notFound.description": "此分頁指向的工作階段已不存在於此伺服器。", + "session.error.notFound.closeTab": "關閉分頁", + "session.error.serverConnection": "無法連線至此伺服器", "session.review.filesChanged": "{{count}} 個檔案變更", "session.review.change.one": "變更", "session.review.change.other": "變更", "session.review.loadingChanges": "正在載入變更...", "session.review.empty": "此工作階段暫無變更", "session.review.noChanges": "沒有變更", + "session.review.noUncommittedChanges": "尚無未提交的變更", + "session.review.noBranchChanges": "尚無分支變更", "session.review.noVcs": "未偵測到 Git 版本控制系統,無法顯示變更", "session.review.noSnapshot": "設定中已停用快照追蹤,因此無法使用工作階段變更", "session.files.selectToOpen": "選取要開啟的檔案", @@ -522,9 +626,10 @@ export const dict = { "session.messages.jumpToLatest": "跳到最新", "session.context.addToContext": "將 {{selection}} 新增到上下文", - "session.todo.title": "待辦事項", - "session.todo.collapse": "折疊", - "session.todo.expand": "展開", + "session.question.minimize": "最小化問題", + "session.question.restore": "還原問題", + "session.question.pending.one": "{{count}} 個待處理問題", + "session.question.pending.other": "{{count}} 個待處理問題", "session.followupDock.summary.one": "{{count}} 則佇列訊息", "session.followupDock.summary.other": "{{count}} 則佇列訊息", "session.followupDock.sendNow": "立即傳送", @@ -538,9 +643,16 @@ export const dict = { "session.revertDock.restore": "還原訊息", "session.new.title": "建構任何東西", + "session.new.project.new": "新專案", + "session.new.project.search": "搜尋專案", + "session.new.project.add": "新增專案", "session.new.worktree.main": "主分支", "session.new.worktree.mainWithBranch": "主分支 ({{branch}})", "session.new.worktree.create": "建立新的 worktree", + "session.new.workspace.runIn": "工作階段執行位置", + "session.new.workspace.triggerLocal": "本機", + "session.new.workspace.local": "本機儲存庫", + "session.new.workspace.existing": "工作區…", "session.new.lastModified": "最後修改", "session.header.search.placeholder": "搜尋 {{project}}", @@ -608,6 +720,8 @@ export const dict = { "sidebar.project.recentSessions": "最近工作階段", "sidebar.project.viewAllSessions": "查看全部工作階段", "sidebar.project.clearNotifications": "清除通知", + "sidebar.empty.title": "未開啟任何專案", + "sidebar.empty.description": "開啟專案以開始使用", "app.name.desktop": "OpenCode Desktop", "settings.section.desktop": "桌面", @@ -619,6 +733,7 @@ export const dict = { "settings.desktop.wsl.description": "在 Windows 上的 WSL 中執行 OpenCode 伺服器。", "settings.general.section.appearance": "外觀", + "settings.general.section.advanced": "進階", "settings.general.section.notifications": "系統通知", "settings.general.section.updates": "更新", "settings.general.section.sounds": "音效", @@ -627,6 +742,10 @@ export const dict = { "settings.general.row.language.title": "語言", "settings.general.row.language.description": "變更 OpenCode 的顯示語言", + "settings.general.row.shell.title": "終端機 Shell", + "settings.general.row.shell.description": "選擇終端機使用的 Shell。相容的 Shell 也會用於代理程式工具呼叫。", + "settings.general.row.shell.autoDefault": "自動(預設)", + "settings.general.row.shell.terminalOnly": "僅限終端機", "settings.general.row.appearance.title": "外觀", "settings.general.row.appearance.description": "自訂 OpenCode 在你的裝置上的外觀", "settings.general.row.colorScheme.title": "配色方案", @@ -635,14 +754,28 @@ export const dict = { "settings.general.row.theme.description": "自訂 OpenCode 的主題。", "settings.general.row.font.title": "程式碼字型", "settings.general.row.font.description": "自訂程式碼區塊使用的字型", - "settings.general.row.terminalFont.title": "Terminal Font", - "settings.general.row.terminalFont.description": "Customise the font used in the terminal", + "settings.general.row.terminalFont.title": "終端機字型", + "settings.general.row.terminalFont.description": "自訂終端機使用的字型", "settings.general.row.uiFont.title": "介面字型", "settings.general.row.uiFont.description": "自訂整個介面使用的字型", "settings.general.row.followup.title": "後續追問行為", "settings.general.row.followup.description": "選擇後續追問提示是立即引導還是進入佇列等待", "settings.general.row.followup.option.queue": "佇列", "settings.general.row.followup.option.steer": "引導", + "settings.general.row.showFileTree.title": "檔案樹", + "settings.general.row.showFileTree.description": "在工作階段中顯示檔案樹面板", + "settings.general.row.showNavigation.title": "導覽控制項", + "settings.general.row.showNavigation.description": "在桌面標題列中顯示上一頁和下一頁按鈕", + "settings.general.row.showSearch.title": "命令面板", + "settings.general.row.showSearch.description": "在標題列中顯示搜尋和命令面板按鈕", + "settings.general.row.showTerminal.title": "終端機", + "settings.general.row.showTerminal.description": "在桌面標題列中顯示終端機按鈕", + "settings.general.row.showStatus.title": "伺服器狀態", + "settings.general.row.showStatus.description": "在標題列中顯示伺服器狀態按鈕", + "settings.general.row.mobileTitlebarBottom.title": "底部導覽", + "settings.general.row.mobileTitlebarBottom.description": "在行動裝置上將標題列和工作階段分頁置於畫面底部", + "settings.general.row.showCustomAgents.title": "自訂代理程式", + "settings.general.row.showCustomAgents.description": "在輸入區顯示代理程式選擇器", "settings.general.row.reasoningSummaries.title": "顯示推理摘要", "settings.general.row.reasoningSummaries.description": "在時間軸中顯示模型推理摘要", @@ -650,6 +783,10 @@ export const dict = { "settings.general.row.shellToolPartsExpanded.description": "在時間軸中預設展開 shell 工具區塊", "settings.general.row.editToolPartsExpanded.title": "展開 edit 工具區塊", "settings.general.row.editToolPartsExpanded.description": "在時間軸中預設展開 edit、write 和 patch 工具區塊", + "settings.general.row.newLayoutDesigns.title": "新版面與設計", + "settings.general.row.newLayoutDesigns.description": "啟用重新設計的版面、首頁、輸入區和工作階段介面", + "settings.general.row.pinchZoom.title": "雙指縮放", + "settings.general.row.pinchZoom.description": "允許使用觸控板雙指開合和 Ctrl-捲動手勢縮放", "settings.general.row.wayland.title": "使用原生 Wayland", "settings.general.row.wayland.description": "在 Wayland 上停用 X11 後備模式。需要重新啟動。", "settings.general.row.wayland.tooltip": "在混合更新率螢幕的 Linux 系統上,原生 Wayland 可能更穩定。", @@ -663,6 +800,8 @@ export const dict = { "settings.updates.row.check.description": "手動檢查更新並在有更新時安裝", "settings.updates.action.checkNow": "立即檢查", "settings.updates.action.checking": "檢查中...", + "settings.updates.action.downloading": "下載中...", + "settings.updates.action.installing": "安裝中...", "settings.updates.toast.latest.title": "已是最新版本", "settings.updates.toast.latest.description": "你正在使用最新版本的 OpenCode。", @@ -789,8 +928,6 @@ export const dict = { "settings.permissions.tool.skill.description": "按名稱載入技能", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "執行語言伺服器查詢", - "settings.permissions.tool.todowrite.title": "更新待辦", - "settings.permissions.tool.todowrite.description": "更新待辦清單", "settings.permissions.tool.webfetch.title": "Web Fetch", "settings.permissions.tool.webfetch.description": "從 URL 取得內容", "settings.permissions.tool.websearch.title": "Web Search", @@ -855,7 +992,6 @@ export const dict = { "session.review.noVcs.createGit.description": "追蹤、檢閱及復原此專案中的變更", "session.review.noVcs.createGit.actionLoading": "正在建立 Git 儲存庫...", "session.review.noVcs.createGit.action": "建立 Git 儲存庫", - "session.todo.progress": "已完成 {{done}} 個待辦事項(共 {{total}} 個)", "session.question.progress": "{{current}}/{{total}} 個問題", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "檔案總管", diff --git a/packages/app/src/index.css b/packages/app/src/index.css index bc6866f976..78a9e103a7 100644 --- a/packages/app/src/index.css +++ b/packages/app/src/index.css @@ -224,7 +224,26 @@ [data-slot="model-selector-scroll"]::before { top: 0; - background: linear-gradient(to bottom, var(--v2-background-bg-layer-01), transparent); + height: 12px; + background: linear-gradient( + 180deg, + color-mix(in srgb, var(--v2-background-bg-layer-01) 80%, transparent) 0%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 78.3336%, transparent) 4.7%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 76.4824%, transparent) 8.9%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 74.368%, transparent) 12.8%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 71.9123%, transparent) 16.56%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 69.037%, transparent) 20.37%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 65.664%, transparent) 24.4%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 61.715%, transparent) 28.83%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 57.1117%, transparent) 33.84%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 51.776%, transparent) 39.6%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 45.6296%, transparent) 46.3%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 38.5944%, transparent) 54.1%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 30.592%, transparent) 63.2%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 21.5443%, transparent) 73.76%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 11.373%, transparent) 85.97%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 0%, transparent) 100% + ); } [data-slot="manage-models-scroll"]::before { @@ -239,7 +258,26 @@ [data-slot="model-selector-scroll"]::after { bottom: 0; - background: linear-gradient(to top, var(--v2-background-bg-layer-01), transparent); + height: 12px; + background: linear-gradient( + 0deg, + color-mix(in srgb, var(--v2-background-bg-layer-01) 80%, transparent) 0%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 78.3336%, transparent) 4.7%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 76.4824%, transparent) 8.9%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 74.368%, transparent) 12.8%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 71.9123%, transparent) 16.56%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 69.037%, transparent) 20.37%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 65.664%, transparent) 24.4%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 61.715%, transparent) 28.83%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 57.1117%, transparent) 33.84%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 51.776%, transparent) 39.6%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 45.6296%, transparent) 46.3%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 38.5944%, transparent) 54.1%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 30.592%, transparent) 63.2%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 21.5443%, transparent) 73.76%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 11.373%, transparent) 85.97%, + color-mix(in srgb, var(--v2-background-bg-layer-01) 0%, transparent) 100% + ); } @supports (animation-timeline: --home-projects-scroll) and (timeline-scope: --home-projects-scroll) { diff --git a/packages/app/src/pages/home.tsx b/packages/app/src/pages/home.tsx index efbab7809e..c4d84a96f8 100644 --- a/packages/app/src/pages/home.tsx +++ b/packages/app/src/pages/home.tsx @@ -35,7 +35,7 @@ import { usePlatform } from "@/context/platform" import { DateTime } from "luxon" import { useDialog } from "@opencode-ai/ui/context/dialog" import { useDirectoryPicker } from "@/components/directory-picker" -import { useSettingsCommand } from "@/components/settings-dialog" +import { useSettingsDialog } from "@/components/settings-dialog" import { DialogSelectServer, useServerManagementController } from "@/components/dialog-select-server" import { DialogServerV2 } from "@/components/settings-v2/dialog-server-v2" import { ServerConnection, serverName, useServer } from "@/context/server" @@ -267,7 +267,7 @@ export function NewHome() { const command = useCommand() const notification = useNotification() const marked = useMarked() - const openSettings = useSettingsCommand() + const openSettings = useSettingsDialog() let focusSessionSearch: (() => void) | undefined const [state, setState] = createStore({ search: "", @@ -1278,7 +1278,7 @@ function HomeSessionSearch(props: { -