From 425b76e9a79e27237fcc9c3abcf4d2c2fc830bdc Mon Sep 17 00:00:00 2001 From: ConnorYoh <40631091+ConnorYoh@users.noreply.github.com> Date: Tue, 30 Jun 2026 10:23:13 +0100 Subject: [PATCH] fix(portal/i18n): add inline default values to account-link + billing t() calls (#6842) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem The account-link / billing / Usage strings migrated to i18next in #6738 call `t("key")` with **no inline default**. When no i18next instance is initialized — which is the case in **Storybook** (the preview doesn't load the portal i18n config) — or whenever a key is missing, react-i18next renders the **raw key** (e.g. `billing.walletMeter.title`) instead of English. That's why the billing stories regressed to showing keys. ## Fix Add the English string as the `t()` default value, matching the **existing portal convention** (`AuthGate`, `Header`, `Sidebar`) and the editor: - plain → `t("key", "English")` - interpolation → `t("key", "English {{var}}", { var })` - plural → `t("key", "{{count}} …", { count })` Dynamic keys resolved via data fields carry a sibling `*Default` string passed as the default: - `LINK_INFO` badge labels → `labelDefault` (`t(info.labelKey, info.labelDefault)`) - `PdfsProcessedCard` segment legend → `labelDefault` / `descDefault` Defaults were sourced **verbatim from the merged `en-US/translation.toml`**, so the TOML stays the source of truth — the inline default only fills in when the catalogue isn't loaded or lacks the key. ## Scope All strings added in #6738: 5 account-link + 12 billing components + the Usage view (157 static call sites + the `LINK_INFO` / segment dynamic ones). No new keys; no copy changes. ## Verification - `tsc -p portal/tsconfig.json` → 0 - `eslint --max-warnings=0` (changed files) → 0 - `prettier --check` → clean - portal `vitest` → **62/62 pass** No behaviour change when i18n is initialized; Storybook and any missing-key fallback now render English. --- .../account-link/AccountLinkPanel.tsx | 39 ++++-- .../account-link/LinkAccountCard.tsx | 48 ++++++-- .../account-link/LinkAccountModal.tsx | 30 +++-- .../src/components/account-link/LinkGate.tsx | 13 +- .../account-link/LinkedInstancesTable.tsx | 38 +++--- .../components/billing/EnterpriseUpsell.tsx | 11 +- .../components/billing/FreePdfEditorsCard.tsx | 25 ++-- .../src/components/billing/FreePlanView.tsx | 32 +++-- .../src/components/billing/InvoicesList.tsx | 74 +++++++---- .../components/billing/LinkAccountPrompt.tsx | 9 +- .../components/billing/PaymentMethodCard.tsx | 40 +++--- .../components/billing/PdfsProcessedCard.tsx | 38 ++++-- .../src/components/billing/SpendLimitCard.tsx | 116 ++++++++++++------ .../components/billing/SpendThisMonthCard.tsx | 28 +++-- .../billing/StripeCheckoutModal.tsx | 31 +++-- .../components/billing/SubscribedPlanView.tsx | 32 +++-- .../src/components/billing/WalletMeter.tsx | 47 ++++--- frontend/portal/src/contexts/LinkContext.tsx | 15 ++- frontend/portal/src/views/Usage.tsx | 57 ++++++--- 19 files changed, 508 insertions(+), 215 deletions(-) diff --git a/frontend/portal/src/components/account-link/AccountLinkPanel.tsx b/frontend/portal/src/components/account-link/AccountLinkPanel.tsx index bccf2cfb74..eaf3c86be6 100644 --- a/frontend/portal/src/components/account-link/AccountLinkPanel.tsx +++ b/frontend/portal/src/components/account-link/AccountLinkPanel.tsx @@ -56,7 +56,12 @@ export function AccountLinkPanel() {
{t("accountLink.panel.sub")}
++ {t( + "accountLink.panel.sub", + "Link this self-hosted org to its Stirling account so unattended processing bills against your org wallet.", + )} +
- {t("accountLink.panel.instancesSub")} + {t( + "accountLink.panel.instancesSub", + "Every self-hosted instance registered to this org. Revoke a credential to immediately cut off its unattended access.", + )}
VITE_SAAS_SUPABASE_URL{" "}
- {t("accountLink.card.loginNotConfigured.after")}
+ {t(
+ "accountLink.card.loginNotConfigured.after",
+ "to enable account linking against the hosted Stirling account. In dev you can simulate sign-in from the link dialog.",
+ )}
VITE_SAAS_SUPABASE_URL{" "}
- {t("accountLink.modal.loginNotConfigured.and")}{" "}
+ {t("accountLink.modal.loginNotConfigured.and", "and")}{" "}
VITE_SAAS_SUPABASE_ANON_KEY{" "}
- {t("accountLink.modal.loginNotConfigured.after")}
+ {t(
+ "accountLink.modal.loginNotConfigured.after",
+ "to enable in-app linking against the hosted Stirling account.",
+ )}
{i.deviceId}