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)
This commit is contained in:
Cyberboy
2026-07-30 15:03:35 +02:00
parent e63fa70700
commit 350402b179
5 changed files with 28 additions and 8 deletions
+1
View File
@@ -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)) } }),
+7 -2
View File
@@ -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
+1 -1
View File
@@ -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
+14
View File
@@ -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
+5 -5
View File
@@ -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