diff --git a/config/mobile-localization-coverage-allowlist.json b/config/mobile-localization-coverage-allowlist.json
index f3b4a7c8bc5..8b3a409b7aa 100644
--- a/config/mobile-localization-coverage-allowlist.json
+++ b/config/mobile-localization-coverage-allowlist.json
@@ -202,97 +202,6 @@
"dynamic": false,
"count": 1
},
- {
- "filePath": "mobile/src/components/AgentLaunchNotice.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Copy prompt",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/AgentLaunchNotice.tsx",
- "kind": "object-property:label",
- "text": "Copied",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/AgentLaunchNotice.tsx",
- "kind": "object-property:label",
- "text": "Couldn't copy",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/AgentSpinner.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Couldn’t confirm",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/AgentSpinner.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Monitoring background tasks",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/AgentStateDot.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Monitoring background tasks",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/AgentStateDot.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "No recent update",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/AuthFailedBanner.tsx",
- "kind": "jsx-text",
- "text": "Authentication failed — try reconnecting first; if it keeps failing, re-pair from desktop.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/AuthFailedBannerActions.tsx",
- "kind": "jsx-text",
- "text": "Re-pair",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/AuthFailedBannerActions.tsx",
- "kind": "jsx-text",
- "text": "Remove",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/AuthFailedBannerActions.tsx",
- "kind": "jsx-text",
- "text": "Retry",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/AuthFailedBannerActions.web.tsx",
- "kind": "jsx-text",
- "text": "Re-pair",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/AuthFailedBannerActions.web.tsx",
- "kind": "jsx-text",
- "text": "Reconnect or remove this host from the Orca app.",
- "dynamic": false,
- "count": 1
- },
{
"filePath": "mobile/src/components/codex-reset-credit-reply-schema.ts",
"kind": "object-property:message",
@@ -307,251 +216,6 @@
"dynamic": false,
"count": 1
},
- {
- "filePath": "mobile/src/components/codex-reset-credit.ts",
- "kind": "object-property:message",
- "text": "Codex usage has been refreshed.",
- "dynamic": false,
- "count": 2
- },
- {
- "filePath": "mobile/src/components/codex-reset-credit.ts",
- "kind": "object-property:message",
- "text": "No eligible Codex rate-limit window is exhausted.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/codex-reset-credit.ts",
- "kind": "object-property:message",
- "text": "This account has no earned reset credits available.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/codex-reset-credit.ts",
- "kind": "object-property:title",
- "text": "No reset available",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/codex-reset-credit.ts",
- "kind": "object-property:title",
- "text": "Nothing to reset",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/codex-reset-credit.ts",
- "kind": "object-property:title",
- "text": "Rate limits reset",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/codex-reset-credit.ts",
- "kind": "object-property:title",
- "text": "Reset already applied",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CodexResetCreditAction.tsx",
- "kind": "jsx-attribute:accessibilityHint",
- "text": "Uses one earned reset for",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CodexResetCreditAction.tsx",
- "kind": "jsx-attribute:accessibilityHint",
- "text": "Uses one earned reset for the active Codex account",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CodexResetCreditAction.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Resetting Codex rate limits",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CodexResetCreditAction.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Use Codex rate-limit reset",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CodexResetCreditAction.tsx",
- "kind": "jsx-expression",
- "text": "Earned Codex rate-limit reset",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CodexResetCreditAction.tsx",
- "kind": "jsx-expression",
- "text": "Resetting…",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CodexResetCreditAction.tsx",
- "kind": "jsx-expression",
- "text": "Use reset",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Back",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-attribute:placeholder",
- "text": "e.g. Build",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-attribute:placeholder",
- "text": "e.g. pnpm build",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-expression",
- "text": "Add Shortcut",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-expression",
- "text": "Pick a key",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-expression",
- "text": "Shortcut Combo",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-expression",
- "text": "Text Macro",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-text",
- "text": "Add",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-text",
- "text": "Add Shortcut",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-text",
- "text": "Build Ctrl, Alt, and Shift key chords",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-text",
- "text": "Command",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-text",
- "text": "Key",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-text",
- "text": "Label",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-text",
- "text": "Manage Shortcuts",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-text",
- "text": "Modifiers",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-text",
- "text": "More keys — Tab, arrows, F1–F12…",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-text",
- "text": "Press Enter",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-text",
- "text": "Send custom text command",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-text",
- "text": "Shortcut Combo",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-text",
- "text": "Show, hide, or reorder shortcut keys",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "jsx-text",
- "text": "Text Macro",
- "dynamic": false,
- "count": 1
- },
{
"filePath": "mobile/src/components/CustomKeyModal.tsx",
"kind": "object-property:label",
@@ -573,125 +237,6 @@
"dynamic": false,
"count": 1
},
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "object-property:title",
- "text": "Editing",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "object-property:title",
- "text": "Function",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/CustomKeyModal.tsx",
- "kind": "object-property:title",
- "text": "Navigation",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/DragReorderRow.tsx",
- "kind": "jsx-attribute:accessibilityHint",
- "text": "Use the move up and move down actions to reorder without dragging",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/DragReorderRow.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Drag to reorder",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/DragReorderRow.tsx",
- "kind": "object-property:label",
- "text": "Move down",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/DragReorderRow.tsx",
- "kind": "object-property:label",
- "text": "Move up",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/HostDiagnosticsLink.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "View network diagnostics",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/HostDiagnosticsLink.tsx",
- "kind": "jsx-text",
- "text": "View network diagnostics",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/HostProtocolGate.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Checking host compatibility",
- "dynamic": false,
- "count": 2
- },
- {
- "filePath": "mobile/src/components/HostRouteNoticeBanner.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Dismiss notice",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/JiraConnectPrompt.tsx",
- "kind": "jsx-expression",
- "text": "Add your Jira site in Orca desktop under Settings → Integrations, then check again.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/JiraConnectPrompt.tsx",
- "kind": "jsx-expression",
- "text": "Connect Jira on your desktop",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/JiraConnectPrompt.tsx",
- "kind": "jsx-expression",
- "text": "Jira is saved but unreadable:",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/JiraConnectPrompt.tsx",
- "kind": "jsx-expression",
- "text": "Update Orca desktop",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/JiraConnectPrompt.tsx",
- "kind": "jsx-text",
- "text": "Check again",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/mobile-markdown-blocks.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Copy code",
- "dynamic": false,
- "count": 1
- },
{
"filePath": "mobile/src/components/mobile-markdown-blocks.tsx",
"kind": "jsx-expression",
@@ -699,671 +244,6 @@
"dynamic": false,
"count": 1
},
- {
- "filePath": "mobile/src/components/mobile-markdown-blocks.tsx",
- "kind": "jsx-expression",
- "text": "Open image",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDictationSetupSheet.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Dictation enabled",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDictationSetupSheet.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Download",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDictationSetupSheet.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Use",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDictationSetupSheet.tsx",
- "kind": "jsx-expression",
- "text": "· extracting…",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDictationSetupSheet.tsx",
- "kind": "jsx-expression",
- "text": "OpenAI API",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDictationSetupSheet.tsx",
- "kind": "jsx-text",
- "text": "Dictation enabled",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDictationSetupSheet.tsx",
- "kind": "jsx-text",
- "text": "Download",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDictationSetupSheet.tsx",
- "kind": "jsx-text",
- "text": "Download or pick a model and enable dictation on the paired computer — all from here.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDictationSetupSheet.tsx",
- "kind": "jsx-text",
- "text": "In use",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDictationSetupSheet.tsx",
- "kind": "jsx-text",
- "text": "Recommended",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDictationSetupSheet.tsx",
- "kind": "jsx-text",
- "text": "Set up voice dictation",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDictationSetupSheet.tsx",
- "kind": "jsx-text",
- "text": "Use",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewBody.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Retry loading review",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewBody.tsx",
- "kind": "jsx-attribute:text",
- "text": "Loading diff...",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewBody.tsx",
- "kind": "jsx-attribute:text",
- "text": "Loading review...",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewBody.tsx",
- "kind": "jsx-attribute:text",
- "text": "Try a different review filter.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewBody.tsx",
- "kind": "jsx-attribute:title",
- "text": "No Reviewable Changes",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewBody.tsx",
- "kind": "jsx-attribute:title",
- "text": "Review Unavailable",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewBody.tsx",
- "kind": "jsx-attribute:title",
- "text": "Unable to Load Review",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewBody.tsx",
- "kind": "jsx-text",
- "text": "Diff truncated for mobile preview.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewBody.tsx",
- "kind": "jsx-text",
- "text": "Retry",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Cancel note",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Delete note",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Send notes to agent",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Stage reviewed files",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-attribute:message",
- "text": "\"? This cannot be undone.",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-attribute:message",
- "text": "Discard changes to \"",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-attribute:message",
- "text": "reviewed unstaged files can be staged",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-attribute:placeholder",
- "text": "Review note",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-attribute:title",
- "text": "Discard File",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-attribute:title",
- "text": "Review Actions",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-attribute:title",
- "text": "Send Notes",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-expression",
- "text": "Add Note",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-expression",
- "text": "Edit Note",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-expression",
- "text": "File note",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-expression",
- "text": "Line",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-text",
- "text": "Delete",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-text",
- "text": "Review Complete",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-text",
- "text": "reviewed,",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-text",
- "text": "Save",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-text",
- "text": "Send Notes",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "jsx-text",
- "text": "Stage Reviewed",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "object-property:label",
- "text": "Clear Sent Notes",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "object-property:label",
- "text": "Copy Notes",
- "dynamic": false,
- "count": 2
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "object-property:label",
- "text": "Mark Unreviewed",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "object-property:label",
- "text": "New Agent Session",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "object-property:label",
- "text": "Open in Session",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "object-property:label",
- "text": "Send Unsent Notes",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewDrawers.tsx",
- "kind": "object-property:label",
- "text": "Stage Reviewed Files",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFileSummary.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Edit file note",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFileSummary.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Next hunk",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFileSummary.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Previous hunk",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFileSummary.tsx",
- "kind": "jsx-expression",
- "text": "from",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFileSummary.tsx",
- "kind": "jsx-text",
- "text": "Changed",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFileSummary.tsx",
- "kind": "jsx-text",
- "text": "Hunk",
- "dynamic": false,
- "count": 2
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFileSummary.tsx",
- "kind": "jsx-text",
- "text": "Reviewed",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFileSummary.tsx",
- "kind": "jsx-text",
- "text": "stale",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFileSummary.tsx",
- "kind": "jsx-text",
- "text": "Stale",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFooter.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Add file note",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFooter.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Discard file",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFooter.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Mark file reviewed",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFooter.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Next file",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFooter.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Previous file",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFooter.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Stage file",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFooter.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Unstage file",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFooter.tsx",
- "kind": "jsx-expression",
- "text": "Mark Reviewed",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFooter.tsx",
- "kind": "jsx-expression",
- "text": "Reviewed",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFooter.tsx",
- "kind": "jsx-text",
- "text": "Discard",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFooter.tsx",
- "kind": "jsx-text",
- "text": "Note",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFooter.tsx",
- "kind": "jsx-text",
- "text": "Stage",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewFooter.tsx",
- "kind": "jsx-text",
- "text": "Unstage",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewHeader.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Back",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewHeader.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Open pull request sidebar",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewHeader.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Open review actions",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewHeader.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "review files",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewHeader.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Show",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewHeader.tsx",
- "kind": "jsx-expression",
- "text": "All",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewHeader.tsx",
- "kind": "jsx-text",
- "text": "Changes",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewHeader.tsx",
- "kind": "jsx-text",
- "text": "reviewed",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewLine.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Add note on line",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileDiffReviewLine.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Edit note on line",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileHomeQuickActions.tsx",
- "kind": "jsx-text",
- "text": "New Workspace",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileHomeQuickActions.tsx",
- "kind": "jsx-text",
- "text": "Pair Desktop",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileHomeQuickActions.tsx",
- "kind": "jsx-text",
- "text": "Quick Actions",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileHostCard.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Actions for",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileHtmlPreview.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Preview rendered HTML",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileHtmlPreview.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "View HTML source",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileHtmlPreview.tsx",
- "kind": "jsx-attribute:title",
- "text": "HTML preview",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileHtmlPreview.tsx",
- "kind": "jsx-text",
- "text": "Preview",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileHtmlPreview.tsx",
- "kind": "jsx-text",
- "text": "Source",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileLoadErrorState.tsx",
- "kind": "jsx-attribute:label",
- "text": "Retry",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobilePRSidebar.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Retry loading pull request",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobilePRSidebar.tsx",
- "kind": "jsx-text",
- "text": "Loading pull request…",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobilePRSidebar.tsx",
- "kind": "jsx-text",
- "text": "Retry",
- "dynamic": false,
- "count": 1
- },
{
"filePath": "mobile/src/components/MobileRichMarkdownEditor.tsx",
"kind": "jsx-attribute:placeholder",
@@ -1371,167 +251,6 @@
"dynamic": false,
"count": 1
},
- {
- "filePath": "mobile/src/components/MobileRichMarkdownToolbar.tsx",
- "kind": "object-property:label",
- "text": "Body",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileRichMarkdownToolbar.tsx",
- "kind": "object-property:label",
- "text": "Bold",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileRichMarkdownToolbar.tsx",
- "kind": "object-property:label",
- "text": "Bullet list",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileRichMarkdownToolbar.tsx",
- "kind": "object-property:label",
- "text": "Checklist",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileRichMarkdownToolbar.tsx",
- "kind": "object-property:label",
- "text": "Code block",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileRichMarkdownToolbar.tsx",
- "kind": "object-property:label",
- "text": "H1",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileRichMarkdownToolbar.tsx",
- "kind": "object-property:label",
- "text": "H2",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileRichMarkdownToolbar.tsx",
- "kind": "object-property:label",
- "text": "H3",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileRichMarkdownToolbar.tsx",
- "kind": "object-property:label",
- "text": "Image",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileRichMarkdownToolbar.tsx",
- "kind": "object-property:label",
- "text": "Inline code",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileRichMarkdownToolbar.tsx",
- "kind": "object-property:label",
- "text": "Italic",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileRichMarkdownToolbar.tsx",
- "kind": "object-property:label",
- "text": "Link",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileRichMarkdownToolbar.tsx",
- "kind": "object-property:label",
- "text": "Numbered list",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileRichMarkdownToolbar.tsx",
- "kind": "object-property:label",
- "text": "Quote",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileRichMarkdownToolbar.tsx",
- "kind": "object-property:label",
- "text": "Strike",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileSourceCopyButton.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Couldn't copy",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileSourceCopyButton.tsx",
- "kind": "user-visible-call",
- "text": "Copy failed",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileSourceCopyButton.tsx",
- "kind": "user-visible-call",
- "text": "The clipboard rejected the text.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/MobileWorkspaceNameInput.tsx",
- "kind": "jsx-attribute:placeholder",
- "text": "Workspace name",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/mounted-bottom-drawer.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Dismiss drawer",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/new-worktree-agent-selection.ts",
- "kind": "object-property:label",
- "text": "Blank Terminal",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorkspaceFab.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "New workspace",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorkspaceSetupScriptField.tsx",
- "kind": "jsx-expression",
- "text": "HOOKS",
- "dynamic": false,
- "count": 1
- },
{
"filePath": "mobile/src/components/NewWorkspaceSetupScriptField.tsx",
"kind": "jsx-expression",
@@ -1539,188 +258,6 @@
"dynamic": false,
"count": 1
},
- {
- "filePath": "mobile/src/components/NewWorkspaceSetupScriptField.tsx",
- "kind": "jsx-text",
- "text": "Run",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorkspaceSetupScriptField.tsx",
- "kind": "jsx-text",
- "text": "Run setup command",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorkspaceSetupScriptField.tsx",
- "kind": "jsx-text",
- "text": "Setup script",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorkspaceSetupScriptField.tsx",
- "kind": "jsx-text",
- "text": "Skip",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorkspaceSshConnectionField.tsx",
- "kind": "jsx-expression",
- "text": "Connect",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorkspaceSshConnectionField.tsx",
- "kind": "jsx-expression",
- "text": "Connecting...",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorkspaceSshConnectionField.tsx",
- "kind": "jsx-text",
- "text": "Its server needs recovering from the desktop: Settings → SSH hosts → Recover server.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorkspaceSshConnectionField.tsx",
- "kind": "jsx-text",
- "text": "SSH Connection",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeFormSheet.tsx",
- "kind": "jsx-attribute:label",
- "text": "Name or 'Create From'",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeFormSheet.tsx",
- "kind": "jsx-attribute:label",
- "text": "Workspace name",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeFormSheet.tsx",
- "kind": "jsx-attribute:placeholder",
- "text": "Write a note",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeFormSheet.tsx",
- "kind": "jsx-expression",
- "text": "Connect target",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeFormSheet.tsx",
- "kind": "jsx-expression",
- "text": "Connect target first",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeFormSheet.tsx",
- "kind": "jsx-expression",
- "text": "Create worktree",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeFormSheet.tsx",
- "kind": "jsx-text",
- "text": "Advanced",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeFormSheet.tsx",
- "kind": "jsx-text",
- "text": "Agent",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeFormSheet.tsx",
- "kind": "jsx-text",
- "text": "Create worktree",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeFormSheet.tsx",
- "kind": "jsx-text",
- "text": "No projects found",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeFormSheet.tsx",
- "kind": "jsx-text",
- "text": "Note",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeModalDrawers.tsx",
- "kind": "jsx-attribute:title",
- "text": "Agent",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeModalDrawers.tsx",
- "kind": "jsx-attribute:title",
- "text": "Project",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeModalDrawers.tsx",
- "kind": "jsx-attribute:title",
- "text": "Run on",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeProjectTargetFields.tsx",
- "kind": "jsx-attribute:placeholder",
- "text": "Select a project",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeProjectTargetFields.tsx",
- "kind": "jsx-attribute:placeholder",
- "text": "Select a run target",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeProjectTargetFields.tsx",
- "kind": "jsx-text",
- "text": "Project",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/NewWorktreeProjectTargetFields.tsx",
- "kind": "jsx-text",
- "text": "Run on",
- "dynamic": false,
- "count": 1
- },
{
"filePath": "mobile/src/components/pr-sidebar/MermaidDiagram.tsx",
"kind": "jsx-text",
@@ -1728,1385 +265,6 @@
"dynamic": false,
"count": 1
},
- {
- "filePath": "mobile/src/components/pr-sidebar/MobileLinkPrForm.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Cancel",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/MobileLinkPrForm.tsx",
- "kind": "jsx-attribute:placeholder",
- "text": "#123 or https://github.com/owner/repo/pull/123",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/MobileLinkPrForm.tsx",
- "kind": "jsx-expression",
- "text": "Link #",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/MobileLinkPrForm.tsx",
- "kind": "jsx-expression",
- "text": "Link pull request",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/MobileLinkPrForm.tsx",
- "kind": "jsx-text",
- "text": "Cancel",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/MobileLinkPrForm.tsx",
- "kind": "jsx-text",
- "text": "Link existing pull request",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/MobileLinkPrForm.tsx",
- "kind": "jsx-text",
- "text": "PR number or GitHub URL",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/MobilePrViewPanel.tsx",
- "kind": "object-property:message",
- "text": "Current branch unavailable.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/MobilePrViewPanel.tsx",
- "kind": "object-property:message",
- "text": "Hosted review panel unavailable for this provider.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-actions-state.ts",
- "kind": "object-property:label",
- "text": "Able to merge",
- "dynamic": false,
- "count": 2
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-actions-state.ts",
- "kind": "object-property:label",
- "text": "Approval required",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-actions-state.ts",
- "kind": "object-property:label",
- "text": "Auto-merge on",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-actions-state.ts",
- "kind": "object-property:label",
- "text": "Behind",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-actions-state.ts",
- "kind": "object-property:label",
- "text": "Blocked",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-actions-state.ts",
- "kind": "object-property:label",
- "text": "Changes requested",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-actions-state.ts",
- "kind": "object-property:label",
- "text": "Checking",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-actions-state.ts",
- "kind": "object-property:label",
- "text": "Checks failed",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-actions-state.ts",
- "kind": "object-property:label",
- "text": "Checks passed",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-actions-state.ts",
- "kind": "object-property:label",
- "text": "Checks pending",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-actions-state.ts",
- "kind": "object-property:label",
- "text": "Closed",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-actions-state.ts",
- "kind": "object-property:label",
- "text": "Conflicts",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-actions-state.ts",
- "kind": "object-property:label",
- "text": "Draft",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-actions-state.ts",
- "kind": "object-property:label",
- "text": "Merge",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-actions-state.ts",
- "kind": "object-property:label",
- "text": "Merge when ready",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-actions-state.ts",
- "kind": "object-property:label",
- "text": "Merged",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-checks-presentation.ts",
- "kind": "object-property:label",
- "text": "No checks",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-comment-audience-labels.ts",
- "kind": "object-property:label",
- "text": "All",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-comment-audience-labels.ts",
- "kind": "object-property:label",
- "text": "Bots",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/pr-comment-audience-labels.ts",
- "kind": "object-property:label",
- "text": "Humans",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Close pull request",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Mark pull request ready for review",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Merge pull request",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Recheck merge status",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Reopen pull request",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Toggle auto-merge",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Unlink pull request",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "jsx-expression",
- "text": "Close",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "jsx-expression",
- "text": "Off",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "jsx-expression",
- "text": "On",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "jsx-expression",
- "text": "Reopen",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "jsx-text",
- "text": "Auto-merge when ready",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "jsx-text",
- "text": "Ready for review",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "jsx-text",
- "text": "Recheck",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "jsx-text",
- "text": "Unlink",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "object-property:message",
- "text": "will be closed without merging.",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "object-property:message",
- "text": "will be reopened.",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "object-property:title",
- "text": "Close pull request?",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "object-property:title",
- "text": "Merge pull request?",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRActionsSection.tsx",
- "kind": "object-property:title",
- "text": "Reopen pull request?",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCheckDetail.tsx",
- "kind": "jsx-text",
- "text": "Annotations",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCheckDetail.tsx",
- "kind": "jsx-text",
- "text": "No details available.",
- "dynamic": false,
- "count": 2
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCheckDetail.tsx",
- "kind": "jsx-text",
- "text": "Showing first 100 jobs",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCheckDetail.tsx",
- "kind": "jsx-text",
- "text": "Showing first 20 annotations",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRChecksSection.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "check details",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRChecksSection.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Fix failing checks with AI",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRChecksSection.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "on the web",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRChecksSection.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Open",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRChecksSection.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Rerun failing checks",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRChecksSection.tsx",
- "kind": "jsx-attribute:title",
- "text": "Checks",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRChecksSection.tsx",
- "kind": "jsx-text",
- "text": "failing check",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRChecksSection.tsx",
- "kind": "jsx-text",
- "text": "Fix",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRChecksSection.tsx",
- "kind": "jsx-text",
- "text": "Inspect details or start an AI fix pass.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentCard.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Delete comment",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentCard.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Edit comment",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentCard.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Open comment on GitHub",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentCard.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Reply to comment",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentCard.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Resolve thread",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentCard.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Unresolve thread",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentCard.tsx",
- "kind": "jsx-attribute:message",
- "text": "This permanently deletes the comment on GitHub.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentCard.tsx",
- "kind": "jsx-attribute:placeholder",
- "text": "Edit comment…",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentCard.tsx",
- "kind": "jsx-attribute:placeholder",
- "text": "Write a reply…",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentCard.tsx",
- "kind": "jsx-attribute:title",
- "text": "Delete comment?",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentCard.tsx",
- "kind": "jsx-expression",
- "text": "Delete",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentCard.tsx",
- "kind": "jsx-expression",
- "text": "Resolve",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentCard.tsx",
- "kind": "jsx-expression",
- "text": "Unresolve",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentCard.tsx",
- "kind": "jsx-text",
- "text": "Edit",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentCard.tsx",
- "kind": "jsx-text",
- "text": "Reply",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentCard.tsx",
- "kind": "jsx-text",
- "text": "resolved",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentComposer.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Cancel",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentComposer.tsx",
- "kind": "jsx-text",
- "text": "Cancel",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentsSection.tsx",
- "kind": "jsx-attribute:placeholder",
- "text": "Add a comment…",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentsSection.tsx",
- "kind": "jsx-attribute:title",
- "text": "Comments",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentsSection.tsx",
- "kind": "jsx-attribute:title",
- "text": "Description",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentsSection.tsx",
- "kind": "jsx-expression",
- "text": "comment",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentsSection.tsx",
- "kind": "jsx-expression",
- "text": "of",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentsSection.tsx",
- "kind": "jsx-expression",
- "text": "thread",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentsSection.tsx",
- "kind": "jsx-text",
- "text": "by",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentsSection.tsx",
- "kind": "jsx-text",
- "text": "Could not load comments. Tap refresh to try again.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentsSection.tsx",
- "kind": "jsx-text",
- "text": "Could not load description. Tap refresh to try again.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentsSection.tsx",
- "kind": "jsx-text",
- "text": "more",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentsSection.tsx",
- "kind": "jsx-text",
- "text": "No comments yet.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentsSection.tsx",
- "kind": "jsx-text",
- "text": "No description provided.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentsSection.tsx",
- "kind": "jsx-text",
- "text": "Resolved",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRCommentsSection.tsx",
- "kind": "jsx-text",
- "text": "Show",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRConflictingFilesSection.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Copy mergeability refresh commands",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRConflictingFilesSection.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Resolve conflicts with AI",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRConflictingFilesSection.tsx",
- "kind": "jsx-attribute:title",
- "text": "Conflicts",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRConflictingFilesSection.tsx",
- "kind": "jsx-text",
- "text": "behind (base commit:",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRConflictingFilesSection.tsx",
- "kind": "jsx-text",
- "text": "commit",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRConflictingFilesSection.tsx",
- "kind": "jsx-text",
- "text": "Conflicting files",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRConflictingFilesSection.tsx",
- "kind": "jsx-text",
- "text": "Resolve conflicts with AI",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRConflictingFilesSection.tsx",
- "kind": "jsx-text",
- "text": "Run from this worktree",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRConflictingFilesSection.tsx",
- "kind": "jsx-text",
- "text": "This branch has conflicts that must be resolved",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRReviewersSection.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Add or remove reviewers",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRReviewersSection.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Remove",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRReviewersSection.tsx",
- "kind": "jsx-attribute:title",
- "text": "Reviewers",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRReviewersSection.tsx",
- "kind": "jsx-text",
- "text": "Could not load reviewers. Tap refresh to try again.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRReviewersSection.tsx",
- "kind": "jsx-text",
- "text": "Loading reviewers…",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRReviewersSection.tsx",
- "kind": "jsx-text",
- "text": "No reviewers requested",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PrSidebarCreateEmptyState.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Create pull request",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PrSidebarCreateEmptyState.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Link an existing pull request",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PrSidebarCreateEmptyState.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Refresh pull request",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PrSidebarCreateEmptyState.tsx",
- "kind": "jsx-expression",
- "text": "is not linked to an open PR.",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PrSidebarCreateEmptyState.tsx",
- "kind": "jsx-expression",
- "text": "Linked PR #",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PrSidebarCreateEmptyState.tsx",
- "kind": "jsx-expression",
- "text": "No open pull request",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PrSidebarCreateEmptyState.tsx",
- "kind": "jsx-expression",
- "text": "Refresh to check again, or create a new PR for this branch.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PrSidebarCreateEmptyState.tsx",
- "kind": "jsx-expression",
- "text": "The current branch is not linked to an open PR.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PrSidebarCreateEmptyState.tsx",
- "kind": "jsx-expression",
- "text": "unavailable",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PrSidebarCreateEmptyState.tsx",
- "kind": "jsx-text",
- "text": "Create PR",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PrSidebarCreateEmptyState.tsx",
- "kind": "jsx-text",
- "text": "Link an existing PR",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PrSidebarCreateEmptyState.tsx",
- "kind": "jsx-text",
- "text": "Pull request",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRSidebarHeader.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Cancel editing title",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRSidebarHeader.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Edit pull request title",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRSidebarHeader.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "in browser",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRSidebarHeader.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "on the web",
- "dynamic": true,
- "count": 2
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRSidebarHeader.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Open pull request #",
- "dynamic": true,
- "count": 3
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRSidebarHeader.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Save title",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRSidebarHeader.tsx",
- "kind": "jsx-text",
- "text": "Cancel",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/PRSidebarHeader.tsx",
- "kind": "jsx-text",
- "text": "Save",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/ReviewerPickerDrawer.tsx",
- "kind": "jsx-attribute:placeholder",
- "text": "Search people",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/ReviewerPickerDrawer.tsx",
- "kind": "jsx-text",
- "text": "No matching people",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/ReviewerPickerDrawer.tsx",
- "kind": "jsx-text",
- "text": "Reviewers",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/pr-sidebar/ReviewerPickerDrawer.tsx",
- "kind": "object-property:message",
- "text": "Failed to load people",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/ProtocolBlockScreen.tsx",
- "kind": "jsx-text",
- "text": "Back to hosts",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/ProtocolBlockScreen.tsx",
- "kind": "object-property:label",
- "text": "Get Orca",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/ProtocolBlockScreen.tsx",
- "kind": "object-property:label",
- "text": "Open App Store",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/ProtocolBlockScreen.tsx",
- "kind": "object-property:label",
- "text": "Open GitHub Releases",
- "dynamic": false,
- "count": 2
- },
- {
- "filePath": "mobile/src/components/SetupHookTrustDrawer.tsx",
- "kind": "jsx-expression",
- "text": "'s setup script changed",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SetupHookTrustDrawer.tsx",
- "kind": "jsx-expression",
- "text": "New setup script",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SetupHookTrustDrawer.tsx",
- "kind": "jsx-expression",
- "text": "Run setup from",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SetupHookTrustDrawer.tsx",
- "kind": "jsx-expression",
- "text": "Setup script",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SetupHookTrustDrawer.tsx",
- "kind": "jsx-text",
- "text": "Always trust and run",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SetupHookTrustDrawer.tsx",
- "kind": "jsx-text",
- "text": "Don't run",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SetupHookTrustDrawer.tsx",
- "kind": "jsx-text",
- "text": "Run hooks",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SetupHookTrustDrawer.tsx",
- "kind": "jsx-text",
- "text": "This repository's orca.yaml runs before the workspace starts. Only run it if you trust this repository.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceAdvancedFields.tsx",
- "kind": "jsx-attribute:placeholder",
- "text": "Derived from name",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceAdvancedFields.tsx",
- "kind": "jsx-attribute:placeholder",
- "text": "Workspace name",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceAdvancedFields.tsx",
- "kind": "jsx-text",
- "text": "Branch name",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceAdvancedFields.tsx",
- "kind": "jsx-text",
- "text": "Name",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceAdvancedFields.tsx",
- "kind": "jsx-text",
- "text": "Reuse branch “",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceDrawer.tsx",
- "kind": "jsx-attribute:placeholder",
- "text": "Type a name or search a source",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceDrawer.tsx",
- "kind": "jsx-expression",
- "text": "No results found.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceDrawer.tsx",
- "kind": "jsx-text",
- "text": "Cancel",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceDrawer.tsx",
- "kind": "jsx-text",
- "text": "Connect the repository to search sources.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceDrawer.tsx",
- "kind": "jsx-text",
- "text": "Done",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceDrawer.tsx",
- "kind": "jsx-text",
- "text": "Name or 'Create From'",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceDrawer.tsx",
- "kind": "jsx-text",
- "text": "Switch to",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceDrawer.tsx",
- "kind": "jsx-text",
- "text": "This item lives in",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceDrawer.tsx",
- "kind": "jsx-text",
- "text": "This SSH repo needs a GitHub remote to list issues and PRs.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceDrawer.tsx",
- "kind": "jsx-text",
- "text": "Type a workspace name in the field below.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceField.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Open selected source",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceField.tsx",
- "kind": "jsx-attribute:placeholder",
- "text": "Type a name or search a source",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceField.tsx",
- "kind": "jsx-text",
- "text": "[Optional]",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceRow.tsx",
- "kind": "object-property:subtitle",
- "text": "Name this workspace",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceRow.tsx",
- "kind": "object-property:subtitle",
- "text": "New branch",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceRow.tsx",
- "kind": "object-property:title",
- "text": "Create branch \"",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/SmartWorkspaceSourceRow.tsx",
- "kind": "object-property:title",
- "text": "Use \"",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/TerminalShortcutSettings.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Remove",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/TerminalShortcutSettings.tsx",
- "kind": "jsx-text",
- "text": "Add Custom Shortcut…",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/TerminalShortcutSettings.tsx",
- "kind": "jsx-text",
- "text": "Create key combo or text macro",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/TerminalShortcutSettings.tsx",
- "kind": "jsx-text",
- "text": "CUSTOM SHORTCUTS",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/TerminalShortcutSettings.tsx",
- "kind": "jsx-text",
- "text": "No custom shortcuts defined yet.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/TerminalShortcutSettings.tsx",
- "kind": "jsx-text",
- "text": "Reset Defaults",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/TerminalShortcutSettings.tsx",
- "kind": "jsx-text",
- "text": "SHORTCUT BAR",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/TerminalShortcutSettings.tsx",
- "kind": "jsx-text",
- "text": "Show every built-in shortcut key in the original order",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/TerminalShortcutSettings.tsx",
- "kind": "jsx-text",
- "text": "Toggle keys to show or hide them, and hold the grip to drag a key into the order you want on the terminal shortcut bar.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/TextInputModal.tsx",
- "kind": "jsx-text",
- "text": "Cancel",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/use-codex-reset-credit-action.ts",
- "kind": "object-property:message",
- "text": "and immediately resets eligible rate-limit windows.",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/use-codex-reset-credit-action.ts",
- "kind": "object-property:message",
- "text": "The account or reset offer changed before the host contacted Codex. Review the updated details, then confirm again.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/use-codex-reset-credit-action.ts",
- "kind": "object-property:message",
- "text": "This spends one earned reset for",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/use-codex-reset-credit-action.ts",
- "kind": "object-property:title",
- "text": "Could not reset rate limits",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/use-codex-reset-credit-action.ts",
- "kind": "object-property:title",
- "text": "Reset details changed",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/use-codex-reset-credit-action.ts",
- "kind": "object-property:title",
- "text": "Use a rate-limit reset?",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/VoiceModelList.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Delete",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/VoiceModelList.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Download",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/VoiceModelList.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Use",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/VoiceModelList.tsx",
- "kind": "jsx-text",
- "text": "In use",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/VoiceModelList.tsx",
- "kind": "jsx-text",
- "text": "Recommended",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/VoiceModelList.tsx",
- "kind": "jsx-text",
- "text": "Use",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/WorkspaceDetailPlaceholder.tsx",
- "kind": "jsx-text",
- "text": "No workspace open",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/WorkspaceDetailPlaceholder.tsx",
- "kind": "jsx-text",
- "text": "Pick a workspace from the sidebar to open its terminal here.",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/WorktreeListRow.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Project",
- "dynamic": true,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/WorktreeListRow.tsx",
- "kind": "jsx-attribute:accessibilityLabel",
- "text": "Remote host",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/WorktreeListRow.tsx",
- "kind": "jsx-expression",
- "text": "child",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/WorktreeListRow.tsx",
- "kind": "jsx-expression",
- "text": "children",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/WorktreeListRow.tsx",
- "kind": "jsx-text",
- "text": "Child",
- "dynamic": false,
- "count": 1
- },
- {
- "filePath": "mobile/src/components/WorktreeListRow.tsx",
- "kind": "jsx-text",
- "text": "Folder",
- "dynamic": false,
- "count": 1
- },
{
"filePath": "mobile/src/diagnostics/connection-diagnostics-submission.ts",
"kind": "object-property:error",
diff --git a/mobile/src/accounts/MobileAccountsScreen.tsx b/mobile/src/accounts/MobileAccountsScreen.tsx
index 1181a6f5794..91bcfc0e16c 100644
--- a/mobile/src/accounts/MobileAccountsScreen.tsx
+++ b/mobile/src/accounts/MobileAccountsScreen.tsx
@@ -11,10 +11,10 @@ import { useMobileTranslation } from '../i18n/use-mobile-translation'
import { styles } from './mobile-accounts-screen-styles'
import { useNow } from '../hooks/use-now'
import { ClaudeIcon, OpenAIIcon } from '../components/AgentIcons'
+import { AccountsSnapshotError, decodeAccountsSnapshot } from '../components/accounts-snapshot'
import {
type AccountsSnapshot,
type ProviderKey,
- decodeAccountsSnapshot,
getActiveProviderRateLimits,
getInactiveProviderUsage,
getUsageBarState,
@@ -142,7 +142,7 @@ export function MobileAccountsScreen() {
setError(res.error.message)
}
} catch (e) {
- if (e instanceof Error && e.message === 'Invalid accounts snapshot from host') {
+ if (e instanceof AccountsSnapshotError) {
rejectInvalidSnapshot()
} else {
setError(e instanceof Error ? e.message : String(e))
diff --git a/mobile/src/components/AgentLaunchNotice.tsx b/mobile/src/components/AgentLaunchNotice.tsx
index 6ddeed79074..804fd5cbb49 100644
--- a/mobile/src/components/AgentLaunchNotice.tsx
+++ b/mobile/src/components/AgentLaunchNotice.tsx
@@ -1,10 +1,7 @@
import { useState } from 'react'
import { Pressable, Text, View, type StyleProp, type TextStyle } from 'react-native'
import { useClipboardWriter } from '../platform/clipboard'
-import {
- AGENT_LAUNCH_STATUS_UNREADABLE_MESSAGE,
- AGENT_LAUNCH_UPDATE_REQUIRED_MESSAGE
-} from '../session/mobile-existing-agent-launch'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import type { MobileAgentLaunchAvailability } from '../session/mobile-agent-launch-availability'
import { colors, spacing, typography } from '../theme/mobile-theme'
import { themedStyleSheet } from '../theme/themed-styles'
@@ -31,14 +28,24 @@ export function AgentLaunchNotice({
undeliveredPrompt,
errorStyle
}: Props) {
+ const t = useMobileTranslation()
useMobileColorScheme()
const clipboard = useClipboardWriter()
- const [copyState, setCopyState] = useState<{ prompt: string; label: string } | null>(null)
+ const [copyState, setCopyState] = useState<{
+ prompt: string
+ status: 'copied' | 'failed'
+ } | null>(null)
const availabilityMessage =
availability === 'update-required'
- ? AGENT_LAUNCH_UPDATE_REQUIRED_MESSAGE
+ ? t(
+ 'components.agentLaunchNotice.updateRequired',
+ 'Update Orca on your computer to start an agent from your phone.'
+ )
: availability === 'unverified'
- ? AGENT_LAUNCH_STATUS_UNREADABLE_MESSAGE
+ ? t(
+ 'components.agentLaunchNotice.statusUnreadable',
+ "Could not read this host's status. Retrying…"
+ )
: null
const message = availabilityMessage ?? error
const note = availabilityMessage ? null : warning
@@ -47,7 +54,11 @@ export function AgentLaunchNotice({
return null
}
const copyLabel =
- copyState && copyState.prompt === undeliveredPrompt ? copyState.label : 'Copy prompt'
+ copyState && copyState.prompt === undeliveredPrompt
+ ? copyState.status === 'copied'
+ ? t('common.copied', 'Copied')
+ : t('components.agentLaunchNotice.copyFailed', "Couldn't copy")
+ : t('components.agentLaunchNotice.copyPrompt', 'Copy prompt')
return (
{confirmation ? {confirmation} : null}
@@ -57,12 +68,12 @@ export function AgentLaunchNotice({
{
clipboard.writeText(undeliveredPrompt).then(
- () => setCopyState({ prompt: undeliveredPrompt, label: 'Copied' }),
- () => setCopyState({ prompt: undeliveredPrompt, label: "Couldn't copy" })
+ () => setCopyState({ prompt: undeliveredPrompt, status: 'copied' }),
+ () => setCopyState({ prompt: undeliveredPrompt, status: 'failed' })
)
}}
accessibilityRole="button"
- accessibilityLabel="Copy prompt"
+ accessibilityLabel={t('components.agentLaunchNotice.copyPrompt', 'Copy prompt')}
hitSlop={spacing.sm}
>
{copyLabel}
diff --git a/mobile/src/components/AgentSpinner.tsx b/mobile/src/components/AgentSpinner.tsx
index 23c0370c2e4..84788b6bbce 100644
--- a/mobile/src/components/AgentSpinner.tsx
+++ b/mobile/src/components/AgentSpinner.tsx
@@ -2,6 +2,7 @@ import { Activity } from 'lucide-react-native'
import { Animated, View } from 'react-native'
import type { AgentWorkingMode } from '../../../src/shared/agent-status-types'
import type { WorktreeStatus } from '../../../src/shared/worktree-status-rollup'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import { colors } from '../theme/mobile-theme'
import { themedStyleSheet } from '../theme/themed-styles'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
@@ -27,6 +28,7 @@ export function AgentSpinner({
status: WorktreeStatus
workingMode?: AgentWorkingMode
}) {
+ const t = useMobileTranslation()
useMobileColorScheme()
const monitoring =
status === 'monitoring' || (status === 'working' && workingMode === 'monitoring')
@@ -37,7 +39,10 @@ export function AgentSpinner({
if (monitoring) {
return (
-
+
)
@@ -45,7 +50,10 @@ export function AgentSpinner({
if (status === 'unconfirmed') {
return (
-
+
)
diff --git a/mobile/src/components/AgentStateDot.tsx b/mobile/src/components/AgentStateDot.tsx
index 28cac5f1a99..c1490ef0d7b 100644
--- a/mobile/src/components/AgentStateDot.tsx
+++ b/mobile/src/components/AgentStateDot.tsx
@@ -1,6 +1,7 @@
import { Activity } from 'lucide-react-native'
import { Animated, View } from 'react-native'
import type { AgentDotState } from '../worktree/agent-row-display'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import { colors } from '../theme/mobile-theme'
import { themedStyleSheet } from '../theme/themed-styles'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
@@ -25,6 +26,7 @@ export const AGENT_WORKING_COLOR = '#eab308'
/** `unverifiable` is a child row's lost contact: desktop's dashed amber ring, a missing-evidence
* mark rather than a state claim. */
export function AgentStateDot({ state }: { state: AgentDotState | 'unverifiable' }) {
+ const t = useMobileTranslation()
useMobileColorScheme()
const rotate = useWorkingRingRotation(state === 'working')
@@ -38,7 +40,10 @@ export function AgentStateDot({ state }: { state: AgentDotState | 'unverifiable'
if (state === 'monitoring') {
return (
-
+
)
@@ -46,7 +51,10 @@ export function AgentStateDot({ state }: { state: AgentDotState | 'unverifiable'
if (state === 'unverifiable') {
return (
-
+
)
diff --git a/mobile/src/components/AuthFailedBanner.tsx b/mobile/src/components/AuthFailedBanner.tsx
index b1552013834..9005b8d6ecb 100644
--- a/mobile/src/components/AuthFailedBanner.tsx
+++ b/mobile/src/components/AuthFailedBanner.tsx
@@ -1,4 +1,5 @@
import { View, Text } from 'react-native'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import { AuthFailedBannerActions } from './AuthFailedBannerActions'
import { authFailedBannerStyles as styles } from './auth-failed-banner-styles'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
@@ -15,11 +16,15 @@ export function AuthFailedBanner({
onRepair: () => void
onRemove: () => void
}) {
+ const t = useMobileTranslation()
useMobileColorScheme()
return (
- Authentication failed — try reconnecting first; if it keeps failing, re-pair from desktop.
+ {t(
+ 'components.authFailedBanner.message',
+ 'Authentication failed — try reconnecting first; if it keeps failing, re-pair from desktop.'
+ )}
void
onRemove: () => void
}) {
+ const t = useMobileTranslation()
useMobileColorScheme()
return (
<>
{canRetry && (
- Retry
+ {t('common.retry', 'Retry')}
)}
- Re-pair
+
+ {t('components.authFailedBannerActions.repair', 'Re-pair')}
+
- Remove
+
+ {t('common.remove', 'Remove')}
+
>
)
diff --git a/mobile/src/components/AuthFailedBannerActions.web.tsx b/mobile/src/components/AuthFailedBannerActions.web.tsx
index 0c04cd69f25..312ea488852 100644
--- a/mobile/src/components/AuthFailedBannerActions.web.tsx
+++ b/mobile/src/components/AuthFailedBannerActions.web.tsx
@@ -1,4 +1,5 @@
import { Pressable, Text } from 'react-native'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import { authFailedBannerStyles as styles } from './auth-failed-banner-styles'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
@@ -11,13 +12,21 @@ export function AuthFailedBannerActions({
onRepair: () => void
onRemove: () => void
}) {
+ const t = useMobileTranslation()
useMobileColorScheme()
return (
<>
- Re-pair
+
+ {t('components.authFailedBannerActions.repair', 'Re-pair')}
+
- Reconnect or remove this host from the Orca app.
+
+ {t(
+ 'components.authFailedBannerActions.webNote',
+ 'Reconnect or remove this host from the Orca app.'
+ )}
+
>
)
}
diff --git a/mobile/src/components/CodexResetCreditAction.tsx b/mobile/src/components/CodexResetCreditAction.tsx
index 436ba12708d..87e964dea7e 100644
--- a/mobile/src/components/CodexResetCreditAction.tsx
+++ b/mobile/src/components/CodexResetCreditAction.tsx
@@ -1,5 +1,6 @@
import { ActivityIndicator, Pressable, StyleSheet, Text, View } from 'react-native'
import { RotateCcw } from 'lucide-react-native'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import { colors, radii, spacing, typography } from '../theme/mobile-theme'
import { themedStyleSheet } from '../theme/themed-styles'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
@@ -18,6 +19,7 @@ export function CodexResetCreditAction({
disabled: boolean
onPress: () => void
}) {
+ const t = useMobileTranslation()
useMobileColorScheme()
return (
<>
@@ -27,7 +29,7 @@ export function CodexResetCreditAction({
{summary.availabilityLabel}
{[summary.expiryLabel, scopeLabel].filter(Boolean).join(' · ') ||
- 'Earned Codex rate-limit reset'}
+ t('components.codexResetCreditAction.earnedReset', 'Earned Codex rate-limit reset')}
)}
- {busy ? 'Resetting…' : 'Use reset'}
+
+ {busy
+ ? t('components.codexResetCreditAction.resetting', 'Resetting…')
+ : t('components.codexResetCreditAction.useReset', 'Use reset')}
+
>
diff --git a/mobile/src/components/ConfirmModal.tsx b/mobile/src/components/ConfirmModal.tsx
index 7254d0f3759..d0baee3ff4d 100644
--- a/mobile/src/components/ConfirmModal.tsx
+++ b/mobile/src/components/ConfirmModal.tsx
@@ -1,4 +1,5 @@
import { View, Text, Pressable } from 'react-native'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import { colors, spacing, radii, typography } from '../theme/mobile-theme'
import { themedStyleSheet } from '../theme/themed-styles'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
@@ -29,12 +30,13 @@ export function ConfirmModal({ visible, ...content }: Props) {
export function ConfirmContent({
title,
message,
- confirmLabel = 'Confirm',
- cancelLabel = 'Cancel',
+ confirmLabel,
+ cancelLabel,
destructive = false,
onConfirm,
onCancel
}: ContentProps) {
+ const t = useMobileTranslation()
useMobileColorScheme()
return (
<>
@@ -48,7 +50,7 @@ export function ConfirmContent({
style={({ pressed }) => [styles.button, styles.cancelButton, pressed && styles.pressed]}
onPress={onCancel}
>
- {cancelLabel}
+ {cancelLabel ?? t('common.cancel', 'Cancel')}
)}
- {confirmLabel}
+ {confirmLabel ?? t('common.confirm', 'Confirm')}
diff --git a/mobile/src/components/CustomKeyModal.tsx b/mobile/src/components/CustomKeyModal.tsx
index f647b7acd76..fce1ab1a646 100644
--- a/mobile/src/components/CustomKeyModal.tsx
+++ b/mobile/src/components/CustomKeyModal.tsx
@@ -13,6 +13,8 @@ import {
} from '../terminal/terminal-accessory-keys'
import { customKeyModalStyles as styles } from './CustomKeyModal.styles'
import { updateStoredCustomKeys, type CustomKey } from '../terminal/terminal-custom-keys'
+import type { Translate } from '../i18n/mobile-i18n'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
type Step = 'choose-type' | 'shortcut-combo' | 'special-keys' | 'text-macro'
@@ -24,23 +26,28 @@ const SHORTCUT_MODIFIERS: { id: TerminalShortcutModifier; label: string; glyph?:
]
// Group keys into three fixed grids; ragged wrapping clipped F7–F12.
-const SPECIAL_KEY_GROUPS: { title: string; ids: string[]; columns: number }[] = [
- {
- title: 'Editing',
- ids: ['escape', 'tab', 'enter', 'backspace', 'delete', 'insert', 'space'],
- columns: 4
- },
- {
- title: 'Navigation',
- ids: ['arrowUp', 'arrowDown', 'arrowLeft', 'arrowRight', 'home', 'end', 'pageUp', 'pageDown'],
- columns: 4
- },
- {
- title: 'Function',
- ids: ['f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'f11', 'f12'],
- columns: 6
- }
-]
+function specialKeyGroups(t: Translate) {
+ return [
+ {
+ id: 'editing',
+ title: t('components.customKeyModal.editing', 'Editing'),
+ ids: ['escape', 'tab', 'enter', 'backspace', 'delete', 'insert', 'space'],
+ columns: 4
+ },
+ {
+ id: 'navigation',
+ title: t('components.customKeyModal.navigation', 'Navigation'),
+ ids: ['arrowUp', 'arrowDown', 'arrowLeft', 'arrowRight', 'home', 'end', 'pageUp', 'pageDown'],
+ columns: 4
+ },
+ {
+ id: 'function',
+ title: t('components.customKeyModal.function', 'Function'),
+ ids: ['f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'f11', 'f12'],
+ columns: 6
+ }
+ ]
+}
const SPECIAL_KEY_BY_ID: Record = Object.fromEntries(
TERMINAL_SHORTCUT_SPECIAL_KEYS.map((key) => [key.id, key])
@@ -55,6 +62,7 @@ type Props = {
export function CustomKeyModal({ visible, onClose, onKeysChanged, onManageShortcuts }: Props) {
useMobileColorScheme()
+ const t = useMobileTranslation()
const [step, setStep] = useState('choose-type')
const [shortcutKey, setShortcutKey] = useState('c')
const [shortcutModifiers, setShortcutModifiers] = useState(['ctrl'])
@@ -173,7 +181,7 @@ export function CustomKeyModal({ visible, onClose, onKeysChanged, onManageShortc
style={({ pressed }) => [styles.backButton, pressed && styles.backButtonPressed]}
onPress={onBack}
accessibilityRole="button"
- accessibilityLabel="Back"
+ accessibilityLabel={t('common.back', 'Back')}
>
@@ -181,10 +189,11 @@ export function CustomKeyModal({ visible, onClose, onKeysChanged, onManageShortc
)}
- {step === 'choose-type' && 'Add Shortcut'}
- {step === 'shortcut-combo' && 'Shortcut Combo'}
- {step === 'special-keys' && 'Pick a key'}
- {step === 'text-macro' && 'Text Macro'}
+ {step === 'choose-type' && t('components.customKeyModal.addShortcut', 'Add Shortcut')}
+ {step === 'shortcut-combo' &&
+ t('components.customKeyModal.shortcutCombo', 'Shortcut Combo')}
+ {step === 'special-keys' && t('components.customKeyModal.pickKey', 'Pick a key')}
+ {step === 'text-macro' && t('components.customKeyModal.textMacro', 'Text Macro')}
@@ -195,16 +204,27 @@ export function CustomKeyModal({ visible, onClose, onKeysChanged, onManageShortc
style={({ pressed }) => [styles.row, pressed && styles.rowPressed]}
onPress={() => setStep('shortcut-combo')}
>
- Shortcut Combo
- Build Ctrl, Alt, and Shift key chords
+
+ {t('components.customKeyModal.shortcutCombo', 'Shortcut Combo')}
+
+
+ {t(
+ 'components.customKeyModal.shortcutComboHint',
+ 'Build Ctrl, Alt, and Shift key chords'
+ )}
+
[styles.row, pressed && styles.rowPressed]}
onPress={() => setStep('text-macro')}
>
- Text Macro
- Send custom text command
+
+ {t('components.customKeyModal.textMacro', 'Text Macro')}
+
+
+ {t('components.customKeyModal.textMacroHint', 'Send custom text command')}
+
{onManageShortcuts ? (
<>
@@ -213,8 +233,15 @@ export function CustomKeyModal({ visible, onClose, onKeysChanged, onManageShortc
style={({ pressed }) => [styles.row, pressed && styles.rowPressed]}
onPress={onManageShortcuts}
>
- Manage Shortcuts
- Show, hide, or reorder shortcut keys
+
+ {t('components.customKeyModal.manageShortcuts', 'Manage Shortcuts')}
+
+
+ {t(
+ 'components.customKeyModal.manageShortcutsHint',
+ 'Show, hide, or reorder shortcut keys'
+ )}
+
>
) : null}
@@ -241,7 +268,9 @@ export function CustomKeyModal({ visible, onClose, onKeysChanged, onManageShortc
- Modifiers
+
+ {t('components.customKeyModal.modifiers', 'Modifiers')}
+
{SHORTCUT_MODIFIERS.map((modifier) => {
const selected = shortcutModifiers.includes(modifier.id)
@@ -272,7 +301,7 @@ export function CustomKeyModal({ visible, onClose, onKeysChanged, onManageShortc
- Key
+ {t('components.customKeyModal.key', 'Key')}
[styles.moreLink, pressed && styles.moreLinkPressed]}
onPress={() => setStep('special-keys')}
>
- More keys — Tab, arrows, F1–F12…
+
+ {t('components.customKeyModal.moreKeys', 'More keys — Tab, arrows, F1–F12…')}
+
@@ -299,7 +330,7 @@ export function CustomKeyModal({ visible, onClose, onKeysChanged, onManageShortc
- Add
+ {t('components.customKeyModal.add', 'Add')}
@@ -307,8 +338,8 @@ export function CustomKeyModal({ visible, onClose, onKeysChanged, onManageShortc
{step === 'special-keys' && (
- {SPECIAL_KEY_GROUPS.map((group) => (
-
+ {specialKeyGroups(t).map((group) => (
+
{group.title}
{group.ids.map((id) => {
@@ -346,28 +377,32 @@ export function CustomKeyModal({ visible, onClose, onKeysChanged, onManageShortc
{step === 'text-macro' && (
- Label
+ {t('components.customKeyModal.label', 'Label')}
- Command
+
+ {t('components.customKeyModal.command', 'Command')}
+
- Press Enter
+
+ {t('components.customKeyModal.pressEnter', 'Press Enter')}
+
- Add Shortcut
+ {t('components.customKeyModal.addShortcut', 'Add Shortcut')}
diff --git a/mobile/src/components/DragReorderRow.tsx b/mobile/src/components/DragReorderRow.tsx
index 2619b8d807b..53c313dcf74 100644
--- a/mobile/src/components/DragReorderRow.tsx
+++ b/mobile/src/components/DragReorderRow.tsx
@@ -14,6 +14,7 @@ import Animated, {
import { colors, spacing } from '../theme/mobile-theme'
import { themedStyleSheet } from '../theme/themed-styles'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import { triggerMediumImpact } from '../platform/haptics'
import {
type DragReorderLayout,
@@ -69,6 +70,7 @@ export function DragReorderRow({
renderContent: (handle: ReactNode) => ReactNode
}): React.JSX.Element {
useMobileColorScheme()
+ const t = useMobileTranslation()
const {
layout,
initialPositions,
@@ -183,11 +185,14 @@ export function DragReorderRow({
accessible
accessibilityRole="button"
accessibilityState={{ disabled }}
- accessibilityLabel="Drag to reorder"
- accessibilityHint="Use the move up and move down actions to reorder without dragging"
+ accessibilityLabel={t('components.dragReorderRow.dragToReorder', 'Drag to reorder')}
+ accessibilityHint={t(
+ 'components.dragReorderRow.reorderHint',
+ 'Use the move up and move down actions to reorder without dragging'
+ )}
accessibilityActions={[
- { name: 'moveUp', label: 'Move up' },
- { name: 'moveDown', label: 'Move down' }
+ { name: 'moveUp', label: t('components.dragReorderRow.moveUp', 'Move up') },
+ { name: 'moveDown', label: t('components.dragReorderRow.moveDown', 'Move down') }
]}
onAccessibilityAction={(event) => {
if (disabled) {
diff --git a/mobile/src/components/HostDiagnosticsLink.tsx b/mobile/src/components/HostDiagnosticsLink.tsx
index 6e90fca2633..ef1ec17625c 100644
--- a/mobile/src/components/HostDiagnosticsLink.tsx
+++ b/mobile/src/components/HostDiagnosticsLink.tsx
@@ -3,17 +3,24 @@ import { Pressable, Text } from 'react-native'
import { colors, radii, spacing, typography } from '../theme/mobile-theme'
import { themedStyleSheet } from '../theme/themed-styles'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
export function HostDiagnosticsLink({ onPress }: { onPress: () => void }): React.JSX.Element {
useMobileColorScheme()
+ const t = useMobileTranslation()
return (
- View network diagnostics
+
+ {t('components.hostDiagnosticsLink.viewDiagnostics', 'View network diagnostics')}
+
)
diff --git a/mobile/src/components/HostProtocolGate.tsx b/mobile/src/components/HostProtocolGate.tsx
index 54ac9fe99d4..4dc5ae0ca28 100644
--- a/mobile/src/components/HostProtocolGate.tsx
+++ b/mobile/src/components/HostProtocolGate.tsx
@@ -5,6 +5,7 @@ import { useHostStatusGates } from '../transport/host-status-gates'
import { colors } from '../theme/mobile-theme'
import { themedStyleSheet } from '../theme/themed-styles'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import { HostStatusGatesContext } from './host-protocol-gates-context'
import { ProtocolBlockScreen } from './ProtocolBlockScreen'
@@ -25,6 +26,7 @@ export function HostProtocolGate({
blocked: blockedView
}: Props) {
useMobileColorScheme()
+ const t = useMobileTranslation()
const { client, state } = useHostClient(hostId)
const gates = useHostStatusGates({ hostId, client, connState: state })
const { compatVerdict, statusPending } = gates
@@ -59,7 +61,10 @@ export function HostProtocolGate({
)
@@ -89,7 +94,10 @@ export function HostProtocolGate({
>
) : null}
diff --git a/mobile/src/components/HostRouteNoticeBanner.tsx b/mobile/src/components/HostRouteNoticeBanner.tsx
index 25817fe5f1b..aa2837d0b81 100644
--- a/mobile/src/components/HostRouteNoticeBanner.tsx
+++ b/mobile/src/components/HostRouteNoticeBanner.tsx
@@ -3,6 +3,7 @@ import { X } from 'lucide-react-native'
import { colors, spacing } from '../theme/mobile-theme'
import { themedStyleSheet } from '../theme/themed-styles'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
// Monochrome notice reports vanished target; failure uses one red rule for action refusal without taking screen.
// Announce inserted banners: failure uses alert/assertive, notice uses polite live region (RN has no status role).
@@ -16,6 +17,7 @@ export function HostRouteNoticeBanner({
onDismiss: () => void
}) {
useMobileColorScheme()
+ const t = useMobileTranslation()
return (
diff --git a/mobile/src/components/JiraConnectPrompt.tsx b/mobile/src/components/JiraConnectPrompt.tsx
index 170e4318bcb..d28dbda4ac8 100644
--- a/mobile/src/components/JiraConnectPrompt.tsx
+++ b/mobile/src/components/JiraConnectPrompt.tsx
@@ -2,6 +2,7 @@ import { Pressable, Text, View } from 'react-native'
import { colors, radii, spacing, typography } from '../theme/mobile-theme'
import { themedStyleSheet } from '../theme/themed-styles'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import { TaskProviderLogo } from './TaskProviderLogo'
type Props = {
@@ -19,17 +20,27 @@ export function JiraConnectPrompt({
onCheckAgain
}: Props) {
useMobileColorScheme()
+ const t = useMobileTranslation()
return (
- {unavailableReason ? 'Update Orca desktop' : 'Connect Jira on your desktop'}
+ {unavailableReason
+ ? t('components.jiraConnectPrompt.updateDesktop', 'Update Orca desktop')
+ : t('components.jiraConnectPrompt.connectOnDesktop', 'Connect Jira on your desktop')}
{unavailableReason ??
(credentialError
- ? `Jira is saved but unreadable: ${credentialError}`
- : 'Add your Jira site in Orca desktop under Settings → Integrations, then check again.')}
+ ? t(
+ 'components.jiraConnectPrompt.credentialUnreadable',
+ 'Jira is saved but unreadable: {{credentialError}}',
+ { credentialError }
+ )
+ : t(
+ 'components.jiraConnectPrompt.connectHint',
+ 'Add your Jira site in Orca desktop under Settings → Integrations, then check again.'
+ ))}
- Check again
+
+ {t('components.jiraConnectPrompt.checkAgain', 'Check again')}
+
)
diff --git a/mobile/src/components/MobileDictationSetupSheet.tsx b/mobile/src/components/MobileDictationSetupSheet.tsx
index 3afa817c5f2..f9762fba214 100644
--- a/mobile/src/components/MobileDictationSetupSheet.tsx
+++ b/mobile/src/components/MobileDictationSetupSheet.tsx
@@ -6,6 +6,9 @@ import { MobileSwitch } from './MobileSwitch'
import { colors, radii, spacing, typography } from '../theme/mobile-theme'
import { themedStyleSheet } from '../theme/themed-styles'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
+import type { Translate } from '../i18n/mobile-i18n'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
+import { getUiIntlLocale } from '../i18n/ui-intl-locale'
import type { RpcClient } from '../transport/rpc-client'
import { triggerError, triggerSuccess } from '../platform/haptics'
import { useDictationSetupPoller } from '../dictation/use-dictation-setup-poller'
@@ -30,18 +33,52 @@ type Props = {
onReady?: () => void
}
-function formatSize(bytes: number | null | undefined): string {
+type SetupError = { message: string } | { kind: 'load' | 'download' | 'select' | 'update' }
+
+function setupErrorMessage(error: SetupError, t: Translate): string {
+ if ('message' in error) {
+ return error.message
+ }
+ switch (error.kind) {
+ case 'load':
+ return t('components.dictationSetupSheet.loadFailed', 'Failed to load')
+ case 'download':
+ return t('components.dictationSetupSheet.downloadFailed', 'Download failed')
+ case 'select':
+ return t('components.dictationSetupSheet.selectFailed', 'Could not select model')
+ case 'update':
+ return t('components.dictationSetupSheet.updateFailed', 'Could not update')
+ }
+}
+
+function formatSize(bytes: number | null | undefined, t: Translate): string {
if (!bytes) {
return ''
}
- return `${Math.round(bytes / 1_000_000)} MB`
+ return t('components.dictationSetupSheet.modelSize', '{{size}} MB', {
+ size: Math.round(bytes / 1_000_000).toLocaleString(getUiIntlLocale())
+ })
+}
+
+function modelMetadata(model: MobileSpeechModel, t: Translate): string {
+ const details = model.provider === 'openai' ? 'OpenAI API' : formatSize(model.sizeBytes, t)
+ if (isModelInFlight(model) && model.progress != null) {
+ return t('components.dictationSetupSheet.modelProgress', '{{details}} · {{progress}}%', {
+ details,
+ progress: Math.round(model.progress * 100).toLocaleString(getUiIntlLocale())
+ })
+ }
+ return model.status === 'extracting'
+ ? t('components.dictationSetupSheet.modelExtracting', '{{details}} · extracting…', { details })
+ : details
}
// Configure paired computer’s dictation/model from phone; poll while download is in flight.
export function MobileDictationSetupSheet({ visible, client, onClose, onReady }: Props) {
useMobileColorScheme()
+ const t = useMobileTranslation()
const [setup, setSetup] = useState(null)
- const [error, setError] = useState(null)
+ const [error, setError] = useState(null)
const [busy, setBusy] = useState(null)
const refresh = useCallback(async (): Promise => {
if (!client) {
@@ -53,7 +90,7 @@ export function MobileDictationSetupSheet({ visible, client, onClose, onReady }:
setError(null)
return next.models.some(isModelInFlight)
} catch (err) {
- setError(err instanceof Error ? err.message : 'Failed to load')
+ setError(err instanceof Error ? { message: err.message } : { kind: 'load' })
return undefined
}
}, [client])
@@ -84,7 +121,7 @@ export function MobileDictationSetupSheet({ visible, client, onClose, onReady }:
await refreshSetup()
} catch (err) {
triggerError()
- setError(err instanceof Error ? err.message : 'Download failed')
+ setError(err instanceof Error ? { message: err.message } : { kind: 'download' })
} finally {
setBusy(null)
}
@@ -106,7 +143,7 @@ export function MobileDictationSetupSheet({ visible, client, onClose, onReady }:
onReady?.()
} catch (err) {
triggerError()
- setError(err instanceof Error ? err.message : 'Could not select model')
+ setError(err instanceof Error ? { message: err.message } : { kind: 'select' })
} finally {
setBusy(null)
}
@@ -123,7 +160,7 @@ export function MobileDictationSetupSheet({ visible, client, onClose, onReady }:
try {
setSetup(await setDictationConfig(client, { enabled }))
} catch (err) {
- setError(err instanceof Error ? err.message : 'Could not update')
+ setError(err instanceof Error ? { message: err.message } : { kind: 'update' })
}
},
[client]
@@ -133,9 +170,14 @@ export function MobileDictationSetupSheet({ visible, client, onClose, onReady }:
{/* BottomDrawer already scrolls above keyboard; nested capped ScrollView clipped lower controls. */}
- Set up voice dictation
+
+ {t('components.dictationSetupSheet.title', 'Set up voice dictation')}
+
- Download or pick a model and enable dictation on the paired computer — all from here.
+ {t(
+ 'components.dictationSetupSheet.description',
+ 'Download or pick a model and enable dictation on the paired computer — all from here.'
+ )}
{setup === null ? (
@@ -145,16 +187,20 @@ export function MobileDictationSetupSheet({ visible, client, onClose, onReady }:
) : (
<>
- Dictation enabled
+
+ {t('components.dictationSetupSheet.enabled', 'Dictation enabled')}
+
void handleToggleEnabled(v)}
/>
{setup.models.map((model) => {
- const inFlight = isModelInFlight(model)
const action = dictationModelRowAction(model, setup.selectedModelId)
const rowBusy = busy === model.id
return (
@@ -163,24 +209,21 @@ export function MobileDictationSetupSheet({ visible, client, onClose, onReady }:
{model.label}
{model.recommended ? (
- Recommended
+
+ {t('components.dictationSetupSheet.recommended', 'Recommended')}
+
) : null}
-
- {model.provider === 'openai' ? 'OpenAI API' : formatSize(model.sizeBytes)}
- {inFlight && model.progress != null
- ? ` · ${Math.round(model.progress * 100)}%`
- : model.status === 'extracting'
- ? ' · extracting…'
- : ''}
-
+ {modelMetadata(model, t)}
{action === 'needs-api-key' ? (
{cloudModelNeedsKey()}
) : action === 'in-use' ? (
- In use
+
+ {t('components.dictationSetupSheet.inUse', 'In use')}
+
) : action === 'use' ? (
void handleUseModel(model)}
>
- Use
+
+ {t('components.dictationSetupSheet.use', 'Use')}
+
) : action === 'downloading' ? (
@@ -206,7 +255,11 @@ export function MobileDictationSetupSheet({ visible, client, onClose, onReady }:
]}
disabled={rowBusy}
accessibilityRole="button"
- accessibilityLabel={`Download ${model.label}`}
+ accessibilityLabel={t(
+ 'components.dictationSetupSheet.downloadModel',
+ 'Download {{model}}',
+ { model: model.label }
+ )}
accessibilityState={{ disabled: rowBusy }}
onPress={() => void handleDownload(model)}
>
@@ -215,7 +268,9 @@ export function MobileDictationSetupSheet({ visible, client, onClose, onReady }:
) : (
<>
- Download
+
+ {t('components.dictationSetupSheet.download', 'Download')}
+
>
)}
@@ -225,7 +280,7 @@ export function MobileDictationSetupSheet({ visible, client, onClose, onReady }:
})}
>
)}
- {error ? {error} : null}
+ {error ? {setupErrorMessage(error, t)} : null}
)
diff --git a/mobile/src/components/MobileDiffReviewBody.tsx b/mobile/src/components/MobileDiffReviewBody.tsx
index 43ccf066799..46bc70dda67 100644
--- a/mobile/src/components/MobileDiffReviewBody.tsx
+++ b/mobile/src/components/MobileDiffReviewBody.tsx
@@ -4,6 +4,7 @@ import type { RefObject } from 'react'
import type { DiffComment } from '../../../src/shared/diff-comment-types'
import { colors } from '../theme/mobile-theme'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import { MobileDiffReviewLine } from './MobileDiffReviewLine'
import type {
ReviewDiffLine,
@@ -41,23 +42,44 @@ export function MobileDiffReviewBody({
onRetry
}: Props) {
useMobileColorScheme()
+ const t = useMobileTranslation()
if (screenState.kind === 'loading') {
- return
+ return (
+
+ )
}
if (screenState.kind === 'error' || screenState.kind === 'unavailable') {
return (
)
}
if (filteredCount === 0) {
- return
+ return (
+
+ )
}
if (diffState.kind === 'loading') {
- return
+ return (
+
+ )
}
if (diffState.kind !== 'ready') {
return
@@ -93,7 +115,9 @@ export function MobileDiffReviewBody({
}}
ListFooterComponent={
diffState.truncated ? (
- Diff truncated for mobile preview.
+
+ {t('components.diffReviewBody.diffTruncated', 'Diff truncated for mobile preview.')}
+
) : null
}
/>
@@ -107,24 +131,34 @@ function DiffUnavailableState({
diffState: ReviewDiffState
onRetry: (() => void) | undefined
}) {
+ const t = useMobileTranslation()
const title =
diffState.kind === 'binary'
- ? 'Binary Diff'
+ ? t('components.diffReviewBody.binaryDiff', 'Binary Diff')
: diffState.kind === 'too-large'
- ? 'Diff Too Large'
+ ? t('components.diffReviewBody.diffTooLarge', 'Diff Too Large')
: diffState.kind === 'deleted'
- ? 'Deleted File'
- : 'Diff Unavailable'
+ ? t('components.diffReviewBody.deletedFile', 'Deleted File')
+ : t('components.diffReviewBody.diffUnavailable', 'Diff Unavailable')
const text =
diffState.kind === 'binary'
- ? 'This file cannot be rendered as text on mobile.'
+ ? t(
+ 'components.diffReviewBody.binaryMessage',
+ 'This file cannot be rendered as text on mobile.'
+ )
: diffState.kind === 'too-large'
- ? 'This diff is too large for the mobile preview.'
+ ? t(
+ 'components.diffReviewBody.tooLargeMessage',
+ 'This diff is too large for the mobile preview.'
+ )
: diffState.kind === 'deleted'
- ? 'This file was deleted. Add a file note or mark it reviewed.'
+ ? t(
+ 'components.diffReviewBody.deletedMessage',
+ 'This file was deleted. Add a file note or mark it reviewed.'
+ )
: diffState.kind === 'error'
? diffState.message
- : 'Select a file to review.'
+ : t('components.diffReviewBody.selectFile', 'Select a file to review.')
return
}
@@ -142,6 +176,7 @@ function CenteredState({
onRetry?: () => void
}) {
useMobileColorScheme()
+ const t = useMobileTranslation()
return (
{busy ? (
@@ -154,10 +189,10 @@ function CenteredState({
style={({ pressed }) => [styles.retryButton, pressed && styles.buttonPressed]}
onPress={onRetry}
accessibilityRole="button"
- accessibilityLabel="Retry loading review"
+ accessibilityLabel={t('components.diffReviewBody.retryLabel', 'Retry loading review')}
>
- Retry
+ {t('common.retry', 'Retry')}
) : null}
diff --git a/mobile/src/components/MobileDiffReviewDrawers.tsx b/mobile/src/components/MobileDiffReviewDrawers.tsx
index 99c2dc8a9e3..8812aa9249f 100644
--- a/mobile/src/components/MobileDiffReviewDrawers.tsx
+++ b/mobile/src/components/MobileDiffReviewDrawers.tsx
@@ -4,16 +4,13 @@ import { Check, Copy, FileText, Plus, Send, Trash2, X } from 'lucide-react-nativ
import type { DiffComment } from '../../../src/shared/diff-comment-types'
import { colors } from '../theme/mobile-theme'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
+import type { Translate } from '../i18n/mobile-i18n'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import type { ActionSheetAction } from './ActionSheetModal'
import { ActionSheetContent } from './ActionSheetModal'
import { ConfirmContent } from './ConfirmModal'
import { KeyedBottomDrawer } from './keyed-bottom-drawer'
-import { AGENT_LAUNCH_STATUS_UNREADABLE_MESSAGE } from '../session/mobile-existing-agent-launch'
-import {
- mobileReviewCountLabel,
- type ComposerState,
- type SendSheetState
-} from '../session/mobile-diff-review-screen-model'
+import type { ComposerState, SendSheetState } from '../session/mobile-diff-review-screen-model'
import { reviewSheetKey, type ReviewSheet } from '../session/mobile-diff-review-sheets'
import type { useMobileDiffReviewController } from '../session/use-mobile-diff-review-controller'
import { mobileDiffReviewStyles as styles } from './mobile-diff-review-screen-styles'
@@ -38,6 +35,7 @@ export function MobileDiffReviewDrawers({ controller }: Props) {
}
function ReviewSheetContent({ controller, sheet }: Props & { sheet: ReviewSheet }) {
+ const t = useMobileTranslation()
switch (sheet.kind) {
case 'actions':
return
@@ -46,9 +44,13 @@ function ReviewSheetContent({ controller, sheet }: Props & { sheet: ReviewSheet
case 'discard':
return (
{
controller.closeSheet('discard')
@@ -65,13 +67,25 @@ function ReviewSheetContent({ controller, sheet }: Props & { sheet: ReviewSheet
}
function ReviewActionsContent({ controller }: Props) {
+ const t = useMobileTranslation()
const overflowActions = useOverflowActions(controller)
+ const count = controller.reviewedUnstagedCount
return (
0
- ? `${controller.reviewedUnstagedCount} reviewed unstaged files can be staged`
+ count > 0
+ ? count === 1
+ ? t(
+ 'components.diffReviewDrawers.stageableFiles_one',
+ '{{count}} reviewed unstaged files can be staged',
+ { count }
+ )
+ : t(
+ 'components.diffReviewDrawers.stageableFiles_other',
+ '{{count}} reviewed unstaged files can be staged',
+ { count }
+ )
: undefined
}
actions={overflowActions}
@@ -81,11 +95,12 @@ function ReviewActionsContent({ controller }: Props) {
}
function SendNotesContent({ controller, load }: Props & { load: SendSheetState }) {
+ const t = useMobileTranslation()
const sendActions = useSendActions(controller, load)
return (
controller.closeSheet('send')}
/>
@@ -96,12 +111,16 @@ function useSendActions(
controller: ReturnType,
load: SendSheetState
) {
+ const t = useMobileTranslation()
return useMemo(() => {
const comments = controller.unsentComments
const terminalActions =
load.kind === 'ready' || load.kind === 'error'
? load.terminals.map((terminal) => ({
- label: `${terminal.title || 'Terminal'} (${terminal.terminal.slice(0, 6)})`,
+ label: t('components.diffReviewDrawers.terminalLabel', '{{title}} ({{id}})', {
+ title: terminal.title || t('components.diffReviewDrawers.terminal', 'Terminal'),
+ id: terminal.terminal.slice(0, 6)
+ }),
icon: Send,
disabled: comments.length === 0,
skipAutoClose: true,
@@ -111,47 +130,55 @@ function useSendActions(
return [
...terminalActions,
{
- label: 'New Agent Session',
+ label: t('components.diffReviewDrawers.newAgentSession', 'New Agent Session'),
icon: Plus,
disabled: comments.length === 0 || controller.agentLaunchAvailability !== 'available',
...(controller.agentLaunchAvailability === 'update-required'
- ? { hint: 'Update Orca on your computer' }
+ ? {
+ hint: t('components.diffReviewDrawers.updateRequired', 'Update Orca on your computer')
+ }
: controller.agentLaunchAvailability === 'unverified'
- ? { hint: AGENT_LAUNCH_STATUS_UNREADABLE_MESSAGE }
+ ? {
+ hint: t(
+ 'components.diffReviewDrawers.statusUnreadable',
+ "Could not read this host's status. Retrying…"
+ )
+ }
: {}),
skipAutoClose: true,
onPress: () => void controller.createTerminalAndSend(comments)
},
{
- label: 'Copy Notes',
+ label: t('components.diffReviewDrawers.copyNotes', 'Copy Notes'),
icon: Copy,
disabled:
controller.screenState.kind !== 'ready' || controller.screenState.comments.length === 0,
onPress: () => void controller.copyNotes()
}
]
- }, [controller, load])
+ }, [controller, load, t])
}
function useOverflowActions(controller: ReturnType) {
+ const t = useMobileTranslation()
const sessionTabsAvailable = useWorkspaceOnPairedHost()
return useMemo(
() => [
{
- label: 'Copy Notes',
+ label: t('components.diffReviewDrawers.copyNotes', 'Copy Notes'),
icon: Copy,
disabled:
controller.screenState.kind !== 'ready' || controller.screenState.comments.length === 0,
onPress: () => void controller.copyNotes()
},
{
- label: 'Send Unsent Notes',
+ label: t('components.diffReviewDrawers.sendUnsentNotes', 'Send Unsent Notes'),
icon: Send,
disabled: controller.unsentComments.length === 0,
onPress: () => void controller.openSendSheet()
},
{
- label: 'Clear Sent Notes',
+ label: t('components.diffReviewDrawers.clearSentNotes', 'Clear Sent Notes'),
icon: Trash2,
disabled:
controller.screenState.kind !== 'ready' ||
@@ -160,14 +187,14 @@ function useOverflowActions(controller: ReturnType void controller.clearSentNotes()
},
{
- label: 'Stage Reviewed Files',
+ label: t('components.diffReviewDrawers.stageReviewedFiles', 'Stage Reviewed Files'),
icon: Check,
disabled: controller.reviewedUnstagedCount === 0 || controller.busyAction !== null,
skipAutoClose: true,
onPress: () => void controller.stageReviewedFiles()
},
{
- label: 'Mark Unreviewed',
+ label: t('components.diffReviewDrawers.markUnreviewed', 'Mark Unreviewed'),
icon: X,
disabled:
controller.screenState.kind !== 'ready' ||
@@ -179,7 +206,7 @@ function useOverflowActions(controller: ReturnType void controller.openInSession()
@@ -187,41 +214,50 @@ function useOverflowActions(controller: ReturnType,
load: SendSheetState
): string | undefined {
+ const count = controller.unsentComments.length
return load.kind === 'loading'
- ? 'Loading agent sessions...'
+ ? t('components.diffReviewDrawers.loadingSessions', 'Loading agent sessions...')
: load.kind === 'error'
? load.message
- : `${controller.unsentComments.length} unsent notes`
+ : count === 1
+ ? t('components.diffReviewDrawers.unsentNotes_one', '{{count}} unsent notes', { count })
+ : t('components.diffReviewDrawers.unsentNotes_other', '{{count}} unsent notes', { count })
}
function NoteComposerContent({ controller, composer }: Props & { composer: ComposerState }) {
useMobileColorScheme()
+ const t = useMobileTranslation()
return (
- {composer.mode === 'edit' ? 'Edit Note' : 'Add Note'}
+ {composer.mode === 'edit'
+ ? t('components.diffReviewDrawers.editNote', 'Edit Note')
+ : t('components.diffReviewDrawers.addNote', 'Add Note')}
{composer.mode === 'create' && composer.lineNumber > 0
- ? `Line ${composer.lineNumber}`
- : 'File note'}
+ ? t('components.diffReviewDrawers.lineNumber', 'Line {{lineNumber}}', {
+ lineNumber: composer.lineNumber
+ })
+ : t('components.diffReviewDrawers.fileNote', 'File note')}
[styles.iconButton, pressed && styles.iconButtonPressed]}
onPress={controller.closeComposer}
accessibilityRole="button"
- accessibilityLabel="Cancel note"
+ accessibilityLabel={t('components.diffReviewDrawers.cancelNote', 'Cancel note')}
>
@@ -232,9 +268,9 @@ function NoteComposerContent({ controller, composer }: Props & { composer: Compo
onChangeText={controller.setComposerBody}
multiline
autoFocus
- placeholder="Review note"
+ placeholder={t('components.diffReviewDrawers.reviewNote', 'Review note')}
placeholderTextColor={colors.textMuted}
- accessibilityLabel={composerLabel(composer)}
+ accessibilityLabel={composerLabel(t, composer)}
/>
{composer.mode === 'edit' ? : null}
@@ -245,24 +281,28 @@ function NoteComposerContent({ controller, composer }: Props & { composer: Compo
}
function composerLabel(
+ t: Translate,
composer: { mode: 'create'; lineNumber: number } | { mode: 'edit'; comment: DiffComment } | null
): string {
return composer?.mode === 'create' && composer.lineNumber > 0
- ? `Save note on line ${composer.lineNumber}`
- : 'Review note'
+ ? t('components.diffReviewDrawers.saveLineNote', 'Save note on line {{lineNumber}}', {
+ lineNumber: composer.lineNumber
+ })
+ : t('components.diffReviewDrawers.reviewNote', 'Review note')
}
function DeleteNoteButton({ onPress }: { onPress: () => Promise }) {
useMobileColorScheme()
+ const t = useMobileTranslation()
return (
[styles.secondaryButton, pressed && styles.buttonPressed]}
onPress={() => void onPress()}
accessibilityRole="button"
- accessibilityLabel="Delete note"
+ accessibilityLabel={t('components.diffReviewDrawers.deleteNote', 'Delete note')}
>
- Delete
+ {t('common.delete', 'Delete')}
)
}
@@ -275,6 +315,7 @@ function SaveNoteButton({
composer: ReturnType['composer']
}) {
useMobileColorScheme()
+ const t = useMobileTranslation()
const disabled = controller.composerBody.trim().length === 0
return (
void controller.saveComposer()}
accessibilityRole="button"
- accessibilityLabel={composerLabel(composer)}
+ accessibilityLabel={composerLabel(t, composer)}
>
- Save
+ {t('common.save', 'Save')}
)
}
function CompletionContent({ controller }: Props) {
useMobileColorScheme()
- const noteCount =
- controller.screenState.kind === 'ready' ? controller.screenState.comments.length : 0
+ const t = useMobileTranslation()
+ const fileCount = controller.queue.length
+ const count = controller.screenState.kind === 'ready' ? controller.screenState.comments.length : 0
return (
<>
- Review Complete
+
+ {t('components.diffReviewDrawers.completeTitle', 'Review Complete')}
+
- {mobileReviewCountLabel(controller.queue.length, 'file', 'files')} reviewed,{' '}
- {mobileReviewCountLabel(noteCount, 'note', 'notes')}
+ {fileCount === 1
+ ? count === 1
+ ? t(
+ 'components.diffReviewDrawers.fileSummary_one',
+ '{{fileCount}} file reviewed, {{count}} note',
+ { fileCount, count }
+ )
+ : t(
+ 'components.diffReviewDrawers.fileSummary_other',
+ '{{fileCount}} file reviewed, {{count}} notes',
+ { fileCount, count }
+ )
+ : count === 1
+ ? t(
+ 'components.diffReviewDrawers.filesSummary_one',
+ '{{fileCount}} files reviewed, {{count}} note',
+ { fileCount, count }
+ )
+ : t(
+ 'components.diffReviewDrawers.filesSummary_other',
+ '{{fileCount}} files reviewed, {{count}} notes',
+ { fileCount, count }
+ )}
void controller.stageReviewedFiles()}
accessibilityRole="button"
- accessibilityLabel="Stage reviewed files"
+ accessibilityLabel={t(
+ 'components.diffReviewDrawers.stageReviewedLabel',
+ 'Stage reviewed files'
+ )}
>
- Stage Reviewed
+
+ {t('components.diffReviewDrawers.stageReviewed', 'Stage Reviewed')}
+
[styles.primaryButton, pressed && styles.buttonPressed]}
disabled={controller.unsentComments.length === 0}
onPress={() => void controller.openSendSheet()}
accessibilityRole="button"
- accessibilityLabel="Send notes to agent"
+ accessibilityLabel={t(
+ 'components.diffReviewDrawers.sendNotesLabel',
+ 'Send notes to agent'
+ )}
>
- Send Notes
+
+ {t('components.diffReviewDrawers.sendNotes', 'Send Notes')}
+
>
diff --git a/mobile/src/components/MobileDiffReviewFileSummary.tsx b/mobile/src/components/MobileDiffReviewFileSummary.tsx
index 9e8ce21a2d8..fc6c202e327 100644
--- a/mobile/src/components/MobileDiffReviewFileSummary.tsx
+++ b/mobile/src/components/MobileDiffReviewFileSummary.tsx
@@ -3,13 +3,11 @@ import { ArrowDown, ArrowUp } from 'lucide-react-native'
import type { DiffComment } from '../../../src/shared/diff-comment-types'
import { colors } from '../theme/mobile-theme'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
+import type { Translate } from '../i18n/mobile-i18n'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import type { MobileDiffReviewQueueItem } from '../session/mobile-diff-review-queue'
import { STATUS_LABELS } from '../../../src/shared/git-status-labels'
-import {
- mobileReviewCountLabel,
- mobileReviewScopeLabel,
- type ReviewDiffState
-} from '../session/mobile-diff-review-screen-model'
+import type { ReviewDiffState } from '../session/mobile-diff-review-screen-model'
import { mobileDiffReviewStyles as styles } from './mobile-diff-review-screen-styles'
type Props = {
@@ -40,6 +38,22 @@ function statusColor(status: MobileDiffReviewQueueItem['status']): string {
}
}
+function fileScopeLabel(t: Translate, item: MobileDiffReviewQueueItem): string {
+ if (item.oldPath) {
+ const options = { oldPath: item.oldPath }
+ return item.scope === 'branch'
+ ? t('components.diffReviewFileSummary.branchFrom', 'Branch from {{oldPath}}', options)
+ : item.scope === 'staged'
+ ? t('components.diffReviewFileSummary.stagedFrom', 'Staged from {{oldPath}}', options)
+ : t('components.diffReviewFileSummary.unstagedFrom', 'Unstaged from {{oldPath}}', options)
+ }
+ return item.scope === 'branch'
+ ? t('components.diffReviewFileSummary.branch', 'Branch')
+ : item.scope === 'staged'
+ ? t('components.diffReviewFileSummary.staged', 'Staged')
+ : t('components.diffReviewFileSummary.unstaged', 'Unstaged')
+}
+
export function MobileDiffReviewFileSummary({
currentIndex,
diffState,
@@ -51,6 +65,8 @@ export function MobileDiffReviewFileSummary({
onJumpHunk
}: Props) {
useMobileColorScheme()
+ const t = useMobileTranslation()
+ const count = item.noteCount
const hunkDisabled = diffState.kind !== 'ready' || diffState.hunks.length === 0
const badgeColor = statusColor(item.status)
return (
@@ -66,8 +82,7 @@ export function MobileDiffReviewFileSummary({
{item.filePath}
- {mobileReviewScopeLabel(item)}
- {item.oldPath ? ` from ${item.oldPath}` : ''}
+ {fileScopeLabel(t, item)}
@@ -75,15 +90,29 @@ export function MobileDiffReviewFileSummary({
{currentIndex + 1}/{filteredCount}
- {item.isReviewed ? Reviewed : null}
- {item.changedSinceReview ? Changed : null}
+ {item.isReviewed ? (
+
+ {t('components.diffReviewFileSummary.reviewed', 'Reviewed')}
+
+ ) : null}
+ {item.changedSinceReview ? (
+
+ {t('components.diffReviewFileSummary.changed', 'Changed')}
+
+ ) : null}
{item.noteCount > 0 ? (
- {mobileReviewCountLabel(item.noteCount, 'note', 'notes')}
+ {count === 1
+ ? t('components.diffReviewFileSummary.notes_one', '{{count}} note', { count })
+ : t('components.diffReviewFileSummary.notes_other', '{{count}} notes', { count })}
) : null}
{item.staleNoteCount > 0 ? (
- {item.staleNoteCount} stale
+
+ {t('components.diffReviewFileSummary.staleCount', '{{count}} stale', {
+ count: item.staleNoteCount
+ })}
+
) : null}
{fileNotes.length > 0 ? (
@@ -94,12 +123,19 @@ export function MobileDiffReviewFileSummary({
style={({ pressed }) => [styles.fileNote, pressed && styles.fileNotePressed]}
onPress={() => onEditNote(note)}
accessibilityRole="button"
- accessibilityLabel="Edit file note"
+ accessibilityLabel={t(
+ 'components.diffReviewFileSummary.editFileNote',
+ 'Edit file note'
+ )}
>
{note.body}
- {staleCommentIds.has(note.id) ? Stale : null}
+ {staleCommentIds.has(note.id) ? (
+
+ {t('components.diffReviewFileSummary.stale', 'Stale')}
+
+ ) : null}
))}
@@ -110,20 +146,24 @@ export function MobileDiffReviewFileSummary({
disabled={hunkDisabled}
onPress={() => onJumpHunk('previous')}
accessibilityRole="button"
- accessibilityLabel="Previous hunk"
+ accessibilityLabel={t('components.diffReviewFileSummary.previousHunk', 'Previous hunk')}
>
- Hunk
+
+ {t('components.diffReviewFileSummary.hunk', 'Hunk')}
+
[styles.hunkButton, pressed && styles.hunkButtonPressed]}
disabled={hunkDisabled}
onPress={() => onJumpHunk('next')}
accessibilityRole="button"
- accessibilityLabel="Next hunk"
+ accessibilityLabel={t('components.diffReviewFileSummary.nextHunk', 'Next hunk')}
>
- Hunk
+
+ {t('components.diffReviewFileSummary.hunk', 'Hunk')}
+
diff --git a/mobile/src/components/MobileDiffReviewFooter.tsx b/mobile/src/components/MobileDiffReviewFooter.tsx
index 215eed6e0cc..2de2016fc8d 100644
--- a/mobile/src/components/MobileDiffReviewFooter.tsx
+++ b/mobile/src/components/MobileDiffReviewFooter.tsx
@@ -9,6 +9,7 @@ import {
Undo2
} from 'lucide-react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import type { MobileDiffReviewQueueItem } from '../session/mobile-diff-review-queue'
import type { GitMutationMethod } from '../session/mobile-diff-review-screen-model'
import { colors, spacing } from '../theme/mobile-theme'
@@ -34,6 +35,7 @@ export function MobileDiffReviewFooter({
onMarkReviewed,
onMoveFile
}: Props) {
+ const t = useMobileTranslation()
useMobileColorScheme()
const insets = useSafeAreaInsets()
return (
@@ -45,10 +47,12 @@ export function MobileDiffReviewFooter({
disabled={busyAction !== null}
onPress={() => onGitMutation('git.stage', item)}
accessibilityRole="button"
- accessibilityLabel="Stage file"
+ accessibilityLabel={t('components.diffReviewFooter.stageFile', 'Stage file')}
>
- Stage
+
+ {t('components.diffReviewFooter.stage', 'Stage')}
+
) : null}
{item.canUnstage ? (
@@ -57,10 +61,12 @@ export function MobileDiffReviewFooter({
disabled={busyAction !== null}
onPress={() => onGitMutation('git.unstage', item)}
accessibilityRole="button"
- accessibilityLabel="Unstage file"
+ accessibilityLabel={t('components.diffReviewFooter.unstageFile', 'Unstage file')}
>
- Unstage
+
+ {t('components.diffReviewFooter.unstage', 'Unstage')}
+
) : null}
{item.canDiscard ? (
@@ -69,10 +75,12 @@ export function MobileDiffReviewFooter({
disabled={busyAction !== null}
onPress={() => onDiscard(item)}
accessibilityRole="button"
- accessibilityLabel="Discard file"
+ accessibilityLabel={t('components.diffReviewFooter.discardFile', 'Discard file')}
>
- Discard
+
+ {t('components.diffReviewFooter.discard', 'Discard')}
+
) : null}
@@ -81,7 +89,7 @@ export function MobileDiffReviewFooter({
style={({ pressed }) => [styles.navButton, pressed && styles.buttonPressed]}
onPress={() => onMoveFile('previous')}
accessibilityRole="button"
- accessibilityLabel="Previous file"
+ accessibilityLabel={t('components.diffReviewFooter.previousFile', 'Previous file')}
>
@@ -89,10 +97,12 @@ export function MobileDiffReviewFooter({
style={({ pressed }) => [styles.footerButton, pressed && styles.buttonPressed]}
onPress={onAddFileNote}
accessibilityRole="button"
- accessibilityLabel="Add file note"
+ accessibilityLabel={t('components.diffReviewFooter.addFileNote', 'Add file note')}
>
- Note
+
+ {t('components.diffReviewFooter.note', 'Note')}
+
[
@@ -102,18 +112,23 @@ export function MobileDiffReviewFooter({
]}
onPress={onMarkReviewed}
accessibilityRole="button"
- accessibilityLabel="Mark file reviewed"
+ accessibilityLabel={t(
+ 'components.diffReviewFooter.markFileReviewed',
+ 'Mark file reviewed'
+ )}
>
- {item.isReviewed ? 'Reviewed' : 'Mark Reviewed'}
+ {item.isReviewed
+ ? t('components.diffReviewFooter.reviewed', 'Reviewed')
+ : t('components.diffReviewFooter.markReviewed', 'Mark Reviewed')}
[styles.navButton, pressed && styles.buttonPressed]}
onPress={() => onMoveFile('next')}
accessibilityRole="button"
- accessibilityLabel="Next file"
+ accessibilityLabel={t('components.diffReviewFooter.nextFile', 'Next file')}
>
diff --git a/mobile/src/components/MobileDiffReviewHeader.tsx b/mobile/src/components/MobileDiffReviewHeader.tsx
index 8e087ef8075..e7470853b3c 100644
--- a/mobile/src/components/MobileDiffReviewHeader.tsx
+++ b/mobile/src/components/MobileDiffReviewHeader.tsx
@@ -1,9 +1,10 @@
import { FlatList, Pressable, Text, View } from 'react-native'
import { ChevronLeft, ListChecks, MoreHorizontal } from 'lucide-react-native'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import { colors } from '../theme/mobile-theme'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
import type { MobileDiffReviewQueueFilter } from '../session/mobile-diff-review-queue'
-import { REVIEW_FILTERS, mobileReviewCountLabel } from '../session/mobile-diff-review-screen-model'
+import { REVIEW_FILTERS } from '../session/mobile-diff-review-screen-model'
import { shouldShowTrigger } from './mobile-pr-sidebar-presentation'
import { mobileDiffReviewStyles as styles } from './mobile-diff-review-screen-styles'
@@ -36,7 +37,50 @@ export function MobileDiffReviewHeader({
onOpenPRSidebar,
onSelectFilter
}: Props) {
+ const t = useMobileTranslation()
const colorScheme = useMobileColorScheme()
+ const count = unsentCount
+ const filters: Record<
+ MobileDiffReviewQueueFilter,
+ { label: string; accessibilityLabel: string }
+ > = {
+ all: {
+ label: t('components.diffReviewHeader.filterAll', 'All'),
+ accessibilityLabel: t('components.diffReviewHeader.showAllFiles', 'Show all review files')
+ },
+ unreviewed: {
+ label: t('components.diffReviewHeader.filterUnreviewed', 'Unreviewed'),
+ accessibilityLabel: t(
+ 'components.diffReviewHeader.showUnreviewedFiles',
+ 'Show unreviewed review files'
+ )
+ },
+ notes: {
+ label: t('components.diffReviewHeader.filterNotes', 'Notes'),
+ accessibilityLabel: t('components.diffReviewHeader.showNotesFiles', 'Show notes review files')
+ },
+ unstaged: {
+ label: t('components.diffReviewHeader.filterUnstaged', 'Unstaged'),
+ accessibilityLabel: t(
+ 'components.diffReviewHeader.showUnstagedFiles',
+ 'Show unstaged review files'
+ )
+ },
+ staged: {
+ label: t('components.diffReviewHeader.filterStaged', 'Staged'),
+ accessibilityLabel: t(
+ 'components.diffReviewHeader.showStagedFiles',
+ 'Show staged review files'
+ )
+ },
+ branch: {
+ label: t('components.diffReviewHeader.filterBranch', 'Branch'),
+ accessibilityLabel: t(
+ 'components.diffReviewHeader.showBranchFiles',
+ 'Show branch review files'
+ )
+ }
+ }
// Show PR icon on narrow/overlay GitHub repos; wide docked sidebar needs no trigger.
const showPRTrigger = shouldShowTrigger({
isGithubRepo: prSidebarIsGithubRepo,
@@ -50,13 +94,13 @@ export function MobileDiffReviewHeader({
style={({ pressed }) => [styles.iconButton, pressed && styles.iconButtonPressed]}
onPress={onBack}
accessibilityRole="button"
- accessibilityLabel="Back"
+ accessibilityLabel={t('common.back', 'Back')}
>
- Changes
+ {t('components.diffReviewHeader.title', 'Changes')}
{worktreeLabel}
@@ -67,7 +111,10 @@ export function MobileDiffReviewHeader({
style={({ pressed }) => [styles.iconButton, pressed && styles.iconButtonPressed]}
onPress={onOpenPRSidebar}
accessibilityRole="button"
- accessibilityLabel="Open pull request sidebar"
+ accessibilityLabel={t(
+ 'components.diffReviewHeader.openPullRequestSidebar',
+ 'Open pull request sidebar'
+ )}
>
@@ -76,17 +123,31 @@ export function MobileDiffReviewHeader({
style={({ pressed }) => [styles.iconButton, pressed && styles.iconButtonPressed]}
onPress={onOpenActions}
accessibilityRole="button"
- accessibilityLabel="Open review actions"
+ accessibilityLabel={t(
+ 'components.diffReviewHeader.openReviewActions',
+ 'Open review actions'
+ )}
>
- {reviewedCount}/{queueLength} reviewed
+ {t(
+ 'components.diffReviewHeader.reviewedProgress',
+ '{{reviewedCount}}/{{queueLength}} reviewed',
+ {
+ reviewedCount,
+ queueLength
+ }
+ )}
- {mobileReviewCountLabel(unsentCount, 'unsent note', 'unsent notes')}
+ {count === 1
+ ? t('components.diffReviewHeader.unsentNotes_one', '{{count}} unsent note', { count })
+ : t('components.diffReviewHeader.unsentNotes_other', '{{count}} unsent notes', {
+ count
+ })}
item}
- extraData={colorScheme}
+ extraData={[colorScheme, t]}
contentContainerStyle={styles.filterRow}
renderItem={({ item }) => (
onSelectFilter(item)}
accessibilityRole="button"
accessibilityState={{ selected: filter === item }}
- accessibilityLabel={`Show ${item} review files`}
+ accessibilityLabel={filters[item].accessibilityLabel}
>
- {item === 'all' ? 'All' : item[0]?.toUpperCase() + item.slice(1)}
+ {filters[item].label}
)}
diff --git a/mobile/src/components/MobileDiffReviewLine.tsx b/mobile/src/components/MobileDiffReviewLine.tsx
index 3beecc0330c..e2fde475783 100644
--- a/mobile/src/components/MobileDiffReviewLine.tsx
+++ b/mobile/src/components/MobileDiffReviewLine.tsx
@@ -1,5 +1,7 @@
import { Pressable, StyleSheet, Text, View } from 'react-native'
import { MessageSquare } from 'lucide-react-native'
+import type { Translate } from '../i18n/mobile-i18n'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import type { DiffComment } from '../../../src/shared/diff-comment-types'
import type { MobileDiffLine } from '../session/mobile-diff-lines'
import type { MobileHighlightedDiffLine } from '../session/mobile-file-syntax'
@@ -18,10 +20,21 @@ type Props = {
onEditNote: (comment: DiffComment) => void
}
-function accessibilityLabelForLine(line: MobileDiffLine): string {
+function accessibilityLabelForLine(line: MobileDiffLine, t: Translate): string {
const number = mobileDiffLineNumber(line)
- const label = line.kind === 'add' ? 'Added' : line.kind === 'delete' ? 'Deleted' : 'Context'
- return number ? `${label} line ${number}` : `${label} line`
+ if (line.kind === 'add') {
+ return number
+ ? t('components.diffReviewLine.addedLineNumber', 'Added line {{number}}', { number })
+ : t('components.diffReviewLine.addedLine', 'Added line')
+ }
+ if (line.kind === 'delete') {
+ return number
+ ? t('components.diffReviewLine.deletedLineNumber', 'Deleted line {{number}}', { number })
+ : t('components.diffReviewLine.deletedLine', 'Deleted line')
+ }
+ return number
+ ? t('components.diffReviewLine.contextLineNumber', 'Context line {{number}}', { number })
+ : t('components.diffReviewLine.contextLine', 'Context line')
}
function canCommentOnLine(line: MobileDiffLine): boolean {
@@ -36,6 +49,7 @@ export function MobileDiffReviewLine({
onAddNote,
onEditNote
}: Props) {
+ const t = useMobileTranslation()
useMobileColorScheme()
const lineNumber = mobileDiffLineNumber(line)
const canComment = canCommentOnLine(line)
@@ -49,7 +63,7 @@ export function MobileDiffReviewLine({
active && styles.activeRow
]}
accessible
- accessibilityLabel={accessibilityLabelForLine(line)}
+ accessibilityLabel={accessibilityLabelForLine(line, t)}
>
{mobileDiffLinePrefix(line.kind)}
{lineNumber ? String(lineNumber) : ''}
@@ -64,8 +78,10 @@ export function MobileDiffReviewLine({
accessibilityRole={canComment ? 'button' : 'text'}
accessibilityLabel={
canComment && line.newLineNumber !== undefined
- ? `Add note on line ${line.newLineNumber}`
- : accessibilityLabelForLine(line)
+ ? t('components.diffReviewLine.addNoteOnLine', 'Add note on line {{number}}', {
+ number: line.newLineNumber
+ })
+ : accessibilityLabelForLine(line, t)
}
>
@@ -80,7 +96,13 @@ export function MobileDiffReviewLine({
style={({ pressed }) => [styles.noteButton, pressed && styles.noteButtonPressed]}
onPress={() => onEditNote(comment)}
accessibilityRole="button"
- accessibilityLabel={`Edit note on line ${comment.lineNumber}`}
+ accessibilityLabel={t(
+ 'components.diffReviewLine.editNoteOnLine',
+ 'Edit note on line {{number}}',
+ {
+ number: comment.lineNumber
+ }
+ )}
>
0
return (
<>
- Quick Actions
+
+ {t('components.homeQuickActions.title', 'Quick Actions')}
+
- Pair Desktop
+
+ {t('components.homeQuickActions.pairDesktop', 'Pair Desktop')}
+
- New Workspace
+
+ {t('components.homeQuickActions.newWorkspace', 'New Workspace')}
+
>
diff --git a/mobile/src/components/MobileHostCard.tsx b/mobile/src/components/MobileHostCard.tsx
index 7bafcf306ab..93eeab4c104 100644
--- a/mobile/src/components/MobileHostCard.tsx
+++ b/mobile/src/components/MobileHostCard.tsx
@@ -1,5 +1,7 @@
import { Monitor, MoreVertical } from 'lucide-react-native'
import { Pressable, Text, View } from 'react-native'
+import type { Translate } from '../i18n/mobile-i18n'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import type { ConnectionVerdict } from '../transport/connection-health'
import { verdictDisplayLabel } from '../transport/connection-health'
import {
@@ -15,6 +17,23 @@ import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
import { homeHostWorktreeSummary, type HostWorktreeInfo } from '../worktree/home-worktree-info'
import { StatusDot } from './StatusDot'
+function hostCardWorktreeSummaries(info: HostWorktreeInfo | undefined, t: Translate) {
+ const now = Date.now()
+ const visual = homeHostWorktreeSummary(info, now)
+ const accessibility =
+ info && info.activeCount > 0 && (!info.catalogUnavailable || info.staleCounts)
+ ? t(
+ 'components.hostCard.worktreeAccessibilitySummary',
+ '{{summary}}, {{activeCount}} active',
+ {
+ summary: homeHostWorktreeSummary({ ...info, activeCount: 0 }, now),
+ activeCount: info.activeCount
+ }
+ )
+ : visual
+ return { visual, accessibility }
+}
+
export function MobileHostCard(props: {
host: HostProfile | HostCatalogEntry
credentialStatus?: HostCatalogEntry['credentialStatus']
@@ -27,6 +46,7 @@ export function MobileHostCard(props: {
onLongPress: () => void
onOpenActions: () => void
}) {
+ const t = useMobileTranslation()
useMobileColorScheme()
const credentialUnavailable = props.credentialStatus === 'temporarily-unavailable'
const credentialMissing = props.credentialStatus === 'missing'
@@ -34,16 +54,16 @@ export function MobileHostCard(props: {
const isError =
credentialMissing || ['warning', 'unreachable', 'auth-failed'].includes(props.verdict.kind)
const statusLabel = credentialMissing
- ? 'Pairing invalid'
+ ? t('components.hostCard.pairingInvalid', 'Pairing invalid')
: credentialUnavailable
- ? 'Pairing temporarily unavailable'
+ ? t('components.hostCard.pairingTemporarilyUnavailable', 'Pairing temporarily unavailable')
: verdictDisplayLabel(props.verdict)
const statusVerdict: ConnectionVerdict = credentialMissing
? { kind: 'auth-failed', label: statusLabel }
: credentialUnavailable
? { kind: 'warning', label: statusLabel }
: props.verdict
- const worktreeSummary = homeHostWorktreeSummary(props.worktreeInfo)
+ const worktreeSummary = hostCardWorktreeSummaries(props.worktreeInfo, t)
const display = useHostDisplay(props.host)
const descriptorText = display.descriptorLine
const connectionPathLabel =
@@ -52,22 +72,25 @@ export function MobileHostCard(props: {
: null
const discoveryHint =
props.verdict.kind === 'unreachable' && !props.host.relay
- ? 'Update desktop Orca and sign in to connect from anywhere'
+ ? t(
+ 'components.hostCard.updateDesktopHint',
+ 'Update desktop Orca and sign in to connect from anywhere'
+ )
: null
const credentialHint = credentialMissing
- ? 'Tap to re-pair with your desktop'
+ ? t('components.hostCard.repairHint', 'Tap to re-pair with your desktop')
: credentialUnavailable
- ? 'Unlock your phone, then tap to retry'
+ ? t('components.hostCard.unlockHint', 'Unlock your phone, then tap to retry')
: null
// The verdict's own second line (what to check on the desktop); credential copy wins.
const verdictDetail =
credentialHint === null && 'detail' in props.verdict ? (props.verdict.detail ?? null) : null
const accessibilityLabel = [
- `Open ${display.title}`,
+ t('components.hostCard.openHost', 'Open {{title}}', { title: display.title }),
descriptorText,
statusLabel,
connectionPathLabel ? mobileConnectionPathAccessibilityLabel(props.path) : null,
- connected ? worktreeSummary?.replace(' · ', ', ') : null,
+ connected ? worktreeSummary.accessibility : null,
discoveryHint,
credentialHint,
verdictDetail
@@ -113,9 +136,9 @@ export function MobileHostCard(props: {
{connectionPathLabel ? ` · ${connectionPathLabel}` : ''}
- {connected && worktreeSummary ? (
+ {connected && worktreeSummary.visual ? (
- {worktreeSummary}
+ {worktreeSummary.visual}
) : null}
{discoveryHint ? (
@@ -137,7 +160,9 @@ export function MobileHostCard(props: {
[styles.actionButton, pressed && styles.actionButtonPressed]}
onPress={props.onOpenActions}
diff --git a/mobile/src/components/MobileHtmlPreview.tsx b/mobile/src/components/MobileHtmlPreview.tsx
index a12fe07cfab..ec2b4ad5f56 100644
--- a/mobile/src/components/MobileHtmlPreview.tsx
+++ b/mobile/src/components/MobileHtmlPreview.tsx
@@ -1,6 +1,7 @@
import { useMemo, useState } from 'react'
import { Pressable, Text, View } from 'react-native'
import { Code, Eye } from 'lucide-react-native'
+import { useMobileTranslation } from '../i18n/use-mobile-translation'
import { colors, spacing, typography } from '../theme/mobile-theme'
import { themedStyleSheet } from '../theme/themed-styles'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
@@ -25,6 +26,7 @@ export const MOBILE_HTML_PREVIEW_SEALED_SANDBOX = ''
// Inherited img/font/connect/script policies still constrain artifact; https images can report view through fixed author URL, but scripts cannot add dynamic data.
// Shell Referrer-Policy:no-referrer is required: WebKit ignores iframe referrerPolicy for srcdoc images, unlike Chromium.
export function MobileHtmlPreview({ html, renderSource }: MobileHtmlPreviewProps) {
+ const t = useMobileTranslation()
useMobileColorScheme()
const [mode, setMode] = useState<'preview' | 'source'>('preview')
// Read immutable session grants once after init, before page mounts.
@@ -46,10 +48,13 @@ export function MobileHtmlPreview({ html, renderSource }: MobileHtmlPreviewProps
// Set both native accessibilityState and web aria-selected: RN Web drops former without emitting latter.
accessibilityState={{ selected: mode === 'preview' }}
aria-selected={mode === 'preview'}
- accessibilityLabel="Preview rendered HTML"
+ accessibilityLabel={t(
+ 'components.htmlPreview.previewRenderedHtml',
+ 'Preview rendered HTML'
+ )}
>
- Preview
+ {t('components.htmlPreview.preview', 'Preview')}
- Source
+ {t('components.htmlPreview.source', 'Source')}
{/* Show author’s original source; inert-link rewrite is only this shell’s rendering policy. */}
@@ -71,11 +76,12 @@ export function MobileHtmlPreview({ html, renderSource }: MobileHtmlPreviewProps
// Use DOM iframe: RN has no primitive. Set srcdoc attribute to parse untrusted content only inside sealed frame.
function PreviewFrame({ html, linksOpen }: { html: string; linksOpen: boolean }) {
+ const t = useMobileTranslation()
useMobileColorScheme()
return (