How to Translate a Game 3/3: Gamemaker Studio 2 Example

This is part 3 of my article series about translating video games. Part 1 gave you a high level overview of the process, and things to consider when translating a game. Part 2 talked about splitting up the content and handing it back and forth, plus tools for getting it done.

In this final act I talk implementing it all, using a Gamemaker Studio 2 project as an example (download link below). Note however, that using this approach can be done with any engine. With a few changes, you could adapt a similar solution using XML-files with C#, instead of ini-files and GML.

Open the example project to get a better idea of how all the elements fit together. Note that the free version of Gamemaker Studio 2 does not support included files. For the record, yours truly has no official affiliation with YoYo Games or Gamemaker. I use Gamemaker in this article, because that is the engine I used for Torgar’s Quest. As a final disclaimer, while these scripts are all fairly simple, I do not explain any basic concepts like if/else-statements.


DOWNLOAD EXAMPLE PROJECT FILE: LocTut.zip – You will need to unzip it, before you can open it in Gamemaker Studio.

Setting Up Project and Assets

Your text assets should be correctly formatted files, added and organized by language for easy navigation. A main folder with a subfolder for each language is a good starting point, giving you a path like: text_assets/en/strings.ini

If you want to generate a set of ini-files that go with the example project, you can use the spreadsheet provided in part 2. It already contains the needed data and a macro that spits out an ini-file for both languages in that project.

When abbreviating a language for reference, use its actual ISO code. That way everyone knows what you mean, or can at least google it. Find a list of codes here: https://en.wikipedia.org/wiki/ISO_639-1

Next, make sure you have imported all relevant special characters for each language. From umlauts to caron characters, fonts are not always imported with these by default, or may not even include them at all. The reasoning is that fonts take up memory, so any unneeded character that is excluded equals memory saved and performance gained. This especially true with alphabets containing many characters, such as Chinese.

Identify exactly which special characters are needed for your translations, and add them to the game. For Torgar’s Quest, I asked each translator to provide a list of special characters (since they know their language better than me), and trusted that they did not miss one. And when it happened anyway, it was still caught in QA and fixed in a couple of minutes.

If a font used in the project does not include the characters you need, you may have to use a different font altogether. At that point you will have to decide whether to change that font game-wide or just for this one language. Game-wide changes can affect the overall look and feel of the game, and language specific changes can result in a mess of exceptions, as different languages have their own issues. This is a common example of a translation related problem that appears late in the development or QA phase of a project, and may require last minute design compromises.

Implementation in Gamemaker Studio

Match the folder structure in your project with the one on your drive to avoid unnecessary confusion. Little consistencies like that make a big difference in keeping things organized as your project scales.

When the game launches, it loads the default settings. In our example, the default is English. Next, the strings are loaded into a ds_map called global.text (if you are unfamiliar with GML, a ds_map is the equivalent of a Dictionary/Hashmap in other languages). Since I only have a small amount of data, I just add it directly. If you don’t have a ton of text, this is fine. If you have a lot of data, you may want to make a loop of some kind instead.

This script is only executed on launch.

GML Script:
// default language
global.language = "en";

// Initial setup of map to hold the strings
global.text = ds_map_create();

// Open the ini-file matching the language
ini_open(working_directory+"\\text_assets\\"+global.language+"\\strings.ini");

// Copy data from the ini to the map.
ds_map_add(global.text,"MENU_BUTTON_SAVE",ini_read_string("menu","MENU_BUTTON_SAVE","MENU_BUTTON_SAVE"));

ini_close();

Normally, I would put this code in a persistent controller object, but for the sake of simplicity, in the example project the button itself runs the code to set things up as well as switching the language, which comes next.

The current language reference code is stored in a simple, global string. To change the language, we call a script called s_setLoc() and provide the language code, we want to switch to, as an argument.

Any time you want to change the language, run this script with the target language as the parameter, for example to change the language to Danish, type:
s_setLoc(“da”);

GML Script for s_setLoc:
/// Sets the active language.
global.language = argument[0];

// Opens the ini file matching the language.
ini_open(working_directory+"\\text_assets\\"+global.language+"\\strings.ini");

