import { resolve as resolvePath } from 'path';
import { readFile } from 'fs/promises';
// import type baseLanguage from '@app/locales/en-AU.json';
// This const is the data from the .json file
const baseLanguage = {
botName: 'Jive',
number: 123
};
const defaultLanguage = 'en-AU' as const;
const knownLanguages = [
'en-AU',
'en-US'
] as const;
type I18n = Record<typeof knownLanguages[number], Partial<typeof baseLanguage>>;
const i18n = {} as I18n;
const getLanguage = async (language: typeof knownLanguages[number] = defaultLanguage) => {
try {
i18n[language] ?? await readFile(resolvePath(__dirname, 'src/locales/', `${language}.json`), 'utf-8').then(file => {
const loadedLanguage = JSON.parse(file) as Partial<typeof baseLanguage>;
i18n[language] = loadedLanguage;
return loadedLanguage;
});
} catch { }
return {} as Partial<typeof baseLanguage>;
};
export const t = async (key: keyof I18n[keyof typeof i18n], language: typeof knownLanguages[number] = defaultLanguage) => {
// Check if the language is loaded
// If not then load it
const loadedLanguage = await getLanguage(language);
// Check if the key is in the language
const value = loadedLanguage[key];
if (value === undefined) throw new Error(`Missing key "${key}" for "${language}".`);
return value;
};
void t('botName').then(value => {
console.log(typeof value); // string | number <-- this should be "Jive" as a const
});
#How can I have the return type inferred based on the key and use const?
47 messages · Page 1 of 1 (latest)
I think your problem is you're returning a Partial<typeof baseLanguage> which might not have the botname key
Is there another way around this then? I know the base language will contain all keys but others may be missing some. 🤔
can you just remove the Partial for the base language type then after you parse it
if it can fail with an error, you don't really have a guarantee it really is populated though
Why should value be of type Jive?
so im not sure you really can guarantee it is jive
You can't, because if it wasn't the base language, the type will be different.
Unless it's Jive in every single language, then you are not translating anything.
Yes I get that.. the reason it's Jive is that it shows the base language to the developer while in the IDE, this is the same as some other i18n setups work. Figured I'd ask in here about this before I go and look at how they're all doing it.
If other i18n setups work like that, then that's just bad design.
That's simply lying to TS about the type.
I'm trying to explain to you why that's a bad idea, but sure.
i didnt ask about that...
thanks for the help. ill have a think about how i can change this around. 🤔
I dont have a full understanding of what the intent is
key in value as const out.
what is the purpose of base language
to hold all the keys that should exist in the typing for t(key)
I see
The idea is I can do t('botName') and in the IDE we'll get "Jive" as a const and at runtime the value of whatever language.
I may be completely going at this in the wrong direction.
so first of all your const baseLanguage = {} is not immutable, so it needs to be const to do anything
but that doesnt solve the problem, just pointing it out
or, satisfies
For what its worth that was a json import before which I believe was making it const.
oh....
you know what that fixes it.
added as const to the baseLanguage and we're good.
well not good but closer..
there's still the issue of if it fails, you're asserting a type that's incorrect
still have the issue of it returning a combined union of all possible types.
Preview:```ts
// import type baseLanguage from '@app/locales/en-AU.json';
// This const is the data from the .json file
const baseLanguage = {
botName: 'Jive',
number: 123
} as const;
const defaultLanguage = 'en-AU' as const;
const knownLanguages = [
'en-AU',
...```
You can choose specific lines to embed by selecting them before copying the link.
do you have to return an empty object? can you just throw if it fails? you shouldn't be importing files that don't exist, right?
so you can do an assertion function
Here's exactly what you want, but yeah, imo still a bad idea.
What was the change needed?
added const
as const your baseLanguage, changed the t signature.
!resolved
I just removed the getLanguage implementation because it's irrelevant to the question.
I see