Add i18n text
This guide builds on the mouse guide. The setup guide already installed the CSV file, and we declared the TEXT_* constants back in the composition guide. Here we explain how the code reads that CSV, add a helper to keep the calls short, and replace our last hardcoded string.
Principle
All player-visible text must come from a CSV file -- never hardcode strings in Ruby. The PSDK i18n system picks the column matching the game's current language:
- Each CSV file has a unique numeric identifier (
TEXT_FILE_ID). - Each row maps to an index: the first data row is ID 0, the next is ID 1, and so on.
- Empty cells fall back to the English (
en) value, so an unfinished translation still shows English. - You read a row with
ext_text(file_id, row_index).
The CSV and its constants
The CSV lives at Data/Text/Dialogs/311125.csv (installed in the setup guide). Its filename matches TEXT_FILE_ID = 311_125. Each row maps to a TEXT_* constant from 001 Constants.rb:
| Constant | Row | English text |
|---|---|---|
TEXT_ENTER_CODE | 0 | Enter Code |
TEXT_QUIT | 1 | Quit |
TEXT_TITLE | 2 | Mystery Gift |
TEXT_PROMPT | 3 | Enter your gift code |
TEXT_INVALID | 4 | Invalid code! |
TEXT_ALREADY_CLAIMED | 5 | Gift already claimed! |
TEXT_RECEIVED | 6 | You received %s! |
TEXT_NO_GIFTS | 7 | No gifts claimed yet |
TEXT_CONFIRM | 8 | Claim this gift? |
TEXT_GIFT_RECEIVED | 9 | Gift received! |
TEXT_YES | 10 | Yes |
TEXT_NO | 11 | No |
We already use two of these: the Composition reads ext_text(TEXT_FILE_ID, TEXT_TITLE) for the title and TEXT_NO_GIFTS for the empty message. The rest are used as we build the dialogs.
A helper to shorten the calls
Writing ext_text(TEXT_FILE_ID, id) everywhere is verbose. Add a private helper to the scene. Update scripts/20 MysteryGift/003 GamePlay/001 Main.rb -- add this method (the include UI::MysteryGift at the top of the class makes the TEXT_* constants available):
# Shortcut to access Mystery Gift text
# @param id [Integer] the text row index
# @return [String]
def gift_text(id)
return ext_text(TEXT_FILE_ID, id)
end
gift_text(TEXT_QUIT)is much clearer thanext_text(311_125, 1).- It returns the text already in the game's current language.
The Composition is in the UI::MysteryGift module and calls ext_text directly; the scene uses this gift_text shortcut. Both reach the same CSV.
Localizing the buttons
In the scene guide we hardcoded 'Quit' in button_texts. Replace it with the CSV value. Update button_texts in 001 Main.rb:
# Return the button texts for the ctrl buttons [A, X, Y, B]
# @return [Array<String, nil>]
def button_texts
return [nil, nil, nil, gift_text(TEXT_QUIT)]
end
- The B button now reads its label from the CSV: "Quit" in English, "Quitter" in French.
- The A button stays hidden (
nil) for now. We reveal it -- with itsgift_text(TEXT_ENTER_CODE)label -- in the dialogs guide, at the same time as theaction_ait triggers. (A visible ctrl button calls its action on click, so it must not appear before its action exists.)
Text colors
PSDK uses an indexed color palette:
add_text(0, 0, 200, 18, gift_text(TEXT_TITLE), color: 0) # black
add_text(0, 0, 200, 18, gift_text(TEXT_TITLE), color: 1) # blue
add_text(0, 0, 200, 18, gift_text(TEXT_TITLE), color: 2) # red
add_text(0, 0, 200, 18, gift_text(TEXT_TITLE), color: 3) # green
add_text(0, 0, 200, 18, gift_text(TEXT_TITLE), color: 9) # grey
add_text(0, 0, 200, 18, gift_text(TEXT_TITLE), color: 10) # white
- The
color:parameter is an index into the font palette. Common ones: 0 black, 1 blue, 2 red, 3 green, 9 grey, 10 white.
For an exact RGB color not in the palette, omit color: and assign fill_color/outline_color directly:
title = add_text(0, 0, 200, 18, gift_text(TEXT_TITLE))
title.fill_color = Color.new(0, 255, 136)
title.outline_color = Color.new(0, 85, 45)
- A common trick for the outline is to divide each fill channel by 3: a fill of
(0, 255, 136)pairs with an outline of(0, 85, 45).
Dynamic text with format
When a row contains a format specifier (%s for a string, %d for an integer), Ruby's format fills it in:
# "You received Rare Candy!" / "Vous avez recu Rare Candy !"
message = format(gift_text(TEXT_RECEIVED), gift_name)
gift_text(TEXT_RECEIVED)returns "You received %s!";format(template, gift_name)replaces%s. We use this in the dialogs guide to announce the claimed gift.- The gift name comes from the database, which is not translated here.
Try it
Switch the game to French (or check the B button): the bottom button now reads "Quitter" instead of a hardcoded "Quit", and the title stays localized.
Conclusion
- All player-visible text goes through a CSV identified by
TEXT_FILE_ID; read it withext_text(file_id, row_index). - The
TEXT_*constants (declared in001 Constants.rb) name the CSV rows -- no magic numbers. - Add a
gift_texthelper in the scene to shortenext_textcalls; the Composition usesext_textdirectly. - Never hardcode player-facing strings -- we replaced the last one (
'Quit'). - Use indexed
color:for palette colors, orfill_color/outline_colorfor exact RGB. - Use
formatwith%s/%dfor parameterized text.