From b7b0388dc1fab9e6d3de7308bb46120f68e1b417 Mon Sep 17 00:00:00 2001 From: DCCONSTRUCTIONS Date: Wed, 22 Apr 2026 22:05:31 +0300 Subject: [PATCH] =?UTF-8?q?UI=20-=20=D0=9C=D0=95=D0=96=D0=9F=D0=A0=D0=9E?= =?UTF-8?q?=D0=95=D0=9A=D0=A2=D0=9D=D0=90=D0=AF=20=D0=9A=D0=9E=D0=9C=D0=9C?= =?UTF-8?q?=D0=A3=D0=9D=D0=98=D0=9A=D0=90=D0=A6=D0=98=D0=AF:=20=D0=BA?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE=D0=BD=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D1=82=D1=83=D1=81=D0=BE=D0=B2=20=D0=B8=20?= =?UTF-8?q?=D1=81=D0=B8=D1=81=D1=82=D0=B5=D0=BC=D1=8B=20=D0=BE=D1=86=D0=B5?= =?UTF-8?q?=D0=BD=D0=BE=D0=BA=20=D0=B2=20=D0=BD=D0=B0=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=B9=D0=BA=D0=B0=D1=85=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/estimates/create/modal.tsx | 37 +++++--- .../components/estimates/create/stage-one.tsx | 25 +++--- .../components/estimates/delete/modal.tsx | 5 +- .../estimates/estimate-list-item.tsx | 7 +- .../web/core/components/estimates/helpers.ts | 89 +++++++++++++++++++ .../estimates/points/create-root.tsx | 17 +++- .../components/estimates/points/create.tsx | 8 +- .../components/estimates/points/preview.tsx | 17 ++-- .../components/estimates/points/update.tsx | 8 +- .../components/estimates/radio-select.tsx | 34 ++++--- .../project-states/create-update/update.tsx | 8 +- .../core/components/project-states/helpers.ts | 38 ++++++++ .../project-states/options/delete.tsx | 14 +-- .../options/mark-as-default.tsx | 8 +- .../project-states/state-item-title.tsx | 6 +- .../i18n/src/locales/en/translations.ts | 17 ++++ .../i18n/src/locales/ru/translations.ts | 17 ++++ 17 files changed, 292 insertions(+), 63 deletions(-) create mode 100644 plane-src/apps/web/core/components/estimates/helpers.ts create mode 100644 plane-src/apps/web/core/components/project-states/helpers.ts diff --git a/plane-src/apps/web/core/components/estimates/create/modal.tsx b/plane-src/apps/web/core/components/estimates/create/modal.tsx index 518f666..bcf8c2a 100644 --- a/plane-src/apps/web/core/components/estimates/create/modal.tsx +++ b/plane-src/apps/web/core/components/estimates/create/modal.tsx @@ -18,6 +18,7 @@ import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui"; import { useProjectEstimates } from "@/hooks/store/estimates"; // local imports import { EstimatePointCreateRoot } from "../points"; +import { getLocalizedEstimateSystemName, getLocalizedEstimateTemplateValues } from "../helpers"; import { EstimateCreateStageOne } from "./stage-one"; type TCreateEstimateModal = { @@ -92,7 +93,7 @@ export const CreateEstimateModal = observer(function CreateEstimateModal(props: setButtonLoader(true); const payload: IEstimateFormData = { estimate: { - name: ESTIMATE_SYSTEMS[estimateSystem]?.name, + name: getLocalizedEstimateSystemName(estimateSystem, t, ESTIMATE_SYSTEMS[estimateSystem]?.name), type: estimateSystem, last_used: true, }, @@ -142,15 +143,19 @@ export const CreateEstimateModal = observer(function CreateEstimateModal(props: // }, [estimatePointError]); return ( - -
+ +
{/* heading */} -
+
{estimatePoints && (
{ - setEstimateSystem(EEstimateSystem.POINTS); handleUpdatePoints(undefined); }} className="flex h-5 w-5 flex-shrink-0 cursor-pointer items-center justify-center" @@ -169,13 +174,13 @@ export const CreateEstimateModal = observer(function CreateEstimateModal(props:
{/* estimate steps */} -
+
{!estimatePoints && ( - handleUpdatePoints(ESTIMATE_SYSTEMS[estimateSystem].templates[templateType].values) + handleUpdatePoints(getLocalizedEstimateTemplateValues(estimateSystem, templateType, t)) } /> )} @@ -199,12 +204,24 @@ export const CreateEstimateModal = observer(function CreateEstimateModal(props: )} */}
-
- {estimatePoints && ( - )} diff --git a/plane-src/apps/web/core/components/estimates/create/stage-one.tsx b/plane-src/apps/web/core/components/estimates/create/stage-one.tsx index f6b4c99..a1f618c 100644 --- a/plane-src/apps/web/core/components/estimates/create/stage-one.tsx +++ b/plane-src/apps/web/core/components/estimates/create/stage-one.tsx @@ -16,6 +16,10 @@ import { convertMinutesToHoursMinutesString } from "@plane/utils"; import { isEstimateSystemEnabled } from "@/plane-web/components/estimates/helper"; import { UpgradeBadge } from "@/plane-web/components/workspace/upgrade-badge"; import { RadioInput } from "../radio-select"; +import { + getLocalizedEstimatePointValue, + getLocalizedEstimateTemplateTitle, +} from "../helpers"; // local imports type TEstimateCreateStageOne = { @@ -65,10 +69,10 @@ export function EstimateCreateStageOne(props: TEstimateCreateStageOne) { .filter((option) => option !== null)} name="estimate-radio-input" label={t("project_settings.estimates.create.choose_estimate_system")} - labelClassName="text-13 font-medium text-secondary mb-1.5" - wrapperClassName="relative flex flex-wrap gap-14" - fieldClassName="relative flex items-center gap-1.5" - buttonClassName="size-4" + labelClassName="mb-1.5 text-13 font-medium text-secondary" + wrapperClassName="relative flex flex-wrap gap-x-10 gap-y-4" + fieldClassName="relative flex items-center gap-2.5 text-primary" + buttonClassName="size-[1.05rem]" selected={estimateSystem} onChange={(value) => handleEstimateSystem(value as TEstimateSystemKeys)} /> @@ -80,13 +84,13 @@ export function EstimateCreateStageOne(props: TEstimateCreateStageOne) { {t("project_settings.estimates.create.start_from_scratch")}
@@ -100,16 +104,17 @@ export function EstimateCreateStageOne(props: TEstimateCreateStageOne) { currentEstimateSystem.templates[name]?.hide ? null : ( )}
diff --git a/plane-src/apps/web/core/components/estimates/points/create.tsx b/plane-src/apps/web/core/components/estimates/points/create.tsx index 50aced9..abbc09e 100644 --- a/plane-src/apps/web/core/components/estimates/points/create.tsx +++ b/plane-src/apps/web/core/components/estimates/points/create.tsx @@ -170,8 +170,8 @@ export const EstimatePointCreate = observer(function EstimatePointCreate(props:
0 && ( ))}
diff --git a/plane-src/apps/web/core/components/project-states/create-update/update.tsx b/plane-src/apps/web/core/components/project-states/create-update/update.tsx index 0c9535b..8792357 100644 --- a/plane-src/apps/web/core/components/project-states/create-update/update.tsx +++ b/plane-src/apps/web/core/components/project-states/create-update/update.tsx @@ -11,6 +11,7 @@ import { TOAST_TYPE, setToast } from "@plane/propel/toast"; import type { IState, TStateOperationsCallbacks } from "@plane/types"; // components import { StateForm } from "@/components/project-states"; +import { getLocalizedStateName } from "../helpers"; type TStateUpdate = { state: IState; @@ -62,9 +63,14 @@ export const StateUpdate = observer(function StateUpdate(props: TStateUpdate) { } }; + const localizedState = { + ...state, + name: getLocalizedStateName(state.name, state.group, t), + }; + return ( = { + backlog: "workspace_projects.state.backlog", + unstarted: "workspace_projects.state.unstarted", + started: "workspace_projects.state.started", + completed: "workspace_projects.state.completed", + cancelled: "workspace_projects.state.cancelled", +}; + +const DEFAULT_STATE_NAMES_BY_GROUP: Record = { + backlog: ["backlog"], + unstarted: ["todo", "to do", "unstarted"], + started: ["in progress", "in-progress", "started"], + completed: ["done", "completed"], + cancelled: ["cancelled", "canceled"], +}; + +export const getLocalizedStateName = ( + name: string | undefined, + group: TStateGroups, + t: (key: string) => string +) => { + if (!name) return ""; + + const normalizedName = name.trim().toLowerCase(); + if (DEFAULT_STATE_NAMES_BY_GROUP[group]?.includes(normalizedName)) { + return t(DEFAULT_STATE_KEYS_BY_GROUP[group]); + } + + return name; +}; diff --git a/plane-src/apps/web/core/components/project-states/options/delete.tsx b/plane-src/apps/web/core/components/project-states/options/delete.tsx index f349c0a..11ef2b4 100644 --- a/plane-src/apps/web/core/components/project-states/options/delete.tsx +++ b/plane-src/apps/web/core/components/project-states/options/delete.tsx @@ -17,6 +17,7 @@ import { AlertModalCore } from "@plane/ui"; import { cn } from "@plane/utils"; // hooks import { usePlatformOS } from "@/hooks/use-platform-os"; +import { getLocalizedStateName } from "../helpers"; type TStateDelete = { totalStates: number; @@ -35,6 +36,7 @@ export const StateDelete = observer(function StateDelete(props: TStateDelete) { const [isDelete, setIsDelete] = useState(false); // derived values const isDeleteDisabled = state.default ? true : totalStates === 1 ? true : false; + const localizedStateName = getLocalizedStateName(state?.name, state.group, t); const handleDeleteState = async () => { if (isDeleteDisabled) return; @@ -70,12 +72,12 @@ export const StateDelete = observer(function StateDelete(props: TStateDelete) { handleSubmit={handleDeleteState} isSubmitting={isDelete} isOpen={isDeleteModal} - title={t("entity.delete.label", { entity: t("common.state") })} - content={t("entity.delete.confirmation", { - entity: t("common.state").toLowerCase(), - identifier: state?.name ? `"${state.name}"` : "", - })} - /> + title={t("entity.delete.label", { entity: t("common.state") })} + content={t("entity.delete.confirmation", { + entity: t("common.state").toLowerCase(), + identifier: localizedStateName ? `"${localizedStateName}"` : "", + })} + /> ); }); diff --git a/plane-src/apps/web/core/components/project-states/state-item-title.tsx b/plane-src/apps/web/core/components/project-states/state-item-title.tsx index b3fce44..fd4a3f6 100644 --- a/plane-src/apps/web/core/components/project-states/state-item-title.tsx +++ b/plane-src/apps/web/core/components/project-states/state-item-title.tsx @@ -11,9 +11,11 @@ import { EIconSize, STATE_TRACKER_ELEMENTS } from "@plane/constants"; // plane imports import { EditIcon, StateGroupIcon } from "@plane/propel/icons"; import type { IState, TStateOperationsCallbacks } from "@plane/types"; +import { useTranslation } from "@plane/i18n"; // local imports import { useProjectState } from "@/hooks/store/use-project-state"; import { StateDelete, StateMarksAsDefault } from "./options"; +import { getLocalizedStateName } from "./helpers"; type TBaseStateItemTitleProps = { stateCount: number; @@ -38,9 +40,11 @@ export const StateItemTitle = observer(function StateItemTitle(props: TStateItem const { stateCount, setUpdateStateModal, disabled, state, shouldShowDescription = true } = props; // store hooks const { getStatePercentageInGroup } = useProjectState(); + const { t } = useTranslation(); // derived values const statePercentage = getStatePercentageInGroup(state.id); const percentage = statePercentage ? statePercentage / 100 : undefined; + const stateTitle = getLocalizedStateName(state.name, state.group, t); return (
@@ -57,7 +61,7 @@ export const StateItemTitle = observer(function StateItemTitle(props: TStateItem
{/* state title and description */}
-
{state.name}
+
{stateTitle}
{shouldShowDescription &&

{state.description}

}
diff --git a/plane-src/packages/i18n/src/locales/en/translations.ts b/plane-src/packages/i18n/src/locales/en/translations.ts index cda724d..94acccd 100644 --- a/plane-src/packages/i18n/src/locales/en/translations.ts +++ b/plane-src/packages/i18n/src/locales/en/translations.ts @@ -1930,6 +1930,9 @@ export default { heading: "States", description: "Define and customize workflow states to track the progress of your work items.", describe_this_state_for_your_members: "Describe this state for your members.", + default_label: "Default", + mark_as_default: "Mark as default", + marking_as_default: "Marking as default", delete: { blocked: "This state still contains work items. Move them to another state before deleting it.", error: "State could not be deleted. Please try again.", @@ -1988,6 +1991,14 @@ export default { enter_estimate_point: "Enter estimate", step: "Step {step} of {total}", label: "Create estimate", + add_points: "Add points", + add_categories: "Add categories", + add_time: "Add time", + custom_description: { + points: "Build your own point scale from scratch.", + categories: "Build your own category scale from scratch.", + time: "Build your own time scale from scratch.", + }, }, toasts: { created: { @@ -2056,6 +2067,12 @@ export default { hours: "Hours", }, }, + values: { + easy: "Easy", + medium: "Medium", + hard: "Hard", + very_hard: "Very hard", + }, }, automations: { label: "Automations", diff --git a/plane-src/packages/i18n/src/locales/ru/translations.ts b/plane-src/packages/i18n/src/locales/ru/translations.ts index 7984375..aa1bf56 100644 --- a/plane-src/packages/i18n/src/locales/ru/translations.ts +++ b/plane-src/packages/i18n/src/locales/ru/translations.ts @@ -2089,6 +2089,9 @@ export default { heading: "Статусы", description: "Определяйте и настраивайте статусы рабочего процесса для отслеживания прогресса рабочих элементов.", describe_this_state_for_your_members: "Опишите этот статус для участников", + default_label: "По умолчанию", + mark_as_default: "Сделать по умолчанию", + marking_as_default: "Назначение по умолчанию", delete: { blocked: "В этом статусе есть рабочие элементы. Переместите их в другой статус, чтобы удалить текущий.", error: "Не удалось удалить статус. Попробуйте снова.", @@ -2147,6 +2150,14 @@ export default { enter_estimate_point: "Ввести оценку", step: "Шаг {step} из {total}", label: "Создать оценку", + add_points: "Добавить баллы", + add_categories: "Добавить категории", + add_time: "Добавить время", + custom_description: { + points: "Создайте собственную шкалу баллов с нуля.", + categories: "Создайте собственную шкалу категорий с нуля.", + time: "Создайте собственную шкалу времени с нуля.", + }, }, toasts: { created: { @@ -2216,6 +2227,12 @@ export default { hours: "Часы", }, }, + values: { + easy: "Легко", + medium: "Средне", + hard: "Сложно", + very_hard: "Очень сложно", + }, }, automations: { label: "Автоматизация",