diff --git a/web/app/components/base/quadrant-matrix/index.tsx b/web/app/components/base/quadrant-matrix/index.tsx index 43fc68e6b6..27aa62f66d 100644 --- a/web/app/components/base/quadrant-matrix/index.tsx +++ b/web/app/components/base/quadrant-matrix/index.tsx @@ -3,6 +3,7 @@ import type { FC } from 'react' import type { QuadrantData } from './types' import { RiExpandDiagonalLine } from '@remixicon/react' import { useCallback, useMemo, useState } from 'react' +import { useTranslation } from 'react-i18next' import ActionButton from '@/app/components/base/action-button' import FullScreenModal from '@/app/components/base/fullscreen-modal' import QuadrantCard from './quadrant-card' @@ -13,6 +14,7 @@ type QuadrantMatrixProps = { } const QuadrantMatrix: FC = ({ content }) => { + const { t } = useTranslation() const [isExpanded, setIsExpanded] = useState(false) const parsedData = useMemo(() => { @@ -42,9 +44,9 @@ const QuadrantMatrix: FC = ({ content }) => { return (
-
Invalid Quadrant Data
+
{t('quadrantMatrix.invalidData', { ns: 'app' })}
- Expected JSON format with q1, q2, q3, q4 arrays + {t('quadrantMatrix.invalidDataDesc', { ns: 'app' })}
@@ -93,30 +95,17 @@ const QuadrantMatrix: FC = ({ content }) => {
- Eisenhower Matrix + {t('quadrantMatrix.title', { ns: 'app' })}
- {totalTasks} - {' '} - task - {totalTasks !== 1 ? 's' : ''} - {' '} - prioritized + {t('quadrantMatrix.taskCount', { ns: 'app', count: totalTasks })}
{/* Legend + Expand Button */}
- - I - {' '} - = Importance - - - U - {' '} - = Urgency - + {t('quadrantMatrix.legend.importance', { ns: 'app' })} + {t('quadrantMatrix.legend.urgency', { ns: 'app' })}
@@ -139,28 +128,15 @@ const QuadrantMatrix: FC = ({ content }) => {
- Eisenhower Matrix + {t('quadrantMatrix.title', { ns: 'app' })}
- {totalTasks} - {' '} - task - {totalTasks !== 1 ? 's' : ''} - {' '} - prioritized + {t('quadrantMatrix.taskCount', { ns: 'app', count: totalTasks })}
- - I - {' '} - = Importance - - - U - {' '} - = Urgency - + {t('quadrantMatrix.legend.importance', { ns: 'app' })} + {t('quadrantMatrix.legend.urgency', { ns: 'app' })}
diff --git a/web/app/components/base/quadrant-matrix/quadrant-card.tsx b/web/app/components/base/quadrant-matrix/quadrant-card.tsx index 469c4c4082..4becefe435 100644 --- a/web/app/components/base/quadrant-matrix/quadrant-card.tsx +++ b/web/app/components/base/quadrant-matrix/quadrant-card.tsx @@ -1,6 +1,7 @@ 'use client' import type { FC } from 'react' import type { QuadrantConfig, Task } from './types' +import { useTranslation } from 'react-i18next' import { cn } from '@/utils/classnames' import TaskItem from './task-item' @@ -17,7 +18,8 @@ const QuadrantCard: FC = ({ expanded = false, maxDisplay = 3, }) => { - const { number, title, subtitle, bgClass, borderClass, titleClass } = config + const { t } = useTranslation() + const { number, titleKey, subtitleKey, bgClass, borderClass, titleClass } = config const displayLimit = expanded ? Infinity : maxDisplay const displayTasks = tasks.slice(0, displayLimit) const remainingCount = Math.max(0, tasks.length - displayLimit) @@ -43,14 +45,14 @@ const QuadrantCard: FC = ({ > {number} - {title} + {t(titleKey, { ns: 'app' })} {tasks.length > 0 && ( {tasks.length} )}
-
{subtitle}
+
{t(subtitleKey, { ns: 'app' })}
{/* Task List */} @@ -61,17 +63,28 @@ const QuadrantCard: FC = ({ > {displayTasks.length > 0 ? ( - displayTasks.map((task, index) => ( - - )) + displayTasks.map((task) => { + const taskKey = [ + task.name, + task.deadline ?? 'no-deadline', + task.importance_score, + task.urgency_score, + task.description ?? '', + task.action_advice ?? '', + ].join('|') + + return ( + + ) + }) ) : (
- No tasks + {t('quadrantMatrix.noTasks', { ns: 'app' })}
)} @@ -79,10 +92,7 @@ const QuadrantCard: FC = ({ {/* More indicator (only in non-expanded mode) */} {!expanded && remainingCount > 0 && (
- + - {remainingCount} - {' '} - more + {t('quadrantMatrix.more', { ns: 'app', count: remainingCount })}
)} diff --git a/web/app/components/base/quadrant-matrix/task-item.tsx b/web/app/components/base/quadrant-matrix/task-item.tsx index 68f47ddde2..2995e2e27d 100644 --- a/web/app/components/base/quadrant-matrix/task-item.tsx +++ b/web/app/components/base/quadrant-matrix/task-item.tsx @@ -2,6 +2,7 @@ import type { FC } from 'react' import type { Task } from './types' import { RiCalendarLine } from '@remixicon/react' +import { useTranslation } from 'react-i18next' import { cn } from '@/utils/classnames' type TaskItemProps = { @@ -11,6 +12,7 @@ type TaskItemProps = { } const TaskItem: FC = ({ task, expanded = false, showScores = true }) => { + const { t } = useTranslation() const { name, description, deadline, importance_score, urgency_score, action_advice } = task return ( @@ -57,7 +59,8 @@ const TaskItem: FC = ({ task, expanded = false, showScores = true - DDL: + {t('quadrantMatrix.deadline', { ns: 'app' })} + {' '} {deadline} diff --git a/web/app/components/base/quadrant-matrix/types.ts b/web/app/components/base/quadrant-matrix/types.ts index b86e686cf4..ecb65826d8 100644 --- a/web/app/components/base/quadrant-matrix/types.ts +++ b/web/app/components/base/quadrant-matrix/types.ts @@ -1,6 +1,7 @@ /** * Type definitions for Eisenhower Matrix (Task Quadrant) visualization */ +import type { I18nKeysWithPrefix } from '@/types/i18n' export type Task = { name: string @@ -18,11 +19,15 @@ export type QuadrantData = { q4: Task[] // Not Urgent & Not Important - Don't Do } +type QuadrantKeyBase = I18nKeysWithPrefix<'app', 'quadrantMatrix.q'> +type QuadrantTitleKey = Extract +type QuadrantSubtitleKey = Extract + export type QuadrantConfig = { key: 'q1' | 'q2' | 'q3' | 'q4' number: number - title: string - subtitle: string + titleKey: QuadrantTitleKey // i18n key for title + subtitleKey: QuadrantSubtitleKey // i18n key for subtitle bgClass: string borderClass: string titleClass: string @@ -35,8 +40,8 @@ export const QUADRANT_CONFIGS: Record = { q1: { key: 'q1', number: 1, - title: 'Do First', - subtitle: 'Urgent & Important', + titleKey: 'quadrantMatrix.q1.title', + subtitleKey: 'quadrantMatrix.q1.subtitle', bgClass: 'bg-state-destructive-hover', borderClass: 'border-state-destructive-border', titleClass: 'text-text-destructive', @@ -44,8 +49,8 @@ export const QUADRANT_CONFIGS: Record = { q2: { key: 'q2', number: 2, - title: 'Schedule', - subtitle: 'Important & Not Urgent', + titleKey: 'quadrantMatrix.q2.title', + subtitleKey: 'quadrantMatrix.q2.subtitle', bgClass: 'bg-state-accent-hover', borderClass: 'border-state-accent-border', titleClass: 'text-text-accent', @@ -53,8 +58,8 @@ export const QUADRANT_CONFIGS: Record = { q3: { key: 'q3', number: 3, - title: 'Delegate', - subtitle: 'Urgent & Not Important', + titleKey: 'quadrantMatrix.q3.title', + subtitleKey: 'quadrantMatrix.q3.subtitle', bgClass: 'bg-state-warning-hover', borderClass: 'border-state-warning-border', titleClass: 'text-text-warning', @@ -62,8 +67,8 @@ export const QUADRANT_CONFIGS: Record = { q4: { key: 'q4', number: 4, - title: 'Don\'t Do', - subtitle: 'Not Urgent & Not Important', + titleKey: 'quadrantMatrix.q4.title', + subtitleKey: 'quadrantMatrix.q4.subtitle', bgClass: 'bg-components-panel-on-panel-item-bg', borderClass: 'border-divider-regular', titleClass: 'text-text-tertiary', diff --git a/web/i18n/en-US/app.json b/web/i18n/en-US/app.json index e4109db4b6..bd8392a95a 100644 --- a/web/i18n/en-US/app.json +++ b/web/i18n/en-US/app.json @@ -196,6 +196,24 @@ "publishApp.notSet": "Not set", "publishApp.notSetDesc": "Currently nobody can access the web app. Please set permissions.", "publishApp.title": "Who can access web app", + "quadrantMatrix.deadline": "DDL:", + "quadrantMatrix.invalidData": "Invalid Quadrant Data", + "quadrantMatrix.invalidDataDesc": "Expected JSON format with q1, q2, q3, q4 arrays", + "quadrantMatrix.legend.importance": "I = Importance", + "quadrantMatrix.legend.urgency": "U = Urgency", + "quadrantMatrix.more": "+{{count}} more", + "quadrantMatrix.noTasks": "No tasks", + "quadrantMatrix.q1.subtitle": "Urgent & Important", + "quadrantMatrix.q1.title": "Do First", + "quadrantMatrix.q2.subtitle": "Important & Not Urgent", + "quadrantMatrix.q2.title": "Schedule", + "quadrantMatrix.q3.subtitle": "Urgent & Not Important", + "quadrantMatrix.q3.title": "Delegate", + "quadrantMatrix.q4.subtitle": "Not Urgent & Not Important", + "quadrantMatrix.q4.title": "Don't Do", + "quadrantMatrix.taskCount_one": "{{count}} task prioritized", + "quadrantMatrix.taskCount_other": "{{count}} tasks prioritized", + "quadrantMatrix.title": "Eisenhower Matrix", "removeOriginal": "Delete the original app", "roadmap": "See our roadmap", "showMyCreatedAppsOnly": "Created by me", diff --git a/web/i18n/zh-Hans/app.json b/web/i18n/zh-Hans/app.json index ee60cd3413..6a54e3e8b3 100644 --- a/web/i18n/zh-Hans/app.json +++ b/web/i18n/zh-Hans/app.json @@ -196,6 +196,24 @@ "publishApp.notSet": "未设置", "publishApp.notSetDesc": "当前任何人都无法访问 Web 应用。请设置访问权限。", "publishApp.title": "谁可以访问 web 应用", + "quadrantMatrix.deadline": "截止:", + "quadrantMatrix.invalidData": "无效的象限数据", + "quadrantMatrix.invalidDataDesc": "需要包含 q1, q2, q3, q4 数组的 JSON 格式", + "quadrantMatrix.legend.importance": "I = 重要性", + "quadrantMatrix.legend.urgency": "U = 紧急性", + "quadrantMatrix.more": "+{{count}} 更多", + "quadrantMatrix.noTasks": "暂无任务", + "quadrantMatrix.q1.subtitle": "紧急且重要", + "quadrantMatrix.q1.title": "立即执行", + "quadrantMatrix.q2.subtitle": "重要但不紧急", + "quadrantMatrix.q2.title": "计划安排", + "quadrantMatrix.q3.subtitle": "紧急但不重要", + "quadrantMatrix.q3.title": "委派他人", + "quadrantMatrix.q4.subtitle": "不紧急也不重要", + "quadrantMatrix.q4.title": "不要做", + "quadrantMatrix.taskCount_one": "{{count}} 个任务已排序", + "quadrantMatrix.taskCount_other": "{{count}} 个任务已排序", + "quadrantMatrix.title": "艾森豪威尔矩阵", "removeOriginal": "删除原应用", "roadmap": "产品路线图", "showMyCreatedAppsOnly": "我创建的",