diff --git a/README.md b/README.md
index 1f5996d..5a08ffe 100644
--- a/README.md
+++ b/README.md
@@ -1,18 +1,30 @@
-# 2020 L4 Application Programming coursework
+# Scrabble (Multiplayer)
+## 2020/21 L4 Application Programming coursework
SEE BELOW FOR CONFIGURATION GUIDE
-## Product Description
+### Product Description
https://scrabble.hasbro.com/en-us/rules
https://www.zapsplat.com/?s=scrabble
https://www.scrabble3d.info/t2342f139-Default-rules.html
-## Configuration Guide
+
+If the scope allowed for it, every function would be (reasonably) unit tested.
+
+The solution to locale-ise language in HTML is extremely naive and there are a lot better ways to do it, i did what i could in the time without a full refractor and SSR.
+However it is not at much detriment of readability and maintainability of the code so i diddn't deem it neccesary.
+
+The locales are stored in different language files so it is easier for people to contribute and thus more maintanable.
+
+### Configuration Guide
+### Contributing
-## Acknowledgements
+To contribute a translation
+
+### Acknowledgements
Inês Filipa Baiõa Antunes - Tranlations (Portuguese, Spanish)
diff --git a/client/public/game/index.html b/client/public/game/index.html
index 5f54dc5..89f3031 100644
--- a/client/public/game/index.html
+++ b/client/public/game/index.html
@@ -12,8 +12,9 @@
Lobby
-
- Game Lobby
+
+
+
@@ -22,9 +23,12 @@
diff --git a/client/public/index.js b/client/public/index.js
index f3d4d43..3846239 100644
--- a/client/public/index.js
+++ b/client/public/index.js
@@ -8,7 +8,7 @@ UsernameForm.addEventListener('submit', onUsernameSubmit);
function playSingleplayer()
{
- document.location.href += '/scrabble';
+ window.location.pathname = "/scrabble";
}
// User submits their desired username
@@ -38,7 +38,7 @@ async function onUsernameSubmit(e)
if (body.errors)
{
ConnectionState.classList.add('red');
- ConnectionState.innerHTML = `ERROR: ${body.errors[body.errors.length - 1].desc}`;
+ ConnectionState.innerHTML = `${localeString('error-bold')}: ${localeString(body.errors[body.errors.length - 1].desc)}`;
return;
}
@@ -51,6 +51,6 @@ async function onUsernameSubmit(e)
{
sessionStorage.setItem('user', JSON.stringify(body.login.user));
console.log(sessionStorage.user)
- document.location.href += 'game';
+ window.location.pathname = "/game";
}
}
diff --git a/client/public/scrabble/board.js b/client/public/scrabble/board.js
index fa2272d..7bf17c3 100644
--- a/client/public/scrabble/board.js
+++ b/client/public/scrabble/board.js
@@ -58,7 +58,15 @@ window.onload = e => {
const boardLocation = document.querySelector(`#row-${y}`).querySelector(`#col-${x}`);
boardLocation.classList.add(BoardLookup[BoardLocations[location]]);
- boardLocation.innerHTML = BoardLocations[location];
+ let localeThing = BoardLocations[location];
+
+ // hacky but it works
+ if (localStorage.getItem('locale') === "es" || localStorage.getItem('locale') === "pt")
+ {
+ localeThing = localeThing.replace('W', 'P');
+ }
+
+ boardLocation.innerHTML = localeThing;
}
// flip it
@@ -73,6 +81,13 @@ window.onload = e => {
const boardLocation = document.querySelector(`#row-${y}`).querySelector(`#col-${x}`);
boardLocation.classList.add(BoardLookup[BoardLocations[location]]);
- boardLocation.innerHTML = BoardLocations[location];
+ let localeThing = BoardLocations[location];
+
+ if (localStorage.getItem('locale') === "es" || localStorage.getItem('locale') === "pt")
+ {
+ localeThing = localeThing.replace('W', 'P');
+ }
+
+ boardLocation.innerHTML = localeThing;
}
};
diff --git a/data/locale.json b/data/locale.json
new file mode 100644
index 0000000..d11ec75
--- /dev/null
+++ b/data/locale.json
@@ -0,0 +1,288 @@
+{
+ "scrabble-name": {
+ "en": "Scrabble",
+ "es": "Scrabble",
+ "pt": "Scrabble"
+ },
+ "game-lobby": {
+ "en": "create or join a game",
+ "es": "Crea o conecta a un juego",
+ "pt": "Crie ou entre em um jogo"
+ },
+ "name": {
+ "en": "name",
+ "es": "nombre",
+ "pt": "nome"
+ },
+ "username": {
+ "en": "Username",
+ "es": "Nombre de usuario",
+ "pt": "Nome de usuàrio"
+ },
+ "players": {
+ "en": "Players",
+ "es": "Jugadores",
+ "pt": "Jogadores"
+ },
+ "button-singleplayer": {
+ "en": "Play singleplayer",
+ "es": "Jugar a un(a) jugador(a)",
+ "pt": "Jogar singleplayer"
+ },
+ "button-submit": {
+ "en": "Submit",
+ "es": "Enviar",
+ "pt": "Enviar"
+ },
+ "button-create": {
+ "en": "create",
+ "es": "crear",
+ "pt": "criar"
+ },
+ "button-join": {
+ "en": "join",
+ "es": "participar",
+ "pt": "entrar"
+ },
+ "button-back": {
+ "en": "back",
+ "es": "regresar",
+ "pt": "voltar"
+ },
+
+ "status-connected": {
+ "en": "Connected",
+ "es": "Conectado(a)",
+ "pt": "Conectado(a)"
+ },
+ "status-connected-as": {
+ "en": "Connected as ",
+ "es": "Conectado/a como ",
+ "pt": "Conectado/a como "
+ },
+ "status-disconnected": {
+ "en": "Disconnected",
+ "es": "Desconectado/a",
+ "pt": "Desconectado/a"
+ },
+ "connection-waiting": {
+ "en": "Waiting for connection",
+ "es": "Esperando la conexión",
+ "pt": "Aguardando conexão"
+ },
+
+ "message": {
+ "en": "message",
+ "es": "mensaje",
+ "pt": "mensagem"
+ },
+ "log-console": {
+ "en": "log console",
+ "es": "consola de log",
+ "pt": "console de log"
+ },
+ "button-send": {
+ "en": "send",
+ "es": "enviar",
+ "pt": "enviar"
+ },
+
+ "lobby": {
+ "en": "Lobby",
+ "es": "Lobby",
+ "pt": "Lobby"
+ },
+ "lobby-create": {
+ "en": "Create Lobby",
+ "es": "Crear Lobby",
+ "pt": "Criar Lobby"
+ },
+ "lobby-join": {
+ "en": "Join Lobby",
+ "es": "Conectarse al Lobby",
+ "pt": "Conectar ao Lobby"
+ },
+ "lobby-join-code": {
+ "en": "Join Code",
+ "es": "Código para Conectar",
+ "pt": "Código para Conectar"
+ },
+ "lobby-code": {
+ "en": "lobby code",
+ "es": "código de lobby",
+ "pt": "código do lobby"
+ },
+ "lobby-private": {
+ "en": "private lobby",
+ "es": "lobby privado",
+ "pt": "lobby privado"
+ },
+ "lobby-allow-spectators": {
+ "en": "allow spectators",
+ "es": "permitir espectadores",
+ "pt": "permitir espectadores"
+ },
+ "lobby-join-spectator": {
+ "en": "join as spectator",
+ "es": "conectar como espectador(a)",
+ "pt": "junte-se como espectador"
+ },
+ "lobby-created-joining": {
+ "en": "Lobby created, Joining...",
+ "es": "Lobby creado, Conectando...",
+ "pt": "Lobby criaso, Juntando-se..."
+ },
+ "lobby-created": {
+ "en": "created lobby",
+ "es": "lobby creado",
+ "pt": "Lobby criado"
+ },
+ "lobby-joining": {
+ "en": "joining lobby",
+ "es": "entrando al lobby",
+ "pt": "entrando no lobby"
+ },
+ "lobby-joined": {
+ "en": "joined lobby",
+ "es": "entró en el lobby",
+ "pt": "entrou no lobby"
+ },
+ "lobby-deleted": {
+ "en": "deleted lobby",
+ "es": "lobby eliminado",
+ "pt": "lobby apagado"
+ },
+ "joined": {
+ "en": "joined",
+ "es": "conectado(a)",
+ "pt": "juntou"
+ },
+ "left": {
+ "en": "left",
+ "es": "salió",
+ "pt": "saiu"
+ },
+ "left-lobby": {
+ "en": "left lobby",
+ "es": "salió del lobby",
+ "pt": "saiu do lobby"
+ },
+
+ "spectators": {
+ "en": "Spectators",
+ "es": "Espectadores",
+ "pt": "Espectadores"
+ },
+ "visibility": {
+ "en": "Visibility",
+ "es": "Visibilidad",
+ "pt": "Visibilidade"
+ },
+ "status": {
+ "en": "Status",
+ "es": "Status",
+ "pt": "Status"
+ },
+ "button-start-game": {
+ "en": "Start Game",
+ "es": "Empezar Juego",
+ "pt": "Começar Jogo"
+ },
+ "button-leave-lobby": {
+ "en": "Leave Lobby",
+ "es": "Salir del Lobby",
+ "pt": "Sair do Lobby"
+ },
+
+
+ "error-bold": {
+ "en": "ERROR",
+ "es": "ERRO",
+ "pt": "ERROR"
+ },
+ "error-no-username": {
+ "en": "Username not present",
+ "es": "Nombre de usuario no esta presente",
+ "pt": "Nome de usuário não esta presente"
+ },
+ "error-invalid-username": {
+ "en": "Invalid username",
+ "es": "Nombre de usuario no es válido",
+ "pt": "Nome de usuário Inválido"
+ },
+ "error-taken-username": {
+ "en": "Username taken",
+ "es": "Nombre de usuario no esta disponible",
+ "pt": "Nome de usuário já está em uso"
+ },
+ "error-too-many-clients": {
+ "en": "Too many connections",
+ "es": "Demasiadas conexiones",
+ "pt": "Demasiadas conexões"
+ },
+ "error-bad-intent": {
+ "en": "Client has no intent",
+ "es": "Cliente no tiene intención",
+ "pt": "Cliente não tem intenção"
+ },
+ "error-unknown-uid": {
+ "en": "Unknown user ID",
+ "es": "ID de usuario desconocido",
+ "pt": "ID de usuário desconhecido"
+ },
+ "error-taken-user-connection": {
+ "en": "User already connected",
+ "es": "Usuario ya está conectado/a",
+ "pt": "Usuário já está conectado/a"
+ },
+ "error-illegal-user": {
+ "en": "Illegal user",
+ "es": "Usuario ilegal",
+ "pt": "Usuário ilegal"
+ },
+ "error-malformed-lobby": {
+ "en": "Lobby malformed",
+ "es": "Lobby malformado",
+ "pt": "Lobby malformado"
+ },
+ "error-taken-lobby-ownership": {
+ "en": "User already owns lobby",
+ "es": "Usuario ya tiene lobby",
+ "pt": "Usuário já tem um lobby"
+ },
+ "error-illegal-lobby": {
+ "en": "Illegal lobby",
+ "es": "Lobby ilegal",
+ "pt": "Lobby ilegal"
+ },
+ "error-cannot-join-lobby": {
+ "en": "Cannot join lobby",
+ "es": "No se puede unir al lobby",
+ "pt": "Não é possível entrar no lobby"
+ },
+ "error-lobby-not-exist": {
+ "en": "Lobby does not exist",
+ "es": "Lobby no existe",
+ "pt": "Lobby não existe"
+ },
+ "error-lobby-name-required": {
+ "en": "A name is requred",
+ "es": "Se requiere un nombre",
+ "pt": "Um nome é obrigatório"
+ },
+ "error-creating-lobby": {
+ "en": "An error occurred while creating the lobby ",
+ "es": "Ocurrió un error al crear el lobby ",
+ "pt": "Ocorreu um erro ao criar o lobby "
+ },
+ "error-lobby-id-required": {
+ "en": "A lobby ID is required",
+ "es": "Se requiere un lobby ID",
+ "pt": "É necessário um lobby ID"
+ },
+ "error-lobby-joining": {
+ "en": "An error occurred while joining the lobby ",
+ "es": "Ocurrió un error al conectarse al lobby ",
+ "pt": "Ocorreu um erro ao entrar no lobby "
+ }
+}
diff --git a/scripts/deploy.js b/scripts/deploy.js
new file mode 100644
index 0000000..e69de29
diff --git a/scripts/langParser.js b/scripts/langParser.js
new file mode 100644
index 0000000..e69de29
diff --git a/scripts/localeToLang.js b/scripts/localeToLang.js
new file mode 100644
index 0000000..e69de29
diff --git a/server/locale.json b/server/locale.json
deleted file mode 100644
index d2bc235..0000000
--- a/server/locale.json
+++ /dev/null
@@ -1,110 +0,0 @@
-{
- "scrabble-name": {
- "en": "Scrabble",
- "es": "Scrabble",
- "pt": "Scrabble"
- },
- "username": {
- "en": "Username",
- "es": "Nombre de usuario",
- "pt": "Nome de usuàrio"
- },
- "button-singleplayer": {
- "en": "Play singleplayer",
- "es": "Jugar a un(a) jugador(a)",
- "pt": "Jogar singleplayer"
- },
- "button-submit": {
- "en": "Submit",
- "es": "Enviar",
- "pt": "Enviar"
- },
- "status-connected": {
- "en": "Connected",
- "es": "Conectado(a)",
- "pt": "Conectado(a)"
- },
-
-
- "error-bold": {
- "en": "ERROR",
- "es": "ERRO",
- "pt": "ERROR"
- },
- "error-no-username": {
- "en": "Username not present",
- "es": "Nombre de usuario no esta presente",
- "pt": "Nome de usuário não esta presente"
- },
- "error-invalid-username": {
- "en": "Invalid username",
- "es": "Nombre de usuario no es válido",
- "pt": "Nome de usuário Inválido"
- },
- "error-taken-username": {
- "en": "Username taken",
- "es": "Nombre de usuario no esta disponible",
- "pt": "Nome de usuário já está em uso"
- },
- "error-too-many-clients": {
- "en": "Too many connections",
- "es": "Demasiadas conexiones",
- "pt": "Demasiadas conexões"
- },
- "error-bad-intent": {
- "en": "Client has no intent",
- "es": "Cliente no tiene intención",
- "pt": "Cliente não tem intenção"
- },
- "error-unknown-uid": {
- "en": "Unknown user ID",
- "es": "",
- "pt": ""
- },
- "error-taken-user-connection": {
- "en": "User already connected",
- "es": "",
- "pt": ""
- },
- "error-illegal-user": {
- "en": "Illegal user",
- "es": "",
- "pt": ""
- },
- "error-malformed-lobby": {
- "en": "Lobby malformed",
- "es": "",
- "pt": ""
- },
- "error-taken-lobby-ownership": {
- "en": "User already owns lobby",
- "es": "",
- "pt": ""
- },
- "error-illegal-lobby": {
- "en": "Illegal lobby",
- "es": "",
- "pt": ""
- },
- "error-cannot-join-lobby": {
- "en": "Cannot join lobby",
- "es": "",
- "pt": ""
- },
- "error-lobby-not-exist": {
- "en": "Lobby does not exist",
- "es": "",
- "pt": ""
- },
- "error-lobby-join": {
- "en": "Cannot join lobby",
- "es": "",
- "pt": ""
- },
-
-
-
- "en": "",
- "es": "",
- "pt": ""
-}
diff --git a/server/src/locale.js b/server/src/locale.js
index 36b262d..a908723 100644
--- a/server/src/locale.js
+++ b/server/src/locale.js
@@ -1,10 +1,13 @@
+const Logger = require('./logger.js');
+
const FS = require('fs');
let locales = {};
-function init()
+async function init()
{
- locales = JSON.parse(FS.readFileSync('./locale.json'));
+ locales = JSON.parse(FS.readFileSync('../data/locale.json'));
+ Logger.info('LOCALES LOADED');
}
function GetLocaleListJSON()
diff --git a/server/src/socketserver.js b/server/src/socketserver.js
index 2faaa87..46d5dcb 100644
--- a/server/src/socketserver.js
+++ b/server/src/socketserver.js
@@ -101,6 +101,8 @@ function ClientIdentify(socket, args)
}
}
+// if i use a database in the future i need to consider that the lobby
+// name is not yet sanatised
function LobbyCreate(socket, args)
{
const err = new Error;
@@ -201,7 +203,7 @@ function LobbyJoin(socket, args)
// Make sure user isn't already in a lobby
if (!Game.Lobbies.CheckUserAvailability(useruid))
{
- err.addError(400, 'Bad Request', 'Uerror-taken-lobby-ownership');
+ err.addError(400, 'Bad Request', 'error-taken-lobby-ownership');
socket.emit('lobby-join-error', err.toError);
return;
}
@@ -223,7 +225,7 @@ function LobbyJoin(socket, args)
if (!status)
{
- err.addError(403, 'Forbidden', 'error-lobby-join');
+ err.addError(403, 'Forbidden', 'error-cannot-join-lobby');
socket.emit('lobby-join-error', err.toError);
return;
}