From 4b31ff4728bee8914eee928a94d8cd055cdc536a Mon Sep 17 00:00:00 2001 From: Austin Wang Date: Sun, 6 Sep 2026 17:27:42 -0700 Subject: [PATCH 01/50] Add macOS localization parity tooling --- .github/workflows/ci.yml | 3 + CLAUDE.md | 2 +- .../SimulatorLocalizationCatalogTests.swift | 4 +- scripts/localization-allowed-omissions.json | 185 ++++++++++ scripts/localization-plurals.json | 43 +++ scripts/localization_catalog.py | 347 ++++++++++++++++++ skills/cmux-localization/SKILL.md | 6 +- 7 files changed, 585 insertions(+), 5 deletions(-) create mode 100644 scripts/localization-allowed-omissions.json create mode 100644 scripts/localization-plurals.json create mode 100644 scripts/localization_catalog.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e04c9183bca5..151f06e4d528 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -156,6 +156,9 @@ jobs: - name: Validate Python test harness syntax run: git ls-files 'tests/*.py' 'tests_v2/*.py' 'scripts/*.py' | xargs python3 -m py_compile + - name: Validate macOS localization parity + run: python3 scripts/localization_catalog.py check + - name: Validate TUI npm package artifact transfer run: python3 tests/test_tui_npm_package_artifact.py diff --git a/CLAUDE.md b/CLAUDE.md index 9aa9f141fa84..70575df5f038 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -127,7 +127,7 @@ Each of these has full detail in the skill named in parentheses. - **Terminal find layering** (`cmux-debugging`): `SurfaceSearchOverlay` mounts from `GhosttySurfaceScrollView` in `Sources/GhosttyTerminalView.swift` (AppKit portal layer), never from SwiftUI panel containers such as `Sources/Panels/TerminalPanelView.swift`. Portal-hosted terminal views can sit above SwiftUI during split/workspace churn. - **Custom UTTypes** for drag-and-drop must be declared in `Resources/Info.plist` under `UTExportedTypeDeclarations` (e.g. `com.splittabbar.tabtransfer`, `com.cmux.sidebar-tab-reorder`). - **Submodule safety** (`cmux-ghostty`): push the submodule commit to its remote `main` before committing the pointer in the parent repo. Never commit on a detached HEAD. Verify with `git merge-base --is-ancestor HEAD origin/main`. -- **Localize every user-facing string** (`cmux-localization`): `String(localized:)` with keys in `Resources/Localizable.xcstrings`, plus every web message catalog (`web/messages/en.json`, `web/messages/ja.json`). A localization audit is required for any UI, Settings, menu, schema, docs, or help-text change, and the handoff must state what was audited. +- **Localize every user-facing string** (`cmux-localization`): `String(localized:)` with keys in `Resources/Localizable.xcstrings`, plus every web message catalog (`web/messages/en.json`, `web/messages/ja.json`). The supported macOS app locales are English, German, French, Arabic, Spanish, Traditional Chinese, Simplified Chinese, Korean, and Japanese (`en`, `de`, `fr`, `ar`, `es`, `zh-Hant`, `zh-Hans`, `ko`, `ja`). A localization audit is required for any UI, Settings, menu, schema, docs, or help-text change, and the handoff must state what was audited. - **Shortcut policy** (`cmux-keyboard-shortcuts`): every new cmux-owned shortcut goes in `KeyboardShortcutSettings`, is editable in Settings, is supported in `~/.config/cmux/cmux.json`, and is documented. - **Test wiring** (`cmux-testing`): a `.swift` file in `cmuxTests/` without a `PBXFileReference` + `PBXSourcesBuildPhase` entry is silently skipped, and both `xcodebuild test` and bot reviews pass with "Executed 0 tests". `workflow-guard-tests` runs `./scripts/lint-pbxproj-test-wiring.sh` to catch it. - **SPM package groups** (`cmux-architecture`): packages live under `Packages/{Shared,iOS,macOS}/` and the workspace mirrors that folder shape. To move one, `git mv` the directory then `python3 scripts/check-workspace-package-groups.py --write`. Never hand-edit workspace group membership. diff --git a/Packages/macOS/CmuxSimulator/Tests/CmuxSimulatorTests/SimulatorLocalizationCatalogTests.swift b/Packages/macOS/CmuxSimulator/Tests/CmuxSimulatorTests/SimulatorLocalizationCatalogTests.swift index 0e42d52328b0..3439feec9486 100644 --- a/Packages/macOS/CmuxSimulator/Tests/CmuxSimulatorTests/SimulatorLocalizationCatalogTests.swift +++ b/Packages/macOS/CmuxSimulator/Tests/CmuxSimulatorTests/SimulatorLocalizationCatalogTests.swift @@ -3,7 +3,7 @@ import Testing @Suite("Simulator localization catalog") struct SimulatorLocalizationCatalogTests { - @Test("Worker request routing failures have English and Japanese copy") + @Test("Worker request routing failures have all supported macOS locale copy") func workerRequestRoutingFailuresAreLocalized() throws { var repositoryRoot = URL(fileURLWithPath: #filePath) for _ in 0..<6 { @@ -25,7 +25,7 @@ struct SimulatorLocalizationCatalogTests { let entry = strings[key] as? [String: Any] #expect(entry != nil) let localizations = entry?["localizations"] as? [String: Any] - for language in ["en", "ja"] { + for language in ["en", "de", "fr", "ar", "es", "zh-Hant", "zh-Hans", "ko", "ja"] { let localization = localizations?[language] as? [String: Any] let stringUnit = localization?["stringUnit"] as? [String: Any] let value = stringUnit?["value"] as? String diff --git a/scripts/localization-allowed-omissions.json b/scripts/localization-allowed-omissions.json new file mode 100644 index 000000000000..7368fdb5930c --- /dev/null +++ b/scripts/localization-allowed-omissions.json @@ -0,0 +1,185 @@ +{ + "agent.hermes.notification.body.approvalCommand": "price and plan literals", + "agent.kimi.displayName": "product and brand names", + "agent.ollama.displayName": "product and brand names", + "browser.designMode.copy.shortcut": "format-only strings or CLI syntax fragments", + "browser.import.complete.profileMapping": "product and brand names", + "cli.browser.designMode.help": "CLI syntax fragments", + "cli.browser.help.viewportUsage": "CLI syntax fragments", + "cli.browser.profile.option": "CLI syntax fragments", + "cli.claude-hook.notification.title": "product and brand names", + "cli.help.ios": "CLI syntax fragments", + "cli.help.simulator": "CLI syntax fragments", + "cli.sidebar.report.ok": "product and brand names", + "command.cloudVM.restore.prompt.placeholder": "product and brand names", + "command.cloudVM.result.title": "product and brand names", + "command.cmuxConfig.builtInSubtitle": "product and brand names", + "command.cmuxConfig.defaultClaudeCodeTitle": "product and brand names", + "command.cmuxConfig.defaultCodexTitle": "product and brand names", + "command.cmuxConfig.defaultOpenCodeTitle": "product and brand names", + "command.cmuxConfig.issue.schemaError.detail": "format-only strings or CLI syntax fragments", + "command.cmuxConfig.issue.subtitle": "product and brand names", + "command.toggleSetting.subtitle": "product and brand names", + "commandPalette.kind.cloudVMLoading": "product and brand names", + "commandPalette.kind.markdown": "product and brand names", + "commandPalette.subtitle.markdownWithName": "product and brand names", + "debug.bonsplitTabBarDebug.pixelsValue": "product and brand names", + "debug.tabBarBackdropLab.leftSidebar": "product and brand names", + "debug.tabBarBackdropLab.rightSidebar": "product and brand names", + "debug.tabBarBackdropLab.terminal.prompt": "product and brand names", + "debug.tabBarBackdropLab.titlebarSample": "product and brand names", + "dock.source.error": "product and brand names", + "dock.source.title": "product and brand names", + "feed.exitplan.mode.ultraplan": "product and brand names", + "feed.exitplan.ultraplan": "product and brand names", + "feed.notification.exitPlan.ultraplan": "product and brand names", + "feed.textEditorDebug.section.appkit": "product and brand names", + "feed.textEditorDebug.section.swiftui": "product and brand names", + "feed.textEditorDebug.variant.swiftUIMirror": "product and brand names", + "feed.textEditorDebug.variant.swiftUITextField": "product and brand names", + "globalSearch.kind.markdown": "product and brand names", + "markdown.fontSize.unit": "product and brand names", + "markdown.maxWidth.unit": "product and brand names", + "menu.help.claudeCodeTeams": "product and brand names", + "menu.help.dock": "product and brand names", + "menu.help.ohMyClaudeCode": "product and brand names", + "menu.help.ohMyCodex": "product and brand names", + "menu.help.ohMyOpenCode": "product and brand names", + "menu.help.ssh": "product and brand names", + "menu.history.recentlyClosed.panel.cloudVM": "product and brand names", + "paneMemoryGuardrail.banner.detail": "price and plan literals", + "panel.cloudVM.loading.title": "product and brand names", + "pricing.enterprise.f3": "technical acronyms and identifiers", + "pricing.native.compare.concurrent.free": "product and brand names", + "pricing.native.eyebrow": "product and brand names", + "pricing.native.free.price": "price and plan literals", + "pricing.native.metric.vm.value": "price and plan literals", + "pricing.native.plan.pro": "product and brand names", + "pricing.native.size.large.rate": "price and plan literals", + "pricing.native.size.medium.rate": "price and plan literals", + "pricing.native.size.small.rate": "price and plan literals", + "pricing.pro.name": "product and brand names", + "pricing.pro.workspace.title": "product and brand names", + "pricing.window.title": "product and brand names", + "rightSidebar.mode.dock": "product and brand names", + "rightSidebar.mode.feed": "product and brand names", + "rightSidebar.mode.sessions": "product and brand names", + "sessionIndex.agent.claude": "product and brand names", + "sessionIndex.agent.codex": "product and brand names", + "sessionIndex.agent.grok": "product and brand names", + "sessionIndex.agent.opencode": "product and brand names", + "sessionIndex.agent.pi": "product and brand names", + "sessionIndex.agent.rovodev": "product and brand names", + "settings.account.pro.title": "product and brand names", + "settings.betaFeatures.dock": "product and brand names", + "settings.betaFeatures.feed": "product and brand names", + "settings.config.source.cmux": "product and brand names", + "settings.fontSize.valuePoints": "product and brand names", + "settings.mobile.route.iroh": "product and brand names", + "settings.mobile.route.tailscale": "product and brand names", + "settings.mobile.route.websocket": "product and brand names", + "settings.networking.custom.summary": "price and plan literals", + "settings.notifications.command.placeholder": "product and brand names", + "settings.search.alias.section.customSidebars": "product and brand names", + "settings.search.alias.section.mobile": "product and brand names", + "settings.search.alias.section.networking": "product and brand names", + "settings.search.alias.section.sleepyMode": "product and brand names", + "settings.search.alias.setting.app.canvas-pane-gap": "product and brand names", + "settings.search.alias.setting.app.canvas-snapping": "product and brand names", + "settings.search.alias.setting.app.default-terminal": "product and brand names", + "settings.search.alias.setting.app.file-editor-word-wrap": "product and brand names", + "settings.search.alias.setting.app.markdown-font-family": "product and brand names", + "settings.search.alias.setting.app.markdown-font-size": "product and brand names", + "settings.search.alias.setting.app.markdown-max-width": "product and brand names", + "settings.search.alias.setting.app.show-workspace-description": "product and brand names", + "settings.search.alias.setting.app.supported-file-previews": "product and brand names", + "settings.search.alias.setting.app.warn-before-closing-tab": "product and brand names", + "settings.search.alias.setting.app.workspace-inherit-working-directory": "product and brand names", + "settings.search.alias.setting.automation.kiro": "product and brand names", + "settings.search.alias.setting.automation.kiro-notification-level": "product and brand names", + "settings.search.alias.setting.automation.ripgrep-path": "product and brand names", + "settings.search.alias.setting.betaFeatures.workspace-todo-controls": "product and brand names", + "settings.search.alias.setting.betaFeatures.workspace-todos-checklist-style": "product and brand names", + "settings.search.alias.setting.browser.ask-where-to-save-downloads": "product and brand names", + "settings.search.alias.setting.browser.hidden-webview-discard": "product and brand names", + "settings.search.alias.setting.browser.hidden-webview-discard-delay": "product and brand names", + "settings.search.alias.setting.mobile.artifactFolderAccess": "product and brand names", + "settings.search.alias.setting.mobile.iOSPairingDisplayName": "product and brand names", + "settings.search.alias.setting.mobile.iOSPairingHost": "product and brand names", + "settings.search.alias.setting.mobile.iOSPairingPort": "product and brand names", + "settings.search.alias.setting.networking.customRelays": "product and brand names", + "settings.search.alias.setting.networking.policy": "product and brand names", + "settings.search.alias.setting.networking.privateNetworks": "product and brand names", + "settings.search.alias.setting.networking.relayPreference": "product and brand names", + "settings.search.alias.setting.networking.status": "product and brand names", + "settings.search.alias.setting.networking.tailscaleCompatibility": "product and brand names", + "settings.search.alias.setting.sidebarAppearance.font-size": "product and brand names", + "settings.search.alias.setting.terminal.resume-commands": "product and brand names", + "settings.search.alias.setting.terminal.session-content-alignment": "product and brand names", + "settings.search.alias.setting.terminal.session-content-width": "product and brand names", + "settings.search.alias.setting.terminal.tab-bar-font-size": "product and brand names", + "settings.search.alias.setting.textBox.default-submit-action": "product and brand names", + "settings.section.settingsJSON": "product and brand names", + "settings.sidebarAppearance.fontSize.points": "product and brand names", + "settings.terminal.scrollSpeed.value": "format-only strings or CLI syntax fragments", + "settings.terminal.sessionContentWidth.unit": "product and brand names", + "settings.terminal.tabBarFontSize.points": "product and brand names", + "settings.textBox.submitAction.claude": "product and brand names", + "settings.textBox.submitAction.codex": "product and brand names", + "settings.textBox.submitAction.opencode": "product and brand names", + "settings.textBox.submitAction.pi": "product and brand names", + "shortcut.recorder.pendingChord": "product and brand names", + "sidebar.help.discord": "product and brand names", + "sidebar.help.feedback.emailPlaceholder": "product and brand names", + "sidebar.help.githubIssues": "product and brand names", + "sidebar.port.label": "product and brand names", + "sidebar.provider.default.subtitle": "product and brand names", + "sidebar.remote.badge": "product and brand names", + "sidebar.tree.group.remote.subtitle": "product and brand names", + "simulator.action.siri": "technical acronyms and identifiers", + "simulator.appearance.voiceOver": "technical acronyms and identifiers", + "simulator.application.reactNative": "product and brand names", + "simulator.dataNetwork.fiveG": "technical acronyms and identifiers", + "simulator.dataNetwork.fiveGPlus": "technical acronyms and identifiers", + "simulator.dataNetwork.fiveGUC": "technical acronyms and identifiers", + "simulator.dataNetwork.fiveGUWB": "technical acronyms and identifiers", + "simulator.dataNetwork.fourG": "product and brand names", + "simulator.dataNetwork.lte": "technical acronyms and identifiers", + "simulator.dataNetwork.lteAdvanced": "product and brand names", + "simulator.dataNetwork.ltePlus": "product and brand names", + "simulator.dataNetwork.threeG": "product and brand names", + "simulator.dataNetwork.wifi": "technical acronyms and identifiers", + "simulator.device.udid": "technical acronyms and identifiers", + "simulator.field.url": "technical acronyms and identifiers", + "simulator.privacy.faceID": "technical acronyms and identifiers", + "simulator.privacy.homeKit": "technical acronyms and identifiers", + "simulator.privacy.siri": "technical acronyms and identifiers", + "simulator.statusBar.wifiMode": "technical acronyms and identifiers", + "sleepyMode.glow.cmux": "product and brand names", + "sleepyMode.theme.cmux": "product and brand names", + "statusMenu.profiling.emailPlaceholder": "product and brand names", + "taskManager.agent.amp": "product and brand names", + "taskManager.agent.claudeCode": "product and brand names", + "taskManager.agent.codebuddy": "product and brand names", + "taskManager.agent.codex": "product and brand names", + "taskManager.agent.copilot": "product and brand names", + "taskManager.agent.cursor": "product and brand names", + "taskManager.agent.factory": "product and brand names", + "taskManager.agent.gemini": "product and brand names", + "taskManager.agent.grok": "product and brand names", + "taskManager.agent.hermesAgent": "product and brand names", + "taskManager.agent.opencode": "product and brand names", + "taskManager.agent.pi": "product and brand names", + "taskManager.agent.qoder": "product and brand names", + "taskManager.agent.rovodev": "product and brand names", + "taskManager.column.cpu": "technical acronyms and identifiers", + "taskManager.killProcess.target.pid": "product and brand names", + "taskManager.row.pid": "product and brand names", + "taskManager.row.webview": "technical acronyms and identifiers", + "taskManager.summary.cpu": "technical acronyms and identifiers", + "textbox.submitAction.claude": "product and brand names", + "textbox.submitAction.codex": "product and brand names", + "textbox.submitAction.opencode": "product and brand names", + "textbox.submitAction.pi": "product and brand names", + "workspace.cloudVM.defaultTitle": "product and brand names" +} diff --git a/scripts/localization-plurals.json b/scripts/localization-plurals.json new file mode 100644 index 000000000000..7b920fd0ff8e --- /dev/null +++ b/scripts/localization-plurals.json @@ -0,0 +1,43 @@ +{ + "browser.profile.automation.error.profileInUse": {}, + "browser.screenshot.error.renderedContentMismatch": {}, + "cli.localTmux.output.foundStale": {}, + "cli.localTmux.output.removedStale": {}, + "cli.localTmux.output.sessionRow": {}, + "cli.localTmux.output.status": {}, + "cli.memory.output.processCount.other": {}, + "cli.sshPtyAttach.noProgressRetryLimitReached.other": {}, + "cli.vm.list.planMeter.unlimited": {}, + "cli.vm.list.planMeter": {}, + "cli.vm.list.planMeter.single": {}, + "cli.vm.tree.localSummary": {}, + "dialog.saveWorkspaceLayout.skippedNote": {}, + "feed.textEditorDebug.metrics": {}, + "fileExplorer.search.limit": {}, + "fileExplorer.search.matches": {}, + "fileExplorer.search.searching": {}, + "machines.empty.planIncludes": {}, + "machines.empty.upgrade": {}, + "machines.freeAccess.help": {}, + "machines.meter.count": {}, + "machines.meter.count.unlimited": {}, + "machines.meter.count.single": {}, + "machines.meter.help.atLimit": {}, + "machines.row.daysLeft": {}, + "memory.attribution.multipleWorkspaces": {}, + "menu.history.recentlyClosed.window.workspaceCount": {}, + "menu.history.recentlyClosed.window.workspaceCount.other": {}, + "notifications.forwardToPhone.mode.subtitle": {}, + "remoteTmux.error.controlSocketPathTooLong": {}, + "settings.cloudMachines.plan.summary.unlimited": {}, + "settings.cloudMachines.plan.summary": {}, + "statusMenu.profiling.bodyFormat": {}, + "statusMenu.profiling.remainingFormat": {}, + "taskManager.aggregate.processCount.other": {}, + "taskManager.killProcess.message.other": {}, + "machines.new.plan.single": {}, + "machines.new.plan.unlimited": {}, + "machines.new.plan.multi": {}, + "machines.new.plan.freeWindow": {}, + "cloudTree.deleteWorkspace.message.other": {} +} diff --git a/scripts/localization_catalog.py b/scripts/localization_catalog.py new file mode 100644 index 000000000000..de17259f9048 --- /dev/null +++ b/scripts/localization_catalog.py @@ -0,0 +1,347 @@ +#!/usr/bin/env python3 +"""Audit and update the macOS XCStrings catalogs without losing Xcode ordering.""" + +from __future__ import annotations + +import argparse +import json +import re +import sys +from pathlib import Path +from typing import Any, Iterable + + +TARGET_LOCALES = ("de", "fr", "ar", "es", "zh-Hant", "zh-Hans", "ko", "ja") +CATALOGS = ( + "Resources/Localizable.xcstrings", + "Resources/InfoPlist.xcstrings", + "Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Resources/Localizable.xcstrings", + "Packages/macOS/CmuxFeedback/Sources/CmuxFeedback/ComposerUI/Resources/Localizable.xcstrings", + "Packages/macOS/CmuxSwiftRenderUI/Sources/CmuxSwiftRenderUI/Resources/Localizable.xcstrings", + "TunnelExtension/InfoPlist.xcstrings", +) +OMISSIONS_PATH = Path(__file__).with_name("localization-allowed-omissions.json") +PLURALS_PATH = Path(__file__).with_name("localization-plurals.json") +PLACEHOLDER_RE = re.compile( + r"%(?:(?:\d+\$)?[-+0 #]*\d*(?:\.\d+)?(?:hh|h|ll|l|L|z|t|j)?[diouxXeEfFgGcsSpaA@]|%)" +) +MACHINE_MARKER_RE = re.compile(r"(?:TODO|TRANSLATE|MACHINE_TRANSLATION||\[translation\])", re.I) + + +class ObjectPairs(list): + """A JSON object represented as ordered pairs, including duplicate keys.""" + + +def _pairs_hook(pairs: list[tuple[str, Any]]) -> ObjectPairs: + return ObjectPairs(pairs) + + +def _load_pairs(path: Path) -> ObjectPairs: + return json.loads(path.read_text(encoding="utf-8"), object_pairs_hook=_pairs_hook) + + +def _load_plain(path: Path) -> dict[str, Any]: + return json.loads(path.read_text(encoding="utf-8")) + + +def _dump_value(value: Any, level: int = 0) -> str: + indent = " " * level + child_indent = " " * (level + 1) + if isinstance(value, ObjectPairs): + if not value: + return "{}" + lines = ["{"] + for index, (key, item) in enumerate(value): + suffix = "," if index + 1 < len(value) else "" + lines.append(f"{child_indent}{json.dumps(key, ensure_ascii=False)}: {_dump_value(item, level + 1)}{suffix}") + lines.append(f"{indent}}}") + return "\n".join(lines) + if isinstance(value, list): + if not value: + return "[]" + lines = ["["] + for index, item in enumerate(value): + suffix = "," if index + 1 < len(value) else "" + lines.append(f"{child_indent}{_dump_value(item, level + 1)}{suffix}") + lines.append(f"{indent}]") + return "\n".join(lines) + return json.dumps(value, ensure_ascii=False) + + +def _write_pairs(path: Path, value: ObjectPairs) -> None: + path.write_text(_dump_value(value) + "\n", encoding="utf-8") + + +def _get(obj: ObjectPairs, key: str, default: Any = None) -> Any: + for candidate, value in reversed(obj): + if candidate == key: + return value + return default + + +def _get_pair(obj: ObjectPairs, key: str) -> tuple[int, Any] | None: + for index in range(len(obj) - 1, -1, -1): + if obj[index][0] == key: + return index, obj[index][1] + return None + + +def _set(obj: ObjectPairs, key: str, value: Any) -> None: + pair = _get_pair(obj, key) + if pair is None: + obj.append((key, value)) + else: + obj[pair[0]] = (key, value) + + +def _plain(value: Any) -> Any: + if isinstance(value, ObjectPairs): + result: dict[str, Any] = {} + for key, item in value: + result[key] = _plain(item) + return result + if isinstance(value, list): + return [_plain(item) for item in value] + return value + + +def _source(entry: dict[str, Any]) -> str: + return entry.get("localizations", {}).get("en", {}).get("stringUnit", {}).get("value", "") + + +def _placeholders(value: str) -> list[str]: + return PLACEHOLDER_RE.findall(value) + + +def _locale_unit(entry: dict[str, Any], locale: str) -> dict[str, Any] | None: + return entry.get("localizations", {}).get(locale, {}).get("stringUnit") + + +def _allowed_omissions() -> dict[str, str]: + if not OMISSIONS_PATH.exists(): + return {} + data = json.loads(OMISSIONS_PATH.read_text(encoding="utf-8")) + return {str(key): str(value) for key, value in data.items()} + + +def _plural_keys() -> set[str]: + if not PLURALS_PATH.exists(): + return set() + data = json.loads(PLURALS_PATH.read_text(encoding="utf-8")) + return {str(key) for key in data} + + +def _entry_rows(path: Path) -> Iterable[tuple[str, dict[str, Any]]]: + data = _load_plain(path) + for key, entry in data.get("strings", {}).items(): + yield key, entry + + +def _catalog_paths(args: argparse.Namespace) -> list[Path]: + if args.catalog: + return [Path(item) for item in args.catalog] + return [Path(item) for item in CATALOGS] + + +def command_extract(args: argparse.Namespace) -> int: + path = Path(args.catalog) + rows = [] + for key, entry in _entry_rows(path): + unit = _locale_unit(entry, args.locale) + if unit and unit.get("state") == "translated": + continue + source = _source(entry) + rows.append( + { + "key": key, + "source": source, + "comment": entry.get("comment"), + "placeholders": _placeholders(source), + } + ) + start = args.batch * args.batch_size + selected = rows[start : start + args.batch_size] + payload = {"catalog": str(path), "locale": args.locale, "batch": args.batch, "total": len(rows), "entries": selected} + output = json.dumps(payload, ensure_ascii=False, indent=2) + "\n" + if args.output: + Path(args.output).write_text(output, encoding="utf-8") + else: + print(output, end="") + return 0 + + +def _localized_object(value: str, plural: dict[str, str] | None = None) -> ObjectPairs: + unit = ObjectPairs([("state", "translated"), ("value", value)]) + pairs: list[tuple[str, Any]] = [("stringUnit", unit)] + if plural: + variations = ObjectPairs( + [ + ( + "plural", + ObjectPairs( + [ + (category, ObjectPairs([("stringUnit", ObjectPairs([("state", "translated"), ("value", text)]))])) + for category, text in plural.items() + ] + ), + ) + ] + ) + pairs.append(("variations", variations)) + return ObjectPairs(pairs) + + +def _merge_localization(entry: ObjectPairs, locale: str, value: str, plural: dict[str, str] | None) -> None: + localizations = _get(entry, "localizations") + if not isinstance(localizations, ObjectPairs): + localizations = ObjectPairs() + _set(entry, "localizations", localizations) + localization = _get(localizations, locale) + if not isinstance(localization, ObjectPairs): + _set(localizations, locale, _localized_object(value, plural)) + return + string_unit = _get(localization, "stringUnit") + if not isinstance(string_unit, ObjectPairs): + string_unit = ObjectPairs() + _set(localization, "stringUnit", string_unit) + _set(string_unit, "state", "translated") + _set(string_unit, "value", value) + if plural: + _set( + localization, + "variations", + _localized_object("", plural)[1][1], + ) + + +def _merge_entry_pairs(data: ObjectPairs, locale: str, translations: dict[str, dict[str, Any]]) -> set[str]: + strings = _get(data, "strings") + if not isinstance(strings, ObjectPairs): + raise ValueError("catalog has no strings object") + seen: set[str] = set() + for key, entry in strings: + if key not in translations or not isinstance(entry, ObjectPairs): + continue + item = translations[key] + if item.get("omit"): + localizations = _get(entry, "localizations") + if isinstance(localizations, ObjectPairs): + localizations[:] = [(name, value) for name, value in localizations if name != locale] + else: + value = item.get("value") + if not isinstance(value, str): + raise ValueError(f"translation for {key} must have a string value") + _merge_localization(entry, locale, value, item.get("plural")) + seen.add(key) + return seen + + +def command_merge(args: argparse.Namespace) -> int: + path = Path(args.catalog) + payload = json.loads(Path(args.input).read_text(encoding="utf-8")) + if isinstance(payload, dict) and "translations" in payload: + payload = payload["translations"] + if isinstance(payload, list): + translations = {item["key"]: item for item in payload} + elif isinstance(payload, dict): + translations = {key: (item if isinstance(item, dict) else {"value": item}) for key, item in payload.items()} + else: + raise ValueError("translation input must be a list or object") + data = _load_pairs(path) + merged = _merge_entry_pairs(data, args.locale, translations) + missing = set(translations) - merged + if missing: + raise ValueError(f"translation keys not found in {path}: {', '.join(sorted(missing)[:5])}") + _write_pairs(path, data) + print(f"merged {len(merged)} {args.locale} translations into {path}") + return 0 + + +def _check_entry(path: Path, key: str, entry: dict[str, Any], locale: str, omissions: dict[str, str]) -> list[str]: + errors: list[str] = [] + source = _source(entry) + source_placeholders = _placeholders(source) + unit = _locale_unit(entry, locale) + allowed = locale != "ja" and path.resolve() == Path("Resources/Localizable.xcstrings").resolve() and key in omissions + if unit is None: + if not allowed: + errors.append(f"{path}:{key}: missing {locale} entry") + return errors + if unit.get("state") != "translated": + errors.append(f"{path}:{key}: {locale} state is {unit.get('state')!r}") + value = unit.get("value") + if not isinstance(value, str) or not value.strip(): + errors.append(f"{path}:{key}: {locale} value is empty") + return errors + if _placeholders(value) != source_placeholders: + errors.append(f"{path}:{key}: {locale} placeholders {_placeholders(value)!r} != {source_placeholders!r}") + if value == source and not allowed: + errors.append(f"{path}:{key}: {locale} copies English") + if MACHINE_MARKER_RE.search(value): + errors.append(f"{path}:{key}: {locale} contains a machine marker") + return errors + + +def command_check(args: argparse.Namespace) -> int: + omissions = _allowed_omissions() + plural_keys = _plural_keys() + errors: list[str] = [] + for path in _catalog_paths(args): + try: + data = _load_plain(path) + except (OSError, json.JSONDecodeError) as exc: + errors.append(f"{path}: invalid JSON: {exc}") + continue + strings = data.get("strings") + if not isinstance(strings, dict): + errors.append(f"{path}: missing strings object") + continue + for locale in TARGET_LOCALES: + for key, entry in strings.items(): + errors.extend(_check_entry(path, key, entry, locale, omissions)) + if key in plural_keys: + localization = entry.get("localizations", {}).get(locale, {}) + plural = localization.get("variations", {}).get("plural", {}) + required_categories = {"zero", "one", "two", "few", "many", "other"} if locale == "ar" else {"one", "other"} + missing_categories = required_categories - set(plural) + if missing_categories: + errors.append(f"{path}:{key}: {locale} missing plural categories {sorted(missing_categories)}") + if errors: + print("\n".join(errors), file=sys.stderr) + print(f"localization check failed: {len(errors)} error(s)", file=sys.stderr) + return 1 + print(f"localization check passed: {len(_catalog_paths(args))} catalogs, {len(TARGET_LOCALES)} locales") + return 0 + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description=__doc__) + subparsers = parser.add_subparsers(dest="command", required=True) + + extract = subparsers.add_parser("extract", help="extract one locale's unfinished entries") + extract.add_argument("--catalog", required=True) + extract.add_argument("--locale", required=True, choices=TARGET_LOCALES) + extract.add_argument("--batch", type=int, default=0) + extract.add_argument("--batch-size", type=int, default=100) + extract.add_argument("--output") + extract.set_defaults(function=command_extract) + + merge = subparsers.add_parser("merge", help="merge translated values into a catalog") + merge.add_argument("--catalog", required=True) + merge.add_argument("--locale", required=True, choices=TARGET_LOCALES) + merge.add_argument("--input", required=True) + merge.set_defaults(function=command_merge) + + check = subparsers.add_parser("check", help="validate macOS catalog parity") + check.add_argument("--catalog", action="append") + check.set_defaults(function=command_check) + return parser + + +if __name__ == "__main__": + try: + parsed_args = build_parser().parse_args() + raise SystemExit(parsed_args.function(parsed_args)) + except (OSError, ValueError, json.JSONDecodeError) as exc: + print(f"error: {exc}", file=sys.stderr) + raise SystemExit(2) diff --git a/skills/cmux-localization/SKILL.md b/skills/cmux-localization/SKILL.md index d851f47cdc79..8e5d6677a04c 100644 --- a/skills/cmux-localization/SKILL.md +++ b/skills/cmux-localization/SKILL.md @@ -10,7 +10,7 @@ Use this skill for any user-facing string change. ## Hard rules - Every user-facing string is localized. Never a bare string literal in SwiftUI `Text()`, `Button()`, alert titles, tooltips, menus, or dialogs. -- Swift/AppKit/SwiftUI: `String(localized: "key.name", defaultValue: "English text")`, with keys in `Resources/Localizable.xcstrings`. Feature PRs add the key and English source value; translations for every supported language are completed in the release PR. +- Swift/AppKit/SwiftUI: `String(localized: "key.name", defaultValue: "English text")`, with keys in `Resources/Localizable.xcstrings`. Feature PRs add the key and English source value; translations for every supported macOS language (`en`, `de`, `fr`, `ar`, `es`, `zh-Hant`, `zh-Hans`, `ko`, `ja`) are completed in the same release PR. - `defaultValue`, English fallback text, schema descriptions, and copied English strings do not count as localization. They are acceptable in feature PRs only when the release workflow tracks the key for translation. - Localized web/docs content updates every supported message catalog (currently `web/messages/en.json` and `web/messages/ja.json`) plus any localized data structures carrying inline translations. - A localization audit is required for every user-facing change. @@ -20,11 +20,13 @@ Use this skill for any user-facing string change. Before finishing a task that changes UI, Settings rows, menus, shortcut metadata, schema/config text, docs, command/help text, alerts, or tooltips: 1. Enumerate the changed user-facing surfaces. -2. Verify each surface has a catalog key in the feature PR. Verify translated values for every supported locale in the release PR. +2. Verify each surface has a catalog key in the feature PR. Verify translated values for every supported macOS locale (`en`, `de`, `fr`, `ar`, `es`, `zh-Hant`, `zh-Hans`, `ko`, `ja`) in the release PR. 3. Parse the touched localization files and compare changed message keys across locales. 4. Run `rg` over changed Swift/TS/TSX/docs files for newly introduced bare English. 5. State in the final handoff what audit was performed, or explicitly say what could not be verified. +`Resources/Localizable.xcstrings`, `Resources/InfoPlist.xcstrings`, and the linked macOS package catalogs must pass `python3 scripts/localization_catalog.py check`. New keys must carry all nine macOS locale entries, preserve printf placeholders, and use plural variations for count strings where the source has a count. + ## Detailed reference - [references/audit-workflow.md](references/audit-workflow.md): what counts as user-facing, search patterns, and handoff wording. From 21e682b0697e678ceebc1a0f98b218ccae23aab7 Mon Sep 17 00:00:00 2001 From: Austin Wang Date: Tue, 8 Sep 2026 06:38:54 -0700 Subject: [PATCH 02/50] Preserve catalog formatting and record translation metadata --- .github/workflows/ci.yml | 3 + .../Resources/Localizable.xcstrings | 18 + Resources/InfoPlist.xcstrings | 108 ++ scripts/localization-allowed-omissions.json | 951 ++++++++++++++---- scripts/localization-plurals.json | 254 ++++- scripts/localization_catalog.py | 604 ++++++----- tests/test_localization_catalog.py | 73 ++ 7 files changed, 1469 insertions(+), 542 deletions(-) create mode 100644 tests/test_localization_catalog.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 151f06e4d528..16a16ada3d5e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -159,6 +159,9 @@ jobs: - name: Validate macOS localization parity run: python3 scripts/localization_catalog.py check + - name: Test macOS localization catalog tooling + run: python3 tests/test_localization_catalog.py + - name: Validate TUI npm package artifact transfer run: python3 tests/test_tui_npm_package_artifact.py diff --git a/Packages/macOS/CmuxSwiftRenderUI/Sources/CmuxSwiftRenderUI/Resources/Localizable.xcstrings b/Packages/macOS/CmuxSwiftRenderUI/Sources/CmuxSwiftRenderUI/Resources/Localizable.xcstrings index 9483924c4bb5..f9dacc3b43ee 100644 --- a/Packages/macOS/CmuxSwiftRenderUI/Sources/CmuxSwiftRenderUI/Resources/Localizable.xcstrings +++ b/Packages/macOS/CmuxSwiftRenderUI/Sources/CmuxSwiftRenderUI/Resources/Localizable.xcstrings @@ -15,6 +15,12 @@ "state": "translated", "value": "サイドバーエラー" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "侧边栏错误" + } } } }, @@ -32,6 +38,12 @@ "state": "translated", "value": "サイドバーファイルが空か見つかりません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "侧边栏文件为空或缺失。" + } } } }, @@ -49,6 +61,12 @@ "state": "translated", "value": "対応するSwiftUIビューが見つかりません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到受支持的 SwiftUI 视图。" + } } } } diff --git a/Resources/InfoPlist.xcstrings b/Resources/InfoPlist.xcstrings index ccd53cb975ae..36346867d497 100644 --- a/Resources/InfoPlist.xcstrings +++ b/Resources/InfoPlist.xcstrings @@ -16,6 +16,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムがほかのアプリのバンドル内容へのアクセスを求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要访问其他应用的内容。" + } } } }, @@ -33,6 +39,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムがほかのアプリのデータへのアクセスを求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要访问其他应用的数据。" + } } } }, @@ -50,6 +62,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムが AppleScript の使用を求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要使用 AppleScript。" + } } } }, @@ -67,6 +85,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムが、パスキーとセキュリティキーを検出するために Bluetooth の使用を求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要使用蓝牙来发现通行密钥和安全密钥。" + } } } }, @@ -84,6 +108,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムがカレンダーの読み書きへのアクセスを求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要读取和写入您的日历。" + } } } }, @@ -101,6 +131,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムがカレンダーへのイベントの追加を求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要向您的日历中添加事件。" + } } } }, @@ -118,6 +154,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムがカメラの使用を求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要使用您的摄像头。" + } } } }, @@ -135,6 +177,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムがデスクトップフォルダ内のファイルへのアクセスを求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要访问您「桌面」文件夹中的文件。" + } } } }, @@ -152,6 +200,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムが書類フォルダ内のファイルへのアクセスを求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要访问您「文稿」文件夹中的文件。" + } } } }, @@ -169,6 +223,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムがダウンロードフォルダ内のファイルへのアクセスを求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要访问您「下载」文件夹中的文件。" + } } } }, @@ -186,6 +246,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムがファイルプロバイダによって管理されているファイルへのアクセスを求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要访问由文件提供程序管理的文件。" + } } } }, @@ -220,6 +286,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムが位置情報へのアクセスを求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要访问您的位置信息。" + } } } }, @@ -350,6 +422,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムがモーションデータへのアクセスを求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要访问运动数据。" + } } } }, @@ -367,6 +445,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムがネットワークボリューム上のファイルへのアクセスを求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要访问网络宗卷上的文件。" + } } } }, @@ -384,6 +468,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムがリマインダーの読み書きへのアクセスを求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要读取和写入您的提醒事项。" + } } } }, @@ -401,6 +491,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムがリムーバブルボリューム上のファイルへのアクセスを求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要访问可移除宗卷上的文件。" + } } } }, @@ -418,6 +514,12 @@ "state": "translated", "value": "cmux 内で実行中のプログラムが音声認識の使用を求めています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 cmux 中运行的程序想要使用语音识别。" + } } } }, @@ -1808,6 +1910,12 @@ "state": "translated", "value": "cmux はこの Mac からプライベートネットワーク上のクラウドマシンに到達できるように、ネットワーク機能拡張をインストールします。機能拡張は cmux Cloud を使用している間だけ動作します。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux 会安装一个网络扩展,让这台 Mac 能够通过专用网络访问您的云端机器。它仅在您使用 cmux Cloud 期间运行。" + } } } } diff --git a/scripts/localization-allowed-omissions.json b/scripts/localization-allowed-omissions.json index 7368fdb5930c..e5d0f95ff394 100644 --- a/scripts/localization-allowed-omissions.json +++ b/scripts/localization-allowed-omissions.json @@ -1,185 +1,770 @@ { - "agent.hermes.notification.body.approvalCommand": "price and plan literals", - "agent.kimi.displayName": "product and brand names", - "agent.ollama.displayName": "product and brand names", - "browser.designMode.copy.shortcut": "format-only strings or CLI syntax fragments", - "browser.import.complete.profileMapping": "product and brand names", - "cli.browser.designMode.help": "CLI syntax fragments", - "cli.browser.help.viewportUsage": "CLI syntax fragments", - "cli.browser.profile.option": "CLI syntax fragments", - "cli.claude-hook.notification.title": "product and brand names", - "cli.help.ios": "CLI syntax fragments", - "cli.help.simulator": "CLI syntax fragments", - "cli.sidebar.report.ok": "product and brand names", - "command.cloudVM.restore.prompt.placeholder": "product and brand names", - "command.cloudVM.result.title": "product and brand names", - "command.cmuxConfig.builtInSubtitle": "product and brand names", - "command.cmuxConfig.defaultClaudeCodeTitle": "product and brand names", - "command.cmuxConfig.defaultCodexTitle": "product and brand names", - "command.cmuxConfig.defaultOpenCodeTitle": "product and brand names", - "command.cmuxConfig.issue.schemaError.detail": "format-only strings or CLI syntax fragments", - "command.cmuxConfig.issue.subtitle": "product and brand names", - "command.toggleSetting.subtitle": "product and brand names", - "commandPalette.kind.cloudVMLoading": "product and brand names", - "commandPalette.kind.markdown": "product and brand names", - "commandPalette.subtitle.markdownWithName": "product and brand names", - "debug.bonsplitTabBarDebug.pixelsValue": "product and brand names", - "debug.tabBarBackdropLab.leftSidebar": "product and brand names", - "debug.tabBarBackdropLab.rightSidebar": "product and brand names", - "debug.tabBarBackdropLab.terminal.prompt": "product and brand names", - "debug.tabBarBackdropLab.titlebarSample": "product and brand names", - "dock.source.error": "product and brand names", - "dock.source.title": "product and brand names", - "feed.exitplan.mode.ultraplan": "product and brand names", - "feed.exitplan.ultraplan": "product and brand names", - "feed.notification.exitPlan.ultraplan": "product and brand names", - "feed.textEditorDebug.section.appkit": "product and brand names", - "feed.textEditorDebug.section.swiftui": "product and brand names", - "feed.textEditorDebug.variant.swiftUIMirror": "product and brand names", - "feed.textEditorDebug.variant.swiftUITextField": "product and brand names", - "globalSearch.kind.markdown": "product and brand names", - "markdown.fontSize.unit": "product and brand names", - "markdown.maxWidth.unit": "product and brand names", - "menu.help.claudeCodeTeams": "product and brand names", - "menu.help.dock": "product and brand names", - "menu.help.ohMyClaudeCode": "product and brand names", - "menu.help.ohMyCodex": "product and brand names", - "menu.help.ohMyOpenCode": "product and brand names", - "menu.help.ssh": "product and brand names", - "menu.history.recentlyClosed.panel.cloudVM": "product and brand names", - "paneMemoryGuardrail.banner.detail": "price and plan literals", - "panel.cloudVM.loading.title": "product and brand names", - "pricing.enterprise.f3": "technical acronyms and identifiers", - "pricing.native.compare.concurrent.free": "product and brand names", - "pricing.native.eyebrow": "product and brand names", - "pricing.native.free.price": "price and plan literals", - "pricing.native.metric.vm.value": "price and plan literals", - "pricing.native.plan.pro": "product and brand names", - "pricing.native.size.large.rate": "price and plan literals", - "pricing.native.size.medium.rate": "price and plan literals", - "pricing.native.size.small.rate": "price and plan literals", - "pricing.pro.name": "product and brand names", - "pricing.pro.workspace.title": "product and brand names", - "pricing.window.title": "product and brand names", - "rightSidebar.mode.dock": "product and brand names", - "rightSidebar.mode.feed": "product and brand names", - "rightSidebar.mode.sessions": "product and brand names", - "sessionIndex.agent.claude": "product and brand names", - "sessionIndex.agent.codex": "product and brand names", - "sessionIndex.agent.grok": "product and brand names", - "sessionIndex.agent.opencode": "product and brand names", - "sessionIndex.agent.pi": "product and brand names", - "sessionIndex.agent.rovodev": "product and brand names", - "settings.account.pro.title": "product and brand names", - "settings.betaFeatures.dock": "product and brand names", - "settings.betaFeatures.feed": "product and brand names", - "settings.config.source.cmux": "product and brand names", - "settings.fontSize.valuePoints": "product and brand names", - "settings.mobile.route.iroh": "product and brand names", - "settings.mobile.route.tailscale": "product and brand names", - "settings.mobile.route.websocket": "product and brand names", - "settings.networking.custom.summary": "price and plan literals", - "settings.notifications.command.placeholder": "product and brand names", - "settings.search.alias.section.customSidebars": "product and brand names", - "settings.search.alias.section.mobile": "product and brand names", - "settings.search.alias.section.networking": "product and brand names", - "settings.search.alias.section.sleepyMode": "product and brand names", - "settings.search.alias.setting.app.canvas-pane-gap": "product and brand names", - "settings.search.alias.setting.app.canvas-snapping": "product and brand names", - "settings.search.alias.setting.app.default-terminal": "product and brand names", - "settings.search.alias.setting.app.file-editor-word-wrap": "product and brand names", - "settings.search.alias.setting.app.markdown-font-family": "product and brand names", - "settings.search.alias.setting.app.markdown-font-size": "product and brand names", - "settings.search.alias.setting.app.markdown-max-width": "product and brand names", - "settings.search.alias.setting.app.show-workspace-description": "product and brand names", - "settings.search.alias.setting.app.supported-file-previews": "product and brand names", - "settings.search.alias.setting.app.warn-before-closing-tab": "product and brand names", - "settings.search.alias.setting.app.workspace-inherit-working-directory": "product and brand names", - "settings.search.alias.setting.automation.kiro": "product and brand names", - "settings.search.alias.setting.automation.kiro-notification-level": "product and brand names", - "settings.search.alias.setting.automation.ripgrep-path": "product and brand names", - "settings.search.alias.setting.betaFeatures.workspace-todo-controls": "product and brand names", - "settings.search.alias.setting.betaFeatures.workspace-todos-checklist-style": "product and brand names", - "settings.search.alias.setting.browser.ask-where-to-save-downloads": "product and brand names", - "settings.search.alias.setting.browser.hidden-webview-discard": "product and brand names", - "settings.search.alias.setting.browser.hidden-webview-discard-delay": "product and brand names", - "settings.search.alias.setting.mobile.artifactFolderAccess": "product and brand names", - "settings.search.alias.setting.mobile.iOSPairingDisplayName": "product and brand names", - "settings.search.alias.setting.mobile.iOSPairingHost": "product and brand names", - "settings.search.alias.setting.mobile.iOSPairingPort": "product and brand names", - "settings.search.alias.setting.networking.customRelays": "product and brand names", - "settings.search.alias.setting.networking.policy": "product and brand names", - "settings.search.alias.setting.networking.privateNetworks": "product and brand names", - "settings.search.alias.setting.networking.relayPreference": "product and brand names", - "settings.search.alias.setting.networking.status": "product and brand names", - "settings.search.alias.setting.networking.tailscaleCompatibility": "product and brand names", - "settings.search.alias.setting.sidebarAppearance.font-size": "product and brand names", - "settings.search.alias.setting.terminal.resume-commands": "product and brand names", - "settings.search.alias.setting.terminal.session-content-alignment": "product and brand names", - "settings.search.alias.setting.terminal.session-content-width": "product and brand names", - "settings.search.alias.setting.terminal.tab-bar-font-size": "product and brand names", - "settings.search.alias.setting.textBox.default-submit-action": "product and brand names", - "settings.section.settingsJSON": "product and brand names", - "settings.sidebarAppearance.fontSize.points": "product and brand names", - "settings.terminal.scrollSpeed.value": "format-only strings or CLI syntax fragments", - "settings.terminal.sessionContentWidth.unit": "product and brand names", - "settings.terminal.tabBarFontSize.points": "product and brand names", - "settings.textBox.submitAction.claude": "product and brand names", - "settings.textBox.submitAction.codex": "product and brand names", - "settings.textBox.submitAction.opencode": "product and brand names", - "settings.textBox.submitAction.pi": "product and brand names", - "shortcut.recorder.pendingChord": "product and brand names", - "sidebar.help.discord": "product and brand names", - "sidebar.help.feedback.emailPlaceholder": "product and brand names", - "sidebar.help.githubIssues": "product and brand names", - "sidebar.port.label": "product and brand names", - "sidebar.provider.default.subtitle": "product and brand names", - "sidebar.remote.badge": "product and brand names", - "sidebar.tree.group.remote.subtitle": "product and brand names", - "simulator.action.siri": "technical acronyms and identifiers", - "simulator.appearance.voiceOver": "technical acronyms and identifiers", - "simulator.application.reactNative": "product and brand names", - "simulator.dataNetwork.fiveG": "technical acronyms and identifiers", - "simulator.dataNetwork.fiveGPlus": "technical acronyms and identifiers", - "simulator.dataNetwork.fiveGUC": "technical acronyms and identifiers", - "simulator.dataNetwork.fiveGUWB": "technical acronyms and identifiers", - "simulator.dataNetwork.fourG": "product and brand names", - "simulator.dataNetwork.lte": "technical acronyms and identifiers", - "simulator.dataNetwork.lteAdvanced": "product and brand names", - "simulator.dataNetwork.ltePlus": "product and brand names", - "simulator.dataNetwork.threeG": "product and brand names", - "simulator.dataNetwork.wifi": "technical acronyms and identifiers", - "simulator.device.udid": "technical acronyms and identifiers", - "simulator.field.url": "technical acronyms and identifiers", - "simulator.privacy.faceID": "technical acronyms and identifiers", - "simulator.privacy.homeKit": "technical acronyms and identifiers", - "simulator.privacy.siri": "technical acronyms and identifiers", - "simulator.statusBar.wifiMode": "technical acronyms and identifiers", - "sleepyMode.glow.cmux": "product and brand names", - "sleepyMode.theme.cmux": "product and brand names", - "statusMenu.profiling.emailPlaceholder": "product and brand names", - "taskManager.agent.amp": "product and brand names", - "taskManager.agent.claudeCode": "product and brand names", - "taskManager.agent.codebuddy": "product and brand names", - "taskManager.agent.codex": "product and brand names", - "taskManager.agent.copilot": "product and brand names", - "taskManager.agent.cursor": "product and brand names", - "taskManager.agent.factory": "product and brand names", - "taskManager.agent.gemini": "product and brand names", - "taskManager.agent.grok": "product and brand names", - "taskManager.agent.hermesAgent": "product and brand names", - "taskManager.agent.opencode": "product and brand names", - "taskManager.agent.pi": "product and brand names", - "taskManager.agent.qoder": "product and brand names", - "taskManager.agent.rovodev": "product and brand names", - "taskManager.column.cpu": "technical acronyms and identifiers", - "taskManager.killProcess.target.pid": "product and brand names", - "taskManager.row.pid": "product and brand names", - "taskManager.row.webview": "technical acronyms and identifiers", - "taskManager.summary.cpu": "technical acronyms and identifiers", - "textbox.submitAction.claude": "product and brand names", - "textbox.submitAction.codex": "product and brand names", - "textbox.submitAction.opencode": "product and brand names", - "textbox.submitAction.pi": "product and brand names", - "workspace.cloudVM.defaultTitle": "product and brand names" + "cli.usage.readScreen": { + "class": "syntax", + "source": "read-screen [--workspace ] [--surface ] [--window ] [--scrollback] [--lines ] [--selection]" + }, + "cli.usage.readSelection": { + "class": "syntax", + "source": "read-selection [--workspace ] [--surface ] [--window ]" + }, + "about.appName": { + "class": "brand", + "source": "cmux" + }, + "cli.codexMonitor.notification.title": { + "class": "syntax", + "source": "Codex" + }, + "agent.hermes.notification.body.approvalCommand": { + "class": "format", + "source": "%1$@: %2$@" + }, + "agent.kimi.displayName": { + "class": "brand", + "source": "Kimi Code" + }, + "agent.ollama.displayName": { + "class": "brand", + "source": "Ollama" + }, + "agentSession.provider.claude": { + "class": "brand", + "source": "Claude Code" + }, + "agentSession.provider.codex": { + "class": "brand", + "source": "Codex" + }, + "agentSession.provider.opencode": { + "class": "brand", + "source": "OpenCode" + }, + "agentSession.renderer.react": { + "class": "brand", + "source": "React" + }, + "agentSession.renderer.solid": { + "class": "brand", + "source": "Solid" + }, + "agentSession.web.planSuggestion.shortcut": { + "class": "brand", + "source": "Shift + Tab" + }, + "browser.designMode.copy.shortcut": { + "class": "format", + "source": "⌘↩" + }, + "browser.dialog.clientCertificate.titleWithSubtitle": { + "class": "format", + "source": "%@ (%@)" + }, + "browser.focusMode.helpWithShortcut.format": { + "class": "format", + "source": "%@ (%@)" + }, + "browser.import.complete.profileMapping": { + "class": "format", + "source": "%@ -> %@" + }, + "cli.browser.designMode.help": { + "class": "syntax", + "source": "browser design-mode enable|disable|toggle|status [--surface ]" + }, + "cli.browser.help.viewportUsage": { + "class": "syntax", + "source": "viewport | reset" + }, + "cli.browser.profile.option": { + "class": "syntax", + "source": "[--profile ]" + }, + "cli.claude-hook.notification.title": { + "class": "brand", + "source": "Claude Code" + }, + "cli.help.ios": { + "class": "syntax", + "source": "ios [args] [--surface ]" + }, + "cli.help.simulator": { + "class": "syntax", + "source": "simulator [args] [--surface ]" + }, + "clipboard.sshError.item": { + "class": "format", + "source": "%lld. %@ (%@): %@" + }, + "cloudTree.terminal.badge.views": { + "class": "format", + "source": "×%d" + }, + "command.cloudVM.restore.prompt.placeholder": { + "class": "syntax", + "source": "snapshot-id" + }, + "command.cmuxConfig.builtInSubtitle": { + "class": "brand", + "source": "cmux" + }, + "command.cmuxConfig.defaultClaudeCodeTitle": { + "class": "brand", + "source": "Claude Code" + }, + "command.cmuxConfig.defaultCodexTitle": { + "class": "brand", + "source": "Codex" + }, + "command.cmuxConfig.defaultOpenCodeTitle": { + "class": "brand", + "source": "OpenCode" + }, + "command.cmuxConfig.issue.schemaError.detail": { + "class": "format", + "source": "%@" + }, + "command.cmuxConfig.issue.subtitle": { + "class": "format", + "source": "%@: %@" + }, + "command.cmuxConfig.subtitle": { + "class": "syntax", + "source": "cmux.json" + }, + "command.mobileConnect.subtitle": { + "class": "brand", + "source": "Tailscale" + }, + "commandPalette.kind.markdown": { + "class": "technical", + "source": "Markdown" + }, + "debug.bonsplitTabBarDebug.pixelsValue": { + "class": "format", + "source": "%@ px" + }, + "debug.tabBarBackdropLab.leftSidebar": { + "class": "format", + "source": "L" + }, + "debug.tabBarBackdropLab.rightSidebar": { + "class": "format", + "source": "R" + }, + "debug.tabBarBackdropLab.terminal.prompt": { + "class": "syntax", + "source": "lawrence in ~/cmux" + }, + "debug.tabBarBackdropLab.titlebarSample": { + "class": "syntax", + "source": "workspace@lab:~" + }, + "feed.buttonDebug.style.solid": { + "class": "brand", + "source": "Solid" + }, + "feed.exitplan.mode.ultraplan": { + "class": "brand", + "source": "ultraplan" + }, + "feed.exitplan.ultraplan": { + "class": "brand", + "source": "Ultraplan" + }, + "feed.notification.exitPlan.ultraplan": { + "class": "brand", + "source": "Ultraplan" + }, + "feed.textEditorDebug.section.appkit": { + "class": "technical", + "source": "AppKit" + }, + "feed.textEditorDebug.section.swiftui": { + "class": "technical", + "source": "SwiftUI" + }, + "globalSearch.kind.markdown": { + "class": "technical", + "source": "Markdown" + }, + "machines.agent.claude": { + "class": "brand", + "source": "Claude Code" + }, + "machines.agent.codex": { + "class": "brand", + "source": "Codex" + }, + "machines.agent.opencode": { + "class": "brand", + "source": "OpenCode" + }, + "machines.stats.cpu": { + "class": "technical", + "source": "CPU" + }, + "machines.stats.provisioned": { + "class": "brand", + "source": "%@ GB" + }, + "markdown.fontSize.unit": { + "class": "technical", + "source": "pt" + }, + "markdown.maxWidth.unit": { + "class": "technical", + "source": "px" + }, + "menu.help.claudeCodeTeams": { + "class": "brand", + "source": "Claude Code Teams" + }, + "menu.help.ohMyClaudeCode": { + "class": "brand", + "source": "oh-my-claudecode" + }, + "menu.help.ohMyCodex": { + "class": "brand", + "source": "oh-my-codex" + }, + "menu.help.ohMyOpenCode": { + "class": "brand", + "source": "oh-my-opencode" + }, + "menu.help.ssh": { + "class": "technical", + "source": "SSH" + }, + "menu.history.focusedItemTitleFormat": { + "class": "format", + "source": "%1$@ - %2$@" + }, + "menu.history.menuItemSubtitleFormat": { + "class": "format", + "source": "%1$@, %2$@" + }, + "menu.history.recentlyClosed.menuItemFormat": { + "class": "format", + "source": "%1$@ (%2$@)" + }, + "menu.history.recentlyClosed.panel.markdown": { + "class": "technical", + "source": "Markdown" + }, + "mobile.pairing.target.appStore": { + "class": "brand", + "source": "cmux" + }, + "pricing.enterprise.f3": { + "class": "technical", + "source": "SOC 2" + }, + "pricing.native.compare.concurrent.free": { + "class": "format", + "source": "1" + }, + "pricing.native.compare.concurrent.paid": { + "class": "price", + "source": "50" + }, + "pricing.native.eyebrow": { + "class": "brand", + "source": "cmux Pro" + }, + "pricing.native.free.price": { + "class": "price", + "source": "$0" + }, + "pricing.native.metric.vm.value": { + "class": "price", + "source": "4 vCPU / 16 GB" + }, + "pricing.native.pro.price": { + "class": "price", + "source": "$50" + }, + "pricing.native.size.large.rate": { + "class": "price", + "source": "$0.80" + }, + "pricing.native.size.medium.rate": { + "class": "price", + "source": "$0.40" + }, + "pricing.native.size.small.rate": { + "class": "price", + "source": "$0.20" + }, + "pricing.native.team.price": { + "class": "price", + "source": "$60" + }, + "pricing.pro.name": { + "class": "brand", + "source": "cmux Pro" + }, + "pricing.pro.workspace.title": { + "class": "brand", + "source": "cmux Pro" + }, + "pricing.window.title": { + "class": "brand", + "source": "cmux Pro" + }, + "remotePTYAttach.error.allocationDiagnostic": { + "class": "brand", + "source": "%@" + }, + "remoteTmux.tab.windowPaneIndexed": { + "class": "format", + "source": "%1$@ [%2$@]" + }, + "sessionIndex.agent.claude": { + "class": "brand", + "source": "Claude Code" + }, + "sessionIndex.agent.codex": { + "class": "brand", + "source": "Codex" + }, + "sessionIndex.agent.grok": { + "class": "brand", + "source": "Grok" + }, + "sessionIndex.agent.hermesAgent": { + "class": "brand", + "source": "Hermes Agent" + }, + "sessionIndex.agent.opencode": { + "class": "brand", + "source": "OpenCode" + }, + "sessionIndex.agent.pi": { + "class": "brand", + "source": "Pi" + }, + "sessionIndex.agent.rovodev": { + "class": "brand", + "source": "Rovo Dev" + }, + "settings.account.pro.title": { + "class": "brand", + "source": "cmux Pro" + }, + "settings.browser.defaultZoomLevel.percent": { + "class": "format", + "source": "%lld%%" + }, + "settings.config.source.cmux": { + "class": "brand", + "source": "cmux" + }, + "settings.fontSize.valuePoints": { + "class": "format", + "source": "%@ pt" + }, + "settings.mobile.route.iroh": { + "class": "brand", + "source": "Iroh" + }, + "settings.mobile.route.tailscale": { + "class": "brand", + "source": "Tailscale" + }, + "settings.mobile.route.websocket": { + "class": "technical", + "source": "WebSocket" + }, + "settings.notifications.command.placeholder": { + "class": "syntax", + "source": "say \"done\"" + }, + "settings.section.settingsJSON": { + "class": "technical", + "source": "cmux.json" + }, + "settings.sidebar.rightMaxWidth.unit": { + "class": "technical", + "source": "pt" + }, + "settings.sidebarAppearance.fontSize.points": { + "class": "format", + "source": "%@ pt" + }, + "settings.terminal.scrollSpeed.value": { + "class": "format", + "source": "%.2f×" + }, + "settings.terminal.sessionContentWidth.unit": { + "class": "technical", + "source": "pt" + }, + "settings.terminal.tabBarFontSize.points": { + "class": "format", + "source": "%@ pt" + }, + "settings.textBox.submitAction.codex": { + "class": "syntax", + "source": "Codex --yolo" + }, + "settings.textBox.submitAction.opencode": { + "class": "brand", + "source": "OpenCode" + }, + "settings.textBox.submitAction.pi": { + "class": "brand", + "source": "Pi" + }, + "shortcut.recorder.pendingChord": { + "class": "format", + "source": "%@ …" + }, + "sidebar.help.discord": { + "class": "brand", + "source": "Discord" + }, + "sidebar.help.feedback.emailPlaceholder": { + "class": "syntax", + "source": "you@example.com" + }, + "sidebar.port.label": { + "class": "format", + "source": ":%lld" + }, + "sidebar.provider.default.subtitle": { + "class": "brand", + "source": "cmux" + }, + "sidebar.remote.badge": { + "class": "technical", + "source": "SSH" + }, + "sidebar.tree.group.remote.subtitle": { + "class": "technical", + "source": "SSH" + }, + "simulator.action.siri": { + "class": "brand", + "source": "Siri" + }, + "simulator.appearance.voiceOver": { + "class": "brand", + "source": "VoiceOver" + }, + "simulator.application.reactNative": { + "class": "brand", + "source": "React Native" + }, + "simulator.dataNetwork.fiveG": { + "class": "technical", + "source": "5G" + }, + "simulator.dataNetwork.fiveGPlus": { + "class": "technical", + "source": "5G+" + }, + "simulator.dataNetwork.fiveGUC": { + "class": "technical", + "source": "5G UC" + }, + "simulator.dataNetwork.fiveGUWB": { + "class": "technical", + "source": "5G UWB" + }, + "simulator.dataNetwork.fourG": { + "class": "technical", + "source": "4G" + }, + "simulator.dataNetwork.lte": { + "class": "technical", + "source": "LTE" + }, + "simulator.dataNetwork.lteAdvanced": { + "class": "technical", + "source": "LTE-A" + }, + "simulator.dataNetwork.ltePlus": { + "class": "technical", + "source": "LTE+" + }, + "simulator.dataNetwork.threeG": { + "class": "technical", + "source": "3G" + }, + "simulator.dataNetwork.wifi": { + "class": "technical", + "source": "Wi-Fi" + }, + "simulator.device.udid": { + "class": "technical", + "source": "UDID" + }, + "simulator.field.url": { + "class": "technical", + "source": "URL" + }, + "simulator.privacy.faceID": { + "class": "brand", + "source": "Face ID" + }, + "simulator.privacy.homeKit": { + "class": "brand", + "source": "HomeKit" + }, + "simulator.privacy.siri": { + "class": "brand", + "source": "Siri" + }, + "simulator.statusBar.wifiMode": { + "class": "technical", + "source": "Wi-Fi" + }, + "sleepyMode.glow.cmux": { + "class": "brand", + "source": "cmux" + }, + "sleepyMode.theme.cmux": { + "class": "brand", + "source": "cmux" + }, + "statusMenu.profiling.emailPlaceholder": { + "class": "syntax", + "source": "you@example.com" + }, + "taskManager.agent.amp": { + "class": "brand", + "source": "Amp" + }, + "taskManager.agent.claudeCode": { + "class": "brand", + "source": "Claude Code" + }, + "taskManager.agent.codebuddy": { + "class": "brand", + "source": "CodeBuddy" + }, + "taskManager.agent.codex": { + "class": "brand", + "source": "Codex" + }, + "taskManager.agent.copilot": { + "class": "brand", + "source": "Copilot" + }, + "taskManager.agent.cursor": { + "class": "brand", + "source": "Cursor" + }, + "taskManager.agent.factory": { + "class": "brand", + "source": "Factory" + }, + "taskManager.agent.gemini": { + "class": "brand", + "source": "Gemini" + }, + "taskManager.agent.grok": { + "class": "brand", + "source": "Grok" + }, + "taskManager.agent.hermesAgent": { + "class": "brand", + "source": "Hermes Agent" + }, + "taskManager.agent.opencode": { + "class": "brand", + "source": "OpenCode" + }, + "taskManager.agent.pi": { + "class": "brand", + "source": "Pi" + }, + "taskManager.agent.qoder": { + "class": "brand", + "source": "Qoder" + }, + "taskManager.agent.rovodev": { + "class": "brand", + "source": "Rovo Dev" + }, + "taskManager.column.cpu": { + "class": "technical", + "source": "CPU" + }, + "taskManager.killProcess.target.pid": { + "class": "format", + "source": "PID %lld" + }, + "taskManager.row.pid": { + "class": "format", + "source": "PID %lld" + }, + "taskManager.row.webview": { + "class": "technical", + "source": "WebView" + }, + "taskManager.summary.cpu": { + "class": "technical", + "source": "CPU" + }, + "textbox.submitAction.codex": { + "class": "syntax", + "source": "Codex --yolo" + }, + "textbox.submitAction.opencode": { + "class": "brand", + "source": "OpenCode" + }, + "textbox.submitAction.pi": { + "class": "brand", + "source": "Pi" + }, + "update.error.details.url": { + "class": "technical", + "source": "URL" + }, + "machines.new.size.gb": { + "class": "format", + "source": "%d GB" + }, + "machines.new.size.mb": { + "class": "format", + "source": "%d MB" + }, + "cli.readSelection.output.url": { + "class": "format", + "source": "URL: %@" + }, + "computerUse.menu.sessionTitle": { + "class": "format", + "source": "%1$@ · %2$@" + }, + "computerUse.menu.title": { + "class": "brand", + "source": "cmux Computer Use" + }, + "debug.menu.notification.cli": { + "class": "technical", + "source": "CLI" + }, + "debug.menu.notification.osc": { + "class": "technical", + "source": "OSC" + }, + "about.github": { + "class": "brand", + "source": "GitHub" + }, + "agentSession.panel.title": { + "class": "format", + "source": "%@ · %@" + }, + "agentSession.web.shellLabel": { + "class": "technical", + "source": "Shell" + }, + "browser.focusMode.shortcutHint": { + "class": "format", + "source": "Esc Esc" + }, + "cli.error.clearNotificationsUsage": { + "class": "syntax", + "source": "clear_notifications [--tab=X] [--panel=ID] [--correlation-key=UUID]" + }, + "cli.help.restore": { + "class": "syntax", + "source": "restore [--surface ] | restore --surface [id|ref]" + }, + "cli.sessions.command": { + "class": "syntax", + "source": "sessions [list] [options]" + }, + "cli.vm.tree.workspaces": { + "class": "syntax", + "source": "workspaces/" + }, + "cli.vm.tree.terminals": { + "class": "syntax", + "source": "terminals/" + }, + "cli.vm.tree.browsers": { + "class": "syntax", + "source": "browsers/" + }, + "cli.vm.tree.displays": { + "class": "syntax", + "source": "VNC Displays/" + }, + "cli.vm.tree.ports": { + "class": "syntax", + "source": "ports/" + }, + "cloudTree.node.desktop.detail": { + "class": "technical", + "source": "noVNC" + }, + "cloudTree.node.desktop.detail.screen": { + "class": "format", + "source": "%1$@ · %2$@" + }, + "cloudTree.stats.cpu": { + "class": "format", + "source": "CPU %d%%" + }, + "command.installCLI.subtitle": { + "class": "technical", + "source": "CLI" + }, + "command.uninstallCLI.subtitle": { + "class": "technical", + "source": "CLI" + }, + "ghostty.copy-mode.indicator": { + "class": "technical", + "source": "vim" + }, + "machines.usage.line": { + "class": "format", + "source": "%1$@ · %2$@ tokens · %3$@" + }, + "mobile.pairing.target.beta": { + "class": "brand", + "source": "cmux BETA" + }, + "mobile.pairing.target.demo": { + "class": "brand", + "source": "cmux DEMO" + }, + "mobile.pairing.target.dev": { + "class": "brand", + "source": "cmux DEV %@" + }, + "mobile.pairing.target.internal": { + "class": "brand", + "source": "cmux INTERNAL" + }, + "settings.notifications.sound.option.ping": { + "class": "brand", + "source": "Ping" + }, + "settings.notifications.sound.option.pop": { + "class": "brand", + "source": "Pop" + }, + "settings.notifications.sound.option.sosumi": { + "class": "brand", + "source": "Sosumi" + }, + "shortcut.key.tab": { + "class": "brand", + "source": "Tab" + }, + "sidebar.pathMenu.macintoshHD": { + "class": "brand", + "source": "Macintosh HD" + }, + "cli.help.fork": { + "class": "syntax", + "source": "fork [--surface ] | fork --surface [id|ref]" + } } diff --git a/scripts/localization-plurals.json b/scripts/localization-plurals.json index 7b920fd0ff8e..603ec28028af 100644 --- a/scripts/localization-plurals.json +++ b/scripts/localization-plurals.json @@ -1,43 +1,215 @@ { - "browser.profile.automation.error.profileInUse": {}, - "browser.screenshot.error.renderedContentMismatch": {}, - "cli.localTmux.output.foundStale": {}, - "cli.localTmux.output.removedStale": {}, - "cli.localTmux.output.sessionRow": {}, - "cli.localTmux.output.status": {}, - "cli.memory.output.processCount.other": {}, - "cli.sshPtyAttach.noProgressRetryLimitReached.other": {}, - "cli.vm.list.planMeter.unlimited": {}, - "cli.vm.list.planMeter": {}, - "cli.vm.list.planMeter.single": {}, - "cli.vm.tree.localSummary": {}, - "dialog.saveWorkspaceLayout.skippedNote": {}, - "feed.textEditorDebug.metrics": {}, - "fileExplorer.search.limit": {}, - "fileExplorer.search.matches": {}, - "fileExplorer.search.searching": {}, - "machines.empty.planIncludes": {}, - "machines.empty.upgrade": {}, - "machines.freeAccess.help": {}, - "machines.meter.count": {}, - "machines.meter.count.unlimited": {}, - "machines.meter.count.single": {}, - "machines.meter.help.atLimit": {}, - "machines.row.daysLeft": {}, - "memory.attribution.multipleWorkspaces": {}, - "menu.history.recentlyClosed.window.workspaceCount": {}, - "menu.history.recentlyClosed.window.workspaceCount.other": {}, - "notifications.forwardToPhone.mode.subtitle": {}, - "remoteTmux.error.controlSocketPathTooLong": {}, - "settings.cloudMachines.plan.summary.unlimited": {}, - "settings.cloudMachines.plan.summary": {}, - "statusMenu.profiling.bodyFormat": {}, - "statusMenu.profiling.remainingFormat": {}, - "taskManager.aggregate.processCount.other": {}, - "taskManager.killProcess.message.other": {}, - "machines.new.plan.single": {}, - "machines.new.plan.unlimited": {}, - "machines.new.plan.multi": {}, - "machines.new.plan.freeWindow": {}, - "cloudTree.deleteWorkspace.message.other": {} + "browser.profile.automation.error.profileInUse": { + "source": "Cannot delete cmux browser profile '%@' while %d browser panel(s) are using it", + "arguments": [ + 2 + ] + }, + "browser.screenshot.error.renderedContentMismatch": { + "source": "The browser screenshot disagreed with rendered text at %1$@; %2$lld text probes were blank after %3$lld attempts.", + "arguments": [ + 2, + 3 + ] + }, + "cli.localTmux.output.foundStale": { + "source": "Found %lld stale local tmux session(s); pass --prune to remove them", + "arguments": [ + 1 + ] + }, + "cli.localTmux.output.removedStale": { + "source": "Removed %lld stale local tmux session(s)", + "arguments": [ + 1 + ] + }, + "cli.memory.output.processCount.other": { + "source": "%lld processes", + "arguments": [ + 1 + ] + }, + "cli.vm.list.planMeter.unlimited": { + "source": "%1$d machines on the %2$@ plan, no limit", + "arguments": [ + 1 + ] + }, + "cli.vm.list.planMeter": { + "source": "%1$d of %2$d machines on the %3$@ plan", + "arguments": [ + 2 + ] + }, + "cli.vm.tree.localSummary": { + "source": "%1$d terminals · %2$d browsers", + "arguments": [ + 1, + 2 + ] + }, + "dialog.saveWorkspaceLayout.skippedNote": { + "source": "%lld panels have no layout representation (previews, viewers, …) and will be left out.", + "arguments": [ + 1 + ] + }, + "feed.textEditorDebug.metrics": { + "source": "%lld lines · %lld chars", + "arguments": [ + 1, + 2 + ] + }, + "fileExplorer.search.limit": { + "source": "First %d matches", + "arguments": [ + 1 + ] + }, + "fileExplorer.search.matches": { + "source": "%d matches", + "arguments": [ + 1 + ] + }, + "fileExplorer.search.searching": { + "source": "%d matches, searching", + "arguments": [ + 1 + ] + }, + "machines.empty.planIncludes": { + "source": "Your plan includes %d machines", + "arguments": [ + 1 + ] + }, + "machines.empty.upgrade": { + "source": "Upgrade to use more than %d machines", + "arguments": [ + 1 + ] + }, + "machines.freeAccess.help": { + "source": "Free plans keep a machine reachable for %d days after it is created. Upgrade to Pro to keep using it.", + "arguments": [ + 1 + ] + }, + "machines.meter.count": { + "source": "%1$d of %2$d machines", + "arguments": [ + 2 + ] + }, + "machines.meter.count.unlimited": { + "source": "%1$d machines", + "arguments": [ + 1 + ] + }, + "machines.meter.help.atLimit": { + "source": "Your plan includes %d machines. Upgrade to create more.", + "arguments": [ + 1 + ] + }, + "machines.row.daysLeft": { + "source": "%d days left", + "arguments": [ + 1 + ] + }, + "memory.attribution.multipleWorkspaces": { + "source": "%lld workspaces", + "arguments": [ + 1 + ] + }, + "menu.history.recentlyClosed.window.workspaceCount": { + "source": "%d workspaces", + "arguments": [ + 1 + ] + }, + "menu.history.recentlyClosed.window.workspaceCount.other": { + "source": "%d workspaces", + "arguments": [ + 1 + ] + }, + "notifications.forwardToPhone.mode.subtitle": { + "source": "Away means the screen is locked or asleep, the screensaver is running, or there has been no keyboard or mouse input for %lld minutes.", + "arguments": [ + 1 + ] + }, + "remoteTmux.error.controlSocketPathTooLong": { + "source": "SSH control socket path is too long for a Unix domain socket (%lld > %lld bytes); home directory path is too long", + "arguments": [ + 2 + ] + }, + "settings.cloudMachines.plan.summary.unlimited": { + "source": "%1$@ · %2$d machines, no limit", + "arguments": [ + 2 + ] + }, + "settings.cloudMachines.plan.summary": { + "source": "%1$@ · %2$d of %3$d machines", + "arguments": [ + 3 + ] + }, + "statusMenu.profiling.bodyFormat": { + "source": "Recording CPU, SwiftUI, memory, and system traces for %d seconds each. Finalizing may take longer.", + "arguments": [ + 1 + ] + }, + "statusMenu.profiling.remainingFormat": { + "source": "About %d seconds remaining", + "arguments": [ + 1 + ] + }, + "taskManager.aggregate.processCount.other": { + "source": "%lld processes", + "arguments": [ + 1 + ] + }, + "taskManager.killProcess.message.other": { + "source": "Ask %lld processes to terminate gracefully. cmux will force-kill remaining processes after a short grace period. PIDs: %@.", + "arguments": [ + 1 + ] + }, + "machines.new.plan.unlimited": { + "source": "%1$d machines in use", + "arguments": [ + 1 + ] + }, + "machines.new.plan.multi": { + "source": "%1$d of %2$d machines in use", + "arguments": [ + 2 + ] + }, + "machines.new.plan.freeWindow": { + "source": "Free plan: this machine stays reachable for %d days. Upgrade to keep it.", + "arguments": [ + 1 + ] + }, + "cloudTree.deleteWorkspace.message.other": { + "source": "Its %d terminals are killed with it. To keep them, use “Close Workspace” instead — they move to the Terminals pool.", + "arguments": [ + 1 + ] + } } diff --git a/scripts/localization_catalog.py b/scripts/localization_catalog.py index de17259f9048..af8e52cd92b8 100644 --- a/scripts/localization_catalog.py +++ b/scripts/localization_catalog.py @@ -1,347 +1,315 @@ #!/usr/bin/env python3 -"""Audit and update the macOS XCStrings catalogs without losing Xcode ordering.""" +"""Extract, merge, and validate macOS XCStrings translations (Python 3.9+).""" from __future__ import annotations import argparse +import copy import json +import os import re import sys +import tempfile +from dataclasses import dataclass from pathlib import Path -from typing import Any, Iterable -TARGET_LOCALES = ("de", "fr", "ar", "es", "zh-Hant", "zh-Hans", "ko", "ja") -CATALOGS = ( - "Resources/Localizable.xcstrings", - "Resources/InfoPlist.xcstrings", - "Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/Resources/Localizable.xcstrings", - "Packages/macOS/CmuxFeedback/Sources/CmuxFeedback/ComposerUI/Resources/Localizable.xcstrings", - "Packages/macOS/CmuxSwiftRenderUI/Sources/CmuxSwiftRenderUI/Resources/Localizable.xcstrings", - "TunnelExtension/InfoPlist.xcstrings", +ROOT = Path(__file__).resolve().parent.parent +LOCALES = ("en", "de", "fr", "ar", "es", "zh-Hant", "zh-Hans", "ko", "ja") +CATEGORIES = {"ar": {"zero", "one", "two", "few", "many", "other"}} +OMISSION_CLASSES = {"brand", "technical", "format", "price", "syntax"} +FORMAT = re.compile( + r"%%|%#@[^@]+@|%(?:\d+\$)?[-+ #0']*(?:\d+|\*(?:\d+\$)?)?" + r"(?:\.(?:\d+|\*(?:\d+\$)?))?(?:hh|ll|[hlLqjzt])?[diouxXfFeEgGaAcCsSp@]" ) -OMISSIONS_PATH = Path(__file__).with_name("localization-allowed-omissions.json") -PLURALS_PATH = Path(__file__).with_name("localization-plurals.json") -PLACEHOLDER_RE = re.compile( - r"%(?:(?:\d+\$)?[-+0 #]*\d*(?:\.\d+)?(?:hh|h|ll|l|L|z|t|j)?[diouxXeEfFgGcsSpaA@]|%)" -) -MACHINE_MARKER_RE = re.compile(r"(?:TODO|TRANSLATE|MACHINE_TRANSLATION||\[translation\])", re.I) - - -class ObjectPairs(list): - """A JSON object represented as ordered pairs, including duplicate keys.""" - - -def _pairs_hook(pairs: list[tuple[str, Any]]) -> ObjectPairs: - return ObjectPairs(pairs) - - -def _load_pairs(path: Path) -> ObjectPairs: - return json.loads(path.read_text(encoding="utf-8"), object_pairs_hook=_pairs_hook) - - -def _load_plain(path: Path) -> dict[str, Any]: - return json.loads(path.read_text(encoding="utf-8")) - - -def _dump_value(value: Any, level: int = 0) -> str: - indent = " " * level - child_indent = " " * (level + 1) - if isinstance(value, ObjectPairs): - if not value: - return "{}" - lines = ["{"] - for index, (key, item) in enumerate(value): - suffix = "," if index + 1 < len(value) else "" - lines.append(f"{child_indent}{json.dumps(key, ensure_ascii=False)}: {_dump_value(item, level + 1)}{suffix}") - lines.append(f"{indent}}}") - return "\n".join(lines) - if isinstance(value, list): - if not value: - return "[]" - lines = ["["] - for index, item in enumerate(value): - suffix = "," if index + 1 < len(value) else "" - lines.append(f"{child_indent}{_dump_value(item, level + 1)}{suffix}") - lines.append(f"{indent}]") - return "\n".join(lines) - return json.dumps(value, ensure_ascii=False) - - -def _write_pairs(path: Path, value: ObjectPairs) -> None: - path.write_text(_dump_value(value) + "\n", encoding="utf-8") - - -def _get(obj: ObjectPairs, key: str, default: Any = None) -> Any: - for candidate, value in reversed(obj): - if candidate == key: - return value - return default - - -def _get_pair(obj: ObjectPairs, key: str) -> tuple[int, Any] | None: - for index in range(len(obj) - 1, -1, -1): - if obj[index][0] == key: - return index, obj[index][1] - return None - - -def _set(obj: ObjectPairs, key: str, value: Any) -> None: - pair = _get_pair(obj, key) - if pair is None: - obj.append((key, value)) - else: - obj[pair[0]] = (key, value) - - -def _plain(value: Any) -> Any: - if isinstance(value, ObjectPairs): - result: dict[str, Any] = {} - for key, item in value: - result[key] = _plain(item) - return result - if isinstance(value, list): - return [_plain(item) for item in value] +MARKER = re.compile(r"\b(?:TODO|TRANSLATE_ME|MACHINE_TRANSLATION)\b|__CMUX_TOKEN_\d+__|", re.I) +BIDI = re.compile("[\u202a-\u202e\u2066-\u2069]") + + +@dataclass +class Member: + key: str + value: object + start: int + end: int + + +def members(text: str, start: int = 0) -> list[Member]: + decoder = json.JSONDecoder() + position = start + 1 + result = [] + while True: + while text[position].isspace() or text[position] == ",": + position += 1 + if text[position] == "}": + return result + key, position = decoder.raw_decode(text, position) + while text[position].isspace(): + position += 1 + if text[position] != ":": + raise ValueError("expected object member separator") + position += 1 + while text[position].isspace(): + position += 1 + value, end = decoder.raw_decode(text, position) + result.append(Member(key, value, position, end)) + position = end + + +def catalog_entries(text: str) -> list[Member]: + parsed = json.loads(text) + if parsed.get("sourceLanguage") != "en" or not isinstance(parsed.get("strings"), dict): + raise ValueError("expected an English-source string catalog") + strings = next(item for item in members(text, len(text) - len(text.lstrip())) if item.key == "strings") + return members(text, strings.start) + + +def discover(root: Path) -> list[Path]: + paths = set((root / "Resources").rglob("*.xcstrings")) + paths.update((root / "TunnelExtension").rglob("*.xcstrings")) + paths.update((root / "Packages/macOS").glob("*/Sources/**/*.xcstrings")) + return sorted(paths) + + +def load_metadata(name: str) -> dict: + with (ROOT / "scripts" / name).open(encoding="utf-8") as handle: + return json.load(handle) + + +def placeholders(value: str) -> list[str]: + return FORMAT.findall(value) + + +def source(entry: dict) -> str: + english = entry.get("localizations", {}).get("en", {}) + unit = english.get("stringUnit") or english.get("variations", {}).get("plural", {}).get("other", {}).get("stringUnit", {}) + value = unit.get("value") + if not isinstance(value, str): + raise ValueError("missing English source value") return value -def _source(entry: dict[str, Any]) -> str: - return entry.get("localizations", {}).get("en", {}).get("stringUnit", {}).get("value", "") - - -def _placeholders(value: str) -> list[str]: - return PLACEHOLDER_RE.findall(value) - - -def _locale_unit(entry: dict[str, Any], locale: str) -> dict[str, Any] | None: - return entry.get("localizations", {}).get(locale, {}).get("stringUnit") - - -def _allowed_omissions() -> dict[str, str]: - if not OMISSIONS_PATH.exists(): - return {} - data = json.loads(OMISSIONS_PATH.read_text(encoding="utf-8")) - return {str(key): str(value) for key, value in data.items()} +def plural_nodes(localization: dict): + plural = localization.get("variations", {}).get("plural") + if plural is not None: + yield 1, plural + for substitution in localization.get("substitutions", {}).values(): + plural = substitution.get("variations", {}).get("plural") + if plural is not None: + yield substitution.get("argNum"), plural + + +def units(localization: dict, prefix: str = ""): + if "stringUnit" in localization: + yield prefix, localization["stringUnit"] + for dimension, variants in localization.get("variations", {}).items(): + for variant, node in variants.items(): + yield from units(node, f"{prefix}/{dimension}/{variant}") + + +def omission(key: str, english: str, metadata: dict) -> bool: + record = metadata.get(key, {}) + return record.get("source") == english and record.get("class") in OMISSION_CLASSES + + +def validate_localization(english: str, localization: dict, locale: str, allow_identity: bool = False) -> list[str]: + errors = [] + expected = placeholders(english) + found_units = list(units(localization)) + if not found_units: + return ["missing translated string unit or variations"] + substitutions = localization.get("substitutions", {}) + for location, unit in found_units: + value = unit.get("value") + if unit.get("state") != "translated": + errors.append(f"{location}: state is {unit.get('state')!r}") + if not isinstance(value, str) or not value.strip(): + errors.append(f"{location}: empty value") + continue + actual = [] + for token in placeholders(value): + if token.startswith("%#@"): + substitution = substitutions.get(token[3:-1], {}) + argument = substitution.get("argNum") + if not isinstance(argument, int) or not 1 <= argument <= len(expected): + errors.append(f"{location}: invalid substitution {token}") + continue + actual.append(expected[argument - 1]) + else: + actual.append(token) + if actual != expected: + errors.append(f"{location}: placeholders {actual!r} != {expected!r}") + if value == english and locale != "en" and not allow_identity: + errors.append(f"{location}: identical to English; translate or document an invariant literal") + if MARKER.search(value): + errors.append(f"{location}: unfinished translation marker") + if BIDI.search(value): + errors.append(f"{location}: bidi controls require explicit review") + for name, substitution in substitutions.items(): + argument = substitution.get("argNum") + specifier = substitution.get("formatSpecifier") + if not isinstance(argument, int) or not 1 <= argument <= len(expected): + errors.append(f"substitution {name}: invalid argument number") + continue + expected_specifier = re.sub(r"^%(?:\d+\$)?", "", expected[argument - 1]) + if specifier != expected_specifier: + errors.append(f"substitution {name}: format specifier does not match source") + for location, unit in units(substitution): + value = unit.get("value") + if unit.get("state") != "translated" or not isinstance(value, str) or not value.strip(): + errors.append(f"substitution {name}{location}: missing translated value") + elif placeholders(value) != [f"%{specifier}"]: + errors.append(f"substitution {name}{location}: count placeholder does not match source") + elif MARKER.search(value) or BIDI.search(value): + errors.append(f"substitution {name}{location}: unfinished or bidi marker") + required = CATEGORIES.get(locale, {"other"} if locale in {"zh-Hans", "zh-Hant", "ko", "ja"} else {"one", "other"}) + for argument, variants in plural_nodes(localization): + if required - set(variants): + errors.append(f"argument {argument}: missing plural categories {sorted(required - set(variants))}") + return errors -def _plural_keys() -> set[str]: - if not PLURALS_PATH.exists(): - return set() - data = json.loads(PLURALS_PATH.read_text(encoding="utf-8")) - return {str(key) for key in data} +def check_entry(entry: Member, locale: str, omissions: dict, counts: dict) -> list[str]: + english = source(entry.value) + allowed = locale not in {"en", "ja"} and omission(entry.key, english, omissions) + localization = entry.value.get("localizations", {}).get(locale) + if localization is None: + return [] if allowed and locale not in {"en", "ja"} else ["missing locale entry"] + errors = validate_localization(english, localization, locale, allowed) + count = counts.get(entry.key) + if count: + if count["source"] != english: + errors.append("count source changed; review plural argument metadata") + present = {argument for argument, _ in plural_nodes(localization)} + for argument in count["arguments"]: + if argument not in present: + errors.append(f"count argument {argument} has no plural variation") + return errors -def _entry_rows(path: Path) -> Iterable[tuple[str, dict[str, Any]]]: - data = _load_plain(path) - for key, entry in data.get("strings", {}).items(): - yield key, entry +def render(value: dict, indent: int) -> str: + return json.dumps(value, ensure_ascii=False, indent=2).replace("\n", "\n" + " " * indent) -def _catalog_paths(args: argparse.Namespace) -> list[Path]: - if args.catalog: - return [Path(item) for item in args.catalog] - return [Path(item) for item in CATALOGS] +def replace_locale(text: str, entry: Member, locale: str, localization: dict) -> tuple[int, int, str]: + container = next(item for item in members(text, entry.start) if item.key == "localizations") + existing = members(text, container.start) + selected = [item for item in existing if item.key == locale] + if len(selected) > 1: + raise ValueError(f"{entry.key}: duplicate {locale} entries") + if selected: + item = selected[0] + return item.start, item.end, render(localization, 8) + insertion = existing[-1].end if existing else container.start + 1 + addition = ("," if existing else "") + f"\n {json.dumps(locale)}: " + render(localization, 8) + return insertion, insertion, addition -def command_extract(args: argparse.Namespace) -> int: - path = Path(args.catalog) - rows = [] - for key, entry in _entry_rows(path): - unit = _locale_unit(entry, args.locale) - if unit and unit.get("state") == "translated": - continue - source = _source(entry) - rows.append( - { - "key": key, - "source": source, - "comment": entry.get("comment"), - "placeholders": _placeholders(source), - } - ) - start = args.batch * args.batch_size - selected = rows[start : start + args.batch_size] - payload = {"catalog": str(path), "locale": args.locale, "batch": args.batch, "total": len(rows), "entries": selected} - output = json.dumps(payload, ensure_ascii=False, indent=2) + "\n" - if args.output: - Path(args.output).write_text(output, encoding="utf-8") - else: - print(output, end="") - return 0 - - -def _localized_object(value: str, plural: dict[str, str] | None = None) -> ObjectPairs: - unit = ObjectPairs([("state", "translated"), ("value", value)]) - pairs: list[tuple[str, Any]] = [("stringUnit", unit)] - if plural: - variations = ObjectPairs( - [ - ( - "plural", - ObjectPairs( - [ - (category, ObjectPairs([("stringUnit", ObjectPairs([("state", "translated"), ("value", text)]))])) - for category, text in plural.items() - ] - ), - ) - ] - ) - pairs.append(("variations", variations)) - return ObjectPairs(pairs) - - -def _merge_localization(entry: ObjectPairs, locale: str, value: str, plural: dict[str, str] | None) -> None: - localizations = _get(entry, "localizations") - if not isinstance(localizations, ObjectPairs): - localizations = ObjectPairs() - _set(entry, "localizations", localizations) - localization = _get(localizations, locale) - if not isinstance(localization, ObjectPairs): - _set(localizations, locale, _localized_object(value, plural)) - return - string_unit = _get(localization, "stringUnit") - if not isinstance(string_unit, ObjectPairs): - string_unit = ObjectPairs() - _set(localization, "stringUnit", string_unit) - _set(string_unit, "state", "translated") - _set(string_unit, "value", value) - if plural: - _set( - localization, - "variations", - _localized_object("", plural)[1][1], - ) - - -def _merge_entry_pairs(data: ObjectPairs, locale: str, translations: dict[str, dict[str, Any]]) -> set[str]: - strings = _get(data, "strings") - if not isinstance(strings, ObjectPairs): - raise ValueError("catalog has no strings object") - seen: set[str] = set() - for key, entry in strings: - if key not in translations or not isinstance(entry, ObjectPairs): - continue - item = translations[key] - if item.get("omit"): - localizations = _get(entry, "localizations") - if isinstance(localizations, ObjectPairs): - localizations[:] = [(name, value) for name, value in localizations if name != locale] - else: - value = item.get("value") - if not isinstance(value, str): - raise ValueError(f"translation for {key} must have a string value") - _merge_localization(entry, locale, value, item.get("plural")) - seen.add(key) - return seen - - -def command_merge(args: argparse.Namespace) -> int: - path = Path(args.catalog) - payload = json.loads(Path(args.input).read_text(encoding="utf-8")) - if isinstance(payload, dict) and "translations" in payload: - payload = payload["translations"] - if isinstance(payload, list): - translations = {item["key"]: item for item in payload} - elif isinstance(payload, dict): - translations = {key: (item if isinstance(item, dict) else {"value": item}) for key, item in payload.items()} - else: - raise ValueError("translation input must be a list or object") - data = _load_pairs(path) - merged = _merge_entry_pairs(data, args.locale, translations) - missing = set(translations) - merged - if missing: - raise ValueError(f"translation keys not found in {path}: {', '.join(sorted(missing)[:5])}") - _write_pairs(path, data) - print(f"merged {len(merged)} {args.locale} translations into {path}") - return 0 - - -def _check_entry(path: Path, key: str, entry: dict[str, Any], locale: str, omissions: dict[str, str]) -> list[str]: - errors: list[str] = [] - source = _source(entry) - source_placeholders = _placeholders(source) - unit = _locale_unit(entry, locale) - allowed = locale != "ja" and path.resolve() == Path("Resources/Localizable.xcstrings").resolve() and key in omissions - if unit is None: - if not allowed: - errors.append(f"{path}:{key}: missing {locale} entry") - return errors - if unit.get("state") != "translated": - errors.append(f"{path}:{key}: {locale} state is {unit.get('state')!r}") - value = unit.get("value") - if not isinstance(value, str) or not value.strip(): - errors.append(f"{path}:{key}: {locale} value is empty") - return errors - if _placeholders(value) != source_placeholders: - errors.append(f"{path}:{key}: {locale} placeholders {_placeholders(value)!r} != {source_placeholders!r}") - if value == source and not allowed: - errors.append(f"{path}:{key}: {locale} copies English") - if MACHINE_MARKER_RE.search(value): - errors.append(f"{path}:{key}: {locale} contains a machine marker") - return errors - - -def command_check(args: argparse.Namespace) -> int: - omissions = _allowed_omissions() - plural_keys = _plural_keys() - errors: list[str] = [] - for path in _catalog_paths(args): - try: - data = _load_plain(path) - except (OSError, json.JSONDecodeError) as exc: - errors.append(f"{path}: invalid JSON: {exc}") - continue - strings = data.get("strings") - if not isinstance(strings, dict): - errors.append(f"{path}: missing strings object") - continue - for locale in TARGET_LOCALES: - for key, entry in strings.items(): - errors.extend(_check_entry(path, key, entry, locale, omissions)) - if key in plural_keys: - localization = entry.get("localizations", {}).get(locale, {}) - plural = localization.get("variations", {}).get("plural", {}) - required_categories = {"zero", "one", "two", "few", "many", "other"} if locale == "ar" else {"one", "other"} - missing_categories = required_categories - set(plural) - if missing_categories: - errors.append(f"{path}:{key}: {locale} missing plural categories {sorted(missing_categories)}") - if errors: - print("\n".join(errors), file=sys.stderr) - print(f"localization check failed: {len(errors)} error(s)", file=sys.stderr) - return 1 - print(f"localization check passed: {len(_catalog_paths(args))} catalogs, {len(TARGET_LOCALES)} locales") - return 0 - - -def build_parser() -> argparse.ArgumentParser: +def atomic_write(path: Path, text: str) -> None: + descriptor, temporary = tempfile.mkstemp(prefix=f".{path.name}.", dir=path.parent) + try: + with os.fdopen(descriptor, "w", encoding="utf-8") as handle: + handle.write(text) + os.chmod(temporary, path.stat().st_mode) + os.replace(temporary, path) + finally: + if os.path.exists(temporary): + os.unlink(temporary) + + +def merge(path: Path, locale: str, rows: list[dict], omissions: dict) -> int: + text = path.read_text(encoding="utf-8") + indexed = {} + for entry in catalog_entries(text): + indexed.setdefault((entry.key, source(entry.value)), []).append(entry) + changes = [] + seen = set() + for row in rows: + identity = (row["key"], row["source"]) + if identity in seen or identity not in indexed: + raise ValueError(f"{row['key']}: duplicate row, unknown key, or stale English source") + seen.add(identity) + for entry in indexed[identity]: + current = entry.value.get("localizations", {}).get(locale, {}) + if "localization" in row: + localization = row["localization"] + else: + if "variations" in current or "substitutions" in current: + raise ValueError(f"{entry.key}: provide the full localization to update variations") + localization = copy.deepcopy(current) + localization.setdefault("stringUnit", {}).update(state="translated", value=row["value"]) + errors = validate_localization(identity[1], localization, locale, omission(entry.key, identity[1], omissions)) + if errors: + raise ValueError(f"{entry.key}: {'; '.join(errors)}") + if localization != current: + changes.append(replace_locale(text, entry, locale, localization)) + for start, end, replacement in sorted(changes, reverse=True): + text = text[:start] + replacement + text[end:] + catalog_entries(text) + if changes: + atomic_write(path, text) + return len(changes) + + +def main() -> int: parser = argparse.ArgumentParser(description=__doc__) - subparsers = parser.add_subparsers(dest="command", required=True) - - extract = subparsers.add_parser("extract", help="extract one locale's unfinished entries") - extract.add_argument("--catalog", required=True) - extract.add_argument("--locale", required=True, choices=TARGET_LOCALES) - extract.add_argument("--batch", type=int, default=0) - extract.add_argument("--batch-size", type=int, default=100) - extract.add_argument("--output") - extract.set_defaults(function=command_extract) - - merge = subparsers.add_parser("merge", help="merge translated values into a catalog") - merge.add_argument("--catalog", required=True) - merge.add_argument("--locale", required=True, choices=TARGET_LOCALES) - merge.add_argument("--input", required=True) - merge.set_defaults(function=command_merge) - - check = subparsers.add_parser("check", help="validate macOS catalog parity") - check.add_argument("--catalog", action="append") - check.set_defaults(function=command_check) - return parser + parser.add_argument("command", choices=("check", "extract", "merge")) + parser.add_argument("--root", type=Path, default=ROOT) + parser.add_argument("--catalog", type=Path) + parser.add_argument("--locale", choices=LOCALES) + parser.add_argument("--input", type=Path) + parser.add_argument("--output", type=Path) + parser.add_argument("--batch-size", type=int, default=100) + parser.add_argument("--batch", type=int, default=0) + parser.add_argument("--limit", type=int, default=40, help="maximum printed diagnostics; 0 prints all") + args = parser.parse_args() + if args.batch_size < 1 or args.batch < 0 or args.limit < 0: + parser.error("batch size must be positive; batch and limit must be nonnegative") + omissions = load_metadata("localization-allowed-omissions.json") + counts = load_metadata("localization-plurals.json") + if args.command == "merge": + if not args.catalog or not args.locale or not args.input: + parser.error("merge requires --catalog, --locale, and --input") + rows = json.loads(args.input.read_text(encoding="utf-8")) + print(f"Updated {merge(args.catalog, args.locale, rows, omissions)} locale entries") + return 0 + paths = [args.catalog] if args.catalog else discover(args.root) + if not paths: + raise ValueError("no macOS catalogs found") + if args.command == "extract" and not args.locale: + parser.error("extract requires --locale") + rows, diagnostics = [], [] + locales = [args.locale] if args.locale else LOCALES + for path in paths: + entries = catalog_entries(path.read_text(encoding="utf-8")) + effective = {entry.key: entry for entry in entries} + for entry in effective.values(): + local_omissions = omissions if path.resolve() == (args.root / "Resources/Localizable.xcstrings").resolve() else {} + local_counts = counts if local_omissions is omissions else {} + for locale in locales: + errors = check_entry(entry, locale, local_omissions, local_counts) + diagnostics.extend(f"{path}:{entry.key}:{locale}: {error}" for error in errors) + if errors and args.command == "extract": + rows.append({"catalog": str(path), "key": entry.key, "source": source(entry.value), + "comment": entry.value.get("comment"), "placeholders": placeholders(source(entry.value)), + "locale": locale, "issues": errors}) + if args.command == "extract": + start = args.batch * args.batch_size + output = json.dumps({"total": len(rows), "entries": rows[start:start + args.batch_size]}, ensure_ascii=False, indent=2) + "\n" + if args.output: + args.output.write_text(output, encoding="utf-8") + else: + print(output, end="") + return 0 + for diagnostic in diagnostics[:args.limit or None]: + print(diagnostic, file=sys.stderr) + print(f"{len(paths)} catalogs, {len(locales)} locales: {len(diagnostics)} parity errors") + return int(bool(diagnostics)) if __name__ == "__main__": try: - parsed_args = build_parser().parse_args() - raise SystemExit(parsed_args.function(parsed_args)) - except (OSError, ValueError, json.JSONDecodeError) as exc: - print(f"error: {exc}", file=sys.stderr) + raise SystemExit(main()) + except (OSError, ValueError, KeyError, TypeError) as error: + print(f"error: {error}", file=sys.stderr) raise SystemExit(2) diff --git a/tests/test_localization_catalog.py b/tests/test_localization_catalog.py new file mode 100644 index 000000000000..15e783356c9f --- /dev/null +++ b/tests/test_localization_catalog.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 + +import importlib.util +import json +import sys +import tempfile +import unittest +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +SPEC = importlib.util.spec_from_file_location("localization_catalog", ROOT / "scripts/localization_catalog.py") +MODULE = importlib.util.module_from_spec(SPEC) +assert SPEC.loader is not None +sys.modules[SPEC.name] = MODULE +SPEC.loader.exec_module(MODULE) + + +class LocalizationCatalogTests(unittest.TestCase): + def test_info_plist_duplicate_records_remain_lossless(self): + path = ROOT / "Resources/InfoPlist.xcstrings" + text = path.read_text(encoding="utf-8") + entries = MODULE.catalog_entries(text) + keys = [entry.key for entry in entries] + self.assertEqual(keys.count("NSLocalNetworkUsageDescription"), 2) + self.assertEqual(keys.count("NSMotionUsageDescription"), 2) + self.assertEqual(keys.count("NSSpeechRecognitionUsageDescription"), 2) + self.assertEqual(keys.count("NSSystemAdministrationUsageDescription"), 2) + + def test_merge_rejects_stale_source_and_wrong_placeholder(self): + original = { + "sourceLanguage": "en", + "strings": { + "example": { + "extractionState": "manual", + "localizations": {"en": {"stringUnit": {"state": "translated", "value": "Open %@"}}}, + } + }, + } + with tempfile.TemporaryDirectory() as directory: + path = Path(directory) / "Localizable.xcstrings" + path.write_text(json.dumps(original, indent=2) + "\n", encoding="utf-8") + with self.assertRaises(ValueError): + MODULE.merge(path, "de", [{"key": "example", "source": "Stale %@", "value": "Öffnen %@"}], {}) + with self.assertRaises(ValueError): + MODULE.merge(path, "de", [{"key": "example", "source": "Open %@", "value": "Öffnen"}], {}) + self.assertEqual(json.loads(path.read_text(encoding="utf-8")), original) + + def test_merge_preserves_other_locales_and_updates_only_target(self): + original = { + "sourceLanguage": "en", + "strings": { + "example": { + "extractionState": "manual", + "localizations": { + "en": {"stringUnit": {"state": "translated", "value": "Open"}}, + "ja": {"stringUnit": {"state": "translated", "value": "開く"}}, + }, + } + }, + } + with tempfile.TemporaryDirectory() as directory: + path = Path(directory) / "Localizable.xcstrings" + path.write_text(json.dumps(original, indent=2) + "\n", encoding="utf-8") + MODULE.merge(path, "de", [{"key": "example", "source": "Open", "value": "Öffnen"}], {}) + updated = json.loads(path.read_text(encoding="utf-8")) + localizations = updated["strings"]["example"]["localizations"] + self.assertEqual(localizations["ja"]["stringUnit"]["value"], "開く") + self.assertEqual(localizations["de"]["stringUnit"]["value"], "Öffnen") + + +if __name__ == "__main__": + unittest.main() From 4235c7c650ecd7278585e01fc9fdee31a81bcf69 Mon Sep 17 00:00:00 2001 From: Austin Wang Date: Tue, 8 Sep 2026 06:40:28 -0700 Subject: [PATCH 03/50] Add failing regression coverage for catalog plural validation --- .github/workflows/ci.yml | 6 +-- tests/test_localization_catalog.py | 62 ++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 16a16ada3d5e..435f77a0e3ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -156,12 +156,12 @@ jobs: - name: Validate Python test harness syntax run: git ls-files 'tests/*.py' 'tests_v2/*.py' 'scripts/*.py' | xargs python3 -m py_compile - - name: Validate macOS localization parity - run: python3 scripts/localization_catalog.py check - - name: Test macOS localization catalog tooling run: python3 tests/test_localization_catalog.py + - name: Validate macOS localization parity + run: python3 scripts/localization_catalog.py check + - name: Validate TUI npm package artifact transfer run: python3 tests/test_tui_npm_package_artifact.py diff --git a/tests/test_localization_catalog.py b/tests/test_localization_catalog.py index 15e783356c9f..6c50fcd264ab 100644 --- a/tests/test_localization_catalog.py +++ b/tests/test_localization_catalog.py @@ -16,7 +16,69 @@ SPEC.loader.exec_module(MODULE) +def unit(value): + return {"stringUnit": {"state": "translated", "value": value}} + + +def counted(parent, one, other, specifier="d"): + return { + **unit(parent), + "substitutions": { + "count": { + "argNum": 1, + "formatSpecifier": specifier, + "variations": {"plural": {"one": one, "other": other}}, + } + }, + } + + class LocalizationCatalogTests(unittest.TestCase): + def test_japanese_invariant_requires_entry_but_allows_literal(self): + entry = MODULE.Member("brand", {"localizations": {"en": unit("cmux"), "ja": unit("cmux")}}, 0, 0) + omissions = {"brand": {"source": "cmux", "class": "brand"}} + self.assertEqual(MODULE.check_entry(entry, "ja", omissions, {}), []) + del entry.value["localizations"]["ja"] + self.assertIn("missing locale entry", MODULE.check_entry(entry, "ja", omissions, {})) + + def test_english_substitutions_and_plural_metadata_validate(self): + english = counted("%#@count@", unit("%d match"), unit("%d matches")) + german = counted("%#@count@", unit("%d Treffer"), unit("%d Treffer")) + entry = MODULE.Member("matches", {"localizations": {"en": english, "de": german}}, 0, 0) + counts = {"matches": {"source": "%d matches", "arguments": [1]}} + for locale in ("en", "de"): + with self.subTest(locale=locale): + self.assertEqual(MODULE.check_entry(entry, locale, {}, counts), []) + + def test_each_required_plural_leaf_needs_text(self): + for bad_leaf in ({}, {"stringUnit": {"state": "translated", "value": ""}}): + for position in ("one", "other"): + with self.subTest(leaf=bad_leaf, position=position): + german = counted("%#@count@ Treffer", unit("%d"), unit("%d")) + german["substitutions"]["count"]["variations"]["plural"][position] = bad_leaf + self.assertTrue(MODULE.validate_localization("%d matches", german, "de")) + + def test_substitution_cannot_hide_copied_english(self): + german = counted("Treffer: %#@count@", unit("%d matches"), unit("%d matches")) + self.assertTrue(MODULE.validate_localization("%d matches", german, "de")) + + def test_plural_only_numeric_leaves_are_valid_when_parent_is_translated(self): + german = counted("%#@count@ Treffer", unit("%d"), unit("%d")) + self.assertEqual(MODULE.validate_localization("%d matches", german, "de"), []) + + def test_unused_substitutions_cannot_satisfy_count_metadata(self): + german = counted("%d Treffer", unit("%d"), unit("%d")) + entry = MODULE.Member("matches", {"localizations": {"en": unit("%d matches"), "de": german}}, 0, 0) + counts = {"matches": {"source": "%d matches", "arguments": [1]}} + self.assertTrue(MODULE.check_entry(entry, "de", {}, counts)) + + def test_arabic_requires_all_six_nonempty_categories(self): + variants = {category: unit("%d نتائج") for category in ("zero", "one", "two", "few", "many", "other")} + arabic = {"variations": {"plural": variants}} + self.assertEqual(MODULE.validate_localization("%d matches", arabic, "ar"), []) + variants["few"] = {} + self.assertTrue(MODULE.validate_localization("%d matches", arabic, "ar")) + def test_info_plist_duplicate_records_remain_lossless(self): path = ROOT / "Resources/InfoPlist.xcstrings" text = path.read_text(encoding="utf-8") From fd3af76e05d4bb6a2927ebc640f524ee9b9829a8 Mon Sep 17 00:00:00 2001 From: Austin Wang Date: Tue, 8 Sep 2026 06:47:34 -0700 Subject: [PATCH 04/50] Validate source arguments and every translated plural leaf --- scripts/localization_catalog.py | 174 ++++++++++++++++++++++++-------- 1 file changed, 131 insertions(+), 43 deletions(-) diff --git a/scripts/localization_catalog.py b/scripts/localization_catalog.py index af8e52cd92b8..5b507ccad9d9 100644 --- a/scripts/localization_catalog.py +++ b/scripts/localization_catalog.py @@ -19,7 +19,7 @@ CATEGORIES = {"ar": {"zero", "one", "two", "few", "many", "other"}} OMISSION_CLASSES = {"brand", "technical", "format", "price", "syntax"} FORMAT = re.compile( - r"%%|%#@[^@]+@|%(?:\d+\$)?[-+ #0']*(?:\d+|\*(?:\d+\$)?)?" + r"%%|%(?:\d+\$)?#@[^@]+@|%(?:\d+\$)?[-+ #0']*(?:\d+|\*(?:\d+\$)?)?" r"(?:\.(?:\d+|\*(?:\d+\$)?))?(?:hh|ll|[hlLqjzt])?[diouxXfFeEgGaAcCsSp@]" ) MARKER = re.compile(r"\b(?:TODO|TRANSLATE_ME|MACHINE_TRANSLATION)\b|__CMUX_TOKEN_\d+__|", re.I) @@ -80,13 +80,66 @@ def placeholders(value: str) -> list[str]: return FORMAT.findall(value) +def substitution_name(token: str) -> str | None: + match = re.fullmatch(r"%(?:\d+\$)?#@([^@]+)@", token) + return match[1] if match else None + + +def signature(value: str, substitutions: dict | None = None) -> list[tuple[int, str]]: + result = [] + next_argument = 1 + for token in placeholders(value): + if token == "%%": + result.append((0, "%")) + continue + name = substitution_name(token) + if name is not None: + substitution = (substitutions or {}).get(name, {}) + argument = substitution.get("argNum") + specifier = substitution.get("formatSpecifier") + if type(argument) is not int or argument < 1 or not isinstance(specifier, str): + raise ValueError(f"invalid substitution {token}") + else: + match = re.fullmatch(r"%(?:(\d+)\$)?(.*)", token) + argument = int(match[1]) if match[1] else next_argument + specifier = match[2] + result.append((argument, specifier)) + next_argument += 1 + return result + + +def canonical_text(value: str) -> str: + """Compare implicit and explicit argument positions without changing their order.""" + arguments = iter(signature(value)) + return FORMAT.sub(lambda match: "%%" if (part := next(arguments))[0] == 0 + else f"%{part[0]}${part[1]}", value) + + +def expand_text(value: str, substitutions: dict, category: str = "other") -> str: + def replace(match): + token = match[0] + name = substitution_name(token) + if name is None: + return token + substitution = substitutions.get(name, {}) + plural = substitution.get("variations", {}).get("plural", {}) + node = plural.get(category, plural.get("other", substitution)) + leaf = node.get("stringUnit", {}).get("value") + argument = substitution.get("argNum") + if not isinstance(leaf, str) or type(argument) is not int or argument < 1: + raise ValueError(f"{token}: missing source substitution value or argument") + return FORMAT.sub(lambda item: "%%" if item[0] == "%%" else + "%" + str(argument) + "$" + re.sub(r"^%(?:[0-9]+\$)?", "", item[0]), leaf) + return FORMAT.sub(replace, value) + + def source(entry: dict) -> str: english = entry.get("localizations", {}).get("en", {}) unit = english.get("stringUnit") or english.get("variations", {}).get("plural", {}).get("other", {}).get("stringUnit", {}) value = unit.get("value") if not isinstance(value, str): raise ValueError("missing English source value") - return value + return expand_text(value, english.get("substitutions", {})) def plural_nodes(localization: dict): @@ -112,73 +165,106 @@ def omission(key: str, english: str, metadata: dict) -> bool: return record.get("source") == english and record.get("class") in OMISSION_CLASSES -def validate_localization(english: str, localization: dict, locale: str, allow_identity: bool = False) -> list[str]: +def validate_localization(english: str, localization: dict, locale: str, allow_identity: bool = False, + source_localization: dict | None = None) -> list[str]: errors = [] - expected = placeholders(english) - found_units = list(units(localization)) - if not found_units: - return ["missing translated string unit or variations"] - substitutions = localization.get("substitutions", {}) - for location, unit in found_units: + expected = signature(english) + expected_arguments = {argument: specifier for argument, specifier in expected if argument} + source_values = {canonical_text(english)} + reference = source_localization or {} + for _, source_unit in units(reference): + value = source_unit.get("value") + if isinstance(value, str): + for category in ("zero", "one", "two", "few", "many", "other"): + source_values.add(canonical_text(expand_text(value, reference.get("substitutions", {}), category))) + for substitution in reference.get("substitutions", {}).values(): + for _, source_unit in units(substitution): + value = source_unit.get("value") + if isinstance(value, str): + source_values.add(canonical_text(value)) + + def validate_unit(location, unit): value = unit.get("value") if unit.get("state") != "translated": errors.append(f"{location}: state is {unit.get('state')!r}") if not isinstance(value, str) or not value.strip(): errors.append(f"{location}: empty value") - continue - actual = [] - for token in placeholders(value): - if token.startswith("%#@"): - substitution = substitutions.get(token[3:-1], {}) - argument = substitution.get("argNum") - if not isinstance(argument, int) or not 1 <= argument <= len(expected): - errors.append(f"{location}: invalid substitution {token}") - continue - actual.append(expected[argument - 1]) - else: - actual.append(token) - if actual != expected: - errors.append(f"{location}: placeholders {actual!r} != {expected!r}") - if value == english and locale != "en" and not allow_identity: - errors.append(f"{location}: identical to English; translate or document an invariant literal") + return None if MARKER.search(value): errors.append(f"{location}: unfinished translation marker") if BIDI.search(value): errors.append(f"{location}: bidi controls require explicit review") + return value + + def check_identity(location, value, *, numeric_leaf=False): + if locale == "en" or allow_identity: + return + # A numeric substitution leaf may legitimately be only its format token; + # the parent supplies translated words. Text-bearing leaves may not copy English. + if numeric_leaf and not FORMAT.sub("", value).strip(): + return + if canonical_text(value) in source_values: + errors.append(f"{location}: identical to English; translate or document an invariant literal") + + substitutions = localization.get("substitutions", {}) + found_units = list(units(localization)) + if not found_units: + errors.append("missing translated string unit or variations") + referenced = set() + for location, unit in found_units: + value = validate_unit(location, unit) + if value is None: + continue + referenced.update(name for token in placeholders(value) if (name := substitution_name(token)) is not None) + try: + actual = signature(value, substitutions) + if actual != expected: + errors.append(f"{location}: placeholders {actual!r} != {expected!r}") + for category in ("zero", "one", "two", "few", "many", "other"): + check_identity(location, expand_text(value, substitutions, category)) + except ValueError as error: + errors.append(f"{location}: {error}") for name, substitution in substitutions.items(): argument = substitution.get("argNum") specifier = substitution.get("formatSpecifier") - if not isinstance(argument, int) or not 1 <= argument <= len(expected): + if name not in referenced: + errors.append(f"substitution {name}: not referenced by parent text") + if type(argument) is not int or argument not in expected_arguments: errors.append(f"substitution {name}: invalid argument number") continue - expected_specifier = re.sub(r"^%(?:\d+\$)?", "", expected[argument - 1]) - if specifier != expected_specifier: + if specifier != expected_arguments[argument]: errors.append(f"substitution {name}: format specifier does not match source") - for location, unit in units(substitution): - value = unit.get("value") - if unit.get("state") != "translated" or not isinstance(value, str) or not value.strip(): - errors.append(f"substitution {name}{location}: missing translated value") - elif placeholders(value) != [f"%{specifier}"]: - errors.append(f"substitution {name}{location}: count placeholder does not match source") - elif MARKER.search(value) or BIDI.search(value): - errors.append(f"substitution {name}{location}: unfinished or bidi marker") + leaves = list(units(substitution)) + if not leaves: + errors.append(f"substitution {name}: missing translated value") + for location, unit in leaves: + location = f"substitution {name}{location}" + value = validate_unit(location, unit) + if value is not None: + if placeholders(value) != [f"%{specifier}"]: + errors.append(f"{location}: count placeholder does not match source") + check_identity(location, value, numeric_leaf=True) required = CATEGORIES.get(locale, {"other"} if locale in {"zh-Hans", "zh-Hant", "ko", "ja"} else {"one", "other"}) for argument, variants in plural_nodes(localization): if required - set(variants): errors.append(f"argument {argument}: missing plural categories {sorted(required - set(variants))}") - return errors + for category, node in variants.items(): + if not list(units(node)): + errors.append(f"argument {argument}/{category}: missing translated string unit") + return list(dict.fromkeys(errors)) def check_entry(entry: Member, locale: str, omissions: dict, counts: dict) -> list[str]: english = source(entry.value) - allowed = locale not in {"en", "ja"} and omission(entry.key, english, omissions) + allowed = omission(entry.key, english, omissions) localization = entry.value.get("localizations", {}).get(locale) if localization is None: return [] if allowed and locale not in {"en", "ja"} else ["missing locale entry"] - errors = validate_localization(english, localization, locale, allowed) + errors = validate_localization(english, localization, locale, allowed, + entry.value.get("localizations", {}).get("en")) count = counts.get(entry.key) if count: - if count["source"] != english: + if canonical_text(count["source"]) != canonical_text(english): errors.append("count source changed; review plural argument metadata") present = {argument for argument, _ in plural_nodes(localization)} for argument in count["arguments"]: @@ -221,11 +307,11 @@ def merge(path: Path, locale: str, rows: list[dict], omissions: dict) -> int: text = path.read_text(encoding="utf-8") indexed = {} for entry in catalog_entries(text): - indexed.setdefault((entry.key, source(entry.value)), []).append(entry) + indexed.setdefault((entry.key, canonical_text(source(entry.value))), []).append(entry) changes = [] seen = set() for row in rows: - identity = (row["key"], row["source"]) + identity = (row["key"], canonical_text(row["source"])) if identity in seen or identity not in indexed: raise ValueError(f"{row['key']}: duplicate row, unknown key, or stale English source") seen.add(identity) @@ -238,7 +324,9 @@ def merge(path: Path, locale: str, rows: list[dict], omissions: dict) -> int: raise ValueError(f"{entry.key}: provide the full localization to update variations") localization = copy.deepcopy(current) localization.setdefault("stringUnit", {}).update(state="translated", value=row["value"]) - errors = validate_localization(identity[1], localization, locale, omission(entry.key, identity[1], omissions)) + errors = validate_localization(source(entry.value), localization, locale, + omission(entry.key, source(entry.value), omissions), + entry.value.get("localizations", {}).get("en")) if errors: raise ValueError(f"{entry.key}: {'; '.join(errors)}") if localization != current: From 5633d557b68bdd56e02b57d7afd4cbcb4ea4801c Mon Sep 17 00:00:00 2001 From: Austin Wang Date: Tue, 8 Sep 2026 07:02:49 -0700 Subject: [PATCH 05/50] Cover ignored catalog records and locale-specific shared spellings --- tests/test_localization_catalog.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/test_localization_catalog.py b/tests/test_localization_catalog.py index 6c50fcd264ab..587d69cc5095 100644 --- a/tests/test_localization_catalog.py +++ b/tests/test_localization_catalog.py @@ -34,6 +34,20 @@ def counted(parent, one, other, specifier="d"): class LocalizationCatalogTests(unittest.TestCase): + def test_rejects_strings_outside_the_catalog_strings_object(self): + catalog = {"sourceLanguage": "en", "strings": {}, "version": "1.0", + "orphan": {"localizations": {"en": unit("Ignored by Xcode")}}} + with self.assertRaisesRegex(ValueError, "outside.*strings"): + MODULE.catalog_entries(json.dumps(catalog)) + + def test_shared_spelling_exception_is_locale_specific_and_never_allows_omission(self): + entry = MODULE.Member("terminal", {"localizations": {"en": unit("Terminal"), "de": unit("Terminal"), "ja": unit("Terminal")}}, 0, 0) + metadata = {"terminal": {"source": "Terminal", "identityLocales": {"de": "Established German technical term."}}} + self.assertEqual(MODULE.check_entry(entry, "de", metadata, {}), []) + self.assertTrue(MODULE.check_entry(entry, "ja", metadata, {})) + del entry.value["localizations"]["de"] + self.assertIn("missing locale entry", MODULE.check_entry(entry, "de", metadata, {})) + def test_japanese_invariant_requires_entry_but_allows_literal(self): entry = MODULE.Member("brand", {"localizations": {"en": unit("cmux"), "ja": unit("cmux")}}, 0, 0) omissions = {"brand": {"source": "cmux", "class": "brand"}} From ef9ff8fa1fd30ddd5dbb4e48a65b4f72d525300b Mon Sep 17 00:00:00 2001 From: Austin Wang Date: Tue, 8 Sep 2026 07:04:27 -0700 Subject: [PATCH 06/50] Restore ignored catalog records and reuse verified locale data --- .../Resources/Localizable.xcstrings | 174 + Resources/Localizable.xcstrings | 108358 ++++++++++----- scripts/localization-allowed-omissions.json | 1122 +- scripts/localization-plurals.json | 389 +- scripts/localization_catalog.py | 21 +- 5 files changed, 75823 insertions(+), 34241 deletions(-) diff --git a/Packages/macOS/CmuxFeedback/Sources/CmuxFeedback/ComposerUI/Resources/Localizable.xcstrings b/Packages/macOS/CmuxFeedback/Sources/CmuxFeedback/ComposerUI/Resources/Localizable.xcstrings index dad2c6fff85c..a949db46b19c 100644 --- a/Packages/macOS/CmuxFeedback/Sources/CmuxFeedback/ComposerUI/Resources/Localizable.xcstrings +++ b/Packages/macOS/CmuxFeedback/Sources/CmuxFeedback/ComposerUI/Resources/Localizable.xcstrings @@ -144,6 +144,30 @@ "state": "translated", "value": "취소" } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Annuler" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Cancelar" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "取消" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "取消" + } } } }, @@ -202,6 +226,42 @@ "state": "translated", "value": "완료" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Erledigt" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Fait" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "منتهي" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Hecho" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "完畢" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "完毕" + } } } }, @@ -434,6 +494,36 @@ "state": "translated", "value": "메시지" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Nachricht" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "رسالة" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Mensaje" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "訊息" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "信息" + } } } }, @@ -579,6 +669,18 @@ "state": "translated", "value": "제거" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Entfernen" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Eliminar" + } } } }, @@ -608,6 +710,42 @@ "state": "translated", "value": "보내기" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Schicken" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Envoyer" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "يرسل" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Enviar" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "傳送" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "发送" + } } } }, @@ -695,6 +833,42 @@ "state": "translated", "value": "피드백 보내기" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Feedback senden" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Envoyer des commentaires" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "إرسال الملاحظات" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Enviar comentarios" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "傳送回饋" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "发送反馈" + } } } }, diff --git a/Resources/Localizable.xcstrings b/Resources/Localizable.xcstrings index 8f92993742c9..89e6f710cefb 100644 --- a/Resources/Localizable.xcstrings +++ b/Resources/Localizable.xcstrings @@ -23,6 +23,12 @@ "state": "translated", "value": "使用方法: cmux read-screen [flags]\n\nサーフェスのターミナルテキストをプレーンテキストとして読み取ります。\n\nフラグ:\n --workspace 対象ワークスペース(既定: $CMUX_WORKSPACE_ID)\n --surface 対象サーフェス(既定: $CMUX_SURFACE_ID)\n --window ワークスペース/サーフェスの参照とインデックスに使うウィンドウコンテキスト\n --scrollback 表示中のビューポートだけでなくスクロールバックも含める\n --lines 末尾 n 行に制限する(--scrollback を含意)\n --selection アクティブな選択範囲だけを読み取る(--scrollback、--lines との併用不可)\n\n例:\n cmux read-screen\n cmux read-screen --surface surface:2 --scrollback --lines 200\n cmux read-screen --surface surface:2 --selection" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux read-screen [flags]\n\n以纯文本读取某个表面的终端文本。\n\n标志:\n --workspace 目标工作区(默认:$CMUX_WORKSPACE_ID)\n --surface 目标表面(默认:$CMUX_SURFACE_ID)\n --window 工作区/表面引用与索引的窗口上下文\n --scrollback 包含回滚内容(不只是可见视口)\n --lines 限制为最后 n 行(隐含 --scrollback)\n --selection 只读取当前选区;不能与 --scrollback 或 --lines 同用\n\n示例:\n cmux read-screen\n cmux read-screen --surface surface:2 --scrollback --lines 200\n cmux read-screen --surface surface:2 --selection" + } } } }, @@ -40,6 +46,12 @@ "state": "translated", "value": "使用方法: cmux read-selection [flags]\n\n選択可能なサーフェスからアクティブな選択範囲を読み取ります。通常出力にはソースコンテキストが含まれ、--json は完全なレスポンスを返します。\n\nフラグ:\n --workspace 対象ワークスペース(既定: $CMUX_WORKSPACE_ID)\n --surface 対象サーフェス(既定: $CMUX_SURFACE_ID)\n --window ワークスペース/サーフェスの参照とインデックスに使うウィンドウコンテキスト\n\n例:\n cmux read-selection --surface surface:2\n cmux read-selection --surface surface:2 --json" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux read-selection [flags]\n\n读取任意可选中表面上的当前选区。纯文本输出包含来源上下文;--json 返回完整响应。\n\n标志:\n --workspace 目标工作区(默认:$CMUX_WORKSPACE_ID)\n --surface 目标表面(默认:$CMUX_SURFACE_ID)\n --window 工作区/表面引用与索引的窗口上下文\n\n示例:\n cmux read-selection --surface surface:2\n cmux read-selection --surface surface:2 --json" + } } } }, @@ -57,6 +69,12 @@ "state": "translated", "value": "選択範囲あり: false" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "有选区: false" + } } } }, @@ -74,6 +92,12 @@ "state": "translated", "value": "read-screen: --selection は --scrollback または --lines と併用できません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "read-screen: --selection 不能与 --scrollback 或 --lines 同用" + } } } }, @@ -91,6 +115,12 @@ "state": "translated", "value": "%@: 予期しない引数: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%@: 多余的参数: %@" + } } } }, @@ -108,6 +138,12 @@ "state": "translated", "value": "ファイル: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "文件: %@" + } } } }, @@ -125,6 +161,12 @@ "state": "translated", "value": "種類: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "类型: %@" + } } } }, @@ -142,6 +184,12 @@ "state": "translated", "value": "行: %lld" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "行: %lld" + } } } }, @@ -159,6 +207,12 @@ "state": "translated", "value": "行: %lld-%lld" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "行: %lld-%lld" + } } } }, @@ -176,6 +230,12 @@ "state": "translated", "value": "URL: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "URL: %@" + } } } }, @@ -193,6 +253,12 @@ "state": "translated", "value": "read-screen [--workspace ] [--surface ] [--window ] [--scrollback] [--lines ] [--selection]" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "read-screen [--workspace ] [--surface ] [--window ] [--scrollback] [--lines ] [--selection]" + } } } }, @@ -210,6 +276,12 @@ "state": "translated", "value": "read-selection [--workspace ] [--surface ] [--window ]" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "read-selection [--workspace ] [--surface ] [--window ]" + } } } }, @@ -227,6 +299,12 @@ "state": "translated", "value": "フォーカスされているサーフェスがありません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有处于聚焦状态的表面。" + } } } }, @@ -244,6 +322,12 @@ "state": "translated", "value": "`%@` のセレクターが無効です。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "`%@` 的选择器无效。" + } } } }, @@ -261,6 +345,12 @@ "state": "translated", "value": "指定したサーフェスセレクターに一致するサーフェスが見つかりません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "按给定的表面选择器未找到表面。" + } } } }, @@ -278,6 +368,12 @@ "state": "translated", "value": "現在、選択範囲を読み取れません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "当前无法读取选区。" + } } } }, @@ -295,6 +391,12 @@ "state": "translated", "value": "現在、選択範囲を読み取れません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "当前无法读取选区。" + } } } }, @@ -312,6 +414,12 @@ "state": "translated", "value": "リクエストは5秒後にタイムアウトしました。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请求在 5 秒后超时" + } } } }, @@ -329,6 +437,12 @@ "state": "translated", "value": "このサーフェスは選択範囲の読み取りに対応していません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "此表面不支持读取选区。" + } } } }, @@ -346,6 +460,12 @@ "state": "translated", "value": "ワークスペースが見つかりません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到工作区。" + } } } }, @@ -613,6 +733,12 @@ "state": "translated", "value": "コンピュータ操作カーソル" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Computer Use 光标" + } } } }, @@ -630,6 +756,12 @@ "state": "translated", "value": "cmux Computer Use — バックグラウンドで実行中" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux Computer Use —— 正在后台运行" + } } } }, @@ -647,6 +779,12 @@ "state": "translated", "value": "バックグラウンドで続行" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在后台继续" + } } } }, @@ -664,6 +802,12 @@ "state": "translated", "value": "コンピュータ操作にフォーカス" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "聚焦 Computer Use" + } } } }, @@ -681,6 +825,12 @@ "state": "translated", "value": "呼び出し元のターミナルにフォーカス" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "聚焦调用方终端" + } } } }, @@ -698,6 +848,12 @@ "state": "translated", "value": "コンピュータ操作の履歴はまだありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "暂无 Computer Use 活动" + } } } }, @@ -715,6 +871,12 @@ "state": "translated", "value": "実行中のエージェントセッションはありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有活跃的代理会话" + } } } }, @@ -732,6 +894,48 @@ "state": "translated", "value": "%1$@ · %2$@" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "%1$@ · %2$@" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "%1$@ · %2$@" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "%1$@ · %2$@" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "%1$@ · %2$@" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "%1$@ · %2$@" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%1$@ · %2$@" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "%1$@ · %2$@" + } } } }, @@ -749,6 +953,12 @@ "state": "translated", "value": "%1$@ — %2$@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%1$@ —— %2$@" + } } } }, @@ -766,6 +976,12 @@ "state": "translated", "value": "%@の使用を停止" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "停止使用 %@" + } } } }, @@ -783,6 +999,12 @@ "state": "translated", "value": "cmux Computer Use" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux Computer Use" + } } } }, @@ -800,6 +1022,12 @@ "state": "translated", "value": "アプリ" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "应用" + } } } }, @@ -817,6 +1045,12 @@ "state": "translated", "value": "不明なワークスペース" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知工作区" + } } } }, @@ -834,6 +1068,12 @@ "state": "translated", "value": "コンピュータ操作を表示" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "查看 Computer Use" + } } } }, @@ -851,6 +1091,12 @@ "state": "translated", "value": "cmuxがアプリのインターフェースにアクセスできるようにします" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "允许 cmux 访问应用界面" + } } } }, @@ -868,6 +1114,12 @@ "state": "translated", "value": "アクセシビリティを許可すると、Computer Useヘルパーはエージェントに操作を依頼したアプリのコントロールを確認し、ボタンのクリックや文字入力を行えます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "辅助功能让 Computer Use 助手能够检查控件、点按按钮,并在你让代理使用的应用中输入。" + } } } }, @@ -885,6 +1137,12 @@ "state": "translated", "value": "アクセシビリティ" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "辅助功能" + } } } }, @@ -902,6 +1160,12 @@ "state": "translated", "value": "アクセシビリティを許可" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "授予辅助功能权限" + } } } }, @@ -919,6 +1183,12 @@ "state": "translated", "value": "許可" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "允许" + } } } }, @@ -936,6 +1206,48 @@ "state": "translated", "value": "戻る" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Zurück" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Dos" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "خلف" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Atrás" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "後退" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "返回" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "뒤쪽에" + } } } }, @@ -953,6 +1265,12 @@ "state": "translated", "value": "%@をアクセシビリティにドラッグ" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "将 %@ 拖入「辅助功能」" + } } } }, @@ -970,6 +1288,12 @@ "state": "translated", "value": "macOSのダイアログで画面収録を許可してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 macOS 提示中允许屏幕捕捉" + } } } }, @@ -987,6 +1311,12 @@ "state": "translated", "value": "このシステム警告は想定どおりの動作です。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "此处出现系统的“绕过”警告属于正常现象。" + } } } }, @@ -1004,6 +1334,12 @@ "state": "translated", "value": "%@をスクリーンショットにドラッグ" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "将 %@ 拖入「屏幕快照」" + } } } }, @@ -1021,6 +1357,12 @@ "state": "translated", "value": "その後、オンにしてください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "然后将其打开。" + } } } }, @@ -1038,6 +1380,12 @@ "state": "translated", "value": "システム設定で%@を完了" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在「系统设置」中完成 %@" + } } } }, @@ -1055,6 +1403,12 @@ "state": "translated", "value": "システム設定で完了" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在「系统设置」中完成" + } } } }, @@ -1072,6 +1426,48 @@ "state": "translated", "value": "続ける" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Weitermachen" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Continuer" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "يكمل" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Continuar" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "繼續" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "继续" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "계속하다" + } } } }, @@ -1089,6 +1485,48 @@ "state": "translated", "value": "完了" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Erledigt" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Fait" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "منتهي" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Hecho" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "完畢" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "完成" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "완료" + } } } }, @@ -1106,6 +1544,12 @@ "state": "translated", "value": "設定が完了しました。cmuxにこのMac上のアプリの操作を依頼できます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "设置已完成。现在你可以让 cmux 使用这台 Mac 上的应用了。" + } } } }, @@ -1123,6 +1567,12 @@ "state": "translated", "value": "cmux Computer Useの準備ができました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux Computer Use 已就绪" + } } } }, @@ -1140,6 +1590,12 @@ "state": "translated", "value": "ドラッグ" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "拖移" + } } } }, @@ -1157,6 +1613,12 @@ "state": "translated", "value": "このアプリをシステム設定のリストにドラッグしてオンにし、ここに戻ってください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "把这个应用拖到「系统设置」的列表里,打开它,然后回到这里。" + } } } }, @@ -1174,6 +1636,12 @@ "state": "translated", "value": "このウインドウではなく、アプリカードを権限リストにドラッグしてください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请拖移应用卡片,而不是这个窗口,把它拖到权限列表中。" + } } } }, @@ -1191,6 +1659,12 @@ "state": "translated", "value": "%@を権限リストにドラッグ" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "将 %@ 拖入权限列表" + } } } }, @@ -1208,6 +1682,12 @@ "state": "translated", "value": "スクリーンショットへのアクセスを完了" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "完成屏幕快照授权" + } } } }, @@ -1225,6 +1705,12 @@ "state": "translated", "value": "macOSが画面収録の確認を求めています。\nシステムの警告で「許可」を選択するとセットアップが完了します。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "macOS 正在请求确认屏幕捕捉。\n请在系统提示中选择「允许」以完成设置。" + } } } }, @@ -1242,6 +1728,12 @@ "state": "translated", "value": "cmux Computer UseがこのMac上のアプリを操作するには、これらの権限が必要です。\n権限は、cmuxにタスクを依頼したときに使用されます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux Computer Use 需要这些权限才能使用你 Mac 上的应用。\n这些权限只在你让 cmux 执行任务时才会用到。" + } } } }, @@ -1259,6 +1751,12 @@ "state": "translated", "value": "権限は独立したcmux Computer Useヘルパーに付与され、cmuxターミナル本体には付与されません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "权限授予的是独立的 cmux Computer Use 助手 —— cmux 终端本身永远不会获得这些权限。" + } } } }, @@ -1276,6 +1774,12 @@ "state": "translated", "value": "cmux Computer Useを有効にする" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "启用 cmux Computer Use" + } } } }, @@ -1293,6 +1797,48 @@ "state": "translated", "value": "もう一度確認" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Überprüfen Sie es erneut" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Revérifier" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "تحقق مرة أخرى" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Comprobar de nuevo" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "再次檢查" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "重新检查" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "다시 확인하세요" + } } } }, @@ -1310,6 +1856,12 @@ "state": "translated", "value": "確認中…" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "正在检查…" + } } } }, @@ -1327,6 +1879,48 @@ "state": "translated", "value": "今はしない" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Nicht jetzt" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Pas maintenant" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "ليس الآن" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Ahora no" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "現在不要" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "以后再说" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "지금은 아님" + } } } }, @@ -1344,6 +1938,12 @@ "state": "translated", "value": "選択したアプリをエージェントが操作できます" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "让代理在你指定的应用之间工作" + } } } }, @@ -1361,6 +1961,12 @@ "state": "translated", "value": "コンピュータ操作" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Computer Use" + } } } }, @@ -1378,6 +1984,12 @@ "state": "translated", "value": "システム設定を開く" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "打开「系统设置」" + } } } }, @@ -1395,6 +2007,12 @@ "state": "translated", "value": "選択したアプリを操作" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "控制你指定的应用" + } } } }, @@ -1412,6 +2030,12 @@ "state": "translated", "value": "ターミナル以外の操作が必要なとき、対応するエージェントはローカルアプリを表示して操作できます。権限は別のヘルパーに付与されるため、許可後にcmuxを再起動する必要はありません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "当任务超出终端能力范围时,受支持的代理可以查看并操作本地应用。权限归属于一个独立的助手,因此授权时无需重启 cmux。" + } } } }, @@ -1429,6 +2053,12 @@ "state": "translated", "value": "独立したcmux Computer Useの権限でローカル実行" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在本地运行,使用独立的 cmux Computer Use 权限" + } } } }, @@ -1446,6 +2076,12 @@ "state": "translated", "value": "権限の変更後に再起動が必要なのはComputer Useヘルパーだけです。cmuxは開いたままです。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "权限变更后只需重启 Computer Use 助手,cmux 保持打开。" + } } } }, @@ -1463,6 +2099,12 @@ "state": "translated", "value": "アプリウインドウと画面内容を表示" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "查看应用窗口与屏幕内容" + } } } }, @@ -1480,6 +2122,12 @@ "state": "translated", "value": "仕組み" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "工作原理" + } } } }, @@ -1497,6 +2145,12 @@ "state": "translated", "value": "ドライバーのテレメトリと更新確認は無効" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "驱动遥测与更新检查均已禁用" + } } } }, @@ -1514,6 +2168,12 @@ "state": "translated", "value": "エージェントがこのMac上のアプリを操作できます" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "代理可以在这台 Mac 的各个应用间工作" + } } } }, @@ -1531,6 +2191,12 @@ "state": "translated", "value": "次のステップに進めます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "你可以继续下一步了。" + } } } }, @@ -1548,6 +2214,12 @@ "state": "translated", "value": "権限が許可されました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已授予权限" + } } } }, @@ -1565,6 +2237,12 @@ "state": "translated", "value": "システム設定で%@をオンにしてから、ここに戻ってください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在「系统设置」中打开 %@,然后回到这里。" + } } } }, @@ -1582,6 +2260,12 @@ "state": "translated", "value": "cmux Computer Useを準備中…" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "正在准备 cmux Computer Use…" + } } } }, @@ -1599,6 +2283,12 @@ "state": "translated", "value": "cmux Computer Useがアプリのウインドウと画面の内容を表示できるようにします" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "允许 cmux Computer Use 查看应用窗口与屏幕内容" + } } } }, @@ -1616,6 +2306,12 @@ "state": "translated", "value": "画面収録を許可すると、Computer Useヘルパーはアプリウインドウや画面内容を確認し、表示されているものを操作できます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "屏幕录制让 Computer Use 助手能够看到应用窗口与屏幕内容,从而根据可见内容进行操作。" + } } } }, @@ -1633,6 +2329,12 @@ "state": "translated", "value": "画面収録" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "屏幕录制" + } } } }, @@ -1650,6 +2352,12 @@ "state": "translated", "value": "画面収録を許可" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "授予屏幕录制权限" + } } } }, @@ -1667,6 +2375,12 @@ "state": "translated", "value": "cmuxはスクリーンショットを使ってクリック位置を判断します" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux 通过屏幕快照判断该点按哪里" + } } } }, @@ -1684,6 +2398,12 @@ "state": "translated", "value": "macOSの確認で画面収録を許可してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "macOS 会请求确认 —— 请允许屏幕捕捉" + } } } }, @@ -1701,6 +2421,12 @@ "state": "translated", "value": "スクリーンショット" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "屏幕快照" + } } } }, @@ -1718,6 +2444,12 @@ "state": "translated", "value": "許可済み" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已授予" + } } } }, @@ -1735,6 +2467,12 @@ "state": "translated", "value": "未許可" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未授予" + } } } }, @@ -1752,6 +2490,12 @@ "state": "translated", "value": "3ステップ中%lld" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "第 %lld 步,共 3 步" + } } } }, @@ -1769,6 +2513,12 @@ "state": "translated", "value": "コンピュータ操作の設定" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Computer Use 设置" + } } } }, @@ -1786,6 +2536,12 @@ "state": "translated", "value": "「コンピュータ操作」のメニューバー項目と自動オンボーディングを表示します。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "显示 Computer Use 菜单栏项与自动引导流程。" + } } } }, @@ -1803,6 +2559,12 @@ "state": "translated", "value": "コンピュータ操作UX" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Computer Use 体验" + } } } }, @@ -1820,6 +2582,12 @@ "state": "translated", "value": "コンピュータ操作を有効にする" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "启用 Computer Use" + } } } }, @@ -1837,6 +2605,12 @@ "state": "translated", "value": "Computer Useは、cmuxに同梱されたcmux Computer Useアプリでローカル実行されます。権限と再起動のライフサイクルはcmuxから独立しています。テレメトリと更新確認は無効です。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Computer Use 在内置的 cmux Computer Use 应用中本地运行。它的权限与重启生命周期都独立于 cmux。遥测与更新检查均已禁用。" + } } } }, @@ -1854,6 +2628,12 @@ "state": "translated", "value": "すでに開いているターミナルも含め、新しく起動するエージェントはコンピュータ操作ツールなしで開始されます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "新启动的代理不再带 Computer Use 工具,已经打开的终端同样如此。" + } } } }, @@ -1871,6 +2651,12 @@ "state": "translated", "value": "対応するエージェントセッションがこのMac上のアプリを表示して操作できます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "受支持的代理会话可以查看并操作这台 Mac 上的应用。" + } } } }, @@ -1888,6 +2674,12 @@ "state": "translated", "value": "アクセシビリティ" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "辅助功能" + } } } }, @@ -1905,6 +2697,12 @@ "state": "translated", "value": "cmux Computer Useがアプリのインターフェースを確認して操作できるようにします。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "让 cmux Computer Use 能够检查并控制应用界面。" + } } } }, @@ -1922,6 +2720,12 @@ "state": "translated", "value": "許可…" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "授予…" + } } } }, @@ -1939,6 +2743,12 @@ "state": "translated", "value": "許可済み" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已授予" + } } } }, @@ -1956,6 +2766,12 @@ "state": "translated", "value": "未許可" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未授予" + } } } }, @@ -1973,6 +2789,48 @@ "state": "translated", "value": "不明" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Unbekannt" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Inconnu" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "مجهول" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Desconocido" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "未知" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "알려지지 않은" + } } } }, @@ -1990,6 +2848,12 @@ "state": "translated", "value": "システム設定を開く" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "打开「系统设置」" + } } } }, @@ -2007,6 +2871,12 @@ "state": "translated", "value": "画面収録" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "屏幕录制" + } } } }, @@ -2024,6 +2894,12 @@ "state": "translated", "value": "cmux Computer Useがアプリウインドウや画面内容を確認できるようにします。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "让 cmux Computer Use 能够看到应用窗口与屏幕内容。" + } } } }, @@ -2041,6 +2917,12 @@ "state": "translated", "value": "権限" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "权限" + } } } }, @@ -2058,6 +2940,12 @@ "state": "translated", "value": "メニューバーにコンピュータ操作を表示" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在菜单栏中显示 Computer Use" + } } } }, @@ -2075,6 +2963,12 @@ "state": "translated", "value": "実行中のエージェントセッションと、そのターミナルや操作対象アプリへのショートカットを表示します。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "显示进行中的代理会话,以及通往其终端和被操作应用的快捷入口。" + } } } }, @@ -2092,6 +2986,12 @@ "state": "translated", "value": "computer use cua accessibility screen capture recording permissions cursor mcp agents menu bar onboarding コンピュータ操作 アクセシビリティ 画面収録 権限 エージェント メニューバー オンボーディング" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "computer use cua accessibility screen capture recording permissions cursor mcp agents menu bar onboarding 电脑操作 辅助功能 屏幕录制 权限 光标 代理 菜单栏 引导" + } } } }, @@ -2109,6 +3009,12 @@ "state": "translated", "value": "computerUse.enabled enable disable computer use cua mcp agent sessions コンピュータ操作 有効 無効 エージェント セッション" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "computerUse.enabled enable disable computer use cua mcp agent sessions 启用 停用 电脑操作 代理 会话" + } } } }, @@ -2126,6 +3032,12 @@ "state": "translated", "value": "accessibility screen recording capture permissions privacy system settings grant アクセシビリティ 画面収録 権限 プライバシー システム設定 許可" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "accessibility screen recording capture permissions privacy system settings grant 辅助功能 屏幕录制 捕捉 权限 隐私 系统设置 授予" + } } } }, @@ -2143,6 +3055,12 @@ "state": "translated", "value": "computerUse.showInMenuBar menu bar menubar status item cursor agents メニューバー ステータス項目 カーソル エージェント" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "computerUse.showInMenuBar menu bar menubar status item cursor agents 菜单栏 状态项 光标 代理" + } } } }, @@ -2160,6 +3078,12 @@ "state": "translated", "value": "computer use accessibility screen recording permissions cursor mcp agents menu bar onboarding コンピュータ操作 アクセシビリティ 画面収録 権限 カーソル エージェント メニューバー オンボーディング" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "computer use accessibility screen recording permissions cursor mcp agents menu bar onboarding 电脑操作 辅助功能 屏幕录制 权限 光标 代理 菜单栏 引导" + } } } }, @@ -2194,6 +3118,12 @@ "state": "translated", "value": "enabled=true または enabled=false を指定してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请传入 enabled=true 或 enabled=false。" + } } } }, @@ -2211,6 +3141,12 @@ "state": "translated", "value": "「Macをスリープさせない」はまだ利用できません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "「保持 Mac 唤醒」尚不可用。" + } } } }, @@ -2728,6 +3664,12 @@ "state": "translated", "value": "使用法: cmux vault [options]\n\nVaultインデックスからエージェントセッションを閲覧・検索・チェックポイント作成・フォークします。\n\nサブコマンド:\n sessions [--agent ] [--folder ] [--limit ]\n インデックス済みセッションを新しい順に一覧表示します。\n search [--limit ]\n セッションを検索します。agent:、repo:、ws:、before:/after: 演算子と\n 引用句をサポートし、新しい順にランク付けされます。\n checkpoints --agent --session \n セッションのチェックポイントタイムラインを一覧表示します。\n checkpoint --agent --session [--name ]\n 現在の先端に手動チェックポイントを作成します。\n fork --agent --session (--checkpoint | --turn ) [--open]\n チェックポイントから新しいセッションをフォークします。--open で\n 新しいワークスペースで開きます。\n\nすべてのサブコマンドは --json をサポートします。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux vault [options]\n\n从 Vault 索引中浏览、搜索、创建检查点并分叉代理会话。\n\n子命令:\n sessions [--agent ] [--folder ] [--limit ]\n 列出已索引的代理会话,最新的在前。\n search [--limit ]\n 搜索会话。支持 agent:、repo:、ws:、before:/after:\n 操作符与带引号的短语,按时间新旧排序。\n checkpoints --agent --session \n 列出某个会话的检查点时间线(派生的轮次 + 手动创建)。\n checkpoint --agent --session [--name ]\n 在会话当前顶端创建一个手动命名的检查点。\n fork --agent --session (--checkpoint | --turn ) [--open]\n 从某个检查点分叉出新会话。打印新会话 id\n 及其恢复命令;加 --open 还会在新工作区中打开它。\n\n所有子命令都支持 --json 以输出机器可读格式。" + } } } }, @@ -2745,6 +3687,12 @@ "state": "translated", "value": "セッションがありません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有会话。" + } } } }, @@ -2762,6 +3710,12 @@ "state": "translated", "value": "再開コマンド: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "恢复方式: %@" + } } } }, @@ -2779,6 +3733,12 @@ "state": "translated", "value": "新しいワークスペースで開きました。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已在新工作区中打开。" + } } } }, @@ -2796,6 +3756,12 @@ "state": "translated", "value": "セッション %@ をフォークしました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已分叉会话 %@" + } } } }, @@ -2813,6 +3779,12 @@ "state": "translated", "value": "不明な vault サブコマンド '%@' です。sessions、search、checkpoints、checkpoint、fork を試してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知的 vault 子命令 '%@'。可试:sessions、search、checkpoints、checkpoint、fork" + } } } }, @@ -2830,6 +3802,12 @@ "state": "translated", "value": "cmux vault %2$@ に予期しない引数 '%1$@' が指定されました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux vault %@ 收到多余的参数 '%@'" + } } } }, @@ -2847,6 +3825,12 @@ "state": "translated", "value": "vault にはサブコマンドが必要です。sessions、search、checkpoints、checkpoint、fork を試してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "vault 需要一个子命令。可试:sessions、search、checkpoints、checkpoint、fork" + } } } }, @@ -2864,6 +3848,12 @@ "state": "translated", "value": "このサブコマンドには --agent --session が必要です(cmux vault sessions を参照)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "此子命令需要 --agent --session (参见 cmux vault sessions)" + } } } }, @@ -2881,6 +3871,12 @@ "state": "translated", "value": "vault search にはクエリが必要です。演算子: agent:、repo:、ws:、before:/after:" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "vault search 需要一个查询串。操作符:agent:、repo:、ws:、before:/after:" + } } } }, @@ -2898,6 +3894,12 @@ "state": "translated", "value": "--turn には正の数が必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "--turn 需要一个正数" + } } } }, @@ -2915,6 +3917,12 @@ "state": "translated", "value": "--limit には正の数が必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "--limit 需要一个正数" + } } } }, @@ -2932,6 +3940,12 @@ "state": "translated", "value": "vault fork には --checkpoint または --turn が必要です(cmux vault checkpoints を参照)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "vault fork 需要 --checkpoint 或 --turn (参见 cmux vault checkpoints)" + } } } }, @@ -2949,6 +3963,12 @@ "state": "translated", "value": "注: このエージェントのチェックポイントは表示専用です(フォーク未対応)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "注意:该代理的检查点仅供查看(暂不支持分叉)" + } } } }, @@ -2966,6 +3986,12 @@ "state": "translated", "value": "チェックポイントがありません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有检查点。" + } } } }, @@ -2983,6 +4009,12 @@ "state": "translated", "value": "使用法: cmux automation [引数]\n\nルールは ~/.cmuxterm/automations.json に保存されます。\n例:\n cmux automation list\n cmux automation show surface-needs-input\n cmux automation test surface-needs-input --event '{\"name\":\"agent.needs_input\"}'\n cmux automation enable surface-needs-input\n cmux automation disable surface-needs-input\n cmux automation logs [--limit ]\n cmux automation reload" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux automation [args]\n\n规则存放在 ~/.cmuxterm/automations.json。\n示例:\n cmux automation list\n cmux automation show surface-needs-input\n cmux automation test surface-needs-input --event '{\"name\":\"agent.needs_input\"}'\n cmux automation enable surface-needs-input\n cmux automation disable surface-needs-input\n cmux automation logs [--limit ]\n cmux automation reload" + } } } }, @@ -3000,6 +4032,12 @@ "state": "translated", "value": "自動化アクションを準備できませんでした。ルール設定を確認して、もう一度お試しください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法准备该自动化动作。请检查规则配置后重试。" + } } } }, @@ -3017,6 +4055,12 @@ "state": "translated", "value": "自動化を利用できません。~/.cmuxterm/automations.json を確認して、cmux automation reload を実行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "自动化不可用。请检查 ~/.cmuxterm/automations.json,然后运行 cmux automation reload。" + } } } }, @@ -3034,6 +4078,12 @@ "state": "translated", "value": "この自動化アクションにはサーフェスをフォーカスまたは選択する権限が必要です。ルールでフォーカスを許可して、もう一度お試しください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "此自动化动作需要聚焦或选中表面的权限。请更新规则以允许聚焦,然后重试。" + } } } }, @@ -3051,6 +4101,12 @@ "state": "translated", "value": "サポートされていない自動化設定バージョン %lld です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "不支持的自动化配置版本 %lld" + } } } }, @@ -3068,6 +4124,12 @@ "state": "translated", "value": "無効な自動化ルール: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无效的自动化规则:%@" + } } } }, @@ -3085,6 +4147,12 @@ "state": "translated", "value": "自動化設定が 4 MiB を超えています" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "自动化配置超过 4 MiB" + } } } }, @@ -3102,6 +4170,12 @@ "state": "translated", "value": "自動化ルール ID がありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "缺少自动化规则 id" + } } } }, @@ -3119,6 +4193,12 @@ "state": "translated", "value": "自動化ルールが見つかりません: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到自动化规则:%@" + } } } }, @@ -3136,6 +4216,12 @@ "state": "translated", "value": "automation.test にはイベントオブジェクトが必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "automation.test 需要 event 对象" + } } } }, @@ -3153,6 +4239,12 @@ "state": "translated", "value": "automation test には --event が必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "automation test 需要 --event " + } } } }, @@ -3170,6 +4262,12 @@ "state": "translated", "value": "automation test のイベントは JSON オブジェクトである必要があります" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "automation test 的 event 必须是 JSON 对象" + } } } }, @@ -3187,6 +4285,12 @@ "state": "translated", "value": "オフラインの自動化テストにはイベントペイロードのワークスペースタグが必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "离线的 automation test 需要事件负载中包含工作区标记" + } } } }, @@ -3204,6 +4308,12 @@ "state": "translated", "value": "自動化ルールはありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有自动化规则" + } } } }, @@ -3221,6 +4331,12 @@ "state": "translated", "value": "%1$@ [%2$@] 条件: %3$@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%1$@ [%2$@] 当 %3$@" + } } } }, @@ -3238,6 +4354,12 @@ "state": "translated", "value": "自動化設定の再読み込みを要求しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已请求重新加载自动化配置" + } } } }, @@ -3255,6 +4377,12 @@ "state": "translated", "value": "%@ を有効にしました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已启用 %@" + } } } }, @@ -3272,6 +4400,12 @@ "state": "translated", "value": "%@ を無効にしました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已禁用 %@" + } } } }, @@ -3289,6 +4423,12 @@ "state": "translated", "value": "%@ の有効化要求をキューに追加しました。完了を確認するには cmux automation logs を実行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已排队 %@ 的启用请求。运行 cmux automation logs 确认是否完成。" + } } } }, @@ -3306,6 +4446,12 @@ "state": "translated", "value": "%@ の無効化要求をキューに追加しました。完了を確認するには cmux automation logs を実行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已排队 %@ 的禁用请求。运行 cmux automation logs 确认是否完成。" + } } } }, @@ -3323,6 +4469,12 @@ "state": "translated", "value": "有効" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已启用" + } } } }, @@ -3340,6 +4492,12 @@ "state": "translated", "value": "無効" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已禁用" + } } } }, @@ -3357,6 +4515,12 @@ "state": "translated", "value": "すべて送信" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "全部发出" + } } } }, @@ -3374,6 +4538,12 @@ "state": "translated", "value": "CLI" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "CLI" + } } } }, @@ -3391,6 +4561,12 @@ "state": "translated", "value": "CLI 返信" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "CLI 回复" + } } } }, @@ -3408,6 +4584,12 @@ "state": "translated", "value": "通知を送信" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "发出通知" + } } } }, @@ -3425,6 +4607,42 @@ "state": "translated", "value": "エラー" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Fehler" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Erreur" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "خطأ" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "錯誤" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "错误" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "오류" + } } } }, @@ -3442,6 +4660,12 @@ "state": "translated", "value": "フィード終了プラン" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Feed 退出计划" + } } } }, @@ -3459,6 +4683,12 @@ "state": "translated", "value": "フィード権限" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Feed 权限" + } } } }, @@ -3476,6 +4706,12 @@ "state": "translated", "value": "フィード質問" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Feed 提问" + } } } }, @@ -3493,6 +4729,12 @@ "state": "translated", "value": "フィード質問(4つの選択肢)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Feed 提问(4 个选项)" + } } } }, @@ -3510,6 +4752,12 @@ "state": "translated", "value": "フィード質問(多数の選択肢)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Feed 提问(多个选项)" + } } } }, @@ -3527,6 +4775,12 @@ "state": "translated", "value": "フィード質問(複数質問)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Feed 提问(多条)" + } } } }, @@ -3544,6 +4798,12 @@ "state": "translated", "value": "フィード質問(複数選択)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Feed 提问(多选)" + } } } }, @@ -3561,6 +4821,12 @@ "state": "translated", "value": "フック失敗" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Hook 失败" + } } } }, @@ -3578,6 +4844,12 @@ "state": "translated", "value": "アイドル通知" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "空闲提醒" + } } } }, @@ -3595,6 +4867,12 @@ "state": "translated", "value": "通知デバッグモード" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "通知调试模式" + } } } }, @@ -3612,6 +4890,12 @@ "state": "translated", "value": "権限が必要" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "需要权限" + } } } }, @@ -3629,6 +4913,12 @@ "state": "translated", "value": "OSC" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "OSC" + } } } }, @@ -3646,6 +4936,12 @@ "state": "translated", "value": "ターン完了" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "轮次完成" + } } } }, @@ -3663,6 +4959,12 @@ "state": "translated", "value": "不明な種類、または通知対象がありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知类型或没有通知目标" + } } } }, @@ -3680,6 +4982,12 @@ "state": "translated", "value": "enabled=true または enabled=false を指定して、通知デバッグモードのオン/オフを切り替えてください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "传入 enabled=true 或 enabled=false 以开启或关闭通知调试模式。" + } } } }, @@ -3697,6 +5005,12 @@ "state": "translated", "value": "kind=<通知の種類> を指定して、発行するデバッグ通知を選んでください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "传入 kind= 以选择要发出哪种调试通知。" + } } } }, @@ -3714,6 +5028,12 @@ "state": "translated", "value": "合成 %@ 通知" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "合成的 %@ 通知" + } } } }, @@ -3731,6 +5051,12 @@ "state": "translated", "value": "選択肢 %d" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "选项 %d" + } } } }, @@ -3748,6 +5074,12 @@ "state": "translated", "value": "通知を確認し、アクションを検証します。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请检查该通知并验证其中的操作。" + } } } }, @@ -3765,6 +5097,12 @@ "state": "translated", "value": "通知デバッグの回答を選択" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "选择一个通知调试答案" + } } } }, @@ -3782,6 +5120,12 @@ "state": "translated", "value": "通知デバッグ" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "通知调试" + } } } }, @@ -3799,6 +5143,12 @@ "state": "translated", "value": "修正…" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "修改…" + } } } }, @@ -3816,6 +5166,12 @@ "state": "translated", "value": "その他…" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "其他…" + } } } }, @@ -3833,6 +5189,12 @@ "state": "translated", "value": "このエージェントではチェックポイントからのフォークはまだ利用できません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "此代理暂不支持从检查点分叉" + } } } }, @@ -3850,6 +5212,12 @@ "state": "translated", "value": "フォークしたトランスクリプトを書き込めませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法写入分叉出的转录内容" + } } } }, @@ -3867,6 +5235,12 @@ "state": "translated", "value": "予期しないエラーが発生しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "发生了意外错误" + } } } }, @@ -3884,6 +5258,12 @@ "state": "translated", "value": "元のトランスクリプトを読み込めませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法读取原始转录内容" + } } } }, @@ -3901,6 +5281,12 @@ "state": "translated", "value": "元のトランスクリプトファイルが見つかりません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "原始转录文件缺失" + } } } }, @@ -3918,6 +5304,12 @@ "state": "translated", "value": "新しいセッションIDが無効です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "新的会话 id 无效" + } } } }, @@ -3935,6 +5327,12 @@ "state": "translated", "value": "このチェックポイントより前にフォークできる内容がありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "此检查点之前没有可分叉的内容" + } } } }, @@ -3952,6 +5350,12 @@ "state": "translated", "value": "トランスクリプトが大きすぎてフォークできません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "转录内容过大,无法分叉" + } } } }, @@ -3969,6 +5373,12 @@ "state": "translated", "value": "このチェックポイントはトランスクリプトと一致しなくなりました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "此检查点已与转录内容不匹配" + } } } }, @@ -3986,6 +5396,12 @@ "state": "translated", "value": "このエージェントではチェックポイントからのフォークはまだ利用できません。タイムラインは表示専用です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "此代理暂不支持从检查点分叉 —— 时间线仅供查看" + } } } }, @@ -4003,6 +5419,12 @@ "state": "translated", "value": "ターン%lld" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "第 %lld 轮" + } } } }, @@ -4020,6 +5442,12 @@ "state": "translated", "value": "トランスクリプトが長いため、最初期のターンは表示されません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "转录内容过长 —— 最早的轮次未显示" + } } } }, @@ -4037,6 +5465,12 @@ "state": "translated", "value": "トランスクリプト" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "转录" + } } } }, @@ -4054,6 +5488,12 @@ "state": "translated", "value": "チェックポイント" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "检查点" + } } } }, @@ -4071,6 +5511,12 @@ "state": "translated", "value": "チェックポイントを保存できませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法保存检查点" + } } } }, @@ -4088,6 +5534,12 @@ "state": "translated", "value": "トランスクリプト全体を読み込むまで「今すぐチェックポイント」は利用できません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在完整转录读取完成前,「立即创建检查点」不可用" + } } } }, @@ -4105,6 +5557,12 @@ "state": "translated", "value": "トランスクリプトの現在の末尾にチェックポイントを保存" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在转录内容的当前末尾保存一个检查点" + } } } }, @@ -4122,6 +5580,12 @@ "state": "translated", "value": "復元は新しいセッションをフォークして巻き戻します。元のセッションは変更されません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "恢复是通过分叉出新会话来回退的 —— 原会话永远不会被修改" + } } } }, @@ -4139,6 +5603,12 @@ "state": "translated", "value": "今すぐチェックポイント" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "立即创建检查点" + } } } }, @@ -4156,6 +5626,12 @@ "state": "translated", "value": "名前(任意)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "名称(可选)" + } } } }, @@ -4173,6 +5649,12 @@ "state": "translated", "value": "手動チェックポイント" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "手动检查点" + } } } }, @@ -4190,6 +5672,12 @@ "state": "translated", "value": "%@(フォーク)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%@(分叉)" + } } } }, @@ -4207,6 +5695,12 @@ "state": "translated", "value": "ここからフォーク" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "从此处分叉" + } } } }, @@ -4224,6 +5718,12 @@ "state": "translated", "value": "フォークできませんでした: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法分叉:%@" + } } } }, @@ -4241,6 +5741,12 @@ "state": "translated", "value": "チェックポイントはまだありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "暂无检查点" + } } } }, @@ -4258,6 +5764,12 @@ "state": "translated", "value": "上で名前を付けると、ここへ簡単に戻れます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在上方为某个位置命名,方便日后回到这里。" + } } } }, @@ -4275,6 +5787,12 @@ "state": "translated", "value": "フォーク" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "分叉" + } } } }, @@ -4292,6 +5810,12 @@ "state": "translated", "value": "コミットSHAをコピー" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "复制提交 SHA" + } } } }, @@ -4309,6 +5833,42 @@ "state": "translated", "value": "実行中" } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "En direct" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "يعيش" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Vivir" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "居住" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "进行中" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "살다" + } } } }, @@ -4326,6 +5886,12 @@ "state": "translated", "value": "アイドル" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "空闲" + } } } }, @@ -4343,6 +5909,48 @@ "state": "translated", "value": "終了" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Beendet" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Terminé" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "انتهى" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Terminado" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "結束" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已结束" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "종료됨" + } } } }, @@ -4360,6 +5968,12 @@ "state": "translated", "value": "ペインでアクティブ" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在窗格中活动" + } } } }, @@ -4377,6 +5991,48 @@ "state": "translated", "value": "アクティブ" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Aktiv" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Actif" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "نشط" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Activo" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "使用中" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "活动中" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "활성" + } } } }, @@ -4394,6 +6050,42 @@ "state": "translated", "value": "非アクティブ" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Inaktiv" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Inactif" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "غير نشط" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Inactivo" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "不活动" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "비활성" + } } } }, @@ -4411,6 +6103,12 @@ "state": "translated", "value": "最終アクティビティ" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "最后活动时间" + } } } }, @@ -4428,6 +6126,48 @@ "state": "translated", "value": "フォルダ" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Ordner" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Dossier" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "مجلد" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Carpeta" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "資料夾" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "文件夹" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "접는 사람" + } } } }, @@ -4445,6 +6185,48 @@ "state": "translated", "value": "継続時間" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Dauer" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Durée" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "مدة" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Duración" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "期間" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "时长" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "지속" + } } } }, @@ -4462,6 +6244,48 @@ "state": "translated", "value": "作成日時" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Erstellt" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Créé" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "مخلوق" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Creado" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "已創建" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "创建时间" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "생성됨" + } } } }, @@ -4479,6 +6303,12 @@ "state": "translated", "value": "検索中…" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "正在搜索…" + } } } }, @@ -4496,6 +6326,12 @@ "state": "translated", "value": "一致するセッションはありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有匹配的会话" + } } } }, @@ -4513,6 +6349,12 @@ "state": "translated", "value": "一部のセッション履歴を検索できませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "部分会话历史无法被搜索" + } } } }, @@ -4530,6 +6372,12 @@ "state": "translated", "value": "結果" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "结果" + } } } }, @@ -4547,6 +6395,48 @@ "state": "translated", "value": "最近" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Jüngste" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Récent" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "مؤخرًا" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Reciente" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "最近的" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "最近" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "최근의" + } } } }, @@ -4564,6 +6454,42 @@ "state": "translated", "value": "実行中" } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "En direct" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "يعيش" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Vivir" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "居住" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "进行中" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "살다" + } } } }, @@ -4581,6 +6507,48 @@ "state": "translated", "value": "終了" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Beendet" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Terminé" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "انتهى" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Terminado" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "結束" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已结束" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "종료됨" + } } } }, @@ -4598,6 +6566,12 @@ "state": "translated", "value": "すべてのステータス" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "所有状态" + } } } }, @@ -4615,6 +6589,42 @@ "state": "translated", "value": "ステータス" } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Statut" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "حالة" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Estado" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "地位" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "状态" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "상태" + } } } }, @@ -4632,6 +6642,12 @@ "state": "translated", "value": "フィルタをリセット" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "重置筛选条件" + } } } }, @@ -4649,6 +6665,12 @@ "state": "translated", "value": "すべてのフォルダ" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "所有文件夹" + } } } }, @@ -4666,6 +6688,48 @@ "state": "translated", "value": "フォルダ" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Ordner" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Dossier" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "مجلد" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Carpeta" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "資料夾" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "文件夹" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "접는 사람" + } } } }, @@ -4683,6 +6747,48 @@ "state": "translated", "value": "今日" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Heute" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Aujourd'hui" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "اليوم" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Hoy" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "今天" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "今天" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "오늘" + } } } }, @@ -4700,6 +6806,12 @@ "state": "translated", "value": "過去7日間" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "最近 7 天" + } } } }, @@ -4717,6 +6829,12 @@ "state": "translated", "value": "過去30日間" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "最近 30 天" + } } } }, @@ -4734,6 +6852,12 @@ "state": "translated", "value": "全期間" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "任意时间" + } } } }, @@ -4751,7 +6875,13 @@ "state": "translated", "value": "期間" } - } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "日期" + } + } } }, "sessionIndex.filter.agent.all": { @@ -4768,6 +6898,12 @@ "state": "translated", "value": "すべてのエージェント" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "所有代理" + } } } }, @@ -4785,6 +6921,36 @@ "state": "translated", "value": "エージェント" } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "عامل" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Agente" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "代理人" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "代理" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "대리인" + } } } }, @@ -4802,6 +6968,48 @@ "state": "translated", "value": "昨日" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Gestern" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Hier" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "أمس" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Ayer" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "昨天" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "昨天" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "어제" + } } } }, @@ -4819,6 +7027,48 @@ "state": "translated", "value": "今日" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Heute" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Aujourd'hui" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "اليوم" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Hoy" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "今天" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "今天" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "오늘" + } } } }, @@ -4836,6 +7086,12 @@ "state": "translated", "value": "セッションを並べ替え" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "排序会话" + } } } }, @@ -4853,6 +7109,12 @@ "state": "translated", "value": "並べ替え" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "排序方式" + } } } }, @@ -4870,6 +7132,12 @@ "state": "translated", "value": "セッションを検索…" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "搜索会话…" + } } } }, @@ -4887,6 +7155,12 @@ "state": "translated", "value": "セッションを絞り込む" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "筛选会话" + } } } }, @@ -4904,6 +7178,12 @@ "state": "translated", "value": "検索をクリア" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "清除搜索" + } } } }, @@ -4921,6 +7201,12 @@ "state": "translated", "value": "セッション表示" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "会话视图" + } } } }, @@ -4938,6 +7224,12 @@ "state": "translated", "value": "標準表示" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "默认视图" + } } } }, @@ -4955,6 +7247,12 @@ "state": "translated", "value": "コンパクト表示" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "紧凑视图" + } } } }, @@ -4972,6 +7270,12 @@ "state": "translated", "value": "セッション表示を選択" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "选择会话视图" + } } } }, @@ -4989,6 +7293,12 @@ "state": "translated", "value": "詳細を表示" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "显示详情" + } } } }, @@ -5006,6 +7316,12 @@ "state": "translated", "value": "詳細を非表示" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "隐藏详情" + } } } }, @@ -5023,6 +7339,12 @@ "state": "translated", "value": "不明なエージェントです。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知代理。" + } } } }, @@ -5040,6 +7362,12 @@ "state": "translated", "value": "一致するVaultセッションがありません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有匹配的 Vault 会话。" + } } } }, @@ -5057,6 +7385,12 @@ "state": "translated", "value": "このセッションには読み取り可能なトランスクリプトがありません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "此会话没有可读取的转录内容。" + } } } }, @@ -5074,6 +7408,12 @@ "state": "translated", "value": "agent と session は必須です。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "必须提供 agent 和 session。" + } } } }, @@ -5091,6 +7431,12 @@ "state": "translated", "value": "query は必須です。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "必须提供 query。" + } } } }, @@ -5108,6 +7454,12 @@ "state": "translated", "value": "一致するチェックポイントがありません。vault checkpoints の checkpoint または turn を指定してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有匹配的检查点。请从 vault checkpoints 中取 checkpoint 或 turn 传入。" + } } } }, @@ -5125,6 +7477,48 @@ "state": "translated", "value": "返信" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Antwort" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Répondre" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "رد" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Responder" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "回覆" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "回复" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "회신하다" + } } } }, @@ -5142,6 +7536,48 @@ "state": "translated", "value": "エージェントにメッセージ…" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Nachricht an den Agenten…" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Envoyez un message à l'agent…" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "مراسلة الوكيل…" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Envía un mensaje al agente..." + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "給代理商留言..." + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "给代理发消息…" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "상담원에게 메시지를 보내세요…" + } } } }, @@ -5159,6 +7595,48 @@ "state": "translated", "value": "送信" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Schicken" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Envoyer" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "يرسل" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Enviar" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "傳送" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "发送" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "보내다" + } } } }, @@ -5305,7 +7783,7 @@ "de": { "stringUnit": { "state": "translated", - "value": "Build" + "value": "Bauen" } }, "en": { @@ -5323,7 +7801,7 @@ "fr": { "stringUnit": { "state": "translated", - "value": "Build" + "value": "Construire" } }, "it": { @@ -5335,7 +7813,7 @@ "ja": { "stringUnit": { "state": "translated", - "value": "Build" + "value": "ビルド" } }, "ko": { @@ -6009,6 +8487,12 @@ "state": "translated", "value": "このビルドの対応するソースコード" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "此构建的对应源代码" + } } } }, @@ -6145,6 +8629,12 @@ "state": "translated", "value": "cmux プロジェクトライセンス" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux 项目许可证" + } } } }, @@ -6162,6 +8652,12 @@ "state": "translated", "value": "プロジェクトのソースコード" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "项目源代码" + } } } }, @@ -6338,7 +8834,7 @@ "ja": { "stringUnit": { "state": "translated", - "value": "Version" + "value": "バージョン" } }, "ko": { @@ -6536,6 +9032,12 @@ "state": "translated", "value": "ブラウザを開けませんでした。リンクをコピーして任意のブラウザに貼り付けてください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法打开浏览器。请复制链接并粘贴到任意浏览器中。" + } } } }, @@ -6553,6 +9055,12 @@ "state": "translated", "value": "ブラウザを開きました。そこでサインインを完了してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "浏览器已打开。请在其中完成登录。" + } } } }, @@ -6570,6 +9078,12 @@ "state": "translated", "value": "リンクをコピーできませんでした。代わりにブラウザで開いてください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法复制链接。请改在浏览器中打开。" + } } } }, @@ -6587,6 +9101,12 @@ "state": "translated", "value": "サインインリンクをコピー" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "复制登录链接" + } } } }, @@ -6604,6 +9124,12 @@ "state": "translated", "value": "ブラウザでリンクを開くか、リンクをコピーして任意のブラウザに貼り付けてください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请在浏览器中打开该链接,或复制后粘贴到任意浏览器中。" + } } } }, @@ -6621,6 +9147,12 @@ "state": "translated", "value": "サインインを開けませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法打开登录" + } } } }, @@ -6638,6 +9170,12 @@ "state": "translated", "value": "変更はありません。準備ができたらもう一度試すか、下のブラウザリンクを使用してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未做任何更改。准备好后可重试,或使用下方的浏览器链接。" + } } } }, @@ -6655,6 +9193,12 @@ "state": "translated", "value": "サインインをキャンセルしました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "登录已取消" + } } } }, @@ -6672,6 +9216,12 @@ "state": "translated", "value": "もう一度試して新しい安全なリンクを作成してください。古いリンクではサインインできません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请重试以创建新的安全链接。旧链接无法用于登录。" + } } } }, @@ -6689,6 +9239,12 @@ "state": "translated", "value": "そのサインインリンクは無効です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "该登录链接已失效" + } } } }, @@ -6706,6 +9262,12 @@ "state": "translated", "value": "接続を確認してから、もう一度試してください。アカウントは変更されていません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请检查网络连接后重试。你的账户未发生更改。" + } } } }, @@ -6723,6 +9285,12 @@ "state": "translated", "value": "cmux に接続できません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法连接 cmux" + } } } }, @@ -6740,6 +9308,12 @@ "state": "translated", "value": "Wi-Fi または別のネットワークに接続して、もう一度試してください。このペインは開いたままにできます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请连接 Wi-Fi 或其他网络后重试。可以保持此窗格打开。" + } } } }, @@ -6757,6 +9331,12 @@ "state": "translated", "value": "インターネットに接続されていません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无互联网连接" + } } } }, @@ -6774,6 +9354,12 @@ "state": "translated", "value": "ブラウザでアカウント情報を確認して、もう一度試してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请在浏览器中核对账户信息后重试。" + } } } }, @@ -6791,6 +9377,12 @@ "state": "translated", "value": "cmux でサインインを完了できませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux 无法完成登录" + } } } }, @@ -6808,6 +9400,12 @@ "state": "translated", "value": "しばらくしてからもう一度試してください。アカウントと既存の cmux ワークスペースは変更されていません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请稍后重试。你的账户和现有 cmux 工作区未发生更改。" + } } } }, @@ -6825,6 +9423,12 @@ "state": "translated", "value": "cmux のサインインは一時的に利用できません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux 登录暂时不可用" + } } } }, @@ -6842,6 +9446,12 @@ "state": "translated", "value": "サインインウインドウから cmux に戻りませんでした。ブラウザリンクをもう一度開くか、新しいサインインを開始してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "登录窗口未返回 cmux。请重新打开浏览器链接,或重新发起一次登录。" + } } } }, @@ -6859,6 +9469,12 @@ "state": "translated", "value": "サインインがタイムアウトしました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "登录超时" + } } } }, @@ -6876,6 +9492,12 @@ "state": "translated", "value": "使用する cmux アカウントが正しいことを確認して、もう一度試してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请确认使用的是目标 cmux 账户,然后重试。" + } } } }, @@ -6893,6 +9515,12 @@ "state": "translated", "value": "cmux がこのサインインを承認できませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux 无法授权此次登录" + } } } }, @@ -6910,6 +9538,12 @@ "state": "translated", "value": "もう一度試してください。サインインウインドウが引き続き失敗する場合は、リンクをコピーしてブラウザで開いてください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请重试。如果登录窗口仍然失败,请复制链接并在浏览器中打开。" + } } } }, @@ -6927,6 +9561,12 @@ "state": "translated", "value": "サインインを完了できませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法完成登录" + } } } }, @@ -6944,6 +9584,12 @@ "state": "translated", "value": "cmux にサインイン" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "登录 cmux" + } } } }, @@ -6961,6 +9607,12 @@ "state": "translated", "value": "開いたウインドウでサインインを完了してください。このペインは自動的に更新されます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请在打开的窗口中完成登录。此窗格会自动更新。" + } } } }, @@ -6978,6 +9630,12 @@ "state": "translated", "value": "リンクをコピーしました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "链接已复制" + } } } }, @@ -6995,6 +9653,12 @@ "state": "translated", "value": "サインインを完了しています…" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "正在完成登录…" + } } } }, @@ -7012,6 +9676,12 @@ "state": "translated", "value": "cmux がアカウントを確認しています。このペインを開いたままにしてください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux 正在验证你的账户。请保持此窗格打开。" + } } } }, @@ -7029,6 +9699,12 @@ "state": "translated", "value": "安全なサインインを開いています…" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "正在打开安全登录…" + } } } }, @@ -7046,6 +9722,12 @@ "state": "translated", "value": "cmux が安全なサインインウインドウを準備しています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux 正在准备安全登录窗口。" + } } } }, @@ -7063,6 +9745,12 @@ "state": "translated", "value": "サインインを待機中…" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "正在等待登录…" + } } } }, @@ -7080,6 +9768,12 @@ "state": "translated", "value": "開いたウインドウでサインインを完了してください。このペインは自動的に更新されます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请在打开的窗口中完成登录。此窗格会自动更新。" + } } } }, @@ -7097,6 +9791,12 @@ "state": "translated", "value": "引き続きサインインを待機中…" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "仍在等待登录…" + } } } }, @@ -7114,6 +9814,12 @@ "state": "translated", "value": "サインインウインドウに時間がかかっています。最初からやり直さずに、同じ安全なリンクをもう一度開くかコピーできます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "登录窗口耗时超出预期。你可以重新打开或复制同一个安全链接,无需重新开始。" + } } } }, @@ -7131,6 +9837,12 @@ "state": "translated", "value": "サインインが完了しませんでした。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "登录未完成。" + } } } }, @@ -7148,6 +9860,12 @@ "state": "translated", "value": "ブラウザでもう一度開く" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在浏览器中重新打开" + } } } }, @@ -7165,6 +9883,12 @@ "state": "translated", "value": "cmux アカウントで続行します。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "使用你的 cmux 账户继续。" + } } } }, @@ -7182,6 +9906,48 @@ "state": "translated", "value": "サインイン" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Anmelden" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Se connecter" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "تسجيل الدخول" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Iniciar sesión" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "登入" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "登录" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "로그인" + } } } }, @@ -7199,6 +9965,12 @@ "state": "translated", "value": "cmux アカウントに接続しました。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "你的 cmux 账户已连接。" + } } } }, @@ -7216,6 +9988,12 @@ "state": "translated", "value": "サインインしました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "你已登录" + } } } }, @@ -7233,6 +10011,48 @@ "state": "translated", "value": "もう一度試す" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Versuchen Sie es erneut" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Essayer à nouveau" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "حاول ثانية" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Intentar otra vez" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "再試一次" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "重试" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "다시 시도" + } } } }, @@ -7250,6 +10070,12 @@ "state": "translated", "value": "サインインを待機中…" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "正在等待登录…" + } } } }, @@ -7267,6 +10093,48 @@ "state": "translated", "value": "サインイン" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Anmelden" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Se connecter" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "تسجيل الدخول" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Iniciar sesión" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "登入" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "登录" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "로그인" + } } } }, @@ -8659,6 +11527,12 @@ "state": "translated", "value": "完了" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已完成" + } } } }, @@ -8676,6 +11550,12 @@ "state": "translated", "value": "%@ で完了" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已在 %@ 中完成" + } } } }, @@ -8693,6 +11573,12 @@ "state": "translated", "value": "%@ セッションが完了しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%@ 会话已完成" + } } } }, @@ -8710,6 +11596,12 @@ "state": "translated", "value": "完了" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已完成" + } } } }, @@ -8727,6 +11619,12 @@ "state": "translated", "value": "%@ で完了" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已在 %@ 中完成" + } } } }, @@ -8744,6 +11642,12 @@ "state": "translated", "value": "Codex でエラーが発生しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Codex 报告了一个错误" + } } } }, @@ -8761,6 +11665,12 @@ "state": "translated", "value": "Codex は最終応答を送信する前に終了しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Codex 在发送最终响应前结束" + } } } }, @@ -8778,6 +11688,12 @@ "state": "translated", "value": "Codex 認証エラー" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Codex 认证错误" + } } } }, @@ -8795,6 +11711,12 @@ "state": "translated", "value": "Codex エラー" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Codex 错误" + } } } }, @@ -8812,6 +11734,12 @@ "state": "translated", "value": "Codex ネットワークエラー" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Codex 网络错误" + } } } }, @@ -8829,6 +11757,12 @@ "state": "translated", "value": "Codex レート制限" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Codex 速率限制" + } } } }, @@ -8846,6 +11780,12 @@ "state": "translated", "value": "認証エラー" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "认证错误" + } } } }, @@ -8863,6 +11803,42 @@ "state": "translated", "value": "エラー" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Fehler" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Erreur" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "خطأ" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "錯誤" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "错误" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "오류" + } } } }, @@ -8880,6 +11856,12 @@ "state": "translated", "value": "ネットワークエラー" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "网络错误" + } } } }, @@ -8897,6 +11879,12 @@ "state": "translated", "value": "レート制限" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "速率限制" + } } } }, @@ -9039,6 +12027,12 @@ "state": "translated", "value": "Codex が質問しています" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Codex 正在提问" + } } } }, @@ -9056,6 +12050,12 @@ "state": "translated", "value": "Codex 入力待ち" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Codex 需要输入" + } } } }, @@ -9073,6 +12073,12 @@ "state": "translated", "value": "待機状態" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "等待中" + } } } }, @@ -9090,6 +12096,12 @@ "state": "translated", "value": "入力待ち" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "空闲" + } } } }, @@ -9107,6 +12119,12 @@ "state": "translated", "value": "PID は正の整数でなければなりません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "PID 必须是正整数" + } } } }, @@ -9124,6 +12142,12 @@ "state": "translated", "value": "pid_resolution は corroborated または controlling_tty でなければなりません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "pid_resolution 必须为 corroborated 或 controlling_tty" + } } } }, @@ -9141,6 +12165,12 @@ "state": "translated", "value": "有効な配信先が見つかりません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有活动的投递目标" + } } } }, @@ -9158,6 +12188,12 @@ "state": "translated", "value": "配信先の解決を利用できません。cmux の起動が完了してから再試行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "投递目标解析不可用;请在 cmux 启动完成后重试。" + } } } }, @@ -9550,6 +12586,12 @@ "state": "translated", "value": "承認が必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "需要批准" + } } } }, @@ -9567,6 +12609,12 @@ "state": "translated", "value": "%@ がエラーを報告しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%@ 报告了一个错误" + } } } }, @@ -9584,6 +12632,12 @@ "state": "translated", "value": "タスクが完了しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "任务已完成" + } } } }, @@ -9601,6 +12655,12 @@ "state": "translated", "value": "タスクがエラーを報告しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "任务报告了一个错误" + } } } }, @@ -9618,6 +12678,12 @@ "state": "translated", "value": "入力待ち" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "等待输入" + } } } }, @@ -9635,6 +12701,12 @@ "state": "translated", "value": "%@ エラー" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%@ 错误" + } } } }, @@ -9777,6 +12849,12 @@ "state": "translated", "value": "待機中" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "空闲" + } } } }, @@ -9794,6 +12872,12 @@ "state": "translated", "value": "%@ 入力待ち" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%@ 需要输入" + } } } }, @@ -9811,6 +12895,12 @@ "state": "translated", "value": "確認" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "需关注" + } } } }, @@ -9828,6 +12918,12 @@ "state": "translated", "value": "完了" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已完成" + } } } }, @@ -9845,6 +12941,42 @@ "state": "translated", "value": "エラー" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Fehler" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Erreur" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "خطأ" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "錯誤" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "错误" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "오류" + } } } }, @@ -9862,6 +12994,12 @@ "state": "translated", "value": "権限" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "权限" + } } } }, @@ -9879,6 +13017,12 @@ "state": "translated", "value": "待機中" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "等待中" + } } } }, @@ -9990,7 +13134,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Running" + "value": "运行中" } }, "zh-Hant": { @@ -10015,6 +13159,48 @@ "state": "translated", "value": "%1$@: %2$@" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "%1$@: %2$@" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "%1$@: %2$@" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "%1$@: %2$@" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "%1$@: %2$@" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "%1$@: %2$@" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%1$@: %2$@" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "%1$@: %2$@" + } } } }, @@ -10049,6 +13235,48 @@ "state": "translated", "value": "Ollama" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Ollama" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Ollama" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "أولاما" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Ollama" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "奧拉馬" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "奥拉马" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "올라마" + } } } }, @@ -10165,8 +13393,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "The selected provider is unavailable." + "state": "translated", + "value": "所选提供方不可用。" } }, "zh-Hant": { @@ -10290,8 +13518,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Invalid bridge request." + "state": "translated", + "value": "无效的桥接请求。" } }, "zh-Hant": { @@ -10415,8 +13643,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "The request is incomplete." + "state": "translated", + "value": "请求不完整。" } }, "zh-Hant": { @@ -10540,8 +13768,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "The provider is not ready yet." + "state": "translated", + "value": "提供方尚未就绪。" } }, "zh-Hant": { @@ -10665,8 +13893,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "An agent session is already running." + "state": "translated", + "value": "已有代理会话正在运行。" } }, "zh-Hant": { @@ -10790,8 +14018,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "The agent session is no longer available." + "state": "translated", + "value": "该代理会话已不可用。" } }, "zh-Hant": { @@ -10915,8 +14143,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "This action is not supported." + "state": "translated", + "value": "不支持此操作。" } }, "zh-Hant": { @@ -11040,8 +14268,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Agent transport is not supported." + "state": "translated", + "value": "不支持该代理传输方式。" } }, "zh-Hant": { @@ -11165,8 +14393,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Ran" + "state": "translated", + "value": "已运行" } }, "zh-Hant": { @@ -11290,8 +14518,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Running" + "state": "translated", + "value": "运行中" } }, "zh-Hant": { @@ -11307,8 +14535,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "Stopped" + "state": "translated", + "value": "توقف" } }, "bs": { @@ -11325,8 +14553,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Stopped" + "state": "translated", + "value": "Angehalten" } }, "en": { @@ -11337,14 +14565,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Stopped" + "state": "translated", + "value": "Interrumpido" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Stopped" + "state": "translated", + "value": "Arrêté" } }, "it": { @@ -11367,8 +14595,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Stopped" + "state": "translated", + "value": "중지됨" } }, "nb": { @@ -11415,14 +14643,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Stopped" + "state": "translated", + "value": "已停止" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Stopped" + "state": "translated", + "value": "已停止" } } } @@ -11432,8 +14660,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "Created" + "state": "translated", + "value": "مخلوق" } }, "bs": { @@ -11450,8 +14678,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Created" + "state": "translated", + "value": "Erstellt" } }, "en": { @@ -11462,14 +14690,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Created" + "state": "translated", + "value": "Creado" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Created" + "state": "translated", + "value": "Créé" } }, "it": { @@ -11492,8 +14720,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Created" + "state": "translated", + "value": "생성됨" } }, "nb": { @@ -11540,14 +14768,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Created" + "state": "translated", + "value": "已创建" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Created" + "state": "translated", + "value": "已創建" } } } @@ -11665,8 +14893,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Creating" + "state": "translated", + "value": "正在创建" } }, "zh-Hant": { @@ -11682,8 +14910,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "Deleted" + "state": "translated", + "value": "تم الحذف" } }, "bs": { @@ -11700,8 +14928,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Deleted" + "state": "translated", + "value": "Gelöscht" } }, "en": { @@ -11712,14 +14940,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Deleted" + "state": "translated", + "value": "Eliminado" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Deleted" + "state": "translated", + "value": "Supprimé" } }, "it": { @@ -11742,8 +14970,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Deleted" + "state": "translated", + "value": "삭제됨" } }, "nb": { @@ -11790,14 +15018,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Deleted" + "state": "translated", + "value": "已删除" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Deleted" + "state": "translated", + "value": "已刪除" } } } @@ -11915,8 +15143,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Deleting" + "state": "translated", + "value": "正在删除" } }, "zh-Hant": { @@ -12040,8 +15268,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Edited" + "state": "translated", + "value": "已编辑" } }, "zh-Hant": { @@ -12165,8 +15393,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Editing" + "state": "translated", + "value": "正在编辑" } }, "zh-Hant": { @@ -12290,8 +15518,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Codex app-server response was not valid JSON." + "state": "translated", + "value": "Codex app-server 的响应不是有效的 JSON。" } }, "zh-Hant": { @@ -12415,8 +15643,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Codex app-server request failed." + "state": "translated", + "value": "Codex app-server 请求失败。" } }, "zh-Hant": { @@ -12540,8 +15768,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Request from Codex app-server is not supported: %@" + "state": "translated", + "value": "不支持来自 Codex app-server 的请求:%@" } }, "zh-Hant": { @@ -12665,8 +15893,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Codex app-server reported a warning." + "state": "translated", + "value": "Codex app-server 报告了一条警告。" } }, "zh-Hant": { @@ -12790,8 +16018,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "%@ was not found. Install it and make sure \"%@\" is available on PATH." + "state": "translated", + "value": "未找到 %@。请先安装,并确保 \"%@\" 在 PATH 中可用。" } }, "zh-Hant": { @@ -12915,8 +16143,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "OpenCode event stream disconnected." + "state": "translated", + "value": "OpenCode 事件流已断开。" } }, "zh-Hant": { @@ -13040,8 +16268,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "OpenCode session could not be created." + "state": "translated", + "value": "无法创建 OpenCode 会话。" } }, "zh-Hant": { @@ -13057,8 +16285,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "%@ · %@" + "state": "translated", + "value": "%1$@ · %2$@" } }, "bs": { @@ -13075,8 +16303,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "%@ · %@" + "state": "translated", + "value": "%1$@ · %2$@" } }, "en": { @@ -13087,14 +16315,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "%@ · %@" + "state": "translated", + "value": "%1$@ · %2$@" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "%@ · %@" + "state": "translated", + "value": "%1$@ · %2$@" } }, "it": { @@ -13117,8 +16345,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "%@ · %@" + "state": "translated", + "value": "%1$@ · %2$@" } }, "nb": { @@ -13165,14 +16393,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", + "state": "translated", "value": "%@ · %@" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "%@ · %@" + "state": "translated", + "value": "%1$@ · %2$@" } } } @@ -13290,7 +16518,7 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", + "state": "translated", "value": "Claude Code" } }, @@ -13307,8 +16535,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "Codex" + "state": "translated", + "value": "الدستور الغذائي" } }, "bs": { @@ -13325,8 +16553,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Codex" + "state": "translated", + "value": "Kodex" } }, "en": { @@ -13337,14 +16565,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Codex" + "state": "translated", + "value": "Códice" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Codex" + "state": "translated", + "value": "Manuscrit" } }, "it": { @@ -13367,8 +16595,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Codex" + "state": "translated", + "value": "사본" } }, "nb": { @@ -13415,14 +16643,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", + "state": "translated", "value": "Codex" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Codex" + "state": "translated", + "value": "法典" } } } @@ -13432,8 +16660,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "OpenCode" + "state": "translated", + "value": "كود مفتوح" } }, "bs": { @@ -13450,7 +16678,7 @@ }, "de": { "stringUnit": { - "state": "needs_review", + "state": "translated", "value": "OpenCode" } }, @@ -13462,14 +16690,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "OpenCode" + "state": "translated", + "value": "código abierto" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "OpenCode" + "state": "translated", + "value": "Code Ouvert" } }, "it": { @@ -13492,8 +16720,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "OpenCode" + "state": "translated", + "value": "오픈코드" } }, "nb": { @@ -13540,14 +16768,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", + "state": "translated", "value": "OpenCode" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "OpenCode" + "state": "translated", + "value": "開放程式碼" } } } @@ -13665,7 +16893,7 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", + "state": "translated", "value": "React" } }, @@ -13790,7 +17018,7 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", + "state": "translated", "value": "Solid" } }, @@ -13915,8 +17143,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Add files and more" + "state": "translated", + "value": "添加文件等" } }, "zh-Hant": { @@ -14040,8 +17268,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Add photos & files" + "state": "translated", + "value": "添加照片和文件" } }, "zh-Hant": { @@ -14165,8 +17393,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Attach file" + "state": "translated", + "value": "附加文件" } }, "zh-Hant": { @@ -14290,8 +17518,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Context" + "state": "translated", + "value": "上下文" } }, "zh-Hant": { @@ -14415,8 +17643,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Browse web" + "state": "translated", + "value": "浏览网页" } }, "zh-Hant": { @@ -14540,8 +17768,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Change permissions" + "state": "translated", + "value": "更改权限" } }, "zh-Hant": { @@ -14665,8 +17893,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Collapse shell" + "state": "translated", + "value": "收起 shell" } }, "zh-Hant": { @@ -14790,8 +18018,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "No results" + "state": "translated", + "value": "无结果" } }, "zh-Hant": { @@ -14825,8 +18053,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Copied" + "state": "translated", + "value": "Kopiert" } }, "en": { @@ -14837,14 +18065,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Copied" + "state": "translated", + "value": "Copiado" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Copied" + "state": "translated", + "value": "Copié" } }, "it": { @@ -14867,8 +18095,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Copied" + "state": "translated", + "value": "복사됨" } }, "nb": { @@ -14915,14 +18143,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Copied" + "state": "translated", + "value": "已复制" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Copied" + "state": "translated", + "value": "已複製" } } } @@ -15040,8 +18268,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Copied shell contents" + "state": "translated", + "value": "已复制 shell 内容" } }, "zh-Hant": { @@ -15075,8 +18303,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Copied" + "state": "translated", + "value": "Kopiert" } }, "en": { @@ -15087,14 +18315,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Copied" + "state": "translated", + "value": "Copiado" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Copied" + "state": "translated", + "value": "Copié" } }, "it": { @@ -15117,8 +18345,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Copied" + "state": "translated", + "value": "복사됨" } }, "nb": { @@ -15165,14 +18393,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Copied" + "state": "translated", + "value": "已复制" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Copied" + "state": "translated", + "value": "已複製" } } } @@ -15290,8 +18518,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Copy" + "state": "translated", + "value": "复制" } }, "zh-Hant": { @@ -15415,8 +18643,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Copy output" + "state": "translated", + "value": "复制输出" } }, "zh-Hant": { @@ -15540,8 +18768,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Copy shell contents" + "state": "translated", + "value": "复制 shell 内容" } }, "zh-Hant": { @@ -15665,8 +18893,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Copy message" + "state": "translated", + "value": "复制消息" } }, "zh-Hant": { @@ -15790,8 +19018,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Native bridge request failed." + "state": "translated", + "value": "原生桥接请求失败。" } }, "zh-Hant": { @@ -15915,8 +19143,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "IDE context" + "state": "translated", + "value": "IDE 上下文" } }, "zh-Hant": { @@ -16040,8 +19268,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Include IDE context" + "state": "translated", + "value": "包含 IDE 上下文" } }, "zh-Hant": { @@ -16165,8 +19393,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Provider exited %d" + "state": "translated", + "value": "提供方已退出 %d" } }, "zh-Hant": { @@ -16290,8 +19518,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Provider started" + "state": "translated", + "value": "提供方已启动" } }, "zh-Hant": { @@ -16415,8 +19643,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "%@ ready" + "state": "translated", + "value": "%@ 已就绪" } }, "zh-Hant": { @@ -16449,15 +19677,39 @@ } }, "de": { - "stringUnit": { - "state": "needs_review", - "value": "Sent %d chars" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%d Zeichen gesendet" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%d Zeichen gesendet" + } + } + } } }, "en": { - "stringUnit": { - "state": "translated", - "value": "Sent %d chars" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Sent %d char" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Sent %d chars" + } + } + } } }, "es": { @@ -16540,8 +19792,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Sent %d chars" + "state": "translated", + "value": "已发送 %d 个字符" } }, "zh-Hant": { @@ -16557,8 +19809,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "Stopped" + "state": "translated", + "value": "توقف" } }, "bs": { @@ -16575,8 +19827,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Stopped" + "state": "translated", + "value": "Angehalten" } }, "en": { @@ -16587,14 +19839,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Stopped" + "state": "translated", + "value": "Interrumpido" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Stopped" + "state": "translated", + "value": "Arrêté" } }, "it": { @@ -16617,8 +19869,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Stopped" + "state": "translated", + "value": "중지됨" } }, "nb": { @@ -16665,14 +19917,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Stopped" + "state": "translated", + "value": "已停止" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Stopped" + "state": "translated", + "value": "已停止" } } } @@ -16682,8 +19934,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "Current workspace" + "state": "translated", + "value": "مساحة العمل الحالية" } }, "bs": { @@ -16700,8 +19952,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Current workspace" + "state": "translated", + "value": "Aktueller Arbeitsbereich" } }, "en": { @@ -16712,14 +19964,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Current workspace" + "state": "translated", + "value": "Espacio de trabajo actual" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Current workspace" + "state": "translated", + "value": "Espace de travail actuel" } }, "it": { @@ -16742,8 +19994,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Current workspace" + "state": "translated", + "value": "현재 작업공간" } }, "nb": { @@ -16790,14 +20042,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Current workspace" + "state": "translated", + "value": "当前工作区" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Current workspace" + "state": "translated", + "value": "目前工作空間" } } } @@ -16915,8 +20167,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Mention" + "state": "translated", + "value": "提及" } }, "zh-Hant": { @@ -17040,8 +20292,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Auto-review" + "state": "translated", + "value": "自动审查" } }, "zh-Hant": { @@ -17165,8 +20417,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Custom (config.toml)" + "state": "translated", + "value": "自定义(config.toml)" } }, "zh-Hant": { @@ -17290,8 +20542,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Default permissions" + "state": "translated", + "value": "默认权限" } }, "zh-Hant": { @@ -17415,8 +20667,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Full access" + "state": "translated", + "value": "完全访问" } }, "zh-Hant": { @@ -17540,8 +20792,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Plan mode" + "state": "translated", + "value": "计划模式" } }, "zh-Hant": { @@ -17665,8 +20917,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Use plan mode" + "state": "translated", + "value": "使用计划模式" } }, "zh-Hant": { @@ -17790,8 +21042,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Dismiss suggestion" + "state": "translated", + "value": "忽略建议" } }, "zh-Hant": { @@ -17915,7 +21167,7 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", + "state": "translated", "value": "Shift + Tab" } }, @@ -18040,8 +21292,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Create a plan" + "state": "translated", + "value": "创建计划" } }, "zh-Hant": { @@ -18165,8 +21417,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Ask anything" + "state": "translated", + "value": "问点什么" } }, "zh-Hant": { @@ -18182,8 +21434,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "Provider" + "state": "translated", + "value": "مزود" } }, "bs": { @@ -18200,8 +21452,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Provider" + "state": "translated", + "value": "Anbieter" } }, "en": { @@ -18212,14 +21464,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Provider" + "state": "translated", + "value": "Proveedor" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Provider" + "state": "translated", + "value": "Fournisseur" } }, "it": { @@ -18242,8 +21494,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Provider" + "state": "translated", + "value": "공급자" } }, "nb": { @@ -18290,14 +21542,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Provider" + "state": "translated", + "value": "提供方" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Provider" + "state": "translated", + "value": "提供者" } } } @@ -18790,8 +22042,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Monthly" + "state": "translated", + "value": "每月" } }, "zh-Hant": { @@ -18915,8 +22167,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Primary" + "state": "translated", + "value": "主要" } }, "zh-Hant": { @@ -19040,8 +22292,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "resets" + "state": "translated", + "value": "重置" } }, "zh-Hant": { @@ -19165,8 +22417,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Secondary" + "state": "translated", + "value": "次要" } }, "zh-Hant": { @@ -19290,8 +22542,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Usage remaining" + "state": "translated", + "value": "剩余用量" } }, "zh-Hant": { @@ -19415,8 +22667,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Weekly" + "state": "translated", + "value": "每周" } }, "zh-Hant": { @@ -19540,8 +22792,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Rate limits" + "state": "translated", + "value": "速率限制" } }, "zh-Hant": { @@ -19557,8 +22809,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "High" + "state": "translated", + "value": "عالي" } }, "bs": { @@ -19575,8 +22827,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "High" + "state": "translated", + "value": "Hoch" } }, "en": { @@ -19587,14 +22839,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "High" + "state": "translated", + "value": "Alto" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "High" + "state": "translated", + "value": "Haut" } }, "it": { @@ -19617,8 +22869,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "High" + "state": "translated", + "value": "높은" } }, "nb": { @@ -19665,14 +22917,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "High" + "state": "translated", + "value": "高" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "High" + "state": "translated", + "value": "高的" } } } @@ -19790,8 +23042,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Remove attachment" + "state": "translated", + "value": "移除附件" } }, "zh-Hant": { @@ -19807,8 +23059,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "Send" + "state": "translated", + "value": "يرسل" } }, "bs": { @@ -19825,8 +23077,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Send" + "state": "translated", + "value": "Schicken" } }, "en": { @@ -19837,14 +23089,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Send" + "state": "translated", + "value": "Enviar" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Send" + "state": "translated", + "value": "Envoyer" } }, "it": { @@ -19867,8 +23119,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Send" + "state": "translated", + "value": "보내다" } }, "nb": { @@ -19915,14 +23167,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Send" + "state": "translated", + "value": "发送" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Send" + "state": "translated", + "value": "傳送" } } } @@ -19932,8 +23184,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "Shell" + "state": "translated", + "value": "صدَفَة" } }, "bs": { @@ -19950,8 +23202,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Shell" + "state": "translated", + "value": "Hülse" } }, "en": { @@ -19962,14 +23214,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Shell" + "state": "translated", + "value": "Caparazón" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Shell" + "state": "translated", + "value": "Coquille" } }, "it": { @@ -19992,8 +23244,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Shell" + "state": "translated", + "value": "껍데기" } }, "nb": { @@ -20040,14 +23292,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", + "state": "translated", "value": "Shell" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Shell" + "state": "translated", + "value": "殼" } } } @@ -20165,8 +23417,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Success" + "state": "translated", + "value": "成功" } }, "zh-Hant": { @@ -20290,8 +23542,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Show less" + "state": "translated", + "value": "收起" } }, "zh-Hant": { @@ -20307,8 +23559,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "Show more" + "state": "translated", + "value": "عرض المزيد" } }, "bs": { @@ -20325,8 +23577,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Show more" + "state": "translated", + "value": "Mehr anzeigen" } }, "en": { @@ -20337,14 +23589,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Show more" + "state": "translated", + "value": "Mostrar más" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Show more" + "state": "translated", + "value": "Afficher plus" } }, "it": { @@ -20367,8 +23619,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Show more" + "state": "translated", + "value": "더 보기" } }, "nb": { @@ -20415,14 +23667,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Show more" + "state": "translated", + "value": "展开" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Show more" + "state": "translated", + "value": "顯示更多" } } } @@ -20540,8 +23792,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Code review" + "state": "translated", + "value": "代码审查" } }, "zh-Hant": { @@ -20665,8 +23917,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Skills" + "state": "translated", + "value": "技能" } }, "zh-Hant": { @@ -20790,8 +24042,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Plan" + "state": "translated", + "value": "计划" } }, "zh-Hant": { @@ -20915,8 +24167,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Research" + "state": "translated", + "value": "调研" } }, "zh-Hant": { @@ -21040,8 +24292,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Start" + "state": "translated", + "value": "开始" } }, "zh-Hant": { @@ -21057,8 +24309,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "Failed" + "state": "translated", + "value": "فشل" } }, "bs": { @@ -21075,8 +24327,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Failed" + "state": "translated", + "value": "Fehlgeschlagen" } }, "en": { @@ -21087,14 +24339,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Failed" + "state": "translated", + "value": "Fallido" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Failed" + "state": "translated", + "value": "Échoué" } }, "it": { @@ -21117,8 +24369,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Failed" + "state": "translated", + "value": "실패한" } }, "nb": { @@ -21165,14 +24417,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Failed" + "state": "translated", + "value": "失败" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Failed" + "state": "translated", + "value": "失敗的" } } } @@ -21290,8 +24542,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Idle" + "state": "translated", + "value": "空闲" } }, "zh-Hant": { @@ -21307,8 +24559,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "Loading" + "state": "translated", + "value": "تحميل" } }, "bs": { @@ -21325,8 +24577,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Loading" + "state": "translated", + "value": "Laden" } }, "en": { @@ -21337,14 +24589,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Loading" + "state": "translated", + "value": "Cargando" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Loading" + "state": "translated", + "value": "Chargement" } }, "it": { @@ -21367,8 +24619,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Loading" + "state": "translated", + "value": "로드 중" } }, "nb": { @@ -21415,14 +24667,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Loading" + "state": "translated", + "value": "加载中" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Loading" + "state": "translated", + "value": "載入中" } } } @@ -21540,8 +24792,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Running" + "state": "translated", + "value": "运行中" } }, "zh-Hant": { @@ -21557,8 +24809,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "Starting" + "state": "translated", + "value": "البدء" } }, "bs": { @@ -21575,8 +24827,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Starting" + "state": "translated", + "value": "Beginnt" } }, "en": { @@ -21587,14 +24839,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Starting" + "state": "translated", + "value": "A partir de" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Starting" + "state": "translated", + "value": "Départ" } }, "it": { @@ -21617,8 +24869,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Starting" + "state": "translated", + "value": "시작" } }, "nb": { @@ -21665,14 +24917,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Starting" + "state": "translated", + "value": "启动中" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Starting" + "state": "translated", + "value": "開始" } } } @@ -21790,8 +25042,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Stopping" + "state": "translated", + "value": "停止中" } }, "zh-Hant": { @@ -21807,8 +25059,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "Stop" + "state": "translated", + "value": "قف" } }, "bs": { @@ -21825,8 +25077,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Stop" + "state": "translated", + "value": "Stoppen" } }, "en": { @@ -21837,14 +25089,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Stop" + "state": "translated", + "value": "Detener" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Stop" + "state": "translated", + "value": "Arrêt" } }, "it": { @@ -21867,8 +25119,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Stop" + "state": "translated", + "value": "멈추다" } }, "nb": { @@ -21915,14 +25167,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Stop" + "state": "translated", + "value": "停止" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Stop" + "state": "translated", + "value": "停止" } } } @@ -21932,8 +25184,8 @@ "localizations": { "ar": { "stringUnit": { - "state": "needs_review", - "value": "Tools" + "state": "translated", + "value": "أدوات" } }, "bs": { @@ -21950,8 +25202,8 @@ }, "de": { "stringUnit": { - "state": "needs_review", - "value": "Tools" + "state": "translated", + "value": "Werkzeuge" } }, "en": { @@ -21962,14 +25214,14 @@ }, "es": { "stringUnit": { - "state": "needs_review", - "value": "Tools" + "state": "translated", + "value": "Herramientas" } }, "fr": { "stringUnit": { - "state": "needs_review", - "value": "Tools" + "state": "translated", + "value": "Outils" } }, "it": { @@ -21992,8 +25244,8 @@ }, "ko": { "stringUnit": { - "state": "needs_review", - "value": "Tools" + "state": "translated", + "value": "도구" } }, "nb": { @@ -22040,14 +25292,14 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Tools" + "state": "translated", + "value": "工具" } }, "zh-Hant": { "stringUnit": { - "state": "needs_review", - "value": "Tools" + "state": "translated", + "value": "工具" } } } @@ -22165,8 +25417,8 @@ }, "zh-Hans": { "stringUnit": { - "state": "needs_review", - "value": "Voice input" + "state": "translated", + "value": "语音输入" } }, "zh-Hant": { @@ -23058,7 +26310,7 @@ "fr": { "stringUnit": { "state": "translated", - "value": "OK" + "value": "D'ACCORD" } }, "it": { @@ -23124,7 +26376,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "OK" + "value": "确定" } }, "zh-Hant": { @@ -24087,7 +27339,7 @@ "fr": { "stringUnit": { "state": "translated", - "value": "OK" + "value": "D'ACCORD" } }, "it": { @@ -26112,6 +29364,12 @@ "state": "translated", "value": "AppleScript вимкнено параметром конфігурації macos-applescript." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "AppleScript 已被 macos-applescript 配置禁用。" + } } } }, @@ -26141,6 +29399,12 @@ "state": "translated", "value": "Не вдалося створити розділення." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法创建分屏。" + } } } }, @@ -26170,6 +29434,12 @@ "state": "translated", "value": "Не вдалося створити вікно." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法创建窗口。" + } } } }, @@ -26199,6 +29469,12 @@ "state": "translated", "value": "Не вдалося створити робочу область." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法创建工作区。" + } } } }, @@ -26228,6 +29504,12 @@ "state": "translated", "value": "Відсутній рядок дії." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "缺少操作字符串。" + } } } }, @@ -26257,6 +29539,12 @@ "state": "translated", "value": "Відсутній текст введення." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "缺少输入文本。" + } } } }, @@ -26286,6 +29574,12 @@ "state": "translated", "value": "Відсутній або невідомий напрямок розділення." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "缺少或未知的拆分方向。" + } } } }, @@ -26315,6 +29609,12 @@ "state": "translated", "value": "Відсутня ціль терміналу." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "缺少终端目标。" + } } } }, @@ -26344,6 +29644,12 @@ "state": "translated", "value": "Термінал більше недоступний." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "终端已不可用。" + } } } }, @@ -26373,6 +29679,12 @@ "state": "translated", "value": "Вікно більше недоступне." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "窗口已不可用。" + } } } }, @@ -26402,6 +29714,12 @@ "state": "translated", "value": "Робоча область більше недоступна." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "工作区已不可用。" + } } } }, @@ -26669,6 +29987,48 @@ "state": "translated", "value": "コードが無効です。もう一度お試しください。" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Ungültiger Code. Bitte versuchen Sie es erneut." + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Code invalide. Veuillez réessayer." + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "رمز غير صالح. يرجى المحاولة مرة أخرى." + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Código no válido. Por favor inténtalo de nuevo." + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "代碼無效。請再試一次。" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "验证码无效。请重试。" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "코드가 잘못되었습니다. 다시 시도해 주세요." + } } } }, @@ -26686,6 +30046,48 @@ "state": "translated", "value": "ネットワークエラーです。接続を確認してください。" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Netzwerkfehler. Bitte überprüfen Sie Ihre Verbindung." + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Erreur réseau. Veuillez vérifier votre connexion." + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "خطأ في الشبكة. يرجى التحقق من الاتصال الخاص بك." + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Error de red. Por favor verifique su conexión." + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "網路錯誤。請檢查您的連線。" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "网络错误。请检查网络连接。" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "네트워크 오류입니다. 연결을 확인해주세요." + } } } }, @@ -26703,6 +30105,12 @@ "state": "translated", "value": "インターネットに接続されていません。Wi-Fiまたはモバイル回線に接続して、もう一度お試しください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无互联网连接。请连接 Wi-Fi 或蜂窝网络后重试。" + } } } }, @@ -26720,6 +30128,48 @@ "state": "translated", "value": "問題が発生しました。もう一度お試しください。" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Etwas ist schief gelaufen. Bitte versuchen Sie es erneut." + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Quelque chose s'est mal passé. Veuillez réessayer." + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "حدث خطأ ما. يرجى المحاولة مرة أخرى." + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Algo salió mal. Por favor inténtalo de nuevo." + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "出了點問題。請再試一次。" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "出了点问题。请重试。" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "문제가 발생했습니다. 다시 시도해 주세요." + } } } }, @@ -26737,6 +30187,48 @@ "state": "translated", "value": "サインインがタイムアウトしました。接続を確認してもう一度お試しください。" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Zeitüberschreitung bei der Anmeldung. Überprüfen Sie Ihre Verbindung und versuchen Sie es erneut." + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Le délai de connexion a expiré. Vérifiez votre connexion et réessayez." + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "انتهت مهلة تسجيل الدخول. تحقق من اتصالك وحاول مرة أخرى." + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Se agotó el tiempo de inicio de sesión. Comprueba tu conexión y vuelve a intentarlo." + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "登入超時。檢查您的連線並重試。" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "登录超时。请检查网络连接后重试。" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "로그인 시간이 초과되었습니다. 연결을 확인하고 다시 시도하세요." + } } } }, @@ -26754,6 +30246,48 @@ "state": "translated", "value": "セッションの有効期限が切れました。もう一度サインインしてください。" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Sitzung abgelaufen. Bitte melden Sie sich erneut an." + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Session expirée. Veuillez vous reconnecter." + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "انتهت صلاحية الجلسة. الرجاء تسجيل الدخول مرة أخرى." + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "La sesión expiró. Por favor inicia sesión nuevamente." + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "會話已過期。請重新登入。" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "会话已过期。请重新登录。" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "세션이 만료되었습니다. 다시 로그인해 주세요." + } } } }, @@ -26771,6 +30305,48 @@ "state": "translated", "value": "メールまたはパスワードが正しくありません。" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Falsche E-Mail-Adresse oder falsches Passwort." + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Email ou mot de passe incorrect." + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "البريد الإلكتروني أو كلمة المرور غير صحيحة." + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Correo electrónico o contraseña incorrectos." + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "電子郵件或密碼不正確。" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "电子邮件或密码不正确。" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "이메일이나 비밀번호가 잘못되었습니다." + } } } }, @@ -28252,6 +31828,12 @@ "state": "translated", "value": "デザインモード(%@)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "设计模式(%@)" + } } } }, @@ -28269,6 +31851,12 @@ "state": "translated", "value": "変更内容を入力" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "描述所需的更改" + } } } }, @@ -28286,6 +31874,12 @@ "state": "translated", "value": "ページ上の要素を1つ以上選択してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在页面上选择一个或多个元素。" + } } } }, @@ -28303,6 +31897,12 @@ "state": "translated", "value": "選択した要素を削除" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "移除所选元素" + } } } }, @@ -28320,6 +31920,12 @@ "state": "translated", "value": "%@ のコンテキストを削除" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "移除 %@ 上下文" + } } } }, @@ -28337,6 +31943,12 @@ "state": "translated", "value": "コピー" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "复制" + } } } }, @@ -28354,6 +31966,42 @@ "state": "translated", "value": "コピー済み" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Kopiert" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Copié" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Copiado" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "已複製" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已复制" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "복사됨" + } } } }, @@ -28371,6 +32019,12 @@ "state": "translated", "value": "コピー中…" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "正在复制…" + } } } }, @@ -28405,6 +32059,12 @@ "state": "translated", "value": "注釈をキャプチャできませんでした。もう一度描いてください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法捕获标注。请重新绘制。" + } } } }, @@ -28422,6 +32082,12 @@ "state": "translated", "value": "キャプチャ中に選択した要素が移動しました。ページが静止しているときにもう一度お試しください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "所选元素在捕获过程中发生了移动。请在页面静止时重试。" + } } } }, @@ -28439,6 +32105,12 @@ "state": "translated", "value": "デザインコンテキストをコピーできませんでした。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法复制设计上下文。" + } } } }, @@ -28456,6 +32128,12 @@ "state": "translated", "value": "デザインモードのクリーンアップに失敗しました。ページを再読み込みするか、もう一度お試しください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "设计模式清理失败。请重新加载页面或重试。" + } } } }, @@ -28473,6 +32151,12 @@ "state": "translated", "value": "デザインモードを開始できませんでした。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "设计模式无法启动。" + } } } }, @@ -28490,6 +32174,12 @@ "state": "translated", "value": "ページから無効なデザインデータが返されました。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "页面返回了无效的设计数据。" + } } } }, @@ -28507,6 +32197,12 @@ "state": "translated", "value": "デザインモードを開始する前にページを開いてください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请先打开一个页面,再进入设计模式。" + } } } }, @@ -28524,6 +32220,12 @@ "state": "translated", "value": "ページが応答しなくなりました。再読み込みして、もう一度お試しください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "页面已停止响应。请重新加载后重试。" + } } } }, @@ -28541,6 +32243,12 @@ "state": "translated", "value": "もう一度お試しください。問題が続く場合は、ページを再読み込みしてください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请重试。如果问题仍然存在,请重新加载页面。" + } } } }, @@ -28558,6 +32266,12 @@ "state": "translated", "value": "React Grabを開始する前にデザインモードを終了できませんでした。ページを再読み込みして、もう一度お試しください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "启动 React Grab 前设计模式无法关闭。请重新加载页面后重试。" + } } } }, @@ -28575,6 +32289,12 @@ "state": "translated", "value": "React Grabを終了できませんでした。ページを再読み込みして、もう一度お試しください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "React Grab 无法关闭。请重新加载页面后重试。" + } } } }, @@ -28592,6 +32312,12 @@ "state": "translated", "value": "選択した要素を更新できませんでした。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法更新所选元素。" + } } } }, @@ -28609,6 +32335,12 @@ "state": "translated", "value": "詳細: %1$@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "详细信息:%1$@" + } } } }, @@ -28626,6 +32358,12 @@ "state": "translated", "value": "選択したページ要素のデザインモードコンテキストです。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "所选页面元素的设计模式上下文。" + } } } }, @@ -28643,6 +32381,12 @@ "state": "translated", "value": "ページ: %1$@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "页面:%1$@" + } } } }, @@ -28660,6 +32404,12 @@ "state": "translated", "value": "キャプチャ範囲を描画" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "绘制捕获区域" + } } } }, @@ -28677,6 +32427,12 @@ "state": "translated", "value": "要素を選択" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "选择元素" + } } } }, @@ -28694,6 +32450,12 @@ "state": "translated", "value": "デザインモード" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "设计模式" + } } } }, @@ -30949,6 +34711,12 @@ "state": "translated", "value": "ダウンロードに失敗しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "下载失败" + } } } }, @@ -31204,6 +34972,48 @@ "state": "translated", "value": "消去" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Klar" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Clair" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "واضح" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Claro" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "清除" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "清除" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "분명한" + } } } }, @@ -31221,6 +35031,12 @@ "state": "translated", "value": "最近のダウンロードはありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有最近的下载" + } } } }, @@ -31238,6 +35054,48 @@ "state": "translated", "value": "失敗しました" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Fehlgeschlagen" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Échoué" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "فشل" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Fallido" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "失敗的" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "失败" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "실패한" + } } } }, @@ -31255,6 +35113,48 @@ "state": "translated", "value": "開く" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Offen" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Ouvrir" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "يفتح" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Abierto" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "打開" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "打开" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "열려 있는" + } } } }, @@ -31272,6 +35172,12 @@ "state": "translated", "value": "Finderに表示" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在访达中显示" + } } } }, @@ -31289,6 +35195,12 @@ "state": "translated", "value": "ダウンロード" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "下载" + } } } }, @@ -32270,6 +36182,12 @@ "state": "translated", "value": "試行したURL" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "尝试访问的 URL" + } } } }, @@ -32287,6 +36205,12 @@ "state": "translated", "value": "このURLは組織の内蔵ブラウザポリシーで許可されていません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "你所在组织的内嵌浏览器策略不允许访问此 URL。" + } } } }, @@ -32304,6 +36228,12 @@ "state": "translated", "value": "このURLは内蔵ブラウザのURLポリシーで許可されていません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "内嵌浏览器 URL 策略不允许访问此 URL。" + } } } }, @@ -32321,6 +36251,12 @@ "state": "translated", "value": "組織のポリシーによりブロックされました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已被你所在组织的策略拦截" + } } } }, @@ -32338,6 +36274,12 @@ "state": "translated", "value": "内蔵ブラウザのURLポリシーによりブロックされました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已被内嵌浏览器 URL 策略拦截" + } } } }, @@ -32956,6 +36898,12 @@ "state": "translated", "value": "リンクをコピー" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "复制链接" + } } } }, @@ -32973,6 +36921,12 @@ "state": "translated", "value": "cmux はこのリンクを開けませんでした。リンクをコピーして別のアプリで開けます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux 无法打开此链接。你可以复制它并在其他应用中打开。" + } } } }, @@ -32990,6 +36944,12 @@ "state": "translated", "value": "リンクを開けません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法打开链接" + } } } }, @@ -33007,6 +36967,12 @@ "state": "translated", "value": "cmux のウェブページが別のアプリでリンクを開こうとしています。代わりにブラウザに留まることもできます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux 中的网页想在其他应用中打开链接。你也可以留在浏览器中。" + } } } }, @@ -33024,6 +36990,12 @@ "state": "translated", "value": "アプリを開く" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "打开应用" + } } } }, @@ -33041,6 +37013,12 @@ "state": "translated", "value": "ブラウザに留まる" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "留在浏览器" + } } } }, @@ -33058,6 +37036,12 @@ "state": "translated", "value": "外部アプリを開きますか?" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "打开外部应用?" + } } } }, @@ -34563,6 +38547,12 @@ "state": "translated", "value": "Додаткові дані (закладки, налаштування, розширення)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "其他数据(书签、设置、扩展)" + } } } }, @@ -34592,6 +38582,12 @@ "state": "translated", "value": "Закладки, налаштування та розширення поки недоступні." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "书签、设置和扩展尚不可用。" + } } } }, @@ -34609,6 +38605,12 @@ "state": "translated", "value": "'%@' に一致するインポート可能なブラウザーが見つかりません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有匹配 '%@' 的可导入浏览器" + } } } }, @@ -34626,6 +38628,12 @@ "state": "translated", "value": "cmux ブラウザープロファイル '%@' を作成できませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法创建 cmux 浏览器配置文件 '%@'" + } } } }, @@ -34643,6 +38651,12 @@ "state": "translated", "value": "'%@' に一致する cmux ブラウザープロファイルが見つかりません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有匹配 '%@' 的 cmux 浏览器配置文件" + } } } }, @@ -34660,6 +38674,12 @@ "state": "translated", "value": "ブラウザーのインポートに失敗しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "浏览器导入失败" + } } } }, @@ -34677,6 +38697,12 @@ "state": "translated", "value": "インポート可能なブラウザーが見つかりません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到可导入的浏览器" + } } } }, @@ -34694,6 +38720,12 @@ "state": "translated", "value": "%@ のソースプロファイルが見つかりません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到 %@ 的源配置文件" + } } } }, @@ -34711,6 +38743,12 @@ "state": "translated", "value": "'%@' に一致するソースプロファイルが見つかりません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有匹配 '%@' 的源配置文件" + } } } }, @@ -34740,6 +38778,42 @@ "state": "translated", "value": "Назад" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Zurück" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Dos" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "خلف" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Atrás" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "後退" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "上一步" + } } } }, @@ -34769,6 +38843,12 @@ "state": "translated", "value": "Браузер: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "浏览器:%@" + } } } }, @@ -34798,6 +38878,12 @@ "state": "translated", "value": "Створені профілі cmux: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已创建的 cmux 配置文件:%@" + } } } }, @@ -34827,6 +38913,12 @@ "state": "translated", "value": "Профіль призначення: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "目标配置文件:%@" + } } } }, @@ -34856,6 +38948,12 @@ "state": "translated", "value": "Фільтр доменів: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "域名过滤:%@" + } } } }, @@ -34863,9 +38961,21 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "Imported cookies: %ld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Imported cookie: %ld" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Imported cookies: %ld" + } + } + } } }, "ja": { @@ -34885,6 +38995,30 @@ "state": "translated", "value": "Імпортовано cookies: %ld" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已导入 Cookie:%ld" + } + }, + "de": { + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Importiertes Cookie: %ld" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Importierte Cookies: %ld" + } + } + } + } } } }, @@ -34892,9 +39026,21 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "Imported history entries: %ld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Imported history entry: %ld" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Imported history entries: %ld" + } + } + } } }, "ja": { @@ -34914,6 +39060,30 @@ "state": "translated", "value": "Імпортовано записів історії: %ld" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已导入历史记录条目:%ld" + } + }, + "de": { + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Importierter Verlaufseintrag: %ld" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Importierte Verlaufseinträge: %ld" + } + } + } + } } } }, @@ -34972,6 +39142,12 @@ "state": "translated", "value": "Відповідності профілів:" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "配置文件映射:" + } } } }, @@ -35001,6 +39177,12 @@ "state": "translated", "value": "Обсяг: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "范围:%@" + } } } }, @@ -35008,9 +39190,21 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "Skipped cookies: %ld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Skipped cookie: %ld" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Skipped cookies: %ld" + } + } + } } }, "ja": { @@ -35030,6 +39224,30 @@ "state": "translated", "value": "Пропущено cookies: %ld" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已跳过 Cookie:%ld" + } + }, + "de": { + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Übersprungenes Cookie: %ld" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Übersprungene Cookies: %ld" + } + } + } + } } } }, @@ -35059,6 +39277,12 @@ "state": "translated", "value": "Вихідні профілі: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "源配置文件:%@" + } } } }, @@ -35088,6 +39312,12 @@ "state": "translated", "value": "Імпорт даних браузера завершено" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "浏览器数据导入完成" + } } } }, @@ -35117,6 +39347,12 @@ "state": "translated", "value": "Попередження:" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "警告:" + } } } }, @@ -35146,6 +39382,12 @@ "state": "translated", "value": "Cookies (авторизації на сайтах)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Cookie(网站登录)" + } } } }, @@ -35175,6 +39417,12 @@ "state": "translated", "value": "Призначення" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "目标" + } } } }, @@ -35204,6 +39452,12 @@ "state": "translated", "value": "Об'єднати в один" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "合并为一个" + } } } }, @@ -35233,6 +39487,12 @@ "state": "translated", "value": "Окремі профілі" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "分开的配置文件" + } } } }, @@ -35262,6 +39522,12 @@ "state": "translated", "value": "Імпортувати до" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "导入到" + } } } }, @@ -35291,6 +39557,12 @@ "state": "translated", "value": "Створити \"%@\"" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "创建 \"%@\"" + } } } }, @@ -35320,6 +39592,12 @@ "state": "translated", "value": "Імпортовані дані потрапляють у вибраний профіль cmux." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "导入的数据会进入所选的 cmux 配置文件。" + } } } }, @@ -35349,6 +39627,12 @@ "state": "translated", "value": "Усі вибрані вихідні профілі об'єднуються в один профіль cmux." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "所有选中的源配置文件都会进入同一个 cmux 配置文件。" + } } } }, @@ -35378,6 +39662,12 @@ "state": "translated", "value": "Відсутні профілі cmux створюються під час імпорту." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "缺失的 cmux 配置文件会在导入时创建。" + } } } }, @@ -35407,6 +39697,12 @@ "state": "translated", "value": "Виявлено: %@." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已检测到:%@。" + } } } }, @@ -35436,6 +39732,12 @@ "state": "translated", "value": "Виявлено: %@, +1 інший." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已检测到:%@,另有 1 个。" + } } } }, @@ -35445,7 +39747,29 @@ "en": { "stringUnit": { "state": "translated", - "value": "Detected: %@, +%ld more." + "value": "Detected: %@, +%#@count2@." + }, + "substitutions": { + "count2": { + "argNum": 2, + "formatSpecifier": "ld", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%ld more" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%ld more" + } + } + } + } + } } }, "ja": { @@ -35465,6 +39789,40 @@ "state": "translated", "value": "Виявлено: %@, +%ld інших." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已检测到:%@,另有 %ld 个。" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Erkannt: %@, %#@count2@" + }, + "substitutions": { + "count2": { + "argNum": 2, + "formatSpecifier": "ld", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "+%ld mehr" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "+%ld mehr" + } + } + } + } + } + } } } }, @@ -35494,6 +39852,12 @@ "state": "translated", "value": "Підтримувані браузери не виявлено." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未检测到受支持的浏览器。" + } } } }, @@ -35523,6 +39887,12 @@ "state": "translated", "value": "Домени" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "域名" + } } } }, @@ -35552,6 +39922,12 @@ "state": "translated", "value": "Необов'язкові домени, через кому" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "可选域名,以逗号分隔" + } } } }, @@ -35581,6 +39957,12 @@ "state": "translated", "value": "cmux не зміг створити профіль призначення \"%@\"." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux 无法创建目标配置文件 \"%@\"。" + } } } }, @@ -35610,6 +39992,12 @@ "state": "translated", "value": "Вибраний профіль браузера cmux більше не існує. Виберіть профіль призначення знову." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "所选的 cmux 浏览器配置文件已不存在。请重新选择目标配置文件。" + } } } }, @@ -35639,6 +40027,12 @@ "state": "translated", "value": "Не вдалося розпочати імпорт" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法开始导入" + } } } }, @@ -35668,6 +40062,12 @@ "state": "translated", "value": "Сховати підказку" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "隐藏提示" + } } } }, @@ -35697,6 +40097,12 @@ "state": "translated", "value": "Імпортувати…" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "导入…" + } } } }, @@ -35726,6 +40132,12 @@ "state": "translated", "value": "Налаштування браузера" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "浏览器设置" + } } } }, @@ -35755,6 +40167,12 @@ "state": "translated", "value": "Ви завжди можете знайти це в Налаштуваннях > Браузер." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "你随时可以在「设置 > 浏览器」中找到它。" + } } } }, @@ -35772,6 +40190,12 @@ "state": "translated", "value": "Safari、Chrome、Firefox、Brave、Edge、Arc からブックマーク、履歴、Cookie をインポートします。インポート済みの項目は自動的に重複排除されます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "从 Safari、Chrome、Firefox、Brave、Edge 或 Arc 导入书签、历史记录和 Cookie。已导入的条目会自动去重。" + } } } }, @@ -35801,6 +40225,12 @@ "state": "translated", "value": "Імпорт даних браузера" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "导入浏览器数据" + } } } }, @@ -35830,6 +40260,12 @@ "state": "translated", "value": "Імпортувати" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "导入" + } } } }, @@ -35859,6 +40295,12 @@ "state": "translated", "value": "Імпорт даних браузера" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "导入浏览器数据" + } } } }, @@ -35888,6 +40330,12 @@ "state": "translated", "value": "Історія (відвідані сторінки)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "历史记录(已访问页面)" + } } } }, @@ -35917,6 +40365,42 @@ "state": "translated", "value": "Далі" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Nächste" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Suivant" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "التالي" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Próximo" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "下一個" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "下一步" + } } } }, @@ -35946,6 +40430,12 @@ "state": "translated", "value": "cmux не знайшов профілів браузерів для імпорту на цьому Mac." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux 在这台 Mac 上找不到可导入的浏览器配置文件。" + } } } }, @@ -35975,6 +40465,12 @@ "state": "translated", "value": "Браузери для імпорту не знайдено" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到可导入的浏览器" + } } } }, @@ -36004,6 +40500,12 @@ "state": "translated", "value": "Імпортування %@ з %@…" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "正在导入 %@,来源:%@…" + } } } }, @@ -36033,6 +40535,12 @@ "state": "translated", "value": "Це може зайняти кілька секунд для великих профілів." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "配置文件较大时,这可能需要几秒钟。" + } } } }, @@ -36062,6 +40570,12 @@ "state": "translated", "value": "Імпорт даних браузера" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "正在导入浏览器数据" + } } } }, @@ -36091,6 +40605,12 @@ "state": "translated", "value": "Cookies + історія" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Cookie + 历史记录" + } } } }, @@ -36120,6 +40640,12 @@ "state": "translated", "value": "Тільки cookies" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "仅 Cookie" + } } } }, @@ -36149,6 +40675,12 @@ "state": "translated", "value": "Усе" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "全部" + } } } }, @@ -36178,6 +40710,12 @@ "state": "translated", "value": "Тільки історія" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "仅历史记录" + } } } }, @@ -36207,6 +40745,36 @@ "state": "translated", "value": "Браузер" } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Navigateur" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "المتصفح" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Navegador" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "瀏覽器" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "浏览器" + } } } }, @@ -36236,6 +40804,12 @@ "state": "translated", "value": "Профіль %ld" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "配置文件 %ld" + } } } }, @@ -36265,6 +40839,12 @@ "state": "translated", "value": "Профілі" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "配置文件" + } } } }, @@ -36294,6 +40874,12 @@ "state": "translated", "value": "Вихідні профілі для %@ не виявлено." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未检测到 %@ 的源配置文件。" + } } } }, @@ -36323,6 +40909,12 @@ "state": "translated", "value": "Виберіть один або кілька профілів." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请选择一个或多个配置文件。" + } } } }, @@ -36352,6 +40944,12 @@ "state": "translated", "value": "Почати імпорт" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "开始导入" + } } } }, @@ -36381,6 +40979,12 @@ "state": "translated", "value": "Крок 3 з 3" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "第 3 步,共 3 步" + } } } }, @@ -36410,6 +41014,12 @@ "state": "translated", "value": "Крок 1 з 3" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "第 1 步,共 3 步" + } } } }, @@ -36439,6 +41049,12 @@ "state": "translated", "value": "Крок 2 з 3" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "第 2 步,共 3 步" + } } } }, @@ -36468,6 +41084,12 @@ "state": "translated", "value": "Імпорт даних браузера" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "导入浏览器数据" + } } } }, @@ -36497,6 +41119,12 @@ "state": "translated", "value": "Виберіть Cookies, Історію або обидва перед початком імпорту." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "开始导入前,请选择 Cookie、历史记录或两者。" + } } } }, @@ -36526,6 +41154,12 @@ "state": "translated", "value": "Виберіть принаймні один вихідний профіль для імпорту." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请至少选择一个要导入的源配置文件。" + } } } }, @@ -36555,6 +41189,12 @@ "state": "translated", "value": "Імпорт закладок, налаштувань і розширень ще недоступний. Імпортовано лише cookies та історію." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "书签、设置和扩展的导入尚不可用。仅导入了 Cookie 和历史记录。" + } } } }, @@ -36584,6 +41224,12 @@ "state": "translated", "value": "Не вдалося прочитати cookies %@ за адресою %@: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "读取 %@ 的 Cookie 失败,位置 %@:%@" + } } } }, @@ -36613,6 +41259,12 @@ "state": "translated", "value": "Не вдалося прочитати історію %@ за адресою %@: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "读取 %@ 的历史记录失败,位置 %@:%@" + } } } }, @@ -36642,6 +41294,12 @@ "state": "translated", "value": "Імпорт cookies %@ ще не реалізовано." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%@ 的 Cookie 导入尚未实现。" + } } } }, @@ -36649,9 +41307,21 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "Skipped %ld encrypted cookies that require Keychain decryption." + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Skipped %ld encrypted cookie that requires Keychain decryption." + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Skipped %ld encrypted cookies that require Keychain decryption." + } + } + } } }, "ja": { @@ -36671,6 +41341,30 @@ "state": "translated", "value": "Пропущено %ld зашифрованих cookies, які потребують дешифрування через Keychain." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已跳过 %ld 个需要钥匙串解密的加密 Cookie。" + } + }, + "de": { + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%ld verschlüsseltes Cookie, das eine Schlüsselbund-Entschlüsselung erfordert, wurde übersprungen." + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%ld verschlüsselte Cookies, die eine Schlüsselbund-Entschlüsselung erfordern, wurden übersprungen." + } + } + } + } } } }, @@ -36700,6 +41394,12 @@ "state": "translated", "value": "Не вдалося прочитати cookies Firefox за адресою %@: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "读取 Firefox Cookie 失败,位置 %@:%@" + } } } }, @@ -36729,6 +41429,12 @@ "state": "translated", "value": "Не вдалося прочитати історію Firefox за адресою %@: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "读取 Firefox 历史记录失败,位置 %@:%@" + } } } }, @@ -36736,9 +41442,21 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "Skipped %ld encrypted %@ cookies because %@ could not be unlocked from Keychain." + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Skipped %ld encrypted %@ cookie because %@ could not be unlocked from Keychain." + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Skipped %ld encrypted %@ cookies because %@ could not be unlocked from Keychain." + } + } + } } }, "ja": { @@ -36758,6 +41476,30 @@ "state": "translated", "value": "Пропущено %ld зашифрованих cookies %@, оскільки %@ не вдалося розблокувати через Keychain." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已跳过 %ld 个加密的 %@ Cookie,因为无法从钥匙串解锁 %@。" + } + }, + "de": { + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%ld verschlüsseltes %@-Cookie wurde übersprungen, da %@ nicht im Schlüsselbund entsperrt werden konnte." + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%ld verschlüsselte %@-Cookies wurden übersprungen, da %@ nicht im Schlüsselbund entsperrt werden konnte." + } + } + } + } } } }, @@ -36787,6 +41529,12 @@ "state": "translated", "value": "База даних історії для %@ не знайдена." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到 %@ 的历史记录数据库。" + } } } }, @@ -36816,6 +41564,12 @@ "state": "translated", "value": "Cookies Safari зберігаються у форматі Cookies.binarycookies і поки не підтримуються цим імпортером." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Safari 的 Cookie 存储在 Cookies.binarycookies 中,此导入工具尚不支持。" + } } } }, @@ -37190,6 +41944,12 @@ "state": "translated", "value": "PDFをダウンロード" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "下载 PDF" + } } } }, @@ -37207,6 +41967,12 @@ "state": "translated", "value": "PDFをプリント" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "打印 PDF" + } } } }, @@ -37236,6 +42002,12 @@ "state": "translated", "value": "Завантаження…" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "正在加载…" + } } } }, @@ -37372,6 +42144,12 @@ "state": "translated", "value": "'%@' に一致する cmux ブラウザープロファイルが複数あります: %@。プロファイル UUID を使用してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "有多个 cmux 浏览器配置文件匹配 '%@':%@。请使用配置文件 UUID。" + } } } }, @@ -37389,6 +42167,12 @@ "state": "translated", "value": "cmux ブラウザーが無効な間はブラウザープロファイルを使用できません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux 浏览器被禁用时无法使用浏览器配置文件" + } } } }, @@ -37406,6 +42190,12 @@ "state": "translated", "value": "デフォルトのブラウザープロファイルは削除できません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法删除默认浏览器配置文件" + } } } }, @@ -37423,6 +42213,12 @@ "state": "translated", "value": "ブラウザープロファイルコマンドに失敗しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "浏览器配置文件命令失败" + } } } }, @@ -37440,6 +42236,12 @@ "state": "translated", "value": "ブラウザープロファイルには空でない名前または UUID を指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "浏览器配置文件必须是非空的名称或 UUID" + } } } }, @@ -37457,6 +42259,12 @@ "state": "translated", "value": "ブラウザープロファイル名がありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "缺少浏览器配置文件名称" + } } } }, @@ -37474,6 +42282,12 @@ "state": "translated", "value": "ブラウザープロファイルがありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "缺少浏览器配置文件" + } } } }, @@ -37491,6 +42305,12 @@ "state": "translated", "value": "ブラウザープロファイルセレクターは 1 つだけ指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "只能指定一个浏览器配置文件选择器" + } } } }, @@ -37508,6 +42328,12 @@ "state": "translated", "value": "cmux ブラウザープロファイル '%@' を消去できませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法清除 cmux 浏览器配置文件 '%@'" + } } } }, @@ -37525,6 +42351,12 @@ "state": "translated", "value": "cmux ブラウザープロファイル '%@' を作成できませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法创建 cmux 浏览器配置文件 '%@'" + } } } }, @@ -37542,6 +42374,12 @@ "state": "translated", "value": "cmux ブラウザープロファイル '%@' を削除できませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法删除 cmux 浏览器配置文件 '%@'" + } } } }, @@ -37551,7 +42389,29 @@ "en": { "stringUnit": { "state": "translated", - "value": "Cannot delete cmux browser profile '%@' while %d browser panel(s) are using it" + "value": "Cannot delete cmux browser profile '%@' while %#@count2@" + }, + "substitutions": { + "count2": { + "argNum": 2, + "formatSpecifier": "d", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%d browser panel is using it" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%d browser panels are using it" + } + } + } + } + } } }, "ja": { @@ -37559,6 +42419,40 @@ "state": "translated", "value": "cmux ブラウザープロファイル '%@' は %d 個のブラウザーパネルが使用中のため削除できません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法删除 cmux 浏览器配置文件 '%@',仍有 %d 个浏览器面板正在使用它" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Das cmux-Browserprofil '%@' kann nicht gelöscht werden, während %#@count2@" + }, + "substitutions": { + "count2": { + "argNum": 2, + "formatSpecifier": "d", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%d Browser-Panel es verwendet" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%d Browser-Panels es verwenden" + } + } + } + } + } + } } } }, @@ -37576,6 +42470,12 @@ "state": "translated", "value": "'%@' に一致する cmux ブラウザープロファイルが見つかりません。使用可能なプロファイルを表示するには 'cmux browser profiles' を実行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有匹配 '%@' 的 cmux 浏览器配置文件。运行 'cmux browser profiles' 可列出可用的配置文件。" + } } } }, @@ -37593,6 +42493,12 @@ "state": "translated", "value": "cmux ブラウザープロファイルの名前を '%@' に変更できませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法将 cmux 浏览器配置文件重命名为 '%@'" + } } } }, @@ -37610,6 +42516,12 @@ "state": "translated", "value": "ブラウザープロファイルはブラウザーペインの作成時にのみ使用できます" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "浏览器配置文件仅在创建浏览器窗格时可用" + } } } }, @@ -37627,6 +42539,12 @@ "state": "translated", "value": "リモートワークスペースでブラウザーペインを作成する場合、ブラウザープロファイルは選択できません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在远程工作区中创建浏览器窗格时无法选择浏览器配置文件" + } } } }, @@ -37656,6 +42574,12 @@ "state": "translated", "value": "Профіль браузера: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "浏览器配置文件:%@" + } } } }, @@ -37685,6 +42609,42 @@ "state": "translated", "value": "Стандартний" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Standard" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Défaut" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "تقصير" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Por defecto" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "預設" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "默认" + } } } }, @@ -37714,6 +42674,12 @@ "state": "translated", "value": "Профілі" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "配置文件" + } } } }, @@ -37743,6 +42709,12 @@ "state": "translated", "value": "Новий профіль..." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "新建配置文件..." + } } } }, @@ -37772,6 +42744,12 @@ "state": "translated", "value": "Створити окремий профіль браузера для cookies, історії та локального сховища." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "为 Cookie、历史记录和本地存储创建独立的浏览器配置文件。" + } } } }, @@ -37801,6 +42779,12 @@ "state": "translated", "value": "Назва профілю" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "配置文件名称" + } } } }, @@ -37830,6 +42814,12 @@ "state": "translated", "value": "Новий профіль браузера" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "新建浏览器配置文件" + } } } }, @@ -37859,6 +42849,12 @@ "state": "translated", "value": "Перейменувати поточний профіль..." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "重命名当前配置文件..." + } } } }, @@ -37888,6 +42884,12 @@ "state": "translated", "value": "Виберіть нову назву для цього профілю браузера." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "为此浏览器配置文件选择新名称。" + } } } }, @@ -37917,6 +42919,12 @@ "state": "translated", "value": "Перейменувати профіль браузера" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "重命名浏览器配置文件" + } } } }, @@ -38356,6 +43364,12 @@ "state": "translated", "value": "別のブラウザのスクリーンショットを取得中です。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已有另一个浏览器截图正在进行中。" + } } } }, @@ -38865,7 +43879,49 @@ "en": { "stringUnit": { "state": "translated", - "value": "The browser screenshot disagreed with rendered text at %1$@; %2$lld text probes were blank after %3$lld attempts." + "value": "The browser screenshot disagreed with rendered text at %1$@; %#@count2@ after %#@count3@." + }, + "substitutions": { + "count2": { + "argNum": 2, + "formatSpecifier": "lld", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%lld text probe was blank" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%lld text probes were blank" + } + } + } + } + }, + "count3": { + "argNum": 3, + "formatSpecifier": "lld", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%lld attempt" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%lld attempts" + } + } + } + } + } } }, "ja": { @@ -38873,6 +43929,54 @@ "state": "translated", "value": "ブラウザのスクリーンショットが %1$@ の描画済みテキストと一致しません。%3$lld 回試行した後も %2$lld 個のテキストプローブが空白でした。" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Der Browser-Screenshot stimmte nicht mit dem gerenderten Text bei %1$@ überein; %#@count2@ nach %#@count3@." + }, + "substitutions": { + "count2": { + "argNum": 2, + "formatSpecifier": "lld", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%lld Textprüfung war leer" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%lld Textprüfungen waren leer" + } + } + } + } + }, + "count3": { + "argNum": 3, + "formatSpecifier": "lld", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%lld Versuch" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%lld Versuchen" + } + } + } + } + } + } } } }, @@ -39884,6 +44988,12 @@ "state": "translated", "value": "Тема браузера: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "浏览器主题:%@" + } } } }, @@ -40020,6 +45130,12 @@ "state": "translated", "value": "ブラウザのビューポートを変更する前にブラウザインスペクタを閉じるか切り離してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "更改浏览器视口前,请先关闭或分离浏览器检查器" + } } } }, @@ -40037,6 +45153,12 @@ "state": "translated", "value": "ビューポートの寸法は 1 から 4096 の範囲で指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "视口尺寸必须介于 1 到 4096 之间" + } } } }, @@ -40054,6 +45176,12 @@ "state": "translated", "value": "ブラウザのビューポートを変更する前に、ブラウザの要素フルスクリーンを終了してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "更改浏览器视口前,请先退出浏览器元素全屏" + } } } }, @@ -40071,6 +45199,12 @@ "state": "translated", "value": "ビューポートとページズームがブラウザのレンダリング上限を超えています" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "视口与页面缩放超出浏览器渲染上限" + } } } }, @@ -40088,6 +45222,12 @@ "state": "translated", "value": "browser.viewport.set には整数の width と height が必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "browser.viewport.set 要求宽度和高度为整数" + } } } }, @@ -40831,6 +45971,12 @@ "state": "translated", "value": "無効" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已禁用" + } } } }, @@ -40848,6 +45994,12 @@ "state": "translated", "value": "有効" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已启用" + } } } }, @@ -40865,6 +46017,12 @@ "state": "translated", "value": "browser design-mode には enable、disable、toggle、status のいずれかを指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "browser design-mode 需要以下之一:enable、disable、toggle、status" + } } } }, @@ -40899,6 +46057,12 @@ "state": "translated", "value": "mode は enable、disable、toggle のいずれかである必要があります" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "mode 必须为以下之一:enable、disable、toggle" + } } } }, @@ -40916,6 +46080,12 @@ "state": "translated", "value": "ブラウザデザインモードの更新がタイムアウトしました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "更新浏览器设计模式超时" + } } } }, @@ -40933,6 +46103,12 @@ "state": "translated", "value": "ブラウザデザインモードを更新できませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法更新浏览器设计模式" + } } } }, @@ -40950,6 +46126,12 @@ "state": "translated", "value": "信頼済み差分ビューアの許可リストが無効です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "受信任 diff 查看器允许列表无效" + } } } }, @@ -40967,6 +46149,12 @@ "state": "translated", "value": "信頼済み差分ビューアの許可リストがないか、無効です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "受信任 diff 查看器允许列表缺失或无效" + } } } }, @@ -40984,6 +46172,12 @@ "state": "translated", "value": "信頼済み差分ビューアのセッションが無効です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "受信任 diff 查看器会话无效" + } } } }, @@ -41001,6 +46195,12 @@ "state": "translated", "value": "信頼済み差分ビューアのセッションがありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "缺少受信任 diff 查看器会话" + } } } }, @@ -41018,6 +46218,12 @@ "state": "translated", "value": "組織のブラウザポリシーによりブロックされました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已被你所在组织的浏览器策略拦截" + } } } }, @@ -41035,6 +46241,12 @@ "state": "translated", "value": "内蔵ブラウザのURLポリシーによりブロックされました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已被内嵌浏览器 URL 策略拦截" + } } } }, @@ -41052,6 +46264,12 @@ "state": "translated", "value": "ブラウザ操作に失敗しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "浏览器操作失败" + } } } }, @@ -41069,6 +46287,12 @@ "state": "translated", "value": "browser cookies clear には --all または Cookie スコープを1つだけ指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "browser cookies clear 需要 --all 或一个 cookie 作用域,二者取其一" + } } } }, @@ -41086,6 +46310,12 @@ "state": "translated", "value": "browser cookies clear --expires には Unix 時刻の整数を指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "browser cookies clear --expires 必须是整数形式的 Unix 时间戳" + } } } }, @@ -41103,6 +46333,12 @@ "state": "translated", "value": "browser cookies clear に無効な Cookie フィルターが指定されました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "browser cookies clear 收到了无效的 cookie 过滤条件" + } } } }, @@ -41120,6 +46356,12 @@ "state": "translated", "value": "browser cookies clear --url にはホストを含む有効な URL を指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "browser cookies clear --url 需要一个带主机名的有效 URL" + } } } }, @@ -41137,6 +46379,12 @@ "state": "translated", "value": "ブラウザ機能を利用できません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "浏览器控制不可用" + } } } }, @@ -41154,6 +46402,12 @@ "state": "translated", "value": "browser viewport には または reset が必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "browser viewport 需要: | reset" + } } } }, @@ -41171,6 +46425,12 @@ "state": "translated", "value": "browser viewport reset は追加の引数を受け付けません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "browser viewport reset 不接受额外参数" + } } } }, @@ -41188,6 +46448,12 @@ "state": "translated", "value": "名前付きキーは Playwright/W3C の名前に従います。Space、Spacebar、space は DOM key \" \" と code \"Space\" を送信し、--key ' ' では生の DOM key を渡せます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "具名按键遵循 Playwright/W3C 命名。Space、Spacebar 和 space 会发出 DOM key \" \",code 为 \"Space\";--key ' ' 则直接传递原始 DOM key。" + } } } }, @@ -41205,6 +46471,12 @@ "state": "translated", "value": "ペインのサイズを変更せず、正確な 1...4096 CSS ピクセルのビューポートをエミュレートします" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在窗格内模拟精确的 1...4096 CSS 像素视口,而不改变窗格大小" + } } } }, @@ -41222,6 +46494,12 @@ "state": "translated", "value": "ページは既存のペイン内にアスペクトフィットされ、reset でペイン本来のサイズに戻ります" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "页面会按比例适配到现有窗格中;reset 可恢复窗格的原生尺寸" + } } } }, @@ -41239,6 +46517,12 @@ "state": "translated", "value": "大きすぎるビューポートとページズームの組み合わせでは、レンダリング上限の詳細が構造化形式で返されます" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "视口与页面缩放的组合过大时,会返回结构化的渲染上限详情" + } } } }, @@ -41273,6 +46557,12 @@ "state": "translated", "value": "--profile には空でないプロファイル名または UUID が必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "--profile 需要非空的配置文件名称或 UUID" + } } } }, @@ -41290,6 +46580,12 @@ "state": "translated", "value": "--profile は browser open が新しいペインを作成する場合にのみ使用できます。サーフェスセレクターを省略してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "--profile 仅在 browser open 创建新窗格时受支持;请省略 surface 选择器" + } } } }, @@ -41324,6 +46620,12 @@ "state": "translated", "value": "前回使用" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "最近使用" + } } } }, @@ -41341,6 +46643,12 @@ "state": "translated", "value": "typeにはterminal、browser、simulatorのいずれかを指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "type 必须为 terminal、browser 或 simulator" + } } } }, @@ -41358,6 +46666,12 @@ "state": "translated", "value": "使用方法: cmux canvas new-pane [--type terminal|browser|simulator]" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux canvas new-pane [--type terminal|browser|simulator]" + } } } }, @@ -41375,6 +46689,12 @@ "state": "translated", "value": "無効なサーフェスハンドル: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无效的表面句柄:%@" + } } } }, @@ -41392,6 +46712,12 @@ "state": "translated", "value": "サーフェスが見つかりません: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到表面:%@" + } } } }, @@ -41450,6 +46776,12 @@ "state": "translated", "value": "Використання: cmux claude-teams [аргументи-claude...]\n\nЗапуск Claude Code з увімкненими командами агентів.\n\nЦя команда:\n - типово вмикає режим teammate для Claude\n - забезпечує підтримку cmux для сеансу\n - встановлює CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1\n - додає приватну tmux-прокладку на початок PATH\n - передає всі інші аргументи до claude\n\nTmux-прокладка перетворює підтримувані команди tmux вікон/панелей на операції\nробочих просторів і розділів cmux у поточному сеансі cmux.\n\nПриклади:\n cmux claude-teams\n cmux claude-teams --continue\n cmux claude-teams --model sonnet" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux claude-teams [claude-args...]\n\n启动 Claude Code 并启用 agent teams。\n\n此命令会:\n - 将 Claude teammate 模式默认设为 auto\n - 设置类 tmux 环境,使 Claude auto 模式使用 cmux 分屏\n - 设置 CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1\n - 将私有 tmux shim 前置到 PATH\n - 将其余所有参数转发给 claude\n\ntmux shim 会把受支持的 tmux window/pane 命令,转换为当前 cmux 会话中的\n工作区和分屏操作。\n\n示例:\n cmux claude-teams\n cmux claude-teams --continue\n cmux claude-teams --model sonnet" + } } } }, @@ -41592,6 +46924,12 @@ "state": "translated", "value": "ID: %1$@\n検証: %2$@\n証明書: %3$@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "id: %1$@\n验证: %2$@\n证书: %3$@" + } } } }, @@ -41609,6 +46947,12 @@ "state": "translated", "value": "カスタム Cloud VM ドメインはありません。`cmux cloud domains verify ` で開始してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有自定义的 Cloud VM 域名。用 `cmux cloud domains verify ` 添加一个。" + } } } }, @@ -41626,6 +46970,12 @@ "state": "translated", "value": "公開: なし" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "发布: 无" + } } } }, @@ -41643,6 +46993,12 @@ "state": "translated", "value": "公開: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "发布: %@" + } } } }, @@ -41660,6 +47016,12 @@ "state": "translated", "value": "ID: %1$@\nVM: %2$@:%3$@\nアクセス: %4$@\n状態: %5$@\nルーティングリビジョン: %6$@\nドメイン: %7$@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "id: %1$@\nvm: %2$@:%3$@\n访问: %4$@\n状态: %5$@\n路由版本: %6$@\n域名: %7$@" + } } } }, @@ -41677,6 +47039,12 @@ "state": "translated", "value": "DNS プロバイダーに ALIAS/ANAME/フラット化レコードがない場合は、www.%@ を公開して apex からリダイレクトしてください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "你的 DNS 服务商没有 ALIAS/ANAME/flattening 记录?请发布 www.%@ 并把裸域重定向到它。" + } } } }, @@ -41694,6 +47062,12 @@ "state": "translated", "value": "証明書" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "证书" + } } } }, @@ -41711,6 +47085,12 @@ "state": "translated", "value": "%@ に次の DNS レコードを追加してください:" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请为 %@ 添加以下 DNS 记录:" + } } } }, @@ -41728,6 +47108,12 @@ "state": "translated", "value": "所有権" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "所有权" + } } } }, @@ -41745,6 +47131,12 @@ "state": "translated", "value": "ルーティング" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "路由" + } } } }, @@ -41762,6 +47154,12 @@ "state": "translated", "value": "ルーティング: apex レコードは %@ 自体を、* レコードはすべてのサブドメインを配信します。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "路由:裸域记录服务 %@ 本身;* 记录服务所有子域名。" + } } } }, @@ -41779,6 +47177,12 @@ "state": "translated", "value": "公開済みの Cloud VM ドメインはありません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有已发布的 Cloud VM 域名。" + } } } }, @@ -41796,6 +47200,12 @@ "state": "translated", "value": "生成ドメインまたはカスタムドメインで VM ポートを公開します。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在生成的域名或自定义域名上发布 VM 端口。" + } } } }, @@ -41813,6 +47223,12 @@ "state": "translated", "value": "アクセスは personal、team、または public で指定してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "访问级别必须是 personal、team 或 public。" + } } } }, @@ -41830,6 +47246,12 @@ "state": "translated", "value": "cmux アプリから、この CLI では読み取れないドメインレスポンスが返されました。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux 应用返回的域名响应,本 CLI 无法解析。" + } } } }, @@ -41847,6 +47269,12 @@ "state": "translated", "value": "cmux アプリから、この CLI では読み取れない公開レスポンスが返されました。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux 应用返回的发布响应,本 CLI 无法解析。" + } } } }, @@ -41864,6 +47292,12 @@ "state": "translated", "value": "公開 %@ を削除しました。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已移除发布 %@。" + } } } }, @@ -41881,6 +47315,12 @@ "state": "translated", "value": "%1$@(チーム %2$@)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%1$@(团队 %2$@)" + } } } }, @@ -41898,6 +47338,12 @@ "state": "translated", "value": "`--team` は team アクセスでのみ使用できます。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "`--team` 只能与 team 访问级别一起使用。" + } } } }, @@ -41915,6 +47361,12 @@ "state": "translated", "value": "team アクセスには `--team ` が必要です。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "team 访问级别需要 `--team `。" + } } } }, @@ -41932,6 +47384,48 @@ "state": "translated", "value": "不明" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "unbekannt" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "inconnu" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "مجهول" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "desconocido" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "未知" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "알려지지 않은" + } } } }, @@ -41949,6 +47443,12 @@ "state": "translated", "value": "使用方法:\n cmux cloud domains [list]\n cmux cloud domains zones\n cmux cloud domains verify \n cmux cloud domains publish [--domain ] [--access personal|team|public] [--team ] [--org-slug ] [--yes]\n cmux cloud domains access [--team ] [--yes]\n cmux cloud domains grant [--expires ]\n cmux cloud domains ungrant \n cmux cloud domains grants \n cmux cloud domains rm \n\nカスタムドメインは先にverifyを実行し、表示されたDNSレコードを追加した後、もう一度verifyを実行して所有権確認を完了してください。\npublish --domainには確認済みドメイン、またはその直下1階層のサブドメインを指定できます。\n生成される名前は----.cmux.shで、DNS確認は不要です。\n既定のアクセス権は所有チームまたは個人所有者です。メールのアクセス許可は1つのポートにのみ適用されます。\n公開アクセスには確認が必要です。スクリプトでは--yesで確認できます。JSON出力には--jsonを追加してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:\n cmux cloud domains [list]\n cmux cloud domains zones\n cmux cloud domains verify \n cmux cloud domains publish [--domain ] [--access personal|team|public] [--team ] [--org-slug ] [--yes]\n cmux cloud domains access [--team ] [--yes]\n cmux cloud domains grant [--expires ]\n cmux cloud domains ungrant \n cmux cloud domains grants \n cmux cloud domains rm \n\n请先验证你拥有的域名:`verify` 会打印需要添加的 DNS 记录,添加后再次运行\n即可完成验证。之后 `publish --domain` 可接受该域名或它的任意一级子域名。\n生成的名称形如 ----.cmux.sh,无需验证。\n访问级别默认归属所属团队或个人所有者。邮箱授权仅对单个端口生效。\n公开访问需要确认;脚本中可用 --yes 直接确认。加 --json 输出 JSON。" + } } } }, @@ -41966,6 +47466,12 @@ "state": "translated", "value": "検証: 不要(cmux ドメイン)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "验证: 无需验证(cmux 域名)" + } } } }, @@ -41983,6 +47489,12 @@ "state": "translated", "value": "検証: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "验证: %@" + } } } }, @@ -42000,6 +47512,12 @@ "state": "translated", "value": "DNS の更新後: cmux cloud domains verify %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "更新 DNS 后运行: cmux cloud domains verify %@" + } } } }, @@ -42653,6 +48171,12 @@ "state": "translated", "value": "cmux codex-teams ウォッチャーは Codex サブエージェントをスキップしました: 深さ %1$lld がペイン自動作成の上限 %2$lld を超えています。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux codex-teams 监视器跳过了一个 Codex 子代理:深度 %1$lld 超过自动窗格上限 %2$lld。" + } } } }, @@ -42670,6 +48194,12 @@ "state": "translated", "value": "cmux codex-teams ウォッチャーは再開された Codex サブエージェント用のペインを作成できませんでした。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux codex-teams 监视器无法为已恢复的 Codex 子代理创建窗格。" + } } } }, @@ -42687,6 +48217,12 @@ "state": "translated", "value": "cmux codex-teams ウォッチャーは再開された Codex サブエージェント用のペインを作成できませんでした(エラーコード: %@)。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux codex-teams 监视器无法为已恢复的 Codex 子代理创建窗格(错误代码:%@)。" + } } } }, @@ -42704,6 +48240,12 @@ "state": "translated", "value": "cmux codex-teams ウォッチャーは、再開されたスレッドの準備ができていないため Codex サブエージェントをアタッチできませんでした。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux codex-teams 监视器无法附加 Codex 子代理,因为其恢复的线程尚未就绪。" + } } } }, @@ -42721,6 +48263,12 @@ "state": "translated", "value": "cmux codex-teams ウォッチャーは Codex サブエージェントをスキップしました: スレッドの状態 %@ はアタッチ可能ではありません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux codex-teams 监视器跳过了一个 Codex 子代理:线程状态 %@ 不可附加。" + } } } }, @@ -43746,15 +49294,39 @@ } }, "de": { - "stringUnit": { - "state": "translated", - "value": "%1$lld Review-Kommentare (Repository: %2$@)" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%1$lld Review-Kommentar (Repo: %2$@)" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%1$lld Review-Kommentare (Repo: %2$@)" + } + } + } } }, "en": { - "stringUnit": { - "state": "translated", - "value": "%1$lld review comments (repo: %2$@)" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%1$lld review comment (repo: %2$@)" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%1$lld review comments (repo: %2$@)" + } + } + } } }, "es": { @@ -44238,6 +49810,12 @@ "state": "translated", "value": "(リモート tmux にルーティングされました。新しいペインは非同期で反映されます)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "(已路由到远程 tmux;新窗格会异步到达)" + } } } }, @@ -44255,6 +49833,12 @@ "state": "translated", "value": "(リモート tmux にルーティングされました。新しいウインドウは非同期で反映されます)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "(已路由到远程 tmux;新窗口会异步到达)" + } } } }, @@ -44397,6 +49981,12 @@ "state": "translated", "value": "dismiss-notification には --id または --all-read のどちらか一方だけを指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "dismiss-notification 需要且仅需 --id 或 --all-read 之一" + } } } }, @@ -44414,6 +50004,12 @@ "state": "translated", "value": "通知相関キーが無効です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "通知关联键无效" + } } } }, @@ -44431,6 +50027,12 @@ "state": "translated", "value": "--correlation-key には --panel が必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "--correlation-key 需要配合 --panel 使用" + } } } }, @@ -44448,6 +50050,12 @@ "state": "translated", "value": "clear_notifications [--tab=X] [--panel=ID] [--correlation-key=UUID]" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "clear_notifications [--tab=X] [--panel=ID] [--correlation-key=UUID]" + } } } }, @@ -44465,6 +50073,12 @@ "state": "translated", "value": "mark-notification-read には --id、--workspace、--all のいずれか一つだけを指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "mark-notification-read 需要且仅需一个选择器:--id、--workspace 或 --all" + } } } }, @@ -44482,6 +50096,12 @@ "state": "translated", "value": "--surface には --workspace が必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "--surface 需要 --workspace" + } } } }, @@ -44499,6 +50119,12 @@ "state": "translated", "value": "open-notification には --id が必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "open-notification 需要 --id" + } } } }, @@ -44516,6 +50142,12 @@ "state": "translated", "value": "ssh-session-attach: ID '%@' の永続 SSH PTY セッションが見つかりません。有効なセッション ID を確認するには 'cmux ssh-session-list --all-workspaces' を実行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "ssh-session-attach: 没有 id 为 '%@' 的持久化 SSH PTY 会话。运行 'cmux ssh-session-list --all-workspaces' 查看有效的会话 id。" + } } } }, @@ -44533,6 +50165,12 @@ "state": "translated", "value": "ssh-session-attach: 永続 SSH PTY セッションの状態を利用できません。'cmux ssh-session-list --all-workspaces' を実行してから再試行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "ssh-session-attach: 持久化 SSH PTY 会话状态不可用。请运行 'cmux ssh-session-list --all-workspaces' 后重试。" + } } } }, @@ -44550,6 +50188,12 @@ "state": "translated", "value": "ssh-session-attach: セッション '%1$@' は複数のワークスペース (%2$@) に存在します。--workspace で指定してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "ssh-session-attach: 会话 '%1$@' 存在于多个工作区(%2$@)。请传入 --workspace 指定其中一个。" + } } } }, @@ -44567,6 +50211,12 @@ "state": "translated", "value": "ssh-session-attach: セッション '%1$@' はワークスペース %2$@ に属していますが、--workspace では別のワークスペースが指定されました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "ssh-session-attach: 会话 '%1$@' 属于工作区 %2$@,但 --workspace 请求的是另一个工作区" + } } } }, @@ -44584,6 +50234,12 @@ "state": "translated", "value": "ssh-session-attach: --workspace の値を指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "ssh-session-attach:--workspace 需要一个值" + } } } }, @@ -44613,6 +50269,12 @@ "state": "translated", "value": "Неприпустимий --id '%@'. Використовуйте літери, цифри, '.', '_' або '-' (без пробілів)." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无效的 --id '%@'。请使用字母、数字、'.'、'_' 或 '-'(不能有空格)。" + } } } }, @@ -44642,6 +50304,12 @@ "state": "translated", "value": "Неприпустимий стан '%@'. Очікується on або off. %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无效的状态 '%@'。应为 on 或 off。%@" + } } } }, @@ -44671,6 +50339,12 @@ "state": "translated", "value": "Не вдалося визначити робочий простір. Запустіть у робочому просторі cmux або передайте --workspace ." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未解析到工作区。请在 cmux 工作区内运行,或传入 --workspace 。" + } } } }, @@ -44700,6 +50374,12 @@ "state": "translated", "value": "workspace потребує підкоманди. Доступні: list, create, env, close, rename, select, status, reconnect, disconnect, loading, group" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "workspace 需要一个子命令。可尝试:list、create、env、close、rename、select、status、reconnect、disconnect、loading、group" + } } } }, @@ -44729,6 +50409,12 @@ "state": "translated", "value": "Невідома підкоманда workspace: %@. Доступні: list, create, env, close, rename, select, status, reconnect, disconnect, loading, group" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知的 workspace 子命令:%@。可尝试:list、create、env、close、rename、select、status、reconnect、disconnect、loading、group" + } } } }, @@ -44746,6 +50432,12 @@ "state": "translated", "value": "--timeout は0より大きい値である必要があります" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "--timeout 必须大于 0" + } } } }, @@ -44763,6 +50455,12 @@ "state": "translated", "value": "一致するイベントを待機中にタイムアウトしました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "等待匹配事件超时" + } } } }, @@ -44792,6 +50490,12 @@ "state": "translated", "value": "Вивести знімок підписки та завершити роботу" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "打印订阅快照后退出" + } } } }, @@ -44821,6 +50525,12 @@ "state": "translated", "value": "Завершити з помилкою, якщо відповідна подія не надійде до кінцевого терміну" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "若在截止前没有匹配事件到达,则以失败退出" + } } } }, @@ -44932,7 +50642,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "cmux could not start this command. Try again, or reinstall cmux if the problem continues." + "value": "cmux 无法启动此命令。请重试;如果问题仍然存在,请重新安装 cmux。" } }, "zh-Hant": { @@ -45051,7 +50761,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "cmux could not start the command-line tool from the app bundle. Reinstall cmux or run the command from a standard cmux CLI installation." + "value": "cmux 无法从应用包中启动命令行工具。请重新安装 cmux,或从标准的 cmux CLI 安装中运行该命令。" } }, "zh-Hant": { @@ -45170,7 +50880,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "cmux could not run this command from the app bundle. Reinstall cmux or run the command from a standard cmux CLI installation." + "value": "cmux 无法从应用包中运行此命令。请重新安装 cmux,或从标准的 cmux CLI 安装中运行该命令。" } }, "zh-Hant": { @@ -45320,6 +51030,12 @@ "state": "translated", "value": "Usage: cmux dismiss-notification (--id | --all-read)\n\n通知を1件削除するか、既読の通知をすべて削除します。\n\nFlags:\n --id 削除する通知 ID\n --all-read 既読の通知をすべて削除\n --json JSON を出力\n --id-format refs、uuids、both のいずれか" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux dismiss-notification (--id | --all-read)\n\n移除一条通知,或移除所有已读通知。\n\n标志:\n --id 要移除的通知 id\n --all-read 移除所有已读通知\n --json 输出 JSON\n --id-format refs、uuids 或 both" + } } } }, @@ -45479,6 +51195,12 @@ "state": "translated", "value": "Usage: cmux jump-to-unread\n\n通知ページの操作と同じく、最新の未読通知へフォーカスします。\n\nFlags:\n --json JSON を出力\n --id-format refs、uuids、both のいずれか" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux jump-to-unread\n\n聚焦最新的未读通知,与通知页面上的操作一致。\n\n标志:\n --json 输出 JSON\n --id-format refs、uuids 或 both" + } } } }, @@ -45496,6 +51218,12 @@ "state": "translated", "value": "Usage: cmux mark-notification-read (--id | --workspace [--surface ] | --all)\n\n通知を開かずに既読にします。セレクタは1つだけ指定してください。\n\nFlags:\n --id 通知を1件既読にする\n --workspace ワークスペースの通知を既読にする\n --surface --workspace を1つのサーフェスに絞り込む\n --all すべての通知を既読にする\n --json JSON を出力\n --id-format refs、uuids、both のいずれか" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux mark-notification-read (--id | --workspace [--surface ] | --all)\n\n不打开通知即将其标记为已读。必须且只能指定一个选择器。\n\n标志:\n --id 将一条通知标记为已读\n --workspace 标记某个工作区的通知\n --surface 将 --workspace 缩小到某个表面\n --all 将所有通知标记为已读\n --json 输出 JSON\n --id-format refs、uuids 或 both" + } } } }, @@ -45882,6 +51610,12 @@ "state": "translated", "value": "Usage: cmux open-notification --id \n\n通知のワークスペースとサーフェスへフォーカスし、その行を既読にします。\n\nFlags:\n --id 開く通知 ID\n --json JSON を出力\n --id-format refs、uuids、both のいずれか" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux open-notification --id \n\n聚焦该通知所属的工作区和表面,然后将该行标记为已读。\n\n标志:\n --id 要打开的通知 id\n --json 输出 JSON\n --id-format refs、uuids 或 both" + } } } }, @@ -46149,6 +51883,12 @@ "state": "translated", "value": "Usage: cmux set-status [flags]\n\nワークスペースのサイドバーステータスエントリを設定します。ステータスエントリは\nサイドバーのタブ行にピルとして表示されます。異なるツール\n(例: \"claude_code\", \"build\")がそれぞれのエントリを管理できるよう、一意のキーを使用してください。\n\nFlags:\n --icon アイコン名(例: \"sparkle\", \"hammer\")\n --color <#hex> ピルの色(例: \"#ff9500\")\n --priority 並び順の優先度。大きい値ほど先に表示(デフォルト: 0)\n --workspace 対象ワークスペース(デフォルト: $CMUX_WORKSPACE_ID)\n\nExample:\n cmux set-status build \"compiling\" --icon hammer --color \"#ff9500\" --priority 80\n cmux set-status deploy \"v1.2.3\" --workspace workspace:2" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux set-status [flags]\n\n为工作区设置一个侧边栏状态条目。状态条目会以胶囊标签的形式\n显示在侧边栏的标签页行中。请使用唯一的 key,让不同工具\n(例如 \"claude_code\"、\"build\")各自管理自己的条目。\n\n标志:\n --icon 图标名称(例如 \"sparkle\"、\"hammer\")\n --color <#hex> 胶囊标签颜色(例如 \"#ff9500\")\n --priority 排序优先级;数值越大越靠前(默认:0)\n --workspace 目标工作区(默认:$CMUX_WORKSPACE_ID)\n\n示例:\n cmux set-status build \"compiling\" --icon hammer --color \"#ff9500\" --priority 80\n cmux set-status deploy \"v1.2.3\" --workspace workspace:2" + } } } }, @@ -46623,8 +52363,43 @@ "cli.localTmux.output.foundStale": { "extractionState": "manual", "localizations": { - "en": { "stringUnit": { "state": "translated", "value": "Found %lld stale local tmux session(s); pass --prune to remove them" } }, - "ja": { "stringUnit": { "state": "translated", "value": "古い local tmux セッションが %lld 件見つかりました。削除するには --prune を指定してください" } } + "en": { + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Found %lld stale local tmux session; pass --prune to remove it" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Found %lld stale local tmux sessions; pass --prune to remove them" + } + } + } + } + }, + "ja": { "stringUnit": { "state": "translated", "value": "古い local tmux セッションが %lld 件見つかりました。削除するには --prune を指定してください" } }, + "de": { + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%lld veraltete lokale tmux-Sitzung gefunden; geben Sie --prune an, um sie zu entfernen" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%lld veraltete lokale tmux-Sitzungen gefunden; geben Sie --prune an, um sie zu entfernen" + } + } + } + } + } } }, "cli.localTmux.output.idSuffix": { @@ -46658,8 +52433,43 @@ "cli.localTmux.output.removedStale": { "extractionState": "manual", "localizations": { - "en": { "stringUnit": { "state": "translated", "value": "Removed %lld stale local tmux session(s)" } }, - "ja": { "stringUnit": { "state": "translated", "value": "古い local tmux セッションを %lld 件削除しました" } } + "en": { + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Removed %lld stale local tmux session" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Removed %lld stale local tmux sessions" + } + } + } + } + }, + "ja": { "stringUnit": { "state": "translated", "value": "古い local tmux セッションを %lld 件削除しました" } }, + "de": { + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%lld veraltete lokale tmux-Sitzung entfernt" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%lld veraltete lokale tmux-Sitzungen entfernt" + } + } + } + } + } } }, "cli.localTmux.output.sessionRow": { @@ -46701,7 +52511,49 @@ "extractionState": "manual", "localizations": { "en": { "stringUnit": { "state": "translated", "value": "unknown" } }, - "ja": { "stringUnit": { "state": "translated", "value": "不明" } } + "ja": { "stringUnit": { "state": "translated", "value": "不明" } }, + "de": { + "stringUnit": { + "state": "translated", + "value": "unbekannt" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "inconnu" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "مجهول" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "desconocido" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "未知" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "알려지지 않은" + } + } } }, "cli.localTmux.target.pane": { @@ -47593,7 +53445,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Aborted." + "value": "已中止。" } }, "zh-Hant": { @@ -47712,7 +53564,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "%@ hooks already up to date at %@" + "value": "%@ hooks 已是最新,位置:%@" } }, "zh-Hant": { @@ -47831,7 +53683,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "\nProceed? [y/N] " + "value": "\n是否继续? [y/N] " } }, "zh-Hant": { @@ -47950,7 +53802,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "%@ exists but is not valid JSON. Fix or remove it before installing hooks." + "value": "%@ 存在但不是有效的 JSON。请先修复或移除它,再安装 hooks。" } }, "zh-Hant": { @@ -48069,7 +53921,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "%@ hooks installed at %@" + "value": "已安装 %@ hooks,位置:%@" } }, "zh-Hant": { @@ -48188,7 +54040,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Malformed %@ at %@. Fix or remove it before uninstalling hooks." + "value": "%@ 格式错误,位置:%@。请先修复或移除它,再卸载 hooks。" } }, "zh-Hant": { @@ -48307,7 +54159,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "No %@ found at %@" + "value": "未找到 %@,位置:%@" } }, "zh-Hant": { @@ -48426,7 +54278,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Removed Antigravity cmux hooks from %@" + "value": "已从 %@ 移除 Antigravity cmux hooks" } }, "zh-Hant": { @@ -48545,7 +54397,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Removed 0 cmux hook(s) from %@" + "value": "已从 %@ 移除 0 个 cmux hook" } }, "zh-Hant": { @@ -50164,7 +56016,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Aborted." + "value": "已中止。" } }, "zh-Hant": { @@ -50283,7 +56135,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "%@ hooks already up to date at %@" + "value": "%@ hooks 已是最新,位置:%@" } }, "zh-Hant": { @@ -50402,7 +56254,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "\nProceed? [y/N] " + "value": "\n是否继续? [y/N] " } }, "zh-Hant": { @@ -50521,7 +56373,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "%@ hooks installed at %@" + "value": "已安装 %@ hooks,位置:%@" } }, "zh-Hant": { @@ -50640,7 +56492,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "No %@ found at %@" + "value": "未找到 %@,位置:%@" } }, "zh-Hant": { @@ -50759,7 +56611,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Removed Kimi Code cmux hooks from %@" + "value": "已从 %@ 移除 Kimi Code cmux hooks" } }, "zh-Hant": { @@ -50878,7 +56730,7 @@ "zh-Hans": { "stringUnit": { "state": "translated", - "value": "Removed 0 cmux hook(s) from %@" + "value": "已从 %@ 移除 0 个 cmux hook" } }, "zh-Hant": { @@ -51158,6 +57010,12 @@ "state": "translated", "value": "Kiro 훅은 cmux 에이전트로 실행할 때만 적용됩니다. `kiro-cli chat --agent cmux`로 Kiro를 실행하거나 `kiro-cli settings chat.defaultAgent cmux`로 기본값으로 설정하세요." } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Kiro 仅在以 cmux agent 身份运行时应用这些 hooks。请用 `kiro-cli chat --agent cmux` 启动 Kiro,或用 `kiro-cli settings chat.defaultAgent cmux` 将其设为默认。" + } } } }, @@ -52675,6 +58533,12 @@ "state": "translated", "value": "cmux が Pi フィードの取り込み確認を受信できませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "cmux 未收到 Pi feed 摄取的确认" + } } } }, @@ -53908,9 +59772,21 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "Found %lld iOS Simulator panes; pass --surface or --all" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Found %lld iOS Simulator pane; pass --surface or --all" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Found %lld iOS Simulator panes; pass --surface or --all" + } + } + } } }, "ja": { @@ -53918,6 +59794,30 @@ "state": "translated", "value": "%lld個のiOS Simulatorペインが見つかりました。--surface または --all を指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "找到 %lld 个 iOS 模拟器窗格;请传入 --surface 或 --all" + } + }, + "de": { + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%lld iOS-Simulator-Teilfenster gefunden; gib --surface oder --all an" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%lld iOS-Simulator-Teilfenster gefunden; gib --surface oder --all an" + } + } + } + } } } }, @@ -53935,6 +59835,12 @@ "state": "translated", "value": "指定したiOS Simulatorデバイスが見つかりませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到请求的 iOS 模拟器设备" + } } } }, @@ -53952,6 +59858,12 @@ "state": "translated", "value": "指定したiOS Simulatorデバイスのストリーミングを開始できませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "请求的 iOS 模拟器设备未开始串流" + } } } }, @@ -53969,6 +59881,12 @@ "state": "translated", "value": "選択したiOSペインにSimulator識別子がありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "所选的 iOS 窗格没有模拟器标识符" + } } } }, @@ -53986,6 +59904,12 @@ "state": "translated", "value": "選択したiOSペインにサーフェス参照がありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "所选的 iOS 窗格没有表面引用" + } } } }, @@ -54003,6 +59927,12 @@ "state": "translated", "value": "一致するiOS Simulatorペインが見つかりませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到匹配的 iOS 模拟器窗格" + } } } }, @@ -54020,6 +59950,12 @@ "state": "translated", "value": "複数のSimulatorをキャプチャする場合、--outには既存のディレクトリを指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "捕获多个模拟器时,--out 必须指向一个已存在的目录" + } } } }, @@ -54037,6 +59973,12 @@ "state": "translated", "value": "1台のSimulatorをキャプチャする場合、--outにはファイルを指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "捕获单个模拟器时,--out 必须指向一个文件" + } } } }, @@ -54044,9 +59986,21 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "Found %lld iOS Simulator panes; screenshot --all supports at most 8" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Found %lld iOS Simulator pane; screenshot --all supports at most 8" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Found %lld iOS Simulator panes; screenshot --all supports at most 8" + } + } + } } }, "ja": { @@ -54054,6 +60008,30 @@ "state": "translated", "value": "%lld個のiOS Simulatorペインが見つかりました。screenshot --allは最大8個まで対応しています" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "找到 %lld 个 iOS 模拟器窗格;screenshot --all 最多支持 8 个" + } + }, + "de": { + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%lld iOS-Simulator-Teilfenster gefunden; screenshot --all unterstützt maximal 8" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%lld iOS-Simulator-Teilfenster gefunden; screenshot --all unterstützt maximal 8" + } + } + } + } } } }, @@ -54071,6 +60049,12 @@ "state": "translated", "value": "iOS Simulatorスクリーンショットの一括処理が10分の期限を超えました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "iOS 模拟器批量截图超过了 10 分钟的期限" + } } } }, @@ -54088,6 +60072,12 @@ "state": "translated", "value": "1つ以上のiOS Simulatorスクリーンショットに失敗しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "一个或多个 iOS 模拟器截图失败" + } } } }, @@ -54105,6 +60095,12 @@ "state": "translated", "value": "iOS Simulatorペインがありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有 iOS 模拟器窗格" + } } } }, @@ -54122,6 +60118,12 @@ "state": "translated", "value": "使用方法: cmux ios [args] [--surface ]\n\nすべてのネイティブ `cmux simulator` サブコマンドをそのまま使用できます。\n\n追加サブコマンド:\n list [--workspace ] Simulatorペインとデバイス識別子を表示\n context [--udid] 選択したSimulator識別情報を表示\n select ペインをiPhoneまたはiPad Simulatorに接続\n screenshot [--out ] 選択したSimulatorをキャプチャ\n\n例:\n cmux ios list --json\n cmux ios screenshot --surface surface:2 --out phone.png\n cmux ios screenshot --all --out screenshots/\n cmux ios rotate landscape-left" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux ios [args] [--surface ]\n\n所有原生 `cmux simulator` 子命令均可原样使用。\n\n附加子命令:\n list [--workspace ] 列出模拟器窗格和设备标识符\n context [--udid] 输出所选的一个模拟器身份\n select 将窗格绑定到 iPhone 或 iPad 模拟器\n screenshot [--out ] 截取一个或多个所选模拟器\n\n示例:\n cmux ios list --json\n cmux ios screenshot --surface surface:2 --out phone.png\n cmux ios screenshot --all --out screenshots/\n cmux ios rotate landscape-left" + } } } }, @@ -55932,15 +61934,39 @@ } }, "de": { - "stringUnit": { - "state": "translated", - "value": "%lld Prozesse" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%lld Prozess" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%lld Prozesse" + } + } + } } }, "en": { - "stringUnit": { - "state": "translated", - "value": "%lld processes" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%lld process" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%lld processes" + } + } + } } }, "es": { @@ -56757,6 +62783,12 @@ "state": "translated", "value": "ペアリング済みの iPhone に許可した Mac 開発タグ: %@(接続中のデバイスへ送信済み)。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已为配对的手机授权 Mac 开发标记:%@(已推送到已连接的设备)。" + } } } }, @@ -56774,6 +62806,12 @@ "state": "translated", "value": "ペアリング済みの iPhone に許可した Mac 開発タグ: %@(次回接続時に適用されます)。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已为配对的手机授权 Mac 开发标记:%@(将在手机下次连接时生效)。" + } } } }, @@ -56791,6 +62829,12 @@ "state": "translated", "value": "この Mac のペアリング済み iPhone に追加で許可された Mac 開発タグはありません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未向本机配对的手机授权额外的 Mac 开发标记。" + } } } }, @@ -56808,6 +62852,12 @@ "state": "translated", "value": "(なし)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "(无)" + } } } }, @@ -56825,6 +62875,12 @@ "state": "translated", "value": "使い方: cmux mobile compatible-tags [list|set <タグ...>|add <タグ...>|remove <タグ...>|clear]" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux mobile compatible-tags [list|set |add |remove |clear]" + } } } }, @@ -56842,6 +62898,12 @@ "state": "translated", "value": "モバイルターミナルのフォントを %@pt に設定しました(接続中のデバイス)。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已将已连接设备上的移动端终端字体设为 %@pt。" + } } } }, @@ -56859,6 +62921,12 @@ "state": "translated", "value": "モバイルターミナルのフォントを %@pt に設定しました(現在 iOS デバイスは接続されていません)。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已将移动端终端字体设为 %@pt(当前没有连接的 iOS 设备)。" + } } } }, @@ -56876,6 +62944,12 @@ "state": "translated", "value": "使い方: cmux mobile set-font <ポイント数> [--surface ] [--workspace ]" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux mobile set-font [--surface ] [--workspace ]" + } } } }, @@ -57143,6 +63217,12 @@ "state": "translated", "value": "--profile <名前|UUID> ブラウザープロファイル名または UUID" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "--profile 浏览器配置文件名称或 UUID" + } } } }, @@ -57767,6 +63847,12 @@ "state": "translated", "value": "Використання: cmux omo [аргументи-opencode...]\n\nЗапуск OpenCode з oh-my-openagent у середовищі cmux.\n\noh-my-openagent оркеструє кілька моделей ШІ як спеціалізованих агентів\nпаралельно. Ця команда налаштовує tmux-прокладку, щоб панелі агентів\nстали нативними розділами cmux з метаданими бічної панелі та сповіщеннями.\n\nЦя команда:\n - забезпечує підтримку cmux для oh-my-openagent\n - додає приватну tmux-прокладку на початок PATH\n - передає всі інші аргументи до opencode\n\nTmux-прокладка перетворює команди tmux вікон/панелей на операції\nробочих просторів і розділів cmux у поточному сеансі cmux.\n\nПриклади:\n cmux omo\n cmux omo --continue\n cmux omo --model claude-sonnet-4-6" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux omo [opencode-args...]\n\n在 cmux 感知的环境中,使用 oh-my-openagent 启动 OpenCode。\n\noh-my-openagent 会把多个 AI 模型编排为并行工作的专职代理。此命令会\n设置一个 tmux shim,使代理窗格成为带有侧边栏元数据和通知的\n原生 cmux 分屏。\n\n此命令会:\n - 设置类 tmux 环境,使 oh-my-openagent 使用 cmux 分屏\n - 将私有 tmux shim 前置到 PATH\n - 将其余所有参数转发给 opencode\n\ntmux shim 会把 tmux window/pane 命令,转换为当前 cmux 会话中的\n工作区和分屏操作。\n\n示例:\n cmux omo\n cmux omo --continue\n cmux omo --model claude-sonnet-4-6" + } } } }, @@ -57784,6 +63870,12 @@ "state": "translated", "value": "cmux をアクティブにできませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法激活 cmux" + } } } }, @@ -57801,6 +63893,12 @@ "state": "translated", "value": "cmux を起動できませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法启动 cmux" + } } } }, @@ -57818,6 +63916,12 @@ "state": "translated", "value": "%@ を cmux で開けませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法在 cmux 中打开 %@" + } } } }, @@ -57835,6 +63939,12 @@ "state": "translated", "value": "パスが存在しません: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "路径不存在:%@" + } } } }, @@ -57852,6 +63962,12 @@ "state": "translated", "value": "プロセス終了の監視に失敗しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法监视进程退出" + } } } }, @@ -57869,6 +63985,12 @@ "state": "translated", "value": "%@ (タイムアウト)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%@(超时)" + } } } }, @@ -58636,6 +64758,12 @@ "state": "translated", "value": "restore: 保存されたエージェント セッションを利用できません。ターミナルは保存されたディレクトリに残っています。後でもう一度試すか、新しいエージェント セッションを開始してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore: 已保存的代理会话不可用。终端仍留在其保存目录中;请稍后重试,或新建一个代理会话。" + } } } }, @@ -58653,6 +64781,12 @@ "state": "translated", "value": "restore: このコマンドは現在のセッションと一致しません。現在の状態を使用するには 'cmux restore --surface' を実行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:此命令与该会话已不匹配。请运行 'cmux restore --surface' 以使用当前记录。" + } } } }, @@ -58670,6 +64804,12 @@ "state": "translated", "value": "restore: 保存されたプロセスを開始できませんでした。表示されている復元コマンドを再実行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:无法启动已保存的进程。请重试屏幕上显示的 restore 命令。" + } } } }, @@ -58687,6 +64827,12 @@ "state": "translated", "value": "restore: 現在の cmux サーフェスを特定できませんでした。このターミナルから再試行するか、--surface を指定してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:无法识别当前的 cmux 表面。请从此终端重试,或传入 --surface 。" + } } } }, @@ -58704,6 +64850,12 @@ "state": "translated", "value": "restore: 保存されたエージェントコマンドを利用できません。エージェントがインストールされていることを確認してから、再試行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:已保存的代理命令不可用。请确认该代理已安装,然后重试。" + } } } }, @@ -58721,6 +64873,12 @@ "state": "translated", "value": "restore: 保存されたプロセスを開始できませんでした。表示されている復元コマンドを再実行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:无法启动已保存的进程。请重试屏幕上显示的 restore 命令。" + } } } }, @@ -58738,6 +64896,12 @@ "state": "translated", "value": "restore: このセッションの保存済み復元データには互換性がありません。このターミナルでエージェントをもう一度起動してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:此会话保存的恢复数据不兼容。请在此终端中重新启动该代理。" + } } } }, @@ -58755,6 +64919,12 @@ "state": "translated", "value": "restore: このコマンドは現在のセッションと一致しません。現在の状態を使用するには 'cmux restore --surface' を実行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:此命令与该会话已不匹配。请运行 'cmux restore --surface' 以使用当前记录。" + } } } }, @@ -58772,6 +64942,12 @@ "state": "translated", "value": "restore: このセッションの保存済み復元データには互換性がありません。このターミナルでエージェントをもう一度起動してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:此会话保存的恢复数据不兼容。请在此终端中重新启动该代理。" + } } } }, @@ -58789,6 +64965,12 @@ "state": "translated", "value": "restore: このセッションの保存済み復元データには互換性がありません。このターミナルでエージェントをもう一度起動してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:此会话保存的恢复数据不兼容。请在此终端中重新启动该代理。" + } } } }, @@ -58806,6 +64988,12 @@ "state": "translated", "value": "restore: このセッションには復元できるものがありません。このターミナルでエージェントをもう一度起動してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:此会话没有可恢复的内容。请在此终端中重新启动该代理。" + } } } }, @@ -58823,6 +65011,12 @@ "state": "translated", "value": "restore: プロバイダー設定を開始できませんでした。エージェントのプロバイダー設定を確認してから、再試行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:无法启动提供方设置。请检查该代理的提供方设置,然后重试。" + } } } }, @@ -58840,6 +65034,12 @@ "state": "translated", "value": "restore: プロバイダー設定に失敗しました。エージェントのプロバイダー設定を確認してから、再試行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:提供方设置失败。请检查该代理的提供方设置,然后重试。" + } } } }, @@ -58857,6 +65057,12 @@ "state": "translated", "value": "restore: プロバイダー設定に失敗しました。エージェントのプロバイダー設定を確認してから、再試行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:提供方设置失败。请检查该代理的提供方设置,然后重试。" + } } } }, @@ -58874,6 +65080,12 @@ "state": "translated", "value": "restore: プロバイダー設定を開始できませんでした。エージェントのプロバイダー設定を確認してから、再試行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:无法启动提供方设置。请检查该代理的提供方设置,然后重试。" + } } } }, @@ -58891,6 +65103,12 @@ "state": "translated", "value": "restore: プロバイダー設定に時間がかかりすぎました。プロバイダー接続を確認してから、再試行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:提供方设置耗时过长。请检查提供方连接,然后重试。" + } } } }, @@ -58908,6 +65126,12 @@ "state": "translated", "value": "restore: プロバイダー設定を利用できません。エージェントのプロバイダー設定を確認してから、再試行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:提供方设置不可用。请检查该代理的提供方设置,然后重试。" + } } } }, @@ -58925,6 +65149,12 @@ "state": "translated", "value": "restore: プロバイダー設定を完了できませんでした。表示されている復元コマンドを再実行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:提供方设置无法完成。请重试屏幕上显示的 restore 命令。" + } } } }, @@ -58942,6 +65172,12 @@ "state": "translated", "value": "restore: cmux はまだ起動中です。しばらくしてから、表示されている復元コマンドを再実行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:cmux 仍在启动中。请稍后重试屏幕上显示的 restore 命令。" + } } } }, @@ -58959,6 +65195,12 @@ "state": "translated", "value": "restore: 指定されたサーフェスが見つかりません。サーフェスの参照を確認してから、再試行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:未找到请求的表面。请检查表面引用,然后重试。" + } } } }, @@ -58976,6 +65218,12 @@ "state": "translated", "value": "restore: このセッションの保存済み復元データには互換性がありません。このターミナルでエージェントをもう一度起動してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:此会话保存的恢复数据不兼容。请在此终端中重新启动该代理。" + } } } }, @@ -58993,6 +65241,12 @@ "state": "translated", "value": "restore: 保存された作業ディレクトリにアクセスできません。アクセスを復元してから、再試行してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "restore:已保存的工作目录无法访问。请恢复其访问权限,然后重试。" + } } } }, @@ -59260,6 +65514,12 @@ "state": "translated", "value": "使用法: cmux restore --surface [id|ref]" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux restore --surface [id|ref]" + } } } }, @@ -59277,6 +65537,12 @@ "state": "translated", "value": "無効なウィンドウ指定: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无效的窗口句柄:%@" + } } } }, @@ -59294,6 +65560,12 @@ "state": "translated", "value": "無効なワークスペース指定: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无效的工作区句柄:%@" + } } } }, @@ -59311,6 +65583,12 @@ "state": "translated", "value": "right-sidebar にはサブコマンドが必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "right-sidebar 需要一个子命令" + } } } }, @@ -59328,6 +65606,12 @@ "state": "translated", "value": "right-sidebar: --no-focus は set でのみ使えます" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "right-sidebar:--no-focus 仅在与 set 一起使用时有效" + } } } }, @@ -59345,6 +65629,12 @@ "state": "translated", "value": "right-sidebar set にはモードが必要です: files, find, vault, sessions, feed, dock, cloud, custom [sidebar-name]" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "right-sidebar set 需要一个模式:files、find、vault、sessions、feed、dock、cloud 或 custom [sidebar-name]" + } } } }, @@ -59362,6 +65652,12 @@ "state": "translated", "value": "right-sidebar %@ に予期しない引数があります" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "right-sidebar %@ 收到了意外参数" + } } } }, @@ -59379,6 +65675,12 @@ "state": "translated", "value": "不明な right-sidebar コマンド '%@'" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知的 right-sidebar 命令 '%@'" + } } } }, @@ -59396,6 +65698,12 @@ "state": "translated", "value": "right-sidebar: 不明なフラグ '%@'" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "right-sidebar:未知标志 '%@'" + } } } }, @@ -59413,6 +65721,12 @@ "state": "translated", "value": "不明な right-sidebar モード '%@'" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知的 right-sidebar 模式 '%@'" + } } } }, @@ -59430,6 +65744,12 @@ "state": "translated", "value": "ウィンドウ参照が見つかりません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到窗口引用" + } } } }, @@ -59447,6 +65767,12 @@ "state": "translated", "value": "right-sidebar: --window には ID が必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "right-sidebar:--window 需要一个 id" + } } } }, @@ -59464,6 +65790,12 @@ "state": "translated", "value": "ワークスペース参照が見つかりません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到工作区引用" + } } } }, @@ -59481,6 +65813,12 @@ "state": "translated", "value": "right-sidebar: --workspace には ID が必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "right-sidebar:--workspace 需要一个 id" + } } } }, @@ -59498,6 +65836,12 @@ "state": "translated", "value": "使用法: cmux right-sidebar [flags]\n\nCLI から右サイドバーを操作します。\n\nコマンド:\n toggle 右サイドバーの表示を切り替えます\n show 右サイドバーを表示します\n hide 右サイドバーを隠します\n focus 現在の右サイドバーモードにフォーカスします\n set [sidebar-name]\n 表示して、モードを切り替え、フォーカスします。custom は\n ~/.config/cmux/sidebars の JS/Swift サイドバーを右パネルに\n 表示します(名前で選択できます)\n mode {\"visible\":bool,\"mode\":string} を出力します\n files|find|vault|sessions|feed|dock|cloud|custom\n show + set + focus のエイリアス\n\nフラグ:\n --workspace ワークスペースを含むウィンドウを対象にします\n --window ウィンドウを対象にします\n --no-focus set で、フォーカスを移さずにモードだけ切り替えます\n\n例:\n cmux right-sidebar toggle\n cmux right-sidebar set find\n cmux right-sidebar set vault --no-focus\n cmux right-sidebar mode" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux right-sidebar [flags]\n\n从 CLI 控制右侧边栏。\n\n命令:\n toggle 切换右侧边栏的显示与隐藏\n show 显示右侧边栏\n hide 隐藏右侧边栏\n focus 聚焦当前的右侧边栏模式\n set [sidebar-name]\n 显示、切换模式并聚焦。`custom` 会把\n ~/.config/cmux/sidebars 中的 JS/Swift 侧边栏\n 渲染为右侧面板;可选的名称用于指定其中一个。\n mode 打印 {\"visible\":bool,\"mode\":string}\n files|find|vault|sessions|feed|dock|cloud|custom\n show + set + focus 的别名\n\n标志:\n --workspace 指向包含该工作区的窗口\n --window 指向某个窗口\n --no-focus 与 set 同用时,只切换模式不移动焦点\n\n示例:\n cmux right-sidebar toggle\n cmux right-sidebar set find\n cmux right-sidebar set vault --no-focus\n cmux right-sidebar mode" + } } } }, @@ -59515,6 +65859,12 @@ "state": "translated", "value": "キュー済み(ターミナル起動中。PTY 生成後に入力が送信されます)" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已排队(终端正在启动;PTY 就绪后会发送输入)" + } } } }, @@ -59657,6 +66007,12 @@ "state": "translated", "value": "sessions list: --agent には値が必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "sessions list:--agent 需要一个值" + } } } }, @@ -59674,6 +66030,12 @@ "state": "translated", "value": "sessions list: --limit には正の整数を指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "sessions list:--limit 必须是正整数" + } } } }, @@ -59691,6 +66053,12 @@ "state": "translated", "value": "sessions list: 予期しない引数 '%@'" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "sessions list:意外参数 '%@'" + } } } }, @@ -59708,6 +66076,12 @@ "state": "translated", "value": "sessions list: 不明なエージェント '%@'" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "sessions list:未知代理 '%@'" + } } } }, @@ -59725,6 +66099,12 @@ "state": "translated", "value": "sessions list: 不明なフラグ '%@'" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "sessions list:未知标志 '%@'" + } } } }, @@ -59742,6 +66122,12 @@ "state": "translated", "value": "不明な sessions サブコマンドです: %@。使用方法: cmux sessions list [options]" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知的 sessions 子命令:%@。用法:cmux sessions list [options]" + } } } }, @@ -59749,9 +66135,21 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "... %lld more. Pass --all or --limit ." + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "... %lld more. Pass --all or --limit ." + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "... %lld more. Pass --all or --limit ." + } + } + } } }, "ja": { @@ -59759,6 +66157,30 @@ "state": "translated", "value": "... %lld 件追加で一致。--all または --limit を指定してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "... 还有 %lld 条。请传入 --all 或 --limit 。" + } + }, + "de": { + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "... %lld weitere. Geben Sie --all oder --limit an." + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "... %lld weitere. Geben Sie --all oder --limit an." + } + } + } + } } } }, @@ -59776,6 +66198,12 @@ "state": "translated", "value": "一致する保存済みエージェントセッションはありません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有匹配的已保存代理会话。" + } } } }, @@ -59793,6 +66221,12 @@ "state": "translated", "value": "使用方法: cmux sessions list [options]\n cmux sessions [options]\n\n~/.cmuxterm/*-hook-sessions.json から保存済みエージェントセッション記録を表示します。\nこのコマンドは実行中の cmux ソケットを必要としません。\n既定では、広範な出力にはアクティブ、復元可能、またはトランスクリプト付きの記録だけを表示します。\n保存済みフック記録をすべて確認するには --all を指定します。\n\nオプション:\n --agent 1 つのエージェントに絞り込みます。例: codex または claude\n --session 1 つのエージェントセッション ID に絞り込みます\n --workspace 保存済みワークスペース ID に絞り込みます\n --surface 保存済みサーフェス ID に絞り込みます\n --cwd 保存済み cwd または起動時の作業ディレクトリで絞り込みます\n --state-dir フック状態ディレクトリを上書きします\n --codex-home トランスクリプト確認に使う既定の Codex ホームを上書きします\n --limit テキスト出力の件数を制限します(既定: 100)\n --all すべての一致を表示します\n --json 構造化 JSON を出力します\n\nCodex 行には、保存済み ID が CODEX_HOME/session_index.jsonl に存在するか、\n一致するトランスクリプトファイルが CODEX_HOME/sessions または\nCODEX_HOME/archived_sessions に存在するかが含まれます。\n\n互換エイリアス:\n cmux sessions debug [options]\n cmux session-debug [options]" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux sessions list [options]\n cmux sessions [options]\n\n输出 ~/.cmuxterm/*-hook-sessions.json 中保存的代理会话记录。\n此命令不需要正在运行的 cmux socket。\n默认情况下,宽泛输出会显示活动的、可恢复的或有转写记录支撑的记录。\n传入 --all 可查看每一条已保存的 hook 记录。\n\n选项:\n --agent 仅筛选一个代理,例如 codex 或 claude\n --session 仅筛选一个代理会话 id\n --workspace 仅筛选一个已保存的工作区 id\n --surface 仅筛选一个已保存的表面 id\n --cwd 按已保存的 cwd 或启动工作目录筛选\n --state-dir 覆盖 hook 状态目录\n --codex-home 覆盖用于转写检查的默认 Codex home\n --limit 限制文本输出(默认:100)\n --all 输出所有匹配项\n --json 输出结构化 JSON\n\nCodex 行会显示已保存的 id 是否存在于 CODEX_HOME/session_index.jsonl,\n以及在 CODEX_HOME/sessions 或 CODEX_HOME/archived_sessions 下\n是否存在匹配的转写文件。\n\n兼容别名:\n cmux sessions debug [options]\n cmux session-debug [options]" + } } } }, @@ -59810,6 +66244,12 @@ "state": "translated", "value": "sidebar %@: --all またはサイドバー名のどちらか一方を指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "sidebar %@:请使用 --all 或某个 sidebar 名称,不能同时使用" + } } } }, @@ -59827,6 +66267,12 @@ "state": "translated", "value": "sidebar にはサブコマンド validate、reload、select、open のいずれかが必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "sidebar 需要一个子命令:validate、reload、select 或 open" + } } } }, @@ -59844,6 +66290,12 @@ "state": "translated", "value": "sidebar %@ は --all をサポートしていません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "sidebar %@ 不支持 --all" + } } } }, @@ -59861,6 +66313,12 @@ "state": "translated", "value": "sidebar %@ にはサイドバー名が 1 つ必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "sidebar %@ 需要一个 sidebar 名称" + } } } }, @@ -59878,6 +66336,12 @@ "state": "translated", "value": "sidebar select は --all をサポートしていません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "sidebar select 不支持 --all" + } } } }, @@ -59895,6 +66359,12 @@ "state": "translated", "value": "sidebar select にはサイドバー名が 1 つ必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "sidebar select 需要一个 sidebar 名称" + } } } }, @@ -59912,6 +66382,12 @@ "state": "translated", "value": "sidebar %@ に指定できるサイドバー名は 1 つまでです" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "sidebar %@ 最多接受一个 sidebar 名称" + } } } }, @@ -59929,6 +66405,12 @@ "state": "translated", "value": "不明な sidebar コマンド '%@'" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知的 sidebar 命令 '%@'" + } } } }, @@ -59946,6 +66428,12 @@ "state": "translated", "value": "カスタムサイドバーが見つかりません。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到自定义侧边栏。" + } } } }, @@ -59963,6 +66451,12 @@ "state": "translated", "value": "エラー %@ [%@] %@: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "ERROR %@ [%@] %@:%@" + } } } }, @@ -59997,6 +66491,12 @@ "state": "translated", "value": "%@ をペイン %@ として開きました。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已将 %@ 作为窗格 %@ 打开。" + } } } }, @@ -60006,7 +66506,69 @@ "en": { "stringUnit": { "state": "translated", - "value": "Reloaded %d valid sidebars. %d valid, %d invalid." + "value": "Reloaded %#@count1@. %#@count2@, %#@count3@." + }, + "substitutions": { + "count1": { + "argNum": 1, + "formatSpecifier": "d", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%d valid sidebar" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%d valid sidebars" + } + } + } + } + }, + "count2": { + "argNum": 2, + "formatSpecifier": "d", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%d valid" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%d valid" + } + } + } + } + }, + "count3": { + "argNum": 3, + "formatSpecifier": "d", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%d invalid" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%d invalid" + } + } + } + } + } } }, "ja": { @@ -60014,6 +66576,80 @@ "state": "translated", "value": "有効なサイドバーを %d 件再読み込みしました。%d 件有効、%d 件無効です。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已重新加载 %d 个有效侧边栏。有效 %d 个,无效 %d 个。" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "%#@count1@. %#@count2@, %#@count3@." + }, + "substitutions": { + "count1": { + "argNum": 1, + "formatSpecifier": "d", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%d gültige Seitenleiste neu geladen" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%d gültige Seitenleisten neu geladen" + } + } + } + } + }, + "count2": { + "argNum": 2, + "formatSpecifier": "d", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%d gültige" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%d gültige" + } + } + } + } + }, + "count3": { + "argNum": 3, + "formatSpecifier": "d", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%d ungültige" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%d ungültige" + } + } + } + } + } + } } } }, @@ -60031,6 +66667,12 @@ "state": "translated", "value": "%@ を選択しました。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已选择 %@。" + } } } }, @@ -60040,7 +66682,49 @@ "en": { "stringUnit": { "state": "translated", - "value": "%d valid, %d invalid." + "value": "%#@count1@, %#@count2@." + }, + "substitutions": { + "count1": { + "argNum": 1, + "formatSpecifier": "d", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%d valid" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%d valid" + } + } + } + } + }, + "count2": { + "argNum": 2, + "formatSpecifier": "d", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%d invalid" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%d invalid" + } + } + } + } + } } }, "ja": { @@ -60048,6 +66732,60 @@ "state": "translated", "value": "%d 件有効、%d 件無効です。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "有效 %d 个,无效 %d 个。" + } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "%#@count1@, %#@count2@." + }, + "substitutions": { + "count1": { + "argNum": 1, + "formatSpecifier": "d", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%d gültige" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%d gültige" + } + } + } + } + }, + "count2": { + "argNum": 2, + "formatSpecifier": "d", + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%d ungültige" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%d ungültige" + } + } + } + } + } + } } } }, @@ -60065,6 +66803,12 @@ "state": "translated", "value": "不明なエラー" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知错误" + } } } }, @@ -60082,6 +66826,12 @@ "state": "translated", "value": "使用法: cmux sidebar [name|--all] [--json]\n\n~/.config/cmux/sidebars のカスタムサイドバーを検証、再読み込み、選択、または開きます。\n同じベース名の JSON ファイルより Swift ファイルが優先されます。\n\nコマンド:\n validate [name] すべてのカスタムサイドバー、または指定したサイドバーを検証します\n reload [name] すべてのサイドバーを検証して、有効なものを再読み込みします\n select 指定したカスタムサイドバーを検証して有効化します\n open 指定したカスタムサイドバーを Bonsplit ペインとして開きます\n\n例:\n cmux sidebar validate\n cmux sidebar reload --all\n cmux sidebar select finder.tree\n cmux sidebar open finder.tree" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:cmux sidebar [name|--all] [--json]\n\n校验、重新加载、选择或打开 ~/.config/cmux/sidebars 中的自定义侧边栏。\n同名情况下,Swift 文件优先于 JSON 文件。\n\n命令:\n validate [name] 校验所有自定义侧边栏,或校验指定名称的一个\n reload [name] 校验所有侧边栏,然后重新加载每一个有效的侧边栏\n select 校验并激活一个自定义侧边栏\n open 将一个自定义侧边栏作为 Bonsplit 窗格打开\n\n示例:\n cmux sidebar validate\n cmux sidebar reload --all\n cmux sidebar select finder.tree\n cmux sidebar open finder.tree" + } } } }, @@ -60099,6 +66849,12 @@ "state": "translated", "value": "Simulatorワーカーからアクセシビリティスナップショットが返されませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器 worker 未返回辅助功能快照" + } } } }, @@ -60116,6 +66872,12 @@ "state": "translated", "value": "複数のSimulatorサーフェスが見つかりました。surface_idを指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "找到多个模拟器表面;请传入 surface_id" + } } } }, @@ -60133,6 +66895,12 @@ "state": "translated", "value": "呼び出し元のサーフェスは利用できなくなりました。--surface または --window でSimulatorを選択してください。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "调用方表面已不可用。请传入 --surface 或 --window 以选择模拟器。" + } } } }, @@ -60150,6 +66918,12 @@ "state": "translated", "value": "Simulatorのカメラ操作に失敗しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器摄像头操作失败" + } } } }, @@ -60167,6 +66941,12 @@ "state": "translated", "value": "カメラソース%@にはファイルパスが必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "摄像头源 %@ 需要一个文件路径" + } } } }, @@ -60184,6 +66964,12 @@ "state": "translated", "value": "Simulatorワーカーからカメラ状態が返されませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器 worker 未返回摄像头状态" + } } } }, @@ -60201,6 +66987,12 @@ "state": "translated", "value": "カメラファイルを画像または動画として読み込めません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "摄像头文件不是可读的图片或视频" + } } } }, @@ -60218,6 +67010,12 @@ "state": "translated", "value": "現在のSimulatorワーカーはこの操作に対応していません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "当前的模拟器 worker 不支持此操作" + } } } }, @@ -60235,6 +67033,12 @@ "state": "translated", "value": "Simulatorペインでデバイスが選択されていません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "该模拟器窗格未选择设备" + } } } }, @@ -60252,6 +67056,12 @@ "state": "translated", "value": "Simulatorはリモートで無効化されています" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器已被远程禁用" + } } } }, @@ -60269,6 +67079,12 @@ "state": "translated", "value": "SimulatorワーカーからフォアグラウンドAppの結果が返されませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器 worker 未返回前台应用结果" + } } } }, @@ -60286,6 +67102,12 @@ "state": "translated", "value": "Simulator入力の送信に失敗しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器输入传输失败" + } } } }, @@ -60303,6 +67125,12 @@ "state": "translated", "value": "期限までにSimulator入力の送信が完了しませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器输入传输未在期限内完成" + } } } }, @@ -60310,9 +67138,21 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "simulator input exceeds the %lld-byte UTF-8 limit" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "simulator input exceeds the %lld-byte UTF-8 limit" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "simulator input exceeds the %lld-byte UTF-8 limit" + } + } + } } }, "ja": { @@ -60320,6 +67160,30 @@ "state": "translated", "value": "Simulator入力がUTF-8の%lldバイト制限を超えています" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "simulator input 超过了 %lld 字节的 UTF-8 上限" + } + }, + "de": { + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Simulatoreingabe überschreitet das %lld-Byte-UTF-8-Limit" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Simulatoreingabe überschreitet das %lld-Byte-UTF-8-Limit" + } + } + } + } } } }, @@ -60337,6 +67201,12 @@ "state": "translated", "value": "Simulatorワーカーからインターフェース状態が返されませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器 worker 未返回界面状态" + } } } }, @@ -60354,6 +67224,12 @@ "state": "translated", "value": "simulator %@ の引数が無効です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "simulator %@ 的参数无效" + } } } }, @@ -60371,6 +67247,12 @@ "state": "translated", "value": "Simulatorアプリのバンドル識別子が無効です: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无效的模拟器应用 bundle identifier:%@" + } } } }, @@ -60388,6 +67270,12 @@ "state": "translated", "value": "Simulator座標は0から1までの数値で指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器坐标必须是 0 到 1 之间的数字" + } } } }, @@ -60405,6 +67293,12 @@ "state": "translated", "value": "simulator gesture にはJSONタッチオブジェクトまたは配列が必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "simulator gesture 需要一个 JSON 触摸对象或数组" + } } } }, @@ -60422,6 +67316,12 @@ "state": "translated", "value": "simulator highlight には on または off が必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "simulator highlight 需要 on 或 off" + } } } }, @@ -60439,6 +67339,12 @@ "state": "translated", "value": "カメラのミラーモードはauto、on、offのいずれかで指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "摄像头镜像模式必须为 auto、on 或 off" + } } } }, @@ -60456,6 +67362,12 @@ "state": "translated", "value": "Simulatorのパラメータが無効です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无效的模拟器参数" + } } } }, @@ -60473,6 +67385,12 @@ "state": "translated", "value": "Simulatorの権限操作またはサービスが無効です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器权限操作或服务无效" + } } } }, @@ -60490,6 +67408,12 @@ "state": "translated", "value": "値'%@'はSimulator権限%@では無効です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "'%@' 不是模拟器权限 %@ 的有效值" + } } } }, @@ -60507,6 +67431,12 @@ "state": "translated", "value": "Simulatorツールの操作には show、hide、toggle のいずれかを指定してください" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器 tools 操作必须为 show、hide 或 toggle" + } } } }, @@ -60524,6 +67454,12 @@ "state": "translated", "value": "Simulatorのインターフェース項目または値が無効です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器界面选项或值无效" + } } } }, @@ -60541,6 +67477,12 @@ "state": "translated", "value": "値'%@'はSimulatorインターフェース項目%@では無効です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "'%@' 不是模拟器界面选项 %@ 的有效值" + } } } }, @@ -60558,6 +67500,12 @@ "state": "translated", "value": "Simulator入力は有効なUTF-8である必要があります" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "simulator input 必须是有效的 UTF-8" + } } } }, @@ -60575,6 +67523,12 @@ "state": "translated", "value": "Simulatorのキーボード入力を使用できません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器键盘输入不可用" + } } } }, @@ -60592,6 +67546,12 @@ "state": "translated", "value": "simulator: %@ には値が必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "simulator:%@ 需要一个值" + } } } }, @@ -60609,6 +67569,12 @@ "state": "translated", "value": "アクティブなcmuxウィンドウがありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有活动的 cmux 窗口" + } } } }, @@ -60626,6 +67592,12 @@ "state": "translated", "value": "Simulatorペインでデバイスが選択されていません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "该模拟器窗格未选择设备" + } } } }, @@ -60643,6 +67615,12 @@ "state": "translated", "value": "選択したSimulatorはストリーミング中ではありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "所选模拟器未在串流" + } } } }, @@ -60660,6 +67638,12 @@ "state": "translated", "value": "Simulator操作はキャンセルされました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器操作已取消" + } } } }, @@ -60677,6 +67661,12 @@ "state": "translated", "value": "Simulator操作に失敗しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器操作失败" + } } } }, @@ -60694,6 +67684,12 @@ "state": "translated", "value": "期限までにSimulator操作が完了しませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器操作未在期限内完成" + } } } }, @@ -60711,6 +67707,12 @@ "state": "translated", "value": "このSimulator操作は使用できません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "此模拟器操作不可用" + } } } }, @@ -60728,6 +67730,12 @@ "state": "translated", "value": "操作の開始前にSimulatorペインが閉じられました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器窗格在操作开始前已关闭" + } } } }, @@ -60745,6 +67753,12 @@ "state": "translated", "value": "Simulatorワーカーから権限状態が返されませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器 worker 未返回权限状态" + } } } }, @@ -60762,6 +67776,12 @@ "state": "translated", "value": "リモートワークスペースではSimulatorを操作できません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "远程工作区中无法使用模拟器控制" + } } } }, @@ -60779,6 +67799,12 @@ "state": "translated", "value": "Simulatorサーフェスが見つかりません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到模拟器表面" + } } } }, @@ -60796,6 +67822,12 @@ "state": "translated", "value": "Simulator入力には位置引数、--stdin、または--fileが必要です" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "simulator input 需要一个位置参数值、--stdin 或 --file" + } } } }, @@ -60813,6 +67845,12 @@ "state": "translated", "value": "Simulator入力元は同時に指定できません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "simulator input 的各输入源互斥" + } } } }, @@ -60830,6 +67868,12 @@ "state": "translated", "value": "サーフェスが見つかりません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到表面" + } } } }, @@ -60847,6 +67891,12 @@ "state": "translated", "value": "対象のサーフェスはSimulatorではありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "目标表面不是模拟器" + } } } }, @@ -60864,6 +67914,12 @@ "state": "translated", "value": "テキストを空にすることはできません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "文本不能为空" + } } } }, @@ -60871,9 +67927,21 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "Text exceeds the %lld-byte UTF-8 limit" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Text exceeds the %lld-byte UTF-8 limit" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Text exceeds the %lld-byte UTF-8 limit" + } + } + } } }, "ja": { @@ -60881,6 +67949,30 @@ "state": "translated", "value": "テキストがUTF-8の%lldバイト制限を超えています" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "文本超过了 %lld 字节的 UTF-8 上限" + } + }, + "de": { + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Text überschreitet das %lld-Byte-UTF-8-Limit" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Text überschreitet das %lld-Byte-UTF-8-Limit" + } + } + } + } } } }, @@ -60898,6 +67990,12 @@ "state": "translated", "value": "実行中のSimulator操作が多すぎます" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "正在运行的模拟器操作过多" + } } } }, @@ -60915,6 +68013,12 @@ "state": "translated", "value": "Simulator入力を送信できません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器输入传输不可用" + } } } }, @@ -60932,6 +68036,12 @@ "state": "translated", "value": "Simulator入力の位置引数は引用符で囲んだ1つの値だけ指定できます" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "simulator input 只接受一个带引号的位置参数值" + } } } }, @@ -60949,6 +68059,12 @@ "state": "translated", "value": "simulator %@ は入力を受け付けません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "simulator %@ 不接受输入" + } } } }, @@ -60966,6 +68082,12 @@ "state": "translated", "value": "不明なSimulatorハードウェアボタン: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知的模拟器硬件按键:%@" + } } } }, @@ -60983,6 +68105,12 @@ "state": "translated", "value": "不明なCore Animation診断: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知的 Core Animation 诊断项:%@" + } } } }, @@ -61000,6 +68128,12 @@ "state": "translated", "value": "不明なSimulatorカメラソース: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知的模拟器摄像头源:%@" + } } } }, @@ -61017,6 +68151,12 @@ "state": "translated", "value": "simulator: 不明なフラグ '%@'" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "simulator:未知标志 '%@'" + } } } }, @@ -61034,6 +68174,12 @@ "state": "translated", "value": "不明なSimulatorの向き: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知的模拟器方向:%@" + } } } }, @@ -61051,6 +68197,12 @@ "state": "translated", "value": "不明または未対応のSimulator権限です: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知或不受支持的模拟器权限:%@" + } } } }, @@ -61068,6 +68220,12 @@ "state": "translated", "value": "不明なSimulatorサブコマンド: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知的 simulator 子命令:%@" + } } } }, @@ -61085,6 +68243,12 @@ "state": "translated", "value": "不明なSimulatorタッチエッジ: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知的模拟器触摸边缘:%@" + } } } }, @@ -61102,6 +68266,12 @@ "state": "translated", "value": "不明なSimulatorタッチフェーズ: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知的模拟器触摸阶段:%@" + } } } }, @@ -61119,6 +68289,12 @@ "state": "translated", "value": "不明なSimulatorインターフェース項目です: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未知的模拟器界面选项:%@" + } } } }, @@ -61136,6 +68312,12 @@ "state": "translated", "value": "テキストにSimulator入力で使用できない文字が含まれています" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "文本包含模拟器输入不支持的字符" + } } } }, @@ -61153,6 +68335,12 @@ "state": "translated", "value": "Web Inspector対象が接続されていません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未附加 Web Inspector 目标" + } } } }, @@ -61170,6 +68358,12 @@ "state": "translated", "value": "Web Inspector操作に失敗しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Web Inspector 操作失败" + } } } }, @@ -61187,6 +68381,12 @@ "state": "translated", "value": "Web Inspectorセッションを解放できませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "无法释放 Web Inspector 会话" + } } } }, @@ -61204,6 +68404,12 @@ "state": "translated", "value": "Web Inspector対象が見つかりません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到 Web Inspector 目标" + } } } }, @@ -61221,6 +68427,12 @@ "state": "translated", "value": "期限までにWeb Inspector操作が完了しませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Web Inspector 操作未在期限内完成" + } } } }, @@ -61238,6 +68450,12 @@ "state": "translated", "value": "ネイティブWeb Inspectorを使用できません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "原生 Web Inspector 不可用" + } } } }, @@ -61255,6 +68473,12 @@ "state": "translated", "value": "操作の完了前にSimulatorワーカーが停止しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器 worker 在完成操作前已停止" + } } } }, @@ -61272,6 +68496,12 @@ "state": "translated", "value": "期限までにSimulatorワーカーが応答しませんでした" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "模拟器 worker 未在期限内响应" + } } } }, @@ -61289,6 +68519,48 @@ "state": "translated", "value": "ワークスペースが見つかりません" } + }, + "de": { + "stringUnit": { + "state": "translated", + "value": "Workspace nicht gefunden" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Espace de travail introuvable" + } + }, + "ar": { + "stringUnit": { + "state": "translated", + "value": "لم يتم العثور على مساحة العمل" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Espacio de trabajo no encontrado" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "找不到工作區" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到工作区" + } + }, + "ko": { + "stringUnit": { + "state": "translated", + "value": "워크스페이스를 찾을 수 없습니다" + } } } }, @@ -61306,6 +68578,12 @@ "state": "translated", "value": "完了しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已完成" + } } } }, @@ -61323,6 +68601,12 @@ "state": "translated", "value": "アクセシビリティ結果が500要素の上限に達しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "辅助功能结果已达到 500 个元素的上限" + } } } }, @@ -61340,6 +68624,12 @@ "state": "translated", "value": "%@を%@に設定しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已将 %@ 设为 %@" + } } } }, @@ -61357,6 +68647,12 @@ "state": "translated", "value": "フォアグラウンドAppがありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有前台应用" + } } } }, @@ -61374,6 +68670,12 @@ "state": "translated", "value": "インターフェース設定がありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有界面设置" + } } } }, @@ -61391,6 +68693,12 @@ "state": "translated", "value": "権限の値がありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有权限值" + } } } }, @@ -61408,6 +68716,12 @@ "state": "translated", "value": "Web Inspector対象がありません" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有 Web Inspector 目标" + } } } }, @@ -61425,6 +68739,12 @@ "state": "translated", "value": "操作: %@、権限: %@、アプリ: %@" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%@ %@(针对 %@)" + } } } }, @@ -61442,6 +68762,12 @@ "state": "translated", "value": "権限の結果は256個のアプリで切り捨てられました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "权限结果已在 256 个应用处截断" + } } } }, @@ -61449,9 +68775,21 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "Typed %lld character(s)" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Typed %lld character" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Typed %lld characters" + } + } + } } }, "ja": { @@ -61459,6 +68797,30 @@ "state": "translated", "value": "%lld文字を入力しました" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已输入 %lld 个字符" + } + }, + "de": { + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%lld Zeichen getippt" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%lld Zeichen getippt" + } + } + } + } } } }, @@ -61476,6 +68838,12 @@ "state": "translated", "value": "使用方法:\n cmux simulator permissions list [bundle-id] [--surface ]\n cmux simulator permissions grant [--value ] [--surface ]\n cmux simulator permissions revoke [--surface ]\n cmux simulator permissions reset [--surface ]\n\n値: photos は limited、notifications は critical、location は always、inuse、never。" } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:\n cmux simulator permissions list [bundle-id] [--surface ]\n cmux simulator permissions grant [--value ] [--surface ]\n cmux simulator permissions revoke [--surface ]\n cmux simulator permissions reset [--surface ]\n\n取值:photos 为 limited;notifications 为 critical;location 为 always、inuse 或 never。" + } } } }, @@ -61493,6 +68861,12 @@ "state": "translated", "value": "使用方法:\n cmux simulator ui [status] [--surface ]\n cmux simulator ui [get]