Logo
Kythia
Logo
Kythia
Login
Login
i18n & Localization
Minimized (Click to Restore)

i18n & Localization

Build a multilingual bot using Kythia's built-in internationalization system — locale files, variable interpolation, and AI-powered auto-translation.


Kythia uses a file-based i18n system managed by the TranslatorManager. Every string shown to users should go through the translation function t() so that your bot can serve communities in their native language.


How It Works

The TranslatorManager loads locale files in this priority order during boot:

Priority (highest to lowest)
─────────────────────────────
1. Addon lang files       addons/*/lang/*.json
2. User lang files        {appRoot}/lang/*.json
3. Core lang files        kythia-core/src/lang/*.json (built-in)

Higher-priority files override lower-priority ones by key. This lets your addons override core strings without touching the core package.


Locale File Format

Place locale files at addons/{your-addon}/lang/{locale}.json:

// addons/leveling/lang/en.json
{
  "leveling": {
    "profile": {
      "title": "Profile — {{username}}",
      "level": "Level {{level}}",
      "xp": "{{current}} / {{required}} XP"
    },
    "set": {
      "success": "Set {{username}}'s level to {{level}}."
    }
  }
}
Use namespaced keys (e.g. addon.command.key) to prevent collisions between addons.

Using t() in Commands

The translation function is injected into every command via the DI container:

async execute(interaction, container) {
  const { t } = container;

  // Simple key lookup
  const title = await t(interaction, 'leveling.profile.title', {
    username: interaction.user.username,
  });

  await interaction.reply(title);
}

The interaction parameter provides the user's locale (set in Discord's user settings). Kythia automatically falls back to en.json if the user's language isn't available.

Variable Interpolation

Pass a second object argument with your variables. Use {{variableName}} in your JSON strings:

await t(interaction, 'leveling.set.success', {
  username: 'Alice',
  level: 25,
});
// → "Set Alice's level to 25."

Adding a New Language

1
Translate with AI:
npx kythia lang:translate --target id   # Indonesian
npx kythia lang:translate --target ja   # Japanese
npx kythia lang:translate --target zh   # Chinese

This uses Google Gemini to translate your en.json and saves the result as {locale}.json in the same directory.

2
Review the output:
AI translations are a great starting point but should be reviewed by a native speaker before shipping to production.
3
Sync regularly:
npx kythia lang:sync

After adding new keys to en.json, run lang:sync to add [placeholder] stubs for all other locale files so nothing is missing.


Checking for Missing Keys

npx kythia lang:check

Uses Babel AST parsing to scan all .js/.ts files for t('key') calls and compares them against your locale JSON. Reports:

  • Missing keys — your code calls a key that doesn't exist in en.json
  • ⚠️ Unused keys — a key exists in en.json but is never called in code
Add lang:check to your Husky pre-commit hook so missing translations can never slip into a commit.

Supported Locales

Kythia maps Discord's user locale codes to your locale files. Common codes:

Discord Locale File name Language
en-US / en-GB en.json English
id id.json Indonesian
ja ja.json Japanese
zh-CN zh.json Chinese (Simplified)
ko ko.json Korean
de de.json German
fr fr.json French
pt-BR pt-BR.json Portuguese (Brazil)
If a user's locale file doesn't exist or doesn't contain the requested key, Kythia automatically falls back to en.json.
Kythia Documentation Sign in →