Building a Multilingual Static Blog with Astro
Why Astro
I went with Astro for a few straightforward reasons:
- Pure static output: after build, it’s just HTML/CSS/JS — no Node runtime needed
- MDX support: embed React components directly in Markdown
- On-demand loading: interactive components only load when the browser is idle via
client:idle
Total Bundle=Static HTML+i∑1[visiblei]⋅Componenti
Compared to VitePress (Vue-locked, limited extensibility) and Next.js (requires a server), Astro is the lightest option.
Math Rendering
LaTeX support is essential. Setup is simple with remark-math + rehype-katex:
Inline: ∇f=(∂x∂f,∂y∂f)
Block:
L(θ)=−N1i=1∑N[yilogy^i+(1−yi)log(1−y^i)]
Syntax Highlighting
Shiki provides dual-theme highlighting (light + dark), server-rendered with zero JS cost:
import torch
def cross_entropy(logits: torch.Tensor, targets: torch.Tensor) -> torch.Tensor:
log_probs = torch.log_softmax(logits, dim=-1)
return -log_probs.gather(dim=-1, index=targets.unsqueeze(-1)).mean()
Multilingual Support
This very post is an example. Click the language toggle in the top-right corner to switch to the Chinese version.
The translation workflow is simple:
- Write the post in Chinese as an
.mdx file
- Copy the prompt from
TRANSLATE_PROMPT.md into any LLM
- Paste the entire file content
- The LLM returns a complete
.en.mdx file — save it directly
No translation plugins or backend services needed — everything is resolved at build time.
用 Astro 搭建多语言静态博客
为什么选择 Astro
最终选了 Astro,原因很简单:
- 纯静态输出:构建后只有 HTML/CSS/JS,不需要 Node 运行时
- MDX 支持:可以在 Markdown 里直接嵌入 React 组件
- 按需加载:通过
client:idle 指令,交互组件只在浏览器空闲时才加载
Total Bundle=Static HTML+i∑1[visiblei]⋅Componenti
相比 VitePress(Vue 生态,扩展性一般)和 Next.js(需要服务端),Astro 是最轻量的选择。
数学公式
博客必须支持 LaTeX。配置很简单,用 remark-math + rehype-katex:
行内公式:∇f=(∂x∂f,∂y∂f)
块级公式:
L(θ)=−N1i=1∑N[yilogy^i+(1−yi)log(1−y^i)]
代码高亮
Shiki 提供双主题(亮色 + 暗色),服务端渲染,零运行时成本:
import torch
def cross_entropy(logits: torch.Tensor, targets: torch.Tensor) -> torch.Tensor:
log_probs = torch.log_softmax(logits, dim=-1)
return -log_probs.gather(dim=-1, index=targets.unsqueeze(-1)).mean()
多语言支持
这篇文章本身就是一个例子。点击右上角的语言切换按钮,可以切换到英文版本。
翻译工作流很简单:
- 用中文写完
.mdx 文件
- 复制
TRANSLATE_PROMPT.md 里的提示词到任意 LLM
- 粘贴整个文件内容
- LLM 返回完整的
.en.mdx 文件,直接保存即可
不需要任何翻译插件或后端服务,一切都在构建时完成。