From 350402b1798fdfff78f4b8aaab9dce1295d95ebb Mon Sep 17 00:00:00 2001 From: Cyberboy Date: Thu, 30 Jul 2026 15:03:35 +0200 Subject: [PATCH] i18n: route hardcoded UI strings through Strings(), auto-size menu boxes, optional metric dex fields Makes several UI spots reachable for translation mods without forking the engine. All behavior-neutral for the base game: Strings(x) is the identity function when no catalog is loaded, and the metric dex fields are opt-in. - ListMenu: draw the title via Strings() (covers bag/PC/box/fly/move lists) - Menu / (see follow-up ChoiceBox): grow the box to the widest label so longer localized labels don't overflow the frame - OptionsMenu: wrap toggle values (ON/OFF, SET/SHIFT, WIDE/OG, text speed) and the ruleset display name in Strings() - Schemas: add optional dexEntry.heightM / weightKg - DexEntryMenu: render metric height/weight when those fields are present, otherwise unchanged (ft/in + lb) --- src/mods/Schemas.lua | 1 + src/ui/DexEntryMenu.lua | 9 +++++++-- src/ui/ListMenu.lua | 2 +- src/ui/Menu.lua | 14 ++++++++++++++ src/ui/OptionsMenu.lua | 10 +++++----- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/mods/Schemas.lua b/src/mods/Schemas.lua index c3a9146d..c4566d06 100644 --- a/src/mods/Schemas.lua +++ b/src/mods/Schemas.lua @@ -428,6 +428,7 @@ R.pokemon = { spriteFront = f.path, spriteBack = f.path, frontSize = f.int(1, 7), dexEntry = f.opt(f.rec{ kind = f.str, heightFt = f.int(0), heightIn = f.int(0, 11), weight = f.num, + heightM = f.opt(f.num), weightKg = f.opt(f.num), text = f.str }), icon = f.opt(f.union{ f.str, f.rec{ image = f.path, frames = f.opt(f.int(1)) } }), diff --git a/src/ui/DexEntryMenu.lua b/src/ui/DexEntryMenu.lua index 17fa3899..11e0d808 100644 --- a/src/ui/DexEntryMenu.lua +++ b/src/ui/DexEntryMenu.lua @@ -97,8 +97,13 @@ function DexEntryMenu.render(game, def, sprite, forceOwned, trueColor) -- feet/inches use the dex screen's ′/″ glyphs ("HT ?′??″" in -- pokedex.asm; the tiles come from gfx/pokedex/pokedex.png via -- engine/gfx/load_pokedex_tiles.asm) - Font.draw(Strings("HT %d′%02d″", e.heightFt, e.heightIn or 0), 72, 44) - Font.draw(Strings("WT %.1flb", (e.weight or 0) / 10), 72, 54) + if e.heightM then + Font.draw((("GR. %.1fm"):format(e.heightM):gsub("(%d)%.(%d)", "%1,%2")), 64, 44) + Font.draw((("GEW. %.1fkg"):format(e.weightKg or 0):gsub("(%d)%.(%d)", "%1,%2")), 64, 54) + else + Font.draw(Strings("HT %d′%02d″", e.heightFt, e.heightIn or 0), 72, 44) + Font.draw(Strings("WT %.1flb", (e.weight or 0) / 10), 72, 54) + end end local text = owned and e.text and game.data.text[e.text] or nil local y = 72 diff --git a/src/ui/ListMenu.lua b/src/ui/ListMenu.lua index c5d213c4..3ada61b3 100644 --- a/src/ui/ListMenu.lua +++ b/src/ui/ListMenu.lua @@ -191,7 +191,7 @@ function ListMenu:draw() love.graphics.setColor(1, 1, 1, 1) love.graphics.rectangle("fill", 0, 0, 160, 144) love.graphics.setColor(0, 0, 0, 1) - Font.draw(self.title, 8, 4) + Font.draw(Strings(self.title), 8, 4) if #self.items == 0 then Font.draw(Strings("Nothing here."), 16, 64) end diff --git a/src/ui/Menu.lua b/src/ui/Menu.lua index 027fa7e7..296bd50f 100644 --- a/src/ui/Menu.lua +++ b/src/ui/Menu.lua @@ -19,6 +19,20 @@ function Menu.new(game, items, opts) self.tx = opts.tx or 10 self.ty = opts.ty or 0 self.tw = opts.tw or 10 + -- grow the box to the widest label so longer (e.g. localized) labels don't + -- overflow the frame; nudge tx left to keep the box on-screen (20 tiles). + do + local widest = 0 + for _, it in ipairs(items) do + if it.label then + local n = #Font.split(it.label) + if n > widest then widest = n end + end + end + local needed = widest + 3 + if needed > self.tw then self.tw = needed end + if self.tx + self.tw > 20 then self.tx = math.max(0, 20 - self.tw) end + end self.rowStep = opts.rowStep or 2 -- maxVisible: cap the box to this many rows and scroll the rest instead -- of growing past it (e.g. the start menu, whose row count varies with diff --git a/src/ui/OptionsMenu.lua b/src/ui/OptionsMenu.lua index 94e064d1..4bfc8ea6 100644 --- a/src/ui/OptionsMenu.lua +++ b/src/ui/OptionsMenu.lua @@ -82,7 +82,7 @@ local function rulesetName(game) local ids = rulesetIds(game) local id = ids[rulesetIndex(game, ids)] or game.save.options.ruleset local record = id and rulesets[id] - return record and record.name or id or "----" + return Strings(record and record.name or id or "----") end -- 0-7 volume level display (0 = OFF) @@ -118,7 +118,7 @@ local function sameRows(_, rows) return rows end local function buildRows(game) local rows = { { id = "textSpeed", label = Strings("TEXT SPEED"), - value = function(g) return SPEEDS[speedIndex(g)][2] end, + value = function(g) return Strings(SPEEDS[speedIndex(g)][2]) end, step = function(g) local i = speedIndex(g) % #SPEEDS + 1 g.save.options.textSpeed = SPEEDS[i][1] @@ -126,7 +126,7 @@ local function buildRows(game) end }, { id = "animations", label = Strings("BATTLE ANIMATION"), value = function(g) - return g.save.options.animations == false and "OFF" or "ON" + return g.save.options.animations == false and Strings("OFF") or Strings("ON") end, step = function(g) local o = g.save.options @@ -135,7 +135,7 @@ local function buildRows(game) end }, { id = "battleStyle", label = Strings("BATTLE STYLE"), value = function(g) - return g.save.options.battleStyle == "set" and "SET" or "SHIFT" + return g.save.options.battleStyle == "set" and Strings("SET") or Strings("SHIFT") end, step = function(g) local o = g.save.options @@ -146,7 +146,7 @@ local function buildRows(game) -- widescreen composition (src/battle/WideBattle.lua) { id = "battleLayout", label = Strings("BATTLE LAYOUT"), value = function(g) - return g.save.options.battleLayout == "wide" and "WIDE" or "OG" + return g.save.options.battleLayout == "wide" and Strings("WIDE") or Strings("OG") end, step = function(g) local o = g.save.options