Skip to content

Commit 1cf759a

Browse files
committed
feat: Add optional locale frowm browser to signup flow
1 parent 2cd53cd commit 1cf759a

File tree

9 files changed

+86
-4
lines changed

9 files changed

+86
-4
lines changed

packages/clerk-js/src/core/resources/SignUp.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import {
4646
generateSignatureWithMetamask,
4747
generateSignatureWithOKXWallet,
4848
getBaseIdentifier,
49+
getBrowserLocale,
4950
getClerkQueryParam,
5051
getCoinbaseWalletIdentifier,
5152
getMetamaskIdentifier,
@@ -95,6 +96,7 @@ export class SignUp extends BaseResource implements SignUpResource {
9596
createdUserId: string | null = null;
9697
abandonAt: number | null = null;
9798
legalAcceptedAt: number | null = null;
99+
locale: string | null = null;
98100

99101
/**
100102
* The current status of the sign-up process.
@@ -154,6 +156,11 @@ export class SignUp extends BaseResource implements SignUpResource {
154156

155157
let finalParams = { ...params };
156158

159+
// Inject browser locale if not already provided
160+
if (!finalParams.locale) {
161+
finalParams.locale = getBrowserLocale();
162+
}
163+
157164
if (!__BUILD_DISABLE_RHC__ && !this.clientBypass() && !this.shouldBypassCaptchaForAttempt(params)) {
158165
const captchaChallenge = new CaptchaChallenge(SignUp.clerk);
159166
const captchaParams = await captchaChallenge.managedOrInvisible({ action: 'signup' });
@@ -677,7 +684,9 @@ class SignUpFuture implements SignUpFutureResource {
677684

678685
async create(params: SignUpFutureCreateParams): Promise<{ error: unknown }> {
679686
return runAsyncResourceTask(this.resource, async () => {
680-
await this._create(params);
687+
// Inject browser locale if not already provided
688+
const locale = params.locale || getBrowserLocale();
689+
await this._create({ ...params, locale });
681690
});
682691
}
683692

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { describe, expect, it } from 'vitest';
2+
3+
import { getBrowserLocale } from '../locale';
4+
5+
describe('getBrowserLocale()', () => {
6+
it('returns the browser locale when available', () => {
7+
Object.defineProperty(window.navigator, 'language', {
8+
value: 'es-ES',
9+
configurable: true,
10+
});
11+
12+
expect(getBrowserLocale()).toBe('es-ES');
13+
});
14+
15+
it('returns en-US as default when navigator.language is not available', () => {
16+
Object.defineProperty(window.navigator, 'language', {
17+
value: undefined,
18+
configurable: true,
19+
});
20+
21+
expect(getBrowserLocale()).toBe('en-US');
22+
});
23+
24+
it('returns en-US when navigator.language is empty string', () => {
25+
Object.defineProperty(window.navigator, 'language', {
26+
value: '',
27+
configurable: true,
28+
});
29+
30+
expect(getBrowserLocale()).toBe('en-US');
31+
});
32+
33+
it('returns en-US when navigator object is not defined', () => {
34+
Object.defineProperty(window, 'navigator', {
35+
value: undefined,
36+
configurable: true,
37+
});
38+
39+
expect(getBrowserLocale()).toBe('en-US');
40+
});
41+
});

packages/clerk-js/src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export * from './props';
2323
export * from './queryStateParams';
2424
export * from './querystring';
2525
export * from './runtime';
26+
export * from './locale';
2627
export * from './url';
2728
export * from './web3';
2829
export * from './windowNavigate';
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { inBrowser } from '@clerk/shared/browser';
2+
3+
const DEFAULT_LOCALE = 'en-US';
4+
5+
/**
6+
* Detects the user's preferred locale from the browser.
7+
* Falls back to 'en-US' if locale cannot be determined.
8+
*
9+
* @returns The detected locale string in BCP 47 format (e.g., 'en-US', 'es-ES')
10+
*/
11+
export function getBrowserLocale(): string {
12+
if (!inBrowser()) {
13+
return DEFAULT_LOCALE;
14+
}
15+
16+
// Get locale from the browser
17+
const locale = navigator?.language;
18+
19+
// Validate that we got a non-empty string
20+
if (!locale || typeof locale !== 'string' || locale.trim() === '') {
21+
return DEFAULT_LOCALE;
22+
}
23+
24+
return locale;
25+
}

packages/types/src/signUp.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export interface SignUpResource extends ClerkResource {
6060
createdUserId: string | null;
6161
abandonAt: number | null;
6262
legalAcceptedAt: number | null;
63+
locale: string | null;
6364

6465
create: (params: SignUpCreateParams) => Promise<SignUpResource>;
6566

packages/types/src/signUpCommon.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ export type SignUpCreateParams = Partial<
100100
oidcPrompt: string;
101101
oidcLoginHint: string;
102102
channel: PhoneCodeChannel;
103+
locale?: string;
103104
} & Omit<SnakeToCamel<Record<SignUpAttributeField | SignUpVerifiableField, string>>, 'legalAccepted'>
104105
>;
105106

packages/types/src/signUpFuture.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ interface SignUpFutureAdditionalParams {
88
lastName?: string;
99
unsafeMetadata?: SignUpUnsafeMetadata;
1010
legalAccepted?: boolean;
11+
locale?: string;
1112
}
1213

1314
export interface SignUpFutureCreateParams extends SignUpFutureAdditionalParams {

playground/app-router/.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ yarn-debug.log*
2525
yarn-error.log*
2626

2727
# local env files
28-
.env*.local
28+
.env*
2929

3030
# vercel
3131
.vercel
3232

3333
# typescript
3434
*.tsbuildinfo
3535
next-env.d.ts
36+
37+
# clerk configuration (can include secrets)
38+
/.clerk/

playground/app-router/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ yarn dev
1212
pnpm dev
1313
```
1414

15-
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
15+
Open [http://localhost:4011](http://localhost:4011) with your browser to see the result.
1616

1717
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
1818

19-
[http://localhost:3000/api/hello](http://localhost:3000/api/hello) is an endpoint that uses [Route Handlers](https://nextjs.org/docs/routing/route-handlers). This endpoint can be edited in `app/api/hello/route.ts`.
19+
[http://localhost:4011/api/hello](http://localhost:4011/api/hello) is an endpoint that uses [Route Handlers](https://nextjs.org/docs/routing/route-handlers). This endpoint can be edited in `app/api/hello/route.ts`.
2020

2121
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
2222

0 commit comments

Comments
 (0)