From 7ceee777b48bbfa91e30b9c75e2cd1468af1ab68 Mon Sep 17 00:00:00 2001 From: HuanLinOTO Date: Sun, 23 Aug 2026 00:52:20 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat(i18n):=20=E6=8E=A5=E5=85=A5=20@huanlin?= =?UTF-8?q?/dsh-plugin-better-locale=20=E6=94=AF=E6=8C=81=20ja=20=E8=A6=86?= =?UTF-8?q?=E7=9B=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 ja 词典(src/client/locales-ja.ts,326 keys,与 zh key-set-equal), 通过可选 peer @huanlin/dsh-plugin-better-locale 接入第三语言覆盖: - locales.ts: 新增 attachBetterLocale(store) + ja dict export;t() 先查 store.getOverride(active, 'betterSidebar', key),命中则返回覆盖文本, 否则走原 zh/en 链;isZh() 在 override 激活时返回 false - client/index.tsx: apply 中 ctx.get('betterLocale') 取得 override store (optional,未安装时为 undefined),attachBetterLocale 注入 t();同时 register('betterSidebar', { ja }) 把 ja 词典注册进 better-locale 的 store,让外部 ctx.locale.lookup 调用者也能拿到 ja 文本 - Sidebar.tsx: 新增 betterLocaleActive uSES 订阅 store.subscribe,覆盖 切换时全树重渲染(DSH locale 的 active 字段不变,既有 localeRevision uSES 不会触发) - package.json: @huanlin/dsh-plugin-better-locale 加为 optional peer + devDep link - tests/locales.spec.ts: 新增 7 个 better-locale override 测试(命中/ fallback/detach/interpolate/ja dict 完整性 smoke check) 未安装 better-locale 时 ctx.get 返回 undefined,整段为 no-op,zh/en 行为完全不变。 --- AGENTS.md | 1 + README.md | 2 +- package.json | 5 + pnpm-lock.yaml | 3 + src/client/Sidebar.tsx | 31 ++++ src/client/index.tsx | 33 +++- src/client/locales-ja.ts | 345 +++++++++++++++++++++++++++++++++++++++ src/client/locales.ts | 73 ++++++++- tests/locales.spec.ts | 120 +++++++++++++- 9 files changed, 607 insertions(+), 6 deletions(-) create mode 100644 src/client/locales-ja.ts diff --git a/AGENTS.md b/AGENTS.md index 24b7a9f..aa310e3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -595,6 +595,7 @@ interface OpenTabSeed { | **id 冲突** | `registerTab` / `registerFileViewer` 对重复 id 抛错;建议用包前缀(`my-plugin:xxx`) | | **家族右面板互斥(v0.13.0+)** | 读取 `aionui-panel` 设置命名空间的 `rightPanel`:解析为 `'aionui-panel'` 时整个侧边栏不挂载(`settings.get` 路由返回 `externalDisable: true`,客户端挂载门 + 各类接管一并停用;`settings/document-updated` 推送实时生效,无 `remote` 服务的部署回退为启动时判定)。未安装 aionui 或提供方为其他值时不受影响 | | **i18n 跟随** | 侧边栏界面文案跟随 DSH 的 `ctx.locale`(`@deepseek-ai/dsh-client-locale`):词典注册在 `betterSidebar` 命名空间,语言偏好(Host-backed `locale.preference`)与浏览器语言不一致时以 DSH 为准并实时切换;locale 服务缺失时回退浏览器语言。插件自身的 `t()`(`src/client/locales.ts`)由 `apply()` 挂接服务;消费插件**不要**依赖此内部函数——标题等字段传字符串或 `() => string` 即可(i18n 友好)。⚠️ 渲染 DSH 的 `MarkdownText` 时必须传 `codeLabels={{ copyLabel: t('copy'), copiedLabel: t('copied') }}`——该组件 cordis-free,漏传则代码块复制按钮回退硬编码中文 | +| **第三语言覆盖(ja 等)** | 可选 peer `@huanlin/dsh-plugin-better-locale`(`peerDependenciesMeta.optional: true`)提供 ja/ko/... 等第三语言覆盖。安装后 `apply()` 调 `ctx.get('betterLocale')` 取得 override store 并经 `attachBetterLocale()` 注入 `t()`:`t()` 先查 `store.getOverride(active, 'betterSidebar', key)`,命中则返回覆盖文本(如 ja),否则走原 zh/en 链。Sidebar root 另订阅 store 的 `subscribe()`(uSES on `store.active`),覆盖切换时全树重渲染(DSH locale 的 `active` 字段不变,所以既有 `localeRevision` uSES 不会触发)。本插件同时把 ja 词典 `register('betterSidebar', { ja })` 进 better-locale 的 store,让外部 `ctx.locale.lookup('betterSidebar', key)` 调用者也能拿到 ja 文本。未安装 better-locale 时 `ctx.get` 返回 undefined,整段为 no-op,zh/en 行为不变。新增 zh key 时**必须**同步加 ja 翻译(`src/client/locales-ja.ts`),否则该 key 在 ja 覆盖下回退到 en | | **懒加载 chunk** | 内置重依赖(xterm/CodeMirror)在独立 bundle(`lib/client-.js`)中,经 `/sidebar/bundle` 路由按需下发;每个脚本把 factory 赋到插件自有全局注册表 `globalThis.__dshChunks__[]`,由 `src/client/chunk-loader.ts` 用自定义 require(externals 经 `__DSH_MODULES__` seed 分支解析)物化——**不经过** `__ModuleLoader__` 注册;**核心 bundle 禁止静态 import `src/client/chunks/*`**(会把库拖回启动路径);对消费插件透明——懒加载只作用于内置 descriptor,`component` 契约(`(props) => ReactNode` 纯渲染函数)不变 | --- diff --git a/README.md b/README.md index b1e0be5..f63fd8b 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ - **🔁 会话隔离**:布局 / Tab / 面板按会话持久化,陈旧状态自动净化 - **⚙️ 声明式设置**:设置页「侧边卡片」逐项独立开关,二级设置经齿轮弹窗 - **⚡ 按需加载**:启动只拉 ~325KB 核心,终端 / 编辑器 / Mermaid 图表等重依赖用到才按需拉取([设计文档](docs/plans/2026-08-12-lazy-chunks-design.md)) -- **🌏 多语言**:界面文案跟随 DSH 语言(zh / en)实时切换 +- **🌏 多语言**:界面文案跟随 DSH 语言(zh / en)实时切换;安装 `@huanlin/dsh-plugin-better-locale` 后支持日语(ja)等第三语言覆盖(见下方「🌏 第三语言覆盖」) > 🔌 **核心理念**:服务优先——内置的 7 tab + 6 viewer 与第三方插件通过同一套 `ctx.betterSidebar` API 注册,能力完全对等;官方不再内置、可由生态提供的功能,交由生态插件实现(已有 **28+ 生态插件**,见下方「🌐 插件生态」)。接入文档见「🔌 服务化扩展」与 [外部插件接入指南](./docs/external-plugin-guide.md)。 diff --git a/package.json b/package.json index a923848..5a0bb2a 100644 --- a/package.json +++ b/package.json @@ -99,6 +99,7 @@ "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@huanlin/dsh-plugin-better-locale": "^0.1.0", "cordis": "^4.0.0-rc.8", "react": "^18.2.0", "react-dom": "^18.2.0" @@ -106,6 +107,9 @@ "peerDependenciesMeta": { "cordis": { "optional": true + }, + "@huanlin/dsh-plugin-better-locale": { + "optional": true } }, "dependencies": { @@ -154,6 +158,7 @@ "@deepseek-ai/dsh-settings": "0.1.1-rc.1", "@deepseek-ai/dsh-subagent": "0.1.1-rc.1", "@deepseek-ai/dsh-tools": "0.1.1-rc.1", + "@huanlin/dsh-plugin-better-locale": "link:D:/Projects/deepseek-harness/dsh-plugin-better-locale", "@playwright/test": "^1.62.1", "@types/node": "^24.0.0", "@types/react": "~18.3.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e074cf2..16a4b8e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -141,6 +141,9 @@ importers: '@deepseek-ai/dsh-tools': specifier: 0.1.1-rc.1 version: 0.1.1-rc.1(5493e0ab460eb504a0593977b284c2a8) + '@huanlin/dsh-plugin-better-locale': + specifier: link:D:/Projects/deepseek-harness/dsh-plugin-better-locale + version: link:../dsh-plugin-better-locale '@playwright/test': specifier: ^1.62.1 version: 1.62.1 diff --git a/src/client/Sidebar.tsx b/src/client/Sidebar.tsx index 2b5be43..77efde3 100644 --- a/src/client/Sidebar.tsx +++ b/src/client/Sidebar.tsx @@ -188,6 +188,37 @@ export function Sidebar(props: { ctx: Context; store: SidebarStore }) { ) void localeRevision + // better-locale override freshness: when @huanlin/dsh-plugin-better-locale + // is installed and the user picks an override language (e.g. ja), the + // store's `active` changes but the DSH locale's `active` does NOT — + // better-locale keeps the dsh active value (zh/en) unchanged and only + // patches `LocaleRuntime.prototype.lookup`. The localeRevision uSES + // above reads `getSnapshot().active`, so it sees no change and skips + // re-render. This second uSES reads the better-locale store's `active` + // directly, so an override switch fires a full re-render and t() picks + // up the new override text. Optional: ctx.get returns undefined when + // better-locale is absent, in which case this is a no-op uSES. + type BetterLocaleStore = { + readonly active: string | undefined + subscribe(listener: () => void): () => void + } + const betterLocaleStore = (ctx as unknown as { + get(name: 'betterLocale'): BetterLocaleStore | undefined + }).get('betterLocale') + const betterLocaleActive = useSyncExternalStore( + useMemo(() => { + const store = betterLocaleStore + if (store === undefined) return (_cb: () => void) => () => {} + return (callback: () => void) => store.subscribe(callback) + }, [betterLocaleStore]), + useMemo(() => { + const store = betterLocaleStore + if (store === undefined) return () => undefined + return () => store.active + }, [betterLocaleStore]), + ) + void betterLocaleActive + // Tab-registry revision: TabContent memo cells must pick up a descriptor // a plugin registers/disposes after mount (the + menu / icons already read // the registry at render). Rare events (plugin (un)mount), so one full diff --git a/src/client/index.tsx b/src/client/index.tsx index c87fbd1..08bcc06 100644 --- a/src/client/index.tsx +++ b/src/client/index.tsx @@ -24,7 +24,7 @@ import { registerSettingsNavIcon } from './settings-nav-icon.ts' import { loadExternalDisable, loadPrefs } from './prefs.ts' import { SideCardSection } from './SideCardSection.tsx' import { api } from './api.ts' -import { LOCALE_NS, attachLocale, t, zh, en } from './locales.ts' +import { LOCALE_NS, attachLocale, attachBetterLocale, t, zh, en, ja } from './locales.ts' import css from './sidebar.module.css' import './layout.css' @@ -57,6 +57,37 @@ export function apply(ctx: Context): void { const offEn = ctx.locale.register(LOCALE_NS, 'en', en) return () => { offZh(); offEn() } }, 'dsh-better-sidebar: dictionaries') + + // Opt-in third-language support through @huanlin/dsh-plugin-better-locale. + // When that plugin is installed, it publishes `ctx.betterLocale` (the + // override store) and patches LocaleRuntime.prototype.lookup to consult + // it. We mirror the same override awareness into the sidebar's own `t()`: + // attachBetterLocale() makes t() consult the store's getOverride first, + // so the sidebar's chrome (which bypasses ctx.locale and calls t() + // directly) also switches to the override language. We also register + // the ja dict with the better-locale store so external callers of + // ctx.locale.lookup('betterSidebar', key) get the override text too. + // Optional peer: ctx.get returns undefined when better-locale is absent, + // in which case the whole block is a no-op and the zh/en chain runs. + const betterLocale = ctx.get('betterLocale') as + | { + readonly active: string | undefined + getOverride(dshActive: string, ns: string, key: string): string | undefined + register(ns: string, dicts: Record>): () => void + subscribe(listener: () => void): () => void + } + | undefined + attachBetterLocale(betterLocale) + if (betterLocale !== undefined) { + ctx.effect(() => { + // Register the ja dict for the betterSidebar namespace. Better-locale's + // patched lookup consults this when the user has selected the ja + // override; the dict stays owned by better-sidebar (the namespace + // owner), so a single source of truth covers both ctx.locale callers + // and the internal t(). + return betterLocale.register(LOCALE_NS, { ja }) + }, 'dsh-better-sidebar: better-locale ja dict') + } // One store instance per activation: production code creates it only here, // then hands it to the mounted panel and closes over it in the slot // registrations (the official createXXXStore() factory rule — no diff --git a/src/client/locales-ja.ts b/src/client/locales-ja.ts new file mode 100644 index 0000000..ec29559 --- /dev/null +++ b/src/client/locales-ja.ts @@ -0,0 +1,345 @@ +/** + * The ja (Japanese) dictionary for the betterSidebar namespace. + * + * Mirrors the key set of `zh` in `locales.ts`. The sidebar's `t()` + * consults this dict when `attachBetterLocale(store)` has been called + * with an active better-locale store whose `active` is `'ja'`; absent + * that, the existing zh/en chain runs unchanged. + * + * Translation conventions: + * - Common dev-tool loanwords stay in katakana (ターミナル, ブラウザー, サンドボックス). + * - Git vocabulary follows the GitHub Japan style guide (ステージ, コミット, ブランチ). + * - Settings labels end in する/名/方法 to mirror the zh 「…行为/方式」 cadence. + * - Placeholders keep `{name}` verbatim (interpolation runs after lookup). + * - English brand names (VS Code, Cursor, Zed, SSH) stay as-is. + */ + +/** The ja dictionary (key-set-equal to zh, enforced by the type annotation in locales.ts). */ +export const ja: Record = { + files: 'ファイル', + explorer: 'エクスプローラー', + git: 'ソース管理', + terminal: 'ターミナル', + editor: 'エディター', + editorExplorer: 'ファイルの開き方', + editorExplorerDesc: 'ファイルを開く方法を制御', + editorExplorerMerged: '統合', + editorExplorerMergedDesc: '同じウィンドウ内でファイルを切り替え。新しいウィンドウはファイルツューを展開した状態で開く', + editorExplorerSplit: '個別', + editorExplorerSplitDesc: 'パスなしウィンドウはエクスプローラー単体(ツリーのみ)。各ファイルは別ウィンドウで開く(ツリーは格納済み、デフォルトで折りたたみ)', + editorTreeToggle: 'ファイルツリーパネル', + editorPathPlaceholder: 'ファイルパス(セッションディレクトリからの相対 or 絶対)、Enter で開く', + editorSearchPlaceholder: 'ファイル名で検索…', + editorSearchNoResults: '一致するファイルはありません', + editorSearchTruncated: '結果が多すぎます — 一部のみ表示', + editorEmptyHint: '右のファイルツリーまたは上のパス入力欄からファイルを選んでプレビュー', + openFileNewTab: '新しいタブで開く', + openFileSide: '横に開く', + openWithMenu: 'アプリで開く', + openWithSshSuffix: ' (SSH)', + pinOpenWith: 'メニューに固定', + unpinOpenWith: '固定を解除', + openWithExplorer: 'エクスプローラー', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'SSH リモートホスト', + openWithSettingsSshDesc: '空欄 = ローカルワークスペース。user@host または SSH エイリアスを入力すると、VSCode 系の起動方法は vscode-remote/ssh-remote プロトコルに切り替わり、エクスプローラー / Zed / 非 VSCode 系カスタムエディターはメニューから非表示になります', + openWithSettingsSshPlaceholder: 'user@host または SSH エイリアス', + openWithSettingsCustomTitle: 'カスタムエディター', + openWithSettingsCustomDesc: '名前 + URL テンプレート({path} プレースホルダー)+ VSCode 系かどうか。SSH モードでは VSCode 系のみリモートパスを開けます', + openWithSettingsAdd: '追加', + openWithSettingsName: '名前', + openWithSettingsTemplate: '例: cursor://file/{path}', + openWithSettingsFamily: 'VSCode 系', + openWithSettingsFamilyDesc: 'このエディターは VSCode の URL プロトコルを使います(SSH リモートオープンをサポート)', + openWithSettingsRemove: '削除', + openWithSettingsInvalidHint: '名前またはテンプレート({path} を含み scheme:// で始まる必要あり)が未入力の編集者はメニューに表示されません', + newTab: '新しいタブ', + openExplorer: 'エクスプローラー', + brokenSymlink: '無効なシンボリックリンク', + openGit: 'Git パネル', + newTerminal: '新しいターミナル', + terminalLimit: 'ターミナル数が上限に達しました (3)', + close: '閉じる', + closeOtherTabs: '他のタブを閉じる', + closeLeftTabs: '左のタブを閉じる', + closeRightTabs: '右のタブを閉じる', + collapse: 'サイドバーを折りたたむ', + expand: 'サイドバーを展開', + collapseBottomPanel: '下パネルを折りたたむ', + expandBottomPanel: '下パネルを展開', + terminalError: 'ターミナル接続に失敗', + terminalConnectFailed: 'ターミナル接続が繰り返し失敗しました', + terminalRetry: '再試行', + terminalDepsFailed: 'ターミナル依存関係 node-pty の読み込みに失敗', + terminalDepsHint: 'DSH 環境のターミナルまたは cmd で以下のコマンドを実行して修復し、再試行してください(node-pty は DSH コアと同じバージョンを維持):', + terminalDepsProfile: '(検出された profile:{profile})', + preview: 'プレビュー', + edit: '編集', + mermaidError: 'Mermaid レンダリング失敗', + mermaidZoomIn: '拡大', + mermaidZoomOut: '縮小', + mermaidZoomReset: 'リセット', + mermaidZoomHint: 'スクロールで拡大 ・ ドラッグで移動 ・ Esc で閉じる', + refresh: '更新', + save: '保存', + saved: '保存済み', + unsaved: '未保存', + saveFailed: '保存に失敗', + truncation: 'ファイルが大きすぎます — 最初の 512KB のみ表示', + binary: 'バイナリファイル、プレビュー不可', + loading: '読み込み中…', + error: '読み込みに失敗', + retry: '再試行', + splitLeft: '左に分割', + splitRight: '右に分割', + splitUp: '上に分割', + splitDown: '下に分割', + notRepo: 'このディレクトリは git リポジトリではありません', + noChanges: '変更はありません', + stage: 'ステージ', + unstage: 'ステージ解除', + stageAll: 'すべてステージ', + unstageAll: 'すべてステージ解除', + commitPlaceholder: 'コミットメッセージ (Ctrl+Enter)', + commit: 'コミット', + commitError: 'コミット失敗', + branch: 'ブランチ', + checkoutError: 'ブランチ切り替えに失敗', + history: '履歴', + changes: '変更', + staged: 'ステージ済み', + unstaged: '未ステージ', + cancel: 'キャンセル', + diffEmpty: 'テキスト差分はありません', + diffLoadError: '差分の読み込みに失敗', + diffBinary: 'バイナリ', + diffAdded: '追加', + diffDeleted: '削除', + diffRenamed: '名前変更', + diffExpand: '残り {count} 行を展開', + diffCollapse: '折りたたむ', + discard: '変更を破棄', + discardTitle: '変更を破棄', + discardDesc: '「{path}」のワークツリー変更を破棄します(復元不可)。', + viewCommitDiff: 'コミット差分を表示', + copyShortHash: '短いハッシュをコピー', + copyFullHash: '完全なハッシュをコピー', + copySubject: 'コミットメッセージをコピー', + revertCommit: 'このコミットを取り消す', + revertTitle: 'このコミットを取り消す', + revertDesc: '現在のブランチに「{subject}」を取り消す新しいコミットを作成します。', + cherryPickCommit: 'このコミットをチェリーピック', + cherryPickTitle: 'このコミットをチェリーピック', + cherryPickDesc: '「{subject}」の変更を現在のブランチに適用します。', + timeJustNow: 'たった今', + timeMinutesAgo: '{n} 分前', + timeHoursAgo: '{n} 時間前', + timeYesterday: '昨日', + loadMore: 'もっと読み込む', + historyLoadError: '履歴の追加読み込みに失敗', + produced: '今回の産物', + producedOpen: 'サイドバーで開く', + disconnected: 'ターミナル接続が切れました、再接続中…', + exited: 'ターミナルプロセスが終了しました', + noSession: 'サイドバーを使うには会話を選択してください', + pluginNotLoaded: 'プラグイン未読み込み、タブは一時的に利用不可:', + hiddenFiles: '隠しファイル', + parent: '上位ディレクトリ', + copied: 'コピーしました', + copy: 'コピー', + newFile: '新規ファイル', + openEditor: 'エディターで開く', + gitDetail: '変更詳細を表示', + referenceFile: '@ファイル', + addToConversation: '会話に追加', + copyRelative: '相対パスをコピー', + copyAbsolute: '絶対パスをコピー', + download: 'ダウンロード', + uploadFiles: 'ファイルをアップロード', + uploadFolder: 'フォルダーをアップロード', + uploadHere: 'ここにアップロード', + uploadDropHint: 'ファイル/フォルダーをここにドロップしてアップロード', + uploadDropChat: 'チャットにドロップで画像を会話に追加', + uploadTo: '{dir} にアップロード', + uploadingTo: '{dir} にアップロード中…', + uploadProgress: 'アップロード中 {done}/{total}: {name}', + uploadDone: '{count} 個のファイルをアップロードしました', + uploadFailed: 'アップロード失敗:{error}', + uploadFailedUnknown: '不明なエラー', + uploadTooLarge: 'ファイルが大きすぎます(アップロード上限超過)', + uploadCancelled: 'アップロードはキャンセルされました', + settingsNav: 'サイドカード', + settingsIntro: 'サイドカードの表示内容とデフォルト挙動を管理', + settingsPopupDesc: '「{feature}」の関連オプションを設定', + settingsDone: '完了', + settingsOpenTitle: '新規会話でデフォルト展開', + settingsOpenDesc: '新規会話時にサイドカードを自動展開。既存の会話はそれぞれのレイアウトを維持', + settingsWidthTitle: 'デフォルト幅の比率', + settingsWidthDesc: '新規会話時のサイドカードがウィンドウ幅に占める割合 (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: 'チャット内ファイルをサイドバーで開く', + settingsOpenPathDesc: 'チャット内のファイルリンク(ツール行、産物リスト、ファイル言及)クリック時に、システム既定アプリではなくサイドバーエディターで開く', + settingsTitleBarTitle: '位置互換モード', + settingsTitleBarDesc: 'タイトルバー互換スキームを選択:自動検出(デフォルト、控えめ)/ DSH 公式 Web / 既知のデスクトップシェル / カスタムスキーム(下移動距離 + カスタム CSS)', + settingsTitleBarStripTitle: '下移動距離', + settingsTitleBarStripDesc: 'タイトルバー帯の高さ:サイドバーボタンとコンテンツが下に移動するピクセル数 (0–120、デフォルト 40。カスタムスキーム下で有効)', + settingsSchemeAutoTitle: '自動検出', + settingsSchemeAutoDesc: '控えめなスキーム:Window Controls Overlay 標準 API が利用可能な場合のみ実際のタイトルバー高さ分譲る。通常の Web 環境では何も変更しない', + settingsSchemeWebTitle: 'DSH 公式 Web', + settingsSchemeWebDesc: '公式 Web 版で動いていることを明示:一切適用しない(標準 WCO 幾何も適用外)', + settingsSchemeCustomTitle: 'カスタム', + settingsSchemeCustomDesc: '完全に制御:カスタム CSS を注入(内置スタイルも上書き可)し、タイトルバーの下移動距離を指定', + settingsSchemeDetectedSuffix: '検出済み', + settingsCustomCssTitle: 'カスタム CSS', + settingsCustomCssDesc: 'ページ末尾に追加されるスタイル(同優先度では後勝ち。JS 起点のインライン変数を上書きするには !important を使用)', + settingsCustomCssPlaceholder: '/* 例:自描きタイトルバーのシェルに 36px を予約 */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: '保存に失敗', + settingsConflict: '設定が別のウィンドウで変更されました、再試行してください', + binaryNoPreview: 'このファイル形式はプレビューできません', + downloadToView: 'ダウンロードして表示', + settingsSubagentTitle: 'サブエージェント検出時に自動展開', + settingsSubagentDesc: '現在の会話で新しいサブエージェントが発生した際、サイドバーを自動展開してタスク管理ページを開く。オフ時は手動で開く必要あり', + settingsJobsTitle: '新規バックグラウンドタスク時に自動展開', + settingsJobsDesc: '現在の会話で新しいバックグラウンドタスクが発生するたびにサイドバーを展開してタスクページを開く(新規タスクごとに発火)。オフ時は手動で開く必要あり', + settingsToolsTitle: 'モデルにターミナルツールを注入', + settingsToolsDesc: 'オンにすると、モデルが terminal_create 等 8 個のツールでサイドバーターミナルを作成・操作可能(デフォルトオフ)', + settingsBottomTerminalTitle: '下パネル初回展開時に自動でターミナルを開く', + settingsBottomTerminalDesc: '会話ごとに下パネルを初めて展開した際、下パネルに新しいターミナルタブを自動で開く(ターミナル数上限は依然適用。デフォルトオン)', + settingsFontFamilyTitle: 'ターミナルフォント', + settingsFontFamilyDesc: 'ターミナルのカスタムフォントファミリー(CSS font-family、例: "JetBrains Mono", monospace。空欄でテーマの等幅フォントに追従)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: 'ターミナルフォントサイズ', + settingsFontSizeDesc: 'ターミナルのフォントサイズ (px、9–32、デフォルト 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'シェルパス', + settingsShellDesc: 'UI とモデルのターミナルが起動するシェル(絶対パス or 実行ファイル名)。空欄時は従来順で解決: yaml の config.shell → $SHELL / ログインシェル / Windows の powershell.exe。以降に開くターミナルに適用', + settingsShellPlaceholder: '例: /bin/zsh(空欄で自動解決)', + settingsShellArgsTitle: 'シェル引数', + settingsShellArgsDesc: '明示的なシェル起動引数(スペース区切り)。非空の場合デフォルト引数を完全に置き換え(yaml の shellArgs 契約と同じ)', + settingsShellArgsPlaceholder: '例: -l(空欄でデフォルト引数)', + settingsTabsTitle: 'サイドバーの内容', + settingsViewersTitle: 'ファイルプレビュー', + settingsGeneralTitle: '一般', + settingsPopup: '機能設定', + settingsViewerCatchAll: 'フォールバック:任意のファイル', + viewerImage: '画像', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: 'コード', + viewerBinary: 'バイナリダウンロード', + viewerHtml: 'HTML', + browser: 'ブラウザー', + browserPlaceholder: 'URL を入力、例: example.com', + browserGo: '開く', + browserBack: '戻る', + browserForward: '進む', + browserStart: 'URL を入力してブラウズ開始(サンドボックスモード)', + browserBlockedScheme: 'ブロック:http/https リンクのみ許可', + browserBlockedLoopback: 'ブロック:ローカルや内部アドレスはブラウズできません', + browserInvalid: '無効な URL', + browserNoSandboxWarning: 'サンドボックスオフ:現在のページは GUI と同一オリジンで、完全な会話権限を持ちます(設定で復元可)', + htmlNoSandboxWarning: 'サンドボックスオフ:この HTML は GUI と同一オリジンで、会話ファイルや内部 API を読み取れます(設定で復元可)', + sandboxStatusOn: 'サンドボックスモード:オン ・ ページは GUI のデータやローカルファイルにアクセス不可。ログイン状態とサードパーティ Cookie は利用できない場合あり', + sandboxUnlock: '一時的に解除(非安全)', + sandboxRestore: 'サンドボックスを復元', + settingsHtmlDefaultUnsafeTitle: 'HTML プレビューをデフォルトで非サンドボックスで開く(非安全)', + settingsHtmlDefaultUnsafeDesc: 'オンにすると、新しく開く HTML プレビューは非サンドボックス状態で起動(GUI と同一オリジン、会話ファイルや内部 API を読み取り可)。ステータス行から一時的にサンドボックスを復元可能', + settingsHtmlSandboxTitle: 'HTML プレビューのサンドボックスを無効化(非安全)', + settingsHtmlSandboxDesc: 'サンドボックスをオフにすると、プレビューされる HTML は GUI と同一オリジンで動作し、会話ファイル・ローカルストレージ・内部 API にアクセス可能。完全に信頼できるファイルのみで有効化', + settingsBrowserSandboxTitle: 'ブラウザーサンドボックスを無効化(非安全)', + settingsBrowserSandboxDesc: 'サンドボックスをオフにすると、訪問するあらゆるサイトが GUI と同一オリジンで動作し、会話データを読み取ったりログイン状態を偽装したりできます。完全に信頼できるサイトのみで有効化', + settingsBrowserLinksTitle: 'チャット内の外部リンクをサイドバーで開く', + settingsBrowserLinksDesc: 'オンにすると、チャットや GUI の外部リンククリック時に新しいウィンドウではなくサイドバーで開く。HTTP と HTTPS は下のスイッチで個別制御。Ctrl/Cmd+クリックで一時的にバイパス', + settingsBrowserHttpTitle: 'HTTP ページをサイドバーで開く', + settingsBrowserHttpDesc: 'オンにすると、チャットや GUI の HTTP 外部リンククリック時にサイドバーで開く(urlTarget を宣言したプラグインページが優先)。Ctrl/Cmd+クリックで一時的にバイパス', + settingsBrowserHttpsTitle: 'HTTPS ページをサイドバーで開く', + settingsBrowserHttpsDesc: 'オンにすると、チャットや GUI の HTTPS 外部リンククリック時にサイドバーで開く。デフォルトオフ:大半の HTTPS サイトは埋め込みを拒否するため、システムブラウザーの方がスムーズ', + browserOpenExternal: 'ブラウザーで開く', + browserEmbedBlocked: '{host} は埋め込みを拒否しました', + browserEmbedBlockedDesc: 'このサイトは X-Frame-Options / frame-ancestors で他ページ内での表示を禁止しているため、サイドバー内で読み込めません。ブラウザーで直接開いてください', + browserEmbedAnyway: 'それでも読み込む', + subagent: 'タスク管理', + openSubagent: 'タスク管理', + subagentMainAgent: 'メインエージェント', + subagentEmpty: 'サブエージェントなし', + subagentEmptyDesc: 'メインエージェントが派生したサブエージェントはここに表示されます', + subagentRunning: '実行中', + subagentInactive: 'アイドル', + subagentModeOneShot: 'ワンショット', + subagentModeContinuable: '継続可', + subagentCount: '{count} 個のサブエージェント', + subagentCountRunning: '{count} 個のサブエージェント ・ {running} 個実行中', + subagentDiagCorrupt: 'ディレクトリ破損', + subagentDiagUnsupported: '未サポートのエントリ', + subagentDiagUnavailable: '利用不可', + subagentThinking: '思考中…', + sideChat: 'サイドチャット(beta)', + sideChatNew: '新規スレッド', + sideChatUntitled: '新規スレッド', + sideChatEmpty: 'サイド会話なし', + sideChatEmptyDesc: '各サイド会話はタブバーの独立 Tab で、現在の会話のコンテキストを継承し、メイン会話には入りません', + sideChatCreating: 'サイド会話を作成中…', + sideChatRetry: '再試行', + sideChatThreads: 'スレッド切替 / 新規', + sideChatSave: '新規会話として保存', + sideChatSaveTitle: 'このスレッドをトップレベルの会話に昇格、メイン会話リストに表示', + sideChatSaved: '新規会話として保存しました', + sideChatNoTurn: '最初のターンを完了してから保存可能', + sideChatPendingDrop: '最後の未回答フォローアップは保存される会話に含まれません', + sideChatFirstPlaceholder: '最初の質問を入力、コンテキスト継承済み…', + sideChatComposerPlaceholder: 'フォローアップを質問…', + sideChatThinking: '深掘り中…', + sideChatThink: '思考プロセス', + sideChatInjection: 'コンテキスト注入済み', + sideChatSend: '送信', + sideChatCancel: '停止', + sideChatCancelTitle: '現在のターンを中止(キューは保持)', + sideChatClose: 'スレッドを閉じる', + sideChatCloseTitle: 'スレッドの agent を解放(履歴は保持)', + sideChatError: 'サイド会話エラー:{message}', + jobs: 'バックグラウンドタスク', + jobsCount: '{count} 個のバックグラウンドタスク', + jobsCountRunning: '{count} 個のバックグラウンドタスク ・ {running} 個実行中', + jobStatusRunning: '実行中', + jobStatusStopping: '停止中', + jobStatusCompleted: '完了', + jobStatusKilled: '終了', + jobStatusFailed: '失敗', + jobDurationSeconds: '{seconds} 秒', + jobDurationMinutes: '{minutes} 分 {seconds} 秒', + jobDurationHours: '{hours} 時間 {minutes} 分', + jobViewOutput: '出力を表示', + jobHideOutput: '出力を隠す', + jobNoOutput: 'まだ出力なし', + jobNotReadYet: 'モデルがこのタスクの出力を読み取るのを待機中(モデルが job_output を実行すると、出力がここに表示されます)', + jobOutputTruncated: '出力が長すぎるため表示を切り詰めました', + jobOutputError: '出力の読み取りに失敗', + jobKill: '終了', + jobKillConfirm: 'もう一度クリックして終了を確認', + jobKillError: '終了に失敗', + addPluginsTabCard: 'Tab プラグインを追加', + addPluginsTabCardDesc: '新しいサイドバーページを登録', + addPluginsViewerCard: 'プレビュープラグインを追加', + addPluginsViewerCardDesc: '新しいファイル種別プレビューを登録', + addPluginsTabDesc: 'サイドバーページ(Tab)はプラグインで拡張可能。プラグインは ctx.betterSidebar サービス経由で登録。「インストール」をクリックしてインストールコマンドをコピー、DSH 環境のターミナルに貼り付けて実行。', + addPluginsViewerDesc: 'ファイルプレビューアーはプラグインで拡張可能。プラグインは ctx.betterSidebar サービス経由で登録。「インストール」をクリックしてインストールコマンドをコピー、DSH 環境のターミナルに貼り付けて実行。', + addPluginsBrowseMore: 'GitHub でプラグинをさらに閲覧(topic: dsh-better-sidebar)', + addPluginsSearch: 'プラグイン名 / 説明で検索…', + addPluginsNoMatch: '一致するプラグインなし', + addPluginsRecommended: '推奨プラグイン', + addPluginsEmpty: 'まだプラグインが収録されていません、GitHub topic であなたのプラグインを公開してください', + openPlugin: '開く', + copyInstall: 'インストールコマンドをコピー', + pluginOfficeDesc: 'better-sidebar エディター向け Office スイートプレビュー(.docx / .xlsx / .pptx)。重い Office レンダリングライブラリをコアバンドルから分離、必要に応じてインストール', + pluginFlowglassDesc: 'ライブセッションフローグラフ:ユーザー、アシスタント、ツール呼び出しの 3 レーン泳道、並列グループ、サブエージェント支線、ドリルダウン、ライブ状態をサポート。better-sidebar インストール時にネイティブ「Flowglass」Tab を登録、未インストール時は独立ドロワーを保持', + pluginGitForgeDesc: 'better-sidebar「Git Forge」Tab:GitHub/Gitea 等 Forge アカウントライブラリ + プロジェクト単位の認可 + push ポリシー硬核拒絶。token はローカル secrets のみ、モデルコンテキストに入らない。読み取り専用 GitForge ツールと agent HTTPS credential helper を提供', + pluginGitRemotesDesc: 'better-sidebar Git リモート Tab:ブランチ/アップストリーム/ahead-behind 表示、fetch(prune 可)、ff-only pull、確認後のみ push。内蔵 Git のステージ/コミットは置き換えず、force-push やモデル自動 push ツールは提供しない', + pluginSentinelDesc: '条件駆動の agent 起動システム:ファイル/プロセス/ポート/HTTP/コマンド/webhook センサーが条件達成時に休眠会話を自動起動。「Sentinel」Tab を登録しサーバー全体の監視テーブルを表示', + pluginSidebarQaDesc: 'better-sidebar ベースの選択して質問 Tab:会話選択 → 右パネルで質問 → 同ワークスペースの独立追問会話(❓追問・主題)。高速 no-thinking モデルが主対話コンテキストを圧縮し引用と一緒に注入、主対話を中断しない。追問はネスト、継続、アーカイブ可能', + pluginSshTunnelDesc: 'better-sidebar「SSH トンネル」Tab:複数ホストインベントリ + プロジェクト単位の認可 + 鍵のローカル保管。モデルツール SSHManager(exec/SFTP/セッション戦略)。中央対話ターミナルと双欄 SFTP', + pluginTurnReviewDesc: '「直近のターン」の diff に Approve / Request changes のヒューマンゲート。直前ターンのみ審査、会話を fork しない。ファイルをメイン会話/サブエージェント/未帰属グループ分け、ファイル単位でチェックして差し戻し + 任意コメント、ファイルをクリックするとターン開始スナップショット vs 現在の diff を先に表示。/rewind ではない', + pluginVideoPreviewDesc: 'better-sidebar エディター内で動画ファイルをインラインプレビュー(.mp4/.webm/.mov/.mkv/.avi 等)。HTTP Range (206) をサポートする専用 /video ホストルートを搭載、プログレスバードラッグ可、20MB mediaLimit 制限なし', + pluginDocsPanelDesc: 'DSH サイドバー内の「グローバルドキュメント」:任意のワークスペースから読めるグローバル Markdown ノート。リストで選んで閲覧、ホバーでアウトラインジャンプ、Chrome / VS Code で外部オープン、コードコピー。ディレクトリは設定可(デフォルト ~/.dsh/docs)', +} diff --git a/src/client/locales.ts b/src/client/locales.ts index e868552..dd22225 100644 --- a/src/client/locales.ts +++ b/src/client/locales.ts @@ -1,5 +1,5 @@ /** - * Minimal zh/en copy for the sidebar. The copy follows the DSH i18n system: + * Minimal zh/en/ja copy for the sidebar. The copy follows the DSH i18n system: * the client apply attaches the locale service (`ctx.locale`, provided by * `@deepseek-ai/dsh-client-locale`) through {@link attachLocale}, and * `t()`/`isZh()` resolve the active locale from it — the Host-backed @@ -7,6 +7,18 @@ * Without an attached service (standalone/test compositions) the browser * language is used, matching the previous behavior. The dictionaries are * also registered into the DSH locale registry under {@link LOCALE_NS}. + * + * ja (Japanese) is opt-in through `@huanlin/dsh-plugin-better-locale`: when + * that plugin is installed, the client apply also calls + * {@link attachBetterLocale} with the override store. `t()` then consults + * the store's active override id first; if it is `'ja'` (or any id whose + * dict has the requested key) the ja text wins, otherwise the existing + * zh/en chain runs unchanged. better-locale itself patches + * `LocaleRuntime.prototype.lookup` so DSH's own translate chain also + * returns ja where the `betterSidebar` namespace has a ja entry — that + * path covers external callers of `ctx.locale.bind('betterSidebar')`, + * while the override-aware `t()` here covers better-sidebar's own + * components (which bypass `ctx.locale` and call `t()` directly). */ /** The zh dictionary (also registered into the DSH locale registry under {@link LOCALE_NS}). */ @@ -675,9 +687,28 @@ export const en: Record = { */ export const LOCALE_NS = 'betterSidebar' +// The ja dictionary lives in a sibling file (326 keys) so this module +// stays readable. Type-checked against the zh key set: a missing or extra +// ja key is a compile error. +import { ja as jaDict } from './locales-ja.ts' + +/** The ja dictionary (key-set-equal to zh, enforced by the type annotation). */ +export const ja: Record = jaDict as Record + /** The DSH locale service attached by the client apply (absent → browser detection). */ let localeService: { getSnapshot(): { active: string } } | undefined +/** + * The better-locale override store attached by the client apply + * (absent → no override; the zh/en chain runs). The store's `active` + * field holds the user's chosen override id (e.g. `'ja'`); `undefined` + * means "no override, use DSH native zh/en". + */ +let betterLocaleStore: { + readonly active: string | undefined + getOverride(dshActive: string, ns: string, key: string): string | undefined +} | undefined + /** * Attach (or detach, with undefined) the DSH locale service. The sidebar * mounts its own React root outside the slot system's locale seat, so the @@ -689,6 +720,23 @@ export function attachLocale(service: { getSnapshot(): { active: string } } | un localeService = service } +/** + * Attach (or detach, with undefined) the better-locale override store. + * When attached with an active override, `t()` consults the store's + * `getOverride(active, LOCALE_NS, key)` first; if it returns a string, + * that text wins over the zh/en chain. Detaching (or the store's active + * being `undefined`) restores the zh/en chain unchanged. + * + * The Sidebar root subscribes to the store separately (see Sidebar.tsx) + * so an override change re-renders the whole tree — the locale service's + * own revision bump (which better-locale triggers via `publish(active, true)`) + * does NOT fire the existing `localeRevision` uSES because that snapshot + * reads `getSnapshot().active` (unchanged) rather than `revision`. + */ +export function attachBetterLocale(store: typeof betterLocaleStore): void { + betterLocaleStore = store +} + /** * The active locale id ('zh' | 'en'): the DSH locale service's snapshot when * attached, else the browser language. @@ -704,8 +752,24 @@ export type CopyKey = keyof typeof zh /** Translate a copy key; `{name}` placeholders interpolate from `params`. */ export function t(key: CopyKey, params?: Record): string { - const dict = activeLocale().toLowerCase().startsWith('zh') ? zh : en - let text = dict[key] + // 1. better-locale override (e.g. ja) wins when an override is active + // and the store has a translation for this (ns, key). The DSH active + // locale is forwarded for forward compatibility (a future mode could + // gate overrides on DSH being 'en'); the current store ignores it. + const dshActive = localeService?.getSnapshot().active ?? '' + const override = betterLocaleStore?.getOverride(dshActive, LOCALE_NS, key) + let text: string | undefined = override + // 2. Fall back to the zh/en chain when no override matched. + if (text === undefined) { + const dict = activeLocale().toLowerCase().startsWith('zh') ? zh : en + text = dict[key] + } + if (text === undefined) { + // Key missing from every dict (should not happen — zh is the source of + // truth and en/ja are checked against it). Return the key itself so the + // UI shows something identifiable rather than `undefined`. + text = key + } if (params !== undefined) { for (const [name, value] of Object.entries(params)) { text = text.replaceAll(`{${name}}`, String(value)) @@ -716,6 +780,9 @@ export function t(key: CopyKey, params?: Record): strin /** Whether the active locale is Chinese (used for selectors). */ export function isZh(): boolean { + // An active override is not Chinese — short-circuit so selectors pick + // the non-zh branch (e.g. date format, pluralization). + if (betterLocaleStore?.active !== undefined) return false return activeLocale().toLowerCase().startsWith('zh') } diff --git a/tests/locales.spec.ts b/tests/locales.spec.ts index 06f763a..8ec9d7d 100644 --- a/tests/locales.spec.ts +++ b/tests/locales.spec.ts @@ -6,7 +6,7 @@ * interpolation. */ import { afterEach, describe, expect, it } from 'vitest' -import { LOCALE_NS, attachLocale, en, isZh, relativeTime, t, zh } from '../src/client/locales.ts' +import { LOCALE_NS, attachBetterLocale, attachLocale, en, isZh, ja, relativeTime, t, zh } from '../src/client/locales.ts' /** Minimal structural fake of the DSH LocaleService face the sidebar uses. */ class FakeLocale { @@ -35,6 +35,7 @@ function stubNavigatorLanguage(lang: string | undefined): void { afterEach(() => { attachLocale(undefined) + attachBetterLocale(undefined) stubNavigatorLanguage(undefined) }) @@ -106,4 +107,121 @@ describe('locales (DSH i18n following)', () => { it('keeps the zh and en dictionaries key-set-equal', () => { expect(Object.keys(en).sort()).toEqual(Object.keys(zh).sort()) }) + + it('keeps the ja dictionary key-set-equal to zh', () => { + expect(Object.keys(ja).sort()).toEqual(Object.keys(zh).sort()) + }) +}) + +/** Minimal fake of the better-locale override store (the subset t() reads). */ +class FakeBetterLocale { + active: string | undefined = undefined + private readonly dict: Record>> + constructor(dict: Record>>) { + this.dict = dict + } + getOverride(_dshActive: string, ns: string, key: string): string | undefined { + if (this.active === undefined) return undefined + return this.dict[ns]?.[this.active]?.[key] + } + subscribe(_listener: () => void): () => void { + return () => {} + } +} + +describe('locales (better-locale override)', () => { + it('returns the override text when an override is active and the key exists', () => { + const locale = new FakeLocale() + locale.switchTo('en') + attachLocale(locale) + + const betterLocale = new FakeBetterLocale({ + [LOCALE_NS]: { ja: { explorer: 'エクスプローラー' } }, + }) + betterLocale.active = 'ja' + attachBetterLocale(betterLocale) + + expect(t('explorer')).toBe('エクスプローラー') + expect(isZh()).toBe(false) + }) + + it('falls back to the zh/en chain when override is active but the key is missing', () => { + const locale = new FakeLocale() + locale.switchTo('en') + attachLocale(locale) + + const betterLocale = new FakeBetterLocale({ + [LOCALE_NS]: { ja: { explorer: 'エクスプローラー' } }, + }) + betterLocale.active = 'ja' + attachBetterLocale(betterLocale) + + // 'git' has no ja entry in this fake; should fall back to the en text. + expect(t('git')).toBe('Source Control') + }) + + it('falls back to the zh/en chain when no override is active', () => { + const locale = new FakeLocale() + locale.switchTo('zh') + attachLocale(locale) + + const betterLocale = new FakeBetterLocale({ + [LOCALE_NS]: { ja: { explorer: 'エクスプローラー' } }, + }) + // active is undefined — no override. + attachBetterLocale(betterLocale) + + expect(t('explorer')).toBe('资源管理器') + expect(isZh()).toBe(true) + }) + + it('returns to the zh/en chain after detaching the override store', () => { + const locale = new FakeLocale() + locale.switchTo('en') + attachLocale(locale) + + const betterLocale = new FakeBetterLocale({ + [LOCALE_NS]: { ja: { explorer: 'エクスプローラー' } }, + }) + betterLocale.active = 'ja' + attachBetterLocale(betterLocale) + expect(t('explorer')).toBe('エクスプローラー') + + attachBetterLocale(undefined) + expect(t('explorer')).toBe('Explorer') + expect(isZh()).toBe(false) + }) + + it('interpolates {name} placeholders in the override text', () => { + const locale = new FakeLocale() + locale.switchTo('en') + attachLocale(locale) + + const betterLocale = new FakeBetterLocale({ + [LOCALE_NS]: { ja: { timeMinutesAgo: '{n} 分前' } }, + }) + betterLocale.active = 'ja' + attachBetterLocale(betterLocale) + + expect(t('timeMinutesAgo', { n: 5 })).toBe('5 分前') + }) + + it('ships a ja dictionary whose every key resolves to a non-empty string', () => { + // Smoke-check the shipped ja dict: every key in zh must have a non-empty + // ja entry. This catches copy-paste mistakes where a key was added to zh + // but its ja translation was left blank or missing. + const locale = new FakeLocale() + locale.switchTo('en') + attachLocale(locale) + + const betterLocale = new FakeBetterLocale({ [LOCALE_NS]: { ja } }) + betterLocale.active = 'ja' + attachBetterLocale(betterLocale) + + for (const key of Object.keys(zh) as (keyof typeof zh)[]) { + const text = t(key) + expect(text, `ja translation for "${key}"`).toBeTruthy() + expect(text, `ja translation for "${key}"`).not.toBe(key) + } + }) }) From 38dc807d153599e641c89355549e0ceeae1b7f74 Mon Sep 17 00:00:00 2001 From: HuanLinOTO Date: Sun, 23 Aug 2026 01:42:01 +0800 Subject: [PATCH 2/6] =?UTF-8?q?refactor(i18n):=20=E8=A6=86=E7=9B=96?= =?UTF-8?q?=E5=8F=AA=E5=9C=A8=20DSH=20active=3Den=20=E6=97=B6=E7=94=9F?= =?UTF-8?q?=E6=95=88=EF=BC=88=E5=80=9F=E7=94=A8=E8=8B=B1=E6=96=87=E6=A7=BD?= =?UTF-8?q?=E4=BD=8D=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit better-locale 的覆盖本质上是借用 DSH 的英文槽位来渲染第三语言: - store.getOverride(dshActive, ns, key) 改为只在 dshActive === 'en' 时返回覆盖文本;DSH 在 zh 下覆盖完全惰性(保持原生 zh) - 新增 store.isOverrideActive(dshActive):返回 active !== undefined && dshActive === 'en',供 better-sidebar 的 isZh() 判断 - isZh() 改用 isOverrideActive(dshActive) 判断(仅在 DSH=en 且有 override 时返回 false),zh 下返回 true - LanguageSwitcher 接收 dshActive prop,选了非 native 且 DSH 非 en 时显示「请将 DSH 切换到英文以查看 [语言名]」提示 - 新增 switchToEnHint copy key(zh + en) - 测试:better-locale +3 store tests(en-only / inert on zh / isOverrideActive),+1 patch test(inert on zh);better-sidebar +1 locales test(override inert while DSH on zh),FakeBetterLocale 加 isOverrideActive 方法 --- AGENTS.md | 2 +- src/client/index.tsx | 1 + src/client/locales.ts | 25 +++++++++++++++++++------ tests/locales.spec.ts | 25 +++++++++++++++++++++++-- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index aa310e3..a9b3836 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -595,7 +595,7 @@ interface OpenTabSeed { | **id 冲突** | `registerTab` / `registerFileViewer` 对重复 id 抛错;建议用包前缀(`my-plugin:xxx`) | | **家族右面板互斥(v0.13.0+)** | 读取 `aionui-panel` 设置命名空间的 `rightPanel`:解析为 `'aionui-panel'` 时整个侧边栏不挂载(`settings.get` 路由返回 `externalDisable: true`,客户端挂载门 + 各类接管一并停用;`settings/document-updated` 推送实时生效,无 `remote` 服务的部署回退为启动时判定)。未安装 aionui 或提供方为其他值时不受影响 | | **i18n 跟随** | 侧边栏界面文案跟随 DSH 的 `ctx.locale`(`@deepseek-ai/dsh-client-locale`):词典注册在 `betterSidebar` 命名空间,语言偏好(Host-backed `locale.preference`)与浏览器语言不一致时以 DSH 为准并实时切换;locale 服务缺失时回退浏览器语言。插件自身的 `t()`(`src/client/locales.ts`)由 `apply()` 挂接服务;消费插件**不要**依赖此内部函数——标题等字段传字符串或 `() => string` 即可(i18n 友好)。⚠️ 渲染 DSH 的 `MarkdownText` 时必须传 `codeLabels={{ copyLabel: t('copy'), copiedLabel: t('copied') }}`——该组件 cordis-free,漏传则代码块复制按钮回退硬编码中文 | -| **第三语言覆盖(ja 等)** | 可选 peer `@huanlin/dsh-plugin-better-locale`(`peerDependenciesMeta.optional: true`)提供 ja/ko/... 等第三语言覆盖。安装后 `apply()` 调 `ctx.get('betterLocale')` 取得 override store 并经 `attachBetterLocale()` 注入 `t()`:`t()` 先查 `store.getOverride(active, 'betterSidebar', key)`,命中则返回覆盖文本(如 ja),否则走原 zh/en 链。Sidebar root 另订阅 store 的 `subscribe()`(uSES on `store.active`),覆盖切换时全树重渲染(DSH locale 的 `active` 字段不变,所以既有 `localeRevision` uSES 不会触发)。本插件同时把 ja 词典 `register('betterSidebar', { ja })` 进 better-locale 的 store,让外部 `ctx.locale.lookup('betterSidebar', key)` 调用者也能拿到 ja 文本。未安装 better-locale 时 `ctx.get` 返回 undefined,整段为 no-op,zh/en 行为不变。新增 zh key 时**必须**同步加 ja 翻译(`src/client/locales-ja.ts`),否则该 key 在 ja 覆盖下回退到 en | +| **第三语言覆盖(ja 等)** | 可选 peer `@huanlin/dsh-plugin-better-locale`(`peerDependenciesMeta.optional: true`)提供 ja/ko/... 等第三语言覆盖。覆盖**借用 DSH 的英文槽位**:`store.getOverride(dshActive, ns, key)` 只在 `dshActive === 'en'` 时返回覆盖文本,DSH 在 zh 下覆盖完全惰性(保持原生 zh)。安装后 `apply()` 调 `ctx.get('betterLocale')` 取得 override store 并经 `attachBetterLocale()` 注入 `t()`:`t()` 先查 `store.getOverride(active, 'betterSidebar', key)`,命中则返回覆盖文本(如 ja),否则走原 zh/en 链;`isZh()` 改用 `store.isOverrideActive(active)` 判断(仅在 DSH=en 且有 override 时返回 false)。Sidebar root 另订阅 store 的 `subscribe()`(uSES on `store.active`),覆盖切换时全树重渲染(DSH locale 的 `active` 字段不变,所以既有 `localeRevision` uSES 不会触发)。本插件同时把 ja 词典 `register('betterSidebar', { ja })` 进 better-locale 的 store,让外部 `ctx.locale.lookup('betterSidebar', key)` 调用者也能拿到 ja 文本。better-locale 的 LanguageSwitcher 在用户选了非 native 且 DSH 非 en 时显示「请将 DSH 切换到英文以查看 [语言名]」提示。未安装 better-locale 时 `ctx.get` 返回 undefined,整段为 no-op,zh/en 行为不变。新增 zh key 时**必须**同步加 ja 翻译(`src/client/locales-ja.ts`),否则该 key 在 ja 覆盖下回退到 en | | **懒加载 chunk** | 内置重依赖(xterm/CodeMirror)在独立 bundle(`lib/client-.js`)中,经 `/sidebar/bundle` 路由按需下发;每个脚本把 factory 赋到插件自有全局注册表 `globalThis.__dshChunks__[]`,由 `src/client/chunk-loader.ts` 用自定义 require(externals 经 `__DSH_MODULES__` seed 分支解析)物化——**不经过** `__ModuleLoader__` 注册;**核心 bundle 禁止静态 import `src/client/chunks/*`**(会把库拖回启动路径);对消费插件透明——懒加载只作用于内置 descriptor,`component` 契约(`(props) => ReactNode` 纯渲染函数)不变 | --- diff --git a/src/client/index.tsx b/src/client/index.tsx index 08bcc06..856fac3 100644 --- a/src/client/index.tsx +++ b/src/client/index.tsx @@ -73,6 +73,7 @@ export function apply(ctx: Context): void { | { readonly active: string | undefined getOverride(dshActive: string, ns: string, key: string): string | undefined + isOverrideActive(dshActive: string): boolean register(ns: string, dicts: Record>): () => void subscribe(listener: () => void): () => void } diff --git a/src/client/locales.ts b/src/client/locales.ts index dd22225..86bf928 100644 --- a/src/client/locales.ts +++ b/src/client/locales.ts @@ -703,10 +703,17 @@ let localeService: { getSnapshot(): { active: string } } | undefined * (absent → no override; the zh/en chain runs). The store's `active` * field holds the user's chosen override id (e.g. `'ja'`); `undefined` * means "no override, use DSH native zh/en". + * + * The override only takes effect when DSH's active locale is `'en'` + * (it borrows DSH's English slot to render a third language). While + * DSH is on `'zh'` the override is inert — `getOverride` returns + * `undefined` and `isOverrideActive` returns `false` — so `t()` and + * `isZh()` fall through to the native zh/en chain unchanged. */ let betterLocaleStore: { readonly active: string | undefined getOverride(dshActive: string, ns: string, key: string): string | undefined + isOverrideActive(dshActive: string): boolean } | undefined /** @@ -752,10 +759,11 @@ export type CopyKey = keyof typeof zh /** Translate a copy key; `{name}` placeholders interpolate from `params`. */ export function t(key: CopyKey, params?: Record): string { - // 1. better-locale override (e.g. ja) wins when an override is active - // and the store has a translation for this (ns, key). The DSH active - // locale is forwarded for forward compatibility (a future mode could - // gate overrides on DSH being 'en'); the current store ignores it. + // 1. better-locale override (e.g. ja) wins when an override is active, + // DSH's active locale is 'en' (the override borrows the en slot), + // and the store has a translation for this (ns, key). The store's + // getOverride returns undefined otherwise (no override, DSH on zh, + // or missing key) and the zh/en chain runs. const dshActive = localeService?.getSnapshot().active ?? '' const override = betterLocaleStore?.getOverride(dshActive, LOCALE_NS, key) let text: string | undefined = override @@ -780,9 +788,14 @@ export function t(key: CopyKey, params?: Record): strin /** Whether the active locale is Chinese (used for selectors). */ export function isZh(): boolean { - // An active override is not Chinese — short-circuit so selectors pick + // An override is only "effectively active" when DSH is on 'en' (the + // override borrows the en slot). While DSH is on 'zh' the override is + // inert — the user sees native zh, so isZh() returns true. When an + // override is effectively active, the rendered text is neither zh nor + // en (it's ja/ko/...), so isZh() returns false to route selectors to // the non-zh branch (e.g. date format, pluralization). - if (betterLocaleStore?.active !== undefined) return false + const dshActive = localeService?.getSnapshot().active ?? '' + if (betterLocaleStore?.isOverrideActive(dshActive) === true) return false return activeLocale().toLowerCase().startsWith('zh') } diff --git a/tests/locales.spec.ts b/tests/locales.spec.ts index 8ec9d7d..56e0750 100644 --- a/tests/locales.spec.ts +++ b/tests/locales.spec.ts @@ -113,17 +113,21 @@ describe('locales (DSH i18n following)', () => { }) }) -/** Minimal fake of the better-locale override store (the subset t() reads). */ +/** Minimal fake of the better-locale override store (the subset t()/isZh() read). */ class FakeBetterLocale { active: string | undefined = undefined private readonly dict: Record>> constructor(dict: Record>>) { this.dict = dict } - getOverride(_dshActive: string, ns: string, key: string): string | undefined { + getOverride(dshActive: string, ns: string, key: string): string | undefined { if (this.active === undefined) return undefined + if (dshActive !== 'en') return undefined return this.dict[ns]?.[this.active]?.[key] } + isOverrideActive(dshActive: string): boolean { + return this.active !== undefined && dshActive === 'en' + } subscribe(_listener: () => void): () => void { return () => {} } @@ -175,6 +179,23 @@ describe('locales (better-locale override)', () => { expect(isZh()).toBe(true) }) + it('override is inert while DSH is on zh (override borrows the en slot)', () => { + const locale = new FakeLocale() + locale.switchTo('zh') + attachLocale(locale) + + const betterLocale = new FakeBetterLocale({ + [LOCALE_NS]: { ja: { explorer: 'エクスプローラー' } }, + }) + betterLocale.active = 'ja' + attachBetterLocale(betterLocale) + + // Override is set to 'ja' but DSH is on zh — override is inert, + // native zh text wins. The user must switch DSH to en to see ja. + expect(t('explorer')).toBe('资源管理器') + expect(isZh()).toBe(true) + }) + it('returns to the zh/en chain after detaching the override store', () => { const locale = new FakeLocale() locale.switchTo('en') From 16a809594cdce8d4846c653a1bded9209096fd7c Mon Sep 17 00:00:00 2001 From: HuanLinOTO Date: Sun, 23 Aug 2026 02:31:30 +0800 Subject: [PATCH 3/6] =?UTF-8?q?fix(i18n):=20better-locale=20=E6=8E=A5?= =?UTF-8?q?=E5=85=A5=E6=94=B9=E4=B8=BA=20activation-order-safe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ctx.get('betterLocale') 是非响应式读取(cordis 只对声明的 inject 依赖重新求值)。如果 better-locale 在 better-sidebar 之后激活, apply 顶层的 ctx.get 返回 undefined,attachBetterLocale(undefined) 使整个覆盖接入变成 no-op,即使用户后来在设置页选了日语, better-sidebar 的 t() 也不查询 override store。 改为在 ctx.effect 中订阅 ctx.locale.subscribe:better-locale 在 激活时(若有持久化的 override)和用户切换 override 时都会 bump locale revision,subscribe 回调触发 sync(),重新读取 ctx.get ('betterLocale')。store 可用后 attachBetterLocale(store) + register ja dict;store 不可用时 detach。 这解决了插件激活顺序不确定的问题:无论 better-locale 先于还是后于 better-sidebar 激活,override 接入都能正确建立。 --- src/client/index.tsx | 58 ++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/src/client/index.tsx b/src/client/index.tsx index 856fac3..a8fd047 100644 --- a/src/client/index.tsx +++ b/src/client/index.tsx @@ -67,28 +67,44 @@ export function apply(ctx: Context): void { // directly) also switches to the override language. We also register // the ja dict with the better-locale store so external callers of // ctx.locale.lookup('betterSidebar', key) get the override text too. - // Optional peer: ctx.get returns undefined when better-locale is absent, - // in which case the whole block is a no-op and the zh/en chain runs. - const betterLocale = ctx.get('betterLocale') as - | { - readonly active: string | undefined - getOverride(dshActive: string, ns: string, key: string): string | undefined - isOverrideActive(dshActive: string): boolean - register(ns: string, dicts: Record>): () => void - subscribe(listener: () => void): () => void + // + // Activation-order-safe: ctx.get('betterLocale') is a non-reactive read + // (cordis only re-evaluates declared `inject` deps). If better-locale + // activates after better-sidebar, the initial read returns undefined. + // We subscribe to the locale revision — better-locale bumps it on + // activation (when a persisted override exists) and on every override + // switch — and re-check ctx.get on each bump, attaching + registering + // the ja dict once the store becomes available. + ctx.effect(() => { + let dispose: (() => void) | undefined + const sync = (): void => { + dispose?.() + dispose = undefined + const store = ctx.get('betterLocale') as + | { + readonly active: string | undefined + getOverride(dshActive: string, ns: string, key: string): string | undefined + isOverrideActive(dshActive: string): boolean + register(ns: string, dicts: Record>): () => void + subscribe(listener: () => void): () => void + } + | undefined + attachBetterLocale(store) + if (store !== undefined) { + dispose = store.register(LOCALE_NS, { ja }) } - | undefined - attachBetterLocale(betterLocale) - if (betterLocale !== undefined) { - ctx.effect(() => { - // Register the ja dict for the betterSidebar namespace. Better-locale's - // patched lookup consults this when the user has selected the ja - // override; the dict stays owned by better-sidebar (the namespace - // owner), so a single source of truth covers both ctx.locale callers - // and the internal t(). - return betterLocale.register(LOCALE_NS, { ja }) - }, 'dsh-better-sidebar: better-locale ja dict') - } + } + // Initial check (picks up the store if better-locale activated first). + sync() + // Re-check on every locale revision bump (better-locale bumps when it + // activates with a persisted override, and when the user switches). + const unsubscribe = ctx.locale.subscribe(sync) + return () => { + unsubscribe() + dispose?.() + attachBetterLocale(undefined) + } + }, 'dsh-better-sidebar: better-locale lazy integration') // One store instance per activation: production code creates it only here, // then hands it to the mounted panel and closes over it in the slot // registrations (the official createXXXStore() factory rule — no From 7f8f95a59b48b4e95cd1f6c9e50dfdede1a56dc8 Mon Sep 17 00:00:00 2001 From: HuanLinOTO Date: Sun, 23 Aug 2026 14:57:48 +0800 Subject: [PATCH 4/6] =?UTF-8?q?feat(i18n):=20=E8=A6=86=E7=9B=96=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=89=A9=E5=B1=95=E5=88=B0=2019=20=E8=AF=AD=E8=A8=80?= =?UTF-8?q?=EF=BC=88de/fr/pt/ko/ar/hi/id/tr/vi/th/ru/it/nl/sv/pl/zh-HK/zh-?= =?UTF-8?q?TW/zh-MO=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/client/index.tsx | 10 +- src/client/locales-ar.ts | 346 ++++++++++++++++++++++++++++++++++ src/client/locales-de.ts | 331 +++++++++++++++++++++++++++++++++ src/client/locales-fr.ts | 338 +++++++++++++++++++++++++++++++++ src/client/locales-hi.ts | 345 ++++++++++++++++++++++++++++++++++ src/client/locales-id.ts | 343 ++++++++++++++++++++++++++++++++++ src/client/locales-it.ts | 336 +++++++++++++++++++++++++++++++++ src/client/locales-ko.ts | 337 +++++++++++++++++++++++++++++++++ src/client/locales-nl.ts | 343 ++++++++++++++++++++++++++++++++++ src/client/locales-pl.ts | 347 ++++++++++++++++++++++++++++++++++ src/client/locales-pt.ts | 328 ++++++++++++++++++++++++++++++++ src/client/locales-ru.ts | 343 ++++++++++++++++++++++++++++++++++ src/client/locales-sv.ts | 328 ++++++++++++++++++++++++++++++++ src/client/locales-th.ts | 345 ++++++++++++++++++++++++++++++++++ src/client/locales-tr.ts | 345 ++++++++++++++++++++++++++++++++++ src/client/locales-vi.ts | 345 ++++++++++++++++++++++++++++++++++ src/client/locales-zh-HK.ts | 360 ++++++++++++++++++++++++++++++++++++ src/client/locales-zh-MO.ts | 360 ++++++++++++++++++++++++++++++++++++ src/client/locales-zh-TW.ts | 360 ++++++++++++++++++++++++++++++++++++ src/client/locales.ts | 36 ++++ 20 files changed, 6224 insertions(+), 2 deletions(-) create mode 100644 src/client/locales-ar.ts create mode 100644 src/client/locales-de.ts create mode 100644 src/client/locales-fr.ts create mode 100644 src/client/locales-hi.ts create mode 100644 src/client/locales-id.ts create mode 100644 src/client/locales-it.ts create mode 100644 src/client/locales-ko.ts create mode 100644 src/client/locales-nl.ts create mode 100644 src/client/locales-pl.ts create mode 100644 src/client/locales-pt.ts create mode 100644 src/client/locales-ru.ts create mode 100644 src/client/locales-sv.ts create mode 100644 src/client/locales-th.ts create mode 100644 src/client/locales-tr.ts create mode 100644 src/client/locales-vi.ts create mode 100644 src/client/locales-zh-HK.ts create mode 100644 src/client/locales-zh-MO.ts create mode 100644 src/client/locales-zh-TW.ts diff --git a/src/client/index.tsx b/src/client/index.tsx index a8fd047..95b9530 100644 --- a/src/client/index.tsx +++ b/src/client/index.tsx @@ -24,7 +24,10 @@ import { registerSettingsNavIcon } from './settings-nav-icon.ts' import { loadExternalDisable, loadPrefs } from './prefs.ts' import { SideCardSection } from './SideCardSection.tsx' import { api } from './api.ts' -import { LOCALE_NS, attachLocale, attachBetterLocale, t, zh, en, ja } from './locales.ts' +import { LOCALE_NS, attachLocale, attachBetterLocale, t, zh, en, + ja, de, fr, pt, ko, ar, hi, id, tr, vi, th, ru, it, nl, sv, pl, + zhHK, zhTW, zhMO, +} from './locales.ts' import css from './sidebar.module.css' import './layout.css' @@ -91,7 +94,10 @@ export function apply(ctx: Context): void { | undefined attachBetterLocale(store) if (store !== undefined) { - dispose = store.register(LOCALE_NS, { ja }) + dispose = store.register(LOCALE_NS, { + ja, de, fr, pt, ko, ar, hi, id, tr, vi, th, ru, it, nl, sv, pl, + 'zh-HK': zhHK, 'zh-TW': zhTW, 'zh-MO': zhMO, + }) } } // Initial check (picks up the store if better-locale activated first). diff --git a/src/client/locales-ar.ts b/src/client/locales-ar.ts new file mode 100644 index 0000000..55901f3 --- /dev/null +++ b/src/client/locales-ar.ts @@ -0,0 +1,346 @@ +/** + * The ar (Arabic) dictionary for the betterSidebar namespace. + * + * Mirrors the key set of `zh` in `locales.ts`. The sidebar's `t()` + * consults this dict when `attachBetterLocale(store)` has been called + * with an active better-locale store whose `active` is `'ar'`; absent + * that, the existing zh/en chain runs unchanged. + * + * Translation conventions: + * - Modern Standard Arabic (فصحى); UI text is RTL-ready (the framework + * handles direction). + * - Git vocabulary follows standard Arabic localizations (إدراج، تثبيت، فرع). + * - Placeholders keep `{name}` verbatim (interpolation runs after lookup). + * - English brand names (VS Code, Cursor, Zed, SSH, Git, HTML, PDF, Markdown) + * stay as-is. + */ + +/** The ar dictionary (key-set-equal to zh, enforced by the type annotation in locales.ts). */ +export const ar: Record = { + files: 'الملفات', + explorer: 'المستكشف', + git: 'إدارة المصدر', + terminal: 'الطرفية', + editor: 'المحرّر', + editorExplorer: 'سلوك فتح الملفات', + editorExplorerDesc: 'يتحكّم في كيفية فتح الملفات', + editorExplorerMerged: 'مدمج', + editorExplorerMergedDesc: 'الملفات تتبدّل في مكانها داخل نفس النافذة؛ النوافذ الجديدة تبدأ بالشجرة مفتوحة', + editorExplorerSplit: 'منفصل', + editorExplorerSplitDesc: 'النوافذ بلا مسار هي المستكشف المستقل (شجرة فقط)؛ كل ملف يفتح نافذته الخاصة (الشجرة مرساة، مغلقة افتراضياً)', + editorTreeToggle: 'لوحة شجرة الملفات', + editorPathPlaceholder: 'مسار الملف (نسبي لدليل الجلسة أو مطلق)، Enter للفتح', + editorSearchPlaceholder: 'البحث في الملفات بالاسم…', + editorSearchNoResults: 'لا ملفات مطابقة', + editorSearchTruncated: 'نتائج كثيرة جداً — عرض قائمة جزئية', + editorEmptyHint: 'اختر ملفاً من لوحة الشجرة أو من حقل المسار بالأعلى لبدء المعاينة', + openFileNewTab: 'فتح في تبويب جديد', + openFileSide: 'فتح إلى الجانب', + openWithMenu: 'فتح بواسطة', + openWithSshSuffix: ' (SSH)', + pinOpenWith: 'تثبيت في القائمة', + unpinOpenWith: 'إلغاء التثبيت', + openWithExplorer: 'مدير الملفات', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'مضيف SSH البعيد', + openWithSettingsSshDesc: 'فارغ = مساحة عمل محلية؛ مع user@host أو اسم مستعار SSH، تتحوّل فواتح عائلة VSCode إلى بروتوكول vscode-remote/ssh-remote ويُخفى مدير الملفات وZed والمحرّرات المخصّصة غير التابعة لعائلة VSCode من القائمة', + openWithSettingsSshPlaceholder: 'user@host أو اسم مستعار SSH', + openWithSettingsCustomTitle: 'محرّرات مخصّصة', + openWithSettingsCustomDesc: 'اسم + قالب URL (عنصر نائب {path}) + علامة عائلة VSCode؛ في الوضع البعيد، يمكن فقط لمحرّرات عائلة VSCode فتح مسار بعيد', + openWithSettingsAdd: 'إضافة', + openWithSettingsName: 'الاسم', + openWithSettingsTemplate: 'مثل cursor://file/{path}', + openWithSettingsFamily: 'عائلة VSCode', + openWithSettingsFamilyDesc: 'يتحدّث هذا المحرّر لهجة URL لـ VSCode (يدعم الفتح عبر SSH البعيد)', + openWithSettingsRemove: 'إزالة', + openWithSettingsInvalidHint: 'لن تظهر المحرّرات التي تفتقر إلى الاسم أو القالب (يلزم أن يحتوي على {path} ويبدأ بـ scheme://) في القائمة', + newTab: 'تبويب جديد', + openExplorer: 'المستكشف', + brokenSymlink: 'رابط رمزي معطوب', + openGit: 'لوحة Git', + newTerminal: 'طرفية جديدة', + terminalLimit: 'تم بلوغ حد الطرفيات (3)', + close: 'إغلاق', + closeOtherTabs: 'إغلاق التبويبات الأخرى', + closeLeftTabs: 'إغلاق التبويبات على اليسار', + closeRightTabs: 'إغلاق التبويبات على اليمين', + collapse: 'طي الشريط الجانبي', + expand: 'توسيع الشريط الجانبي', + collapseBottomPanel: 'طي اللوحة السفلية', + expandBottomPanel: 'توسيع اللوحة السفلية', + terminalError: 'فشل اتصال الطرفية', + terminalConnectFailed: 'فشل اتصال الطرفية عدة مرات', + terminalRetry: 'إعادة المحاولة', + terminalDepsFailed: 'فشل تحميل تبعية الطرفية node-pty', + terminalDepsHint: 'شغّل الأمر التالي في طرفية أو cmd على جهاز DSH للإصلاح، ثم أعد المحاولة (يبقى node-pty متزامناً مع إصدار نواة DSH):', + terminalDepsProfile: ' (الملف الشخصي المكتشف: {profile})', + preview: 'معاينة', + edit: 'تحرير', + mermaidError: 'فشل رسم Mermaid', + mermaidZoomIn: 'تكبير', + mermaidZoomOut: 'تصغير', + mermaidZoomReset: 'إعادة تعيين', + mermaidZoomHint: 'العجلة للتقريب · السحب للتحريك · Esc للإغلاق', + refresh: 'تحديث', + save: 'حفظ', + saved: 'تم الحفظ', + unsaved: 'غير محفوظ', + saveFailed: 'فشل الحفظ', + truncation: 'الملف كبير جداً — عرض أول 512KB', + binary: 'ملف ثنائي، المعاينة غير متاحة', + loading: 'جارٍ التحميل…', + error: 'فشل التحميل', + retry: 'إعادة المحاولة', + splitLeft: 'تقسيم يساراً', + splitRight: 'تقسيم يميناً', + splitUp: 'تقسيم لأعلى', + splitDown: 'تقسيم لأسفل', + notRepo: 'هذا الدليل ليس مستودع git', + noChanges: 'لا تغييرات', + stage: 'إدراج', + unstage: 'إلغاء الإدراج', + stageAll: 'إدراج الكل', + unstageAll: 'إلغاء إدراج الكل', + commitPlaceholder: 'رسالة التثبيت (Ctrl+Enter)', + commit: 'تثبيت', + commitError: 'فشل التثبيت', + branch: 'الفرع', + checkoutError: 'فشل تبديل الفرع', + history: 'السجل', + changes: 'التغييرات', + staged: 'مُدرج', + unstaged: 'غير مُدرج', + cancel: 'إلغاء', + diffEmpty: 'لا تغييرات نصية', + diffLoadError: 'فشل تحميل الفرق', + diffBinary: 'ثنائي', + diffAdded: 'مُضاف', + diffDeleted: 'محذوف', + diffRenamed: 'إعادة تسمية', + diffExpand: 'إظهار {count} صفوف أخرى', + diffCollapse: 'طي', + discard: 'تجاهل التغييرات', + discardTitle: 'تجاهل التغييرات', + discardDesc: 'هذا يتجاهل تغييرات مساحة العمل في "{path}" (غير قابل للاستعادة).', + viewCommitDiff: 'عرض فرق التثبيت', + copyShortHash: 'نسخ الهاش القصير', + copyFullHash: 'نسخ الهاش الكامل', + copySubject: 'نسخ موضوع التثبيت', + revertCommit: 'عكس التثبيت', + revertTitle: 'عكس التثبيت', + revertDesc: 'ينشئ تثبيتاً جديداً على الفرع الحالي يعكس "{subject}".', + cherryPickCommit: 'اقتطاف التثبيت', + cherryPickTitle: 'اقتطاف التثبيت', + cherryPickDesc: 'يطبّق تغييرات "{subject}" على الفرع الحالي.', + timeJustNow: 'الآن', + timeMinutesAgo: 'منذ {n} دقيقة', + timeHoursAgo: 'منذ {n} ساعة', + timeYesterday: 'أمس', + loadMore: 'تحميل المزيد', + historyLoadError: 'فشل تحميل المزيد من السجل', + produced: 'النواتج', + producedOpen: 'فتح في الشريط الجانبي', + disconnected: 'انقطع اتصال الطرفية، جارٍ إعادة الاتصال…', + exited: 'خرجت عملية الطرفية', + noSession: 'اختر محادثة لاستخدام الشريط الجانبي', + pluginNotLoaded: 'الإضافة غير محمّلة؛ التبويب غير متاح:', + hiddenFiles: 'ملفات مخفية', + parent: 'الدليل الأصل', + copied: 'تم النسخ', + copy: 'نسخ', + newFile: 'ملف جديد', + openEditor: 'فتح المحرّر', + gitDetail: 'عرض تفاصيل التغيير', + referenceFile: '@ملف', + addToConversation: 'إضافة إلى المحادثة', + copyRelative: 'نسخ المسار النسبي', + copyAbsolute: 'نسخ المسار المطلق', + download: 'تنزيل', + uploadFiles: 'رفع ملفات', + uploadFolder: 'رفع مجلد', + uploadHere: 'ارفع هنا', + uploadDropHint: 'أسقط الملفات/المجلدات هنا للرفع', + uploadDropChat: 'الإسقاط على منطقة المحادثة: إضافة صور إلى المحادثة', + uploadTo: 'رفع إلى {dir}', + uploadingTo: 'جارٍ الرفع إلى {dir}…', + uploadProgress: 'جارٍ الرفع {done}/{total}: {name}', + uploadDone: 'تم رفع {count} ملف', + uploadFailed: 'فشل الرفع: {error}', + uploadFailedUnknown: 'خطأ غير معروف', + uploadTooLarge: 'الملف كبير جداً (يتجاوز حد الرفع)', + uploadCancelled: 'تم إلغاء الرفع', + settingsNav: 'البطاقة الجانبية', + settingsIntro: 'إدارة ما تعرضه البطاقة الجانبية وكيف تتصرف', + settingsPopupDesc: 'تكوين خيارات ذات صلة بـ {feature}', + settingsDone: 'تم', + settingsOpenTitle: 'فتح افتراضياً للمحادثات الجديدة', + settingsOpenDesc: 'توسيع البطاقة الجانبية تلقائياً للمحادثات الجديدة تماماً؛ المحادثات الموجودة تحتفظ بتخطيطاتها', + settingsWidthTitle: 'الحصة الافتراضية للعرض', + settingsWidthDesc: 'الحصة الافتراضية للبطاقة الجانبية من عرض النافذة للمحادثات الجديدة (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: 'فتح ملفات المحادثة في الشريط الجانبي', + settingsOpenPathDesc: 'فتح روابط الملفات في المحادثة (صفوف الأدوات، الملفات الناتجة، الإشارات) في محرّر الشريط الجانبي بدلاً من التطبيق الافتراضي للنظام', + settingsTitleBarTitle: 'وضع توافق الموضع', + settingsTitleBarDesc: 'اختر نظام توافق الشريط العلوي: كشف تلقائي (افتراضي، محافظ) / ويب DSH الرسمي / أغلفة سطح المكتب المعروفة / مخصّص (مسافة الإزاحة + CSS مخصّص)', + settingsTitleBarStripTitle: 'مسافة الإزاحة', + settingsTitleBarStripDesc: 'ارتفاع شريط الشريط العلوي: كم بكسل تتحرك به أزرار الشريط الجانبي والمحتوى للأسفل (0–120، افتراضي 40؛ يسري تحت النظام المخصّص)', + settingsSchemeAutoTitle: 'كشف تلقائي', + settingsSchemeAutoDesc: 'محافظ: يساهم فقط معيار Window Controls Overlay API (ارتفاع التسمية التوضيحية الحقيقي)؛ بيئات الويب العادية لا تعدّل شيئاً', + settingsSchemeWebTitle: 'ويب DSH الرسمي', + settingsSchemeWebDesc: 'صراحة: الإعلان عن تشغيل في واجهة الويب الرسمية: لا أي تكيّف (حتى هندسة WCO القياسية لا تطبّق)', + settingsSchemeCustomTitle: 'مخصّص', + settingsSchemeCustomDesc: 'تحكّم كامل: حقن CSS مخصّص (يمكن أن يلغي الأنماط المدمجة) وتحديد مسافة إزاحة الشريط العلوي', + settingsSchemeDetectedSuffix: 'تم الكشف', + settingsCustomCssTitle: 'CSS مخصّص', + settingsCustomCssDesc: 'أنماط تُضاف في نهاية الصفحة (المكتوب لاحقاً يكسر التعادل في نفس الأولوية؛ استخدم !important لتلغي المتغيرات المكتوبة بواسطة JS)', + settingsCustomCssPlaceholder: '/* مثال: حجز 36px لغلاف له شريط علوي مرسوم ذاتياً */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: 'فشل الحفظ', + settingsConflict: 'تغيّر الإعداد في نافذة أخرى — يُرجى إعادة المحاولة', + binaryNoPreview: 'لا يمكن معاينة هذا النوع من الملفات', + downloadToView: 'تنزيل للعرض', + settingsSubagentTitle: 'فتح صفحة المهام تلقائياً عند ظهور وكيل فرعي', + settingsSubagentDesc: 'توسيع البطاقة الجانبية وفتح صفحة المهام عند توليد المحادثة الحالية لوكيل فرعي جديد؛ أوقفها للفتح يدوياً', + settingsJobsTitle: 'فتح صفحة المهام الخلفية تلقائياً عند مهمة خلفية جديدة', + settingsJobsDesc: 'توسيع البطاقة الجانبية وفتح صفحة المهام الخلفية عند ظهور مهمة خلفية جديدة للمحادثة الحالية (كل مهمة جديدة تُطلق ذلك)؛ أوقفها للفتح يدوياً', + settingsToolsTitle: 'حقن أدوات الطرفية للنموذج', + settingsToolsDesc: 'عند التفعيل، يمكن للنموذج إنشاء وتشغيل طرفيات الشريط الجانبي عبر أدوات terminal_* الثمانية (معطّل افتراضياً)', + settingsBottomTerminalTitle: 'فتح طرفية تلقائياً عند أول توسيع للوحة السفلية', + settingsBottomTerminalDesc: 'عند توسيع اللوحة السفلية لأول مرة في الجلسة، حاول فتح تبويب طرفية جديد هناك (حصة الطرفيات ما زالت تسري؛ مفعّل افتراضياً)', + settingsFontFamilyTitle: 'عائلة خط الطرفية', + settingsFontFamilyDesc: 'عائلة خط الطرفية المخصّصة (مكدس CSS font-family مثل "JetBrains Mono", monospace؛ اتركه فارغاً لاتّباع خط السمة أحادي المسافة)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: 'حجم خط الطرفية', + settingsFontSizeDesc: 'حجم خط الطرفية بالبكسل (9–32، افتراضي 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'مسار الصدفة', + settingsShellDesc: 'الصدفة التي تُطلق لطرفيات الواجهة والنموذج (مسار مطلق أو اسم تنفيذي مجرّد). الفراغ يحافظ على الترتيب القائم: yaml config.shell ← $SHELL / صدفة الدخول / Windows powershell.exe. يسري على الطرفيات المفتوحة لاحقاً', + settingsShellPlaceholder: 'مثل /bin/zsh (فارغ = تلقائي)', + settingsShellArgsTitle: 'وسائط الصدفة', + settingsShellArgsDesc: 'وسائط صدفة صريحة، مفصولة بمسافات؛ عند عدم الفراغ تستبدل الافتراضيات بالكامل (نفس عقد yaml shellArgs)', + settingsShellArgsPlaceholder: 'مثل -l (فارغ = الافتراضيات)', + settingsTabsTitle: 'محتوى الشريط الجانبي', + settingsViewersTitle: 'عارضات الملفات', + settingsGeneralTitle: 'عام', + settingsPopup: 'إعدادات الميزة', + settingsViewerCatchAll: 'شامل: أي ملف', + viewerImage: 'صورة', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: 'كود', + viewerBinary: 'تنزيل ثنائي', + viewerHtml: 'HTML', + browser: 'المتصفح', + browserPlaceholder: 'أدخل عنوان URL، مثل example.com', + browserGo: 'اذهب', + browserBack: 'للخلف', + browserForward: 'للأمام', + browserStart: 'أدخل عنوان URL لبدء التصفح (وضع الحماية)', + browserBlockedScheme: 'محظور: يُسمح فقط بعناوين URL من نوع http/https', + browserBlockedLoopback: 'محظور: لا يمكن تصفّح العناوين المحلية والداخلية هنا', + browserInvalid: 'عنوان URL غير صالح', + browserNoSandboxWarning: 'الحماية معطّلة: الصفحة الحالية تعمل بكامل صلاحيات الواجهة (يمكن إعادة تفعيلها في الإعدادات)', + htmlNoSandboxWarning: 'الحماية معطّلة: يعمل هذا HTML بنفس أصل الواجهة — يمكنه قراءة ملفات الجلسة وواجهات API الداخلية (يمكن إعادة تفعيلها في الإعدادات)', + sandboxStatusOn: 'وضع الحماية: مفعّل · لا يمكن للصفحات الوصول إلى بيانات الواجهة أو الملفات المحلية؛ قد لا تعمل تسجيلات الدخول وملفات الارتباط التابعة لجهات خارجية', + sandboxUnlock: 'تعطيل مؤقت (غير آمن)', + sandboxRestore: 'استعادة الحماية', + settingsHtmlDefaultUnsafeTitle: 'فتح معاينات HTML بدون حماية افتراضياً (غير آمن)', + settingsHtmlDefaultUnsafeDesc: 'عند التفعيل، تبدأ كل معاينة HTML مفتوحة حديثاً في الحالة غير المحمية (نفس أصل الواجهة — يمكنها قراءة ملفات الجلسة وواجهات API الداخلية)؛ يوفر صف الحالة استعادة بلمسة واحدة', + settingsHtmlSandboxTitle: 'تعطيل حماية معاينة HTML (غير آمن)', + settingsHtmlSandboxDesc: 'مع تعطيل الحماية، يعمل HTML المعاين بنفس أصل الواجهة: يمكنه قراءة ملفات الجلسة والتخزين المحلي واستدعاء واجهات API الداخلية. فعّله فقط للملفات الموثوقة بالكامل', + settingsBrowserSandboxTitle: 'تعطيل حماية المتصفح (غير آمن)', + settingsBrowserSandboxDesc: 'مع تعطيل الحماية، يعمل أي موقع تزوره بنفس أصل الواجهة: يمكنه قراءة بيانات الجلسة وانتحال جلسة تسجيل الدخول الخاصة بك. فعّله فقط للمواقع الموثوقة بالكامل', + settingsBrowserLinksTitle: 'فتح الروابط الخارجية للمحادثة في الشريط الجانبي', + settingsBrowserLinksDesc: 'عند التفعيل، النقر على رابط خارجي في المحادثة أو الواجهة يفتح الشريط الجانبي بدلاً من نافذة جديدة؛ يتحكّم في HTTP وHTTPS بشكل منفصل بالمبدلات بالأسفل؛ Ctrl/Cmd+نقر يتجاوز دائماً', + settingsBrowserHttpTitle: 'فتح صفحات HTTP في الشريط الجانبي', + settingsBrowserHttpDesc: 'عند التفعيل، النقر على رابط HTTP خارجي في المحادثة أو الواجهة يفتح الشريط الجانبي (صفحات الإضافات المعرّفة عن urlTarget تفوز)؛ Ctrl/Cmd+نقر يتجاوز دائماً', + settingsBrowserHttpsTitle: 'فتح صفحات HTTPS في الشريط الجانبي', + settingsBrowserHttpsDesc: 'عند التفعيل، النقر على رابط HTTPS خارجي في المحادثة أو الواجهة يفتح الشريط الجانبي. معطّل افتراضياً: معظم مواقع HTTPS ترفض التضمين، لذا فالمتصفح الافتراضي للنظام هو الخيار الأنسب', + browserOpenExternal: 'فتح في المتصفح', + browserEmbedBlocked: 'رفض {host} التضمين', + browserEmbedBlockedDesc: 'يحظر الموقع عرضه داخل صفحات أخرى (X-Frame-Options / frame-ancestors)، لذا لا يمكن تحميله في الشريط الجانبي. افتحه مباشرة في متصفحك بدلاً من ذلك.', + browserEmbedAnyway: 'تحميل على أي حال', + subagent: 'المهام', + openSubagent: 'المهام', + subagentMainAgent: 'الوكيل الرئيسي', + subagentEmpty: 'لا وكلاء فرعيون', + subagentEmptyDesc: 'الوكلاء الفرعيون المُنتَجون تحت الوكيل الرئيسي سيظهرون هنا', + subagentRunning: 'قيد التشغيل', + subagentInactive: 'خامل', + subagentModeOneShot: 'مرة واحدة', + subagentModeContinuable: 'قابل للاستئناف', + subagentCount: '{count} وكلاء فرعيون', + subagentCountRunning: '{count} وكلاء فرعيون · {running} قيد التشغيل', + subagentDiagCorrupt: 'تالف', + subagentDiagUnsupported: 'غير مدعوم', + subagentDiagUnavailable: 'غير متاح', + subagentThinking: 'جارٍ التفكير…', + sideChat: 'محادثة جانبية (تجريبية)', + sideChatNew: 'خيط جديد', + sideChatUntitled: 'خيط جديد', + sideChatEmpty: 'لا محادثات جانبية', + sideChatEmptyDesc: 'كل محادثة جانبية هي تبويب مستقل في شريط التبويبات — ترث سياق الجلسة الحالية ولا تدخل المحادثة الرئيسية', + sideChatCreating: 'جارٍ إنشاء محادثة جانبية…', + sideChatRetry: 'إعادة المحاولة', + sideChatThreads: 'تبديل خيط / جديد', + sideChatSave: 'حفظ كجلسة جديدة', + sideChatSaveTitle: 'ترقية هذا الخيط إلى جلسة عالية المستوى في قائمة الجلسات الرئيسية', + sideChatSaved: 'تم الحفظ كجلسة جديدة', + sideChatNoTurn: 'الحفظ متاح بعد أول دور مكتمل', + sideChatPendingDrop: 'لن يُضمَّ آخر متابعة لم يُجَب عنها في الجلسة المحفوظة', + sideChatFirstPlaceholder: 'اطرح السؤال الأول — السياق موروث…', + sideChatComposerPlaceholder: 'متابعة…', + sideChatThinking: 'جارٍ التعمّق…', + sideChatThink: 'التفكير', + sideChatInjection: 'تم حقن السياق', + sideChatSend: 'إرسال', + sideChatCancel: 'إيقاف', + sideChatCancelTitle: 'إلغاء الدور الجاري (يُحتفظ بالعمل في قائمة الانتظار)', + sideChatClose: 'إغلاق الخيط', + sideChatCloseTitle: 'تحرير وكيل الخيط (يُحتفظ بالسجل)', + sideChatError: 'خطأ في المحادثة الجانبية: {message}', + jobs: 'المهام الخلفية', + jobsCount: '{count} مهمة خلفية', + jobsCountRunning: '{count} مهمة خلفية · {running} قيد التشغيل', + jobStatusRunning: 'قيد التشغيل', + jobStatusStopping: 'جارٍ الإيقاف', + jobStatusCompleted: 'اكتمل', + jobStatusKilled: 'تم الإنهاء', + jobStatusFailed: 'فشل', + jobDurationSeconds: '{seconds}ث', + jobDurationMinutes: '{minutes}د {seconds}ث', + jobDurationHours: '{hours}س {minutes}د', + jobViewOutput: 'عرض الإخراج', + jobHideOutput: 'إخفاء الإخراج', + jobNoOutput: 'لا إخراج بعد', + jobNotReadYet: 'في انتظار قراءة النموذج لإخراج هذه المهمة؛ سيظهر الإخراج هنا بمجرد أن يشغّل النموذج job_output', + jobOutputTruncated: 'الإخراج مقطوع', + jobOutputError: 'فشل قراءة الإخراج', + jobKill: 'إنهاء', + jobKillConfirm: 'انقر مجدداً للتأكيد على الإنهاء', + jobKillError: 'فشل الإنهاء', + addPluginsTabCard: 'إضافة إضافات تبويب', + addPluginsTabCardDesc: 'تسجيل صفحة شريط جانبي جديدة', + addPluginsViewerCard: 'إضافة إضافات معاينة', + addPluginsViewerCardDesc: 'تسجيل معاينة نوع ملف', + addPluginsTabDesc: 'يمكن توسيع صفحات الشريط الجانبي (التبويبات) بواسطة الإضافات. تُسجَّل الإضافات عبر خدمة ctx.betterSidebar؛ النقر على «تثبيت» ينسخ أمر التثبيت — الصقه في طرفية حيث يقيم ملف DSH الشخصي وشغّله.', + addPluginsViewerDesc: 'يمكن توسيع عارضات الملفات بواسطة الإضافات. تُسجَّل الإضافات عبر خدمة ctx.betterSidebar؛ النقر على «تثبيت» ينسخ أمر التثبيت — الصقه في طرفية حيث يقيم ملف DSH الشخصي وشغّله.', + addPluginsBrowseMore: 'تصفّح المزيد من الإضافات على GitHub (topic: dsh-better-sidebar)', + addPluginsSearch: 'البحث باسم الإضافة / الوصف…', + addPluginsNoMatch: 'لا إضافات مطابقة', + addPluginsRecommended: 'إضافات موصى بها', + addPluginsEmpty: 'لا إضافات منسّقة بعد — انشر إضافتك تحت موضوع GitHub', + openPlugin: 'فتح', + copyInstall: 'نسخ أمر التثبيت', + pluginOfficeDesc: 'معاينة حزمة Office (.docx / .xlsx / .pptx) لمحرّر better-sidebar، مع إبقاء مكتبات عرض Office الثقيلة خارج الحزمة الأساسية، تُثبَّت عند الطلب', + pluginFlowglassDesc: 'مخطط تدفق جلسة حيّ بثلاثة مسارات للمستخدم والمساعد واستدعاءات الأدوات، مع مجموعات متوازية وفروع وكلاء فرعيين وتعمّق تدريجي وحالة حيّة؛ يُسجِّل تبويب Flowglass الأصلي عند تثبيت better-sidebar ويحتفظ بدرجه المستقل كاحتياط', + pluginGitForgeDesc: 'تبويب Git Forge: مكتبة حسابات GitHub/Gitea (وغيرها من Forges) + منح لكل مشروع + سياسة دفع صارمة؛ تبقى الرموز في الأسرار المحلية (لا تدخل سياق النموذج)؛ أداة GitForge للقراءة فقط ومساعد بيانات اعتماد HTTPS للوكيل', + pluginGitRemotesDesc: 'تبويب Git Remotes: فرع/أصل/أمام-خلف، fetch (مع prune اختياري)، ff-only pull، والدفع فقط بعد تأكيد داخل التبويب. لا يستبدل تبويب Git المدمج للإدراج/التثبيت، ولا يقدّم force-push أو أداة دفع آلي للنموذج', + pluginSentinelDesc: 'نظام إيقاظ وكيل يحرّكه تحقّق الشروط: مستشعرات ملف/عملية/منفذ/HTTP/أمر/webhook توقظ الجلسات الخاملة عند تحقّق الشرط؛ يُسجِّل تبويب «Sentinel» مع جدول مراقبة شامل للخادم', + pluginSidebarQaDesc: 'حدِّد واسأل: تحديد نص المحادثة ← السؤال في اللوحة اليمنى ← جلسة متابعات مخصّصة في نفس مساحة العمل (❓ متابعة · موضوع): نموذج سريع بلا تفكير يضغط سياق المحادثة الرئيسي ويحقنه مع الاقتباس دون مقاطعة المحادثة الرئيسية؛ المتابعات تتداخل وتستمر وتُؤرشف', + pluginSshTunnelDesc: 'تبويب «SSH Tunnel»: قائمة مضيفين متعددين + منح لكل مشروع + أسرار محلية؛ أداة SSHManager للنموذج (exec/SFTP/استراتيجيات الجلسة)؛ طرفية تفاعلية مركزية وSFTP ذو عمودين', + pluginTurnReviewDesc: 'بوابة بشرية على فرق «الدور المنتهي للتو»: Approve / Request changes لكل مسار مع تعليق اختياري؛ المسارات مجمّعة حسب الجلسة الرئيسية / الوكيل الفرعي / غير منسوب؛ فرق snapshot-vs-now مضمّن قبل القرار. لا تفريع، لا /rewind', + pluginVideoPreviewDesc: 'معاينة فيديو مضمّنة (.mp4/.webm/.mov/.mkv/.avi إلخ) في محرّر better-sidebar، مدعومة بمسار /video مخصّص يدعم HTTP Range (206) — التحكم بالتشغيل يعمل والملفات غير مقيدة بحد mediaLimit البالغ 20MB', + pluginDocsPanelDesc: '«وثائق عامة» في شريط DSH الجانبي: ملاحظات Markdown عامة، قابلة للقراءة من أي مساحة عمل — قائمة ملفات، مخطط تفصيلي، فتح في Chrome / VS Code، وأزرار نسخ؛ دليل الوثائق قابل للتكوين (الافتراضي ~/.dsh/docs)', +} diff --git a/src/client/locales-de.ts b/src/client/locales-de.ts new file mode 100644 index 0000000..d42b5fe --- /dev/null +++ b/src/client/locales-de.ts @@ -0,0 +1,331 @@ +/** + * German dictionary for better-sidebar. + */ +export const de: Record = { + files: 'Dateien', + explorer: 'Explorer', + git: 'Quellcodeverwaltung', + terminal: 'Terminal', + editor: 'Editor', + editorExplorer: 'Dateiöffnungsverhalten', + editorExplorerDesc: 'Steuert, wie Dateien geöffnet werden', + editorExplorerMerged: 'Zusammengeführt', + editorExplorerMergedDesc: 'Dateien wechseln im selben Fenster; neue Fenster starten mit geöffneter Baumansicht', + editorExplorerSplit: 'Getrennt', + editorExplorerSplitDesc: 'Fenster ohne Pfad sind der eigenständige Explorer (nur Dateibaum); jede Datei öffnet ein eigenes Fenster (mit angedocktem, standardmäßig eingeklapptem Baum)', + editorTreeToggle: 'Dateibaum-Panel', + editorPathPlaceholder: 'Dateipfad (relativ zum Sitzungsverzeichnis oder absolut), Enter zum Öffnen', + editorSearchPlaceholder: 'Nach Dateiname suchen…', + editorSearchNoResults: 'Keine passenden Dateien', + editorSearchTruncated: 'Zu viele Ergebnisse – nur ein Teil wird angezeigt', + editorEmptyHint: 'Wählen Sie eine Datei aus dem Dateibaum rechts oder dem Pfadeingabefeld oben, um mit der Vorschau zu beginnen', + openFileNewTab: 'In neuem Tab öffnen', + openFileSide: 'Seitlich öffnen', + openWithMenu: 'Öffnen mit', + openWithSshSuffix: ' (SSH)', + pinOpenWith: 'Im Menü anheften', + unpinOpenWith: 'Lösen', + openWithExplorer: 'Dateimanager', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'SSH-Remote-Host', + openWithSettingsSshDesc: 'Leer = lokaler Arbeitsbereich; bei Angabe von user@host oder eines SSH-Alias verwenden die VSCode-Familienöffner das vscode-remote/ssh-remote-Protokoll, und Dateimanager / Zed / benutzerdefinierte Editoren außerhalb der VSCode-Familie werden im Menü ausgeblendet', + openWithSettingsSshPlaceholder: 'user@host oder SSH-Alias', + openWithSettingsCustomTitle: 'Benutzerdefinierte Editoren', + openWithSettingsCustomDesc: 'Name + URL-Vorlage ({path}-Platzhalter) + VSCode-Familien-Kennzeichen; im SSH-Modus können nur Editoren der VSCode-Familie Remote-Pfade öffnen', + openWithSettingsAdd: 'Hinzufügen', + openWithSettingsName: 'Name', + openWithSettingsTemplate: 'z. B. cursor://file/{path}', + openWithSettingsFamily: 'VSCode-Familie', + openWithSettingsFamilyDesc: 'Dieser Editor spricht das VSCode-URL-Protokoll (unterstützt SSH-Remote-Öffnen)', + openWithSettingsRemove: 'Entfernen', + openWithSettingsInvalidHint: 'Editoren ohne Namen oder mit Vorlage ohne {path} / scheme:// erscheinen nicht im Menü', + newTab: 'Neuer Tab', + openExplorer: 'Explorer', + brokenSymlink: 'Defekter Symlink', + openGit: 'Git-Panel', + newTerminal: 'Neues Terminal', + terminalLimit: 'Terminal-Limit erreicht (3)', + close: 'Schließen', + closeOtherTabs: 'Andere Tabs schließen', + closeLeftTabs: 'Tabs links schließen', + closeRightTabs: 'Tabs rechts schließen', + collapse: 'Seitenleiste einklappen', + expand: 'Seitenleiste ausklappen', + collapseBottomPanel: 'Unteres Panel einklappen', + expandBottomPanel: 'Unteres Panel ausklappen', + terminalError: 'Terminalverbindung fehlgeschlagen', + terminalConnectFailed: 'Terminal konnte wiederholt keine Verbindung herstellen', + terminalRetry: 'Erneut versuchen', + terminalDepsFailed: 'Die Terminal-Abhängigkeit node-pty konnte nicht geladen werden', + terminalDepsHint: 'Führen Sie den folgenden Befehl in einem Terminal oder in cmd auf dem DSH-System aus, um dies zu beheben, und klicken Sie dann auf „Erneut versuchen“ (node-pty bleibt mit der DSH-Core-Version synchron):', + terminalDepsProfile: ' (erkanntes Profil: {profile})', + preview: 'Vorschau', + edit: 'Bearbeiten', + mermaidError: 'Mermaid-Rendering fehlgeschlagen', + mermaidZoomIn: 'Vergrößern', + mermaidZoomOut: 'Verkleinern', + mermaidZoomReset: 'Zurücksetzen', + mermaidZoomHint: 'Scrollen zum Zoomen · Ziehen zum Verschieben · Esc zum Schließen', + refresh: 'Aktualisieren', + save: 'Speichern', + saved: 'Gespeichert', + unsaved: 'Nicht gespeichert', + saveFailed: 'Speichern fehlgeschlagen', + truncation: 'Datei zu groß – nur die ersten 512KB werden angezeigt', + binary: 'Binärdatei, Vorschau nicht verfügbar', + loading: 'Wird geladen…', + error: 'Laden fehlgeschlagen', + retry: 'Erneut versuchen', + splitLeft: 'Nach links teilen', + splitRight: 'Nach rechts teilen', + splitUp: 'Nach oben teilen', + splitDown: 'Nach unten teilen', + notRepo: 'Dieses Verzeichnis ist kein Git-Repository', + noChanges: 'Keine Änderungen', + stage: 'Stagen', + unstage: 'Unstagen', + stageAll: 'Alle stagen', + unstageAll: 'Alle unstagen', + commitPlaceholder: 'Commit-Nachricht (Ctrl+Enter)', + commit: 'Committen', + commitError: 'Commit fehlgeschlagen', + branch: 'Branch', + checkoutError: 'Branchenwechsel fehlgeschlagen', + history: 'Verlauf', + changes: 'Änderungen', + staged: 'Gestaged', + unstaged: 'Nicht gestaged', + cancel: 'Abbrechen', + diffEmpty: 'Keine Textunterschiede', + diffLoadError: 'Diff konnte nicht geladen werden', + diffBinary: 'Binär', + diffAdded: 'Hinzugefügt', + diffDeleted: 'Gelöscht', + diffRenamed: 'Umbenannt', + diffExpand: '{count} weitere Zeilen ausklappen', + diffCollapse: 'Einklappen', + discard: 'Änderungen verwerfen', + discardTitle: 'Änderungen verwerfen', + discardDesc: 'Dadurch werden die Arbeitsbereichsänderungen von „{path}“ verworfen (nicht wiederherstellbar).', + viewCommitDiff: 'Commit-Diff ansehen', + copyShortHash: 'Kurzen Hash kopieren', + copyFullHash: 'Vollständigen Hash kopieren', + copySubject: 'Commit-Titel kopieren', + revertCommit: 'Commit zurücknehmen', + revertTitle: 'Commit zurücknehmen', + revertDesc: 'Erstellt einen neuen Commit im aktuellen Branch, der „{subject}“ rückgängig macht.', + cherryPickCommit: 'Commit cherripicken', + cherryPickTitle: 'Commit cherripicken', + cherryPickDesc: 'Wendet die Änderungen von „{subject}“ auf den aktuellen Branch an.', + timeJustNow: 'gerade eben', + timeMinutesAgo: 'vor {n} Min.', + timeHoursAgo: 'vor {n} Std.', + timeYesterday: 'gestern', + loadMore: 'Mehr laden', + historyLoadError: 'Laden weiterer Verlaufseinträge fehlgeschlagen', + produced: 'Erstellt', + producedOpen: 'In der Seitenleiste öffnen', + disconnected: 'Terminalverbindung getrennt, Verbindung wird wiederhergestellt…', + exited: 'Terminalprozess beendet', + noSession: 'Wählen Sie eine Sitzung, um die Seitenleiste zu verwenden', + pluginNotLoaded: 'Plugin nicht geladen; Tab vorübergehend nicht verfügbar:', + hiddenFiles: 'Versteckte Dateien', + parent: 'Übergeordnetes Verzeichnis', + copied: 'Kopiert', + copy: 'Kopieren', + newFile: 'Neue Datei', + openEditor: 'Editor öffnen', + gitDetail: 'Änderungsdetails ansehen', + referenceFile: '@Datei', + addToConversation: 'Zur Unterhaltung hinzufügen', + copyRelative: 'Relativen Pfad kopieren', + copyAbsolute: 'Absoluten Pfad kopieren', + download: 'Herunterladen', + uploadFiles: 'Dateien hochladen', + uploadFolder: 'Ordner hochladen', + uploadHere: 'Hierher hochladen', + uploadDropHint: 'Dateien/Ordner hierher ziehen, um sie hochzuladen', + uploadDropChat: 'In den Chatbereich ziehen: Bilder zur Unterhaltung hinzufügen', + uploadTo: 'Nach {dir} hochladen', + uploadingTo: 'Wird nach {dir} hochgeladen…', + uploadProgress: 'Lade {done}/{total} hoch: {name}', + uploadDone: '{count} Dateien hochgeladen', + uploadFailed: 'Upload fehlgeschlagen: {error}', + uploadFailedUnknown: 'Unbekannter Fehler', + uploadTooLarge: 'Datei zu groß (über dem Upload-Limit)', + uploadCancelled: 'Upload abgebrochen', + settingsNav: 'Seitenkarte', + settingsIntro: 'Verwalten Sie, was die Seitenkarte anzeigt und wie sie sich verhält', + settingsPopupDesc: 'Optionen für „{feature}“ konfigurieren', + settingsDone: 'Fertig', + settingsOpenTitle: 'Für neue Unterhaltungen standardmäßig geöffnet', + settingsOpenDesc: 'Die Seitenkarte wird für brandneue Unterhaltungen automatisch ausgeklappt; bestehende Unterhaltungen behalten ihr eigenes Layout', + settingsWidthTitle: 'Standardbreite', + settingsWidthDesc: 'Standardanteil der Seitenkarte an der Fensterbreite für neue Unterhaltungen (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: 'Chat-Dateien in der Seitenleiste öffnen', + settingsOpenPathDesc: 'Dateilinks im Chat (Werkzeugzeilen, erstellte Dateien, Erwähnungen) werden im Seitenleisten-Editor geöffnet statt in der System-Standardanwendung', + settingsTitleBarTitle: 'Kompatibilitätsmodus der Position', + settingsTitleBarDesc: 'Kompatibilitätsschema der Titelleiste wählen: automatische Erkennung (Standard, konservativ) / offizielles DSH-Web / bekannte Desktop-Shells / benutzerdefiniert (Verschiebung + benutzerdefiniertes CSS)', + settingsTitleBarStripTitle: 'Verschiebungsabstand', + settingsTitleBarStripDesc: 'Höhe des Titelleisten-Streifens: um wie viele Pixel Seitenleisten-Buttons und -Inhalt nach unten rutschen (0–120, Standard 40; wirkt beim benutzerdefinierten Schema)', + settingsSchemeAutoTitle: 'Automatische Erkennung', + settingsSchemeAutoDesc: 'Konservativ: nur die Standard-API „Window Controls Overlay“ trägt bei (echte Caption-Overlay-Höhe); reine Web-Umgebungen erhalten keine Anpassung', + settingsSchemeWebTitle: 'Offizielles DSH-Web', + settingsSchemeWebDesc: 'Explizit die offizielle Webversion erklären: keinerlei Anpassung (nicht einmal die Standard-WCO-Geometrie)', + settingsSchemeCustomTitle: 'Benutzerdefiniert', + settingsSchemeCustomDesc: 'Volle Kontrolle: benutzerdefiniertes CSS einspielen (kann eingebaute Stile überschreiben) und den Verschiebungsabstand der Titelleiste festlegen', + settingsSchemeDetectedSuffix: 'erkannt', + settingsCustomCssTitle: 'Benutzerdefiniertes CSS', + settingsCustomCssDesc: 'Am Seitenende angehängte Stile (bei gleicher Priorität gewinnt der spätere; zum Überschreiben von JS-Inline-Variablen ist !important nötig)', + settingsCustomCssPlaceholder: '/* z. B. 36px für eine Shell mit selbst gezeichneter Titelleiste reservieren */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: 'Speichern fehlgeschlagen', + settingsConflict: 'Die Einstellung wurde in einem anderen Fenster geändert – bitte erneut versuchen', + binaryNoPreview: 'Dieser Dateityp kann nicht in der Vorschau angezeigt werden', + downloadToView: 'Zum Ansehen herunterladen', + settingsSubagentTitle: 'Aufgaben-Seite bei einem Subagenten automatisch öffnen', + settingsSubagentDesc: 'Die Seitenkarte wird ausgeklappt und die Aufgaben-Seite geöffnet, wenn die aktuelle Unterhaltung einen neuen Subagenten erzeugt; ausschalten, um sie manuell zu öffnen', + settingsJobsTitle: 'Aufgaben-Seite bei einer neuen Hintergrundaufgabe automatisch öffnen', + settingsJobsDesc: 'Die Seitenkarte wird ausgeklappt und die Aufgaben-Seite geöffnet, sobald für die aktuelle Unterhaltung eine neue Hintergrundaufgabe erscheint (jede neue Aufgabe löst dies aus); ausschalten, um sie manuell zu öffnen', + settingsToolsTitle: 'Terminal-Werkzeuge für das Modell bereitstellen', + settingsToolsDesc: 'Wenn aktiviert, kann das Modell über die 8 terminal_*-Werkzeuge Terminale in der Seitenleiste erstellen und steuern (standardmäßig deaktiviert)', + settingsBottomTerminalTitle: 'Beim ersten Ausklappen des unteren Panels automatisch ein Terminal öffnen', + settingsBottomTerminalDesc: 'Wird das untere Panel in einer Sitzung zum ersten Mal ausgeklappt, wird dort versucht, einen neuen Terminal-Tab zu öffnen (das Terminal-Kontingent gilt weiterhin; standardmäßig aktiviert)', + settingsFontFamilyTitle: 'Terminal-Schriftart', + settingsFontFamilyDesc: 'Benutzerdefinierte Terminal-Schriftfamilie (ein CSS-font-family-Stapel wie "JetBrains Mono", monospace; leer lassen, um der Monospace-Schrift des Themas zu folgen)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: 'Terminal-Schriftgröße', + settingsFontSizeDesc: 'Terminal-Schriftgröße in px (9–32, Standard 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'Shell-Pfad', + settingsShellDesc: 'Shell für UI- und Modell-Terminals (absoluter Pfad oder ausführbarer Name). Leer lassen für die bestehende Reihenfolge: config.shell aus der yaml → $SHELL / Login-Shell / powershell.exe unter Windows. Wirkt für danach geöffnete Terminals', + settingsShellPlaceholder: 'z. B. /bin/zsh (leer = automatisch)', + settingsShellArgsTitle: 'Shell-Argumente', + settingsShellArgsDesc: 'Explizite Shell-Startargumente, durch Leerzeichen getrennt; wenn nicht leer, ersetzen sie die Standardargumente vollständig (gleicher Vertrag wie shellArgs in der yaml)', + settingsShellArgsPlaceholder: 'z. B. -l (leer = Standardargumente)', + settingsTabsTitle: 'Seitenleisten-Inhalt', + settingsViewersTitle: 'Datei-Viewer', + settingsGeneralTitle: 'Allgemein', + settingsPopup: 'Funktionseinstellungen', + settingsViewerCatchAll: 'Catch-all: beliebige Datei', + viewerImage: 'Bild', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: 'Code', + viewerBinary: 'Binär-Download', + viewerHtml: 'HTML', + browser: 'Browser', + browserPlaceholder: 'URL eingeben, z. B. example.com', + browserGo: 'Los', + browserBack: 'Zurück', + browserForward: 'Vor', + browserStart: 'URL eingeben, um mit dem Browsen zu beginnen (Sandbox-Modus)', + browserBlockedScheme: 'Blockiert: nur http/https-Links sind erlaubt', + browserBlockedLoopback: 'Blockiert: lokale und interne Adressen können hier nicht aufgerufen werden', + browserInvalid: 'Ungültige URL', + browserNoSandboxWarning: 'Sandbox aus: Die aktuelle Seite läuft mit vollen Benutzeroberflächen-Rechten (in den Einstellungen wieder aktivierbar)', + htmlNoSandboxWarning: 'Sandbox aus: Dieses HTML läuft mit vollen Benutzeroberflächen-Rechten (in den Einstellungen wieder aktivierbar)', + sandboxStatusOn: 'Sandbox-Modus: aktiviert · Seiten können weder auf die Daten der Oberfläche noch auf lokale Dateien zugreifen; Anmeldungen und Drittanbieter-Cookies funktionieren möglicherweise nicht', + sandboxUnlock: 'Vorübergehend deaktivieren (unsicher)', + sandboxRestore: 'Sandbox wiederherstellen', + settingsHtmlDefaultUnsafeTitle: 'HTML-Vorschauen standardmäßig ohne Sandbox öffnen (unsicher)', + settingsHtmlDefaultUnsafeDesc: 'Wenn aktiviert, startet jede neu geöffnete HTML-Vorschau ohne Sandbox (gleiche Herkunft wie die Oberfläche – sie kann Sitzungsdateien und interne APIs lesen); die Statuszeile bietet weiterhin eine einmalige Wiederherstellung', + settingsHtmlSandboxTitle: 'HTML-Vorschau-Sandbox deaktivieren (unsicher)', + settingsHtmlSandboxDesc: 'Ohne Sandbox läuft das angezeigte HTML mit der gleichen Herkunft wie die Oberfläche: Es kann Sitzungsdateien und lokalen Speicher lesen und interne APIs aufrufen. Nur für vollständig vertrauenswürdige Dateien aktivieren', + settingsBrowserSandboxTitle: 'Browser-Sandbox deaktivieren (unsicher)', + settingsBrowserSandboxDesc: 'Ohne Sandbox läuft jede besuchte Website mit der gleichen Herkunft wie die Oberfläche: Sie kann Sitzungsdaten lesen und sich als Ihre Anmeldung ausgeben. Nur für vollständig vertrauenswürdige Websites aktivieren', + settingsBrowserLinksTitle: 'Externe Links aus dem Chat in der Seitenleiste öffnen', + settingsBrowserLinksDesc: 'Wenn aktiviert, öffnet ein Klick auf einen externen Link im Chat oder in der Oberfläche die Seitenleiste statt eines neuen Fensters; HTTP und HTTPS werden getrennt über die Schalter unten gesteuert; Ctrl/Cmd-Klick umgeht dies immer', + settingsBrowserHttpTitle: 'HTTP-Seiten in der Seitenleiste öffnen', + settingsBrowserHttpDesc: 'Wenn aktiviert, öffnet ein Klick auf einen HTTP-Externlink im Chat oder in der Oberfläche die Seitenleiste (Plugin-Seiten mit urlTarget gewinnen); Ctrl/Cmd-Klick umgeht dies immer', + settingsBrowserHttpsTitle: 'HTTPS-Seiten in der Seitenleiste öffnen', + settingsBrowserHttpsDesc: 'Wenn aktiviert, öffnet ein Klick auf einen HTTPS-Externlink im Chat oder in der Oberfläche die Seitenleiste. Standardmäßig deaktiviert: Die meisten HTTPS-Sites verweigern die Einbettung, der Systembrowser ist der reibungslosere Standard', + browserOpenExternal: 'Im Browser öffnen', + browserEmbedBlocked: '{host} hat die Einbettung verweigert', + browserEmbedBlockedDesc: 'Die Site verbietet die Anzeige in anderen Seiten (X-Frame-Options / frame-ancestors) und kann daher nicht in der Seitenleiste geladen werden. Öffnen Sie sie stattdessen direkt im Browser.', + browserEmbedAnyway: 'Trotzdem laden', + subagent: 'Aufgaben', + openSubagent: 'Aufgaben', + subagentMainAgent: 'Hauptagent', + subagentEmpty: 'Keine Subagenten', + subagentEmptyDesc: 'Subagenten, die unter dem Hauptagenten erzeugt werden, erscheinen hier', + subagentRunning: 'Läuft', + subagentInactive: 'Inaktiv', + subagentModeOneShot: 'Einmalig', + subagentModeContinuable: 'Fortsetzbar', + subagentCount: '{count} Subagenten', + subagentCountRunning: '{count} Subagenten · {running} läuft', + subagentDiagCorrupt: 'Beschädigt', + subagentDiagUnsupported: 'Nicht unterstützt', + subagentDiagUnavailable: 'Nicht verfügbar', + subagentThinking: 'Denkt nach…', + sideChat: 'Seitenchat (beta)', + sideChatNew: 'Neuer Thread', + sideChatUntitled: 'Neuer Thread', + sideChatEmpty: 'Keine Seitenunterhaltungen', + sideChatEmptyDesc: 'Jede Seitenunterhaltung ist ein eigener Tab in der Tab-Leiste – sie erbt den Kontext der aktuellen Sitzung und wird nie Teil der Hauptunterhaltung', + sideChatCreating: 'Seitenunterhaltung wird erstellt…', + sideChatRetry: 'Erneut versuchen', + sideChatThreads: 'Thread wechseln / neu', + sideChatSave: 'Als neue Sitzung speichern', + sideChatSaveTitle: 'Diesen Thread in der Hauptsitzungsliste zu einer Top-Level-Sitzung erheben', + sideChatSaved: 'Als neue Sitzung gespeichert', + sideChatNoTurn: 'Das Speichern ist nach der ersten abgeschlossenen Runde verfügbar', + sideChatPendingDrop: 'Die letzte unbeantwortete Nachfrage wird in der gespeicherten Sitzung nicht enthalten sein', + sideChatFirstPlaceholder: 'Stellen Sie die erste Frage – der Kontext ist geerbt…', + sideChatComposerPlaceholder: 'Nachfrage stellen…', + sideChatThinking: 'Denkt vertieft…', + sideChatThink: 'Denkvorgang', + sideChatInjection: 'Kontext eingespielt', + sideChatSend: 'Senden', + sideChatCancel: 'Stoppen', + sideChatCancelTitle: 'Laufende Runde abbrechen (wartende Nachrichten bleiben erhalten)', + sideChatClose: 'Thread schließen', + sideChatCloseTitle: 'Den Agenten des Threads freigeben (Verlauf bleibt erhalten)', + sideChatError: 'Seitenchat-Fehler: {message}', + jobs: 'Hintergrundaufgaben', + jobsCount: '{count} Hintergrundaufgaben', + jobsCountRunning: '{count} Hintergrundaufgaben · {running} läuft', + jobStatusRunning: 'Läuft', + jobStatusStopping: 'Wird beendet', + jobStatusCompleted: 'Abgeschlossen', + jobStatusKilled: 'Beendet', + jobStatusFailed: 'Fehlgeschlagen', + jobDurationSeconds: '{seconds} s', + jobDurationMinutes: '{minutes} m {seconds} s', + jobDurationHours: '{hours} h {minutes} m', + jobViewOutput: 'Ausgabe ansehen', + jobHideOutput: 'Ausgabe ausblenden', + jobNoOutput: 'Noch keine Ausgabe', + jobNotReadYet: 'Warten, bis das Modell die Ausgabe dieser Aufgabe liest (nach Ausführung von job_output durch das Modell erscheint die Ausgabe hier)', + jobOutputTruncated: 'Ausgabe zu lang, gekürzt angezeigt', + jobOutputError: 'Ausgabe konnte nicht gelesen werden', + jobKill: 'Beenden', + jobKillConfirm: 'Zum Bestätigen erneut klicken', + jobKillError: 'Beenden fehlgeschlagen', + addPluginsTabCard: 'Tab-Plugins hinzufügen', + addPluginsTabCardDesc: 'Eine neue Seitenleisten-Seite registrieren', + addPluginsViewerCard: 'Vorschau-Plugins hinzufügen', + addPluginsViewerCardDesc: 'Eine Dateityp-Vorschau registrieren', + addPluginsTabDesc: 'Seitenleisten-Seiten (Tabs) können durch Plugins erweitert werden. Plugins registrieren sich über den ctx.betterSidebar-Dienst; ein Klick auf „Installieren“ kopiert den Installationsbefehl – fügen Sie ihn in einem Terminal ein, in dem Ihr DSH-Profil liegt, und führen Sie ihn aus.', + addPluginsViewerDesc: 'Datei-Viewer können durch Plugins erweitert werden. Plugins registrieren sich über den ctx.betterSidebar-Dienst; ein Klick auf „Installieren“ kopiert den Installationsbefehl – fügen Sie ihn in einem Terminal ein, in dem Ihr DSH-Profil liegt, und führen Sie ihn aus.', + addPluginsBrowseMore: 'Weitere Plugins auf GitHub durchsuchen (Topic: dsh-better-sidebar)', + addPluginsSearch: 'Nach Plugin-Name oder -Beschreibung suchen…', + addPluginsNoMatch: 'Keine passenden Plugins', + addPluginsRecommended: 'Empfohlene Plugins', + addPluginsEmpty: 'Noch keine Plugins katalogisiert – veröffentlichen Sie Ihre Plugin unter dem GitHub-Topic', + openPlugin: 'Öffnen', + copyInstall: 'Installationsbefehl kopieren', + pluginOfficeDesc: 'Office-Suite-Vorschau (.docx / .xlsx / .pptx) für den better-sidebar-Editor, die die schweren Office-Render-Bibliotheken aus dem Kernbundle heraushält', + pluginFlowglassDesc: 'Live-Sitzungsflussdiagramm: dreispurige Darstellung von Benutzer, Assistent und Werkzeugaufrufen mit parallelen Gruppen, Subagent-Zweigen, Drill-down und Live-Status; registriert bei installiertem better-sidebar einen nativen „Flowglass“-Tab und behält sonst eine eigenständige Schublade', + pluginGitForgeDesc: '„Git-Anmeldedaten“-Tab: Konto-Bibliothek für Forges wie GitHub/Gitea + projektbezogene Freigaben + harte Push-Richtlinie; Tokens liegen nur in lokalen Secrets, nie im Modellkontext; bietet ein schreibgeschütztes GitForge-Werkzeug und einen HTTPS-Credential-Helper für den Agenten', + pluginGitRemotesDesc: '„Git-Remotes“-Tab: Branches/Upstream/ahead-behind ansehen, fetch (optional prune), ff-only pull und push erst nach Bestätigung im Tab. Ersetzt nicht den eingebauten Stagen/Commit-Tab und bietet weder force-push noch automatisches Push-Werkzeug für das Modell', + pluginSentinelDesc: 'Bedingungsgesteuertes Wecksystem für Agenten: Datei-/Prozess-/Port-/HTTP-/Befehls-/Webhook-Sensoren wecken ruhende Sitzungen, wenn Bedingungen zutreffen; registriert einen „Sentinel“-Tab mit der serverweiten Überwachungstabelle', + pluginSidebarQaDesc: 'Auswählen-und-Fragen mit Tab-Aufteilung: Text in der Unterhaltung auswählen → rechts im Panel fragen → eine eigene Folgesitzung (❓Nachfrage) im selben Arbeitsbereich; ein schnelles Modell ohne Denkvorgang komprimiert den Hauptkontext und spielt ihn samt Zitat ein, ohne die Hauptunterhaltung zu unterbrechen. Nachfragen lassen sich verschachteln, fortsetzen und archivieren', + pluginSshTunnelDesc: '„SSH-Tunnel“-Tab: Multi-Host-Inventar + projektbezogene Freigaben + lokale Schlüsselverwahrung; Modellwerkzeug SSHManager (exec/SFTP/Sitzungsstrategien); zentrales interaktives Terminal und zweispaltiges SFTP', + pluginTurnReviewDesc: 'Eine menschliche Freigabestufe für den Diff der „gerade abgeschlossenen Runde“: Approve / Request changes pro Pfad mit optionalem Kommentar; Pfade gruppiert nach Hauptsitzung / Subagent / nicht zugeordnet; Inline-Diff von Snapshot-vs-jetzt, bevor Sie entscheiden. Kein Fork, kein /rewind', + pluginVideoPreviewDesc: 'Inline-Videovorschau (.mp4/.webm/.mov/.mkv/.avi usw.) für den better-sidebar-Editor, gestützt auf eine eigene /video-Hostroute mit HTTP-Range-Unterstützung (206) – das Scrubbing funktioniert und Dateien unterliegen nicht dem 20MB-mediaLimit', + pluginDocsPanelDesc: '„Globale Dokumente“ in der DSH-Seitenleiste: eigene Markdown-Notizen aus jedem Arbeitsbereich lesen – Dateiliste, Gliederung, Öffnen in Chrome / VS Code und Kopieren-Buttons; das Dokumentenverzeichnis ist konfigurierbar (Standard ~/.dsh/docs)', +} diff --git a/src/client/locales-fr.ts b/src/client/locales-fr.ts new file mode 100644 index 0000000..3bc2de8 --- /dev/null +++ b/src/client/locales-fr.ts @@ -0,0 +1,338 @@ +/** + * French translation of the better-sidebar copy. + * + * Mirrors the key set of the zh dictionary in `locales.ts` (enforced by + * the `Record` type annotation). The better-locale + * override store registers this dict under the `betterSidebar` namespace, + * so it takes effect when the user has selected the `fr` override. + */ + +/** fr dictionary for the `betterSidebar` namespace. */ +export const fr: Record = { + files: 'Fichiers', + explorer: 'Explorateur', + git: 'Gestion de code source', + terminal: 'Terminal', + editor: 'Éditeur', + editorExplorer: 'Comportement d’ouverture des fichiers', + editorExplorerDesc: 'Contrôle la façon dont les fichiers s’ouvrent', + editorExplorerMerged: 'Fusionné', + editorExplorerMergedDesc: 'Les fichiers se remplacent dans la même fenêtre ; les nouvelles fenêtres ouvrent l’arborescence par défaut', + editorExplorerSplit: 'Séparé', + editorExplorerSplitDesc: 'Les fenêtres sans chemin sont l’explorateur autonome (arborescence uniquement) ; chaque fichier ouvre sa propre fenêtre (avec arborescence, réduite par défaut)', + editorTreeToggle: 'Panneau d’arborescence', + editorPathPlaceholder: 'Saisissez un chemin de fichier (relatif au répertoire de session ou absolu), Entrée pour ouvrir', + editorSearchPlaceholder: 'Rechercher par nom de fichier…', + editorSearchNoResults: 'Aucun fichier correspondant', + editorSearchTruncated: 'Trop de résultats, seule une partie des correspondances est affichée', + editorEmptyHint: 'Choisissez un fichier dans l’arborescence à droite ou dans le champ de chemin ci-dessus pour commencer l’aperçu', + openFileNewTab: 'Ouvrir dans un nouvel onglet', + openFileSide: 'Ouvrir de côté', + openWithMenu: 'Ouvrir avec', + openWithSshSuffix: ' (SSH)', + pinOpenWith: 'Épingler au menu', + unpinOpenWith: 'Désépingler', + openWithExplorer: 'Explorateur de fichiers', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'Hôte distant SSH', + openWithSettingsSshDesc: 'Vide = espace de travail local ; avec un user@host ou un alias SSH, les ouvreurs de la famille VSCode passent aux protocoles vscode-remote/ssh-remote, et l’explorateur de fichiers / Zed / les éditeurs personnalisés hors famille VSCode sont masqués du menu', + openWithSettingsSshPlaceholder: 'user@host ou alias SSH', + openWithSettingsCustomTitle: 'Éditeurs personnalisés', + openWithSettingsCustomDesc: 'Nom + modèle d’URL (placeholder {path}) + famille VSCode ou non ; en mode SSH, seuls les éditeurs de la famille VSCode peuvent ouvrir un distant', + openWithSettingsAdd: 'Ajouter', + openWithSettingsName: 'Nom', + openWithSettingsTemplate: 'ex. cursor://file/{path}', + openWithSettingsFamily: 'Famille VSCode', + openWithSettingsFamilyDesc: 'Cet éditeur utilise le protocole d’URL de VSCode (prend en charge l’ouverture à distance via SSH)', + openWithSettingsRemove: 'Supprimer', + openWithSettingsInvalidHint: 'Les éditeurs sans nom ou sans modèle (contenant {path} et commençant par scheme://) n’apparaissent pas dans le menu', + newTab: 'Nouvel onglet', + openExplorer: 'Explorateur', + brokenSymlink: 'Lien symbolique cassé', + openGit: 'Panneau Git', + newTerminal: 'Nouveau terminal', + terminalLimit: 'Nombre maximal de terminaux atteint (3)', + close: 'Fermer', + closeOtherTabs: 'Fermer les autres onglets', + closeLeftTabs: 'Fermer les onglets à gauche', + closeRightTabs: 'Fermer les onglets à droite', + collapse: 'Réduire la barre latérale', + expand: 'Déployer la barre latérale', + collapseBottomPanel: 'Réduire le panneau inférieur', + expandBottomPanel: 'Déployer le panneau inférieur', + terminalError: 'Échec de la connexion au terminal', + terminalConnectFailed: 'Le terminal a échoué à se connecter à plusieurs reprises', + terminalRetry: 'Réessayer', + terminalDepsFailed: 'Échec du chargement de la dépendance terminal node-pty', + terminalDepsHint: 'Exécutez la commande suivante dans un terminal ou cmd de l’environnement DSH pour réparer, puis cliquez sur Réessayer (node-pty reste à la même version que le cœur DSH) :', + terminalDepsProfile: ' (profil détecté : {profile})', + preview: 'Aperçu', + edit: 'Modifier', + mermaidError: 'Échec du rendu Mermaid', + mermaidZoomIn: 'Agrandir', + mermaidZoomOut: 'Réduire', + mermaidZoomReset: 'Réinitialiser', + mermaidZoomHint: 'Molette pour zoomer · glisser pour déplacer · Échap pour fermer', + refresh: 'Actualiser', + save: 'Enregistrer', + saved: 'Enregistré', + unsaved: 'Non enregistré', + saveFailed: 'Échec de l’enregistrement', + truncation: 'Fichier trop volumineux, seuls les 512 premiers Ko sont affichés', + binary: 'Fichier binaire, aperçu impossible', + loading: 'Chargement…', + error: 'Échec du chargement', + retry: 'Réessayer', + splitLeft: 'Diviser à gauche', + splitRight: 'Diviser à droite', + splitUp: 'Diviser en haut', + splitDown: 'Diviser en bas', + notRepo: 'Ce répertoire n’est pas un dépôt git', + noChanges: 'Aucune modification', + stage: 'Mettre en scène', + unstage: 'Annuler la mise en scène', + stageAll: 'Tout mettre en scène', + unstageAll: 'Tout retirer de la scène', + commitPlaceholder: 'Message de commit (Ctrl+Entrée)', + commit: 'Valider', + commitError: 'Échec du commit', + branch: 'Branche', + checkoutError: 'Échec du changement de branche', + history: 'Historique', + changes: 'Modifications', + staged: 'En scène', + unstaged: 'Hors scène', + cancel: 'Annuler', + diffEmpty: 'Aucune différence textuelle', + diffLoadError: 'Échec du chargement de la différence', + diffBinary: 'Binaire', + diffAdded: 'Ajouté', + diffDeleted: 'Supprimé', + diffRenamed: 'Renommé', + diffExpand: 'Déployer les {count} lignes restantes', + diffCollapse: 'Réduire', + discard: 'Abandonner les modifications', + discardTitle: 'Abandonner les modifications', + discardDesc: 'Les modifications de l’espace de travail de « {path} » seront abandonnées (irréversible).', + viewCommitDiff: 'Voir la différence du commit', + copyShortHash: 'Copier le hash court', + copyFullHash: 'Copier le hash complet', + copySubject: 'Copier le message du commit', + revertCommit: 'Annuler ce commit', + revertTitle: 'Annuler ce commit', + revertDesc: 'Un nouveau commit inversant « {subject} » sera créé sur la branche actuelle.', + cherryPickCommit: 'Cherry-pick de ce commit', + cherryPickTitle: 'Cherry-pick de ce commit', + cherryPickDesc: 'Les modifications de « {subject} » seront appliquées à la branche actuelle.', + timeJustNow: 'à l’instant', + timeMinutesAgo: 'il y a {n} min', + timeHoursAgo: 'il y a {n} h', + timeYesterday: 'hier', + loadMore: 'Charger plus', + historyLoadError: 'Échec du chargement de davantage d’historique', + produced: 'Produits de cette exécution', + producedOpen: 'Ouvrir dans la barre latérale', + disconnected: 'Connexion du terminal perdue, reconnexion…', + exited: 'Le processus du terminal s’est terminé', + noSession: 'Sélectionnez une session pour utiliser la barre latérale', + pluginNotLoaded: 'Plugin non chargé, onglet indisponible pour le moment :', + hiddenFiles: 'Fichiers cachés', + parent: 'Répertoire parent', + copied: 'Copié', + copy: 'Copier', + newFile: 'Nouveau fichier', + openEditor: 'Ouvrir l’éditeur', + gitDetail: 'Voir le détail des modifications', + referenceFile: '@fichier', + addToConversation: 'Ajouter à la discussion', + copyRelative: 'Copier le chemin relatif', + copyAbsolute: 'Copier le chemin absolu', + download: 'Télécharger', + uploadFiles: 'Importer des fichiers', + uploadFolder: 'Importer un dossier', + uploadHere: 'Importer ici', + uploadDropHint: 'Glissez des fichiers/dossiers ici pour les importer', + uploadDropChat: 'Glissez dans la zone de discussion : ajouter des images à la discussion', + uploadTo: 'Importer dans {dir}', + uploadingTo: 'Import en cours vers {dir}…', + uploadProgress: 'Import de {done}/{total} : {name}', + uploadDone: '{count} fichier(s) importé(s)', + uploadFailed: 'Échec de l’import : {error}', + uploadFailedUnknown: 'Erreur inconnue', + uploadTooLarge: 'Fichier trop volumineux, limite d’import dépassée', + uploadCancelled: 'Import annulé', + settingsNav: 'Carte latérale', + settingsIntro: 'Gérer le contenu affiché par la carte latérale et son comportement par défaut', + settingsPopupDesc: 'Configurer les options liées à « {feature} »', + settingsDone: 'Terminé', + settingsOpenTitle: 'Ouvert par défaut pour les nouvelles sessions', + settingsOpenDesc: 'Déployer automatiquement la carte latérale lors de la création d’une session ; les sessions existantes conservent chacune leur disposition', + settingsWidthTitle: 'Part de largeur par défaut', + settingsWidthDesc: 'Pourcentage de la largeur de la fenêtre occupé par la carte latérale pour les nouvelles sessions (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: 'Ouvrir les fichiers de discussion dans la barre latérale', + settingsOpenPathDesc: 'À la place de l’application par défaut du système, ouvrir dans l’éditeur de la barre latérale les liens vers les fichiers du chat (lignes d’outils, listes de produits, mentions de fichiers)', + settingsTitleBarTitle: 'Mode de compatibilité de position', + settingsTitleBarDesc: 'Choisissez le schéma de compatibilité de la barre de titre : détection automatique (par défaut, conservateur) / Web officiel DSH / coquilles de bureau connues / schéma personnalisé (distance de décalage + CSS personnalisé)', + settingsTitleBarStripTitle: 'Distance de décalage', + settingsTitleBarStripDesc: 'Hauteur de la bande de la barre de titre : nombre de pixels dont les boutons et le contenu de la barre latérale descendent (0–120, défaut 40 ; s’applique en schéma personnalisé)', + settingsSchemeAutoTitle: 'Détection automatique', + settingsSchemeAutoDesc: 'Schéma conservateur : ne cède de la place selon la hauteur réelle de la barre de titre que lorsque l’API standard Window Controls Overlay est disponible ; aucune modification dans un environnement web', + settingsSchemeWebTitle: 'Web officiel DSH', + settingsSchemeWebDesc: 'Déclare explicitement l’exécution dans la version web officielle : aucune adaptation (même la géométrie standard WCO n’est pas appliquée)', + settingsSchemeCustomTitle: 'Schéma personnalisé', + settingsSchemeCustomDesc: 'Entièrement à votre contrôle : injecter du CSS personnalisé (pouvant remplacer les styles intégrés) et définir la distance de décalage de la barre de titre', + settingsSchemeDetectedSuffix: 'détecté', + settingsCustomCssTitle: 'CSS personnalisé', + settingsCustomCssDesc: 'Styles ajoutés à la fin de la page (à priorité égale, le dernier écrit gagne ; utilisez !important pour remplacer les variables en ligne écrites par JS)', + settingsCustomCssPlaceholder: '/* ex. : réserver 36px pour une coquille à barre de titre dessinée */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: 'Échec de l’enregistrement', + settingsConflict: 'Les réglages ont été modifiés par une autre fenêtre, veuillez réessayer', + binaryNoPreview: 'Ce type de fichier ne prend pas en charge l’aperçu', + downloadToView: 'Télécharger pour consulter', + settingsSubagentTitle: 'Déployer automatiquement la page de gestion des tâches à la détection d’un sous-agent', + settingsSubagentDesc: 'Lorsque la session actuelle produit un nouveau sous-agent, déployer automatiquement la barre latérale et ouvrir la page de gestion des tâches ; une fois désactivé, l’ouverture est manuelle', + settingsJobsTitle: 'Déployer automatiquement la page des tâches d’arrière-plan sur nouvelle tâche', + settingsJobsDesc: 'Lorsque la session actuelle produit une nouvelle tâche d’arrière-plan, déployer automatiquement la barre latérale et ouvrir la page des tâches (déclenché à chaque nouvelle tâche) ; une fois désactivé, l’ouverture est manuelle', + settingsToolsTitle: 'Injecter des outils de terminal au modèle', + settingsToolsDesc: 'Une fois activé, le modèle peut créer et piloter des terminaux de la barre latérale via les 8 outils terminal_* (désactivé par défaut)', + settingsBottomTerminalTitle: 'Ouvrir automatiquement un terminal au premier déploiement du panneau inférieur', + settingsBottomTerminalDesc: 'Lors du premier déploiement du panneau inférieur dans une session, tenter d’y ouvrir automatiquement un nouvel onglet de terminal (la limite du nombre de terminaux s’applique toujours ; activé par défaut)', + settingsFontFamilyTitle: 'Police du terminal', + settingsFontFamilyDesc: 'Famille de polices personnalisée du terminal (CSS font-family, ex. "JetBrains Mono", monospace ; vide = suit la police monospace du thème)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: 'Taille de police du terminal', + settingsFontSizeDesc: 'Taille de police du terminal (9–32, défaut 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'Chemin du shell', + settingsShellDesc: 'Shell lancé pour les terminaux de l’interface et du modèle (chemin absolu ou nom d’exécutable). Vide = résolution dans l’ordre existant : config.shell du yaml → $SHELL / shell de connexion / powershell.exe sur Windows. S’applique aux terminaux ouverts ensuite', + settingsShellPlaceholder: 'ex. /bin/zsh (vide = résolution automatique)', + settingsShellArgsTitle: 'Arguments du shell', + settingsShellArgsDesc: 'Arguments explicites de lancement du shell, séparés par des espaces ; non vide = remplacement complet des arguments par défaut (contrat identique aux shellArgs du yaml)', + settingsShellArgsPlaceholder: 'ex. -l (vide = arguments par défaut)', + settingsTabsTitle: 'Contenu de la barre latérale', + settingsViewersTitle: 'Aperçus de fichiers', + settingsGeneralTitle: 'Général', + settingsPopup: 'Réglages de la fonctionnalité', + settingsViewerCatchAll: 'Par défaut : n’importe quel fichier', + viewerImage: 'Image', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: 'Code', + viewerBinary: 'Téléchargement binaire', + viewerHtml: 'HTML', + browser: 'Navigateur', + browserPlaceholder: 'Saisissez une adresse, ex. example.com', + browserGo: 'Aller', + browserBack: 'Précédent', + browserForward: 'Suivant', + browserStart: 'Saisissez une adresse pour commencer à naviguer (mode bac à sable)', + browserBlockedScheme: 'Bloqué : seuls les liens http/https sont pris en charge', + browserBlockedLoopback: 'Bloqué : l’accès aux adresses locales ou internes n’est pas autorisé dans le navigateur', + browserInvalid: 'Adresse invalide', + browserNoSandboxWarning: 'Bac à sable désactivé : la page actuelle partage l’origine de l’interface et dispose de l’ensemble des droits de session (restauration possible dans les réglages)', + htmlNoSandboxWarning: 'Bac à sable désactivé : ce HTML partage l’origine de l’interface, peut lire les fichiers de session et les interfaces internes (restauration possible dans les réglages)', + sandboxStatusOn: 'Mode bac à sable : activé · la page ne peut pas accéder aux données de l’interface ni aux fichiers locaux ; l’état de connexion et les cookies tiers peuvent être indisponibles', + sandboxUnlock: 'Déverrouiller temporairement (non sécurisé)', + sandboxRestore: 'Restaurer le bac à sable', + settingsHtmlDefaultUnsafeTitle: 'Ouvrir l’aperçu HTML en mode non bac à sable par défaut (non sécurisé)', + settingsHtmlDefaultUnsafeDesc: 'Une fois activé, chaque ouverture d’un fichier HTML démarre l’aperçu en état non bac à sable (même origine que l’interface, pouvant lire les fichiers de session et les interfaces internes) ; la barre d’état permet de restaurer temporairement le bac à sable', + settingsHtmlSandboxTitle: 'Désactiver le bac à sable de l’aperçu HTML (non sécurisé)', + settingsHtmlSandboxDesc: 'Une fois désactivé, le HTML de l’aperçu s’exécute avec la même origine que l’interface, peut lire les fichiers de session, le stockage local et appeler les interfaces internes. À activer uniquement pour des fichiers entièrement fiables', + settingsBrowserSandboxTitle: 'Désactiver le bac à sable du navigateur (non sécurisé)', + settingsBrowserSandboxDesc: 'Une fois désactivé, tout site visité s’exécute avec la même origine que l’interface, peut lire les données de session et usurper votre état de connexion. À activer uniquement pour des sites entièrement fiables', + settingsBrowserLinksTitle: 'Ouvrir les liens externes du chat dans la barre latérale', + settingsBrowserLinksDesc: 'Une fois activé, cliquer sur un lien externe dans le chat ou l’interface l’ouvre dans la barre latérale au lieu d’une nouvelle fenêtre ; HTTP et HTTPS sont contrôlés séparément par les interrupteurs ci-dessous ; Ctrl/Cmd+clic autorise temporairement', + settingsBrowserHttpTitle: 'Ouvrir les pages HTTP de côté', + settingsBrowserHttpDesc: 'Une fois activé, cliquer sur un lien externe HTTP du chat ou de l’interface l’ouvre dans la barre latérale (les pages de plugin déclarant urlTarget sont prioritaires) ; Ctrl/Cmd+clic autorise temporairement', + settingsBrowserHttpsTitle: 'Ouvrir les pages HTTPS de côté', + settingsBrowserHttpsDesc: 'Une fois activé, cliquer sur un lien externe HTTPS du chat ou de l’interface l’ouvre dans la barre latérale. Désactivé par défaut : la plupart des sites HTTPS refusent l’encapsulation, le navigateur système est plus fluide', + browserOpenExternal: 'Ouvrir dans le navigateur', + browserEmbedBlocked: '{host} a refusé la demande d’encapsulation', + browserEmbedBlockedDesc: 'Ce site interdit son affichage dans d’autres pages (X-Frame-Options / frame-ancestors) et ne peut donc pas être chargé dans la barre latérale. Vous pouvez l’ouvrir directement dans le navigateur', + browserEmbedAnyway: 'Charger quand même', + subagent: 'Gestion des tâches', + openSubagent: 'Gestion des tâches', + subagentMainAgent: 'Agent principal', + subagentEmpty: 'Aucun sous-agent pour l’instant', + subagentEmptyDesc: 'Les sous-agents dérivés de l’agent principal actuel s’afficheront ici', + subagentRunning: 'En cours', + subagentInactive: 'Inactif', + subagentModeOneShot: 'À usage unique', + subagentModeContinuable: 'Reprenable', + subagentCount: '{count} sous-agent(s)', + subagentCountRunning: '{count} sous-agent(s) · {running} en cours', + subagentDiagCorrupt: 'Répertoire corrompu', + subagentDiagUnsupported: 'Entrée non prise en charge', + subagentDiagUnavailable: 'Indisponible', + subagentThinking: 'Réflexion…', + sideChat: 'Discussion latérale (bêta)', + sideChatNew: 'Nouvelle discussion', + sideChatUntitled: 'Nouvelle discussion', + sideChatEmpty: 'Aucune discussion latérale pour l’instant', + sideChatEmptyDesc: 'Chaque discussion latérale est un onglet indépendant de la barre d’onglets, qui hérite du contexte de la session actuelle et n’entre jamais dans la session principale', + sideChatCreating: 'Création de la discussion latérale…', + sideChatRetry: 'Réessayer', + sideChatThreads: 'Changer de fil / nouveau', + sideChatSave: 'Enregistrer comme nouvelle session', + sideChatSaveTitle: 'Promouvoir ce fil en session de premier niveau, visible dans la liste des sessions principales', + sideChatSaved: 'Enregistré comme nouvelle session', + sideChatNoTurn: 'Au moins un tour de discussion doit être terminé avant l’enregistrement', + sideChatPendingDrop: 'La dernière relance inachevée ne sera pas incluse dans la nouvelle session', + sideChatFirstPlaceholder: 'Saisissez la première question, le contexte de la session actuelle est hérité…', + sideChatComposerPlaceholder: 'Relance…', + sideChatThinking: 'Approfondissement…', + sideChatThink: 'Processus de réflexion', + sideChatInjection: 'Contexte injecté', + sideChatSend: 'Envoyer', + sideChatCancel: 'Arrêter', + sideChatCancelTitle: 'Interrompre le tour en cours (la file d’attente est conservée)', + sideChatClose: 'Fermer le fil', + sideChatCloseTitle: 'Libérer l’agent du fil (l’historique est conservé)', + sideChatError: 'Erreur de la discussion latérale : {message}', + jobs: 'Tâches d’arrière-plan', + jobsCount: '{count} tâche(s) d’arrière-plan', + jobsCountRunning: '{count} tâche(s) d’arrière-plan · {running} en cours', + jobStatusRunning: 'En cours', + jobStatusStopping: 'Arrêt en cours', + jobStatusCompleted: 'Terminée', + jobStatusKilled: 'Interrompue', + jobStatusFailed: 'Échouée', + jobDurationSeconds: '{seconds} s', + jobDurationMinutes: '{minutes} min {seconds} s', + jobDurationHours: '{hours} h {minutes} min', + jobViewOutput: 'Voir la sortie', + jobHideOutput: 'Réduire la sortie', + jobNoOutput: 'Aucune sortie pour l’instant', + jobNotReadYet: 'En attente que le modèle lise la sortie de cette tâche (la sortie s’affichera ici une fois que le modèle aura exécuté job_output)', + jobOutputTruncated: 'Sortie trop longue, affichage tronqué', + jobOutputError: 'Échec de la lecture de la sortie', + jobKill: 'Interrompre', + jobKillConfirm: 'Cliquez à nouveau pour confirmer l’interruption', + jobKillError: 'Échec de l’interruption', + addPluginsTabCard: 'Ajouter un plugin d’onglet', + addPluginsTabCardDesc: 'Enregistrer une nouvelle page de la barre latérale', + addPluginsViewerCard: 'Ajouter un plugin d’aperçu', + addPluginsViewerCardDesc: 'Enregistrer un aperçu d’un type de fichier', + addPluginsTabDesc: 'Les pages de la barre latérale (onglets) peuvent être étendues par des plugins. Les plugins s’enregistrent via le service ctx.betterSidebar ; cliquez sur « Installer » pour copier la commande d’installation, collez-la dans un terminal de l’environnement DSH et exécutez-la.', + addPluginsViewerDesc: 'Les aperçus de fichiers peuvent être étendus par des plugins. Les plugins s’enregistrent via le service ctx.betterSidebar ; cliquez sur « Installer » pour copier la commande d’installation, collez-la dans un terminal de l’environnement DSH et exécutez-la.', + addPluginsBrowseMore: 'Parcourir plus de plugins sur GitHub (topic : dsh-better-sidebar)', + addPluginsSearch: 'Rechercher par nom / description de plugin…', + addPluginsNoMatch: 'Aucun plugin correspondant', + addPluginsRecommended: 'Plugins recommandés', + addPluginsEmpty: 'Aucun plugin référencé pour l’instant, publiez le vôtre sous le topic GitHub', + openPlugin: 'Aller', + copyInstall: 'Copier la commande d’installation', + pluginOfficeDesc: 'Aperçu de la suite Office (.docx / .xlsx / .pptx) pour l’éditeur better-sidebar, avec les lourdes bibliothèques de rendu Office extraites du package principal et installées à la demande', + pluginFlowglassDesc: 'Schéma de flux de session en temps réel : trois couloirs pour l’utilisateur, l’assistant et les appels d’outils, avec regroupement en parallèle, branches de sous-agents, exploration par niveau et états en temps réel ; enregistre l’onglet natif « Flowglass » une fois better-sidebar installé, sinon conserve un tiroir indépendant', + pluginGitForgeDesc: 'Onglet « Identifiants Git » de better-sidebar : bibliothèque de comptes GitHub/Gitea (et autres forges) + autorisations par projet + blocage strict des stratégies push ; les tokens restent dans les secrets locaux, jamais dans le contexte du modèle ; fournit un outil GitForge en lecture seule et un helper HTTPS de credentials pour l’agent', + pluginGitRemotesDesc: 'Onglet Git Remotes de better-sidebar : branches/amonts/ahead-behind, fetch (avec prune possible), pull en ff-only, push seulement après confirmation. Ne remplace pas la mise en scène/les commits du Git intégré et ne fournit pas de force-push ni de push automatique par le modèle', + pluginSentinelDesc: 'Système de réveil d’agent piloté par conditions : capteurs fichier/processus/port/HTTP/commande/webhook, les sessions en veille se réveillent automatiquement lorsque les conditions sont remplies ; enregistre l’onglet « Sentinel » affichant le tableau de surveillance global du serveur', + pluginSidebarQaDesc: 'Onglet de questions sur sélection basé sur better-sidebar : sélection dans la discussion → question dans le panneau de droite → session de relance indépendante du même espace de travail (❓ relance · thème) : un modèle rapide sans réflexion compresse le contexte de la discussion principale puis l’injecte avec la citation, sans interrompre la discussion principale ; les relances peuvent être imbriquées, poursuivies et archivées', + pluginSshTunnelDesc: 'Onglet « Tunnel SSH » de better-sidebar : inventaire multi-machines + autorisations par projet + clés conservées localement ; outil de modèle SSHManager (exec/SFTP/stratégies de session) ; terminal interactif central et SFTP à deux volets', + pluginTurnReviewDesc: 'Passerelle humaine sur le diff de « ce dernier tour » : Approve / Request changes, sans forker la session ; fichiers regroupés par session principale / sous-agent / non attribués, cochez les fichiers pour renvoyer + commentaire facultatif ; cliquez un fichier pour voir le diff entre l’instantané de début de tour et maintenant. Ce n’est pas /rewind', + pluginVideoPreviewDesc: 'Aperçu vidéo en ligne dans l’éditeur better-sidebar (.mp4/.webm/.mov/.mkv/.avi, etc.), avec une route hôte /video prenant en charge HTTP Range (206) ; barre de progression déplaçable, non limité par la mediaLimit de 20 Mo', + pluginDocsPanelDesc: '« Documentation globale » dans la barre latérale DSH : notes Markdown globales, lisibles depuis n’importe quel espace de travail — sélection dans la liste, saut via le plan flottant, ouverture externe Chrome / VS Code, copie de code, répertoire configurable (défaut ~/.dsh/docs)', +} diff --git a/src/client/locales-hi.ts b/src/client/locales-hi.ts new file mode 100644 index 0000000..c65772a --- /dev/null +++ b/src/client/locales-hi.ts @@ -0,0 +1,345 @@ +/** + * The hi (Hindi) dictionary for the betterSidebar namespace. + * + * Mirrors the key set of `zh` in `locales.ts`. The sidebar's `t()` + * consults this dict when `attachBetterLocale(store)` has been called + * with an active better-locale store whose `active` is `'hi'`; absent + * that, the existing zh/en chain runs unchanged. + * + * Translation conventions: + * - Technical terms (Git, SSH, HTTP, URL, Markdown, PDF, VS Code, API, etc.) stay in English. + * - Common dev-tool terms use Devanagari transliterations (टर्मिनल, ब्राउज़र, सैंडबॉक्स). + * - Git vocabulary follows English loanwords (स्टेज, कमिट, ब्रांच, चेरी-पिक). + * - Placeholders keep `{name}` verbatim (interpolation runs after lookup). + * - English brand names (VS Code, Cursor, Zed, SSH, Chrome) stay as-is. + */ + +/** The hi dictionary (key-set-equal to zh, enforced by the type annotation in locales.ts). */ +export const hi: Record = { + files: 'फ़ाइलें', + explorer: 'एक्सप्लोरर', + git: 'सोर्स कंट्रोल', + terminal: 'टर्मिनल', + editor: 'एडिटर', + editorExplorer: 'फ़ाइल खोलने का तरीका', + editorExplorerDesc: 'फ़ाइल खोलने के तरीके को नियंत्रित करें', + editorExplorerMerged: 'मर्ज किया', + editorExplorerMergedDesc: 'फ़ाइलें उसी विंडो में स्थान पर स्विच होती हैं; नई विंडो फ़ाइल ट्री खुला हुआ शुरू होती है', + editorExplorerSplit: 'अलग', + editorExplorerSplitDesc: 'पथ-रहित विंडो एक्सप्लोरर है (केवल ट्री); प्रत्येक फ़ाइल अपनी नई विंडो खोलती है (ट्री साथ, डिफ़ॉल्ट रूप से संक्षिप्त)', + editorTreeToggle: 'फ़ाइल ट्री पैनल', + editorPathPlaceholder: 'फ़ाइल पथ दर्ज करें (सत्र डायरेक्टरी के सापेक्ष या निरपेक्ष), Enter से खोलें', + editorSearchPlaceholder: 'फ़ाइल नाम से खोजें…', + editorSearchNoResults: 'कोई मेल खाती फ़ाइल नहीं', + editorSearchTruncated: 'परिणाम बहुत अधिक — आंशिक सूची दिखाई जा रही', + editorEmptyHint: 'पूर्वावलोकन शुरू करने के लिए दाएँ फ़ाइल ट्री या ऊपर पथ इनपुट से फ़ाइल चुनें', + openFileNewTab: 'नए टैब में खोलें', + openFileSide: 'बाजू में खोलें', + openWithMenu: 'इसके साथ खोलें', + openWithSshSuffix: ' (SSH)', + pinOpenWith: 'मेन्यू पर पिन करें', + unpinOpenWith: 'पिन हटाएं', + openWithExplorer: 'फ़ाइल मैनेजर', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'SSH रिमोट होस्ट', + openWithSettingsSshDesc: 'खाली = स्थानीय वर्कस्पेस; user@host या SSH उपनाम के साथ, VSCode-परिवार ओपनर vscode-remote/ssh-remote प्रोटोकॉल पर स्विच हो जाते हैं और फ़ाइल मैनेजर / Zed / ग़ैर-VSCode-परिवार कस्टम एडिटर मेन्यू से छिप जाते हैं', + openWithSettingsSshPlaceholder: 'user@host या SSH उपनाम', + openWithSettingsCustomTitle: 'कस्टम एडिटर', + openWithSettingsCustomDesc: 'नाम + URL टेम्पलेट ({path} प्लेसहोल्डर) + VSCode-परिवार फ़्लैग; रिमोट मोड में केवल VSCode-परिवार एडिटर रिमोट पथ खोल सकते हैं', + openWithSettingsAdd: 'जोड़ें', + openWithSettingsName: 'नाम', + openWithSettingsTemplate: 'जैसे cursor://file/{path}', + openWithSettingsFamily: 'VSCode-परिवार', + openWithSettingsFamilyDesc: 'यह एडिटर VSCode URL बोली बोलता है (SSH-रिमोट खोलने का समर्थन)', + openWithSettingsRemove: 'हटाएं', + openWithSettingsInvalidHint: 'नाम या {path} / scheme:// के बिना टेम्पलेट वाले एडिटर मेन्यू में नहीं दिखते', + newTab: 'नया टैब', + openExplorer: 'एक्सप्लोरर', + brokenSymlink: 'टूटा सिमलिंक', + openGit: 'Git पैनल', + newTerminal: 'नया टर्मिनल', + terminalLimit: 'टर्मिनल सीमा पहुँची (3)', + close: 'बंद करें', + closeOtherTabs: 'अन्य टैब बंद करें', + closeLeftTabs: 'बाएँ टैब बंद करें', + closeRightTabs: 'दाएँ टैब बंद करें', + collapse: 'साइडबार संक्षिप्त करें', + expand: 'साइडबार विस्तृत करें', + collapseBottomPanel: 'निचला पैनल संक्षिप्त करें', + expandBottomPanel: 'निचला पैनल विस्तृत करें', + terminalError: 'टर्मिनल कनेक्शन विफल', + terminalConnectFailed: 'टर्मिनल बार-बार कनेक्ट विफल', + terminalRetry: 'पुनः प्रयास', + terminalDepsFailed: 'टर्मिनल निर्भरता node-pty लोड विफल', + terminalDepsHint: 'DSH मशीन पर एक टर्मिनल या cmd में नीचे दिया गया कमांड चलाएँ, फिर पुनः प्रयास करें (node-pty DSH कोर संस्करण के साथ सिंक रहता है):', + terminalDepsProfile: ' (पहचाना गया प्रोफ़ाइल: {profile})', + preview: 'पूर्वावलोकन', + edit: 'संपादित करें', + mermaidError: 'Mermaid रेंडर विफल', + mermaidZoomIn: 'ज़ूम इन', + mermaidZoomOut: 'ज़ूम आउट', + mermaidZoomReset: 'रीसेट', + mermaidZoomHint: 'स्क्रॉल से ज़ूम · खींचें पैन करने · Esc से बंद', + refresh: 'ताज़ा करें', + save: 'सहेजें', + saved: 'सहेजा गया', + unsaved: 'असहेजित', + saveFailed: 'सहेजना विफल', + truncation: 'फ़ाइल बहुत बड़ी — पहले 512KB दिखाए जा रहे', + binary: 'बाइनरी फ़ाइल, पूर्वावलोकन अनुपलब्ध', + loading: 'लोड हो रहा…', + error: 'लोड विफल', + retry: 'पुनः प्रयास', + splitLeft: 'बाएँ स्प्लिट', + splitRight: 'दाएँ स्प्लिट', + splitUp: 'ऊपर स्प्लिट', + splitDown: 'नीचे स्प्लिट', + notRepo: 'यह डायरेक्टरी एक git रिपॉज़िटरी नहीं है', + noChanges: 'कोई बदलाव नहीं', + stage: 'स्टेज', + unstage: 'अनस्टेज', + stageAll: 'सभी स्टेज करें', + unstageAll: 'सभी अनस्टेज करें', + commitPlaceholder: 'कमिट संदेश (Ctrl+Enter)', + commit: 'कमिट', + commitError: 'कमिट विफल', + branch: 'ब्रांच', + checkoutError: 'ब्रांच स्विच विफल', + history: 'इतिहास', + changes: 'बदलाव', + staged: 'स्टेज किया', + unstaged: 'अनस्टेज', + cancel: 'रद्द करें', + diffEmpty: 'कोई पाठ बदलाव नहीं', + diffLoadError: 'डिफ लोड विफल', + diffBinary: 'बाइनरी', + diffAdded: 'जोड़ा', + diffDeleted: 'हटाया', + diffRenamed: 'नाम बदला', + diffExpand: '{count} और पंक्तियाँ विस्तृत करें', + diffCollapse: 'संक्षिप्त करें', + discard: 'बदलाव त्यागें', + discardTitle: 'बदलाव त्यागें', + discardDesc: 'यह "{path}" के वर्कट्री बदलाव त्याग देगा (पुनर्प्राप्त नहीं)।', + viewCommitDiff: 'कमिट डिफ देखें', + copyShortHash: 'शॉर्ट हैश कॉपी', + copyFullHash: 'पूर्ण हैश कॉपी', + copySubject: 'सब्जेक्ट कॉपी', + revertCommit: 'कमिट रिवर्ट', + revertTitle: 'कमिट रिवर्ट', + revertDesc: 'वर्तमान ब्रांच पर "{subject}" को रिवर्ट करता हुआ नया कमिट बनाएगा।', + cherryPickCommit: 'चेरी-पिक कमिट', + cherryPickTitle: 'चेरी-पिक कमिट', + cherryPickDesc: '"{subject}" के बदलाव वर्तमान ब्रांच पर लागू करेगा।', + timeJustNow: 'अभी', + timeMinutesAgo: '{n} मिनट पहले', + timeHoursAgo: '{n} घंटे पहले', + timeYesterday: 'कल', + loadMore: 'और लोड करें', + historyLoadError: 'और इतिहास लोड विफल', + produced: 'उत्पादित', + producedOpen: 'साइडबार में खोलें', + disconnected: 'टर्मिनल डिस्कनेक्ट हो गया, पुनः कनेक्ट हो रहा…', + exited: 'टर्मिनल प्रक्रिया बाहर निकली', + noSession: 'साइडबार उपयोग करने के लिए एक वार्तालाप चुनें', + pluginNotLoaded: 'प्लगइन लोड नहीं; टैब अनुपलब्ध:', + hiddenFiles: 'छिपी फ़ाइलें', + parent: 'मूल डायरेक्टरी', + copied: 'कॉपी हो गया', + copy: 'कॉपी', + newFile: 'नई फ़ाइल', + openEditor: 'एडिटर खोलें', + gitDetail: 'बदलाव विवरण देखें', + referenceFile: '@फ़ाइल', + addToConversation: 'वार्तालाप में जोड़ें', + copyRelative: 'सापेक्ष पथ कॉपी', + copyAbsolute: 'निरपेक्ष पथ कॉपी', + download: 'डाउनलोड', + uploadFiles: 'फ़ाइलें अपलोड करें', + uploadFolder: 'फ़ोल्डर अपलोड करें', + uploadHere: 'यहाँ अपलोड करें', + uploadDropHint: 'फ़ाइलें/फ़ोल्डर यहाँ छोड़कर अपलोड करें', + uploadDropChat: 'चैट पर छोड़ें: वार्तालाप में छवियाँ जोड़ें', + uploadTo: '{dir} में अपलोड करें', + uploadingTo: '{dir} में अपलोड हो रहा…', + uploadProgress: 'अपलोड हो रहा {done}/{total}: {name}', + uploadDone: '{count} फ़ाइल(ें) अपलोड हुई', + uploadFailed: 'अपलोड विफल: {error}', + uploadFailedUnknown: 'अज्ञात त्रुटि', + uploadTooLarge: 'फ़ाइल बहुत बड़ी (अपलोड सीमा से अधिक)', + uploadCancelled: 'अपलोड रद्द', + settingsNav: 'साइड कार्ड', + settingsIntro: 'साइड कार्ड क्या दिखाता है और कैसे व्यवहार करता है प्रबंधित करें', + settingsPopupDesc: '{feature} के लिए संबंधित विकल्प कॉन्फ़िगर करें', + settingsDone: 'पूर्ण', + settingsOpenTitle: 'नए वार्तालाप के लिए डिफ़ॉल्ट रूप से खोलें', + settingsOpenDesc: 'बिल्कुल नए वार्तालाप के लिए साइड कार्ड स्वतः विस्तृत करें; मौजूदा वार्तालाप अपना लेआउट रखते हैं', + settingsWidthTitle: 'डिफ़ॉल्ट चौड़ाई हिस्सा', + settingsWidthDesc: 'नए वार्तालाप के लिए साइड कार्ड की विंडो चौड़ाई का डिफ़ॉल्ट हिस्सा (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: 'चैट फ़ाइलें साइडबार में खोलें', + settingsOpenPathDesc: 'चैट में फ़ाइल लिंक (टूल पंक्ति, उत्पादित फ़ाइलें, उल्लेख) क्लिक करने पर सिस्टम डिफ़ॉल्ट ऐप के बजाय साइडबार एडिटर में खोलें', + settingsTitleBarTitle: 'स्थिति संगतता मोड', + settingsTitleBarDesc: 'टाइटल-बार संगतता योजना चुनें: ऑटो-डिटेक्ट (डिफ़ॉल्ट, रूढ़िवादी) / DSH आधिकारिक वेब / ज्ञात डेस्कटॉप शेल / कस्टम (शिफ्ट दूरी + कस्टम CSS)', + settingsTitleBarStripTitle: 'शिफ्ट दूरी', + settingsTitleBarStripDesc: 'टाइटल-बार स्ट्रिप ऊँचाई: साइडबार बटन और सामग्री कितने px नीचे जाते हैं (0–120, डिफ़ॉल्ट 40; कस्टम योजना के तहत लागू)', + settingsSchemeAutoTitle: 'ऑटो-डिटेक्ट', + settingsSchemeAutoDesc: 'रूढ़िवादी: केवल मानक Window Controls Overlay API योगदान देता है (वास्तविक कैप्शन-ओवरले ऊँचाई); सादे वेब परिवेश में कोई संशोधन नहीं', + settingsSchemeWebTitle: 'DSH आधिकारिक वेब', + settingsSchemeWebDesc: 'स्पष्ट रूप से आधिकारिक वेब UI घोषित करें: कोई अनुकूलन नहीं (मानक WCO ज्यामिति भी नहीं)', + settingsSchemeCustomTitle: 'कस्टम', + settingsSchemeCustomDesc: 'पूर्ण नियंत्रण: कस्टम CSS इंजेक्ट करें (अंतर्निहित शैलियाँ ओवरराइड कर सकते हैं) और टाइटल-बार शिफ्ट दूरी सेट करें', + settingsSchemeDetectedSuffix: 'पहचाना गया', + settingsCustomCssTitle: 'कस्टम CSS', + settingsCustomCssDesc: 'पृष्ठ के अंत में जोड़ी गई शैलियाँ (कैस्केड में बाद में टाई जीतता है; JS-लिखित इनलाइन चर ओवरराइड करने के लिए !important उपयोग करें)', + settingsCustomCssPlaceholder: '/* उदा.: कस्टम-तैयार टाइटल बार वाले शेल के लिए 36px आरक्षित करें */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: 'सहेजना विफल', + settingsConflict: 'सेटिंग दूसरी विंडो में बदली — कृपया पुनः प्रयास करें', + binaryNoPreview: 'इस फ़ाइल प्रकार का पूर्वावलोकन नहीं हो सकता', + downloadToView: 'देखने के लिए डाउनलोड करें', + settingsSubagentTitle: 'सबएजेंट दिखने पर स्वतः कार्य पृष्ठ खोलें', + settingsSubagentDesc: 'वर्तमान वार्तालाप में नया सबएजेंट बनने पर साइडबार विस्तृत करें और कार्य पृष्ठ खोलें; बंद करने पर मैन्युअल रूप से खोलें', + settingsJobsTitle: 'नया बैकग्राउंड कार्य आने पर स्वतः कार्य पृष्ठ खोलें', + settingsJobsDesc: 'वर्तमान वार्तालाप में नया बैकग्राउंड कार्य दिखने पर साइडबार विस्तृत करें और कार्य पृष्ठ खोलें (हर नया कार्य ट्रिगर करता है); बंद करने पर मैन्युअल रूप से खोलें', + settingsToolsTitle: 'मॉडल के लिए टर्मिनल टूल इंजेक्ट करें', + settingsToolsDesc: 'सक्षम होने पर, मॉडल 8 terminal_* टूल्स से साइडबार टर्मिनल बना और चला सकता है (डिफ़ॉल्ट रूप से बंद)', + settingsBottomTerminalTitle: 'निचला पैनल पहली बार खुलने पर स्वतः टर्मिनल खोलें', + settingsBottomTerminalDesc: 'सत्र में निचला पैनल पहली बार विस्तृत होने पर वहाँ नया टर्मिनल टैब खोलने का प्रयास (टर्मिनल कोटा लागू; डिफ़ॉल्ट रूप से चालू)', + settingsFontFamilyTitle: 'टर्मिनल फ़ॉन्ट परिवार', + settingsFontFamilyDesc: 'कस्टम टर्मिनल फ़ॉन्ट परिवार (CSS font-family स्टैक जैसे "JetBrains Mono", monospace; थीम के मोनोस्पेस फ़ॉन्ट का पालन करने के लिए खाली छोड़ें)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: 'टर्मिनल फ़ॉन्ट आकार', + settingsFontSizeDesc: 'टर्मिनल फ़ॉन्ट आकार px में (9–32, डिफ़ॉल्ट 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'Shell पथ', + settingsShellDesc: 'UI और मॉडल टर्मिनल के लिए शुरू किया गया shell (निरपेक्ष पथ या निष्पादन योग्य नाम)। खाली पुराना क्रम रखता है: yaml config.shell → $SHELL / लॉगिन shell / Windows powershell.exe। बाद में खुले टर्मिनल पर लागू', + settingsShellPlaceholder: 'जैसे /bin/zsh (खाली = ऑटो)', + settingsShellArgsTitle: 'Shell तर्क', + settingsShellArgsDesc: 'स्पष्ट shell तर्क, स्पेस से अलग; ग़ैर-खाली होने पर डिफ़ॉल्ट को पूरी तरह बदलें (yaml shellArgs के समान अनुबंध)', + settingsShellArgsPlaceholder: 'जैसे -l (खाली = डिफ़ॉल्ट)', + settingsTabsTitle: 'साइडबार सामग्री', + settingsViewersTitle: 'फ़ाइल दर्शक', + settingsGeneralTitle: 'सामान्य', + settingsPopup: 'सुविधा सेटिंग्स', + settingsViewerCatchAll: 'कैच-ऑल: कोई भी फ़ाइल', + viewerImage: 'छवि', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: 'कोड', + viewerBinary: 'बाइनरी डाउनलोड', + viewerHtml: 'HTML', + browser: 'ब्राउज़र', + browserPlaceholder: 'URL दर्ज करें, जैसे example.com', + browserGo: 'जाएं', + browserBack: 'पीछे', + browserForward: 'आगे', + browserStart: 'ब्राउज़िंग शुरू करने के लिए URL दर्ज करें (सैंडबॉक्स मोड)', + browserBlockedScheme: 'रोका गया: केवल http/https URL अनुमत हैं', + browserBlockedLoopback: 'रोका गया: स्थानीय और आंतरिक पते यहाँ ब्राउज़ नहीं किए जा सकते', + browserInvalid: 'अमान्य URL', + browserNoSandboxWarning: 'सैंडबॉक्स बंद: वर्तमान पृष्ठ GUI विशेषाधिकार के साथ चलता है (सेटिंग्स में पुनः सक्षम करें)', + htmlNoSandboxWarning: 'सैंडबॉक्स बंद: यह HTML GUI विशेषाधिकार के साथ चलता है (सेटिंग्स में पुनः सक्षम करें)', + sandboxStatusOn: 'सैंडबॉक्स मोड: चालू · पृष्ठ GUI के डेटा या स्थानीय फ़ाइलों तक नहीं पहुँच सकते; लॉगिन और थर्ड-पार्टी कुकीज़ काम नहीं कर सकतीं', + sandboxUnlock: 'अस्थायी रूप से अक्षम (असुरक्षित)', + sandboxRestore: 'सैंडबॉक्स पुनर्स्थापित करें', + settingsHtmlDefaultUnsafeTitle: 'HTML पूर्वावलोकन डिफ़ॉल्ट रूप से अनसैंडबॉक्स्ड खोलें (असुरक्षित)', + settingsHtmlDefaultUnsafeDesc: 'चालू होने पर, हर नया खुला HTML पूर्वावलोकन अनसैंडबॉक्स्ड स्थिति में शुरू होता है (GUI के समान मूल — सत्र फ़ाइलें और आंतरिक API पढ़ सकता है); स्थिति पंक्ति अभी भी एक-टैप पुनर्स्थापना देती है', + settingsHtmlSandboxTitle: 'HTML पूर्वावलोकन सैंडबॉक्स अक्षम करें (असुरक्षित)', + settingsHtmlSandboxDesc: 'सैंडबॉक्स बंद होने पर, पूर्वावलोकित HTML GUI के समान मूल के साथ चलता है: सत्र फ़ाइलें, स्थानीय स्टोरेज पढ़ सकता है और आंतरिक API कॉल कर सकता है। केवल पूर्ण विश्वसनीय फ़ाइलों के लिए सक्षम करें', + settingsBrowserSandboxTitle: 'ब्राउज़र सैंडबॉक्स अक्षम करें (असुरक्षित)', + settingsBrowserSandboxDesc: 'सैंडबॉक्स बंद होने पर, कोई भी विज़िट की गई साइट GUI के समान मूल के साथ चलती है: सत्र डेटा पढ़ सकती है और आपके लॉग-इन सत्र के रूप में कार्य कर सकती है। केवल पूर्ण विश्वसनीय साइटों के लिए सक्षम करें', + settingsBrowserLinksTitle: 'चैट बाहरी लिंक साइडबार में खोलें', + settingsBrowserLinksDesc: 'चालू होने पर, चैट या GUI में बाहरी लिंक क्लिक करने पर नई विंडो के बजाय साइडबार खुलता है; HTTP और HTTPS नीचे स्विच द्वारा अलग से नियंत्रित; Ctrl/Cmd+क्लिक हमेशा बायपास करता है', + settingsBrowserHttpTitle: 'HTTP पृष्ठ साइडबार में खोलें', + settingsBrowserHttpDesc: 'चालू होने पर, चैट या GUI में HTTP बाहरी लिंक क्लिक करने पर साइडबार खुलता है (urlTarget घोषित प्लगइन पृष्ठ जीतते हैं); Ctrl/Cmd+क्लिक हमेशा बायपास करता है', + settingsBrowserHttpsTitle: 'HTTPS पृष्ठ साइडबार में खोलें', + settingsBrowserHttpsDesc: 'चालू होने पर, चैट या GUI में HTTPS बाहरी लिंक क्लिक करने पर साइडबार खुलता है। डिफ़ॉल्ट रूप से बंद: अधिकांश HTTPS साइटें एम्बेड होने से इनकार करती हैं, सिस्टम ब्राउज़र चिकना डिफ़ॉल्ट है', + browserOpenExternal: 'ब्राउज़र में खोलें', + browserEmbedBlocked: '{host} एम्बेड होने से इनकार', + browserEmbedBlockedDesc: 'साइट अन्य पृष्ठों के अंदर प्रदर्शित होने से मना करती है (X-Frame-Options / frame-ancestors), इसलिए साइडबार में लोड नहीं हो सकती। इसे अपने ब्राउज़र में सीधे खोलें।', + browserEmbedAnyway: 'फिर भी लोड करें', + subagent: 'कार्य', + openSubagent: 'कार्य', + subagentMainAgent: 'मुख्य एजेंट', + subagentEmpty: 'कोई सबएजेंट नहीं', + subagentEmptyDesc: 'मुख्य एजेंट के अंतर्गत बने सबएजेंट यहाँ दिखेंगे', + subagentRunning: 'चल रहा', + subagentInactive: 'निष्क्रिय', + subagentModeOneShot: 'एक-बार', + subagentModeContinuable: 'जारी रखने योग्य', + subagentCount: '{count} सबएजेंट', + subagentCountRunning: '{count} सबएजेंट · {running} चल रहे', + subagentDiagCorrupt: 'दूषित', + subagentDiagUnsupported: 'असमर्थित', + subagentDiagUnavailable: 'अनुपलब्ध', + subagentThinking: 'सोच रहा…', + sideChat: 'साइड चैट (बीटा)', + sideChatNew: 'नया थ्रेड', + sideChatUntitled: 'नया थ्रेड', + sideChatEmpty: 'कोई साइड वार्तालाप नहीं', + sideChatEmptyDesc: 'हर साइड वार्तालाप टैब स्ट्रिप में अपना टैब है — यह वर्तमान सत्र के संदर्भ को विरासत में लेता है और कभी मुख्य वार्तालाप में नहीं जाता', + sideChatCreating: 'साइड वार्तालाप बन रहा…', + sideChatRetry: 'पुनः प्रयास', + sideChatThreads: 'थ्रेड स्विच / नया', + sideChatSave: 'नए सत्र के रूप में सहेजें', + sideChatSaveTitle: 'इस थ्रेड को मुख्य सत्र सूची में शीर्ष-स्तरीय सत्र में प्रमोट करें', + sideChatSaved: 'नए सत्र के रूप में सहेजा', + sideChatNoTurn: 'पहला टर्न पूरा होने के बाद सहेजना उपलब्ध', + sideChatPendingDrop: 'अंतिम अनुत्तरित फ़ॉलो-अप सहेजे गए सत्र में शामिल नहीं होगा', + sideChatFirstPlaceholder: 'पहला प्रश्न पूछें — संदर्भ विरासत में मिला…', + sideChatComposerPlaceholder: 'फ़ॉलो-अप पूछें…', + sideChatThinking: 'गहराई से विचार…', + sideChatThink: 'विचार', + sideChatInjection: 'संदर्भ इंजेक्ट किया', + sideChatSend: 'भेजें', + sideChatCancel: 'रोकें', + sideChatCancelTitle: 'चल रहे टर्न को रोकें (कतारबद्ध कार्य रखा जाता है)', + sideChatClose: 'थ्रेड बंद करें', + sideChatCloseTitle: 'थ्रेड का एजेंट रिलीज़ करें (इतिहास रखा जाता है)', + sideChatError: 'साइड चैट त्रुटि: {message}', + jobs: 'बैकग्राउंड कार्य', + jobsCount: '{count} बैकग्राउंड कार्य', + jobsCountRunning: '{count} बैकग्राउंड कार्य · {running} चल रहे', + jobStatusRunning: 'चल रहा', + jobStatusStopping: 'रुक रहा', + jobStatusCompleted: 'पूर्ण', + jobStatusKilled: 'समाप्त', + jobStatusFailed: 'विफल', + jobDurationSeconds: '{seconds}से', + jobDurationMinutes: '{minutes}मि {seconds}से', + jobDurationHours: '{hours}घं {minutes}मि', + jobViewOutput: 'आउटपुट देखें', + jobHideOutput: 'आउटपुट छिपाएं', + jobNoOutput: 'अभी कोई आउटपुट नहीं', + jobNotReadYet: 'मॉडल का इस कार्य का आउटपुट पढ़ने की प्रतीक्षा; मॉडल job_output चलाने पर आउटपुट यहाँ दिखेगा', + jobOutputTruncated: 'आउटपुट कटा हुआ', + jobOutputError: 'आउटपुट पढ़ना विफल', + jobKill: 'समाप्त', + jobKillConfirm: 'समाप्त की पुष्टि के लिए फिर क्लिक करें', + jobKillError: 'समाप्त विफल', + addPluginsTabCard: 'टैब प्लगइन जोड़ें', + addPluginsTabCardDesc: 'नया साइडबार पृष्ठ पंजीकृत करें', + addPluginsViewerCard: 'पूर्वावलोकन प्लगइन जोड़ें', + addPluginsViewerCardDesc: 'फ़ाइल-प्रकार पूर्वावलोकन पंजीकृत करें', + addPluginsTabDesc: 'साइडबार पृष्ठ (टैब) प्लगइन्स द्वारा विस्तारित हो सकते हैं। प्लगइन्स ctx.betterSidebar सेवा के माध्यम से पंजीकृत होते हैं; इंस्टॉल क्लिक करने पर इंस्टॉल कमांड कॉपी होता है — इसे उस टर्मिनल में पेस्ट करें जहाँ आपका DSH प्रोफ़ाइल है और चलाएँ।', + addPluginsViewerDesc: 'फ़ाइल पूर्वावलोकक प्लगइन्स द्वारा विस्तारित हो सकते हैं। प्लगइन्स ctx.betterSidebar सेवा के माध्यम से पंजीकृत होते हैं; इंस्टॉल क्लिक करने पर इंस्टॉल कमांड कॉपी होता है — इसे उस टर्मिनल में पेस्ट करें जहाँ आपका DSH प्रोफ़ाइल है और चलाएँ।', + addPluginsBrowseMore: 'GitHub पर और प्लगइन्स देखें (topic: dsh-better-sidebar)', + addPluginsSearch: 'प्लगइन नाम या विवरण से खोजें…', + addPluginsNoMatch: 'कोई प्लगइन मेल नहीं खाता', + addPluginsRecommended: 'अनुशंसित प्लगइन', + addPluginsEmpty: 'अभी कोई प्लगइन संकलित नहीं — अपना प्लगइन GitHub topic के तहत प्रकाशित करें', + openPlugin: 'खोलें', + copyInstall: 'इंस्टॉल कमांड कॉपी', + pluginOfficeDesc: 'better-sidebar एडिटर के लिए Office-सूट पूर्वावलोकन (.docx / .xlsx / .pptx), भारी Office रेंडर लाइब्रेरीज़ को मुख्य बंडल से बाहर रखता है', + pluginFlowglassDesc: 'लाइव सत्र फ़्लोग्राफ़: उपयोगकर्ता, सहायक और टूल कॉल के लिए तीन लेन, समानांतर समूह, सबएजेंट शाखाएँ, ड्रिल-डाउन और लाइव स्थिति; better-sidebar इंस्टॉल होने पर देशी Flowglass टैब पंजीकृत करता है और फ़ॉलबैक के रूप में स्टैंडअलोन दराज रखता है', + pluginGitForgeDesc: 'Git Forge टैब: GitHub/Gitea (और अन्य forge) खाता लाइब्रेरी + प्रोजेक्ट-वार अनुदान + सख्त push नीति; टोकन स्थानीय secrets में रहते हैं (कभी मॉडल संदर्भ में नहीं); केवल-पढ़ने GitForge टूल और एजेंट HTTPS क्रेडेंशियल हेल्पर', + pluginGitRemotesDesc: 'Git Remotes टैब: ब्रांच/अपस्ट्रीम/ahead-behind, fetch (वैकल्पिक prune), ff-only pull, और केवल टैब-में पुष्टि के बाद push। अंतर्निहित Git स्टेज/कमिट टैब को प्रतिस्थापित नहीं करता, और force-push या मॉडल ऑटो-push टूल नहीं देता', + pluginSentinelDesc: 'स्थिति-संचालित एजेंट जागरूकता: फ़ाइल/प्रक्रिया/पोर्ट/http/कमांड/webhook सेंसर स्थितियाँ पूरी होने पर निष्क्रिय सत्र जगाते हैं; सर्वर-व्यापी वॉच टेबल के साथ "Sentinel" टैब पंजीकृत करता है', + pluginSidebarQaDesc: 'चुनें और पूछें: वार्तालाप पाठ चुनें → दाएँ पैनल में पूछें → उसी वर्कस्पेस में एक समर्पित फ़ॉलो-अप सत्र (❓फ़ॉलो-अप); एक तेज़ no-thinking मॉडल मुख्य संदर्भ को संक्षिप्त करता है और उद्धरण के साथ इंजेक्ट करता है, मुख्य वार्तालाप को बाधित किए बिना। फ़ॉलो-अप नेस्ट, जारी रखते और संग्रहित करते हैं', + pluginSshTunnelDesc: 'SSH Tunnel टैब: मल्टी-होस्ट इन्वेंटरी + प्रोजेक्ट-वार अनुदान + स्थानीय secrets; SSHManager टूल (exec/SFTP/सत्र रणनीतियाँ); केंद्रीय इंटरैक्टिव टर्मिनल और दो-फलक SFTP', + pluginTurnReviewDesc: 'अभी-समाप्त टर्न पर मानव गेट: प्रत्येक पथ के लिए वैकल्पिक टिप्पणी के साथ Approve / Request changes; मुख्य सत्र / सबएजेंट / अप्रत्यायित द्वारा समूहबद्ध पथ; निर्णय से पहले इनलाइन स्नैपशॉट-बनाम-अभी डिफ। कोई फ़ोर्क नहीं, कोई /rewind नहीं', + pluginVideoPreviewDesc: 'better-sidebar एडिटर के लिए इनलाइन वीडियो पूर्वावलोकन (.mp4/.webm/.mov/.mkv/.avi आदि), HTTP Range (206) समर्थन के साथ समर्पित /video होस्ट रूट द्वारा समर्थित — स्क्रबिंग काम करता है और फ़ाइलें 20MB mediaLimit द्वारा सीमित नहीं हैं', + pluginDocsPanelDesc: 'DSH साइडबार में ग्लोबल डॉक्स: किसी भी वर्कस्पेस से अपने Markdown नोट्स पढ़ें — फ़ाइल सूची, रूपरेखा, Chrome / VS Code में खोलें, और कॉपी बटन; docs डायरेक्टरी कॉन्फ़िगर करने योग्य (डिफ़ॉल्ट ~/.dsh/docs)', +} diff --git a/src/client/locales-id.ts b/src/client/locales-id.ts new file mode 100644 index 0000000..74db07f --- /dev/null +++ b/src/client/locales-id.ts @@ -0,0 +1,343 @@ +/** + * The id (Indonesian) dictionary for the betterSidebar namespace. + * + * Mirrors the key set of `zh` in `locales.ts`. The sidebar's `t()` + * consults this dict when `attachBetterLocale(store)` has been called + * with an active better-locale store whose `active` is `'id'`; absent + * that, the existing zh/en chain runs unchanged. + * + * Translation conventions: + * - Git vocabulary stays close to the English form (stage, commit, branch, fork). + * - Settings labels mirror the zh cadence (… perilaku / … cara). + * - Placeholders keep {name} verbatim (interpolation runs after lookup). + * - English brand names (VS Code, Cursor, Zed, SSH) stay as-is. + */ + +export const id: Record = { + files: 'Berkas', + explorer: 'Explorer', + git: 'Source Control', + terminal: 'Terminal', + editor: 'Editor', + editorExplorer: 'Perilaku buka berkas', + editorExplorerDesc: 'Mengontrol cara berkas dibuka', + editorExplorerMerged: 'Gabung', + editorExplorerMergedDesc: 'Berkas beralih di tempat di jendela yang sama; jendela baru memulai dengan pohon terbuka', + editorExplorerSplit: 'Terpisah', + editorExplorerSplitDesc: 'Jendela tanpa path adalah explorer mandiri (pohon saja); setiap berkas membuka jendelanya sendiri (pohon terpasang, tertutup secara default)', + editorTreeToggle: 'Panel pohon berkas', + editorPathPlaceholder: 'Path berkas (relatif terhadap direktori sesi atau absolut), Enter untuk membuka', + editorSearchPlaceholder: 'Cari berkas berdasarkan nama…', + editorSearchNoResults: 'Tidak ada berkas yang cocok', + editorSearchTruncated: 'Terlalu banyak hasil — menampilkan daftar parsial', + editorEmptyHint: 'Pilih berkas dari panel pohon atau input path di atas untuk mulai pratinjau', + openFileNewTab: 'Buka di Tab Baru', + openFileSide: 'Buka di Samping', + openWithMenu: 'Buka dengan', + openWithSshSuffix: ' (SSH)', + pinOpenWith: 'Sematkan ke menu', + unpinOpenWith: 'Lepas sematan', + openWithExplorer: 'File Manager', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'Host remote SSH', + openWithSettingsSshDesc: 'Kosong = ruang kerja lokal; dengan user@host atau alias SSH, opener VSCode-family beralih ke protokol vscode-remote/ssh-remote dan File Manager / Zed / editor kustom non-VSCode-family disembunyikan dari menu', + openWithSettingsSshPlaceholder: 'user@host atau alias SSH', + openWithSettingsCustomTitle: 'Editor kustom', + openWithSettingsCustomDesc: 'Nama + template URL (placeholder {path}) + flag VSCode-family; dalam mode remote hanya editor VSCode-family yang dapat membuka path remote', + openWithSettingsAdd: 'Tambah', + openWithSettingsName: 'Nama', + openWithSettingsTemplate: 'mis. cursor://file/{path}', + openWithSettingsFamily: 'VSCode-family', + openWithSettingsFamilyDesc: 'Editor ini menggunakan dialek URL VSCode (mendukung pembukaan remote SSH)', + openWithSettingsRemove: 'Hapus', + openWithSettingsInvalidHint: 'Editor dengan nama hilang atau template tanpa {path} / scheme:// tidak ditampilkan di menu', + newTab: 'Tab baru', + openExplorer: 'Explorer', + brokenSymlink: 'Symlink rusak', + openGit: 'Panel Git', + newTerminal: 'Terminal baru', + terminalLimit: 'Batas terminal tercapai (3)', + close: 'Tutup', + closeOtherTabs: 'Tutup Tab Lain', + closeLeftTabs: 'Tutup Tab di Kiri', + closeRightTabs: 'Tutup Tab di Kanan', + collapse: 'Lipat sidebar', + expand: 'Bentangkan sidebar', + collapseBottomPanel: 'Lipat panel bawah', + expandBottomPanel: 'Bentangkan panel bawah', + terminalError: 'Koneksi terminal gagal', + terminalConnectFailed: 'Terminal gagal terhubung berulang kali', + terminalRetry: 'Coba lagi', + terminalDepsFailed: 'Dependensi terminal node-pty gagal dimuat', + terminalDepsHint: 'Jalankan perintah di bawah ini di terminal atau cmd pada mesin DSH untuk memperbaikinya, lalu coba lagi (node-pty tetap sinkron dengan versi inti DSH):', + terminalDepsProfile: ' (profil terdeteksi: {profile})', + preview: 'Pratinjau', + edit: 'Edit', + mermaidError: 'Render Mermaid gagal', + mermaidZoomIn: 'Perbesar', + mermaidZoomOut: 'Perkecil', + mermaidZoomReset: 'Reset', + mermaidZoomHint: 'Gulir untuk zoom · seret untuk geser · Esc untuk tutup', + refresh: 'Segarkan', + save: 'Simpan', + saved: 'Tersimpan', + unsaved: 'Belum disimpan', + saveFailed: 'Gagal menyimpan', + truncation: 'Berkas terlalu besar — menampilkan 512KB pertama', + binary: 'Berkas biner, pratinjau tidak tersedia', + loading: 'Memuat…', + error: 'Gagal memuat', + retry: 'Coba lagi', + splitLeft: 'Bagi ke kiri', + splitRight: 'Bagi ke kanan', + splitUp: 'Bagi ke atas', + splitDown: 'Bagi ke bawah', + notRepo: 'Direktori ini bukan repositori git', + noChanges: 'Tidak ada perubahan', + stage: 'Stage', + unstage: 'Unstage', + stageAll: 'Stage semua', + unstageAll: 'Unstage semua', + commitPlaceholder: 'Pesan commit (Ctrl+Enter)', + commit: 'Commit', + commitError: 'Commit gagal', + branch: 'Branch', + checkoutError: 'Beralih branch gagal', + history: 'Riwayat', + changes: 'Perubahan', + staged: 'Staged', + unstaged: 'Unstaged', + cancel: 'Batal', + diffEmpty: 'Tidak ada perubahan teks', + diffLoadError: 'Gagal memuat diff', + diffBinary: 'Biner', + diffAdded: 'Ditambahkan', + diffDeleted: 'Dihapus', + diffRenamed: 'Diubah nama', + diffExpand: 'Bentangkan {count} baris lagi', + diffCollapse: 'Lipat', + discard: 'Buang perubahan', + discardTitle: 'Buang perubahan', + discardDesc: 'Ini membuang perubahan worktree "{path}" (tidak dapat dipulihkan).', + viewCommitDiff: 'Lihat diff commit', + copyShortHash: 'Salin hash pendek', + copyFullHash: 'Salin hash lengkap', + copySubject: 'Salin subjek', + revertCommit: 'Revert commit', + revertTitle: 'Revert commit', + revertDesc: 'Membuat commit baru pada branch saat ini yang membalikkan "{subject}".', + cherryPickCommit: 'Cherry-pick commit', + cherryPickTitle: 'Cherry-pick commit', + cherryPickDesc: 'Menerapkan perubahan dari "{subject}" ke branch saat ini.', + timeJustNow: 'baru saja', + timeMinutesAgo: '{n} mnt lalu', + timeHoursAgo: '{n} j lalu', + timeYesterday: 'kemarin', + loadMore: 'Muat lebih banyak', + historyLoadError: 'Gagal memuat lebih banyak riwayat', + produced: 'Dihasilkan', + producedOpen: 'Buka di sidebar', + disconnected: 'Terminal terputus, menyambung ulang…', + exited: 'Proses terminal keluar', + noSession: 'Pilih obrolan untuk menggunakan sidebar', + pluginNotLoaded: 'Plugin tidak dimuat; tab tidak tersedia untuk sementara:', + hiddenFiles: 'Berkas tersembunyi', + parent: 'Direktori induk', + copied: 'Tersalin', + copy: 'Salin', + newFile: 'Berkas baru', + openEditor: 'Buka editor', + gitDetail: 'Lihat detail perubahan', + referenceFile: '@berkas', + addToConversation: 'Tambahkan ke obrolan', + copyRelative: 'Salin path relatif', + copyAbsolute: 'Salin path absolut', + download: 'Unduh', + uploadFiles: 'Unggah berkas', + uploadFolder: 'Unggah folder', + uploadHere: 'Unggah di sini', + uploadDropHint: 'Jatuhkan berkas/folder di sini untuk mengunggah', + uploadDropChat: 'Jatuhkan ke area obrolan: tambahkan gambar ke obrolan', + uploadTo: 'Unggah ke {dir}', + uploadingTo: 'Mengunggah ke {dir}…', + uploadProgress: 'Mengunggah {done}/{total}: {name}', + uploadDone: 'Diunggah {count} berkas', + uploadFailed: 'Unggahan gagal: {error}', + uploadFailedUnknown: 'Galat tak dikenal', + uploadTooLarge: 'Berkas terlalu besar (melebihi batas unggah)', + uploadCancelled: 'Unggahan dibatalkan', + settingsNav: 'Kartu samping', + settingsIntro: 'Kelola apa yang ditampilkan kartu samping dan perilakunya', + settingsPopupDesc: 'Konfigurasikan opsi terkait untuk {feature}', + settingsDone: 'Selesai', + settingsOpenTitle: 'Buka secara default untuk obrolan baru', + settingsOpenDesc: 'Bentangkan kartu samping secara otomatis untuk obrolan baru; obrolan yang sudah ada mempertahankan tata letaknya', + settingsWidthTitle: 'Porsi lebar default', + settingsWidthDesc: 'Porsi lebar jendela default kartu samping untuk obrolan baru (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: 'Buka berkas obrolan di sidebar', + settingsOpenPathDesc: 'Buka tautan berkas di obrolan (baris alat, berkas yang dihasilkan, mention) di editor sidebar alih-alih aplikasi default sistem', + settingsTitleBarTitle: 'Mode kompatibilitas posisi', + settingsTitleBarDesc: 'Pilih skema kompatibilitas title-bar: auto-detect (default, konservatif) / Web resmi DSH / shell desktop yang dikenal / kustom (jarak geser + CSS kustom)', + settingsTitleBarStripTitle: 'Jarak geser', + settingsTitleBarStripDesc: 'Tinggi strip title-bar: seberapa jauh tombol sidebar dan konten bergeser ke bawah dalam px (0–120, default 40; berlaku di bawah skema kustom)', + settingsSchemeAutoTitle: 'Auto-detect', + settingsSchemeAutoDesc: 'Konservatif: hanya API Window Controls Overlay standar yang berkontribusi (tinggi caption-overlay nyata); lingkungan web polos tidak dimodifikasi', + settingsSchemeWebTitle: 'Web resmi DSH', + settingsSchemeWebDesc: 'Deklarasikan secara eksplisit UI web resmi: tanpa adaptasi sama sekali (bahkan geometri WCO standar tidak berlaku)', + settingsSchemeCustomTitle: 'Kustom', + settingsSchemeCustomDesc: 'Kendali penuh: injeksikan CSS kustom (dapat menimpa style bawaan) dan atur jarak geser title-bar', + settingsSchemeDetectedSuffix: 'terdeteksi', + settingsCustomCssTitle: 'CSS kustom', + settingsCustomCssDesc: 'Style yang ditambahkan di akhir halaman (yang ditulis kemudian menang pada seri; gunakan !important untuk menimpa variabel inline yang ditulis JS)', + settingsCustomCssPlaceholder: '/* mis. sediakan 36px untuk shell dengan title-bar yang digambar sendiri */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: 'Gagal menyimpan', + settingsConflict: 'Pengaturan diubah di jendela lain — silakan coba lagi', + binaryNoPreview: 'Tipe berkas ini tidak dapat dipratinjau', + downloadToView: 'Unduh untuk melihat', + settingsSubagentTitle: 'Buka otomatis halaman Tasks saat subagen muncul', + settingsSubagentDesc: 'Bentangkan kartu samping dan buka halaman Tasks saat obrolan saat ini menelurkan subagen baru; matikan untuk membukanya secara manual', + settingsJobsTitle: 'Buka otomatis halaman Jobs saat ada tugas latar baru', + settingsJobsDesc: 'Bentangkan kartu samping dan buka halaman Jobs setiap kali tugas latar baru muncul untuk obrolan saat ini (setiap tugas baru memicu); matikan untuk membukanya secara manual', + settingsToolsTitle: 'Suntik alat terminal untuk model', + settingsToolsDesc: 'Saat diaktifkan, model dapat membuat dan mengendalikan terminal sidebar melalui 8 alat terminal_* (nonaktif secara default)', + settingsBottomTerminalTitle: 'Buka terminal otomatis saat panel bawah pertama kali dibentangkan', + settingsBottomTerminalDesc: 'Saat panel bawah pertama kali dibentangkan dalam sesi, coba buka tab terminal baru di panel bawah (kuota terminal tetap berlaku; aktif secara default)', + settingsFontFamilyTitle: 'Keluarga font terminal', + settingsFontFamilyDesc: 'Keluarga font terminal kustom (stack CSS font-family seperti "JetBrains Mono", monospace; biarkan kosong untuk mengikuti font monospace tema)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: 'Ukuran font terminal', + settingsFontSizeDesc: 'Ukuran font terminal dalam px (9–32, default 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'Path shell', + settingsShellDesc: 'Shell yang dibangkitkan untuk terminal UI dan model (path absolut atau executable polos). Kosong mempertahankan urutan lama: config.shell yaml → $SHELL / login shell / powershell.exe Windows. Berlaku untuk terminal yang dibuka setelahnya', + settingsShellPlaceholder: 'mis. /bin/zsh (kosong = auto)', + settingsShellArgsTitle: 'Argumen shell', + settingsShellArgsDesc: 'Argumen shell eksplisit, dipisah spasi; jika tidak kosong, sepenuhnya menggantikan default (kontrak yang sama dengan shellArgs yaml)', + settingsShellArgsPlaceholder: 'mis. -l (kosong = default)', + settingsTabsTitle: 'Konten sidebar', + settingsViewersTitle: 'Pratinjau berkas', + settingsGeneralTitle: 'Umum', + settingsPopup: 'Pengaturan fitur', + settingsViewerCatchAll: 'Catch-all: berkas apa pun', + viewerImage: 'Gambar', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: 'Kode', + viewerBinary: 'Unduhan biner', + viewerHtml: 'HTML', + browser: 'Browser', + browserPlaceholder: 'Masukkan URL, mis. example.com', + browserGo: 'Buka', + browserBack: 'Mundur', + browserForward: 'Maju', + browserStart: 'Masukkan URL untuk mulai menjelajah (mode sandbox)', + browserBlockedScheme: 'Diblokir: hanya URL http/https yang diizinkan', + browserBlockedLoopback: 'Diblokir: alamat lokal dan internal tidak dapat dijelajahi di sini', + browserInvalid: 'URL tidak valid', + browserNoSandboxWarning: 'Sandbox mati: halaman saat ini berjalan dengan hak penuh GUI (aktifkan kembali di pengaturan)', + htmlNoSandboxWarning: 'Sandbox mati: HTML ini berjalan dengan hak penuh GUI (aktifkan kembali di pengaturan)', + sandboxStatusOn: 'Mode sandbox: aktif · halaman tidak dapat mengakses data GUI atau berkas lokal; login dan cookie pihak ketiga mungkin tidak berfungsi', + sandboxUnlock: 'Nonaktifkan sementara (tidak aman)', + sandboxRestore: 'Pulihkan sandbox', + settingsHtmlDefaultUnsafeTitle: 'Buka pratinjau HTML tanpa sandbox secara default (tidak aman)', + settingsHtmlDefaultUnsafeDesc: 'Saat aktif, setiap pratinjau HTML yang baru dibuka dimulai dalam keadaan tanpa sandbox (asal yang sama dengan GUI — dapat membaca berkas sesi dan API internal); baris status masih menawarkan pemulihan sekali ketuk', + settingsHtmlSandboxTitle: 'Nonaktifkan sandbox pratinjau HTML (tidak aman)', + settingsHtmlSandboxDesc: 'Dengan sandbox mati, HTML yang dipratinjau berjalan dengan asal yang sama dengan GUI: dapat membaca berkas sesi, penyimpanan lokal, dan memanggil API internal. Hanya aktifkan untuk berkas yang sepenuhnya tepercaya', + settingsBrowserSandboxTitle: 'Nonaktifkan sandbox browser (tidak aman)', + settingsBrowserSandboxDesc: 'Dengan sandbox mati, situs yang dikunjungi berjalan dengan asal yang sama dengan GUI: dapat membaca data sesi dan menyamar sebagai sesi login Anda. Hanya aktifkan untuk situs yang sepenuhnya tepercaya', + settingsBrowserLinksTitle: 'Buka tautan eksternal obrolan di sidebar', + settingsBrowserLinksDesc: 'Saat aktif, mengeklik tautan eksternal di obrolan atau GUI membuka sidebar alih-alih jendela baru; HTTP dan HTTPS dikendalikan terpisah oleh sakelar di bawah; Ctrl/Cmd+klik selalu menembus', + settingsBrowserHttpTitle: 'Buka halaman HTTP di sidebar', + settingsBrowserHttpDesc: 'Saat aktif, mengeklik tautan eksternal HTTP di obrolan atau GUI membuka sidebar (halaman plugin yang mendeklarasikan urlTarget menang); Ctrl/Cmd+klik selalu menembus', + settingsBrowserHttpsTitle: 'Buka halaman HTTPS di sidebar', + settingsBrowserHttpsDesc: 'Saat aktif, mengeklik tautan eksternal HTTPS di obrolan atau GUI membuka sidebar. Nonaktif secara default: kebanyakan situs HTTPS menolak untuk disematkan, jadi browser sistem adalah default yang lebih mulus', + browserOpenExternal: 'Buka di browser', + browserEmbedBlocked: '{host} menolak untuk disematkan', + browserEmbedBlockedDesc: 'Situs melarang ditampilkan di dalam halaman lain (X-Frame-Options / frame-ancestors), sehingga tidak dapat dimuat di sidebar. Buka langsung di browser Anda.', + browserEmbedAnyway: 'Tetap muat', + subagent: 'Tasks', + openSubagent: 'Tasks', + subagentMainAgent: 'Agen utama', + subagentEmpty: 'Tidak ada subagen', + subagentEmptyDesc: 'Subagen yang dibangkitkan di bawah agen utama akan muncul di sini', + subagentRunning: 'Berjalan', + subagentInactive: 'Menganggur', + subagentModeOneShot: 'Sekali pakai', + subagentModeContinuable: 'Dapat dilanjutkan', + subagentCount: '{count} subagen', + subagentCountRunning: '{count} subagen · {running} berjalan', + subagentDiagCorrupt: 'Rusak', + subagentDiagUnsupported: 'Tidak didukung', + subagentDiagUnavailable: 'Tidak tersedia', + subagentThinking: 'Berpikir…', + sideChat: 'Side Chat (beta)', + sideChatNew: 'Thread baru', + sideChatUntitled: 'Thread baru', + sideChatEmpty: 'Tidak ada obrolan samping', + sideChatEmptyDesc: 'Setiap obrolan samping adalah tab sendiri di strip tab — mewarisi konteks sesi saat ini dan tidak pernah masuk ke obrolan utama', + sideChatCreating: 'Membuat obrolan samping…', + sideChatRetry: 'Coba lagi', + sideChatThreads: 'Beralih thread / baru', + sideChatSave: 'Simpan sebagai sesi baru', + sideChatSaveTitle: 'Promosikan thread ini ke sesi tingkat atas dalam daftar sesi utama', + sideChatSaved: 'Tersimpan sebagai sesi baru', + sideChatNoTurn: 'Simpan tersedia setelah giliran pertama selesai', + sideChatPendingDrop: 'Tindak lanjut yang belum terjawab terakhir tidak akan disertakan dalam sesi yang disimpan', + sideChatFirstPlaceholder: 'Ajukan pertanyaan pertama — konteks diwarisi…', + sideChatComposerPlaceholder: 'Ajukan tindak lanjut…', + sideChatThinking: 'Mendalami…', + sideChatThink: 'Berpikir', + sideChatInjection: 'Konteks disuntik', + sideChatSend: 'Kirim', + sideChatCancel: 'Hentikan', + sideChatCancelTitle: 'Batalkan giliran yang berjalan (pekerjaan antrean dipertahankan)', + sideChatClose: 'Tutup thread', + sideChatCloseTitle: 'Lepaskan agen thread (riwayat dipertahankan)', + sideChatError: 'Kesalahan Side Chat: {message}', + jobs: 'Tugas latar', + jobsCount: '{count} tugas latar', + jobsCountRunning: '{count} tugas latar · {running} berjalan', + jobStatusRunning: 'Berjalan', + jobStatusStopping: 'Menghentikan', + jobStatusCompleted: 'Selesai', + jobStatusKilled: 'Dihentikan', + jobStatusFailed: 'Gagal', + jobDurationSeconds: '{seconds}d', + jobDurationMinutes: '{minutes}m {seconds}d', + jobDurationHours: '{hours}j {minutes}m', + jobViewOutput: 'Lihat keluaran', + jobHideOutput: 'Sembunyikan keluaran', + jobNoOutput: 'Belum ada keluaran', + jobNotReadYet: 'Menunggu model membaca tugas ini; keluarannya muncul di sini setelah model menjalankan job_output', + jobOutputTruncated: 'Keluaran dipotong', + jobOutputError: 'Gagal membaca keluaran', + jobKill: 'Hentikan', + jobKillConfirm: 'Klik lagi untuk mengonfirmasi penghentian', + jobKillError: 'Penghentian gagal', + addPluginsTabCard: 'Tambah plugin tab', + addPluginsTabCardDesc: 'Daftarkan halaman sidebar baru', + addPluginsViewerCard: 'Tambah plugin pratinjau', + addPluginsViewerCardDesc: 'Daftarkan pratinjau tipe berkas', + addPluginsTabDesc: 'Halaman sidebar (tab) dapat diperluas oleh plugin. Plugin mendaftar melalui layanan ctx.betterSidebar; klik Install menyalin perintah instalasi — tempel ke terminal tempat profil DSH Anda berada dan jalankan.', + addPluginsViewerDesc: 'Pratinjau berkas dapat diperluas oleh plugin. Plugin mendaftar melalui layanan ctx.betterSidebar; klik Install menyalin perintah instalasi — tempel ke terminal tempat profil DSH Anda berada dan jalankan.', + addPluginsBrowseMore: 'Jelajahi lebih banyak plugin di GitHub (topic: dsh-better-sidebar)', + addPluginsSearch: 'Cari berdasarkan nama / deskripsi plugin…', + addPluginsNoMatch: 'Tidak ada plugin yang cocok', + addPluginsRecommended: 'Plugin yang direkomendasikan', + addPluginsEmpty: 'Belum ada plugin yang dikurasi — publikasikan plugin Anda di bawah topik GitHub', + openPlugin: 'Buka', + copyInstall: 'Salin perintah instalasi', + pluginOfficeDesc: 'Pratinjau Office-suite (.docx / .xlsx / .pptx) untuk editor better-sidebar, menjaga pustaka render Office yang berat tetap di luar bundle inti', + pluginFlowglassDesc: 'Flowgraph sesi langsung dengan tiga lajur untuk pengguna, asisten, dan panggilan alat, plus grup paralel, cabang sub-agen, drill-down, dan status langsung; mendaftarkan tab Flowglass native saat better-sidebar terpasang dan mempertahankan laci mandirinya sebagai fallback', + pluginGitForgeDesc: 'Tab Git Forge: pustaka akun GitHub/Gitea (dan forge lain) + pemberian izin per proyek + kebijakan push yang ditegakkan keras; token tetap di rahasia lokal (tidak pernah dalam konteks model); alat GitForge hanya-baca dan helper kredensial HTTPS agen', + pluginGitRemotesDesc: 'Tab Git Remotes: branch/upstream/ahead-behind, fetch (prune opsional), ff-only pull, dan push hanya setelah konfirmasi dalam tab. Tidak menggantikan tab stage/commit Git bawaan, dan tidak menawarkan force-push atau alat auto-push model', + pluginSentinelDesc: 'Sistem bangun agen berbasis kondisi: sensor berkas/proses/port/http/perintah/webhook membangunkan sesi yang tidur saat kondisi terpicu; mendaftarkan tab "Sentinel" dengan tabel pengawasan server-wide', + pluginSidebarQaDesc: 'Select-and-ask: Pilih teks obrolan → ajukan di panel kanan → sesi tindak lanjut khusus (❓追问) di ruang kerja yang sama; model no-thinking yang cepat mengompresi konteks utama dan menyuntiknya bersama kutipan, tanpa mengganggu obrolan utama. Tindak lanjut dapat bersarang, dilanjutkan, dan diarsipkan', + pluginSshTunnelDesc: 'Tab SSH Tunnel: inventaris multi-host + pemberian izin per proyek + rahasia lokal; alat SSHManager (exec/SFTP/strategi sesi); terminal interaktif pusat dan SFTP dua panel', + pluginTurnReviewDesc: 'Gerbang manusia pada giliran yang baru selesai: Approve / Request changes per path dengan komentar opsional; path dikelompokkan berdasarkan sesi utama / subagen / tidak teratribusi; diff snapshot-vs-now inline sebelum Anda memutuskan. Tanpa fork, tanpa /rewind', + pluginVideoPreviewDesc: 'Pratinjau video inline (.mp4/.webm/.mov/.mkv/.avi dll.) untuk editor better-sidebar, didukung oleh rute host /video khusus dengan dukungan HTTP Range (206) — scrubbing berfungsi dan berkas tidak dibatasi oleh mediaLimit 20MB', + pluginDocsPanelDesc: 'Dokumen global di sidebar DSH: baca catatan Markdown Anda sendiri dari ruang kerja apa pun — daftar berkas, kerangka, buka di Chrome / VS Code, dan tombol salin; direktori docs dapat dikonfigurasi (default ~/.dsh/docs)', +} diff --git a/src/client/locales-it.ts b/src/client/locales-it.ts new file mode 100644 index 0000000..fd93783 --- /dev/null +++ b/src/client/locales-it.ts @@ -0,0 +1,336 @@ +/** + * Italian copy for the sidebar. Key-set-equal to `zh` in `locales.ts`; + * consumed by the better-locale override store (see `locales.ts` for the + * zh/en/ja lookup chain and the `attachBetterLocale` contract). + * + * @module dsh-better-sidebar/client/locales-it + */ + +export const it: Record = { + files: 'File', + explorer: 'Esplora risorse', + git: 'Controllo del codice sorgente', + terminal: 'Terminale', + editor: 'Editor', + editorExplorer: 'Modalità di apertura dei file', + editorExplorerDesc: 'Controlla come si aprono i file', + editorExplorerMerged: 'Unito', + editorExplorerMergedDesc: 'I file cambiano sul posto nella stessa finestra; le nuove finestre avviano l’albero espanso', + editorExplorerSplit: 'Separato', + editorExplorerSplitDesc: 'Le finestre senza percorso sono l’esplora risorse autonomo (solo albero dei file); ogni file apre la propria finestra (albero agganciato, chiuso per impostazione predefinita)', + editorTreeToggle: 'Pannello dell’albero dei file', + editorPathPlaceholder: 'Percorso del file (relativo alla directory della sessione o assoluto), Invio per aprire', + editorSearchPlaceholder: 'Cerca file per nome…', + editorSearchNoResults: 'Nessun file corrispondente', + editorSearchTruncated: 'Troppi risultati — viene mostrato un elenco parziale', + editorEmptyHint: 'Scelga un file dal pannello dell’albero a destra o dal campo del percorso in alto per iniziare l’anteprima', + openFileNewTab: 'Apri in una nuova scheda', + openFileSide: 'Apri a lato', + openWithMenu: 'Apri con', + openWithSshSuffix: ' (SSH)', + pinOpenWith: 'Fissa al menu', + unpinOpenWith: 'Rimuovi dal fisso', + openWithExplorer: 'Esplora risorse', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'Host remoto SSH', + openWithSettingsSshDesc: 'Vuoto = spazio di lavoro locale; con un user@host o un alias SSH, gli apritori della famiglia VSCode passano al protocollo vscode-remote/ssh-remote e l’Esplora risorse / Zed / gli editor personalizzati non VSCode vengono nascosti dal menu', + openWithSettingsSshPlaceholder: 'user@host o alias SSH', + openWithSettingsCustomTitle: 'Editor personalizzati', + openWithSettingsCustomDesc: 'Nome + modello URL (segnaposto {path}) + flag famiglia VSCode; in modalità remota solo gli editor della famiglia VSCode possono aprire un percorso remoto', + openWithSettingsAdd: 'Aggiungi', + openWithSettingsName: 'Nome', + openWithSettingsTemplate: 'es. cursor://file/{path}', + openWithSettingsFamily: 'Famiglia VSCode', + openWithSettingsFamilyDesc: 'Questo editor usa il protocollo URL di VSCode (supporta aperture SSH remote)', + openWithSettingsRemove: 'Rimuovi', + openWithSettingsInvalidHint: 'Gli editor con nome mancante o modello senza {path} / scheme:// non vengono mostrati nel menu', + newTab: 'Nuova scheda', + openExplorer: 'Esplora risorse', + brokenSymlink: 'Collegamento simbolico interrotto', + openGit: 'Pannello Git', + newTerminal: 'Nuovo terminale', + terminalLimit: 'Numero massimo di terminali raggiunto (3)', + close: 'Chiudi', + closeOtherTabs: 'Chiudi le altre schede', + closeLeftTabs: 'Chiudi le schede a sinistra', + closeRightTabs: 'Chiudi le schede a destra', + collapse: 'Comprimi barra laterale', + expand: 'Espandi barra laterale', + collapseBottomPanel: 'Comprimi pannello inferiore', + expandBottomPanel: 'Espandi pannello inferiore', + terminalError: 'Connessione del terminale non riuscita', + terminalConnectFailed: 'Il terminale non è riuscito a connettersi più volte', + terminalRetry: 'Riprova', + terminalDepsFailed: 'Caricamento della dipendenza del terminale node-pty non riuscito', + terminalDepsHint: 'Esegua il comando seguente in un terminale o cmd sul computer DSH per ripristinarlo, poi riprovi (node-pty resta sincronizzato con la versione del core DSH):', + terminalDepsProfile: ' (rilevato profilo: {profile})', + preview: 'Anteprima', + edit: 'Modifica', + mermaidError: 'Rendering Mermaid non riuscito', + mermaidZoomIn: 'Ingrandisci', + mermaidZoomOut: 'Riduci', + mermaidZoomReset: 'Ripristina', + mermaidZoomHint: 'Scorra per zoom · trascini per panoramica · Esc per chiudere', + refresh: 'Aggiorna', + save: 'Salva', + saved: 'Salvato', + unsaved: 'Non salvato', + saveFailed: 'Salvataggio non riuscito', + truncation: 'File troppo grande — vengono mostrati i primi 512KB', + binary: 'File binario, anteprima non disponibile', + loading: 'Caricamento…', + error: 'Caricamento non riuscito', + retry: 'Riprova', + splitLeft: 'Dividi a sinistra', + splitRight: 'Dividi a destra', + splitUp: 'Dividi in alto', + splitDown: 'Dividi in basso', + notRepo: 'Questa directory non è un repository git', + noChanges: 'Nessuna modifica', + stage: 'Prepara', + unstage: 'Rimuovi dalla preparazione', + stageAll: 'Prepara tutto', + unstageAll: 'Rimuovi tutto dalla preparazione', + commitPlaceholder: 'Messaggio di commit (Ctrl+Enter)', + commit: 'Commit', + commitError: 'Commit non riuscito', + branch: 'Ramo', + checkoutError: 'Cambio di ramo non riuscito', + history: 'Cronologia', + changes: 'Modifiche', + staged: 'In stage', + unstaged: 'Non in stage', + cancel: 'Annulla', + diffEmpty: 'Nessuna modifica testuale', + diffLoadError: 'Caricamento del diff non riuscito', + diffBinary: 'Binario', + diffAdded: 'Aggiunto', + diffDeleted: 'Eliminato', + diffRenamed: 'Rinominato', + diffExpand: 'Espandi altre {count} righe', + diffCollapse: 'Comprimi', + discard: 'Annulla modifiche', + discardTitle: 'Annulla modifiche', + discardDesc: 'Questo annulla le modifiche della copia di lavoro di «{path}» (non recuperabile).', + viewCommitDiff: 'Vedi il diff del commit', + copyShortHash: 'Copia hash breve', + copyFullHash: 'Copia hash completo', + copySubject: 'Copia messaggio di commit', + revertCommit: 'Ripristina questo commit', + revertTitle: 'Ripristina questo commit', + revertDesc: 'Crea un nuovo commit sul ramo attuale che inverte «{subject}».', + cherryPickCommit: 'Cherry-pick di questo commit', + cherryPickTitle: 'Cherry-pick di questo commit', + cherryPickDesc: 'Applica le modifiche di «{subject}» al ramo attuale.', + timeJustNow: 'adesso', + timeMinutesAgo: '{n} min fa', + timeHoursAgo: '{n} h fa', + timeYesterday: 'ieri', + loadMore: 'Carica altro', + historyLoadError: 'Caricamento di altra cronologia non riuscito', + produced: 'Prodotti', + producedOpen: 'Apri nella barra laterale', + disconnected: 'Terminale disconnesso, riconnessione…', + exited: 'Il processo del terminale è terminato', + noSession: 'Selezioni una conversazione per usare la barra laterale', + pluginNotLoaded: 'Plugin non caricato; scheda non disponibile:', + hiddenFiles: 'File nascosti', + parent: 'Directory superiore', + copied: 'Copiato', + copy: 'Copia', + newFile: 'Nuovo file', + openEditor: 'Apri editor', + gitDetail: 'Vedi i dettagli delle modifiche', + referenceFile: '@file', + addToConversation: 'Aggiungi alla conversazione', + copyRelative: 'Copia percorso relativo', + copyAbsolute: 'Copia percorso assoluto', + download: 'Scarica', + uploadFiles: 'Carica file', + uploadFolder: 'Carica cartella', + uploadHere: 'Carica qui', + uploadDropHint: 'Trascini file/cartelle qui per caricarli', + uploadDropChat: 'Trascini sulla chat per aggiungere immagini alla conversazione', + uploadTo: 'Carica in {dir}', + uploadingTo: 'Caricamento in {dir}…', + uploadProgress: 'Caricamento {done}/{total}: {name}', + uploadDone: 'Caricati {count} file', + uploadFailed: 'Caricamento non riuscito: {error}', + uploadFailedUnknown: 'Errore sconosciuto', + uploadTooLarge: 'File troppo grande (oltre il limite di caricamento)', + uploadCancelled: 'Caricamento annullato', + settingsNav: 'Scheda laterale', + settingsIntro: 'Gestisca cosa mostra la scheda laterale e come si comporta', + settingsPopupDesc: 'Configuri le opzioni relative a {feature}', + settingsDone: 'Fatto', + settingsOpenTitle: 'Apri per impostazione predefinita per le nuove conversazioni', + settingsOpenDesc: 'Espande automaticamente la scheda laterale per le conversazioni nuove; le conversazioni esistenti mantengono il proprio layout', + settingsWidthTitle: 'Quota di larghezza predefinita', + settingsWidthDesc: 'La quota predefinita della scheda laterale sulla larghezza della finestra per le nuove conversazioni (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: 'Apri i file della chat nella barra laterale', + settingsOpenPathDesc: 'Apre i collegamenti ai file nella chat (righe di strumenti, file prodotti, menzioni) nell’editor della barra laterale invece dell’app predefinita di sistema', + settingsTitleBarTitle: 'Modalità di compatibilità della posizione', + settingsTitleBarDesc: 'Scelga lo schema di compatibilità della barra del titolo: rilevamento automatico (predefinito, prudente) / DSH Web ufficiale / shell desktop note / personalizzato (distanza di scorrimento + CSS personalizzato)', + settingsTitleBarStripTitle: 'Distanza di scorrimento', + settingsTitleBarStripDesc: 'Altezza della striscia della barra del titolo: di quanti pixel scendono i pulsanti e i contenuti della barra laterale (0–120, predefinito 40; si applica con lo schema personalizzato)', + settingsSchemeAutoTitle: 'Rilevamento automatico', + settingsSchemeAutoDesc: 'Prudente: solo l’API standard Window Controls Overlay contribuisce (altezza reale della barra del titolo); gli ambienti web puri non subiscono modifiche', + settingsSchemeWebTitle: 'DSH Web ufficiale', + settingsSchemeWebDesc: 'Dichiara esplicitamente la web UI ufficiale: nessun adattamento (nemmeno la geometria WCO standard)', + settingsSchemeCustomTitle: 'Personalizzato', + settingsSchemeCustomDesc: 'Controllo totale: inietti CSS personalizzato (può sovrascrivere gli stili integrati) e imposti la distanza di scorrimento della barra del titolo', + settingsSchemeDetectedSuffix: 'rilevato', + settingsCustomCssTitle: 'CSS personalizzato', + settingsCustomCssDesc: 'Stili accodati alla fine della pagina (in caso di parità vince chi è dopo; usi !important per sovrascrivere le variabili inline scritte da JS)', + settingsCustomCssPlaceholder: '/* es. riserva 36px per una shell con barra del titolo disegnata a mano */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: 'Salvataggio non riuscito', + settingsConflict: 'L’impostazione è stata modificata in un’altra finestra — riprovi', + binaryNoPreview: 'Questo tipo di file non può essere visualizzato in anteprima', + downloadToView: 'Scarica per visualizzare', + settingsSubagentTitle: 'Apri automaticamente la pagina Attività quando compare un sottoagente', + settingsSubagentDesc: 'Espande la barra laterale e apre la pagina Attività quando la conversazione attuale genera un nuovo sottoagente; disattivato va aperta manualmente', + settingsJobsTitle: 'Apri automaticamente la pagina Attività in background in caso di nuova attività', + settingsJobsDesc: 'Espande la barra laterale e apre la pagina Attività in background ogni volta che compare una nuova attività in background per la conversazione attuale (ogni nuova attività la attiva); disattivato va aperta manualmente', + settingsToolsTitle: 'Inietta strumenti del terminale per il modello', + settingsToolsDesc: 'Se attivato, il modello può creare e gestire terminali della barra laterale attraverso gli 8 strumenti terminal_* (disattivato per impostazione predefinita)', + settingsBottomTerminalTitle: 'Apri automaticamente un terminale alla prima espansione del pannello inferiore', + settingsBottomTerminalDesc: 'Quando il pannello inferiore viene espanso per la prima volta in una sessione, prova ad aprire una nuova scheda terminale nel pannello inferiore (il limite di terminali si applica comunque; attivo per impostazione predefinita)', + settingsFontFamilyTitle: 'Famiglia di caratteri del terminale', + settingsFontFamilyDesc: 'Famiglia di caratteri personalizzata del terminale (uno stack CSS font-family come "JetBrains Mono", monospace; lasci vuoto per seguire il carattere a spaziatura fissa del tema)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: 'Dimensione del carattere del terminale', + settingsFontSizeDesc: 'Dimensione del carattere del terminale in px (9–32, predefinito 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'Percorso della shell', + settingsShellDesc: 'Shell avviata per i terminali dell’interfaccia e del modello (percorso assoluto o nome eseguibile). Vuoto mantiene l’ordine preesistente: config.shell di yaml → $SHELL / shell di login / powershell.exe di Windows. Si applica ai terminali aperti successivamente', + settingsShellPlaceholder: 'es. /bin/zsh (vuoto = automatico)', + settingsShellArgsTitle: 'Argomenti della shell', + settingsShellArgsDesc: 'Argomenti espliciti della shell, separati da spazi; quando non vuoti sostituiscono completamente i predefiniti (stesso contratto di shellArgs di yaml)', + settingsShellArgsPlaceholder: 'es. -l (vuoto = predefiniti)', + settingsTabsTitle: 'Contenuto della barra laterale', + settingsViewersTitle: 'Visualizzatori di file', + settingsGeneralTitle: 'Generali', + settingsPopup: 'Impostazioni della funzionalità', + settingsViewerCatchAll: 'Raccoglitore: qualsiasi file', + viewerImage: 'Immagine', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: 'Codice', + viewerBinary: 'Download binario', + viewerHtml: 'HTML', + browser: 'Browser', + browserPlaceholder: 'Inserisca un URL, es. example.com', + browserGo: 'Vai', + browserBack: 'Indietro', + browserForward: 'Avanti', + browserStart: 'Inserisca un URL per iniziare a navigare (modalità sandbox)', + browserBlockedScheme: 'Bloccato: sono ammessi solo URL http/https', + browserBlockedLoopback: 'Bloccato: gli indirizzi locali e interni non possono essere navigati qui', + browserInvalid: 'URL non valido', + browserNoSandboxWarning: 'Sandbox disattivata: la pagina attuale viene eseguita con i privilegi completi dell’interfaccia (può riattivarla nelle impostazioni)', + htmlNoSandboxWarning: 'Sandbox disattivata: questo HTML viene eseguito con la stessa origine dell’interfaccia e può leggere i file di sessione e le API interne (può riattivarla nelle impostazioni)', + sandboxStatusOn: 'Modalità sandbox: attiva · le pagine non possono accedere ai dati dell’interfaccia o ai file locali; i login e i cookie di terze parti potrebbero non funzionare', + sandboxUnlock: 'Disattiva temporaneamente (non sicuro)', + sandboxRestore: 'Ripristina sandbox', + settingsHtmlDefaultUnsafeTitle: 'Apri le anteprime HTML senza sandbox per impostazione predefinita (non sicuro)', + settingsHtmlDefaultUnsafeDesc: 'Se attivato, ogni anteprima HTML appena aperta inizia nello stato senza sandbox (stessa origine dell’interfaccia — può leggere i file di sessione e le API interne); la riga di stato offre ancora un ripristino con un tocco', + settingsHtmlSandboxTitle: 'Disattiva la sandbox dell’anteprima HTML (non sicuro)', + settingsHtmlSandboxDesc: 'Con la sandbox disattivata, l’HTML in anteprima viene eseguito con la stessa origine dell’interfaccia: può leggere i file di sessione, l’archiviazione locale e chiamare le API interne. Attivi solo per file completamente attendibili', + settingsBrowserSandboxTitle: 'Disattiva la sandbox del browser (non sicuro)', + settingsBrowserSandboxDesc: 'Con la sandbox disattivata, ogni sito visitato viene eseguito con la stessa origine dell’interfaccia: può leggere i dati di sessione e fingersi la sua sessione di login. Attivi solo per siti completamente attendibili', + settingsBrowserLinksTitle: 'Apri i collegamenti esterni della chat nella barra laterale', + settingsBrowserLinksDesc: 'Se attivato, cliccando un collegamento esterno nella chat o nell’interfaccia si apre la barra laterale invece di una nuova finestra; HTTP e HTTPS sono controllati separatamente dagli interruttori qui sotto; Ctrl/Cmd+clic li aggira sempre', + settingsBrowserHttpTitle: 'Apri le pagine HTTP nella barra laterale', + settingsBrowserHttpDesc: 'Se attivato, cliccando un collegamento HTTP esterno nella chat o nell’interfaccia si apre la barra laterale (le pagine dei plugin che dichiarano urlTarget vincono); Ctrl/Cmd+clic lo aggira sempre', + settingsBrowserHttpsTitle: 'Apri le pagine HTTPS nella barra laterale', + settingsBrowserHttpsDesc: 'Se attivato, cliccando un collegamento HTTPS esterno nella chat o nell’interfaccia si apre la barra laterale. Disattivato per impostazione predefinita: la maggior parte dei siti HTTPS rifiuta di essere incorporata, per cui il browser di sistema è l’impostazione più fluida', + browserOpenExternal: 'Apri nel browser', + browserEmbedBlocked: '{host} ha rifiutato di essere incorporato', + browserEmbedBlockedDesc: 'Il sito vieta di essere mostrato all’interno di altre pagine (X-Frame-Options / frame-ancestors), per cui non può essere caricato nella barra laterale. Lo apra direttamente nel browser.', + browserEmbedAnyway: 'Carica comunque', + subagent: 'Attività', + openSubagent: 'Attività', + subagentMainAgent: 'Agente principale', + subagentEmpty: 'Nessun sottoagente', + subagentEmptyDesc: 'I sottoagenti generati dall’agente principale compariranno qui', + subagentRunning: 'In esecuzione', + subagentInactive: 'Inattivo', + subagentModeOneShot: 'Monouso', + subagentModeContinuable: 'Proseguibile', + subagentCount: '{count} sottoagenti', + subagentCountRunning: '{count} sottoagenti · {running} in esecuzione', + subagentDiagCorrupt: 'Danneggiato', + subagentDiagUnsupported: 'Non supportato', + subagentDiagUnavailable: 'Non disponibile', + subagentThinking: 'In pensiero…', + sideChat: 'Chat laterale (beta)', + sideChatNew: 'Nuova conversazione', + sideChatUntitled: 'Nuova conversazione', + sideChatEmpty: 'Nessuna conversazione laterale', + sideChatEmptyDesc: 'Ogni conversazione laterale è una scheda a sé nella striscia delle schede — eredita il contesto della sessione attuale e non entra mai nella conversazione principale', + sideChatCreating: 'Creazione della conversazione laterale…', + sideChatRetry: 'Riprova', + sideChatThreads: 'Cambia conversazione / nuova', + sideChatSave: 'Salva come nuova sessione', + sideChatSaveTitle: 'Promuove questa conversazione a sessione di primo livello nella lista delle sessioni principali', + sideChatSaved: 'Salvata come nuova sessione', + sideChatNoTurn: 'Il salvataggio è disponibile dopo il primo turno completato', + sideChatPendingDrop: 'L’ultima domanda di follow-up senza risposta non sarà inclusa nella sessione salvata', + sideChatFirstPlaceholder: 'Ponga la prima domanda — contesto ereditato…', + sideChatComposerPlaceholder: 'Ponga un follow-up…', + sideChatThinking: 'Approfondimento…', + sideChatThink: 'Pensiero', + sideChatInjection: 'Contesto iniettato', + sideChatSend: 'Invia', + sideChatCancel: 'Arresta', + sideChatCancelTitle: 'Interrompe il turno in corso (il lavoro in coda è conservato)', + sideChatClose: 'Chiudi conversazione', + sideChatCloseTitle: 'Rilascia l’agente della conversazione (la cronologia è conservata)', + sideChatError: 'Errore della chat laterale: {message}', + jobs: 'Attività in background', + jobsCount: '{count} attività in background', + jobsCountRunning: '{count} attività in background · {running} in esecuzione', + jobStatusRunning: 'In esecuzione', + jobStatusStopping: 'Arresto in corso', + jobStatusCompleted: 'Completata', + jobStatusKilled: 'Terminata', + jobStatusFailed: 'Non riuscita', + jobDurationSeconds: '{seconds}s', + jobDurationMinutes: '{minutes}min {seconds}s', + jobDurationHours: '{hours}h {minutes}min', + jobViewOutput: 'Vedi output', + jobHideOutput: 'Nascondi output', + jobNoOutput: 'Nessun output per ora', + jobNotReadYet: 'In attesa che il modello legga questa attività; il suo output compare qui quando il modello esegue job_output', + jobOutputTruncated: 'Output troncato', + jobOutputError: 'Lettura dell’output non riuscita', + jobKill: 'Termina', + jobKillConfirm: 'Faccia di nuovo clic per confermare la terminazione', + jobKillError: 'Terminazione non riuscita', + addPluginsTabCard: 'Aggiungi plugin scheda', + addPluginsTabCardDesc: 'Registri una nuova pagina della barra laterale', + addPluginsViewerCard: 'Aggiungi plugin di anteprima', + addPluginsViewerCardDesc: 'Registri un’anteprima di tipo di file', + addPluginsTabDesc: 'Le pagine della barra laterale (schede) possono essere estese dai plugin. I plugin si registrano tramite il servizio ctx.betterSidebar; cliccando Installa viene copiato il comando di installazione — lo incolli in un terminale dove risiede il profilo DSH e lo esegua.', + addPluginsViewerDesc: 'I visualizzatori di file possono essere estesi dai plugin. I plugin si registrano tramite il servizio ctx.betterSidebar; cliccando Installa viene copiato il comando di installazione — lo incolli in un terminale dove risiede il profilo DSH e lo esegua.', + addPluginsBrowseMore: 'Sfogli altri plugin su GitHub (topic: dsh-better-sidebar)', + addPluginsSearch: 'Cerca per nome / descrizione del plugin…', + addPluginsNoMatch: 'Nessun plugin corrispondente', + addPluginsRecommended: 'Plugin consigliati', + addPluginsEmpty: 'Nessun plugin curato per ora — pubblichi il suo sotto il topic GitHub', + openPlugin: 'Apri', + copyInstall: 'Copia comando di installazione', + pluginOfficeDesc: 'Anteprima della suite Office (.docx / .xlsx / .pptx) per l’editor di better-sidebar, tenendo le pesanti librerie di rendering Office fuori dal bundle principale, installabili su richiesta', + pluginFlowglassDesc: 'Diagramma di flusso live della sessione con tre corsie per utente, assistente e chiamate agli strumenti, più gruppi paralleli, rami dei sottoagenti, drill-down e stato in tempo reale; registra una scheda nativa Flowglass quando better-sidebar è installato e mantiene il suo cassetto autonomo come fallback', + pluginGitForgeDesc: 'Scheda Git Forge: libreria di account GitHub/Gitea (e altri forge) + concessioni per progetto + blocco rigido della politica di push; i token restano nei segreti locali (mai nel contesto del modello); strumento GitForge in sola lettura e helper di credenziali HTTPS per l’agente', + pluginGitRemotesDesc: 'Scheda Git Remotes: rami/upstream/ahead-behind, fetch (prune opzionale), pull ff-only e push solo dopo una conferma nella scheda. Non sostituisce la scheda stage/commit integrata di Git, e non offre force-push o uno strumento di push automatico del modello', + pluginSentinelDesc: 'Sistema di risveglio dell’agente guidato da condizioni: sensori file/processo/porta/HTTP/comando/webhook risvegliano le sessioni dormienti quando le condizioni si verificano; registra una scheda «Sentinella» con la tabella di monitoraggio globale del server', + pluginSidebarQaDesc: 'Selezione e domanda: selezioni il testo della conversazione → ponga la domanda nel pannello a destra → una sessione di follow-up dedicata (❓ follow-up) nello stesso spazio di lavoro; un modello veloce senza pensiero comprime il contesto principale e lo inietta con la citazione, senza interrompere la conversazione principale. I follow-up si annidano, proseguono e si archiviano', + pluginSshTunnelDesc: 'Scheda SSH Tunnel: inventario multi-host + concessioni per progetto + chiavi locali; strumento SSHManager per il modello (exec/SFTP/strategie di sessione); terminale interattivo centrale e SFTP a due pannelli', + pluginTurnReviewDesc: 'Una porta umana sul diff del turno appena concluso: Approve / Request changes per percorso con un commento facoltativo; percorsi raggruppati per sessione principale / sottoagente / non attribuito; diff snapshot-vs-ora in linea prima di decidere. Nessun fork, nessun /rewind', + pluginVideoPreviewDesc: 'Anteprima video in linea nell’editor di better-sidebar (.mp4/.webm/.mov/.mkv/.avi ecc.), supportata da una route host /video dedicata con supporto HTTP Range (206) — la barra di scorrimento funziona e i file non sono limitati dal mediaLimit di 20MB', + pluginDocsPanelDesc: 'Documenti globali nella barra laterale di DSH: legga le sue note Markdown da qualsiasi spazio di lavoro — una lista di file, una struttura, apertura in Chrome / VS Code e pulsanti di copia; la directory dei documenti è configurabile (predefinita ~/.dsh/docs)', +} diff --git a/src/client/locales-ko.ts b/src/client/locales-ko.ts new file mode 100644 index 0000000..7e3bbd5 --- /dev/null +++ b/src/client/locales-ko.ts @@ -0,0 +1,337 @@ +/** + * Korean dictionary for the better-sidebar plugin (LOCALE_NS `betterSidebar`). + * + * Key-set-equal to the zh dictionary in `./locales.ts` (zh is the source of + * truth). Registered through the better-locale override store when that + * plugin is installed; the override borrows DSH's English slot, so it takes + * effect only while DSH's active locale is `'en'`. + */ + +export const ko: Record = { + files: '파일', + explorer: '탐색기', + git: '소스 제어', + terminal: '터미널', + editor: '편집기', + editorExplorer: '파일 열기 방식', + editorExplorerDesc: '파일이 열리는 방식을 제어합니다', + editorExplorerMerged: '병합', + editorExplorerMergedDesc: '파일이 같은 창에서 그 자리로 전환됩니다. 새 창은 기본으로 파일 트리가 펼쳐집니다', + editorExplorerSplit: '분리', + editorExplorerSplitDesc: '경로가 없는 창은 파일 탐색기(파일 트리만)입니다. 파일은 각자 새 창(파일 트리 포함, 기본 접힘)으로 열립니다', + editorTreeToggle: '파일 트리 패널', + editorPathPlaceholder: '파일 경로 입력(세션 디렉터리 기준 상대 경로 또는 절대 경로), Enter로 열기', + editorSearchPlaceholder: '파일 이름으로 검색…', + editorSearchNoResults: '일치하는 파일 없음', + editorSearchTruncated: '결과가 너무 많아 일부 일치 항목만 표시합니다', + editorEmptyHint: '오른쪽 파일 트리나 위쪽 경로 입력란에서 파일을 선택해 미리보기를 시작하세요', + openFileNewTab: '새 Tab으로 열기', + openFileSide: '측면에 열기', + openWithMenu: '앱에서 열기', + openWithSshSuffix: ' (SSH)', + pinOpenWith: '메뉴에 고정', + unpinOpenWith: '고정 해제', + openWithExplorer: '파일 탐색기', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'SSH 원격 호스트', + openWithSettingsSshDesc: '비워두면 로컬 작업 공간입니다. user@host 또는 SSH 별칭을 입력하면 VSCode 계열 열기 방식이 vscode-remote/ssh-remote 프로토콜을 사용하게 되며, 파일 탐색기 / Zed / 비 VSCode 계열 사용자 지정 편집기는 메뉴에서 숨겨집니다', + openWithSettingsSshPlaceholder: 'user@host 또는 SSH 별칭', + openWithSettingsCustomTitle: '사용자 지정 편집기', + openWithSettingsCustomDesc: '이름 + URL 템플릿({path} 자리 표시자) + VSCode 계열 여부. SSH 모드에서는 VSCode 계열만 원격을 열 수 있습니다', + openWithSettingsAdd: '추가', + openWithSettingsName: '이름', + openWithSettingsTemplate: '예: cursor://file/{path}', + openWithSettingsFamily: 'VSCode 계열', + openWithSettingsFamilyDesc: '이 편집기는 VSCode의 URL 프로토콜을 사용합니다(SSH 원격 열기 지원)', + openWithSettingsRemove: '삭제', + openWithSettingsInvalidHint: '이름이나 템플릿({path} 포함, scheme:// 로 시작해야 함)을 입력하지 않은 편집기는 메뉴에 표시되지 않습니다', + newTab: '새 탭', + openExplorer: '파일 탐색기', + brokenSymlink: '깨진 심볼릭 링크', + openGit: 'Git 패널', + newTerminal: '새 터미널', + terminalLimit: '터미널 개수가 최대치에 도달했습니다 (3)', + close: '닫기', + closeOtherTabs: '다른 탭 닫기', + closeLeftTabs: '왼쪽 탭 닫기', + closeRightTabs: '오른쪽 탭 닫기', + collapse: '사이드바 접기', + expand: '사이드바 펼치기', + collapseBottomPanel: '하단 패널 접기', + expandBottomPanel: '하단 패널 펼치기', + terminalError: '터미널 연결 실패', + terminalConnectFailed: '터미널 연결이 여러 번 실패했습니다', + terminalRetry: '다시 시도', + terminalDepsFailed: '터미널 의존성 node-pty 로드 실패', + terminalDepsHint: 'DSH가 설치된 환경의 터미널 또는 cmd에서 아래 명령을 실행하여 복구한 후 다시 시도를 클릭하세요(node-pty는 DSH 코어와 동일한 버전을 유지합니다):', + terminalDepsProfile: ' (profile 감지됨: {profile})', + preview: '미리보기', + edit: '편집', + mermaidError: 'Mermaid 렌더링 실패', + mermaidZoomIn: '확대', + mermaidZoomOut: '축소', + mermaidZoomReset: '초기화', + mermaidZoomHint: '휠로 확대/축소 · 드래그로 이동 · Esc로 닫기', + refresh: '새로고침', + save: '저장', + saved: '저장됨', + unsaved: '저장 안 됨', + saveFailed: '저장 실패', + truncation: '파일이 너무 커 앞의 512KB만 표시합니다', + binary: '이진 파일이라 미리보기를 할 수 없습니다', + loading: '불러오는 중…', + error: '불러오기 실패', + retry: '다시 시도', + splitLeft: '왼쪽으로 분할', + splitRight: '오른쪽으로 분할', + splitUp: '위로 분할', + splitDown: '아래로 분할', + notRepo: '현재 디렉터리는 git 저장소가 아닙니다', + noChanges: '변경 사항 없음', + stage: '스테이징', + unstage: '스테이징 해제', + stageAll: '모두 스테이징', + unstageAll: '모두 스테이징 해제', + commitPlaceholder: '커밋 메시지 (Ctrl+Enter)', + commit: '커밋', + commitError: '커밋 실패', + branch: '브랜치', + checkoutError: '브랜치 전환 실패', + history: '기록', + changes: '변경 사항', + staged: '스테이징됨', + unstaged: '스테이징 안 됨', + cancel: '취소', + diffEmpty: '텍스트 차이 없음', + diffLoadError: '차이(diff) 불러오기 실패', + diffBinary: '이진', + diffAdded: '추가됨', + diffDeleted: '삭제됨', + diffRenamed: '이름 변경됨', + diffExpand: '나머지 {count}줄 펼치기', + diffCollapse: '접기', + discard: '변경 사항 버리기', + discardTitle: '변경 사항 버리기', + discardDesc: '"{path}"의 작업 공간 수정을 버립니다(복구 불가).', + viewCommitDiff: '커밋 차이 보기', + copyShortHash: '짧은 해시 복사', + copyFullHash: '전체 해시 복사', + copySubject: '커밋 메시지 복사', + revertCommit: '이 커밋 되돌리기', + revertTitle: '이 커밋 되돌리기', + revertDesc: '현재 브랜치에 "{subject}"을(를) 되돌리는 새 커밋을 만듭니다.', + cherryPickCommit: '이 커밋 체리픽', + cherryPickTitle: '이 커밋 체리픽', + cherryPickDesc: '"{subject}"의 변경 사항을 현재 브랜치에 적용합니다.', + timeJustNow: '방금', + timeMinutesAgo: '{n}분 전', + timeHoursAgo: '{n}시간 전', + timeYesterday: '어제', + loadMore: '더 불러오기', + historyLoadError: '더 많은 기록 불러오기 실패', + produced: '이번 산출물', + producedOpen: '사이드바에서 열기', + disconnected: '터미널 연결이 끊겨 다시 연결하는 중…', + exited: '터미널 프로세스가 종료되었습니다', + noSession: '사이드바를 사용하려면 대화를 선택하세요', + pluginNotLoaded: '플러그인이 로드되지 않아 탭을 지금 사용할 수 없습니다:', + hiddenFiles: '숨김 파일', + parent: '상위 디렉터리', + copied: '복사됨', + copy: '복사', + newFile: '새 파일', + openEditor: '편집기 열기', + gitDetail: '변경 사항 세부 정보 보기', + referenceFile: '@파일', + addToConversation: '대화에 추가', + copyRelative: '상대 경로 복사', + copyAbsolute: '절대 경로 복사', + download: '다운로드', + uploadFiles: '파일 업로드', + uploadFolder: '폴더 업로드', + uploadHere: '여기에 업로드', + uploadDropHint: '파일/폴더를 여기로 끌어다 놓아 업로드', + uploadDropChat: '채팅 영역에 끌어다 놓기: 대화에 이미지 추가', + uploadTo: '{dir}에 업로드', + uploadingTo: '{dir}에 업로드 중…', + uploadProgress: '{done}/{total} 업로드 중: {name}', + uploadDone: '파일 {count}개 업로드됨', + uploadFailed: '업로드 실패: {error}', + uploadFailedUnknown: '알 수 없는 오류', + uploadTooLarge: '파일이 너무 커 업로드 상한을 초과했습니다', + uploadCancelled: '업로드가 취소됨', + settingsNav: '사이드 카드', + settingsIntro: '사이드 카드의 표시 내용과 기본 동작을 관리합니다', + settingsPopupDesc: '"{feature}" 관련 옵션을 구성합니다', + settingsDone: '완료', + settingsOpenTitle: '새 대화 기본 열림', + settingsOpenDesc: '새 대화를 만들 때 사이드 카드를 자동으로 펼칩니다. 기존 대화는 각자의 레이아웃을 유지합니다', + settingsWidthTitle: '기본 너비 비율', + settingsWidthDesc: '새 대화에서 사이드 카드가 창 너비에서 차지하는 비율(%) (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: '채팅 영역 파일을 사이드바에서 열기', + settingsOpenPathDesc: '채팅에서 파일 링크(도구 행, 산출물 목록, 파일 언급)를 클릭하면 사이드바 편집기에서 열고, 시스템 기본 앱은 호출하지 않습니다', + settingsTitleBarTitle: '위치 호환 모드', + settingsTitleBarDesc: '상단 바 호환 방식을 선택하세요: 자동 감지(기본, 보수적) / DSH 공식 Web / 알려진 데스크톱 셸 / 사용자 지정 방식(하강 거리 + 사용자 지정 CSS)', + settingsTitleBarStripTitle: '하강 거리', + settingsTitleBarStripDesc: '타이틀 바 스트립 높이: 사이드바 버튼과 콘텐츠가 아래로 내려가는 픽셀 수(0–120, 기본 40. 사용자 지정 방식에서 적용)', + settingsSchemeAutoTitle: '자동 감지', + settingsSchemeAutoDesc: '보수적 방식: Window Controls Overlay 표준 API를 사용할 수 있을 때만 실제 타이틀 바 높이만큼 양보합니다. 웹 환경에서는 아무 것도 수정하지 않습니다', + settingsSchemeWebTitle: 'DSH 공식 Web', + settingsSchemeWebDesc: '공식 웹 버전에서 실행 중임을 명시적으로 선언합니다. 어떤 적응도 하지 않습니다(표준 WCO 기하 정보도 적용하지 않음)', + settingsSchemeCustomTitle: '사용자 지정 방식', + settingsSchemeCustomDesc: '전적으로 사용자가 제어합니다. 사용자 지정 CSS(내장 스타일 덮어쓰기 가능)를 주입하고 타이틀 바 하강 거리를 지정합니다', + settingsSchemeDetectedSuffix: '감지됨', + settingsCustomCssTitle: '사용자 지정 CSS', + settingsCustomCssDesc: '페이지 끝에 추가되는 스타일(동일 우선순위에서는 나중에 쓴 것이 이깁니다. JS 인라인 변수를 덮으려면 !important를 사용해야 합니다)', + settingsCustomCssPlaceholder: '/* 예: 직접 그린 타이틀 바의 셸을 위해 36px 확보 */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: '저장 실패', + settingsConflict: '설정이 다른 창에서 수정되었습니다. 다시 시도하세요', + binaryNoPreview: '이 파일 형식은 미리보기를 지원하지 않습니다', + downloadToView: '다운로드하여 보기', + settingsSubagentTitle: '서브 에이전트를 감지하면 작업 관리 페이지를 자동으로 펼치기', + settingsSubagentDesc: '현재 대화에 새 서브 에이전트가 생기면 사이드바를 자동으로 펼치고 작업 관리 페이지를 엽니다. 끄면 수동으로 열어야 합니다', + settingsJobsTitle: '새 백그라운드 작업이 있으면 백그라운드 작업 페이지를 자동으로 펼치기', + settingsJobsDesc: '현재 대화에 새 백그라운드 작업이 생기면 사이드바를 자동으로 펼치고 백그라운드 작업 페이지를 엽니다(새 작업마다 트리거됨). 끄면 수동으로 열어야 합니다', + settingsToolsTitle: '모델에 터미널 도구 주입', + settingsToolsDesc: '켜면 모델이 terminal_create 등 8개 도구로 사이드바 터미널을 만들고 조작할 수 있습니다(기본 꺼짐)', + settingsBottomTerminalTitle: '하단 패널을 처음 펼칠 때 터미널 자동 열기', + settingsBottomTerminalDesc: '세션에서 하단 패널을 처음 펼칠 때 하단 패널에 새 터미널 탭을 자동으로 열려고 시도합니다(터미널 개수 상한은 여전히 적용됩니다. 기본 켜짐)', + settingsFontFamilyTitle: '터미널 글꼴', + settingsFontFamilyDesc: '터미널 글꼴 모음을 지정합니다(CSS font-family, 예: "JetBrains Mono", monospace. 비워두면 테마의 고정폭 글꼴을 따릅니다)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: '터미널 글꼴 크기', + settingsFontSizeDesc: '터미널 글꼴 크기(9–32, 기본 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'Shell 경로', + settingsShellDesc: 'UI와 모델 터미널이 시작하는 shell(절대 경로 또는 실행 파일 이름). 비워두면 기존 순서로 해석합니다: yaml의 config.shell → $SHELL / 로그인 shell / Windows의 powershell.exe. 이후에 여는 터미널부터 적용됩니다', + settingsShellPlaceholder: '예: /bin/zsh (비워두면 자동 해석)', + settingsShellArgsTitle: 'Shell 인수', + settingsShellArgsDesc: '명시적 shell 시작 인수, 공백으로 구분. 비어 있지 않으면 기본 인수를 완전히 대체합니다(yaml의 shellArgs 계약과 동일)', + settingsShellArgsPlaceholder: '예: -l (비워두면 기본 인수 사용)', + settingsTabsTitle: '사이드바 콘텐츠', + settingsViewersTitle: '파일 미리보기', + settingsGeneralTitle: '일반', + settingsPopup: '기능 설정', + settingsViewerCatchAll: '폴백: 모든 파일', + viewerImage: '이미지', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: '코드', + viewerBinary: '이진 다운로드', + viewerHtml: 'HTML', + browser: '브라우저', + browserPlaceholder: 'URL 입력, 예: example.com', + browserGo: '이동', + browserBack: '뒤로', + browserForward: '앞으로', + browserStart: 'URL을 입력하여 탐색 시작(샌드박스 모드)', + browserBlockedScheme: '차단됨: http/https 링크만 지원합니다', + browserBlockedLoopback: '차단됨: 브라우저에서 로컬 또는 내부 주소에 접근할 수 없습니다', + browserInvalid: '잘못된 URL', + browserNoSandboxWarning: '샌드박스가 꺼짐: 현재 페이지가 인터페이스와 동일 출처로 전체 세션 권한을 가집니다(설정에서 복원 가능)', + htmlNoSandboxWarning: '샌드박스가 꺼짐: 이 HTML이 인터페이스와 동일 출처로 세션 파일과 내부 인터페이스를 읽을 수 있습니다(설정에서 복원 가능)', + sandboxStatusOn: '샌드박스 모드: 사용 중 · 페이지가 인터페이스 데이터와 로컬 파일에 접근할 수 없으며, 로그인 상태와 타사 Cookie는 동작하지 않을 수 있습니다', + sandboxUnlock: '임시 해제(안전하지 않음)', + sandboxRestore: '샌드박스 복원', + settingsHtmlDefaultUnsafeTitle: 'HTML 미리보기를 기본적으로 샌드박스 없이 열기(안전하지 않음)', + settingsHtmlDefaultUnsafeDesc: '켜면 HTML 파일을 열 때마다 미리보기가 기본적으로 샌드박스 없이 열립니다(인터페이스와 동일 출처로 세션 파일과 내부 인터페이스를 읽을 수 있음). 상태 표시줄에서 임시로 샌드박스를 복원할 수 있습니다', + settingsHtmlSandboxTitle: 'HTML 미리보기 샌드박스 끄기(안전하지 않음)', + settingsHtmlSandboxDesc: '끄면 미리보기 HTML이 인터페이스와 동일 출처로 실행되어 세션 파일, 로컬 저장소를 읽고 내부 인터페이스를 호출할 수 있습니다. 완전히 신뢰하는 파일에서만 켜세요', + settingsBrowserSandboxTitle: '브라우저 샌드박스 끄기(안전하지 않음)', + settingsBrowserSandboxDesc: '끄면 방문하는 모든 사이트가 인터페이스와 동일 출처로 실행되어 세션 데이터를 읽고 사용자의 로그인 상태를 가장할 수 있습니다. 완전히 신뢰하는 사이트에서만 켜세요', + settingsBrowserLinksTitle: '채팅 영역 외부 링크를 사이드바에서 열기', + settingsBrowserLinksDesc: '켜면 채팅이나 인터페이스에서 외부 링크를 클릭할 때 새 창 대신 사이드바에서 엽니다. HTTP와 HTTPS는 아래 스위치로 각각 제어할 수 있습니다. Ctrl/Cmd 클릭으로 임시 허용할 수 있습니다', + settingsBrowserHttpTitle: 'HTTP 페이지를 사이드바에서 열기', + settingsBrowserHttpDesc: '켜면 채팅이나 인터페이스에서 HTTP 외부 링크를 클릭할 때 사이드바에서 엽니다(urlTarget을 선언한 플러그인 페이지가 우선). Ctrl/Cmd 클릭으로 임시 허용할 수 있습니다', + settingsBrowserHttpsTitle: 'HTTPS 페이지를 사이드바에서 열기', + settingsBrowserHttpsDesc: '켜면 채팅이나 인터페이스에서 HTTPS 외부 링크를 클릭할 때 사이드바에서 엽니다. 기본 꺼짐: 대부분의 HTTPS 사이트가 임베드를 거부하므로 시스템 브라우저가 더 원활합니다', + browserOpenExternal: '브라우저에서 열기', + browserEmbedBlocked: '{host} 가(이) 임베드 요청을 거부했습니다', + browserEmbedBlockedDesc: '이 사이트는 X-Frame-Options / frame-ancestors로 다른 페이지에 표시되는 것을 금지하여 사이드바에서 로드할 수 없습니다. 브라우저에서 직접 열 수 있습니다', + browserEmbedAnyway: '그래도 로드', + subagent: '작업 관리', + openSubagent: '작업 관리', + subagentMainAgent: '주 에이전트', + subagentEmpty: '서브 에이전트 없음', + subagentEmptyDesc: '현재 주 에이전트에서 파생된 서브 에이전트가 여기에 표시됩니다', + subagentRunning: '실행 중', + subagentInactive: '대기 중', + subagentModeOneShot: '일회성', + subagentModeContinuable: '이어서 가능', + subagentCount: '서브 에이전트 {count}개', + subagentCountRunning: '서브 에이전트 {count}개 · {running} 실행 중', + subagentDiagCorrupt: '기록 손상', + subagentDiagUnsupported: '지원되지 않는 항목', + subagentDiagUnavailable: '사용할 수 없음', + subagentThinking: '생각하는 중…', + sideChat: '사이드 채팅(beta)', + sideChatNew: '새 대화', + sideChatUntitled: '새 대화', + sideChatEmpty: '사이드 대화 없음', + sideChatEmptyDesc: '각 사이드 대화는 탭 바의 독립된 Tab입니다. 현재 세션의 컨텍스트를 상속받아 실행되며, 주 대화에 들어가지 않습니다', + sideChatCreating: '사이드 대화를 만드는 중…', + sideChatRetry: '다시 시도', + sideChatThreads: '스레드 전환 / 새로 만들기', + sideChatSave: '새 세션으로 저장', + sideChatSaveTitle: '이 스레드를 최상위 세션으로 승격하여 주 세션 목록에 표시합니다', + sideChatSaved: '새 세션으로 저장됨', + sideChatNoTurn: '최소 한 턴의 대화를 완료해야 저장할 수 있습니다', + sideChatPendingDrop: '마지막으로 완료되지 않은 후속 질문은 새 세션에 포함되지 않습니다', + sideChatFirstPlaceholder: '첫 번째 질문 입력, 현재 세션 컨텍스트가 상속됨…', + sideChatComposerPlaceholder: '후속 질문…', + sideChatThinking: '더 파고드는 중…', + sideChatThink: '생각 과정', + sideChatInjection: '컨텍스트 주입됨', + sideChatSend: '보내기', + sideChatCancel: '중지', + sideChatCancelTitle: '현재 턴 중단(대기열 유지)', + sideChatClose: '스레드 닫기', + sideChatCloseTitle: '스레드의 agent를 해제합니다(기록은 유지)', + sideChatError: '사이드 대화 오류: {message}', + jobs: '백그라운드 작업', + jobsCount: '백그라운드 작업 {count}개', + jobsCountRunning: '백그라운드 작업 {count}개 · {running} 실행 중', + jobStatusRunning: '실행 중', + jobStatusStopping: '종료 중', + jobStatusCompleted: '완료됨', + jobStatusKilled: '종료됨', + jobStatusFailed: '실패', + jobDurationSeconds: '{seconds}초', + jobDurationMinutes: '{minutes}분 {seconds}초', + jobDurationHours: '{hours}시간 {minutes}분', + jobViewOutput: '출력 보기', + jobHideOutput: '출력 접기', + jobNoOutput: '출력 없음', + jobNotReadYet: '모델이 이 작업의 출력을 읽기를 기다리는 중입니다(모델이 job_output을 실행하면 출력이 여기에 표시됩니다)', + jobOutputTruncated: '출력이 너무 길어 잘라서 표시합니다', + jobOutputError: '출력 읽기 실패', + jobKill: '종료', + jobKillConfirm: '다시 클릭하여 종료 확인', + jobKillError: '종료 실패', + addPluginsTabCard: 'Tab 플러그인 추가', + addPluginsTabCardDesc: '새 사이드바 페이지 등록', + addPluginsViewerCard: '미리보기 플러그인 추가', + addPluginsViewerCardDesc: '새 파일 형식 미리보기 등록', + addPluginsTabDesc: '사이드바 페이지(Tab)는 플러그인으로 확장할 수 있습니다. 플러그인은 ctx.betterSidebar 서비스를 통해 등록합니다. "설치"를 클릭하면 설치 명령이 복사되며, DSH가 설치된 환경의 터미널에 붙여넣어 실행하세요.', + addPluginsViewerDesc: '파일 미리보기는 플러그인으로 확장할 수 있습니다. 플러그인은 ctx.betterSidebar 서비스를 통해 등록합니다. "설치"를 클릭하면 설치 명령이 복사되며, DSH가 설치된 환경의 터미널에 붙여넣어 실행하세요.', + addPluginsBrowseMore: 'GitHub에서 더 많은 플러그인 보기(topic: dsh-better-sidebar)', + addPluginsSearch: '플러그인 이름 / 설명 검색…', + addPluginsNoMatch: '일치하는 플러그인 없음', + addPluginsRecommended: '추천 플러그인', + addPluginsEmpty: '아직 플러그인이 등록되지 않았습니다. GitHub topic 아래에 플러그인을 공개해 주세요', + openPlugin: '이동', + copyInstall: '설치 명령 복사', + pluginOfficeDesc: 'better-sidebar 편집기에 Office 3종 미리보기(.docx / .xlsx / .pptx)를 제공하며, 무거운 Office 렌더링 라이브러리를 메인 패키지에서 분리하여 필요할 때 설치합니다', + pluginFlowglassDesc: '실시간 세션 흐름도: 사용자, 어시스턴트, 도구 호출을 3열 레인으로 표시하며, 병렬 그룹, 서브 에이전트 지선, 단계별 드릴다운과 실시간 상태를 지원합니다. better-sidebar 설치 시 기본 "흐름 거울(流镜)" Tab을 등록하고, 미설치 시 독립 서랍을 유지합니다', + pluginGitForgeDesc: 'better-sidebar "Git 자격 증명" Tab: GitHub/Gitea 등 Forge 계정 라이브러리 + 프로젝트별 권한 + push 정책 하드 차단. 토큰은 로컬 secrets에만 저장되고 모델 컨텍스트에 들어가지 않습니다. 읽기 전용 GitForge 도구와 agent HTTPS credential helper를 제공합니다', + pluginGitRemotesDesc: 'better-sidebar Git 원격 Tab: 브랜치/업스트림/ahead-behind 확인, fetch(prune 가능), ff-only pull, 확인 후에만 push. 내장 Git의 스테이징/커밋을 대체하지 않으며, force-push나 모델 자동 push도 제공하지 않습니다', + pluginSentinelDesc: '조건 기반 agent 웨이크업 시스템: 파일/프로세스/포트/HTTP/명령/webhook 센서가 조건을 충족하면 휴면 세션을 자동으로 깨웁니다. "센티널(哨兵)" Tab을 등록하여 서버 전역 모니터링 표를 보여줍니다', + pluginSidebarQaDesc: 'better-sidebar 기반 드래그 선택 질문 탭: 대화 드래그 선택 → 오른쪽 패널 질문 → 같은 작업 공간의 독립 후속 질문 세션(❓후속 질문·주제). 빠른 무사고 모델이 주 대화 컨텍스트를 압축한 후 인용과 함께 주입하며, 주 대화를 방해하지 않습니다. 후속 질문은 중첩, 계속, 보관이 가능합니다', + pluginSshTunnelDesc: 'better-sidebar "SSH 터널" Tab: 다중 호스트 목록 + 프로젝트별 권한 + 키 로컬 보관. 모델 도구 SSHManager(exec/SFTP/세션 전략). 중앙 대화형 터미널과 이중 창 SFTP', + pluginTurnReviewDesc: '방금 끝난 턴의 diff에 대해 Approve / Request changes를 하는 사람 게이트: 지난 턴만 검토하며 세션을 fork하지 않습니다. 파일을 주 세션/서브 에이전트/미귀속으로 그룹화하고, 파일별로 선택하여 반려 + 선택적 코멘트. 파일을 클릭하면 턴 시작 스냅샷 vs 현재 diff를 먼저 봅니다. /rewind가 아닙니다', + pluginVideoPreviewDesc: 'better-sidebar 편집기에서 비디오 파일(.mp4/.webm/.mov/.mkv/.avi 등)을 인라인 미리보기합니다. HTTP Range(206)를 지원하는 /video 호스트 라우트를 내장하며, 진행 바를 드래그할 수 있고 20MB mediaLimit 제한을 받지 않습니다', + pluginDocsPanelDesc: 'DSH 사이드바의 "전역 문서": 전역 Markdown 메모로, 어떤 작업 공간에서든 언제든 읽을 수 있습니다. 목록을 클릭해 읽기, 마우스를 올리면 개요로 이동, Chrome / VS Code에서 외부 열기, 코드 복사. 디렉터리를 설정할 수 있습니다(기본 ~/.dsh/docs)', +} diff --git a/src/client/locales-nl.ts b/src/client/locales-nl.ts new file mode 100644 index 0000000..252d3dc --- /dev/null +++ b/src/client/locales-nl.ts @@ -0,0 +1,343 @@ +/** + * The nl (Dutch) dictionary for the betterSidebar namespace. + * + * Mirrors the key set of `zh` in `locales.ts`. The sidebar's `t()` + * consults this dict when `attachBetterLocale(store)` has been called + * with an active better-locale store whose `active` is `'nl'`; absent + * that, the existing zh/en chain runs unchanged. + * + * Translation conventions: + * - Formal "u" form for user-facing text. + * - Technical loanwords stay in English (Git, SSH, HTTP, URL, Markdown, PDF, VS Code). + * - Git vocabulary follows English-derived conventions (stagen, unstagen, commit, branch). + * - Placeholders keep `{name}` verbatim (interpolation runs after lookup). + * - English brand names (VS Code, Cursor, Zed, SSH) stay as-is. + */ +export const nl: Record = { + files: 'Bestanden', + explorer: 'Verkenner', + git: 'Bronbeheer', + terminal: 'Terminal', + editor: 'Editor', + editorExplorer: 'Bestand openingsgedrag', + editorExplorerDesc: 'Bepaalt hoe bestanden worden geopend', + editorExplorerMerged: 'Samengevoegd', + editorExplorerMergedDesc: 'Bestanden wisselen in-place in hetzelfde venster; nieuwe vensters beginnen met de boom open', + editorExplorerSplit: 'Afzonderlijk', + editorExplorerSplitDesc: 'Vensters zonder pad zijn de zelfstandige verkenner (alleen bestandsboom); elk bestand opent een eigen venster (boom gedockt, standaard gesloten)', + editorTreeToggle: 'Bestandsboompaneel', + editorPathPlaceholder: 'Voer een bestandspad in (relatief aan de sessiemap of absoluut), Enter om te openen', + editorSearchPlaceholder: 'Zoek op bestandsnaam…', + editorSearchNoResults: 'Geen overeenkomende bestanden', + editorSearchTruncated: 'Te veel resultaten — een gedeeltelijke lijst wordt getoond', + editorEmptyHint: 'Kies een bestand uit het boompaneel of het pad-invoerveld hierboven om te beginnen met previewen', + openFileNewTab: 'Openen in nieuw tabblad', + openFileSide: 'Openen aan de zijkant', + openWithMenu: 'Openen met', + openWithSshSuffix: ' (SSH)', + pinOpenWith: 'Vastmaken aan menu', + unpinOpenWith: 'Losmaken', + openWithExplorer: 'Bestandsbeheerder', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'SSH externe host', + openWithSettingsSshDesc: 'Leeg = lokale werkruimte; met een user@host of SSH-alias schakelen VSCode-familie-openers over op het vscode-remote/ssh-remote protocol en worden de Bestandsbeheerder / Zed / niet-VSCode-familie custom editors verborgen uit het menu', + openWithSettingsSshPlaceholder: 'user@host of SSH-alias', + openWithSettingsCustomTitle: 'Aangepaste editors', + openWithSettingsCustomDesc: 'Naam + URL-sjabloon ({path} placeholder) + VSCode-familie-vlag; in externe modus kunnen alleen VSCode-familie-editors een extern pad openen', + openWithSettingsAdd: 'Toevoegen', + openWithSettingsName: 'Naam', + openWithSettingsTemplate: 'bijv. cursor://file/{path}', + openWithSettingsFamily: 'VSCode-familie', + openWithSettingsFamilyDesc: 'Deze editor spreekt het VSCode URL-dialect (ondersteunt SSH-externe openingen)', + openWithSettingsRemove: 'Verwijderen', + openWithSettingsInvalidHint: 'Editors met een ontbrekende naam of een sjabloon zonder {path} / scheme:// worden niet in het menu getoond', + newTab: 'Nieuw tabblad', + openExplorer: 'Verkenner', + brokenSymlink: 'Gebroken symlink', + openGit: 'Git-paneel', + newTerminal: 'Nieuwe terminal', + terminalLimit: 'Terminallimiet bereikt (3)', + close: 'Sluiten', + closeOtherTabs: 'Andere tabbladen sluiten', + closeLeftTabs: 'Tabbladen links sluiten', + closeRightTabs: 'Tabbladen rechts sluiten', + collapse: 'Zijbalk inklappen', + expand: 'Zijbalk uitklappen', + collapseBottomPanel: 'Onderpaneel inklappen', + expandBottomPanel: 'Onderpaneel uitklappen', + terminalError: 'Terminalverbinding mislukt', + terminalConnectFailed: 'Terminalverbinding herhaaldelijk mislukt', + terminalRetry: 'Opnieuw proberen', + terminalDepsFailed: 'Terminalafhankelijkheid node-pty kon niet worden geladen', + terminalDepsHint: 'Voer het onderstaande commando uit in een terminal of cmd op de DSH-machine om het te herstellen en probeer het opnieuw (node-pty blijft in sync met de DSH-coreversie):', + terminalDepsProfile: ' (gedetecteerde profile: {profile})', + preview: 'Voorbeeld', + edit: 'Bewerken', + mermaidError: 'Mermaid-renderen mislukt', + mermaidZoomIn: 'Inzoomen', + mermaidZoomOut: 'Uitzoomen', + mermaidZoomReset: 'Resetten', + mermaidZoomHint: 'Scrollen om te zoomen · slepen om te pannen · Esc om te sluiten', + refresh: 'Vernieuwen', + save: 'Opslaan', + saved: 'Opgeslagen', + unsaved: 'Niet opgeslagen', + saveFailed: 'Opslaan mislukt', + truncation: 'Bestand te groot — alleen de eerste 512KB worden getoond', + binary: 'Binair bestand, geen voorbeeld beschikbaar', + loading: 'Laden…', + error: 'Laden mislukt', + retry: 'Opnieuw proberen', + splitLeft: 'Splitsen links', + splitRight: 'Splitsen rechts', + splitUp: 'Splitsen omhoog', + splitDown: 'Splitsen omlaag', + notRepo: 'Deze map is geen git-repository', + noChanges: 'Geen wijzigingen', + stage: 'Stagen', + unstage: 'Unstagen', + stageAll: 'Alles stagen', + unstageAll: 'Alles unstagen', + commitPlaceholder: 'Commitbericht (Ctrl+Enter)', + commit: 'Commit', + commitError: 'Commit mislukt', + branch: 'Branch', + checkoutError: 'Wisselen van branch mislukt', + history: 'Geschiedenis', + changes: 'Wijzigingen', + staged: 'Gestaged', + unstaged: 'Niet gestaged', + cancel: 'Annuleren', + diffEmpty: 'Geen tekstwijzigingen', + diffLoadError: 'Diff laden mislukt', + diffBinary: 'Binair', + diffAdded: 'Toegevoegd', + diffDeleted: 'Verwijderd', + diffRenamed: 'Hernoemd', + diffExpand: '{count} rijen extra uitklappen', + diffCollapse: 'Inklappen', + discard: 'Wijzigingen verwijderen', + discardTitle: 'Wijzigingen verwijderen', + discardDesc: 'Dit verwijdert de worktree-wijzigingen van "{path}" (niet terugdraaibaar).', + viewCommitDiff: 'Commit-diff bekijken', + copyShortHash: 'Korte hash kopiëren', + copyFullHash: 'Volledige hash kopiëren', + copySubject: 'Onderwerp kopiëren', + revertCommit: 'Commit reverten', + revertTitle: 'Commit reverten', + revertDesc: 'Maakt een nieuwe commit op de huidige branch die "{subject}" revertd.', + cherryPickCommit: 'Commit cherry-picken', + cherryPickTitle: 'Commit cherry-picken', + cherryPickDesc: 'Past de wijzigingen van "{subject}" toe op de huidige branch.', + timeJustNow: 'zojuist', + timeMinutesAgo: '{n} min geleden', + timeHoursAgo: '{n} u geleden', + timeYesterday: 'gisteren', + loadMore: 'Meer laden', + historyLoadError: 'Meer geschiedenis laden mislukt', + produced: 'Geproduceerd', + producedOpen: 'Openen in zijbalk', + disconnected: 'Terminalverbinding verbroken, opnieuw verbinden…', + exited: 'Terminalproces beëindigd', + noSession: 'Selecteer een conversatie om de zijbalk te gebruiken', + pluginNotLoaded: 'Plugin niet geladen; tabblad niet beschikbaar:', + hiddenFiles: 'Verborgen bestanden', + parent: 'Bovenliggende map', + copied: 'Gekopieerd', + copy: 'Kopiëren', + newFile: 'Nieuw bestand', + openEditor: 'Editor openen', + gitDetail: 'Wijzigingsdetails bekijken', + referenceFile: '@bestand', + addToConversation: 'Aan conversatie toevoegen', + copyRelative: 'Relatief pad kopiëren', + copyAbsolute: 'Absoluut pad kopiëren', + download: 'Downloaden', + uploadFiles: 'Bestanden uploaden', + uploadFolder: 'Map uploaden', + uploadHere: 'Hier uploaden', + uploadDropHint: 'Sleep bestanden/mappen hierheen om te uploaden', + uploadDropChat: 'Sleep naar de chat om afbeeldingen toe te voegen', + uploadTo: 'Uploaden naar {dir}', + uploadingTo: 'Uploaden naar {dir}…', + uploadProgress: 'Uploaden {done}/{total}: {name}', + uploadDone: '{count} bestand(en) geüpload', + uploadFailed: 'Uploaden mislukt: {error}', + uploadFailedUnknown: 'Onbekende fout', + uploadTooLarge: 'Bestand te groot (boven de uploadlimiet)', + uploadCancelled: 'Upload geannuleerd', + settingsNav: 'Zijkaart', + settingsIntro: 'Beheer wat de zijkaart toont en hoe deze zich gedraagt', + settingsPopupDesc: 'Gerelateerde opties voor {feature} configureren', + settingsDone: 'Klaar', + settingsOpenTitle: 'Standaard openen voor nieuwe conversaties', + settingsOpenDesc: 'De zijkaart automatisch uitklappen voor gloednieuwe conversaties; bestaande conversaties behouden hun eigen layout', + settingsWidthTitle: 'Standaard breedte-aandeel', + settingsWidthDesc: 'Het standaard breedte-aandeel van de zijkaart voor nieuwe conversaties (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: 'Chatbestanden in de zijbalk openen', + settingsOpenPathDesc: 'Bestandslinks in de chat (toolrijen, geproduceerde bestanden, vermeldingen) openen in de zijbalk-editor in plaats van de standaard systeemapp', + settingsTitleBarTitle: 'Positiecompatibiliteitsmodus', + settingsTitleBarDesc: 'Kies het titelbalk-compatibiliteitsschema: auto-detect (standaard, conservatief) / DSH officiële web / bekende desktop-shells / aangepast (verschuivingsafstand + aangepaste CSS)', + settingsTitleBarStripTitle: 'Verschuivingsafstand', + settingsTitleBarStripDesc: 'Titelbalk-striphoogte: hoeveel pixels de zijbalkknoppen en -inhoud naar beneden schuiven (0–120, standaard 40; geldt onder het aangepaste schema)', + settingsSchemeAutoTitle: 'Auto-detect', + settingsSchemeAutoDesc: 'Conservatief: alleen de standaard Window Controls Overlay API draagt bij (werkelijke caption-overlay-hoogte); gewone webomgevingen worden niet aangepast', + settingsSchemeWebTitle: 'DSH officiële web', + settingsSchemeWebDesc: 'Expliciet declareren dat u op de officiële web-UI draait: geen enkele aanpassing (ook de standaard WCO-geometrie niet)', + settingsSchemeCustomTitle: 'Aangepast', + settingsSchemeCustomDesc: 'Volledige controle: aangepaste CSS injecteren (kan ingebouwde stijlen overschrijven) en de verschuivingsafstand van de titelbalk instellen', + settingsSchemeDetectedSuffix: 'gedetecteerd', + settingsCustomCssTitle: 'Aangepaste CSS', + settingsCustomCssDesc: 'Stijlen die aan het einde van de pagina worden toegevoegd (later in de cascade wint bij gelijke prioriteit; gebruik !important om JS-geschreven inline-variabelen te overschrijven)', + settingsCustomCssPlaceholder: '/* bijv. reserveer 36px voor een shell met een zelf-getekende titelbalk */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: 'Opslaan mislukt', + settingsConflict: 'De instelling is in een ander venster gewijzigd — probeer het opnieuw', + binaryNoPreview: 'Dit bestandstype kan niet worden gepreviewed', + downloadToView: 'Downloaden om te bekijken', + settingsSubagentTitle: 'Taken-pagina automatisch openen wanneer een subagent verschijnt', + settingsSubagentDesc: 'De zijkaart uitklappen en de Taken-pagina openen wanneer de huidige conversatie een nieuwe subagent voortbrengt; schakel uit om het handmatig te openen', + settingsJobsTitle: 'Jobs-pagina automatisch openen bij een nieuwe achtergrondtaak', + settingsJobsDesc: 'De zijkaart uitklappen en de Jobs-pagina openen telkens een nieuwe achtergrondtaak verschijnt voor de huidige conversatie (elke nieuwe taak triggert); schakel uit om het handmatig te openen', + settingsToolsTitle: 'Terminaltools voor het model injecteren', + settingsToolsDesc: 'Indien ingeschakeld kan het model zijbalk-terminals aanmaken en besturen via de 8 terminal_*-tools (standaard uit)', + settingsBottomTerminalTitle: 'Automatisch een terminal openen bij de eerste uitklap van het onderpaneel', + settingsBottomTerminalDesc: 'Wanneer het onderpaneel voor het eerst in een sessie wordt uitgeklapt, wordt geprobeerd daar een nieuw terminaltabblad te openen (het terminalquotum blijft gelden; standaard aan)', + settingsFontFamilyTitle: 'Terminallettertype-familie', + settingsFontFamilyDesc: 'Aangepaste terminallettertype-familie (een CSS font-family-stack zoals "JetBrains Mono", monospace; leeg laten om het monospace-lettertype van het thema te volgen)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: 'Terminallettergrootte', + settingsFontSizeDesc: 'Terminallettergrootte in px (9–32, standaard 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'Shell-pad', + settingsShellDesc: 'Shell die wordt gestart voor UI- en model-terminals (absoluut pad of kale executable). Leeg houden volgt de bestaande volgorde: yaml config.shell → $SHELL / inlog-shell / Windows powershell.exe. Geldt voor terminals die daarna worden geopend', + settingsShellPlaceholder: 'bijv. /bin/zsh (leeg = auto)', + settingsShellArgsTitle: 'Shell-argumenten', + settingsShellArgsDesc: 'Expliciete shell-argumenten, spatiegescheiden; indien niet-leeg vervangen ze de standaardwaarden volledig (zelfde contract als de yaml shellArgs)', + settingsShellArgsPlaceholder: 'bijv. -l (leeg = standaardwaarden)', + settingsTabsTitle: 'Zijbalk-inhoud', + settingsViewersTitle: 'Bestandsviewers', + settingsGeneralTitle: 'Algemeen', + settingsPopup: 'Functie-instellingen', + settingsViewerCatchAll: 'Catch-all: elk bestand', + viewerImage: 'Afbeelding', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: 'Code', + viewerBinary: 'Binaire download', + viewerHtml: 'HTML', + browser: 'Browser', + browserPlaceholder: 'Voer een URL in, bijv. example.com', + browserGo: 'Ga', + browserBack: 'Terug', + browserForward: 'Vooruit', + browserStart: 'Voer een URL in om te beginnen met browsen (sandbox-modus)', + browserBlockedScheme: 'Geblokkeerd: alleen http/https-URL\'s zijn toegestaan', + browserBlockedLoopback: 'Geblokkeerd: lokale en interne adressen kunnen hier niet worden bezocht', + browserInvalid: 'Ongeldige URL', + browserNoSandboxWarning: 'Sandbox uit: de huidige pagina draait met volledige GUI-privileges (herinschakelen in instellingen)', + htmlNoSandboxWarning: 'Sandbox uit: deze HTML draait met volledige GUI-privileges (herinschakelen in instellingen)', + sandboxStatusOn: 'Sandbox-modus: aan · pagina\'s kunnen de GUI-gegevens of lokale bestanden niet benaderen; logins en third-party cookies werken mogelijk niet', + sandboxUnlock: 'Tijdelijk uitschakelen (onveilig)', + sandboxRestore: 'Sandbox herstellen', + settingsHtmlDefaultUnsafeTitle: 'HTML-voorbeelden standaard zonder sandbox openen (onveilig)', + settingsHtmlDefaultUnsafeDesc: 'Indien aan, start elke nieuw geopende HTML-voorbeeld in de niet-gesandboxte staat (zelfde origin als de GUI — kan sessiebestanden en interne API\'s lezen); de statusbalk biedt nog een eenkliks-herstel', + settingsHtmlSandboxTitle: 'HTML-voorbeeld-sandbox uitschakelen (onveilig)', + settingsHtmlSandboxDesc: 'Met de sandbox uit draait gepreviewde HTML met dezelfde origin als de GUI: kan sessiebestanden, lokale opslag lezen en interne API\'s aanroepen. Alleen inschakelen voor volledig vertrouwde bestanden', + settingsBrowserSandboxTitle: 'Browser-sandbox uitschakelen (onveilig)', + settingsBrowserSandboxDesc: 'Met de sandbox uit draait elke bezochte site met dezelfde origin als de GUI: kan sessiegegevens lezen en zich voordoen als uw ingelogde sessie. Alleen inschakelen voor volledig vertrouwde sites', + settingsBrowserLinksTitle: 'Externe chatlinks in de zijbalk openen', + settingsBrowserLinksDesc: 'Indien aan, opent een klik op een externe link in de chat of GUI de zijbalk in plaats van een nieuw venster; HTTP en HTTPS worden apart bestuurd door de schakelaars hieronder; Ctrl/Cmd+klik omzeilt altijd', + settingsBrowserHttpTitle: 'HTTP-pagina\'s in de zijbalk openen', + settingsBrowserHttpDesc: 'Indien aan, opent een klik op een externe HTTP-link in de chat of GUI de zijbalk (plugin-pagina\'s die urlTarget declareren winnen); Ctrl/Cmd+klik omzeilt altijd', + settingsBrowserHttpsTitle: 'HTTPS-pagina\'s in de zijbalk openen', + settingsBrowserHttpsDesc: 'Indien aan, opent een klik op een externe HTTPS-link in de chat of GUI de zijbalk. Standaard uit: de meeste HTTPS-sites weigeren ingebed te worden, dus de systeembrowser is soepeler', + browserOpenExternal: 'Openen in browser', + browserEmbedBlocked: '{host} weigerde ingebed te worden', + browserEmbedBlockedDesc: 'De site verbiedt weergave binnen andere pagina\'s (X-Frame-Options / frame-ancestors), dus kan niet in de zijbalk laden. Open de site direct in uw browser.', + browserEmbedAnyway: 'Toch laden', + subagent: 'Taken', + openSubagent: 'Taken', + subagentMainAgent: 'Hoofdagent', + subagentEmpty: 'Geen subagents', + subagentEmptyDesc: 'Subagents voortgebracht door de hoofdagent verschijnen hier', + subagentRunning: 'Actief', + subagentInactive: 'Inactief', + subagentModeOneShot: 'One-shot', + subagentModeContinuable: 'Vervolgbaar', + subagentCount: '{count} subagents', + subagentCountRunning: '{count} subagents · {running} actief', + subagentDiagCorrupt: 'Corrupt', + subagentDiagUnsupported: 'Niet ondersteund', + subagentDiagUnavailable: 'Niet beschikbaar', + subagentThinking: 'Nadenken…', + sideChat: 'Side Chat (bèta)', + sideChatNew: 'Nieuwe thread', + sideChatUntitled: 'Nieuwe thread', + sideChatEmpty: 'Geen side-conversaties', + sideChatEmptyDesc: 'Elke side-conversatie is een eigen tabblad in de tabstrip — erft de context van de huidige sessie en komt nooit in de hoofdconversatie', + sideChatCreating: 'Side-conversatie aanmaken…', + sideChatRetry: 'Opnieuw proberen', + sideChatThreads: 'Thread wisselen / nieuw', + sideChatSave: 'Opslaan als nieuwe sessie', + sideChatSaveTitle: 'Promoveer deze thread naar een top-level sessie in de hoofd-sessielijst', + sideChatSaved: 'Opgeslagen als een nieuwe sessie', + sideChatNoTurn: 'Opslaan is pas beschikbaar na de eerste voltooide beurt', + sideChatPendingDrop: 'De laatste onbeantwoorde follow-up wordt niet meegenomen in de opgeslagen sessie', + sideChatFirstPlaceholder: 'Stel de eerste vraag — context overgenomen…', + sideChatComposerPlaceholder: 'Stel een follow-up…', + sideChatThinking: 'Diep ingaan…', + sideChatThink: 'Denken', + sideChatInjection: 'Context geïnjecteerd', + sideChatSend: 'Versturen', + sideChatCancel: 'Stoppen', + sideChatCancelTitle: 'De lopende beurt afbreken (wachtrij blijft behouden)', + sideChatClose: 'Thread sluiten', + sideChatCloseTitle: 'De agent van de thread vrijgeven (geschiedenis blijft behouden)', + sideChatError: 'Side Chat-fout: {message}', + jobs: 'Achtergrondtaken', + jobsCount: '{count} achtergrondtaken', + jobsCountRunning: '{count} achtergrondtaken · {running} actief', + jobStatusRunning: 'Actief', + jobStatusStopping: 'Stoppen', + jobStatusCompleted: 'Voltooid', + jobStatusKilled: 'Beëindigd', + jobStatusFailed: 'Mislukt', + jobDurationSeconds: '{seconds}s', + jobDurationMinutes: '{minutes}m {seconds}s', + jobDurationHours: '{hours}u {minutes}m', + jobViewOutput: 'Uitvoer bekijken', + jobHideOutput: 'Uitvoer verbergen', + jobNoOutput: 'Nog geen uitvoer', + jobNotReadYet: 'Wachten tot het model deze taak leest; de uitvoer verschijnt hier zodra het model job_output uitvoert', + jobOutputTruncated: 'Uitvoer afgekapt', + jobOutputError: 'Uitvoer lezen mislukt', + jobKill: 'Beëindigen', + jobKillConfirm: 'Klik nogmaals om beëindigen te bevestigen', + jobKillError: 'Beëindigen mislukt', + addPluginsTabCard: 'Tabblad-plugins toevoegen', + addPluginsTabCardDesc: 'Een nieuwe zijbalkpagina registreren', + addPluginsViewerCard: 'Preview-plugins toevoegen', + addPluginsViewerCardDesc: 'Een bestandstype-preview registreren', + addPluginsTabDesc: 'Zijbalkpagina\'s (tabbladen) kunnen door plugins worden uitgebreid. Plugins registreren via de ctx.betterSidebar-service; op Installeren klikken kopieert het installatiecommando — plak het in een terminal waar uw DSH-profiel zich bevindt en voer het uit.', + addPluginsViewerDesc: 'Bestandsviewers kunnen door plugins worden uitgebreid. Plugins registreren via de ctx.betterSidebar-service; op Installeren klikken kopieert het installatiecommando — plak het in een terminal waar uw DSH-profiel zich bevindt en voer het uit.', + addPluginsBrowseMore: 'Meer plugins bekijken op GitHub (topic: dsh-better-sidebar)', + addPluginsSearch: 'Zoek op plugin-naam of -beschrijving…', + addPluginsNoMatch: 'Geen plugins komen overeen', + addPluginsRecommended: 'Aanbevolen plugins', + addPluginsEmpty: 'Nog geen plugins samengesteld — publiceer de uwe onder het GitHub-topic', + openPlugin: 'Openen', + copyInstall: 'Installatiecommando kopiëren', + pluginOfficeDesc: 'Office-suite-preview (.docx / .xlsx / .pptx) voor de better-sidebar-editor, de zware Office-renderbibliotheken buiten de core-bundle houdend', + pluginFlowglassDesc: 'Live sessie-flowgraph met drie banen voor gebruiker, assistent en tool-aanroepen, plus parallelle groepen, subagent-takken, drill-down en live status; registreert een native Flowglass-tabblad wanneer better-sidebar is geïnstalleerd en behoudt zijn standalone lade als fallback', + pluginGitForgeDesc: 'Git Forge-tabblad: GitHub/Gitea (en andere forge) accountbibliotheek + per-project grants + harde push-policy; tokens blijven in lokale secrets (nooit in model-context); alleen-lezen GitForge-tool en agent HTTPS-credential-helper', + pluginGitRemotesDesc: 'Git Remotes-tabblad: branch/upstream/ahead-behind, fetch (optioneel prune), ff-only pull, en push pas na een bevestiging in het tabblad. Vervangt het ingebouwde Git stage/commit-tabblad niet, en biedt geen force-push of een model-auto-push-tool', + pluginSentinelDesc: 'Conditie-gedreven agent-wakeupsysteem: bestands/proces/poort/http/command/webhook-sensoren wekken slapende sessies wanneer condities af gaan; registreert een "Sentinel"-tabblad met de serverbrede watch-tabel', + pluginSidebarQaDesc: 'Select-and-ask: Selecteer conversatie-tekst → vraag in het rechterpaneel → een toegewijde follow-up-sessie (❓ follow-up) in dezelfde werkruimte; een snel no-thinking-model comprimeert de hoofdcontext en injecteert deze met de quote, zonder de hoofdconversatie te onderbreken. Follow-ups nesten, vervolgen en archiveren', + pluginSshTunnelDesc: 'SSH Tunnel-tabblad: multi-host-inventaris + per-project grants + lokale secrets; SSHManager-tool (exec/SFTP/sessie-strategieën); centrale interactieve terminal en dubbelpanelig SFTP', + pluginTurnReviewDesc: 'Een menselijke poort op de net voltooide beurt: Approve / Request changes per pad met een optionele opmerking; paden gegroepeerd op hoofd-sessie / subagent / niet-toegeschreven; inline snapshot-vs-nu diff voordat u beslist. Geen fork, geen /rewind', + pluginVideoPreviewDesc: 'Inline videovoorbeeld (.mp4/.webm/.mov/.mkv/.avi enz.) voor de better-sidebar-editor, ondersteund door een toegewijde /video-host-route met HTTP Range (206)-ondersteuning — scrubben werkt en bestanden worden niet beperkt door de 20MB mediaLimit', + pluginDocsPanelDesc: 'Globale docs in de DSH-zijbalk: lees uw eigen Markdown-notities vanuit elke werkruimte — een bestandslijst, een outline, openen in Chrome / VS Code, en kopieerknoppen; de docs-map is configureerbaar (standaard ~/.dsh/docs)', +} diff --git a/src/client/locales-pl.ts b/src/client/locales-pl.ts new file mode 100644 index 0000000..e4adacd --- /dev/null +++ b/src/client/locales-pl.ts @@ -0,0 +1,347 @@ +/** + * The pl (Polish) dictionary for the betterSidebar namespace. + * + * Mirrors the key set of `zh` in `locales.ts`. The sidebar's `t()` + * consults this dict when `attachBetterLocale(store)` has been called + * with an active better-locale store whose `active` is `'pl'`; absent + * that, the existing zh/en chain runs unchanged. + * + * Translation conventions: + * - Formal register (Pan/Pani/Państwo) for user-facing copy. + * - Polish diacritics used throughout (ą, ć, ę, ł, ń, ó, ś, ź, ż). + * - {placeholder} patterns kept verbatim (interpolation runs after lookup). + * - Git vocabulary follows the English-leaning developer style + * (commit, branch, stage, diff, cherry-pick, hash, push, fetch, pull). + * - English brand names (VS Code, Cursor, Zed, SSH, Mermaid, HTML, CSS, + * PDF, Markdown, Cursor) stay as-is. + */ + +/** The pl dictionary (key-set-equal to zh, enforced by the type annotation in locales.ts). */ +export const pl: Record = { + files: 'Pliki', + explorer: 'Eksplorator', + git: 'Kontrola źródła', + terminal: 'Terminal', + editor: 'Edytor', + editorExplorer: 'Sposób otwierania plików', + editorExplorerDesc: 'Kontroluje sposób otwierania plików', + editorExplorerMerged: 'Połączone', + editorExplorerMergedDesc: 'Pliki przełączają się w miejscu w tym samym oknie; nowe okna zaczynają z rozwiniętym drzewem', + editorExplorerSplit: 'Osobne', + editorExplorerSplitDesc: 'Okna bez ścieżki to samodzielny eksplorator (tylko drzewo); każdy plik otwiera własne okno (drzewo zadokowane, domyślnie zwinięte)', + editorTreeToggle: 'Panel drzewa plików', + editorPathPlaceholder: 'Ścieżka pliku (względna do katalogu sesji lub bezwzględna), Enter, aby otworzyć', + editorSearchPlaceholder: 'Szukaj po nazwie pliku…', + editorSearchNoResults: 'Brak pasujących plików', + editorSearchTruncated: 'Zbyt wiele wyników — pokazuję częściową listę', + editorEmptyHint: 'Wybierz plik z panelu drzewa lub pola ścieżki powyżej, aby rozpocząć podgląd', + openFileNewTab: 'Otwórz w nowej karcie', + openFileSide: 'Otwórz z boku', + openWithMenu: 'Otwórz za pomocą', + openWithSshSuffix: ' (SSH)', + pinOpenWith: 'Przypnij do menu', + unpinOpenWith: 'Odepnij', + openWithExplorer: 'Menedżer plików', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'Zdalny host SSH', + openWithSettingsSshDesc: 'Puste = lokalny obszar roboczy; z user@host lub aliasem SSH otwieracze rodziny VSCode przełączają się na protokół vscode-remote/ssh-remote, a Menedżer plików / Zed / niestandardowe edytory spoza rodziny VSCode są ukrywane w menu', + openWithSettingsSshPlaceholder: 'user@host lub alias SSH', + openWithSettingsCustomTitle: 'Niestandardowe edytory', + openWithSettingsCustomDesc: 'Nazwa + szablon URL (zastępnik {path}) + flaga rodziny VSCode; w trybie zdalnym tylko edytory rodziny VSCode mogą otwierać ścieżkę zdalną', + openWithSettingsAdd: 'Dodaj', + openWithSettingsName: 'Nazwa', + openWithSettingsTemplate: 'np. cursor://file/{path}', + openWithSettingsFamily: 'Rodzina VSCode', + openWithSettingsFamilyDesc: 'Ten edytor używa dialektu URL VSCode (obsługuje otwieranie zdalne przez SSH)', + openWithSettingsRemove: 'Usuń', + openWithSettingsInvalidHint: 'Edytory z brakującą nazwą lub szablonem bez {path} / scheme:// nie są pokazywane w menu', + newTab: 'Nowa karta', + openExplorer: 'Eksplorator', + brokenSymlink: 'Uszkodzone dowiązanie symboliczne', + openGit: 'Panel Git', + newTerminal: 'Nowy terminal', + terminalLimit: 'Osiągnięto limit terminali (3)', + close: 'Zamknij', + closeOtherTabs: 'Zamknij inne karty', + closeLeftTabs: 'Zamknij karty po lewej', + closeRightTabs: 'Zamknij karty po prawej', + collapse: 'Zwiń panel boczny', + expand: 'Rozwiń panel boczny', + collapseBottomPanel: 'Zwiń panel dolny', + expandBottomPanel: 'Rozwiń panel dolny', + terminalError: 'Połączenie z terminalem nie powiodło się', + terminalConnectFailed: 'Terminal nie mógł połączyć się wielokrotnie', + terminalRetry: 'Ponów', + terminalDepsFailed: 'Zależność terminala node-pty nie mogła się załadować', + terminalDepsHint: 'Uruchom poniższe polecenie w terminalu lub cmd na maszynie DSH, aby to naprawić, a następnie ponów (node-pty pozostaje w synchronizacji z wersją rdzenia DSH):', + terminalDepsProfile: ' (wykryty profil: {profile})', + preview: 'Podgląd', + edit: 'Edytuj', + mermaidError: 'Renderowanie Mermaid nie powiodło się', + mermaidZoomIn: 'Powiększ', + mermaidZoomOut: 'Pomniejsz', + mermaidZoomReset: 'Resetuj', + mermaidZoomHint: 'Kółko: powiększenie · przeciąganie: panowanie · Esc: zamknięcie', + refresh: 'Odśwież', + save: 'Zapisz', + saved: 'Zapisano', + unsaved: 'Niezapisane', + saveFailed: 'Zapis nie powiódł się', + truncation: 'Plik zbyt duży — pokazuję pierwsze 512 KB', + binary: 'Plik binarny, podgląd niedostępny', + loading: 'Ładowanie…', + error: 'Ładowanie nie powiodło się', + retry: 'Ponów', + splitLeft: 'Podziel w lewo', + splitRight: 'Podziel w prawo', + splitUp: 'Podziel w górę', + splitDown: 'Podziel w dół', + notRepo: 'Ten katalog nie jest repozytorium git', + noChanges: 'Brak zmian', + stage: 'Dodaj do indeksu', + unstage: 'Usuń z indeksu', + stageAll: 'Dodaj wszystko do indeksu', + unstageAll: 'Usuń wszystko z indeksu', + commitPlaceholder: 'Komunikat commitu (Ctrl+Enter)', + commit: 'Commit', + commitError: 'Commit nie powiódł się', + branch: 'Gałąź', + checkoutError: 'Przełączenie gałęzi nie powiodło się', + history: 'Historia', + changes: 'Zmiany', + staged: 'W indeksie', + unstaged: 'Poza indeksem', + cancel: 'Anuluj', + diffEmpty: 'Brak zmian tekstowych', + diffLoadError: 'Ładowanie diff nie powiodło się', + diffBinary: 'Binarny', + diffAdded: 'Dodany', + diffDeleted: 'Usunięty', + diffRenamed: 'Zmieniono nazwę', + diffExpand: 'Rozwiń jeszcze {count} wierszy', + diffCollapse: 'Zwiń', + discard: 'Odrzuć zmiany', + discardTitle: 'Odrzuć zmiany', + discardDesc: 'To odrzuci zmiany w drzewie roboczym dla „{path}” (nieodwracalne).', + viewCommitDiff: 'Pokaż diff commitu', + copyShortHash: 'Kopiuj krótki hash', + copyFullHash: 'Kopiuj pełny hash', + copySubject: 'Kopiuj temat commitu', + revertCommit: 'Cofnij commit', + revertTitle: 'Cofnij commit', + revertDesc: 'Utworzy nowy commit na bieżącej gałęzi, który cofa „{subject}”.', + cherryPickCommit: 'Cherry-pick commit', + cherryPickTitle: 'Cherry-pick commit', + cherryPickDesc: 'Zastosuje zmiany z „{subject}” na bieżącej gałęzi.', + timeJustNow: 'przed chwilą', + timeMinutesAgo: '{n} min temu', + timeHoursAgo: '{n} g temu', + timeYesterday: 'wczoraj', + loadMore: 'Wczytaj więcej', + historyLoadError: 'Ładowanie dalszej historii nie powiodło się', + produced: 'Wyprodukowane', + producedOpen: 'Otwórz w panelu bocznym', + disconnected: 'Terminal odłączony, ponowne łączenie…', + exited: 'Proces terminala zakończony', + noSession: 'Wybierz rozmowę, aby korzystać z panelu bocznego', + pluginNotLoaded: 'Wtyczka niezaładowana; karta chwilowo niedostępna:', + hiddenFiles: 'Ukryte pliki', + parent: 'Katalog nadrzędny', + copied: 'Skopiowano', + copy: 'Kopiuj', + newFile: 'Nowy plik', + openEditor: 'Otwórz edytor', + gitDetail: 'Zobacz szczegóły zmian', + referenceFile: '@plik', + addToConversation: 'Dodaj do rozmowy', + copyRelative: 'Kopiuj ścieżkę względną', + copyAbsolute: 'Kopiuj ścieżkę bezwzględną', + download: 'Pobierz', + uploadFiles: 'Wgraj pliki', + uploadFolder: 'Wgraj folder', + uploadHere: 'Wgraj tutaj', + uploadDropHint: 'Upuść pliki/foldery tutaj, aby wgrać', + uploadDropChat: 'Upuść na obszar czatu, aby dodać obrazy do rozmowy', + uploadTo: 'Wgraj do {dir}', + uploadingTo: 'Wgrywanie do {dir}…', + uploadProgress: 'Wgrywanie {done}/{total}: {name}', + uploadDone: 'Wgrano {count} plików', + uploadFailed: 'Wgrywanie nie powiodło się: {error}', + uploadFailedUnknown: 'Nieznany błąd', + uploadTooLarge: 'Plik zbyt duży (ponad limit wgrywania)', + uploadCancelled: 'Wgrywanie anulowane', + settingsNav: 'Karta boczna', + settingsIntro: 'Zarządzaj tym, co pokazuje karta boczna i jak się zachowuje', + settingsPopupDesc: 'Skonfiguruj opcje powiązane z: {feature}', + settingsDone: 'Gotowe', + settingsOpenTitle: 'Otwórz domyślnie dla nowych rozmów', + settingsOpenDesc: 'Rozwiń kartę boczną automatycznie dla zupełnie nowych rozmów; istniejące rozmowy zachowują własne układy', + settingsWidthTitle: 'Domyślny udział szerokości', + settingsWidthDesc: 'Domyślny udział szerokości okna dla karty bocznej w nowych rozmowach (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: 'Otwieraj pliki czatu w panelu bocznym', + settingsOpenPathDesc: 'Otwieraj linki plików na czacie (wiersze narzędzi, wyprodukowane pliki, wzmianki) w edytorze panelu bocznego zamiast w domyślnej aplikacji systemu', + settingsTitleBarTitle: 'Tryb zgodności pozycji', + settingsTitleBarDesc: 'Wybierz schemat zgodności paska tytułu: automatyczne wykrywanie (domyślne, konserwatywne) / oficjalny web DSH / znane powłoki pulpitu / niestandardowy (przesunięcie + własne CSS)', + settingsTitleBarStripTitle: 'Przesunięcie', + settingsTitleBarStripDesc: 'Wysokość paska tytułu: o ile pikseli przyciski i treść panelu bocznego są przesunięte w dół (0–120, domyślnie 40; obowiązuje w schemacie niestandardowym)', + settingsSchemeAutoTitle: 'Automatyczne wykrywanie', + settingsSchemeAutoDesc: 'Konserwatywne: tylko standardowe API Window Controls Overlay się wlicza (rzeczywista wysokość nakładki); zwykłe środowiska web nie są modyfikowane', + settingsSchemeWebTitle: 'Oficjalny web DSH', + settingsSchemeWebDesc: 'Jawnie zadeklaruj oficjalny interfejs web: brak adaptacji (nawet standardowa geometria WCO nie ma zastosowania)', + settingsSchemeCustomTitle: 'Niestandardowy', + settingsSchemeCustomDesc: 'Pełna kontrola: wstrzykuj własne CSS (może nadpisać style wbudowane) i ustawiasz przesunięcie paska tytułu', + settingsSchemeDetectedSuffix: 'wykryto', + settingsCustomCssTitle: 'Niestandardowe CSS', + settingsCustomCssDesc: 'Style dodawane na końcu strony (późniejsze w kaskadzie wygrywa remisy; użyj !important, aby nadpisać zmienne inline zapisane przez JS)', + settingsCustomCssPlaceholder: '/* np. zarezerwuj 36px dla powłoki z własnym paskiem tytułu */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: 'Zapis nie powiódł się', + settingsConflict: 'Ustawienie zmienione w innym oknie — spróbuj ponownie', + binaryNoPreview: 'Tego typu pliku nie można wyświetlić w podglądzie', + downloadToView: 'Pobierz, aby zobaczyć', + settingsSubagentTitle: 'Automatycznie otwieraj stronę Zadań przy pojawieniu się podagenta', + settingsSubagentDesc: 'Gdy bieżąca rozmowa powoła nowego podagenta, rozwiń panel boczny i otwórz stronę Zadań; wyłącz, aby otwierać ręcznie', + settingsJobsTitle: 'Automatycznie otwieraj stronę zadań w tle przy nowym zadaniu', + settingsJobsDesc: 'Gdy w bieżącej rozmowie pojawi się nowe zadanie w tle, rozwiń panel boczny i otwórz stronę zadań w tle (każde nowe zadanie wyzwala); wyłącz, aby otwierać ręcznie', + settingsToolsTitle: 'Wstrzyknij narzędzia terminala dla modelu', + settingsToolsDesc: 'Po włączeniu model może tworzyć i sterować terminalami panelu bocznego przez 8 narzędzi terminal_* (domyślnie wyłączone)', + settingsBottomTerminalTitle: 'Automatycznie otwieraj terminal przy pierwszym rozwinięciu panelu dolnego', + settingsBottomTerminalDesc: 'Gdy panel dolny jest rozwijany po raz pierwszy w sesji, spróbuj otworzyć nową kartę terminala tam (limit terminali nadal obowiązuje; domyślnie włączone)', + settingsFontFamilyTitle: 'Krój czcionki terminala', + settingsFontFamilyDesc: 'Niestandardowy krój czcionki terminala (stos font-family CSS, np. "JetBrains Mono", monospace; puste = krój monospace z motywu)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: 'Rozmiar czcionki terminala', + settingsFontSizeDesc: 'Rozmiar czcionki terminala w px (9–32, domyślnie 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'Ścieżka powłoki', + settingsShellDesc: 'Powłoka uruchamiana dla terminali UI i modelu (ścieżka bezwzględna lub nazwa pliku). Puste zachowuje dawną kolejność: yaml config.shell → $SHELL / powłoka logowania / Windows powershell.exe. Dotyczy terminali otwieranych potem', + settingsShellPlaceholder: 'np. /bin/zsh (puste = auto)', + settingsShellArgsTitle: 'Argumenty powłoki', + settingsShellArgsDesc: 'Jawne argumenty powłoki, oddzielone spacjami; niepuste w pełni zastępuje domyślne (zgodnie z kontraktem shellArgs w yaml)', + settingsShellArgsPlaceholder: 'np. -l (puste = domyślne)', + settingsTabsTitle: 'Treść panelu bocznego', + settingsViewersTitle: 'Podglądy plików', + settingsGeneralTitle: 'Ogólne', + settingsPopup: 'Ustawienia funkcji', + settingsViewerCatchAll: 'Zapasowy: dowolny plik', + viewerImage: 'Obraz', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: 'Kod', + viewerBinary: 'Pobieranie binarne', + viewerHtml: 'HTML', + browser: 'Przeglądarka', + browserPlaceholder: 'Wpisz adres URL, np. example.com', + browserGo: 'Przejdź', + browserBack: 'Wstecz', + browserForward: 'Naprzód', + browserStart: 'Wpisz adres URL, aby rozpocząć przeglądanie (tryb piaskownicy)', + browserBlockedScheme: 'Zablokowano: dozwolone są tylko adresy URL http/https', + browserBlockedLoopback: 'Zablokowano: nie można tu przeglądać adresów lokalnych i wewnętrznych', + browserInvalid: 'Nieprawidłowy adres URL', + browserNoSandboxWarning: 'Piaskownica wyłączona: bieżąca strona działa z pełnymi uprawnieniami interfejsu (można przywrócić w ustawieniach)', + htmlNoSandboxWarning: 'Piaskownica wyłączona: ten HTML działa z pełnymi uprawnieniami interfejsu (można przywrócić w ustawieniach)', + sandboxStatusOn: 'Tryb piaskownicy: włączony · strony nie mogą dostępować danych interfejsu ani plików lokalnych; logowania i ciasteczka firm trzecich mogą nie działać', + sandboxUnlock: 'Wyłącz tymczasowo (niebezpieczne)', + sandboxRestore: 'Przywróć piaskownicę', + settingsHtmlDefaultUnsafeTitle: 'Otwieraj podgląd HTML bez piaskownicy domyślnie (niebezpieczne)', + settingsHtmlDefaultUnsafeDesc: 'Po włączeniu każdy nowo otwarty podgląd HTML zaczyna się bez piaskownicy (ten sam origin co interfejs — może czytać pliki sesji i wewnętrzne API); pasek stanu nadal pozwala przywrócić piaskownicę', + settingsHtmlSandboxTitle: 'Wyłącz piaskownicę podglądu HTML (niebezpieczne)', + settingsHtmlSandboxDesc: 'Po wyłączeniu podglądany HTML działa w tym samym originie co interfejs: może czytać pliki sesji, localStorage i wywoływać wewnętrzne API. Włączaj tylko dla w pełni zaufanych plików', + settingsBrowserSandboxTitle: 'Wyłącz piaskownicę przeglądarki (niebezpieczne)', + settingsBrowserSandboxDesc: 'Po wyłączeniu każda odwiedzana strona działa w tym samym originie co interfejs: może czytać dane sesji i podszywać się pod Twoją sesję logowania. Włączaj tylko dla w pełni zaufanych witryn', + settingsBrowserLinksTitle: 'Otwieraj linki zewnętrzne z czatu w panelu bocznym', + settingsBrowserLinksDesc: 'Po włączeniu kliknięcie linku zewnętrznego na czacie lub w interfejsie otwiera panel boczny zamiast nowego okna; HTTP i HTTPS sterowane są osobnymi przełącznikami poniżej; Ctrl/Cmd+klik zawsze pomija', + settingsBrowserHttpTitle: 'Otwieraj strony HTTP w panelu bocznym', + settingsBrowserHttpDesc: 'Po włączeniu kliknięcie zewnętrznego linku HTTP na czacie lub w interfejsie otwiera panel boczny (strony wtyczek deklarujące urlTarget mają pierwszeństwo); Ctrl/Cmd+klik zawsze pomija', + settingsBrowserHttpsTitle: 'Otwieraj strony HTTPS w panelu bocznym', + settingsBrowserHttpsDesc: 'Po włączeniu kliknięcie zewnętrznego linku HTTPS na czacie lub w interfejsie otwiera panel boczny. Domyślnie wyłączone: większość stron HTTPS odmawia osadzania, więc przeglądarka systemowa jest płynniejszym domyślnym wyborem', + browserOpenExternal: 'Otwórz w przeglądarce', + browserEmbedBlocked: '{host} odmówił osadzenia', + browserEmbedBlockedDesc: 'Witryna zabrania wyświetlania w innych stronach (X-Frame-Options / frame-ancestors), więc nie może się załadować w panelu bocznym. Otwórz ją bezpośrednio w przeglądarce.', + browserEmbedAnyway: 'Załaduj mimo to', + subagent: 'Zadania', + openSubagent: 'Zadania', + subagentMainAgent: 'Agent główny', + subagentEmpty: 'Brak podagentów', + subagentEmptyDesc: 'Podagenci powołani przez agenta głównego pojawią się tutaj', + subagentRunning: 'Działa', + subagentInactive: 'Bezczynny', + subagentModeOneShot: 'Jednorazowy', + subagentModeContinuable: 'Kontynuowalny', + subagentCount: '{count} podagentów', + subagentCountRunning: '{count} podagentów · {running} działa', + subagentDiagCorrupt: 'Uszkodzony', + subagentDiagUnsupported: 'Nieobsługiwany', + subagentDiagUnavailable: 'Niedostępny', + subagentThinking: 'Myśli…', + sideChat: 'Czat boczny (beta)', + sideChatNew: 'Nowy wątek', + sideChatUntitled: 'Nowy wątek', + sideChatEmpty: 'Brak rozmów bocznych', + sideChatEmptyDesc: 'Każda rozmowa boczna to własna karta w pasku kart — dziedziczy kontekst bieżącej sesji i nigdy nie trafia do rozmowy głównej', + sideChatCreating: 'Tworzenie rozmowy bocznej…', + sideChatRetry: 'Ponów', + sideChatThreads: 'Przełącz wątek / nowy', + sideChatSave: 'Zapisz jako nową sesję', + sideChatSaveTitle: 'Promuj ten wątek do sesji najwyższego poziomu na głównej liście sesji', + sideChatSaved: 'Zapisano jako nową sesję', + sideChatNoTurn: 'Zapis jest dostępny po pierwszej ukończonej turze', + sideChatPendingDrop: 'Ostatnie niezakończone pytanie następcze nie zostanie uwzględnione w zapisanej sesji', + sideChatFirstPlaceholder: 'Zadaj pierwsze pytanie — kontekst odziedziczony…', + sideChatComposerPlaceholder: 'Pytaj dalej…', + sideChatThinking: 'Drążenie…', + sideChatThink: 'Myślenie', + sideChatInjection: 'Kontekst wstrzyknięty', + sideChatSend: 'Wyślij', + sideChatCancel: 'Zatrzymaj', + sideChatCancelTitle: 'Przerwij bieżącą turę (kolejka jest zachowana)', + sideChatClose: 'Zamknij wątek', + sideChatCloseTitle: 'Zwolnij agenta wątku (historia jest zachowana)', + sideChatError: 'Błąd czatu bocznego: {message}', + jobs: 'Zadania w tle', + jobsCount: '{count} zadań w tle', + jobsCountRunning: '{count} zadań w tle · {running} działa', + jobStatusRunning: 'Działa', + jobStatusStopping: 'Zatrzymywanie', + jobStatusCompleted: 'Ukończono', + jobStatusKilled: 'Zabito', + jobStatusFailed: 'Nie powiodło się', + jobDurationSeconds: '{seconds}s', + jobDurationMinutes: '{minutes}m {seconds}s', + jobDurationHours: '{hours}g {minutes}m', + jobViewOutput: 'Pokaż wyjście', + jobHideOutput: 'Ukryj wyjście', + jobNoOutput: 'Brak wyjścia', + jobNotReadYet: 'Oczekiwanie, aż model odczyta to zadanie; wyjście pojawi się tutaj, gdy model uruchomi job_output', + jobOutputTruncated: 'Wyjście skrócone', + jobOutputError: 'Ładowanie wyjścia nie powiodło się', + jobKill: 'Zabij', + jobKillConfirm: 'Kliknij ponownie, aby potwierdzić zabicie', + jobKillError: 'Zabicie nie powiodło się', + addPluginsTabCard: 'Dodaj wtyczki kart', + addPluginsTabCardDesc: 'Zarejestruj nową stronę panelu bocznego', + addPluginsViewerCard: 'Dodaj wtyczki podglądu', + addPluginsViewerCardDesc: 'Zarejestruj podgląd typu pliku', + addPluginsTabDesc: 'Strony panelu bocznego (karty) mogą być rozszerzane przez wtyczki. Wtyczki rejestrują się przez usługę ctx.betterSidebar; kliknięcie „Zainstaluj” kopiuje polecenie instalacji — wklej je do terminala tam, gdzie żyje Twój profil DSH, i uruchom.', + addPluginsViewerDesc: 'Podglądy plików mogą być rozszerzane przez wtyczki. Wtyczki rejestrują się przez usługę ctx.betterSidebar; kliknięcie „Zainstaluj” kopiuje polecenie instalacji — wklej je do terminala tam, gdzie żyje Twój profil DSH, i uruchom.', + addPluginsBrowseMore: 'Przeglądaj więcej wtyczek na GitHub (topic: dsh-better-sidebar)', + addPluginsSearch: 'Szukaj po nazwie lub opisie wtyczki…', + addPluginsNoMatch: 'Brak pasujących wtyczek', + addPluginsRecommended: 'Zalecane wtyczki', + addPluginsEmpty: 'Brak wyselekcjonowanych wtyczek — opublikuj swoją pod tematem na GitHub', + openPlugin: 'Otwórz', + copyInstall: 'Kopiuj polecenie instalacji', + pluginOfficeDesc: 'Podgląd pakietu Office (.docx / .xlsx / .pptx) dla edytora better-sidebar, utrzymujący ciężkie biblioteki renderujące Office poza rdzeniem głównego pakietu', + pluginFlowglassDesc: 'Wykres przepływu sesji na żywo: trzy tory dla użytkownika, asystenta i wywołań narzędzi, z grupami równoległymi, gałęziami podagentów, drążeniem i statusem na żywo; rejestruje natywną kartę Flowglass po zainstalowaniu better-sidebar, z fallbackiem do samodzielnej szuflady', + pluginGitForgeDesc: 'Karta Git Forge: biblioteka kont GitHub/Gitea (i innych forges) + autoryzacja per projekt + twarda polityka push; tokeny zostają w lokalnych sekretach (nigdy w kontekście modelu); narzędzie GitForge tylko do odczytu i agentowy helper poświadczeń HTTPS', + pluginGitRemotesDesc: 'Karta Git Remotes: gałąź/nadrzędne/ahead-behind, fetch (z opcjonalnym prune), ff-only pull i push dopiero po potwierdzeniu w karcie. Nie zastępuje wbudowanej karty Git stage/commit i nie oferuje force-push ani narzędzia auto-push modelu', + pluginSentinelDesc: 'Budzenie agenta sterowane warunkami: czujniki plików/procesów/portów/HTTP/poleceń/webhooków wybudzają uśpione sesje, gdy warunek zajdzie; rejestruje kartę „Sentinel” z ogólnoserwerową tabelą obserwacji', + pluginSidebarQaDesc: 'Wybierz-i-zapytaj: Zaznacz tekst rozmowy → zapytaj w prawym panelu → niezależna sesja pytań następczych (❓) w tym samym obszarze roboczym; szybki model bez myślenia kompresuje główny kontekst i wstrzykuje go z cytatem, nie przerywając głównej rozmowy; pytania następcze mogą zagnieżdżać się, kontynuować i być archiwizowane', + pluginSshTunnelDesc: 'Karta SSH Tunnel: spis wielu hostów + autoryzacja per projekt + klucze trzymane lokalnie; narzędzie modelu SSHManager (exec/SFTP/strategie sesji); centralny interaktywny terminal i dwupanelowy SFTP', + pluginTurnReviewDesc: 'Ludzka bramka na diffie „tej właśnie tury”: Approve / Request changes per ścieżka z opcjonalnym komentarzem; ścieżki pogrupowane wg sesji głównej / podagenta / nieprzypisane; wbudowany diff migawka-początku-tury vs teraz, zanim zdecydujesz. Bez forka, bez /rewind', + pluginVideoPreviewDesc: 'Wbudowany podgląd plików wideo (.mp4/.webm/.mov/.mkv/.avi itp.) w edytorze better-sidebar, wspierany przez dedykowaną trasę hosta /video z obsługą HTTP Range (206) — przewijanie działa, a pliki nie są ograniczane przez mediaLimit 20 MB', + pluginDocsPanelDesc: 'Globalne dokumenty w panelu bocznym DSH: globalne notatki Markdown, czytelne z dowolnego obszaru roboczego — lista z kliknięciem, kontur z przejściami, otwieranie w Chrome / VS Code i przyciski kopiowania kodu; katalog konfigurowalny (domyślnie ~/.dsh/docs)', +} diff --git a/src/client/locales-pt.ts b/src/client/locales-pt.ts new file mode 100644 index 0000000..9c3b209 --- /dev/null +++ b/src/client/locales-pt.ts @@ -0,0 +1,328 @@ +export const pt: Record = { + files: 'Arquivos', + explorer: 'Explorador', + git: 'Controle de código-fonte', + terminal: 'Terminal', + editor: 'Editor', + editorExplorer: 'Comportamento de abertura de arquivos', + editorExplorerDesc: 'Controla como os arquivos são abertos', + editorExplorerMerged: 'Mesclado', + editorExplorerMergedDesc: 'Arquivos alternam no mesmo lugar na mesma janela; novas janelas começam com a árvore de arquivos aberta', + editorExplorerSplit: 'Separado', + editorExplorerSplitDesc: 'Janelas sem caminho são o explorador independente (somente árvore de arquivos); cada arquivo abre sua própria janela (com árvore encaixada, fechada por padrão)', + editorTreeToggle: 'Painel da árvore de arquivos', + editorPathPlaceholder: 'Caminho do arquivo (relativo ao diretório da sessão ou absoluto), Enter para abrir', + editorSearchPlaceholder: 'Pesquisar arquivos por nome…', + editorSearchNoResults: 'Nenhum arquivo correspondente', + editorSearchTruncated: 'Resultados demais — exibindo lista parcial', + editorEmptyHint: 'Escolha um arquivo na árvore do painel ou no campo de caminho acima para começar a pré-visualizar', + openFileNewTab: 'Abrir em nova aba', + openFileSide: 'Abrir ao lado', + openWithMenu: 'Abrir com', + openWithSshSuffix: ' (SSH)', + pinOpenWith: 'Fixar no menu', + unpinOpenWith: 'Desafixar', + openWithExplorer: 'Gerenciador de arquivos', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'Host remoto SSH', + openWithSettingsSshDesc: 'Vazio = workspace local; com user@host ou um alias SSH, os abridores da família VSCode passam a usar o protocolo vscode-remote/ssh-remote e o Gerenciador de arquivos / Zed / editores personalizados fora da família VSCode ficam ocultos do menu', + openWithSettingsSshPlaceholder: 'user@host ou alias SSH', + openWithSettingsCustomTitle: 'Editores personalizados', + openWithSettingsCustomDesc: 'Nome + modelo de URL (espaço reservado {path}) + sinalizador de família VSCode; no modo remoto, apenas editores da família VSCode podem abrir um caminho remoto', + openWithSettingsAdd: 'Adicionar', + openWithSettingsName: 'Nome', + openWithSettingsTemplate: 'ex.: cursor://file/{path}', + openWithSettingsFamily: 'Família VSCode', + openWithSettingsFamilyDesc: 'Este editor fala o dialeto de URL do VSCode (suporta aberturas SSH remotas)', + openWithSettingsRemove: 'Remover', + openWithSettingsInvalidHint: 'Editores com nome ausente ou modelo sem {path} / scheme:// não aparecem no menu', + newTab: 'Nova aba', + openExplorer: 'Explorador', + brokenSymlink: 'Symlink quebrado', + openGit: 'Painel Git', + newTerminal: 'Novo terminal', + terminalLimit: 'Limite de terminais atingido (3)', + close: 'Fechar', + closeOtherTabs: 'Fechar outras abas', + closeLeftTabs: 'Fechar abas à esquerda', + closeRightTabs: 'Fechar abas à direita', + collapse: 'Recolher barra lateral', + expand: 'Expandir barra lateral', + collapseBottomPanel: 'Recolher painel inferior', + expandBottomPanel: 'Expandir painel inferior', + terminalError: 'Falha na conexão do terminal', + terminalConnectFailed: 'O terminal falhou ao conectar repetidamente', + terminalRetry: 'Tentar novamente', + terminalDepsFailed: 'A dependência do terminal node-pty falhou ao carregar', + terminalDepsHint: 'Execute o comando abaixo em um terminal ou cmd na máquina do DSH para reparar e tente novamente (node-pty permanece em sincronia com a versão do núcleo do DSH):', + terminalDepsProfile: ' (perfil detectado: {profile})', + preview: 'Pré-visualizar', + edit: 'Editar', + mermaidError: 'Falha ao renderizar o Mermaid', + mermaidZoomIn: 'Ampliar', + mermaidZoomOut: 'Reduzir', + mermaidZoomReset: 'Redefinir', + mermaidZoomHint: 'Rolar para ampliar · arrastar para mover · Esc para fechar', + refresh: 'Atualizar', + save: 'Salvar', + saved: 'Salvo', + unsaved: 'Não salvo', + saveFailed: 'Falha ao salvar', + truncation: 'Arquivo grande demais — exibindo os primeiros 512KB', + binary: 'Arquivo binário, pré-visualização indisponível', + loading: 'Carregando…', + error: 'Falha ao carregar', + retry: 'Tentar novamente', + splitLeft: 'Dividir à esquerda', + splitRight: 'Dividir à direita', + splitUp: 'Dividir acima', + splitDown: 'Dividir abaixo', + notRepo: 'Este diretório não é um repositório git', + noChanges: 'Sem alterações', + stage: 'Preparar (stage)', + unstage: 'Desfazer stage', + stageAll: 'Preparar tudo', + unstageAll: 'Desfazer stage de tudo', + commitPlaceholder: 'Mensagem de commit (Ctrl+Enter)', + commit: 'Commit', + commitError: 'Falha no commit', + branch: 'Branch', + checkoutError: 'Falha ao alternar de branch', + history: 'Histórico', + changes: 'Alterações', + staged: 'Preparadas', + unstaged: 'Não preparadas', + cancel: 'Cancelar', + diffEmpty: 'Sem alterações de texto', + diffLoadError: 'Falha ao carregar o diff', + diffBinary: 'Binário', + diffAdded: 'Adicionado', + diffDeleted: 'Excluído', + diffRenamed: 'Renomeado', + diffExpand: 'Expandir mais {count} linhas', + diffCollapse: 'Recolher', + discard: 'Descartar alterações', + discardTitle: 'Descartar alterações', + discardDesc: 'Isso descarta as alterações do diretório de trabalho de "{path}" (não recuperável).', + viewCommitDiff: 'Ver diff do commit', + copyShortHash: 'Copiar hash curto', + copyFullHash: 'Copiar hash completo', + copySubject: 'Copiar assunto', + revertCommit: 'Reverter commit', + revertTitle: 'Reverter commit', + revertDesc: 'Crie um novo commit no branch atual que reverte "{subject}".', + cherryPickCommit: 'Cherry-pick deste commit', + cherryPickTitle: 'Cherry-pick deste commit', + cherryPickDesc: 'Aplicar as alterações de "{subject}" ao branch atual.', + timeJustNow: 'agora mesmo', + timeMinutesAgo: 'há {n} min', + timeHoursAgo: 'há {n} h', + timeYesterday: 'ontem', + loadMore: 'Carregar mais', + historyLoadError: 'Falha ao carregar mais histórico', + produced: 'Produzidos', + producedOpen: 'Abrir na barra lateral', + disconnected: 'Terminal desconectado, reconectando…', + exited: 'O processo do terminal saiu', + noSession: 'Selecione uma conversa para usar a barra lateral', + pluginNotLoaded: 'Plugin não carregado; aba indisponível:', + hiddenFiles: 'Arquivos ocultos', + parent: 'Diretório pai', + copied: 'Copiado', + copy: 'Copiar', + newFile: 'Novo arquivo', + openEditor: 'Abrir editor', + gitDetail: 'Ver detalhes das alterações', + referenceFile: '@arquivo', + addToConversation: 'Adicionar à conversa', + copyRelative: 'Copiar caminho relativo', + copyAbsolute: 'Copiar caminho absoluto', + download: 'Baixar', + uploadFiles: 'Enviar arquivos', + uploadFolder: 'Enviar pasta', + uploadHere: 'Enviar aqui', + uploadDropHint: 'Solte arquivos/pastas aqui para enviar', + uploadDropChat: 'Solte no chat para adicionar imagens', + uploadTo: 'Enviar para {dir}', + uploadingTo: 'Enviando para {dir}…', + uploadProgress: 'Enviando {done}/{total}: {name}', + uploadDone: '{count} arquivo(s) enviado(s)', + uploadFailed: 'Falha no envio: {error}', + uploadFailedUnknown: 'Erro desconhecido', + uploadTooLarge: 'Arquivo grande demais (acima do limite de envio)', + uploadCancelled: 'Envio cancelado', + settingsNav: 'Cartão lateral', + settingsIntro: 'Gerencie o que o cartão lateral mostra e como ele se comporta', + settingsPopupDesc: 'Configurar opções relacionadas para {feature}', + settingsDone: 'Concluído', + settingsOpenTitle: 'Abrir por padrão em novas conversas', + settingsOpenDesc: 'Expandir o cartão lateral automaticamente em conversas totalmente novas; conversas existentes mantêm seus próprios layouts', + settingsWidthTitle: 'Participação padrão na largura', + settingsWidthDesc: 'Participação padrão do cartão lateral na largura da janela em novas conversas (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: 'Abrir arquivos do chat na barra lateral', + settingsOpenPathDesc: 'Abrir links de arquivos no chat (linhas de ferramentas, arquivos produzidos, menções) no editor da barra lateral em vez do aplicativo padrão do sistema', + settingsTitleBarTitle: 'Modo de compatibilidade de posição', + settingsTitleBarDesc: 'Escolha o esquema de compatibilidade da barra de título: detecção automática (padrão, conservador) / web oficial do DSH / shells de desktop conhecidos / personalizado (distância de deslocamento + CSS personalizado)', + settingsTitleBarStripTitle: 'Distância de deslocamento', + settingsTitleBarStripDesc: 'Altura da faixa da barra de título: quantos pixels os botões e o conteúdo da barra lateral descem (0–120, padrão 40; aplica-se no esquema personalizado)', + settingsSchemeAutoTitle: 'Detecção automática', + settingsSchemeAutoDesc: 'Conservador: somente a API padrão Window Controls Overlay contribui (altura real da sobreposição de título); ambientes web comuns não recebem nenhuma modificação', + settingsSchemeWebTitle: 'Web oficial do DSH', + settingsSchemeWebDesc: 'Declare explicitamente a interface web oficial: nenhuma adaptação (nem mesmo a geometria padrão do WCO)', + settingsSchemeCustomTitle: 'Personalizado', + settingsSchemeCustomDesc: 'Controle total: injete CSS personalizado (pode sobrescrever estilos internos) e defina a distância de deslocamento da barra de título', + settingsSchemeDetectedSuffix: 'detectado', + settingsCustomCssTitle: 'CSS personalizado', + settingsCustomCssDesc: 'Estilos anexados ao final da página (quem vem depois vence em empate de cascata; use !important para sobrescrever variáveis inline escritas por JS)', + settingsCustomCssPlaceholder: '/* ex.: reserve 36px para um shell com barra de título desenhada por conta própria */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: 'Falha ao salvar', + settingsConflict: 'A configuração foi alterada em outra janela — tente novamente', + binaryNoPreview: 'Este tipo de arquivo não pode ser pré-visualizado', + downloadToView: 'Baixar para ver', + settingsSubagentTitle: 'Abrir automaticamente a página de Tarefas quando um subagente aparecer', + settingsSubagentDesc: 'Expandir o cartão lateral e abrir a página de Tarefas quando a conversa atual gerar um novo subagente; desative para abrir manualmente', + settingsJobsTitle: 'Abrir automaticamente a página de Tarefas em segundo plano quando houver uma nova tarefa', + settingsJobsDesc: 'Expandir o cartão lateral e abrir a página de Tarefas sempre que uma nova tarefa em segundo plano aparecer para a conversa atual (cada nova tarefa dispara); desative para abrir manualmente', + settingsToolsTitle: 'Injetar ferramentas de terminal para o modelo', + settingsToolsDesc: 'Quando ativado, o modelo pode criar e operar terminais da barra lateral por meio das 8 ferramentas terminal_* (desativado por padrão)', + settingsBottomTerminalTitle: 'Abrir um terminal automaticamente na primeira expansão do painel inferior', + settingsBottomTerminalDesc: 'Quando o painel inferior for expandido pela primeira vez em uma sessão, tente abrir uma nova aba de terminal lá (a cota de terminais ainda se aplica; ativado por padrão)', + settingsFontFamilyTitle: 'Família de fonte do terminal', + settingsFontFamilyDesc: 'Família de fonte personalizada do terminal (uma pilha CSS font-family como "JetBrains Mono", monospace; deixe vazio para seguir a fonte monoespaçada do tema)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: 'Tamanho da fonte do terminal', + settingsFontSizeDesc: 'Tamanho da fonte do terminal em px (9–32, padrão 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'Caminho do shell', + settingsShellDesc: 'Shell iniciado para terminais de UI e do modelo (caminho absoluto ou executável puro). Vazio mantém a ordem legada: config.shell do yaml → $SHELL / shell de login / powershell.exe no Windows. Aplica-se aos terminais abertos depois', + settingsShellPlaceholder: 'ex.: /bin/zsh (vazio = automático)', + settingsShellArgsTitle: 'Argumentos do shell', + settingsShellArgsDesc: 'Argumentos explícitos do shell, separados por espaço; quando não vazios, substituem totalmente os padrões (mesmo contrato do shellArgs do yaml)', + settingsShellArgsPlaceholder: 'ex.: -l (vazio = padrões)', + settingsTabsTitle: 'Conteúdo da barra lateral', + settingsViewersTitle: 'Visualizadores de arquivos', + settingsGeneralTitle: 'Geral', + settingsPopup: 'Configurações do recurso', + settingsViewerCatchAll: 'Curinga: qualquer arquivo', + viewerImage: 'Imagem', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: 'Código', + viewerBinary: 'Download binário', + viewerHtml: 'HTML', + browser: 'Navegador', + browserPlaceholder: 'Digite uma URL, ex.: example.com', + browserGo: 'Ir', + browserBack: 'Voltar', + browserForward: 'Avançar', + browserStart: 'Digite uma URL para começar a navegar (modo sandbox)', + browserBlockedScheme: 'Bloqueado: apenas URLs http/https são permitidas', + browserBlockedLoopback: 'Bloqueado: endereços locais e internos não podem ser navegados aqui', + browserInvalid: 'URL inválida', + browserNoSandboxWarning: 'Sandbox desativado: a página atual roda com privilégios completos da interface (reative nas configurações)', + htmlNoSandboxWarning: 'Sandbox desativado: este HTML roda com privilégios completos da interface (reative nas configurações)', + sandboxStatusOn: 'Modo sandbox: ativado · as páginas não podem acessar os dados da interface nem arquivos locais; logins e cookies de terceiros podem não funcionar', + sandboxUnlock: 'Desativar temporariamente (inseguro)', + sandboxRestore: 'Restaurar sandbox', + settingsHtmlDefaultUnsafeTitle: 'Abrir pré-visualizações de HTML sem sandbox por padrão (inseguro)', + settingsHtmlDefaultUnsafeDesc: 'Quando ativado, toda pré-visualização de HTML recém-aberta começa sem sandbox (mesma origem da interface — pode ler arquivos de sessão e APIs internas); a linha de status ainda oferece restauração em um toque', + settingsHtmlSandboxTitle: 'Desativar o sandbox da pré-visualização de HTML (inseguro)', + settingsHtmlSandboxDesc: 'Com o sandbox desativado, o HTML pré-visualizado roda com a mesma origem da interface: pode ler arquivos de sessão, armazenamento local e chamar APIs internas. Ative apenas para arquivos totalmente confiáveis', + settingsBrowserSandboxTitle: 'Desativar o sandbox do navegador (inseguro)', + settingsBrowserSandboxDesc: 'Com o sandbox desativado, qualquer site visitado roda com a mesma origem da interface: pode ler dados da sessão e agir como sua sessão conectada. Ative apenas para sites totalmente confiáveis', + settingsBrowserLinksTitle: 'Abrir links externos do chat na barra lateral', + settingsBrowserLinksDesc: 'Quando ativado, clicar em um link externo no chat ou na interface abre na barra lateral em vez de uma nova janela; HTTP e HTTPS são controlados separadamente pelos interruptores abaixo; Ctrl/Cmd+clique sempre ignora', + settingsBrowserHttpTitle: 'Abrir páginas HTTP na barra lateral', + settingsBrowserHttpDesc: 'Quando ativado, clicar em um link externo HTTP no chat ou na interface abre na barra lateral (páginas de plugins que declaram urlTarget vencem); Ctrl/Cmd+clique sempre ignora', + settingsBrowserHttpsTitle: 'Abrir páginas HTTPS na barra lateral', + settingsBrowserHttpsDesc: 'Quando ativado, clicar em um link externo HTTPS no chat ou na interface abre na barra lateral. Desativado por padrão: a maioria dos sites HTTPS se recusa a ser incorporada, então o navegador do sistema é o padrão mais suave', + browserOpenExternal: 'Abrir no navegador', + browserEmbedBlocked: '{host} se recusou a ser incorporado', + browserEmbedBlockedDesc: 'O site proíbe ser exibido dentro de outras páginas (X-Frame-Options / frame-ancestors), então não pode carregar na barra lateral. Abra-o diretamente no navegador.', + browserEmbedAnyway: 'Carregar mesmo assim', + subagent: 'Tarefas', + openSubagent: 'Tarefas', + subagentMainAgent: 'Agente principal', + subagentEmpty: 'Nenhum subagente', + subagentEmptyDesc: 'Subagentes gerados sob o agente principal aparecerão aqui', + subagentRunning: 'Executando', + subagentInactive: 'Inativo', + subagentModeOneShot: 'De uso único', + subagentModeContinuable: 'Continuável', + subagentCount: '{count} subagentes', + subagentCountRunning: '{count} subagentes · {running} executando', + subagentDiagCorrupt: 'Corrompido', + subagentDiagUnsupported: 'Não suportado', + subagentDiagUnavailable: 'Indisponível', + subagentThinking: 'Pensando…', + sideChat: 'Chat lateral (beta)', + sideChatNew: 'Novo tópico', + sideChatUntitled: 'Novo tópico', + sideChatEmpty: 'Nenhuma conversa lateral', + sideChatEmptyDesc: 'Cada conversa lateral é uma aba própria na faixa de abas — ela herda o contexto da sessão atual e nunca entra na conversa principal', + sideChatCreating: 'Criando conversa lateral…', + sideChatRetry: 'Tentar novamente', + sideChatThreads: 'Alternar tópico / novo', + sideChatSave: 'Salvar como nova sessão', + sideChatSaveTitle: 'Promover este tópico a uma sessão de nível superior na lista principal de sessões', + sideChatSaved: 'Salvo como nova sessão', + sideChatNoTurn: 'O salvamento está disponível após o primeiro turno concluído', + sideChatPendingDrop: 'A última pergunta não respondida não será incluída na sessão salva', + sideChatFirstPlaceholder: 'Faça a primeira pergunta — contexto herdado…', + sideChatComposerPlaceholder: 'Fazer uma pergunta de acompanhamento…', + sideChatThinking: 'Mergulhando fundo…', + sideChatThink: 'Pensamento', + sideChatInjection: 'Contexto injetado', + sideChatSend: 'Enviar', + sideChatCancel: 'Parar', + sideChatCancelTitle: 'Abortar o turno em execução (o trabalho na fila é mantido)', + sideChatClose: 'Fechar tópico', + sideChatCloseTitle: 'Liberar o agente do tópico (o histórico é mantido)', + sideChatError: 'Erro no chat lateral: {message}', + jobs: 'Tarefas em segundo plano', + jobsCount: '{count} tarefas em segundo plano', + jobsCountRunning: '{count} tarefas em segundo plano · {running} executando', + jobStatusRunning: 'Executando', + jobStatusStopping: 'Parando', + jobStatusCompleted: 'Concluída', + jobStatusKilled: 'Encerrada', + jobStatusFailed: 'Falhou', + jobDurationSeconds: '{seconds}s', + jobDurationMinutes: '{minutes}m {seconds}s', + jobDurationHours: '{hours}h {minutes}m', + jobViewOutput: 'Ver saída', + jobHideOutput: 'Ocultar saída', + jobNoOutput: 'Sem saída ainda', + jobNotReadYet: 'Aguardando o modelo ler esta tarefa; a saída aparece aqui quando o modelo executa job_output', + jobOutputTruncated: 'Saída truncada', + jobOutputError: 'Falha ao ler a saída', + jobKill: 'Encerrar', + jobKillConfirm: 'Clique novamente para confirmar o encerramento', + jobKillError: 'Falha ao encerrar', + addPluginsTabCard: 'Adicionar plugins de aba', + addPluginsTabCardDesc: 'Registrar uma nova página da barra lateral', + addPluginsViewerCard: 'Adicionar plugins de pré-visualização', + addPluginsViewerCardDesc: 'Registrar uma pré-visualização de tipo de arquivo', + addPluginsTabDesc: 'As páginas da barra lateral (abas) podem ser estendidas por plugins. Os plugins registram pelo serviço ctx.betterSidebar; clicar em Instalar copia o comando de instalação — cole-o em um terminal onde seu perfil do DSH vive e execute.', + addPluginsViewerDesc: 'Os visualizadores de arquivos podem ser estendidos por plugins. Os plugins registram pelo serviço ctx.betterSidebar; clicar em Instalar copia o comando de instalação — cole-o em um terminal onde seu perfil do DSH vive e execute.', + addPluginsBrowseMore: 'Navegue por mais plugins no GitHub (topic: dsh-better-sidebar)', + addPluginsSearch: 'Pesquisar por nome ou descrição do plugin…', + addPluginsNoMatch: 'Nenhum plugin corresponde', + addPluginsRecommended: 'Plugins recomendados', + addPluginsEmpty: 'Nenhum plugin selecionado ainda — publique o seu sob o topic do GitHub', + openPlugin: 'Abrir', + copyInstall: 'Copiar comando de instalação', + pluginOfficeDesc: 'Pré-visualização do pacote Office (.docx / .xlsx / .pptx) para o editor do better-sidebar, mantendo as bibliotecas pesadas de renderização do Office fora do bundle principal', + pluginFlowglassDesc: 'Fluxograma de sessão ao vivo com três faixas para usuário, assistente e chamadas de ferramenta, além de grupos paralelos, ramos de subagentes, drill-down e status ao vivo; registra uma aba nativa "Fluxograma" quando o better-sidebar está instalado e mantém a gaveta independente como fallback', + pluginGitForgeDesc: 'Aba Git Forge: biblioteca de contas GitHub/Gitea (e outras forges) + concessões por projeto + política rígida de push; os tokens ficam em secrets locais (nunca no contexto do modelo); ferramenta GitForge somente leitura e helper de credenciais HTTPS do agente', + pluginGitRemotesDesc: 'Aba de remotos Git: branch/upstream/ahead-behind, fetch (prune opcional), pull ff-only e push apenas após confirmar na aba. Não substitui a aba interna de stage/commit do Git e não oferece force-push nem push automático pelo modelo', + pluginSentinelDesc: 'Despertar de agentes dirigido por condições: sensores de arquivo/processo/porta/HTTP/comando/webhook acordam sessões adormecidas quando as condições disparam; registra uma aba "Sentinelas" com a tabela de monitoramento global do servidor', + pluginSidebarQaDesc: 'Selecionar e perguntar: selecione o texto da conversa → pergunte no painel à direita → uma sessão de acompanhamento dedicada (❓acompanhamento) no mesmo workspace; um modelo rápido sem pensamento comprime o contexto principal e o injeta com a citação, sem interromper a conversa principal. Acompanhamentos aninham, continuam e arquivam', + pluginSshTunnelDesc: 'Aba de túnel SSH: inventário de múltiplos hosts + concessões por projeto + chaves locais; ferramenta SSHManager (exec/SFTP/estratégias de sessão); terminal interativo central e SFTP de dois painéis', + pluginTurnReviewDesc: 'Um portão humano no diff do turno recém-terminado: Approve / Request changes por caminho com comentário opcional; caminhos agrupados por sessão principal / subagente / não atribuído; diff inline de snapshot-vs-atual antes de decidir. Sem fork, sem /rewind', + pluginVideoPreviewDesc: 'Pré-visualização inline de vídeo (.mp4/.webm/.mov/.mkv/.avi etc.) para o editor do better-sidebar, respaldada por uma rota de host /video dedicada com suporte a HTTP Range (206) — a barra de progresso funciona e os arquivos não são limitados pelo mediaLimit de 20MB', + pluginDocsPanelDesc: 'Documentos globais na barra lateral do DSH: leia suas próprias notas Markdown de qualquer workspace — uma lista de arquivos, um sumário, abrir no Chrome / VS Code e botões de copiar; o diretório de documentos é configurável (padrão ~/.dsh/docs)', +} diff --git a/src/client/locales-ru.ts b/src/client/locales-ru.ts new file mode 100644 index 0000000..f7fa9f1 --- /dev/null +++ b/src/client/locales-ru.ts @@ -0,0 +1,343 @@ +/** + * Russian (ru) dictionary for the better-sidebar plugin. + * + * Translated from the Simplified-Chinese (zh) source-of-truth dictionary in + * `./locales.ts`. Placeholders like `{name}` / `{path}` / `{dir}` are + * preserved verbatim; technical terms (Git, SSH, HTTP, URL, Markdown, PDF, + * VS Code, Tab, cherry-pick, etc.) are kept in English where idiomatic in + * Russian product UI. + * + * Tone: formal «Вы». Key set is type-checked against `zh` via the import in + * `locales.ts` (`Record`). + */ + +export const ru: Record = { + files: 'Файлы', + explorer: 'Проводник', + git: 'Контроль версий', + terminal: 'Терминал', + editor: 'Редактор', + editorExplorer: 'Способ открытия файлов', + editorExplorerDesc: 'Управление способом открытия файлов', + editorExplorerMerged: 'Объединённый', + editorExplorerMergedDesc: 'Файлы переключаются в том же окне; новые окна открываются с развёрнутым деревом', + editorExplorerSplit: 'Раздельный', + editorExplorerSplitDesc: 'Окно без пути — отдельный проводник (только дерево); каждый файл открывается в новом окне (с деревом, по умолчанию свёрнутым)', + editorTreeToggle: 'Панель дерева файлов', + editorPathPlaceholder: 'Введите путь к файлу (относительно каталога сессии или абсолютный), Enter, чтобы открыть', + editorSearchPlaceholder: 'Поиск по имени файла…', + editorSearchNoResults: 'Нет совпадающих файлов', + editorSearchTruncated: 'Слишком много результатов — показана часть совпадений', + editorEmptyHint: 'Выберите файл из дерева справа или введите путь выше, чтобы начать предпросмотр', + openFileNewTab: 'Открыть в новой вкладке', + openFileSide: 'Открыть сбоку', + openWithMenu: 'Открыть в приложении', + openWithSshSuffix: ' (SSH)', + pinOpenWith: 'Закрепить в меню', + unpinOpenWith: 'Открепить', + openWithExplorer: 'Проводник', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'Удалённый хост SSH', + openWithSettingsSshDesc: 'Пусто = локальная рабочая область; при указании user@host или псевдонима SSH способы открытия семейства VSCode переключаются на протокол vscode-remote/ssh-remote, а проводник / Zed / сторонние редакторы вне семейства VSCode скрываются из меню', + openWithSettingsSshPlaceholder: 'user@host или псевдоним SSH', + openWithSettingsCustomTitle: 'Собственные редакторы', + openWithSettingsCustomDesc: 'Имя + шаблон URL (плейсхолдер {path}) + признак семейства VSCode; в режиме SSH только редакторы семейства VSCode могут открывать удалённые пути', + openWithSettingsAdd: 'Добавить', + openWithSettingsName: 'Имя', + openWithSettingsTemplate: 'напр. cursor://file/{path}', + openWithSettingsFamily: 'Семейство VSCode', + openWithSettingsFamilyDesc: 'Этот редактор использует URL-протокол VSCode (поддерживает удалённое открытие по SSH)', + openWithSettingsRemove: 'Удалить', + openWithSettingsInvalidHint: 'Редакторы без имени или с шаблоном без {path} / scheme:// не появятся в меню', + newTab: 'Новая вкладка', + openExplorer: 'Проводник', + brokenSymlink: 'Сломанная символическая ссылка', + openGit: 'Панель Git', + newTerminal: 'Новый терминал', + terminalLimit: 'Достигнут лимит терминалов (3)', + close: 'Закрыть', + closeOtherTabs: 'Закрыть остальные вкладки', + closeLeftTabs: 'Закрыть вкладки слева', + closeRightTabs: 'Закрыть вкладки справа', + collapse: 'Свернуть боковую панель', + expand: 'Развернуть боковую панель', + collapseBottomPanel: 'Свернуть нижнюю панель', + expandBottomPanel: 'Развернуть нижнюю панель', + terminalError: 'Сбой подключения терминала', + terminalConnectFailed: 'Терминал не смог подключиться после нескольких попыток', + terminalRetry: 'Повторить', + terminalDepsFailed: 'Не удалось загрузить зависимость терминала node-pty', + terminalDepsHint: 'Выполните приведённую ниже команду в терминале или cmd на машине DSH, затем нажмите «Повторить» (node-pty остаётся синхронизированным с версией ядра DSH):', + terminalDepsProfile: ' (обнаружен profile: {profile})', + preview: 'Предпросмотр', + edit: 'Изменить', + mermaidError: 'Сбой рендеринга Mermaid', + mermaidZoomIn: 'Приблизить', + mermaidZoomOut: 'Отдалить', + mermaidZoomReset: 'Сбросить', + mermaidZoomHint: 'Колесо — масштаб · перетаскивание — панорама · Esc — закрыть', + refresh: 'Обновить', + save: 'Сохранить', + saved: 'Сохранено', + unsaved: 'Не сохранено', + saveFailed: 'Не удалось сохранить', + truncation: 'Файл слишком велик — показаны первые 512 КБ', + binary: 'Бинарный файл — предпросмотр недоступен', + loading: 'Загрузка…', + error: 'Ошибка загрузки', + retry: 'Повторить', + splitLeft: 'Разделить влево', + splitRight: 'Разделить вправо', + splitUp: 'Разделить вверх', + splitDown: 'Разделить вниз', + notRepo: 'Этот каталог не является git-репозиторием', + noChanges: 'Нет изменений', + stage: 'Индексировать', + unstage: 'Убрать из индекса', + stageAll: 'Индексировать всё', + unstageAll: 'Убрать всё из индекса', + commitPlaceholder: 'Сообщение коммита (Ctrl+Enter)', + commit: 'Закоммитить', + commitError: 'Сбой коммита', + branch: 'Ветка', + checkoutError: 'Сбой переключения ветки', + history: 'История', + changes: 'Изменения', + staged: 'В индексе', + unstaged: 'Не в индексе', + cancel: 'Отмена', + diffEmpty: 'Нет текстовых отличий', + diffLoadError: 'Не удалось загрузить diff', + diffBinary: 'Бинарный', + diffAdded: 'Добавлен', + diffDeleted: 'Удалён', + diffRenamed: 'Переименован', + diffExpand: 'Показать оставшиеся {count} строк', + diffCollapse: 'Свернуть', + discard: 'Отменить изменения', + discardTitle: 'Отменить изменения', + discardDesc: 'Изменения «{path}» в рабочем дереве будут отброшены (восстановить нельзя).', + viewCommitDiff: 'Просмотреть diff коммита', + copyShortHash: 'Копировать короткий хеш', + copyFullHash: 'Копировать полный хеш', + copySubject: 'Копировать сообщение', + revertCommit: 'Отменить коммит', + revertTitle: 'Отменить коммит', + revertDesc: 'В текущей ветке будет создан новый коммит, отменяющий «{subject}».', + cherryPickCommit: 'Cherry-pick коммита', + cherryPickTitle: 'Cherry-pick коммита', + cherryPickDesc: 'Изменения «{subject}» будут применены к текущей ветке.', + timeJustNow: 'только что', + timeMinutesAgo: '{n} мин назад', + timeHoursAgo: '{n} ч назад', + timeYesterday: 'вчера', + loadMore: 'Загрузить ещё', + historyLoadError: 'Не удалось загрузить ещё историю', + produced: 'Результаты', + producedOpen: 'Открыть в боковой панели', + disconnected: 'Терминал отключён, переподключение…', + exited: 'Процесс терминала завершился', + noSession: 'Выберите сессию, чтобы использовать боковую панель', + pluginNotLoaded: 'Плагин не загружен — вкладка недоступна:', + hiddenFiles: 'Скрытые файлы', + parent: 'Родительский каталог', + copied: 'Скопировано', + copy: 'Копировать', + newFile: 'Новый файл', + openEditor: 'Открыть редактор', + gitDetail: 'Просмотр изменений', + referenceFile: '@файл', + addToConversation: 'Добавить в диалог', + copyRelative: 'Копировать относительный путь', + copyAbsolute: 'Копировать абсолютный путь', + download: 'Скачать', + uploadFiles: 'Загрузить файлы', + uploadFolder: 'Загрузить папку', + uploadHere: 'Загрузить сюда', + uploadDropHint: 'Перетащите файлы/папки сюда, чтобы загрузить', + uploadDropChat: 'Перетащите в чат, чтобы добавить изображения в диалог', + uploadTo: 'Загрузить в {dir}', + uploadingTo: 'Загрузка в {dir}…', + uploadProgress: 'Загрузка {done}/{total}: {name}', + uploadDone: 'Загружено файлов: {count}', + uploadFailed: 'Сбой загрузки: {error}', + uploadFailedUnknown: 'Неизвестная ошибка', + uploadTooLarge: 'Файл слишком велик — превышен лимит загрузки', + uploadCancelled: 'Загрузка отменена', + + settingsNav: 'Боковая карточка', + settingsIntro: 'Управление содержимым и поведением боковой карточки по умолчанию', + settingsPopupDesc: 'Настройка параметров «{feature}»', + settingsDone: 'Готово', + settingsOpenTitle: 'Открывать по умолчанию для новых сессий', + settingsOpenDesc: 'Автоматически разворачивать боковую карточку для новых сессий; у существующих сессий сохраняется их собственная раскладка', + settingsWidthTitle: 'Доля ширины по умолчанию', + settingsWidthDesc: 'Доля боковой карточки в ширине окна для новых сессий, в процентах (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: 'Открывать файлы чата в боковой панели', + settingsOpenPathDesc: 'При щелчке по ссылке на файл в чате (строки инструментов, списки результатов, упоминания) файл открывается в редакторе боковой панели, а не в системном приложении по умолчанию', + settingsTitleBarTitle: 'Режим совместимости заголовка', + settingsTitleBarDesc: 'Выберите схему совместимости заголовка: автоопределение (по умолчанию, консервативно) / официальный Web DSH / известные десктоп-оболочки / своя схема (смещение + пользовательский CSS)', + settingsTitleBarStripTitle: 'Величина смещения', + settingsTitleBarStripDesc: 'Высота полосы заголовка: на сколько пикселей сдвигаются вниз кнопки и содержимое боковой панели (0–120, по умолчанию 40; действует при собственной схеме)', + settingsSchemeAutoTitle: 'Автоопределение', + settingsSchemeAutoDesc: 'Консервативно: отступ применяется только при доступности стандартного Window Controls Overlay API (по реальной высоте заголовка); в веб-среде изменения не вносятся', + settingsSchemeWebTitle: 'Официальный Web DSH', + settingsSchemeWebDesc: 'Явно объявляется официальный веб-интерфейс: адаптация не выполняется (даже стандартная геометрия WCO не применяется)', + settingsSchemeCustomTitle: 'Своя схема', + settingsSchemeCustomDesc: 'Полный контроль: внедряется пользовательский CSS (может перекрывать встроенные стили) и задаётся величина смещения заголовка', + settingsSchemeDetectedSuffix: 'обнаружено', + settingsCustomCssTitle: 'Пользовательский CSS', + settingsCustomCssDesc: 'Стили, добавляемые в конец страницы (при равном приоритете побеждает более поздний; для перезаписи инлайновых переменных из JS используйте !important)', + settingsCustomCssPlaceholder: '/* напр.: зарезервировать 36px для оболочки с собственным заголовком */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: 'Не удалось сохранить', + settingsConflict: 'Настройки были изменены в другом окне — повторите', + binaryNoPreview: 'Этот тип файла не поддерживает предпросмотр', + downloadToView: 'Скачать для просмотра', + settingsSubagentTitle: 'Автоматически разворачивать страницу «Задачи» при появлении субагента', + settingsSubagentDesc: 'При появлении нового субагента в текущей сессии боковая панель автоматически разворачивается и открывается страница «Задачи»; при отключении нужно открывать вручную', + settingsJobsTitle: 'Автоматически разворачивать страницу «Фоновые задачи» при новой задаче', + settingsJobsDesc: 'При появлении новой фоновой задачи в текущей сессии боковая панель автоматически разворачивается и открывается страница «Фоновые задачи» (срабатывает на каждую новую задачу); при отключении нужно открывать вручную', + settingsToolsTitle: 'Внедрить терминальные инструменты для модели', + settingsToolsDesc: 'Если включено, модель может через 8 инструментов (terminal_create и др.) создавать терминалы боковой панели и управлять ими (по умолчанию выключено)', + settingsBottomTerminalTitle: 'Автооткрытие терминала при первом разворачивании нижней панели', + settingsBottomTerminalDesc: 'При первом разворачивании нижней панели в сессии попытаться автоматически открыть новую вкладку терминала в ней (лимит терминалов всё равно применяется; по умолчанию включено)', + settingsFontFamilyTitle: 'Шрифт терминала', + settingsFontFamilyDesc: 'Семейство шрифта терминала (CSS font-family, напр. "JetBrains Mono", monospace; пусто — моноширинный шрифт темы)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: 'Размер шрифта терминала', + settingsFontSizeDesc: 'Размер шрифта терминала в px (9–32, по умолчанию 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'Путь к shell', + settingsShellDesc: 'Shell для терминалов UI и модели (абсолютный путь или имя исполняемого файла). Пусто — сохраняется прежний порядок: config.shell из yaml → $SHELL / login shell / powershell.exe в Windows. Применяется к терминалам, открываемым позже', + settingsShellPlaceholder: 'напр. /bin/zsh (пусто = авто)', + settingsShellArgsTitle: 'Аргументы shell', + settingsShellArgsDesc: 'Явные аргументы запуска shell, разделённые пробелами; при непустом значении полностью заменяют аргументы по умолчанию (тот же контракт, что у shellArgs из yaml)', + settingsShellArgsPlaceholder: 'напр. -l (пусто = по умолчанию)', + settingsTabsTitle: 'Содержимое боковой панели', + settingsViewersTitle: 'Просмотрщики файлов', + settingsGeneralTitle: 'Общие', + settingsPopup: 'Настройки функции', + settingsViewerCatchAll: 'Универсальный: любой файл', + viewerImage: 'Изображение', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: 'Код', + viewerBinary: 'Бинарная загрузка', + viewerHtml: 'HTML', + browser: 'Браузер', + browserPlaceholder: 'Введите URL, например example.com', + browserGo: 'Перейти', + browserBack: 'Назад', + browserForward: 'Вперёд', + browserStart: 'Введите URL для начала просмотра (режим песочницы)', + browserBlockedScheme: 'Заблокировано: разрешены только ссылки http/https', + browserBlockedLoopback: 'Заблокировано: локальные и внутренние адреса недоступны для просмотра здесь', + browserInvalid: 'Неверный URL', + browserNoSandboxWarning: 'Песочница выключена: текущая страница работает с полными привилегиями интерфейса (можно включить заново в настройках)', + htmlNoSandboxWarning: 'Песочница выключена: этот HTML работает с полными привилегиями интерфейса и может читать файлы сессии и внутренние API (можно включить заново в настройках)', + sandboxStatusOn: 'Режим песочницы: включён · страницы не имеют доступа к данным интерфейса и локальным файлам; вход и сторонние cookie могут не работать', + sandboxUnlock: 'Временно отключить (небезопасно)', + sandboxRestore: 'Восстановить песочницу', + settingsHtmlDefaultUnsafeTitle: 'Открывать HTML-предпросмотр без песочницы по умолчанию (небезопасно)', + settingsHtmlDefaultUnsafeDesc: 'Если включено, каждый новый HTML-предпросмотр стартует без песочницы (тот же источник, что у интерфейса — может читать файлы сессии и внутренние API); в строке состояния можно временно включить песочницу', + settingsHtmlSandboxTitle: 'Отключить песочницу HTML-предпросмотра (небезопасно)', + settingsHtmlSandboxDesc: 'При отключении предпросматриваемый HTML работает в том же источнике, что интерфейс: может читать файлы сессии, локальное хранилище и вызывать внутренние API. Включайте только для полностью доверенных файлов', + settingsBrowserSandboxTitle: 'Отключить песочницу браузера (небезопасно)', + settingsBrowserSandboxDesc: 'При отключении любой посещаемый сайт работает в том же источнике, что интерфейс: может читать данные сессии и выдавать себя за ваш вход. Включайте только для полностью доверенных сайтов', + settingsBrowserLinksTitle: 'Открывать внешние ссылки чата в боковой панели', + settingsBrowserLinksDesc: 'Если включено, щелчок по внешней ссылке в чате или интерфейсе открывает её в боковой панели, а не в новом окне; HTTP и HTTPS управляются отдельно переключателями ниже; Ctrl/Cmd+щелчок всегда пропускает', + settingsBrowserHttpTitle: 'Открывать HTTP-страницы в боковой панели', + settingsBrowserHttpDesc: 'Если включено, щелчок по HTTP-ссылке в чате или интерфейсе открывает её в боковой панели (страницы плагинов с urlTarget имеют приоритет); Ctrl/Cmd+щелчок всегда пропускает', + settingsBrowserHttpsTitle: 'Открывать HTTPS-страницы в боковой панели', + settingsBrowserHttpsDesc: 'Если включено, щелчок по HTTPS-ссылке в чате или интерфейсе открывает её в боковой панели. По умолчанию выключено: большинство HTTPS-сайтов отказываются встраиваться, поэтому системный браузер работает плавнее', + browserOpenExternal: 'Открыть в браузере', + browserEmbedBlocked: '{host} отказал во встраивании', + browserEmbedBlockedDesc: 'Сайт запрещает отображение внутри других страниц (X-Frame-Options / frame-ancestors), поэтому его нельзя загрузить в боковой панели. Откройте его напрямую в браузере', + browserEmbedAnyway: 'Загрузить всё равно', + + subagent: 'Задачи', + openSubagent: 'Задачи', + subagentMainAgent: 'Главный агент', + subagentEmpty: 'Нет субагентов', + subagentEmptyDesc: 'Субагенты, порождённые главным агентом, появятся здесь', + subagentRunning: 'Выполняется', + subagentInactive: 'Простаивает', + subagentModeOneShot: 'Одноразовый', + subagentModeContinuable: 'Продолжаемый', + subagentCount: '{count} субагентов', + subagentCountRunning: '{count} субагентов · {running} выполняется', + subagentDiagCorrupt: 'Повреждён', + subagentDiagUnsupported: 'Не поддерживается', + subagentDiagUnavailable: 'Недоступен', + subagentThinking: 'Размышляет…', + sideChat: 'Боковой чат (бета)', + sideChatNew: 'Новый поток', + sideChatUntitled: 'Новый поток', + sideChatEmpty: 'Нет боковых диалогов', + sideChatEmptyDesc: 'Каждый боковой диалог — отдельная вкладка в полосе; наследует контекст текущей сессии и не попадает в основной диалог', + sideChatCreating: 'Создание бокового диалога…', + sideChatRetry: 'Повторить', + sideChatThreads: 'Сменить поток / новый', + sideChatSave: 'Сохранить как новую сессию', + sideChatSaveTitle: 'Повысить поток до сессии верхнего уровня в основном списке сессий', + sideChatSaved: 'Сохранено как новая сессия', + sideChatNoTurn: 'Сохранение доступно после первого завершённого хода', + sideChatPendingDrop: 'Последний незавершённый уточняющий вопрос не попадёт в сохранённую сессию', + sideChatFirstPlaceholder: 'Задайте первый вопрос — контекст уже унаследован…', + sideChatComposerPlaceholder: 'Уточняющий вопрос…', + sideChatThinking: 'Углубляется…', + sideChatThink: 'Размышления', + sideChatInjection: 'Контекст внедрён', + sideChatSend: 'Отправить', + sideChatCancel: 'Остановить', + sideChatCancelTitle: 'Прервать текущий ход (очередь сохраняется)', + sideChatClose: 'Закрыть поток', + sideChatCloseTitle: 'Освободить агента потока (история сохраняется)', + sideChatError: 'Ошибка бокового чата: {message}', + jobs: 'Фоновые задачи', + jobsCount: '{count} фоновых задач', + jobsCountRunning: '{count} фоновых задач · {running} выполняется', + jobStatusRunning: 'Выполняется', + jobStatusStopping: 'Останавливается', + jobStatusCompleted: 'Завершено', + jobStatusKilled: 'Уничтожен', + jobStatusFailed: 'Сбой', + jobDurationSeconds: '{seconds} с', + jobDurationMinutes: '{minutes}м {seconds}с', + jobDurationHours: '{hours}ч {minutes}м', + jobViewOutput: 'Показать вывод', + jobHideOutput: 'Скрыть вывод', + jobNoOutput: 'Пока нет вывода', + jobNotReadYet: 'Ожидание, пока модель прочитает вывод этой задачи (после выполнения job_output вывод появится здесь)', + jobOutputTruncated: 'Вывод обрезан', + jobOutputError: 'Не удалось прочитать вывод', + jobKill: 'Завершить', + jobKillConfirm: 'Нажмите ещё раз, чтобы подтвердить завершение', + jobKillError: 'Не удалось завершить', + addPluginsTabCard: 'Добавить плагины вкладок', + addPluginsTabCardDesc: 'Зарегистрировать новую страницу боковой панели', + addPluginsViewerCard: 'Добавить плагины предпросмотра', + addPluginsViewerCardDesc: 'Зарегистрировать предпросмотр типа файлов', + addPluginsTabDesc: 'Страницы боковой панели (вкладки) расширяются плагинами. Плагины регистрируются через службу ctx.betterSidebar; щелчок по «Установить» копирует команду — вставьте её в терминал, где находится профиль DSH, и выполните.', + addPluginsViewerDesc: 'Просмотрщики файлов расширяются плагинами. Плагины регистрируются через службу ctx.betterSidebar; щелчок по «Установить» копирует команду — вставьте её в терминал, где находится профиль DSH, и выполните.', + addPluginsBrowseMore: 'Найти больше плагинов на GitHub (topic: dsh-better-sidebar)', + addPluginsSearch: 'Поиск по имени или описанию плагина…', + addPluginsNoMatch: 'Нет совпадающих плагинов', + addPluginsRecommended: 'Рекомендуемые плагины', + addPluginsEmpty: 'Пока плагины не собраны — опубликуйте свой под топиком на GitHub', + openPlugin: 'Открыть', + copyInstall: 'Копировать команду установки', + pluginOfficeDesc: 'Предпросмотр Office (.docx / .xlsx / .pptx) для редактора better-sidebar; тяжёлые библиотеки рендеринга Office вынесены из основного пакета и устанавливаются по требованию', + pluginFlowglassDesc: 'Живой граф потока сессии: три дорожки для пользователя, ассистента и вызовов инструментов, с параллельными группами, ветками субагентов, послойным раскрытием и статусом в реальном времени; регистрирует собственную вкладку «Flowglass» при установленном better-sidebar и сохраняет отдельный лоток как запас', + pluginGitForgeDesc: 'Вкладка «Git Forge»: библиотека аккаунтов GitHub/Gitea и других Forge + попроектные разрешения + жёсткая блокировка push; токены хранятся только в локальных секретах и не попадают в контекст модели; даёт инструмент GitForge (только чтение) и HTTPS credential helper для агента', + pluginGitRemotesDesc: 'Вкладка Git Remotes: просмотр веток/апстрима/ahead-behind, fetch (с возможностью prune), ff-only pull и push только после подтверждения во вкладке. Не заменяет встроенную вкладку Git (индексирование/коммит), не предоставляет force-push и инструмент авто-push для модели', + pluginSentinelDesc: 'Система пробуждения агента по условиям: сенсоры файлов/процессов/портов/HTTP/команд/webhook будят спящие сессии при срабатывании; регистрирует вкладку «Sentinel» с глобальной таблицей наблюдений сервера', + pluginSidebarQaDesc: 'Вкладка «выделить и спросить» на базе better-sidebar: выделение текста в диалоге → вопрос в правой панели → отдельная сессия уточняющих вопросов в той же рабочей области (❓вопросы·тема): быстрая модель без размышлений сжимает контекст основного диалога и внедряет его вместе с цитатой, не прерывая основной диалог; уточняющие вопросы вкладываются, продолжаются и архивируются', + pluginSshTunnelDesc: 'Вкладка «SSH-туннель»: список хостов нескольких машин + попроектные разрешения + локальное хранение ключей; инструмент модели SSHManager (exec/SFTP/стратегии сессий); центральный интерактивный терминал и двухпанельный SFTP', + pluginTurnReviewDesc: 'Человеческий шлюз Approve / Request changes для diff «только что завершённого хода»: рассматривается только предыдущий ход, без форка сессии; файлы группируются по основная сессия/субагент/без атрибуции, отметка возврата по файлам + необязательный комментарий; щелчок по файлу сначала показывает diff между снимком начала хода и текущим состоянием. Это не /rewind', + pluginVideoPreviewDesc: 'Встроенный предпросмотр видеофайлов (.mp4/.webm/.mov/.mkv/.avi и др.) в редакторе better-sidebar; обслуживается выделенным хост-маршрутом /video с поддержкой HTTP Range (206) — перемотка работает, а файлы не ограничены mediaLimit в 20 МБ', + pluginDocsPanelDesc: '«Глобальные документы» в боковой панели DSH: глобальные Markdown-заметки, доступные из любой рабочей области — список для чтения, навигация по плавающему оглавлению, открытие в Chrome / VS Code, копирование кода; каталог настраивается (по умолчанию ~/.dsh/docs)', +} diff --git a/src/client/locales-sv.ts b/src/client/locales-sv.ts new file mode 100644 index 0000000..fd28a42 --- /dev/null +++ b/src/client/locales-sv.ts @@ -0,0 +1,328 @@ +export const sv: Record = { + files: 'Filer', + explorer: 'Utforskare', + git: 'Källkodshantering', + terminal: 'Terminal', + editor: 'Editor', + editorExplorer: 'Filers öppningsbeteende', + editorExplorerDesc: 'Styr hur filer öppnas', + editorExplorerMerged: 'Sammanslagen', + editorExplorerMergedDesc: 'Filer växlas på plats i samma fönster; nya fönster startar med trädet öppet', + editorExplorerSplit: 'Separat', + editorExplorerSplitDesc: 'Fönster utan sökväg är den fristående utforskaren (endast träd); varje fil öppnar ett eget fönster (träd dockat, stängt som standard)', + editorTreeToggle: 'Filträdspanel', + editorPathPlaceholder: 'Filsökväg (relativ sessionskatalogen eller absolut), Enter för att öppna', + editorSearchPlaceholder: 'Sök filer efter namn…', + editorSearchNoResults: 'Inga matchande filer', + editorSearchTruncated: 'För många resultat — visar en delvis lista', + editorEmptyHint: 'Välj en fil från trädpanelen eller sökvägsinmatningen ovan för att börja förhandsgranska', + openFileNewTab: 'Öppna i ny flik', + openFileSide: 'Öppna vid sidan', + openWithMenu: 'Öppna med', + openWithSshSuffix: ' (SSH)', + pinOpenWith: 'Fäst i meny', + unpinOpenWith: 'Lossa', + openWithExplorer: 'Filhanterare', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'SSH-fjärrvärd', + openWithSettingsSshDesc: 'Tomt = lokal arbetsyta; med user@host eller SSH-alias byter VSCode-familjens öppnare till vscode-remote/ssh-remote-protokollet och Filhanterare / Zed / icke-VSCode-familjens anpassade editorer döljs från menyn', + openWithSettingsSshPlaceholder: 'user@host eller SSH-alias', + openWithSettingsCustomTitle: 'Anpassade editorer', + openWithSettingsCustomDesc: 'Namn + URL-mall ({path}-platshållare) + VSCode-familj-flagga; i fjärrläge kan endast VSCode-familjens editorer öppna en fjärrsökväg', + openWithSettingsAdd: 'Lägg till', + openWithSettingsName: 'Namn', + openWithSettingsTemplate: 't.ex. cursor://file/{path}', + openWithSettingsFamily: 'VSCode-familj', + openWithSettingsFamilyDesc: 'Denna editor talar VSCode:s URL-dialekt (stöder SSH-fjärröppning)', + openWithSettingsRemove: 'Ta bort', + openWithSettingsInvalidHint: 'Editorer med saknat namn eller en mall utan {path} / scheme:// visas inte i menyn', + newTab: 'Ny flik', + openExplorer: 'Utforskare', + brokenSymlink: 'Bruten symbolisk länk', + openGit: 'Git-panel', + newTerminal: 'Ny terminal', + terminalLimit: 'Terminalgräns nådd (3)', + close: 'Stäng', + closeOtherTabs: 'Stäng andra flikar', + closeLeftTabs: 'Stäng flikar till vänster', + closeRightTabs: 'Stäng flikar till höger', + collapse: 'Komprimera sidopanel', + expand: 'Expandera sidopanel', + collapseBottomPanel: 'Komprimera bottenpanel', + expandBottomPanel: 'Expandera bottenpanel', + terminalError: 'Terminalanslutning misslyckades', + terminalConnectFailed: 'Terminal misslyckades att ansluta upprepade gånger', + terminalRetry: 'Försök igen', + terminalDepsFailed: 'Terminalberoendet node-pty kunde inte laddas', + terminalDepsHint: 'Kör kommandot nedan i en terminal eller cmd på DSH-maskinen för att reparera det, försök sedan igen (node-pty hålls synkad med DSH-kärnversionen):', + terminalDepsProfile: ' (upptäckt profil: {profile})', + preview: 'Förhandsgranska', + edit: 'Redigera', + mermaidError: 'Mermaid-rendering misslyckades', + mermaidZoomIn: 'Zooma in', + mermaidZoomOut: 'Zooma ut', + mermaidZoomReset: 'Återställ', + mermaidZoomHint: 'Rulla för att zooma · dra för att panorera · Esc för att stänga', + refresh: 'Uppdatera', + save: 'Spara', + saved: 'Sparad', + unsaved: 'Osparad', + saveFailed: 'Kunde inte spara', + truncation: 'Filen är för stor — visar de första 512KB', + binary: 'Binärfil, förhandsgranskning otillgänglig', + loading: 'Laddar…', + error: 'Kunde inte ladda', + retry: 'Försök igen', + splitLeft: 'Dela vänster', + splitRight: 'Dela höger', + splitUp: 'Dela upp', + splitDown: 'Dela ner', + notRepo: 'Denna katalog är inte ett Git-arkiv', + noChanges: 'Inga ändringar', + stage: 'Köa', + unstage: 'Avköa', + stageAll: 'Köa alla', + unstageAll: 'Avköa alla', + commitPlaceholder: 'Commit-meddelande (Ctrl+Enter)', + commit: 'Commit', + commitError: 'Commit misslyckades', + branch: 'Gren', + checkoutError: 'Grenbyte misslyckades', + history: 'Historik', + changes: 'Ändringar', + staged: 'Köade', + unstaged: 'Avköade', + cancel: 'Avbryt', + diffEmpty: 'Inga textändringar', + diffLoadError: 'Kunde inte ladda diff', + diffBinary: 'Binär', + diffAdded: 'Tillagd', + diffDeleted: 'Borttagen', + diffRenamed: 'Omdöpt', + diffExpand: 'Expandera {count} fler rader', + diffCollapse: 'Komprimera', + discard: 'Förkasta ändringar', + discardTitle: 'Förkasta ändringar', + discardDesc: 'Detta förkastar arbetskopians ändringar av ”{path}” (kan inte ångras).', + viewCommitDiff: 'Visa commit-diff', + copyShortHash: 'Kopiera kort hash', + copyFullHash: 'Kopiera full hash', + copySubject: 'Kopiera ämne', + revertCommit: 'Återställ commit', + revertTitle: 'Återställ commit', + revertDesc: 'Skapa en ny commit på aktuell gren som återställer ”{subject}”.', + cherryPickCommit: 'Cherry-picka commit', + cherryPickTitle: 'Cherry-picka commit', + cherryPickDesc: 'Tillämpa ändringarna från ”{subject}” på aktuell gren.', + timeJustNow: 'just nu', + timeMinutesAgo: '{n} min sedan', + timeHoursAgo: '{n} h sedan', + timeYesterday: 'igår', + loadMore: 'Ladda fler', + historyLoadError: 'Kunde inte ladda mer historik', + produced: 'Producerat', + producedOpen: 'Öppna i sidopanelen', + disconnected: 'Terminalen frånkopplad, ansluter igen…', + exited: 'Terminalprocess avslutad', + noSession: 'Välj en konversation för att använda sidopanelen', + pluginNotLoaded: 'Plugin inte laddad; flik otillgänglig:', + hiddenFiles: 'Dolda filer', + parent: 'Överordnad katalog', + copied: 'Kopierades', + copy: 'Kopiera', + newFile: 'Ny fil', + openEditor: 'Öppna editor', + gitDetail: 'Visa ändringsdetaljer', + referenceFile: '@fil', + addToConversation: 'Lägg till i konversation', + copyRelative: 'Kopiera relativ sökväg', + copyAbsolute: 'Kopiera absolut sökväg', + download: 'Ladda ner', + uploadFiles: 'Ladda upp filer', + uploadFolder: 'Ladda upp mapp', + uploadHere: 'Ladda upp hit', + uploadDropHint: 'Släpp filer/mappar här för att ladda upp', + uploadDropChat: 'Släpp på chatareat för att lägga till bilder', + uploadTo: 'Ladda upp till {dir}', + uploadingTo: 'Laddar upp till {dir}…', + uploadProgress: 'Laddar upp {done}/{total}: {name}', + uploadDone: 'Laddade upp {count} fil(er)', + uploadFailed: 'Uppladdning misslyckades: {error}', + uploadFailedUnknown: 'Okänt fel', + uploadTooLarge: 'Filen för stor (över uppladdningsgränsen)', + uploadCancelled: 'Uppladdning avbruten', + settingsNav: 'Sidokort', + settingsIntro: 'Hantera vad sidokortet visar och hur det beter sig', + settingsPopupDesc: 'Konfigurera relaterade alternativ för {feature}', + settingsDone: 'Klar', + settingsOpenTitle: 'Öppna som standard för nya konversationer', + settingsOpenDesc: 'Expandera sidokortet automatiskt för helt nya konversationer; befintliga konversationer behåller sina egna layouter', + settingsWidthTitle: 'Standardbreddandel', + settingsWidthDesc: 'Sidokortets standardandel av fönsterbredden för nya konversationer (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: 'Öppna chattfiler i sidopanelen', + settingsOpenPathDesc: 'Öppna fillänkar i chatten (verktygsrader, producerade filer, omnämnanden) i sidopanelens editor i stället för systemets standardapp', + settingsTitleBarTitle: 'Positions kompatibilitetsläge', + settingsTitleBarDesc: 'Välj titelfälts kompatibilitetsschema: auto-detektera (standard, konservativt) / DSH officiella webb / kända skrivbordsskal / anpassat (förskjutningsavstånd + egen CSS)', + settingsTitleBarStripTitle: 'Förskjutningsavstånd', + settingsTitleBarStripDesc: 'Titelfältsremsans höjd: hur långt sidopanelens knappar och innehåll flyttas ner i px (0–120, standard 40; gäller under det anpassade schemat)', + settingsSchemeAutoTitle: 'Auto-detektera', + settingsSchemeAutoDesc: 'Konservativt: endast standard Window Controls Overlay API bidrar (reell caption-overlay-höjd); vanliga webbmiljöer får ingen ändring', + settingsSchemeWebTitle: 'DSH officiella webb', + settingsSchemeWebDesc: 'Explicit deklarera det officiella webbgränssnittet: ingen anpassning alls (inte ens standard WCO-geometri)', + settingsSchemeCustomTitle: 'Anpassat', + settingsSchemeCustomDesc: 'Full kontroll: injicera egen CSS (kan åsidosätta inbyggda stilar) och sätt titelfältets förskjutningsavstånd', + settingsSchemeDetectedSuffix: 'upptäckt', + settingsCustomCssTitle: 'Anpassad CSS', + settingsCustomCssDesc: 'Stilar tillagda på slutet av sidan (senare i kaskaden vinner vid oavgjort; använd !important för att åsidosätta JS-skrivna inline-variabler)', + settingsCustomCssPlaceholder: '/* t.ex. reservera 36px för ett skal med egenritat titelfält */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: 'Kunde inte spara', + settingsConflict: 'Inställningen ändrades i ett annat fönster — vänligen försök igen', + binaryNoPreview: 'Denna filtyp kan inte förhandsgranskas', + downloadToView: 'Ladda ner för att visa', + settingsSubagentTitle: 'Öppna automatiskt Uppgiftssidan när en subagent dyker upp', + settingsSubagentDesc: 'Expandera sidokortet och öppna Uppgiftssidan när aktuell konversation skapar en ny subagent; stäng av för att öppna manuellt', + settingsJobsTitle: 'Öppna automatiskt Jobbsidan vid nytt bakgrundsjobb', + settingsJobsDesc: 'Expandera sidokortet och öppna Jobbsidan när ett nytt bakgrundsjobb dyker upp för aktuell konversation (varje nytt jobb utlöser); stäng av för att öppna manuellt', + settingsToolsTitle: 'Injicera terminalverktyg för modellen', + settingsToolsDesc: 'När aktiverat kan modellen skapa och styra sidopanelsterminaler via de 8 terminal_*-verktygen (av som standard)', + settingsBottomTerminalTitle: 'Öppna automatiskt en terminal vid bottenpanelens första expandering', + settingsBottomTerminalDesc: 'När bottenpanelen expanderas för första gången i en session, försök öppna en ny terminalflik där (terminalgränsen gäller fortfarande; på som standard)', + settingsFontFamilyTitle: 'Terminalens teckensnittsfamilj', + settingsFontFamilyDesc: 'Anpassad teckensnittsfamilj för terminalen (en CSS font-family-stack som "JetBrains Mono", monospace; lämna tomt för att följa temats monospaced-teckensnitt)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: 'Terminalens teckenstorlek', + settingsFontSizeDesc: 'Terminalens teckenstorlek i px (9–32, standard 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'Skalsökväg', + settingsShellDesc: 'Skal som startas för UI- och modellterminaler (absolut sökväg ellerbart körbart namn). Tomt behåller den äldre ordningen: yaml config.shell → $SHELL / inloggningsskal / Windows powershell.exe. Gäller terminaler som öppnas senare', + settingsShellPlaceholder: 't.ex. /bin/zsh (tomt = auto)', + settingsShellArgsTitle: 'Skalargument', + settingsShellArgsDesc: 'Uttryckliga skalargument, mellanslagsseparerade; när icke-tomma ersätter de helt standardvärdena (samma kontrakt som yaml shellArgs)', + settingsShellArgsPlaceholder: 't.ex. -l (tomt = standard)', + settingsTabsTitle: 'Sidopanelens innehåll', + settingsViewersTitle: 'Filvisare', + settingsGeneralTitle: 'Allmänt', + settingsPopup: 'Funktionsinställningar', + settingsViewerCatchAll: 'Fånga alla: alla filer', + viewerImage: 'Bild', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: 'Kod', + viewerBinary: 'Binär nedladdning', + viewerHtml: 'HTML', + browser: 'Webbläsare', + browserPlaceholder: 'Ange en URL, t.ex. example.com', + browserGo: 'Gå', + browserBack: 'Bakåt', + browserForward: 'Framåt', + browserStart: 'Ange en URL för att börja surfa (sandlådeläge)', + browserBlockedScheme: 'Blockerat: endast http/https-URL:er är tillåtna', + browserBlockedLoopback: 'Blockerat: lokala och interna adresser kan inte surfas här', + browserInvalid: 'Ogiltig URL', + browserNoSandboxWarning: 'Sandlåda av: den aktuella sidan kör med fullständiga GUI-privilegier (återaktivera i inställningarna)', + htmlNoSandboxWarning: 'Sandlåda av: denna HTML kör med fullständiga GUI-privilegier (återaktivera i inställningarna)', + sandboxStatusOn: 'Sandlådeläge: på · sidor kan inte komma åt GUI:ts data eller lokala filer; inloggningar och tredjepartscookies kanske inte fungerar', + sandboxUnlock: 'Avaktivera tillfälligt (osäkert)', + sandboxRestore: 'Återställ sandlåda', + settingsHtmlDefaultUnsafeTitle: 'Öppna HTML-förhandsgranskningar osandlådade som standard (osäkert)', + settingsHtmlDefaultUnsafeDesc: 'När på, startar varje nyöppnad HTML-förhandsgranskning i osandlådat tillstånd (samma ursprung som GUI — kan läsa sessionsfiler och interna API:er); statusraden erbjuder fortfarande en återställning med ett klick', + settingsHtmlSandboxTitle: 'Avaktivera sandlåda för HTML-förhandsgranskning (osäkert)', + settingsHtmlSandboxDesc: 'Med sandlådan av körs förhandsgranskad HTML med samma ursprung som GUI: kan läsa sessionsfiler, lokal lagring och anropa interna API:er. Aktivera endast för fullt betrodda filer', + settingsBrowserSandboxTitle: 'Avaktivera webbläsarsandlåda (osäkert)', + settingsBrowserSandboxDesc: 'Med sandlådan av körs alla besökta sajter med samma ursprung som GUI: kan läsa sessionsdata och agera som er inloggade session. Aktivera endast för fullt betrodda sajter', + settingsBrowserLinksTitle: 'Öppna chattens externa länkar i sidopanelen', + settingsBrowserLinksDesc: 'När på, klick på en extern länk i chatten eller GUI öppnar sidopanelen i stället för ett nytt fönster; HTTP och HTTPS styrs separat av knapparna nedan; Ctrl/Cmd+klick kringgår alltid', + settingsBrowserHttpTitle: 'Öppna HTTP-sidor i sidopanelen', + settingsBrowserHttpDesc: 'När på, klick på en extern HTTP-länk i chatten eller GUI öppnar sidopanelen (pluginsidor som deklarerar urlTarget vinner); Ctrl/Cmd+klick kringgår alltid', + settingsBrowserHttpsTitle: 'Öppna HTTPS-sidor i sidopanelen', + settingsBrowserHttpsDesc: 'När på, klick på en extern HTTPS-länk i chatten eller GUI öppnar sidopanelen. Av som standard: de flesta HTTPS-sajter vägrar bli inbäddade, så systemwebbläsaren är det smidigare standardvalet', + browserOpenExternal: 'Öppna i webbläsare', + browserEmbedBlocked: '{host} vägrade bli inbäddad', + browserEmbedBlockedDesc: 'Sajten förbjuder att visas inuti andra sidor (X-Frame-Options / frame-ancestors), så den kan inte ladda i sidopanelen. Öppna den direkt i er webbläsare i stället.', + browserEmbedAnyway: 'Ladda ändå', + subagent: 'Uppgifter', + openSubagent: 'Uppgifter', + subagentMainAgent: 'Huvudagent', + subagentEmpty: 'Inga subagenter', + subagentEmptyDesc: 'Subagenter skapade under huvudagenten visas här', + subagentRunning: 'Kör', + subagentInactive: 'Inaktiv', + subagentModeOneShot: 'Engångs', + subagentModeContinuable: 'Fortsättbar', + subagentCount: '{count} subagenter', + subagentCountRunning: '{count} subagenter · {running} kör', + subagentDiagCorrupt: 'Korrupt', + subagentDiagUnsupported: 'Stöds ej', + subagentDiagUnavailable: 'Otillgänglig', + subagentThinking: 'Tänker…', + sideChat: 'Sidochatt (beta)', + sideChatNew: 'Ny tråd', + sideChatUntitled: 'Ny tråd', + sideChatEmpty: 'Inga sidokonversationer', + sideChatEmptyDesc: 'Varje sidokonversation är en egen flik i flikraden — den ärver den aktuella sessionens kontext och kommer aldrig in i huvudkonversationen', + sideChatCreating: 'Skapar sidokonversation…', + sideChatRetry: 'Försök igen', + sideChatThreads: 'Byt tråd / ny', + sideChatSave: 'Spara som ny session', + sideChatSaveTitle: 'Höj denna tråd till en toppnivå-session i huvudsessionslistan', + sideChatSaved: 'Sparad som ny session', + sideChatNoTurn: 'Spara är tillgängligt efter den första slutförda vändan', + sideChatPendingDrop: 'Den senaste obesvarade följdfrågan inkluderas inte i den sparade sessionen', + sideChatFirstPlaceholder: 'Ställ den första frågan — kontext ärvd…', + sideChatComposerPlaceholder: 'Ställ en följdfråga…', + sideChatThinking: 'Dyk djupare…', + sideChatThink: 'Tänker', + sideChatInjection: 'Kontext injicerad', + sideChatSend: 'Skicka', + sideChatCancel: 'Stoppa', + sideChatCancelTitle: 'Avbryt den pågående vändan (köat arbete behålls)', + sideChatClose: 'Stäng tråd', + sideChatCloseTitle: 'Frigör trådens agent (historik behålls)', + sideChatError: 'Sidochattsfel: {message}', + jobs: 'Bakgrundsjobb', + jobsCount: '{count} bakgrundsjobb', + jobsCountRunning: '{count} bakgrundsjobb · {running} kör', + jobStatusRunning: 'Kör', + jobStatusStopping: 'Stoppar', + jobStatusCompleted: 'Klar', + jobStatusKilled: 'Dödad', + jobStatusFailed: 'Misslyckades', + jobDurationSeconds: '{seconds}s', + jobDurationMinutes: '{minutes}m {seconds}s', + jobDurationHours: '{hours}t {minutes}m', + jobViewOutput: 'Visa utdata', + jobHideOutput: 'Dölj utdata', + jobNoOutput: 'Ingen utdata än', + jobNotReadYet: 'Väntar på att modellen ska läsa detta jobb; dess utdata visas här när modellen kör job_output', + jobOutputTruncated: 'Utdata avkortad', + jobOutputError: 'Kunde inte läsa utdata', + jobKill: 'Döda', + jobKillConfirm: 'Klicka igen för att bekräfta dödande', + jobKillError: 'Kunde inte döda', + addPluginsTabCard: 'Lägg till flik-plugins', + addPluginsTabCardDesc: 'Registrera en ny sidopanelssida', + addPluginsViewerCard: 'Lägg till förhandsgransknings-plugins', + addPluginsViewerCardDesc: 'Registrera en filtypsförhandsgranskning', + addPluginsTabDesc: 'Sidopanelens sidor (flikar) kan utökas av plugins. Plugins registreras via ctx.betterSidebar-tjänsten; att klicka på Installera kopierar installationskommandot — klistra in det i en terminal där er DSH-profil lever och kör det.', + addPluginsViewerDesc: 'Filförhandsgranskare kan utökas av plugins. Plugins registreras via ctx.betterSidebar-tjänsten; att klicka på Installera kopierar installationskommandot — klistra in det i en terminal där er DSH-profil lever och kör det.', + addPluginsBrowseMore: 'Bläddra bland fler plugins på GitHub (topic: dsh-better-sidebar)', + addPluginsSearch: 'Sök på plugin-namn eller beskrivning…', + addPluginsNoMatch: 'Inga plugins matchar', + addPluginsRecommended: 'Rekommenderade plugins', + addPluginsEmpty: 'Inga plugins kurerade ännu — publicera er egen under GitHub-topic:n', + openPlugin: 'Öppna', + copyInstall: 'Kopiera installationskommando', + pluginOfficeDesc: 'Office-svitförhandsgranskning (.docx / .xlsx / .pptx) för better-sidebar-editorn, som håller de tunga Office-renderingsbiblioteken utanför kärnbundlen', + pluginFlowglassDesc: 'Live sessionsflödesgraf med tre banor för användare, assistent och verktygsanrop, plus parallella grupper, subagent-grenar, djupdykning och live-status; registrerar en inbyggd Flowglass-flik när better-sidebar är installerat och behåller sin fristående låda som reserv', + pluginGitForgeDesc: 'Git Forge-flik: GitHub/Gitea (och andra forge) kontobibliotek + per-projekt-tillstånd + hård push-policy; token stannar i lokala secrets (aldrig i modellkontext); skrivskyddat GitForge-verktyg och agent-HTTPS credential helper', + pluginGitRemotesDesc: 'Git Remotes-flik: gren/upstream/ahead-behind, fetch (valbar prune), ff-only pull och push endast efter bekräftelse i fliken. Ersätter inte den inbyggda Git-köa/commit-fliken, och erbjuder inte force-push eller ett model-auto-push-verktyg', + pluginSentinelDesc: 'Villkorsdriven agentväckning: fil-/process-/port-/http-/kommando-/webhook-sensorer väcker vilande sessioner när villkor utlöses; registrerar en "Sentinel"-flik med serverns globala bevakningstabell', + pluginSidebarQaDesc: 'Markera-och-fråga: Markera konversationstext → fråga i högra panelen → en dedikerad följdfrågesession (❓ följdfråga) i samma arbetsyta; en snabb no-thinking-modell komprimerar huvudkontexten och injicerar den tillsammans med citatet, utan att avbryta huvudkonversationen. Följdfrågor kan nästlas, fortsättas och arkiveras', + pluginSshTunnelDesc: 'SSH Tunnel-flik: flervärd-inventering + per-projekt-tillstånd + lokala secrets; SSHManager-verktyg (exec/SFTP/sessionsstrategier); central interaktiv terminal och dubbelpanelig SFTP', + pluginTurnReviewDesc: 'En mänsklig grinds för den just avslutade vändan: Godkänn / Begär ändringar per sökväg med valfri kommentar; sökvägar grupperade per huvudsession / subagent / oattribuerade; inline ögonblicksbild-mot-nu-diff innan ni bestämmer er. Ingen förgrening, ingen /rewind', + pluginVideoPreviewDesc: 'Inline videoförhandsgranskning (.mp4/.webm/.mov/.mkv/.avi etc.) för better-sidebar-editorn, backad av en dedikerad /video-värdroute med HTTP Range (206)-stöd — sökning fungerar och filer begränsas inte av 20MB mediaLimit', + pluginDocsPanelDesc: 'Globala dokument i DSH-sidopanelen: läs era egna Markdown-anteckningar från valfri arbetsyta — en fillista, en översikt, öppna i Chrome / VS Code och kopieringsknappar; dokumentkatalogen är konfigurerbar (standard ~/.dsh/docs)', +} diff --git a/src/client/locales-th.ts b/src/client/locales-th.ts new file mode 100644 index 0000000..ce0f6f4 --- /dev/null +++ b/src/client/locales-th.ts @@ -0,0 +1,345 @@ +/** + * The th (Thai) dictionary for the betterSidebar namespace. + * + * Mirrors the key set of `zh` in `locales.ts`. The sidebar's `t()` + * consults this dict when `attachBetterLocale(store)` has been called + * with an active better-locale store whose `active` is `'th'`; absent + * that, the existing zh/en chain runs unchanged. + * + * Translation conventions: + * - Technical terms stay in English where appropriate (Git, SSH, HTTP, URL, + * Markdown, PDF, VS Code, API Key, Base URL, token, etc.). + * - Placeholders keep {name} verbatim (interpolation runs after lookup). + * - Formal Thai appropriate for software UI. + * - Terminology is kept consistent with the DSH core th dictionary. + */ + +/** The th dictionary (key-set-equal to zh, enforced by the type annotation in locales.ts). */ +export const th: Record = { + files: 'ไฟล์', + explorer: 'ตัวสำรวจ', + git: 'การควบคุมซอร์ส', + terminal: 'เทอร์มินัล', + editor: 'ตัวแก้ไข', + editorExplorer: 'พฤติกรรมการเปิดไฟล์', + editorExplorerDesc: 'ควบคุมวิธีเปิดไฟล์', + editorExplorerMerged: 'รวม', + editorExplorerMergedDesc: 'ไฟล์สลับในตำแหน่งเดิมในหน้าต่างเดียวกัน; หน้าต่างใหม่เริ่มต้นด้วยต้นไม้ไฟล์ที่เปิดอยู่', + editorExplorerSplit: 'แยก', + editorExplorerSplitDesc: 'หน้าต่างที่ไม่มีพาธคือตัวสำรวจแบบสแตนด์อโลน (ต้นไม้ไฟล์เท่านั้น); แต่ละไฟล์เปิดหน้าต่างของตัวเอง (ต้นไม้ไฟล์ docked, ปิดเป็นค่าเริ่มต้น)', + editorTreeToggle: 'พาเนลต้นไม้ไฟล์', + editorPathPlaceholder: 'พาธไฟล์ (สัมพันธ์กับไดเรกทอรีเซสชันหรือแบบ absolute), Enter เพื่อเปิด', + editorSearchPlaceholder: 'ค้นหาไฟล์ตามชื่อ…', + editorSearchNoResults: 'ไม่มีไฟล์ที่ตรง', + editorSearchTruncated: 'ผลลัพธ์มากเกินไป — แสดงเพียงบางส่วน', + editorEmptyHint: 'เลือกไฟล์จากพาเนลต้นไม้ไฟล์หรือช่องกรอกพาธด้านบนเพื่อเริ่มพรีวิว', + openFileNewTab: 'เปิดใน Tab ใหม่', + openFileSide: 'เปิดด้านข้าง', + openWithMenu: 'เปิดด้วย', + openWithSshSuffix: ' (SSH)', + pinOpenWith: 'ปักหมุดในเมนู', + unpinOpenWith: 'ยกเลิกการปักหมุด', + openWithExplorer: 'ตัวจัดการไฟล์', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'โฮสต์ระยะไกล SSH', + openWithSettingsSshDesc: 'ว่าง = พื้นที่ทำงานในเครื่อง; เมื่อกรอก user@host หรือ alias SSH ตัวเปิดตระกูล VSCode จะสลับไปใช้โปรโตคอล vscode-remote/ssh-remote และตัวจัดการไฟล์ / Zed / ตัวแก้ไขที่กำหนดเองที่ไม่ใช่ตระกูล VSCode จะถูกซ่อนจากเมนู', + openWithSettingsSshPlaceholder: 'user@host หรือ alias SSH', + openWithSettingsCustomTitle: 'ตัวแก้ไขที่กำหนดเอง', + openWithSettingsCustomDesc: 'ชื่อ + เทมเพลต URL (placeholder {path}) + แฟล็กตระกูล VSCode; ในโหมดระยะไกลเฉพาะตัวแก้ไขตระกูล VSCode เท่านั้นที่เปิดพาธระยะไกลได้', + openWithSettingsAdd: 'เพิ่ม', + openWithSettingsName: 'ชื่อ', + openWithSettingsTemplate: 'เช่น cursor://file/{path}', + openWithSettingsFamily: 'ตระกูล VSCode', + openWithSettingsFamilyDesc: 'ตัวแก้ไขนี้ใช้โปรโตคอล URL ของ VSCode (รองรับการเปิดจากระยะไกลผ่าน SSH)', + openWithSettingsRemove: 'ลบ', + openWithSettingsInvalidHint: 'ตัวแก้ไขที่ไม่มีชื่อหรือเทมเพลตที่ไม่มี {path} / scheme:// จะไม่ปรากฏในเมนู', + newTab: 'Tab ใหม่', + openExplorer: 'ตัวสำรวจ', + brokenSymlink: 'Symlink เสีย', + openGit: 'พาเนล Git', + newTerminal: 'เทอร์มินัลใหม่', + terminalLimit: 'ถึงขีดจำกัดเทอร์มินัลแล้ว (3)', + close: 'ปิด', + closeOtherTabs: 'ปิด Tab อื่น', + closeLeftTabs: 'ปิด Tab ด้านซ้าย', + closeRightTabs: 'ปิด Tab ด้านขวา', + collapse: 'ย่อแถบด้านข้าง', + expand: 'ขยายแถบด้านข้าง', + collapseBottomPanel: 'ย่อพาเนลด้านล่าง', + expandBottomPanel: 'ขยายพาเนลด้านล่าง', + terminalError: 'การเชื่อมต่อเทอร์มินัลล้มเหลว', + terminalConnectFailed: 'เทอร์มินัลเชื่อมต่อล้มเหลวหลายครั้ง', + terminalRetry: 'ลองอีกครั้ง', + terminalDepsFailed: 'การอ้างอิงเทอร์มินัล node-pty โหลดล้มเหลว', + terminalDepsHint: 'เรียกใช้คำสั่งด้านล่างในเทอร์มินัลหรือ cmd บนเครื่อง DSH เพื่อซ่อมแซม แล้วกดลองอีกครั้ง (node-pty ต้องซิงค์กับเวอร์ชันหลักของ DSH):', + terminalDepsProfile: ' (ตรวจพบ profile: {profile})', + preview: 'พรีวิว', + edit: 'แก้ไข', + mermaidError: 'เรนเดอร์ Mermaid ล้มเหลว', + mermaidZoomIn: 'ซูมเข้า', + mermaidZoomOut: 'ซูมออก', + mermaidZoomReset: 'รีเซ็ต', + mermaidZoomHint: 'เลื่อนเพื่อซูม · ลากเพื่อแพน · Esc เพื่อปิด', + refresh: 'รีเฟรช', + save: 'บันทึก', + saved: 'บันทึกแล้ว', + unsaved: 'ยังไม่ได้บันทึก', + saveFailed: 'บันทึกล้มเหลว', + truncation: 'ไฟล์ใหญ่เกินไป — แสดงเพียง 512KB แรก', + binary: 'ไฟล์ไบนารี ไม่สามารถพรีวิวได้', + loading: 'กำลังโหลด…', + error: 'โหลดล้มเหลว', + retry: 'ลองอีกครั้ง', + splitLeft: 'แยกซ้าย', + splitRight: 'แยกขวา', + splitUp: 'แยกขึ้น', + splitDown: 'แยกลง', + notRepo: 'ไดเรกทอรีนี้ไม่ใช่ git repository', + noChanges: 'ไม่มีการเปลี่ยนแปลง', + stage: 'Stage', + unstage: 'Unstage', + stageAll: 'Stage ทั้งหมด', + unstageAll: 'Unstage ทั้งหมด', + commitPlaceholder: 'ข้อความ commit (Ctrl+Enter)', + commit: 'Commit', + commitError: 'Commit ล้มเหลว', + branch: 'Branch', + checkoutError: 'สลับ branch ล้มเหลว', + history: 'ประวัติ', + changes: 'การเปลี่ยนแปลง', + staged: 'Staged', + unstaged: 'Unstaged', + cancel: 'ยกเลิก', + diffEmpty: 'ไม่มีการเปลี่ยนแปลงข้อความ', + diffLoadError: 'โหลด diff ล้มเหลว', + diffBinary: 'ไบนารี', + diffAdded: 'เพิ่ม', + diffDeleted: 'ลบ', + diffRenamed: 'เปลี่ยนชื่อ', + diffExpand: 'ขยายอีก {count} บรรทัด', + diffCollapse: 'ย่อ', + discard: 'ยกเลิกการเปลี่ยนแปลง', + discardTitle: 'ยกเลิกการเปลี่ยนแปลง', + discardDesc: 'จะยกเลิกการเปลี่ยนแปลง worktree ของ "{path}" (ไม่สามารถกู้คืนได้)', + viewCommitDiff: 'ดู diff ของ commit', + copyShortHash: 'คัดลอก short hash', + copyFullHash: 'คัดลอก full hash', + copySubject: 'คัดลอกหัวข้อ commit', + revertCommit: 'Revert commit', + revertTitle: 'Revert commit', + revertDesc: 'สร้าง commit ใหม่บน branch ปัจจุบันที่ revert "{subject}"', + cherryPickCommit: 'Cherry-pick commit', + cherryPickTitle: 'Cherry-pick commit', + cherryPickDesc: 'นำการเปลี่ยนแปลงของ "{subject}" ไปใช้กับ branch ปัจจุบัน', + timeJustNow: 'เมื่อสักครู่', + timeMinutesAgo: '{n} นาทีที่แล้ว', + timeHoursAgo: '{n} ชม. ที่แล้ว', + timeYesterday: 'เมื่อวาน', + loadMore: 'โหลดเพิ่มเติม', + historyLoadError: 'โหลดประวัติเพิ่มเติมล้มเหลว', + produced: 'ผลลัพธ์ที่สร้าง', + producedOpen: 'เปิดในแถบด้านข้าง', + disconnected: 'เทอร์มินัลถูกตัดการเชื่อมต่อ กำลังเชื่อมต่อใหม่…', + exited: 'กระบวนการเทอร์มินัลออกแล้ว', + noSession: 'เลือกแชทเพื่อใช้แถบด้านข้าง', + pluginNotLoaded: 'ปลั๊กอินไม่ได้โหลด; tab ไม่พร้อมใช้งาน:', + hiddenFiles: 'ไฟล์ที่ซ่อนอยู่', + parent: 'ไดเรกทอรีหลัก', + copied: 'คัดลอกแล้ว', + copy: 'คัดลอก', + newFile: 'ไฟล์ใหม่', + openEditor: 'เปิดตัวแก้ไข', + gitDetail: 'ดูรายละเอียดการเปลี่ยนแปลง', + referenceFile: '@ไฟล์', + addToConversation: 'เพิ่มไปยังแชท', + copyRelative: 'คัดลอกพาธสัมพัทธ์', + copyAbsolute: 'คัดลอกพาธ absolute', + download: 'ดาวน์โหลด', + uploadFiles: 'อัปโหลดไฟล์', + uploadFolder: 'อัปโหลดโฟลเดอร์', + uploadHere: 'อัปโหลดที่นี่', + uploadDropHint: 'ลากไฟล์/โฟลเดอร์มาที่นี่เพื่ออัปโหลด', + uploadDropChat: 'ลากไปที่แชทเพื่อเพิ่มรูปภาพ', + uploadTo: 'อัปโหลดไปยัง {dir}', + uploadingTo: 'กำลังอัปโหลดไปยัง {dir}…', + uploadProgress: 'กำลังอัปโหลด {done}/{total}: {name}', + uploadDone: 'อัปโหลด {count} ไฟล์แล้ว', + uploadFailed: 'อัปโหลดล้มเหลว: {error}', + uploadFailedUnknown: 'ข้อผิดพลาดที่ไม่รู้จัก', + uploadTooLarge: 'ไฟล์ใหญ่เกินไป (เกินขีดจำกัดการอัปโหลด)', + uploadCancelled: 'การอัปโหลดถูกยกเลิก', + settingsNav: 'การ์ดด้านข้าง', + settingsIntro: 'จัดการสิ่งที่การ์ดด้านข้างแสดงและพฤติกรรมของมัน', + settingsPopupDesc: 'กำหนดค่าตัวเลือกที่เกี่ยวข้องสำหรับ {feature}', + settingsDone: 'เสร็จสิ้น', + settingsOpenTitle: 'เปิดโดยค่าเริ่มต้นสำหรับแชทใหม่', + settingsOpenDesc: 'ขยายการ์ดด้านข้างโดยอัตโนมัติสำหรับแชทใหม่; แชทที่มีอยู่แล้วยังคงเค้าโครงของตัวเอง', + settingsWidthTitle: 'สัดส่วนความกว้างเริ่มต้น', + settingsWidthDesc: 'สัดส่วนความกว้างเริ่มต้นของการ์ดด้านข้างจากความกว้างหน้าต่างสำหรับแชทใหม่ (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: 'เปิดไฟล์แชทในแถบด้านข้าง', + settingsOpenPathDesc: 'เปิดลิงก์ไฟล์ในแชท (แถวเครื่องมือ, ไฟล์ที่สร้าง, การกล่าวถึง) ในตัวแก้ไขแถบด้านข้างแทนแอปเริ่มต้นของระบบ', + settingsTitleBarTitle: 'โหมดความเข้ากันได้ของตำแหน่ง', + settingsTitleBarDesc: 'เลือกโครงร่างความเข้ากันได้ของไตเติลบาร์: ตรวจจับอัตโนมัติ (ค่าเริ่มต้น, อนุรักษ์นิยม) / DSH เว็บอย่างเป็นทางการ / เชลล์เดสก์ท็อปที่รู้จัก / กำหนดเอง (ระยะการเลื่อน + CSS ที่กำหนดเอง)', + settingsTitleBarStripTitle: 'ระยะการเลื่อน', + settingsTitleBarStripDesc: 'ความสูงของแถบไตเติลบาร์: จำนวนพิกเซลที่ปุ่มแถบด้านข้างและเนื้อหาเลื่อนลง (0–120, ค่าเริ่มต้น 40; มีผลภายใต้โครงร่างกำหนดเอง)', + settingsSchemeAutoTitle: 'ตรวจจับอัตโนมัติ', + settingsSchemeAutoDesc: 'อนุรักษ์นิยม: เฉพาะ API มาตรฐาน Window Controls Overlay เท่านั้นที่มีส่วนร่วม (ความสูง caption-overlay จริง); สภาพแวดล้อมเว็บธรรมดาไม่ได้รับการแก้ไข', + settingsSchemeWebTitle: 'DSH เว็บอย่างเป็นทางการ', + settingsSchemeWebDesc: 'ประกาศอย่างชัดเจนว่าเป็นเว็บ UI อย่างเป็นทางการ: ไม่มีการปรับตัวใดๆ (แม้แต่เรขาคณิต WCO มาตรฐาน)', + settingsSchemeCustomTitle: 'กำหนดเอง', + settingsSchemeCustomDesc: 'ควบคุมเต็ม: ฉีด CSS ที่กำหนดเอง (สามารถแทนที่สไตล์ built-in) และตั้งระยะการเลื่อนไตเติลบาร์', + settingsSchemeDetectedSuffix: 'ตรวจพบแล้ว', + settingsCustomCssTitle: 'CSS ที่กำหนดเอง', + settingsCustomCssDesc: 'สไตล์ที่เพิ่มต่อท้ายหน้า (ที่มาทีหลังใน cascade ชนะ; ใช้ !important เพื่อแทนที่ตัวแปร inline ที่เขียนโดย JS)', + settingsCustomCssPlaceholder: '/* เช่น สำรอง 36px สำหรับเชลล์ที่มีไตเติลบาร์ที่วาดเอง */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: 'บันทึกล้มเหลว', + settingsConflict: 'การตั้งค่าถูกเปลี่ยนในหน้าต่างอื่น — โปรดลองอีกครั้ง', + binaryNoPreview: 'ไม่สามารถพรีวิวประเภทไฟล์นี้ได้', + downloadToView: 'ดาวน์โหลดเพื่อดู', + settingsSubagentTitle: 'เปิดหน้า Tasks อัตโนมัติเมื่อมีตัวแทนย่อยปรากฏ', + settingsSubagentDesc: 'ขยายการ์ดด้านข้างและเปิดหน้า Tasks เมื่อแชทปัจจุบันสร้างตัวแทนย่อยใหม่; ปิดเพื่อเปิดเอง', + settingsJobsTitle: 'เปิดหน้า Jobs อัตโนมัติเมื่อมีงานเบื้องหลังใหม่', + settingsJobsDesc: 'ขยายการ์ดด้านข้างและเปิดหน้า Jobs เมื่อใดก็ตามที่มีงานเบื้องหลังใหม่ปรากฏสำหรับแชทปัจจุบัน (ทุกงานใหม่จะทริกเกอร์); ปิดเพื่อเปิดเอง', + settingsToolsTitle: 'ฉีดเครื่องมือเทอร์มินัลสำหรับโมเดล', + settingsToolsDesc: 'เมื่อเปิดใช้ โมเดลสามารถสร้างและควบคุมเทอร์มินัลแถบด้านข้างผ่านเครื่องมือ terminal_* 8 ตัว (ปิดเป็นค่าเริ่มต้น)', + settingsBottomTerminalTitle: 'เปิดเทอร์มินัลอัตโนมัติเมื่อพาเนลล่างขยายครั้งแรก', + settingsBottomTerminalDesc: 'เมื่อพาเนลล่างถูกขยายครั้งแรกในเซสชัน ลองเปิด tab เทอร์มินัลใหม่ที่นั่น (โควต้าเทอร์มินัลยังคงมีผล; เปิดเป็นค่าเริ่มต้น)', + settingsFontFamilyTitle: 'ฟอนต์เทอร์มินัล', + settingsFontFamilyDesc: 'ฟอนต์เทอร์มินัลที่กำหนดเอง (CSS font-family stack เช่น "JetBrains Mono", monospace; ปล่อยว่างเพื่อตามฟอนต์ monospace ของธีม)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: 'ขนาดฟอนต์เทอร์มินัล', + settingsFontSizeDesc: 'ขนาดฟอนต์เทอร์มินัลเป็น px (9–32, ค่าเริ่มต้น 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'พาธ Shell', + settingsShellDesc: 'Shell ที่เรียกสำหรับเทอร์มินัล UI และโมเดล (พาธ absolute หรือ executable ลำพัง) ว่างจะคงลำดับเดิม: yaml config.shell → $SHELL / login shell / Windows powershell.exe มีผลกับเทอร์มินัลที่เปิดภายหลัง', + settingsShellPlaceholder: 'เช่น /bin/zsh (ว่าง = อัตโนมัติ)', + settingsShellArgsTitle: 'อาร์กิวเมนต์ Shell', + settingsShellArgsDesc: 'อาร์กิวเมนต์ shell ที่ชัดเจน คั่นด้วยช่องว่าง; เมื่อไม่ว่างจะแทนที่ค่าเริ่มต้นทั้งหมด (สัญญาณเดียวกับ yaml shellArgs)', + settingsShellArgsPlaceholder: 'เช่น -l (ว่าง = ค่าเริ่มต้น)', + settingsTabsTitle: 'เนื้อหาแถบด้านข้าง', + settingsViewersTitle: 'ตัวพรีวิวไฟล์', + settingsGeneralTitle: 'ทั่วไป', + settingsPopup: 'การตั้งค่าคุณสมบัติ', + settingsViewerCatchAll: 'Catch-all: ไฟล์ใดๆ', + viewerImage: 'รูปภาพ', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: 'โค้ด', + viewerBinary: 'ดาวน์โหลดไบนารี', + viewerHtml: 'HTML', + browser: 'เบราว์เซอร์', + browserPlaceholder: 'กรอก URL เช่น example.com', + browserGo: 'ไป', + browserBack: 'ย้อนกลับ', + browserForward: 'ไปข้างหน้า', + browserStart: 'กรอก URL เพื่อเริ่มเรียกดู (โหมดแซนด์บ็อกซ์)', + browserBlockedScheme: 'ถูกบล็อก: อนุญาตเฉพาะ URL http/https เท่านั้น', + browserBlockedLoopback: 'ถูกบล็อก: ไม่สามารถเรียกดูที่อยู่ภายในเครื่องและภายในได้ที่นี่', + browserInvalid: 'URL ไม่ถูกต้อง', + browserNoSandboxWarning: 'แซนด์บ็อกซ์ปิด: หน้าปัจจุบันทำงานด้วยสิทธิ์ GUI เต็มรูปแบบ (เปิดใช้ใหม่ได้ในการตั้งค่า)', + htmlNoSandboxWarning: 'แซนด์บ็อกซ์ปิด: HTML นี้ทำงานด้วยสิทธิ์ GUI เต็มรูปแบบ (เปิดใช้ใหม่ได้ในการตั้งค่า)', + sandboxStatusOn: 'โหมดแซนด์บ็อกซ์: เปิด · หน้าเว็บไม่สามารถเข้าถึงข้อมูลหรือไฟล์ภายในของ GUI ได้; การล็อกอินและคุกกี้ของบุคคลที่สามอาจไม่ทำงาน', + sandboxUnlock: 'ปิดใช้ชั่วคราว (ไม่ปลอดภัย)', + sandboxRestore: 'คืนค่าแซนด์บ็อกซ์', + settingsHtmlDefaultUnsafeTitle: 'เปิดพรีวิว HTML โดยไม่มีแซนด์บ็อกซ์เป็นค่าเริ่มต้น (ไม่ปลอดภัย)', + settingsHtmlDefaultUnsafeDesc: 'เมื่อเปิด พรีวิว HTML ที่เปิดใหม่ทุกครั้งจะเริ่มในสถานะไม่มีแซนด์บ็อกซ์ (origin เดียวกับ GUI — สามารถอ่านไฟล์เซสชันและ API ภายในได้); แถวสถานะยังคงเสนอการคืนค่าแบบแตะครั้งเดียว', + settingsHtmlSandboxTitle: 'ปิดแซนด์บ็อกซ์พรีวิว HTML (ไม่ปลอดภัย)', + settingsHtmlSandboxDesc: 'เมื่อปิดแซนด์บ็อกซ์ HTML ที่พรีวิวจะทำงานด้วย origin เดียวกับ GUI: สามารถอ่านไฟล์เซสชัน, ที่เก็บข้อมูลในเครื่อง และเรียก API ภายในได้ เปิดใช้เฉพาะสำหรับไฟล์ที่เชื่อถือได้อย่างเต็มที่', + settingsBrowserSandboxTitle: 'ปิดแซนด์บ็อกซ์เบราว์เซอร์ (ไม่ปลอดภัย)', + settingsBrowserSandboxDesc: 'เมื่อปิดแซนด์บ็อกซ์ ไซต์ที่เยี่ยมชมใดๆ จะทำงานด้วย origin เดียวกับ GUI: สามารถอ่านข้อมูลเซสชันและแสดงเป็นเซสชันล็อกอินของคุณได้ เปิดใช้เฉพาะสำหรับไซต์ที่เชื่อถือได้อย่างเต็มที่', + settingsBrowserLinksTitle: 'เปิดลิงก์ภายนอกของแชทในแถบด้านข้าง', + settingsBrowserLinksDesc: 'เมื่อเปิด การคลิกลิงก์ภายนอกในแชทหรือ GUI จะเปิดแถบด้านข้างแทนหน้าต่างใหม่; HTTP และ HTTPS ถูกควบคุมแยกโดยสวิตช์ด้านล่าง; Ctrl/Cmd+click จะข้ามเสมอ', + settingsBrowserHttpTitle: 'เปิดหน้า HTTP ในแถบด้านข้าง', + settingsBrowserHttpDesc: 'เมื่อเปิด การคลิกลิงก์ HTTP ภายนอกในแชทหรือ GUI จะเปิดแถบด้านข้าง (หน้าปลั๊กอินที่ประกาศ urlTarget win มีความสำคัญก่อน); Ctrl/Cmd+click จะข้ามเสมอ', + settingsBrowserHttpsTitle: 'เปิดหน้า HTTPS ในแถบด้านข้าง', + settingsBrowserHttpsDesc: 'เมื่อเปิด การคลิกลิงก์ HTTPS ภายนอกในแชทหรือ GUI จะเปิดแถบด้านข้าง ปิดเป็นค่าเริ่มต้น: ไซต์ HTTPS ส่วนใหญ่ปฏิเสธที่จะฝัง ดังนั้นเบราว์เซอร์ระบบจะราบรื่นกว่าเป็นค่าเริ่มต้น', + browserOpenExternal: 'เปิดในเบราว์เซอร์', + browserEmbedBlocked: '{host} ปฏิเสธที่จะถูกฝัง', + browserEmbedBlockedDesc: 'ไซต์ห้ามไม่ให้แสดงภายในหน้าอื่น (X-Frame-Options / frame-ancestors) จึงไม่สามารถโหลดในแถบด้านข้างได้ เปิดโดยตรงในเบราว์เซอร์ของคุณแทน', + browserEmbedAnyway: 'โหลดต่อไป', + subagent: 'งาน', + openSubagent: 'งาน', + subagentMainAgent: 'ตัวแทนหลัก', + subagentEmpty: 'ไม่มีตัวแทนย่อย', + subagentEmptyDesc: 'ตัวแทนย่อยที่สร้างภายใต้ตัวแทนหลักจะปรากฏที่นี่', + subagentRunning: 'กำลังทำงาน', + subagentInactive: 'ไม่ได้ทำงาน', + subagentModeOneShot: 'ครั้งเดียว', + subagentModeContinuable: 'ทำต่อได้', + subagentCount: '{count} ตัวแทนย่อย', + subagentCountRunning: '{count} ตัวแทนย่อย · {running} กำลังทำงาน', + subagentDiagCorrupt: 'เสียหาย', + subagentDiagUnsupported: 'ไม่รองรับ', + subagentDiagUnavailable: 'ไม่พร้อมใช้งาน', + subagentThinking: 'กำลังคิด…', + sideChat: 'แชทด้านข้าง (เบต้า)', + sideChatNew: 'เธรดใหม่', + sideChatUntitled: 'เธรดใหม่', + sideChatEmpty: 'ไม่มีแชทด้านข้าง', + sideChatEmptyDesc: 'แชทด้านข้างทุกรายการคือ tab ของตัวเองในแถบ tab — สืบทอดบริบทของเซสชันปัจจุบันและไม่เข้าสู่แชทหลัก', + sideChatCreating: 'กำลังสร้างแชทด้านข้าง…', + sideChatRetry: 'ลองอีกครั้ง', + sideChatThreads: 'สลับเธรด / ใหม่', + sideChatSave: 'บันทึกเป็นเซสชันใหม่', + sideChatSaveTitle: 'เลื่อนเธรดนี้เป็นเซสชันระดับบนสุดในรายการเซสชันหลัก', + sideChatSaved: 'บันทึกเป็นเซสชันใหม่แล้ว', + sideChatNoTurn: 'การบันทึกพร้อมใช้งานหลังจากรอบแรกเสร็จสมบูรณ์', + sideChatPendingDrop: 'การติดตามที่ยังไม่ได้ตอบครั้งสุดท้ายจะไม่รวมในเซสชันที่บันทึก', + sideChatFirstPlaceholder: 'ถามคำถามแรก — บริบทที่สืบทอด…', + sideChatComposerPlaceholder: 'ถามติดตาม…', + sideChatThinking: 'กำลังดำดิ่ง…', + sideChatThink: 'กำลังคิด', + sideChatInjection: 'แทรกบริบทแล้ว', + sideChatSend: 'ส่ง', + sideChatCancel: 'หยุด', + sideChatCancelTitle: 'ยกเลิกการทำงานรอบปัจจุบัน (งานในคิวยังคงอยู่)', + sideChatClose: 'ปิดเธรด', + sideChatCloseTitle: 'ปล่อยตัวแทนของเธรด (ประวัติยังคงอยู่)', + sideChatError: 'ข้อผิดพลาดแชทด้านข้าง: {message}', + jobs: 'งานเบื้องหลัง', + jobsCount: '{count} งานเบื้องหลัง', + jobsCountRunning: '{count} งานเบื้องหลัง · {running} กำลังทำงาน', + jobStatusRunning: 'กำลังทำงาน', + jobStatusStopping: 'กำลังหยุด', + jobStatusCompleted: 'เสร็จสิ้น', + jobStatusKilled: 'ถูก kill', + jobStatusFailed: 'ล้มเหลว', + jobDurationSeconds: '{seconds} วิ', + jobDurationMinutes: '{minutes} นาที {seconds} วิ', + jobDurationHours: '{hours} ชม. {minutes} นาที', + jobViewOutput: 'ดูเอาต์พุต', + jobHideOutput: 'ซ่อนเอาต์พุต', + jobNoOutput: 'ยังไม่มีเอาต์พุต', + jobNotReadYet: 'รอให้โมเดลอ่านงานนี้; เอาต์พุตจะปรากฏที่นี่เมื่อโมเดลเรียก job_output', + jobOutputTruncated: 'เอาต์พุตถูกตัดทิ้ง', + jobOutputError: 'โหลดเอาต์พุตล้มเหลว', + jobKill: 'Kill', + jobKillConfirm: 'คลิกอีกครั้งเพื่อยืนยันการ kill', + jobKillError: 'Kill ล้มเหลว', + addPluginsTabCard: 'เพิ่มปลั๊กอิน tab', + addPluginsTabCardDesc: 'ลงทะเบียนหน้าแถบด้านข้างใหม่', + addPluginsViewerCard: 'เพิ่มปลั๊กอินพรีวิว', + addPluginsViewerCardDesc: 'ลงทะเบียนพรีวิวประเภทไฟล์', + addPluginsTabDesc: 'หน้าแถบด้านข้าง (tab) สามารถขยายได้ด้วยปลั๊กอิน ปลั๊กอินลงทะเบียนผ่านบริการ ctx.betterSidebar; การคลิก Install จะคัดลอกคำสั่งติดตั้ง — วางลงในเทอร์มินัลที่ DSH profile ของคุณอยู่แล้วเรียกใช้', + addPluginsViewerDesc: 'ตัวพรีวิวไฟล์สามารถขยายได้ด้วยปลั๊กอิน ปลั๊กอินลงทะเบียนผ่านบริการ ctx.betterSidebar; การคลิก Install จะคัดลอกคำสั่งติดตั้ง — วางลงในเทอร์มินัลที่ DSH profile ของคุณอยู่แล้วเรียกใช้', + addPluginsBrowseMore: 'เรียกดูปลั๊กอินเพิ่มเติมบน GitHub (topic: dsh-better-sidebar)', + addPluginsSearch: 'ค้นหาตามชื่อหรือคำอธิบายปลั๊กอิน…', + addPluginsNoMatch: 'ไม่มีปลั๊กอินที่ตรง', + addPluginsRecommended: 'ปลั๊กอินแนะนำ', + addPluginsEmpty: 'ยังไม่มีปลั๊กอินที่คัดสรร — เผยแพร่ปลั๊กอินของคุณภายใต้ topic บน GitHub', + openPlugin: 'เปิด', + copyInstall: 'คัดลอกคำสั่งติดตั้ง', + pluginOfficeDesc: 'พรีวิวชุด Office (.docx / .xlsx / .pptx) สำหรับตัวแก้ไข better-sidebar โดยแยกไลบรารีเรนเดอร์ Office ที่หนักออกจาก bundle หลัก', + pluginFlowglassDesc: 'กราฟโฟลว์เซสชันสดพร้อมเลนสามเลนสำหรับผู้ใช้, ผู้ช่วย และการเรียกเครื่องมือ พร้อมกลุ่มขนาน, สาขาตัวแทนย่อย, drill-down และสถานะสด; ลงทะเบียน tab Flowglass แบบ native เมื่อติดตั้ง better-sidebar และคงลิ้นชักสแตนด์อโลนเป็นทางเลือกสำรอง', + pluginGitForgeDesc: 'tab Git Forge: คลังบัญชี GitHub/Gitea (และ forge อื่นๆ) + การอนุญาตต่อโปรเจกต์ + นโยบาย push แบบเข้มงวด; token อยู่ใน secrets ในเครื่อง (ไม่เคยอยู่ในบริบทโมเดล); เครื่องมือ GitForge แบบอ่านอย่างเดียวและตัวช่วย credential HTTPS ของตัวแทน', + pluginGitRemotesDesc: 'tab Git Remotes: branch/upstream/ahead-behind, fetch (optional prune), ff-only pull และ push หลังการยืนยันใน tab เท่านั้น ไม่แทนที่ tab stage/commit ของ Git แบบ built-in และไม่เสนอ force-push หรือเครื่องมือ auto-push ของโมเดล', + pluginSentinelDesc: 'การปลุกตัวแทนที่ขับเคลื่อนด้วยเงื่อนไข: เซนเซอร์ file/process/port/http/command/webhook ปลุกเซสชันที่หลับเมื่อเงื่อนไขเกิดขึ้น; ลงทะเบียน tab "Sentinel" พร้อมตารางเฝ้าระวังทั่วทั้งเซิร์ฟเวอร์', + pluginSidebarQaDesc: 'เลือกแล้วถาม: เลือกข้อความในแชท → ถามในพาเนลด้านขวา → เซสชันติดตามเฉพาะ (❓追问) ในพื้นที่ทำงานเดียวกัน; โมเดล no-thinking ที่รวดเร็วบีบอัดบริบทหลักและฉีดพร้อมกับคำพูดอ้างอิง โดยไม่หยุดแชทหลัก การติดตามสามารถซ้อน, ทำต่อ และเก็บถาวรได้', + pluginSshTunnelDesc: 'tab SSH Tunnel: รายการโฮสต์หลายเครื่อง + การอนุญาตต่อโปรเจกต์ + secrets ในเครื่อง; เครื่องมือ SSHManager (exec/SFTP/กลยุทธ์เซสชัน); เทอร์มินัลโต้ตอบกลางและ SFTP แบบสองพาเนล', + pluginTurnReviewDesc: 'ประตูมนุษย์บนรอบที่เพิ่งเสร็จสิ้น: Approve / Request changes ต่อพาธพร้อมความคิดเห็นที่ไม่บังคับ; พาธจัดกลุ่มตามเซสชันหลัก / ตัวแทนย่อย / ไม่ระบุแหล่งที่มา; diff แบบ snapshot-vs-now อินไลน์ก่อนตัดสินใจ ไม่มีการ fork, ไม่มี /rewind', + pluginVideoPreviewDesc: 'พรีวิววิดีโอแบบอินไลน์ (.mp4/.webm/.mov/.mkv/.avi ฯลฯ) สำหรับตัวแก้ไข better-sidebar โดยสนับสนุนด้วย route /video โฮสต์เฉพาะพร้อมรองรับ HTTP Range (206) — การ scrub ทำงานได้และไฟล์ไม่จำกัดโดย mediaLimit 20MB', + pluginDocsPanelDesc: 'เอกสารส่วนกลางในแถบด้านข้าง DSH: อ่านบันทึก Markdown ของคุณเองจากพื้นที่ทำงานใดๆ — รายการไฟล์, เค้าโครง, เปิดใน Chrome / VS Code และปุ่มคัดลอก; ไดเรกทอรีเอกสารสามารถกำหนดค่าได้ (ค่าเริ่มต้น ~/.dsh/docs)', +} diff --git a/src/client/locales-tr.ts b/src/client/locales-tr.ts new file mode 100644 index 0000000..bc38c72 --- /dev/null +++ b/src/client/locales-tr.ts @@ -0,0 +1,345 @@ +/** + * The tr (Turkish) dictionary for the betterSidebar namespace. + * + * Mirrors the key set of `zh` in `locales.ts`. The sidebar's `t()` + * consults this dict when `attachBetterLocale(store)` has been called + * with an active better-locale store whose `active` is `'tr'`; absent + * that, the existing zh/en chain runs unchanged. + * + * Translation conventions: + * - Common dev-tool loanwords stay in Turkish (Terminal, Tarayıcı, Klasör). + * - Git vocabulary follows standard Turkish usage ( Sahnele, İşle, Dal). + * - Settings labels end in noun/infinitive forms to mirror the zh cadence. + * - Placeholders keep `{name}` verbatim (interpolation runs after lookup). + * - English brand names (VS Code, Cursor, Zed, SSH) stay as-is. + */ + +/** The tr dictionary (key-set-equal to zh, enforced by the type annotation in locales.ts). */ +export const tr: Record = { + files: 'Dosyalar', + explorer: 'Gezgin', + git: 'Kaynak denetimi', + terminal: 'Terminal', + editor: 'Düzenleyici', + editorExplorer: 'Dosya açma davranışı', + editorExplorerDesc: 'Dosyaların açılma biçimini denetler', + editorExplorerMerged: 'Birleşik', + editorExplorerMergedDesc: 'Dosyalar aynı pencerede yerinde geçer; yeni pencereler ağaç açık başlar', + editorExplorerSplit: 'Ayrı', + editorExplorerSplitDesc: 'Yolsuz pencere tek başına gezgindir (yalnızca ağaç); her dosya kendi penceresini açar (ağaç yuvalanmış, varsayılan kapalı)', + editorTreeToggle: 'Dosya ağacı paneli', + editorPathPlaceholder: 'Dosya yolu (oturum dizinine göreli veya mutlak), Enter ile aç', + editorSearchPlaceholder: 'Dosya adına göre ara…', + editorSearchNoResults: 'Eşleşen dosya yok', + editorSearchTruncated: 'Sonuç çok fazla — kısmi liste gösteriliyor', + editorEmptyHint: 'Önizlemeye başlamak için sağdaki dosya ağacından veya yukarıdaki yol girişinden bir dosya seçin', + openFileNewTab: 'Yeni sekmede aç', + openFileSide: 'Yana aç', + openWithMenu: 'Birlikte aç', + openWithSshSuffix: ' (SSH)', + pinOpenWith: 'Menüye sabitle', + unpinOpenWith: 'Sabitlemeyi kaldır', + openWithExplorer: 'Dosya yöneticisi', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'SSH uzak ana makine', + openWithSettingsSshDesc: 'Boş = yerel çalışma alanı; bir user@host veya SSH rumuzu verilirse VSCode ailesi açıcılar vscode-remote/ssh-remote protokolüne geçer ve Dosya yöneticisi / Zed / VSCode ailesi olmayan özel düzenleyiciler menüden gizlenir', + openWithSettingsSshPlaceholder: 'user@host veya SSH rumuzu', + openWithSettingsCustomTitle: 'Özel düzenleyiciler', + openWithSettingsCustomDesc: 'Ad + URL şablonu ({path} yer tutucusu) + VSCode ailesi bayrağı; uzak modda yalnızca VSCode ailesi düzenleyiciler uzak yolu açabilir', + openWithSettingsAdd: 'Ekle', + openWithSettingsName: 'Ad', + openWithSettingsTemplate: 'ör. cursor://file/{path}', + openWithSettingsFamily: 'VSCode ailesi', + openWithSettingsFamilyDesc: 'Bu düzenleyici VSCode URL dilini konuşur (SSH uzak açmayı destekler)', + openWithSettingsRemove: 'Kaldır', + openWithSettingsInvalidHint: 'Adı eksik veya {path}/scheme:// içermeyen şablonlu düzenleyiciler menüde gösterilmez', + newTab: 'Yeni sekme', + openExplorer: 'Gezgin', + brokenSymlink: 'Bozuk sembolik bağ', + openGit: 'Git paneli', + newTerminal: 'Yeni terminal', + terminalLimit: 'Terminal sınırına ulaşıldı (3)', + close: 'Kapat', + closeOtherTabs: 'Diğer sekmeleri kapat', + closeLeftTabs: 'Soldaki sekmeleri kapat', + closeRightTabs: 'Sağdaki sekmeleri kapat', + collapse: 'Kenar çubuğunu daralt', + expand: 'Kenar çubuğunu genişlet', + collapseBottomPanel: 'Alt paneli daralt', + expandBottomPanel: 'Alt paneli genişlet', + terminalError: 'Terminal bağlantısı başarısız', + terminalConnectFailed: 'Terminal art arda bağlanamadı', + terminalRetry: 'Yeniden dene', + terminalDepsFailed: 'Terminal bağımlılığı node-pty yüklenemedi', + terminalDepsHint: 'Onarmak için DSH makinesindeki bir terminalde veya cmd’de aşağıdaki komutu çalıştırın, sonra yeniden deneyin (node-pty, DSH çekirdek sürümüyle senkron kalır):', + terminalDepsProfile: ' (algılanan profil: {profile})', + preview: 'Önizleme', + edit: 'Düzenle', + mermaidError: 'Mermaid oluşturma başarısız', + mermaidZoomIn: 'Yakınlaştır', + mermaidZoomOut: 'Uzaklaştır', + mermaidZoomReset: 'Sıfırla', + mermaidZoomHint: 'Yakınlaştırmak için kaydır · taşımak için sürükle · kapatmak için Esc', + refresh: 'Yenile', + save: 'Kaydet', + saved: 'Kaydedildi', + unsaved: 'Kaydedilmedi', + saveFailed: 'Kaydetme başarısız', + truncation: 'Dosya çok büyük — ilk 512KB gösteriliyor', + binary: 'İkili dosya, önizleme kullanılamıyor', + loading: 'Yükleniyor…', + error: 'Yükleme başarısız', + retry: 'Yeniden dene', + splitLeft: 'Sola böl', + splitRight: 'Sağa böl', + splitUp: 'Yukarı böl', + splitDown: 'Aşağı böl', + notRepo: 'Bu dizin bir git deposu değil', + noChanges: 'Değişiklik yok', + stage: 'Sahnele', + unstage: 'Sahnelemeden kaldır', + stageAll: 'Tümünü sahnele', + unstageAll: 'Tümünü sahnelemeden kaldır', + commitPlaceholder: 'İşleme iletisi (Ctrl+Enter)', + commit: 'İşle', + commitError: 'İşleme başarısız', + branch: 'Dal', + checkoutError: 'Dal değiştirme başarısız', + history: 'Geçmiş', + changes: 'Değişiklikler', + staged: 'Sahnelendi', + unstaged: 'Sahnelenmedi', + cancel: 'İptal', + diffEmpty: 'Metin değişikliği yok', + diffLoadError: 'Diff yüklenemedi', + diffBinary: 'İkili', + diffAdded: 'Eklendi', + diffDeleted: 'Silindi', + diffRenamed: 'Yeniden adlandırıldı', + diffExpand: '{count} satır daha göster', + diffCollapse: 'Daralt', + discard: 'Değişiklikleri at', + discardTitle: 'Değişiklikleri at', + discardDesc: 'Bu, «{path}» öğesinin çalışma ağacı değişikliklerini atar (geri alınamaz).', + viewCommitDiff: 'İşleme diff’ini görüntüle', + copyShortHash: 'Kısa karmayı kopyala', + copyFullHash: 'Tam karmayı kopyala', + copySubject: 'İşleme iletisini kopyala', + revertCommit: 'İşlemeyi geri al', + revertTitle: 'İşlemeyi geri al', + revertDesc: '«{subject}» işlemini geriye alan yeni bir işleme geçerli dalda oluşturur.', + cherryPickCommit: 'İşlemeyi seç-al', + cherryPickTitle: 'İşlemeyi seç-al', + cherryPickDesc: '«{subject}» değişikliklerini geçerli dala uygular.', + timeJustNow: 'az önce', + timeMinutesAgo: '{n} dk önce', + timeHoursAgo: '{n} sa önce', + timeYesterday: 'dün', + loadMore: 'Daha fazla yükle', + historyLoadError: 'Daha fazla geçmiş yüklenemedi', + produced: 'Üretilenler', + producedOpen: 'Kenar çubuğunda aç', + disconnected: 'Terminal bağlantısı kesildi, yeniden bağlanılıyor…', + exited: 'Terminal süreci sonlandı', + noSession: 'Kenar çubuğunu kullanmak için bir oturum seçin', + pluginNotLoaded: 'Eklenti yüklenmedi; sekme kullanılamıyor:', + hiddenFiles: 'Gizli dosyalar', + parent: 'Üst dizin', + copied: 'Kopyalandı', + copy: 'Kopyala', + newFile: 'Yeni dosya', + openEditor: 'Düzenleyiciyi aç', + gitDetail: 'Değişiklik ayrıntılarını görüntüle', + referenceFile: '@dosya', + addToConversation: 'Sohbete ekle', + copyRelative: 'Göreli yolu kopyala', + copyAbsolute: 'Mutlak yolu kopyala', + download: 'İndir', + uploadFiles: 'Dosyaları yükle', + uploadFolder: 'Klasör yükle', + uploadHere: 'Buraya yükle', + uploadDropHint: 'Yüklemek için dosyaları/klasörleri buraya bırakın', + uploadDropChat: 'Resim eklemek için sohbet alanına bırakın', + uploadTo: '{dir} içine yükle', + uploadingTo: '{dir} içine yükleniyor…', + uploadProgress: 'Yükleniyor {done}/{total}: {name}', + uploadDone: '{count} dosya yüklendi', + uploadFailed: 'Yükleme başarısız: {error}', + uploadFailedUnknown: 'Bilinmeyen hata', + uploadTooLarge: 'Dosya çok büyük (yükleme sınırını aşıyor)', + uploadCancelled: 'Yükleme iptal edildi', + settingsNav: 'Yan kart', + settingsIntro: 'Yan kartın ne gösterdiğini ve nasıl davrandığını yönetin', + settingsPopupDesc: '«{feature}» için ilgili seçenekleri yapılandırın', + settingsDone: 'Bitti', + settingsOpenTitle: 'Yeni sohbetlerde varsayılan olarak aç', + settingsOpenDesc: 'Yepyeni sohbetler için yan kartı otomatik genişlet; var olan sohbetler kendi düzenlerini korur', + settingsWidthTitle: 'Varsayılan genişlik payı', + settingsWidthDesc: 'Yeni sohbetler için yan kartın pencere genişliğindeki varsayılan payı (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: 'Sohbet dosyalarını kenar çubuğunda aç', + settingsOpenPathDesc: 'Sohbetteki dosya bağlantılarını (araç satırları, üretilen dosyalar, anılmalar) sistem varsayılan uygulaması yerine kenar çubuğu düzenleyicisinde aç', + settingsTitleBarTitle: 'Konum uyumluluk modu', + settingsTitleBarDesc: 'Başlık çubuğu uyumluluk düzenini seçin: otomatik algıla (varsayılan, tutucu) / DSH resmi web / bilinen masaüstü kabukları / özel (kaydırma mesafesi + özel CSS)', + settingsTitleBarStripTitle: 'Kaydırma mesafesi', + settingsTitleBarStripDesc: 'Başlık çubuğu şerit yüksekliği: kenar çubuğu düğmelerinin ve içeriğin kaç px aşağı kayacağı (0–120, varsayılan 40; özel düzen altında geçerli)', + settingsSchemeAutoTitle: 'Otomatik algıla', + settingsSchemeAutoDesc: 'Tutucu: yalnızca standart Window Controls Overlay API’si katkıda bulunur (gerçek başlık katmanı yüksekliği); sade web ortamlarında hiçbir değişiklik yapılmaz', + settingsSchemeWebTitle: 'DSH resmi web', + settingsSchemeWebDesc: 'Resmi web arayüzünde çalıştığını açıkça bildir: hiçbir uyarlama yapılmaz (standart WCO geometrisi bile uygulanmaz)', + settingsSchemeCustomTitle: 'Özel', + settingsSchemeCustomDesc: 'Tam denetim: özel CSS enjekte et (yerleşik stilleri geçersiz kılabilir) ve başlık çubuğu kaydırma mesafesini ayarla', + settingsSchemeDetectedSuffix: 'algılandı', + settingsCustomCssTitle: 'Özel CSS', + settingsCustomCssDesc: 'Sayfanın sonuna eklenen stiller (basamakta sonra yazılan kazanır; JS ile yazılmış satır içi değişkenleri geçersiz kılmak için !important kullanın)', + settingsCustomCssPlaceholder: '/* örn. özel çizili başlık çubuğu olan bir kabuk için 36px ayır */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: 'Kaydetme başarısız', + settingsConflict: 'Ayar başka bir pencerede değiştirildi — lütfen yeniden deneyin', + binaryNoPreview: 'Bu dosya türü önizlenemiyor', + downloadToView: 'Görüntülemek için indir', + settingsSubagentTitle: 'Bir alt aracı belirdiğinde Görevler sayfasını otomatik aç', + settingsSubagentDesc: 'Geçerli sohbet yeni bir alt aracı doğurduğunda yan kartı genişlet ve Görevler sayfasını aç; elle açmak için kapatın', + settingsJobsTitle: 'Yeni arka plan işinde İşler sayfasını otomatik aç', + settingsJobsDesc: 'Geçerli sohbet için yeni bir arka plan işi belirdiğinde yan kartı genişlet ve İşler sayfasını aç (her yeni iş tetikler); elle açmak için kapatın', + settingsToolsTitle: 'Model için terminal araçları enjekte et', + settingsToolsDesc: 'Etkinleştirildiğinde model, 8 terminal_* aracı üzerinden kenar çubuğu terminalleri oluşturup kullanabilir (varsayılan kapalı)', + settingsBottomTerminalTitle: 'Alt panelin ilk genişletilmesinde otomatik terminal aç', + settingsBottomTerminalDesc: 'Bir oturumda alt panel ilk genişletildiğinde orada yeni bir terminal sekmesi açmayı dene (terminal kotası yine geçerli; varsayılan açık)', + settingsFontFamilyTitle: 'Terminal yazı tipi ailesi', + settingsFontFamilyDesc: 'Özel terminal yazı tipi ailesi (bir CSS font-family yığını gibi "JetBrains Mono", monospace; temanın sabit genişlikli yazı tipini izlemek için boş bırakın)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: 'Terminal yazı boyutu', + settingsFontSizeDesc: 'px cinsinden terminal yazı boyutu (9–32, varsayılan 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'Kabuk yolu', + settingsShellDesc: 'Arayüz ve model terminalleri için başlatılan kabuk (mutlak yol veya yalın yürütülebilir). Boş, eski sırayı korur: yaml config.shell → $SHELL / oturum açma kabuğu / Windows powershell.exe. Sonradan açılan terminaller için geçerli', + settingsShellPlaceholder: 'ör. /bin/zsh (boş = otomatik)', + settingsShellArgsTitle: 'Kabuk bağımsız değişkenleri', + settingsShellArgsDesc: 'Açık kabuk bağımsız değişkenleri, boşlukla ayrılmış; boş olmadıklarında varsayılanları tamamen değiştirir (yaml shellArgs ile aynı sözleşme)', + settingsShellArgsPlaceholder: 'ör. -l (boş = varsayılanlar)', + settingsTabsTitle: 'Kenar çubuğu içeriği', + settingsViewersTitle: 'Dosya önizleyicileri', + settingsGeneralTitle: 'Genel', + settingsPopup: 'Özellik ayarları', + settingsViewerCatchAll: 'Hepsi yakala: herhangi bir dosya', + viewerImage: 'Resim', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: 'Kod', + viewerBinary: 'İkili indirme', + viewerHtml: 'HTML', + browser: 'Tarayıcı', + browserPlaceholder: 'Bir URL girin, örn. example.com', + browserGo: 'Git', + browserBack: 'Geri', + browserForward: 'İleri', + browserStart: 'Gezinmeye başlamak için bir URL girin (kum modu)', + browserBlockedScheme: 'Engellendi: yalnızca http/https URL’lerine izin verilir', + browserBlockedLoopback: 'Engellendi: yerel ve iç adresler burada gezilemez', + browserInvalid: 'Geçersiz URL', + browserNoSandboxWarning: 'Kum kapalı: geçerli sayfa tam arayüz ayrıcalıklarıyla çalışır (ayarlardan yeniden etkinleştirin)', + htmlNoSandboxWarning: 'Kum kapalı: bu HTML tam arayüz ayrıcalıklarıyla çalışır (ayarlardan yeniden etkinleştirin)', + sandboxStatusOn: 'Kum modu: açık · sayfalar arayüzün verilerine veya yerel dosyalara erişemez; oturum açmalar ve üçüncü taraf çerezler çalışmayabilir', + sandboxUnlock: 'Geçici olarak devre dışı bırak (güvenli değil)', + sandboxRestore: 'Kumu geri yükle', + settingsHtmlDefaultUnsafeTitle: 'HTML önizlemelerini varsayılan olarak kumsuz aç (güvenli değil)', + settingsHtmlDefaultUnsafeDesc: 'Açıkken, yeni açılan her HTML önizlemesi kumsuz durumda başlar (arayüzle aynı kaynak — oturum dosyalarını ve iç API’leri okuyabilir); durum satırı yine tek dokunuşla geri yükleme sunar', + settingsHtmlSandboxTitle: 'HTML önizleme kumunu devre dışı bırak (güvenli değil)', + settingsHtmlSandboxDesc: 'Kum kapalıyken önizlenen HTML arayüzle aynı kaynakta çalışır: oturum dosyalarını, yerel depoyu okuyabilir ve iç API’leri çağırabilir. Yalnızca tamamen güvenilen dosyalar için etkinleştirin', + settingsBrowserSandboxTitle: 'Tarayıcı kumunu devre dışı bırak (güvenli değil)', + settingsBrowserSandboxDesc: 'Kum kapalıyken ziyaret edilen her site arayüzle aynı kaynakta çalışır: oturum verilerini okuyabilir ve oturum açmış halinize bürünebilir. Yalnızca tamamen güvenilen siteler için etkinleştirin', + settingsBrowserLinksTitle: 'Sohbet dış bağlantılarını kenar çubuğunda aç', + settingsBrowserLinksDesc: 'Açıkken sohbetteki veya arayüzdeki bir dış bağlantıya tıklamak yeni pencere yerine kenar çubuğunu açar; HTTP ve HTTPS aşağıdaki anahtarlarla ayrı ayrı denetlenir; Ctrl/Cmd+tıklama her zaman atlatır', + settingsBrowserHttpTitle: 'HTTP sayfalarını kenar çubuğunda aç', + settingsBrowserHttpDesc: 'Açıkken sohbetteki veya arayüzdeki bir HTTP dış bağlantısına tıklamak kenar çubuğunu açar (urlTarget bildiren eklenti sayfaları öncelikli); Ctrl/Cmd+tıklama her zaman atlatır', + settingsBrowserHttpsTitle: 'HTTPS sayfalarını kenar çubuğunda aç', + settingsBrowserHttpsDesc: 'Açıkken sohbetteki veya arayüzdeki bir HTTPS dış bağlantısına tıklamak kenar çubuğunu açar. Varsayılan kapalı: çoğu HTTPS sitesi gömülmeyi reddeder, bu yüzden sistem tarayıcısı daha akıcı varsayılandır', + browserOpenExternal: 'Tarayıcıda aç', + browserEmbedBlocked: '{host} gömülmeyi reddetti', + browserEmbedBlockedDesc: 'Site başka sayfalar içinde gösterilmeyi yasaklıyor (X-Frame-Options / frame-ancestors), bu yüzden kenar çubuğunda yüklenemiyor. Bunun yerine doğrudan tarayıcınızda açın.', + browserEmbedAnyway: 'Yine de yükle', + subagent: 'Görevler', + openSubagent: 'Görevler', + subagentMainAgent: 'Ana aracı', + subagentEmpty: 'Alt aracı yok', + subagentEmptyDesc: 'Ana aracının altında doğan alt aracılar burada görünür', + subagentRunning: 'Çalışıyor', + subagentInactive: 'Etkin değil', + subagentModeOneShot: 'Tek seferlik', + subagentModeContinuable: 'Sürdürülebilir', + subagentCount: '{count} alt aracı', + subagentCountRunning: '{count} alt aracı · {running} çalışıyor', + subagentDiagCorrupt: 'Bozuk', + subagentDiagUnsupported: 'Desteklenmiyor', + subagentDiagUnavailable: 'Kullanılamıyor', + subagentThinking: 'Düşünüyor…', + sideChat: 'Yan sohbet (beta)', + sideChatNew: 'Yeni iş parçacığı', + sideChatUntitled: 'Yeni iş parçacığı', + sideChatEmpty: 'Yan sohbet yok', + sideChatEmptyDesc: 'Her yan sohbet sekme şeridindeki kendi sekmesidir — geçerli oturumun bağlamını miras alır ve asla ana sohbete girmez', + sideChatCreating: 'Yan sohbet oluşturuluyor…', + sideChatRetry: 'Yeniden dene', + sideChatThreads: 'İş parçacığını değiştir / yeni', + sideChatSave: 'Yeni oturum olarak kaydet', + sideChatSaveTitle: 'Bu iş parçacığını ana oturum listesinde üst düzey oturuma yükselt', + sideChatSaved: 'Yeni oturum olarak kaydedildi', + sideChatNoTurn: 'Kaydetme ilk tamamlanan turdan sonra kullanılabilir', + sideChatPendingDrop: 'Son yanıtlanmamış devam sorusu kaydedilen oturuma dahil edilmez', + sideChatFirstPlaceholder: 'İlk soruyu sorun — bağlam miras alındı…', + sideChatComposerPlaceholder: 'Devam sorusu sor…', + sideChatThinking: 'Derin dalıyor…', + sideChatThink: 'Düşünme', + sideChatInjection: 'Bağlam enjekte edildi', + sideChatSend: 'Gönder', + sideChatCancel: 'Durdur', + sideChatCancelTitle: 'Geçerli turu durdur (sıradaki iş korunur)', + sideChatClose: 'İş parçacığını kapat', + sideChatCloseTitle: 'İş parçacığının aracısını serbest bırak (geçmiş korunur)', + sideChatError: 'Yan sohbet hatası: {message}', + jobs: 'Arka plan işleri', + jobsCount: '{count} arka plan işi', + jobsCountRunning: '{count} arka plan işi · {running} çalışıyor', + jobStatusRunning: 'Çalışıyor', + jobStatusStopping: 'Durduruluyor', + jobStatusCompleted: 'Tamamlandı', + jobStatusKilled: 'Sonlandırıldı', + jobStatusFailed: 'Başarısız', + jobDurationSeconds: '{seconds} sn', + jobDurationMinutes: '{minutes} dk {seconds} sn', + jobDurationHours: '{hours} sa {minutes} dk', + jobViewOutput: 'Çıkışı görüntüle', + jobHideOutput: 'Çıkışı gizle', + jobNoOutput: 'Henüz çıkış yok', + jobNotReadYet: 'Modelin bu işin çıkışını okuması bekleniyor; model job_output çalıştırdıktan sonra çıkış burada görünür', + jobOutputTruncated: 'Çıkış kırpıldı', + jobOutputError: 'Çıkış okunamadı', + jobKill: 'Sonlandır', + jobKillConfirm: 'Sonlandırmayı onaylamak için tekrar tıklayın', + jobKillError: 'Sonlandırma başarısız', + addPluginsTabCard: 'Sekme eklentileri ekle', + addPluginsTabCardDesc: 'Yeni bir kenar çubuğu sayfası kaydet', + addPluginsViewerCard: 'Önizleme eklentileri ekle', + addPluginsViewerCardDesc: 'Yeni bir dosya türü önizlemesi kaydet', + addPluginsTabDesc: 'Kenar çubuğu sayfaları (sekmeler) eklentilerce genişletilebilir. Eklentiler ctx.betterSidebar hizmeti aracılığıyla kaydolur; Yükle’ye tıklamak kurulum komutunu kopyalar — DSH profilinizin yaşadığı bir terminale yapıştırın ve çalıştırın.', + addPluginsViewerDesc: 'Dosya önizleyicileri eklentilerce genişletilebilir. Eklentiler ctx.betterSidebar hizmeti aracılığıyla kaydolur; Yükle’ye tıklamak kurulum komutunu kopyalar — DSH profilinizin yaşadığı bir terminale yapıştırın ve çalıştırın.', + addPluginsBrowseMore: 'GitHub’da daha fazla eklentiye göz atın (topic: dsh-better-sidebar)', + addPluginsSearch: 'Eklenti adı / açıklamasına göre ara…', + addPluginsNoMatch: 'Eşleşen eklenti yok', + addPluginsRecommended: 'Önerilen eklentiler', + addPluginsEmpty: 'Henüz derlenen eklenti yok — eklentinizi GitHub topic’i altında yayınlayın', + openPlugin: 'Aç', + copyInstall: 'Kurulum komutunu kopyala', + pluginOfficeDesc: 'better-sidebar düzenleyicisi için Office üçlüsü önizlemesi (.docx / .xlsx / .pptx); ağır Office oluşturma kitaplıklarını çekirdek paketin dışında tutar, isteğe bağlı kurulur', + pluginFlowglassDesc: 'Canlı oturum akış grafiği: kullanıcı, asistan ve araç çağrıları için üç şeritli kulvar; paralel gruplar, alt aracı dalları, derinlemesine inme ve canlı durum; better-sidebar kuruluyken yerli «Flowglass» sekmesi kaydeder, kurulmadığında bağımsız çekmecesi korunur', + pluginGitForgeDesc: 'Git Forge sekmesi: GitHub/Gitea (ve diğer formlar) hesap kitaplığı + proje başına yetkiler + sıkı itme ilkesi; token’lar yalnızca yerel sırlardadır (asla model bağlamında değil); salt okunur GitForge aracı ve aracı HTTPS kimlik bilgisi yardımcısı', + pluginGitRemotesDesc: 'Git Remotes sekmesi: dal/yukarı akış/ahead-behind, fetch (isteğe bağlı prune), ff-only pull ve yalnızca sekme içi onaydan sonra push. Yerleşik Git sahnele/işle sekmesini değiştirmez; force-push veya model otomatik push aracı sunmaz', + pluginSentinelDesc: 'Koşul odaklı aracı uyandırma: dosya/süreç/port/HTTP/komut/web algılayıcılar koşullar tetiklendiğinde uyuyan oturumları uyandırır; sunucu geneli izleme tablosuyla «Sentinel» sekmesi kaydeder', + pluginSidebarQaDesc: 'Seç ve sor: Sohbet metnini seç → sağ panelde sor → aynı çalışma alanında özel devam oturumu (❓devam·konu): hızlı bir düşünmesiz model ana bağlamı sıkıştırıp alıntıyla birlikte enjekte eder, ana sohbeti bölmez. Devam soruları iç içe geçer, sürdürülebilir ve arşivlenebilir', + pluginSshTunnelDesc: 'SSH Tunnel sekmesi: çok ana makinelik envanter + proje başına yetkiler + yerel sır saklama; SSHManager aracı (exec/SFTP/oturum stratejileri); merkez etkileşimli terminal ve çift panelli SFTP', + pluginTurnReviewDesc: 'Az önce biten turun diff’i için Approve / Request changes insan kapısı: yalnızca son turu inceler, oturumu çatallamaz; dosyalar ana oturum / alt aracı / atfedilmemiş olarak gruplanır, dosya başına işaretle geri çevir + isteğe bağlı yorum, dosyaya tıklayınca tur başlangıcı anlık görüntüsü ile şimdiki diff gösterilir. /rewind değil', + pluginVideoPreviewDesc: 'better-sidebar düzenleyicisinde satır içi video önizlemesi (.mp4/.webm/.mov/.mkv/.avi vb.); HTTP Range (206) destekli özel /video sunucu rotasıyla — ilerleme çubuğu sürükleme çalışır ve 20MB mediaLimit ile sınırlanmaz', + pluginDocsPanelDesc: 'DSH kenar çubuğunda «Genel belgeler»: herhangi bir çalışma alanından kendi Markdown notlarınızı okuyun — dosya listesi, ana hat, Chrome / VS Code’da açma ve kopyalama düğmeleri; belgeler dizini yapılandırılabilir (varsayılan ~/.dsh/docs)', +} diff --git a/src/client/locales-vi.ts b/src/client/locales-vi.ts new file mode 100644 index 0000000..5bdfbee --- /dev/null +++ b/src/client/locales-vi.ts @@ -0,0 +1,345 @@ +/** + * The vi (Vietnamese) dictionary for the betterSidebar namespace. + * + * Mirrors the key set of `zh` in `locales.ts`. The sidebar's `t()` + * consults this dict when `attachBetterLocale(store)` has been called + * with an active better-locale store whose `active` is `'vi'`; absent + * that, the existing zh/en chain runs unchanged. + * + * Translation conventions: + * - Technical terms stay in English where appropriate (Git, SSH, HTTP, URL, + * Markdown, PDF, VS Code, API Key, Base URL, token, etc.). + * - Placeholders keep {name} verbatim (interpolation runs after lookup). + * - Formal Vietnamese appropriate for software UI. + * - Terminology is kept consistent with the DSH core vi dictionary. + */ + +/** The vi dictionary (key-set-equal to zh, enforced by the type annotation in locales.ts). */ +export const vi: Record = { + files: 'Tệp', + explorer: 'Trình khám phá', + git: 'Quản lý mã nguồn', + terminal: 'Terminal', + editor: 'Trình soạn thảo', + editorExplorer: 'Cách mở tệp', + editorExplorerDesc: 'Kiểm soát cách mở tệp', + editorExplorerMerged: 'Gộp', + editorExplorerMergedDesc: 'Tệp chuyển tại chỗ trong cùng cửa sổ; cửa sổ mới mặc định mở cây tệp', + editorExplorerSplit: 'Riêng biệt', + editorExplorerSplitDesc: 'Cửa sổ không đường dẫn là trình khám phá (chỉ cây tệp); mỗi tệp mở cửa sổ riêng (có cây tệp, mặc định thu gọn)', + editorTreeToggle: 'Panel cây tệp', + editorPathPlaceholder: 'Nhập đường dẫn tệp (tương đối thư mục phiên hoặc tuyệt đối), Enter để mở', + editorSearchPlaceholder: 'Tìm theo tên tệp…', + editorSearchNoResults: 'Không có tệp phù hợp', + editorSearchTruncated: 'Quá nhiều kết quả, chỉ hiển thị một phần', + editorEmptyHint: 'Chọn tệp từ cây tệp bên phải hoặc ô nhập đường dẫn phía trên để xem trước', + openFileNewTab: 'Mở trong Tab mới', + openFileSide: 'Mở ở bên cạnh', + openWithMenu: 'Mở bằng', + openWithSshSuffix: ' (SSH)', + pinOpenWith: 'Ghim vào menu', + unpinOpenWith: 'Bỏ ghim', + openWithExplorer: 'Trình quản lý tệp', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'Máy chủ từ xa SSH', + openWithSettingsSshDesc: 'Để trống cho không gian làm việc cục bộ; nhập user@host hoặc alias SSH, các trình mở họ VSCode sẽ chuyển sang giao thức vscode-remote/ssh-remote, Trình quản lý tệp / Zed / trình soạn thảo tùy chỉnh không phải VSCode sẽ ẩn khỏi menu', + openWithSettingsSshPlaceholder: 'user@host hoặc alias SSH', + openWithSettingsCustomTitle: 'Trình soạn thảo tùy chỉnh', + openWithSettingsCustomDesc: 'Tên + mẫu URL (placeholder {path}) + cờ họ VSCode; ở chế độ SSH chỉ họ VSCode mở được đường dẫn từ xa', + openWithSettingsAdd: 'Thêm', + openWithSettingsName: 'Tên', + openWithSettingsTemplate: 'vd: cursor://file/{path}', + openWithSettingsFamily: 'Họ VSCode', + openWithSettingsFamilyDesc: 'Trình soạn thảo này dùng giao thức URL của VSCode (hỗ trợ mở từ xa qua SSH)', + openWithSettingsRemove: 'Xóa', + openWithSettingsInvalidHint: 'Trình soạn thảo thiếu tên hoặc mẫu (cần chứa {path} và bắt đầu bằng scheme://) sẽ không xuất hiện trong menu', + newTab: 'Tab mới', + openExplorer: 'Trình khám phá', + brokenSymlink: 'Symlink hỏng', + openGit: 'Panel Git', + newTerminal: 'Terminal mới', + terminalLimit: 'Đã đạt giới hạn terminal (3)', + close: 'Đóng', + closeOtherTabs: 'Đóng các tab khác', + closeLeftTabs: 'Đóng tab bên trái', + closeRightTabs: 'Đóng tab bên phải', + collapse: 'Thu gọn thanh bên', + expand: 'Mở rộng thanh bên', + collapseBottomPanel: 'Thu gọn panel dưới', + expandBottomPanel: 'Mở rộng panel dưới', + terminalError: 'Kết nối terminal thất bại', + terminalConnectFailed: 'Terminal kết nối thất bại nhiều lần', + terminalRetry: 'Thử lại', + terminalDepsFailed: 'Dependency terminal node-pty tải thất bại', + terminalDepsHint: 'Chạy lệnh sau trong terminal hoặc cmd trên máy DSH để sửa, rồi nhấn thử lại (node-pty đồng bộ phiên bản với lõi DSH):', + terminalDepsProfile: ' (phát hiện profile: {profile})', + preview: 'Xem trước', + edit: 'Chỉnh sửa', + mermaidError: 'Render Mermaid thất bại', + mermaidZoomIn: 'Phóng to', + mermaidZoomOut: 'Thu nhỏ', + mermaidZoomReset: 'Đặt lại', + mermaidZoomHint: 'Cuộn để zoom · kéo để di chuyển · Esc để đóng', + refresh: 'Làm mới', + save: 'Lưu', + saved: 'Đã lưu', + unsaved: 'Chưa lưu', + saveFailed: 'Lưu thất bại', + truncation: 'Tệp quá lớn, chỉ hiển thị 512KB đầu', + binary: 'Tệp nhị phân, không xem trước được', + loading: 'Đang tải…', + error: 'Tải thất bại', + retry: 'Thử lại', + splitLeft: 'Chia bên trái', + splitRight: 'Chia bên phải', + splitUp: 'Chia lên trên', + splitDown: 'Chia xuống dưới', + notRepo: 'Thư mục hiện tại không phải repo git', + noChanges: 'Không có thay đổi', + stage: 'Stage', + unstage: 'Unstage', + stageAll: 'Stage tất cả', + unstageAll: 'Unstage tất cả', + commitPlaceholder: 'Thông điệp commit (Ctrl+Enter)', + commit: 'Commit', + commitError: 'Commit thất bại', + branch: 'Branch', + checkoutError: 'Chuyển branch thất bại', + history: 'Lịch sử', + changes: 'Thay đổi', + staged: 'Đã stage', + unstaged: 'Chưa stage', + cancel: 'Hủy', + diffEmpty: 'Không có khác biệt văn bản', + diffLoadError: 'Tải diff thất bại', + diffBinary: 'Nhị phân', + diffAdded: 'Thêm', + diffDeleted: 'Xóa', + diffRenamed: 'Đổi tên', + diffExpand: 'Mở rộng {count} dòng còn lại', + diffCollapse: 'Thu gọn', + discard: 'Bỏ thay đổi', + discardTitle: 'Bỏ thay đổi', + discardDesc: 'Sẽ hủy các thay đổi worktree của «{path}» (không thể khôi phục).', + viewCommitDiff: 'Xem diff commit', + copyShortHash: 'Sao chép hash ngắn', + copyFullHash: 'Sao chép hash đầy đủ', + copySubject: 'Sao chép thông điệp commit', + revertCommit: 'Revert commit', + revertTitle: 'Revert commit', + revertDesc: 'Sẽ tạo commit mới trên branch hiện tại đảo ngược «{subject}».', + cherryPickCommit: 'Cherry-pick commit', + cherryPickTitle: 'Cherry-pick commit', + cherryPickDesc: 'Áp dụng các thay đổi của «{subject}» lên branch hiện tại.', + timeJustNow: 'vừa xong', + timeMinutesAgo: '{n} phút trước', + timeHoursAgo: '{n} giờ trước', + timeYesterday: 'hôm qua', + loadMore: 'Tải thêm', + historyLoadError: 'Tải thêm lịch sử thất bại', + produced: 'Đã tạo', + producedOpen: 'Mở trong thanh bên', + disconnected: 'Terminal mất kết nối, đang kết nối lại…', + exited: 'Tiến trình terminal đã thoát', + noSession: 'Chọn một phiên để dùng thanh bên', + pluginNotLoaded: 'Plugin chưa tải, tab tạm không khả dụng:', + hiddenFiles: 'Tệp ẩn', + parent: 'Thư mục cha', + copied: 'Đã sao chép', + copy: 'Sao chép', + newFile: 'Tệp mới', + openEditor: 'Mở trình soạn thảo', + gitDetail: 'Xem chi tiết thay đổi', + referenceFile: '@tệp', + addToConversation: 'Thêm vào cuộc trò chuyện', + copyRelative: 'Sao chép đường dẫn tương đối', + copyAbsolute: 'Sao chép đường dẫn tuyệt đối', + download: 'Tải xuống', + uploadFiles: 'Tải tệp lên', + uploadFolder: 'Tải thư mục lên', + uploadHere: 'Tải lên đây', + uploadDropHint: 'Kéo tệp/thư mục vào đây để tải lên', + uploadDropChat: 'Kéo vào khu vực chat: thêm hình ảnh vào cuộc trò chuyện', + uploadTo: 'Tải lên {dir}', + uploadingTo: 'Đang tải lên {dir}…', + uploadProgress: 'Đang tải lên {done}/{total}: {name}', + uploadDone: 'Đã tải lên {count} tệp', + uploadFailed: 'Tải lên thất bại: {error}', + uploadFailedUnknown: 'Lỗi không xác định', + uploadTooLarge: 'Tệp quá lớn, vượt giới hạn tải lên', + uploadCancelled: 'Đã hủy tải lên', + settingsNav: 'Thẻ bên', + settingsIntro: 'Quản lý nội dung hiển thị và hành vi mặc định của thẻ bên', + settingsPopupDesc: 'Cấu hình tùy chọn cho «{feature}»', + settingsDone: 'Xong', + settingsOpenTitle: 'Mở mặc định cho phiên mới', + settingsOpenDesc: 'Tự động mở rộng thẻ bên cho phiên mới; phiên đã có giữ nguyên bố cục', + settingsWidthTitle: 'Tỷ lệ chiều rộng mặc định', + settingsWidthDesc: 'Tỷ lệ phần trăm chiều rộng cửa sổ mà thẻ bên chiếm cho phiên mới (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: 'Mở tệp chat trong thanh bên', + settingsOpenPathDesc: 'Khi nhấp link tệp trong chat (dòng công cụ, danh sách sản phẩm, nhắc tệp), mở trong trình soạn thảo thanh bên thay vì ứng dụng mặc định hệ thống', + settingsTitleBarTitle: 'Chế độ tương thích thanh tiêu đề', + settingsTitleBarDesc: 'Chọn phương án tương thích thanh tiêu đề: tự động phát hiện (mặc định, bảo thủ) / Web DSH chính thức / shell desktop đã biết / tùy chỉnh (khoảng dịch chuyển + CSS tùy chỉnh)', + settingsTitleBarStripTitle: 'Khoảng dịch chuyển', + settingsTitleBarStripDesc: 'Chiều cao dải thanh tiêu đề: số pixel dịch xuống của nút và nội dung thanh bên (0–120, mặc định 40; áp dụng trong chế độ tùy chỉnh)', + settingsSchemeAutoTitle: 'Tự động phát hiện', + settingsSchemeAutoDesc: 'Bảo thủ: chỉ nhường chỗ theo chiều cao thanh tiêu đề thật khi API Window Controls Overlay chuẩn khả dụng; môi trường web thuần không sửa gì', + settingsSchemeWebTitle: 'Web DSH chính thức', + settingsSchemeWebDesc: 'Khai báo tường minh chạy trên web chính thức: không điều chỉnh gì cả (kể cả hình học WCO chuẩn)', + settingsSchemeCustomTitle: 'Tùy chỉnh', + settingsSchemeCustomDesc: 'Toàn quyền kiểm soát: chèn CSS tùy chỉnh (có thể ghi đè style built-in), và chỉ định khoảng dịch chuyển thanh tiêu đề', + settingsSchemeDetectedSuffix: 'đã phát hiện', + settingsCustomCssTitle: 'CSS tùy chỉnh', + settingsCustomCssDesc: 'Style追加 vào cuối trang (cùng ưu tiên thì viết sau thắng; ghi đè biến inline JS cần !important)', + settingsCustomCssPlaceholder: '/* vd: dành sẵn 36px cho shell tự vẽ thanh tiêu đề */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: 'Lưu thất bại', + settingsConflict: 'Cài đặt đã bị sửa bởi cửa sổ khác, vui lòng thử lại', + binaryNoPreview: 'Loại tệp này không hỗ trợ xem trước', + downloadToView: 'Tải xuống để xem', + settingsSubagentTitle: 'Tự động mở trang Quản lý tác vụ khi phát hiện tác nhân con', + settingsSubagentDesc: 'Khi phiên hiện tại tạo tác nhân con mới, tự động mở rộng thanh bên và mở trang Quản lý tác vụ; tắt thì phải mở thủ công', + settingsJobsTitle: 'Tự động mở trang Tác vụ nền khi có tác vụ nền mới', + settingsJobsDesc: 'Khi phiên hiện tại có tác vụ nền mới, tự động mở rộng thanh bên và mở trang Tác vụ nền (mỗi tác vụ mới đều kích hoạt); tắt thì phải mở thủ công', + settingsToolsTitle: 'Tiêm công cụ terminal cho mô hình', + settingsToolsDesc: 'Khi bật, mô hình có thể tạo và điều khiển terminal thanh bên qua 8 công cụ terminal_* (mặc định tắt)', + settingsBottomTerminalTitle: 'Tự động mở terminal khi panel dưới mở rộng lần đầu', + settingsBottomTerminalDesc: 'Khi panel dưới được mở rộng lần đầu trong phiên, thử mở một tab terminal mới ở panel dưới (giới hạn terminal vẫn áp dụng; mặc định bật)', + settingsFontFamilyTitle: 'Font terminal', + settingsFontFamilyDesc: 'Font terminal tùy chỉnh (CSS font-family, vd: "JetBrains Mono", monospace; để trống theo font mono của theme)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: 'Cỡ chữ terminal', + settingsFontSizeDesc: 'Cỡ chữ terminal (9–32, mặc định 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'Đường dẫn shell', + settingsShellDesc: 'Shell khởi động cho terminal UI và mô hình (đường dẫn tuyệt đối hoặc tên thực thi). Để trống sẽ phân tích theo thứ tự: yaml config.shell → $SHELL / login shell / powershell.exe trên Windows. Áp dụng cho terminal mở sau đó', + settingsShellPlaceholder: 'vd: /bin/zsh (để trống = tự động)', + settingsShellArgsTitle: 'Tham số shell', + settingsShellArgsDesc: 'Tham số shell tường minh, phân tách bằng dấu cách; khi không trống sẽ thay thế hoàn toàn mặc định (đồng bộ với contract shellArgs yaml)', + settingsShellArgsPlaceholder: 'vd: -l (để trống = mặc định)', + settingsTabsTitle: 'Nội dung thanh bên', + settingsViewersTitle: 'Trình xem tệp', + settingsGeneralTitle: 'Chung', + settingsPopup: 'Cài đặt tính năng', + settingsViewerCatchAll: 'Catch-all: mọi tệp', + viewerImage: 'Hình ảnh', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: 'Mã', + viewerBinary: 'Tải nhị phân', + viewerHtml: 'HTML', + browser: 'Trình duyệt', + browserPlaceholder: 'Nhập URL, vd: example.com', + browserGo: 'Đi', + browserBack: 'Lùi', + browserForward: 'Tiến', + browserStart: 'Nhập URL để bắt đầu duyệt (chế độ sandbox)', + browserBlockedScheme: 'Đã chặn: chỉ cho phép link http/https', + browserBlockedLoopback: 'Đã chặn: không cho phép truy cập địa chỉ cục bộ hoặc nội bộ trong trình duyệt', + browserInvalid: 'URL không hợp lệ', + browserNoSandboxWarning: 'Sandbox đã tắt: trang hiện tại cùng nguồn với UI, có toàn quyền phiên (có thể bật lại trong cài đặt)', + htmlNoSandboxWarning: 'Sandbox đã tắt: HTML này cùng nguồn với UI, có thể đọc tệp phiên và API nội bộ (có thể bật lại trong cài đặt)', + sandboxStatusOn: 'Chế độ sandbox: đã bật · trang không thể truy cập dữ liệu UI và tệp cục bộ, đăng nhập và cookie bên thứ ba có thể không hoạt động', + sandboxUnlock: 'Mở khóa tạm (không an toàn)', + sandboxRestore: 'Khôi phục sandbox', + settingsHtmlDefaultUnsafeTitle: 'Mở xem trước HTML không sandbox mặc định (không an toàn)', + settingsHtmlDefaultUnsafeDesc: 'Khi bật, mỗi lần mở tệp HTML xem trước sẽ mặc định không sandbox (cùng nguồn UI, có thể đọc tệp phiên và API nội bộ); có thể khôi phục sandbox tạm thời trên thanh trạng thái', + settingsHtmlSandboxTitle: 'Tắt sandbox xem trước HTML (không an toàn)', + settingsHtmlSandboxDesc: 'Khi tắt, HTML xem trước sẽ chạy cùng nguồn với UI: có thể đọc tệp phiên, local storage và gọi API nội bộ. Chỉ bật cho tệp hoàn toàn đáng tin cậy', + settingsBrowserSandboxTitle: 'Tắt sandbox trình duyệt (không an toàn)', + settingsBrowserSandboxDesc: 'Khi tắt, mọi trang truy cập sẽ chạy cùng nguồn với UI: có thể đọc dữ liệu phiên và mạo danh phiên đăng nhập. Chỉ bật cho trang hoàn toàn đáng tin cậy', + settingsBrowserLinksTitle: 'Mở link ngoài trong chat ở thanh bên', + settingsBrowserLinksDesc: 'Khi bật, nhấp link ngoài trong chat hoặc UI sẽ mở trong thanh bên thay vì cửa sổ mới; HTTP và HTTPS được kiểm soát riêng bởi công tắc bên dưới; Ctrl/Cmd+nhấp luôn bỏ qua', + settingsBrowserHttpTitle: 'Mở trang HTTP trong thanh bên', + settingsBrowserHttpDesc: 'Khi bật, nhấp link HTTP ngoài trong chat hoặc UI sẽ mở trong thanh bên (trang plugin khai báo urlTarget ưu tiên); Ctrl/Cmd+nhấp luôn bỏ qua', + settingsBrowserHttpsTitle: 'Mở trang HTTPS trong thanh bên', + settingsBrowserHttpsDesc: 'Khi bật, nhấp link HTTPS ngoài trong chat hoặc UI sẽ mở trong thanh bên. Mặc định tắt: đa số trang HTTPS từ chối nhúng, trình duyệt hệ thống mượt mà hơn', + browserOpenExternal: 'Mở trong trình duyệt', + browserEmbedBlocked: '{host} từ chối nhúng', + browserEmbedBlockedDesc: 'Trang này cấm hiển thị trong trang khác qua X-Frame-Options / frame-ancestors, không thể tải trong thanh bên. Mở trực tiếp trong trình duyệt', + browserEmbedAnyway: 'Vẫn tải', + subagent: 'Quản lý tác vụ', + openSubagent: 'Quản lý tác vụ', + subagentMainAgent: 'Tác nhân chính', + subagentEmpty: 'Không có tác nhân con', + subagentEmptyDesc: 'Tác nhân con do tác nhân chính tạo ra sẽ hiển thị ở đây', + subagentRunning: 'Đang chạy', + subagentInactive: 'Nghỉ', + subagentModeOneShot: 'Một lần', + subagentModeContinuable: 'Có thể tiếp tục', + subagentCount: '{count} tác nhân con', + subagentCountRunning: '{count} tác nhân con · {running} đang chạy', + subagentDiagCorrupt: 'Bị hỏng', + subagentDiagUnsupported: 'Không hỗ trợ', + subagentDiagUnavailable: 'Không khả dụng', + subagentThinking: 'Đang suy nghĩ…', + sideChat: 'Chat bên (beta)', + sideChatNew: 'Luồng mới', + sideChatUntitled: 'Luồng mới', + sideChatEmpty: 'Không có cuộc trò chuyện bên', + sideChatEmptyDesc: 'Mỗi cuộc trò chuyện bên là một Tab riêng trong thanh tab, kế thừa ngữ cảnh phiên hiện tại, không vào phiên chính', + sideChatCreating: 'Đang tạo cuộc trò chuyện bên…', + sideChatRetry: 'Thử lại', + sideChatThreads: 'Chuyển luồng / mới', + sideChatSave: 'Lưu thành phiên mới', + sideChatSaveTitle: 'Nâng luồng này thành phiên cấp cao nhất, xuất hiện trong danh sách phiên chính', + sideChatSaved: 'Đã lưu thành phiên mới', + sideChatNoTurn: 'Cần hoàn thành ít nhất một vòng trò chuyện trước khi lưu', + sideChatPendingDrop: 'Tin nhắn theo dõi chưa hoàn thành cuối cùng sẽ không được đưa vào phiên đã lưu', + sideChatFirstPlaceholder: 'Hỏi câu đầu tiên — ngữ cảnh đã kế thừa…', + sideChatComposerPlaceholder: 'Hỏi tiếp…', + sideChatThinking: 'Đang đào sâu…', + sideChatThink: 'Suy nghĩ', + sideChatInjection: 'Đã tiêm ngữ cảnh', + sideChatSend: 'Gửi', + sideChatCancel: 'Dừng', + sideChatCancelTitle: 'Hủy vòng hiện tại (giữ hàng đợi)', + sideChatClose: 'Đóng luồng', + sideChatCloseTitle: 'Giải phóng agent của luồng (lịch sử được giữ)', + sideChatError: 'Lỗi chat bên: {message}', + jobs: 'Tác vụ nền', + jobsCount: '{count} tác vụ nền', + jobsCountRunning: '{count} tác vụ nền · {running} đang chạy', + jobStatusRunning: 'Đang chạy', + jobStatusStopping: 'Đang dừng', + jobStatusCompleted: 'Đã hoàn thành', + jobStatusKilled: 'Đã hủy', + jobStatusFailed: 'Thất bại', + jobDurationSeconds: '{seconds}s', + jobDurationMinutes: '{minutes}m {seconds}s', + jobDurationHours: '{hours}h {minutes}m', + jobViewOutput: 'Xem đầu ra', + jobHideOutput: 'Ẩn đầu ra', + jobNoOutput: 'Chưa có đầu ra', + jobNotReadYet: 'Đang chờ mô hình đọc đầu ra tác vụ này (sau khi mô hình chạy job_output, đầu ra sẽ hiển thị ở đây)', + jobOutputTruncated: 'Đầu ra quá dài, đã cắt bớt', + jobOutputError: 'Đọc đầu ra thất bại', + jobKill: 'Hủy', + jobKillConfirm: 'Nhấp lại để xác nhận hủy', + jobKillError: 'Hủy thất bại', + addPluginsTabCard: 'Thêm plugin tab', + addPluginsTabCardDesc: 'Đăng ký trang thanh bên mới', + addPluginsViewerCard: 'Thêm plugin xem trước', + addPluginsViewerCardDesc: 'Đăng ký xem trước loại tệp mới', + addPluginsTabDesc: 'Trang thanh bên (tab) có thể mở rộng qua plugin. Plugin đăng ký qua service ctx.betterSidebar; nhấp «Cài đặt» để sao chép lệnh cài, dán vào terminal nơi DSH chạy rồi thực thi.', + addPluginsViewerDesc: 'Trình xem tệp có thể mở rộng qua plugin. Plugin đăng ký qua service ctx.betterSidebar; nhấp «Cài đặt» để sao chép lệnh cài, dán vào terminal nơi DSH chạy rồi thực thi.', + addPluginsBrowseMore: 'Duyệt thêm plugin trên GitHub (topic: dsh-better-sidebar)', + addPluginsSearch: 'Tìm theo tên / mô tả plugin…', + addPluginsNoMatch: 'Không có plugin phù hợp', + addPluginsRecommended: 'Plugin đề xuất', + addPluginsEmpty: 'Chưa có plugin nào, hoan nghênh bạn publish plugin dưới GitHub topic', + openPlugin: 'Mở', + copyInstall: 'Sao chép lệnh cài', + pluginOfficeDesc: 'Xem trước bộ Office (.docx / .xlsx / .pptx) cho trình soạn thảo better-sidebar, tách thư viện render Office nặng ra khỏi bundle chính, cài theo nhu cầu', + pluginFlowglassDesc: 'Biểu đồ luồng phiên theo thời gian thực: ba lane cho user, assistant và tool call, hỗ trợ nhóm song song, nhánh tác nhân con, drill-down từng lớp và trạng thái trực tiếp; sau khi cài better-sidebar đăng ký tab «Flowglass» native, khi chưa cài giữ drawer riêng', + pluginGitForgeDesc: 'Tab «Git Forge» của better-sidebar: kho tài khoản GitHub/Gitea và Forge khác + cấp quyền theo project + chặn cứng chính sách push; token chỉ lưu secrets cục bộ, không vào ngữ cảnh mô hình; cung cấp công cụ GitForge chỉ đọc và HTTPS credential helper cho agent', + pluginGitRemotesDesc: 'Tab Git Remotes của better-sidebar: xem branch/upstream/ahead-behind, fetch (có thể prune), pull ff-only, push chỉ sau khi xác nhận trong tab. Không thay thế tab stage/commit Git built-in, cũng không cung cấp force-push hay công cụ auto-push cho mô hình', + pluginSentinelDesc: 'Hệ thống đánh thức agent theo điều kiện: cảm biến file/process/port/HTTP/command/webhook, khi điều kiện đạt sẽ tự đánh thức phiên ngủ; đăng ký tab «Sentinel» hiển thị bảng giám sát toàn server', + pluginSidebarQaDesc: 'Tab chọn-đoạn-hỏi dựa trên better-sidebar: chọn văn bản trò chuyện → hỏi ở panel phải → phiên theo dõi riêng trong cùng workspace (❓ theo dõi · chủ đề): mô hình nhanh không suy nghĩ nén ngữ cảnh chat chính rồi tiêm cùng trích dẫn, không gián đoạn chat chính; theo dõi có thể lồng nhau, tiếp tục, lưu trữ', + pluginSshTunnelDesc: 'Tab «SSH Tunnel» của better-sidebar: danh sách máy đa host + cấp quyền theo project + khóa lưu cục bộ; công cụ mô hình SSHManager (exec/SFTP/chiến lược phiên); terminal tương tác trung tâm và SFTP hai pane', + pluginTurnReviewDesc: 'Cổng duyệt người cho diff «vừa rồi»: Approve / Request changes theo path kèm comment tùy chọn; path nhóm theo phiên chính / tác nhân con / không rõ nguồn; nhấp file xem diff snapshot đầu vòng vs hiện tại. Không fork, không /rewind', + pluginVideoPreviewDesc: 'Xem trước video inline trong trình soạn thảo better-sidebar (.mp4/.webm/.mov/.mkv/.avi v.v.), có route host /video hỗ trợ HTTP Range (206), có thể tua tiến độ, không bị giới hạn mediaLimit 20MB', + pluginDocsPanelDesc: '«Tài liệu toàn cục» trong thanh bên DSH: ghi chú Markdown toàn cục, đọc từ bất kỳ workspace nào — danh sách chọn để đọc, outline hover để nhảy, mở ngoài trong Chrome / VS Code, sao chép code, thư mục cấu hình được (mặc định ~/.dsh/docs)', +} diff --git a/src/client/locales-zh-HK.ts b/src/client/locales-zh-HK.ts new file mode 100644 index 0000000..2dabfbb --- /dev/null +++ b/src/client/locales-zh-HK.ts @@ -0,0 +1,360 @@ +/** + * The zh-HK (Traditional Chinese — Hong Kong) dictionary for the betterSidebar + * namespace. + * + * Mirrors the key set of `zh` in `locales.ts`. Consumed by better-locale's + * override store when the active override id is `'zh-HK'` (registered under + * the `betterSidebar` namespace). Absent that, the existing zh/en chain + * runs unchanged. + * + * Hong Kong regional conventions: + * - 软件 → 軟件 (NOT 軟體); 网络 → 網絡 (NOT 網路); 鼠标 → 滑鼠 + * - 檔案 (file), 資料夾 (folder), 程式 (program), 程式碼 (code), 螢幕 (screen) + * - 預設 (default), 儲存 (save), 設定 (settings/config), 唯讀 (read-only) + * - 資源管理器 → 檔案總管; refresh → 重新整理; cache → 快取 + * - timeout → 逾時; loop → 迴圈; override → 覆寫; built-in → 內建 + * - adapter → 介面卡; interface → 介面; address → 位址; field → 欄位 + * - byte → 位元組; binary → 二進位; character → 字元; hash → 雜湊 + * - rename → 重新命名; archive → 歸檔; idle → 閒置; mount → 掛載 + * - package → 套件; generate → 產生; fetch → 取得; export → 匯出 + * - login → 登入; detect → 偵測; block → 封鎖; access → 存取 + * - port → 連接埠; sensor → 感測器; server → 伺服器; global → 全域 + * - nested → 巢狀; thread → 執行緒; queue → 佇列; tab → 標籤 + * - source code → 原始碼; symlink → 符號連結; recover → 復原 + * - placeholder → 佔位符; template → 範本; variable → 變數 + * - through → 透過; paste → 貼上; project → 專案; account → 帳號 + * - session (会话) → 工作階段; chat (对话) → 對話 + * - quotation marks: "" → 「」 + * - Placeholders keep `{name}` verbatim (interpolation runs after lookup). + * - English brand names (VS Code, Cursor, Zed, SSH, Git, Chrome) stay as-is. + */ + +/** The zh-HK dictionary (key-set-equal to zh, enforced by the type annotation in locales.ts). */ +export const zhHK: Record = { + files: '檔案', + explorer: '檔案總管', + git: '原始碼管理', + terminal: '終端', + editor: '編輯器', + editorExplorer: '檔案開啟方式', + editorExplorerDesc: '控制檔案開啟方式', + editorExplorerMerged: '合併', + editorExplorerMergedDesc: '檔案在同一視窗內原地切換;新視窗預設展開檔案樹', + editorExplorerSplit: '獨立', + editorExplorerSplitDesc: '無路徑視窗即檔案總管(僅檔案樹);檔案各自新開視窗(帶檔案樹,預設收起)', + editorTreeToggle: '檔案樹面板', + editorPathPlaceholder: '輸入檔案路徑(相對工作階段目錄或絕對路徑),Enter 開啟', + editorSearchPlaceholder: '按檔案名稱搜尋…', + editorSearchNoResults: '無匹配檔案', + editorSearchTruncated: '結果過多,僅顯示部分匹配', + editorEmptyHint: '從右側檔案樹或上方路徑輸入框選擇檔案開始預覽', + openFileNewTab: '在新 Tab 中開啟', + openFileSide: '在側邊開啟', + openWithMenu: '在應用程式中開啟', + openWithSshSuffix: ' (SSH)', + pinOpenWith: '固定到選單', + unpinOpenWith: '取消固定', + openWithExplorer: '檔案總管', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'SSH 遠端主機', + openWithSettingsSshDesc: '留空為本地工作區;填入 user@host 或 SSH 別名後,VSCode 系開啟方式將改用 vscode-remote/ssh-remote 協議,檔案總管 / Zed / 非 VSCode 系自訂編輯器將從選單隱藏', + openWithSettingsSshPlaceholder: 'user@host 或 SSH 別名', + openWithSettingsCustomTitle: '自訂編輯器', + openWithSettingsCustomDesc: '名稱 + URL 範本({path} 佔位符)+ 是否 VSCode 系;SSH 模式下僅 VSCode 系可開啟遠端', + openWithSettingsAdd: '新增', + openWithSettingsName: '名稱', + openWithSettingsTemplate: '如 cursor://file/{path}', + openWithSettingsFamily: 'VSCode 系', + openWithSettingsFamilyDesc: '該編輯器使用 VSCode 的 URL 協議(支援 SSH 遠端開啟)', + openWithSettingsRemove: '刪除', + openWithSettingsInvalidHint: '名稱或範本(需含 {path} 且以 scheme:// 開頭)未填寫的編輯器不會出現在選單中', + newTab: '新增標籤', + openExplorer: '檔案總管', + brokenSymlink: '失效的符號連結', + openGit: 'Git 面板', + newTerminal: '新終端', + terminalLimit: '終端數量已達上限 (3)', + close: '關閉', + closeOtherTabs: '關閉其他標籤', + closeLeftTabs: '關閉左側標籤', + closeRightTabs: '關閉右側標籤', + collapse: '收起側邊欄', + expand: '展開側邊欄', + collapseBottomPanel: '收起底部面板', + expandBottomPanel: '展開底部面板', + terminalError: '終端連線失敗', + terminalConnectFailed: '終端多次連線失敗', + terminalRetry: '重試', + terminalDepsFailed: '終端依賴 node-pty 載入失敗', + terminalDepsHint: '在 DSH 所在環境的終端或 cmd 中執行以下命令修復,然後點重試(node-pty 與 DSH 核心保持同一版本):', + terminalDepsProfile: '(偵測到 profile:{profile})', + preview: '預覽', + edit: '編輯', + mermaidError: 'Mermaid 渲染失敗', + mermaidZoomIn: '放大', + mermaidZoomOut: '縮小', + mermaidZoomReset: '重設', + mermaidZoomHint: '滾輪縮放 · 拖曳平移 · Esc 關閉', + refresh: '重新整理', + save: '儲存', + saved: '已儲存', + unsaved: '未儲存', + saveFailed: '儲存失敗', + truncation: '檔案過大,僅顯示前 512KB', + binary: '二進位檔案,無法預覽', + loading: '載入中…', + error: '載入失敗', + retry: '重試', + splitLeft: '向左分欄', + splitRight: '向右分欄', + splitUp: '向上分欄', + splitDown: '向下分欄', + notRepo: '目前目錄不是 git 倉庫', + noChanges: '沒有變更', + stage: '暫存', + unstage: '取消暫存', + stageAll: '全部暫存', + unstageAll: '全部取消暫存', + commitPlaceholder: '提交訊息 (Ctrl+Enter)', + commit: '提交', + commitError: '提交失敗', + branch: '分支', + checkoutError: '切換分支失敗', + history: '歷史', + changes: '變更', + staged: '已暫存', + unstaged: '未暫存', + cancel: '取消', + diffEmpty: '沒有文字差異', + diffLoadError: '載入差異失敗', + diffBinary: '二進位', + diffAdded: '新增', + diffDeleted: '刪除', + diffRenamed: '重新命名', + diffExpand: '展開其餘 {count} 行', + diffCollapse: '收起', + discard: '放棄變更', + discardTitle: '放棄變更', + discardDesc: '將丟棄「{path}」的工作區修改(不可復原)。', + viewCommitDiff: '檢視提交差異', + copyShortHash: '複製短雜湊', + copyFullHash: '複製完整雜湊', + copySubject: '複製提交訊息', + revertCommit: '還原此提交', + revertTitle: '還原此提交', + revertDesc: '將在目前分支建立一個反轉「{subject}」的新提交。', + cherryPickCommit: '撿取此提交', + cherryPickTitle: '撿取此提交', + cherryPickDesc: '將「{subject}」的變更套用到目前分支。', + timeJustNow: '剛剛', + timeMinutesAgo: '{n} 分鐘前', + timeHoursAgo: '{n} 小時前', + timeYesterday: '昨天', + loadMore: '載入更多', + historyLoadError: '載入更多歷史失敗', + produced: '本次產出', + producedOpen: '在側邊欄中開啟', + disconnected: '終端連線斷開,重新連線中…', + exited: '終端程序已退出', + noSession: '選擇一個工作階段以使用側邊欄', + pluginNotLoaded: '插件未載入,標籤暫不可用:', + hiddenFiles: '隱藏檔案', + parent: '上層目錄', + copied: '已複製', + copy: '複製', + newFile: '新檔案', + openEditor: '開啟編輯器', + gitDetail: '檢視變更詳情', + referenceFile: '@檔案', + addToConversation: '新增到對話', + copyRelative: '複製相對位址', + copyAbsolute: '複製絕對位址', + download: '下載', + uploadFiles: '上傳檔案', + uploadFolder: '上傳資料夾', + uploadHere: '上傳到此處', + uploadDropHint: '拖曳檔案/資料夾到此處上傳', + uploadDropChat: '拖放到聊天區:新增圖片到對話', + uploadTo: '上傳到 {dir}', + uploadingTo: '正在上傳到 {dir}…', + uploadProgress: '正在上傳 {done}/{total}: {name}', + uploadDone: '已上傳 {count} 個檔案', + uploadFailed: '上傳失敗:{error}', + uploadFailedUnknown: '未知錯誤', + uploadTooLarge: '檔案過大,超出上傳上限', + uploadCancelled: '上傳已取消', + settingsNav: '側邊卡片', + settingsIntro: '管理側邊卡片的顯示內容與預設行為', + settingsPopupDesc: '為「{feature}」設定相關選項', + settingsDone: '完成', + settingsOpenTitle: '新工作階段預設開啟', + settingsOpenDesc: '新增工作階段時自動展開側邊卡片;已存在的工作階段保持各自佈局', + settingsWidthTitle: '預設寬度佔比', + settingsWidthDesc: '新增工作階段時側邊卡片佔視窗寬度的百分比 (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: '聊天區檔案在側邊欄開啟', + settingsOpenPathDesc: '在聊天裡點擊檔案連結(工具行、產物列表、檔案提及)時,在側邊欄編輯器中開啟,不再呼叫系統預設應用程式', + settingsTitleBarTitle: '位置相容模式', + settingsTitleBarDesc: '選擇頂欄相容方案:自動偵測(預設,保守)/ DSH官方Web / 已知桌面殼 / 自訂方案(下移距離 + 自訂 CSS)', + settingsTitleBarStripTitle: '下移距離', + settingsTitleBarStripDesc: '標題欄條帶高度:側邊欄按鈕與內容下移的像素數(0–120,預設 40;自訂方案下生效)', + settingsSchemeAutoTitle: '自動偵測', + settingsSchemeAutoDesc: '保守方案:僅在 Window Controls Overlay 標準 API 可用時按真實標題欄高度讓位;網頁環境下不做任何修改', + settingsSchemeWebTitle: 'DSH官方Web', + settingsSchemeWebDesc: '顯式宣告執行在官方網頁版:不做任何適配(連標準 WCO 幾何也不適用)', + settingsSchemeCustomTitle: '自訂方案', + settingsSchemeCustomDesc: '完全由你控制:注入自訂 CSS(可覆寫內建樣式),並指定標題欄下移距離', + settingsSchemeDetectedSuffix: '已偵測', + settingsCustomCssTitle: '自訂 CSS', + settingsCustomCssDesc: '附加到頁面末尾的樣式(同優先級下後寫勝出;覆寫 JS 內聯變數需用 !important)', + settingsCustomCssPlaceholder: '/* 例:為自繪標題欄的殼預留 36px */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: '儲存失敗', + settingsConflict: '設定已被其他視窗修改,請重試', + binaryNoPreview: '此檔案類型不支援預覽', + downloadToView: '下載檢視', + settingsSubagentTitle: '偵測到子代理時自動展開任務管理頁', + settingsSubagentDesc: '目前工作階段產生新的子代理時,自動展開側邊欄並開啟任務管理頁;關閉後需手動開啟', + settingsJobsTitle: '有新背景任務時自動展開背景任務頁', + settingsJobsDesc: '目前工作階段出現新的背景任務時,自動展開側邊欄並開啟背景任務頁(每個新任務都會觸發);關閉後需手動開啟', + settingsToolsTitle: '為模型注入終端工具', + settingsToolsDesc: '開啟後,模型可透過 terminal_create 等 8 個工具建立並操作側邊欄終端(預設關閉)', + settingsBottomTerminalTitle: '底部面板首次展開自動開終端', + settingsBottomTerminalDesc: '每次工作階段中第一次展開底部面板時,嘗試在底部面板自動開啟一個新終端標籤(終端數量上限仍會限制;預設開啟)', + settingsFontFamilyTitle: '終端字體', + settingsFontFamilyDesc: '自訂終端字體族(CSS font-family,如 "JetBrains Mono", monospace;留空跟隨主題等寬字體)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: '終端字型大小', + settingsFontSizeDesc: '終端字型大小(9–32,預設 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'Shell 路徑', + settingsShellDesc: 'UI 與模型終端啟動的 shell(絕對路徑或可執行名)。留空按既有順序解析:yaml 的 config.shell → $SHELL / 登入 shell / Windows 的 powershell.exe。對之後開啟的終端生效', + settingsShellPlaceholder: '如 /bin/zsh(留空自動解析)', + settingsShellArgsTitle: 'Shell 參數', + settingsShellArgsDesc: '顯式 shell 啟動參數,空格分隔;非空時完全替換預設參數(與 yaml 的 shellArgs 契約一致)', + settingsShellArgsPlaceholder: '如 -l(留空用預設參數)', + settingsTabsTitle: '側邊欄內容', + settingsViewersTitle: '檔案預覽', + settingsGeneralTitle: '一般', + settingsPopup: '功能設定', + settingsViewerCatchAll: '兜底:任意檔案', + viewerImage: '圖片', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: '程式碼', + viewerBinary: '二進位下載', + viewerHtml: 'HTML', + browser: '瀏覽器', + browserPlaceholder: '輸入網址,例如 example.com', + browserGo: '前往', + browserBack: '上一頁', + browserForward: '下一頁', + browserStart: '輸入網址開始瀏覽(沙箱模式)', + browserBlockedScheme: '已封鎖:僅支援 http/https 連結', + browserBlockedLoopback: '已封鎖:不允許在瀏覽器中存取本機或內部位址', + browserInvalid: '無效的網址', + browserNoSandboxWarning: '沙箱已關閉:目前頁面與介面同源,擁有完整工作階段權限(可在設定中恢復)', + htmlNoSandboxWarning: '沙箱已關閉:此 HTML 與介面同源,可讀取工作階段檔案與內部介面(可在設定中恢復)', + sandboxStatusOn: '沙箱模式:已啟用 · 頁面無法存取介面資料與本地檔案,登入態與第三方 Cookie 可能不可用', + sandboxUnlock: '臨時解鎖(不安全)', + sandboxRestore: '恢復沙箱', + settingsHtmlDefaultUnsafeTitle: 'HTML 預覽預設以非沙箱模式開啟(不安全)', + settingsHtmlDefaultUnsafeDesc: '開啟後,每次開啟 HTML 檔案時預覽預設處於非沙箱狀態(與介面同源,可讀取工作階段檔案與內部介面);可在狀態列臨時恢復沙箱', + settingsHtmlSandboxTitle: '關閉 HTML 預覽沙箱(不安全)', + settingsHtmlSandboxDesc: '關閉後,預覽的 HTML 將與介面同源執行,可讀取工作階段檔案、本地儲存並呼叫內部介面。僅對完全可信的檔案開啟', + settingsBrowserSandboxTitle: '關閉瀏覽器沙箱(不安全)', + settingsBrowserSandboxDesc: '關閉後,存取的任何網站都將與介面同源執行,可讀取工作階段資料並冒充你的登入狀態。僅對完全可信的網站開啟', + settingsBrowserLinksTitle: '聊天區外鏈在側邊欄開啟', + settingsBrowserLinksDesc: '開啟後,點擊聊天或介面中的外鏈時在側邊欄開啟,不再彈出新視窗;HTTP 與 HTTPS 可分別透過下方開關控制;Ctrl/Cmd 點擊可臨時放行', + settingsBrowserHttpTitle: '側邊開啟HTTP網頁', + settingsBrowserHttpDesc: '開啟後,點擊聊天或介面中的 HTTP 外鏈時在側邊欄開啟(宣告了 urlTarget 的插件頁面優先);Ctrl/Cmd 點擊可臨時放行', + settingsBrowserHttpsTitle: '側邊開啟HTTPS網頁', + settingsBrowserHttpsDesc: '開啟後,點擊聊天或介面中的 HTTPS 外鏈時在側邊欄開啟。預設關閉:多數 HTTPS 網站拒絕被嵌入,走系統瀏覽器更順暢', + browserOpenExternal: '在瀏覽器中開啟', + browserEmbedBlocked: '{host} 拒絕了嵌入請求', + browserEmbedBlockedDesc: '該網站透過 X-Frame-Options / frame-ancestors 禁止在其它頁面中顯示,無法在側邊欄內載入。可在瀏覽器中直接開啟', + browserEmbedAnyway: '仍然載入', + subagent: '任務管理', + openSubagent: '任務管理', + subagentMainAgent: '主代理', + subagentEmpty: '暫無子代理', + subagentEmptyDesc: '目前主代理派生的子代理將顯示在這裡', + subagentRunning: '執行中', + subagentInactive: '閒置', + subagentModeOneShot: '一次性', + subagentModeContinuable: '可續接', + subagentCount: '{count} 個子代理', + subagentCountRunning: '{count} 個子代理 · {running} 執行中', + subagentDiagCorrupt: '目錄損壞', + subagentDiagUnsupported: '不支援的條目', + subagentDiagUnavailable: '不可用', + subagentThinking: '思考中…', + sideChat: '側邊對話(beta)', + sideChatNew: '新增對話', + sideChatUntitled: '新對話', + sideChatEmpty: '暫無側邊對話', + sideChatEmptyDesc: '每個側邊對話是標籤列裡的獨立 Tab,繼承目前工作階段的上下文執行,不會進入主工作階段', + sideChatCreating: '正在建立側邊對話…', + sideChatRetry: '重試', + sideChatThreads: '切換執行緒 / 新增', + sideChatSave: '儲存為新工作階段', + sideChatSaveTitle: '把該執行緒提升為頂層工作階段,出現在主工作階段列表中', + sideChatSaved: '已儲存為新工作階段', + sideChatNoTurn: '至少完成一輪對話後才能儲存', + sideChatPendingDrop: '最後一則未完成的追問不會包含在新工作階段中', + sideChatFirstPlaceholder: '輸入第一個問題,已繼承目前工作階段上下文…', + sideChatComposerPlaceholder: '追問…', + sideChatThinking: '正在深入…', + sideChatThink: '思考過程', + sideChatInjection: '已注入上下文', + sideChatSend: '發送', + sideChatCancel: '停止', + sideChatCancelTitle: '中止目前回合(保留佇列)', + sideChatClose: '關閉執行緒', + sideChatCloseTitle: '釋放執行緒的 agent(歷史保留)', + sideChatError: '側邊對話出錯:{message}', + jobs: '背景任務', + jobsCount: '{count} 個背景任務', + jobsCountRunning: '{count} 個背景任務 · {running} 執行中', + jobStatusRunning: '執行中', + jobStatusStopping: '終止中', + jobStatusCompleted: '已完成', + jobStatusKilled: '已終止', + jobStatusFailed: '失敗', + jobDurationSeconds: '{seconds} 秒', + jobDurationMinutes: '{minutes} 分 {seconds} 秒', + jobDurationHours: '{hours} 小時 {minutes} 分', + jobViewOutput: '檢視輸出', + jobHideOutput: '收起輸出', + jobNoOutput: '暫無輸出', + jobNotReadYet: '等待模型讀取該任務的輸出(模型執行 job_output 後,輸出會顯示在這裡)', + jobOutputTruncated: '輸出過長,已截斷顯示', + jobOutputError: '輸出讀取失敗', + jobKill: '終止', + jobKillConfirm: '再次點擊確認終止', + jobKillError: '終止失敗', + addPluginsTabCard: '新增 Tab 插件', + addPluginsTabCardDesc: '註冊新的側邊欄頁面', + addPluginsViewerCard: '新增預覽插件', + addPluginsViewerCardDesc: '註冊新的檔案類型預覽', + addPluginsTabDesc: '側邊欄頁面(Tab)可以由插件擴展。插件透過 ctx.betterSidebar 服務註冊;點擊「安裝」複製安裝命令,貼到 DSH 所在環境的終端執行。', + addPluginsViewerDesc: '檔案預覽器可以由插件擴展。插件透過 ctx.betterSidebar 服務註冊;點擊「安裝」複製安裝命令,貼到 DSH 所在環境的終端執行。', + addPluginsBrowseMore: '在 GitHub 上瀏覽更多插件(topic: dsh-better-sidebar)', + addPluginsSearch: '搜尋插件名稱 / 描述…', + addPluginsNoMatch: '沒有匹配的插件', + addPluginsRecommended: '推薦插件', + addPluginsEmpty: '暫未收錄插件,歡迎在 GitHub topic 下發布你的插件', + openPlugin: '跳轉', + copyInstall: '複製安裝命令', + pluginOfficeDesc: '為 better-sidebar 編輯器提供 Office 三件套預覽(.docx / .xlsx / .pptx),把重型 Office 渲染庫拆出主套件、按需安裝', + pluginFlowglassDesc: '即時工作階段流程圖:三列泳道展示使用者、助手與工具呼叫,支援並行分組、子代理支線、逐層鑽取和即時狀態;安裝 better-sidebar 後註冊原生「流鏡」Tab,未安裝時保留獨立抽屜', + pluginGitForgeDesc: 'better-sidebar「Git 憑證」Tab:GitHub/Gitea 等 Forge 帳號庫 + 按專案授權 + push 策略硬攔;token 僅存本地 secrets,不進模型上下文;提供唯讀 GitForge 工具與 agent HTTPS credential helper', + pluginGitRemotesDesc: 'better-sidebar Git 遠端 Tab:看分支/上游/ahead-behind,fetch(可 prune)、ff-only pull、確認後才 push。不替換內建 Git 的暫存/提交,也不提供 force-push 或模型自動推送', + pluginSentinelDesc: '條件驅動的 agent 喚醒系統:檔案/程序/連接埠/HTTP/命令/webhook 感測器,條件達成自動喚醒休眠工作階段;註冊「哨兵」Tab 展示伺服器全域監控表', + pluginSidebarQaDesc: '基於 better-sidebar 的劃選提問tab分頁: 對話劃選 → 右側面板提問 → 同工作區獨立追問工作階段(❓追問·主題):快速無思考模型壓縮主對話上下文後與引文一起注入,不打斷主對話;追問可巢狀、可繼續、可歸檔', + pluginSshTunnelDesc: 'better-sidebar「SSH 隧道」Tab:多機主機清單 + 按專案授權 + 密鑰本地保管;模型工具 SSHManager(exec/SFTP/工作階段策略);中央互動終端與雙欄 SFTP', + pluginTurnReviewDesc: '對「剛剛這一回合」的 diff 做 Approve / Request changes 的人閘門:只審上一回合,不 fork 工作階段;檔案按主工作階段/子代理/未歸因分組,按檔案勾選打回 + 可選評語,點檔案先看回合開始快照 vs 現在的 diff。不是 /rewind', + pluginVideoPreviewDesc: '在 better-sidebar 編輯器內聯預覽影片檔案(.mp4/.webm/.mov/.mkv/.avi 等),自帶支援 HTTP Range(206)的 /video 宿主路由,可拖曳進度條、不受 20MB mediaLimit 限制', + pluginDocsPanelDesc: 'DSH 側邊欄裡的「全域文件」:全域 Markdown 筆記,任何工作區隨時可讀——列表點選閱讀、懸浮大綱跳轉、Chrome / VS Code 外部開啟、程式碼複製,目錄可設定(預設 ~/.dsh/docs)', +} diff --git a/src/client/locales-zh-MO.ts b/src/client/locales-zh-MO.ts new file mode 100644 index 0000000..f108901 --- /dev/null +++ b/src/client/locales-zh-MO.ts @@ -0,0 +1,360 @@ +/** + * The zh-HK (Traditional Chinese — Hong Kong) dictionary for the betterSidebar + * namespace. + * + * Mirrors the key set of `zh` in `locales.ts`. Consumed by better-locale's + * override store when the active override id is `'zh-HK'` (registered under + * the `betterSidebar` namespace). Absent that, the existing zh/en chain + * runs unchanged. + * + * Hong Kong regional conventions: + * - 软件 → 軟件 (NOT 軟體); 网络 → 網絡 (NOT 網路); 鼠标 → 滑鼠 + * - 檔案 (file), 資料夾 (folder), 程式 (program), 程式碼 (code), 螢幕 (screen) + * - 預設 (default), 儲存 (save), 設定 (settings/config), 唯讀 (read-only) + * - 資源管理器 → 檔案總管; refresh → 重新整理; cache → 快取 + * - timeout → 逾時; loop → 迴圈; override → 覆寫; built-in → 內建 + * - adapter → 介面卡; interface → 介面; address → 位址; field → 欄位 + * - byte → 位元組; binary → 二進位; character → 字元; hash → 雜湊 + * - rename → 重新命名; archive → 歸檔; idle → 閒置; mount → 掛載 + * - package → 套件; generate → 產生; fetch → 取得; export → 匯出 + * - login → 登入; detect → 偵測; block → 封鎖; access → 存取 + * - port → 連接埠; sensor → 感測器; server → 伺服器; global → 全域 + * - nested → 巢狀; thread → 執行緒; queue → 佇列; tab → 標籤 + * - source code → 原始碼; symlink → 符號連結; recover → 復原 + * - placeholder → 佔位符; template → 範本; variable → 變數 + * - through → 透過; paste → 貼上; project → 專案; account → 帳號 + * - session (会话) → 工作階段; chat (对话) → 對話 + * - quotation marks: "" → 「」 + * - Placeholders keep `{name}` verbatim (interpolation runs after lookup). + * - English brand names (VS Code, Cursor, Zed, SSH, Git, Chrome) stay as-is. + */ + +/** The zh-HK dictionary (key-set-equal to zh, enforced by the type annotation in locales.ts). */ +export const zhMO: Record = { + files: '檔案', + explorer: '檔案總管', + git: '原始碼管理', + terminal: '終端', + editor: '編輯器', + editorExplorer: '檔案開啟方式', + editorExplorerDesc: '控制檔案開啟方式', + editorExplorerMerged: '合併', + editorExplorerMergedDesc: '檔案在同一視窗內原地切換;新視窗預設展開檔案樹', + editorExplorerSplit: '獨立', + editorExplorerSplitDesc: '無路徑視窗即檔案總管(僅檔案樹);檔案各自新開視窗(帶檔案樹,預設收起)', + editorTreeToggle: '檔案樹面板', + editorPathPlaceholder: '輸入檔案路徑(相對工作階段目錄或絕對路徑),Enter 開啟', + editorSearchPlaceholder: '按檔案名稱搜尋…', + editorSearchNoResults: '無匹配檔案', + editorSearchTruncated: '結果過多,僅顯示部分匹配', + editorEmptyHint: '從右側檔案樹或上方路徑輸入框選擇檔案開始預覽', + openFileNewTab: '在新 Tab 中開啟', + openFileSide: '在側邊開啟', + openWithMenu: '在應用程式中開啟', + openWithSshSuffix: ' (SSH)', + pinOpenWith: '固定到選單', + unpinOpenWith: '取消固定', + openWithExplorer: '檔案總管', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'SSH 遠端主機', + openWithSettingsSshDesc: '留空為本地工作區;填入 user@host 或 SSH 別名後,VSCode 系開啟方式將改用 vscode-remote/ssh-remote 協議,檔案總管 / Zed / 非 VSCode 系自訂編輯器將從選單隱藏', + openWithSettingsSshPlaceholder: 'user@host 或 SSH 別名', + openWithSettingsCustomTitle: '自訂編輯器', + openWithSettingsCustomDesc: '名稱 + URL 範本({path} 佔位符)+ 是否 VSCode 系;SSH 模式下僅 VSCode 系可開啟遠端', + openWithSettingsAdd: '新增', + openWithSettingsName: '名稱', + openWithSettingsTemplate: '如 cursor://file/{path}', + openWithSettingsFamily: 'VSCode 系', + openWithSettingsFamilyDesc: '該編輯器使用 VSCode 的 URL 協議(支援 SSH 遠端開啟)', + openWithSettingsRemove: '刪除', + openWithSettingsInvalidHint: '名稱或範本(需含 {path} 且以 scheme:// 開頭)未填寫的編輯器不會出現在選單中', + newTab: '新增標籤', + openExplorer: '檔案總管', + brokenSymlink: '失效的符號連結', + openGit: 'Git 面板', + newTerminal: '新終端', + terminalLimit: '終端數量已達上限 (3)', + close: '關閉', + closeOtherTabs: '關閉其他標籤', + closeLeftTabs: '關閉左側標籤', + closeRightTabs: '關閉右側標籤', + collapse: '收起側邊欄', + expand: '展開側邊欄', + collapseBottomPanel: '收起底部面板', + expandBottomPanel: '展開底部面板', + terminalError: '終端連線失敗', + terminalConnectFailed: '終端多次連線失敗', + terminalRetry: '重試', + terminalDepsFailed: '終端依賴 node-pty 載入失敗', + terminalDepsHint: '在 DSH 所在環境的終端或 cmd 中執行以下命令修復,然後點重試(node-pty 與 DSH 核心保持同一版本):', + terminalDepsProfile: '(偵測到 profile:{profile})', + preview: '預覽', + edit: '編輯', + mermaidError: 'Mermaid 渲染失敗', + mermaidZoomIn: '放大', + mermaidZoomOut: '縮小', + mermaidZoomReset: '重設', + mermaidZoomHint: '滾輪縮放 · 拖曳平移 · Esc 關閉', + refresh: '重新整理', + save: '儲存', + saved: '已儲存', + unsaved: '未儲存', + saveFailed: '儲存失敗', + truncation: '檔案過大,僅顯示前 512KB', + binary: '二進位檔案,無法預覽', + loading: '載入中…', + error: '載入失敗', + retry: '重試', + splitLeft: '向左分欄', + splitRight: '向右分欄', + splitUp: '向上分欄', + splitDown: '向下分欄', + notRepo: '目前目錄不是 git 倉庫', + noChanges: '沒有變更', + stage: '暫存', + unstage: '取消暫存', + stageAll: '全部暫存', + unstageAll: '全部取消暫存', + commitPlaceholder: '提交訊息 (Ctrl+Enter)', + commit: '提交', + commitError: '提交失敗', + branch: '分支', + checkoutError: '切換分支失敗', + history: '歷史', + changes: '變更', + staged: '已暫存', + unstaged: '未暫存', + cancel: '取消', + diffEmpty: '沒有文字差異', + diffLoadError: '載入差異失敗', + diffBinary: '二進位', + diffAdded: '新增', + diffDeleted: '刪除', + diffRenamed: '重新命名', + diffExpand: '展開其餘 {count} 行', + diffCollapse: '收起', + discard: '放棄變更', + discardTitle: '放棄變更', + discardDesc: '將丟棄「{path}」的工作區修改(不可復原)。', + viewCommitDiff: '檢視提交差異', + copyShortHash: '複製短雜湊', + copyFullHash: '複製完整雜湊', + copySubject: '複製提交訊息', + revertCommit: '還原此提交', + revertTitle: '還原此提交', + revertDesc: '將在目前分支建立一個反轉「{subject}」的新提交。', + cherryPickCommit: '撿取此提交', + cherryPickTitle: '撿取此提交', + cherryPickDesc: '將「{subject}」的變更套用到目前分支。', + timeJustNow: '剛剛', + timeMinutesAgo: '{n} 分鐘前', + timeHoursAgo: '{n} 小時前', + timeYesterday: '昨天', + loadMore: '載入更多', + historyLoadError: '載入更多歷史失敗', + produced: '本次產出', + producedOpen: '在側邊欄中開啟', + disconnected: '終端連線斷開,重新連線中…', + exited: '終端程序已退出', + noSession: '選擇一個工作階段以使用側邊欄', + pluginNotLoaded: '插件未載入,標籤暫不可用:', + hiddenFiles: '隱藏檔案', + parent: '上層目錄', + copied: '已複製', + copy: '複製', + newFile: '新檔案', + openEditor: '開啟編輯器', + gitDetail: '檢視變更詳情', + referenceFile: '@檔案', + addToConversation: '新增到對話', + copyRelative: '複製相對位址', + copyAbsolute: '複製絕對位址', + download: '下載', + uploadFiles: '上傳檔案', + uploadFolder: '上傳資料夾', + uploadHere: '上傳到此處', + uploadDropHint: '拖曳檔案/資料夾到此處上傳', + uploadDropChat: '拖放到聊天區:新增圖片到對話', + uploadTo: '上傳到 {dir}', + uploadingTo: '正在上傳到 {dir}…', + uploadProgress: '正在上傳 {done}/{total}: {name}', + uploadDone: '已上傳 {count} 個檔案', + uploadFailed: '上傳失敗:{error}', + uploadFailedUnknown: '未知錯誤', + uploadTooLarge: '檔案過大,超出上傳上限', + uploadCancelled: '上傳已取消', + settingsNav: '側邊卡片', + settingsIntro: '管理側邊卡片的顯示內容與預設行為', + settingsPopupDesc: '為「{feature}」設定相關選項', + settingsDone: '完成', + settingsOpenTitle: '新工作階段預設開啟', + settingsOpenDesc: '新增工作階段時自動展開側邊卡片;已存在的工作階段保持各自佈局', + settingsWidthTitle: '預設寬度佔比', + settingsWidthDesc: '新增工作階段時側邊卡片佔視窗寬度的百分比 (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: '聊天區檔案在側邊欄開啟', + settingsOpenPathDesc: '在聊天裡點擊檔案連結(工具行、產物列表、檔案提及)時,在側邊欄編輯器中開啟,不再呼叫系統預設應用程式', + settingsTitleBarTitle: '位置相容模式', + settingsTitleBarDesc: '選擇頂欄相容方案:自動偵測(預設,保守)/ DSH官方Web / 已知桌面殼 / 自訂方案(下移距離 + 自訂 CSS)', + settingsTitleBarStripTitle: '下移距離', + settingsTitleBarStripDesc: '標題欄條帶高度:側邊欄按鈕與內容下移的像素數(0–120,預設 40;自訂方案下生效)', + settingsSchemeAutoTitle: '自動偵測', + settingsSchemeAutoDesc: '保守方案:僅在 Window Controls Overlay 標準 API 可用時按真實標題欄高度讓位;網頁環境下不做任何修改', + settingsSchemeWebTitle: 'DSH官方Web', + settingsSchemeWebDesc: '顯式宣告執行在官方網頁版:不做任何適配(連標準 WCO 幾何也不適用)', + settingsSchemeCustomTitle: '自訂方案', + settingsSchemeCustomDesc: '完全由你控制:注入自訂 CSS(可覆寫內建樣式),並指定標題欄下移距離', + settingsSchemeDetectedSuffix: '已偵測', + settingsCustomCssTitle: '自訂 CSS', + settingsCustomCssDesc: '附加到頁面末尾的樣式(同優先級下後寫勝出;覆寫 JS 內聯變數需用 !important)', + settingsCustomCssPlaceholder: '/* 例:為自繪標題欄的殼預留 36px */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: '儲存失敗', + settingsConflict: '設定已被其他視窗修改,請重試', + binaryNoPreview: '此檔案類型不支援預覽', + downloadToView: '下載檢視', + settingsSubagentTitle: '偵測到子代理時自動展開任務管理頁', + settingsSubagentDesc: '目前工作階段產生新的子代理時,自動展開側邊欄並開啟任務管理頁;關閉後需手動開啟', + settingsJobsTitle: '有新背景任務時自動展開背景任務頁', + settingsJobsDesc: '目前工作階段出現新的背景任務時,自動展開側邊欄並開啟背景任務頁(每個新任務都會觸發);關閉後需手動開啟', + settingsToolsTitle: '為模型注入終端工具', + settingsToolsDesc: '開啟後,模型可透過 terminal_create 等 8 個工具建立並操作側邊欄終端(預設關閉)', + settingsBottomTerminalTitle: '底部面板首次展開自動開終端', + settingsBottomTerminalDesc: '每次工作階段中第一次展開底部面板時,嘗試在底部面板自動開啟一個新終端標籤(終端數量上限仍會限制;預設開啟)', + settingsFontFamilyTitle: '終端字體', + settingsFontFamilyDesc: '自訂終端字體族(CSS font-family,如 "JetBrains Mono", monospace;留空跟隨主題等寬字體)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: '終端字型大小', + settingsFontSizeDesc: '終端字型大小(9–32,預設 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'Shell 路徑', + settingsShellDesc: 'UI 與模型終端啟動的 shell(絕對路徑或可執行名)。留空按既有順序解析:yaml 的 config.shell → $SHELL / 登入 shell / Windows 的 powershell.exe。對之後開啟的終端生效', + settingsShellPlaceholder: '如 /bin/zsh(留空自動解析)', + settingsShellArgsTitle: 'Shell 參數', + settingsShellArgsDesc: '顯式 shell 啟動參數,空格分隔;非空時完全替換預設參數(與 yaml 的 shellArgs 契約一致)', + settingsShellArgsPlaceholder: '如 -l(留空用預設參數)', + settingsTabsTitle: '側邊欄內容', + settingsViewersTitle: '檔案預覽', + settingsGeneralTitle: '一般', + settingsPopup: '功能設定', + settingsViewerCatchAll: '兜底:任意檔案', + viewerImage: '圖片', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: '程式碼', + viewerBinary: '二進位下載', + viewerHtml: 'HTML', + browser: '瀏覽器', + browserPlaceholder: '輸入網址,例如 example.com', + browserGo: '前往', + browserBack: '上一頁', + browserForward: '下一頁', + browserStart: '輸入網址開始瀏覽(沙箱模式)', + browserBlockedScheme: '已封鎖:僅支援 http/https 連結', + browserBlockedLoopback: '已封鎖:不允許在瀏覽器中存取本機或內部位址', + browserInvalid: '無效的網址', + browserNoSandboxWarning: '沙箱已關閉:目前頁面與介面同源,擁有完整工作階段權限(可在設定中恢復)', + htmlNoSandboxWarning: '沙箱已關閉:此 HTML 與介面同源,可讀取工作階段檔案與內部介面(可在設定中恢復)', + sandboxStatusOn: '沙箱模式:已啟用 · 頁面無法存取介面資料與本地檔案,登入態與第三方 Cookie 可能不可用', + sandboxUnlock: '臨時解鎖(不安全)', + sandboxRestore: '恢復沙箱', + settingsHtmlDefaultUnsafeTitle: 'HTML 預覽預設以非沙箱模式開啟(不安全)', + settingsHtmlDefaultUnsafeDesc: '開啟後,每次開啟 HTML 檔案時預覽預設處於非沙箱狀態(與介面同源,可讀取工作階段檔案與內部介面);可在狀態列臨時恢復沙箱', + settingsHtmlSandboxTitle: '關閉 HTML 預覽沙箱(不安全)', + settingsHtmlSandboxDesc: '關閉後,預覽的 HTML 將與介面同源執行,可讀取工作階段檔案、本地儲存並呼叫內部介面。僅對完全可信的檔案開啟', + settingsBrowserSandboxTitle: '關閉瀏覽器沙箱(不安全)', + settingsBrowserSandboxDesc: '關閉後,存取的任何網站都將與介面同源執行,可讀取工作階段資料並冒充你的登入狀態。僅對完全可信的網站開啟', + settingsBrowserLinksTitle: '聊天區外鏈在側邊欄開啟', + settingsBrowserLinksDesc: '開啟後,點擊聊天或介面中的外鏈時在側邊欄開啟,不再彈出新視窗;HTTP 與 HTTPS 可分別透過下方開關控制;Ctrl/Cmd 點擊可臨時放行', + settingsBrowserHttpTitle: '側邊開啟HTTP網頁', + settingsBrowserHttpDesc: '開啟後,點擊聊天或介面中的 HTTP 外鏈時在側邊欄開啟(宣告了 urlTarget 的插件頁面優先);Ctrl/Cmd 點擊可臨時放行', + settingsBrowserHttpsTitle: '側邊開啟HTTPS網頁', + settingsBrowserHttpsDesc: '開啟後,點擊聊天或介面中的 HTTPS 外鏈時在側邊欄開啟。預設關閉:多數 HTTPS 網站拒絕被嵌入,走系統瀏覽器更順暢', + browserOpenExternal: '在瀏覽器中開啟', + browserEmbedBlocked: '{host} 拒絕了嵌入請求', + browserEmbedBlockedDesc: '該網站透過 X-Frame-Options / frame-ancestors 禁止在其它頁面中顯示,無法在側邊欄內載入。可在瀏覽器中直接開啟', + browserEmbedAnyway: '仍然載入', + subagent: '任務管理', + openSubagent: '任務管理', + subagentMainAgent: '主代理', + subagentEmpty: '暫無子代理', + subagentEmptyDesc: '目前主代理派生的子代理將顯示在這裡', + subagentRunning: '執行中', + subagentInactive: '閒置', + subagentModeOneShot: '一次性', + subagentModeContinuable: '可續接', + subagentCount: '{count} 個子代理', + subagentCountRunning: '{count} 個子代理 · {running} 執行中', + subagentDiagCorrupt: '目錄損壞', + subagentDiagUnsupported: '不支援的條目', + subagentDiagUnavailable: '不可用', + subagentThinking: '思考中…', + sideChat: '側邊對話(beta)', + sideChatNew: '新增對話', + sideChatUntitled: '新對話', + sideChatEmpty: '暫無側邊對話', + sideChatEmptyDesc: '每個側邊對話是標籤列裡的獨立 Tab,繼承目前工作階段的上下文執行,不會進入主工作階段', + sideChatCreating: '正在建立側邊對話…', + sideChatRetry: '重試', + sideChatThreads: '切換執行緒 / 新增', + sideChatSave: '儲存為新工作階段', + sideChatSaveTitle: '把該執行緒提升為頂層工作階段,出現在主工作階段列表中', + sideChatSaved: '已儲存為新工作階段', + sideChatNoTurn: '至少完成一輪對話後才能儲存', + sideChatPendingDrop: '最後一則未完成的追問不會包含在新工作階段中', + sideChatFirstPlaceholder: '輸入第一個問題,已繼承目前工作階段上下文…', + sideChatComposerPlaceholder: '追問…', + sideChatThinking: '正在深入…', + sideChatThink: '思考過程', + sideChatInjection: '已注入上下文', + sideChatSend: '發送', + sideChatCancel: '停止', + sideChatCancelTitle: '中止目前回合(保留佇列)', + sideChatClose: '關閉執行緒', + sideChatCloseTitle: '釋放執行緒的 agent(歷史保留)', + sideChatError: '側邊對話出錯:{message}', + jobs: '背景任務', + jobsCount: '{count} 個背景任務', + jobsCountRunning: '{count} 個背景任務 · {running} 執行中', + jobStatusRunning: '執行中', + jobStatusStopping: '終止中', + jobStatusCompleted: '已完成', + jobStatusKilled: '已終止', + jobStatusFailed: '失敗', + jobDurationSeconds: '{seconds} 秒', + jobDurationMinutes: '{minutes} 分 {seconds} 秒', + jobDurationHours: '{hours} 小時 {minutes} 分', + jobViewOutput: '檢視輸出', + jobHideOutput: '收起輸出', + jobNoOutput: '暫無輸出', + jobNotReadYet: '等待模型讀取該任務的輸出(模型執行 job_output 後,輸出會顯示在這裡)', + jobOutputTruncated: '輸出過長,已截斷顯示', + jobOutputError: '輸出讀取失敗', + jobKill: '終止', + jobKillConfirm: '再次點擊確認終止', + jobKillError: '終止失敗', + addPluginsTabCard: '新增 Tab 插件', + addPluginsTabCardDesc: '註冊新的側邊欄頁面', + addPluginsViewerCard: '新增預覽插件', + addPluginsViewerCardDesc: '註冊新的檔案類型預覽', + addPluginsTabDesc: '側邊欄頁面(Tab)可以由插件擴展。插件透過 ctx.betterSidebar 服務註冊;點擊「安裝」複製安裝命令,貼到 DSH 所在環境的終端執行。', + addPluginsViewerDesc: '檔案預覽器可以由插件擴展。插件透過 ctx.betterSidebar 服務註冊;點擊「安裝」複製安裝命令,貼到 DSH 所在環境的終端執行。', + addPluginsBrowseMore: '在 GitHub 上瀏覽更多插件(topic: dsh-better-sidebar)', + addPluginsSearch: '搜尋插件名稱 / 描述…', + addPluginsNoMatch: '沒有匹配的插件', + addPluginsRecommended: '推薦插件', + addPluginsEmpty: '暫未收錄插件,歡迎在 GitHub topic 下發布你的插件', + openPlugin: '跳轉', + copyInstall: '複製安裝命令', + pluginOfficeDesc: '為 better-sidebar 編輯器提供 Office 三件套預覽(.docx / .xlsx / .pptx),把重型 Office 渲染庫拆出主套件、按需安裝', + pluginFlowglassDesc: '即時工作階段流程圖:三列泳道展示使用者、助手與工具呼叫,支援並行分組、子代理支線、逐層鑽取和即時狀態;安裝 better-sidebar 後註冊原生「流鏡」Tab,未安裝時保留獨立抽屜', + pluginGitForgeDesc: 'better-sidebar「Git 憑證」Tab:GitHub/Gitea 等 Forge 帳號庫 + 按專案授權 + push 策略硬攔;token 僅存本地 secrets,不進模型上下文;提供唯讀 GitForge 工具與 agent HTTPS credential helper', + pluginGitRemotesDesc: 'better-sidebar Git 遠端 Tab:看分支/上游/ahead-behind,fetch(可 prune)、ff-only pull、確認後才 push。不替換內建 Git 的暫存/提交,也不提供 force-push 或模型自動推送', + pluginSentinelDesc: '條件驅動的 agent 喚醒系統:檔案/程序/連接埠/HTTP/命令/webhook 感測器,條件達成自動喚醒休眠工作階段;註冊「哨兵」Tab 展示伺服器全域監控表', + pluginSidebarQaDesc: '基於 better-sidebar 的劃選提問tab分頁: 對話劃選 → 右側面板提問 → 同工作區獨立追問工作階段(❓追問·主題):快速無思考模型壓縮主對話上下文後與引文一起注入,不打斷主對話;追問可巢狀、可繼續、可歸檔', + pluginSshTunnelDesc: 'better-sidebar「SSH 隧道」Tab:多機主機清單 + 按專案授權 + 密鑰本地保管;模型工具 SSHManager(exec/SFTP/工作階段策略);中央互動終端與雙欄 SFTP', + pluginTurnReviewDesc: '對「剛剛這一回合」的 diff 做 Approve / Request changes 的人閘門:只審上一回合,不 fork 工作階段;檔案按主工作階段/子代理/未歸因分組,按檔案勾選打回 + 可選評語,點檔案先看回合開始快照 vs 現在的 diff。不是 /rewind', + pluginVideoPreviewDesc: '在 better-sidebar 編輯器內聯預覽影片檔案(.mp4/.webm/.mov/.mkv/.avi 等),自帶支援 HTTP Range(206)的 /video 宿主路由,可拖曳進度條、不受 20MB mediaLimit 限制', + pluginDocsPanelDesc: 'DSH 側邊欄裡的「全域文件」:全域 Markdown 筆記,任何工作區隨時可讀——列表點選閱讀、懸浮大綱跳轉、Chrome / VS Code 外部開啟、程式碼複製,目錄可設定(預設 ~/.dsh/docs)', +} diff --git a/src/client/locales-zh-TW.ts b/src/client/locales-zh-TW.ts new file mode 100644 index 0000000..e1f8153 --- /dev/null +++ b/src/client/locales-zh-TW.ts @@ -0,0 +1,360 @@ +/** + * The zh-HK (Traditional Chinese — Hong Kong) dictionary for the betterSidebar + * namespace. + * + * Mirrors the key set of `zh` in `locales.ts`. Consumed by better-locale's + * override store when the active override id is `'zh-HK'` (registered under + * the `betterSidebar` namespace). Absent that, the existing zh/en chain + * runs unchanged. + * + * Hong Kong regional conventions: + * - 软件 → 軟體 (NOT 軟體); 网络 → 網路 (NOT 網路); 鼠标 → 滑鼠 + * - 檔案 (file), 資料夾 (folder), 程式 (program), 程式碼 (code), 螢幕 (screen) + * - 預設 (default), 儲存 (save), 設定 (settings/config), 唯讀 (read-only) + * - 資源管理器 → 檔案總管; refresh → 重新整理; cache → 快取 + * - timeout → 逾時; loop → 迴圈; override → 覆寫; built-in → 內建 + * - adapter → 介面卡; interface → 介面; address → 位址; field → 欄位 + * - byte → 位元組; binary → 二進位; character → 字元; hash → 雜湊 + * - rename → 重新命名; archive → 歸檔; idle → 閒置; mount → 掛載 + * - package → 套件; generate → 產生; fetch → 取得; export → 匯出 + * - login → 登入; detect → 偵測; block → 封鎖; access → 存取 + * - port → 連接埠; sensor → 感測器; server → 伺服器; global → 全域 + * - nested → 巢狀; thread → 執行緒; queue → 佇列; tab → 標籤 + * - source code → 原始碼; symlink → 符號連結; recover → 復原 + * - placeholder → 佔位符; template → 範本; variable → 變數 + * - through → 透過; paste → 貼上; project → 專案; account → 帳號 + * - session (会话) → 工作階段; chat (对话) → 對話 + * - quotation marks: "" → 「」 + * - Placeholders keep `{name}` verbatim (interpolation runs after lookup). + * - English brand names (VS Code, Cursor, Zed, SSH, Git, Chrome) stay as-is. + */ + +/** The zh-HK dictionary (key-set-equal to zh, enforced by the type annotation in locales.ts). */ +export const zhTW: Record = { + files: '檔案', + explorer: '檔案總管', + git: '原始碼管理', + terminal: '終端', + editor: '編輯器', + editorExplorer: '檔案開啟方式', + editorExplorerDesc: '控制檔案開啟方式', + editorExplorerMerged: '合併', + editorExplorerMergedDesc: '檔案在同一視窗內原地切換;新視窗預設展開檔案樹', + editorExplorerSplit: '獨立', + editorExplorerSplitDesc: '無路徑視窗即檔案總管(僅檔案樹);檔案各自新開視窗(帶檔案樹,預設收起)', + editorTreeToggle: '檔案樹面板', + editorPathPlaceholder: '輸入檔案路徑(相對工作階段目錄或絕對路徑),Enter 開啟', + editorSearchPlaceholder: '按檔案名稱搜尋…', + editorSearchNoResults: '無匹配檔案', + editorSearchTruncated: '結果過多,僅顯示部分匹配', + editorEmptyHint: '從右側檔案樹或上方路徑輸入框選擇檔案開始預覽', + openFileNewTab: '在新 Tab 中開啟', + openFileSide: '在側邊開啟', + openWithMenu: '在應用程式中開啟', + openWithSshSuffix: ' (SSH)', + pinOpenWith: '固定到選單', + unpinOpenWith: '取消固定', + openWithExplorer: '檔案總管', + openWithVscode: 'VS Code', + openWithCursor: 'Cursor', + openWithZed: 'Zed', + openWithSettingsSshTitle: 'SSH 遠端主機', + openWithSettingsSshDesc: '留空為本地工作區;填入 user@host 或 SSH 別名後,VSCode 系開啟方式將改用 vscode-remote/ssh-remote 協議,檔案總管 / Zed / 非 VSCode 系自訂編輯器將從選單隱藏', + openWithSettingsSshPlaceholder: 'user@host 或 SSH 別名', + openWithSettingsCustomTitle: '自訂編輯器', + openWithSettingsCustomDesc: '名稱 + URL 範本({path} 佔位符)+ 是否 VSCode 系;SSH 模式下僅 VSCode 系可開啟遠端', + openWithSettingsAdd: '新增', + openWithSettingsName: '名稱', + openWithSettingsTemplate: '如 cursor://file/{path}', + openWithSettingsFamily: 'VSCode 系', + openWithSettingsFamilyDesc: '該編輯器使用 VSCode 的 URL 協議(支援 SSH 遠端開啟)', + openWithSettingsRemove: '刪除', + openWithSettingsInvalidHint: '名稱或範本(需含 {path} 且以 scheme:// 開頭)未填寫的編輯器不會出現在選單中', + newTab: '新增標籤', + openExplorer: '檔案總管', + brokenSymlink: '失效的符號連結', + openGit: 'Git 面板', + newTerminal: '新終端', + terminalLimit: '終端數量已達上限 (3)', + close: '關閉', + closeOtherTabs: '關閉其他標籤', + closeLeftTabs: '關閉左側標籤', + closeRightTabs: '關閉右側標籤', + collapse: '收起側邊欄', + expand: '展開側邊欄', + collapseBottomPanel: '收起底部面板', + expandBottomPanel: '展開底部面板', + terminalError: '終端連線失敗', + terminalConnectFailed: '終端多次連線失敗', + terminalRetry: '重試', + terminalDepsFailed: '終端依賴 node-pty 載入失敗', + terminalDepsHint: '在 DSH 所在環境的終端或 cmd 中執行以下命令修復,然後點重試(node-pty 與 DSH 核心保持同一版本):', + terminalDepsProfile: '(偵測到 profile:{profile})', + preview: '預覽', + edit: '編輯', + mermaidError: 'Mermaid 渲染失敗', + mermaidZoomIn: '放大', + mermaidZoomOut: '縮小', + mermaidZoomReset: '重設', + mermaidZoomHint: '滾輪縮放 · 拖曳平移 · Esc 關閉', + refresh: '重新整理', + save: '儲存', + saved: '已儲存', + unsaved: '未儲存', + saveFailed: '儲存失敗', + truncation: '檔案過大,僅顯示前 512KB', + binary: '二進位檔案,無法預覽', + loading: '載入中…', + error: '載入失敗', + retry: '重試', + splitLeft: '向左分欄', + splitRight: '向右分欄', + splitUp: '向上分欄', + splitDown: '向下分欄', + notRepo: '目前目錄不是 git 倉庫', + noChanges: '沒有變更', + stage: '暫存', + unstage: '取消暫存', + stageAll: '全部暫存', + unstageAll: '全部取消暫存', + commitPlaceholder: '提交訊息 (Ctrl+Enter)', + commit: '提交', + commitError: '提交失敗', + branch: '分支', + checkoutError: '切換分支失敗', + history: '歷史', + changes: '變更', + staged: '已暫存', + unstaged: '未暫存', + cancel: '取消', + diffEmpty: '沒有文字差異', + diffLoadError: '載入差異失敗', + diffBinary: '二進位', + diffAdded: '新增', + diffDeleted: '刪除', + diffRenamed: '重新命名', + diffExpand: '展開其餘 {count} 行', + diffCollapse: '收起', + discard: '放棄變更', + discardTitle: '放棄變更', + discardDesc: '將丟棄「{path}」的工作區修改(不可復原)。', + viewCommitDiff: '檢視提交差異', + copyShortHash: '複製短雜湊', + copyFullHash: '複製完整雜湊', + copySubject: '複製提交訊息', + revertCommit: '還原此提交', + revertTitle: '還原此提交', + revertDesc: '將在目前分支建立一個反轉「{subject}」的新提交。', + cherryPickCommit: '撿取此提交', + cherryPickTitle: '撿取此提交', + cherryPickDesc: '將「{subject}」的變更套用到目前分支。', + timeJustNow: '剛剛', + timeMinutesAgo: '{n} 分鐘前', + timeHoursAgo: '{n} 小時前', + timeYesterday: '昨天', + loadMore: '載入更多', + historyLoadError: '載入更多歷史失敗', + produced: '本次產出', + producedOpen: '在側邊欄中開啟', + disconnected: '終端連線斷開,重新連線中…', + exited: '終端程序已退出', + noSession: '選擇一個工作階段以使用側邊欄', + pluginNotLoaded: '插件未載入,標籤暫不可用:', + hiddenFiles: '隱藏檔案', + parent: '上層目錄', + copied: '已複製', + copy: '複製', + newFile: '新檔案', + openEditor: '開啟編輯器', + gitDetail: '檢視變更詳情', + referenceFile: '@檔案', + addToConversation: '新增到對話', + copyRelative: '複製相對位址', + copyAbsolute: '複製絕對位址', + download: '下載', + uploadFiles: '上傳檔案', + uploadFolder: '上傳資料夾', + uploadHere: '上傳到此處', + uploadDropHint: '拖曳檔案/資料夾到此處上傳', + uploadDropChat: '拖放到聊天區:新增圖片到對話', + uploadTo: '上傳到 {dir}', + uploadingTo: '正在上傳到 {dir}…', + uploadProgress: '正在上傳 {done}/{total}: {name}', + uploadDone: '已上傳 {count} 個檔案', + uploadFailed: '上傳失敗:{error}', + uploadFailedUnknown: '未知錯誤', + uploadTooLarge: '檔案過大,超出上傳上限', + uploadCancelled: '上傳已取消', + settingsNav: '側邊卡片', + settingsIntro: '管理側邊卡片的顯示內容與預設行為', + settingsPopupDesc: '為「{feature}」設定相關選項', + settingsDone: '完成', + settingsOpenTitle: '新工作階段預設開啟', + settingsOpenDesc: '新增工作階段時自動展開側邊卡片;已存在的工作階段保持各自佈局', + settingsWidthTitle: '預設寬度佔比', + settingsWidthDesc: '新增工作階段時側邊卡片佔視窗寬度的百分比 (20–60)', + settingsWidthSuffix: '%', + settingsOpenPathTitle: '聊天區檔案在側邊欄開啟', + settingsOpenPathDesc: '在聊天裡點擊檔案連結(工具行、產物列表、檔案提及)時,在側邊欄編輯器中開啟,不再呼叫系統預設應用程式', + settingsTitleBarTitle: '位置相容模式', + settingsTitleBarDesc: '選擇頂欄相容方案:自動偵測(預設,保守)/ DSH官方Web / 已知桌面殼 / 自訂方案(下移距離 + 自訂 CSS)', + settingsTitleBarStripTitle: '下移距離', + settingsTitleBarStripDesc: '標題欄條帶高度:側邊欄按鈕與內容下移的像素數(0–120,預設 40;自訂方案下生效)', + settingsSchemeAutoTitle: '自動偵測', + settingsSchemeAutoDesc: '保守方案:僅在 Window Controls Overlay 標準 API 可用時按真實標題欄高度讓位;網頁環境下不做任何修改', + settingsSchemeWebTitle: 'DSH官方Web', + settingsSchemeWebDesc: '顯式宣告執行在官方網頁版:不做任何適配(連標準 WCO 幾何也不適用)', + settingsSchemeCustomTitle: '自訂方案', + settingsSchemeCustomDesc: '完全由你控制:注入自訂 CSS(可覆寫內建樣式),並指定標題欄下移距離', + settingsSchemeDetectedSuffix: '已偵測', + settingsCustomCssTitle: '自訂 CSS', + settingsCustomCssDesc: '附加到頁面末尾的樣式(同優先級下後寫勝出;覆寫 JS 內聯變數需用 !important)', + settingsCustomCssPlaceholder: '/* 例:為自繪標題欄的殼預留 36px */\nhtml[data-dsh-title-bar-height="36"] {\n --dsh-title-bar-strip: 36px !important;\n}', + settingsSaveFailed: '儲存失敗', + settingsConflict: '設定已被其他視窗修改,請重試', + binaryNoPreview: '此檔案類型不支援預覽', + downloadToView: '下載檢視', + settingsSubagentTitle: '偵測到子代理時自動展開任務管理頁', + settingsSubagentDesc: '目前工作階段產生新的子代理時,自動展開側邊欄並開啟任務管理頁;關閉後需手動開啟', + settingsJobsTitle: '有新背景任務時自動展開背景任務頁', + settingsJobsDesc: '目前工作階段出現新的背景任務時,自動展開側邊欄並開啟背景任務頁(每個新任務都會觸發);關閉後需手動開啟', + settingsToolsTitle: '為模型注入終端工具', + settingsToolsDesc: '開啟後,模型可透過 terminal_create 等 8 個工具建立並操作側邊欄終端(預設關閉)', + settingsBottomTerminalTitle: '底部面板首次展開自動開終端', + settingsBottomTerminalDesc: '每次工作階段中第一次展開底部面板時,嘗試在底部面板自動開啟一個新終端標籤(終端數量上限仍會限制;預設開啟)', + settingsFontFamilyTitle: '終端字體', + settingsFontFamilyDesc: '自訂終端字體族(CSS font-family,如 "JetBrains Mono", monospace;留空跟隨主題等寬字體)', + settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace', + settingsFontSizeTitle: '終端字型大小', + settingsFontSizeDesc: '終端字型大小(9–32,預設 13)', + settingsFontSizeSuffix: 'px', + settingsShellTitle: 'Shell 路徑', + settingsShellDesc: 'UI 與模型終端啟動的 shell(絕對路徑或可執行名)。留空按既有順序解析:yaml 的 config.shell → $SHELL / 登入 shell / Windows 的 powershell.exe。對之後開啟的終端生效', + settingsShellPlaceholder: '如 /bin/zsh(留空自動解析)', + settingsShellArgsTitle: 'Shell 參數', + settingsShellArgsDesc: '顯式 shell 啟動參數,空格分隔;非空時完全替換預設參數(與 yaml 的 shellArgs 契約一致)', + settingsShellArgsPlaceholder: '如 -l(留空用預設參數)', + settingsTabsTitle: '側邊欄內容', + settingsViewersTitle: '檔案預覽', + settingsGeneralTitle: '一般', + settingsPopup: '功能設定', + settingsViewerCatchAll: '兜底:任意檔案', + viewerImage: '圖片', + viewerPdf: 'PDF', + viewerMarkdown: 'Markdown', + viewerCode: '程式碼', + viewerBinary: '二進位下載', + viewerHtml: 'HTML', + browser: '瀏覽器', + browserPlaceholder: '輸入網址,例如 example.com', + browserGo: '前往', + browserBack: '上一頁', + browserForward: '下一頁', + browserStart: '輸入網址開始瀏覽(沙箱模式)', + browserBlockedScheme: '已封鎖:僅支援 http/https 連結', + browserBlockedLoopback: '已封鎖:不允許在瀏覽器中存取本機或內部位址', + browserInvalid: '無效的網址', + browserNoSandboxWarning: '沙箱已關閉:目前頁面與介面同源,擁有完整工作階段權限(可在設定中恢復)', + htmlNoSandboxWarning: '沙箱已關閉:此 HTML 與介面同源,可讀取工作階段檔案與內部介面(可在設定中恢復)', + sandboxStatusOn: '沙箱模式:已啟用 · 頁面無法存取介面資料與本地檔案,登入態與第三方 Cookie 可能不可用', + sandboxUnlock: '臨時解鎖(不安全)', + sandboxRestore: '恢復沙箱', + settingsHtmlDefaultUnsafeTitle: 'HTML 預覽預設以非沙箱模式開啟(不安全)', + settingsHtmlDefaultUnsafeDesc: '開啟後,每次開啟 HTML 檔案時預覽預設處於非沙箱狀態(與介面同源,可讀取工作階段檔案與內部介面);可在狀態列臨時恢復沙箱', + settingsHtmlSandboxTitle: '關閉 HTML 預覽沙箱(不安全)', + settingsHtmlSandboxDesc: '關閉後,預覽的 HTML 將與介面同源執行,可讀取工作階段檔案、本地儲存並呼叫內部介面。僅對完全可信的檔案開啟', + settingsBrowserSandboxTitle: '關閉瀏覽器沙箱(不安全)', + settingsBrowserSandboxDesc: '關閉後,存取的任何網站都將與介面同源執行,可讀取工作階段資料並冒充你的登入狀態。僅對完全可信的網站開啟', + settingsBrowserLinksTitle: '聊天區外鏈在側邊欄開啟', + settingsBrowserLinksDesc: '開啟後,點擊聊天或介面中的外鏈時在側邊欄開啟,不再彈出新視窗;HTTP 與 HTTPS 可分別透過下方開關控制;Ctrl/Cmd 點擊可臨時放行', + settingsBrowserHttpTitle: '側邊開啟HTTP網頁', + settingsBrowserHttpDesc: '開啟後,點擊聊天或介面中的 HTTP 外鏈時在側邊欄開啟(宣告了 urlTarget 的插件頁面優先);Ctrl/Cmd 點擊可臨時放行', + settingsBrowserHttpsTitle: '側邊開啟HTTPS網頁', + settingsBrowserHttpsDesc: '開啟後,點擊聊天或介面中的 HTTPS 外鏈時在側邊欄開啟。預設關閉:多數 HTTPS 網站拒絕被嵌入,走系統瀏覽器更順暢', + browserOpenExternal: '在瀏覽器中開啟', + browserEmbedBlocked: '{host} 拒絕了嵌入請求', + browserEmbedBlockedDesc: '該網站透過 X-Frame-Options / frame-ancestors 禁止在其它頁面中顯示,無法在側邊欄內載入。可在瀏覽器中直接開啟', + browserEmbedAnyway: '仍然載入', + subagent: '任務管理', + openSubagent: '任務管理', + subagentMainAgent: '主代理', + subagentEmpty: '暫無子代理', + subagentEmptyDesc: '目前主代理派生的子代理將顯示在這裡', + subagentRunning: '執行中', + subagentInactive: '閒置', + subagentModeOneShot: '一次性', + subagentModeContinuable: '可續接', + subagentCount: '{count} 個子代理', + subagentCountRunning: '{count} 個子代理 · {running} 執行中', + subagentDiagCorrupt: '目錄損壞', + subagentDiagUnsupported: '不支援的條目', + subagentDiagUnavailable: '不可用', + subagentThinking: '思考中…', + sideChat: '側邊對話(beta)', + sideChatNew: '新增對話', + sideChatUntitled: '新對話', + sideChatEmpty: '暫無側邊對話', + sideChatEmptyDesc: '每個側邊對話是標籤列裡的獨立 Tab,繼承目前工作階段的上下文執行,不會進入主工作階段', + sideChatCreating: '正在建立側邊對話…', + sideChatRetry: '重試', + sideChatThreads: '切換執行緒 / 新增', + sideChatSave: '儲存為新工作階段', + sideChatSaveTitle: '把該執行緒提升為頂層工作階段,出現在主工作階段列表中', + sideChatSaved: '已儲存為新工作階段', + sideChatNoTurn: '至少完成一輪對話後才能儲存', + sideChatPendingDrop: '最後一則未完成的追問不會包含在新工作階段中', + sideChatFirstPlaceholder: '輸入第一個問題,已繼承目前工作階段上下文…', + sideChatComposerPlaceholder: '追問…', + sideChatThinking: '正在深入…', + sideChatThink: '思考過程', + sideChatInjection: '已注入上下文', + sideChatSend: '發送', + sideChatCancel: '停止', + sideChatCancelTitle: '中止目前回合(保留佇列)', + sideChatClose: '關閉執行緒', + sideChatCloseTitle: '釋放執行緒的 agent(歷史保留)', + sideChatError: '側邊對話出錯:{message}', + jobs: '背景任務', + jobsCount: '{count} 個背景任務', + jobsCountRunning: '{count} 個背景任務 · {running} 執行中', + jobStatusRunning: '執行中', + jobStatusStopping: '終止中', + jobStatusCompleted: '已完成', + jobStatusKilled: '已終止', + jobStatusFailed: '失敗', + jobDurationSeconds: '{seconds} 秒', + jobDurationMinutes: '{minutes} 分 {seconds} 秒', + jobDurationHours: '{hours} 小時 {minutes} 分', + jobViewOutput: '檢視輸出', + jobHideOutput: '收起輸出', + jobNoOutput: '暫無輸出', + jobNotReadYet: '等待模型讀取該任務的輸出(模型執行 job_output 後,輸出會顯示在這裡)', + jobOutputTruncated: '輸出過長,已截斷顯示', + jobOutputError: '輸出讀取失敗', + jobKill: '終止', + jobKillConfirm: '再次點擊確認終止', + jobKillError: '終止失敗', + addPluginsTabCard: '新增 Tab 插件', + addPluginsTabCardDesc: '註冊新的側邊欄頁面', + addPluginsViewerCard: '新增預覽插件', + addPluginsViewerCardDesc: '註冊新的檔案類型預覽', + addPluginsTabDesc: '側邊欄頁面(Tab)可以由插件擴展。插件透過 ctx.betterSidebar 服務註冊;點擊「安裝」複製安裝命令,貼到 DSH 所在環境的終端執行。', + addPluginsViewerDesc: '檔案預覽器可以由插件擴展。插件透過 ctx.betterSidebar 服務註冊;點擊「安裝」複製安裝命令,貼到 DSH 所在環境的終端執行。', + addPluginsBrowseMore: '在 GitHub 上瀏覽更多插件(topic: dsh-better-sidebar)', + addPluginsSearch: '搜尋插件名稱 / 描述…', + addPluginsNoMatch: '沒有匹配的插件', + addPluginsRecommended: '推薦插件', + addPluginsEmpty: '暫未收錄插件,歡迎在 GitHub topic 下發布你的插件', + openPlugin: '跳轉', + copyInstall: '複製安裝命令', + pluginOfficeDesc: '為 better-sidebar 編輯器提供 Office 三件套預覽(.docx / .xlsx / .pptx),把重型 Office 渲染庫拆出主套件、按需安裝', + pluginFlowglassDesc: '即時工作階段流程圖:三列泳道展示使用者、助手與工具呼叫,支援並行分組、子代理支線、逐層鑽取和即時狀態;安裝 better-sidebar 後註冊原生「流鏡」Tab,未安裝時保留獨立抽屜', + pluginGitForgeDesc: 'better-sidebar「Git 憑證」Tab:GitHub/Gitea 等 Forge 帳號庫 + 按專案授權 + push 策略硬攔;token 僅存本地 secrets,不進模型上下文;提供唯讀 GitForge 工具與 agent HTTPS credential helper', + pluginGitRemotesDesc: 'better-sidebar Git 遠端 Tab:看分支/上游/ahead-behind,fetch(可 prune)、ff-only pull、確認後才 push。不替換內建 Git 的暫存/提交,也不提供 force-push 或模型自動推送', + pluginSentinelDesc: '條件驅動的 agent 喚醒系統:檔案/程序/連接埠/HTTP/命令/webhook 感測器,條件達成自動喚醒休眠工作階段;註冊「哨兵」Tab 展示伺服器全域監控表', + pluginSidebarQaDesc: '基於 better-sidebar 的劃選提問tab分頁: 對話劃選 → 右側面板提問 → 同工作區獨立追問工作階段(❓追問·主題):快速無思考模型壓縮主對話上下文後與引文一起注入,不打斷主對話;追問可巢狀、可繼續、可歸檔', + pluginSshTunnelDesc: 'better-sidebar「SSH 隧道」Tab:多機主機清單 + 按專案授權 + 密鑰本地保管;模型工具 SSHManager(exec/SFTP/工作階段策略);中央互動終端與雙欄 SFTP', + pluginTurnReviewDesc: '對「剛剛這一回合」的 diff 做 Approve / Request changes 的人閘門:只審上一回合,不 fork 工作階段;檔案按主工作階段/子代理/未歸因分組,按檔案勾選打回 + 可選評語,點檔案先看回合開始快照 vs 現在的 diff。不是 /rewind', + pluginVideoPreviewDesc: '在 better-sidebar 編輯器內聯預覽影片檔案(.mp4/.webm/.mov/.mkv/.avi 等),自帶支援 HTTP Range(206)的 /video 宿主路由,可拖曳進度條、不受 20MB mediaLimit 限制', + pluginDocsPanelDesc: 'DSH 側邊欄裡的「全域文件」:全域 Markdown 筆記,任何工作區隨時可讀——列表點選閱讀、懸浮大綱跳轉、Chrome / VS Code 外部開啟、程式碼複製,目錄可設定(預設 ~/.dsh/docs)', +} diff --git a/src/client/locales.ts b/src/client/locales.ts index 86bf928..f2a4413 100644 --- a/src/client/locales.ts +++ b/src/client/locales.ts @@ -691,9 +691,45 @@ export const LOCALE_NS = 'betterSidebar' // stays readable. Type-checked against the zh key set: a missing or extra // ja key is a compile error. import { ja as jaDict } from './locales-ja.ts' +import { de as deDict } from './locales-de.ts' +import { fr as frDict } from './locales-fr.ts' +import { pt as ptDict } from './locales-pt.ts' +import { ko as koDict } from './locales-ko.ts' +import { ar as arDict } from './locales-ar.ts' +import { hi as hiDict } from './locales-hi.ts' +import { id as idDict } from './locales-id.ts' +import { tr as trDict } from './locales-tr.ts' +import { vi as viDict } from './locales-vi.ts' +import { th as thDict } from './locales-th.ts' +import { ru as ruDict } from './locales-ru.ts' +import { it as itDict } from './locales-it.ts' +import { nl as nlDict } from './locales-nl.ts' +import { sv as svDict } from './locales-sv.ts' +import { pl as plDict } from './locales-pl.ts' +import { zhHK as zhHKDict } from './locales-zh-HK.ts' +import { zhTW as zhTWDict } from './locales-zh-TW.ts' +import { zhMO as zhMODict } from './locales-zh-MO.ts' /** The ja dictionary (key-set-equal to zh, enforced by the type annotation). */ export const ja: Record = jaDict as Record +export const de: Record = deDict as Record +export const fr: Record = frDict as Record +export const pt: Record = ptDict as Record +export const ko: Record = koDict as Record +export const ar: Record = arDict as Record +export const hi: Record = hiDict as Record +export const id: Record = idDict as Record +export const tr: Record = trDict as Record +export const vi: Record = viDict as Record +export const th: Record = thDict as Record +export const ru: Record = ruDict as Record +export const it: Record = itDict as Record +export const nl: Record = nlDict as Record +export const sv: Record = svDict as Record +export const pl: Record = plDict as Record +export const zhHK: Record = zhHKDict as Record +export const zhTW: Record = zhTWDict as Record +export const zhMO: Record = zhMODict as Record /** The DSH locale service attached by the client apply (absent → browser detection). */ let localeService: { getSnapshot(): { active: string } } | undefined From f58e361cbe1807eeee93a73c4fc6b516560b4725 Mon Sep 17 00:00:00 2001 From: HuanLinOTO Date: Sun, 23 Aug 2026 16:56:07 +0800 Subject: [PATCH 5/6] fix(i18n): guard ctx.get call so absent better-locale is truly no-op MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sidebar.tsx read ctx.get('betterLocale') unconditionally. In real cordis hosts ctx.get exists and returns undefined when better-locale is absent — but the unit-test mocks build a minimal ctx without a get method, throwing 'TypeError: ctx.get is not a function' inside render and taking down 7 tests (bottom-auto-terminal + sidebar-crash suites). Add a typeof guard so the optional contract holds even when ctx.get is missing. The activation-order-safe ctx.effect path in index.tsx is unaffected (real cordis Context, runs once). --- src/client/Sidebar.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/client/Sidebar.tsx b/src/client/Sidebar.tsx index 77efde3..d7c8c07 100644 --- a/src/client/Sidebar.tsx +++ b/src/client/Sidebar.tsx @@ -197,14 +197,17 @@ export function Sidebar(props: { ctx: Context; store: SidebarStore }) { // re-render. This second uSES reads the better-locale store's `active` // directly, so an override switch fires a full re-render and t() picks // up the new override text. Optional: ctx.get returns undefined when - // better-locale is absent, in which case this is a no-op uSES. + // better-locale is absent (or when ctx is a minimal test mock without + // a `get` method), in which case this is a no-op uSES. type BetterLocaleStore = { readonly active: string | undefined subscribe(listener: () => void): () => void } - const betterLocaleStore = (ctx as unknown as { - get(name: 'betterLocale'): BetterLocaleStore | undefined - }).get('betterLocale') + const betterLocaleStore = typeof ctx.get === 'function' + ? (ctx as unknown as { + get(name: 'betterLocale'): BetterLocaleStore | undefined + }).get('betterLocale') + : undefined const betterLocaleActive = useSyncExternalStore( useMemo(() => { const store = betterLocaleStore From 4af8d3121ad97a210b454c91c5a70be70836ab5d Mon Sep 17 00:00:00 2001 From: HuanLinOTO Date: Sun, 23 Aug 2026 19:42:24 +0800 Subject: [PATCH 6/6] =?UTF-8?q?fix:=20devDependency=20=E6=94=B9=E7=94=A8?= =?UTF-8?q?=20npm=20registry=20=E7=89=88=E6=9C=AC=EF=BC=8C=E5=8E=BB?= =?UTF-8?q?=E6=8E=89=E6=9C=AC=E6=9C=BA=20link=20=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- pnpm-lock.yaml | 48 +++++++++++++++++++++++++++++++++++++++++++-- pnpm-workspace.yaml | 16 ++++++--------- 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 5a0bb2a..b7c0ec8 100644 --- a/package.json +++ b/package.json @@ -158,7 +158,7 @@ "@deepseek-ai/dsh-settings": "0.1.1-rc.1", "@deepseek-ai/dsh-subagent": "0.1.1-rc.1", "@deepseek-ai/dsh-tools": "0.1.1-rc.1", - "@huanlin/dsh-plugin-better-locale": "link:D:/Projects/deepseek-harness/dsh-plugin-better-locale", + "@huanlin/dsh-plugin-better-locale": "^0.1.0", "@playwright/test": "^1.62.1", "@types/node": "^24.0.0", "@types/react": "~18.3.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 16a4b8e..1e75c65 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -142,8 +142,8 @@ importers: specifier: 0.1.1-rc.1 version: 0.1.1-rc.1(5493e0ab460eb504a0593977b284c2a8) '@huanlin/dsh-plugin-better-locale': - specifier: link:D:/Projects/deepseek-harness/dsh-plugin-better-locale - version: link:../dsh-plugin-better-locale + specifier: ^0.1.0 + version: 0.1.0(cb831dcffe1fb561624a57e14d05c62c) '@playwright/test': specifier: ^1.62.1 version: 1.62.1 @@ -1052,6 +1052,37 @@ packages: '@noble/hashes': optional: true + '@huanlin/dsh-plugin-better-locale@0.1.0': + resolution: {integrity: sha512-fGXDgVq1R3gVTi2M9TMn2x5ROqiaYkhEsFJqYF5xiVUFfs9KjwIpOF0ZbhUyK6vFBOeYP4uetc/ZVknQb38WrQ==} + engines: {node: '>=22.0.0'} + peerDependencies: + '@deepseek-ai/cordis': ^4.0.1-rc.1 + '@deepseek-ai/dsh-client-locale': ^0.1.0-rc.8 + '@deepseek-ai/dsh-client-runtime': ^0.1.0-rc.8 + '@deepseek-ai/dsh-client-ui-primitives': ^0.1.0-rc.8 + '@deepseek-ai/dsh-client-ui-settings': ^0.1.0-rc.8 + '@deepseek-ai/dsh-client-ui-slots': ^0.1.0-rc.8 + '@deepseek-ai/dsh-invariants': ^0.1.0-rc.8 + react: ^18.2.0 + react-dom: ^18.2.0 + peerDependenciesMeta: + '@deepseek-ai/dsh-client-locale': + optional: true + '@deepseek-ai/dsh-client-runtime': + optional: true + '@deepseek-ai/dsh-client-ui-primitives': + optional: true + '@deepseek-ai/dsh-client-ui-settings': + optional: true + '@deepseek-ai/dsh-client-ui-slots': + optional: true + '@deepseek-ai/dsh-invariants': + optional: true + react: + optional: true + react-dom: + optional: true + '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} @@ -3678,6 +3709,19 @@ snapshots: '@exodus/bytes@1.15.1': {} + '@huanlin/dsh-plugin-better-locale@0.1.0(cb831dcffe1fb561624a57e14d05c62c)': + dependencies: + '@deepseek-ai/cordis': 4.0.1(@deepseek-ai/cordis-plugin-include@1.0.6)(@deepseek-ai/cordis-plugin-loader@1.0.2) + optionalDependencies: + '@deepseek-ai/dsh-client-locale': 0.1.1-rc.1(cdf31bdbf1c332c5404cbf36a25aebfd) + '@deepseek-ai/dsh-client-runtime': 0.1.1-rc.1(114626bcc5e5280d3934a64ac9cf965f) + '@deepseek-ai/dsh-client-ui-primitives': 0.1.1-rc.1(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.1-rc.1(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-client-ui-settings': 0.1.1-rc.1(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-api-remotes@0.1.1-rc.1(0dbd24110e04aadb9415a7fc081ef3f0))(@deepseek-ai/dsh-client-connection@0.1.1-rc.1)(@deepseek-ai/dsh-client-runtime@0.1.1-rc.1(114626bcc5e5280d3934a64ac9cf965f))(@deepseek-ai/dsh-invariants@0.1.1-rc.1(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/dsh-settings@0.1.1-rc.1(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-brand@0.1.1-rc.1(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.1-rc.1(@deepseek-ai/cordis@4.0.1)))(@deepseek-ai/dsh-invariants@0.1.1-rc.1(@deepseek-ai/cordis@4.0.1))(@deepseek-ai/schemastery@3.18.1)) + '@deepseek-ai/dsh-client-ui-slots': 0.1.1-rc.1(@deepseek-ai/cordis@4.0.1)(@deepseek-ai/dsh-invariants@0.1.1-rc.1(@deepseek-ai/cordis@4.0.1)) + '@deepseek-ai/dsh-invariants': 0.1.1-rc.1(@deepseek-ai/cordis@4.0.1) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + '@iconify/types@2.0.0': {} '@iconify/utils@3.1.4': diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 3215c13..2c68e76 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -10,10 +10,10 @@ allowBuilds: minimumReleaseAgeExclude: - '@deepseek-ai/*' - - '@deepseek-ai/cordis-plugin-include@1.0.5-rc.1' - - '@deepseek-ai/cordis-plugin-loader@1.0.1-rc.1' - - '@deepseek-ai/cordis@4.0.1-rc.1' - - '@deepseek-ai/cosmokit@1.8.2-rc.1' + - '@deepseek-ai/cordis-plugin-include@1.0.5-rc.1 || 1.0.6' + - '@deepseek-ai/cordis-plugin-loader@1.0.1-rc.1 || 1.0.2' + - '@deepseek-ai/cordis@4.0.1-rc.1 || 4.0.1' + - '@deepseek-ai/cosmokit@1.8.2-rc.1 || 1.8.2' - '@deepseek-ai/dsh-agent-default-model@0.0.1-rc.1' - '@deepseek-ai/dsh-agent-presets@0.0.1-rc.1' - '@deepseek-ai/dsh-agent@0.0.1-rc.1' @@ -65,9 +65,5 @@ minimumReleaseAgeExclude: - '@deepseek-ai/dsh-user-approval@0.0.1-rc.1' - '@deepseek-ai/dsh-user-interaction@0.0.1-rc.1' - '@deepseek-ai/dsh-workspace@0.0.1-rc.1' - - '@deepseek-ai/schemastery@3.18.1-rc.1' - - '@deepseek-ai/cordis-plugin-include@1.0.6' - - '@deepseek-ai/cordis-plugin-loader@1.0.2' - - '@deepseek-ai/cordis@4.0.1' - - '@deepseek-ai/cosmokit@1.8.2' - - '@deepseek-ai/schemastery@3.18.1' + - '@deepseek-ai/schemastery@3.18.1-rc.1 || 3.18.1' + - '@huanlin/dsh-plugin-better-locale@0.1.0'