feat: RCON API transport, full furnidata translation with LibreTranslate fallback, remove organize feature, bump per-page limit to 500
CI / check (push) Failing after 7s
CI / release (push) Skipped
CI / deploy (push) Skipped

- Add EMULATOR_MODE=api option with HTTP transport mirroring RCON payload
- buildLocalizedFurniDataFiles now falls back to LibreTranslate for customs (incl. pl/ru/ar/ja)
- Remove Organiseer import button from studio and Reorganize Catalog from import page
- Delete organize API route and PUT handler; remove organizeCatalogAll from catalog-repair.ts
- Increase imported-furni list perPage from 50 to 500
This commit is contained in:
openhands committed 2026-08-22 14:28:06 +02:00
1 parent 5668493485
commit 85b5792d40
8 files changed
+146 -768

No files matched your search

+37 -5
View File
@@ -324,22 +324,50 @@ export async function buildLocalizedFurniDataFiles(): Promise<
for (const section of ["roomitemtypes", "wallitemtypes"] as const) {
const arr = cloned[section]?.furnitype;
if (!Array.isArray(arr)) continue;
// A language mapped to hotel "com" only carries English names,
// so it must NOT be treated as a real translation — fall through
// to LibreTranslate for those (pl/ru/ar/ja).
const officialIsReal = lang === "en" || hotel !== "com";
for (const entry of arr) {
const cn =
typeof entry.classname === "string" ? entry.classname : "";
if (!cn) continue;
const t = lookupTranslation(map, cn);
if (!t) continue;
// Only override when the translation carries content — empty
// strings in official data would otherwise blank existing names.
let didTranslate = false;
if (t.name) {
// Prefer the official Habbo translation when it carries content;
// otherwise fall back to LibreTranslate (customs, or languages
// whose hotel only provides English) so every entry gets a
// localized name/description rather than staying English.
if (officialIsReal && t?.name) {
entry.name = t.name;
didTranslate = true;
} else if (
lang !== "en" &&
typeof entry.name === "string" &&
entry.name.trim()
) {
const translated = await translateWithLibre(entry.name, lang);
if (translated && translated !== entry.name) {
entry.name = translated;
didTranslate = true;
}
}
if (t.description) {
if (officialIsReal && t?.description) {
entry.description = t.description;
didTranslate = true;
} else if (
lang !== "en" &&
typeof entry.description === "string" &&
entry.description.trim()
) {
const translated = await translateWithLibre(
entry.description,
lang,
);
if (translated && translated !== entry.description) {
entry.description = translated;
didTranslate = true;
}
}
if (didTranslate) {
if (section === "roomitemtypes") translatedRoom++;
@@ -361,6 +389,10 @@ export async function buildLocalizedFurniDataFiles(): Promise<
await fs.rename(tmp, target);
}
// Persist the LibreTranslate cache once per language so the next
// full build reuses translations instead of re-calling the API.
if (lang !== "en") await saveLibreCache();
results.push({
lang,
hotel,