diff --git a/.workbuddy/memory/2026-08-25.md b/.workbuddy/memory/2026-08-25.md new file mode 100644 index 0000000..5801e04 --- /dev/null +++ b/.workbuddy/memory/2026-08-25.md @@ -0,0 +1,14 @@ +# 2026-08-25 工作日志 + +## 新增 /en/ 登录注册页(20:02) +- 用户要求:把 /en/ 下的 login 和 register 做出来,符合当前网站设计。 +- 背景:Astro i18n `prefixDefaultLocale: true`,导航 Login/Signup 链接解析为 `/en/login`、`/en/register`,但这两个文件之前不存在(只有根 `src/pages/login.astro` 等 ComingSoon 占位),点开 404。 +- 改动(加法式,不动根 ComingSoon 页、不动原 Login.astro/Register.astro 组件): + 1. `src/lib/api.ts`:新增 `saveSession(token, user)`,写入 `fa_token`/`fa_user`(与 `getUser`/`fetchMe` 共用 key),供登录/注册后落地本地会话。 + 2. 新建 `src/components/pages/AuthForm.astro`:登录/注册通用编辑风表单(props `mode: 'login'|'register'`)。 + - 设计:沿用全站黑白极简编辑风——monospace 顶边 kicker(Account / Sign In|Create Account)、`font-serif font-black` 大标题、monospace 副标题、黑底描边 input(`auth-input`)、黑底白字描边按钮(hover 反白,沿用 `cs-btn` 调性)、底部 footer 链接(注册↔登录互链)。容器用 `w-full max-w-[460px] mx-auto`(避免 m-auto shrink-to-fit,见 MEMORY Layout 陷阱)。 + - 客户端 ` diff --git a/src/i18n/dictionary.ts b/src/i18n/dictionary.ts index 4f204d1..5c3994a 100644 --- a/src/i18n/dictionary.ts +++ b/src/i18n/dictionary.ts @@ -18,53 +18,86 @@ type OtherLocale = Exclude; type TranslationEntry = Partial>; export const dict: Record = { + // ── 导航 / Navigation ── - 'About': { cn: '关于' }, - '全部的 runway': { cn: '全部的 runway' }, - 'Contact': { cn: '联系' }, - 'Contact Us': { cn: '联系我们' }, - 'Home': { cn: '首页' }, - 'Latest Projects': { cn: '最新项目' }, - 'Login': { cn: '登录' }, - 'Portfolio': { cn: '作品集' }, - 'Runway Archive': { cn: '走秀档案' }, - 'Signup': { cn: '注册' }, + + 'about': { cn: '关于' }, + + '全部的 runway': { cn: '全部的 runway' }, + + 'contact': { cn: '联系' }, + + 'contact us': { cn: '联系我们' }, + + 'home': { cn: '首页' }, + + 'latest projects': { cn: '最新项目' }, + + 'login': { cn: '登录' }, + + 'portfolio': { cn: '作品集' }, + + 'runway archive': { cn: '走秀档案' }, + + 'signup': { cn: '注册' }, // ── 控件 / Controls ── - 'Back to Index': { cn: '返回首页' }, - 'Back to top': { cn: '回到顶部' }, - 'Close': { cn: '关闭' }, - 'Previous image': { cn: '上一张' }, - 'Next image': { cn: '下一张' }, - 'Previous': { cn: '上一组' }, - 'Next': { cn: '下一组' }, + + 'back to index': { cn: '返回首页' }, + + 'back to top': { cn: '回到顶部' }, + + 'close': { cn: '关闭' }, + + 'previous image': { cn: '上一张' }, + + 'next image': { cn: '下一张' }, + + 'previous': { cn: '上一组' }, + + 'next': { cn: '下一组' }, // ── 错误 / Errors ── - 'No article ID specified': { cn: '未指定文章 ID' }, - 'Failed to load article. Please refresh or try later.': { cn: '加载文章失败,请刷新或稍后再试' }, - 'Click image to zoom · Scroll to view · Esc to close': { cn: '点击图片放大 · 上下滚动查看 · Esc 关闭' }, + + 'no article id specified': { cn: '未指定文章 ID' }, + + 'failed to load article. please refresh or try later.': { cn: '加载文章失败,请刷新或稍后再试' }, + + 'click image to zoom · scroll to view · esc to close': { cn: '点击图片放大 · 上下滚动查看 · Esc 关闭' }, // ── 页脚 / Footer ── - '© 2026 PORTFOLIO STUDIO. ALL RIGHTS RESERVED.': { cn: '© 2026 PORTFOLIO STUDIO. 保留所有权利。' }, + + '© 2026 portfolio studio. all rights reserved.': { cn: '© 2026 PORTFOLIO STUDIO. 保留所有权利。' }, // ── 页脚工具 / Footer tools ── - 'Color Studio Tools': { cn: '色彩工作室工具' }, - 'AI Color Trend Generator': { cn: 'AI 色彩趋势生成器' }, - 'Photo Swatch Extractor': { cn: '图片色板提取器' }, - 'Upload': { cn: '上传' }, - 'Reset B&W Theme': { cn: '重置黑白主题' }, - 'Default': { cn: '默认' }, + + 'color studio tools': { cn: '色彩工作室工具' }, + + 'ai color trend generator': { cn: 'AI 色彩趋势生成器' }, + + 'photo swatch extractor': { cn: '图片色板提取器' }, + + 'upload': { cn: '上传' }, + + 'reset b&w theme': { cn: '重置黑白主题' }, + + 'default': { cn: '默认' }, // ── 页脚简介 / Manifesto ── - 'Minimalist editorial portfolio documenting haute couture shows, backstage fittings, and street culture. Integrated with 2026 color forecast intelligence and AI palette generator.': + + 'minimalist editorial portfolio documenting haute couture shows, backstage fittings, and street culture. integrated with 2026 color forecast intelligence and ai palette generator.': { cn: '极简编辑风格作品集,记录高级定制秀场、后台试装与街头文化。集成 2026 色彩预测情报与 AI 调色板生成器。' }, // ── 登录态 / Auth ── - 'Hi': { cn: '你好' }, - 'Logout': { cn: '退出' }, - 'Language': { cn: '语言' }, - 'Runway looks': {cn: '秀场造型'} + 'hi': { cn: '你好' }, + + 'logout': { cn: '退出' }, + + 'language': { cn: '语言' }, + + 'runway looks': { cn: '秀场造型' } + }; /** 把 {name} 形式的占位符替换成参数值。 */ @@ -81,7 +114,7 @@ function interpolate(text: string, params?: Record): st export function translate(key: string, locale: Locale, params?: Record): string { if (locale === DEFAULT_LOCALE) return interpolate(key, params); - const localized = dict[key]?.[locale as OtherLocale]; + const localized = dict[key.toLowerCase()]?.[locale as OtherLocale]; if (localized) return interpolate(localized, params); if (import.meta.env.DEV) { diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index 825dec8..fb0cad8 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -8,6 +8,9 @@ import { toCodes } from 'astro:i18n'; import LanguageDetector from '@/components/LanguageDetector.astro' +const { title } = Astro.props as { title?: string } +const siteTitle = title ? `${title} — Portfolio Studio` : "Portfolio Studio" + const { locale, t, getRelativeLocaleUrl } = getI18n(Astro) // 经 data-* 属性把已翻译字符串传入打包型