Merge pull request #16 from whtvrboo/i18n-pages-partial

feat: Add missing i18n translations for page components (partial)
This commit is contained in:
whtvrboo 2025-06-07 22:41:18 +02:00 committed by GitHub
commit b0ec84b8ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 156 additions and 42 deletions

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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 });

View File

@ -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) => {
<label class="form-label" for="chore-interval">{{ t('choresPage.form.interval', 'Interval (days)')
}}</label>
<input id="chore-interval" type="number" v-model.number="choreForm.custom_interval_days"
class="form-input" placeholder="e.g., 10" min="1">
class="form-input" :placeholder="t('choresPage.form.intervalPlaceholder')" min="1">
</div>
<div class="form-group">
<label class="form-label">{{ t('choresPage.form.type', 'Type') }}</label>

View File

@ -21,7 +21,7 @@
<div class="popup-header">
<span class="font-semibold truncate">{{ member.email }}</span>
<VButton variant="neutral" size="sm" :icon-only="true" iconLeft="x" @click="activeMemberMenu = null"
aria-label="Close menu" />
:aria-label="t('groupDetailPage.members.closeMenuLabel')" />
</div>
<div class="member-menu-content">
<VBadge :text="member.role || t('groupDetailPage.members.defaultRole')"
@ -37,8 +37,7 @@
</div>
<button ref="addMemberButtonRef" @click="toggleInviteUI" class="add-member-btn"
:aria-label="t('groupDetailPage.invites.title')">
<!-- <VIcon name="plus" size="md" /> -->
+
{{ t('groupDetailPage.invites.addMemberButtonLabel') }}
</button>
<!-- Invite Members Popup -->
@ -47,9 +46,9 @@
<VHeading :level="3" class="!m-0 !p-0 !border-none">{{ t('groupDetailPage.invites.title') }}
</VHeading>
<VButton variant="neutral" size="sm" :icon-only="true" iconLeft="x" @click="showInviteUI = false"
aria-label="Close invite" />
:aria-label="t('groupDetailPage.invites.closeInviteLabel')" />
</div>
<p class="text-sm text-gray-500 my-2">Invite new members by generating a shareable code.</p>
<p class="text-sm text-gray-500 my-2">{{ t('groupDetailPage.invites.description') }}</p>
<VButton variant="primary" class="w-full" @click="generateInviteCode" :disabled="generatingInvite">
<VSpinner v-if="generatingInvite" size="sm" /> {{ inviteCode ?
t('groupDetailPage.invites.regenerateButton') :
@ -146,7 +145,7 @@
<div class="neo-splits-list">
<div v-for="split in expense.splits" :key="split.id" class="neo-split-item">
<div class="split-col split-user">
<strong>{{ split.user?.name || split.user?.email || `User ID: ${split.user_id}` }}</strong>
<strong>{{ split.user?.name || split.user?.email || t('groupDetailPage.expenses.fallbackUserName', { userId: split.user_id }) }}</strong>
</div>
<div class="split-col split-owes">
{{ t('groupDetailPage.expenses.owes') }} <strong>{{
@ -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() }}
</li>
</ul>
@ -209,7 +207,7 @@
<div v-else>
<p>{{ 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 })
}) }}</p>
<VFormField :label="t('groupDetailPage.settleShareModal.amountLabel')"
:error-message="settleAmountError || undefined">
@ -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' });
}
}

View File

@ -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;