XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/XFESpaceNinjaServer

feat(webui): translations (#909)

Closes #900 Supersedes #903 Co-authored-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/909

78032f19
Sainan <sainan@calamity.inc>
提交于

代码差异

8 个文件 +449 -179
Modified package.json +2 -1
@@ -9,7 +9,8 @@
9 9 "build": "tsc && copyfiles static/webui/** build",
10 10 "lint": "eslint --ext .ts .",
11 11 "lint:fix": "eslint --fix --ext .ts .",
12 "prettier": "prettier --write ."
12 "prettier": "prettier --write .",
13 "update-translations": "cd scripts && node update-translations.js"
13 14 },
14 15 "license": "GNU",
15 16 "dependencies": {
Added scripts/update-translations.js +46 -0
@@ -0,0 +1,46 @@
1 // Based on http://209.141.38.3/OpenWF/Translations/src/branch/main/update.php
2 // Converted via ChatGPT-4o
3
4 const fs = require('fs');
5
6 function extractStrings(content) {
7 const regex = /([a-zA-Z_]+): `([^`]*)`,/g;
8 let matches;
9 const strings = {};
10 while ((matches = regex.exec(content)) !== null) {
11 strings[matches[1]] = matches[2];
12 }
13 return strings;
14 }
15
16 const source = fs.readFileSync("../static/webui/translations/en.js", "utf8");
17 const sourceStrings = extractStrings(source);
18 const sourceLines = source.split("\n");
19
20 fs.readdirSync("../static/webui/translations").forEach(file => {
21 if (fs.lstatSync(`../static/webui/translations/${file}`).isFile() && file !== "en.js") {
22 const content = fs.readFileSync(`../static/webui/translations/${file}`, "utf8");
23 const targetStrings = extractStrings(content);
24 const contentLines = content.split("\n");
25
26 const fileHandle = fs.openSync(`../static/webui/translations/${file}`, "w");
27 fs.writeSync(fileHandle, contentLines[0] + "\n");
28
29 sourceLines.forEach(line => {
30 const strings = extractStrings(line);
31 if (Object.keys(strings).length > 0) {
32 Object.entries(strings).forEach(([key, value]) => {
33 if (targetStrings.hasOwnProperty(key)) {
34 fs.writeSync(fileHandle, `\t${key}: \`${targetStrings[key]}\`,\n`);
35 } else {
36 fs.writeSync(fileHandle, `\t${key}: \`[UNTRANSLATED] ${value}\`,\n`);
37 }
38 });
39 } else {
40 fs.writeSync(fileHandle, line + "\n");
41 }
42 });
43
44 fs.closeSync(fileHandle);
45 }
46 });
Modified src/routes/webui.ts +5 -0
@@ -54,4 +54,9 @@ webuiRouter.get("/webui/riven-tool/RivenParser.js", (_req, res) => {
54 54 res.sendFile(path.join(repoDir, "node_modules/warframe-riven-info/RivenParser.js"));
55 55 });
56 56
57 // Serve translations
58 webuiRouter.get("/translations/:file", (req, res) => {
59 res.sendFile(path.join(rootDir, `static/webui/translations/${req.params.file}`));
60 });
61
57 62 export { webuiRouter };
Modified static/webui/index.html +91 -111
@@ -34,13 +34,13 @@
34 34 <li><a class="dropdown-item" href="#" data-lang="th" onclick="event.preventDefault();setLanguage('th');">แบบไทย</a></li>
35 35 </ul>
36 36 </li>
37 <li class="nav-item dropdown">
37 <li class="nav-item dropdown user-dropdown">
38 38 <button class="nav-link dropdown-toggle displayname" data-bs-toggle="dropdown" aria-expanded="false"></button>
39 39 <ul class="dropdown-menu dropdown-menu-end">
40 <li><a class="dropdown-item" href="/webui/" onclick="logout();">Logout</a></li>
40 <li><a class="dropdown-item" href="/webui/" onclick="logout();" data-loc="navbar_logout"></a></li>
41 41 <li><hr class="dropdown-divider"></li>
42 <li><a class="dropdown-item" href="#" onclick="event.preventDefault();renameAccount();">Rename Account</a></li>
43 <li><a class="dropdown-item" href="#" onclick="event.preventDefault();deleteAccount();">Delete Account</a></li>
42 <li><a class="dropdown-item" href="#" onclick="event.preventDefault();renameAccount();" data-loc="navbar_renameAccount"></a></li>
43 <li><a class="dropdown-item" href="#" onclick="event.preventDefault();deleteAccount();" data-loc="navbar_deleteAccount"></a></li>
44 44 </ul>
45 45 </li>
46 46 </ul>
@@ -56,16 +56,16 @@
56 56 <div class="navbar p-0">
57 57 <ul class="navbar-nav justify-content-end">
58 58 <li class="nav-item">
59 <a class="nav-link" href="/webui/inventory" data-bs-dismiss="offcanvas" data-bs-target="#sidebar">Inventory</a>
59 <a class="nav-link" href="/webui/inventory" data-bs-dismiss="offcanvas" data-bs-target="#sidebar" data-loc="navbar_inventory"></a>
60 60 </li>
61 61 <li class="nav-item">
62 <a class="nav-link" href="/webui/mods" data-bs-dismiss="offcanvas" data-bs-target="#sidebar">Mods</a>
62 <a class="nav-link" href="/webui/mods" data-bs-dismiss="offcanvas" data-bs-target="#sidebar" data-loc="navbar_mods"></a>
63 63 </li>
64 64 <li class="nav-item">
65 <a class="nav-link" href="/webui/cheats" data-bs-dismiss="offcanvas" data-bs-target="#sidebar">Cheats</a>
65 <a class="nav-link" href="/webui/cheats" data-bs-dismiss="offcanvas" data-bs-target="#sidebar" data-loc="navbar_cheats"></a>
66 66 </li>
67 67 <li class="nav-item">
68 <a class="nav-link" href="/webui/import" data-bs-dismiss="offcanvas" data-bs-target="#sidebar">Import</a>
68 <a class="nav-link" href="/webui/import" data-bs-dismiss="offcanvas" data-bs-target="#sidebar" data-loc="navbar_import"></a>
69 69 </li>
70 70 </ul>
71 71 </div>
@@ -73,38 +73,35 @@
73 73 </div>
74 74 <div class="w-100">
75 75 <div data-route="/webui/" data-title="Login | OpenWF WebUI">
76 <p>Login using your OpenWF account credentials (same as in-game when connecting to this server).</p>
76 <p data-loc="login_description"></p>
77 77 <form onsubmit="doLogin();return false;">
78 <label for="email">Email address</label>
78 <label for="email" data-loc="login_emailLabel"></label>
79 79 <input class="form-control" type="email" id="email" required />
80 80 <br />
81 <label for="password">Password</label>
81 <label for="password" data-loc="login_passwordLabel"></label>
82 82 <input class="form-control" type="password" id="password" required />
83 83 <br />
84 <button class="btn btn-primary" type="submit">Login</button>
84 <button class="btn btn-primary" type="submit" data-loc="login_loginButton"></button>
85 85 </form>
86 86 </div>
87 87 <div data-route="/webui/inventory" data-title="Inventory | OpenWF WebUI">
88 <p class="mb-3">
89 Note: Changes made here will only be reflected in-game when the game re-downloads your
90 inventory. Visiting the navigation should be the easiest way to trigger that.
91 </p>
88 <p class="mb-3" data-loc="general_inventoryUpdateNote"></p>
92 89 <div class="card mb-3">
93 <h5 class="card-header">Add Items</h5>
90 <h5 class="card-header" data-loc="inventory_addItems"></h5>
94 91 <form class="card-body input-group" onsubmit="doAcquireMiscItems();return false;">
95 92 <input class="form-control" id="miscitem-count" type="number" min="1" value="1" />
96 93 <input class="form-control w-50" id="miscitem-type" list="datalist-miscitems" />
97 <button class="btn btn-primary" type="submit">Add</button>
94 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
98 95 </form>
99 96 </div>
100 97 <div class="row g-3">
101 98 <div class="col-lg-6">
102 99 <div class="card mb-3" style="height: 400px;">
103 <h5 class="card-header">Warframes</h5>
100 <h5 class="card-header" data-loc="inventory_suits"></h5>
104 101 <div class="card-body overflow-auto">
105 102 <form class="input-group mb-3" onsubmit="doAcquireEquipment('Suits');return false;">
106 103 <input class="form-control" id="acquire-type-Suits" list="datalist-Suits" />
107 <button class="btn btn-primary" type="submit">Add</button>
104 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
108 105 </form>
109 106 <table class="table table-hover w-100">
110 107 <tbody id="Suits-list"></tbody>
@@ -114,11 +111,11 @@
114 111 </div>
115 112 <div class="col-lg-6">
116 113 <div class="card mb-3" style="height: 400px;">
117 <h5 class="card-header">Primary Weapons</h5>
114 <h5 class="card-header" data-loc="inventory_longGuns"></h5>
118 115 <div class="card-body overflow-auto">
119 116 <form class="input-group mb-3" onsubmit="doAcquireEquipment('LongGuns');return false;">
120 117 <input class="form-control" id="acquire-type-LongGuns" list="datalist-LongGuns" />
121 <button class="btn btn-primary" type="submit">Add</button>
118 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
122 119 </form>
123 120 <table class="table table-hover w-100">
124 121 <tbody id="LongGuns-list"></tbody>
@@ -130,11 +127,11 @@
130 127 <div class="row g-3">
131 128 <div class="col-lg-6">
132 129 <div class="card mb-3" style="height: 400px;">
133 <h5 class="card-header">Secondary Weapons</h5>
130 <h5 class="card-header" data-loc="inventory_pistols"></h5>
134 131 <div class="card-body overflow-auto">
135 132 <form class="input-group mb-3" onsubmit="doAcquireEquipment('Pistols');return false;">
136 133 <input class="form-control" id="acquire-type-Pistols" list="datalist-Pistols" />
137 <button class="btn btn-primary" type="submit">Add</button>
134 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
138 135 </form>
139 136 <table class="table table-hover w-100">
140 137 <tbody id="Pistols-list"></tbody>
@@ -144,11 +141,11 @@
144 141 </div>
145 142 <div class="col-lg-6">
146 143 <div class="card mb-3" style="height: 400px;">
147 <h5 class="card-header">Melee Weapons</h5>
144 <h5 class="card-header" data-loc="inventory_melee"></h5>
148 145 <div class="card-body overflow-auto">
149 146 <form class="input-group mb-3" onsubmit="doAcquireEquipment('Melee');return false;">
150 147 <input class="form-control" id="acquire-type-Melee" list="datalist-Melee" />
151 <button class="btn btn-primary" type="submit">Add</button>
148 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
152 149 </form>
153 150 <table class="table table-hover w-100">
154 151 <tbody id="Melee-list"></tbody>
@@ -160,11 +157,11 @@
160 157 <div class="row g-3">
161 158 <div class="col-lg-6">
162 159 <div class="card mb-3" style="height: 400px;">
163 <h5 class="card-header">Archwing</h5>
160 <h5 class="card-header" data-loc="inventory_spaceSuits"></h5>
164 161 <div class="card-body overflow-auto">
165 162 <form class="input-group mb-3" onsubmit="doAcquireEquipment('SpaceSuits');return false;">
166 163 <input class="form-control" id="acquire-type-SpaceSuits" list="datalist-SpaceSuits" />
167 <button class="btn btn-primary" type="submit">Add</button>
164 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
168 165 </form>
169 166 <table class="table table-hover w-100">
170 167 <tbody id="SpaceSuits-list"></tbody>
@@ -174,11 +171,11 @@
174 171 </div>
175 172 <div class="col-lg-6">
176 173 <div class="card mb-3" style="height: 400px;">
177 <h5 class="card-header">Archwing Primary Weapons</h5>
174 <h5 class="card-header" data-loc="inventory_spaceGuns"></h5>
178 175 <div class="card-body overflow-auto">
179 176 <form class="input-group mb-3" onsubmit="doAcquireEquipment('SpaceGuns');return false;">
180 177 <input class="form-control" id="acquire-type-SpaceGuns" list="datalist-SpaceGuns" />
181 <button class="btn btn-primary" type="submit">Add</button>
178 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
182 179 </form>
183 180 <table class="table table-hover w-100">
184 181 <tbody id="SpaceGuns-list"></tbody>
@@ -190,11 +187,11 @@
190 187 <div class="row g-3">
191 188 <div class="col-lg-6">
192 189 <div class="card mb-3" style="height: 400px;">
193 <h5 class="card-header">Archwing Melee Weapons</h5>
190 <h5 class="card-header" data-loc="inventory_spaceMelee"></h5>
194 191 <div class="card-body overflow-auto">
195 192 <form class="input-group mb-3" onsubmit="doAcquireEquipment('SpaceMelee');return false;">
196 193 <input class="form-control" id="acquire-type-SpaceMelee" list="datalist-SpaceMelee" />
197 <button class="btn btn-primary" type="submit">Add</button>
194 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
198 195 </form>
199 196 <table class="table table-hover w-100">
200 197 <tbody id="SpaceMelee-list"></tbody>
@@ -204,11 +201,11 @@
204 201 </div>
205 202 <div class="col-lg-6">
206 203 <div class="card mb-3" style="height: 400px;">
207 <h5 class="card-header">Necramechs</h5>
204 <h5 class="card-header" data-loc="inventory_mechSuits"></h5>
208 205 <div class="card-body overflow-auto">
209 206 <form class="input-group mb-3" onsubmit="doAcquireEquipment('MechSuits');return false;">
210 207 <input class="form-control" id="acquire-type-MechSuits" list="datalist-MechSuits" />
211 <button class="btn btn-primary" type="submit">Add</button>
208 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
212 209 </form>
213 210 <table class="table table-hover w-100">
214 211 <tbody id="MechSuits-list"></tbody>
@@ -220,11 +217,11 @@
220 217 <div class="row g-3">
221 218 <div class="col-lg-6">
222 219 <div class="card mb-3" style="height: 400px;">
223 <h5 class="card-header">Sentinels</h5>
220 <h5 class="card-header" data-loc="inventory_sentinels"></h5>
224 221 <div class="card-body overflow-auto">
225 222 <form class="input-group mb-3" onsubmit="doAcquireEquipment('Sentinels');return false;">
226 223 <input class="form-control" id="acquire-type-Sentinels" list="datalist-Sentinels" />
227 <button class="btn btn-primary" type="submit">Add</button>
224 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
228 225 </form>
229 226 <table class="table table-hover w-100">
230 227 <tbody id="Sentinels-list"></tbody>
@@ -234,11 +231,11 @@
234 231 </div>
235 232 <div class="col-lg-6">
236 233 <div class="card mb-3" style="height: 400px;">
237 <h5 class="card-header">Sentinel Weapons</h5>
234 <h5 class="card-header" data-loc="inventory_sentinelWeapons"></h5>
238 235 <div class="card-body overflow-auto">
239 236 <form class="input-group mb-3" onsubmit="doAcquireEquipment('SentinelWeapons');return false;">
240 237 <input class="form-control" id="acquire-type-SentinelWeapons" list="datalist-SentinelWeapons" />
241 <button class="btn btn-primary" type="submit">Add</button>
238 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
242 239 </form>
243 240 <table class="table table-hover w-100">
244 241 <tbody id="SentinelWeapons-list"></tbody>
@@ -250,7 +247,7 @@
250 247 <div class="row g-3">
251 248 <div class="col-lg-6">
252 249 <div class="card mb-3" style="height: 400px;">
253 <h5 class="card-header">Amps</h5>
250 <h5 class="card-header" data-loc="inventory_operatorAmps"></h5>
254 251 <div class="card-body overflow-auto">
255 252 <table class="table table-hover w-100">
256 253 <tbody id="OperatorAmps-list"></tbody>
@@ -260,7 +257,7 @@
260 257 </div>
261 258 <div class="col-lg-6">
262 259 <div class="card mb-3" style="height: 400px;">
263 <h5 class="card-header">K-Drives</h5>
260 <h5 class="card-header" data-loc="inventory_hoverboards"></h5>
264 261 <div class="card-body overflow-auto">
265 262 <table class="table table-hover w-100">
266 263 <tbody id="Hoverboards-list"></tbody>
@@ -270,23 +267,23 @@
270 267 </div>
271 268 </div>
272 269 <div class="card mb-3">
273 <h5 class="card-header">Bulk Actions</h5>
270 <h5 class="card-header" data-loc="general_bulkActions"></h5>
274 271 <div class="card-body">
275 272 <div class="mb-2 d-flex flex-wrap gap-2">
276 <button class="btn btn-primary" onclick="addMissingEquipment(['Suits']);">Add Missing Warframes</button>
277 <button class="btn btn-primary" onclick="addMissingEquipment(['Melee', 'LongGuns', 'Pistols']);">Add Missing Weapons</button>
278 <button class="btn btn-primary" onclick="addMissingEquipment(['SpaceSuits']);">Add Missing Archwings</button>
279 <button class="btn btn-primary" onclick="addMissingEquipment(['SpaceGuns', 'SpaceMelee']);">Add Missing Archwing Weapons</button>
280 <button class="btn btn-primary" onclick="addMissingEquipment(['Sentinels']);">Add Missing Sentinels</button>
281 <button class="btn btn-primary" onclick="addMissingEquipment(['SentinelWeapons']);">Add Missing Sentinel Weapons</button>
273 <button class="btn btn-primary" onclick="addMissingEquipment(['Suits']);" data-loc="inventory_bulkAddSuits"></button>
274 <button class="btn btn-primary" onclick="addMissingEquipment(['Melee', 'LongGuns', 'Pistols']);" data-loc="inventory_bulkAddWeapons"></button>
275 <button class="btn btn-primary" onclick="addMissingEquipment(['SpaceSuits']);" data-loc="inventory_bulkAddSpaceSuits"></button>
276 <button class="btn btn-primary" onclick="addMissingEquipment(['SpaceGuns', 'SpaceMelee']);" data-loc="inventory_bulkAddSpaceWeapons"></button>
277 <button class="btn btn-primary" onclick="addMissingEquipment(['Sentinels']);" data-loc="inventory_bulkAddSentinels"></button>
278 <button class="btn btn-primary" onclick="addMissingEquipment(['SentinelWeapons']);" data-loc="inventory_bulkAddSentinelWeapons"></button>
282 279 </div>
283 280 <div class="mb-2 d-flex flex-wrap gap-2">
284 <button class="btn btn-success" onclick="maxRankAllEquipment(['Suits']);">Max Rank All Warframes</button>
285 <button class="btn btn-success" onclick="maxRankAllEquipment(['Melee', 'LongGuns', 'Pistols']);">Max Rank All Weapons</button>
286 <button class="btn btn-success" onclick="maxRankAllEquipment(['SpaceSuits']);">Max Rank All Archwings</button>
287 <button class="btn btn-success" onclick="maxRankAllEquipment(['SpaceGuns', 'SpaceMelee']);">Max Rank All Archwing Weapons</button>
288 <button class="btn btn-success" onclick="maxRankAllEquipment(['Sentinels']);">Max Rank All Sentinels</button>
289 <button class="btn btn-success" onclick="maxRankAllEquipment(['SentinelWeapons']);">Max Rank All Sentinel Weapons</button>
281 <button class="btn btn-success" onclick="maxRankAllEquipment(['Suits']);" data-loc="inventory_bulkRankUpSuits"></button>
282 <button class="btn btn-success" onclick="maxRankAllEquipment(['Melee', 'LongGuns', 'Pistols']);" data-loc="inventory_bulkRankUpWeapons"></button>
283 <button class="btn btn-success" onclick="maxRankAllEquipment(['SpaceSuits']);" data-loc="inventory_bulkRankUpSpaceSuits"></button>
284 <button class="btn btn-success" onclick="maxRankAllEquipment(['SpaceGuns', 'SpaceMelee']);" data-loc="inventory_bulkRankUpSpaceWeapons"></button>
285 <button class="btn btn-success" onclick="maxRankAllEquipment(['Sentinels']);" data-loc="inventory_bulkRankUpSentinels"></button>
286 <button class="btn btn-success" onclick="maxRankAllEquipment(['SentinelWeapons']);" data-loc="inventory_bulkRankUpSentinelWeapons"></button>
290 287 </div>
291 288 </div>
292 289 </div>
@@ -295,14 +292,14 @@
295 292 <h3 class="mb-0"></h3>
296 293 <p class="text-body-secondary"></p>
297 294 <div class="card mb-3">
298 <h5 class="card-header">Archon Shard Slots</h5>
295 <h5 class="card-header" data-loc="powersuit_archonShardsLabel"></h5>
299 296 <div class="card-body">
300 <p>You can use these unlimited slots to apply a wide range of upgrades.</p>
297 <p data-loc="powersuit_archonShardsDescription"></p>
301 298 <form class="input-group mb-3" onsubmit="doPushArchonCrystalUpgrade();return false;">
302 299 <input type="number" id="archon-crystal-add-count" min="1" max="10000" value="1" class="form-control" style="max-width:100px" />
303 300 <span class="input-group-text">x</span>
304 301 <input class="form-control" list="datalist-archonCrystalUpgrades" />
305 <button class="btn btn-primary" type="submit">Add</button>
302 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
306 303 </form>
307 304 <table class="table table-hover w-100">
308 305 <tbody id="crystals-list"></tbody>
@@ -311,14 +308,11 @@
311 308 </div>
312 309 </div>
313 310 <div data-route="/webui/mods" data-title="Mods | OpenWF WebUI">
314 <p class="mb-3">
315 Note: Changes made here will only be reflected in-game when the game re-downloads your
316 inventory. Visiting the navigation should be the easiest way to trigger that.
317 </p>
311 <p class="mb-3" data-loc="general_inventoryUpdateNote"></p>
318 312 <div class="row g-3">
319 313 <div class="col-xxl-6">
320 314 <div class="card mb-3">
321 <h5 class="card-header">Add Riven</h5>
315 <h5 class="card-header" data-loc="mods_addRiven"></h5>
322 316 <form class="card-body" onsubmit="doAcquireRiven();return false;">
323 317 <select class="form-control mb-3" id="addriven-type">
324 318 <option value="LotusArchgunRandomModRare">LotusArchgunRandomModRare</option>
@@ -329,13 +323,13 @@
329 323 <option value="LotusShotgunRandomModRare">LotusShotgunRandomModRare</option>
330 324 <option value="PlayerMeleeWeaponRandomModRare">PlayerMeleeWeaponRandomModRare</option>
331 325 </select>
332 <textarea id="addriven-fingerprint" class="form-control mb-3" placeholder="Fingerprint"></textarea>
333 <button class="btn btn-primary" style="margin-right: 5px" type="submit">Add</button>
334 <a href="riven-tool/" target="_blank">Need help with the fingerprint?</a>
326 <textarea id="addriven-fingerprint" class="form-control mb-3" data-loc-placeholder_"mods.fingerprint"></textarea>
327 <button class="btn btn-primary" style="margin-right: 5px" type="submit" data-loc="general_addButton"></button>
328 <a href="riven-tool/" target="_blank" data-loc="mods_fingerprintHelp"></a>
335 329 </form>
336 330 </div>
337 331 <div class="card mb-3">
338 <h5 class="card-header">Rivens</h5>
332 <h5 class="card-header" data-loc="mods_rivens"></h5>
339 333 <div class="card-body">
340 334 <table class="table table-hover w-100">
341 335 <tbody id="riven-list"></tbody>
@@ -345,12 +339,12 @@
345 339 </div>
346 340 <div class="col-xxl-6">
347 341 <div class="card mb-3">
348 <h5 class="card-header">Mods</h5>
342 <h5 class="card-header" data-loc="mods_mods"></h5>
349 343 <div class="card-body">
350 344 <form class="input-group mb-3" onsubmit="doAcquireMod();return false;">
351 345 <input class="form-control" id="mod-count" type="number" min="1" value="1"/>
352 346 <input class="form-control w-50" id="mod-to-acquire" list="datalist-mods" />
353 <button class="btn btn-primary" type="submit">Add</button>
347 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
354 348 </form>
355 349 <table class="table table-hover w-100">
356 350 <tbody id="mods-list"></tbody>
@@ -358,9 +352,9 @@
358 352 </div>
359 353 </div>
360 354 <div class="card mb-3">
361 <h5 class="card-header">Bulk Actions</h5>
355 <h5 class="card-header" data-loc="general_bulkActions"></h5>
362 356 <div class="card-body">
363 <button class="btn btn-primary" onclick="doAddAllMods();">Add Missing Mods</button>
357 <button class="btn btn-primary" onclick="doAddAllMods();" data-loc="mods_bulkAddMods"></button>
364 358 </div>
365 359 </div>
366 360 </div>
@@ -373,127 +367,113 @@
373 367 <h5 class="card-header">Server</h5>
374 368 <div class="card-body">
375 369 <div id="server-settings-no-perms" class="d-none">
376 <p class="card-text">You must be an administrator to use this feature. To become an administrator, add <code>"<span class="displayname"></span>"</code> to <code>administratorNames</code> in the config.json.</p>
370 <p class="card-text" data-loc="cheats_administratorRequirement"></p>
377 371 </div>
378 372 <form id="server-settings" class="d-none" onsubmit="doChangeSettings();return false;">
379 373 <div class="form-check">
380 374 <input class="form-check-input" type="checkbox" id="skipTutorial" />
381 <label class="form-check-label" for="skipTutorial">Skip Tutorial</label>
375 <label class="form-check-label" for="skipTutorial" data-loc="cheats_skipTutorial"></label>
382 376 </div>
383 377 <div class="form-check">
384 378 <input class="form-check-input" type="checkbox" id="skipAllDialogue" />
385 <label class="form-check-label" for="skipAllDialogue">Skip All Dialogue</label>
379 <label class="form-check-label" for="skipAllDialogue" data-loc="cheats_skipAllDialogue"></label>
386 380 </div>
387 381 <div class="form-check">
388 382 <input class="form-check-input" type="checkbox" id="unlockAllScans" />
389 <label class="form-check-label" for="unlockAllScans">Unlock All Scans</label>
383 <label class="form-check-label" for="unlockAllScans" data-loc="cheats_unlockAllScans"></label>
390 384 </div>
391 385 <div class="form-check">
392 386 <input class="form-check-input" type="checkbox" id="unlockAllMissions" />
393 <label class="form-check-label" for="unlockAllMissions">Unlock All Missions</label>
387 <label class="form-check-label" for="unlockAllMissions" data-loc="cheats_unlockAllMissions"></label>
394 388 </div>
395 389 <div class="form-check">
396 390 <input class="form-check-input" type="checkbox" id="unlockAllQuests" />
397 <label class="form-check-label" for="unlockAllQuests">Unlock All Quests</label>
391 <label class="form-check-label" for="unlockAllQuests" data-loc="cheats_unlockAllQuests"></label>
398 392 </div>
399 393 <div class="form-check">
400 394 <input class="form-check-input" type="checkbox" id="completeAllQuests" />
401 <label class="form-check-label" for="completeAllQuests">Complete All Quests</label>
395 <label class="form-check-label" for="completeAllQuests" data-loc="cheats_completeAllQuests"></label>
402 396 </div>
403 397 <div class="form-check">
404 398 <input class="form-check-input" type="checkbox" id="infiniteCredits" />
405 <label class="form-check-label" for="infiniteCredits">Infinite Credits</label>
399 <label class="form-check-label" for="infiniteCredits" data-loc="cheats_infiniteCredits"></label>
406 400 </div>
407 401 <div class="form-check">
408 402 <input class="form-check-input" type="checkbox" id="infinitePlatinum" />
409 <label class="form-check-label" for="infinitePlatinum">Infinite Platinum</label>
403 <label class="form-check-label" for="infinitePlatinum" data-loc="cheats_infinitePlatinum"></label>
410 404 </div>
411 405 <div class="form-check">
412 406 <input class="form-check-input" type="checkbox" id="infiniteEndo" />
413 <label class="form-check-label" for="infiniteEndo">Infinite Endo</label>
407 <label class="form-check-label" for="infiniteEndo" data-loc="cheats_infiniteEndo"></label>
414 408 </div>
415 409 <div class="form-check">
416 410 <input class="form-check-input" type="checkbox" id="infiniteRegalAya" />
417 <label class="form-check-label" for="infiniteRegalAya">Infinite Regal Aya</label>
411 <label class="form-check-label" for="infiniteRegalAya" data-loc="cheats_infiniteRegalAya"></label>
418 412 </div>
419 413 <div class="form-check">
420 414 <input class="form-check-input" type="checkbox" id="unlockAllShipFeatures" />
421 <label class="form-check-label" for="unlockAllShipFeatures">Unlock All Ship Features</label>
415 <label class="form-check-label" for="unlockAllShipFeatures" data-loc="cheats_unlockAllShipFeatures"></label>
422 416 </div>
423 417 <div class="form-check">
424 418 <input class="form-check-input" type="checkbox" id="unlockAllShipDecorations" />
425 <label class="form-check-label" for="unlockAllShipDecorations">Unlock All Ship Decorations</label>
419 <label class="form-check-label" for="unlockAllShipDecorations" data-loc="cheats_unlockAllShipDecorations"></label>
426 420 </div>
427 421 <div class="form-check">
428 422 <input class="form-check-input" type="checkbox" id="unlockAllFlavourItems" />
429 <label class="form-check-label" for="unlockAllFlavourItems">
430 Unlock All <abbr title="Animation Sets, Glyphs, Plattes, etc.">Flavor Items</abbr>
431 </label>
423 <label class="form-check-label" for="unlockAllFlavourItems" data-loc="cheats_unlockAllFlavourItems"></label>
432 424 </div>
433 425 <div class="form-check">
434 426 <input class="form-check-input" type="checkbox" id="unlockAllSkins" />
435 <label class="form-check-label" for="unlockAllSkins">Unlock All Skins</label>
427 <label class="form-check-label" for="unlockAllSkins" data-loc="cheats_unlockAllSkins"></label>
436 428 </div>
437 429 <div class="form-check">
438 430 <input class="form-check-input" type="checkbox" id="unlockAllCapturaScenes" />
439 <label class="form-check-label" for="unlockAllCapturaScenes">Unlock All Captura Scenes</label>
431 <label class="form-check-label" for="unlockAllCapturaScenes" data-loc="cheats_unlockAllCapturaScenes"></label>
440 432 </div>
441 433 <div class="form-check">
442 434 <input class="form-check-input" type="checkbox" id="universalPolarityEverywhere" />
443 <label class="form-check-label" for="universalPolarityEverywhere">
444 Universal Polarity Everywhere
445 </label>
435 <label class="form-check-label" for="universalPolarityEverywhere" data-loc="cheats_universalPolarityEverywhere"></label>
446 436 </div>
447 437 <div class="form-check">
448 438 <input class="form-check-input" type="checkbox" id="unlockDoubleCapacityPotatoesEverywhere" />
449 <label class="form-check-label" for="unlockDoubleCapacityPotatoesEverywhere">
450 Potatoes Everywhere
451 </label>
439 <label class="form-check-label" for="unlockDoubleCapacityPotatoesEverywhere" data-loc="cheats_unlockDoubleCapacityPotatoesEverywhere"></label>
452 440 </div>
453 441 <div class="form-check">
454 442 <input class="form-check-input" type="checkbox" id="unlockExilusEverywhere" />
455 <label class="form-check-label" for="unlockExilusEverywhere">
456 Exilus Adapters Everywhere
457 </label>
443 <label class="form-check-label" for="unlockExilusEverywhere" data-loc="cheats_unlockExilusEverywhere"></label>
458 444 </div>
459 445 <div class="form-check">
460 446 <input class="form-check-input" type="checkbox" id="unlockArcanesEverywhere" />
461 <label class="form-check-label" for="unlockArcanesEverywhere">
462 Arcane Adapters Everywhere
463 </label>
447 <label class="form-check-label" for="unlockArcanesEverywhere" data-loc="cheats_unlockArcanesEverywhere"></label>
464 448 </div>
465 449 <div class="form-check">
466 450 <input class="form-check-input" type="checkbox" id="noDailyStandingLimits" />
467 <label class="form-check-label" for="noDailyStandingLimits">
468 No Daily Standing Limits
469 </label>
451 <label class="form-check-label" for="noDailyStandingLimits" data-loc="cheats_noDailyStandingLimits"></label>
470 452 </div>
471 453 <div class="form-group mt-2">
472 <label class="form-label" for="spoofMasteryRank">
473 Spoofed Mastery Rank (-1 to disable)
474 </label>
454 <label class="form-label" for="spoofMasteryRank" data-loc="cheats_spoofMasteryRank"></label>
475 455 <input class="form-control" id="spoofMasteryRank" type="number" min="-1" max="65535" />
476 456 </div>
477 <button class="btn btn-primary mt-3" type="submit">Save Settings</button>
457 <button class="btn btn-primary mt-3" type="submit" data-loc="cheats_saveSettings"></button>
478 458 </form>
479 459 </div>
480 460 </div>
481 461 </div>
482 462 <div class="col-md-6">
483 463 <div class="card mb-3">
484 <h5 class="card-header">Account</h5>
464 <h5 class="card-header" data-loc="cheats_account"></h5>
485 465 <div class="card-body">
486 <p><button class="btn btn-primary" onclick="doUnlockAllFocusSchools();">Unlock All Focus Schools</button></p>
487 <button class="btn btn-primary" onclick="doHelminthUnlockAll();">Fully Level Up Helminth</button>
466 <p><button class="btn btn-primary" onclick="doUnlockAllFocusSchools();" data-loc="cheats_unlockAllFocusSchools"></button></p>
467 <button class="btn btn-primary" onclick="doHelminthUnlockAll();" data-loc="cheats_helminthUnlockAll"></button>
488 468 </div>
489 469 </div>
490 470 </div>
491 471 </div>
492 472 </div>
493 473 <div data-route="/webui/import" data-title="Import | OpenWF WebUI">
494 <p>You can provide a full or partial inventory response (client respresentation) here. All fields that are supported by the importer <b>will be overwritten</b> in your account.</p>
474 <p data-loc="import_importNote"></p>
495 475 <textarea class="form-control" id="import-inventory"></textarea>
496 <button class="btn btn-primary mt-3" onclick="doImport();">Submit</button>
476 <button class="btn btn-primary mt-3" onclick="doImport();" data-loc="import_submit"></button>
497 477 </div>
498 478 </div>
499 479 </div>
Modified static/webui/script.js +81 -64
@@ -14,6 +14,9 @@ function loginFromLocalStorage() {
14 14 $(".displayname").text(data.DisplayName);
15 15 window.accountId = data.id;
16 16 window.authz = "accountId=" + data.id + "&nonce=" + data.Nonce;
17 if (window.dict) {
18 updateLocElements();
19 }
17 20 updateInventory();
18 21 },
19 22 () => {
@@ -50,7 +53,7 @@ function revalidateAuthz(succ_cb) {
50 53 },
51 54 () => {
52 55 logout();
53 alert("Your credentials are no longer valid.");
56 alert(loc("code_nonValidAuthz"));
54 57 single.loadRoute("/webui/"); // Show login screen
55 58 }
56 59 );
@@ -62,24 +65,17 @@ function logout() {
62 65 }
63 66
64 67 function renameAccount() {
65 const newname = window.prompt("What would you like to change your account name to?");
68 const newname = window.prompt(loc("code_changeNameConfirm"));
66 69 if (newname) {
67 70 fetch("/custom/renameAccount?" + window.authz + "&newname=" + newname).then(() => {
68 71 $(".displayname").text(newname);
72 updateLocElements();
69 73 });
70 74 }
71 75 }
72 76
73 77 function deleteAccount() {
74 if (
75 window.confirm(
76 "Are you sure you want to delete your account " +
77 document.querySelector(".displayname").textContent +
78 " (" +
79 localStorage.getItem("email") +
80 ")? This action cannot be undone."
81 )
82 ) {
78 if (window.confirm(loc("code_deleteAccountConfirm"))) {
83 79 fetch("/custom/deleteAccount?" + window.authz).then(() => {
84 80 logout();
85 81 single.loadRoute("/webui/"); // Show login screen
@@ -110,55 +106,80 @@ single.on("route_load", function (event) {
110 106 }
111 107 });
112 108
109 function loc(tag) {
110 return ((window.dict ?? {})[tag] ?? tag)
111 .split("|DISPLAYNAME|").join(document.querySelector(".displayname").textContent)
112 .split("|EMAIL|").join(localStorage.getItem("email"));
113 }
114
115 function updateLocElements() {
116 document.querySelectorAll("[data-loc]").forEach(elm => {
117 elm.innerHTML = loc(elm.getAttribute("data-loc"));
118 });
119 }
120
113 121 function setActiveLanguage(lang) {
114 122 window.lang = lang;
115 123 const lang_name = document.querySelector("[data-lang=" + lang + "]").textContent;
116 124 document.getElementById("active-lang-name").textContent = lang_name;
117 125 document.querySelector("[data-lang].active").classList.remove("active");
118 126 document.querySelector("[data-lang=" + lang + "]").classList.add("active");
127
128 window.dictPromise = new Promise(resolve => {
129 const webui_lang = ["en", "ru"].indexOf(lang) == -1 ? "en" : lang;
130 const script = document.createElement("script");
131 script.src = "/translations/" + webui_lang + ".js";
132 script.onload = function() {
133 updateLocElements();
134 resolve(window.dict);
135 };
136 document.documentElement.appendChild(script);
137 });
119 138 }
120 139 setActiveLanguage(localStorage.getItem("lang") ?? "en");
121 140
122 141 function setLanguage(lang) {
123 142 setActiveLanguage(lang);
124 143 localStorage.setItem("lang", lang);
125 fetchItemList();
126 updateInventory();
144 if (window.authz) { // Not in prelogin state?
145 fetchItemList();
146 updateInventory();
147 }
127 148 }
128 149
129 150 let uniqueLevelCaps = {};
130 151 function fetchItemList() {
131 152 window.itemListPromise = new Promise(resolve => {
132 153 const req = $.get("/custom/getItemLists?lang=" + window.lang);
133 req.done(data => {
154 req.done(async (data) => {
155 await dictPromise;
156
134 157 window.archonCrystalUpgrades = data.archonCrystalUpgrades;
135 158
136 159 const itemMap = {
137 160 // Generics for rivens
138 "/Lotus/Weapons/Tenno/Archwing/Primary/ArchGun": { name: "Archgun" },
139 "/Lotus/Weapons/Tenno/Melee/PlayerMeleeWeapon": { name: "Melee" },
140 "/Lotus/Weapons/Tenno/Pistol/LotusPistol": { name: "Pistol" },
141 "/Lotus/Weapons/Tenno/Rifle/LotusRifle": { name: "Rifle" },
142 "/Lotus/Weapons/Tenno/Shotgun/LotusShotgun": { name: "Shotgun" },
161 "/Lotus/Weapons/Tenno/Archwing/Primary/ArchGun": { name: loc("code_archgun") },
162 "/Lotus/Weapons/Tenno/Melee/PlayerMeleeWeapon": { name: loc("code_melee") },
163 "/Lotus/Weapons/Tenno/Pistol/LotusPistol": { name: loc("code_pistol") },
164 "/Lotus/Weapons/Tenno/Rifle/LotusRifle": { name: loc("code_rifle") },
165 "/Lotus/Weapons/Tenno/Shotgun/LotusShotgun": { name: loc("code_shotgun") },
143 166 // Modular weapons
144 "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimary": { name: "Kitgun" },
145 "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryBeam": { name: "Kitgun" },
146 "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryLauncher": { name: "Kitgun" },
147 "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryShotgun": { name: "Kitgun" },
148 "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimarySniper": { name: "Kitgun" },
149 "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary": { name: "Kitgun" },
150 "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryBeam": { name: "Kitgun" },
151 "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryShotgun": { name: "Kitgun" },
152 "/Lotus/Weapons/Ostron/Melee/LotusModularWeapon": { name: "Zaw" },
153 "/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/OperatorTrainingAmpWeapon": {
154 name: "Mote Amp"
155 },
156 "/Lotus/Weapons/Sentients/OperatorAmplifiers/OperatorAmpWeapon": { name: "Amp" },
157 "/Lotus/Weapons/Operator/Pistols/DrifterPistol/DrifterPistolPlayerWeapon": { name: "Sirocco" },
158 "/Lotus/Types/Vehicles/Hoverboard/HoverboardSuit": { name: "K-Drive" },
167 "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimary": { name: loc("code_kitgun") },
168 "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryBeam": { name: loc("code_kitgun") },
169 "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryLauncher": { name: loc("code_kitgun") },
170 "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryShotgun": { name: loc("code_kitgun") },
171 "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimarySniper": { name: loc("code_kitgun") },
172 "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary": { name: loc("code_kitgun") },
173 "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryBeam": { name: loc("code_kitgun") },
174 "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryShotgun": { name: loc("code_kitgun") },
175 "/Lotus/Weapons/Ostron/Melee/LotusModularWeapon": { name: loc("code_zaw") },
176 "/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/OperatorTrainingAmpWeapon": { name: loc("code_moteAmp") },
177 "/Lotus/Weapons/Sentients/OperatorAmplifiers/OperatorAmpWeapon": { name: loc("code_amp") },
178 "/Lotus/Weapons/Operator/Pistols/DrifterPistol/DrifterPistolPlayerWeapon": { name: loc("code_sirocco") },
179 "/Lotus/Types/Vehicles/Hoverboard/HoverboardSuit": { name: loc("code_kdrive") },
159 180 // Missing in data sources
160 "/Lotus/Upgrades/Mods/Fusers/LegendaryModFuser": { name: "Legendary Core" },
161 "/Lotus/Upgrades/CosmeticEnhancers/Peculiars/CyoteMod": { name: "Traumatic Peculiar" }
181 "/Lotus/Upgrades/Mods/Fusers/LegendaryModFuser": { name: loc("code_legendaryCore") },
182 "/Lotus/Upgrades/CosmeticEnhancers/Peculiars/CyoteMod": { name: loc("code_traumaticPeculiar") }
162 183 };
163 184 for (const [type, items] of Object.entries(data)) {
164 185 if (type == "archonCrystalUpgrades") {
@@ -173,7 +194,7 @@ function fetchItemList() {
173 194 } else if (type != "badItems") {
174 195 items.forEach(item => {
175 196 if (item.uniqueName in data.badItems) {
176 item.name += " (Imposter)";
197 item.name += " " + loc("code_badItem");
177 198 } else if (item.uniqueName.substr(0, 18) != "/Lotus/Types/Game/") {
178 199 const option = document.createElement("option");
179 200 option.setAttribute("data-key", item.uniqueName);
@@ -272,7 +293,7 @@ function updateInventory() {
272 293 }
273 294 }
274 295 };
275 a.title = "Max Rank";
296 a.title = loc("code_maxRank");
276 297 a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>`;
277 298 td.appendChild(a);
278 299 }
@@ -287,12 +308,12 @@ function updateInventory() {
287 308 a.href = "#";
288 309 a.onclick = function (event) {
289 310 event.preventDefault();
290 const name = prompt("Enter new custom name:");
311 const name = prompt(loc("code_renamePrompt"));
291 312 if (name !== null) {
292 313 renameGear(category, item.ItemId.$oid, name);
293 314 }
294 315 };
295 a.title = "Rename";
316 a.title = loc("code_rename");
296 317 a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M0 80V229.5c0 17 6.7 33.3 18.7 45.3l176 176c25 25 65.5 25 90.5 0L418.7 317.3c25-25 25-65.5 0-90.5l-176-176c-12-12-28.3-18.7-45.3-18.7H48C21.5 32 0 53.5 0 80zm112 32a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"/></svg>`;
297 318 td.appendChild(a);
298 319 }
@@ -303,7 +324,7 @@ function updateInventory() {
303 324 event.preventDefault();
304 325 disposeOfGear(category, item.ItemId.$oid);
305 326 };
306 a.title = "Remove";
327 a.title = loc("code_remove");
307 328 a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M135.2 17.7L128 32H32C14.3 32 0 46.3 0 64S14.3 96 32 96H416c17.7 0 32-14.3 32-32s-14.3-32-32-32H320l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7zM416 128H32L53.2 467c1.6 25.3 22.6 45 47.9 45H346.9c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>`;
308 329 td.appendChild(a);
309 330 }
@@ -327,11 +348,11 @@ function updateInventory() {
327 348 const td = document.createElement("td");
328 349 td.textContent = itemMap[fingerprint.compat]?.name ?? fingerprint.compat;
329 350 td.textContent += " " + RivenParser.parseRiven(rivenType, fingerprint, 1).name;
330 td.innerHTML += " <span title='Number of buffs'>▲ " + fingerprint.buffs.length + "</span>";
351 td.innerHTML += " <span title='" + loc("code_buffsNumber") + "'>▲ " + fingerprint.buffs.length + "</span>";
331 352 td.innerHTML +=
332 " <span title='Number of curses'>▼ " + fingerprint.curses.length + "</span>";
353 " <span title='" + loc("code_cursesNumber") + "'>▼ " + fingerprint.curses.length + "</span>";
333 354 td.innerHTML +=
334 " <span title='Number of rerolls'>⟳ " + parseInt(fingerprint.rerolls) + "</span>";
355 " <span title='" + loc("code_rerollsNumber") + "'>⟳ " + parseInt(fingerprint.rerolls) + "</span>";
335 356 tr.appendChild(td);
336 357 }
337 358 {
@@ -349,7 +370,7 @@ function updateInventory() {
349 370 })
350 371 );
351 372 a.target = "_blank";
352 a.title = "View Stats";
373 a.title = loc("code_viewStats");
353 374 a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M160 80c0-26.5 21.5-48 48-48h32c26.5 0 48 21.5 48 48V432c0 26.5-21.5 48-48 48H208c-26.5 0-48-21.5-48-48V80zM0 272c0-26.5 21.5-48 48-48H80c26.5 0 48 21.5 48 48V432c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V272zM368 96h32c26.5 0 48 21.5 48 48V432c0 26.5-21.5 48-48 48H368c-26.5 0-48-21.5-48-48V144c0-26.5 21.5-48 48-48z"/></svg>`;
354 375 td.appendChild(a);
355 376 }
@@ -360,7 +381,7 @@ function updateInventory() {
360 381 event.preventDefault();
361 382 disposeOfGear("Upgrades", item.ItemId.$oid);
362 383 };
363 a.title = "Remove";
384 a.title = loc("code_remove");
364 385 a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M135.2 17.7L128 32H32C14.3 32 0 46.3 0 64S14.3 96 32 96H416c17.7 0 32-14.3 32-32s-14.3-32-32-32H320l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7zM416 128H32L53.2 467c1.6 25.3 22.6 45 47.9 45H346.9c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>`;
365 386 td.appendChild(a);
366 387 }
@@ -376,7 +397,7 @@ function updateInventory() {
376 397 {
377 398 const td = document.createElement("td");
378 399 td.textContent = itemMap[item.ItemType]?.name ?? item.ItemType;
379 td.innerHTML += " <span title='Rank'>★ " + rank + "/" + maxRank + "</span>";
400 td.innerHTML += " <span title='" + loc("code_rank") + "'>★ " + rank + "/" + maxRank + "</span>";
380 401 tr.appendChild(td);
381 402 }
382 403 {
@@ -389,7 +410,7 @@ function updateInventory() {
389 410 event.preventDefault();
390 411 setFingerprint(item.ItemType, item.ItemId, { lvl: maxRank });
391 412 };
392 a.title = "Max Rank";
413 a.title = loc("code_maxRank");
393 414 a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>`;
394 415 td.appendChild(a);
395 416 }
@@ -400,7 +421,7 @@ function updateInventory() {
400 421 event.preventDefault();
401 422 disposeOfGear("Upgrades", item.ItemId.$oid);
402 423 };
403 a.title = "Remove";
424 a.title = loc("code_remove");
404 425 a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M135.2 17.7L128 32H32C14.3 32 0 46.3 0 64S14.3 96 32 96H416c17.7 0 32-14.3 32-32s-14.3-32-32-32H320l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7zM416 128H32L53.2 467c1.6 25.3 22.6 45 47.9 45H346.9c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>`;
405 426 td.appendChild(a);
406 427 }
@@ -415,7 +436,7 @@ function updateInventory() {
415 436 {
416 437 const td = document.createElement("td");
417 438 td.textContent = itemMap[item.ItemType]?.name ?? item.ItemType;
418 td.innerHTML += " <span title='Rank'>★ 0/" + maxRank + "</span>";
439 td.innerHTML += " <span title='" + loc("code_rank") + "'>★ 0/" + maxRank + "</span>";
419 440 if (item.ItemCount > 1) {
420 441 td.innerHTML += " <span title='Count'>🗍 " + parseInt(item.ItemCount) + "</span>";
421 442 }
@@ -431,7 +452,7 @@ function updateInventory() {
431 452 event.preventDefault();
432 453 setFingerprint(item.ItemType, item.LastAdded, { lvl: maxRank });
433 454 };
434 a.title = "Max Rank";
455 a.title = loc("code_maxRank");
435 456 a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>`;
436 457 td.appendChild(a);
437 458 }
@@ -442,7 +463,7 @@ function updateInventory() {
442 463 event.preventDefault();
443 464 disposeOfItems("Upgrades", item.ItemType, item.ItemCount);
444 465 };
445 a.title = "Remove";
466 a.title = loc("code_remove");
446 467 a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M135.2 17.7L128 32H32C14.3 32 0 46.3 0 64S14.3 96 32 96H416c17.7 0 32-14.3 32-32s-14.3-32-32-32H320l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7zM416 128H32L53.2 467c1.6 25.3 22.6 45 47.9 45H346.9c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>`;
447 468 td.appendChild(a);
448 469 }
@@ -491,7 +512,7 @@ function updateInventory() {
491 512 event.preventDefault();
492 513 doPopArchonCrystalUpgrade(upgradeType);
493 514 };
494 a.title = "Remove";
515 a.title = loc("code_remove");
495 516 a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M135.2 17.7L128 32H32C14.3 32 0 46.3 0 64S14.3 96 32 96H416c17.7 0 32-14.3 32-32s-14.3-32-32-32H320l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7zM416 128H32L53.2 467c1.6 25.3 22.6 45 47.9 45H346.9c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>`;
496 517 td.appendChild(a);
497 518 }
@@ -572,7 +593,7 @@ function addMissingEquipment(categories) {
572 593 });
573 594 if (
574 595 requests.length != 0 &&
575 window.confirm("Are you sure you want to add " + requests.length + " items to your account?")
596 window.confirm(loc("code_addItemsConfirm").split("|COUNT|").join(requests.length))
576 597 ) {
577 598 dispatchAddItemsRequestsBatch(requests);
578 599 }
@@ -627,7 +648,7 @@ function maxRankAllEquipment(categories) {
627 648 return sendBatchGearExp(batchData);
628 649 }
629 650
630 alert("No equipment to rank up.");
651 alert(loc("code_noEquipmentToRankUp"));
631 652 });
632 653 });
633 654 }
@@ -743,7 +764,7 @@ function doAcquireMiscItems() {
743 764 }
744 765 ])
745 766 }).done(function () {
746 alert("Successfully added.");
767 alert(loc("code_succAdded"));
747 768 });
748 769 });
749 770 }
@@ -938,13 +959,9 @@ function doUnlockAllFocusSchools() {
938 959 await unlockFocusSchool(upgradeType);
939 960 }
940 961 if (Object.keys(missingFocusUpgrades).length == 0) {
941 alert("All focus schools are already unlocked.");
962 alert(loc("code_focusAllUnlocked"));
942 963 } else {
943 alert(
944 "Unlocked " +
945 Object.keys(missingFocusUpgrades).length +
946 " new focus schools! An inventory update will be needed for the changes to be reflected in-game. Visiting the navigation should be the easiest way to trigger that."
947 );
964 alert(loc("code_focusUnlocked").split("|COUNT|").join(Object.keys(missingFocusUpgrades).length));
948 965 }
949 966 });
950 967 });
@@ -996,7 +1013,7 @@ function doAddAllMods() {
996 1013 modsAll = Array.from(modsAll);
997 1014 if (
998 1015 modsAll.length != 0 &&
999 window.confirm("Are you sure you want to add " + modsAll.length + " mods to your account?")
1016 window.confirm(loc("code_addModsConfirm").split("|COUNT|").join(modsAll.length))
1000 1017 ) {
1001 1018 $.post({
1002 1019 url: "/custom/addItems?" + window.authz,
@@ -1071,7 +1088,7 @@ function doImport() {
1071 1088 inventory: JSON.parse($("#import-inventory").val())
1072 1089 })
1073 1090 }).then(function () {
1074 alert("Successfully imported.");
1091 alert(loc("code_succImport"));
1075 1092 updateInventory();
1076 1093 });
1077 1094 });
Modified static/webui/style.css +1 -3
@@ -14,9 +14,7 @@
14 14 }
15 15 }
16 16
17 body:not(.logged-in) .navbar-toggler,
18 body:not(.logged-in) .nav-item.dropdown,
19 body:not(.logged-in) #refresh-note {
17 body:not(.logged-in) .user-dropdown {
20 18 display: none;
21 19 }
22 20
Added static/webui/translations/en.js +111 -0
@@ -0,0 +1,111 @@
1 dict = {
2 general_inventoryUpdateNote: `Note: Changes made here will only be reflected in-game when the game re-downloads your inventory. Visiting the navigation should be the easiest way to trigger that.`,
3 general_addButton: `Add`,
4 general_bulkActions: `Bulk Actions`,
5 code_nonValidAuthz: `Your credentials are no longer valid.`,
6 code_changeNameConfirm: `What would you like to change your account name to?`,
7 code_deleteAccountConfirm: `Are you sure you want to delete your account |DISPLAYNAME| (|EMAIL|)? This action cannot be undone.`,
8 code_archgun: `Archgun`,
9 code_melee: `Melee`,
10 code_pistol: `Pistol`,
11 code_rifle: `Rifle`,
12 code_shotgun: `Shotgun`,
13 code_kitgun: `Kitgun`,
14 code_zaw: `Zaw`,
15 code_moteAmp: `Mote Amp`,
16 code_amp: `Amp`,
17 code_sirocco: `Sirocco`,
18 code_kDrive: `K-Drive`,
19 code_legendaryCore: `Legendary Core`,
20 code_traumaticPeculiar: `Traumatic Peculiar`,
21 code_badItem: `(Imposter)`,
22 code_maxRank: `Max Rank`,
23 code_rename: `Rename`,
24 code_renamePrompt: `Enter new custom name:`,
25 code_remove: `Remove`,
26 code_addItemsConfirm: `Are you sure you want to add |COUNT| items to your account?`,
27 code_noEquipmentToRankUp: `No equipment to rank up.`,
28 code_succAdded: `Successfully added.`,
29 code_buffsNumber: `Number of buffs`,
30 code_cursesNumber: `Number of curses`,
31 code_rerollsNumber: `Number of rerolls`,
32 code_viewStats: `View Stats`,
33 code_rank: `Rank`,
34 code_count: `Count`,
35 code_focusAllUnlocked: `All focus schools are already unlocked.`,
36 code_focusUnlocked: `Unlocked |COUNT| new focus schools! An inventory update will be needed for the changes to be reflected in-game. Visiting the navigation should be the easiest way to trigger that.`,
37 code_addModsConfirm: `Are you sure you want to add |COUNT| mods to your account?`,
38 code_succImport: `Successfully imported.`,
39 login_description: `Login using your OpenWF account credentials (same as in-game when connecting to this server).`,
40 login_emailLabel: `Email address`,
41 login_passwordLabel: `Password`,
42 login_loginButton: `Login`,
43 navbar_logout: `Logout`,
44 navbar_renameAccount: `Rename Account`,
45 navbar_deleteAccount: `Delete Account`,
46 navbar_inventory: `Inventory`,
47 navbar_mods: `Mods`,
48 navbar_cheats: `Cheats`,
49 navbar_import: `Import`,
50 inventory_addItems: `Add Items`,
51 inventory_suits: `Warframes`,
52 inventory_longGuns: `Primary Weapons`,
53 inventory_pistols: `Secondary Weapons`,
54 inventory_melee: `Melee Weapons`,
55 inventory_spaceSuits: `Archwings`,
56 inventory_spaceGuns: `Archwing Primary Weapons`,
57 inventory_spaceMelee: `Archwing Melee Weapons`,
58 inventory_mechSuits: `Necramechs`,
59 inventory_sentinels: `Sentinels`,
60 inventory_sentinelWeapons: `Sentinel Weapons`,
61 inventory_operatorAmps: `Amps`,
62 inventory_hoverboards: `K-Drives`,
63 inventory_bulkAddSuits: `Add Missing Warframes`,
64 inventory_bulkAddWeapons: `Add Missing Weapons`,
65 inventory_bulkAddSpaceSuits: `Add Missing Archwings`,
66 inventory_bulkAddSpaceWeapons: `Add Missing Archwing Weapons`,
67 inventory_bulkAddSentinels: `Add Missing Sentinels`,
68 inventory_bulkAddSentinelWeapons: `Add Missing Sentinel Weapons`,
69 inventory_bulkRankUpSuits: `Max Rank All Warframes`,
70 inventory_bulkRankUpWeapons: `Max Rank All Weapons`,
71 inventory_bulkRankUpSpaceSuits: `Max Rank All Archwings`,
72 inventory_bulkRankUpSpaceWeapons: `Max Rank All Archwing Weapons`,
73 inventory_bulkRankUpSentinels: `Max Rank All Sentinels`,
74 inventory_bulkRankUpSentinelWeapons: `Max Rank All Sentinel Weapons`,
75 powersuit_archonShardsLabel: `Archon Shard Slots`,
76 powersuit_archonShardsDescription: `You can use these unlimited slots to apply a wide range of upgrades`,
77 mods_addRiven: `Add Riven`,
78 mods_fingerprint: `Fingerprint`,
79 mods_fingerprintHelp: `Need help with the fingerprint?`,
80 mods_rivens: `Rivens`,
81 mods_mods: `Mods`,
82 mods_bulkAddMods: `Add Missing Mods`,
83 cheats_administratorRequirement: `You must be an administrator to use this feature. To become an administrator, add <code>|DISPLAYNAME|</code> to <code>administratorNames</code> in the config.json.`,
84 cheats_skipTutorial: `Skip Tutorial`,
85 cheats_skipAllDialogue: `Skip All Dialogue`,
86 cheats_unlockAllScans: `Unlock All Scans`,
87 cheats_unlockAllMissions: `Unlock All Missions`,
88 cheats_unlockAllQuests: `Unlock All Quests`,
89 cheats_completeAllQuests: `Complete All Quests`,
90 cheats_infiniteCredits: `Infinite Credits`,
91 cheats_infinitePlatinum: `Infinite Platinum`,
92 cheats_infiniteEndo: `Infinite Endo`,
93 cheats_infiniteRegalAya: `Infinite Regal Aya`,
94 cheats_unlockAllShipFeatures: `Unlock All Ship Features`,
95 cheats_unlockAllShipDecorations: `Unlock All Ship Decorations`,
96 cheats_unlockAllFlavourItems: `Unlock All <abbr title=\"Animation Sets, Glyphs, Plattes, etc.\">Flavor Items</abbr>`,
97 cheats_unlockAllSkins: `Unlock All Skins`,
98 cheats_unlockAllCapturaScenes: `Unlock All Captura Scenes`,
99 cheats_universalPolarityEverywhere: `Universal Polarity Everywhere`,
100 cheats_unlockDoubleCapacityPotatoesEverywhere: `Potatoes Everywhere`,
101 cheats_unlockExilusEverywhere: `Exilus Adapters Everywhere`,
102 cheats_unlockArcanesEverywhere: `Arcane Adapters Everywhere`,
103 cheats_noDailyStandingLimits: `No Daily Standing Limits`,
104 cheats_spoofMasteryRank: `Spoofed Mastery Rank (-1 to disable)`,
105 cheats_saveSettings: `Save Settings`,
106 cheats_account: `Account`,
107 cheats_unlockAllFocusSchools: `Unlock All Focus Schools`,
108 cheats_helminthUnlockAll: `Fully Level Up Helminth`,
109 import_importNote: `You can provide a full or partial inventory response (client respresentation) here. All fields that are supported by the importer <b>will be overwritten</b> in your account.`,
110 import_submit: `Submit`,
111 }
Added static/webui/translations/ru.js +112 -0
@@ -0,0 +1,112 @@
1 // Russian translation by AMelonInsideLemon
2 dict = {
3 general_inventoryUpdateNote: `Примечание: изменения, внесенные здесь, отобразятся в игре только после повторной загрузки вашего инвентаря. Посещение навигации — самый простой способ этого добиться.`,
4 general_addButton: `Добавить`,
5 general_bulkActions: `Массовые действия`,
6 code_nonValidAuthz: `Ваши данные больше не действительны.`,
7 code_changeNameConfirm: `Какое имя вы хотите установить для своей учетной записи?`,
8 code_deleteAccountConfirm: `Вы уверены, что хотите удалить аккаунт |DISPLAYNAME| (|EMAIL|)? Это действие нельзя отменить.`,
9 code_archgun: `Арч-Пушка`,
10 code_melee: `Ближний бой`,
11 code_pistol: `Пистолет`,
12 code_rifle: `Винтовка`,
13 code_shotgun: `Дробовик`,
14 code_kitgun: `Китган`,
15 code_zaw: `Зо`,
16 code_moteAmp: `Пылинка`,
17 code_amp: `Усилитель`,
18 code_sirocco: `Сирокко`,
19 code_kDrive: `К-Драйв`,
20 code_legendaryCore: `Легендарное ядро`,
21 code_traumaticPeculiar: `Травмирующая Странность`,
22 code_badItem: `(Самозванец)`,
23 code_maxRank: `Максимальный ранг`,
24 code_rename: `Переименовать`,
25 code_renamePrompt: `Введите новое имя:`,
26 code_remove: `Удалить`,
27 code_addItemsConfirm: `Вы уверены, что хотите добавить |COUNT| предметов на ваш аккаунт?`,
28 code_noEquipmentToRankUp: `Нет снаряжения для повышения ранга.`,
29 code_succAdded: `Успешно добавлено.`,
30 code_buffsNumber: `Количество усилений`,
31 code_cursesNumber: `Количество проклятий`,
32 code_rerollsNumber: `Количество циклов`,
33 code_viewStats: `Просмотр характеристики`,
34 code_rank: `Ранг`,
35 code_count: `Количество`,
36 code_focusAllUnlocked: `Все школы фокуса уже разблокированы.`,
37 code_focusUnlocked: `Разблокировано |COUNT| новых школ фокуса! Для отображения изменений в игре потребуется обновление инвентаря. Посещение навигации — самый простой способ этого добиться.`,
38 code_addModsConfirm: `Вы уверены, что хотите добавить |COUNT| модов на ваш аккаунт?`,
39 code_succImport: `Успешно импортировано.`,
40 login_description: `Войдите, используя учетные данные OpenWF (те же, что и в игре при подключении к этому серверу).`,
41 login_emailLabel: `Адрес электронной почты`,
42 login_passwordLabel: `Пароль`,
43 login_loginButton: `Войти`,
44 navbar_logout: `Выйти`,
45 navbar_renameAccount: `Переименовать аккаунт`,
46 navbar_deleteAccount: `Удалить аккаунт`,
47 navbar_inventory: `Инвентарь`,
48 navbar_mods: `Моды`,
49 navbar_cheats: `Читы`,
50 navbar_import: `Импорт`,
51 inventory_addItems: `Добавить предметы`,
52 inventory_suits: `Варфреймы`,
53 inventory_longGuns: `Основное оружие`,
54 inventory_pistols: `Вторичное оружие`,
55 inventory_melee: `Оружие ближнего боя`,
56 inventory_spaceSuits: `Арчвинги`,
57 inventory_spaceGuns: `Оружие арчвинга`,
58 inventory_spaceMelee: `Оружие ближнего боя арчвинга`,
59 inventory_mechSuits: `Некрамехи`,
60 inventory_sentinels: `Стражи`,
61 inventory_sentinelWeapons: `Оружие стражей`,
62 inventory_operatorAmps: `Усилители`,
63 inventory_hoverboards: `К-Драйвы`,
64 inventory_bulkAddSuits: `Добавить отсутствующие варфреймы`,
65 inventory_bulkAddWeapons: `Добавить отсутствующее оружие`,
66 inventory_bulkAddSpaceSuits: `Добавить отсутствующие арчвинги`,
67 inventory_bulkAddSpaceWeapons: `Добавить отсутствующее оружие арчвингов`,
68 inventory_bulkAddSentinels: `Добавить отсутствующих стражей`,
69 inventory_bulkAddSentinelWeapons: `Добавить отсутствующее оружие стражей`,
70 inventory_bulkRankUpSuits: `Максимальный ранг всех варфреймов`,
71 inventory_bulkRankUpWeapons: `Максимальный ранг всего оружия`,
72 inventory_bulkRankUpSpaceSuits: `Максимальный ранг всех арчвингов`,
73 inventory_bulkRankUpSpaceWeapons: `Максимальный ранг всего оружия арчвингов`,
74 inventory_bulkRankUpSentinels: `Максимальный ранг всех стражей`,
75 inventory_bulkRankUpSentinelWeapons: `Максимальный ранг всего оружия стражей`,
76 powersuit_archonShardsLabel: `Ячейки осколков архонта`,
77 powersuit_archonShardsDescription: `Вы можете использовать эти неограниченные ячейки для установки множества улучшений.`,
78 mods_addRiven: `Добавить Мод Разлома`,
79 mods_fingerprint: `Отпечаток`,
80 mods_fingerprintHelp: `Нужна помощь с отпечатком?`,
81 mods_rivens: `Моды Разлома`,
82 mods_mods: `Моды`,
83 mods_bulkAddMods: `Добавить отсутствующие моды`,
84 cheats_administratorRequirement: `Вы должны быть администратором для использования этой функции. Чтобы стать администратором, добавьте <code>\"|DISPLAYNAME|\"</code> в <code>administratorNames</code> в config.json.`,
85 cheats_skipTutorial: `Пропустить обучение`,
86 cheats_skipAllDialogue: `Пропустить все диалоги`,
87 cheats_unlockAllScans: `Разблокировать все сканирования`,
88 cheats_unlockAllMissions: `Разблокировать все миссии`,
89 cheats_unlockAllQuests: `Разблокировать все квесты`,
90 cheats_completeAllQuests: `Завершить все квесты`,
91 cheats_infiniteCredits: `Бесконечные кредиты`,
92 cheats_infinitePlatinum: `Бесконечная платина`,
93 cheats_infiniteEndo: `Бесконечное эндо`,
94 cheats_infiniteRegalAya: `Бесконечная Королевская Айя`,
95 cheats_unlockAllShipFeatures: `Разблокировать все функции корабля`,
96 cheats_unlockAllShipDecorations: `Разблокировать все украшения корабля`,
97 cheats_unlockAllFlavourItems: `Разблокировать все <abbr title=\"Наборы анимаций, глифы, палитры и т. д.\">уникальные предметы</abbr>`,
98 cheats_unlockAllSkins: `Разблокировать все скины`,
99 cheats_unlockAllCapturaScenes: `Разблокировать все сцены Каптуры`,
100 cheats_universalPolarityEverywhere: `Универсальная полярность везде`,
101 cheats_unlockDoubleCapacityPotatoesEverywhere: `Катализаторы везде`,
102 cheats_unlockExilusEverywhere: `Адаптеры Эксилус везде`,
103 cheats_unlockArcanesEverywhere: `Адаптеры для мистификаторов везде`,
104 cheats_noDailyStandingLimits: `Без ежедневных ограничений репутации`,
105 cheats_spoofMasteryRank: `Подделанный ранг мастерства (-1 для отключения)`,
106 cheats_saveSettings: `Сохранить настройки`,
107 cheats_account: `Аккаунт`,
108 cheats_unlockAllFocusSchools: `Разблокировать все школы фокуса`,
109 cheats_helminthUnlockAll: `Полностью улучшить Гельминта`,
110 import_importNote: `Вы можете загрузить полный или частичный ответ инвентаря (клиентское представление) здесь. Все поддерживаемые поля <b>будут перезаписаны</b> в вашем аккаунте.`,
111 import_submit: `Отправить`,
112 }