diff --git a/packages/constants/src/index.ts b/packages/constants/src/index.ts index 75e25cf91e0..d6175b8c6cf 100644 --- a/packages/constants/src/index.ts +++ b/packages/constants/src/index.ts @@ -15,6 +15,7 @@ export * from "./tab-indices"; export * from "./user"; export * from "./workspace"; export * from "./stickies"; +export * from "./module"; export * from "./project"; export * from "./views"; export * from "./inbox"; diff --git a/web/core/constants/module.ts b/packages/constants/src/module.ts similarity index 51% rename from web/core/constants/module.ts rename to packages/constants/src/module.ts index 8d26ab5f4e7..6ce30f0dcf1 100644 --- a/web/core/constants/module.ts +++ b/packages/constants/src/module.ts @@ -1,51 +1,54 @@ -import { GanttChartSquare, LayoutGrid, List } from "lucide-react"; // types -import { TModuleLayoutOptions, TModuleOrderByOptions, TModuleStatus } from "@plane/types"; +import { + TModuleLayoutOptions, + TModuleOrderByOptions, + TModuleStatus, +} from "@plane/types"; export const MODULE_STATUS: { - label: string; + i18n_label: string; value: TModuleStatus; color: string; textColor: string; bgColor: string; }[] = [ { - label: "Backlog", + i18n_label: "project_modules.status.backlog", value: "backlog", color: "#a3a3a2", textColor: "text-custom-text-400", bgColor: "bg-custom-background-80", }, { - label: "Planned", + i18n_label: "project_modules.status.planned", value: "planned", color: "#3f76ff", textColor: "text-blue-500", bgColor: "bg-indigo-50", }, { - label: "In Progress", + i18n_label: "project_modules.status.in_progress", value: "in-progress", color: "#f39e1f", textColor: "text-amber-500", bgColor: "bg-amber-50", }, { - label: "Paused", + i18n_label: "project_modules.status.paused", value: "paused", color: "#525252", textColor: "text-custom-text-300", bgColor: "bg-custom-background-90", }, { - label: "Completed", + i18n_label: "project_modules.status.completed", value: "completed", color: "#16a34a", textColor: "text-green-600", bgColor: "bg-green-100", }, { - label: "Cancelled", + i18n_label: "project_modules.status.cancelled", value: "cancelled", color: "#ef4444", textColor: "text-red-500", @@ -53,47 +56,50 @@ export const MODULE_STATUS: { }, ]; -export const MODULE_VIEW_LAYOUTS: { key: TModuleLayoutOptions; icon: any; title: string }[] = [ +export const MODULE_VIEW_LAYOUTS: { + key: TModuleLayoutOptions; + i18n_title: string; +}[] = [ { key: "list", - icon: List, - title: "List layout", + i18n_title: "project_modules.layout.list", }, { key: "board", - icon: LayoutGrid, - title: "Gallery layout", + i18n_title: "project_modules.layout.board", }, { key: "gantt", - icon: GanttChartSquare, - title: "Timeline layout", + i18n_title: "project_modules.layout.timeline", }, ]; -export const MODULE_ORDER_BY_OPTIONS: { key: TModuleOrderByOptions; label: string }[] = [ +export const MODULE_ORDER_BY_OPTIONS: { + key: TModuleOrderByOptions; + i18n_label: string; +}[] = [ { key: "name", - label: "Name", + i18n_label: "project_modules.order_by.name", }, { key: "progress", - label: "Progress", + i18n_label: "project_modules.order_by.progress", }, { key: "issues_length", - label: "Number of issues", + i18n_label: "project_modules.order_by.issues", }, { key: "target_date", - label: "Due date", + i18n_label: "project_modules.order_by.due_date", }, { key: "created_at", - label: "Created date", + i18n_label: "project_modules.order_by.created_at", }, { key: "sort_order", - label: "Manual", + i18n_label: "project_modules.order_by.manual", }, ]; diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 8391ac01ab6..f3b006c2a85 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -1279,5 +1279,28 @@ "assigned": "Assigned", "created": "Created", "subscribed": "Subscribed" + }, + "project_modules": { + "status": { + "backlog": "Backlog", + "planned": "Planned", + "in_progress": "In Progress", + "paused": "Paused", + "completed": "Completed", + "cancelled": "Cancelled" + }, + "layout": { + "list": "List layout", + "board": "Gallery layout", + "timeline": "Timeline layout" + }, + "order_by": { + "name": "Name", + "progress": "Progress", + "issues": "Number of issues", + "due_date": "Due date", + "created_at": "Created date", + "manual": "Manual" + } } } diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index a4baa482bab..79d379ea802 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -1283,5 +1283,29 @@ "assigned": "Asignados", "created": "Creados", "subscribed": "Suscritos" + }, + + "project_modules": { + "status": { + "backlog": "Pendientes", + "planned": "Planificado", + "in_progress": "En progreso", + "paused": "Pausado", + "completed": "Completado", + "cancelled": "Cancelado" + }, + "layout": { + "list": "Vista lista", + "board": "Vista galería", + "timeline": "Vista cronológica" + }, + "order_by": { + "name": "Nombre", + "progress": "Progreso", + "issues": "Número de problemas", + "due_date": "Fecha de vencimiento", + "created_at": "Fecha de creación", + "manual": "Manual" + } } } diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 2c5847e4b93..83886c12cff 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -1278,5 +1278,29 @@ "assigned": "Assignés", "created": "Créés", "subscribed": "Abonnés" + }, + + "project_modules": { + "status": { + "backlog": "Backlog", + "planned": "Planifié", + "in_progress": "En cours", + "paused": "En pause", + "completed": "Terminé", + "cancelled": "Annulé" + }, + "layout": { + "list": "Vue liste", + "board": "Vue galerie", + "timeline": "Vue chronologique" + }, + "order_by": { + "name": "Nom", + "progress": "Progression", + "issues": "Nombre de problèmes", + "due_date": "Date d'échéance", + "created_at": "Date de création", + "manual": "Manuel" + } } } diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index 7f727c34964..5f1c2a47459 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -1281,5 +1281,31 @@ "assigned": "割り当て済み", "created": "作成済み", "subscribed": "購読済み" + }, + + + "project_modules": { + "status": { + "backlog": "バックログ", + "planned": "計画済み", + "in_progress": "進行中", + "paused": "一時停止", + "completed": "完了", + "cancelled": "キャンセル" + }, + "layout": { + "list": "リスト表示", + "board": "ギャラリー表示", + "timeline": "タイムライン表示" + }, + "order_by": { + "name": "名前", + "progress": "進捗", + "issues": "課題数", + "due_date": "期限", + "created_at": "作成日", + "manual": "手動" + } } + } diff --git a/packages/i18n/src/locales/zh-CN/translations.json b/packages/i18n/src/locales/zh-CN/translations.json index e75371244a2..b86c5d1674a 100644 --- a/packages/i18n/src/locales/zh-CN/translations.json +++ b/packages/i18n/src/locales/zh-CN/translations.json @@ -852,5 +852,30 @@ "common": { "months_count": "{months, plural, one{#个月} other{#个月}}" } + }, + + "project_modules": { + "status": { + "backlog": "待办", + "planned": "已规划", + "in_progress": "进行中", + "paused": "已暂停", + "completed": "已完成", + "cancelled": "已取消" + }, + "layout": { + "list": "列表视图", + "board": "画廊视图", + "timeline": "时间轴视图" + }, + "order_by": { + "name": "名称", + "progress": "进度", + "issues": "问题数量", + "due_date": "截止日期", + "created_at": "创建日期", + "manual": "手动" + } } + } diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(list)/mobile-header.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(list)/mobile-header.tsx index 12301c9d44d..629dca36a1c 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(list)/mobile-header.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(list)/mobile-header.tsx @@ -2,13 +2,16 @@ import { observer } from "mobx-react"; import { ChevronDown } from "lucide-react"; +import { MODULE_VIEW_LAYOUTS } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { CustomMenu, Row } from "@plane/ui"; -import { MODULE_VIEW_LAYOUTS } from "@/constants/module"; +import { ModuleLayoutIcon } from "@/components/modules"; import { useModuleFilter, useProject } from "@/hooks/store"; export const ModulesListMobileHeader = observer(() => { const { currentProjectDetails } = useProject(); const { updateDisplayFilters } = useModuleFilter(); + const { t } = useTranslation(); return (
@@ -34,8 +37,8 @@ export const ModulesListMobileHeader = observer(() => { }} className="flex items-center gap-2" > - -
{layout.title}
+ +
{t(layout.i18n_title)}
); })} diff --git a/web/core/components/modules/analytics-sidebar/root.tsx b/web/core/components/modules/analytics-sidebar/root.tsx index cf3ae40c85b..227619623ed 100644 --- a/web/core/components/modules/analytics-sidebar/root.tsx +++ b/web/core/components/modules/analytics-sidebar/root.tsx @@ -18,6 +18,8 @@ import { } from "lucide-react"; import { Disclosure, Transition } from "@headlessui/react"; // plane types +import { MODULE_STATUS } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { ILinkDetails, IModule, ModuleLink } from "@plane/types"; // plane ui import { @@ -46,7 +48,7 @@ import { MODULE_LINK_UPDATED, MODULE_UPDATED, } from "@/constants/event-tracker"; -import { MODULE_STATUS } from "@/constants/module"; + // helpers import { getDate, renderFormattedPayloadDate } from "@/helpers/date-time.helper"; import { copyUrlToClipboard } from "@/helpers/string.helper"; @@ -84,7 +86,7 @@ export const ModuleAnalyticsSidebar: React.FC = observer((props) => { const { workspaceSlug, projectId } = useParams(); // store hooks - + const { t } = useTranslation(); const { allowPermissions } = useUserPermissions(); const { getModuleById, updateModuleDetails, createModuleLink, updateModuleLink, deleteModuleLink, restoreModule } = @@ -374,7 +376,7 @@ export const ModuleAnalyticsSidebar: React.FC = observer((props) => { backgroundColor: moduleStatus ? `${moduleStatus.color}20` : "#a3a3a220", }} > - {moduleStatus?.label ?? "Backlog"} + {(moduleStatus && t(moduleStatus?.i18n_label)) ?? t("project_modules.status.backlog")} } value={value} @@ -387,7 +389,7 @@ export const ModuleAnalyticsSidebar: React.FC = observer((props) => {
- {status.label} + {t(status.i18n_label)}
))} diff --git a/web/core/components/modules/applied-filters/status.tsx b/web/core/components/modules/applied-filters/status.tsx index 442dcfadcc8..15a2e8b6ee7 100644 --- a/web/core/components/modules/applied-filters/status.tsx +++ b/web/core/components/modules/applied-filters/status.tsx @@ -3,9 +3,10 @@ import { observer } from "mobx-react"; import { X } from "lucide-react"; // ui +import { MODULE_STATUS } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { ModuleStatusIcon } from "@plane/ui"; // constants -import { MODULE_STATUS } from "@/constants/module"; type Props = { handleRemove: (val: string) => void; @@ -15,6 +16,7 @@ type Props = { export const AppliedStatusFilters: React.FC = observer((props) => { const { handleRemove, values, editable } = props; + const { t } = useTranslation(); return ( <> @@ -25,7 +27,7 @@ export const AppliedStatusFilters: React.FC = observer((props) => { return (
- {statusDetails.label} + {t(statusDetails.i18n_label)} {editable && ( ))} diff --git a/web/core/components/modules/select/status.tsx b/web/core/components/modules/select/status.tsx index f3a583516ed..7da437946c1 100644 --- a/web/core/components/modules/select/status.tsx +++ b/web/core/components/modules/select/status.tsx @@ -4,11 +4,12 @@ import React from "react"; // react hook form import { Controller, FieldError, Control } from "react-hook-form"; +import { MODULE_STATUS } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import type { IModule } from "@plane/types"; // ui import { CustomSelect, DoubleCircleIcon, ModuleStatusIcon } from "@plane/ui"; // types -import { MODULE_STATUS } from "@/constants/module"; // constants type Props = { @@ -17,39 +18,45 @@ type Props = { tabIndex?: number; }; -export const ModuleStatusSelect: React.FC = ({ control, error, tabIndex }) => ( - ( - - {value ? ( - - ) : ( - - )} - {MODULE_STATUS.find((s) => s.value === value)?.label ?? ( - Status - )} -
- } - onChange={onChange} - tabIndex={tabIndex} - noChevron - > - {MODULE_STATUS.map((status) => ( - -
- - {status.label} -
-
- ))} - - )} - /> -); +export const ModuleStatusSelect: React.FC = ({ control, error, tabIndex }) => { + const { t } = useTranslation(); + return ( + { + const selectedValue = MODULE_STATUS.find((s) => s.value === value); + return ( + + {value ? ( + + ) : ( + + )} + {(selectedValue && t(selectedValue?.i18n_label)) ?? ( + Status + )} +
+ } + onChange={onChange} + tabIndex={tabIndex} + noChevron + > + {MODULE_STATUS.map((status) => ( + +
+ + {t(status.i18n_label)} +
+
+ ))} + + ); + }} + /> + ); +}; diff --git a/web/core/components/modules/sidebar-select/select-status.tsx b/web/core/components/modules/sidebar-select/select-status.tsx index fcac3e01fae..9d7a7fda93d 100644 --- a/web/core/components/modules/sidebar-select/select-status.tsx +++ b/web/core/components/modules/sidebar-select/select-status.tsx @@ -4,11 +4,12 @@ import React from "react"; // react-hook-form import { Control, Controller, UseFormWatch } from "react-hook-form"; +import { MODULE_STATUS } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { IModule } from "@plane/types"; // ui import { CustomSelect, DoubleCircleIcon } from "@plane/ui"; // types -import { MODULE_STATUS } from "@/constants/module"; // common // constants @@ -18,45 +19,48 @@ type Props = { watch: UseFormWatch>; }; -export const SidebarStatusSelect: React.FC = ({ control, submitChanges, watch }) => ( -
-
- -

Status

+export const SidebarStatusSelect: React.FC = ({ control, submitChanges, watch }) => { + const { t } = useTranslation(); + return ( +
+
+ +

Status

+
+
+ ( + + option.value === value)?.color, + }} + /> + {watch("status")} + + } + value={value} + onChange={(value: any) => { + submitChanges({ status: value }); + }} + > + {MODULE_STATUS.map((option) => ( + +
+ + {t(option.i18n_label)} +
+
+ ))} +
+ )} + /> +
-
- ( - - option.value === value)?.color, - }} - /> - {watch("status")} - - } - value={value} - onChange={(value: any) => { - submitChanges({ status: value }); - }} - > - {MODULE_STATUS.map((option) => ( - -
- - {option.label} -
-
- ))} -
- )} - /> -
-
-); + ); +};