Translate Spanish text to English across docs and code

This commit is contained in:
Pandipipas
2026-02-24 00:37:48 +01:00
parent fdc013bdb7
commit 12b85e6579
13 changed files with 262 additions and 282 deletions
+2 -2
View File
@@ -56,7 +56,7 @@ export function parseEnvIntInRange(name: string, fallback: number, min: number,
const parsedValue = Number.parseInt(rawValue, 10);
if (!Number.isFinite(parsedValue) || parsedValue < min || parsedValue > max) {
throw new Error(`La variable ${name} debe ser un entero entre ${min} y ${max}. Valor recibido: '${rawValue}'.`);
throw new Error(`The ${name} variable must be an integer between ${min} and ${max}. Received value: '${rawValue}'.`);
}
return parsedValue;
@@ -68,7 +68,7 @@ export function parseEnvPort(name: string, fallback: string): string {
if (!Number.isFinite(parsedValue) || parsedValue < MIN_TCP_PORT || parsedValue > MAX_TCP_PORT) {
throw new Error(
`La variable ${name} debe ser un puerto TCP válido (${MIN_TCP_PORT}-${MAX_TCP_PORT}). Valor recibido: '${rawValue}'.`,
`The ${name} variable must be a valid TCP port (${MIN_TCP_PORT}-${MAX_TCP_PORT}). Received value: '${rawValue}'.`,
);
}
+2 -2
View File
@@ -146,9 +146,9 @@ process.on("exit", () => {
});
process.on("uncaughtException", (error) => {
showFatalError("Error inesperado en el proceso principal de Electron.", error);
showFatalError("Unexpected error in Electron main process.", error);
});
process.on("unhandledRejection", (reason) => {
showFatalError("Promesa no controlada en el proceso principal de Electron.", reason);
showFatalError("Unhandled promise in Electron main process.", reason);
});
+17 -17
View File
@@ -64,7 +64,7 @@ export function createNodecgProcessManager({
const isPortAvailable = await resolvedDeps.probePortAvailable(portAsNumber);
if (!isPortAvailable) {
throw new Error(
`El puerto ${appConfig.nodecgPort} ya está en uso. Cierra el proceso que lo ocupa o configura NODECG_PORT antes de iniciar.`,
`Port ${appConfig.nodecgPort} is already in use. Stop the process using it or set NODECG_PORT before starting.`,
);
}
@@ -110,16 +110,16 @@ export function createNodecgProcessManager({
while (Date.now() - startTime < appConfig.startupTimeoutMs) {
if (!nodecgProcess) {
const exitDetails = lastExit
? `Última salida registrada: code=${lastExit.code ?? "null"}, signal=${lastExit.signal ?? "none"}.`
: "No se registró código de salida del proceso NodeCG.";
const stderrDetails = lastStderrLine ? `Último stderr: ${lastStderrLine}` : "Sin salida stderr capturada.";
? `Last recorded exit: code=${lastExit.code ?? "null"}, signal=${lastExit.signal ?? "none"}.`
: "No NodeCG process exit code was recorded.";
const stderrDetails = lastStderrLine ? `Last stderr: ${lastStderrLine}` : "No stderr output captured.";
throw new Error(
[
"NodeCG terminó antes de estar listo.",
"NodeCG exited before becoming ready.",
exitDetails,
stderrDetails,
`Ruta NodeCG: ${nodecgRootPath}`,
"Revisa que lib/nodecg tenga dependencias instaladas y que el bundle exista.",
`NodeCG path: ${nodecgRootPath}`,
"Check that lib/nodecg dependencies are installed and the bundle exists.",
].join("\n"),
);
}
@@ -136,7 +136,7 @@ export function createNodecgProcessManager({
await sleep(500, resolvedDeps.setTimer);
}
throw new Error(`Timeout esperando NodeCG en ${nodecgBaseUrl} (${appConfig.startupTimeoutMs}ms).`);
throw new Error(`Timeout waiting for NodeCG at ${nodecgBaseUrl} (${appConfig.startupTimeoutMs}ms).`);
};
const stopNodecgProcessGracefully = (): Promise<void> => {
@@ -223,23 +223,23 @@ function validateNodecgInstall(
const bundlePath = path.join(nodecgRootPath, "bundles", bundleName);
if (!pathExists(nodecgRootPath)) {
throw new Error(`No existe la carpeta NodeCG: ${nodecgRootPath}`);
throw new Error(`NodeCG folder does not exist: ${nodecgRootPath}`);
}
if (!hasReadWriteAccessToPath(nodecgRootPath)) {
throw new Error(`Sin permisos de lectura/escritura sobre NodeCG: ${nodecgRootPath}`);
throw new Error(`No read/write permissions on NodeCG: ${nodecgRootPath}`);
}
if (!pathExists(indexPath)) {
throw new Error(`No se encontró ${indexPath}. Copia una instalación completa de NodeCG en lib/nodecg.`);
throw new Error(`${indexPath} was not found. Copy a full NodeCG installation into lib/nodecg.`);
}
if (!pathExists(nodecgBootstrapPath)) {
throw new Error(
[
"NodeCG está presente pero faltan dependencias internas.",
`No existe: ${nodecgBootstrapPath}`,
"Solución: entra a lib/nodecg e instala dependencias:",
"NodeCG is present but internal dependencies are missing.",
`Not found: ${nodecgBootstrapPath}`,
"Solution: enter lib/nodecg and install dependencies:",
" npm install",
].join("\n"),
);
@@ -248,9 +248,9 @@ function validateNodecgInstall(
if (!pathExists(bundlePath)) {
throw new Error(
[
`No se encontró el bundle '${bundleName}'.`,
`Ruta esperada: ${bundlePath}`,
"Copia/clona tu bundle dentro de lib/nodecg/bundles antes de ejecutar Electron.",
`Bundle '${bundleName}' was not found.`,
`Expected path: ${bundlePath}`,
"Copy/clone your bundle inside lib/nodecg/bundles before running Electron.",
].join("\n"),
);
}
+3 -3
View File
@@ -19,7 +19,7 @@ function getBaseConfig(): AppRuntimeConfig {
};
}
test("resolveAppIconPath prioriza iconPathOverride cuando existe", () => {
test("resolveAppIconPath prioritizes iconPathOverride when present", () => {
const appConfig: AppRuntimeConfig = {
...getBaseConfig(),
iconPathOverride: "/custom/icon.ico",
@@ -30,7 +30,7 @@ test("resolveAppIconPath prioriza iconPathOverride cuando existe", () => {
assert.equal(iconPath, "/custom/icon.ico");
});
test("resolveAppIconPath cae al primer icono por defecto existente", () => {
test("resolveAppIconPath falls back to the first existing default icon", () => {
const appConfig = getBaseConfig();
const expectedIconPath = path.join("/app", "static", "icons", "icon.png");
@@ -39,7 +39,7 @@ test("resolveAppIconPath cae al primer icono por defecto existente", () => {
assert.equal(iconPath, expectedIconPath);
});
test("resolveAppIconPath devuelve undefined cuando no hay iconos", () => {
test("resolveAppIconPath returns undefined when no icons exist", () => {
const appConfig = getBaseConfig();
const iconPath = resolveAppIconPath(appConfig, "/app", () => false);
+6 -6
View File
@@ -5,37 +5,37 @@ import { shouldAllowInternalNavigation, shouldOpenExternalNavigation } from "../
const dashboardUrl = "http://localhost:9090/bundles/scoreko-dev/dashboard/main.html";
test("shouldAllowInternalNavigation permite navegación interna esperada", () => {
test("shouldAllowInternalNavigation allows expected internal navigation", () => {
assert.equal(
shouldAllowInternalNavigation("http://127.0.0.1:9090/bundles/scoreko-dev/dashboard/page.html", dashboardUrl),
true,
);
});
test("shouldAllowInternalNavigation rechaza host no permitido", () => {
test("shouldAllowInternalNavigation rejects disallowed host", () => {
assert.equal(
shouldAllowInternalNavigation("http://evil.local:9090/bundles/scoreko-dev/dashboard/page.html", dashboardUrl),
false,
);
});
test("shouldAllowInternalNavigation rechaza puerto distinto", () => {
test("shouldAllowInternalNavigation rejects different port", () => {
assert.equal(
shouldAllowInternalNavigation("http://localhost:8080/bundles/scoreko-dev/dashboard/page.html", dashboardUrl),
false,
);
});
test("shouldAllowInternalNavigation rechaza esquemas inseguros", () => {
test("shouldAllowInternalNavigation rejects unsafe schemes", () => {
assert.equal(shouldAllowInternalNavigation("javascript:alert(1)", dashboardUrl), false);
});
test("shouldOpenExternalNavigation permite protocolos externos seguros", () => {
test("shouldOpenExternalNavigation allows safe external protocols", () => {
assert.equal(shouldOpenExternalNavigation("https://scoreko.com/docs"), true);
assert.equal(shouldOpenExternalNavigation("mailto:test@scoreko.com"), true);
});
test("shouldOpenExternalNavigation rechaza protocolos inseguros", () => {
test("shouldOpenExternalNavigation rejects unsafe protocols", () => {
assert.equal(shouldOpenExternalNavigation("file:///etc/passwd"), false);
assert.equal(shouldOpenExternalNavigation("javascript:alert(1)"), false);
});
+15 -15
View File
@@ -31,7 +31,7 @@ function getBaseConfig(): AppRuntimeConfig {
};
}
test("startNodeCG valida instalación de NodeCG antes de arrancar", async () => {
test("startNodeCG validates NodeCG installation before starting", async () => {
const manager = createNodecgProcessManager({
isDev: true,
nodecgRootPath: "/fake/nodecg",
@@ -41,17 +41,17 @@ test("startNodeCG valida instalación de NodeCG antes de arrancar", async () =>
deps: {
pathExists: () => false,
spawnProcess: () => {
throw new Error("no debe intentar arrancar si la validación falla");
throw new Error("it must not try to start if validation fails");
},
},
});
await assert.rejects(async () => {
await manager.startNodecgProcess();
}, /No existe la carpeta NodeCG/);
}, /NodeCG folder does not exist/);
});
test("startNodeCG falla si no hay permisos de lectura/escritura", async () => {
test("startNodeCG fails when there are no read/write permissions", async () => {
const manager = createNodecgProcessManager({
isDev: true,
nodecgRootPath: "/fake/nodecg",
@@ -66,10 +66,10 @@ test("startNodeCG falla si no hay permisos de lectura/escritura", async () => {
await assert.rejects(async () => {
await manager.startNodecgProcess();
}, /Sin permisos de lectura\/escritura/);
}, /No read\/write permissions on NodeCG/);
});
test("waitForNodeCGReady resuelve cuando el endpoint responde 404", async () => {
test("waitForNodeCGReady resolves when endpoint returns 404", async () => {
const child = new MockChildProcess(4321);
const manager = createNodecgProcessManager({
isDev: true,
@@ -99,7 +99,7 @@ test("waitForNodeCGReady resuelve cuando el endpoint responde 404", async () =>
});
});
test("stopNodeCG envía SIGTERM y luego SIGKILL si el proceso no sale", async () => {
test("stopNodeCG sends SIGTERM and then SIGKILL if the process does not exit", async () => {
const child = new MockChildProcess(9999);
const timers: Array<() => void> = [];
const killSignals: Array<{ pid: number; signal: NodeJS.Signals }> = [];
@@ -147,7 +147,7 @@ test("stopNodeCG envía SIGTERM y luego SIGKILL si el proceso no sale", async ()
await stopPromise;
});
test("stopNodeCG reutiliza la misma promesa cuando se invoca en paralelo", async () => {
test("stopNodeCG reuses the same promise when invoked in parallel", async () => {
const child = new MockChildProcess(5555);
const manager = createNodecgProcessManager({
@@ -179,7 +179,7 @@ test("stopNodeCG reutiliza la misma promesa cuando se invoca en paralelo", async
await firstStop;
});
test("stopNodeCG normaliza timeout negativo a cero", async () => {
test("stopNodeCG normalizes negative timeout to zero", async () => {
const child = new MockChildProcess(7777);
const timeouts: number[] = [];
@@ -218,7 +218,7 @@ test("stopNodeCG normaliza timeout negativo a cero", async () => {
await stopPromise;
});
test("startNodeCG falla si el puerto ya está ocupado", async () => {
test("startNodeCG fails if the port is already in use", async () => {
const manager = createNodecgProcessManager({
isDev: true,
nodecgRootPath: "/fake/nodecg",
@@ -234,10 +234,10 @@ test("startNodeCG falla si el puerto ya está ocupado", async () => {
await assert.rejects(async () => {
await manager.startNodecgProcess();
}, /ya está en uso/);
}, /is already in use/);
});
test("waitForNodeCGReady expone diagnóstico cuando NodeCG sale antes de readiness", async () => {
test("waitForNodeCGReady exposes diagnostics when NodeCG exits before readiness", async () => {
const child = new MockChildProcess(4242);
const manager = createNodecgProcessManager({
isDev: true,
@@ -272,9 +272,9 @@ test("waitForNodeCGReady expone diagnóstico cuando NodeCG sale antes de readine
},
(error: unknown) => {
assert.ok(error instanceof Error);
assert.match(error.message, /NodeCG terminó antes de estar listo/);
assert.match(error.message, /Última salida registrada/);
assert.match(error.message, /Ruta NodeCG: \/fake\/nodecg/);
assert.match(error.message, /NodeCG exited before becoming ready/);
assert.match(error.message, /Last recorded exit/);
assert.match(error.message, /NodeCG path: \/fake\/nodecg/);
return true;
},
);
+14 -14
View File
@@ -24,61 +24,61 @@ function withEnv(name: string, value: string | undefined, run: () => void): void
}
}
test("getOptionalEnv devuelve undefined para variable ausente", () => {
test("getOptionalEnv returns undefined for missing variable", () => {
withEnv("TEST_OPTIONAL_ENV", undefined, () => {
assert.equal(getOptionalEnv("TEST_OPTIONAL_ENV"), undefined);
});
});
test("getOptionalEnv recorta espacios y devuelve valor", () => {
test("getOptionalEnv trims spaces and returns value", () => {
withEnv("TEST_OPTIONAL_ENV", " scoreko ", () => {
assert.equal(getOptionalEnv("TEST_OPTIONAL_ENV"), "scoreko");
});
});
test("getEnv devuelve fallback para valor vacío", () => {
test("getEnv returns fallback for empty value", () => {
withEnv("TEST_ENV", " ", () => {
assert.equal(getEnv("TEST_ENV", "fallback"), "fallback");
});
});
test("getEnv devuelve el valor cuando existe", () => {
withEnv("TEST_ENV", "valor", () => {
assert.equal(getEnv("TEST_ENV", "fallback"), "valor");
test("getEnv returns the value when present", () => {
withEnv("TEST_ENV", "value", () => {
assert.equal(getEnv("TEST_ENV", "fallback"), "value");
});
});
test("parseEnvInt devuelve fallback para valores inválidos", () => {
test("parseEnvInt returns fallback for invalid values", () => {
withEnv("TEST_ENV_INT", "abc", () => {
assert.equal(parseEnvInt("TEST_ENV_INT", 100), 100);
});
});
test("parseEnvInt parsea enteros válidos", () => {
test("parseEnvInt parses valid integers", () => {
withEnv("TEST_ENV_INT", "4500", () => {
assert.equal(parseEnvInt("TEST_ENV_INT", 100), 4500);
});
});
test("parseEnvIntInRange hace hard-fail para valores fuera de rango", () => {
test("parseEnvIntInRange hard-fails for out-of-range values", () => {
withEnv("TEST_ENV_INT_RANGE", "999", () => {
assert.throws(() => parseEnvIntInRange("TEST_ENV_INT_RANGE", 100, 0, 100), /debe ser un entero/);
assert.throws(() => parseEnvIntInRange("TEST_ENV_INT_RANGE", 100, 0, 100), /must be an integer/);
});
});
test("parseEnvIntInRange acepta valor válido", () => {
test("parseEnvIntInRange accepts valid value", () => {
withEnv("TEST_ENV_INT_RANGE", "42", () => {
assert.equal(parseEnvIntInRange("TEST_ENV_INT_RANGE", 100, 0, 100), 42);
});
});
test("parseEnvPort valida rango TCP", () => {
test("parseEnvPort validates TCP range", () => {
withEnv("TEST_ENV_PORT", "70000", () => {
assert.throws(() => parseEnvPort("TEST_ENV_PORT", "9090"), /puerto TCP válido/);
assert.throws(() => parseEnvPort("TEST_ENV_PORT", "9090"), /valid TCP port/);
});
});
test("parseEnvPort normaliza el puerto válido", () => {
test("parseEnvPort normalizes valid port", () => {
withEnv("TEST_ENV_PORT", "009090", () => {
assert.equal(parseEnvPort("TEST_ENV_PORT", "9090"), "9090");
});
+2 -2
View File
@@ -3,12 +3,12 @@ import test from "node:test";
import { getRemainingDelayMs } from "../main/utils/timing";
test("getRemainingDelayMs devuelve el tiempo restante cuando aún no se cumple", () => {
test("getRemainingDelayMs returns the remaining time when delay has not elapsed", () => {
const remaining = getRemainingDelayMs(10000, 1000, 4000);
assert.equal(remaining, 7000);
});
test("getRemainingDelayMs devuelve 0 si ya pasó el delay", () => {
test("getRemainingDelayMs returns 0 when delay has already elapsed", () => {
const remaining = getRemainingDelayMs(1000, 1000, 5000);
assert.equal(remaining, 0);
});