Add translations for various project management features

Integrate i18n translation keys for project template page elements, including column titles, buttons, dialogs, and input fields, within the ProjectTemplate component.

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/HdLXOOf
This commit is contained in:
paul-nothaft
2025-10-24 11:00:26 +00:00
parent 57f09310ca
commit 102315fa7c
2 changed files with 51 additions and 56 deletions
-4
View File
@@ -14,10 +14,6 @@ run = ["npm", "run", "start"]
localPort = 5000
externalPort = 80
[[ports]]
localPort = 33611
externalPort = 4200
[[ports]]
localPort = 35345
externalPort = 3002
+51 -52
View File
@@ -127,6 +127,7 @@ export default function ProjectTemplate({
onCreateTasks,
onNavigateToSettings
}: ProjectTemplateProps) {
const { t } = useTranslation();
const [projects, setProjects] = useState<Project[]>(defaultProjects);
const [selectedProject, setSelectedProject] = useState<Project | null>(null);
const [draggedProject, setDraggedProject] = useState<string | null>(null);
@@ -497,7 +498,7 @@ export default function ProjectTemplate({
};
const handleDeleteLabel = (id: string) => {
if (confirm('Are you sure you want to delete this label?')) {
if (confirm(t('projectTemplate.deleteConfirm'))) {
deleteLabelMutation.mutate(id);
}
};
@@ -517,13 +518,11 @@ export default function ProjectTemplate({
};
const projectColumns = [
{ id: 'planning', title: 'Planning', status: 'planning' as const, color: 'bg-slate-100' },
{ id: 'active', title: 'Active', status: 'active' as const, color: 'bg-blue-100' },
{ id: 'finished', title: 'Finished', status: 'finished' as const, color: 'bg-green-100' }
{ id: 'planning', title: t('projectTemplate.planning'), status: 'planning' as const, color: 'bg-slate-100' },
{ id: 'active', title: t('projectTemplate.active'), status: 'active' as const, color: 'bg-blue-100' },
{ id: 'finished', title: t('projectTemplate.finished'), status: 'finished' as const, color: 'bg-green-100' }
];
const { t } = useTranslation();
return (
<div className="space-y-6">
{/* Header */}
@@ -550,14 +549,14 @@ export default function ProjectTemplate({
className="h-11"
>
<Plus className="w-4 h-4 mr-2" />
New Project
{t('projectTemplate.newProject')}
</Button>
</div>
<Tabs defaultValue="projects" className="space-y-3 sm:space-y-4">
<TabsList className="w-full">
<TabsTrigger value="projects" data-testid="tab-projects" className="flex-1">Projects</TabsTrigger>
<TabsTrigger value="labels" data-testid="tab-labels" className="flex-1">Labels</TabsTrigger>
<TabsTrigger value="projects" data-testid="tab-projects" className="flex-1">{t('projectTemplate.projects')}</TabsTrigger>
<TabsTrigger value="labels" data-testid="tab-labels" className="flex-1">{t('projectTemplate.labels')}</TabsTrigger>
</TabsList>
<TabsContent value="projects" className="space-y-4 sm:space-y-6">
@@ -845,29 +844,29 @@ export default function ProjectTemplate({
}}>
<DialogContent className="sm:max-w-3xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>Create New Project</DialogTitle>
<DialogTitle>{t('projectTemplate.createProject')}</DialogTitle>
<DialogDescription>
Create a new project with tasks, timeline, and organize your work efficiently.
{t('projectTemplate.description')}
</DialogDescription>
</DialogHeader>
<div className="space-y-6 py-4">
{/* Project Details */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
<label className="text-sm font-medium">Project Name</label>
<label className="text-sm font-medium">{t('projectTemplate.projectName')}</label>
<Input
value={newProjectName}
onChange={(e) => setNewProjectName(e.target.value)}
placeholder="Enter project name"
placeholder={t('projectTemplate.projectNamePlaceholder')}
data-testid="input-project-name"
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Description (Optional)</label>
<label className="text-sm font-medium">{t('projectTemplate.projectDescription')}</label>
<Input
value={newProjectDescription}
onChange={(e) => setNewProjectDescription(e.target.value)}
placeholder="Enter project description"
placeholder={t('projectTemplate.projectDescriptionPlaceholder')}
data-testid="input-project-description"
/>
</div>
@@ -875,7 +874,7 @@ export default function ProjectTemplate({
{/* Planned End Date */}
<div className="space-y-2">
<label className="text-sm font-medium">Planned End Date (Optional)</label>
<label className="text-sm font-medium">{t('projectTemplate.plannedEndDate')}</label>
<Popover open={isPlannedEndDateCalendarOpen} onOpenChange={setIsPlannedEndDateCalendarOpen}>
<PopoverTrigger asChild>
<Button
@@ -884,7 +883,7 @@ export default function ProjectTemplate({
data-testid="button-select-planned-end-date"
>
<CalendarIcon className="mr-2 h-4 w-4" />
{newPlannedEndDate ? newPlannedEndDate.toLocaleDateString() : "Select planned end date"}
{newPlannedEndDate ? newPlannedEndDate.toLocaleDateString() : t('projectTemplate.selectPlannedEndDate')}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
@@ -908,7 +907,7 @@ export default function ProjectTemplate({
className="text-xs text-muted-foreground hover:text-destructive"
data-testid="button-clear-create-planned-end-date"
>
Clear date
{t('projectTemplate.clearDate')}
</Button>
)}
</div>
@@ -916,7 +915,7 @@ export default function ProjectTemplate({
{/* Tasks Section */}
<div className="space-y-4">
<div className="flex items-center justify-between">
<h3 className="text-lg font-semibold">Project Tasks</h3>
<h3 className="text-lg font-semibold">{t('projectTemplate.projectTasks')}</h3>
<Button
variant="outline"
size="sm"
@@ -924,7 +923,7 @@ export default function ProjectTemplate({
data-testid="button-add-task"
>
<Plus className="w-4 h-4 mr-2" />
Add Task
{t('projectTemplate.addTask')}
</Button>
</div>
@@ -976,7 +975,7 @@ export default function ProjectTemplate({
{projectTasks.length === 0 && (
<div className="text-center text-muted-foreground text-sm py-8 border-2 border-dashed border-muted rounded-lg">
No tasks added yet. Click "Add Task" to get started.
{t('projectTemplate.noLabelsDescription')}
</div>
)}
</div>
@@ -986,32 +985,32 @@ export default function ProjectTemplate({
<Card className="p-4 border-primary">
<div className="space-y-4">
<h4 className="font-semibold text-sm">
{editingTaskIndex !== null ? 'Edit Task' : 'New Task'}
{editingTaskIndex !== null ? t('projectTemplate.edit') : t('projectTemplate.addTask')}
</h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
<label className="text-sm font-medium">Task Title</label>
<label className="text-sm font-medium">{t('projectTemplate.taskTitle')}</label>
<Input
value={taskForm.title || ''}
onChange={(e) => setTaskForm({...taskForm, title: e.target.value})}
placeholder="Enter task title"
placeholder={t('projectTemplate.enterTaskTitle')}
data-testid="input-task-title"
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Description</label>
<label className="text-sm font-medium">{t('projectTemplate.description')}</label>
<Input
value={taskForm.description || ''}
onChange={(e) => setTaskForm({...taskForm, description: e.target.value})}
placeholder="Enter task description"
placeholder={t('projectTemplate.enterTaskDescription')}
data-testid="input-task-description"
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Priority</label>
<label className="text-sm font-medium">{t('projectTemplate.priority')}</label>
<Select
value={taskForm.priority || 'medium'}
onValueChange={(value: ProjectTask['priority']) =>
@@ -1022,15 +1021,15 @@ export default function ProjectTemplate({
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="low">Low</SelectItem>
<SelectItem value="medium">Medium</SelectItem>
<SelectItem value="high">High</SelectItem>
<SelectItem value="low">{t('priority.low')}</SelectItem>
<SelectItem value="medium">{t('priority.medium')}</SelectItem>
<SelectItem value="high">{t('priority.high')}</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Status</label>
<label className="text-sm font-medium">{t('projectTemplate.status')}</label>
<Select
value={taskForm.status || 'todo'}
onValueChange={(value: ProjectTask['status']) =>
@@ -1041,15 +1040,15 @@ export default function ProjectTemplate({
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="todo">To Do</SelectItem>
<SelectItem value="inProgress">In Progress</SelectItem>
<SelectItem value="done">Done</SelectItem>
<SelectItem value="todo">{t('status.todo')}</SelectItem>
<SelectItem value="inProgress">{t('status.inProgress')}</SelectItem>
<SelectItem value="done">{t('status.done')}</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Estimated Hours</label>
<label className="text-sm font-medium">{t('projectTemplate.estimatedHours')}</label>
<Input
type="number"
value={taskForm.estimatedHours || ''}
@@ -1067,7 +1066,7 @@ export default function ProjectTemplate({
onClick={handleCancelTaskEdit}
className="flex-1"
>
Cancel
{t('projectTemplate.cancel')}
</Button>
<Button
onClick={editingTaskIndex !== null ? handleSaveTask : handleAddTask}
@@ -1075,7 +1074,7 @@ export default function ProjectTemplate({
className="flex-1"
data-testid="button-save-task"
>
{editingTaskIndex !== null ? 'Save Changes' : 'Add Task'}
{editingTaskIndex !== null ? t('projectTemplate.save') : t('projectTemplate.addTask')}
</Button>
</div>
</div>
@@ -1094,7 +1093,7 @@ export default function ProjectTemplate({
}}
className="flex-1"
>
Cancel
{t('projectTemplate.cancel')}
</Button>
<Button
onClick={handleCreateProject}
@@ -1102,7 +1101,7 @@ export default function ProjectTemplate({
className="flex-1"
data-testid="button-save-project"
>
Create Project ({projectTasks.length} tasks)
{t('projectTemplate.createProject')} ({projectTasks.length} {t('projectTemplate.tasks', { count: projectTasks.length })})
</Button>
</div>
</DialogContent>
@@ -1118,7 +1117,7 @@ export default function ProjectTemplate({
}}>
<DialogContent className="sm:max-w-3xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>Edit Project</DialogTitle>
<DialogTitle>{t('projectTemplate.edit')}</DialogTitle>
</DialogHeader>
{selectedProject && (
<div className="space-y-6 py-4">
@@ -1422,7 +1421,7 @@ export default function ProjectTemplate({
}}
className="flex-1"
>
Cancel
{t('projectTemplate.cancel')}
</Button>
<Button
onClick={handleSaveEditedProject}
@@ -1430,7 +1429,7 @@ export default function ProjectTemplate({
className="flex-1"
data-testid="button-update-project"
>
Update Project ({projectTasks.length} tasks)
{t('projectTemplate.update')} ({projectTasks.length} {t('projectTemplate.tasks', { count: projectTasks.length })})
</Button>
</div>
</DialogContent>
@@ -1439,22 +1438,22 @@ export default function ProjectTemplate({
<TabsContent value="labels" className="space-y-6">
{/* Labels Section Header */}
<div className="flex items-center justify-between">
<h3 className="text-md font-medium">Task Labels</h3>
<h3 className="text-md font-medium">{t('settings.labels.title')}</h3>
<Dialog open={isLabelDialogOpen} onOpenChange={setIsLabelDialogOpen}>
<DialogTrigger asChild>
<Button variant="outline" size="sm" data-testid="button-create-label">
<Plus className="w-4 h-4 mr-2" />
Create Label
{t('projectTemplate.createLabel')}
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>{editingLabel ? 'Edit Label' : 'Create New Label'}</DialogTitle>
<DialogTitle>{editingLabel ? t('projectTemplate.editLabel') : t('projectTemplate.createNewLabel')}</DialogTitle>
</DialogHeader>
<div className="space-y-4">
<div>
<Input
placeholder="Label name"
placeholder={t('projectTemplate.labelNamePlaceholder')}
value={labelName}
onChange={(e) => setLabelName(e.target.value)}
data-testid="input-label-name"
@@ -1490,7 +1489,7 @@ export default function ProjectTemplate({
className="flex-1"
data-testid="button-cancel-label"
>
Cancel
{t('projectTemplate.cancel')}
</Button>
<Button
onClick={handleSaveLabel}
@@ -1498,7 +1497,7 @@ export default function ProjectTemplate({
className="flex-1"
data-testid="button-save-label"
>
{editingLabel ? 'Update' : 'Create'}
{editingLabel ? t('projectTemplate.update') : t('projectTemplate.create')}
</Button>
</div>
</div>
@@ -1509,7 +1508,7 @@ export default function ProjectTemplate({
{/* Labels List */}
{labelsLoading ? (
<div className="flex items-center justify-center p-8">
<div className="text-muted-foreground">Loading labels...</div>
<div className="text-muted-foreground">{t('projectTemplate.loadingLabels')}</div>
</div>
) : (
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
@@ -1556,9 +1555,9 @@ export default function ProjectTemplate({
{labels.length === 0 && (
<div className="col-span-full flex flex-col items-center justify-center p-8 text-center">
<Tag className="w-12 h-12 text-muted-foreground mb-4" />
<h3 className="font-medium text-muted-foreground mb-2">No labels yet</h3>
<h3 className="font-medium text-muted-foreground mb-2">{t('projectTemplate.noLabelsYet')}</h3>
<p className="text-sm text-muted-foreground mb-4">
Create your first label to organize your tasks by color and category.
{t('projectTemplate.noLabelsDescription')}
</p>
<Button
variant="outline"
@@ -1566,7 +1565,7 @@ export default function ProjectTemplate({
data-testid="button-create-first-label"
>
<Plus className="w-4 h-4 mr-2" />
Create Label
{t('projectTemplate.createLabel')}
</Button>
</div>
)}