I18n API Reference
Complete API documentation for Zustic i18n library.
createI18n<T, L>(params)
Creates an i18n hook for managing translations.
Type Parameters:
T- Type of translation object (usually inferred from your translations)L- Language type (union of supported languages)
Parameters:
interface I18nParams<T, L> {
/**
* Initial language to load
* @example 'en'
*/
initialLan: L;
/**
* Resource loader function
* Can be async or sync, returns translation data
* @example (lan) => fetch(`/translations/${lan}.json`)
* @example (lan) => translations[lan]
*/
resource: (lan: L) => Promise<T> | T;
}
Returns: A React hook useTranslation()
Example:
import { createI18n } from 'zustic/i18n';
type Language = 'en' | 'es' | 'fr';
export const useTranslation = createI18n<TranslationType, Language>({
initialLan: 'en',
resource: async (lan) => {
const response = await fetch(`/translations/${lan}.json`);
return response.json();
},
});
useTranslation() Hook
The hook returned by createI18n. Use it in any React component.
Return Type
{
/**
* Translate function using dot notation keys
* @example t('common.welcome')
* @example t('pages.home.title')
* @returns Translation string or fallback key
*/
t: (key: TranslationKey<T>) => string;
/**
* Current active language
* @example 'en'
*/
lan: L;
/**
* Update active language and reload translations
* @example updateTranslation('es')
*/
updateTranslation: (lang: L) => void;
/**
* True while translations are loading for first time
*/
isInitialLoading: boolean;
/**
* True while switching between languages
*/
isUpdating: boolean;
}
Examples
Basic Usage
import { useTranslation } from './i18n';
export function App() {
const { t, lan } = useTranslation();
return <h1>{t('common.welcome')}</h1>;
}
With Loading States
import { useTranslation } from './i18n';
export function App() {
const { t, isInitialLoading, isUpdating } = useTranslation();
if (isInitialLoading) {
return <div>⏳ Loading translations...</div>;
}
return (
<main>
{isUpdating && <div className="loader">Switching language...</div>}
<h1>{t('common.welcome')}</h1>
</main>
);
}
Language Switching
import { useTranslation } from './i18n';
export function LanguageSwitcher() {
const { lan, updateTranslation, isUpdating } = useTranslation();
return (
<select
value={lan}
onChange={(e) => updateTranslation(e.target.value as any)}
disabled={isUpdating}
>
<option value="en">English</option>
<option value="es">Español</option>
<option value="fr">Français</option>
</select>
);
}
TranslationKey<T>
Type-safe translation keys using dot notation.
What It Does
Provides full TypeScript autocomplete for nested translation objects:
// With this structure:
const translations = {
common: {
welcome: 'Welcome',
goodbye: 'Goodbye'
},
pages: {
home: {
title: 'Home',
description: 'Welcome'
}
},
};
// TranslationKey generates these valid keys:
type ValidKeys = TranslationKey<typeof translations>;
// Results in:
// 'common'
// | 'common.welcome'
// | 'common.goodbye'
// | 'pages'
// | 'pages.home'
// | 'pages.home.title'
// | 'pages.home.description'
IDE Autocomplete
Your IDE will show intelligent suggestions:
t('common.') // Shows: welcome, goodbye
t('pages.') // Shows: home
t('pages.home.') // Shows: title, description
Benefits
✅ No typos - TypeScript catches mistakes
✅ Auto-completion - Your IDE helps you
✅ Refactoring safe - Rename translations safely
✅ Documentation - Keys are self-documenting
Type Definition Reference
I18nParams
interface I18nParams<T, L> {
initialLan: L;
resource: (lan: L) => Promise<T> | T;
}
useTranslation Return
interface TranslationHook<T, L> {
t: (key: TranslationKey<T>) => string;
lan: L;
updateTranslation: (lang: L) => void;
isInitialLoading: boolean;
isUpdating: boolean;
}
StoreState (Internal)
interface StoreState<T, L> {
lan: L;
data: T | null;
isInitialLoading: boolean;
isUpdating: boolean;
}
Function Signatures
t() - Translate Function
/**
* Get translation for a key
* @param key - Dot notation key (type-safe)
* @returns Translated string or fallback key if not found
*/
t(key: TranslationKey<T>): string
updateTranslation() - Language Switch
/**
* Switch to a different language
* @param lang - Target language
* @returns void (updates are reactive)
*/
updateTranslation(lang: L): void
Common Patterns
Static Translations
export const useTranslation = createI18n({
initialLan: 'en',
resource: (lan) => translations[lan], // Sync
});
API-Based Translations
export const useTranslation = createI18n({
initialLan: 'en',
resource: async (lan) => {
const res = await fetch(`/api/translations/${lan}`);
return res.json(); // Async
},
});
JSON File Import
export const useTranslation = createI18n({
initialLan: 'en',
resource: async (lan) => {
const module = await import(`./translations/${lan}.json`);
return module.default;
},
});
Error Handling
Missing Translation Keys
If a key doesn't exist, the function returns the key itself:
const { t } = useTranslation();
// If 'invalid.key' doesn't exist:
console.log(t('invalid.key')); // Output: 'invalid.key'
Failed Resource Loading
Catch errors in the resource function:
export const useTranslation = createI18n({
initialLan: 'en',
resource: async (lan) => {
try {
const res = await fetch(`/api/translations/${lan}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
} catch (error) {
console.error(`Failed to load ${lan}:`, error);
return {}; // Return empty translations
}
},
});
Performance Characteristics
Bundle Size
- Minified: ~1.8KB
- Gzipped: ~0.8KB
Runtime Performance
- Initial Load: Depends on resource function
- Language Switch:
<50ms(typically) - Translation Lookup: O(1) - instant
- Memory: Minimal (~100 bytes per translation set)
Optimization Tips
-
Lazy load translations
resource: async (lan) => {
const module = await import(`./translations/${lan}.js`);
return module.default;
} -
Cache fetched translations
const cache = new Map();
resource: async (lan) => {
if (cache.has(lan)) return cache.get(lan);
const data = await fetch(`/api/i18n/${lan}`).then(r => r.json());
cache.set(lan, data);
return data;
} -
Preload common languages
// In your app initialization
await fetch('/api/translations/en');
await fetch('/api/translations/es');
TypeScript Tips
Infer Translation Type
// Let TypeScript infer the type
const translations = {
en: { hello: 'Hello', bye: 'Goodbye' },
es: { hello: 'Hola', bye: 'Adiós' },
};
export const useTranslation = createI18n({
initialLan: 'en',
resource: (lan) => translations[lan],
// Type is automatically: typeof translations.en
});
Explicit Type Annotation
interface Translations {
common: {
welcome: string;
goodbye: string;
};
pages: {
home: {
title: string;
description: string;
};
};
}
type Language = 'en' | 'es' | 'fr';
export const useTranslation = createI18n<Translations, Language>({
initialLan: 'en',
resource: async (lan) => {
// Explicitly typed
const response = await fetch(`/translations/${lan}.json`);
return response.json() as Translations;
},
});
Generic Component
interface LocalizedProps<T> {
translationKey: TranslationKey<T>;
}
export function LocalizedText<T>({ translationKey }: LocalizedProps<T>) {
const { t } = useTranslation();
return <span>{t(translationKey)}</span>;
}
Next Steps
- Examples - See practical implementations
- Advanced Guide - Learn advanced patterns
- Best Practices - Follow best practices