mirror of
https://github.com/MaciejkaG/statki.git
synced 2024-11-30 03:32:56 +01:00
Working localisation (big spaghetti)
This commit is contained in:
parent
2e3a46b7e1
commit
9d0c60419e
99
index.js
99
index.js
@ -6,16 +6,16 @@ import { createServer } from 'node:http';
|
||||
import { Server } from 'socket.io';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { v4 as uuidv4, validate } from 'uuid';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import session from "express-session";
|
||||
import { engine } from 'express-handlebars';
|
||||
import { createClient } from 'redis';
|
||||
import * as bships from './utils/battleships.js';
|
||||
import { MailAuth } from './utils/auth.js';
|
||||
import { Lang } from './utils/localisation.js';
|
||||
import { rateLimit } from 'express-rate-limit';
|
||||
import { RedisStore as LimiterRedisStore } from 'rate-limit-redis';
|
||||
import SessionRedisStore from 'connect-redis';
|
||||
import { I18n } from 'i18n';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@ -37,11 +37,6 @@ const redis = createClient();
|
||||
redis.on('error', err => console.log('Redis Client Error', err));
|
||||
await redis.connect();
|
||||
|
||||
const i18n = new I18n({
|
||||
locales: ['en', 'pl'],
|
||||
directory: path.join(__dirname, 'lang')
|
||||
});
|
||||
|
||||
const limiter = rateLimit({
|
||||
windowMs: 40 * 1000,
|
||||
limit: 500,
|
||||
@ -93,26 +88,47 @@ io.engine.use(sessionMiddleware);
|
||||
app.get('/', async (req, res) => {
|
||||
let login = loginState(req);
|
||||
|
||||
const locale = new Lang(req.acceptsLanguages());
|
||||
|
||||
if (login != 2) {
|
||||
res.redirect('/login');
|
||||
} else if (req.session.nickname == null) {
|
||||
auth.getNickname(req.session.userId).then(nickname => {
|
||||
if (nickname != null) {
|
||||
req.session.langs = req.acceptsLanguages();
|
||||
req.session.nickname = nickname;
|
||||
res.render('index');
|
||||
|
||||
res.render('index', {
|
||||
helpers: {
|
||||
t: (key) => { return locale.t(key) }
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.redirect('/nickname');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.render('index');
|
||||
req.session.langs = req.acceptsLanguages();
|
||||
|
||||
res.render('index', {
|
||||
helpers: {
|
||||
t: (key) => { return locale.t(key) }
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/login', (req, res) => {
|
||||
let login = loginState(req);
|
||||
|
||||
const locale = new Lang(req.acceptsLanguages());
|
||||
|
||||
if (!login) {
|
||||
res.render('login');
|
||||
res.render('login', {
|
||||
helpers: {
|
||||
t: (key) => { return locale.t(key) }
|
||||
}
|
||||
});
|
||||
} else if (login == 1) {
|
||||
res.redirect('/auth');
|
||||
} else {
|
||||
@ -122,10 +138,17 @@ app.get('/login', (req, res) => {
|
||||
|
||||
app.get('/auth', (req, res) => {
|
||||
let login = loginState(req);
|
||||
|
||||
const locale = new Lang(req.acceptsLanguages());
|
||||
|
||||
if (!login) { // Niezalogowany
|
||||
res.redirect('/login');
|
||||
} else if (login == 1) { // W trakcie autoryzacji
|
||||
res.render('auth');
|
||||
res.render('auth', {
|
||||
helpers: {
|
||||
t: (key) => { return locale.t(key) }
|
||||
}
|
||||
});
|
||||
} else { // Zalogowany
|
||||
res.redirect('/auth');
|
||||
}
|
||||
@ -133,15 +156,23 @@ app.get('/auth', (req, res) => {
|
||||
|
||||
app.get('/nickname', (req, res) => {
|
||||
let login = loginState(req);
|
||||
|
||||
const locale = new Lang(req.acceptsLanguages());
|
||||
|
||||
if (!login) { // Niezalogowany
|
||||
res.redirect('/login');
|
||||
} else {
|
||||
res.render('setup');
|
||||
res.render('setup', {
|
||||
helpers: {
|
||||
t: (key) => { return locale.t(key) }
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/login', (req, res) => {
|
||||
let login = loginState(req);
|
||||
|
||||
if (login == 2) {
|
||||
res.redirect('/');
|
||||
} else if (login == 0 && req.body.email != null && validateEmail(req.body.email)) {
|
||||
@ -164,19 +195,25 @@ app.post('/api/login', (req, res) => {
|
||||
res.sendStatus(500);
|
||||
}
|
||||
}).catch((err) => {
|
||||
const locale = new Lang(req.acceptsLanguages());
|
||||
|
||||
res.render("error", {
|
||||
helpers: {
|
||||
error: "Wystąpił nieznany błąd logowania",
|
||||
fallback: "/login"
|
||||
fallback: "/login",
|
||||
t: (key) => { return locale.t(key) }
|
||||
}
|
||||
});
|
||||
throw err;
|
||||
});
|
||||
} else {
|
||||
const locale = new Lang(req.acceptsLanguages());
|
||||
|
||||
res.render("error", {
|
||||
helpers: {
|
||||
error: "Niepoprawny adres e-mail",
|
||||
fallback: "/login"
|
||||
fallback: "/login",
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -192,18 +229,24 @@ app.post('/api/auth', async (req, res) => {
|
||||
req.session.loggedIn = 2;
|
||||
res.redirect('/');
|
||||
} else {
|
||||
const locale = new Lang(req.acceptsLanguages());
|
||||
|
||||
res.render("error", {
|
||||
helpers: {
|
||||
error: "Niepoprawny kod logowania",
|
||||
fallback: "/auth"
|
||||
fallback: "/auth",
|
||||
t: (key) => { return locale.t(key) }
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const locale = new Lang(req.acceptsLanguages());
|
||||
|
||||
res.render("error", {
|
||||
helpers: {
|
||||
error: "Niepoprawny kod logowania",
|
||||
fallback: "/login"
|
||||
fallback: "/login",
|
||||
t: (key) => { return locale.t(key) }
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -222,6 +265,9 @@ app.post('/api/nickname', (req, res) => {
|
||||
});
|
||||
|
||||
app.get('/game', async (req, res) => {
|
||||
|
||||
const locale = new Lang(req.acceptsLanguages());
|
||||
|
||||
const game = await redis.json.get(`game:${req.query.id}`);
|
||||
if (req.session.nickname == null) {
|
||||
res.redirect('/setup');
|
||||
@ -229,11 +275,16 @@ app.get('/game', async (req, res) => {
|
||||
res.render("error", {
|
||||
helpers: {
|
||||
error: "Nie znaleziono wskazanej gry",
|
||||
fallback: "/"
|
||||
fallback: "/",
|
||||
t: (key) => { return locale.t(key) }
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.render('board');
|
||||
res.render('board', {
|
||||
helpers: {
|
||||
t: (key) => { return locale.t(key) }
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -428,9 +479,13 @@ io.on('connection', async (socket) => {
|
||||
let shipAvailable = bships.getShipsAvailable(playerShips)[type] > 0;
|
||||
|
||||
if (!canPlace) {
|
||||
socket.emit("toast", "Nie możesz postawić tak statku");
|
||||
const locale = new Lang(session.langs);
|
||||
|
||||
socket.emit("toast", locale.t("board.You cannot place a ship like this"));
|
||||
} else if (!shipAvailable) {
|
||||
socket.emit("toast", "Nie masz już statków tego typu");
|
||||
const locale = new Lang(session.langs);
|
||||
|
||||
socket.emit("toast", locale.t("board.You have ran out of ships of that type"));
|
||||
} else {
|
||||
await GInfo.placeShip(socket, { type: type, posX: posX, posY: posY, rot: rot, hits: Array.from(new Array(type+1), () => false) });
|
||||
socket.emit("placed ship", { type: type, posX: posX, posY: posY, rot: rot });
|
||||
@ -491,7 +546,9 @@ io.on('connection', async (socket) => {
|
||||
return;
|
||||
}
|
||||
} else if (hit.status === -1) {
|
||||
socket.emit("toast", "Już strzeliłeś w to miejsce");
|
||||
const locale = new Lang(session.langs);
|
||||
|
||||
socket.emit("toast", locale.t("You have already shot at this field"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
68
lang/en.json
68
lang/en.json
@ -1,13 +1,14 @@
|
||||
{
|
||||
"errors": {
|
||||
"Reonnecting...": "Reconnecting...",
|
||||
"Reconnecting": "Reconnecting...",
|
||||
"Reconnected": "Reconnected",
|
||||
"Reconnection error occured": "Reconnection error occured",
|
||||
"Reconection failed": "Reconnection failed",
|
||||
"Reconnection failed": "Reconnection failed",
|
||||
"Disconnected": "Disconnected",
|
||||
"Try to refresh the page if this error reoccurs": "Try to refresh the page if this error reoccurs",
|
||||
"Connection error": "Connection error"
|
||||
},
|
||||
|
||||
"menu": {
|
||||
"navbar": {
|
||||
"Main menu": "Main menu",
|
||||
@ -17,7 +18,7 @@
|
||||
"Select game mode": "Select game mode",
|
||||
"PvP": "PvP",
|
||||
"Play against another player": "Play against another player",
|
||||
"Vs. AI": "Vs. AI",
|
||||
"Vs AI": "Vs. AI",
|
||||
"Play against the computer": "Play against the computer"
|
||||
},
|
||||
"PvP": {
|
||||
@ -38,28 +39,77 @@
|
||||
"Room code": "Room code",
|
||||
"Join": "Join"
|
||||
},
|
||||
"PvP/Prepairing": {
|
||||
"PvP/Loading": {
|
||||
"PvP / Loading": "PvP / Loading",
|
||||
"Wait...": "Wait...",
|
||||
"Wait": "Wait...",
|
||||
"You will be redirected soon": "You will be redirected soon",
|
||||
"Opponent:": "Opponent"
|
||||
},
|
||||
"Profile": {
|
||||
"Loading...": "Loading...",
|
||||
"Player since: ": "Player since: ",
|
||||
"Loading": "Loading...",
|
||||
"Player since:": "Player since:",
|
||||
"Victory": "Victory",
|
||||
"Defeat": "Defeat",
|
||||
"Click to view match statistics": "Click to view match statistics",
|
||||
"matches played this month": "matches played this month",
|
||||
"total matches played": "total matches played",
|
||||
"winrate": "winrate",
|
||||
|
||||
"No matches played": "No matches played"
|
||||
},
|
||||
|
||||
"General": {
|
||||
"Unknown error occured": "Unknown error occured",
|
||||
"Status:": "Status:"
|
||||
}
|
||||
},
|
||||
|
||||
"login": {
|
||||
"Login": "Login",
|
||||
"E-mail address": "E-mail address",
|
||||
"Proceed": "Proceed"
|
||||
},
|
||||
|
||||
"auth": {
|
||||
"Authorisation": "Authorisation",
|
||||
"Enter the code sent to your e-mail box": "Enter the code sent to your e-mail box",
|
||||
"Code": "Code",
|
||||
"Login": "Login"
|
||||
},
|
||||
|
||||
"setup": {
|
||||
"Profile setup": "Profile setup",
|
||||
"Your nickname will be visible to other players": "Your nickname will be visible to other players",
|
||||
"Nickname": "Nickname",
|
||||
"Confirm": "Confirm"
|
||||
},
|
||||
|
||||
"error": {
|
||||
"Error": "Erorr",
|
||||
"Return": "Return"
|
||||
},
|
||||
|
||||
"board": {
|
||||
"Connecting": "Connecting...",
|
||||
"Waiting for the server": "Waiting for the server...",
|
||||
"Back to menu": "Back to menu",
|
||||
|
||||
"Selected ship": "Selected ship",
|
||||
"Single-masted": "Single-masted",
|
||||
"Two-masted": "Two-masted",
|
||||
"Three-masted": "Three-masted",
|
||||
"Four-masted": "Four-masted",
|
||||
"Available:": "Available:",
|
||||
|
||||
"Controls": "Controls",
|
||||
"Change ship": "Change ship",
|
||||
"Rotate ship": "Rotate ship",
|
||||
"Change boards": "Change boards",
|
||||
|
||||
"Preparation phase": "Preparation phase",
|
||||
"Your turn": "Your turn",
|
||||
"Opponents turn": "Opponent's turn",
|
||||
|
||||
"You cannot place a ship like this": "You cannot place a ship like this",
|
||||
"You have ran out of ships of that type": "You have ran out of ships of that type",
|
||||
"You have already shot at this field": "You have already shot at this field"
|
||||
}
|
||||
}
|
117
lang/pl.json
117
lang/pl.json
@ -0,0 +1,117 @@
|
||||
{
|
||||
"errors": {
|
||||
"Reconnecting": "Ponowne łączenie...",
|
||||
"Reconnected": "Połączono ponownie",
|
||||
"Reconnection error occured": "Wystąpił problem podczas ponownego łączenia",
|
||||
"Reconnection failed": "Ponowne łączenie nieudane",
|
||||
"Disconnected": "Rozłączono",
|
||||
"Try to refresh the page if this error reoccurs": "Spróbuj odświeżyć stronę jeżeli błąd będzie się powtarzał",
|
||||
"Connection error": "Błąd połączenia"
|
||||
},
|
||||
|
||||
"menu": {
|
||||
"navbar": {
|
||||
"Main menu": "Menu główne",
|
||||
"Profile": "Profil"
|
||||
},
|
||||
"index": {
|
||||
"Select game mode": "Wybierz tryb gry",
|
||||
"PvP": "PvP",
|
||||
"Play against another player": "Graj przeciwko innemu graczowi",
|
||||
"Vs AI": "Vs. AI",
|
||||
"Play against the computer": "Graj przeciwko komputerowi"
|
||||
},
|
||||
"PvP": {
|
||||
"PvP": "PvP",
|
||||
"Create": "Stwórz",
|
||||
"Create your own room": "Stwórz własny pokój",
|
||||
"Join": "Dołącz",
|
||||
"Join a room by a code": "Dołącz do pokoju poprzez kod"
|
||||
},
|
||||
"PvP/Create": {
|
||||
"PvP / Create": "PvP / Stwórz",
|
||||
"Room code:": "Kod pokoju:",
|
||||
"Waiting for an opponent": "Oczekiwanie na przeciwnika",
|
||||
"Leave the room": "Opuść pokój"
|
||||
},
|
||||
"PvP/Join": {
|
||||
"PvP / Join": "PvP / Dołącz",
|
||||
"Room code": "Kod pokoju",
|
||||
"Join": "Dołącz"
|
||||
},
|
||||
"PvP/Loading": {
|
||||
"PvP / Loading": "PvP / Wczytywanie",
|
||||
"Wait": "Czekaj...",
|
||||
"You will be redirected soon": "Wkrótce zostaniesz przekierowany(-a)",
|
||||
"Opponent:": "Przeciwnik"
|
||||
},
|
||||
"Profile": {
|
||||
"Loading": "Wczytywanie...",
|
||||
"Player since:": "Gracz od:",
|
||||
"Victory": "Zwycięstwo",
|
||||
"Defeat": "Porażka",
|
||||
"Click to view match statistics": "Kliknij by wyświetlić statystyki meczu",
|
||||
"matches played this month": "meczy zagranych w tym miesiącu",
|
||||
"total matches played": "meczy zagranych łącznie",
|
||||
"winrate": "winrate",
|
||||
|
||||
"No matches played": "Nie zagrano meczy"
|
||||
},
|
||||
|
||||
"General": {
|
||||
"Unknown error occured": "Wystąpił nieznany błąd",
|
||||
"Status:": "Status:"
|
||||
}
|
||||
},
|
||||
|
||||
"login": {
|
||||
"Login": "Zaloguj się",
|
||||
"E-mail address": "Adres e-mail",
|
||||
"Proceed": "Kontynuuj"
|
||||
},
|
||||
|
||||
"auth": {
|
||||
"Authorisation": "Autoryzacja",
|
||||
"Enter the code sent to your e-mail box": "Podaj kod wysłany do twojej skrzynki e-mail",
|
||||
"Code": "Kod",
|
||||
"Login": "Zaloguj się"
|
||||
},
|
||||
|
||||
"setup": {
|
||||
"Profile setup": "Konfiguracja profilu",
|
||||
"Your nickname will be visible to other players": "Twoja nazwa użytkownika będzie widoczna dla innych graczy",
|
||||
"Nickname": "Nazwa użytkownika",
|
||||
"Confirm": "Potwierdź"
|
||||
},
|
||||
|
||||
"error": {
|
||||
"Error": "Błąd",
|
||||
"Return": "Wróć"
|
||||
},
|
||||
|
||||
"board": {
|
||||
"Connecting": "Łączenie...",
|
||||
"Waiting for the server": "Oczekiwanie na serwer...",
|
||||
"Back to menu": "Powrót do menu",
|
||||
|
||||
"Selected ship": "Wybrany statek",
|
||||
"Single-masted": "Jednomasztowiec",
|
||||
"Two-masted": "Dwumasztowiec",
|
||||
"Three-masted": "Trójmasztowiec",
|
||||
"Four-masted": "Czteromasztowiec",
|
||||
"Available:": "Dostępne:",
|
||||
|
||||
"Controls": "Sterowanie",
|
||||
"Change ship": "Zmień statek",
|
||||
"Rotate ship": "Obróć statek",
|
||||
"Change boards": "Zmień plansze",
|
||||
|
||||
"Preparation phase": "Faza przygotowań",
|
||||
"Your turn": "Twoja tura",
|
||||
"Opponents turn": "Tura przeciwnika",
|
||||
|
||||
"You cannot place a ship like this": "Nie możesz tak postawić statku",
|
||||
"You have ran out of ships of that type": "Skończyły ci się statki tego typu",
|
||||
"You have already shot at this field": "Już strzelałeś w to pole"
|
||||
}
|
||||
}
|
106
package-lock.json
generated
106
package-lock.json
generated
@ -16,7 +16,6 @@
|
||||
"express-rate-limit": "^7.2.0",
|
||||
"express-session": "^1.18.0",
|
||||
"geoip-lite": "^1.4.10",
|
||||
"i18n": "^0.15.1",
|
||||
"mysql": "^2.18.1",
|
||||
"nodemailer": "^6.9.12",
|
||||
"rate-limit-redis": "^4.2.0",
|
||||
@ -42,45 +41,6 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@messageformat/core": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@messageformat/core/-/core-3.3.0.tgz",
|
||||
"integrity": "sha512-YcXd3remTDdeMxAlbvW6oV9d/01/DZ8DHUFwSttO3LMzIZj3iO0NRw+u1xlsNNORFI+u0EQzD52ZX3+Udi0T3g==",
|
||||
"dependencies": {
|
||||
"@messageformat/date-skeleton": "^1.0.0",
|
||||
"@messageformat/number-skeleton": "^1.0.0",
|
||||
"@messageformat/parser": "^5.1.0",
|
||||
"@messageformat/runtime": "^3.0.1",
|
||||
"make-plural": "^7.0.0",
|
||||
"safe-identifier": "^0.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@messageformat/date-skeleton": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@messageformat/date-skeleton/-/date-skeleton-1.0.1.tgz",
|
||||
"integrity": "sha512-jPXy8fg+WMPIgmGjxSlnGJn68h/2InfT0TNSkVx0IGXgp4ynnvYkbZ51dGWmGySEK+pBiYUttbQdu5XEqX5CRg=="
|
||||
},
|
||||
"node_modules/@messageformat/number-skeleton": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@messageformat/number-skeleton/-/number-skeleton-1.2.0.tgz",
|
||||
"integrity": "sha512-xsgwcL7J7WhlHJ3RNbaVgssaIwcEyFkBqxHdcdaiJzwTZAWEOD8BuUFxnxV9k5S0qHN3v/KzUpq0IUpjH1seRg=="
|
||||
},
|
||||
"node_modules/@messageformat/parser": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@messageformat/parser/-/parser-5.1.0.tgz",
|
||||
"integrity": "sha512-jKlkls3Gewgw6qMjKZ9SFfHUpdzEVdovKFtW1qRhJ3WI4FW5R/NnGDqr8SDGz+krWDO3ki94boMmQvGke1HwUQ==",
|
||||
"dependencies": {
|
||||
"moo": "^0.5.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@messageformat/runtime": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@messageformat/runtime/-/runtime-3.0.1.tgz",
|
||||
"integrity": "sha512-6RU5ol2lDtO8bD9Yxe6CZkl0DArdv0qkuoZC+ZwowU+cdRlVE1157wjCmlA5Rsf1Xc/brACnsZa5PZpEDfTFFg==",
|
||||
"dependencies": {
|
||||
"make-plural": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
@ -273,11 +233,6 @@
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/boolean": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz",
|
||||
"integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw=="
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
@ -727,17 +682,6 @@
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/fast-printf": {
|
||||
"version": "1.6.9",
|
||||
"resolved": "https://registry.npmjs.org/fast-printf/-/fast-printf-1.6.9.tgz",
|
||||
"integrity": "sha512-FChq8hbz65WMj4rstcQsFB0O7Cy++nmbNfLYnD9cYv2cRn8EG6k/MGn9kO/tjO66t09DLDugj3yL+V2o6Qftrg==",
|
||||
"dependencies": {
|
||||
"boolean": "^3.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fd-slicer": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
|
||||
@ -987,25 +931,6 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/i18n": {
|
||||
"version": "0.15.1",
|
||||
"resolved": "https://registry.npmjs.org/i18n/-/i18n-0.15.1.tgz",
|
||||
"integrity": "sha512-yue187t8MqUPMHdKjiZGrX+L+xcUsDClGO0Cz4loaKUOK9WrGw5pgan4bv130utOwX7fHE9w2iUeHFalVQWkXA==",
|
||||
"dependencies": {
|
||||
"@messageformat/core": "^3.0.0",
|
||||
"debug": "^4.3.3",
|
||||
"fast-printf": "^1.6.9",
|
||||
"make-plural": "^7.0.0",
|
||||
"math-interval-parser": "^2.0.1",
|
||||
"mustache": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/mashpie"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
@ -1113,19 +1038,6 @@
|
||||
"node": "14 || >=16.14"
|
||||
}
|
||||
},
|
||||
"node_modules/make-plural": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/make-plural/-/make-plural-7.3.0.tgz",
|
||||
"integrity": "sha512-/K3BC0KIsO+WK2i94LkMPv3wslMrazrQhfi5We9fMbLlLjzoOSJWr7TAdupLlDWaJcWxwoNosBkhFDejiu5VDw=="
|
||||
},
|
||||
"node_modules/math-interval-parser": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/math-interval-parser/-/math-interval-parser-2.0.1.tgz",
|
||||
"integrity": "sha512-VmlAmb0UJwlvMyx8iPhXUDnVW1F9IrGEd9CIOmv+XL8AErCUUuozoDMrgImvnYt2A+53qVX/tPW6YJurMKYsvA==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
@ -1207,24 +1119,11 @@
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/moo": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz",
|
||||
"integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q=="
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/mustache": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
|
||||
"integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
|
||||
"bin": {
|
||||
"mustache": "bin/mustache"
|
||||
}
|
||||
},
|
||||
"node_modules/mysql": {
|
||||
"version": "2.18.1",
|
||||
"resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz",
|
||||
@ -1530,11 +1429,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/safe-identifier": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz",
|
||||
"integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w=="
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
|
@ -26,7 +26,6 @@
|
||||
"express-rate-limit": "^7.2.0",
|
||||
"express-session": "^1.18.0",
|
||||
"geoip-lite": "^1.4.10",
|
||||
"i18n": "^0.15.1",
|
||||
"mysql": "^2.18.1",
|
||||
"nodemailer": "^6.9.12",
|
||||
"rate-limit-redis": "^4.2.0",
|
||||
|
@ -63,6 +63,7 @@ nav span:hover {
|
||||
background-color: black;
|
||||
border: solid 1px white;
|
||||
border-radius: 15px;
|
||||
padding: 0.5rem 1rem;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
@ -87,6 +88,7 @@ nav span:hover {
|
||||
background-color: black;
|
||||
border: solid 1px white;
|
||||
border-radius: 15px;
|
||||
padding: 0.5rem 1rem;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
@ -156,16 +156,16 @@ function switchShips() {
|
||||
setTimeout(() => {
|
||||
switch (selectedShip) {
|
||||
case 0:
|
||||
$("#selectedShip").html("Jednomasztowiec");
|
||||
$("#selectedShip").html(window.locale["Single-masted"]);
|
||||
break;
|
||||
case 1:
|
||||
$("#selectedShip").html("Dwumasztowiec");
|
||||
$("#selectedShip").html(window.locale["Two-masted"]);
|
||||
break;
|
||||
case 2:
|
||||
$("#selectedShip").html("Trójmasztowiec");
|
||||
$("#selectedShip").html(window.locale["Three-masted"]);
|
||||
break;
|
||||
case 3:
|
||||
$("#selectedShip").html("Czteromasztowiec");
|
||||
$("#selectedShip").html(window.locale["Four-masted"]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Handling connection errors
|
||||
socket.on("reconnecting", (number) => {
|
||||
Toastify({
|
||||
text: `Ponowne łączenie... ${number}`,
|
||||
text: `${window.locale["Reconnecting"]} ${number}`,
|
||||
duration: 5000,
|
||||
newWindow: true,
|
||||
gravity: "bottom",
|
||||
@ -13,7 +13,7 @@ socket.on("reconnecting", (number) => {
|
||||
|
||||
socket.on("reconnect", () => {
|
||||
Toastify({
|
||||
text: "Połączono ponownie",
|
||||
text: window.locale["Reconnected"],
|
||||
duration: 5000,
|
||||
newWindow: true,
|
||||
gravity: "bottom",
|
||||
@ -25,7 +25,7 @@ socket.on("reconnect", () => {
|
||||
|
||||
socket.on("reconnect_error", () => {
|
||||
Toastify({
|
||||
text: "Wystąpił problem w trakcie ponownego łączenia",
|
||||
text: window.locale["Reconnection error occured"],
|
||||
duration: 5000,
|
||||
newWindow: true,
|
||||
gravity: "bottom",
|
||||
@ -37,7 +37,7 @@ socket.on("reconnect_error", () => {
|
||||
|
||||
socket.on("reconnect_failed", () => {
|
||||
Toastify({
|
||||
text: "Nie udało się połączyć ponownie",
|
||||
text: window.locale["Reconnection failed"],
|
||||
duration: 5000,
|
||||
newWindow: true,
|
||||
gravity: "bottom",
|
||||
@ -49,7 +49,7 @@ socket.on("reconnect_failed", () => {
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
Toastify({
|
||||
text: "Rozłączono z serwerem\nSpróbuj odświeżyć stronę jeżeli błąd będzie się powtarzał",
|
||||
text: `${window.locale["Disconnected"]}\n${window.locale["Try to refresh the page if this error reoccurs"]}`,
|
||||
duration: 5000,
|
||||
newWindow: true,
|
||||
gravity: "bottom",
|
||||
@ -61,7 +61,7 @@ socket.on("disconnect", () => {
|
||||
|
||||
socket.on("error", () => {
|
||||
Toastify({
|
||||
text: "Błąd połączenia",
|
||||
text: window.locale["Connection error"],
|
||||
duration: 5000,
|
||||
newWindow: true,
|
||||
gravity: "bottom",
|
||||
|
@ -144,14 +144,12 @@ socket.on("ship sunk", (victimIdx, ship) => {
|
||||
let l = !ship.type ? ship.type + 1 : ship.type + 2;
|
||||
if (victimIdx === playerIdx) {
|
||||
for (let i = 0; i < l; i++) {
|
||||
console.log("ourship");
|
||||
setTimeout(() => {
|
||||
bsc.setField(ship.posX + multips[0] * i, ship.posY + multips[1] * i, "sunken");
|
||||
}, i * 150);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < l; i++) {
|
||||
console.log("theirship");
|
||||
setTimeout(() => {
|
||||
bsc.setFieldEnemy(ship.posX + multips[0] * i, ship.posY + multips[1] * i, "sunken");
|
||||
}, i * 150);
|
||||
@ -174,8 +172,8 @@ var updateTimer = setInterval(() => {
|
||||
$("#timer").removeClass("active");
|
||||
}
|
||||
|
||||
const minutes = Math.floor(time / 60).toLocaleString('pl-PL', { minimumIntegerDigits: 2, useGrouping: false });
|
||||
const seconds = (time - minutes * 60).toLocaleString('pl-PL', { minimumIntegerDigits: 2, useGrouping: false });
|
||||
const minutes = Math.floor(time / 60).toLocaleString(undefined, { minimumIntegerDigits: 2, useGrouping: false });
|
||||
const seconds = (time - minutes * 60).toLocaleString(undefined, { minimumIntegerDigits: 2, useGrouping: false });
|
||||
|
||||
$("#timer").html(`${minutes}:${seconds}`);
|
||||
}
|
||||
@ -200,7 +198,7 @@ socket.on("game finished", (winnerIdx, oppName) => {
|
||||
});
|
||||
|
||||
socket.on('connect', () => {
|
||||
$(".cover .title").html("Oczekiwanie na serwer...");
|
||||
$(".cover .title").html(window.locale["Waiting for the server"]);
|
||||
});
|
||||
|
||||
socket.on("players ready", () => {
|
||||
@ -213,12 +211,12 @@ socket.on("player idx", (idx) => {
|
||||
|
||||
socket.on('turn update', (turnData) => {
|
||||
if (turnData.phase === "preparation") {
|
||||
$("#whosTurn").html("Faza przygotowań");
|
||||
$("#whosTurn").html(window.locale["Preparation phase"]);
|
||||
$(".boardSwitch").css("opacity", 0.3);
|
||||
} else {
|
||||
postPrep = true;
|
||||
myTurn = turnData.turn === playerIdx;
|
||||
turnData.turn === playerIdx ? $("#whosTurn").html("Twoja tura") : $("#whosTurn").html("Tura przeciwnika");
|
||||
turnData.turn === playerIdx ? $("#whosTurn").html(window.locale["Your turn"]) : $("#whosTurn").html(window.locale["Opponents turn"]);
|
||||
$(".boardSwitch").css("opacity", 1);
|
||||
}
|
||||
|
||||
@ -229,9 +227,4 @@ socket.on('turn update', (turnData) => {
|
||||
|
||||
socket.on('player left', () => {
|
||||
window.location.replace("/");
|
||||
});
|
||||
|
||||
// Profile stats: SELECT ROUND((AVG(statistics.won)) * 100) AS winrate, COUNT(statistics.match_id) AS alltime_matches, COUNT(CASE WHEN (YEAR(matches.date) = YEAR(NOW()) AND MONTH(matches.date) = MONTH(NOW())) THEN matches.match_id END) AS monthly_matches FROM accounts NATURAL JOIN statistics NATURAL JOIN matches WHERE accounts.nickname = "MaciejkaG";
|
||||
// Match history: SELECT statistics.match_id, accounts.nickname AS opponent, matches.match_type, statistics.won, matches.duration, matches.date FROM statistics JOIN matches ON matches.match_id = statistics.match_id JOIN accounts ON accounts.user_id = (CASE WHEN matches.host_id != statistics.user_id THEN matches.host_id ELSE matches.guest_id END) WHERE statistics.user_id = "c231c4f7-e179-11ee-920b-fa163e32c013";
|
||||
// Profile: SELECT nickname, account_creation FROM accounts WHERE user_id = "c231c4f7-e179-11ee-920b-fa163e32c013";
|
||||
// Badges: SELECT badge, achievement_date FROM badges WHERE user_id = "c231c4f7-e179-11ee-920b-fa163e32c013";
|
||||
});
|
@ -26,7 +26,7 @@ var nickname;
|
||||
socket.emit("my profile", (profile) => {
|
||||
// General profile data
|
||||
let options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
|
||||
$("#playerSince").html(new Date(profile.profile.account_creation).toLocaleDateString("pl-PL", options));
|
||||
$("#playerSince").html(new Date(profile.profile.account_creation).toLocaleDateString(undefined, options));
|
||||
$("#nickname").html(profile.profile.nickname);
|
||||
|
||||
// Profile stats
|
||||
@ -45,16 +45,16 @@ socket.emit("my profile", (profile) => {
|
||||
|
||||
let date = new Date(match.date).toLocaleDateString(undefined, options);
|
||||
|
||||
const seconds = (match.duration - minutes * 60).toLocaleString(undefined, { minimumIntegerDigits: 2, useGrouping: false });
|
||||
const minutes = Math.floor(match.duration / 60).toLocaleString(undefined, { minimumIntegerDigits: 2, useGrouping: false });
|
||||
const seconds = (match.duration - minutes * 60).toLocaleString(undefined, { minimumIntegerDigits: 2, useGrouping: false });
|
||||
|
||||
const duration = `${minutes}:${seconds}`;
|
||||
|
||||
matchHistoryDOM += `<div class="match" data-matchid="${match.match_id}"><div><h1 class="dynamic${match.won === 1 ? "" : " danger"}">${match.won === 1 ? "Zwycięstwo" : "Porażka"}</h1><span> vs. ${match.match_type === "pvp" ? match.opponent : "AI"}</span></div><h2 class="statsButton">Kliknij by wyświetlić statystyki</h2><span>${date}</span><br><span>${duration}</span></div>`;
|
||||
matchHistoryDOM += `<div class="match" data-matchid="${match.match_id}"><div><h1 class="dynamic${match.won === 1 ? "" : " danger"}">${match.won === 1 ? window.locale["Victory"] : window.locale["Defeat"]}</h1><span> vs. ${match.match_type === "pvp" ? match.opponent : "AI"}</span></div><h2 class="statsButton">${window.locale["Click to view match statistics"]}</h2><span>${date}</span><br><span>${duration}</span></div>`;
|
||||
}
|
||||
|
||||
if (matchHistoryDOM === "") {
|
||||
matchHistoryDOM = `<h2>${locale["No matches played"]}</h2>`;
|
||||
matchHistoryDOM = `<h2>${window.locale["No matches played"]}</h2>`;
|
||||
}
|
||||
|
||||
$(".matchList").html(matchHistoryDOM);
|
||||
@ -84,7 +84,7 @@ $("#createGameButton").on("click", function () {
|
||||
break;
|
||||
|
||||
default:
|
||||
alert(`${locale["Unknown error occured"]}\n${locale["Status:"]} ${response.status}`);
|
||||
alert(`${window.locale["Unknown error occured"]}\n${window.locale["Status:"]} ${response.status}`);
|
||||
lockUI(false);
|
||||
break;
|
||||
}
|
||||
@ -122,7 +122,7 @@ form.addEventListener('submit', (e) => {
|
||||
// break;
|
||||
|
||||
default:
|
||||
alert(`${locale["Unknown error occured"]}\n${locale["Status:"]} ${response.status}`);
|
||||
alert(`${window.locale["Unknown error occured"]}\n${window.locale["Status:"]} ${response.status}`);
|
||||
lockUI(false);
|
||||
switchView("mainMenuView");
|
||||
break;
|
||||
|
41
utils/localisation.js
Normal file
41
utils/localisation.js
Normal file
@ -0,0 +1,41 @@
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
export class Lang {
|
||||
constructor(langs) {
|
||||
const languagesPath = path.join(__dirname, '../lang');
|
||||
for (let i = 0; i < langs.length; i++) {
|
||||
const lang = langs[i];
|
||||
|
||||
if (fs.readdirSync(languagesPath).includes(`${lang}.json`)) {
|
||||
try {
|
||||
this.allText = JSON.parse(fs.readFileSync(path.join(languagesPath, `${lang}.json`), 'utf8'));
|
||||
return;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t(key) {
|
||||
if (this.allText == null) {
|
||||
throw new Error(`Language class has been improperly configured. (Unknown localisation module error)`);
|
||||
} else {
|
||||
let keySplit = key.split(".");
|
||||
|
||||
try {
|
||||
return keySplit.reduce((x, y) => x[y], this.allText);
|
||||
} catch (e) {
|
||||
if (e instanceof TypeError) {
|
||||
return "LocKeyErr"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,13 +10,13 @@
|
||||
<div class="container" id="pvpJoinView">
|
||||
<div>
|
||||
<h1>Statki</h1>
|
||||
<h2>Autoryzacja</h2>
|
||||
<h2>{{ t 'auth.Authorisation' }}</h2>
|
||||
<div class="modes">
|
||||
<div>
|
||||
<p>Podaj kod wysłany do Twojej skrzynki e-mail</p>
|
||||
<p>{{ t 'auth.Enter the code sent to your e-mail box' }}</p>
|
||||
<form action="/api/auth" method="post">
|
||||
<input type="text" name="code" placeholder="Kod" style="font-size: 1rem;" minlength="8" maxlength="10" autocomplete="off">
|
||||
<input type="submit" value="Zaloguj się">
|
||||
<input type="text" name="code" placeholder="{{ t 'auth.Code' }}" style="font-size: 1rem;" minlength="8" maxlength="10" autocomplete="off">
|
||||
<input type="submit" value="{{ t 'auth.Login' }}">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,9 +1,9 @@
|
||||
<div class="cover">
|
||||
<h1 class="title">Łączenie...</h1>
|
||||
<h1 class="title">{{ t 'board.Connecting' }}</h1>
|
||||
<div class="dialog">
|
||||
<h1 id="state"></h1>
|
||||
<h3 id="opponent"></h3>
|
||||
<button onclick="window.location.href = '/'">Powróć do menu</button>
|
||||
<button onclick="window.location.href = '/'">{{ t 'board.Back to menu' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -13,20 +13,20 @@
|
||||
<div class="panelContainer">
|
||||
<div class="shapes">
|
||||
<div class="ownBoardInfo">
|
||||
<h3>Wybrany statek</h3>
|
||||
<h2 class="dynamic" id="selectedShip">Jednomasztowiec</h2>
|
||||
<h3>Dostępne: <span class="dynamic danger" id="shipsLeft">1</span></h3>
|
||||
<h3>{{ t 'board.Selected ship' }}</h3>
|
||||
<h2 class="dynamic" id="selectedShip">{{ t 'board.Single-masted' }}</h2>
|
||||
<h3>{{ t 'board.Available:' }} <span class="dynamic danger" id="shipsLeft">-</span></h3>
|
||||
</div>
|
||||
<span class="break"></span>
|
||||
<div class="controls">
|
||||
<h2>Sterowanie</h2>
|
||||
<h3 class="controlsOwnBoard"><span class="important">S</span> Zmiana statku</h3>
|
||||
<h3 class="controlsOwnBoard"><span class="important">R</span> Obrót statku</h3>
|
||||
<h3 class="boardSwitch"><span class="important">B</span> Zamiana planszy</h3>
|
||||
<h2>{{ t 'board.Controls' }}</h2>
|
||||
<h3 class="controlsOwnBoard"><span class="important">S</span> {{ t 'board.Change ship' }}</h3>
|
||||
<h3 class="controlsOwnBoard"><span class="important">R</span> {{ t 'board.Rotate ship' }}</h3>
|
||||
<h3 class="boardSwitch"><span class="important">B</span> {{ t 'board.Change boards' }}</h3>
|
||||
</div>
|
||||
<div class="mobileControls">
|
||||
<button class="controlsOwnBoard" onclick="switchShips()">Zmiana statku</button>
|
||||
<button class="boardSwitch" onclick="switchBoards()">Zmiana planszy</button>
|
||||
<button class="controlsOwnBoard" onclick="switchShips()">{{ t 'board.Change ship' }}</button>
|
||||
<button class="boardSwitch" onclick="switchBoards()">{{ t 'board.Change boards' }}</button>
|
||||
</div>
|
||||
<span class="break"></span>
|
||||
<h3><span class="dynamic" id="whosTurn"></span></h3>
|
||||
@ -50,6 +50,29 @@
|
||||
<button class="tippyBtn" style="background-color: var(--danger)" onclick="manualShoot([[FIELDPOS]])"><span class="material-symbols-outlined">ads_click</span></button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.locale = {
|
||||
"Waiting for the server": "{{ t 'board.Waiting for the server' }}",
|
||||
|
||||
"Reconnecting": "{{ t 'errors.Reconnecting' }}",
|
||||
"Reconnected": "{{ t 'errors.Reconnected' }}",
|
||||
"Reconnection error occured": "{{ t 'errors.Reconnection error occured' }}",
|
||||
"Reconnection failed": "{{ t 'errors.Reconnection failed' }}",
|
||||
"Disconnected": "{{ t 'errors.Disconnected' }}",
|
||||
"Try to refresh the page if this error reoccurs": "{{ t 'errors.Try to refresh the page if this error reoccurs' }}",
|
||||
"Connection error": "{{ t 'errors.Connection error' }}",
|
||||
|
||||
"Single-masted": "{{ t 'board.Single-masted' }}",
|
||||
"Two-masted": "{{ t 'board.Two-masted' }}",
|
||||
"Three-masted": "{{ t 'board.Three-masted' }}",
|
||||
"Four-masted": "{{ t 'board.Four-masted' }}",
|
||||
|
||||
"Preparation phase": "{{ t 'board.Preparation phase' }}",
|
||||
"Your turn": "{{ t 'board.Your turn' }}",
|
||||
"Opponents turn": "{{ t 'board.Opponents turn' }}",
|
||||
};
|
||||
</script>
|
||||
|
||||
<script src="/assets/js/battleships-lib.js"></script>
|
||||
<script src="/assets/js/main.js"></script>
|
||||
<script src="/assets/js/key-handling.js"></script>
|
||||
|
@ -28,11 +28,11 @@
|
||||
<div class="container" id="pvpJoinView">
|
||||
<div>
|
||||
<h1>Statki</h1>
|
||||
<h2>Błąd</h2>
|
||||
<h2>{{ t 'error.Error' }}</h2>
|
||||
<div class="modes">
|
||||
<div>
|
||||
<p>{{ error }}</p>
|
||||
<button onclick="window.location.href = '{{ fallback }}'">Wróć</button>
|
||||
<button onclick="window.location.href = '{{ fallback }}'">{{ t 'error.Return' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,111 +1,114 @@
|
||||
<nav><span onclick="switchView('mainMenuView')">Menu główne</span> <span id="profileButton" onclick="switchView('profileView')">Profil</span></nav>
|
||||
<nav><span onclick="switchView('mainMenuView')">{{ t 'menu.navbar.Main menu' }}</span> <span id="profileButton" onclick="switchView('profileView')">{{ t 'menu.navbar.Profile' }}</span></nav>
|
||||
{{!-- <h1 class="header">Statki</h1> --}}
|
||||
<div class="container" id="mainMenuView" data-title="Statki" data-path="/">
|
||||
<div class="container" id="mainMenuView" data-path="/">
|
||||
<div>
|
||||
|
||||
<h2>Wybierz tryb gry</h2>
|
||||
<h2>{{ t 'menu.index.Select game mode' }}</h2>
|
||||
<div class="modes">
|
||||
<div id="pvpMenuButton">
|
||||
<h2>PvP</h2>
|
||||
<p>Graj przeciwko innemu graczowi</p>
|
||||
<h2>{{ t 'menu.index.PvP' }}</h2>
|
||||
<p>{{ t 'menu.index.Play against another player' }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<h2 id="ai">Vs. AI</h2>
|
||||
<p>Graj przeciwko komputerowi</p>
|
||||
<h2 id="ai">{{ t 'menu.index.Vs AI' }}</h2>
|
||||
<p>{{ t 'menu.index.Play against the computer' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container" id="pvpMenuView" data-title="Statki / PvP" data-path="/pvp">
|
||||
<div class="container" id="pvpMenuView" data-path="/pvp">
|
||||
<div>
|
||||
<h2>PvP</h2>
|
||||
<h2>{{ t 'menu.PvP.PvP' }}</h2>
|
||||
<div class="modes">
|
||||
<div id="createGameButton">
|
||||
<h2>Stwórz</h2>
|
||||
<p>Stwórz własny pokój</p>
|
||||
<h2>{{ t 'menu.PvP.Create' }}</h2>
|
||||
<p>{{ t 'menu.PvP.Create your own room' }}</p>
|
||||
</div>
|
||||
<div onclick="switchView('pvpJoinView')">
|
||||
<h2>Dołącz</h2>
|
||||
<p>Dołącz do czyjegoś pokoju poprzez kod</p>
|
||||
<h2>{{ t 'menu.PvP.Join' }}</h2>
|
||||
<p>{{ t 'menu.PvP.Join a room by a code' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container" id="pvpCreateView" data-title="Statki / PvP / Stwórz" data-path="/pvp/create">
|
||||
<div class="container" id="pvpCreateView" data-path="/pvp/create">
|
||||
<div>
|
||||
<h2>PvP / Stwórz</h2>
|
||||
<h2>{{ t 'menu.PvP/Create.PvP / Create' }}</h2>
|
||||
<div class="modes">
|
||||
<div>
|
||||
<h2>Kod pokoju:</h2>
|
||||
<h2>{{ t 'menu.PvP/Create.Room code' }}</h2>
|
||||
<input type="text" maxlength="6" readonly value="-" id="createGameCode">
|
||||
<h3>Oczekiwanie na gracza...</h3>
|
||||
<button id="leaveGameButton">Opuść pokój</button>
|
||||
<h3>{{ t 'menu.PvP/Create.Waiting for an opponent' }}</h3>
|
||||
<button id="leaveGameButton">{{ t 'menu.PvP/Create.Leave the room' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container" id="pvpJoinView" data-title="Statki / PvP / Dołącz" data-path="/pvp/join">
|
||||
<div class="container" id="pvpJoinView" data-path="/pvp/join">
|
||||
<div>
|
||||
<h2>PvP / Dołącz</h2>
|
||||
<h2>{{ t 'menu.PvP/Join.PvP / Join' }}</h2>
|
||||
<div class="modes">
|
||||
<div>
|
||||
<form action="/api/joinme" id="pvpJoinForm">
|
||||
<input type="text" maxlength="6" id="pvpJoinCode" placeholder="Kod pokoju" autocomplete="off">
|
||||
<input type="submit" value="Dołącz">
|
||||
<input type="text" maxlength="6" id="pvpJoinCode" placeholder="{{ t 'menu.PvP/Join.Room code' }}" autocomplete="off">
|
||||
<input type="submit" value="{{ t 'menu.PvP/Join.Join' }}">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container" id="preparingGame" data-title="Statki / PvP / Przygotowywanie" data-path="/pvp/prepairing">
|
||||
<div class="container" id="preparingGame" data-path="/pvp/prepairing">
|
||||
<div>
|
||||
<h2>PvP / Wczytywanie</h2>
|
||||
<h2>{{ t 'menu.PvP/Loading.PvP / Loading' }}</h2>
|
||||
<div class="modes">
|
||||
<div>
|
||||
<h2>Czekaj...</h2>
|
||||
<h3>Wkrótce nastąpi przekierowanie</h3>
|
||||
<h3>Przeciwnik:</h3>
|
||||
<h2>{{ t 'menu.PvP/Loading.Wait' }}</h2>
|
||||
<h3>{{ t 'menu.PvP/Loading.You will be redirected soon' }}</h3>
|
||||
<h3>{{ t 'menu.PvP/Loading.Opponent:' }}</h3>
|
||||
<h4 id="oppNameField"></h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container" id="profileView" data-title="Statki / Profil" data-path="/profile">
|
||||
<div class="container" id="profileView" data-path="/profile">
|
||||
<div class="profile">
|
||||
<h1 id="nickname">Wczytywanie...</h1>
|
||||
<h1 id="nickname">{{ t 'menu.Profile.Loading' }}</h1>
|
||||
<div>
|
||||
<span>Gracz od: </span>
|
||||
<span>{{ t 'menu.Profile.Player since:' }} </span>
|
||||
<span id="playerSince">-</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats">
|
||||
<div class="matchList">
|
||||
<div class="match">
|
||||
<div><h1 class="dynamic danger">Porażka</h1><span> vs. Wczytywanie...</span></div>
|
||||
<h2 class="statsButton">Kliknij by wyświetlić statystyki</h2>
|
||||
</div>
|
||||
<div class="match">
|
||||
<div><h1 class="dynamic">Zwycięstwo</h1><span> vs. Wczytywanie...</span></div>
|
||||
<h2 class="statsButton">Kliknij by wyświetlić statystyki</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="matchList"></div>
|
||||
<div class="periodal">
|
||||
<div class="stat"><h1 id="monthlyPlayed">-</h1><span>meczów zagranych w ostatnim miesiącu</span></div>
|
||||
<div class="stat"><h1 id="totalPlayed">-</h1><span>meczów zagranych łącznie</span></div>
|
||||
<div class="stat"><h1 id="winrate">-</h1><span>winrate</span></div>
|
||||
<div class="stat"><h1 id="monthlyPlayed">-</h1><span>{{ t 'menu.Profile.matches played this month' }}</span></div>
|
||||
<div class="stat"><h1 id="totalPlayed">-</h1><span>{{ t 'menu.Profile.total matches played' }}</span></div>
|
||||
<div class="stat"><h1 id="winrate">-</h1><span>{{ t 'menu.Profile.winrate' }}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
locale = {
|
||||
"Unknown error occured": "{{ __('Profile.') }}"
|
||||
}
|
||||
window.locale = {
|
||||
"Unknown error occured": "{{ t 'menu.General.Unknown error occured' }}",
|
||||
"Status:": "{{ t 'menu.General.Status:' }}",
|
||||
"Victory": "{{ t 'menu.Profile.Victory' }}",
|
||||
"Defeat": "{{ t 'menu.Profile.Defeat' }}",
|
||||
"Click to view match statistics": "{{ t 'menu.Profile.Click to view match statistics' }}",
|
||||
|
||||
"Reconnecting": "{{ t 'errors.Reconnecting' }}",
|
||||
"Reconnected": "{{ t 'errors.Reconnected' }}",
|
||||
"Reconnection error occured": "{{ t 'errors.Reconnection error occured' }}",
|
||||
"Reconnection failed": "{{ t 'errors.Reconnection failed' }}",
|
||||
"Disconnected": "{{ t 'errors.Disconnected' }}",
|
||||
"Try to refresh the page if this error reoccurs": "{{ t 'errors.Try to refresh the page if this error reoccurs' }}",
|
||||
"Connection error": "{{ t 'errors.Connection error' }}",
|
||||
};
|
||||
</script>
|
||||
<script src="/assets/js/spa_lib.js"></script>
|
||||
<script src="/assets/js/socket.js"></script>
|
||||
|
@ -10,12 +10,12 @@
|
||||
<div class="container" id="pvpJoinView">
|
||||
<div>
|
||||
<h1>Statki</h1>
|
||||
<h2>Logowanie</h2>
|
||||
<h2>{{ t 'login.Login' }}</h2>
|
||||
<div class="modes">
|
||||
<div>
|
||||
<form action="/api/login" method="post">
|
||||
<input type="email" name="email" placeholder="Adres e-mail" style="font-size: 1rem;">
|
||||
<input type="submit" value="Przejdź dalej">
|
||||
<input type="email" name="email" placeholder="{{ t 'login.E-mail address' }}" style="font-size: 1rem;">
|
||||
<input type="submit" value="{{ t 'login.Proceed' }}">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,13 +10,13 @@
|
||||
<div class="container" id="pvpJoinView">
|
||||
<div>
|
||||
<h1>Statki</h1>
|
||||
<h2>Konfiguracja profilu</h2>
|
||||
<h2>{{ t 'setup.Profile setup' }}</h2>
|
||||
<div class="modes">
|
||||
<div>
|
||||
<p>Twój nickname będzie widoczny dla innych graczy</p>
|
||||
<p>{{ t 'setup.Your nickname will be visible to other players' }}</p>
|
||||
<form action="/api/nickname" method="post">
|
||||
<input type="text" name="nickname" placeholder="Nazwa użytkownika" style="font-size: 1rem;">
|
||||
<input type="submit" value="Zatwierdź">
|
||||
<input type="text" name="nickname" placeholder="{{ t 'setup.Nickname' }}" style="font-size: 1rem;">
|
||||
<input type="submit" value="{{ t 'setup.Confirm' }}">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user