International Types
international-types is a focused TypeScript package that provides essential utility types for constructing robust and type-safe internationalization (i18n) solutions. It is designed to enhance developer experience by offering strong type inference and autocompletion for translation keys, message scopes, and interpolation parameters within i18n implementations. The current stable version is 0.8.1. While this package does not provide any runtime i18n functionality itself, it serves as the foundational typing layer for higher-level i18n libraries, such as `next-international`. Its core differentiators are compile-time validation, preventing common i18n-related errors like missing keys or incorrect parameter types, and promoting maintainability in localized applications by ensuring all translation requirements are met at build time. Its release cycle is often synchronized with its primary consumer, `next-international`.
Common errors
-
Argument of type 'string' is not assignable to parameter of type 'Key extends LocaleKeys<AppLocale, undefined>'
cause Attempting to pass a dynamic string variable as a translation key instead of a literal string. The types require literal keys for compile-time validation.fixEnsure translation keys are always string literals for direct calls. If dynamic keys are necessary, you might need a runtime lookup combined with type assertion (e.g., `t(dynamicKey as LocaleKeys<AppLocale, undefined>)`) or rethink the approach, acknowledging a loss of compile-time key validation for that specific call. -
Property 'value' is missing in type '{}' but required in type '{ value: string; }'cause A required interpolation parameter for a translation string was omitted or incorrectly named when calling the translation function.fixProvide all necessary parameters as defined in your `Locale` type for the specific translation key. Double-check the parameter names and their types. -
TS2307: Cannot find module 'international-types' or its corresponding type declarations.
cause The package is not installed, or TypeScript cannot locate its declaration files (e.g., incorrect `tsconfig.json` paths, or `node_modules` not properly resolved).fixRun `npm install international-types` or `pnpm install international-types`. Ensure `tsconfig.json` includes `node_modules` in its `typeRoots` or `include` paths, or that `moduleResolution` is set appropriately for your project (e.g., `bundler` or `node`).
Warnings
- gotcha This package (`international-types`) provides only TypeScript types and does not include any runtime internationalization logic or components. It must be integrated with a separate i18n library (like `next-international` or a custom implementation) to provide actual translation capabilities.
- gotcha Incorrectly defining your `Locale` type (e.g., not matching the expected flat or dot-notation structure) will lead to incorrect or incomplete type inference for `LocaleKeys` and `Scopes`. This can result in a loss of type safety and autocompletion benefits.
- gotcha The package relies heavily on TypeScript's inference capabilities. In very large projects with extremely complex or deeply nested locale structures, TypeScript compilation times might be slightly affected. Type-checking performance can degrade with overly intricate generic types.
Install
-
npm install international-types -
yarn add international-types -
pnpm add international-types
Imports
- LocaleKeys
import { LocaleKeys } from 'international-types'import type { LocaleKeys } from 'international-types' - Scopes
import { Scopes } from 'international-types'import type { Scopes } from 'international-types' - CreateParams
import { CreateParams } from 'international-types'import type { CreateParams } from 'international-types' - BaseLocale
import { BaseLocale } from 'international-types'import type { BaseLocale } from 'international-types'
Quickstart
import type {
LocaleKeys,
BaseLocale,
Scopes,
ScopedValue,
CreateParams,
ParamsObject
} from 'international-types';
type AppLocale = {
param: 'This is a {value}';
'hello.people': 'Hello {name}! You are {age} years old.';
'scope.nested.greeting': 'A nested greeting.';
};
function createI18nTypedT<Locale extends BaseLocale, Scope extends Scopes<Locale> | undefined>(scope?: Scope) {
return function t<Key extends LocaleKeys<Locale, Scope>, Value extends ScopedValue<Locale, Scope, Key>>(
key: Key,
...params: CreateParams<ParamsObject<Value>, Locale, Scope, Key, Value>
) {
// In a real i18n library, this function would handle the actual translation lookup and interpolation.
// For this example, we just log the key and params to demonstrate type safety.
console.log(`Translating key: ${String(key)} with params: ${JSON.stringify(params[0]) || '{}'}`);
// Example: Dummy return for a type-safe signature
return `Translated: ${String(key)}`
};
}
const t = createI18nTypedT<AppLocale, undefined>();
t('param', {
value: 'exampleValue' // 'value' is required and type-checked here
});
t('hello.people', {
name: 'John Doe',
age: 30 // 'name' and 'age' are required and type-checked
});
const scopedT = createI18nTypedT<AppLocale, 'scope.nested'>('scope.nested');
scopedT('greeting'); // Autocompletes to 'greeting' under 'scope.nested'
// Example of intentionally incorrect usage (will cause TypeScript errors)
// t('non.existent.key');
// t('param', { wrongParam: 'value' });
// t('hello.people', { name: 'Alice' }); // Missing 'age' parameter