npx superpowers-zh 會自動識別專案目錄並安裝;識別不出的用 --tool 指定。',
+ instLabel: '我用的是',
+ instNoteAuto: '在你的專案根目錄執行,自動識別 {name} 並安裝。安裝後重啟工具即可生效。',
+ instNoteManual: '{name} 無法自動識別,需用 --tool 顯式指定。在專案根目錄執行,安裝後重啟工具即可生效。',
+ skTitle: '{n} 個 Skill,覆蓋開發全流程',
+ skSub: '點擊任意卡片查看完整操作文件。',
+ skSearch: '搜尋 skill…(如 除錯 / review / TDD)',
+ skEmpty: '沒有符合的 skill。',
+ skDetail: '查看文件 →',
+ tagCn: '中國原創',
+ ucTitle: '典型使用場景', ucSub: '每個場景背後都是一組協同工作的 skill。',
+ toolsTitle: '一套 skill,20 款工具通用', toolsSub: '換工具不用換習慣,方法論跟著你走。',
+ faqTitle: '常見問題',
+ bookTitle: '裝好之後,配上方法論效率翻倍',
+ bookDesc: '《AI 編程實戰 · 方法論三卷書》—— 10 個 AI 編程工具完整教程 + 真實踩坑。線上書 + PDF,永久免費。',
+ bookBtn: '免費閱讀 ↗',
+ aiolaolaBtn: '免費學 AI 編程 · aiOlaOla ↗',
+ ctaTitle: '準備好讓 AI 真正會幹活了嗎?',
+ ctaDesc: '一條命令,{n} 個實戰方法論裝進你的工具。免費、開源、零依賴。',
+ ctaBtn1: '查看安裝命令', ctaBtn2: '⭐ Star on GitHub',
+ footCols: [
+ { h: '產品', links: [['特性', '#why'], ['Skills', '#skills'], ['支援工具', '#tools'], ['FAQ', '#faq']] },
+ { h: '資源', links: [['GitHub', 'https://github.com/jnMetaCode/superpowers-zh'], ['npm', 'https://www.npmjs.com/package/superpowers-zh'], ['方法論三卷書', 'https://book.aibuzhiyu.com/']] },
+ { h: '生態', links: [['aiOlaOla · 從零學會 AI 編程', 'https://aiolaola.com/?utm_source=sp1'], ['X / Twitter', 'https://x.com/jnMetaCode'], ['公眾號 AI不止語', 'https://aiolaola.com/'], ['姊妹專案', 'https://github.com/jnMetaCode']] },
+ { h: '社群', links: [['提交 Issue', 'https://github.com/jnMetaCode/superpowers-zh/issues'], ['貢獻指南', 'https://github.com/jnMetaCode/superpowers-zh/blob/main/CLAUDE.md'], ['聯絡信箱', 'mailto:jnMetaCode@qq.com']] },
+ ],
+ footTag: 'AI 編程超能力 · 中文增強版 · MIT License',
+ copyright: '© 2026 superpowers-zh · MIT License',
+ followUs: '掃碼關注', qrWechat: '公眾號 · AI不止語', qrDouyin: '抖音 · @AI不止語(AIBZY)',
+ copy: '複製', copied: '已複製 ✓',
+ backToSkills: '← 返回全部 Skill',
+ detailInstall: '安裝此 skill',
+ detailSource: '在 GitHub 查看原始檔 ↗',
+ features: [
+ { icon: '🧠', t: '20 個實戰方法論', d: '不是 prompt 範本,是經過跨會話對抗式壓力測試調優的工作方法論 —— 從頭腦風暴到 TDD、除錯、程式碼審查。' },
+ { icon: '🔌', t: '20 款工具通用', d: '一套 skill,Claude Code / Cursor / Codex / Gemini CLI / Windsurf… 全適配,換工具不用換習慣。' },
+ { icon: '⚡', t: '一條命令安裝', d: 'npx superpowers-zh 自動識別專案裡用的是哪款工具並安裝,零設定,裝完重啟即生效。' },
+ { icon: '🇨🇳', t: '中國原創 Skills', d: '中文程式碼審查話術、中文提交規範、中文文件排版、國內 Git 平台(Gitee/Coding/極狐)設定 —— 上游沒有。' },
+ { icon: '📖', t: '完整漢化上游', d: '同步 obra/superpowers(250k+ ⭐),核心 skill 全部中文母語化,不是機翻,是逐條校準。' },
+ { icon: '🔓', t: '零依賴 · MIT 開源', d: '純 Markdown skill,不引入任何外部依賴、不連網、不上傳程式碼,按需觸發零執行時開銷。' },
+ ],
+ pipeline: [
+ { n: '頭腦風暴', d: '動手前先理清意圖與需求' },
+ { n: '寫計畫', d: '把需求拆成可執行步驟' },
+ { n: 'TDD', d: '先寫測試再寫實作' },
+ { n: '系統化除錯', d: '先重現定位再改' },
+ { n: '程式碼審查', d: '合併前嚴謹驗收' },
+ { n: '完成前驗證', d: '用證據證明真的好了' },
+ ],
+ usecases: [
+ { tag: '開發新功能', skills: 'brainstorming → writing-plans → TDD', desc: 'AI 先反問需求、寫出實作計畫,再用測試驅動落地,而不是上來就糊一坨程式碼。' },
+ { tag: '修 Bug', skills: 'systematic-debugging', desc: '強制先重現、定位根因,再提修復方案 —— 杜絕「猜一個改一下」的瞎試迴圈。' },
+ { tag: '提交 / 合併前', skills: 'verification-before-completion → code-review', desc: '必須跑驗證命令、拿證據說話,再走一輪程式碼審查,才允許聲稱「完成」。' },
+ { tag: '國內團隊協作', skills: 'chinese-commit-conventions → chinese-code-review', desc: '中文 commit 規範 + 分級 review 話術,配 Gitee / Coding / 極狐 GitLab 工作流。' },
+ ],
+ faq: [
+ { q: 'superpowers-zh 是免費的嗎?', a: '完全免費。MIT 協議開源,永久免費,不含任何付費牆或訂閱。' },
+ { q: '支援哪些 AI 編程工具?', a: '共 20 款:Claude Code、Cursor、Windsurf、Codex CLI、Gemini CLI、Kiro、Trae、Qoder、CodeBuddy(騰訊)、CodeArts(華為雲碼道)、Aider、OpenCode、Qwen Code、Antigravity、DeerFlow、VS Code(Copilot)、Copilot CLI、Hermes Agent、Claw Code、OpenClaw。' },
+ { q: 'superpowers-zh 有哪些獨特價值?', a: '一套完整中文化的系統工作方法論:從頭腦風暴、規劃、TDD 到除錯、程式碼審查,每個 skill 都是實戰驗證的工作流;並疊加 4 個面向中國開發者的原創 skill(中文程式碼審查 / Git 工作流 / 文件規範 / 提交規範),適配 20 款 AI 編程工具。MIT 協議開源,永久免費。' },
+ { q: '安裝後怎麼生效?', a: 'npx 會把 skill 檔案裝到你專案對應工具的目錄(如 .claude/skills/),重啟 AI 工具後,它會在恰當時機自動觸發相應 skill —— 無需你每次手動呼叫。' },
+ { q: '能一次裝好、所有專案都用嗎?(全域安裝)', a: '能。npx superpowers-zh --global 裝到工具的使用者級目錄(如 ~/.claude/skills),所有專案自動共享,更新時只需重裝一次。專案級優先、全域兜底,二者可共存。支援全域的工具(均為各工具文件確認的載入路徑):Claude Code / Codex CLI / Qoder / Windsurf / Qwen Code / OpenClaw / OpenCode;其餘工具(含 Gemini / Antigravity,有各自專屬全域方式)請在專案內安裝或參考對應文件。' },
+ { q: '會拖慢我的 AI 嗎?會上傳程式碼嗎?', a: '不會。skill 是按需觸發的純 Markdown,零執行時、不連網、不上傳任何程式碼或資料,全程在本機。' },
+ { q: '怎麼更新或解除安裝?', a: '更新:重新執行 npx superpowers-zh 覆蓋即可。解除安裝:npx superpowers-zh --uninstall 清理目前專案;全域安裝用 npx superpowers-zh --global --uninstall 清理。' },
+ ],
+ },
};
// ---- 读取 skills(含正文) ----
@@ -305,11 +389,30 @@ function loadSkills() {
return skills;
}
+// ---- 多语言配置:新增语言只需往这里加一项 + 写一个 T. 翻译对象 ----
+// dir: 该语言站点子目录(根语言为 '');hreflang: SEO 语言标记;label: 语言切换器显示名
+const LANGS = [
+ { code: 'zh', dir: '', label: '中文', hreflang: 'zh-CN' },
+ { code: 'en', dir: 'en/', label: 'EN', hreflang: 'en' },
+ { code: 'zht', dir: 'zh-Hant/', label: '繁體', hreflang: 'zh-Hant' },
+];
+const DEFAULT_DIR = LANGS[0].dir; // 根语言(zh)用于 x-default
+
// ---- 公共布局 ----
-// base: 资源相对前缀('' / '../' / '../../');langHref: 切换语言的目标 URL
-function layout({ lang, base, title, desc, body, langHref, canonical = '/', altZh = '/', altEn = '/en/', extraHead = '' }) {
+// pageClean: 语言无关的 canonical 后缀(首页 '';skill 页 'skills/')
+// pageFile: 语言无关的文件后缀,用于语言切换链接(首页 '';skill 页 'skills/.html')
+// base: 资源相对前缀('' / '../' / '../../'),仅用于品牌链接等相对引用
+function layout({ lang, base, title, desc, body, pageClean = '', pageFile = '', extraHead = '' }) {
const t = T[lang];
- const other = lang === 'zh' ? 'EN' : '中文';
+ const curDir = LANGS.find(l => l.code === lang).dir;
+ const canonical = `/${curDir}${pageClean}`;
+ const altLinks = LANGS
+ .map(l => ``)
+ .join('\n') + `\n`;
+ const langSwitch = LANGS
+ .filter(l => l.code !== lang)
+ .map(l => `${l.label}`)
+ .join('');
return `
@@ -322,9 +425,7 @@ function layout({ lang, base, title, desc, body, langHref, canonical = '/', altZ
${esc(title)}
-
-
-
+${altLinks}
@@ -351,7 +452,7 @@ ${extraHead}
${t.nav.faq}
${t.nav.learn}
${t.nav.github}
- ${other}
+ ${langSwitch}
@@ -387,8 +488,8 @@ function renderLanding(skills, lang) {
const fill = (s, map) => s.replace(/\{(\w+)\}/g, (_, k) => map[k]);
const cards = skills.map(s => {
- const title = lang === 'zh' ? s.title : s.titleEn;
- const d = lang === 'zh' ? s.desc : (s.descEn || s.desc);
+ const title = lang === 'en' ? s.titleEn : s.title;
+ const d = lang === 'en' ? (s.descEn || s.desc) : s.desc;
return `
${esc(title)}
${s.china ? `${t.tagCn}` : ''}
@@ -506,7 +607,7 @@ function renderLanding(skills, lang) {
// ---- skill 详情(操作文档)页正文 ----
function renderDetail(skill, lang) {
const t = T[lang];
- const title = lang === 'zh' ? skill.title : skill.titleEn;
+ const title = lang === 'en' ? skill.titleEn : skill.title;
const bodyHtml = renderMarkdown(skill.raw);
const cnNotice = lang === 'en'
? '📖 This skill\'s content is written in Chinese — superpowers-zh is a Chinese-localized toolkit.'
@@ -550,31 +651,28 @@ function build() {
copyFileSync(join(TEMPLATE, 'assets', 'qr-wechat.jpg'), join(DIST, 'assets', 'qr-wechat.jpg'));
copyFileSync(join(TEMPLATE, 'assets', 'qr-douyin.jpg'), join(DIST, 'assets', 'qr-douyin.jpg'));
- // 中文站(根)
- writeFileSync(join(DIST, 'index.html'), layout({
- lang: 'zh', base: '', title: T.zh.title, desc: T.zh.desc,
- body: renderLanding(skills, 'zh'), langHref: 'en/index.html',
- canonical: '/', altZh: '/', altEn: '/en/',
- }));
- // 英文站(/en/)
- writeFileSync(join(DIST, 'en', 'index.html'), layout({
- lang: 'en', base: '../', title: T.en.title, desc: T.en.desc,
- body: renderLanding(skills, 'en'), langHref: '../index.html',
- canonical: '/en/', altZh: '/', altEn: '/en/',
- }));
-
- // 详情(操作文档)页 ×2 语言
- for (const s of skills) {
- writeFileSync(join(DIST, 'skills', `${s.name}.html`), layout({
- lang: 'zh', base: '../', title: `${s.title} · superpowers-zh`, desc: s.desc,
- body: renderDetail(s, 'zh'), langHref: `../en/skills/${s.name}.html`,
- canonical: `/skills/${s.name}`, altZh: `/skills/${s.name}`, altEn: `/en/skills/${s.name}`,
- }));
- writeFileSync(join(DIST, 'en', 'skills', `${s.name}.html`), layout({
- lang: 'en', base: '../../', title: `${s.titleEn} · superpowers-zh`, desc: s.descEn || s.desc,
- body: renderDetail(s, 'en'), langHref: `../../skills/${s.name}.html`,
- canonical: `/en/skills/${s.name}`, altZh: `/skills/${s.name}`, altEn: `/en/skills/${s.name}`,
+ // ---- 每种语言生成首页 + 全部 skill 详情页 ----
+ for (const L of LANGS) {
+ const t = T[L.code];
+ const dirParts = L.dir ? [L.dir.replace(/\/$/, '')] : [];
+ const homeBase = L.dir ? '../' : '';
+ mkdirSync(join(DIST, ...dirParts, 'skills'), { recursive: true });
+ // 首页
+ writeFileSync(join(DIST, ...dirParts, 'index.html'), layout({
+ lang: L.code, base: homeBase, title: t.title, desc: t.desc,
+ body: renderLanding(skills, L.code), pageClean: '', pageFile: '',
}));
+ // skill 详情页
+ for (const s of skills) {
+ const title = L.code === 'en' ? s.titleEn : s.title;
+ const desc = L.code === 'en' ? (s.descEn || s.desc) : s.desc;
+ writeFileSync(join(DIST, ...dirParts, 'skills', `${s.name}.html`), layout({
+ lang: L.code, base: L.dir ? '../../' : '../',
+ title: `${title} · superpowers-zh`, desc,
+ body: renderDetail(s, L.code),
+ pageClean: `skills/${s.name}`, pageFile: `skills/${s.name}.html`,
+ }));
+ }
}
// ---- SEO: robots.txt + sitemap.xml ----
@@ -582,11 +680,14 @@ function build() {
'User-agent: *\nAllow: /\n\nSitemap: ' + SITE_URL + '/sitemap.xml\n');
const today = new Date().toISOString().slice(0, 10);
- const urls = ['/', '/en/'];
- for (const s of skills) { urls.push(`/skills/${s.name}`, `/en/skills/${s.name}`); }
+ const urls = [];
+ for (const L of LANGS) {
+ urls.push(`/${L.dir}`);
+ for (const s of skills) urls.push(`/${L.dir}skills/${s.name}`);
+ }
const sitemap = '\n' +
'\n' +
- urls.map(u => ` ${SITE_URL}${u} ${today} weekly ${u === '/' ? '1.0' : '0.7'} `).join('\n') +
+ urls.map(u => ` ${SITE_URL}${u} ${today} weekly ${u === '/' ? '1.0' : (u.endsWith('/') ? '0.8' : '0.7')} `).join('\n') +
'\n \n';
writeFileSync(join(DIST, 'sitemap.xml'), sitemap);
@@ -643,8 +744,8 @@ function build() {
'/styles.css\n Cache-Control: public, max-age=31536000, immutable\n' +
'/app.js\n Cache-Control: public, max-age=31536000, immutable\n');
- const pages = 2 + skills.length * 2;
- console.log(`✅ 生成 ${pages} 个页面:中/英首页 + ${skills.length} 个 skill × 2 语言详情页 → ${DIST}`);
+ const pages = LANGS.length * (1 + skills.length);
+ console.log(`✅ 生成 ${pages} 个页面:${LANGS.length} 语言(${LANGS.map(l => l.code).join('/')})× (首页 + ${skills.length} 个 skill 详情页) → ${DIST}`);
}
build();