
Available for free on GitHub!
Introduction #
Localising a game isn’t just about translating text, it’s about managing assets, sound files, UI elements, and cultural nuances in a way that’s efficient, deterministic, and scalable. Traditional localisation systems often rely on fragile string tables or hardcoded references, leading to brittle workflows and runtime overhead.
We built the Lexicon Localisation Gem for Open 3D Engine (O3DE) to solve these problems. Our system decouples logical addresses from runtime values, using xxHash for deterministic lookups and supporting not just text, but any asset type, sound files, textures, prefabs, and more.
What is Lexicon Localisation? #
Lexicon Localisation is a deterministic, asset-driven system that replaces fragile string matching with hashed, high-performance lookups. Here’s how it works:
- Dot-Path Keys: Logical addresses like
"Menu.Play"or"Audio.Music.Theme"are hashed into u64 values using XXH3_64bits (the same algorithm used across our Gem suite). - Cultural Flexibility: Each
.helexfile can support multiple cultures (e.g.,"en-GB","fr-FR","es-419"), with no enforced folder structure. - Asset Agnostic: Supports text strings, sound assets, textures, or any other asset type referenced by UUID.
- Binary Lookups: Runtime lookups are O(log n) binary searches on a sorted hash index, fast and predictable.
Core Concepts #
File Pair System #
Each localisation culture is defined by a pair of files:
| Extension | Role | Contents |
|---|---|---|
.helex | Source | Human-readable JSON, edited by developers and localisation teams. |
.lexicon | Product | Binary LexiconAssemblyAsset, generated by the Asset Processor. |
At runtime, the system loads the active culture (e.g., "fr-FR") and falls back to a default culture (e.g., "en-GB") if a key is missing.
Deterministic Hashing #
Keys are hashed using XXH3_64bits (seed 0) to ensure consistent lookups across platforms. This means:
- The same key always resolves to the same hash.
- No runtime string comparisons, just fast, numeric lookups even if the scripter uses strings in the input.
- Works seamlessly with Script Canvas and Lua.
Support for All Asset Types #
Lexicon Localisation isn’t just for text. It supports:
- Localised strings (e.g.,
"Menu.Play": "Play"). - Sound assets (e.g.,
"Audio.Music.Theme": { "uuid": "{1A2B3C4D-5E6F-7890-ABCD-EF1234567890}" }). - Textures, prefabs, or any asset referenced by UUID.
This makes it ideal for fully localised UI, audio, and even gameplay elements.
The .helex File Format #
.helex files are UTF-8 JSON documents with two top-level fields: cultures and entries.
Schema #
{
"cultures": ["<culture-code>", ...],
"entries": {
"<dot.path.key>": <value>,
...
}
}
Fields #
**cultures**
An array of BCP 47 culture codes (e.g., "en-GB", "fr-FR").
Example:
"cultures": ["en-GB", "en-IE"]
**entries**
A flat object mapping dot-path keys to values. Values can be:
- Strings (for localised text).
- Asset references (for sounds, textures, etc.).
Example:
"entries": {
"Menu.Play": "Play",
"Menu.Settings": "Settings",
"Audio.Music.Theme": { "uuid": "{1A2B3C4D-5E6F-7890-ABCD-EF1234567890}" },
"UI.Logo": { "uuid": "{AABBCCDD-EEFF-0011-2233-445566778899}" }
}
How to Use #
C++ (via EBus) #
#include <FoundationLocalisation/FoundationLocalisationBus.h>
// Load a culture (async)
FoundationLocalisation::FoundationLocalisationRequestBus::Broadcast(
&FoundationLocalisation::FoundationLocalisationRequests::LoadCulture, "en-GB");
// Resolve a string by dot-path (hashes internally)
AZStd::string label;
FoundationLocalisation::FoundationLocalisationRequestBus::BroadcastResult(
label, &FoundationLocalisation::FoundationLocalisationRequests::ResolveString, "Menu.Play");
// Resolve by pre-cached hash (optimised for hot paths)
AZ::u64 hash = xxHash::xxHashFunctions::Hash64("Menu.Play", 0);
FoundationLocalisation::FoundationLocalisationRequestBus::BroadcastResult(
label, &FoundationLocalisation::FoundationLocalisationRequests::ResolveString, hash);
// Resolve an asset UUID
AZ::Uuid assetId;
FoundationLocalisation::FoundationLocalisationRequestBus::BroadcastResult(
assetId, &FoundationLocalisation::FoundationLocalisationRequests::ResolveAssetId, "Audio.Music.Theme");
C++ (via AZ::Interface) #
For lowest overhead:
if (auto* loc = FoundationLocalisation::FoundationLocalisationInterface::Get())
{
AZStd::string label = loc->ResolveString("Menu.Play");
AZ::Uuid soundId = loc->ResolveAssetId("Audio.Music.Theme");
}
Localisation Aware Fields #
Lexicon Localisation provides specialised data types to make localisation seamless in your components:
Heathen::LexiconText #
A localisation-aware string field. Perfect for UI labels, dialogue, or any text.
Example:
#include <FoundationLocalisation/LexiconText.h>
class MyComponent : public AZ::Component
{
Heathen::LexiconText m_buttonLabel; // Serialises into the Inspector
};
Inspector Modes:
| Mode | Behaviour |
|---|---|
| Localised | m_keyOrValue is a dot-path key; resolved at runtime via the bus. |
| Literal | m_keyOrValue is a raw string; no lookup performed. |
| Invariant | Same as Literal; excluded from batch-conversion tools. |
Resolve in Code:
AZStd::string value;
if (m_buttonLabel.IsLocalised())
value = loc->ResolveString(m_buttonLabel.GetHash());
else
value = m_buttonLabel.m_keyOrValue;
Heathen::LexiconSound #
A localisation-aware sound asset reference. Resolves to an AZ::Uuid (asset ID).
Example:
Heathen::LexiconSound m_backgroundMusic;
AZ::Uuid soundId = m_backgroundMusic.IsLocalised()
? loc->ResolveAssetId(m_backgroundMusic.GetHash())
: m_backgroundMusic.m_literalAssetId;
Heathen::LexiconAsset #
A localisation-aware generic asset reference (textures, prefabs, fonts, etc.). Same interface as LexiconSound.
