From a9efeeafbf7b0b55b64d32683c63982f836172ba Mon Sep 17 00:00:00 2001
From: paul-nothaft <40865108-paul-nothaft@users.noreply.replit.com>
Date: Fri, 24 Oct 2025 09:33:15 +0000
Subject: [PATCH] Add missing translations for task management features
Integrates i18next for internationalization, adding translated strings for task details, search, filters, and calendar views in both English and German.
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: ceced2fc-aa46-458d-ba87-ddd4b7bb1518
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/659922a9-0087-461c-90dd-6d9a58b81d4d/ceced2fc-aa46-458d-ba87-ddd4b7bb1518/E3NLe8e
---
.replit | 4 ++
client/src/components/TaskDetailsModal.tsx | 77 +++++++++++----------
client/src/components/TasksWithCalendar.tsx | 32 ++++-----
client/src/i18n/locales/de.json | 30 ++++++++
client/src/i18n/locales/en.json | 32 ++++++++-
5 files changed, 121 insertions(+), 54 deletions(-)
diff --git a/.replit b/.replit
index a572720..57855f4 100644
--- a/.replit
+++ b/.replit
@@ -18,6 +18,10 @@ externalPort = 80
localPort = 35345
externalPort = 3002
+[[ports]]
+localPort = 38309
+externalPort = 4200
+
[[ports]]
localPort = 39063
externalPort = 3001
diff --git a/client/src/components/TaskDetailsModal.tsx b/client/src/components/TaskDetailsModal.tsx
index f174324..769bf54 100644
--- a/client/src/components/TaskDetailsModal.tsx
+++ b/client/src/components/TaskDetailsModal.tsx
@@ -10,6 +10,7 @@ import { Separator } from '@/components/ui/separator';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Clock, Timer, FileText, Plus, Edit2, Save, X, Calendar, Tag } from 'lucide-react';
import { Task, Label } from '@shared/schema';
+import { useTranslation } from 'react-i18next';
interface TimeEntry {
id: string;
@@ -33,6 +34,8 @@ export default function TaskDetailsModal({
onSave,
labels = []
}: TaskDetailsModalProps) {
+ const { t } = useTranslation();
+
// Edit form state
const [editedTitle, setEditedTitle] = useState('');
const [editedDescription, setEditedDescription] = useState('');
@@ -73,7 +76,7 @@ export default function TaskDetailsModal({
id: 'tracked-time',
date: new Date(),
timeSpent: task.timeTracked,
- description: 'Previously tracked time'
+ description: t('taskDetails.previouslyTrackedTime')
}]);
} else {
setTimeEntries([]);
@@ -237,7 +240,7 @@ export default function TaskDetailsModal({
- Task Details
+ {t('taskDetails.title')}
@@ -257,14 +260,14 @@ export default function TaskDetailsModal({
- {task.priority} priority
+ {t(`taskDetails.priorityValue.${task.priority}`)}
- {task.status}
+ {t(`taskDetails.statusValue.${task.status}`)}
{getTotalTrackedTime() > 0 && (
- {formatMinutesToHours(getTotalTrackedTime())} tracked
+ {formatMinutesToHours(getTotalTrackedTime())} {t('taskDetails.tracked')}
)}
@@ -275,41 +278,41 @@ export default function TaskDetailsModal({
- Edit
+ {t('taskDetails.editTab')}
- Notes
+ {t('taskDetails.notesTab')}
- Time Tracking
+ {t('taskDetails.timeTab')}
{/* Edit Tab */}
- Edit Task
+ {t('taskDetails.editTask')}
{/* Title */}
- Title
+ {t('taskDetails.titleLabel')}
setEditedTitle(e.target.value)}
- placeholder="Task title"
+ placeholder={t('taskDetails.titlePlaceholder')}
data-testid="input-task-title"
/>
{/* Description */}
-
Description
+
{t('taskDetails.description')}
) : (
- No notes added yet. Click "Edit" to add notes.
+ {t('taskDetails.noNotesYet')}
)}
@@ -468,7 +471,7 @@ export default function TaskDetailsModal({
-
Total Time Tracked
+
{t('taskDetails.totalTimeTracked')}
{formatMinutesToHours(getTotalTrackedTime())}
@@ -479,7 +482,7 @@ export default function TaskDetailsModal({
data-testid="button-add-time"
>
- Add Time
+ {t('taskDetails.addTime')}
@@ -489,7 +492,7 @@ export default function TaskDetailsModal({
-
Add Time Entry
+
{t('taskDetails.addTimeEntry')}
- Clock
+ {t('taskDetails.clock')}
- Manual
+ {t('taskDetails.manual')}
diff --git a/client/src/components/TasksWithCalendar.tsx b/client/src/components/TasksWithCalendar.tsx
index c52371d..257fe0f 100644
--- a/client/src/components/TasksWithCalendar.tsx
+++ b/client/src/components/TasksWithCalendar.tsx
@@ -219,16 +219,16 @@ export default function TasksWithCalendar({ tasks, onTaskUpdate, onTaskEdit, onT
{/* Title Bar */}
- My Tasks
+ {t('taskList.title')}
- {filteredAndSortedTasks.length} tasks
+ {t('taskList.taskCount', { count: filteredAndSortedTasks.length })}
{
setSearchQuery(e.target.value);
@@ -251,11 +251,11 @@ export default function TasksWithCalendar({ tasks, onTaskUpdate, onTaskEdit, onT
- All ({getFilterCount('all')})
- To Do ({getFilterCount('todo')})
- In Progress ({getFilterCount('inProgress')})
- Done ({getFilterCount('done')})
- Overdue ({getFilterCount('overdue')})
+ {t('taskList.filter.all')} ({getFilterCount('all')})
+ {t('taskList.filter.todo')} ({getFilterCount('todo')})
+ {t('taskList.filter.inProgress')} ({getFilterCount('inProgress')})
+ {t('taskList.filter.done')} ({getFilterCount('done')})
+ {t('taskList.filter.overdue')} ({getFilterCount('overdue')})
@@ -270,10 +270,10 @@ export default function TasksWithCalendar({ tasks, onTaskUpdate, onTaskEdit, onT
- Due Date
- Priority
- Title
- Status
+ {t('taskList.sort.dueDate')}
+ {t('taskList.sort.priority')}
+ {t('taskList.sort.title')}
+ {t('taskList.sort.status')}
@@ -286,15 +286,15 @@ export default function TasksWithCalendar({ tasks, onTaskUpdate, onTaskEdit, onT
{searchQuery || filterBy !== 'all'
- ? 'No unscheduled tasks match your filters'
- : 'No unscheduled tasks. Drag tasks to the calendar below to schedule them!'
+ ? t('taskList.noMatchingTasks')
+ : t('taskList.noUnscheduledTasks')
}
) : (
<>
- Unscheduled Tasks - Drag to calendar below to schedule
+ {t('taskList.unscheduledTasksLabel')}
{unscheduledTasks.map((task) => (
- Next {visibleDays} Days
+ {t('taskList.calendarTitle', { count: visibleDays })}
diff --git a/client/src/i18n/locales/de.json b/client/src/i18n/locales/de.json
index 59f2296..ac5e256 100644
--- a/client/src/i18n/locales/de.json
+++ b/client/src/i18n/locales/de.json
@@ -17,6 +17,9 @@
"searchPlaceholder": "Aufgaben suchen...",
"noTasks": "Noch keine Aufgaben. Erstelle deine erste Aufgabe!",
"noMatchingTasks": "Keine Aufgaben entsprechen deinen Filtern",
+ "noUnscheduledTasks": "Keine ungeplanten Aufgaben. Ziehe Aufgaben in den Kalender unten, um sie zu planen!",
+ "unscheduledTasksLabel": "Ungeplante Aufgaben - In den Kalender ziehen zum Planen",
+ "calendarTitle": "Nächste {{count}} Tage",
"filter": {
"all": "Alle",
"todo": "Zu erledigen",
@@ -68,6 +71,33 @@
},
"taskDetails": {
"title": "Aufgabendetails",
+ "selectLabel": "Label auswählen",
+ "tracked": "erfasst",
+ "priorityValue": {
+ "low": "Niedrige Priorität",
+ "medium": "Mittlere Priorität",
+ "high": "Hohe Priorität"
+ },
+ "statusValue": {
+ "todo": "Zu erledigen",
+ "inProgress": "In Bearbeitung",
+ "done": "Erledigt"
+ },
+ "editTab": "Bearbeiten",
+ "notesTab": "Notizen",
+ "timeTab": "Zeiterfassung",
+ "editTask": "Aufgabe bearbeiten",
+ "titleLabel": "Titel",
+ "titlePlaceholder": "Aufgabentitel",
+ "taskNotes": "Aufgabennotizen",
+ "edit": "Bearbeiten",
+ "noNotesYet": "Noch keine Notizen hinzugefügt. Klicke auf \"Bearbeiten\", um Notizen hinzuzufügen.",
+ "totalTimeTracked": "Gesamt erfasste Zeit",
+ "addTime": "Zeit hinzufügen",
+ "addTimeEntry": "Zeiteintrag hinzufügen",
+ "clock": "Uhr",
+ "manual": "Manuell",
+ "previouslyTrackedTime": "Zuvor erfasste Zeit",
"description": "Beschreibung",
"descriptionPlaceholder": "Beschreibung hinzufügen...",
"priority": "Priorität",
diff --git a/client/src/i18n/locales/en.json b/client/src/i18n/locales/en.json
index 4ba57bd..7d9ecbe 100644
--- a/client/src/i18n/locales/en.json
+++ b/client/src/i18n/locales/en.json
@@ -17,6 +17,9 @@
"searchPlaceholder": "Search tasks...",
"noTasks": "No tasks yet. Create your first task!",
"noMatchingTasks": "No tasks match your filters",
+ "noUnscheduledTasks": "No unscheduled tasks. Drag tasks to the calendar below to schedule them!",
+ "unscheduledTasksLabel": "Unscheduled Tasks - Drag to calendar below to schedule",
+ "calendarTitle": "Next {{count}} Days",
"filter": {
"all": "All",
"todo": "To Do",
@@ -74,6 +77,7 @@
"status": "Status",
"label": "Label",
"noLabel": "No Label",
+ "selectLabel": "Select a label",
"dueDate": "Due Date",
"selectDate": "Select date",
"notes": "Notes",
@@ -81,7 +85,33 @@
"timeTracked": "Time Tracked",
"delete": "Delete Task",
"cancel": "Cancel",
- "save": "Save Changes"
+ "save": "Save Changes",
+ "tracked": "tracked",
+ "priorityValue": {
+ "low": "Low Priority",
+ "medium": "Medium Priority",
+ "high": "High Priority"
+ },
+ "statusValue": {
+ "todo": "To Do",
+ "inProgress": "In Progress",
+ "done": "Done"
+ },
+ "editTab": "Edit",
+ "notesTab": "Notes",
+ "timeTab": "Time Tracking",
+ "editTask": "Edit Task",
+ "titleLabel": "Title",
+ "titlePlaceholder": "Task title",
+ "taskNotes": "Task Notes",
+ "edit": "Edit",
+ "noNotesYet": "No notes added yet. Click \"Edit\" to add notes.",
+ "totalTimeTracked": "Total Time Tracked",
+ "addTime": "Add Time",
+ "addTimeEntry": "Add Time Entry",
+ "clock": "Clock",
+ "manual": "Manual",
+ "previouslyTrackedTime": "Previously tracked time"
},
"taskCard": {
"play": "Start timer",