Files
flxn-app/src/lib/i18n/provider.tsx
T
kyle 0a7b5fa00f
CI/CD Pipeline / Build and Push PocketBase Docker Image (push) Successful in 8s
CI/CD Pipeline / i18n Catalog Check (push) Failing after 10s
CI/CD Pipeline / Build and Push App Docker Image (push) Skipped
CI/CD Pipeline / Deploy to Kubernetes (push) Skipped
i18n
2026-08-08 15:29:40 -07:00

62 lines
2.0 KiB
TypeScript

import { useEffect, useMemo, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { I18nProvider } from "@lingui/react";
import { playerQueries } from "@/features/players/queries";
import {
createI18n,
ensureMessages,
hasCachedMessages,
resolveLocale,
} from "@/lib/i18n";
/**
* Must mount ABOVE AuthProvider: the localized server-query hooks (useMe
* included) call useLingui, so this provider cannot depend on auth context.
* It reads the same auth query via raw useQuery instead — passively (useMe
* is the active fetcher; SSR data is ensured in __root beforeLoad).
*/
export const LinguiProvider = ({ children }: { children: React.ReactNode }) => {
const { queryKey, queryFn } = playerQueries.auth();
const { data } = useQuery({
queryKey,
queryFn: async () => {
const result = await queryFn();
if (!result.success) throw new Error(result.error.userMessage);
return result.data;
},
staleTime: 30 * 1000,
refetchOnMount: false,
refetchOnWindowFocus: false,
});
const locale = resolveLocale(data?.metadata?.locale);
const [catalogVersion, setCatalogVersion] = useState(0);
// Fresh instance per locale (and per SSR request tree). __root beforeLoad
// preloads the catalog on authed routes; on public routes (login) it may
// not be cached yet — createI18n falls back to en until the effect below
// loads it and bumps catalogVersion.
const i18n = useMemo(
() => createI18n(locale),
// eslint-disable-next-line react-hooks/exhaustive-deps
[locale, catalogVersion]
);
useEffect(() => {
if (hasCachedMessages(locale)) return;
let cancelled = false;
ensureMessages(locale).then(() => {
if (!cancelled) setCatalogVersion((v) => v + 1);
});
return () => {
cancelled = true;
};
}, [locale]);
useEffect(() => {
document.documentElement.lang = locale;
}, [locale]);
return <I18nProvider i18n={i18n}>{children}</I18nProvider>;
};