feat(i18n): 实现应用国际化支持,添加中英文翻译

- 为所有UI组件添加国际化支持,替换硬编码文本
- 新增useI18n钩子函数统一管理翻译
- 完善中英文翻译资源,覆盖统计、用药、通知设置等模块
- 优化Tab布局使用翻译键值替代静态文本
- 更新药品管理、个人资料编辑等页面的多语言支持
This commit is contained in:
richarjiang
2025-11-13 11:09:55 +08:00
parent 416d144387
commit 2dca3253e6
21 changed files with 1669 additions and 366 deletions

View File

@@ -1,5 +1,6 @@
import { ThemedText } from '@/components/ThemedText';
import { useAppDispatch } from '@/hooks/redux';
import { useI18n } from '@/hooks/useI18n';
import { takeMedicationAction } from '@/store/medicationsSlice';
import type { MedicationDisplayItem } from '@/types/medication';
import { Ionicons } from '@expo/vector-icons';
@@ -19,6 +20,7 @@ export type MedicationCardProps = {
export function MedicationCard({ medication, colors, selectedDate, onOpenDetails, onCelebrate }: MedicationCardProps) {
const dispatch = useAppDispatch();
const { t } = useI18n();
const [isSubmitting, setIsSubmitting] = useState(false);
const [imageError, setImageError] = useState(false);
@@ -43,11 +45,11 @@ export function MedicationCard({ medication, colors, selectedDate, onOpenDetails
if (timeDiffMinutes > 60) {
// 显示二次确认弹窗
Alert.alert(
'尚未到服药时间',
`该用药计划在 ${medication.scheduledTime}现在还早于1小时以上。\n\n是否确认已服用此药物`,
t('medications.card.earlyTakeAlert.title'),
t('medications.card.earlyTakeAlert.message', { time: medication.scheduledTime }),
[
{
text: '取消',
text: t('medications.card.earlyTakeAlert.cancel'),
style: 'cancel',
onPress: () => {
// 用户取消,不执行任何操作
@@ -55,7 +57,7 @@ export function MedicationCard({ medication, colors, selectedDate, onOpenDetails
},
},
{
text: '确认已服用',
text: t('medications.card.earlyTakeAlert.confirm'),
style: 'default',
onPress: () => {
// 用户确认,执行服药逻辑
@@ -89,9 +91,9 @@ export function MedicationCard({ medication, colors, selectedDate, onOpenDetails
} catch (error) {
console.error('[MEDICATION_CARD] 服药操作失败', error);
Alert.alert(
'操作失败',
error instanceof Error ? error.message : '记录服药时发生错误,请稍后重试',
[{ text: '确定' }]
t('medications.card.takeError.title'),
error instanceof Error ? error.message : t('medications.card.takeError.message'),
[{ text: t('medications.card.takeError.confirm') }]
);
} finally {
setIsSubmitting(false);
@@ -102,7 +104,7 @@ export function MedicationCard({ medication, colors, selectedDate, onOpenDetails
if (medication.status === 'missed') {
return (
<View style={[styles.statusChip, styles.statusChipMissed]}>
<ThemedText style={styles.statusChipText}></ThemedText>
<ThemedText style={styles.statusChipText}>{t('medications.card.status.missed')}</ThemedText>
</View>
);
}
@@ -112,7 +114,7 @@ export function MedicationCard({ medication, colors, selectedDate, onOpenDetails
return (
<View style={[styles.statusChip, styles.statusChipUpcoming]}>
<Ionicons name="time-outline" size={14} color="#fff" />
<ThemedText style={styles.statusChipText}></ThemedText>
<ThemedText style={styles.statusChipText}>{t('medications.card.status.timeToTake')}</ThemedText>
</View>
);
}
@@ -125,7 +127,7 @@ export function MedicationCard({ medication, colors, selectedDate, onOpenDetails
return (
<View style={[styles.statusChip, styles.statusChipUpcoming]}>
<Ionicons name="time-outline" size={14} color="#fff" />
<ThemedText style={styles.statusChipText}> {formatted}</ThemedText>
<ThemedText style={styles.statusChipText}>{t('medications.card.status.remaining', { time: formatted })}</ThemedText>
</View>
);
}
@@ -138,7 +140,7 @@ export function MedicationCard({ medication, colors, selectedDate, onOpenDetails
return (
<View style={[styles.actionButton, styles.actionButtonTaken]}>
<Ionicons name="checkmark-circle" size={18} color="#fff" />
<ThemedText style={styles.actionButtonText}></ThemedText>
<ThemedText style={styles.actionButtonText}>{t('medications.card.action.taken')}</ThemedText>
</View>
);
}
@@ -158,13 +160,13 @@ export function MedicationCard({ medication, colors, selectedDate, onOpenDetails
isInteractive={!isSubmitting}
>
<ThemedText style={styles.actionButtonText}>
{isSubmitting ? '提交中...' : '立即服用'}
{isSubmitting ? t('medications.card.action.submitting') : t('medications.card.action.takeNow')}
</ThemedText>
</GlassView>
) : (
<View style={[styles.actionButton, styles.actionButtonUpcoming, styles.fallbackActionButton]}>
<ThemedText style={styles.actionButtonText}>
{isSubmitting ? '提交中...' : '立即服用'}
{isSubmitting ? t('medications.card.action.submitting') : t('medications.card.action.takeNow')}
</ThemedText>
</View>
)}