Gamasutra is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Gamasutra: The Art & Business of Making Gamesspacer
Localizing MMOGs
View All     RSS
November 15, 2019
arrowPress Releases
November 15, 2019
Games Press
View All     RSS







If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 

Localizing MMOGs


September 12, 2003 Article Start Page 1 of 3 Next
 

Last Fall, Turbine Entertainment released Asheron's Call 2, a massively-multiplayer online role-playing game (MMORPG) that shipped simultaneously in English, French, and German, with a Korean version following last Spring. Instead of using language-restricted servers, all AC2 servers allow all languages, so players speaking different languages can play together on the same world. I'd like to share some of the things we learned as we made the game "localizable". I'd also like to present a technique that improved grammar quality in all the supported languages (including English).

In many ways, localization is just a catchall phrase for a long list of smaller tasks. For instance, every language has its own keyboard, and the game needs to have reasonable key mappings on any of these keyboards. To allow Korean or Japanese users to type in their native language, you need to integrate support for the Microsoft Input Method Editor (or provide similar Eastern character features). German words tend to be longer than English ones, so German needs 30% additional space for each field in the UI. There are also cultural and legal differences that can cause the content of the game to need variation - green blood is the classic example, although a "very low gore" option is often just as useful these days. Fortunately these issues are relatively well understood - they are essentially the same for any PC game, and a good book on localization will help you overcome these hurdles. The biggest difference between localizing MMORPGs and other games is the number and format of their strings.

Most of the MMORPGs released so far have a lot of strings - far more than a typical game. This is because the number of strings keeps growing for as long as they run - text is a cost-efficient way of adding content after a game ships, and most MMORPGs add new content on a regular basis.

Storing the Strings

Early MMORPGs such as Asheron's Call 1 tend to send strings to the client in the most straightforward way possible: they send the string to the client each time the string is needed. When the player talks to a vendor, the server sends the client a string to be displayed: "Bob says, 'I'll custom fit any purchases for free!'" When the player leaves and returns later, that same string is sent to the client again. The biggest problem with this system is that it uses more bandwidth than is necessary. How many times do you really need to send Bob's greeting string to the player? After the first time, it shouldn't need to be sent again unless it changes.

The approach for using strings in localized single-player games is completely different. In this method, all the strings are placed in a resource file. Translated versions of these strings are made, and the data for every supported language is shipped on the CDs with the game. When the program needs to display a particular string, it looks up the appropriate ID from the resource file, fills in any variables (such as player name), and displays it. This is a great solution for games that don't change much after ship, but if strings are changed post-ship (such as due to a bug-fix patch), the entire resource file must be re-downloaded. Also, because all the strings are contained on the client in a well-organized resource file, it becomes rather easy for hackers to read every string in the game. This isn't an issue with traditional PC games, as they take the stance of "if you cheat and look ahead, you just ruin your own fun," but one of our selling points is monthly updates that add new quests and secrets to the game. Some of these secrets are meant to appear a few weeks after the player has downloaded the monthly update. If we sent all the new strings to the client during the initial monthly download, they would appear on spoiler sites instantly and we'd have no way to surprise players between updates.


Asheron's Call 2 in English.

We took the model used by other types of games and modified it to better fit the requirements of an MMORPG. The most important enhancement is to allow the resource file to be updated on the fly. Each monthly patch can send only the strings that have changed or been added. And not all the new strings have to be sent to the client during the monthly patch; a handful of secret strings can be kept out of the big download. These strings are downloaded only when needed.

All the strings are stored in one file on the client, but that file contains thousands of individual tables. When the server sends strings to the client, it doesn't send them one string at a time; it sends all the strings of a particular table. A typical table contains a half-dozen strings. There is a table for every monster, item, and quest in the game. The idea is that if the client is asking the server for the name of a particular monster, it will soon be asking for the description and other text relating to that monster, so we might as well send them all at once. If any of the strings in that table change, the whole table must be re-sent, but the odds are that if the name of a monster changes, for instance, other strings relating to that monster will also change.

Representing the Strings in Code

Most strings have fill-in-the-blank spots, such as "You take the $ITEM$!", where $ITEM$ needs to be replaced at run-time with the name of the item being taken. (In our system, these variables are surrounded by $ characters.) In a non-networked game, filling in the variables is easy. But our server often needs to manipulate strings without knowing what the variables will be yet. Should the server fill in "$ITEM$" as "Sword" or "Épée"? It can't tell without knowing what language the client is running in, and that could be different for each player. It's easier to just send the IDs of the variables to the client and let the client pull that string from its file. This way most of the server code doesn't care what language each person is running in.

We use a simple structure called a StringInfo to encapsulate our strings and all their variables. They have two integers, the table ID and the string ID, to indicate which string they're referring to. They also contain an embedded StringInfo for each variable. (Alternatively, a StringInfo can simply store a literal string that a user typed in, such as a player name.) Each of the embedded StringInfos contains the IDs for one particular variable in the original StringInfo. This is shown in Example 1.


Example 1. The StringInfo for a message being displayed when an item is picked up. The string in data is "$PLAYER$ picks up the $ITEM$." When filled out, it becomes "Bob the berserker picks up the Sword.

In the most extreme cases, the embedded variables can contain variables themselves - for instance, the "Fiery Sword of Doom" might be the $ITEM$ in our earlier example, but this string is actually a randomly generated name created by filling in a string with the variables "$PRE$ $MID$ $POST$". As is shown in Example 2, $PRE$ becomes "Fiery", $MID$ becomes "Sword" and $POST$ becomes "of Doom." Then the whole StringInfo gets embedded in the first string as the $ITEM$ variable for that string.


Example 2. Here is the StringInfo for a random treasure item; this is the structure that the item serializes, and is what is used when a string needs the name of the item for a variable. The string in data is "$PRE$ $MID$ $POST$"; when the variables are filled in, it becomes "Fiery Sword of Doom."

Since a StringInfo can represent a string from a table and all of that string's variables, or even just a literal string, it is a very convenient storage format. Objects can store their names in a StringInfo without concerning themselves whether the name is from a table or not, or where the variables come from. When the client wants to display a StringInfo, it calls the RenderString() function on the StringInfo. If the string is a literal value, that value is immediately returned; otherwise, the table is fetched, the variables are recursively rendered and inserted, and a literal value is finally returned.


Article Start Page 1 of 3 Next

Related Jobs

Wargaming Sydney
Wargaming Sydney — Sydney, New South Wales, Australia
[11.14.19]

Senior C++ Engineer (Gameplay Programmer)
Wargaming Sydney
Wargaming Sydney — Sydney, New South Wales, Australia
[11.14.19]

Gameplay Programmer, C++ - Vehicle Physics
Wargaming Sydney
Wargaming Sydney — Sydney, New South Wales, Australia
[11.14.19]

Software Engineer (Automation)
Wargaming Sydney
Wargaming Sydney — Sydney, New South Wales, Australia
[11.14.19]

UI Programmer





Loading Comments

loader image