I'm trying to create my own solution for i18n, but the problem is general and concerns typing on JSON records with Astro Content Collections.
To keep it simple, I'm trying to get all the keys of a JSON and make a type out of them.
At the moment I'm using z.record(z.string()) which isn't optimal.
I think the code is more useful than explanations.
Exemple JSON
{
"name": "English (NA)",
"default_language": true,
"translations": {
"foo": "Foo",
"bar": "Bar",
}
}```
The config content collections files
```TS
const i18nCollection = defineCollection({
type: 'data',
schema: z.object({
default_language: z.boolean().default(false),
name: z.string(),
translations: z.record(z.string())
})
});```
A useful method for obtaining translations depending on the language of the URL bar.
```ts
export const getTranslations = async (url: URL) => {
// Get the i18n collection including all jsons files
const i18nCollections = await getCollection('i18n');
// Get the lang from the url example: "en-us"
const [, urlLang] = url.pathname.split('/');
// Get the default language, if not found throw an error
const defaultLang = i18nCollections.find((i18nCollection) => i18nCollection.data.default_language)?.id;
if (!defaultLang) throw new Error('Default language not found');
// Get Entry from lang id
const content =
i18nCollections.find((i18nCollection) => i18nCollection.id === urlLang) ??
i18nCollections.find((i18nCollection) => i18nCollection.id === defaultLang);
if (!content) throw new Error(`Language ${urlLang} not found`);
// return values
const lang = content.id;
const translate = content.data.translations;
const names = content.data.name;
return { lang, translate, names };
};```
Example of use on my pages.
```ts
const { lang, translate, names } = await getTranslations(Astro.url);
console.log(translate['baz']);```
In my specific case, I would like the translations field to look like this: Record<TranslateKey, String>.
Each key in the translate attribute must be typed.
Example baz don't exist but typescript doesn't detect it because it's not a Record<String, String>.
I wonder if Astro allows the typing of JSON records with collections anf if yes, how to do ?