feat(i18n): 实现应用国际化支持,添加中英文翻译
- 为所有UI组件添加国际化支持,替换硬编码文本 - 新增useI18n钩子函数统一管理翻译 - 完善中英文翻译资源,覆盖统计、用药、通知设置等模块 - 优化Tab布局使用翻译键值替代静态文本 - 更新药品管理、个人资料编辑等页面的多语言支持
This commit is contained in:
@@ -3,12 +3,13 @@ import { ConfirmationSheet } from '@/components/ui/ConfirmationSheet';
|
||||
import { HeaderBar } from '@/components/ui/HeaderBar';
|
||||
import InfoCard from '@/components/ui/InfoCard';
|
||||
import { Colors } from '@/constants/Colors';
|
||||
import { DOSAGE_UNITS, DOSAGE_VALUES, FORM_LABELS, FORM_OPTIONS } from '@/constants/Medication';
|
||||
import { DOSAGE_UNITS, DOSAGE_VALUES, FORM_OPTIONS } from '@/constants/Medication';
|
||||
import { ROUTES } from '@/constants/Routes';
|
||||
import { useMembershipModal } from '@/contexts/MembershipModalContext';
|
||||
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
|
||||
import { useAuthGuard } from '@/hooks/useAuthGuard';
|
||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useVipService } from '@/hooks/useVipService';
|
||||
import { medicationNotificationService } from '@/services/medicationNotifications';
|
||||
import {
|
||||
@@ -59,6 +60,7 @@ type RecordsSummary = {
|
||||
};
|
||||
|
||||
export default function MedicationDetailScreen() {
|
||||
const { t } = useI18n();
|
||||
const params = useLocalSearchParams<{ medicationId?: string }>();
|
||||
const medicationId = Array.isArray(params.medicationId)
|
||||
? params.medicationId[0]
|
||||
@@ -198,7 +200,7 @@ export default function MedicationDetailScreen() {
|
||||
console.error('加载药品详情失败', err);
|
||||
console.log('[MEDICATION_DETAIL] API call failed for medication', medicationId, err);
|
||||
if (isMounted) {
|
||||
setError('暂时无法获取该药品的信息,请稍后重试。');
|
||||
setError(t('medications.detail.error.title'));
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
@@ -295,7 +297,7 @@ export default function MedicationDetailScreen() {
|
||||
console.log('[MEDICATION_DETAIL] voice error', error);
|
||||
setDictationActive(false);
|
||||
setDictationLoading(false);
|
||||
Alert.alert('语音识别不可用', '无法使用语音输入,请检查权限设置后重试');
|
||||
Alert.alert(t('medications.add.note.voiceError'), t('medications.add.note.voiceErrorMessage'));
|
||||
};
|
||||
|
||||
return () => {
|
||||
@@ -354,7 +356,7 @@ export default function MedicationDetailScreen() {
|
||||
} catch (error) {
|
||||
console.log('[MEDICATION_DETAIL] unable to start dictation', error);
|
||||
setDictationLoading(false);
|
||||
Alert.alert('无法启动语音输入', '请检查麦克风与语音识别权限后重试');
|
||||
Alert.alert(t('medications.add.note.voiceStartError'), t('medications.add.note.voiceStartErrorMessage'));
|
||||
}
|
||||
}, [dictationActive, dictationLoading, isDictationSupported]);
|
||||
|
||||
@@ -400,7 +402,7 @@ export default function MedicationDetailScreen() {
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('切换药品状态失败', err);
|
||||
Alert.alert('操作失败', '切换提醒状态时出现问题,请稍后重试。');
|
||||
Alert.alert(t('medications.detail.toggleError.title'), t('medications.detail.toggleError.message'));
|
||||
} finally {
|
||||
setUpdatePending(false);
|
||||
}
|
||||
@@ -430,13 +432,13 @@ export default function MedicationDetailScreen() {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('停用药物失败', error);
|
||||
Alert.alert('操作失败', '停用药物时发生问题,请稍后重试。');
|
||||
Alert.alert(t('medications.detail.deactivate.error.title'), t('medications.detail.deactivate.error.message'));
|
||||
} finally {
|
||||
setDeactivateLoading(false);
|
||||
}
|
||||
}, [dispatch, medication, deactivateLoading]);
|
||||
|
||||
const formLabel = medication ? FORM_LABELS[medication.form] : '';
|
||||
const formLabel = medication ? t(`medications.manage.formLabels.${medication.form}`) : '';
|
||||
const dosageLabel = medication ? `${medication.dosageValue} ${medication.dosageUnit}` : '--';
|
||||
const startDateLabel = medication
|
||||
? dayjs(medication.startDate).format('YYYY年M月D日')
|
||||
@@ -454,24 +456,24 @@ export default function MedicationDetailScreen() {
|
||||
return `${startDate} - ${endDate}`;
|
||||
} else {
|
||||
// 没有结束日期,显示长期
|
||||
return `${startDate} - 长期`;
|
||||
return `${startDate} - ${t('medications.detail.plan.longTerm')}`;
|
||||
}
|
||||
}, [medication]);
|
||||
}, [medication, t]);
|
||||
|
||||
const reminderTimes = medication?.medicationTimes?.length
|
||||
? medication.medicationTimes.join('、')
|
||||
: '尚未设置';
|
||||
: t('medications.manage.reminderNotSet');
|
||||
const frequencyLabel = useMemo(() => {
|
||||
if (!medication) return '--';
|
||||
switch (medication.repeatPattern) {
|
||||
case 'daily':
|
||||
return `每日 ${medication.timesPerDay} 次`;
|
||||
return `${t('medications.manage.frequency.daily')} ${medication.timesPerDay} ${t('medications.add.frequency.value', { count: medication.timesPerDay }).split(' ')[1]}`;
|
||||
case 'weekly':
|
||||
return `每周 ${medication.timesPerDay} 次`;
|
||||
return `${t('medications.manage.frequency.weekly')} ${medication.timesPerDay} ${t('medications.add.frequency.value', { count: medication.timesPerDay }).split(' ')[1]}`;
|
||||
default:
|
||||
return `自定义 · ${medication.timesPerDay} 次/日`;
|
||||
return `${t('medications.manage.frequency.custom')} · ${medication.timesPerDay} ${t('medications.add.frequency.value', { count: medication.timesPerDay }).split(' ')[1]}`;
|
||||
}
|
||||
}, [medication]);
|
||||
}, [medication, t]);
|
||||
|
||||
const handleOpenNoteModal = useCallback(() => {
|
||||
setNoteDraft(medication?.note ?? '');
|
||||
@@ -493,20 +495,20 @@ export default function MedicationDetailScreen() {
|
||||
closeNoteModal();
|
||||
} catch (err) {
|
||||
console.error('保存备注失败', err);
|
||||
Alert.alert('保存失败', '提交备注时出现问题,请稍后重试。');
|
||||
Alert.alert(t('medications.detail.note.saveError.title'), t('medications.detail.note.saveError.message'));
|
||||
} finally {
|
||||
setNoteSaving(false);
|
||||
}
|
||||
}, [closeNoteModal, dispatch, medication, noteDraft]);
|
||||
|
||||
const statusLabel = medication?.isActive ? '提醒已开启' : '提醒已关闭';
|
||||
const noteText = medication?.note?.trim() ? medication.note : '暂无备注信息';
|
||||
const statusLabel = medication?.isActive ? t('medications.detail.status.enabled') : t('medications.detail.status.disabled');
|
||||
const noteText = medication?.note?.trim() ? medication.note : t('medications.detail.note.noNote');
|
||||
const dayStreakText =
|
||||
typeof summary.startedDays === 'number'
|
||||
? `已坚持 ${summary.startedDays} 天`
|
||||
? t('medications.detail.overview.startedDays', { days: summary.startedDays })
|
||||
: medication
|
||||
? `开始于 ${dayjs(medication.startDate).format('YYYY年M月D日')}`
|
||||
: '暂无开始日期';
|
||||
? t('medications.detail.overview.startDate', { date: dayjs(medication.startDate).format('YYYY年M月D日') })
|
||||
: t('medications.detail.overview.noStartDate');
|
||||
|
||||
const handleDeleteMedication = useCallback(async () => {
|
||||
if (!medication || deleteLoading) {
|
||||
@@ -534,7 +536,7 @@ export default function MedicationDetailScreen() {
|
||||
router.back();
|
||||
} catch (err) {
|
||||
console.error('删除药品失败', err);
|
||||
Alert.alert('删除失败', '移除该药品时出现问题,请稍后再试。');
|
||||
Alert.alert(t('medications.detail.delete.error.title'), t('medications.detail.delete.error.message'));
|
||||
} finally {
|
||||
setDeleteLoading(false);
|
||||
}
|
||||
@@ -550,21 +552,26 @@ export default function MedicationDetailScreen() {
|
||||
if (!medication) return;
|
||||
|
||||
const startDate = dayjs(medication.startDate).format('YYYY年M月D日');
|
||||
let message = `开始服药日期:${startDate}`;
|
||||
|
||||
let message;
|
||||
if (medication.endDate) {
|
||||
const endDate = dayjs(medication.endDate).format('YYYY年M月D日');
|
||||
message += `\n结束服药日期:${endDate}`;
|
||||
message = t('medications.detail.plan.periodMessage', {
|
||||
startDate,
|
||||
endDateInfo: t('medications.detail.plan.periodMessage', { endDate })
|
||||
});
|
||||
} else {
|
||||
message += `\n服药计划:长期服药`;
|
||||
message = t('medications.detail.plan.periodMessage', {
|
||||
startDate,
|
||||
endDateInfo: t('medications.detail.plan.longTermPlan')
|
||||
});
|
||||
}
|
||||
|
||||
Alert.alert('服药周期', message);
|
||||
}, [medication]);
|
||||
Alert.alert(t('medications.detail.sections.plan'), message);
|
||||
}, [medication, t]);
|
||||
|
||||
const handleTimePress = useCallback(() => {
|
||||
Alert.alert('服药时间', `设置的时间:${reminderTimes}`);
|
||||
}, [reminderTimes]);
|
||||
Alert.alert(t('medications.detail.plan.time'), t('medications.detail.plan.timeMessage', { times: reminderTimes }));
|
||||
}, [reminderTimes, t]);
|
||||
|
||||
const handleDosagePress = useCallback(() => {
|
||||
if (!medication) return;
|
||||
@@ -621,7 +628,7 @@ export default function MedicationDetailScreen() {
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('更新剂量失败', err);
|
||||
Alert.alert('更新失败', '更新剂量时出现问题,请稍后重试。');
|
||||
Alert.alert(t('medications.detail.updateErrors.dosage'), t('medications.detail.updateErrors.dosageMessage'));
|
||||
} finally {
|
||||
setUpdatePending(false);
|
||||
}
|
||||
@@ -656,7 +663,7 @@ export default function MedicationDetailScreen() {
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('更新剂型失败', err);
|
||||
Alert.alert('更新失败', '更新剂型时出现问题,请稍后重试。');
|
||||
Alert.alert(t('medications.detail.updateErrors.form'), t('medications.detail.updateErrors.formMessage'));
|
||||
} finally {
|
||||
setUpdatePending(false);
|
||||
}
|
||||
@@ -723,27 +730,27 @@ export default function MedicationDetailScreen() {
|
||||
onError: (error: any) => {
|
||||
console.error('[MEDICATION] AI 分析失败:', error);
|
||||
|
||||
let errorMessage = 'AI 分析失败,请稍后重试';
|
||||
let errorMessage = t('medications.detail.aiAnalysis.error.message');
|
||||
|
||||
// 解析服务端返回的错误信息
|
||||
if (error?.message) {
|
||||
if (error.message.includes('[ERROR]')) {
|
||||
errorMessage = error.message.replace('[ERROR]', '').trim();
|
||||
} else if (error.message.includes('无权访问')) {
|
||||
errorMessage = '无权访问此药物';
|
||||
errorMessage = t('medications.detail.aiAnalysis.error.forbidden');
|
||||
} else if (error.message.includes('不存在')) {
|
||||
errorMessage = '药物不存在';
|
||||
errorMessage = t('medications.detail.aiAnalysis.error.notFound');
|
||||
}
|
||||
} else if (error?.status === 401) {
|
||||
errorMessage = '请先登录';
|
||||
errorMessage = t('medications.detail.aiAnalysis.error.unauthorized');
|
||||
} else if (error?.status === 403) {
|
||||
errorMessage = '无权访问此药物';
|
||||
errorMessage = t('medications.detail.aiAnalysis.error.forbidden');
|
||||
} else if (error?.status === 404) {
|
||||
errorMessage = '药物不存在';
|
||||
errorMessage = t('medications.detail.aiAnalysis.error.notFound');
|
||||
}
|
||||
|
||||
// 使用 Alert 弹窗显示错误
|
||||
Alert.alert('分析失败', errorMessage);
|
||||
Alert.alert(t('medications.detail.aiAnalysis.error.title'), errorMessage);
|
||||
|
||||
// 清空内容和加载状态
|
||||
setAiAnalysisContent('');
|
||||
@@ -756,7 +763,7 @@ export default function MedicationDetailScreen() {
|
||||
console.error('[MEDICATION] AI 分析异常:', error);
|
||||
|
||||
// 使用 Alert 弹窗显示错误
|
||||
Alert.alert('分析失败', '发起分析请求失败,请检查网络连接');
|
||||
Alert.alert(t('medications.detail.aiAnalysis.error.title'), t('medications.detail.aiAnalysis.error.networkError'));
|
||||
|
||||
// 清空内容和加载状态
|
||||
setAiAnalysisContent('');
|
||||
@@ -789,10 +796,10 @@ export default function MedicationDetailScreen() {
|
||||
<View style={styles.decorativeCircle1} />
|
||||
<View style={styles.decorativeCircle2} />
|
||||
|
||||
<HeaderBar title="药品详情" variant="minimal" transparent />
|
||||
<HeaderBar title={t('medications.detail.title')} variant="minimal" transparent />
|
||||
<View style={[styles.centered, { paddingTop: insets.top + 72, paddingHorizontal: 24 }]}>
|
||||
<ThemedText style={styles.emptyTitle}>未找到药品信息</ThemedText>
|
||||
<ThemedText style={styles.emptySubtitle}>请从用药列表重新进入此页面。</ThemedText>
|
||||
<ThemedText style={styles.emptyTitle}>{t('medications.detail.notFound.title')}</ThemedText>
|
||||
<ThemedText style={styles.emptySubtitle}>{t('medications.detail.notFound.subtitle')}</ThemedText>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
@@ -815,17 +822,17 @@ export default function MedicationDetailScreen() {
|
||||
<View style={styles.decorativeCircle1} />
|
||||
<View style={styles.decorativeCircle2} />
|
||||
|
||||
<HeaderBar title="药品详情" variant="minimal" transparent />
|
||||
<HeaderBar title={t('medications.detail.title')} variant="minimal" transparent />
|
||||
{isLoadingState ? (
|
||||
<View style={[styles.centered, { paddingTop: insets.top + 48 }]}>
|
||||
<ActivityIndicator color={colors.primary} />
|
||||
<Text style={[styles.loadingText, { color: colors.textSecondary }]}>正在载入...</Text>
|
||||
<Text style={[styles.loadingText, { color: colors.textSecondary }]}>{t('medications.detail.loading')}</Text>
|
||||
</View>
|
||||
) : error ? (
|
||||
<View style={[styles.centered, { paddingHorizontal: 24, paddingTop: insets.top + 72 }]}>
|
||||
<ThemedText style={styles.emptyTitle}>{error}</ThemedText>
|
||||
<ThemedText style={[styles.emptySubtitle, { color: colors.textMuted }]}>
|
||||
请检查网络后重试,或返回上一页。
|
||||
{t('medications.detail.error.subtitle')}
|
||||
</ThemedText>
|
||||
</View>
|
||||
) : medication ? (
|
||||
@@ -878,10 +885,10 @@ export default function MedicationDetailScreen() {
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Section title="服药计划" color={colors.text}>
|
||||
<Section title={t('medications.detail.sections.plan')} color={colors.text}>
|
||||
<View style={styles.row}>
|
||||
<InfoCard
|
||||
label="服药周期"
|
||||
label={t('medications.detail.plan.period')}
|
||||
value={medicationPeriodLabel}
|
||||
icon="calendar-outline"
|
||||
colors={colors}
|
||||
@@ -889,7 +896,7 @@ export default function MedicationDetailScreen() {
|
||||
onPress={handleStartDatePress}
|
||||
/>
|
||||
<InfoCard
|
||||
label="用药时间"
|
||||
label={t('medications.detail.plan.time')}
|
||||
value={reminderTimes}
|
||||
icon="time-outline"
|
||||
colors={colors}
|
||||
@@ -904,7 +911,7 @@ export default function MedicationDetailScreen() {
|
||||
>
|
||||
<View style={styles.fullCardLeading}>
|
||||
<Ionicons name="repeat-outline" size={18} color={colors.primary} />
|
||||
<Text style={[styles.fullCardLabel, { color: colors.text }]}>频率</Text>
|
||||
<Text style={[styles.fullCardLabel, { color: colors.text }]}>{t('medications.detail.plan.frequency')}</Text>
|
||||
</View>
|
||||
<View style={styles.fullCardTrailing}>
|
||||
<Text style={[styles.fullCardValue, { color: colors.text }]}>{frequencyLabel}</Text>
|
||||
@@ -913,10 +920,10 @@ export default function MedicationDetailScreen() {
|
||||
</TouchableOpacity>
|
||||
</Section>
|
||||
|
||||
<Section title="剂量与形式" color={colors.text}>
|
||||
<Section title={t('medications.detail.sections.dosage')} color={colors.text}>
|
||||
<View style={styles.row}>
|
||||
<InfoCard
|
||||
label="每次剂量"
|
||||
label={t('medications.detail.dosage.label')}
|
||||
value={dosageLabel}
|
||||
icon="medkit-outline"
|
||||
colors={colors}
|
||||
@@ -924,7 +931,7 @@ export default function MedicationDetailScreen() {
|
||||
onPress={handleDosagePress}
|
||||
/>
|
||||
<InfoCard
|
||||
label="剂型"
|
||||
label={t('medications.detail.dosage.form')}
|
||||
value={formLabel}
|
||||
icon="cube-outline"
|
||||
colors={colors}
|
||||
@@ -934,7 +941,7 @@ export default function MedicationDetailScreen() {
|
||||
</View>
|
||||
</Section>
|
||||
|
||||
<Section title="备注" color={colors.text}>
|
||||
<Section title={t('medications.detail.sections.note')} color={colors.text}>
|
||||
<TouchableOpacity
|
||||
style={[styles.noteCard, { backgroundColor: colors.surface }]}
|
||||
activeOpacity={0.92}
|
||||
@@ -942,7 +949,7 @@ export default function MedicationDetailScreen() {
|
||||
>
|
||||
<Ionicons name="document-text-outline" size={20} color={colors.primary} />
|
||||
<View style={styles.noteBody}>
|
||||
<Text style={[styles.noteLabel, { color: colors.text }]}>药品备注</Text>
|
||||
<Text style={[styles.noteLabel, { color: colors.text }]}>{t('medications.detail.note.label')}</Text>
|
||||
<Text
|
||||
style={[
|
||||
styles.noteValue,
|
||||
@@ -956,17 +963,17 @@ export default function MedicationDetailScreen() {
|
||||
</TouchableOpacity>
|
||||
</Section>
|
||||
|
||||
<Section title="服药概览" color={colors.text}>
|
||||
<Section title={t('medications.detail.sections.overview')} color={colors.text}>
|
||||
<View style={[styles.summaryCard, { backgroundColor: colors.surface }]}>
|
||||
<View style={styles.summaryIcon}>
|
||||
<Ionicons name="tablet-portrait-outline" size={22} color={colors.primary} />
|
||||
</View>
|
||||
<View style={styles.summaryBody}>
|
||||
<Text style={[styles.summaryHighlight, { color: colors.text }]}>
|
||||
{summaryLoading ? '统计中...' : `累计服药 ${summary.takenCount} 次`}
|
||||
{summaryLoading ? t('medications.detail.overview.calculating') : t('medications.detail.overview.takenCount', { count: summary.takenCount })}
|
||||
</Text>
|
||||
<Text style={[styles.summaryMeta, { color: colors.textSecondary }]}>
|
||||
{summaryLoading ? '正在计算坚持天数' : dayStreakText}
|
||||
{summaryLoading ? t('medications.detail.overview.calculatingDays') : dayStreakText}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
@@ -974,13 +981,13 @@ export default function MedicationDetailScreen() {
|
||||
|
||||
{/* AI 分析结果展示 - 移动到底部 */}
|
||||
{(aiAnalysisContent || aiAnalysisLoading) && (
|
||||
<Section title="AI 用药分析" color={colors.text}>
|
||||
<Section title={t('medications.detail.sections.aiAnalysis')} color={colors.text}>
|
||||
<View style={[styles.aiAnalysisCard, { backgroundColor: colors.surface }]}>
|
||||
{aiAnalysisLoading && !aiAnalysisContent && (
|
||||
<View style={styles.aiAnalysisLoading}>
|
||||
<ActivityIndicator color={colors.primary} size="small" />
|
||||
<Text style={[styles.aiAnalysisLoadingText, { color: colors.textSecondary }]}>
|
||||
正在分析用药信息...
|
||||
{t('medications.detail.aiAnalysis.analyzing')}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
@@ -1102,7 +1109,7 @@ export default function MedicationDetailScreen() {
|
||||
<Ionicons name="sparkles-outline" size={18} color="#fff" />
|
||||
)}
|
||||
<Text style={styles.aiAnalysisButtonText}>
|
||||
{aiAnalysisLoading ? '分析中...' : 'AI 分析'}
|
||||
{aiAnalysisLoading ? t('medications.detail.aiAnalysis.analyzingButton') : t('medications.detail.aiAnalysis.button')}
|
||||
</Text>
|
||||
</GlassView>
|
||||
) : (
|
||||
@@ -1113,7 +1120,7 @@ export default function MedicationDetailScreen() {
|
||||
<Ionicons name="sparkles-outline" size={18} color="#fff" />
|
||||
)}
|
||||
<Text style={styles.aiAnalysisButtonText}>
|
||||
{aiAnalysisLoading ? '分析中...' : 'AI 分析'}
|
||||
{aiAnalysisLoading ? t('medications.detail.aiAnalysis.analyzingButton') : t('medications.detail.aiAnalysis.button')}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
@@ -1161,7 +1168,7 @@ export default function MedicationDetailScreen() {
|
||||
<View style={[styles.modalCard, { backgroundColor: colors.surface }]}>
|
||||
<View style={styles.modalHandle} />
|
||||
<View style={styles.modalHeader}>
|
||||
<Text style={[styles.modalTitle, { color: colors.text }]}>编辑备注</Text>
|
||||
<Text style={[styles.modalTitle, { color: colors.text }]}>{t('medications.detail.note.edit')}</Text>
|
||||
<TouchableOpacity onPress={closeNoteModal} hitSlop={12}>
|
||||
<Ionicons name="close" size={20} color={colors.textSecondary} />
|
||||
</TouchableOpacity>
|
||||
@@ -1181,7 +1188,7 @@ export default function MedicationDetailScreen() {
|
||||
numberOfLines={6}
|
||||
value={noteDraft}
|
||||
onChangeText={setNoteDraft}
|
||||
placeholder="记录注意事项、医生叮嘱或自定义提醒"
|
||||
placeholder={t('medications.detail.note.placeholder')}
|
||||
placeholderTextColor={colors.textMuted}
|
||||
style={[styles.noteEditorInput, { color: colors.text }]}
|
||||
textAlignVertical="center"
|
||||
@@ -1213,7 +1220,7 @@ export default function MedicationDetailScreen() {
|
||||
</View>
|
||||
{!isDictationSupported && (
|
||||
<Text style={[styles.voiceHint, { color: colors.textMuted }]}>
|
||||
当前设备暂不支持语音转文字,可直接输入备注
|
||||
{t('medications.detail.note.voiceNotSupported')}
|
||||
</Text>
|
||||
)}
|
||||
<View style={styles.modalActionContainer}>
|
||||
@@ -1232,7 +1239,7 @@ export default function MedicationDetailScreen() {
|
||||
{noteSaving ? (
|
||||
<ActivityIndicator color={colors.onPrimary} size="small" />
|
||||
) : (
|
||||
<Text style={[styles.modalActionPrimaryText, { color: colors.onPrimary }]}>保存</Text>
|
||||
<Text style={[styles.modalActionPrimaryText, { color: colors.onPrimary }]}>{t('medications.detail.note.save')}</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
@@ -1253,12 +1260,12 @@ export default function MedicationDetailScreen() {
|
||||
/>
|
||||
<View style={[styles.pickerSheet, { backgroundColor: colors.surface }]}>
|
||||
<ThemedText style={[styles.pickerTitle, { color: colors.text }]}>
|
||||
选择剂量
|
||||
{t('medications.detail.dosage.selectDosage')}
|
||||
</ThemedText>
|
||||
<View style={styles.pickerRow}>
|
||||
<View style={styles.pickerColumn}>
|
||||
<ThemedText style={[styles.pickerLabel, { color: colors.textSecondary }]}>
|
||||
剂量值
|
||||
{t('medications.detail.dosage.dosageValue')}
|
||||
</ThemedText>
|
||||
<Picker
|
||||
selectedValue={dosageValuePicker}
|
||||
@@ -1277,7 +1284,7 @@ export default function MedicationDetailScreen() {
|
||||
</View>
|
||||
<View style={styles.pickerColumn}>
|
||||
<ThemedText style={[styles.pickerLabel, { color: colors.textSecondary }]}>
|
||||
单位
|
||||
{t('medications.detail.dosage.unit')}
|
||||
</ThemedText>
|
||||
<Picker
|
||||
selectedValue={dosageUnitPicker}
|
||||
@@ -1301,7 +1308,7 @@ export default function MedicationDetailScreen() {
|
||||
style={[styles.pickerBtn, { borderColor: colors.border }]}
|
||||
>
|
||||
<ThemedText style={[styles.pickerBtnText, { color: colors.textSecondary }]}>
|
||||
取消
|
||||
{t('medications.detail.pickers.cancel')}
|
||||
</ThemedText>
|
||||
</Pressable>
|
||||
<Pressable
|
||||
@@ -1309,7 +1316,7 @@ export default function MedicationDetailScreen() {
|
||||
style={[styles.pickerBtn, styles.pickerBtnPrimary, { backgroundColor: colors.primary }]}
|
||||
>
|
||||
<ThemedText style={[styles.pickerBtnText, { color: colors.onPrimary }]}>
|
||||
确定
|
||||
{t('medications.detail.pickers.confirm')}
|
||||
</ThemedText>
|
||||
</Pressable>
|
||||
</View>
|
||||
@@ -1328,7 +1335,7 @@ export default function MedicationDetailScreen() {
|
||||
/>
|
||||
<View style={[styles.pickerSheet, { backgroundColor: colors.surface }]}>
|
||||
<ThemedText style={[styles.pickerTitle, { color: colors.text }]}>
|
||||
选择剂型
|
||||
{t('medications.detail.dosage.selectForm')}
|
||||
</ThemedText>
|
||||
<Picker
|
||||
selectedValue={formPicker}
|
||||
@@ -1350,7 +1357,7 @@ export default function MedicationDetailScreen() {
|
||||
style={[styles.pickerBtn, { borderColor: colors.border }]}
|
||||
>
|
||||
<ThemedText style={[styles.pickerBtnText, { color: colors.textSecondary }]}>
|
||||
取消
|
||||
{t('medications.detail.pickers.cancel')}
|
||||
</ThemedText>
|
||||
</Pressable>
|
||||
<Pressable
|
||||
@@ -1358,7 +1365,7 @@ export default function MedicationDetailScreen() {
|
||||
style={[styles.pickerBtn, styles.pickerBtnPrimary, { backgroundColor: colors.primary }]}
|
||||
>
|
||||
<ThemedText style={[styles.pickerBtnText, { color: colors.onPrimary }]}>
|
||||
确定
|
||||
{t('medications.detail.pickers.confirm')}
|
||||
</ThemedText>
|
||||
</Pressable>
|
||||
</View>
|
||||
@@ -1370,10 +1377,10 @@ export default function MedicationDetailScreen() {
|
||||
visible={deleteSheetVisible}
|
||||
onClose={() => setDeleteSheetVisible(false)}
|
||||
onConfirm={handleDeleteMedication}
|
||||
title={`删除 ${medication.name}?`}
|
||||
description="删除后将清除与该药品相关的提醒与历史记录,且无法恢复。"
|
||||
confirmText="删除"
|
||||
cancelText="取消"
|
||||
title={t('medications.detail.delete.title', { name: medication.name })}
|
||||
description={t('medications.detail.delete.description')}
|
||||
confirmText={t('medications.detail.delete.confirm')}
|
||||
cancelText={t('medications.detail.delete.cancel')}
|
||||
destructive
|
||||
loading={deleteLoading}
|
||||
/>
|
||||
@@ -1384,10 +1391,10 @@ export default function MedicationDetailScreen() {
|
||||
visible={deactivateSheetVisible}
|
||||
onClose={() => setDeactivateSheetVisible(false)}
|
||||
onConfirm={handleDeactivateMedication}
|
||||
title={`停用 ${medication.name}?`}
|
||||
description="停用后,当天已生成的用药计划会一并删除,且无法恢复。"
|
||||
confirmText="确认停用"
|
||||
cancelText="取消"
|
||||
title={t('medications.detail.deactivate.title', { name: medication.name })}
|
||||
description={t('medications.detail.deactivate.description')}
|
||||
confirmText={t('medications.detail.deactivate.confirm')}
|
||||
cancelText={t('medications.detail.deactivate.cancel')}
|
||||
destructive
|
||||
loading={deactivateLoading}
|
||||
/>
|
||||
@@ -1415,7 +1422,7 @@ export default function MedicationDetailScreen() {
|
||||
style={styles.imageViewerFooterButton}
|
||||
onPress={() => setShowImagePreview(false)}
|
||||
>
|
||||
<Text style={styles.imageViewerFooterButtonText}>关闭</Text>
|
||||
<Text style={styles.imageViewerFooterButtonText}>{t('medications.detail.imageViewer.close')}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user