Finalish MVP

This commit is contained in:
mdares
2026-01-05 16:36:00 +00:00
parent 538b06bd4b
commit ea92b32618
19 changed files with 2289 additions and 701 deletions

60
lib/i18n/useI18n.ts Normal file
View File

@@ -0,0 +1,60 @@
"use client";
import { useCallback, useEffect, useMemo, useState } from "react";
import { defaultLocale, Locale, translate } from "./translations";
const LOCALE_COOKIE = "mis_locale";
const LOCALE_EVENT = "mis-locale-change";
function readCookieLocale(): Locale | null {
const match = document.cookie
.split(";")
.map((part) => part.trim())
.find((part) => part.startsWith(`${LOCALE_COOKIE}=`));
if (!match) return null;
const value = match.split("=")[1];
if (value === "es-MX" || value === "en") return value;
return null;
}
function readLocale(): Locale {
const docLang = document.documentElement.getAttribute("lang");
if (docLang === "es-MX" || docLang === "en") return docLang;
return readCookieLocale() ?? defaultLocale;
}
export function useI18n() {
const [locale, setLocale] = useState<Locale>(() => readLocale());
useEffect(() => {
const handler = (event: Event) => {
const detail = (event as CustomEvent).detail;
if (detail === "es-MX" || detail === "en") {
setLocale(detail);
}
};
window.addEventListener(LOCALE_EVENT, handler);
return () => window.removeEventListener(LOCALE_EVENT, handler);
}, []);
const setLocaleAndPersist = useCallback((next: Locale) => {
document.documentElement.setAttribute("lang", next);
document.cookie = `${LOCALE_COOKIE}=${next}; Path=/; Max-Age=31536000; SameSite=Lax`;
setLocale(next);
window.dispatchEvent(new CustomEvent(LOCALE_EVENT, { detail: next }));
}, [setLocale]);
const t = useCallback(
(key: string, vars?: Record<string, string | number>) => translate(locale, key, vars),
[locale]
);
return useMemo(
() => ({
locale,
setLocale: setLocaleAndPersist,
t,
}),
[locale, setLocaleAndPersist, t]
);
}