From 2a01d1c93d6114a26434174e89ee0628a1e99ed9 Mon Sep 17 00:00:00 2001 From: Alexandre Combemorel Date: Tue, 18 Nov 2025 14:17:16 +0100 Subject: [PATCH 1/3] fix: make sure namespace params from useTranslation hooks are not passed empty --- biome.json | 12 ++++++------ packages/use-i18n/src/usei18n.tsx | 11 +++++------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/biome.json b/biome.json index 875faaa00..8361de582 100644 --- a/biome.json +++ b/biome.json @@ -32,16 +32,16 @@ "attributePosition": "auto", "includes": [ "**", - "!**/.next/", - "!**/coverage/", - "!**/node_modules/", - "!**/storybook-static", - "!**/dist/", + "!**/.next/*", + "!**/coverage/*", + "!**/node_modules/*", + "!**/storybook-static/*", + "!**/dist/*", "!**/pnpm-lock.yaml", "!**/package.json", "!**/CHANGELOG.md", "!**/*.snap", - "!**/__snapshots__/" + "!**/__snapshots__/*" ] }, "javascript": { diff --git a/packages/use-i18n/src/usei18n.tsx b/packages/use-i18n/src/usei18n.tsx index 2e232e2a7..df71262c6 100644 --- a/packages/use-i18n/src/usei18n.tsx +++ b/packages/use-i18n/src/usei18n.tsx @@ -151,7 +151,7 @@ export function useTranslation< LocaleParam extends BaseLocale = {}, LocalSupportedType extends string = '', >( - namespaces: string[] = [], + namespaces: [string, ...string[]], load: LoadTranslationsFn | undefined = undefined, ): RequiredGenericContext & { isLoaded: boolean @@ -162,13 +162,12 @@ export function useTranslation< } const { loadTranslations, namespaces: loadedNamespaces } = context - const key = namespaces.join(',') useEffect(() => { // eslint-disable-next-line @typescript-eslint/no-floating-promises - key - .split(',') - .map(async (namespace: string) => loadTranslations(namespace, load)) - }, [loadTranslations, key, load]) + namespaces.map(async (namespace: string) => + loadTranslations(namespace, load), + ) + }, [loadTranslations, namespaces, load]) const isLoaded = useMemo( () => areNamespacesLoaded(namespaces, loadedNamespaces), From a26522e367aa2c87a8e95b1fce74c7f5cceced71 Mon Sep 17 00:00:00 2001 From: Alexandre Combemorel Date: Tue, 18 Nov 2025 18:10:14 +0100 Subject: [PATCH 2/3] fix: back key useEffect --- .../use-i18n/src/__tests__/usei18n.test.tsx | 58 +++++++++++-------- packages/use-i18n/src/usei18n.tsx | 11 ++-- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/packages/use-i18n/src/__tests__/usei18n.test.tsx b/packages/use-i18n/src/__tests__/usei18n.test.tsx index 14e7899fd..b1084ae2b 100644 --- a/packages/use-i18n/src/__tests__/usei18n.test.tsx +++ b/packages/use-i18n/src/__tests__/usei18n.test.tsx @@ -117,7 +117,7 @@ describe('i18n hook', () => { const spy = vi.spyOn(console, 'error') spy.mockImplementation(() => {}) - expect(() => renderHook(() => useTranslation())).toThrow( + expect(() => renderHook(() => useTranslation(['test']))).toThrow( new Error('useTranslation must be used within a I18nProvider'), ) spy.mockRestore() @@ -133,34 +133,41 @@ describe('i18n hook', () => { spy.mockRestore() }) - it('should use defaultLoad, useTranslation, switch local and translate', async () => { - const { result } = renderHook(() => useTranslation([]), { - wrapper: wrapper({ defaultLocale: 'en' }), - }) - // first render there is no load - expect(result.current.t('title')).toEqual('') + it( + 'should use defaultLoad, useTranslation, switch local and translate', + async () => { + const { result } = renderHook( + () => useTranslation(['test']), + { + wrapper: wrapper({ defaultLocale: 'en' }), + }, + ) + // first render there is no load + expect(result.current.t('title')).toEqual('') - await waitFor(() => { - // after load of en locale - expect(result.current.t('title')).toEqual(en.title) - }) + await waitFor(() => { + // after load of en locale + expect(result.current.t('title')).toEqual(en.title) + }) - await act(async () => { - await result.current.switchLocale('fr') - }) + await act(async () => { + await result.current.switchLocale('fr') + }) - await waitFor(() => { - expect(result.current.t('title')).toEqual(fr.title) - }) + await waitFor(() => { + expect(result.current.t('title')).toEqual(fr.title) + }) - await act(async () => { - await result.current.switchLocale('es') - }) + await act(async () => { + await result.current.switchLocale('es') + }) - await waitFor(() => { - expect(result.current.t('title')).toEqual(es.title) - }) - }) + await waitFor(() => { + expect(result.current.t('title')).toEqual(es.title) + }) + }, + {}, + ) it('should use specific load on useTranslation', async () => { const { result } = renderHook( @@ -262,7 +269,8 @@ describe('i18n hook', () => { it('should work with a component', async () => { const { result } = renderHook( - () => useTranslation<{ 'with.identifier': 'Hello {identifier}' }>([]), + () => + useTranslation<{ 'with.identifier': 'Hello {identifier}' }>(['test']), { wrapper: wrapper({ defaultLocale: 'en' }), }, diff --git a/packages/use-i18n/src/usei18n.tsx b/packages/use-i18n/src/usei18n.tsx index df71262c6..492c172f5 100644 --- a/packages/use-i18n/src/usei18n.tsx +++ b/packages/use-i18n/src/usei18n.tsx @@ -162,12 +162,15 @@ export function useTranslation< } const { loadTranslations, namespaces: loadedNamespaces } = context + // here we generate a key string from the array of namespace in order to only trigger the use effect + // when the passed keys change and not when the ref of the array change + const key = namespaces.join(',') useEffect(() => { // eslint-disable-next-line @typescript-eslint/no-floating-promises - namespaces.map(async (namespace: string) => - loadTranslations(namespace, load), - ) - }, [loadTranslations, namespaces, load]) + key + .split(',') + .map(async (namespace: string) => loadTranslations(namespace, load)) + }, [loadTranslations, key, load]) const isLoaded = useMemo( () => areNamespacesLoaded(namespaces, loadedNamespaces), From 50d5912ad7f8da95053f1777e25c5b619e2fc688 Mon Sep 17 00:00:00 2001 From: Alexandre Combemorel Date: Tue, 18 Nov 2025 18:11:36 +0100 Subject: [PATCH 3/3] docs: changeset --- .changeset/breezy-yaks-taste.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/breezy-yaks-taste.md diff --git a/.changeset/breezy-yaks-taste.md b/.changeset/breezy-yaks-taste.md new file mode 100644 index 000000000..7f876fe0f --- /dev/null +++ b/.changeset/breezy-yaks-taste.md @@ -0,0 +1,5 @@ +--- +"@scaleway/use-i18n": minor +--- + +fix: typing issue and force use of string array with at least one element for namespaces in useTranslation hook