LogoRobo.js

@robojs/i18n

Type-safe internationalization for Robo.js with MessageFormat 2 (MF2).

Install @robojs/i18n with:

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@next

Or start a new project with it preinstalled:

npx create-robo@next my-project -p @robojs/i18n@next

Type-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 error
import { tr } from '@robojs/i18n'

tr('en-US', 'app:hello', { name: 'Robo' }) // OK
// tr('en-US', 'app:hello')                // compile error

Next Steps

On this page