In nextjs, I'm using this example to load translations and return them into the component
import "server-only";
import i18nConfig from "../../i18n-config";
const dictionaries = {
en: () =>
import("../../dictionaries/en.json").then((module) => module.default),
hr: () =>
import("../../dictionaries/hr.json").then((module) => module.default),
};
type TDictionary = (typeof dictionaries)["en"];
export const getDictionary = async (locale: string): Promise<TDictionary> =>
dictionaries[
i18nConfig.locales.includes(locale) ? locale : i18nConfig.defaultLocale
]();
export default async function Navbar ( props: ILangParams ) {
const dict = await getDictionary(props.params.lang);
return (
<nav className={styles.navbar}>
<Link href="/" className={styles.linkLogo}>
<Image
priority
src={logo}
alt={dict.navbar.links.home}
className={styles.logo}
/>
</nav>
);
}
If I don't type getDictionary to return Promise<TDictionary>
, it returns as Promise<any>
.
With Promise<TDictionary>
, it returns
const dict: () => Promise<{
navbar: {
links: {
logoAlt: string;
escapeGames: string;
becomeAPartner: string;
bookDemo: string;
};
};
}>
This seems wrong as I cannot use dict.navbar.links.home to get the translated string.
How do I properly type this?
the structure is the same for all translations, so I only have to cast it as one of those files ((typeof dictionaries)["en"])
I have a piece of code that works, it's pretty close to the one you wrote.
export type Lang = "fr" | "en" | "zh"
const dictionaries = {
fr: () => import('./dictionaries/fr.json').then((module) => module.default),
en: () => import('./dictionaries/en.json').then((module) => module.default),
zh: () => import('./dictionaries/zh.json').then((module) => module.default),
}
type TDictionary = ReturnType<(typeof dictionaries)["fr"]>; // has to be the return type
// The type of lang has to be union type
// otherwise you will get the error "Element implicitly has an 'any' type"
export default async function getDictionary(lang: Lang): Promise<TDictionary> {
return dictionaries[lang]();
}