From 0d97653e3928f511cc28cb7a446c1985126e11fd Mon Sep 17 00:00:00 2001
From: Neil <4138956+nwparker@users.noreply.github.com>
Date: Sun, 19 Jul 2026 21:24:24 -0700
Subject: [PATCH] fix(ui): restore missing spaces in i18n JSX fragment copy
(#9513)
---
.../src/components/GitHubItemDialog.tsx | 5 +-
.../src/components/GitLabItemDialog.tsx | 4 +-
.../src/components/PullRequestPage.tsx | 5 +-
src/renderer/src/components/TaskPage.tsx | 2 +-
src/renderer/src/components/UpdateCard.tsx | 3 +-
.../automations/AutomationsPage.tsx | 2 +-
.../ExternalAutomationRunTable.tsx | 2 +-
.../ContextualTourProgressDots.tsx | 2 +-
.../components/editor/CombinedDiffViewer.tsx | 2 +-
.../components/editor/ConflictComponents.tsx | 6 +-
.../src/components/editor/IpynbViewer.tsx | 2 +-
.../src/components/editor/MermaidBlock.tsx | 3 +-
.../editor/RichMarkdownDocLinkMenu.tsx | 4 +-
.../ReviewNotesAnimatedVisual.tsx | 2 +-
.../ReviewPRViewAnimatedVisual.tsx | 2 +-
.../feature-wall/ReviewShipAnimatedVisual.tsx | 2 +-
.../feature-wall/review-notes-diff-rows.tsx | 2 +-
.../components/github/PRFilterSections.tsx | 3 +-
.../github/github-rate-limit-display.tsx | 4 +-
.../gitlab/gitlab-rate-limit-display.tsx | 2 +-
.../src/components/linear-priority-icon.tsx | 9 +-
.../right-sidebar/FileExplorerTreeStatus.tsx | 2 +-
.../SourceControlAgentActionDialogForm.tsx | 2 +-
.../right-sidebar/checks-panel-content.tsx | 4 +-
.../src/components/settings/AccountsPane.tsx | 4 +-
.../AutoRenameBranchFromWorkSetting.tsx | 8 +-
.../src/components/settings/BaseRefPicker.tsx | 4 +-
.../settings/BrowserSessionCookiesSection.tsx | 2 +-
.../src/components/settings/CliSection.tsx | 2 +-
.../settings/CommitMessageAiPane.tsx | 2 +-
.../settings/GeneralEditorSettingsSection.tsx | 2 +-
.../settings/GeneralUpdateSettingsSection.tsx | 4 +-
.../src/components/settings/GitPane.tsx | 9 +-
.../settings/ManageSessionKillDialog.tsx | 2 +-
.../settings/NotificationSoundSection.tsx | 2 +-
.../settings/RepositoryHooksSection.tsx | 6 +-
.../components/settings/RepositoryPane.tsx | 2 +-
...orySourceControlAiHostedReviewDefaults.tsx | 2 +-
.../settings/RuntimeEnvironmentsPane.tsx | 2 +-
.../settings/SshPassphraseDialog.tsx | 4 +-
.../settings/WslCliRegistration.tsx | 2 +-
.../sidebar/DeleteWorktreeWarningPanels.tsx | 4 +-
.../sidebar/SetupScriptPromptCardViews.tsx | 6 +-
.../src/components/stats/ShareUsageCard.tsx | 2 +-
.../components/stats/UsageOverviewPane.tsx | 2 +-
.../src/lib/i18n-jsx-spacing-guard.test.ts | 140 ++++++++++++++++++
46 files changed, 212 insertions(+), 77 deletions(-)
create mode 100644 src/renderer/src/lib/i18n-jsx-spacing-guard.test.ts
diff --git a/src/renderer/src/components/GitHubItemDialog.tsx b/src/renderer/src/components/GitHubItemDialog.tsx
index 6f6b7fb2424..5d98a84f0f1 100644
--- a/src/renderer/src/components/GitHubItemDialog.tsx
+++ b/src/renderer/src/components/GitHubItemDialog.tsx
@@ -4935,13 +4935,12 @@ function ChecksTab({
{startedAt && (
- {translate('auto.components.GitHubItemDialog.4812814bc8', 'Started')}
- {startedAt}
+ {translate('auto.components.GitHubItemDialog.4812814bc8', 'Started')} {startedAt}
)}
{completedAt && (
- {translate('auto.components.GitHubItemDialog.0f478f5efa', 'Completed')}
+ {translate('auto.components.GitHubItemDialog.0f478f5efa', 'Completed')}{' '}
{completedAt}
)}
diff --git a/src/renderer/src/components/GitLabItemDialog.tsx b/src/renderer/src/components/GitLabItemDialog.tsx
index b71386b4c34..827d86ad2d8 100644
--- a/src/renderer/src/components/GitLabItemDialog.tsx
+++ b/src/renderer/src/components/GitLabItemDialog.tsx
@@ -1034,7 +1034,7 @@ export default function GitLabItemDialog({
{content}
diff --git a/src/renderer/src/components/editor/RichMarkdownDocLinkMenu.tsx b/src/renderer/src/components/editor/RichMarkdownDocLinkMenu.tsx
index d339f1e3da6..dafc70c658b 100644
--- a/src/renderer/src/components/editor/RichMarkdownDocLinkMenu.tsx
+++ b/src/renderer/src/components/editor/RichMarkdownDocLinkMenu.tsx
@@ -68,9 +68,9 @@ export function RichMarkdownDocLinkMenu({
)}
{overflow ? (
- {translate('auto.components.editor.RichMarkdownDocLinkMenu.2aaf7d9678', 'Showing')}
+ {translate('auto.components.editor.RichMarkdownDocLinkMenu.2aaf7d9678', 'Showing')}{' '}
{rows.length}{' '}
- {translate('auto.components.editor.RichMarkdownDocLinkMenu.90c5f0e1e4', 'of')}
+ {translate('auto.components.editor.RichMarkdownDocLinkMenu.90c5f0e1e4', 'of')}{' '}
{totalMatches}
) : null}
diff --git a/src/renderer/src/components/feature-wall/ReviewNotesAnimatedVisual.tsx b/src/renderer/src/components/feature-wall/ReviewNotesAnimatedVisual.tsx
index 24c8399761e..ba9684ba708 100644
--- a/src/renderer/src/components/feature-wall/ReviewNotesAnimatedVisual.tsx
+++ b/src/renderer/src/components/feature-wall/ReviewNotesAnimatedVisual.tsx
@@ -381,7 +381,7 @@ export function ReviewNotesAnimatedVisual(props: { reducedMotion: boolean }): JS
- {translate('auto.components.feature.wall.ReviewNotesAnimatedVisual.a7a89d8f94', 'Line')}
+ {translate('auto.components.feature.wall.ReviewNotesAnimatedVisual.a7a89d8f94', 'Line')}{' '}
?
diff --git a/src/renderer/src/components/feature-wall/ReviewPRViewAnimatedVisual.tsx b/src/renderer/src/components/feature-wall/ReviewPRViewAnimatedVisual.tsx
index be3148a0e7c..461da2f21c6 100644
--- a/src/renderer/src/components/feature-wall/ReviewPRViewAnimatedVisual.tsx
+++ b/src/renderer/src/components/feature-wall/ReviewPRViewAnimatedVisual.tsx
@@ -272,7 +272,7 @@ export function ReviewPRViewAnimatedVisual(props: { reducedMotion: boolean }): J
{translate(
'auto.components.feature.wall.ReviewPRViewAnimatedVisual.6f4c2d7cb7',
'Add a coverage case for'
- )}
+ )}{' '}
{translate(
'auto.components.feature.wall.ReviewPRViewAnimatedVisual.c2062da7ec',
diff --git a/src/renderer/src/components/feature-wall/ReviewShipAnimatedVisual.tsx b/src/renderer/src/components/feature-wall/ReviewShipAnimatedVisual.tsx
index 0b2ef880ffa..548ac8334f2 100644
--- a/src/renderer/src/components/feature-wall/ReviewShipAnimatedVisual.tsx
+++ b/src/renderer/src/components/feature-wall/ReviewShipAnimatedVisual.tsx
@@ -303,7 +303,7 @@ export function ReviewShipAnimatedVisual(props: { reducedMotion: boolean }): JSX
{translate(
'auto.components.feature.wall.ReviewShipAnimatedVisual.e725000cd7',
'Changes'
- )}
+ )}{' '}
{SHIP_FILES.length}
diff --git a/src/renderer/src/components/feature-wall/review-notes-diff-rows.tsx b/src/renderer/src/components/feature-wall/review-notes-diff-rows.tsx
index c5c476a39d2..cbba8da521c 100644
--- a/src/renderer/src/components/feature-wall/review-notes-diff-rows.tsx
+++ b/src/renderer/src/components/feature-wall/review-notes-diff-rows.tsx
@@ -85,7 +85,7 @@ export function ReviewDiffRows(): JSX.Element {
{translate(
'auto.components.feature.wall.review.notes.diff.rows.f621c734f8',
'Note · line'
- )}
+ )}{' '}
?
diff --git a/src/renderer/src/components/github/PRFilterSections.tsx b/src/renderer/src/components/github/PRFilterSections.tsx
index 59fc7634120..6f65eee8e55 100644
--- a/src/renderer/src/components/github/PRFilterSections.tsx
+++ b/src/renderer/src/components/github/PRFilterSections.tsx
@@ -208,8 +208,7 @@ export function SectionMenu({
return (
- {translate('auto.components.github.PRFilterSections.8177eda37e', 'Filter')}
- {subject}
+ {translate('auto.components.github.PRFilterSections.8177eda37e', 'Filter')} {subject}
{rows.map((row) => (
diff --git a/src/renderer/src/components/gitlab/gitlab-rate-limit-display.tsx b/src/renderer/src/components/gitlab/gitlab-rate-limit-display.tsx
index 6bc87d967e8..a85c566b0d6 100644
--- a/src/renderer/src/components/gitlab/gitlab-rate-limit-display.tsx
+++ b/src/renderer/src/components/gitlab/gitlab-rate-limit-display.tsx
@@ -133,7 +133,7 @@ function GitLabRateLimitRows({
)}
>
{rest.remaining}{' '}
- {translate('auto.components.gitlab.gitlab.rate.limit.display.ea8ad0bae8', 'of')}
+ {translate('auto.components.gitlab.gitlab.rate.limit.display.ea8ad0bae8', 'of')}{' '}
{rest.limit}{' '}
{translate(
'auto.components.gitlab.gitlab.rate.limit.display.3e2c982cfa',
diff --git a/src/renderer/src/components/linear-priority-icon.tsx b/src/renderer/src/components/linear-priority-icon.tsx
index ae9ebbb16a8..92f8bfaa210 100644
--- a/src/renderer/src/components/linear-priority-icon.tsx
+++ b/src/renderer/src/components/linear-priority-icon.tsx
@@ -54,8 +54,7 @@ export function LinearPriorityIcon({
>
- {translate('auto.components.linear.priority.icon.c43d3e065b', 'Priority:')}
- {label}
+ {translate('auto.components.linear.priority.icon.c43d3e065b', 'Priority:')} {label}
)
@@ -72,8 +71,7 @@ export function LinearPriorityIcon({
className="size-3 rounded-full border border-muted-foreground/55"
/>
- {translate('auto.components.linear.priority.icon.c43d3e065b', 'Priority:')}
- {label}
+ {translate('auto.components.linear.priority.icon.c43d3e065b', 'Priority:')} {label}
)
@@ -110,8 +108,7 @@ export function LinearPriorityIcon({
})}
- {translate('auto.components.linear.priority.icon.c43d3e065b', 'Priority:')}
- {label}
+ {translate('auto.components.linear.priority.icon.c43d3e065b', 'Priority:')} {label}
)
diff --git a/src/renderer/src/components/right-sidebar/FileExplorerTreeStatus.tsx b/src/renderer/src/components/right-sidebar/FileExplorerTreeStatus.tsx
index 7f8d3824151..58fa294e5da 100644
--- a/src/renderer/src/components/right-sidebar/FileExplorerTreeStatus.tsx
+++ b/src/renderer/src/components/right-sidebar/FileExplorerTreeStatus.tsx
@@ -29,7 +29,7 @@ export function FileExplorerTreeStatus({
{translate(
'auto.components.right.sidebar.FileExplorerTreeStatus.c76693e456',
'Could not load files for this workspace:'
- )}
+ )}{' '}
{error}
{translate('auto.components.settings.AccountsPane.922b51e02d', 'Fe26.2**…')}
{translate(
'auto.components.settings.AccountsPane.338820326a',
') or the full cookie header (e.g.'
- )}
+ )}{' '}
{translate('auto.components.settings.AccountsPane.8951c5309f', 'auth=Fe26.2**…')}
diff --git a/src/renderer/src/components/settings/AutoRenameBranchFromWorkSetting.tsx b/src/renderer/src/components/settings/AutoRenameBranchFromWorkSetting.tsx
index b8540cdefa9..c4d520cbdb7 100644
--- a/src/renderer/src/components/settings/AutoRenameBranchFromWorkSetting.tsx
+++ b/src/renderer/src/components/settings/AutoRenameBranchFromWorkSetting.tsx
@@ -159,7 +159,7 @@ export function AutoRenameBranchFromWorkSetting({
{translate(
'auto.components.settings.AutoRenameBranchFromWorkSetting.12ea4a408d',
'When an agent starts working in a new workspace, Orca renames its auto-generated branch (e.g.'
- )}
+ )}{' '}
{translate(
'auto.components.settings.AutoRenameBranchFromWorkSetting.1626524572',
@@ -223,7 +223,7 @@ export function AutoRenameBranchFromWorkSetting({
{translate(
'auto.components.settings.AutoRenameBranchFromWorkSetting.9241b59bf5',
'Use'
- )}
+ )}{' '}
{translate(
'auto.components.settings.AutoRenameBranchFromWorkSetting.c71770c455',
@@ -261,7 +261,7 @@ export function AutoRenameBranchFromWorkSetting({
{translate(
'auto.components.settings.AutoRenameBranchFromWorkSetting.56580dcf60',
'. You can also reference'
- )}
+ )}{' '}
{translate(
'auto.components.settings.AutoRenameBranchFromWorkSetting.2ee2779c05',
@@ -281,7 +281,7 @@ export function AutoRenameBranchFromWorkSetting({
{translate(
'auto.components.settings.AutoRenameBranchFromWorkSetting.5d569f5199',
'. Orca generates only the final segment, like'
- )}
+ )}{' '}
{translate(
'auto.components.settings.AutoRenameBranchFromWorkSetting.800edb1e54',
diff --git a/src/renderer/src/components/settings/BaseRefPicker.tsx b/src/renderer/src/components/settings/BaseRefPicker.tsx
index b0c0b6e72ef..8bb96a508cc 100644
--- a/src/renderer/src/components/settings/BaseRefPicker.tsx
+++ b/src/renderer/src/components/settings/BaseRefPicker.tsx
@@ -195,14 +195,14 @@ export function BaseRefPicker({
{translate(
'auto.components.settings.BaseRefPicker.a5c16712c1',
'Multiple remotes detected. Type a remote name (e.g.'
- )}
+ )}{' '}
{translate('auto.components.settings.BaseRefPicker.915ad97875', 'upstream')}
{translate(
'auto.components.settings.BaseRefPicker.80f7c82303',
') or a full ref (e.g.'
- )}
+ )}{' '}
{translate('auto.components.settings.BaseRefPicker.b468f46726', 'upstream/main')}
diff --git a/src/renderer/src/components/settings/BrowserSessionCookiesSection.tsx b/src/renderer/src/components/settings/BrowserSessionCookiesSection.tsx
index f1c39ca8fec..8fa1e6c9a60 100644
--- a/src/renderer/src/components/settings/BrowserSessionCookiesSection.tsx
+++ b/src/renderer/src/components/settings/BrowserSessionCookiesSection.tsx
@@ -72,7 +72,7 @@ export function BrowserSessionCookiesSection({
{translate(
'auto.components.settings.BrowserPane.cd47bc9622',
'Select a default profile for new browser tabs. Import cookies and switch profiles per-tab via the'
- )}
+ )}{' '}
···{' '}
{translate('auto.components.settings.BrowserPane.e4aaf8051b', 'toolbar menu.')}
diff --git a/src/renderer/src/components/settings/CliSection.tsx b/src/renderer/src/components/settings/CliSection.tsx
index 5f61d1e8ef3..6f6eab2ee94 100644
--- a/src/renderer/src/components/settings/CliSection.tsx
+++ b/src/renderer/src/components/settings/CliSection.tsx
@@ -317,7 +317,7 @@ export function CliSection({
{translate(
'auto.components.settings.CliSection.b0c310ab46',
'Existing launcher target:'
- )}
+ )}{' '}
{status.currentTarget}
) : null}
diff --git a/src/renderer/src/components/settings/CommitMessageAiPane.tsx b/src/renderer/src/components/settings/CommitMessageAiPane.tsx
index 9b8ebc6d9ff..e24fc97ee40 100644
--- a/src/renderer/src/components/settings/CommitMessageAiPane.tsx
+++ b/src/renderer/src/components/settings/CommitMessageAiPane.tsx
@@ -273,7 +273,7 @@ export function CommitMessageAiPane({
{translate(
'auto.components.settings.CommitMessageAiPane.4f722a5f53',
'Used by commit-message, pull-request, and branch-name recipes that select Custom command. Use'
- )}
+ )}{' '}
{translate('auto.components.settings.CommitMessageAiPane.b8b6fd55b4', '{prompt}')}
{' '}
diff --git a/src/renderer/src/components/settings/GeneralEditorSettingsSection.tsx b/src/renderer/src/components/settings/GeneralEditorSettingsSection.tsx
index 9cccdf166ee..2a524600b07 100644
--- a/src/renderer/src/components/settings/GeneralEditorSettingsSection.tsx
+++ b/src/renderer/src/components/settings/GeneralEditorSettingsSection.tsx
@@ -170,7 +170,7 @@ export function GeneralEditorSettingsSection({
{translate(
'auto.components.settings.GeneralEditorSettingsSection.8112cd6dcf',
'How long Orca waits after your last edit before saving automatically. First launch defaults to'
- )}
+ )}{' '}
{DEFAULT_EDITOR_AUTO_SAVE_DELAY_MS}{' '}
{translate('auto.components.settings.GeneralEditorSettingsSection.fc5c5306ff', 'ms.')}
diff --git a/src/renderer/src/components/settings/GeneralUpdateSettingsSection.tsx b/src/renderer/src/components/settings/GeneralUpdateSettingsSection.tsx
index 51668b1ac12..da1984cca0e 100644
--- a/src/renderer/src/components/settings/GeneralUpdateSettingsSection.tsx
+++ b/src/renderer/src/components/settings/GeneralUpdateSettingsSection.tsx
@@ -161,7 +161,7 @@ export function GeneralUpdateSettingsSection(): React.JSX.Element {
{translate(
'auto.components.settings.GeneralUpdateSettingsSection.a6b37929dc',
'Version'
- )}
+ )}{' '}
{updateStatus.version}{' '}
{translate(
'auto.components.settings.GeneralUpdateSettingsSection.8311da27ba',
@@ -199,7 +199,7 @@ export function GeneralUpdateSettingsSection(): React.JSX.Element {
{translate(
'auto.components.settings.GeneralUpdateSettingsSection.a6b37929dc',
'Version'
- )}
+ )}{' '}
{updateStatus.version}{' '}
{translate(
'auto.components.settings.GeneralUpdateSettingsSection.d89806cc89',
diff --git a/src/renderer/src/components/settings/GitPane.tsx b/src/renderer/src/components/settings/GitPane.tsx
index 6d346fb1de6..bdfff4a6967 100644
--- a/src/renderer/src/components/settings/GitPane.tsx
+++ b/src/renderer/src/components/settings/GitPane.tsx
@@ -236,11 +236,14 @@ export function GitPane({
{translate(
'auto.components.settings.GitPane.976afc6b3e',
'When you create a workspace, Orca refreshes the remote base and safely fast-forwards your matching local branch, such as'
- )}
+ )}{' '}
{translate('auto.components.settings.GitPane.ffba483bae', 'main')}{' '}
- {translate('auto.components.settings.GitPane.5bf885be48', 'or')}
+ {translate('auto.components.settings.GitPane.5bf885be48', 'or')}{' '}
{translate('auto.components.settings.GitPane.3ae3de8898', 'master')}
- {translate('auto.components.settings.GitPane.db3a127eb1', '. This keeps commands like')}
+ {translate(
+ 'auto.components.settings.GitPane.db3a127eb1',
+ '. This keeps commands like'
+ )}{' '}
{translate('auto.components.settings.GitPane.d072a12995', 'git diff main...HEAD')}
{' '}
diff --git a/src/renderer/src/components/settings/ManageSessionKillDialog.tsx b/src/renderer/src/components/settings/ManageSessionKillDialog.tsx
index 56ddb9845ee..04c795f3748 100644
--- a/src/renderer/src/components/settings/ManageSessionKillDialog.tsx
+++ b/src/renderer/src/components/settings/ManageSessionKillDialog.tsx
@@ -66,7 +66,7 @@ export function ManageSessionKillDialog({
{translate(
'auto.components.settings.ManageSessionKillDialog.8401328fed',
'Force-quits'
- )}
+ )}{' '}
{session.sessionId}
{translate(
'auto.components.settings.ManageSessionKillDialog.ad9832aa26',
diff --git a/src/renderer/src/components/settings/NotificationSoundSection.tsx b/src/renderer/src/components/settings/NotificationSoundSection.tsx
index 0d0b92279e7..da1fe4e11cc 100644
--- a/src/renderer/src/components/settings/NotificationSoundSection.tsx
+++ b/src/renderer/src/components/settings/NotificationSoundSection.tsx
@@ -159,7 +159,7 @@ export function NotificationSoundSection({
className="truncate font-mono text-[11px] text-muted-foreground"
title={notificationSettings.customSoundPath}
>
- {translate('auto.components.settings.NotificationsPane.4aa5085cd7', 'Custom:')}
+ {translate('auto.components.settings.NotificationsPane.4aa5085cd7', 'Custom:')}{' '}
{notificationSettings.customSoundPath}
) : null}
diff --git a/src/renderer/src/components/settings/RepositoryHooksSection.tsx b/src/renderer/src/components/settings/RepositoryHooksSection.tsx
index 1ee7cfe19f8..bec7ba52a28 100644
--- a/src/renderer/src/components/settings/RepositoryHooksSection.tsx
+++ b/src/renderer/src/components/settings/RepositoryHooksSection.tsx
@@ -441,7 +441,7 @@ function ExampleTemplateCard({
return (
- {translate('auto.components.settings.RepositoryHooksSection.175daba180', 'Example')}
+ {translate('auto.components.settings.RepositoryHooksSection.175daba180', 'Example')}{' '}
{translate('auto.components.settings.RepositoryHooksSection.39da2ae12f', 'orca.yaml')}
{' '}
@@ -665,7 +665,7 @@ function ScriptEditor({
- {translate('auto.components.settings.RepositoryHooksSection.b113344b6a', 'Edit')}
+ {translate('auto.components.settings.RepositoryHooksSection.b113344b6a', 'Edit')}{' '}
{translate(
'auto.components.settings.RepositoryHooksSection.39da2ae12f',
@@ -1308,7 +1308,7 @@ export function RepositoryHooksSection({
{translate(
'auto.components.settings.RepositoryHooksSection.ac9038d2cc',
'When both'
- )}
+ )}{' '}
{translate(
'auto.components.settings.RepositoryHooksSection.39da2ae12f',
diff --git a/src/renderer/src/components/settings/RepositoryPane.tsx b/src/renderer/src/components/settings/RepositoryPane.tsx
index bb178d3c17f..a90c94e5ea8 100644
--- a/src/renderer/src/components/settings/RepositoryPane.tsx
+++ b/src/renderer/src/components/settings/RepositoryPane.tsx
@@ -226,7 +226,7 @@ export function RepositoryPane({
)}
- {translate('auto.components.settings.RepositoryPane.323debba71', 'Type:')}
+ {translate('auto.components.settings.RepositoryPane.323debba71', 'Type:')}{' '}
{getRepoKindLabel(repo)}
{isFolder ? (
diff --git a/src/renderer/src/components/settings/RepositorySourceControlAiHostedReviewDefaults.tsx b/src/renderer/src/components/settings/RepositorySourceControlAiHostedReviewDefaults.tsx
index 7d620ee7ace..07156b38388 100644
--- a/src/renderer/src/components/settings/RepositorySourceControlAiHostedReviewDefaults.tsx
+++ b/src/renderer/src/components/settings/RepositorySourceControlAiHostedReviewDefaults.tsx
@@ -82,7 +82,7 @@ export function RepositorySourceControlAiHostedReviewDefaults({
{translate(
'auto.components.settings.RepositorySourceControlAiHostedReviewDefaults.a68849a859',
'Global default is'
- )}
+ )}{' '}
{inherited}.
diff --git a/src/renderer/src/components/settings/RuntimeEnvironmentsPane.tsx b/src/renderer/src/components/settings/RuntimeEnvironmentsPane.tsx
index 116dc02c5be..af3e2be3ee0 100644
--- a/src/renderer/src/components/settings/RuntimeEnvironmentsPane.tsx
+++ b/src/renderer/src/components/settings/RuntimeEnvironmentsPane.tsx
@@ -813,7 +813,7 @@ export function RuntimeEnvironmentsPane({
className="h-8 min-w-0 font-mono text-xs"
/>
- {translate('auto.components.settings.RuntimeEnvironmentsPane.163671f7b5', 'Run')}
+ {translate('auto.components.settings.RuntimeEnvironmentsPane.163671f7b5', 'Run')}{' '}
{translate(
'auto.components.settings.RuntimeEnvironmentsPane.960e901ae4',
diff --git a/src/renderer/src/components/settings/SshPassphraseDialog.tsx b/src/renderer/src/components/settings/SshPassphraseDialog.tsx
index 7cfb4dbd0b8..56fd3c3d374 100644
--- a/src/renderer/src/components/settings/SshPassphraseDialog.tsx
+++ b/src/renderer/src/components/settings/SshPassphraseDialog.tsx
@@ -133,7 +133,7 @@ export function SshPassphraseDialog(): React.JSX.Element | null {
{translate(
'auto.components.settings.SshPassphraseDialog.dbf9b6f2d0',
'Enter the password for'
- )}
+ )}{' '}
{label}
>
) : (
@@ -141,7 +141,7 @@ export function SshPassphraseDialog(): React.JSX.Element | null {
{translate(
'auto.components.settings.SshPassphraseDialog.ce4fdf7914',
'Enter the passphrase for'
- )}
+ )}{' '}
{label}
>
)}
diff --git a/src/renderer/src/components/settings/WslCliRegistration.tsx b/src/renderer/src/components/settings/WslCliRegistration.tsx
index 9d23dbeca93..7d01d96d58b 100644
--- a/src/renderer/src/components/settings/WslCliRegistration.tsx
+++ b/src/renderer/src/components/settings/WslCliRegistration.tsx
@@ -217,7 +217,7 @@ export function WslCliRegistration({
{translate(
'auto.components.settings.WslCliRegistration.1dbb0377d9',
'Existing launcher target:'
- )}
+ )}{' '}
{status.currentTarget}
) : null}
diff --git a/src/renderer/src/components/sidebar/DeleteWorktreeWarningPanels.tsx b/src/renderer/src/components/sidebar/DeleteWorktreeWarningPanels.tsx
index 89b22f6c841..b143148249c 100644
--- a/src/renderer/src/components/sidebar/DeleteWorktreeWarningPanels.tsx
+++ b/src/renderer/src/components/sidebar/DeleteWorktreeWarningPanels.tsx
@@ -21,7 +21,7 @@ export function DeleteWorktreeWarningPanels({
{translate(
'auto.components.sidebar.DeleteWorktreeWarningPanels.e3be9eba15',
'This is the'
- )}
+ )}{' '}
{translate(
'auto.components.sidebar.DeleteWorktreeWarningPanels.c4f96a6e18',
@@ -32,7 +32,7 @@ export function DeleteWorktreeWarningPanels({
'auto.components.sidebar.DeleteWorktreeWarningPanels.026738155a',
'(the original clone directory).'
)}
- {mainWorktreeBlocker}
+ {mainWorktreeBlocker ? <> {mainWorktreeBlocker}> : null}
diff --git a/src/renderer/src/components/sidebar/SetupScriptPromptCardViews.tsx b/src/renderer/src/components/sidebar/SetupScriptPromptCardViews.tsx
index 45f2947d3ed..25a960bff8c 100644
--- a/src/renderer/src/components/sidebar/SetupScriptPromptCardViews.tsx
+++ b/src/renderer/src/components/sidebar/SetupScriptPromptCardViews.tsx
@@ -71,7 +71,7 @@ export function DetectedSetupPreview({
{translate(
'auto.components.sidebar.SetupScriptPromptCardViews.d02e6a42b1',
'Detected from'
- )}
+ )}{' '}
{provenance}
) : null}
@@ -157,7 +157,7 @@ export function SetupScriptPromptBody({
{translate(
'auto.components.sidebar.SetupScriptPromptCardViews.bb879db364',
'This repo ignores shared'
- )}
+ )}{' '}
{translate('auto.components.sidebar.SetupScriptPromptCardViews.8f6be51aa1', 'orca.yaml')}
{' '}
@@ -184,7 +184,7 @@ export function SetupScriptPromptBody({
{translate(
'auto.components.sidebar.SetupScriptPromptCardViews.b56d1322f7',
'Found a setup command in'
- )}
+ )}{' '}
{candidateSource}
{translate(
'auto.components.sidebar.SetupScriptPromptCardViews.8349e3fa4c',
diff --git a/src/renderer/src/components/stats/ShareUsageCard.tsx b/src/renderer/src/components/stats/ShareUsageCard.tsx
index cb6eb5c92bf..dcd2f673cb2 100644
--- a/src/renderer/src/components/stats/ShareUsageCard.tsx
+++ b/src/renderer/src/components/stats/ShareUsageCard.tsx
@@ -233,7 +233,7 @@ function ChartHeader(props: {
{props.sessions}{' '}
- {translate('auto.components.stats.ShareUsageCard.4a4c6c79a3', 'sessions ·')}
+ {translate('auto.components.stats.ShareUsageCard.4a4c6c79a3', 'sessions ·')}{' '}
{props.turnsOrEvents.count} {props.turnsOrEvents.label}
diff --git a/src/renderer/src/components/stats/UsageOverviewPane.tsx b/src/renderer/src/components/stats/UsageOverviewPane.tsx
index 1f2080c995d..03001c2bec9 100644
--- a/src/renderer/src/components/stats/UsageOverviewPane.tsx
+++ b/src/renderer/src/components/stats/UsageOverviewPane.tsx
@@ -253,7 +253,7 @@ export function UsageOverviewPane(): React.JSX.Element {
{overview.enabledProviderCount}{' '}
- {translate('auto.components.stats.UsageOverviewPane.ecb0cd8a4c', 'enabled -')}
+ {translate('auto.components.stats.UsageOverviewPane.ecb0cd8a4c', 'enabled -')}{' '}
{overview.dataProviderCount}{' '}
{translate('auto.components.stats.UsageOverviewPane.444585cb41', 'with data')}
diff --git a/src/renderer/src/lib/i18n-jsx-spacing-guard.test.ts b/src/renderer/src/lib/i18n-jsx-spacing-guard.test.ts
new file mode 100644
index 00000000000..f2dde24571e
--- /dev/null
+++ b/src/renderer/src/lib/i18n-jsx-spacing-guard.test.ts
@@ -0,0 +1,140 @@
+import { readFileSync } from 'node:fs'
+import path from 'node:path'
+import { describe, expect, it } from 'vitest'
+
+/**
+ * Guard against the i18n fragment glue-word class of bugs:
+ * `translate('…', 'word')}` immediately followed by `` / `{value}` without
+ * an explicit `{' '}` space. Newline indentation alone is not reliable.
+ */
+const ROOT = path.resolve(__dirname, '..')
+
+type GuardCase = {
+ file: string
+ /** English fallback that must be followed by `{' '}` before the next token. */
+ afterFallback: string
+ /** Human-readable description for assertion messages. */
+ label: string
+}
+
+const CASES: GuardCase[] = [
+ {
+ file: 'components/sidebar/SetupScriptPromptCardViews.tsx',
+ afterFallback: 'This repo ignores shared',
+ label: 'shared orca.yaml'
+ },
+ {
+ file: 'components/sidebar/SetupScriptPromptCardViews.tsx',
+ afterFallback: 'Detected from',
+ label: 'Detected from provenance'
+ },
+ {
+ file: 'components/sidebar/SetupScriptPromptCardViews.tsx',
+ afterFallback: 'Found a setup command in',
+ label: 'Found a setup command in source'
+ },
+ {
+ file: 'components/settings/RepositoryHooksSection.tsx',
+ afterFallback: 'Example',
+ label: 'Example orca.yaml template'
+ },
+ {
+ file: 'components/settings/RepositoryHooksSection.tsx',
+ afterFallback: 'Edit',
+ label: 'Edit orca.yaml'
+ },
+ {
+ file: 'components/settings/RepositoryHooksSection.tsx',
+ afterFallback: 'When both',
+ label: 'When both orca.yaml'
+ },
+ {
+ file: 'components/settings/GitPane.tsx',
+ afterFallback: 'or',
+ label: 'main or master'
+ },
+ {
+ file: 'components/settings/GitPane.tsx',
+ afterFallback: 'such as',
+ label: 'such as main'
+ },
+ {
+ file: 'components/settings/RuntimeEnvironmentsPane.tsx',
+ afterFallback: 'Run',
+ label: 'Run orca serve'
+ },
+ {
+ file: 'components/settings/AutoRenameBranchFromWorkSetting.tsx',
+ afterFallback: 'Use',
+ label: 'Use {basePrompt}'
+ },
+ {
+ file: 'components/settings/CommitMessageAiPane.tsx',
+ afterFallback: 'Use',
+ label: 'Use {prompt}'
+ },
+ {
+ file: 'components/editor/RichMarkdownDocLinkMenu.tsx',
+ afterFallback: 'Showing',
+ label: 'Showing N of M'
+ },
+ {
+ file: 'components/editor/RichMarkdownDocLinkMenu.tsx',
+ afterFallback: 'of',
+ label: 'of totalMatches'
+ },
+ {
+ file: 'components/contextual-tours/ContextualTourProgressDots.tsx',
+ afterFallback: 'of',
+ label: 'tour of total'
+ },
+ {
+ file: 'components/github/PRFilterSections.tsx',
+ afterFallback: 'Filter',
+ label: 'Filter pull requests'
+ },
+ {
+ file: 'components/editor/ConflictComponents.tsx',
+ afterFallback: 'Renamed from',
+ label: 'Renamed from path'
+ },
+ {
+ file: 'components/settings/SshPassphraseDialog.tsx',
+ afterFallback: 'Enter the password for',
+ label: 'password for host'
+ },
+ {
+ file: 'components/settings/ManageSessionKillDialog.tsx',
+ afterFallback: 'Force-quits',
+ label: 'Force-quits session id'
+ },
+ {
+ file: 'components/sidebar/DeleteWorktreeWarningPanels.tsx',
+ afterFallback: 'This is the',
+ label: 'This is the main worktree'
+ }
+]
+
+function hasExplicitSpaceAfterFallback(source: string, fallback: string): boolean {
+ // Match translate fallbacks that end with (or equal) the given phrase, then
+ // require an explicit {' '} after the closing )} so JSX whitespace is not
+ // left to indentation alone.
+ const escaped = fallback.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+ const pattern = new RegExp(
+ String.raw`translate\(\s*'[^']+',\s*(?:'[^']*${escaped}'|"[^"]*${escaped}")\s*(?:,\s*\{[^}]*\})?\s*\)\s*\}\s*\{\s*['"]\s['"]\s*\}`,
+ 'm'
+ )
+ return pattern.test(source)
+}
+
+describe('i18n JSX fragment spacing guard', () => {
+ for (const testCase of CASES) {
+ it(`keeps an explicit space after "${testCase.label}" in ${testCase.file}`, () => {
+ const source = readFileSync(path.join(ROOT, testCase.file), 'utf8')
+ expect(
+ hasExplicitSpaceAfterFallback(source, testCase.afterFallback),
+ `Expected {' '} immediately after translate fallback "${testCase.afterFallback}" in ${testCase.file}`
+ ).toBe(true)
+ })
+ }
+})