From 537a88bcb1f4178b99783eec6d7eac41f310d512 Mon Sep 17 00:00:00 2001 From: Antoine LE TAXIN Date: Fri, 19 May 2023 11:08:27 +0200 Subject: [PATCH] feat(use-i18n): make the provider compatible with server side rendering --- .changeset/shiny-hairs-decide.md | 5 ++ packages/use-i18n/src/__tests__/usei18n.tsx | 96 ++++++++++++++++++++- packages/use-i18n/src/usei18n.tsx | 26 +++--- 3 files changed, 112 insertions(+), 15 deletions(-) create mode 100644 .changeset/shiny-hairs-decide.md diff --git a/.changeset/shiny-hairs-decide.md b/.changeset/shiny-hairs-decide.md new file mode 100644 index 000000000..1bcaa049d --- /dev/null +++ b/.changeset/shiny-hairs-decide.md @@ -0,0 +1,5 @@ +--- +'@scaleway/use-i18n': minor +--- + +feat(use-i18n): make the provider compatible with server side rendering diff --git a/packages/use-i18n/src/__tests__/usei18n.tsx b/packages/use-i18n/src/__tests__/usei18n.tsx index 7a8f052b2..9291b6fe4 100644 --- a/packages/use-i18n/src/__tests__/usei18n.tsx +++ b/packages/use-i18n/src/__tests__/usei18n.tsx @@ -237,7 +237,7 @@ describe('i18n hook', () => { }) }) - it('should set current locale from navigator languages', async () => { + it('should set current locale from defaultLocale', async () => { const { result } = renderHook(() => useI18n(), { wrapper: wrapper({ defaultLocale: 'fr', @@ -250,6 +250,91 @@ describe('i18n hook', () => { }) }) + describe('getCurrentLocale', () => { + it('should set current locale from localStorage', async () => { + jest.spyOn(global, 'navigator', 'get').mockReturnValueOnce({ + languages: ['fr'], + } as unknown as Navigator) + const mockGetItem = jest.fn().mockImplementation(() => 'en') + const mockSetItem = jest.fn() + const localStorageMock = jest + .spyOn(global, 'localStorage', 'get') + .mockReturnValue({ + getItem: mockGetItem, + setItem: mockSetItem, + clear: jest.fn(), + } as unknown as Storage) + + const { result } = renderHook(() => useI18n(), { + wrapper: wrapper({ + defaultLocale: 'es', + supportedLocales: ['en', 'fr', 'es'], + }), + }) + + await waitFor(() => { + expect(result.current.currentLocale).toEqual('en') + expect(mockGetItem).toHaveBeenCalledTimes(2) + expect(mockGetItem).toHaveBeenCalledWith(LOCALE_ITEM_STORAGE) + }) + localStorageMock.mockRestore() + }) + + it('should set current locale from navigator', async () => { + jest.spyOn(global, 'navigator', 'get').mockReturnValueOnce({ + languages: ['fr'], + } as unknown as Navigator) + const mockGetItem = jest.fn() + const mockSetItem = jest.fn() + const localStorageMock = jest + .spyOn(global, 'localStorage', 'get') + .mockReturnValueOnce({ + getItem: mockGetItem, + setItem: mockSetItem, + clear: jest.fn(), + } as unknown as Storage) + + const { result } = renderHook(() => useI18n(), { + wrapper: wrapper({ + defaultLocale: 'es', + supportedLocales: ['en', 'fr', 'es'], + }), + }) + + await waitFor(() => { + expect(result.current.currentLocale).toEqual('fr') + }) + localStorageMock.mockRestore() + }) + + it('should set current locale from defaultLocale', async () => { + jest.spyOn(global, 'navigator', 'get').mockReturnValueOnce({ + languages: [], + } as unknown as Navigator) + const mockGetItem = jest.fn() + const mockSetItem = jest.fn() + const localStorageMock = jest + .spyOn(global, 'localStorage', 'get') + .mockReturnValueOnce({ + getItem: mockGetItem, + setItem: mockSetItem, + clear: jest.fn(), + } as unknown as Storage) + + const { result } = renderHook(() => useI18n(), { + wrapper: wrapper({ + defaultLocale: 'es', + supportedLocales: ['en', 'fr', 'es'], + }), + }) + + await waitFor(() => { + expect(result.current.currentLocale).toEqual('es') + }) + localStorageMock.mockRestore() + }) + }) + it('should switch locale', async () => { const { result } = renderHook(() => useI18n(), { wrapper: wrapper({ @@ -266,8 +351,8 @@ describe('i18n hook', () => { await waitFor(() => { expect(result.current.currentLocale).toEqual('fr') - expect(localStorage.getItem(LOCALE_ITEM_STORAGE)).toBe('fr') }) + expect(localStorage.getItem(LOCALE_ITEM_STORAGE)).toBe('fr') act(() => { result.current.switchLocale('es') @@ -275,13 +360,16 @@ describe('i18n hook', () => { await waitFor(() => { expect(result.current.currentLocale).toEqual('es') - expect(localStorage.getItem(LOCALE_ITEM_STORAGE)).toBe('es') }) + expect(localStorage.getItem(LOCALE_ITEM_STORAGE)).toBe('es') act(() => { result.current.switchLocale('test') }) - expect(result.current.currentLocale).toEqual('es') + + await waitFor(() => { + expect(result.current.currentLocale).toEqual('es') + }) expect(localStorage.getItem(LOCALE_ITEM_STORAGE)).toBe('es') }) diff --git a/packages/use-i18n/src/usei18n.tsx b/packages/use-i18n/src/usei18n.tsx index a3b5abe10..67499ca7d 100644 --- a/packages/use-i18n/src/usei18n.tsx +++ b/packages/use-i18n/src/usei18n.tsx @@ -50,17 +50,21 @@ const getCurrentLocale = ({ supportedLocales: string[] localeItemStorage: string }): string => { - const { languages } = navigator - const browserLocales = [...new Set(languages.map(getLocaleFallback))] - const localeStorage = localStorage.getItem(localeItemStorage) - - return ( - localeStorage || - browserLocales.find( - locale => locale && supportedLocales.includes(locale), - ) || - defaultLocale - ) + if (typeof window !== 'undefined') { + const { languages } = navigator + const browserLocales = [...new Set(languages.map(getLocaleFallback))] + const localeStorage = localStorage.getItem(localeItemStorage) + + return ( + localeStorage || + browserLocales.find( + locale => locale && supportedLocales.includes(locale), + ) || + defaultLocale + ) + } + + return defaultLocale } type Context = {