From 996999453ae89cca0d18eabcfb22c50b64efa952 Mon Sep 17 00:00:00 2001 From: 1 <1> Date: Mon, 2 Feb 2026 20:11:09 +0800 Subject: [PATCH] feat(client): i18n copy + reco lang refresh + home polish --- client/app/(app)/home.tsx | 202 ++++++----- client/app/(onboarding)/onboarding.tsx | 85 ++--- client/app/_layout.tsx | 4 +- .../fonts/STIXTwoText-VariableFont_wght.ttf | Bin 0 -> 423048 bytes client/assets/images/home/like.svg | 2 +- client/assets/images/home/like_filled.svg | 2 +- client/assets/images/icon/like_icon.svg | 2 +- client/components/home/FavoritesModal.tsx | 47 ++- client/components/home/ProfileModal.tsx | 33 +- .../onboarding/IntentSelectionStep.tsx | 14 +- .../components/onboarding/SelectionStep.tsx | 14 +- client/components/ui/SheetModal.tsx | 4 +- client/src/constants/mockContent.ts | 12 +- client/src/i18n/ALL_COPY.md | 22 ++ client/src/i18n/index.ts | 9 +- client/src/i18n/locales/all.json | 314 ++++++++++++++++++ client/src/services/recoApi.ts | 3 +- client/src/storage/appStorage.ts | 12 +- spec_kit/overview.md | 1 + 19 files changed, 594 insertions(+), 188 deletions(-) create mode 100644 client/assets/fonts/STIXTwoText-VariableFont_wght.ttf create mode 100644 client/src/i18n/ALL_COPY.md create mode 100644 client/src/i18n/locales/all.json diff --git a/client/app/(app)/home.tsx b/client/app/(app)/home.tsx index 9699192..dd03030 100644 --- a/client/app/(app)/home.tsx +++ b/client/app/(app)/home.tsx @@ -14,19 +14,18 @@ import Animated, { import { MOCK_CONTENT } from '@/src/constants/mockContent'; import { addFavorite, - getRecoFeedCache, - getRecoFeedHistory, getThemeMode, getUserProfile, - getUserProfileScoring, - recordRecoFeedServed, - recordRecoFeedTouched, - setRecoFeedCache, setReaction, setThemeMode, - type RecoFeedCacheItem, + getRecoFeedCache, + setRecoFeedCache, + getUserProfileScoring, + getRecoFeedHistory, + recordRecoFeedServed, type ThemeMode, } from '@/src/storage/appStorage'; + import { fetchRecoFeed } from '@/src/services/recoApi'; import ProfileModal from '@/components/home/ProfileModal'; @@ -73,8 +72,12 @@ const THEME_COLORS = [ '#CBD9F2', ]; +type FeedItem = { content_id: string; text: string }; + export default function HomeScreen() { - const { t } = useTranslation(); + const { t, i18n } = useTranslation(); + const isEnglish = i18n.language?.startsWith('en'); + const recoLang: 'en' | 'tc' = i18n.language?.toLowerCase().startsWith('zh') ? 'tc' : 'en'; const navigation = useNavigation(); const [index, setIndex] = useState(0); const [themeMode, setThemeModeState] = useState('scenery'); @@ -83,83 +86,115 @@ export default function HomeScreen() { const [profileName, setProfileName] = useState(undefined); const [busy, setBusy] = useState(false); const [likeFilled, setLikeFilled] = useState(false); - const [feedItems, setFeedItems] = useState>([]); + const [feedItems, setFeedItems] = useState([]); + const [isFetching, setIsFetching] = useState(false); - const currentList = feedItems.length > 0 ? feedItems : MOCK_CONTENT; - const item = useMemo(() => currentList[index % currentList.length], [currentList, index]); - const currentContentId = typeof (item as any)?.content_id === 'number' ? Number((item as any).content_id) : null; + // 解决语言切换时重复触发拉取/清空导致“文案不停跳动”的问题: + // 用 ref 持有最新状态,避免 useCallback 依赖 feedItems/isFetching 造成函数 identity 变化 → effect 重复执行 + const feedItemsRef = useRef([]); + const isFetchingRef = useRef(false); + useEffect(() => { + feedItemsRef.current = feedItems; + }, [feedItems]); + useEffect(() => { + isFetchingRef.current = isFetching; + }, [isFetching]); // 动画相关 Shared Values const translateY = useSharedValue(0); const opacity = useSharedValue(1); const likeScale = useSharedValue(1); - // 每次进入页面或页面获得焦点时刷新个人信息 + // 统一文案对象结构 + const currentFeed = useMemo(() => { + if (feedItems.length > 0) { + return feedItems; + } + return MOCK_CONTENT.map(item => ({ + content_id: item.id, + text: t(item.textKey) + })); + }, [feedItems, t]); + + const item = useMemo(() => { + const data = currentFeed[index % currentFeed.length]; + return { + id: String(data.content_id), + text: data.text + }; + }, [currentFeed, index]); + + // 异步拉取新文案 + const fetchNewFeed = useCallback(async () => { + if (isFetchingRef.current) return; + isFetchingRef.current = true; + setIsFetching(true); + try { + const scoringProfile = await getUserProfileScoring(); + if (!scoringProfile) return; + + const history = await getRecoFeedHistory(); + + const { items, meta } = await fetchRecoFeed({ + k: 30, + user_profile: scoringProfile, + already_recommended_ids: history.already_recommended_ids, + touched_or_viewed_ids: history.touched_or_viewed_ids, + }); + + if (items.length > 0) { + const wasEmpty = feedItemsRef.current.length === 0; + const newCache = { + saved_at: new Date().toISOString(), + lang: recoLang, + items: items.map((x) => ({ content_id: x.content_id, text: x.text })), + meta: meta as Record, + }; + await setRecoFeedCache(newCache); + await recordRecoFeedServed(items.map((x) => x.content_id)); + setFeedItems(newCache.items.map((x) => ({ content_id: String(x.content_id), text: x.text }))); + // 如果当前是 mock 数据,切换到新数据的第一条 + if (wasEmpty) { + setIndex(0); + } + } + } catch (error) { + console.error('Failed to fetch new feed:', error); + } finally { + isFetchingRef.current = false; + setIsFetching(false); + } + }, [recoLang]); + + // 每次进入页面或页面获得焦点时刷新个人信息和缓存文案 useFocusEffect( useCallback(() => { let cancelled = false; (async () => { const mode = await getThemeMode(); const profile = await getUserProfile(); + const cache = await getRecoFeedCache(); + if (cancelled) return; setThemeModeState(mode); setProfileName(profile.name); + + // 语言切换时:旧语言缓存不复用,触发重新拉取 + if (cache && cache.items.length > 0 && (cache.lang ?? 'en') === recoLang) { + setFeedItems(cache.items.map((x) => ({ content_id: String(x.content_id), text: x.text }))); + } else { + // 语言不匹配或没有缓存:先清空回落到本地 mock(会立即随语言切换),再拉取对应语言的推荐文案 + setFeedItems([]); + setIndex(0); + fetchNewFeed(); + } })(); return () => { cancelled = true; }; - }, []) + }, [fetchNewFeed, recoLang]) ); - // 首次进入:先读缓存,再拉后端 feed(失败则保持 mock/缓存) - useEffect(() => { - let cancelled = false; - (async () => { - const cache = await getRecoFeedCache(); - if (!cancelled && cache?.items?.length) { - setFeedItems(cache.items.map((x: RecoFeedCacheItem) => ({ content_id: x.content_id, text: x.text }))); - } - - const scoring = await getUserProfileScoring(); - if (!scoring) return; - - try { - const hist = await getRecoFeedHistory(); - const out = await fetchRecoFeed({ - k: 30, - user_profile: { - profile_version: scoring.profile_version, - profile_source: scoring.profile_source, - profile_generated_at: scoring.profile_generated_at, - profile_confidence: scoring.profile_confidence, - profile_answered: scoring.profile_answered, - stage: scoring.stage, - emotion_score: scoring.emotion_score, - context: scoring.context, - need: scoring.need, - }, - already_recommended_ids: hist.already_recommended_ids, - touched_or_viewed_ids: hist.touched_or_viewed_ids, - }); - - if (!cancelled && out.items?.length) { - setFeedItems(out.items.map((x) => ({ content_id: x.content_id, text: x.text }))); - await setRecoFeedCache({ - saved_at: new Date().toISOString(), - items: out.items.map((x) => ({ content_id: x.content_id, text: x.text })), - meta: out.meta as Record, - }); - await recordRecoFeedServed(out.items.map((x) => x.content_id)); - } - } catch { - // 忽略:保持缓存/本地 mock - } - })(); - return () => { - cancelled = true; - }; - }, []); - const backgroundColor = useMemo(() => { if (themeMode === 'color') { const colorIndex = Math.floor(index / 10) % THEME_COLORS.length; @@ -178,8 +213,10 @@ export default function HomeScreen() { useLayoutEffect(() => { navigation.setOptions({ headerShadowVisible: false, - headerStyle: { backgroundColor: themeMode === 'scenery' ? 'transparent' : backgroundColor }, - headerTransparent: themeMode === 'scenery', + // 为了让风景/颜色两种主题下“文案的视觉居中位置”一致,统一使用透明 Header + // 颜色主题下 Header 透明也不会影响观感(背景就是纯色) + headerStyle: { backgroundColor: 'transparent' }, + headerTransparent: true, headerRight: () => ( { @@ -226,6 +258,11 @@ export default function HomeScreen() { runOnJS(setIndex)(index + 1); runOnJS(setLikeFilled)(false); + // 检查是否需要拉取新文案(当接近当前列表末尾时,例如还剩 5 条) + if (index + 5 >= currentFeed.length && !isFetching) { + runOnJS(fetchNewFeed)(); + } + // 3. 准备下一条文案:先瞬移到下方 40pt translateY.value = 40; @@ -238,7 +275,7 @@ export default function HomeScreen() { }); } }); - }, [busy, currentContentId, index, translateY, opacity]); + }, [busy, index, currentFeed.length, isFetching, fetchNewFeed, translateY, opacity]); const lastTapRef = useRef(0); @@ -288,20 +325,28 @@ export default function HomeScreen() { const dateStr = `${now.getFullYear()}.${String(now.getMonth() + 1).padStart(2, '0')}.${String(now.getDate()).padStart(2, '0')}`; // 2. 保存到收藏夹,包含当前背景信息 - await addFavorite({ + const favItem = { favId: String(Date.now()), // 生成唯一 ID id: item.id, + text: item.text, date: dateStr, themeMode: themeMode, background: themeMode === 'scenery' ? String(natureImageIndex) : backgroundColor, - }); + }; + console.log('Home: Triggering addFavorite', JSON.stringify(favItem)); + await addFavorite(favItem); - // 3. 爱心缩放动画 + // 3. 记录到后端 Reaction(喜欢) + console.log('Home: Triggering setReaction', item.id); + await setReaction(item.id, 'like'); + + // 4. 爱心缩放动画 likeScale.value = withSequence( withTiming(0.8, { duration: 100 }), withTiming(1.2, { duration: 150 }), withTiming(1, { duration: 100 }, (finished) => { if (finished) { + console.log('Home: Like animation finished, triggering next content'); runOnJS(triggerNextContent)(); } }) @@ -324,7 +369,9 @@ export default function HomeScreen() { /> )} - {item.text} + + {item.text} + @@ -419,6 +466,11 @@ const styles = StyleSheet.create({ fontWeight: '700', textAlign: 'center', }, + textEnglish: { + fontFamily: 'STIXTwoText', + // 英文字体观感更细一点,避免过粗 + fontWeight: '600', + }, sceneryCard: { // 风景模式下稍微收窄文案宽度,增加呼吸感 paddingHorizontal: 50, diff --git a/client/app/(onboarding)/onboarding.tsx b/client/app/(onboarding)/onboarding.tsx index 42bbfe8..1d9aae8 100644 --- a/client/app/(onboarding)/onboarding.tsx +++ b/client/app/(onboarding)/onboarding.tsx @@ -1,6 +1,7 @@ -import { useState } from 'react'; +import { useMemo, useState } from 'react'; import { useRouter } from 'expo-router'; import * as Notifications from 'expo-notifications'; +import { useTranslation } from 'react-i18next'; import { OnboardingLayout } from '@/components/onboarding/OnboardingLayout'; import { NameInputStep } from '@/components/onboarding/NameInputStep'; import { SelectionStep } from '@/components/onboarding/SelectionStep'; @@ -16,64 +17,37 @@ import { setRecoFeedCache, } from '@/src/storage/appStorage'; -const STEPS = [ - { id: 'name', type: 'name', title: '我可以怎么称呼你?' }, - { - id: 'status', - type: 'selection', - title: '媽媽的狀態?', - options: [ - { id: 'pregnant', label: '懷孕中/準備成為媽媽' }, - { id: 'has_kids', label: '已經有孩子' }, - { id: 'no_fill', label: '不想填寫' }, - ] - }, - { - id: 'emotion', - type: 'selection', - title: '當下情緒狀態?', - options: [ - { id: 'happy', label: '愉悅、滿足' }, - { id: 'calm', label: '平靜、安穩' }, - { id: 'stressed', label: '被壓得有點喘不過氣' }, - { id: 'low', label: '情緒低落' }, - ] - }, - { - id: 'influence', - type: 'selection', - title: '是什麼影響了你最近的感受?', - options: [ - { id: 'family', label: '家庭與孩子' }, - { id: 'work', label: '工作或學習' }, - { id: 'relationship', label: '親密關係' }, - { id: 'friends', label: '朋友與人際' }, - { id: 'health', label: '身心健康' }, - ] - }, - { - id: 'support', - type: 'selection', - title: '最需要什麼支持?', - options: [ - { id: 'emotional', label: '情緒支持' }, - { id: 'parenting', label: '育兒壓力' }, - { id: 'self_worth', label: '自我價值' }, - { id: 'anxiety', label: '焦慮舒緩' }, - { id: 'balance', label: '休息與平衡' }, - ] - }, - { id: 'reminder', type: 'reminder', title: '你需要每天几次提醒?' }, +type Step = + | { id: 'name'; type: 'name' } + | { id: 'status' | 'emotion' | 'influence' | 'support'; type: 'selection'; optionIds: string[] } + | { id: 'reminder'; type: 'reminder' }; + +const STEPS: Step[] = [ + { id: 'name', type: 'name' }, + { id: 'status', type: 'selection', optionIds: ['pregnant', 'has_kids', 'no_fill'] }, + { id: 'emotion', type: 'selection', optionIds: ['happy', 'calm', 'stressed', 'low'] }, + { id: 'influence', type: 'selection', optionIds: ['family', 'work', 'relationship', 'friends', 'health'] }, + { id: 'support', type: 'selection', optionIds: ['emotional', 'parenting', 'self_worth', 'anxiety', 'balance'] }, + { id: 'reminder', type: 'reminder' }, ]; export default function OnboardingScreen() { const router = useRouter(); + const { t, i18n } = useTranslation(); const [stepIndex, setStepIndex] = useState(0); const [name, setName] = useState(''); const [selections, setSelections] = useState>({}); const [reminderTimes, setReminderTimes] = useState(3); const currentStep = STEPS[stepIndex]; + const currentTitle = useMemo(() => t(`onboardingSurvey.steps.${currentStep.id}.title`), [t, currentStep.id]); + const currentOptions = useMemo(() => { + if (currentStep.type !== 'selection') return []; + return currentStep.optionIds.map((optId) => ({ + id: optId, + label: t(`onboardingSurvey.steps.${currentStep.id}.options.${optId}`), + })); + }, [t, currentStep]); async function onFinish() { // 请求推送权限 @@ -89,6 +63,7 @@ export default function OnboardingScreen() { // Onboarding 结束后预拉取一次 Feed 文案(失败不阻塞进入首页) try { + const lang = i18n.language?.toLowerCase().startsWith('zh') ? 'tc' : 'en'; const { items, meta } = await fetchRecoFeed({ k: 30, user_profile: { @@ -106,6 +81,7 @@ export default function OnboardingScreen() { await setRecoFeedCache({ saved_at: new Date().toISOString(), + lang, items: items.map((x) => ({ content_id: x.content_id, text: x.text })), meta: meta as Record, }); @@ -150,11 +126,13 @@ export default function OnboardingScreen() { router.replace('/(app)/home'); }; - // 题目为单选:再次点击可取消;选择其他选项会替换为唯一选项 + // 题目为多选:点击切换选中状态 const handleToggleSelection = (id: string) => { setSelections(prev => { const currentIds = prev[currentStep.id] || []; - const nextIds = currentIds.includes(id) ? [] : [id]; + const nextIds = currentIds.includes(id) + ? currentIds.filter(i => i !== id) + : [...currentIds, id]; return { ...prev, [currentStep.id]: nextIds }; }); }; @@ -166,7 +144,7 @@ export default function OnboardingScreen() { return ( )} diff --git a/client/app/_layout.tsx b/client/app/_layout.tsx index b5f5188..9d8e4a1 100644 --- a/client/app/_layout.tsx +++ b/client/app/_layout.tsx @@ -34,7 +34,7 @@ SplashScreen.preventAutoHideAsync(); export default function RootLayout() { const [loaded, error] = useFonts({ - SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'), + STIXTwoText: require('../assets/fonts/STIXTwoText-VariableFont_wght.ttf'), ...FontAwesome.font, }); const [i18nReady, setI18nReady] = useState(false); @@ -48,7 +48,7 @@ export default function RootLayout() { initI18n() .catch((e) => { // i18n 初始化失败不应阻塞 App 启动,先打印错误再继续 - console.error('i18n 初始化失败', e); + console.error('i18n init failed', e); }) .finally(() => setI18nReady(true)); }, []); diff --git a/client/assets/fonts/STIXTwoText-VariableFont_wght.ttf b/client/assets/fonts/STIXTwoText-VariableFont_wght.ttf new file mode 100644 index 0000000000000000000000000000000000000000..088918f5fa4d942a744056682fe08268fd105555 GIT binary patch literal 423048 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

EOp2 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