Skip to content

Commit 8da6d75

Browse files
authored
feat(use-i18n): make the provider compatible with server side rendering (#1320)
1 parent 34a3305 commit 8da6d75

File tree

3 files changed

+112
-15
lines changed

3 files changed

+112
-15
lines changed

.changeset/shiny-hairs-decide.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@scaleway/use-i18n': minor
3+
---
4+
5+
feat(use-i18n): make the provider compatible with server side rendering

packages/use-i18n/src/__tests__/usei18n.tsx

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ describe('i18n hook', () => {
237237
})
238238
})
239239

240-
it('should set current locale from navigator languages', async () => {
240+
it('should set current locale from defaultLocale', async () => {
241241
const { result } = renderHook(() => useI18n(), {
242242
wrapper: wrapper({
243243
defaultLocale: 'fr',
@@ -250,6 +250,91 @@ describe('i18n hook', () => {
250250
})
251251
})
252252

253+
describe('getCurrentLocale', () => {
254+
it('should set current locale from localStorage', async () => {
255+
jest.spyOn(global, 'navigator', 'get').mockReturnValueOnce({
256+
languages: ['fr'],
257+
} as unknown as Navigator)
258+
const mockGetItem = jest.fn().mockImplementation(() => 'en')
259+
const mockSetItem = jest.fn()
260+
const localStorageMock = jest
261+
.spyOn(global, 'localStorage', 'get')
262+
.mockReturnValue({
263+
getItem: mockGetItem,
264+
setItem: mockSetItem,
265+
clear: jest.fn(),
266+
} as unknown as Storage)
267+
268+
const { result } = renderHook(() => useI18n(), {
269+
wrapper: wrapper({
270+
defaultLocale: 'es',
271+
supportedLocales: ['en', 'fr', 'es'],
272+
}),
273+
})
274+
275+
await waitFor(() => {
276+
expect(result.current.currentLocale).toEqual('en')
277+
expect(mockGetItem).toHaveBeenCalledTimes(2)
278+
expect(mockGetItem).toHaveBeenCalledWith(LOCALE_ITEM_STORAGE)
279+
})
280+
localStorageMock.mockRestore()
281+
})
282+
283+
it('should set current locale from navigator', async () => {
284+
jest.spyOn(global, 'navigator', 'get').mockReturnValueOnce({
285+
languages: ['fr'],
286+
} as unknown as Navigator)
287+
const mockGetItem = jest.fn()
288+
const mockSetItem = jest.fn()
289+
const localStorageMock = jest
290+
.spyOn(global, 'localStorage', 'get')
291+
.mockReturnValueOnce({
292+
getItem: mockGetItem,
293+
setItem: mockSetItem,
294+
clear: jest.fn(),
295+
} as unknown as Storage)
296+
297+
const { result } = renderHook(() => useI18n(), {
298+
wrapper: wrapper({
299+
defaultLocale: 'es',
300+
supportedLocales: ['en', 'fr', 'es'],
301+
}),
302+
})
303+
304+
await waitFor(() => {
305+
expect(result.current.currentLocale).toEqual('fr')
306+
})
307+
localStorageMock.mockRestore()
308+
})
309+
310+
it('should set current locale from defaultLocale', async () => {
311+
jest.spyOn(global, 'navigator', 'get').mockReturnValueOnce({
312+
languages: [],
313+
} as unknown as Navigator)
314+
const mockGetItem = jest.fn()
315+
const mockSetItem = jest.fn()
316+
const localStorageMock = jest
317+
.spyOn(global, 'localStorage', 'get')
318+
.mockReturnValueOnce({
319+
getItem: mockGetItem,
320+
setItem: mockSetItem,
321+
clear: jest.fn(),
322+
} as unknown as Storage)
323+
324+
const { result } = renderHook(() => useI18n(), {
325+
wrapper: wrapper({
326+
defaultLocale: 'es',
327+
supportedLocales: ['en', 'fr', 'es'],
328+
}),
329+
})
330+
331+
await waitFor(() => {
332+
expect(result.current.currentLocale).toEqual('es')
333+
})
334+
localStorageMock.mockRestore()
335+
})
336+
})
337+
253338
it('should switch locale', async () => {
254339
const { result } = renderHook(() => useI18n(), {
255340
wrapper: wrapper({
@@ -266,22 +351,25 @@ describe('i18n hook', () => {
266351

267352
await waitFor(() => {
268353
expect(result.current.currentLocale).toEqual('fr')
269-
expect(localStorage.getItem(LOCALE_ITEM_STORAGE)).toBe('fr')
270354
})
355+
expect(localStorage.getItem(LOCALE_ITEM_STORAGE)).toBe('fr')
271356

272357
act(() => {
273358
result.current.switchLocale('es')
274359
})
275360

276361
await waitFor(() => {
277362
expect(result.current.currentLocale).toEqual('es')
278-
expect(localStorage.getItem(LOCALE_ITEM_STORAGE)).toBe('es')
279363
})
364+
expect(localStorage.getItem(LOCALE_ITEM_STORAGE)).toBe('es')
280365

281366
act(() => {
282367
result.current.switchLocale('test')
283368
})
284-
expect(result.current.currentLocale).toEqual('es')
369+
370+
await waitFor(() => {
371+
expect(result.current.currentLocale).toEqual('es')
372+
})
285373
expect(localStorage.getItem(LOCALE_ITEM_STORAGE)).toBe('es')
286374
})
287375

packages/use-i18n/src/usei18n.tsx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,21 @@ const getCurrentLocale = ({
5050
supportedLocales: string[]
5151
localeItemStorage: string
5252
}): string => {
53-
const { languages } = navigator
54-
const browserLocales = [...new Set(languages.map(getLocaleFallback))]
55-
const localeStorage = localStorage.getItem(localeItemStorage)
56-
57-
return (
58-
localeStorage ||
59-
browserLocales.find(
60-
locale => locale && supportedLocales.includes(locale),
61-
) ||
62-
defaultLocale
63-
)
53+
if (typeof window !== 'undefined') {
54+
const { languages } = navigator
55+
const browserLocales = [...new Set(languages.map(getLocaleFallback))]
56+
const localeStorage = localStorage.getItem(localeItemStorage)
57+
58+
return (
59+
localeStorage ||
60+
browserLocales.find(
61+
locale => locale && supportedLocales.includes(locale),
62+
) ||
63+
defaultLocale
64+
)
65+
}
66+
67+
return defaultLocale
6468
}
6569

6670
type Context<Locale extends BaseLocale> = {

0 commit comments

Comments
 (0)