feat(i18n): 实现应用国际化支持,添加中英文翻译
- 为所有UI组件添加国际化支持,替换硬编码文本 - 新增useI18n钩子函数统一管理翻译 - 完善中英文翻译资源,覆盖统计、用药、通知设置等模块 - 优化Tab布局使用翻译键值替代静态文本 - 更新药品管理、个人资料编辑等页面的多语言支持
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { DateSelector } from '@/components/DateSelector';
|
||||
import CelebrationAnimation, { CelebrationAnimationRef } from '@/components/CelebrationAnimation';
|
||||
import { DateSelector } from '@/components/DateSelector';
|
||||
import { MedicationCard } from '@/components/medication/MedicationCard';
|
||||
import { ThemedText } from '@/components/ThemedText';
|
||||
import { IconSymbol } from '@/components/ui/IconSymbol';
|
||||
@@ -17,6 +17,7 @@ import { Image } from 'expo-image';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { router } from 'expo-router';
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
@@ -32,6 +33,7 @@ type MedicationFilter = 'all' | 'taken' | 'missed';
|
||||
type ThemeColors = (typeof Colors)[keyof typeof Colors];
|
||||
|
||||
export default function MedicationsScreen() {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const insets = useSafeAreaInsets();
|
||||
const theme = (useColorScheme() ?? 'light') as 'light' | 'dark';
|
||||
@@ -147,8 +149,8 @@ export default function MedicationsScreen() {
|
||||
|
||||
const displayName = userProfile.name?.trim() || DEFAULT_MEMBER_NAME;
|
||||
const headerDateLabel = selectedDate.isSame(dayjs(), 'day')
|
||||
? `今天,${selectedDate.format('M月D日')}`
|
||||
: selectedDate.format('M月D日 dddd');
|
||||
? t('medications.dateFormats.today', { date: selectedDate.format('M月D日') })
|
||||
: t('medications.dateFormats.other', { date: selectedDate.format('M月D日 dddd') });
|
||||
|
||||
const emptyState = filteredMedications.length === 0;
|
||||
|
||||
@@ -178,9 +180,9 @@ export default function MedicationsScreen() {
|
||||
>
|
||||
<View style={styles.header}>
|
||||
<View>
|
||||
<ThemedText style={styles.greeting}>你好,{displayName}</ThemedText>
|
||||
<ThemedText style={styles.greeting}>{t('medications.greeting', { name: displayName })}</ThemedText>
|
||||
<ThemedText style={[styles.welcome, { color: colors.textMuted }]}>
|
||||
欢迎来到用药助手!
|
||||
{t('medications.welcome')}
|
||||
</ThemedText>
|
||||
</View>
|
||||
<View style={styles.headerActions}>
|
||||
@@ -239,15 +241,10 @@ export default function MedicationsScreen() {
|
||||
</View>
|
||||
|
||||
<View style={styles.sectionSpacing}>
|
||||
<ThemedText style={styles.sectionHeader}>今日用药</ThemedText>
|
||||
<ThemedText style={styles.sectionHeader}>{t('medications.todayMedications')}</ThemedText>
|
||||
<View style={[styles.segmentedControl, { backgroundColor: colors.surface }]}>
|
||||
{(['all', 'taken', 'missed'] as MedicationFilter[]).map((filter) => {
|
||||
const isActive = activeFilter === filter;
|
||||
const labelMap: Record<MedicationFilter, string> = {
|
||||
all: '全部',
|
||||
taken: '已服用',
|
||||
missed: '未服用',
|
||||
};
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={filter}
|
||||
@@ -263,7 +260,7 @@ export default function MedicationsScreen() {
|
||||
{ color: isActive ? colors.onPrimary : colors.textSecondary },
|
||||
]}
|
||||
>
|
||||
{labelMap[filter]}
|
||||
{t(`medications.filters.${filter}`)}
|
||||
</ThemedText>
|
||||
<View
|
||||
style={[
|
||||
@@ -295,9 +292,9 @@ export default function MedicationsScreen() {
|
||||
style={styles.emptyIllustration}
|
||||
contentFit="cover"
|
||||
/>
|
||||
<ThemedText style={styles.emptyTitle}>今日暂无用药安排</ThemedText>
|
||||
<ThemedText style={styles.emptyTitle}>{t('medications.emptyState.title')}</ThemedText>
|
||||
<ThemedText style={[styles.emptySubtitle, { color: colors.textMuted }]}>
|
||||
还未添加任何用药计划,快来补充吧。
|
||||
{t('medications.emptyState.subtitle')}
|
||||
</ThemedText>
|
||||
</View>
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user