Major changes

- Multiple translation improvements
- Added language switch in settings
- Minor fixes and improvements

- Still need to fix error messages (they are hardcoded in polish)
This commit is contained in:
MaciejkaG 2024-04-06 01:48:49 +02:00
parent acdbad41cd
commit 38ae0c7796
9 changed files with 130 additions and 23 deletions

View File

@ -16,6 +16,7 @@ import { Lang } from './utils/localisation.js';
import { rateLimit } from 'express-rate-limit'; import { rateLimit } from 'express-rate-limit';
import { RedisStore as LimiterRedisStore } from 'rate-limit-redis'; import { RedisStore as LimiterRedisStore } from 'rate-limit-redis';
import SessionRedisStore from 'connect-redis'; import SessionRedisStore from 'connect-redis';
import mysql from 'mysql';
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
@ -24,6 +25,8 @@ const app = express();
const flags = process.env.flags ? process.env.flags.split(",") : null; const flags = process.env.flags ? process.env.flags.split(",") : null;
const langs = [{ id: "en", name: "English" }, { id: "pl", name: "Polish" }];
app.use(express.json()); app.use(express.json());
app.use(express.urlencoded({ extended: true })); app.use(express.urlencoded({ extended: true }));
@ -93,6 +96,9 @@ app.get('/', async (req, res) => {
} else if (req.session.nickname == null) { } else if (req.session.nickname == null) {
auth.getLanguage(req.session.userId).then(language => { auth.getLanguage(req.session.userId).then(language => {
var locale; var locale;
req.session.autoLang = language == null ? true : false;
if (language) { if (language) {
locale = new Lang([language]); locale = new Lang([language]);
req.session.langs = [language]; req.session.langs = [language];
@ -351,10 +357,47 @@ io.on('connection', async (socket) => {
socket.on('my profile', (callback) => { socket.on('my profile', (callback) => {
auth.getProfile(session.userId).then((profile) => { auth.getProfile(session.userId).then((profile) => {
profile.uid = session.userId;
callback(profile); callback(profile);
}); });
}); });
socket.on('locale options', (callback) => {
const locale = new Lang(session.langs);
let userLanguage = langs.find((element) => element.id == locale.lang);
let userLangs = langs.filter((element) => element.id != locale.lang);
if (session.autoLang) {
userLangs.unshift(userLanguage);
userLangs.unshift({ id: "null", name: "Auto" });
} else {
userLangs.unshift({ id: "null", name: "Auto" });
userLangs.unshift(userLanguage);
}
callback(userLangs);
});
socket.on('change locale', (locale, callback) => {
if (locale === "null" || langs.find((element) => element.id == locale)) {
locale = locale === "null" ? null : locale;
const conn = mysql.createConnection({ host: process.env.db_host, user: process.env.db_user, password: process.env.db_pass, database: 'statki' });
conn.query(`UPDATE accounts SET language = ${conn.escape(locale)} WHERE user_id = ${conn.escape(session.userId)}`, (err) => {
if (err) { callback({ status: 'dbErr' }); return; }
else callback({ status: 'ok' });
req.session.reload((err) => {
if (err) return socket.disconnect();
req.session.autoLang = locale ? false : true;
req.session.save();
});
});
conn.end();
}
});
socket.on('create lobby', (callback) => { socket.on('create lobby', (callback) => {
if (socket.rooms.size === 1) { if (socket.rooms.size === 1) {
let id = genID(); let id = genID();

View File

@ -57,6 +57,9 @@
"winrate": "winrate", "winrate": "winrate",
"No matches played": "No matches played" "No matches played": "No matches played"
}, },
"Settings": {
"General": "General"
},
"General": { "General": {
"Unknown error occured": "Unknown error occured", "Unknown error occured": "Unknown error occured",
"Status:": "Status:" "Status:": "Status:"

View File

@ -43,7 +43,7 @@
"PvP/Loading": { "PvP/Loading": {
"PvP / Loading": "PvP / Wczytywanie", "PvP / Loading": "PvP / Wczytywanie",
"Wait": "Czekaj...", "Wait": "Czekaj...",
"You will be redirected soon": "Wkrótce zostaniesz przekierowany(-a)", "You will be redirected soon": "Wkrótce nastąpi przekierowanie",
"Opponent:": "Przeciwnik" "Opponent:": "Przeciwnik"
}, },
"Profile": { "Profile": {
@ -56,9 +56,11 @@
"total matches played": "meczy zagranych łącznie", "total matches played": "meczy zagranych łącznie",
"winrate": "winrate", "winrate": "winrate",
"No matches played": "Nie zagrano meczy" "No matches played": "Nie zagrano żadnych meczy"
},
"Settings": {
"General": "Ogólne"
}, },
"General": { "General": {
"Unknown error occured": "Wystąpił nieznany błąd", "Unknown error occured": "Wystąpił nieznany błąd",
"Status:": "Status:" "Status:": "Status:"

View File

@ -2,6 +2,7 @@
"ignore": [ "ignore": [
"public/*", "public/*",
"views/*", "views/*",
"utils/mail/*" "utils/mail/*",
"lang/*"
] ]
} }

View File

@ -246,8 +246,6 @@ nav span:hover {
flex-direction: column; flex-direction: column;
gap: 2rem; gap: 2rem;
flex: 2; flex: 2;
overflow-y: scroll;
} }
#profileView .matchList::-webkit-scrollbar { #profileView .matchList::-webkit-scrollbar {
@ -323,4 +321,20 @@ nav span:hover {
.tippyTemplate { .tippyTemplate {
display: none; display: none;
}
#settingsView label {
font-size: 1.2rem;
}
#settingsView select {
padding: 0.5rem 1rem;
padding: 0.5rem 2rem;
font-size: 1rem;
background-color: black;
border: solid 1px white;
color: white;
border-radius: 15px;
outline: none;
margin-left: 2rem;
} }

View File

@ -29,7 +29,38 @@ socket.on("gameReady", (gameId) => {
var nickname; var nickname;
socket.emit('locale options', (langs) => {
console.log("Fetching available locale options");
let menu = "";
langs.forEach(lang => {
menu += `<option value="${lang.id}">${lang.name}</option>`;
});
$("#languages").html(menu);
console.log("Locale options fetched");
});
$("#languages").on("change", function() {
lockUI(true);
console.log("Switching language to", $(this).val());
socket.emit("change locale", $(this).val(), (response) => {
switch (response.status) {
case "ok":
console.log("Switched languages, refreshing");
window.location.reload();
break;
default:
alert(`${window.locale["Unknown error occured"]}\n${window.locale["Status:"]} ${response.status}`);
lockUI(false);
break;
}
});
});
socket.emit("my profile", (profile) => { socket.emit("my profile", (profile) => {
console.log("Received user data. UID:", profile.uid);
// General profile data // General profile data
let options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }; let options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
$("#playerSince").html(new Date(profile.profile.account_creation).toLocaleDateString(undefined, options)); $("#playerSince").html(new Date(profile.profile.account_creation).toLocaleDateString(undefined, options));
@ -59,7 +90,7 @@ socket.emit("my profile", (profile) => {
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>`; 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 === "") { if (!matchHistoryDOM) {
matchHistoryDOM = `<h2>${window.locale["No matches played"]}</h2>`; matchHistoryDOM = `<h2>${window.locale["No matches played"]}</h2>`;
} }

View File

@ -84,9 +84,9 @@ export class MailAuth {
const row = response[0]; const row = response[0];
resolve({ status: 1, uid: row.user_id }); resolve({ status: 1, uid: row.user_id });
conn.end();
}); });
conn.end();
}); });
} }
@ -101,9 +101,9 @@ export class MailAuth {
} else { } else {
resolve(null); resolve(null);
} }
conn.end();
}); });
conn.end();
}); });
} }
@ -191,9 +191,9 @@ export class MailAuth {
resolve({ status: 1, uid: row.user_id }); resolve({ status: 1, uid: row.user_id });
conn.end();
}); });
conn.end();
}); });
} }
@ -205,10 +205,10 @@ export class MailAuth {
else conn.query(`INSERT INTO statistics(match_id, user_id, board, won) VALUES (${conn.escape(matchId)}, ${conn.escape(hostId)}, ${conn.escape(JSON.stringify(boards[0]))}, ${conn.escape(!winnerIdx ? 1 : 0)}), (${conn.escape(matchId)}, ${conn.escape(guestId)}, ${conn.escape(JSON.stringify(boards[1]))}, ${conn.escape(winnerIdx ? 1 : 0)})`, async (error, response) => { else conn.query(`INSERT INTO statistics(match_id, user_id, board, won) VALUES (${conn.escape(matchId)}, ${conn.escape(hostId)}, ${conn.escape(JSON.stringify(boards[0]))}, ${conn.escape(!winnerIdx ? 1 : 0)}), (${conn.escape(matchId)}, ${conn.escape(guestId)}, ${conn.escape(JSON.stringify(boards[1]))}, ${conn.escape(winnerIdx ? 1 : 0)})`, async (error, response) => {
if (error) reject(error); if (error) reject(error);
else resolve(); else resolve();
conn.end();
}); });
}); });
conn.end();
}); });
} }
@ -227,9 +227,9 @@ export class MailAuth {
resolve({ profile, stats, matchHistory }); resolve({ profile, stats, matchHistory });
} }
conn.end();
}); });
conn.end();
}); });
} }
@ -251,9 +251,9 @@ export class MailAuth {
conn.query(`UPDATE accounts SET nickname = ${conn.escape(nickname)} WHERE user_id = ${conn.escape(uid)}`, (error) => { conn.query(`UPDATE accounts SET nickname = ${conn.escape(nickname)} WHERE user_id = ${conn.escape(uid)}`, (error) => {
if (error) reject(error); if (error) reject(error);
resolve(); resolve();
conn.end();
}); });
conn.end();
}); });
} }
@ -263,9 +263,9 @@ export class MailAuth {
conn.query(`SELECT nickname FROM accounts WHERE user_id = ${conn.escape(uid)}`, (error, response) => { conn.query(`SELECT nickname FROM accounts WHERE user_id = ${conn.escape(uid)}`, (error, response) => {
if (error) reject(error); if (error) reject(error);
resolve(response[0].nickname); resolve(response[0].nickname);
conn.end();
}); });
conn.end();
}); });
} }
} }

View File

@ -8,18 +8,23 @@ const __dirname = path.dirname(__filename);
export class Lang { export class Lang {
constructor(langs) { constructor(langs) {
const languagesPath = path.join(__dirname, '../lang'); const languagesPath = path.join(__dirname, '../lang');
this.allText = null;
for (let i = 0; i < langs.length; i++) { for (let i = 0; i < langs.length; i++) {
const lang = langs[i]; const lang = langs[i];
if (fs.readdirSync(languagesPath).includes(`${lang}.json`)) { if (fs.readdirSync(languagesPath).includes(`${lang}.json`)) {
try { try {
this.allText = JSON.parse(fs.readFileSync(path.join(languagesPath, `${lang}.json`), 'utf8')); this.allText = JSON.parse(fs.readFileSync(path.join(languagesPath, `${lang}.json`), 'utf8'));
this.lang = lang;
return; return;
} catch (e) { } catch (e) {
console.log(e); console.log(e);
} }
} }
} }
this.allText = JSON.parse(fs.readFileSync(path.join(languagesPath, 'en.json'), 'utf8'));
this.lang = 'en';
} }
t(key) { t(key) {
@ -37,5 +42,7 @@ export class Lang {
} }
} }
} }
} }

View File

@ -93,9 +93,14 @@
</div> </div>
</div> </div>
<div class="container" id="settingsView" data-path="/match"> <div class="container" id="settingsView" data-path="/settings">
<div> <div>
<h1>{{ t 'menu.Settings.Settings' }}</h1>
<h2>{{ t 'menu.Settings.General' }}</h2>
<label for="language">Language: </label>
<select name="language" id="languages">
</select>
</div> </div>
</div> </div>
@ -106,6 +111,7 @@
"Victory": "{{ t 'menu.Profile.Victory' }}", "Victory": "{{ t 'menu.Profile.Victory' }}",
"Defeat": "{{ t 'menu.Profile.Defeat' }}", "Defeat": "{{ t 'menu.Profile.Defeat' }}",
"Click to view match statistics": "{{ t 'menu.Profile.Click to view match statistics' }}", "Click to view match statistics": "{{ t 'menu.Profile.Click to view match statistics' }}",
"No matches played": "{{ t 'menu.Profile.No matches played' }}",
"Reconnecting": "{{ t 'errors.Reconnecting' }}", "Reconnecting": "{{ t 'errors.Reconnecting' }}",
"Reconnected": "{{ t 'errors.Reconnected' }}", "Reconnected": "{{ t 'errors.Reconnected' }}",