diff --git a/config/scripts/locale-ko-key-overrides.json b/config/scripts/locale-ko-key-overrides.json index e8d13941ffaa..ff2b6005ffa8 100644 --- a/config/scripts/locale-ko-key-overrides.json +++ b/config/scripts/locale-ko-key-overrides.json @@ -5089,5 +5089,98 @@ }, "auto.components.right.sidebar.AiVaultPanel.noAgentsSelected": { "ko": "선택된 에이전트가 없습니다" + }, + "auto.components.contextual.tours.contextual.tour.step.copy.agent.sessions.parallel.body": { + "ko": "워크트리마다 자체 브랜치를 가지므로 병렬로 진행하는 작업이 서로 섞이지 않습니다." + }, + "auto.components.contextual.tours.contextual.tour.step.copy.agent.sessions.parallel.title": { + "ko": "다른 작업을 병렬로 시작하기" + }, + "auto.components.contextual.tours.contextual.tour.step.copy.agent.sessions.split.action": { + "ko": "Terminal 분할" + }, + "auto.components.contextual.tours.contextual.tour.step.copy.agent.sessions.split.body": { + "ko": "{terminal.splitRight} 키로 두 번째 Terminal 창을 열거나, 창을 우클릭해 분할 옵션을 확인하세요." + }, + "auto.components.contextual.tours.contextual.tour.step.copy.agent.sessions.split.title": { + "ko": "Terminal 창 분할" + }, + "auto.components.contextual.tours.contextual.tour.step.copy.browser.annotate.body": { + "ko": "요소에 주석을 달고 그 메모를 agent에 보내세요." + }, + "auto.components.contextual.tours.contextual.tour.step.copy.browser.annotate.title": { + "ko": "디자인 피드백을 화면에 바로 남기기" + }, + "auto.components.contextual.tours.contextual.tour.step.copy.browser.grab.body": { + "ko": "grab 도구로 페이지 요소의 컨텍스트를 복사해 agent에 전달하세요." + }, + "auto.components.contextual.tours.contextual.tour.step.copy.browser.grab.title": { + "ko": "agent를 위한 페이지 컨텍스트 가져오기" + }, + "auto.components.contextual.tours.contextual.tour.step.copy.browser.logins.body": { + "ko": "기존 로그인 정보를 Orca로 가져와 바로 로그인 상태를 유지하세요." + }, + "auto.components.contextual.tours.contextual.tour.step.copy.browser.logins.title": { + "ko": "로그인 상태 유지" + }, + "auto.components.contextual.tours.contextual.tour.step.copy.floating.workspace.repos.body": { + "ko": "이곳의 agent는 선택한 어떤 폴더에서도 실행됩니다. 서비스들의 상위 디렉터리를 지정하면 모든 repo에서 한 번에 작업할 수 있습니다." + }, + "auto.components.contextual.tours.contextual.tour.step.copy.floating.workspace.repos.title": { + "ko": "agent 하나로 모든 repo 다루기" + }, + "auto.components.contextual.tours.contextual.tour.step.copy.floating.workspace.scratchpad.body": { + "ko": "집중하고 있는 워크트리를 어지럽히지 않고 agent, 임시 Terminal, 노트, 브라우저 탭을 열 수 있습니다." + }, + "auto.components.contextual.tours.contextual.tour.step.copy.floating.workspace.scratchpad.title": { + "ko": "메모장처럼 사용하기" + }, + "auto.components.contextual.tours.contextual.tour.step.copy.tasks.filter.body": { + "ko": "프리셋과 검색으로 이슈, 리뷰, merge requests, 작업의 범위를 좁히세요." + }, + "auto.components.contextual.tours.contextual.tour.step.copy.tasks.filter.title": { + "ko": "필요한 작업만 필터링하기" + }, + "auto.components.contextual.tours.contextual.tour.step.copy.tasks.source.body": { + "ko": "페이지를 이동하지 않고 연결된 제공자와 프로젝트 필터를 전환하세요." + }, + "auto.components.contextual.tours.contextual.tour.step.copy.tasks.source.title": { + "ko": "작업 소스 선택" + }, + "auto.components.contextual.tours.contextual.tour.step.copy.tasks.start.body": { + "ko": "작업, 이슈, 리뷰, merge request에서 시작 또는 열기를 눌러 해당 컨텍스트를 워크스페이스로 가져오세요." + }, + "auto.components.contextual.tours.contextual.tour.step.copy.tasks.start.title": { + "ko": "작업 항목에서 시작하기" + }, + "auto.components.contextual.tours.contextual.tour.step.copy.workspace.board.lanes.body": { + "ko": "상태가 바뀌면 워크스페이스를 레인 사이로 끌어다 놓으세요." + }, + "auto.components.contextual.tours.contextual.tour.step.copy.workspace.board.lanes.title": { + "ko": "레인을 따라 작업 옮기기" + }, + "auto.components.contextual.tours.contextual.tour.step.copy.workspace.board.plan.body": { + "ko": "프로젝트별이 아니라 상태별로 워크스페이스를 보고 싶을 때 보드를 사용하세요." + }, + "auto.components.contextual.tours.contextual.tour.step.copy.workspace.board.plan.title": { + "ko": "보드에서 작업 계획하기" + }, + "auto.components.contextual.tours.contextual.tour.step.copy.workspace.creation.agent.body": { + "ko": "이 워크트리가 생성될 때 열릴 agent를 선택하세요." + }, + "auto.components.contextual.tours.contextual.tour.step.copy.workspace.creation.agent.title": { + "ko": "작업을 시작할 agent 선택" + }, + "auto.components.contextual.tours.contextual.tour.step.copy.workspace.creation.name.body": { + "ko": "연결된 작업에서 시작하면 짧은 이슈나 PR 이름을 사용합니다. 비워 두면 첫 agent 메시지에서 이름이 자동으로 지정됩니다." + }, + "auto.components.contextual.tours.contextual.tour.step.copy.workspace.creation.name.title": { + "ko": "이름을 정하거나 기존 작업에서 시작하기" + }, + "auto.components.contextual.tours.contextual.tour.step.copy.workspace.creation.project.body": { + "ko": "Orca는 각 작업을 기준 브랜치에서 분기한 자체 워크트리로 분리합니다." + }, + "auto.components.contextual.tours.contextual.tour.step.copy.workspace.creation.project.title": { + "ko": "프로젝트 선택" } } diff --git a/src/renderer/src/components/contextual-tours/contextual-tour-overlay-measurement.test.ts b/src/renderer/src/components/contextual-tours/contextual-tour-overlay-measurement.test.ts index 4b2ce9631ca1..f6c35e5dd857 100644 --- a/src/renderer/src/components/contextual-tours/contextual-tour-overlay-measurement.test.ts +++ b/src/renderer/src/components/contextual-tours/contextual-tour-overlay-measurement.test.ts @@ -79,6 +79,7 @@ describe('contextual tour overlay measurement', () => { ...automations, steps: [ { + id: 'inserted-step', title: 'Inserted step', body: 'Added ahead of the localized steps.', targetSelector: '[data-contextual-tour-target="automations-create"]' diff --git a/src/renderer/src/components/contextual-tours/contextual-tour-overlay-measurement.ts b/src/renderer/src/components/contextual-tours/contextual-tour-overlay-measurement.ts index 1fe945a42cbf..ce27baa9e773 100644 --- a/src/renderer/src/components/contextual-tours/contextual-tour-overlay-measurement.ts +++ b/src/renderer/src/components/contextual-tours/contextual-tour-overlay-measurement.ts @@ -11,6 +11,7 @@ import { getVisibleContextualTourStepIndexes } from './contextual-tour-gate' import type { ActiveTourRenderState } from './ContextualTourOverlaySurface' +import { getLocalizedContextualTourStepCopy } from './contextual-tour-step-copy' import { translate } from '@/i18n/i18n' export type ContextualTourMeasurementAction = @@ -28,36 +29,6 @@ export type ContextualTourOverlayMeasurementResult = telemetryTotalSteps: number } -// Why: keyed by the step's stable id, not its position — inserting a step must -// not shift localized copy onto a neighbour. Thunks keep translate() out of -// module scope so the lookup resolves in the language active at render time. -const LOCALIZED_STEP_COPY: Record string; body: () => string }> = { - 'automations-intro': { - title: () => - translate( - 'auto.components.contextual.tours.contextual.tour.overlay.measurement.automations.intro.title', - 'What is an automation?' - ), - body: () => - translate( - 'auto.components.contextual.tours.contextual.tour.overlay.measurement.automations.intro.body', - 'Automations run agent work on a schedule. Add an automation by clicking this button.' - ) - }, - 'automations-results': { - title: () => - translate( - 'auto.components.contextual.tours.contextual.tour.overlay.measurement.automations.results.title', - 'Find the results' - ), - body: () => - translate( - 'auto.components.contextual.tours.contextual.tour.overlay.measurement.automations.results.body', - 'Runs show when automations ran, what happened, and where to inspect their output.' - ) - } -} - export function getContextualTourDisplayProgress(args: { tour: ContextualTour visibleStepIndexes: readonly number[] @@ -119,13 +90,10 @@ export function measureContextualTourOverlayRenderState(args: { ) const activeStep = args.tour.steps[args.activeStepIndex] const target = activeStep ? getMeasurableContextualTourTarget(activeStep.targetSelector) : null - const localizedCopy = activeStep?.id ? LOCALIZED_STEP_COPY[activeStep.id] : undefined - const localizedTitle = localizedCopy ? localizedCopy.title() : activeStep?.title - const localizedBody = localizedCopy - ? localizedCopy.body() - : activeStep - ? getContextualTourStepCopy(activeStep) - : undefined + const localizedCopy = getLocalizedContextualTourStepCopy(activeStep?.id) + const localizedTitle = localizedCopy?.title ?? activeStep?.title + const localizedBody = + localizedCopy?.body ?? (activeStep ? getContextualTourStepCopy(activeStep) : undefined) const progress = getContextualTourDisplayProgress({ tour: args.tour, visibleStepIndexes, @@ -162,7 +130,9 @@ export function measureContextualTourOverlayRenderState(args: { 'Next' ) } as const) - : activeStep.primaryAction + : activeStep.primaryAction && localizedCopy?.primaryActionLabel + ? { ...activeStep.primaryAction, label: localizedCopy.primaryActionLabel } + : activeStep.primaryAction const secondaryAction = sidebarAlreadyVisible ? undefined : activeStep.secondaryAction return { diff --git a/src/renderer/src/components/contextual-tours/contextual-tour-step-copy.test.ts b/src/renderer/src/components/contextual-tours/contextual-tour-step-copy.test.ts new file mode 100644 index 000000000000..ef3a6a79ff8f --- /dev/null +++ b/src/renderer/src/components/contextual-tours/contextual-tour-step-copy.test.ts @@ -0,0 +1,43 @@ +// @vitest-environment happy-dom + +import { afterEach, describe, expect, it } from 'vitest' +import { CONTEXTUAL_TOURS, type ContextualTour } from '../../../../shared/contextual-tours' +import { setRendererUiLanguage } from '@/i18n/i18n' +import { getLocalizedContextualTourStepCopy } from './contextual-tour-step-copy' + +afterEach(async () => { + await setRendererUiLanguage('en') +}) + +describe('contextual tour step copy', () => { + it('translates every tour step, so no step falls back to English mid-tour', async () => { + await setRendererUiLanguage('ko') + + for (const tour of CONTEXTUAL_TOURS as readonly ContextualTour[]) { + for (const step of tour.steps) { + const copy = getLocalizedContextualTourStepCopy(step.id) + expect(copy, `${tour.id} step "${step.title}" has no localized copy`).toBeDefined() + expect(copy?.title).not.toBe(step.title) + expect(copy?.body).not.toBe(step.body) + if (step.primaryAction) { + expect(copy?.primaryActionLabel).toBeDefined() + expect(copy?.primaryActionLabel).not.toBe(step.primaryAction.label) + } + } + } + }) + + it('renders the floating workspace copy in Korean', async () => { + await setRendererUiLanguage('ko') + + expect(getLocalizedContextualTourStepCopy('floating-workspace-scratchpad')?.title).toBe( + '메모장처럼 사용하기' + ) + }) + + it('falls back to English copy for the active locale', () => { + expect(getLocalizedContextualTourStepCopy('floating-workspace-repos')?.title).toBe( + 'Run an agent across every repo' + ) + }) +}) diff --git a/src/renderer/src/components/contextual-tours/contextual-tour-step-copy.ts b/src/renderer/src/components/contextual-tours/contextual-tour-step-copy.ts new file mode 100644 index 000000000000..b574285ed04e --- /dev/null +++ b/src/renderer/src/components/contextual-tours/contextual-tour-step-copy.ts @@ -0,0 +1,195 @@ +import { translate } from '@/i18n/i18n' + +export type LocalizedContextualTourStepCopy = { + title: string + body: string + primaryActionLabel?: string +} + +// Automations keys are unchanged from the original fix so its shipped translations still resolve. + +// Why: keyed by the step's stable id, not its position — inserting a step must +// not shift localized copy onto a neighbour. Thunks keep translate() out of +// module scope so the lookup resolves in the language active at render time. +const LOCALIZED_STEP_COPY: Record LocalizedContextualTourStepCopy> = { + 'workspace-board-plan': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.workspace.board.plan.title', + 'Plan work on the board' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.workspace.board.plan.body', + 'Use the board when you want to see workspaces by status instead of by project.' + ) + }), + 'workspace-board-lanes': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.workspace.board.lanes.title', + 'Move work through lanes' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.workspace.board.lanes.body', + 'Drag workspaces between lanes as their status changes.' + ) + }), + 'agent-sessions-split': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.agent.sessions.split.title', + 'Split a terminal pane' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.agent.sessions.split.body', + 'Open a second terminal pane with {terminal.splitRight}, or right-click the pane for split options.' + ), + primaryActionLabel: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.agent.sessions.split.action', + 'Split terminal' + ) + }), + 'agent-sessions-parallel': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.agent.sessions.parallel.title', + 'Start another task in parallel' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.agent.sessions.parallel.body', + 'Each worktree gets its own branch, so parallel work stays separate.' + ) + }), + 'browser-grab': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.browser.grab.title', + 'Grab page context for agents' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.browser.grab.body', + "Use the grab tool to copy a page element's context for agents." + ) + }), + 'browser-annotate': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.browser.annotate.title', + 'Mark design feedback in place' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.browser.annotate.body', + 'Annotate elements and send those notes to an agent.' + ) + }), + 'browser-logins': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.browser.logins.title', + 'Stay logged in' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.browser.logins.body', + 'Bring your existing logins into Orca to stay signed in immediately.' + ) + }), + 'tasks-source': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.tasks.source.title', + 'Choose the work source' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.tasks.source.body', + 'Switch between connected providers and project filters without changing pages.' + ) + }), + 'tasks-filter': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.tasks.filter.title', + 'Filter to the work you need' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.tasks.filter.body', + 'Use presets and search to narrow issues, reviews, merge requests, or tasks.' + ) + }), + 'tasks-start': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.tasks.start.title', + 'Start from work items' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.tasks.start.body', + 'Use Start or Open on a task, issue, review, or merge request to bring its context into a workspace.' + ) + }), + 'automations-intro': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.overlay.measurement.automations.intro.title', + 'What is an automation?' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.overlay.measurement.automations.intro.body', + 'Automations run agent work on a schedule. Add an automation by clicking this button.' + ) + }), + 'automations-results': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.overlay.measurement.automations.results.title', + 'Find the results' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.overlay.measurement.automations.results.body', + 'Runs show when automations ran, what happened, and where to inspect their output.' + ) + }), + 'floating-workspace-repos': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.floating.workspace.repos.title', + 'Run an agent across every repo' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.floating.workspace.repos.body', + 'Agents here run in any folder you choose. Point one at the directory above your services to work across all your repos at once.' + ) + }), + 'floating-workspace-scratchpad': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.floating.workspace.scratchpad.title', + 'Or use it as a scratchpad' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.floating.workspace.scratchpad.body', + 'Open agents, scratch terminals, notes, and browser tabs without cluttering the worktree you’re focused on.' + ) + }), + 'workspace-creation-project': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.workspace.creation.project.title', + 'Pick a project' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.workspace.creation.project.body', + 'Orca isolates each task in its own worktree, branched off your base.' + ) + }), + 'workspace-creation-name': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.workspace.creation.name.title', + 'Name it, or start from existing work' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.workspace.creation.name.body', + 'Start from a linked task for a short issue or PR name. Or leave it blank to auto-name it from your first agent message.' + ) + }), + 'workspace-creation-agent': () => ({ + title: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.workspace.creation.agent.title', + 'Choose what agent starts the work' + ), + body: translate( + 'auto.components.contextual.tours.contextual.tour.step.copy.workspace.creation.agent.body', + 'Pick the agent that should be opened when this worktree is created.' + ) + }) +} + +export function getLocalizedContextualTourStepCopy( + stepId: string | undefined +): LocalizedContextualTourStepCopy | undefined { + return stepId ? LOCALIZED_STEP_COPY[stepId]?.() : undefined +} diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json index 996d7138ea06..f8aa67838386 100644 --- a/src/renderer/src/i18n/locales/en.json +++ b/src/renderer/src/i18n/locales/en.json @@ -13599,6 +13599,89 @@ } } } + }, + "step": { + "copy": { + "workspace": { + "board": { + "plan": { + "title": "Plan work on the board", + "body": "Use the board when you want to see workspaces by status instead of by project." + }, + "lanes": { + "title": "Move work through lanes", + "body": "Drag workspaces between lanes as their status changes." + } + }, + "creation": { + "project": { + "title": "Pick a project", + "body": "Orca isolates each task in its own worktree, branched off your base." + }, + "name": { + "title": "Name it, or start from existing work", + "body": "Start from a linked task for a short issue or PR name. Or leave it blank to auto-name it from your first agent message." + }, + "agent": { + "title": "Choose what agent starts the work", + "body": "Pick the agent that should be opened when this worktree is created." + } + } + }, + "agent": { + "sessions": { + "split": { + "title": "Split a terminal pane", + "body": "Open a second terminal pane with {terminal.splitRight}, or right-click the pane for split options.", + "action": "Split terminal" + }, + "parallel": { + "title": "Start another task in parallel", + "body": "Each worktree gets its own branch, so parallel work stays separate." + } + } + }, + "browser": { + "grab": { + "title": "Grab page context for agents", + "body": "Use the grab tool to copy a page element's context for agents." + }, + "annotate": { + "title": "Mark design feedback in place", + "body": "Annotate elements and send those notes to an agent." + }, + "logins": { + "title": "Stay logged in", + "body": "Bring your existing logins into Orca to stay signed in immediately." + } + }, + "tasks": { + "source": { + "title": "Choose the work source", + "body": "Switch between connected providers and project filters without changing pages." + }, + "filter": { + "title": "Filter to the work you need", + "body": "Use presets and search to narrow issues, reviews, merge requests, or tasks." + }, + "start": { + "title": "Start from work items", + "body": "Use Start or Open on a task, issue, review, or merge request to bring its context into a workspace." + } + }, + "floating": { + "workspace": { + "repos": { + "title": "Run an agent across every repo", + "body": "Agents here run in any folder you choose. Point one at the directory above your services to work across all your repos at once." + }, + "scratchpad": { + "title": "Or use it as a scratchpad", + "body": "Open agents, scratch terminals, notes, and browser tabs without cluttering the worktree you’re focused on." + } + } + } + } } } } diff --git a/src/renderer/src/i18n/locales/es.json b/src/renderer/src/i18n/locales/es.json index 095de652a6ac..96717e48e500 100644 --- a/src/renderer/src/i18n/locales/es.json +++ b/src/renderer/src/i18n/locales/es.json @@ -13306,7 +13306,8 @@ "4a9568f773": "Atrás", "4f86e2a10b": "Saltar recorrido", "d974f32a83": "Descartar recorrido", - "ffa4412b66": "próximo" + "ffa4412b66": "Siguiente", + "complete": "Hecho" }, "ContextualTourProgressDots": { "7734cb8ad3": "de", @@ -13316,7 +13317,100 @@ "tour": { "overlay": { "measurement": { - "38b3155418": "Próximo" + "38b3155418": "Siguiente", + "automations": { + "intro": { + "title": "¿Qué es una automatización?", + "body": "Las automatizaciones ejecutan trabajo de agentes según una programación. Añade una automatización con este botón." + }, + "results": { + "title": "Consulta los resultados", + "body": "Las ejecuciones muestran cuándo se ejecutaron las automatizaciones, qué ocurrió y dónde revisar su salida." + } + } + } + }, + "step": { + "copy": { + "workspace": { + "board": { + "plan": { + "title": "Planifica el trabajo en el tablero", + "body": "Usa el tablero cuando quieras ver los espacios de trabajo por estado en lugar de por proyecto." + }, + "lanes": { + "title": "Mueve el trabajo entre carriles", + "body": "Arrastra los espacios de trabajo entre carriles a medida que cambia su estado." + } + }, + "creation": { + "project": { + "title": "Elige un proyecto", + "body": "Orca aísla cada tarea en su propio worktree, creado a partir de tu rama base." + }, + "name": { + "title": "Ponle nombre o usa un elemento de trabajo existente", + "body": "Parte de una tarea vinculada para usar un nombre corto de incidencia o PR. O déjalo en blanco para nombrarlo automáticamente a partir de tu primer mensaje al agente." + }, + "agent": { + "title": "Elige qué agente empieza el trabajo", + "body": "Elige el agente que debe abrirse cuando se cree este worktree." + } + } + }, + "agent": { + "sessions": { + "split": { + "title": "Divide un panel de terminal", + "body": "Abre un segundo panel de terminal con {terminal.splitRight} o haz clic derecho en el panel para ver las opciones de división.", + "action": "Dividir terminal" + }, + "parallel": { + "title": "Empieza otra tarea en paralelo", + "body": "Cada worktree tiene su propia rama, así que el trabajo en paralelo se mantiene separado." + } + } + }, + "browser": { + "grab": { + "title": "Captura el contexto de la página para los agentes", + "body": "Usa la herramienta de captura para copiar el contexto de un elemento de la página para los agentes." + }, + "annotate": { + "title": "Marca el feedback de diseño sobre la página", + "body": "Anota elementos y envía esas notas a un agente." + }, + "logins": { + "title": "Mantén la sesión iniciada", + "body": "Lleva tus inicios de sesión existentes a Orca para seguir conectado de inmediato." + } + }, + "tasks": { + "source": { + "title": "Elige el origen del trabajo", + "body": "Cambia entre proveedores conectados y filtros de proyecto sin cambiar de página." + }, + "filter": { + "title": "Filtra hasta el trabajo que necesitas", + "body": "Usa los preajustes y la búsqueda para acotar incidencias, revisiones, merge requests o tareas." + }, + "start": { + "title": "Empieza desde los elementos de trabajo", + "body": "Usa Iniciar o Abrir en una tarea, incidencia, revisión o merge request para llevar su contexto a un espacio de trabajo." + } + }, + "floating": { + "workspace": { + "repos": { + "title": "Ejecuta un agente en todos los repositorios", + "body": "Los agentes de aquí se ejecutan en la carpeta que elijas. Apunta uno al directorio superior a tus servicios para trabajar en todos tus repositorios a la vez." + }, + "scratchpad": { + "title": "O úsalo como bloc de notas", + "body": "Abre agentes, terminales temporales, notas y pestañas del navegador sin saturar el worktree en el que estás concentrado." + } + } + } } } } diff --git a/src/renderer/src/i18n/locales/ja.json b/src/renderer/src/i18n/locales/ja.json index 4ed7237ae844..f0742b71a6c7 100644 --- a/src/renderer/src/i18n/locales/ja.json +++ b/src/renderer/src/i18n/locales/ja.json @@ -13306,7 +13306,8 @@ "4a9568f773": "戻る", "4f86e2a10b": "ツアーをスキップ", "d974f32a83": "ツアーを閉じる", - "ffa4412b66": "次" + "ffa4412b66": "次", + "complete": "完了" }, "ContextualTourProgressDots": { "7734cb8ad3": "の", @@ -13316,7 +13317,100 @@ "tour": { "overlay": { "measurement": { - "38b3155418": "次へ" + "38b3155418": "次へ", + "automations": { + "intro": { + "title": "オートメーションとは?", + "body": "オートメーションはスケジュールに従って agent の作業を実行します。このボタンからオートメーションを追加できます。" + }, + "results": { + "title": "結果を確認する", + "body": "実行履歴では、オートメーションがいつ実行され、何が起きて、出力をどこで確認できるかがわかります。" + } + } + } + }, + "step": { + "copy": { + "workspace": { + "board": { + "plan": { + "title": "ボードで作業を計画する", + "body": "プロジェクト別ではなく状態別にワークスペースを見たいときはボードを使います。" + }, + "lanes": { + "title": "レーン間で作業を動かす", + "body": "状態が変わったら、ワークスペースをレーン間にドラッグします。" + } + }, + "creation": { + "project": { + "title": "プロジェクトを選ぶ", + "body": "Orca は各タスクをベースブランチから分岐した専用のワークツリーに分離します。" + }, + "name": { + "title": "名前を付けるか、既存の作業から始める", + "body": "リンクされたタスクから始めると、短い issue 名や PR 名が使われます。空欄のままにすると、最初の agent メッセージから自動で名前が付きます。" + }, + "agent": { + "title": "作業を開始する agent を選ぶ", + "body": "このワークツリーが作成されたときに開く agent を選びます。" + } + } + }, + "agent": { + "sessions": { + "split": { + "title": "Terminal ペインを分割する", + "body": "{terminal.splitRight} で 2 つ目の Terminal ペインを開くか、ペインを右クリックして分割オプションを表示します。", + "action": "Terminal を分割" + }, + "parallel": { + "title": "別のタスクを並行して始める", + "body": "ワークツリーごとに専用のブランチがあるため、並行して進める作業が混ざりません。" + } + } + }, + "browser": { + "grab": { + "title": "agent 向けにページのコンテキストを取得する", + "body": "grab ツールでページ要素のコンテキストをコピーして agent に渡します。" + }, + "annotate": { + "title": "デザインのフィードバックをその場で残す", + "body": "要素に注釈を付けて、そのメモを agent に送ります。" + }, + "logins": { + "title": "ログイン状態を保つ", + "body": "既存のログイン情報を Orca に取り込んで、すぐにログイン状態を保ちます。" + } + }, + "tasks": { + "source": { + "title": "作業のソースを選ぶ", + "body": "ページを移動せずに、接続済みのプロバイダーとプロジェクトフィルターを切り替えます。" + }, + "filter": { + "title": "必要な作業だけに絞り込む", + "body": "プリセットと検索で issues、レビュー、merge requests、タスクを絞り込みます。" + }, + "start": { + "title": "作業アイテムから始める", + "body": "タスク、issue、レビュー、merge request で開始または開くを押すと、そのコンテキストをワークスペースに取り込めます。" + } + }, + "floating": { + "workspace": { + "repos": { + "title": "すべての repo で agent を実行する", + "body": "ここの agent は選んだ任意のフォルダーで実行されます。サービスの 1 つ上のディレクトリを指定すれば、すべての repo をまとめて扱えます。" + }, + "scratchpad": { + "title": "スクラッチパッドとしても使える", + "body": "集中しているワークツリーを散らかさずに、agent、一時的な Terminal、ノート、ブラウザータブを開けます。" + } + } + } } } } diff --git a/src/renderer/src/i18n/locales/ko.json b/src/renderer/src/i18n/locales/ko.json index bb5bbc4b4da9..f1fd050068f3 100644 --- a/src/renderer/src/i18n/locales/ko.json +++ b/src/renderer/src/i18n/locales/ko.json @@ -13329,6 +13329,89 @@ } } } + }, + "step": { + "copy": { + "workspace": { + "board": { + "plan": { + "title": "보드에서 작업 계획하기", + "body": "프로젝트별이 아니라 상태별로 워크스페이스를 보고 싶을 때 보드를 사용하세요." + }, + "lanes": { + "title": "레인을 따라 작업 옮기기", + "body": "상태가 바뀌면 워크스페이스를 레인 사이로 끌어다 놓으세요." + } + }, + "creation": { + "project": { + "title": "프로젝트 선택", + "body": "Orca는 각 작업을 기준 브랜치에서 분기한 자체 워크트리로 분리합니다." + }, + "name": { + "title": "이름을 정하거나 기존 작업에서 시작하기", + "body": "연결된 작업에서 시작하면 짧은 이슈나 PR 이름을 사용합니다. 비워 두면 첫 agent 메시지에서 이름이 자동으로 지정됩니다." + }, + "agent": { + "title": "작업을 시작할 agent 선택", + "body": "이 워크트리가 생성될 때 열릴 agent를 선택하세요." + } + } + }, + "agent": { + "sessions": { + "split": { + "title": "Terminal 창 분할", + "body": "{terminal.splitRight} 키로 두 번째 Terminal 창을 열거나, 창을 우클릭해 분할 옵션을 확인하세요.", + "action": "Terminal 분할" + }, + "parallel": { + "title": "다른 작업을 병렬로 시작하기", + "body": "워크트리마다 자체 브랜치를 가지므로 병렬로 진행하는 작업이 서로 섞이지 않습니다." + } + } + }, + "browser": { + "grab": { + "title": "agent를 위한 페이지 컨텍스트 가져오기", + "body": "grab 도구로 페이지 요소의 컨텍스트를 복사해 agent에 전달하세요." + }, + "annotate": { + "title": "디자인 피드백을 화면에 바로 남기기", + "body": "요소에 주석을 달고 그 메모를 agent에 보내세요." + }, + "logins": { + "title": "로그인 상태 유지", + "body": "기존 로그인 정보를 Orca로 가져와 바로 로그인 상태를 유지하세요." + } + }, + "tasks": { + "source": { + "title": "작업 소스 선택", + "body": "페이지를 이동하지 않고 연결된 제공자와 프로젝트 필터를 전환하세요." + }, + "filter": { + "title": "필요한 작업만 필터링하기", + "body": "프리셋과 검색으로 이슈, 리뷰, merge requests, 작업의 범위를 좁히세요." + }, + "start": { + "title": "작업 항목에서 시작하기", + "body": "작업, 이슈, 리뷰, merge request에서 시작 또는 열기를 눌러 해당 컨텍스트를 워크스페이스로 가져오세요." + } + }, + "floating": { + "workspace": { + "repos": { + "title": "agent 하나로 모든 repo 다루기", + "body": "이곳의 agent는 선택한 어떤 폴더에서도 실행됩니다. 서비스들의 상위 디렉터리를 지정하면 모든 repo에서 한 번에 작업할 수 있습니다." + }, + "scratchpad": { + "title": "메모장처럼 사용하기", + "body": "집중하고 있는 워크트리를 어지럽히지 않고 agent, 임시 Terminal, 노트, 브라우저 탭을 열 수 있습니다." + } + } + } + } } } } diff --git a/src/renderer/src/i18n/locales/zh.json b/src/renderer/src/i18n/locales/zh.json index e7529643e5e2..9636cfb6671c 100644 --- a/src/renderer/src/i18n/locales/zh.json +++ b/src/renderer/src/i18n/locales/zh.json @@ -13326,7 +13326,8 @@ "4a9568f773": "返回", "4f86e2a10b": "跳过导览", "d974f32a83": "关闭导览", - "ffa4412b66": "下一步" + "ffa4412b66": "下一步", + "complete": "完成" }, "ContextualTourProgressDots": { "7734cb8ad3": "的", @@ -13336,7 +13337,100 @@ "tour": { "overlay": { "measurement": { - "38b3155418": "下一步" + "38b3155418": "下一步", + "automations": { + "intro": { + "title": "什么是自动化?", + "body": "自动化会按计划运行智能体任务。点击此按钮添加自动化。" + }, + "results": { + "title": "查看运行结果", + "body": "运行记录会显示自动化何时运行、发生了什么,以及在哪里查看输出。" + } + } + } + }, + "step": { + "copy": { + "workspace": { + "board": { + "plan": { + "title": "在看板中规划工作", + "body": "想按状态而不是按项目查看工作区时,请使用看板。" + }, + "lanes": { + "title": "在泳道之间移动工作", + "body": "状态变化时,把工作区拖到相应的泳道。" + } + }, + "creation": { + "project": { + "title": "选择项目", + "body": "Orca 会把每个任务隔离到基于基础分支创建的独立工作树中。" + }, + "name": { + "title": "命名,或从已有工作开始", + "body": "从关联的任务开始可获得简短的 issue 或 PR 名称。留空则会根据你的第一条智能体消息自动命名。" + }, + "agent": { + "title": "选择由哪个智能体开始工作", + "body": "选择创建此工作树时要打开的智能体。" + } + } + }, + "agent": { + "sessions": { + "split": { + "title": "拆分终端窗格", + "body": "使用 {terminal.splitRight} 打开第二个终端窗格,或右键点击窗格查看拆分选项。", + "action": "拆分终端" + }, + "parallel": { + "title": "并行开始另一个任务", + "body": "每个工作树都有自己的分支,因此并行进行的工作互不干扰。" + } + } + }, + "browser": { + "grab": { + "title": "为智能体抓取页面上下文", + "body": "使用抓取工具复制页面元素的上下文,供智能体使用。" + }, + "annotate": { + "title": "就地标注设计反馈", + "body": "为元素添加批注,并把这些备注发送给智能体。" + }, + "logins": { + "title": "保持登录状态", + "body": "把现有登录信息导入 Orca,立即保持登录状态。" + } + }, + "tasks": { + "source": { + "title": "选择工作来源", + "body": "无需切换页面即可在已连接的提供方和项目筛选之间切换。" + }, + "filter": { + "title": "筛选出你需要的工作", + "body": "使用预设和搜索来缩小 issues、评审、merge requests 或任务的范围。" + }, + "start": { + "title": "从工作项开始", + "body": "在任务、issue、评审或 merge request 上点击开始或打开,即可把其上下文带入工作区。" + } + }, + "floating": { + "workspace": { + "repos": { + "title": "在所有存储库中运行智能体", + "body": "这里的智能体可在你选择的任意文件夹中运行。把它指向服务所在目录的上一级,即可一次性处理所有存储库。" + }, + "scratchpad": { + "title": "也可当作草稿区使用", + "body": "打开智能体、临时终端、笔记和浏览器标签页,同时不会弄乱你正在专注的工作树。" + } + } + } } } } diff --git a/src/shared/contextual-tours.ts b/src/shared/contextual-tours.ts index 623a0bbd6ec8..c33f806ad3f4 100644 --- a/src/shared/contextual-tours.ts +++ b/src/shared/contextual-tours.ts @@ -31,7 +31,7 @@ export type ContextualTourStepPlacement = 'top' | 'right' | 'bottom' | 'left' export type ContextualTourStep = { // Stable anchor for localized copy — position-keyed translations shift onto the wrong step when one is inserted. - id?: string + id: string title: string body: string targetSelector: string @@ -57,6 +57,7 @@ export const CONTEXTUAL_TOURS = [ id: 'workspace-board', steps: [ { + id: 'workspace-board-plan', title: 'Plan work on the board', body: 'Use the board when you want to see workspaces by status instead of by project.', targetSelector: '[data-contextual-tour-target="workspace-board-center"]', @@ -64,6 +65,7 @@ export const CONTEXTUAL_TOURS = [ preferredPlacement: 'bottom' }, { + id: 'workspace-board-lanes', title: 'Move work through lanes', body: 'Drag workspaces between lanes as their status changes.', targetSelector: @@ -75,6 +77,7 @@ export const CONTEXTUAL_TOURS = [ id: 'workspace-agent-sessions', steps: [ { + id: 'agent-sessions-split', title: 'Split a terminal pane', body: 'Open a second terminal pane with {terminal.splitRight}, or right-click the pane for split options.', targetSelector: @@ -85,6 +88,7 @@ export const CONTEXTUAL_TOURS = [ advanceOnFeatureInteraction: 'terminal-pane-split' }, { + id: 'agent-sessions-parallel', title: 'Start another task in parallel', body: 'Each worktree gets its own branch, so parallel work stays separate.', targetSelector: '[data-contextual-tour-target="workspace-create-control"]', @@ -98,6 +102,7 @@ export const CONTEXTUAL_TOURS = [ id: 'browser', steps: [ { + id: 'browser-grab', title: 'Grab page context for agents', body: "Use the grab tool to copy a page element's context for agents.", targetSelector: '[data-contextual-tour-target="browser-grab-control"]', @@ -105,12 +110,14 @@ export const CONTEXTUAL_TOURS = [ preferredPlacement: 'bottom' }, { + id: 'browser-annotate', title: 'Mark design feedback in place', body: 'Annotate elements and send those notes to an agent.', targetSelector: '[data-contextual-tour-target="browser-annotation-control"]', preferredPlacement: 'bottom' }, { + id: 'browser-logins', title: 'Stay logged in', body: 'Bring your existing logins into Orca to stay signed in immediately.', // Prefer the always-visible Import button; fall back to the overflow-menu @@ -126,17 +133,20 @@ export const CONTEXTUAL_TOURS = [ id: 'tasks', steps: [ { + id: 'tasks-source', title: 'Choose the work source', body: 'Switch between connected providers and project filters without changing pages.', targetSelector: '[data-contextual-tour-target="tasks-source-filters"]', requiredForStart: true }, { + id: 'tasks-filter', title: 'Filter to the work you need', body: 'Use presets and search to narrow issues, reviews, merge requests, or tasks.', targetSelector: '[data-contextual-tour-target="tasks-search-presets"]' }, { + id: 'tasks-start', title: 'Start from work items', body: 'Use Start or Open on a task, issue, review, or merge request to bring its context into a workspace.', targetSelector: @@ -166,6 +176,7 @@ export const CONTEXTUAL_TOURS = [ id: 'floating-workspace', steps: [ { + id: 'floating-workspace-repos', title: 'Run an agent across every repo', body: 'Agents here run in any folder you choose. Point one at the directory above your services to work across all your repos at once.', // Why: the per-action anchors only render in the empty state; fall back @@ -176,6 +187,7 @@ export const CONTEXTUAL_TOURS = [ preferredPlacement: 'left' }, { + id: 'floating-workspace-scratchpad', title: 'Or use it as a scratchpad', body: 'Open agents, scratch terminals, notes, and browser tabs without cluttering the worktree you’re focused on.', targetSelector: @@ -189,18 +201,21 @@ export const CONTEXTUAL_TOURS = [ allowedActiveModals: ['new-workspace-composer'], steps: [ { + id: 'workspace-creation-project', title: 'Pick a project', body: 'Orca isolates each task in its own worktree, branched off your base.', targetSelector: '[data-contextual-tour-target="workspace-creation-project"]', requiredForStart: true }, { + id: 'workspace-creation-name', title: 'Name it, or start from existing work', body: 'Start from a linked task for a short issue or PR name. Or leave it blank to auto-name it from your first agent message.', targetSelector: '[data-contextual-tour-target="workspace-creation-name"]', control: { kind: 'auto-rename-branch-from-work' } }, { + id: 'workspace-creation-agent', title: 'Choose what agent starts the work', body: 'Pick the agent that should be opened when this worktree is created.', targetSelector: '[data-contextual-tour-target="workspace-creation-agent"]'