diff --git a/apps/web/src/i18n.ts b/apps/web/src/i18n.ts index f7542ffba..c78d5db43 100644 --- a/apps/web/src/i18n.ts +++ b/apps/web/src/i18n.ts @@ -2,7 +2,7 @@ import i18n from 'i18next' import I18NextHttpBackend from 'i18next-http-backend' import { initReactI18next } from 'react-i18next' -import { clientI18nConfig } from '@lifeforge/localization' +import { clientI18nConfig, setI18n } from '@lifeforge/localization' import forgeAPI from './forgeAPI' @@ -40,11 +40,12 @@ export async function initI18n() { await i18n.init( clientI18nConfig({ - i18n, forgeAPI, getAvailableLanguages: () => AVAILABLE_LANG }) ) + setI18n(i18n) + return i18n } diff --git a/apps/web/src/providers/index.tsx b/apps/web/src/providers/index.tsx index 29dd18bba..fc02923dd 100644 --- a/apps/web/src/providers/index.tsx +++ b/apps/web/src/providers/index.tsx @@ -10,7 +10,6 @@ import { SocketProvider } from '@lifeforge/api' import { FederationProvider } from '@lifeforge/federation' -import { I18nInitProvider } from '@lifeforge/localization' import { APIOnlineStatusWrapper, BackgroundProvider, @@ -32,6 +31,7 @@ import AppRoutesProvider from '@/routes/providers/AppRoutesProvider' import ExternalModuleProviders from './features/ExternalModuleProviders' import UserPersonalizationProvider from './features/UserPersonalizationProvider' import { constructComponentTree, defineProviders } from './utils/providerUtils' +import { I18nInitProvider } from '@lifeforge/localization'; const queryClient = new QueryClient() diff --git a/bun.lock b/bun.lock index b09176f1d..41e116a6b 100644 --- a/bun.lock +++ b/bun.lock @@ -174,7 +174,6 @@ "autoprefixer": "^10.4.21", "copy-to-clipboard": "^3.3.3", "dayjs": "^1.11.18", - "i18next": "^25.6.0", "lodash": "^4.17.21", "mermaid": "^11.12.2", "postcss": "^8.5.6", @@ -737,16 +736,6 @@ "dependencies": { "@lifeforge/federation": "workspace:*", }, - "devDependencies": { - "@types/react": "^19.2.0", - "i18next": "^25.7.4", - "react-i18next": "^16.5.1", - }, - "peerDependencies": { - "i18next": "^25.7.4", - "react": "^19.2.0", - "react-i18next": "^16.5.1", - }, }, "packages/log": { "name": "@lifeforge/log", diff --git a/docs/package.json b/docs/package.json index e4e4fbba8..bb2c10cb7 100644 --- a/docs/package.json +++ b/docs/package.json @@ -27,7 +27,6 @@ "autoprefixer": "^10.4.21", "copy-to-clipboard": "^3.3.3", "dayjs": "^1.11.18", - "i18next": "^25.6.0", "@lifeforge/api": "workspace:*", "@lifeforge/ui": "workspace:*", "lodash": "^4.17.21", diff --git a/packages/localization/package.json b/packages/localization/package.json index e4198a89c..bb43199b8 100644 --- a/packages/localization/package.json +++ b/packages/localization/package.json @@ -11,15 +11,5 @@ }, "dependencies": { "@lifeforge/federation": "workspace:*" - }, - "peerDependencies": { - "react": "^19.2.0", - "react-i18next": "^16.5.1", - "i18next": "^25.7.4" - }, - "devDependencies": { - "@types/react": "^19.2.0", - "react-i18next": "^16.5.1", - "i18next": "^25.7.4" } } diff --git a/packages/localization/src/config/client-i18n.config.ts b/packages/localization/src/config/client-i18n.config.ts index 08716ec40..46533f64e 100644 --- a/packages/localization/src/config/client-i18n.config.ts +++ b/packages/localization/src/config/client-i18n.config.ts @@ -1,7 +1,6 @@ import type { InitOptions, i18n } from 'i18next' interface ClientI18nConfigOptions { - i18n: i18n forgeAPI: { locales: { getLocale: { @@ -21,7 +20,6 @@ interface ClientI18nConfigOptions { } export function clientI18nConfig({ - i18n, forgeAPI, getAvailableLanguages }: ClientI18nConfigOptions): InitOptions { diff --git a/packages/localization/src/getI18n.ts b/packages/localization/src/getI18n.ts new file mode 100644 index 000000000..6d99b020a --- /dev/null +++ b/packages/localization/src/getI18n.ts @@ -0,0 +1,11 @@ +import type { i18n } from 'i18next' + +let _i18nInstance: i18n | null = null + +export function getI18n(): i18n | null { + return _i18nInstance +} + +export function setI18n(instance: i18n): void { + _i18nInstance = instance +} diff --git a/packages/localization/src/hooks/useLanguageEffect.ts b/packages/localization/src/hooks/useLanguageEffect.ts new file mode 100644 index 000000000..3fb0a6156 --- /dev/null +++ b/packages/localization/src/hooks/useLanguageEffect.ts @@ -0,0 +1,19 @@ +import { useEffect } from 'react' + +import { getI18n } from '../getI18n' + +export function useLanguageEffect(language: string) { + useEffect(() => { + const i18n = getI18n() + + if (!i18n?.changeLanguage) { + return + } + + if (i18n.language !== language) { + i18n.changeLanguage(language).catch(() => { + console.error('Failed to change language.') + }) + } + }, [language]) +} diff --git a/packages/localization/src/providers/useModuleTranslation.ts b/packages/localization/src/hooks/useModuleTranslation.ts similarity index 100% rename from packages/localization/src/providers/useModuleTranslation.ts rename to packages/localization/src/hooks/useModuleTranslation.ts diff --git a/packages/localization/src/index.ts b/packages/localization/src/index.ts index ec20c28cd..833cdf3e5 100644 --- a/packages/localization/src/index.ts +++ b/packages/localization/src/index.ts @@ -1,5 +1,9 @@ export { clientI18nConfig } from './config/client-i18n.config' -export { I18nInitProvider } from './providers/I18nInitProvider' +export { getI18n, setI18n } from './getI18n' -export { useModuleTranslation } from './providers/useModuleTranslation' +export { useLanguageEffect } from './hooks/useLanguageEffect' + +export { useModuleTranslation } from './hooks/useModuleTranslation' + +export { I18nInitProvider } from './providers/I18nInitProvider' diff --git a/packages/ui/src/providers/PersonalizationProvider/hooks/useLanguageEffect.tsx b/packages/ui/src/providers/PersonalizationProvider/hooks/useLanguageEffect.tsx deleted file mode 100644 index d3d2fa71c..000000000 --- a/packages/ui/src/providers/PersonalizationProvider/hooks/useLanguageEffect.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import i18n from 'i18next' -import { useEffect } from 'react' - -import { toast } from '@/providers' - -function useLanguageEffect(language: string) { - useEffect(() => { - if (!i18n || !i18n.changeLanguage) { - console.error('i18n instance is not available') - - return - } - - if (i18n.isInitialized && i18n.language !== language) { - i18n.changeLanguage(language).catch(() => { - toast.error('Failed to change language.') - }) - } - }, [language]) -} - -export default useLanguageEffect diff --git a/packages/ui/src/providers/PersonalizationProvider/index.tsx b/packages/ui/src/providers/PersonalizationProvider/index.tsx index 6d11e305e..824b531f2 100644 --- a/packages/ui/src/providers/PersonalizationProvider/index.tsx +++ b/packages/ui/src/providers/PersonalizationProvider/index.tsx @@ -6,11 +6,12 @@ import type { ProxyTree } from '@lifeforge/api' import { BG_THEME } from './constants/bg_theme' import THEME_COLOR_HEX from './constants/theme_color_hex' +import { useLanguageEffect } from '@lifeforge/localization' + import useBgTempEffect from './hooks/useBgTempEffect' import useBorderRadiusEffect from './hooks/useBorderRadiusEffect' import useBorderedEffect from './hooks/useBorderedEffect' import useFontFamily from './hooks/useFontFamilyEffect' -import useLanguageEffect from './hooks/useLanguageEffect' import useMetaEffect from './hooks/useMetaEffect' import useRawThemeColorEffect from './hooks/useRawThemeColorEffect' import useThemeEffect from './hooks/useThemeEffect'