@shelchin/svelte-i18n
Version:
The last Svelte i18n library you'll ever need. Type-safe, AI-powered, zero-config.
103 lines (102 loc) • 4.48 kB
JavaScript
/**
* Universal load function for i18n (+layout.ts)
* Handles both server and client-side initialization
*/
import { browser } from '$app/environment';
/**
* Universal load function for i18n
* Use this in your +layout.ts file
*
* @param i18n - The i18n instance
* @param data - Data from parent layout (server data)
* @param url - Optional URL for pathname detection
* @param options - Configuration options
*/
export async function loadI18nUniversal(i18n, data, url, options) {
const storageKey = options?.storageKey || 'i18n-locale';
// On client, first ensure auto-discovery is completed
if (browser && typeof window !== 'undefined') {
// FIRST: Ensure auto-discovered languages are registered
// This must happen BEFORE attempting to set any locale
if ('clientLoad' in i18n && typeof i18n.clientLoad === 'function') {
console.log('[loadI18nUniversal] Running clientLoad to register auto-discovered languages');
try {
// Call clientLoad with skipLocaleRestore=true to only load translations
// We'll handle locale restoration ourselves after
await i18n.clientLoad({ skipLocaleRestore: true });
}
catch (error) {
console.warn('[loadI18nUniversal] clientLoad failed:', error);
}
}
// THEN: Try to restore locale from localStorage
try {
const storedLocale = localStorage.getItem(storageKey);
console.log(`[loadI18nUniversal] localStorage locale: ${storedLocale}, server data locale: ${data?.locale}`);
console.log(`[loadI18nUniversal] Available locales after clientLoad:`, i18n.locales);
// Priority: localStorage > server data > current locale
if (storedLocale) {
// Wait a tiny bit to ensure all async operations in clientLoad are complete
// This is a workaround for potential race conditions
await new Promise((resolve) => setTimeout(resolve, 10));
// Try to set the stored locale - setLocale will handle loading if needed
console.log(`[loadI18nUniversal] Attempting to restore locale from localStorage: ${storedLocale}`);
console.log(`[loadI18nUniversal] Available locales before setLocale:`, i18n.locales);
await i18n.setLocale(storedLocale);
// Mark locale as restored to prevent duplicate restoration
if ('localeRestored' in i18n) {
i18n.localeRestored = true;
}
}
else if (data?.locale && data.locale !== i18n.locale) {
// Use server-provided locale only if different from current
console.log(`[loadI18nUniversal] Using server locale: ${data.locale}`);
await i18n.setLocale(data.locale);
// Mark locale as restored to prevent duplicate restoration
if ('localeRestored' in i18n) {
i18n.localeRestored = true;
}
}
else {
console.log(`[loadI18nUniversal] Keeping current locale: ${i18n.locale}`);
// Mark locale as restored even if we kept the current locale
if ('localeRestored' in i18n) {
i18n.localeRestored = true;
}
}
}
catch (e) {
console.warn('[loadI18nUniversal] Failed to restore locale:', e);
// Fall back to server locale if available
if (data?.locale) {
try {
await i18n.setLocale(data.locale);
}
catch {
// Ignore fallback error
}
}
}
}
else if (data?.locale) {
// On server or during SSR, use data from server
if (i18n.locales.includes(data.locale)) {
await i18n.setLocale(data.locale);
}
}
// Return combined data
return {
locale: i18n.locale,
locales: data?.locales || i18n.locales,
i18nReady: true,
...(data || {})
};
}
/**
* Backward compatible universal load function
* @deprecated Use loadI18nUniversal instead
*/
export async function i18nUniversalLoad(i18n, data, browser, options) {
// Delegate to new implementation
return loadI18nUniversal(i18n, data, undefined, options);
}