diff --git a/maternal-web/app/children/page.tsx b/maternal-web/app/children/page.tsx
index 1c4ee7d..e55a649 100644
--- a/maternal-web/app/children/page.tsx
+++ b/maternal-web/app/children/page.tsx
@@ -239,7 +239,7 @@ export default function ChildrenPage() {
{child.name}
diff --git a/maternal-web/app/family/page.tsx b/maternal-web/app/family/page.tsx
index 7dbd477..fbe54cd 100644
--- a/maternal-web/app/family/page.tsx
+++ b/maternal-web/app/family/page.tsx
@@ -25,8 +25,10 @@ import { InviteMemberDialog } from '@/components/family/InviteMemberDialog';
import { JoinFamilyDialog } from '@/components/family/JoinFamilyDialog';
import { RemoveMemberDialog } from '@/components/family/RemoveMemberDialog';
import { motion } from 'framer-motion';
+import { useTranslation } from '@/hooks/useTranslation';
export default function FamilyPage() {
+ const { t } = useTranslation('family');
const { user, refreshUser } = useAuth();
const [family, setFamily] = useState(null);
const [members, setMembers] = useState([]);
@@ -47,7 +49,7 @@ export default function FamilyPage() {
fetchFamilyData();
} else {
setLoading(false);
- setError('No family found. Please complete onboarding first.');
+ setError(t('messages.noFamilyFound'));
}
}, [familyId]);
@@ -65,7 +67,7 @@ export default function FamilyPage() {
setMembers(membersData);
} catch (err: any) {
console.error('Failed to fetch family data:', err);
- setError(err.response?.data?.message || 'Failed to load family information');
+ setError(err.response?.data?.message || t('messages.failedToLoad'));
} finally {
setLoading(false);
}
@@ -76,26 +78,26 @@ export default function FamilyPage() {
try {
await navigator.clipboard.writeText(family.shareCode);
- setSnackbar({ open: true, message: 'Share code copied to clipboard!' });
+ setSnackbar({ open: true, message: t('messages.shareCodeCopied') });
} catch (err) {
- setSnackbar({ open: true, message: 'Failed to copy share code' });
+ setSnackbar({ open: true, message: t('messages.shareCodeCopyFailed') });
}
};
const handleInviteMember = async (data: InviteMemberData) => {
if (!familyId) {
- throw new Error('No family ID found');
+ throw new Error(t('messages.noFamilyId'));
}
try {
setActionLoading(true);
await familiesApi.inviteMember(familyId, data);
- setSnackbar({ open: true, message: 'Invitation sent successfully!' });
+ setSnackbar({ open: true, message: t('messages.invitationSent') });
await fetchFamilyData();
setInviteDialogOpen(false);
} catch (err: any) {
console.error('Failed to invite member:', err);
- throw new Error(err.response?.data?.message || 'Failed to send invitation');
+ throw new Error(err.response?.data?.message || t('messages.failedToInvite'));
} finally {
setActionLoading(false);
}
@@ -105,13 +107,13 @@ export default function FamilyPage() {
try {
setActionLoading(true);
await familiesApi.joinFamily(data);
- setSnackbar({ open: true, message: 'Successfully joined family!' });
+ setSnackbar({ open: true, message: t('messages.joinedFamily') });
await refreshUser();
await fetchFamilyData();
setJoinDialogOpen(false);
} catch (err: any) {
console.error('Failed to join family:', err);
- throw new Error(err.response?.data?.message || 'Failed to join family');
+ throw new Error(err.response?.data?.message || t('messages.failedToJoin'));
} finally {
setActionLoading(false);
}
@@ -128,13 +130,13 @@ export default function FamilyPage() {
try {
setActionLoading(true);
await familiesApi.removeMember(familyId, memberToRemove.userId);
- setSnackbar({ open: true, message: 'Member removed successfully' });
+ setSnackbar({ open: true, message: t('messages.memberRemoved') });
await fetchFamilyData();
setRemoveDialogOpen(false);
setMemberToRemove(null);
} catch (err: any) {
console.error('Failed to remove member:', err);
- setError(err.response?.data?.message || 'Failed to remove member');
+ setError(err.response?.data?.message || t('messages.failedToRemove'));
} finally {
setActionLoading(false);
}
@@ -164,10 +166,10 @@ export default function FamilyPage() {
- Family
+ {t('pageTitle')}
- Manage your family members and share access
+ {t('pageSubtitle')}
@@ -177,7 +179,7 @@ export default function FamilyPage() {
onClick={() => setJoinDialogOpen(true)}
disabled={loading}
>
- Join Family
+ {t('buttons.joinFamily')}
@@ -208,10 +210,10 @@ export default function FamilyPage() {
- Family Share Code
+ {t('shareCode.title')}
- Share this code with family members to give them access to your family's data
+ {t('shareCode.description')}
}
onClick={handleCopyCode}
>
- Copy Code
+ {t('buttons.copyCode')}
@@ -242,30 +244,30 @@ export default function FamilyPage() {
- Family Members ({members.length})
+ {t('members.title', { count: members.length })}
{members.length === 0 ? (
- No family members yet
+ {t('members.noMembers')}
- Invite family members to collaborate on child care
+ {t('members.noMembersDescription')}
}
onClick={() => setInviteDialogOpen(true)}
>
- Invite First Member
+ {t('buttons.inviteFirstMember')}
) : (
{members.map((member, index) => {
- const memberName = member.user?.name || 'Unknown User';
+ const memberName = member.user?.name || t('placeholders.unknownUser');
return (
{isCurrentUser(member.userId) && (
-
+
)}
- {member.user?.email || 'No email'}
+ {member.user?.email || t('placeholders.noEmail')}
@@ -306,7 +308,7 @@ export default function FamilyPage() {
size="small"
onClick={() => handleRemoveClick(member)}
color="error"
- aria-label={`Remove ${memberName} from family`}
+ aria-label={t('members.removeAriaLabel', { name: memberName })}
>
diff --git a/maternal-web/app/track/feeding/page.tsx b/maternal-web/app/track/feeding/page.tsx
index 88bf450..473d450 100644
--- a/maternal-web/app/track/feeding/page.tsx
+++ b/maternal-web/app/track/feeding/page.tsx
@@ -142,7 +142,7 @@ function FeedingTrackPage() {
}
} catch (err: any) {
console.error('Failed to load children:', err);
- setError(err.response?.data?.message || 'Failed to load children');
+ setError(err.response?.data?.message || t('common.error.loadChildrenFailed'));
} finally {
setChildrenLoading(false);
}
@@ -189,23 +189,23 @@ function FeedingTrackPage() {
const handleSubmit = async () => {
if (!selectedChild) {
- setError('Please select a child');
+ setError(t('common.selectChild'));
return;
}
// Validation
if (feedingType === 'breast' && duration === 0 && timerSeconds === 0) {
- setError('Please enter duration or use the timer');
+ setError(t('feeding.validation.durationRequired'));
return;
}
if (feedingType === 'bottle' && !amount) {
- setError('Please enter amount');
+ setError(t('feeding.validation.amountRequired'));
return;
}
if (feedingType === 'solid' && !foodDescription) {
- setError('Please enter food description');
+ setError(t('feeding.validation.foodRequired'));
return;
}
@@ -235,7 +235,7 @@ function FeedingTrackPage() {
notes: notes || undefined,
});
- setSuccessMessage('Feeding logged successfully!');
+ setSuccessMessage(t('feeding.success'));
// Reset form
resetForm();
@@ -244,7 +244,7 @@ function FeedingTrackPage() {
await loadRecentFeedings();
} catch (err: any) {
console.error('Failed to save feeding:', err);
- setError(err.response?.data?.message || 'Failed to save feeding');
+ setError(err.response?.data?.message || t('feeding.error.saveFailed'));
} finally {
setLoading(false);
}
@@ -273,13 +273,13 @@ function FeedingTrackPage() {
try {
setLoading(true);
await trackingApi.deleteActivity(activityToDelete);
- setSuccessMessage('Feeding deleted successfully');
+ setSuccessMessage(t('feeding.deleted'));
setDeleteDialogOpen(false);
setActivityToDelete(null);
await loadRecentFeedings();
} catch (err: any) {
console.error('Failed to delete feeding:', err);
- setError(err.response?.data?.message || 'Failed to delete feeding');
+ setError(err.response?.data?.message || t('feeding.error.deleteFailed'));
} finally {
setLoading(false);
}
@@ -345,17 +345,17 @@ function FeedingTrackPage() {
- No Children Added
+ {t('common.noChildrenAdded')}
- You need to add a child before you can track feeding activities
+ {t('common.noChildrenMessage')}
}
onClick={() => router.push('/children')}
>
- Add Child
+ {t('common.addChild')}
@@ -414,11 +414,11 @@ function FeedingTrackPage() {
{children.length > 1 && (
- Select Child
+ {t('common.selectChild')}
@@ -591,7 +591,7 @@ function FeedingTrackPage() {
- {t('feeding.title')}
+ {t('feeding.recentFeedings')}
@@ -685,10 +685,10 @@ function FeedingTrackPage() {
diff --git a/maternal-web/app/track/medicine/page.tsx b/maternal-web/app/track/medicine/page.tsx
index 4bd4ef6..376576d 100644
--- a/maternal-web/app/track/medicine/page.tsx
+++ b/maternal-web/app/track/medicine/page.tsx
@@ -114,7 +114,7 @@ function MedicineTrackPage() {
}
} catch (err: any) {
console.error('Failed to load children:', err);
- setError(err.response?.data?.message || 'Failed to load children');
+ setError(err.response?.data?.message || t('common.error.loadChildrenFailed'));
} finally {
setChildrenLoading(false);
}
@@ -140,19 +140,19 @@ function MedicineTrackPage() {
const handleSubmit = async () => {
if (!selectedChild) {
- setError('Please select a child');
+ setError(t('common.selectChild'));
return;
}
// Validation
if (!medicineName) {
- setError('Please enter medicine name');
+ setError(t('health.medicineName.required'));
return;
}
const dosageValue = unit === 'ml' ? dosage : dosageText;
if (!dosageValue || (unit === 'ml' && dosage === 0) || (unit !== 'ml' && !dosageText)) {
- setError('Please enter dosage');
+ setError(t('health.dosage.required'));
return;
}
@@ -175,7 +175,7 @@ function MedicineTrackPage() {
notes: notes || undefined,
});
- setSuccessMessage('Medicine logged successfully!');
+ setSuccessMessage(t('health.success'));
// Reset form
resetForm();
@@ -184,7 +184,7 @@ function MedicineTrackPage() {
await loadRecentMedicines();
} catch (err: any) {
console.error('Failed to save medicine:', err);
- setError(err.response?.data?.message || 'Failed to save medicine');
+ setError(err.response?.data?.message || t('health.error'));
} finally {
setLoading(false);
}
@@ -211,13 +211,13 @@ function MedicineTrackPage() {
try {
setLoading(true);
await trackingApi.deleteActivity(activityToDelete);
- setSuccessMessage('Medicine deleted successfully');
+ setSuccessMessage(t('health.deleted'));
setDeleteDialogOpen(false);
setActivityToDelete(null);
await loadRecentMedicines();
} catch (err: any) {
console.error('Failed to delete medicine:', err);
- setError(err.response?.data?.message || 'Failed to delete medicine');
+ setError(err.response?.data?.message || t('health.deleteError'));
} finally {
setLoading(false);
}
@@ -282,17 +282,17 @@ function MedicineTrackPage() {
- No Children Added
+ {t('common.noChildrenAdded')}
- You need to add a child before you can track medicine activities
+ {t('common.noChildrenMessage')}
}
onClick={() => router.push('/children')}
>
- Add Child
+ {t('common.addChild')}
@@ -352,11 +352,11 @@ function MedicineTrackPage() {
{children.length > 1 && (
- Select Child
+ {t('common.selectChild')}
@@ -485,7 +485,7 @@ function MedicineTrackPage() {
- {t('activities.medicine')}
+ {t('health.recentMedicines')}
@@ -578,10 +578,10 @@ function MedicineTrackPage() {
diff --git a/maternal-web/components/features/ai-chat/AIChatInterface.tsx b/maternal-web/components/features/ai-chat/AIChatInterface.tsx
index 5fd43a9..81d6c8b 100644
--- a/maternal-web/components/features/ai-chat/AIChatInterface.tsx
+++ b/maternal-web/components/features/ai-chat/AIChatInterface.tsx
@@ -52,6 +52,7 @@ import { useAuth } from '@/lib/auth/AuthContext';
import apiClient from '@/lib/api/client';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
+import { useTranslation } from '@/hooks/useTranslation';
interface Message {
id: string;
@@ -83,43 +84,9 @@ interface ConversationGroup {
isCollapsed: boolean;
}
-const suggestedQuestions = [
- 'How much should my baby sleep at 3 months?',
- 'What are normal feeding patterns?',
- 'When should I introduce solid foods?',
- 'Tips for better sleep routine',
-];
-
-const thinkingMessages = [
- 'Gathering baby wisdom...',
- 'Consulting the baby books...',
- 'Mixing up the perfect answer...',
- 'Warming up some advice...',
- 'Preparing your bottle of knowledge...',
- 'Counting tiny fingers and toes...',
- 'Connecting the building blocks...',
- 'Peeking into the toy box...',
- 'Arranging the puzzle pieces...',
- 'Stirring the baby food jar...',
- 'Polishing the pacifier of wisdom...',
- 'Tiptoeing through naptime...',
- 'Organizing the diaper bag...',
- 'Wrapping up your answer with love...',
- 'Brewing a warm cup of guidance...',
- 'Knitting together some thoughts...',
- 'Tucking in the details...',
- 'Sprinkling some magic dust...',
- 'Humming a lullaby while I think...',
-];
-
-// Get a random selection of 3-5 thinking messages
-const getRandomThinkingMessages = () => {
- const count = Math.floor(Math.random() * 3) + 3; // 3 to 5
- const shuffled = [...thinkingMessages].sort(() => Math.random() - 0.5);
- return shuffled.slice(0, count);
-};
export const AIChatInterface: React.FC = () => {
+ const { t } = useTranslation('ai');
const [messages, setMessages] = useState([]);
const [input, setInput] = useState('');
const [isLoading, setIsLoading] = useState(false);
@@ -141,6 +108,43 @@ export const AIChatInterface: React.FC = () => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
+ // Localized arrays that depend on translations
+ const suggestedQuestions = [
+ t('interface.suggestedQuestion1'),
+ t('interface.suggestedQuestion2'),
+ t('interface.suggestedQuestion3'),
+ t('interface.suggestedQuestion4'),
+ ];
+
+ const thinkingMessages = [
+ t('interface.thinking1'),
+ t('interface.thinking2'),
+ t('interface.thinking3'),
+ t('interface.thinking4'),
+ t('interface.thinking5'),
+ t('interface.thinking6'),
+ t('interface.thinking7'),
+ t('interface.thinking8'),
+ t('interface.thinking9'),
+ t('interface.thinking10'),
+ t('interface.thinking11'),
+ t('interface.thinking12'),
+ t('interface.thinking13'),
+ t('interface.thinking14'),
+ t('interface.thinking15'),
+ t('interface.thinking16'),
+ t('interface.thinking17'),
+ t('interface.thinking18'),
+ t('interface.thinking19'),
+ ];
+
+ // Get a random selection of 3-5 thinking messages
+ const getRandomThinkingMessages = () => {
+ const count = Math.floor(Math.random() * 3) + 3; // 3 to 5
+ const shuffled = [...thinkingMessages].sort(() => Math.random() - 0.5);
+ return shuffled.slice(0, count);
+ };
+
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
};
@@ -243,10 +247,11 @@ export const AIChatInterface: React.FC = () => {
// Group conversations by their group name
const organizeConversations = (): ConversationGroup[] => {
const groups: { [key: string]: Conversation[] } = {};
+ const ungroupedLabel = t('interface.ungrouped');
// Separate conversations by group
conversations.forEach((conv) => {
- const groupName = conv.metadata?.groupName || 'Ungrouped';
+ const groupName = conv.metadata?.groupName || ungroupedLabel;
if (!groups[groupName]) {
groups[groupName] = [];
}
@@ -262,8 +267,8 @@ export const AIChatInterface: React.FC = () => {
}))
.sort((a, b) => {
// Ungrouped always last
- if (a.name === 'Ungrouped') return 1;
- if (b.name === 'Ungrouped') return -1;
+ if (a.name === ungroupedLabel) return 1;
+ if (b.name === ungroupedLabel) return -1;
return a.name.localeCompare(b.name);
});
@@ -372,7 +377,7 @@ export const AIChatInterface: React.FC = () => {
const errorMessage: Message = {
id: (Date.now() + 1).toString(),
role: 'assistant',
- content: 'Sorry, I encountered an error. Please try again.',
+ content: t('interface.errorMessage'),
timestamp: new Date(),
};
setMessages((prev) => [...prev, errorMessage]);
@@ -390,10 +395,10 @@ export const AIChatInterface: React.FC = () => {
- Chat History
+ {t('history.title')}
{isMobile && (
- setDrawerOpen(false)} size="small" aria-label="Close drawer">
+ setDrawerOpen(false)} size="small" aria-label={t('interface.closeDrawer')}>
)}
@@ -405,7 +410,7 @@ export const AIChatInterface: React.FC = () => {
onClick={handleNewConversation}
sx={{ borderRadius: 2 }}
>
- New Chat
+ {t('chat.newChat')}
@@ -413,7 +418,7 @@ export const AIChatInterface: React.FC = () => {
- No conversations yet
+ {t('history.noHistory')}
) : (
@@ -434,7 +439,7 @@ export const AIChatInterface: React.FC = () => {
{
}
}}
sx={{ ml: 1 }}
- aria-label={isMobile ? 'More options' : 'Delete conversation'}
+ aria-label={isMobile ? t('interface.moreOptions') : t('interface.deleteConversation')}
>
{isMobile ? : }
@@ -566,10 +571,10 @@ export const AIChatInterface: React.FC = () => {
- AI Parenting Assistant
+ {t('interface.assistantTitle')}
- Ask me anything about parenting and childcare
+ {t('interface.assistantSubtitle')}
@@ -599,7 +604,7 @@ export const AIChatInterface: React.FC = () => {
>
- Hi {user?.name}! How can I help you today?
+ {t('interface.greeting', { name: user?.name })}
{
transition: 'opacity 0.3s ease-in-out',
}}
>
- {currentThinkingMessages[currentThinkingIndex] || 'Thinking...'}
+ {currentThinkingMessages[currentThinkingIndex] || t('chat.thinking')}
@@ -758,7 +763,7 @@ export const AIChatInterface: React.FC = () => {
fullWidth
multiline
maxRows={4}
- placeholder="Ask me anything..."
+ placeholder={t('interface.inputPlaceholder')}
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => {
@@ -795,24 +800,23 @@ export const AIChatInterface: React.FC = () => {
- This AI assistant provides general information. Always consult healthcare professionals
- for medical advice.
+ {t('interface.disclaimerFooter')}
{/* Delete Confirmation Dialog */}
@@ -837,7 +841,7 @@ export const AIChatInterface: React.FC = () => {
- Move to Group
+ {t('interface.moveToGroup')}
{
@@ -851,7 +855,7 @@ export const AIChatInterface: React.FC = () => {
- Delete
+ {t('interface.delete')}
@@ -862,7 +866,7 @@ export const AIChatInterface: React.FC = () => {
maxWidth="xs"
fullWidth
>
- Move to Group
+ {t('interface.moveToGroup')}
{
-
+
{getExistingGroups().map((groupName) => (
@@ -898,13 +902,13 @@ export const AIChatInterface: React.FC = () => {
-
+
@@ -919,12 +923,12 @@ export const AIChatInterface: React.FC = () => {
maxWidth="xs"
fullWidth
>
- Create New Group
+ {t('interface.createNewGroup')}
{
setNewGroupName('');
}}
>
- Cancel
+ {t('interface.cancel')}
diff --git a/maternal-web/components/features/analytics/InsightsDashboard.tsx b/maternal-web/components/features/analytics/InsightsDashboard.tsx
index c3ee7ca..af32bb7 100644
--- a/maternal-web/components/features/analytics/InsightsDashboard.tsx
+++ b/maternal-web/components/features/analytics/InsightsDashboard.tsx
@@ -41,6 +41,7 @@ import { trackingApi, Activity, ActivityType } from '@/lib/api/tracking';
import { childrenApi, Child } from '@/lib/api/children';
import { subDays, startOfDay, endOfDay, parseISO, differenceInMinutes } from 'date-fns';
import { useLocalizedDate } from '@/hooks/useLocalizedDate';
+import { useTranslation } from '@/hooks/useTranslation';
import { BarChart, Bar, LineChart, Line, PieChart, Pie, Cell, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
type DateRange = '7days' | '30days' | '3months';
@@ -99,6 +100,7 @@ const getActivityColor = (type: ActivityType) => {
export const InsightsDashboard: React.FC = () => {
const router = useRouter();
const { format, formatDistanceToNow } = useLocalizedDate();
+ const { t } = useTranslation('insights');
const [children, setChildren] = useState([]);
const [selectedChild, setSelectedChild] = useState('');
const [dateRange, setDateRange] = useState('7days');
@@ -116,7 +118,7 @@ export const InsightsDashboard: React.FC = () => {
setSelectedChild(childrenData[0].id);
}
} catch (err: any) {
- setError(err.response?.data?.message || 'Failed to load children');
+ setError(err.response?.data?.message || t('errors.loadChildren'));
}
};
fetchChildren();
@@ -142,7 +144,7 @@ export const InsightsDashboard: React.FC = () => {
);
setActivities(activitiesData);
} catch (err: any) {
- setError(err.response?.data?.message || 'Failed to load activities');
+ setError(err.response?.data?.message || t('errors.loadActivities'));
} finally {
setLoading(false);
}
@@ -172,7 +174,7 @@ export const InsightsDashboard: React.FC = () => {
activities.forEach((a) => {
typeCounts[a.type] = (typeCounts[a.type] || 0) + 1;
});
- const mostCommonType = Object.entries(typeCounts).sort((a, b) => b[1] - a[1])[0]?.[0] || 'None';
+ const mostCommonType = Object.entries(typeCounts).sort((a, b) => b[1] - a[1])[0]?.[0] || 'none';
return {
totalFeedings,
@@ -230,7 +232,7 @@ export const InsightsDashboard: React.FC = () => {
});
return Object.entries(typeCount).map(([name, value]) => ({
- name: name.charAt(0).toUpperCase() + name.slice(1),
+ name: t(`diaperTypes.${name}`),
value,
color: COLORS[name as keyof typeof COLORS] || '#CCCCCC',
}));
@@ -244,7 +246,7 @@ export const InsightsDashboard: React.FC = () => {
});
return Object.entries(typeCount).map(([name, count]) => ({
- name: name.charAt(0).toUpperCase() + name.slice(1),
+ name: t(`activityTypes.${name}`),
count,
color: COLORS[name as keyof typeof COLORS] || '#CCCCCC',
}));
@@ -269,10 +271,10 @@ export const InsightsDashboard: React.FC = () => {
>
- Insights & Analytics
+ {t('title')}
- Track patterns and get insights about your child's activities
+ {t('subtitle')}
{/* Filters */}
@@ -281,11 +283,11 @@ export const InsightsDashboard: React.FC = () => {
{children.length > 1 && (
- Child
+ {t('filters.child')}
setSelectedChild(e.target.value)}
- label="Child"
+ label={t('filters.child')}
>
{children.map((child) => (
@@ -304,9 +306,9 @@ export const InsightsDashboard: React.FC = () => {
fullWidth
size="large"
>
- 7 Days
- 30 Days
- 3 Months
+ {t('filters.dateRange.7days')}
+ {t('filters.dateRange.30days')}
+ {t('filters.dateRange.3months')}
@@ -323,17 +325,17 @@ export const InsightsDashboard: React.FC = () => {
- No Children Added
+ {t('emptyStates.noChildren.title')}
- Add a child to view insights and analytics
+ {t('emptyStates.noChildren.message')}
}
onClick={() => router.push('/children')}
>
- Add Child
+ {t('emptyStates.noChildren.action')}
@@ -347,7 +349,7 @@ export const InsightsDashboard: React.FC = () => {
{noActivities && !noChildren && (
- No activities found for the selected date range. Start tracking activities to see insights!
+ {t('emptyStates.noActivities')}
)}
@@ -366,14 +368,14 @@ export const InsightsDashboard: React.FC = () => {
- Feedings
+ {t('stats.feedings.title')}
{stats.totalFeedings}
- Total count
+ {t('stats.feedings.subtitle')}
@@ -391,14 +393,14 @@ export const InsightsDashboard: React.FC = () => {
- Sleep
+ {t('stats.sleep.title')}
{stats.avgSleepHours}h
- Average per day
+ {t('stats.sleep.subtitle')}
@@ -416,14 +418,14 @@ export const InsightsDashboard: React.FC = () => {
- Diapers
+ {t('stats.diapers.title')}
{stats.totalDiapers}
- Total changes
+ {t('stats.diapers.subtitle')}
@@ -441,14 +443,14 @@ export const InsightsDashboard: React.FC = () => {
- Top Activity
+ {t('stats.topActivity.title')}
- {stats.mostCommonType}
+ {t(`activityTypes.${stats.mostCommonType}`)}
- Most frequent
+ {t('stats.topActivity.subtitle')}
@@ -464,7 +466,7 @@ export const InsightsDashboard: React.FC = () => {
- Feeding Frequency
+ {t('charts.feedingFrequency')}
@@ -473,7 +475,7 @@ export const InsightsDashboard: React.FC = () => {
-
+
@@ -486,7 +488,7 @@ export const InsightsDashboard: React.FC = () => {
- Sleep Duration (Hours)
+ {t('charts.sleepDuration')}
@@ -500,7 +502,7 @@ export const InsightsDashboard: React.FC = () => {
dataKey="sleepHours"
stroke={COLORS.sleep}
strokeWidth={3}
- name="Sleep Hours"
+ name={t('charts.chartLabels.sleepHours')}
dot={{ fill: COLORS.sleep, r: 4 }}
/>
@@ -516,7 +518,7 @@ export const InsightsDashboard: React.FC = () => {
- Diaper Changes by Type
+ {t('charts.diaperChangesByType')}
@@ -549,7 +551,7 @@ export const InsightsDashboard: React.FC = () => {
- Activity Timeline
+ {t('charts.activityTimeline')}
@@ -559,9 +561,9 @@ export const InsightsDashboard: React.FC = () => {
-
-
-
+
+
+
@@ -573,7 +575,7 @@ export const InsightsDashboard: React.FC = () => {
- Activity Distribution
+ {t('charts.activityDistribution')}
{activityTypeData.map((activity) => (
@@ -600,7 +602,7 @@ export const InsightsDashboard: React.FC = () => {
- Recent Activities (Last 20)
+ {t('recentActivities.title')}
@@ -627,7 +629,7 @@ export const InsightsDashboard: React.FC = () => {
primary={
- {activity.type}
+ {t(`activityTypes.${activity.type}`)}