Skip to content

Localization

The plugin supports multiple languages with full translation coverage.

:::info Version 1.6.0+ Since version 1.6.0, language files are stored externally as JSON files, allowing server operators to customize translations without modifying the JAR. :::

LanguageCodeStatus
Englishen-US✅ Complete
Germande-DE✅ Complete

:::tip Custom Languages Additional languages can be added manually. Simply create a <locale>.json file in the localization folder and set the language code in config.json. :::

Set the language in config.json:

{
"language": "en-US"
}

Language files are located in the plugin’s data folder:

KyuubiAchievements/
└── localization/
├── en-US.json # English (standard)
├── de-DE.json # German (standard)
├── custom_en-US.json # Custom English overrides
├── custom_de-DE.json # Custom German overrides
├── custom_en-US.json.example # Template for custom translations
└── custom_de-DE.json.example # Template for custom translations

:::tip Auto-Extraction On first start, the plugin automatically extracts the standard language files from the JAR. Standard files may be updated during plugin updates to include new translations. :::

:::info Version 1.8.6+ Custom translation files (custom_*.json) are NEVER overwritten by plugin updates. Use these files for your own translations to preserve them across updates. :::

:::tip Custom Languages Any language can be added manually! Simply create a <locale>.json file (e.g., es-ES.json, pt-BR.json, ja-JP.json) in the localization folder and set "language": "<locale>" in config.json. No code changes required! :::

Language files use JSON format:

{
"achievements.ui.gallery": "Achievement Gallery",
"achievements.ui.search": "Search...",
"achievements.name.first_blood": "First Blood",
"achievements.desc.first_blood": "Kill your first enemy"
}
  • Syntax Highlighting - Better editor support
  • Validation - JSON schema validation possible
  • No Escaping Issues - Special characters handled automatically
  • Standard Format - Widely supported and understood
{
"achievements.name.first_blood": "First Blood",
"achievements.name.spider_hunter_1": "Spider Hunter I",
"achievements.name.spider_hunter_2": "Spider Hunter II"
}
{
"achievements.desc.first_blood": "Kill your first enemy",
"achievements.desc.spider_hunter_1": "Kill 1 spider",
"achievements.desc.spider_hunter_2": "Kill 10 spiders"
}
{
"achievements.title.spider_slayer": "Spider Slayer",
"achievements.title.monster_hunter": "Monster Hunter",
"achievements.title.veteran": "Veteran"
}
achievements.ui.gallery=Achievement Gallery
achievements.ui.search=Search...
achievements.ui.all=All
achievements.ui.combat=Combat
achievements.ui.progression=Progression
achievements.ui.exploration=Exploration
achievements.ui.social=Social
achievements.ui.completed=Completed
achievements.ui.locked=Locked
achievements.ui.unlocked=Unlocked
achievements.ui.progress=Progress
achievements.ui.requires=Requires
achievements.ui.reward=Reward
achievements.ui.title=Title
achievements.ui.prev=Previous
achievements.ui.next=Next
achievements.ui.page=Page
achievements.trigger.blocks_mined=Mine {0} blocks
achievements.trigger.blocks_placed=Place {0} blocks
achievements.trigger.kills=Kill {0} {1}
achievements.trigger.items_crafted=Craft {0} {1}
achievements.trigger.playtime_minutes=Play for {0} minutes
achievements.trigger.distance_walked=Walk {0} blocks
achievements.trigger.chat_messages=Send {0} chat messages
achievements.trigger.zones_discovered=Discover {0} zones
achievements.cmd.grant.success=Granted {0} to {1}
achievements.cmd.grant.already=Player already has this achievement
achievements.cmd.revoke.success=Revoked {0} from {1}
achievements.cmd.revoke.not_unlocked=Player doesn't have this achievement
achievements.cmd.list.header={0}'s Achievements ({1}/{2}):
achievements.cmd.list.empty=No achievements unlocked
achievements.broadcast.unlock={0} unlocked: {1}
achievements.broadcast.title={0} earned the title: {1}

:::info Version 1.8.6+ Custom translation files allow you to add or override translations without losing them during plugin updates. :::

  1. Create custom_en-US.json (copy from custom_en-US.json.example)
  2. Add only the keys you want to override or add
  3. Custom translations are merged on top of standard translations
  4. Custom files are NEVER overwritten by updates

Translations are loaded in this order:

  1. localization/{language}.json (e.g., en-US.json) - Standard translations
  2. localization/custom_{language}.json (e.g., custom_en-US.json) - Custom overrides

Keys in the custom file will override keys from the standard file.

localization/custom_en-US.json:

{
"achievements.name.first_blood": "My First Kill",
"achievements.desc.first_blood": "Defeat your very first enemy!",
"lootbag.name.my_custom_bag": "Treasure Chest",
"lootbag.desc.my_custom_bag": "Contains rare treasures!"
}

:::info Version 1.8.5+ All lootbag names, descriptions, and rarities are now fully localizable using translation keys. :::

