English | 简体中文
A bilingual personal blog system built with Astro, file-based authoring, Feishu auto-sync pipeline, and GitHub Pages deployment.
This repository is not an unrestricted open-source template. Usage is governed by LICENSE. Without prior written permission, commercial use, redeployment, and derivative distribution are prohibited.
- Bilingual site structure:
/zhand/en - Static blog rendering with Astro + MDX
- Locale switch and translation pairing via
translationKey - Light/Dark theme, post TOC, previous/next navigation, code copy button
- Category and tag filters with i18n label mapping
- Local static search index endpoint:
/search-index.json /adminis disabled by default for security hardening- Optional Feishu Drive -> content sync (with optional AI zh->en translation)
- GitHub Actions deployment to GitHub Pages
- Astro 5
- MDX
- Tailwind CSS (
@tailwindcss/typography) - giscus (GitHub Discussions)
- GitHub Actions + GitHub Pages
- Feishu API +
feishu-docx
src/
components/
config/
content/
blog/
zh/
en/
layouts/
lib/
pages/
zh/
en/
search-index.json.ts
styles/
public/
images/
uploads/
oauth-proxy/
api/
vercel.json
scripts/
translate-post.mjs
feishu-cms-bridge/
.github/workflows/
deploy.yml
feishu-sync.yml
- Node.js
>= 20(Node 22 is used in CI) - npm
npm install
cp .env.example .env.local
npm run devLocal URL: http://localhost:4321
Build and check:
npm run check
npm run buildnpm run dev # local dev server
npm run build # production build
npm run preview # preview built site
npm run check # astro check
npm run check:all # check + build
npm run translate -- --source src/content/blog/zh/your-post.mdx
npm run feishu:sync # sync Feishu folder into src/content/blog- Site root (
/) performs language-based redirect (zhif browser language starts withzh, otherwiseen). - Main routes per locale:
/[locale]/[locale]/blog/[locale]/about/[locale]/projects/[locale]/uses/[locale]/contact/[locale]/search/[locale]/[...slug](post pages)
- Search index endpoint:
/search-index.json
Post schema is defined in src/content.config.ts, including:
- core fields:
lang,title,description,date,updated,category,tags,draft,translationKey - optional fields:
summary,seoDescription,keywords,social,heroImage
See .env.example for the full list.
Key groups:
- Site branding/SEO:
PUBLIC_SITE_*,PUBLIC_AUTHOR_*,PUBLIC_OG_IMAGE - Social/contact:
PUBLIC_SOCIAL_GITHUB_URL,PUBLIC_CONTACT_EMAIL_* - giscus:
PUBLIC_GISCUS_* - Taxonomy display overrides:
PUBLIC_CATEGORY_MAP_ZH,PUBLIC_CATEGORY_MAP_ENPUBLIC_TAG_MAP_ZH,PUBLIC_TAG_MAP_EN
- Feishu bridge:
FEISHU_*,TRANSLATE_*
- Chinese posts:
src/content/blog/zh/*.mdx - English posts:
src/content/blog/en/*.mdx
npm run translate -- --source src/content/blog/zh/your-post.mdx- reads
config/translation.config.json - uses prompt template
config/translation.prompt.md - writes translated post to
src/content/blog/en/ - optionally creates
.review.mdQA checklist
- Public
/adminroute is intentionally disabled. - If you need CMS UI again later, deploy it behind a private auth gateway and do not expose it on the public Pages domain.
Required IDs (typically configured as GitHub Secrets in CI):
PUBLIC_GISCUS_REPO_IDPUBLIC_GISCUS_CATEGORY_GENERAL_IDPUBLIC_GISCUS_CATEGORY_ENGINEERING_IDPUBLIC_GISCUS_CATEGORY_LIFE_ID
If missing, post pages display a fallback hint instead of a broken widget.
Bridge code: scripts/feishu-cms-bridge/
Main behavior:
- scans Feishu folder tree (
zh/en) - converts doc/docx to Markdown/MDX
- downloads assets to
public/uploads/feishu/... - generates frontmatter and writes posts into
src/content/blog/{zh|en} - optionally translates zh->en and generates SEO metadata via AI
- optionally auto-commits and pushes
Local run:
npm run feishu:syncWorkflow automation:
feishu-sync.yml- scheduled daily (
0 2 * * *) + manual trigger
Triggers:
pushtomain- successful
workflow_runfromFeishu CMS Sync - manual dispatch
Build output is deployed to GitHub Pages via actions/deploy-pages.
- checks out full history
- runs
npm run feishu:sync - auto-pushes synced content to
main - then deployment is handled by
deploy.yml
- Update project/about/uses/contact static data in
src/lib/page-data.ts - Adjust category/tag display mapping in env (
PUBLIC_CATEGORY_MAP_*,PUBLIC_TAG_MAP_*) - Update site identity defaults in
src/config/site.tsand env vars - Keep locale pairs aligned via
translationKey
- giscus not rendered:
- check
PUBLIC_GISCUS_REPO_IDand category IDs
- check
- Feishu sync exits early:
- verify
FEISHU_APP_ID,FEISHU_APP_SECRET, and folder token/name - verify
TRANSLATE_API_KEYwhen AI translation is enabled - tune
FEISHU_AI_TIMEOUT_MSif the provider is slow for long documents - keep
FEISHU_AI_FAIL_ON_TRANSLATION_ERROR=falseto let nightly sync continue with zh content and preserved stale en output on retryable AI failures
- verify
See LICENSE.