UNPKG

@shelchin/svelte-i18n

Version:

The last Svelte i18n library you'll ever need. Type-safe, AI-powered, zero-config.

170 lines (169 loc) 6.33 kB
/** * Client-side initialization functions for i18n * Handles browser-specific initialization and hydration */ import { browser } from '$app/environment'; /** * Setup i18n on client with SSR data * Handles hydration of SSR translations * * @param i18n - The i18n instance * @param data - SSR data from server * @param options - Configuration options */ export function setupI18nClient(i18n, data, options) { const defaultLocale = options?.defaultLocale || data?.locale || i18n.locale || 'en'; const storageKey = options?.storageKey || 'i18n-locale'; // Handle SSR translations for auto-discovered languages if (data?.ssrTranslations && data?.locale) { // Load SSR translations immediately to prevent flash const loadSync = i18n.loadLanguageSync; if (loadSync && typeof loadSync === 'function') { loadSync.call(i18n, data.locale, data.ssrTranslations); } } // For static builds, prioritize localStorage over SSR data // Check if we have a stored locale that should take precedence let actualLocale = data?.locale || defaultLocale; let shouldUseStoredLocale = false; if (browser) { try { const storedLocale = localStorage.getItem(storageKey); if (storedLocale && i18n.locales.includes(storedLocale)) { shouldUseStoredLocale = true; actualLocale = storedLocale; console.log(`[setupI18nClient] Found stored locale: ${storedLocale}, will use it instead of SSR data`); // Set the stored locale immediately const setLocaleSync = i18n.setLocaleSync; if (setLocaleSync && typeof setLocaleSync === 'function') { setLocaleSync.call(i18n, storedLocale); } } } catch (e) { console.warn('[setupI18nClient] Failed to check stored locale:', e); } } // Only use SSR data if we don't have a stored locale if (!shouldUseStoredLocale && data?.locale && data.locale !== i18n.locale && i18n.locales.includes(data.locale)) { console.log(`[setupI18nClient] Setting locale from SSR data: ${data.locale}`); // Use synchronous method if available const setLocaleSync = i18n.setLocaleSync; if (setLocaleSync && typeof setLocaleSync === 'function') { setLocaleSync.call(i18n, data.locale); } else { // Queue async operation i18n.setLocale(data.locale).catch(console.error); } } // Only save to localStorage if we're not using a stored locale // This prevents overwriting the user's preference with SSR data if (browser && !shouldUseStoredLocale && actualLocale) { try { console.log(`[setupI18nClient] Saving initial locale to storage: ${actualLocale}`); localStorage.setItem(storageKey, actualLocale); } catch (e) { console.warn('[setupI18nClient] Failed to save locale:', e); } } return { locale: actualLocale, locales: data?.locales || i18n.locales, i18nReady: true }; } /** * Initialize i18n on mount (client-side only) * Use this in your +layout.svelte onMount * * @param i18n - The i18n instance * @param data - SSR data * @param options - Configuration options */ export async function initI18nOnMount(i18n, _data, options) { if (!browser) return; const storageKey = options?.storageKey || 'i18n-locale'; // Run custom initialization if provided // Don't pass skipLocaleRestore here - let the init function handle locale restoration if (options?.initFunction) { await options.initFunction(i18n); } // Always try to restore locale from localStorage // This ensures persistence works across page refreshes try { const storedLocale = localStorage.getItem(storageKey); console.log(`[initI18nOnMount] Stored locale: ${storedLocale}, current locale: ${i18n.locale}`); if (storedLocale) { // Always try to set the stored locale, even if it matches current // This ensures the locale is properly set after page refresh const allLocales = [...i18n.locales]; // Also check availableLocales if the instance has it if (i18n.availableLocales) { allLocales.push(...i18n.availableLocales); } // Remove duplicates const uniqueLocales = [...new Set(allLocales)]; if (uniqueLocales.includes(storedLocale)) { console.log(`[initI18nOnMount] Setting/restoring locale to: ${storedLocale}`); await i18n.setLocale(storedLocale); } else { console.log(`[initI18nOnMount] Stored locale ${storedLocale} not in available locales:`, uniqueLocales); } } } catch (e) { console.warn('[initI18nOnMount] Failed to restore locale:', e); } // Subscribe to locale changes to save preference if (i18n.subscribe) { i18n.subscribe((state) => { if (browser && state?.locale) { try { localStorage.setItem(storageKey, state.locale); } catch (e) { console.warn('[initI18nOnMount] Failed to save locale:', e); } } }); } return { locale: i18n.locale, locales: i18n.locales, i18nReady: true }; } /** * Check if i18n is ready (translations loaded) * * @param i18n - The i18n instance * @param data - SSR data */ export function i18nIsReady(i18n, data) { const locale = data?.locale || i18n.locale; return i18n.locales.includes(locale); } /** * Backward compatible client init function * @deprecated Use setupI18nClient or initI18nOnMount instead */ export async function i18nClientInit(i18n, data, options) { // Setup client first setupI18nClient(i18n, data, options); // Then run mount initialization if in browser if (browser) { await initI18nOnMount(i18n, data, options); } return { locale: i18n.locale, locales: data?.locales || i18n.locales, i18nReady: true }; }