@shelchin/svelte-i18n
Version:
The last Svelte i18n library you'll ever need. Type-safe, AI-powered, zero-config.
174 lines (173 loc) • 5.92 kB
JavaScript
/**
* Unified persistence module for i18n locale management
* Handles both client-side (localStorage) and universal (cookie + localStorage) persistence
*/
import { getBrowserLocale } from '../utils/browser-detection.js';
// Default configuration
const DEFAULT_COOKIE_NAME = 'i18n-locale';
const DEFAULT_STORAGE_KEY = 'i18n-locale';
// ============================================
// Cookie utilities
// ============================================
/**
* Parse cookies from a cookie string
*/
function parseCookies(cookieString) {
const cookies = {};
if (!cookieString)
return cookies;
cookieString.split(';').forEach((cookie) => {
const [name, value] = cookie.trim().split('=');
if (name && value) {
cookies[name] = decodeURIComponent(value);
}
});
return cookies;
}
/**
* Get locale from cookies (works on both server and client)
*/
export function getLocaleFromCookie(cookieString, cookieName = DEFAULT_COOKIE_NAME) {
const cookies = parseCookies(cookieString);
return cookies[cookieName] || null;
}
/**
* Set locale in cookie (client-side only)
*/
export function setLocaleCookie(locale, cookieName = DEFAULT_COOKIE_NAME) {
if (typeof document !== 'undefined') {
// Set cookie with 1 year expiry
const expires = new Date();
expires.setFullYear(expires.getFullYear() + 1);
// For localhost, don't set domain to avoid issues
// Also use max-age as a fallback to expires
const maxAge = 365 * 24 * 60 * 60; // 1 year in seconds
document.cookie = `${cookieName}=${encodeURIComponent(locale)}; expires=${expires.toUTCString()}; max-age=${maxAge}; path=/; SameSite=Lax`;
console.log(`[setLocaleCookie] Set cookie: ${cookieName}=${locale}`);
}
}
// ============================================
// LocalStorage utilities
// ============================================
/**
* Get locale from localStorage (client-side only)
*/
export function getLocaleFromStorage(storageKey = DEFAULT_STORAGE_KEY) {
if (typeof window !== 'undefined' && window.localStorage) {
try {
return localStorage.getItem(storageKey);
}
catch {
// Silent fail
}
}
return null;
}
/**
* Set locale in localStorage (client-side only)
*/
export function setLocaleStorage(locale, storageKey = DEFAULT_STORAGE_KEY) {
if (typeof window !== 'undefined' && window.localStorage) {
try {
localStorage.setItem(storageKey, locale);
}
catch {
// Silent fail
}
}
}
// ============================================
// Universal persistence (cookie + localStorage)
// ============================================
/**
* Save locale to both cookie and localStorage
*/
export function saveLocaleUniversal(locale, config) {
const { cookieName = DEFAULT_COOKIE_NAME, storageKey = DEFAULT_STORAGE_KEY } = config || {};
// Save to cookie (for SSR)
setLocaleCookie(locale, cookieName);
// Save to localStorage (for client-side persistence)
setLocaleStorage(locale, storageKey);
}
/**
* Get initial locale from cookie or localStorage
* Priority: cookie > localStorage > browser > default
*/
export function getInitialLocaleUniversal(defaultLocale, cookieString, config) {
const { cookieName = DEFAULT_COOKIE_NAME, storageKey = DEFAULT_STORAGE_KEY, enableBrowserDetection = false // Default to false, respect configured default
} = config || {};
// First priority: cookie (works on server and client)
if (cookieString) {
const cookieLocale = getLocaleFromCookie(cookieString, cookieName);
if (cookieLocale) {
return cookieLocale;
}
}
// Second priority: localStorage (client-side only)
const storageLocale = getLocaleFromStorage(storageKey);
if (storageLocale) {
return storageLocale;
}
// Third priority: browser language detection (only if explicitly enabled)
if (enableBrowserDetection) {
const browserLang = getBrowserLocale();
if (browserLang) {
const langCode = browserLang.split('-')[0];
return langCode;
}
}
// Fallback to default
return defaultLocale;
}
// ============================================
// Simple persistence API (backward compatibility)
// ============================================
/**
* Save the selected locale to localStorage and cookie
*/
export function saveLocale(locale) {
saveLocaleUniversal(locale, { storageKey: DEFAULT_STORAGE_KEY });
}
/**
* Load the saved locale from localStorage
*/
export function loadSavedLocale() {
return getLocaleFromStorage(DEFAULT_STORAGE_KEY);
}
/**
* Clear the saved locale from both localStorage and cookie
*/
export function clearSavedLocale() {
if (typeof window !== 'undefined' && window.localStorage) {
try {
localStorage.removeItem(DEFAULT_STORAGE_KEY);
// Also clear cookie for consistency
if (typeof document !== 'undefined') {
document.cookie = `${DEFAULT_STORAGE_KEY}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
}
}
catch (error) {
console.error('Failed to clear locale:', error);
}
}
}
/**
* Get initial locale based on priority:
* 1. Saved locale from localStorage
* 2. Browser language
* 3. Default locale
*/
export function getInitialLocale(defaultLocale, availableLocales) {
// First priority: saved locale
const savedLocale = loadSavedLocale();
if (savedLocale && (!availableLocales || availableLocales.includes(savedLocale))) {
return savedLocale;
}
// Second priority: browser language
const browserLocale = getBrowserLocale(availableLocales);
if (browserLocale) {
return browserLocale;
}
// Fallback to default
return defaultLocale;
}