diff --git a/apps/desktop/src/main/agent/agent-manager.ts b/apps/desktop/src/main/agent/agent-manager.ts index 21a538490c..b60f6dd907 100644 --- a/apps/desktop/src/main/agent/agent-manager.ts +++ b/apps/desktop/src/main/agent/agent-manager.ts @@ -128,6 +128,11 @@ export class AgentManager extends EventEmitter { return accounts.length > 0; } + private getSettingsLanguage(): string | undefined { + const settings = readSettingsFile(); + return settings?.language as string | undefined; + } + /** * Resolve auth using the provider accounts priority queue. * Falls back to legacy Claude profile if no provider accounts exist. @@ -389,6 +394,7 @@ export class AgentManager extends EventEmitter { maxSteps: 1000, specDir: resolvedSpecDir, projectDir: projectPath, + language: this.getSettingsLanguage(), provider: resolved.provider, modelId: resolved.modelId, apiKey: resolved.auth?.apiKey, @@ -510,6 +516,7 @@ export class AgentManager extends EventEmitter { maxSteps: 1000, specDir: worktreeSpecDir, projectDir: effectiveProjectDir, + language: this.getSettingsLanguage(), // When running in a worktree, sourceSpecDir points to the main project spec dir // so the subtask iterator can sync phase updates in real time (not just on exit). sourceSpecDir: worktreePath ? specDir : undefined, @@ -616,6 +623,7 @@ export class AgentManager extends EventEmitter { maxSteps: 1000, specDir: effectiveSpecDir, projectDir: effectiveProjectDir, + language: this.getSettingsLanguage(), provider: resolved.provider, modelId: resolved.modelId, apiKey: resolved.auth?.apiKey, diff --git a/apps/desktop/src/main/ai/agent/types.ts b/apps/desktop/src/main/ai/agent/types.ts index 0f7f453055..2ccf8ea097 100644 --- a/apps/desktop/src/main/ai/agent/types.ts +++ b/apps/desktop/src/main/ai/agent/types.ts @@ -77,6 +77,8 @@ export interface SerializableSessionConfig { }; /** Enable agentic orchestration mode where the AI drives the pipeline via SpawnSubagent tool */ useAgenticOrchestration?: boolean; + /** UI language code for agent response language (e.g., 'en', 'ru') */ + language?: string; /** Tool context serialized fields */ toolContext: { cwd: string; diff --git a/apps/desktop/src/main/ai/agent/worker.ts b/apps/desktop/src/main/ai/agent/worker.ts index f03bb19d20..4644297bda 100644 --- a/apps/desktop/src/main/ai/agent/worker.ts +++ b/apps/desktop/src/main/ai/agent/worker.ts @@ -230,6 +230,7 @@ async function assemblePrompt( specDir: session.specDir, projectDir: session.projectDir, projectInstructions: cachedProjectInstructions, + language: session.language, }); } diff --git a/apps/desktop/src/main/ai/client/factory.ts b/apps/desktop/src/main/ai/client/factory.ts index e1acc75719..e615ad1d21 100644 --- a/apps/desktop/src/main/ai/client/factory.ts +++ b/apps/desktop/src/main/ai/client/factory.ts @@ -15,6 +15,8 @@ import type { Tool as AITool } from 'ai'; import { resolveAuth, resolveAuthFromQueue, buildDefaultQueueConfig } from '../auth/resolver'; +import { readSettingsFile } from '../../settings-utils'; +import { buildLanguageInstruction } from '../prompts/language-utils'; import { getDefaultThinkingLevel, getRequiredMcpServers, @@ -192,6 +194,17 @@ export async function createAgentClient( }; } +// ============================================================================= +// Language Injection +// ============================================================================= + +function injectLanguageInstruction(prompt: string): string { + const settings = readSettingsFile(); + const lang = (settings?.language as string | undefined) ?? 'en'; + const instruction = buildLanguageInstruction(lang); + return instruction ? instruction + prompt : prompt; +} + // ============================================================================= // createSimpleClient // ============================================================================= @@ -289,7 +302,7 @@ export async function createSimpleClient( model, resolvedModelId, tools, - systemPrompt, + systemPrompt: injectLanguageInstruction(systemPrompt), maxSteps, thinkingLevel: resolvedThinkingLevel, ...(queueAuth ? { queueAuth } : {}), diff --git a/apps/desktop/src/main/ai/prompts/language-utils.ts b/apps/desktop/src/main/ai/prompts/language-utils.ts new file mode 100644 index 0000000000..a1fcc2a1aa --- /dev/null +++ b/apps/desktop/src/main/ai/prompts/language-utils.ts @@ -0,0 +1,11 @@ +import { AVAILABLE_LANGUAGES } from '../../../shared/constants/i18n'; + +export function buildLanguageInstruction(language: string): string | null { + if (!language || language === 'en') return null; + const entry = AVAILABLE_LANGUAGES.find((l) => l.value === language); + const langName = entry?.label ?? language; + return ( + `**LANGUAGE**: Always respond in ${langName}. All code comments, ` + + `documentation, commit messages, and explanations must be in ${langName}.\n\n` + ); +} diff --git a/apps/desktop/src/main/ai/prompts/prompt-loader.ts b/apps/desktop/src/main/ai/prompts/prompt-loader.ts index 6ad1ff34fe..d7072baf81 100644 --- a/apps/desktop/src/main/ai/prompts/prompt-loader.ts +++ b/apps/desktop/src/main/ai/prompts/prompt-loader.ts @@ -15,6 +15,7 @@ import { join } from 'node:path'; import { execSync } from 'node:child_process'; import type { ProjectCapabilities, PromptContext, PromptValidationResult } from './types'; +import { buildLanguageInstruction } from './language-utils'; // ============================================================================= // Expected prompt files (used for startup validation) @@ -223,7 +224,13 @@ export function injectContext(promptTemplate: string, context: PromptContext): s sections.push(context.recoveryContext); } - // 3. Human input + // 3. Language instruction (non-English only) + if (context.language) { + const instruction = buildLanguageInstruction(context.language); + if (instruction) sections.push(instruction); + } + + // 4. Human input if (context.humanInput) { sections.push( `## HUMAN INPUT (READ THIS FIRST!)\n\n` + @@ -234,7 +241,7 @@ export function injectContext(promptTemplate: string, context: PromptContext): s ); } - // 4. Project instructions (AGENTS.md or CLAUDE.md fallback) + // 5. Project instructions (AGENTS.md or CLAUDE.md fallback) if (context.projectInstructions) { sections.push( `## PROJECT INSTRUCTIONS\n\n` + @@ -243,7 +250,7 @@ export function injectContext(promptTemplate: string, context: PromptContext): s ); } - // 5. Base prompt + // 6. Base prompt sections.push(promptTemplate); return sections.join(''); diff --git a/apps/desktop/src/main/ai/prompts/types.ts b/apps/desktop/src/main/ai/prompts/types.ts index 335bca3f9b..c1ab4bef76 100644 --- a/apps/desktop/src/main/ai/prompts/types.ts +++ b/apps/desktop/src/main/ai/prompts/types.ts @@ -32,6 +32,8 @@ export interface PromptContext { recoveryHints?: string[]; /** Phase-specific planning retry context */ planningRetryContext?: string; + /** UI language code for agent response language (e.g., 'en', 'ru') */ + language?: string; } // ============================================================================= diff --git a/apps/desktop/src/shared/constants/i18n.ts b/apps/desktop/src/shared/constants/i18n.ts index 5f4ebbde38..5d29eafde3 100644 --- a/apps/desktop/src/shared/constants/i18n.ts +++ b/apps/desktop/src/shared/constants/i18n.ts @@ -3,11 +3,12 @@ * Available languages and display labels */ -export type SupportedLanguage = 'en' | 'fr'; +export type SupportedLanguage = 'en' | 'fr' | 'ru'; 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: 'ru' as const, label: 'Russian', nativeLabel: 'Русский' } ] as const; export const DEFAULT_LANGUAGE: SupportedLanguage = 'en'; diff --git a/apps/desktop/src/shared/i18n/index.ts b/apps/desktop/src/shared/i18n/index.ts index 095b0b1188..e53f02035d 100644 --- a/apps/desktop/src/shared/i18n/index.ts +++ b/apps/desktop/src/shared/i18n/index.ts @@ -27,6 +27,19 @@ import frTaskReview from './locales/fr/taskReview.json'; import frTerminal from './locales/fr/terminal.json'; import frErrors from './locales/fr/errors.json'; +// Import Russian translation resources +import ruCommon from './locales/ru/common.json'; +import ruNavigation from './locales/ru/navigation.json'; +import ruSettings from './locales/ru/settings.json'; +import ruTasks from './locales/ru/tasks.json'; +import ruWelcome from './locales/ru/welcome.json'; +import ruOnboarding from './locales/ru/onboarding.json'; +import ruDialogs from './locales/ru/dialogs.json'; +import ruGitlab from './locales/ru/gitlab.json'; +import ruTaskReview from './locales/ru/taskReview.json'; +import ruTerminal from './locales/ru/terminal.json'; +import ruErrors from './locales/ru/errors.json'; + export const defaultNS = 'common'; export const resources = { @@ -55,6 +68,19 @@ export const resources = { taskReview: frTaskReview, terminal: frTerminal, errors: frErrors + }, + ru: { + common: ruCommon, + navigation: ruNavigation, + settings: ruSettings, + tasks: ruTasks, + welcome: ruWelcome, + onboarding: ruOnboarding, + dialogs: ruDialogs, + gitlab: ruGitlab, + taskReview: ruTaskReview, + terminal: ruTerminal, + errors: ruErrors } } as const; diff --git a/apps/desktop/src/shared/i18n/locales/ru/common.json b/apps/desktop/src/shared/i18n/locales/ru/common.json new file mode 100644 index 0000000000..cb60cfac97 --- /dev/null +++ b/apps/desktop/src/shared/i18n/locales/ru/common.json @@ -0,0 +1,1012 @@ +{ + "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": "{{selected}} из {{total}} выбрано" + }, + "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_one": "{{count}} воркдерево успешно удалено", + "bulkDeleteSuccess_few": "{{count}} воркдерева успешно удалено", + "bulkDeleteSuccess_many": "{{count}} воркдеревьев успешно удалено", + "bulkDeleteSuccess_other": "{{count}} воркдеревьев успешно удалено" + }, + "notification": { + "accountSwitched": "Аккаунт переключён", + "swapFrom": "Переключено с", + "swapTo": "на", + "swapReason": "(переключение: {{reason}})" + }, + "rateLimit": { + "title": "Превышен лимит запросов", + "resetsAt": "Сбросится {{time}}", + "hitLimit": "{{source}} достиг лимита использования", + "clickToManage": "Нажмите для управления →", + "modalTitle": "Достигнут лимит использования Claude Code", + "modalDescription": "Вы достигли лимита использования Claude Code за этот период.", + "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": "Улучшить до Pro для повышенных лимитов", + "resetsLabel": "Сбросится {{time}}", + "weeklyLimit": "Недельный лимит — сбрасывается примерно через неделю", + "sessionLimit": "Лимит сессии — сбрасывается через несколько часов", + "switchAccountRetry": "Переключить аккаунт и повторить", + "retrying": "Повтор...", + "retry": "Повторить", + "autoSwitchRetryLabel": "Автопереключение и повтор при лимите", + "add": "Добавить", + "whatHappened": "Что произошло:", + "whatHappenedDesc": "Операция {{source}} была остановлена, так как ваш аккаунт Claude ({{account}}) достиг лимита использования.", + "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": "Pull Requests", + "open": "открыто", + "selectPRToView": "Выберите pull request для просмотра деталей", + "loadingPRs": "Загрузка pull requests...", + "noOpenPRs": "Нет открытых pull requests", + "notConnected": "GitHub не подключён", + "connectPrompt": "Подключите аккаунт GitHub для просмотра и проверки pull requests.", + "openSettings": "Открыть настройки", + "runAIReview": "Запустить AI-проверку", + "reviewStarted": "Проверка начата", + "analysisInProgress": "AI-анализ в процессе...", + "analysisComplete": "Анализ завершён ({{count}} находок)", + "findingsPostedToGitHub": "Находки опубликованы на GitHub", + "newCommits": "{{count}} новый коммит", + "newCommit": "{{count}} новый коммит", + "runFollowup": "Запустить повторную проверку", + "aiReviewInProgress": "AI-проверка в процессе", + "waitingForChanges": "Ожидание изменений", + "reviewComplete": "Проверка завершена", + "reviewStatus": "Статус проверки", + "files": "файлы", + "filesChanged": "Изменено файлов: {{count}}", + "clickToViewFiles": "Нажмите для просмотра изменённых файлов", + "loadingFiles": "Загрузка файлов...", + "noFilesAvailable": "Список файлов недоступен", + "posting": "Публикация...", + "postingApproval": "Публикация одобрения...", + "postFindings_one": "Опубликовать {{count}} находку", + "postFindings_few": "Опубликовать {{count}} находки", + "postFindings_many": "Опубликовать {{count}} находок", + "postFindings_other": "Опубликовать {{count}} находок", + "approve": "Одобрить", + "merge": "Смержить", + "mergeViaGitHub": "Слияние через GitHub CLI. Может завершиться неудачей, если правила защиты ветки требуют дополнительных проверок.", + "autoApprovePR": "Одобрить PR", + "suggestions": "с {{count}} предложениями", + "postedFindings_one": "Опубликована {{count}} находка", + "postedFindings_few": "Опубликовано {{count}} находки", + "postedFindings_many": "Опубликовано {{count}} находок", + "postedFindings_other": "Опубликовано {{count}} находок", + "resolved_one": "{{count}} решено", + "resolved_few": "{{count}} решено", + "resolved_many": "{{count}} решено", + "resolved_other": "{{count}} решено", + "stillOpen_one": "{{count}} ещё открыто", + "stillOpen_few": "{{count}} ещё открыто", + "stillOpen_many": "{{count}} ещё открыто", + "stillOpen_other": "{{count}} ещё открыто", + "newIssue_one": "{{count}} новая проблема", + "newIssue_few": "{{count}} новые проблемы", + "newIssue_many": "{{count}} новых проблем", + "newIssue_other": "{{count}} новых проблем", + "reviewFailed": "Проверка не удалась", + "externalReviewDetected": "Обнаружена внешняя проверка", + "reviewStartedExternally": "Эта проверка была запущена из другой сессии", + "description": "Описание", + "noDescription": "Описание отсутствует.", + "followupReviewDetails": "Детали повторной проверки", + "aiAnalysisResults": "Результаты AI-анализа", + "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_one": "{{count}} находка опубликована на GitHub", + "findingsPostedCount_few": "{{count}} находки опубликовано на GitHub", + "findingsPostedCount_many": "{{count}} находок опубликовано на GitHub", + "findingsPostedCount_other": "{{count}} находок опубликовано на GitHub", + "selectedOfTotal": "{{selected}}/{{total}} выбрано", + "suggestedFix": "Предлагаемое исправление:", + "runAIReviewDesc": "Запустите AI-проверку для анализа этого PR", + "newCommitsSinceFollowup_one": "{{count}} новый коммит с момента повторной проверки. Запустите ещё одну повторную проверку.", + "newCommitsSinceFollowup_few": "{{count}} новых коммита с момента повторной проверки. Запустите ещё одну повторную проверку.", + "newCommitsSinceFollowup_many": "{{count}} новых коммитов с момента повторной проверки. Запустите ещё одну повторную проверку.", + "newCommitsSinceFollowup_other": "{{count}} новых коммитов с момента повторной проверки. Запустите ещё одну повторную проверку.", + "allIssuesResolved_one": "Все {{count}} проблема решена. Этот PR можно смержить.", + "allIssuesResolved_few": "Все {{count}} проблемы решены. Этот PR можно смержить.", + "allIssuesResolved_many": "Все {{count}} проблем решены. Этот PR можно смержить.", + "allIssuesResolved_other": "Все {{count}} проблем решены. Этот PR можно смержить.", + "nonBlockingSuggestions_one": "{{resolved}} решено. Осталось {{suggestions}} не блокирующее предложение.", + "nonBlockingSuggestions_few": "{{resolved}} решено. Осталось {{suggestions}} не блокирующих предложения.", + "nonBlockingSuggestions_many": "{{resolved}} решено. Осталось {{suggestions}} не блокирующих предложений.", + "nonBlockingSuggestions_other": "{{resolved}} решено. Осталось {{suggestions}} не блокирующих предложений.", + "blockingIssues": "Блокирующие проблемы", + "blockingIssuesDesc_one": "{{resolved}} решено, {{unresolved}} блокирующая проблема ещё открыта.", + "blockingIssuesDesc_few": "{{resolved}} решено, {{unresolved}} блокирующих проблемы ещё открыто.", + "blockingIssuesDesc_many": "{{resolved}} решено, {{unresolved}} блокирующих проблем ещё открыто.", + "blockingIssuesDesc_other": "{{resolved}} решено, {{unresolved}} блокирующих проблем ещё открыто.", + "newCommitsSinceReview_one": "{{count}} новый коммит с момента проверки. Запустите повторную проверку, чтобы убедиться в устранении проблем.", + "newCommitsSinceReview_few": "{{count}} новых коммита с момента проверки. Запустите повторную проверку, чтобы убедиться в устранении проблем.", + "newCommitsSinceReview_many": "{{count}} новых коммитов с момента проверки. Запустите повторную проверку, чтобы убедиться в устранении проблем.", + "newCommitsSinceReview_other": "{{count}} новых коммитов с момента проверки. Запустите повторную проверку, чтобы убедиться в устранении проблем.", + "noBlockingIssues": "Блокирующих проблем не обнаружено. Этот PR можно смержить.", + "findingsPostedWaiting_one": "{{count}} находка опубликована. Ожидание устранения проблем участником.", + "findingsPostedWaiting_few": "{{count}} находки опубликовано. Ожидание устранения проблем участником.", + "findingsPostedWaiting_many": "{{count}} находок опубликовано. Ожидание устранения проблем участником.", + "findingsPostedWaiting_other": "{{count}} находок опубликовано. Ожидание устранения проблем участником.", + "findingsPostedNoBlockers_one": "{{count}} находка опубликована. Блокирующих проблем не осталось.", + "findingsPostedNoBlockers_few": "{{count}} находки опубликовано. Блокирующих проблем не осталось.", + "findingsPostedNoBlockers_many": "{{count}} находок опубликовано. Блокирующих проблем не осталось.", + "findingsPostedNoBlockers_other": "{{count}} находок опубликовано. Блокирующих проблем не осталось.", + "needsAttention": "Требует внимания", + "findingsNeedPosting_one": "{{count}} находку необходимо опубликовать на GitHub.", + "findingsNeedPosting_few": "{{count}} находки необходимо опубликовать на GitHub.", + "findingsNeedPosting_many": "{{count}} находок необходимо опубликовать на GitHub.", + "findingsNeedPosting_other": "{{count}} находок необходимо опубликовать на GitHub.", + "findingsFoundSelectPost_one": "Найдена {{count}} находка. Выберите и опубликуйте на GitHub.", + "findingsFoundSelectPost_few": "Найдено {{count}} находки. Выберите и опубликуйте на GitHub.", + "findingsFoundSelectPost_many": "Найдено {{count}} находок. Выберите и опубликуйте на GitHub.", + "findingsFoundSelectPost_other": "Найдено {{count}} находок. Выберите и опубликуйте на GitHub.", + "reviewLogs": "Логи проверки", + "followup": "Повторная проверка", + "initial": "Первичная", + "rerunFollowup": "Перезапустить повторную проверку", + "retryReview": "Повторить проверку", + "rerunReview": "Перезапустить проверку", + "updateBranch": "Обновить ветку", + "updatingBranch": "Обновление...", + "branchUpdated": "Ветка обновлена", + "branchUpdateFailed": "Не удалось обновить ветку", + "allPRsLoaded": "Все PR загружены", + "maxPRsShown": "Показаны первые 100 PR", + "loadMore": "Загрузить ещё", + "loadingMore": "Загрузка...", + "workflowsAwaitingApproval_one": "{{count}} воркфлоу ожидает одобрения", + "workflowsAwaitingApproval_few": "{{count}} воркфлоу ожидают одобрения", + "workflowsAwaitingApproval_many": "{{count}} воркфлоу ожидают одобрения", + "workflowsAwaitingApproval_other": "{{count}} воркфлоу ожидают одобрения", + "blockedByWorkflows": "Заблокировано", + "workflowsAwaitingDescription": "Этот PR из форка и требует одобрения воркфлоу перед запуском CI-проверок. Одобрите воркфлоу для продолжения.", + "viewOnGitHub": "Просмотр", + "approveWorkflow": "Одобрить", + "approveAllWorkflows": "Одобрить все воркфлоу", + "postCleanReview": "Опубликовать чистую проверку", + "postingCleanReview": "Публикация...", + "cleanReviewPosted": "Чистая проверка опубликована", + "cleanReviewMessageTitle": "## ✅ Aperant PR Review - ПРОЙДЕНО", + "cleanReviewMessageStatus": "**Статус:** Весь код в порядке", + "cleanReviewMessageFooter": "*Автоматическая проверка не обнаружила проблем. Сгенерировано Aperant.*", + "failedPostCleanReview": "Не удалось опубликовать чистую проверку", + "viewErrorDetails": "Показать детали", + "hideErrorDetails": "Скрыть детали", + "postBlockedStatus": "Опубликовать статус", + "postingBlockedStatus": "Публикация...", + "blockedStatusPosted": "Статус опубликован в PR", + "blockedStatusMessageTitle": "## 🤖 Aperant PR Review", + "blockedStatusMessageFooter": "*Проверка выявила блокирующие проблемы, которые необходимо устранить перед мержем. Сгенерировано Aperant.*", + "failedPostBlockedStatus": "Не удалось опубликовать статус", + "branchSynced_one": "Ветка синхронизирована ({{count}} коммит от базовой)", + "branchSynced_few": "Ветка синхронизирована ({{count}} коммита от базовой)", + "branchSynced_many": "Ветка синхронизирована ({{count}} коммитов от базовой)", + "branchSynced_other": "Ветка синхронизирована ({{count}} коммитов от базовой)", + "newCommitsOverlap_one": "{{count}} новый коммит ({{files}} файл(ов) с находками изменён)", + "newCommitsOverlap_few": "{{count}} новых коммита ({{files}} файл(ов) с находками изменено)", + "newCommitsOverlap_many": "{{count}} новых коммитов ({{files}} файл(ов) с находками изменено)", + "newCommitsOverlap_other": "{{count}} новых коммитов ({{files}} файл(ов) с находками изменено)", + "newCommitsNoOverlap_one": "{{count}} новый коммит (пересечений с находками нет)", + "newCommitsNoOverlap_few": "{{count}} новых коммита (пересечений с находками нет)", + "newCommitsNoOverlap_many": "{{count}} новых коммитов (пересечений с находками нет)", + "newCommitsNoOverlap_other": "{{count}} новых коммитов (пересечений с находками нет)", + "verifyChanges": "Проверить изменения", + "verifyAnyway": "Проверить", + "runFollowupAnyway": "Запустить повторную проверку, даже если файлы не пересекаются", + "disputed": "Оспорено", + "disputedByValidator": "Оспорено валидатором ({{count}})", + "crossValidatedBy": "Подтверждено {{count}} агентами", + "disputedSectionHint": "Эти находки были сообщены специалистами, но оспорены валидатором. Вы всё равно можете выбрать и опубликовать их.", + "logs": { + "agentActivity": "Активность агента", + "showMore": "Показать ещё {{count}}", + "hideMore": "Скрыть {{count}}" + } + }, + "downloads": { + "toggleExpand": "Переключить детали загрузки", + "downloading_one": "Загрузка {{count}} модели", + "downloading_few": "Загрузка {{count}} моделей", + "downloading_many": "Загрузка {{count}} моделей", + "downloading_other": "Загрузка {{count}} моделей", + "complete_one": "{{count}} загрузка завершена", + "complete_few": "{{count}} загрузки завершено", + "complete_many": "{{count}} загрузок завершено", + "complete_other": "{{count}} загрузок завершено", + "failed_one": "{{count}} загрузка не удалась", + "failed_few": "{{count}} загрузки не удались", + "failed_many": "{{count}} загрузок не удалось", + "failed_other": "{{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_one": "{{count}} сообщение", + "messageCount_few": "{{count}} сообщения", + "messageCount_many": "{{count}} сообщений", + "messageCount_other": "{{count}} сообщений", + "images": { + "pasteHint": "Вставьте изображение или снимок экрана", + "dropHint": "Перетащите изображение сюда", + "screenshotButton": "Прикрепить снимок экрана", + "removeImage": "Удалить изображение", + "imageCount_one": "Прикреплено {{count}} изображение", + "imageCount_few": "Прикреплено {{count}} изображения", + "imageCount_many": "Прикреплено {{count}} изображений", + "imageCount_other": "Прикреплено {{count}} изображений", + "maxImagesReached": "Достигнуто максимальное количество изображений", + "invalidType": "Недопустимый тип файла. Используйте PNG, JPEG, GIF или WebP.", + "processFailed": "Не удалось обработать изображение", + "dragOver": "Перетащите изображение для прикрепления", + "analysisUnsupported": "Примечание: анализ изображений пока не поддерживается. Изображения сохранены для справки, но не могут быть проанализированы моделью.", + "screenshotTooLarge": "Снимок экрана слишком большой ({{size}}МБ). Максимальный размер — {{max}}МБ. Попробуйте захватить меньшую область.", + "notAnalyzed": "Изображения сохранены для справки, но не были проанализированы моделью." + } + }, + "ideation": { + "converting": "Преобразование...", + "convertToTask": "Преобразовать в задачу Auto-Build", + "dismissIdea": "Отклонить идею", + "description": "Описание", + "rationale": "Обоснование", + "goToTask": "Перейти к задаче", + "conversionFailed": "Преобразование не удалось", + "conversionFailedDescription": "Не удалось преобразовать идею в задачу", + "conversionError": "Ошибка преобразования", + "conversionErrorDescription": "При преобразовании идеи произошла ошибка" + }, + "issues": { + "loadingMore": "Загрузка ещё...", + "scrollForMore": "Прокрутите для загрузки", + "allLoaded": "Все задачи загружены" + }, + "usage": { + "dataUnavailable": "Данные об использовании недоступны", + "dataUnavailableDescription": "Эндпоинт мониторинга использования для этого провайдера недоступен или не поддерживается.", + "activeAccount": "Активный аккаунт", + "usageAlert": "Предупреждение об использовании", + "accountExceedsThreshold": "Использование аккаунта превышает порог 90%", + "authentication": "Аутентификация", + "authenticationAriaLabel": "Аутентификация: {{provider}}", + "authenticationDetails": "Детали аутентификации", + "apiProfile": "API-профиль", + "apiKey": "API-ключ", + "oauth": "OAuth", + "codex": "Codex", + "codexSubscription": "Подписка Codex", + "claudeCode": "Claude Code", + "claudeCodeSubscription": "Подписка Claude Code", + "subscription": "Подписка", + "provider": "Провайдер", + "providerAnthropic": "Anthropic", + "providerZai": "Z.AI", + "providerZhipu": "ZHIPU AI", + "crossProvider": "Кросс-провайдер", + "crossProviderConfig": "Кросс-провайдер", + "crossProviderUsage": "Использование кросс-провайдера", + "crossProviderActive": "Кросс-провайдер активен", + "providerOpenRouter": "OpenRouter", + "providerUnknown": "Неизвестно", + "providerOpenAI": "OpenAI", + "providerGoogle": "Google AI", + "providerMistral": "Mistral", + "providerGroq": "Groq", + "providerXai": "xAI", + "providerBedrock": "AWS Bedrock", + "providerAzure": "Azure OpenAI", + "providerOllama": "Ollama", + "providerCustomEndpoint": "Пользовательский эндпоинт", + "billingSubscription": "Подписка", + "billingPayPerUse": "Оплата по использованию", + "unlimited": "Безлимитно", + "unlimitedApiKey": "Безлимитно (API-ключ)", + "noUsageMonitoring": "Мониторинг использования недоступен для этого провайдера", + "subscriptionBadge": "Подписка", + "subscriptionLimitsApply": "Действуют лимиты скорости", + "subscriptionMonitoringComingSoon": "У этого аккаунта с подпиской есть лимиты скорости, но мониторинг использования пока недоступен для этого провайдера.", + "queuePosition": "Позиция в очереди", + "inUse": "Используется", + "noAccount": "Нет аккаунта", + "noAccountDescription": "Добавьте аккаунт в настройках для начала работы", + "accountName": "Аккаунт", + "profile": "Профиль", + "id": "ID", + "created": "Создан", + "apiEndpoint": "API-эндпоинт", + "sessionQuota": "Квота сессии", + "notAvailable": "Н/Д", + "usageStatusAriaLabel": "Статус использования", + "usageBreakdown": "Разбивка использования", + "used": "использовано", + "loading": "Загрузка...", + "sessionDefault": "Сессия", + "weeklyDefault": "Неделя", + "resetsInHours": "Сброс через {{hours}}ч {{minutes}}м", + "resetsInDays": "Сброс через {{days}}д {{hours}}ч", + "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": "Aperant требует аутентификации 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": "Теперь вы можете использовать все AI-функции Aperant", + "authFailed": "Аутентификация не удалась", + "skipForNow": "Пропустить", + "manualTokenEntry": "Ручной ввод токена", + "tokenCommandHint": "Выполните claude setup-token для получения токена", + "emailOptionalPlaceholder": "Email (необязательно, для отображения)", + "saveToken": "Сохранить токен", + "accountNamePlaceholder": "Название аккаунта (например, Работа, Личный)", + "hasAuthenticatedAccount": "У вас есть хотя бы один аутентифицированный аккаунт Claude. Вы можете перейти к следующему шагу.", + "authNotDetected": "Аутентификация не обнаружена. Сначала выполните /login в терминале.", + "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. Активный аккаунт будет использоваться для AI-функций. Вы можете переключать аккаунты в любое время.", + "keychainTitle": "Безопасное хранилище", + "keychainDescription": "Ваши токены аутентификации надёжно хранятся в macOS Keychain.", + "noAccountsYet": "Аккаунты ещё не добавлены. Добавьте ваш первый аккаунт Claude ниже." + }, + "authTerminal": { + "failedToCreate": "Не удалось создать терминал", + "unknownError": "Неизвестная ошибка", + "instructionTitle": "Аутентификация Claude", + "step1": "Нажмите Enter для запуска аутентификации", + "step2": "Завершите аутентификацию в вашем браузере", + "step3": "Вернитесь сюда — аутентификация будет обнаружена автоматически", + "authFailed": "Аутентификация не удалась", + "connecting": "Подключение...", + "authenticate": "Аутентификация: {{profileName}}", + "authenticatedAs": "Аутентифицирован как {{email}}", + "authenticated": "Аутентифицирован!", + "authError": "Ошибка аутентификации", + "successMessage": "Аутентификация успешна! Закрытие..." + }, + "profileCreated": { + "title": "Профиль «{{profileName}}» создан.", + "instructions": "Для аутентификации этого профиля:", + "step1": "Перейдите в Настройки > Интеграции", + "step2": "Найдите профиль в разделе «Аккаунты Claude»", + "step3": "Нажмите «Аутентифицировать» для завершения входа", + "footer": "Аккаунт станет доступен после завершения аутентификации." + }, + "roadmap": { + "taskCompleted": "Выполнено", + "taskDeleted": "Удалено", + "taskArchived": "Архивировано", + "showMoreFeatures_one": "Показать ещё {{count}} функцию", + "showMoreFeatures_few": "Показать ещё {{count}} функции", + "showMoreFeatures_many": "Показать ещё {{count}} функций", + "showMoreFeatures_other": "Показать ещё {{count}} функций", + "showLessFeatures": "Показать меньше", + "archiveFeature": "Архивировать", + "archiveFeatureConfirmTitle": "Архивировать функцию?", + "archiveFeatureConfirmDescription": "Это удалит «{{title}}» из вашей дорожной карты.", + "goToTask": "Перейти к задаче", + "convertToTask": "Преобразовать в задачу Auto-Build", + "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 для продолжения использования Aperant.", + "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}}ч {{minutes}}м", + "countdownMinutesSeconds": "{{minutes}}м {{seconds}}с", + "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": "Последнее полученное обновление прогресса" + }, + "memory": { + "types": { + "gotcha": "Ловушка", + "decision": "Решение", + "preference": "Предпочтение", + "pattern": "Паттерн", + "requirement": "Требование", + "error_pattern": "Паттерн ошибки", + "module_insight": "Инсайт модуля", + "prefetch_pattern": "Паттерн предзагрузки", + "work_state": "Рабочее состояние", + "causal_dependency": "Причинная зависимость", + "task_calibration": "Калибровка задачи", + "e2e_observation": "E2E-наблюдение", + "dead_end": "Тупик", + "work_unit_outcome": "Результат рабочей единицы", + "workflow_recipe": "Рецепт воркфлоу", + "context_cost": "Стоимость контекста" + }, + "filters": { + "all": "Все", + "patterns": "Паттерны", + "errors": "Ошибки и ловушки", + "decisions": "Решения", + "insights": "Инсайты кода", + "calibration": "Калибровка" + }, + "badges": { + "needsReview": "Требует проверки", + "verified": "Проверено", + "pinned": "Закреплено", + "confidence": "Уверенность" + }, + "sources": { + "agent_explicit": "Агент", + "observer_inferred": "Наблюдатель", + "qa_auto": "QA", + "mcp_auto": "MCP", + "commit_auto": "Коммит", + "user_taught": "Пользователь" + }, + "health": { + "totalMemories": "Всего воспоминаний", + "avgConfidence": "Средняя уверенность", + "verified": "Проверено" + }, + "info": { + "database": "База данных", + "path": "Путь", + "embedding": "Эмбеддинг", + "memories": "Воспоминания" + }, + "status": { + "title": "Статус памяти", + "connected": "Подключено", + "notAvailable": "Недоступно", + "notConfigured": "Система памяти не настроена", + "enableInSettings": "Для включения памяти настройте её в параметрах проекта." + }, + "search": { + "title": "Поиск по памяти", + "placeholder": "Поиск воспоминаний...", + "resultsCount_one": "Найден {{count}} результат", + "resultsCount_few": "Найдено {{count}} результата", + "resultsCount_many": "Найдено {{count}} результатов", + "resultsCount_other": "Найдено {{count}} результатов" + }, + "browser": { + "title": "Браузер памяти", + "countOf": "{{filtered}} из {{total}} воспоминаний" + }, + "empty": "Воспоминаний пока нет. Они создаются автоматически по мере работы агентов над задачами.", + "emptyFilter": "Нет воспоминаний, соответствующих выбранному фильтру.", + "showAll": "Показать все воспоминания", + "expand": "Развернуть", + "collapse": "Свернуть", + "sections": { + "whatWorked": "Что сработало", + "whatFailed": "Что не сработало", + "approach": "Подход", + "recommendations": "Рекомендации", + "patterns": "Паттерны", + "gotchas": "Ловушки", + "changedFiles": "Изменённые файлы", + "fileInsights": "Инсайты файлов", + "subtasksCompleted": "Выполненные подзадачи", + "relatedFiles": "Связанные файлы", + "tags": "Теги", + "approachTried": "Испробованный подход", + "whyItFailed": "Почему не сработало", + "alternativeUsed": "Использованная альтернатива", + "steps": "Шаги" + }, + "actions": { + "verify": "Подтвердить", + "pin": "Закрепить", + "unpin": "Открепить", + "deprecate": "Удалить" + } + }, + "context": { + "tabs": { + "projectIndex": "Индекс проекта", + "memories": "Воспоминания" + } + }, + "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/desktop/src/shared/i18n/locales/ru/dialogs.json b/apps/desktop/src/shared/i18n/locales/ru/dialogs.json new file mode 100644 index 0000000000..aba652fe56 --- /dev/null +++ b/apps/desktop/src/shared/i18n/locales/ru/dialogs.json @@ -0,0 +1,239 @@ +{ + "initialize": { + "title": "Инициализация Aperant", + "description": "В этом проекте не инициализирован Aperant. Хотите настроить его сейчас?", + "willDo": "Будет выполнено:", + "createFolder": "Создание папки .auto-claude в вашем проекте", + "copyFramework": "Копирование файлов фреймворка Aperant", + "setupSpecs": "Настройка директории спецификаций для ваших задач", + "sourcePathNotConfigured": "Исходный путь не настроен", + "sourcePathNotConfiguredDescription": "Пожалуйста, укажите исходный путь Aperant в настройках приложения перед инициализацией.", + "initFailed": "Ошибка инициализации", + "initFailedDescription": "Не удалось инициализировать Aperant. Пожалуйста, попробуйте снова." + }, + "gitSetup": { + "title": "Требуется Git-репозиторий", + "description": "Aperant использует git для безопасной разработки функций в изолированных рабочих пространствах", + "notGitRepo": "Эта папка не является git-репозиторием", + "noCommits": "Git-репозиторий не содержит коммитов", + "needsInit": "Необходимо инициализировать Git, прежде чем Aperant сможет управлять вашим кодом.", + "needsCommit": "Для создания воркдеревьев Aperant требуется хотя бы один коммит.", + "willSetup": "Мы настроим git за вас:", + "initRepo": "Инициализация нового git-репозитория", + "createCommit": "Создание начального коммита с вашими текущими файлами", + "manual": "Предпочитаете сделать это вручную?", + "settingUp": "Настройка Git", + "initializingRepo": "Инициализация git-репозитория и создание начального коммита...", + "success": "Git инициализирован", + "readyToUse": "Ваш проект готов к использованию с Aperant!" + }, + "githubSetup": { + "connectTitle": "Подключение к GitHub", + "connectDescription": "Aperant требует GitHub для управления ветками кода и актуализации задач.", + "claudeTitle": "Подключение к Claude AI", + "claudeDescription": "Aperant использует Claude AI для интеллектуальных функций, таких как генерация дорожной карты, автоматизация задач и генерация идей.", + "aiProviderTitle": "Подключение к AI", + "aiProviderDescription": "Добавьте учётную запись AI-провайдера для работы функций генерации дорожной карты, автоматизации задач и генерации идей.", + "aiProviderReady": "У вас настроен хотя бы один AI-провайдер. Можете перейти к следующему шагу.", + "skipForNow": "Пропустить пока", + "continue": "Продолжить", + "selectRepo": "Выбор репозитория", + "repoDescription": "Aperant будет использовать этот репозиторий для управления ветками задач и поддержания актуальности кода.", + "selectBranch": "Выбор базовой ветки", + "branchDescription": "Выберите ветку, которую Aperant будет использовать как базовую для создания веток задач.", + "whyBranch": "Зачем выбирать ветку?", + "branchExplanation": "Aperant создаёт изолированные рабочие пространства для каждой задачи. Правильный выбор базовой ветки гарантирует, что ваши задачи начнутся с последней версией кода из основной ветки разработки.", + "ready": "Aperant готов к использованию! Теперь вы можете создавать задачи, которые автоматически будут основаны на ветке {{branchName}}.", + "createRepoAriaLabel": "Создать новый репозиторий на GitHub", + "linkRepoAriaLabel": "Привязать существующий репозиторий", + "goBackAriaLabel": "Вернуться к выбору репозитория", + "selectOwnerAriaLabel": "Выбрать {{owner}} владельцем репозитория", + "selectOrgAriaLabel": "Выбрать {{org}} владельцем репозитория", + "selectVisibilityAriaLabel": "Установить видимость репозитория: {{visibility}}" + }, + "worktrees": { + "title": "Воркдеревья", + "description": "Управление изолированными рабочими пространствами для задач Aperant", + "empty": "Нет воркдеревьев", + "emptyDescription": "Воркдеревья создаются автоматически, когда Aperant разрабатывает функции. Они обеспечивают изолированные рабочие пространства для каждой задачи.", + "merge": "Слить воркдерево", + "mergeDescription": "Слить изменения из этого воркдерева в базовую ветку.", + "delete": "Удалить воркдерево?", + "deleteDescription": "Это навсегда удалит воркдерево и все незафиксированные изменения. Действие необратимо.", + "bulkDeleteTitle": "Удалить {{count}} воркдеревьев?", + "bulkDeleteDescription": "Это навсегда удалит выбранные воркдеревья и все их незафиксированные изменения. Действие необратимо.", + "deleting": "Удаление...", + "deleteSelected": "Удалить выбранные" + }, + "worktreeCleanup": { + "title": "Завершить задачу", + "hasWorktree": "У задачи «{{taskTitle}}» всё ещё есть изолированное рабочее пространство (воркдерево).", + "willDelete": "Для отметки задачи как завершённой воркдерево и связанная ветка будут удалены.", + "warning": "Убедитесь, что вы слили или сохранили все нужные изменения перед продолжением.", + "confirm": "Удалить воркдерево и завершить", + "completing": "Завершение...", + "retry": "Попробовать снова", + "errorTitle": "Ошибка очистки", + "errorDescription": "Не удалось очистить воркдерево. Пожалуйста, попробуйте снова." + }, + "update": { + "title": "Aperant", + "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": "my-awesome-project", + "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": "Новая версия Aperant готова к загрузке", + "newVersion": "Новая версия", + "released": "Выпущено", + "downloading": "Загрузка...", + "downloadUpdate": "Загрузить обновление", + "installAndRestart": "Установить и перезапустить", + "installLater": "Установить позже", + "remindMeLater": "Напомнить позже", + "updateDownloaded": "Обновление успешно загружено! Нажмите «Установить», чтобы перезапустить и применить обновление.", + "downloadError": "Не удалось загрузить обновление", + "claudeCodeChangelog": "Просмотреть список изменений Claude Code", + "claudeCodeChangelogAriaLabel": "Просмотреть список изменений Claude Code (открывается в новом окне)", + "readOnlyVolumeTitle": "Невозможно установить из образа диска", + "readOnlyVolumeDescription": "Пожалуйста, переместите Aperant в папку Applications перед обновлением." + }, + "addCompetitor": { + "title": "Добавить конкурента", + "description": "Добавьте известного конкурента в ваш анализ...", + "competitorName": "Название конкурента", + "competitorNamePlaceholder": "например, Slack, Notion, Figma", + "competitorUrl": "URL сайта", + "competitorUrlPlaceholder": "например, https://example.com", + "competitorDescription": "Описание", + "competitorDescriptionPlaceholder": "Краткое описание того, чем занимается этот конкурент...", + "relevance": "Релевантность", + "selectRelevance": "Выберите релевантность", + "highRelevance": "Высокая — прямой конкурент", + "mediumRelevance": "Средняя — частичное пересечение", + "lowRelevance": "Низкая — косвенная", + "nameRequired": "Название конкурента обязательно", + "urlRequired": "URL сайта обязателен", + "invalidUrl": "Пожалуйста, введите корректный URL", + "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/desktop/src/shared/i18n/locales/ru/errors.json b/apps/desktop/src/shared/i18n/locales/ru/errors.json new file mode 100644 index 0000000000..70f48dfa66 --- /dev/null +++ b/apps/desktop/src/shared/i18n/locales/ru/errors.json @@ -0,0 +1,9 @@ +{ + "task": { + "parseImplementationPlan": "Не удалось разобрать implementation_plan.json для {{specId}}: {{error}}", + "jsonError": { + "titleSuffix": "(Ошибка JSON)", + "description": "⚠️ Ошибка разбора JSON: {{error}}\n\nФайл implementation_plan.json повреждён. Запустите автоисправление в бэкенде или исправьте файл вручную." + } + } +} diff --git a/apps/desktop/src/shared/i18n/locales/ru/gitlab.json b/apps/desktop/src/shared/i18n/locales/ru/gitlab.json new file mode 100644 index 0000000000..49462d1a49 --- /dev/null +++ b/apps/desktop/src/shared/i18n/locales/ru/gitlab.json @@ -0,0 +1,208 @@ +{ + "title": "Задачи GitLab", + "states": { + "opened": "Открытые", + "closed": "Закрытые" + }, + "complexity": { + "simple": "Простая", + "standard": "Стандартная", + "complex": "Сложная" + }, + "header": { + "open": "открыто", + "searchPlaceholder": "Поиск задач..." + }, + "filters": { + "opened": "Открытые", + "closed": "Закрытые", + "all": "Все" + }, + "empty": { + "noMatch": "Нет задач, соответствующих вашему поиску", + "selectIssue": "Выберите задачу для просмотра деталей" + }, + "notConnected": { + "title": "GitLab не подключён", + "description": "Настройте ваш токен GitLab и проект в настройках проекта для синхронизации задач.", + "openSettings": "Открыть настройки" + }, + "detail": { + "notes": "заметки", + "viewTask": "Просмотреть задачу", + "createTask": "Создать задачу", + "taskLinked": "Задача привязана", + "taskId": "ID задачи", + "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": "Автоопределение (main/master)", + "searchBranches": "Поиск веток...", + "noMatchingBranches": "Нет подходящих веток", + "noBranchesFound": "Ветки не найдены", + "branchFromNote": "Все новые задачи будут ответвляться от", + "autoSyncOnLoad": "Автосинхронизация при загрузке", + "autoSyncDescription": "Автоматически загружать тикеты при открытии проекта", + "cli": { + "required": "Требуется GitLab CLI", + "notInstalled": "GitLab CLI (glab) необходим для аутентификации через OAuth. Установите его, чтобы использовать опцию «Использовать OAuth».", + "installButton": "Установить glab", + "installing": "Установка...", + "installSuccess": "Установка запущена в вашем терминале. Завершите её и нажмите «Обновить».", + "refresh": "Обновить", + "learnMore": "Подробнее", + "installed": "GitLab CLI установлен:" + } + }, + "mergeRequests": { + "title": "Merge Request-ы GitLab", + "newMR": "Новый Merge Request", + "selectMR": "Выберите merge request для просмотра деталей", + "states": { + "opened": "Открытые", + "closed": "Закрытые", + "merged": "Слитые", + "locked": "Заблокированные" + }, + "filters": { + "opened": "Открытые", + "closed": "Закрытые", + "merged": "Слитые", + "all": "Все" + } + }, + "mrReview": { + "runReview": "Запустить AI-ревью", + "reviewing": "Ревью...", + "followupReview": "Повторное ревью", + "newCommits": "новый коммит", + "newCommitsPlural": "новых коммита", + "cancel": "Отмена", + "postFindings": "Опубликовать результаты", + "posting": "Публикация...", + "postedTo": "Опубликовано в GitLab", + "approve": "Одобрить", + "approving": "Одобрение...", + "merge": "Слить MR", + "merging": "Слияние...", + "aiReviewResult": "Результат AI-ревью", + "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/desktop/src/shared/i18n/locales/ru/navigation.json b/apps/desktop/src/shared/i18n/locales/ru/navigation.json new file mode 100644 index 0000000000..9e328f791b --- /dev/null +++ b/apps/desktop/src/shared/i18n/locales/ru/navigation.json @@ -0,0 +1,87 @@ +{ + "sections": { + "project": "Проект", + "tools": "Инструменты" + }, + "items": { + "kanban": "Kanban-доска", + "terminals": "Терминалы агентов", + "insights": "Аналитика", + "roadmap": "Дорожная карта", + "ideation": "Генерация идей", + "changelog": "История изменений", + "context": "Контекст", + "githubIssues": "GitHub Issues", + "githubPRs": "GitHub PRs", + "gitlabIssues": "GitLab Issues", + "gitlabMRs": "GitLab MRs", + "worktrees": "Воркtree-ветки", + "agentTools": "Обзор MCP" + }, + "actions": { + "settings": "Настройки", + "help": "Помощь и обратная связь", + "newTask": "Новая задача", + "collapseSidebar": "Свернуть боковую панель", + "expandSidebar": "Развернуть боковую панель", + "sponsor": "Поддержать нас" + }, + "tooltips": { + "settings": "Настройки приложения", + "help": "Помощь и обратная связь" + }, + "messages": { + "initializeToCreateTasks": "Инициализируйте Aperant для создания задач" + }, + "updateBanner": { + "title": "Доступно обновление", + "version": "Версия {{version}} готова к установке", + "updateAndRestart": "Обновить и перезапустить", + "installAndRestart": "Установить и перезапустить", + "downloading": "Загрузка...", + "dismiss": "Закрыть", + "downloadError": "Не удалось загрузить обновление", + "readOnlyVolumeWarning": "Перенесите приложение в папку «Программы» для обновления" + }, + "claudeCode": { + "checking": "Проверка Claude Code...", + "upToDate": "Claude Code актуален", + "updateAvailable": "Доступно обновление Claude Code", + "notInstalled": "Claude Code не установлен", + "error": "Ошибка при проверке Claude Code", + "installed": "Установлен", + "outdated": "Доступно обновление", + "missing": "Не установлен", + "current": "Текущая", + "latest": "Последняя", + "path": "Путь", + "lastChecked": "Последняя проверка", + "learnMore": "Узнать больше о Claude Code", + "learnMoreAriaLabel": "Узнать больше о Claude Code (откроется в новом окне)", + "viewChangelog": "Просмотреть историю изменений Claude Code", + "viewChangelogAriaLabel": "Просмотреть историю изменений Claude Code (откроется в новом окне)", + "updateWarningTitle": "Обновить Claude Code?", + "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/desktop/src/shared/i18n/locales/ru/onboarding.json b/apps/desktop/src/shared/i18n/locales/ru/onboarding.json new file mode 100644 index 0000000000..edad27cadb --- /dev/null +++ b/apps/desktop/src/shared/i18n/locales/ru/onboarding.json @@ -0,0 +1,261 @@ +{ + "wizard": { + "title": "Мастер настройки", + "description": "Настройте ваше окружение Aperant за несколько простых шагов", + "helpText": "Этот мастер поможет вам настроить окружение всего за несколько шагов. Вы можете настроить OAuth-токен Claude, включить функции памяти и создать первую задачу." + }, + "welcome": { + "title": "Добро пожаловать в Aperant", + "subtitle": "Создавайте программное обеспечение автономно с помощью AI-агентов", + "getStarted": "Начать", + "skip": "Пропустить настройку", + "features": { + "aiPowered": { + "title": "Разработка на базе AI", + "description": "Генерируйте код и создавайте функции с помощью агентов Claude Code" + }, + "specDriven": { + "title": "Процесс на основе спецификаций", + "description": "Определяйте задачи с чёткими спецификациями и позвольте Aperant взять реализацию на себя" + }, + "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": "Память Aperant помогает запоминать контекст между сессиями разработки", + "enableMemory": "Включить память", + "enableMemoryDescription": "Постоянная память между сессиями с использованием встроенной базы данных", + "memoryDisabledInfo": "Память отключена. Результаты сессий будут сохраняться только в локальных файлах. Включите память для постоянного контекста между сессиями с семантическим поиском.", + "embeddingProvider": "Провайдер эмбеддингов", + "embeddingProviderDescription": "Провайдер для семантического поиска (необязательно — ключевой поиск работает без него)", + "selectEmbeddingModel": "Выберите модель эмбеддингов", + "openaiApiKey": "API-ключ OpenAI", + "openaiApiKeyDescription": "Требуется для эмбеддингов OpenAI", + "openaiGetKey": "Получите ваш ключ на", + "voyageApiKey": "API-ключ Voyage AI", + "voyageApiKeyDescription": "Требуется для эмбеддингов Voyage AI", + "voyageEmbeddingModel": "Модель эмбеддингов", + "googleApiKey": "API-ключ Google AI", + "googleApiKeyDescription": "Требуется для эмбеддингов Google AI", + "azureConfig": "Конфигурация Azure OpenAI", + "azureApiKey": "API-ключ", + "azureBaseUrl": "Базовый URL", + "azureEmbeddingDeployment": "Название развёртывания эмбеддингов", + "memoryInfo": "Память хранит открытия, паттерны и выводы о вашей кодовой базе, чтобы будущие сессии начинались с уже загруженным контекстом.", + "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": "Базовый URL", + "embeddingModel": "Модель эмбеддингов", + "embeddingDim": "Размерность эмбеддингов", + "embeddingDimDescription": "Требуется для эмбеддингов Ollama (например, 768 для nomic-embed-text)", + "modelRecommendation": "Рекомендуется: qwen3-embedding:4b (баланс), :8b (качество), :0.6b (скорость)" + }, + "completion": { + "title": "Всё готово!", + "subtitle": "Aperant готов помочь вам создавать отличное программное обеспечение", + "setupComplete": "Настройка завершена", + "setupCompleteDescription": "Ваше окружение настроено и готово к работе. Вы можете немедленно начать создавать задачи или изучить приложение в своём темпе.", + "whatsNext": "Что дальше?", + "createTask": { + "title": "Создать задачу", + "description": "Начните с создания первой задачи, чтобы увидеть Aperant в действии.", + "action": "Открыть создание задачи" + }, + "customizeSettings": { + "title": "Настроить параметры", + "description": "Настройте предпочтения, настройте интеграции или повторно запустите этот мастер.", + "action": "Открыть настройки" + }, + "exploreDocs": { + "title": "Изучить документацию", + "description": "Узнайте больше о расширенных функциях, лучших практиках и устранении неполадок." + }, + "finish": "Завершить и начать разработку", + "rerunHint": "Вы всегда можете повторно запустить этот мастер из Настройки → Приложение" + }, + "steps": { + "welcome": "Добро пожаловать", + "accounts": "Аккаунты", + "devtools": "Инструменты", + "privacy": "Конфиденциальность", + "memory": "Память", + "done": "Готово" + }, + "privacy": { + "title": "Помогите улучшить Aperant", + "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 Code...", + "info": { + "title": "Что такое Claude Code?", + "description": "Claude Code — официальный CLI от Anthropic, обеспечивающий AI-функции Aperant. Он предоставляет безопасную аутентификацию и прямой доступ к моделям Claude." + }, + "status": { + "installed": "Установлено", + "outdated": "Доступно обновление", + "notFound": "Не установлено" + }, + "version": { + "current": "Текущая версия", + "latest": "Последняя версия" + }, + "install": { + "button": "Установить Claude Code", + "updating": "Обновить Claude Code", + "inProgress": "Установка...", + "success": "Команда установки отправлена в терминал. Пожалуйста, завершите установку там.", + "instructions": "Установщик откроется в вашем терминале. Следуйте инструкциям для завершения установки." + }, + "learnMore": "Подробнее о Claude Code" + }, + "devtools": { + "title": "Инструменты разработчика", + "description": "Выберите предпочитаемые IDE, терминал и CLI для работы с воркдеревьями Aperant", + "detecting": "Определение установленных инструментов...", + "detectAgain": "Определить снова", + "whyConfigure": "Зачем это настраивать?", + "whyConfigureDescription": "Когда Aperant разрабатывает функции в изолированных воркдеревьях, вы можете открывать их напрямую в предпочитаемой IDE или терминале для тестирования и проверки изменений.", + "ide": { + "label": "Предпочитаемая IDE", + "description": "Aperant будет открывать воркдеревья в этом редакторе", + "customPath": "Пользовательский путь к IDE" + }, + "terminal": { + "label": "Предпочитаемый терминал", + "description": "Aperant будет открывать сессии терминала здесь", + "customPath": "Пользовательский путь к терминалу" + }, + "cli": { + "label": "Предпочитаемый CLI", + "description": "CLI-инструмент для AI-сессий терминала", + "customPath": "Пользовательский путь к CLI" + }, + "detectedSummary": "Обнаружено в вашей системе:", + "noToolsDetected": "Дополнительные инструменты не обнаружены (будут использованы VS Code и системный терминал)", + "custom": "Пользовательский...", + "saveAndContinue": "Сохранить и продолжить" + }, + "accounts": { + "title": "Добавьте ваши AI-аккаунты", + "description": "Подключите аккаунты ваших AI-провайдеров. Вы можете добавить ещё позже в настройках.", + "buttons": { + "back": "Назад", + "continue": "Продолжить", + "skip": "Пропустить пока" + } + }, + "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/desktop/src/shared/i18n/locales/ru/settings.json b/apps/desktop/src/shared/i18n/locales/ru/settings.json new file mode 100644 index 0000000000..f4a3f9781f --- /dev/null +++ b/apps/desktop/src/shared/i18n/locales/ru/settings.json @@ -0,0 +1,1188 @@ +{ + "title": "Настройки", + "tabs": { + "app": "Настройки приложения", + "project": "Настройки проекта" + }, + "sections": { + "appearance": { + "title": "Внешний вид", + "description": "Настройте отображение Aperant" + }, + "display": { + "title": "Отображение", + "description": "Настройте размер элементов интерфейса" + }, + "language": { + "title": "Язык", + "description": "Выберите предпочитаемый язык" + }, + "devtools": { + "title": "Инструменты разработчика", + "description": "Настройки IDE и терминала" + }, + "agent": { + "title": "Настройки агента", + "description": "Модель и фреймворк по умолчанию" + }, + "paths": { + "title": "Пути", + "description": "Пути к CLI-инструментам и фреймворкам" + }, + "accounts": { + "title": "Аккаунты", + "description": "Аккаунты Claude и API-эндпоинты" + }, + "updates": { + "title": "Обновления", + "description": "Обновления Aperant" + }, + "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": "Базовый URL", + "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": "Модель Haiku (необязательно)", + "sonnetLabel": "Модель Sonnet (необязательно)", + "opusLabel": "Модель Opus (необязательно)", + "defaultPlaceholder": "напр., claude-sonnet-4-6", + "haikuPlaceholder": "напр., claude-haiku-4-5-20251001", + "sonnetPlaceholder": "напр., claude-sonnet-4-6", + "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-6)", + "searchPlaceholder": "Поиск моделей...", + "noResults": "Модели не найдены", + "discoveryNotAvailable": "Обнаружение моделей недоступно. Введите название модели вручную.", + "ollamaLoading": "Загрузка моделей Ollama...", + "ollamaNoModels": "Модели Ollama не установлены", + "ollamaNoModelsHint": "Установите модели в Настройках агента → вкладка Ollama", + "apiKeyOnly": "Только API-ключ" + }, + "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": "Aperant", + "aiTerminalNaming": "AI-именование терминалов", + "aiTerminalNamingDescription": "Автоматически называть терминалы на основе команд (использует модель AI Naming)", + "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": "Системный PATH", + "sourceBundled": "Встроенный", + "sourceFallback": "Запасной вариант", + "notDetected": "Не обнаружен", + "autoClaudePath": "Путь Aperant", + "autoClaudePathDescription": "Относительный путь к директории auto-claude в проектах", + "autoClaudePathPlaceholder": "auto-claude (по умолчанию)", + "autoNameTerminals": "Автоматически именовать терминалы", + "autoNameTerminalsDescription": "Использовать AI для генерации описательных имён вкладок терминала на основе активности" + }, + "theme": { + "title": "Внешний вид", + "description": "Настройте отображение Aperant", + "mode": "Режим", + "modeDescription": "Выберите светлую или тёмную тему", + "light": "Светлая", + "dark": "Тёмная", + "system": "Системная", + "colorTheme": "Цветовая тема", + "colorThemeDescription": "Выберите предпочитаемую цветовую палитру" + }, + "devtools": { + "title": "Инструменты разработчика", + "description": "Настройте предпочитаемые IDE, терминал и шрифты терминала", + "detecting": "Обнаружение установленных инструментов...", + "detectAgain": "Обнаружить снова", + "tabTools": "Инструменты", + "tabTerminalFonts": "Шрифты терминала", + "ide": { + "label": "Предпочитаемая IDE", + "description": "Aperant будет открывать воркtree в этом редакторе", + "placeholder": "Выберите IDE...", + "customPath": "Пользовательский путь к IDE", + "customPathPlaceholder": "/путь/к/вашей/ide" + }, + "terminal": { + "label": "Предпочитаемый терминал", + "description": "Aperant будет открывать терминальные сессии здесь", + "placeholder": "Выберите терминал...", + "customPath": "Пользовательский путь к терминалу", + "customPathPlaceholder": "/путь/к/вашему/терминалу" + }, + "cli": { + "label": "Предпочитаемый CLI", + "description": "CLI-инструмент для терминальных сессий с AI", + "placeholder": "Выберите CLI...", + "customPath": "Пользовательский путь к CLI", + "customPathPlaceholder": "/путь/к/вашему/cli" + }, + "detected": "Обнаружен", + "notInstalled": "Не установлен", + "detectedSummary": "Обнаружено в системе:", + "noToolsDetected": "Дополнительные инструменты не обнаружены (будут использоваться VS Code и системный терминал)", + "autoNameClaude": { + "label": "Автоименование Claude-терминалов", + "description": "Использовать AI для генерации описательного имени Claude-терминалов на основе первого сообщения" + }, + "yoloMode": { + "label": "Режим YOLO", + "description": "Запустить Claude с флагом --dangerously-skip-permissions, обходя все запросы безопасности. Используйте с крайней осторожностью.", + "warning": "Этот режим обходит систему разрешений Claude. Включайте только если полностью доверяете выполняемому коду." + } + }, + "updates": { + "title": "Обновления", + "description": "Управление обновлениями Aperant", + "appUpdateReady": "Обновление приложения готово", + "newVersion": "Новая версия", + "released": "Выпущено", + "downloading": "Загрузка...", + "updateDownloaded": "Обновление загружено! Нажмите «Установить» для перезапуска и применения обновления.", + "installAndRestart": "Установить и перезапустить", + "downloadUpdate": "Загрузить обновление", + "version": "Версия", + "loading": "Загрузка...", + "checkingForUpdates": "Проверка обновлений...", + "newVersionAvailable": "Доступна новая версия:", + "latestVersion": "У вас установлена последняя версия.", + "viewRelease": "Посмотреть полный релиз на GitHub", + "unableToCheck": "Не удалось проверить обновления", + "checkForUpdates": "Проверить обновления", + "autoUpdateProjects": "Автообновление проектов", + "autoUpdateProjectsDescription": "Автоматически обновлять Aperant в проектах при выходе новой версии", + "betaUpdates": "Бета-обновления", + "betaUpdatesDescription": "Получать предрелизные бета-версии с новыми функциями (может быть менее стабильным)", + "stableDowngradeAvailable": "Доступна стабильная версия", + "stableDowngradeDescription": "Вы используете бета-версию. Поскольку бета-обновления отключены, можно переключиться на последний стабильный релиз.", + "stableVersion": "Стабильная версия", + "downloadStableVersion": "Загрузить стабильную версию", + "readOnlyVolumeTitle": "Невозможно установить с образа диска", + "readOnlyVolumeDescription": "Aperant запущен с образа диска только для чтения (DMG). Перетащите приложение в папку «Программы» и перезапустите его оттуда для установки обновлений.", + "downloadError": "Не удалось загрузить обновление" + }, + "notifications": { + "title": "Уведомления", + "description": "Настройте параметры уведомлений по умолчанию", + "onTaskComplete": "При завершении задачи", + "onTaskCompleteDescription": "Уведомлять при успешном завершении задачи", + "onTaskFailed": "При ошибке задачи", + "onTaskFailedDescription": "Уведомлять при возникновении ошибки в задаче", + "onReviewNeeded": "При необходимости проверки", + "onReviewNeededDescription": "Уведомлять когда QA требует вашей проверки", + "sound": "Звук", + "soundDescription": "Воспроизводить звук с уведомлениями" + }, + "actions": { + "save": "Сохранить настройки", + "rerunWizard": "Перезапустить мастер настройки", + "rerunWizardDescription": "Запустить мастер настройки снова" + }, + "projectSections": { + "general": { + "title": "Основные", + "description": "Конфигурация Auto-Build и агента", + "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 Issues", + "integrationTitle": "Интеграция с GitHub", + "integrationDescription": "Подключитесь к GitHub для отслеживания задач", + "syncDescription": "Синхронизация с GitHub Issues", + "defaultBranch": { + "label": "Ветка по умолчанию", + "description": "Базовая ветка для создания воркtree задач", + "autoDetect": "Автоопределение (main/master)", + "searchPlaceholder": "Поиск веток...", + "noBranchesFound": "Ветки не найдены", + "selectedBranchHelp": "Все новые задачи будут ветвиться от {{branch}}" + }, + "pushNewBranches": { + "label": "Автоматически отправлять новые ветки", + "description": "Отправлять новые ветки задач и воркtree на GitHub и автоматически настраивать отслеживание" + } + }, + "gitlab": { + "title": "GitLab", + "description": "Синхронизация GitLab Issues", + "integrationTitle": "Интеграция с GitLab", + "integrationDescription": "Подключитесь к GitLab для отслеживания задач", + "syncDescription": "Синхронизация с GitLab Issues" + }, + "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": "Настроен", + "ollamaNotConfigured": "Выберите модели ниже", + "phaseConfigNote": "Эти настройки будут использоваться по умолчанию при создании новых задач с данным профилем. Их можно переопределить для каждой задачи в мастере создания задачи.", + "adaptiveThinking": { + "badge": "Адаптивное", + "tooltip": "Opus использует адаптивное мышление — он динамически решает, сколько думать в рамках установленного бюджетного лимита уровня мышления." + }, + "reasoning": { + "adaptive": "Адаптивное", + "budget": "Бюджет", + "reasoning": "Рассуждение", + "thinking": "Мышление", + "noThinking": "(Без мышления)", + "toggle": { + "off": "Выкл", + "on": "Вкл" + }, + "badgeTooltip": { + "adaptive_effort": "Динамически решает, сколько думать в рамках бюджетного лимита", + "thinking_tokens": "Мышление на основе бюджета с настраиваемым распределением токенов", + "reasoning_effort": "Уровни усилий рассуждения (низкий/средний/высокий)", + "thinking_toggle": "Включение/выключение мышления", + "none": "Расширенное мышление не поддерживается" + } + }, + "phases": { + "spec": { + "label": "Создание спецификации", + "description": "Исследование, требования, сбор контекста" + }, + "planning": { + "label": "Планирование", + "description": "Планирование реализации и архитектура" + }, + "coding": { + "label": "Разработка", + "description": "Непосредственная реализация кода" + }, + "qa": { + "label": "QA-проверка", + "description": "Обеспечение качества и валидация" + } + }, + "providerOverrides": { + "title": "Маппинг моделей провайдера", + "description": "Настройте, какую модель использует каждый провайдер для каждого сокращённого имени", + "defaultMapping": "По умолчанию", + "yourOverride": "Ваш вариант", + "shorthand": "Сокращённое имя", + "useDefault": "Использовать по умолчанию", + "resetAll": "Сбросить всё", + "noConnectedProviders": "Нет подключённых провайдеров. Добавьте аккаунты в настройках Аккаунтов для настройки маппинга моделей.", + "equivalentNote": "Когда активен не-Anthropic провайдер, эти маппинги определяют, какая модель используется для каждой фазы." + }, + "providerTabs": { + "moreProviders": "Ещё", + "noProviders": "Нет подключённых провайдеров. Добавьте аккаунты в настройках Аккаунтов для настройки специфических параметров агента провайдера.", + "configureFor": "Настроить параметры агента для {{provider}}", + "crossProvider": "Кросс-провайдерный", + "crossProviderDisabledTooltip": "Подключите два или более аккаунта провайдеров для включения кросс-провайдерных возможностей", + "needsSetup": "Требуется настройка" + }, + "crossProviderTab": { + "title": "Кросс-провайдерная конфигурация", + "description": "Назначьте разный провайдер и модель для каждой фазы конвейера для максимальной гибкости.", + "activateInfo": "Задачи, созданные при активной данной конфигурации, будут использовать кросс-провайдерную настройку.", + "featureModelsTitle": "Модели функций", + "featureModelsDescription": "Настройте модели для функций вне конвейера (Аналитика, Генерация идей и др.)" + }, + "customProfile": { + "name": "Пользовательский (кросс-провайдерный)", + "description": "Смешивайте разных провайдеров и модели для каждой фазы", + "phaseAssignment": "Назначьте провайдера и модель для каждой фазы" + }, + "ollamaModels": { + "title": "Модели Ollama", + "description": "Управляйте локально установленными моделями для задач AI-агента", + "installed": "Установленные модели", + "installedCount": "{{count}} модел(и)", + "noModels": "Модели LLM не установлены", + "recommended": "Рекомендуется для разработки", + "recommendedDescription": "Популярные модели, оптимизированные для генерации кода и рассуждений", + "download": "Загрузить", + "downloading": "Загрузка...", + "refresh": "Обновить", + "loading": "Загрузка моделей...", + "ollamaNotAvailable": "Подключите Ollama в настройках Аккаунтов для управления моделями" + } + }, + "workspace": { + "roles": { + "backend": "Бэкенд", + "frontend": "Фронтенд", + "mobile": "Мобильный", + "shared": "Общий", + "apiGateway": "API-шлюз", + "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": "Email (необязательно, для отображения)", + "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": "API-ключ OpenAI", + "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": "Email (необязательно, для отображения)", + "saveToken": "Сохранить токен", + "accountNamePlaceholder": "Название аккаунта (напр., Работа, Личный)" + }, + "customEndpoints": { + "description": "Настройте пользовательские Anthropic-совместимые API-эндпоинты", + "addButton": "Добавить профиль", + "activeBadge": "Активен", + "customModels": "Пользовательские модели: {{models}}", + "setActive": { + "label": "Сделать активным", + "loading": "Применение..." + }, + "switchToOauth": { + "label": "Использовать Claude Code", + "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": "Перетащите для изменения порядка. Система будет переключаться на следующий доступный аккаунт по порядку.", + "tabs": { + "default": "По умолчанию", + "crossProvider": "Кросс-провайдерный" + }, + "crossProviderDescription": "Этот приоритет используется при активном кросс-провайдерном режиме. Когда несколько аккаунтов используют одного провайдера, система выбирает лучший доступный на основе этого порядка.", + "setActive": "Сделать активным", + "setActiveTooltip": "Сделать основным аккаунтом", + "noAccounts": "Аккаунты не настроены. Добавьте аккаунты выше для установки приоритета.", + "noEmail": "Нет email", + "active": "Активен", + "inUse": "Используется", + "next": "Следующий", + "unlimited": "Без ограничений", + "unavailable": "Недоступен", + "typeOAuth": "OAuth", + "typeAPI": "API", + "payPerUse": "Оплата за использование", + "needsAuth": "Не аутентифицирован", + "duplicateUsage": "Дублирующийся шаблон использования", + "duplicateUsageHint": "Эти OAuth-профили имеют совпадающие значения использования. Убедитесь, что каждый профиль привязан к разному аккаунту, если это неожиданно.", + "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": "Не удалось запустить аутентификацию. Попробуйте ещё раз." + } + }, + "providers": { + "card": { + "oauth": "OAuth", + "codex": "Codex", + "codexSubscription": "Подписка Codex", + "claudeCode": "Claude Code", + "claudeCodeSubscription": "Подписка Claude Code", + "zaiCodingPlan": "Тарифный план для разработки", + "zaiUsageBased": "Оплата за использование", + "zaiCodingPlanSubscription": "Z.AI Тарифный план для разработки", + "apiKey": "API-ключ", + "active": "Активен", + "setDefault": "Сделать активным", + "edit": "Редактировать аккаунт", + "reauth": "Повторно аутентифицироваться", + "delete": "Удалить аккаунт", + "showKey": "Показать API-ключ", + "hideKey": "Скрыть API-ключ", + "oauthAccount": "OAuth-аккаунт", + "oauthLinked": "Связанный аккаунт", + "noEndpoint": "Нет эндпоинта", + "customModels": "{{count}} модел(и) настроено" + }, + "section": { + "envDetected": "Из окружения", + "envCredentialDetected": "Учётные данные обнаружены из переменной окружения {{envVar}}", + "noAccounts": "Аккаунты не настроены", + "addOAuth": "Добавить OAuth-аккаунт", + "addClaudeCode": "Добавить аккаунт Claude Code", + "addCodexSubscription": "Добавить подписку Codex", + "addCodingPlan": "Добавить тарифный план для разработки", + "addUsageBased": "Добавить API-ключ с оплатой за использование", + "addApiKey": "Добавить API-ключ", + "addEndpoint": "Добавить эндпоинт" + }, + "dialog": { + "addTitle": "Добавить аккаунт", + "editTitle": "Редактировать аккаунт", + "deleteTitle": "Удалить аккаунт?", + "deleteDescription": "Вы уверены, что хотите удалить этот аккаунт? Это действие нельзя отменить.", + "cancel": "Отмена", + "close": "Закрыть", + "delete": "Удалить", + "deleting": "Удаление...", + "save": "Сохранить изменения", + "add": "Добавить аккаунт", + "optional": "(необязательно)", + "oauthDescription": "Подключиться с помощью OAuth-аутентификации", + "apiKeyDescription": "Добавьте ваш API-ключ и конфигурацию", + "zaiCodingPlanDescription": "Добавьте ваш API-ключ Z.AI Coding Plan для использования моделей GLM по подписке", + "zaiUsageBasedDescription": "Добавьте ваш API-ключ Z.AI с оплатой за использование для доступа к моделям GLM", + "codexOAuthDescription": "Войдите с подпиской ChatGPT Plus или Pro для использования моделей Codex", + "codexAuthenticating": "Открывается вход в OpenAI в браузере...", + "codexWaiting": "Ожидание аутентификации в браузере...", + "codexSuccess": "Аутентификация через OpenAI Codex выполнена", + "codexError": "Ошибка аутентификации OpenAI: {{error}}", + "codexAuthenticate": "Аутентифицироваться через OpenAI", + "codexReauthenticate": "Повторно аутентифицироваться через OpenAI", + "oauthInstructions": "Для добавления OAuth-аккаунта используйте процесс аутентификации Claude Code на вкладке Claude Code выше. OAuth-аккаунты привязаны к вашей подписке Claude.ai.", + "oauthAuthenticate": "Аутентифицироваться через Anthropic", + "oauthReauthenticate": "Повторно аутентифицироваться через Anthropic", + "oauthAuthenticating": "Открывается браузер...", + "oauthWaiting": "Ожидание авторизации...", + "oauthSuccess": "Аутентифицировано как {{email}}", + "oauthError": "Ошибка аутентификации: {{error}}", + "oauthFallback": "Использовать терминал (запасной вариант)", + "oauthFallbackDescription": "Если вход через браузер не работает, используйте встроенный терминал", + "oauthNameRequired": "Введите название аккаунта перед аутентификацией", + "modelsDescription": "Добавьте ID моделей, доступных на этом эндпоинте. Они появятся в выборщике моделей.", + "fields": { + "name": "Название аккаунта", + "apiKey": "API-ключ", + "baseUrl": "Базовый URL", + "region": "Регион AWS", + "models": "Модели" + }, + "placeholders": { + "name": "Мой аккаунт", + "apiKey": "sk-...", + "baseUrl": "https://...", + "modelId": "ID модели (напр. llama-3.1-70b)", + "modelLabel": "Отображаемое имя" + }, + "toast": { + "added": "Аккаунт добавлен", + "updated": "Аккаунт обновлён", + "error": "Не удалось сохранить аккаунт", + "duplicateEmail": "Этот email уже зарегистрирован как «{{existingName}}»", + "createProfileFailed": "Не удалось создать профиль", + "authPrepareFailed": "Не удалось подготовить терминал", + "unexpectedError": "Неожиданная ошибка" + } + }, + "toast": { + "deleted": "Аккаунт удалён", + "deleteFailed": "Не удалось удалить аккаунт", + "reauthStarted": "Открывается аутентификация...", + "reauthSuccess": "Повторная аутентификация выполнена успешно", + "reauthFailed": "Повторная аутентификация не удалась" + }, + "categories": { + "popular": "Популярные", + "infrastructure": "Инфраструктура", + "local": "Локальные и пользовательские" + }, + "ollama": { + "connection": { + "checking": "Проверка подключения к Ollama...", + "connected": "Подключено", + "connectedDescription": "Ollama запущен и готов к работе", + "modelsAvailable": "Установлено {{count}} модел(и) LLM", + "noModels": "Модели LLM пока не установлены", + "customUrl": "Пользовательский URL", + "customUrlPlaceholder": "http://localhost:11434", + "notInstalled": "Ollama не установлен", + "notInstalledDescription": "Установите Ollama для запуска открытых AI-моделей локально", + "notRunning": "Ollama не запущен", + "notRunningDescription": "Запустите сервис Ollama для подключения", + "install": "Установить Ollama", + "retry": "Повторить", + "learnMore": "Узнать больше", + "autoConnected": "Автоматически подключено как локальный провайдер", + "startCommand": "Выполните 'ollama serve' в терминале" + } + } + }, + "debug": { + "title": "Отладка и логи", + "description": "Доступ к логам и отладочной информации для диагностики", + "errorReporting": { + "label": "Анонимные отчёты об ошибках", + "description": "Отправлять отчёты о сбоях для улучшения Aperant. Персональные данные и код не собираются." + }, + "openLogsFolder": "Открыть папку логов", + "copyDebugInfo": "Скопировать отладочную информацию", + "copied": "Скопировано!", + "loadInfo": "Загрузить отладочную информацию", + "systemInfo": "Информация о системе", + "logsLocation": "Расположение логов", + "recentErrors": "Последние ошибки", + "noRecentErrors": "Последних ошибок нет", + "helpTitle": "Сообщение о проблемах", + "helpText": "При сообщении об ошибках нажмите «Скопировать отладочную информацию» для получения сведений о системе и последних ошибках, которые помогут нам диагностировать проблему." + }, + "projectSettings": { + "noProjectSelected": { + "title": "Проект не выбран", + "description": "Выберите проект в боковой панели для настройки его параметров." + } + }, + "mcp": { + "title": "Обзор MCP-серверов", + "titleWithProject": "Обзор MCP-серверов для {{projectName}}", + "description": "Настройте, какие MCP-серверы доступны агентам в этом проекте", + "descriptionNoProject": "Выберите проект для настройки MCP-серверов", + "serversEnabled": "Включено серверов: {{count}}", + "configuration": "Конфигурация MCP-серверов", + "configurationHint": "Отключённые серверы снижают использование контекста и время запуска", + "noProjectSelected": "Проект не выбран", + "noProjectSelectedDescription": "Выберите проект из выпадающего списка для просмотра и настройки MCP-серверов.", + "projectNotInitialized": "Проект не инициализирован", + "projectNotInitializedDescription": "Инициализируйте Aperant для этого проекта, чтобы настроить 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 Memory", + "description": "Граф знаний для межсессионного контекста", + "notConfigured": "Требуется настройка памяти (см. настройки Памяти)" + }, + "linear": { + "name": "Linear", + "description": "Интеграция с системой управления проектами", + "notConfigured": "Требуется интеграция с Linear (см. настройки Linear)" + }, + "electron": { + "name": "Electron", + "description": "Автоматизация десктопного приложения через Chrome DevTools" + }, + "puppeteer": { + "name": "Puppeteer", + "description": "Автоматизация веб-браузера для тестирования" + }, + "autoClaude": { + "name": "Инструменты Aperant", + "description": "Отслеживание прогресса сборки" + } + }, + "customServers": "Пользовательские серверы", + "addCustomServer": "Добавить пользовательский сервер", + "editCustomServer": "Редактировать пользовательский сервер", + "customServerDescription": "Добавьте MCP-сервер на основе команды или HTTP", + "serverType": "Тип сервера", + "typeCommand": "Команда (npx/npm)", + "typeHttp": "HTTP", + "serverName": "Название", + "serverNamePlaceholder": "Мой MCP-сервер", + "serverDescription": "Описание", + "serverDescriptionPlaceholder": "Что делает этот сервер", + "command": "Команда", + "args": "Аргументы", + "argsHint": "Аргументы, разделённые пробелами", + "url": "URL", + "headers": "Заголовки", + "headerName": "Название заголовка", + "headerValue": "Значение заголовка", + "noCustomServers": "Пользовательские серверы не настроены. Добавьте один для использования с агентами.", + "errorNameRequired": "Название сервера обязательно", + "errorIdExists": "Сервер с таким ID уже существует", + "errorCommandRequired": "Команда обязательна для серверов на основе команды", + "errorUrlRequired": "URL обязателен для HTTP-серверов", + "testConnection": "Проверить", + "testing": "Проверка...", + "authToken": "Токен аутентификации", + "authTokenPlaceholder": "Вставьте ваш API-токен или PAT сюда", + "authTokenHint": "Используется как Bearer-токен в заголовке Authorization", + "advancedHeaders": "Дополнительные заголовки", + "status": { + "healthy": "Сервер отвечает", + "unhealthy": "Сервер не отвечает", + "needsAuth": "Требуется аутентификация", + "checking": "Проверка...", + "unknown": "Статус неизвестен" + }, + "hints": { + "github": "Похоже на GitHub MCP-сервер. Вам потребуется Personal Access Token с соответствующими правами.", + "createGithubPat": "Создать GitHub PAT", + "google": "Похоже на Google API. Вам потребуется OAuth-токен или API-ключ.", + "createGoogleToken": "Создать учётные данные Google", + "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 Terminal", + "ubuntu": "Ubuntu Mono 13px, блочный курсор", + "ubuntuName": "Ubuntu Terminal", + "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 на основе изменений кода" + } + }, + "provider": { + "title": "AI-провайдер", + "description": "Настройте предпочтения AI-провайдера и модели", + "selection": { + "label": "Провайдер", + "description": "Выберите AI-провайдера для задач агента", + "anthropic": "Anthropic", + "openai": "OpenAI", + "ollama": "Ollama (локальный)", + "openrouter": "OpenRouter" + }, + "apiKey": { + "label": "API-ключ", + "description": "Ваш API-ключ для выбранного провайдера", + "placeholder": "Введите ваш API-ключ", + "anthropicPlaceholder": "sk-ant-...", + "openaiPlaceholder": "sk-...", + "openrouterPlaceholder": "sk-or-...", + "validation": { + "required": "API-ключ обязателен для этого провайдера", + "invalid": "Неверный формат API-ключа" + } + }, + "ollama": { + "endpointUrl": "URL эндпоинта Ollama", + "endpointDescription": "URL, по которому запущен ваш экземпляр Ollama", + "endpointPlaceholder": "http://localhost:11434", + "validation": { + "urlRequired": "URL эндпоинта обязателен для Ollama", + "urlInvalid": "Неверный формат URL (должен начинаться с http:// или https://)" + } + }, + "phaseModels": { + "title": "Настройки модели для каждой фазы", + "description": "Настройте, какую модель использовать для каждой фазы конвейера", + "spec": { + "label": "Модель создания спецификации", + "description": "Модель для исследования, требований и сбора контекста" + }, + "planning": { + "label": "Модель планирования", + "description": "Модель для планирования реализации и архитектуры" + }, + "coding": { + "label": "Модель разработки", + "description": "Модель для реализации кода" + }, + "qa": { + "label": "Модель QA-проверки", + "description": "Модель для обеспечения качества и валидации" + }, + "placeholder": "Выберите модель", + "useDefault": "Использовать модель по умолчанию" + }, + "testConnection": { + "label": "Проверить подключение", + "testing": "Проверка...", + "success": "Подключение успешно", + "failure": "Подключение не удалось" + }, + "toast": { + "saved": { + "title": "Настройки провайдера сохранены", + "description": "Конфигурация вашего AI-провайдера обновлена." + }, + "error": { + "title": "Не удалось сохранить настройки провайдера", + "description": "При сохранении конфигурации провайдера произошла ошибка." + } + } + } +} diff --git a/apps/desktop/src/shared/i18n/locales/ru/taskReview.json b/apps/desktop/src/shared/i18n/locales/ru/taskReview.json new file mode 100644 index 0000000000..a0741e9ff4 --- /dev/null +++ b/apps/desktop/src/shared/i18n/locales/ru/taskReview.json @@ -0,0 +1,162 @@ +{ + "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": "{{count}} файл требует AI-слияния из-за {{renameCount}} переименования файла.", + "filesNeedAIMergeDueToRenames_other": "{{count}} файла требуют AI-слияния из-за {{renameCount}} переименований файлов.", + "filesNeedAIMergeDueToRenamesPlural": "{{count}} файл требует AI-слияния из-за {{renameCount}} переименований файлов.", + "filesNeedAIMergeDueToRenamesPlural_other": "{{count}} файла требуют AI-слияния из-за {{renameCount}} переименований файлов.", + "fileRenamesDetected": "{{count}} переименование файла обнаружено — AI выполнит слияние.", + "fileRenamesDetected_other": "{{count}} переименования файлов обнаружено — AI выполнит слияние.", + "filesRenamedOrMoved": "Файлы могли быть переименованы или перемещены — AI выполнит слияние.", + "alreadyMergedTitle": "Изменения уже в вашей ветке", + "alreadyMergedDescription": "Похоже, эти изменения уже существуют в вашей текущей ветке. Вы можете безопасно отметить эту задачу как выполненную.", + "alreadyMergedTooltip": "Изменения задачи уже присутствуют в вашей ветке. Пометка как выполнено очистит воркдерево без слияния.", + "matchingFiles": "Совпадающие файлы", + "supersededTitle": "Изменения устарели", + "supersededDescription": "Ваша текущая ветка содержит более новую версию этих изменений. Рассмотрите возможность отклонения этой задачи или просмотра сравнения.", + "supersededCompareTooltip": "Просмотрите подробное сравнение, чтобы увидеть, чем текущая ветка отличается от изменений этой задачи.", + "supersededDiscardTooltip": "Удалите воркдерево этой задачи, поскольку изменения больше не нужны.", + "status": { + "branchDiverged": "Ветки разошлись", + "aiWillResolve": "AI разрешит конфликт", + "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": "Создать Pull Request", + "description": "Отправить ветку и создать pull request для «{{taskTitle}}»", + "errors": { + "unknown": "Произошла неизвестная ошибка при создании pull request", + "invalidBranchName": "Имя ветки содержит недопустимые символы. Используйте только буквы, цифры, дефисы (-), подчёркивания (_) и косую черту (/).", + "emptyTitle": "Заголовок pull request не может быть пустым." + }, + "success": { + "created": "Pull request успешно создан!", + "alreadyExists": "Pull request для этой ветки уже существует" + }, + "actions": { + "retry": "Повторить", + "creating": "Создание PR...", + "create": "Создать Pull Request" + }, + "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": "Во время процесса слияния произошла ошибка." + }, + "stagedSuccess": { + "title": "Изменения успешно подготовлены", + "aiCommitMessage": "Сообщение коммита, сгенерированное AI", + "copied": "Скопировано!", + "copy": "Скопировать", + "editHint": "Отредактируйте по необходимости, затем скопируйте и используйте с", + "nextSteps": "Следующие шаги:", + "reviewChanges": "Проверьте подготовленные изменения с помощью", + "commitWhenReady": "Зафиксируйте, когда будете готовы:", + "pushToRemote": "Отправьте на удалённый сервер, когда удовлетворены результатом", + "cleaningUp": "Очистка...", + "markingDone": "Отметка как выполнено...", + "resetting": "Сброс...", + "deleteWorktreeAndMarkDone": "Удалить воркдерево и отметить как выполнено", + "markDoneOnly": "Только отметить как выполнено", + "markAsDone": "Отметить как выполнено", + "reviewAgain": "Проверить снова", + "commitMessagePlaceholder": "Сообщение коммита...", + "worktreeExplanation": "«Удалить воркдерево и отметить как выполнено» очищает изолированное рабочее пространство. «Только отметить как выполнено» оставляет его для справки.", + "errors": { + "failedToDeleteWorktree": "Не удалось удалить воркдерево", + "worktreeDeletedButStatusFailed": "Воркдерево удалено, но не удалось обновить статус задачи: {{error}}", + "failedToMarkAsDone": "Не удалось отметить как выполнено", + "failedToResetStagedState": "Не удалось сбросить состояние подготовки" + } + }, + "bulkPR": { + "title": "Создать Pull Request-ы", + "description": "Создать pull request-ы для {{count}} выбранных задач", + "creating": "Создание PR {{current}} из {{total}}...", + "creatingPR": "Создание PR {{current}} из {{total}}", + "resultsDescription": "{{success}} успешно, {{failed}} с ошибками", + "tasksToProcess": "Задачи для обработки", + "targetBranchHint": "Оставьте пустым для использования ветки по умолчанию каждой задачи. Будет применено ко всем PR.", + "createAll": "Создать {{count}} PR", + "completed": "завершено", + "succeeded": "успешно", + "failed": "с ошибкой", + "skipped": "пропущено", + "alreadyExisted": "уже существовало", + "noWorktree": "Воркдерево для этой задачи не найдено", + "resultsDescriptionWithSkipped": "{{success}} успешно, {{skipped}} пропущено, {{failed}} с ошибками" + } +} diff --git a/apps/desktop/src/shared/i18n/locales/ru/tasks.json b/apps/desktop/src/shared/i18n/locales/ru/tasks.json new file mode 100644 index 0000000000..9ffab06b77 --- /dev/null +++ b/apps/desktop/src/shared/i18n/locales/ru/tasks.json @@ -0,0 +1,357 @@ +{ + "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": "Проблемы QA", + "approvePlan": "Одобрить план", + "stopped": "Остановлено" + }, + "tooltips": { + "archiveTask": "Архивировать задачу", + "archiveAllDone": "Архивировать все выполненные задачи", + "viewPR": "Открыть pull request в браузере" + }, + "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": "QA" + } + }, + "files": { + "title": "Файлы", + "tab": "Файлы", + "noSpecPath": "Файлы спецификации недоступны", + "noFiles": "Файлы не найдены", + "loading": "Загрузка файлов...", + "loadingContent": "Загрузка содержимого...", + "errorLoading": "Не удалось загрузить файлы", + "errorLoadingContent": "Не удалось загрузить содержимое файла", + "retry": "Повторить", + "selectFile": "Выберите файл для просмотра его содержимого", + "openInIDE": "Открыть в IDE" + }, + "metadata": { + "fastMode": "Быстрый", + "severity": "серьёзность", + "pullRequest": "Pull Request", + "showMore": "Показать больше", + "showLess": "Показать меньше" + }, + "images": { + "removeImageAriaLabel": "Удалить изображение {{filename}}", + "pasteHint": "Совет: вставляйте скриншоты напрямую с помощью {{shortcut}} для добавления референсных изображений." + }, + "imagePreview": { + "close": "Закрыть предпросмотр", + "unavailable": "Изображение недоступно", + "description": "Предпросмотр {{filename}}", + "doubleClickHint": "Двойной клик для увеличения", + "lowResolution": "Предпросмотр низкого разрешения" + }, + "notifications": { + "backgroundTaskTitle": "Задача продолжается в фоне", + "backgroundTaskDescription": "Задача всё ещё выполняется. Вы можете повторно открыть этот диалог для отслеживания прогресса." + }, + "wizard": { + "createTitle": "Создать новую задачу", + "createDescription": "Опишите, что вы хотите создать. AI проанализирует ваш запрос и создаст подробную спецификацию.", + "descriptionPlaceholder": "Опишите функцию, исправление бага или улучшение, которое вы хотите реализовать. Будьте максимально конкретны относительно требований, ограничений и ожидаемого поведения. Введите @ для ссылки на файлы.", + "draftRestored": "Черновик восстановлен", + "startFresh": "Начать заново", + "hideFiles": "Скрыть файлы", + "browseFiles": "Обзор файлов", + "creating": "Создание...", + "createTask": "Создать задачу", + "worktreeNotice": { + "title": "Изолированное рабочее пространство", + "description": "Эта задача выполняется в изолированном git-воркдереве. Ваша основная ветка остаётся в безопасности до тех пор, пока вы не решите выполнить слияние." + }, + "gitOptions": { + "title": "Git-опции (необязательно)", + "baseBranchLabel": "Базовая ветка (необязательно)", + "useProjectDefault": "Использовать проектную по умолчанию", + "useProjectDefaultWithBranch": "Использовать проектную по умолчанию ({{branch}})", + "searchBranches": "Поиск веток...", + "noBranchesFound": "Ветки не найдены", + "helpText": "Переопределите ветку, из которой будет создано воркдерево этой задачи. Оставьте пустым для использования настроенной ветки по умолчанию проекта.", + "pushNewBranchesLabel": "Автоматически отправлять новую ветку", + "pushNewBranchesDescription": "Опубликовать ветку этой задачи на GitHub и автоматически настроить отслеживание. Отключите, чтобы оставить только локально.", + "useWorktreeLabel": "Использовать изолированное рабочее пространство (рекомендуется)", + "useWorktreeDescription": "Создаёт изменения в отдельном git-воркдереве для безопасной проверки перед слиянием. Отключите для разработки напрямую в вашем проекте (быстрее, но рискованнее)." + }, + "errors": { + "createFailed": "Не удалось создать задачу. Пожалуйста, попробуйте снова.", + "startFailed": "Не удалось запустить задачу" + } + }, + "feedback": { + "dragDropHint": "Перетащите изображения или вставьте скриншоты", + "imageAdded": "Изображение успешно добавлено", + "maxImagesError": "Максимально допустимо {{count}} изображений", + "invalidTypeError": "Недопустимый тип изображения. Допустимые: {{types}}", + "removeImage": "Удалить изображение", + "processingError": "Не удалось обработать изображение" + }, + "review": { + "mergeTooltip": "Сливает изменения из ветки воркдерева задачи обратно в базовую ветку. AI разрешит возможные конфликты. Затем вы можете выбрать, сохранить или удалить воркдерево." + }, + "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": "Безымянная подзадача", + "expandAll": "Развернуть все", + "collapseAll": "Свернуть все" + }, + "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": "Добавьте визуальные референсы, такие как скриншоты или дизайны, чтобы помочь AI понять ваши требования." + } +} diff --git a/apps/desktop/src/shared/i18n/locales/ru/terminal.json b/apps/desktop/src/shared/i18n/locales/ru/terminal.json new file mode 100644 index 0000000000..f2cfa25e2b --- /dev/null +++ b/apps/desktop/src/shared/i18n/locales/ru/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": "Воркtree", + "createNew": "Новый воркtree", + "existing": "Воркtree-ветки терминала", + "taskWorktrees": "Воркtree-ветки задач", + "otherWorktrees": "Прочие", + "createTitle": "Создать воркtree терминала", + "createDescription": "Создайте изолированное рабочее пространство для этого терминала. Вся работа будет выполняться в директории воркtree.", + "name": "Название воркtree", + "namePlaceholder": "my-feature", + "nameRequired": "Название воркtree обязательно", + "nameInvalid": "Название должно начинаться и заканчиваться буквой или цифрой", + "nameHelp": "Строчные буквы, цифры, дефисы и подчёркивания (пробелы заменяются дефисами)", + "associateTask": "Привязать к задаче", + "selectTask": "Выберите задачу...", + "noTask": "Без задачи (отдельный воркtree)", + "createBranch": "Создать ветку Git", + "branchHelp": "Будет создана ветка: {{branch}}", + "baseBranch": "Базовая ветка", + "selectBaseBranch": "Выберите базовую ветку...", + "searchBranch": "Поиск веток...", + "noBranchFound": "Ветки не найдены", + "useProjectDefault": "Использовать по умолчанию ({{branch}})", + "baseBranchHelp": "Ветка, из которой будет создан воркtree", + "openInIDE": "Открыть в IDE", + "maxReached": "Достигнут максимум из 12 воркtree-веток терминала", + "alreadyExists": "Воркtree с таким именем уже существует", + "searchPlaceholder": "Поиск воркtree...", + "noResults": "Воркtree не найдены", + "deleteTitle": "Удалить воркtree?", + "deleteDescription": "Это безвозвратно удалит воркtree и его ветку. Все незафиксированные изменения будут потеряны.", + "detached": "(отсоединён)", + "remotePushFailed": "Отслеживание удалённой ветки не настроено", + "remotePushFailedDescription": "Воркtree создан, но ветку не удалось отправить на удалённый сервер. Возможно, потребуется вручную выполнить git push -u." + } +} diff --git a/apps/desktop/src/shared/i18n/locales/ru/welcome.json b/apps/desktop/src/shared/i18n/locales/ru/welcome.json new file mode 100644 index 0000000000..d5e5008669 --- /dev/null +++ b/apps/desktop/src/shared/i18n/locales/ru/welcome.json @@ -0,0 +1,17 @@ +{ + "hero": { + "title": "Добро пожаловать в Aperant", + "subtitle": "Создавайте программное обеспечение автономно с помощью AI-агентов" + }, + "actions": { + "newProject": "Новый проект", + "openProject": "Открыть проект" + }, + "recentProjects": { + "title": "Последние проекты", + "empty": "Проектов пока нет", + "emptyDescription": "Создайте новый проект или откройте существующий, чтобы начать", + "openFolder": "Открыть папку", + "openProjectAriaLabel": "Открыть проект {{name}}" + } +}