Files
blog/src/i18n/ui.ts
T
wait4xandGLM-5.3 fb97d76ddb feat(launch): 命令面板+预发布验收+上线脚本(T1/T4/T5)
- T1 (op-gitea 车道):CommandPalette 三层(动作 theme/lang/rss+导航
  zh/en+Pagefind 搜索),Ctrl K 与 / 入口,document 级委托修 ClientRouter
  换页绑定失效;连带修复动态结果节点的 scoped CSS 失效潜伏 bug
- T4:preflight.sh 17 项全绿(产物/hreflang/双轨/微信 UA 200/
  responsive 11/halo 无恙/回滚前置);headless 渲染经 c4ai 复核
  (en 书评页全文+标注+ICP 实测在案)
- T5:launch.sh/rollback.sh 双向 dry-run 绿 + 上线检查单(linger/
  ESA 刷新/验证 URL/回滚路径)

验证: build 21 页 exit 0;command-palette+cmd-item zh/en 断言;
      bash scripts/preflight.sh ALL OK;launch/rollback dry-run exit 0

Spec: 2026-10-25_add-blog-launch
Co-authored-by: GLM-5.3
2026-10-25 09:52:50 +08:00

98 lines
6.6 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' },
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: '数据来自 gitea · 构建期生成', en: 'via gitea · generated at build time' },
// ===== 命令面板(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;
}