Hi,
I want to translate my CV and some translations need vars, so I try this:
// src/i18n/ui.ts
import { i18n } from "@/i18n/config";
export const languages = {
en: "English",
es: "Español",
};
export const defaultLang = i18n.defaultLocale;
export const showDefaultLang = false;
export const ui = {
es: {
title: "Portafolio de",
"sections.about": "Sobre mí",
"sections.experience": "Experiencia laboral",
"sections.education": "Educación",
"sections.projects": "Proyectos",
"sections.skills": "Habilidades",
"common.present": "Actual",
"common.seeLink": ({ link }) => `Ver ${link}`,
"see.email": ({ name, email }) => `Enviar un correo electrónico a ${name} al correo ${email}`,
"see.phone": ({ name, phone }) => `Llamar por teléfono a ${name} al número ${phone}`,
"see.network": ({ name, network }) => `Visitar el perfil de ${name} en ${network}`,
},
en: {
title: "Portfolio of",
"sections.about": "About me",
"sections.experience": "Work Experience",
"sections.education": "Education",
"sections.projects": "Projects",
"sections.skills": "Skills",
"common.present": "Present",
"common.seeLink": ({ link }) => `See ${link}`,
"see.email": ({ name, email }) => `Send an email to ${name} at ${email}`,
"see.phone": ({ name, phone }) => `Call ${name} at ${phone}`,
"see.network": ({ name, network }) => `Visit ${name}'s profile on ${network}`,
},
} as const;
// src/i18n/utils.ts
import { ui, defaultLang, showDefaultLang } from './ui';
export function getLangFromUrl(url: URL) {
const [, lang] = url.pathname.split('/');
if (lang in ui) return lang as keyof typeof ui;
return defaultLang;
}
type KeysOfValue<T, V extends T[keyof T]> =
{ [K in keyof T]-?: T[K] extends V ? K : never }[keyof T];
type PickOfValue<T, V extends T[keyof T]> = Pick<T, KeysOfValue<T, V>>;
type functionsKeys = PickOfValue<typeof ui[typeof defaultLang], (...args: any) => any>;
export function useTranslations(lang: keyof typeof ui) {
return function t<T extends keyof functionsKeys | keyof stringKeys>(key: T, vars: (T extends keyof functionsKeys ? Parameters<typeof ui[typeof defaultLang][T]>[0] : never)) {
const translation = ui[lang][key] || ui[defaultLang][key];
return (typeof translation === 'function' ? translation(vars) : translation) satisfies string;
}
}
export function useTranslatedPath(lang: keyof typeof ui) {
return function translatePath(path: string, l: string = lang) {
return !showDefaultLang && l === defaultLang ? path : `/${l}${path}`
}
}
---
import { getLangFromUrl, useTranslations } from '@/i18n/utils';
const { work } = Astro.props
const lang = getLangFromUrl(Astro.url);
const t = useTranslations(lang);
---
<ul>
{
work.map(
({ name, endDate, url }) => {
const endYear =
endDate != null ? new Date(endDate).getFullYear() : t('common.present')
return (
<a href={url} title={t('common.seeLink', { link: name })} target="_blank">
{name}
</a>
)
}
)
}
</ul>
But there is some errors:
- useTranslations: error type in vars
- t: vars is not typed as an optional when the key is not a function
- ui: the functions object argument keys should be type automatically as a string
Does anyone knows how to fix it?