Key PatternDescription
lootbag.name.<id>Display name of the lootbag
lootbag.desc.<id>Description text
lootbag.rarity.<rarity>Rarity display name (common, uncommon, rare, epic, legendary)

localization/custom_en-US.json:

{
"lootbag.name.starter_pack": "Starter Pack",
"lootbag.desc.starter_pack": "A bag of essential items for new adventurers.",
"lootbag.name.epic_treasure": "Epic Treasure Chest",
"lootbag.desc.epic_treasure": "Contains powerful weapons and rare materials!",
"lootbag.rarity.common": "Common",
"lootbag.rarity.uncommon": "Uncommon",
"lootbag.rarity.rare": "Rare",
"lootbag.rarity.epic": "Epic",
"lootbag.rarity.legendary": "Legendary"
}

localization/custom_de-DE.json:

{
"lootbag.name.starter_pack": "Starterpaket",
"lootbag.desc.starter_pack": "Eine Tasche mit wichtigen Gegenständen für neue Abenteurer.",
"lootbag.name.epic_treasure": "Epische Schatzkiste",
"lootbag.desc.epic_treasure": "Enthält mächtige Waffen und seltene Materialien!",
"lootbag.rarity.common": "Gewöhnlich",
"lootbag.rarity.uncommon": "Ungewöhnlich",
"lootbag.rarity.rare": "Selten",
"lootbag.rarity.epic": "Episch",
"lootbag.rarity.legendary": "Legendär"
}

When creating custom achievements, add translations to the custom JSON files:

custom/custom_achievements.json:

{
"achievements": [
{
"id": "my_custom_achievement",
"category": "progression",
"trigger": { "type": "blocks_mined", "target": "any", "count": 100 }
}
]
}

localization/custom_en-US.json:

{
"achievements.name.my_custom_achievement": "My Custom Achievement",
"achievements.desc.my_custom_achievement": "Mine 100 blocks of any type"
}

localization/custom_de-DE.json:

{
"achievements.name.my_custom_achievement": "Mein Eigenes Achievement",
"achievements.desc.my_custom_achievement": "Baue 100 Blöcke beliebiger Art ab"
}

If a translation is missing:

  1. Uses the achievement id formatted as display name
  2. my_custom_achievementMy Custom Achievement
  3. Underscores become spaces, words capitalized
# {0} = first parameter, {1} = second, etc.
achievements.trigger.kills=Kill {0} {1}
# Result: "Kill 50 Spiders"
achievements.broadcast.unlock={player} unlocked: {achievement}

Create a new JSON file in the localization folder:

KyuubiAchievements/
└── localization/
├── en-US.json
├── de-DE.json
├── fr-FR.json
└── es-ES.json ← New language file

Copy en-US.json and rename it to your language code (e.g., fr-FR.json).

Translate all values (keep keys unchanged):

{
"achievements.ui.gallery": "Galerie des Succès",
"achievements.ui.search": "Rechercher...",
"achievements.name.first_blood": "Premier Sang"
}

Set the language in config.json:

{
"language": "fr-FR"
}
  • Use consistent terminology throughout
  • Match game terminology where applicable
  • Keep placeholder positions logical
  • UI elements have limited space
  • Test translations in-game
  • Abbreviate if necessary
  • Umlauts and accents are supported (ä, ö, ü, é, etc.)
  • Unicode characters work
  • Emoji support depends on client font
{
"achievements.name.miner_1": "Novice Miner",
"achievements.name.miner_2": "Apprentice Miner",
"achievements.name.miner_3": "Journeyman Miner",
"achievements.name.miner_4": "Master Miner",
"achievements.desc.miner_1": "Mine 100 blocks",
"achievements.desc.miner_2": "Mine 1,000 blocks",
"achievements.desc.miner_3": "Mine 10,000 blocks",
"achievements.desc.miner_4": "Mine 100,000 blocks"
}
{
"achievements.name.miner_1": "Bergbau-Anfänger",
"achievements.name.miner_2": "Bergbau-Lehrling",
"achievements.name.miner_3": "Bergbau-Geselle",
"achievements.name.miner_4": "Bergbau-Meister",
"achievements.desc.miner_1": "Baue 100 Blöcke ab",
"achievements.desc.miner_2": "Baue 1.000 Blöcke ab",
"achievements.desc.miner_3": "Baue 10.000 Blöcke ab",
"achievements.desc.miner_4": "Baue 100.000 Blöcke ab"
}

Language changes require a server restart to take effect.

:::tip Development During development, consider creating a reload command to test translations without restarting. :::


If you’re upgrading from v1.5.x or earlier:

  1. Automatic Migration - The plugin automatically extracts new JSON files on first start
  2. Old Format - The old .lang files in Server/Languages/ are no longer used
  3. Custom Translations - Copy your custom translations to the new JSON format in localization/

Old format:

achievements.name.my_achievement=My Achievement
achievements.desc.my_achievement=Do something cool

New format:

{
"achievements.name.my_achievement": "My Achievement",
"achievements.desc.my_achievement": "Do something cool"
}