// Replace the current string with the same one from the new language
ds_map_replace(global.text,"MENU_BUTTON_SAVE",ini_read_string("menu","MENU_BUTTON_SAVE","MENU_BUTTON_SAVE"));

ini_close();

As you can see, changing the language is very similar to the initial setup.

The strings are loaded into memory to avoid opening the ini-file every time a string is displayed. Continual loading of a file would slow down your game’s performance on lower end systems, and it’s just not a good approach. Loading from memory is faster and more efficient. If you have tons of text, you may have to expand on this to support several sources instead of just one ini-file per language, and then only load what is needed for the section of the game that is running.

Once the language is set and the assets are loaded, you call another script to show the specific string. That script takes the string ID as its parameter, then matches the ID with the keys of the string map in memory, and spits out the matching value.

This script doesn’t care what your language setting is, it strictly matches an ID with whatever is in that slot in the map. If there is no translation for a string at all, or the ID was mistyped, the ID itself will be displayed in-game. This helps with debugging, making it very easy to see, what still needs to be translated.

Call this script from anywhere in your code to fetch a string. Following the example project, to display the button text, the script is called like this:
s_print("MENU_BUTTON_SAVE")

GML Script for s_print:
/// Fetches string based on language setting and resource ID
myString = argument[0]; // Resource ID requested

// If the string does not exist, return the ID as a string.
// Otherwise return the string value matching the ID.
if (global.text[? myString] == undefined) {
return myString;
} else {
return global.text[? myString];
}

Troubleshooting

If you are seeing unexpected results, check that…

  • You are using the most current assets.
  • Are you using the right version of Gamemaker Studio?
  • Your ini-files are utf-8 formatted, which is what Gamemaker expects. You can check this (and convert if necessary) from most text editors.
  • You have included all necessary special characters in your font set.

Final Words

Translation is so much more than switching one language out with another, both in terms of content considerations and technical challenges. I hope these three articles have helped shed some light on what is actually involved, what most of the dangers are, and how some of them can be averted. I don’t claim to have all the answers, in part because I believe every project is unique and will come with its own set of challenges.

I guess you can boil it down to this: successful translation of a video game is the sum of good source material, careful scope consideration and properly equipped translators, held together by a streamlined workflow. It may be rare to see those factors all come together perfectly, but aiming for the best is always a good starting point.

If I missed anything, please do share it, drop a comment or reach out to me on twitter (@theprint).

How to Translate a Game 1/3 : The Process

Translating a video game sounds simple enough. There are some words, you replace them with other words, and you have a translated game, right?

This high level overview covers the basic requirements for translating any videogame. Using my own game as an example, I will cover what it takes to get started, how to prepare, prioritize, and how to implement translations. This is the first in a 3-part series aimed at small and medium sized games, and while every detail may not apply to your project, you will still find useful information here, to help get your next game translated.

Early on in the development of my tiny roguelike, Torgar’s Quest, I knew it would be translated into several languages. I knew, because I was lucky enough to work with people from all over the world, several of whom had already asked if they could translate it. In other words, I got lucky and had awesome co-workers. If you need help finding translators for your game, I recommend using social media, reddit, etc. to get fans on board – that is, if hiring a professional service is not in your budget.

There is nothing wrong with crowdsourcing your translations – for small teams this might be the best approach, as it lessens the cost while also has potential to help build an audience in the process. But if you’re a studio with a medium sized or larger project, I do recommend using a professional service, just because they provide more than just translations – they typically have tools and experience from working on similar projects, and can help you avoid common mistakes. None of which you are guaranteed to get with crowdsourced work.

Since the game was published, I have received some feedback from fans who were happy it was available in their language. Furthermore, Torgar’s Quest sales, however pitiful the may be overall, do show better performance in the markets the game was localized for. That’s what it’s all about!

Define the scope

Whether your game supports 2 languages or 20, the technical setup will be more or less the same. You will need to separate out all strings from your source code, and load those using ID-references to match the correct assets, and finally display that depending on the user’s language settings. There are UI design challenges involved with mixing left-to-right and right-to-left text, as well as other language specific issues to be aware of, so the sooner you know which languages are to be supported, the faster you can accommodate any such specifics.

