diff --git a/Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/ConfigValidation/CmuxConfigSchema.generated.swift b/Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/ConfigValidation/CmuxConfigSchema.generated.swift index 308f0dfbb70f..e9e41f3c4963 100644 --- a/Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/ConfigValidation/CmuxConfigSchema.generated.swift +++ b/Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/ConfigValidation/CmuxConfigSchema.generated.swift @@ -1337,6 +1337,11 @@ enum CmuxEmbeddedConfigSchema { "default": false, "description": "Allow workspace titles in the sidebar to wrap to multiple lines instead of truncating after one line." }, + "twoLineWorkspaceTitles": { + "type": "boolean", + "default": false, + "description": "Allow a workspace title in the sidebar a second line before it is truncated, instead of showing it in full like wrapWorkspaceTitles." + }, "showWorkspaceDescription": { "type": "boolean", "default": true, diff --git a/Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/SidebarCatalogSection.swift b/Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/SidebarCatalogSection.swift index 457c04953b9c..1ec6dcc0442d 100644 --- a/Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/SidebarCatalogSection.swift +++ b/Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/SidebarCatalogSection.swift @@ -27,6 +27,16 @@ public struct SidebarCatalogSection: SettingCatalogSection { userDefaultsKey: "sidebarWrapWorkspaceTitles" ) + /// Allows a workspace title a second line before it is truncated. A middle + /// ground between one line and `wrapWorkspaceTitles`, which shows a title in + /// full however many lines that takes. Off by default: one line per row + /// keeps the list scannable. + public let twoLineWorkspaceTitles = DefaultsKey( + id: "sidebar.twoLineWorkspaceTitles", + defaultValue: false, + userDefaultsKey: "sidebarTwoLineWorkspaceTitles" + ) + public let showWorkspaceDescription = DefaultsKey( id: "sidebar.showWorkspaceDescription", defaultValue: true, diff --git a/Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/CuratedSettingEntry+Default.swift b/Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/CuratedSettingEntry+Default.swift index ec7ef6b3f70e..c84d93676db6 100644 --- a/Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/CuratedSettingEntry+Default.swift +++ b/Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/CuratedSettingEntry+Default.swift @@ -296,6 +296,7 @@ extension Array where Element == CuratedSettingEntry { .init(section: .sidebarAppearance, id: "match-terminal", title: String(localized: "settings.sidebarAppearance.matchTerminalBackground", defaultValue: "Match Terminal Background"), synonyms: "Match Terminal Background sidebarAppearance.matchTerminalBackground transparent background material terminal background sync"), .init(section: .sidebarAppearance, id: "hide-sidebar-details", title: String(localized: "settings.app.hideAllSidebarDetails", defaultValue: "Hide All Sidebar Details"), synonyms: "Hide All Sidebar Details sidebar.hideAllDetails compact sidebar hide details only title minimal left rail"), .init(section: .sidebarAppearance, id: "wrap-workspace-titles", title: String(localized: "settings.app.wrapWorkspaceTitles", defaultValue: "Wrap Workspace Titles in Sidebar"), synonyms: "Wrap Workspace Titles in Sidebar sidebar.wrapWorkspaceTitles workspace title wrap multiline pr pull request"), + .init(section: .sidebarAppearance, id: "two-line-workspace-titles", title: String(localized: "settings.app.twoLineWorkspaceTitles", defaultValue: "Allow Two Lines for Workspace Titles"), synonyms: "Allow Two Lines for Workspace Titles sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten"), .init(section: .sidebarAppearance, id: "show-workspace-description", title: String(localized: "settings.app.showWorkspaceDescription", defaultValue: "Show Workspace Description in Sidebar"), synonyms: "Show Workspace Description in Sidebar sidebar.showWorkspaceDescription workspace description notes markdown sidebar"), .init(section: .sidebarAppearance, id: "workspace-description-color", title: String(localized: "settings.app.workspaceDescriptionColor", defaultValue: "Workspace Description Color"), synonyms: "Workspace Description Color sidebar.workspaceDescriptionColor description text color notes markdown sidebar"), .init(section: .sidebarAppearance, id: "sidebar-branch-layout", title: String(localized: "settings.app.sidebarBranchLayout", defaultValue: "Sidebar Branch Layout"), synonyms: "Sidebar Branch Layout sidebar.branchLayout sidebar.branchVerticalLayout git branch layout vertical inline cwd directory"), diff --git a/Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/SidebarSection.swift b/Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/SidebarSection.swift index 2806096e7eeb..b7945e4e0af4 100644 --- a/Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/SidebarSection.swift +++ b/Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/SidebarSection.swift @@ -13,6 +13,7 @@ public struct SidebarSection: View { @State private var matchTerminal: DefaultsValueModel @State var hideAll: DefaultsValueModel @State private var wrapTitles: DefaultsValueModel + @State private var twoLineTitles: DefaultsValueModel @State private var showDesc: DefaultsValueModel @State private var workspaceDescriptionHex: DefaultsValueModel @State private var branchVerticalLayout: DefaultsValueModel @@ -45,6 +46,7 @@ public struct SidebarSection: View { _matchTerminal = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.sidebarAppearance.matchTerminalBackground)) _hideAll = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.sidebar.hideAllDetails)) _wrapTitles = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.sidebar.wrapWorkspaceTitles)) + _twoLineTitles = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.sidebar.twoLineWorkspaceTitles)) _showDesc = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.sidebar.showWorkspaceDescription)) _workspaceDescriptionHex = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.sidebar.workspaceDescriptionColorHex)) _branchVerticalLayout = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.sidebar.branchVerticalLayout)) @@ -90,6 +92,7 @@ public struct SidebarSection: View { matchTerminal, hideAll, wrapTitles, + twoLineTitles, showDesc, workspaceDescriptionHex, branchVerticalLayout, @@ -280,6 +283,18 @@ public struct SidebarSection: View { } SettingsCardDivider() + SettingsCardRow( + configurationReview: .json("sidebar.twoLineWorkspaceTitles"), + String(localized: "settings.app.twoLineWorkspaceTitles", defaultValue: "Allow Two Lines for Workspace Titles"), + subtitle: String(localized: "settings.app.twoLineWorkspaceTitles.subtitle", defaultValue: "Gives a long workspace title a second line before it is shortened.") + ) { + Toggle("", isOn: Binding(get: { twoLineTitles.current }, set: { twoLineTitles.set($0) })) + .labelsHidden() + .controlSize(.small) + } + .disabled(wrapTitles.current) + SettingsCardDivider() + SettingsCardRow( configurationReview: .json("sidebar.showWorkspaceDescription"), String(localized: "settings.app.showWorkspaceDescription", defaultValue: "Show Workspace Description in Sidebar"), diff --git a/Packages/macOS/CmuxSettingsUI/Tests/CmuxSettingsUITests/SettingsRowAnchorResolutionTests.swift b/Packages/macOS/CmuxSettingsUI/Tests/CmuxSettingsUITests/SettingsRowAnchorResolutionTests.swift index 4858c4f47eea..a7eafea9b208 100644 --- a/Packages/macOS/CmuxSettingsUI/Tests/CmuxSettingsUITests/SettingsRowAnchorResolutionTests.swift +++ b/Packages/macOS/CmuxSettingsUI/Tests/CmuxSettingsUITests/SettingsRowAnchorResolutionTests.swift @@ -132,6 +132,7 @@ struct SettingsRowAnchorResolutionTests { "sidebar.showWorkspaceDescription", "sidebar.workspaceDescriptionColor", "sidebar.stackBranchDirectory", + "sidebar.twoLineWorkspaceTitles", "sidebar.watchGitStatus", "sidebar.wrapWorkspaceTitles", "sidebar.beta.workspaceTodos.controls.enabled", diff --git a/Packages/macOS/CmuxSidebar/Sources/CmuxSidebar/Typography/SidebarRowTextWeight.swift b/Packages/macOS/CmuxSidebar/Sources/CmuxSidebar/Typography/SidebarRowTextWeight.swift new file mode 100644 index 000000000000..6eb75418840b --- /dev/null +++ b/Packages/macOS/CmuxSidebar/Sources/CmuxSidebar/Typography/SidebarRowTextWeight.swift @@ -0,0 +1,52 @@ +public import AppKit +public import SwiftUI + +/// Font weights the workspace sidebar draws its row text with. +/// +/// The workspace list has two renderers: the AppKit table cells and the +/// SwiftUI rows. Both resolve weight here, so a row reads the same whichever +/// one draws it, and a weight change cannot land in one path only. +/// +/// Resting rows are `regular`: a sidebar where every title is semibold has no +/// spare emphasis left for the rows that matter. Selected rows and rows with +/// unread notifications keep `semibold`, so the two states still stand out +/// without the whole list shouting. +public enum SidebarRowTextWeight: Sendable, Hashable, CaseIterable { + case regular + case medium + case semibold + + /// Weight for a workspace row's title. + /// + /// `isSelected` covers both the active workspace and a row that joined a + /// multi-selection; both are rows the user is acting on. + public static func workspaceTitle(isSelected: Bool, hasUnread: Bool) -> SidebarRowTextWeight { + isSelected || hasUnread ? .semibold : .regular + } + + /// Weight for a workspace group header's name. Constant, so the header's + /// measured height never depends on selection. + public static let workspaceGroupHeaderName: SidebarRowTextWeight = .medium + + public var appKitWeight: NSFont.Weight { + switch self { + case .regular: + return .regular + case .medium: + return .medium + case .semibold: + return .semibold + } + } + + public var swiftUIWeight: Font.Weight { + switch self { + case .regular: + return .regular + case .medium: + return .medium + case .semibold: + return .semibold + } + } +} diff --git a/Packages/macOS/CmuxSidebar/Sources/CmuxSidebar/Typography/SidebarRowTitleMetrics.swift b/Packages/macOS/CmuxSidebar/Sources/CmuxSidebar/Typography/SidebarRowTitleMetrics.swift new file mode 100644 index 000000000000..98fa52a7d833 --- /dev/null +++ b/Packages/macOS/CmuxSidebar/Sources/CmuxSidebar/Typography/SidebarRowTitleMetrics.swift @@ -0,0 +1,73 @@ +public import AppKit +public import SwiftUI + +/// Type metrics for one workspace row title in the sidebar. +/// +/// Both sidebar renderers (the AppKit table cells and the SwiftUI rows) build +/// this from the two title settings, so a title occupies the same box and +/// truncates the same way whichever one draws it. +/// +/// The line limit is the value the rest of the metrics are derived from rather +/// than an argument passed alongside them: a title truncated at its end while +/// being laid out on one line, or in the middle while wrapping, is a mismatch +/// the two renderers used to be free to make independently. +public struct SidebarRowTitleMetrics: Equatable, Sendable { + /// Base point size for a workspace row title, before the sidebar font scale + /// and the global font magnification. + /// + /// Half a point smaller than the size cmux shipped before: at the default + /// sidebar width the old size cut most titles inside a dozen characters, + /// and the row is a label, not body text. + public static let fontSize: CGFloat = 12 + + /// Lines a wrapped title may occupy when `sidebar.wrapWorkspaceTitles` is on. + public static let maxWrappedLines = 8 + + /// Lines a title may occupy when only `sidebar.twoLineWorkspaceTitles` is on. + public static let twoLineLines = 2 + + /// Lines this title may occupy. + public let lineLimit: Int + + /// `wrapsTitles` keeps its shipped meaning (show the whole title, up to + /// `maxWrappedLines`). `usesTwoLines` is the middle setting: a second line + /// for the titles that need one, still bounded so a long title cannot push + /// its neighbours off screen. + public init(wrapsTitles: Bool, usesTwoLines: Bool) { + if wrapsTitles { + lineLimit = Self.maxWrappedLines + } else { + lineLimit = usesTwoLines ? Self.twoLineLines : 1 + } + } + + /// Metrics for a title already known to be laid out on `lineLimit` lines. + public init(lineLimit: Int) { + self.lineLimit = max(1, lineLimit) + } + + /// Whether this title is shortened in its middle. + /// + /// A single line is: the start of a title and its distinctive tail are both + /// worth more than the words in between, so "Fix cmux pane focus indicator + /// flicker" reads as "Fix cmux pa…r flicker" and "cmux-remote-status @host" + /// keeps the host it points at. Titles on more than one line truncate at the + /// end of the last line, where the earlier lines already carry the start. + public var truncatesMiddle: Bool { + lineLimit == 1 + } + + public var appKitLineBreakMode: NSLineBreakMode { + if truncatesMiddle { + return .byTruncatingMiddle + } + // Word wrapping with no truncation is only safe when the limit is high + // enough to show a whole title; a two-line title has to show the reader + // that something was cut. + return lineLimit >= Self.maxWrappedLines ? .byWordWrapping : .byTruncatingTail + } + + public var swiftUITruncationMode: Text.TruncationMode { + truncatesMiddle ? .middle : .tail + } +} diff --git a/Packages/macOS/CmuxSidebar/Tests/CmuxSidebarTests/SidebarRowTextWeightTests.swift b/Packages/macOS/CmuxSidebar/Tests/CmuxSidebarTests/SidebarRowTextWeightTests.swift new file mode 100644 index 000000000000..7deb4dbaedac --- /dev/null +++ b/Packages/macOS/CmuxSidebar/Tests/CmuxSidebarTests/SidebarRowTextWeightTests.swift @@ -0,0 +1,44 @@ +import AppKit +import SwiftUI +import Testing + +@testable import CmuxSidebar + +@Suite("SidebarRowTextWeight") +struct SidebarRowTextWeightTests { + @Test("A resting workspace row title is lighter than semibold") + func restingTitleIsLight() { + let weight = SidebarRowTextWeight.workspaceTitle(isSelected: false, hasUnread: false) + #expect(weight == .regular) + #expect(weight.appKitWeight.rawValue < SidebarRowTextWeight.semibold.appKitWeight.rawValue) + } + + @Test("Selected and unread workspace row titles stay semibold") + func selectedAndUnreadTitlesAreEmphasized() { + #expect(SidebarRowTextWeight.workspaceTitle(isSelected: true, hasUnread: false) == .semibold) + #expect(SidebarRowTextWeight.workspaceTitle(isSelected: false, hasUnread: true) == .semibold) + #expect(SidebarRowTextWeight.workspaceTitle(isSelected: true, hasUnread: true) == .semibold) + } + + @Test("Group header names use one constant weight") + func groupHeaderNameWeightIsConstant() { + #expect(SidebarRowTextWeight.workspaceGroupHeaderName == .medium) + } + + /// The AppKit table cells and the SwiftUI rows read these two properties + /// separately, so a row would look different depending on which renderer + /// drew it if the two mappings ever drifted apart. + @Test("The AppKit and SwiftUI mappings agree for every weight") + func appKitAndSwiftUIMappingsAgree() { + let expected: [(SidebarRowTextWeight, NSFont.Weight, Font.Weight)] = [ + (.regular, .regular, .regular), + (.medium, .medium, .medium), + (.semibold, .semibold, .semibold), + ] + #expect(expected.count == SidebarRowTextWeight.allCases.count) + for (weight, appKit, swiftUI) in expected { + #expect(weight.appKitWeight == appKit) + #expect(weight.swiftUIWeight == swiftUI) + } + } +} diff --git a/Packages/macOS/CmuxSidebar/Tests/CmuxSidebarTests/SidebarRowTitleMetricsTests.swift b/Packages/macOS/CmuxSidebar/Tests/CmuxSidebarTests/SidebarRowTitleMetricsTests.swift new file mode 100644 index 000000000000..449f5a682232 --- /dev/null +++ b/Packages/macOS/CmuxSidebar/Tests/CmuxSidebarTests/SidebarRowTitleMetricsTests.swift @@ -0,0 +1,66 @@ +import AppKit +import SwiftUI +import Testing + +@testable import CmuxSidebar + +@Suite("SidebarRowTitleMetrics") +struct SidebarRowTitleMetricsTests { + @Test("One line by default, and wrapping still shows a title in full") + func lineLimits() { + #expect(SidebarRowTitleMetrics(wrapsTitles: false, usesTwoLines: false).lineLimit == 1) + #expect(SidebarRowTitleMetrics(wrapsTitles: false, usesTwoLines: true).lineLimit == 2) + #expect( + SidebarRowTitleMetrics(wrapsTitles: true, usesTwoLines: false).lineLimit + == SidebarRowTitleMetrics.maxWrappedLines + ) + // Wrapping is the stronger request, so it is not reduced to two lines. + #expect( + SidebarRowTitleMetrics(wrapsTitles: true, usesTwoLines: true).lineLimit + == SidebarRowTitleMetrics.maxWrappedLines + ) + } + + /// The AppKit cells and the SwiftUI rows resolve truncation separately, so + /// a drift here would shorten the same title differently depending on which + /// renderer drew the sidebar. + @Test("Both renderers truncate a one-line title in the middle") + func truncationModesAgree() { + let oneLine = SidebarRowTitleMetrics(lineLimit: 1) + #expect(oneLine.truncatesMiddle) + #expect(oneLine.appKitLineBreakMode == .byTruncatingMiddle) + #expect(oneLine.swiftUITruncationMode == .middle) + + for limit in [2, 3, SidebarRowTitleMetrics.maxWrappedLines] { + let metrics = SidebarRowTitleMetrics(lineLimit: limit) + #expect(!metrics.truncatesMiddle) + #expect(metrics.swiftUITruncationMode == .tail) + } + } + + /// A bounded multi-line title has to show that it was cut; only the limit + /// that shows a title in full may wrap without a mark. + @Test("A two-line title truncates, a fully wrapped title does not") + func lineBreakModesMatchTheirLimits() { + #expect(SidebarRowTitleMetrics(lineLimit: 2).appKitLineBreakMode == .byTruncatingTail) + #expect( + SidebarRowTitleMetrics(lineLimit: SidebarRowTitleMetrics.maxWrappedLines).appKitLineBreakMode + == .byWordWrapping + ) + } + + /// A line limit is a count of lines, so the metrics cannot be built with a + /// limit that would draw no title at all. + @Test("A limit below one line is treated as one line") + func limitsBelowOneLineAreClamped() { + #expect(SidebarRowTitleMetrics(lineLimit: 0).lineLimit == 1) + #expect(SidebarRowTitleMetrics(lineLimit: -3).truncatesMiddle) + } + + /// Row titles are labels in a narrow column, not body text. + @Test("The title size stays smaller than the system body size") + func titleSizeIsSmall() { + #expect(SidebarRowTitleMetrics.fontSize < NSFont.systemFontSize) + #expect(SidebarRowTitleMetrics.fontSize >= 11) + } +} diff --git a/Resources/Localizable.xcstrings b/Resources/Localizable.xcstrings index 83f898ad1104..bded78af2062 100644 --- a/Resources/Localizable.xcstrings +++ b/Resources/Localizable.xcstrings @@ -234922,6 +234922,256 @@ } } }, + "cloudTree.group.cloudMachines": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Cloud Machines" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Cloud-Maschinen" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Machines cloud" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "أجهزة سحابية" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Máquinas en la nube" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "雲端機器" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "云端机器" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "클라우드 머신" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "クラウドマシン" + } + }, + "bs": { + "stringUnit": { + "state": "translated", + "value": "Mašine u oblaku" + } + }, + "da": { + "stringUnit": { + "state": "translated", + "value": "Cloud-maskiner" + } + }, + "it": { + "stringUnit": { + "state": "translated", + "value": "Macchine cloud" + } + }, + "km": { + "stringUnit": { + "state": "translated", + "value": "ម៉ាស៊ីនលើពពក" + } + }, + "nb": { + "stringUnit": { + "state": "translated", + "value": "Skymaskiner" + } + }, + "pl": { + "stringUnit": { + "state": "translated", + "value": "Maszyny w chmurze" + } + }, + "pt-BR": { + "stringUnit": { + "state": "translated", + "value": "Máquinas na nuvem" + } + }, + "ru": { + "stringUnit": { + "state": "translated", + "value": "Облачные машины" + } + }, + "th": { + "stringUnit": { + "state": "translated", + "value": "เครื่องคลาวด์" + } + }, + "tr": { + "stringUnit": { + "state": "translated", + "value": "Bulut makineleri" + } + }, + "uk": { + "stringUnit": { + "state": "translated", + "value": "Хмарні машини" + } + } + } + }, + "cloudTree.group.devices": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "My Devices" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Meine Geräte" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Mes appareils" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "أجهزتي" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Mis dispositivos" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "我的裝置" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "我的设备" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "내 기기" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "マイデバイス" + } + }, + "bs": { + "stringUnit": { + "state": "translated", + "value": "Moji uređaji" + } + }, + "da": { + "stringUnit": { + "state": "translated", + "value": "Mine enheder" + } + }, + "it": { + "stringUnit": { + "state": "translated", + "value": "I miei dispositivi" + } + }, + "km": { + "stringUnit": { + "state": "translated", + "value": "ឧបករណ៍របស់ខ្ញុំ" + } + }, + "nb": { + "stringUnit": { + "state": "translated", + "value": "Mine enheter" + } + }, + "pl": { + "stringUnit": { + "state": "translated", + "value": "Moje urządzenia" + } + }, + "pt-BR": { + "stringUnit": { + "state": "translated", + "value": "Meus dispositivos" + } + }, + "ru": { + "stringUnit": { + "state": "translated", + "value": "Мои устройства" + } + }, + "th": { + "stringUnit": { + "state": "translated", + "value": "อุปกรณ์ของฉัน" + } + }, + "tr": { + "stringUnit": { + "state": "translated", + "value": "Cihazlarım" + } + }, + "uk": { + "stringUnit": { + "state": "translated", + "value": "Мої пристрої" + } + } + } + }, "machines.operation.checkpoint": { "extractionState": "manual", "localizations": { @@ -237317,6 +237567,419 @@ } } }, + "machines.listUnavailable.stale": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Machine list unavailable — showing last known" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Maschinenliste nicht verfügbar – zeige letzten bekannten Stand" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Liste des machines indisponible — affichage des dernières informations connues" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "قائمة الأجهزة غير متاحة — يتم عرض آخر حالة معروفة" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Lista de máquinas no disponible — se muestra el último estado conocido" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "無法取得機器清單 — 顯示上次已知的狀態" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "机器列表不可用 —— 显示的是最后已知状态" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "머신 목록을 사용할 수 없음 — 마지막으로 확인된 상태 표시 중" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "マシン一覧を取得できません — 最後の状態を表示中" + } + } + } + }, + "machines.listUnavailable.subtitle": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Your machines are unchanged. cmux couldn’t load the list from the Cloud service and retries on its own." + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Deine Maschinen sind unverändert. cmux konnte die Liste nicht vom Cloud-Dienst laden und versucht es selbstständig erneut." + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Vos machines ne sont pas modifiées. cmux n’a pas pu charger la liste depuis le service Cloud et va réessayer automatiquement." + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "لم تتغير أجهزتك. تعذر على cmux تحميل القائمة من الخدمة السحابية، وسيعيد المحاولة تلقائيًا." + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Tus máquinas no han cambiado. cmux no pudo cargar la lista desde el servicio de la nube y volverá a intentarlo automáticamente." + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "您的機器沒有任何變動。cmux 無法從雲端服務載入清單,會自動重試。" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "你的机器没有任何变化。cmux 无法从云端服务加载列表,会自动重试。" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "머신은 변경되지 않았습니다. cmux가 클라우드 서비스에서 목록을 불러오지 못했으며 자동으로 다시 시도합니다." + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "マシンは変更されていません。cmux はクラウドサービスから一覧を読み込めませんでした。自動的に再試行します。" + } + } + } + }, + "machines.listUnavailable.title": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Can’t load the machine list" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Maschinenliste kann nicht geladen werden" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Impossible de charger la liste des machines" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "تعذر تحميل قائمة الأجهزة" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "No se puede cargar la lista de máquinas" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "無法載入機器清單" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法加载机器列表" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "머신 목록을 불러올 수 없습니다" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "マシン一覧を読み込めません" + } + } + } + }, + "machines.offline.stale": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Offline — showing last known" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Offline – zeige letzten bekannten Stand" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Hors ligne — affichage des dernières informations connues" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "غير متصل — يتم عرض آخر حالة معروفة" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Sin conexión — se muestra el último estado conocido" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "離線 — 顯示上次已知的狀態" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "离线 —— 显示的是最后已知状态" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "오프라인 — 마지막으로 확인된 상태 표시 중" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "オフライン — 最後の状態を表示中" + } + } + } + }, + "machines.offline.subtitle": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Cloud machines load when this Mac is back online." + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Cloud-Maschinen werden geladen, sobald dieser Mac wieder online ist." + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Les machines Cloud se chargeront dès que ce Mac sera de nouveau en ligne." + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "سيتم تحميل الأجهزة السحابية عندما يعود جهاز Mac هذا إلى الاتصال بالإنترنت." + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Las máquinas en la nube se cargarán cuando este Mac vuelva a estar en línea." + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "這台 Mac 恢復連線後,就會載入雲端機器。" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "这台 Mac 恢复联网后,就会加载云端机器。" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "이 Mac이 다시 온라인 상태가 되면 클라우드 머신을 불러옵니다." + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "この Mac がオンラインに戻ると Cloud マシンを読み込みます。" + } + } + } + }, + "machines.offline.title": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Waiting for network" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Warte auf Netzwerk" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "En attente du réseau" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "في انتظار الشبكة" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Esperando la red" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "正在等待網路" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "正在等待网络" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "네트워크 대기 중" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "ネットワークを待機中" + } + } + } + }, + "machines.reconnecting.title": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Reconnecting to Cloud…" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Verbindung zur Cloud wird wiederhergestellt…" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Reconnexion au Cloud…" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "جارٍ إعادة الاتصال بالسحابة…" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Reconectando con la nube…" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "正在重新連線至雲端…" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "正在重新连接云端…" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "클라우드에 다시 연결하는 중…" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "クラウドに再接続中…" + } + } + } + }, "markdown.copyConfirm.html": { "extractionState": "manual", "localizations": { @@ -260042,6 +260705,381 @@ } } }, + "cli.auth.status.teamNotLoaded": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": " team: not loaded" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": " チーム: 未読み込み" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": " 团队: 未加载" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": " Team: nicht geladen" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": " équipe: non chargée" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": " الفريق: لم يتم تحميله" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": " equipo: no cargado" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": " 團隊: 未載入" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": " 팀: 로드되지 않음" + } + }, + "bs": { + "stringUnit": { + "state": "translated", + "value": " tim: nije učitan" + } + }, + "da": { + "stringUnit": { + "state": "translated", + "value": " team: ikke indlæst" + } + }, + "it": { + "stringUnit": { + "state": "translated", + "value": " team: non caricato" + } + }, + "km": { + "stringUnit": { + "state": "translated", + "value": " ក្រុម៖ មិនទាន់បានផ្ទុក" + } + }, + "nb": { + "stringUnit": { + "state": "translated", + "value": " team: ikke lastet" + } + }, + "pl": { + "stringUnit": { + "state": "translated", + "value": " zespół: nie załadowano" + } + }, + "pt-BR": { + "stringUnit": { + "state": "translated", + "value": " equipe: não carregada" + } + }, + "ru": { + "stringUnit": { + "state": "translated", + "value": " команда: не загружена" + } + }, + "th": { + "stringUnit": { + "state": "translated", + "value": " ทีม: ยังไม่ได้โหลด" + } + }, + "tr": { + "stringUnit": { + "state": "translated", + "value": " ekip: yüklenmedi" + } + }, + "uk": { + "stringUnit": { + "state": "translated", + "value": " команда: не завантажена" + } + } + } + }, + "cli.auth.status.teamNotLoadedRetrying": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": " team: not loaded (retrying)" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": " チーム: 未読み込み(再試行中)" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": " 团队: 未加载(正在重试)" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": " Team: nicht geladen (wird erneut versucht)" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": " équipe: non chargée (nouvel essai)" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": " الفريق: لم يتم تحميله (جارٍ إعادة المحاولة)" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": " equipo: no cargado (reintentando)" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": " 團隊: 未載入(重試中)" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": " 팀: 로드되지 않음 (재시도 중)" + } + }, + "bs": { + "stringUnit": { + "state": "translated", + "value": " tim: nije učitan (ponovni pokušaj)" + } + }, + "da": { + "stringUnit": { + "state": "translated", + "value": " team: ikke indlæst (prøver igen)" + } + }, + "it": { + "stringUnit": { + "state": "translated", + "value": " team: non caricato (nuovo tentativo)" + } + }, + "km": { + "stringUnit": { + "state": "translated", + "value": " ក្រុម៖ មិនទាន់បានផ្ទុក (កំពុងព្យាយាមម្ដងទៀត)" + } + }, + "nb": { + "stringUnit": { + "state": "translated", + "value": " team: ikke lastet (prøver igjen)" + } + }, + "pl": { + "stringUnit": { + "state": "translated", + "value": " zespół: nie załadowano (ponawianie próby)" + } + }, + "pt-BR": { + "stringUnit": { + "state": "translated", + "value": " equipe: não carregada (tentando novamente)" + } + }, + "ru": { + "stringUnit": { + "state": "translated", + "value": " команда: не загружена (повторная попытка)" + } + }, + "th": { + "stringUnit": { + "state": "translated", + "value": " ทีม: ยังไม่ได้โหลด (กำลังลองอีกครั้ง)" + } + }, + "tr": { + "stringUnit": { + "state": "translated", + "value": " ekip: yüklenmedi (yeniden deneniyor)" + } + }, + "uk": { + "stringUnit": { + "state": "translated", + "value": " команда: не завантажена (повторна спроба)" + } + } + } + }, + "mobile.pairing.error.teamUnavailable": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Could not load your cmux team. Check your internet connection, then try again." + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "cmux チームを読み込めませんでした。インターネット接続を確認してから、もう一度お試しください。" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法加载你的 cmux 团队。请检查网络连接,然后重试。" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Dein cmux-Team konnte nicht geladen werden. Prüfe deine Internetverbindung und versuche es erneut." + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Impossible de charger votre équipe cmux. Vérifiez votre connexion Internet, puis réessayez." + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "تعذّر تحميل فريق cmux الخاص بك. تحقّق من اتصالك بالإنترنت، ثم حاول مرة أخرى." + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "No se pudo cargar tu equipo de cmux. Comprueba tu conexión a internet e inténtalo de nuevo." + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "無法載入你的 cmux 團隊。請檢查網路連線,然後再試一次。" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "cmux 팀을 불러올 수 없습니다. 인터넷 연결을 확인한 후 다시 시도하세요." + } + }, + "bs": { + "stringUnit": { + "state": "translated", + "value": "Nije moguće učitati vaš cmux tim. Provjerite internetsku vezu i pokušajte ponovo." + } + }, + "da": { + "stringUnit": { + "state": "translated", + "value": "Din cmux-team kunne ikke indlæses. Kontrollér din internetforbindelse, og prøv igen." + } + }, + "it": { + "stringUnit": { + "state": "translated", + "value": "Impossibile caricare il tuo team cmux. Controlla la connessione Internet e riprova." + } + }, + "km": { + "stringUnit": { + "state": "translated", + "value": "មិនអាចផ្ទុកក្រុម cmux របស់អ្នកបានទេ។ សូមពិនិត្យការតភ្ជាប់អ៊ីនធឺណិត ហើយព្យាយាមម្ដងទៀត។" + } + }, + "nb": { + "stringUnit": { + "state": "translated", + "value": "Kunne ikke laste inn cmux-teamet ditt. Kontroller internettilkoblingen, og prøv igjen." + } + }, + "pl": { + "stringUnit": { + "state": "translated", + "value": "Nie udało się załadować Twojego zespołu cmux. Sprawdź połączenie z internetem i spróbuj ponownie." + } + }, + "pt-BR": { + "stringUnit": { + "state": "translated", + "value": "Não foi possível carregar sua equipe cmux. Verifique sua conexão com a internet e tente novamente." + } + }, + "ru": { + "stringUnit": { + "state": "translated", + "value": "Не удалось загрузить вашу команду cmux. Проверьте подключение к интернету и попробуйте ещё раз." + } + }, + "th": { + "stringUnit": { + "state": "translated", + "value": "ไม่สามารถโหลดทีม cmux ของคุณได้ ตรวจสอบการเชื่อมต่ออินเทอร์เน็ตแล้วลองอีกครั้ง" + } + }, + "tr": { + "stringUnit": { + "state": "translated", + "value": "cmux ekibiniz yüklenemedi. İnternet bağlantınızı kontrol edip tekrar deneyin." + } + }, + "uk": { + "stringUnit": { + "state": "translated", + "value": "Не вдалося завантажити вашу команду cmux. Перевірте підключення до інтернету й спробуйте ще раз." + } + } + } +}, "mobile.pairing.error.noTicket": { "extractionState": "manual", "localizations": { @@ -302618,6 +303656,124 @@ } } }, + "settings.app.twoLineWorkspaceTitles": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Allow Two Lines for Workspace Titles" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "السماح بسطرين لعناوين مساحات العمل" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Zwei Zeilen für Arbeitsbereichstitel zulassen" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Permitir dos líneas en los títulos de espacio de trabajo" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Autoriser deux lignes pour les titres d'espace de travail" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "ワークスペース名を2行まで表示" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "작업 공간 제목에 두 줄 허용" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "允许工作区标题显示两行" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "允許工作區標題顯示兩行" + } + } + } + }, + "settings.app.twoLineWorkspaceTitles.subtitle": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Gives a long workspace title a second line before it is shortened." + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "يمنح عنوان مساحة العمل الطويل سطرًا ثانيًا قبل اختصاره." + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Gibt einem langen Arbeitsbereichstitel eine zweite Zeile, bevor er gekürzt wird." + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Da una segunda línea a un título largo de espacio de trabajo antes de acortarlo." + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Donne une deuxième ligne à un titre d'espace de travail long avant de le raccourcir." + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "長いワークスペース名を短縮する前に2行目を使います。" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "긴 작업 공간 제목이 줄어들기 전에 두 번째 줄을 사용합니다." + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "让过长的工作区标题在被缩短前多一行显示。" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "讓過長的工作區標題在被縮短前多一行顯示。" + } + } + } + }, "settings.app.warnBeforeClosingTab": { "extractionState": "manual", "localizations": { @@ -350029,6 +351185,131 @@ } } }, + "settings.search.alias.setting.app.two-line-workspace-titles": { + "extractionState": "manual", + "localizations": { + "ar": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten مساحة العمل عنوان سطران السطر الثاني اختصار الشريط الجانبي" + } + }, + "bs": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten radni prostor naslov dva reda drugi red skraćivanje bočna traka" + } + }, + "da": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten arbejdsområde titel to linjer anden linje forkort sidepanel" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten arbeitsbereich titel zwei zeilen zweite zeile kürzen seitenleiste" + } + }, + "en": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten espacio de trabajo título dos líneas segunda línea acortar barra lateral" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten espace de travail titre deux lignes deuxième ligne raccourcir barre latérale" + } + }, + "it": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten spazio di lavoro titolo due righe seconda riga abbreviare barra laterale" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten ワークスペース タイトル 2行 2行目 短縮 サイドバー" + } + }, + "km": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten កន្លែងធ្វើការ ចំណងជើង ពីរបន្ទាត់ បន្ទាត់ទីពីរ បង្រួញ របារចំហៀង" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten 워크스페이스 제목 두 줄 둘째 줄 축약 사이드바" + } + }, + "nb": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten arbeidsområde tittel to linjer andre linje forkort sidepanel" + } + }, + "pl": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten obszar roboczy tytuł dwie linie druga linia skracanie pasek boczny" + } + }, + "pt-BR": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten espaço de trabalho título duas linhas segunda linha encurtar barra lateral" + } + }, + "ru": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten рабочая область название две строки вторая строка сокращение боковая панель" + } + }, + "th": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten เวิร์กสเปซ ชื่อ สองบรรทัด บรรทัดที่สอง ย่อ แถบด้านข้าง" + } + }, + "tr": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten çalışma alanı başlık iki satır ikinci satır kısalt kenar çubuğu" + } + }, + "uk": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten робоча область назва два рядки другий рядок скорочення бічна панель" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten 工作区 标题 两行 第二行 缩短 边栏" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten 工作區 標題 兩行 第二行 縮短 側邊欄" + } + } + } + }, "settings.search.alias.setting.app.wrap-workspace-titles": { "extractionState": "manual", "localizations": { @@ -563227,669 +564508,6 @@ } } }, - "cloudTree.group.cloudMachines": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Cloud Machines" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Cloud-Maschinen" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "Machines cloud" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "أجهزة سحابية" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "Máquinas en la nube" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "雲端機器" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "云端机器" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "클라우드 머신" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "クラウドマシン" - } - }, - "bs": { - "stringUnit": { - "state": "translated", - "value": "Mašine u oblaku" - } - }, - "da": { - "stringUnit": { - "state": "translated", - "value": "Cloud-maskiner" - } - }, - "it": { - "stringUnit": { - "state": "translated", - "value": "Macchine cloud" - } - }, - "km": { - "stringUnit": { - "state": "translated", - "value": "ម៉ាស៊ីនលើពពក" - } - }, - "nb": { - "stringUnit": { - "state": "translated", - "value": "Skymaskiner" - } - }, - "pl": { - "stringUnit": { - "state": "translated", - "value": "Maszyny w chmurze" - } - }, - "pt-BR": { - "stringUnit": { - "state": "translated", - "value": "Máquinas na nuvem" - } - }, - "ru": { - "stringUnit": { - "state": "translated", - "value": "Облачные машины" - } - }, - "th": { - "stringUnit": { - "state": "translated", - "value": "เครื่องคลาวด์" - } - }, - "tr": { - "stringUnit": { - "state": "translated", - "value": "Bulut makineleri" - } - }, - "uk": { - "stringUnit": { - "state": "translated", - "value": "Хмарні машини" - } - } - } - }, - "cloudTree.group.devices": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "My Devices" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Meine Geräte" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "Mes appareils" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "أجهزتي" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "Mis dispositivos" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "我的裝置" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "我的设备" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "내 기기" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "マイデバイス" - } - }, - "bs": { - "stringUnit": { - "state": "translated", - "value": "Moji uređaji" - } - }, - "da": { - "stringUnit": { - "state": "translated", - "value": "Mine enheder" - } - }, - "it": { - "stringUnit": { - "state": "translated", - "value": "I miei dispositivi" - } - }, - "km": { - "stringUnit": { - "state": "translated", - "value": "ឧបករណ៍របស់ខ្ញុំ" - } - }, - "nb": { - "stringUnit": { - "state": "translated", - "value": "Mine enheter" - } - }, - "pl": { - "stringUnit": { - "state": "translated", - "value": "Moje urządzenia" - } - }, - "pt-BR": { - "stringUnit": { - "state": "translated", - "value": "Meus dispositivos" - } - }, - "ru": { - "stringUnit": { - "state": "translated", - "value": "Мои устройства" - } - }, - "th": { - "stringUnit": { - "state": "translated", - "value": "อุปกรณ์ของฉัน" - } - }, - "tr": { - "stringUnit": { - "state": "translated", - "value": "Cihazlarım" - } - }, - "uk": { - "stringUnit": { - "state": "translated", - "value": "Мої пристрої" - } - } - } - }, - "machines.listUnavailable.stale": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Machine list unavailable — showing last known" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Maschinenliste nicht verfügbar – zeige letzten bekannten Stand" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "Liste des machines indisponible — affichage des dernières informations connues" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "قائمة الأجهزة غير متاحة — يتم عرض آخر حالة معروفة" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "Lista de máquinas no disponible — se muestra el último estado conocido" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "無法取得機器清單 — 顯示上次已知的狀態" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "机器列表不可用 —— 显示的是最后已知状态" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "머신 목록을 사용할 수 없음 — 마지막으로 확인된 상태 표시 중" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "マシン一覧を取得できません — 最後の状態を表示中" - } - } - } - }, - "machines.listUnavailable.subtitle": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Your machines are unchanged. cmux couldn’t load the list from the Cloud service and retries on its own." - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Deine Maschinen sind unverändert. cmux konnte die Liste nicht vom Cloud-Dienst laden und versucht es selbstständig erneut." - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "Vos machines ne sont pas modifiées. cmux n’a pas pu charger la liste depuis le service Cloud et va réessayer automatiquement." - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "لم تتغير أجهزتك. تعذر على cmux تحميل القائمة من الخدمة السحابية، وسيعيد المحاولة تلقائيًا." - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "Tus máquinas no han cambiado. cmux no pudo cargar la lista desde el servicio de la nube y volverá a intentarlo automáticamente." - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "您的機器沒有任何變動。cmux 無法從雲端服務載入清單,會自動重試。" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "你的机器没有任何变化。cmux 无法从云端服务加载列表,会自动重试。" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "머신은 변경되지 않았습니다. cmux가 클라우드 서비스에서 목록을 불러오지 못했으며 자동으로 다시 시도합니다." - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "マシンは変更されていません。cmux はクラウドサービスから一覧を読み込めませんでした。自動的に再試行します。" - } - } - } - }, - "machines.listUnavailable.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Can’t load the machine list" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Maschinenliste kann nicht geladen werden" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "Impossible de charger la liste des machines" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "تعذر تحميل قائمة الأجهزة" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "No se puede cargar la lista de máquinas" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "無法載入機器清單" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "无法加载机器列表" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "머신 목록을 불러올 수 없습니다" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "マシン一覧を読み込めません" - } - } - } - }, - "machines.offline.stale": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Offline — showing last known" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Offline – zeige letzten bekannten Stand" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "Hors ligne — affichage des dernières informations connues" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "غير متصل — يتم عرض آخر حالة معروفة" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "Sin conexión — se muestra el último estado conocido" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "離線 — 顯示上次已知的狀態" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "离线 —— 显示的是最后已知状态" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "오프라인 — 마지막으로 확인된 상태 표시 중" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "オフライン — 最後の状態を表示中" - } - } - } - }, - "machines.offline.subtitle": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Cloud machines load when this Mac is back online." - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Cloud-Maschinen werden geladen, sobald dieser Mac wieder online ist." - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "Les machines Cloud se chargeront dès que ce Mac sera de nouveau en ligne." - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "سيتم تحميل الأجهزة السحابية عندما يعود جهاز Mac هذا إلى الاتصال بالإنترنت." - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "Las máquinas en la nube se cargarán cuando este Mac vuelva a estar en línea." - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "這台 Mac 恢復連線後,就會載入雲端機器。" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "这台 Mac 恢复联网后,就会加载云端机器。" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "이 Mac이 다시 온라인 상태가 되면 클라우드 머신을 불러옵니다." - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "この Mac がオンラインに戻ると Cloud マシンを読み込みます。" - } - } - } - }, - "machines.offline.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Waiting for network" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Warte auf Netzwerk" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "En attente du réseau" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "في انتظار الشبكة" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "Esperando la red" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "正在等待網路" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "正在等待网络" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "네트워크 대기 중" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "ネットワークを待機中" - } - } - } - }, - "machines.reconnecting.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Reconnecting to Cloud…" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Verbindung zur Cloud wird wiederhergestellt…" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "Reconnexion au Cloud…" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "جارٍ إعادة الاتصال بالسحابة…" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "Reconectando con la nube…" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "正在重新連線至雲端…" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "正在重新连接云端…" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "클라우드에 다시 연결하는 중…" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "クラウドに再接続中…" - } - } - } - }, "devices.link.error.notDiscoverable": { "extractionState": "manual", "localizations": { @@ -564765,6 +565383,244 @@ } } }, + "command.newPaneAutoLayout.title": { + "extractionState": "manual", + "localizations": { + "ar": { + "stringUnit": { + "state": "translated", + "value": "لوحة جديدة (تخطيط تلقائي)" + } + }, + "bs": { + "stringUnit": { + "state": "translated", + "value": "Novi panel (automatski raspored)" + } + }, + "da": { + "stringUnit": { + "state": "translated", + "value": "Nyt panel (automatisk layout)" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Neuer Bereich (automatisches Layout)" + } + }, + "en": { + "stringUnit": { + "state": "translated", + "value": "New Pane (Auto Layout)" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Nuevo panel (diseño automático)" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Nouveau panneau (disposition automatique)" + } + }, + "it": { + "stringUnit": { + "state": "translated", + "value": "Nuovo pannello (layout automatico)" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "新しいペイン(自動レイアウト)" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "새 패널 (자동 레이아웃)" + } + }, + "nb": { + "stringUnit": { + "state": "translated", + "value": "Nytt panel (automatisk oppsett)" + } + }, + "pl": { + "stringUnit": { + "state": "translated", + "value": "Nowy panel (układ automatyczny)" + } + }, + "pt-BR": { + "stringUnit": { + "state": "translated", + "value": "Novo Painel (Layout Automático)" + } + }, + "ru": { + "stringUnit": { + "state": "translated", + "value": "Новая панель (автоматическая раскладка)" + } + }, + "th": { + "stringUnit": { + "state": "translated", + "value": "บานหน้าต่างใหม่ (จัดวางอัตโนมัติ)" + } + }, + "tr": { + "stringUnit": { + "state": "translated", + "value": "Yeni Bölme (Otomatik Düzen)" + } + }, + "uk": { + "stringUnit": { + "state": "translated", + "value": "Нова панель (автоматичне розташування)" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "新建窗格(自动布局)" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "新增窗格(自動佈局)" + } + } + } + }, + "shortcut.newPaneAutoLayout.label": { + "extractionState": "manual", + "localizations": { + "ar": { + "stringUnit": { + "state": "translated", + "value": "لوحة جديدة (تخطيط تلقائي)" + } + }, + "bs": { + "stringUnit": { + "state": "translated", + "value": "Novi panel (automatski raspored)" + } + }, + "da": { + "stringUnit": { + "state": "translated", + "value": "Nyt panel (automatisk layout)" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Neuer Bereich (automatisches Layout)" + } + }, + "en": { + "stringUnit": { + "state": "translated", + "value": "New Pane (Auto Layout)" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Nuevo panel (diseño automático)" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Nouveau panneau (disposition automatique)" + } + }, + "it": { + "stringUnit": { + "state": "translated", + "value": "Nuovo pannello (layout automatico)" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "新しいペイン(自動レイアウト)" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "새 패널 (자동 레이아웃)" + } + }, + "nb": { + "stringUnit": { + "state": "translated", + "value": "Nytt panel (automatisk oppsett)" + } + }, + "pl": { + "stringUnit": { + "state": "translated", + "value": "Nowy panel (układ automatyczny)" + } + }, + "pt-BR": { + "stringUnit": { + "state": "translated", + "value": "Novo Painel (Layout Automático)" + } + }, + "ru": { + "stringUnit": { + "state": "translated", + "value": "Новая панель (автоматическая раскладка)" + } + }, + "th": { + "stringUnit": { + "state": "translated", + "value": "บานหน้าต่างใหม่ (จัดวางอัตโนมัติ)" + } + }, + "tr": { + "stringUnit": { + "state": "translated", + "value": "Yeni Bölme (Otomatik Düzen)" + } + }, + "uk": { + "stringUnit": { + "state": "translated", + "value": "Нова панель (автоматичне розташування)" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "新建窗格(自动布局)" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "新增窗格(自動佈局)" + } + } + } + }, "socket.terminal.notRunning.awaitingRestore": { "extractionState": "manual", "localizations": { @@ -565390,929 +566246,65 @@ } } }, - "cli.help.record": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Usage: cmux record [start] [flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\nRecord a cmux window to an mp4 or gif, for a pull request or a bug\nreport. Only cmux's own windows can be recorded, and no Screen\nRecording permission is involved.\n\nFlags for start:\n --format mp4|gif Output format (default: mp4)\n --gif Shorthand for --format gif\n --fps <1-30> Frames per second (default: 12 for mp4, 8 for gif)\n --max-seconds Stop by itself after n seconds, 0.5-120 (default: 15)\n --scale <0.1-1> Scale the output (default: 1 for mp4, 0.5 for gif)\n --max-width <64-4096> Cap the output width, keeping the aspect ratio\n --region Record part of the window, in window points\n --out Write here instead of a temporary directory\n --label Name the file\n --no-captions Do not draw `record note` captions into the clip\n --window Window to record (default: the frontmost one)\n\nOutput: ` `, or the full response with --json.\n\nA recording stops itself at --max-seconds, so a clip is never left\nrunning by an agent that goes away. One recording at a time.\n\nExample:\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "الاستخدام: cmux record [start] [flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\nتسجيل نافذة cmux بصيغة mp4 أو gif، من أجل طلب سحب أو تقرير خطأ.\nلا يمكن تسجيل سوى نوافذ cmux نفسها،\nولا يتطلب ذلك إذن تسجيل الشاشة.\n\nخيارات start:\n --format mp4|gif صيغة الإخراج (الافتراضي: mp4)\n --gif اختصار لـ --format gif\n --fps <1-30> الإطارات في الثانية (الافتراضي: 12 لـ mp4، 8 لـ gif)\n --max-seconds يتوقف من تلقاء نفسه بعد n ثانية، 0.5-120 (الافتراضي: 15)\n --scale <0.1-1> تحجيم الإخراج (الافتراضي: 1 لـ mp4، 0.5 لـ gif)\n --max-width <64-4096> تحديد أقصى عرض للإخراج مع الحفاظ على نسبة الأبعاد\n --region تسجيل جزء من النافذة، بوحدات نقاط النافذة\n --out الكتابة هنا بدلاً من دليل مؤقت\n --label تسمية الملف\n --no-captions عدم رسم تعليقات `record note` داخل المقطع\n --window النافذة المراد تسجيلها (الافتراضي: النافذة الأمامية)\n\nالإخراج: ` `، أو الاستجابة الكاملة مع --json.\n\nيتوقف التسجيل من تلقاء نفسه عند --max-seconds، حتى لا يترك وكيل غادر\nمقطعًا قيد التسجيل. تسجيل واحد في كل مرة.\n\nمثال:\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Verwendung: cmux record [start] [Flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\nEin cmux-Fenster als mp4 oder gif aufzeichnen, für einen Pull Request\noder einen Fehlerbericht. Nur cmux-eigene Fenster können aufgezeichnet\nwerden, und es ist keine Bildschirmaufnahme-Berechtigung beteiligt.\n\nFlags für start:\n --format mp4|gif Ausgabeformat (Standard: mp4)\n --gif Kurzform für --format gif\n --fps <1-30> Bilder pro Sekunde (Standard: 12 für mp4, 8 für gif)\n --max-seconds Nach n Sekunden selbst beenden, 0.5-120 (Standard: 15)\n --scale <0.1-1> Ausgabe skalieren (Standard: 1 für mp4, 0.5 für gif)\n --max-width <64-4096> Ausgabebreite begrenzen, Seitenverhältnis bleibt\n --region Teil des Fensters aufzeichnen, in Fensterpunkten\n --out Hierhin schreiben statt in ein temporäres Verzeichnis\n --label Datei benennen\n --no-captions Keine `record note`-Untertitel in den Clip zeichnen\n --window Fenster zum Aufzeichnen (Standard: das vorderste)\n\nAusgabe: ` `, oder mit --json die vollständige Antwort.\n\nEine Aufzeichnung beendet sich bei --max-seconds selbst, damit ein Agent, der\nverschwindet, keinen laufenden Clip hinterlässt. Eine Aufzeichnung zur Zeit.\n\nBeispiel:\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "Uso: cmux record [start] [flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\nGraba una ventana de cmux en mp4 o gif, para un pull request o un informe\nde error. Solo se pueden grabar las ventanas propias de cmux, y no\ninterviene ningún permiso de grabación de pantalla.\n\nFlags para start:\n --format mp4|gif Formato de salida (predeterminado: mp4)\n --gif Atajo para --format gif\n --fps <1-30> Fotogramas por segundo (predeterminado: 12 para mp4, 8 para gif)\n --max-seconds Se detiene solo tras n segundos, 0.5-120 (predeterminado: 15)\n --scale <0.1-1> Escala la salida (predeterminado: 1 para mp4, 0.5 para gif)\n --max-width <64-4096> Limita el ancho de salida manteniendo la proporción\n --region Graba parte de la ventana, en puntos de ventana\n --out Escribe aquí en lugar de en un directorio temporal\n --label Da nombre al archivo\n --no-captions No dibujar los subtítulos de `record note` en el clip\n --window Ventana que se graba (predeterminado: la del frente)\n\nSalida: ` `, o la respuesta completa con --json.\n\nUna grabación se detiene sola en --max-seconds, para que un agente que\ndesaparece nunca deje un clip en marcha. Una grabación a la vez.\n\nEjemplo:\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "Utilisation : cmux record [start] [flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\nEnregistrer une fenêtre cmux en mp4 ou gif, pour une pull request ou un\nrapport de bug. Seules les fenêtres de cmux peuvent être enregistrées, et\naucune autorisation d'enregistrement de l'écran n'intervient.\n\nFlags pour start :\n --format mp4|gif Format de sortie (par défaut : mp4)\n --gif Raccourci pour --format gif\n --fps <1-30> Images par seconde (par défaut : 12 pour mp4, 8 pour gif)\n --max-seconds S'arrête seul après n secondes, 0.5-120 (par défaut : 15)\n --scale <0.1-1> Mettre la sortie à l'échelle (par défaut : 1 pour mp4, 0.5 pour gif)\n --max-width <64-4096> Limiter la largeur de sortie en gardant les proportions\n --region N'enregistrer qu'une partie de la fenêtre, en points fenêtre\n --out Écrire ici au lieu d'un répertoire temporaire\n --label Nommer le fichier\n --no-captions Ne pas dessiner les légendes `record note` dans le clip\n --window Fenêtre à enregistrer (par défaut : celle au premier plan)\n\nSortie : ` `, ou la réponse complète avec --json.\n\nUn enregistrement s'arrête de lui-même à --max-seconds, afin qu'un agent qui\ndisparaît ne laisse jamais un clip en cours. Un seul enregistrement à la fois.\n\nExemple :\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "使用方法: cmux record [start] [flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\nプルリクエストやバグ報告のために、cmux のウィンドウを mp4 または gif\nで録画します。録画できるのは cmux 自身のウィンドウだけで、画面収録の\n権限は必要ありません。\n\nstart のフラグ:\n --format mp4|gif 出力形式(既定: mp4)\n --gif --format gif の短縮形\n --fps <1-30> 1 秒あたりのフレーム数(既定: mp4 は 12、gif は 8)\n --max-seconds n 秒後に自動停止、0.5-120(既定: 15)\n --scale <0.1-1> 出力を拡大縮小(既定: mp4 は 1、gif は 0.5)\n --max-width <64-4096> 縦横比を保ったまま出力の幅を制限\n --region ウィンドウの一部だけを録画(ウィンドウポイント単位)\n --out 一時ディレクトリではなくこのパスに書き出す\n --label ファイルに名前を付ける\n --no-captions `record note` のキャプションをクリップに描画しない\n --window 録画するウィンドウ(既定: 最前面のウィンドウ)\n\n出力: ` `、または --json で完全なレスポンス。\n\n録画は --max-seconds で自動停止するので、いなくなったエージェントが\n録画を実行したままにすることはありません。録画は同時に 1 つだけです。\n\n例:\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "사용법: cmux record [start] [flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\n풀 리퀘스트나 버그 리포트에 쓰려고 cmux 창을 mp4 또는 gif로\n녹화합니다. cmux 자신의 창만 녹화할 수 있고, 화면 기록 권한은\n필요하지 않습니다.\n\nstart 플래그:\n --format mp4|gif 출력 형식 (기본값: mp4)\n --gif --format gif의 단축형\n --fps <1-30> 초당 프레임 수 (기본값: mp4는 12, gif는 8)\n --max-seconds n초 후 스스로 정지, 0.5-120 (기본값: 15)\n --scale <0.1-1> 출력 크기 조정 (기본값: mp4는 1, gif는 0.5)\n --max-width <64-4096> 가로 세로 비율을 유지하며 출력 너비 제한\n --region 창의 일부만 녹화, 창 포인트 단위\n --out 임시 디렉터리 대신 이 경로에 기록\n --label 파일 이름 지정\n --no-captions `record note` 캡션을 클립에 그리지 않음\n --window 녹화할 창 (기본값: 맨 앞 창)\n\n출력: ` `, 또는 --json으로 전체 응답.\n\n녹화는 --max-seconds에서 스스로 멈추므로 사라진 에이전트가 녹화를 계속\n남겨 두는 일은 없습니다. 한 번에 하나의 녹화만 가능합니다.\n\n예:\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "使用方法: cmux record [start] [flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\n将 cmux 窗口录制为 mp4 或 gif,用于 pull request 或错误报告。\n只能录制 cmux 自己的窗口,\n而且不需要任何屏幕录制权限。\n\nstart 的标志:\n --format mp4|gif 输出格式(默认: mp4)\n --gif --format gif 的简写\n --fps <1-30> 每秒帧数(默认: mp4 为 12,gif 为 8)\n --max-seconds n 秒后自行停止,0.5-120(默认: 15)\n --scale <0.1-1> 缩放输出(默认: mp4 为 1,gif 为 0.5)\n --max-width <64-4096> 限制输出宽度并保持宽高比\n --region 只录制窗口的一部分,以窗口点为单位\n --out 写入此处而非临时目录\n --label 为文件命名\n --no-captions 不要把 `record note` 字幕画进视频\n --window 要录制的窗口(默认: 最前面的窗口)\n\n输出: ` `,或用 --json 获取完整响应。\n\n录制会在 --max-seconds 时自行停止,因此离开的代理不会留下仍在录制的\n视频。同一时间只能有一份录制。\n\n示例:\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "使用方法: cmux record [start] [flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\n將 cmux 視窗錄製成 mp4 或 gif,用於 pull request 或錯誤報告。\n只能錄製 cmux 自己的視窗,\n而且不需要任何螢幕錄製權限。\n\nstart 的旗標:\n --format mp4|gif 輸出格式(預設: mp4)\n --gif --format gif 的簡寫\n --fps <1-30> 每秒影格數(預設: mp4 為 12,gif 為 8)\n --max-seconds n 秒後自行停止,0.5-120(預設: 15)\n --scale <0.1-1> 縮放輸出(預設: mp4 為 1,gif 為 0.5)\n --max-width <64-4096> 限制輸出寬度並維持長寬比\n --region 只錄製視窗的一部分,以視窗點為單位\n --out 寫入此處而非暫存目錄\n --label 為檔案命名\n --no-captions 不要將 `record note` 字幕畫進影片\n --window 要錄製的視窗(預設: 最前面的視窗)\n\n輸出: ` `,或以 --json 取得完整回應。\n\n錄製會在 --max-seconds 時自行停止,因此離開的代理程式不會留下仍在\n錄製的影片。同一時間只能有一份錄製。\n\n範例:\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" - } - } - } - }, - "cli.record.error.formatConflict": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "record start: --gif conflicts with --format" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "record start: لا يمكن دمج --gif مع --format" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "record start: --gif kann nicht mit --format kombiniert werden" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "record start: --gif no se puede combinar con --format" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "record start: --gif ne peut pas être combiné avec --format" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "record start: --gif は --format と併用できません" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "record start: --gif은 --format과 함께 사용할 수 없습니다" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "record start: --gif 不能与 --format 同用" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "record start: --gif 無法與 --format 同時使用" - } - } - } - }, - "cli.record.error.noteText": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "record note: text is required" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "record note: النص مطلوب" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "record note: Text ist erforderlich" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "record note: se requiere el texto" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "record note : le texte est requis" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "record note: テキストが必要です" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "record note: 텍스트가 필요합니다" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "record note: 必须提供文本" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "record note: 必須提供文字" - } - } - } - }, - "cli.record.error.unexpectedArguments": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "record %@: unexpected arguments: %@" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "record %@: وسائط غير متوقعة: %@" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "record %@: unerwartete Argumente: %@" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "record %@: argumentos inesperados: %@" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "record %@ : arguments inattendus : %@" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "record %@: 予期しない引数: %@" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "record %@: 예기치 않은 인수: %@" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "record %@: 多余的参数: %@" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "record %@: 未預期的引數: %@" - } - } - } - }, - "cli.record.error.unknownSubcommand": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "record: unknown subcommand '%@' (start, stop, status, note, list)" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "record: أمر فرعي غير معروف '%@' (start، stop، status، note، list)" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "record: unbekannter Unterbefehl „%@“ (start, stop, status, note, list)" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "record: subcomando desconocido '%@' (start, stop, status, note, list)" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "record : sous-commande inconnue '%@' (start, stop, status, note, list)" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "record: 不明なサブコマンド '%@' です(start、stop、status、note、list)" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "record: 알 수 없는 하위 명령 '%@' (start, stop, status, note, list)" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "record: 未知的子命令 '%@'(start、stop、status、note、list)" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "record: 未知的子命令 '%@'(start、stop、status、note、list)" - } - } - } - }, - "cli.usage.record": { - "extractionState": "manual", - "localizations": { - "ar": { - "stringUnit": { - "state": "translated", - "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" - } - }, - "en": { - "stringUnit": { - "state": "translated", - "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" - } - } - } - }, - "cli.help.shot": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Usage: cmux shot [flags]\n\nScreenshot a cmux window, or a region of one, to a png or a jpeg. Only\ncmux's own windows can be captured, and no Screen Recording permission\nis involved, so this works on a release build and inside CI.\n\nFlags:\n --format png|jpg Output format (default: png)\n --jpg Shorthand for --format jpg\n --scale <0.1-1> Scale the output (default: 1)\n --max-width <64-8192> Cap the output width, keeping the aspect ratio\n --quality <0.1-1> JPEG quality (default: 0.8, ignored for png)\n --region Capture part of the window, in window points\n --out Write here instead of a temporary directory\n --label Name the file\n --caption Draw a caption into the image\n --window Window to capture (default: the frontmost one)\n\nOutput: `x `, or the full response with --json.\n\nA region is the same rectangle `cmux record --region` films, so a\ndetail spotted in a clip can be shot with the same four numbers.\n\nExample:\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "الاستخدام: cmux shot [flags]\n\nتصوير نافذة cmux أو جزء منها بصيغة png أو jpeg.\nلا يمكن تصوير سوى نوافذ cmux نفسها، ولا يتطلب ذلك إذن تسجيل الشاشة،\nلذلك يعمل هذا في بناء الإصدار وداخل CI.\n\nالخيارات:\n --format png|jpg صيغة الإخراج (الافتراضي: png)\n --jpg اختصار لـ --format jpg\n --scale <0.1-1> تحجيم الإخراج (الافتراضي: 1)\n --max-width <64-8192> تحديد أقصى عرض للإخراج مع الحفاظ على نسبة الأبعاد\n --quality <0.1-1> جودة JPEG (الافتراضي: 0.8، وتُهمل مع png)\n --region تصوير جزء من النافذة، بوحدات نقاط النافذة\n --out الكتابة هنا بدلاً من دليل مؤقت\n --label تسمية الملف\n --caption رسم تعليق داخل الصورة\n --window النافذة المراد تصويرها (الافتراضي: النافذة الأمامية)\n\nالإخراج: `x `، أو الاستجابة الكاملة مع --json.\n\nالمنطقة هي نفس المستطيل الذي يصوّره `cmux record --region`، لذا يمكن تصوير\nتفصيل لوحظ في مقطع بالأرقام الأربعة نفسها.\n\nمثال:\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Verwendung: cmux shot [Flags]\n\nEin cmux-Fenster oder einen Teil davon als png oder jpeg aufnehmen. Nur\ncmux-eigene Fenster sind aufnehmbar, und es ist keine Berechtigung für\nBildschirmaufnahmen nötig, das geht also im Release-Build und in der CI.\n\nFlags:\n --format png|jpg Ausgabeformat (Standard: png)\n --jpg Kurzform für --format jpg\n --scale <0.1-1> Ausgabe skalieren (Standard: 1)\n --max-width <64-8192> Ausgabebreite begrenzen, Seitenverhältnis bleibt\n --quality <0.1-1> JPEG-Qualität (Standard: 0.8, für png ignoriert)\n --region Teil des Fensters aufnehmen, in Fensterpunkten\n --out Hierhin schreiben statt in ein temporäres Verzeichnis\n --label Datei benennen\n --caption Eine Bildunterschrift ins Bild zeichnen\n --window Fenster zum Aufnehmen (Standard: das vorderste)\n\nAusgabe: `x `, oder mit --json die vollständige Antwort.\n\nEine Region ist dasselbe Rechteck, das `cmux record --region` filmt: ein im\nClip entdecktes Detail lässt sich mit denselben vier Zahlen aufnehmen.\n\nBeispiel:\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "Uso: cmux shot [flags]\n\nCaptura una ventana de cmux, o una región de ella, en png o jpeg. Solo se\npueden capturar las ventanas propias de cmux, y no interviene ningún permiso\nde grabación de pantalla, así que funciona en una release y dentro de CI.\n\nFlags:\n --format png|jpg Formato de salida (predeterminado: png)\n --jpg Atajo para --format jpg\n --scale <0.1-1> Escala la salida (predeterminado: 1)\n --max-width <64-8192> Limita el ancho de salida manteniendo la proporción\n --quality <0.1-1> Calidad JPEG (predeterminado: 0.8, se ignora en png)\n --region Captura parte de la ventana, en puntos de ventana\n --out Escribe aquí en lugar de en un directorio temporal\n --label Da nombre al archivo\n --caption Dibuja un rótulo dentro de la imagen\n --window Ventana que se captura (predeterminado: la del frente)\n\nSalida: `x `, o la respuesta completa con --json.\n\nUna región es el mismo rectángulo que filma `cmux record --region`, así que un\ndetalle visto en un clip se captura con los mismos cuatro números.\n\nEjemplo:\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "Utilisation : cmux shot [flags]\n\nCapture une fenêtre cmux, ou une partie de celle-ci, en png ou en jpeg.\nSeules les fenêtres de cmux peuvent être capturées, et aucune autorisation\nd'enregistrement d'écran n'intervient : cela marche en release et dans la CI.\n\nFlags :\n --format png|jpg Format de sortie (par défaut : png)\n --jpg Raccourci pour --format jpg\n --scale <0.1-1> Met la sortie à l'échelle (par défaut : 1)\n --max-width <64-8192> Limite la largeur de sortie en gardant les proportions\n --quality <0.1-1> Qualité JPEG (par défaut : 0.8, ignorée pour png)\n --region Capture une partie de la fenêtre, en points de fenêtre\n --out Écrit ici au lieu d'un répertoire temporaire\n --label Nomme le fichier\n --caption Dessine une légende dans l'image\n --window Fenêtre à capturer (par défaut : celle au premier plan)\n\nSortie : `x `, ou la réponse complète avec --json.\n\nUne région est le même rectangle que filme `cmux record --region` : un détail\nrepéré dans un clip se capture avec les mêmes quatre nombres.\n\nExemple :\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "使用方法: cmux shot [flags]\n\ncmux のウィンドウ、またはその一部の領域を png または jpeg で撮ります。\n撮れるのは cmux 自身のウィンドウだけで、画面収録の権限は必要ないので、\nリリースビルドでも CI の中でも動きます。\n\nフラグ:\n --format png|jpg 出力形式(既定: png)\n --jpg --format jpg の短縮形\n --scale <0.1-1> 出力を拡大縮小(既定: 1)\n --max-width <64-8192> 縦横比を保ったまま出力の幅を制限\n --quality <0.1-1> JPEG の品質(既定: 0.8、png では無視)\n --region ウィンドウの一部だけを撮る(ウィンドウポイント単位)\n --out 一時ディレクトリではなくこのパスに書き出す\n --label ファイルに名前を付ける\n --caption 画像にキャプションを描画する\n --window 撮るウィンドウ(既定: 最前面のウィンドウ)\n\n出力: `x `、または --json で完全なレスポンス。\n\n領域は `cmux record --region` が撮るのと同じ矩形なので、クリップで見つけた\n細部を同じ 4 つの数字で撮れます。\n\n例:\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "사용법: cmux shot [flags]\n\ncmux 창이나 창의 일부 영역을 png 또는 jpeg로 캡처합니다. cmux 자신의\n창만 캡처할 수 있고, 화면 기록 권한이 필요하지 않으므로 릴리스 빌드와\nCI 안에서도 동작합니다.\n\n플래그:\n --format png|jpg 출력 형식 (기본값: png)\n --jpg --format jpg의 단축형\n --scale <0.1-1> 출력 크기 조정 (기본값: 1)\n --max-width <64-8192> 가로 세로 비율을 유지하며 출력 너비 제한\n --quality <0.1-1> JPEG 품질 (기본값: 0.8, png에서는 무시)\n --region 창의 일부만 캡처, 창 포인트 단위\n --out 임시 디렉터리 대신 이 경로에 기록\n --label 파일 이름 지정\n --caption 이미지에 캡션 그리기\n --window 캡처할 창 (기본값: 맨 앞 창)\n\n출력: `x `, 또는 --json으로 전체 응답.\n\n영역은 `cmux record --region`이 촬영하는 사각형과 같으므로, 클립에서 본\n세부를 같은 네 숫자로 캡처할 수 있습니다.\n\n예:\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "使用方法: cmux shot [flags]\n\n将 cmux 窗口或其中一块区域截取为 png 或 jpeg。\n只能截取 cmux 自己的窗口,而且不需要任何屏幕录制权限,\n因此在 release 构建和 CI 中都能用。\n\n标志:\n --format png|jpg 输出格式(默认: png)\n --jpg --format jpg 的简写\n --scale <0.1-1> 缩放输出(默认: 1)\n --max-width <64-8192> 限制输出宽度并保持宽高比\n --quality <0.1-1> JPEG 质量(默认: 0.8,png 会忽略)\n --region 只截取窗口的一部分,以窗口点为单位\n --out 写入此处而非临时目录\n --label 为文件命名\n --caption 在图片上绘制字幕\n --window 要截取的窗口(默认: 最前面的窗口)\n\n输出: `x `,或用 --json 获取完整响应。\n\n区域和 `cmux record --region` 拍摄的矩形相同,因此在视频里看到的细节\n可以用同样的四个数字截取。\n\n示例:\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "使用方法: cmux shot [flags]\n\n將 cmux 視窗或其中一塊區域擷取成 png 或 jpeg。\n只能擷取 cmux 自己的視窗,而且不需要任何螢幕錄製權限,\n因此在 release 版本與 CI 內都能用。\n\n旗標:\n --format png|jpg 輸出格式(預設: png)\n --jpg --format jpg 的簡寫\n --scale <0.1-1> 縮放輸出(預設: 1)\n --max-width <64-8192> 限制輸出寬度並保持長寬比\n --quality <0.1-1> JPEG 品質(預設: 0.8,png 會忽略)\n --region 只擷取視窗的一部分,以視窗點為單位\n --out 寫入此處而非暫存目錄\n --label 為檔案命名\n --caption 在圖片上畫出字幕\n --window 要擷取的視窗(預設: 最前面的視窗)\n\n輸出: `x `,或用 --json 取得完整回應。\n\n區域和 `cmux record --region` 拍攝的矩形相同,所以在影片裡看到的細節\n可以用同樣的四個數字擷取。\n\n範例:\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" - } - } - } - }, - "cli.shot.error.formatConflict": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "shot: --jpg conflicts with --format" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "shot: لا يمكن دمج --jpg مع --format" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "shot: --jpg kann nicht mit --format kombiniert werden" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "shot: --jpg no se puede combinar con --format" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "shot : --jpg ne peut pas être combiné avec --format" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "shot: --jpg は --format と併用できません" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "shot: --jpg은 --format과 함께 사용할 수 없습니다" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "shot: --jpg 不能与 --format 同用" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "shot: --jpg 無法與 --format 同時使用" - } - } - } - }, - "cli.shot.error.unexpectedArguments": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "shot: unexpected arguments: %@" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "shot: وسائط غير متوقعة: %@" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "shot: unerwartete Argumente: %@" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "shot: argumentos inesperados: %@" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "shot : arguments inattendus : %@" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "shot: 予期しない引数: %@" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "shot: 예기치 않은 인수: %@" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "shot: 多余的参数: %@" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "shot: 未預期的引數: %@" - } - } - } - }, - "cli.usage.shot": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "shot [--format png|jpg] [--jpg] [--scale ] [--max-width ] [--quality ] [--region ] [--out ] [--label ] [--caption ] [--window ]" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "shot [--format png|jpg] [--jpg] [--scale ] [--max-width ] [--quality ] [--region ] [--out ] [--label ] [--caption ] [--window ]" - } - } - } - }, - "cli.auth.status.teamNotLoaded": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": " team: not loaded" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": " チーム: 未読み込み" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": " 团队: 未加载" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": " Team: nicht geladen" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": " équipe: non chargée" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": " الفريق: لم يتم تحميله" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": " equipo: no cargado" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": " 團隊: 未載入" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": " 팀: 로드되지 않음" - } - }, - "bs": { - "stringUnit": { - "state": "translated", - "value": " tim: nije učitan" - } - }, - "da": { - "stringUnit": { - "state": "translated", - "value": " team: ikke indlæst" - } - }, - "it": { - "stringUnit": { - "state": "translated", - "value": " team: non caricato" - } - }, - "km": { - "stringUnit": { - "state": "translated", - "value": " ក្រុម៖ មិនទាន់បានផ្ទុក" - } - }, - "nb": { - "stringUnit": { - "state": "translated", - "value": " team: ikke lastet" - } - }, - "pl": { - "stringUnit": { - "state": "translated", - "value": " zespół: nie załadowano" - } - }, - "pt-BR": { - "stringUnit": { - "state": "translated", - "value": " equipe: não carregada" - } - }, - "ru": { - "stringUnit": { - "state": "translated", - "value": " команда: не загружена" - } - }, - "th": { - "stringUnit": { - "state": "translated", - "value": " ทีม: ยังไม่ได้โหลด" - } - }, - "tr": { - "stringUnit": { - "state": "translated", - "value": " ekip: yüklenmedi" - } - }, - "uk": { - "stringUnit": { - "state": "translated", - "value": " команда: не завантажена" - } - } - } - }, - "cli.auth.status.teamNotLoadedRetrying": { + "cli.restore.notice.routedLauncherUnavailable": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": " team: not loaded (retrying)" + "value": "restore: this session was started through the routed launcher '%@', which is not on PATH. Resuming the agent directly instead." } }, "ja": { "stringUnit": { "state": "translated", - "value": " チーム: 未読み込み(再試行中)" + "value": "restore: このセッションはルーティングされたランチャー「%@」経由で開始されましたが、PATH にありません。代わりにエージェントを直接再開します。" } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": " 团队: 未加载(正在重试)" + "value": "restore:此会话是通过路由启动器“%@”启动的,但它不在 PATH 中。将改为直接恢复该代理。" } }, "de": { "stringUnit": { "state": "translated", - "value": " Team: nicht geladen (wird erneut versucht)" + "value": "restore: Diese Sitzung wurde über den weitergeleiteten Launcher „%@“ gestartet, der nicht im PATH liegt. Der Agent wird stattdessen direkt fortgesetzt." } }, "fr": { "stringUnit": { "state": "translated", - "value": " équipe: non chargée (nouvel essai)" + "value": "restore : cette session a été lancée via le lanceur routé « %@ », qui est introuvable dans le PATH. Reprise directe de l'agent à la place." } }, "ar": { "stringUnit": { "state": "translated", - "value": " الفريق: لم يتم تحميله (جارٍ إعادة المحاولة)" + "value": "restore: بدأت هذه الجلسة عبر المشغّل الموجَّه '%@'، وهو غير موجود في PATH. سيتم استئناف الوكيل مباشرةً بدلاً من ذلك." } }, "es": { "stringUnit": { "state": "translated", - "value": " equipo: no cargado (reintentando)" + "value": "restore: esta sesión se inició mediante el lanzador enrutado '%@', que no está en el PATH. Se reanudará el agente directamente." } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": " 團隊: 未載入(重試中)" + "value": "restore:此工作階段是透過路由啟動器「%@」啟動的,但它不在 PATH 中。將改為直接繼續該代理程式。" } }, "ko": { "stringUnit": { "state": "translated", - "value": " 팀: 로드되지 않음 (재시도 중)" - } - }, - "bs": { - "stringUnit": { - "state": "translated", - "value": " tim: nije učitan (ponovni pokušaj)" - } - }, - "da": { - "stringUnit": { - "state": "translated", - "value": " team: ikke indlæst (prøver igen)" - } - }, - "it": { - "stringUnit": { - "state": "translated", - "value": " team: non caricato (nuovo tentativo)" - } - }, - "km": { - "stringUnit": { - "state": "translated", - "value": " ក្រុម៖ មិនទាន់បានផ្ទុក (កំពុងព្យាយាមម្ដងទៀត)" - } - }, - "nb": { - "stringUnit": { - "state": "translated", - "value": " team: ikke lastet (prøver igjen)" - } - }, - "pl": { - "stringUnit": { - "state": "translated", - "value": " zespół: nie załadowano (ponawianie próby)" - } - }, - "pt-BR": { - "stringUnit": { - "state": "translated", - "value": " equipe: não carregada (tentando novamente)" - } - }, - "ru": { - "stringUnit": { - "state": "translated", - "value": " команда: не загружена (повторная попытка)" - } - }, - "th": { - "stringUnit": { - "state": "translated", - "value": " ทีม: ยังไม่ได้โหลด (กำลังลองอีกครั้ง)" - } - }, - "tr": { - "stringUnit": { - "state": "translated", - "value": " ekip: yüklenmedi (yeniden deneniyor)" - } - }, - "uk": { - "stringUnit": { - "state": "translated", - "value": " команда: не завантажена (повторна спроба)" + "value": "restore: 이 세션은 라우팅된 런처 '%@'를 통해 시작되었지만 PATH에 없습니다. 대신 에이전트를 직접 재개합니다." } } } }, - "mobile.pairing.error.teamUnavailable": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Could not load your cmux team. Check your internet connection, then try again." - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "cmux チームを読み込めませんでした。インターネット接続を確認してから、もう一度お試しください。" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "无法加载你的 cmux 团队。请检查网络连接,然后重试。" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Dein cmux-Team konnte nicht geladen werden. Prüfe deine Internetverbindung und versuche es erneut." - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "Impossible de charger votre équipe cmux. Vérifiez votre connexion Internet, puis réessayez." - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "تعذّر تحميل فريق cmux الخاص بك. تحقّق من اتصالك بالإنترنت، ثم حاول مرة أخرى." - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "No se pudo cargar tu equipo de cmux. Comprueba tu conexión a internet e inténtalo de nuevo." - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "無法載入你的 cmux 團隊。請檢查網路連線,然後再試一次。" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "cmux 팀을 불러올 수 없습니다. 인터넷 연결을 확인한 후 다시 시도하세요." - } - }, - "bs": { - "stringUnit": { - "state": "translated", - "value": "Nije moguće učitati vaš cmux tim. Provjerite internetsku vezu i pokušajte ponovo." - } - }, - "da": { - "stringUnit": { - "state": "translated", - "value": "Din cmux-team kunne ikke indlæses. Kontrollér din internetforbindelse, og prøv igen." - } - }, - "it": { - "stringUnit": { - "state": "translated", - "value": "Impossibile caricare il tuo team cmux. Controlla la connessione Internet e riprova." - } - }, - "km": { - "stringUnit": { - "state": "translated", - "value": "មិនអាចផ្ទុកក្រុម cmux របស់អ្នកបានទេ។ សូមពិនិត្យការតភ្ជាប់អ៊ីនធឺណិត ហើយព្យាយាមម្ដងទៀត។" - } - }, - "nb": { - "stringUnit": { - "state": "translated", - "value": "Kunne ikke laste inn cmux-teamet ditt. Kontroller internettilkoblingen, og prøv igjen." - } - }, - "pl": { - "stringUnit": { - "state": "translated", - "value": "Nie udało się załadować Twojego zespołu cmux. Sprawdź połączenie z internetem i spróbuj ponownie." - } - }, - "pt-BR": { - "stringUnit": { - "state": "translated", - "value": "Não foi possível carregar sua equipe cmux. Verifique sua conexão com a internet e tente novamente." - } - }, - "ru": { - "stringUnit": { - "state": "translated", - "value": "Не удалось загрузить вашу команду cmux. Проверьте подключение к интернету и попробуйте ещё раз." - } - }, - "th": { - "stringUnit": { - "state": "translated", - "value": "ไม่สามารถโหลดทีม cmux ของคุณได้ ตรวจสอบการเชื่อมต่ออินเทอร์เน็ตแล้วลองอีกครั้ง" - } - }, - "tr": { - "stringUnit": { - "state": "translated", - "value": "cmux ekibiniz yüklenemedi. İnternet bağlantınızı kontrol edip tekrar deneyin." - } - }, - "uk": { - "stringUnit": { - "state": "translated", - "value": "Не вдалося завантажити вашу команду cmux. Перевірте підключення до інтернету й спробуйте ще раз." - } - } - } -}, "settings.app.reorderOnNotification.mode.agentActivity": { "extractionState": "manual", "localizations": { @@ -566789,244 +566781,6 @@ } } }, - "command.newPaneAutoLayout.title": { - "extractionState": "manual", - "localizations": { - "ar": { - "stringUnit": { - "state": "translated", - "value": "لوحة جديدة (تخطيط تلقائي)" - } - }, - "bs": { - "stringUnit": { - "state": "translated", - "value": "Novi panel (automatski raspored)" - } - }, - "da": { - "stringUnit": { - "state": "translated", - "value": "Nyt panel (automatisk layout)" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Neuer Bereich (automatisches Layout)" - } - }, - "en": { - "stringUnit": { - "state": "translated", - "value": "New Pane (Auto Layout)" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "Nuevo panel (diseño automático)" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "Nouveau panneau (disposition automatique)" - } - }, - "it": { - "stringUnit": { - "state": "translated", - "value": "Nuovo pannello (layout automatico)" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "新しいペイン(自動レイアウト)" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "새 패널 (자동 레이아웃)" - } - }, - "nb": { - "stringUnit": { - "state": "translated", - "value": "Nytt panel (automatisk oppsett)" - } - }, - "pl": { - "stringUnit": { - "state": "translated", - "value": "Nowy panel (układ automatyczny)" - } - }, - "pt-BR": { - "stringUnit": { - "state": "translated", - "value": "Novo Painel (Layout Automático)" - } - }, - "ru": { - "stringUnit": { - "state": "translated", - "value": "Новая панель (автоматическая раскладка)" - } - }, - "th": { - "stringUnit": { - "state": "translated", - "value": "บานหน้าต่างใหม่ (จัดวางอัตโนมัติ)" - } - }, - "tr": { - "stringUnit": { - "state": "translated", - "value": "Yeni Bölme (Otomatik Düzen)" - } - }, - "uk": { - "stringUnit": { - "state": "translated", - "value": "Нова панель (автоматичне розташування)" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "新建窗格(自动布局)" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "新增窗格(自動佈局)" - } - } - } - }, - "shortcut.newPaneAutoLayout.label": { - "extractionState": "manual", - "localizations": { - "ar": { - "stringUnit": { - "state": "translated", - "value": "لوحة جديدة (تخطيط تلقائي)" - } - }, - "bs": { - "stringUnit": { - "state": "translated", - "value": "Novi panel (automatski raspored)" - } - }, - "da": { - "stringUnit": { - "state": "translated", - "value": "Nyt panel (automatisk layout)" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Neuer Bereich (automatisches Layout)" - } - }, - "en": { - "stringUnit": { - "state": "translated", - "value": "New Pane (Auto Layout)" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "Nuevo panel (diseño automático)" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "Nouveau panneau (disposition automatique)" - } - }, - "it": { - "stringUnit": { - "state": "translated", - "value": "Nuovo pannello (layout automatico)" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "新しいペイン(自動レイアウト)" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "새 패널 (자동 레이아웃)" - } - }, - "nb": { - "stringUnit": { - "state": "translated", - "value": "Nytt panel (automatisk oppsett)" - } - }, - "pl": { - "stringUnit": { - "state": "translated", - "value": "Nowy panel (układ automatyczny)" - } - }, - "pt-BR": { - "stringUnit": { - "state": "translated", - "value": "Novo Painel (Layout Automático)" - } - }, - "ru": { - "stringUnit": { - "state": "translated", - "value": "Новая панель (автоматическая раскладка)" - } - }, - "th": { - "stringUnit": { - "state": "translated", - "value": "บานหน้าต่างใหม่ (จัดวางอัตโนมัติ)" - } - }, - "tr": { - "stringUnit": { - "state": "translated", - "value": "Yeni Bölme (Otomatik Düzen)" - } - }, - "uk": { - "stringUnit": { - "state": "translated", - "value": "Нова панель (автоматичне розташування)" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "新建窗格(自动布局)" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "新增窗格(自動佈局)" - } - } - } - }, "cli.restoreSession.help": { "extractionState": "manual", "localizations": { @@ -568679,65 +568433,6 @@ } } }, - "cli.restore.notice.routedLauncherUnavailable": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "restore: this session was started through the routed launcher '%@', which is not on PATH. Resuming the agent directly instead." - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "restore: このセッションはルーティングされたランチャー「%@」経由で開始されましたが、PATH にありません。代わりにエージェントを直接再開します。" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "restore:此会话是通过路由启动器“%@”启动的,但它不在 PATH 中。将改为直接恢复该代理。" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "restore: Diese Sitzung wurde über den weitergeleiteten Launcher „%@“ gestartet, der nicht im PATH liegt. Der Agent wird stattdessen direkt fortgesetzt." - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "restore : cette session a été lancée via le lanceur routé « %@ », qui est introuvable dans le PATH. Reprise directe de l'agent à la place." - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "restore: بدأت هذه الجلسة عبر المشغّل الموجَّه '%@'، وهو غير موجود في PATH. سيتم استئناف الوكيل مباشرةً بدلاً من ذلك." - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "restore: esta sesión se inició mediante el lanzador enrutado '%@', que no está en el PATH. Se reanudará el agente directamente." - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "restore:此工作階段是透過路由啟動器「%@」啟動的,但它不在 PATH 中。將改為直接繼續該代理程式。" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "restore: 이 세션은 라우팅된 런처 '%@'를 통해 시작되었지만 PATH에 없습니다. 대신 에이전트를 직접 재개합니다." - } - } - } - }, "cli.focus.defaultHelp": { "extractionState": "manual", "localizations": { @@ -569446,301 +569141,6 @@ } } }, - "settings.app.compactAgentStatus": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Compact Agent Status" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "حالة الوكيل المختصرة" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Kompakter Agentenstatus" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "Estado de agente compacto" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "Statut d’agent compact" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "エージェント状態のコンパクト表示" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "간결한 에이전트 상태" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "精简代理状态" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "精簡代理狀態" - } - } - } - }, - "settings.app.compactAgentStatus.subtitle": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Show a workspace's agent, unread and pull request state as one colored icon before the title instead of separate rows. Hover the icon for details." - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "إظهار حالة الوكيل والعناصر غير المقروءة وطلب السحب لمساحة العمل كأيقونة ملونة واحدة قبل العنوان بدلاً من صفوف منفصلة. مرّر المؤشر فوق الأيقونة لعرض التفاصيل." - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Agenten-, Ungelesen- und Pull-Request-Status eines Workspace als ein farbiges Symbol vor dem Titel anzeigen statt in eigenen Zeilen. Details erscheinen, wenn du den Zeiger über das Symbol bewegst." - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "Mostrar el estado del agente, lo no leído y la pull request de un espacio de trabajo como un único icono de color antes del título, en lugar de filas separadas. Pasa el cursor sobre el icono para ver los detalles." - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "Afficher l’état de l’agent, des éléments non lus et de la pull request d’un espace de travail sous forme d’une seule icône colorée avant le titre, au lieu de lignes distinctes. Survolez l’icône pour voir les détails." - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "ワークスペースのエージェント、未読、プルリクエストの状態を、個別の行ではなくタイトルの前の色付きアイコン1つで示します。詳細はアイコンにポインタを合わせると表示されます。" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "워크스페이스의 에이전트, 읽지 않음, 풀 리퀘스트 상태를 별도의 줄이 아니라 제목 앞의 색상 아이콘 하나로 나타냅니다. 자세한 내용은 아이콘 위에 포인터를 올려 확인하세요." - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "用标题前的单个彩色图标表示工作区的代理、未读和拉取请求状态,而不是各自占一行。将指针悬停在图标上可查看详细信息。" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "以標題前的單一彩色圖示表示工作區的代理、未讀與拉取請求狀態,而非各自佔一行。將游標移到圖示上可查看詳細資訊。" - } - } - } - }, - "settings.search.alias.setting.app.compact-agent-status": { - "extractionState": "manual", - "localizations": { - "ar": { - "stringUnit": { - "state": "translated", - "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex مختصر وكيل حالة أيقونة سطر العنوان" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex kompakt Agent Status Symbol Titelzeile" - } - }, - "en": { - "stringUnit": { - "state": "translated", - "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex compacto agente estado icono línea de título" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex compact agent statut icône ligne de titre" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex コンパクト エージェント 状態 アイコン タイトル行" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex 간결 에이전트 상태 아이콘 제목 줄" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex 精简 代理 状态 图标 标题行" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex 精簡 代理 狀態 圖示 標題列" - } - } - } - }, - "sidebar.agentStatus.glyph.tooltip": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "%1$@: %2$@" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "%1$@: %2$@" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "%1$@: %2$@" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "%1$@: %2$@" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "%1$@ : %2$@" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "%1$@:%2$@" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "%1$@: %2$@" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "%1$@:%2$@" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "%1$@:%2$@" - } - } - } - }, - "sidebar.compactStatus.profile": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Profile" - } - }, - "ar": { - "stringUnit": { - "state": "translated", - "value": "الملف الشخصي" - } - }, - "de": { - "stringUnit": { - "state": "translated", - "value": "Profil" - } - }, - "es": { - "stringUnit": { - "state": "translated", - "value": "Perfil" - } - }, - "fr": { - "stringUnit": { - "state": "translated", - "value": "Profil" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "プロファイル" - } - }, - "ko": { - "stringUnit": { - "state": "translated", - "value": "프로필" - } - }, - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "配置文件" - } - }, - "zh-Hant": { - "stringUnit": { - "state": "translated", - "value": "設定檔" - } - } - } - }, "sidebar.extensions.action.noSpaceForPane": { "extractionState": "manual", "localizations": { @@ -569800,238 +569200,297 @@ } } }, - "machines.requiresPro.upgrade.short": { + "settings.app.compactAgentStatus": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Upgrade" + "value": "Compact Agent Status" } }, "ar": { "stringUnit": { "state": "translated", - "value": "ترقية" + "value": "حالة الوكيل المختصرة" } }, "de": { "stringUnit": { "state": "translated", - "value": "Upgraden" + "value": "Kompakter Agentenstatus" } }, "es": { "stringUnit": { "state": "translated", - "value": "Actualizar" + "value": "Estado de agente compacto" } }, "fr": { "stringUnit": { "state": "translated", - "value": "Mettre à niveau" + "value": "Statut d’agent compact" } }, "ja": { "stringUnit": { "state": "translated", - "value": "アップグレード" + "value": "エージェント状態のコンパクト表示" } }, "ko": { "stringUnit": { "state": "translated", - "value": "업그레이드" + "value": "간결한 에이전트 상태" } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": "升级" + "value": "精简代理状态" } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "升級" + "value": "精簡代理狀態" } } } }, - "machines.sessionRejected.signInAgain.short": { + "settings.app.compactAgentStatus.subtitle": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Sign In" + "value": "Show a workspace's agent, unread and pull request state as one colored icon before the title instead of separate rows. Hover the icon for details." } }, "ar": { "stringUnit": { "state": "translated", - "value": "تسجيل الدخول" + "value": "إظهار حالة الوكيل والعناصر غير المقروءة وطلب السحب لمساحة العمل كأيقونة ملونة واحدة قبل العنوان بدلاً من صفوف منفصلة. مرّر المؤشر فوق الأيقونة لعرض التفاصيل." } }, "de": { "stringUnit": { "state": "translated", - "value": "Anmelden" + "value": "Agenten-, Ungelesen- und Pull-Request-Status eines Workspace als ein farbiges Symbol vor dem Titel anzeigen statt in eigenen Zeilen. Details erscheinen, wenn du den Zeiger über das Symbol bewegst." } }, "es": { "stringUnit": { "state": "translated", - "value": "Iniciar sesión" + "value": "Mostrar el estado del agente, lo no leído y la pull request de un espacio de trabajo como un único icono de color antes del título, en lugar de filas separadas. Pasa el cursor sobre el icono para ver los detalles." } }, "fr": { "stringUnit": { "state": "translated", - "value": "Se reconnecter" + "value": "Afficher l’état de l’agent, des éléments non lus et de la pull request d’un espace de travail sous forme d’une seule icône colorée avant le titre, au lieu de lignes distinctes. Survolez l’icône pour voir les détails." } }, "ja": { "stringUnit": { "state": "translated", - "value": "再サインイン" + "value": "ワークスペースのエージェント、未読、プルリクエストの状態を、個別の行ではなくタイトルの前の色付きアイコン1つで示します。詳細はアイコンにポインタを合わせると表示されます。" } }, "ko": { "stringUnit": { "state": "translated", - "value": "다시 로그인" + "value": "워크스페이스의 에이전트, 읽지 않음, 풀 리퀘스트 상태를 별도의 줄이 아니라 제목 앞의 색상 아이콘 하나로 나타냅니다. 자세한 내용은 아이콘 위에 포인터를 올려 확인하세요." } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": "重新登录" + "value": "用标题前的单个彩色图标表示工作区的代理、未读和拉取请求状态,而不是各自占一行。将指针悬停在图标上可查看详细信息。" } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "重新登入" + "value": "以標題前的單一彩色圖示表示工作區的代理、未讀與拉取請求狀態,而非各自佔一行。將游標移到圖示上可查看詳細資訊。" } } } }, - "machines.requiresPro.stale": { + "settings.search.alias.setting.app.compact-agent-status": { "extractionState": "manual", "localizations": { + "ar": { + "stringUnit": { + "state": "translated", + "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex مختصر وكيل حالة أيقونة سطر العنوان" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex kompakt Agent Status Symbol Titelzeile" + } + }, "en": { "stringUnit": { "state": "translated", - "value": "Cloud machines need cmux Pro, showing last known" + "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex compacto agente estado icono línea de título" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex compact agent statut icône ligne de titre" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex コンパクト エージェント 状態 アイコン タイトル行" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex 간결 에이전트 상태 아이콘 제목 줄" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex 精简 代理 状态 图标 标题行" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "sidebar.compactAgentStatus compact agent status running needs input glyph icon title line dense claude codex 精簡 代理 狀態 圖示 標題列" + } + } + } + }, + "sidebar.agentStatus.glyph.tooltip": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "%1$@: %2$@" } }, "ar": { "stringUnit": { "state": "translated", - "value": "تتطلب الأجهزة السحابية إصدار cmux Pro، يتم عرض آخر حالة معروفة" + "value": "%1$@: %2$@" } }, "de": { "stringUnit": { "state": "translated", - "value": "Cloud-Maschinen erfordern cmux Pro, zeige letzten bekannten Stand" + "value": "%1$@: %2$@" } }, "es": { "stringUnit": { "state": "translated", - "value": "Las máquinas en la nube requieren cmux Pro, se muestra el último estado conocido" + "value": "%1$@: %2$@" } }, "fr": { "stringUnit": { "state": "translated", - "value": "Les machines Cloud nécessitent cmux Pro, affichage des dernières informations connues" + "value": "%1$@ : %2$@" } }, "ja": { "stringUnit": { "state": "translated", - "value": "Cloud マシンには cmux Pro が必要です。最後の状態を表示中" + "value": "%1$@:%2$@" } }, "ko": { "stringUnit": { "state": "translated", - "value": "클라우드 머신을 사용하려면 cmux Pro가 필요함, 마지막으로 확인된 상태 표시 중" + "value": "%1$@: %2$@" } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": "云端机器需要 cmux Pro,显示的是最后已知状态" + "value": "%1$@:%2$@" } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "雲端機器需要 cmux Pro,顯示上次已知的狀態" + "value": "%1$@:%2$@" } } } }, - "machines.sessionRejected.stale": { + "sidebar.compactStatus.profile": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Sign-in needs a refresh, showing last known" + "value": "Profile" } }, "ar": { "stringUnit": { "state": "translated", - "value": "يحتاج تسجيل الدخول إلى تحديث، يتم عرض آخر حالة معروفة" + "value": "الملف الشخصي" } }, "de": { "stringUnit": { "state": "translated", - "value": "Anmeldung muss aktualisiert werden, zeige letzten bekannten Stand" + "value": "Profil" } }, "es": { "stringUnit": { "state": "translated", - "value": "Es necesario actualizar el inicio de sesión, se muestra el último estado conocido" + "value": "Perfil" } }, "fr": { "stringUnit": { "state": "translated", - "value": "La connexion doit être actualisée, affichage des dernières informations connues" + "value": "Profil" } }, "ja": { "stringUnit": { "state": "translated", - "value": "再サインインが必要です。最後の状態を表示中" + "value": "プロファイル" } }, "ko": { "stringUnit": { "state": "translated", - "value": "로그인 갱신 필요, 마지막으로 확인된 상태 표시 중" + "value": "프로필" } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": "登录状态需要刷新,显示的是最后已知状态" + "value": "配置文件" } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "登入狀態需要重新整理,顯示上次已知的狀態" + "value": "設定檔" } } } @@ -572886,6 +572345,242 @@ } } }, + "machines.requiresPro.upgrade.short": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Upgrade" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "ترقية" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Upgraden" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Actualizar" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Mettre à niveau" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "アップグレード" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "업그레이드" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "升级" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "升級" + } + } + } + }, + "machines.sessionRejected.signInAgain.short": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Sign In" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "تسجيل الدخول" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Anmelden" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Iniciar sesión" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Se reconnecter" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "再サインイン" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "다시 로그인" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "重新登录" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "重新登入" + } + } + } + }, + "machines.requiresPro.stale": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Cloud machines need cmux Pro, showing last known" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "تتطلب الأجهزة السحابية إصدار cmux Pro، يتم عرض آخر حالة معروفة" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Cloud-Maschinen erfordern cmux Pro, zeige letzten bekannten Stand" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Las máquinas en la nube requieren cmux Pro, se muestra el último estado conocido" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Les machines Cloud nécessitent cmux Pro, affichage des dernières informations connues" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "Cloud マシンには cmux Pro が必要です。最後の状態を表示中" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "클라우드 머신을 사용하려면 cmux Pro가 필요함, 마지막으로 확인된 상태 표시 중" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "云端机器需要 cmux Pro,显示的是最后已知状态" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "雲端機器需要 cmux Pro,顯示上次已知的狀態" + } + } + } + }, + "machines.sessionRejected.stale": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Sign-in needs a refresh, showing last known" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "يحتاج تسجيل الدخول إلى تحديث، يتم عرض آخر حالة معروفة" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Anmeldung muss aktualisiert werden, zeige letzten bekannten Stand" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Es necesario actualizar el inicio de sesión, se muestra el último estado conocido" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "La connexion doit être actualisée, affichage des dernières informations connues" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "再サインインが必要です。最後の状態を表示中" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "로그인 갱신 필요, 마지막으로 확인된 상태 표시 중" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "登录状态需要刷新,显示的是最后已知状态" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "登入狀態需要重新整理,顯示上次已知的狀態" + } + } + } + }, "terminal.clipboardReadConfirmation.deny": { "extractionState": "manual", "localizations": { @@ -585900,2490 +585595,2490 @@ } } }, - "settings.terminal.textEditingCommandMovesByWord": { + "cloudTree.action.newCloudMachine": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Command Moves by Word" + "value": "New Cloud Machine" } }, "ar": { "stringUnit": { "state": "translated", - "value": "Command ينقل حسب الكلمة" + "value": "جهاز سحابي جديد" } }, "de": { "stringUnit": { "state": "translated", - "value": "Befehlstaste bewegt wortweise" + "value": "Neue Cloud-Maschine" } }, "es": { "stringUnit": { "state": "translated", - "value": "Comando mueve por palabra" + "value": "Nueva máquina en la nube" } }, "fr": { "stringUnit": { "state": "translated", - "value": "Commande déplace par mot" + "value": "Nouvelle machine cloud" } }, "ja": { "stringUnit": { "state": "translated", - "value": "Command で単語単位に移動" + "value": "新しいクラウドマシン" } }, "ko": { "stringUnit": { "state": "translated", - "value": "Command로 단어 단위 이동" + "value": "새 클라우드 머신" } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Command 按词移动" + "value": "新建云主机" } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "Command 依字移動" + "value": "新增雲端機器" } - } - } - }, - "settings.terminal.textEditingCommandMovesByWord.subtitleOn": { - "extractionState": "manual", - "localizations": { - "en": { + }, + "bs": { "stringUnit": { "state": "translated", - "value": "Command arrow and delete keys move and delete by word, like Option. Control Left and Right Arrow move to the start and end of the line." + "value": "Nova cloud mašina" } }, - "ar": { + "da": { "stringUnit": { "state": "translated", - "value": "تنقل مفاتيح الأسهم والحذف مع Command وتحذف حسب الكلمة، مثل Option. وينقل Control مع السهمين الأيسر والأيمن إلى بداية السطر ونهايته." + "value": "Ny cloud-maskine" } }, - "de": { + "it": { "stringUnit": { "state": "translated", - "value": "Befehlstaste mit Pfeil- und Löschtasten bewegt und löscht wortweise, wie die Wahltaste. Control mit Links- und Rechtspfeil springt an Anfang und Ende der Zeile." + "value": "Nuova macchina cloud" } }, - "es": { + "km": { "stringUnit": { "state": "translated", - "value": "Las flechas y la tecla Eliminar con Comando mueven y borran por palabra, como Opción. Control con las flechas izquierda y derecha va al inicio y al final de la línea." + "value": "ម៉ាស៊ីន Cloud ថ្មី" } }, - "fr": { + "nb": { "stringUnit": { "state": "translated", - "value": "Les flèches et la touche Supprimer avec Commande déplacent et suppriment par mot, comme Option. Contrôle avec les flèches gauche et droite va au début et à la fin de la ligne." + "value": "Ny sky-maskin" } }, - "ja": { + "pl": { "stringUnit": { "state": "translated", - "value": "Command と矢印キー・削除キーで、Option と同じく単語単位に移動・削除します。Control と左右矢印キーで行頭・行末に移動します。" + "value": "Nowa maszyna w chmurze" } }, - "ko": { + "pt-BR": { "stringUnit": { "state": "translated", - "value": "Command 화살표 및 삭제 키가 Option처럼 단어 단위로 이동하고 삭제합니다. Control 왼쪽 및 오른쪽 화살표는 줄의 시작과 끝으로 이동합니다." + "value": "Nova máquina na nuvem" } }, - "zh-Hans": { + "ru": { "stringUnit": { "state": "translated", - "value": "Command 加方向键和删除键按词移动和删除,与 Option 相同。Control 加左右方向键移到行首和行尾。" + "value": "Новая облачная машина" } }, - "zh-Hant": { + "th": { "stringUnit": { "state": "translated", - "value": "Command 加方向鍵與刪除鍵會依字移動與刪除,與 Option 相同。Control 加左右方向鍵會移到行首與行尾。" + "value": "เครื่องคลาวด์ใหม่" + } + }, + "tr": { + "stringUnit": { + "state": "translated", + "value": "Yeni bulut makinesi" + } + }, + "uk": { + "stringUnit": { + "state": "translated", + "value": "Нова хмарна машина" } } } }, - "settings.terminal.textEditingCommandMovesByWord.subtitleOff": { + "terminalContextMenu.copyLink": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Command arrow and delete keys move and delete by line, as in macOS text fields." + "value": "Copy Link" } }, "ar": { "stringUnit": { "state": "translated", - "value": "تنقل مفاتيح الأسهم والحذف مع Command وتحذف حسب السطر، كما في حقول النص في macOS." + "value": "نسخ الرابط" } }, "de": { "stringUnit": { "state": "translated", - "value": "Befehlstaste mit Pfeil- und Löschtasten bewegt und löscht zeilenweise, wie in macOS-Textfeldern." + "value": "Link kopieren" } }, "es": { "stringUnit": { "state": "translated", - "value": "Las flechas y la tecla Eliminar con Comando mueven y borran por línea, como en los campos de texto de macOS." + "value": "Copiar enlace" } }, "fr": { "stringUnit": { "state": "translated", - "value": "Les flèches et la touche Supprimer avec Commande déplacent et suppriment par ligne, comme dans les champs de texte de macOS." + "value": "Copier le lien" } }, "ja": { "stringUnit": { "state": "translated", - "value": "Command と矢印キー・削除キーで、macOS のテキストフィールドと同じく行単位に移動・削除します。" + "value": "リンクをコピー" } }, "ko": { "stringUnit": { "state": "translated", - "value": "Command 화살표 및 삭제 키가 macOS 텍스트 필드처럼 줄 단위로 이동하고 삭제합니다." + "value": "링크 복사" } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Command 加方向键和删除键按行移动和删除,与 macOS 文本框相同。" + "value": "复制链接" } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "Command 加方向鍵與刪除鍵會依行移動與刪除,與 macOS 文字欄位相同。" + "value": "複製連結" } } } }, - "settings.terminal.textEditingGesturesInFullScreenApps": { + "terminalContextMenu.openLinkInCmuxBrowser": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Text Editing Gestures in Full-Screen Apps" + "value": "Open Link in cmux Browser" } }, "ar": { "stringUnit": { "state": "translated", - "value": "إيماءات تحرير النص في التطبيقات بملء الشاشة" + "value": "فتح الرابط في متصفح cmux" } }, "de": { "stringUnit": { "state": "translated", - "value": "Textbearbeitungsgesten in Vollbild-Apps" + "value": "Link im cmux-Browser öffnen" } }, "es": { "stringUnit": { "state": "translated", - "value": "Gestos de edición de texto en apps a pantalla completa" + "value": "Abrir enlace en el navegador de cmux" } }, "fr": { "stringUnit": { "state": "translated", - "value": "Gestes d’édition de texte dans les apps plein écran" + "value": "Ouvrir le lien dans le navigateur cmux" } }, "ja": { "stringUnit": { "state": "translated", - "value": "フルスクリーンアプリでのテキスト編集ジェスチャー" + "value": "リンクをcmuxブラウザで開く" } }, "ko": { "stringUnit": { "state": "translated", - "value": "전체 화면 앱에서 텍스트 편집 제스처" + "value": "링크를 cmux 브라우저에서 열기" } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": "全屏应用中的文本编辑手势" + "value": "在 cmux 浏览器中打开链接" } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "全螢幕 App 中的文字編輯手勢" + "value": "在 cmux 瀏覽器中開啟連結" } } } }, - "settings.terminal.textEditingGesturesInFullScreenApps.subtitle": { + "terminalContextMenu.openLinkInDefaultBrowser": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Gestures also apply while a full-screen app such as vim, less, or tmux is running, so they keep working at a shell inside tmux, screen, or zellij." + "value": "Open Link in Default Browser" } }, "ar": { "stringUnit": { "state": "translated", - "value": "تنطبق الإيماءات أيضًا أثناء تشغيل تطبيق بملء الشاشة مثل vim أو less أو tmux، فتظل تعمل في الصدفة داخل tmux أو screen أو zellij." + "value": "فتح الرابط في المتصفح الافتراضي" } }, "de": { "stringUnit": { "state": "translated", - "value": "Gesten gelten auch, während eine Vollbild-App wie vim, less oder tmux läuft, und funktionieren so weiter an einer Shell in tmux, screen oder zellij." + "value": "Link im Standardbrowser öffnen" } }, "es": { "stringUnit": { "state": "translated", - "value": "Los gestos también se aplican mientras se ejecuta una app a pantalla completa como vim, less o tmux, así que siguen funcionando en una shell dentro de tmux, screen o zellij." + "value": "Abrir enlace en el navegador predeterminado" } }, "fr": { "stringUnit": { "state": "translated", - "value": "Les gestes s’appliquent aussi lorsqu’une app plein écran comme vim, less ou tmux est en cours d’exécution, et continuent donc de fonctionner dans un shell sous tmux, screen ou zellij." + "value": "Ouvrir le lien dans le navigateur par défaut" } }, "ja": { "stringUnit": { "state": "translated", - "value": "vim、less、tmux などのフルスクリーンアプリの実行中もジェスチャーが有効になるため、tmux、screen、zellij 内のシェルでも引き続き使えます。" + "value": "リンクをデフォルトブラウザで開く" } }, "ko": { "stringUnit": { "state": "translated", - "value": "vim, less, tmux 같은 전체 화면 앱이 실행 중일 때도 제스처가 적용되므로 tmux, screen, zellij 안의 셸에서도 계속 작동합니다." + "value": "링크를 기본 브라우저에서 열기" } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": "在 vim、less 或 tmux 等全屏应用运行时手势也会生效,因此在 tmux、screen 或 zellij 中的 shell 里仍可使用。" + "value": "在默认浏览器中打开链接" } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "在 vim、less 或 tmux 等全螢幕 App 執行時手勢也會生效,因此在 tmux、screen 或 zellij 中的 shell 裡仍可使用。" + "value": "在預設瀏覽器中開啟連結" } } } }, - "cloudTree.action.newCloudMachine": { + "cli.restore.error.routedLauncherNotFound": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "New Cloud Machine" + "value": "restore: this session was started with '%1$@ claude proxy', but '%1$@' is not on PATH in this shell. Add it to PATH, then retry." } }, - "ar": { + "ja": { "stringUnit": { "state": "translated", - "value": "جهاز سحابي جديد" + "value": "restore: このセッションは「%1$@ claude proxy」で起動されましたが、このシェルの PATH に「%1$@」がありません。PATH に追加してから、再試行してください。" } }, - "de": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Neue Cloud-Maschine" + "value": "restore:此会话是通过“%1$@ claude proxy”启动的,但此 shell 的 PATH 中没有“%1$@”。请将其添加到 PATH,然后重试。" } }, - "es": { + "de": { "stringUnit": { "state": "translated", - "value": "Nueva máquina en la nube" + "value": "restore: Diese Sitzung wurde mit „%1$@ claude proxy“ gestartet, aber „%1$@“ ist in dieser Shell nicht im PATH. Fügen Sie es zum PATH hinzu und versuchen Sie es dann erneut." } }, "fr": { "stringUnit": { "state": "translated", - "value": "Nouvelle machine cloud" - } - }, - "ja": { - "stringUnit": { - "state": "translated", - "value": "新しいクラウドマシン" + "value": "restore : cette session a été démarrée avec « %1$@ claude proxy », mais « %1$@ » n'est pas dans le PATH de ce shell. Ajoutez-le au PATH, puis réessayez." } }, - "ko": { + "ar": { "stringUnit": { "state": "translated", - "value": "새 클라우드 머신" + "value": "restore: بدأت هذه الجلسة باستخدام '%1$@ claude proxy'، لكن '%1$@' غير موجود في PATH في هذه الصدفة. أضفه إلى PATH، ثم أعد المحاولة." } }, - "zh-Hans": { + "es": { "stringUnit": { "state": "translated", - "value": "新建云主机" + "value": "restore: esta sesión se inició con '%1$@ claude proxy', pero '%1$@' no está en el PATH de este shell. Agréguelo al PATH y vuelva a intentarlo." } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "新增雲端機器" - } - }, - "bs": { - "stringUnit": { - "state": "translated", - "value": "Nova cloud mašina" + "value": "restore:此工作階段是以「%1$@ claude proxy」啟動的,但此 shell 的 PATH 中沒有「%1$@」。請將其加入 PATH,然後重試。" } }, - "da": { + "ko": { "stringUnit": { "state": "translated", - "value": "Ny cloud-maskine" + "value": "restore: 이 세션은 '%1$@ claude proxy'로 시작되었지만 이 셸의 PATH에 '%1$@'이(가) 없습니다. PATH에 추가한 후 다시 시도하십시오." } - }, - "it": { + } + } + }, + "settings.terminal.textEditingCommandMovesByWord": { + "extractionState": "manual", + "localizations": { + "en": { "stringUnit": { "state": "translated", - "value": "Nuova macchina cloud" + "value": "Command Moves by Word" } }, - "km": { + "ar": { "stringUnit": { "state": "translated", - "value": "ម៉ាស៊ីន Cloud ថ្មី" + "value": "Command ينقل حسب الكلمة" } }, - "nb": { + "de": { "stringUnit": { "state": "translated", - "value": "Ny sky-maskin" + "value": "Befehlstaste bewegt wortweise" } }, - "pl": { + "es": { "stringUnit": { "state": "translated", - "value": "Nowa maszyna w chmurze" + "value": "Comando mueve por palabra" } }, - "pt-BR": { + "fr": { "stringUnit": { "state": "translated", - "value": "Nova máquina na nuvem" + "value": "Commande déplace par mot" } }, - "ru": { + "ja": { "stringUnit": { "state": "translated", - "value": "Новая облачная машина" + "value": "Command で単語単位に移動" } }, - "th": { + "ko": { "stringUnit": { "state": "translated", - "value": "เครื่องคลาวด์ใหม่" + "value": "Command로 단어 단위 이동" } }, - "tr": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Yeni bulut makinesi" + "value": "Command 按词移动" } }, - "uk": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "Нова хмарна машина" + "value": "Command 依字移動" } } } }, - "terminalContextMenu.copyLink": { + "settings.terminal.textEditingCommandMovesByWord.subtitleOn": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Copy Link" + "value": "Command arrow and delete keys move and delete by word, like Option. Control Left and Right Arrow move to the start and end of the line." } }, "ar": { "stringUnit": { "state": "translated", - "value": "نسخ الرابط" + "value": "تنقل مفاتيح الأسهم والحذف مع Command وتحذف حسب الكلمة، مثل Option. وينقل Control مع السهمين الأيسر والأيمن إلى بداية السطر ونهايته." } }, "de": { "stringUnit": { "state": "translated", - "value": "Link kopieren" + "value": "Befehlstaste mit Pfeil- und Löschtasten bewegt und löscht wortweise, wie die Wahltaste. Control mit Links- und Rechtspfeil springt an Anfang und Ende der Zeile." } }, "es": { "stringUnit": { "state": "translated", - "value": "Copiar enlace" + "value": "Las flechas y la tecla Eliminar con Comando mueven y borran por palabra, como Opción. Control con las flechas izquierda y derecha va al inicio y al final de la línea." } }, "fr": { "stringUnit": { "state": "translated", - "value": "Copier le lien" + "value": "Les flèches et la touche Supprimer avec Commande déplacent et suppriment par mot, comme Option. Contrôle avec les flèches gauche et droite va au début et à la fin de la ligne." } }, "ja": { "stringUnit": { "state": "translated", - "value": "リンクをコピー" + "value": "Command と矢印キー・削除キーで、Option と同じく単語単位に移動・削除します。Control と左右矢印キーで行頭・行末に移動します。" } }, "ko": { "stringUnit": { "state": "translated", - "value": "링크 복사" + "value": "Command 화살표 및 삭제 키가 Option처럼 단어 단위로 이동하고 삭제합니다. Control 왼쪽 및 오른쪽 화살표는 줄의 시작과 끝으로 이동합니다." } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": "复制链接" + "value": "Command 加方向键和删除键按词移动和删除,与 Option 相同。Control 加左右方向键移到行首和行尾。" } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "複製連結" + "value": "Command 加方向鍵與刪除鍵會依字移動與刪除,與 Option 相同。Control 加左右方向鍵會移到行首與行尾。" } } } }, - "terminalContextMenu.openLinkInCmuxBrowser": { + "settings.terminal.textEditingCommandMovesByWord.subtitleOff": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Open Link in cmux Browser" + "value": "Command arrow and delete keys move and delete by line, as in macOS text fields." } }, "ar": { "stringUnit": { "state": "translated", - "value": "فتح الرابط في متصفح cmux" + "value": "تنقل مفاتيح الأسهم والحذف مع Command وتحذف حسب السطر، كما في حقول النص في macOS." } }, "de": { "stringUnit": { "state": "translated", - "value": "Link im cmux-Browser öffnen" + "value": "Befehlstaste mit Pfeil- und Löschtasten bewegt und löscht zeilenweise, wie in macOS-Textfeldern." } }, "es": { "stringUnit": { "state": "translated", - "value": "Abrir enlace en el navegador de cmux" + "value": "Las flechas y la tecla Eliminar con Comando mueven y borran por línea, como en los campos de texto de macOS." } }, "fr": { "stringUnit": { "state": "translated", - "value": "Ouvrir le lien dans le navigateur cmux" + "value": "Les flèches et la touche Supprimer avec Commande déplacent et suppriment par ligne, comme dans les champs de texte de macOS." } }, "ja": { "stringUnit": { "state": "translated", - "value": "リンクをcmuxブラウザで開く" + "value": "Command と矢印キー・削除キーで、macOS のテキストフィールドと同じく行単位に移動・削除します。" } }, "ko": { "stringUnit": { "state": "translated", - "value": "링크를 cmux 브라우저에서 열기" + "value": "Command 화살표 및 삭제 키가 macOS 텍스트 필드처럼 줄 단위로 이동하고 삭제합니다." } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": "在 cmux 浏览器中打开链接" + "value": "Command 加方向键和删除键按行移动和删除,与 macOS 文本框相同。" } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "在 cmux 瀏覽器中開啟連結" + "value": "Command 加方向鍵與刪除鍵會依行移動與刪除,與 macOS 文字欄位相同。" } } } }, - "terminalContextMenu.openLinkInDefaultBrowser": { + "settings.terminal.textEditingGesturesInFullScreenApps": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Open Link in Default Browser" + "value": "Text Editing Gestures in Full-Screen Apps" } }, "ar": { "stringUnit": { "state": "translated", - "value": "فتح الرابط في المتصفح الافتراضي" + "value": "إيماءات تحرير النص في التطبيقات بملء الشاشة" } }, "de": { "stringUnit": { "state": "translated", - "value": "Link im Standardbrowser öffnen" + "value": "Textbearbeitungsgesten in Vollbild-Apps" } }, "es": { "stringUnit": { "state": "translated", - "value": "Abrir enlace en el navegador predeterminado" + "value": "Gestos de edición de texto en apps a pantalla completa" } }, "fr": { "stringUnit": { "state": "translated", - "value": "Ouvrir le lien dans le navigateur par défaut" + "value": "Gestes d’édition de texte dans les apps plein écran" } }, "ja": { "stringUnit": { "state": "translated", - "value": "リンクをデフォルトブラウザで開く" + "value": "フルスクリーンアプリでのテキスト編集ジェスチャー" } }, "ko": { "stringUnit": { "state": "translated", - "value": "링크를 기본 브라우저에서 열기" + "value": "전체 화면 앱에서 텍스트 편집 제스처" } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": "在默认浏览器中打开链接" + "value": "全屏应用中的文本编辑手势" } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "在預設瀏覽器中開啟連結" + "value": "全螢幕 App 中的文字編輯手勢" } } } }, - "cli.restore.error.routedLauncherNotFound": { + "settings.terminal.textEditingGesturesInFullScreenApps.subtitle": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "restore: this session was started with '%1$@ claude proxy', but '%1$@' is not on PATH in this shell. Add it to PATH, then retry." + "value": "Gestures also apply while a full-screen app such as vim, less, or tmux is running, so they keep working at a shell inside tmux, screen, or zellij." } }, - "ja": { + "ar": { "stringUnit": { "state": "translated", - "value": "restore: このセッションは「%1$@ claude proxy」で起動されましたが、このシェルの PATH に「%1$@」がありません。PATH に追加してから、再試行してください。" + "value": "تنطبق الإيماءات أيضًا أثناء تشغيل تطبيق بملء الشاشة مثل vim أو less أو tmux، فتظل تعمل في الصدفة داخل tmux أو screen أو zellij." } }, - "zh-Hans": { + "de": { "stringUnit": { "state": "translated", - "value": "restore:此会话是通过“%1$@ claude proxy”启动的,但此 shell 的 PATH 中没有“%1$@”。请将其添加到 PATH,然后重试。" + "value": "Gesten gelten auch, während eine Vollbild-App wie vim, less oder tmux läuft, und funktionieren so weiter an einer Shell in tmux, screen oder zellij." } }, - "de": { + "es": { "stringUnit": { "state": "translated", - "value": "restore: Diese Sitzung wurde mit „%1$@ claude proxy“ gestartet, aber „%1$@“ ist in dieser Shell nicht im PATH. Fügen Sie es zum PATH hinzu und versuchen Sie es dann erneut." + "value": "Los gestos también se aplican mientras se ejecuta una app a pantalla completa como vim, less o tmux, así que siguen funcionando en una shell dentro de tmux, screen o zellij." } }, "fr": { "stringUnit": { "state": "translated", - "value": "restore : cette session a été démarrée avec « %1$@ claude proxy », mais « %1$@ » n'est pas dans le PATH de ce shell. Ajoutez-le au PATH, puis réessayez." + "value": "Les gestes s’appliquent aussi lorsqu’une app plein écran comme vim, less ou tmux est en cours d’exécution, et continuent donc de fonctionner dans un shell sous tmux, screen ou zellij." } }, - "ar": { + "ja": { "stringUnit": { "state": "translated", - "value": "restore: بدأت هذه الجلسة باستخدام '%1$@ claude proxy'، لكن '%1$@' غير موجود في PATH في هذه الصدفة. أضفه إلى PATH، ثم أعد المحاولة." + "value": "vim、less、tmux などのフルスクリーンアプリの実行中もジェスチャーが有効になるため、tmux、screen、zellij 内のシェルでも引き続き使えます。" } }, - "es": { + "ko": { "stringUnit": { "state": "translated", - "value": "restore: esta sesión se inició con '%1$@ claude proxy', pero '%1$@' no está en el PATH de este shell. Agréguelo al PATH y vuelva a intentarlo." + "value": "vim, less, tmux 같은 전체 화면 앱이 실행 중일 때도 제스처가 적용되므로 tmux, screen, zellij 안의 셸에서도 계속 작동합니다." } }, - "zh-Hant": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "restore:此工作階段是以「%1$@ claude proxy」啟動的,但此 shell 的 PATH 中沒有「%1$@」。請將其加入 PATH,然後重試。" + "value": "在 vim、less 或 tmux 等全屏应用运行时手势也会生效,因此在 tmux、screen 或 zellij 中的 shell 里仍可使用。" } }, - "ko": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "restore: 이 세션은 '%1$@ claude proxy'로 시작되었지만 이 셸의 PATH에 '%1$@'이(가) 없습니다. PATH에 추가한 후 다시 시도하십시오." + "value": "在 vim、less 或 tmux 等全螢幕 App 執行時手勢也會生效,因此在 tmux、screen 或 zellij 中的 shell 裡仍可使用。" } } } }, - "socket.sidebar.closeSurface.confirmationRequired": { + "shortcut.diffViewerToggleViewed.label": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Surface has a running process; retry with --force" + "value": "Diff Viewer: Toggle Viewed" } }, - "ar": { + "ja": { "stringUnit": { "state": "translated", - "value": "تحتوي السطح على عملية قيد التشغيل؛ أعد المحاولة باستخدام --force" + "value": "差分ビューア: 確認済みを切り替え" } }, - "de": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Die Oberfläche hat einen laufenden Prozess; erneut mit --force versuchen" + "value": "差异查看器:切换已查看" } }, - "es": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "La superficie tiene un proceso en ejecución; vuelve a intentarlo con --force" + "value": "差異檢視器:切換已檢視" } }, - "fr": { + "de": { "stringUnit": { "state": "translated", - "value": "La surface a un processus en cours d’exécution ; réessayez avec --force" + "value": "Diff-Viewer: Angesehen umschalten" } }, - "ja": { + "fr": { "stringUnit": { "state": "translated", - "value": "サーフェスでプロセスが実行中です。--force を指定して再試行してください" + "value": "Visionneuse de diff : Basculer « vu »" } }, - "ko": { + "ar": { "stringUnit": { "state": "translated", - "value": "표면에서 실행 중인 프로세스가 있습니다. --force로 다시 시도하세요" + "value": "عارض الفروق: تبديل حالة المشاهدة" } }, - "zh-Hans": { + "es": { "stringUnit": { "state": "translated", - "value": "此表面有正在运行的进程;请使用 --force 重试" + "value": "Visor de diff: Alternar visto" } }, - "zh-Hant": { + "ko": { "stringUnit": { "state": "translated", - "value": "此表面有正在執行的程序;請使用 --force 重試" + "value": "차이 뷰어: 확인함 전환" } } } }, - "socket.sidebar.closeSurface.failed": { + "diffViewer.viewed": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Failed to close surface" + "value": "Viewed" } }, - "ar": { + "ja": { "stringUnit": { "state": "translated", - "value": "تعذر إغلاق السطح" + "value": "確認済み" } }, - "de": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Die Oberfläche konnte nicht geschlossen werden" + "value": "已查看" } }, - "es": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "No se pudo cerrar la superficie" + "value": "已檢視" } }, - "fr": { + "de": { "stringUnit": { "state": "translated", - "value": "Échec de la fermeture de la surface" + "value": "Angesehen" } }, - "ja": { + "fr": { "stringUnit": { "state": "translated", - "value": "サーフェスを閉じられませんでした" + "value": "Vu" } }, - "ko": { + "ar": { "stringUnit": { "state": "translated", - "value": "표면을 닫지 못했습니다" + "value": "تمت المشاهدة" } }, - "zh-Hans": { + "es": { "stringUnit": { "state": "translated", - "value": "无法关闭此表面" + "value": "Visto" } }, - "zh-Hant": { + "ko": { "stringUnit": { "state": "translated", - "value": "無法關閉表面" + "value": "확인함" } } } }, - "socket.surface.close.confirmationRequired": { + "diffViewer.markViewed": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Surface has a running process; retry with force=true" + "value": "Mark as viewed" } }, - "ar": { + "ja": { "stringUnit": { "state": "translated", - "value": "تحتوي السطح على عملية قيد التشغيل؛ أعد المحاولة باستخدام force=true" + "value": "確認済みにする" } }, - "de": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Die Oberfläche hat einen laufenden Prozess; erneut mit force=true versuchen" + "value": "标记为已查看" } }, - "es": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "La superficie tiene un proceso en ejecución; vuelve a intentarlo con force=true" + "value": "標記為已檢視" } }, - "fr": { + "de": { "stringUnit": { "state": "translated", - "value": "La surface a un processus en cours d’exécution ; réessayez avec force=true" + "value": "Als angesehen markieren" } }, - "ja": { + "fr": { "stringUnit": { "state": "translated", - "value": "サーフェスでプロセスが実行中です。force=true を指定して再試行してください" + "value": "Marquer comme vu" } }, - "ko": { + "ar": { "stringUnit": { "state": "translated", - "value": "표면에서 실행 중인 프로세스가 있습니다. force=true로 다시 시도하세요" + "value": "وضع علامة تمت المشاهدة" } }, - "zh-Hans": { + "es": { "stringUnit": { "state": "translated", - "value": "此表面有正在运行的进程;请使用 force=true 重试" + "value": "Marcar como visto" } }, - "zh-Hant": { + "ko": { "stringUnit": { "state": "translated", - "value": "此表面有正在執行的程序;請使用 force=true 重試" + "value": "확인함으로 표시" } } } }, - "socket.surface.close.failed": { + "diffViewer.markNotViewed": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Failed to close surface" + "value": "Mark as not viewed" } }, - "ar": { + "ja": { "stringUnit": { "state": "translated", - "value": "تعذر إغلاق السطح" + "value": "未確認にする" } }, - "de": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Die Oberfläche konnte nicht geschlossen werden" + "value": "标记为未查看" } }, - "es": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "No se pudo cerrar la superficie" + "value": "標記為未檢視" } }, - "fr": { + "de": { "stringUnit": { "state": "translated", - "value": "Échec de la fermeture de la surface" + "value": "Als nicht angesehen markieren" } }, - "ja": { + "fr": { "stringUnit": { "state": "translated", - "value": "サーフェスを閉じられませんでした" + "value": "Marquer comme non vu" } }, - "ko": { + "ar": { "stringUnit": { "state": "translated", - "value": "표면을 닫지 못했습니다" + "value": "إزالة علامة تمت المشاهدة" } }, - "zh-Hans": { + "es": { "stringUnit": { "state": "translated", - "value": "无法关闭此表面" + "value": "Marcar como no visto" } }, - "zh-Hant": { + "ko": { "stringUnit": { "state": "translated", - "value": "無法關閉表面" + "value": "확인 안 함으로 표시" } } } }, - "socket.tabAction.close.confirmationRequired": { + "diffViewer.changedSinceViewed": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "One or more surfaces have a running process; retry with force=true" + "value": "Changed since viewed" } }, - "ar": { + "ja": { "stringUnit": { "state": "translated", - "value": "سطح واحد أو أكثر يحتوي على عملية قيد التشغيل؛ أعد المحاولة باستخدام force=true" + "value": "確認後に変更あり" } }, - "de": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Mindestens eine Oberfläche hat einen laufenden Prozess; erneut mit force=true versuchen" + "value": "查看后已更改" } }, - "es": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "Una o más superficies tienen un proceso en ejecución; vuelve a intentarlo con force=true" + "value": "檢視後已變更" } }, - "fr": { + "de": { "stringUnit": { "state": "translated", - "value": "Une ou plusieurs surfaces ont un processus en cours d’exécution ; réessayez avec force=true" + "value": "Seit dem Ansehen geändert" } }, - "ja": { + "fr": { "stringUnit": { "state": "translated", - "value": "1 つ以上のサーフェスでプロセスが実行中です。force=true を指定して再試行してください" + "value": "Modifié depuis la consultation" } }, - "ko": { + "ar": { "stringUnit": { "state": "translated", - "value": "하나 이상의 표면에서 프로세스가 실행 중입니다. force=true로 다시 시도하세요" + "value": "تغيّر منذ المشاهدة" } }, - "zh-Hans": { + "es": { "stringUnit": { "state": "translated", - "value": "一个或多个表面有正在运行的进程;请使用 force=true 重试" + "value": "Cambiado desde que se vio" } }, - "zh-Hant": { + "ko": { "stringUnit": { "state": "translated", - "value": "一個或多個表面有正在執行的程序;請使用 force=true 重試" + "value": "확인 후 변경됨" } } } }, - "cli.socket.error.workspaceCloseConfirmationRequired": { + "diffViewer.filesViewedProgress": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Workspace has a running process; retry with --force" + "value": "{viewed} of {total} files viewed" } }, - "ar": { + "ja": { "stringUnit": { "state": "translated", - "value": "تحتوي مساحة العمل على عملية قيد التشغيل؛ أعد المحاولة باستخدام --force" + "value": "{total} 件中 {viewed} 件のファイルを確認済み" } }, - "de": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Arbeitsbereich mit laufendem Prozess; erneut mit --force versuchen" + "value": "已查看 {viewed}/{total} 个文件" } }, - "es": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "El espacio de trabajo tiene un proceso en ejecución; vuelve a intentarlo con --force" + "value": "已檢視 {viewed}/{total} 個檔案" } }, - "fr": { + "de": { "stringUnit": { "state": "translated", - "value": "L’espace de travail a un processus en cours d’exécution ; réessayez avec --force" + "value": "{viewed} von {total} Dateien angesehen" } }, - "ja": { + "fr": { "stringUnit": { "state": "translated", - "value": "ワークスペースでプロセスが実行中です。--force を指定して再試行してください" + "value": "{viewed} fichiers sur {total} vus" } }, - "ko": { + "ar": { "stringUnit": { "state": "translated", - "value": "워크스페이스에서 프로세스가 실행 중입니다. --force로 다시 시도하세요" + "value": "تمت مشاهدة {viewed} من {total} ملفات" } }, - "zh-Hans": { + "es": { "stringUnit": { "state": "translated", - "value": "此工作区有正在运行的进程;请使用 --force 重试" + "value": "{viewed} de {total} archivos vistos" } }, - "zh-Hant": { + "ko": { "stringUnit": { "state": "translated", - "value": "此工作區有正在執行的程序;請使用 --force 重試" + "value": "{total}개 중 {viewed}개 파일 확인함" } } } }, - "cli.socket.error.windowCloseConfirmationRequired": { + "diffViewer.filterFiles": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "One or more workspaces or Dock surfaces have a running process; retry with --force" + "value": "Filter files" } }, - "ar": { + "ja": { "stringUnit": { "state": "translated", - "value": "تحتوي مساحة عمل واحدة أو أكثر أو أسطح Dock على عملية قيد التشغيل؛ أعد المحاولة باستخدام --force" + "value": "ファイルを絞り込む" } }, - "de": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Mindestens ein Workspace oder eine Dock-Oberfläche hat einen laufenden Prozess; erneut mit --force versuchen" + "value": "筛选文件" } }, - "es": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "Uno o más espacios de trabajo o superficies del Dock tienen un proceso en ejecución; vuelve a intentarlo con --force" + "value": "篩選檔案" } }, - "fr": { + "de": { "stringUnit": { "state": "translated", - "value": "Un ou plusieurs espaces de travail ou surfaces du Dock ont un processus en cours d’exécution ; réessayez avec --force" + "value": "Dateien filtern" } }, - "ja": { + "fr": { "stringUnit": { "state": "translated", - "value": "1 つ以上のワークスペースまたは Dock サーフェスでプロセスが実行中です。--force を指定して再試行してください" + "value": "Filtrer les fichiers" } }, - "ko": { + "ar": { "stringUnit": { "state": "translated", - "value": "하나 이상의 워크스페이스 또는 Dock 표면에서 실행 중인 프로세스가 있습니다. --force로 다시 시도하세요" + "value": "تصفية الملفات" } }, - "zh-Hans": { + "es": { "stringUnit": { "state": "translated", - "value": "一个或多个工作区或 Dock 表面有正在运行的进程;请使用 --force 重试" + "value": "Filtrar archivos" } }, - "zh-Hant": { + "ko": { "stringUnit": { "state": "translated", - "value": "一個或多個工作區或 Dock 表面有正在執行的程序;請使用 --force 重試" + "value": "파일 필터" } } } }, - "command.copyWorkingDirectory.title": { + "diffViewer.filterAddedFiles": { "extractionState": "manual", "localizations": { - "ar": { - "stringUnit": { - "state": "translated", - "value": "نسخ دليل العمل" - } - }, - "bs": { + "en": { "stringUnit": { "state": "translated", - "value": "Kopiraj radni direktorij" + "value": "Added" } }, - "da": { + "ja": { "stringUnit": { "state": "translated", - "value": "Kopiér arbejdsmappe" + "value": "追加" } }, - "de": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Arbeitsverzeichnis kopieren" + "value": "新增" } }, - "en": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "Copy Working Directory" + "value": "新增" } }, - "es": { + "de": { "stringUnit": { "state": "translated", - "value": "Copiar directorio de trabajo" + "value": "Hinzugefügt" } }, "fr": { "stringUnit": { "state": "translated", - "value": "Copier le répertoire de travail" + "value": "Ajoutés" } }, - "it": { + "ar": { "stringUnit": { "state": "translated", - "value": "Copia directory di lavoro" + "value": "مضافة" } }, - "ja": { + "es": { "stringUnit": { "state": "translated", - "value": "作業ディレクトリをコピー" + "value": "Añadidos" } }, "ko": { "stringUnit": { "state": "translated", - "value": "작업 디렉터리 복사" + "value": "추가됨" } - }, - "nb": { + } + } + }, + "diffViewer.filterModifiedFiles": { + "extractionState": "manual", + "localizations": { + "en": { "stringUnit": { "state": "translated", - "value": "Kopier arbeidsmappe" + "value": "Modified" } }, - "pl": { + "ja": { "stringUnit": { "state": "translated", - "value": "Kopiuj katalog roboczy" + "value": "変更" } }, - "pt-BR": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Copiar Diretório de Trabalho" + "value": "已修改" } }, - "ru": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "Копировать рабочий каталог" + "value": "已修改" } }, - "th": { + "de": { "stringUnit": { "state": "translated", - "value": "คัดลอกไดเรกทอรีทำงาน" + "value": "Geändert" } }, - "tr": { + "fr": { "stringUnit": { "state": "translated", - "value": "Çalışma Dizinini Kopyala" + "value": "Modifiés" } }, - "uk": { + "ar": { "stringUnit": { "state": "translated", - "value": "Копіювати робочий каталог" + "value": "معدّلة" } }, - "zh-Hans": { + "es": { "stringUnit": { "state": "translated", - "value": "复制工作目录" + "value": "Modificados" } }, - "zh-Hant": { + "ko": { "stringUnit": { "state": "translated", - "value": "複製工作目錄" + "value": "수정됨" } } } }, - "command.copyProjectRoot.title": { + "diffViewer.filterDeletedFiles": { "extractionState": "manual", "localizations": { - "ar": { - "stringUnit": { - "state": "translated", - "value": "نسخ جذر المشروع" - } - }, - "bs": { + "en": { "stringUnit": { "state": "translated", - "value": "Kopiraj korijen projekta" + "value": "Deleted" } }, - "da": { + "ja": { "stringUnit": { "state": "translated", - "value": "Kopiér projektrod" + "value": "削除" } }, - "de": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Projektstamm kopieren" + "value": "已删除" } }, - "en": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "Copy Project Root" + "value": "已刪除" } }, - "es": { + "de": { "stringUnit": { "state": "translated", - "value": "Copiar raíz del proyecto" + "value": "Gelöscht" } }, "fr": { "stringUnit": { "state": "translated", - "value": "Copier la racine du projet" + "value": "Supprimés" } }, - "it": { + "ar": { "stringUnit": { "state": "translated", - "value": "Copia radice del progetto" + "value": "محذوفة" } }, - "ja": { + "es": { "stringUnit": { "state": "translated", - "value": "プロジェクトのルートをコピー" + "value": "Eliminados" } }, "ko": { "stringUnit": { "state": "translated", - "value": "프로젝트 루트 복사" + "value": "삭제됨" } - }, - "nb": { + } + } + }, + "diffViewer.filterRenamedFiles": { + "extractionState": "manual", + "localizations": { + "en": { "stringUnit": { "state": "translated", - "value": "Kopier prosjektrot" + "value": "Renamed" } }, - "pl": { + "ja": { "stringUnit": { "state": "translated", - "value": "Kopiuj katalog główny projektu" + "value": "名前変更" } }, - "pt-BR": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Copiar Raiz do Projeto" + "value": "已重命名" } }, - "ru": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "Копировать корень проекта" + "value": "已重新命名" } }, - "th": { + "de": { "stringUnit": { "state": "translated", - "value": "คัดลอกรากโปรเจกต์" + "value": "Umbenannt" } }, - "tr": { + "fr": { "stringUnit": { "state": "translated", - "value": "Proje Kökünü Kopyala" + "value": "Renommés" } }, - "uk": { + "ar": { "stringUnit": { "state": "translated", - "value": "Копіювати корінь проєкту" + "value": "معاد تسميتها" } }, - "zh-Hans": { + "es": { "stringUnit": { "state": "translated", - "value": "复制项目根目录" + "value": "Renombrados" } }, - "zh-Hant": { + "ko": { "stringUnit": { "state": "translated", - "value": "複製專案根目錄" + "value": "이름 변경됨" } } } }, - "command.copyScreen.title": { + "diffViewer.hideViewedFiles": { "extractionState": "manual", "localizations": { - "ar": { - "stringUnit": { - "state": "translated", - "value": "نسخ الشاشة المرئية" - } - }, - "bs": { + "en": { "stringUnit": { "state": "translated", - "value": "Kopiraj vidljivi ekran" + "value": "Hide viewed files" } }, - "da": { + "ja": { "stringUnit": { "state": "translated", - "value": "Kopiér synlig skærm" + "value": "確認済みのファイルを隠す" } }, - "de": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Sichtbaren Bildschirm kopieren" + "value": "隐藏已查看的文件" } }, - "en": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "Copy Visible Screen" + "value": "隱藏已檢視的檔案" } }, - "es": { + "de": { "stringUnit": { "state": "translated", - "value": "Copiar pantalla visible" + "value": "Angesehene Dateien ausblenden" } }, "fr": { "stringUnit": { "state": "translated", - "value": "Copier l'écran visible" + "value": "Masquer les fichiers vus" } }, - "it": { + "ar": { "stringUnit": { "state": "translated", - "value": "Copia schermo visibile" + "value": "إخفاء الملفات التي تمت مشاهدتها" } }, - "ja": { + "es": { "stringUnit": { "state": "translated", - "value": "表示中の画面をコピー" + "value": "Ocultar archivos vistos" } }, "ko": { "stringUnit": { "state": "translated", - "value": "보이는 화면 복사" + "value": "확인한 파일 숨기기" } - }, - "nb": { + } + } + }, + "diffViewer.showViewedFiles": { + "extractionState": "manual", + "localizations": { + "en": { "stringUnit": { "state": "translated", - "value": "Kopier synlig skjerm" + "value": "Show viewed files" } }, - "pl": { + "ja": { "stringUnit": { "state": "translated", - "value": "Kopiuj widoczny ekran" + "value": "確認済みのファイルを表示" } }, - "pt-BR": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Copiar Tela Visível" + "value": "显示已查看的文件" } }, - "ru": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "Копировать видимый экран" + "value": "顯示已檢視的檔案" } }, - "th": { + "de": { "stringUnit": { "state": "translated", - "value": "คัดลอกหน้าจอที่มองเห็น" + "value": "Angesehene Dateien anzeigen" } }, - "tr": { + "fr": { "stringUnit": { "state": "translated", - "value": "Görünür Ekranı Kopyala" + "value": "Afficher les fichiers vus" } }, - "uk": { + "ar": { "stringUnit": { "state": "translated", - "value": "Копіювати видимий екран" + "value": "إظهار الملفات التي تمت مشاهدتها" } }, - "zh-Hans": { + "es": { "stringUnit": { "state": "translated", - "value": "复制可见屏幕" + "value": "Mostrar archivos vistos" } }, - "zh-Hant": { + "ko": { "stringUnit": { "state": "translated", - "value": "複製可見畫面" + "value": "확인한 파일 표시" } } } }, - "shortcut.diffViewerToggleViewed.label": { + "diffViewer.noFilesMatchFilter": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Diff Viewer: Toggle Viewed" + "value": "No files match the filter." } }, "ja": { "stringUnit": { "state": "translated", - "value": "差分ビューア: 確認済みを切り替え" + "value": "絞り込み条件に一致するファイルはありません。" } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": "差异查看器:切换已查看" + "value": "没有符合筛选条件的文件。" } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "差異檢視器:切換已檢視" + "value": "沒有符合篩選條件的檔案。" } }, "de": { "stringUnit": { "state": "translated", - "value": "Diff-Viewer: Angesehen umschalten" + "value": "Keine Dateien entsprechen dem Filter." } }, "fr": { "stringUnit": { "state": "translated", - "value": "Visionneuse de diff : Basculer « vu »" + "value": "Aucun fichier ne correspond au filtre." } }, "ar": { "stringUnit": { "state": "translated", - "value": "عارض الفروق: تبديل حالة المشاهدة" + "value": "لا توجد ملفات مطابقة للتصفية." } }, "es": { "stringUnit": { "state": "translated", - "value": "Visor de diff: Alternar visto" + "value": "Ningún archivo coincide con el filtro." } }, "ko": { "stringUnit": { "state": "translated", - "value": "차이 뷰어: 확인함 전환" + "value": "필터와 일치하는 파일이 없습니다." } } } }, - "diffViewer.viewed": { + "diffViewer.generatedFile": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Viewed" + "value": "Generated file" } }, "ja": { "stringUnit": { "state": "translated", - "value": "確認済み" + "value": "自動生成ファイル" } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": "已查看" + "value": "生成的文件" } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "已檢視" + "value": "產生的檔案" } }, "de": { "stringUnit": { "state": "translated", - "value": "Angesehen" + "value": "Generierte Datei" } }, "fr": { "stringUnit": { "state": "translated", - "value": "Vu" + "value": "Fichier généré" } }, "ar": { "stringUnit": { "state": "translated", - "value": "تمت المشاهدة" + "value": "ملف مُولَّد" } }, "es": { "stringUnit": { "state": "translated", - "value": "Visto" + "value": "Archivo generado" } }, "ko": { "stringUnit": { "state": "translated", - "value": "확인함" + "value": "생성된 파일" } } } }, - "diffViewer.markViewed": { + "diffViewer.largeDiff": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Mark as viewed" + "value": "Large diff" } }, "ja": { "stringUnit": { "state": "translated", - "value": "確認済みにする" + "value": "大きな差分" } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": "标记为已查看" + "value": "大型差异" } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "標記為已檢視" + "value": "大型差異" } }, "de": { "stringUnit": { "state": "translated", - "value": "Als angesehen markieren" + "value": "Großer Diff" } }, "fr": { "stringUnit": { "state": "translated", - "value": "Marquer comme vu" + "value": "Diff volumineux" } }, "ar": { "stringUnit": { "state": "translated", - "value": "وضع علامة تمت المشاهدة" + "value": "فرق كبير" } }, "es": { "stringUnit": { "state": "translated", - "value": "Marcar como visto" + "value": "Diff grande" } }, "ko": { "stringUnit": { "state": "translated", - "value": "확인함으로 표시" + "value": "큰 변경 사항" } } } }, - "diffViewer.markNotViewed": { + "diffViewer.loadDiff": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Mark as not viewed" + "value": "Load diff" } }, "ja": { "stringUnit": { "state": "translated", - "value": "未確認にする" + "value": "差分を読み込む" } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": "标记为未查看" + "value": "加载差异" } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "標記為未檢視" + "value": "載入差異" } }, "de": { "stringUnit": { "state": "translated", - "value": "Als nicht angesehen markieren" + "value": "Diff laden" } }, "fr": { "stringUnit": { "state": "translated", - "value": "Marquer comme non vu" + "value": "Charger le diff" } }, "ar": { "stringUnit": { "state": "translated", - "value": "إزالة علامة تمت المشاهدة" + "value": "تحميل الفرق" } }, "es": { "stringUnit": { "state": "translated", - "value": "Marcar como no visto" + "value": "Cargar diff" } }, "ko": { "stringUnit": { "state": "translated", - "value": "확인 안 함으로 표시" + "value": "변경 사항 불러오기" } } } }, - "diffViewer.changedSinceViewed": { + "diffViewer.clearFileFilter": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Changed since viewed" + "value": "Clear filter" } }, "ja": { "stringUnit": { "state": "translated", - "value": "確認後に変更あり" + "value": "絞り込みを解除" } }, "zh-Hans": { "stringUnit": { "state": "translated", - "value": "查看后已更改" + "value": "清除筛选" } }, "zh-Hant": { "stringUnit": { "state": "translated", - "value": "檢視後已變更" + "value": "清除篩選" } }, "de": { "stringUnit": { "state": "translated", - "value": "Seit dem Ansehen geändert" + "value": "Filter zurücksetzen" } }, "fr": { "stringUnit": { "state": "translated", - "value": "Modifié depuis la consultation" + "value": "Effacer le filtre" } }, "ar": { "stringUnit": { "state": "translated", - "value": "تغيّر منذ المشاهدة" + "value": "مسح التصفية" } }, "es": { "stringUnit": { "state": "translated", - "value": "Cambiado desde que se vio" + "value": "Borrar filtro" } }, "ko": { "stringUnit": { "state": "translated", - "value": "확인 후 변경됨" + "value": "필터 지우기" } } } }, - "diffViewer.filesViewedProgress": { + "command.copyWorkingDirectory.title": { "extractionState": "manual", "localizations": { - "en": { + "ar": { "stringUnit": { "state": "translated", - "value": "{viewed} of {total} files viewed" + "value": "نسخ دليل العمل" } }, - "ja": { + "bs": { "stringUnit": { "state": "translated", - "value": "{total} 件中 {viewed} 件のファイルを確認済み" + "value": "Kopiraj radni direktorij" } }, - "zh-Hans": { + "da": { "stringUnit": { "state": "translated", - "value": "已查看 {viewed}/{total} 个文件" + "value": "Kopiér arbejdsmappe" } }, - "zh-Hant": { + "de": { "stringUnit": { "state": "translated", - "value": "已檢視 {viewed}/{total} 個檔案" + "value": "Arbeitsverzeichnis kopieren" } }, - "de": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Copy Working Directory" + } + }, + "es": { "stringUnit": { "state": "translated", - "value": "{viewed} von {total} Dateien angesehen" + "value": "Copiar directorio de trabajo" } }, "fr": { "stringUnit": { "state": "translated", - "value": "{viewed} fichiers sur {total} vus" + "value": "Copier le répertoire de travail" } }, - "ar": { + "it": { "stringUnit": { "state": "translated", - "value": "تمت مشاهدة {viewed} من {total} ملفات" + "value": "Copia directory di lavoro" } }, - "es": { + "ja": { "stringUnit": { "state": "translated", - "value": "{viewed} de {total} archivos vistos" + "value": "作業ディレクトリをコピー" } }, "ko": { "stringUnit": { "state": "translated", - "value": "{total}개 중 {viewed}개 파일 확인함" + "value": "작업 디렉터리 복사" } - } - } - }, - "diffViewer.filterFiles": { - "extractionState": "manual", - "localizations": { - "en": { + }, + "nb": { "stringUnit": { "state": "translated", - "value": "Filter files" + "value": "Kopier arbeidsmappe" } }, - "ja": { + "pl": { "stringUnit": { "state": "translated", - "value": "ファイルを絞り込む" + "value": "Kopiuj katalog roboczy" } }, - "zh-Hans": { + "pt-BR": { "stringUnit": { "state": "translated", - "value": "筛选文件" + "value": "Copiar Diretório de Trabalho" } }, - "zh-Hant": { + "ru": { "stringUnit": { "state": "translated", - "value": "篩選檔案" + "value": "Копировать рабочий каталог" } }, - "de": { + "th": { "stringUnit": { "state": "translated", - "value": "Dateien filtern" + "value": "คัดลอกไดเรกทอรีทำงาน" } }, - "fr": { + "tr": { "stringUnit": { "state": "translated", - "value": "Filtrer les fichiers" + "value": "Çalışma Dizinini Kopyala" } }, - "ar": { + "uk": { "stringUnit": { "state": "translated", - "value": "تصفية الملفات" + "value": "Копіювати робочий каталог" } }, - "es": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Filtrar archivos" + "value": "复制工作目录" } }, - "ko": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "파일 필터" + "value": "複製工作目錄" } } } }, - "diffViewer.filterAddedFiles": { + "command.copyProjectRoot.title": { "extractionState": "manual", "localizations": { - "en": { + "ar": { "stringUnit": { "state": "translated", - "value": "Added" + "value": "نسخ جذر المشروع" } }, - "ja": { + "bs": { "stringUnit": { "state": "translated", - "value": "追加" + "value": "Kopiraj korijen projekta" } }, - "zh-Hans": { + "da": { "stringUnit": { "state": "translated", - "value": "新增" + "value": "Kopiér projektrod" } }, - "zh-Hant": { + "de": { "stringUnit": { "state": "translated", - "value": "新增" + "value": "Projektstamm kopieren" } }, - "de": { + "en": { "stringUnit": { "state": "translated", - "value": "Hinzugefügt" + "value": "Copy Project Root" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Copiar raíz del proyecto" } }, "fr": { "stringUnit": { "state": "translated", - "value": "Ajoutés" + "value": "Copier la racine du projet" } }, - "ar": { + "it": { "stringUnit": { "state": "translated", - "value": "مضافة" + "value": "Copia radice del progetto" } }, - "es": { + "ja": { "stringUnit": { "state": "translated", - "value": "Añadidos" + "value": "プロジェクトのルートをコピー" } }, "ko": { "stringUnit": { "state": "translated", - "value": "추가됨" + "value": "프로젝트 루트 복사" } - } - } - }, - "diffViewer.filterModifiedFiles": { - "extractionState": "manual", - "localizations": { - "en": { + }, + "nb": { "stringUnit": { "state": "translated", - "value": "Modified" + "value": "Kopier prosjektrot" } }, - "ja": { + "pl": { "stringUnit": { "state": "translated", - "value": "変更" + "value": "Kopiuj katalog główny projektu" } }, - "zh-Hans": { + "pt-BR": { "stringUnit": { "state": "translated", - "value": "已修改" + "value": "Copiar Raiz do Projeto" } }, - "zh-Hant": { + "ru": { "stringUnit": { "state": "translated", - "value": "已修改" + "value": "Копировать корень проекта" } }, - "de": { + "th": { "stringUnit": { "state": "translated", - "value": "Geändert" + "value": "คัดลอกรากโปรเจกต์" } }, - "fr": { + "tr": { "stringUnit": { "state": "translated", - "value": "Modifiés" + "value": "Proje Kökünü Kopyala" } }, - "ar": { + "uk": { "stringUnit": { "state": "translated", - "value": "معدّلة" + "value": "Копіювати корінь проєкту" } }, - "es": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Modificados" + "value": "复制项目根目录" } }, - "ko": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "수정됨" + "value": "複製專案根目錄" } } } }, - "diffViewer.filterDeletedFiles": { + "command.copyScreen.title": { "extractionState": "manual", "localizations": { - "en": { + "ar": { "stringUnit": { "state": "translated", - "value": "Deleted" + "value": "نسخ الشاشة المرئية" } }, - "ja": { + "bs": { "stringUnit": { "state": "translated", - "value": "削除" + "value": "Kopiraj vidljivi ekran" } }, - "zh-Hans": { + "da": { "stringUnit": { "state": "translated", - "value": "已删除" + "value": "Kopiér synlig skærm" } }, - "zh-Hant": { + "de": { "stringUnit": { "state": "translated", - "value": "已刪除" + "value": "Sichtbaren Bildschirm kopieren" } }, - "de": { + "en": { "stringUnit": { "state": "translated", - "value": "Gelöscht" + "value": "Copy Visible Screen" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Copiar pantalla visible" } }, "fr": { "stringUnit": { "state": "translated", - "value": "Supprimés" + "value": "Copier l'écran visible" } }, - "ar": { + "it": { "stringUnit": { "state": "translated", - "value": "محذوفة" + "value": "Copia schermo visibile" } }, - "es": { + "ja": { "stringUnit": { "state": "translated", - "value": "Eliminados" + "value": "表示中の画面をコピー" } }, "ko": { "stringUnit": { "state": "translated", - "value": "삭제됨" + "value": "보이는 화면 복사" } - } - } - }, - "diffViewer.filterRenamedFiles": { - "extractionState": "manual", - "localizations": { - "en": { + }, + "nb": { "stringUnit": { "state": "translated", - "value": "Renamed" + "value": "Kopier synlig skjerm" } }, - "ja": { + "pl": { "stringUnit": { "state": "translated", - "value": "名前変更" + "value": "Kopiuj widoczny ekran" } }, - "zh-Hans": { + "pt-BR": { "stringUnit": { "state": "translated", - "value": "已重命名" + "value": "Copiar Tela Visível" } }, - "zh-Hant": { + "ru": { "stringUnit": { "state": "translated", - "value": "已重新命名" + "value": "Копировать видимый экран" } }, - "de": { + "th": { "stringUnit": { "state": "translated", - "value": "Umbenannt" + "value": "คัดลอกหน้าจอที่มองเห็น" } }, - "fr": { + "tr": { "stringUnit": { "state": "translated", - "value": "Renommés" + "value": "Görünür Ekranı Kopyala" } }, - "ar": { + "uk": { "stringUnit": { "state": "translated", - "value": "معاد تسميتها" + "value": "Копіювати видимий екран" } }, - "es": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Renombrados" + "value": "复制可见屏幕" } }, - "ko": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "이름 변경됨" + "value": "複製可見畫面" } } } }, - "diffViewer.hideViewedFiles": { + "socket.sidebar.closeSurface.confirmationRequired": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Hide viewed files" + "value": "Surface has a running process; retry with --force" } }, - "ja": { + "ar": { "stringUnit": { "state": "translated", - "value": "確認済みのファイルを隠す" + "value": "تحتوي السطح على عملية قيد التشغيل؛ أعد المحاولة باستخدام --force" } }, - "zh-Hans": { + "de": { "stringUnit": { "state": "translated", - "value": "隐藏已查看的文件" + "value": "Die Oberfläche hat einen laufenden Prozess; erneut mit --force versuchen" } }, - "zh-Hant": { + "es": { "stringUnit": { "state": "translated", - "value": "隱藏已檢視的檔案" + "value": "La superficie tiene un proceso en ejecución; vuelve a intentarlo con --force" } }, - "de": { + "fr": { "stringUnit": { "state": "translated", - "value": "Angesehene Dateien ausblenden" + "value": "La surface a un processus en cours d’exécution ; réessayez avec --force" } }, - "fr": { + "ja": { "stringUnit": { "state": "translated", - "value": "Masquer les fichiers vus" + "value": "サーフェスでプロセスが実行中です。--force を指定して再試行してください" } }, - "ar": { + "ko": { "stringUnit": { "state": "translated", - "value": "إخفاء الملفات التي تمت مشاهدتها" + "value": "표면에서 실행 중인 프로세스가 있습니다. --force로 다시 시도하세요" } }, - "es": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Ocultar archivos vistos" + "value": "此表面有正在运行的进程;请使用 --force 重试" } }, - "ko": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "확인한 파일 숨기기" + "value": "此表面有正在執行的程序;請使用 --force 重試" } } } }, - "diffViewer.showViewedFiles": { + "socket.sidebar.closeSurface.failed": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Show viewed files" + "value": "Failed to close surface" } }, - "ja": { + "ar": { "stringUnit": { "state": "translated", - "value": "確認済みのファイルを表示" + "value": "تعذر إغلاق السطح" } }, - "zh-Hans": { + "de": { "stringUnit": { "state": "translated", - "value": "显示已查看的文件" + "value": "Die Oberfläche konnte nicht geschlossen werden" } }, - "zh-Hant": { + "es": { "stringUnit": { "state": "translated", - "value": "顯示已檢視的檔案" + "value": "No se pudo cerrar la superficie" } }, - "de": { + "fr": { "stringUnit": { "state": "translated", - "value": "Angesehene Dateien anzeigen" + "value": "Échec de la fermeture de la surface" } }, - "fr": { + "ja": { "stringUnit": { "state": "translated", - "value": "Afficher les fichiers vus" + "value": "サーフェスを閉じられませんでした" } }, - "ar": { + "ko": { "stringUnit": { "state": "translated", - "value": "إظهار الملفات التي تمت مشاهدتها" + "value": "표면을 닫지 못했습니다" } }, - "es": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Mostrar archivos vistos" + "value": "无法关闭此表面" } }, - "ko": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "확인한 파일 표시" + "value": "無法關閉表面" } } } }, - "diffViewer.noFilesMatchFilter": { + "socket.surface.close.confirmationRequired": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "No files match the filter." + "value": "Surface has a running process; retry with force=true" } }, - "ja": { + "ar": { "stringUnit": { "state": "translated", - "value": "絞り込み条件に一致するファイルはありません。" + "value": "تحتوي السطح على عملية قيد التشغيل؛ أعد المحاولة باستخدام force=true" } }, - "zh-Hans": { + "de": { "stringUnit": { "state": "translated", - "value": "没有符合筛选条件的文件。" + "value": "Die Oberfläche hat einen laufenden Prozess; erneut mit force=true versuchen" } }, - "zh-Hant": { + "es": { "stringUnit": { "state": "translated", - "value": "沒有符合篩選條件的檔案。" + "value": "La superficie tiene un proceso en ejecución; vuelve a intentarlo con force=true" } }, - "de": { + "fr": { "stringUnit": { "state": "translated", - "value": "Keine Dateien entsprechen dem Filter." + "value": "La surface a un processus en cours d’exécution ; réessayez avec force=true" } }, - "fr": { + "ja": { "stringUnit": { "state": "translated", - "value": "Aucun fichier ne correspond au filtre." + "value": "サーフェスでプロセスが実行中です。force=true を指定して再試行してください" } }, - "ar": { + "ko": { "stringUnit": { "state": "translated", - "value": "لا توجد ملفات مطابقة للتصفية." + "value": "표면에서 실행 중인 프로세스가 있습니다. force=true로 다시 시도하세요" } }, - "es": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Ningún archivo coincide con el filtro." + "value": "此表面有正在运行的进程;请使用 force=true 重试" } }, - "ko": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "필터와 일치하는 파일이 없습니다." + "value": "此表面有正在執行的程序;請使用 force=true 重試" } } } }, - "diffViewer.generatedFile": { + "socket.surface.close.failed": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Generated file" + "value": "Failed to close surface" } }, - "ja": { + "ar": { "stringUnit": { "state": "translated", - "value": "自動生成ファイル" + "value": "تعذر إغلاق السطح" } }, - "zh-Hans": { + "de": { "stringUnit": { "state": "translated", - "value": "生成的文件" + "value": "Die Oberfläche konnte nicht geschlossen werden" } }, - "zh-Hant": { + "es": { "stringUnit": { "state": "translated", - "value": "產生的檔案" + "value": "No se pudo cerrar la superficie" } }, - "de": { + "fr": { "stringUnit": { "state": "translated", - "value": "Generierte Datei" + "value": "Échec de la fermeture de la surface" } }, - "fr": { + "ja": { "stringUnit": { "state": "translated", - "value": "Fichier généré" + "value": "サーフェスを閉じられませんでした" } }, - "ar": { + "ko": { "stringUnit": { "state": "translated", - "value": "ملف مُولَّد" + "value": "표면을 닫지 못했습니다" } }, - "es": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Archivo generado" + "value": "无法关闭此表面" } }, - "ko": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "생성된 파일" + "value": "無法關閉表面" } } } }, - "diffViewer.largeDiff": { + "socket.tabAction.close.confirmationRequired": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Large diff" + "value": "One or more surfaces have a running process; retry with force=true" } }, - "ja": { + "ar": { "stringUnit": { "state": "translated", - "value": "大きな差分" + "value": "سطح واحد أو أكثر يحتوي على عملية قيد التشغيل؛ أعد المحاولة باستخدام force=true" } }, - "zh-Hans": { + "de": { "stringUnit": { "state": "translated", - "value": "大型差异" + "value": "Mindestens eine Oberfläche hat einen laufenden Prozess; erneut mit force=true versuchen" } }, - "zh-Hant": { + "es": { "stringUnit": { "state": "translated", - "value": "大型差異" + "value": "Una o más superficies tienen un proceso en ejecución; vuelve a intentarlo con force=true" } }, - "de": { + "fr": { "stringUnit": { "state": "translated", - "value": "Großer Diff" + "value": "Une ou plusieurs surfaces ont un processus en cours d’exécution ; réessayez avec force=true" } }, - "fr": { + "ja": { "stringUnit": { "state": "translated", - "value": "Diff volumineux" + "value": "1 つ以上のサーフェスでプロセスが実行中です。force=true を指定して再試行してください" } }, - "ar": { + "ko": { "stringUnit": { "state": "translated", - "value": "فرق كبير" + "value": "하나 이상의 표면에서 프로세스가 실행 중입니다. force=true로 다시 시도하세요" } }, - "es": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Diff grande" + "value": "一个或多个表面有正在运行的进程;请使用 force=true 重试" } }, - "ko": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "큰 변경 사항" + "value": "一個或多個表面有正在執行的程序;請使用 force=true 重試" } } } }, - "diffViewer.loadDiff": { + "cli.socket.error.workspaceCloseConfirmationRequired": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Load diff" + "value": "Workspace has a running process; retry with --force" } }, - "ja": { + "ar": { "stringUnit": { "state": "translated", - "value": "差分を読み込む" + "value": "تحتوي مساحة العمل على عملية قيد التشغيل؛ أعد المحاولة باستخدام --force" } }, - "zh-Hans": { + "de": { "stringUnit": { "state": "translated", - "value": "加载差异" + "value": "Arbeitsbereich mit laufendem Prozess; erneut mit --force versuchen" } }, - "zh-Hant": { + "es": { "stringUnit": { "state": "translated", - "value": "載入差異" + "value": "El espacio de trabajo tiene un proceso en ejecución; vuelve a intentarlo con --force" } }, - "de": { + "fr": { "stringUnit": { "state": "translated", - "value": "Diff laden" + "value": "L’espace de travail a un processus en cours d’exécution ; réessayez avec --force" } }, - "fr": { + "ja": { "stringUnit": { "state": "translated", - "value": "Charger le diff" + "value": "ワークスペースでプロセスが実行中です。--force を指定して再試行してください" } }, - "ar": { + "ko": { "stringUnit": { "state": "translated", - "value": "تحميل الفرق" + "value": "워크스페이스에서 프로세스가 실행 중입니다. --force로 다시 시도하세요" } }, - "es": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Cargar diff" + "value": "此工作区有正在运行的进程;请使用 --force 重试" } }, - "ko": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "변경 사항 불러오기" + "value": "此工作區有正在執行的程序;請使用 --force 重試" } } } }, - "diffViewer.clearFileFilter": { + "cli.socket.error.windowCloseConfirmationRequired": { "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Clear filter" + "value": "One or more workspaces or Dock surfaces have a running process; retry with --force" } }, - "ja": { + "ar": { "stringUnit": { "state": "translated", - "value": "絞り込みを解除" + "value": "تحتوي مساحة عمل واحدة أو أكثر أو أسطح Dock على عملية قيد التشغيل؛ أعد المحاولة باستخدام --force" } }, - "zh-Hans": { + "de": { "stringUnit": { "state": "translated", - "value": "清除筛选" + "value": "Mindestens ein Workspace oder eine Dock-Oberfläche hat einen laufenden Prozess; erneut mit --force versuchen" } }, - "zh-Hant": { + "es": { "stringUnit": { "state": "translated", - "value": "清除篩選" + "value": "Uno o más espacios de trabajo o superficies del Dock tienen un proceso en ejecución; vuelve a intentarlo con --force" } }, - "de": { + "fr": { "stringUnit": { "state": "translated", - "value": "Filter zurücksetzen" + "value": "Un ou plusieurs espaces de travail ou surfaces du Dock ont un processus en cours d’exécution ; réessayez avec --force" } }, - "fr": { + "ja": { "stringUnit": { "state": "translated", - "value": "Effacer le filtre" + "value": "1 つ以上のワークスペースまたは Dock サーフェスでプロセスが実行中です。--force を指定して再試行してください" } }, - "ar": { + "ko": { "stringUnit": { "state": "translated", - "value": "مسح التصفية" + "value": "하나 이상의 워크스페이스 또는 Dock 표면에서 실행 중인 프로세스가 있습니다. --force로 다시 시도하세요" } }, - "es": { + "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Borrar filtro" + "value": "一个或多个工作区或 Dock 表面有正在运行的进程;请使用 --force 重试" } }, - "ko": { + "zh-Hant": { "stringUnit": { "state": "translated", - "value": "필터 지우기" + "value": "一個或多個工作區或 Dock 表面有正在執行的程序;請使用 --force 重試" } } } @@ -589154,6 +588849,554 @@ } } } + }, + "cli.help.record": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Usage: cmux record [start] [flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\nRecord a cmux window to an mp4 or gif, for a pull request or a bug\nreport. Only cmux's own windows can be recorded, and no Screen\nRecording permission is involved.\n\nFlags for start:\n --format mp4|gif Output format (default: mp4)\n --gif Shorthand for --format gif\n --fps <1-30> Frames per second (default: 12 for mp4, 8 for gif)\n --max-seconds Stop by itself after n seconds, 0.5-120 (default: 15)\n --scale <0.1-1> Scale the output (default: 1 for mp4, 0.5 for gif)\n --max-width <64-4096> Cap the output width, keeping the aspect ratio\n --region Record part of the window, in window points\n --out Write here instead of a temporary directory\n --label Name the file\n --no-captions Do not draw `record note` captions into the clip\n --window Window to record (default: the frontmost one)\n\nOutput: ` `, or the full response with --json.\n\nA recording stops itself at --max-seconds, so a clip is never left\nrunning by an agent that goes away. One recording at a time.\n\nExample:\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "الاستخدام: cmux record [start] [flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\nتسجيل نافذة cmux بصيغة mp4 أو gif، من أجل طلب سحب أو تقرير خطأ.\nلا يمكن تسجيل سوى نوافذ cmux نفسها،\nولا يتطلب ذلك إذن تسجيل الشاشة.\n\nخيارات start:\n --format mp4|gif صيغة الإخراج (الافتراضي: mp4)\n --gif اختصار لـ --format gif\n --fps <1-30> الإطارات في الثانية (الافتراضي: 12 لـ mp4، 8 لـ gif)\n --max-seconds يتوقف من تلقاء نفسه بعد n ثانية، 0.5-120 (الافتراضي: 15)\n --scale <0.1-1> تحجيم الإخراج (الافتراضي: 1 لـ mp4، 0.5 لـ gif)\n --max-width <64-4096> تحديد أقصى عرض للإخراج مع الحفاظ على نسبة الأبعاد\n --region تسجيل جزء من النافذة، بوحدات نقاط النافذة\n --out الكتابة هنا بدلاً من دليل مؤقت\n --label تسمية الملف\n --no-captions عدم رسم تعليقات `record note` داخل المقطع\n --window النافذة المراد تسجيلها (الافتراضي: النافذة الأمامية)\n\nالإخراج: ` `، أو الاستجابة الكاملة مع --json.\n\nيتوقف التسجيل من تلقاء نفسه عند --max-seconds، حتى لا يترك وكيل غادر\nمقطعًا قيد التسجيل. تسجيل واحد في كل مرة.\n\nمثال:\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Verwendung: cmux record [start] [Flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\nEin cmux-Fenster als mp4 oder gif aufzeichnen, für einen Pull Request\noder einen Fehlerbericht. Nur cmux-eigene Fenster können aufgezeichnet\nwerden, und es ist keine Bildschirmaufnahme-Berechtigung beteiligt.\n\nFlags für start:\n --format mp4|gif Ausgabeformat (Standard: mp4)\n --gif Kurzform für --format gif\n --fps <1-30> Bilder pro Sekunde (Standard: 12 für mp4, 8 für gif)\n --max-seconds Nach n Sekunden selbst beenden, 0.5-120 (Standard: 15)\n --scale <0.1-1> Ausgabe skalieren (Standard: 1 für mp4, 0.5 für gif)\n --max-width <64-4096> Ausgabebreite begrenzen, Seitenverhältnis bleibt\n --region Teil des Fensters aufzeichnen, in Fensterpunkten\n --out Hierhin schreiben statt in ein temporäres Verzeichnis\n --label Datei benennen\n --no-captions Keine `record note`-Untertitel in den Clip zeichnen\n --window Fenster zum Aufzeichnen (Standard: das vorderste)\n\nAusgabe: ` `, oder mit --json die vollständige Antwort.\n\nEine Aufzeichnung beendet sich bei --max-seconds selbst, damit ein Agent, der\nverschwindet, keinen laufenden Clip hinterlässt. Eine Aufzeichnung zur Zeit.\n\nBeispiel:\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Uso: cmux record [start] [flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\nGraba una ventana de cmux en mp4 o gif, para un pull request o un informe\nde error. Solo se pueden grabar las ventanas propias de cmux, y no\ninterviene ningún permiso de grabación de pantalla.\n\nFlags para start:\n --format mp4|gif Formato de salida (predeterminado: mp4)\n --gif Atajo para --format gif\n --fps <1-30> Fotogramas por segundo (predeterminado: 12 para mp4, 8 para gif)\n --max-seconds Se detiene solo tras n segundos, 0.5-120 (predeterminado: 15)\n --scale <0.1-1> Escala la salida (predeterminado: 1 para mp4, 0.5 para gif)\n --max-width <64-4096> Limita el ancho de salida manteniendo la proporción\n --region Graba parte de la ventana, en puntos de ventana\n --out Escribe aquí en lugar de en un directorio temporal\n --label Da nombre al archivo\n --no-captions No dibujar los subtítulos de `record note` en el clip\n --window Ventana que se graba (predeterminado: la del frente)\n\nSalida: ` `, o la respuesta completa con --json.\n\nUna grabación se detiene sola en --max-seconds, para que un agente que\ndesaparece nunca deje un clip en marcha. Una grabación a la vez.\n\nEjemplo:\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Utilisation : cmux record [start] [flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\nEnregistrer une fenêtre cmux en mp4 ou gif, pour une pull request ou un\nrapport de bug. Seules les fenêtres de cmux peuvent être enregistrées, et\naucune autorisation d'enregistrement de l'écran n'intervient.\n\nFlags pour start :\n --format mp4|gif Format de sortie (par défaut : mp4)\n --gif Raccourci pour --format gif\n --fps <1-30> Images par seconde (par défaut : 12 pour mp4, 8 pour gif)\n --max-seconds S'arrête seul après n secondes, 0.5-120 (par défaut : 15)\n --scale <0.1-1> Mettre la sortie à l'échelle (par défaut : 1 pour mp4, 0.5 pour gif)\n --max-width <64-4096> Limiter la largeur de sortie en gardant les proportions\n --region N'enregistrer qu'une partie de la fenêtre, en points fenêtre\n --out Écrire ici au lieu d'un répertoire temporaire\n --label Nommer le fichier\n --no-captions Ne pas dessiner les légendes `record note` dans le clip\n --window Fenêtre à enregistrer (par défaut : celle au premier plan)\n\nSortie : ` `, ou la réponse complète avec --json.\n\nUn enregistrement s'arrête de lui-même à --max-seconds, afin qu'un agent qui\ndisparaît ne laisse jamais un clip en cours. Un seul enregistrement à la fois.\n\nExemple :\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "使用方法: cmux record [start] [flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\nプルリクエストやバグ報告のために、cmux のウィンドウを mp4 または gif\nで録画します。録画できるのは cmux 自身のウィンドウだけで、画面収録の\n権限は必要ありません。\n\nstart のフラグ:\n --format mp4|gif 出力形式(既定: mp4)\n --gif --format gif の短縮形\n --fps <1-30> 1 秒あたりのフレーム数(既定: mp4 は 12、gif は 8)\n --max-seconds n 秒後に自動停止、0.5-120(既定: 15)\n --scale <0.1-1> 出力を拡大縮小(既定: mp4 は 1、gif は 0.5)\n --max-width <64-4096> 縦横比を保ったまま出力の幅を制限\n --region ウィンドウの一部だけを録画(ウィンドウポイント単位)\n --out 一時ディレクトリではなくこのパスに書き出す\n --label ファイルに名前を付ける\n --no-captions `record note` のキャプションをクリップに描画しない\n --window 録画するウィンドウ(既定: 最前面のウィンドウ)\n\n出力: ` `、または --json で完全なレスポンス。\n\n録画は --max-seconds で自動停止するので、いなくなったエージェントが\n録画を実行したままにすることはありません。録画は同時に 1 つだけです。\n\n例:\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "사용법: cmux record [start] [flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\n풀 리퀘스트나 버그 리포트에 쓰려고 cmux 창을 mp4 또는 gif로\n녹화합니다. cmux 자신의 창만 녹화할 수 있고, 화면 기록 권한은\n필요하지 않습니다.\n\nstart 플래그:\n --format mp4|gif 출력 형식 (기본값: mp4)\n --gif --format gif의 단축형\n --fps <1-30> 초당 프레임 수 (기본값: mp4는 12, gif는 8)\n --max-seconds n초 후 스스로 정지, 0.5-120 (기본값: 15)\n --scale <0.1-1> 출력 크기 조정 (기본값: mp4는 1, gif는 0.5)\n --max-width <64-4096> 가로 세로 비율을 유지하며 출력 너비 제한\n --region 창의 일부만 녹화, 창 포인트 단위\n --out 임시 디렉터리 대신 이 경로에 기록\n --label 파일 이름 지정\n --no-captions `record note` 캡션을 클립에 그리지 않음\n --window 녹화할 창 (기본값: 맨 앞 창)\n\n출력: ` `, 또는 --json으로 전체 응답.\n\n녹화는 --max-seconds에서 스스로 멈추므로 사라진 에이전트가 녹화를 계속\n남겨 두는 일은 없습니다. 한 번에 하나의 녹화만 가능합니다.\n\n예:\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "使用方法: cmux record [start] [flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\n将 cmux 窗口录制为 mp4 或 gif,用于 pull request 或错误报告。\n只能录制 cmux 自己的窗口,\n而且不需要任何屏幕录制权限。\n\nstart 的标志:\n --format mp4|gif 输出格式(默认: mp4)\n --gif --format gif 的简写\n --fps <1-30> 每秒帧数(默认: mp4 为 12,gif 为 8)\n --max-seconds n 秒后自行停止,0.5-120(默认: 15)\n --scale <0.1-1> 缩放输出(默认: mp4 为 1,gif 为 0.5)\n --max-width <64-4096> 限制输出宽度并保持宽高比\n --region 只录制窗口的一部分,以窗口点为单位\n --out 写入此处而非临时目录\n --label 为文件命名\n --no-captions 不要把 `record note` 字幕画进视频\n --window 要录制的窗口(默认: 最前面的窗口)\n\n输出: ` `,或用 --json 获取完整响应。\n\n录制会在 --max-seconds 时自行停止,因此离开的代理不会留下仍在录制的\n视频。同一时间只能有一份录制。\n\n示例:\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "使用方法: cmux record [start] [flags]\n cmux record stop|status [--id ]\n cmux record note [--id ] \n cmux record list\n\n將 cmux 視窗錄製成 mp4 或 gif,用於 pull request 或錯誤報告。\n只能錄製 cmux 自己的視窗,\n而且不需要任何螢幕錄製權限。\n\nstart 的旗標:\n --format mp4|gif 輸出格式(預設: mp4)\n --gif --format gif 的簡寫\n --fps <1-30> 每秒影格數(預設: mp4 為 12,gif 為 8)\n --max-seconds n 秒後自行停止,0.5-120(預設: 15)\n --scale <0.1-1> 縮放輸出(預設: mp4 為 1,gif 為 0.5)\n --max-width <64-4096> 限制輸出寬度並維持長寬比\n --region 只錄製視窗的一部分,以視窗點為單位\n --out 寫入此處而非暫存目錄\n --label 為檔案命名\n --no-captions 不要將 `record note` 字幕畫進影片\n --window 要錄製的視窗(預設: 最前面的視窗)\n\n輸出: ` `,或以 --json 取得完整回應。\n\n錄製會在 --max-seconds 時自行停止,因此離開的代理程式不會留下仍在\n錄製的影片。同一時間只能有一份錄製。\n\n範例:\n cmux record start --gif --max-seconds 8 --label sidebar-drag\n cmux record note \"dragging the workspace\"\n cmux record stop" + } + } + } + }, + "cli.record.error.formatConflict": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "record start: --gif conflicts with --format" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "record start: لا يمكن دمج --gif مع --format" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "record start: --gif kann nicht mit --format kombiniert werden" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "record start: --gif no se puede combinar con --format" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "record start: --gif ne peut pas être combiné avec --format" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "record start: --gif は --format と併用できません" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "record start: --gif은 --format과 함께 사용할 수 없습니다" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "record start: --gif 不能与 --format 同用" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "record start: --gif 無法與 --format 同時使用" + } + } + } + }, + "cli.record.error.noteText": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "record note: text is required" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "record note: النص مطلوب" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "record note: Text ist erforderlich" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "record note: se requiere el texto" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "record note : le texte est requis" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "record note: テキストが必要です" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "record note: 텍스트가 필요합니다" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "record note: 必须提供文本" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "record note: 必須提供文字" + } + } + } + }, + "cli.record.error.unexpectedArguments": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "record %@: unexpected arguments: %@" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "record %@: وسائط غير متوقعة: %@" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "record %@: unerwartete Argumente: %@" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "record %@: argumentos inesperados: %@" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "record %@ : arguments inattendus : %@" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "record %@: 予期しない引数: %@" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "record %@: 예기치 않은 인수: %@" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "record %@: 多余的参数: %@" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "record %@: 未預期的引數: %@" + } + } + } + }, + "cli.record.error.unknownSubcommand": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "record: unknown subcommand '%@' (start, stop, status, note, list)" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "record: أمر فرعي غير معروف '%@' (start، stop، status، note، list)" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "record: unbekannter Unterbefehl „%@“ (start, stop, status, note, list)" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "record: subcomando desconocido '%@' (start, stop, status, note, list)" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "record : sous-commande inconnue '%@' (start, stop, status, note, list)" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "record: 不明なサブコマンド '%@' です(start、stop、status、note、list)" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "record: 알 수 없는 하위 명령 '%@' (start, stop, status, note, list)" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "record: 未知的子命令 '%@'(start、stop、status、note、list)" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "record: 未知的子命令 '%@'(start、stop、status、note、list)" + } + } + } + }, + "cli.usage.record": { + "extractionState": "manual", + "localizations": { + "ar": { + "stringUnit": { + "state": "translated", + "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" + } + }, + "en": { + "stringUnit": { + "state": "translated", + "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "record [start] [--format mp4|gif] [--gif] [--fps ] [--max-seconds ] [--scale ] [--max-width ] [--region ] [--out ] [--label ] [--no-captions] [--window ] | record stop|status [--id ] | record note [--id ] | record list" + } + } + } + }, + "cli.help.shot": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Usage: cmux shot [flags]\n\nScreenshot a cmux window, or a region of one, to a png or a jpeg. Only\ncmux's own windows can be captured, and no Screen Recording permission\nis involved, so this works on a release build and inside CI.\n\nFlags:\n --format png|jpg Output format (default: png)\n --jpg Shorthand for --format jpg\n --scale <0.1-1> Scale the output (default: 1)\n --max-width <64-8192> Cap the output width, keeping the aspect ratio\n --quality <0.1-1> JPEG quality (default: 0.8, ignored for png)\n --region Capture part of the window, in window points\n --out Write here instead of a temporary directory\n --label Name the file\n --caption Draw a caption into the image\n --window Window to capture (default: the frontmost one)\n\nOutput: `x `, or the full response with --json.\n\nA region is the same rectangle `cmux record --region` films, so a\ndetail spotted in a clip can be shot with the same four numbers.\n\nExample:\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "الاستخدام: cmux shot [flags]\n\nتصوير نافذة cmux أو جزء منها بصيغة png أو jpeg.\nلا يمكن تصوير سوى نوافذ cmux نفسها، ولا يتطلب ذلك إذن تسجيل الشاشة،\nلذلك يعمل هذا في بناء الإصدار وداخل CI.\n\nالخيارات:\n --format png|jpg صيغة الإخراج (الافتراضي: png)\n --jpg اختصار لـ --format jpg\n --scale <0.1-1> تحجيم الإخراج (الافتراضي: 1)\n --max-width <64-8192> تحديد أقصى عرض للإخراج مع الحفاظ على نسبة الأبعاد\n --quality <0.1-1> جودة JPEG (الافتراضي: 0.8، وتُهمل مع png)\n --region تصوير جزء من النافذة، بوحدات نقاط النافذة\n --out الكتابة هنا بدلاً من دليل مؤقت\n --label تسمية الملف\n --caption رسم تعليق داخل الصورة\n --window النافذة المراد تصويرها (الافتراضي: النافذة الأمامية)\n\nالإخراج: `x `، أو الاستجابة الكاملة مع --json.\n\nالمنطقة هي نفس المستطيل الذي يصوّره `cmux record --region`، لذا يمكن تصوير\nتفصيل لوحظ في مقطع بالأرقام الأربعة نفسها.\n\nمثال:\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Verwendung: cmux shot [Flags]\n\nEin cmux-Fenster oder einen Teil davon als png oder jpeg aufnehmen. Nur\ncmux-eigene Fenster sind aufnehmbar, und es ist keine Berechtigung für\nBildschirmaufnahmen nötig, das geht also im Release-Build und in der CI.\n\nFlags:\n --format png|jpg Ausgabeformat (Standard: png)\n --jpg Kurzform für --format jpg\n --scale <0.1-1> Ausgabe skalieren (Standard: 1)\n --max-width <64-8192> Ausgabebreite begrenzen, Seitenverhältnis bleibt\n --quality <0.1-1> JPEG-Qualität (Standard: 0.8, für png ignoriert)\n --region Teil des Fensters aufnehmen, in Fensterpunkten\n --out Hierhin schreiben statt in ein temporäres Verzeichnis\n --label Datei benennen\n --caption Eine Bildunterschrift ins Bild zeichnen\n --window Fenster zum Aufnehmen (Standard: das vorderste)\n\nAusgabe: `x `, oder mit --json die vollständige Antwort.\n\nEine Region ist dasselbe Rechteck, das `cmux record --region` filmt: ein im\nClip entdecktes Detail lässt sich mit denselben vier Zahlen aufnehmen.\n\nBeispiel:\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Uso: cmux shot [flags]\n\nCaptura una ventana de cmux, o una región de ella, en png o jpeg. Solo se\npueden capturar las ventanas propias de cmux, y no interviene ningún permiso\nde grabación de pantalla, así que funciona en una release y dentro de CI.\n\nFlags:\n --format png|jpg Formato de salida (predeterminado: png)\n --jpg Atajo para --format jpg\n --scale <0.1-1> Escala la salida (predeterminado: 1)\n --max-width <64-8192> Limita el ancho de salida manteniendo la proporción\n --quality <0.1-1> Calidad JPEG (predeterminado: 0.8, se ignora en png)\n --region Captura parte de la ventana, en puntos de ventana\n --out Escribe aquí en lugar de en un directorio temporal\n --label Da nombre al archivo\n --caption Dibuja un rótulo dentro de la imagen\n --window Ventana que se captura (predeterminado: la del frente)\n\nSalida: `x `, o la respuesta completa con --json.\n\nUna región es el mismo rectángulo que filma `cmux record --region`, así que un\ndetalle visto en un clip se captura con los mismos cuatro números.\n\nEjemplo:\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Utilisation : cmux shot [flags]\n\nCapture une fenêtre cmux, ou une partie de celle-ci, en png ou en jpeg.\nSeules les fenêtres de cmux peuvent être capturées, et aucune autorisation\nd'enregistrement d'écran n'intervient : cela marche en release et dans la CI.\n\nFlags :\n --format png|jpg Format de sortie (par défaut : png)\n --jpg Raccourci pour --format jpg\n --scale <0.1-1> Met la sortie à l'échelle (par défaut : 1)\n --max-width <64-8192> Limite la largeur de sortie en gardant les proportions\n --quality <0.1-1> Qualité JPEG (par défaut : 0.8, ignorée pour png)\n --region Capture une partie de la fenêtre, en points de fenêtre\n --out Écrit ici au lieu d'un répertoire temporaire\n --label Nomme le fichier\n --caption Dessine une légende dans l'image\n --window Fenêtre à capturer (par défaut : celle au premier plan)\n\nSortie : `x `, ou la réponse complète avec --json.\n\nUne région est le même rectangle que filme `cmux record --region` : un détail\nrepéré dans un clip se capture avec les mêmes quatre nombres.\n\nExemple :\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "使用方法: cmux shot [flags]\n\ncmux のウィンドウ、またはその一部の領域を png または jpeg で撮ります。\n撮れるのは cmux 自身のウィンドウだけで、画面収録の権限は必要ないので、\nリリースビルドでも CI の中でも動きます。\n\nフラグ:\n --format png|jpg 出力形式(既定: png)\n --jpg --format jpg の短縮形\n --scale <0.1-1> 出力を拡大縮小(既定: 1)\n --max-width <64-8192> 縦横比を保ったまま出力の幅を制限\n --quality <0.1-1> JPEG の品質(既定: 0.8、png では無視)\n --region ウィンドウの一部だけを撮る(ウィンドウポイント単位)\n --out 一時ディレクトリではなくこのパスに書き出す\n --label ファイルに名前を付ける\n --caption 画像にキャプションを描画する\n --window 撮るウィンドウ(既定: 最前面のウィンドウ)\n\n出力: `x `、または --json で完全なレスポンス。\n\n領域は `cmux record --region` が撮るのと同じ矩形なので、クリップで見つけた\n細部を同じ 4 つの数字で撮れます。\n\n例:\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "사용법: cmux shot [flags]\n\ncmux 창이나 창의 일부 영역을 png 또는 jpeg로 캡처합니다. cmux 자신의\n창만 캡처할 수 있고, 화면 기록 권한이 필요하지 않으므로 릴리스 빌드와\nCI 안에서도 동작합니다.\n\n플래그:\n --format png|jpg 출력 형식 (기본값: png)\n --jpg --format jpg의 단축형\n --scale <0.1-1> 출력 크기 조정 (기본값: 1)\n --max-width <64-8192> 가로 세로 비율을 유지하며 출력 너비 제한\n --quality <0.1-1> JPEG 품질 (기본값: 0.8, png에서는 무시)\n --region 창의 일부만 캡처, 창 포인트 단위\n --out 임시 디렉터리 대신 이 경로에 기록\n --label 파일 이름 지정\n --caption 이미지에 캡션 그리기\n --window 캡처할 창 (기본값: 맨 앞 창)\n\n출력: `x `, 또는 --json으로 전체 응답.\n\n영역은 `cmux record --region`이 촬영하는 사각형과 같으므로, 클립에서 본\n세부를 같은 네 숫자로 캡처할 수 있습니다.\n\n예:\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "使用方法: cmux shot [flags]\n\n将 cmux 窗口或其中一块区域截取为 png 或 jpeg。\n只能截取 cmux 自己的窗口,而且不需要任何屏幕录制权限,\n因此在 release 构建和 CI 中都能用。\n\n标志:\n --format png|jpg 输出格式(默认: png)\n --jpg --format jpg 的简写\n --scale <0.1-1> 缩放输出(默认: 1)\n --max-width <64-8192> 限制输出宽度并保持宽高比\n --quality <0.1-1> JPEG 质量(默认: 0.8,png 会忽略)\n --region 只截取窗口的一部分,以窗口点为单位\n --out 写入此处而非临时目录\n --label 为文件命名\n --caption 在图片上绘制字幕\n --window 要截取的窗口(默认: 最前面的窗口)\n\n输出: `x `,或用 --json 获取完整响应。\n\n区域和 `cmux record --region` 拍摄的矩形相同,因此在视频里看到的细节\n可以用同样的四个数字截取。\n\n示例:\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "使用方法: cmux shot [flags]\n\n將 cmux 視窗或其中一塊區域擷取成 png 或 jpeg。\n只能擷取 cmux 自己的視窗,而且不需要任何螢幕錄製權限,\n因此在 release 版本與 CI 內都能用。\n\n旗標:\n --format png|jpg 輸出格式(預設: png)\n --jpg --format jpg 的簡寫\n --scale <0.1-1> 縮放輸出(預設: 1)\n --max-width <64-8192> 限制輸出寬度並保持長寬比\n --quality <0.1-1> JPEG 品質(預設: 0.8,png 會忽略)\n --region 只擷取視窗的一部分,以視窗點為單位\n --out 寫入此處而非暫存目錄\n --label 為檔案命名\n --caption 在圖片上畫出字幕\n --window 要擷取的視窗(預設: 最前面的視窗)\n\n輸出: `x `,或用 --json 取得完整回應。\n\n區域和 `cmux record --region` 拍攝的矩形相同,所以在影片裡看到的細節\n可以用同樣的四個數字擷取。\n\n範例:\n cmux shot --label settings-sheet\n cmux shot --region 0,0,420,900 --out ~/sidebar.png" + } + } + } + }, + "cli.shot.error.formatConflict": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "shot: --jpg conflicts with --format" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "shot: لا يمكن دمج --jpg مع --format" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "shot: --jpg kann nicht mit --format kombiniert werden" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "shot: --jpg no se puede combinar con --format" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "shot : --jpg ne peut pas être combiné avec --format" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "shot: --jpg は --format と併用できません" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "shot: --jpg은 --format과 함께 사용할 수 없습니다" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "shot: --jpg 不能与 --format 同用" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "shot: --jpg 無法與 --format 同時使用" + } + } + } + }, + "cli.shot.error.unexpectedArguments": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "shot: unexpected arguments: %@" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "shot: وسائط غير متوقعة: %@" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "shot: unerwartete Argumente: %@" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "shot: argumentos inesperados: %@" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "shot : arguments inattendus : %@" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "shot: 予期しない引数: %@" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "shot: 예기치 않은 인수: %@" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "shot: 多余的参数: %@" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "shot: 未預期的引數: %@" + } + } + } + }, + "cli.usage.shot": { + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "shot [--format png|jpg] [--jpg] [--scale ] [--max-width ] [--quality ] [--region ] [--out ] [--label ] [--caption ] [--window ]" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "shot [--format png|jpg] [--jpg] [--scale ] [--max-width ] [--quality ] [--region ] [--out ] [--label ] [--caption ] [--window ]" + } + } + } } }, "version": "1.0" diff --git a/Sources/CmuxSettingsFileStore+SupportedPaths.swift b/Sources/CmuxSettingsFileStore+SupportedPaths.swift index eea2d5bb747d..379aa84e4edf 100644 --- a/Sources/CmuxSettingsFileStore+SupportedPaths.swift +++ b/Sources/CmuxSettingsFileStore+SupportedPaths.swift @@ -89,6 +89,7 @@ extension CmuxSettingsFileStore { "notifications.agentIdleReminder", "sidebar.hideAllDetails", "sidebar.wrapWorkspaceTitles", + "sidebar.twoLineWorkspaceTitles", "sidebar.showWorkspaceDescription", "sidebar.workspaceDescriptionColor", "sidebar.beta.workspaceTodos.controls.enabled", diff --git a/Sources/CmuxSettingsJSONPathSupport.swift b/Sources/CmuxSettingsJSONPathSupport.swift index a99d50977b2a..8b3a124f0cc9 100644 --- a/Sources/CmuxSettingsJSONPathSupport.swift +++ b/Sources/CmuxSettingsJSONPathSupport.swift @@ -352,6 +352,10 @@ enum SidebarSettingsFileMapping { jsonKey: "wrapWorkspaceTitles", defaultsKey: SidebarWorkspaceTitleWrapSettings.key ), + .init( + jsonKey: "twoLineWorkspaceTitles", + defaultsKey: sidebar.twoLineWorkspaceTitles.userDefaultsKey + ), .init( jsonKey: "showWorkspaceDescription", defaultsKey: sidebar.showWorkspaceDescription.userDefaultsKey diff --git a/Sources/ContentView.swift b/Sources/ContentView.swift index 4cc3c6547f77..56dfed821edf 100644 --- a/Sources/ContentView.swift +++ b/Sources/ContentView.swift @@ -16051,7 +16051,6 @@ struct TabItemView: View, Equatable { @State private var renameDraft = "" @State private var renameBaselineHadUserCustomTitle = false - private static let maxWrappedTitleLines = 8 private static let maxDisplayedTitleCharacters = 2048 var workspaceSnapshot: SidebarWorkspaceSnapshotBuilder.Snapshot { snapshot.workspace } @@ -16152,8 +16151,18 @@ struct TabItemView: View, Equatable { ) } + /// Resting rows draw their title at `regular`; the selected row and rows + /// with unread notifications keep `semibold`. Resolved through + /// `SidebarRowTextWeight` so the AppKit row cell agrees. + private var titleTextWeight: SidebarRowTextWeight { + .workspaceTitle( + isSelected: isActive || isMultiSelected, + hasUnread: unreadCount > 0 + ) + } + private var titleFontWeight: Font.Weight { - .semibold + titleTextWeight.swiftUIWeight } private var fontScale: CGFloat { @@ -16363,10 +16372,14 @@ struct TabItemView: View, Equatable { : SidebarMarkdownRenderer(markdown: display).plainText } let detailVisibility = visibleAuxiliaryDetails - // Compact status rows are one line, so title wrapping does not undo it. - let titleLineLimit = settings.wrapsWorkspaceTitles && workspaceSnapshot.compactStatusGlyph == nil - ? Self.maxWrappedTitleLines - : 1 + // Compact status rows are one line, so neither title setting undoes it. + let titleMetrics = workspaceSnapshot.compactStatusGlyph == nil + ? SidebarRowTitleMetrics( + wrapsTitles: settings.wrapsWorkspaceTitles, + usesTwoLines: settings.usesTwoLineWorkspaceTitles + ) + : SidebarRowTitleMetrics(lineLimit: 1) + let titleLineLimit = titleMetrics.lineLimit let displayedTitle = workspaceSnapshot.title.sidebarBoundedDisplayString( maxDisplayedLines: titleLineLimit, maxDisplayedCharacters: Self.maxDisplayedTitleCharacters @@ -16374,7 +16387,7 @@ struct TabItemView: View, Equatable { let scaledUnreadBadgeSize = 16 * fontScale let scaledLoadingSpinnerSize = max(10, 12 * fontScale) let titleFirstLineCenter = GlobalFontMagnification.scaledSize( - scaledFontSize(12.5), + scaledFontSize(SidebarRowTitleMetrics.fontSize), percent: globalFontMagnificationPercent ) * 0.6 let todoControlsEnabled = WorkspaceTodoFeature.isEnabled @@ -16461,7 +16474,9 @@ struct TabItemView: View, Equatable { if isEditing { SidebarInlineRenameField( initialText: renameDraft, - fontSize: GlobalFontMagnification.scaledSize(scaledFontSize(12.5), percent: globalFontMagnificationPercent), textColor: selectedWorkspaceForegroundNSColor(opacity: 1.0), + fontSize: GlobalFontMagnification.scaledSize(scaledFontSize(SidebarRowTitleMetrics.fontSize), percent: globalFontMagnificationPercent), + fontWeight: titleTextWeight.appKitWeight, + textColor: selectedWorkspaceForegroundNSColor(opacity: 1.0), accessibilityLabel: String( localized: "sidebar.workspace.rename.field.accessibilityLabel", defaultValue: "Rename workspace" @@ -16488,18 +16503,30 @@ struct TabItemView: View, Equatable { .layoutPriority(1) } else { Text(displayedTitle) - .font(magnifiedFont(scaledFontSize(12.5), weight: titleFontWeight)) + .font(magnifiedFont(scaledFontSize(SidebarRowTitleMetrics.fontSize), weight: titleFontWeight)) .foregroundColor(activePrimaryTextColor) .opacity(workspaceSnapshot.isMuted ? 0.6 : 1) .lineLimit(titleLineLimit) - .truncationMode(.tail) + .truncationMode(titleMetrics.swiftUITruncationMode) .fixedSize(horizontal: false, vertical: true) .frame(maxWidth: .infinity, alignment: .leading) .alignmentGuide(.sidebarTitleFirstLineCenter) { _ in titleFirstLineCenter } .layoutPriority(1) } - if trailingStatusActive || canCloseWorkspace { + // Matches the AppKit rows: the hover-revealed close button no + // longer holds a column open on rows that are not hovered, so a + // resting title gets that width. The shortcut hint pill is drawn + // over the same trailing edge and replaces the close button + // while it shows, so the title yields to it as well. A title on + // more than one line keeps the reservation at all times, since + // changing its width would change its line count and the row's + // height. + let reservesTrailingSlot = trailingStatusActive + || showCloseButton + || showsWorkspaceShortcutHint + || titleLineLimit != 1 + if reservesTrailingSlot { SidebarWorkspaceTrailingStatusSlot(showsSpinner: spinnerOnTrailing, showsBadge: badgeOnTrailing, unreadCount: unreadCount, side: scaledUnreadBadgeSize, width: scaledCloseButtonWidth, height: scaledCloseButtonHitSize, badgeFont: badgeFont, badgeFillColor: activeUnreadBadgeFillColor, badgeTextColor: activeUnreadBadgeTextColor, spinnerColor: spinnerColor, spinnerTooltip: spinnerTooltip, canCloseWorkspace: canCloseWorkspace, showsCloseButton: showCloseButton, closeButtonTooltip: closeButtonTooltip, closeButtonColor: activeSecondaryColor(0.7), closeButtonFontSize: scaledFontSize(9), closeAction: actions.closeWorkspace) } } diff --git a/Sources/SettingsSearchAliases.swift b/Sources/SettingsSearchAliases.swift index cb3666b4007a..fdaa3076ba03 100644 --- a/Sources/SettingsSearchAliases.swift +++ b/Sources/SettingsSearchAliases.swift @@ -141,6 +141,7 @@ enum SettingsSearchAliasIndex { "sidebarAppearance:font-size": localized("settings.search.alias.setting.sidebarAppearance.font-size", defaultValue: "sidebar-font-size sidebar font size text scale workspace title badge metadata shortcut hint"), "sidebarAppearance:hide-sidebar-details": localized("settings.search.alias.setting.app.hide-sidebar-details", defaultValue: "sidebar.hideAllDetails compact sidebar hide details only title minimal left rail"), "sidebarAppearance:wrap-workspace-titles": localized("settings.search.alias.setting.app.wrap-workspace-titles", defaultValue: "sidebar.wrapWorkspaceTitles workspace title wrap multiline pr pull request"), + "sidebarAppearance:two-line-workspace-titles": localized("settings.search.alias.setting.app.two-line-workspace-titles", defaultValue: "sidebar.twoLineWorkspaceTitles workspace title two lines second line truncate shorten"), "sidebarAppearance:show-workspace-description": localized("settings.search.alias.setting.app.show-workspace-description", defaultValue: "sidebar.showWorkspaceDescription workspace description notes markdown sidebar"), "sidebarAppearance:workspace-description-color": localized("settings.search.alias.setting.app.workspace-description-color", defaultValue: "sidebar.workspaceDescriptionColor workspace description text color notes markdown sidebar"), "betaFeatures:workspace-todo-controls": localized("settings.search.alias.setting.betaFeatures.workspace-todo-controls", defaultValue: "sidebar.beta.workspaceTodos.controls.enabled workspace todo todos task status checklist add item controls beta"), diff --git a/Sources/SettingsSearchIndex.swift b/Sources/SettingsSearchIndex.swift index 2267552bcbe8..197ca424932b 100644 --- a/Sources/SettingsSearchIndex.swift +++ b/Sources/SettingsSearchIndex.swift @@ -129,6 +129,7 @@ enum SettingsSearchIndex { setting(.sidebarAppearance, "font-size", String(localized: "settings.sidebarAppearance.fontSize", defaultValue: "Sidebar Font Size"), "font size text scale workspace title badge metadata shortcut hint sidebar-font-size"), setting(.sidebarAppearance, "hide-sidebar-details", String(localized: "settings.app.hideAllSidebarDetails", defaultValue: "Hide All Sidebar Details"), "workspace sidebar compact"), setting(.sidebarAppearance, "wrap-workspace-titles", String(localized: "settings.app.wrapWorkspaceTitles", defaultValue: "Wrap Workspace Titles in Sidebar"), "workspace title wrap multiline pr pull request"), + setting(.sidebarAppearance, "two-line-workspace-titles", String(localized: "settings.app.twoLineWorkspaceTitles", defaultValue: "Allow Two Lines for Workspace Titles"), "workspace title two lines second line truncate shorten"), setting(.sidebarAppearance, "show-workspace-description", String(localized: "settings.app.showWorkspaceDescription", defaultValue: "Show Workspace Description in Sidebar"), "workspace description notes markdown"), setting(.sidebarAppearance, "workspace-description-color", String(localized: "settings.app.workspaceDescriptionColor", defaultValue: "Workspace Description Color"), "workspace description text color notes markdown"), setting(.sidebarAppearance, "sidebar-branch-layout", String(localized: "settings.app.sidebarBranchLayout", defaultValue: "Sidebar Branch Layout"), "branch directory vertical inline"), @@ -278,6 +279,7 @@ enum SettingsSearchIndex { "canvas.snappingEnabled": settingID(for: .app, idSuffix: "canvas-snapping"), "sidebar.hideAllDetails": settingID(for: .sidebarAppearance, idSuffix: "hide-sidebar-details"), "sidebar.wrapWorkspaceTitles": settingID(for: .sidebarAppearance, idSuffix: "wrap-workspace-titles"), + "sidebar.twoLineWorkspaceTitles": settingID(for: .sidebarAppearance, idSuffix: "two-line-workspace-titles"), "sidebar.showWorkspaceDescription": settingID(for: .sidebarAppearance, idSuffix: "show-workspace-description"), "sidebar.workspaceDescriptionColor": settingID(for: .sidebarAppearance, idSuffix: "workspace-description-color"), "sidebar.beta.workspaceTodos.controls.enabled": settingID(for: .betaFeatures, idSuffix: "workspace-todo-controls"), diff --git a/Sources/Sidebar/AppKitList/Cells/SidebarGroupHeaderRowView.swift b/Sources/Sidebar/AppKitList/Cells/SidebarGroupHeaderRowView.swift index 8e21460afc6b..de7557f72368 100644 --- a/Sources/Sidebar/AppKitList/Cells/SidebarGroupHeaderRowView.swift +++ b/Sources/Sidebar/AppKitList/Cells/SidebarGroupHeaderRowView.swift @@ -1,5 +1,6 @@ import AppKit import CmuxFoundation +import CmuxSidebar import SwiftUI /// Pure-AppKit group header cell for the sidebar workspace table. @@ -201,7 +202,7 @@ final class SidebarGroupHeaderTableCellView: NSTableCellView { nameField.stringValue = model.name nameField.font = .systemFont( ofSize: GlobalFontMagnification.scaledSize(metrics.nameFontSize, percent: percent), - weight: .semibold + weight: SidebarRowTextWeight.workspaceGroupHeaderName.appKitWeight ) nameField.textColor = model.isAnchorActive ? colorResolver.resolvedColor(.labelColor, for: colorScheme) @@ -421,9 +422,11 @@ final class SidebarGroupHeaderTableCellView: NSTableCellView { static func preferredHeight(model: SidebarGroupHeaderRowModel) -> CGFloat { let metrics = SidebarWorkspaceGroupHeaderMetrics(fontScale: model.fontScale) let percent = model.globalFontMagnificationPercent + // Must stay the same font `applyModel` installs on `nameField`, or the + // measured height drifts from the drawn line. let nameFont = NSFont.systemFont( ofSize: GlobalFontMagnification.scaledSize(metrics.nameFontSize, percent: percent), - weight: .semibold + weight: SidebarRowTextWeight.workspaceGroupHeaderName.appKitWeight ) let nameLineHeight = ceil(nameFont.ascender - nameFont.descender + nameFont.leading) let content = max(metrics.chevronFrame, metrics.iconFrame, metrics.plusFrame, nameLineHeight) diff --git a/Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowCellView.swift b/Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowCellView.swift index 07709901e132..81404735ba80 100644 --- a/Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowCellView.swift +++ b/Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowCellView.swift @@ -142,6 +142,37 @@ final class SidebarWorkspaceRowTableCellView: NSTableCellView { needsLayout = true } + /// Title weight for this row, resolved through the weights the SwiftUI + /// rows use, so both renderers agree. + /// + /// Selection and unread count both take part in row-model equality, so a + /// change here re-measures the row instead of reusing a height cached at + /// the other weight. + private static func titleWeight(for model: SidebarWorkspaceRowModel) -> SidebarRowTextWeight { + .workspaceTitle( + isSelected: model.isActive || model.isMultiSelected, + hasUnread: model.unreadCount > 0 + ) + } + + /// Title font resolved from the row's STORED model, even while a painted + /// copy supplies the colors. + /// + /// Row heights are measured from the stored model, and weight changes text + /// metrics: a wrapped title can need one more line at semibold than at + /// regular. Letting the optimistic selection paint flip the weight would + /// therefore draw a row at one weight inside a frame measured at another, + /// and `refreshVisiblePumpHeightOverrides` can record that mis-measured + /// height and keep it past the paint. Selection colors still flip on press; + /// the weight follows the authoritative apply a moment later. + private func titleFont(paintedWith painted: SidebarWorkspaceRowModel) -> NSFont { + let measured = model ?? painted + return .systemFont( + ofSize: measured.scaled(SidebarRowTitleMetrics.fontSize), + weight: Self.titleWeight(for: measured).appKitWeight + ) + } + var currentModelForMeasurement: SidebarWorkspaceRowModel? { model } /// Paints the FULL selected treatment instantly on press by applying a @@ -602,10 +633,16 @@ final class SidebarWorkspaceRowTableCellView: NSTableCellView { reconcileStatusPopover(model: model, showsAnchor: showsStatusGlyph) configureCompactStatusGlyph(model: model, palette: palette) - // Compact status rows are one line, so title wrapping does not undo it. - let titleLineLimit = settings.wrapsWorkspaceTitles && snapshot.compactStatusGlyph == nil ? 8 : 1 + // Compact status rows are one line, so neither title setting undoes it. + let titleMetrics = snapshot.compactStatusGlyph == nil + ? SidebarRowTitleMetrics( + wrapsTitles: settings.wrapsWorkspaceTitles, + usesTwoLines: settings.usesTwoLineWorkspaceTitles + ) + : SidebarRowTitleMetrics(lineLimit: 1) + let titleLineLimit = titleMetrics.lineLimit titleView.maximumNumberOfLines = titleLineLimit - titleView.lineBreakMode = titleLineLimit == 1 ? .byTruncatingTail : .byWordWrapping + titleView.lineBreakMode = titleMetrics.appKitLineBreakMode let boundedTitle = snapshot.title.sidebarBoundedDisplayString( maxDisplayedLines: titleLineLimit, maxDisplayedCharacters: 2048 @@ -619,7 +656,12 @@ final class SidebarWorkspaceRowTableCellView: NSTableCellView { } #endif titleView.stringValue = boundedTitle - titleView.font = .systemFont(ofSize: model.scaled(12.5), weight: .semibold) + let titleFont = titleFont(paintedWith: model) + titleView.font = titleFont + // A rename in progress occupies the title's slot, so it tracks the same + // font: a notification arriving mid-rename would otherwise leave the + // field one weight behind the row it sits in. + renameSession?.field.font = titleFont titleView.textColor = palette.primaryText titleView.alphaValue = snapshot.isMuted ? 0.6 : 1 @@ -1183,7 +1225,9 @@ final class SidebarWorkspaceRowTableCellView: NSTableCellView { self?.removeInlineRenameSession() } ) - session.field.font = .systemFont(ofSize: model.scaled(12.5), weight: .semibold) + // The rename field replaces the title in place, so it draws at the + // title's weight and the text does not shift when editing starts. + session.field.font = titleFont(paintedWith: model) session.field.inlineRenameTextColor = palette(model).selectedForeground(1.0) renameSession = session titleView.isHidden = true @@ -1279,7 +1323,7 @@ final class SidebarWorkspaceRowTableCellView: NSTableCellView { var x = leading let badgeSide = 16 * model.fontScale let spinnerSide = max(10, 12 * model.fontScale) - let firstLineCenter = model.scaled(12.5) * 0.6 + y + let firstLineCenter = model.scaled(SidebarRowTitleMetrics.fontSize) * 0.6 + y func place(_ view: NSView, size: NSSize, centerY: CGFloat) { guard apply else { return } @@ -1335,7 +1379,31 @@ final class SidebarWorkspaceRowTableCellView: NSTableCellView { // Trailing slot let closeHit = max(16, 16 * model.fontScale) let closeWidth = max(16, closeHit) - let trailingSlotActive = !trailingBadge.isHidden || (trailingSpinner?.isHidden == false) || model.canCloseWorkspace + let trailingStatusVisible = !trailingBadge.isHidden || (trailingSpinner?.isHidden == false) + // A row that merely CAN be closed no longer reserves the close button's + // width: the button is hover-revealed, so on every other row that + // reservation was 24pt of blank trailing space paid for by the title. + // + // The reveal insets the title instead of overlaying it, which is safe + // for a single line because a single line's height does not depend on + // its width. + // + // The shortcut hint pill takes the trailing edge too, as an overlay + // rather than a slot occupant, and it replaces the close button while it + // shows. The title has to yield to it for the same reason it yields to + // the button: a held modifier would otherwise paint the pill over the + // end of the title, and a one-line title now truncates in the middle, so + // its end is a part of the name worth reading. + // + // A title on more than one line keeps the slot reserved at all times, + // whatever is or is not in it. Such a title's height depends on its + // width, and neither hover nor a held modifier may restate a row's + // height. + let titleWrapsToMultipleLines = titleView.maximumNumberOfLines != 1 + let trailingSlotActive = trailingStatusVisible + || showsCloseNow + || model.shortcutHintText != nil + || titleWrapsToMultipleLines let titleMaxX = trailingSlotActive ? (trailing - closeWidth - titleRowSpacing) : trailing let titleWidth = max(10, titleMaxX - x) let renameField = renameSession?.field diff --git a/Sources/Sidebar/SidebarInlineRenameField.swift b/Sources/Sidebar/SidebarInlineRenameField.swift index 937255b21d25..fd679e26f41f 100644 --- a/Sources/Sidebar/SidebarInlineRenameField.swift +++ b/Sources/Sidebar/SidebarInlineRenameField.swift @@ -8,6 +8,9 @@ import SwiftUI struct SidebarInlineRenameField: NSViewRepresentable { let initialText: String let fontSize: CGFloat + /// Weight of the title this field replaces, so the text does not change + /// weight when editing starts. + let fontWeight: NSFont.Weight let textColor: NSColor let accessibilityLabel: String let placeholder: String @@ -30,7 +33,7 @@ struct SidebarInlineRenameField: NSViewRepresentable { field.usesSingleLineMode = true field.cell?.usesSingleLineMode = true field.lineBreakMode = .byTruncatingTail - field.font = .systemFont(ofSize: fontSize, weight: .semibold) + field.font = .systemFont(ofSize: fontSize, weight: fontWeight) field.inlineRenameTextColor = textColor field.placeholderString = placeholder field.setAccessibilityLabel(accessibilityLabel) @@ -46,7 +49,7 @@ struct SidebarInlineRenameField: NSViewRepresentable { // Keep driven visual/accessibility state in sync (NSViewRepresentable // convention). initialText/stringValue is intentionally NOT synced here: // doing so would reset the cursor and clobber in-progress typing. - nsView.font = .systemFont(ofSize: fontSize, weight: .semibold) + nsView.font = .systemFont(ofSize: fontSize, weight: fontWeight) nsView.inlineRenameTextColor = textColor nsView.placeholderString = placeholder nsView.setAccessibilityLabel(accessibilityLabel) diff --git a/Sources/SidebarTabItemSettingsSnapshot.swift b/Sources/SidebarTabItemSettingsSnapshot.swift index f62ba12dcf89..9dd3f9ea66ef 100644 --- a/Sources/SidebarTabItemSettingsSnapshot.swift +++ b/Sources/SidebarTabItemSettingsSnapshot.swift @@ -8,6 +8,7 @@ import Foundation struct SidebarTabItemSettingsSnapshot: Equatable { let hidesAllDetails: Bool let wrapsWorkspaceTitles: Bool + let usesTwoLineWorkspaceTitles: Bool /// `sidebar.compactAgentStatus`: agent status entries draw on the title line. let compactsAgentStatus: Bool /// `sidebar.compactStatusIcons`, keeping only known states and non-empty names. @@ -70,6 +71,7 @@ struct SidebarTabItemSettingsSnapshot: Equatable { ) hidesAllDetails = settings.value(for: sidebar.hideAllDetails) wrapsWorkspaceTitles = settings.value(for: sidebar.wrapWorkspaceTitles) + usesTwoLineWorkspaceTitles = settings.value(for: sidebar.twoLineWorkspaceTitles) compactsAgentStatus = settings.value(for: sidebar.compactAgentStatus) compactStatusIcons = SidebarCompactStatusGlyph.validIconOverrides(settings.value(for: sidebar.compactStatusIcons)) let detailVisibility = SidebarWorkspaceDetailVisibility( diff --git a/Sources/SidebarWorkspaceGroupHeaderView.swift b/Sources/SidebarWorkspaceGroupHeaderView.swift index 995898f662d6..b34ec583d942 100644 --- a/Sources/SidebarWorkspaceGroupHeaderView.swift +++ b/Sources/SidebarWorkspaceGroupHeaderView.swift @@ -193,7 +193,10 @@ struct SidebarWorkspaceGroupHeaderView: View, Equatable { .frame(width: metrics.iconFrame, height: metrics.iconFrame) .accessibilityHidden(true) Text(name) - .cmuxFont(size: metrics.nameFontSize, weight: .semibold) + .cmuxFont( + size: metrics.nameFontSize, + weight: SidebarRowTextWeight.workspaceGroupHeaderName.swiftUIWeight + ) .foregroundStyle(isAnchorActive ? Color.primary : Color.primary.opacity(0.9)) .lineLimit(1) .truncationMode(.tail) diff --git a/Sources/WindowChromeMetrics.swift b/Sources/WindowChromeMetrics.swift index 5b5ae2fa9ac2..c1090354df72 100644 --- a/Sources/WindowChromeMetrics.swift +++ b/Sources/WindowChromeMetrics.swift @@ -75,7 +75,12 @@ enum SidebarWorkspaceListMetrics { static let firstRowTopOffset: CGFloat = MinimalModeChromeMetrics.titlebarHeight + 2 static let rowVerticalPadding: CGFloat = 8 static let rowOuterHorizontalPadding: CGFloat = 6 - static let rowContentHorizontalPadding: CGFloat = 10 + /// Padding between a row's selection background and its content. + /// + /// Two points narrower than the shipped 10: with the outer padding this + /// spent 32 of a 240pt sidebar on empty margins, and the title is what the + /// sidebar is for. + static let rowContentHorizontalPadding: CGFloat = 8 /// The top fade ends where the first row rests, so rows fade only while /// scrolled under the titlebar. It used to reach 20 pt into the list, /// which left the first row partly transparent at rest; over a light diff --git a/cmux.xcodeproj/project.pbxproj b/cmux.xcodeproj/project.pbxproj index 8e95c44b8236..11df7ff0383a 100644 --- a/cmux.xcodeproj/project.pbxproj +++ b/cmux.xcodeproj/project.pbxproj @@ -3252,6 +3252,7 @@ B804A0170000000000000017 /* SidebarWorkspaceTableViewportAnchor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B804B0170000000000000017 /* SidebarWorkspaceTableViewportAnchor.swift */; }; 603C12E917E3C4877809CAD9 /* SidebarWorkspaceTaskStatusGlyph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E01DE5B078B38299582BB0 /* SidebarWorkspaceTaskStatusGlyph.swift */; }; A12481500000000000000001 /* SidebarWorkspaceTaskStatusSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = A12481500000000000000002 /* SidebarWorkspaceTaskStatusSnapshot.swift */; }; + 37FD66D9F50E825472874750 /* SidebarWorkspaceTitleRoomTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113AC461B8EC754FBE12E568 /* SidebarWorkspaceTitleRoomTests.swift */; }; ADA26B5F30224634707004CC /* SidebarWorkspaceTodoPopoverHost.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEAD128139F57CB0E5BD39E /* SidebarWorkspaceTodoPopoverHost.swift */; }; C9A57601C9A57601C9A57601 /* SidebarWorkspaceTopDropIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9A57602C9A57602C9A57602 /* SidebarWorkspaceTopDropIndicator.swift */; }; A6AC73330000000000000001 /* SidebarWorkspaceTrailingStatusSlot.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6AC73330000000000000002 /* SidebarWorkspaceTrailingStatusSlot.swift */; }; @@ -7462,6 +7463,7 @@ B804B0170000000000000017 /* SidebarWorkspaceTableViewportAnchor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sidebar/AppKitList/SidebarWorkspaceTableViewportAnchor.swift; sourceTree = ""; }; 55E01DE5B078B38299582BB0 /* SidebarWorkspaceTaskStatusGlyph.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarWorkspaceTaskStatusGlyph.swift; sourceTree = ""; }; A12481500000000000000002 /* SidebarWorkspaceTaskStatusSnapshot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarWorkspaceTaskStatusSnapshot.swift; sourceTree = ""; }; + 113AC461B8EC754FBE12E568 /* SidebarWorkspaceTitleRoomTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SidebarWorkspaceTitleRoomTests.swift"; sourceTree = ""; }; 4AEAD128139F57CB0E5BD39E /* SidebarWorkspaceTodoPopoverHost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SidebarWorkspaceTodoPopoverHost.swift"; sourceTree = ""; }; C9A57602C9A57602C9A57602 /* SidebarWorkspaceTopDropIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarWorkspaceTopDropIndicator.swift; sourceTree = ""; }; A6AC73330000000000000002 /* SidebarWorkspaceTrailingStatusSlot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sidebar/SidebarWorkspaceTrailingStatusSlot.swift; sourceTree = ""; }; @@ -12822,6 +12824,7 @@ 5DEADB23282C5C0D06630294 /* CloudMachineDeleteOptimismTests.swift */, B66A94F226BD05E5B9262ED5 /* MachineDeleteCoordinatorTests.swift */, 311C986A1E7430418708AAA6 /* MachinesListStatusToolbarRowTests.swift */, + 113AC461B8EC754FBE12E568 /* SidebarWorkspaceTitleRoomTests.swift */, 1C38B9AFEEE4FAE6089C250F /* CloudTreeRowToolTipTests.swift */, 6F27EA9972F21B98FB4A7312 /* SurfaceCatalogObservationTests.swift */, 81B9355A408361D86E077820 /* TerminalDictationAccessibilityTests.swift */, @@ -17495,6 +17498,7 @@ 961200010000000000000001 /* SidebarWorkspaceSwitchLayoutFaultTests.swift in Sources */, B8624C030000000000000003 /* SidebarWorkspaceTableSuspensionTests.swift in Sources */, B804C0010000000000000001 /* SidebarWorkspaceTableTests.swift in Sources */, + 37FD66D9F50E825472874750 /* SidebarWorkspaceTitleRoomTests.swift in Sources */, C51A720000000000000000B1 /* SimulatorPanelIntegrationTests.swift in Sources */, C51A760000000000000000D1 /* SimulatorPanelThemeTests.swift in Sources */, A7984AE10000000000000001 /* SocketACLReloadRegressionTests+Connections.swift in Sources */, diff --git a/cmuxTests/SidebarAppKitRowCellTests.swift b/cmuxTests/SidebarAppKitRowCellTests.swift index adc6cba2bc85..dc9af71ce3c7 100644 --- a/cmuxTests/SidebarAppKitRowCellTests.swift +++ b/cmuxTests/SidebarAppKitRowCellTests.swift @@ -63,6 +63,8 @@ struct SidebarAppKitRowCellTests { static func makeModel( workspaceId: UUID = UUID(), isActive: Bool = false, + isMultiSelected: Bool = false, + unreadCount: Int = 0, isPinned: Bool = false, canClose: Bool = true, settings: SidebarTabItemSettingsSnapshot? = nil, @@ -88,11 +90,11 @@ struct SidebarAppKitRowCellTests { ), settings: resolvedSettings, isActive: isActive, - isMultiSelected: false, + isMultiSelected: isMultiSelected, hasUserCustomTitle: false, canCloseWorkspace: canClose, accessibilityWorkspaceCount: 1, - unreadCount: 0, + unreadCount: unreadCount, latestNotificationText: nil, showsAgentActivity: resolvedSettings.details.showAgentActivity, rowSpacing: 8, @@ -473,6 +475,188 @@ struct SidebarAppKitRowCellTests { return textView.convert(localPoint, to: textView.superview) } + /// The sidebar reads better when only the rows that need attention are + /// heavy, so a resting row draws its title lighter than a selected row or + /// a row with unread notifications. + @Test + func workspaceTitleWeightTracksSelectionAndUnread() throws { + func titleFont(_ model: SidebarWorkspaceRowModel) throws -> NSFont { + let cell = Self.configuredCell(model: model) + let titleView = try #require( + Self.descendants(of: cell) + .compactMap { $0 as? SidebarRowTextView } + .first { !$0.isHidden && $0.stringValue == model.snapshot.title } + ) + return try #require(titleView.font) + } + + let size = Self.makeModel().scaled(SidebarRowTitleMetrics.fontSize) + #expect(try titleFont(Self.makeModel()) == NSFont.systemFont(ofSize: size, weight: .regular)) + #expect(try titleFont(Self.makeModel(isActive: true)) == NSFont.systemFont(ofSize: size, weight: .semibold)) + #expect(try titleFont(Self.makeModel(isMultiSelected: true)) == NSFont.systemFont(ofSize: size, weight: .semibold)) + #expect(try titleFont(Self.makeModel(unreadCount: 3)) == NSFont.systemFont(ofSize: size, weight: .semibold)) + } + + /// The selection preview paints colors ahead of the authoritative apply, + /// but row heights are measured from the stored model. Weight changes text + /// metrics, so a preview that also changed the weight could draw a wrapped + /// title at one weight inside a frame measured at the other. + @Test + func optimisticSelectionPaintDoesNotChangeTitleWeight() throws { + let model = Self.makeModel(isActive: false) + let cell = Self.configuredCell(model: model) + func titleFont() throws -> NSFont { + let titleView = try #require( + Self.descendants(of: cell) + .compactMap { $0 as? SidebarRowTextView } + .first { !$0.isHidden && $0.stringValue == model.snapshot.title } + ) + return try #require(titleView.font) + } + + let resting = NSFont.systemFont(ofSize: model.scaled(SidebarRowTitleMetrics.fontSize), weight: .regular) + #expect(try titleFont() == resting) + cell.showOptimisticSelectionHighlight() + #expect(cell.hasOptimisticSelectionForTesting) + #expect(try titleFont() == resting) + } + + private static func titleView( + in cell: SidebarWorkspaceRowTableCellView, + model: SidebarWorkspaceRowModel + ) throws -> SidebarRowTextView { + try #require( + Self.descendants(of: cell) + .compactMap { $0 as? SidebarRowTextView } + .first { !$0.isHidden && $0.stringValue == model.snapshot.title } + ) + } + + /// A one-line title keeps its start and its distinctive tail: the middle of + /// a title is the least useful part of it to read, and the tail carries the + /// host in names like `cmux-remote-status @host`. + @Test + func singleLineTitleTruncatesInTheMiddle() throws { + let model = Self.makeModel() + let cell = Self.configuredCell(model: model) + let titleView = try Self.titleView(in: cell, model: model) + + #expect(titleView.maximumNumberOfLines == 1) + #expect(titleView.lineBreakMode == .byTruncatingMiddle) + } + + /// `sidebar.twoLineWorkspaceTitles` is the middle ground between one line + /// and showing a title in full. A two-line title has to end in an ellipsis, + /// so it truncates rather than wrapping without a mark. + @Test + func twoLineTitleSettingGivesTheTitleASecondLine() throws { + let defaults = Self.makeDefaults() + defaults.set(true, forKey: "sidebarTwoLineWorkspaceTitles") + let settings = SidebarTabItemSettingsSnapshot(defaults: defaults) + #expect(settings.usesTwoLineWorkspaceTitles) + #expect(Self.makeSwiftUIRow(settings: settings).settings.usesTwoLineWorkspaceTitles) + + let model = Self.makeModel(settings: settings) + let cell = Self.configuredCell(model: model) + let titleView = try Self.titleView(in: cell, model: model) + + #expect(titleView.maximumNumberOfLines == 2) + #expect(titleView.lineBreakMode == .byTruncatingTail) + } + + /// Wrapping still wins when it is on: the setting that shows a title in + /// full is not overridden by the two-line setting. + @Test + func wrappingTitlesOutranksTheTwoLineSetting() throws { + let defaults = Self.makeDefaults() + defaults.set(true, forKey: "sidebarTwoLineWorkspaceTitles") + defaults.set(true, forKey: SidebarWorkspaceTitleWrapSettings.key) + let model = Self.makeModel(settings: SidebarTabItemSettingsSnapshot(defaults: defaults)) + let cell = Self.configuredCell(model: model) + let titleView = try Self.titleView(in: cell, model: model) + + #expect(titleView.maximumNumberOfLines == SidebarRowTitleMetrics.maxWrappedLines) + #expect(titleView.lineBreakMode == .byWordWrapping) + } + + /// The close button is revealed on hover, so a row the pointer is not on + /// spends that column on its title instead of leaving it blank. The reveal + /// insets the title, which is safe because a single line's height does not + /// depend on its width. + @Test + func closeButtonColumnIsOnlyHeldOpenWhileItShows() throws { + let width: CGFloat = 240 + let model = Self.makeModel(canClose: true) + let cell = Self.configuredCell(model: model) + let window = Self.layoutCell(cell, model: model, width: width) + defer { window.close() } + let titleView = try Self.titleView(in: cell, model: model) + let contentTrailing = width + - SidebarWorkspaceListMetrics.rowOuterHorizontalPadding + - SidebarWorkspaceListMetrics.rowContentHorizontalPadding + + #expect(titleView.frame.maxX == contentTrailing) + + cell.enforcePointerHovering(true) + cell.layoutContent(model: model, width: width, apply: true) + + #expect(titleView.frame.maxX == contentTrailing - 24) + #expect(!cell.closeButtonPaintForTesting.isHidden) + } + + /// The shortcut hint pill is painted over the row's trailing edge instead of + /// being placed in the trailing slot, and it replaces the close button while + /// it shows. The title still has to stay out from under it, because a + /// one-line title truncates in the middle and its end carries meaning. + @Test + func shortcutHintPillHoldsTheTrailingColumnOpen() throws { + let width: CGFloat = 240 + let model = Self.makeModel(canClose: true, shortcutHintText: "1") + let cell = Self.configuredCell(model: model) + let window = Self.layoutCell(cell, model: model, width: width) + defer { window.close() } + let titleView = try Self.titleView(in: cell, model: model) + let reserved = width + - SidebarWorkspaceListMetrics.rowOuterHorizontalPadding + - SidebarWorkspaceListMetrics.rowContentHorizontalPadding + - 24 + + #expect(titleView.frame.maxX == reserved) + + // The pill stands in for the close button, so hovering such a row shows + // no button and moves nothing. + cell.enforcePointerHovering(true) + cell.layoutContent(model: model, width: width, apply: true) + + #expect(titleView.frame.maxX == reserved) + #expect(cell.closeButtonPaintForTesting.isHidden) + } + + /// A wrapped title's height DOES depend on its width, so hovering such a + /// row must not change the width its height was measured at. + @Test + func wrappedTitleKeepsTheCloseButtonColumnReserved() throws { + let width: CGFloat = 240 + let defaults = Self.makeDefaults() + defaults.set(true, forKey: SidebarWorkspaceTitleWrapSettings.key) + let model = Self.makeModel(canClose: true, settings: SidebarTabItemSettingsSnapshot(defaults: defaults)) + let cell = Self.configuredCell(model: model) + let window = Self.layoutCell(cell, model: model, width: width) + defer { window.close() } + let titleView = try Self.titleView(in: cell, model: model) + let reserved = width + - SidebarWorkspaceListMetrics.rowOuterHorizontalPadding + - SidebarWorkspaceListMetrics.rowContentHorizontalPadding + - 24 + + #expect(titleView.frame.maxX == reserved) + + cell.enforcePointerHovering(true) + cell.layoutContent(model: model, width: width, apply: true) + + #expect(titleView.frame.maxX == reserved) + } + @Test func cancelingInlineRenameRestoresWorkspaceTitle() throws { let model = Self.makeModel() diff --git a/cmuxTests/SidebarCloudWorkspaceBadgeTests.swift b/cmuxTests/SidebarCloudWorkspaceBadgeTests.swift index 9ec5743cf0a5..0f7931835606 100644 --- a/cmuxTests/SidebarCloudWorkspaceBadgeTests.swift +++ b/cmuxTests/SidebarCloudWorkspaceBadgeTests.swift @@ -1,6 +1,7 @@ import AppKit import CmuxCore import CmuxSettings +import CmuxSidebar import CmuxSurfaceCatalogModel import Observation import Testing @@ -265,7 +266,12 @@ struct SidebarCloudWorkspaceBadgeTests { #expect(badge.frame.maxX + 8 == title.frame.minX) } #expect(title.frame.maxX <= width) - #expect(title.lineBreakMode == .byTruncatingTail) + // What the badge has to leave behind is a truncating single line, not a + // wrapping one. Naming a mode here would restate the default and go stale + // whenever the truncation settings change; the modes themselves are pinned + // by SidebarRowTitleMetricsTests. + #expect(title.maximumNumberOfLines == 1) + #expect(title.lineBreakMode == SidebarRowTitleMetrics(lineLimit: 1).appKitLineBreakMode) #expect(cell.accessibilityLabel()?.contains("Cloud workspace on vivid-newt") == true) let pins = images.filter { !$0.isHidden && $0.toolTip == String( localized: "sidebar.pinnedWorkspaceProtected.tooltip", defaultValue: "Pinned workspace — protected from Close") } diff --git a/cmuxTests/SidebarWorkspaceGroupHeaderMetricsTests.swift b/cmuxTests/SidebarWorkspaceGroupHeaderMetricsTests.swift index 2b0a500d3dcf..ed649dd99389 100644 --- a/cmuxTests/SidebarWorkspaceGroupHeaderMetricsTests.swift +++ b/cmuxTests/SidebarWorkspaceGroupHeaderMetricsTests.swift @@ -72,11 +72,11 @@ import Testing let closeButtonWidth = SidebarTrailingAccessoryWidthPolicy().closeButtonWidth let metrics = SidebarWorkspaceGroupHeaderMetrics(fontScale: 1) - #expect(SidebarWorkspaceListMetrics.rowContentHorizontalPadding == 10) + #expect(SidebarWorkspaceListMetrics.rowContentHorizontalPadding == 8) #expect(SidebarWorkspaceListMetrics.rowOuterHorizontalPadding == 6) #expect(metrics.plusFrame == closeButtonWidth) - #expect(SidebarWorkspaceListMetrics.trailingAccessoryRightEdgeOffset == 16) - #expect(SidebarWorkspaceListMetrics.trailingAccessoryCenterOffset(controlWidth: metrics.plusFrame) == 24) + #expect(SidebarWorkspaceListMetrics.trailingAccessoryRightEdgeOffset == 14) + #expect(SidebarWorkspaceListMetrics.trailingAccessoryCenterOffset(controlWidth: metrics.plusFrame) == 22) #expect( SidebarWorkspaceListMetrics.trailingAccessoryCenterOffset(controlWidth: metrics.plusFrame) == SidebarWorkspaceListMetrics.trailingAccessoryCenterOffset(controlWidth: closeButtonWidth) diff --git a/cmuxTests/SidebarWorkspaceTitleRoomTests.swift b/cmuxTests/SidebarWorkspaceTitleRoomTests.swift new file mode 100644 index 000000000000..bb4ad02623d1 --- /dev/null +++ b/cmuxTests/SidebarWorkspaceTitleRoomTests.swift @@ -0,0 +1,118 @@ +import AppKit +import CmuxSidebar +import Testing +@testable import cmux_DEV + +/// How much of a workspace title the sidebar can show on one line at the +/// default sidebar width. +/// +/// Titles were cutting off inside a dozen characters, which made the list +/// useless for telling similar workspaces apart. Three defaults paid for that: +/// the title point size, the row's content padding, and a trailing column held +/// open for a close button that only appears on hover. These tests measure the +/// shipped-before and current geometry with the same text layout the rows use, +/// so a later change that quietly takes the room back fails here. +@Suite +@MainActor +struct SidebarWorkspaceTitleRoomTests { + /// Titles taken from cmux work: a PR title, a branch-shaped name, a + /// remote workspace with a host suffix, and two task names. + static let titles = [ + "Fix cmux pane focus indicator flicker", + "cmux-remote-status @workstation", + "Docs pass over the sidebar row copy", + "Sidebar title truncation", + "feat/workspace-group-collapse", + ] + + struct Geometry { + /// Point size of the title font. + let fontSize: CGFloat + /// `SidebarWorkspaceListMetrics.rowContentHorizontalPadding`. + let contentPadding: CGFloat + /// Whether a row that merely CAN be closed holds the close button's + /// column open while the pointer is elsewhere. + let reservesCloseButtonColumn: Bool + + /// Width available to a resting, ungrouped row's title. + var titleWidth: CGFloat { + let outer = SidebarWorkspaceListMetrics.rowOuterHorizontalPadding + let content = CGFloat(SessionPersistencePolicy.defaultSidebarWidth) - 2 * (outer + contentPadding) + guard reservesCloseButtonColumn else { return content } + // The cell's own numbers: a 16pt close button and the 8pt gap + // between the title and the trailing slot. + return content - 16 - 8 + } + + /// Leading characters of `title` that fit on one line. + func visibleCharacters(of title: String) -> Int { + let font = NSFont.systemFont(ofSize: fontSize, weight: .regular) + let attributes: [NSAttributedString.Key: Any] = [.font: font] + let limit = titleWidth + var fitting = 0 + for count in 1...title.count { + let prefix = String(title.prefix(count)) + if ceil((prefix as NSString).size(withAttributes: attributes).width) <= limit { + fitting = count + } else { + break + } + } + return fitting + } + } + + /// What cmux shipped before this change. + static let before = Geometry(fontSize: 12.5, contentPadding: 10, reservesCloseButtonColumn: true) + + /// What the current defaults resolve to. Read from the shipping sources, so + /// this cannot drift from what the rows draw. + static var current: Geometry { + Geometry( + fontSize: SidebarRowTitleMetrics.fontSize, + contentPadding: SidebarWorkspaceListMetrics.rowContentHorizontalPadding, + reservesCloseButtonColumn: false + ) + } + + @Test + func defaultWidthShowsMoreOfEveryTitleThanBefore() { + let before = Self.before + let current = Self.current + #expect(current.titleWidth > before.titleWidth) + + var report = ["title | before | after"] + for title in Self.titles { + let was = before.visibleCharacters(of: title) + let now = current.visibleCharacters(of: title) + report.append("\(title) | \(was) | \(now)") + #expect(now >= was, "\(title) lost room: \(was) -> \(now)") + if was < title.count { + // A title that was being cut off gets strictly more room. + #expect(now > was, "\(title) gained nothing: \(was) -> \(now)") + } else { + // A title that already fitted whole cannot gain characters, and + // must not start losing them. + #expect(now == title.count, "\(title) no longer fits whole: \(now)") + } + // The complaint was titles cutting off around a dozen characters. + #expect(now >= 20, "\(title) still cuts off at \(now) characters") + } + // Printed so the exact counts are readable in the test log and can be + // quoted without re-deriving them by hand. + print("sidebar title room at \(Int(SessionPersistencePolicy.defaultSidebarWidth))pt\n" + report.joined(separator: "\n")) + } + + /// The hover-revealed close button is the only thing that needs the + /// trailing column, so a resting row spends that width on its title. + @Test + func restingRowDoesNotReserveTheCloseButtonColumn() { + let reserved = Geometry( + fontSize: SidebarRowTitleMetrics.fontSize, + contentPadding: SidebarWorkspaceListMetrics.rowContentHorizontalPadding, + reservesCloseButtonColumn: true + ) + + #expect(Self.current.titleWidth == reserved.titleWidth + 24) + } +} diff --git a/dogfood/scenarios/sidebar-row-weight-tour.json b/dogfood/scenarios/sidebar-row-weight-tour.json new file mode 100644 index 000000000000..b3ee3600abef --- /dev/null +++ b/dogfood/scenarios/sidebar-row-weight-tour.json @@ -0,0 +1,187 @@ +{ + "note": "Sidebar row states for judging text weight and title room: resting rows, a selected row, an unread row, group rows collapsed and expanded, and a hovered row. The launch arguments pin every sidebar setting that changes the row layout to its shipping default, so the frames show the default rather than settings a machine kept from an earlier run.", + "paths": [ + "Packages/macOS/CmuxSidebar/Sources/CmuxSidebar/Typography/*", + "Sources/Sidebar/AppKitList/Cells/*" + ], + "launch": { + "args": [ + "-sidebarTwoLineWorkspaceTitles", + "", + "-sidebarWrapWorkspaceTitles", + "", + "-sidebarCompactAgentStatus", + "", + "-workspacePresentationMode", + "standard" + ] + }, + "steps": [ + { + "socket": "workspace.create", + "params": { + "title": "Fix cmux pane focus indicator flicker", + "focus": false + }, + "save": "focusFix" + }, + { + "socket": "workspace.create", + "params": { + "title": "cmux-remote-status @workstation", + "focus": false + }, + "save": "remoteStatus" + }, + { + "socket": "workspace.create", + "params": { + "title": "Docs pass over the sidebar row copy", + "focus": false + }, + "save": "docs" + }, + { + "socket": "workspace.create", + "params": { + "title": "feat/workspace-group-collapse", + "focus": false + }, + "save": "groupCollapse" + }, + { + "socket": "workspace.create", + "params": { + "title": "Deploy checks", + "focus": false + }, + "save": "deploy" + }, + { + "socket": "workspace.create", + "params": { + "title": "API refactor", + "focus": false + }, + "save": "api" + }, + { + "socket": "workspace.create", + "params": { + "title": "Migrations", + "focus": false + }, + "save": "migrations" + }, + { + "socket": "workspace.create", + "params": { + "title": "Notification badge colors", + "focus": false + }, + "save": "badges" + }, + { + "socket": "workspace.create", + "params": { + "title": "cmux-cloud-machines @builder", + "focus": false + }, + "save": "cloudMachines" + }, + { + "socket": "workspace.create", + "params": { + "title": "Settings search index cleanup", + "focus": false + }, + "save": "settingsSearch" + }, + { + "socket": "workspace.group.create", + "params": { + "name": "Release 0.42", + "child_workspace_ids": [ + "${deploy.workspace_id}", + "${api.workspace_id}" + ] + }, + "save": "grp" + }, + { + "wait": 1 + }, + { + "socket": "notification.create_for_caller", + "params": { + "preferred_workspace_id": "${docs.workspace_id}", + "preferred_workspace_is_explicit": true, + "title": "Agent finished a turn", + "body": "Unread row state for the sidebar tour" + } + }, + { + "socket": "workspace.create", + "params": { + "title": "Sidebar title truncation", + "focus": true + }, + "save": "selected" + }, + { + "wait": 2 + }, + { + "shot": "sidebar-row-states" + }, + { + "tree": "sidebar-row-states" + }, + { + "key": "escape" + }, + { + "wait": 1 + }, + { + "shot": "sidebar-row-states-settled" + }, + { + "hoverAt": { + "x": 0.08, + "y": 0.2 + } + }, + { + "wait": 0.5 + }, + { + "shot": "sidebar-row-hover" + }, + { + "socket": "workspace.group.collapse", + "params": { + "group_id": "${grp.group.id}" + } + }, + { + "wait": 1 + }, + { + "shot": "sidebar-group-collapsed" + }, + { + "socket": "workspace.group.expand", + "params": { + "group_id": "${grp.group.id}" + } + }, + { + "wait": 1 + }, + { + "shot": "sidebar-group-expanded", + "screen": true + } + ] +} diff --git a/skills/cmux-settings/references/all-keys.md b/skills/cmux-settings/references/all-keys.md index dc3c1a4759df..c8661ad72084 100644 --- a/skills/cmux-settings/references/all-keys.md +++ b/skills/cmux-settings/references/all-keys.md @@ -126,6 +126,7 @@ Sidebar content and metadata visibility from Settings > Sidebar. | `sidebar.compactAgentStatus` | boolean | `false` | Fold a workspace's agent status, branch, pull request and unread rows into one colored icon before the title, with the details in its tooltip. Rows you added yourself keep their lines. | | `sidebar.compactStatusIcons` | object | `{}` | SF Symbol names that replace the compactAgentStatus glyph for each state, for example {"terminal": "apple.terminal", "needsInput": "hand.raised.fill"}. Unset states keep the built-in symbol, and a name that does not render falls back to it. | | `sidebar.wrapWorkspaceTitles` | boolean | `false` | Allow workspace titles in the sidebar to wrap to multiple lines instead of truncating after one line. | +| `sidebar.twoLineWorkspaceTitles` | boolean | `false` | Allow a workspace title in the sidebar a second line before it is truncated, instead of showing it in full like wrapWorkspaceTitles. | | `sidebar.beta` | object | — | Experimental sidebar features. | | `sidebar.notificationMessageLineLimit` | integer | `12` | Maximum lines shown for the latest notification below each workspace title. | | `sidebar.watchGitStatus` | boolean | `true` | Watch repository files for sidebar branch and pull request metadata without polling git. | diff --git a/web/data/cmux.schema.json b/web/data/cmux.schema.json index 77b4930d1c60..064910aa25ac 100644 --- a/web/data/cmux.schema.json +++ b/web/data/cmux.schema.json @@ -1327,6 +1327,11 @@ "default": false, "description": "Allow workspace titles in the sidebar to wrap to multiple lines instead of truncating after one line." }, + "twoLineWorkspaceTitles": { + "type": "boolean", + "default": false, + "description": "Allow a workspace title in the sidebar a second line before it is truncated, instead of showing it in full like wrapWorkspaceTitles." + }, "showWorkspaceDescription": { "type": "boolean", "default": true,