feat(webui): language selector #593
@ -1,5 +1,5 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getEnglishString } from "@/src/services/itemDataService";
|
import { getDict, getString } from "@/src/services/itemDataService";
|
||||||
import {
|
import {
|
||||||
ExportArcanes,
|
ExportArcanes,
|
||||||
ExportGear,
|
ExportGear,
|
||||||
@ -16,7 +16,8 @@ interface ListedItem {
|
|||||||
fusionLimit?: number;
|
fusionLimit?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getItemListsController: RequestHandler = (_req, res) => {
|
const getItemListsController: RequestHandler = (req, res) => {
|
||||||
|
const lang = getDict(typeof req.query.lang == "string" ? req.query.lang : "en");
|
||||||
const weapons = [];
|
const weapons = [];
|
||||||
const miscitems = [];
|
const miscitems = [];
|
||||||
for (const [uniqueName, item] of Object.entries(ExportWeapons)) {
|
for (const [uniqueName, item] of Object.entries(ExportWeapons)) {
|
||||||
@ -24,12 +25,12 @@ const getItemListsController: RequestHandler = (_req, res) => {
|
|||||||
if (item.totalDamage !== 0) {
|
if (item.totalDamage !== 0) {
|
||||||
weapons.push({
|
weapons.push({
|
||||||
uniqueName,
|
uniqueName,
|
||||||
name: getEnglishString(item.name)
|
name: getString(item.name, lang)
|
||||||
});
|
});
|
||||||
} else if (!item.excludeFromCodex) {
|
} else if (!item.excludeFromCodex) {
|
||||||
miscitems.push({
|
miscitems.push({
|
||||||
uniqueName: "MiscItems:" + uniqueName,
|
uniqueName: "MiscItems:" + uniqueName,
|
||||||
name: getEnglishString(item.name)
|
name: getString(item.name, lang)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -37,13 +38,13 @@ const getItemListsController: RequestHandler = (_req, res) => {
|
|||||||
for (const [uniqueName, item] of Object.entries(ExportResources)) {
|
for (const [uniqueName, item] of Object.entries(ExportResources)) {
|
||||||
miscitems.push({
|
miscitems.push({
|
||||||
uniqueName: item.productCategory + ":" + uniqueName,
|
uniqueName: item.productCategory + ":" + uniqueName,
|
||||||
name: getEnglishString(item.name)
|
name: getString(item.name, lang)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for (const [uniqueName, item] of Object.entries(ExportGear)) {
|
for (const [uniqueName, item] of Object.entries(ExportGear)) {
|
||||||
miscitems.push({
|
miscitems.push({
|
||||||
uniqueName: "Consumables:" + uniqueName,
|
uniqueName: "Consumables:" + uniqueName,
|
||||||
name: getEnglishString(item.name)
|
name: getString(item.name, lang)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ const getItemListsController: RequestHandler = (_req, res) => {
|
|||||||
for (const [uniqueName, upgrade] of Object.entries(ExportUpgrades)) {
|
for (const [uniqueName, upgrade] of Object.entries(ExportUpgrades)) {
|
||||||
mods.push({
|
mods.push({
|
||||||
uniqueName,
|
uniqueName,
|
||||||
name: getEnglishString(upgrade.name),
|
name: getString(upgrade.name, lang),
|
||||||
fusionLimit: upgrade.fusionLimit
|
fusionLimit: upgrade.fusionLimit
|
||||||
});
|
});
|
||||||
if (upgrade.isStarter || upgrade.isFrivolous || upgrade.upgradeEntries) {
|
if (upgrade.isStarter || upgrade.isFrivolous || upgrade.upgradeEntries) {
|
||||||
@ -62,7 +63,7 @@ const getItemListsController: RequestHandler = (_req, res) => {
|
|||||||
for (const [uniqueName, arcane] of Object.entries(ExportArcanes)) {
|
for (const [uniqueName, arcane] of Object.entries(ExportArcanes)) {
|
||||||
mods.push({
|
mods.push({
|
||||||
uniqueName,
|
uniqueName,
|
||||||
name: getEnglishString(arcane.name)
|
name: getString(arcane.name, lang)
|
||||||
});
|
});
|
||||||
if (arcane.isFrivolous) {
|
if (arcane.isFrivolous) {
|
||||||
badItems[uniqueName] = true;
|
badItems[uniqueName] = true;
|
||||||
@ -75,7 +76,7 @@ const getItemListsController: RequestHandler = (_req, res) => {
|
|||||||
.map(([uniqueName, warframe]) => {
|
.map(([uniqueName, warframe]) => {
|
||||||
return {
|
return {
|
||||||
uniqueName,
|
uniqueName,
|
||||||
name: getEnglishString(warframe.name)
|
name: getString(warframe.name, lang)
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
weapons,
|
weapons,
|
||||||
|
@ -1,7 +1,21 @@
|
|||||||
import { getIndexAfter } from "@/src/helpers/stringHelpers";
|
import { getIndexAfter } from "@/src/helpers/stringHelpers";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import {
|
import {
|
||||||
|
dict_de,
|
||||||
dict_en,
|
dict_en,
|
||||||
|
dict_es,
|
||||||
|
dict_fr,
|
||||||
|
dict_it,
|
||||||
|
dict_ja,
|
||||||
|
dict_ko,
|
||||||
|
dict_pl,
|
||||||
|
dict_pt,
|
||||||
|
dict_ru,
|
||||||
|
dict_tc,
|
||||||
|
dict_th,
|
||||||
|
dict_tr,
|
||||||
|
dict_uk,
|
||||||
|
dict_zh,
|
||||||
ExportRecipes,
|
ExportRecipes,
|
||||||
ExportWarframes,
|
ExportWarframes,
|
||||||
ExportWeapons,
|
ExportWeapons,
|
||||||
@ -70,6 +84,40 @@ export const getSuitByUniqueName = (uniqueName: string): IPowersuit | undefined
|
|||||||
return ExportWarframes[uniqueName];
|
return ExportWarframes[uniqueName];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getEnglishString = (key: string): string => {
|
export const getDict = (lang: string): Record<string, string> => {
|
||||||
return dict_en[key] ?? key;
|
switch (lang) {
|
||||||
|
case "de":
|
||||||
|
return dict_de;
|
||||||
|
case "es":
|
||||||
|
return dict_es;
|
||||||
|
case "fr":
|
||||||
|
return dict_fr;
|
||||||
|
case "it":
|
||||||
|
return dict_it;
|
||||||
|
case "ja":
|
||||||
|
return dict_ja;
|
||||||
|
case "ko":
|
||||||
|
return dict_ko;
|
||||||
|
case "pl":
|
||||||
|
return dict_pl;
|
||||||
|
case "pt":
|
||||||
|
return dict_pt;
|
||||||
|
case "ru":
|
||||||
|
return dict_ru;
|
||||||
|
case "tc":
|
||||||
|
return dict_tc;
|
||||||
|
case "th":
|
||||||
|
return dict_th;
|
||||||
|
case "tr":
|
||||||
|
return dict_tr;
|
||||||
|
case "uk":
|
||||||
|
return dict_uk;
|
||||||
|
case "zh":
|
||||||
|
return dict_zh;
|
||||||
|
}
|
||||||
|
return dict_en;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getString = (key: string, dict: Record<string, string>): string => {
|
||||||
|
return dict[key] ?? key;
|
||||||
};
|
};
|
||||||
|
@ -7,18 +7,40 @@
|
|||||||
<link rel="stylesheet" href="/webui/style.css" />
|
<link rel="stylesheet" href="/webui/style.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar sticky-top bg-body-tertiary">
|
<nav class="navbar navbar-expand sticky-top bg-body-tertiary">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<button class="navbar-toggler d-lg-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebar" aria-controls="sidebar" aria-label="Toggle sidebar">
|
<button class="navbar-toggler d-lg-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebar" aria-controls="sidebar" aria-label="Toggle sidebar">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
</button>
|
</button>
|
||||||
<a class="navbar-brand">OpenWF WebUI</a>
|
<a class="navbar-brand">OpenWF WebUI</a>
|
||||||
<div class="nav-item dropdown">
|
<ul class="navbar-nav ms-auto mb-2 mb-lg-0">
|
||||||
<button class="nav-link dropdown-toggle displayname" data-bs-toggle="dropdown" aria-expanded="false"></button>
|
<li class="nav-item dropdown">
|
||||||
<ul class="dropdown-menu dropdown-menu-end">
|
<button id="active-lang-name" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false"></button>
|
||||||
<li><a class="dropdown-item" href="/webui/" onclick="logout();">Logout</a></li>
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
</ul>
|
<li><a class="dropdown-item active" href="#" data-lang="en" onclick="event.preventDefault();setLanguage('en');">English</a></li>
|
||||||
</div>
|
<li><a class="dropdown-item" href="#" data-lang="de" onclick="event.preventDefault();setLanguage('de');">Deutsch</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" data-lang="es" onclick="event.preventDefault();setLanguage('es');">Español</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" data-lang="fr" onclick="event.preventDefault();setLanguage('fr');">Français</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" data-lang="it" onclick="event.preventDefault();setLanguage('it');">Italiano</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" data-lang="ja" onclick="event.preventDefault();setLanguage('ja');">日本語</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" data-lang="ko" onclick="event.preventDefault();setLanguage('ko');">한국어</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" data-lang="pl" onclick="event.preventDefault();setLanguage('pl');">Polski</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" data-lang="pt" onclick="event.preventDefault();setLanguage('pt');">Português</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" data-lang="ru" onclick="event.preventDefault();setLanguage('ru');">Русский</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" data-lang="tr" onclick="event.preventDefault();setLanguage('tr');">Türkçe</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" data-lang="uk" onclick="event.preventDefault();setLanguage('uk');">Українська</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" data-lang="zh" onclick="event.preventDefault();setLanguage('zh');">简体中文</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" data-lang="tc" onclick="event.preventDefault();setLanguage('tc');">繁體中文</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#" data-lang="th" onclick="event.preventDefault();setLanguage('th');">แบบไทย</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<button class="nav-link dropdown-toggle displayname" data-bs-toggle="dropdown" aria-expanded="false"></button>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
|
<li><a class="dropdown-item" href="/webui/" onclick="logout();">Logout</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="container pt-3 pb-3" id="main-view">
|
<div class="container pt-3 pb-3" id="main-view">
|
||||||
|
@ -84,52 +84,71 @@ single.on("route_load", function (event) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.itemListPromise = new Promise(resolve => {
|
function setActiveLanguage(lang) {
|
||||||
const req = $.get("/custom/getItemLists");
|
window.lang = lang;
|
||||||
req.done(data => {
|
const lang_name = document.querySelector("[data-lang=" + lang + "]").textContent;
|
||||||
window.archonCrystalUpgrades = data.archonCrystalUpgrades;
|
document.getElementById("active-lang-name").textContent = lang_name;
|
||||||
|
document.querySelector("[data-lang].active").classList.remove("active");
|
||||||
|
document.querySelector("[data-lang=" + lang + "]").classList.add("active");
|
||||||
|
}
|
||||||
|
setActiveLanguage(localStorage.getItem("lang") ?? "en");
|
||||||
|
|
||||||
const itemMap = {
|
function setLanguage(lang) {
|
||||||
// Generics for rivens
|
setActiveLanguage(lang);
|
||||||
"/Lotus/Weapons/Tenno/Archwing/Primary/ArchGun": { name: "Archgun" },
|
localStorage.setItem("lang", lang);
|
||||||
"/Lotus/Weapons/Tenno/Melee/PlayerMeleeWeapon": { name: "Melee" },
|
fetchItemList();
|
||||||
"/Lotus/Weapons/Tenno/Pistol/LotusPistol": { name: "Pistol" },
|
updateInventory();
|
||||||
"/Lotus/Weapons/Tenno/Rifle/LotusRifle": { name: "Rifle" },
|
}
|
||||||
"/Lotus/Weapons/Tenno/Shotgun/LotusShotgun": { name: "Shotgun" },
|
|
||||||
// Modular weapons
|
function fetchItemList() {
|
||||||
"/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryBeam": { name: "Kitgun" },
|
window.itemListPromise = new Promise(resolve => {
|
||||||
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary": { name: "Kitgun" },
|
const req = $.get("/custom/getItemLists?lang=" + window.lang);
|
||||||
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryBeam": { name: "Kitgun" },
|
req.done(data => {
|
||||||
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryShotgun": { name: "Kitgun" },
|
window.archonCrystalUpgrades = data.archonCrystalUpgrades;
|
||||||
"/Lotus/Weapons/Ostron/Melee/LotusModularWeapon": { name: "Zaw" },
|
|
||||||
// Missing in data sources
|
const itemMap = {
|
||||||
"/Lotus/Upgrades/CosmeticEnhancers/Peculiars/CyoteMod": { name: "Traumatic Peculiar" }
|
// Generics for rivens
|
||||||
};
|
"/Lotus/Weapons/Tenno/Archwing/Primary/ArchGun": { name: "Archgun" },
|
||||||
for (const [type, items] of Object.entries(data)) {
|
"/Lotus/Weapons/Tenno/Melee/PlayerMeleeWeapon": { name: "Melee" },
|
||||||
if (type == "archonCrystalUpgrades") {
|
"/Lotus/Weapons/Tenno/Pistol/LotusPistol": { name: "Pistol" },
|
||||||
Object.entries(items).forEach(([uniqueName, name]) => {
|
"/Lotus/Weapons/Tenno/Rifle/LotusRifle": { name: "Rifle" },
|
||||||
const option = document.createElement("option");
|
"/Lotus/Weapons/Tenno/Shotgun/LotusShotgun": { name: "Shotgun" },
|
||||||
option.setAttribute("data-key", uniqueName);
|
// Modular weapons
|
||||||
option.value = name;
|
"/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryBeam": { name: "Kitgun" },
|
||||||
document.getElementById("datalist-" + type).appendChild(option);
|
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary": { name: "Kitgun" },
|
||||||
});
|
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryBeam": { name: "Kitgun" },
|
||||||
} else if (type != "badItems") {
|
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryShotgun": { name: "Kitgun" },
|
||||||
items.forEach(item => {
|
"/Lotus/Weapons/Ostron/Melee/LotusModularWeapon": { name: "Zaw" },
|
||||||
if (item.uniqueName in data.badItems) {
|
// Missing in data sources
|
||||||
item.name += " (Imposter)";
|
"/Lotus/Upgrades/CosmeticEnhancers/Peculiars/CyoteMod": { name: "Traumatic Peculiar" }
|
||||||
} else if (item.uniqueName.substr(0, 18) != "/Lotus/Types/Game/") {
|
};
|
||||||
|
for (const [type, items] of Object.entries(data)) {
|
||||||
|
if (type == "archonCrystalUpgrades") {
|
||||||
|
Object.entries(items).forEach(([uniqueName, name]) => {
|
||||||
const option = document.createElement("option");
|
const option = document.createElement("option");
|
||||||
option.setAttribute("data-key", item.uniqueName);
|
option.setAttribute("data-key", uniqueName);
|
||||||
option.value = item.name;
|
option.value = name;
|
||||||
document.getElementById("datalist-" + type).appendChild(option);
|
document.getElementById("datalist-" + type).appendChild(option);
|
||||||
}
|
});
|
||||||
itemMap[item.uniqueName] = { ...item, type };
|
} else if (type != "badItems") {
|
||||||
});
|
items.forEach(item => {
|
||||||
|
if (item.uniqueName in data.badItems) {
|
||||||
|
item.name += " (Imposter)";
|
||||||
|
} else if (item.uniqueName.substr(0, 18) != "/Lotus/Types/Game/") {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.setAttribute("data-key", item.uniqueName);
|
||||||
|
option.value = item.name;
|
||||||
|
document.getElementById("datalist-" + type).appendChild(option);
|
||||||
|
}
|
||||||
|
itemMap[item.uniqueName] = { ...item, type };
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
resolve(itemMap);
|
||||||
resolve(itemMap);
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
fetchItemList();
|
||||||
|
|
||||||
function updateInventory() {
|
function updateInventory() {
|
||||||
const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1");
|
const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user