mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-25 06:55:29 +02:00
654650e3ff
An independent review flagged two gaps:
Pokegear.lua's clock card (drawClock and the card-list clock view) prints
the same AM/PM information MainMenu's clock box does, but was left as bare
literals -- so a mod translating AM/PM would now show it correctly on the
title screen and in English on the Pokegear for the exact same hour. Both
call sites now go through Strings("AM")/Strings("PM"), the same source key
MainMenu.lua already added, so no new corpus entry is needed on the
translation-mods side.
SaveMenu.lua's twoLines() only ever split on the first "\n": drawPanel's
box has room for exactly two Chrome.print calls, so a translation needing
a third line (nothing in the current fr/de/es/it overrides does, but
nothing stopped one from trying) had nowhere on screen to go, and the
extra "\n" landed as a literal newline byte drawn as glyph garbage on the
second line with no indication anything was wrong. It now warns once per
source text instead.
Added a gen2_save_menu_translation_test.lua case driving drawPanel() with a
three-line mod translation: confirms only the first two lines render, the
warning fires exactly once (not once per frame), and drawing does not
crash. Pokegear.lua has no engine-tier test suite to extend for the AM/PM
change; verified by direct inspection and a syntax check instead.
200 lines
7.8 KiB
Lua
200 lines
7.8 KiB
Lua
-- Gold's SAVE screen (src/ui/gen2/SaveMenu.lua) drew every prompt ("Would
|
|
-- you like to save the game?", the overwrite/saving/saved messages), the
|
|
-- YES/NO choice, and the summary panel's labels (PLAYER <name>/BADGES/
|
|
-- POKéDEX/TIME) as bare literals, invisible to a translation mod's
|
|
-- `strings` registry -- unlike the Gen 1 port's own SAVE screen
|
|
-- (src/ui/StartMenu.lua), which already routes the same rows through
|
|
-- Strings(). Drives SaveMenu:drawPanel() directly at each phase with a
|
|
-- mod-loaded Strings catalog and checks the translated text reaches
|
|
-- Font.draw, same technique as
|
|
-- tests/engine/gen2_naming_screen_translation_test.lua.
|
|
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,
|
|
width = function() return 0 end,
|
|
}
|
|
|
|
local SaveMenu = require("src.ui.gen2.SaveMenu")
|
|
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).
|
|
-- PLAYER row at (5, 2); the two prompt lines at (1, 14)/(1, 16); YES/NO at
|
|
-- (2, 8)/(2, 10) (YESNO_X + 2, YESNO_Y + 1 / + 3).
|
|
local PANEL_PLAYER_X, PANEL_PLAYER_Y = 5 * 8, 2 * 8
|
|
local PROMPT1_X, PROMPT1_Y = 1 * 8, 14 * 8
|
|
local PROMPT2_X, PROMPT2_Y = 1 * 8, 16 * 8
|
|
local YES_X, YES_Y = 2 * 8, 8 * 8
|
|
local NO_X, NO_Y = 2 * 8, 10 * 8
|
|
|
|
local SAVE = { player = { name = "GOLD" } }
|
|
|
|
-- ---------------------------------------------- vanilla: no mod catalog
|
|
do
|
|
local menu = SaveMenu.new({}, { save = SAVE, existed = false })
|
|
drawn = {}
|
|
menu:drawPanel()
|
|
T.eq(drawnAt(PANEL_PLAYER_X, PANEL_PLAYER_Y), "PLAYER GOLD",
|
|
"the summary panel draws in English with no mod loaded")
|
|
T.eq(drawnAt(PROMPT1_X, PROMPT1_Y), "Would you like to",
|
|
"and the confirm prompt's first line")
|
|
T.eq(drawnAt(PROMPT2_X, PROMPT2_Y), "save the game?", "and its second line")
|
|
T.eq(drawnAt(YES_X, YES_Y), "YES", "and YES")
|
|
T.eq(drawnAt(NO_X, NO_Y), "NO", "and NO")
|
|
|
|
menu.phase = "overwrite"
|
|
drawn = {}
|
|
menu:drawPanel()
|
|
T.eq(drawnAt(PROMPT1_X, PROMPT1_Y), "There is already a", "the overwrite prompt")
|
|
T.eq(drawnAt(PROMPT2_X, PROMPT2_Y), "save file. Is it", "its second line")
|
|
|
|
menu.phase = "saving"
|
|
drawn = {}
|
|
menu:drawPanel()
|
|
T.eq(drawnAt(PROMPT1_X, PROMPT1_Y), "SAVING… DON'T TURN", "the saving message")
|
|
T.eq(drawnAt(PROMPT2_X, PROMPT2_Y), "OFF THE POWER.", "its second line")
|
|
|
|
menu.phase, menu.saved = "done", true
|
|
drawn = {}
|
|
menu:drawPanel()
|
|
T.eq(drawnAt(PROMPT1_X, PROMPT1_Y), "GOLD saved", "the saved message")
|
|
T.eq(drawnAt(PROMPT2_X, PROMPT2_Y), "the game.", "its second line")
|
|
|
|
menu.phase, menu.saved = "done", false
|
|
drawn = {}
|
|
menu:drawPanel()
|
|
T.eq(drawnAt(PROMPT1_X, PROMPT1_Y), "Could not save.", "the failed-save message")
|
|
end
|
|
|
|
-- ------------------------------------------------- a translation mod's turn
|
|
do
|
|
Strings.load({
|
|
strings = {
|
|
["PLAYER %s"] = "JOUEUR %s",
|
|
["BADGES"] = "BADGES_FR",
|
|
["POKéDEX"] = "POKéDEX_FR",
|
|
["TIME"] = "TEMPS",
|
|
["YES"] = "OUI",
|
|
["NO"] = "NON",
|
|
["Would you like to\nsave the game?"] = "Voulez-vous\nsauvegarder ?",
|
|
["There is already a\nsave file. Is it"] = "Un fichier existe\ndeja. Est-ce",
|
|
["SAVING… DON'T TURN\nOFF THE POWER."] = "SAUVEGARDE...\nN'ETEIGNEZ PAS.",
|
|
["%s saved\nthe game."] = "%s a sauvegarde\nla partie.",
|
|
["Could not save."] = "Echec de sauvegarde.",
|
|
},
|
|
})
|
|
|
|
local menu = SaveMenu.new({}, { save = SAVE, existed = false })
|
|
drawn = {}
|
|
menu:drawPanel()
|
|
T.eq(drawnAt(PANEL_PLAYER_X, PANEL_PLAYER_Y), "JOUEUR GOLD",
|
|
"the summary panel's PLAYER row takes the mod's own word order")
|
|
T.eq(drawnAt(5 * 8, 4 * 8), "BADGES_FR", "and BADGES")
|
|
T.eq(drawnAt(5 * 8, 6 * 8), "POKéDEX_FR", "and POKéDEX")
|
|
T.eq(drawnAt(5 * 8, 8 * 8), "TEMPS", "and TIME")
|
|
T.eq(drawnAt(PROMPT1_X, PROMPT1_Y), "Voulez-vous", "the confirm prompt")
|
|
T.eq(drawnAt(PROMPT2_X, PROMPT2_Y), "sauvegarder ?", "its second line")
|
|
T.eq(drawnAt(YES_X, YES_Y), "OUI", "and YES")
|
|
T.eq(drawnAt(NO_X, NO_Y), "NON", "and NO")
|
|
|
|
menu.phase = "overwrite"
|
|
drawn = {}
|
|
menu:drawPanel()
|
|
T.eq(drawnAt(PROMPT1_X, PROMPT1_Y), "Un fichier existe", "the overwrite prompt")
|
|
T.eq(drawnAt(PROMPT2_X, PROMPT2_Y), "deja. Est-ce", "its second line")
|
|
|
|
menu.phase = "saving"
|
|
drawn = {}
|
|
menu:drawPanel()
|
|
T.eq(drawnAt(PROMPT1_X, PROMPT1_Y), "SAUVEGARDE...", "the saving message")
|
|
T.eq(drawnAt(PROMPT2_X, PROMPT2_Y), "N'ETEIGNEZ PAS.", "its second line")
|
|
|
|
menu.phase, menu.saved = "done", true
|
|
drawn = {}
|
|
menu:drawPanel()
|
|
T.eq(drawnAt(PROMPT1_X, PROMPT1_Y), "GOLD a sauvegarde",
|
|
"the saved message folds the player name into the mod's own word order")
|
|
T.eq(drawnAt(PROMPT2_X, PROMPT2_Y), "la partie.", "its second line")
|
|
|
|
menu.phase, menu.saved = "done", false
|
|
drawn = {}
|
|
menu:drawPanel()
|
|
T.eq(drawnAt(PROMPT1_X, PROMPT1_Y), "Echec de sauvegarde.", "the failed-save message")
|
|
|
|
-- 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
|
|
|
|
-- src/ui/gen2/PcMenu.lua:savePrompt() returns SaveMenu.OVERWRITE_PROMPT/
|
|
-- SAVING_PROMPT straight through to its own `lines[1]`/`lines[2]`
|
|
-- Chrome.print calls (the PC's CHANGE BOX save uses the same two prompts).
|
|
-- Indexing a plain string with [1]/[2] returns nil, not characters, so this
|
|
-- shape is a cross-file contract: it caught a real regression during review,
|
|
-- where routing these through a single Strings.source()-wrapped string (to
|
|
-- translate SaveMenu's own screen) silently turned them into non-table
|
|
-- values and left PcMenu's overwrite/saving prompt blank.
|
|
do
|
|
T.eq(type(SaveMenu.OVERWRITE_PROMPT), "table", "OVERWRITE_PROMPT stays a table for PcMenu.lua")
|
|
T.eq(SaveMenu.OVERWRITE_PROMPT[1], "There is already a", "and its first line stays indexable")
|
|
T.eq(SaveMenu.OVERWRITE_PROMPT[2], "save file. Is it", "and its second line")
|
|
T.eq(type(SaveMenu.SAVING_PROMPT), "table", "SAVING_PROMPT stays a table for PcMenu.lua")
|
|
T.eq(SaveMenu.SAVING_PROMPT[1], "SAVING… DON'T TURN", "and its first line stays indexable")
|
|
T.eq(SaveMenu.SAVING_PROMPT[2], "OFF THE POWER.", "and its second line")
|
|
end
|
|
|
|
-- A translation with a THIRD line (a second embedded "\n") has nowhere on
|
|
-- screen to go -- drawPanel's box has room for exactly two Chrome.print
|
|
-- calls -- so it must not silently draw the literal newline byte as glyph
|
|
-- garbage on the second line, and should warn so a translator notices.
|
|
do
|
|
Strings.load({
|
|
strings = {
|
|
["Would you like to\nsave the game?"] = "Ligne un\nLigne deux\nLigne trois",
|
|
},
|
|
})
|
|
|
|
local warned = {}
|
|
require("src.core.Logger").warn = function(fmt, ...)
|
|
warned[#warned + 1] = select("#", ...) > 0 and fmt:format(...) or fmt
|
|
end
|
|
|
|
local menu = SaveMenu.new({}, { save = SAVE, existed = false })
|
|
drawn = {}
|
|
menu:drawPanel()
|
|
T.eq(drawnAt(PROMPT1_X, PROMPT1_Y), "Ligne un", "only the first line reaches the box")
|
|
T.eq(drawnAt(PROMPT2_X, PROMPT2_Y), "Ligne deux\nLigne trois",
|
|
"the rest lands in the second slot rather than vanishing")
|
|
T.check(#warned == 1, "and a single warning is logged")
|
|
|
|
drawn = {}
|
|
menu:drawPanel()
|
|
T.check(#warned == 1, "the warning does not repeat for the same text")
|
|
|
|
require("src.core.Logger").warn = function() end
|
|
Strings.load({})
|
|
end
|
|
|
|
T.finish("gen2_save_menu_translation_test")
|