Skip to content

Commit c3fa15d

Browse files
authored
chore(clerk-js, localizations): Improve type safety of localizationKeys() with params (#6108)
1 parent 675011c commit c3fa15d

19 files changed

+180
-122
lines changed

.changeset/cold-turtles-press.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/types': minor
3+
---
4+
5+
Expose `__internal_LocalizationResource` which now includes metadata for which keys require interpolation.

packages/clerk-js/bundlewatch.config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
{ "path": "./dist/clerk.browser.js", "maxSize": "70.16KB" },
55
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "113KB" },
66
{ "path": "./dist/clerk.headless*.js", "maxSize": "53.06KB" },
7-
{ "path": "./dist/ui-common*.js", "maxSize": "108.36KB" },
7+
{ "path": "./dist/ui-common*.js", "maxSize": "108.4KB" },
88
{ "path": "./dist/vendors*.js", "maxSize": "40.2KB" },
99
{ "path": "./dist/coinbase*.js", "maxSize": "38KB" },
1010
{ "path": "./dist/createorganization*.js", "maxSize": "5KB" },

packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ type RevokeAPIKeyConfirmationModalProps = {
1515
onOpen: () => void;
1616
onClose: () => void;
1717
apiKeyId?: string;
18-
apiKeyName?: string;
18+
apiKeyName: string;
1919
modalRoot?: React.MutableRefObject<HTMLElement | null>;
2020
};
2121

