fix(ui): restore missing spaces in i18n JSX fragment copy (#9513)

This commit is contained in:
Neil
2026-07-19 21:24:24 -07:00
committed by GitHub
parent 7df56adaf1
commit 0d97653e39
46 changed files with 212 additions and 77 deletions
@@ -4935,13 +4935,12 @@ function ChecksTab({
</span>
{startedAt && (
<span>
{translate('auto.components.GitHubItemDialog.4812814bc8', 'Started')}
{startedAt}
{translate('auto.components.GitHubItemDialog.4812814bc8', 'Started')} {startedAt}
</span>
)}
{completedAt && (
<span>
{translate('auto.components.GitHubItemDialog.0f478f5efa', 'Completed')}
{translate('auto.components.GitHubItemDialog.0f478f5efa', 'Completed')}{' '}
{completedAt}
</span>
)}
@@ -1034,7 +1034,7 @@ export default function GitLabItemDialog({
<StateBadge state={item.state} />
{item.author ? (
<span>
{translate('auto.components.GitLabItemDialog.9bfb4a24d7', 'by')}
{translate('auto.components.GitLabItemDialog.9bfb4a24d7', 'by')}{' '}
{item.author}
</span>
) : null}
@@ -1521,7 +1521,7 @@ export default function GitLabItemDialog({
{translate(
'auto.components.GitLabItemDialog.a7eb4f4916',
'from'
)}
)}{' '}
{file.oldPath}
</div>
) : null}
@@ -5030,13 +5030,12 @@ function ChecksTab({
</span>
{startedAt && (
<span>
{translate('auto.components.PullRequestPage.76551b1161', 'Started')}
{startedAt}
{translate('auto.components.PullRequestPage.76551b1161', 'Started')} {startedAt}
</span>
)}
{completedAt && (
<span>
{translate('auto.components.PullRequestPage.000f90afcf', 'Completed')}
{translate('auto.components.PullRequestPage.000f90afcf', 'Completed')}{' '}
{completedAt}
</span>
)}
+1 -1
View File
@@ -9323,7 +9323,7 @@ export default function TaskPage(): React.JSX.Element {
// Why: per-repo partial-failure signal — distinct from a hard
// IPC reject (tasksError). The two are mutually exclusive.
<div className="border-b border-border/50 bg-amber-500/10 px-4 py-3 text-sm text-amber-700 dark:text-amber-200">
{failedCount} {translate('auto.components.TaskPage.7762f4b03a', 'of')}
{failedCount} {translate('auto.components.TaskPage.7762f4b03a', 'of')}{' '}
{selectedRepos.length}{' '}
{translate('auto.components.TaskPage.d1766fd62d', 'projects failed to load')}
</div>
+1 -2
View File
@@ -887,8 +887,7 @@ function DownloadingContent({
<div className="flex items-start justify-between gap-2">
{release ? (
<h3 className="text-sm font-semibold">
{translate('auto.components.UpdateCard.f58b5c57a6', 'New:')}
{release.title}
{translate('auto.components.UpdateCard.f58b5c57a6', 'New:')} {release.title}
</h3>
) : (
<h3 className="text-sm font-semibold">
@@ -2877,7 +2877,7 @@ export default function AutomationsPage(): React.JSX.Element {
)}
</TabsTrigger>
<TabsTrigger value="runs" disabled={!selected}>
{translate('auto.components.automations.AutomationsPage.0e110a3469', 'Runs')}
{translate('auto.components.automations.AutomationsPage.0e110a3469', 'Runs')}{' '}
<span className="text-xs text-muted-foreground">{selectedRuns.length}</span>
</TabsTrigger>
</TabsList>
@@ -288,7 +288,7 @@ export function ExternalAutomationRunTable({
<FileText className="size-3.5" />
<span>
{pageStart}-{pageEnd}{' '}
{translate('auto.components.automations.ExternalAutomationRunTable.7475c0ce96', 'of')}
{translate('auto.components.automations.ExternalAutomationRunTable.7475c0ce96', 'of')}{' '}
{totalCount}
</span>
</div>
@@ -46,7 +46,7 @@ export function ContextualTourProgressDots({
</span>
<span className="whitespace-nowrap text-[11px] font-medium leading-none text-muted-foreground">
{current}{' '}
{translate('auto.components.contextual.tours.ContextualTourProgressDots.7734cb8ad3', 'of')}
{translate('auto.components.contextual.tours.ContextualTourProgressDots.7734cb8ad3', 'of')}{' '}
{total}
</span>
</div>
@@ -2022,7 +2022,7 @@ export default function CombinedDiffViewer({
{translate('auto.components.editor.CombinedDiffViewer.948a5fd6c8', 'Clear Notes')}
</DialogTitle>
<DialogDescription className="text-xs">
{translate('auto.components.editor.CombinedDiffViewer.84898c548d', 'Clear')}
{translate('auto.components.editor.CombinedDiffViewer.84898c548d', 'Clear')}{' '}
{diffCommentCount}{' '}
{diffCommentCount === 1
? translate('auto.components.editor.CombinedDiffViewer.8ab3248fd8', 'note')
@@ -101,7 +101,7 @@ export function ConflictBanner({
)}
<span className="min-w-0 truncate font-medium text-foreground">
{label}{' '}
{translate('auto.components.editor.ConflictComponents.55d61a0ccd', 'conflict ·')}
{translate('auto.components.editor.ConflictComponents.55d61a0ccd', 'conflict ·')}{' '}
{CONFLICT_KIND_LABELS[conflict.conflictKind]}
</span>
{conflictNavigation && conflictNavigation.total > 0 && (
@@ -171,7 +171,7 @@ export function ConflictBanner({
)}
{entry?.oldPath && (
<div className="mt-1 text-muted-foreground">
{translate('auto.components.editor.ConflictComponents.d5edd81755', 'Renamed from')}
{translate('auto.components.editor.ConflictComponents.d5edd81755', 'Renamed from')}{' '}
{entry.oldPath}
</div>
)}
@@ -334,7 +334,7 @@ export function ConflictReviewPanel({
{translate(
'auto.components.editor.ConflictComponents.a1ce36f77d',
'Snapshot captured at'
)}
)}{' '}
{snapshotTime}.
</span>
</div>
@@ -899,7 +899,7 @@ export default function IpynbViewer({
{translate('auto.components.editor.IpynbViewer.329764e9fc', 'BETA')}
</span>
<span className="font-mono">
{translate('auto.components.editor.IpynbViewer.8c3b21369a', 'nbformat')}
{translate('auto.components.editor.IpynbViewer.8c3b21369a', 'nbformat')}{' '}
{notebook.nbformat}
</span>
</div>
@@ -103,8 +103,7 @@ export default function MermaidBlock({
return (
<div className="mermaid-block">
<div className="mermaid-error">
{translate('auto.components.editor.MermaidBlock.dcc132e691', 'Diagram error:')}
{error}
{translate('auto.components.editor.MermaidBlock.dcc132e691', 'Diagram error:')} {error}
</div>
<pre>
<code>{content}</code>
@@ -68,9 +68,9 @@ export function RichMarkdownDocLinkMenu({
)}
{overflow ? (
<div className="rich-markdown-doc-link-footer">
{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}
</div>
) : null}
@@ -381,7 +381,7 @@ export function ReviewNotesAnimatedVisual(props: { reducedMotion: boolean }): JS
</button>
<div className="ravs-popover" data-note-popover>
<div className="ravs-pop-label">
{translate('auto.components.feature.wall.ReviewNotesAnimatedVisual.a7a89d8f94', 'Line')}
{translate('auto.components.feature.wall.ReviewNotesAnimatedVisual.a7a89d8f94', 'Line')}{' '}
<span data-pop-line>?</span>
</div>
<div className="ravs-pop-input" data-pop-input />
@@ -272,7 +272,7 @@ export function ReviewPRViewAnimatedVisual(props: { reducedMotion: boolean }): J
{translate(
'auto.components.feature.wall.ReviewPRViewAnimatedVisual.6f4c2d7cb7',
'Add a coverage case for'
)}
)}{' '}
<code>
{translate(
'auto.components.feature.wall.ReviewPRViewAnimatedVisual.c2062da7ec',
@@ -303,7 +303,7 @@ export function ReviewShipAnimatedVisual(props: { reducedMotion: boolean }): JSX
{translate(
'auto.components.feature.wall.ReviewShipAnimatedVisual.e725000cd7',
'Changes'
)}
)}{' '}
<span className="ravs-sc-changes-count">{SHIP_FILES.length}</span>
</span>
<span className="ravs-sc-view-all">
@@ -85,7 +85,7 @@ export function ReviewDiffRows(): JSX.Element {
{translate(
'auto.components.feature.wall.review.notes.diff.rows.f621c734f8',
'Note · line'
)}
)}{' '}
<span data-slot-line>?</span>
</div>
<div className="ravs-note-body" data-slot-body />
@@ -208,8 +208,7 @@ export function SectionMenu({
return (
<div className="py-1 text-xs">
<div className="px-3 py-1.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground">
{translate('auto.components.github.PRFilterSections.8177eda37e', 'Filter')}
{subject}
{translate('auto.components.github.PRFilterSections.8177eda37e', 'Filter')} {subject}
</div>
{rows.map((row) => (
<button
@@ -154,12 +154,12 @@ function GitHubRateLimitRows({
)}
>
{v.remaining}{' '}
{translate('auto.components.github.github.rate.limit.display.f42790d150', 'of')}
{translate('auto.components.github.github.rate.limit.display.f42790d150', 'of')}{' '}
{v.limit}{' '}
{translate(
'auto.components.github.github.rate.limit.display.6da1858354',
'left · resets in'
)}
)}{' '}
{formatGitHubRateLimitReset(v.resetAt)}
</span>
</div>
@@ -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',
@@ -54,8 +54,7 @@ export function LinearPriorityIcon({
>
<span aria-hidden="true">!</span>
<span className="sr-only">
{translate('auto.components.linear.priority.icon.c43d3e065b', 'Priority:')}
{label}
{translate('auto.components.linear.priority.icon.c43d3e065b', 'Priority:')} {label}
</span>
</span>
)
@@ -72,8 +71,7 @@ export function LinearPriorityIcon({
className="size-3 rounded-full border border-muted-foreground/55"
/>
<span className="sr-only">
{translate('auto.components.linear.priority.icon.c43d3e065b', 'Priority:')}
{label}
{translate('auto.components.linear.priority.icon.c43d3e065b', 'Priority:')} {label}
</span>
</span>
)
@@ -110,8 +108,7 @@ export function LinearPriorityIcon({
})}
</svg>
<span className="sr-only">
{translate('auto.components.linear.priority.icon.c43d3e065b', 'Priority:')}
{label}
{translate('auto.components.linear.priority.icon.c43d3e065b', 'Priority:')} {label}
</span>
</span>
)
@@ -29,7 +29,7 @@ export function FileExplorerTreeStatus({
{translate(
'auto.components.right.sidebar.FileExplorerTreeStatus.c76693e456',
'Could not load files for this workspace:'
)}
)}{' '}
{error}
</div>
)
@@ -378,7 +378,7 @@ export function SourceControlAgentActionDialogForm({
{translate(
'auto.components.right.sidebar.SourceControlAgentActionDialogForm.1bc0bdbb5e',
'Launch:'
)}
)}{' '}
{deliveryPlan.commandLabel}
</div>
<div className="text-[11px]">{deliveryPlan.caveat}</div>
@@ -735,7 +735,7 @@ function CheckRunDetails({
{translate(
'auto.components.right.sidebar.checks.panel.content.fd46a70f1a',
'Started'
)}
)}{' '}
{startedAt}
</span>
)}
@@ -744,7 +744,7 @@ function CheckRunDetails({
{translate(
'auto.components.right.sidebar.checks.panel.content.00e1c1658a',
'Completed'
)}
)}{' '}
{completedAt}
</span>
)}
@@ -1501,14 +1501,14 @@ export function AccountsPane({
{translate(
'auto.components.settings.AccountsPane.0023cc336e',
'Paste either the raw token value (e.g.'
)}
)}{' '}
<code className="text-xs">
{translate('auto.components.settings.AccountsPane.922b51e02d', 'Fe26.2**…')}
</code>
{translate(
'auto.components.settings.AccountsPane.338820326a',
') or the full cookie header (e.g.'
)}
)}{' '}
<code className="text-xs">
{translate('auto.components.settings.AccountsPane.8951c5309f', 'auth=Fe26.2**…')}
</code>
@@ -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.'
)}
)}{' '}
<code>
{translate(
'auto.components.settings.AutoRenameBranchFromWorkSetting.1626524572',
@@ -223,7 +223,7 @@ export function AutoRenameBranchFromWorkSetting({
{translate(
'auto.components.settings.AutoRenameBranchFromWorkSetting.9241b59bf5',
'Use'
)}
)}{' '}
<code className="font-mono">
{translate(
'auto.components.settings.AutoRenameBranchFromWorkSetting.c71770c455',
@@ -261,7 +261,7 @@ export function AutoRenameBranchFromWorkSetting({
{translate(
'auto.components.settings.AutoRenameBranchFromWorkSetting.56580dcf60',
'. You can also reference'
)}
)}{' '}
<code className="font-mono">
{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'
)}
)}{' '}
<code className="font-mono">
{translate(
'auto.components.settings.AutoRenameBranchFromWorkSetting.800edb1e54',
@@ -195,14 +195,14 @@ export function BaseRefPicker({
{translate(
'auto.components.settings.BaseRefPicker.a5c16712c1',
'Multiple remotes detected. Type a remote name (e.g.'
)}
)}{' '}
<code>
{translate('auto.components.settings.BaseRefPicker.915ad97875', 'upstream')}
</code>
{translate(
'auto.components.settings.BaseRefPicker.80f7c82303',
') or a full ref (e.g.'
)}
)}{' '}
<code>
{translate('auto.components.settings.BaseRefPicker.b468f46726', 'upstream/main')}
</code>
@@ -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'
)}
)}{' '}
<strong>···</strong>{' '}
{translate('auto.components.settings.BrowserPane.e4aaf8051b', 'toolbar menu.')}
</p>
@@ -317,7 +317,7 @@ export function CliSection({
{translate(
'auto.components.settings.CliSection.b0c310ab46',
'Existing launcher target:'
)}
)}{' '}
<code>{status.currentTarget}</code>
</p>
) : null}
@@ -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'
)}
)}{' '}
<code className="font-mono">
{translate('auto.components.settings.CommitMessageAiPane.b8b6fd55b4', '{prompt}')}
</code>{' '}
@@ -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.')}
</p>
@@ -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',
@@ -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'
)}
)}{' '}
<code>{translate('auto.components.settings.GitPane.ffba483bae', 'main')}</code>{' '}
{translate('auto.components.settings.GitPane.5bf885be48', 'or')}
{translate('auto.components.settings.GitPane.5bf885be48', 'or')}{' '}
<code>{translate('auto.components.settings.GitPane.3ae3de8898', 'master')}</code>
{translate('auto.components.settings.GitPane.db3a127eb1', '. This keeps commands like')}
{translate(
'auto.components.settings.GitPane.db3a127eb1',
'. This keeps commands like'
)}{' '}
<code>
{translate('auto.components.settings.GitPane.d072a12995', 'git diff main...HEAD')}
</code>{' '}
@@ -66,7 +66,7 @@ export function ManageSessionKillDialog({
{translate(
'auto.components.settings.ManageSessionKillDialog.8401328fed',
'Force-quits'
)}
)}{' '}
<span className="font-medium text-foreground">{session.sessionId}</span>
{translate(
'auto.components.settings.ManageSessionKillDialog.ad9832aa26',
@@ -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}
</p>
) : null}
@@ -441,7 +441,7 @@ function ExampleTemplateCard({
return (
<div className="space-y-2">
<p className="text-[10px] tracking-[0.18em] text-muted-foreground">
{translate('auto.components.settings.RepositoryHooksSection.175daba180', 'Example')}
{translate('auto.components.settings.RepositoryHooksSection.175daba180', 'Example')}{' '}
<code className="rounded bg-muted px-1 py-0.5">
{translate('auto.components.settings.RepositoryHooksSection.39da2ae12f', 'orca.yaml')}
</code>{' '}
@@ -665,7 +665,7 @@ function ScriptEditor({
</span>
</span>
<span className="text-[11px] text-muted-foreground">
{translate('auto.components.settings.RepositoryHooksSection.b113344b6a', 'Edit')}
{translate('auto.components.settings.RepositoryHooksSection.b113344b6a', 'Edit')}{' '}
<code className="rounded bg-muted px-1 py-0.5">
{translate(
'auto.components.settings.RepositoryHooksSection.39da2ae12f',
@@ -1308,7 +1308,7 @@ export function RepositoryHooksSection({
{translate(
'auto.components.settings.RepositoryHooksSection.ac9038d2cc',
'When both'
)}
)}{' '}
<code className="rounded bg-muted px-1 py-0.5">
{translate(
'auto.components.settings.RepositoryHooksSection.39da2ae12f',
@@ -226,7 +226,7 @@ export function RepositoryPane({
)}
</p>
<p className="text-xs text-muted-foreground">
{translate('auto.components.settings.RepositoryPane.323debba71', 'Type:')}
{translate('auto.components.settings.RepositoryPane.323debba71', 'Type:')}{' '}
<span className="text-foreground">{getRepoKindLabel(repo)}</span>
</p>
{isFolder ? (
@@ -82,7 +82,7 @@ export function RepositorySourceControlAiHostedReviewDefaults({
{translate(
'auto.components.settings.RepositorySourceControlAiHostedReviewDefaults.a68849a859',
'Global default is'
)}
)}{' '}
{inherited}.
</span>
</span>
@@ -813,7 +813,7 @@ export function RuntimeEnvironmentsPane({
className="h-8 min-w-0 font-mono text-xs"
/>
<p id="runtime-server-pairing-code-help" className="text-xs text-muted-foreground">
{translate('auto.components.settings.RuntimeEnvironmentsPane.163671f7b5', 'Run')}
{translate('auto.components.settings.RuntimeEnvironmentsPane.163671f7b5', 'Run')}{' '}
<span className="font-mono">
{translate(
'auto.components.settings.RuntimeEnvironmentsPane.960e901ae4',
@@ -133,7 +133,7 @@ export function SshPassphraseDialog(): React.JSX.Element | null {
{translate(
'auto.components.settings.SshPassphraseDialog.dbf9b6f2d0',
'Enter the password for'
)}
)}{' '}
<span className="font-medium">{label}</span>
</>
) : (
@@ -141,7 +141,7 @@ export function SshPassphraseDialog(): React.JSX.Element | null {
{translate(
'auto.components.settings.SshPassphraseDialog.ce4fdf7914',
'Enter the passphrase for'
)}
)}{' '}
<span className="font-medium">{label}</span>
</>
)}
@@ -217,7 +217,7 @@ export function WslCliRegistration({
{translate(
'auto.components.settings.WslCliRegistration.1dbb0377d9',
'Existing launcher target:'
)}
)}{' '}
<code>{status.currentTarget}</code>
</p>
) : null}
@@ -21,7 +21,7 @@ export function DeleteWorktreeWarningPanels({
{translate(
'auto.components.sidebar.DeleteWorktreeWarningPanels.e3be9eba15',
'This is the'
)}
)}{' '}
<span className="font-semibold text-foreground">
{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}
</div>
</div>
</div>
@@ -71,7 +71,7 @@ export function DetectedSetupPreview({
{translate(
'auto.components.sidebar.SetupScriptPromptCardViews.d02e6a42b1',
'Detected from'
)}
)}{' '}
<code className="rounded bg-muted px-1 py-0.5">{provenance}</code>
</p>
) : null}
@@ -157,7 +157,7 @@ export function SetupScriptPromptBody({
{translate(
'auto.components.sidebar.SetupScriptPromptCardViews.bb879db364',
'This repo ignores shared'
)}
)}{' '}
<code>
{translate('auto.components.sidebar.SetupScriptPromptCardViews.8f6be51aa1', 'orca.yaml')}
</code>{' '}
@@ -184,7 +184,7 @@ export function SetupScriptPromptBody({
{translate(
'auto.components.sidebar.SetupScriptPromptCardViews.b56d1322f7',
'Found a setup command in'
)}
)}{' '}
<span className="break-words">{candidateSource}</span>
{translate(
'auto.components.sidebar.SetupScriptPromptCardViews.8349e3fa4c',
@@ -233,7 +233,7 @@ function ChartHeader(props: {
<div style={{ display: 'table-cell', verticalAlign: 'bottom', textAlign: 'right' }}>
<span style={{ fontSize: 10, color: '#444' }}>
{props.sessions}{' '}
{translate('auto.components.stats.ShareUsageCard.4a4c6c79a3', 'sessions ·')}
{translate('auto.components.stats.ShareUsageCard.4a4c6c79a3', 'sessions ·')}{' '}
{props.turnsOrEvents.count} {props.turnsOrEvents.label}
</span>
</div>
@@ -253,7 +253,7 @@ export function UsageOverviewPane(): React.JSX.Element {
</h4>
<p className="text-xs text-muted-foreground">
{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')}
</p>
@@ -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 `<code>` / `{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)
})
}
})