Basic Type Definitions
Install Type Definitions
npm install --save-dev @types/i18next
# for react-i18next
npm install --save-dev @types/react-i18next
Define Translation Resource Types
interface TranslationResources {
en: {
translation: EnTranslation;
};
zh: {
translation: ZhTranslation;
};
}
interface EnTranslation {
welcome: string;
greeting: string;
user: {
name: string;
profile: string;
};
}
interface ZhTranslation {
welcome: string;
greeting: string;
user: {
name: string;
profile: string;
};
}
Using useTranslation Hook
Basic Usage
import { useTranslation } from 'react-i18next';
function MyComponent() {
const { t } = useTranslation();
return <h1>{t('welcome')}</h1>;
}
Specify Namespace
function MyComponent() {
const { t } = useTranslation('common');
return <button>{t('save')}</button>;
}
Type-safe Translation Keys
// define translation key types
type TranslationKeys = 'welcome' | 'greeting' | 'user.name';
function useTypedTranslation() {
const { t } = useTranslation();
return {
t: (key: TranslationKeys, options?: any) => t(key, options)
};
}
function MyComponent() {
const { t } = useTypedTranslation();
return <h1>{t('welcome')}</h1>;
}
Creating Type-safe Translation Functions
Using Generics
import i18next from 'i18next';
type TranslationFunction<T> = (key: keyof T, options?: any) => string;
function createTypedTranslation<T>(ns: string): TranslationFunction<T> {
return (key: keyof T, options?: any) => {
return i18next.t(`${ns}:${String(key)}`, options);
};
}
// usage
interface CommonTranslations {
save: string;
cancel: string;
delete: string;
}
const tCommon = createTypedTranslation<CommonTranslations>('common');
function MyComponent() {
return (
<div>
<button>{tCommon('save')}</button>
<button>{tCommon('cancel')}</button>
</div>
);
}
Using i18next-resources-to-ts
Generate Type Definitions
npm install --save-dev i18next-resources-to-ts
// scripts/generate-types.js
const { generateTypes } = require('i18next-resources-to-ts');
const fs = require('fs');
generateTypes('./locales', {
indent: 2,
sort: true,
lineEnding: 'lf'
}).then(types => {
fs.writeFileSync('./src/types/i18n.d.ts', types);
console.log('Types generated successfully');
});
Add Script in package.json
{
"scripts": {
"generate:i18n-types": "node scripts/generate-types.js"
}
}
Interpolation Type Safety
interface GreetingOptions {
name: string;
title?: string;
}
function useGreeting() {
const { t } = useTranslation();
return (options: GreetingOptions) => {
return t('greeting', options);
};
}
function MyComponent() {
const greet = useGreeting();
return (
<div>
{greet({ name: 'John' })}
{greet({ name: 'Jane', title: 'Dr.' })}
</div>
);
}
Pluralization Types
interface PluralOptions {
count: number;
item: string;
}
function usePlural() {
const { t } = useTranslation();
return (options: PluralOptions) => {
return t('item_count', options);
};
}
function MyComponent() {
const plural = usePlural();
return (
<div>
{plural({ count: 1, item: 'apple' })}
{plural({ count: 5, item: 'apple' })}
</div>
);
}
Context Types
type Context = 'male' | 'female' | 'other';
interface ContextOptions {
context: Context;
name: string;
}
function useContextTranslation() {
const { t } = useTranslation();
return (options: ContextOptions) => {
return t('friend', options);
};
}
function MyComponent() {
const tFriend = useContextTranslation();
return (
<div>
{tFriend({ context: 'male', name: 'John' })}
{tFriend({ context: 'female', name: 'Jane' })}
</div>
);
}
Namespace Types
interface Namespaces {
common: CommonTranslations;
errors: ErrorTranslations;
user: UserTranslations;
}
function useNamespacedTranslation<K extends keyof Namespaces>(
namespace: K
) {
const { t } = useTranslation(namespace);
return {
t: (key: keyof Namespaces[K], options?: any) => t(key, options)
};
}
function MyComponent() {
const { t: tCommon } = useNamespacedTranslation('common');
const { t: tErrors } = useNamespacedTranslation('errors');
return (
<div>
<button>{tCommon('save')}</button>
<p>{tErrors('notFound')}</p>
</div>
);
}
Trans Component Types
import { Trans } from 'react-i18next';
interface TransProps {
i18nKey: string;
values?: Record<string, string | number>;
components?: Record<string, React.ReactNode>;
}
function TypedTrans({ i18nKey, values, components }: TransProps) {
return (
<Trans
i18nKey={i18nKey}
values={values}
components={components}
/>
);
}
function MyComponent() {
return (
<TypedTrans
i18nKey="user.greeting"
values={{ name: 'John' }}
components={{ strong: <strong /> }}
/>
);
}
Best Practices
- Generate Types: Use tools to automatically generate translation resource types
- Strict Mode: Enable TypeScript strict mode
- Namespaces: Use namespaces to organize translations
- Type Guards: Use type guards to ensure type safety
- Continuous Integration: Generate and check types in CI/CD
- Documentation: Document type definitions and usage
- Testing: Write type tests to ensure type correctness