initial commit
Some checks failed
build / lint (push) Failing after 36s
build / build (push) Has been skipped

This commit is contained in:
2026-01-29 16:13:04 +00:00
commit a32badd025
31 changed files with 6256 additions and 0 deletions

77
app/hooks/useI18n.ts Normal file
View File

@@ -0,0 +1,77 @@
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import de from "@/locales/de.json";
import en from "@/locales/en.json";
import es from "@/locales/es.json";
import fr from "@/locales/fr.json";
import it from "@/locales/it.json";
import sv from "@/locales/sv.json";
const bundles = { en, es, fr, de, it, sv } as const;
export type Locale = keyof typeof bundles;
export type MessageKey = string;
export type LocaleOption = {
code: Locale;
name: string;
emoji: string;
};
const localeOptions: LocaleOption[] = [
{ code: "en", name: "English", emoji: "🇺🇸" },
{ code: "es", name: "Español", emoji: "🇪🇸" },
{ code: "fr", name: "Français", emoji: "🇫🇷" },
{ code: "de", name: "Deutsch", emoji: "🇩🇪" },
{ code: "it", name: "Italiano", emoji: "🇮🇹" },
{ code: "sv", name: "Svenska", emoji: "🇸🇪" },
];
export function useI18n(defaultLocale: Locale = "en") {
const [locale, setLocale] = useState<Locale>(defaultLocale);
const hasDetectedLocale = useRef(false);
useEffect(() => {
if (hasDetectedLocale.current) return;
hasDetectedLocale.current = true;
const navLangs =
typeof navigator !== "undefined" ? navigator.languages || [navigator.language] : [];
const mapToLocale = (lang: string | undefined | null): Locale | null => {
if (!lang) return null;
const lower = lang.toLowerCase();
if (lower.startsWith("es")) return "es";
if (lower.startsWith("fr")) return "fr";
if (lower.startsWith("de")) return "de";
if (lower.startsWith("it")) return "it";
if (lower.startsWith("sv")) return "sv";
if (lower.startsWith("en")) return "en";
return null;
};
const detected = navLangs.map((l) => mapToLocale(l)).find(Boolean);
if (detected && detected !== locale) {
setLocale(detected);
}
}, [locale]);
const t = useCallback(
(key: MessageKey, vars?: Record<string, string>): string => {
const parts = key.split(".");
const dict = bundles[locale] ?? bundles.en;
const fallbackDict = bundles.en;
const resolveKey = (source: unknown) =>
parts.reduce<unknown>(
(acc, part) =>
acc && typeof acc === "object" ? (acc as Record<string, unknown>)[part] : undefined,
source
);
const value = resolveKey(dict) ?? resolveKey(fallbackDict);
const text = typeof value === "string" ? value : key;
if (!vars) return text;
return text.replace(/\{(\w+)\}/g, (_: string, k: string) => (vars[k] ? vars[k] : `{${k}}`));
},
[locale]
);
const options = useMemo(() => localeOptions, []);
return { locale, setLocale, t, localeOptions: options };
}