Internationalization (i18n)
Epiphany uses Minecraft's native Component + lang file mechanism for internationalization. Whether you're a datapack author or a mod developer, simply provide translation keys in the appropriate assets/<namespace>/lang/<language>.json and the game will automatically display localized text.
Mechanism: Native Component Support
All Component-typed fields in datapacks (name, description, condition_description, *_reward_description, and UI text) support three JSON writing styles:
| Style | Meaning |
|---|---|
"Warrior" (string) | Plain literal text |
{ "text": "Warrior", "color": "gold" } (object) | Styled literal text |
{ "translate": "mymod.module.combat.name" } (object) | Translation key (looked up in lang files) |
How translation keys work
When JSON is written as {"translate": "key"}, Minecraft automatically looks up the translation for that key on the client:
- Found in
assets/<namespace>/lang/en_us.jsonor other language files → displays the translated text - Not found → displays the raw key string
This mechanism is natively supported by Minecraft; Epiphany does no additional processing. You only need to: ① write {"translate": "key"} in your JSON; ② provide the translation for that key in a lang file.
Epiphany's Default Lang Auto-Fallback
TIP
When a Component field is omitted (not written or set to null), Epiphany automatically constructs a convention-based translation key rather than displaying the raw ID string or leaving it blank.
This means you don't need to write {"translate": ...} in your JSON — just fill in the convention keys in your lang file.
The fallback rule for all four data types:
<type>.<namespace>.<path>.<field>| Data Type | Field | Translation Key |
|---|---|---|
| Module | name | module.<ns>.<path>.name |
| Module | description | module.<ns>.<path>.description |
| Module | condition_description | module.<ns>.<path>.condition_description |
| Module | on_select_reward_description | module.<ns>.<path>.on_select_reward_description |
| Module | on_complete_reward_description | module.<ns>.<path>.on_complete_reward_description |
| Insight | name | insight.<ns>.<path>.name |
| Insight | description | insight.<ns>.<path>.description |
| Insight | reward_description | insight.<ns>.<path>.reward_description |
| Epiphany | name | epiphany.<ns>.<path>.name |
| Epiphany | description | epiphany.<ns>.<path>.description |
| Epiphany | condition_description | epiphany.<ns>.<path>.condition_description |
| Epiphany | reward_description | epiphany.<ns>.<path>.reward_description |
| Path | name | path.<ns>.<path>.name |
| Path | description | path.<ns>.<path>.description |
Where <ns> and <path> come from the registry ID <ns>:<path>. For example:
data/mymod/epiphany/module/class/warrior.json→ registry IDmymod:class/warriornameomitted → fallback key:module.mymod.class/warrior.name
Slashes in subdirectory paths
The path portion of the registry ID retains slashes (/). So a translation key might be module.mymod.class/warrior.name (with a slash). This is valid but not very tidy in a lang file. If you prefer cleaner keys, you have two options:
- Use flat filenames in your datapack (avoid subdirectories)
- Explicitly write
"name": {"translate": "mymod.class.warrior.name"}with dot-separated keys
Three i18n Styles
Style A: Rely on Auto-Fallback (Recommended)
Omit name in JSON; only fill in the lang file:
// data/mymod/epiphany/module/warrior.json
{
"initial_state": "selectable",
"insights": [ ... ]
}// assets/mymod/lang/en_us.json
{
"module.mymod.warrior.name": "Warrior",
"module.mymod.warrior.description": "Veteran of the battlefield"
}Style B: Explicit Translation Keys
Cleaner decoupling between datapack and lang; free-form key naming:
{
"name": { "translate": "mymod.warrior.name" },
"description": { "translate": "mymod.warrior.desc" }
}// assets/mymod/lang/en_us.json
{
"mymod.warrior.name": "Warrior",
"mymod.warrior.desc": "Veteran of the battlefield"
}Style C: Literal Text (No i18n)
Suitable for small datapacks serving a single language:
{
"name": "Warrior",
"description": "Veteran of the battlefield"
}The displayed language is independent of the player's client language and always shows this text.
Lang File Location
assets/<namespace>/lang/<language>.json<namespace>typically matches your datapack or mod namespace<language>follows MC standards:en_us,zh_cn,ja_jp, etc.
KubeJS Perspective
When accessing localized text visible to players from KubeJS scripts, take special care:
let module = Epiphany.getModule('mymod:warrior');
// ❌ Raw Optional (the literal Component from the datapack JSON; may be empty)
let rawName = module.name; // Optional<Component>
// ✅ Display text with full lang fallback
let displayName = module.effectiveName('mymod:warrior').getString();