packages/clerk-js/src/ui/components/OrganizationProfile/ActionConfirmationPage.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ export const LeaveOrganizationForm = (props: LeaveOrganizationFormProps) => {
4949

5050
return (
5151
<ActionConfirmationPage
52-
organizationName={organization?.name}
52+
organizationName={organization.name}
5353
title={localizationKeys('organizationProfile.profilePage.dangerSection.leaveOrganization.title')}
5454
messageLine1={localizationKeys('organizationProfile.profilePage.dangerSection.leaveOrganization.messageLine1')}
5555
messageLine2={localizationKeys('organizationProfile.profilePage.dangerSection.leaveOrganization.messageLine2')}
5656
actionDescription={localizationKeys(
5757
'organizationProfile.profilePage.dangerSection.leaveOrganization.actionDescription',
58-
{ organizationName: organization?.name },
58+
{ organizationName: organization.name },
5959
)}
6060
submitLabel={localizationKeys('organizationProfile.profilePage.dangerSection.leaveOrganization.title')}
6161
successMessage={localizationKeys(
@@ -79,13 +79,13 @@ export const DeleteOrganizationForm = (props: DeleteOrganizationFormProps) => {
7979

8080
return (
8181
<ActionConfirmationPage
82-
organizationName={organization?.name}
82+
organizationName={organization.name}
8383
title={localizationKeys('organizationProfile.profilePage.dangerSection.deleteOrganization.title')}
8484
messageLine1={localizationKeys('organizationProfile.profilePage.dangerSection.deleteOrganization.messageLine1')}
8585
messageLine2={localizationKeys('organizationProfile.profilePage.dangerSection.deleteOrganization.messageLine2')}
8686
actionDescription={localizationKeys(
8787
'organizationProfile.profilePage.dangerSection.deleteOrganization.actionDescription',
88-
{ organizationName: organization?.name },
88+
{ organizationName: organization.name },
8989
)}
9090
submitLabel={localizationKeys('organizationProfile.profilePage.dangerSection.deleteOrganization.title')}
9191
successMessage={localizationKeys(
@@ -101,7 +101,7 @@ type ActionConfirmationPageProps = FormProps & {
101101
title: LocalizationKey;
102102
messageLine1: LocalizationKey;
103103
messageLine2: LocalizationKey;
104-
actionDescription?: LocalizationKey;
104+
actionDescription: LocalizationKey;
105105
organizationName?: string;
106106
successMessage: LocalizationKey;
107107
submitLabel: LocalizationKey;
@@ -128,9 +128,7 @@ const ActionConfirmationPage = withCardStateProvider((props: ActionConfirmationP
128128

129129
const confirmationField = useFormControl('deleteOrganizationConfirmation', '', {
130130
type: 'text',
131-
label:
132-
actionDescription ||
133-
localizationKeys('organizationProfile.profilePage.dangerSection.leaveOrganization.actionDescription'),
131+
label: actionDescription,
134132
isRequired: true,
135133
placeholder: organizationName,
136134
});

packages/clerk-js/src/ui/components/OrganizationProfile/RemoveDomainForm.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export const RemoveDomainForm = (props: RemoveDomainFormProps) => {
6262
<RemoveResourceForm
6363
title={localizationKeys('organizationProfile.removeDomainPage.title')}
6464
messageLine1={localizationKeys('organizationProfile.removeDomainPage.messageLine1', {
65-
domain: ref.current?.name,
65+
domain: ref.current?.name || '',
6666
})}
6767
messageLine2={localizationKeys('organizationProfile.removeDomainPage.messageLine2')}
6868
deleteResource={() =>

packages/clerk-js/src/ui/components/OrganizationProfile/VerifiedDomainForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,10 @@ export const VerifiedDomainForm = withCardStateProvider((props: VerifiedDomainFo
129129
}, [domain?.id]);
130130

131131
const title = localizationKeys('organizationProfile.verifiedDomainPage.title', {
132-
domain: domain?.name,
132+
domain: domain?.name || '',
133133
});
134134
const subtitle = localizationKeys('organizationProfile.verifiedDomainPage.subtitle', {
135-
domain: domain?.name,
135+
domain: domain?.name || '',
136136
});
137137

138138
const calloutLabel = useCalloutLabel(domain, {

packages/clerk-js/src/ui/components/OrganizationProfile/VerifyDomainForm.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export const VerifyDomainForm = withCardStateProvider((props: VerifyDomainFormPr
5050
const subtitleVerificationCodeScreen = localizationKeys(
5151
'organizationProfile.verifyDomainPage.subtitleVerificationCodeScreen',
5252
{
53-
emailAddress: affiliationEmailAddressRef.current,
53+
emailAddress: affiliationEmailAddressRef.current || '',
5454
},
5555
);
5656

packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,13 @@ function Card(props: CardProps) {
247247
order: ctaPosition === 'top' ? -1 : undefined,
248248
})}
249249
>
250-
{shouldShowFooterNotice ? (
250+
{shouldShowFooterNotice && subscription ? (
251251
<Text
252252
elementDescriptor={descriptors.pricingTableCardFooterNotice}
253253
variant={isCompact ? 'buttonSmall' : 'buttonLarge'}
254-
localizationKey={localizationKeys('badge__startsAt', { date: subscription?.periodStart })}
254+
localizationKey={localizationKeys('badge__startsAt', {
255+
date: subscription?.periodStart,
256+
})}
255257
colorScheme='secondary'
256258
sx={t => ({
257259
paddingBlock: t.space.$1x5,

packages/clerk-js/src/ui/components/SignIn/SignInFactorOneAlternativePhoneCodeCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const SignInFactorOneAlternativePhoneCodeCard = (props: SignInFactorOneAl
1515
<SignInFactorOneAlternativeChannelCodeForm
1616
{...props}
1717
cardTitle={localizationKeys('signIn.alternativePhoneCodeProvider.title', {
18-
provider: getAlternativePhoneCodeProviderData(props.factor.channel)?.name,
18+
provider: getAlternativePhoneCodeProviderData(props.factor.channel)?.name || '',
1919
})}
2020
cardSubtitle={localizationKeys('signIn.alternativePhoneCodeProvider.subtitle')}
2121
inputLabel={localizationKeys('signIn.alternativePhoneCodeProvider.formTitle')}

packages/clerk-js/src/ui/components/SignUp/SignUpPhoneCodeCard.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@ export const SignUpPhoneCodeCard = withCardStateProvider(() => {
5858

5959
if (isAlternativePhoneCodeProvider) {
6060
const provider = getAlternativePhoneCodeProviderData(channel)?.name;
61-
cardTitleKey = localizationKeys('signUp.alternativePhoneCodeProvider.title', { provider });
62-
cardSubtitleKey = localizationKeys('signUp.alternativePhoneCodeProvider.subtitle', { provider });
61+
cardTitleKey = localizationKeys('signUp.alternativePhoneCodeProvider.title', { provider: provider || '' });
62+
cardSubtitleKey = localizationKeys('signUp.alternativePhoneCodeProvider.subtitle', {
63+
provider: provider || '',
64+
});
6365
resendButtonKey = localizationKeys('signUp.alternativePhoneCodeProvider.resendButton');
6466
}
6567

packages/clerk-js/src/ui/components/SignUp/SignUpStartAlternativePhoneCodePhoneNumberCard.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ export const SignUpStartAlternativePhoneCodePhoneNumberCard = (props: SignUpForm
7575
<Form.ControlRow elementId='phoneNumber'>
7676
<Form.PhoneInput
7777
{...formState.phoneNumber.props}
78-
label={localizationKeys('signUp.start.alternativePhoneCodeProvider.label', { provider })}
78+
label={localizationKeys('signUp.start.alternativePhoneCodeProvider.label', {
79+
provider: provider || '',
80+
})}
7981
isRequired
8082
isOptional={false}
8183
actionLabel={undefined}

packages/clerk-js/src/ui/components/UserProfile/EmailForm.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export const EmailForm = withCardStateProvider((props: EmailFormProps) => {
8686
<FormContainer
8787
headerTitle={localizationKeys('userProfile.emailAddressPage.verifyTitle')}
8888
headerSubtitle={localizationKeys(`${translationKey}.formSubtitle`, {
89-
identifier: emailAddressRef.current?.emailAddress,
89+
identifier: emailAddressRef.current?.emailAddress || '',
9090
})}
9191
>
9292
{strategy === 'email_link' && (

packages/clerk-js/src/ui/components/UserProfile/MfaPhoneCodeScreen.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ export const MFAVerifyPhone = (props: MFAVerifyPhoneProps) => {
151151
<FormContainer
152152
headerTitle={title}
153153
headerSubtitle={localizationKeys('userProfile.phoneNumberPage.verifySubtitle', {
154-
identifier: resourceRef.current?.phoneNumber,
154+
identifier: resourceRef.current?.phoneNumber || '',
155155
})}
156156
>
157157
<VerifyWithCode

packages/clerk-js/src/ui/components/UserProfile/PhoneForm.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ export const VerifyPhone = (props: VerifyPhoneProps) => {
130130
<FormContainer
131131
headerTitle={title}
132132
headerSubtitle={localizationKeys('userProfile.phoneNumberPage.verifySubtitle', {
133-
identifier: resourceRef.current?.phoneNumber,
133+
identifier: resourceRef.current?.phoneNumber || '',
134134
})}
135135
>
136136
<VerifyWithCode

packages/clerk-js/src/ui/components/UserProfile/RemoveResourceForm.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,11 @@ export const RemoveConnectedAccountForm = (props: ConnectedAccountFormProps) =>
100100
<RemoveResourceForm
101101
title={localizationKeys('userProfile.connectedAccountPage.removeResource.title')}
102102
messageLine1={localizationKeys('userProfile.connectedAccountPage.removeResource.messageLine1', {
103-
identifier: providerToDisplayData[ref.current]?.name,
103+
identifier: providerToDisplayData[ref.current]?.name || '',
104104
})}
105105
messageLine2={localizationKeys('userProfile.connectedAccountPage.removeResource.messageLine2')}
106106
successMessage={localizationKeys('userProfile.connectedAccountPage.removeResource.successMessage', {
107-
connectedAccount: providerToDisplayData[ref.current]?.name,
107+
connectedAccount: providerToDisplayData[ref.current]?.name || '',
108108
})}
109109
deleteResource={() => Promise.resolve(resource?.destroy())}
110110
onSuccess={onSuccess}
@@ -212,7 +212,7 @@ export const RemovePasskeyForm = (props: RemovePasskeyFormProps) => {
212212
<RemoveResourceForm
213213
title={localizationKeys('userProfile.passkeyScreen.removeResource.title')}
214214
messageLine1={localizationKeys('userProfile.passkeyScreen.removeResource.messageLine1', {
215-
name: passkey.name,
215+
name: passkey.name || '',
216216
})}
217217
deleteResource={passkey.delete}
218218
onSuccess={onSuccess}

packages/clerk-js/src/ui/components/UserProfile/VerifyWithCode.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ export const VerifyWithCode = (props: VerifyWithCodeProps) => {
4545
<Form.OTPInput
4646
{...otp}
4747
label={localizationKeys('userProfile.emailAddressPage.emailCode.formTitle')}
48-
description={localizationKeys('userProfile.emailAddressPage.emailCode.formSubtitle', { identifier })}
48+
description={localizationKeys('userProfile.emailAddressPage.emailCode.formSubtitle', {
49+
identifier: identifier || '',
50+
})}
4951
resendButton={localizationKeys('userProfile.emailAddressPage.emailCode.resendButton')}
5052
centerAlign={false}
5153
/>

packages/clerk-js/src/ui/elements/LegalConsentCheckbox.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,16 @@ const LegalCheckboxLabel = (props: { termsUrl?: string; privacyPolicyUrl?: strin
2323

2424
if (termsUrl && privacyPolicyUrl) {
2525
localizationKey = localizationKeys('signUp.legalConsent.checkbox.label__termsOfServiceAndPrivacyPolicy', {
26-
termsOfServiceLink: props.termsUrl,
27-
privacyPolicyLink: props.privacyPolicyUrl,
26+
termsOfServiceLink: termsUrl,
27+
privacyPolicyLink: privacyPolicyUrl,
2828
});
2929
} else if (termsUrl) {
3030
localizationKey = localizationKeys('signUp.legalConsent.checkbox.label__onlyTermsOfService', {
31-
termsOfServiceLink: props.termsUrl,
31+
termsOfServiceLink: termsUrl,
3232
});
3333
} else if (privacyPolicyUrl) {
3434
localizationKey = localizationKeys('signUp.legalConsent.checkbox.label__onlyPrivacyPolicy', {
35-
privacyPolicyLink: props.privacyPolicyUrl,
35+
privacyPolicyLink: privacyPolicyUrl,
3636
});
3737
}
3838

packages/clerk-js/src/ui/localization/localizationKeys.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import type { PathValue, RecordToPath } from '@clerk/types';
2-
3-
import type { defaultResource } from './defaultEnglishResource';
1+
import type { __internal_LocalizationResource, PathValue, RecordToPath } from '@clerk/types';
42

53
type Value = string | number | boolean | Date;
64
type Whitespace = ' ' | '\t' | '\n' | '\r';
@@ -61,20 +59,19 @@ export type GetICUArgs<Text extends string, T extends RemovePipeUtils<Text>> = T
6159
T extends readonly string[] ? TupleFindBlocks<T> : FindBlocks<T>
6260
>;
6361

64-
type DefaultLocalizationKey = RecordToPath<typeof defaultResource>;
65-
type LocalizationKeyToValue<P extends DefaultLocalizationKey> = PathValue<typeof defaultResource, P>;
66-
67-
// @ts-ignore
68-
type LocalizationKeyToParams<P extends DefaultLocalizationKey> = GetICUArgs<LocalizationKeyToValue<P>>;
62+
type DefaultLocalizationKey = RecordToPath<__internal_LocalizationResource>;
63+
type LocalizationKeyToValue<P extends DefaultLocalizationKey> = PathValue<__internal_LocalizationResource, P>;
6964

7065
export type LocalizationKey = {
7166
key: string;
7267
params: Record<string, any> | undefined;
7368
};
7469

75-
export const localizationKeys = <Key extends DefaultLocalizationKey, Params extends LocalizationKeyToParams<Key>>(
70+
type ExtractArgsFromValue<Value> = Value extends { __params: any } ? [params: Value['__params']] : [];
71+
72+
export const localizationKeys = <Key extends DefaultLocalizationKey, Value extends LocalizationKeyToValue<Key>>(
7673
key: Key,
77-
params?: keyof Params extends never ? never : Params,
74+
...args: ExtractArgsFromValue<Value>
7875
): LocalizationKey => {
79-
return { key, params } as LocalizationKey;
76+
return { key, params: args[0] } as LocalizationKey;
8077
};

0 commit comments

Comments
 (0)