* feat(app): workspace labels baseline Existing labels implementation, committed as-is as the baseline for the UI redesign. Server, protocol, catalog store and sync are sound; the UI layer is reworked in the commits that follow. Co-authored-by: Christoph Leiter <christoph@leiter.io> * feat(app): show workspace labels on the sidebar meta line Labels could be assigned and then appeared nowhere. They now draw as a chip on the workspace meta row, after the host, change request, checks and service, and they can be switched off from the Show submenu like any other item on that line. One palette, not two. `baseColors.workspaceLabel` was ten raw Tailwind 500s spanning a 1.9:1 to 4.5:1 contrast range — the exact set identity-colors.ts was written to replace. Label color is now the identity color of the same name, so a chip, a host badge and a CI check on one row sit in one contrast band. `workspace-labels/colors.ts` and its per-file `labelColorViolet` blocks are gone; `chip.tsx` and `swatch.tsx` are the only places a label color becomes ink. A row resolves its labels against its own host's catalog and nothing else. The cross-host projection answers too, but two hosts may give one name two colors and the merge settles that by target precedence and then alphabetical serverId — a row painted in a color its host never assigned is lying about the one thing the color is for. The meta row's doc comment argued against tinted chrome on that line. The chip is a deliberate exception — everything else there reports state and shares the state colors, a label is a name a person chose — so the comment now says that instead of contradicting the code. Alignment: - The chip is exactly as tall as the line: text at the row's 16pt lineHeight, no vertical padding, so a labelled row is the same height as an unlabelled one. - A label run that opens the line hangs left by the chip's own padding, landing the name on the rail the title above it uses. Mid-line the ground stays in the flow. - The swatch row reaches 44pt through hitSlop growing outward from a 20pt swatch, replacing ten 44pt colored blobs in the manager modal. - The picker's raw `<Plus>`, `<CheckSquare>` and `<Square>` go through withUnistyles with module-level mappings, at the menu's 14pt. Also fixes a bug this change exposed: `SidebarRowItemsSchema` is a strict object, so adding an item without a key there fails the whole settings write and silently loses every other Show toggle with it. A test now covers each item in SIDEBAR_ROW_ITEMS. Phase 1 of the workspace labels redesign. The filter menu, the picker's interaction model and the manager modal's layout are later phases. Co-authored-by: Christoph Leiter <christoph@leiter.io> * feat(app): one Labels filter page with tri-state rows Filtering by label cost three levels: Display -> Labels -> Include -> a page of labels, or -> Exclude -> the same page again. It is now one page: every label across every host, one row each, leading with its colour dot. A row cycles off -> include -> exclude -> off. Include is MenuItem's own check; exclude is lucide's X, the check's own pair, at the same 16 in the same trailing slot, so the column does not shift as a row cycles. Exclude also dims the row, because a state you have to identify by its glyph is not one you read at a glance. Unlabelled is a row in the same list, with a hollow ring where the others carry their colour. Match any / all still appears only once two labels are included. Clear is absent, not disabled, when nothing is filtered. Manage labels sits at the bottom below a separator. The whole root row is gone when no host has a label — unless a filter is still active, since the merged catalog only counts online hosts and losing one would otherwise strand a filter that is still hiding workspaces. The page is titled Labels, so its rows stop repeating the word: "Match any", "Match all", "Clear filter". The two Match rows sit directly under the list they qualify and only appear once two labels are included, so the subject is already on screen. All nine locales move together, translated rather than transliterated — Arabic keeps its noun, where "أي" is a determiner that needs one to stay grammatical. SidebarLabelFilter collapses from four collections plus match to one Record<labelKey, "include" | "exclude"> plus match: a tri-state row is one value per label, so include and exclude can no longer disagree about the same name. Unlabelled keys off the empty string, which normalizeWorkspaceLabelName makes unreachable for a real label. toggleSidebarLabelSelection, countSidebarLabelSelections, sidebarLabelSelectionIncludes and deduplicateSidebarLabelNames go with the old shape; setLabelFilter becomes cycleLabelFilter and setLabelMatch, so the store owns its own transitions. No migration: labels are unreleased, so the old persisted shape never shipped, and migrateSidebarViewState already resets on a safeParse failure. The e2e manager step asserted "Red label color" on a swatch that Phase 1 renamed to "Red"; the selector follows the code, and the accessibility.color key behind the old string is deleted from all nine locales as unreferenced. Co-authored-by: Christoph Leiter <christoph@leiter.io> * feat(app): assign labels on the menu's own rails The assign picker was a search box, a create row that unfolded an inline form under it, and hand-rolled label rows whose 44x44 checkbox pushed every dot and name off the rail the rows above them sat on. Nothing lined up with anything. Rows are `MenuItem` now: the colour dot in the 16pt leading slot, assignment as the trailing check the engine already draws for a chosen row. Using the engine's row is the alignment fix; there is no second row implementation to keep in step. Every press toggles and the menu stays open — assigning labels is multi-select, so the dual-target model (`source: "row" | "checkbox"`, `shouldCloseWorkspaceLabelPicker`) is gone along with the model's `close` dependency. You leave by dismissing the menu. Search is deleted. Nobody has enough labels to search, and the field was the thing pushing the list down the surface. `workspaceLabels.search` and `createNamed` go with it across all nine locales; `clearSearch` stays because the manager modal still owns a search field (Phase 4's copy, untouched here). `Create label` moves below a separator at the bottom and opens a page that replaces the list: a name field, the swatch row, one commit row. Picking a colour picks a colour — it no longer creates the label. A failed create keeps the draft and shows the error on the page; a successful one creates, assigns, and returns to the list with the row ticked. Both menus share one page definition. `SidebarWorkspaceMenu` and `SidebarWorkspaceContextMenu` each built the same `pages` memo; they now call `useWorkspaceLabelMenuPages`. Menu engine, all of it forced by putting a text input on a menu page: - `MenuTextField` — the form kit's `FormTextInput` carries a screen's geometry and lands its text 4pt inside the labels above it. This one is drawn as a row's own fill, so the box and the text sit on the row's two rails at once. - `MenuPageDefinition.hoverIntent` — a page you type into is not one the pointer opens or dismisses. Without it the create flyout opened on a pointer passing over the row, and threw the draft away when the mouse drifted off it while the hands were on the keyboard. - The sheet keeps `keyboardBehavior="interactive"`, not `extend`. With `enableDynamicSizing` the largest snap point is the content's own height, so a short page did not grow and the keyboard came up over the field. Caught on an iOS simulator, fixed, and re-shot. - `MenuItem` announces `selected` as `aria-checked`. The deleted checkbox said so; a check drawn and never announced would have been an accessibility regression. Tri-state rows (the filter page's exclude) still cannot announce themselves — menu-wide, still Phase 5's. `sidebar-workspace-row.tsx`'s `isTouchPlatform = platformIsNative || isCompact` is kept deliberately. On a compact web viewport there is no hover, so the row's trailing actions and kebab were unreachable and the labels menu with them; this is the documented `isHovered || isNative || isCompact` shape from CLAUDE.md. Evidence: /tmp/labels-p3-{wide,compact}-{light,dark}-{list,create}.png, the create page on iOS with the keyboard up (/tmp/labels-p3-native-compact-keyboard.png) and the clipped sheet it replaced (-before.png). `packages/app/e2e/browser/workspace-labels.spec.ts` rewritten for the new model, daemon-backed failure coverage kept for both the toggle and the create path, green with the menu unit suites. Co-authored-by: Christoph Leiter <christoph@leiter.io> * feat(app): edit a label in one operation `workspace.label.rename.request` and `workspace.label.recolor.request` become one `workspace.label.update.request { name, newName?, color? }`. Both old RPCs are deleted outright — no COMPAT shim, because the labels feature is unreleased and neither name has ever been on a wire a user owns. The `workspaceLabels` capability flag stays; that one is how a new app detects an old daemon. Two calls could land half-applied, which left the catalog in a state nobody asked for and the UI with nothing true to say. One catalog commit now applies the name, the colour, or both. Renaming onto a name the host already has is rejected rather than merged, and the check runs inside the planner so a refused collision applies neither field. A label keeping its own key is not colliding with itself, so case-only edits pass. The manager modal follows: - The host selector is `HostFilter`, the pill History and Schedules use. `includeAllHost` is now a prop: a surface that edits one host's catalog cannot carry out "all". - Search moves to the sheet header, where it spans the header's own rails. As a body control it capped at the component's 420pt and left a hole on the right whenever a host filter wasn't beside it. `workspaceLabels.clearSearch` goes with the box that had a clear button. - A row no longer opens an editor. It carries a pencil in its trailing slot, hover-revealed on web and always visible on native and compact, on the canonical plain-View hover pattern with the press on an inner Pressable. - The edit view is a name field, the swatch row, and one Save that issues one update. Delete keeps its confirm and its affected-workspace count, and moves to `outline` — red belongs to the dialog, not to the surface that opens it. - Copy says edit, never rename or recolor, in all nine locales. `workspaceLabelErrorMessage` drops the `requestType=… code=…` the daemon client appends to every RPC failure. That is what a log wants, not what a user reads under a name field. `workspaceLabels.accessibility.color` stays deleted: the swatch's accessible name is already the colour's name, so nothing needed it back. Co-authored-by: Christoph Leiter <christoph@leiter.io> * chore(app): converge the labels phases The sweep at the end of the labels redesign: the three items earlier phases found and kept out of their own commits, one cross-phase pass, and the docs. `AdaptiveModalSheet`'s close button reaches its target with `hitSlop` instead of `padding`, which had inset its glyph 8pt from the rail the title, the search field and every trailing glyph below it sit on. This is shared chrome, so it moves the close glyph in every sheet in the app; measured on four of them across both paths — the labels manager desktop and compact, the shortcuts dialog, the rename sheet — and each one's trailing rail now agrees with its leading one. `MenuItem` takes `selected: boolean | "mixed"`. A tri-state row was silent to a screen reader: the check announced itself after the last phase, but exclude had no state at all, so an excluded label was indistinguishable from an untouched one. `"mixed"` is ARIA's own third state, the engine still draws the check only for `true`, and the row keeps supplying its own trailing mark — nothing in the menu engine learns what a label is. CLAUDE.md's platform-gating rules said "NEVER use `onPointerEnter`/ `onPointerLeave`", which is the opposite of what `docs/hover.md` and `constants/platform.ts` both mandate. It now names the real rule — hover on a plain `View`, press on a separate inner `Pressable`, and no `onHoverIn`/ `onHoverOut` on a `Pressable` that contains other pressables — and links the doc that owns it rather than restating it. The cross-phase pass turned up one real defect: the replica cache never learned about labels. `StoredWorkspaceSchema` had no `labels`, so a restored workspace came back unlabelled, and since the directory cursor is current on reconnect the daemon has nothing newer to send — the chips stayed gone for the whole session and the filter matched nothing. An optional field, a serializer line, and an assertion in the restore spec. Everything else measured onto its rails already. Left alone and logged: the per-row `Map` in `useWorkspaceLabelDefinitions`, and the display menu closing when the sidebar swaps to its empty state, which is confined to that swap and predates every phase here. `docs/architecture.md` and `docs/data-model.md` described rename and recolor; they now describe the one update commit, which fields it rewrites, and the per-host resolution a row's chips use. `docs/menus.md` documents the third item state where it already documents the other two. Co-authored-by: Christoph Leiter <christoph@leiter.io> * feat(app): split the labels filter into include and exclude controls The Labels page rotated one row through off -> include -> exclude -> off, which billed the rare operation to the common one: clearing an include cost two presses and routed through exclude, so the sidebar visibly re-filtered into a state nobody asked for on the way out. The row now owns include and a control on its trailing rail owns exclude. Each is one press each way and neither is reached through the other. `cycleLabelFilter` becomes `toggleLabelInclude` and `toggleLabelExclude`; the store's map shape is unchanged, and setting either state clears the other for that label, so including an excluded row is still one press. A row is never both, so the trailing rail holds exactly one 16pt glyph in every state: the check, a permanent `X`, or the same `X` revealed on hover. `X` rather than a circle-slash for the reason Phase 2 settled it — `Ban` fills its box where the check does not, and the column twitches. The control fades rather than mounts and takes its 44pt target from `hitSlop`, so neither revealing it nor changing state moves anything: measured 453-469 on every row, wide and compact. The control carries a tooltip, gated to web where hover exists. It portals into the overlay root above the flyout with no backdrop of its own, and resting on it does not read as the pointer leaving the surface, so the menu stays up. Accessibility: the control is a `checkbox` named "Exclude {label}" with its own checked state, and it stays in the tree at opacity 0 on rows that have no visible mark, so it is reachable without hover. Keyboard focus reveals it, so tabbing to it never means pressing something invisible. The row keeps Phase 5's `selected="mixed"` for exclude. Co-authored-by: Christoph Leiter <christoph@leiter.io> * feat(app): put include and exclude on their own rails on every label row Phase 6 gave the row include and its trailing rail a hover-revealed exclude. The rotation was gone but the awkwardness was not: `X` is the glyph this app dismisses things with, so on a filter row it reads as delete rather than exclude, and one rail with a changing occupant still means the row's trailing area keeps changing identity as you read down the column. Both controls are now on every row in fixed positions, and state is which one is lit. Nothing appears, disappears, swaps places or shifts: the check box is 429-445 and the ban box 453-469 on an included row, an excluded row and an untouched one alike, wide and compact. Because the ban is always there, include -> exclude is one press instead of two. The row still includes, and the check is that same action named. `Ban` rather than `X`. Phase 2 rejected it because its ink fills its 16pt box where a check's does not, so the column twitched when the two swapped on one rail. Nothing swaps here, so what is left is a weight difference: the ban is drawn at 14 inside a 16pt box, which is the visible optical correction available before it stops being a glyph. The box is what the rail is measured from and it stays 16. Lit is `foreground`, unlit `foregroundExtraMuted`. Not `foregroundMuted`, which is the obvious choice and is wrong here specifically: the Match rows further down the same page carry `MenuItem`'s own check in that colour to mean *selected*, so an unlit check in the same ink would say the opposite thing eight pixels above it. Excluded keeps Phase 2's dimmed row. Accessibility: the row keeps `selected` — `true` include, `"mixed"` exclude — and the two buttons carry no checked state of their own, so a label's state is announced once and its two controls read as the actions they are. Both buttons take a tooltip, gated to web with `enabledOnDesktop={isWeb}`, because on non-compact native `TooltipContent` falls back to a `Modal` with its own backdrop. Deleted with it: the `isHovered || isFocused || isNative || isCompact` reveal, the `opacity: 0` mounting, the hover-tracking `View` and the focus plumbing that existed to keep an invisible control reachable. Net -7 lines of code on this row, all of the growth in comments. The store is unchanged; both buttons and the row press map onto `toggleLabelInclude` / `toggleLabelExclude` as they are. The e2e's hover-reveal and `toHaveCount(0)` steps encoded the deleted behaviour and are replaced by a rail measurement taken in every state — relative to the row, since filtering moves the anchor the menu hangs off, and behind a settle poll, since the flyout scales in and a box read mid-animation is not a rail. Co-authored-by: Christoph Leiter <christoph@leiter.io> * feat(app): reveal the label filter's controls, and stop the empty state closing the menu Phase 7 put the check and the ban on every label row at all times, which made a resting list of labels read as two columns of buttons with a filter somewhere behind them. A row now shows its own state and nothing else — a marked row its mark, an untouched row nothing — and hovering any row brings both controls up, the mark you have lit and the other one unlit beside it. So the column you read down is the filter, and the row you are pointing at is the one offering to change it. Nothing about the rails changed. The two boxes are laid out in every state and only their ink comes and goes: check 429-445, ban 453-469 on an included row, an excluded row, an untouched one, hovered or not, wide and compact. The reveal is opacity, never mounting, so it cannot move the row out from under the pointer that fired it. Hover is tracked on a plain `View` wrapping the `MenuItem` with the presses on the buttons inside it, since `MenuItem` is itself a `Pressable` (docs/hover.md); each control counts its own keyboard focus as revealed, so tabbing to one never means pressing something invisible; and `pointerEvents` follows visibility so a hidden control cannot be clicked. On native and compact there is no pointer, so both simply stand there. Everything Phase 7 settled is kept: `Ban` at 14 in a 16pt box, `foregroundExtraMuted` for unlit against `foregroundMuted` meaning *selected* eight pixels below, `spacing[2]` between the two with `hitSlop` tiling the gap, the row owning `aria-checked` while the buttons stay plain named actions, and both tooltips gated `enabledOnDesktop={isWeb}`. --- Excluding a label that empties the sidebar closed the display menu. Logged since Phase 2, narrowed in Phase 5 to the empty-state swap, owned by nobody. `SidebarLabelFilterEmptyState` was a component rendered *instead of* the list, with its own container and scroll view, and both branches were handed the same header element. Different subtrees, so React unmounted the header on the swap — and the header holds the display menu's trigger, so the popover went with its anchor. The empty state is now a body: both list modes render it where their groups would go, inside the scroll they already own and below the header they already render, and the swap can no longer reach anything above it. Cleared from that same still-open page, the way back out is the swap in reverse and it holds too. `ProjectModeList` was already the right shape — its "no projects yet" body sits below the header — but its header was conditional on `unpinnedProjects.length > 0 || hasActiveHostFilter`, which is the same bug written as a guard: keep the header when there is a filter to undo. The label filter joins that condition rather than getting a second mechanism. Both empty states move into `sidebar/empty-states.tsx` so the two list modes can render either without importing each other, which also leaves the card's geometry defined once instead of once per body. Still conditional, and left alone: a sidebar with no projects and no filter has no header at all, so clearing the last host filter on an empty sidebar closes the menu the same way. That one is the onboarding empty state, where a section heading over "Add a project" would be a heading over nothing, and no menu is reachable in the state it lands in. The e2e gets the step that would have caught this: exclude into the empty state, assert the page you pressed on is still up, clear from it, assert the same. Verified by reverting both list files to Phase 7 and watching it fail on "element(s) not found". Phase 7's rail assertions are kept as they are — offsets within the row, behind a settle poll — and joined by computed-opacity reads for the four states of the reveal. Evidence: /tmp/labels-qa-p8/, 28 shots plus INDEX.md — the resting list, a hovered row, an included row with the pointer away, and the empty state with the menu still open over it, at wide and compact in both schemes. Co-authored-by: Christoph Leiter <christoph@leiter.io> * feat(app): make the label filter include-only Phases 2, 6, 7 and 8 each tried to give exclusion a comfortable shape inside a 232pt menu row: tri-state rotation, a hover-revealed control, two permanent buttons, two hover-or-lit buttons. Every fix bought a new awkwardness, because two controls in one menu row is a lot of machinery for a filter. The label filter is now the host filter — one tap in, one tap out — and nobody has ever complained about that one. A row is a plain `MenuItem` with the colour dot leading and the engine's own check trailing. Nothing else. Which makes the alignment law trivial to satisfy, and that is the point. Deleted rather than disabled, since 6, 7 and 8 are in the branch history if exclusion ever comes back: both trailing controls, the hover-tracking `View`, the `opacity: 0` mounting, the focus/blur plumbing, the `pointerEvents` gating, both tooltips and their `enabledOnDesktop={isWeb}` gates, the lit/unlit token pair, `Ban`, and the two rails they held. `SidebarLabelFilter` collapses onto the shape of `hostFilters` sitting three fields above it in the same store: `labels: string[]` plus `match`, one `toggleLabelFilter`, one `clearLabelFilter`. The exclude arm of `filterWorkspacesByLabels` goes with it, and `filter.include` / `includeLabel` / `exclude` / `excludeLabel` leave all nine locales. Persisted version 4 with no migration — the record shape never shipped, and `createValidatedPersistStorage` drops state that fails the current schema before `migrate` ever runs. Two things this leaves unused, both deleted: - `MenuItem`'s `selected: boolean | "mixed"`, added in Phase 5 so a tri-state row could announce itself. The filter row was the only caller, so the union collapses back to `boolean` and the two `selected === true` guards that existed for `"mixed"` go back to plain truthiness. - The `docs/menus.md` paragraphs from Phases 7 and 8 on hover-revealing a pressable trailing control inside a menu row. No caller does that any more, so the doc was describing a pattern the codebase no longer has. Kept: `SIDEBAR_UNLABELLED_LABEL_KEY`, because `Unlabelled` is still a row and now includes like any other; `Match any` / `Match all`, because multi-select include still means two different things. Phase 8's empty-state fix is untouched and still holds — `hasActiveSidebarLabelFilter` is what the header's survival condition reads, and it answers the same question against the new shape. Evidence: /tmp/labels-qa-p9/, 12 shots plus INDEX.md — resting, two selected, and the empty state with the menu still open over it, at wide and compact in both schemes. Co-authored-by: Christoph Leiter <christoph@leiter.io> * fix(app): give label-grouped rows their project icons, and label groups a tag Grouping the sidebar by label rendered every workspace row with its placeholder initial. The same workspace under status or project grouping showed its real project icon. The components were reused; the data feeding them was not. One component served both grouping modes and threaded the icon map through correctly. Fourteen lines above it, a second `useProjectIcons` call was gated on `groupMode === "status"`, written when status was the only mode that put icons on rows. Phase 2 extended the render branch to `status || label` and left the gate alone. Nothing forces a render branch and the data it renders to agree, and these two were far enough apart to drift in silence. Reuse buys you one implementation of the drawing; it buys you nothing about who decides what to fetch. So the fix is the shape, not the line. There is now one `useProjectIcons` call for every mode, and its targets come from `buildSidebarProjection` — the same function that produced the rows, from the same `projects` list. A mode can only render a row for a project the projection already knows about, so the map cannot disagree with the screen. The gate is gone rather than extended: extending it would leave the identical trap for the next grouping mode. `useProjectIcons` dedupes by `serverId:projectId` and caches through `useQueries`, so the gate was a premature optimization that bought a bug. Pinned by `sidebar-projection.test.ts`: for each of the three modes, every project view key the projection will render — pinned rows, grouped rows, project headers and the rows under them — has an icon target. Red on the old gate: restoring `groupMode === "status" ? … : []` in its new home fails project and label grouping with `['project', 'other-project']` uncovered, and status passes, which is exactly the bug's signature. The sibling sweep over everything `SidebarStatusModeWrapper` is handed found one more of the same shape, correct today: the projection chose its shortcut sections with `status || label`, so a fourth mode would have silently walked the project rows. Both the groups and the sections now come from one exhaustive `switch` on the mode, which makes the next mode a compile error rather than an empty list. `workspaceEntriesByKey` is already written the safe way round (`!== "project"`), and the rest — host badges, pinning support, the empty-filter state — never read the mode at all. Two names moved with the shape: `SidebarStatusModeWrapper` is `SidebarGroupedModeList`, and its branch is `groupMode !== "project"`, so a new mode lands in the grouped list instead of the project list's `else`. Also: label group headers draw lucide `Tag` instead of `CircleDot`, in the label's colour, muted for `Unlabelled` — the glyph the Labels menu and the workspace menu already use for this feature. It keeps `StatusGroupIcon`'s 14 with no optical nudge, and that is measured rather than assumed: in the header's leading slot both ink a 14x14 box at the same offset, and the tag lays down 76 ink pixels to the circle's 84, so reaching the corners of its box costs it no weight beside the status glyphs. QA: /tmp/labels-qa-p10/ — wide and compact, light and dark, label grouping and the same workspaces under status grouping, plus the hover chevron swap, the glyph zooms, and a before/after pair taken with the fix reverted to the bug's shape. Co-authored-by: Christoph Leiter <christoph@leiter.io> * fix(app): align label chip typography Co-authored-by: Christoph Leiter <christoph@leiter.io> * docs: format architecture module table Co-authored-by: Christoph Leiter <christoph@leiter.io> * fix(app): narrow workspace labels workflow Co-authored-by: Christoph Leiter <christoph@leiter.io> * fix(app): mirror bottom sheet test exports Co-authored-by: Christoph Leiter <christoph@leiter.io> * test(desktop): assert project browse by destination Co-authored-by: Christoph Leiter <christoph@leiter.io> * fix(app): retain empty projects without label filters Co-authored-by: Christoph Leiter <christoph@leiter.io> * fix(app): preserve status grouping test contract Co-authored-by: Christoph Leiter <christoph@leiter.io> * fix(app): retain filters after label load failures Co-authored-by: Christoph Leiter <christoph@leiter.io> --------- Co-authored-by: Christoph Leiter <christoph@leiter.io>
2601 lines
131 KiB
TypeScript
2601 lines
131 KiB
TypeScript
import { en, type TranslationResources } from "./en";
|
||
import { pluginSettings } from "./plugin-settings";
|
||
|
||
export const ru: TranslationResources = {
|
||
common: {
|
||
back: "Назад",
|
||
loading: "Загрузка...",
|
||
actions: {
|
||
back: "Назад",
|
||
cancel: "Отмена",
|
||
close: "Закрывать",
|
||
copy: "Копировать",
|
||
dismiss: "Увольнять",
|
||
retry: "Повторить попытку",
|
||
search: "Поиск",
|
||
select: "Выбирать",
|
||
},
|
||
placeholders: {
|
||
search: "Поиск...",
|
||
},
|
||
empty: {
|
||
noResults: "Результаты не найдены",
|
||
noOptionsMatchSearch: "Нет вариантов, соответствующих вашему запросу.",
|
||
},
|
||
states: {
|
||
loading: "Загрузка...",
|
||
starting: "Начало...",
|
||
copied: "Скопировано",
|
||
copiedLabel: "Скопировано{{label}}",
|
||
downloadComplete: "Загрузка завершена",
|
||
downloadFailed: "Загрузка не удалась",
|
||
},
|
||
errors: {
|
||
error: "Ошибка",
|
||
unableToSave: "Не удалось сохранить",
|
||
nameRequired: "Требуется имя",
|
||
daemonUnavailable: "Daemon недоступен",
|
||
daemonClientUnavailable: "Клиент Daemon недоступен",
|
||
daemonClientDisconnected: "Клиент Daemon отключен",
|
||
noFileFound: "Файл для{{token}}не найден",
|
||
unexpectedDictationError: "При обработке диктовки произошла непредвиденная ошибка.",
|
||
},
|
||
connectionStatus: {
|
||
online: "Онлайн",
|
||
connecting: "Подключение",
|
||
offline: "Оффлайн",
|
||
error: "Ошибка",
|
||
idle: "Праздный",
|
||
},
|
||
},
|
||
shell: {
|
||
menu: {
|
||
toggleSidebar: "Переключить боковую панель",
|
||
open: "Открыть меню",
|
||
close: "Закрыть меню",
|
||
},
|
||
commandCenter: {
|
||
placeholder: "Поиск команд, файлов, рабочих пространств и агентов...",
|
||
filePlaceholder: "Поиск файлов...",
|
||
searchingFiles: "Поиск файлов...",
|
||
noMatches: "Нет совпадений",
|
||
actions: "Действия",
|
||
files: "Файлы",
|
||
workspaces: "Рабочие пространства",
|
||
agents: "Агенты",
|
||
newAgent: "Новый агент",
|
||
addProject: "Добавить проект",
|
||
home: "Дом",
|
||
groupByProject: "Группировать по проекту",
|
||
groupByStatus: "Группировать по статусу",
|
||
modelGroupLabel: "Модель",
|
||
modelSearchKeywords: "сменить модель изменить модель выбрать модель установить модель",
|
||
thinkingGroupLabel: "Мышление",
|
||
thinkingSearchKeywords: "рассуждение усилие мышление",
|
||
modeGroupLabel: "Режим",
|
||
modeSearchKeywords: "доступ разрешение одобрение режим",
|
||
planModeGroupLabel: "Режим плана",
|
||
planModeSearchKeywords: "план планирование режим плана",
|
||
fastModeGroupLabel: "Быстрый",
|
||
fastModeSearchKeywords: "быстрый скорость низкая задержка",
|
||
settingOn: "Вкл",
|
||
settingOff: "Выкл",
|
||
},
|
||
},
|
||
composer: {
|
||
placeholders: {
|
||
desktop: "Напишите агенту сообщение, отметьте @files или используйте /commands и /skills.",
|
||
mobile: "Сообщение,@files,/commands",
|
||
fallback: "Сообщение...",
|
||
terminal: "Prompt",
|
||
},
|
||
input: {
|
||
accessibilityLabel: "Агент сообщений...",
|
||
terminalAccessibilityLabel: "Terminal prompt",
|
||
focusHint: "{{shortcut}}, чтобы сосредоточиться",
|
||
addAttachment: "Добавить вложение",
|
||
interruptAgent: "Агент прерываний",
|
||
queueMessage: "Сообщение в очереди",
|
||
sendAndInterrupt: "Отправить и прервать",
|
||
sendAndSteer: "Отправить и направить",
|
||
sendMessage: "Отправить сообщение",
|
||
queue: "Очередь",
|
||
send: "Отправлять",
|
||
},
|
||
cancel: {
|
||
cancelingAgent: "Отменяющий агент",
|
||
stopAgent: "Остановить агент",
|
||
interrupt: "Прерывать",
|
||
},
|
||
voice: {
|
||
enableVoiceMode: "Включить голосовой режим",
|
||
voiceMode: "Голосовой режим",
|
||
unmuteVoiceMode: "Включить голосовой режим",
|
||
muteVoiceMode: "Отключить голосовой режим",
|
||
stopDictation: "Остановить диктовку",
|
||
startDictation: "Начать диктовку",
|
||
unmuteVoice: "Включить звук",
|
||
muteVoice: "Отключить голос",
|
||
dictation: "Диктант",
|
||
interruptBeforeVoice: "Прерывайте агента перед запуском голосового режима",
|
||
},
|
||
attachments: {
|
||
addImage: "Добавить изображение",
|
||
pasteImage: "Вставить изображение",
|
||
addFile: "Upload file",
|
||
addIssueOrPr: "Добавить проблему или PR",
|
||
addIssueOrPr_mr: "Добавить проблему или MR",
|
||
dropImagesHere: "Скиньте изображения сюда",
|
||
dropFilesHere: "Drop files here",
|
||
editQueuedMessage: "Изменить сообщение в очереди",
|
||
sendQueuedMessageNow: "Отправить сообщение в очереди сейчас",
|
||
openImage: "Открыть прикрепленное изображение",
|
||
removeImage: "Удалить прикрепленное изображение",
|
||
removeFile: "Remove file attachment",
|
||
openGithub: "Открыть {{kind}} {{number}}",
|
||
removeGithub: "Удалить {{kind}} {{number}}",
|
||
element: "Элемент",
|
||
openBrowserElement: "Открыть вложение элемента браузера",
|
||
removeBrowserElement: "Удалить вложение элемента браузера",
|
||
openReview: "Открыть прикрепленный файл с отзывом",
|
||
removeReview: "Удалить прикрепленный отзыв",
|
||
},
|
||
errors: {
|
||
failedToSend: "Не удалось отправить сообщение",
|
||
failedToCreateAgent: "Не удалось создать агента.",
|
||
noHostSelected: "Хост не выбран",
|
||
initialPromptRequired: "Требуется начальное приглашение",
|
||
alreadyLoading: "Уже загружается",
|
||
uploadFailed: "Failed to upload file",
|
||
noClipboardImage: "В буфере обмена нет изображения",
|
||
pasteImageFailed: "Не удалось вставить изображение",
|
||
fileTooLarge: "{{fileName}} is too large (max {{size}})",
|
||
},
|
||
clientCommands: {
|
||
archiveAgent: "Архивировать текущего агента",
|
||
freshDraft: "Архивируйте этот агент и начните новый черновик",
|
||
},
|
||
github: {
|
||
searching: "Идет поиск...",
|
||
noResults: "Результаты не найдены.",
|
||
searchPlaceholder: "Поиск проблем и пиар...",
|
||
searchPlaceholder_mr: "Поиск проблем и MR...",
|
||
title: "Прикрепите проблему или PR",
|
||
title_mr: "Прикрепите проблему или MR",
|
||
},
|
||
},
|
||
agentControls: {
|
||
provider: {
|
||
fallback: "Поставщик",
|
||
select: "Выберите поставщика агентов",
|
||
},
|
||
thinking: {
|
||
title: "мышление",
|
||
unknown: "Неизвестный",
|
||
extraHigh: "Очень высокий",
|
||
select: "Выберите вариант мышления",
|
||
selectWithValue: "Выберите вариант мышления ({{value}})",
|
||
},
|
||
model: {
|
||
unknown: "Неизвестная модель",
|
||
},
|
||
features: {
|
||
title: "Функции",
|
||
open: "Открытые возможности агента",
|
||
on: "На",
|
||
off: "Выключенный",
|
||
},
|
||
mode: {
|
||
title: "Режим",
|
||
searchPlaceholder: "Режимы поиска...",
|
||
selectWithValue: "Выберите режим агента ({{value}})",
|
||
},
|
||
hints: {
|
||
thinking: "Режим мышления",
|
||
model: "Изменить модель",
|
||
mode: "Изменить режим",
|
||
},
|
||
},
|
||
agentStream: {
|
||
empty: "Начните общаться с этим агентом...",
|
||
scrollToBottom: "Прокрутить вниз",
|
||
historyLoadFailed: "Не удалось загрузить историю агента",
|
||
permission: {
|
||
plan: "План",
|
||
required: "Требуется разрешение",
|
||
deny: "Отрицать",
|
||
accept: "Принимать",
|
||
implement: "Осуществлять",
|
||
question: "Как бы вы хотели продолжить?",
|
||
proposedPlan: "Предлагаемый план",
|
||
},
|
||
},
|
||
agentPanel: {
|
||
states: {
|
||
notFound: "Agent не найден",
|
||
failedToLoad: "Не удалось загрузить агент",
|
||
reconnecting: "Повторное подключение",
|
||
timelineSyncFailed: "Не удалось обновить историю агента.",
|
||
timelineSyncRetrying: "Повторная попытка…",
|
||
archivingTitle: "Архивный агент...",
|
||
archivingSubtitle: "Пожалуйста, подождите, пока мы архивируем этого агента.",
|
||
},
|
||
unavailable: {
|
||
selectedHost: "Выбранный хост",
|
||
unknownHost:
|
||
"Невозможно открыть этот агент, поскольку{{serverLabel}}не настроен на этом устройстве.",
|
||
addHost:
|
||
"Добавьте хост в настройках или откройте агент на настроенном сервере, чтобы продолжить.",
|
||
preparingSession: "Подготовка сеанса{{serverLabel}}...",
|
||
connecting: "Подключение к{{serverLabel}}...",
|
||
showSoon: "Мы покажем этого агента через минуту.",
|
||
showWhenOnline: "Мы покажем этого агента, как только хост будет онлайн.",
|
||
reconnectingTo: "Повторное подключение к{{serverLabel}}...",
|
||
showAgainWhenReachable: "Мы снова покажем этого агента, как только хост станет доступен.",
|
||
},
|
||
archived: {
|
||
callout: "Этот агент находится в архиве",
|
||
unarchive: "Разархивировать",
|
||
},
|
||
},
|
||
sessions: {
|
||
title: "История",
|
||
empty: "Сеансов пока нет",
|
||
noMatches: "Нет подходящих сеансов",
|
||
tooManyMatches: "Слишком много совпадений — уточните запрос",
|
||
hostLoadFailed: "{{host}}: Не удалось загрузить историю",
|
||
searchPlaceholder: "Поиск по истории",
|
||
actions: {
|
||
loadMore: "Загрузить больше",
|
||
clearSearch: "Очистить поиск",
|
||
},
|
||
},
|
||
agentList: {
|
||
fallbackTitle: "Новая сессия",
|
||
dateSections: {
|
||
recent: "Недавний",
|
||
today: "Сегодня",
|
||
yesterday: "Вчера",
|
||
thisWeek: "На этой неделе",
|
||
thisMonth: "В этом месяце",
|
||
older: "Старше",
|
||
},
|
||
status: {
|
||
initializing: "Начало",
|
||
idle: "Праздный",
|
||
running: "Бег",
|
||
error: "Ошибка",
|
||
closed: "Закрыто",
|
||
},
|
||
badges: {
|
||
archived: "В архиве",
|
||
pending: "{{count}}на рассмотрении",
|
||
attention: "Внимание",
|
||
},
|
||
archiveSheet: {
|
||
hostOffline: "Host оффлайн",
|
||
runningAgent: "Этот агент все еще работает. Архивирование остановит агент.",
|
||
archive: "Архив",
|
||
},
|
||
},
|
||
message: {
|
||
diagram: {
|
||
diagram: "Диаграмма",
|
||
zoomIn: "Приблизить",
|
||
zoomOut: "Отдалить",
|
||
resetZoom: "Сбросить вид",
|
||
viewSource: "Показать код",
|
||
viewDiagram: "Показать диаграмму",
|
||
},
|
||
actions: {
|
||
copyCode: "Скопировать код",
|
||
copyTurn: "Копировать ход",
|
||
copyMessage: "Копировать сообщение",
|
||
forkMenu: "Форкнуть сообщение",
|
||
forkInNewTab: "Форкнуть в новой вкладке",
|
||
forkInNewWorkspace: "Форкнуть в новом рабочем пространстве",
|
||
forkUnavailable: "Обновите хост, чтобы использовать это.",
|
||
forkMissingWorkspace: "Этот агент не находится в рабочем пространстве.",
|
||
forkFailed: "Не удалось форкнуть чат",
|
||
openFile: "Открыть файл",
|
||
copied: "Скопировано",
|
||
},
|
||
attachments: {
|
||
dismissImage: "Закрыть изображение",
|
||
closeImage: "Закрыть изображение",
|
||
imageLoadFailed: "Не удалось загрузить изображение",
|
||
imageUnavailable: "Изображение недоступно",
|
||
imagePreviewUnavailable: "Предварительный просмотр изображения недоступен.",
|
||
imagePreviewLoadFailed: "Невозможно загрузить предварительный просмотр изображения.",
|
||
review: "Ревью",
|
||
commentsOne: "1 комментарий",
|
||
commentsMany: "Комментарии: {{count}}",
|
||
textAttachment: "Текстовое вложение",
|
||
text: "Текст",
|
||
file: "Файл",
|
||
},
|
||
speak: {
|
||
header: "Говорил",
|
||
},
|
||
activity: {
|
||
details: "Подробности",
|
||
},
|
||
dictation: {
|
||
start: "Начать голосовой диктовку",
|
||
cancel: "Отменить диктовку",
|
||
retry: "Повторить диктовку",
|
||
insert: "Вставить транскрипцию",
|
||
insertAndSend: "Вставьте транскрипцию и отправьте",
|
||
failed: "Диктовка не удалась:{{error}}",
|
||
failedRetry: "Диктант не удался. Нажмите «Повторить».",
|
||
},
|
||
question: {
|
||
submit: "Представлять на рассмотрение",
|
||
next: "Далее",
|
||
answerPlaceholder: "Введите ответ...",
|
||
otherPlaceholder: "Другой...",
|
||
},
|
||
todo: {
|
||
title: "Задачи",
|
||
empty: "Заданий пока нет.",
|
||
tasksProgress: "{{completed}}/{{total}} задач",
|
||
activity: {
|
||
created: "Создано задач: {{count}}",
|
||
added: "Добавлена",
|
||
started: "Начата",
|
||
completed: "Завершена",
|
||
reopened: "Возобновлена",
|
||
},
|
||
},
|
||
compaction: {
|
||
loading: "Уплотнение...",
|
||
auto: "Контекст автоматически сжимается",
|
||
manual: "Контекст сжимается вручную",
|
||
withTokens: "Сжатый контекст (токены{{tokens}}K)",
|
||
completed: "Контекст сжат",
|
||
},
|
||
},
|
||
importSession: {
|
||
title: "Импортировать сеанс",
|
||
filters: {
|
||
all: "Все",
|
||
},
|
||
status: {
|
||
connectHost: "Подключитесь к хосту, чтобы импортировать сеансы",
|
||
updateHost: "Обновите хост для импорта сеансов.",
|
||
noProviders: "Импортируемые поставщики не включены.",
|
||
loading: "Загрузка последних сеансов...",
|
||
failedAll: "Не удалось загрузить последние сеансы.",
|
||
failedProviders: "Не удалось загрузить сеансы для{{providers}}.",
|
||
failedImport: "Не удалось импортировать выбранный сеанс.",
|
||
},
|
||
actions: {
|
||
refresh: "Обновить сеансы",
|
||
},
|
||
preview: {
|
||
untitledSession: "Сессия без названия",
|
||
noPrompt: "Нет быстрого предварительного просмотра",
|
||
},
|
||
empty: {
|
||
noRecent: "Нет последних сеансов для импорта.",
|
||
alreadyImported: "Все последние сеансы уже импортированы.",
|
||
noProviderSessions: "Сеансы{{provider}}не найдены.",
|
||
},
|
||
row: {
|
||
importing: "Импорт...",
|
||
},
|
||
},
|
||
workspace: {
|
||
route: {
|
||
loading: "Загрузка рабочей области",
|
||
connecting: "Подключение",
|
||
hostOffline: "{{hostName}}не в сети",
|
||
cannotReachHost: "Невозможно связаться с{{hostName}}",
|
||
hostStatus: "Статус Host:{{status}}",
|
||
needsHostUpgrade: "Обновите хост, чтобы восстановить эту рабочую область",
|
||
manageHost: "Управление хостом",
|
||
recovery: {
|
||
archivedTitle: "Рабочая область в архиве",
|
||
restoreDescription:
|
||
"{{workspaceName}} была архивирована, а её worktree удалён. Восстановите ветку {{branch}}, чтобы открыть её снова.",
|
||
unarchiveDescription:
|
||
"{{workspaceName}} находится в архиве. Разархивируйте её, чтобы открыть снова.",
|
||
restoreAction: "Восстановить",
|
||
unarchiveAction: "Разархивировать",
|
||
restoringTitle: "Восстановление рабочей области",
|
||
restoringAction: "Восстановление...",
|
||
unavailableTitle: "Рабочая область недоступна",
|
||
checkFailedTitle: "Не удалось проверить рабочую область",
|
||
},
|
||
},
|
||
hoverCard: {
|
||
scriptsAccessibility: "Скрипты Workspace",
|
||
copyPath: "Копировать путь",
|
||
copyBranchName: "Копировать имя ветки",
|
||
copied: "Скопировано",
|
||
},
|
||
fileActions: {
|
||
openFile: "Открыть файл",
|
||
copyPath: "Копировать путь",
|
||
copyRelativePath: "Копировать относительный путь",
|
||
revealIn: "Показать в {{target}}",
|
||
download: "Скачать",
|
||
addToChat: "Добавить в чат",
|
||
moreActions: "Дополнительные действия",
|
||
newFile: "Новый файл",
|
||
newFolder: "Новая папка",
|
||
collapseFolder: "Свернуть папку",
|
||
rename: "Переименовать",
|
||
duplicate: "Дублировать",
|
||
revert: "Отменить изменения",
|
||
delete: "Удалить",
|
||
confirmDelete: {
|
||
fileTitle: "Удалить файл?",
|
||
folderTitle: "Удалить папку?",
|
||
message: "«{{name}}» будет удалён безвозвратно.",
|
||
confirm: "Удалить",
|
||
cancel: "Отмена",
|
||
},
|
||
confirmRevert: {
|
||
title: "Отменить изменения?",
|
||
message: "Изменения в «{{name}}» будут безвозвратно отменены.",
|
||
confirm: "Отменить",
|
||
cancel: "Отмена",
|
||
failed: "Не удалось отменить изменения",
|
||
},
|
||
},
|
||
fileExplorer: {
|
||
sort: {
|
||
name: "Имя",
|
||
modified: "Модифицированный",
|
||
size: "Размер",
|
||
},
|
||
context: {
|
||
size: "Размер",
|
||
modified: "Модифицированный",
|
||
},
|
||
actions: {
|
||
back: "Назад",
|
||
retry: "Повторить попытку",
|
||
refresh: "Обновить файлы",
|
||
refreshing: "Обновление файлов",
|
||
hideHiddenFiles: "Скрыть скрытые файлы",
|
||
showHiddenFiles: "Показать скрытые файлы",
|
||
},
|
||
empty: {
|
||
noFiles: "Нет файлов",
|
||
noVisibleFiles: "Нет видимых файлов",
|
||
},
|
||
states: {
|
||
unavailable: "Workspace недоступен",
|
||
loading: "Загрузка файлов...",
|
||
},
|
||
errors: {
|
||
failedToListDirectory: "Не удалось указать каталог",
|
||
createFailed: "Не удалось создать элемент",
|
||
renameFailed: "Не удалось переименовать элемент",
|
||
duplicateFailed: "Не удалось дублировать элемент",
|
||
revealFailed: "Не удалось показать элемент",
|
||
deleteFailed: "Не удалось удалить элемент",
|
||
},
|
||
draft: {
|
||
filePlaceholder: "Имя файла",
|
||
folderPlaceholder: "Имя папки",
|
||
},
|
||
},
|
||
setup: {
|
||
descriptor: {
|
||
label: "Настраивать",
|
||
completed: "Настройка завершена",
|
||
failed: "Установка не удалась",
|
||
workspace: "Настройка Workspace",
|
||
},
|
||
status: {
|
||
running: "Бег",
|
||
completed: "Завершенный",
|
||
failed: "Неуспешный",
|
||
waiting: "Ожидание вывода настройки",
|
||
},
|
||
waiting: "Настройка рабочего места...",
|
||
empty: {
|
||
noCommands: "Для этой рабочей области не выполнялись команды настройки.",
|
||
},
|
||
accessibility: {
|
||
noCommands: "Для этой рабочей области не выполнялись команды настройки.",
|
||
log: "Журнал настройки Workspace",
|
||
},
|
||
log: {
|
||
noOutput: "Нет вывода",
|
||
},
|
||
},
|
||
browser: {
|
||
unavailable: {
|
||
title: "Браузер доступен только на рабочем столе",
|
||
subtitle:
|
||
"Откройте это рабочее пространство в Electron, чтобы использовать встроенный браузер.",
|
||
},
|
||
session: "Сеанс браузера{{browserId}}",
|
||
controls: {
|
||
back: "Назад",
|
||
forward: "Вперед",
|
||
stopLoading: "Остановить загрузку",
|
||
refresh: "Обновить",
|
||
browserUrl: "Браузер URL",
|
||
enterUrl: "Введите URL",
|
||
openDevTools: "Открыть инструменты разработки браузера",
|
||
cancelSelector: "Отменить выбор элемента",
|
||
annotateElement: "Аннотировать элемент",
|
||
screenshotElement: "Снимок элемента",
|
||
screenshotCopied: "Снимок скопирован в буфер обмена",
|
||
elementCopied: "Элемент скопирован в буфер обмена",
|
||
screenshotFailed: "Не удалось скопировать снимок",
|
||
selectorLoading: "Дождитесь окончания загрузки страницы",
|
||
selectorFailed: "Не удалось запустить выбор элемента",
|
||
},
|
||
annotate: {
|
||
title: "Аннотировать элемент",
|
||
placeholder: "Сообщение агенту об этом элементе…",
|
||
submit: "Прикрепить",
|
||
cancel: "Отмена",
|
||
},
|
||
devices: {
|
||
label: "Размер устройства",
|
||
responsive: "Адаптивный",
|
||
},
|
||
errors: {
|
||
failedToLoad: "Не удалось загрузить страницу",
|
||
invalidUrl: "Неверный браузер URL",
|
||
unsupportedProtocol: "Заблокирован неподдерживаемый браузер URL:{{protocol}}",
|
||
},
|
||
},
|
||
terminal: {
|
||
hostDisconnected: "Host не подключен",
|
||
updateHost: "Обновите хост, чтобы использовать нативный терминал.",
|
||
unableToSubscribe: "Невозможно подписаться на терминал",
|
||
},
|
||
tabs: {
|
||
loading: "Загрузка...",
|
||
modified: "Несохранённые изменения",
|
||
loadingAgentTitle: "Название агента загрузки",
|
||
emptyPane: "На этой панели нет вкладок.",
|
||
fallback: {
|
||
newAgent: "Новый агент",
|
||
setup: "Настраивать",
|
||
workspaceSetup: "Настройка Workspace",
|
||
terminal: "Terminal",
|
||
browser: "Браузер",
|
||
agent: "Agent",
|
||
workspace: "Workspace",
|
||
},
|
||
switcher: {
|
||
trigger: "Переключить вкладки ({{count}}открыт)",
|
||
title: "Переключить вкладку",
|
||
searchPlaceholder: "Вкладки поиска",
|
||
},
|
||
menu: {
|
||
openFor: "Открыть меню для{{label}}",
|
||
copyResumeCommand: "Копировать команду возобновления",
|
||
copyAgentId: "Скопировать идентификатор агента",
|
||
copyTerminalId: "Скопировать идентификатор терминала",
|
||
copyFilePath: "Copy file path",
|
||
rename: "Переименовать",
|
||
closeAbove: "Закрыть вкладки выше",
|
||
closeBelow: "Закройте вкладки ниже",
|
||
closeLeft: "Ближе к левому краю",
|
||
closeRight: "Ближе к правому",
|
||
closeOthers: "Закрыть другие вкладки",
|
||
reloadAgent: "Перезагрузить агент",
|
||
reloadAgentTooltip: "Перезагрузите агента, чтобы обновить навыки, MCP или статус входа.",
|
||
close: "Закрывать",
|
||
renameTerminal: "Переименование терминала",
|
||
renameAgent: "Переименовать агента",
|
||
},
|
||
actions: {
|
||
newTab: "Новая вкладка",
|
||
newAgent: "Новый агент",
|
||
newTerminal: "Новый терминал",
|
||
preparingTerminal: "Подготовка вкладки терминала",
|
||
preparingTerminalTooltip: "Подготовка терминала...",
|
||
newBrowser: "Новый браузер",
|
||
maximizePane: "Развернуть панель",
|
||
restorePane: "Восстановить панель",
|
||
exitFocusMode: "Выйти из режима фокусировки",
|
||
splitRight: "Разделить панель справа",
|
||
splitDown: "Разделить панель вниз",
|
||
changes: "Изменения",
|
||
files: "Файлы",
|
||
pullRequest: "Запрос на слияние",
|
||
terminalProfilesMenu: "Terminal profiles",
|
||
editTerminalProfiles: "Edit profiles…",
|
||
},
|
||
explorer: {
|
||
open: "Открыть проводник",
|
||
close: "Закрыть проводник",
|
||
toggle: "Переключить проводник",
|
||
changes: "Изменения",
|
||
files: "Файлы",
|
||
},
|
||
toasts: {
|
||
copyFailed: "Не удалось скопировать",
|
||
agentIdCopiedLabel: "AgentID",
|
||
terminalIdCopiedLabel: "Идентификатор терминала",
|
||
resumeCommandCopiedLabel: "команда возобновления",
|
||
filePathCopiedLabel: "File path",
|
||
resumeIdUnavailable: "Резюме ID недоступно",
|
||
resumeCommandUnavailable: "Команда возобновления недоступна",
|
||
reloadingAgent: "Перезагрузка агента...",
|
||
reloadedAgent: "Перезагруженный агент",
|
||
failedToReloadAgent: "Не удалось перезагрузить агент",
|
||
failedToCloseAgent: "Не удалось закрыть агент",
|
||
},
|
||
confirmations: {
|
||
unsavedTitle: "Несохранённые изменения",
|
||
unsavedMessage:
|
||
"В этой вкладке есть несохранённые изменения. При закрытии черновик будет удалён.",
|
||
closeWithoutSaving: "Закрыть без сохранения",
|
||
closePaneTitle: "Закрыть панель?",
|
||
bulkUnsaved:
|
||
"В {{count}} вкладках есть несохранённые изменения. При закрытии черновики будут удалены.",
|
||
close: "Закрывать",
|
||
cancel: "Отмена",
|
||
archive: "Архив",
|
||
closeTerminalTitle: "Закрыть терминал?",
|
||
closeTerminalMessage:
|
||
"Любой запущенный процесс в этом терминале будет немедленно остановлен.",
|
||
archiveRunningAgentTitle: "Агент запуска архива?",
|
||
archiveRunningAgentMessage:
|
||
"Этот агент все еще работает. Архивирование остановит агент и закроет вкладку.",
|
||
closeTabsLeftTitle: "Закрыть вкладки слева?",
|
||
closeTabsRightTitle: "Закрыть вкладки справа?",
|
||
closeOtherTabsTitle: "Закрыть другие вкладки?",
|
||
bulk: {
|
||
all: "При этом агенты{{agents}}будут заархивированы, терминалы{{terminals}}закроются, а вкладки{{tabs}}будут закрыты. Любой запущенный процесс в закрытом терминале будет немедленно остановлен.",
|
||
agentsAndTerminals:
|
||
"Это приведет к архивированию агентов{{agents}}и закрытию терминалов{{terminals}}. Любой запущенный процесс в закрытом терминале будет немедленно остановлен.",
|
||
terminalsAndTabs:
|
||
"Это закроет терминал(ы){{terminals}}и закроет вкладки(и){{tabs}}. Любой запущенный процесс в закрытом терминале будет немедленно остановлен.",
|
||
agentsAndTabs:
|
||
"При этом агенты{{agents}}будут заархивированы, а вкладки{{tabs}}закроются.",
|
||
terminals:
|
||
"Это закроет терминал(ы){{terminals}}. Любой запущенный процесс в закрытом терминале будет немедленно остановлен.",
|
||
tabs: "Это закроет вкладки{{tabs}}.",
|
||
agents: "Это приведет к архивированию агентов{{agents}}.",
|
||
},
|
||
},
|
||
},
|
||
header: {
|
||
actions: {
|
||
workspaceActions: "Действия Workspace",
|
||
newAgent: "Новый агент",
|
||
newTerminal: "Новый терминал",
|
||
newBrowser: "Новая вкладка браузера",
|
||
importSession: "Импортировать сеанс",
|
||
copyPath: "Копировать путь к рабочей области",
|
||
copyBranchName: "Скопировать название ветки",
|
||
showSetup: "Показать настройки",
|
||
},
|
||
toasts: {
|
||
workspacePathUnavailable: "Путь Workspace пока недоступен.",
|
||
branchNameUnavailable: "Название филиала недоступно",
|
||
terminalQueued: "Подготовка рабочего пространства, открытие терминала по готовности...",
|
||
workspacePathCopiedLabel: "Путь Workspace",
|
||
branchNameCopiedLabel: "Название филиала",
|
||
},
|
||
},
|
||
scripts: {
|
||
title: "Скрипты",
|
||
actions: {
|
||
chooseUrl: "Выбрать URL",
|
||
copyUrl: "Скопировать URL",
|
||
openService: "Просмотреть сервис",
|
||
restart: "Перезапустить",
|
||
run: "Бегать",
|
||
stop: "Остановить",
|
||
view: "Открыть терминал",
|
||
},
|
||
accessibility: {
|
||
trigger: "Скрипты Workspace",
|
||
openService: "Просмотреть сервис {{scriptName}}",
|
||
viewTerminal: "Посмотреть терминал{{scriptName}}",
|
||
runScript: "Запустите скрипт{{scriptName}}",
|
||
stopScript: "Остановить{{scriptName}}",
|
||
restartScript: "Перезапустить{{scriptName}}",
|
||
copyUrl: "Скопировать URL {{scriptName}}",
|
||
chooseUrl: "Выбрать URL для {{scriptName}}",
|
||
script: "скрипт{{scriptName}}",
|
||
},
|
||
routes: {
|
||
public: "Обратный прокси",
|
||
paseo: "Memorable",
|
||
direct: "Прямой адрес",
|
||
},
|
||
states: {
|
||
exitCode: "выйти из{{code}}",
|
||
startFailed: "Не удалось запустить{{scriptName}}",
|
||
stopFailed: "Не удалось остановить{{scriptName}}",
|
||
},
|
||
},
|
||
git: {
|
||
actions: {
|
||
moreOptions: "Больше возможностей",
|
||
moreActions: "Дополнительные действия",
|
||
commit: {
|
||
label: "Совершить",
|
||
pending: "Совершение...",
|
||
success: "Преданный идее",
|
||
},
|
||
pull: {
|
||
label: "Тянуть",
|
||
pending: "Тяну...",
|
||
success: "Вытащил",
|
||
},
|
||
push: {
|
||
label: "Толкать",
|
||
pending: "Толкаю...",
|
||
success: "Нажатый",
|
||
},
|
||
pullAndPush: {
|
||
label: "Тяни и толкай",
|
||
pending: "Тянет и толкает...",
|
||
success: "Вытащил и толкнул",
|
||
},
|
||
viewPr: "Посмотреть PR",
|
||
createPr: {
|
||
label: "Создать PR",
|
||
pending: "Создание PR...",
|
||
success: "PR создано",
|
||
label_mr: "Создать MR",
|
||
pending_mr: "Создание MR...",
|
||
success_mr: "MR создано",
|
||
},
|
||
mergeBranch: {
|
||
label: "Объединить локально",
|
||
pending: "Слияние...",
|
||
success: "Объединено",
|
||
},
|
||
mergeFromBase: {
|
||
label: "Обновление от{{baseRef}}",
|
||
pending: "Обновление...",
|
||
success: "Обновлено",
|
||
},
|
||
archive: {
|
||
label: "Архивировать рабочее пространство",
|
||
pending: "Архивирование...",
|
||
success: "В архиве",
|
||
},
|
||
mergePr: {
|
||
squash: "Объединить PR (squash)",
|
||
merge: "Объединить PR (merge)",
|
||
rebase: "Объединить PR (rebase)",
|
||
pending: "Объединение PR...",
|
||
success: "PR объединен",
|
||
squash_mr: "Объединить MR (squash)",
|
||
merge_mr: "Объединить MR (merge)",
|
||
rebase_mr: "Объединить MR (rebase)",
|
||
pending_mr: "Объединение MR...",
|
||
success_mr: "MR объединен",
|
||
},
|
||
viewPr_mr: "Посмотреть MR",
|
||
autoMerge: {
|
||
enableSquash: "Автообъединение (squash)",
|
||
enableMerge: "Автообъединение (merge)",
|
||
enableRebase: "Автообъединение (rebase)",
|
||
enabled: "Автоматическое объединение включено",
|
||
enabling: "Включение автоматического объединения...",
|
||
disabling: "Отключение автоматического объединения...",
|
||
disabled: "Автоматическое объединение отключено",
|
||
},
|
||
unavailable: {
|
||
viewPrNoForge: "Просмотр {{noun}} сейчас недоступен, поскольку {{brand}} не подключен.",
|
||
pullNoRemote:
|
||
"Функция Pull здесь недоступна, поскольку эта ветка еще не подключена к удаленному серверу.",
|
||
pullDirty:
|
||
"Функция Pull недоступна, пока у вас есть локальные изменения, поэтому сначала зафиксируйте или сохраните их.",
|
||
pullUpToDate: "Функция Pull недоступна, поскольку эта ветка уже обновлена.",
|
||
pushNoRemote:
|
||
"Push здесь недоступен, поскольку эта ветка еще не подключена к удаленному устройству.",
|
||
pushBehind: "Push пока недоступен, поскольку сначала нужно внести новые изменения.",
|
||
pushNothing: "Push недоступен, поскольку нет ничего нового для отправки.",
|
||
pullAndPushNoRemote:
|
||
"Функция Pull and Push здесь недоступна, поскольку эта ветка еще не подключена к удаленному устройству.",
|
||
pullAndPushDirty:
|
||
"Функция извлечения и отправки недоступна, пока у вас есть локальные изменения, поэтому сначала зафиксируйте или сохраните их.",
|
||
pullAndPushNoIncoming:
|
||
"Функция Pull and Push недоступна, поскольку сначала нечего получать.",
|
||
pullAndPushInSync:
|
||
"Функция Pull and Push недоступна, поскольку эта ветвь уже синхронизирована.",
|
||
pullAndPushNothingToPush:
|
||
"Функция Pull and Push недоступна, поскольку после pull нечего отправлять.",
|
||
createPrNoForge:
|
||
"Функция «Создать {{noun}}» сейчас недоступна, поскольку {{brand}} не подключен.",
|
||
createPrNoCommits:
|
||
"Функция «Создать PR» недоступна, поскольку в этой ветке еще нет новых коммитов.",
|
||
mergeNoBase: "Объединение недоступно, поскольку нам не удалось определить базовую ветку.",
|
||
mergeDirty:
|
||
"Объединение недоступно, пока у вас есть локальные изменения, поэтому сначала зафиксируйте или сохраните их.",
|
||
mergeNothing:
|
||
"Объединение недоступно, поскольку в этой ветке еще нет ничего нового для объединения.",
|
||
updateNoBase: "Обновление недоступно, поскольку нам не удалось определить базовую ветку.",
|
||
updateDirty:
|
||
"Обновление недоступно, пока у вас есть локальные изменения, поэтому сначала зафиксируйте или сохраните их.",
|
||
updateCurrent:
|
||
"Обновление недоступно, поскольку эта ветка уже обновлена до версии{{baseRef}}.",
|
||
mergePrNoGithub: "Объединение PR сейчас недоступно, поскольку GitHub не подключен.",
|
||
archiveNotWorktree:
|
||
"Архив здесь недоступен, поскольку это рабочее пространство не было создано как рабочее дерево Paseo.",
|
||
mergePrNoForge:
|
||
"Объединение {{noun}} сейчас недоступно, поскольку {{brand}} не подключен.",
|
||
mergePrMissing: "Объединение PR недоступно, поскольку еще нет запроса на включение",
|
||
mergePrDraft:
|
||
"Объединение PR недоступно, поскольку запрос на включение все еще находится на стадии черновика.",
|
||
mergePrMerged: "Объединение PR недоступно, поскольку запрос на включение уже объединен.",
|
||
mergePrClosed: "Объединение PR недоступно, поскольку запрос на включение закрыт.",
|
||
mergePrConflicts:
|
||
"Объединение PR недоступно, поскольку запрос на включение содержит конфликты.",
|
||
mergePrQueue:
|
||
"Слияние PR здесь недоступно, поскольку этот репозиторий использует очередь слияния.",
|
||
mergePrNotReady:
|
||
"Функция слияния {{noun}} недоступна до тех пор, пока {{brand}} не сообщит, что {{noun}} готов к слиянию.",
|
||
autoMergeCannotDisable:
|
||
"Автоматическое объединение включено, но этот аккаунт не может его отключить.",
|
||
},
|
||
toasts: {
|
||
failedCommit: "Не удалось совершить фиксацию",
|
||
failedPull: "Не удалось вытащить",
|
||
failedPush: "Не удалось нажать",
|
||
failedPullAndPush: "Не удалось тянуть и толкать",
|
||
failedCreatePr: "Не удалось создать PR.",
|
||
failedMergePr: "Не удалось объединить PR.",
|
||
failedEnableAutoMerge: "Не удалось включить автоматическое объединение",
|
||
failedDisableAutoMerge: "Не удалось отключить автоматическое объединение",
|
||
baseRefUnavailable: "Базовый номер недоступен.",
|
||
failedMerge: "Не удалось объединиться",
|
||
failedMergeFromBase: "Не удалось объединиться с базой.",
|
||
},
|
||
archiveWarning: {
|
||
title: 'Архив "{{workspaceName}}"?',
|
||
confirm: "Архив",
|
||
cancel: "Отмена",
|
||
uncommittedChanges: "Незафиксированные изменения",
|
||
uncommittedChangesWithDiff: "Незафиксированные изменения ({{diffStat}})",
|
||
addedLine: "{{count}}добавлена строка",
|
||
addedLines: "{{count}}добавил строки",
|
||
deletedLine: "{{count}}удалена строка",
|
||
deletedLines: "{{count}}удалил строки",
|
||
unpushedCommit: "Неотправленная фиксация{{count}}",
|
||
unpushedCommits: "Неотправленные коммиты{{count}}",
|
||
},
|
||
},
|
||
diff: {
|
||
openChangesTab: "Открыть вкладку «Изменения»",
|
||
closeChangesTab: "Закрыть вкладку «Изменения»",
|
||
binaryFile: "Бинарный файл",
|
||
tooLarge: "Разница слишком велика для отображения",
|
||
previewTooLargeTitle: "Этот diff слишком велик для предпросмотра",
|
||
previewTooLargeDescription: "Сузьте сравнение, чтобы просмотреть его здесь",
|
||
unified: "Единый дифференциал",
|
||
split: "Параллельная разница",
|
||
switchToUnified: "Переключить на объединенный diff",
|
||
switchToSplit: "Переключить на diff рядом",
|
||
showTreeView: "Показать дерево папок",
|
||
hideTreeView: "Скрыть дерево папок",
|
||
options: "Параметры diff",
|
||
hideWhitespace: "Скрыть пробелы",
|
||
showWhitespace: "Показать пробелы",
|
||
scrollLongLines: "Прокручивать длинные строки",
|
||
wrapLongLines: "Перенос длинных строк",
|
||
collapseAllFolders: "Свернуть все папки",
|
||
expandAllFolders: "Развернуть все папки",
|
||
collapseAllFiles: "Свернуть все файлы",
|
||
expandAllFiles: "Развернуть все файлы",
|
||
refreshing: "Освежающий",
|
||
refresh: "Обновить",
|
||
refreshState: "Обновить состояние git и {{brand}}",
|
||
failedRefresh: "Не удалось обновить состояние git.",
|
||
emptyHiddenWhitespace: "Никаких видимых изменений после скрытия пробелов",
|
||
emptyUncommitted: "Нет незафиксированных изменений",
|
||
emptyAgainstBase: "Никаких изменений по сравнению с{{baseRef}}",
|
||
checkingRepository: "Проверяем репозиторий...",
|
||
notRepository: "Не git- репозиторий",
|
||
diffMode: "Режим разницы",
|
||
uncommitted: "Незафиксированный",
|
||
committed: "Преданный идее",
|
||
branchUnknown: "Неизвестный",
|
||
base: "база",
|
||
newFile: "Новый",
|
||
deletedFile: "Удалено",
|
||
modifiedFile: "Изменено",
|
||
commits: {
|
||
title: "Коммиты",
|
||
countLabel: "{{count}} коммитов рабочего пространства",
|
||
noneAhead: "Коммитов впереди {{baseRef}} пока нет",
|
||
fileDiffEmpty: "Нет изменений для отображения",
|
||
fileDiffError: "Не удалось загрузить различия файла",
|
||
loading: "Загрузка коммитов…",
|
||
loadError: "Не удалось загрузить коммиты",
|
||
empty: "Коммитов пока нет",
|
||
},
|
||
},
|
||
openInEditor: {
|
||
open: "Открыть",
|
||
chooseEditor: "Выбрать редактор",
|
||
openIn: "Открыть рабочую область в{{target}}",
|
||
openFileIn: "Open {{fileName}} in {{target}}",
|
||
failedOpen: "Не удалось открыть рабочую область",
|
||
},
|
||
pr: {
|
||
actions: {
|
||
viewPullRequest: "Открыть",
|
||
openOn: "Открыть на {{brand}}",
|
||
},
|
||
checksSummary: {
|
||
passedLabel: "успешно",
|
||
failedLabel: "ошибка",
|
||
runningLabel: "выполняется",
|
||
passedAccessible: "Проверки пройдены",
|
||
failedAccessible: "Проверки не пройдены",
|
||
runningAccessible: "Проверки выполняются",
|
||
},
|
||
sections: {
|
||
checks: "Чеки",
|
||
pipeline: "Пайплайн",
|
||
reviews: "Отзывы",
|
||
},
|
||
empty: {
|
||
noJobs: "Нет задач",
|
||
loadingPipeline: "Загрузка пайплайна...",
|
||
pipelineJobsLoadFailed: "Не удалось загрузить задачи пайплайна",
|
||
allowedToFail: "допускается сбой",
|
||
},
|
||
approvals: "{{given}} из {{required}} одобрений",
|
||
accessibility: {
|
||
pullRequest: "Запрос на извлечение №{{number}}",
|
||
pullRequest_mr: "Запрос на слияние !{{number}}",
|
||
},
|
||
states: {
|
||
draft: "Черновик",
|
||
merged: "Объединено",
|
||
closed: "Закрыто",
|
||
open: "Открыть",
|
||
},
|
||
activity: {
|
||
commented: "Прокомментировал",
|
||
approved: "Одобренный",
|
||
requestedChanges: "Запрошенные изменения",
|
||
reviewed: "Рассмотрено",
|
||
},
|
||
time: {
|
||
justNow: "прямо сейчас",
|
||
},
|
||
thread: {
|
||
discussion: "Обсуждение",
|
||
},
|
||
errors: {
|
||
statusLoadFailed: "Невозможно загрузить статус запроса на включение",
|
||
activityLoadFailed: "Невозможно загрузить активность запроса на включение",
|
||
},
|
||
},
|
||
forgeSetup: {
|
||
installCli: "Установите CLI {{cli}}, чтобы использовать возможности {{brand}}.",
|
||
signIn: "Выполните {{command}}, чтобы использовать возможности {{brand}}.",
|
||
generic: "Настройте {{brand}} на этом хосте, чтобы использовать его функции.",
|
||
},
|
||
},
|
||
},
|
||
workspaceLabels: {
|
||
title: "Метки",
|
||
unlabelled: "Без метки",
|
||
create: "Создать метку",
|
||
createConfirm: "Создать",
|
||
creating: "Создание…",
|
||
name: "Название метки",
|
||
updateHostUse: "Обновите этот хост, чтобы использовать метки.",
|
||
errors: { update: "Не удалось обновить метку", load: "Не удалось загрузить метки" },
|
||
colors: {
|
||
violet: "Фиолетовый",
|
||
sky: "Небесный",
|
||
emerald: "Изумрудный",
|
||
orange: "Оранжевый",
|
||
pink: "Розовый",
|
||
indigo: "Индиго",
|
||
teal: "Бирюзовый",
|
||
red: "Красный",
|
||
amber: "Янтарный",
|
||
blue: "Синий",
|
||
},
|
||
filter: {
|
||
clear: "Очистить фильтр",
|
||
noMatchesTitle: "Нет подходящих рабочих пространств",
|
||
noMatchesDescription:
|
||
"Измените или очистите фильтр меток, чтобы увидеть рабочие пространства.",
|
||
},
|
||
manage: {
|
||
open: "Управление метками…",
|
||
title: "Управление метками",
|
||
search: "Поиск меток",
|
||
empty: "На этом хосте нет меток.",
|
||
edit: "Изменить метку",
|
||
editLabel: "Изменить {{name}}",
|
||
name: "Название",
|
||
color: "Цвет",
|
||
save: "Сохранить",
|
||
delete: "Удалить",
|
||
deleteTitle: "Удалить {{name}}?",
|
||
deleteMessage_one: "Метка будет удалена из {{count}} рабочего пространства на этом хосте.",
|
||
deleteMessage_other: "Метка будет удалена из {{count}} рабочих пространств на этом хосте.",
|
||
offline: "Этот хост не в сети.",
|
||
updateHost: "Обновите этот хост для управления метками.",
|
||
},
|
||
},
|
||
sidebar: {
|
||
display: {
|
||
trigger: "Настройки отображения",
|
||
heading: "Отображение",
|
||
grouping: {
|
||
label: "Группировка",
|
||
project: "Проект",
|
||
status: "Статус",
|
||
labels: "Метки",
|
||
},
|
||
titleSource: {
|
||
label: "Заголовок",
|
||
title: "Заголовок",
|
||
branch: "Имя ветки",
|
||
},
|
||
show: {
|
||
label: "Показывать",
|
||
branch: "Ветка",
|
||
project: "Проект",
|
||
host: "Хост",
|
||
changeRequest: "Pull request",
|
||
checks: "Проверки",
|
||
services: "Сервисы",
|
||
labels: "Метки",
|
||
diff: "Статистика изменений",
|
||
timestamp: "Последняя активность",
|
||
},
|
||
checks: {
|
||
iconAndText: "Значок и текст",
|
||
icon: "Только значок",
|
||
none: "Скрыто",
|
||
},
|
||
hostFilter: {
|
||
label: "Хост",
|
||
all: "Все хосты",
|
||
},
|
||
},
|
||
pinned: {
|
||
title: "Закреплённые",
|
||
},
|
||
host: {
|
||
noHost: "Нет хоста",
|
||
switchTitle: "Сменить хост",
|
||
searchPlaceholder: "Поиск хостов...",
|
||
},
|
||
actions: {
|
||
addProject: "Добавить проект",
|
||
newWorkspace: "Новое рабочее пространство",
|
||
hosts: "Хосты",
|
||
home: "Дом",
|
||
settings: "Настройки",
|
||
closeSidebar: "Закрыть боковую панель",
|
||
},
|
||
help: {
|
||
trigger: "Помощь и поддержка",
|
||
sectionHelp: "Помощь",
|
||
diagnostics: "Запустить диагностику",
|
||
shortcuts: "Сочетания клавиш",
|
||
reportIssue: "Сообщить о проблеме",
|
||
discord: "Discord",
|
||
github: "Создать issue в GitHub",
|
||
whatsNew: "Что нового",
|
||
appName: "Paseo",
|
||
},
|
||
sections: {
|
||
sessions: "История",
|
||
schedules: "Расписания",
|
||
},
|
||
worktreeSetup: {
|
||
title: "Настройка сценариев рабочего дерева",
|
||
description:
|
||
"Добавьте команды настройки, чтобы новые рабочие деревья могли автоматически устанавливать зависимости и готовиться.",
|
||
openProjectSettings: "Открыть настройки проекта",
|
||
},
|
||
project: {
|
||
actions: {
|
||
menu: "Действия проекта",
|
||
openSettings: "Открыть настройки проекта",
|
||
openNewWindow: "Open in new window",
|
||
openNewWindowFailed: "Couldn't open a new window",
|
||
openFolder: "Open in file manager",
|
||
openFolderFailed: "Couldn't open folder",
|
||
remove: "Удалить проект",
|
||
removing: "Удаление...",
|
||
},
|
||
confirmations: {
|
||
removeTitle: "Удалить проект?",
|
||
removeMessage:
|
||
"Удалить «{{projectName}}» с боковой панели?\n\n Файлы на диске не будут изменены.",
|
||
removeConfirm: "Удалять",
|
||
cancel: "Отмена",
|
||
},
|
||
toasts: {
|
||
hostDisconnected: "Host не подключен",
|
||
removeFailed: "Не удалось удалить некоторые рабочие области.",
|
||
updateHostToRemove: "Обновите host, чтобы удалять проекты.",
|
||
},
|
||
empty: {
|
||
title: "Пока нет проектов",
|
||
description: "Добавьте проект, чтобы начать",
|
||
},
|
||
},
|
||
workspace: {
|
||
status: {
|
||
serviceRunning: "Сервис {{name}} запущен",
|
||
serviceUnhealthy: "Сервис {{name}} неисправен",
|
||
creating: "Создание...",
|
||
},
|
||
actions: {
|
||
menu: "Действия Workspace",
|
||
newWorkspace: "Новое рабочее пространство",
|
||
showMore: "Показать ещё",
|
||
showLess: "Показать меньше",
|
||
createWorkspaceFor: "Создайте новое рабочее пространство для{{projectName}}.",
|
||
copyPath: "Копировать путь",
|
||
copyBranchName: "Скопировать название ветки",
|
||
rename: "Переименовать рабочую область",
|
||
pin: "Закрепить вверху",
|
||
unpin: "Открепить",
|
||
archive: "Архив",
|
||
archiveWorkspace: "Архивировать рабочее пространство",
|
||
hideFromSidebar: "Скрыть с боковой панели",
|
||
archiving: "Архивирование...",
|
||
hiding: "Скрытие...",
|
||
},
|
||
confirmations: {
|
||
hideTitle: "Скрыть рабочее пространство?",
|
||
hideMessage:
|
||
"Скрыть «{{workspaceName}}» на боковой панели?\n\n Файлы на диске не будут изменены.",
|
||
hideConfirm: "Скрывать",
|
||
cancel: "Отмена",
|
||
},
|
||
rename: {
|
||
title: "Переименовать рабочую область",
|
||
submit: "Переименовать",
|
||
invalidBranchName: "Неверное название ветки",
|
||
},
|
||
toasts: {
|
||
workspacePathUnavailable: "Путь Workspace недоступен",
|
||
pathCopied: "Путь скопирован",
|
||
branchNameCopied: "Название филиала скопировано.",
|
||
hostDisconnected: "Host не подключен",
|
||
hideFailed: "Не удалось скрыть рабочую область.",
|
||
archiveFailed: "Не удалось заархивировать рабочее пространство.",
|
||
},
|
||
},
|
||
},
|
||
newWorkspace: {
|
||
title: "Новое рабочее пространство",
|
||
create: "Создавать",
|
||
isolation: {
|
||
local: "Локально",
|
||
worktree: "Новый worktree",
|
||
label: "Изоляция",
|
||
},
|
||
fields: {
|
||
project: "Проект",
|
||
base: "База",
|
||
baseNotApplicable: "Неприменимо",
|
||
},
|
||
titlePlaceholder: "Название (необязательно)",
|
||
errors: {
|
||
hostDisconnected: "Host не подключен",
|
||
createWorktreeFailed: "Не удалось создать рабочее дерево.",
|
||
composerStateRequired: "Требуется состояние композитора.",
|
||
selectModel: "Выберите модель",
|
||
},
|
||
tooltips: {
|
||
project: "Choose the project",
|
||
host: "Choose the host",
|
||
isolation: "Choose the isolation level",
|
||
startingRef: "Выберите, с чего начать",
|
||
launch: "Choose what to launch",
|
||
},
|
||
refPicker: {
|
||
startingRef: "Начальная ссылка",
|
||
intoBase: "в {{baseRef}}",
|
||
searching: "Идет поиск...",
|
||
noMatchingRefs: "Нет подходящих ссылок.",
|
||
searchPlaceholder: "Поиск филиалов и PR",
|
||
title: "Начать с",
|
||
},
|
||
launch: {
|
||
title: "What to launch",
|
||
chat: "Chat",
|
||
terminal: "Terminal",
|
||
manageProfiles: "Manage profiles",
|
||
submit: "Launch",
|
||
promptPlaceholder: "Prompt {{name}}",
|
||
commandPlaceholder: "Run a command, or leave empty for a blank terminal",
|
||
},
|
||
},
|
||
desktop: {
|
||
quitting: {
|
||
title: "Выход из Paseo...",
|
||
detail: "Остановка локального демона.",
|
||
},
|
||
daemon: {
|
||
title: "Daemon",
|
||
status: {
|
||
title: "Статус",
|
||
builtInOnly: "Здесь показан только встроенный демон рабочего стола.",
|
||
running: "бег",
|
||
notRunning: "не работает",
|
||
pid: "PID{{pid}}",
|
||
},
|
||
management: {
|
||
title: "Управление встроенным демоном",
|
||
hint: "Позвольте Paseo запустить и остановить встроенный демон.",
|
||
pauseTitle: "Приостановить встроенный демон",
|
||
pauseMessage:
|
||
"Это немедленно остановит встроенный демон. Запущенные агенты и терминалы, подключенные к встроенному демону, будут остановлены.",
|
||
pauseAndStop: "Пауза и остановка",
|
||
registrationFailed:
|
||
"Built-in daemon started, but Paseo could not save the localhost connection. Toggle daemon management off and on again, or add localhost manually.",
|
||
pausedStopFailed:
|
||
"Встроенное управление демоном было приостановлено, но Paseo не смог остановить демон.",
|
||
updateFailed: "Невозможно обновить встроенное управление демонами.",
|
||
},
|
||
keepRunning: {
|
||
title: "Продолжать работу демона после выхода",
|
||
hint: "Daemon продолжает работать, когда вы выходите из Paseo",
|
||
},
|
||
logs: {
|
||
title: "Файл журнала",
|
||
modalTitle: "Журналы Daemon",
|
||
unavailable: "Путь к журналу недоступен",
|
||
empty: "(файл журнала пуст)",
|
||
copied: "Путь к журналу скопирован.",
|
||
copyFailed: "Невозможно скопировать путь к журналу.",
|
||
open: "Открыть журналы",
|
||
copyPath: "Копировать путь",
|
||
},
|
||
fullStatus: {
|
||
title: "Полный статус",
|
||
modalTitle: "Статус Daemon",
|
||
hint: "Запускает`paseo daemon status`и показывает результат",
|
||
view: "Посмотреть статус",
|
||
copied: "Статус скопирован в буфер обмена.",
|
||
fetchFailed: "Не удалось получить статус демона:{{message}}.",
|
||
},
|
||
advancedSettings: "Расширенные настройки",
|
||
openAdvancedSettings: "Открыть дополнительные настройки демона",
|
||
versionMismatch:
|
||
"Версии приложения и демона не совпадают. Обновите обе версии до одной и той же версии для лучшего опыта.",
|
||
loadFailed: "Невозможно загрузить статус демона рабочего стола.",
|
||
},
|
||
updates: {
|
||
status: {
|
||
checking: "Проверка обновлений приложения...",
|
||
installing: "Установка обновления приложения...",
|
||
upToDate: "Приложение актуально.",
|
||
upToDateWithLastChecked: "Up to date. Last checked at {{time}}.",
|
||
pending: "Мы сообщим вам, когда обновление будет готово.",
|
||
pendingWithLastChecked:
|
||
"Мы сообщим вам, когда обновление будет готово. Последняя проверка в {{time}}.",
|
||
pendingWithVersion: "Найдено обновление: {{version}}. Загрузка...",
|
||
pendingWithVersionAndLastChecked:
|
||
"Найдено обновление: {{version}}. Загрузка... Последняя проверка в {{time}}.",
|
||
availableWithVersion: "Обновление готово:{{version}}",
|
||
availableWithVersionAndLastChecked:
|
||
"Обновление готово:{{version}}. Последняя проверка в {{time}}.",
|
||
available: "Обновление приложения готово к установке.",
|
||
availableWithLastChecked:
|
||
"Обновление приложения готово к установке. Последняя проверка в {{time}}.",
|
||
installed: "Обновление приложения установлено. Требуется перезагрузка.",
|
||
failed: "Не удалось обновить приложение.",
|
||
idle: "Статус обновления еще не проверен.",
|
||
},
|
||
installError: "Невозможно установить обновление настольного приложения.",
|
||
callout: {
|
||
installingTitle: "Установка обновления",
|
||
failedTitle: "Обновление не выполнено",
|
||
availableTitle: "Доступно обновление",
|
||
genericError: "Что- то пошло не так.",
|
||
whatsNew: "Что нового",
|
||
installingAction: "Установка...",
|
||
installAndRestart: "Установить и перезапустить",
|
||
installingDescription: "Установка и перезапуск...",
|
||
versionReady: "{{version}}готов к установке.",
|
||
newVersionReady: "Новая версия готова к установке.",
|
||
restartWarning:
|
||
"Обновление приложения приведет к остановке работы агентов и закрытию сеансов терминала.",
|
||
},
|
||
},
|
||
settings: {
|
||
loadFailed: "Невозможно загрузить настройки рабочего стола.",
|
||
saveFailed: "Невозможно сохранить настройки рабочего стола.",
|
||
},
|
||
rosetta: {
|
||
title: "Загрузите сборку Apple Silicon",
|
||
runningIntel: "Вы используете сборку Intel для Paseo под Rosetta на Apple Silicon.",
|
||
highCpu:
|
||
"Это приводит к высокой загрузке ЦП. Загрузите сборку Apple Silicon, чтобы исправить это.",
|
||
download: "Скачать",
|
||
},
|
||
permissions: {
|
||
notifications: {
|
||
allowed: "Уведомления разрешены операционной системой.",
|
||
denied: "Уведомления запрещены в настройках системы.",
|
||
notGranted: "Уведомления еще не были предоставлены.",
|
||
webOnly: "Статус уведомлений на рабочем столе доступен только в веб- среде выполнения.",
|
||
supported: "Уведомления на рабочем столе поддерживаются.",
|
||
unsupported: "Уведомления на рабочем столе не поддерживаются на этой платформе.",
|
||
apiUnavailable: "API веб- уведомлений недоступен в этой среде.",
|
||
requestsWebOnly:
|
||
"Запросы уведомлений на рабочем столе доступны только в веб- среде выполнения.",
|
||
requestUnavailable: "API веб- уведомлений requestPermission() недоступен.",
|
||
requestFailed: "Не удалось запросить разрешение на уведомление:{{message}}.",
|
||
unexpectedState: "Состояние разрешения на непредвиденное уведомление:{{state}}.",
|
||
},
|
||
microphone: {
|
||
webOnly: "Статус настольного микрофона доступен только в веб- среде выполнения.",
|
||
navigatorUnavailable: "Навигатор недоступен в этой среде.",
|
||
granted: "Доступ к микрофону разрешен.",
|
||
denied: "Доступ к микрофону запрещен в настройках системы.",
|
||
notGranted: "Разрешение на использование микрофона еще не получено.",
|
||
unexpectedState: "Неожиданное состояние разрешения микрофона:{{state}}.",
|
||
statusApiUnavailable:
|
||
"API состояния микрофона недоступен в этой среде выполнения. Используйте Запрос, чтобы проверить доступ.",
|
||
queryFailed: "Не удалось запросить статус микрофона:{{message}}.",
|
||
captureUnavailable: "В этой среде захват микрофона недоступен.",
|
||
permissionApiUnavailable:
|
||
"API статуса разрешения недоступен. Используйте Запрос, чтобы проверить доступ.",
|
||
requestsWebOnly: "Запросы настольного микрофона доступны только в веб- среде выполнения.",
|
||
captureApiUnavailable: "API захвата микрофона недоступен в этой среде.",
|
||
requestDenied:
|
||
"Разрешение на использование микрофона было отклонено пользователем или системой.",
|
||
noDevice: "Микрофонное устройство не обнаружено.",
|
||
requestFailed: "Не удалось запросить разрешение микрофона:{{message}}.",
|
||
},
|
||
empty: {
|
||
notifications: "Статус уведомления еще не проверен.",
|
||
microphone: "Состояние микрофона еще не проверялось.",
|
||
},
|
||
testNotification: {
|
||
title: "Тест уведомлений Paseo",
|
||
body: "Если вы это видите, уведомления на рабочем столе работают.",
|
||
notDelivered:
|
||
"Уведомление не было доставлено. Проверьте Системные настройки > Уведомления.",
|
||
failed: "Не удалось отправить уведомление.",
|
||
},
|
||
},
|
||
integrations: {
|
||
cli: {
|
||
statusFailed: "Невозможно проверить статус установки CLI.",
|
||
installFailed: "Невозможно установить PaseoCLI.",
|
||
},
|
||
},
|
||
},
|
||
rootError: {
|
||
title: "В Paseo возникла проблема.",
|
||
body: "Попробуйте снова перезагрузить приложение. Если это повторяется, приложите приведенные ниже подробности к отчету.",
|
||
details: "Подробности",
|
||
},
|
||
startup: {
|
||
errorTitle: "Что- то пошло не так",
|
||
errorDescription:
|
||
"Локальный сервер не удалось запустить. Если это повторяется, сообщите о проблеме на GitHub и приложите журналы ниже.",
|
||
logs: {
|
||
loading: "Загрузка журналов демона...",
|
||
unavailable: "Журналы демона отсутствуют.",
|
||
loadFailed: "Невозможно загрузить журналы демона:{{message}}",
|
||
},
|
||
},
|
||
openProject: {
|
||
tiles: {
|
||
addProject: {
|
||
title: "Добавить проект",
|
||
description: "Откройте папку на своем компьютере",
|
||
},
|
||
importSession: {
|
||
title: "Импортировать сеанс",
|
||
description: "Добавьте последние внешние сеансы CLI.",
|
||
},
|
||
setupProviders: {
|
||
title: "Поставщики установки",
|
||
description: "Настройте Claude Code,Codex и другие",
|
||
},
|
||
pairDevice: {
|
||
title: "Сопряжение устройства",
|
||
description: "Подключите свой телефон к этому демону",
|
||
},
|
||
},
|
||
},
|
||
projectPicker: {
|
||
placeholder: "Введите текст для поиска...",
|
||
browse: "Обзор…",
|
||
opening: "Открытие проекта...",
|
||
searching: "Идет поиск...",
|
||
empty: "Начните вводить путь",
|
||
errors: {
|
||
directory_not_found: "Каталог не найден.",
|
||
open_failed: "Не удалось открыть проект.",
|
||
},
|
||
openPath: "Открыть путь",
|
||
},
|
||
branchSwitcher: {
|
||
triggerTooltip: "Переключить ветку рабочего пространства",
|
||
currentBranch: "Текущая ветка:{{branchName}}. Нажмите, чтобы переключить ветку.",
|
||
placeholder: "Сменить ветку...",
|
||
searchPlaceholder: "Фильтровать ветки...",
|
||
empty: "Филиалов не найдено.",
|
||
title: "Переключить ветку",
|
||
uncommittedTitle: "Незафиксированные изменения",
|
||
uncommittedMessage:
|
||
"У вас есть незафиксированные изменения. Спрятать их перед переключением веток?",
|
||
stashAndSwitch: "Тайник и переключатель",
|
||
failedToStash: "Не удалось сохранить изменения.",
|
||
failedToSwitch: "Не удалось переключить ветку",
|
||
restoreStashTitle: "Восстановить спрятанные изменения?",
|
||
restoreStashMessage:
|
||
"В этой ветке сохранены изменения с предыдущего сеанса. Хотели бы вы их восстановить?",
|
||
restore: "Восстановить",
|
||
later: "Позже",
|
||
stashRestored: "Спрятанные изменения восстановлены.",
|
||
},
|
||
agentAutocomplete: {
|
||
searchingWorkspace: "Ищем рабочее место...",
|
||
loadingCommands: "Загрузка команд...",
|
||
noFiles: "Файлы и каталоги не найдены",
|
||
noCommands: "Команды не найдены",
|
||
failedToLoad: "Не удалось загрузить",
|
||
},
|
||
loadOlderHistory: {
|
||
failed: "Не удалось загрузить старую историю.",
|
||
},
|
||
imageAttachmentPicker: {
|
||
permissionTitle: "Требуется разрешение",
|
||
permissionMessage:
|
||
"Пожалуйста, разрешите доступ к вашей библиотеке фотографий, чтобы прикреплять изображения.",
|
||
errorTitle: "Ошибка",
|
||
failedToSelect: "Не удалось выбрать изображение",
|
||
dialogTitle: "Прикрепите изображения",
|
||
dialogFilterName: "Изображения",
|
||
},
|
||
workspaceSetup: {
|
||
title: "Создать рабочую область",
|
||
errors: {
|
||
failedCreateWorktree: "Не удалось создать рабочее дерево.",
|
||
failedOpenProject: "Не удалось открыть проект",
|
||
selectModel: "Выберите модель",
|
||
hostDisconnected: "Host не подключен",
|
||
pendingRequired: "Никакой настройки рабочей области не ожидается.",
|
||
composerStateRequired: "Требуется состояние композитора настройки Workspace.",
|
||
},
|
||
},
|
||
onboarding: {
|
||
title: "Добро пожаловать в Paseo",
|
||
subtitle: "Подключите компьютер, чтобы начать",
|
||
actions: {
|
||
settings: "Настройки",
|
||
},
|
||
},
|
||
modelSelector: {
|
||
title: "Выберите провайдера",
|
||
selectModel: "Выберите модель",
|
||
selectedModel: "Выберите модель ({{model}})",
|
||
loading: "Загрузка...",
|
||
loadingShort: "Загрузка",
|
||
loadingSelector: "Загрузка выбора модели...",
|
||
error: "Ошибка",
|
||
defaultModel: "По умолчанию",
|
||
profiles: "Профили",
|
||
providers: "Провайдеры",
|
||
model: "Модель",
|
||
editProfiles: "Изменить",
|
||
editProfilesLabel: "Изменить профили агентов",
|
||
createProfile: "Создать профиль",
|
||
modelCount: "{{count}} модель",
|
||
modelCountPlural: "{{count}} моделей",
|
||
retry: "Повторить попытку",
|
||
retrying: "Повторная попытка...",
|
||
noMatches: "Ни одна модель не соответствует вашему запросу",
|
||
noMatchesForQuery: "Нет моделей, соответствующих «{{query}}»",
|
||
searchAllPlaceholder: "Поиск по всем моделям...",
|
||
searchPlaceholder: "Поиск моделей...",
|
||
openProviderSettings: "Открыть настройки{{provider}}",
|
||
},
|
||
providerCatalog: {
|
||
title: "Добавить провайдера",
|
||
search: "Поиск поставщиков",
|
||
noProviders: "Поставщики не найдены",
|
||
actions: {
|
||
add: "Добавлять",
|
||
adding: "Добавление",
|
||
installed: "Установлено",
|
||
cancel: "Отмена",
|
||
installInstructions: "Инструкции по установке",
|
||
installInstructionsFor: "Инструкция по установке{{provider}}",
|
||
},
|
||
errors: {
|
||
unableToInstall: "Невозможно установить провайдера",
|
||
},
|
||
},
|
||
providerSelection: {
|
||
defaultModel: "По умолчанию",
|
||
selectModel: "Выберите модель",
|
||
loading: "Загрузка...",
|
||
error: "Ошибка",
|
||
unavailable: "Недоступно",
|
||
unknownError: "Неизвестная ошибка",
|
||
readiness: {
|
||
initialPromptRequired: "Требуется начальное приглашение",
|
||
noProviders: "На выбранном хосте нет доступных провайдеров",
|
||
modelDefaultsLoading: "Настройки модели по умолчанию все еще загружаются",
|
||
noModelAvailable: "Для выбранного поставщика модель недоступна.",
|
||
workspaceDirectoryNotFound: "Каталог Workspace не найден",
|
||
hostDisconnected: "Host не подключен",
|
||
},
|
||
},
|
||
pairing: {
|
||
connectionMethods: {
|
||
title: "Добавить соединение",
|
||
direct: {
|
||
title: "Прямое подключение",
|
||
description: "Локальная сеть или VPN.",
|
||
},
|
||
scanQr: {
|
||
title: "Сканировать код QR",
|
||
description: "Зашифрованное релейное соединение.",
|
||
},
|
||
pasteLink: {
|
||
title: "Вставьте ссылку на сопряжение",
|
||
description: "Зашифрованное релейное соединение.",
|
||
},
|
||
},
|
||
direct: {
|
||
title: "Прямое подключение",
|
||
helper: "Введите адрес сервера Paseo.",
|
||
fields: {
|
||
host: "Host",
|
||
port: "Порт",
|
||
password: "Пароль",
|
||
optional: "Необязательный",
|
||
useSsl: "Использовать SSL",
|
||
connectionUri: "URI подключения",
|
||
},
|
||
advanced: {
|
||
label: "Передовой",
|
||
show: "Показать расширенные",
|
||
hide: "Скрыть расширенные",
|
||
},
|
||
passwordVisibility: {
|
||
show: "Показать пароль",
|
||
hide: "Скрыть пароль",
|
||
},
|
||
actions: {
|
||
cancel: "Отмена",
|
||
connect: "Соединять",
|
||
connecting: "Подключение...",
|
||
},
|
||
errors: {
|
||
hostRequired: "Требуется Host",
|
||
invalidPort: "Порт должен быть в диапазоне от 1 до 65535.",
|
||
invalidConnection: "Неверное соединение",
|
||
failedTitle: "Соединение не удалось",
|
||
failedToConnect: "Нам не удалось подключиться к{{endpoint}}.",
|
||
noAdditionalDetails: "{{detail}}(дополнительная информация не предоставлена)",
|
||
timedOut: "Время подключения истекло. Проверьте хост /port и вашу сеть.",
|
||
refused: "В соединении отказано. Сервер работает по этому адресу?",
|
||
hostNotFound: "Host не найден. Проверьте имя хоста и повторите попытку.",
|
||
hostUnreachable: "Host недоступен. Проверьте свою сеть и брандмауэр.",
|
||
tlsError:
|
||
"Ошибка TLS. Прямые соединения используют SSL только тогда, когда перед демоном находится терминатор TLS.",
|
||
unableToConnect:
|
||
"Не удалось подключиться. Проверьте хост /port и убедитесь, что демон доступен.",
|
||
details: "Подробности:{{detail}}",
|
||
},
|
||
},
|
||
link: {
|
||
title: "Вставьте ссылку на сопряжение",
|
||
helper: "Вставьте ссылку на сопряжение с вашего сервера.",
|
||
label: "Ссылка на сопряжение",
|
||
errors: {
|
||
required: "Вставьте ссылку для сопряжения (.../#offer=...)",
|
||
missingOffer: "Ссылка должна содержать #offer=...",
|
||
emptyOffer: "Полезная нагрузка предложения пуста.",
|
||
invalid: "Неверная ссылка для сопряжения",
|
||
unableToPair: "Невозможно подключить хост",
|
||
},
|
||
alert: {
|
||
failedTitle: "Сопряжение не удалось",
|
||
},
|
||
actions: {
|
||
cancel: "Отмена",
|
||
pair: "Пара",
|
||
pairing: "Сопряжение...",
|
||
},
|
||
},
|
||
scan: {
|
||
title: "Сканировать QR",
|
||
webUnavailableTitle: "Недоступно в Интернете",
|
||
webUnavailableBody:
|
||
"Сканирование QR не поддерживается в веб- сборке. Вместо этого используйте «Вставить ссылку».",
|
||
backToSettings: "Вернуться к настройкам",
|
||
cameraPermissionTitle: "Разрешение камеры",
|
||
cameraPermissionBody:
|
||
"Разрешите камере доступ к сканированию кода сопряжения QR с вашего демона.",
|
||
grantPermission: "Предоставить разрешение",
|
||
pairing: "Сопряжение...",
|
||
unableToPair: "Невозможно подключить хост",
|
||
errorTitle: "Ошибка",
|
||
},
|
||
device: {
|
||
loadingOffer: "Загрузка предложения по сопряжению...",
|
||
failedToLoadOffer: "Не удалось загрузить предложение сопряжения.",
|
||
relayDisabled: "Реле не включено. Включите реле для сопряжения устройства.",
|
||
enableTitle: "Включить реле?",
|
||
enableDescription:
|
||
"Реле позволяет подключаться с этого устройства откуда угодно. Трафик сопряжения защищён сквозным шифрованием.",
|
||
relayDocs: "Как работает реле",
|
||
relayDocsAccessibility: "Прочитать, как работает реле Paseo",
|
||
enableRelay: "Включить реле",
|
||
enablingRelay: "Включение...",
|
||
notNow: "Не сейчас",
|
||
directConnectionHint:
|
||
"Без реле подключайтесь напрямую через TCP, Tailscale или другую VPN. QR-код не создаётся.",
|
||
updateRequired: "Обновите хост, чтобы включить реле из Paseo Desktop.",
|
||
unavailable: "Предложение по сопряжению недоступно.",
|
||
hint: "Отсканируйте этот код QR с помощью Paseo на своем телефоне или скопируйте ссылку ниже.",
|
||
qrUnavailable: "Код QR недоступен.",
|
||
qrAccessibility: "QR-код сопряжения",
|
||
retry: "Повторить попытку",
|
||
copy: "Копировать",
|
||
copied: "Скопировано",
|
||
},
|
||
},
|
||
realtimeVoice: {
|
||
actions: {
|
||
mute: "Отключить звук в реальном времени",
|
||
unmute: "Включить звук голоса в реальном времени",
|
||
stop: "Остановить голос в реальном времени и прервать поворот",
|
||
},
|
||
},
|
||
rewind: {
|
||
tooltip: "Перемотка назад к этому сообщению",
|
||
warning: "Это действие нельзя отменить.",
|
||
actions: {
|
||
conversation: "Перемотать разговор назад",
|
||
files: "Перемотка файлов",
|
||
both: "Перемотка разговора и файлов назад",
|
||
},
|
||
errors: {
|
||
failed: "Не удалось перемотать агент",
|
||
},
|
||
},
|
||
diffViewer: {
|
||
empty: "Нет изменений для отображения",
|
||
},
|
||
serviceUrl: {
|
||
title: "Открыть сервис URL",
|
||
message: "Открыть{{url}}?",
|
||
inPaseo: "В Paseo",
|
||
externalBrowser: "Внешний браузер",
|
||
dontAskAgain: "Не спрашивай больше",
|
||
},
|
||
downloads: {
|
||
requestTokenFailed: "Не удалось запросить токен загрузки.",
|
||
hostUnavailable: "Хост загрузки недоступен.",
|
||
cancelled: "Загрузка отменена.",
|
||
failed: "Не удалось загрузить файл.",
|
||
shareFile: "Поделиться файлом",
|
||
shareFileNamed: "Поделиться {{fileName}}",
|
||
},
|
||
menu: {
|
||
backdrop: "Фон меню",
|
||
},
|
||
subagents: {
|
||
title: "Субагенты",
|
||
pillLabelOne: "1 субагент",
|
||
pillLabelMany: "{{count}} субагентов",
|
||
pillLabelRunning: "{{count}} в работе",
|
||
pillLabelFailed: "{{count}} с ошибкой",
|
||
pillLabelNeedsInputOne: "1 ожидает ввода",
|
||
pillLabelNeedsInputMany: "{{count}} ожидают ввода",
|
||
pillLabelReadyToReview: "{{count}} на проверку",
|
||
detachAction: "Отсоединить {{label}}",
|
||
detachTooltip: "Отсоединить субагент",
|
||
archiveAction: "Архив{{label}}",
|
||
archiveTooltip: "Архивный субагент",
|
||
archiveFinishedAction: "Архивировать завершенные субагенты",
|
||
archiveFinishedRetry: "Повторить ({{failed}}/{{total}})",
|
||
},
|
||
panels: {
|
||
draft: {
|
||
newAgent: "Новый агент",
|
||
creatingAgent: "Создание агента",
|
||
},
|
||
file: {
|
||
directoryMissing: "Каталог Workspace не найден.",
|
||
loading: "Загрузка файла...",
|
||
noPreview: "Предварительный просмотр недоступен",
|
||
binaryPreviewUnavailable: "Предварительный просмотр двоичного файла недоступен.",
|
||
failedToLoad: "Не удалось загрузить файл",
|
||
failedToLoadPreview: "Не удалось загрузить предварительный просмотр файла.",
|
||
editor: {
|
||
fileSize: "Размер файла {{size}}",
|
||
lines: "Строк: {{count}}",
|
||
editorStatus: "Состояние редактора: {{status}}",
|
||
unsavedChanges: "Несохранённые изменения",
|
||
saving: "Сохранение...",
|
||
saveFailed: "Не удалось сохранить",
|
||
changedOnDisk: "Изменён на диске",
|
||
vimMode: "Режим Vim {{mode}}",
|
||
cursor: "Строка {{line}}, столбец {{column}}",
|
||
preview: "Просмотр",
|
||
source: "Исходник",
|
||
deletedTitle: "Файл удалён с диска",
|
||
checkFailedTitle: "Не удалось проверить файл на диске",
|
||
preservedDescription: "Открытая копия сохранена.",
|
||
conflictDescription: "Локальный буфер сохранён. Выберите версию, которую нужно оставить.",
|
||
overwrite: "Перезаписать",
|
||
reload: "Перезагрузить",
|
||
reloadTitle: "Перезагрузить с диска?",
|
||
reloadMessage: "Локальные изменения будут потеряны.",
|
||
},
|
||
},
|
||
files: {
|
||
label: "Файлы",
|
||
subtitle: "Файлы рабочего пространства",
|
||
tooltip: "Просмотр файлов рабочего пространства",
|
||
},
|
||
pullRequest: {
|
||
label: "Запрос на слияние",
|
||
subtitle: "Сведения о запросе на слияние",
|
||
emptyTitle: "Запроса на слияние пока нет",
|
||
emptyDescription:
|
||
"Создайте запрос на слияние для этой рабочей копии, чтобы увидеть здесь его сведения.",
|
||
},
|
||
diff: {
|
||
changesLabel: "Изменения",
|
||
changesSubtitle: "Различия рабочего дерева",
|
||
commitSubtitle: "Различия коммита",
|
||
uncommittedSubtitle: "Незафиксированные изменения",
|
||
baseSubtitle: "Сравнение с {{baseRef}}",
|
||
directoryMissing: "Каталог Workspace не найден.",
|
||
empty: "Нет изменений",
|
||
loadError: "Не удалось загрузить различия",
|
||
capabilityMissing: "Обновите хост, чтобы просматривать различия коммитов.",
|
||
},
|
||
},
|
||
toolCallDetails: {
|
||
error: "Ошибка",
|
||
empty: "Дополнительные сведения отсутствуют",
|
||
subAgentActivity: "Субагентская деятельность",
|
||
input: "Вход",
|
||
output: "Выход",
|
||
},
|
||
toolCallGroup: {
|
||
editedFiles: {
|
||
one: "изменён {{count}} файл",
|
||
other: "изменено {{count}} файлов",
|
||
},
|
||
commands: {
|
||
one: "выполнена {{count}} команда",
|
||
other: "выполнено {{count}} команд",
|
||
},
|
||
readFiles: {
|
||
one: "прочитан {{count}} файл",
|
||
other: "прочитано {{count}} файлов",
|
||
},
|
||
searches: {
|
||
one: "выполнен {{count}} поиск",
|
||
other: "выполнено {{count}} поисков",
|
||
},
|
||
otherTools: {
|
||
one: "использован {{count}} другой инструмент",
|
||
other: "использовано {{count}} других инструментов",
|
||
},
|
||
paseoCalls: {
|
||
one: "Paseo вызван {{count}} раз",
|
||
other: "Paseo вызван {{count}} раз",
|
||
},
|
||
and: "и",
|
||
},
|
||
renameModal: {
|
||
rename: "Переименовать",
|
||
saving: "Сохранение...",
|
||
},
|
||
sidebarCallout: {
|
||
dismiss: "Увольнять",
|
||
},
|
||
contextWindow: {
|
||
title: "Контекстное окно",
|
||
used: "{{percentage}}% использовано",
|
||
tokens: "Токены{{used}}/{{max}}",
|
||
sessionCost: "Стоимость сеанса{{cost}}",
|
||
accessibility: "Контекстное окно{{percentage}}% использовано",
|
||
},
|
||
review: {
|
||
comment: {
|
||
add: "Добавить комментарий к обзору",
|
||
edit: "Изменить комментарий к отзыву",
|
||
delete: "Удалить комментарий к отзыву",
|
||
label: "Посмотреть комментарий",
|
||
placeholder: "Оставить комментарий",
|
||
cancel: "Отмена",
|
||
cancelAccessibility: "Отменить комментарий к отзыву",
|
||
save: "Комментарий",
|
||
saveAccessibility: "Сохранить комментарий к отзыву",
|
||
},
|
||
},
|
||
settings: {
|
||
title: "Настройки",
|
||
loading: "Загрузка настроек...",
|
||
groups: {
|
||
app: "Приложение",
|
||
host: "Host",
|
||
},
|
||
hostPicker: {
|
||
switchHost: "Сменить хост",
|
||
local: "Местный",
|
||
},
|
||
backToWorkspace: "Назад",
|
||
addHost: "Добавить хост",
|
||
enableBuiltInDaemon: "Включить встроенный демон",
|
||
projects: "Проекты",
|
||
projectList: {
|
||
hostLoadFailed: "Не удалось загрузить проекты с хоста{{hostName}}:{{message}}.",
|
||
editProject: "Изменить{{projectName}}",
|
||
},
|
||
groupInfo: "О{{title}}",
|
||
sections: {
|
||
general: "Общий",
|
||
appearance: "Появление",
|
||
editor: "Редактор",
|
||
shortcuts: "Ярлыки",
|
||
integrations: "Интеграции",
|
||
notifications: "Уведомления",
|
||
permissions: "Разрешения",
|
||
diagnostics: "Диагностика",
|
||
about: "О",
|
||
},
|
||
editor: {
|
||
title: "Редактор",
|
||
vimKeybindings: "Клавиши Vim",
|
||
vimHint: "Применяется к исходным файлам в веб- и настольной версии.",
|
||
},
|
||
notifications: {
|
||
title: "Уведомления",
|
||
permission: "Разрешение на уведомления",
|
||
refreshAccessibility: "Обновить разрешение на уведомления",
|
||
playSound: "Воспроизводить звук",
|
||
playSoundHint: "Воспроизводит звук при получении уведомления на компьютере",
|
||
test: "Проверить уведомление",
|
||
testHint: "Отправляет уведомление с текущими настройками",
|
||
permissionRequired: "Разрешите доступ к уведомлениям перед проверкой",
|
||
send: "Отправить",
|
||
sending: "Отправка...",
|
||
sentTitle: "Тестовое уведомление отправлено",
|
||
sentDescription: "Paseo передал уведомление операционной системе.",
|
||
sendFailedTitle: "Не удалось отправить тестовое уведомление",
|
||
},
|
||
hostSections: {
|
||
projects: "Проекты",
|
||
connections: "Соединения",
|
||
agents: "Agents",
|
||
metadata: "Метаданные",
|
||
workspaces: "Workspaces",
|
||
providers: "Провайдеры",
|
||
usage: "Использование",
|
||
terminals: "Terminals",
|
||
plugins: "Plugins",
|
||
host: "Обзор",
|
||
},
|
||
plugins: pluginSettings.ru,
|
||
metadataGeneration: {
|
||
title: "Создание метаданных",
|
||
description:
|
||
"Выберите модель, которую Paseo использует для названий рабочих пространств, веток, сообщений коммитов и черновиков pull request",
|
||
selection: "Выбор модели",
|
||
automatic: "Автоматически",
|
||
preferred: "Вручную",
|
||
automaticHint: "Paseo выбирает быструю доступную модель",
|
||
preferredHint: "Выберите модель, которую использует Paseo",
|
||
model: "Модель",
|
||
fallbackHint: "Если она недоступна, Paseo использует другую доступную модель",
|
||
docs: "Документация",
|
||
saveError: "Не удалось обновить создание метаданных",
|
||
},
|
||
general: {
|
||
title: "Общий",
|
||
browserData: {
|
||
title: "Данные браузера",
|
||
siteData: "Файлы cookie и данные сайтов",
|
||
description: "Вкладки браузера используют общие данные входа и данные сайтов в Paseo.",
|
||
clear: "Очистить данные браузера",
|
||
clearing: "Очистка...",
|
||
confirmTitle: "Очистить данные браузера?",
|
||
confirmMessage:
|
||
"На сайтах будет выполнен выход, а открытые вкладки браузера перезагрузятся.",
|
||
success: "Данные браузера очищены.",
|
||
error: "Не удалось очистить данные браузера.",
|
||
},
|
||
defaultSend: {
|
||
label: "Отправка по умолчанию",
|
||
descriptions: {
|
||
interrupt: "Когда агент работает, Enter прерывает. Command/Ctrl+Enter ставит в очередь.",
|
||
steer:
|
||
"Когда агент работает, Enter направляет текущий ход. Command/Ctrl+Enter ставит в очередь.",
|
||
queue: "Когда агент работает, Enter ставит в очередь. Command/Ctrl+Enter отправляет.",
|
||
},
|
||
options: {
|
||
interrupt: "Прерывать",
|
||
steer: "Направить",
|
||
queue: "Очередь",
|
||
},
|
||
},
|
||
serviceUrls: {
|
||
label: "URL- адреса служб",
|
||
description: "Где открыть URL- адреса запущенных скриптов",
|
||
options: {
|
||
ask: "Просить",
|
||
inApp: "В Paseo",
|
||
external: "Внешний браузер",
|
||
},
|
||
},
|
||
terminalScrollback: {
|
||
label: "Terminal прокрутка назад",
|
||
description: "Строки, хранящиеся во встроенном буфере терминала.",
|
||
accessibilityLabel: "Линии прокрутки Terminal",
|
||
},
|
||
autoExpandReasoning: {
|
||
label: "Всегда разворачивать размышления",
|
||
description:
|
||
"По умолчанию показывать блоки размышлений и логики агента полностью развернутыми",
|
||
},
|
||
toolCallDetail: {
|
||
label: "Отображение вызовов инструментов",
|
||
description: "Как вызовы инструментов отображаются на временной шкале",
|
||
accessibilityLabel: "Выбрать отображение вызовов инструментов ({{value}})",
|
||
options: {
|
||
overview: "Сводка",
|
||
detailed: "Полная детализация",
|
||
},
|
||
},
|
||
language: {
|
||
label: "Язык",
|
||
description: "Язык приложения",
|
||
options: {
|
||
system: "Система",
|
||
ar: "العربية",
|
||
en: "English",
|
||
es: "Español",
|
||
fr: "Français",
|
||
ja: "日本語",
|
||
ko: "한국어",
|
||
ptBR: "Português brasileiro",
|
||
ru: "Русский",
|
||
zhCN: "中文",
|
||
},
|
||
},
|
||
},
|
||
diagnostics: {
|
||
title: "Диагностика",
|
||
legacyTerminalRenderer: {
|
||
label: "Использовать прежний рендерер терминала",
|
||
description: "Использовать прежний WebView-терминал после повторного открытия",
|
||
accessibilityLabel: "Использовать прежний рендерер терминала",
|
||
},
|
||
testAudio: "Тестирование звука",
|
||
playTest: "Игровой тест",
|
||
playing: "Игра...",
|
||
playbackFailed: "Ошибка воспроизведения:{{message}}",
|
||
app: {
|
||
title: "App diagnostic",
|
||
rowTitle: "App diagnostic",
|
||
rowHint: "Collect connection, daemon, provider, desktop, and log details",
|
||
run: "Run",
|
||
running: "Running diagnostic...",
|
||
copyLabel: "diagnostic",
|
||
copyAccessibility: "Copy diagnostic",
|
||
copyFailed: "Failed to copy diagnostic",
|
||
refreshAccessibility: "Refresh diagnostic",
|
||
refreshingAccessibility: "Refreshing diagnostic",
|
||
progress: {
|
||
client: "Client",
|
||
desktop: "Desktop",
|
||
},
|
||
},
|
||
},
|
||
about: {
|
||
title: "О",
|
||
appVersion: "Версия приложения",
|
||
thisDevice: "Это устройство",
|
||
connectedHosts: "Подключенные хосты",
|
||
offline: "Оффлайн",
|
||
versionDiffers: "Версия отличается от этого устройства",
|
||
releaseChannel: {
|
||
label: "Канал выпуска",
|
||
description:
|
||
"Перейдите на Beta, чтобы получать обновления раньше и помогать их формировать.",
|
||
stable: "Stable",
|
||
beta: "Beta",
|
||
},
|
||
updates: {
|
||
label: "Обновления приложений",
|
||
readyToInstall: "Готово к установке:{{version}}",
|
||
installTitle: "Установить обновление рабочего стола",
|
||
installMessage: "Это обновит Paseo на этом компьютере.",
|
||
installConfirm: "Установить обновление",
|
||
update: "Обновлять",
|
||
updateTo: "Обновление до{{version}}",
|
||
installing: "Установка...",
|
||
check: "Проверять",
|
||
checking: "Проверка...",
|
||
alertTitle: "Ошибка",
|
||
alertMessage: "Невозможно открыть диалоговое окно подтверждения обновления.",
|
||
},
|
||
},
|
||
appearance: {
|
||
theme: {
|
||
title: "Тема",
|
||
accessibilityLabel: "Тема:{{value}}",
|
||
options: {
|
||
light: "Свет",
|
||
dark: "Темный",
|
||
zinc: "Цинк",
|
||
midnight: "Полночь",
|
||
claude: "Клод",
|
||
ghostty: "Призрачный",
|
||
pureBlack: "Чистый чёрный",
|
||
auto: "Система",
|
||
},
|
||
},
|
||
detailLevel: {
|
||
title: "Уровень детализации",
|
||
},
|
||
chatOutline: {
|
||
title: "Структура чата",
|
||
description: "Показывать структуру для перехода между запросами",
|
||
},
|
||
fonts: {
|
||
title: "Шрифты",
|
||
systemDefault: "Система по умолчанию",
|
||
interfaceFont: "Шрифт интерфейса",
|
||
interfaceFontHint:
|
||
"Используется во всем приложении. Оставьте пустым для системного значения по умолчанию.",
|
||
interfaceFontAccessibility: "Семейство интерфейсных шрифтов",
|
||
baseSize: "Базовый размер",
|
||
baseSizeAccessibility: "Базовый размер шрифта",
|
||
codeFont: "Шрифт кода",
|
||
codeFontHint:
|
||
"Используется в коде, различиях и выводе терминала. Оставьте пустым для системного значения по умолчанию.",
|
||
codeFontAccessibility: "Семейство шрифтов кода",
|
||
codeSize: "Размер кода",
|
||
codeSizeAccessibility: "Размер шрифта кода",
|
||
},
|
||
syntax: {
|
||
title: "Синтаксис",
|
||
highlightTheme: "Выделить тему",
|
||
highlightThemeHint: "Цвета кода независимо от темы приложения",
|
||
highlightThemeAccessibility: "Выделить тему:{{value}}",
|
||
previewAccessibility:
|
||
"Предварительный просмотр темы синтаксиса и шрифта кода в реальном времени.",
|
||
},
|
||
},
|
||
shortcuts: {
|
||
dialogTitle: "Ярлыки",
|
||
searchPlaceholder: "Поиск сочетаний клавиш",
|
||
unavailableOnMobile: "Сочетания клавиш доступны только на рабочем столе.",
|
||
capturePrompt: "Нажмите ярлык...",
|
||
unassigned: "Не задано",
|
||
actions: {
|
||
menu: "Действия для {{name}}",
|
||
done: "Сделанный",
|
||
cancel: "Отмена",
|
||
bind: "Привязать",
|
||
rebind: "Перепривязка",
|
||
clear: "Очистить",
|
||
reset: "Сбросить к значению по умолчанию",
|
||
resetAll: "Сбросить все",
|
||
},
|
||
sections: {
|
||
general: "Общие",
|
||
workspaces: "Проекты и рабочие пространства",
|
||
tabsPanes: "Вкладки и панели",
|
||
layout: "Макет",
|
||
agentInput: "Вход Agent",
|
||
},
|
||
help: {
|
||
openProject: "Открыть проект",
|
||
newWorkspace: "Новое рабочее пространство",
|
||
newWorktree: "Новое рабочее дерево",
|
||
archiveWorkspace: "Архивировать рабочее пространство",
|
||
newTab: "Новая вкладка",
|
||
closeCurrentTab: "Закрыть текущую вкладку",
|
||
jumpToWorkspace: "Перейти в рабочую область",
|
||
jumpToTab: "Перейти на вкладку",
|
||
previousWorkspace: "Предыдущая рабочая область",
|
||
nextWorkspace: "Следующая рабочая область",
|
||
previousTab: "Предыдущая вкладка",
|
||
nextTab: "Следующая вкладка",
|
||
splitPaneRight: "Разделить панель справа",
|
||
splitPaneDown: "Разделить панель вниз",
|
||
focusPaneLeft: "Панель фокусировки слева",
|
||
focusPaneRight: "Панель фокусировки справа",
|
||
focusPaneUp: "Панель фокусировки вверх",
|
||
focusPaneDown: "Панель фокусировки вниз",
|
||
moveTabLeft: "Переместить вкладку влево",
|
||
moveTabRight: "Переместить вкладку вправо",
|
||
moveTabUp: "Переместить вкладку вверх",
|
||
moveTabDown: "Переместить вкладку вниз",
|
||
closePane: "Закрыть панель",
|
||
newTerminal: "Новый терминал",
|
||
searchFiles: "Поиск файлов",
|
||
toggleCommandCenter: "Переключить командный центр",
|
||
showKeyboardShortcuts: "Показать сочетания клавиш",
|
||
toggleLeftSidebar: "Переключить левую боковую панель",
|
||
toggleRightSidebar: "Переключить правую боковую панель",
|
||
toggleBothSidebars: "Переключить обе боковые панели",
|
||
toggleSettings: "Переключить настройки",
|
||
toggleFocusMode: "Переключить режим фокусировки",
|
||
toggleExplorerPaneMaximization: "Переключить разворачивание панели Проводника",
|
||
cycleTheme: "Циклическая тема",
|
||
focusMessageInput: "Фокус ввода сообщения",
|
||
cycleAgentMode: "Переключить режим агента",
|
||
toggleVoiceMode: "Переключить голосовой режим",
|
||
startStopDictation: "Начать диктовку /stop",
|
||
interruptAgent: "Агент прерываний",
|
||
sendMessage: "Отправить сообщение",
|
||
queueMessage: "Сообщение в очереди",
|
||
muteUnmuteVoiceMode: "Отключить голосовой режим /unmute",
|
||
switchProject: "Сменить проект",
|
||
},
|
||
helpNotes: {
|
||
showKeyboardShortcuts: "Доступно, когда фокус находится не в текстовом поле или терминале.",
|
||
},
|
||
},
|
||
integrations: {
|
||
title: "Интеграции",
|
||
docs: {
|
||
cli: "Документация CLI",
|
||
openCli: "Открыть документацию CLI",
|
||
},
|
||
commandLine: {
|
||
title: "Командная строка",
|
||
description: "Агенты управления и сценариев с вашего терминала",
|
||
},
|
||
actions: {
|
||
install: "Установить",
|
||
installing: "Установка...",
|
||
installed: "Установлено",
|
||
},
|
||
},
|
||
permissions: {
|
||
title: "Разрешения",
|
||
microphone: "Микрофон",
|
||
refresh: "Обновить",
|
||
refreshing: "Освежающий...",
|
||
refreshAccessibility: "Обновить разрешения рабочего стола",
|
||
actions: {
|
||
granted: "Предоставленный",
|
||
request: "Запрос",
|
||
requesting: "Запрос...",
|
||
},
|
||
},
|
||
host: {
|
||
appearance: {
|
||
title: "Оформление",
|
||
name: {
|
||
label: "Имя",
|
||
},
|
||
color: {
|
||
label: "Цвет",
|
||
accessibilityLabel: "Цвет, {{value}}",
|
||
options: {
|
||
none: "По умолчанию",
|
||
violet: "Фиолетовый",
|
||
sky: "Небесный",
|
||
emerald: "Изумрудный",
|
||
orange: "Оранжевый",
|
||
pink: "Розовый",
|
||
indigo: "Индиго",
|
||
teal: "Бирюзовый",
|
||
red: "Красный",
|
||
amber: "Янтарный",
|
||
blue: "Синий",
|
||
},
|
||
},
|
||
badge: {
|
||
label: "Значок на боковой панели",
|
||
accessibilityLabel: "Значок на боковой панели, {{value}}",
|
||
options: {
|
||
name: "Имя",
|
||
icon: "Только значок",
|
||
hidden: "Скрыт",
|
||
},
|
||
},
|
||
preview: {
|
||
workspaceName: "my-workspace",
|
||
},
|
||
},
|
||
notFound: "Host не найден",
|
||
badges: {
|
||
relay: "Реле",
|
||
local: "Местный",
|
||
},
|
||
connections: {
|
||
title: "Соединения",
|
||
removeTitle: "Удалить соединение",
|
||
removeMessage: "Удалить{{name}}? Это невозможно отменить.",
|
||
removeAction: "Удалять",
|
||
removeErrorTitle: "Ошибка",
|
||
removeErrorMessage: "Невозможно удалить соединение",
|
||
timeout: "Тайм- аут",
|
||
},
|
||
pairDevices: {
|
||
title: "Сопряжение устройств",
|
||
rowTitle: "Сопряжение устройства",
|
||
rowHint:
|
||
"Отсканируйте код QR или скопируйте ссылку, чтобы подключить свой телефон к этому хосту.",
|
||
},
|
||
skills: {
|
||
...en.settings.host.skills,
|
||
sectionTitle: "Навыки оркестровки",
|
||
title: "Навыки оркестровки",
|
||
description: "Научите своих агентов организовывать работу через CLI",
|
||
updateAvailable: "Доступно обновление",
|
||
updateTitle: "Обновить навыки Paseo?",
|
||
updateFallback: "Синхронизируйте связанные навыки с вашим компьютером.",
|
||
uninstallTitle: "Удалить навыки Paseo?",
|
||
uninstallMessage: "Удаляет все навыки оркестровки Paseo из ~/.agents, ~/.claude, ~/.codex.",
|
||
choose: "Выбрать навыки",
|
||
chooseAll: "Все навыки",
|
||
chooseAllHint: "Держите установленными все входящие навыки, включая добавленные позже.",
|
||
chooseList: "Входящие навыки",
|
||
chooseEmpty: "В этой сборке нет навыков.",
|
||
removeTitle: "Удалить снятые навыки?",
|
||
removeMessage:
|
||
"{{skills}} будут удалены из ~/.agents, ~/.claude и ~/.codex. Всё, что вы добавили внутри этих папок навыков, тоже удаляется.",
|
||
saveFailed: "Не удалось сохранить выбор навыков.",
|
||
statusFailed: "Невозможно проверить статус навыков оркестровки.",
|
||
updateFailed: "Невозможно обновить навыки оркестровки.",
|
||
uninstallFailed: "Невозможно удалить навыки оркестровки.",
|
||
saveSelectionFailed: "Не удалось сохранить выбор навыков оркестровки.",
|
||
actions: {
|
||
install: "Установить",
|
||
installing: "Установка...",
|
||
installed: "Установлено",
|
||
update: "Обновлять",
|
||
working: "Работающий...",
|
||
remove: "Удалить",
|
||
uninstall: "Удалить",
|
||
save: "Сохранить",
|
||
saving: "Сохранение...",
|
||
cancel: "Отмена",
|
||
},
|
||
operations: {
|
||
add: "Добавить навык",
|
||
update: "Обновить навык",
|
||
delete: "Удалить навык",
|
||
},
|
||
},
|
||
orchestration: {
|
||
title: "оркестровка",
|
||
unavailable: "Подключитесь к этому хосту, чтобы управлять оркестрацией.",
|
||
enableTools: {
|
||
title: "Включить инструменты Paseo",
|
||
hint: "Агенты смогут управлять рабочими деревьями, агентами и расписаниями.",
|
||
accessibilityLabel: "Инструменты внедрения Paseo",
|
||
},
|
||
systemPrompt: {
|
||
title: "Системная подсказка",
|
||
hint: "Добавляет системное приглашение всем агентам",
|
||
sheetTitle: "Добавить системное приглашение",
|
||
accessibilityLabel: "Добавить системное приглашение",
|
||
placeholder: "Всегда отвечайте кратко.",
|
||
edit: "Редактировать",
|
||
reset: "Сбросить",
|
||
save: "Сохранить",
|
||
saving: "Сохранение...",
|
||
},
|
||
},
|
||
agents: {
|
||
unavailable: "Connect to this host to manage agents",
|
||
},
|
||
workspaces: {
|
||
unavailable: "Connect to this host to manage workspaces",
|
||
},
|
||
terminalProfiles: {
|
||
unavailable: "Connect to this host to manage terminal profiles",
|
||
sectionTitle: "Terminal profiles",
|
||
editProfile: "Edit profile",
|
||
addProfileTitle: "Add terminal profile",
|
||
editProfileTitle: "Edit terminal profile",
|
||
namePlaceholder: "Claude Code",
|
||
commandPlaceholder: "claude",
|
||
argsPlaceholder: "--dangerously-skip-permissions",
|
||
nameLabel: "Name",
|
||
commandLabel: "Command",
|
||
argsLabel: "Arguments",
|
||
nameRequired: "Name is required",
|
||
commandRequired: "Command is required",
|
||
argsHint: "Space-separated arguments passed to the command",
|
||
saving: "Saving...",
|
||
remove: "Remove",
|
||
removeConfirmTitle: "Remove profile?",
|
||
removeConfirmMessage: 'Remove "{{name}}"?',
|
||
moveUp: "Move up",
|
||
moveDown: "Move down",
|
||
save: "Save",
|
||
emptyState: "No profiles yet. Add one to launch terminals with a specific command.",
|
||
},
|
||
agentProfiles: {
|
||
sectionTitle: "Профили агента",
|
||
unavailable: "Подключитесь к этому хосту, чтобы управлять профилями агента",
|
||
unsupported: "На этом хосте работает daemon, который пока не поддерживает профили агента",
|
||
emptyState:
|
||
"Пока нет профилей. Добавьте один, чтобы запускать агентов с сохранённым провайдером и моделью.",
|
||
addProfileTitle: "Добавить профиль агента",
|
||
newProfile: "Новый профиль",
|
||
editProfile: "Изменить профиль",
|
||
editProfileTitle: "Изменить профиль агента",
|
||
nameLabel: "Имя",
|
||
namePlaceholder: "Работа над UI",
|
||
iconLabel: "Значок",
|
||
noIcon: "Нет",
|
||
providerLabel: "Провайдер",
|
||
providerPlaceholder: "Выберите провайдера",
|
||
noProviders: "На этом хосте нет доступных провайдеров",
|
||
modelLabel: "Модель",
|
||
noModels: "У этого провайдера нет моделей для выбора",
|
||
modeLabel: "Режим",
|
||
noModes: "У этого провайдера нет режимов для выбора",
|
||
thinkingLabel: "Мышление",
|
||
noThinkingOptions: "У этой модели нет уровней мышления",
|
||
featuresLabel: "Функции",
|
||
featureCount: "{{count}} функций",
|
||
featureCountOne: "{{count}} функция",
|
||
notesLabel: "Заметки для агентов",
|
||
notesPlaceholder: "Используйте для работы над UI — компоненты, макет и токены дизайна.",
|
||
notesHint:
|
||
"Возвращается инструментом MCP «list_profiles». Напишите это как инструкцию для другого агента.",
|
||
save: "Сохранить",
|
||
saving: "Сохранение...",
|
||
remove: "Удалить",
|
||
removeConfirmTitle: "Удалить профиль?",
|
||
removeConfirmMessage: "Удалить «{{name}}»?",
|
||
moveUp: "Переместить вверх",
|
||
moveDown: "Переместить вниз",
|
||
},
|
||
daemon: {
|
||
rename: {
|
||
editLabel: "Изменить ярлык",
|
||
title: "Переименовать хост",
|
||
placeholder: "Мой Host",
|
||
submit: "Переименовать",
|
||
},
|
||
restart: {
|
||
title: "Перезапустить демон",
|
||
hint: "Перезапускает процесс демона. Приложение автоматически переподключится",
|
||
confirm: "Перезапустить",
|
||
confirmTitle: "Перезапустите{{name}}",
|
||
confirmMessage:
|
||
"Это перезапустит демон. Агенты, работающие на нем, будут продолжать работать; приложение автоматически повторно подключится.",
|
||
restarting: "Перезапуск...",
|
||
unableToReconnectTitle: "Невозможно повторно подключиться",
|
||
unableToReconnectMessage:
|
||
"{{name}}не вернулся в онлайн. Пожалуйста, убедитесь, что он перезапущен.",
|
||
unavailableTitle: "Host недоступен",
|
||
unavailableMessage:
|
||
"Этот хост не подключен. Подождите, пока он подключится к сети, прежде чем перезапустить.",
|
||
offlineTitle: "Host оффлайн",
|
||
offlineMessage:
|
||
"Этот хост не в сети.Paseo автоматически повторно подключается — подождите, пока он снова подключится к сети, прежде чем перезапускаться.",
|
||
requestFailedTitle: "Ошибка",
|
||
requestFailedMessage:
|
||
"Не удалось отправить запрос на перезапуск.Paseo автоматически повторно подключается. Повторите попытку, как только хост окажется в сети.",
|
||
dialogFailedMessage: "Невозможно открыть диалоговое окно подтверждения перезапуска.",
|
||
},
|
||
update: {
|
||
desktopManagedHint:
|
||
"Этот демон управляется Paseo Desktop. Обновите Paseo Desktop на хосте.",
|
||
title: "Update daemon",
|
||
hint: "Update the daemon to the latest version and restart it",
|
||
confirm: "Update",
|
||
confirmTitle: "Update {{name}}",
|
||
confirmMessage:
|
||
"This will update the daemon to the latest version and restart it. Running agents will be briefly interrupted.",
|
||
updating: "Updating...",
|
||
phaseStarting: "Preparing update...",
|
||
phaseDownloading: "Downloading packages...",
|
||
phaseInstalling: "Installing...",
|
||
phaseComplete: "Update complete, restarting...",
|
||
unableToReconnectTitle: "Unable to reconnect",
|
||
unableToReconnectMessage:
|
||
"{{name}} did not come back online after updating. Please verify the daemon restarted.",
|
||
unavailableTitle: "Host unavailable",
|
||
unavailableMessage:
|
||
"This host is not connected. Wait for it to come online before updating.",
|
||
offlineTitle: "Host offline",
|
||
offlineMessage: "This host is offline. Wait until it is back online before updating.",
|
||
requestFailedTitle: "Update failed",
|
||
requestFailedMessage: "Failed to update the daemon: {{error}}",
|
||
dialogFailedMessage: "Unable to open the update confirmation dialog.",
|
||
},
|
||
dangerZone: "Опасная зона",
|
||
remove: {
|
||
title: "Удалить хост",
|
||
localTitle: "Remove localhost connection",
|
||
hint: "Удаляет этот хост и его сохраненные подключения с этого устройства.",
|
||
localHint: "Removes localhost from this device and stops the built-in daemon",
|
||
localConfirmTitle: "Remove localhost connection and stop daemon?",
|
||
confirmMessage: "Удалить{{name}}? Это приведет к удалению сохраненных соединений.",
|
||
localConfirmMessage:
|
||
"This will remove the localhost connection, turn off built-in daemon management, and stop the managed daemon. Remote hosts remain connected.",
|
||
errorTitle: "Ошибка",
|
||
errorMessage: "Невозможно удалить хост",
|
||
localErrorMessage: "Unable to remove localhost connection",
|
||
},
|
||
},
|
||
},
|
||
providers: {
|
||
title: "Провайдеры",
|
||
addProvider: "Добавить провайдера",
|
||
providerDetails: "Подробности о провайдере{{name}}",
|
||
enableProvider: "Включить{{name}}",
|
||
unavailable: "Подключитесь к этому хосту, чтобы увидеть поставщиков",
|
||
loading: "Загрузка...",
|
||
addErrorTitle: "Unable to add provider",
|
||
updateErrorTitle: "Невозможно обновить провайдера",
|
||
actions: {
|
||
menu: "{{name}} actions",
|
||
remove: "Remove provider",
|
||
removing: "Removing...",
|
||
},
|
||
remove: {
|
||
confirmTitle: "Remove {{name}}?",
|
||
confirmMessage: "This deletes the provider entry from config.json. It cannot be undone.",
|
||
confirm: "Remove",
|
||
errorTitle: "Unable to remove provider",
|
||
},
|
||
statuses: {
|
||
disabled: "Неполноценный",
|
||
loading: "Загрузка",
|
||
error: "Ошибка",
|
||
available: "Доступный",
|
||
notInstalled: "Не установлено",
|
||
},
|
||
models: {
|
||
one: "1 модель",
|
||
many: "{{count}} моделей",
|
||
addModel: "Добавить модель",
|
||
addCustomTitle: "Добавить пользовательскую модель",
|
||
modelId: "Модель ID",
|
||
modelIdPlaceholder: "например опенай /gpt-5",
|
||
add: "Добавлять",
|
||
adding: "Добавление...",
|
||
failedToSave: "Не удалось сохранить модель.",
|
||
removeModel: "Удалить{{id}}",
|
||
searchPlaceholder: "Поиск моделей",
|
||
loading: "Загрузка моделей...",
|
||
retry: "Повторить попытку",
|
||
retrying: "Повторная попытка...",
|
||
noSearchMatches: "Ни одна модель не соответствует вашему запросу",
|
||
noneDetected: "Модели не обнаружены",
|
||
discovered: "Обнаруженный",
|
||
custom: "Пользовательские модели",
|
||
updated: "Обновлен{{time}}",
|
||
},
|
||
diagnostic: {
|
||
title: "Диагностика",
|
||
button: "Диагностика",
|
||
refresh: "Обновить",
|
||
refreshing: "Освежающий...",
|
||
copyLabel: "диагностика",
|
||
copyAccessibility: "Скопировать диагностику",
|
||
copyFailed: "Не удалось скопировать диагностику",
|
||
refreshAccessibility: "Обновить диагностику",
|
||
refreshingAccessibility: "Обновление диагностики",
|
||
running: "Запускаю диагностику...",
|
||
none: "Диагностика недоступна",
|
||
failedToFetch: "Не удалось получить диагностику.",
|
||
unknownError: "Неизвестная ошибка",
|
||
},
|
||
},
|
||
project: {
|
||
noEditableTarget: "Этот проект нельзя редактировать на этом хосте.",
|
||
backToProjects: "Вернуться к проектам",
|
||
edit: {
|
||
title: "Изменить проект",
|
||
name: "Название",
|
||
nameLabel: "Название проекта",
|
||
icon: "Значок",
|
||
chooseImage: "Выбрать изображение",
|
||
useAutomatic: "Использовать автоматический",
|
||
imageUrl: "URL изображения или сайта",
|
||
save: "Сохранить изменения",
|
||
savedToast: "Проект обновлён",
|
||
},
|
||
readFailures: {
|
||
invalidTitle: "paseo.json не удалось разобрать",
|
||
invalidDescription: "Исправьте файл на диске, затем перезагрузите.",
|
||
missingTitle: "У этого хоста нет этого проекта",
|
||
missingSingleHost: "У выбранного хоста нет записей об этом проекте.",
|
||
transportTitle: "Не удалось загрузить paseo.json.",
|
||
transportFallback: "Хозяин не ответил.",
|
||
failedTitle: "Не удалось загрузить paseo.json.",
|
||
failedDescription: "Перезагрузите, чтобы попробовать еще раз.",
|
||
},
|
||
worktree: {
|
||
title: "Перехватчики жизненного цикла Worktree",
|
||
info: "Команды, которые выполняются при создании или удалении рабочего дерева для этого проекта.",
|
||
docs: "Документы",
|
||
docsTooltip:
|
||
"Дополнительную информацию и переменные среды, доступные для этих команд, см. в документации.",
|
||
setup: "Настраивать",
|
||
setupAccessibility: "Команды настройки рабочего дерева",
|
||
uncommittedTitle: "Закоммитьте изменения paseo.json",
|
||
uncommittedDescription:
|
||
"Новые рабочие деревья используют сценарий настройки из выбранной базовой ветки.",
|
||
teardown: "Срывать",
|
||
teardownAccessibility: "Команды разрушения рабочего дерева",
|
||
},
|
||
scripts: {
|
||
title: "Скрипты",
|
||
info: "Долгоработающие службы и одноразовые команды, которые можно запускать из любого агента в этом проекте.",
|
||
empty: "Скриптов пока нет.",
|
||
untitled: "Безымянный сценарий",
|
||
port: "порт{{port}}",
|
||
menuAccessibility: "Открыть меню скриптов",
|
||
removeTitle: "Удалить скрипт?",
|
||
removeMessage: "Удалить{{name}}?",
|
||
removeFallbackName: "этот сценарий",
|
||
name: "Имя",
|
||
command: "Команда",
|
||
nameAccessibility: "Имя сценария",
|
||
commandAccessibility: "Команда сценария",
|
||
nameRequired: "Требуется имя",
|
||
commandRequired: "Требуется команда",
|
||
newScript: "Новый сценарий",
|
||
editScript: "Изменить{{name}}",
|
||
runAsService: "Запуск как служба",
|
||
serviceHint: "Paseo контролирует процесс и назначает порт через $PASEO_PORT.",
|
||
actions: {
|
||
add: "Добавить скрипт",
|
||
edit: "Редактировать",
|
||
remove: "Удалять",
|
||
},
|
||
},
|
||
metadata: {
|
||
title: "Генерация метаданных",
|
||
info: "Инструкции для конкретного проекта, внедренные в подсказки ИИ, которые Paseo использует для генерации метаданных. Используйте их для обеспечения соблюдения соглашений вашей команды, таких как наименование ветвей, стиль фиксации или формат PR.",
|
||
branchName: "Названия ветвей",
|
||
branchNamePlaceholder: "Префиксные ветки с feat/ или fix/, mb/ для личных веток",
|
||
commitMessage: "Фиксировать сообщения",
|
||
commitMessagePlaceholder: "Используйте обычные фиксации с областью действия",
|
||
pullRequest: "Запросы на вытягивание",
|
||
pullRequestPlaceholder:
|
||
"Начните с резюме в один абзац, включая раздел «План тестирования».",
|
||
},
|
||
writeFailures: {
|
||
staleTitle: "Конфигурация изменена на диске",
|
||
staleDescription:
|
||
"Перед сохранением перезагрузите компьютер, чтобы получить последнюю версию файла paseo.json.",
|
||
failedTitle: "Не удалось сохранить paseo.json.",
|
||
failedDescription: "Попробуйте еще раз или перезагрузите последнюю версию с диска.",
|
||
},
|
||
actions: {
|
||
reload: "Перезагрузить",
|
||
tryAgain: "Попробуйте еще раз",
|
||
save: "Сохранять",
|
||
saved: "Проект сохранен.",
|
||
saving: "Сохранение...",
|
||
cancel: "Отмена",
|
||
},
|
||
},
|
||
},
|
||
};
|