diff --git a/backend/langs.js b/backend/langs.js index 510d42f..c1f35d3 100644 --- a/backend/langs.js +++ b/backend/langs.js @@ -9,6 +9,9 @@ import { log } from "./util.js"; // populated at runtime and updated asynchronously. export let langs = {}; +// Map from language aliases and IDs to canonical language IDs. +export let aliases = {}; + // Read languages from JSON files in /opt/riju/langs, and update the // global langs variable in this module. Never throw an error. If // there is a problem then just leave the languages as they previously @@ -16,6 +19,7 @@ export let langs = {}; async function readLangsFromDisk() { try { const newLangs = {}; + const newAliases = {}; for (const filename of await fs.readdir("/opt/riju/langs")) { if (path.parse(filename).ext !== ".json") { continue; @@ -31,6 +35,10 @@ async function readLangsFromDisk() { continue; } newLangs[id] = langConfig; + newAliases[id] = id; + for (const alias of langConfig.aliases || []) { + newAliases[alias] = id; + } } log.info( `Loaded ${ @@ -38,6 +46,7 @@ async function readLangsFromDisk() { } language configuration(s) from disk` ); langs = newLangs; + aliases = newAliases; } catch (err) { log.error("Failed to read languages from disk:", err); } diff --git a/backend/server.js b/backend/server.js index cab3603..b460e80 100644 --- a/backend/server.js +++ b/backend/server.js @@ -7,7 +7,7 @@ import ws from "express-ws"; import _ from "lodash"; import * as api from "./api.js"; -import { langs } from "./langs.js"; +import { aliases, langs } from "./langs.js"; import { log } from "./util.js"; const host = process.env.HOST || "localhost"; @@ -28,10 +28,7 @@ app.get("/", (_, res) => { analyticsEnabled, }); } else { - res.send( - 503, - "Still loading languages, or encountered error while doing so\n" - ); + res.send(503, "Encountered unexpected error while loading languages\n"); } }); for (const [lang, { aliases }] of Object.entries(langs)) { @@ -48,14 +45,19 @@ app.get("/:lang", (req, res) => { const lowered = lang.toLowerCase(); if (lowered !== lang) { res.redirect(301, `/${lowered}`); - } else if (langs[lang]) { - res.render(path.resolve("frontend/pages/app"), { - config: { id: lang, ...langs[lang] }, - analyticsEnabled, - }); - } else { - res.send(404, `No such language: ${lang}\n`); + return; } + const canonical = aliases[lang]; + if (!canonical) { + res.send(404, `No such language: ${lang}\n`); + } else if (canonical !== lang) { + res.redirect(301, `/${canonical}`); + return; + } + res.render(path.resolve("frontend/pages/app"), { + config: langs[lang], + analyticsEnabled, + }); }); app.use("/css", express.static("frontend/styles")); app.use("/js", express.static("frontend/out"));