RSS isn't dead — it just moved to better readers. Here's how I added bilingual feeds to a Next.js blog and made them discoverable on Folo.
Why RSS in 2026?
The Architecture
Mdx
---
title: "English Title"
titleCn: "中文标题"
---
<En>
English content here...
</En>
<Cn>
中文内容...
</Cn>
- Extract only the relevant language block from each post
- Convert raw MDX to clean HTML (not markdown — RSS readers expect HTML)
- Serve two separate feeds at /rss.xml and /rss-cn.xml
- Make them discoverable via autodiscovery, UI entry points, and Folo
The Gotcha: Static Generation
Typescript
// src/app/rss.xml/route.ts
export const dynamic = "force-static";
MDX → HTML Conversion
- Extracts the <En> or <Cn> block based on a lang parameter
- Strips MDX imports and custom React components
- Converts markdown to HTML: headings, bold, italic, code blocks, links, lists, blockquotes
- Converts markdown tables to proper <table><tr><td> HTML
- Converts  to <img> tags
- Escapes XML entities
Two Feeds, One Utility
Typescript
// src/utils/rss.ts
export function generateRssFeed({
lang,
feedPath,
}: {
lang: "en" | "cn";
feedPath: string;
}): string {
const posts = getPosts(["src", "app", "blog", "posts"]);
// ... generate RSS XML with language-specific content
}
Typescript
// src/app/rss.xml/route.ts
import { generateRssFeed } from "@/utils/rss";
export const dynamic = "force-static";
export async function GET() {
const feed = generateRssFeed({ lang: "en", feedPath: "/rss.xml" });
return new Response(feed, {
headers: { "Content-Type": "application/xml; charset=utf-8" },
});
}
Discovery: Three Entry Points
Html
<link rel="alternate" type="application/rss+xml"
href="/rss.xml" title="Blog (English)" />
<link rel="alternate" type="application/rss+xml"
href="/rss-cn.xml" title="Blog (中文)" />
Claiming on Folo
Xml
<follow_challenge>
<feedId>YOUR_FEED_ID</feedId>
<userId>YOUR_USER_ID</userId>
</follow_challenge>
Result
- English: mjshao.fun/rss.xml
- Chinese: mjshao.fun/rss-cn.xml
RSS 没死——只是换了更好的阅读器。这篇讲讲怎么给 Next.js 博客加双语 RSS,并在 Folo 上被发现。
2026 了为什么还要 RSS?
架构
Mdx
---
title: "English Title"
titleCn: "中文标题"
---
<En>
English content here...
</En>
<Cn>
中文内容...
</Cn>
- 从每篇文章中提取对应语言的内容块
- 把 MDX 转成干净的 HTML(RSS 阅读器要 HTML,不是 markdown)
- 分别提供 /rss.xml(英文)和 /rss-cn.xml(中文)
- 让用户能发现这些 feed——自动发现、UI 入口、Folo 认领
踩坑:静态生成
Typescript
// src/app/rss.xml/route.ts
export const dynamic = "force-static";
MDX → HTML 转换
- 根据 lang 参数提取 <En> 或 <Cn> 内容块
- 去掉 MDX import 和自定义 React 组件
- 把 markdown 转成 HTML:标题、加粗、斜体、代码块、链接、列表、引用
- 把 markdown 表格转成 <table><tr><td> HTML
- 把  转成 <img> 标签
- 转义 XML 实体
两个 Feed,一个工具函数
Typescript
// src/utils/rss.ts
export function generateRssFeed({
lang,
feedPath,
}: {
lang: "en" | "cn";
feedPath: string;
}): string {
const posts = getPosts(["src", "app", "blog", "posts"]);
// ... 根据语言生成 RSS XML
}
Typescript
// src/app/rss.xml/route.ts
import { generateRssFeed } from "@/utils/rss";
export const dynamic = "force-static";
export async function GET() {
const feed = generateRssFeed({ lang: "en", feedPath: "/rss.xml" });
return new Response(feed, {
headers: { "Content-Type": "application/xml; charset=utf-8" },
});
}
三个发现入口
Html
<link rel="alternate" type="application/rss+xml"
href="/rss.xml" title="Blog (English)" />
<link rel="alternate" type="application/rss+xml"
href="/rss-cn.xml" title="Blog (中文)" />
在 Folo 上认领
Xml
<follow_challenge>
<feedId>你的FEED_ID</feedId>
<userId>你的USER_ID</userId>
</follow_challenge>