feat(localizations,ui): Render monetary amounts according to locale#8918
feat(localizations,ui): Render monetary amounts according to locale#8918dstaley wants to merge 6 commits into
Conversation
🦋 Changeset detectedLatest commit: 9b5b8e0 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository YAML (base), Repository UI (inherited) Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (28)
💤 Files with no reviewable changes (19)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (8)
📝 WalkthroughWalkthroughIntroduces ChangesLocale-aware monetary formatting
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
Comment |
@clerk/astro
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/eslint-plugin
@clerk/expo
@clerk/expo-passkeys
@clerk/express
@clerk/fastify
@clerk/hono
@clerk/localizations
@clerk/nextjs
@clerk/nuxt
@clerk/react
@clerk/react-router
@clerk/shared
@clerk/tanstack-react-start
@clerk/testing
@clerk/ui
@clerk/upgrade
@clerk/vue
commit: |
API Changes Report
Summary
@clerk/sharedCurrent version: 4.19.0 Subpath
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
packages/ui/src/localization/useCurrencyFormatter.ts (1)
56-61: ⚡ Quick winAdd an explicit return type to the exported hook.
useCurrencyFormatteris exported, so relying on inference makes this API contract easier to drift.Suggested change
+type CurrencyFormatter = (amount: BillingMoneyAmount, options?: FormatAmountOptions) => string; + -export function useCurrencyFormatter(locale: string) { +export function useCurrencyFormatter(locale: string): CurrencyFormatter { return useCallback( (amount: BillingMoneyAmount, options?: FormatAmountOptions) => formatAmount(locale, amount, options), [locale], ); }As per coding guidelines, “Always define explicit return types for functions, especially public APIs.” Based on learnings, exported TS functions in this repository should keep explicit return annotations.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ui/src/localization/useCurrencyFormatter.ts` around lines 56 - 61, The exported `useCurrencyFormatter` hook function is missing an explicit return type annotation, which makes the API contract unclear and susceptible to drift. Add a return type annotation after the closing parenthesis of the function parameters in `useCurrencyFormatter`, specifying the type returned by the `useCallback` hook (which is a memoized callback function that takes a BillingMoneyAmount and optional FormatAmountOptions and returns the result type of the formatAmount function).Sources: Coding guidelines, Learnings
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/ui/src/components/PaymentAttempts/PaymentAttemptPage.tsx`:
- Around line 284-285: The hard-coded `- ` prefix used for discounts/credits in
LineItems.Description components (at lines 284, 292, and 300 in
PaymentAttemptPage.tsx) does not respect locale-specific negative currency
formatting rules. Instead of manually prefixing with `- `, pass a negated
monetary value directly to the `$` currency formatting function. For each
occurrence where you have a pattern like
`${$(paymentAttempt.totals.discounts.proration.amount)}`, remove the hard-coded
`- ` prefix and negate the amount value before passing it to the `$` function so
it applies proper locale-native formatting for negative currencies.
In `@packages/ui/src/components/SubscriptionDetails/index.tsx`:
- Around line 355-357: The prefix prop is redundant because the text prop
already contains a complete currency-formatted string returned by the
$(subscription.nextPayment.amount) function. Remove the prefix prop that
references subscription.nextPayment.amount.currency from the component, keeping
only the text prop with the $(subscription.nextPayment.amount) value to prevent
duplicate currency labeling in the UI.
In `@packages/ui/src/localization/__tests__/useCurrencyFormatter.test.ts`:
- Line 1: The try/catch fallback behavior in the formatAmount function lacks
test coverage. Add test cases to the useCurrencyFormatter.test.ts file that
specifically verify the fallback path is executed when the primary formatter
fails, and confirm that the fallback formatter produces the expected output.
Include test scenarios that simulate formatting errors or edge cases that would
trigger the catch block to ensure both the error handling and the fallback
behavior are properly validated.
---
Nitpick comments:
In `@packages/ui/src/localization/useCurrencyFormatter.ts`:
- Around line 56-61: The exported `useCurrencyFormatter` hook function is
missing an explicit return type annotation, which makes the API contract unclear
and susceptible to drift. Add a return type annotation after the closing
parenthesis of the function parameters in `useCurrencyFormatter`, specifying the
type returned by the `useCallback` hook (which is a memoized callback function
that takes a BillingMoneyAmount and optional FormatAmountOptions and returns the
result type of the formatAmount function).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Repository UI (inherited)
Review profile: CHILL
Plan: Pro
Run ID: 9874539e-a8de-4688-af0a-ed30128dd20e
📒 Files selected for processing (43)
.changeset/fair-currency-hugs.mdpackages/localizations/src/bn-IN.tspackages/localizations/src/ca-ES.tspackages/localizations/src/cs-CZ.tspackages/localizations/src/de-DE.tspackages/localizations/src/en-US.tspackages/localizations/src/es-ES.tspackages/localizations/src/fa-IR.tspackages/localizations/src/fr-FR.tspackages/localizations/src/hi-IN.tspackages/localizations/src/hr-HR.tspackages/localizations/src/hu-HU.tspackages/localizations/src/is-IS.tspackages/localizations/src/it-IT.tspackages/localizations/src/ja-JP.tspackages/localizations/src/ko-KR.tspackages/localizations/src/ms-MY.tspackages/localizations/src/nb-NO.tspackages/localizations/src/pt-BR.tspackages/localizations/src/pt-PT.tspackages/localizations/src/ro-RO.tspackages/localizations/src/ta-IN.tspackages/localizations/src/te-IN.tspackages/localizations/src/th-TH.tspackages/localizations/src/vi-VN.tspackages/localizations/src/zh-TW.tspackages/shared/src/types/localization.tspackages/ui/src/components/Checkout/CheckoutComplete.tsxpackages/ui/src/components/Checkout/CheckoutForm.tsxpackages/ui/src/components/PaymentAttempts/PaymentAttemptPage.tsxpackages/ui/src/components/PaymentAttempts/PaymentAttemptsList.tsxpackages/ui/src/components/Plans/PlanDetails.tsxpackages/ui/src/components/PricingTable/PricingTableDefault.tsxpackages/ui/src/components/PricingTable/PricingTableMatrix.tsxpackages/ui/src/components/Statements/StatementPage.tsxpackages/ui/src/components/Statements/StatementsList.tsxpackages/ui/src/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsxpackages/ui/src/components/SubscriptionDetails/index.tsxpackages/ui/src/components/Subscriptions/SubscriptionsList.tsxpackages/ui/src/contexts/components/Plans.tsxpackages/ui/src/localization/__tests__/useCurrencyFormatter.test.tspackages/ui/src/localization/makeLocalizable.tsxpackages/ui/src/localization/useCurrencyFormatter.ts
💤 Files with no reviewable changes (1)
- packages/ui/src/contexts/components/Plans.tsx
| <LineItems.Description text={`- ${$(paymentAttempt.totals.discounts.proration.amount)}`} /> | ||
| </LineItems.Group> |
There was a problem hiding this comment.
Use locale-native negative currency formatting for credits/discounts.
At Line 284, Line 292, and Line 300, the hard-coded - prefix can produce incorrect sign placement/spacing for some locales. Prefer formatting a negative monetary value directly through $.
💡 Suggested fix
- <LineItems.Description text={`- ${$(paymentAttempt.totals.discounts.proration.amount)}`} />
+ <LineItems.Description
+ text={$({
+ ...paymentAttempt.totals.discounts.proration.amount,
+ amount: -paymentAttempt.totals.discounts.proration.amount.amount,
+ })}
+ />
@@
- <LineItems.Description text={`- ${$(subscriptionItem.credits.proration.amount)}`} />
+ <LineItems.Description
+ text={$({
+ ...subscriptionItem.credits.proration.amount,
+ amount: -subscriptionItem.credits.proration.amount.amount,
+ })}
+ />
@@
- <LineItems.Description text={`- ${$(subscriptionItem.credits.payer.appliedAmount)}`} />
+ <LineItems.Description
+ text={$({
+ ...subscriptionItem.credits.payer.appliedAmount,
+ amount: -subscriptionItem.credits.payer.appliedAmount.amount,
+ })}
+ />Also applies to: 292-293, 300-300
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/ui/src/components/PaymentAttempts/PaymentAttemptPage.tsx` around
lines 284 - 285, The hard-coded `- ` prefix used for discounts/credits in
LineItems.Description components (at lines 284, 292, and 300 in
PaymentAttemptPage.tsx) does not respect locale-specific negative currency
formatting rules. Instead of manually prefixing with `- `, pass a negated
monetary value directly to the `$` currency formatting function. For each
occurrence where you have a pattern like
`${$(paymentAttempt.totals.discounts.proration.amount)}`, remove the hard-coded
`- ` prefix and negate the amount value before passing it to the `$` function so
it applies proper locale-native formatting for negative currencies.
| prefix={subscription.nextPayment.amount.currency} | ||
| text={`${subscription.nextPayment.amount.currencySymbol}${subscription.nextPayment.amount.amountFormatted}`} | ||
| text={$(subscription.nextPayment.amount)} | ||
| /> |
There was a problem hiding this comment.
Remove prefix now that $(...) already returns a currency-formatted string.
Line 355 adds subscription.nextPayment.amount.currency while Line 356 now renders a complete localized currency value. This can duplicate currency labeling in the UI row.
Suggested fix
- <LineItems.Description
- prefix={subscription.nextPayment.amount.currency}
- text={$(subscription.nextPayment.amount)}
- />
+ <LineItems.Description text={$(subscription.nextPayment.amount)} />🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/ui/src/components/SubscriptionDetails/index.tsx` around lines 355 -
357, The prefix prop is redundant because the text prop already contains a
complete currency-formatted string returned by the
$(subscription.nextPayment.amount) function. Remove the prefix prop that
references subscription.nextPayment.amount.currency from the component, keeping
only the text prop with the $(subscription.nextPayment.amount) value to prevent
duplicate currency labeling in the UI.
There was a problem hiding this comment.
amount.currency is the three-letter ISO currency identifier, which is not always rendered from the formatter. I'm inclined to leave it as-is for now and we can adjust in the future if it looks truly wonky. For example, with USD in en-US this renders USD $10.00. But with USD in en-CA this would render USD US$10.00.
Description
This PR replaces our naive monetary amount formatting with a more robust system that is locale-aware.
Via a new
$helper exported fromuseLocalizations, monetary amounts can be formatted according to their configured currency and the configured locale of the application. For example:fr-FRlocale, 1,000 USD will be rendered as1 000,00 $USen-CAlocale, 1,000 USD will be rendered asUS$1,000.00This ensures that monetary amounts are formatted according to the standard monetary amount formatting rules of the configured locale. In the event the
Intl.NumberFormatAPI is not available, the helper will fall back to our previous behavior of simply concatenating the currency symbol and the API-provided formatted amount.As part of this change, two localization keys were changed to remove their hardcoded currency symbol interpolated value; they now just accept a
pricevalue for the monetary amount.Checklist
pnpm testruns as expected.pnpm buildruns as expected.Type of change
Summary by CodeRabbit
New Features / Improvements
Bug Fixes
Tests