Usage with Legacy Plugin
The i18n plugin is fully compatible with CommandKit's legacy command system, allowing you to add internationalization to existing projects without major refactoring.
Translations in Legacy Commands
For legacy commands, import the locale
function directly from the i18n plugin:
src/app/commands/legacy/ping.js
import { locale } from '@commandkit/i18n';
export async function run({ interaction, client }) {
// The locale function can automatically infer the locale from the interaction
const { t } = locale();
const latency = client.ws.ping;
return interaction.reply({
content: t('response', { latency }),
ephemeral: true,
});
}
// Legacy command metadata
export const data = {
name: 'ping',
description: 'Check bot latency',
};
Manual Locale Specification
You can also specify a locale manually:
export async function run({ interaction, client }) {
// Use a specific locale
const guildLocale = interaction.guild?.preferredLocale || 'en-US';
const { t } = locale(guildLocale);
return interaction.reply({
content: t('response', { latency: client.ws.ping }),
ephemeral: true,
});
}
Legacy Command Translation Files
Translation files for legacy commands work the same way as modern commands:
src/app/locales/en-US/ping.json
{
"response": "🏓 Pong! Latency: **{{latency}}ms**",
"error": "❌ Could not determine latency"
}
src/app/locales/fr/ping.json
{
"response": "🏓 Pong! Latence: **{{latency}}ms**",
"error": "❌ Impossible de déterminer la latence"
}
Migrating Legacy Commands
Here's how to migrate an existing legacy command to use i18n:
Before (No Localization)
src/app/commands/legacy/userinfo.js
export async function run({ interaction }) {
const user = interaction.options.getUser('user') || interaction.user;
const member = interaction.guild?.members.cache.get(user.id);
const embed = {
title: `User Information - ${user.username}`,
fields: [
{ name: 'Username', value: user.username, inline: true },
{ name: 'ID', value: user.id, inline: true },
{
name: 'Account Created',
value: user.createdAt.toDateString(),
inline: true,
},
],
color: 0x0099ff,
};
if (member) {
embed.fields.push(
{
name: 'Joined Server',
value: member.joinedAt?.toDateString() || 'Unknown',
inline: true,
},
{
name: 'Roles',
value: member.roles.cache.map((role) => role.name).join(', '),
inline: false,
},
);
}
return interaction.reply({ embeds: [embed] });
}
export const data = {
name: 'userinfo',
description: 'Get information about a user',
options: [
{
name: 'user',
description: 'The user to get information about',
type: 'USER',
required: false,
},
],
};
After (With Localization)
src/app/commands/legacy/userinfo.js
import { locale } from '@commandkit/i18n';
export async function run({ interaction }) {
const { t } = locale();
const user = interaction.options.getUser('user') || interaction.user;
const member = interaction.guild?.members.cache.get(user.id);
const embed = {
title: t('embed.title', { username: user.username }),
fields: [
{ name: t('embed.fields.username'), value: user.username, inline: true },
{ name: t('embed.fields.id'), value: user.id, inline: true },
{
name: t('embed.fields.created'),
value: user.createdAt.toDateString(),
inline: true,
},
],
color: 0x0099ff,
};
if (member) {
embed.fields.push(
{
name: t('embed.fields.joined'),
value: member.joinedAt?.toDateString() || t('embed.unknown'),
inline: true,
},
{
name: t('embed.fields.roles'),
value: member.roles.cache.map((role) => role.name).join(', '),
inline: false,
},
);
}
return interaction.reply({ embeds: [embed] });
}
export const data = {
name: 'userinfo',
description: 'Get information about a user',
options: [
{
name: 'user',
description: 'The user to get information about',
type: 'USER',
required: false,
},
],
};
src/app/locales/en-US/userinfo.json
{
"embed": {
"title": "User Information - {{username}}",
"unknown": "Unknown",
"fields": {
"username": "Username",
"id": "ID",
"created": "Account Created",
"joined": "Joined Server",
"roles": "Roles"
}
}
}
src/app/locales/es/userinfo.json
{
"embed": {
"title": "Información del Usuario - {{username}}",
"unknown": "Desconocido",
"fields": {
"username": "Nombre de Usuario",
"id": "ID",
"created": "Cuenta Creada",
"joined": "Se Unió al Servidor",
"roles": "Roles"
}
}
}
Best Practices for Legacy Commands
- Gradual Migration: You can migrate commands one at a time without affecting others
- Consistent Naming: Use the same translation keys across legacy and modern commands when possible
- Error Handling: Always provide fallback text for missing translations
- Testing: Test legacy commands with different locales to ensure compatibility
Mixed Command Types
You can use both legacy and modern commands with i18n in the same project:
commandkit.config.ts
import { defineConfig } from 'commandkit';
import { i18n } from '@commandkit/i18n';
export default defineConfig({
// Enable both legacy and modern command support
plugins: [i18n()],
// Configuration for mixed command types
paths: {
commands: 'src/app/commands',
events: 'src/app/events',
},
});
This allows you to:
- Keep existing legacy commands working
- Add new commands using the modern syntax
- Gradually migrate legacy commands when convenient
- Maintain consistent localization across all command types