-
-
- mail
-
-
- tipilan@ituk.ee
-
+
+
+ {t("footer.contact")}
+
+
+
+
{t("footer.studentUnion")}
+
-
-
- phone
-
-
- +372 5693 1193
-
+
+ {t("footer.organization")}
+
+
+
+ {t("footer.registrationCode")}:{" "}
+
+ 80391807
+
+
+
+ ICO-210, Raja tn 4c, Tallinn, Harjumaa, 12616
+
-
MTÜ For Tsükkel
-
-
- Registrikood:{" "}
-
- 80391807
-
-
-
- ICO-210, Raja tn 4c, Tallinn, Harjumaa, 12616
-
-
-
-);
+ );
+};
export default Footer;
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index 3c54ad5..381c1f6 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -12,6 +12,8 @@ import {
// Theme Provider
import { useTheme } from "next-themes";
+import LanguageSwitcher from "./LanguageSwitcher";
+
// Shadcn UI
import { Button } from "@/components/ui/button";
import {
@@ -24,65 +26,74 @@ import {
// Fonts
// import { vipnagorgialla } from "@/components/Vipnagorgialla";
-const Header = ({
- isOpen,
- toggleSidebar,
-}: {
+interface HeaderProps {
isOpen: boolean;
- toggleSidebar: () => void;
-}) => {
+ onToggle: () => void;
+ themeLabels: {
+ light: string;
+ dark: string;
+ system: string;
+ };
+}
+
+const Header = ({ isOpen, onToggle, themeLabels }: HeaderProps) => {
const { theme, setTheme } = useTheme();
return (
);
};
diff --git a/src/components/LanguageSwitcher.tsx b/src/components/LanguageSwitcher.tsx
new file mode 100644
index 0000000..53f3d02
--- /dev/null
+++ b/src/components/LanguageSwitcher.tsx
@@ -0,0 +1,47 @@
+"use client";
+
+import { useLocale } from "next-intl";
+import { useRouter, usePathname } from "@/i18n/routing";
+import { routing } from "@/i18n/routing";
+import { Button } from "@/components/ui/button";
+import { vipnagorgialla } from "@/components/Vipnagorgialla";
+
+export default function LanguageSwitcher() {
+ const locale = useLocale();
+ const router = useRouter();
+ const pathname = usePathname();
+
+ const getNextLocale = (): "et" | "en" => {
+ const currentIndex = routing.locales.indexOf(locale as "et" | "en");
+ const nextIndex = (currentIndex + 1) % routing.locales.length;
+ return routing.locales[nextIndex] as "et" | "en";
+ };
+
+ const getNextLanguageName = () => {
+ const nextLocale = getNextLocale();
+ switch (nextLocale) {
+ case "et":
+ return "EST";
+ case "en":
+ return "ENG";
+ default:
+ return nextLocale;
+ }
+ };
+
+ const handleLanguageSwitch = () => {
+ const nextLocale = getNextLocale();
+ router.replace(pathname, { locale: nextLocale });
+ };
+
+ return (
+
+ );
+}
diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx
deleted file mode 100644
index 086bb4c..0000000
--- a/src/components/Sidebar.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-"use client";
-
-// Fonts
-import { vipnagorgialla } from "@/components/Vipnagorgialla";
-
-// Use effect to handle route changes and close the sidebar if it's open
-// usePathName to listen to route changes in Next.js
-import { useEffect } from "react";
-import { usePathname } from "next/navigation";
-import Link from "next/link";
-
-const Sidebar = ({
- isOpen,
- toggleSidebar,
-}: {
- isOpen: boolean;
- toggleSidebar: () => void;
-}) => {
- const pathname = usePathname();
-
- useEffect(() => {
- if (isOpen) {
- toggleSidebar();
- }
- }, [pathname]);
-
- return (
- <>
-
-
-
- Avaleht
-
-
- Messiala
-
-
- Piletid
-
-
- Ajakava
-
-
- Turniirid
-
-
- Kodukord
-
-
- Reeglid
-
-
-
-
- >
- );
-};
-
-export default Sidebar;
diff --git a/src/components/SidebarLayoutClient.tsx b/src/components/SidebarLayoutClient.tsx
new file mode 100644
index 0000000..1fec6ce
--- /dev/null
+++ b/src/components/SidebarLayoutClient.tsx
@@ -0,0 +1,84 @@
+"use client";
+
+import { useState, useEffect } from "react";
+import { usePathname } from "@/i18n/routing";
+import { Link } from "@/i18n/routing";
+import { vipnagorgialla } from "@/components/Vipnagorgialla";
+import Header from "./Header";
+
+interface NavItem {
+ href:
+ | "/"
+ | "/ajakava"
+ | "/haldus"
+ | "/kodukord"
+ | "/messiala"
+ | "/piletid"
+ | "/reeglid"
+ | "/striim"
+ | "/turniirid";
+ label: string;
+}
+
+interface SidebarLayoutClientProps {
+ themeLabels: {
+ light: string;
+ dark: string;
+ system: string;
+ };
+ navItems: NavItem[];
+}
+
+export default function SidebarLayoutClient({
+ themeLabels,
+ navItems,
+}: SidebarLayoutClientProps) {
+ const [isOpen, setIsOpen] = useState(false);
+ const pathname = usePathname();
+
+ const toggleSidebar = () => setIsOpen(!isOpen);
+
+ // Close sidebar when route changes
+ useEffect(() => {
+ if (isOpen) {
+ setIsOpen(false);
+ }
+ }, [pathname]);
+
+ return (
+ <>
+
+
+ {/* Sidebar */}
+ <>
+
setIsOpen(false)}
+ >
+
+ {navItems.map((item) => (
+
+ {item.label}
+
+ ))}
+
+ >
+ >
+ );
+}
diff --git a/src/components/SidebarLayoutServer.tsx b/src/components/SidebarLayoutServer.tsx
new file mode 100644
index 0000000..97820b9
--- /dev/null
+++ b/src/components/SidebarLayoutServer.tsx
@@ -0,0 +1,26 @@
+import { getTranslations } from "next-intl/server";
+import SidebarLayoutClient from "./SidebarLayoutClient";
+
+export default async function SidebarLayoutServer() {
+ const t = await getTranslations("common");
+
+ const themeLabels = {
+ light: t("theme.light"),
+ dark: t("theme.dark"),
+ system: t("theme.system"),
+ };
+
+ const navT = await getTranslations("navigation");
+
+ const navItems = [
+ { href: "/" as const, label: navT("home") },
+ { href: "/messiala" as const, label: navT("expo") },
+ { href: "/piletid" as const, label: navT("tickets") },
+ { href: "/ajakava" as const, label: navT("schedule") },
+ { href: "/turniirid" as const, label: navT("tournaments") },
+ { href: "/kodukord" as const, label: navT("houserules") },
+ { href: "/reeglid" as const, label: navT("rules") },
+ ];
+
+ return
;
+}
diff --git a/src/components/SidebarParent.tsx b/src/components/SidebarParent.tsx
index eabb07b..8c4becb 100644
--- a/src/components/SidebarParent.tsx
+++ b/src/components/SidebarParent.tsx
@@ -1,22 +1,14 @@
-'use client';
-
-import { useState } from "react";
-import Header from "./Header";
-import Sidebar from "./Sidebar";
+import SidebarLayoutServer from "./SidebarLayoutServer";
const SidebarParent = () => {
- const [isOpen, setIsOpen] = useState(false);
- const toggleSidebar = () => setIsOpen(!isOpen);
-
- return (
-
-
-
-
- );
+ return (
+
+
+
+ );
};
-// This component is responsible for rendering the sidebar and header together.
-// It manages the state of the sidebar (open/closed) and passes the necessary props to both the Header and Sidebar components.
+// This component is responsible for rendering the sidebar and header together.
+// Server-side translations are handled by SidebarLayoutServer.
-export default SidebarParent;
\ No newline at end of file
+export default SidebarParent;
diff --git a/src/data/timetable.ts b/src/data/timetable.ts
index d91615e..db0cf2c 100644
--- a/src/data/timetable.ts
+++ b/src/data/timetable.ts
@@ -1,33 +1,68 @@
export type ScheduleItem = {
time?: string; // Aeg on ajutine praegu kuna pole 100% kindlalt paigas
- title: string;
- location: string;
+ titleKey: string;
+ locationKey: string;
description?: string;
};
export const scheduleData: Record
= {
- "24. oktoober": [
+ oct24: [
{
- title: "League of Legends põhiturniir",
- location: "Aula",
- time: "-",
+ titleKey: "schedule.events.doorsOpen",
+ locationKey: "schedule.locations.registrationSetup",
+ time: "17:00",
},
{
- title: "Miniturniirid",
- location: "Tudengimaja",
- time: "-",
+ titleKey: "schedule.events.mainTournamentsStart",
+ locationKey: "schedule.locations.auditorium",
+ time: "20:00",
+ },
+ {
+ titleKey: "schedule.events.miniTournamentsKickoff",
+ locationKey: "schedule.locations.studentHouse",
+ time: "18:00",
+ },
+ {
+ titleKey: "schedule.events.fightingGamesStart",
+ locationKey: "schedule.locations.studentHouse",
+ time: "18:30",
+ },
+ {
+ titleKey: "schedule.events.doorsClose",
+ locationKey: "schedule.locations.auditoriumAndStudentHouse",
+ time: "*01:00",
},
],
- "25. oktoober": [
+ oct25: [
+ {
+ titleKey: "schedule.events.doorsOpen",
+ locationKey: "schedule.locations.auditoriumAndStudentHouse",
+ time: "10:00",
+ },
+ {
+ titleKey: "schedule.events.miniTournamentsStart",
+ locationKey: "schedule.locations.studentHouse",
+ time: "11:00",
+ },
+ {
+ titleKey: "schedule.events.granblue",
+ locationKey: "schedule.locations.studentHouse",
+ time: "11:30",
+ },
+ {
+ titleKey: "schedule.events.mainTournamentsStart",
+ locationKey: "schedule.locations.auditorium",
+ time: "12:00",
+ },
{
- title: "Counter-Strike 2 põhiturniir",
- location: "Aula",
- time: "-",
+ titleKey: "schedule.events.granTurismo",
+ locationKey: "schedule.locations.studentHouse",
+ time: "20:00",
},
{
- title: "Miniturniirid",
- location: "Tudengimaja",
- time: "-",
+ titleKey: "schedule.events.doorsClose",
+ locationKey: "schedule.locations.auditoriumAndStudentHouse",
+ time: "*01:00",
},
],
};
diff --git a/src/i18n/request.ts b/src/i18n/request.ts
new file mode 100644
index 0000000..07c6359
--- /dev/null
+++ b/src/i18n/request.ts
@@ -0,0 +1,17 @@
+import { getRequestConfig } from "next-intl/server";
+import { routing } from "./routing";
+
+export default getRequestConfig(async ({ requestLocale }) => {
+ // This typically corresponds to the `[locale]` segment
+ let locale = await requestLocale;
+
+ // Ensure that a valid locale is used
+ if (!locale || !routing.locales.includes(locale as "et" | "en")) {
+ locale = routing.defaultLocale;
+ }
+
+ return {
+ locale: locale!,
+ messages: (await import(`../../translations/${locale}.json`)).default,
+ };
+});
diff --git a/src/i18n/routing.ts b/src/i18n/routing.ts
new file mode 100644
index 0000000..07d8c6f
--- /dev/null
+++ b/src/i18n/routing.ts
@@ -0,0 +1,55 @@
+import { defineRouting } from "next-intl/routing";
+import { createNavigation } from "next-intl/navigation";
+
+export const routing = defineRouting({
+ // A list of all locales that are supported
+ locales: ["et", "en"],
+
+ // Used when no locale matches
+ defaultLocale: "et",
+
+ // The `pathnames` object holds pairs of internal and
+ // external paths. The external paths are shown in the URL.
+ pathnames: {
+ // If all locales use the same pathname, a single
+ // external path can be used for all locales
+ "/": "/",
+ "/ajakava": {
+ et: "/ajakava",
+ en: "/schedule",
+ },
+ "/haldus": {
+ et: "/haldus",
+ en: "/admin",
+ },
+ "/kodukord": {
+ et: "/kodukord",
+ en: "/rules",
+ },
+ "/messiala": {
+ et: "/messiala",
+ en: "/expo",
+ },
+ "/piletid": {
+ et: "/piletid",
+ en: "/tickets",
+ },
+ "/reeglid": {
+ et: "/reeglid",
+ en: "/regulations",
+ },
+ "/striim": {
+ et: "/striim",
+ en: "/stream",
+ },
+ "/turniirid": {
+ et: "/turniirid",
+ en: "/tournaments",
+ },
+ },
+});
+
+// Lightweight wrappers around Next.js' navigation APIs
+// that will consider the routing configuration
+export const { Link, redirect, usePathname, useRouter } =
+ createNavigation(routing);
diff --git a/src/middleware.ts b/src/middleware.ts
new file mode 100644
index 0000000..c7fbd95
--- /dev/null
+++ b/src/middleware.ts
@@ -0,0 +1,20 @@
+import createMiddleware from 'next-intl/middleware';
+import {routing} from './i18n/routing';
+
+export default createMiddleware(routing);
+
+export const config = {
+ // Match only internationalized pathnames
+ matcher: [
+ // Enable a redirect to a matching locale at the root
+ '/',
+
+ // Set a cookie to remember the previous locale for
+ // all requests that have a locale prefix
+ '/(et|en)/:path*',
+
+ // Enable redirects that add missing locales
+ // (e.g. `/pathnames` -> `/en/pathnames`)
+ '/((?!_next|_vercel|.*\\..*).*)'
+ ]
+};
diff --git a/translations/en.json b/translations/en.json
new file mode 100644
index 0000000..73ec36e
--- /dev/null
+++ b/translations/en.json
@@ -0,0 +1,216 @@
+{
+ "navigation": {
+ "home": "Home",
+ "schedule": "Schedule",
+ "admin": "Admin",
+ "houserules": "House rules",
+ "expo": "Expo",
+ "tickets": "Tickets",
+ "rules": "Rules",
+ "stream": "Stream",
+ "tournaments": "Tournaments"
+ },
+ "common": {
+ "loading": "Loading...",
+ "error": "Error",
+ "success": "Success",
+ "save": "Save",
+ "cancel": "Cancel",
+ "delete": "Delete",
+ "edit": "Edit",
+ "close": "Close",
+ "next": "Next",
+ "previous": "Previous",
+ "search": "Search",
+ "filter": "Filter",
+ "reset": "Reset",
+ "theme": {
+ "light": "Light",
+ "dark": "Dark",
+ "system": "System"
+ },
+ "language": {
+ "et": "Eesti",
+ "en": "English"
+ }
+ },
+ "home": {
+ "title": "TipiLAN 2025",
+ "subtitle": "Estonia's largest student-organized LAN event!",
+ "welcome": "Welcome to TipiLAN 2025!",
+ "description": "Join us at Estonia's largest student-organized LAN event. Games, competitions and much more await you!",
+ "sections": {
+ "schedule": {
+ "description": "TipiLAN is packed with exciting tournaments, mini-competitions and much more."
+ },
+ "tournaments": {
+ "description": "TipiLAN features massive CS2 and LoL tournaments with a prize pool of €10,000."
+ },
+ "expo": {
+ "description": "The TipiLAN expo area hosts companies, additional activities and lectures."
+ },
+ "reserveSpot": "Reserve your spot today!",
+ "poweredBy": "TipiLAN is powered by..."
+ }
+ },
+ "tickets": {
+ "title": "TICKETS AND REGISTRATION",
+ "buyNow": "Buy now",
+ "soldOut": "Sold out",
+ "available": "Available",
+ "price": "Price",
+ "includes": "Includes",
+ "computerParticipant": {
+ "title": "Computer Participant",
+ "price": "8€",
+ "features": [
+ "Personal desk, power and internet connection",
+ "Access to demo area",
+ "Tournament spectating",
+ "Ability to participate in mini-tournaments"
+ ]
+ },
+ "competitor": {
+ "title": "Competitor",
+ "price": "12-15€",
+ "features": [
+ "Ability to participate in the CS2 or LoL tournament",
+ "Personal desk, power and internet connection",
+ "Access to demo area",
+ "Tournament spectating",
+ "Ability to participate in mini-tournaments"
+ ]
+ },
+ "visitor": {
+ "title": "Visitor",
+ "price": "6€",
+ "features": [
+ "Access to demo area",
+ "Tournament spectating",
+ "Ability to participate in mini-tournaments"
+ ]
+ },
+ "buyTicket": "BUY TICKETS"
+ },
+ "tournaments": {
+ "title": "Tournaments",
+ "register": "Register",
+ "participants": "Participants",
+ "prizePool": "Prize pool",
+ "schedule": "Schedule",
+ "rules": "Rules",
+ "cs2": {
+ "title": "CS2 Tournament",
+ "timing": "Timing to be announced",
+ "description1": "TipiLAN hosts one of Estonia's largest CS2 tournaments with a significant prize pool this fall. Grab your friends and experience the adrenaline rush!",
+ "description2": "The prize pool is €5,250, distributed among the TOP3 teams. Each team member receives €600, €300, or €150 based on their placement.",
+ "readRules": "READ RULES",
+ "buyTicket": "BUY TICKETS"
+ },
+ "lol": {
+ "title": "LoL Tournament",
+ "timing": "Timing to be announced",
+ "description1": "TipiLAN hosts one of Estonia's largest LoL tournaments with a significant prize pool this fall. Grab your friends and experience the adrenaline rush!",
+ "description2": "The prize pool is €3,500, distributed among the TOP3 teams. Each team member receives €400, €200, or €100 based on their placement.",
+ "readRules": "READ RULES",
+ "buyTicket": "BUY TICKETS"
+ },
+ "mini": {
+ "titleSingular": "Mini-tournament",
+ "title": "Mini-tournaments",
+ "timing": "Timing to be announced",
+ "description1": "TipiLAN hosts various fun and competitive mini-tournaments. Mini-tournaments take place in the following games: SimRacing, Tekken, FIFA, Minecraft Bedwars, Buckshot Roulette, LostGamer and many more.",
+ "description2": "The total prize pool for all tournaments is €1,250 and typically the mini-tournament winner receives a cash prize.",
+ "readRules": "READ RULES",
+ "buyTicket": "BUY TICKETS"
+ }
+ },
+ "schedule": {
+ "title": "Schedule",
+ "day": "Day",
+ "time": "Time",
+ "event": "Event",
+ "location": "Location",
+ "oct24": "October 24th",
+ "oct25": "October 25th",
+ "events": {
+ "doorsOpen": "Doors open",
+ "mainTournamentsStart": "Main tournaments begin",
+ "miniTournamentsKickoff": "Mini-tournaments kick-off",
+ "fightingGamesStart": "Fighting game tournaments start",
+ "doorsClose": "Doors close",
+ "miniTournamentsStart": "Mini-tournaments begin",
+ "granblue": "Granblue tournament",
+ "granTurismo": "Gran Turismo tournament"
+ },
+ "locations": {
+ "registrationSetup": "Registration and setup in auditorium",
+ "auditorium": "Auditorium",
+ "studentHouse": "Student House (Tudengimaja)",
+ "auditoriumAndStudentHouse": "Auditorium and Student House"
+ }
+ },
+ "stream": {
+ "title": "Stream",
+ "live": "Live",
+ "offline": "Offline",
+ "watchNow": "Watch now"
+ },
+ "footer": {
+ "copyright": "© 2025 TipiLAN. All rights reserved.",
+ "contact": "Contact",
+ "privacy": "Privacy",
+ "terms": "Terms",
+ "studentUnion": "IT Faculty Student Council",
+ "organization": "MTÜ For Tsükkel",
+ "registrationCode": "Registration code"
+ },
+ "notFound": {
+ "title": "404",
+ "message": "We couldn't find this page."
+ },
+ "expo": {
+ "title": "Expo Area",
+ "description": "The TipiLAN expo area hosts companies, additional activities and lectures.",
+ "areas": {
+ "bar": "Bar Area",
+ "boardGames": "Board Games Area",
+ "simRacing": "Red Bull Sim Racing",
+ "fighting": "Fighting Games Area"
+ },
+ "hide": "Hide",
+ "show": "Show"
+ },
+ "rules": {
+ "title": "Rules",
+ "houseRules": "House Rules",
+ "cs2Rules": "CS2 Rules",
+ "lolRules": "LoL Rules"
+ },
+ "admin": {
+ "title": "Admin",
+ "users": "Users",
+ "teams": "Teams",
+ "success": {
+ "title": "Operation was successful!",
+ "description": "Database data has been updated."
+ },
+ "sync": {
+ "title": "Do you want to update the database?",
+ "description1": "This will pull current data from Fienta and replace",
+ "all": "ALL",
+ "description2": "existing data in the database!",
+ "warning": "If you're not sure, click \"Cancel\".",
+ "update": "Update"
+ },
+ "roles": {
+ "captain": "Captain",
+ "teammate": "Teammate"
+ },
+ "table": {
+ "name": "Name",
+ "members": "Members",
+ "noMembers": "No members"
+ }
+ }
+}
diff --git a/translations/et.json b/translations/et.json
new file mode 100644
index 0000000..40ba4f3
--- /dev/null
+++ b/translations/et.json
@@ -0,0 +1,215 @@
+{
+ "navigation": {
+ "home": "Avaleht",
+ "schedule": "Ajakava",
+ "admin": "Haldus",
+ "houserules": "Kodukord",
+ "expo": "Messiala",
+ "tickets": "Piletid",
+ "rules": "Reeglid",
+ "stream": "Striim",
+ "tournaments": "Turniirid"
+ },
+ "common": {
+ "loading": "Laadimine...",
+ "error": "Viga",
+ "success": "Õnnestus",
+ "save": "Salvesta",
+ "cancel": "Tühista",
+ "delete": "Kustuta",
+ "edit": "Muuda",
+ "close": "Sulge",
+ "next": "Järgmine",
+ "previous": "Eelmine",
+ "search": "Otsi",
+ "filter": "Filtreeri",
+ "reset": "Lähtesta",
+ "theme": {
+ "light": "Hele",
+ "dark": "Tume",
+ "system": "Süsteemipõhine"
+ },
+ "language": {
+ "et": "Eesti",
+ "en": "English"
+ }
+ },
+ "home": {
+ "title": "TipiLAN 2025",
+ "subtitle": "Eesti suurim tudengite korraldatud LAN!",
+ "welcome": "Tere tulemast TipiLAN 2025 sündmusele!",
+ "description": "Liitu meiega Eesti suurimal tudengite korraldatud LAN-üritusel. Mängud, võistlused ja palju muud ootavad sind!",
+ "sections": {
+ "schedule": {
+ "description": "TipiLAN on pungil põnevatest turniiridest, mini-võistlustest ja paljust muust."
+ },
+ "tournaments": {
+ "description": "TipiLANil toimuvad suurejoonelised CS2 ja LoL turniirid, mille auhinnafond on 10 000€."
+ },
+ "expo": {
+ "description": "TipiLANi messialal paiknevad ettevõtted, lisategevused ja toimuvad loengud."
+ },
+ "reserveSpot": "Broneeri oma koht juba täna!",
+ "poweredBy": "TipiLANi tõmbab käima..."
+ }
+ },
+ "tickets": {
+ "title": "PILETID JA REGISTREERIMINE",
+ "buyNow": "Osta nüüd",
+ "soldOut": "Välja müüdud",
+ "available": "Saadaval",
+ "price": "Hind",
+ "includes": "Sisaldab",
+ "computerParticipant": {
+ "title": "Arvutiga osaleja",
+ "price": "8€",
+ "features": [
+ "Isiklik laud, voolu- ja internetiühendus",
+ "Ligipääs demoalale",
+ "Turniiride pealt vaatamine",
+ "Võimalus osaleda miniturniiridel"
+ ]
+ },
+ "competitor": {
+ "title": "Võistleja",
+ "price": "12-15€",
+ "features": [
+ "Võimalus osaleda CS2 või LoL turniiril",
+ "Isiklik laud, voolu- ja internetiühendus",
+ "Ligipääs demoalale",
+ "Turniiride pealt vaatamine",
+ "Võimalus osaleda miniturniiridel"
+ ]
+ },
+ "visitor": {
+ "title": "Külastaja",
+ "price": "6€",
+ "features": [
+ "Ligipääs demoalale",
+ "Turniiride pealt vaatamine",
+ "Võimalus osaleda miniturniiridel"
+ ]
+ },
+ "buyTicket": "OSTA PILET"
+ },
+ "tournaments": {
+ "title": "Turniirid",
+ "register": "Registreeru",
+ "participants": "Osalejad",
+ "prizePool": "Auhinnafond",
+ "schedule": "Ajakava",
+ "rules": "Reeglid",
+ "cs2": {
+ "title": "CS2 turniir",
+ "timing": "Toimumisaeg veel selgumisel",
+ "description1": "TipiLANil toimub Eesti ühe suurima auhinnafondiga CS2 turniire juba sel sügisel. Haara kaasa sõbrad ja saa osa adrenaliinirohkest kogemusest!",
+ "description2": "Auhinnafond on suuruses 5250€, mis jaotatakse TOP3 meeskonna vahel ära. Iga tiimiliige saab vastavalt saavutatud kohale auhinnaks kas 600€, 300€ või 150€.",
+ "readRules": "LOE REEGLEID",
+ "buyTicket": "OSTA PILET"
+ },
+ "lol": {
+ "title": "LoL turniir",
+ "timing": "Toimumisaeg veel selgumisel",
+ "description1": "TipiLANil toimub Eesti ühe suurima auhinnafondiga LoL turniire juba sel sügisel. Haara kaasa sõbrad ja saa osa adrenaliinirohkest kogemusest!",
+ "description2": "Auhinnafond on suuruses 3500€, mis jaotatakse TOP3 meeskonna vahel ära. Iga tiimiliige saab vastavalt saavutatud kohale auhinnaks kas 400€, 200€ või 100€.",
+ "readRules": "LOE REEGLEID",
+ "buyTicket": "OSTA PILET"
+ },
+ "mini": {
+ "title": "Miniturniirid",
+ "timing": "Toimumisaeg veel selgumisel",
+ "description1": "TipiLANil toimub mitmeid erinevaid lõbusaid ja võistlushimu tekitavaid miniturniire. Miniturniirid toimuvad järgnevates mängudes: SimRacing, Tekken, FIFA, Minecraft Bedwars, Buckshot Roulette, LostGamer ja palju muud.",
+ "description2": "Auhinnafond on kõigi turniiride peale 1250€ ja reeglina saab rahalise auhinna miniturniiri võitja.",
+ "readRules": "LOE REEGLEID",
+ "buyTicket": "OSTA PILET"
+ }
+ },
+ "schedule": {
+ "title": "Ajakava",
+ "day": "Päev",
+ "time": "Aeg",
+ "event": "Sündmus",
+ "location": "Asukoht",
+ "oct24": "24. oktoober",
+ "oct25": "25. oktoober",
+ "events": {
+ "doorsOpen": "Uksed avatakse",
+ "mainTournamentsStart": "Põhiturniirid algavad",
+ "miniTournamentsKickoff": "Miniturniiride kick-off",
+ "fightingGamesStart": "Fighting games turniiride algus",
+ "doorsClose": "Uksed suletakse",
+ "miniTournamentsStart": "Miniturniirid algavad",
+ "granblue": "Granblue turniir",
+ "granTurismo": "Gran Turismo turniir"
+ },
+ "locations": {
+ "registrationSetup": "Registreerimine ja setup aulas",
+ "auditorium": "Aula",
+ "studentHouse": "Tudengimaja",
+ "auditoriumAndStudentHouse": "Aula ja Tudengimaja"
+ }
+ },
+ "stream": {
+ "title": "Striim",
+ "live": "Otse-eetris",
+ "offline": "Väljas",
+ "watchNow": "Vaata nüüd"
+ },
+ "footer": {
+ "copyright": "© 2025 TipiLAN. Kõik õigused kaitstud.",
+ "contact": "Kontakt",
+ "privacy": "Privaatsus",
+ "terms": "Tingimused",
+ "studentUnion": "IT-teaduskonna üliõpilaskogu",
+ "organization": "MTÜ For Tsükkel",
+ "registrationCode": "Registrikood"
+ },
+ "notFound": {
+ "title": "404",
+ "message": "Seda lehte me ei leidnud."
+ },
+ "expo": {
+ "title": "Messiala",
+ "description": "TipiLANi messialal paiknevad ettevõtted, lisategevused ja toimuvad loengud.",
+ "areas": {
+ "bar": "Baariala",
+ "boardGames": "Lauamängude ala",
+ "simRacing": "Red Bull Sim Racing",
+ "fighting": "Võitlusmängu ala"
+ },
+ "hide": "Peida",
+ "show": "Näita"
+ },
+ "rules": {
+ "title": "Reeglid",
+ "houseRules": "Kodukord",
+ "cs2Rules": "CS2 Reeglid",
+ "lolRules": "LoL Reeglid"
+ },
+ "admin": {
+ "title": "Haldus",
+ "users": "Kasutajaid",
+ "teams": "Meeskondasid",
+ "success": {
+ "title": "Toiming oli edukas!",
+ "description": "Andmebaasi andmed on uuendatud."
+ },
+ "sync": {
+ "title": "Kas soovite värskendada andmebaasi?",
+ "description1": "See tõmbab Fientast praegused andmed ning asendab",
+ "all": "KÕIK",
+ "description2": "olemasolevad andmed andmebaasis!",
+ "warning": "Kui sa ei ole kindel, vajuta \"Tühista\".",
+ "update": "Värskenda"
+ },
+ "roles": {
+ "captain": "Kapten",
+ "teammate": "Meeskonnaliige"
+ },
+ "table": {
+ "name": "Nimi",
+ "members": "Liikmed",
+ "noMembers": "Liikmeid puuduvad"
+ }
+ }
+}