-
Notifications
You must be signed in to change notification settings - Fork 397
feat(clerk-js): Detect locale
from browser and send it to FAPI if exists during sign-in (i18n)
#7011
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
guilherme6191
merged 6 commits into
main
from
guilherme/user-3712-detect-and-send-locale-in-sign-ins-js-lib
Oct 17, 2025
Merged
feat(clerk-js): Detect locale
from browser and send it to FAPI if exists during sign-in (i18n)
#7011
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
216056c
feat(i18n): detect locale from browser and send it to FAPI if exists …
guilherme6191 bbc986a
chore: generate changeset
guilherme6191 b5a3586
tests: add global unstub to be extra safe
guilherme6191 35b45c2
fix: default value to empty string
guilherme6191 f500017
feat: Address review comments
guilherme6191 c781372
refactor: Reduce spreads
guilherme6191 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@clerk/clerk-js': patch | ||
--- | ||
|
||
Add support for automatically sending the browser locale during the sign-in flow |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
114 changes: 85 additions & 29 deletions
114
packages/clerk-js/src/core/resources/__tests__/SignIn.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,95 @@ | ||
import { describe, expect, it, vi } from 'vitest'; | ||
import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest'; | ||
|
||
import { BaseResource } from '../internal'; | ||
import { SignIn } from '../SignIn'; | ||
|
||
describe('SignIn', () => { | ||
describe('signIn.create', () => { | ||
afterEach(() => { | ||
vi.clearAllMocks(); | ||
vi.unstubAllGlobals(); | ||
}); | ||
|
||
it('includes locale in request body when navigator.language is available', async () => { | ||
vi.stubGlobal('navigator', { language: 'fr-FR' }); | ||
|
||
const mockFetch = vi.fn().mockResolvedValue({ | ||
client: null, | ||
response: { id: 'signin_123', status: 'needs_first_factor' }, | ||
}); | ||
BaseResource._fetch = mockFetch; | ||
|
||
const signIn = new SignIn(); | ||
await signIn.create({ identifier: 'user@example.com' }); | ||
|
||
expect(mockFetch).toHaveBeenCalledWith( | ||
expect.objectContaining({ | ||
method: 'POST', | ||
path: '/client/sign_ins', | ||
body: { | ||
identifier: 'user@example.com', | ||
locale: 'fr-FR', | ||
}, | ||
}), | ||
); | ||
}); | ||
|
||
it('excludes locale from request body when navigator.language is empty', async () => { | ||
vi.stubGlobal('navigator', { language: '' }); | ||
|
||
const mockFetch = vi.fn().mockResolvedValue({ | ||
client: null, | ||
response: { id: 'signin_123', status: 'needs_first_factor' }, | ||
}); | ||
BaseResource._fetch = mockFetch; | ||
|
||
const signIn = new SignIn(); | ||
await signIn.create({ identifier: 'user@example.com' }); | ||
|
||
expect(mockFetch).toHaveBeenCalledWith( | ||
expect.objectContaining({ | ||
method: 'POST', | ||
path: '/client/sign_ins', | ||
body: { | ||
identifier: 'user@example.com', | ||
}, | ||
}), | ||
); | ||
}); | ||
}); | ||
|
||
describe('SignInFuture', () => { | ||
describe('selectFirstFactor', () => { | ||
const signInCreatedJSON = { | ||
id: 'test_id', | ||
|
||
supported_first_factors: [ | ||
{ strategy: 'email_code', emailAddressId: 'email_address_0', safe_identifier: 'test+abc@clerk.com' }, | ||
{ strategy: 'email_code', emailAddressId: 'email_address_1', safe_identifier: 'test@clerk.com' }, | ||
{ strategy: 'phone_code', phoneNumberId: 'phone_number_1', safe_identifier: '+301234567890' }, | ||
], | ||
}; | ||
|
||
const firstFactorPreparedJSON = {}; | ||
|
||
BaseResource._fetch = vi.fn().mockImplementation(({ method, path, body }) => { | ||
if (method === 'POST' && path === '/client/sign_ins') { | ||
return Promise.resolve({ | ||
client: null, | ||
response: { ...signInCreatedJSON, identifier: body.identifier }, | ||
}); | ||
} | ||
|
||
if (method === 'POST' && path === '/client/sign_ins/test_id/prepare_first_factor') { | ||
return Promise.resolve({ | ||
client: null, | ||
response: firstFactorPreparedJSON, | ||
}); | ||
} | ||
|
||
throw new Error('Unexpected call to BaseResource._fetch'); | ||
beforeAll(() => { | ||
const signInCreatedJSON = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. with new tests and mocks, this was source of failing tests. So I just added moved the into the beforeAll function so we can have more control over order and scope |
||
id: 'test_id', | ||
|
||
supported_first_factors: [ | ||
{ strategy: 'email_code', emailAddressId: 'email_address_0', safe_identifier: 'test+abc@clerk.com' }, | ||
{ strategy: 'email_code', emailAddressId: 'email_address_1', safe_identifier: 'test@clerk.com' }, | ||
{ strategy: 'phone_code', phoneNumberId: 'phone_number_1', safe_identifier: '+301234567890' }, | ||
], | ||
}; | ||
|
||
const firstFactorPreparedJSON = {}; | ||
|
||
BaseResource._fetch = vi.fn().mockImplementation(({ method, path, body }) => { | ||
if (method === 'POST' && path === '/client/sign_ins') { | ||
return Promise.resolve({ | ||
client: null, | ||
response: { ...signInCreatedJSON, identifier: body.identifier }, | ||
}); | ||
} | ||
|
||
if (method === 'POST' && path === '/client/sign_ins/test_id/prepare_first_factor') { | ||
return Promise.resolve({ | ||
client: null, | ||
response: firstFactorPreparedJSON, | ||
}); | ||
} | ||
|
||
throw new Error('Unexpected call to BaseResource._fetch'); | ||
}); | ||
}); | ||
|
||
it('should select correct first factor by email address', async () => { | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since there is no change (even backwards compatible) to the sdk api for users, I think we have a
patch
here -- open to make it aminor
as well