From 9dadb1ebd36e4c575cfb1f724d6f9f7613f1c6e6 Mon Sep 17 00:00:00 2001 From: VariableVince <24507472+VariableVince@users.noreply.github.com> Date: Wed, 6 May 2026 22:25:59 +0200 Subject: [PATCH] Translate 1002 errors. Always starts with translation for "connection refused: " followed by translated error. Cosmetic.reason isn't translated, doesn't seem like going another level deeper really helps. Add translated tips if turnstile is invalid. Append English error for screenshots so devs understand what error user gets. --- resources/lang/en.json | 12 ++++++++++++ src/client/Transport.ts | 25 ++++++++++++++++++++++++- src/client/Utils.ts | 11 ++++++++++- src/server/Worker.ts | 26 ++++++++++---------------- 4 files changed, 56 insertions(+), 18 deletions(-) diff --git a/resources/lang/en.json b/resources/lang/en.json index a2c7324eb..940ad09cf 100644 --- a/resources/lang/en.json +++ b/resources/lang/en.json @@ -1219,5 +1219,17 @@ "fullscreen": { "enter": "Enter fullscreen", "exit": "Exit fullscreen" + }, + "worker_error": { + "account_banned": "Account Banned", + "cannot_join_game": "Cannot join game", + "connection_refused": "Connection refused", + "flare_forbidden": "Forbidden", + "game_not_found": "Game not found", + "lobby_full": "Lobby full", + "turnstile_invalid": "Unauthorized: invalid token", + "turnstile_fix_tips": "Try this to fix: \n 1. Do a hard refresh (Mac: Cmd+Shift+R, Windows: Ctrl+F5) \n 2. Or resync your device clock \n 3. Or close all browser windows and restart your browser \n 4. Or try another browser, preferably without extensions \n 5. Or clear site data for this site", + "unauthorized": "Unauthorized", + "user_me_fetch_failed": "Unauthorized: user fetch failed" } } diff --git a/src/client/Transport.ts b/src/client/Transport.ts index 1e4526a8c..2eb9851e8 100644 --- a/src/client/Transport.ts +++ b/src/client/Transport.ts @@ -29,6 +29,7 @@ import { replacer } from "../core/Util"; import { getPlayToken } from "./Auth"; import { LobbyConfig } from "./ClientGameRunner"; import { LocalServer } from "./LocalServer"; +import { getEnglishText, translateText } from "./Utils"; export class PauseGameIntentEvent implements GameEvent { constructor(public readonly paused: boolean) {} @@ -378,8 +379,30 @@ export class Transport { `WebSocket closed. Code: ${event.code}, Reason: ${event.reason}`, ); if (event.code === 1002) { + const connRefusedKey = `worker_error.connection_refused`; + let alertMsg = translateText(connRefusedKey); + const errorKey = `worker_error.${event.reason}`; + alertMsg += `: ${translateText(errorKey)}`; + + // Add tips if turnstile token invalid + if (event.reason === "turnstile_invalid") { + alertMsg += `\n\n${translateText("worker_error.turnstile_fix_tips")}`; + } + + // Append English error if it differs, for screenshots posted by users + const englishMsg = getEnglishText(errorKey); + if (!alertMsg.includes(englishMsg)) { + const englishConnRefusedMsg = getEnglishText(connRefusedKey); + alertMsg += `\n\n--- English ---\n${englishConnRefusedMsg}: `; + if (englishMsg !== errorKey) { + alertMsg += `${englishMsg}`; + } else if (englishMsg === errorKey) { + alertMsg += `${event.reason}`; + } + } + // TODO: make this a modal - alert(`connection refused: ${event.reason}`); + alert(alertMsg); } else if (event.code !== 1000) { console.log(`received error code ${event.code}, reconnecting`); this.reconnect(); diff --git a/src/client/Utils.ts b/src/client/Utils.ts index 943e764a4..18130f75a 100644 --- a/src/client/Utils.ts +++ b/src/client/Utils.ts @@ -12,6 +12,7 @@ import { import { GameConfig } from "../core/Schemas"; import type { LangSelector } from "./LangSelector"; import { Platform } from "./Platform"; +import { get } from "http"; export const TUTORIAL_VIDEO_URL = "https://www.youtube.com/embed/EN2oOog3pSs"; @@ -407,9 +408,17 @@ function getCachedLangSelector(): LangSelector | null { return found; } +export function getEnglishText( + key: string, + params?: Record, +): string { + return translateText(key, params, true); +} + export const translateText = ( key: string, params?: Record, + getOnlyEnglish: boolean = false, ): string => { const self = translateText as any; self.formatterCache ??= new Map(); @@ -436,7 +445,7 @@ export const translateText = ( self.lastLang = langSelector.currentLang; } - let message = translations?.[key]; + let message = getOnlyEnglish ? undefined : translations?.[key]; const hasPrimaryTranslation = message !== undefined; message ??= defaultTranslations?.[key]; diff --git a/src/server/Worker.ts b/src/server/Worker.ts index b3a46d80a..b6855c394 100644 --- a/src/server/Worker.ts +++ b/src/server/Worker.ts @@ -330,16 +330,13 @@ export async function startWorker() { log.warn(`Invalid token: ${result.message}`, { gameID: clientMsg.gameID, }); - ws.close( - 1002, - "Unauthorized: invalid token \n\n Try this to fix: \n 1. Do a hard refresh (Mac: Cmd+Shift+R, Windows: Ctrl+F5) \n 2. Or resync your device clock \n 3. Or close all browser windows and restart your browser \n 4. Or try another browser, preferably without extensions \n 5. Or clear site data for this site", - ); + ws.close(1002, "turnstile_invalid"); return; } const { persistentId, claims } = result; if (claims?.role === "banned") { - ws.close(1002, "Account Banned"); + ws.close(1002, "account_banned"); return; } @@ -358,7 +355,7 @@ export async function startWorker() { log.warn( `game ${clientMsg.gameID} not found on worker ${workerId}`, ); - ws.close(1002, "Game not found"); + ws.close(1002, "game_not_found"); } return; } @@ -388,7 +385,7 @@ export async function startWorker() { if (claims === null) { if (allowedFlares !== undefined) { log.warn("Unauthorized: Anonymous user attempted to join game"); - ws.close(1002, "Unauthorized"); + ws.close(1002, "unauthorized"); return; } } else { @@ -399,7 +396,7 @@ export async function startWorker() { persistentID: persistentId, gameID: clientMsg.gameID, }); - ws.close(1002, "Unauthorized: user me fetch failed"); + ws.close(1002, "user_me_fetch_failed"); return; } flares = result.response.player.flares; @@ -412,7 +409,7 @@ export async function startWorker() { log.warn( "Forbidden: player without an allowed flare attempted to join game", ); - ws.close(1002, "Forbidden"); + ws.close(1002, "forbidden"); return; } } @@ -446,10 +443,7 @@ export async function startWorker() { gameID: clientMsg.gameID, reason: turnstileResult.reason, }); - ws.close( - 1002, - "Unauthorized: Turnstile token rejected \n\n Try this to fix: \n 1. Do a hard refresh (Mac: Cmd+Shift+R, Windows: Ctrl+F5) \n 2. Or resync your device clock \n 3. Or close all browser windows and restart your browser \n 4. Or try another browser, preferably without extensions \n 5. Or clear site data for this site", - ); + ws.close(1002, "turnstile_invalid"); return; case "error": // Fail open, allow the client to join. @@ -479,19 +473,19 @@ export async function startWorker() { if (joinResult === "not_found") { log.info(`game ${clientMsg.gameID} not found on worker ${workerId}`); - ws.close(1002, "Game not found"); + ws.close(1002, "game_not_found"); } else if (joinResult === "kicked") { log.warn(`kicked client tried to join game ${clientMsg.gameID}`, { gameID: clientMsg.gameID, workerId, }); - ws.close(1002, "Cannot join game"); + ws.close(1002, "cannot_join_game"); } else if (joinResult === "rejected") { log.info(`client rejected from game ${clientMsg.gameID}`, { gameID: clientMsg.gameID, workerId, }); - ws.close(1002, "Lobby full"); + ws.close(1002, "lobby_full"); } // Handle other message types