Live video on the AT Protocol
1// Simple i18n provider wrapper for consistent setup
2import type { i18n } from "i18next";
3import { ReactNode, useEffect, useState } from "react";
4import { I18nextProvider } from "react-i18next";
5
6interface I18nProviderProps {
7 children: ReactNode;
8 i18n: i18n;
9}
10
11/**
12 * Simple wrapper around I18nextProvider for consistent setup
13 * The actual i18n instance should be configured at the app level
14 * Waits for i18next to be initialized AND language loaded to prevent FOUC
15 */
16export function I18nProvider({ children, i18n }: I18nProviderProps) {
17 const [isReady, setIsReady] = useState(false);
18
19 useEffect(() => {
20 // Check if both initialized and language is loaded
21 const checkReady = () => {
22 const initialized = i18n.isInitialized;
23 const hasCommon = i18n.hasLoadedNamespace("common");
24 console.log("i18n ready check:", {
25 initialized,
26 hasCommon,
27 language: i18n.language,
28 });
29
30 if (initialized && hasCommon) {
31 setIsReady(true);
32 }
33 };
34
35 checkReady();
36
37 // Fallback: if not ready after 300ms, just proceed anyway
38 const fallbackTimeout = setTimeout(() => {
39 if (!isReady) {
40 console.log("i18n ready timeout - proceeding anyway");
41 setIsReady(true);
42 }
43 }, 300);
44
45 // Listen for both initialization and language loaded events
46 const handleInitialized = () => {
47 checkReady();
48 };
49 const handleLanguageLoaded = () => {
50 checkReady();
51 };
52
53 i18n.on("initialized", handleInitialized);
54 i18n.on("languageChanged", handleLanguageLoaded);
55 i18n.on("loaded", handleLanguageLoaded);
56
57 return () => {
58 clearTimeout(fallbackTimeout);
59 i18n.off("initialized", handleInitialized);
60 i18n.off("languageChanged", handleLanguageLoaded);
61 i18n.off("loaded", handleLanguageLoaded);
62 };
63 }, [i18n, isReady]);
64
65 if (!isReady) {
66 return null;
67 }
68
69 return <I18nextProvider i18n={i18n}>{children}</I18nextProvider>;
70}