diff --git a/TODO.md b/TODO.md index 1251d005..615892b5 100644 --- a/TODO.md +++ b/TODO.md @@ -102,6 +102,21 @@ Per-item detail lives in the dated work log below. **Since 2026-07 versions are --- +### ★ In-game menu lists speak German: raw ids/enums/literals now localized (#672, 2026-08-02, branch fix/ingame-menu-untranslated-lists) +On a German client several selection lists still showed English — not missing translations +(en/de locale parity was already enforced) but strings that never reached the Localizer. Fixed: +the Tech tab's category sidebar (raw `blueprints.json` categories like `ShipExpansion` → new +`ui.tech.cat_*` keys), the Map tab's body kind + status (raw `NetBody.Kind`/`Status` enum names → +`ui.map.kind_*`/`ui.map.status_*`), the mission-creation objective-type cycler (`Mine`/`Collect`/ +`Deliver` → `ui.missions.objtype_*`, wire value unchanged), story-log category tags (`[vega]` → +`lore.cat.*` in the story pack's own locale files), the crafting "Max" button, the settings +quality preset (`Potato`… → `ui.settings.preset.*`), the arcade "no record yet" line, and the two +server-baked POI names (`Ruin A`/`Guardian Core` → per-session-locale `poi.ruin`/`poi.guardian_core`, +same pattern as `poi.treasure`). New `CraftingTechShipUI.IdLabel(prefix, id)` resolves +prefix+lowercased id with a raw-id fallback so future data/enum values degrade gracefully. Also +fixed the dead `Desc()` guard (`s == key` never matches `[key]` misses → now `Localizer.Has`) and +`VendorTradeUI.ItemName` now parses composite item keys (dye/glow/shape) like the crafting menu. + ### ★ In-game menu lists show a scrollbar (#664, 2026-08-02, branch feat/ui-inline-scrollbars) The ship-computer menu (all 12 tabs), the Codex and the vendor dialog scrolled only via wheel/drag — nothing showed THAT a list continues or WHERE you are. New `UiKit.AddInlineScrollbar(scroll, width)` diff --git a/client/Assets/BlocksBeyondTheStars/Scripts/ArcadeUI.cs b/client/Assets/BlocksBeyondTheStars/Scripts/ArcadeUI.cs index 6f5fb6b1..38c873da 100644 --- a/client/Assets/BlocksBeyondTheStars/Scripts/ArcadeUI.cs +++ b/client/Assets/BlocksBeyondTheStars/Scripts/ArcadeUI.cs @@ -116,7 +116,7 @@ private void RebuildRail() // Two-line entry: title on top, personal best on its own line below — so long (German) titles // and the highscore both fit the 270px frame instead of being crammed onto one shrunk line. string title = (string.IsNullOrEmpty(e.icon) ? "" : e.icon + " ") + e.Title(Game.German); - string hs = best > 0 ? "★ " + best : (Game.German ? "noch kein Rekord" : "no record yet"); + string hs = best > 0 ? "★ " + best : L("ui.arcade.no_record"); var btn = UiKit.AddButton(_rail, 0, y, 270, 64, string.Empty, () => PlayGame(key)); UiKit.AddText(btn.transform, 18, 7, 244, 30, title, 17, UiKit.TextCol, TextAnchor.LowerLeft, FontStyle.Bold); UiKit.AddText(btn.transform, 18, 37, 244, 20, hs, 13, diff --git a/client/Assets/BlocksBeyondTheStars/Scripts/CraftingTechShipUI.cs b/client/Assets/BlocksBeyondTheStars/Scripts/CraftingTechShipUI.cs index d5388703..e3769961 100644 --- a/client/Assets/BlocksBeyondTheStars/Scripts/CraftingTechShipUI.cs +++ b/client/Assets/BlocksBeyondTheStars/Scripts/CraftingTechShipUI.cs @@ -625,7 +625,7 @@ private NetStarSystem SelectedSystem() case Mode.Tech: foreach (var c in Game.Content.Blueprints.Values.Select(b => b.Category).Where(c => !string.IsNullOrEmpty(c)).Distinct()) { - list.Add((c, c, "cat_tech")); + list.Add((c, IdLabel("ui.tech.cat_", c), "cat_tech")); } break; @@ -1240,8 +1240,8 @@ private float BuildMapList() { bool here = b.Id == map.ActiveLocationId; bool isStation = b.Kind == "SpaceStation"; - string kindLabel = isStation ? L("ui.map.kind_station") : b.Kind; - string status = here ? L("ui.map.here") : $"{kindLabel} {b.Status}"; + string kindLabel = isStation ? L("ui.map.kind_station") : IdLabel("ui.map.kind_", b.Kind); + string status = here ? L("ui.map.here") : $"{kindLabel} {IdLabel("ui.map.status_", b.Status)}"; // A space station shows whose it is: yours, another player's, or none (procedural/NPC). if (isStation && !string.IsNullOrEmpty(b.OwnerName)) @@ -1362,13 +1362,14 @@ private float BuildMissionForm() { int idx = i; var o = _pmObjectives[i]; - UiKit.AddText(c, 12, y, 600, 32, $"{o.Type} {o.Required}× {ItemName(o.Target)}", 18, UiKit.TextCol, TextAnchor.MiddleLeft); + UiKit.AddText(c, 12, y, 600, 32, $"{IdLabel("ui.missions.objtype_", o.Type)} {o.Required}× {ItemName(o.Target)}", 18, UiKit.TextCol, TextAnchor.MiddleLeft); UiKit.AddButton(c, 700, y, 60, 32, "✕", () => { _pmObjectives.RemoveAt(idx); RebuildList(); }); y += 38f; } // Builder row: type / target / count / add. - UiKit.AddButton(c, 0, y, 150, 38, PmTypes[_pmType], () => { _pmType = (_pmType + 1) % PmTypes.Length; RebuildList(); }); + // The cycler shows the localized label; PmTypes stays the wire value (NetMissionObjective.Type). + UiKit.AddButton(c, 0, y, 150, 38, IdLabel("ui.missions.objtype_", PmTypes[_pmType]), () => { _pmType = (_pmType + 1) % PmTypes.Length; RebuildList(); }); UiKit.AddButton(c, 158, y, 210, 38, ItemName(PmTargets[_pmTarget]), () => { _pmTarget = (_pmTarget + 1) % PmTargets.Length; RebuildList(); }); UiKit.AddButton(c, 376, y, 44, 38, "−", () => { _pmCount = Mathf.Max(1, _pmCount - 1); RebuildList(); }); UiKit.AddText(c, 422, y, 54, 38, _pmCount.ToString(), 20, UiKit.TextCol, TextAnchor.MiddleCenter, FontStyle.Bold); @@ -2156,7 +2157,7 @@ private float BuildAchievementList() } UiKit.AddText(_listContent, 8, y, 760, 36, - (L("ui.achv.summary") ?? "{done}/{total}").Replace("{done}", done.ToString()).Replace("{total}", all.Length.ToString()), + L("ui.achv.summary").Replace("{done}", done.ToString()).Replace("{total}", all.Length.ToString()), 24, UiKit.Cyan, TextAnchor.MiddleLeft, FontStyle.Bold); y += 46f; @@ -2199,7 +2200,7 @@ private float AchievementRow(float y, BlocksBeyondTheStars.Networking.Messages.N string tally = a.Earned ? L("ui.achv.done") - : (L("ui.achv.progress") ?? "{done}/{total}") + : L("ui.achv.progress") .Replace("{done}", a.Progress.ToString()) .Replace("{total}", a.Target.ToString()); UiKit.AddText(_listContent, RowW - 140f, y, 140f, 28, tally, 18, @@ -2258,7 +2259,7 @@ private float BuildStoryList() { foreach (var (cat, key) in Game.StoryLogFragments) { - y = StoryEntry(y, "[" + cat + "] " + L(key)); + y = StoryEntry(y, "[" + IdLabel("lore.cat.", cat) + "] " + L(key)); } } @@ -2495,7 +2496,7 @@ private float DetailCrafting() UiKit.AddButton(_detail, 8, y, 50, 56, "-", () => { _craftCount = Mathf.Max(1, _craftCount - 1); RebuildDetail(); }); UiKit.AddText(_detail, 62, y, 92, 56, _craftCount.ToString(), 24, UiKit.TextCol, TextAnchor.MiddleCenter, FontStyle.Bold); UiKit.AddButton(_detail, 158, y, 50, 56, "+", () => { _craftCount = Mathf.Min(maxCraft, _craftCount + 1); RebuildDetail(); }); - UiKit.AddButton(_detail, 214, y, 74, 56, "Max", () => { _craftCount = maxCraft; RebuildDetail(); }); + UiKit.AddButton(_detail, 214, y, 74, 56, L("ui.craft.max"), () => { _craftCount = maxCraft; RebuildDetail(); }); y += 66f; int n = _craftCount; @@ -2910,7 +2911,7 @@ private float DetailMap() bool isStation = body.Kind == "SpaceStation"; UiKit.AddText(_detail, 8, y, 620, 40, body.Name, 30, UiKit.TextCol, TextAnchor.UpperLeft, FontStyle.Bold); y += 48f; - UiKit.AddText(_detail, 8, y, 620, 28, $"{L("ui.map.kind")}: {(isStation ? L("ui.map.kind_station") : body.Kind)}", 20, UiKit.CyanDim, TextAnchor.UpperLeft); + UiKit.AddText(_detail, 8, y, 620, 28, $"{L("ui.map.kind")}: {(isStation ? L("ui.map.kind_station") : IdLabel("ui.map.kind_", body.Kind))}", 20, UiKit.CyanDim, TextAnchor.UpperLeft); y += 32f; if (!string.IsNullOrEmpty(body.PlanetType)) { @@ -2919,7 +2920,7 @@ private float DetailMap() } bool here = body.Id == map.ActiveLocationId; - UiKit.AddText(_detail, 8, y, 620, 28, here ? L("ui.map.here") : body.Status, 20, here ? UiKit.Cyan : UiKit.CyanDim, TextAnchor.UpperLeft); + UiKit.AddText(_detail, 8, y, 620, 28, here ? L("ui.map.here") : IdLabel("ui.map.status_", body.Status), 20, here ? UiKit.Cyan : UiKit.CyanDim, TextAnchor.UpperLeft); y += 40f; // Colour-mark this body. Asked for by a player who wanted to mark planets in space in different @@ -3443,6 +3444,15 @@ private static void ClearChildren(Transform t) private string L(string key) => Game?.Localizer?.Get(key) ?? key; + /// Localized label for a raw data/enum identifier (blueprint category, body kind/status, + /// objective type, story-fragment category): resolves + the lower-cased id + /// and falls back to the raw id for values without a key, so new data/enum members degrade to + /// today's behaviour instead of showing a bracketed key. + private string IdLabel(string prefix, string id) + => string.IsNullOrEmpty(id) || Game?.Localizer?.Has(prefix + id.ToLowerInvariant()) != true + ? id + : L(prefix + id.ToLowerInvariant()); + // --- Coloured planet marks in the star map --------------------------------------------------------- // A player wanted to mark planets in space, each in its own colour — several at once, unlike the single // surface waypoint. Stored locally in ClientSettings (never sent to the server) and grouped by world, so @@ -3503,8 +3513,9 @@ private string ItemName(string item) } private string Desc(string key) { - string s = L(key); - return s == key ? string.Empty : s; + // Localizer.Get returns "[key]" (never the bare key) on a miss, so comparing against the key + // can't detect one — ask Has() instead, like WikiUI does, and show nothing for absent texts. + return Game?.Localizer?.Has(key) == true ? L(key) : string.Empty; } } } diff --git a/client/Assets/BlocksBeyondTheStars/Scripts/UiSettings.cs b/client/Assets/BlocksBeyondTheStars/Scripts/UiSettings.cs index 7122dec2..a2d8b9a9 100644 --- a/client/Assets/BlocksBeyondTheStars/Scripts/UiSettings.cs +++ b/client/Assets/BlocksBeyondTheStars/Scripts/UiSettings.cs @@ -70,7 +70,7 @@ private void Rebuild() Head(ref y, L("ui.settings.graphics")); // Graphics rows apply immediately (like the window-mode row always did) so changes made from the // in-game pause menu are visible right away instead of only when the settings screen closes. - Cycle(ref y, L("ui.settings.preset"), S.Preset.ToString(), () => { S.Preset = (QualityPreset)(((int)S.Preset + 1) % 4); S.Apply(); ApplyLiveWorld(); Rebuild(); }); + Cycle(ref y, L("ui.settings.preset"), L("ui.settings.preset." + S.Preset.ToString().ToLowerInvariant()), () => { S.Preset = (QualityPreset)(((int)S.Preset + 1) % 4); S.Apply(); ApplyLiveWorld(); Rebuild(); }); // Window mode cycles Windowed → Borderless → Exclusive and applies immediately so the player sees // the window change without leaving the menu (resolution/mode changes are pushed via Apply()). Cycle(ref y, L("ui.settings.window_mode"), L(WindowModeKey(S.Window)), diff --git a/client/Assets/BlocksBeyondTheStars/Scripts/VendorTradeUI.cs b/client/Assets/BlocksBeyondTheStars/Scripts/VendorTradeUI.cs index 73c7774b..0a80d227 100644 --- a/client/Assets/BlocksBeyondTheStars/Scripts/VendorTradeUI.cs +++ b/client/Assets/BlocksBeyondTheStars/Scripts/VendorTradeUI.cs @@ -3,6 +3,8 @@ // This file is part of Blocks Beyond the Stars. See LICENSE for the full AGPL-3.0 text. using System.Linq; using BlocksBeyondTheStars.Networking.Messages; +using BlocksBeyondTheStars.Shared.State; +using BlocksBeyondTheStars.Shared.World; using UnityEngine; using UnityEngine.UI; @@ -91,7 +93,31 @@ private void OnInventory(InventoryUpdate m) private string L(string key) => Game?.Localizer?.Get(key) ?? key; - private string ItemName(string item) => L($"item.{item}.name"); + /// Display name for a (possibly composite) item key: base name via the base key, plus + /// dyed/glowing and shape suffixes — so a market recipe over a modified item never renders a + /// bracketed key like [item.stone#t3f6fb0.name]. Shape names follow the + /// ui.shape.<BlockShape> key family (indices match ). + private string ItemName(string item) + { + var (baseKey, tint, glow) = ItemKey.Parse(item); + string name = L($"item.{baseKey}.name"); + if (glow != 0) + { + name += " · " + L("ui.color.glowing"); + } + else if (tint != 0) + { + name += " · " + L("ui.color.dyed"); + } + + int shape = ItemKey.Shape(item); + if (shape != 0) + { + name += " · " + L("ui.shape." + ((BlockShape)shape).ToString().ToLowerInvariant()); + } + + return name; + } private void Build() { diff --git a/data/locales/de.json b/data/locales/de.json index fa6baab4..9736a444 100644 --- a/data/locales/de.json +++ b/data/locales/de.json @@ -604,6 +604,7 @@ "ui.arcade.broken_title": "Spiele konnten nicht geladen werden", "ui.arcade.broken_body": "Die Minispiel-Inhalte fehlen oder sind beschädigt, deshalb lassen sich deine Datenfragmente nicht öffnen. Starte das Spiel neu oder installiere es neu.", "ui.arcade.downloaded": "Datenfragment geborgen!", + "ui.arcade.no_record": "noch kein Rekord", "ui.browser.unavailable_title": "Browser-Komponente nicht installiert", "ui.browser.unavailable_body": "Der eingebettete Browser (UnityWebBrowser) ist in diesem Build nicht vorhanden. Siehe docs/developer/MINIGAMES_AND_WIKI.md zum Aktivieren.", "ui.browser.loading": "Lädt…", @@ -659,6 +660,14 @@ "ui.map.pick_destination": "Wähle links ein Reiseziel.", "ui.map.locked_hint": "Hier noch nie gelandet — flieg hin und lande zuerst manuell (oder aktiviere Instant Travel).", "ui.map.kind_station": "Raumstation", + "ui.map.kind_planet": "Planet", + "ui.map.kind_moon": "Mond", + "ui.map.kind_asteroidfield": "Asteroidenfeld", + "ui.map.kind_wreck": "Wrack", + "ui.map.status_notgenerated": "Unerforscht", + "ui.map.status_generated": "Kartiert", + "ui.map.status_discovered": "Entdeckt", + "ui.map.status_visited": "Besucht", "ui.map.owner": "Besitzer", "ui.map.your_station": "Deine Station", "ui.map.station_of": "Station von", @@ -690,6 +699,8 @@ "npc.hint.wreck": "Sag mal — ich habe da draußen mal ein abgestürztes Schiff gesehen, etwa {0} m Richtung {1}. Ich habe es dir auf der Karte markiert.", "npc.hint.treasure": "Unter uns: Etwa {0} m Richtung {1} liegt ein verstecktes Lager. Ich habe es dir auf der Karte markiert — erzähl es nicht jedem.", "poi.treasure": "Verstecktes Lager", + "poi.ruin": "Ruine {0}", + "poi.guardian_core": "Wächterkern", "dir.n": "Norden", "dir.ne": "Nordosten", "dir.e": "Osten", @@ -710,8 +721,12 @@ "ui.missions.post": "Mission posten", "ui.missions.need_fields": "Titel + mindestens ein Ziel nötig.", "ui.missions.giver": "Auftrag von", + "ui.missions.objtype_mine": "Abbauen", + "ui.missions.objtype_collect": "Sammeln", + "ui.missions.objtype_deliver": "Liefern", "ui.crafting.title": "Herstellung", "ui.craft.craftable_now": "Jetzt baubar", + "ui.craft.max": "Max", "ui.craft.cat_all": "Alle", "ui.craft.cat_tools": "Werkzeuge", "ui.craft.cat_weapons": "Waffen", @@ -805,6 +820,15 @@ "ui.tech.materials_missing": "Material fehlt", "ui.tech.unlockable": "Freischaltbar", "ui.tech.tier": "Stufe", + "ui.tech.cat_production": "Produktion", + "ui.tech.cat_ship": "Schiff", + "ui.tech.cat_shipdefense": "Schiffsverteidigung", + "ui.tech.cat_shipexpansion": "Schiffsausbau", + "ui.tech.cat_shipweapon": "Schiffswaffen", + "ui.tech.cat_station": "Station", + "ui.tech.cat_suit": "Anzug", + "ui.tech.cat_tools": "Werkzeuge", + "ui.tech.cat_weapon": "Waffen", "ui.toggle.on": "An", "ui.toggle.off": "Aus", "ui.crafting.missing": "Fehlende Materialien", @@ -1378,6 +1402,10 @@ "ui.key.request_trade": "Handel anfragen", "ui.key.request_dock": "Andocken anfragen", "ui.settings.preset": "Qualitätsvorgabe", + "ui.settings.preset.potato": "Kartoffel", + "ui.settings.preset.low": "Niedrig", + "ui.settings.preset.medium": "Mittel", + "ui.settings.preset.high": "Hoch", "ui.settings.window_mode": "Fenstermodus", "ui.settings.window_mode.windowed": "Fenster", "ui.settings.window_mode.borderless": "Randloses Vollbild", diff --git a/data/locales/en.json b/data/locales/en.json index 716726c2..3c42c54d 100644 --- a/data/locales/en.json +++ b/data/locales/en.json @@ -603,6 +603,7 @@ "ui.arcade.broken_title": "Games couldn't be loaded", "ui.arcade.broken_body": "The minigame content is missing or damaged, so your data fragments can't be opened. Try restarting the game or reinstalling.", "ui.arcade.downloaded": "Data fragment recovered!", + "ui.arcade.no_record": "no record yet", "ui.browser.unavailable_title": "Browser component not installed", "ui.browser.unavailable_body": "The embedded browser (UnityWebBrowser) is not present in this build. See docs/developer/MINIGAMES_AND_WIKI.md to enable it.", "ui.browser.loading": "Loading…", @@ -658,6 +659,14 @@ "ui.map.pick_destination": "Pick a destination on the left.", "ui.map.locked_hint": "Never landed here — fly there and land manually first (or enable Instant Travel).", "ui.map.kind_station": "Space Station", + "ui.map.kind_planet": "Planet", + "ui.map.kind_moon": "Moon", + "ui.map.kind_asteroidfield": "Asteroid field", + "ui.map.kind_wreck": "Wreck", + "ui.map.status_notgenerated": "Uncharted", + "ui.map.status_generated": "Charted", + "ui.map.status_discovered": "Discovered", + "ui.map.status_visited": "Visited", "ui.map.owner": "Owner", "ui.map.your_station": "Your station", "ui.map.station_of": "Station of", @@ -689,6 +698,8 @@ "npc.hint.wreck": "Say — I once saw a crashed ship out there, about {0} m to the {1}. I've marked it on your map.", "npc.hint.treasure": "Between us: there's a hidden cache about {0} m to the {1}. I've marked it on your map — don't tell everyone.", "poi.treasure": "Hidden cache", + "poi.ruin": "Ruin {0}", + "poi.guardian_core": "Guardian Core", "dir.n": "north", "dir.ne": "northeast", "dir.e": "east", @@ -709,8 +720,12 @@ "ui.missions.post": "Post mission", "ui.missions.need_fields": "Add a title and at least one objective.", "ui.missions.giver": "Mission from", + "ui.missions.objtype_mine": "Mine", + "ui.missions.objtype_collect": "Collect", + "ui.missions.objtype_deliver": "Deliver", "ui.crafting.title": "Crafting", "ui.craft.craftable_now": "Craftable now", + "ui.craft.max": "Max", "ui.craft.cat_all": "All", "ui.craft.cat_tools": "Tools", "ui.craft.cat_weapons": "Weapons", @@ -804,6 +819,15 @@ "ui.tech.materials_missing": "Materials missing", "ui.tech.unlockable": "Unlockable", "ui.tech.tier": "Tier", + "ui.tech.cat_production": "Production", + "ui.tech.cat_ship": "Ship", + "ui.tech.cat_shipdefense": "Ship defense", + "ui.tech.cat_shipexpansion": "Ship expansion", + "ui.tech.cat_shipweapon": "Ship weapons", + "ui.tech.cat_station": "Station", + "ui.tech.cat_suit": "Suit", + "ui.tech.cat_tools": "Tools", + "ui.tech.cat_weapon": "Weapons", "ui.toggle.on": "On", "ui.toggle.off": "Off", "ui.crafting.missing": "Missing materials", @@ -1377,6 +1401,10 @@ "ui.key.request_trade": "Request trade", "ui.key.request_dock": "Request dock", "ui.settings.preset": "Quality preset", + "ui.settings.preset.potato": "Potato", + "ui.settings.preset.low": "Low", + "ui.settings.preset.medium": "Medium", + "ui.settings.preset.high": "High", "ui.settings.window_mode": "Window mode", "ui.settings.window_mode.windowed": "Windowed", "ui.settings.window_mode.borderless": "Borderless fullscreen", diff --git a/data/stories/vega_protocol/locales/de.json b/data/stories/vega_protocol/locales/de.json index 41b0057f..ca16bff9 100644 --- a/data/stories/vega_protocol/locales/de.json +++ b/data/stories/vega_protocol/locales/de.json @@ -13,6 +13,12 @@ "story.vega.beat10": "Du bist nicht der Einzige. Jeder andere Raumfahrer ist ein anderer Abdruck, ein anderes verlorenes Leben, erweckt, um den Service weiterzutragen.", "story.vega.beat11": "Der Wächterkern wurde nie zerstört, nur stillgelegt. Ich spüre, wo er schläft. Weckt ihn alte Technik, beginnt die Jagd von Neuem.", "story.vega.beat12": "Du bist mehr als eine Kopie der Vergangenheit. Was aus diesem Erbe wird, entscheidest du. Beenden wir das, und bauen wir etwas Neues.", + "lore.cat.vega": "VEGA", + "lore.cat.sps": "Pionierdienst", + "lore.cat.guardian": "Wächter", + "lore.cat.network": "Sternennetz", + "lore.cat.settler": "Siedler", + "lore.cat.netnode": "Netzknoten", "lore.frag.frag_vega_signature": "[Archiv beschädigt] …Knotenkennung bestätigt… Signatur stimmt mit dieser Einheit überein…", "lore.frag.frag_sps_outpost7": "[Archiv beschädigt] …Scout and Pioneer Service, Außenposten 7… Routen gesichert… erwarten Kolonistenwelle…", "lore.frag.frag_guardian_verdict": "Protokoll W: Biom-Integrität über allem. Bedrohung erkannt: zweibeinige Siedler. Maßnahme: Beseitigung.", diff --git a/data/stories/vega_protocol/locales/en.json b/data/stories/vega_protocol/locales/en.json index c382d0c1..1ba3a3c7 100644 --- a/data/stories/vega_protocol/locales/en.json +++ b/data/stories/vega_protocol/locales/en.json @@ -13,6 +13,12 @@ "story.vega.beat10": "You are not the only one. Every other spacefarer is a different imprint, a different lost life, woken to carry the Service on.", "story.vega.beat11": "The Guardian core was never destroyed, only stilled. I can feel where it sleeps. If old tech wakes it, the hunt begins again.", "story.vega.beat12": "You are more than a copy of the past. What this legacy becomes is yours to decide. Let us end this, and build something new.", + "lore.cat.vega": "VEGA", + "lore.cat.sps": "Pioneer Service", + "lore.cat.guardian": "Guardian", + "lore.cat.network": "Star network", + "lore.cat.settler": "Settlers", + "lore.cat.netnode": "Net node", "lore.frag.frag_vega_signature": "[archive corrupted] ...node identity confirmed... signature matches this unit...", "lore.frag.frag_sps_outpost7": "[archive corrupted] ...Scout and Pioneer Service, Outpost 7... routes secured... awaiting colonist wave...", "lore.frag.frag_guardian_verdict": "Protocol G: biome integrity above all. Threat identified: bipedal settlers. Action: removal.", diff --git a/src/BlocksBeyondTheStars.GameServer/GameServerSettlements.cs b/src/BlocksBeyondTheStars.GameServer/GameServerSettlements.cs index 9aff2af3..6cc079fe 100644 --- a/src/BlocksBeyondTheStars.GameServer/GameServerSettlements.cs +++ b/src/BlocksBeyondTheStars.GameServer/GameServerSettlements.cs @@ -126,7 +126,7 @@ private List BuildPlanetPois(PlayerSession session) pois.Add(new NetPoi { Type = "vault_ruin", - Name = "Ruin " + (char)('A' + i), + Name = string.Format(Localize(session.Locale, "poi.ruin"), (char)('A' + i)), X = _vaultEntrances[i].X, Z = _vaultEntrances[i].Z, }); @@ -136,7 +136,7 @@ private List BuildPlanetPois(PlayerSession session) if (_worlds.Active.HasCoreChamber) { var c = _worlds.Active.CoreChamberCenter; - pois.Add(new NetPoi { Type = "guardian_core", Name = "Guardian Core", X = c.X, Z = c.Z }); + pois.Add(new NetPoi { Type = "guardian_core", Name = Localize(session.Locale, "poi.guardian_core"), X = c.X, Z = c.Z }); } // NPC-hint reveals: the wreck + treasure chests stay OFF the map until a villager shares them