@robojs/i18n
Type-safe internationalization for Robo.js with MessageFormat 2 (MF2).
Translate your Robo project with type-safe, file-based internationalization. Drop JSON files in /locales, and the plugin generates TypeScript types from your messages — giving you autocomplete for keys, inferred parameter types, and compile-time safety.
Built on MessageFormat 2 (MF2), it supports plurals, numbers, dates, times, and nested parameters out of the box.
Features
Type-safe Keys
Autocomplete and compile-time safety for all translation keys
MessageFormat 2
Full MF2 syntax with plurals, numbers, dates, and times
Pluralization
Automatic plural rules via MF2 annotations
Discord Commands
Localize slash command names, descriptions, and options
Strict Mode
Compile-time enforcement that all parameters are provided
Auto-generated Types
TypeScript types generated from your locale files
Date/Time Formatting
Locale-aware date and time formatting built in
File-based Locales
Drop JSON files in /locales and start translating
Installation
Add the plugin to an existing Robo:
npx robo add @robojs/i18n@nextOr start a new project with it preinstalled:
npx create-robo@next my-project -p @robojs/i18n@nextType-safe translations
The plugin scans your /locales directory and generates TypeScript types automatically. Keys, parameters, and return types are all inferred from your locale files.
import { t } from '@robojs/i18n'
t('en-US', 'app:hello', { name: 'Robo' }) // "Hello Robo!"
t('en-US', 'app:pets.count', { count: 3 }) // "You have 3 pets"import { t } from '@robojs/i18n'
t('en-US', 'app:hello', { name: 'Robo' }) // "Hello Robo!"
t('en-US', 'app:pets.count', { count: 3 }) // "You have 3 pets"MessageFormat 2
Full support for MF2 syntax including plurals, numbers, dates, and times. Parameter types are inferred from annotations like :number, :date, and :time.
// Pluralization
t('en-US', 'app:pets.count', { count: 1 }) // "You have 1 pet"
t('en-US', 'app:pets.count', { count: 3 }) // "You have 3 pets"
// Date formatting
t('en-US', 'app:event', { date: new Date() })// Pluralization
t('en-US', 'app:pets.count', { count: 1 }) // "You have 1 pet"
t('en-US', 'app:pets.count', { count: 3 }) // "You have 3 pets"
// Date formatting
t('en-US', 'app:event', { date: new Date() })Discord command localization
Localize slash command names, descriptions, and options for all your supported locales using createCommandConfig().
import { createCommandConfig } from '@robojs/i18n'
export const config = createCommandConfig({
descriptionKey: 'commands:ping.desc',
options: [
{
type: 'string',
name: 'text',
nameKey: 'commands:ping.arg.name',
descriptionKey: 'commands:ping.arg.desc'
}
]
} as const)import { createCommandConfig } from '@robojs/i18n'
export const config = createCommandConfig({
descriptionKey: 'commands:ping.desc',
options: [
{
type: 'string',
name: 'text',
nameKey: 'commands:ping.arg.name',
descriptionKey: 'commands:ping.arg.desc'
}
]
})Strict mode
Use tr() when you want compile-time enforcement that all parameters are provided. No accidental omissions.
import { tr } from '@robojs/i18n'
tr('en-US', 'app:hello', { name: 'Robo' }) // OK
// tr('en-US', 'app:hello') // compile errorimport { tr } from '@robojs/i18n'
tr('en-US', 'app:hello', { name: 'Robo' }) // OK
// tr('en-US', 'app:hello') // compile error