Skip to content

Internationalization

Add a translations.yml file to an extension to localize slash command names/descriptions and user-facing messages. Botkit picks the right language from the guild's locale (or falls back to en-US).

Translation strings can include:

Placeholder Example You provide
Your own values {latency}, {user} Python .format(...) when sending the message
Slash commands {commands.help}, {commands.admin__kick} Name of an existing slash command in YAML
App emojis {emojis.checkmark} Name of an emoji uploaded to the bot application

Where to put translation files

Either next to the extension:

src/extensions/my_ext/translations.yml

Or centralized (same <name> as the extension folder):

src/translations/my_ext.yml

Botkit loads the file when the extension starts. Top-level strings from the file are also available on the extension's config as config["translations"].


File layout

commands:
  # localize slash / bridge commands (optional)
strings:
  # general messages for this extension (optional)

Localizing commands

Under commands, use the same name as in your Python code (the cog method / decorator name), not the translated label shown in Discord.

You can nest up to three levels for command groups:

commands:
  ping:
    name:
      en-US: ping
      fr: ping
    description:
      en-US: Get the bot's latency
      fr: Obtenir la latence du bot
    options:
      ephemeral:
        name:
          en-US: ephemeral
        description:
          en-US: Whether the response should be ephemeral
    strings:
      response:
        en-US: "Pong! Latency is {latency}ms. Try {commands.help} next."
        fr: "Pong ! Latence : {latency} ms. Essayez {commands.help} ensuite."

  admin:
    name:
      en-US: admin
    description:
      en-US: Admin commands
    commands:
      kick:
        name:
          en-US: kick
        description:
          en-US: Kick a member
        strings:
          success:
            en-US: "Done {emojis.checkmark}"
Block What it does
name Localized command name shown in Discord
description Localized command description
options.<name> Localized slash option name and description
commands Subcommands inside a group
strings Messages for this command (see below)

See src/extensions/ping/translations.yml in the repo for a full working example.

Extension-wide messages

Use top-level strings for text that is not tied to one command:

strings:
  welcome:
    en-US: "Welcome! Use {commands.help} or {commands.ping} to get started."
    fr: "Bienvenue ! Utilisez {commands.help} ou {commands.ping} pour commencer."

Supported locales

Use Discord locale tags as YAML keys, for example:

en-US, en-GB, fr, de, es-ES, es-419, pt-BR, ja, ko, nl, pl, ru, it, zh-CN, zh-TW, and others Discord supports.

Always include en-US — Botkit uses it when no translation exists for the user's locale.


Using translations in your code

Command messages (ctx.translations)

Define strings under commands.<cmd>.strings. In the handler, read them from ctx.translations:

from src import custom

@discord.slash_command(name="ping")
async def ping(self, ctx: custom.ApplicationContext) -> None:
    text = ctx.translations.response.format(
        latency=round(self.bot.latency * 1000),
    )
    await ctx.respond(text)

Works the same for prefix / bridge commands when you use custom.Context — Botkit loads command strings into ctx.translations automatically.

Extension-wide messages (apply_locale)

For top-level strings, pick the locale and read the key:

from src.i18n import apply_locale

locale = ctx.guild.preferred_locale if ctx.guild else None
t = apply_locale(config["translations"], locale)
await ctx.respond(t.welcome)

Pass your own placeholders with .format():

message = t.greeting.format(username=ctx.author.display_name)

Insert clickable slash command mentions in translated text.

strings:
  hint:
    en-US: "Need help? Run {commands.help}."
  moderation:
    en-US: "Use {commands.admin__kick} to remove members."
In YAML Refers to
{commands.ping} Slash command /ping
{commands.admin__kick} Subcommand /admin kick — use __ between group and subcommand names
{commands.tools__config__reload} Deeper groups: __ between each level

Rules:

  • The command must exist and be registered on the bot.
  • Placeholders work after the bot is online. Before that, the raw {commands.name} may appear in text.
  • If the name does not match any command, the placeholder is left unchanged in the message.

Example

commands:
  help:
    strings:
      footer:
        en-US: "Also try {commands.ping} to check latency."

  ping:
    strings:
      response:
        en-US: "Pong! {latency}ms  see {commands.help} for more."
await ctx.respond(
    ctx.translations.response.format(latency=round(self.bot.latency * 1000)),
)

{commands.help} is filled in by Botkit; {latency} is filled in by your .format().


{emojis.x} — app emoji mentions

Reference emojis uploaded to the bot application by name:

strings:
  success:
    en-US: "Saved {emojis.checkmark}"
  failure:
    en-US: "Something went wrong {emojis.cross_mark}"
In YAML Refers to
{emojis.checkmark} App emoji named checkmark

Requirements:

  • Upload the emoji to your bot in the Developer Portal (or via API).
  • The name in YAML must match the emoji name exactly.
  • Keep bot.cache_app_emojis: true in config (default) so emoji data is available.

Like {commands.x}, emoji placeholders work once the bot is online. Use emoji names you have actually created — a missing name causes an error when the string is resolved.


Quick reference

I want to… In translations.yml In Python
Localize /command name & description commands.<name>.name / .description Nothing — applied at startup
Localize a slash option commands.<name>.options.<opt> Nothing — applied at startup
Message tied to one command commands.<name>.strings.<key> ctx.translations.<key>
General extension text strings.<key> apply_locale(config["translations"], locale).<key>
Mention another command {commands.other} or {commands.group__sub} in the string Usually nothing extra
Show an app emoji {emojis.name} in the string Usually nothing extra
Insert dynamic values {my_key} in the string .format(my_key=…)

Help pages (bundled extension)

The help extension uses a separate YAML format under src/extensions/help/pages/ for help categories and command docs shown in /help. That is not the same schema as translations.yml.

The help extension still has its own translations.yml for the /help command itself (for example UI labels like "Tips & Tricks"). See that extension's readme if you customize help content.