First Commit

This commit is contained in:
cesnimda
2026-03-21 11:55:27 +01:00
commit 2e8a29b4d0
1757 changed files with 166084 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
import React, { createContext, useContext, useState } from "react";
import { translations, TranslationKey, UiLanguage } from "./translations";
type Ctx = {
language: UiLanguage;
setLanguage: (l: UiLanguage) => void;
t: (key: TranslationKey) => string;
};
const I18nContext = createContext<Ctx | null>(null);
export function I18nProvider({ children }: { children: React.ReactNode }) {
const [language, setLanguageState] = useState<UiLanguage>(() => {
const raw = window.localStorage.getItem("uiLanguage");
return raw === "no" ? "no" : "en";
});
const setLanguage = (l: UiLanguage) => {
setLanguageState(l);
window.localStorage.setItem("uiLanguage", l);
};
const t = (key: TranslationKey) => translations[language][key] ?? translations.en[key];
return <I18nContext.Provider value={{ language, setLanguage, t }}>{children}</I18nContext.Provider>;
}
export function useI18n() {
const ctx = useContext(I18nContext);
if (!ctx) throw new Error("useI18n must be used within I18nProvider");
return ctx;
}
+35
View File
@@ -0,0 +1,35 @@
export type UiLanguage = "en" | "no";
export const translations = {
en: {
appTitle: "Job Tracker",
dashboard: "Dashboard",
jobApplications: "Job Applications",
reminders: "Reminders",
kanbanBoard: "Kanban Board",
companies: "Companies",
trash: "Trash",
settings: "Settings",
addJob: "Add Job",
addJobApplication: "Add Job Application",
company: "Company",
location: "Location",
},
no: {
appTitle: "Jobbsporing",
dashboard: "Dashboard",
jobApplications: "Jobbsøknader",
reminders: "Påminnelser",
kanbanBoard: "Kanban-tavle",
companies: "Selskaper",
trash: "Papirkurv",
settings: "Innstillinger",
addJob: "Legg til jobb",
addJobApplication: "Legg til jobbsøknad",
company: "Selskap",
location: "Sted",
},
} as const;
export type TranslationKey = keyof typeof translations.en;