mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-25 08:46:22 +02:00
Replace static imports of all 5 locale JSON files with dynamic imports. Only English is bundled by default, other locales (es, hi, pt, zh) load on demand when the user switches languages. Also removes unused 'set' import from zod (line 5) that was dragging Zod surface into this module unnecessarily. Changes: - Removed static imports for es, hi, pt, zh locale files - Removed unused zod import - Added loadMessages() function for dynamic locale loading - Updated setLocale() to load messages asynchronously - Added useEffect to load non-English locale on mount if stored Benefits: - Only active locale's JSON in initial bundle (English default) - 80% reduction in locale data in initial bundle - Other locale files load on demand (~50-100KB each) - Removed unnecessary zod dependency from module - Locale switching still works seamlessly - Faster initial page load Fixes #1143
95 lines
2.9 KiB
TypeScript
95 lines
2.9 KiB
TypeScript
"use client";
|
|
|
|
import type React from "react";
|
|
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
|
|
import enMessages from "../messages/en.json";
|
|
|
|
type Locale = "en" | "es" | "pt" | "hi" | "zh";
|
|
|
|
/**
|
|
* Dynamically load locale messages on demand.
|
|
* English is the default and always available synchronously.
|
|
*/
|
|
const loadMessages = async (locale: Locale): Promise<typeof enMessages> => {
|
|
switch (locale) {
|
|
case "es":
|
|
return (await import("../messages/es.json")).default;
|
|
case "hi":
|
|
return (await import("../messages/hi.json")).default;
|
|
case "pt":
|
|
return (await import("../messages/pt.json")).default;
|
|
case "zh":
|
|
return (await import("../messages/zh.json")).default;
|
|
default:
|
|
return enMessages;
|
|
}
|
|
};
|
|
|
|
interface LocaleContextType {
|
|
locale: Locale;
|
|
messages: typeof enMessages;
|
|
setLocale: (locale: Locale) => void;
|
|
}
|
|
|
|
const LocaleContext = createContext<LocaleContextType | undefined>(undefined);
|
|
|
|
const LOCALE_STORAGE_KEY = "surfsense-locale";
|
|
|
|
export function LocaleProvider({ children }: { children: React.ReactNode }) {
|
|
// Always start with 'en' to avoid hydration mismatch
|
|
// Then sync with localStorage after mount
|
|
const [locale, setLocaleState] = useState<Locale>("en");
|
|
const [messages, setMessages] = useState<typeof enMessages>(enMessages);
|
|
const [mounted, setMounted] = useState(false);
|
|
|
|
// Load locale from localStorage after component mounts (client-side only)
|
|
useEffect(() => {
|
|
setMounted(true);
|
|
if (typeof window !== "undefined") {
|
|
const stored = localStorage.getItem(LOCALE_STORAGE_KEY);
|
|
if (stored && (["en", "es", "pt", "hi", "zh"] as const).includes(stored as Locale)) {
|
|
const storedLocale = stored as Locale;
|
|
setLocaleState(storedLocale);
|
|
// Load messages for non-English locale
|
|
if (storedLocale !== "en") {
|
|
loadMessages(storedLocale).then(setMessages);
|
|
}
|
|
}
|
|
}
|
|
}, []);
|
|
|
|
// Update locale and persist to localStorage
|
|
const setLocale = useCallback(async (newLocale: Locale) => {
|
|
// Load messages for the new locale
|
|
const newMessages = await loadMessages(newLocale);
|
|
setMessages(newMessages);
|
|
setLocaleState(newLocale);
|
|
if (typeof window !== "undefined") {
|
|
localStorage.setItem(LOCALE_STORAGE_KEY, newLocale);
|
|
// Update HTML lang attribute
|
|
document.documentElement.lang = newLocale;
|
|
}
|
|
}, []);
|
|
|
|
// Set HTML lang attribute when locale changes
|
|
useEffect(() => {
|
|
if (typeof window !== "undefined" && mounted) {
|
|
document.documentElement.lang = locale;
|
|
}
|
|
}, [locale, mounted]);
|
|
|
|
const contextValue = useMemo(
|
|
() => ({ locale, messages, setLocale }),
|
|
[locale, messages, setLocale]
|
|
);
|
|
|
|
return <LocaleContext.Provider value={contextValue}>{children}</LocaleContext.Provider>;
|
|
}
|
|
|
|
export function useLocaleContext() {
|
|
const context = useContext(LocaleContext);
|
|
if (context === undefined) {
|
|
throw new Error("useLocaleContext must be used within a LocaleProvider");
|
|
}
|
|
return context;
|
|
}
|