双语契约收口后留下几处重复,单独看都很小,但它们都是「同一个事实存在两份」——
正是 i18nContract.js / contentLayout.js 想消灭的东西。
1. OVERLAY_META 定义了两遍
src/utils/i18nContract.js —— 数组,check:content 用
src/utils/localized.ts —— Set,渲染时用
两者必须一致,却没有任何交叉引用。一旦漂移,多出来的 key 会被
localizedData 当成内容合并进 frontmatter(例如 source_sha 泄漏到渲染层)。
localized.ts 当初不 import i18nContract.js 是为了避免把 gray-matter 拖进
页面构建图——这个理由成立,但应当显式写下来,或把这类纯常量抽到
contentLayout.js(已经是两边都 import 的无依赖模块)。
2. sidecar 目录字面量散在两处
src/pages/[lang]/research/[slug].astro:37 `${COLLECTION_VAULT_PATHS.library}/文献/精选`
src/pages/[lang]/publications/[slug].astro 同上
而 PUBLICATION_SIDECAR_DIR、BUNDLE_COLLECTION_DIRS.publicationHighlights、
I18N_COLLECTIONS[].dir 已经各存了一份。现在一共四份集合→目录的映射。
建议合并到 contentLayout.js 一处,其余都从它派生。
3. const isFallback = lang !== 'zh' && !overlay; 抄了 7 遍
TranslationNotice.astro 的注释说它「owns the choice」,但每个路由仍自己算
isFallback。直接把 overlay 传进去,让组件自己判断,注释才名副其实。
4. resolveLocalized / LocalizedEntry 已无生产调用者
grep -rn resolveLocalized src/ 只剩 localized.ts 自身与测试。
localizedIndex / localizedData 取代了它。要么在路由里改用它,要么删掉——
现在的状态是「有测试覆盖的死代码」,比没测试的死代码更容易骗过下一个人。
双语契约收口后留下几处重复,单独看都很小,但它们都是「同一个事实存在两份」——
正是
i18nContract.js/contentLayout.js想消灭的东西。1.
OVERLAY_META定义了两遍src/utils/i18nContract.js—— 数组,check:content用src/utils/localized.ts——Set,渲染时用两者必须一致,却没有任何交叉引用。一旦漂移,多出来的 key 会被
localizedData当成内容合并进 frontmatter(例如source_sha泄漏到渲染层)。localized.ts当初不 importi18nContract.js是为了避免把 gray-matter 拖进页面构建图——这个理由成立,但应当显式写下来,或把这类纯常量抽到
contentLayout.js(已经是两边都 import 的无依赖模块)。2. sidecar 目录字面量散在两处
而
PUBLICATION_SIDECAR_DIR、BUNDLE_COLLECTION_DIRS.publicationHighlights、I18N_COLLECTIONS[].dir已经各存了一份。现在一共四份集合→目录的映射。建议合并到
contentLayout.js一处,其余都从它派生。3.
const isFallback = lang !== 'zh' && !overlay;抄了 7 遍TranslationNotice.astro的注释说它「owns the choice」,但每个路由仍自己算isFallback。直接把overlay传进去,让组件自己判断,注释才名副其实。4.
resolveLocalized/LocalizedEntry已无生产调用者grep -rn resolveLocalized src/只剩localized.ts自身与测试。localizedIndex/localizedData取代了它。要么在路由里改用它,要么删掉——现在的状态是「有测试覆盖的死代码」,比没测试的死代码更容易骗过下一个人。