From bebd56238b37f2e1135d0d781892354d8a54eddb Mon Sep 17 00:00:00 2001 From: Giancarlo Buomprisco Date: Sun, 18 Jan 2026 10:39:40 +0100 Subject: [PATCH] Fix: use pluralization correctly (#445) * feat(billing): add i18n pluralization support for billing unit names Use i18next plural feature to properly translate and pluralize unit names in billing plans (e.g., "member" vs "members"). This ensures correct grammar for phrases like "Up to 4 members included in the plan" and enables proper translation of unit names in non-English locales. * fix(billing): handle 'unlimited' tier values in pluralization Add getSafeCount helper to safely convert tier values to numbers, preventing NaN when 'unlimited' values are passed to pluralization. Falls back to plural form for 'unlimited' or invalid values. --------- Co-authored-by: Claude --- apps/web/public/locales/en/billing.json | 4 ++ .../src/components/line-item-details.tsx | 42 ++++++++++++++----- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/apps/web/public/locales/en/billing.json b/apps/web/public/locales/en/billing.json index fab6e2361..8438b5319 100644 --- a/apps/web/public/locales/en/billing.json +++ b/apps/web/public/locales/en/billing.json @@ -1,4 +1,8 @@ { + "units": { + "member_one": "member", + "member_other": "members" + }, "subscriptionTabSubheading": "Manage your Subscription and Billing", "planCardTitle": "Your Plan", "planCardDescription": "Below are the details of your current plan. You can change your plan or cancel your subscription at any time.", diff --git a/packages/billing/gateway/src/components/line-item-details.tsx b/packages/billing/gateway/src/components/line-item-details.tsx index 2dd5b7ab9..64532041c 100644 --- a/packages/billing/gateway/src/components/line-item-details.tsx +++ b/packages/billing/gateway/src/components/line-item-details.tsx @@ -19,7 +19,8 @@ export function LineItemDetails( selectedInterval?: string | undefined; }>, ) { - const locale = useTranslation().i18n.language; + const { t, i18n } = useTranslation(); + const locale = i18n.language; const currencyCode = props?.currency.toLowerCase(); return ( @@ -115,7 +116,7 @@ export function LineItemDetails( @@ -171,7 +172,7 @@ export function LineItemDetails( @@ -223,8 +224,17 @@ function Tiers({ currency: string; item: z.infer; }) { - const unit = item.unit; - const locale = useTranslation().i18n.language; + const unitKey = `billing:units.${item.unit}`; + const { t, i18n } = useTranslation(); + const locale = i18n.language; + + // Helper to safely convert tier values to numbers for pluralization + // Falls back to plural form (2) for 'unlimited' values + const getSafeCount = (value: number | 'unlimited' | string): number => { + if (value === 'unlimited') return 2; + const num = typeof value === 'number' ? value : Number(value); + return Number.isNaN(num) ? 2 : num; + }; const tiers = item.tiers?.map((tier, index) => { const tiersLength = item.tiers?.length ?? 0; @@ -257,8 +267,10 @@ function Tiers({ @@ -268,7 +280,7 @@ function Tiers({ @@ -277,7 +289,13 @@ function Tiers({ - + {' '} @@ -291,7 +309,11 @@ function Tiers({