Skip to content

Instantly share code, notes, and snippets.

@bautistaaa
Last active August 12, 2022 21:52
Show Gist options
  • Save bautistaaa/93dc608750c4fb70f3659a63ff78a92a to your computer and use it in GitHub Desktop.
Save bautistaaa/93dc608750c4fb70f3659a63ff78a92a to your computer and use it in GitHub Desktop.
typesafe i18n
const translations = {
translationOne: 'hello world',
translationTwo: 'hello {{world}}',
translationThree: "hello {{world}}, I'm {{name}}!",
translationFour: '{{foo}} has a {{bar}}',
} as const;
type Translations = typeof translations;
type InterpolateInner<
S extends string,
U extends object = {}
> = S extends `${string}{{${infer V}}}${infer Rest}`
? InterpolateInner<Rest, U & { [key in V]: string }>
: U;
type Interpolate<S extends keyof Translations> = InterpolateInner<
Translations[S]
>;
function t<T extends keyof Translations, Payload = Interpolate<T>>(
...args: keyof Payload extends never
? [translation: T]
: [translation: T, payload: Interpolate<T>]
) { }
// Test cases
t('translationOne');
t('translationTwo'); // FAIL needs world
t('translationTwo', { world: 'Greece' });
t('translationThree', { world: 'Greece' }); // FAIL needs name
t('translationThree', { world: 'Greece', name: 'Trash', });
t('translationFour', { foo: 'Greece', bar: 'Trash', });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment