diff --git a/src/core/gen2/Clock.lua b/src/core/gen2/Clock.lua index e926cda7..a74d2113 100644 --- a/src/core/gen2/Clock.lua +++ b/src/core/gen2/Clock.lua @@ -16,13 +16,56 @@ -- it (src/ui/gen2/InitClock.lua, src/script/gen2/Specials.lua SetDayOfWeek) -- and World only ever reads it. +local Palettes = require("src.world.gen2.Palettes") local Runtime = require("src.mods.Runtime") +local Strings = require("src.core.Strings") local Clock = {} Clock.MINUTES_PER_DAY = 24 * 60 Clock.DAYS = 7 +-- data/text/day_of_week.asm order, which is wCurDay's own: SUNDAY is 0, so +-- index 1 is SUNDAY -- matching both InitClock's `self.day + 1` and +-- `Clock.weekday(save) + 1`. Strings.source, not Strings: built at require +-- time, before Strings.load has a catalog, so Clock.weekdayName looks each +-- name up at display time instead (src/battle/MoveEffects.lua's STAT_LABEL +-- is the same pattern). One shared table and one lookup function, so +-- InitClock's screens, the main menu clock box and the Pokegear clock card +-- cannot drift apart on what a weekday is called. +Clock.DAY_NAMES = { + Strings.source("SUNDAY"), Strings.source("MONDAY"), Strings.source("TUESDAY"), + Strings.source("WEDNESDAY"), Strings.source("THURSDAY"), Strings.source("FRIDAY"), + Strings.source("SATURDAY"), +} + +-- The translated name for a 1-based weekday (SUNDAY = 1), or nil if `day` is +-- out of range. +function Clock.weekdayName(day) + local name = Clock.DAY_NAMES[day] + return name and Strings(name) +end + +-- The three words Palettes.clockDaytime can hand back, translated (never +-- DARK: that one only comes out of Palettes.daytimeFor, for a PALETTE_DARK +-- map, and is never printed as text). Strings.source, not Strings: +-- clockDaytime's return value is also an internal key every +-- FORCED_DAYTIME/palette lookup in Palettes.lua compares against, so THAT +-- stays untranslated -- only this table, and Clock.daytimeLabel below, look +-- a word up, at the UI call sites that actually print it. +local DAYTIME_LABEL = { + MORN = Strings.source("MORN"), DAY = Strings.source("DAY"), + NITE = Strings.source("NITE"), +} + +-- clockDaytime's word, translated -- the one InitClock's clock-setting +-- screen and the Pokegear's clock card print (DisplayHourOClock / +-- Pokegear_UpdateClock). +function Clock.daytimeLabel(hour) + local daytime = Palettes.clockDaytime(hour) + return Strings(DAYTIME_LABEL[daytime] or daytime) +end + -- InitClock's own default: `ld a, 10 ; default hour = 10 AM`, with the minute -- buffer left at the zero ByteFill put there. Clock.DEFAULT_HOUR = 10 diff --git a/src/ui/gen2/InitClock.lua b/src/ui/gen2/InitClock.lua index d06bd81c..b957c956 100644 --- a/src/ui/gen2/InitClock.lua +++ b/src/ui/gen2/InitClock.lua @@ -60,10 +60,11 @@ InitClock.TEXT = TEXT -- same three and has always had them right. local MORN_HOUR, DAY_HOUR, NITE_HOUR = 4, 10, 18 --- data/text/day_of_week.asm order, which is wCurDay's own: SUNDAY is 0. -local DAYS = { - "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", -} +-- Clock.DAY_NAMES / Clock.weekdayName is the single translated home for this +-- table: MainMenu's clock box and the Pokegear's clock card read the same +-- weekday off the same save and must never disagree about what it is +-- called. +local DAYS = Clock.DAY_NAMES InitClock.DAYS = DAYS function InitClock:wantsFillScale() return true end @@ -88,12 +89,15 @@ function InitClock.hourString(hour) local h = math.floor(hour or 0) % 24 local display = h % 12 if display == 0 then display = 12 end - local word = require("src.world.gen2.Palettes").clockDaytime(h) + -- Clock.daytimeLabel, not Palettes.clockDaytime: the printed word, + -- translated -- this string reaches the player as-is, unlike the internal + -- MORN/DAY/NITE key other palette code compares against. + local word = Clock.daytimeLabel(h) return ("%s %d"):format(word, display) end function InitClock.oclockString(hour) - return InitClock.hourString(hour) .. " o'clock" + return Strings("%s o'clock", InitClock.hourString(hour)) end function InitClock.timeString(hour, minute) @@ -187,7 +191,7 @@ function InitClock:question() return Strings(TEXT.whoaMinutes, self.minute) end if self.phase == "confirm-day" then - return Strings(TEXT.confirmDay, DAYS[self.day + 1] or "?") + return Strings(TEXT.confirmDay, Clock.weekdayName(self.day + 1) or "?") end if self.phase == "response" then return Strings(TEXT[InitClock.responseKey(self.hour)], @@ -196,11 +200,15 @@ function InitClock:question() return "" end +-- data/text/common_1.asm's "@MIN." suffix (DisplayMinutesWithMinString), +-- separate from TEXT.whoaMinutes' own "%d min.?" confirmation line above. +local MINUTES = Strings.source("%d min.") + -- The value the picker box shows, or nil while a page is up with no picker. function InitClock:display() if self.phase == "hour" then return InitClock.oclockString(self.hour) end - if self.phase == "minute" then return ("%d min."):format(self.minute) end - if self.phase == "day" then return DAYS[self.day + 1] or "?" end + if self.phase == "minute" then return Strings(MINUTES, self.minute) end + if self.phase == "day" then return Clock.weekdayName(self.day + 1) or "?" end return nil end diff --git a/src/ui/gen2/MainMenu.lua b/src/ui/gen2/MainMenu.lua index ac3ed88e..c8fb68fc 100644 --- a/src/ui/gen2/MainMenu.lua +++ b/src/ui/gen2/MainMenu.lua @@ -29,10 +29,11 @@ local MainMenu = {} MainMenu.__index = MainMenu MainMenu.isOpaque = true --- MainMenu_PrintCurrentTimeAndDay's PrintDayOfWeek strings. -local DAYS = { - "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", -} +-- MainMenu_PrintCurrentTimeAndDay's PrintDayOfWeek strings. Clock.DAY_NAMES +-- / Clock.weekdayName is the single translated home for this table (see +-- InitClock.lua's DAYS), so this screen's clock box cannot drift from the +-- Pokegear's own. +local DAYS = Clock.DAY_NAMES -- MUSIC_MAIN_MENU; resolved by name so a cache without it just stays quiet. local MENU_MUSIC = "Music_MainMenu" @@ -164,7 +165,7 @@ function MainMenu:drawClockBox() -- Textbox at (0,12) with 4 interior rows and 13 interior columns. Chrome.textbox(0, 12, 13, 4) local hour, minute, weekday = self:clockParts() - Chrome.print(DAYS[weekday] or "DAY", 1, 14) + Chrome.print(Clock.weekdayName(weekday) or "DAY", 1, 14) -- PrintHour prints 1-12 with no leading zero, then ':' then two zero-padded -- minutes; the AM/PM half is drawn by PrintHour itself. local display = hour % 12 diff --git a/src/ui/gen2/Pokegear.lua b/src/ui/gen2/Pokegear.lua index 0413cdaa..30bbea33 100644 --- a/src/ui/gen2/Pokegear.lua +++ b/src/ui/gen2/Pokegear.lua @@ -56,10 +56,6 @@ local CARDS = { -- card over. One row, so `#self.cards` stays 1 and nothing pages. local FLY_MAP_CARD = { id = "map", label = "FLY" } -local DAYS = { - "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", -} - -- ---------------------------------------------------------------- the radio -- -- engine/pokegear/radio.asm is not a text table: it is a jumptable of code. @@ -1878,7 +1874,7 @@ function Pokegear:drawClock() -- Pokegear_UpdateClock: ClearBox(3,5) 5x14, the day at (6,6) and -- PrintHoursMins at (6,8) -- two digits, ':', two more, then AM/PM at -- column 12. - self:text(DAYS[weekday] or "", 6, 6) + self:text(Clock.weekdayName(weekday) or "", 6, 6) local display = hour % 12 if display == 0 then display = 12 end self:text(Chrome.number(display, 2), 6, 8) @@ -2203,13 +2199,13 @@ function Pokegear:drawPlain() if id == "clock" then local hour, minute, weekday = self:clockParts() Chrome.box(1, 5, 18, 7) - Chrome.print(DAYS[weekday] or "DAY", 3, 7) + Chrome.print(Clock.weekdayName(weekday) or "DAY", 3, 7) local display = hour % 12 if display == 0 then display = 12 end Chrome.print(("%s:%s %s"):format( Chrome.number(display, 2), Chrome.number(minute, 2, true), hour < 12 and "AM" or "PM"), 5, 9) - Chrome.print(Palettes.clockDaytime(hour), 5, 11) + Chrome.print(Clock.daytimeLabel(hour), 5, 11) elseif id == "radio" then -- Without the gear sheet there is no dial art, so the frequencies go down -- the screen as a list. A frequency whose test failed still gets a row: diff --git a/tests/gen2_clock_test.lua b/tests/gen2_clock_test.lua index 91848816..3d82d007 100644 --- a/tests/gen2_clock_test.lua +++ b/tests/gen2_clock_test.lua @@ -18,6 +18,7 @@ require("src.core.Logger").warn = function() end local Clock = require("src.core.gen2.Clock") local InitClock = require("src.ui.gen2.InitClock") +local Strings = require("src.core.Strings") -- A stub input the screen drives off, the same shape Input:wasPressed has. local function fakeInput() @@ -254,4 +255,66 @@ do end end +-- Clock.DAY_NAMES / Clock.weekdayName / Clock.daytimeLabel: the single home +-- InitClock, MainMenu and the Pokegear clock card all share, so a weekday +-- cannot be named one way on one screen and another way on the next. +do + eq(Clock.weekdayName(1), "SUNDAY", "1-based, SUNDAY first") + eq(Clock.weekdayName(6), "FRIDAY", "and the rest in wCurDay's order") + check(Clock.weekdayName(0) == nil, "day 0 is out of range") + check(Clock.weekdayName(8) == nil, "and so is day 8") + + eq(Clock.daytimeLabel(4), "MORN", "daytimeLabel matches clockDaytime's word") + eq(Clock.daytimeLabel(10), "DAY", "for every hour band") + eq(Clock.daytimeLabel(20), "NITE", "including the wrap back to NITE") + + local MainMenu = require("src.ui.gen2.MainMenu") + check(MainMenu.DAYS == Clock.DAY_NAMES, + "MainMenu reuses the same table InitClock and the Pokegear do") +end + +-- ------------------------------------------------- a translation mod's turn +-- +-- DAYS, the clockDaytime word and the "o'clock"/"min." suffixes used to +-- bypass Strings entirely, so a translation mod's `strings` registry had no +-- seam to catch them: the picker kept printing the English day name and +-- "o'clock" no matter the catalog (reported from a real Gold build). +do + Strings.load({ + strings = { + SUNDAY = "DIMANCHE", + MORN = "MATIN", + ["%s o'clock"] = "%s heures", + ["%d min."] = "%d min", + }, + }) + + local wheel = InitClock.new({ input = fakeInput() }, { mode = "day", save = {} }) + eq(wheel:display(), "DIMANCHE", "a translated catalog reaches the day wheel") + + eq(InitClock.hourString(4), "MATIN 4", + "and the clockDaytime word, through Clock.daytimeLabel") + eq(InitClock.oclockString(4), "MATIN 4 heures", + "and the o'clock suffix, template and all") + + local minutePicker = InitClock.new({ input = fakeInput() }, { save = {} }) + minutePicker.phase = "minute" + minutePicker.minute = 30 + eq(minutePicker:display(), "30 min", "and the minutes picker's own suffix") + + -- Palettes.clockDaytime itself must stay untranslated even with a catalog + -- loaded: FORCED_DAYTIME and the rest of Palettes.lua's own lookups + -- compare against its return value as an internal key, not display text. + local Palettes = require("src.world.gen2.Palettes") + eq(Palettes.clockDaytime(4), "MORN", + "the internal palette key is untouched by the loaded catalog") + + -- Module state is process-global and tests/run_tests.lua runs every suite + -- in one process (see tests/mod_strings_tests.lua's own note): leaving the + -- catalog loaded would translate the day/hour of every suite after this + -- one. + Strings.load({}) + check(not Strings.active(), "the catalog is unloaded for the suites after this one") +end + S.finish()