"use client"; import { createContext, useContext, useState, useEffect, useCallback, ReactNode } from "react"; import cs from "@/messages/cs.json"; import he from "@/messages/he.json"; import ru from "@/messages/ru.json"; import ua from "@/messages/ua.json"; export type Locale = "cs" | "he" | "ru" | "ua"; export const LOCALES: { code: Locale; label: string; flag: string; dir: "ltr" | "rtl" }[] = [ { code: "cs", label: "\u010ce\u0161tina", flag: "\ud83c\udde8\ud83c\uddff", dir: "ltr" }, { code: "he", label: "\u05e2\u05d1\u05e8\u05d9\u05ea", flag: "\ud83c\uddee\ud83c\uddf1", dir: "rtl" }, { code: "ru", label: "\u0420\u0443\u0441\u0441\u043a\u0438\u0439", flag: "\ud83c\uddf7\ud83c\uddfa", dir: "ltr" }, { code: "ua", label: "\u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430", flag: "\ud83c\uddfa\ud83c\udde6", dir: "ltr" }, ]; type Messages = typeof cs; const MESSAGES: Record = { cs, he, ru, ua }; const STORAGE_KEY = "taskteam_language"; function getNestedValue(obj: unknown, path: string): string { const keys = path.split("."); let current: unknown = obj; for (const key of keys) { if (current == null || typeof current !== "object") return path; current = (current as Record)[key]; } return typeof current === "string" ? current : path; } interface I18nContextType { locale: Locale; setLocale: (locale: Locale) => void; t: (key: string) => string; dir: "ltr" | "rtl"; isRTL: boolean; } const I18nContext = createContext({ locale: "cs", setLocale: () => {}, t: (key: string) => key, dir: "ltr", isRTL: false, }); export function useTranslation() { return useContext(I18nContext); } export function I18nProvider({ children }: { children: ReactNode }) { const [locale, setLocaleState] = useState("cs"); const [mounted, setMounted] = useState(false); useEffect(() => { setMounted(true); if (typeof window !== "undefined") { const stored = localStorage.getItem(STORAGE_KEY) as Locale | null; if (stored && MESSAGES[stored]) { setLocaleState(stored); } } }, []); const setLocale = useCallback((newLocale: Locale) => { setLocaleState(newLocale); if (typeof window !== "undefined") { localStorage.setItem(STORAGE_KEY, newLocale); } }, []); const t = useCallback( (key: string): string => { return getNestedValue(MESSAGES[locale], key); }, [locale] ); const localeInfo = LOCALES.find((l) => l.code === locale) || LOCALES[0]; const dir = localeInfo.dir; const isRTL = dir === "rtl"; // Update html attributes when locale changes useEffect(() => { if (!mounted) return; document.documentElement.lang = locale; document.documentElement.dir = dir; }, [locale, dir, mounted]); return ( {children} ); }