Closed rentalhost closed 11 months ago
As expected, the issue comes from this Object.fromEntries
that doesn't narrow the correct type information:
You can manually cast the result to get the correct type:
import { createI18nServer } from "next-international/server";
const locales = ["en", "pt"] as const;
export const { getI18n } = createI18nServer(
Object.fromEntries(
locales.map((locale) => [locale, () => import(`./${locale}`)]),
) as Record<(typeof locales)[number], () => Promise<typeof import('./en')>>
);
Perfect, I'll give it a try. I almost tried to do this but thought it wouldn't work and gave up (I was having trouble understanding the return precisely, which, in the end, was exactly the same problem that TS was having because of my mistake haha). Anyway, I thought TS would be able to understand the return on its own, but it seems to be having some kind of issue with Object.fromEntries()
that starts returning an any
instead of the precise type (even when using as consts
).
Yeah unfortunately many of these internal JS methods often return types that aren't narrowed properly and are too wide, for reasons that I ignore. I've tried on your CodeSanbox and it was working fine!
Have done something inspired from your proposals here! Just to give an idea:
export const getEnumKeys = (e: object): string[] => Object.keys(e).filter((key) => isNaN(Number(key)));
export default getEnumKeys;
type JSONPrimitiveLeafs = string | number | boolean | null;
type JSONLeafs = JSONPrimitiveLeafs | JSONPrimitiveLeafs[];
export type JSONData = {
[_: string]: JSONData | JSONData[] | JSONLeafs;
};
export type TypedLeafsJSONData<LeafsTypes extends JSONLeafs, AllowObjArrays extends 'ALLOW_OBJ_ARRAYS' | never = never> = {
[_: string]: TypedLeafsJSONData<LeafsTypes> | (AllowObjArrays extends never ? never : TypedLeafsJSONData<LeafsTypes>[]) | LeafsTypes;
};
type LanguageFlagKey = keyof typeof ELanguagesFlag;
export type LanguageFlag = LanguageFlagKey;
import DEFAULT_LANGUAGE_OBJ from '@/i18n/locales/fr';
export enum ELanguagesFlag {
fr,
en
}
export type VocabBase = typeof DEFAULT_LANGUAGE_OBJ;
export const LANGUAGES: LanguageFlag[] = getEnumKeys(ELanguagesFlag) as LanguageFlag[];
export const DEFAULT_LANGUAGE: LanguageFlag = DEFAULT_LANGUAGE_OBJ._infos.lng; // * ... Could be also = LANGUAGES[0], or just a raw ELanguagesFlag key, like `"fr"`. But I'd prefer to link everything to the `DEFAULT_LANGUAGE_OBJ`, cuz Im a lazybones.
type AllowedVocabObjValuesTypes = string;
type VocabObjValue = AllowedVocabObjValuesTypes;
type NextInternationalMagic = {
default: VocabBase;
};
export type LocalesObj = Record<LanguageFlag, () => Promise<NextInternationalMagic>>;
export type LocalesGetterConfigObjTypeConstraint = Record<LanguageFlag, () => Promise<TypedLeafsJSONData<VocabObjValue>>>;
export const LOCALES_OBJ = Object.fromEntries(
LANGUAGES.map((language) => [language, () => import(`@/i18n/locales/${language}`)])
) as LocalesObj satisfies LocalesGetterConfigObjTypeConstraint; // * ... NOT perfectly typesafe! See this to enforce the type safety of your different locales schemas: https://github.com/QuiiBz/next-international/issues/225
export default LOCALES_OBJ;
export const { getI18n: getServerSideI18n, getScopedI18n, getStaticParams } = createI18nServer(LOCALES_OBJ);
export const { useI18n: getClientSideI18n, useScopedI18n, I18nProviderClient, useCurrentLocale } = createI18nClient(LOCALES_OBJ);
Describe the bug When using the
createI18nServer
(or client) function to create internationalization providers with locales provided from an external source, thet
function (e.g.,t("example")
) generates a TypeScript error, indicating that two arguments are expected, but only one is provided.To Reproduce Steps to reproduce the behavior:
t
function with a single parameter, e.g.,t("example")
.Expected behavior I expected the
t
function to work with a single parameter (t("example")
) without generating TypeScript errors.Screenshots
![image](https://github.com/QuiiBz/next-international/assets/421851/d5b37451-b77f-4186-88d0-e26971f252ce)
About (please complete the following information):
next-international version: 1.1.1 Next.js version: 13.5.4 TypeScript version: 5.2.2
Additional context
I created a CodeSandbox to illustrate the issue. Despite the TypeScript error, the translated text ("example in en") appears as expected. It seems that the usage of
Object.fromEntries()
in conjunction with external locales may be causing this issue.