From e656ea555c7f22e6c1480518a31f4f67c0d98a9b Mon Sep 17 00:00:00 2001 From: daidaidaiok Date: Fri, 6 Mar 2026 13:43:29 +0800 Subject: [PATCH 1/2] feat(i18n): add Simplified Chinese (zh) locale and extract GitHub/GitLab issue strings - Add complete zh locale with 11 namespace files (common, navigation, settings, tasks, welcome, onboarding, dialogs, gitlab, taskReview, terminal, errors) - Extract hardcoded strings from GitHub/GitLab issue components into i18n translation keys - Add corresponding en/fr translations for newly extracted strings - Register zh language in i18n config, spellcheck mapping, and language selector - Add locale-coverage test to verify key alignment and placeholder consistency across locales - Separate issue state badge labels from filter labels for correct singular/plural translations Co-Authored-By: Claude Opus 4.6 --- .../src/renderer/components/GitHubIssues.tsx | 4 +- .../github-issues/components/EmptyStates.tsx | 11 +- .../components/InvestigationDialog.tsx | 34 +- .../github-issues/components/IssueDetail.tsx | 20 +- .../github-issues/components/IssueList.tsx | 2 +- .../components/IssueListHeader.tsx | 22 +- .../components/IssueListItem.tsx | 5 +- .../components/InvestigationDialog.tsx | 2 +- .../gitlab-issues/components/IssueList.tsx | 4 +- .../components/IssueListItem.tsx | 6 +- apps/frontend/src/shared/constants/i18n.ts | 5 +- .../src/shared/constants/spellcheck.ts | 2 + apps/frontend/src/shared/i18n/index.ts | 25 + .../src/shared/i18n/locale-coverage.test.ts | 148 +++ .../src/shared/i18n/locales/en/common.json | 44 + .../src/shared/i18n/locales/en/gitlab.json | 6 +- .../src/shared/i18n/locales/fr/common.json | 44 + .../src/shared/i18n/locales/fr/gitlab.json | 6 +- .../src/shared/i18n/locales/zh/common.json | 871 +++++++++++++++++ .../src/shared/i18n/locales/zh/dialogs.json | 234 +++++ .../src/shared/i18n/locales/zh/errors.json | 9 + .../src/shared/i18n/locales/zh/gitlab.json | 212 ++++ .../shared/i18n/locales/zh/navigation.json | 87 ++ .../shared/i18n/locales/zh/onboarding.json | 253 +++++ .../src/shared/i18n/locales/zh/settings.json | 905 ++++++++++++++++++ .../shared/i18n/locales/zh/taskReview.json | 136 +++ .../src/shared/i18n/locales/zh/tasks.json | 353 +++++++ .../src/shared/i18n/locales/zh/terminal.json | 58 ++ .../src/shared/i18n/locales/zh/welcome.json | 17 + 29 files changed, 3473 insertions(+), 52 deletions(-) create mode 100644 apps/frontend/src/shared/i18n/locale-coverage.test.ts create mode 100644 apps/frontend/src/shared/i18n/locales/zh/common.json create mode 100644 apps/frontend/src/shared/i18n/locales/zh/dialogs.json create mode 100644 apps/frontend/src/shared/i18n/locales/zh/errors.json create mode 100644 apps/frontend/src/shared/i18n/locales/zh/gitlab.json create mode 100644 apps/frontend/src/shared/i18n/locales/zh/navigation.json create mode 100644 apps/frontend/src/shared/i18n/locales/zh/onboarding.json create mode 100644 apps/frontend/src/shared/i18n/locales/zh/settings.json create mode 100644 apps/frontend/src/shared/i18n/locales/zh/taskReview.json create mode 100644 apps/frontend/src/shared/i18n/locales/zh/tasks.json create mode 100644 apps/frontend/src/shared/i18n/locales/zh/terminal.json create mode 100644 apps/frontend/src/shared/i18n/locales/zh/welcome.json diff --git a/apps/frontend/src/renderer/components/GitHubIssues.tsx b/apps/frontend/src/renderer/components/GitHubIssues.tsx index 410b60d485..1766f0d858 100644 --- a/apps/frontend/src/renderer/components/GitHubIssues.tsx +++ b/apps/frontend/src/renderer/components/GitHubIssues.tsx @@ -1,4 +1,5 @@ import { useState, useCallback, useMemo, useEffect } from "react"; +import { useTranslation } from "react-i18next"; import { useProjectStore } from "../stores/project-store"; import { useTaskStore } from "../stores/task-store"; import { @@ -22,6 +23,7 @@ import type { GitHubIssue } from "../../shared/types"; import type { GitHubIssuesProps } from "./github-issues/types"; export function GitHubIssues({ onOpenSettings, onNavigateToTask }: GitHubIssuesProps) { + const { t } = useTranslation(); const projects = useProjectStore((state) => state.projects); const selectedProjectId = useProjectStore((state) => state.selectedProjectId); const selectedProject = projects.find((p) => p.id === selectedProjectId); @@ -197,7 +199,7 @@ export function GitHubIssues({ onOpenSettings, onNavigateToTask }: GitHubIssuesP autoFixQueueItem={getAutoFixQueueItem(selectedIssue.number)} /> ) : ( - + )} diff --git a/apps/frontend/src/renderer/components/github-issues/components/EmptyStates.tsx b/apps/frontend/src/renderer/components/github-issues/components/EmptyStates.tsx index ca2f182eae..9b9f1beb7e 100644 --- a/apps/frontend/src/renderer/components/github-issues/components/EmptyStates.tsx +++ b/apps/frontend/src/renderer/components/github-issues/components/EmptyStates.tsx @@ -1,36 +1,39 @@ import { Github, Settings2 } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { Button } from '../../ui/button'; import type { EmptyStateProps, NotConnectedStateProps } from '../types'; export function EmptyState({ searchQuery, icon: Icon = Github, message }: EmptyStateProps) { + const { t } = useTranslation('common'); return (

- {searchQuery ? 'No issues match your search' : message} + {searchQuery ? t('issues.noMatch') : message}

); } export function NotConnectedState({ error, onOpenSettings }: NotConnectedStateProps) { + const { t } = useTranslation('common'); return (

- GitHub Not Connected + {t('issues.notConnectedTitle')}

- {error || 'Configure your GitHub token and repository in project settings to sync issues.'} + {error || t('issues.notConnectedDescription')}

{onOpenSettings && ( )}
diff --git a/apps/frontend/src/renderer/components/github-issues/components/InvestigationDialog.tsx b/apps/frontend/src/renderer/components/github-issues/components/InvestigationDialog.tsx index 05b5456a21..0949a50351 100644 --- a/apps/frontend/src/renderer/components/github-issues/components/InvestigationDialog.tsx +++ b/apps/frontend/src/renderer/components/github-issues/components/InvestigationDialog.tsx @@ -1,4 +1,5 @@ import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Sparkles, Loader2, CheckCircle2, MessageCircle } from 'lucide-react'; import { Button } from '../../ui/button'; import { Progress } from '../../ui/progress'; @@ -32,6 +33,7 @@ export function InvestigationDialog({ onClose, projectId }: InvestigationDialogProps) { + const { t } = useTranslation('common'); const [comments, setComments] = useState([]); const [selectedCommentIds, setSelectedCommentIds] = useState([]); const [loadingComments, setLoadingComments] = useState(false); @@ -60,7 +62,7 @@ export function InvestigationDialog({ if (!isMounted) return; console.error('Failed to fetch comments:', err); setFetchCommentsError( - err instanceof Error ? err.message : 'Failed to load comments' + err instanceof Error ? err.message : t('issues.investigation.failedToLoadComments') ); }) .finally(() => { @@ -101,7 +103,7 @@ export function InvestigationDialog({ - Create Task from Issue + {t('issues.investigation.title')} {selectedIssue && ( @@ -115,7 +117,7 @@ export function InvestigationDialog({ {investigationStatus.phase === 'idle' ? (

- Create a task from this GitHub issue. The task will be added to your Kanban board in the Backlog column. + {t('issues.investigation.description')}

{/* Comments section */} @@ -125,7 +127,7 @@ export function InvestigationDialog({
) : fetchCommentsError ? (
-

Failed to load comments

+

{t('issues.investigation.failedToLoadComments')}

{fetchCommentsError}

) : comments.length > 0 ? ( @@ -133,7 +135,7 @@ export function InvestigationDialog({

- Select Comments to Include ({selectedCommentIds.length}/{comments.length}) + {t('issues.investigation.selectComments', { selected: selectedCommentIds.length, total: comments.length })}

) : (
-

The task will include:

+

{t('issues.investigation.willInclude')}

    -
  • • Issue title and description
  • -
  • • Link back to the GitHub issue
  • -
  • • Labels and metadata from the issue
  • -
  • • No comments (this issue has no comments)
  • +
  • • {t('issues.investigation.includeTitle')}
  • +
  • • {t('issues.investigation.includeLink')}
  • +
  • • {t('issues.investigation.includeLabels')}
  • +
  • • {t('issues.investigation.noComments')}
)} @@ -206,7 +208,7 @@ export function InvestigationDialog({ {investigationStatus.phase === 'complete' && (
- Task created! View it in your Kanban board. + {t('issues.investigation.taskCreated')}
)} @@ -216,23 +218,23 @@ export function InvestigationDialog({ {investigationStatus.phase === 'idle' && ( <> )} {investigationStatus.phase !== 'idle' && investigationStatus.phase !== 'complete' && ( )} {investigationStatus.phase === 'complete' && ( )} diff --git a/apps/frontend/src/renderer/components/github-issues/components/IssueDetail.tsx b/apps/frontend/src/renderer/components/github-issues/components/IssueDetail.tsx index 5e511270b8..e96abcad59 100644 --- a/apps/frontend/src/renderer/components/github-issues/components/IssueDetail.tsx +++ b/apps/frontend/src/renderer/components/github-issues/components/IssueDetail.tsx @@ -75,7 +75,7 @@ export function IssueDetail({ {issue.commentsCount > 0 && (
- {issue.commentsCount} comments + {t('issues.commentsCount', { count: issue.commentsCount })}
)} @@ -104,13 +104,13 @@ export function IssueDetail({ {hasLinkedTask ? ( ) : ( <> {projectId && autoFixConfig?.enabled && ( - Task Linked + {t('issues.taskLinked')} @@ -142,14 +142,14 @@ export function IssueDetail({ {investigationResult.analysis.estimatedComplexity} - Task ID: {taskId} + {t('issues.taskId')}: {taskId} ) : (
- Task ID: {taskId} + {t('issues.taskId')}: {taskId}
)} @@ -160,7 +160,7 @@ export function IssueDetail({ {/* Body */} - Description + {t('issues.description')} {issue.body ? ( @@ -169,7 +169,7 @@ export function IssueDetail({ ) : (

- No description provided. + {t('issues.noDescription')}

)}
@@ -179,7 +179,7 @@ export function IssueDetail({ {issue.assignees.length > 0 && ( - Assignees + {t('issues.assignees')}
@@ -198,7 +198,7 @@ export function IssueDetail({ {issue.milestone && ( - Milestone + {t('issues.milestone')} {issue.milestone.title} diff --git a/apps/frontend/src/renderer/components/github-issues/components/IssueList.tsx b/apps/frontend/src/renderer/components/github-issues/components/IssueList.tsx index d6586889cb..4f78a892ed 100644 --- a/apps/frontend/src/renderer/components/github-issues/components/IssueList.tsx +++ b/apps/frontend/src/renderer/components/github-issues/components/IssueList.tsx @@ -71,7 +71,7 @@ export function IssueList({ } if (issues.length === 0) { - return ; + return ; } return ( diff --git a/apps/frontend/src/renderer/components/github-issues/components/IssueListHeader.tsx b/apps/frontend/src/renderer/components/github-issues/components/IssueListHeader.tsx index 10a28ee527..42a4d00086 100644 --- a/apps/frontend/src/renderer/components/github-issues/components/IssueListHeader.tsx +++ b/apps/frontend/src/renderer/components/github-issues/components/IssueListHeader.tsx @@ -47,7 +47,7 @@ export function IssueListHeader({

- GitHub Issues + {t('issues.githubTitle')}

{repoFullName} @@ -56,7 +56,7 @@ export function IssueListHeader({

- {openIssuesCount} open + {t('issues.openCount', { count: openIssuesCount })} -

Analyze up to 200 open issues, group similar ones, and review proposed batches before creating tasks.

+

{t('issues.analyzeGroupTip')}

@@ -112,7 +112,7 @@ export function IssueListHeader({ )} -

Automatically fix new issues as they come in.

+

{t('issues.autoFixTip')}

{autoFixRunning && autoFixProcessing !== undefined && autoFixProcessing > 0 && ( -

Processing {autoFixProcessing} issue{autoFixProcessing > 1 ? 's' : ''}...

+

{t('issues.autoFixProcessing', { count: autoFixProcessing })}

)}
@@ -139,7 +139,7 @@ export function IssueListHeader({
onSearchChange(e.target.value)} className="pl-9" @@ -151,9 +151,9 @@ export function IssueListHeader({ - Open - Closed - All + {t('issues.filterOpen')} + {t('issues.filterClosed')} + {t('issues.filterAll')}
diff --git a/apps/frontend/src/renderer/components/github-issues/components/IssueListItem.tsx b/apps/frontend/src/renderer/components/github-issues/components/IssueListItem.tsx index 41aef5d11a..b3f515c3ad 100644 --- a/apps/frontend/src/renderer/components/github-issues/components/IssueListItem.tsx +++ b/apps/frontend/src/renderer/components/github-issues/components/IssueListItem.tsx @@ -1,4 +1,5 @@ import { User, MessageCircle, Tag, Sparkles } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { Badge } from '../../ui/badge'; import { Button } from '../../ui/button'; import { @@ -8,6 +9,7 @@ import { import type { IssueListItemProps } from '../types'; export function IssueListItem({ issue, isSelected, onClick, onInvestigate }: IssueListItemProps) { + const { t } = useTranslation('common'); return (
- {GITHUB_ISSUE_STATE_LABELS[issue.state]} + {issue.state === 'open' ? t('issues.stateOpen') : issue.state === 'closed' ? t('issues.stateClosed') : (GITHUB_ISSUE_STATE_LABELS[issue.state] ?? issue.state)} #{issue.number}
@@ -58,6 +60,7 @@ export function IssueListItem({ issue, isSelected, onClick, onInvestigate }: Iss e.stopPropagation(); onInvestigate(); }} + aria-label={t('issues.createTask')} > diff --git a/apps/frontend/src/renderer/components/gitlab-issues/components/InvestigationDialog.tsx b/apps/frontend/src/renderer/components/gitlab-issues/components/InvestigationDialog.tsx index 534d37a46c..2d4a9ff1bf 100644 --- a/apps/frontend/src/renderer/components/gitlab-issues/components/InvestigationDialog.tsx +++ b/apps/frontend/src/renderer/components/gitlab-issues/components/InvestigationDialog.tsx @@ -57,7 +57,7 @@ export function InvestigationDialog({ if (!isMounted) return; console.error('Failed to fetch notes:', err); setFetchNotesError( - err instanceof Error ? err.message : 'Failed to load notes' + err instanceof Error ? err.message : t('investigation.failedToLoadNotes') ); }) .finally(() => { diff --git a/apps/frontend/src/renderer/components/gitlab-issues/components/IssueList.tsx b/apps/frontend/src/renderer/components/gitlab-issues/components/IssueList.tsx index 397705df09..bba050094d 100644 --- a/apps/frontend/src/renderer/components/gitlab-issues/components/IssueList.tsx +++ b/apps/frontend/src/renderer/components/gitlab-issues/components/IssueList.tsx @@ -1,4 +1,5 @@ import { Loader2, AlertCircle } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { ScrollArea } from '../../ui/scroll-area'; import { IssueListItem } from './IssueListItem'; import { EmptyState } from './EmptyStates'; @@ -12,6 +13,7 @@ export function IssueList({ onSelectIssue, onInvestigate }: IssueListProps) { + const { t } = useTranslation('gitlab'); if (error) { return (
@@ -32,7 +34,7 @@ export function IssueList({ } if (issues.length === 0) { - return ; + return ; } return ( diff --git a/apps/frontend/src/renderer/components/gitlab-issues/components/IssueListItem.tsx b/apps/frontend/src/renderer/components/gitlab-issues/components/IssueListItem.tsx index 57d1eac9d1..5304aa36bc 100644 --- a/apps/frontend/src/renderer/components/gitlab-issues/components/IssueListItem.tsx +++ b/apps/frontend/src/renderer/components/gitlab-issues/components/IssueListItem.tsx @@ -1,4 +1,5 @@ import { User, MessageCircle, Tag, Sparkles } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { Badge } from '../../ui/badge'; import { Button } from '../../ui/button'; import type { IssueListItemProps } from '../types'; @@ -15,6 +16,7 @@ const GITLAB_ISSUE_STATE_LABELS: Record = { }; export function IssueListItem({ issue, isSelected, onClick, onInvestigate }: IssueListItemProps) { + const { t } = useTranslation('gitlab'); return (
- {GITLAB_ISSUE_STATE_LABELS[issue.state] || issue.state} + {issue.state === 'opened' ? t('states.opened') : issue.state === 'closed' ? t('states.closed') : (GITLAB_ISSUE_STATE_LABELS[issue.state] || issue.state)} #{issue.iid}
@@ -73,7 +75,7 @@ export function IssueListItem({ issue, isSelected, onClick, onInvestigate }: Iss e.stopPropagation(); onInvestigate(); }} - aria-label="Investigate issue" + aria-label={t('accessibility.investigateIssueAriaLabel')} > diff --git a/apps/frontend/src/shared/constants/i18n.ts b/apps/frontend/src/shared/constants/i18n.ts index 5f4ebbde38..feeca467bf 100644 --- a/apps/frontend/src/shared/constants/i18n.ts +++ b/apps/frontend/src/shared/constants/i18n.ts @@ -3,11 +3,12 @@ * Available languages and display labels */ -export type SupportedLanguage = 'en' | 'fr'; +export type SupportedLanguage = 'en' | 'fr' | 'zh'; export const AVAILABLE_LANGUAGES = [ { value: 'en' as const, label: 'English', nativeLabel: 'English' }, - { value: 'fr' as const, label: 'French', nativeLabel: 'Français' } + { value: 'fr' as const, label: 'French', nativeLabel: 'Français' }, + { value: 'zh' as const, label: 'Chinese', nativeLabel: '简体中文' } ] as const; export const DEFAULT_LANGUAGE: SupportedLanguage = 'en'; diff --git a/apps/frontend/src/shared/constants/spellcheck.ts b/apps/frontend/src/shared/constants/spellcheck.ts index 8e32a3c0f3..bab0558b30 100644 --- a/apps/frontend/src/shared/constants/spellcheck.ts +++ b/apps/frontend/src/shared/constants/spellcheck.ts @@ -13,6 +13,7 @@ export const SPELL_CHECK_LANGUAGE_MAP: Record = { en: ['en-US', 'en-GB'], fr: ['fr-FR', 'fr'], + zh: ['zh-CN', 'zh-Hans-CN', 'zh-Hans'], }; /** @@ -27,4 +28,5 @@ export const DEFAULT_SPELL_CHECK_LANGUAGE = 'en-US'; export const ADD_TO_DICTIONARY_LABELS: Record = { en: 'Add to Dictionary', fr: 'Ajouter au dictionnaire', + zh: '添加到词典', }; diff --git a/apps/frontend/src/shared/i18n/index.ts b/apps/frontend/src/shared/i18n/index.ts index 095b0b1188..3e30bea5c0 100644 --- a/apps/frontend/src/shared/i18n/index.ts +++ b/apps/frontend/src/shared/i18n/index.ts @@ -27,6 +27,18 @@ import frTaskReview from './locales/fr/taskReview.json'; import frTerminal from './locales/fr/terminal.json'; import frErrors from './locales/fr/errors.json'; +import zhCommon from './locales/zh/common.json'; +import zhNavigation from './locales/zh/navigation.json'; +import zhSettings from './locales/zh/settings.json'; +import zhTasks from './locales/zh/tasks.json'; +import zhWelcome from './locales/zh/welcome.json'; +import zhOnboarding from './locales/zh/onboarding.json'; +import zhDialogs from './locales/zh/dialogs.json'; +import zhGitlab from './locales/zh/gitlab.json'; +import zhTaskReview from './locales/zh/taskReview.json'; +import zhTerminal from './locales/zh/terminal.json'; +import zhErrors from './locales/zh/errors.json'; + export const defaultNS = 'common'; export const resources = { @@ -55,6 +67,19 @@ export const resources = { taskReview: frTaskReview, terminal: frTerminal, errors: frErrors + }, + zh: { + common: zhCommon, + navigation: zhNavigation, + settings: zhSettings, + tasks: zhTasks, + welcome: zhWelcome, + onboarding: zhOnboarding, + dialogs: zhDialogs, + gitlab: zhGitlab, + taskReview: zhTaskReview, + terminal: zhTerminal, + errors: zhErrors } } as const; diff --git a/apps/frontend/src/shared/i18n/locale-coverage.test.ts b/apps/frontend/src/shared/i18n/locale-coverage.test.ts new file mode 100644 index 0000000000..f178a7e5e0 --- /dev/null +++ b/apps/frontend/src/shared/i18n/locale-coverage.test.ts @@ -0,0 +1,148 @@ +import { describe, expect, it } from 'vitest'; +import enCommon from './locales/en/common.json'; +import enDialogs from './locales/en/dialogs.json'; +import enErrors from './locales/en/errors.json'; +import enGitlab from './locales/en/gitlab.json'; +import enNavigation from './locales/en/navigation.json'; +import enOnboarding from './locales/en/onboarding.json'; +import enSettings from './locales/en/settings.json'; +import enTaskReview from './locales/en/taskReview.json'; +import enTasks from './locales/en/tasks.json'; +import enTerminal from './locales/en/terminal.json'; +import enWelcome from './locales/en/welcome.json'; +import frCommon from './locales/fr/common.json'; +import frDialogs from './locales/fr/dialogs.json'; +import frErrors from './locales/fr/errors.json'; +import frGitlab from './locales/fr/gitlab.json'; +import frNavigation from './locales/fr/navigation.json'; +import frOnboarding from './locales/fr/onboarding.json'; +import frSettings from './locales/fr/settings.json'; +import frTaskReview from './locales/fr/taskReview.json'; +import frTasks from './locales/fr/tasks.json'; +import frTerminal from './locales/fr/terminal.json'; +import frWelcome from './locales/fr/welcome.json'; +import zhCommon from './locales/zh/common.json'; +import zhDialogs from './locales/zh/dialogs.json'; +import zhErrors from './locales/zh/errors.json'; +import zhGitlab from './locales/zh/gitlab.json'; +import zhNavigation from './locales/zh/navigation.json'; +import zhOnboarding from './locales/zh/onboarding.json'; +import zhSettings from './locales/zh/settings.json'; +import zhTaskReview from './locales/zh/taskReview.json'; +import zhTasks from './locales/zh/tasks.json'; +import zhTerminal from './locales/zh/terminal.json'; +import zhWelcome from './locales/zh/welcome.json'; + +const enLocales = { + common: enCommon, + dialogs: enDialogs, + errors: enErrors, + gitlab: enGitlab, + navigation: enNavigation, + onboarding: enOnboarding, + settings: enSettings, + taskReview: enTaskReview, + tasks: enTasks, + terminal: enTerminal, + welcome: enWelcome +} as const; + +const frLocales = { + common: frCommon, + dialogs: frDialogs, + errors: frErrors, + gitlab: frGitlab, + navigation: frNavigation, + onboarding: frOnboarding, + settings: frSettings, + taskReview: frTaskReview, + tasks: frTasks, + terminal: frTerminal, + welcome: frWelcome +} as const; + +const zhLocales = { + common: zhCommon, + dialogs: zhDialogs, + errors: zhErrors, + gitlab: zhGitlab, + navigation: zhNavigation, + onboarding: zhOnboarding, + settings: zhSettings, + taskReview: zhTaskReview, + tasks: zhTasks, + terminal: zhTerminal, + welcome: zhWelcome +} as const; + +function flattenLeaves(node: unknown, prefix = '', acc: Record = {}) { + if (!node || typeof node !== 'object') { + return acc; + } + for (const [key, value] of Object.entries(node as Record)) { + const path = prefix ? `${prefix}.${key}` : key; + if (typeof value === 'string') { + acc[path] = value; + continue; + } + if (value && typeof value === 'object') { + flattenLeaves(value, path, acc); + } + } + return acc; +} + +function extractPlaceholders(value: string) { + const matches = value.match(/\{\{[^}]+\}\}|<\/?\d+>|`[^`]+`/g) || []; + return [...new Set(matches)].sort(); +} + +describe('locale coverage', () => { + it('keeps zh key coverage aligned with en', () => { + for (const namespace of Object.keys(enLocales) as Array) { + const enFlat = flattenLeaves(enLocales[namespace]); + const zhFlat = flattenLeaves(zhLocales[namespace]); + const missingInZh = Object.keys(enFlat).filter((key) => !(key in zhFlat)); + const extraInZh = Object.keys(zhFlat).filter((key) => !(key in enFlat)); + expect(missingInZh, `${namespace} missing keys in zh`).toEqual([]); + expect(extraInZh, `${namespace} extra keys in zh`).toEqual([]); + } + }); + + it('keeps zh placeholders aligned with en', () => { + for (const namespace of Object.keys(enLocales) as Array) { + const enFlat = flattenLeaves(enLocales[namespace]); + const zhFlat = flattenLeaves(zhLocales[namespace]); + for (const key of Object.keys(enFlat)) { + const enPlaceholders = extractPlaceholders(enFlat[key]); + const zhPlaceholders = extractPlaceholders(zhFlat[key] ?? ''); + expect(zhPlaceholders, `${namespace}.${key} placeholder mismatch`).toEqual(enPlaceholders); + expect(zhFlat[key], `${namespace}.${key} unresolved token`).not.toContain('__TOKEN_'); + } + } + }); + + it('keeps zh translations readable', () => { + for (const namespace of Object.keys(zhLocales) as Array) { + const zhFlat = flattenLeaves(zhLocales[namespace]); + for (const [key, value] of Object.entries(zhFlat)) { + expect(value, `${namespace}.${key} should not be empty`).not.toBe(''); + expect(value, `${namespace}.${key} contains mojibake`).not.toContain('�'); + } + } + }); + + it('reports current en/fr key deltas for audit visibility', () => { + const deltas: string[] = []; + for (const namespace of Object.keys(enLocales) as Array) { + const enFlat = flattenLeaves(enLocales[namespace]); + const frFlat = flattenLeaves(frLocales[namespace]); + const missingInFr = Object.keys(enFlat).filter((key) => !(key in frFlat)); + const extraInFr = Object.keys(frFlat).filter((key) => !(key in enFlat)); + if (missingInFr.length > 0 || extraInFr.length > 0) { + deltas.push(`${namespace}: missing=${missingInFr.length}, extra=${extraInFr.length}`); + } + } + expect(deltas).toEqual(['gitlab: missing=0, extra=8', 'onboarding: missing=10, extra=0']); + }); +}); diff --git a/apps/frontend/src/shared/i18n/locales/en/common.json b/apps/frontend/src/shared/i18n/locales/en/common.json index 6a2f1d84f2..5d43ee56c4 100644 --- a/apps/frontend/src/shared/i18n/locales/en/common.json +++ b/apps/frontend/src/shared/i18n/locales/en/common.json @@ -504,6 +504,50 @@ "conversionErrorDescription": "An error occurred while converting the idea" }, "issues": { + "githubTitle": "GitHub Issues", + "openCount": "{{count}} open", + "searchPlaceholder": "Search issues...", + "filterOpen": "Open", + "filterClosed": "Closed", + "stateOpen": "Open", + "stateClosed": "Closed", + "filterAll": "All", + "analyzeGroup": "Analyze & Group Issues", + "analyzeGroupTip": "Analyze up to 200 open issues, group similar ones, and review proposed batches before creating tasks.", + "autoFixNew": "Auto-Fix New", + "autoFixTip": "Automatically fix new issues as they come in.", + "autoFixProcessing": "Processing {{count}} issue...", + "autoFixProcessing_plural": "Processing {{count}} issues...", + "noMatch": "No issues match your search", + "noIssues": "No issues found", + "selectIssue": "Select an issue to view details", + "notConnectedTitle": "GitHub Not Connected", + "notConnectedDescription": "Configure your GitHub token and repository in project settings to sync issues.", + "openSettings": "Open Settings", + "commentsCount": "{{count}} comments", + "viewTask": "View Task", + "createTask": "Create Task", + "taskLinked": "Task Linked", + "taskId": "Task ID", + "description": "Description", + "noDescription": "No description provided.", + "assignees": "Assignees", + "milestone": "Milestone", + "investigation": { + "title": "Create Task from Issue", + "description": "Create a task from this GitHub issue. The task will be added to your Kanban board in the Backlog column.", + "failedToLoadComments": "Failed to load comments", + "selectComments": "Select Comments to Include ({{selected}}/{{total}})", + "deselectAll": "Deselect All", + "selectAll": "Select All", + "willInclude": "The task will include:", + "includeTitle": "Issue title and description", + "includeLink": "Link back to the GitHub issue", + "includeLabels": "Labels and metadata from the issue", + "noComments": "No comments (this issue has no comments)", + "taskCreated": "Task created! View it in your Kanban board.", + "creating": "Creating..." + }, "loadingMore": "Loading more...", "scrollForMore": "Scroll for more", "allLoaded": "All issues loaded" diff --git a/apps/frontend/src/shared/i18n/locales/en/gitlab.json b/apps/frontend/src/shared/i18n/locales/en/gitlab.json index 90c13ba65a..1b00a04d8d 100644 --- a/apps/frontend/src/shared/i18n/locales/en/gitlab.json +++ b/apps/frontend/src/shared/i18n/locales/en/gitlab.json @@ -20,7 +20,11 @@ }, "empty": { "noMatch": "No issues match your search", - "selectIssue": "Select an issue to view details" + "selectIssue": "Select an issue to view details", + "noIssues": "No issues found" + }, + "accessibility": { + "investigateIssueAriaLabel": "Investigate issue" }, "notConnected": { "title": "GitLab Not Connected", diff --git a/apps/frontend/src/shared/i18n/locales/fr/common.json b/apps/frontend/src/shared/i18n/locales/fr/common.json index 113736f227..c8a1b3eb08 100644 --- a/apps/frontend/src/shared/i18n/locales/fr/common.json +++ b/apps/frontend/src/shared/i18n/locales/fr/common.json @@ -504,6 +504,50 @@ "conversionErrorDescription": "Une erreur s'est produite lors de la conversion de l'idée" }, "issues": { + "githubTitle": "Issues GitHub", + "openCount": "{{count}} ouvertes", + "searchPlaceholder": "Rechercher des issues...", + "filterOpen": "Ouvertes", + "filterClosed": "Fermées", + "stateOpen": "Ouverte", + "stateClosed": "Fermée", + "filterAll": "Toutes", + "analyzeGroup": "Analyser et regrouper les issues", + "analyzeGroupTip": "Analyser jusqu'à 200 issues ouvertes, regrouper les similaires et examiner les lots proposés avant de créer des tâches.", + "autoFixNew": "Auto-corriger les nouvelles", + "autoFixTip": "Corrige automatiquement les nouvelles issues lorsqu'elles arrivent.", + "autoFixProcessing": "Traitement de {{count}} issue...", + "autoFixProcessing_plural": "Traitement de {{count}} issues...", + "noMatch": "Aucune issue ne correspond à votre recherche", + "noIssues": "Aucune issue trouvée", + "selectIssue": "Sélectionnez une issue pour voir les détails", + "notConnectedTitle": "GitHub non connecté", + "notConnectedDescription": "Configurez votre token GitHub et le dépôt dans les paramètres du projet pour synchroniser les issues.", + "openSettings": "Ouvrir les paramètres", + "commentsCount": "{{count}} commentaires", + "viewTask": "Voir la tâche", + "createTask": "Créer une tâche", + "taskLinked": "Tâche liée", + "taskId": "ID de tâche", + "description": "Description", + "noDescription": "Aucune description fournie.", + "assignees": "Assignés", + "milestone": "Jalon", + "investigation": { + "title": "Créer une tâche à partir de l'issue", + "description": "Créez une tâche à partir de cette issue GitHub. La tâche sera ajoutée à votre tableau Kanban dans la colonne Backlog.", + "failedToLoadComments": "Échec du chargement des commentaires", + "selectComments": "Sélectionner les commentaires à inclure ({{selected}}/{{total}})", + "deselectAll": "Tout désélectionner", + "selectAll": "Tout sélectionner", + "willInclude": "La tâche inclura :", + "includeTitle": "Titre et description de l'issue", + "includeLink": "Lien vers l'issue GitHub", + "includeLabels": "Labels et métadonnées de l'issue", + "noComments": "Aucun commentaire (cette issue n'a pas de commentaires)", + "taskCreated": "Tâche créée ! Consultez-la dans votre tableau Kanban.", + "creating": "Création..." + }, "loadingMore": "Chargement...", "scrollForMore": "Défiler pour plus", "allLoaded": "Toutes les issues chargées" diff --git a/apps/frontend/src/shared/i18n/locales/fr/gitlab.json b/apps/frontend/src/shared/i18n/locales/fr/gitlab.json index 6c21cc8c3b..3afb45e2ef 100644 --- a/apps/frontend/src/shared/i18n/locales/fr/gitlab.json +++ b/apps/frontend/src/shared/i18n/locales/fr/gitlab.json @@ -20,7 +20,11 @@ }, "empty": { "noMatch": "Aucune issue ne correspond à votre recherche", - "selectIssue": "Sélectionnez une issue pour voir les détails" + "selectIssue": "Sélectionnez une issue pour voir les détails", + "noIssues": "Aucune issue trouvée" + }, + "accessibility": { + "investigateIssueAriaLabel": "Investiguer l'issue" }, "notConnected": { "title": "GitLab non connecté", diff --git a/apps/frontend/src/shared/i18n/locales/zh/common.json b/apps/frontend/src/shared/i18n/locales/zh/common.json new file mode 100644 index 0000000000..9f14031caf --- /dev/null +++ b/apps/frontend/src/shared/i18n/locales/zh/common.json @@ -0,0 +1,871 @@ +{ + "competitorAnalysis": { + "addCompetitor": "添加竞争对手", + "manualBadge": "手动", + "noCompetitorsYet": "尚未添加竞争对手", + "addCompetitorToStart": "添加竞争对手以开始使用", + "analysisResults": "竞争对手分析结果", + "analysisDescription": "分析 {{count}} 竞争对手以确定市场差距和机会", + "visit": "访问", + "identifiedPainPoints": "已识别的痛点 ({{count}})", + "noPainPointsIdentified": "未发现痛点", + "source": "来源:", + "frequency": "频率:", + "opportunity": "机会:", + "marketInsightsSummary": "市场洞察摘要", + "topPainPoints": "主要痛点:", + "differentiatorOpportunities": "差异化机会:", + "marketTrends": "市场趋势:" + }, + "projectTab": { + "settings": "项目设置", + "showArchived": "显示已存档", + "hideArchived": "隐藏已存档", + "showArchivedTasks": "显示已归档的任务", + "hideArchivedTasks": "隐藏存档任务", + "closeTab": "关闭选项卡", + "closeTabAriaLabel": "关闭选项卡(从应用程序中删除项目)", + "addProjectAriaLabel": "添加项目" + }, + "accessibility": { + "deleteFeatureAriaLabel": "删除功能", + "archiveFeatureAriaLabel": "存档功能", + "closeFeatureDetailsAriaLabel": "关闭功能详情", + "regenerateRoadmapAriaLabel": "重新生成路线图", + "repositoryOwnerAriaLabel": "仓库所有者", + "repositoryVisibilityAriaLabel": "仓库可见性", + "opensInNewWindow": "在新窗口中打开", + "visitExternalLink": "访问{{name}}(在新窗口中打开)", + "upgradeSubscriptionAriaLabel": "升级订阅(在新窗口中打开)", + "learnMoreAriaLabel": "了解更多(在新窗口中打开)", + "toggleFolder": "切换 {{name}} 文件夹", + "expandFolder": "展开 {{name}} 文件夹", + "collapseFolder": "折叠 {{name}} 文件夹", + "newConversationAriaLabel": "新对话", + "saveEditAriaLabel": "保存", + "cancelEditAriaLabel": "取消", + "moreOptionsAriaLabel": "更多选择", + "closePanelAriaLabel": "关闭面板", + "openOnGitHubAriaLabel": "在 GitHub 上打开(在新窗口中打开)", + "openOnGitLabAriaLabel": "在 GitLab 上打开(在新窗口中打开)", + "toggleShowArchivedAriaLabel": "切换显示已归档任务", + "clearSelectionAriaLabel": "清除选择", + "selectAllAriaLabel": "选择全部", + "showDismissedAriaLabel": "显示被忽略", + "hideDismissedAriaLabel": "隐藏被忽略", + "configureAriaLabel": "配置", + "addMoreAriaLabel": "添加更多", + "dismissAllAriaLabel": "忽略所有想法", + "regenerateIdeasAriaLabel": "重新产生想法", + "dismissAriaLabel": "忽略", + "browseFilesAriaLabel": "浏览文件", + "renameAriaLabel": "重命名", + "deleteAriaLabel": "删除", + "refreshAriaLabel": "刷新", + "expandAriaLabel": "展开", + "collapseAriaLabel": "收起", + "selectIdeaAriaLabel": "选择想法:{{title}}", + "convertToTaskAriaLabel": "转换为任务", + "goToTaskAriaLabel": "前往任务", + "reAuthenticateProfileAriaLabel": "重新验证配置文件", + "hideTokenEntryAriaLabel": "隐藏令牌条目", + "enterTokenManuallyAriaLabel": "手动输入令牌", + "renameProfileAriaLabel": "重命名配置文件", + "deleteProfileAriaLabel": "删除配置文件" + }, + "buttons": { + "save": "保存", + "cancel": "取消", + "skip": "跳过", + "next": "下一个", + "back": "后退", + "close": "关闭", + "initialize": "初始化", + "delete": "删除", + "confirm": "确认", + "retry": "重试", + "create": "创建", + "createPR": "创建 PR", + "openPR": "打开 PR", + "open": "打开", + "start": "开始", + "stop": "停止", + "refresh": "刷新", + "refreshing": "刷新中...", + "merge": "合并", + "discard": "丢弃", + "switch": "切换", + "add": "添加", + "apply": "应用", + "gotIt": "知道了", + "continue": "继续", + "saving": "保存...", + "deleting": "正在删除..." + }, + "actions": { + "save": "保存", + "apply": "应用", + "delete": "删除", + "settings": "设置" + }, + "os": { + "windows": "Windows", + "macos": "macOS", + "linux": "Linux", + "unknown": "未知操作系统" + }, + "labels": { + "loading": "加载中...", + "error": "错误", + "success": "成功", + "initializing": "正在初始化...", + "saving": "保存...", + "creating": "创建...", + "noData": "无数据", + "optional": "可选", + "required": "必需的", + "dismiss": "忽略", + "important": "重要的", + "orphaned": "(孤立)" + }, + "selection": { + "select": "选择", + "done": "完成", + "selected": "已选择 {{count}}", + "selectAll": "选择全部", + "clearSelection": "清除选择", + "deleteSelected": "删除所选内容", + "archiveSelected": "存档已选择", + "selectedOfTotal": "已选择 {{total}} 中的 {{selected}}" + }, + "time": { + "justNow": "现在", + "minutesAgo": "{{count}} 分钟前", + "hoursAgo": "{{count}} 小时前", + "daysAgo": "{{count}} 天前" + }, + "errors": { + "generic": "发生错误", + "unknownError": "发生未知错误", + "operationFailed": "操作失败", + "networkError": "网络错误", + "notFound": "未找到", + "unauthorized": "未经授权", + "bulkDeletePartialFailure": "某些工作树无法删除:", + "taskNotFoundForWorktree": "找不到工作树的任务:{{specName}}", + "failedToDeleteTaskWorktree": "无法删除任务工作树:{{specName}}", + "terminalWorktreeNotFound": "未找到终端工作树:{{name}}", + "failedToDeleteTerminalWorktree": "无法删除终端工作树:{{name}}" + }, + "worktrees": { + "deleteSuccess": "工作树“{{branch}}”已成功删除", + "bulkDeleteSuccess": "{{count}} 工作树已成功删除", + "bulkDeleteSuccess_plural": "{{count}} 工作树已成功删除" + }, + "notification": { + "accountSwitched": "账户已切换", + "swapFrom": "切换自", + "swapTo": "到", + "swapReason": "({{reason}} 交换)" + }, + "rateLimit": { + "title": "已达速率限制", + "resetsAt": "重置 {{time}}", + "hitLimit": "{{source}} 达到使用限制", + "clickToManage": "点击管理→", + "modalTitle": "已达到Claude代码使用限制", + "modalDescription": "您已达到此期间的Claude代码使用限制。", + "profile": "配置:{{name}}", + "autoSwitching": "自动切换到 {{name}}", + "autoSwitchingDescription": "Claude将自动使用您的其他帐户重新启动", + "resetsTime": "重置 {{time}}", + "usageRestored": "此时您的使用将恢复", + "switchAccount": "切换Claude账户", + "useAnotherAccount": "使用另一个帐户", + "recommended": "推荐:{{name}} 有更多可用容量。", + "otherSubscriptions": "您配置了其他 Claude 订阅。切换到继续工作:", + "selectAccount": "选择帐户...", + "switching": "切换中...", + "addNewAccount": "添加新帐户...", + "addAnotherSubscription": "添加另一个 Claude 订阅,以便在达到速率限制时自动切换。", + "addAnotherAccount": "添加另一个帐户:", + "connectAccount": "连接Claude帐户:", + "accountNamePlaceholder": "帐户名称(例如工作、个人)", + "willOpenLogin": "这将打开Claude登录以验证新帐户。", + "autoSwitchOnRateLimit": "自动切换速率限制", + "upgradeTitle": "升级以获得更多用途", + "upgradeDescription": "升级您的 Claude 订阅以获得更高的使用限制。", + "upgradeSubscription": "升级订阅", + "sources": { + "changelog": "变更日志", + "task": "任务", + "roadmap": "路线图", + "ideation": "创意", + "titleGenerator": "标题生成器", + "claude": "Claude" + }, + "toast": { + "authenticating": "正在验证“{{profileName}}”", + "checkTerminal": "检查侧栏中的代理终端部分以完成 OAuth 登录。", + "authStartFailed": "启动认证失败", + "addProfileFailed": "添加配置文件失败", + "tryAgain": "请再试一次。" + }, + "sdk": { + "title": "Claude Code 速率限制", + "interrupted": "{{source}} 由于使用限制而被中断。", + "proactiveSwap": "✓ 主动交换", + "reactiveSwap": "⚡ 反应性交换", + "proactiveSwapDesc": "在达到速率限制之前自动从 {{from}} 切换到 {{to}}。", + "reactiveSwapDesc": "{{from}} 达到速率限制。自动切换到{{to}}并重新启动。", + "continueWithoutInterruption": "你的工作继续进行,没有中断。", + "rateLimitReached": "达到速率限制", + "operationStopped": "由于 {{account}} 达到其使用限制,操作已停止。", + "switchBelow": "切换到下面的另一个帐户以继续。", + "addAccountToContinue": "添加另一个 Claude 帐户以继续工作。", + "upgradeToProButton": "升级到专业版以获得更高的限制", + "resetsLabel": "重置 {{time}}", + "weeklyLimit": "每周限制 - 大约一周后重置", + "sessionLimit": "会话限制 - 几小时后重置", + "switchAccountRetry": "切换帐户并重试", + "retrying": "正在重试...", + "retry": "重试", + "autoSwitchRetryLabel": "自动切换并重试速率限制", + "add": "添加", + "whatHappened": "发生了什么:", + "whatHappenedDesc": "由于您的 Claude 帐户 ({{account}}) 达到其使用限制,{{source}} 操作已停止。", + "switchRetryOrAdd": "您可以切换到另一个帐户并重试,或者在上面添加更多帐户。", + "addOrWait": "在上面添加另一个Claude帐户以继续工作,或等待限制重置。", + "close": "关闭" + } + }, + "prReview": { + "reviewing": "审阅", + "reviewed": "已审查", + "approved": "已批准", + "changesRequested": "需要修改", + "commented": "评论过", + "readyForFollowup": "待跟进", + "readyToMerge": "准备合并", + "pendingPost": "待发布", + "posted": "已发布", + "notReviewed": "未审查", + "allStatuses": "所有状态", + "allContributors": "所有贡献者", + "searchPlaceholder": "搜索 PR...", + "contributors": "贡献者", + "contributorsSelected": "贡献者 ({{count}})", + "status": "状态", + "filters": "过滤器", + "clearFilters": "清除", + "clearSearch": "清除搜索", + "searchContributors": "搜索贡献者...", + "selectedCount": "已选择 {{count}}", + "noResultsFound": "没有找到结果", + "reset": "重置", + "sort": { + "label": "排序", + "newest": "最新", + "oldest": "最早的", + "largest": "最大改动" + }, + "pullRequests": "拉取请求", + "open": "打开", + "selectPRToView": "选择拉取请求以查看详细信息", + "loadingPRs": "正在加载拉取请求...", + "noOpenPRs": "没有开放的拉取请求", + "notConnected": "GitHub 未连接", + "connectPrompt": "连接您的 GitHub 帐户以查看和审核拉取请求。", + "openSettings": "打开设置", + "runAIReview": "运行人工智能审查", + "reviewStarted": "审核开始", + "analysisInProgress": "人工智能分析正在进行中...", + "analysisComplete": "分析完成({{count}} 结果)", + "findingsPostedToGitHub": "研究结果发布到 GitHub", + "newCommits": "{{count}} 新提交", + "newCommit": "{{count}} 新提交", + "runFollowup": "运行跟进", + "aiReviewInProgress": "人工智能审查正在进行中", + "waitingForChanges": "等待改变", + "reviewComplete": "审核完成", + "reviewStatus": "审核状态", + "files": "文件", + "filesChanged": "{{count}} 文件已更改", + "clickToViewFiles": "点击查看更改的文件", + "loadingFiles": "正在加载文件...", + "noFilesAvailable": "文件列表不可用", + "posting": "发布...", + "postingApproval": "发布批准...", + "postFindings": "发布 {{count}} 发现", + "postFindings_plural": "发布 {{count}} 调查结果", + "approve": "批准", + "merge": "合并", + "mergeViaGitHub": "通过 GitHub CLI 合并。如果分支保护规则需要额外的审查或检查,则可能会失败。", + "autoApprovePR": "批准PR", + "suggestions": "有 {{count}} 建议", + "postedFindings": "发布 {{count}} 发现", + "postedFindings_plural": "发布了 {{count}} 调查结果", + "resolved": "{{count}} 已解决", + "resolved_plural": "{{count}} 已解决", + "stillOpen": "{{count}} 仍然开放", + "stillOpen_plural": "{{count}} 仍然开放", + "newIssue": "{{count}} 新问题", + "newIssue_plural": "{{count}} 新问题", + "reviewFailed": "审核失败", + "externalReviewDetected": "检测到外部审查", + "reviewStartedExternally": "此评论是从另一个会话开始的", + "description": "描述", + "noDescription": "没有提供描述。", + "followupReviewDetails": "后续审核详情", + "aiAnalysisResults": "人工智能分析结果", + "cancel": "取消", + "previousReview": "之前的审查({{count}} 调查结果)", + "findingsPosted": "{{count}} 已发布", + "followupInProgress": "后续分析正在进行中...", + "severity": { + "critical": "阻断级", + "high": "必须修复", + "medium": "建议修复", + "low": "建议", + "criticalDesc": "必须修复", + "highDesc": "应该修复", + "mediumDesc": "提高质量", + "lowDesc": "考虑" + }, + "category": { + "security": "安全", + "logic": "逻辑", + "quality": "质量", + "performance": "性能", + "style": "风格", + "documentation": "文档", + "testing": "测试", + "other": "其他" + }, + "state": { + "open": "打开", + "closed": "关闭", + "merged": "合并" + }, + "selectCriticalHigh": "选择阻断级/必须修复 ({{count}})", + "selectAll": "选择全部", + "clear": "清除", + "noIssuesFound": "没有发现问题!代码看起来不错。", + "allFindingsPosted": "所有调查结果均发布到 GitHub", + "findingsPostedCount": "{{count}} 发现已发布到 GitHub", + "findingsPostedCount_plural": "{{count}} 调查结果发布到 GitHub", + "selectedOfTotal": "已选择 {{selected}}/{{total}}", + "suggestedFix": "建议修复:", + "runAIReviewDesc": "运行 AI 审核来分析此 PR", + "newCommitsSinceFollowup": "{{count}} 自后续以来的新提交。进行另一次后续审查。", + "newCommitsSinceFollowup_plural": "自后续以来 {{count}} 新提交。进行另一次后续审查。", + "allIssuesResolved": "所有 {{count}} 问题均已解决。此 PR 可以合并。", + "allIssuesResolved_plural": "所有 {{count}} 问题均已解决。此 PR 可以合并。", + "nonBlockingSuggestions": "{{resolved}} 已解决。 {{suggestions}} 非阻塞建议仍然存在。", + "nonBlockingSuggestions_plural": "{{resolved}} 已解决。 {{suggestions}} 非阻塞建议仍然存在。", + "blockingIssues": "阻塞问题", + "blockingIssuesDesc": "{{resolved}} 已解决,{{unresolved}} 阻塞问题仍然存在。", + "blockingIssuesDesc_plural": "{{resolved}} 已解决,{{unresolved}} 阻塞问题仍然存在。", + "newCommitsSinceReview": "{{count}} 自审核以来的新提交。进行后续检查以检查问题是否得到解决。", + "newCommitsSinceReview_plural": "自审核以来 {{count}} 新提交。进行后续检查以检查问题是否得到解决。", + "noBlockingIssues": "没有发现阻塞问题。此 PR 可以合并。", + "findingsPostedWaiting": "{{count}} 发现已发布。等待贡献者解决问题。", + "findingsPostedWaiting_plural": "{{count}} 调查结果已发布。等待贡献者解决问题。", + "findingsPostedNoBlockers": "{{count}} 发现已发布。不存在阻塞问题。", + "findingsPostedNoBlockers_plural": "{{count}} 调查结果已发布。不存在阻塞问题。", + "needsAttention": "需要注意", + "findingsNeedPosting": "{{count}} 发现需要发布到 GitHub。", + "findingsNeedPosting_plural": "{{count}} 调查结果需要发布到 GitHub。", + "findingsFoundSelectPost": "找到 {{count}} 发现。选择并发布到 GitHub。", + "findingsFoundSelectPost_plural": "找到 {{count}} 结果。选择并发布到 GitHub。", + "reviewLogs": "查看日志", + "followup": "跟进", + "initial": "初始", + "rerunFollowup": "重新进行后续审查", + "retryReview": "重试审核", + "rerunReview": "重新进行审核", + "updateBranch": "更新分支", + "updatingBranch": "更新中...", + "branchUpdated": "分支已更新", + "branchUpdateFailed": "更新分支失败", + "allPRsLoaded": "所有 PR 均已加载", + "maxPRsShown": "显示前 100 个 PR", + "loadMore": "加载更多", + "loadingMore": "加载中...", + "workflowsAwaitingApproval": "{{count}} 工作流程等待批准", + "workflowsAwaitingApproval_plural": "{{count}} 等待批准的工作流程", + "blockedByWorkflows": "被阻止", + "workflowsAwaitingDescription": "此 PR 来自分支,需要工作流程批准才能运行 CI 检查。批准工作流程继续。", + "viewOnGitHub": "在 GitHub 上查看", + "approveWorkflow": "批准", + "approveAllWorkflows": "批准所有工作流程", + "postCleanReview": "清洁后审查", + "postingCleanReview": "发布...", + "cleanReviewPosted": "干净的评论已发布", + "cleanReviewMessageTitle": "## ✅ Auto Claude PR审查 - 通过", + "cleanReviewMessageStatus": "**状态:** 所有代码都很好", + "cleanReviewMessageFooter": "*此自动审核没有发现任何问题。由Auto Claude生成。*", + "failedPostCleanReview": "无法发布干净的评论", + "viewErrorDetails": "查看详情", + "hideErrorDetails": "隐藏详细信息", + "postBlockedStatus": "发布状态", + "postingBlockedStatus": "发布...", + "blockedStatusPosted": "状态已发布到 PR", + "blockedStatusMessageTitle": "## 🤖 Auto ClaudePR评论", + "blockedStatusMessageFooter": "*此审查确定了合并前必须解决的阻碍因素。由Auto Claude生成。*", + "failedPostBlockedStatus": "无法发布状态", + "branchSynced": "分支已同步({{count}} 从基础提交)", + "branchSynced_plural": "分支同步({{count}} 从基础提交)", + "newCommitsOverlap": "{{count}} 新提交({{files}} 发现文件已修改)", + "newCommitsOverlap_plural": "{{count}} 新提交({{files}} 发现文件已修改)", + "newCommitsNoOverlap": "{{count}} 新提交(与结果不重叠)", + "newCommitsNoOverlap_plural": "{{count}} 新提交(与发现结果不重叠)", + "verifyChanges": "验证更改", + "verifyAnyway": "核实", + "runFollowupAnyway": "即使没有文件重叠也运行后续验证", + "disputed": "争议", + "disputedByValidator": "验证者有争议 ({{count}})", + "crossValidatedBy": "由 {{count}} 代理确认", + "disputedSectionHint": "这些发现由专家报告,但遭到验证者的质疑。您仍然可以选择并发布它们。", + "logs": { + "agentActivity": "代理活动", + "showMore": "显示更多 {{count}}", + "hideMore": "隐藏更多 {{count}}" + } + }, + "downloads": { + "toggleExpand": "切换下载详细信息", + "downloading": "下载 {{count}} 模型", + "downloading_plural": "下载 {{count}} 模型", + "complete": "{{count}} 下载完成", + "complete_plural": "{{count}} 下载完成", + "failed": "{{count}} 下载失败", + "failed_plural": "{{count}} 下载失败", + "clearAll": "清除所有已完成的下载", + "done": "完成", + "failedLabel": "失败", + "starting": "开始..." + }, + "insights": { + "suggestedTask": "建议任务", + "creating": "创建...", + "taskCreated": "任务已创建", + "createTask": "创建任务", + "chatHistory": "聊天记录", + "archive": "归档", + "unarchive": "取消存档", + "archiveSelected": "存档已选择", + "showArchived": "显示已存档", + "hideArchived": "隐藏已存档", + "bulkDeleteTitle": "删除对话", + "bulkDeleteDescription": "您确定要删除 {{count}} 对话吗?此操作无法撤消。", + "bulkDeleteConfirm": "删除 {{count}} 对话", + "noConversations": "没有对话", + "archived": "已存档", + "conversationsToDelete": "要删除的对话", + "archiveConfirmDescription": "您确定要存档选定的对话吗?", + "archiveConfirmTitle": "存档对话", + "archiveConfirmButton": "存档 {{count}} 对话", + "deleteTitle": "删除对话", + "deleteDescription": "您确定要删除此对话吗?此操作无法撤消。", + "selectMode": "选择", + "exitSelectMode": "完成", + "today": "今天", + "yesterday": "昨天", + "daysAgo": "{{count}} 天前", + "messageCount": "{{count}} 消息", + "messageCount_other": "{{count}} 消息", + "images": { + "pasteHint": "粘贴图像或屏幕截图", + "dropHint": "将图像拖放到此处", + "screenshotButton": "附上截图", + "removeImage": "删除图像", + "imageCount": "{{count}} 附加图像", + "imageCount_plural": "{{count}} 附加图像", + "maxImagesReached": "已达到最大图像数量", + "invalidType": "文件类型无效。请使用 PNG、JPEG、GIF 或 WebP。", + "processFailed": "处理图像失败", + "dragOver": "拖放图像以附加", + "analysisUnsupported": "注意:尚不支持图像分析。图像被存储以供参考,但无法由模型进行分析。", + "screenshotTooLarge": "屏幕截图太大 ({{size}}MB)。最大大小为 {{max}}MB。考虑占领较小的区域。", + "notAnalyzed": "图像被存储以供参考,但模型未对其进行分析。" + } + }, + "ideation": { + "converting": "转换...", + "convertToTask": "转换为自动构建任务", + "dismissIdea": "忽略想法", + "description": "描述", + "rationale": "基本原理", + "goToTask": "前往任务", + "conversionFailed": "转换失败", + "conversionFailedDescription": "未能将想法转化为任务", + "conversionError": "转换错误", + "conversionErrorDescription": "转换想法时发生错误" + }, + "issues": { + "githubTitle": "GitHub 问题", + "openCount": "{{count}} 个未关闭", + "searchPlaceholder": "搜索问题...", + "filterOpen": "未关闭", + "filterClosed": "已关闭", + "stateOpen": "未关闭", + "stateClosed": "已关闭", + "filterAll": "全部", + "analyzeGroup": "分析并分组问题", + "analyzeGroupTip": "最多分析 200 个未关闭问题,按相似性分组,并在创建任务前审阅建议批次。", + "autoFixNew": "自动修复新问题", + "autoFixTip": "在新问题出现时自动尝试修复。", + "autoFixProcessing": "正在处理 {{count}} 个问题...", + "autoFixProcessing_plural": "正在处理 {{count}} 个问题...", + "noMatch": "没有符合您搜索条件的问题", + "noIssues": "未找到问题", + "selectIssue": "请选择一个问题以查看详情", + "notConnectedTitle": "GitHub 未连接", + "notConnectedDescription": "请在项目设置中配置 GitHub 令牌和仓库以同步问题。", + "openSettings": "打开设置", + "commentsCount": "{{count}} 条评论", + "viewTask": "查看任务", + "createTask": "创建任务", + "taskLinked": "已关联任务", + "taskId": "任务 ID", + "description": "描述", + "noDescription": "未提供描述。", + "assignees": "指派对象", + "milestone": "里程碑", + "investigation": { + "title": "从问题创建任务", + "description": "从此 GitHub 问题创建任务。任务会被添加到看板的 Backlog 列。", + "failedToLoadComments": "加载评论失败", + "selectComments": "选择要包含的评论({{selected}}/{{total}})", + "deselectAll": "取消全选", + "selectAll": "全选", + "willInclude": "任务将包含:", + "includeTitle": "问题标题和描述", + "includeLink": "返回 GitHub 问题的链接", + "includeLabels": "问题的标签与元数据", + "noComments": "无评论(该问题没有评论)", + "taskCreated": "任务已创建!可在看板中查看。", + "creating": "创建中..." + }, + "loadingMore": "加载更多...", + "scrollForMore": "滚动查看更多", + "allLoaded": "所有问题均已加载" + }, + "usage": { + "dataUnavailable": "使用数据不可用", + "dataUnavailableDescription": "该提供程序的使用情况监控端点不可用或不受支持。", + "activeAccount": "活跃账户", + "usageAlert": "使用提醒", + "accountExceedsThreshold": "帐户使用率超过 90% 阈值", + "authentication": "验证", + "authenticationAriaLabel": "身份验证:{{provider}}", + "authenticationDetails": "认证详情", + "apiProfile": "API配置", + "apiKey": "API密钥", + "oauth": "OAuth", + "claudeCode": "Claude Code", + "claudeCodeSubscription": "Claude Code 订阅", + "subscription": "订阅", + "provider": "提供者", + "providerAnthropic": "Anthropic", + "providerZai": "Z.AI", + "providerZhipu": "智谱AI", + "providerUnknown": "未知", + "profile": "配置", + "id": "ID", + "created": "已创建", + "apiEndpoint": "API端点", + "sessionQuota": "会话配额", + "notAvailable": "不适用", + "usageStatusAriaLabel": "使用状况", + "usageBreakdown": "使用情况细分", + "used": "已使用", + "loading": "加载中...", + "sessionDefault": "会话", + "weeklyDefault": "每周", + "resetsInHours": "在 {{hours}}h {{minutes}}m 中重置", + "resetsInDays": "在 {{days}}d {{hours}}h 中重置", + "window5Hour": "5小时窗口", + "window7Day": "7天窗口期", + "window5HoursQuota": "5小时配额", + "windowMonthlyToolsQuota": "每月工具配额", + "otherAccounts": "其他账户", + "next": "下一个", + "weeklyLimitReached": "已达到每周限额", + "sessionLimitReached": "已达到会话限制", + "notAuthenticated": "未经过验证", + "needsReauth": "需要重新授权", + "reauthRequired": "需要重新认证", + "reauthRequiredDescription": "您的会话已过期。重新验证以查看使用情况并继续使用此帐户。", + "reauthButton": "重新验证", + "clickToOpenSettings": "点击打开设置 →", + "sessionShort": "5小时会话使用", + "weeklyShort": "每周使用 7 天", + "swap": "交换" + }, + "oauth": { + "enterCode": "手动代码输入(后备)", + "enterCodeDescription": "仅当浏览器未自动重定向时才需要此对话框。如果您的浏览器中已完成身份验证,您可以关闭此对话框。", + "fallbackNote": "仅当您在浏览器中看到“将其粘贴到 Claude Code 中”页面时才使用此选项。", + "step1": "在浏览器中完成授权", + "step2": "如果您看到代码页,请复制显示的代码", + "step3": "粘贴下面的代码并单击提交", + "codeLabel": "授权码", + "codePlaceholder": "将您的代码粘贴到此处(仅在需要时)...", + "codeHint": "该代码是一个长字符串,仅在自动重定向失败时显示", + "submit": "提交", + "submitting": "正在提交...", + "codeSubmitted": "代码已提交", + "codeSubmittedDescription": "身份验证应该很快就会完成。检查终端确认。", + "codeSubmitFailed": "提交代码失败", + "codeSubmitFailedDescription": "请重试或手动将代码复制到终端。", + "authenticateTitle": "与Claude验证", + "authenticateDescription": "Auto Claude 需要 Claude AI 身份验证才能实现路线图生成、任务自动化和创意等 AI 驱动的功能。", + "authenticateTerminalInfo": "这将使用 Claude CLI 打开一个终端,您可以在其中进行身份验证。您的凭据将被安全存储,并且有效期为 1 年。", + "completeAuthTitle": "完整认证", + "terminalOpened": "已使用 Claude CLI 打开终端窗口。", + "completeStepsTitle": "在终端中完成以下步骤:", + "stepTypeLogin": "输入 /login 并按 Enter", + "stepBrowserOpen": "您的浏览器将打开以进行Claude身份验证", + "stepCompleteOAuth": "在浏览器中完成 OAuth 流程", + "stepReturnAndVerify": "返回此处并点击验证身份验证", + "verifyAuth": "验证身份验证", + "verifyingAuth": "正在验证身份验证...", + "checkingCredentials": "检查您的Claude凭据。", + "successTitle": "认证成功!", + "connectedAs": "连接为 {{email}}", + "credentialsSaved": "您的Claude凭据已保存", + "canUseFeatures": "您现在可以使用 Auto Claude AI 的所有功能", + "authFailed": "认证失败", + "skipForNow": "暂时跳过", + "manualTokenEntry": "手动输入令牌", + "tokenCommandHint": "运行 claude setup-token 来获取您的令牌", + "emailOptionalPlaceholder": "电子邮件(可选,用于显示)", + "saveToken": "保存令牌", + "accountNamePlaceholder": "帐户名称(例如工作、个人)", + "hasAuthenticatedAccount": "您至少拥有一个经过身份验证的 Claude 帐户。您可以继续下一步。", + "authNotDetected": "未检测到身份验证。请先在终端中完成/登录。", + "noProfileSelected": "未选择用于验证的配置文件", + "alerts": { + "profileCreatedAuthFailed": "配置文件已创建,但无法启动身份验证:{{error}}", + "authPrepareFailed": "无法准备身份验证:{{error}}", + "authStartFailedMessage": "无法启动身份验证。请再试一次。" + }, + "badges": { + "default": "默认", + "active": "活跃", + "authenticated": "已认证", + "needsAuth": "需要验证" + }, + "buttons": { + "authenticate": "认证", + "setActive": "设置为活动状态", + "back": "后退", + "skip": "跳过", + "continue": "继续" + }, + "toast": { + "tokenSaved": "令牌已保存", + "tokenSavedDescription": "您的 Claude 令牌已安全保存。", + "tokenSaveFailed": "保存令牌失败", + "addProfileFailed": "添加配置文件失败", + "tryAgain": "请再试一次。" + }, + "configureTitle": "配置Claude帐户", + "addAccountsDesc": "添加并验证您的 Claude 帐户以使用 AI 功能。", + "multiAccountInfo": "您可以添加多个Claude帐户。活跃账户将用于人工智能功能。您可以随时切换帐户。", + "keychainTitle": "安全存储", + "keychainDescription": "您的身份验证令牌安全地存储在 macOS 钥匙串中。", + "noAccountsYet": "尚未添加帐户。在下面添加您的第一个Claude帐户。" + }, + "authTerminal": { + "failedToCreate": "创建终端失败", + "unknownError": "未知错误", + "instructionTitle": "Claude认证", + "step1": "按 Enter 开始身份验证", + "step2": "在浏览器中完成身份验证", + "step3": "返回此处 - 身份验证将被自动检测", + "authFailed": "认证失败", + "connecting": "正在连接...", + "authenticate": "验证:{{profileName}}", + "completeSetup": "完整设置:{{profileName}}", + "authenticatedAs": "验证为 {{email}}", + "authenticated": "已认证!", + "authError": "认证错误", + "onboardingMessage": "令牌已收到!完成下面的Claude代码设置 - 完成后此窗口将自动关闭。", + "successMessage": "认证成功!关闭..." + }, + "profileCreated": { + "title": "配置文件“{{profileName}}”已创建。", + "instructions": "要验证此配置文件:", + "step1": "转到设置 > 集成", + "step2": "在 Claude Accounts 部分找到配置文件", + "step3": "点击“验证”完成登录", + "footer": "完成身份验证后,该帐户即可使用。" + }, + "roadmap": { + "taskCompleted": "已完成", + "taskDeleted": "已删除", + "taskArchived": "已存档", + "showMoreFeatures": "显示 {{count}} 更多功能", + "showMoreFeatures_plural": "显示 {{count}} 更多功能", + "showLessFeatures": "显示较少", + "archiveFeature": "归档", + "archiveFeatureConfirmTitle": "存档功能?", + "archiveFeatureConfirmDescription": "这将从您的路线图中删除“{{title}}”。", + "goToTask": "前往任务", + "convertToTask": "转换为自动构建任务", + "build": "构建", + "task": "任务", + "viewTask": "查看任务" + }, + "roadmapGeneration": { + "progress": "进度", + "elapsed": "已过:{{time}}", + "stillWorking": "还在工作...", + "stopping": "停止...", + "stop": "停止", + "stopTooltip": "停止生成", + "phases": { + "analyzing": { + "label": "分析中", + "description": "分析项目结构和代码库..." + }, + "discovering": { + "label": "发现", + "description": "发现目标受众和用户需求..." + }, + "generating": { + "label": "生成", + "description": "正在生成功能路线图..." + }, + "complete": { + "label": "已完成", + "description": "路线图生成完成!" + }, + "error": { + "label": "错误", + "description": "生成失败" + } + }, + "steps": { + "analyze": "分析", + "discover": "发现", + "generate": "产生" + } + }, + "auth": { + "failure": { + "title": "需要身份验证", + "profileLabel": "配置", + "unknownProfile": "未知的配置文件", + "tokenExpired": "您的身份验证令牌已过期。", + "tokenInvalid": "您的身份验证令牌无效。", + "tokenMissing": "未找到身份验证令牌。", + "authFailed": "认证失败。", + "description": "请重新验证您的 Claude 配置文件以继续使用 Auto Claude。", + "taskAffected": "任务受影响", + "technicalDetails": "技术细节", + "goToSettings": "前往“设置”" + } + }, + "git": { + "branchGroups": { + "local": "本地分支", + "remote": "远程分支" + }, + "branchType": { + "local": "本地", + "remote": "远程" + } + }, + "githubErrors": { + "rateLimitTitle": "已达到 GitHub 速率限制", + "authTitle": "需要 GitHub 身份验证", + "permissionTitle": "GitHub 权限被拒绝", + "notFoundTitle": "未找到 GitHub 资源", + "networkTitle": "GitHub 连接错误", + "unknownTitle": "GitHub 错误", + "rateLimitMessage": "已达到 GitHub API 速率限制。请稍等片刻,然后重试。", + "rateLimitMessageMinutes": "已达到 GitHub API 速率限制。请等待 {{minutes}} 分钟,然后再重试。", + "rateLimitMessageHours": "已达到 GitHub API 速率限制。速率限制将在大约 {{hours}} 小时后重置。", + "authMessage": "GitHub 身份验证失败。请在“设置”中检查您的 GitHub 令牌,然后重试。", + "permissionMessage": "GitHub 权限被拒绝。您的令牌可能没有所需的访问权限。请在“设置”中检查您的令牌权限。", + "permissionMessageScopes": "GitHub 权限被拒绝。您的令牌缺少必需的范围:{{scopes}}。请在“设置”中更新您的 GitHub 令牌。", + "notFoundMessage": "未找到请求的 GitHub 资源。请验证仓库是否存在并且您有权访问它。", + "networkMessage": "无法连接到 GitHub。请检查您的互联网连接,然后重试。", + "unknownMessage": "与 GitHub 通信时发生意外错误。请再试一次。", + "resetsIn": "在 {{time}} 中重置", + "countdownHoursMinutes": "{{hours}}h {{minutes}}m", + "countdownMinutesSeconds": "{{minutes}}m {{seconds}}s", + "rateLimitExpired": "速率限制已重置。您现在可以重试。", + "requiredScopes": "所需范围" + }, + "roadmapProgress": { + "elapsedTime": "已用时间", + "lastActivity": "上次活动", + "staleWarning": "暂时没有活动", + "staleWarningTooltip": "此任务在 {{minutes}} 分钟内没有任何活动", + "phases": { + "analyzing": { + "label": "分析中", + "description": "分析项目结构和代码库..." + }, + "discovering": { + "label": "发现", + "description": "发现目标受众和用户需求..." + }, + "generating": { + "label": "生成", + "description": "正在生成功能路线图..." + }, + "complete": { + "label": "已完成", + "description": "路线图生成完成!" + }, + "error": { + "label": "错误", + "description": "生成失败" + } + }, + "steps": { + "analyze": "分析", + "discover": "发现", + "generate": "产生" + }, + "processing": "处理中", + "processActiveTooltip": "进程正在主动运行", + "stopGeneration": "停止生成", + "stopping": "停止...", + "progress": "进度", + "lastActivityPrefix": "上次活动", + "lastProgressUpdateTooltip": "收到的最新进度更新" + }, + "prStatus": { + "ci": { + "success": "CI 通过", + "pending": "CI 待定", + "failure": "CI 失败", + "successTooltip": "所有 CI 检查均已通过", + "pendingTooltip": "CI 检查仍在运行", + "failureTooltip": "一项或多项 CI 检查失败" + }, + "review": { + "approved": "已批准", + "changesRequested": "需要修改", + "pending": "审核待决", + "approvedTooltip": "此 PR 已获得批准", + "changesRequestedTooltip": "已请求对此 PR 进行更改", + "pendingTooltip": "等待审核" + }, + "merge": { + "ready": "准备合并", + "blocked": "合并被阻止", + "conflict": "有冲突", + "readyTooltip": "此 PR 已准备好合并", + "blockedTooltip": "由于阻塞条件,此 PR 无法合并", + "conflictTooltip": "此 PR 存在需要解决的合并冲突" + } + } +} diff --git a/apps/frontend/src/shared/i18n/locales/zh/dialogs.json b/apps/frontend/src/shared/i18n/locales/zh/dialogs.json new file mode 100644 index 0000000000..b82217803e --- /dev/null +++ b/apps/frontend/src/shared/i18n/locales/zh/dialogs.json @@ -0,0 +1,234 @@ +{ + "initialize": { + "title": "初始化Auto Claude", + "description": "该项目没有初始化 Auto Claude。您想立即设置吗?", + "willDo": "这将:", + "createFolder": "在项目中创建 .auto-claude 文件夹", + "copyFramework": "复制 Auto Claude 框架文件", + "setupSpecs": "为您的任务设置规格目录", + "sourcePathNotConfigured": "源路径未配置", + "sourcePathNotConfiguredDescription": "初始化前请先在App Settings中设置Auto Claude源码路径。", + "initFailed": "初始化失败", + "initFailedDescription": "未能初始化Auto Claude。请再试一次。" + }, + "gitSetup": { + "title": "需要 Git 仓库", + "description": "Auto Claude 使用 git 在隔离的工作空间中安全地构建功能", + "notGitRepo": "该文件夹不是 git 仓库", + "noCommits": "Git 仓库没有提交", + "needsInit": "在 Auto Claude 可以管理您的代码之前,需要初始化 Git。", + "needsCommit": "Auto Claude 至少需要一次提交才能创建工作树。", + "willSetup": "我们将为您设置 git:", + "initRepo": "初始化一个新的git仓库", + "createCommit": "使用当前文件创建初始提交", + "manual": "更喜欢手动执行?", + "settingUp": "设置 Git", + "initializingRepo": "正在初始化 git 仓库并创建初始提交...", + "success": "Git 初始化", + "readyToUse": "您的项目现在可以与 Auto Claude 一起使用了!" + }, + "githubSetup": { + "connectTitle": "连接到 GitHub", + "connectDescription": "Auto Claude 需要 GitHub 来管理您的代码分支并保持任务最新。", + "claudeTitle": "连接到Claude人工智能", + "claudeDescription": "Auto Claude 使用 Claude AI 实现路线图生成、任务自动化和创意等智能功能。", + "selectRepo": "选择仓库", + "repoDescription": "Auto Claude 将使用此仓库来管理任务分支并使您的代码保持最新。", + "selectBranch": "选择基础分支", + "branchDescription": "选择 Auto Claude 应使用哪个分支作为创建任务分支的基础。", + "whyBranch": "为什么选择分支?", + "branchExplanation": "Auto Claude 为每项任务创建独立的工作空间。选择正确的基础分支可确保您的任务从主开发线的最新代码开始。", + "ready": "Auto Claude已准备好使用!您现在可以创建自动基于 {{branchName}} 分支的任务。", + "createRepoAriaLabel": "在 GitHub 上创建新仓库", + "linkRepoAriaLabel": "链接到现有仓库", + "goBackAriaLabel": "返回仓库选择", + "selectOwnerAriaLabel": "选择 {{owner}} 作为仓库所有者", + "selectOrgAriaLabel": "选择 {{org}} 作为仓库所有者", + "selectVisibilityAriaLabel": "将仓库可见性设置为 {{visibility}}" + }, + "worktrees": { + "title": "工作树", + "description": "管理 Auto Claude 任务的独立工作区", + "empty": "无工作树", + "emptyDescription": "Auto Claude 构建特征时会自动创建工作树。他们为每项任务提供独立的工作空间。", + "merge": "合并工作树", + "mergeDescription": "将此工作树的更改合并到基础分支中。", + "delete": "删除工作树?", + "deleteDescription": "这将永久删除工作树和所有未提交的更改。此操作无法撤消。", + "bulkDeleteTitle": "删除 {{count}} 工作树?", + "bulkDeleteDescription": "这将永久删除选定的工作树及其所有未提交的更改。此操作无法撤消。", + "deleting": "正在删除...", + "deleteSelected": "删除所选内容" + }, + "worktreeCleanup": { + "title": "完成任务", + "hasWorktree": "任务“{{taskTitle}}”仍然有一个独立的工作区(工作树)。", + "willDelete": "要将此任务标记为完成,工作树及其关联的分支将被删除。", + "warning": "在继续之前,请确保您已合并或保存要保留的所有更改。", + "confirm": "删除工作树并完成", + "completing": "正在完成...", + "retry": "再试一次", + "errorTitle": "清理失败", + "errorDescription": "无法清理工作树。请再试一次。" + }, + "update": { + "title": "Auto Claude", + "projectInitialized": "项目已初始化。" + }, + "addFeature": { + "title": "添加功能", + "description": "向您的路线图添加新功能。提供有关您想要构建的内容以及它如何融入您的产品策略的详细信息。", + "featureTitle": "专题标题", + "featureTitlePlaceholder": "例如,用户身份验证、深色模式支持", + "featureDescription": "描述", + "featureDescriptionPlaceholder": "描述此功能的用途以及为什么它对用户有价值。", + "rationale": "基本原理", + "optional": "可选", + "rationalePlaceholder": "解释为什么应该构建此功能以及它如何符合产品愿景。", + "phase": "阶段", + "selectPhase": "选择阶段", + "priority": "优先事项", + "selectPriority": "选择优先级", + "complexity": "复杂", + "selectComplexity": "选择复杂性", + "impact": "影响", + "selectImpact": "选择影响", + "lowComplexity": "低", + "mediumComplexity": "中等", + "highComplexity": "高", + "lowImpact": "低影响", + "mediumImpact": "中等影响", + "highImpact": "高影响力", + "titleRequired": "标题为必填项", + "descriptionRequired": "描述为必填项", + "phaseRequired": "请选择一个阶段", + "cancel": "取消", + "adding": "添加...", + "addFeature": "添加功能", + "failedToAdd": "添加功能失败。请再试一次。" + }, + "addProject": { + "title": "添加项目", + "description": "选择您想要如何添加项目", + "openExisting": "打开现有文件夹", + "openExistingDescription": "浏览到计算机上的现有项目", + "createNew": "创建新项目", + "createNewDescription": "使用新的项目文件夹重新开始", + "createNewTitle": "创建新项目", + "createNewSubtitle": "设置新的项目文件夹", + "projectName": "项目名称", + "projectNamePlaceholder": "我很棒的项目", + "projectNameHelp": "这将是文件夹名称。使用带连字符的小写字母。", + "location": "地点", + "locationPlaceholder": "选择一个文件夹...", + "willCreate": "将创建:", + "browse": "浏览", + "initGit": "初始化git仓库", + "back": "后退", + "creating": "创建...", + "createProject": "创建项目", + "nameRequired": "请输入项目名称", + "locationRequired": "请选择地点", + "failedToOpen": "无法打开项目", + "failedToCreate": "创建项目失败", + "openExistingAriaLabel": "打开现有项目文件夹", + "createNewAriaLabel": "创建新项目" + }, + "customModel": { + "title": "自定义模型配置", + "description": "配置本次聊天会话的模型和思维水平。", + "model": "模型", + "thinkingLevel": "思维层面", + "cancel": "取消", + "apply": "应用" + }, + "removeProject": { + "title": "删除项目?", + "description": "这将从应用程序中删除“{{projectName}}”。您的文件将保留在磁盘上,您可以稍后重新添加项目。", + "cancel": "取消", + "remove": "移除", + "error": "删除项目失败" + }, + "appUpdate": { + "title": "应用程序更新可用", + "description": "新版本的 Auto Claude 可供下载", + "newVersion": "新版本", + "released": "已发布", + "downloading": "正在下载...", + "downloadUpdate": "下载更新", + "installAndRestart": "安装并重新启动", + "installLater": "稍后安装", + "remindMeLater": "稍后提醒我", + "updateDownloaded": "更新下载成功!单击“安装”重新启动并应用更新。", + "downloadError": "下载更新失败", + "claudeCodeChangelog": "查看Claude代码变更日志", + "claudeCodeChangelogAriaLabel": "查看 Claude 代码变更日志(在新窗口中打开)", + "readOnlyVolumeTitle": "无法从磁盘映像安装", + "readOnlyVolumeDescription": "更新之前,请将 Auto Claude 移动到您的应用程序文件夹。" + }, + "addCompetitor": { + "title": "添加竞争对手", + "description": "在您的分析中添加一个已知的竞争对手...", + "competitorName": "竞争对手名称", + "competitorNamePlaceholder": "例如Slack、Notion、Figma", + "competitorUrl": "网站网址", + "competitorUrlPlaceholder": "例如https://example.com", + "competitorDescription": "描述", + "competitorDescriptionPlaceholder": "简要描述该竞争对手的业务...", + "relevance": "关联", + "selectRelevance": "选择相关性", + "highRelevance": "高 - 直接竞争对手", + "mediumRelevance": "中 - 部分重叠", + "lowRelevance": "低-切向", + "nameRequired": "竞争对手名称为必填项", + "urlRequired": "网站网址为必填项", + "invalidUrl": "请输入有效的网址", + "optional": "可选", + "cancel": "取消", + "adding": "添加...", + "addCompetitor": "添加竞争对手", + "failedToAdd": "添加竞争对手失败" + }, + "competitorAnalysis": { + "title": "启用竞争对手分析?", + "description": "利用竞争对手产品的洞察来增强您的路线图", + "whatItDoes": "竞争对手分析的作用:", + "identifiesCompetitors": "根据您的项目类型确定 3-5 个主要竞争对手", + "searchesAppStores": "搜索应用商店、论坛和社交媒体以获取用户反馈和痛点", + "suggestsFeatures": "建议弥补竞争对手产品差距的功能", + "webSearchesTitle": "将执行网络搜索", + "webSearchesDescription": "此功能将执行网络搜索以收集竞争对手信息。您的项目名称和类型将用于搜索查询。不共享任何代码或敏感数据。", + "optionalInfo": "如果您愿意,您可以在不分析竞争对手的情况下生成路线图。该路线图仍将基于您的项目结构和最佳实践。", + "skipAnalysis": "否,跳过分析", + "enableAnalysis": "是,启用分析", + "knowYourCompetitors": "已经了解您的竞争对手了吗?", + "addThemDirectly": "直接添加以提高分析准确性", + "addKnownCompetitors": "添加已知竞争对手", + "addKnownCompetitorsDescription": "将您已经了解的竞争对手手动添加到现有分析中。", + "competitorsAdded": "添加了 {{count}}" + }, + "existingCompetitorAnalysis": { + "title": "竞争对手分析选项", + "description": "该项目有来自 {{date}} 的现有竞争对手分析", + "recently": "最近", + "useExistingTitle": "使用现有分析", + "recommended": "(推荐)", + "useExistingDescription": "重用您已有的竞争对手洞察。更快且无需额外的网络搜索。", + "runNewTitle": "运行新分析", + "runNewDescription": "执行新的网络搜索以获取最新的竞争对手信息。需要更长的时间。", + "skipTitle": "跳过竞争对手分析", + "skipDescription": "在没有任何竞争对手洞察的情况下生成路线图。", + "cancel": "取消" + }, + "versionWarning": { + "title": "需要采取的行动", + "subtitle": "2.7.5版本更新", + "description": "由于此版本中的身份验证更改,您需要重新验证您的 Claude 配置文件。", + "instructions": "重新验证:", + "step1": "前往“设置”", + "step2": "导航至应用程序设置 > 集成", + "step3": "点击您的配置文件上的“重新验证”", + "gotIt": "知道了", + "goToSettings": "前往“设置”" + } +} diff --git a/apps/frontend/src/shared/i18n/locales/zh/errors.json b/apps/frontend/src/shared/i18n/locales/zh/errors.json new file mode 100644 index 0000000000..c07dd7a08b --- /dev/null +++ b/apps/frontend/src/shared/i18n/locales/zh/errors.json @@ -0,0 +1,9 @@ +{ + "task": { + "parseImplementationPlan": "无法解析 {{specId}} 的implementation_plan.json:{{error}}", + "jsonError": { + "titleSuffix": "(JSON 错误)", + "description": "⚠️ JSON 解析错误:{{error}}\n\nimplementation_plan.json 文件格式错误。运行后端自动修复或手动修复文件。" + } + } +} diff --git a/apps/frontend/src/shared/i18n/locales/zh/gitlab.json b/apps/frontend/src/shared/i18n/locales/zh/gitlab.json new file mode 100644 index 0000000000..69c42f64e4 --- /dev/null +++ b/apps/frontend/src/shared/i18n/locales/zh/gitlab.json @@ -0,0 +1,212 @@ +{ + "title": "GitLab问题", + "states": { + "opened": "打开", + "closed": "关闭" + }, + "complexity": { + "simple": "简单", + "standard": "标准", + "complex": "复杂" + }, + "header": { + "open": "打开", + "searchPlaceholder": "搜索问题..." + }, + "filters": { + "opened": "打开", + "closed": "关闭", + "all": "全部" + }, + "empty": { + "noMatch": "没有符合您搜索条件的问题", + "selectIssue": "选择问题查看详细信息", + "noIssues": "未找到问题" + }, + "accessibility": { + "investigateIssueAriaLabel": "分析该问题" + }, + "notConnected": { + "title": "GitLab未连接", + "description": "在项目设置中配置您的 GitLab 令牌和项目以同步问题。", + "openSettings": "打开设置" + }, + "detail": { + "notes": "笔记", + "viewTask": "查看任务", + "createTask": "创建任务", + "taskLinked": "任务链接", + "taskId": "任务编号", + "description": "描述", + "noDescription": "没有提供描述。", + "assignees": "受让人", + "milestone": "里程碑" + }, + "investigation": { + "title": "从问题创建任务", + "issuePrefix": "问题", + "description": "从此 GitLab 问题创建一个任务。该任务将添加到看板的“待办事项”列中。", + "selectNotes": "选择要包含的注释", + "deselectAll": "取消全选", + "selectAll": "选择全部", + "willInclude": "该任务将包括:", + "includeTitle": "问题标题和描述", + "includeLink": "返回 GitLab 问题的链接", + "includeLabels": "问题中的标签和元数据", + "noNotes": "无注释(本期无注释)", + "failedToLoadNotes": "加载笔记失败", + "taskCreated": "任务已创建!在您的看板中查看它。", + "creating": "创建...", + "cancel": "取消", + "done": "完成", + "close": "关闭" + }, + "settings": { + "enableIssues": "启用 GitLab 问题", + "enableIssuesDescription": "从 GitLab 同步问题并自动创建任务", + "instance": "GitLab实例", + "instanceDescription": "使用 https://gitlab.com 或您的自托管实例 URL", + "connectedVia": "通过 GitLab CLI 连接", + "authenticatedAs": "验证为", + "useDifferentToken": "使用不同的令牌", + "authentication": "GitLab身份验证", + "useManualToken": "使用手动令牌", + "authenticating": "使用 glab CLI 进行身份验证...", + "browserWindow": "应打开一个浏览器窗口供您登录。", + "personalAccessToken": "个人访问令牌", + "useOAuth": "使用 OAuth 代替", + "tokenScope": "创建一个令牌", + "scopeApi": "API", + "scopeFrom": "范围从", + "gitlabSettings": "GitLab设置", + "project": "项目", + "enterManually": "手动输入", + "loadingProjects": "正在加载项目...", + "selectProject": "选择一个项目...", + "searchProjects": "搜索项目...", + "noMatchingProjects": "没有匹配的项目", + "noProjectsFound": "没有找到项目", + "selected": "已选择", + "projectFormat": "格式:", + "projectFormatExample": "(例如,gitlab-org/gitlab)", + "connectionStatus": "连接状态", + "checking": "检查...", + "connectedTo": "连接到", + "notConnected": "未连接", + "issuesAvailable": "可用问题", + "issuesAvailableDescription": "从侧边栏访问 GitLab 问题以查看、调查问题并根据问题创建任务。", + "defaultBranch": "默认分支", + "defaultBranchDescription": "用于创建任务工作树的基础分支", + "loadingBranches": "正在加载分支...", + "autoDetect": "自动检测(主/主)", + "searchBranches": "搜索分支...", + "noMatchingBranches": "没有匹配的分支", + "noBranchesFound": "没有找到分支", + "branchFromNote": "所有新任务都将从", + "autoSyncOnLoad": "加载时自动同步", + "autoSyncDescription": "项目加载时自动获取问题", + "cli": { + "required": "需要 GitLab CLI", + "notInstalled": "OAuth 身份验证需要 GitLab CLI (glab)。安装它以使用“使用 OAuth”选项。", + "installButton": "安装glab", + "installing": "正在安装...", + "installSuccess": "安装在您的终端中开始。完成它并单击刷新。", + "refresh": "刷新", + "learnMore": "了解更多", + "installed": "安装的 GitLab CLI:" + } + }, + "mergeRequests": { + "title": "GitLab 合并请求", + "newMR": "新合并请求", + "selectMR": "选择合并请求以查看详细信息", + "states": { + "opened": "打开", + "closed": "关闭", + "merged": "合并", + "locked": "锁定" + }, + "filters": { + "opened": "打开", + "closed": "关闭", + "merged": "合并", + "all": "全部" + } + }, + "mrReview": { + "runReview": "运行人工智能审查", + "reviewing": "正在审查...", + "followupReview": "后续审查", + "newCommits": "新提交", + "newCommitsPlural": "新提交", + "cancel": "取消", + "postFindings": "发布调查结果", + "posting": "发布...", + "postedTo": "发布到 GitLab", + "approve": "批准", + "approving": "正在批准...", + "merge": "合并MR", + "merging": "合并...", + "aiReviewResult": "人工智能审核结果", + "followupReviewResult": "后续审查", + "description": "描述", + "noDescription": "没有提供描述。", + "labels": "标签", + "status": { + "notReviewed": "未审查", + "notReviewedDesc": "运行 AI 审核来分析此 MR", + "reviewComplete": "审核完成", + "reviewCompleteDesc": "发现结果。选择并发布到 GitLab。", + "waitingForChanges": "等待改变", + "waitingForChangesDesc": "已发布调查结果。等待贡献者解决问题。", + "readyToMerge": "准备合并", + "readyToMergeDesc": "没有发现阻塞问题。这个MR可以合并。", + "needsAttention": "需要注意", + "needsAttentionDesc": "发现结果需要发布到 GitLab。", + "readyForFollowup": "准备跟进", + "readyForFollowupDesc": "自审查以来。进行后续检查以检查问题是否得到解决。", + "blockingIssues": "阻塞问题", + "blockingIssuesDesc": "阻塞问题仍然存在。" + }, + "overallStatus": { + "approve": "批准", + "requestChanges": "要求更改", + "comment": "评论" + }, + "resolution": { + "resolved": "已解决", + "stillOpen": "仍然开放", + "newIssue": "新一期", + "newIssues": "新问题" + } + }, + "findings": { + "summary": "已选择", + "selectCriticalHigh": "选择拦截器/必需", + "selectAll": "选择全部", + "clear": "清除", + "noIssues": "没有发现问题!代码看起来不错。", + "suggestedFix": "建议修复:", + "posted": "已发布", + "severity": { + "critical": "拦截者", + "criticalDesc": "必须修复", + "high": "必须修复", + "highDesc": "应该修复", + "medium": "推荐", + "mediumDesc": "提高质量", + "low": "建议", + "lowDesc": "考虑" + }, + "category": { + "security": "安全", + "quality": "质量", + "style": "风格", + "test": "测试", + "docs": "文档", + "pattern": "模式", + "performance": "性能", + "logic": "逻辑" + } + } +} diff --git a/apps/frontend/src/shared/i18n/locales/zh/navigation.json b/apps/frontend/src/shared/i18n/locales/zh/navigation.json new file mode 100644 index 0000000000..172982d38e --- /dev/null +++ b/apps/frontend/src/shared/i18n/locales/zh/navigation.json @@ -0,0 +1,87 @@ +{ + "sections": { + "project": "项目", + "tools": "工具" + }, + "items": { + "kanban": "看板", + "terminals": "代理终端", + "insights": "洞察", + "roadmap": "路线图", + "ideation": "创意", + "changelog": "变更日志", + "context": "上下文", + "githubIssues": "GitHub 问题", + "githubPRs": "GitHub PR", + "gitlabIssues": "GitLab问题", + "gitlabMRs": "GitLab MR", + "worktrees": "工作树", + "agentTools": "MCP概述" + }, + "actions": { + "settings": "设置", + "help": "帮助与反馈", + "newTask": "新任务", + "collapseSidebar": "折叠侧边栏", + "expandSidebar": "展开侧边栏", + "sponsor": "赞助我们" + }, + "tooltips": { + "settings": "应用程序设置", + "help": "帮助与反馈" + }, + "messages": { + "initializeToCreateTasks": "初始化 Auto Claude 以创建任务" + }, + "updateBanner": { + "title": "可用更新", + "version": "版本 {{version}} 已准备就绪", + "updateAndRestart": "更新并重启", + "installAndRestart": "安装并重新启动", + "downloading": "正在下载...", + "dismiss": "忽略", + "downloadError": "下载更新失败", + "readOnlyVolumeWarning": "移至应用程序文件夹进行更新" + }, + "claudeCode": { + "checking": "检查Claude代码...", + "upToDate": "Claude代码已更新", + "updateAvailable": "Claude代码更新可用", + "notInstalled": "Claude代码未安装", + "error": "检查Claude代码时出错", + "installed": "已安装", + "outdated": "可用更新", + "missing": "未安装", + "current": "当前的", + "latest": "最新的", + "path": "路径", + "lastChecked": "最后检查", + "learnMore": "了解有关Claude Code的更多信息", + "learnMoreAriaLabel": "了解有关Claude Code的更多信息(在新窗口中打开)", + "viewChangelog": "查看Claude代码变更日志", + "viewChangelogAriaLabel": "查看 Claude 代码变更日志(在新窗口中打开)", + "updateWarningTitle": "更新Claude代码?", + "updateWarningDescription": "更新将关闭所有正在运行的 Claude Code 会话。这些会话中任何未保存的工作都可能会丢失。请确保在继续之前保存您的工作。", + "updateWarningTerminalNote": "将打开一个终端窗口以运行安装命令。请等待安装完成后再继续。", + "updateAnyway": "打开终端并更新", + "switchVersion": "切换版本", + "selectVersion": "选择版本", + "loadingVersions": "正在加载版本...", + "failedToLoadVersions": "无法加载版本", + "installingVersion": "正在安装版本 {{version}}...", + "rollbackWarningTitle": "切换到版本 {{version}}?", + "rollbackWarningDescription": "切换版本将关闭所有正在运行的 Claude Code 会话。这些会话中任何未保存的工作都可能会丢失。请确保在继续之前保存您的工作。", + "rollbackWarningTerminalNote": "将打开一个终端窗口以运行安装命令。请等待安装完成后再继续。", + "switchAnyway": "打开终端并切换", + "currentVersion": "当前的", + "switchInstallation": "切换安装", + "selectInstallation": "选择安装", + "loadingInstallations": "正在加载安装...", + "failedToLoadInstallations": "无法加载安装", + "activeInstallation": "活跃", + "pathChangeWarningTitle": "切换 CLI 安装?", + "pathChangeWarningDescription": "切换 CLI 安装将使用不同的 Claude Code 二进制文件。任何正在运行的会话将继续使用以前的安装,直到重新启动。", + "switchInstallationConfirm": "切换", + "versionUnknown": "版本未知" + } +} diff --git a/apps/frontend/src/shared/i18n/locales/zh/onboarding.json b/apps/frontend/src/shared/i18n/locales/zh/onboarding.json new file mode 100644 index 0000000000..c4eeb24087 --- /dev/null +++ b/apps/frontend/src/shared/i18n/locales/zh/onboarding.json @@ -0,0 +1,253 @@ +{ + "wizard": { + "title": "设置向导", + "description": "只需几个简单的步骤即可配置您的 Auto Claude 环境", + "helpText": "该向导将帮助您只需几个步骤即可设置环境。您可以配置 Claude OAuth 令牌、设置内存功能并创建您的第一个任务。" + }, + "welcome": { + "title": "欢迎来到Auto Claude", + "subtitle": "使用人工智能代理自主构建软件", + "getStarted": "开始使用", + "skip": "跳过设置", + "features": { + "aiPowered": { + "title": "人工智能驱动的开发", + "description": "使用 Claude Code 代理生成代码并构建功能" + }, + "specDriven": { + "title": "规范驱动的工作流程", + "description": "定义具有明确规范的任务,并让 Auto Claude 负责实施" + }, + "memory": { + "title": "记忆与背景", + "description": "使用 Graphiti 实现跨会话的持久内存" + }, + "parallel": { + "title": "并行执行", + "description": "并行运行多个代理以加快开发周期" + } + } + }, + "oauth": { + "title": "Claude认证", + "description": "连接您的 Claude 帐户以启用 AI 功能", + "configureTitle": "配置Claude身份验证", + "addAccountsDesc": "添加您的 Claude 帐户以启用 AI 功能", + "multiAccountInfo": "添加多个 Claude 订阅,以便在达到速率限制时自动在它们之间切换。", + "noAccountsYet": "尚未配置帐户", + "badges": { + "default": "默认", + "active": "活跃", + "authenticated": "已认证", + "needsAuth": "需要验证" + }, + "buttons": { + "authenticate": "认证", + "setActive": "设置为活动状态", + "rename": "重命名", + "delete": "删除", + "add": "添加", + "adding": "添加...", + "showToken": "显示代币", + "hideToken": "隐藏令牌", + "copyToken": "复制令牌", + "back": "后退", + "continue": "继续", + "skip": "跳过" + }, + "labels": { + "accountName": "帐户名称", + "namePlaceholder": "配置文件名称(例如工作、个人)", + "tokenLabel": "OAuth 令牌", + "tokenPlaceholder": "在此输入令牌", + "tokenHint": "完成 OAuth 登录后,粘贴终端中显示的令牌。" + }, + "keychainTitle": "安全存储", + "keychainDescription": "您的令牌是使用系统的钥匙串加密的。您可能会看到来自 macOS 的密码提示 - 单击“始终允许”以避免再次看到它。", + "toast": { + "authSuccess": "配置文件已成功验证", + "authSuccessWithEmail": "账户:{{email}}", + "authSuccessGeneric": "认证完成。您现在可以使用此配置文件。", + "authStartFailed": "启动认证失败", + "addProfileFailed": "添加配置文件失败", + "tokenSaved": "令牌已保存", + "tokenSavedDescription": "您的令牌已成功保存。", + "tokenSaveFailed": "保存令牌失败", + "tryAgain": "请再试一次。" + }, + "alerts": { + "profileCreatedAuthFailed": "配置文件已创建,但无法准备身份验证:{{error}}", + "authPrepareFailed": "无法准备身份验证:{{error}}", + "authStartFailedMessage": "无法启动身份验证。请再试一次。" + } + }, + "memory": { + "title": "记忆", + "description": "为代理配置持久跨会话内存", + "contextDescription": "Auto Claude Memory 有助于记住编码过程中的上下文", + "enableMemory": "启用内存", + "enableMemoryDescription": "使用LadybugDB(嵌入式数据库)持久化跨会话内存", + "memoryDisabledInfo": "内存被禁用。会话洞察将仅存储在本地文件中。通过语义搜索启用持久跨会话上下文的内存。", + "enableAgentAccess": "启用代理内存访问", + "enableAgentAccessDescription": "允许代理通过 MCP 搜索并添加到知识图谱", + "mcpServerUrl": "Graphiti MCP 服务器 URL", + "mcpServerUrlDescription": "用于代理内存访问的 Graphiti MCP 服务器的 URL", + "embeddingProvider": "嵌入提供者", + "embeddingProviderDescription": "语义搜索提供程序(可选 - 无需关键字搜索即可工作)", + "selectEmbeddingModel": "选择嵌入模型", + "openaiApiKey": "OpenAI API 密钥", + "openaiApiKeyDescription": "OpenAI 嵌入所需", + "openaiGetKey": "获取您的钥匙", + "voyageApiKey": "Voyage AI API 密钥", + "voyageApiKeyDescription": "Voyage AI 嵌入所需", + "voyageEmbeddingModel": "嵌入模型", + "googleApiKey": "Google AI API 密钥", + "googleApiKeyDescription": "Google AI 嵌入所需", + "azureConfig": "Azure OpenAI 配置", + "azureApiKey": "API密钥", + "azureBaseUrl": "基本网址", + "azureEmbeddingDeployment": "嵌入部署名称", + "memoryInfo": "内存存储有关代码库的发现、模式和洞察,因此未来的会话从已加载的上下文开始。不需要 Docker - 使用嵌入式数据库。", + "learnMore": "了解有关内存的更多信息", + "back": "后退", + "skip": "跳过", + "saving": "保存...", + "saveAndContinue": "保存并继续", + "providers": { + "ollama": "Ollama(当地 - 免费)", + "openai": "OpenAI", + "voyage": "Voyage AI", + "google": "Google AI", + "azure": "Azure OpenAI" + }, + "ollamaConfig": "Ollama配置", + "checking": "检查...", + "connected": "已连接", + "notRunning": "未运行", + "baseUrl": "基本网址", + "embeddingModel": "嵌入模型", + "embeddingDim": "嵌入维度", + "embeddingDimDescription": "Ollama 嵌入所需(例如 nomic-embed-text 为 768)", + "modelRecommendation": "推荐:qwen3-embedding:4b(平衡),:8b(质量),:0.6b(快速)" + }, + "completion": { + "title": "一切就绪!", + "subtitle": "Auto Claude 已准备好帮助您构建令人惊叹的软件", + "setupComplete": "设置完成", + "setupCompleteDescription": "您的环境已配置并准备就绪。您可以立即开始创建任务或按照自己的节奏探索应用程序。", + "whatsNext": "接下来是什么?", + "createTask": { + "title": "创建任务", + "description": "首先创建您的第一个任务来查看 Auto Claude 的实际情况。", + "action": "打开任务创建器" + }, + "customizeSettings": { + "title": "自定义设置", + "description": "微调您的首选项、配置集成或重新运行此向导。", + "action": "打开设置" + }, + "exploreDocs": { + "title": "探索文档", + "description": "了解有关高级功能、最佳实践和故障排除的更多信息。" + }, + "finish": "完成并开始构建", + "rerunHint": "您始终可以从“设置”→“应用程序”重新运行此向导" + }, + "steps": { + "welcome": "欢迎", + "authChoice": "认证方式", + "auth": "授权", + "claudeCode": "CLI", + "devtools": "开发工具", + "privacy": "隐私", + "memory": "记忆", + "done": "完成" + }, + "privacy": { + "title": "帮助改进Auto Claude", + "subtitle": "匿名错误报告可以帮助我们更快地修复错误", + "whatWeCollect": { + "title": "我们收集什么", + "crashReports": "崩溃报告和错误堆栈跟踪", + "errorMessages": "错误消息(文件路径已匿名)", + "appVersion": "应用程序版本和平台信息" + }, + "whatWeNeverCollect": { + "title": "我们从不收集的东西", + "code": "您的代码或项目文件", + "filenames": "完整文件路径(用户名被屏蔽)", + "apiKeys": "API 密钥或令牌", + "personalData": "个人信息或使用数据" + }, + "toggle": { + "label": "发送匿名错误报告", + "description": "帮助我们识别并解决问题" + } + }, + "claudeCode": { + "title": "Claude Code CLI", + "description": "安装或更新 Claude Code CLI 以启用 AI 驱动的功能", + "detecting": "检查Claude代码安装...", + "info": { + "title": "什么是 Claude Code?", + "description": "Claude Code 是 Anthropic 的官方 CLI,为 Auto Claude 的 AI 功能提供支持。它提供安全身份验证和对 Claude 模型的直接访问。" + }, + "status": { + "installed": "已安装", + "outdated": "可用更新", + "notFound": "未安装" + }, + "version": { + "current": "当前版本", + "latest": "最新版本" + }, + "install": { + "button": "安装Claude代码", + "updating": "更新Claude代码", + "inProgress": "正在安装...", + "success": "安装命令发送到终端。请在那里完成安装。", + "instructions": "安装程序将在您的终端中打开。按照提示完成安装。" + }, + "learnMore": "了解有关Claude Code的更多信息" + }, + "devtools": { + "title": "开发者工具", + "description": "选择您喜欢的 IDE 和终端来使用 Auto Claude 工作树", + "detecting": "正在检测已安装的工具...", + "detectAgain": "再次检测", + "whyConfigure": "为什么要配置这些?", + "whyConfigureDescription": "当 Auto Claude 在独立的工作树中构建功能时,您可以直接在您喜欢的 IDE 或终端中打开它们以测试和查看更改。", + "ide": { + "label": "首选IDE", + "description": "Auto Claude 将在此编辑器中打开工作树", + "customPath": "自定义IDE路径" + }, + "terminal": { + "label": "首选终端", + "description": "Auto Claude 将在这里打开终端会话", + "customPath": "自定义终端路径" + }, + "detectedSummary": "在您的系统上检测到:", + "noToolsDetected": "未检测到其他工具(将使用 VS Code 和系统终端)", + "custom": "自定义...", + "saveAndContinue": "保存并继续" + }, + "ollama": { + "notInstalled": { + "title": "Ollama未安装", + "description": "Ollama 为语义搜索提供免费的本地嵌入模型。一键安装即可启用此功能。", + "installSuccess": "安装在您的终端中开始。在那里完成安装,然后单击“重试”。", + "installButton": "安装Ollama", + "installing": "正在安装...", + "retry": "重试", + "learnMore": "了解更多", + "fallbackNote": "即使没有 Ollama,记忆仍然可以用于关键字搜索。" + }, + "notRunning": { + "title": "Ollama 未运行", + "description": "Ollama 已安装但未运行。启动 Ollama 以使用本地嵌入模型。", + "retry": "重试", + "fallbackNote": "即使没有嵌入,内存仍然可以用于关键字搜索。" + } + } +} diff --git a/apps/frontend/src/shared/i18n/locales/zh/settings.json b/apps/frontend/src/shared/i18n/locales/zh/settings.json new file mode 100644 index 0000000000..a567748b30 --- /dev/null +++ b/apps/frontend/src/shared/i18n/locales/zh/settings.json @@ -0,0 +1,905 @@ +{ + "title": "设置", + "tabs": { + "app": "应用程序设置", + "project": "项目设置" + }, + "sections": { + "appearance": { + "title": "外观", + "description": "自定义Auto Claude的外观" + }, + "display": { + "title": "显示", + "description": "调整UI元素的大小" + }, + "language": { + "title": "语言", + "description": "选择您的首选语言" + }, + "devtools": { + "title": "开发者工具", + "description": "IDE 和终端首选项" + }, + "agent": { + "title": "代理设置", + "description": "默认模型和框架" + }, + "paths": { + "title": "路径", + "description": "CLI 工具和框架路径" + }, + "accounts": { + "title": "账户", + "description": "Claude 帐户和 API 端点" + }, + "updates": { + "title": "更新", + "description": "Auto Claude更新" + }, + "notifications": { + "title": "通知", + "description": "警报首选项" + }, + "debug": { + "title": "调试和日志", + "description": "故障排除工具" + }, + "terminal-fonts": { + "title": "终端字体", + "description": "自定义终端字体外观" + } + }, + "apiProfiles": { + "title": "API 配置文件", + "description": "配置与 Anthropic 兼容的自定义 API 端点", + "addButton": "添加配置文件", + "presets": { + "anthropic": "Anthropic", + "openrouter": "OpenRouter", + "groq": "Groq", + "zaiGlobal": "z.AI(全球)", + "zaiChina": "z.AI(中国)" + }, + "fields": { + "name": "名称", + "preset": "预设", + "baseUrl": "基本网址", + "apiKey": "API密钥" + }, + "placeholders": { + "name": "我的自定义 API", + "preset": "选择提供商预设", + "baseUrl": "https://api.anthropic.com", + "apiKey": "sk-ant-..." + }, + "hints": { + "preset": "预设填充基本 URL;您仍然需要粘贴您的 API 密钥。", + "baseUrl": "示例:https://api.anthropic.com 或 http://localhost:8080" + }, + "validation": { + "nameRequired": "名称为必填项", + "baseUrlRequired": "基本 URL 为必填项", + "baseUrlInvalid": "URL 格式无效(必须是 http:// 或 https://)", + "apiKeyRequired": "需要 API 密钥", + "apiKeyInvalid": "API 密钥格式无效" + }, + "actions": { + "save": "保存配置文件", + "saving": "保存...", + "cancel": "取消", + "changeKey": "改变", + "cancelKeyChange": "取消" + }, + "testConnection": { + "label": "测试连接", + "testing": "测试...", + "success": "连接成功", + "failure": "连接失败" + }, + "models": { + "title": "可选:模型名称映射", + "description": "从您的 API 提供商处选择模型。留空以使用默认值。", + "defaultLabel": "默认模型(可选)", + "haikuLabel": "俳句模型(可选)", + "sonnetLabel": "Sonnet 模型(可选)", + "opusLabel": "Opus 模型(可选)", + "defaultPlaceholder": "例如,claude-sonnet-4-5-20250929", + "haikuPlaceholder": "例如,claude-haiku-4-5-20251001", + "sonnetPlaceholder": "例如,claude-sonnet-4-5-20250929", + "opusPlaceholder": "例如,Claude-opus-4-6", + "opus1mPlaceholder": "例如,claude-opus-4-6(1M 上下文)" + }, + "empty": { + "title": "未配置 API 配置文件", + "description": "创建配置文件来为您的构建配置自定义 API 端点。", + "action": "创建第一个配置文件" + }, + "switchToOauth": { + "label": "切换到 OAuth", + "loading": "切换中..." + }, + "activeBadge": "活跃", + "customModels": "自定义模型:{{models}}", + "setActive": { + "label": "设置为活动状态", + "loading": "设置中..." + }, + "tooltips": { + "edit": "编辑配置文件", + "deleteActive": "删除前切换到 OAuth", + "deleteInactive": "删除配置文件" + }, + "deleteAriaLabel": "删除配置文件 {{name}}", + "toast": { + "create": { + "title": "配置文件已创建", + "description": "“{{name}}”已成功添加。" + }, + "update": { + "title": "配置文件已更新", + "description": "“{{name}}”已成功更新。" + }, + "delete": { + "title": "配置文件已删除", + "description": "“{{name}}”已被删除。", + "errorTitle": "删除配置文件失败", + "errorFallback": "删除配置文件时出错。" + }, + "switch": { + "oauthTitle": "切换到 OAuth", + "oauthDescription": "现在使用 OAuth 身份验证", + "profileTitle": "配置文件已激活", + "profileDescription": "现在使用 {{name}}", + "errorTitle": "切换认证失败", + "errorFallback": "切换身份验证方法时出错。" + } + }, + "dialog": { + "createTitle": "添加API配置文件", + "editTitle": "编辑配置文件", + "description": "为您的构建配置自定义的与 Anthropic 兼容的 API 端点。", + "deleteTitle": "删除配置文件?", + "deleteDescription": "您确定要删除“{{name}}”吗?此操作无法撤消。", + "cancel": "取消", + "delete": "删除", + "deleting": "正在删除..." + } + }, + "modelSelect": { + "placeholder": "手动选择模型或类型", + "placeholderManual": "输入模型名称(例如 claude-sonnet-4-5-20250929)", + "searchPlaceholder": "搜索模型...", + "noResults": "没有符合您搜索的模型", + "discoveryNotAvailable": "模型发现不可用。手动输入模型名称。" + }, + "language": { + "label": "界面语言", + "description": "选择应用程序界面的语言" + }, + "scale": { + "presets": "缩放预设", + "presetsDescription": "满足常见偏好的快速缩放选项", + "fineTune": "微调比例", + "fineTuneDescription": "从 75% 调整到 200%,增量为 5%", + "default": "默认", + "comfortable": "舒适", + "large": "大" + }, + "logOrder": { + "label": "日志顺序", + "description": "选择日志在任务详细信息视图中的显示方式", + "chronological": "按时间顺序(最早的在前)", + "reverseChronological": "按时间倒序排列(最新的在前)" + }, + "gpuAcceleration": { + "label": "GPU加速", + "description": "使用 WebGL 进行终端渲染(实验性的,在许多终端上速度更快)", + "auto": "自动(支持时使用 WebGL)", + "on": "始终开启", + "off": "关闭(默认)", + "helperText": "更改仅适用于新终端" + }, + "general": { + "otherAgentSettings": "其他代理设置", + "otherAgentSettingsDescription": "其他代理配置选项", + "agentFramework": "代理框架", + "agentFrameworkDescription": "用于自主任务的编码框架", + "agentFrameworkAutoClaude": "Auto Claude", + "aiTerminalNaming": "AI终端命名", + "aiTerminalNamingDescription": "根据命令自动命名终端(使用 Haiku)", + "featureModelSettings": "特征模型设置", + "featureModelSettingsDescription": "洞察、构想和路线图的模型和思维水平", + "model": "模型", + "thinkingLevel": "思维层面", + "paths": "路径", + "pathsDescription": "配置可执行文件和框架路径", + "pythonPath": "Python路径", + "pythonPathDescription": "Python 可执行文件的路径(留空以供自动检测)", + "pythonPathPlaceholder": "python3(默认)", + "gitPath": "git路径", + "gitPathDescription": "Git 可执行文件的路径(留空以供自动检测)", + "gitPathPlaceholder": "git(默认)", + "githubCLIPath": "GitHub CLI 路径", + "githubCLIPathDescription": "GitHub CLI (gh) 可执行文件的路径(留空以进行自动检测)", + "githubCLIPathPlaceholder": "gh(默认)", + "gitlabCLIPath": "GitLab CLI路径", + "gitlabCLIPathDescription": "GitLab CLI (glab) 可执行文件的路径(留空以进行自动检测)", + "gitlabCLIPathPlaceholder": "glab(默认)", + "claudePath": "Claude CLI 路径", + "claudePathDescription": "Claude CLI 可执行文件的路径(留空以供自动检测)", + "claudePathPlaceholder": "Claude(默认)", + "detectedPath": "自动检测", + "detectedVersion": "版本", + "detectedSource": "来源", + "sourceUserConfig": "用户配置", + "sourceVenv": "虚拟环境", + "sourceHomebrew": "Homebrew", + "sourceNvm": "NVM", + "sourceSystemPath": "系统路径", + "sourceBundled": "内置", + "sourceFallback": "回退", + "notDetected": "未检测到", + "autoClaudePath": "Auto Claude路径", + "autoClaudePathDescription": "项目中 auto-claude 目录的相对路径", + "autoClaudePathPlaceholder": "Auto Claude(默认)", + "autoNameTerminals": "自动命名终端", + "autoNameTerminalsDescription": "使用 AI 根据终端选项卡的活动生成描述性名称" + }, + "theme": { + "title": "外观", + "description": "自定义Auto Claude的外观", + "mode": "模式", + "modeDescription": "选择浅色和深色主题", + "light": "浅色", + "dark": "深色", + "system": "系统", + "colorTheme": "颜色主题", + "colorThemeDescription": "选择您喜欢的调色板" + }, + "devtools": { + "title": "开发者工具", + "description": "配置您的首选 IDE、终端和终端字体设置", + "detecting": "正在检测已安装的工具...", + "detectAgain": "再次检测", + "tabTools": "工具", + "tabTerminalFonts": "终端字体", + "ide": { + "label": "首选IDE", + "description": "Auto Claude 将在此编辑器中打开工作树", + "placeholder": "选择IDE...", + "customPath": "自定义IDE路径", + "customPathPlaceholder": "/路径/到/你的/ide" + }, + "terminal": { + "label": "首选终端", + "description": "Auto Claude 将在这里打开终端会话", + "placeholder": "选择终端...", + "customPath": "自定义终端路径", + "customPathPlaceholder": "/路径/到/您的/终端" + }, + "detected": "检测到", + "notInstalled": "未安装", + "detectedSummary": "在您的系统上检测到:", + "noToolsDetected": "未检测到其他工具(将使用 VS Code 和系统终端)", + "autoNameClaude": { + "label": "自动命名Claude终端", + "description": "使用 AI 根据您的第一条消息为 Claude 终端生成描述性名称" + }, + "yoloMode": { + "label": "YOLO模式", + "description": "使用 --dangerously-skip-permissions 标志启动 Claude,绕过所有安全提示。请务必谨慎使用。", + "warning": "这种模式绕过了Claude的权限系统。仅当您完全信任正在执行的代码时才启用。" + } + }, + "updates": { + "title": "更新", + "description": "管理Auto Claude更新", + "appUpdateReady": "应用程序更新准备就绪", + "newVersion": "新版本", + "released": "已发布", + "downloading": "正在下载...", + "updateDownloaded": "更新已下载!单击“安装”重新启动并应用更新。", + "installAndRestart": "安装并重新启动", + "downloadUpdate": "下载更新", + "version": "版本", + "loading": "加载中...", + "checkingForUpdates": "正在检查更新...", + "newVersionAvailable": "新版本可用:", + "latestVersion": "您正在运行最新版本。", + "viewRelease": "在 GitHub 上查看完整版本", + "unableToCheck": "无法检查更新", + "checkForUpdates": "检查更新", + "autoUpdateProjects": "自动更新项目", + "autoUpdateProjectsDescription": "当有新版本可用时自动更新项目中的 Auto Claude", + "betaUpdates": "测试版更新", + "betaUpdatesDescription": "接收具有新功能的预发布测试版(可能不太稳定)", + "stableDowngradeAvailable": "稳定版本可用", + "stableDowngradeDescription": "您目前使用的是测试版。由于您已禁用测试版更新,因此您可以切换到最新的稳定版本。", + "stableVersion": "稳定版", + "downloadStableVersion": "下载稳定版本", + "readOnlyVolumeTitle": "无法从磁盘映像安装", + "readOnlyVolumeDescription": "Auto Claude 正在从只读磁盘映像 (DMG) 运行。请将应用程序拖到您的应用程序文件夹中,然后从那里重新启动它以安装更新。", + "downloadError": "下载更新失败" + }, + "notifications": { + "title": "通知", + "description": "配置默认通知首选项", + "onTaskComplete": "任务完成时", + "onTaskCompleteDescription": "任务成功完成时通知", + "onTaskFailed": "任务失败时", + "onTaskFailedDescription": "当任务遇到错误时发出通知", + "onReviewNeeded": "需要审查", + "onReviewNeededDescription": "当 QA 需要您进行审核时通知", + "sound": "声音", + "soundDescription": "播放带有通知的声音" + }, + "actions": { + "save": "保存设置", + "rerunWizard": "重新运行向导", + "rerunWizardDescription": "再次启动设置向导" + }, + "projectSections": { + "general": { + "title": "常规", + "description": "自动构建和代理配置", + "useClaudeMd": "使用 CLAUDE.md", + "useClaudeMdDescription": "在代理上下文中包含 CLAUDE.md 指令" + }, + "claude": { + "title": "Claude 认证", + "description": "Claude 认证" + }, + "linear": { + "title": "Linear", + "description": "Linear 集成", + "integrationTitle": "Linear 集成", + "integrationDescription": "连接到 Linear 以进行问题跟踪和任务导入", + "syncDescription": "与 Linear 同步以进行问题跟踪" + }, + "github": { + "title": "GitHub", + "description": "GitHub 问题同步", + "integrationTitle": "GitHub 集成", + "integrationDescription": "连接到 GitHub 以进行问题跟踪", + "syncDescription": "与 GitHub 问题同步", + "defaultBranch": { + "label": "默认分支", + "description": "用于创建任务工作树的基础分支", + "autoDetect": "自动检测(主/主)", + "searchPlaceholder": "搜索分支...", + "noBranchesFound": "没有找到分支", + "selectedBranchHelp": "所有新任务将从 {{branch}} 分支" + } + }, + "gitlab": { + "title": "GitLab", + "description": "GitLab 问题同步", + "integrationTitle": "集成", + "integrationDescription": "连接到 GitLab 进行问题跟踪", + "syncDescription": "与 GitLab 问题同步" + }, + "memory": { + "title": "记忆", + "description": "Graphiti 内存后端", + "integrationTitle": "记忆", + "integrationDescription": "为代理配置持久跨会话内存", + "syncDescription": "配置持久内存" + } + }, + "agentProfile": { + "label": "代理配置", + "title": "默认代理配置文件", + "sectionDescription": "选择模型和思维水平的预设配置", + "profilesInfo": "代理配置文件为Claude模型和思维水平提供预设配置。当您创建新任务时,这些设置将用作默认值。您始终可以在任务创建向导中覆盖它们。", + "custom": "自定义", + "customConfiguration": "自定义配置", + "customDescription": "选择模型和思维水平", + "phaseConfiguration": "相位配置", + "phaseConfigurationDescription": "为每个阶段定制模型和思维水平", + "clickToCustomize": "点击定制", + "model": "模型", + "thinking": "思维", + "thinkingLevel": "思维层面", + "selectModel": "选择模型", + "selectThinkingLevel": "选择思维层次", + "perPhaseOptimization": "(每阶段优化)", + "resetToDefaults": "重置为默认值", + "resetToProfileDefaults": "重置为 {{profile}} 默认值", + "customized": "定制", + "phaseConfigNote": "使用此配置文件创建新任务时,这些设置将用作默认设置。您可以在任务创建向导中按任务覆盖它们。", + "adaptiveThinking": { + "badge": "自适应", + "tooltip": "Opus 使用适应性思维——它动态地决定在思维水平设定的预算上限内思考多少。" + }, + "phases": { + "spec": { + "label": "规格创建", + "description": "发现、需求、背景收集" + }, + "planning": { + "label": "规划", + "description": "实施规划和架构" + }, + "coding": { + "label": "编码", + "description": "实际代码实现" + }, + "qa": { + "label": "质量检查审查", + "description": "质量保证和验证" + } + } + }, + "workspace": { + "roles": { + "backend": "后端", + "frontend": "前端", + "mobile": "移动端", + "shared": "共享", + "apiGateway": "API 网关", + "worker": "Worker", + "other": "其他" + } + }, + "integrations": { + "title": "集成", + "description": "管理 Claude 帐户和 API 密钥", + "claudeAccounts": "Claude帐户", + "claudeAccountsDescription": "添加多个 Claude 订阅,以便在达到速率限制时自动在它们之间切换。", + "claudeAccountsWarning": "进行身份验证时,请确保您在浏览器中登录到正确的 Claude 帐户。每个配置文件应使用不同的订阅。", + "noAccountsYet": "尚未配置帐户", + "default": "默认", + "active": "活跃", + "authenticated": "已认证", + "needsAuth": "需要验证", + "authenticate": "认证", + "authenticating": "正在验证...", + "setActive": "设置为活动状态", + "manualTokenEntry": "手动输入令牌", + "runSetupToken": "运行 claude 并输入 /login 进行身份验证", + "tokenPlaceholder": "sk-ant-oat01-...", + "emailPlaceholder": "电子邮件(可选,用于显示)", + "saveToken": "保存令牌", + "accountNamePlaceholder": "帐户名称(例如工作、个人)", + "autoSwitching": "自动账户切换", + "autoSwitchingDescription": "自动在 Claude 帐户之间切换以避免中断。配置主动监控以在达到限制之前进行切换。", + "enableAutoSwitching": "启用自动切换", + "masterSwitch": "所有自动交换功能的主开关", + "proactiveMonitoring": "主动监控", + "proactiveDescription": "定期检查使用情况并在达到限制之前进行交换", + "checkUsageEvery": "检查使用情况", + "seconds15": "15秒", + "seconds30": "30 秒(推荐)", + "minute1": "1分钟", + "disabled": "已禁用", + "sessionThreshold": "会话使用阈值", + "sessionThresholdDescription": "当会话使用率达到此水平时进行切换(建议:95%)", + "weeklyThreshold": "每周使用阈值", + "weeklyThresholdDescription": "当每周使用量达到此水平时进行切换(建议:99%)", + "reactiveRecovery": "反应性恢复", + "reactiveDescription": "达到意外速率限制时自动交换", + "autoSwitchOnAuthFailure": "身份验证失败时自动切换", + "autoSwitchOnAuthFailureDescription": "认证失败时自动切换到另一个认证帐户", + "apiKeys": "API 密钥", + "apiKeysInfo": "此处设置的键用作默认值。各个项目可以在其设置中覆盖这些内容。", + "openaiKey": "OpenAI API 密钥", + "openaiKeyDescription": "Graphiti 内存后端(嵌入)所需", + "toast": { + "authSuccess": "配置文件已验证", + "authSuccessWithEmail": "连接为 {{email}}", + "authSuccessGeneric": "认证完成。您现在可以使用此配置文件。", + "authStartFailed": "认证失败", + "addProfileFailed": "添加配置文件失败", + "loadProfilesFailed": "加载配置文件失败", + "deleteProfileFailed": "删除配置文件失败", + "renameProfileFailed": "重命名配置文件失败", + "setActiveProfileFailed": "无法设置活动配置文件", + "profileCreatedAuthFailed": "配置文件已创建 - 需要身份验证", + "profileCreatedAuthFailedDescription": "配置文件已添加,但身份验证无法启动。单击登录按钮进行身份验证。", + "tokenSaved": "令牌已保存", + "tokenSavedDescription": "您的令牌已成功保存。", + "tokenSaveFailed": "保存令牌失败", + "settingsUpdateFailed": "更新设置失败", + "tryAgain": "请再试一次。", + "terminalCreationFailed": "创建认证终端失败", + "terminalCreationFailedDescription": "无法启动身份验证过程。 {{error}}", + "maxTerminalsReached": "已达到最大终端数量", + "maxTerminalsReachedDescription": "请关闭一些终端并重试。您最多可以打开 12 个终端。", + "terminalError": "终端错误", + "terminalErrorDescription": "无法创建终端:{{error}}", + "authProcessFailed": "身份验证过程无法启动", + "authProcessFailedDescription": "无法创建认证终端。请重试或检查日志以了解更多详细信息。" + }, + "alerts": { + "profileCreatedAuthFailed": "配置文件已创建,但无法准备身份验证:{{error}}", + "authPrepareFailed": "无法准备身份验证:{{error}}", + "authStartFailedMessage": "无法启动身份验证。请再试一次。" + } + }, + "accounts": { + "title": "账户", + "description": "管理 Claude 帐户和 API 端点", + "tabs": { + "claudeCode": "Claude Code", + "customEndpoints": "自定义端点" + }, + "claudeCode": { + "description": "添加多个 Claude 订阅,以便在达到速率限制时自动在它们之间切换。", + "noAccountsYet": "尚未配置帐户", + "default": "默认", + "active": "活跃", + "authenticated": "已认证", + "needsAuth": "需要验证", + "authenticate": "认证", + "authenticating": "正在验证...", + "setActive": "设置为活动状态", + "manualTokenEntry": "手动输入令牌", + "runSetupToken": "运行 claude 并输入 /login 进行身份验证", + "tokenPlaceholder": "sk-ant-oat01-...", + "emailPlaceholder": "电子邮件(可选,用于显示)", + "saveToken": "保存令牌", + "accountNamePlaceholder": "帐户名称(例如工作、个人)" + }, + "customEndpoints": { + "description": "配置与 Anthropic 兼容的自定义 API 端点", + "addButton": "添加配置文件", + "activeBadge": "活跃", + "customModels": "自定义模型:{{models}}", + "setActive": { + "label": "设置为活动状态", + "loading": "设置中..." + }, + "switchToOauth": { + "label": "使用Claude代码", + "loading": "切换中..." + }, + "tooltips": { + "edit": "编辑配置文件", + "deleteActive": "无法删除活动配置文件", + "deleteInactive": "删除配置文件" + }, + "empty": { + "title": "无自定义端点", + "description": "配置与 Anthropic 兼容的自定义 API 端点以使用替代提供程序。", + "action": "添加配置文件" + }, + "dialog": { + "deleteTitle": "删除配置文件", + "deleteDescription": "您确定要删除“{{name}}”吗?此操作无法撤消。", + "cancel": "取消", + "delete": "删除", + "deleting": "正在删除..." + } + }, + "autoSwitching": { + "title": "自动账户切换", + "description": "自动在帐户之间切换以避免中断。配置主动监控以在达到限制之前进行切换。", + "enableAutoSwitching": "启用自动切换", + "masterSwitch": "所有自动交换功能的主开关", + "proactiveMonitoring": "主动监控", + "proactiveDescription": "定期检查使用情况并在达到限制之前进行交换", + "sessionThreshold": "会话使用阈值", + "sessionThresholdDescription": "当会话使用率达到此水平时进行切换(建议:95%)", + "weeklyThreshold": "每周使用阈值", + "weeklyThresholdDescription": "当每周使用量达到此水平时进行切换(建议:99%)", + "reactiveRecovery": "反应性恢复", + "reactiveDescription": "达到意外速率限制时自动交换", + "autoSwitchOnAuthFailure": "身份验证失败时自动切换", + "autoSwitchOnAuthFailureDescription": "认证失败时自动切换到另一个认证帐户" + }, + "priority": { + "title": "账户优先顺序", + "description": "拖动以重新排序。系统将按顺序切换到下一个可用帐户。", + "noAccounts": "没有配置帐户。添加上面的帐户以设置优先级。", + "noEmail": "没有电子邮件", + "active": "活跃", + "inUse": "使用中", + "next": "下一个", + "unlimited": "无限", + "unavailable": "不可用", + "typeOAuth": "OAuth", + "typeAPI": "API", + "payPerUse": "按使用付费", + "needsAuth": "未经过验证", + "duplicateUsage": "检测到重复使用", + "duplicateUsageHint": "此配置文件与另一个配置文件具有相同的用法,表明它们可能已通过同一 Anthropic 帐户进行身份验证。使用不同的帐户重新进行身份验证以修复。", + "needsReauth": "需要重新授权", + "needsReauthHint": "此配置文件的刷新令牌无效。单击以重新验证。", + "sessionUsage": "会话使用情况(5 小时窗口)", + "weeklyUsage": "每周使用量(7 天窗口)", + "oauthSection": "Claude帐户(先循环)", + "apiSection": "回退端点(当所有帐户都用尽时)", + "tipTitle": "优先级如何运作", + "tipDescription": "Claude帐户包含在您的订阅中,并将首先循环使用。 API 端点按请求收费,并在所有 Claude 帐户达到限制时用作后备。", + "status": { + "healthy": "健康", + "moderate": "适中", + "highUsage": "使用率高", + "nearLimit": "接近极限", + "rateLimited": "速率有限" + } + }, + "toast": { + "loadProfilesFailed": "加载配置文件失败", + "addProfileFailed": "添加配置文件失败", + "deleteProfileFailed": "删除配置文件失败", + "renameProfileFailed": "重命名配置文件失败", + "setActiveProfileFailed": "无法设置活动配置文件", + "tokenSaved": "令牌已保存", + "tokenSavedDescription": "您的令牌已成功保存。", + "tokenSaveFailed": "保存令牌失败", + "settingsUpdateFailed": "更新设置失败", + "tryAgain": "请再试一次。" + }, + "alerts": { + "profileCreatedAuthFailed": "配置文件已创建,但无法准备身份验证:{{error}}", + "authPrepareFailed": "无法准备身份验证:{{error}}", + "authStartFailedMessage": "无法启动身份验证。请再试一次。" + } + }, + "debug": { + "title": "调试和日志", + "description": "访问日志和调试信息以进行故障排除", + "errorReporting": { + "label": "匿名错误报告", + "description": "发送崩溃报告以帮助改进 Auto Claude。不会收集任何个人数据或代码。" + }, + "openLogsFolder": "打开日志文件夹", + "copyDebugInfo": "复制调试信息", + "copied": "复制了!", + "loadInfo": "加载调试信息", + "systemInfo": "系统信息", + "logsLocation": "日志位置", + "recentErrors": "最近的错误", + "noRecentErrors": "最近没有错误", + "helpTitle": "报告问题", + "helpText": "报告错误时,单击“复制调试信息”即可获取系统信息和最近的错误,以帮助我们诊断问题。" + }, + "projectSettings": { + "noProjectSelected": { + "title": "未选择项目", + "description": "从侧栏中选择一个项目以配置其设置。" + } + }, + "mcp": { + "title": "MCP 服务器概述", + "titleWithProject": "{{projectName}} 的 MCP 服务器概述", + "description": "配置哪些 MCP 服务器可用于此项目中的代理", + "descriptionNoProject": "选择一个项目来配置 MCP 服务器", + "serversEnabled": "{{count}} 服务器已启用", + "configuration": "MCP 服务器配置", + "configurationHint": "禁用的服务器会减少上下文使用和启动时间", + "noProjectSelected": "未选择项目", + "noProjectSelectedDescription": "从下拉列表中选择一个项目以查看和配置 MCP 服务器。", + "projectNotInitialized": "项目未初始化", + "projectNotInitializedDescription": "为此项目初始化 Auto Claude 以配置 MCP 服务器。", + "browserAutomation": "浏览器自动化(仅限 QA 代理)", + "alwaysEnabled": "始终启用", + "addServer": "添加服务器", + "addMcpTo": "将 MCP 服务器添加到 {{agent}}", + "addMcpDescription": "选择要添加到此代理的 MCP 服务器", + "allMcpsAdded": "所有可用的 MCP 服务器均已添加", + "added": "已添加", + "removed": "已删除", + "remove": "移除", + "restore": "恢复", + "noMcpServers": "没有 MCP 服务器", + "cannotRemove": "无法删除(必填)", + "servers": { + "context7": { + "name": "Context7", + "description": "库的文档查找" + }, + "graphiti": { + "name": "Graphiti 内存", + "description": "跨会话上下文的知识图谱", + "notConfigured": "需要内存配置(请参阅内存设置)" + }, + "linear": { + "name": "Linear", + "description": "项目管理集成", + "notConfigured": "需要 Linear 集成(请参阅 Linear 设置)" + }, + "electron": { + "name": "Electron", + "description": "通过 Chrome DevTools 实现桌面应用自动化" + }, + "puppeteer": { + "name": "Puppeteer", + "description": "用于测试的 Web 浏览器自动化" + }, + "autoClaude": { + "name": "Auto Claude工具", + "description": "构建进度跟踪" + } + }, + "customServers": "定制服务器", + "addCustomServer": "添加自定义服务器", + "editCustomServer": "编辑自定义服务器", + "customServerDescription": "添加基于命令或基于 HTTP 的 MCP 服务器", + "serverType": "服务器类型", + "typeCommand": "命令(npx/npm)", + "typeHttp": "HTTP协议", + "serverName": "名称", + "serverNamePlaceholder": "我的 MCP 服务器", + "serverDescription": "描述", + "serverDescriptionPlaceholder": "该服务器的作用", + "command": "命令", + "args": "参数", + "argsHint": "以空格分隔的参数", + "url": "网址", + "headers": "标头", + "headerName": "标头名称", + "headerValue": "标头值", + "noCustomServers": "未配置自定义服务器。添加一个与您的代理一起使用。", + "errorNameRequired": "服务器名称为必填项", + "errorIdExists": "具有此 ID 的服务器已存在", + "errorCommandRequired": "基于命令的服务器需要命令", + "errorUrlRequired": "基于 HTTP 的服务器需要 URL", + "testConnection": "测试", + "testing": "测试...", + "authToken": "身份验证令牌", + "authTokenPlaceholder": "将您的 API 令牌或 PAT 粘贴到此处", + "authTokenHint": "用作授权标头中的承载令牌", + "advancedHeaders": "附加标头", + "status": { + "healthy": "服务器正在响应", + "unhealthy": "服务器没有响应", + "needsAuth": "需要身份验证", + "checking": "检查...", + "unknown": "状态未知" + }, + "hints": { + "github": "这看起来像一个 GitHub MCP 服务器。您需要具有适当范围的个人访问令牌。", + "createGithubPat": "创建 GitHub PAT", + "google": "这看起来像 Google API。您将需要 OAuth 令牌或 API 密钥。", + "createGoogleToken": "创建谷歌凭证", + "anthropic": "这看起来像一个 Anthropic API。您需要一个 API 密钥。", + "createAnthropicKey": "创建 Anthropic API 密钥", + "openai": "这看起来像一个 OpenAI API。您需要一个 API 密钥。", + "createOpenaiKey": "创建 OpenAI API 密钥" + } + }, + "terminalFonts": { + "title": "终端字体", + "description": "自定义终端字体外观和行为", + "configActions": "配置:", + "export": "导出 JSON", + "import": "导入 JSON", + "copy": "复制到剪贴板", + "fontConfig": { + "title": "字体配置", + "description": "自定义字体系列、大小、粗细、行高和字母间距", + "fontFamily": "字体", + "fontFamilyDescription": "终端文本的主要等宽字体", + "selectFont": "选择字体...", + "searchFont": "搜索字体...", + "noFonts": "没有找到字体", + "fontChain": "字体链:", + "fontSize": "字体大小", + "fontSizeDescription": "基本字体大小(以像素为单位)(10-24px)", + "decreaseFontSize": "将字体大小减小 {{step}}px", + "increaseFontSize": "将字体大小增加 {{step}}px", + "pixels": "像素", + "fontWeight": "字体粗细", + "fontWeightDescription": "字体粗细从 100(细)到 900(黑色),步长为 100", + "commonWeights": "常见:400(普通)、600(半粗体)、700(粗体)", + "decreaseFontWeight": "将字体粗细减少 {{step}}", + "increaseFontWeight": "将字体粗细增加 {{step}}", + "lineHeight": "行高", + "lineHeightDescription": "行高为字体大小的倍数 (1.0-2.0)", + "letterSpacing": "字母间距", + "letterSpacingDescription": "字符之间的水平间距(-2 到 5px)" + }, + "cursorConfig": { + "title": "光标配置", + "description": "自定义光标样式、闪烁行为和强调色", + "cursorStyle": "光标样式", + "cursorStyleDescription": "选择终端光标的外观", + "selectStyle": "选择光标样式...", + "currentStyle": "当前的:", + "styleBlock": "方块", + "styleBlockDescription": "全块光标", + "styleUnderline": "下划线", + "styleUnderlineDescription": "下划线光标", + "styleBar": "竖线", + "styleBarDescription": "竖线光标", + "cursorBlink": "光标闪烁", + "cursorBlinkDescription": "启用或禁用光标闪烁动画", + "blinkStatus": "状态:", + "enabled": "启用", + "disabled": "已禁用", + "cursorAccentColor": "光标强调色", + "cursorAccentColorDescription": "选择终端光标的颜色", + "cursorColorLabel": "光标强调色", + "cursorColorDescription": "当前颜色:{{color}}", + "pickColor": "单击以选择颜色", + "resetColor": "重置为黑色", + "reset": "重置", + "preview": "预览:" + }, + "performanceConfig": { + "title": "性能设置", + "description": "调整回滚限制和其他与性能相关的设置", + "presets": "快速预设", + "presetsDescription": "不同用例的常见回滚限制", + "scrollback": "回滚限制", + "scrollbackDescription": "终端历史记录中保留的最大行数", + "scrollbackPresets": "快速预设", + "presetMinimal": "最小", + "presetMinimalDescription": "最小历史记录(1K 行)", + "presetStandard": "标准", + "presetStandardDescription": "标准历史记录(10K 行)", + "presetExtended": "扩展", + "presetExtendedDescription": "扩展历史记录(50K 行)", + "presetMaximum": "最大限度", + "presetMaximumDescription": "最大历史记录(100K 行)", + "decreaseScrollback": "将回滚减少 {{step}}", + "increaseScrollback": "将回滚增加 {{step}}", + "lines": "行", + "kValue": "{{value}}K", + "scrollbackValue": "{{value}} 行" + }, + "presets": { + "title": "快速预设", + "description": "应用预配置的终端字体设置或保存您自己的", + "builtin": "内置预设", + "builtinDescription": "单击以应用预先配置的预设", + "vscode": "Consolas 14px,块光标", + "vscodeName": "VS Code", + "intellij": "JetBrains Mono 13px,块光标", + "intellijName": "IntelliJ IDEA", + "macos": "SF Mono 13px,块光标", + "macosName": "macOS 终端", + "ubuntu": "Ubuntu Mono 13px,块光标", + "ubuntuName": "Ubuntu 终端", + "reset": "重置为默认值", + "resetDescription": "恢复操作系统的默认设置", + "resetToOS": "重置为 {{os}} 默认值", + "resetButton": "重置为操作系统默认值", + "custom": "自定义预设", + "customDescription": "将当前配置保存为自定义预设", + "presetNamePlaceholder": "预设名称...", + "savePreset": "将当前配置保存为预设", + "applyPreset": "应用此预设", + "deletePreset": "删除该预设", + "noCustomPresets": "还没有自定义预设。保存当前配置以开始使用。", + "duplicateName": "同名的预设已存在", + "saved": "预设“{{name}}”已保存", + "deleted": "预设“{{name}}”已删除", + "unknownFont": "未知", + "applyFailed": "无法应用预设“{{name}}”", + "presetNameLabel": "预设名称", + "summary": "{{font}}、{{size}}px、{{cursor}} 光标" + }, + "preview": { + "title": "实时预览", + "description": "实时预览您的终端设置(300毫秒内更新)", + "ariaLabel": "终端字体预览", + "infoText": "此预览会在任何更改后 300 毫秒内更新,以显示您的设置在实际终端中的外观。" + }, + "importExport": { + "exportSuccess": "设置导出成功", + "exportFailed": "导出设置失败", + "importSuccess": "设置导入成功", + "importFailed": "导入设置失败:JSON 格式无效", + "importFailedRange": "导入设置失败:值超出有效范围", + "copySuccess": "设置已复制到剪贴板", + "copyFailed": "无法复制到剪贴板", + "fileTooLarge": "导入文件太大(最大 10KB)", + "readError": "读取文件失败" + }, + "slider": { + "decrease": "将 {{label}} 减少 {{step}}", + "increase": "将 {{label}} 增加 {{step}}", + "currentValue": "当前值:{{value}}" + } + }, + "agents": { + "pr_template_filler": { + "label": "PR 模板填充", + "description": "AI 通过代码更改填充 GitHub PR 模板" + } + } +} diff --git a/apps/frontend/src/shared/i18n/locales/zh/taskReview.json b/apps/frontend/src/shared/i18n/locales/zh/taskReview.json new file mode 100644 index 0000000000..ccfed09b5e --- /dev/null +++ b/apps/frontend/src/shared/i18n/locales/zh/taskReview.json @@ -0,0 +1,136 @@ +{ + "terminal": { + "openTerminal": "打开终端", + "openInbuilt": "在内置终端中打开", + "openExternal": "在外部终端中打开" + }, + "merge": { + "branchHasNewCommits": "{{branch}} 分支有 {{count}} 新提交。", + "branchHasNewCommits_other": "{{branch}} 分支有 {{count}} 新提交。", + "branchHasNewCommitsSinceWorktree": "自创建此工作树以来,{{branch}} 分支有 {{count}} 新提交。", + "branchHasNewCommitsSinceWorktree_other": "自创建此工作树以来,{{branch}} 分支有 {{count}} 新提交。", + "filesNeedMerging": "{{count}} 文件需要合并。", + "filesNeedMerging_other": "{{count}} 文件需要合并。", + "filesNeedIntelligentMerging": "{{count}} 文件需要智能合并:", + "filesNeedIntelligentMerging_other": "{{count}} 文件需要智能合并:", + "branchHasNewCommitsSinceBuild": "自此构建开始以来,{{branch}} 分支有 {{count}} 新提交。", + "branchHasNewCommitsSinceBuild_other": "自此构建开始以来,{{branch}} 分支有 {{count}} 新提交。", + "filesNeedAIMergeDueToRenames": "由于 {{renameCount}} 文件重命名,{{count}} 文件需要 AI 合并。", + "filesNeedAIMergeDueToRenames_other": "由于 {{renameCount}} 文件重命名,{{count}} 文件需要 AI 合并。", + "filesNeedAIMergeDueToRenamesPlural": "由于 {{renameCount}} 文件重命名,{{count}} 文件需要 AI 合并。", + "filesNeedAIMergeDueToRenamesPlural_other": "由于 {{renameCount}} 文件重命名,{{count}} 文件需要 AI 合并。", + "fileRenamesDetected": "检测到 {{count}} 文件重命名 - AI 将处理合并。", + "fileRenamesDetected_other": "检测到 {{count}} 文件重命名 - AI 将处理合并。", + "filesRenamedOrMoved": "文件可能已被重命名或移动 - AI 将处理合并。", + "alreadyMergedTitle": "您的分支中已有更改", + "alreadyMergedDescription": "这些更改似乎已存在于您当前的分支中。您可以安全地将此任务标记为已完成。", + "alreadyMergedTooltip": "任务的更改已存在于您的分支中。标记为完成将清理工作树而不合并。", + "matchingFiles": "匹配文件", + "supersededTitle": "更改被取代", + "supersededDescription": "您当前的分支具有这些更改的更新版本。考虑放弃此任务或查看比较。", + "supersededCompareTooltip": "查看详细比较,了解当前分支与此任务的更改有何不同。", + "supersededDiscardTooltip": "由于不再需要更改,因此删除此任务的工作树。", + "status": { + "branchDiverged": "分支分歧", + "aiWillResolve": "人工智能将解决", + "filesRenamed": "文件已重命名", + "branchBehind": "分支落后", + "readyToMerge": "准备合并", + "files": "文件", + "file": "文件", + "conflict": "冲突", + "conflicts": "冲突", + "details": "细节", + "refresh": "刷新", + "stageOnly": "仅暂存(提交前在 IDE 中审核)", + "discardBuild": "放弃构建" + }, + "buttons": { + "stageWithAIMerge": "AI 合并暂存", + "mergeWithAI": "AI 合并", + "stageTo": "暂存到 {{branch}}", + "mergeTo": "合并到 {{branch}}", + "resolving": "解决...", + "staging": "暂存中...", + "merging": "合并...", + "completing": "正在完成..." + }, + "actions": { + "markAsDone": "标记为完成", + "discardTask": "放弃任务", + "viewComparison": "查看比较" + } + }, + "pr": { + "title": "创建拉取请求", + "description": "推送分支并为“{{taskTitle}}”创建拉取请求", + "errors": { + "unknown": "创建拉取请求时发生未知错误", + "invalidBranchName": "分支名称包含无效字符。仅使用字母、数字、连字符 (-)、下划线 (_) 和正斜杠 (/)。", + "emptyTitle": "拉取请求标题不能为空。" + }, + "success": { + "created": "拉取请求创建成功!", + "alreadyExists": "该分支已存在拉取请求" + }, + "actions": { + "retry": "重试", + "creating": "创建 PR...", + "create": "创建拉取请求" + }, + "labels": { + "sourceBranch": "源分支", + "targetBranch": "目标分支", + "commits": "提交", + "changes": "更改", + "prTitle": "PR标题(可选)", + "draftPR": "创建为草稿 PR", + "unknown": "未知" + }, + "hints": { + "targetBranch": "留空以使用默认分支", + "prTitle": "留空以使用任务标题" + } + }, + "mergeProgress": { + "stages": { + "analyzing": "分析更改", + "detectingConflicts": "检测冲突", + "resolving": "解决冲突", + "validating": "验证合并", + "complete": "合并完成", + "error": "合并失败", + "stalled": "合并停滞" + }, + "conflictCounter": "找到 {{found}},解决 {{resolved}}", + "currentFile": "当前文件", + "viewLogs": "查看日志", + "hideLogs": "隐藏日志", + "logTypes": { + "info": "信息", + "warning": "警告", + "error": "错误", + "conflict": "冲突", + "resolution": "解决" + }, + "completionMessage": "所有更改均已成功合并。", + "errorMessage": "合并过程中发生错误。" + }, + "bulkPR": { + "title": "创建拉取请求", + "description": "为 {{count}} 选定任务创建拉取请求", + "creating": "创建 {{total}} 的 PR {{current}}...", + "creatingPR": "创建 {{total}} 的 PR {{current}}", + "resultsDescription": "{{success}} 成功,{{failed}} 失败", + "tasksToProcess": "要处理的任务", + "targetBranchHint": "留空以使用每个任务的默认分支。这将应用于所有 PR。", + "createAll": "创建 {{count}} PR", + "completed": "已完成", + "succeeded": "成功", + "failed": "失败", + "skipped": "跳过", + "alreadyExisted": "已经存在", + "noWorktree": "没有找到该任务的工作树", + "resultsDescriptionWithSkipped": "{{success}} 成功,{{skipped}} 跳过,{{failed}} 失败" + } +} diff --git a/apps/frontend/src/shared/i18n/locales/zh/tasks.json b/apps/frontend/src/shared/i18n/locales/zh/tasks.json new file mode 100644 index 0000000000..d4280df32b --- /dev/null +++ b/apps/frontend/src/shared/i18n/locales/zh/tasks.json @@ -0,0 +1,353 @@ +{ + "refreshTasks": "刷新任务", + "status": { + "backlog": "积压", + "queue": "队列", + "todo": "待办事项", + "in_progress": "进行中", + "review": "审查", + "prCreated": "已创建 PR", + "complete": "已完成", + "archived": "已存档" + }, + "actions": { + "start": "开始", + "stop": "停止", + "recover": "恢复", + "resume": "恢复", + "archive": "归档", + "delete": "删除", + "view": "查看详情", + "viewPR": "查看PR", + "moveTo": "移至", + "taskActions": "任务动作", + "selectTask": "选择任务:{{title}}" + }, + "labels": { + "running": "运行中", + "aiReview": "AI 审查", + "needsReview": "需要审查", + "pending": "待处理", + "stuck": "卡住", + "incomplete": "不完整", + "recovering": "正在恢复...", + "needsRecovery": "需要恢复", + "needsResume": "需要恢复" + }, + "reviewReason": { + "completed": "已完成", + "hasErrors": "有错误", + "qaIssues": "质量保证问题", + "approvePlan": "批准计划", + "stopped": "已停止" + }, + "tooltips": { + "archiveTask": "存档任务", + "archiveAllDone": "归档所有已完成的任务", + "viewPR": "在浏览器中打开拉取请求" + }, + "creation": { + "title": "创建新任务", + "description": "描述您想要构建的内容", + "placeholder": "描述一下你的任务..." + }, + "empty": { + "title": "还没有任务", + "description": "创建您的第一个任务以开始" + }, + "columns": { + "backlog": "规划", + "queue": "队列", + "in_progress": "进行中", + "ai_review": "AI 审查", + "human_review": "人工审核", + "done": "完成", + "pr_created": "已创建 PR", + "error": "错误" + }, + "kanban": { + "emptyBacklog": "没有计划任务", + "emptyBacklogHint": "添加任务以开始", + "emptyQueue": "队列为空", + "emptyQueueHint": "当达到并行任务限制时,任务将在这里等待", + "emptyInProgress": "没有运行", + "emptyInProgressHint": "从计划开始任务", + "emptyAiReview": "没有正在审核的任务", + "emptyAiReviewHint": "AI将审查已完成的任务", + "emptyHumanReview": "没什么可评论的", + "emptyHumanReviewHint": "任务在这里等待您的批准", + "emptyDone": "没有完成的任务", + "emptyDoneHint": "此处显示已批准的任务", + "emptyDefault": "没有任务", + "dropHere": "放到这里", + "showArchived": "显示已存档", + "addTaskAriaLabel": "将新任务添加到待办事项中", + "queueAllAriaLabel": "将所有任务移至队列", + "closeTaskDetailsAriaLabel": "关闭任务详情", + "editTask": "编辑任务", + "cannotEditWhileRunning": "任务运行时无法编辑", + "worktreeCleanupTitle": "工作树清理", + "worktreeCleanupStaged": "该任务已上演并具有工作树。您想清理工作树吗?", + "worktreeCleanupNotStaged": "此任务有一个工作树,其中包含尚未合并的更改。删除工作树以标记为已完成,或取消以首先查看更改。", + "keepWorktree": "保留工作树", + "deleteWorktree": "删除工作树并标记为完成", + "refreshTasks": "刷新任务", + "queueSettings": "队列设置", + "orderSaveFailedTitle": "重新排序未保存", + "orderSaveFailedDescription": "您的任务顺序更改已应用,但无法保存到存储中。刷新时它将丢失。", + "selectAll": "选择全部", + "deselectAll": "取消全选", + "selectedCount": "已选择 {{count}}", + "selectedCountOne": "已选择 {{count}} 任务", + "selectedCountOther": "已选择 {{count}} 任务", + "createPRs": "创建 PR", + "deleteSelected": "删除", + "deleteConfirmTitle": "删除选定的任务", + "deleteConfirmDescription": "您确定要永久删除这些任务吗?", + "deleteWarning": "此操作无法撤消。所有任务文件,包括规范、实施计划和任何生成的代码都将从项目中永久删除。", + "tasksToDelete": "要删除的任务", + "deleteConfirmButton": "删除 {{count}} 任务", + "deleteSuccess": "已成功删除 {{count}} 任务", + "deleteError": "删除某些任务失败", + "clearSelection": "清除选择", + "collapseColumn": "折叠栏", + "expandColumn": "展开栏目", + "resizeColumn": "调整列大小", + "lockColumn": "锁定列宽", + "unlockColumn": "解锁列宽", + "columnLocked": "列宽已锁定", + "expandAll": "展开所有列" + }, + "queue": { + "limitReached": "达到并行任务限制 ({{current}}/{{max}})。任务移至队列。", + "movedToQueue": "任务移至队列。", + "autoPromoted": "任务自动从队列升级到进行中。", + "capacityAvailable": "{{count}} 插槽正在进行中。", + "queueAll": "将全部添加到队列", + "queueAllSuccess": "将 {{count}} 任务移至队列。", + "settings": { + "title": "队列设置", + "description": "在“进行中”面板中配置可以并行运行的最大任务数", + "maxParallelLabel": "最大并行任务数", + "minValueError": "必须至少为 1", + "maxValueError": "不能超过10个", + "hint": "达到此限制后,新任务将在队列中等待,然后再移至“进行中”", + "saved": "已保存队列设置", + "saveFailed": "无法保存队列设置", + "retry": "请重试" + } + }, + "execution": { + "phases": { + "idle": "空闲", + "planning": "规划", + "coding": "编码", + "rate_limit_paused": "速率限制暂停", + "auth_failure_paused": "需要身份验证", + "reviewing": "审阅", + "fixing": "修复中", + "complete": "已完成", + "failed": "失败" + }, + "labels": { + "interrupted": "已中断", + "progress": "进度", + "entry": "入口", + "entries": "条目" + }, + "shortPhases": { + "plan": "计划", + "code": "代码", + "qa": "质量保证" + } + }, + "files": { + "title": "文件", + "tab": "文件", + "noSpecPath": "没有可用的规格文件", + "noFiles": "没有找到文件", + "loading": "正在加载文件...", + "loadingContent": "正在加载内容...", + "errorLoading": "加载文件失败", + "errorLoadingContent": "无法加载文件内容", + "retry": "重试", + "selectFile": "选择一个文件以查看其内容", + "openInIDE": "在 IDE 中打开" + }, + "metadata": { + "fastMode": "快速模式", + "severity": "严重程度", + "pullRequest": "拉取请求", + "showMore": "显示更多", + "showLess": "显示较少" + }, + "images": { + "removeImageAriaLabel": "删除图像 {{filename}}", + "pasteHint": "提示:直接使用 {{shortcut}} 粘贴屏幕截图以添加参考图像。" + }, + "imagePreview": { + "close": "关闭预览", + "unavailable": "图片不可用", + "description": "{{filename}} 预览", + "doubleClickHint": "双击放大", + "lowResolution": "低分辨率预览" + }, + "notifications": { + "backgroundTaskTitle": "任务在后台继续进行", + "backgroundTaskDescription": "任务仍在运行。您可以重新打开此对话框来监控进度。" + }, + "wizard": { + "createTitle": "创建新任务", + "createDescription": "描述您想要构建的内容。人工智能将分析您的请求并创建详细的规范。", + "descriptionPlaceholder": "描述您想要实施的功能、错误修复或改进。尽可能具体地说明要求、约束和预期行为。键入@以引用文件。", + "draftRestored": "草案已恢复", + "startFresh": "重新开始", + "hideFiles": "隐藏文件", + "browseFiles": "浏览文件", + "creating": "创建...", + "createTask": "创建任务", + "worktreeNotice": { + "title": "隔离工作区", + "description": "此任务在隔离的 git 工作树中运行。在您选择合并之前,您的主分支将保持安全。" + }, + "gitOptions": { + "title": "Git 选项(可选)", + "baseBranchLabel": "基础分支(可选)", + "useProjectDefault": "使用项目默认值", + "useProjectDefaultWithBranch": "使用项目默认值 ({{branch}})", + "searchBranches": "搜索分支...", + "noBranchesFound": "没有找到分支", + "helpText": "覆盖将从中创建该任务的工作树的分支。留空以使用项目配置的默认分支。", + "useWorktreeLabel": "使用隔离工作区(推荐)", + "useWorktreeDescription": "在单独的 git 工作树中创建更改,以便在合并之前进行安全审查。禁止直接在项目中构建(更快但风险更高)。" + }, + "errors": { + "createFailed": "创建任务失败。请再试一次。", + "startFailed": "启动任务失败" + } + }, + "feedback": { + "dragDropHint": "拖放图像或粘贴屏幕截图", + "imageAdded": "图片添加成功", + "maxImagesError": "最多允许 {{count}} 图片", + "invalidTypeError": "图像类型无效。允许:{{types}}", + "removeImage": "删除图像", + "processingError": "处理图像失败" + }, + "review": { + "mergeTooltip": "将更改从任务的工作树分支合并回基础分支。人工智能将解决任何冲突。然后您可以选择是保留还是删除工作树。" + }, + "edit": { + "title": "编辑任务", + "description": "更新任务详细信息,包括标题、描述、分类、图像和设置。更改将保存到规范文件中。", + "saveChanges": "保存更改", + "errors": { + "updateFailed": "更新任务失败。请再试一次。" + } + }, + "form": { + "description": "描述", + "descriptionPlaceholder": "描述您想要实施的功能、错误修复或改进。尽可能具体地说明要求、约束和预期行为。", + "imageAddedSuccess": "图片添加成功!", + "taskTitle": "任务标题", + "titlePlaceholder": "留空以根据描述自动生成", + "titleHelpText": "如果留空,将自动生成一个简短的描述性标题。", + "classificationOptional": "分类(可选)", + "requireReviewLabel": "编码前需要人工审核", + "requireReviewDescription": "启用后,系统会提示您在编码阶段开始之前查看规范和实施计划。这允许您批准、请求更改或提供反馈。", + "fastModeLabel": "快速模式", + "fastModeDescription": "相同的 Opus 4.6 型号,输出速度更快。每个代币的成本更高。", + "fastModeNotice": "需要在您的Claude订阅中启用“额外使用”。", + "errors": { + "descriptionRequired": "请提供描述", + "maxImagesReached": "最多允许 5 张图片", + "invalidImageType": "图像类型无效。允许:PNG、JPEG、GIF、WebP", + "processPasteFailed": "无法处理粘贴的图像", + "processDropFailed": "无法处理删除的图像" + }, + "classification": { + "category": "类别", + "selectCategory": "选择类别", + "priority": "优先事项", + "selectPriority": "选择优先级", + "complexity": "复杂", + "selectComplexity": "选择复杂性", + "impact": "影响", + "selectImpact": "选择影响", + "helpText": "这些标签有助于组织任务并确定其优先级。它们是可选的,但对于过滤很有用。", + "values": { + "category": { + "feature": "功能", + "bug_fix": "错误修复", + "refactoring": "重构", + "documentation": "文档", + "security": "安全" + }, + "priority": { + "low": "低", + "medium": "中", + "high": "高", + "urgent": "紧急" + }, + "complexity": { + "trivial": "极简", + "small": "小", + "medium": "中", + "large": "大", + "complex": "复杂" + }, + "impact": { + "low": "低影响", + "medium": "中等影响", + "high": "高影响力", + "critical": "重大影响" + } + } + } + }, + "subtasks": { + "untitled": "无标题子任务" + }, + "bulkPR": { + "selectAllInColumn": "选择列中的所有任务", + "deselectAllInColumn": "取消选择所有任务", + "selectionMode": "选择模式激活", + "exitSelectionMode": "退出选择模式", + "noTasksToSelect": "没有可供选择的任务", + "confirmBulkAction": "确认 {{count}} 任务的批量操作", + "processingTasks": "处理选定的任务..." + }, + "screenshot": { + "title": "捕获屏幕截图", + "description": "选择要捕获的屏幕或窗口作为参考图像", + "capture": "捕获", + "capturing": "捕捉...", + "noSources": "未找到屏幕或窗口", + "errors": { + "getSources": "获取截图来源失败", + "fetchSources": "获取截图源失败", + "capture": "截图失败", + "captureFailed": "截图失败" + }, + "devMode": { + "title": "无法截图", + "description": "由于系统权限限制,屏幕截图在开发模式下不可用。", + "hint": "使用外部屏幕截图工具并使用 {{shortcut}} 直接粘贴到任务描述中。" + } + }, + "deleteDialog": { + "title": "删除任务", + "confirmMessage": "您确定要删除吗", + "destructiveWarning": "此操作无法撤消。所有任务文件,包括规范、实施计划和任何生成的代码都将从项目中永久删除。", + "checkingChanges": "检查未提交的更改...", + "uncommittedChanges": "此任务的工作树有 {{count}} 未提交的文件", + "uncommittedChangesHint": "这些更改尚未提交或合并。删除此任务将永久丢弃工作树中所有未提交的工作。", + "cancel": "取消", + "deletePermanently": "永久删除", + "deleting": "正在删除..." + }, + "referenceImages": { + "title": "参考图片(可选)", + "description": "添加屏幕截图或设计等视觉参考,以帮助人工智能了解您的需求。" + } +} diff --git a/apps/frontend/src/shared/i18n/locales/zh/terminal.json b/apps/frontend/src/shared/i18n/locales/zh/terminal.json new file mode 100644 index 0000000000..ab4f3d6d21 --- /dev/null +++ b/apps/frontend/src/shared/i18n/locales/zh/terminal.json @@ -0,0 +1,58 @@ +{ + "expand": { + "expand": "扩展终端", + "collapse": "折叠终端" + }, + "resume": { + "pending": "可恢复", + "pendingTooltip": "单击以恢复之前的Claude会话", + "resumeAllSessions": "恢复全部" + }, + "auth": { + "terminalTitle": "授权:{{profileName}}", + "maxTerminalsReached": "无法打开身份验证终端:已达到最大终端数。首先关闭终端。" + }, + "swap": { + "inProgress": "正在切换配置文件...", + "resumingSession": "继续Claude会话...", + "sessionResumed": "会话在新的配置文件下恢复", + "resumeFailed": "无法恢复会话。您可以开始新的会话。", + "noSession": "配置文件已切换。没有可恢复的活动会话。", + "migrationFailed": "配置文件已切换,但会话迁移失败。启动新的终端。" + }, + "worktree": { + "create": "工作树", + "createNew": "新工作树", + "existing": "终端工作树", + "taskWorktrees": "任务工作树", + "otherWorktrees": "其他的", + "createTitle": "创建终端工作树", + "createDescription": "为此终端创建一个独立的工作区。所有工作都将在工作树目录中进行。", + "name": "工作树名称", + "namePlaceholder": "我的功能", + "nameRequired": "工作树名称为必填项", + "nameInvalid": "名称必须以字母或数字开头和结尾", + "nameHelp": "小写字母、数字、破折号和下划线(空格变为连字符)", + "associateTask": "任务链接", + "selectTask": "选择一个任务...", + "noTask": "无任务(独立工作树)", + "createBranch": "创建 Git 分支", + "branchHelp": "创建分支:{{branch}}", + "baseBranch": "基地支部", + "selectBaseBranch": "选择基础分支...", + "searchBranch": "搜索分支...", + "noBranchFound": "没有找到分支", + "useProjectDefault": "使用项目默认值 ({{branch}})", + "baseBranchHelp": "用于创建工作树的分支", + "openInIDE": "在 IDE 中打开", + "maxReached": "达到最多 12 个终端工作树", + "alreadyExists": "同名的工作树已存在", + "searchPlaceholder": "搜索工作树...", + "noResults": "未找到工作树", + "deleteTitle": "删除工作树?", + "deleteDescription": "这将永久删除工作树及其分支。任何未提交的更改都将丢失。", + "detached": "(分离)", + "remotePushFailed": "远程跟踪未设置", + "remotePushFailedDescription": "已创建工作树,但无法将分支推送到远程。您可能需要手动运行 git push -u。" + } +} diff --git a/apps/frontend/src/shared/i18n/locales/zh/welcome.json b/apps/frontend/src/shared/i18n/locales/zh/welcome.json new file mode 100644 index 0000000000..6e6aeae794 --- /dev/null +++ b/apps/frontend/src/shared/i18n/locales/zh/welcome.json @@ -0,0 +1,17 @@ +{ + "hero": { + "title": "欢迎来到Auto Claude", + "subtitle": "使用人工智能代理自主构建软件" + }, + "actions": { + "newProject": "新项目", + "openProject": "打开项目" + }, + "recentProjects": { + "title": "最近的项目", + "empty": "还没有项目", + "emptyDescription": "创建一个新项目或打开现有项目以开始", + "openFolder": "打开文件夹", + "openProjectAriaLabel": "打开项目 {{name}}" + } +} From 8491fd29b2acdcc9b8d4b4b9e0d1dcb83adf11ea Mon Sep 17 00:00:00 2001 From: daidaidaiok Date: Sun, 8 Mar 2026 00:04:51 +0800 Subject: [PATCH 2/2] fix(i18n): address PR review feedback for Chinese locale and issue components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace hardcoded "Issue #" subtitle with i18n key in InvestigationDialog - Use i18n object lookup instead of GITHUB_ISSUE_STATE_LABELS in IssueDetail badge - Replace nested ternary with object lookup in GitHub/GitLab IssueListItem - Add focus:opacity-100 for keyboard accessibility on investigate button - Add singular/plural forms for commentsCount and openCount across en/fr/zh - Make en/fr delta test informational instead of blocking CI - Fix zh translations: 专题标题→功能标题, 复杂→复杂度 - Remove unused GITHUB_ISSUE_STATE_LABELS imports Co-Authored-By: Claude Opus 4.6 --- .../github-issues/components/InvestigationDialog.tsx | 2 +- .../components/github-issues/components/IssueDetail.tsx | 3 +-- .../components/github-issues/components/IssueListItem.tsx | 7 +++---- .../components/gitlab-issues/components/IssueListItem.tsx | 2 +- apps/frontend/src/shared/i18n/locale-coverage.test.ts | 8 +++++++- apps/frontend/src/shared/i18n/locales/en/common.json | 5 ++++- apps/frontend/src/shared/i18n/locales/fr/common.json | 7 +++++-- apps/frontend/src/shared/i18n/locales/zh/common.json | 3 +++ apps/frontend/src/shared/i18n/locales/zh/dialogs.json | 6 +++--- apps/frontend/src/shared/i18n/locales/zh/tasks.json | 4 ++-- 10 files changed, 30 insertions(+), 17 deletions(-) diff --git a/apps/frontend/src/renderer/components/github-issues/components/InvestigationDialog.tsx b/apps/frontend/src/renderer/components/github-issues/components/InvestigationDialog.tsx index 0949a50351..48d0e1b315 100644 --- a/apps/frontend/src/renderer/components/github-issues/components/InvestigationDialog.tsx +++ b/apps/frontend/src/renderer/components/github-issues/components/InvestigationDialog.tsx @@ -108,7 +108,7 @@ export function InvestigationDialog({ {selectedIssue && ( - Issue #{selectedIssue.number}: {selectedIssue.title} + {t('issues.investigation.subtitle', { number: selectedIssue.number, title: selectedIssue.title })} )} diff --git a/apps/frontend/src/renderer/components/github-issues/components/IssueDetail.tsx b/apps/frontend/src/renderer/components/github-issues/components/IssueDetail.tsx index e96abcad59..1230e76258 100644 --- a/apps/frontend/src/renderer/components/github-issues/components/IssueDetail.tsx +++ b/apps/frontend/src/renderer/components/github-issues/components/IssueDetail.tsx @@ -8,7 +8,6 @@ import { Card, CardContent, CardHeader, CardTitle } from '../../ui/card'; import { ScrollArea } from '../../ui/scroll-area'; import { GITHUB_ISSUE_STATE_COLORS, - GITHUB_ISSUE_STATE_LABELS, GITHUB_COMPLEXITY_COLORS } from '../../../../shared/constants'; import { formatDate } from '../utils'; @@ -47,7 +46,7 @@ export function IssueDetail({ variant="outline" className={`${GITHUB_ISSUE_STATE_COLORS[issue.state]}`} > - {GITHUB_ISSUE_STATE_LABELS[issue.state]} + {{ open: t('issues.stateOpen'), closed: t('issues.stateClosed') }[issue.state] ?? issue.state} #{issue.number}
diff --git a/apps/frontend/src/renderer/components/github-issues/components/IssueListItem.tsx b/apps/frontend/src/renderer/components/github-issues/components/IssueListItem.tsx index b3f515c3ad..71989125bb 100644 --- a/apps/frontend/src/renderer/components/github-issues/components/IssueListItem.tsx +++ b/apps/frontend/src/renderer/components/github-issues/components/IssueListItem.tsx @@ -3,8 +3,7 @@ import { useTranslation } from 'react-i18next'; import { Badge } from '../../ui/badge'; import { Button } from '../../ui/button'; import { - GITHUB_ISSUE_STATE_COLORS, - GITHUB_ISSUE_STATE_LABELS + GITHUB_ISSUE_STATE_COLORS } from '../../../../shared/constants'; import type { IssueListItemProps } from '../types'; @@ -26,7 +25,7 @@ export function IssueListItem({ issue, isSelected, onClick, onInvestigate }: Iss variant="outline" className={`text-xs ${GITHUB_ISSUE_STATE_COLORS[issue.state]}`} > - {issue.state === 'open' ? t('issues.stateOpen') : issue.state === 'closed' ? t('issues.stateClosed') : (GITHUB_ISSUE_STATE_LABELS[issue.state] ?? issue.state)} + {{ open: t('issues.stateOpen'), closed: t('issues.stateClosed') }[issue.state] ?? issue.state} #{issue.number}
@@ -55,7 +54,7 @@ export function IssueListItem({ issue, isSelected, onClick, onInvestigate }: Iss