UNPKG

@shelchin/svelte-i18n

Version:

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

159 lines (158 loc) 6.68 kB
/** * Unified SSR load function for i18n * Combines the best features from both implementations */ import { extractLocaleFromPathname } from './pathname-locale.js'; /** * Server-side i18n loader with pathname detection support * This is the main implementation that handles all SSR scenarios * * Priority: pathname locale > cookie locale > default locale * * @param i18n - The i18n instance * @param cookies - SvelteKit cookies object * @param url - Optional URL for pathname locale detection * @param options - Configuration options * @returns SSR data including locale, translations, and metadata */ export async function loadI18nSSR(i18n, cookies, url, options) { const cookieName = options?.cookieName || 'i18n-locale'; const defaultLocale = options?.defaultLocale || i18n.locale || 'zh'; const namespace = options?.namespace || i18n.config?.namespace || 'app'; const pathname = url?.pathname || '/'; // Import server-side utilities (only available on server) let loadServerTranslations; let isAutoDiscoveredLocale; if (typeof window === 'undefined') { const serverLoader = await import('../services/ssr-file-loader.js'); loadServerTranslations = serverLoader.loadServerTranslations; isAutoDiscoveredLocale = serverLoader.isAutoDiscoveredLocale; } // Get locale from cookie const cookieLocale = cookies.get(cookieName); // Extract locale from pathname if URL is provided const pathnameLocale = url ? extractLocaleFromPathname(pathname) : null; console.log(`[loadI18nSSR] Cookie name: ${cookieName}, Cookie value: ${cookieLocale}, Pathname locale: ${pathnameLocale}`); // Determine locale with priority: pathname > cookie > default let locale = defaultLocale; // Priority 1: Check pathname locale if (pathnameLocale) { // Check if it's already loaded if (i18n.locales.includes(pathnameLocale)) { locale = pathnameLocale; } else if (typeof window === 'undefined' && isAutoDiscoveredLocale) { // On server, check if it's an auto-discovered locale if (isAutoDiscoveredLocale(pathnameLocale, namespace)) { locale = pathnameLocale; } } } // Priority 2: If no pathname locale, check cookie if (locale === defaultLocale && cookieLocale) { if (i18n.locales.includes(cookieLocale)) { locale = cookieLocale; } else if (typeof window === 'undefined' && isAutoDiscoveredLocale) { // Check if cookie locale is auto-discovered if (isAutoDiscoveredLocale(cookieLocale, namespace)) { locale = cookieLocale; } } } console.log(`[loadI18nSSR] Final determined locale: ${locale} (default: ${defaultLocale})`); // Try to load and set the locale if (locale) { if (!i18n.locales.includes(locale)) { // Try loading as auto-discovered locale if (typeof window === 'undefined' && loadServerTranslations && isAutoDiscoveredLocale) { if (isAutoDiscoveredLocale(locale, namespace)) { console.log(`[loadI18nSSR] Loading auto-discovered locale: ${locale}`); const loaded = loadServerTranslations(i18n, locale, namespace); if (loaded) { console.log(`[loadI18nSSR] Successfully loaded ${locale} for SSR`); // Use setLocaleSync if available to avoid issues with SSR if (i18n.setLocaleSync) { i18n.setLocaleSync(locale); } else { await i18n.setLocale(locale); } } } } } else { // Locale is already loaded, just set it console.log(`[loadI18nSSR] Setting already loaded locale: ${locale}`); // Use setLocaleSync if available to avoid issues with SSR if (i18n.setLocaleSync) { i18n.setLocaleSync(locale); } else { await i18n.setLocale(locale); } } } // Get all available locales including auto-discovered ones const allLocales = [...i18n.locales]; // Check for auto-discovered locales to include in the list if (typeof window === 'undefined') { try { const fs = await import('fs'); const path = await import('path'); const indexPath = path.join(process.cwd(), 'static', 'translations', 'index.json'); if (fs.existsSync(indexPath)) { const indexContent = fs.readFileSync(indexPath, 'utf-8'); const config = JSON.parse(indexContent); // Add auto-discovered locales to the list if (namespace === 'app' && config.autoDiscovery?.app) { for (const lang of config.autoDiscovery.app) { if (!allLocales.includes(lang)) { allLocales.push(lang); } } } else if (config.autoDiscovery?.packages?.[namespace]) { for (const lang of config.autoDiscovery.packages[namespace]) { if (!allLocales.includes(lang)) { allLocales.push(lang); } } } } } catch (error) { console.warn('[loadI18nSSR] Could not read auto-discovery config:', error); } } // Pass SSR translations for auto-discovered languages // This is CRITICAL for SSR - prevents flash of untranslated content let ssrTranslations = undefined; let isAutoDiscovered = false; if (locale && typeof window === 'undefined' && isAutoDiscoveredLocale) { if (isAutoDiscoveredLocale(locale, namespace)) { isAutoDiscovered = true; // Pass the translations for hydration to prevent flash ssrTranslations = i18n.translations?.[locale]; } } return { locale, locales: allLocales, ssrTranslations, isAutoDiscovered, i18nReady: true, cookieName, namespace }; } /** * Backward compatible server load function * Delegates to loadI18nSSR without URL parameter * * @deprecated Use loadI18nSSR instead for pathname support */ export async function i18nServerLoad(i18n, cookies, options) { return loadI18nSSR(i18n, cookies, undefined, options); }