On Torgar: I limited the translations to left-to-right, Latin based alphabets, to make my own life easier from a design POV. I focused on the traditional main languages: French, Italian, German and Spanish (FIGS), with Danish thrown in since it’s my native language, and I could do it myself. I did have an offer to add Russian, but did not have sufficient time to implement and test the required extra fonts, so I chose to exclude it at launch.

Familiarization and Workflow

Once the content is separated out, translators need access to the source material as well as any relevant design documents, concept artwork, screenshots and test builds you can provide. This helps them build a glossary, and provides context for the content they are translating. Practical workflows for handing assets back and forth must also be established and communicated. I also recommend providing a way for translators to communicate with each other, as well as someone from the design/production team. This helps clarify terminology and avoid contextual misunderstandings.

On Torgar: The text was delivered in Excel format (more on that in part 2), translators had access to test builds, and we used email and a Facebook group to communicate. Next time, I would probably use a Slack board, Confluence and a CAT tool of some kind.

Editing and Quality Assurance

It is important to budget enough time for the translators to not only do the work, but also iterate on it, just like a designer iterates on artwork. This should be done in conjunction with localization QA, where most issues are uncovered. If you can, always use fresh eyes to perform QA on translations in-game. In a perfect world, you will have 2 translators per language (so they can proof read each other), and as many QA testers. For most games however, this is not an option and compromises must be made.

On Torgar: I did not have the luxury of having separate QA testers, so the translators did most of it themselves. In a couple of cases, I happened to have access to additional interested parties, and got some extra QA this way. Handling each language on an individual basis like that is yet another way things can get messy. Knowing it would go down like this, I gave the translators plenty of time to test their work. On bigger projects where you pay someone to do the work, there are other messes to worry about, but the progress is faster and more consistent. I had to rely on donated time, and people willing to work for a game key and credit, so I took what I could get and made the most of it.

Final Testing and Triage

Once the game is fully translated, a full final test pass should be run in every supported language. Sometimes, getting full coverage can be challenging due to release schedules and marketing commitments. In those cases, you will need to prioritize what to cover. However, ignore this phase entirely at your own peril! It almost always happens, that something breaks and will need to be fixed.

A typical scenario might go something like: Two weeks before launch, a UI change to the mini-map means there is now less room for the planned subtitles. These will now need to be retimed to fit a smaller space, as rescaling the fonts make the subtitles illegible. That means inserting new time codes where it makes sense linguistically – a job for the translators, which then has to be verified in-game.

When triaging issues I recommend this 20/80 approach: focus on the 20% of the content users will see 80% of the time. Typically, this starts with UI elements in-game and main menus. Work on those strings this sprint, then repeat the evaluation next sprint, defining the most important 20% of the remaining content, and focusing on that. Repeat the cycle until you run out of time, and you will get the most coverage where it really matters. Got time to cover the top 20% more than once? Perfect!

On Torgar: There wasn’t much time for final testing, and since translators would mostly do their own QA, it was tempting to rationalize the entire phase away as a waste of time. Nevertheless, several issues were found, including missing special characters and a couple of truncated strings.

Coming soon
Part 2 is about splitting and setting up the content, deciding on a way to implement the strings, and then building the Excel spreadsheet that would become the backbone tool of the process.
Part 3 is a guide to implementing a similar approach using Gamemaker Studio 2, including an example project.

Game in a Day: Procformer Infinite

Procformer Infinite
I like to set challenges for myself. Self-imposed, often timed challenges is a great way to learn new things, or experiment with different ideas. I find that it’s a great way to learn new concepts or test theories you might have; set yourself a challenge, and try to overcome it.

So, on a lazy Sunday, instead of playing video games, I challenged myself to make a platform game myself. Right away, I knew I wanted it to have an infinite number of procedurally generated levels, so you could never run out of new challenges. To make it more difficult for myself, I was not allowed to use any third party artwork or sound, everything had to be made for this challenge (no using scraps from the personal archives), and to top it off, I only allowed myself one day to complete it.That was pretty much my entire Sunday, but worth every second of it.

The screenshot is from the resulting game – Procformer Infinite – which you can play yourself, right here!

Challenge completed. Next! Perhaps improving or expanding the game with more features and obstacles? You never know what might happen on any given Sunday.