Merge pull request #1738 from thibautbus/fix/translate-gold-naming-screen

Translate Gold's naming/keyboard screen
This commit is contained in:
bryanthaboi
2026-08-24 08:32:22 -04:00
committed by GitHub
2 changed files with 129 additions and 13 deletions
+29 -13
View File
@@ -21,6 +21,7 @@ local Chrome = require("src.ui.gen2.Chrome")
local Font = require("src.render.Font")
local GbcPalette = require("src.render.GbcPalette")
local Runtime = require("src.mods.Runtime")
local Strings = require("src.core.Strings")
local NamingScreen = {}
NamingScreen.__index = NamingScreen
@@ -67,8 +68,15 @@ local BOX_INPUT_LOWER = {
-- case target names the board it SWITCHES TO, not the one it is on: the last
-- row of NameInputUpper is "lower DEL END" and the last row of
-- NameInputLower is "UPPER DEL END" (data/text/name_input_chars.asm).
local BOTTOM_UPPER_LABELS = { "lower", "DEL", "END" }
local BOTTOM_LOWER_LABELS = { "UPPER", "DEL", "END" }
-- Wrapped in Strings.source, not Strings: both tables are built once at
-- require time, before any mod's Strings.load has a catalog to answer from
-- (src/core/Strings.lua's own note on this); drawPanel resolves them live.
local BOTTOM_UPPER_LABELS = {
Strings.source("lower"), Strings.source("DEL"), Strings.source("END"),
}
local BOTTOM_LOWER_LABELS = {
Strings.source("UPPER"), Strings.source("DEL"), Strings.source("END"),
}
-- Cursor tile for each target: NamingScreen_AnimateCursor's .CaseDelEnd adds
-- pixel $00 / $30 / $60 to the cursor's own XCOORD of 24 (`depixel 10, 3`),
-- which is OAM x 24 / 72 / 120 and so screen tile 2 / 8 / 14. The bracket is
@@ -81,10 +89,10 @@ local BOTTOM_CURSOR_TILES = 5
-- NAME_* types (constants/menu_constants.asm order) as prompts + field sizes.
-- Lengths are the ASM's *_NAME_LENGTH - 1, i.e. usable characters.
NamingScreen.TYPES = {
player = { prompt = "YOUR NAME?", maxLength = 7, sprite = "SPRITE_CHRIS" },
rival = { prompt = "RIVAL'S NAME?", maxLength = 7, sprite = "SPRITE_RIVAL" },
mom = { prompt = "MOTHER'S NAME?", maxLength = 7, sprite = "SPRITE_MOM" },
box = { prompt = "BOX NAME?", maxLength = 8, isBox = true },
player = { prompt = Strings.source("YOUR NAME?"), maxLength = 7, sprite = "SPRITE_CHRIS" },
rival = { prompt = Strings.source("RIVAL'S NAME?"), maxLength = 7, sprite = "SPRITE_RIVAL" },
mom = { prompt = Strings.source("MOTHER'S NAME?"), maxLength = 7, sprite = "SPRITE_MOM" },
box = { prompt = Strings.source("BOX NAME?"), maxLength = 8, isBox = true },
nickname = { prompt = nil, maxLength = 10 },
}
@@ -103,7 +111,7 @@ function NamingScreen.new(game, opts)
self.kind = kind
self.isBox = opts.isBox or kind.isBox or false
self.maxLength = opts.maxLength or kind.maxLength or 7
self.prompt = opts.prompt or kind.prompt or "NICKNAME?"
self.prompt = opts.prompt or kind.prompt or Strings.source("NICKNAME?")
self.monName = opts.monName
self.onDone = opts.onDone
self.onCancel = opts.onCancel
@@ -493,11 +501,15 @@ function NamingScreen:drawPanel()
end
local pal = self.palette
if self.monName then
-- Nickname header is two lines: "<MON>'S" then "NICKNAME?".
Chrome.printThrough(self.monName .. "'S", 5, 2, pal)
Chrome.printThrough("NICKNAME?", 5, 4, pal)
-- Nickname header is two lines: "<MON>'S" then "NICKNAME?". Kept as two
-- Strings() calls, one per line (Chrome.printThrough draws a single row),
-- with the mon name folded into the first line's own format string so a
-- language whose possessive is not a bare suffix can restructure that
-- line rather than being stuck splicing one on.
Chrome.printThrough(Strings("%s'S", self.monName), 5, 2, pal)
Chrome.printThrough(Strings("NICKNAME?"), 5, 4, pal)
else
Chrome.printThrough(self.prompt, 5, 2, pal)
Chrome.printThrough(Strings(self.prompt), 5, 2, pal)
end
self:drawEntry(5, self.isBox and 4 or 6)
@@ -509,14 +521,18 @@ function NamingScreen:drawPanel()
for col = 0, 8 do
local ch = line[col + 1]
if ch and ch ~= " " and ch ~= "" then
Chrome.printThrough(ch, 2 + col * 2, keyboardTop + row * 2, pal)
-- Same seam the Gen 1 board's cells go through (src/ui/NamingScreen
-- .lua's own Strings(cell)): a script whose alphabet does not fit
-- A-Z can swap a cell's glyph without needing the heavier
-- ui.naming.grid hook this screen also offers.
Chrome.printThrough(Strings(ch), 2 + col * 2, keyboardTop + row * 2, pal)
end
end
end
local labels = self.lower and BOTTOM_LOWER_LABELS or BOTTOM_UPPER_LABELS
local bottomY = keyboardTop + bottom * 2
for i, label in ipairs(labels) do
Chrome.printThrough(label, BOTTOM_LABEL_TX[i], bottomY, pal)
Chrome.printThrough(Strings(label), BOTTOM_LABEL_TX[i], bottomY, pal)
end
local function cursor() self:drawCursorBox(self:cursorTile()) end
@@ -0,0 +1,100 @@
-- Gold's naming/keyboard screen (src/ui/gen2/NamingScreen.lua) had zero
-- Strings() calls: every prompt (YOUR NAME?/RIVAL'S NAME?/MOTHER'S NAME?/
-- BOX NAME?/NICKNAME?), the on-screen keyboard's own letters, and the
-- lower/UPPER/DEL/END bottom-row labels were bare literals, invisible to a
-- translation mod's `strings` registry (reported against a real Gold build,
-- gen1recomp#1642). The Gen 1 naming screen (src/ui/NamingScreen.lua) already
-- routes its title and every keyboard cell through Strings().
--
-- GbcPalette.available() is false headless (no real shader compiles), so
-- Chrome.printThrough already falls back to the plain, unshaded Chrome.print
-- -- this drives that path directly and checks the translated text reaches
-- Font.draw, the same technique
-- tests/engine/gen2_options_menu_translation_test.lua uses for the OPTION
-- screen.
package.path = "./?.lua;./?/init.lua;" .. package.path
local T = require("tests.harness")
love = require("tests.love_stub")
require("src.core.Logger").warn = function() end
local drawn
package.loaded["src.render.Font"] = {
draw = function(text, x, y)
drawn[#drawn + 1] = { text = text, x = x, y = y }
end,
drawCode = function() end,
drawBox = function() end,
}
local NamingScreen = require("src.ui.gen2.NamingScreen")
local Strings = require("src.core.Strings")
local function drawnAt(x, y)
for _, d in ipairs(drawn) do
if d.x == x and d.y == y then return d.text end
end
return nil
end
-- Chrome.print multiplies tile coordinates by 8 (src/ui/gen2/Chrome.lua);
-- the prompt lands at tile (5, 2), the keyboard's first cell at (2, 8).
local PROMPT_X, PROMPT_Y = 5 * 8, 2 * 8
local FIRST_CELL_X, FIRST_CELL_Y = 2 * 8, 8 * 8
-- ---------------------------------------------- vanilla: no mod catalog
do
local screen = NamingScreen.new({}, { type = "player" })
drawn = {}
screen:drawPanel()
T.eq(drawnAt(PROMPT_X, PROMPT_Y), "YOUR NAME?",
"the player-name prompt draws in English with no mod loaded")
T.eq(drawnAt(FIRST_CELL_X, FIRST_CELL_Y), "A",
"and the keyboard's first cell too")
end
-- ------------------------------------------------- a translation mod's turn
do
Strings.load({
strings = {
["YOUR NAME?"] = "TON NOM?",
["A"] = "À",
["lower"] = "minusc",
["END"] = "FIN",
["%s'S"] = "DE %s",
["NICKNAME?"] = "SURNOM?",
},
})
local screen = NamingScreen.new({}, { type = "player" })
drawn = {}
screen:drawPanel()
T.eq(drawnAt(PROMPT_X, PROMPT_Y), "TON NOM?",
"a mod catalog reaches the prompt")
T.eq(drawnAt(FIRST_CELL_X, FIRST_CELL_Y), "À",
"and a keyboard cell")
-- The bottom row: lower/DEL/END at tile y = keyboardTop + bottom*2.
local bottomY = (screen:keyboardTop() + screen:bottomRow() * 2) * 8
T.eq(drawnAt(2 * 8, bottomY), "minusc", "the case-switch label is translated")
T.eq(drawnAt(15 * 8, bottomY), "FIN", "and END, the way out of the screen")
-- The nickname header: two lines, the mon name folded into the first.
local nickScreen = NamingScreen.new({}, { type = "nickname", monName = "BULBASAUR" })
drawn = {}
nickScreen:drawPanel()
T.eq(drawnAt(PROMPT_X, PROMPT_Y), "DE BULBASAUR",
"the nickname header's first line takes the mod's own word order")
T.eq(drawnAt(PROMPT_X, 4 * 8), "SURNOM?", "and its second line")
-- Module state is process-global (see tests/gen2_clock_test.lua's own
-- note); this suite gets its own process from tests/tier_runner.lua, but
-- leaving the catalog loaded past this point would still mistranslate
-- every check below it in this file.
Strings.load({})
T.check(not Strings.active(), "the catalog is unloaded for the checks after this one")
end
T.finish("gen2_naming_screen_translation_test")