Commit 16eb5ab
Changed files (5)
src
src/components/Header.astro
@@ -2,7 +2,7 @@
import { getIntlayer, type Locale } from "intlayer";
import { SITE_CONFIG } from "@/config.ts";
-import { getRelativeLocaleUrl, url } from "@/utils/url.ts";
+import { getRelativeLocaleUrl } from "@/utils/url.ts";
import LocaleSwitcher from "@/components/widgets/LocaleSwitcher.astro";
@@ -21,7 +21,7 @@ const globalI18n = getIntlayer("global", locale);
<ul>
<li><a href={getRelativeLocaleUrl("/posts", locale)}>{globalI18n.posts}</a></li>
<li><a href={getRelativeLocaleUrl("/about", locale)}>{globalI18n.about}</a></li>
- <li><a href={url("/feed.atom")}>{globalI18n.feed}</a></li>
+ <li><a href={getRelativeLocaleUrl("/feed.atom", locale).slice(0, -1)}>{globalI18n.feed}</a></li>
</ul>
<LocaleSwitcher availableLocales={availableLocales} />
</nav>
src/layouts/BaseLayout.astro
@@ -3,7 +3,12 @@ import { Font } from "astro:assets";
import { getIntlayer, type Locale } from "intlayer";
import { DEFAULT_LOCALE, SITE_CONFIG } from "@/config";
-import { getPathWithoutLocale, getRelativeLocaleUrl } from "@/utils/url.ts";
+import {
+ getPathWithoutLocale,
+ getRelativeLocaleUrl,
+ joinUrl,
+ url,
+} from "@/utils/url.ts";
import Footer from "@/components/Footer.astro";
import Header from "@/components/Header.astro";
@@ -55,6 +60,13 @@ const getAbsoluteLocaleUrl = (
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" href="/favicon.ico" />
<link rel="sitemap" href="/sitemap-index.xml" />
+ <link
+ rel="alternate"
+ type="application/atom+xml"
+ hreflang={locale ?? DEFAULT_LOCALE}
+ title="Atom Feed"
+ href={url(joinUrl(locale ?? DEFAULT_LOCALE, "feed.atom"))}
+ />
<link
rel="alternate"
type="application/atom+xml"
src/pages/[locale]/feed.atom.ts
@@ -0,0 +1,37 @@
+import type { APIRoute, GetStaticPaths } from "astro";
+import { getCollection } from "astro:content";
+import type { Locale } from "intlayer";
+
+import { SITE_CONFIG } from "@/config.ts";
+import { createFeed, localePostUrl } from "@/utils/feed.ts";
+import { getRelativeLocaleUrl, joinUrl, url } from "@/utils/url.ts";
+
+export const getStaticPaths = (() => {
+ return SITE_CONFIG.locales.map((locale) => ({ params: { locale } }));
+}) satisfies GetStaticPaths;
+
+export const GET: APIRoute = async ({ site, params }) => {
+ if (!site) {
+ throw new Error("`site` must be configured in astro.config to build feeds");
+ }
+ const origin = site.origin;
+ const locale = params.locale as Locale;
+ const posts = (await getCollection("posts")).filter((post) =>
+ post.id.startsWith(`${locale}/`)
+ );
+ const feed = await createFeed({
+ id: new URL(getRelativeLocaleUrl("/", locale), origin).toString(),
+ feedUrl: new URL(url(joinUrl(locale, "feed.atom")), origin).toString(),
+ favicon: new URL(url("/favicon.ico"), origin).toString(),
+ title: SITE_CONFIG.title,
+ description: SITE_CONFIG.description[locale],
+ language: locale,
+ site: origin,
+ posts,
+ postUrl: (post) => localePostUrl(post, origin),
+ });
+
+ return new Response(feed.atom1(), {
+ headers: { "Content-Type": "application/atom+xml" },
+ });
+};
src/pages/feed.atom.ts
@@ -1,8 +1,8 @@
import type { APIRoute } from "astro";
import { getCollection } from "astro:content";
-import { SITE_CONFIG } from "@/config.ts";
-import { createFeed } from "@/utils/feed.ts";
+import { DEFAULT_LOCALE, SITE_CONFIG } from "@/config.ts";
+import { createFeed, localePostUrl } from "@/utils/feed.ts";
import { url } from "@/utils/url.ts";
export const GET: APIRoute = async ({ site }) => {
@@ -15,11 +15,11 @@ export const GET: APIRoute = async ({ site }) => {
feedUrl: new URL(url("/feed.atom"), origin).toString(),
favicon: new URL(url("/favicon.ico"), origin).toString(),
title: SITE_CONFIG.title,
- description: SITE_CONFIG.description,
- language: SITE_CONFIG.locale,
+ description: SITE_CONFIG.description[DEFAULT_LOCALE],
+ language: DEFAULT_LOCALE,
site: origin,
posts: await getCollection("posts"),
- postUrl: (post) => new URL(url(`/posts/${post.id}`), origin).toString(),
+ postUrl: (post) => localePostUrl(post, origin),
});
return new Response(feed.atom1(), {
src/utils/feed.ts
@@ -2,6 +2,9 @@ import type { CollectionEntry } from "astro:content";
import { Feed } from "feed";
import { SITE_CONFIG } from "@/config.ts";
+import { getPostLocaleSlug } from "@/utils/content.ts";
+import { getRelativeLocaleUrl } from "@/utils/url.ts";
+
import { rehypeAbsoluteLinks } from "@/utils/plugins/absolute-links.ts";
import { rehypeCleanEndnotes } from "@/utils/plugins/clean-endnotes.ts";
import { rehypeCleanProperties } from "@/utils/plugins/clean-properties.ts";
@@ -85,3 +88,12 @@ export async function createFeed(data: FeedData): Promise<Feed> {
return feed;
}
+
+/** Absolute URL of a post's page in the locale it was written for. */
+export function localePostUrl(
+ post: CollectionEntry<"posts">,
+ origin: string,
+): string {
+ const { locale, slug } = getPostLocaleSlug(post);
+ return new URL(getRelativeLocaleUrl(slug, locale), origin).toString();
+}