Localisation
THUG speaks English, and its fonts only know 26 letters. Options › Language now switches the whole game to Ukrainian: menus, hints, goals, the story. The scripts weren't touched, and the missing letters were drawn into the retail fonts in each font's own style. Слава скейтбордингу.


1One menu, two languages
To switch: main menu › Options (Налаштування in Ukrainian) › Language (Мова), right under Gamepad. Pick a language and press Enter. That's it. No restart, no reload: the check mark jumps, the menu is rebuilt in the new language, so you watch "МОВА" turn into "LANGUAGE".



The choice goes straight into config.ini, so the next launch starts in the same language:
The menu is a script patch, two new script functions do the work:
This is not the retail Config::GetLanguage. That one picks which data the game loads. Ours only picks which words you read.
2Translate at the last possible moment
Thousands of strings live in hundreds of compiled .q scripts. Editing them all would be a fork, not a
translation. So the scripts keep their English, and the text is swapped where it reaches the screen: the
text of text elements and text blocks, plus the format string and string parameters of
FormatText.
Lang::Translate is one hash lookup. English in, Ukrainian out. No match, or the language is English? The
text comes back untouched, so a missing line shows up in English instead of as an empty box.
What stays in English, on purpose: trick and gap names (a Kickflip is a Kickflip in Kyiv too), people and brands, credits, legal text, key names, old console network settings, and the HUD and title graphics, which are pictures, not text.

dialog font.
Every screen here is the real game, captured frame by frame. No Photoshop, just a font that learned a new alphabet.
3The translation files
Plain UTF-8 text in Lang/uk/, split by area (menus, create-a-skater, levels, story goals, ...). Pairs of
lines: the English exactly as the script has it, then the Ukrainian. # starts a comment.
The build glues the folder into one file, Game/Data/lang/uk.txt, which the game reads the first time it
needs a translation. The log says how it went: Lang: N translations in lang/uk.txt, with N at about four thousand.
"Exactly as the script has it" means exactly: the escapes, the button tags like \\b3, the case, and yes, the two trailing spaces. Eric would not get his "Як воно" otherwise.
4A font with no Cyrillic, fixed with geometry
The retail fonts are bitmaps with a palette: Latin letters, digits, a few symbols. No Ж, no Ї, nothing. Swapping
in a different font would look like a fan patch, so Lang/tools/make_cyrillic_fonts.py builds the
letters out of each font's own Latin ones:
- Lookalikes are free. А В Е К М Н О Р С Т Х І simply point at the Latin glyph. 12 capitals for the price of zero.
- The rest are built from parts. И is a mirrored N, Я a mirrored R, Б is the top of E over the bowl of B, Ї is I with the font's own dots. Strokes, bars and counters are measured on the Latin letters, so Ж and Щ get the right weight.
- Then painted in the font's style. The outline, shading, shadow and slant are learned from the Latin glyphs and applied to the new shape, in the font's own palette.

small font.66 entries per font: 21 capitals drawn, and in dialog and newtrickfont, which have small
letters, another 24 small ones. The italic testtitle gets its new letters sheared by the same 0.32 slant.
Standard library only: no Pillow, no FreeType, just struct, zlib and stubbornness.
Yes, Ф is a pixel-art circle with a stick through it. It was harder than the kickflip.
5Two maps per font, one memcpy to switch
The new letters ship as small .cyr files next to the fonts. When a font loads, chars.cpp
adds the drawn glyphs to the font's texture and builds a second character map. Switching the language just copies the
right map in:
The text is still one byte per letter, so the UTF-8 translation is turned into the fonts' codes when it's loaded. А–я sit at their Windows-1251 codes. Ґ Є І Ї go to 0x81–0x89, because their proper 1251 codes are where the game draws Latin-1 symbols for the special trick combos, and nobody wants a Ї in the middle of their button combo.
| Letters | Code in the font | Why |
|---|---|---|
| А–Я, а–я | 0xC0–0xFF | Windows-1251, as you'd expect. |
| Ґ ґ Є є І і Ї ї | 0x81, 0x83–0x89 | Free codes; the 1251 ones are taken by trick-combo symbols. |
| ‘ ’ – — … | ' - ... | Folded to ASCII. The fonts never heard of typography. |
| anything else | ? | So you can spot it. |
6The developer flow
Fix or add a line. Find the English in the scripts, copy it byte for byte into the right file, write the Ukrainian under it, build, run.
Still English on screen? Usually one of these:
- The key doesn't match: a different case (
"DIFFICULTY"and"Difficulty"are two keys), a missing trailing space,\'written as'. - The text is built by the code (typed names, trick names, scores), not handed over by a script. That's not looked up, on purpose.
- It's
FormatTextwithChecksumName: that's an id, not text, and it's left alone.
A ? on screen means a character the fonts don't have. Use the plain apostrophe and hyphen, or teach the tool a new letter.
Remake the letters (after changing the tool), with a preview PNG per font to eyeball:
Another language? Add it to ELanguage and the name and file tables in p_language.cpp,
a Lang/<code>/ folder and its join rule in CMakeLists.txt, and a check item in the
Language menu. If it needs letters the fonts don't have, it also needs its own glyphs and code mapping (the current
one is Cyrillic only).
"Sick" became "Жесть". Literally "tin". In skater, "brutal". Some things only translate sideways.
7Where it lives
| File | What |
|---|---|
Wn32/Code/Plat/Sys/Lang/p_language.cpp | [Language] in config.ini, loading the table, UTF-8 to font codes, Translate. |
Code/Gfx/2D/TextElement.cpp, Code/Sk/Scripting/cfuncs.cpp | Where script text is translated: text elements, text blocks, FormatText. Plus GetTextLanguage / SetTextLanguage. |
Wn32/Code/Plat/Gfx/nx/chars.cpp | Loads .cyr, adds the glyphs to the font texture, keeps the Latin and Cyrillic maps. |
Lang/uk/*.txt | The translations, joined into Game/Data/lang/uk.txt by Lang/tools/concat.cmake. |
Lang/tools/make_cyrillic_fonts.py, Lang/fonts/*.cyr | The letter builder and the letters it made. |
Scripts/patches/levels/mainmenu/mainmenu_scripts.q | Options › Language. |
It's on the localisation branch (c8fa503). Find a line still in English? It's two lines of text away
from fixed.

