Skip to content

feat(app): i18n share-publish surfaces — wire t() across 7 components + 6 locales#372

Merged
graydawnc merged 1 commit into
mainfrom
feat/i18n-share-publish
Jun 8, 2026
Merged

feat(app): i18n share-publish surfaces — wire t() across 7 components + 6 locales#372
graydawnc merged 1 commit into
mainfrom
feat/i18n-share-publish

Conversation

@graydawnc

Copy link
Copy Markdown
Collaborator

What

Closes the largest single i18n parity gap in the renderer. Pre-commit, ~80 user-visible strings across the share-publish surfaces were hardcoded English — locales.test.ts couldn't catch them because the violation was the absence of keys in en.json, not key drift between locales.

7 components migrated to t():

  • share-editor/share-tabs/PublishTab.tsx — visibility radios, expiry select, PII warnings, error states, manage view (largest single file)
  • share-editor/share-tabs/ExportTab.tsx — footer hint + Download button; also drops the unsafe const tx = t as unknown as (k: string) => string cast
  • share-editor/ConnectCard.tsx — sign-in CTA + privacy hint
  • share-editor/UnpublishConfirmModal.tsx — destructive confirm copy
  • DeleteAccountConfirmModal.tsx — 24h grace explainer + button labels
  • SettingsAccount.tsx — handle claim, sign out, delete account state machine (36 keys)
  • SharesPage.tsx — Published-tab section + tab strip

112 new keys added to en.json under coherent namespaces:

Namespace Keys
shareEditor.publishTab 40
shareEditor.exportTab 4
shareEditor.connectCard 5
shareEditor.unpublishConfirm 6
settings.account 36
shares.publishedTab 18
shares.{tab_drafts, tab_published, tabs_aria} 3

Translated to all 6 non-English locales (de, fr, ja, ko, zh-CN, zh-TW) in the same commit per the project's strict 100%-parity rule.

Notable choices

  • VisibilityCard testid is now an explicit testId prop instead of being derived from title.toLowerCase().replace(/\s+/g, '-'). The derived form silently breaks every translated build, so e2e selectors couldn't depend on it.
  • PublishTab subcomponents take t via props rather than each calling useTranslation(). One call site at the top, no leaf-component coupling to react-i18next.
  • Pluralisation uses i18next _one/_other for counts (X credential-like values). Locales without grammatical plural (ja, ko, zh-CN, zh-TW) collapse to _other.
  • Brand terms stay English: "Spool", "Google", "spool.pro", "@handle".

Verification

  • pnpm --filter @spool/app exec vitest run src/renderer/i18n/locales.test.ts17/17 pass (100% key parity + plural shape + count interpolation rules)
  • pnpm --filter @spool/app exec tsc --noEmit → clean
  • pnpm --filter @spool/app test → 433 pass + 1 pre-existing macOS path-slug flake (sessionResume.test.ts:38, unrelated)
  • grep for hardcoded English in the 7 touched files → only matches inside code comments

Risk

Pure-additive surface change. No new IPC, no schema changes, no runtime gates touched. The destructive-action confirmation copy reads slightly differently in each language, but the underlying flow is unchanged.

Submitted by @graydawnc.

… + 6 locales

Closes the largest single i18n parity gap in the renderer: ~80 hardcoded
English strings across PublishTab, ExportTab, ConnectCard, the two
destructive confirm modals, SettingsAccount, and the Published tab on
SharesPage.

Adds 112 new keys to en.json grouped under coherent namespaces
(shareEditor.publishTab / .exportTab / .connectCard / .unpublishConfirm,
settings.account, shares.publishedTab) and translates each to the six
non-English locales (de, fr, ja, ko, zh-CN, zh-TW). Pluralised counts
use i18next _one/_other (collapsed to _other in the four no-plural
locales). Also drops the unsafe `tx = t as unknown as (k: string) =>
string` cast in ExportTab and propagates the `t` translator into the
PublishTab subcomponents instead of duplicating useTranslation() calls.

The VisibilityCard testid was derived from the (now translated) title;
switched to an explicit `testId` prop so e2e selectors stay stable.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@graydawnc
graydawnc added this pull request to the merge queue Jun 8, 2026
Merged via the queue into main with commit ee71281 Jun 8, 2026
6 checks passed
@graydawnc
graydawnc deleted the feat/i18n-share-publish branch June 8, 2026 09:37
github-merge-queue Bot pushed a commit that referenced this pull request Jun 10, 2026
The Share button, Publish/Export tab labels, and the popover/tablist
aria-labels were the last hardcoded English strings in the share-publish
surfaces after the #372 i18n pass. Route them through t() with new
shareEditor.shareMenu.* keys across all 7 locales.

Co-authored-by: Chen <99816898+donteatfriedrice@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant