Files
gen1recomp/mods/spanish_ui/TRANSLATING.md
T
hernan 83f93c27a1 mods: a Spanish translation of the app's own text
A LANGUAGE-profile mod filling the `strings` registry -- the seam #791 opened
up, used for the thing it was opened for. 566 keys: the launcher, OPTIONS,
the save-slot and profile screens, the mod manager, the naming screen, and
the battle menu.

WHAT IT DOES NOT TOUCH is the cartridge. Dialogue, species, items, moves and
places all come out of the player's ROM and stay exactly as they are, so an
English cartridge is still an English adventure with Spanish menus around
it. The lang/ tables for those ship empty on purpose rather than absent:
they are where a full translation would go, and an empty value falls through
to English, so anyone continuing this can fill one row at a time and the
game stays playable throughout.

THE FONT IS THE CONSTRAINT, and it decided the wording. The 8x8 charmap has
no N-tilde, no accented vowels and no inverted punctuation -- the sole
exception in the whole atlas is the small e-acute of POKeMON. So every value
on an 8x8 surface is plain A-Z: DISENO COMBATE, MESETA ANIL, SEGURO? OTRA
VEZ. Not a spelling preference; a glyph that is missing renders as a hole,
which is how the first cut of this shipped "ESPA OL" to a phone. The
launcher draws with a real font and keeps proper Spanish, inverted marks and
all -- the split is by surface, not by taste.

Adding the glyphs to the atlas would let the 8x8 side read properly too, and
lang/font.lua and lang/charmap.lua are already the place that would hook
into. I have not done it here: it is a separate change with its own taste
questions, and it should not ride in on a catalog.

Tested end to end on iOS and macOS.
2026-08-07 22:16:06 -04:00

3.9 KiB

Translating into Espanol

Everything the player can read is one of two kinds of string, and they live in different places for a reason.

lang/ file What it is Key
dialogue.lua Every line of extracted script text the original label, e.g. _PalletTownText1
strings.lua Text the engine itself writes: battle messages, menus, link play the English source string
species.lua moves.lua items.lua trainers.lua Names the vanilla id
statuses.lua PSN, BRN, ... as they appear in the HUD the status id
font.lua charmap.lua Your glyph sheet and what draws what see below
naming.lua The letter grid for entering names -

Fill in a value and it takes effect. Leave it "" and that string stays in English, so the game is playable at every point along the way.

Where the English is

The catalogs hold keys and your text, never the original English. The English lives next door, in spanish_ui-worksheet/, one tab-separated file per catalog:

"_AbandonLearningText"	"Abandon learning\n{RAM:wStringBuffer}?"

That directory is deliberately outside the mod. Extracted script text and the vanilla names are ROM content, and modkit pack zips everything under the mod directory, so a worksheet kept inside would end up in your release whatever a .gitignore said. Keep it beside the mod, never in it.

lang/strings.lua is the exception: those sources are the engine's own Lua rather than anything out of the ROM, so there the key is the English and you can translate straight from it.

Start with the font, not the text

The engine draws from glyph pages: an image of 8x8 cells plus a charmap saying which byte sequence draws which cell. The vanilla pages sit at $60 and $80. Anything from 0x100 up is free, so a new alphabet is added rather than swapped in:

-- lang/font.lua
return {
  spanish_ui = {
    image = "assets/font/spanish_ui.png",
    base = 0x100,        -- first code this page owns
    glyphsPerRow = 16,
    -- advance = 8,      -- set this if your glyphs are not 8px wide
  },
}
-- lang/charmap.lua: sequence -> code, in the same order as the sheet
return {
  ["A"] = 0x100,
  ["B"] = 0x101,
}

The sheet is a plain PNG, 16 glyphs to a row by default, each cell 8x8, black on white like assets/generated/font.png. Codes run left to right, top to bottom from base.

Sequences are matched longest first, so a multi-byte character and a multi-character ligature both work and neither shadows the other:

["\u{3042}"] = 0x120,   -- one 3-byte character, one glyph
["ch"] = 0x121,          -- two ASCII letters, one glyph

Line length is counted in glyphs

The dialogue box fits 18 glyphs a line, not 18 bytes. A 3-byte character costs one column, and the engine will never cut a character in half. Your own \n line breaks are respected exactly as written, so break lines where they read best rather than where they fit English.

If your glyphs are not 8px wide, set advance on the page and the box re-measures.

Format directives must survive

Some sources carry %s or %d:

["Wild %s\nappeared!"] = "...",

Keep every directive, in a count that matches. Word order is yours to change; the engine substitutes in the order the directives appear, so if your language needs the name last, write the sentence with the %s last. A translation whose directive count does not match the English is refused at runtime and the English is drawn instead, with a line in the log saying so - it will not crash a battle.

Checking your work

python3 tools/modkit.py validate spanish_ui --base imported
python3 tools/modkit.py translation spanish_ui --refresh   # pick up new engine strings
POKEPORT_DEV=1 scripts/run.sh                          # F5 hot-reloads lang/

--refresh rewrites the catalogs from the current engine, keeping every translation you have already written and reporting what changed. Run it after pulling a new engine version.