Internationalization (i18n)
Relevant source files
The following files were used as context for generating this wiki page:- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/messages/Messages.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/messages/Languages.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java
- README.md
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v0_3_X_Changes.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v0_6_X_Changes.java
The internationalization (i18n) system in Shattered Pixel Dungeon is responsible for providing multi-language support for all in-game text. It is built upon the libGDX I18NBundle but is abstracted through a custom Messages wrapper class. This wrapper simplifies text retrieval by using a structured keying system based on class names and provides several locale-aware string utility functions.
The system was first introduced in version 0.3.4 and relies on a community-driven translation project hosted on Transifex to provide localization for numerous languages. The changelogs frequently mention "Updated Translations", reflecting the ongoing effort to keep the game accessible to a global audience.
Sources: messages/Messages.java, README.md:21, ui/changelist/v0_3_X_Changes.java:101-118
Core Architecture
The i18n system is primarily composed of two key components: the Languages enum, which defines all supported languages, and the Messages class, which manages the loading and retrieval of localized strings.
Sources: messages/Messages.java, messages/Languages.java
The Languages Enum
The Languages enum serves as a manifest of all languages supported by the game. Each enum entry contains metadata for a specific language.
code: The standard language code (e.g., "en", "fr", "ko").name: The native name of the language (e.g., "English", "Français", "한국어").completeness: A value indicating the percentage of translation completion.rtl: A boolean flag indicating if the language is read right-to-left.
This enum provides a type-safe and centralized way to manage and reference languages throughout the application.
Sources: messages/Languages.java:23-28
The Messages Class
The Messages class is a static utility class that acts as a simple wrapper around libGDX's I18NBundle. It is the central point for all text retrieval in the game.
Key responsibilities include:
- Initializing the i18n system with a selected language.
- Loading all necessary
.propertiesfiles. - Providing static methods to retrieve and format localized strings.
- Offering locale-aware string manipulation utilities.
The class maintains the currently selected language and locale, which are used for all subsequent text operations.
The following diagram illustrates the relationship between the main components of the i1e8n system.
Sources: messages/Messages.java:31-48
Initialization and Configuration
The i18n system is initialized by the Messages.setup() method, which configures the locale and loads the appropriate resource bundles based on the selected language.
System Setup
The setup(Languages lang) method is the entry point for configuring the localization system.
- It receives a
Languagesenum member. - It sets the static
langandlocalefields. For English,Locale.ROOTis used for the bundle to load the base.propertiesfiles. For other languages, a newLocaleis created from the language code. - It clears a cache of
DecimalFormatinstances. - It iterates through a predefined list of property file paths (from
Assets.java) and creates anI18NBundlefor each, which are stored in a list.
The following diagram shows the initialization flow.
Sources: messages/Messages.java:76-101
Property Files
All localizable strings are stored in .properties files, organized into categories. The paths to these files are defined in the Assets.Messages inner class.
| Category | File Path |
|---|---|
ACTORS | messages/actors/actors |
ITEMS | messages/items/items |
JOURNAL | messages/journal/journal |
LEVELS | messages/levels/levels |
MISC | messages/misc/misc |
PLANTS | messages/plants/plants |
SCENES | messages/scenes/scenes |
UI | messages/ui/ui |
WINDOWS | messages/windows/windows |
For each category, libGDX loads the base file (e.g., actors.properties) and, if a non-English language is selected, the corresponding locale-specific file (e.g., actors_fr.properties).
Sources: Assets.java:101-111, messages/Messages.java:64-74
Text Retrieval
The Messages.get() methods provide a structured way to retrieve strings. The system uses a key generation convention and a fallback mechanism to enhance code organization and reuse.
Key Generation
The primary retrieval method is get(Class c, String k, Object... args). It constructs a string key by combining the class name and a local key.
- The key is built as:
c.getName().replace("com.shatteredpixel.shatteredpixeldungeon.", "") + "." + k. - The resulting key is converted to lowercase before being looked up in the bundles.
For example, a call from ChangesScene.class with the local key "new" would generate the lookup key scenes.changesscene.new.
Sources: messages/Messages.java:117-124
Retrieval Flow
The retrieval logic includes a fallback mechanism that allows child classes to inherit strings from their parent classes.
- A key is generated from the provided
Classand local keyString. - The system iterates through the list of loaded
I18NBundles to find a value for the key. - If a value is found, it is formatted with any provided arguments and returned.
- If the key is not found in any bundle, the system recursively calls
get()with the superclass of the original class. - If the key is still not found after reaching the top of the class hierarchy, the constant
!!!NO TEXT FOUND!!!is returned.
This flow is illustrated in the diagram below.
Sources: messages/Messagesjava:115-135
String Utilities
The Messages class provides several static methods for locale-aware string manipulation. These ensure that formatting, capitalization, and case conversions respect the conventions of the currently selected language.
| Method | Description |
|---|---|
format(String, Object...) | Formats a string using String.format() with the current Locale. |
decimalFormat(String, double) | Formats a number using DecimalFormat with the current Locale. Caches formatters for performance. |
capitalize(String) | Capitalizes the first character of a string. |
titleCase(String) | Applies title case. For English, it capitalizes most words but skips a predefined list of small words (a, of, the, etc.). For other languages, it defaults to sentence case (capitalizing only the first word). |
upperCase(String) | Converts a string to uppercase using the current Locale. |
lowerCase(String) | Converts a string to lowercase using the current Locale. |
Sources: messages/Messages.java:152-205
Community and History
Shattered Pixel Dungeon's localization is a community effort. The README.md file states that the game has a translation project hosted on Transifex, where volunteers contribute translations.
Support for multiple languages was officially added in version 0.3.4, which introduced the core translation system. Since then, changelogs for most versions include a note about "Updated Translations", indicating continuous community contributions.
Sources: README.md:21, ui/changelist/v0_3_X_Changes.java:101-118, ui/changelist/v0_6_X_Changes.java:189
Conclusion
Shattered Pixel Dungeon's internationalization system is a robust and developer-friendly framework. By wrapping libGDX's I18NBundle, it provides a simplified API with a clever, class-based keying system that supports inheritance. The inclusion of locale-aware utility methods ensures consistent text handling across different languages. The system's success is heavily reliant on its active community of translators, making the game accessible to a wide international audience.