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

@@ -3,6 +3,7 @@ import { GlassContainer, GlassView, isLiquidGlassAvailable } from 'expo-glass-ef
import * as Haptics from 'expo-haptics';
import { Tabs, usePathname } from 'expo-router';
import { Icon, Label, NativeTabs } from 'expo-router/unstable-native-tabs';
import { useTranslation } from 'react-i18next';
import React from 'react';
import { Text, TouchableOpacity, View, ViewStyle } from 'react-native';
@@ -16,18 +17,19 @@ import { useColorScheme } from '@/hooks/useColorScheme';
// Tab configuration
type TabConfig = {
icon: string;
title: string;
titleKey: string;
};
const TAB_CONFIGS: Record<string, TabConfig> = {
statistics: { icon: 'chart.pie.fill', title: '健康' },
medications: { icon: 'pills.fill', title: '用药' },
fasting: { icon: 'timer', title: '断食' },
challenges: { icon: 'trophy.fill', title: '挑战' },
personal: { icon: 'person.fill', title: '个人' },
statistics: { icon: 'chart.pie.fill', titleKey: 'statistics.tabs.health' },
medications: { icon: 'pills.fill', titleKey: 'statistics.tabs.medications' },
fasting: { icon: 'timer', titleKey: 'statistics.tabs.fasting' },
challenges: { icon: 'trophy.fill', titleKey: 'statistics.tabs.challenges' },
personal: { icon: 'person.fill', titleKey: 'statistics.tabs.personal' },
};
export default function TabLayout() {
const { t } = useTranslation();
const theme = (useColorScheme() ?? 'light') as 'light' | 'dark';
const colorTokens = Colors[theme];
const pathname = usePathname();
@@ -96,7 +98,7 @@ export default function TabLayout() {
}}
numberOfLines={1}
>
{tabConfig.title}
{t(tabConfig.titleKey)}
</Text>
)}
</View>
@@ -175,24 +177,24 @@ export default function TabLayout() {
if (glassEffectAvailable) {
return <NativeTabs>
<NativeTabs.Trigger name="statistics">
<Label></Label>
<Label>{t('statistics.tabs.health')}</Label>
<Icon sf="chart.pie.fill" drawable="custom_android_drawable" />
</NativeTabs.Trigger>
<NativeTabs.Trigger name="medications">
<Icon sf="pills.fill" drawable="custom_android_drawable" />
<Label></Label>
<Label>{t('statistics.tabs.medications')}</Label>
</NativeTabs.Trigger>
<NativeTabs.Trigger name="fasting">
<Icon sf="timer" drawable="custom_android_drawable" />
<Label></Label>
<Label>{t('statistics.tabs.fasting')}</Label>
</NativeTabs.Trigger>
<NativeTabs.Trigger name="challenges">
<Icon sf="trophy.fill" drawable="custom_android_drawable" />
<Label></Label>
<Label>{t('statistics.tabs.challenges')}</Label>
</NativeTabs.Trigger>
<NativeTabs.Trigger name="personal">
<Icon sf="person.fill" drawable="custom_settings_drawable" />
<Label></Label>
<Label>{t('statistics.tabs.personal')}</Label>
</NativeTabs.Trigger>
</NativeTabs>
}
@@ -203,11 +205,11 @@ export default function TabLayout() {
screenOptions={({ route }) => getScreenOptions(route.name)}
>
<Tabs.Screen name="statistics" options={{ title: '健康' }} />
<Tabs.Screen name="medications" options={{ title: '用药' }} />
<Tabs.Screen name="fasting" options={{ title: '断食' }} />
<Tabs.Screen name="challenges" options={{ title: '挑战' }} />
<Tabs.Screen name="personal" options={{ title: '个人' }} />
<Tabs.Screen name="statistics" options={{ title: t('statistics.tabs.health') }} />
<Tabs.Screen name="medications" options={{ title: t('statistics.tabs.medications') }} />
<Tabs.Screen name="fasting" options={{ title: t('statistics.tabs.fasting') }} />
<Tabs.Screen name="challenges" options={{ title: t('statistics.tabs.challenges') }} />
<Tabs.Screen name="personal" options={{ title: t('statistics.tabs.personal') }} />
</Tabs>
);
}