Merge pull request #1450 from thibautbus/fix/translate-clock-and-day-of-week

This commit is contained in:
bryanthaboi
2026-08-16 20:43:36 -04:00
committed by GitHub
5 changed files with 132 additions and 21 deletions
+43
View File
@@ -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
+17 -9
View File
@@ -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
+6 -5
View File
@@ -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
+3 -7
View File
@@ -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:
+63
View File
@@ -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()