Unreal Localization Support
Tim Sweeney
Epic MegaGames, Inc.
tim@epicgames.com
http://www.epicgames.com/
Audience: UnrealScript Programmers, C++ Programmers, Translators.
Last Updated: 05/01/99
External Localization Links
Overview of Unreal localization support
The design goals for Unreal's translatability are:
- Make Unreal-technology based games easily translatable, where translations to UNICODE
languages (basically, all worldwide languages that are significant to the PC and consumer
electronics markets) require no changes to source code or binary data files.
- Build localization support into the engine at a fundamental level so that all the
translation work can be done by a translator person without taking programmer or level
designer time.
- Make translations modular, so that translations can be installed after a game has been
purchased.
- Keep translations robust, so that when updates/patches to a game are released, they
don't need retranslated; and if a particular piece of text hasn't been translated, be able
to fall back gracefully on the international english text.
- Make the translation support portable, which means that Windows resources (which are
great for translating pure Windows apps) are problematic.
The approach we chose is to place localized text in .ini style files which correspond
to Unreal package files. Translation capability is available in UnrealScript and C++
in three key areas:
- Native script support: default string properties of actor (and object) classes can be
defined using the "localized" keyword in UnrealScript (or CPF_Localized in C++).
These default properties contain the international english text as specified by the
programmer or level designer. However, text in the current language's .ini files
overrides text in the .u files, so translations can be performed purely by creating a new
.ini file, without modifying any code.
- In C++ and UnrealScript, there are Localize() functions which take an arbitrary key name
and return its corresponding localized text. This is intended mainly for C++ code
where there is no convenient UObject containing default properties in which to place the
translatable string.
- The translation .ini files contain a [LocalizedNames] section which enables mapping
UnrealScript names (C++ FName's) to localized text. This is used in areas of the
engine which are based on FName's internally but must use a localized representation of
those FName's for display and user interaction purposes. For example, the
Preferences windows are based on direct editing of named UnrealScript properties (like
SoundVolume) which must be translated into other languages, and which also may benefit
from being translated into more human-readable English, for example "Sound Volume
Level".
Authoring UnrealScript code for translatability
Put all readable text into string instance variables, and use the "localized"
keyword to designate them as localized, and use the "localized" keyword when
declaring the class. For example:
This code will be a bitch to translate because it will require messing with the code:
class OuchSayer expands Trigger;
function Trigger( Pawn A, Actor B )
{
A.Message( "Ouch, you touched me!" );
}
This code will be easy to translate because it can be done in an .ini file by a
non-programmer:
class OuchSayer expands Trigger localized;
var() localized string[64] Msg;
function Trigger( Pawn A, Actor B )
{
A.Message( Msg );
}
defaultproperties
{
Msg="Ouch, you touched me!"
}
The other advantage of this approach is that it makes it easy for a writer to go
through and clean up the English text in a game. This has been beneficial in Unreal
development, because we have a lot of level designers and programmers writing game text
which needed reworking due to stylistic inconsistencies.
Character set
Unreal is designed to use the 16-bit UNICODE character set. The standard Unreal
fonts include only the first page of UNICODE language characters, but our built-in
TrueType font importer enbales you to import (with optional antialiasing) any
Unicode TrueType font, i.e. for piecing together Unreal fonts that support the roman
languages, Japanese, and Korean.
Localized file extensions
Each language has a characteristic file extension, which Unreal uses to try to find the
localized text for a given package file. For example, we define the following
extensions:
- Filename.int: International English text.
- Filename.fr: French text.
- Filename.de: German text.
- Filename.esp: Spanish text.
- Filename.itt: Italian text.
When Unreal loads a package file (such as an .unr level file, or a .u class file), it
searches for localized text in the following places. For example, when loading
MyLevel.unr:
- If using a language other than English, it looks in that language's localized file, such
as MyLevel.fr for French.
- If that file was not found, it looks in the international English version, MyLevel.int.
- Otherwise, the text stored in the raw package file is used.
Preparing level text for translation
Lots of game text is stored within .unr level files, for example the text messages
stored with Counters, Triggers, and TranslatorEvent actors. The intent is that level
designers will write the first-pass version of this text in English, and then the text
will be localized (or the English version cleaned up) by a translator or writer, who edits
the .ini files and never modifies the .unr level file itself.
Not modifying binary data files (such as .unr level files, and .u class files) is an
important concept, because many aspects of Unreal, including network play, rely on the
exact binary contents of these data files. If translations were performed by having
someone actually modify the .unr levels, or .uc scripts (thus affecting the .u binary
files), it would be impossible for French or German people to play on American Unreal
servers, etc.
UnrealEd supports a special console command analyze an Unreal binary file (such as an
.unr or .u file) and generate an .ini style text file containing the international English
version of the text. For example, to process UnrealI.u, type on the console:
dumpint UnrealI.u
And that generates the file UnrealI.int, the international text for the package.
That file can then be given to translators, who rename it to their appropriate language's
extension (such as UnrealI.fr or UnrealI.de) and translate all of the text within.
Hardcoded C++ translation support
CORE_API const char* Localize( const char* Section, const char* Key, const char* Package=GPackage );
- Looks in the localization file corresponding to Package (i.e. Engine.int for the Engine
package, using international English) and returns the localized string for Key, found in
the Value section. If Package isn't specified, it defaults to the current package
being compiled.
CORE_API const char* LocalizeError( const char* Key, const char* Package=GPackage );
CORE_API const char* LocalizeProgress( const char* Key, const char* Package=GPackage );
CORE_API const char* LocalizeQuery( const char* Key, const char* Package=GPackage );
CORE_API const char* LocalizeGeneral( const char* Key, const char* Package=GPackage );
- These functions work like Localize but they look in a the section corresponding to their
function name instead of taking Section as a string. For example, LocalizeError
looks in the "Error" section.
Hardcoded UnrealScript translation support
intrinsic function string[192] Localize( name KeyName, name SectionName, name PackageName );
- This puppy does the same thing as the C++ Localize function.
Debugging translations
When a C++ or UnrealScript localization function is called for which no corresponding
localized .ini file entry is found, the returned string is displayed as
<?Package.Section.Key?>, and an entry is written out to the log to record the
missing translation. This is a non-critical error. Because this is easy to
screw up, I recommend coverage testing all lines of code which lookup localized text.
Non-technical information for translators
You can edit .int files with a text editor like Notepad. A typical .int file will
contain a lot of data that looks like this:
[Errors]
FileOpen=Error opening file
FileNotFound=Can't find file '%s'
FileClose=Error closing file
[Progress]
Saving=Saving file %s...
Closing=Closing
Bold text indicates the text to be translated. For clarity,
these .int files contain three kinds of data:
- Section headings, such as [Errors] and [Progress]. These are used internally by Unreal. Do
not translate these!
- Key names such as FileOpen= and FileClose=.
These are used internally by Unreal to identify the text. Do not translate
these.
- Translatable text such as Error opening file and Saving file %s.... This text always immediately follows the
"=" sign. Translate this.
So, for example, the result, translated file above might look like:
[Errors]
FileOpen=Fehleröffnung Datei
FileNotFound=Kann nicht Datei %s finden
FileClose=Schließende Datei des Fehlers
[Progress]
Saving=Einsparungdatei %s...
Closing=Schließen
There are several important points to keep in mind:
- Be sure to test all translated text thoroughly in the game to make sure it's complete
and it fits in the space available. Some areas that contain text, such as the menus,
have a limited amount of space and the translated text will overflow if it's too large.
- When you see symbols like %s or %i
in the text, leave them and be sure not to move them around. These characters are
used by Unreal to designate where numbers, and other text appear. For example,
changing "Loading item %i from file %s" to
"Loading file %s, item %i" will cause Unreal to
crash when it displays the text. Unreal typically formats a message like "Loading item %i from file %s" into something like "Loading item 10 from file Unreal.unr"
- The standard Unreal fonts should contain all of the ANSI characters necessary for
translation into standard ANSI languages.
Limitations
- Unreal's text printing support is currently limited to left-to-right. Support for
other orientations, or bidirectional text (i.e. for Arabic or Hebrew) is not provided, but
could be pieced together without too much pain.
End