Created
August 21, 2025 14:11
-
-
Save ydrea/321f857648da3e45024ba15e3e9f69d0 to your computer and use it in GitHub Desktop.
i18n UI translations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// translations+interpolations.ts | |
function defineTranslations< | |
T extends Record<string, Record<string, string>> | |
>(t: T & Record<keyof T, Record<keyof T[keyof T], string>>) { | |
return t; | |
} | |
export const translations = defineTranslations({ | |
en: { | |
hello: "Hello", | |
goodbye: "Goodbye", | |
welcome: "Welcome, {name}!", | |
}, | |
hr: { | |
hello: "Bok", | |
goodbye: "Doviđenja", | |
welcome: "Dobrodošao, {name}!", | |
}, | |
}); | |
export type Language = keyof typeof translations; | |
export type TranslationKey = keyof typeof translations[Language]; | |
// Extract placeholders from a string like "Welcome, {name}!" | |
type ExtractPlaceholders<S extends string> = | |
S extends `${string}{${infer Param}}${infer Rest}` | |
? Param | ExtractPlaceholders<Rest> | |
: never; | |
// Params object type for a given language+key | |
type Params<L extends Language, K extends TranslationKey> = | |
ExtractPlaceholders<typeof translations[L][K]> extends never | |
? {} | |
: Record<ExtractPlaceholders<typeof translations[L][K]>, string>; | |
// Our `t()` function with interpolation | |
export function t<L extends Language, K extends TranslationKey>( | |
lang: L, | |
key: K, | |
params?: Params<L, K> | |
): string { | |
let text = translations[lang][key]; | |
if (params) { | |
for (const [param, value] of Object.entries(params)) { | |
text = text.replace(new RegExp(`{${param}}`, "g"), value?.toString() ?? ""); | |
} | |
} | |
return text; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment