@djangocfg/i18n
Lightweight, type-safe i18n library with LLM-powered translation CLI.
Features
- 17 languages - en, ru, ko, ja, de, fr, zh, it, es, nl, ar, tr, pt-BR, pl, sv, no, da
- LLM Translation - Translate with GPT-4o-mini via CLI
- Type-safe - Full TypeScript support with autocomplete
- CLI included - Manage and translate locales
- Works standalone - Components work without provider
Installation
pnpm add @djangocfg/i18n
Quick Start
import { I18nProvider, useT, ru } from '@djangocfg/i18n'
<I18nProvider locale="ru" translations={ru}>
<App />
</I18nProvider>
function MyComponent() {
const t = useT()
return <span>{t('ui.form.save')}</span>
}
Subpath Imports (Server Components)
For Next.js server components, use subpath imports to avoid React Context issues:
import { en, ru, ko } from '@djangocfg/i18n/locales'
import { mergeTranslations } from '@djangocfg/i18n/utils'
import { I18nProvider, useT } from '@djangocfg/i18n'
@djangocfg/i18n | Full package (client components) |
@djangocfg/i18n/locales | Locale data only (server-safe) |
@djangocfg/i18n/utils | Utilities like mergeTranslations (server-safe) |
CLI
Built-in CLI with LLM translation support.
Translate Text
pnpm i18n translate "Hello World" --to ru,ko,ja
pnpm i18n translate "Save" --to ru,ko --json
Translate Locale File
pnpm i18n translate ru
pnpm i18n translate --file --to ru --from en
Sync Missing Keys
pnpm i18n sync --dry
pnpm i18n sync
pnpm i18n sync --translate
pnpm i18n sync --to ru,ko --translate
Other Commands
pnpm i18n list
pnpm i18n list tour
pnpm i18n list -v
pnpm i18n check
pnpm i18n add "tools.new" '{"en":"New","ru":"Новый"}'
pnpm i18n translate --stats
Working with App Locales
CLI supports any locales directory (.ts or .json files):
pnpm i18n translate "Dashboard" --to ru,ko -d ../../apps/hub/i18n/locales
pnpm i18n sync -d ../../apps/hub/i18n/locales --translate
Environment Variables
SDKROUTER_API_KEY=your-key
OPENAI_API_KEY=your-key
ANTHROPIC_API_KEY=your-key
Hooks
useT() | Returns translation function (recommended) |
useI18n() | Full context: { t, locale, setLocale, translations } |
useLocale() | Returns current locale string |
useTypedT<T>() | Type-safe with compile-time key validation |
useT()
function MyComponent() {
const t = useT()
return <button>{t('ui.form.save')}</button>
}
useI18n()
function LocaleSwitcher() {
const { t, locale, setLocale } = useI18n()
return (
<select value={locale} onChange={(e) => setLocale(e.target.value)}>
<option value="en">English</option>
<option value="ru">Russian</option>
</select>
)
}
useTypedT()
import { useTypedT } from '@djangocfg/i18n'
import type { I18nTranslations } from '@djangocfg/i18n'
function MyComponent() {
const t = useTypedT<I18nTranslations>()
return <span>{t('ui.form.save')}</span>
}
Type-safe next-intl Integration
Override useTranslations in your app's global.d.ts to get compile-time key validation.
1. Merge translations (flat, no namespace)
import { en as baseEn } from '@djangocfg/i18n/locales';
import { en as appEn } from './locales';
const locales = {
en: { ...baseEn, ...appEn },
};
2. Add global.d.ts to your app root
type _Messages = import('@djangocfg/i18n').I18nTranslations &
import('./i18n/locales/types').AppTranslations;
type _NSKeys = import('@djangocfg/i18n').NamespaceKeys<
_Messages,
import('@djangocfg/i18n').NestedKeyOf<_Messages>
>;
declare module 'next-intl' {
export function useTranslations<NS extends _NSKeys>(
namespace: NS,
): import('@djangocfg/i18n').IntlTranslator<_Messages, NS>;
}
3. Include in tsconfig.json
{ "include": ["global.d.ts", "app/**/*.ts", ...] }
Now invalid keys and namespaces produce compile errors:
const t = useTranslations('machines');
t('title');
t('dialogs.delete.title');
t('NONEXISTENT');
useTranslations('BOGUS');
Why not use-intl AppConfig? The standard declare module 'use-intl' { interface AppConfig } augmentation doesn't propagate through pnpm's nested node_modules. Overriding useTranslations in next-intl directly works reliably.
Exported utility types
NestedKeyOf<T> | All dot-separated paths (leaves + namespaces) |
NestedValueOf<T, P> | Resolve value type by dot path |
NamespaceKeys<T, A> | Paths resolving to objects (valid namespaces) |
MessageKeys<T, A> | Paths resolving to strings (valid keys) |
IntlTranslator<M, NS> | Type-safe translator with t(), rich(), has(), raw() |
Extending Translations
Spread merge (recommended for next-intl apps)
import { en as baseEn } from '@djangocfg/i18n/locales';
const messages = { ...baseEn, ...appEn };
mergeTranslations() (deep merge with overrides)
import { mergeTranslations, ru } from '@djangocfg/i18n'
const customRu = mergeTranslations(ru, {
ui: { select: { placeholder: 'Выберите...' } },
})
Built-in Locales
import { en, ru, ko, ja, de, fr, zh, it, es, nl, ar, tr, ptBR, pl, sv, no, da } from '@djangocfg/i18n'
Interpolation
t('ui.pagination.showing', { from: 1, to: 10, total: 100 })
t('ui.select.moreItems', { count: 5 })
Translation Key Paths
ui.* - UI components (select, form, dialog, table, pagination)
layouts.* - Layout components (sidebar, auth, profile, theme)
api.* - API/network messages
centrifugo.* - WebSocket monitoring
tools.* - Heavy tools (tour, upload, code, image)
Works Without Provider
Components using useT() work without provider - they fall back to English defaults.
License
MIT