- T1 关于页=markdown 文档:about.yaml intro 扩为多段 markdown(zh/en),
AboutPage 用 @astrojs/markdown-remark 的 createMarkdownProcessor(进程
内单例复用)+ set:html 渲染,正文 p/ul/strong/a 对齐站点排版;名片与
技能卡结构不动
- T2 社交链接单一数据源:home.yaml socials[](label/url/icon)+
SocialLinks.astro(图标注册表白名单:github/rss/email/bilibili/x,
未登记 icon 回退纯文字),首页 zh/en 内联硬编码社交块删除
- T3 头像与 favicon 可上传:schema avatar: image()(Astro Image 出 60px
WebP,未设回退渐变 SVG);home.yaml favicon → BaseLayout link[rel=icon]
按扩展名给 type,留空回退 /favicon.svg
- T4 首页分轨:PostList perTrack → 阅读轨/技术轨两段各限 6,各自出口
(阅读→/books/ 技术→/archives/,en 同构);E2E 断言改为两段各≤6+各自
出口+阅读在前
- T5 后台列表日期:posts summary「{{pubDate}} · {{title}}」、moments
「{{fields.pubDate}} · {{fields.text}}」+sortable;photos 无 frontmatter
日期(JSON sidecar)保持分组 · 标题并在文档写明原因
- 顺手修 content-lint 漏报:中文文件名在 HTML 里为 %XX 编码,脚本直接
拼盘上路径导致 6 条"缺图"误报 → 加 decodeURI
- 清理:删除书封误传遗留的双重嵌套目录文件
车道:op-gitea(5/5,build+E2E 37/37+lint 47 页 0/0/0);收编复验:
build 46 页 + E2E 37/37 连跑(首跑两红为车道并发构建擦 dist 的瞬时态,
复跑绿)
验证: node v26.13.0 + astro 7.4.4 全量构建 46 页 exit 0;E2E 37/37;
content-lint 0/0/0;books details/命令面板 playwright 实测
Spec: none (后台能力扩展,车道级交付)
Co-authored-by: GLM-5.3
140 lines
9.3 KiB
TypeScript
140 lines
9.3 KiB
TypeScript
/**
|
||
* UI 双语字典:组件静态文案的单一事实源。
|
||
* 约定:key 稳定小写蛇形;zh 是源语言(先有),en 跟随;
|
||
* 车道协作:op-gitea 扩展本表并串接五组件(Footer/SearchDialog/gallery/moments/about)。
|
||
*/
|
||
export type Locale = 'zh' | 'en';
|
||
|
||
const dict = {
|
||
skip_to_content: { zh: '跳到正文', en: 'Skip to content' },
|
||
nav_posts: { zh: '文章', en: 'Posts' },
|
||
nav_gallery: { zh: '图库', en: 'Gallery' },
|
||
nav_about: { zh: '关于', en: 'About' },
|
||
cmd_reader: { zh: '阅读模式(纯文本)', en: 'Reader mode (plain text)' },
|
||
nav_opensource: { zh: '开源', en: 'Projects' }, // en 用短词:390-430px 尾部主题钮免内滚(用户拍板)
|
||
nav_books: { zh: '书架', en: 'Books' },
|
||
kbd_gs_books: { zh: '书架', en: 'Books' },
|
||
// 论文内置阅读页(arXiv 原站 iframe 直嵌,PDF 不入仓)
|
||
paper_read_online: { zh: '在线研读全文 PDF', en: 'Read the full PDF online' },
|
||
paper_license: { zh: '授权', en: 'License' },
|
||
paper_download: { zh: '下载 PDF', en: 'Download PDF' },
|
||
paper_fallback_title: { zh: '无法内嵌展示全文,请用浏览器打开', en: 'Inline preview unavailable — open in a browser' },
|
||
paper_wechat_hint: { zh: '微信内请点右上角「···」→ 在浏览器打开', en: 'In WeChat, tap ··· (top right) → Open in Browser' },
|
||
paper_open_browser: { zh: '在浏览器中打开 PDF →', en: 'Open the PDF in your browser →' },
|
||
paper_loading: { zh: '正在加载 PDF…', en: 'Loading PDF…' },
|
||
paper_prev_page: { zh: '上一页', en: 'Previous page' },
|
||
paper_next_page: { zh: '下一页', en: 'Next page' },
|
||
paper_zoom_in: { zh: '放大', en: 'Zoom in' },
|
||
paper_zoom_out: { zh: '缩小', en: 'Zoom out' },
|
||
paper_page_label: { zh: '页码', en: 'Page' },
|
||
// 折叠批(2026-11-02):首页限 6 篇 + 归档/书架按年折叠
|
||
home_more_posts: { zh: '全部文章 →', en: 'All posts →' },
|
||
unit_posts: { zh: '篇', en: 'posts' },
|
||
search_label: { zh: '搜索', en: 'Search' },
|
||
search_placeholder: { zh: '搜索文章…(Esc 关闭)', en: 'Search posts… (Esc to close)' },
|
||
search_hint: { zh: '索引由 Pagefind 构建期生成 · 静态站零后端', en: 'Index built by Pagefind · zero-backend static site' },
|
||
footer_copyright: { zh: '©', en: '©' },
|
||
reading_time_min: { zh: '分钟', en: 'min' },
|
||
category_reading: { zh: '阅读', en: 'Reading' },
|
||
category_tech: { zh: '技术', en: 'Tech' },
|
||
category_photo: { zh: '照片', en: 'Photo' },
|
||
latest_photos: { zh: '最新影像', en: 'Latest photos' },
|
||
enter_gallery: { zh: '进入图库 →', en: 'Gallery →' },
|
||
open_source_projects: { zh: '开源 · Projects', en: 'Open Source · Projects' },
|
||
self_hosted: { zh: '自托管', en: 'self-hosted' },
|
||
prev_post: { zh: '上一篇', en: 'Previous' },
|
||
next_post: { zh: '下一篇', en: 'Next' },
|
||
ai_translated_note: {
|
||
zh: '本文由机器翻译自中文原文,欢迎指正。',
|
||
en: 'Machine-translated from the Chinese original. Corrections welcome.',
|
||
},
|
||
|
||
// ===== T2 车道(op-gitea):Footer/SearchDialog/gallery/moments/about 静态文案 =====
|
||
// footer_icp 是法定备案标识,英文页照抄不译
|
||
search_no_results: { zh: '无结果', en: 'No results' },
|
||
footer_icp: { zh: '陕ICP备2026014860号-1', en: '陕ICP备2026014860号-1' },
|
||
gallery_title: { zh: '图库', en: 'Gallery' },
|
||
gallery_filter_legend: { zh: '分组筛选', en: 'Filter by group' },
|
||
gallery_filter_all: { zh: '全部', en: 'All' },
|
||
gallery_filter_street: { zh: '街拍', en: 'Street' },
|
||
gallery_filter_landscape: { zh: '风景', en: 'Landscape' },
|
||
// {n}/{title}/{exif} 为占位符,调用点 .replace() 填值
|
||
gallery_count: { zh: '共 {n} 张 · EXIF 构建期自动提取', en: '{n} photos · EXIF extracted at build time' },
|
||
gallery_view_aria: { zh: '查看大图:{title}', en: 'View photo: {title}' },
|
||
gallery_view_aria_exif: { zh: '({exif})', en: ' ({exif})' },
|
||
gallery_lightbox_label: { zh: '照片查看', en: 'Photo viewer' },
|
||
gallery_lightbox_close: { zh: '关闭(Esc)', en: 'Close (Esc)' },
|
||
gallery_lightbox_prev: { zh: '上一张(←)', en: 'Previous (←)' },
|
||
gallery_lightbox_next: { zh: '下一张(→)', en: 'Next (→)' },
|
||
gallery_lightbox_original: { zh: '原图', en: 'Original' },
|
||
gallery_lightbox_download: { zh: '下载', en: 'Download' },
|
||
moments_title: { zh: '瞬间', en: 'Moments' },
|
||
moments_note: { zh: '零碎的记录:随手拍、一句话感想、开源动态。', en: 'Fragmented notes: casual shots, one-liners, and open-source updates.' },
|
||
about_title: { zh: '关于', en: 'About' },
|
||
about_tracks_title: { zh: '兴趣版图', en: 'Interests' },
|
||
about_track_reading_name: { zh: '阅读', en: 'Reading' },
|
||
about_track_reading_desc: { zh: '文学与戏剧为主,读到哪写到哪。', en: 'Mostly literature and drama; I write as I read.' },
|
||
about_track_tech_name: { zh: '技术', en: 'Tech' },
|
||
about_track_tech_desc: { zh: 'Linux、容器与自托管,把家里的小机器折腾成顺手的工具。', en: 'Linux, containers, and self-hosting — turning the little machines at home into handy tools.' },
|
||
about_track_photo_name: { zh: '摄影', en: 'Photography' },
|
||
about_track_photo_desc: { zh: '街拍与山野,随身一台无反,在等光的间隙按快门。', en: 'Street and landscapes with a mirrorless camera, pressing the shutter while waiting for the light.' },
|
||
about_build_aria: { zh: '本站构建说明', en: 'Site build notes' },
|
||
about_build_title: { zh: '本站如何构建', en: 'How this site is built' },
|
||
about_build_desc: {
|
||
zh: '页面由 Astro 静态生成,不含运行时框架 JS;内容住在自托管 gitea——本地编辑器与 gitea 网页写的是同一个 git 仓库,push 之后由 homelab 自动构建发布;评论走自托管 Artalk。页脚 built from 一行链到本次构建对应的 commit,构建过程透明可追溯。',
|
||
en: 'Pages are statically generated by Astro with no runtime framework JS. Content lives on a self-hosted gitea — my local editor and the gitea web UI write to the same git repository, and each push is built and published automatically by the homelab. Comments run on self-hosted Artalk. The built-from line in the footer links to the commit behind this build, keeping the process transparent and traceable.',
|
||
},
|
||
|
||
// ===== 热力图(Phase 4 T2 车道):文案全部页面层注入,组件保持 locale 无关 =====
|
||
heatmap_title: { zh: '开源活动', en: 'Open Source Activity' },
|
||
// {n} 为总贡献次数占位符,调用点 .replace() 填值
|
||
heatmap_summary: { zh: '最近一年 {n} 次贡献', en: '{n} contributions in the last year' },
|
||
heatmap_less: { zh: '少', en: 'Less' },
|
||
heatmap_more: { zh: '多', en: 'More' },
|
||
heatmap_note: { zh: '数据来自 GitHub · 构建期生成', en: 'via GitHub · generated at build time' },
|
||
|
||
// ===== B 车道:Footer 极客双页入口(stack/colophon 页内文案各自内联,不入本表) =====
|
||
footer_stack: { zh: '装备', en: 'stack' },
|
||
footer_colophon: { zh: '制作', en: 'colophon' },
|
||
|
||
// ===== C 车道:Keyboard 帮助表全量词条(组件 Astro.url 构建期自推断 locale) =====
|
||
kbd_title: { zh: '键盘快捷键', en: 'Keyboard shortcuts' },
|
||
kbd_palette: { zh: '命令面板', en: 'Command palette' },
|
||
kbd_theme_toggle: { zh: '切换明暗', en: 'Toggle light / dark' },
|
||
kbd_this_help: { zh: '本帮助', en: 'This help' },
|
||
kbd_gh_home: { zh: '首页', en: 'Home' },
|
||
kbd_ga_posts: { zh: '文章', en: 'Posts' },
|
||
kbd_gg_gallery: { zh: '图库', en: 'Gallery' },
|
||
kbd_gm_moments: { zh: '瞬间', en: 'Moments' },
|
||
kbd_terminal: { zh: '终端彩蛋', en: 'Terminal easter egg' },
|
||
kbd_esc_close: { zh: '关闭浮层', en: 'Close dialogs' },
|
||
kbd_hint: { zh: '提示:/terminal 终端彩蛋等你探索', en: 'Tip: the /terminal easter egg awaits' },
|
||
|
||
// ===== F 车道:访问量小字(Artalk pv,组件内独立计数) =====
|
||
pv_viewed: { zh: '人看过', en: 'views' },
|
||
lb_hint: { zh: '滚轮缩放 · 双击放大 · Esc 关闭', en: 'Wheel to zoom · Double-click · Esc' },
|
||
lb_hint_touch: { zh: '双指缩放 · 双击放大', en: 'Pinch to zoom · Double-tap' },
|
||
|
||
// ===== 命令面板(Phase 4 T1 车道):动作/导航/分组与键位提示 =====
|
||
nav_home: { zh: '首页', en: 'Home' },
|
||
nav_moments: { zh: '瞬间', en: 'Moments' },
|
||
cmd_palette_label: { zh: '命令面板', en: 'Command palette' },
|
||
cmd_group_actions: { zh: '动作', en: 'Actions' },
|
||
cmd_group_nav: { zh: '导航', en: 'Navigation' },
|
||
cmd_group_search: { zh: '搜索结果', en: 'Search results' },
|
||
cmd_toggle_theme: { zh: '切换明暗主题', en: 'Toggle dark mode' },
|
||
// 语言动作按当前页面语言命名目标语(zh 页提示切到 English,反之亦然)
|
||
cmd_switch_lang: { zh: '切换到 English', en: 'Switch to Chinese' },
|
||
cmd_open_gitea: { zh: '打开 gitea 源码仓', en: 'Open the gitea repo' },
|
||
cmd_copy_rss: { zh: '复制 RSS 地址', en: 'Copy RSS address' },
|
||
cmd_copied: { zh: '已复制 ✓', en: 'Copied ✓' },
|
||
cmd_hint: { zh: '↑↓ 选择 · Enter 执行 · Esc 关闭', en: '↑↓ navigate · Enter run · Esc close' },
|
||
} as const;
|
||
|
||
export type UiKey = keyof typeof dict;
|
||
|
||
/** 取串:locale 缺省 zh;未知 key 原样返回(编译期 tsc 已挡)。 */
|
||
export function t(key: UiKey, locale: Locale = 'zh'): string {
|
||
return dict[key][locale] ?? dict[key].zh;
|
||
}
|