Introducing Typed-i18n, a Type-Safe Internationalization for TypeScript Apps

Typed-i18n: Type-Safe Internationalization for TypeScript Apps

We’re excited to introduce @qzlcorp/typed-i18n — a zero-dependency, TypeScript-first i18n library designed for modern apps that need scalable, type-safe, and modular translations.

Inspired by modern i18n libraries, typed-i18n ensures that all your translation keys are validated at compile-time, catching errors early and keeping your app robust.

Demo

Watch how TypeScript catches translation key errors at compile time, ensuring type-safe i18n throughout your app.

Live Demo

🚀 View React Demo - Interactive demo showcasing dynamic module loading, locale switching, and type-safe translations.

Features

Module-based architecture – Organize translations by feature/page for better code-splitting.

Compile-time type safety – All translation keys are validated at build time.

Shape validation – TypeScript ensures all locale files match the same structure.

Modern API – Simple t('key') syntax with namespace support.

Mutable locale – Change language dynamically with setLocale().

Fallback support – Automatic fallback to default locale for missing translations.

Zero runtime dependencies – Lightweight and performant.

Installation

npm install @qzlcorp/typed-i18n

Quick Start

1. Create translation files

// locales/common/en.json
{
"hello": "Hello",
"goodbye": "Goodbye"
}

// locales/common/fr.json
{
"hello": "Bonjour",
"goodbye": "Au revoir"
}

2. Define modules and create i18n instance

import { defineModule, createI18n } from '@qzlcorp/typed-i18n';
import commonEn from './locales/common/en.json';
import commonFr from './locales/common/fr.json';

// ⚠️ Provide explicit reference type for compile-time validation
const common = defineModule('common')<typeof commonEn>({
en: commonEn,
fr: commonFr
});

const i18n = createI18n({
locale: 'en',
fallbackLocale: 'en',
modules: { common }
});

3. Use translations

i18n.t('common.hello'); // "Hello"

// Change locale dynamically
i18n.setLocale('fr');
i18n.t('common.hello'); // "Bonjour"

// Interpolation
i18n.t('common.greeting', { name: 'John' }); // Supports {{name}} in JSON

Advanced Usage

Multiple Modules (Code-Splitting)

const dashboard = defineModule('dashboard')<typeof dashboardEn>({
en: dashboardEn,
fr: dashboardFr
});

const i18n2 = i18n.addModule(dashboard); // Returns new typed instance
i18n2.t('dashboard.title'); // ✅ Fully typed

Dynamic Module Loading (React)

const dashboardModule = defineModule('dashboard')<typeof dashboardEn>({
en: await import('./locales/dashboard/en.json'),
fr: await import('./locales/dashboard/fr.json')
});

const i18n3 = i18n.addModule(dashboardModule);

⚠️ Important: Always use the returned instance from addModule to preserve type safety. Original instance will still work at runtime but loses typing for new modules.

Nested Keys

{
"dashboard": {
"stats": {
"clicks": "{{count}} clicks"
}
}
}

i18n.t('common.dashboard.stats.clicks', { count: 5 }); // "5 clicks"

Get Available Locales

i18n.getLocales(); // ['en', 'fr']

Fallback Locale

const i18n = createI18n({
locale: 'de', // German not available
fallbackLocale: 'en',
modules: { common }
});
i18n.t('common.hello'); // Falls back to "Hello"

API Reference

defineModule(namespace)<Ref>(locales)

Creates a typed translation module.

⚠️ Must provide explicit reference type for type-safe cross-locale validation.

createI18n(options)

locale: current locale

fallbackLocale: optional fallback

modules: translation modules

Returns an instance with:

t(key, params?): translate

setLocale(locale): change locale

getLocale(): get current locale

addModule(module): add module dynamically, returns new typed instance

getLocales(): get all available locales

TypeScript Tips

Always provide explicit reference type when defining modules to enable compile-time validation:

const common = defineModule('common')<typeof enJson>({
en: enJson,
fr: frJson
});

Without it, TypeScript may infer a loose union type and mismatched locale structures could pass unnoticed.

React Integration

Use @qzlcorp/typed-i18n-react for first-class React support:

<I18nProvider i18n={i18n}>
<App />
</I18nProvider>

const { t } = useTranslation<I18nModules>();
t('common.hello'); // ✅ compile-time checked

Support & License

License: MIT

Support: Buy Me a Coffee

Typed-i18n is your modern, type-safe, and scalable solution for managing translations in TypeScript projects.

Links

Typed-i18n NPM

Typed-i18n React

Typed-i18n Vue