From 198222c3ffe2a28fc1d96ac8c563cfffbf79ed28 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 7 Jun 2025 20:40:49 +0000 Subject: [PATCH] feat: Add missing i18n translations for page components (partial) This commit introduces internationalization for several page components by identifying hardcoded strings, adding them to translation files, and updating the components to use translation keys. Processed pages: - fe/src/pages/AuthCallbackPage.vue: I internationalized an error message. - fe/src/pages/ChoresPage.vue: I internationalized console error messages and an input placeholder. - fe/src/pages/ErrorNotFound.vue: I found no missing translations. - fe/src/pages/GroupDetailPage.vue: I internationalized various UI elements (ARIA labels, button text, fallback user display names) and console/error messages. - fe/src/pages/GroupsPage.vue: I internationalized error messages and console logs. - fe/src/pages/IndexPage.vue: I found no missing user-facing translations. - fe/src/pages/ListDetailPage.vue: My analysis is complete, and I identified a console message and a fallback string for translation (implementation of changes for this page is pending). For each processed page where changes were needed: - I added new keys to `fe/src/i18n/en.json`. - I added corresponding placeholder keys `"[TRANSLATE] Original Text"` to `fe/src/i18n/de.json`, `fe/src/i18n/es.json`, and `fe/src/i18n/fr.json`. - I updated the Vue component to use the `t()` function with the new keys. Further pages in `fe/src/pages/` are pending analysis and internationalization as per our original plan. --- fe/src/i18n/de.json | 37 +++++++++++++++++++++++++++---- fe/src/i18n/en.json | 37 +++++++++++++++++++++++++++---- fe/src/i18n/es.json | 37 +++++++++++++++++++++++++++---- fe/src/i18n/fr.json | 37 +++++++++++++++++++++++++++---- fe/src/pages/AuthCallbackPage.vue | 2 +- fe/src/pages/ChoresPage.vue | 16 ++++++------- fe/src/pages/GroupDetailPage.vue | 26 ++++++++++------------ fe/src/pages/GroupsPage.vue | 6 ++--- 8 files changed, 156 insertions(+), 42 deletions(-) diff --git a/fe/src/i18n/de.json b/fe/src/i18n/de.json index ab6a3ff..49c77bf 100644 --- a/fe/src/i18n/de.json +++ b/fe/src/i18n/de.json @@ -73,7 +73,10 @@ "groupNameRequired": "DE: Group name is required", "createFailed": "DE: Failed to create group. Please try again.", "inviteCodeRequired": "DE: Invite code is required", - "joinFailed": "DE: Failed to join group. Please check the invite code and try again." + "joinFailed": "DE: Failed to join group. Please check the invite code and try again.", + "invalidDataFromServer": "[TRANSLATE] Invalid data received from server.", + "createFailedConsole": "[TRANSLATE] Error creating group:", + "joinFailedConsole": "[TRANSLATE] Error joining group:" }, "notifications": { "groupCreatedSuccess": "DE: Group '{groupName}' created successfully.", @@ -85,7 +88,8 @@ "authCallbackPage": { "redirecting": "DE: Redirecting...", "errors": { - "authenticationFailed": "DE: Authentication failed" + "authenticationFailed": "DE: Authentication failed", + "noTokenProvided": "[TRANSLATE] No token provided" } }, "choresPage": { @@ -165,7 +169,17 @@ "quickDueDateTomorrow": "DE: Tomorrow", "quickDueDateNextWeek": "DE: Next Week", "cancelButton": "DE: Cancel", - "saveButton": "DE: Save" + "saveButton": "DE: Save", + "intervalPlaceholder": "[TRANSLATE] e.g., 10" + }, + "consoleErrors": { + "loadFailed": "[TRANSLATE] Failed to load all chores:", + "loadGroupsFailed": "[TRANSLATE] Failed to load groups", + "createAssignmentForNewChoreFailed": "[TRANSLATE] Failed to create assignment for new chore:", + "saveFailed": "[TRANSLATE] Failed to save chore:", + "deleteFailed": "[TRANSLATE] Failed to delete chore:", + "createAssignmentFailed": "[TRANSLATE] Failed to create assignment:", + "updateCompletionStatusFailed": "[TRANSLATE] Failed to update chore completion status:" }, "deleteDialog": { "title": "DE: Delete Chore", @@ -228,10 +242,14 @@ "title": "DE: Group Members", "defaultRole": "DE: Member", "removeButton": "DE: Remove", - "emptyState": "DE: No members found." + "emptyState": "DE: No members found.", + "closeMenuLabel": "[TRANSLATE] Close menu" }, "invites": { "title": "DE: Invite Members", + "description": "[TRANSLATE] Invite new members by generating a shareable code.", + "addMemberButtonLabel": "[TRANSLATE] Add member", + "closeInviteLabel": "[TRANSLATE] Close invite", "regenerateButton": "DE: Regenerate Invite Code", "generateButton": "DE: Generate Invite Code", "activeCodeLabel": "DE: Current Active Invite Code:", @@ -242,6 +260,15 @@ "newDataInvalid": "DE: New invite code data is invalid." } }, + "errors": { + "failedToFetchActiveInvite": "[TRANSLATE] Failed to fetch active invite code.", + "failedToFetchGroupDetails": "[TRANSLATE] Failed to fetch group details.", + "failedToLoadUpcomingChores": "[TRANSLATE] Error loading upcoming chores:", + "failedToLoadRecentExpenses": "[TRANSLATE] Error loading recent expenses:" + }, + "console": { + "noActiveInvite": "[TRANSLATE] No active invite code found for this group." + }, "chores": { "title": "DE: Group Chores", "manageButton": "DE: Manage Chores", @@ -252,6 +279,8 @@ "title": "DE: Group Expenses", "manageButton": "DE: Manage Expenses", "emptyState": "DE: No expenses recorded. Click \"Manage Expenses\" to add some!", + "fallbackUserName": "[TRANSLATE] User ID: {userId}", + "activityByUserFallback": "[TRANSLATE] User {userId}", "splitTypes": { "equal": "DE: Equal", "exactAmounts": "DE: Exact Amounts", diff --git a/fe/src/i18n/en.json b/fe/src/i18n/en.json index 62afc82..57abdd0 100644 --- a/fe/src/i18n/en.json +++ b/fe/src/i18n/en.json @@ -73,7 +73,10 @@ "groupNameRequired": "Group name is required", "createFailed": "Failed to create group. Please try again.", "inviteCodeRequired": "Invite code is required", - "joinFailed": "Failed to join group. Please check the invite code and try again." + "joinFailed": "Failed to join group. Please check the invite code and try again.", + "invalidDataFromServer": "Invalid data received from server.", + "createFailedConsole": "Error creating group:", + "joinFailedConsole": "Error joining group:" }, "notifications": { "groupCreatedSuccess": "Group '{groupName}' created successfully.", @@ -85,7 +88,8 @@ "authCallbackPage": { "redirecting": "Redirecting...", "errors": { - "authenticationFailed": "Authentication failed" + "authenticationFailed": "Authentication failed", + "noTokenProvided": "No token provided" } }, "choresPage": { @@ -125,7 +129,17 @@ "save": "Save Changes", "create": "Create", "editChore": "Edit Chore", - "createChore": "Create Chore" + "createChore": "Create Chore", + "intervalPlaceholder": "e.g., 10" + }, + "consoleErrors": { + "loadFailed": "Failed to load all chores:", + "loadGroupsFailed": "Failed to load groups", + "createAssignmentForNewChoreFailed": "Failed to create assignment for new chore:", + "saveFailed": "Failed to save chore:", + "deleteFailed": "Failed to delete chore:", + "createAssignmentFailed": "Failed to create assignment:", + "updateCompletionStatusFailed": "Failed to update chore completion status:" }, "deleteConfirm": { "title": "Confirm Deletion", @@ -160,10 +174,14 @@ "title": "Group Members", "defaultRole": "Member", "removeButton": "Remove", - "emptyState": "No members found." + "emptyState": "No members found.", + "closeMenuLabel": "Close menu" }, "invites": { "title": "Invite Members", + "description": "Invite new members by generating a shareable code.", + "addMemberButtonLabel": "Add member", + "closeInviteLabel": "Close invite", "regenerateButton": "Regenerate Invite Code", "generateButton": "Generate Invite Code", "activeCodeLabel": "Current Active Invite Code:", @@ -174,6 +192,15 @@ "newDataInvalid": "New invite code data is invalid." } }, + "errors": { + "failedToFetchActiveInvite": "Failed to fetch active invite code.", + "failedToFetchGroupDetails": "Failed to fetch group details.", + "failedToLoadUpcomingChores": "Error loading upcoming chores:", + "failedToLoadRecentExpenses": "Error loading recent expenses:" + }, + "console": { + "noActiveInvite": "No active invite code found for this group." + }, "chores": { "title": "Group Chores", "manageButton": "Manage Chores", @@ -191,6 +218,8 @@ "settleShareButton": "Settle My Share", "activityLabel": "Activity:", "byUser": "by", + "fallbackUserName": "User ID: {userId}", + "activityByUserFallback": "User {userId}", "splitTypes": { "equal": "Equal", "exactAmounts": "Exact Amounts", diff --git a/fe/src/i18n/es.json b/fe/src/i18n/es.json index 665870e..5560da0 100644 --- a/fe/src/i18n/es.json +++ b/fe/src/i18n/es.json @@ -73,7 +73,10 @@ "groupNameRequired": "ES: Group name is required", "createFailed": "ES: Failed to create group. Please try again.", "inviteCodeRequired": "ES: Invite code is required", - "joinFailed": "ES: Failed to join group. Please check the invite code and try again." + "joinFailed": "ES: Failed to join group. Please check the invite code and try again.", + "invalidDataFromServer": "[TRANSLATE] Invalid data received from server.", + "createFailedConsole": "[TRANSLATE] Error creating group:", + "joinFailedConsole": "[TRANSLATE] Error joining group:" }, "notifications": { "groupCreatedSuccess": "ES: Group '{groupName}' created successfully.", @@ -85,7 +88,8 @@ "authCallbackPage": { "redirecting": "ES: Redirecting...", "errors": { - "authenticationFailed": "ES: Authentication failed" + "authenticationFailed": "ES: Authentication failed", + "noTokenProvided": "[TRANSLATE] No token provided" } }, "choresPage": { @@ -165,7 +169,17 @@ "quickDueDateTomorrow": "ES: Tomorrow", "quickDueDateNextWeek": "ES: Next Week", "cancelButton": "ES: Cancel", - "saveButton": "ES: Save" + "saveButton": "ES: Save", + "intervalPlaceholder": "[TRANSLATE] e.g., 10" + }, + "consoleErrors": { + "loadFailed": "[TRANSLATE] Failed to load all chores:", + "loadGroupsFailed": "[TRANSLATE] Failed to load groups", + "createAssignmentForNewChoreFailed": "[TRANSLATE] Failed to create assignment for new chore:", + "saveFailed": "[TRANSLATE] Failed to save chore:", + "deleteFailed": "[TRANSLATE] Failed to delete chore:", + "createAssignmentFailed": "[TRANSLATE] Failed to create assignment:", + "updateCompletionStatusFailed": "[TRANSLATE] Failed to update chore completion status:" }, "deleteDialog": { "title": "ES: Delete Chore", @@ -228,10 +242,14 @@ "title": "ES: Group Members", "defaultRole": "ES: Member", "removeButton": "ES: Remove", - "emptyState": "ES: No members found." + "emptyState": "ES: No members found.", + "closeMenuLabel": "[TRANSLATE] Close menu" }, "invites": { "title": "ES: Invite Members", + "description": "[TRANSLATE] Invite new members by generating a shareable code.", + "addMemberButtonLabel": "[TRANSLATE] Add member", + "closeInviteLabel": "[TRANSLATE] Close invite", "regenerateButton": "ES: Regenerate Invite Code", "generateButton": "ES: Generate Invite Code", "activeCodeLabel": "ES: Current Active Invite Code:", @@ -242,6 +260,15 @@ "newDataInvalid": "ES: New invite code data is invalid." } }, + "errors": { + "failedToFetchActiveInvite": "[TRANSLATE] Failed to fetch active invite code.", + "failedToFetchGroupDetails": "[TRANSLATE] Failed to fetch group details.", + "failedToLoadUpcomingChores": "[TRANSLATE] Error loading upcoming chores:", + "failedToLoadRecentExpenses": "[TRANSLATE] Error loading recent expenses:" + }, + "console": { + "noActiveInvite": "[TRANSLATE] No active invite code found for this group." + }, "chores": { "title": "ES: Group Chores", "manageButton": "ES: Manage Chores", @@ -252,6 +279,8 @@ "title": "ES: Group Expenses", "manageButton": "ES: Manage Expenses", "emptyState": "ES: No expenses recorded. Click \"Manage Expenses\" to add some!", + "fallbackUserName": "[TRANSLATE] User ID: {userId}", + "activityByUserFallback": "[TRANSLATE] User {userId}", "splitTypes": { "equal": "ES: Equal", "exactAmounts": "ES: Exact Amounts", diff --git a/fe/src/i18n/fr.json b/fe/src/i18n/fr.json index cf8c4fc..887eb41 100644 --- a/fe/src/i18n/fr.json +++ b/fe/src/i18n/fr.json @@ -73,7 +73,10 @@ "groupNameRequired": "FR: Group name is required", "createFailed": "FR: Failed to create group. Please try again.", "inviteCodeRequired": "FR: Invite code is required", - "joinFailed": "FR: Failed to join group. Please check the invite code and try again." + "joinFailed": "FR: Failed to join group. Please check the invite code and try again.", + "invalidDataFromServer": "[TRANSLATE] Invalid data received from server.", + "createFailedConsole": "[TRANSLATE] Error creating group:", + "joinFailedConsole": "[TRANSLATE] Error joining group:" }, "notifications": { "groupCreatedSuccess": "FR: Group '{groupName}' created successfully.", @@ -85,7 +88,8 @@ "authCallbackPage": { "redirecting": "FR: Redirecting...", "errors": { - "authenticationFailed": "FR: Authentication failed" + "authenticationFailed": "FR: Authentication failed", + "noTokenProvided": "[TRANSLATE] No token provided" } }, "choresPage": { @@ -165,7 +169,17 @@ "quickDueDateTomorrow": "FR: Tomorrow", "quickDueDateNextWeek": "FR: Next Week", "cancelButton": "FR: Cancel", - "saveButton": "FR: Save" + "saveButton": "FR: Save", + "intervalPlaceholder": "[TRANSLATE] e.g., 10" + }, + "consoleErrors": { + "loadFailed": "[TRANSLATE] Failed to load all chores:", + "loadGroupsFailed": "[TRANSLATE] Failed to load groups", + "createAssignmentForNewChoreFailed": "[TRANSLATE] Failed to create assignment for new chore:", + "saveFailed": "[TRANSLATE] Failed to save chore:", + "deleteFailed": "[TRANSLATE] Failed to delete chore:", + "createAssignmentFailed": "[TRANSLATE] Failed to create assignment:", + "updateCompletionStatusFailed": "[TRANSLATE] Failed to update chore completion status:" }, "deleteDialog": { "title": "FR: Delete Chore", @@ -228,10 +242,14 @@ "title": "FR: Group Members", "defaultRole": "FR: Member", "removeButton": "FR: Remove", - "emptyState": "FR: No members found." + "emptyState": "FR: No members found.", + "closeMenuLabel": "[TRANSLATE] Close menu" }, "invites": { "title": "FR: Invite Members", + "description": "[TRANSLATE] Invite new members by generating a shareable code.", + "addMemberButtonLabel": "[TRANSLATE] Add member", + "closeInviteLabel": "[TRANSLATE] Close invite", "regenerateButton": "FR: Regenerate Invite Code", "generateButton": "FR: Generate Invite Code", "activeCodeLabel": "FR: Current Active Invite Code:", @@ -242,6 +260,15 @@ "newDataInvalid": "FR: New invite code data is invalid." } }, + "errors": { + "failedToFetchActiveInvite": "[TRANSLATE] Failed to fetch active invite code.", + "failedToFetchGroupDetails": "[TRANSLATE] Failed to fetch group details.", + "failedToLoadUpcomingChores": "[TRANSLATE] Error loading upcoming chores:", + "failedToLoadRecentExpenses": "[TRANSLATE] Error loading recent expenses:" + }, + "console": { + "noActiveInvite": "[TRANSLATE] No active invite code found for this group." + }, "chores": { "title": "FR: Group Chores", "manageButton": "FR: Manage Chores", @@ -252,6 +279,8 @@ "title": "FR: Group Expenses", "manageButton": "FR: Manage Expenses", "emptyState": "FR: No expenses recorded. Click \"Manage Expenses\" to add some!", + "fallbackUserName": "[TRANSLATE] User ID: {userId}", + "activityByUserFallback": "[TRANSLATE] User {userId}", "splitTypes": { "equal": "FR: Equal", "exactAmounts": "FR: Exact Amounts", diff --git a/fe/src/pages/AuthCallbackPage.vue b/fe/src/pages/AuthCallbackPage.vue index 81ed4d7..d50a510 100644 --- a/fe/src/pages/AuthCallbackPage.vue +++ b/fe/src/pages/AuthCallbackPage.vue @@ -38,7 +38,7 @@ onMounted(async () => { const tokenToUse = accessToken || legacyToken; if (!tokenToUse) { - throw new Error('No token provided'); + throw new Error(t('authCallbackPage.errors.noTokenProvided')); } await authStore.setTokens({ access_token: tokenToUse, refresh_token: refreshToken }); diff --git a/fe/src/pages/ChoresPage.vue b/fe/src/pages/ChoresPage.vue index b4104b8..0ec5b6c 100644 --- a/fe/src/pages/ChoresPage.vue +++ b/fe/src/pages/ChoresPage.vue @@ -80,7 +80,7 @@ const loadChores = async () => { cachedChores.value = mappedChores; cachedTimestamp.value = Date.now() } catch (error) { - console.error('Failed to load all chores:', error) + console.error(t('choresPage.consoleErrors.loadFailed'), error) notificationStore.addNotification({ message: t('choresPage.notifications.loadFailed', 'Failed to load chores.'), type: 'error' }) } finally { isLoading.value = false @@ -91,7 +91,7 @@ const loadGroups = async () => { try { groups.value = await groupService.getUserGroups(); } catch (error) { - console.error("Failed to load groups", error); + console.error(t('choresPage.consoleErrors.loadGroupsFailed'), error); notificationStore.addNotification({ message: t('choresPage.notifications.loadGroupsFailed', 'Failed to load groups.'), type: 'error' }); } } @@ -227,7 +227,7 @@ const handleFormSubmit = async () => { due_date: createdChore.next_due_date }); } catch (assignmentError) { - console.error('Failed to create assignment for new chore:', assignmentError); + console.error(t('choresPage.consoleErrors.createAssignmentForNewChoreFailed'), assignmentError); // Continue anyway since the chore was created } } @@ -237,7 +237,7 @@ const handleFormSubmit = async () => { showChoreModal.value = false; await loadChores(); } catch (error) { - console.error('Failed to save chore:', error); + console.error(t('choresPage.consoleErrors.saveFailed'), error); notificationStore.addNotification({ message: t('choresPage.notifications.saveFailed', 'Failed to save the chore.'), type: 'error' }); } } @@ -255,7 +255,7 @@ const deleteChore = async () => { showDeleteDialog.value = false await loadChores() } catch (error) { - console.error('Failed to delete chore:', error) + console.error(t('choresPage.consoleErrors.deleteFailed'), error) notificationStore.addNotification({ message: t('choresPage.notifications.deleteFailed', 'Failed to delete chore.'), type: 'error' }) } } @@ -271,7 +271,7 @@ const toggleCompletion = async (chore: ChoreWithCompletion) => { }); chore.current_assignment_id = assignment.id; } catch (error) { - console.error('Failed to create assignment:', error); + console.error(t('choresPage.consoleErrors.createAssignmentFailed'), error); notificationStore.addNotification({ message: t('choresPage.notifications.createAssignmentFailed', 'Failed to create assignment for chore.'), type: 'error' @@ -299,7 +299,7 @@ const toggleCompletion = async (chore: ChoreWithCompletion) => { }); await loadChores(); } catch (error) { - console.error('Failed to update chore completion status:', error); + console.error(t('choresPage.consoleErrors.updateCompletionStatusFailed'), error); notificationStore.addNotification({ message: t('choresPage.notifications.updateFailed', 'Failed to update chore status.'), type: 'error' }); chore.is_completed = originalCompleted; } finally { @@ -403,7 +403,7 @@ const toggleCompletion = async (chore: ChoreWithCompletion) => { + class="form-input" :placeholder="t('choresPage.form.intervalPlaceholder')" min="1">
diff --git a/fe/src/pages/GroupDetailPage.vue b/fe/src/pages/GroupDetailPage.vue index 231454d..9c704be 100644 --- a/fe/src/pages/GroupDetailPage.vue +++ b/fe/src/pages/GroupDetailPage.vue @@ -21,7 +21,7 @@
@@ -47,9 +46,9 @@ {{ t('groupDetailPage.invites.title') }} + :aria-label="t('groupDetailPage.invites.closeInviteLabel')" />
-

Invite new members by generating a shareable code.

+

{{ t('groupDetailPage.invites.description') }}

{{ inviteCode ? t('groupDetailPage.invites.regenerateButton') : @@ -146,7 +145,7 @@
- {{ split.user?.name || split.user?.email || `User ID: ${split.user_id}` }} + {{ split.user?.name || split.user?.email || t('groupDetailPage.expenses.fallbackUserName', { userId: split.user_id }) }}
{{ t('groupDetailPage.expenses.owes') }} {{ @@ -178,8 +177,7 @@ {{ t('groupDetailPage.expenses.activityLabel') }} {{ formatCurrency(activity.amount_paid) }} {{ - t('groupDetailPage.expenses.byUser') }} {{ activity.payer?.name || `User - ${activity.paid_by_user_id}` }} {{ t('groupDetailPage.expenses.onDate') }} {{ new + t('groupDetailPage.expenses.byUser') }} {{ activity.payer?.name || t('groupDetailPage.expenses.activityByUserFallback', { userId: activity.paid_by_user_id }) }} {{ t('groupDetailPage.expenses.onDate') }} {{ new Date(activity.paid_at).toLocaleDateString() }} @@ -209,7 +207,7 @@

{{ t('groupDetailPage.settleShareModal.settleAmountFor', { userName: selectedSplitForSettlement?.user?.name - || selectedSplitForSettlement?.user?.email || `User ID: ${selectedSplitForSettlement?.user_id}` + || selectedSplitForSettlement?.user?.email || t('groupDetailPage.expenses.fallbackUserName', { userId: selectedSplitForSettlement?.user_id }) }) }}

@@ -383,9 +381,9 @@ const fetchActiveInviteCode = async () => { inviteCode.value = null; // Explicitly set to null on 404 inviteExpiresAt.value = null; // Optional: notify user or set a flag to show "generate one" message more prominently - console.info('No active invite code found for this group.'); + console.info(t('groupDetailPage.console.noActiveInvite')); } else { - const message = err instanceof Error ? err.message : 'Failed to fetch active invite code.'; + const message = err instanceof Error ? err.message : t('groupDetailPage.errors.failedToFetchActiveInvite'); // error.value = message; // This would display a large error banner, might be too much console.error('Error fetching active invite code:', err); notificationStore.addNotification({ message, type: 'error' }); @@ -418,7 +416,7 @@ const fetchGroupDetails = async () => { timestamp: Date.now(), }; } catch (err: unknown) { - const message = err instanceof Error ? err.message : 'Failed to fetch group details.'; + const message = err instanceof Error ? err.message : t('groupDetailPage.errors.failedToFetchGroupDetails'); // Only show the main error banner if we have no data at all to show if (!group.value) { error.value = message; @@ -524,7 +522,7 @@ const loadUpcomingChores = async () => { timestamp: Date.now() }; } catch (error) { - console.error('Error loading upcoming chores:', error) + console.error(t('groupDetailPage.errors.failedToLoadUpcomingChores'), error) } } @@ -563,7 +561,7 @@ const loadRecentExpenses = async () => { ) recentExpenses.value = response.data } catch (error) { - console.error('Error loading recent expenses:', error) + console.error(t('groupDetailPage.errors.failedToLoadRecentExpenses'), error) notificationStore.addNotification({ message: t('groupDetailPage.notifications.loadExpensesFailed'), type: 'error' }); } } diff --git a/fe/src/pages/GroupsPage.vue b/fe/src/pages/GroupsPage.vue index d08674d..b50482b 100644 --- a/fe/src/pages/GroupsPage.vue +++ b/fe/src/pages/GroupsPage.vue @@ -281,12 +281,12 @@ const handleCreateGroup = async () => { cachedGroups.value = groups.value; cachedTimestamp.value = Date.now(); } else { - throw new Error('Invalid data received from server.'); + throw new Error(t('groupsPage.errors.invalidDataFromServer')); } } catch (error: any) { const message = error.response?.data?.detail || (error instanceof Error ? error.message : t('groupsPage.errors.createFailed')); createGroupFormError.value = message; - console.error('Error creating group:', error); + console.error(t('groupsPage.errors.createFailedConsole'), error); notificationStore.addNotification({ message, type: 'error' }); } finally { creatingGroup.value = false; @@ -327,7 +327,7 @@ const handleJoinGroup = async () => { } catch (error: any) { const message = error.response?.data?.detail || (error instanceof Error ? error.message : t('groupsPage.errors.joinFailed')); joinGroupFormError.value = message; - console.error('Error joining group:', error); + console.error(t('groupsPage.errors.joinFailedConsole'), error); notificationStore.addNotification({ message, type: 'error' }); } finally { joiningGroup.value = false;