main
1import type { CollectionEntry } from "astro:content";
2import type { AstroComponentFactory } from "astro/runtime/server/index.js";
3
4import { DEFAULT_LOCALE } from "@/config.ts";
5
6const contents = import.meta.glob<{ default: AstroComponentFactory }>(
7 "/src/contents/**/*.typ",
8);
9
10/**
11 * Load content from `contents/<name>.<locale>.typ` or `contents/<name>/<locale>.typ`
12 */
13export async function loadLocaleContent(
14 name: string,
15 locale: string = DEFAULT_LOCALE,
16) {
17 const hasFlatFile = Boolean(contents[`/src/contents/${name}.${locale}.typ`]);
18 const hasNestFile = Boolean(contents[`/src/contents/${name}/${locale}.typ`]);
19
20 const resolvedLocale = hasFlatFile || hasNestFile ? locale : DEFAULT_LOCALE;
21
22 const loadedFile =
23 contents[`/src/contents/${name}.${resolvedLocale}.typ`] ||
24 contents[`/src/contents/${name}/${resolvedLocale}.typ`];
25 if (!loadedFile) {
26 throw new Error(`Missing content: /src/contents/${name}.${locale}.typ`);
27 }
28
29 return { Content: (await loadedFile()).default, locale: resolvedLocale };
30}
31
32export function getPostsLocaleMap(posts: CollectionEntry<"posts">[]) {
33 const postsLocaleMap: Record<
34 string,
35 Record<string, CollectionEntry<"posts">>
36 > = posts.reduce(
37 (
38 acc: Record<string, Record<string, CollectionEntry<"posts">>>,
39 curr: CollectionEntry<"posts">,
40 ) => {
41 const [locale, slug] = curr.id.split("/");
42 acc[slug] = { ...acc[slug], [locale]: curr };
43 return acc;
44 },
45 {},
46 );
47 return postsLocaleMap;
48}
49
50export function getLocalePosts(
51 posts: CollectionEntry<"posts">[],
52 locale: string = DEFAULT_LOCALE,
53) {
54 const postsLocaleMap = getPostsLocaleMap(posts);
55 return Object.values(postsLocaleMap).map(
56 (locales) => locales[locale] || locales[DEFAULT_LOCALE],
57 );
58}
59
60export function getPostLocaleSlug(post: CollectionEntry<"posts">) {
61 return {
62 locale: post.id.split("/")[0],
63 slug: `/posts/${post.id.split("/").at(-1)}`,
64 };
65}