diff --git a/packages/i18n/package.json b/packages/i18n/package.json index 7cde582e5..370286341 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -20,6 +20,7 @@ "@kit/shared": "workspace:^", "@kit/tailwind-config": "workspace:*", "@kit/tsconfig": "workspace:*", + "@tanstack/react-query": "5.29.2", "i18next": "^23.11.2", "i18next-browser-languagedetector": "7.2.1", "i18next-resources-to-backend": "^1.2.1", diff --git a/packages/i18n/src/i18n-provider.tsx b/packages/i18n/src/i18n-provider.tsx index 2082777d2..dcfd44d8d 100644 --- a/packages/i18n/src/i18n-provider.tsx +++ b/packages/i18n/src/i18n-provider.tsx @@ -1,8 +1,7 @@ 'use client'; -import type { InitOptions, i18n } from 'i18next'; - -let client: i18n; +import { useSuspenseQuery } from '@tanstack/react-query'; +import type { InitOptions } from 'i18next'; type Resolver = ( lang: string, @@ -17,23 +16,32 @@ export function I18nProvider({ settings: InitOptions; resolver: Resolver; }>) { - // If the client is not initialized or - // the language has changed, reinitialize the client - if (!client || client.language !== settings.lng) { - throw withI18nClient(settings, resolver); - } + useI18nClient(settings, resolver); return children; } -async function withI18nClient(settings: InitOptions, resolver: Resolver) { - if (typeof window !== 'undefined') { - const { initializeI18nClient } = await import('./i18n.client'); +/** + * @name useI18nClient + * @description A hook that initializes the i18n client. + * @param settings + * @param resolver + */ +function useI18nClient(settings: InitOptions, resolver: Resolver) { + return useSuspenseQuery({ + queryKey: ['i18n', settings.lng], + queryFn: async () => { + const isBrowser = typeof window !== 'undefined'; - client = await initializeI18nClient(settings, resolver); - } else { - const { initializeServerI18n } = await import('./i18n.server'); + if (isBrowser) { + const { initializeI18nClient } = await import('./i18n.client'); - client = await initializeServerI18n(settings, resolver); - } + return await initializeI18nClient(settings, resolver); + } else { + const { initializeServerI18n } = await import('./i18n.server'); + + return await initializeServerI18n(settings, resolver); + } + }, + }); } diff --git a/packages/i18n/src/i18n.client.ts b/packages/i18n/src/i18n.client.ts index 1909512b2..c9713c625 100644 --- a/packages/i18n/src/i18n.client.ts +++ b/packages/i18n/src/i18n.client.ts @@ -3,8 +3,6 @@ import LanguageDetector from 'i18next-browser-languagedetector'; import resourcesToBackend from 'i18next-resources-to-backend'; import { initReactI18next } from 'react-i18next'; -let clientInstance: i18n | null = null; - /** * Initialize the i18n instance on the client. * @param settings - the i18n settings @@ -14,10 +12,6 @@ export async function initializeI18nClient( settings: InitOptions, resolver: (lang: string, namespace: string) => Promise, ): Promise { - if (clientInstance) { - return Promise.resolve(clientInstance); - } - await i18next .use( resourcesToBackend(async (language, namespace, callback) => { @@ -47,7 +41,5 @@ export async function initializeI18nClient( }, ); - clientInstance = i18next; - - return clientInstance; + return i18next; } diff --git a/packages/i18n/src/i18n.server.ts b/packages/i18n/src/i18n.server.ts index b47c1a290..64385e13b 100644 --- a/packages/i18n/src/i18n.server.ts +++ b/packages/i18n/src/i18n.server.ts @@ -14,10 +14,6 @@ export async function initializeServerI18n( ) { const i18nInstance = createInstance(); - if (i18nInstance.isInitialized) { - return i18nInstance; - } - await i18nInstance .use( resourcesToBackend(async (language, namespace, callback) => { @@ -36,11 +32,20 @@ export async function initializeServerI18n( }), ) .use(initReactI18next) - .init(settings); + .init(settings, (error) => { + if (error) { + console.error('Error initializing i18n server', error); + } + }); return i18nInstance; } +/** + * Parse the accept-language header value and return the languages that are included in the accepted languages. + * @param languageHeaderValue + * @param acceptedLanguages + */ export function parseAcceptLanguageHeader( languageHeaderValue: string | null | undefined, acceptedLanguages: string[], diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 74be89f7e..e460ce8d5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -989,6 +989,9 @@ importers: '@kit/tsconfig': specifier: workspace:* version: link:../../tooling/typescript + '@tanstack/react-query': + specifier: 5.29.2 + version: 5.29.2(react@18.2.0) i18next: specifier: ^23.11.2 version: 23.11.2