Files
blog/src/i18n/ui.ts
T
wait4xandGLM-5.3 6538311387 feat(content): 置顶契约与计数徽标组件(5h T1 契约部分)
置顶(T1):
- src/lib/post-order.ts 新增 sortPosts:置顶优先 → pubDate 倒序 → id 兜底,
  把首页双轨/归档/书架四处排序口径收敛到一处
- postsSchema 增 pinned;PostList 三处渲染路径加灰阶 pin 小徽标;后台置顶开关
- 语义边界:只影响列表顺序,不改 pubDate/URL/RSS 时间语义

计数徽标(T4 契约组件):
- src/components/geek/ViewMeta.astro:眼睛 = 浏览数、气泡 = 评论数,
  本地 SVG + tokens 着色,不引第三方图片
- 数据只用 Artalk 匿名端点:GET comments?limit=1 一次拿到 count 与 page.pv;
  page 模式先 POST pages/pv 计一次浏览,readonly 模式零写入
- SSR 占位「–」:无 JS/接口失败不显示 0 误导读者

验证: pnpm astro build 48 页 exit 0;config-check 208 字段/65 hint 全过;
      sortPosts 四调用点替换后构建通过

Spec: 2026-11-02_blog-5h-content-social (T1 契约)

Co-authored-by: GLM-5.3
2026-11-02 20:02:08 +08:00

143 lines
9.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 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' },
pinned_label: { zh: '置顶', en: 'Pinned' },
comment_count: { zh: '条评论', en: 'comments' },
moment_comments: { zh: '评论', en: 'Comments' },
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;
}