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