From 0e87184de9d0a4adfd5d9280d7bba21bce355457 Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:14 +0000 Subject: [PATCH 01/62] feat(tracker): register Gantt view tab (placeholder UI) Signed-off-by: Michael Uray --- models/tracker/src/viewlets.ts | 48 +++++++++++++++++++ plugins/tracker-assets/lang/cs.json | 7 ++- plugins/tracker-assets/lang/de.json | 7 ++- plugins/tracker-assets/lang/en.json | 7 ++- plugins/tracker-assets/lang/es.json | 7 ++- plugins/tracker-assets/lang/fr.json | 7 ++- plugins/tracker-assets/lang/it.json | 7 ++- plugins/tracker-assets/lang/ja.json | 7 ++- plugins/tracker-assets/lang/ko.json | 7 ++- plugins/tracker-assets/lang/pt-br.json | 7 ++- plugins/tracker-assets/lang/pt.json | 7 ++- plugins/tracker-assets/lang/ru.json | 7 ++- plugins/tracker-assets/lang/tr.json | 7 ++- plugins/tracker-assets/lang/zh.json | 7 ++- plugins/tracker-resources/package.json | 4 +- .../src/components/gantt/GanttView.svelte | 41 ++++++++++++++++ plugins/tracker-resources/src/index.ts | 2 + plugins/tracker-resources/src/plugin.ts | 11 ++++- 18 files changed, 182 insertions(+), 15 deletions(-) create mode 100644 plugins/tracker-resources/src/components/gantt/GanttView.svelte diff --git a/models/tracker/src/viewlets.ts b/models/tracker/src/viewlets.ts index 509e00d7d0e..194a5a7554d 100644 --- a/models/tracker/src/viewlets.ts +++ b/models/tracker/src/viewlets.ts @@ -212,6 +212,30 @@ export function issueConfig ( ] } +export function ganttViewOptions (): ViewOptionsModel { + // PR 2 ships a minimal read-only Gantt. Group-by / dropdown ViewOptions + // are intentionally NOT advertised here — the canvas does not honour them + // yet. They will be added in PR 3 alongside drag/edit + Component swimlanes + // so users never see options that have no effect. + return { + groupBy: [], + orderBy: [ + ['startDate', SortingOrder.Ascending], + ['rank', SortingOrder.Ascending], + ['dueDate', SortingOrder.Ascending] + ], + other: [showColorsViewOption] + } +} + +export function ganttConfig (): BuildModelKey[] { + // Minimal config — Gantt drives its own column layout. + return [ + { key: '', presenter: tracker.component.PriorityEditor, label: tracker.string.Priority, props: { kind: 'list', size: 'small' } }, + { key: '', presenter: tracker.component.IssuePresenter, label: tracker.string.Issue } + ] +} + export function defineViewlets (builder: Builder): void { builder.createDoc( view.class.ViewletDescriptor, @@ -224,6 +248,30 @@ export function defineViewlets (builder: Builder): void { tracker.viewlet.Kanban ) + builder.createDoc( + view.class.ViewletDescriptor, + core.space.Model, + { + label: tracker.string.Gantt, + icon: tracker.icon.Issues, + component: tracker.component.GanttView + }, + tracker.viewlet.Gantt + ) + + builder.createDoc( + view.class.Viewlet, + core.space.Model, + { + attachTo: tracker.class.Issue, + descriptor: tracker.viewlet.Gantt, + viewOptions: ganttViewOptions(), + configOptions: { strict: true, hiddenKeys: ['title'] }, + config: ganttConfig() + }, + tracker.viewlet.IssueGantt + ) + builder.createDoc( view.class.Viewlet, core.space.Model, diff --git a/plugins/tracker-assets/lang/cs.json b/plugins/tracker-assets/lang/cs.json index dea411668af..9f87e86aff4 100644 --- a/plugins/tracker-assets/lang/cs.json +++ b/plugins/tracker-assets/lang/cs.json @@ -283,7 +283,12 @@ "UnsetParentIssue": "Odebrat nadřazený úkol", "ForbidCreateProjectPermission": "Zakázat vytvoření projektu", "ForbidCreateProjectPermissionDescription": "Zakazuje uživatelům vytvářet nové projekty", - "AllowCreatingIssues": "Povolit vytváření úkolů" + "AllowCreatingIssues": "Povolit vytváření úkolů", + "Day": "Den", + "Gantt": "Gantt", + "Month": "Měsíc", + "Quarter": "Čtvrtletí", + "Week": "Týden" }, "status": {} } diff --git a/plugins/tracker-assets/lang/de.json b/plugins/tracker-assets/lang/de.json index d1e698c9c9a..51aa73d1518 100644 --- a/plugins/tracker-assets/lang/de.json +++ b/plugins/tracker-assets/lang/de.json @@ -293,7 +293,12 @@ "UnsetParentIssue": "Übergeordnete Aufgabe entfernen", "ForbidCreateProjectPermission": "Projekterstellung verbieten", "ForbidCreateProjectPermissionDescription": "Verbietet Benutzern das Erstellen neuer Projekte", - "AllowCreatingIssues": "Erstellen von Aufgaben erlauben" + "AllowCreatingIssues": "Erstellen von Aufgaben erlauben", + "Day": "Tag", + "Gantt": "Gantt", + "Month": "Monat", + "Quarter": "Quartal", + "Week": "Woche" }, "status": {} } diff --git a/plugins/tracker-assets/lang/en.json b/plugins/tracker-assets/lang/en.json index 3d856a20031..7dad04bee41 100644 --- a/plugins/tracker-assets/lang/en.json +++ b/plugins/tracker-assets/lang/en.json @@ -293,7 +293,12 @@ "UnsetParentIssue": "Unset parent issue", "ForbidCreateProjectPermission": "Forbid create project", "ForbidCreateProjectPermissionDescription": "Forbid users creating new projects", - "AllowCreatingIssues": "Allow creating issues" + "AllowCreatingIssues": "Allow creating issues", + "Day": "Day", + "Gantt": "Gantt", + "Month": "Month", + "Quarter": "Quarter", + "Week": "Week" }, "status": {} } diff --git a/plugins/tracker-assets/lang/es.json b/plugins/tracker-assets/lang/es.json index ed9795ef41b..127dc0a4f63 100644 --- a/plugins/tracker-assets/lang/es.json +++ b/plugins/tracker-assets/lang/es.json @@ -276,7 +276,12 @@ "UnsetParentIssue": "Unset parent issue", "ForbidCreateProjectPermission": "Prohibir crear proyecto", "ForbidCreateProjectPermissionDescription": "Prohíbe a los usuarios crear nuevos proyectos", - "AllowCreatingIssues": "Permitir crear incidencias" + "AllowCreatingIssues": "Permitir crear incidencias", + "Day": "Día", + "Gantt": "Gantt", + "Month": "Mes", + "Quarter": "Trimestre", + "Week": "Semana" }, "status": {} } diff --git a/plugins/tracker-assets/lang/fr.json b/plugins/tracker-assets/lang/fr.json index daa7f4eaaba..4bf83349e83 100644 --- a/plugins/tracker-assets/lang/fr.json +++ b/plugins/tracker-assets/lang/fr.json @@ -276,7 +276,12 @@ "UnsetParentIssue": "Désélectionner l'issue parent", "ForbidCreateProjectPermission": "Interdire la création de projet", "ForbidCreateProjectPermissionDescription": "Interdit aux utilisateurs de créer de nouveaux projets", - "AllowCreatingIssues": "Autoriser la création d'issues" + "AllowCreatingIssues": "Autoriser la création d'issues", + "Day": "Jour", + "Gantt": "Gantt", + "Month": "Mois", + "Quarter": "Trimestre", + "Week": "Semaine" }, "status": {} } diff --git a/plugins/tracker-assets/lang/it.json b/plugins/tracker-assets/lang/it.json index 7fe2285f261..02d01f2850c 100644 --- a/plugins/tracker-assets/lang/it.json +++ b/plugins/tracker-assets/lang/it.json @@ -276,7 +276,12 @@ "UnsetParentIssue": "Annulla l'issue genitore", "ForbidCreateProjectPermission": "Vieta creazione progetto", "ForbidCreateProjectPermissionDescription": "Vieta agli utenti di creare nuovi progetti", - "AllowCreatingIssues": "Consenti la creazione di issue" + "AllowCreatingIssues": "Consenti la creazione di issue", + "Day": "Giorno", + "Gantt": "Gantt", + "Month": "Mese", + "Quarter": "Trimestre", + "Week": "Settimana" }, "status": {} } diff --git a/plugins/tracker-assets/lang/ja.json b/plugins/tracker-assets/lang/ja.json index 34426b09875..61b13474fd4 100644 --- a/plugins/tracker-assets/lang/ja.json +++ b/plugins/tracker-assets/lang/ja.json @@ -276,7 +276,12 @@ "UnsetParentIssue": "親イシューの設定を解除", "ForbidCreateProjectPermission": "プロジェクト作成禁止", "ForbidCreateProjectPermissionDescription": "ユーザーが新しいプロジェクトを作成することを禁止します", - "AllowCreatingIssues": "イシューの作成を許可" + "AllowCreatingIssues": "イシューの作成を許可", + "Day": "日", + "Gantt": "Gantt", + "Month": "月", + "Quarter": "四半期", + "Week": "週" }, "status": {} } diff --git a/plugins/tracker-assets/lang/ko.json b/plugins/tracker-assets/lang/ko.json index 32b4b4c75c6..5d8c5ca23b6 100644 --- a/plugins/tracker-assets/lang/ko.json +++ b/plugins/tracker-assets/lang/ko.json @@ -276,7 +276,12 @@ "UnsetParentIssue": "상위 이슈 설정 해제", "ForbidCreateProjectPermission": "프로젝트 생성 금지", "ForbidCreateProjectPermissionDescription": "사용자의 새 프로젝트 생성을 금지", - "AllowCreatingIssues": "이슈 생성 허용" + "AllowCreatingIssues": "이슈 생성 허용", + "Day": "일", + "Gantt": "Gantt", + "Month": "월", + "Quarter": "분기", + "Week": "주" }, "status": {} } diff --git a/plugins/tracker-assets/lang/pt-br.json b/plugins/tracker-assets/lang/pt-br.json index 9d8ec0214e2..c32447c979d 100644 --- a/plugins/tracker-assets/lang/pt-br.json +++ b/plugins/tracker-assets/lang/pt-br.json @@ -276,7 +276,12 @@ "UnsetParentIssue": "Desmarcar problema pai", "ForbidCreateProjectPermission": "Proibir criação de projeto", "ForbidCreateProjectPermissionDescription": "Proíbe os usuários de criar novos projetos", - "AllowCreatingIssues": "Permitir criar problemas" + "AllowCreatingIssues": "Permitir criar problemas", + "Day": "Dia", + "Gantt": "Gantt", + "Month": "Mês", + "Quarter": "Trimestre", + "Week": "Semana" }, "status": {} } diff --git a/plugins/tracker-assets/lang/pt.json b/plugins/tracker-assets/lang/pt.json index 82a640e2c59..d83e2745a75 100644 --- a/plugins/tracker-assets/lang/pt.json +++ b/plugins/tracker-assets/lang/pt.json @@ -276,7 +276,12 @@ "UnsetParentIssue": "Desmarcar problema pai", "ForbidCreateProjectPermission": "Proibir criação de projeto", "ForbidCreateProjectPermissionDescription": "Proíbe os usuários de criar novos projetos", - "AllowCreatingIssues": "Permitir criar problemas" + "AllowCreatingIssues": "Permitir criar problemas", + "Day": "Dia", + "Gantt": "Gantt", + "Month": "Mês", + "Quarter": "Trimestre", + "Week": "Semana" }, "status": {} } diff --git a/plugins/tracker-assets/lang/ru.json b/plugins/tracker-assets/lang/ru.json index 7ccd4cb5ccd..142a3eec2b3 100644 --- a/plugins/tracker-assets/lang/ru.json +++ b/plugins/tracker-assets/lang/ru.json @@ -293,7 +293,12 @@ "UnsetParentIssue": "Снять родительскую задачу", "ForbidCreateProjectPermission": "Запретить создание проекта", "ForbidCreateProjectPermissionDescription": "Запрещает пользователям создавать новые проекты", - "AllowCreatingIssues": "Разрешить создание задач" + "AllowCreatingIssues": "Разрешить создание задач", + "Day": "День", + "Gantt": "Gantt", + "Month": "Месяц", + "Quarter": "Квартал", + "Week": "Неделя" }, "status": {} } diff --git a/plugins/tracker-assets/lang/tr.json b/plugins/tracker-assets/lang/tr.json index ec118014359..0e040c303d7 100644 --- a/plugins/tracker-assets/lang/tr.json +++ b/plugins/tracker-assets/lang/tr.json @@ -274,7 +274,12 @@ "IssueStatus": "Durum", "Extensions": "Uzantılar", "UnsetParentIssue": "Üst sorunu kaldır", - "AllowCreatingIssues": "Sorun oluşturmaya izin ver" + "AllowCreatingIssues": "Sorun oluşturmaya izin ver", + "Day": "Gün", + "Gantt": "Gantt", + "Month": "Ay", + "Quarter": "Çeyrek", + "Week": "Hafta" }, "status": {} } diff --git a/plugins/tracker-assets/lang/zh.json b/plugins/tracker-assets/lang/zh.json index a424d856cac..7bf3bc34d7c 100644 --- a/plugins/tracker-assets/lang/zh.json +++ b/plugins/tracker-assets/lang/zh.json @@ -293,7 +293,12 @@ "UnsetParentIssue": "取消父问题", "ForbidCreateProjectPermission": "禁止创建项目", "ForbidCreateProjectPermissionDescription": "禁止用户创建新项目", - "AllowCreatingIssues": "允许创建问题" + "AllowCreatingIssues": "允许创建问题", + "Day": "日", + "Gantt": "Gantt", + "Month": "月", + "Quarter": "季度", + "Week": "周" }, "status": {} } diff --git a/plugins/tracker-resources/package.json b/plugins/tracker-resources/package.json index 7afa566df43..7ae0b97d0a3 100644 --- a/plugins/tracker-resources/package.json +++ b/plugins/tracker-resources/package.json @@ -8,12 +8,14 @@ "build": "compile ui", "build:docs": "api-extractor run --local", "svelte-check": "do-svelte-check", + "test": "jest --passWithNoTests --silent", "_phase:svelte-check": "do-svelte-check", "format": "format src", "build:watch": "compile ui", "_phase:build": "compile ui", "_phase:format": "format src", - "_phase:validate": "compile validate" + "_phase:validate": "compile validate", + "_phase:test": "jest --passWithNoTests --silent" }, "devDependencies": { "svelte-loader": "^3.2.0", diff --git a/plugins/tracker-resources/src/components/gantt/GanttView.svelte b/plugins/tracker-resources/src/components/gantt/GanttView.svelte new file mode 100644 index 00000000000..5a951fd57ab --- /dev/null +++ b/plugins/tracker-resources/src/components/gantt/GanttView.svelte @@ -0,0 +1,41 @@ + + + +
+
+
+
+ + diff --git a/plugins/tracker-resources/src/index.ts b/plugins/tracker-resources/src/index.ts index 071a13ac73f..58cec18fb0c 100644 --- a/plugins/tracker-resources/src/index.ts +++ b/plugins/tracker-resources/src/index.ts @@ -52,6 +52,7 @@ import ProjectComponents from './components/components/ProjectComponents.svelte' import CreateIssue from './components/CreateIssue.svelte' import EditRelatedTargets from './components/EditRelatedTargets.svelte' import EditRelatedTargetsPopup from './components/EditRelatedTargetsPopup.svelte' +import GanttView from './components/gantt/GanttView.svelte' import AssigneeEditor from './components/issues/AssigneeEditor.svelte' import DueDatePresenter from './components/issues/DueDatePresenter.svelte' import EditIssue from './components/issues/edit/EditIssue.svelte' @@ -434,6 +435,7 @@ export default async (): Promise => ({ EditComponent, IssuesView, KanbanView, + GanttView, ProjectComponents, IssuePreview, RelationsPopup, diff --git a/plugins/tracker-resources/src/plugin.ts b/plugins/tracker-resources/src/plugin.ts index eed088c59d5..fc1f85177ad 100644 --- a/plugins/tracker-resources/src/plugin.ts +++ b/plugins/tracker-resources/src/plugin.ts @@ -36,6 +36,8 @@ export default mergeIds(trackerId, tracker, { SubIssues: '' as Ref, List: '' as Ref, Kanban: '' as Ref, + Gantt: '' as Ref, + IssueGantt: '' as Ref, MilestoneIssuesList: '' as Ref, ComponentIssuesList: '' as Ref }, @@ -307,7 +309,13 @@ export default mergeIds(trackerId, tracker, { UnsetParent: '' as IntlString, PreviousAssigned: '' as IntlString, EditRelatedTargets: '' as IntlString, - RelatedIssueTargetDescription: '' as IntlString + RelatedIssueTargetDescription: '' as IntlString, + + Day: '' as IntlString, + Gantt: '' as IntlString, + Month: '' as IntlString, + Quarter: '' as IntlString, + Week: '' as IntlString }, component: { NopeComponent: '' as AnyComponent, @@ -347,6 +355,7 @@ export default mergeIds(trackerId, tracker, { EditComponent: '' as AnyComponent, IssuesView: '' as AnyComponent, KanbanView: '' as AnyComponent, + GanttView: '' as AnyComponent, ProjectComponents: '' as AnyComponent, IssuePreview: '' as AnyComponent, RelationsPopup: '' as AnyComponent, From 4868b15a869aaca2b423f7dc869950354d6bd869 Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:14 +0000 Subject: [PATCH 02/62] feat(tracker-resources): add Gantt lib types Signed-off-by: Michael Uray --- .../src/components/gantt/.gitignore | 3 ++ .../src/components/gantt/lib/types.ts | 50 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 plugins/tracker-resources/src/components/gantt/.gitignore create mode 100644 plugins/tracker-resources/src/components/gantt/lib/types.ts diff --git a/plugins/tracker-resources/src/components/gantt/.gitignore b/plugins/tracker-resources/src/components/gantt/.gitignore new file mode 100644 index 00000000000..176a11c6ff4 --- /dev/null +++ b/plugins/tracker-resources/src/components/gantt/.gitignore @@ -0,0 +1,3 @@ +# Override root-level lib/ ignore — this lib/ is source code, not build output. +!lib/ +!lib/** diff --git a/plugins/tracker-resources/src/components/gantt/lib/types.ts b/plugins/tracker-resources/src/components/gantt/lib/types.ts new file mode 100644 index 00000000000..485ecabf5ae --- /dev/null +++ b/plugins/tracker-resources/src/components/gantt/lib/types.ts @@ -0,0 +1,50 @@ +// +// Copyright © 2026 Hardcore Engineering Inc. +// SPDX-License-Identifier: EPL-2.0 +// + +import { type Ref } from '@hcengineering/core' +import { type Issue, type Component as TrackerComponent, type Milestone } from '@hcengineering/tracker' + +/** Zoom presets — controls pxPerDay and header tick density. */ +export type ZoomLevel = 'day' | 'week' | 'month' | 'quarter' + +/** A single tick on the time-axis header (vertical gridline + label). */ +export interface Tick { + date: number // UTC ms + label: string // pre-formatted, locale-aware + level: 'major' | 'minor' // major ticks render thicker + with text label +} + +/** A row in the flattened layout. May be an issue or a component-swimlane header. */ +export interface LayoutRow { + kind: 'issue' | 'component-swimlane' + /** Y-coord top-edge of the row in canvas pixels. */ + y: number + /** Row height in pixels. */ + height: number + /** Tree depth — 0 for top-level issues. */ + depth: number + /** Whether this row is currently rendered (vs virtually skipped). */ + visible: boolean + /** The issue this row represents — null for swimlane headers. */ + issue: Issue | null + /** The component this swimlane represents — null for issue rows. */ + component: Ref | null + /** True iff this issue has children (renders as summary "claw" bar). */ + isSummary: boolean +} + +/** Cached aggregate dates of a parent issue's children, for summary-bar rendering. */ +export interface SummaryRange { + startDate: number | null + dueDate: number | null +} + +/** Compact view of a Milestone for the canvas overlay. */ +export interface MilestoneMarker { + _id: Ref + label: string + startDate: number | null + targetDate: number +} From 5399bf69819e094aff389ab0b40682ce3e673714 Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:14 +0000 Subject: [PATCH 03/62] test(tracker-resources): add failing Gantt time-scale tests Signed-off-by: Michael Uray --- .../gantt/lib/__tests__/time-scale.test.ts | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 plugins/tracker-resources/src/components/gantt/lib/__tests__/time-scale.test.ts diff --git a/plugins/tracker-resources/src/components/gantt/lib/__tests__/time-scale.test.ts b/plugins/tracker-resources/src/components/gantt/lib/__tests__/time-scale.test.ts new file mode 100644 index 00000000000..e0b3b8262d2 --- /dev/null +++ b/plugins/tracker-resources/src/components/gantt/lib/__tests__/time-scale.test.ts @@ -0,0 +1,78 @@ +// +// Copyright © 2026 Hardcore Engineering Inc. +// SPDX-License-Identifier: EPL-2.0 +// + +import { createTimeScale, snapToUtcMidnight } from '../time-scale' + +const DAY_MS = 86_400_000 + +describe('snapToUtcMidnight', () => { + it('returns 0 unchanged', () => { + expect(snapToUtcMidnight(0)).toBe(0) + }) + + it('rounds down to UTC midnight', () => { + const t = Date.UTC(2026, 4, 15, 17, 30, 45) // 2026-05-15 17:30:45 UTC + expect(snapToUtcMidnight(t)).toBe(Date.UTC(2026, 4, 15)) + }) + + it('is idempotent', () => { + const t = Date.UTC(2026, 0, 1) + expect(snapToUtcMidnight(snapToUtcMidnight(t))).toBe(t) + }) +}) + +describe('createTimeScale', () => { + const origin = Date.UTC(2026, 0, 1) // 2026-01-01 UTC + + it('week zoom: pxPerDay = 14', () => { + const ts = createTimeScale('week', origin) + expect(ts.pxPerDay).toBe(14) + }) + + it('day/month/quarter zoom values match preset', () => { + expect(createTimeScale('day', origin).pxPerDay).toBe(32) + expect(createTimeScale('month', origin).pxPerDay).toBe(4) + expect(createTimeScale('quarter', origin).pxPerDay).toBe(1.5) + }) + + it('toX(origin) === 0', () => { + const ts = createTimeScale('week', origin) + expect(ts.toX(origin)).toBe(0) + }) + + it('toX(origin + 7d) === 7 * pxPerDay', () => { + const ts = createTimeScale('week', origin) + expect(ts.toX(origin + 7 * DAY_MS)).toBe(7 * 14) + }) + + it('fromX is inverse of toX (snapped)', () => { + const ts = createTimeScale('week', origin) + const t = origin + 5 * DAY_MS + expect(ts.fromX(ts.toX(t))).toBe(t) + }) + + it('week zoom emits weekly ticks aligned to Monday', () => { + const ts = createTimeScale('week', origin) + const ticks = ts.ticks([origin, origin + 30 * DAY_MS]) + expect(ticks.length).toBeGreaterThanOrEqual(4) + expect(ticks.length).toBeLessThanOrEqual(6) + // First tick is the first Monday on or after origin + expect(ticks[0].date).toBeGreaterThanOrEqual(origin) + expect(ticks[0].date).toBeLessThan(origin + 7 * DAY_MS) + // Every tick is on a Monday. + for (const t of ticks) { + expect(new Date(t.date).getUTCDay()).toBe(1) + } + expect(ticks.every(t => Number.isInteger(t.date))).toBe(true) + }) + + it('all tick dates are UTC midnights', () => { + const ts = createTimeScale('week', origin) + const ticks = ts.ticks([origin, origin + 30 * DAY_MS]) + for (const t of ticks) { + expect(snapToUtcMidnight(t.date)).toBe(t.date) + } + }) +}) From de2652ec68cd459917705fa358d16ab1e3ec962f Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:14 +0000 Subject: [PATCH 04/62] feat(tracker-resources): implement Gantt time-scale lib Signed-off-by: Michael Uray --- .../src/components/gantt/lib/time-scale.ts | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 plugins/tracker-resources/src/components/gantt/lib/time-scale.ts diff --git a/plugins/tracker-resources/src/components/gantt/lib/time-scale.ts b/plugins/tracker-resources/src/components/gantt/lib/time-scale.ts new file mode 100644 index 00000000000..da290d0389b --- /dev/null +++ b/plugins/tracker-resources/src/components/gantt/lib/time-scale.ts @@ -0,0 +1,131 @@ +// +// Copyright © 2026 Hardcore Engineering Inc. +// SPDX-License-Identifier: EPL-2.0 +// + +import { type Tick, type ZoomLevel } from './types' + +const DAY_MS = 86_400_000 + +const PX_PER_DAY: Record = { + day: 32, + week: 14, + month: 4, + quarter: 1.5 +} + +/** Snap any Timestamp (ms) to the start of its UTC day. */ +export function snapToUtcMidnight (t: number): number { + const d = new Date(t) + return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()) +} + +export interface TimeScale { + /** Pixel width of one calendar day at the current zoom. */ + pxPerDay: number + /** Convert a Timestamp to its X coordinate (relative to origin). */ + toX: (t: number) => number + /** Convert an X coordinate back to a snapped Timestamp. */ + fromX: (x: number) => number + /** Generate header ticks across [from, to]. */ + ticks: (range: [number, number]) => Tick[] +} + +export function createTimeScale (zoom: ZoomLevel, origin: number): TimeScale { + const pxPerDay = PX_PER_DAY[zoom] + const originSnapped = snapToUtcMidnight(origin) + + const toX = (t: number): number => ((t - originSnapped) / DAY_MS) * pxPerDay + const fromX = (x: number): number => snapToUtcMidnight(originSnapped + (x / pxPerDay) * DAY_MS) + + const ticks = (range: [number, number]): Tick[] => { + const [from, to] = range + const fromDay = snapToUtcMidnight(from) + const result: Tick[] = [] + let cursor = fromDay + + switch (zoom) { + case 'day': { + while (cursor <= to) { + const d = new Date(cursor) + const isMonday = d.getUTCDay() === 1 + result.push({ + date: cursor, + label: d.getUTCDate().toString(), + level: isMonday ? 'major' : 'minor' + }) + cursor += DAY_MS + } + break + } + case 'week': { + const d = new Date(cursor) + const dow = d.getUTCDay() // 0=Sun + const offsetToMonday = ((1 - dow) + 7) % 7 + cursor += offsetToMonday * DAY_MS + while (cursor <= to) { + const c = new Date(cursor) + const isFirstWeekOfMonth = c.getUTCDate() <= 7 + result.push({ + date: cursor, + label: `W${isoWeekNumber(c)}`, + level: isFirstWeekOfMonth ? 'major' : 'minor' + }) + cursor += 7 * DAY_MS + } + break + } + case 'month': { + const start = new Date(cursor) + let y = start.getUTCFullYear() + let m = start.getUTCMonth() + cursor = Date.UTC(y, m, 1) + while (cursor <= to) { + const c = new Date(cursor) + result.push({ + date: cursor, + label: c.toLocaleString(undefined, { month: 'short', timeZone: 'UTC' }), + level: c.getUTCMonth() === 0 ? 'major' : 'minor' + }) + m += 1 + if (m > 11) { m = 0; y += 1 } + cursor = Date.UTC(y, m, 1) + } + break + } + case 'quarter': { + const start = new Date(cursor) + let y = start.getUTCFullYear() + let q = Math.floor(start.getUTCMonth() / 3) + cursor = Date.UTC(y, q * 3, 1) + while (cursor <= to) { + const c = new Date(cursor) + const qNum = Math.floor(c.getUTCMonth() / 3) + 1 + result.push({ + date: cursor, + label: `Q${qNum} ${c.getUTCFullYear()}`, + level: qNum === 1 ? 'major' : 'minor' + }) + q += 1 + if (q > 3) { q = 0; y += 1 } + cursor = Date.UTC(y, q * 3, 1) + } + break + } + } + + return result + } + + return { pxPerDay, toX, fromX, ticks } +} + +/** ISO 8601 week number for a UTC date. */ +function isoWeekNumber (d: Date): number { + const target = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate())) + const dayNum = (target.getUTCDay() + 6) % 7 + target.setUTCDate(target.getUTCDate() - dayNum + 3) + const firstThursday = new Date(Date.UTC(target.getUTCFullYear(), 0, 4)) + const diff = target.getTime() - firstThursday.getTime() + return 1 + Math.round(diff / (7 * DAY_MS)) +} From 1ba2a158440318106fb3fa9f23dc8e230e80e890 Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:14 +0000 Subject: [PATCH 05/62] test(tracker-resources): add failing Gantt layout tests Signed-off-by: Michael Uray --- .../gantt/lib/__tests__/layout.test.ts | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 plugins/tracker-resources/src/components/gantt/lib/__tests__/layout.test.ts diff --git a/plugins/tracker-resources/src/components/gantt/lib/__tests__/layout.test.ts b/plugins/tracker-resources/src/components/gantt/lib/__tests__/layout.test.ts new file mode 100644 index 00000000000..a58bd4ad8b4 --- /dev/null +++ b/plugins/tracker-resources/src/components/gantt/lib/__tests__/layout.test.ts @@ -0,0 +1,99 @@ +// +// Copyright © 2026 Hardcore Engineering Inc. +// SPDX-License-Identifier: EPL-2.0 +// + +import type { Issue } from '@hcengineering/tracker' +import { buildLayout, filterVisibleRows } from '../layout' +import { type LayoutRow } from '../types' + +function fakeIssue (id: string, parentId?: string, hasChildren = false): Issue { + return { + _id: id as any, + _class: 'tracker:class:Issue' as any, + title: `Issue ${id}`, + space: 'project-1' as any, + component: null, + milestone: null, + startDate: null, + dueDate: null, + parents: parentId !== undefined ? [{ parentId: parentId as any }] : [], + childInfo: hasChildren ? [{ childId: 'fake-child' as any, count: 0, category: '' }] : [], + estimation: 0, + remainingTime: 0, + reportedTime: 0, + reports: 0, + subIssues: 0, + priority: 0, + status: '' as any, + attachedTo: 'tracker:ids:NoParent' as any + } as unknown as Issue +} + +const ROW_H = 28 + +describe('buildLayout (no grouping)', () => { + it('flattens a flat list of root issues', () => { + const issues = [fakeIssue('a'), fakeIssue('b')] + const rows = buildLayout(issues, 'none', ROW_H) + expect(rows).toHaveLength(2) + expect(rows[0].issue?._id).toBe('a') + expect(rows[1].issue?._id).toBe('b') + expect(rows[0].depth).toBe(0) + expect(rows[0].y).toBe(0) + expect(rows[1].y).toBe(ROW_H) + }) + + it('places children below parent with depth+1', () => { + const a = fakeIssue('a', undefined, true) + const child = fakeIssue('a.1', 'a') + const rows = buildLayout([a, child], 'none', ROW_H) + expect(rows.find(r => r.issue?._id === 'a.1')?.depth).toBe(1) + }) + + it('marks parent issues as summary rows', () => { + const a = fakeIssue('a', undefined, true) + const child = fakeIssue('a.1', 'a') + const rows = buildLayout([a, child], 'none', ROW_H) + const parentRow = rows.find(r => r.issue?._id === 'a')! + expect(parentRow.isSummary).toBe(true) + expect(rows.find(r => r.issue?._id === 'a.1')?.isSummary).toBe(false) + }) + + it('row Y coordinates are sequential multiples of rowHeight', () => { + const issues = [fakeIssue('a'), fakeIssue('b'), fakeIssue('c')] + const rows = buildLayout(issues, 'none', ROW_H) + expect(rows.map(r => r.y)).toEqual([0, ROW_H, 2 * ROW_H]) + }) +}) + +describe('filterVisibleRows', () => { + it('returns only rows whose Y range intersects the viewport (overscan=0)', () => { + const all: LayoutRow[] = [ + { kind: 'issue', y: 0, height: ROW_H, depth: 0, visible: true, issue: null, component: null, isSummary: false }, + { kind: 'issue', y: 100, height: ROW_H, depth: 0, visible: true, issue: null, component: null, isSummary: false }, + { kind: 'issue', y: 5000, height: ROW_H, depth: 0, visible: true, issue: null, component: null, isSummary: false } + ] + const visible = filterVisibleRows(all, 80, 60, 0) + expect(visible.map(r => r.y)).toEqual([100]) + }) + + it('default overscan brings adjacent rows into the visible set', () => { + const all: LayoutRow[] = [ + { kind: 'issue', y: 0, height: ROW_H, depth: 0, visible: true, issue: null, component: null, isSummary: false }, + { kind: 'issue', y: 100, height: ROW_H, depth: 0, visible: true, issue: null, component: null, isSummary: false }, + { kind: 'issue', y: 5000, height: ROW_H, depth: 0, visible: true, issue: null, component: null, isSummary: false } + ] + const visible = filterVisibleRows(all, 80, 60) + expect(visible.map(r => r.y).sort((a, b) => a - b)).toEqual([0, 100]) + }) + + it('honours an explicit overscan', () => { + const all: LayoutRow[] = [ + { kind: 'issue', y: 0, height: ROW_H, depth: 0, visible: true, issue: null, component: null, isSummary: false }, + { kind: 'issue', y: 1000, height: ROW_H, depth: 0, visible: true, issue: null, component: null, isSummary: false } + ] + const visible = filterVisibleRows(all, 950, 50, 200) + expect(visible.map(r => r.y)).toEqual([1000]) + }) +}) From 4ef672f6ab5225a55d452b20226290e412e43a34 Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:14 +0000 Subject: [PATCH 06/62] feat(tracker-resources): implement Gantt layout lib Signed-off-by: Michael Uray --- .../src/components/gantt/lib/layout.ts | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 plugins/tracker-resources/src/components/gantt/lib/layout.ts diff --git a/plugins/tracker-resources/src/components/gantt/lib/layout.ts b/plugins/tracker-resources/src/components/gantt/lib/layout.ts new file mode 100644 index 00000000000..48fa27a84a7 --- /dev/null +++ b/plugins/tracker-resources/src/components/gantt/lib/layout.ts @@ -0,0 +1,72 @@ +// +// Copyright © 2026 Hardcore Engineering Inc. +// SPDX-License-Identifier: EPL-2.0 +// + +import { type Issue } from '@hcengineering/tracker' +import { type LayoutRow } from './types' + +export type GroupBy = 'none' | 'component' | 'milestone' + +const DEFAULT_OVERSCAN_PX = 240 + +/** + * Flatten the issues array into rows ordered by (parent → child) DFS, + * computing y-coords from rowHeight. + */ +export function buildLayout (issues: Issue[], _group: GroupBy, rowHeight: number): LayoutRow[] { + const childrenOf = new Map() + const roots: Issue[] = [] + for (const i of issues) { + const parentId = i.parents?.[0]?.parentId + if (parentId !== undefined && parentId !== null) { + const list = childrenOf.get(parentId as unknown as string) ?? [] + list.push(i) + childrenOf.set(parentId as unknown as string, list) + } else { + roots.push(i) + } + } + + const rows: LayoutRow[] = [] + let y = 0 + + function emit (i: Issue, depth: number): void { + const kids = childrenOf.get(i._id as unknown as string) ?? [] + rows.push({ + kind: 'issue', + y, + height: rowHeight, + depth, + visible: true, + issue: i, + component: null, + isSummary: kids.length > 0 + }) + y += rowHeight + for (const c of kids) { + emit(c, depth + 1) + } + } + + for (const r of roots) { + emit(r, 0) + } + + return rows +} + +/** + * Return the subset of rows whose [y, y+height] intersects + * [viewportTop - overscan, viewportTop + viewportHeight + overscan]. + */ +export function filterVisibleRows ( + rows: LayoutRow[], + viewportTop: number, + viewportHeight: number, + overscan: number = DEFAULT_OVERSCAN_PX +): LayoutRow[] { + const min = viewportTop - overscan + const max = viewportTop + viewportHeight + overscan + return rows.filter(r => r.y + r.height >= min && r.y <= max) +} From e7e0472e171efd32850d2bae65c51a5c12221e7e Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:14 +0000 Subject: [PATCH 07/62] feat(tracker-resources): add GanttHeader.svelte Signed-off-by: Michael Uray --- .../src/components/gantt/GanttHeader.svelte | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 plugins/tracker-resources/src/components/gantt/GanttHeader.svelte diff --git a/plugins/tracker-resources/src/components/gantt/GanttHeader.svelte b/plugins/tracker-resources/src/components/gantt/GanttHeader.svelte new file mode 100644 index 00000000000..eb4d4245ff6 --- /dev/null +++ b/plugins/tracker-resources/src/components/gantt/GanttHeader.svelte @@ -0,0 +1,63 @@ + + + + + {#each ticks as tick (tick.date)} + {@const x = timeScale.toX(tick.date)} + + + {tick.label} + + {/each} + + + From 2173ab466159d5d66fb28997eb2ffabc617860d6 Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:14 +0000 Subject: [PATCH 08/62] feat(tracker-resources): add GanttBar.svelte (regular + summary claws) Signed-off-by: Michael Uray --- .../src/components/gantt/GanttBar.svelte | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 plugins/tracker-resources/src/components/gantt/GanttBar.svelte diff --git a/plugins/tracker-resources/src/components/gantt/GanttBar.svelte b/plugins/tracker-resources/src/components/gantt/GanttBar.svelte new file mode 100644 index 00000000000..20f23a11029 --- /dev/null +++ b/plugins/tracker-resources/src/components/gantt/GanttBar.svelte @@ -0,0 +1,73 @@ + + + +{#if visible} + {@const barY = row.y + 6} + {@const barH = row.height - 12} + {#if isSummary} + + + + + {:else} + + {tooltipText} + {/if} +{/if} + + From af2d60af64563e09620f3183b475f6628efed8ee Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:14 +0000 Subject: [PATCH 09/62] feat(tracker-resources): add GanttTodayMarker.svelte Signed-off-by: Michael Uray --- .../components/gantt/GanttTodayMarker.svelte | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 plugins/tracker-resources/src/components/gantt/GanttTodayMarker.svelte diff --git a/plugins/tracker-resources/src/components/gantt/GanttTodayMarker.svelte b/plugins/tracker-resources/src/components/gantt/GanttTodayMarker.svelte new file mode 100644 index 00000000000..8a88f6789f7 --- /dev/null +++ b/plugins/tracker-resources/src/components/gantt/GanttTodayMarker.svelte @@ -0,0 +1,34 @@ + + + +{#if visible} + +{/if} + + From 84355bdaf35979693450ae6bd0f0964b7d5db8aa Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:14 +0000 Subject: [PATCH 10/62] feat(tracker-resources): add GanttMilestoneFlag.svelte Signed-off-by: Michael Uray --- .../gantt/GanttMilestoneFlag.svelte | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 plugins/tracker-resources/src/components/gantt/GanttMilestoneFlag.svelte diff --git a/plugins/tracker-resources/src/components/gantt/GanttMilestoneFlag.svelte b/plugins/tracker-resources/src/components/gantt/GanttMilestoneFlag.svelte new file mode 100644 index 00000000000..1e5539fbd56 --- /dev/null +++ b/plugins/tracker-resources/src/components/gantt/GanttMilestoneFlag.svelte @@ -0,0 +1,53 @@ + + + +{#if visible} + + + {milestone.label} + + + {milestone.label} + +{/if} + + From cc376787511a3ee49cc1bec6546ab30843dd6fba Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:14 +0000 Subject: [PATCH 11/62] feat(tracker-resources): add GanttCanvas.svelte Signed-off-by: Michael Uray --- .../src/components/gantt/GanttCanvas.svelte | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte diff --git a/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte b/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte new file mode 100644 index 00000000000..12f0289b591 --- /dev/null +++ b/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte @@ -0,0 +1,75 @@ + + + + + + {#each visibleRows as row (rowKey(row))} + {#if row.issue !== null} + + {/if} + {/each} + + + + {#each milestones as ms (ms._id)} + + {/each} + + + + + + From 528eac42bba8ef11b786758fd6a92582e2706b2a Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:14 +0000 Subject: [PATCH 12/62] feat(tracker-resources): add GanttSidebar.svelte Signed-off-by: Michael Uray --- .../src/components/gantt/GanttSidebar.svelte | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte diff --git a/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte b/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte new file mode 100644 index 00000000000..8644b47e1df --- /dev/null +++ b/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte @@ -0,0 +1,57 @@ + + + +
+ +
+ + From d257021c5dd7ff32ba776590a42560abedc6b43c Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:14 +0000 Subject: [PATCH 13/62] feat(tracker-resources): add GanttToolbar.svelte (zoom buttons) Signed-off-by: Michael Uray --- .../src/components/gantt/GanttToolbar.svelte | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 plugins/tracker-resources/src/components/gantt/GanttToolbar.svelte diff --git a/plugins/tracker-resources/src/components/gantt/GanttToolbar.svelte b/plugins/tracker-resources/src/components/gantt/GanttToolbar.svelte new file mode 100644 index 00000000000..8589cdd6af5 --- /dev/null +++ b/plugins/tracker-resources/src/components/gantt/GanttToolbar.svelte @@ -0,0 +1,46 @@ + + + +
+ {#each order as z} +
+ + From 1dfac462ff99d0277f5479fd258b932286433e13 Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:15 +0000 Subject: [PATCH 14/62] feat(tracker-resources): GanttView wires Sidebar+Canvas+Toolbar with reactive queries PR 2 read-only Gantt is now end-to-end functional: - Two reactive queries (issues, milestones) - buildLayout(issues) -> rows with depth + isSummary - createTimeScale(zoom, dateRange.from) -> date<->px math - Summary ranges computed per parent issue from children's date span - Local zoom state (Day/Week/Month/Quarter) - no ViewletPreference plumbing - Horizontal scroll via canvas-scroller; vertical scroll moves Sidebar via translate Signed-off-by: Michael Uray --- .../src/components/gantt/GanttView.svelte | 202 ++++++++++++++++-- 1 file changed, 183 insertions(+), 19 deletions(-) diff --git a/plugins/tracker-resources/src/components/gantt/GanttView.svelte b/plugins/tracker-resources/src/components/gantt/GanttView.svelte index 5a951fd57ab..a682fd03fff 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttView.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttView.svelte @@ -1,41 +1,205 @@ -
-
-
+
+ + {#if loading} + + {:else} +
+ +
+
+ + +
+
+
+ {/if}
From 787f2ae6c42b7a34cea28d1e0a385010d24967c3 Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:15 +0000 Subject: [PATCH 15/62] - layout.ts: orphan child issues (parent filtered out) now emit as roots - viewlets.ts: register IssueGantt AFTER IssueKanban so List stays default - viewlets.ts: drop showColorsViewOption (canvas does not honour it yet) - GanttBar.svelte: normalise reversed startDate>dueDate ranges UX: - GanttSidebar adds Title column with sticky two-column header - Sticky time-scale header decoupled from milestone strip (layout fix) - Per-row jump-to-bar arrow (Plane-style) when bar is offscreen - ResizeObserver initialises viewport on mount and on resize Milestones as Gantt rows + collapse: - Milestones group their issues as nested children (depth+1) - Collapsible toggle per parent row, local collapsedIds Set - Milestone summary bar uses existing GanttBar with aggregated range Icon: - Register tracker.icon.Gantt to #timeline svg (Gantt pictogram) Tests: 25/25 jest pass; svelte-check 0 errors. Signed-off-by: Michael Uray --- models/tracker/src/viewlets.ts | 42 ++-- plugins/tracker-assets/src/index.ts | 3 +- .../src/components/gantt/GanttBar.svelte | 16 +- .../src/components/gantt/GanttCanvas.svelte | 31 ++- .../src/components/gantt/GanttSidebar.svelte | 205 ++++++++++++++++-- .../src/components/gantt/GanttView.svelte | 116 ++++++++-- .../gantt/lib/__tests__/layout.test.ts | 138 ++++++++++-- .../src/components/gantt/lib/layout.ts | 120 ++++++++-- .../src/components/gantt/lib/types.ts | 20 +- plugins/tracker/src/index.ts | 1 + 10 files changed, 586 insertions(+), 106 deletions(-) diff --git a/models/tracker/src/viewlets.ts b/models/tracker/src/viewlets.ts index 194a5a7554d..ce6e058e535 100644 --- a/models/tracker/src/viewlets.ts +++ b/models/tracker/src/viewlets.ts @@ -213,10 +213,10 @@ export function issueConfig ( } export function ganttViewOptions (): ViewOptionsModel { - // PR 2 ships a minimal read-only Gantt. Group-by / dropdown ViewOptions - // are intentionally NOT advertised here — the canvas does not honour them - // yet. They will be added in PR 3 alongside drag/edit + Component swimlanes - // so users never see options that have no effect. + // PR 2 ships a minimal read-only Gantt. Group-by, "Show colors" and other + // dropdown ViewOptions are intentionally NOT advertised — the canvas does + // not honour them yet. They will be added in PR 3 alongside drag/edit + + // Component swimlanes so users never see options that have no effect. return { groupBy: [], orderBy: [ @@ -224,7 +224,7 @@ export function ganttViewOptions (): ViewOptionsModel { ['rank', SortingOrder.Ascending], ['dueDate', SortingOrder.Ascending] ], - other: [showColorsViewOption] + other: [] } } @@ -253,25 +253,12 @@ export function defineViewlets (builder: Builder): void { core.space.Model, { label: tracker.string.Gantt, - icon: tracker.icon.Issues, + icon: tracker.icon.Gantt, component: tracker.component.GanttView }, tracker.viewlet.Gantt ) - builder.createDoc( - view.class.Viewlet, - core.space.Model, - { - attachTo: tracker.class.Issue, - descriptor: tracker.viewlet.Gantt, - viewOptions: ganttViewOptions(), - configOptions: { strict: true, hiddenKeys: ['title'] }, - config: ganttConfig() - }, - tracker.viewlet.IssueGantt - ) - builder.createDoc( view.class.Viewlet, core.space.Model, @@ -549,6 +536,23 @@ export function defineViewlets (builder: Builder): void { tracker.viewlet.IssueKanban ) + // Gantt is registered AFTER List + Kanban so List remains the default + // viewlet (ViewletSelector falls back to viewlets[0] when no preference + // is saved). Putting Gantt last avoids surprising users with an empty + // canvas on first visit. + builder.createDoc( + view.class.Viewlet, + core.space.Model, + { + attachTo: tracker.class.Issue, + descriptor: tracker.viewlet.Gantt, + viewOptions: ganttViewOptions(), + configOptions: { strict: true, hiddenKeys: ['title'] }, + config: ganttConfig() + }, + tracker.viewlet.IssueGantt + ) + const componentListViewOptions: ViewOptionsModel = { groupBy: ['lead', 'createdBy', 'modifiedBy'], orderBy: [ diff --git a/plugins/tracker-assets/src/index.ts b/plugins/tracker-assets/src/index.ts index 07aaf1badab..4c64fa48f9e 100644 --- a/plugins/tracker-assets/src/index.ts +++ b/plugins/tracker-assets/src/index.ts @@ -64,5 +64,6 @@ loadMetadata(tracker.icon, { CopyBranch: `${icons}#copyBranch`, Duplicate: `${icons}#duplicate`, TimeReport: `${icons}#timeReport`, - Estimation: `${icons}#estimation` + Estimation: `${icons}#estimation`, + Gantt: `${icons}#timeline` }) diff --git a/plugins/tracker-resources/src/components/gantt/GanttBar.svelte b/plugins/tracker-resources/src/components/gantt/GanttBar.svelte index 20f23a11029..f179d163c18 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttBar.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttBar.svelte @@ -3,10 +3,11 @@ // SPDX-License-Identifier: EPL-2.0 -->
+
@@ -37,21 +121,110 @@ overflow: hidden; background: var(--theme-comp-header-color); } + .sidebar-header { + display: flex; + align-items: center; + gap: 8px; + padding: 0 8px; + border-bottom: 1px solid var(--theme-divider-color); + background: var(--theme-comp-header-color); + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + color: var(--theme-darker-color); + letter-spacing: 0.05em; + box-sizing: border-box; + } + .col-toggle { + flex: 0 0 18px; + display: flex; + align-items: center; + justify-content: center; + } + .col-id { + flex: 0 0 88px; + } + .col-title { + flex: 1 1 auto; + } + .col-jump { + flex: 0 0 28px; + } .sidebar-rows { will-change: transform; } .sidebar-row { display: flex; align-items: center; + gap: 8px; padding-right: 8px; border-bottom: 1px solid var(--theme-divider-color); color: var(--theme-content-color); font-size: 13px; overflow: hidden; - text-overflow: ellipsis; white-space: nowrap; + box-sizing: border-box; + } + .cell-id { + flex: 0 0 88px; + overflow: hidden; + text-overflow: ellipsis; + } + .cell-id.ms-icon { + text-align: center; + color: var(--theme-state-info-color, #6366f1); + font-size: 14px; + } + .cell-title { + flex: 1 1 auto; + overflow: hidden; + text-overflow: ellipsis; + } + .cell-jump { + flex: 0 0 28px; + display: flex; + align-items: center; + justify-content: center; + } + .toggle-btn { + width: 18px; + height: 18px; + padding: 0; + border: none; + background: transparent; + color: var(--theme-darker-color); + font-size: 10px; + line-height: 1; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + } + .toggle-btn:hover { + color: var(--theme-content-color); + } + .jump-btn { + width: 22px; + height: 22px; + padding: 0; + border: 1px solid var(--theme-button-border); + border-radius: 3px; + background: var(--theme-button-default); + color: var(--theme-content-color); + font-size: 13px; + line-height: 1; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + } + .jump-btn:hover { + filter: brightness(1.1); } .sidebar-row.summary { font-weight: 600; } + .sidebar-row.milestone { + background: color-mix(in srgb, var(--theme-state-info-color, #6366f1) 6%, transparent); + } diff --git a/plugins/tracker-resources/src/components/gantt/GanttView.svelte b/plugins/tracker-resources/src/components/gantt/GanttView.svelte index a682fd03fff..de1a0690842 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttView.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttView.svelte @@ -8,6 +8,7 @@ import { type Issue, type Milestone } from '@hcengineering/tracker' import { Loading } from '@hcengineering/ui' import { type Viewlet, type ViewOptions } from '@hcengineering/view' + import { onDestroy, onMount } from 'svelte' import tracker from '../../plugin' import GanttCanvas from './GanttCanvas.svelte' import GanttHeader from './GanttHeader.svelte' @@ -24,8 +25,9 @@ export let viewOptions: ViewOptions const ROW_HEIGHT = 28 - const SIDEBAR_WIDTH = 320 - const HEADER_HEIGHT = 32 + const SIDEBAR_WIDTH = 360 + const HEADER_HEIGHT = 56 + const MILESTONE_STRIP_HEIGHT = 22 let issues: Issue[] = [] let milestones: Milestone[] = [] @@ -100,9 +102,26 @@ } $: timeScale = createTimeScale(zoom, dateRange.from) - $: rows = buildLayout(issues, 'none', ROW_HEIGHT) + $: milestoneMarkers = milestones.map(m => ({ + _id: m._id, + label: m.label, + startDate: (m as Milestone & { startDate: number | null }).startDate ?? null, + targetDate: m.targetDate + })) + + // Set of row ids currently collapsed (children hidden). Local state in PR 2. + let collapsedIds: Set = new Set() + function onToggle (e: CustomEvent<{ id: string }>): void { + const next = new Set(collapsedIds) + if (next.has(e.detail.id)) next.delete(e.detail.id) + else next.add(e.detail.id) + collapsedIds = next + } + + $: rows = buildLayout(issues, milestoneMarkers, 'none', { rowHeight: ROW_HEIGHT, collapsedIds }) - // Compute summary ranges for parent issues — aggregate of children's startDate/dueDate + // Compute summary ranges for parent issues + milestones — aggregate of children's + // startDate/dueDate. $: summaryRanges = computeSummaryRanges(rows, issues) function computeSummaryRanges ( @@ -111,6 +130,7 @@ ): Map { const result = new Map() const childrenOf = new Map() + const issuesByMilestone = new Map() for (const i of allIssues) { const p = i.parents?.[0]?.parentId if (p !== undefined && p !== null) { @@ -119,9 +139,27 @@ list.push(i) childrenOf.set(k, list) } + const ms = (i as unknown as { milestone?: string | null }).milestone + if (ms != null) { + const list = issuesByMilestone.get(ms) ?? [] + list.push(i) + issuesByMilestone.set(ms, list) + } } for (const row of layoutRows) { - if (!row.isSummary || row.issue === null) continue + if (!row.isSummary) continue + if (row.kind === 'milestone' && row.milestone !== null) { + const msId = row.milestone._id as unknown as string + const kids = issuesByMilestone.get(msId) ?? [] + const starts = kids.map(k => k.startDate).filter((v): v is number => v !== null && v !== undefined) + const dues = kids.map(k => k.dueDate).filter((v): v is number => v !== null && v !== undefined) + result.set(row.id, { + startDate: starts.length > 0 ? Math.min(...starts) : null, + dueDate: dues.length > 0 ? Math.max(...dues) : null + }) + continue + } + if (row.issue === null) continue const id = (row.issue as Issue)._id as unknown as string const kids = childrenOf.get(id) ?? [] const starts = kids.map(k => k.startDate).filter((v): v is number => v !== null && v !== undefined) @@ -134,13 +172,6 @@ return result } - $: milestoneMarkers = milestones.map(m => ({ - _id: m._id, - label: m.label, - startDate: (m as Milestone & { startDate: number | null }).startDate ?? null, - targetDate: m.targetDate - })) - $: totalCanvasWidth = Math.max(viewportWidth(), timeScale.toX(dateRange.to) - timeScale.toX(dateRange.from)) function viewportWidth (): number { @@ -155,6 +186,34 @@ viewportHeight = t.clientHeight } + function onJump (e: CustomEvent<{ x: number }>): void { + if (scrollerEl !== undefined) { + scrollerEl.scrollTo({ left: Math.max(0, e.detail.x - 80), behavior: 'smooth' }) + } + } + + // Initialise viewport dimensions after mount and on resize so jump-buttons / + // virtualisation start with correct values instead of waiting for the first + // user-driven scroll event. + let resizeObs: ResizeObserver | undefined + function syncViewport (): void { + if (scrollerEl === undefined) return + canvasViewportLeft = scrollerEl.scrollLeft + canvasViewportWidth = scrollerEl.clientWidth + scrollTop = scrollerEl.scrollTop + viewportHeight = scrollerEl.clientHeight + } + onMount(() => { + syncViewport() + if (typeof ResizeObserver !== 'undefined' && scrollerEl !== undefined) { + resizeObs = new ResizeObserver(() => syncViewport()) + resizeObs.observe(scrollerEl) + } + }) + onDestroy(() => { + resizeObs?.disconnect() + }) + $: viewport = { left: canvasViewportLeft, right: canvasViewportLeft + canvasViewportWidth } $: loading = loadingIssues || loadingMilestones @@ -166,10 +225,23 @@ {:else}
- +
-
- +
+
+ +
@@ -197,9 +270,22 @@ display: flex; flex: 1 1 auto; overflow: hidden; + min-height: 0; } .canvas-scroller { flex: 1 1 auto; overflow: auto; + min-width: 0; + min-height: 0; + } + .canvas-stack { + position: relative; + } + .header-sticky { + position: sticky; + top: 0; + z-index: 2; + background: var(--theme-comp-header-color); + border-bottom: 1px solid var(--theme-divider-color); } diff --git a/plugins/tracker-resources/src/components/gantt/lib/__tests__/layout.test.ts b/plugins/tracker-resources/src/components/gantt/lib/__tests__/layout.test.ts index a58bd4ad8b4..4e18eb4e931 100644 --- a/plugins/tracker-resources/src/components/gantt/lib/__tests__/layout.test.ts +++ b/plugins/tracker-resources/src/components/gantt/lib/__tests__/layout.test.ts @@ -5,16 +5,16 @@ import type { Issue } from '@hcengineering/tracker' import { buildLayout, filterVisibleRows } from '../layout' -import { type LayoutRow } from '../types' +import { type LayoutRow, type MilestoneMarker } from '../types' -function fakeIssue (id: string, parentId?: string, hasChildren = false): Issue { +function fakeIssue (id: string, parentId?: string, hasChildren = false, milestone?: string): Issue { return { _id: id as any, _class: 'tracker:class:Issue' as any, title: `Issue ${id}`, space: 'project-1' as any, component: null, - milestone: null, + milestone: milestone ?? null, startDate: null, dueDate: null, parents: parentId !== undefined ? [{ parentId: parentId as any }] : [], @@ -30,12 +30,16 @@ function fakeIssue (id: string, parentId?: string, hasChildren = false): Issue { } as unknown as Issue } +function fakeMilestone (id: string, label = `MS ${id}`): MilestoneMarker { + return { _id: id as any, label, startDate: null, targetDate: 1_700_000_000_000 } +} + const ROW_H = 28 describe('buildLayout (no grouping)', () => { it('flattens a flat list of root issues', () => { const issues = [fakeIssue('a'), fakeIssue('b')] - const rows = buildLayout(issues, 'none', ROW_H) + const rows = buildLayout(issues, [], 'none', ROW_H) expect(rows).toHaveLength(2) expect(rows[0].issue?._id).toBe('a') expect(rows[1].issue?._id).toBe('b') @@ -47,14 +51,14 @@ describe('buildLayout (no grouping)', () => { it('places children below parent with depth+1', () => { const a = fakeIssue('a', undefined, true) const child = fakeIssue('a.1', 'a') - const rows = buildLayout([a, child], 'none', ROW_H) + const rows = buildLayout([a, child], [], 'none', ROW_H) expect(rows.find(r => r.issue?._id === 'a.1')?.depth).toBe(1) }) it('marks parent issues as summary rows', () => { const a = fakeIssue('a', undefined, true) const child = fakeIssue('a.1', 'a') - const rows = buildLayout([a, child], 'none', ROW_H) + const rows = buildLayout([a, child], [], 'none', ROW_H) const parentRow = rows.find(r => r.issue?._id === 'a')! expect(parentRow.isSummary).toBe(true) expect(rows.find(r => r.issue?._id === 'a.1')?.isSummary).toBe(false) @@ -62,37 +66,129 @@ describe('buildLayout (no grouping)', () => { it('row Y coordinates are sequential multiples of rowHeight', () => { const issues = [fakeIssue('a'), fakeIssue('b'), fakeIssue('c')] - const rows = buildLayout(issues, 'none', ROW_H) + const rows = buildLayout(issues, [], 'none', ROW_H) expect(rows.map(r => r.y)).toEqual([0, ROW_H, 2 * ROW_H]) }) + + it('emits orphan children as roots when their parent is not in the input set', () => { + const a = fakeIssue('a', 'p') + const b = fakeIssue('b', 'p') + const rows = buildLayout([a, b], [], 'none', ROW_H) + expect(rows.map(r => r.issue?._id)).toEqual(['a', 'b']) + expect(rows.every(r => r.depth === 0)).toBe(true) + }) + + it('keeps real parent/child nesting when parent IS in the input set', () => { + const parent = fakeIssue('p', undefined, true) + const childA = fakeIssue('a', 'p') + const childB = fakeIssue('b', 'p') + const rows = buildLayout([parent, childA, childB], [], 'none', ROW_H) + expect(rows.map(r => r.issue?._id)).toEqual(['p', 'a', 'b']) + expect(rows[0].depth).toBe(0) + expect(rows[1].depth).toBe(1) + expect(rows[2].depth).toBe(1) + }) +}) + +describe('buildLayout — milestones', () => { + it('emits milestone parent rows above their issues', () => { + const ms = fakeMilestone('m1') + const i1 = fakeIssue('a', undefined, false, 'm1') + const i2 = fakeIssue('b', undefined, false, 'm1') + const rows = buildLayout([i1, i2], [ms], 'none', ROW_H) + expect(rows.map(r => r.id)).toEqual(['milestone:m1', 'issue:a', 'issue:b']) + expect(rows[0].kind).toBe('milestone') + expect(rows[0].milestone?.label).toBe('MS m1') + expect(rows[1].depth).toBe(1) + expect(rows[2].depth).toBe(1) + }) + + it('places issues without a known milestone as top-level roots', () => { + const i1 = fakeIssue('a', undefined, false, 'unknown-ms') + const i2 = fakeIssue('b') + const rows = buildLayout([i1, i2], [], 'none', ROW_H) + expect(rows.map(r => r.id)).toEqual(['issue:a', 'issue:b']) + expect(rows.every(r => r.depth === 0)).toBe(true) + }) + + it('mixes milestone groups with bare issues (milestones first)', () => { + const ms = fakeMilestone('m1') + const inGroup = fakeIssue('a', undefined, false, 'm1') + const ungrouped = fakeIssue('b') + const rows = buildLayout([inGroup, ungrouped], [ms], 'none', ROW_H) + expect(rows.map(r => r.id)).toEqual(['milestone:m1', 'issue:a', 'issue:b']) + }) +}) + +describe('buildLayout — collapse', () => { + it('hides children of a collapsed milestone row', () => { + const ms = fakeMilestone('m1') + const i1 = fakeIssue('a', undefined, false, 'm1') + const i2 = fakeIssue('b', undefined, false, 'm1') + const rows = buildLayout([i1, i2], [ms], 'none', { + rowHeight: ROW_H, + collapsedIds: new Set(['milestone:m1']) + }) + expect(rows.map(r => r.id)).toEqual(['milestone:m1']) + expect(rows[0].collapsed).toBe(true) + }) + + it('hides sub-issues of a collapsed parent issue', () => { + const parent = fakeIssue('p', undefined, true) + const child = fakeIssue('a', 'p') + const rows = buildLayout([parent, child], [], 'none', { + rowHeight: ROW_H, + collapsedIds: new Set(['issue:p']) + }) + expect(rows.map(r => r.id)).toEqual(['issue:p']) + expect(rows[0].collapsed).toBe(true) + expect(rows[0].collapsible).toBe(true) + }) + + it('expanded parents render their children', () => { + const parent = fakeIssue('p', undefined, true) + const child = fakeIssue('a', 'p') + const rows = buildLayout([parent, child], [], 'none', { + rowHeight: ROW_H, + collapsedIds: new Set() + }) + expect(rows.map(r => r.id)).toEqual(['issue:p', 'issue:a']) + expect(rows[0].collapsed).toBe(false) + }) }) describe('filterVisibleRows', () => { + function row (y: number): LayoutRow { + return { + kind: 'issue', + id: `r-${y}`, + y, + height: ROW_H, + depth: 0, + visible: true, + issue: null, + milestone: null, + component: null, + isSummary: false, + collapsible: false, + collapsed: false + } + } + it('returns only rows whose Y range intersects the viewport (overscan=0)', () => { - const all: LayoutRow[] = [ - { kind: 'issue', y: 0, height: ROW_H, depth: 0, visible: true, issue: null, component: null, isSummary: false }, - { kind: 'issue', y: 100, height: ROW_H, depth: 0, visible: true, issue: null, component: null, isSummary: false }, - { kind: 'issue', y: 5000, height: ROW_H, depth: 0, visible: true, issue: null, component: null, isSummary: false } - ] + const all: LayoutRow[] = [row(0), row(100), row(5000)] const visible = filterVisibleRows(all, 80, 60, 0) expect(visible.map(r => r.y)).toEqual([100]) }) it('default overscan brings adjacent rows into the visible set', () => { - const all: LayoutRow[] = [ - { kind: 'issue', y: 0, height: ROW_H, depth: 0, visible: true, issue: null, component: null, isSummary: false }, - { kind: 'issue', y: 100, height: ROW_H, depth: 0, visible: true, issue: null, component: null, isSummary: false }, - { kind: 'issue', y: 5000, height: ROW_H, depth: 0, visible: true, issue: null, component: null, isSummary: false } - ] + const all: LayoutRow[] = [row(0), row(100), row(5000)] const visible = filterVisibleRows(all, 80, 60) expect(visible.map(r => r.y).sort((a, b) => a - b)).toEqual([0, 100]) }) it('honours an explicit overscan', () => { - const all: LayoutRow[] = [ - { kind: 'issue', y: 0, height: ROW_H, depth: 0, visible: true, issue: null, component: null, isSummary: false }, - { kind: 'issue', y: 1000, height: ROW_H, depth: 0, visible: true, issue: null, component: null, isSummary: false } - ] + const all: LayoutRow[] = [row(0), row(1000)] const visible = filterVisibleRows(all, 950, 50, 200) expect(visible.map(r => r.y)).toEqual([1000]) }) diff --git a/plugins/tracker-resources/src/components/gantt/lib/layout.ts b/plugins/tracker-resources/src/components/gantt/lib/layout.ts index 48fa27a84a7..dbf490dc7a7 100644 --- a/plugins/tracker-resources/src/components/gantt/lib/layout.ts +++ b/plugins/tracker-resources/src/components/gantt/lib/layout.ts @@ -4,55 +4,137 @@ // import { type Issue } from '@hcengineering/tracker' -import { type LayoutRow } from './types' +import { type LayoutRow, type MilestoneMarker } from './types' export type GroupBy = 'none' | 'component' | 'milestone' const DEFAULT_OVERSCAN_PX = 240 +/** Stable id used for keyed iteration AND collapse-state lookup. */ +export function rowId (row: LayoutRow): string { + return row.id +} + +export interface BuildLayoutOptions { + rowHeight: number + /** Set of row ids that are currently collapsed (children hidden). */ + collapsedIds?: Set +} + /** - * Flatten the issues array into rows ordered by (parent → child) DFS, - * computing y-coords from rowHeight. + * Build the flattened row layout. + * + * Hierarchy from top to bottom: + * Milestone-row (if any issues belong to that milestone) + * └── Issue-root + * └── Issue-child (sub-issue) + * + * Issues without a milestone are emitted as roots after the milestone groups. + * Issues whose parent is filtered out are promoted to roots so they don't + * silently disappear from the Gantt. */ -export function buildLayout (issues: Issue[], _group: GroupBy, rowHeight: number): LayoutRow[] { - const childrenOf = new Map() - const roots: Issue[] = [] +export function buildLayout ( + issues: Issue[], + milestones: MilestoneMarker[], + _group: GroupBy, + rowHeightOrOpts: number | BuildLayoutOptions +): LayoutRow[] { + const opts: BuildLayoutOptions = + typeof rowHeightOrOpts === 'number' ? { rowHeight: rowHeightOrOpts } : rowHeightOrOpts + const rowHeight = opts.rowHeight + const collapsedIds = opts.collapsedIds ?? new Set() + + // 1) Build issue parent/child map, dropping orphan parent refs. + const visibleIssueIds = new Set(issues.map(i => i._id as unknown as string)) + const issueChildrenOf = new Map() + const issueRoots: Issue[] = [] for (const i of issues) { - const parentId = i.parents?.[0]?.parentId - if (parentId !== undefined && parentId !== null) { - const list = childrenOf.get(parentId as unknown as string) ?? [] + const parentId = i.parents?.[0]?.parentId as unknown as string | undefined + if (parentId != null && visibleIssueIds.has(parentId)) { + const list = issueChildrenOf.get(parentId) ?? [] list.push(i) - childrenOf.set(parentId as unknown as string, list) + issueChildrenOf.set(parentId, list) + } else { + issueRoots.push(i) + } + } + + // 2) Group root-issues by milestone. + const milestoneById = new Map() + for (const m of milestones) { + milestoneById.set(m._id as unknown as string, m) + } + const issuesByMilestone = new Map() + const issuesWithoutMilestone: Issue[] = [] + for (const root of issueRoots) { + const ms = (root as unknown as { milestone?: string | null }).milestone + if (ms != null && milestoneById.has(ms)) { + const list = issuesByMilestone.get(ms) ?? [] + list.push(root) + issuesByMilestone.set(ms, list) } else { - roots.push(i) + issuesWithoutMilestone.push(root) } } const rows: LayoutRow[] = [] let y = 0 - function emit (i: Issue, depth: number): void { - const kids = childrenOf.get(i._id as unknown as string) ?? [] + function emitIssue (issue: Issue, depth: number): void { + const issueId = issue._id as unknown as string + const kids = issueChildrenOf.get(issueId) ?? [] + const id = `issue:${issueId}` + const collapsible = kids.length > 0 + const collapsed = collapsedIds.has(id) rows.push({ kind: 'issue', + id, y, height: rowHeight, depth, visible: true, - issue: i, + issue, + milestone: null, component: null, - isSummary: kids.length > 0 + isSummary: kids.length > 0, + collapsible, + collapsed }) y += rowHeight - for (const c of kids) { - emit(c, depth + 1) + if (!collapsed) { + for (const c of kids) emitIssue(c, depth + 1) } } - for (const r of roots) { - emit(r, 0) + // 3a) Milestone groups first. + for (const [msId, msIssues] of issuesByMilestone) { + const ms = milestoneById.get(msId) + if (ms === undefined) continue + const id = `milestone:${msId}` + const collapsed = collapsedIds.has(id) + rows.push({ + kind: 'milestone', + id, + y, + height: rowHeight, + depth: 0, + visible: true, + issue: null, + milestone: ms, + component: null, + isSummary: true, + collapsible: true, + collapsed + }) + y += rowHeight + if (!collapsed) { + for (const i of msIssues) emitIssue(i, 1) + } } + // 3b) Issues without milestone. + for (const r of issuesWithoutMilestone) emitIssue(r, 0) + return rows } diff --git a/plugins/tracker-resources/src/components/gantt/lib/types.ts b/plugins/tracker-resources/src/components/gantt/lib/types.ts index 485ecabf5ae..8c2b8e2a1a0 100644 --- a/plugins/tracker-resources/src/components/gantt/lib/types.ts +++ b/plugins/tracker-resources/src/components/gantt/lib/types.ts @@ -16,23 +16,31 @@ export interface Tick { level: 'major' | 'minor' // major ticks render thicker + with text label } -/** A row in the flattened layout. May be an issue or a component-swimlane header. */ +/** A row in the flattened layout. May be an issue, milestone, or swimlane header. */ export interface LayoutRow { - kind: 'issue' | 'component-swimlane' + kind: 'issue' | 'milestone' | 'component-swimlane' + /** Stable key for keyed each-blocks and the collapsed-set. */ + id: string /** Y-coord top-edge of the row in canvas pixels. */ y: number /** Row height in pixels. */ height: number - /** Tree depth — 0 for top-level issues. */ + /** Tree depth — 0 for top-level rows. */ depth: number /** Whether this row is currently rendered (vs virtually skipped). */ visible: boolean - /** The issue this row represents — null for swimlane headers. */ + /** The issue this row represents — null for milestone/swimlane rows. */ issue: Issue | null - /** The component this swimlane represents — null for issue rows. */ + /** The milestone this row represents — null for issue/swimlane rows. */ + milestone: MilestoneMarker | null + /** The component this swimlane represents — null otherwise. */ component: Ref | null - /** True iff this issue has children (renders as summary "claw" bar). */ + /** True iff this row has children (renders as summary "claw" bar). */ isSummary: boolean + /** True iff this row has children and the user can collapse/expand it. */ + collapsible: boolean + /** True iff currently collapsed (children hidden). */ + collapsed: boolean } /** Cached aggregate dates of a parent issue's children, for summary-bar rendering. */ diff --git a/plugins/tracker/src/index.ts b/plugins/tracker/src/index.ts index ae4ac58806f..da06d52bd5c 100644 --- a/plugins/tracker/src/index.ts +++ b/plugins/tracker/src/index.ts @@ -496,6 +496,7 @@ const pluginState = plugin(trackerId, { TimeReport: '' as Asset, Estimation: '' as Asset, + Gantt: '' as Asset, // Project icons Home: '' as Asset, From d100e2a0d63a6539a9f230e3e7b0d790f46300bb Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:15 +0000 Subject: [PATCH 16/62] =?UTF-8?q?Toolbar=20(replaces=20previous=20floating?= =?UTF-8?q?=20zoom):=20-=20Visible=20top=20row=20with=20[=C2=AB]=20[Today]?= =?UTF-8?q?=20[=C2=BB]=20|=20Day=20Week=20Month=20Quarter=20|=20=E2=9A=99?= =?UTF-8?q?=20-=20Today=20scrolls=20to=20current=20date,=20prev/next=20pag?= =?UTF-8?q?e-scroll=20by=2080%=20viewport=20-=20Settings=20popover=20toggl?= =?UTF-8?q?es=20Issue-Code=20and=20Title=20columns?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Layout: - Bigger row height (28→36) and bar font (11→13px) for readability - Sidebar reworked into flex-column with separate clipped rows region so scrolled rows can never paint over the sticky header(layout fix) - Drag handle between sidebar and canvas (120–600px range) - ResizeObserver re-syncs viewport on drag/resize/zoom changes Interaction: - Vertical gridlines aligned to time-scale ticks (Plane-style) - Row hover highlights both sidebar and canvas, with rich HTML tooltip (issue title + start + due + duration) - Title click in sidebar dispatches openIssue → showPanel(EditIssue) - Double-click on canvas bar dispatches openIssue - Wheel forwarding from sidebar to canvas-scroller (vertical scroll works while hovering issue list) - Pointerdown + drag on empty canvas pans both axes - Jump-to-bar buttons now use the bar's true left-edge target Tests: 25/25 jest pass; svelte-check 0 errors. Signed-off-by: Michael Uray --- .../src/components/gantt/GanttBar.svelte | 33 +- .../src/components/gantt/GanttCanvas.svelte | 156 +++++-- .../src/components/gantt/GanttSidebar.svelte | 198 ++++++--- .../src/components/gantt/GanttView.svelte | 388 ++++++++++++++++-- 4 files changed, 643 insertions(+), 132 deletions(-) diff --git a/plugins/tracker-resources/src/components/gantt/GanttBar.svelte b/plugins/tracker-resources/src/components/gantt/GanttBar.svelte index f179d163c18..a54c310d91e 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttBar.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttBar.svelte @@ -1,6 +1,5 @@ {#if visible} @@ -52,6 +57,15 @@ points="{x + w - 6},{barY + barH / 2 - 1} {x + w},{barY + barH / 2 - 1} {x + w - 3},{barY + barH / 2 + 5}" fill="var(--theme-content-color)" /> + {#if barLabel !== ''} + {barLabel} + {/if} + {tooltipText} {:else} + {#if barLabel !== ''} + {barLabel} + {/if} {tooltipText} {/if} {/if} @@ -76,4 +98,13 @@ .bar:hover { filter: brightness(1.1); } + .bar-label { + font-size: 13px; + user-select: none; + pointer-events: none; + dominant-baseline: alphabetic; + } + .summary-label { + font-weight: 600; + } diff --git a/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte b/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte index 772b944a294..66dc7990b1a 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte @@ -1,15 +1,22 @@
- diff --git a/plugins/tracker-resources/src/components/gantt/GanttView.svelte b/plugins/tracker-resources/src/components/gantt/GanttView.svelte index de1a0690842..514014be8dc 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttView.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttView.svelte @@ -1,6 +1,5 @@
- {#if loading} {:else} +
+
+ + + +
+
+ {#each ZOOM_LEVELS as z (z)} + + {/each} +
+
+ + {#if showSettings} +
+ + +
+ {/if} +
+
+
- + +
+ +
-
+ +
@@ -251,10 +417,44 @@ {viewportHeight} {viewport} milestoneStripHeight={MILESTONE_STRIP_HEIGHT} + {hoveredRowId} + on:openIssue={onIssueOpen} + on:hoverRow={onRowHover} />
+ {#if tooltipState.visible && tooltipState.row !== null} + {@const row = tooltipState.row} + {@const issue = row.issue} + {@const ms = row.milestone} +
+ {#if row.kind === 'milestone' && ms !== null} +
◆ Milestone
+
{ms.label}
+ {#if ms.startDate !== null} +
Start: {new Date(ms.startDate).toISOString().slice(0, 10)}
+ {/if} +
Target: {new Date(ms.targetDate).toISOString().slice(0, 10)}
+ {:else if issue !== null} +
Issue
+
{issue.title}
+ {#if issue.startDate !== null} +
Start: {new Date(issue.startDate).toISOString().slice(0, 10)}
+ {/if} + {#if issue.dueDate !== null} +
Due: {new Date(issue.dueDate).toISOString().slice(0, 10)}
+ {/if} + {#if issue.startDate !== null && issue.dueDate !== null} + {@const days = Math.round((Math.max(issue.dueDate, issue.startDate) - Math.min(issue.dueDate, issue.startDate)) / 86_400_000) + 1} +
Duration: {days} day{days === 1 ? '' : 's'}
+ {/if} + {/if} +
+ {/if} {/if}
@@ -266,21 +466,111 @@ width: 100%; overflow: hidden; } + .gantt-toolbar { + flex: 0 0 auto; + display: grid; + grid-template-columns: 1fr auto 1fr; + align-items: center; + padding: 0 12px; + border-bottom: 1px solid var(--theme-divider-color); + background: var(--theme-comp-header-color); + } + .toolbar-left { display: flex; gap: 4px; } + .toolbar-center { display: flex; gap: 2px; justify-self: center; } + .toolbar-right { display: flex; gap: 4px; justify-self: end; position: relative; } + .nav-btn { + height: 26px; + padding: 0 10px; + border: 1px solid var(--theme-divider-color); + background: var(--theme-button-default); + color: var(--theme-content-color); + font-size: 12px; + border-radius: 4px; + cursor: pointer; + } + .nav-btn:hover { + background: var(--theme-button-hovered); + } + .today-btn { + font-weight: 600; + } + .zoom-btn { + height: 26px; + padding: 0 12px; + border: 1px solid var(--theme-divider-color); + background: var(--theme-button-default); + color: var(--theme-content-color); + font-size: 12px; + cursor: pointer; + } + .zoom-btn:first-child { border-radius: 4px 0 0 4px; } + .zoom-btn:last-child { border-radius: 0 4px 4px 0; } + .zoom-btn:not(:first-child) { border-left: none; } + .zoom-btn:hover { background: var(--theme-button-hovered); } + .zoom-btn.active { + background: var(--theme-button-pressed); + font-weight: 600; + } + .settings-btn { + width: 26px; + height: 26px; + padding: 0; + border: 1px solid var(--theme-divider-color); + background: var(--theme-button-default); + color: var(--theme-content-color); + font-size: 13px; + cursor: pointer; + border-radius: 4px; + } + .settings-btn:hover { background: var(--theme-button-hovered); } + .settings-popover { + position: absolute; + top: 32px; + right: 0; + background: var(--theme-popup-color, var(--theme-comp-header-color)); + border: 1px solid var(--theme-divider-color); + border-radius: 4px; + padding: 8px; + display: flex; + flex-direction: column; + gap: 6px; + font-size: 12px; + color: var(--theme-content-color); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + z-index: 5; + } + .settings-popover label { + display: flex; align-items: center; gap: 6px; cursor: pointer; white-space: nowrap; + } .gantt-body { display: flex; flex: 1 1 auto; overflow: hidden; min-height: 0; } + .sidebar-host { flex: 0 0 auto; min-height: 0; } + .resize-handle { + flex: 0 0 5px; + cursor: col-resize; + background: var(--theme-divider-color); + transition: background 80ms ease; + user-select: none; + touch-action: none; + } + .resize-handle:hover, .resize-handle.active { + background: var(--theme-state-info-color, #6366f1); + } .canvas-scroller { flex: 1 1 auto; overflow: auto; min-width: 0; min-height: 0; + cursor: grab; } - .canvas-stack { - position: relative; + .canvas-scroller.panning { + cursor: grabbing; } + .canvas-stack { position: relative; } .header-sticky { position: sticky; top: 0; @@ -288,4 +578,34 @@ background: var(--theme-comp-header-color); border-bottom: 1px solid var(--theme-divider-color); } + .hover-tooltip { + position: fixed; + z-index: 100; + background: var(--theme-popup-color, var(--theme-comp-header-color)); + border: 1px solid var(--theme-divider-color); + border-radius: 4px; + padding: 8px 10px; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18); + pointer-events: none; + font-size: 12px; + color: var(--theme-content-color); + max-width: 320px; + } + .tt-head { + font-size: 10px; + font-weight: 600; + text-transform: uppercase; + color: var(--theme-darker-color); + letter-spacing: 0.05em; + margin-bottom: 2px; + } + .tt-title { + font-size: 13px; + font-weight: 600; + margin-bottom: 4px; + } + .tt-line { + font-size: 12px; + line-height: 1.5; + } From 0f43f8f0d9fdd3da3d659d0d078720b48ca42912 Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:15 +0000 Subject: [PATCH 17/62] - SVG horizontal-scroll bug: GanttHeader and GanttCanvas now render at totalCanvasWidth (was viewport width), with viewBox in scroll-content coordinates. The sticky header lives in the same coordinate system as the canvas-stack so horizontal scroll no longer clips the time-axis. - showPanel uses tracker.component.EditIssue instead of the hardcoded string + 'as any' cast. - Removed unused GanttToolbar.svelte and GanttMilestoneFlag.svelte (dead files since toolbar moved into GanttView and milestone flags became rows). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Toolbar: - Time-navigation cluster: ⏮ « Today » ⏭ + native date picker that jumps to a specific date. Replaces the lone Today button. Interaction polish: - Sidebar wheel forwarding now uses direct scrollTop/scrollLeft mutation with deltaMode scaling — same speed as native canvas scroll. - TodayMarker no longer hides when scrolled offscreen (SVG width handles clipping); milestone reference lines render unconditionally for the same reason. Tests: 25/25 jest pass; svelte-check 0 errors. Signed-off-by: Michael Uray --- .../src/components/gantt/GanttCanvas.svelte | 44 +++++++-------- .../src/components/gantt/GanttHeader.svelte | 21 ++++---- .../gantt/GanttMilestoneFlag.svelte | 53 ------------------- .../components/gantt/GanttTodayMarker.svelte | 8 ++- .../src/components/gantt/GanttToolbar.svelte | 46 ---------------- .../src/components/gantt/GanttView.svelte | 52 ++++++++++++++++-- 6 files changed, 88 insertions(+), 136 deletions(-) delete mode 100644 plugins/tracker-resources/src/components/gantt/GanttMilestoneFlag.svelte delete mode 100644 plugins/tracker-resources/src/components/gantt/GanttToolbar.svelte diff --git a/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte b/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte index 66dc7990b1a..500c41a8d9c 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte @@ -24,13 +24,17 @@ export let scrollTop: number = 0 export let viewportHeight: number = 600 export let viewport: { left: number; right: number } + export let totalWidth: number export let milestoneStripHeight: number = 0 export let hoveredRowId: string | null = null $: visibleRows = filterVisibleRows(rows, scrollTop, viewportHeight) $: rowsHeight = rows.length > 0 ? rows[rows.length - 1].y + rows[rows.length - 1].height : 0 $: totalHeight = rowsHeight + milestoneStripHeight - $: ticks = timeScale.ticks([timeScale.fromX(viewport.left), timeScale.fromX(viewport.right)]) + $: ticks = timeScale.ticks([ + timeScale.fromX(Math.max(0, viewport.left - 100)), + timeScale.fromX(viewport.right + 100) + ]) function rowKey (row: LayoutRow): string { return row.id @@ -48,9 +52,9 @@ @@ -75,9 +79,9 @@ {#each visibleRows as row (rowKey(row))} {@const isHover = hoveredRowId === row.id} @@ -140,20 +144,18 @@ {#each milestones as ms (ms._id)} {@const x = timeScale.toX(ms.targetDate)} - {#if x >= viewport.left - 16 && x <= viewport.right + 16} - - {ms.label} - - {/if} + + {ms.label} + {/each} diff --git a/plugins/tracker-resources/src/components/gantt/GanttHeader.svelte b/plugins/tracker-resources/src/components/gantt/GanttHeader.svelte index eb4d4245ff6..dc52767c335 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttHeader.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttHeader.svelte @@ -1,27 +1,30 @@ {#each ticks as tick (tick.date)} @@ -36,7 +39,7 @@ /> @@ -53,7 +56,7 @@ } .tick-label { font-family: var(--mono-font, monospace); - font-size: 11px; + font-size: 12px; user-select: none; pointer-events: none; } diff --git a/plugins/tracker-resources/src/components/gantt/GanttMilestoneFlag.svelte b/plugins/tracker-resources/src/components/gantt/GanttMilestoneFlag.svelte deleted file mode 100644 index 1e5539fbd56..00000000000 --- a/plugins/tracker-resources/src/components/gantt/GanttMilestoneFlag.svelte +++ /dev/null @@ -1,53 +0,0 @@ - - - -{#if visible} - - - {milestone.label} - - - {milestone.label} - -{/if} - - diff --git a/plugins/tracker-resources/src/components/gantt/GanttTodayMarker.svelte b/plugins/tracker-resources/src/components/gantt/GanttTodayMarker.svelte index 8a88f6789f7..ab1bac75106 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttTodayMarker.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttTodayMarker.svelte @@ -7,11 +7,15 @@ export let timeScale: TimeScale export let canvasHeight: number - export let viewport: { left: number; right: number } + // Viewport accepted for API compatibility but no longer needed for visibility + // (the SVG itself spans the whole canvas, scrollbar clips off-viewport). + // eslint-disable-next-line @typescript-eslint/no-unused-vars + export let viewport: { left: number; right: number } = { left: 0, right: 0 } + $: void viewport $: today = Date.now() $: x = timeScale.toX(today) - $: visible = x >= viewport.left && x <= viewport.right + $: visible = true {#if visible} diff --git a/plugins/tracker-resources/src/components/gantt/GanttToolbar.svelte b/plugins/tracker-resources/src/components/gantt/GanttToolbar.svelte deleted file mode 100644 index 8589cdd6af5..00000000000 --- a/plugins/tracker-resources/src/components/gantt/GanttToolbar.svelte +++ /dev/null @@ -1,46 +0,0 @@ - - - -
- {#each order as z} -
- - diff --git a/plugins/tracker-resources/src/components/gantt/GanttView.svelte b/plugins/tracker-resources/src/components/gantt/GanttView.svelte index 514014be8dc..f48f2b05343 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttView.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttView.svelte @@ -217,7 +217,7 @@ function onIssueOpen (e: CustomEvent<{ issue: { _id: string, _class: string } }>): void { showPanel( - 'tracker:component:EditIssue' as any, + tracker.component.EditIssue, e.detail.issue._id as Ref, e.detail.issue._class as Ref>, 'content' @@ -233,14 +233,34 @@ if (scrollerEl === undefined) return scrollerEl.scrollBy({ left: dir * canvasViewportWidth * 0.8, behavior: 'smooth' }) } + function jumpToStart (): void { + if (scrollerEl === undefined) return + scrollerEl.scrollTo({ left: 0, behavior: 'smooth' }) + } + function jumpToEnd (): void { + if (scrollerEl === undefined) return + scrollerEl.scrollTo({ left: scrollerEl.scrollWidth, behavior: 'smooth' }) + } + function jumpToDate (iso: string): void { + if (scrollerEl === undefined || iso === '') return + const t = Date.parse(iso) + if (isNaN(t)) return + const x = timeScale.toX(t) + scrollerEl.scrollTo({ left: Math.max(0, x - canvasViewportWidth / 2), behavior: 'smooth' }) + } + let datePickerValue: string = '' // Forward wheel events from the sidebar to the canvas-scroller so users can - // scroll vertically while hovering the issue list (the sidebar itself uses a - // transform-based layout and has no native scrollbar). + // scroll vertically while hovering the issue list. Direct scrollTop/scrollLeft + // assignment matches the browser's native wheel-to-scroll speed; smooth + // scrolling would feel laggy against the canvas. function forwardSidebarWheel (e: WheelEvent): void { if (scrollerEl === undefined) return e.preventDefault() - scrollerEl.scrollBy({ top: e.deltaY, left: e.deltaX, behavior: 'auto' }) + // deltaMode 1 = lines, 2 = pages; scale to pixels. + const factor = e.deltaMode === 1 ? 16 : (e.deltaMode === 2 ? scrollerEl.clientHeight : 1) + scrollerEl.scrollTop += e.deltaY * factor + scrollerEl.scrollLeft += e.deltaX * factor } // Click-and-drag panning across empty canvas area. @@ -324,9 +344,18 @@ {:else}
+ + + jumpToDate(datePickerValue)} + />
{#each ZOOM_LEVELS as z (z)} @@ -406,7 +435,7 @@ >
- +
Date: Fri, 15 May 2026 12:33:15 +0000 Subject: [PATCH 18/62] feat(tracker-resources): wire Gantt sidebar toggles into Customize-View - Register two ToggleViewOptions on the Gantt viewlet: ganttShowIssueCode (default OFF) and ganttShowTitle (default ON). These show up in the standard Customize-View dropdown. - Drop the per-component settings popover from GanttView; sidebar column visibility now reads viewOptions directly. - Hover tooltip always surfaces the issue code (e.g. OSTRO-31), even when the issue-code column is hidden. - IntlStrings + en/de/es/fr/it/ja/pt/ru/zh/cs translations added. Signed-off-by: Michael Uray --- models/tracker/src/viewlets.ts | 24 +- plugins/tracker-assets/lang/cs.json | 573 +++++++++-------- plugins/tracker-assets/lang/de.json | 591 +++++++++--------- plugins/tracker-assets/lang/en.json | 4 +- plugins/tracker-assets/lang/es.json | 574 ++++++++--------- plugins/tracker-assets/lang/fr.json | 574 ++++++++--------- plugins/tracker-assets/lang/it.json | 574 ++++++++--------- plugins/tracker-assets/lang/ja.json | 574 ++++++++--------- plugins/tracker-assets/lang/pt.json | 574 ++++++++--------- plugins/tracker-assets/lang/ru.json | 591 +++++++++--------- plugins/tracker-assets/lang/zh.json | 591 +++++++++--------- .../src/components/gantt/GanttView.svelte | 37 +- plugins/tracker-resources/src/plugin.ts | 4 +- 13 files changed, 2622 insertions(+), 2663 deletions(-) diff --git a/models/tracker/src/viewlets.ts b/models/tracker/src/viewlets.ts index ce6e058e535..45a9d0406e8 100644 --- a/models/tracker/src/viewlets.ts +++ b/models/tracker/src/viewlets.ts @@ -213,10 +213,9 @@ export function issueConfig ( } export function ganttViewOptions (): ViewOptionsModel { - // PR 2 ships a minimal read-only Gantt. Group-by, "Show colors" and other - // dropdown ViewOptions are intentionally NOT advertised — the canvas does - // not honour them yet. They will be added in PR 3 alongside drag/edit + - // Component swimlanes so users never see options that have no effect. + // PR 2 ships a minimal read-only Gantt. Group-by + Show-colors are + // intentionally NOT advertised — the canvas does not honour them yet. + // The two sidebar-column toggles below ARE wired up to GanttSidebar. return { groupBy: [], orderBy: [ @@ -224,7 +223,22 @@ export function ganttViewOptions (): ViewOptionsModel { ['rank', SortingOrder.Ascending], ['dueDate', SortingOrder.Ascending] ], - other: [] + other: [ + { + key: 'ganttShowIssueCode', + type: 'toggle', + defaultValue: false, + actionTarget: 'display', + label: tracker.string.GanttShowIssueCode + }, + { + key: 'ganttShowTitle', + type: 'toggle', + defaultValue: true, + actionTarget: 'display', + label: tracker.string.GanttShowTitle + } + ] } } diff --git a/plugins/tracker-assets/lang/cs.json b/plugins/tracker-assets/lang/cs.json index 9f87e86aff4..03e0177a161 100644 --- a/plugins/tracker-assets/lang/cs.json +++ b/plugins/tracker-assets/lang/cs.json @@ -1,294 +1,281 @@ { - "string": { - "TrackerApplication": "Přehled", - "Projects": "Vaše projekty", - "More": "Více", - "Default": "Výchozí", - "MakeDefault": "Nastavit jako výchozí", - "Delete": "Smazat", - "Open": "Otevřít", - "Members": "Členové", - "Inbox": "Doručená pošta", - "MyIssues": "Mé úkoly", - "ViewIssue": "Zobrazit úkol", - "IssueCreated": "Úkol vytvořen", - "Issues": "Úkoly", - "Views": "Zobrazení", - "Active": "Aktivní", - "AllIssues": "Všechny úkoly", - "ActiveIssues": "Aktivní úkoly", - "BacklogIssues": "Návrhy", - "Backlog": "Návrhy", - "Board": "Tabule", - "Components": "Komponenty", - "AllComponents": "Vše", - "BacklogComponents": "Návrhy", - "ActiveComponents": "Aktivní", - "ClosedComponents": "Uzavřené", - "NewComponent": "Nová komponenta", - "CreateComponent": "Vytvořit komponentu", - "ComponentNamePlaceholder": "Název komponenty", - "ComponentDescriptionPlaceholder": "Popis (volitelné)", - "ComponentLead": "Vedoucí", - "ComponentMembers": "Členové", - "StartDate": "Datum zahájení", - "TargetDate": "Cílové datum", - "Planned": "Plánováno", - "InProgress": "Probíhá", - "Paused": "Pozastaveno", - "Completed": "Dokončeno", - "Canceled": "Zrušeno", - "CreateProject": "Vytvořit projekt", - "NewProject": "Nový projekt", - "ProjectTitle": "Název projektu", - "ProjectTitlePlaceholder": "Nový projekt", - "UsedInIssueIDs": "Použito v ID úkolů", - "Identifier": "Identifikátor", - "Import": "Importovat", - "ProjectIdentifier": "Identifikátor projektu", - "IdentifierExists": "Identifikátor projektu již existuje", - "ProjectIdentifierPlaceholder": "PROJ", - "ChooseIcon": "Vybrat ikonu", - "AddIssue": "Přidat úkol", - "NewIssue": "Nový úkol", - "NewIssuePlaceholder": "Nový", - "ResumeDraft": "Pokračovat v konceptu", - "SaveIssue": "Vytvořit úkol", - "SetPriority": "Nastavit prioritu…", - "SetStatus": "Nastavit stav…", - "SelectIssue": "Vybrat úkol", - "Priority": "Priorita", - "NoPriority": "Bez priority", - "Urgent": "Naléhavé", - "High": "Vysoká", - "Medium": "Střední", - "Low": "Nízká", - "Unassigned": "Nepřiřazeno", - "Back": "Zpět", - "List": "Seznam", - "NumberLabels": "{count, plural, =0 {žádné štítky} =1 {1 štítek} other {# štítků}}", - "CategoryBacklog": "Návrhy", - "CategoryUnstarted": "Nezahájeno", - "CategoryStarted": "Zahájeno", - "CategoryCompleted": "Dokončeno", - "CategoryCanceled": "Zrušeno", - "Title": "Název", - "Name": "Jméno", - "Description": "Popis", - "Status": "Stav", - "Number": "Číslo", - "Assignee": "Přiřazený", - "AssignTo": "Přiřadit…", - "AssignedTo": "Přiřazeno k {value}", - "Parent": "Nadřazený úkol", - "SetParent": "Nastavit nadřazený úkol…", - "ChangeParent": "Změnit nadřazený úkol…", - "RemoveParent": "Odebrat nadřazený úkol", - "OpenParent": "Otevřít nadřazený úkol", - "SubIssues": "Podúkoly", - "SubIssuesList": "Podúkoly ({subIssues})", - "OpenSubIssues": "Otevřít podúkoly", - "AddSubIssues": "Přidat podúkol", - "BlockedBy": "Blokováno", - "RelatedTo": "Související s", - "Comments": "Komentáře", - "Attachments": "Přílohy", - "Labels": "Štítky", - "Component": "Komponenta", - "SetDueDate": "Nastavit datum splnění…", - "ChangeDueDate": "Změnit datum splnění…", - "ModificationDate": "Aktualizováno {value}", - "Project": "Projekt", - "Issue": "Úkol", - "SubIssue": "Podúkol", - "Rank": "Hodnost", - "TypeIssuePriority": "Priorita úkolu", - "IssueTitlePlaceholder": "Název úkolu", - "SubIssueTitlePlaceholder": "Název podúkolu", - "IssueDescriptionPlaceholder": "Přidat popis…", - "SubIssueDescriptionPlaceholder": "Přidat popis podúkolu", - "AddIssueTooltip": "Přidat úkol…", - "Grouping": "Seskupení", - "Ordering": "Řazení", - "CompletedIssues": "Dokončené úkoly", - "NoGrouping": "Bez seskupení", - "NoAssignee": "Bez přiřazení", - "LastUpdated": "Poslední aktualizace", - "DueDate": "Datum splnění", - "IssueStartDate": "Datum zahájení", - "GanttDependency": "Dependency", - "GanttLag": "Lag", - "Manual": "Manuální", - "All": "Vše", - "PastWeek": "Minulý týden", - "PastMonth": "Minulý měsíc", - "CopyIssueUrl": "Zkopírovat URL úkolu do schránky", - "CopyIssueId": "Zkopírovat ID úkolu do schránky", - "CopyIssueBranch": "Zkopírovat název větve Git do schránky", - "CopyIssueTitle": "Zkopírovat název úkolu do schránky", - "AssetLabel": "Mějte přehled", - "AddToComponent": "Přidat do komponenty…", - "MoveToComponent": "Přesunout do komponenty…", - "NoComponent": "Bez komponenty", - "ComponentLeadTitle": "Vedoucí komponenty", - "ComponentMembersTitle": "Členové komponenty", - "ComponentLeadSearchPlaceholder": "Nastavit vedoucího komponenty…", - "ComponentMembersSearchPlaceholder": "Změnit členy komponenty…", - "MoveToProject": "Přesunout do projektu", - "Duplicate": "Duplikovat", - - "GotoIssues": "Přejít na úkoly", - "GotoActive": "Přejít na aktivní úkoly", - "GotoBacklog": "Přejít na návrhy", - "GotoComponents": "Přejít na komponenty", - "GotoMyIssues": "Přejít na mé úkoly", - "GotoTrackerApplication": "Přepnout na aplikaci Přehled", - - "CreatedOne": "Vytvořeno", - "MoveIssues": "Přesunout úkoly", - "MoveIssuesDescription": "Vyberte projekt, do kterého chcete úkoly přesunout", - "ManageAttributes": "Spravovat atributy", - "KeepOriginalAttributes": "Zachovat původní atributy", - "KeepOriginalAttributesTooltip": "Původní stavy a komponenty úkolů budou zachovány v novém projektu", - "SelectReplacement": "Následující položky nejsou dostupné v novém projektu. Vyberte náhradu.", - "MissingItem": "CHYBĚJÍCÍ POLOŽKA", - "Replacement": "NÁHRADA", - "Original": "PŮVODNÍ", - "OriginalDescription": "Položky z této sekce budou vytvořeny v novém projektu", - - "Relations": "Vztahy", - "RemoveRelation": "Odebrat vztah...", - "AddBlockedBy": "Označit jako blokováno...", - "AddIsBlocking": "Označit jako blokující...", - "AddRelatedIssue": "Odkázat na jiný úkol...", - "RelatedIssue": "Související úkol {id} - {title}", - "BlockedIssue": "Blokovaný úkol {id} - {title}", - "BlockingIssue": "Blokující úkol {id} - {title}", - "BlockedBySearchPlaceholder": "Vyhledat úkol pro označení jako blokováno...", - "IsBlockingSearchPlaceholder": "Vyhledat úkol pro označení jako blokující...", - "RelatedIssueSearchPlaceholder": "Vyhledat úkol pro odkazování...", - "Blocks": "Blokuje", - "Related": "Související", - "RelatedIssues": "Související úkoly", - - "EditIssue": "Upravit {title}", - "EditWorkflowStatuses": "Upravit stavy úkolů", - "EditProject": "Upravit projekt", - "DeleteProject": "Smazat projekt", - "ArchiveProjectName": "Archivovat projekt {name}?", - "ArchiveProjectConfirm": "Chcete tento projekt archivovat?", - "DeleteProjectConfirm": "Chcete tento projekt a všechny jeho úkoly smazat?", - "ProjectHasIssues": "Tento projekt obsahuje úkoly. Opravdu jej chcete archivovat?", - "ManageWorkflowStatuses": "Spravovat typy projektů", - "AddWorkflowStatus": "Přidat stav úkolu", - "EditWorkflowStatus": "Upravit stav úkolu", - "DeleteWorkflowStatus": "Smazat stav úkolu", - "DeleteWorkflowStatusConfirm": "Chcete smazat stav \"{status}\"?", - "DeleteWorkflowStatusErrorDescription": "Stav \"{status}\" má přiřazeno {count, plural, =1 {1 úkol} other {# úkolů}}. Vyberte stav pro přesun", - - "Save": "Uložit", - "IncludeItemsThatMatch": "Zahrnout položky, které odpovídají", - "AnyFilter": "jakémukoli filtru", - "AllFilters": "všem filtrům", - "NoDescription": "Žádný popis", - "SearchIssue": "Hledat úkol...", - - "StatusHistory": "Historie stavů", - "NewSubIssue": "Přidat podúkol...", - "AddLabel": "Přidat štítek", - - "DeleteIssue": "Smazat {issueCount, plural, =1 {úkol} other {# úkolů}}", - "DeleteIssueConfirm": "Chcete smazat {issueCount, plural, =1 {úkol} other {úkoly}}{subIssueCount, plural, =0 {?} =1 { a podúkol?} other { a podúkoly?}}", - - "Milestone": "Milník", - "NoMilestone": "Žádný milník", - "MoveToMilestone": "Vybrat milník", - "Milestones": "Milníky", - "AllMilestones": "Vše", - "PlannedMilestones": "Plánované", - "ActiveMilestones": "Aktivní", - "ClosedMilestones": "Dokončené", - "AddToMilestone": "Přidat do milníku", - "MilestoneNamePlaceholder": "Název milníku", - - "NewMilestone": "Nový milník", - "CreateMilestone": "Vytvořit", - - "MoveAndDeleteMilestone": "Přesunout úkoly do {newMilestone} a smazat {deleteMilestone}", - "MoveAndDeleteMilestoneConfirm": "Chcete smazat milník a přesunout úkoly do jiného milníku?", - - "Estimation": "Odhad", - "ReportedTime": "Strávený čas", - "RemainingTime": "Zbývající čas", - "TimeSpendReports": "Zprávy o stráveném čase", - "TimeSpendReport": "Čas", - "TimeSpendReportAdd": "Přidat zprávu o čase", - "TimeSpendReportDate": "Datum", - "TimeSpendReportValue": "Strávený čas", - "TimeSpendReportValueTooltip": "Strávený čas v hodinách", - "TimeSpendReportDescription": "Popis", - "TimeSpendDays": "{value}d", - "TimeSpendHours": "{value}h", - "TimeSpendMinutes": "{value}m", - "ChildEstimation": "Odhad podúkolů", - "ChildReportedTime": "Čas podúkolů", - "CapacityValue": "z {value}d", - "NewRelatedIssue": "Nový související úkol", - "RelatedIssuesNotFound": "Související úkoly nenalezeny", - - "AddedReference": "Přidán odkaz", - "AddedAsBlocked": "Označeno jako blokované", - "AddedAsBlocking": "Označeno jako blokující", - - "IssueTemplate": "Šablona", - "IssueTemplates": "Šablony", - "NewProcess": "Nová šablona", - "SaveProcess": "Uložit šablonu", - "NoIssueTemplate": "Žádná šablona", - "TemplateReplace": "Chcete použít novou šablonu?", - "TemplateReplaceConfirm": "Všechna pole budou přepsána hodnotami nové šablony", - "Apply": "Použít", - - "CurrentWorkDay": "Aktuální pracovní den", - "PreviousWorkDay": "Předchozí pracovní den", - "TimeReportDayTypeLabel": "Vyberte typ pracovního dne", - "DefaultAssignee": "Výchozí přiřazení úkolů", - - "SevenHoursLength": "Sedm hodin", - "EightHoursLength": "Osm hodin", - "HourLabel": "h", - "MinuteLabel": "m", - "Saved": "Uloženo...", - "CreatedIssue": "Úkol vytvořen", - "CreatedSubIssue": "Podúkol vytvořen", - "ChangeStatus": "Změnit stav", - "ConfigLabel": "Přehled", - "ConfigDescription": "Rozšíření pro správu pracovních úkolů a projektů.", - "NoStatusFound": "Nebyl nalezen odpovídající stav", - "CreateMissingStatus": "Vytvořit chybějící stav", - "UnsetParent": "Nadřazený úkol bude odebrán", - "AllProjects": "Všechny projekty", - "IssueNotificationTitle": "{issueTitle}", - "IssueNotificationBody": "Aktualizováno uživatelem {senderName}", - "IssueNotificationChanged": "{senderName} změnil {property}", - "IssueNotificationChangedProperty": "{senderName} změnil {property} na \"{newValue}\"", - "IssueNotificationMessage": "{senderName}: {message}", - "PreviousAssigned": "Původně přiřazeno", - "IssueAssignedToYou": "Přiřazeno vám", - "RelatedIssueTargetDescription": "Cílový projekt pro související úkol", - "MapRelatedIssues": "Nastavit výchozí projekty pro související úkoly", - "DefaultIssueStatus": "Výchozí stav úkolu", - "IssueStatus": "Stav", - "Extensions": "Rozšíření", - "UnsetParentIssue": "Odebrat nadřazený úkol", - "ForbidCreateProjectPermission": "Zakázat vytvoření projektu", - "ForbidCreateProjectPermissionDescription": "Zakazuje uživatelům vytvářet nové projekty", - "AllowCreatingIssues": "Povolit vytváření úkolů", - "Day": "Den", - "Gantt": "Gantt", - "Month": "Měsíc", - "Quarter": "Čtvrtletí", - "Week": "Týden" - }, - "status": {} -} + "string": { + "TrackerApplication": "Přehled", + "Projects": "Vaše projekty", + "More": "Více", + "Default": "Výchozí", + "MakeDefault": "Nastavit jako výchozí", + "Delete": "Smazat", + "Open": "Otevřít", + "Members": "Členové", + "Inbox": "Doručená pošta", + "MyIssues": "Mé úkoly", + "ViewIssue": "Zobrazit úkol", + "IssueCreated": "Úkol vytvořen", + "Issues": "Úkoly", + "Views": "Zobrazení", + "Active": "Aktivní", + "AllIssues": "Všechny úkoly", + "ActiveIssues": "Aktivní úkoly", + "BacklogIssues": "Návrhy", + "Backlog": "Návrhy", + "Board": "Tabule", + "Components": "Komponenty", + "AllComponents": "Vše", + "BacklogComponents": "Návrhy", + "ActiveComponents": "Aktivní", + "ClosedComponents": "Uzavřené", + "NewComponent": "Nová komponenta", + "CreateComponent": "Vytvořit komponentu", + "ComponentNamePlaceholder": "Název komponenty", + "ComponentDescriptionPlaceholder": "Popis (volitelné)", + "ComponentLead": "Vedoucí", + "ComponentMembers": "Členové", + "StartDate": "Datum zahájení", + "TargetDate": "Cílové datum", + "Planned": "Plánováno", + "InProgress": "Probíhá", + "Paused": "Pozastaveno", + "Completed": "Dokončeno", + "Canceled": "Zrušeno", + "CreateProject": "Vytvořit projekt", + "NewProject": "Nový projekt", + "ProjectTitle": "Název projektu", + "ProjectTitlePlaceholder": "Nový projekt", + "UsedInIssueIDs": "Použito v ID úkolů", + "Identifier": "Identifikátor", + "Import": "Importovat", + "ProjectIdentifier": "Identifikátor projektu", + "IdentifierExists": "Identifikátor projektu již existuje", + "ProjectIdentifierPlaceholder": "PROJ", + "ChooseIcon": "Vybrat ikonu", + "AddIssue": "Přidat úkol", + "NewIssue": "Nový úkol", + "NewIssuePlaceholder": "Nový", + "ResumeDraft": "Pokračovat v konceptu", + "SaveIssue": "Vytvořit úkol", + "SetPriority": "Nastavit prioritu…", + "SetStatus": "Nastavit stav…", + "SelectIssue": "Vybrat úkol", + "Priority": "Priorita", + "NoPriority": "Bez priority", + "Urgent": "Naléhavé", + "High": "Vysoká", + "Medium": "Střední", + "Low": "Nízká", + "Unassigned": "Nepřiřazeno", + "Back": "Zpět", + "List": "Seznam", + "NumberLabels": "{count, plural, =0 {žádné štítky} =1 {1 štítek} other {# štítků}}", + "CategoryBacklog": "Návrhy", + "CategoryUnstarted": "Nezahájeno", + "CategoryStarted": "Zahájeno", + "CategoryCompleted": "Dokončeno", + "CategoryCanceled": "Zrušeno", + "Title": "Název", + "Name": "Jméno", + "Description": "Popis", + "Status": "Stav", + "Number": "Číslo", + "Assignee": "Přiřazený", + "AssignTo": "Přiřadit…", + "AssignedTo": "Přiřazeno k {value}", + "Parent": "Nadřazený úkol", + "SetParent": "Nastavit nadřazený úkol…", + "ChangeParent": "Změnit nadřazený úkol…", + "RemoveParent": "Odebrat nadřazený úkol", + "OpenParent": "Otevřít nadřazený úkol", + "SubIssues": "Podúkoly", + "SubIssuesList": "Podúkoly ({subIssues})", + "OpenSubIssues": "Otevřít podúkoly", + "AddSubIssues": "Přidat podúkol", + "BlockedBy": "Blokováno", + "RelatedTo": "Související s", + "Comments": "Komentáře", + "Attachments": "Přílohy", + "Labels": "Štítky", + "Component": "Komponenta", + "SetDueDate": "Nastavit datum splnění…", + "ChangeDueDate": "Změnit datum splnění…", + "ModificationDate": "Aktualizováno {value}", + "Project": "Projekt", + "Issue": "Úkol", + "SubIssue": "Podúkol", + "Rank": "Hodnost", + "TypeIssuePriority": "Priorita úkolu", + "IssueTitlePlaceholder": "Název úkolu", + "SubIssueTitlePlaceholder": "Název podúkolu", + "IssueDescriptionPlaceholder": "Přidat popis…", + "SubIssueDescriptionPlaceholder": "Přidat popis podúkolu", + "AddIssueTooltip": "Přidat úkol…", + "Grouping": "Seskupení", + "Ordering": "Řazení", + "CompletedIssues": "Dokončené úkoly", + "NoGrouping": "Bez seskupení", + "NoAssignee": "Bez přiřazení", + "LastUpdated": "Poslední aktualizace", + "DueDate": "Datum splnění", + "IssueStartDate": "Datum zahájení", + "GanttDependency": "Dependency", + "GanttLag": "Lag", + "Manual": "Manuální", + "All": "Vše", + "PastWeek": "Minulý týden", + "PastMonth": "Minulý měsíc", + "CopyIssueUrl": "Zkopírovat URL úkolu do schránky", + "CopyIssueId": "Zkopírovat ID úkolu do schránky", + "CopyIssueBranch": "Zkopírovat název větve Git do schránky", + "CopyIssueTitle": "Zkopírovat název úkolu do schránky", + "AssetLabel": "Mějte přehled", + "AddToComponent": "Přidat do komponenty…", + "MoveToComponent": "Přesunout do komponenty…", + "NoComponent": "Bez komponenty", + "ComponentLeadTitle": "Vedoucí komponenty", + "ComponentMembersTitle": "Členové komponenty", + "ComponentLeadSearchPlaceholder": "Nastavit vedoucího komponenty…", + "ComponentMembersSearchPlaceholder": "Změnit členy komponenty…", + "MoveToProject": "Přesunout do projektu", + "Duplicate": "Duplikovat", + "GotoIssues": "Přejít na úkoly", + "GotoActive": "Přejít na aktivní úkoly", + "GotoBacklog": "Přejít na návrhy", + "GotoComponents": "Přejít na komponenty", + "GotoMyIssues": "Přejít na mé úkoly", + "GotoTrackerApplication": "Přepnout na aplikaci Přehled", + "CreatedOne": "Vytvořeno", + "MoveIssues": "Přesunout úkoly", + "MoveIssuesDescription": "Vyberte projekt, do kterého chcete úkoly přesunout", + "ManageAttributes": "Spravovat atributy", + "KeepOriginalAttributes": "Zachovat původní atributy", + "KeepOriginalAttributesTooltip": "Původní stavy a komponenty úkolů budou zachovány v novém projektu", + "SelectReplacement": "Následující položky nejsou dostupné v novém projektu. Vyberte náhradu.", + "MissingItem": "CHYBĚJÍCÍ POLOŽKA", + "Replacement": "NÁHRADA", + "Original": "PŮVODNÍ", + "OriginalDescription": "Položky z této sekce budou vytvořeny v novém projektu", + "Relations": "Vztahy", + "RemoveRelation": "Odebrat vztah...", + "AddBlockedBy": "Označit jako blokováno...", + "AddIsBlocking": "Označit jako blokující...", + "AddRelatedIssue": "Odkázat na jiný úkol...", + "RelatedIssue": "Související úkol {id} - {title}", + "BlockedIssue": "Blokovaný úkol {id} - {title}", + "BlockingIssue": "Blokující úkol {id} - {title}", + "BlockedBySearchPlaceholder": "Vyhledat úkol pro označení jako blokováno...", + "IsBlockingSearchPlaceholder": "Vyhledat úkol pro označení jako blokující...", + "RelatedIssueSearchPlaceholder": "Vyhledat úkol pro odkazování...", + "Blocks": "Blokuje", + "Related": "Související", + "RelatedIssues": "Související úkoly", + "EditIssue": "Upravit {title}", + "EditWorkflowStatuses": "Upravit stavy úkolů", + "EditProject": "Upravit projekt", + "DeleteProject": "Smazat projekt", + "ArchiveProjectName": "Archivovat projekt {name}?", + "ArchiveProjectConfirm": "Chcete tento projekt archivovat?", + "DeleteProjectConfirm": "Chcete tento projekt a všechny jeho úkoly smazat?", + "ProjectHasIssues": "Tento projekt obsahuje úkoly. Opravdu jej chcete archivovat?", + "ManageWorkflowStatuses": "Spravovat typy projektů", + "AddWorkflowStatus": "Přidat stav úkolu", + "EditWorkflowStatus": "Upravit stav úkolu", + "DeleteWorkflowStatus": "Smazat stav úkolu", + "DeleteWorkflowStatusConfirm": "Chcete smazat stav \"{status}\"?", + "DeleteWorkflowStatusErrorDescription": "Stav \"{status}\" má přiřazeno {count, plural, =1 {1 úkol} other {# úkolů}}. Vyberte stav pro přesun", + "Save": "Uložit", + "IncludeItemsThatMatch": "Zahrnout položky, které odpovídají", + "AnyFilter": "jakémukoli filtru", + "AllFilters": "všem filtrům", + "NoDescription": "Žádný popis", + "SearchIssue": "Hledat úkol...", + "StatusHistory": "Historie stavů", + "NewSubIssue": "Přidat podúkol...", + "AddLabel": "Přidat štítek", + "DeleteIssue": "Smazat {issueCount, plural, =1 {úkol} other {# úkolů}}", + "DeleteIssueConfirm": "Chcete smazat {issueCount, plural, =1 {úkol} other {úkoly}}{subIssueCount, plural, =0 {?} =1 { a podúkol?} other { a podúkoly?}}", + "Milestone": "Milník", + "NoMilestone": "Žádný milník", + "MoveToMilestone": "Vybrat milník", + "Milestones": "Milníky", + "AllMilestones": "Vše", + "PlannedMilestones": "Plánované", + "ActiveMilestones": "Aktivní", + "ClosedMilestones": "Dokončené", + "AddToMilestone": "Přidat do milníku", + "MilestoneNamePlaceholder": "Název milníku", + "NewMilestone": "Nový milník", + "CreateMilestone": "Vytvořit", + "MoveAndDeleteMilestone": "Přesunout úkoly do {newMilestone} a smazat {deleteMilestone}", + "MoveAndDeleteMilestoneConfirm": "Chcete smazat milník a přesunout úkoly do jiného milníku?", + "Estimation": "Odhad", + "ReportedTime": "Strávený čas", + "RemainingTime": "Zbývající čas", + "TimeSpendReports": "Zprávy o stráveném čase", + "TimeSpendReport": "Čas", + "TimeSpendReportAdd": "Přidat zprávu o čase", + "TimeSpendReportDate": "Datum", + "TimeSpendReportValue": "Strávený čas", + "TimeSpendReportValueTooltip": "Strávený čas v hodinách", + "TimeSpendReportDescription": "Popis", + "TimeSpendDays": "{value}d", + "TimeSpendHours": "{value}h", + "TimeSpendMinutes": "{value}m", + "ChildEstimation": "Odhad podúkolů", + "ChildReportedTime": "Čas podúkolů", + "CapacityValue": "z {value}d", + "NewRelatedIssue": "Nový související úkol", + "RelatedIssuesNotFound": "Související úkoly nenalezeny", + "AddedReference": "Přidán odkaz", + "AddedAsBlocked": "Označeno jako blokované", + "AddedAsBlocking": "Označeno jako blokující", + "IssueTemplate": "Šablona", + "IssueTemplates": "Šablony", + "NewProcess": "Nová šablona", + "SaveProcess": "Uložit šablonu", + "NoIssueTemplate": "Žádná šablona", + "TemplateReplace": "Chcete použít novou šablonu?", + "TemplateReplaceConfirm": "Všechna pole budou přepsána hodnotami nové šablony", + "Apply": "Použít", + "CurrentWorkDay": "Aktuální pracovní den", + "PreviousWorkDay": "Předchozí pracovní den", + "TimeReportDayTypeLabel": "Vyberte typ pracovního dne", + "DefaultAssignee": "Výchozí přiřazení úkolů", + "SevenHoursLength": "Sedm hodin", + "EightHoursLength": "Osm hodin", + "HourLabel": "h", + "MinuteLabel": "m", + "Saved": "Uloženo...", + "CreatedIssue": "Úkol vytvořen", + "CreatedSubIssue": "Podúkol vytvořen", + "ChangeStatus": "Změnit stav", + "ConfigLabel": "Přehled", + "ConfigDescription": "Rozšíření pro správu pracovních úkolů a projektů.", + "NoStatusFound": "Nebyl nalezen odpovídající stav", + "CreateMissingStatus": "Vytvořit chybějící stav", + "UnsetParent": "Nadřazený úkol bude odebrán", + "AllProjects": "Všechny projekty", + "IssueNotificationTitle": "{issueTitle}", + "IssueNotificationBody": "Aktualizováno uživatelem {senderName}", + "IssueNotificationChanged": "{senderName} změnil {property}", + "IssueNotificationChangedProperty": "{senderName} změnil {property} na \"{newValue}\"", + "IssueNotificationMessage": "{senderName}: {message}", + "PreviousAssigned": "Původně přiřazeno", + "IssueAssignedToYou": "Přiřazeno vám", + "RelatedIssueTargetDescription": "Cílový projekt pro související úkol", + "MapRelatedIssues": "Nastavit výchozí projekty pro související úkoly", + "DefaultIssueStatus": "Výchozí stav úkolu", + "IssueStatus": "Stav", + "Extensions": "Rozšíření", + "UnsetParentIssue": "Odebrat nadřazený úkol", + "ForbidCreateProjectPermission": "Zakázat vytvoření projektu", + "ForbidCreateProjectPermissionDescription": "Zakazuje uživatelům vytvářet nové projekty", + "AllowCreatingIssues": "Povolit vytváření úkolů", + "Day": "Den", + "Gantt": "Gantt", + "Month": "Měsíc", + "Quarter": "Čtvrtletí", + "Week": "Týden", + "GanttShowIssueCode": "Show issue code", + "GanttShowTitle": "Show title" + }, + "status": {} +} \ No newline at end of file diff --git a/plugins/tracker-assets/lang/de.json b/plugins/tracker-assets/lang/de.json index 51aa73d1518..eafe7e7cc44 100644 --- a/plugins/tracker-assets/lang/de.json +++ b/plugins/tracker-assets/lang/de.json @@ -1,304 +1,289 @@ { - "string": { - "TrackerApplication": "Tracker", - "Projects": "Deine Projekte", - "More": "Mehr", - "Default": "Standard", - "MakeDefault": "Als Standard festlegen", - "Delete": "Löschen", - "Open": "Öffnen", - "Members": "Mitglieder", - "Inbox": "Posteingang", - "MyIssues": "Meine Aufgaben", - "ViewIssue": "Aufgabe anzeigen", - "IssueCreated": "Aufgabe erstellt", - "Issues": "Aufgaben", - "Views": "Ansichten", - "Active": "Aktiv", - "AllIssues": "Alle Aufgaben", - "ActiveIssues": "Aktive Aufgaben", - "BacklogIssues": "Backlog", - "Backlog": "Backlog", - "Board": "Board", - "Components": "Komponenten", - "AllComponents": "Alle", - "BacklogComponents": "Backlog", - "ActiveComponents": "Aktive", - "ClosedComponents": "Geschlossen", - "NewComponent": "Neue Komponente", - "CreateComponent": "Komponente erstellen", - "ComponentNamePlaceholder": "Komponentenname", - "ComponentDescriptionPlaceholder": "Beschreibung (optional)", - "ComponentLead": "Leitung", - "ComponentMembers": "Mitglieder", - "StartDate": "Startdatum", - "TargetDate": "Zieldatum", - "Planned": "Geplant", - "InProgress": "In Bearbeitung", - "Paused": "Pausiert", - "Completed": "Abgeschlossen", - "Canceled": "Abgebrochen", - "CreateProject": "Projekt erstellen", - "NewProject": "Neues Projekt", - "ProjectTitle": "Projekttitel", - "ProjectTitlePlaceholder": "Neues Projekt", - "UsedInIssueIDs": "Verwendet in Aufgaben-IDs", - "Identifier": "Kennung", - "Import": "Importieren", - "ProjectIdentifier": "Projektkennung", - "IdentifierExists": "Projektkennung existiert bereits", - "ProjectIdentifierPlaceholder": "PRJKT", - "ChooseIcon": "Symbol wählen", - "AddIssue": "Aufgabe hinzufügen", - "NewIssue": "Neue Aufgabe", - "NewIssuePlaceholder": "Neu", - "ResumeDraft": "Entwurf fortsetzen", - "SaveIssue": "Aufgabe erstellen", - "SetPriority": "Priorität setzen...", - "SetStatus": "Status setzen...", - "SelectIssue": "Aufgabe auswählen", - "Priority": "Priorität", - "NoPriority": "Keine Priorität", - "Urgent": "Dringend", - "High": "Hoch", - "Medium": "Mittel", - "Low": "Niedrig", - "Unassigned": "Nicht zugewiesen", - "Back": "Zurück", - "List": "Liste", - "NumberLabels": "{count, plural, =0 {keine Labels} =1 {1 Label} other {# Labels}}", - - "CategoryBacklog": "Backlog", - "CategoryUnstarted": "Nicht gestartet", - "CategoryStarted": "Gestartet", - "CategoryCompleted": "Abgeschlossen", - "CategoryCanceled": "Abgebrochen", - - "Title": "Titel", - "Name": "Name", - "Description": "Beschreibung", - "Status": "Status", - "Number": "Nummer", - "Assignee": "Zugewiesen an", - "AssignTo": "Zuweisen an...", - "AssignedTo": "Zugewiesen an {value}", - "Parent": "Übergeordnete Aufgabe", - "SetParent": "Übergeordnete Aufgabe setzen...", - "ChangeParent": "Übergeordnete Aufgabe ändern...", - "RemoveParent": "Übergeordnete Aufgabe entfernen", - "OpenParent": "Übergeordnete Aufgabe öffnen", - "SubIssues": "Unteraufgaben", - "SubIssuesList": "Unteraufgaben ({subIssues})", - "OpenSubIssues": "Unteraufgaben öffnen", - "AddSubIssues": "Unteraufgabe hinzufügen", - "BlockedBy": "Blockiert durch", - "RelatedTo": "Verwandt mit", - "Comments": "Kommentare", - "Attachments": "Anhänge", - "Labels": "Labels", - "Component": "Komponente", - "Space": "", - "SetDueDate": "Fälligkeitsdatum setzen...", - "ChangeDueDate": "Fälligkeitsdatum ändern...", - "ModificationDate": "Aktualisiert am {value}", - "Project": "Projekt", - "Issue": "Aufgabe", - "SubIssue": "Unteraufgabe", - "Document": "Dokument", - "DocumentIcon": "Dokumentsymbol", - "DocumentColor": "Dokumentfarbe", - "Rank": "Rang", - "TypeIssuePriority": "Aufgabenpriorität", - "IssueTitlePlaceholder": "Aufgabentitel", - "SubIssueTitlePlaceholder": "Unteraufgabentitel", - "IssueDescriptionPlaceholder": "Beschreibung hinzufügen...", - "SubIssueDescriptionPlaceholder": "Unteraufgabenbeschreibung hinzufügen", - "AddIssueTooltip": "Aufgabe hinzufügen...", - "NewIssueDialogClose": "Möchten Sie diesen Dialog schließen?", - "NewIssueDialogCloseNote": "Alle Änderungen gehen verloren", - "RemoveComponentDialogClose": "Komponente löschen?", - "RemoveComponentDialogCloseNote": "Sind Sie sicher, dass Sie diese Komponente löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden", - "Grouping": "Gruppierung", - "Ordering": "Sortierung", - "CompletedIssues": "Abgeschlossene Aufgaben", - "NoGrouping": "Keine Gruppierung", - "NoAssignee": "Nicht zugewiesen", - "LastUpdated": "Zuletzt aktualisiert", - "DueDate": "Fälligkeitsdatum", - "IssueStartDate": "Startdatum", - "GanttDependency": "Abhängigkeit", - "GanttLag": "Verzögerung", - "Manual": "Manuell", - "All": "Alle", - "PastWeek": "Letzte Woche", - "PastMonth": "Letzter Monat", - "CopyIssueUrl": "Aufgaben-URL in Zwischenablage kopieren", - "CopyIssueId": "Aufgaben-ID in Zwischenablage kopieren", - "CopyIssueBranch": "Git-Branch-Namen in Zwischenablage kopieren", - "CopyIssueTitle": "Aufgabentitel in Zwischenablage kopieren", - "AssetLabel": "Asset", - "AddToComponent": "Zu Komponente hinzufügen...", - "MoveToComponent": "Zu Komponente verschieben...", - "NoComponent": "Keine Komponente", - "ComponentLeadTitle": "Komponentenleitung", - "ComponentMembersTitle": "Komponentenmitglieder", - "ComponentLeadSearchPlaceholder": "Komponentenleitung festlegen...", - "ComponentMembersSearchPlaceholder": "Komponentenmitglieder ändern...", - "MoveToProject": "Zu Projekt verschieben", - "Duplicate": "Duplizieren", - - "GotoIssues": "Zu Aufgaben", - "GotoActive": "Zu aktiven Aufgaben", - "GotoBacklog": "Zum Backlog", - "GotoComponents": "Zu Komponenten", - "GotoMyIssues": "Zu meinen Aufgaben", - "GotoTrackerApplication": "Zum Tracker wechseln", - - "CreatedOne": "Erstellt", - "MoveIssues": "Aufgaben verschieben", - "MoveIssuesDescription": "Wählen Sie das Zielprojekt aus", - "ManageAttributes": "Attribute verwalten", - "KeepOriginalAttributes": "Ursprüngliche Attribute beibehalten", - "KeepOriginalAttributesTooltip": "Ursprüngliche Aufgabenstatus und Komponenten werden im neuen Projekt beibehalten", - "SelectReplacement": "Die folgenden Elemente sind im neuen Projekt nicht verfügbar. Wählen Sie einen Ersatz.", - "MissingItem": "FEHLENDES ELEMENT", - "Replacement": "ERSATZ", - "Original": "ORIGINAL", - "OriginalDescription": "Elemente aus diesem Bereich werden im neuen Projekt erstellt", - - "Relations": "Beziehungen", - "RemoveRelation": "Beziehung entfernen...", - "AddBlockedBy": "Als blockiert markieren durch...", - "AddIsBlocking": "Als blockierend markieren...", - "AddRelatedIssue": "Andere Aufgabe referenzieren...", - "RelatedIssue": "Verwandte Aufgabe {id} - {title}", - "BlockedIssue": "Blockierte Aufgabe {id} - {title}", - "BlockingIssue": "Blockierende Aufgabe {id} - {title}", - "BlockedBySearchPlaceholder": "Nach blockierender Aufgabe suchen...", - "IsBlockingSearchPlaceholder": "Nach zu blockierender Aufgabe suchen...", - "RelatedIssueSearchPlaceholder": "Nach zu referenzierender Aufgabe suchen...", - "Blocks": "Blockiert", - "Related": "Verwandt", - "RelatedIssues": "Verwandte Aufgaben", - - "EditIssue": "{title} bearbeiten", - "EditWorkflowStatuses": "Aufgabenstatus bearbeiten", - "EditProject": "Projekt bearbeiten", - "DeleteProject": "Projekt löschen", - "ArchiveProjectName": "Projekt {name} archivieren?", - "ArchiveProjectConfirm": "Möchten Sie dieses Projekt archivieren?", - "DeleteProjectConfirm": "Möchten Sie dieses Projekt und alle Aufgaben löschen?", - "ProjectHasIssues": "Es gibt bestehende Aufgaben in diesem Projekt. Sind Sie sicher, dass Sie archivieren möchten?", - "ManageWorkflowStatuses": "Projekttypen verwalten", - "AddWorkflowStatus": "Aufgabenstatus hinzufügen", - "EditWorkflowStatus": "Aufgabenstatus bearbeiten", - "DeleteWorkflowStatus": "Aufgabenstatus löschen", - "DeleteWorkflowStatusConfirm": "Möchten Sie den Status \"{status}\" löschen?", - "DeleteWorkflowStatusErrorDescription": "Dem Status \"{status}\" sind {count, plural, =1 {1 Aufgabe} other {# Aufgaben}} zugewiesen. Bitte wählen Sie einen neuen Status", - - "Save": "Speichern", - "IncludeItemsThatMatch": "Elemente einschließen, die übereinstimmen mit", - "AnyFilter": "einem Filter", - "AllFilters": "allen Filtern", - "NoDescription": "Keine Beschreibung", - "SearchIssue": "Nach Aufgabe suchen...", - - "StatusHistory": "Statusverlauf", - "NewSubIssue": "Unteraufgabe hinzufügen...", - "AddLabel": "Label hinzufügen", - - "DeleteIssue": "{issueCount, plural, =1 {Aufgabe} other {# Aufgaben}} löschen", - "DeleteIssueConfirm": "Möchten Sie {issueCount, plural, =1 {die Aufgabe} other {die Aufgaben}}{subIssueCount, plural, =0 {} =1 { und Unteraufgabe} other { und Unteraufgaben}} löschen?", - - "Milestone": "Meilenstein", - "NoMilestone": "Kein Meilenstein", - "MoveToMilestone": "Meilenstein auswählen", - "Milestones": "Meilensteine", - "AllMilestones": "Alle", - "PlannedMilestones": "Geplant", - "ActiveMilestones": "Aktiv", - "ClosedMilestones": "Abgeschlossen", - "AddToMilestone": "Zu Meilenstein hinzufügen", - "MilestoneNamePlaceholder": "Meilensteinname", - - "NewMilestone": "Neuer Meilenstein", - "CreateMilestone": "Erstellen", - - "MoveAndDeleteMilestone": "Aufgaben zu {newMilestone} verschieben und {deleteMilestone} löschen", - "MoveAndDeleteMilestoneConfirm": "Möchten Sie den Meilenstein löschen und die Aufgaben zu einem anderen Meilenstein verschieben?", - - "Estimation": "Schätzung", - "ReportedTime": "Aufgewendete Zeit", - "RemainingTime": "Verbleibende Zeit", - "TimeSpendReports": "Zeiterfassungsberichte", - "TimeSpendReport": "Zeit", - "TimeSpendReportAdd": "Zeiterfassung hinzufügen", - "TimeSpendReportDate": "Datum", - "TimeSpendReportValue": "Aufgewendete Zeit", - "TimeSpendReportValueTooltip": "Aufgewendete Zeit in Stunden", - "TimeSpendReportDescription": "Beschreibung", - "TimeSpendDays": "{value}T", - "TimeSpendHours": "{value}Std", - "TimeSpendMinutes": "{value}Min", - "ChildEstimation": "Schätzung Unteraufgaben", - "ChildReportedTime": "Zeit Unteraufgaben", - "CapacityValue": "von {value}T", - "NewRelatedIssue": "Neue verwandte Aufgabe", - "RelatedIssuesNotFound": "Keine verwandten Aufgaben gefunden", - - "AddedReference": "Referenz hinzugefügt", - "AddedAsBlocked": "Als blockiert markiert", - "AddedAsBlocking": "Als blockierend markiert", - - "IssueTemplate": "Vorlage", - "IssueTemplates": "Vorlagen", - "NewProcess": "Neue Vorlage", - "SaveProcess": "Vorlage speichern", - "NoIssueTemplate": "Keine Vorlage", - "TemplateReplace": "Möchten Sie die neue Vorlage anwenden?", - "TemplateReplaceConfirm": "Alle Felder werden mit den Werten der neuen Vorlage überschrieben", - "Apply": "Anwenden", - - "CurrentWorkDay": "Aktueller Arbeitstag", - "PreviousWorkDay": "Vorheriger Arbeitstag", - "TimeReportDayTypeLabel": "Art des Zeiterfassungstags auswählen", - "DefaultAssignee": "Standardzuweisung für Aufgaben", - - "SevenHoursLength": "Sieben Stunden", - "EightHoursLength": "Acht Stunden", - "HourLabel": "Std", - "MinuteLabel": "Min", - "Saved": "Gespeichert...", - "CreatedIssue": "Aufgabe erstellt", - "CreatedSubIssue": "Unteraufgabe erstellt", - "ChangeStatus": "Status ändern", - "ConfigLabel": "Tracker", - "ConfigDescription": "Erweiterung zur Verwaltung von Arbeitsaufgaben und deren Erledigung.", - "NoStatusFound": "Kein passender Status gefunden", - "CreateMissingStatus": "Fehlenden Status erstellen", - "UnsetParent": "Übergeordnete Aufgabe wird entfernt", - "AllProjects": "Alle Projekte", - "IssueNotificationTitle": "{issueTitle}", - "IssueNotificationBody": "Aktualisiert von {senderName}", - "IssueNotificationChanged": "{senderName} hat {property} geändert", - "IssueNotificationChangedProperty": "{senderName} hat {property} zu \"{newValue}\" geändert", - "IssueNotificationMessage": "{senderName}: {message}", - "PreviousAssigned": "Zuvor zugewiesen", - "IssueAssignedToYou": "Ihnen zugewiesen", - "RelatedIssueTargetDescription": "Zielprojekt für verwandte Aufgaben für Klasse oder Space", - "MapRelatedIssues": "Standard-Projekte für verwandte Aufgaben konfigurieren", - "DefaultIssueStatus": "Standard-Aufgabenstatus", - "IssueStatus": "Status", - "Extensions": "Erweiterungen", - "UnsetParentIssue": "Übergeordnete Aufgabe entfernen", - "ForbidCreateProjectPermission": "Projekterstellung verbieten", - "ForbidCreateProjectPermissionDescription": "Verbietet Benutzern das Erstellen neuer Projekte", - "AllowCreatingIssues": "Erstellen von Aufgaben erlauben", - "Day": "Tag", - "Gantt": "Gantt", - "Month": "Monat", - "Quarter": "Quartal", - "Week": "Woche" - }, - "status": {} -} + "string": { + "TrackerApplication": "Tracker", + "Projects": "Deine Projekte", + "More": "Mehr", + "Default": "Standard", + "MakeDefault": "Als Standard festlegen", + "Delete": "Löschen", + "Open": "Öffnen", + "Members": "Mitglieder", + "Inbox": "Posteingang", + "MyIssues": "Meine Aufgaben", + "ViewIssue": "Aufgabe anzeigen", + "IssueCreated": "Aufgabe erstellt", + "Issues": "Aufgaben", + "Views": "Ansichten", + "Active": "Aktiv", + "AllIssues": "Alle Aufgaben", + "ActiveIssues": "Aktive Aufgaben", + "BacklogIssues": "Backlog", + "Backlog": "Backlog", + "Board": "Board", + "Components": "Komponenten", + "AllComponents": "Alle", + "BacklogComponents": "Backlog", + "ActiveComponents": "Aktive", + "ClosedComponents": "Geschlossen", + "NewComponent": "Neue Komponente", + "CreateComponent": "Komponente erstellen", + "ComponentNamePlaceholder": "Komponentenname", + "ComponentDescriptionPlaceholder": "Beschreibung (optional)", + "ComponentLead": "Leitung", + "ComponentMembers": "Mitglieder", + "StartDate": "Startdatum", + "TargetDate": "Zieldatum", + "Planned": "Geplant", + "InProgress": "In Bearbeitung", + "Paused": "Pausiert", + "Completed": "Abgeschlossen", + "Canceled": "Abgebrochen", + "CreateProject": "Projekt erstellen", + "NewProject": "Neues Projekt", + "ProjectTitle": "Projekttitel", + "ProjectTitlePlaceholder": "Neues Projekt", + "UsedInIssueIDs": "Verwendet in Aufgaben-IDs", + "Identifier": "Kennung", + "Import": "Importieren", + "ProjectIdentifier": "Projektkennung", + "IdentifierExists": "Projektkennung existiert bereits", + "ProjectIdentifierPlaceholder": "PRJKT", + "ChooseIcon": "Symbol wählen", + "AddIssue": "Aufgabe hinzufügen", + "NewIssue": "Neue Aufgabe", + "NewIssuePlaceholder": "Neu", + "ResumeDraft": "Entwurf fortsetzen", + "SaveIssue": "Aufgabe erstellen", + "SetPriority": "Priorität setzen...", + "SetStatus": "Status setzen...", + "SelectIssue": "Aufgabe auswählen", + "Priority": "Priorität", + "NoPriority": "Keine Priorität", + "Urgent": "Dringend", + "High": "Hoch", + "Medium": "Mittel", + "Low": "Niedrig", + "Unassigned": "Nicht zugewiesen", + "Back": "Zurück", + "List": "Liste", + "NumberLabels": "{count, plural, =0 {keine Labels} =1 {1 Label} other {# Labels}}", + "CategoryBacklog": "Backlog", + "CategoryUnstarted": "Nicht gestartet", + "CategoryStarted": "Gestartet", + "CategoryCompleted": "Abgeschlossen", + "CategoryCanceled": "Abgebrochen", + "Title": "Titel", + "Name": "Name", + "Description": "Beschreibung", + "Status": "Status", + "Number": "Nummer", + "Assignee": "Zugewiesen an", + "AssignTo": "Zuweisen an...", + "AssignedTo": "Zugewiesen an {value}", + "Parent": "Übergeordnete Aufgabe", + "SetParent": "Übergeordnete Aufgabe setzen...", + "ChangeParent": "Übergeordnete Aufgabe ändern...", + "RemoveParent": "Übergeordnete Aufgabe entfernen", + "OpenParent": "Übergeordnete Aufgabe öffnen", + "SubIssues": "Unteraufgaben", + "SubIssuesList": "Unteraufgaben ({subIssues})", + "OpenSubIssues": "Unteraufgaben öffnen", + "AddSubIssues": "Unteraufgabe hinzufügen", + "BlockedBy": "Blockiert durch", + "RelatedTo": "Verwandt mit", + "Comments": "Kommentare", + "Attachments": "Anhänge", + "Labels": "Labels", + "Component": "Komponente", + "Space": "", + "SetDueDate": "Fälligkeitsdatum setzen...", + "ChangeDueDate": "Fälligkeitsdatum ändern...", + "ModificationDate": "Aktualisiert am {value}", + "Project": "Projekt", + "Issue": "Aufgabe", + "SubIssue": "Unteraufgabe", + "Document": "Dokument", + "DocumentIcon": "Dokumentsymbol", + "DocumentColor": "Dokumentfarbe", + "Rank": "Rang", + "TypeIssuePriority": "Aufgabenpriorität", + "IssueTitlePlaceholder": "Aufgabentitel", + "SubIssueTitlePlaceholder": "Unteraufgabentitel", + "IssueDescriptionPlaceholder": "Beschreibung hinzufügen...", + "SubIssueDescriptionPlaceholder": "Unteraufgabenbeschreibung hinzufügen", + "AddIssueTooltip": "Aufgabe hinzufügen...", + "NewIssueDialogClose": "Möchten Sie diesen Dialog schließen?", + "NewIssueDialogCloseNote": "Alle Änderungen gehen verloren", + "RemoveComponentDialogClose": "Komponente löschen?", + "RemoveComponentDialogCloseNote": "Sind Sie sicher, dass Sie diese Komponente löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden", + "Grouping": "Gruppierung", + "Ordering": "Sortierung", + "CompletedIssues": "Abgeschlossene Aufgaben", + "NoGrouping": "Keine Gruppierung", + "NoAssignee": "Nicht zugewiesen", + "LastUpdated": "Zuletzt aktualisiert", + "DueDate": "Fälligkeitsdatum", + "IssueStartDate": "Startdatum", + "GanttDependency": "Abhängigkeit", + "GanttLag": "Verzögerung", + "Manual": "Manuell", + "All": "Alle", + "PastWeek": "Letzte Woche", + "PastMonth": "Letzter Monat", + "CopyIssueUrl": "Aufgaben-URL in Zwischenablage kopieren", + "CopyIssueId": "Aufgaben-ID in Zwischenablage kopieren", + "CopyIssueBranch": "Git-Branch-Namen in Zwischenablage kopieren", + "CopyIssueTitle": "Aufgabentitel in Zwischenablage kopieren", + "AssetLabel": "Asset", + "AddToComponent": "Zu Komponente hinzufügen...", + "MoveToComponent": "Zu Komponente verschieben...", + "NoComponent": "Keine Komponente", + "ComponentLeadTitle": "Komponentenleitung", + "ComponentMembersTitle": "Komponentenmitglieder", + "ComponentLeadSearchPlaceholder": "Komponentenleitung festlegen...", + "ComponentMembersSearchPlaceholder": "Komponentenmitglieder ändern...", + "MoveToProject": "Zu Projekt verschieben", + "Duplicate": "Duplizieren", + "GotoIssues": "Zu Aufgaben", + "GotoActive": "Zu aktiven Aufgaben", + "GotoBacklog": "Zum Backlog", + "GotoComponents": "Zu Komponenten", + "GotoMyIssues": "Zu meinen Aufgaben", + "GotoTrackerApplication": "Zum Tracker wechseln", + "CreatedOne": "Erstellt", + "MoveIssues": "Aufgaben verschieben", + "MoveIssuesDescription": "Wählen Sie das Zielprojekt aus", + "ManageAttributes": "Attribute verwalten", + "KeepOriginalAttributes": "Ursprüngliche Attribute beibehalten", + "KeepOriginalAttributesTooltip": "Ursprüngliche Aufgabenstatus und Komponenten werden im neuen Projekt beibehalten", + "SelectReplacement": "Die folgenden Elemente sind im neuen Projekt nicht verfügbar. Wählen Sie einen Ersatz.", + "MissingItem": "FEHLENDES ELEMENT", + "Replacement": "ERSATZ", + "Original": "ORIGINAL", + "OriginalDescription": "Elemente aus diesem Bereich werden im neuen Projekt erstellt", + "Relations": "Beziehungen", + "RemoveRelation": "Beziehung entfernen...", + "AddBlockedBy": "Als blockiert markieren durch...", + "AddIsBlocking": "Als blockierend markieren...", + "AddRelatedIssue": "Andere Aufgabe referenzieren...", + "RelatedIssue": "Verwandte Aufgabe {id} - {title}", + "BlockedIssue": "Blockierte Aufgabe {id} - {title}", + "BlockingIssue": "Blockierende Aufgabe {id} - {title}", + "BlockedBySearchPlaceholder": "Nach blockierender Aufgabe suchen...", + "IsBlockingSearchPlaceholder": "Nach zu blockierender Aufgabe suchen...", + "RelatedIssueSearchPlaceholder": "Nach zu referenzierender Aufgabe suchen...", + "Blocks": "Blockiert", + "Related": "Verwandt", + "RelatedIssues": "Verwandte Aufgaben", + "EditIssue": "{title} bearbeiten", + "EditWorkflowStatuses": "Aufgabenstatus bearbeiten", + "EditProject": "Projekt bearbeiten", + "DeleteProject": "Projekt löschen", + "ArchiveProjectName": "Projekt {name} archivieren?", + "ArchiveProjectConfirm": "Möchten Sie dieses Projekt archivieren?", + "DeleteProjectConfirm": "Möchten Sie dieses Projekt und alle Aufgaben löschen?", + "ProjectHasIssues": "Es gibt bestehende Aufgaben in diesem Projekt. Sind Sie sicher, dass Sie archivieren möchten?", + "ManageWorkflowStatuses": "Projekttypen verwalten", + "AddWorkflowStatus": "Aufgabenstatus hinzufügen", + "EditWorkflowStatus": "Aufgabenstatus bearbeiten", + "DeleteWorkflowStatus": "Aufgabenstatus löschen", + "DeleteWorkflowStatusConfirm": "Möchten Sie den Status \"{status}\" löschen?", + "DeleteWorkflowStatusErrorDescription": "Dem Status \"{status}\" sind {count, plural, =1 {1 Aufgabe} other {# Aufgaben}} zugewiesen. Bitte wählen Sie einen neuen Status", + "Save": "Speichern", + "IncludeItemsThatMatch": "Elemente einschließen, die übereinstimmen mit", + "AnyFilter": "einem Filter", + "AllFilters": "allen Filtern", + "NoDescription": "Keine Beschreibung", + "SearchIssue": "Nach Aufgabe suchen...", + "StatusHistory": "Statusverlauf", + "NewSubIssue": "Unteraufgabe hinzufügen...", + "AddLabel": "Label hinzufügen", + "DeleteIssue": "{issueCount, plural, =1 {Aufgabe} other {# Aufgaben}} löschen", + "DeleteIssueConfirm": "Möchten Sie {issueCount, plural, =1 {die Aufgabe} other {die Aufgaben}}{subIssueCount, plural, =0 {} =1 { und Unteraufgabe} other { und Unteraufgaben}} löschen?", + "Milestone": "Meilenstein", + "NoMilestone": "Kein Meilenstein", + "MoveToMilestone": "Meilenstein auswählen", + "Milestones": "Meilensteine", + "AllMilestones": "Alle", + "PlannedMilestones": "Geplant", + "ActiveMilestones": "Aktiv", + "ClosedMilestones": "Abgeschlossen", + "AddToMilestone": "Zu Meilenstein hinzufügen", + "MilestoneNamePlaceholder": "Meilensteinname", + "NewMilestone": "Neuer Meilenstein", + "CreateMilestone": "Erstellen", + "MoveAndDeleteMilestone": "Aufgaben zu {newMilestone} verschieben und {deleteMilestone} löschen", + "MoveAndDeleteMilestoneConfirm": "Möchten Sie den Meilenstein löschen und die Aufgaben zu einem anderen Meilenstein verschieben?", + "Estimation": "Schätzung", + "ReportedTime": "Aufgewendete Zeit", + "RemainingTime": "Verbleibende Zeit", + "TimeSpendReports": "Zeiterfassungsberichte", + "TimeSpendReport": "Zeit", + "TimeSpendReportAdd": "Zeiterfassung hinzufügen", + "TimeSpendReportDate": "Datum", + "TimeSpendReportValue": "Aufgewendete Zeit", + "TimeSpendReportValueTooltip": "Aufgewendete Zeit in Stunden", + "TimeSpendReportDescription": "Beschreibung", + "TimeSpendDays": "{value}T", + "TimeSpendHours": "{value}Std", + "TimeSpendMinutes": "{value}Min", + "ChildEstimation": "Schätzung Unteraufgaben", + "ChildReportedTime": "Zeit Unteraufgaben", + "CapacityValue": "von {value}T", + "NewRelatedIssue": "Neue verwandte Aufgabe", + "RelatedIssuesNotFound": "Keine verwandten Aufgaben gefunden", + "AddedReference": "Referenz hinzugefügt", + "AddedAsBlocked": "Als blockiert markiert", + "AddedAsBlocking": "Als blockierend markiert", + "IssueTemplate": "Vorlage", + "IssueTemplates": "Vorlagen", + "NewProcess": "Neue Vorlage", + "SaveProcess": "Vorlage speichern", + "NoIssueTemplate": "Keine Vorlage", + "TemplateReplace": "Möchten Sie die neue Vorlage anwenden?", + "TemplateReplaceConfirm": "Alle Felder werden mit den Werten der neuen Vorlage überschrieben", + "Apply": "Anwenden", + "CurrentWorkDay": "Aktueller Arbeitstag", + "PreviousWorkDay": "Vorheriger Arbeitstag", + "TimeReportDayTypeLabel": "Art des Zeiterfassungstags auswählen", + "DefaultAssignee": "Standardzuweisung für Aufgaben", + "SevenHoursLength": "Sieben Stunden", + "EightHoursLength": "Acht Stunden", + "HourLabel": "Std", + "MinuteLabel": "Min", + "Saved": "Gespeichert...", + "CreatedIssue": "Aufgabe erstellt", + "CreatedSubIssue": "Unteraufgabe erstellt", + "ChangeStatus": "Status ändern", + "ConfigLabel": "Tracker", + "ConfigDescription": "Erweiterung zur Verwaltung von Arbeitsaufgaben und deren Erledigung.", + "NoStatusFound": "Kein passender Status gefunden", + "CreateMissingStatus": "Fehlenden Status erstellen", + "UnsetParent": "Übergeordnete Aufgabe wird entfernt", + "AllProjects": "Alle Projekte", + "IssueNotificationTitle": "{issueTitle}", + "IssueNotificationBody": "Aktualisiert von {senderName}", + "IssueNotificationChanged": "{senderName} hat {property} geändert", + "IssueNotificationChangedProperty": "{senderName} hat {property} zu \"{newValue}\" geändert", + "IssueNotificationMessage": "{senderName}: {message}", + "PreviousAssigned": "Zuvor zugewiesen", + "IssueAssignedToYou": "Ihnen zugewiesen", + "RelatedIssueTargetDescription": "Zielprojekt für verwandte Aufgaben für Klasse oder Space", + "MapRelatedIssues": "Standard-Projekte für verwandte Aufgaben konfigurieren", + "DefaultIssueStatus": "Standard-Aufgabenstatus", + "IssueStatus": "Status", + "Extensions": "Erweiterungen", + "UnsetParentIssue": "Übergeordnete Aufgabe entfernen", + "ForbidCreateProjectPermission": "Projekterstellung verbieten", + "ForbidCreateProjectPermissionDescription": "Verbietet Benutzern das Erstellen neuer Projekte", + "AllowCreatingIssues": "Erstellen von Aufgaben erlauben", + "Day": "Tag", + "Gantt": "Gantt", + "Month": "Monat", + "Quarter": "Quartal", + "Week": "Woche", + "GanttShowIssueCode": "Show issue code", + "GanttShowTitle": "Show title" + }, + "status": {} +} \ No newline at end of file diff --git a/plugins/tracker-assets/lang/en.json b/plugins/tracker-assets/lang/en.json index 7dad04bee41..e47d9b284c9 100644 --- a/plugins/tracker-assets/lang/en.json +++ b/plugins/tracker-assets/lang/en.json @@ -298,7 +298,9 @@ "Gantt": "Gantt", "Month": "Month", "Quarter": "Quarter", - "Week": "Week" + "Week": "Week", + "GanttShowIssueCode": "Show issue code", + "GanttShowTitle": "Show title" }, "status": {} } diff --git a/plugins/tracker-assets/lang/es.json b/plugins/tracker-assets/lang/es.json index 127dc0a4f63..35cd60a1e00 100644 --- a/plugins/tracker-assets/lang/es.json +++ b/plugins/tracker-assets/lang/es.json @@ -1,287 +1,289 @@ { - "string": { - "TrackerApplication": "Seguimiento", - "Projects": "Tus proyectos", - "More": "Más", - "Default": "Por defecto", - "MakeDefault": "Establecer como por defecto", - "Delete": "Eliminar", - "Open": "Abrir", - "Members": "Miembros", - "Inbox": "Bandeja de entrada", - "MyIssues": "Mis tareas", - "ViewIssue": "Ver tarea", - "IssueCreated": "Tarea creada", - "Issues": "Tareas", - "Views": "Vistas", - "Active": "Activo", - "AllIssues": "Todas las tareas", - "ActiveIssues": "Tareas activas", - "BacklogIssues": "Atrasadas", - "Backlog": "Atrasadas", - "Board": "Tablero", - "Components": "Componentes", - "AllComponents": "Todos", - "BacklogComponents": "Atrasados", - "ActiveComponents": "Activos", - "ClosedComponents": "Cerrados", - "NewComponent": "Nuevo componente", - "CreateComponent": "Crear componente", - "ComponentNamePlaceholder": "Nombre del componente", - "ComponentDescriptionPlaceholder": "Descripción (opcional)", - "ComponentLead": "Responsable del componente", - "ComponentMembers": "Miembros del componente", - "StartDate": "Fecha de inicio", - "TargetDate": "Fecha objetivo", - "Planned": "Planificado", - "InProgress": "En progreso", - "Paused": "Pausado", - "Completed": "Completado", - "Canceled": "Cancelado", - "CreateProject": "Crear proyecto", - "NewProject": "Nuevo proyecto", - "ProjectTitle": "Título del proyecto", - "ProjectTitlePlaceholder": "Nuevo proyecto", - "UsedInIssueIDs": "Utilizado en IDs de tareas", - "Identifier": "Identificador", - "Import": "Importar", - "ProjectIdentifier": "Identificador del proyecto", - "IdentifierExists": "El identificador del proyecto ya existe", - "ProjectIdentifierPlaceholder": "PROJ", - "ChooseIcon": "Seleccionar icono", - "AddIssue": "Añadir tarea", - "NewIssue": "Nueva tarea", - "NewIssuePlaceholder": "Nueva", - "ResumeDraft": "Continuar borrador", - "SaveIssue": "Crear tarea", - "SetPriority": "Establecer prioridad\u2026", - "SetStatus": "Establecer estado\u2026", - "SelectIssue": "Seleccionar tarea", - "Priority": "Prioridad", - "NoPriority": "Sin prioridad", - "Urgent": "Urgente", - "High": "Alta", - "Medium": "Media", - "Low": "Baja", - "Unassigned": "Sin asignar", - "Back": "Atrás", - "List": "Lista", - "NumberLabels": "{count, plural, =0 {sin etiquetas} =1 {1 etiqueta} other {# etiquetas}}", - "CategoryBacklog": "Atraso", - "CategoryUnstarted": "Por Iniciar", - "CategoryStarted": "Iniciado", - "CategoryCompleted": "Completado", - "CategoryCanceled": "Cancelado", - "Title": "Título", - "Name": "Nombre", - "Description": "Descripción", - "Status": "Estado", - "Number": "Número", - "Assignee": "Asignado a", - "AssignTo": "Asignar a...", - "AssignedTo": "Asignado a {value}", - "Parent": "Tarea principal", - "SetParent": "Establecer tarea principal...", - "ChangeParent": "Cambiar tarea principal...", - "RemoveParent": "Eliminar tarea principal", - "OpenParent": "Abrir tarea principal", - "SubIssues": "Subtareas", - "SubIssuesList": "Subtareas ({subIssues})", - "OpenSubIssues": "Abrir subtareas", - "AddSubIssues": "Añadir subtarea", - "BlockedBy": "Bloqueado por", - "RelatedTo": "Relacionado con", - "Comments": "Comentarios", - "Attachments": "Adjuntos", - "Labels": "Etiquetas", - "Component": "Componente", - "Space": "", - "SetDueDate": "Establecer fecha de vencimiento...", - "ChangeDueDate": "Cambiar fecha de vencimiento...", - "ModificationDate": "Actualizado {value}", - "Project": "Proyecto", - "Issue": "Tarea", - "SubIssue": "Subtarea", - "Document": "", - "DocumentIcon": "", - "DocumentColor": "", - "Rank": "Posición", - "TypeIssuePriority": "Prioridad de la tarea", - "IssueTitlePlaceholder": "Título de la tarea", - "SubIssueTitlePlaceholder": "Título de la subtarea", - "IssueDescriptionPlaceholder": "Añadir descripción...", - "SubIssueDescriptionPlaceholder": "Añadir descripción de la subtarea", - "AddIssueTooltip": "Añadir tarea...", - "NewIssueDialogClose": "¿Quieres cerrar este diálogo?", - "NewIssueDialogCloseNote": "Se perderán todos los cambios", - "RemoveComponentDialogClose": "¿Eliminar el componente?", - "RemoveComponentDialogCloseNote": "¿Estás seguro de que quieres eliminar este componente? Esta operación no se puede deshacer", - "Grouping": "Agrupación", - "Ordering": "Ordenación", - "CompletedIssues": "Tareas completadas", - "NoGrouping": "Sin agrupación", - "NoAssignee": "Sin asignar", - "LastUpdated": "Última actualización", - "DueDate": "Fecha de vencimiento", - "IssueStartDate": "Fecha de inicio", - "GanttDependency": "Dependency", - "GanttLag": "Lag", - "Manual": "Manual", - "All": "Todos", - "PastWeek": "Semana pasada", - "PastMonth": "Mes pasado", - "CopyIssueUrl": "Copiar URL de la tarea al portapapeles", - "CopyIssueId": "Copiar ID de la tarea al portapapeles", - "CopyIssueBranch": "Copiar nombre de la rama Git al portapapeles", - "CopyIssueTitle": "Copiar título de la tarea al portapapeles", - "AssetLabel": "Activo", - "AddToComponent": "Añadir al componente...", - "MoveToComponent": "Mover al componente...", - "NoComponent": "Sin componente", - "ComponentLeadTitle": "Responsable del componente", - "ComponentMembersTitle": "Miembros del componente", - "ComponentLeadSearchPlaceholder": "Establecer responsable del componente...", - "ComponentMembersSearchPlaceholder": "Cambiar miembros del componente...", - "MoveToProject": "Mover al proyecto", - "Duplicate": "Duplicar", - "GotoIssues": "Ir a tareas", - "GotoActive": "Ir a tareas activas", - "GotoBacklog": "Ir al backlog", - "GotoComponents": "Ir a componentes", - "GotoMyIssues": "Ir a mis tareas", - "GotoTrackerApplication": "Cambiar a la aplicación de seguimiento", - "CreatedOne": "Creada", - "MoveIssues": "Mover tareas", - "MoveIssuesDescription": "Selecciona el proyecto al que deseas mover las tareas", - "ManageAttributes": "Gestionar atributos", - "KeepOriginalAttributes": "Mantener atributos originales", - "KeepOriginalAttributesTooltip": "Se mantendrán los estados y componentes originales en el nuevo proyecto", - "SelectReplacement": "Los siguientes elementos no están disponibles en el nuevo proyecto. Seleccione un reemplazo.", - "MissingItem": "SIN ELEMENTO", - "Replacement": "REEMPLAZO", - "Original": "ORIGINAL", - "OriginalDescription": "Los elementos de esta sección se crearán en el nuevo proyecto", - "Relations": "Relaciones", - "RemoveRelation": "Eliminar relación...", - "AddBlockedBy": "Marcar como bloqueado por...", - "AddIsBlocking": "Marcar como bloqueador...", - "AddRelatedIssue": "Referenciar otro problema...", - "RelatedIssue": "Problema relacionado {id} - {title}", - "BlockedIssue": "Problema bloqueado {id} - {title}", - "BlockingIssue": "Problema bloqueador {id} - {title}", - "BlockedBySearchPlaceholder": "Buscar problema para marcar como bloqueado por...", - "IsBlockingSearchPlaceholder": "Buscar problema para marcar como bloqueador...", - "RelatedIssueSearchPlaceholder": "Buscar problema para referenciar...", - "Blocks": "Bloquea", - "Related": "Relacionado", - "RelatedIssues": "Problemas relacionados", - "EditIssue": "Editar {title}", - "EditWorkflowStatuses": "Editar estados de problema", - "EditProject": "Editar proyecto", - "DeleteProject": "Eliminar proyecto", - "ArchiveProjectName": "¿Archivar proyecto {name}?", - "ArchiveProjectConfirm": "¿Desea archivar este proyecto?", - "DeleteProjectConfirm": "¿Desea eliminar este proyecto y todos los problemas?", - "ProjectHasIssues": "Hay problemas existentes en este proyecto, ¿está seguro de que desea archivarlos?", - "ManageWorkflowStatuses": "Administrar tipos de proyecto", - "AddWorkflowStatus": "Agregar estado de problema", - "EditWorkflowStatus": "Editar estado de problema", - "DeleteWorkflowStatus": "Eliminar estado de problema", - "DeleteWorkflowStatusConfirm": "¿Desea eliminar el estado \"{status}\"?", - "DeleteWorkflowStatusErrorDescription": "El estado \"{status}\" tiene {count, plural, =1 {1 problema} other {# problemas}} asignados. Por favor seleccione un estado al que moverlos", - "Save": "Guardar", - "IncludeItemsThatMatch": "Incluir elementos que coincidan", - "AnyFilter": "cualquier filtro", - "AllFilters": "todos los filtros", - "NoDescription": "Sin descripción", - "SearchIssue": "Buscar tarea...", - "StatusHistory": "Historial de estado", - "NewSubIssue": "Agregar subproblema...", - "AddLabel": "Agregar etiqueta", - "DeleteIssue": "Eliminar {issueCount, plural, =1 {problema} other {# problemas}}", - "DeleteIssueConfirm": "¿Desea eliminar {issueCount, plural, =1 {problema} other {problemas}}{subIssueCount, plural, =0 {?} =1 { y subproblema?} other { y subproblemas?}}", - "Milestone": "Hitos", - "NoMilestone": "Sin hito", - "MoveToMilestone": "Seleccionar hito", - "Milestones": "Hitos", - "AllMilestones": "Todos", - "PlannedMilestones": "Planificados", - "ActiveMilestones": "Activos", - "ClosedMilestones": "Completados", - "AddToMilestone": "Agregar a hito", - "MilestoneNamePlaceholder": "Nombre del hito", - "NewMilestone": "Nuevo hito", - "CreateMilestone": "Crear", - "MoveAndDeleteMilestone": "Mover problemas a {newMilestone} y eliminar {deleteMilestone}", - "MoveAndDeleteMilestoneConfirm": "¿Desea eliminar el hito y mover los problemas a otro hito?", - "Estimation": "Estimación", - "ReportedTime": "Tiempo empleado", - "RemainingTime": "Tiempo restante", - "TimeSpendReports": "Informes de tiempo empleado", - "TimeSpendReport": "Tiempo", - "TimeSpendReportAdd": "Agregar informe de tiempo", - "TimeSpendReportDate": "Fecha", - "TimeSpendReportValue": "Tiempo empleado", - "TimeSpendReportValueTooltip": "Tiempo empleado en horas", - "TimeSpendReportDescription": "Descripción", - "TimeSpendDays": "{value}d", - "TimeSpendHours": "{value}h", - "TimeSpendMinutes": "{value}m", - "ChildEstimation": "Estimación de subtemas", - "ChildReportedTime": "Tiempo de subtemas", - "CapacityValue": "de {value}d", - "NewRelatedIssue": "Nuevo problema relacionado", - "RelatedIssuesNotFound": "Problemas relacionados no encontrados", - "AddedReference": "Referencia añadida", - "AddedAsBlocked": "Marcado como bloqueado", - "AddedAsBlocking": "Marcado como bloqueante", - "IssueTemplate": "Plantilla", - "IssueTemplates": "Plantillas", - "NewProcess": "Nueva plantilla", - "SaveProcess": "Guardar plantilla", - "NoIssueTemplate": "Sin plantilla", - "TemplateReplace": "¿Desea aplicar la nueva plantilla?", - "TemplateReplaceConfirm": "Todos los campos serán sobrescritos por los valores de la nueva plantilla", - "Apply": "Aplicar", - "CurrentWorkDay": "Día laboral actual", - "PreviousWorkDay": "Día laboral anterior", - "TimeReportDayTypeLabel": "Seleccionar tipo de día para reporte de tiempo", - "DefaultAssignee": "Asignado por defecto para problemas", - "SevenHoursLength": "Siete horas", - "EightHoursLength": "Ocho horas", - "HourLabel": "h", - "MinuteLabel": "m", - "Saved": "Guardado...", - "CreatedIssue": "Problema creado", - "CreatedSubIssue": "Sub-problema creado", - "ChangeStatus": "Cambiar estado", - "ConfigLabel": "Rastreador", - "ConfigDescription": "Extensión para gestionar elementos de trabajo y realizar todas las tareas realizadas.", - "NoStatusFound": "No se encontró ningún estado coincidente", - "CreateMissingStatus": "Crear estado faltante", - "UnsetParent": "El problema padre será desmarcado", - "AllProjects": "Todos los proyectos", - "IssueNotificationTitle": "{issueTitle}", - "IssueNotificationBody": "Actualizado por {senderName}", - "IssueNotificationChanged": "{senderName} cambió {property}", - "IssueNotificationChangedProperty": "{senderName} cambió {property} a \"{newValue}\"", - "IssueNotificationMessage": "{senderName}: {message}", - "PreviousAssigned": "Anteriormente asignado", - "IssueAssignedToYou": "Asignado a ti", - "RelatedIssueTargetDescription": "Proyecto de destino de problema relacionado para Clase o Espacio", - "MapRelatedIssues": "Configurar proyectos predeterminados de problemas relacionados", - "DefaultIssueStatus": "Estado de problema predeterminado", - "IssueStatus": "Estado", - "Extensions": "Extensions", - "UnsetParentIssue": "Unset parent issue", - "ForbidCreateProjectPermission": "Prohibir crear proyecto", - "ForbidCreateProjectPermissionDescription": "Prohíbe a los usuarios crear nuevos proyectos", - "AllowCreatingIssues": "Permitir crear incidencias", - "Day": "Día", - "Gantt": "Gantt", - "Month": "Mes", - "Quarter": "Trimestre", - "Week": "Semana" - }, - "status": {} -} + "string": { + "TrackerApplication": "Seguimiento", + "Projects": "Tus proyectos", + "More": "Más", + "Default": "Por defecto", + "MakeDefault": "Establecer como por defecto", + "Delete": "Eliminar", + "Open": "Abrir", + "Members": "Miembros", + "Inbox": "Bandeja de entrada", + "MyIssues": "Mis tareas", + "ViewIssue": "Ver tarea", + "IssueCreated": "Tarea creada", + "Issues": "Tareas", + "Views": "Vistas", + "Active": "Activo", + "AllIssues": "Todas las tareas", + "ActiveIssues": "Tareas activas", + "BacklogIssues": "Atrasadas", + "Backlog": "Atrasadas", + "Board": "Tablero", + "Components": "Componentes", + "AllComponents": "Todos", + "BacklogComponents": "Atrasados", + "ActiveComponents": "Activos", + "ClosedComponents": "Cerrados", + "NewComponent": "Nuevo componente", + "CreateComponent": "Crear componente", + "ComponentNamePlaceholder": "Nombre del componente", + "ComponentDescriptionPlaceholder": "Descripción (opcional)", + "ComponentLead": "Responsable del componente", + "ComponentMembers": "Miembros del componente", + "StartDate": "Fecha de inicio", + "TargetDate": "Fecha objetivo", + "Planned": "Planificado", + "InProgress": "En progreso", + "Paused": "Pausado", + "Completed": "Completado", + "Canceled": "Cancelado", + "CreateProject": "Crear proyecto", + "NewProject": "Nuevo proyecto", + "ProjectTitle": "Título del proyecto", + "ProjectTitlePlaceholder": "Nuevo proyecto", + "UsedInIssueIDs": "Utilizado en IDs de tareas", + "Identifier": "Identificador", + "Import": "Importar", + "ProjectIdentifier": "Identificador del proyecto", + "IdentifierExists": "El identificador del proyecto ya existe", + "ProjectIdentifierPlaceholder": "PROJ", + "ChooseIcon": "Seleccionar icono", + "AddIssue": "Añadir tarea", + "NewIssue": "Nueva tarea", + "NewIssuePlaceholder": "Nueva", + "ResumeDraft": "Continuar borrador", + "SaveIssue": "Crear tarea", + "SetPriority": "Establecer prioridad…", + "SetStatus": "Establecer estado…", + "SelectIssue": "Seleccionar tarea", + "Priority": "Prioridad", + "NoPriority": "Sin prioridad", + "Urgent": "Urgente", + "High": "Alta", + "Medium": "Media", + "Low": "Baja", + "Unassigned": "Sin asignar", + "Back": "Atrás", + "List": "Lista", + "NumberLabels": "{count, plural, =0 {sin etiquetas} =1 {1 etiqueta} other {# etiquetas}}", + "CategoryBacklog": "Atraso", + "CategoryUnstarted": "Por Iniciar", + "CategoryStarted": "Iniciado", + "CategoryCompleted": "Completado", + "CategoryCanceled": "Cancelado", + "Title": "Título", + "Name": "Nombre", + "Description": "Descripción", + "Status": "Estado", + "Number": "Número", + "Assignee": "Asignado a", + "AssignTo": "Asignar a...", + "AssignedTo": "Asignado a {value}", + "Parent": "Tarea principal", + "SetParent": "Establecer tarea principal...", + "ChangeParent": "Cambiar tarea principal...", + "RemoveParent": "Eliminar tarea principal", + "OpenParent": "Abrir tarea principal", + "SubIssues": "Subtareas", + "SubIssuesList": "Subtareas ({subIssues})", + "OpenSubIssues": "Abrir subtareas", + "AddSubIssues": "Añadir subtarea", + "BlockedBy": "Bloqueado por", + "RelatedTo": "Relacionado con", + "Comments": "Comentarios", + "Attachments": "Adjuntos", + "Labels": "Etiquetas", + "Component": "Componente", + "Space": "", + "SetDueDate": "Establecer fecha de vencimiento...", + "ChangeDueDate": "Cambiar fecha de vencimiento...", + "ModificationDate": "Actualizado {value}", + "Project": "Proyecto", + "Issue": "Tarea", + "SubIssue": "Subtarea", + "Document": "", + "DocumentIcon": "", + "DocumentColor": "", + "Rank": "Posición", + "TypeIssuePriority": "Prioridad de la tarea", + "IssueTitlePlaceholder": "Título de la tarea", + "SubIssueTitlePlaceholder": "Título de la subtarea", + "IssueDescriptionPlaceholder": "Añadir descripción...", + "SubIssueDescriptionPlaceholder": "Añadir descripción de la subtarea", + "AddIssueTooltip": "Añadir tarea...", + "NewIssueDialogClose": "¿Quieres cerrar este diálogo?", + "NewIssueDialogCloseNote": "Se perderán todos los cambios", + "RemoveComponentDialogClose": "¿Eliminar el componente?", + "RemoveComponentDialogCloseNote": "¿Estás seguro de que quieres eliminar este componente? Esta operación no se puede deshacer", + "Grouping": "Agrupación", + "Ordering": "Ordenación", + "CompletedIssues": "Tareas completadas", + "NoGrouping": "Sin agrupación", + "NoAssignee": "Sin asignar", + "LastUpdated": "Última actualización", + "DueDate": "Fecha de vencimiento", + "IssueStartDate": "Fecha de inicio", + "GanttDependency": "Dependency", + "GanttLag": "Lag", + "Manual": "Manual", + "All": "Todos", + "PastWeek": "Semana pasada", + "PastMonth": "Mes pasado", + "CopyIssueUrl": "Copiar URL de la tarea al portapapeles", + "CopyIssueId": "Copiar ID de la tarea al portapapeles", + "CopyIssueBranch": "Copiar nombre de la rama Git al portapapeles", + "CopyIssueTitle": "Copiar título de la tarea al portapapeles", + "AssetLabel": "Activo", + "AddToComponent": "Añadir al componente...", + "MoveToComponent": "Mover al componente...", + "NoComponent": "Sin componente", + "ComponentLeadTitle": "Responsable del componente", + "ComponentMembersTitle": "Miembros del componente", + "ComponentLeadSearchPlaceholder": "Establecer responsable del componente...", + "ComponentMembersSearchPlaceholder": "Cambiar miembros del componente...", + "MoveToProject": "Mover al proyecto", + "Duplicate": "Duplicar", + "GotoIssues": "Ir a tareas", + "GotoActive": "Ir a tareas activas", + "GotoBacklog": "Ir al backlog", + "GotoComponents": "Ir a componentes", + "GotoMyIssues": "Ir a mis tareas", + "GotoTrackerApplication": "Cambiar a la aplicación de seguimiento", + "CreatedOne": "Creada", + "MoveIssues": "Mover tareas", + "MoveIssuesDescription": "Selecciona el proyecto al que deseas mover las tareas", + "ManageAttributes": "Gestionar atributos", + "KeepOriginalAttributes": "Mantener atributos originales", + "KeepOriginalAttributesTooltip": "Se mantendrán los estados y componentes originales en el nuevo proyecto", + "SelectReplacement": "Los siguientes elementos no están disponibles en el nuevo proyecto. Seleccione un reemplazo.", + "MissingItem": "SIN ELEMENTO", + "Replacement": "REEMPLAZO", + "Original": "ORIGINAL", + "OriginalDescription": "Los elementos de esta sección se crearán en el nuevo proyecto", + "Relations": "Relaciones", + "RemoveRelation": "Eliminar relación...", + "AddBlockedBy": "Marcar como bloqueado por...", + "AddIsBlocking": "Marcar como bloqueador...", + "AddRelatedIssue": "Referenciar otro problema...", + "RelatedIssue": "Problema relacionado {id} - {title}", + "BlockedIssue": "Problema bloqueado {id} - {title}", + "BlockingIssue": "Problema bloqueador {id} - {title}", + "BlockedBySearchPlaceholder": "Buscar problema para marcar como bloqueado por...", + "IsBlockingSearchPlaceholder": "Buscar problema para marcar como bloqueador...", + "RelatedIssueSearchPlaceholder": "Buscar problema para referenciar...", + "Blocks": "Bloquea", + "Related": "Relacionado", + "RelatedIssues": "Problemas relacionados", + "EditIssue": "Editar {title}", + "EditWorkflowStatuses": "Editar estados de problema", + "EditProject": "Editar proyecto", + "DeleteProject": "Eliminar proyecto", + "ArchiveProjectName": "¿Archivar proyecto {name}?", + "ArchiveProjectConfirm": "¿Desea archivar este proyecto?", + "DeleteProjectConfirm": "¿Desea eliminar este proyecto y todos los problemas?", + "ProjectHasIssues": "Hay problemas existentes en este proyecto, ¿está seguro de que desea archivarlos?", + "ManageWorkflowStatuses": "Administrar tipos de proyecto", + "AddWorkflowStatus": "Agregar estado de problema", + "EditWorkflowStatus": "Editar estado de problema", + "DeleteWorkflowStatus": "Eliminar estado de problema", + "DeleteWorkflowStatusConfirm": "¿Desea eliminar el estado \"{status}\"?", + "DeleteWorkflowStatusErrorDescription": "El estado \"{status}\" tiene {count, plural, =1 {1 problema} other {# problemas}} asignados. Por favor seleccione un estado al que moverlos", + "Save": "Guardar", + "IncludeItemsThatMatch": "Incluir elementos que coincidan", + "AnyFilter": "cualquier filtro", + "AllFilters": "todos los filtros", + "NoDescription": "Sin descripción", + "SearchIssue": "Buscar tarea...", + "StatusHistory": "Historial de estado", + "NewSubIssue": "Agregar subproblema...", + "AddLabel": "Agregar etiqueta", + "DeleteIssue": "Eliminar {issueCount, plural, =1 {problema} other {# problemas}}", + "DeleteIssueConfirm": "¿Desea eliminar {issueCount, plural, =1 {problema} other {problemas}}{subIssueCount, plural, =0 {?} =1 { y subproblema?} other { y subproblemas?}}", + "Milestone": "Hitos", + "NoMilestone": "Sin hito", + "MoveToMilestone": "Seleccionar hito", + "Milestones": "Hitos", + "AllMilestones": "Todos", + "PlannedMilestones": "Planificados", + "ActiveMilestones": "Activos", + "ClosedMilestones": "Completados", + "AddToMilestone": "Agregar a hito", + "MilestoneNamePlaceholder": "Nombre del hito", + "NewMilestone": "Nuevo hito", + "CreateMilestone": "Crear", + "MoveAndDeleteMilestone": "Mover problemas a {newMilestone} y eliminar {deleteMilestone}", + "MoveAndDeleteMilestoneConfirm": "¿Desea eliminar el hito y mover los problemas a otro hito?", + "Estimation": "Estimación", + "ReportedTime": "Tiempo empleado", + "RemainingTime": "Tiempo restante", + "TimeSpendReports": "Informes de tiempo empleado", + "TimeSpendReport": "Tiempo", + "TimeSpendReportAdd": "Agregar informe de tiempo", + "TimeSpendReportDate": "Fecha", + "TimeSpendReportValue": "Tiempo empleado", + "TimeSpendReportValueTooltip": "Tiempo empleado en horas", + "TimeSpendReportDescription": "Descripción", + "TimeSpendDays": "{value}d", + "TimeSpendHours": "{value}h", + "TimeSpendMinutes": "{value}m", + "ChildEstimation": "Estimación de subtemas", + "ChildReportedTime": "Tiempo de subtemas", + "CapacityValue": "de {value}d", + "NewRelatedIssue": "Nuevo problema relacionado", + "RelatedIssuesNotFound": "Problemas relacionados no encontrados", + "AddedReference": "Referencia añadida", + "AddedAsBlocked": "Marcado como bloqueado", + "AddedAsBlocking": "Marcado como bloqueante", + "IssueTemplate": "Plantilla", + "IssueTemplates": "Plantillas", + "NewProcess": "Nueva plantilla", + "SaveProcess": "Guardar plantilla", + "NoIssueTemplate": "Sin plantilla", + "TemplateReplace": "¿Desea aplicar la nueva plantilla?", + "TemplateReplaceConfirm": "Todos los campos serán sobrescritos por los valores de la nueva plantilla", + "Apply": "Aplicar", + "CurrentWorkDay": "Día laboral actual", + "PreviousWorkDay": "Día laboral anterior", + "TimeReportDayTypeLabel": "Seleccionar tipo de día para reporte de tiempo", + "DefaultAssignee": "Asignado por defecto para problemas", + "SevenHoursLength": "Siete horas", + "EightHoursLength": "Ocho horas", + "HourLabel": "h", + "MinuteLabel": "m", + "Saved": "Guardado...", + "CreatedIssue": "Problema creado", + "CreatedSubIssue": "Sub-problema creado", + "ChangeStatus": "Cambiar estado", + "ConfigLabel": "Rastreador", + "ConfigDescription": "Extensión para gestionar elementos de trabajo y realizar todas las tareas realizadas.", + "NoStatusFound": "No se encontró ningún estado coincidente", + "CreateMissingStatus": "Crear estado faltante", + "UnsetParent": "El problema padre será desmarcado", + "AllProjects": "Todos los proyectos", + "IssueNotificationTitle": "{issueTitle}", + "IssueNotificationBody": "Actualizado por {senderName}", + "IssueNotificationChanged": "{senderName} cambió {property}", + "IssueNotificationChangedProperty": "{senderName} cambió {property} a \"{newValue}\"", + "IssueNotificationMessage": "{senderName}: {message}", + "PreviousAssigned": "Anteriormente asignado", + "IssueAssignedToYou": "Asignado a ti", + "RelatedIssueTargetDescription": "Proyecto de destino de problema relacionado para Clase o Espacio", + "MapRelatedIssues": "Configurar proyectos predeterminados de problemas relacionados", + "DefaultIssueStatus": "Estado de problema predeterminado", + "IssueStatus": "Estado", + "Extensions": "Extensions", + "UnsetParentIssue": "Unset parent issue", + "ForbidCreateProjectPermission": "Prohibir crear proyecto", + "ForbidCreateProjectPermissionDescription": "Prohíbe a los usuarios crear nuevos proyectos", + "AllowCreatingIssues": "Permitir crear incidencias", + "Day": "Día", + "Gantt": "Gantt", + "Month": "Mes", + "Quarter": "Trimestre", + "Week": "Semana", + "GanttShowIssueCode": "Show issue code", + "GanttShowTitle": "Show title" + }, + "status": {} +} \ No newline at end of file diff --git a/plugins/tracker-assets/lang/fr.json b/plugins/tracker-assets/lang/fr.json index 4bf83349e83..ebbc675b081 100644 --- a/plugins/tracker-assets/lang/fr.json +++ b/plugins/tracker-assets/lang/fr.json @@ -1,287 +1,289 @@ { - "string": { - "TrackerApplication": "Suivi", - "Projects": "Vos projets", - "More": "Plus", - "Default": "Par défaut", - "MakeDefault": "Définir par défaut", - "Delete": "Supprimer", - "Open": "Ouvrir", - "Members": "Membres", - "Inbox": "Boîte de réception", - "MyIssues": "Mes issues", - "ViewIssue": "Voir l'issue", - "IssueCreated": "Issue créées", - "Issues": "Issues", - "Views": "Vues", - "Active": "Actif", - "AllIssues": "Toutes les issues", - "ActiveIssues": "Issues actives", - "BacklogIssues": "Backlog", - "Backlog": "Backlog", - "Board": "Tableau", - "Components": "Composants", - "AllComponents": "Tous", - "BacklogComponents": "Backlog", - "ActiveComponents": "Actif", - "ClosedComponents": "Fermé", - "NewComponent": "Nouveau composant", - "CreateComponent": "Créer un composant", - "ComponentNamePlaceholder": "Nom du composant", - "ComponentDescriptionPlaceholder": "Description (facultatif)", - "ComponentLead": "Responsable", - "ComponentMembers": "Membres", - "StartDate": "Date de début", - "TargetDate": "Date cible", - "Planned": "Planifié", - "InProgress": "En cours", - "Paused": "En pause", - "Completed": "Terminé", - "Canceled": "Annulé", - "CreateProject": "Créer un projet", - "NewProject": "Nouveau projet", - "ProjectTitle": "Titre du projet", - "ProjectTitlePlaceholder": "Nouveau projet", - "UsedInIssueIDs": "Utilisé dans les ID d'une issue", - "Identifier": "Identifiant", - "Import": "Importer", - "ProjectIdentifier": "Identifiant du projet", - "IdentifierExists": "L'identifiant du projet existe déjà", - "ProjectIdentifierPlaceholder": "PRJCT", - "ChooseIcon": "Choisir une icône", - "AddIssue": "Ajouter une issue", - "NewIssue": "Nouvelle issue", - "NewIssuePlaceholder": "Nouveau", - "ResumeDraft": "Reprendre le brouillon", - "SaveIssue": "Créer une issue", - "SetPriority": "Définir la priorité...", - "SetStatus": "Définir le statut...", - "SelectIssue": "Sélectionner une issue", - "Priority": "Priorité", - "NoPriority": "Aucune priorité", - "Urgent": "Urgent", - "High": "Haute", - "Medium": "Moyenne", - "Low": "Basse", - "Unassigned": "Non assigné", - "Back": "Retour", - "List": "Liste", - "NumberLabels": "{count, plural, =0 {aucune étiquette} =1 {1 étiquette} other {# étiquettes}}", - "CategoryBacklog": "Backlog", - "CategoryUnstarted": "Non commencé", - "CategoryStarted": "Commencé", - "CategoryCompleted": "Terminé", - "CategoryCanceled": "Annulé", - "Title": "Titre", - "Name": "Nom", - "Description": "Description", - "Status": "Statut", - "Number": "Numéro", - "Assignee": "Assigné à", - "AssignTo": "Assigner à...", - "AssignedTo": "Assigné à {value}", - "Parent": "Problème parent", - "SetParent": "Définir le problème parent...", - "ChangeParent": "Changer le problème parent...", - "RemoveParent": "Supprimer le problème parent", - "OpenParent": "Ouvrir le problème parent", - "SubIssues": "Sub-issue", - "SubIssuesList": "Sub-issue ({subIssues})", - "OpenSubIssues": "Ouvrir les sub-issue", - "AddSubIssues": "Ajouter un sub-issue", - "BlockedBy": "Bloqué par", - "RelatedTo": "Lié à", - "Comments": "Commentaires", - "Attachments": "Pièces jointes", - "Labels": "Étiquettes", - "Component": "Composant", - "Space": "", - "SetDueDate": "Définir la date d'échéance...", - "ChangeDueDate": "Changer la date d'échéance...", - "ModificationDate": "Mis à jour {value}", - "Project": "Projet", - "Issue": "Issue", - "SubIssue": "Sub-issue", - "Document": "", - "DocumentIcon": "", - "DocumentColor": "", - "Rank": "Rang", - "TypeIssuePriority": "Priorité de l'issue", - "IssueTitlePlaceholder": "Titre de l'issue", - "SubIssueTitlePlaceholder": "Titre de la sub-issue", - "IssueDescriptionPlaceholder": "Ajouter une description...", - "SubIssueDescriptionPlaceholder": "Ajouter une description de la sub-issue", - "AddIssueTooltip": "Ajouter une issue...", - "NewIssueDialogClose": "Voulez-vous fermer cette fenêtre ?", - "NewIssueDialogCloseNote": "Tous les changements seront perdus", - "RemoveComponentDialogClose": "Supprimer le composant ?", - "RemoveComponentDialogCloseNote": "Êtes-vous sûr de vouloir supprimer ce composant ? Cette opération est irréversible", - "Grouping": "Regroupement", - "Ordering": "Classement", - "CompletedIssues": "Issues terminées", - "NoGrouping": "Aucun regroupement", - "NoAssignee": "Non assigné", - "LastUpdated": "Dernière mise à jour", - "DueDate": "Date d'échéance", - "IssueStartDate": "Date de début", - "GanttDependency": "Dependency", - "GanttLag": "Lag", - "Manual": "Manuel", - "All": "Tous", - "PastWeek": "La semaine passée", - "PastMonth": "Le mois passé", - "CopyIssueUrl": "Copier l'URL de l'issue dans le presse-papiers", - "CopyIssueId": "Copier l'ID de l'issue dans le presse-papiers", - "CopyIssueBranch": "Copier le nom de la branche Git dans le presse-papiers", - "CopyIssueTitle": "Copier le titre de l'issue dans le presse-papiers", - "AssetLabel": "Actif", - "AddToComponent": "Ajouter au composant...", - "MoveToComponent": "Déplacer vers le composant...", - "NoComponent": "Aucun composant", - "ComponentLeadTitle": "Responsable du composant", - "ComponentMembersTitle": "Membres du composant", - "ComponentLeadSearchPlaceholder": "Définir le responsable du composant...", - "ComponentMembersSearchPlaceholder": "Modifier les membres du composant...", - "MoveToProject": "Déplacer vers le projet", - "Duplicate": "Dupliquer", - "GotoIssues": "Aller aux issues", - "GotoActive": "Aller aux problèmes actifs", - "GotoBacklog": "Aller au backlog", - "GotoComponents": "Aller aux composants", - "GotoMyIssues": "Aller à mes issues", - "GotoTrackerApplication": "Passer à l'application de suivi", - "CreatedOne": "Créé", - "MoveIssues": "Déplacer les issues", - "MoveIssuesDescription": "Sélectionnez le projet vers lequel vous souhaitez déplacer les issues", - "ManageAttributes": "Gérer les attributs", - "KeepOriginalAttributes": "Conserver les attributs d'origine", - "KeepOriginalAttributesTooltip": "Les statuts et composants des problèmes d'origine seront conservés dans le nouveau projet", - "SelectReplacement": "Les éléments suivants ne sont pas disponibles dans le nouveau projet. Sélectionnez un remplacement.", - "MissingItem": "ÉLÉMENT MANQUANT", - "Replacement": "REMPLACEMENT", - "Original": "ORIGINAL", - "OriginalDescription": "Les éléments de cette section seront créés dans le nouveau projet", - "Relations": "Relations", - "RemoveRelation": "Supprimer la relation...", - "AddBlockedBy": "Marquer comme bloqué par...", - "AddIsBlocking": "Marquer comme bloquant...", - "AddRelatedIssue": "Référencer une autre issue...", - "RelatedIssue": "Issue liée {id} - {title}", - "BlockedIssue": "Issue bloquée {id} - {title}", - "BlockingIssue": "Issue bloquante {id} - {title}", - "BlockedBySearchPlaceholder": "Rechercher un problème à marquer comme bloqué par...", - "IsBlockingSearchPlaceholder": "Rechercher un problème à marquer comme bloquant...", - "RelatedIssueSearchPlaceholder": "Rechercher une issue à référencer...", - "Blocks": "Bloque", - "Related": "Lié", - "RelatedIssues": "Issues liées", - "EditIssue": "Modifier {title}", - "EditWorkflowStatuses": "Modifier les statuts des problèmes", - "EditProject": "Modifier le projet", - "DeleteProject": "Supprimer le projet", - "ArchiveProjectName": "Archiver le projet {name} ?", - "ArchiveProjectConfirm": "Voulez-vous archiver ce projet ?", - "DeleteProjectConfirm": "Voulez-vous supprimer ce projet et tous les problèmes ?", - "ProjectHasIssues": "Il y a des issues existantes dans ce projet, êtes-vous sûr de vouloir archiver ?", - "ManageWorkflowStatuses": "Gérer les types de projet", - "AddWorkflowStatus": "Ajouter un statut de problème", - "EditWorkflowStatus": "Modifier le statut du problème", - "DeleteWorkflowStatus": "Supprimer le statut du problème", - "DeleteWorkflowStatusConfirm": "Voulez-vous supprimer le statut \"{status}\" ?", - "DeleteWorkflowStatusErrorDescription": "Le statut \"{status}\" a {count, plural, =1 {1 problème} other {# problèmes}} assigné(s). Veuillez sélectionner un statut pour le déplacer", - "Save": "Enregistrer", - "IncludeItemsThatMatch": "Inclure les éléments qui correspondent", - "AnyFilter": "n'importe quel filtre", - "AllFilters": "tous les filtres", - "NoDescription": "Pas de description", - "SearchIssue": "Rechercher une tâche...", - "StatusHistory": "Historique des statuts", - "NewSubIssue": "Ajouter un sub-ssue...", - "AddLabel": "Ajouter une étiquette", - "DeleteIssue": "Supprimer {issueCount, plural, =1 {problème} other {# problèmes}}", - "DeleteIssueConfirm": "Voulez-vous supprimer {issueCount, plural, =1 {le problème} other {les problèmes}}{subIssueCount, plural, =0 {?} =1 { et le sous-problème ?} other { et les sous-problèmes ?}}", - "Milestone": "Jalon", - "NoMilestone": "Pas de jalon", - "MoveToMilestone": "Sélectionner un jalon", - "Milestones": "Jalons", - "AllMilestones": "Tous", - "PlannedMilestones": "Prévu", - "ActiveMilestones": "Actif", - "ClosedMilestones": "Terminé", - "AddToMilestone": "Ajouter au jalon", - "MilestoneNamePlaceholder": "Nom du jalon", - "NewMilestone": "Nouveau jalon", - "CreateMilestone": "Créer", - "MoveAndDeleteMilestone": "Déplacer les problèmes vers {newMilestone} et supprimer {deleteMilestone}", - "MoveAndDeleteMilestoneConfirm": "Voulez-vous supprimer le jalon et déplacer les problèmes vers un autre jalon ?", - "Estimation": "Estimation", - "ReportedTime": "Temps passé", - "RemainingTime": "Temps restant", - "TimeSpendReports": "Rapports de temps passé", - "TimeSpendReport": "Temps", - "TimeSpendReportAdd": "Ajouter un rapport de temps", - "TimeSpendReportDate": "Date", - "TimeSpendReportValue": "Temps passé", - "TimeSpendReportValueTooltip": "Temps passé en heures", - "TimeSpendReportDescription": "Description", - "TimeSpendDays": "{value}j", - "TimeSpendHours": "{value}h", - "TimeSpendMinutes": "{value}m", - "ChildEstimation": "Estimation des sous-problèmes", - "ChildReportedTime": "Temps des sous-problèmes", - "CapacityValue": "de {value}j", - "NewRelatedIssue": "Nouvelle issue liée", - "RelatedIssuesNotFound": "Issues liées non trouvés", - "AddedReference": "Référence ajoutée", - "AddedAsBlocked": "Marqué comme bloqué", - "AddedAsBlocking": "Marqué comme bloquant", - "IssueTemplate": "Modèle", - "IssueTemplates": "Modèles", - "NewProcess": "Nouveau modèle", - "SaveProcess": "Enregistrer le modèle", - "NoIssueTemplate": "Aucun modèle", - "TemplateReplace": "Voulez-vous appliquer le nouveau modèle ?", - "TemplateReplaceConfirm": "Tous les champs seront remplacés par les valeurs du nouveau modèle", - "Apply": "Appliquer", - "CurrentWorkDay": "Journée de travail actuelle", - "PreviousWorkDay": "Journée de travail précédente", - "TimeReportDayTypeLabel": "Sélectionnez le type de journée de rapport de temps", - "DefaultAssignee": "Assigné par défaut pour les problèmes", - "SevenHoursLength": "Sept heures", - "EightHoursLength": "Huit heures", - "HourLabel": "h", - "MinuteLabel": "m", - "Saved": "Enregistré...", - "CreatedIssue": "Issue créée", - "CreatedSubIssue": "Sub-issue créée", - "ChangeStatus": "Changer le statut", - "ConfigLabel": "Suivi", - "ConfigDescription": "Extension pour gérer les éléments de travail et accomplir toutes les tâches.", - "NoStatusFound": "Aucun statut correspondant trouvé", - "CreateMissingStatus": "Créer un statut manquant", - "UnsetParent": "Le problème parent sera désélectionné", - "AllProjects": "Tous les projets", - "IssueNotificationTitle": "{issueTitle}", - "IssueNotificationBody": "Mis à jour par {senderName}", - "IssueNotificationChanged": "{senderName} a modifié {property}", - "IssueNotificationChangedProperty": "{senderName} a modifié {property} en \"{newValue}\"", - "IssueNotificationMessage": "{senderName} : {message}", - "PreviousAssigned": "Assigné précédemment", - "IssueAssignedToYou": "Assigné à vous", - "RelatedIssueTargetDescription": "Projet cible de l'issue liée pour la classe ou l'espace", - "MapRelatedIssues": "Configurer les projets par défaut des issues liées", - "DefaultIssueStatus": "Statut par défaut de l'issue", - "IssueStatus": "Statut", - "Extensions": "Extensions", - "UnsetParentIssue": "Désélectionner l'issue parent", - "ForbidCreateProjectPermission": "Interdire la création de projet", - "ForbidCreateProjectPermissionDescription": "Interdit aux utilisateurs de créer de nouveaux projets", - "AllowCreatingIssues": "Autoriser la création d'issues", - "Day": "Jour", - "Gantt": "Gantt", - "Month": "Mois", - "Quarter": "Trimestre", - "Week": "Semaine" - }, - "status": {} -} + "string": { + "TrackerApplication": "Suivi", + "Projects": "Vos projets", + "More": "Plus", + "Default": "Par défaut", + "MakeDefault": "Définir par défaut", + "Delete": "Supprimer", + "Open": "Ouvrir", + "Members": "Membres", + "Inbox": "Boîte de réception", + "MyIssues": "Mes issues", + "ViewIssue": "Voir l'issue", + "IssueCreated": "Issue créées", + "Issues": "Issues", + "Views": "Vues", + "Active": "Actif", + "AllIssues": "Toutes les issues", + "ActiveIssues": "Issues actives", + "BacklogIssues": "Backlog", + "Backlog": "Backlog", + "Board": "Tableau", + "Components": "Composants", + "AllComponents": "Tous", + "BacklogComponents": "Backlog", + "ActiveComponents": "Actif", + "ClosedComponents": "Fermé", + "NewComponent": "Nouveau composant", + "CreateComponent": "Créer un composant", + "ComponentNamePlaceholder": "Nom du composant", + "ComponentDescriptionPlaceholder": "Description (facultatif)", + "ComponentLead": "Responsable", + "ComponentMembers": "Membres", + "StartDate": "Date de début", + "TargetDate": "Date cible", + "Planned": "Planifié", + "InProgress": "En cours", + "Paused": "En pause", + "Completed": "Terminé", + "Canceled": "Annulé", + "CreateProject": "Créer un projet", + "NewProject": "Nouveau projet", + "ProjectTitle": "Titre du projet", + "ProjectTitlePlaceholder": "Nouveau projet", + "UsedInIssueIDs": "Utilisé dans les ID d'une issue", + "Identifier": "Identifiant", + "Import": "Importer", + "ProjectIdentifier": "Identifiant du projet", + "IdentifierExists": "L'identifiant du projet existe déjà", + "ProjectIdentifierPlaceholder": "PRJCT", + "ChooseIcon": "Choisir une icône", + "AddIssue": "Ajouter une issue", + "NewIssue": "Nouvelle issue", + "NewIssuePlaceholder": "Nouveau", + "ResumeDraft": "Reprendre le brouillon", + "SaveIssue": "Créer une issue", + "SetPriority": "Définir la priorité...", + "SetStatus": "Définir le statut...", + "SelectIssue": "Sélectionner une issue", + "Priority": "Priorité", + "NoPriority": "Aucune priorité", + "Urgent": "Urgent", + "High": "Haute", + "Medium": "Moyenne", + "Low": "Basse", + "Unassigned": "Non assigné", + "Back": "Retour", + "List": "Liste", + "NumberLabels": "{count, plural, =0 {aucune étiquette} =1 {1 étiquette} other {# étiquettes}}", + "CategoryBacklog": "Backlog", + "CategoryUnstarted": "Non commencé", + "CategoryStarted": "Commencé", + "CategoryCompleted": "Terminé", + "CategoryCanceled": "Annulé", + "Title": "Titre", + "Name": "Nom", + "Description": "Description", + "Status": "Statut", + "Number": "Numéro", + "Assignee": "Assigné à", + "AssignTo": "Assigner à...", + "AssignedTo": "Assigné à {value}", + "Parent": "Problème parent", + "SetParent": "Définir le problème parent...", + "ChangeParent": "Changer le problème parent...", + "RemoveParent": "Supprimer le problème parent", + "OpenParent": "Ouvrir le problème parent", + "SubIssues": "Sub-issue", + "SubIssuesList": "Sub-issue ({subIssues})", + "OpenSubIssues": "Ouvrir les sub-issue", + "AddSubIssues": "Ajouter un sub-issue", + "BlockedBy": "Bloqué par", + "RelatedTo": "Lié à", + "Comments": "Commentaires", + "Attachments": "Pièces jointes", + "Labels": "Étiquettes", + "Component": "Composant", + "Space": "", + "SetDueDate": "Définir la date d'échéance...", + "ChangeDueDate": "Changer la date d'échéance...", + "ModificationDate": "Mis à jour {value}", + "Project": "Projet", + "Issue": "Issue", + "SubIssue": "Sub-issue", + "Document": "", + "DocumentIcon": "", + "DocumentColor": "", + "Rank": "Rang", + "TypeIssuePriority": "Priorité de l'issue", + "IssueTitlePlaceholder": "Titre de l'issue", + "SubIssueTitlePlaceholder": "Titre de la sub-issue", + "IssueDescriptionPlaceholder": "Ajouter une description...", + "SubIssueDescriptionPlaceholder": "Ajouter une description de la sub-issue", + "AddIssueTooltip": "Ajouter une issue...", + "NewIssueDialogClose": "Voulez-vous fermer cette fenêtre ?", + "NewIssueDialogCloseNote": "Tous les changements seront perdus", + "RemoveComponentDialogClose": "Supprimer le composant ?", + "RemoveComponentDialogCloseNote": "Êtes-vous sûr de vouloir supprimer ce composant ? Cette opération est irréversible", + "Grouping": "Regroupement", + "Ordering": "Classement", + "CompletedIssues": "Issues terminées", + "NoGrouping": "Aucun regroupement", + "NoAssignee": "Non assigné", + "LastUpdated": "Dernière mise à jour", + "DueDate": "Date d'échéance", + "IssueStartDate": "Date de début", + "GanttDependency": "Dependency", + "GanttLag": "Lag", + "Manual": "Manuel", + "All": "Tous", + "PastWeek": "La semaine passée", + "PastMonth": "Le mois passé", + "CopyIssueUrl": "Copier l'URL de l'issue dans le presse-papiers", + "CopyIssueId": "Copier l'ID de l'issue dans le presse-papiers", + "CopyIssueBranch": "Copier le nom de la branche Git dans le presse-papiers", + "CopyIssueTitle": "Copier le titre de l'issue dans le presse-papiers", + "AssetLabel": "Actif", + "AddToComponent": "Ajouter au composant...", + "MoveToComponent": "Déplacer vers le composant...", + "NoComponent": "Aucun composant", + "ComponentLeadTitle": "Responsable du composant", + "ComponentMembersTitle": "Membres du composant", + "ComponentLeadSearchPlaceholder": "Définir le responsable du composant...", + "ComponentMembersSearchPlaceholder": "Modifier les membres du composant...", + "MoveToProject": "Déplacer vers le projet", + "Duplicate": "Dupliquer", + "GotoIssues": "Aller aux issues", + "GotoActive": "Aller aux problèmes actifs", + "GotoBacklog": "Aller au backlog", + "GotoComponents": "Aller aux composants", + "GotoMyIssues": "Aller à mes issues", + "GotoTrackerApplication": "Passer à l'application de suivi", + "CreatedOne": "Créé", + "MoveIssues": "Déplacer les issues", + "MoveIssuesDescription": "Sélectionnez le projet vers lequel vous souhaitez déplacer les issues", + "ManageAttributes": "Gérer les attributs", + "KeepOriginalAttributes": "Conserver les attributs d'origine", + "KeepOriginalAttributesTooltip": "Les statuts et composants des problèmes d'origine seront conservés dans le nouveau projet", + "SelectReplacement": "Les éléments suivants ne sont pas disponibles dans le nouveau projet. Sélectionnez un remplacement.", + "MissingItem": "ÉLÉMENT MANQUANT", + "Replacement": "REMPLACEMENT", + "Original": "ORIGINAL", + "OriginalDescription": "Les éléments de cette section seront créés dans le nouveau projet", + "Relations": "Relations", + "RemoveRelation": "Supprimer la relation...", + "AddBlockedBy": "Marquer comme bloqué par...", + "AddIsBlocking": "Marquer comme bloquant...", + "AddRelatedIssue": "Référencer une autre issue...", + "RelatedIssue": "Issue liée {id} - {title}", + "BlockedIssue": "Issue bloquée {id} - {title}", + "BlockingIssue": "Issue bloquante {id} - {title}", + "BlockedBySearchPlaceholder": "Rechercher un problème à marquer comme bloqué par...", + "IsBlockingSearchPlaceholder": "Rechercher un problème à marquer comme bloquant...", + "RelatedIssueSearchPlaceholder": "Rechercher une issue à référencer...", + "Blocks": "Bloque", + "Related": "Lié", + "RelatedIssues": "Issues liées", + "EditIssue": "Modifier {title}", + "EditWorkflowStatuses": "Modifier les statuts des problèmes", + "EditProject": "Modifier le projet", + "DeleteProject": "Supprimer le projet", + "ArchiveProjectName": "Archiver le projet {name} ?", + "ArchiveProjectConfirm": "Voulez-vous archiver ce projet ?", + "DeleteProjectConfirm": "Voulez-vous supprimer ce projet et tous les problèmes ?", + "ProjectHasIssues": "Il y a des issues existantes dans ce projet, êtes-vous sûr de vouloir archiver ?", + "ManageWorkflowStatuses": "Gérer les types de projet", + "AddWorkflowStatus": "Ajouter un statut de problème", + "EditWorkflowStatus": "Modifier le statut du problème", + "DeleteWorkflowStatus": "Supprimer le statut du problème", + "DeleteWorkflowStatusConfirm": "Voulez-vous supprimer le statut \"{status}\" ?", + "DeleteWorkflowStatusErrorDescription": "Le statut \"{status}\" a {count, plural, =1 {1 problème} other {# problèmes}} assigné(s). Veuillez sélectionner un statut pour le déplacer", + "Save": "Enregistrer", + "IncludeItemsThatMatch": "Inclure les éléments qui correspondent", + "AnyFilter": "n'importe quel filtre", + "AllFilters": "tous les filtres", + "NoDescription": "Pas de description", + "SearchIssue": "Rechercher une tâche...", + "StatusHistory": "Historique des statuts", + "NewSubIssue": "Ajouter un sub-ssue...", + "AddLabel": "Ajouter une étiquette", + "DeleteIssue": "Supprimer {issueCount, plural, =1 {problème} other {# problèmes}}", + "DeleteIssueConfirm": "Voulez-vous supprimer {issueCount, plural, =1 {le problème} other {les problèmes}}{subIssueCount, plural, =0 {?} =1 { et le sous-problème ?} other { et les sous-problèmes ?}}", + "Milestone": "Jalon", + "NoMilestone": "Pas de jalon", + "MoveToMilestone": "Sélectionner un jalon", + "Milestones": "Jalons", + "AllMilestones": "Tous", + "PlannedMilestones": "Prévu", + "ActiveMilestones": "Actif", + "ClosedMilestones": "Terminé", + "AddToMilestone": "Ajouter au jalon", + "MilestoneNamePlaceholder": "Nom du jalon", + "NewMilestone": "Nouveau jalon", + "CreateMilestone": "Créer", + "MoveAndDeleteMilestone": "Déplacer les problèmes vers {newMilestone} et supprimer {deleteMilestone}", + "MoveAndDeleteMilestoneConfirm": "Voulez-vous supprimer le jalon et déplacer les problèmes vers un autre jalon ?", + "Estimation": "Estimation", + "ReportedTime": "Temps passé", + "RemainingTime": "Temps restant", + "TimeSpendReports": "Rapports de temps passé", + "TimeSpendReport": "Temps", + "TimeSpendReportAdd": "Ajouter un rapport de temps", + "TimeSpendReportDate": "Date", + "TimeSpendReportValue": "Temps passé", + "TimeSpendReportValueTooltip": "Temps passé en heures", + "TimeSpendReportDescription": "Description", + "TimeSpendDays": "{value}j", + "TimeSpendHours": "{value}h", + "TimeSpendMinutes": "{value}m", + "ChildEstimation": "Estimation des sous-problèmes", + "ChildReportedTime": "Temps des sous-problèmes", + "CapacityValue": "de {value}j", + "NewRelatedIssue": "Nouvelle issue liée", + "RelatedIssuesNotFound": "Issues liées non trouvés", + "AddedReference": "Référence ajoutée", + "AddedAsBlocked": "Marqué comme bloqué", + "AddedAsBlocking": "Marqué comme bloquant", + "IssueTemplate": "Modèle", + "IssueTemplates": "Modèles", + "NewProcess": "Nouveau modèle", + "SaveProcess": "Enregistrer le modèle", + "NoIssueTemplate": "Aucun modèle", + "TemplateReplace": "Voulez-vous appliquer le nouveau modèle ?", + "TemplateReplaceConfirm": "Tous les champs seront remplacés par les valeurs du nouveau modèle", + "Apply": "Appliquer", + "CurrentWorkDay": "Journée de travail actuelle", + "PreviousWorkDay": "Journée de travail précédente", + "TimeReportDayTypeLabel": "Sélectionnez le type de journée de rapport de temps", + "DefaultAssignee": "Assigné par défaut pour les problèmes", + "SevenHoursLength": "Sept heures", + "EightHoursLength": "Huit heures", + "HourLabel": "h", + "MinuteLabel": "m", + "Saved": "Enregistré...", + "CreatedIssue": "Issue créée", + "CreatedSubIssue": "Sub-issue créée", + "ChangeStatus": "Changer le statut", + "ConfigLabel": "Suivi", + "ConfigDescription": "Extension pour gérer les éléments de travail et accomplir toutes les tâches.", + "NoStatusFound": "Aucun statut correspondant trouvé", + "CreateMissingStatus": "Créer un statut manquant", + "UnsetParent": "Le problème parent sera désélectionné", + "AllProjects": "Tous les projets", + "IssueNotificationTitle": "{issueTitle}", + "IssueNotificationBody": "Mis à jour par {senderName}", + "IssueNotificationChanged": "{senderName} a modifié {property}", + "IssueNotificationChangedProperty": "{senderName} a modifié {property} en \"{newValue}\"", + "IssueNotificationMessage": "{senderName} : {message}", + "PreviousAssigned": "Assigné précédemment", + "IssueAssignedToYou": "Assigné à vous", + "RelatedIssueTargetDescription": "Projet cible de l'issue liée pour la classe ou l'espace", + "MapRelatedIssues": "Configurer les projets par défaut des issues liées", + "DefaultIssueStatus": "Statut par défaut de l'issue", + "IssueStatus": "Statut", + "Extensions": "Extensions", + "UnsetParentIssue": "Désélectionner l'issue parent", + "ForbidCreateProjectPermission": "Interdire la création de projet", + "ForbidCreateProjectPermissionDescription": "Interdit aux utilisateurs de créer de nouveaux projets", + "AllowCreatingIssues": "Autoriser la création d'issues", + "Day": "Jour", + "Gantt": "Gantt", + "Month": "Mois", + "Quarter": "Trimestre", + "Week": "Semaine", + "GanttShowIssueCode": "Show issue code", + "GanttShowTitle": "Show title" + }, + "status": {} +} \ No newline at end of file diff --git a/plugins/tracker-assets/lang/it.json b/plugins/tracker-assets/lang/it.json index 02d01f2850c..d85bdae0d9e 100644 --- a/plugins/tracker-assets/lang/it.json +++ b/plugins/tracker-assets/lang/it.json @@ -1,287 +1,289 @@ { - "string": { - "TrackerApplication": "Tracker", - "Projects": "I tuoi progetti", - "More": "Altro", - "Default": "Predefinito", - "MakeDefault": "Imposta come predefinito", - "Delete": "Elimina", - "Open": "Apri", - "Members": "Membri", - "Inbox": "Posta in arrivo", - "MyIssues": "Le mie issues", - "ViewIssue": "Visualizza issue", - "IssueCreated": "Issue creata", - "Issues": "Issue", - "Views": "Visualizzazioni", - "Active": "Attivo", - "AllIssues": "Tutte le issue", - "ActiveIssues": "Issue attive", - "BacklogIssues": "Backlog", - "Backlog": "Backlog", - "Board": "Bacheca", - "Components": "Componenti", - "AllComponents": "Tutti", - "BacklogComponents": "Backlog", - "ActiveComponents": "Attivi", - "ClosedComponents": "Chiuso", - "NewComponent": "Nuovo componente", - "CreateComponent": "Crea componente", - "ComponentNamePlaceholder": "Nome del componente", - "ComponentDescriptionPlaceholder": "Descrizione (facoltativo)", - "ComponentLead": "Responsabile", - "ComponentMembers": "Membri", - "StartDate": "Data di inizio", - "TargetDate": "Data obiettivo", - "Planned": "Pianificato", - "InProgress": "In corso", - "Paused": "In pausa", - "Completed": "Completato", - "Canceled": "Annullato", - "CreateProject": "Crea progetto", - "NewProject": "Nuovo progetto", - "ProjectTitle": "Titolo del progetto", - "ProjectTitlePlaceholder": "Nuovo progetto", - "UsedInIssueIDs": "Utilizzato negli ID delle issue", - "Identifier": "Identificatore", - "Import": "Importa", - "ProjectIdentifier": "Identificatore del progetto", - "IdentifierExists": "L'identificatore del progetto esiste già", - "ProjectIdentifierPlaceholder": "PRJCT", - "ChooseIcon": "Scegli icona", - "AddIssue": "Aggiungi issue", - "NewIssue": "Nuova issue", - "NewIssuePlaceholder": "Nuovo", - "ResumeDraft": "Riprendi bozza", - "SaveIssue": "Crea issue", - "SetPriority": "Imposta priorità…", - "SetStatus": "Imposta stato…", - "SelectIssue": "Seleziona issue", - "Priority": "Priorità", - "NoPriority": "Nessuna priorità", - "Urgent": "Urgente", - "High": "Alto", - "Medium": "Medio", - "Low": "Basso", - "Unassigned": "Non assegnato", - "Back": "Indietro", - "List": "Elenco", - "NumberLabels": "{count, plural, =0 {nessuna etichetta} =1 {1 etichetta} other {# etichette}}", - "CategoryBacklog": "Backlog", - "CategoryUnstarted": "Non iniziato", - "CategoryStarted": "Iniziato", - "CategoryCompleted": "Completato", - "CategoryCanceled": "Annullato", - "Title": "Titolo", - "Name": "Nome", - "Description": "Descrizione", - "Status": "Stato", - "Number": "Numero", - "Assignee": "Assegnatario", - "AssignTo": "Assegna a...", - "AssignedTo": "Assegnato a {value}", - "Parent": "Issue genitore", - "SetParent": "Imposta issue genitore…", - "ChangeParent": "Cambia issue genitore…", - "RemoveParent": "Rimuovi issue genitore", - "OpenParent": "Apri issue genitore", - "SubIssues": "Subissue", - "SubIssuesList": "Subissue ({subIssues})", - "OpenSubIssues": "Apri subissue", - "AddSubIssues": "Aggiungi subissue", - "BlockedBy": "Bloccato da", - "RelatedTo": "Correlato a", - "Comments": "Commenti", - "Attachments": "Allegati", - "Labels": "Etichette", - "Component": "Componente", - "Space": "", - "SetDueDate": "Imposta data di scadenza…", - "ChangeDueDate": "Cambia data di scadenza…", - "ModificationDate": "Aggiornato {value}", - "Project": "Progetto", - "Issue": "Issue", - "SubIssue": "Subissue", - "Document": "", - "DocumentIcon": "", - "DocumentColor": "", - "Rank": "Classifica", - "TypeIssuePriority": "Priorità della issue", - "IssueTitlePlaceholder": "Titolo della issue", - "SubIssueTitlePlaceholder": "Titolo della subissue", - "IssueDescriptionPlaceholder": "Aggiungi descrizione…", - "SubIssueDescriptionPlaceholder": "Aggiungi descrizione della subissue", - "AddIssueTooltip": "Aggiungi issue...", - "NewIssueDialogClose": "Vuoi chiudere questo dialogo?", - "NewIssueDialogCloseNote": "Tutte le modifiche andranno perse", - "RemoveComponentDialogClose": "Eliminare il componente?", - "RemoveComponentDialogCloseNote": "Sei sicuro di voler eliminare questo componente? Questa operazione non può essere annullata", - "Grouping": "Raggruppamento", - "Ordering": "Ordinamento", - "CompletedIssues": "Issue completate", - "NoGrouping": "Nessun raggruppamento", - "NoAssignee": "Nessun assegnatario", - "LastUpdated": "Ultimo aggiornamento", - "DueDate": "Data di scadenza", - "IssueStartDate": "Data di inizio", - "GanttDependency": "Dependency", - "GanttLag": "Lag", - "Manual": "Manuale", - "All": "Tutti", - "PastWeek": "Settimana scorsa", - "PastMonth": "Mese scorso", - "CopyIssueUrl": "Copia URL della issue negli appunti", - "CopyIssueId": "Copia ID della issue negli appunti", - "CopyIssueBranch": "Copia nome del ramo Git negli appunti", - "CopyIssueTitle": "Copia titolo della issue negli appunti", - "AssetLabel": "Risorsa", - "AddToComponent": "Aggiungi al componente…", - "MoveToComponent": "Sposta nel componente…", - "NoComponent": "Nessun componente", - "ComponentLeadTitle": "Responsabile del componente", - "ComponentMembersTitle": "Membri del componente", - "ComponentLeadSearchPlaceholder": "Imposta responsabile del componente…", - "ComponentMembersSearchPlaceholder": "Cambia membri del componente…", - "MoveToProject": "Sposta nel progetto", - "Duplicate": "Duplicato", - "GotoIssues": "Vai alle issue", - "GotoActive": "Vai alle issue attive", - "GotoBacklog": "Vai al backlog", - "GotoComponents": "Vai ai componenti", - "GotoMyIssues": "Vai alle mie issue", - "GotoTrackerApplication": "Passa all'applicazione Tracker", - "CreatedOne": "Creato", - "MoveIssues": "Sposta issue", - "MoveIssuesDescription": "Seleziona il progetto in cui desideri spostare le issue", - "ManageAttributes": "Gestisci attributi", - "KeepOriginalAttributes": "Mantieni attributi originali", - "KeepOriginalAttributesTooltip": "Gli stati e i componenti originali delle issue saranno mantenuti nel nuovo progetto", - "SelectReplacement": "I seguenti elementi non sono disponibili nel nuovo progetto. Seleziona un sostituto.", - "MissingItem": "ELEMENTO MANCANTE", - "Replacement": "SOSTITUTO", - "Original": "ORIGINALE", - "OriginalDescription": "Gli elementi di questa sezione verranno creati nel nuovo progetto", - "Relations": "Relazioni", - "RemoveRelation": "Rimuovi relazione...", - "AddBlockedBy": "Segna come bloccato da...", - "AddIsBlocking": "Segna come bloccante...", - "AddRelatedIssue": "Riferisci un'altra issue...", - "RelatedIssue": "Issue correlato {id} - {title}", - "BlockedIssue": "Issue bloccato {id} - {title}", - "BlockingIssue": "Issue bloccante {id} - {title}", - "BlockedBySearchPlaceholder": "Cerca una issue da contrassegnare come bloccato da...", - "IsBlockingSearchPlaceholder": "Cerca una issue da contrassegnare come bloccante...", - "RelatedIssueSearchPlaceholder": "Cerca una issue da riferire...", - "Blocks": "Blocca", - "Related": "Correlato", - "RelatedIssues": "Issue correlate", - "EditIssue": "Modifica {title}", - "EditWorkflowStatuses": "Modifica stati della issue", - "EditProject": "Modifica progetto", - "DeleteProject": "Elimina progetto", - "ArchiveProjectName": "Archivia progetto {name}?", - "ArchiveProjectConfirm": "Vuoi archiviare questo progetto?", - "DeleteProjectConfirm": "Vuoi eliminare questo progetto e tutte le issue?", - "ProjectHasIssues": "Ci sono issue esistenti in questo progetto, sei sicuro di voler archiviare?", - "ManageWorkflowStatuses": "Gestisci tipi di progetto", - "AddWorkflowStatus": "Aggiungi stato della issue", - "EditWorkflowStatus": "Modifica stato della issue", - "DeleteWorkflowStatus": "Elimina stato della issue", - "DeleteWorkflowStatusConfirm": "Vuoi eliminare lo stato \"{status}\"?", - "DeleteWorkflowStatusErrorDescription": "Lo stato \"{status}\" ha {count, plural, =1 {1 issue} other {# issue}} assegnate. Seleziona uno stato per spostare", - "Save": "Salva", - "IncludeItemsThatMatch": "Includi elementi che corrispondono", - "AnyFilter": "qualunque filtro", - "AllFilters": "tutti i filtri", - "NoDescription": "Nessuna descrizione", - "SearchIssue": "Cerca attività...", - "StatusHistory": "Storia degli stati", - "NewSubIssue": "Aggiungi subissue...", - "AddLabel": "Aggiungi etichetta", - "DeleteIssue": "Elimina {issueCount, plural, =1 {issue} other {# issue}}", - "DeleteIssueConfirm": "Vuoi eliminare {issueCount, plural, =1 {issue} other {issue}}{subIssueCount, plural, =0 {?} =1 { e subissue?} other { e subissue?}}", - "Milestone": "Traguardo", - "NoMilestone": "Nessun traguardo", - "MoveToMilestone": "Seleziona traguardo", - "Milestones": "Traguardi", - "AllMilestones": "Tutti", - "PlannedMilestones": "Pianificati", - "ActiveMilestones": "Attivi", - "ClosedMilestones": "Fatto", - "AddToMilestone": "Aggiungi al traguardo", - "MilestoneNamePlaceholder": "Nome del traguardo", - "NewMilestone": "Nuovo traguardo", - "CreateMilestone": "Crea", - "MoveAndDeleteMilestone": "Sposta problemi in {newMilestone} ed elimina {deleteMilestone}", - "MoveAndDeleteMilestoneConfirm": "Vuoi eliminare il traguardo e spostare i problemi in un altro traguardo?", - "Estimation": "Stima", - "ReportedTime": "Tempo trascorso", - "RemainingTime": "Tempo rimanente", - "TimeSpendReports": "Rapporti sul tempo trascorso", - "TimeSpendReport": "Tempo", - "TimeSpendReportAdd": "Aggiungi rapporto sul tempo", - "TimeSpendReportDate": "Data", - "TimeSpendReportValue": "Tempo trascorso", - "TimeSpendReportValueTooltip": "Tempo trascorso in ore", - "TimeSpendReportDescription": "Descrizione", - "TimeSpendDays": "{value}d", - "TimeSpendHours": "{value}h", - "TimeSpendMinutes": "{value}m", - "ChildEstimation": "Stima delle subissue", - "ChildReportedTime": "Tempo delle subissue", - "CapacityValue": "di {value}d", - "NewRelatedIssue": "Nuova issue correlata", - "RelatedIssuesNotFound": "Issue correlate non trovate", - "AddedReference": "Riferimento aggiunto", - "AddedAsBlocked": "Contrassegnato come bloccato", - "AddedAsBlocking": "Contrassegnato come bloccante", - "IssueTemplate": "Modello", - "IssueTemplates": "Modelli", - "NewProcess": "Nuovo modello", - "SaveProcess": "Salva modello", - "NoIssueTemplate": "Nessun modello", - "TemplateReplace": "Vuoi applicare il nuovo modello?", - "TemplateReplaceConfirm": "Tutti i campi saranno sovrascritti dai valori del nuovo modello", - "Apply": "Applica", - "CurrentWorkDay": "Giorno lavorativo corrente", - "PreviousWorkDay": "Giorno lavorativo precedente", - "TimeReportDayTypeLabel": "Seleziona il tipo di giorno", - "DefaultAssignee": "Assegnatario predefinito per le issue", - "SevenHoursLength": "Sette ore", - "EightHoursLength": "Otto ore", - "HourLabel": "h", - "MinuteLabel": "m", - "Saved": "Salvato...", - "CreatedIssue": "Issue creata", - "CreatedSubIssue": "Subissue creata", - "ChangeStatus": "Cambia stato", - "ConfigLabel": "Tracker", - "ConfigDescription": "Estensione per gestire elementi di lavoro e completare tutte le attività.", - "NoStatusFound": "Nessuno stato corrispondente trovato", - "CreateMissingStatus": "Crea stato mancante", - "UnsetParent": "La issue genitore sarà annullato", - "AllProjects": "Tutti i progetti", - "IssueNotificationTitle": "{issueTitle}", - "IssueNotificationBody": "Aggiornato da {senderName}", - "IssueNotificationChanged": "{senderName} ha modificato {property}", - "IssueNotificationChangedProperty": "{senderName} ha modificato {property} in \"{newValue}\"", - "IssueNotificationMessage": "{senderName}: {message}", - "PreviousAssigned": "Assegnato in precedenza", - "IssueAssignedToYou": "Assegnato a te", - "RelatedIssueTargetDescription": "Obiettivo del progetto del problema correlato per Classe o Spazio", - "MapRelatedIssues": "Configura i progetti predefiniti per issue correlate", - "DefaultIssueStatus": "Stato predefinito della issue", - "IssueStatus": "Stato", - "Extensions": "Estensioni", - "UnsetParentIssue": "Annulla l'issue genitore", - "ForbidCreateProjectPermission": "Vieta creazione progetto", - "ForbidCreateProjectPermissionDescription": "Vieta agli utenti di creare nuovi progetti", - "AllowCreatingIssues": "Consenti la creazione di issue", - "Day": "Giorno", - "Gantt": "Gantt", - "Month": "Mese", - "Quarter": "Trimestre", - "Week": "Settimana" - }, - "status": {} -} + "string": { + "TrackerApplication": "Tracker", + "Projects": "I tuoi progetti", + "More": "Altro", + "Default": "Predefinito", + "MakeDefault": "Imposta come predefinito", + "Delete": "Elimina", + "Open": "Apri", + "Members": "Membri", + "Inbox": "Posta in arrivo", + "MyIssues": "Le mie issues", + "ViewIssue": "Visualizza issue", + "IssueCreated": "Issue creata", + "Issues": "Issue", + "Views": "Visualizzazioni", + "Active": "Attivo", + "AllIssues": "Tutte le issue", + "ActiveIssues": "Issue attive", + "BacklogIssues": "Backlog", + "Backlog": "Backlog", + "Board": "Bacheca", + "Components": "Componenti", + "AllComponents": "Tutti", + "BacklogComponents": "Backlog", + "ActiveComponents": "Attivi", + "ClosedComponents": "Chiuso", + "NewComponent": "Nuovo componente", + "CreateComponent": "Crea componente", + "ComponentNamePlaceholder": "Nome del componente", + "ComponentDescriptionPlaceholder": "Descrizione (facoltativo)", + "ComponentLead": "Responsabile", + "ComponentMembers": "Membri", + "StartDate": "Data di inizio", + "TargetDate": "Data obiettivo", + "Planned": "Pianificato", + "InProgress": "In corso", + "Paused": "In pausa", + "Completed": "Completato", + "Canceled": "Annullato", + "CreateProject": "Crea progetto", + "NewProject": "Nuovo progetto", + "ProjectTitle": "Titolo del progetto", + "ProjectTitlePlaceholder": "Nuovo progetto", + "UsedInIssueIDs": "Utilizzato negli ID delle issue", + "Identifier": "Identificatore", + "Import": "Importa", + "ProjectIdentifier": "Identificatore del progetto", + "IdentifierExists": "L'identificatore del progetto esiste già", + "ProjectIdentifierPlaceholder": "PRJCT", + "ChooseIcon": "Scegli icona", + "AddIssue": "Aggiungi issue", + "NewIssue": "Nuova issue", + "NewIssuePlaceholder": "Nuovo", + "ResumeDraft": "Riprendi bozza", + "SaveIssue": "Crea issue", + "SetPriority": "Imposta priorità…", + "SetStatus": "Imposta stato…", + "SelectIssue": "Seleziona issue", + "Priority": "Priorità", + "NoPriority": "Nessuna priorità", + "Urgent": "Urgente", + "High": "Alto", + "Medium": "Medio", + "Low": "Basso", + "Unassigned": "Non assegnato", + "Back": "Indietro", + "List": "Elenco", + "NumberLabels": "{count, plural, =0 {nessuna etichetta} =1 {1 etichetta} other {# etichette}}", + "CategoryBacklog": "Backlog", + "CategoryUnstarted": "Non iniziato", + "CategoryStarted": "Iniziato", + "CategoryCompleted": "Completato", + "CategoryCanceled": "Annullato", + "Title": "Titolo", + "Name": "Nome", + "Description": "Descrizione", + "Status": "Stato", + "Number": "Numero", + "Assignee": "Assegnatario", + "AssignTo": "Assegna a...", + "AssignedTo": "Assegnato a {value}", + "Parent": "Issue genitore", + "SetParent": "Imposta issue genitore…", + "ChangeParent": "Cambia issue genitore…", + "RemoveParent": "Rimuovi issue genitore", + "OpenParent": "Apri issue genitore", + "SubIssues": "Subissue", + "SubIssuesList": "Subissue ({subIssues})", + "OpenSubIssues": "Apri subissue", + "AddSubIssues": "Aggiungi subissue", + "BlockedBy": "Bloccato da", + "RelatedTo": "Correlato a", + "Comments": "Commenti", + "Attachments": "Allegati", + "Labels": "Etichette", + "Component": "Componente", + "Space": "", + "SetDueDate": "Imposta data di scadenza…", + "ChangeDueDate": "Cambia data di scadenza…", + "ModificationDate": "Aggiornato {value}", + "Project": "Progetto", + "Issue": "Issue", + "SubIssue": "Subissue", + "Document": "", + "DocumentIcon": "", + "DocumentColor": "", + "Rank": "Classifica", + "TypeIssuePriority": "Priorità della issue", + "IssueTitlePlaceholder": "Titolo della issue", + "SubIssueTitlePlaceholder": "Titolo della subissue", + "IssueDescriptionPlaceholder": "Aggiungi descrizione…", + "SubIssueDescriptionPlaceholder": "Aggiungi descrizione della subissue", + "AddIssueTooltip": "Aggiungi issue...", + "NewIssueDialogClose": "Vuoi chiudere questo dialogo?", + "NewIssueDialogCloseNote": "Tutte le modifiche andranno perse", + "RemoveComponentDialogClose": "Eliminare il componente?", + "RemoveComponentDialogCloseNote": "Sei sicuro di voler eliminare questo componente? Questa operazione non può essere annullata", + "Grouping": "Raggruppamento", + "Ordering": "Ordinamento", + "CompletedIssues": "Issue completate", + "NoGrouping": "Nessun raggruppamento", + "NoAssignee": "Nessun assegnatario", + "LastUpdated": "Ultimo aggiornamento", + "DueDate": "Data di scadenza", + "IssueStartDate": "Data di inizio", + "GanttDependency": "Dependency", + "GanttLag": "Lag", + "Manual": "Manuale", + "All": "Tutti", + "PastWeek": "Settimana scorsa", + "PastMonth": "Mese scorso", + "CopyIssueUrl": "Copia URL della issue negli appunti", + "CopyIssueId": "Copia ID della issue negli appunti", + "CopyIssueBranch": "Copia nome del ramo Git negli appunti", + "CopyIssueTitle": "Copia titolo della issue negli appunti", + "AssetLabel": "Risorsa", + "AddToComponent": "Aggiungi al componente…", + "MoveToComponent": "Sposta nel componente…", + "NoComponent": "Nessun componente", + "ComponentLeadTitle": "Responsabile del componente", + "ComponentMembersTitle": "Membri del componente", + "ComponentLeadSearchPlaceholder": "Imposta responsabile del componente…", + "ComponentMembersSearchPlaceholder": "Cambia membri del componente…", + "MoveToProject": "Sposta nel progetto", + "Duplicate": "Duplicato", + "GotoIssues": "Vai alle issue", + "GotoActive": "Vai alle issue attive", + "GotoBacklog": "Vai al backlog", + "GotoComponents": "Vai ai componenti", + "GotoMyIssues": "Vai alle mie issue", + "GotoTrackerApplication": "Passa all'applicazione Tracker", + "CreatedOne": "Creato", + "MoveIssues": "Sposta issue", + "MoveIssuesDescription": "Seleziona il progetto in cui desideri spostare le issue", + "ManageAttributes": "Gestisci attributi", + "KeepOriginalAttributes": "Mantieni attributi originali", + "KeepOriginalAttributesTooltip": "Gli stati e i componenti originali delle issue saranno mantenuti nel nuovo progetto", + "SelectReplacement": "I seguenti elementi non sono disponibili nel nuovo progetto. Seleziona un sostituto.", + "MissingItem": "ELEMENTO MANCANTE", + "Replacement": "SOSTITUTO", + "Original": "ORIGINALE", + "OriginalDescription": "Gli elementi di questa sezione verranno creati nel nuovo progetto", + "Relations": "Relazioni", + "RemoveRelation": "Rimuovi relazione...", + "AddBlockedBy": "Segna come bloccato da...", + "AddIsBlocking": "Segna come bloccante...", + "AddRelatedIssue": "Riferisci un'altra issue...", + "RelatedIssue": "Issue correlato {id} - {title}", + "BlockedIssue": "Issue bloccato {id} - {title}", + "BlockingIssue": "Issue bloccante {id} - {title}", + "BlockedBySearchPlaceholder": "Cerca una issue da contrassegnare come bloccato da...", + "IsBlockingSearchPlaceholder": "Cerca una issue da contrassegnare come bloccante...", + "RelatedIssueSearchPlaceholder": "Cerca una issue da riferire...", + "Blocks": "Blocca", + "Related": "Correlato", + "RelatedIssues": "Issue correlate", + "EditIssue": "Modifica {title}", + "EditWorkflowStatuses": "Modifica stati della issue", + "EditProject": "Modifica progetto", + "DeleteProject": "Elimina progetto", + "ArchiveProjectName": "Archivia progetto {name}?", + "ArchiveProjectConfirm": "Vuoi archiviare questo progetto?", + "DeleteProjectConfirm": "Vuoi eliminare questo progetto e tutte le issue?", + "ProjectHasIssues": "Ci sono issue esistenti in questo progetto, sei sicuro di voler archiviare?", + "ManageWorkflowStatuses": "Gestisci tipi di progetto", + "AddWorkflowStatus": "Aggiungi stato della issue", + "EditWorkflowStatus": "Modifica stato della issue", + "DeleteWorkflowStatus": "Elimina stato della issue", + "DeleteWorkflowStatusConfirm": "Vuoi eliminare lo stato \"{status}\"?", + "DeleteWorkflowStatusErrorDescription": "Lo stato \"{status}\" ha {count, plural, =1 {1 issue} other {# issue}} assegnate. Seleziona uno stato per spostare", + "Save": "Salva", + "IncludeItemsThatMatch": "Includi elementi che corrispondono", + "AnyFilter": "qualunque filtro", + "AllFilters": "tutti i filtri", + "NoDescription": "Nessuna descrizione", + "SearchIssue": "Cerca attività...", + "StatusHistory": "Storia degli stati", + "NewSubIssue": "Aggiungi subissue...", + "AddLabel": "Aggiungi etichetta", + "DeleteIssue": "Elimina {issueCount, plural, =1 {issue} other {# issue}}", + "DeleteIssueConfirm": "Vuoi eliminare {issueCount, plural, =1 {issue} other {issue}}{subIssueCount, plural, =0 {?} =1 { e subissue?} other { e subissue?}}", + "Milestone": "Traguardo", + "NoMilestone": "Nessun traguardo", + "MoveToMilestone": "Seleziona traguardo", + "Milestones": "Traguardi", + "AllMilestones": "Tutti", + "PlannedMilestones": "Pianificati", + "ActiveMilestones": "Attivi", + "ClosedMilestones": "Fatto", + "AddToMilestone": "Aggiungi al traguardo", + "MilestoneNamePlaceholder": "Nome del traguardo", + "NewMilestone": "Nuovo traguardo", + "CreateMilestone": "Crea", + "MoveAndDeleteMilestone": "Sposta problemi in {newMilestone} ed elimina {deleteMilestone}", + "MoveAndDeleteMilestoneConfirm": "Vuoi eliminare il traguardo e spostare i problemi in un altro traguardo?", + "Estimation": "Stima", + "ReportedTime": "Tempo trascorso", + "RemainingTime": "Tempo rimanente", + "TimeSpendReports": "Rapporti sul tempo trascorso", + "TimeSpendReport": "Tempo", + "TimeSpendReportAdd": "Aggiungi rapporto sul tempo", + "TimeSpendReportDate": "Data", + "TimeSpendReportValue": "Tempo trascorso", + "TimeSpendReportValueTooltip": "Tempo trascorso in ore", + "TimeSpendReportDescription": "Descrizione", + "TimeSpendDays": "{value}d", + "TimeSpendHours": "{value}h", + "TimeSpendMinutes": "{value}m", + "ChildEstimation": "Stima delle subissue", + "ChildReportedTime": "Tempo delle subissue", + "CapacityValue": "di {value}d", + "NewRelatedIssue": "Nuova issue correlata", + "RelatedIssuesNotFound": "Issue correlate non trovate", + "AddedReference": "Riferimento aggiunto", + "AddedAsBlocked": "Contrassegnato come bloccato", + "AddedAsBlocking": "Contrassegnato come bloccante", + "IssueTemplate": "Modello", + "IssueTemplates": "Modelli", + "NewProcess": "Nuovo modello", + "SaveProcess": "Salva modello", + "NoIssueTemplate": "Nessun modello", + "TemplateReplace": "Vuoi applicare il nuovo modello?", + "TemplateReplaceConfirm": "Tutti i campi saranno sovrascritti dai valori del nuovo modello", + "Apply": "Applica", + "CurrentWorkDay": "Giorno lavorativo corrente", + "PreviousWorkDay": "Giorno lavorativo precedente", + "TimeReportDayTypeLabel": "Seleziona il tipo di giorno", + "DefaultAssignee": "Assegnatario predefinito per le issue", + "SevenHoursLength": "Sette ore", + "EightHoursLength": "Otto ore", + "HourLabel": "h", + "MinuteLabel": "m", + "Saved": "Salvato...", + "CreatedIssue": "Issue creata", + "CreatedSubIssue": "Subissue creata", + "ChangeStatus": "Cambia stato", + "ConfigLabel": "Tracker", + "ConfigDescription": "Estensione per gestire elementi di lavoro e completare tutte le attività.", + "NoStatusFound": "Nessuno stato corrispondente trovato", + "CreateMissingStatus": "Crea stato mancante", + "UnsetParent": "La issue genitore sarà annullato", + "AllProjects": "Tutti i progetti", + "IssueNotificationTitle": "{issueTitle}", + "IssueNotificationBody": "Aggiornato da {senderName}", + "IssueNotificationChanged": "{senderName} ha modificato {property}", + "IssueNotificationChangedProperty": "{senderName} ha modificato {property} in \"{newValue}\"", + "IssueNotificationMessage": "{senderName}: {message}", + "PreviousAssigned": "Assegnato in precedenza", + "IssueAssignedToYou": "Assegnato a te", + "RelatedIssueTargetDescription": "Obiettivo del progetto del problema correlato per Classe o Spazio", + "MapRelatedIssues": "Configura i progetti predefiniti per issue correlate", + "DefaultIssueStatus": "Stato predefinito della issue", + "IssueStatus": "Stato", + "Extensions": "Estensioni", + "UnsetParentIssue": "Annulla l'issue genitore", + "ForbidCreateProjectPermission": "Vieta creazione progetto", + "ForbidCreateProjectPermissionDescription": "Vieta agli utenti di creare nuovi progetti", + "AllowCreatingIssues": "Consenti la creazione di issue", + "Day": "Giorno", + "Gantt": "Gantt", + "Month": "Mese", + "Quarter": "Trimestre", + "Week": "Settimana", + "GanttShowIssueCode": "Show issue code", + "GanttShowTitle": "Show title" + }, + "status": {} +} \ No newline at end of file diff --git a/plugins/tracker-assets/lang/ja.json b/plugins/tracker-assets/lang/ja.json index 61b13474fd4..d522504f663 100644 --- a/plugins/tracker-assets/lang/ja.json +++ b/plugins/tracker-assets/lang/ja.json @@ -1,287 +1,289 @@ { - "string": { - "TrackerApplication": "トラッカー", - "Projects": "あなたのプロジェクト", - "More": "その他", - "Default": "デフォルト", - "MakeDefault": "デフォルトに設定", - "Delete": "削除", - "Open": "開く", - "Members": "メンバー", - "Inbox": "受信箱", - "MyIssues": "自分のイシュー", - "ViewIssue": "イシューを表示", - "IssueCreated": "イシューが作成されました", - "Issues": "イシュー", - "Views": "ビュー", - "Active": "アクティブ", - "AllIssues": "すべてのイシュー", - "ActiveIssues": "アクティブなイシュー", - "BacklogIssues": "バックログ", - "Backlog": "バックログ", - "Board": "ボード", - "Components": "コンポーネント", - "AllComponents": "すべて", - "BacklogComponents": "バックログ", - "ActiveComponents": "アクティブ", - "ClosedComponents": "完了", - "NewComponent": "新しいコンポーネント", - "CreateComponent": "コンポーネントを作成", - "ComponentNamePlaceholder": "コンポーネント名", - "ComponentDescriptionPlaceholder": "説明 (オプション)", - "ComponentLead": "リーダー", - "ComponentMembers": "メンバー", - "StartDate": "開始日", - "TargetDate": "目標日", - "Planned": "計画済み", - "InProgress": "進行中", - "Paused": "一時停止", - "Completed": "完了", - "Canceled": "キャンセル", - "CreateProject": "プロジェクトを作成", - "NewProject": "新しいプロジェクト", - "ProjectTitle": "プロジェクトタイトル", - "ProjectTitlePlaceholder": "新しいプロジェクト", - "UsedInIssueIDs": "イシューIDで使用", - "Identifier": "識別子", - "Import": "インポート", - "ProjectIdentifier": "プロジェクト識別子", - "IdentifierExists": "プロジェクト識別子はすでに存在します", - "ProjectIdentifierPlaceholder": "PRJCT", - "ChooseIcon": "アイコンを選択", - "AddIssue": "イシューを追加", - "NewIssue": "新しいイシュー", - "NewIssuePlaceholder": "新規", - "ResumeDraft": "下書きを再開", - "SaveIssue": "イシューを作成", - "SetPriority": "優先度を設定\u2026", - "SetStatus": "ステータスを設定\u2026", - "SelectIssue": "イシューを選択", - "Priority": "優先度", - "NoPriority": "優先度なし", - "Urgent": "緊急", - "High": "高", - "Medium": "中", - "Low": "低", - "Unassigned": "未割り当て", - "Back": "戻る", - "List": "リスト", - "NumberLabels": "{count, plural, =0 {ラベルなし} =1 {1 ラベル} other {# ラベル}}", - "CategoryBacklog": "バックログ", - "CategoryUnstarted": "未着手", - "CategoryStarted": "開始", - "CategoryCompleted": "完了", - "CategoryCanceled": "キャンセル", - "Title": "タイトル", - "Name": "名前", - "Description": "説明", - "Status": "ステータス", - "Number": "番号", - "Assignee": "担当者", - "AssignTo": "担当者を設定...", - "AssignedTo": "{value} に割り当て", - "Parent": "親イシュー", - "SetParent": "親イシューを設定\u2026", - "ChangeParent": "親イシューを変更\u2026", - "RemoveParent": "親イシューを削除", - "OpenParent": "親イシューを開く", - "SubIssues": "子イシュー", - "SubIssuesList": "子イシュー ({subIssues})", - "OpenSubIssues": "子イシューを開く", - "AddSubIssues": "子イシューを追加", - "BlockedBy": "ブロックされている", - "RelatedTo": "関連する", - "Comments": "コメント", - "Attachments": "添付ファイル", - "Labels": "ラベル", - "Component": "コンポーネント", - "Space": "", - "SetDueDate": "期日を設定\u2026", - "ChangeDueDate": "期日を変更\u2026", - "ModificationDate": "更新日 {value}", - "Project": "プロジェクト", - "Issue": "イシュー", - "SubIssue": "子イシュー", - "Document": "", - "DocumentIcon": "", - "DocumentColor": "", - "Rank": "ランク", - "TypeIssuePriority": "イシューの優先度", - "IssueTitlePlaceholder": "イシューのタイトル", - "SubIssueTitlePlaceholder": "子イシューのタイトル", - "IssueDescriptionPlaceholder": "説明を追加\u2026", - "SubIssueDescriptionPlaceholder": "子イシューの説明を追加", - "AddIssueTooltip": "イシューを追加...", - "NewIssueDialogClose": "このダイアログを閉じますか?", - "NewIssueDialogCloseNote": "すべての変更は失われます", - "RemoveComponentDialogClose": "コンポーネントを削除しますか?", - "RemoveComponentDialogCloseNote": "本当にこのコンポーネントを削除しますか?この操作は元に戻せません", - "Grouping": "グループ化", - "Ordering": "順序", - "CompletedIssues": "完了したイシュー", - "NoGrouping": "グループ化なし", - "NoAssignee": "担当者なし", - "LastUpdated": "最終更新日", - "DueDate": "期日", - "IssueStartDate": "開始日", - "GanttDependency": "Dependency", - "GanttLag": "Lag", - "Manual": "手動", - "All": "すべて", - "PastWeek": "先週", - "PastMonth": "先月", - "CopyIssueUrl": "イシューのURLをクリップボードにコピー", - "CopyIssueId": "イシューIDをクリップボードにコピー", - "CopyIssueBranch": "Gitブランチ名をクリップボードにコピー", - "CopyIssueTitle": "イシューのタイトルをクリップボードにコピー", - "AssetLabel": "アセット", - "AddToComponent": "コンポーネントに追加\u2026", - "MoveToComponent": "コンポーネントに移動\u2026", - "NoComponent": "コンポーネントなし", - "ComponentLeadTitle": "コンポーネントリーダー", - "ComponentMembersTitle": "コンポーネントメンバー", - "ComponentLeadSearchPlaceholder": "コンポーネントリーダーを設定\u2026", - "ComponentMembersSearchPlaceholder": "コンポーネントメンバーを変更\u2026", - "MoveToProject": "プロジェクトに移動", - "Duplicate": "複製", - "GotoIssues": "イシューへ移動", - "GotoActive": "アクティブなイシューへ移動", - "GotoBacklog": "バックログへ移動", - "GotoComponents": "コンポーネントへ移動", - "GotoMyIssues": "自分のイシューへ移動", - "GotoTrackerApplication": "トラッカーアプリケーションに切り替え", - "CreatedOne": "作成済み", - "MoveIssues": "イシューを移動", - "MoveIssuesDescription": "イシューを移動するプロジェクトを選択します", - "ManageAttributes": "属性を管理", - "KeepOriginalAttributes": "元の属性を保持", - "KeepOriginalAttributesTooltip": "元のイシューステータスとコンポーネントは新しいプロジェクトに保持されます", - "SelectReplacement": "次のアイテムは新しいプロジェクトで利用できません。代替を選択してください。", - "MissingItem": "不足しているアイテム", - "Replacement": "代替", - "Original": "オリジナル", - "OriginalDescription": "このセクションのアイテムは新しいプロジェクトで作成されます", - "Relations": "関連", - "RemoveRelation": "関連を削除...", - "AddBlockedBy": "ブロックされているとしてマーク...", - "AddIsBlocking": "ブロックしているとしてマーク...", - "AddRelatedIssue": "別のイシューを参照...", - "RelatedIssue": "関連するイシュー {id} - {title}", - "BlockedIssue": "ブロックされているイシュー {id} - {title}", - "BlockingIssue": "ブロックしているイシュー {id} - {title}", - "BlockedBySearchPlaceholder": "ブロックされているとしてマークするイシューを検索...", - "IsBlockingSearchPlaceholder": "ブロックしているとしてマークするイシューを検索...", - "RelatedIssueSearchPlaceholder": "参照するイシューを検索...", - "Blocks": "ブロック", - "Related": "関連", - "RelatedIssues": "関連するイシュー", - "EditIssue": "{title} を編集", - "EditWorkflowStatuses": "イシューステータスを編集", - "EditProject": "プロジェクトを編集", - "DeleteProject": "プロジェクトを削除", - "ArchiveProjectName": "プロジェクト {name} をアーカイブしますか?", - "ArchiveProjectConfirm": "このプロジェクトをアーカイブしますか?", - "DeleteProjectConfirm": "このプロジェクトとすべてのイシューを削除しますか?", - "ProjectHasIssues": "このプロジェクトには既存のイシューがあります。アーカイブしてもよろしいですか?", - "ManageWorkflowStatuses": "プロジェクトタイプを管理", - "AddWorkflowStatus": "イシューステータスを追加", - "EditWorkflowStatus": "イシューステータスを編集", - "DeleteWorkflowStatus": "イシューステータスを削除", - "DeleteWorkflowStatusConfirm": "\"{status}\" ステータスを削除しますか?", - "DeleteWorkflowStatusErrorDescription": "\"{status}\" ステータスには {count, plural, =1 {1 イシュー} other {# イシュー}} が割り当てられています。移動先のステータスを選択してください", - "Save": "保存", - "IncludeItemsThatMatch": "一致するアイテムを含める", - "AnyFilter": "いずれかのフィルター", - "AllFilters": "すべてのフィルター", - "NoDescription": "説明なし", - "SearchIssue": "タスクを検索...", - "StatusHistory": "状態履歴", - "NewSubIssue": "子イシューを追加...", - "AddLabel": "ラベルを追加", - "DeleteIssue": "{issueCount, plural, =1 {イシュー} other {イシュー}} を削除", - "DeleteIssueConfirm": "{issueCount, plural, =1 {イシュー} other {イシュー}}{subIssueCount, plural, =0 {?} =1 { と子イシュー?} other { と子イシュー?}} を削除しますか?", - "Milestone": "マイルストーン", - "NoMilestone": "マイルストーンなし", - "MoveToMilestone": "マイルストーンを選択", - "Milestones": "マイルストーン", - "AllMilestones": "すべて", - "PlannedMilestones": "計画済み", - "ActiveMilestones": "アクティブ", - "ClosedMilestones": "完了", - "AddToMilestone": "マイルストーンに追加", - "MilestoneNamePlaceholder": "マイルストーン名", - "NewMilestone": "新しいマイルストーン", - "CreateMilestone": "作成", - "MoveAndDeleteMilestone": "イシューを {newMilestone} に移動し、{deleteMilestone} を削除", - "MoveAndDeleteMilestoneConfirm": "マイルストーンを削除し、イシューを別のマイルストーンに移動しますか?", - "Estimation": "見積もり", - "ReportedTime": "消費時間", - "RemainingTime": "残り時間", - "TimeSpendReports": "時間消費レポート", - "TimeSpendReport": "時間", - "TimeSpendReportAdd": "時間レポートを追加", - "TimeSpendReportDate": "日付", - "TimeSpendReportValue": "消費時間", - "TimeSpendReportValueTooltip": "消費時間 (時間)", - "TimeSpendReportDescription": "説明", - "TimeSpendDays": "{value}日", - "TimeSpendHours": "{value}時間", - "TimeSpendMinutes": "{value}分", - "ChildEstimation": "子イシューの見積もり", - "ChildReportedTime": "子イシューの時間", - "CapacityValue": "うち {value}日", - "NewRelatedIssue": "新しい関連イシュー", - "RelatedIssuesNotFound": "関連イシューが見つかりません", - "AddedReference": "参照を追加", - "AddedAsBlocked": "ブロックされているとしてマーク", - "AddedAsBlocking": "ブロックしているとしてマーク", - "IssueTemplate": "テンプレート", - "IssueTemplates": "テンプレート", - "NewProcess": "新しいテンプレート", - "SaveProcess": "テンプレートを保存", - "NoIssueTemplate": "テンプレートなし", - "TemplateReplace": "新しいテンプレートを適用しますか?", - "TemplateReplaceConfirm": "すべてのフィールドが新しいテンプレートの値で上書きされます", - "Apply": "適用", - "CurrentWorkDay": "現在の営業日", - "PreviousWorkDay": "前の営業日", - "TimeReportDayTypeLabel": "時間レポートの日種別を選択", - "DefaultAssignee": "イシューのデフォルトの担当者", - "SevenHoursLength": "7時間", - "EightHoursLength": "8時間", - "HourLabel": "時間", - "MinuteLabel": "分", - "Saved": "保存済み...", - "CreatedIssue": "イシューを作成しました", - "CreatedSubIssue": "子イシューを作成しました", - "ChangeStatus": "ステータスを変更", - "ConfigLabel": "トラッカー", - "ConfigDescription": "作業項目を管理し、すべてのジョブを完了するための拡張機能。", - "NoStatusFound": "一致するステータスが見つかりません", - "CreateMissingStatus": "不足しているステータスを作成", - "UnsetParent": "親イシューが設定されなくなります", - "AllProjects": "すべてのプロジェクト", - "IssueNotificationTitle": "{issueTitle}", - "IssueNotificationBody": "{senderName} が更新しました", - "IssueNotificationChanged": "{senderName} が {property} を変更しました", - "IssueNotificationChangedProperty": "{senderName} が {property} を \"{newValue}\" に変更しました", - "IssueNotificationMessage": "{senderName}: {message}", - "PreviousAssigned": "以前に割り当てられた", - "IssueAssignedToYou": "あなたに割り当てられました", - "RelatedIssueTargetDescription": "クラスまたはスペースの関連イシュープロジェクトターゲット", - "MapRelatedIssues": "関連イシューのデフォルトプロジェクトを構成", - "DefaultIssueStatus": "デフォルトのイシューステータス", - "IssueStatus": "ステータス", - "Extensions": "拡張機能", - "UnsetParentIssue": "親イシューの設定を解除", - "ForbidCreateProjectPermission": "プロジェクト作成禁止", - "ForbidCreateProjectPermissionDescription": "ユーザーが新しいプロジェクトを作成することを禁止します", - "AllowCreatingIssues": "イシューの作成を許可", - "Day": "日", - "Gantt": "Gantt", - "Month": "月", - "Quarter": "四半期", - "Week": "週" - }, - "status": {} -} + "string": { + "TrackerApplication": "トラッカー", + "Projects": "あなたのプロジェクト", + "More": "その他", + "Default": "デフォルト", + "MakeDefault": "デフォルトに設定", + "Delete": "削除", + "Open": "開く", + "Members": "メンバー", + "Inbox": "受信箱", + "MyIssues": "自分のイシュー", + "ViewIssue": "イシューを表示", + "IssueCreated": "イシューが作成されました", + "Issues": "イシュー", + "Views": "ビュー", + "Active": "アクティブ", + "AllIssues": "すべてのイシュー", + "ActiveIssues": "アクティブなイシュー", + "BacklogIssues": "バックログ", + "Backlog": "バックログ", + "Board": "ボード", + "Components": "コンポーネント", + "AllComponents": "すべて", + "BacklogComponents": "バックログ", + "ActiveComponents": "アクティブ", + "ClosedComponents": "完了", + "NewComponent": "新しいコンポーネント", + "CreateComponent": "コンポーネントを作成", + "ComponentNamePlaceholder": "コンポーネント名", + "ComponentDescriptionPlaceholder": "説明 (オプション)", + "ComponentLead": "リーダー", + "ComponentMembers": "メンバー", + "StartDate": "開始日", + "TargetDate": "目標日", + "Planned": "計画済み", + "InProgress": "進行中", + "Paused": "一時停止", + "Completed": "完了", + "Canceled": "キャンセル", + "CreateProject": "プロジェクトを作成", + "NewProject": "新しいプロジェクト", + "ProjectTitle": "プロジェクトタイトル", + "ProjectTitlePlaceholder": "新しいプロジェクト", + "UsedInIssueIDs": "イシューIDで使用", + "Identifier": "識別子", + "Import": "インポート", + "ProjectIdentifier": "プロジェクト識別子", + "IdentifierExists": "プロジェクト識別子はすでに存在します", + "ProjectIdentifierPlaceholder": "PRJCT", + "ChooseIcon": "アイコンを選択", + "AddIssue": "イシューを追加", + "NewIssue": "新しいイシュー", + "NewIssuePlaceholder": "新規", + "ResumeDraft": "下書きを再開", + "SaveIssue": "イシューを作成", + "SetPriority": "優先度を設定…", + "SetStatus": "ステータスを設定…", + "SelectIssue": "イシューを選択", + "Priority": "優先度", + "NoPriority": "優先度なし", + "Urgent": "緊急", + "High": "高", + "Medium": "中", + "Low": "低", + "Unassigned": "未割り当て", + "Back": "戻る", + "List": "リスト", + "NumberLabels": "{count, plural, =0 {ラベルなし} =1 {1 ラベル} other {# ラベル}}", + "CategoryBacklog": "バックログ", + "CategoryUnstarted": "未着手", + "CategoryStarted": "開始", + "CategoryCompleted": "完了", + "CategoryCanceled": "キャンセル", + "Title": "タイトル", + "Name": "名前", + "Description": "説明", + "Status": "ステータス", + "Number": "番号", + "Assignee": "担当者", + "AssignTo": "担当者を設定...", + "AssignedTo": "{value} に割り当て", + "Parent": "親イシュー", + "SetParent": "親イシューを設定…", + "ChangeParent": "親イシューを変更…", + "RemoveParent": "親イシューを削除", + "OpenParent": "親イシューを開く", + "SubIssues": "子イシュー", + "SubIssuesList": "子イシュー ({subIssues})", + "OpenSubIssues": "子イシューを開く", + "AddSubIssues": "子イシューを追加", + "BlockedBy": "ブロックされている", + "RelatedTo": "関連する", + "Comments": "コメント", + "Attachments": "添付ファイル", + "Labels": "ラベル", + "Component": "コンポーネント", + "Space": "", + "SetDueDate": "期日を設定…", + "ChangeDueDate": "期日を変更…", + "ModificationDate": "更新日 {value}", + "Project": "プロジェクト", + "Issue": "イシュー", + "SubIssue": "子イシュー", + "Document": "", + "DocumentIcon": "", + "DocumentColor": "", + "Rank": "ランク", + "TypeIssuePriority": "イシューの優先度", + "IssueTitlePlaceholder": "イシューのタイトル", + "SubIssueTitlePlaceholder": "子イシューのタイトル", + "IssueDescriptionPlaceholder": "説明を追加…", + "SubIssueDescriptionPlaceholder": "子イシューの説明を追加", + "AddIssueTooltip": "イシューを追加...", + "NewIssueDialogClose": "このダイアログを閉じますか?", + "NewIssueDialogCloseNote": "すべての変更は失われます", + "RemoveComponentDialogClose": "コンポーネントを削除しますか?", + "RemoveComponentDialogCloseNote": "本当にこのコンポーネントを削除しますか?この操作は元に戻せません", + "Grouping": "グループ化", + "Ordering": "順序", + "CompletedIssues": "完了したイシュー", + "NoGrouping": "グループ化なし", + "NoAssignee": "担当者なし", + "LastUpdated": "最終更新日", + "DueDate": "期日", + "IssueStartDate": "開始日", + "GanttDependency": "Dependency", + "GanttLag": "Lag", + "Manual": "手動", + "All": "すべて", + "PastWeek": "先週", + "PastMonth": "先月", + "CopyIssueUrl": "イシューのURLをクリップボードにコピー", + "CopyIssueId": "イシューIDをクリップボードにコピー", + "CopyIssueBranch": "Gitブランチ名をクリップボードにコピー", + "CopyIssueTitle": "イシューのタイトルをクリップボードにコピー", + "AssetLabel": "アセット", + "AddToComponent": "コンポーネントに追加…", + "MoveToComponent": "コンポーネントに移動…", + "NoComponent": "コンポーネントなし", + "ComponentLeadTitle": "コンポーネントリーダー", + "ComponentMembersTitle": "コンポーネントメンバー", + "ComponentLeadSearchPlaceholder": "コンポーネントリーダーを設定…", + "ComponentMembersSearchPlaceholder": "コンポーネントメンバーを変更…", + "MoveToProject": "プロジェクトに移動", + "Duplicate": "複製", + "GotoIssues": "イシューへ移動", + "GotoActive": "アクティブなイシューへ移動", + "GotoBacklog": "バックログへ移動", + "GotoComponents": "コンポーネントへ移動", + "GotoMyIssues": "自分のイシューへ移動", + "GotoTrackerApplication": "トラッカーアプリケーションに切り替え", + "CreatedOne": "作成済み", + "MoveIssues": "イシューを移動", + "MoveIssuesDescription": "イシューを移動するプロジェクトを選択します", + "ManageAttributes": "属性を管理", + "KeepOriginalAttributes": "元の属性を保持", + "KeepOriginalAttributesTooltip": "元のイシューステータスとコンポーネントは新しいプロジェクトに保持されます", + "SelectReplacement": "次のアイテムは新しいプロジェクトで利用できません。代替を選択してください。", + "MissingItem": "不足しているアイテム", + "Replacement": "代替", + "Original": "オリジナル", + "OriginalDescription": "このセクションのアイテムは新しいプロジェクトで作成されます", + "Relations": "関連", + "RemoveRelation": "関連を削除...", + "AddBlockedBy": "ブロックされているとしてマーク...", + "AddIsBlocking": "ブロックしているとしてマーク...", + "AddRelatedIssue": "別のイシューを参照...", + "RelatedIssue": "関連するイシュー {id} - {title}", + "BlockedIssue": "ブロックされているイシュー {id} - {title}", + "BlockingIssue": "ブロックしているイシュー {id} - {title}", + "BlockedBySearchPlaceholder": "ブロックされているとしてマークするイシューを検索...", + "IsBlockingSearchPlaceholder": "ブロックしているとしてマークするイシューを検索...", + "RelatedIssueSearchPlaceholder": "参照するイシューを検索...", + "Blocks": "ブロック", + "Related": "関連", + "RelatedIssues": "関連するイシュー", + "EditIssue": "{title} を編集", + "EditWorkflowStatuses": "イシューステータスを編集", + "EditProject": "プロジェクトを編集", + "DeleteProject": "プロジェクトを削除", + "ArchiveProjectName": "プロジェクト {name} をアーカイブしますか?", + "ArchiveProjectConfirm": "このプロジェクトをアーカイブしますか?", + "DeleteProjectConfirm": "このプロジェクトとすべてのイシューを削除しますか?", + "ProjectHasIssues": "このプロジェクトには既存のイシューがあります。アーカイブしてもよろしいですか?", + "ManageWorkflowStatuses": "プロジェクトタイプを管理", + "AddWorkflowStatus": "イシューステータスを追加", + "EditWorkflowStatus": "イシューステータスを編集", + "DeleteWorkflowStatus": "イシューステータスを削除", + "DeleteWorkflowStatusConfirm": "\"{status}\" ステータスを削除しますか?", + "DeleteWorkflowStatusErrorDescription": "\"{status}\" ステータスには {count, plural, =1 {1 イシュー} other {# イシュー}} が割り当てられています。移動先のステータスを選択してください", + "Save": "保存", + "IncludeItemsThatMatch": "一致するアイテムを含める", + "AnyFilter": "いずれかのフィルター", + "AllFilters": "すべてのフィルター", + "NoDescription": "説明なし", + "SearchIssue": "タスクを検索...", + "StatusHistory": "状態履歴", + "NewSubIssue": "子イシューを追加...", + "AddLabel": "ラベルを追加", + "DeleteIssue": "{issueCount, plural, =1 {イシュー} other {イシュー}} を削除", + "DeleteIssueConfirm": "{issueCount, plural, =1 {イシュー} other {イシュー}}{subIssueCount, plural, =0 {?} =1 { と子イシュー?} other { と子イシュー?}} を削除しますか?", + "Milestone": "マイルストーン", + "NoMilestone": "マイルストーンなし", + "MoveToMilestone": "マイルストーンを選択", + "Milestones": "マイルストーン", + "AllMilestones": "すべて", + "PlannedMilestones": "計画済み", + "ActiveMilestones": "アクティブ", + "ClosedMilestones": "完了", + "AddToMilestone": "マイルストーンに追加", + "MilestoneNamePlaceholder": "マイルストーン名", + "NewMilestone": "新しいマイルストーン", + "CreateMilestone": "作成", + "MoveAndDeleteMilestone": "イシューを {newMilestone} に移動し、{deleteMilestone} を削除", + "MoveAndDeleteMilestoneConfirm": "マイルストーンを削除し、イシューを別のマイルストーンに移動しますか?", + "Estimation": "見積もり", + "ReportedTime": "消費時間", + "RemainingTime": "残り時間", + "TimeSpendReports": "時間消費レポート", + "TimeSpendReport": "時間", + "TimeSpendReportAdd": "時間レポートを追加", + "TimeSpendReportDate": "日付", + "TimeSpendReportValue": "消費時間", + "TimeSpendReportValueTooltip": "消費時間 (時間)", + "TimeSpendReportDescription": "説明", + "TimeSpendDays": "{value}日", + "TimeSpendHours": "{value}時間", + "TimeSpendMinutes": "{value}分", + "ChildEstimation": "子イシューの見積もり", + "ChildReportedTime": "子イシューの時間", + "CapacityValue": "うち {value}日", + "NewRelatedIssue": "新しい関連イシュー", + "RelatedIssuesNotFound": "関連イシューが見つかりません", + "AddedReference": "参照を追加", + "AddedAsBlocked": "ブロックされているとしてマーク", + "AddedAsBlocking": "ブロックしているとしてマーク", + "IssueTemplate": "テンプレート", + "IssueTemplates": "テンプレート", + "NewProcess": "新しいテンプレート", + "SaveProcess": "テンプレートを保存", + "NoIssueTemplate": "テンプレートなし", + "TemplateReplace": "新しいテンプレートを適用しますか?", + "TemplateReplaceConfirm": "すべてのフィールドが新しいテンプレートの値で上書きされます", + "Apply": "適用", + "CurrentWorkDay": "現在の営業日", + "PreviousWorkDay": "前の営業日", + "TimeReportDayTypeLabel": "時間レポートの日種別を選択", + "DefaultAssignee": "イシューのデフォルトの担当者", + "SevenHoursLength": "7時間", + "EightHoursLength": "8時間", + "HourLabel": "時間", + "MinuteLabel": "分", + "Saved": "保存済み...", + "CreatedIssue": "イシューを作成しました", + "CreatedSubIssue": "子イシューを作成しました", + "ChangeStatus": "ステータスを変更", + "ConfigLabel": "トラッカー", + "ConfigDescription": "作業項目を管理し、すべてのジョブを完了するための拡張機能。", + "NoStatusFound": "一致するステータスが見つかりません", + "CreateMissingStatus": "不足しているステータスを作成", + "UnsetParent": "親イシューが設定されなくなります", + "AllProjects": "すべてのプロジェクト", + "IssueNotificationTitle": "{issueTitle}", + "IssueNotificationBody": "{senderName} が更新しました", + "IssueNotificationChanged": "{senderName} が {property} を変更しました", + "IssueNotificationChangedProperty": "{senderName} が {property} を \"{newValue}\" に変更しました", + "IssueNotificationMessage": "{senderName}: {message}", + "PreviousAssigned": "以前に割り当てられた", + "IssueAssignedToYou": "あなたに割り当てられました", + "RelatedIssueTargetDescription": "クラスまたはスペースの関連イシュープロジェクトターゲット", + "MapRelatedIssues": "関連イシューのデフォルトプロジェクトを構成", + "DefaultIssueStatus": "デフォルトのイシューステータス", + "IssueStatus": "ステータス", + "Extensions": "拡張機能", + "UnsetParentIssue": "親イシューの設定を解除", + "ForbidCreateProjectPermission": "プロジェクト作成禁止", + "ForbidCreateProjectPermissionDescription": "ユーザーが新しいプロジェクトを作成することを禁止します", + "AllowCreatingIssues": "イシューの作成を許可", + "Day": "日", + "Gantt": "Gantt", + "Month": "月", + "Quarter": "四半期", + "Week": "週", + "GanttShowIssueCode": "Show issue code", + "GanttShowTitle": "Show title" + }, + "status": {} +} \ No newline at end of file diff --git a/plugins/tracker-assets/lang/pt.json b/plugins/tracker-assets/lang/pt.json index d83e2745a75..463e20de583 100644 --- a/plugins/tracker-assets/lang/pt.json +++ b/plugins/tracker-assets/lang/pt.json @@ -1,287 +1,289 @@ { - "string": { - "TrackerApplication": "Seguimento", - "Projects": "Os teus projetos", - "More": "Mais", - "Default": "Padrão", - "MakeDefault": "Tornar padrão", - "Delete": "Apagar", - "Open": "Abrir", - "Members": "Membros", - "Inbox": "Caixa de entrada", - "MyIssues": "Os meus problemas", - "ViewIssue": "Ver problema", - "IssueCreated": "Problema criado", - "Issues": "Problemas", - "Views": "Vistas", - "Active": "Ativo", - "AllIssues": "Todos os problemas", - "ActiveIssues": "Problemas ativos", - "BacklogIssues": "Atraso", - "Backlog": "Atraso", - "Board": "Quadro", - "Components": "Componentes", - "AllComponents": "Todos", - "BacklogComponents": "Atraso", - "ActiveComponents": "Ativo", - "ClosedComponents": "Fechado", - "NewComponent": "Novo componente", - "CreateComponent": "Criar componente", - "ComponentNamePlaceholder": "Nome do componente", - "ComponentDescriptionPlaceholder": "Descrição (opcional)", - "ComponentLead": "Líder", - "ComponentMembers": "Membros", - "StartDate": "Data de início", - "TargetDate": "Data alvo", - "Planned": "Planeado", - "InProgress": "Em progresso", - "Paused": "Pausado", - "Completed": "Concluído", - "Canceled": "Cancelado", - "CreateProject": "Criar projeto", - "NewProject": "Novo projeto", - "ProjectTitle": "Título do projeto", - "ProjectTitlePlaceholder": "Novo projeto", - "UsedInIssueIDs": "Usado em IDs de problemas", - "Identifier": "Identificador", - "Import": "Importar", - "ProjectIdentifier": "Identificador do projeto", - "IdentifierExists": "O identificador do projeto já existe", - "ProjectIdentifierPlaceholder": "PROJ", - "ChooseIcon": "Escolher ícone", - "AddIssue": "Adicionar problema", - "NewIssue": "Novo problema", - "NewIssuePlaceholder": "Novo", - "ResumeDraft": "Retomar rascunho", - "SaveIssue": "Criar problema", - "SetPriority": "Definir prioridade\u2026", - "SetStatus": "Definir estado\u2026", - "SelectIssue": "Selecionar problema", - "Priority": "Prioridade", - "NoPriority": "Sem prioridade", - "Urgent": "Urgente", - "High": "Alta", - "Medium": "Média", - "Low": "Baixa", - "Unassigned": "Não atribuído", - "Back": "Voltar", - "List": "Lista", - "NumberLabels": "{count, plural, =0 {sem etiquetas} =1 {1 etiqueta} other {# etiquetas}}", - "CategoryBacklog": "Atraso", - "CategoryUnstarted": "Não iniciado", - "CategoryStarted": "Iniciado", - "CategoryCompleted": "Concluído", - "CategoryCanceled": "Cancelado", - "Title": "Título", - "Name": "Nome", - "Description": "Descrição", - "Status": "Estado", - "Number": "Número", - "Assignee": "Atribuído a", - "AssignTo": "Atribuir a...", - "AssignedTo": "Atribuído a {value}", - "Parent": "Problema superior", - "SetParent": "Definir problema superior\u2026", - "ChangeParent": "Alterar problema superior\u2026", - "RemoveParent": "Remover problema superior", - "OpenParent": "Abrir problema superior", - "SubIssues": "Sub-problemas", - "SubIssuesList": "Sub-problemas ({subIssues})", - "OpenSubIssues": "Abrir sub-problemas", - "AddSubIssues": "Adicionar sub-problema", - "BlockedBy": "Bloqueado por", - "RelatedTo": "Relacionado com", - "Comments": "Comentários", - "Attachments": "Anexos", - "Labels": "Etiquetas", - "Component": "Componente", - "Space": "", - "SetDueDate": "Definir data de vencimento\u2026", - "ChangeDueDate": "Alterar data de vencimento", - "ModificationDate": "Atualizado {value}", - "Project": "Projeto", - "Issue": "Tarefa", - "SubIssue": "Sub-Tarefa", - "Document": "", - "DocumentIcon": "", - "DocumentColor": "", - "Rank": "Classificação", - "TypeIssuePriority": "Prioridade da Tarefa", - "IssueTitlePlaceholder": "Título da Tarefa", - "SubIssueTitlePlaceholder": "Título da Sub-Tarefa", - "IssueDescriptionPlaceholder": "Adicionar descrição...", - "SubIssueDescriptionPlaceholder": "Adicionar Descrição da Sub-Tarefa", - "AddIssueTooltip": "Adicionar Tarefa...", - "NewIssueDialogClose": "Deseja fechar este diálogo?", - "NewIssueDialogCloseNote": "Todas as alterações serão perdidas", - "RemoveComponentDialogClose": "Eliminar o componente?", - "RemoveComponentDialogCloseNote": "Tem a certeza de que deseja eliminar este componente? Esta operação não pode ser desfeita", - "Grouping": "Agrupamento", - "Ordering": "Ordenação", - "CompletedIssues": "Tarefas Concluídas", - "NoGrouping": "Sem agrupamento", - "NoAssignee": "Sem atribuição", - "LastUpdated": "Última atualização", - "DueDate": "Data de vencimento", - "IssueStartDate": "Data de início", - "GanttDependency": "Dependency", - "GanttLag": "Lag", - "Manual": "Manual", - "All": "Todos", - "PastWeek": "Semana passada", - "PastMonth": "Mês passado", - "CopyIssueUrl": "Copiar URL da questão para a área de transferência", - "CopyIssueId": "Copiar ID da questão para a área de transferência", - "CopyIssueBranch": "Copiar nome do branch Git para a área de transferência", - "CopyIssueTitle": "Copiar título da questão para a área de transferência", - "AssetLabel": "Ativo", - "AddToComponent": "Adicionar ao componente...", - "MoveToComponent": "Mover para o componente...", - "NoComponent": "Sem componente", - "ComponentLeadTitle": "Responsável pelo componente", - "ComponentMembersTitle": "Membros do componente", - "ComponentLeadSearchPlaceholder": "Definir responsável pelo componente...", - "ComponentMembersSearchPlaceholder": "Alterar membros do componente...", - "MoveToProject": "Mover para o projeto", - "Duplicate": "Duplicar", - "GotoIssues": "Ir para as questões", - "GotoActive": "Ir para as questões ativas", - "GotoBacklog": "Ir para a lista de espera", - "GotoComponents": "Ir para os componentes", - "GotoMyIssues": "Ir para as minhas questões", - "GotoTrackerApplication": "Alternar para a Aplicação de Acompanhamento", - "CreatedOne": "Criado", - "MoveIssues": "Mover questões", - "MoveIssuesDescription": "Selecione o projeto para mover as questões", - "ManageAttributes": "Gerir atributos", - "KeepOriginalAttributes": "Manter atributos originais", - "KeepOriginalAttributesTooltip": "Os estados e componentes originais da questão serão mantidos no novo projeto", - "SelectReplacement": "Os seguintes itens não estão disponíveis no novo projeto. Selecione uma substituição.", - "MissingItem": "ITEM EM FALTA", - "Replacement": "SUBSTITUIÇÃO", - "Original": "ORIGINAL", - "OriginalDescription": "Os itens desta secção serão criados no novo projeto", - "Relations": "Relações", - "RemoveRelation": "Remover relação...", - "AddBlockedBy": "Marcar como bloqueado por...", - "AddIsBlocking": "Marcar como bloqueador...", - "AddRelatedIssue": "Referenciar outra questão...", - "RelatedIssue": "Questão relacionada {id} - {title}", - "BlockedIssue": "Questão bloqueada {id} - {title}", - "BlockingIssue": "Questão bloqueadora {id} - {title}", - "BlockedBySearchPlaceholder": "Procurar questão para marcar como bloqueada por...", - "IsBlockingSearchPlaceholder": "Procurar questão para marcar como bloqueadora...", - "RelatedIssueSearchPlaceholder": "Procurar questão para referenciar...", - "Blocks": "Bloqueia", - "Related": "Relacionado", - "RelatedIssues": "Questões relacionadas", - "EditIssue": "Editar {title}", - "EditWorkflowStatuses": "Editar estados de tarefa", - "EditProject": "Editar projeto", - "DeleteProject": "Apagar projeto", - "ArchiveProjectName": "Arquivar projeto {name}?", - "ArchiveProjectConfirm": "Deseja arquivar este projeto?", - "DeleteProjectConfirm": "Deseja apagar este projeto e todas as tarefas?", - "ProjectHasIssues": "Existem tarefas neste projeto, tem a certeza de que deseja arquivar?", - "ManageWorkflowStatuses": "Gerir tipos de projeto", - "AddWorkflowStatus": "Adicionar estado de tarefa", - "EditWorkflowStatus": "Editar estado de tarefa", - "DeleteWorkflowStatus": "Apagar estado de tarefa", - "DeleteWorkflowStatusConfirm": "Deseja apagar o estado \"{status}\"?", - "DeleteWorkflowStatusErrorDescription": "O estado \"{status}\" tem {count, plural, =1 {1 tarefa} other {# tarefas}} atribuída. Por favor, selecione um estado para mover", - "Save": "Guardar", - "IncludeItemsThatMatch": "Incluir itens que coincidam", - "AnyFilter": "qualquer filtro", - "AllFilters": "todos os filtros", - "NoDescription": "Sem descrição", - "SearchIssue": "Procurar tarefa...", - "StatusHistory": "Histórico de estado", - "NewSubIssue": "Adicionar sub-tarefa...", - "AddLabel": "Adicionar etiqueta", - "DeleteIssue": "Apagar {issueCount, plural, =1 {tarefa} other {# tarefas}}", - "DeleteIssueConfirm": "Deseja apagar {issueCount, plural, =1 {tarefa} other {tarefas}}{subIssueCount, plural, =0 {?} =1 { e sub-tarefa?} other { e sub-tarefas?}}", - "Milestone": "Objetivo", - "NoMilestone": "Sem objetivo", - "MoveToMilestone": "Selecionar Objetivo", - "Milestones": "Objetivos", - "AllMilestones": "Todos", - "PlannedMilestones": "Planeados", - "ActiveMilestones": "Ativos", - "ClosedMilestones": "Concluídos", - "AddToMilestone": "Adicionar ao Objetivo", - "MilestoneNamePlaceholder": "Nome do objetivo", - "NewMilestone": "Novo Objetivo", - "CreateMilestone": "Criar", - "MoveAndDeleteMilestone": "Mover tarefas para {newMilestone} e Apagar {deleteMilestone}", - "MoveAndDeleteMilestoneConfirm": "Deseja apagar o objetivo e mover tarefas para outro objetivo?", - "Estimation": "Estimativa", - "ReportedTime": "Tempo gasto", - "RemainingTime": "Tempo restante", - "TimeSpendReports": "Relatórios de tempo gasto", - "TimeSpendReport": "Tempo", - "TimeSpendReportAdd": "Adicionar relatório de tempo", - "TimeSpendReportDate": "Data", - "TimeSpendReportValue": "Tempo gasto", - "TimeSpendReportValueTooltip": "Tempo gasto em horas", - "TimeSpendReportDescription": "Descrição", - "TimeSpendDays": "{value}d", - "TimeSpendHours": "{value}h", - "TimeSpendMinutes": "{value}m", - "ChildEstimation": "Estimativa de sub-tarefas", - "ChildReportedTime": "Tempo de sub-tarefas", - "CapacityValue": "de {value}d", - "NewRelatedIssue": "Nova tarefa relacionada", - "RelatedIssuesNotFound": "Tarefas relacionadas não encontradas", - "AddedReference": "Referência adicionada", - "AddedAsBlocked": "Marcado como bloqueado", - "AddedAsBlocking": "Marcado como bloqueador", - "IssueTemplate": "Modelo", - "IssueTemplates": "Modelos", - "NewProcess": "Novo Modelo", - "SaveProcess": "Guardar Modelo", - "NoIssueTemplate": "Sem Modelo", - "TemplateReplace": "Deseja aplicar o novo modelo?", - "TemplateReplaceConfirm": "Todos os campos serão sobrescritos pelos valores do novo modelo", - "Apply": "Aplicar", - "CurrentWorkDay": "Dia de trabalho atual", - "PreviousWorkDay": "Dia de trabalho anterior", - "TimeReportDayTypeLabel": "Selecione o tipo de dia do relatório de tempo", - "DefaultAssignee": "Responsável padrão para problemas", - "SevenHoursLength": "Sete Horas", - "EightHoursLength": "Oito Horas", - "HourLabel": "h", - "MinuteLabel": "m", - "Saved": "Guardado...", - "CreatedIssue": "Problema criado", - "CreatedSubIssue": "Sub-problema criado", - "ChangeStatus": "Alterar estado", - "ConfigLabel": "Rastreador", - "ConfigDescription": "Extensão para gerir itens de trabalho e fazer todas as tarefas necessárias.", - "NoStatusFound": "Nenhum estado correspondente encontrado", - "CreateMissingStatus": "Criar estado em falta", - "UnsetParent": "O problema pai será desassociado", - "AllProjects": "Todos os projetos", - "IssueNotificationTitle": "{issueTitle}", - "IssueNotificationBody": "Atualizado por {senderName}", - "IssueNotificationChanged": "{senderName} alterou {property}", - "IssueNotificationChangedProperty": "{senderName} alterou {property} para \"{newValue}\"", - "IssueNotificationMessage": "{senderName}: {message}", - "PreviousAssigned": "Anteriormente atribuído", - "IssueAssignedToYou": "Atribuído a si", - "RelatedIssueTargetDescription": "Projeto alvo de problemas relacionados para Classe ou Espaço", - "MapRelatedIssues": "Configurar projetos padrão de problemas relacionados", - "DefaultIssueStatus": "Estado padrão do problema", - "IssueStatus": "Estado", - "Extensions": "Extensions", - "UnsetParentIssue": "Desmarcar problema pai", - "ForbidCreateProjectPermission": "Proibir criação de projeto", - "ForbidCreateProjectPermissionDescription": "Proíbe os usuários de criar novos projetos", - "AllowCreatingIssues": "Permitir criar problemas", - "Day": "Dia", - "Gantt": "Gantt", - "Month": "Mês", - "Quarter": "Trimestre", - "Week": "Semana" - }, - "status": {} -} + "string": { + "TrackerApplication": "Seguimento", + "Projects": "Os teus projetos", + "More": "Mais", + "Default": "Padrão", + "MakeDefault": "Tornar padrão", + "Delete": "Apagar", + "Open": "Abrir", + "Members": "Membros", + "Inbox": "Caixa de entrada", + "MyIssues": "Os meus problemas", + "ViewIssue": "Ver problema", + "IssueCreated": "Problema criado", + "Issues": "Problemas", + "Views": "Vistas", + "Active": "Ativo", + "AllIssues": "Todos os problemas", + "ActiveIssues": "Problemas ativos", + "BacklogIssues": "Atraso", + "Backlog": "Atraso", + "Board": "Quadro", + "Components": "Componentes", + "AllComponents": "Todos", + "BacklogComponents": "Atraso", + "ActiveComponents": "Ativo", + "ClosedComponents": "Fechado", + "NewComponent": "Novo componente", + "CreateComponent": "Criar componente", + "ComponentNamePlaceholder": "Nome do componente", + "ComponentDescriptionPlaceholder": "Descrição (opcional)", + "ComponentLead": "Líder", + "ComponentMembers": "Membros", + "StartDate": "Data de início", + "TargetDate": "Data alvo", + "Planned": "Planeado", + "InProgress": "Em progresso", + "Paused": "Pausado", + "Completed": "Concluído", + "Canceled": "Cancelado", + "CreateProject": "Criar projeto", + "NewProject": "Novo projeto", + "ProjectTitle": "Título do projeto", + "ProjectTitlePlaceholder": "Novo projeto", + "UsedInIssueIDs": "Usado em IDs de problemas", + "Identifier": "Identificador", + "Import": "Importar", + "ProjectIdentifier": "Identificador do projeto", + "IdentifierExists": "O identificador do projeto já existe", + "ProjectIdentifierPlaceholder": "PROJ", + "ChooseIcon": "Escolher ícone", + "AddIssue": "Adicionar problema", + "NewIssue": "Novo problema", + "NewIssuePlaceholder": "Novo", + "ResumeDraft": "Retomar rascunho", + "SaveIssue": "Criar problema", + "SetPriority": "Definir prioridade…", + "SetStatus": "Definir estado…", + "SelectIssue": "Selecionar problema", + "Priority": "Prioridade", + "NoPriority": "Sem prioridade", + "Urgent": "Urgente", + "High": "Alta", + "Medium": "Média", + "Low": "Baixa", + "Unassigned": "Não atribuído", + "Back": "Voltar", + "List": "Lista", + "NumberLabels": "{count, plural, =0 {sem etiquetas} =1 {1 etiqueta} other {# etiquetas}}", + "CategoryBacklog": "Atraso", + "CategoryUnstarted": "Não iniciado", + "CategoryStarted": "Iniciado", + "CategoryCompleted": "Concluído", + "CategoryCanceled": "Cancelado", + "Title": "Título", + "Name": "Nome", + "Description": "Descrição", + "Status": "Estado", + "Number": "Número", + "Assignee": "Atribuído a", + "AssignTo": "Atribuir a...", + "AssignedTo": "Atribuído a {value}", + "Parent": "Problema superior", + "SetParent": "Definir problema superior…", + "ChangeParent": "Alterar problema superior…", + "RemoveParent": "Remover problema superior", + "OpenParent": "Abrir problema superior", + "SubIssues": "Sub-problemas", + "SubIssuesList": "Sub-problemas ({subIssues})", + "OpenSubIssues": "Abrir sub-problemas", + "AddSubIssues": "Adicionar sub-problema", + "BlockedBy": "Bloqueado por", + "RelatedTo": "Relacionado com", + "Comments": "Comentários", + "Attachments": "Anexos", + "Labels": "Etiquetas", + "Component": "Componente", + "Space": "", + "SetDueDate": "Definir data de vencimento…", + "ChangeDueDate": "Alterar data de vencimento", + "ModificationDate": "Atualizado {value}", + "Project": "Projeto", + "Issue": "Tarefa", + "SubIssue": "Sub-Tarefa", + "Document": "", + "DocumentIcon": "", + "DocumentColor": "", + "Rank": "Classificação", + "TypeIssuePriority": "Prioridade da Tarefa", + "IssueTitlePlaceholder": "Título da Tarefa", + "SubIssueTitlePlaceholder": "Título da Sub-Tarefa", + "IssueDescriptionPlaceholder": "Adicionar descrição...", + "SubIssueDescriptionPlaceholder": "Adicionar Descrição da Sub-Tarefa", + "AddIssueTooltip": "Adicionar Tarefa...", + "NewIssueDialogClose": "Deseja fechar este diálogo?", + "NewIssueDialogCloseNote": "Todas as alterações serão perdidas", + "RemoveComponentDialogClose": "Eliminar o componente?", + "RemoveComponentDialogCloseNote": "Tem a certeza de que deseja eliminar este componente? Esta operação não pode ser desfeita", + "Grouping": "Agrupamento", + "Ordering": "Ordenação", + "CompletedIssues": "Tarefas Concluídas", + "NoGrouping": "Sem agrupamento", + "NoAssignee": "Sem atribuição", + "LastUpdated": "Última atualização", + "DueDate": "Data de vencimento", + "IssueStartDate": "Data de início", + "GanttDependency": "Dependency", + "GanttLag": "Lag", + "Manual": "Manual", + "All": "Todos", + "PastWeek": "Semana passada", + "PastMonth": "Mês passado", + "CopyIssueUrl": "Copiar URL da questão para a área de transferência", + "CopyIssueId": "Copiar ID da questão para a área de transferência", + "CopyIssueBranch": "Copiar nome do branch Git para a área de transferência", + "CopyIssueTitle": "Copiar título da questão para a área de transferência", + "AssetLabel": "Ativo", + "AddToComponent": "Adicionar ao componente...", + "MoveToComponent": "Mover para o componente...", + "NoComponent": "Sem componente", + "ComponentLeadTitle": "Responsável pelo componente", + "ComponentMembersTitle": "Membros do componente", + "ComponentLeadSearchPlaceholder": "Definir responsável pelo componente...", + "ComponentMembersSearchPlaceholder": "Alterar membros do componente...", + "MoveToProject": "Mover para o projeto", + "Duplicate": "Duplicar", + "GotoIssues": "Ir para as questões", + "GotoActive": "Ir para as questões ativas", + "GotoBacklog": "Ir para a lista de espera", + "GotoComponents": "Ir para os componentes", + "GotoMyIssues": "Ir para as minhas questões", + "GotoTrackerApplication": "Alternar para a Aplicação de Acompanhamento", + "CreatedOne": "Criado", + "MoveIssues": "Mover questões", + "MoveIssuesDescription": "Selecione o projeto para mover as questões", + "ManageAttributes": "Gerir atributos", + "KeepOriginalAttributes": "Manter atributos originais", + "KeepOriginalAttributesTooltip": "Os estados e componentes originais da questão serão mantidos no novo projeto", + "SelectReplacement": "Os seguintes itens não estão disponíveis no novo projeto. Selecione uma substituição.", + "MissingItem": "ITEM EM FALTA", + "Replacement": "SUBSTITUIÇÃO", + "Original": "ORIGINAL", + "OriginalDescription": "Os itens desta secção serão criados no novo projeto", + "Relations": "Relações", + "RemoveRelation": "Remover relação...", + "AddBlockedBy": "Marcar como bloqueado por...", + "AddIsBlocking": "Marcar como bloqueador...", + "AddRelatedIssue": "Referenciar outra questão...", + "RelatedIssue": "Questão relacionada {id} - {title}", + "BlockedIssue": "Questão bloqueada {id} - {title}", + "BlockingIssue": "Questão bloqueadora {id} - {title}", + "BlockedBySearchPlaceholder": "Procurar questão para marcar como bloqueada por...", + "IsBlockingSearchPlaceholder": "Procurar questão para marcar como bloqueadora...", + "RelatedIssueSearchPlaceholder": "Procurar questão para referenciar...", + "Blocks": "Bloqueia", + "Related": "Relacionado", + "RelatedIssues": "Questões relacionadas", + "EditIssue": "Editar {title}", + "EditWorkflowStatuses": "Editar estados de tarefa", + "EditProject": "Editar projeto", + "DeleteProject": "Apagar projeto", + "ArchiveProjectName": "Arquivar projeto {name}?", + "ArchiveProjectConfirm": "Deseja arquivar este projeto?", + "DeleteProjectConfirm": "Deseja apagar este projeto e todas as tarefas?", + "ProjectHasIssues": "Existem tarefas neste projeto, tem a certeza de que deseja arquivar?", + "ManageWorkflowStatuses": "Gerir tipos de projeto", + "AddWorkflowStatus": "Adicionar estado de tarefa", + "EditWorkflowStatus": "Editar estado de tarefa", + "DeleteWorkflowStatus": "Apagar estado de tarefa", + "DeleteWorkflowStatusConfirm": "Deseja apagar o estado \"{status}\"?", + "DeleteWorkflowStatusErrorDescription": "O estado \"{status}\" tem {count, plural, =1 {1 tarefa} other {# tarefas}} atribuída. Por favor, selecione um estado para mover", + "Save": "Guardar", + "IncludeItemsThatMatch": "Incluir itens que coincidam", + "AnyFilter": "qualquer filtro", + "AllFilters": "todos os filtros", + "NoDescription": "Sem descrição", + "SearchIssue": "Procurar tarefa...", + "StatusHistory": "Histórico de estado", + "NewSubIssue": "Adicionar sub-tarefa...", + "AddLabel": "Adicionar etiqueta", + "DeleteIssue": "Apagar {issueCount, plural, =1 {tarefa} other {# tarefas}}", + "DeleteIssueConfirm": "Deseja apagar {issueCount, plural, =1 {tarefa} other {tarefas}}{subIssueCount, plural, =0 {?} =1 { e sub-tarefa?} other { e sub-tarefas?}}", + "Milestone": "Objetivo", + "NoMilestone": "Sem objetivo", + "MoveToMilestone": "Selecionar Objetivo", + "Milestones": "Objetivos", + "AllMilestones": "Todos", + "PlannedMilestones": "Planeados", + "ActiveMilestones": "Ativos", + "ClosedMilestones": "Concluídos", + "AddToMilestone": "Adicionar ao Objetivo", + "MilestoneNamePlaceholder": "Nome do objetivo", + "NewMilestone": "Novo Objetivo", + "CreateMilestone": "Criar", + "MoveAndDeleteMilestone": "Mover tarefas para {newMilestone} e Apagar {deleteMilestone}", + "MoveAndDeleteMilestoneConfirm": "Deseja apagar o objetivo e mover tarefas para outro objetivo?", + "Estimation": "Estimativa", + "ReportedTime": "Tempo gasto", + "RemainingTime": "Tempo restante", + "TimeSpendReports": "Relatórios de tempo gasto", + "TimeSpendReport": "Tempo", + "TimeSpendReportAdd": "Adicionar relatório de tempo", + "TimeSpendReportDate": "Data", + "TimeSpendReportValue": "Tempo gasto", + "TimeSpendReportValueTooltip": "Tempo gasto em horas", + "TimeSpendReportDescription": "Descrição", + "TimeSpendDays": "{value}d", + "TimeSpendHours": "{value}h", + "TimeSpendMinutes": "{value}m", + "ChildEstimation": "Estimativa de sub-tarefas", + "ChildReportedTime": "Tempo de sub-tarefas", + "CapacityValue": "de {value}d", + "NewRelatedIssue": "Nova tarefa relacionada", + "RelatedIssuesNotFound": "Tarefas relacionadas não encontradas", + "AddedReference": "Referência adicionada", + "AddedAsBlocked": "Marcado como bloqueado", + "AddedAsBlocking": "Marcado como bloqueador", + "IssueTemplate": "Modelo", + "IssueTemplates": "Modelos", + "NewProcess": "Novo Modelo", + "SaveProcess": "Guardar Modelo", + "NoIssueTemplate": "Sem Modelo", + "TemplateReplace": "Deseja aplicar o novo modelo?", + "TemplateReplaceConfirm": "Todos os campos serão sobrescritos pelos valores do novo modelo", + "Apply": "Aplicar", + "CurrentWorkDay": "Dia de trabalho atual", + "PreviousWorkDay": "Dia de trabalho anterior", + "TimeReportDayTypeLabel": "Selecione o tipo de dia do relatório de tempo", + "DefaultAssignee": "Responsável padrão para problemas", + "SevenHoursLength": "Sete Horas", + "EightHoursLength": "Oito Horas", + "HourLabel": "h", + "MinuteLabel": "m", + "Saved": "Guardado...", + "CreatedIssue": "Problema criado", + "CreatedSubIssue": "Sub-problema criado", + "ChangeStatus": "Alterar estado", + "ConfigLabel": "Rastreador", + "ConfigDescription": "Extensão para gerir itens de trabalho e fazer todas as tarefas necessárias.", + "NoStatusFound": "Nenhum estado correspondente encontrado", + "CreateMissingStatus": "Criar estado em falta", + "UnsetParent": "O problema pai será desassociado", + "AllProjects": "Todos os projetos", + "IssueNotificationTitle": "{issueTitle}", + "IssueNotificationBody": "Atualizado por {senderName}", + "IssueNotificationChanged": "{senderName} alterou {property}", + "IssueNotificationChangedProperty": "{senderName} alterou {property} para \"{newValue}\"", + "IssueNotificationMessage": "{senderName}: {message}", + "PreviousAssigned": "Anteriormente atribuído", + "IssueAssignedToYou": "Atribuído a si", + "RelatedIssueTargetDescription": "Projeto alvo de problemas relacionados para Classe ou Espaço", + "MapRelatedIssues": "Configurar projetos padrão de problemas relacionados", + "DefaultIssueStatus": "Estado padrão do problema", + "IssueStatus": "Estado", + "Extensions": "Extensions", + "UnsetParentIssue": "Desmarcar problema pai", + "ForbidCreateProjectPermission": "Proibir criação de projeto", + "ForbidCreateProjectPermissionDescription": "Proíbe os usuários de criar novos projetos", + "AllowCreatingIssues": "Permitir criar problemas", + "Day": "Dia", + "Gantt": "Gantt", + "Month": "Mês", + "Quarter": "Trimestre", + "Week": "Semana", + "GanttShowIssueCode": "Show issue code", + "GanttShowTitle": "Show title" + }, + "status": {} +} \ No newline at end of file diff --git a/plugins/tracker-assets/lang/ru.json b/plugins/tracker-assets/lang/ru.json index 142a3eec2b3..ccaa4f22c99 100644 --- a/plugins/tracker-assets/lang/ru.json +++ b/plugins/tracker-assets/lang/ru.json @@ -1,304 +1,289 @@ { - "string": { - "TrackerApplication": "Трекер", - "Projects": "Проекты", - "More": "Больше", - "Default": "По умолчанию", - "MakeDefault": "Установить по умолчанию", - "Delete": "Удалить", - "Open": "Открыть", - "Members": "Участники", - "Inbox": "Входящие", - "ViewIssue": "Открыть задачу", - "IssueCreated": "Задача создана", - "MyIssues": "Мои задачи", - "Issues": "Задачи", - "Views": "Отображения", - "Active": "Активные", - "AllIssues": "Все задачи", - "ActiveIssues": "Активные задачи", - "BacklogIssues": "Пул задач", - "Backlog": "Пул задач", - "Board": "Канбан", - "Components": "Компоненты", - "AllComponents": "Все", - "BacklogComponents": "Пул задач", - "ActiveComponents": "Активные", - "ClosedComponents": "Закрытые", - "NewComponent": "Новый компонент", - "CreateComponent": "Создать компонент", - "ComponentNamePlaceholder": "Название компонента", - "ComponentDescriptionPlaceholder": "Описание (необязательно)", - "ComponentLead": "Руководитель", - "ComponentMembers": "Участники", - "StartDate": "Дата начала", - "TargetDate": "Дата завершения", - "Planned": "Запланирован", - "InProgress": "В работе", - "Paused": "Приостановлен", - "Completed": "Завершен", - "Canceled": "Отменено", - "CreateProject": "Новый проект", - "NewProject": "Новый проект", - "ProjectTitle": "Название проекта", - "ProjectTitlePlaceholder": "Новый проект", - "UsedInIssueIDs": "Используется в идентификаторах задач", - "Identifier": "Идентификатор", - "Import": "Импорт", - "ProjectIdentifier": "Идентификатор проекта", - "IdentifierExists": "Идентификатор уже существует проекта", - "ProjectIdentifierPlaceholder": "ПКТ", - "ChooseIcon": "Выбрать иконку", - "AddIssue": "Добавить задачу", - "NewIssue": "Новая задача", - "NewIssuePlaceholder": "Новая", - "ResumeDraft": "Восстановить черновик", - "SaveIssue": "Создать задачу", - "SetPriority": "Установить приоритет\u2026", - "SetStatus": "Установить статус\u2026", - "SelectIssue": "Выбрать задачу", - "Priority": "Приоритет", - "NoPriority": "Нет приоритета", - "Urgent": "Наивысший", - "High": "Высокий", - "Medium": "Средний", - "Low": "Низкий", - "Unassigned": "Не назначен", - "Back": "Назад", - "List": "Список", - "NumberLabels": "{count, plural, =0 {нет меток} one {# метка} few {# метки} other {# меток}}", - - "CategoryBacklog": "Пул", - "CategoryUnstarted": "Не запущенные", - "CategoryStarted": "Запущенный", - "CategoryCompleted": "Завершенные", - "CategoryCanceled": "Отменённые", - - "Title": "Заголовок", - "Name": "Имя", - "Description": "Описание", - "Status": "Статус", - "Number": "Номер", - "Assignee": "Исполнитель", - "AssignTo": "Назначить...", - "AssignedTo": "Назначен на {value}", - "Parent": "Родительская задача", - "SetParent": "Задать родительскую задачу\u2026", - "ChangeParent": "Изменить родительскую задачу\u2026", - "RemoveParent": "Удалить родительскую задачу", - "OpenParent": "Открыть родительскую задачу", - "SubIssues": "Подзадачи", - "SubIssuesList": "Подзадачи ({subIssues})", - "OpenSubIssues": "Открыть подзадачи", - "AddSubIssues": "Добавить подзадачу", - "BlockedBy": "Блокируется", - "RelatedTo": "Связано", - "Comments": "Комментарии", - "Attachments": "Вложения", - "Labels": "Метки", - "Component": "Компонент", - "Space": "", - "SetDueDate": "Указать срок выполнения\u2026", - "ChangeDueDate": "Изменить срок выполнения\u2026", - "ModificationDate": "Изменено {value}", - "Project": "Проект", - "Issue": "Задача", - "SubIssue": "Подзадача", - "Document": "", - "DocumentIcon": "", - "DocumentColor": "", - "Rank": "Ранг", - "TypeIssuePriority": "Приоритет задачи", - "IssueTitlePlaceholder": "Имя задачи", - "SubIssueTitlePlaceholder": "Имя подзадачи", - "IssueDescriptionPlaceholder": "Добавить описание\u2026", - "SubIssueDescriptionPlaceholder": "Описание подзадачи", - "AddIssueTooltip": "Добавить задачу\u2026", - "NewIssueDialogClose": "Вы действительно хотите закрыть окно?", - "NewIssueDialogCloseNote": "Все внесенные изменения будут потеряны", - "RemoveComponentDialogClose": "Удалить компонент?", - "RemoveComponentDialogCloseNote": "Уверены, что хотите удалить этот компонент? Эта операция не может быть отменена.", - "Grouping": "Группировка", - "Ordering": "Сортировка", - "CompletedIssues": "Завершённые задачи", - "NoGrouping": "Нет группировки", - "NoAssignee": "Нет исполнителя", - "LastUpdated": "Последнее обновление", - "DueDate": "Срок", - "IssueStartDate": "Дата начала", - "GanttDependency": "Dependency", - "GanttLag": "Lag", - "Manual": "Пользовательский", - "All": "Все", - "PastWeek": "Предыдущая неделя", - "PastMonth": "Предыдущий месяц", - "CopyIssueUrl": "Копировать URL-адрес задачи в буфер обмена", - "CopyIssueId": "Копировать ID задачи в буфер обмена", - "CopyIssueBranch": "Копировать имя ветки Git в буфер обмена", - "CopyIssueTitle": "Копировать имя задачи в буфер обмена", - "AssetLabel": "Asset", - "AddToComponent": "Добавить в компонент\u2026", - "MoveToComponent": "Переместить в компонент\u2026", - "NoComponent": "Без компонента", - "ComponentLeadTitle": "Руководитель компонента", - "ComponentMembersTitle": "Участники компонента", - "ComponentLeadSearchPlaceholder": "Назначьте руководителя компонента\u2026", - "ComponentMembersSearchPlaceholder": "Изменить участников компонента\u2026", - "MoveToProject": "Изменить проект", - "Duplicate": "Дублировать", - - "GotoIssues": "Перейти к задачам", - "GotoActive": "Перейти к активным задачам", - "GotoBacklog": "Перейти к пулу задач", - "GotoComponents": "Перейти к компоненту", - "GotoMyIssues": "Перейти к моим задачам", - "GotoTrackerApplication": "Перейти к приложению Трекер", - - "CreatedOne": "Создана", - "MoveIssues": "Переместить задачи", - "MoveIssuesDescription": "Выберите проект, в который вы хотите переместить задачи", - "ManageAttributes": "Управление атрибутами", - "KeepOriginalAttributes": "Оставить оригинальные аттрибуты", - "KeepOriginalAttributesTooltip": "Оригинальные статусы и компоненты будут сохранены в новом проекте", - "SelectReplacement": "Следующие элементы не доступны в новом проекте. Выберите замену.", - "MissingItem": "ОТСУТСТВУЮЩИЙ ЭЛЕМЕНТ", - "Replacement": "ЗАМЕНА", - "Original": "ОРИГИНАЛ", - "OriginalDescription": "Элементы из этой секции будут созданы в новом проекте", - - "Relations": "Зависимости", - "RemoveRelation": "Удалить зависимость...", - "AddBlockedBy": "Отметить как блокируемую...", - "AddIsBlocking": "Отметить как блокирующую...", - "AddRelatedIssue": "Связать с задачей...", - "RelatedIssue": "Связанная задача {id} - {title}", - "BlockedIssue": "Блокируемая задача {id} - {title}", - "BlockingIssue": "Блокирующая {id} - {title}", - "BlockedBySearchPlaceholder": "Поиск блокирующей задачи...", - "IsBlockingSearchPlaceholder": "Поиск блокируемой задачи...", - "RelatedIssueSearchPlaceholder": "Поиск связанной задачи...", - "Blocks": "Блокирует", - "Related": "Связан", - "RelatedIssues": "Связанные задачи", - - "EditIssue": "Редактирование {title}", - "EditWorkflowStatuses": "Редактировать статусы задач", - "EditProject": "Редактировать проект", - "DeleteProject": "Удалить проект", - "ArchiveProjectName": "Архивировать проект {name}?", - "ArchiveProjectConfirm": "Вы действительно хотите заархивировать этот проект?", - "DeleteProjectConfirm": "Вы действительно хотите удалить этот проект со всем содержимым?", - "ProjectHasIssues": "Для данного проекта существуют задачи, уверены, что хотите заархивировать?", - "ManageWorkflowStatuses": "Управлять типами проекта", - "AddWorkflowStatus": "Добавить статус задачи", - "EditWorkflowStatus": "Редактировать статус задачи", - "DeleteWorkflowStatus": "Удалить статус задачи", - "DeleteWorkflowStatusConfirm": "Вы действительно хотите удалить \"{status}\" статус?", - "DeleteWorkflowStatusErrorDescription": "Статус \"{status}\" {count, plural, one {имеет # задача} few {имеет $ задачи} other {имеют # задач}}. Пожалуйста, выберите статус для перемещения.", - - "Save": "Сохранить", - "IncludeItemsThatMatch": "Включить элементы, которые соответствуют", - "AnyFilter": "любому фильтру", - "AllFilters": "всем фильтрам", - "NoDescription": "Нет описания", - "SearchIssue": "Поиск задачи...", - - "StatusHistory": "История состояний", - "NewSubIssue": "Добавить подзадачу...", - "AddLabel": "Добавить метку", - - "DeleteIssue": "Удалить {issueCount, plural, =1 {задачу} one {# задачу} few {# задачи} other {задач}}", - "DeleteIssueConfirm": "Вы действительно хотите удалить {issueCount, plural, =1 {задачу} one {# задачу} few {# задачи} other {задач}}{subIssueCount, plural, =0 {?} =1 { и подзадачу?} one { и # подзадачу?} other { и # подзадач?}}", - - "Milestone": "Этап", - "NoMilestone": "Без Этапа", - "MoveToMilestone": "Выбрать Этап", - "Milestones": "Этапы", - "AllMilestones": "Все", - "PlannedMilestones": "Запланировано", - "ActiveMilestones": "Активно", - "ClosedMilestones": "Завершено", - "AddToMilestone": "Добавить в Этап", - "MilestoneNamePlaceholder": "Название Этапа", - - "NewMilestone": "Новый Этап", - "CreateMilestone": "Создать", - - "MoveAndDeleteMilestone": "Переместить Задачи в {newMilestone} и Удалить {deleteMilestone}", - "MoveAndDeleteMilestoneConfirm": "Вы действительно хотите удалить этап и перенести задачи в другой?", - - "Estimation": "Оценка", - "ReportedTime": "Потраченное времени", - "RemainingTime": "Осталось времени", - "TimeSpendReports": "Отчеты по времени", - "TimeSpendReport": "Время", - "TimeSpendReportAdd": "Добавить затраченное время", - "TimeSpendReportDate": "Дата", - "TimeSpendReportValue": "Затраченное время", - "TimeSpendReportValueTooltip": "Затраченное время в человеко днях", - "TimeSpendReportDescription": "Описание", - "TimeSpendDays": "{value} д", - "TimeSpendHours": "{value} ч", - "TimeSpendMinutes": "{value} м", - "ChildEstimation": "Оценка подзадач", - "ChildReportedTime": "Время подзадач", - "CapacityValue": "из {value} д", - "NewRelatedIssue": "Завести связанную задачу", - "RelatedIssuesNotFound": "Связанные задачи не найдены", - - "AddedReference": "Добавлена зависимость", - "AddedAsBlocked": "Отмечено как заблокировано", - "AddedAsBlocking": "Отмечено как блокирующее", - - "IssueTemplate": "Шаблон", - "IssueTemplates": "Шаблоны", - "NewProcess": "Новый шаблон", - "SaveProcess": "Сохранить шаблон", - "NoIssueTemplate": "Шаблон не задан", - "TemplateReplace": "Вы хотите применить выбранный шаблон?", - "TemplateReplaceConfirm": "Все внесенные изменения в будут заменены значениями из нового шаблона", - "Apply": "Применить", - - "CurrentWorkDay": "Текущий Рабочий День", - "PreviousWorkDay": "Предыдущий Рабочий День", - "TimeReportDayTypeLabel": "Выберите тип дня для временного отчета", - "DefaultAssignee": "Исполнитель задачи по умолчанию", - - "SevenHoursLength": "Семь Часов", - "EightHoursLength": "Восемь Часов", - "HourLabel": "ч", - "MinuteLabel": "м", - "Saved": "Сохранено...", - "CreatedIssue": "Создал(а) задачу", - "CreatedSubIssue": "Создал(а) подзадачу", - "ChangeStatus": "Изменение статуса", - "ConfigLabel": "Трекер", - "ConfigDescription": "Расширение по управлению задачами, чтобы все было в срок.", - "NoStatusFound": "Статус не найдет", - "CreateMissingStatus": "Создать отсутствующий статус", - "UnsetParent": "Родительская задача будет убрана", - "AllProjects": "Все проекты", - "IssueNotificationTitle": "{issueTitle}", - "IssueNotificationBody": "Обновлено {senderName}", - "IssueNotificationChanged": "{senderName} изменил {property}", - "IssueNotificationChangedProperty": "{senderName} изменил {property} на \"{newValue}\"", - "IssueNotificationMessage": "{senderName}: {message}", - "PreviousAssigned": "Ранее назначенные", - "IssueAssignedToYou": "Назначено вам", - "RelatedIssueTargetDescription": "Настройка проекта по умолчанию для Класса или пространства", - "MapRelatedIssues": "Настроить проекты по умолчанию для связанных задач", - "DefaultIssueStatus": "Статус по умолчанию", - "IssueStatus": "Статус", - "Extensions": "Дополнительно", - "UnsetParentIssue": "Снять родительскую задачу", - "ForbidCreateProjectPermission": "Запретить создание проекта", - "ForbidCreateProjectPermissionDescription": "Запрещает пользователям создавать новые проекты", - "AllowCreatingIssues": "Разрешить создание задач", - "Day": "День", - "Gantt": "Gantt", - "Month": "Месяц", - "Quarter": "Квартал", - "Week": "Неделя" - }, - "status": {} -} + "string": { + "TrackerApplication": "Трекер", + "Projects": "Проекты", + "More": "Больше", + "Default": "По умолчанию", + "MakeDefault": "Установить по умолчанию", + "Delete": "Удалить", + "Open": "Открыть", + "Members": "Участники", + "Inbox": "Входящие", + "ViewIssue": "Открыть задачу", + "IssueCreated": "Задача создана", + "MyIssues": "Мои задачи", + "Issues": "Задачи", + "Views": "Отображения", + "Active": "Активные", + "AllIssues": "Все задачи", + "ActiveIssues": "Активные задачи", + "BacklogIssues": "Пул задач", + "Backlog": "Пул задач", + "Board": "Канбан", + "Components": "Компоненты", + "AllComponents": "Все", + "BacklogComponents": "Пул задач", + "ActiveComponents": "Активные", + "ClosedComponents": "Закрытые", + "NewComponent": "Новый компонент", + "CreateComponent": "Создать компонент", + "ComponentNamePlaceholder": "Название компонента", + "ComponentDescriptionPlaceholder": "Описание (необязательно)", + "ComponentLead": "Руководитель", + "ComponentMembers": "Участники", + "StartDate": "Дата начала", + "TargetDate": "Дата завершения", + "Planned": "Запланирован", + "InProgress": "В работе", + "Paused": "Приостановлен", + "Completed": "Завершен", + "Canceled": "Отменено", + "CreateProject": "Новый проект", + "NewProject": "Новый проект", + "ProjectTitle": "Название проекта", + "ProjectTitlePlaceholder": "Новый проект", + "UsedInIssueIDs": "Используется в идентификаторах задач", + "Identifier": "Идентификатор", + "Import": "Импорт", + "ProjectIdentifier": "Идентификатор проекта", + "IdentifierExists": "Идентификатор уже существует проекта", + "ProjectIdentifierPlaceholder": "ПКТ", + "ChooseIcon": "Выбрать иконку", + "AddIssue": "Добавить задачу", + "NewIssue": "Новая задача", + "NewIssuePlaceholder": "Новая", + "ResumeDraft": "Восстановить черновик", + "SaveIssue": "Создать задачу", + "SetPriority": "Установить приоритет…", + "SetStatus": "Установить статус…", + "SelectIssue": "Выбрать задачу", + "Priority": "Приоритет", + "NoPriority": "Нет приоритета", + "Urgent": "Наивысший", + "High": "Высокий", + "Medium": "Средний", + "Low": "Низкий", + "Unassigned": "Не назначен", + "Back": "Назад", + "List": "Список", + "NumberLabels": "{count, plural, =0 {нет меток} one {# метка} few {# метки} other {# меток}}", + "CategoryBacklog": "Пул", + "CategoryUnstarted": "Не запущенные", + "CategoryStarted": "Запущенный", + "CategoryCompleted": "Завершенные", + "CategoryCanceled": "Отменённые", + "Title": "Заголовок", + "Name": "Имя", + "Description": "Описание", + "Status": "Статус", + "Number": "Номер", + "Assignee": "Исполнитель", + "AssignTo": "Назначить...", + "AssignedTo": "Назначен на {value}", + "Parent": "Родительская задача", + "SetParent": "Задать родительскую задачу…", + "ChangeParent": "Изменить родительскую задачу…", + "RemoveParent": "Удалить родительскую задачу", + "OpenParent": "Открыть родительскую задачу", + "SubIssues": "Подзадачи", + "SubIssuesList": "Подзадачи ({subIssues})", + "OpenSubIssues": "Открыть подзадачи", + "AddSubIssues": "Добавить подзадачу", + "BlockedBy": "Блокируется", + "RelatedTo": "Связано", + "Comments": "Комментарии", + "Attachments": "Вложения", + "Labels": "Метки", + "Component": "Компонент", + "Space": "", + "SetDueDate": "Указать срок выполнения…", + "ChangeDueDate": "Изменить срок выполнения…", + "ModificationDate": "Изменено {value}", + "Project": "Проект", + "Issue": "Задача", + "SubIssue": "Подзадача", + "Document": "", + "DocumentIcon": "", + "DocumentColor": "", + "Rank": "Ранг", + "TypeIssuePriority": "Приоритет задачи", + "IssueTitlePlaceholder": "Имя задачи", + "SubIssueTitlePlaceholder": "Имя подзадачи", + "IssueDescriptionPlaceholder": "Добавить описание…", + "SubIssueDescriptionPlaceholder": "Описание подзадачи", + "AddIssueTooltip": "Добавить задачу…", + "NewIssueDialogClose": "Вы действительно хотите закрыть окно?", + "NewIssueDialogCloseNote": "Все внесенные изменения будут потеряны", + "RemoveComponentDialogClose": "Удалить компонент?", + "RemoveComponentDialogCloseNote": "Уверены, что хотите удалить этот компонент? Эта операция не может быть отменена.", + "Grouping": "Группировка", + "Ordering": "Сортировка", + "CompletedIssues": "Завершённые задачи", + "NoGrouping": "Нет группировки", + "NoAssignee": "Нет исполнителя", + "LastUpdated": "Последнее обновление", + "DueDate": "Срок", + "IssueStartDate": "Дата начала", + "GanttDependency": "Dependency", + "GanttLag": "Lag", + "Manual": "Пользовательский", + "All": "Все", + "PastWeek": "Предыдущая неделя", + "PastMonth": "Предыдущий месяц", + "CopyIssueUrl": "Копировать URL-адрес задачи в буфер обмена", + "CopyIssueId": "Копировать ID задачи в буфер обмена", + "CopyIssueBranch": "Копировать имя ветки Git в буфер обмена", + "CopyIssueTitle": "Копировать имя задачи в буфер обмена", + "AssetLabel": "Asset", + "AddToComponent": "Добавить в компонент…", + "MoveToComponent": "Переместить в компонент…", + "NoComponent": "Без компонента", + "ComponentLeadTitle": "Руководитель компонента", + "ComponentMembersTitle": "Участники компонента", + "ComponentLeadSearchPlaceholder": "Назначьте руководителя компонента…", + "ComponentMembersSearchPlaceholder": "Изменить участников компонента…", + "MoveToProject": "Изменить проект", + "Duplicate": "Дублировать", + "GotoIssues": "Перейти к задачам", + "GotoActive": "Перейти к активным задачам", + "GotoBacklog": "Перейти к пулу задач", + "GotoComponents": "Перейти к компоненту", + "GotoMyIssues": "Перейти к моим задачам", + "GotoTrackerApplication": "Перейти к приложению Трекер", + "CreatedOne": "Создана", + "MoveIssues": "Переместить задачи", + "MoveIssuesDescription": "Выберите проект, в который вы хотите переместить задачи", + "ManageAttributes": "Управление атрибутами", + "KeepOriginalAttributes": "Оставить оригинальные аттрибуты", + "KeepOriginalAttributesTooltip": "Оригинальные статусы и компоненты будут сохранены в новом проекте", + "SelectReplacement": "Следующие элементы не доступны в новом проекте. Выберите замену.", + "MissingItem": "ОТСУТСТВУЮЩИЙ ЭЛЕМЕНТ", + "Replacement": "ЗАМЕНА", + "Original": "ОРИГИНАЛ", + "OriginalDescription": "Элементы из этой секции будут созданы в новом проекте", + "Relations": "Зависимости", + "RemoveRelation": "Удалить зависимость...", + "AddBlockedBy": "Отметить как блокируемую...", + "AddIsBlocking": "Отметить как блокирующую...", + "AddRelatedIssue": "Связать с задачей...", + "RelatedIssue": "Связанная задача {id} - {title}", + "BlockedIssue": "Блокируемая задача {id} - {title}", + "BlockingIssue": "Блокирующая {id} - {title}", + "BlockedBySearchPlaceholder": "Поиск блокирующей задачи...", + "IsBlockingSearchPlaceholder": "Поиск блокируемой задачи...", + "RelatedIssueSearchPlaceholder": "Поиск связанной задачи...", + "Blocks": "Блокирует", + "Related": "Связан", + "RelatedIssues": "Связанные задачи", + "EditIssue": "Редактирование {title}", + "EditWorkflowStatuses": "Редактировать статусы задач", + "EditProject": "Редактировать проект", + "DeleteProject": "Удалить проект", + "ArchiveProjectName": "Архивировать проект {name}?", + "ArchiveProjectConfirm": "Вы действительно хотите заархивировать этот проект?", + "DeleteProjectConfirm": "Вы действительно хотите удалить этот проект со всем содержимым?", + "ProjectHasIssues": "Для данного проекта существуют задачи, уверены, что хотите заархивировать?", + "ManageWorkflowStatuses": "Управлять типами проекта", + "AddWorkflowStatus": "Добавить статус задачи", + "EditWorkflowStatus": "Редактировать статус задачи", + "DeleteWorkflowStatus": "Удалить статус задачи", + "DeleteWorkflowStatusConfirm": "Вы действительно хотите удалить \"{status}\" статус?", + "DeleteWorkflowStatusErrorDescription": "Статус \"{status}\" {count, plural, one {имеет # задача} few {имеет $ задачи} other {имеют # задач}}. Пожалуйста, выберите статус для перемещения.", + "Save": "Сохранить", + "IncludeItemsThatMatch": "Включить элементы, которые соответствуют", + "AnyFilter": "любому фильтру", + "AllFilters": "всем фильтрам", + "NoDescription": "Нет описания", + "SearchIssue": "Поиск задачи...", + "StatusHistory": "История состояний", + "NewSubIssue": "Добавить подзадачу...", + "AddLabel": "Добавить метку", + "DeleteIssue": "Удалить {issueCount, plural, =1 {задачу} one {# задачу} few {# задачи} other {задач}}", + "DeleteIssueConfirm": "Вы действительно хотите удалить {issueCount, plural, =1 {задачу} one {# задачу} few {# задачи} other {задач}}{subIssueCount, plural, =0 {?} =1 { и подзадачу?} one { и # подзадачу?} other { и # подзадач?}}", + "Milestone": "Этап", + "NoMilestone": "Без Этапа", + "MoveToMilestone": "Выбрать Этап", + "Milestones": "Этапы", + "AllMilestones": "Все", + "PlannedMilestones": "Запланировано", + "ActiveMilestones": "Активно", + "ClosedMilestones": "Завершено", + "AddToMilestone": "Добавить в Этап", + "MilestoneNamePlaceholder": "Название Этапа", + "NewMilestone": "Новый Этап", + "CreateMilestone": "Создать", + "MoveAndDeleteMilestone": "Переместить Задачи в {newMilestone} и Удалить {deleteMilestone}", + "MoveAndDeleteMilestoneConfirm": "Вы действительно хотите удалить этап и перенести задачи в другой?", + "Estimation": "Оценка", + "ReportedTime": "Потраченное времени", + "RemainingTime": "Осталось времени", + "TimeSpendReports": "Отчеты по времени", + "TimeSpendReport": "Время", + "TimeSpendReportAdd": "Добавить затраченное время", + "TimeSpendReportDate": "Дата", + "TimeSpendReportValue": "Затраченное время", + "TimeSpendReportValueTooltip": "Затраченное время в человеко днях", + "TimeSpendReportDescription": "Описание", + "TimeSpendDays": "{value} д", + "TimeSpendHours": "{value} ч", + "TimeSpendMinutes": "{value} м", + "ChildEstimation": "Оценка подзадач", + "ChildReportedTime": "Время подзадач", + "CapacityValue": "из {value} д", + "NewRelatedIssue": "Завести связанную задачу", + "RelatedIssuesNotFound": "Связанные задачи не найдены", + "AddedReference": "Добавлена зависимость", + "AddedAsBlocked": "Отмечено как заблокировано", + "AddedAsBlocking": "Отмечено как блокирующее", + "IssueTemplate": "Шаблон", + "IssueTemplates": "Шаблоны", + "NewProcess": "Новый шаблон", + "SaveProcess": "Сохранить шаблон", + "NoIssueTemplate": "Шаблон не задан", + "TemplateReplace": "Вы хотите применить выбранный шаблон?", + "TemplateReplaceConfirm": "Все внесенные изменения в будут заменены значениями из нового шаблона", + "Apply": "Применить", + "CurrentWorkDay": "Текущий Рабочий День", + "PreviousWorkDay": "Предыдущий Рабочий День", + "TimeReportDayTypeLabel": "Выберите тип дня для временного отчета", + "DefaultAssignee": "Исполнитель задачи по умолчанию", + "SevenHoursLength": "Семь Часов", + "EightHoursLength": "Восемь Часов", + "HourLabel": "ч", + "MinuteLabel": "м", + "Saved": "Сохранено...", + "CreatedIssue": "Создал(а) задачу", + "CreatedSubIssue": "Создал(а) подзадачу", + "ChangeStatus": "Изменение статуса", + "ConfigLabel": "Трекер", + "ConfigDescription": "Расширение по управлению задачами, чтобы все было в срок.", + "NoStatusFound": "Статус не найдет", + "CreateMissingStatus": "Создать отсутствующий статус", + "UnsetParent": "Родительская задача будет убрана", + "AllProjects": "Все проекты", + "IssueNotificationTitle": "{issueTitle}", + "IssueNotificationBody": "Обновлено {senderName}", + "IssueNotificationChanged": "{senderName} изменил {property}", + "IssueNotificationChangedProperty": "{senderName} изменил {property} на \"{newValue}\"", + "IssueNotificationMessage": "{senderName}: {message}", + "PreviousAssigned": "Ранее назначенные", + "IssueAssignedToYou": "Назначено вам", + "RelatedIssueTargetDescription": "Настройка проекта по умолчанию для Класса или пространства", + "MapRelatedIssues": "Настроить проекты по умолчанию для связанных задач", + "DefaultIssueStatus": "Статус по умолчанию", + "IssueStatus": "Статус", + "Extensions": "Дополнительно", + "UnsetParentIssue": "Снять родительскую задачу", + "ForbidCreateProjectPermission": "Запретить создание проекта", + "ForbidCreateProjectPermissionDescription": "Запрещает пользователям создавать новые проекты", + "AllowCreatingIssues": "Разрешить создание задач", + "Day": "День", + "Gantt": "Gantt", + "Month": "Месяц", + "Quarter": "Квартал", + "Week": "Неделя", + "GanttShowIssueCode": "Show issue code", + "GanttShowTitle": "Show title" + }, + "status": {} +} \ No newline at end of file diff --git a/plugins/tracker-assets/lang/zh.json b/plugins/tracker-assets/lang/zh.json index 7bf3bc34d7c..80679f10f1e 100644 --- a/plugins/tracker-assets/lang/zh.json +++ b/plugins/tracker-assets/lang/zh.json @@ -1,304 +1,289 @@ { - "string": { - "TrackerApplication": "追踪器", - "Projects": "您的项目", - "More": "更多", - "Default": "默认", - "MakeDefault": "设为默认", - "Delete": "删除", - "Open": "打开", - "Members": "成员", - "Inbox": "收件箱", - "MyIssues": "我的问题", - "ViewIssue": "查看问题", - "IssueCreated": "问题已创建", - "Issues": "问题", - "Views": "视图", - "Active": "活跃", - "AllIssues": "所有问题", - "ActiveIssues": "活跃问题", - "BacklogIssues": "积压", - "Backlog": "积压", - "Board": "看板", - "Components": "组件", - "AllComponents": "全部", - "BacklogComponents": "积压", - "ActiveComponents": "活跃", - "ClosedComponents": "已关闭", - "NewComponent": "新组件", - "CreateComponent": "创建组件", - "ComponentNamePlaceholder": "组件名称", - "ComponentDescriptionPlaceholder": "描述(可选)", - "ComponentLead": "负责人", - "ComponentMembers": "成员", - "StartDate": "开始日期", - "TargetDate": "目标日期", - "Planned": "已计划", - "InProgress": "进行中", - "Paused": "暂停", - "Completed": "已完成", - "Canceled": "已取消", - "CreateProject": "创建项目", - "NewProject": "新项目", - "ProjectTitle": "项目标题", - "ProjectTitlePlaceholder": "新项目", - "UsedInIssueIDs": "引用问题ID", - "Identifier": "标识符", - "Import": "导入", - "ProjectIdentifier": "项目标识符", - "IdentifierExists": "项目标识符已存在", - "ProjectIdentifierPlaceholder": "PRJCT", - "ChooseIcon": "选择图标", - "AddIssue": "添加问题", - "NewIssue": "新问题", - "NewIssuePlaceholder": "新问题", - "ResumeDraft": "恢复草稿", - "SaveIssue": "创建问题", - "SetPriority": "设置优先级…", - "SetStatus": "设置状态…", - "SelectIssue": "选择问题", - "Priority": "优先级", - "NoPriority": "无优先级", - "Urgent": "紧急", - "High": "高", - "Medium": "中", - "Low": "低", - "Unassigned": "未分配", - "Back": "返回", - "List": "列表", - "NumberLabels": "{count, plural, =0 {无标签} =1 {1 个标签} other {# 个标签}}", - - "CategoryBacklog": "积压", - "CategoryUnstarted": "未开始", - "CategoryStarted": "已开始", - "CategoryCompleted": "已完成", - "CategoryCanceled": "已取消", - - "Title": "标题", - "Name": "名称", - "Description": "描述", - "Status": "状态", - "Number": "编号", - "Assignee": "受理人", - "AssignTo": "分配给…", - "AssignedTo": "分配给 {value}", - "Parent": "父问题", - "SetParent": "设置父问题…", - "ChangeParent": "更改父问题…", - "RemoveParent": "移除父问题", - "OpenParent": "打开父问题", - "SubIssues": "子问题", - "SubIssuesList": "子问题 ({subIssues})", - "OpenSubIssues": "打开子问题", - "AddSubIssues": "添加子问题", - "BlockedBy": "被阻塞", - "RelatedTo": "相关", - "Comments": "评论", - "Attachments": "附件", - "Labels": "标签", - "Component": "组件", - "Space": "", - "SetDueDate": "设置截止日期…", - "ChangeDueDate": "更改截止日期…", - "ModificationDate": "更新于 {value}", - "Project": "项目", - "Issue": "问题", - "SubIssue": "子问题", - "Document": "", - "DocumentIcon": "", - "DocumentColor": "", - "Rank": "排名", - "TypeIssuePriority": "问题优先级", - "IssueTitlePlaceholder": "问题标题", - "SubIssueTitlePlaceholder": "子问题标题", - "IssueDescriptionPlaceholder": "添加描述…", - "SubIssueDescriptionPlaceholder": "添加子问题描述", - "AddIssueTooltip": "添加问题…", - "NewIssueDialogClose": "您想要关闭此对话框吗?", - "NewIssueDialogCloseNote": "所有更改将会丢失", - "RemoveComponentDialogClose": "删除组件?", - "RemoveComponentDialogCloseNote": "您确定要删除此组件吗?此操作无法撤销", - "Grouping": "分组", - "Ordering": "排序", - "CompletedIssues": "已完成问题", - "NoGrouping": "无分组", - "NoAssignee": "无受理人", - "LastUpdated": "最后更新", - "DueDate": "截止日期", - "IssueStartDate": "开始日期", - "GanttDependency": "Dependency", - "GanttLag": "Lag", - "Manual": "手动", - "All": "全部", - "PastWeek": "过去一周", - "PastMonth": "过去一个月", - "CopyIssueUrl": "复制问题 URL 到剪贴板", - "CopyIssueId": "复制问题 ID 到剪贴板", - "CopyIssueBranch": "复制 Git 分支名称到剪贴板", - "CopyIssueTitle": "复制问题标题到剪贴板", - "AssetLabel": "资产", - "AddToComponent": "添加到组件…", - "MoveToComponent": "移动到组件…", - "NoComponent": "无组件", - "ComponentLeadTitle": "组件负责人", - "ComponentMembersTitle": "组件成员", - "ComponentLeadSearchPlaceholder": "设置组件负责人…", - "ComponentMembersSearchPlaceholder": "更改组件成员…", - "MoveToProject": "移动到项目", - "Duplicate": "复制", - - "GotoIssues": "前往问题", - "GotoActive": "前往活跃问题", - "GotoBacklog": "前往积压", - "GotoComponents": "前往组件", - "GotoMyIssues": "前往我的问题", - "GotoTrackerApplication": "切换到追踪器应用", - - "CreatedOne": "已创建", - "MoveIssues": "移动问题", - "MoveIssuesDescription": "选择要移动问题的项目", - "ManageAttributes": "管理属性", - "KeepOriginalAttributes": "保留原始属性", - "KeepOriginalAttributesTooltip": "原始问题状态和组件将在新项目中保留", - "SelectReplacement": "以下项目在新项目中不可用。请选择替换项。", - "MissingItem": "缺失项目", - "Replacement": "替换项", - "Original": "原始", - "OriginalDescription": "此部分的项目将在新项目中创建", - - "Relations": "关系", - "RemoveRelation": "移除关系…", - "AddBlockedBy": "标记为被阻塞…", - "AddIsBlocking": "标记为阻塞…", - "AddRelatedIssue": "引用其他问题…", - "RelatedIssue": "相关问题 {id} - {title}", - "BlockedIssue": "被阻塞的问题 {id} - {title}", - "BlockingIssue": "阻塞的问题 {id} - {title}", - "BlockedBySearchPlaceholder": "搜索要标记为被阻塞的问题…", - "IsBlockingSearchPlaceholder": "搜索要标记为阻塞的问题…", - "RelatedIssueSearchPlaceholder": "搜索要引用的问题…", - "Blocks": "阻塞", - "Related": "相关", - "RelatedIssues": "相关问题", - - "EditIssue": "编辑 {title}", - "EditWorkflowStatuses": "编辑问题状态", - "EditProject": "编辑项目", - "DeleteProject": "删除项目", - "ArchiveProjectName": "归档项目 {name}?", - "ArchiveProjectConfirm": "您想要归档此项目吗?", - "DeleteProjectConfirm": "您想要删除此项目及所有问题吗?", - "ProjectHasIssues": "此项目中存在问题,您确定要归档吗?", - "ManageWorkflowStatuses": "管理项目类型", - "AddWorkflowStatus": "添加问题状态", - "EditWorkflowStatus": "编辑问题状态", - "DeleteWorkflowStatus": "删除问题状态", - "DeleteWorkflowStatusConfirm": "您想要删除“{status}”状态吗?", - "DeleteWorkflowStatusErrorDescription": "“{status}”状态有 {count, plural, =1 {1 个问题} other {# 个问题}} 分配。请选择一个状态进行移动", - - "Save": "保存", - "IncludeItemsThatMatch": "包括符合条件的项目", - "AnyFilter": "任何过滤器", - "AllFilters": "所有过滤器", - "NoDescription": "无描述", - "SearchIssue": "搜索任务…", - - "StatusHistory": "状态历史", - "NewSubIssue": "添加子问题…", - "AddLabel": "添加标签", - - "DeleteIssue": "删除 {issueCount, plural, =1 {问题} other {# 个问题}}", - "DeleteIssueConfirm": "您想要删除 {issueCount, plural, =1 {问题} other {问题}}{subIssueCount, plural, =0 {?} =1 { 和子问题?} other { 和子问题?}}", - - "Milestone": "里程碑", - "NoMilestone": "无里程碑", - "MoveToMilestone": "选择里程碑", - "Milestones": "里程碑", - "AllMilestones": "全部", - "PlannedMilestones": "已计划", - "ActiveMilestones": "活跃", - "ClosedMilestones": "已完成", - "AddToMilestone": "添加到里程碑", - "MilestoneNamePlaceholder": "里程碑名称", - - "NewMilestone": "新里程碑", - "CreateMilestone": "创建", - - "MoveAndDeleteMilestone": "将问题移动到 {newMilestone} 并删除 {deleteMilestone}", - "MoveAndDeleteMilestoneConfirm": "您想要删除里程碑并将问题移动到其他里程碑吗?", - - "Estimation": "估算", - "ReportedTime": "花费时间", - "RemainingTime": "剩余时间", - "TimeSpendReports": "花费时间报告", - "TimeSpendReport": "时间", - "TimeSpendReportAdd": "添加时间报告", - "TimeSpendReportDate": "日期", - "TimeSpendReportValue": "花费时间", - "TimeSpendReportValueTooltip": "花费时间(小时)", - "TimeSpendReportDescription": "描述", - "TimeSpendDays": "{value} 天", - "TimeSpendHours": "{value} 小时", - "TimeSpendMinutes": "{value} 分钟", - "ChildEstimation": "子问题估算", - "ChildReportedTime": "子问题时间", - "CapacityValue": "共 {value} 天", - "NewRelatedIssue": "新相关问题", - "RelatedIssuesNotFound": "未找到相关问题", - - "AddedReference": "添加了引用", - "AddedAsBlocked": "标记为被阻塞", - "AddedAsBlocking": "标记为阻塞", - - "IssueTemplate": "模板", - "IssueTemplates": "模板", - "NewProcess": "新模板", - "SaveProcess": "保存模板", - "NoIssueTemplate": "无模板", - "TemplateReplace": "您想要应用新模板吗?", - "TemplateReplaceConfirm": "所有字段将被新模板值覆盖", - "Apply": "应用", - - "CurrentWorkDay": "当前工作日", - "PreviousWorkDay": "前一个工作日", - "TimeReportDayTypeLabel": "选择时间报告日类型", - "DefaultAssignee": "默认问题受理人", - - "SevenHoursLength": "七小时", - "EightHoursLength": "八小时", - "HourLabel": "小时", - "MinuteLabel": "分", - "Saved": "已保存...", - "CreatedIssue": "已创建问题", - "CreatedSubIssue": "已创建子问题", - "ChangeStatus": "更改状态", - "ConfigLabel": "追踪器", - "ConfigDescription": "扩展用于管理工作项并完成所有工作。", - "NoStatusFound": "未找到匹配的状态", - "CreateMissingStatus": "创建缺失的状态", - "UnsetParent": "父问题将被取消设置", - "AllProjects": "所有项目", - "IssueNotificationTitle": "{issueTitle}", - "IssueNotificationBody": "由 {senderName} 更新", - "IssueNotificationChanged": "{senderName} 更改了 {property}", - "IssueNotificationChangedProperty": "{senderName} 将 {property} 更改为 \"{newValue}\"", - "IssueNotificationMessage": "{senderName}:{message}", - "PreviousAssigned": "以前分配的", - "IssueAssignedToYou": "分配给您", - "RelatedIssueTargetDescription": "相关问题项目目标用于类别或空间", - "MapRelatedIssues": "配置相关问题默认项目", - "DefaultIssueStatus": "默认问题状态", - "IssueStatus": "状态", - "Extensions": "扩展", - "UnsetParentIssue": "取消父问题", - "ForbidCreateProjectPermission": "禁止创建项目", - "ForbidCreateProjectPermissionDescription": "禁止用户创建新项目", - "AllowCreatingIssues": "允许创建问题", - "Day": "日", - "Gantt": "Gantt", - "Month": "月", - "Quarter": "季度", - "Week": "周" - }, - "status": {} -} + "string": { + "TrackerApplication": "追踪器", + "Projects": "您的项目", + "More": "更多", + "Default": "默认", + "MakeDefault": "设为默认", + "Delete": "删除", + "Open": "打开", + "Members": "成员", + "Inbox": "收件箱", + "MyIssues": "我的问题", + "ViewIssue": "查看问题", + "IssueCreated": "问题已创建", + "Issues": "问题", + "Views": "视图", + "Active": "活跃", + "AllIssues": "所有问题", + "ActiveIssues": "活跃问题", + "BacklogIssues": "积压", + "Backlog": "积压", + "Board": "看板", + "Components": "组件", + "AllComponents": "全部", + "BacklogComponents": "积压", + "ActiveComponents": "活跃", + "ClosedComponents": "已关闭", + "NewComponent": "新组件", + "CreateComponent": "创建组件", + "ComponentNamePlaceholder": "组件名称", + "ComponentDescriptionPlaceholder": "描述(可选)", + "ComponentLead": "负责人", + "ComponentMembers": "成员", + "StartDate": "开始日期", + "TargetDate": "目标日期", + "Planned": "已计划", + "InProgress": "进行中", + "Paused": "暂停", + "Completed": "已完成", + "Canceled": "已取消", + "CreateProject": "创建项目", + "NewProject": "新项目", + "ProjectTitle": "项目标题", + "ProjectTitlePlaceholder": "新项目", + "UsedInIssueIDs": "引用问题ID", + "Identifier": "标识符", + "Import": "导入", + "ProjectIdentifier": "项目标识符", + "IdentifierExists": "项目标识符已存在", + "ProjectIdentifierPlaceholder": "PRJCT", + "ChooseIcon": "选择图标", + "AddIssue": "添加问题", + "NewIssue": "新问题", + "NewIssuePlaceholder": "新问题", + "ResumeDraft": "恢复草稿", + "SaveIssue": "创建问题", + "SetPriority": "设置优先级…", + "SetStatus": "设置状态…", + "SelectIssue": "选择问题", + "Priority": "优先级", + "NoPriority": "无优先级", + "Urgent": "紧急", + "High": "高", + "Medium": "中", + "Low": "低", + "Unassigned": "未分配", + "Back": "返回", + "List": "列表", + "NumberLabels": "{count, plural, =0 {无标签} =1 {1 个标签} other {# 个标签}}", + "CategoryBacklog": "积压", + "CategoryUnstarted": "未开始", + "CategoryStarted": "已开始", + "CategoryCompleted": "已完成", + "CategoryCanceled": "已取消", + "Title": "标题", + "Name": "名称", + "Description": "描述", + "Status": "状态", + "Number": "编号", + "Assignee": "受理人", + "AssignTo": "分配给…", + "AssignedTo": "分配给 {value}", + "Parent": "父问题", + "SetParent": "设置父问题…", + "ChangeParent": "更改父问题…", + "RemoveParent": "移除父问题", + "OpenParent": "打开父问题", + "SubIssues": "子问题", + "SubIssuesList": "子问题 ({subIssues})", + "OpenSubIssues": "打开子问题", + "AddSubIssues": "添加子问题", + "BlockedBy": "被阻塞", + "RelatedTo": "相关", + "Comments": "评论", + "Attachments": "附件", + "Labels": "标签", + "Component": "组件", + "Space": "", + "SetDueDate": "设置截止日期…", + "ChangeDueDate": "更改截止日期…", + "ModificationDate": "更新于 {value}", + "Project": "项目", + "Issue": "问题", + "SubIssue": "子问题", + "Document": "", + "DocumentIcon": "", + "DocumentColor": "", + "Rank": "排名", + "TypeIssuePriority": "问题优先级", + "IssueTitlePlaceholder": "问题标题", + "SubIssueTitlePlaceholder": "子问题标题", + "IssueDescriptionPlaceholder": "添加描述…", + "SubIssueDescriptionPlaceholder": "添加子问题描述", + "AddIssueTooltip": "添加问题…", + "NewIssueDialogClose": "您想要关闭此对话框吗?", + "NewIssueDialogCloseNote": "所有更改将会丢失", + "RemoveComponentDialogClose": "删除组件?", + "RemoveComponentDialogCloseNote": "您确定要删除此组件吗?此操作无法撤销", + "Grouping": "分组", + "Ordering": "排序", + "CompletedIssues": "已完成问题", + "NoGrouping": "无分组", + "NoAssignee": "无受理人", + "LastUpdated": "最后更新", + "DueDate": "截止日期", + "IssueStartDate": "开始日期", + "GanttDependency": "Dependency", + "GanttLag": "Lag", + "Manual": "手动", + "All": "全部", + "PastWeek": "过去一周", + "PastMonth": "过去一个月", + "CopyIssueUrl": "复制问题 URL 到剪贴板", + "CopyIssueId": "复制问题 ID 到剪贴板", + "CopyIssueBranch": "复制 Git 分支名称到剪贴板", + "CopyIssueTitle": "复制问题标题到剪贴板", + "AssetLabel": "资产", + "AddToComponent": "添加到组件…", + "MoveToComponent": "移动到组件…", + "NoComponent": "无组件", + "ComponentLeadTitle": "组件负责人", + "ComponentMembersTitle": "组件成员", + "ComponentLeadSearchPlaceholder": "设置组件负责人…", + "ComponentMembersSearchPlaceholder": "更改组件成员…", + "MoveToProject": "移动到项目", + "Duplicate": "复制", + "GotoIssues": "前往问题", + "GotoActive": "前往活跃问题", + "GotoBacklog": "前往积压", + "GotoComponents": "前往组件", + "GotoMyIssues": "前往我的问题", + "GotoTrackerApplication": "切换到追踪器应用", + "CreatedOne": "已创建", + "MoveIssues": "移动问题", + "MoveIssuesDescription": "选择要移动问题的项目", + "ManageAttributes": "管理属性", + "KeepOriginalAttributes": "保留原始属性", + "KeepOriginalAttributesTooltip": "原始问题状态和组件将在新项目中保留", + "SelectReplacement": "以下项目在新项目中不可用。请选择替换项。", + "MissingItem": "缺失项目", + "Replacement": "替换项", + "Original": "原始", + "OriginalDescription": "此部分的项目将在新项目中创建", + "Relations": "关系", + "RemoveRelation": "移除关系…", + "AddBlockedBy": "标记为被阻塞…", + "AddIsBlocking": "标记为阻塞…", + "AddRelatedIssue": "引用其他问题…", + "RelatedIssue": "相关问题 {id} - {title}", + "BlockedIssue": "被阻塞的问题 {id} - {title}", + "BlockingIssue": "阻塞的问题 {id} - {title}", + "BlockedBySearchPlaceholder": "搜索要标记为被阻塞的问题…", + "IsBlockingSearchPlaceholder": "搜索要标记为阻塞的问题…", + "RelatedIssueSearchPlaceholder": "搜索要引用的问题…", + "Blocks": "阻塞", + "Related": "相关", + "RelatedIssues": "相关问题", + "EditIssue": "编辑 {title}", + "EditWorkflowStatuses": "编辑问题状态", + "EditProject": "编辑项目", + "DeleteProject": "删除项目", + "ArchiveProjectName": "归档项目 {name}?", + "ArchiveProjectConfirm": "您想要归档此项目吗?", + "DeleteProjectConfirm": "您想要删除此项目及所有问题吗?", + "ProjectHasIssues": "此项目中存在问题,您确定要归档吗?", + "ManageWorkflowStatuses": "管理项目类型", + "AddWorkflowStatus": "添加问题状态", + "EditWorkflowStatus": "编辑问题状态", + "DeleteWorkflowStatus": "删除问题状态", + "DeleteWorkflowStatusConfirm": "您想要删除“{status}”状态吗?", + "DeleteWorkflowStatusErrorDescription": "“{status}”状态有 {count, plural, =1 {1 个问题} other {# 个问题}} 分配。请选择一个状态进行移动", + "Save": "保存", + "IncludeItemsThatMatch": "包括符合条件的项目", + "AnyFilter": "任何过滤器", + "AllFilters": "所有过滤器", + "NoDescription": "无描述", + "SearchIssue": "搜索任务…", + "StatusHistory": "状态历史", + "NewSubIssue": "添加子问题…", + "AddLabel": "添加标签", + "DeleteIssue": "删除 {issueCount, plural, =1 {问题} other {# 个问题}}", + "DeleteIssueConfirm": "您想要删除 {issueCount, plural, =1 {问题} other {问题}}{subIssueCount, plural, =0 {?} =1 { 和子问题?} other { 和子问题?}}", + "Milestone": "里程碑", + "NoMilestone": "无里程碑", + "MoveToMilestone": "选择里程碑", + "Milestones": "里程碑", + "AllMilestones": "全部", + "PlannedMilestones": "已计划", + "ActiveMilestones": "活跃", + "ClosedMilestones": "已完成", + "AddToMilestone": "添加到里程碑", + "MilestoneNamePlaceholder": "里程碑名称", + "NewMilestone": "新里程碑", + "CreateMilestone": "创建", + "MoveAndDeleteMilestone": "将问题移动到 {newMilestone} 并删除 {deleteMilestone}", + "MoveAndDeleteMilestoneConfirm": "您想要删除里程碑并将问题移动到其他里程碑吗?", + "Estimation": "估算", + "ReportedTime": "花费时间", + "RemainingTime": "剩余时间", + "TimeSpendReports": "花费时间报告", + "TimeSpendReport": "时间", + "TimeSpendReportAdd": "添加时间报告", + "TimeSpendReportDate": "日期", + "TimeSpendReportValue": "花费时间", + "TimeSpendReportValueTooltip": "花费时间(小时)", + "TimeSpendReportDescription": "描述", + "TimeSpendDays": "{value} 天", + "TimeSpendHours": "{value} 小时", + "TimeSpendMinutes": "{value} 分钟", + "ChildEstimation": "子问题估算", + "ChildReportedTime": "子问题时间", + "CapacityValue": "共 {value} 天", + "NewRelatedIssue": "新相关问题", + "RelatedIssuesNotFound": "未找到相关问题", + "AddedReference": "添加了引用", + "AddedAsBlocked": "标记为被阻塞", + "AddedAsBlocking": "标记为阻塞", + "IssueTemplate": "模板", + "IssueTemplates": "模板", + "NewProcess": "新模板", + "SaveProcess": "保存模板", + "NoIssueTemplate": "无模板", + "TemplateReplace": "您想要应用新模板吗?", + "TemplateReplaceConfirm": "所有字段将被新模板值覆盖", + "Apply": "应用", + "CurrentWorkDay": "当前工作日", + "PreviousWorkDay": "前一个工作日", + "TimeReportDayTypeLabel": "选择时间报告日类型", + "DefaultAssignee": "默认问题受理人", + "SevenHoursLength": "七小时", + "EightHoursLength": "八小时", + "HourLabel": "小时", + "MinuteLabel": "分", + "Saved": "已保存...", + "CreatedIssue": "已创建问题", + "CreatedSubIssue": "已创建子问题", + "ChangeStatus": "更改状态", + "ConfigLabel": "追踪器", + "ConfigDescription": "扩展用于管理工作项并完成所有工作。", + "NoStatusFound": "未找到匹配的状态", + "CreateMissingStatus": "创建缺失的状态", + "UnsetParent": "父问题将被取消设置", + "AllProjects": "所有项目", + "IssueNotificationTitle": "{issueTitle}", + "IssueNotificationBody": "由 {senderName} 更新", + "IssueNotificationChanged": "{senderName} 更改了 {property}", + "IssueNotificationChangedProperty": "{senderName} 将 {property} 更改为 \"{newValue}\"", + "IssueNotificationMessage": "{senderName}:{message}", + "PreviousAssigned": "以前分配的", + "IssueAssignedToYou": "分配给您", + "RelatedIssueTargetDescription": "相关问题项目目标用于类别或空间", + "MapRelatedIssues": "配置相关问题默认项目", + "DefaultIssueStatus": "默认问题状态", + "IssueStatus": "状态", + "Extensions": "扩展", + "UnsetParentIssue": "取消父问题", + "ForbidCreateProjectPermission": "禁止创建项目", + "ForbidCreateProjectPermissionDescription": "禁止用户创建新项目", + "AllowCreatingIssues": "允许创建问题", + "Day": "日", + "Gantt": "Gantt", + "Month": "月", + "Quarter": "季度", + "Week": "周", + "GanttShowIssueCode": "Show issue code", + "GanttShowTitle": "Show title" + }, + "status": {} +} \ No newline at end of file diff --git a/plugins/tracker-resources/src/components/gantt/GanttView.svelte b/plugins/tracker-resources/src/components/gantt/GanttView.svelte index f48f2b05343..a8eaa00985b 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttView.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttView.svelte @@ -64,9 +64,12 @@ const ZOOM_LEVELS: readonly ZoomLevel[] = ['day', 'week', 'month', 'quarter'] let userSidebarWidth: number = DEFAULT_SIDEBAR_WIDTH - let showIssueCode: boolean = true - let showTitle: boolean = true - let showSettings: boolean = false + + // Sidebar column visibility is wired to two ToggleViewOptions registered + // in models/tracker/src/viewlets.ts (Customize-View dropdown). Issue-code + // defaults OFF — the code is still surfaced in the hover tooltip. + $: showIssueCode = (viewOptions as Record)?.ganttShowIssueCode === true + $: showTitle = ((viewOptions as Record)?.ganttShowTitle ?? true) !== false function setZoom (z: ZoomLevel): void { zoom = z @@ -215,6 +218,10 @@ } } + function issueCode (i: Issue): string { + return (i as unknown as { identifier?: string }).identifier ?? 'Issue' + } + function onIssueOpen (e: CustomEvent<{ issue: { _id: string, _class: string } }>): void { showPanel( tracker.component.EditIssue, @@ -367,26 +374,7 @@ >{z[0].toUpperCase() + z.slice(1)} {/each}
-
- - {#if showSettings} -
- - -
- {/if} -
+
@@ -470,7 +458,8 @@ {/if}
Target: {new Date(ms.targetDate).toISOString().slice(0, 10)}
{:else if issue !== null} -
Issue
+ {@const code = issueCode(issue)} +
{code}
{issue.title}
{#if issue.startDate !== null}
Start: {new Date(issue.startDate).toISOString().slice(0, 10)}
diff --git a/plugins/tracker-resources/src/plugin.ts b/plugins/tracker-resources/src/plugin.ts index fc1f85177ad..28533dfd662 100644 --- a/plugins/tracker-resources/src/plugin.ts +++ b/plugins/tracker-resources/src/plugin.ts @@ -315,7 +315,9 @@ export default mergeIds(trackerId, tracker, { Gantt: '' as IntlString, Month: '' as IntlString, Quarter: '' as IntlString, - Week: '' as IntlString + Week: '' as IntlString, + GanttShowIssueCode: '' as IntlString, + GanttShowTitle: '' as IntlString }, component: { NopeComponent: '' as AnyComponent, From 8cbe5a0aa746c8bfb6c05be02d61b94bac2a69ee Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:15 +0000 Subject: [PATCH 19/62] fix(tracker-resources): clip GanttSidebar inside its host MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: .gantt-sidebar rendered at its natural height (≈ rows × 36px), and .sidebar-host had overflow:visible, so for many issues the sidebar visually overflowed gantt-body which in turn made gantt-body's scrollHeight balloon to the sidebar's natural height. The result was that scrolling over the sidebar appeared to scroll the page area instead of just the canvas. Fix: - .sidebar-host now overflow:hidden + height:100% + flex-column - .gantt-sidebar height:100% + flex:1 1 auto so it fills the host rather than stretching past it Verified: gantt-body scrollHeight == clientHeight, only .canvas-scroller has scrollable content. Wheel-forward over the sidebar moves canvas-scroller and the sidebar transform together. Signed-off-by: Michael Uray --- .../src/components/gantt/GanttSidebar.svelte | 3 ++- .../src/components/gantt/GanttView.svelte | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte b/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte index a972e69d92a..82b6b028320 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte @@ -167,13 +167,14 @@ From 44b87974df57bd3cf9ef142cd452ac532656058f Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:33:15 +0000 Subject: [PATCH 24/62] fix(tracker-resources): resize handle no longer fights canvas pan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sidebar resize handle and the canvas pointer-pan handler both lived on the gantt-scroller, so dragging the handle started a canvas pan in parallel — the result was visible stutter and barely-controllable resize. Two fixes: - Add .resize-cell to onCanvasPanStart's element exclusion list so the pan never starts when the handle is the pointerdown target. - The resize-cell's own pointer handlers now stopPropagation + preventDefault, so even if a sibling listener picked up the bubbled event it would not double-process it. setPointerCapture stays so the drag tracks the pointer outside the cell bounds. Plus the v16 toolbar consolidation: - Move the always-visible blue + button to IssuesView.svelte (the shared wrapper for List, Kanban and Gantt). Single source — no duplication per viewlet. - NewIssueHeader stays as the original HeaderButton-based component; inline category-level + buttons in the issue list are unaffected. Signed-off-by: Michael Uray --- .../src/components/NewIssueHeader.svelte | 153 +++++++----------- .../src/components/gantt/GanttView.svelte | 12 +- .../src/components/issues/IssuesView.svelte | 14 +- 3 files changed, 78 insertions(+), 101 deletions(-) diff --git a/plugins/tracker-resources/src/components/NewIssueHeader.svelte b/plugins/tracker-resources/src/components/NewIssueHeader.svelte index b1e73a6fa2c..3078a2168d2 100644 --- a/plugins/tracker-resources/src/components/NewIssueHeader.svelte +++ b/plugins/tracker-resources/src/components/NewIssueHeader.svelte @@ -14,10 +14,10 @@ --> -{#if loading} - -{:else if projectExists || draftExists} -
- -
-{:else} -
-
-{/if} + $: updateActions(draftExists, projectExists, closed) + - + diff --git a/plugins/tracker-resources/src/components/gantt/GanttView.svelte b/plugins/tracker-resources/src/components/gantt/GanttView.svelte index 44f6b07839f..d629fbf802c 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttView.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttView.svelte @@ -271,9 +271,10 @@ function onCanvasPanStart (e: PointerEvent): void { if (scrollerEl === undefined) return // Only pan with primary mouse button on empty space — let SVG/HTML - // children (bars, buttons, links) handle their own click/dblclick. + // children (bars, buttons, links, resize-handle) handle their own + // click/drag without competing with the canvas pan. const target = e.target as HTMLElement - if (target.closest('.bar-wrap, button, a, .toggle-btn, .jump-btn, .settings-popover')) return + if (target.closest('.bar-wrap, button, a, .toggle-btn, .jump-btn, .settings-popover, .resize-cell')) return panning = true panStartX = e.clientX panStartY = e.clientY @@ -296,6 +297,8 @@ let resizeStartX = 0 let resizeStartWidth = 0 function onResizeStart (e: PointerEvent): void { + e.stopPropagation() + e.preventDefault() resizing = true resizeStartX = e.clientX resizeStartWidth = userSidebarWidth @@ -303,13 +306,16 @@ } function onResizeMove (e: PointerEvent): void { if (!resizing) return + e.stopPropagation() const next = resizeStartWidth + (e.clientX - resizeStartX) userSidebarWidth = Math.max(MIN_SIDEBAR_WIDTH, Math.min(MAX_SIDEBAR_WIDTH, next)) - queueMicrotask(syncViewport) } function onResizeEnd (e: PointerEvent): void { + if (!resizing) return + e.stopPropagation() resizing = false ;(e.currentTarget as HTMLElement).releasePointerCapture(e.pointerId) + queueMicrotask(syncViewport) } let resizeObs: ResizeObserver | undefined diff --git a/plugins/tracker-resources/src/components/issues/IssuesView.svelte b/plugins/tracker-resources/src/components/issues/IssuesView.svelte index 72af1e78e9f..b65d4950b91 100644 --- a/plugins/tracker-resources/src/components/issues/IssuesView.svelte +++ b/plugins/tracker-resources/src/components/issues/IssuesView.svelte @@ -3,12 +3,16 @@ import { Asset, IntlString, translateCB } from '@hcengineering/platform' import { ComponentExtensions } from '@hcengineering/presentation' import { Issue, TrackerEvents } from '@hcengineering/tracker' - import { IModeSelector, themeStore } from '@hcengineering/ui' + import { Button, IconAdd, IModeSelector, showPopup, themeStore } from '@hcengineering/ui' import { ViewOptions, Viewlet } from '@hcengineering/view' import { FilterBar, SpaceHeader, ViewletContentView, ViewletSettingButton } from '@hcengineering/view-resources' import tracker from '../../plugin' import CreateIssue from '../CreateIssue.svelte' + function newIssue (): void { + showPopup(CreateIssue, { space, shouldSaveDraft: true }, 'top') + } + export let space: Ref | undefined = undefined export let query: DocumentQuery = {} export let title: IntlString | undefined = undefined @@ -65,6 +69,14 @@ extension={tracker.extensions.IssueListHeader} props={{ size: 'small', kind: 'tertiary', space }} /> + - + + - - - jumpToDate(datePickerValue)} - /> + + +
{#each ZOOM_LEVELS as z (z)} @@ -510,13 +529,28 @@ class="gantt-grid" style="grid-template-columns: {sidebarWidthPx}px 5px 1fr; --sidebar-w: {sidebarWidthPx}px;" > - +
- - {#if showStatus}{/if} - {#if showIssueCode}{/if} - {#if showTitle}{/if} - +
+ + {#if showStatus}{/if} + {#if showIssueCode}{/if} + {#if showTitle}{/if} + +
+
+ + { if (e.key === 'Enter') jumpToToday() }} role="button" tabindex="0"> + {formatRange(dateRange.from)} – {formatRange(dateRange.to)} + + +
@@ -577,7 +611,7 @@ {#if vHasOverflow}
+ style="top: {TOOLBAR_HEIGHT}px; bottom: 11px;">
Date: Fri, 15 May 2026 12:33:15 +0000 Subject: [PATCH 30/62] feat(tracker-resources): inline-add row in Gantt sidebar (PR2.1) Plane-style: dashed-top-border "+ Add issue" row at the bottom of GanttSidebar opens the standard CreateIssue popup via showPopup. - GanttSidebar dispatches `addIssue` from a keyboard- and click- accessible row using the existing tracker.string.AddIssue label. - GanttView wires it to showPopup(CreateIssue, { space, shouldSaveDraft }). - Row is hidden when no space is available (defensive guard in newIssue handler). Verified on dk3 huly_v7 (gantt-v28): row renders, click opens "New issue" dialog with Issue title field focused. Signed-off-by: Michael Uray --- .../src/components/gantt/GanttSidebar.svelte | 44 ++++++++++++++++++- .../src/components/gantt/GanttView.svelte | 9 +++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte b/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte index 2be033622dd..d02e4df50c0 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte @@ -3,7 +3,7 @@ --> {#if visible} @@ -83,17 +94,14 @@ fill="var(--theme-content-color)" /> {#if barLabel !== ''} - {barLabel} + {barLabel} {/if} {tooltipText} {:else} {#if barLabel !== ''} - {barLabel} + {barLabel} {/if} {tooltipText} {/if} diff --git a/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte b/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte index 8bdc2ca29a0..99d14ca04fa 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte @@ -23,7 +23,7 @@ export let summaryRanges: Map export let scrollTop: number = 0 export let viewportHeight: number = 600 - export let viewport: { left: number; right: number } + export let viewport: { left: number, right: number } export let totalWidth: number export let milestoneStripHeight: number = 0 export let hoveredRowId: string | null = null @@ -39,10 +39,7 @@ $: visibleRows = filterVisibleRows(rows, scrollTop, viewportHeight) $: rowsHeight = rows.length > 0 ? rows[rows.length - 1].y + rows[rows.length - 1].height : 0 $: totalHeight = rowsHeight + milestoneStripHeight - $: ticks = timeScale.ticks([ - timeScale.fromX(Math.max(0, viewport.left - 100)), - timeScale.fromX(viewport.right + 100) - ]) + $: ticks = timeScale.ticks([timeScale.fromX(Math.max(0, viewport.left - 100)), timeScale.fromX(viewport.right + 100)]) function rowKey (row: LayoutRow): string { return row.id @@ -108,13 +105,7 @@ on:mouseleave={() => dispatch('hoverRow', { id: null })} > - + {#if row.kind === 'milestone' && row.milestone !== null} {@const range = summaryFor(row)} {#if range !== null} @@ -160,15 +151,8 @@ {#each milestones as ms (ms._id)} {@const x = timeScale.toX(ms.targetDate)} - - + + {ms.label} {/each} diff --git a/plugins/tracker-resources/src/components/gantt/GanttHeader.svelte b/plugins/tracker-resources/src/components/gantt/GanttHeader.svelte index 4022e0f596e..718c97969d0 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttHeader.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttHeader.svelte @@ -5,7 +5,7 @@ import { type TimeScale } from './lib/time-scale' export let timeScale: TimeScale - export let viewport: { left: number; right: number } // px + export let viewport: { left: number, right: number } // px export let totalWidth: number export let height: number = 36 @@ -13,20 +13,14 @@ // canvas width so the sticky-header lives in the same coordinate system // as the canvas-stack (review note: SVG must extend across the whole // scroll content, not just the visible viewport). - $: visibleRange = [ - timeScale.fromX(Math.max(0, viewport.left - 100)), - timeScale.fromX(viewport.right + 100) - ] as [number, number] + $: visibleRange = [timeScale.fromX(Math.max(0, viewport.left - 100)), timeScale.fromX(viewport.right + 100)] as [ + number, + number + ] $: ticks = timeScale.ticks(visibleRange) - + {#each ticks as tick (tick.date)} {@const x = timeScale.toX(tick.date)} - + {tick.label} {/each} diff --git a/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte b/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte index ea7090bc03c..2310ac62b7d 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte @@ -32,9 +32,7 @@ dispatch('openIssue', { issue: { _id: issue._id as string, _class: issue._class as string } }) } - function jumpDirection ( - obj: { startDate: number | null, dueDate: number | null } - ): 'left' | 'right' | null { + function jumpDirection (obj: { startDate: number | null, dueDate: number | null }): 'left' | 'right' | null { if (timeScale === undefined) return null if (viewportRight <= viewportLeft) return null if (obj.startDate == null && obj.dueDate == null) return null @@ -47,9 +45,7 @@ return null } - function rowJumpTarget ( - row: LayoutRow - ): { startDate: number | null, dueDate: number | null } | null { + function rowJumpTarget (row: LayoutRow): { startDate: number | null, dueDate: number | null } | null { if (row.kind === 'issue' && row.issue !== null) { return { startDate: row.issue.startDate, dueDate: row.issue.dueDate } } @@ -129,7 +125,9 @@ on:click={() => { if (row.issue !== null) openIssue(row.issue) }} - on:keydown={(e) => { if (e.key === 'Enter' && row.issue !== null) openIssue(row.issue) }} + on:keydown={(e) => { + if (e.key === 'Enter' && row.issue !== null) openIssue(row.issue) + }} > {row.issue.title} @@ -148,7 +146,9 @@ + @@ -221,8 +223,12 @@ overflow: hidden; text-overflow: ellipsis; } - .cell-title.clickable { cursor: pointer; } - .cell-title.clickable:hover { text-decoration: underline; } + .cell-title.clickable { + cursor: pointer; + } + .cell-title.clickable:hover { + text-decoration: underline; + } .cell-jump { flex: 0 0 28px; display: flex; @@ -243,7 +249,9 @@ align-items: center; justify-content: center; } - .toggle-btn:hover { color: var(--theme-content-color); } + .toggle-btn:hover { + color: var(--theme-content-color); + } .jump-btn { width: 22px; height: 22px; @@ -259,15 +267,19 @@ align-items: center; justify-content: center; } - .jump-btn:hover { filter: brightness(1.1); } - .sidebar-row.summary { font-weight: 600; } + .jump-btn:hover { + filter: brightness(1.1); + } + .sidebar-row.summary { + font-weight: 600; + } .sidebar-row.milestone { background: color-mix(in srgb, var(--theme-state-info-color, #6366f1) 6%, transparent); } .sidebar-row.hovered { background: var(--theme-button-hovered); } - /* When ANY row is hovered, dim non-hovered rows for a + /* When ANY row is hovered, dim non-hovered rows for a spotlight effect — implemented by the parent setting a data attr. */ :global(.sidebar-rows.has-hover) .sidebar-row:not(.hovered) { opacity: 0.55; diff --git a/plugins/tracker-resources/src/components/gantt/GanttTodayMarker.svelte b/plugins/tracker-resources/src/components/gantt/GanttTodayMarker.svelte index 2761682a707..fdef34fcbc6 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttTodayMarker.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttTodayMarker.svelte @@ -9,7 +9,7 @@ // Viewport accepted for API compatibility but no longer used for clipping // (the SVG itself spans the whole canvas so the browser handles overflow). // eslint-disable-next-line @typescript-eslint/no-unused-vars - export let viewport: { left: number; right: number } = { left: 0, right: 0 } + export let viewport: { left: number, right: number } = { left: 0, right: 0 } $: void viewport $: today = Date.now() @@ -29,10 +29,8 @@ /> - - {dateLabel} + + {dateLabel} From e70801a78d1c6dd2a3be98a61d6f9fa58492ede4 Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:39:53 +0000 Subject: [PATCH 45/62] feat(tracker-resources): GanttCanvas forwards bar events + mounts resize overlay Signed-off-by: Michael Uray --- .../src/components/gantt/GanttCanvas.svelte | 24 +++- .../gantt/GanttResizeOverlay.svelte | 130 ++++++++++++++++++ .../src/components/gantt/GanttView.svelte | 3 + 3 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 plugins/tracker-resources/src/components/gantt/GanttResizeOverlay.svelte diff --git a/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte b/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte index 99d14ca04fa..4731a096b56 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte @@ -3,15 +3,19 @@ --> + +{#if state.kind !== 'idle' && state.kind !== 'hover-bar' && geom !== null} + + +{/if} + +{#if gx !== null} + +{/if} + +{#if pd !== null && gx !== null} + + + {fmt(pd)} + +{/if} + +{#if tip !== null && gx !== null} + + + {tip} + +{/if} + + diff --git a/plugins/tracker-resources/src/components/gantt/GanttView.svelte b/plugins/tracker-resources/src/components/gantt/GanttView.svelte index 7f66aedc3da..d88e3594db5 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttView.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttView.svelte @@ -675,8 +675,11 @@ milestoneStripHeight={MILESTONE_STRIP_HEIGHT} {hoveredRowId} {statusCategoryMap} + {editableIssueIds} + {activeDrag} on:openIssue={onIssueOpen} on:hoverRow={onRowHover} + on:barMouseDown />
From 631accc3c5fde7552e0b2a243075663db2e3f48b Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:39:53 +0000 Subject: [PATCH 46/62] feat(tracker-resources): wire drag reducer + atomic commitDrag in GanttView Signed-off-by: Michael Uray --- .../src/components/gantt/GanttView.svelte | 99 ++++++++++++++++++- 1 file changed, 96 insertions(+), 3 deletions(-) diff --git a/plugins/tracker-resources/src/components/gantt/GanttView.svelte b/plugins/tracker-resources/src/components/gantt/GanttView.svelte index d88e3594db5..72c0d45773b 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttView.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttView.svelte @@ -3,9 +3,10 @@ --> -
+ +
{#if loading} {:else} @@ -797,6 +872,7 @@ {statusCategoryMap} {editableIssueIds} {activeDrag} + {focusedIssueId} on:openIssue={onIssueOpen} on:hoverRow={onRowHover} on:barMouseDown={handleBarMouseDown} @@ -903,6 +979,7 @@ width: 100%; overflow: hidden; position: relative; + outline: none; } .gantt-toolbar { flex: 0 0 auto; From 9b8e3da2e942ebfa8e20a4f71463a013713a202e Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:39:53 +0000 Subject: [PATCH 50/62] feat(tracker-resources): dim non-active rows during drag (spotlight focus) Signed-off-by: Michael Uray --- .../src/components/gantt/GanttCanvas.svelte | 16 ++++++++++++++++ .../src/components/gantt/GanttSidebar.svelte | 10 +++++++++- .../src/components/gantt/GanttView.svelte | 1 + 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte b/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte index e9a831cba31..571c99acf29 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttCanvas.svelte @@ -55,6 +55,17 @@ return focusedIssueId !== null && String(issueId) === focusedIssueId } + // PR 3 spotlight dim: while a drag is active, dim every row that is NOT the + // active issue. Keeps the cursor's row at full opacity so the user can see + // where the bar is being placed relative to other rows. + $: dragState = $activeDrag + $: activeIssueIdStr = 'issue' in dragState ? String((dragState as { issue: { _id: unknown } }).issue._id) : null + $: anyDragActive = dragState.kind !== 'idle' && dragState.kind !== 'hover-bar' + + function isDimmed (issueId: unknown): boolean { + return anyDragActive && activeIssueIdStr !== null && String(issueId) !== activeIssueIdStr + } + $: visibleRows = filterVisibleRows(rows, scrollTop, viewportHeight) $: rowsHeight = rows.length > 0 ? rows[rows.length - 1].y + rows[rows.length - 1].height : 0 $: totalHeight = rowsHeight + milestoneStripHeight @@ -110,6 +121,7 @@ class="row-rect" class:hovered={isHover} class:milestone-bg={row.kind === 'milestone'} + class:dimmed={row.issue !== null && isDimmed(row.issue._id)} /> {/each} @@ -209,6 +221,10 @@ :global(svg.gantt-canvas .row-rect.milestone-bg) { fill: color-mix(in srgb, var(--theme-state-info-color, #6366f1) 6%, transparent); } + :global(svg.gantt-canvas .row-rect.dimmed) { + fill: var(--theme-bg-color); + opacity: 0.55; + } :global(svg.gantt-canvas .row-rect.milestone-bg.hovered) { fill: color-mix(in srgb, var(--theme-state-info-color, #6366f1) 14%, transparent); } diff --git a/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte b/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte index e13fc221bfe..5f4aedc10f5 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte @@ -3,9 +3,10 @@ --> + + + +
+ + {issue.title} +
+
+
diff --git a/plugins/tracker-resources/src/components/gantt/GanttHeader.svelte b/plugins/tracker-resources/src/components/gantt/GanttHeader.svelte index 718c97969d0..85eaa463b14 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttHeader.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttHeader.svelte @@ -20,18 +20,58 @@ $: ticks = timeScale.ticks(visibleRange) - + + + + {#each ticks as tick (tick.date)} {@const x = timeScale.toX(tick.date)} + - + {#if tick.secondaryLabel !== undefined} + + {tick.secondaryLabel} + + {/if} + {tick.label} {/each} @@ -52,4 +92,9 @@ .tick-label-major { font-weight: 600; } + .tick-label-secondary { + font-size: 11px; + font-weight: 600; + opacity: 0.7; + } diff --git a/plugins/tracker-resources/src/components/gantt/GanttHierarchySubmenu.svelte b/plugins/tracker-resources/src/components/gantt/GanttHierarchySubmenu.svelte new file mode 100644 index 00000000000..40ee5fd20ba --- /dev/null +++ b/plugins/tracker-resources/src/components/gantt/GanttHierarchySubmenu.svelte @@ -0,0 +1,68 @@ + + + + diff --git a/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte b/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte index 7de19bd5035..7b6c5206b67 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttSidebar.svelte @@ -41,6 +41,12 @@ dispatch('openIssue', { issue: { _id: issue._id as string, _class: issue._class as string } }) } + function onDragGripDown (issue: Issue): (evt: MouseEvent) => void { + return (evt: MouseEvent): void => { + dispatch('rowDragStart', { issue, cursorX: evt.clientX }) + } + } + function onRowContextMenu (evt: MouseEvent, row: LayoutRow): void { if (row.issue === null) return evt.preventDefault() @@ -134,8 +140,8 @@ { if (row.issue !== null) dispatch('rowDragStart', { issue: row.issue, cursorX: e.clientX }) }} + use:tooltip={{ label: tracker.string.GanttDragToSchedule }} + on:mousedown|stopPropagation={row.issue !== null ? onDragGripDown(row.issue) : undefined} >⋮⋮ {/if} {#if showStatus} diff --git a/plugins/tracker-resources/src/components/gantt/GanttView.svelte b/plugins/tracker-resources/src/components/gantt/GanttView.svelte index 4e0bb961523..07cce3c1812 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttView.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttView.svelte @@ -351,7 +351,7 @@ if (state.kind === 'dragging-unscheduled' && !state.hasCanvasTarget) return const client = getClient() const ops = client.apply('gantt-drag') - if (state.kind === 'dragging-body' || state.kind === 'dragging-unscheduled') { + if (state.kind === 'dragging-body') { await ops.update(state.issue, { startDate: state.previewStart, dueDate: state.previewDue }) const delta = state.previewStart - state.originStart if (delta !== 0) { @@ -362,6 +362,13 @@ }) } } + } else if (state.kind === 'dragging-unscheduled') { + // Unscheduled-drag only schedules the parent issue. originStart is the + // synthetic "today" anchor — using its delta to shift existing scheduled + // descendants would move them by a wildly unrelated amount (Codex + // review-4 2026-05-11). Descendants stay put; the user can drag the + // (now-scheduled) parent again to do a coordinated shift. + await ops.update(state.issue, { startDate: state.previewStart, dueDate: state.previewDue }) } else if (state.kind === 'resizing-left') { await ops.update(state.issue, { startDate: state.previewStart }) } else if (state.kind === 'resizing-right') { @@ -408,7 +415,11 @@ 'tracker:action:EditRelatedTargets', 'tracker:action:MoveToProject', 'tracker:action:CopyAsMarkdownTable', - 'tracker:action:UnsetParent' + 'tracker:action:UnsetParent', + // Below are surfaced via the local Hierarchy ▸ submenu instead, so the + // top-level menu has one collapsed entry rather than three separate ones. + 'tracker:action:SetParent', + 'tracker:action:NewSubIssue' ] function openGanttMenu (event: MouseEvent, issue: Issue): void { @@ -655,8 +666,18 @@ scrollerEl.scrollTop = panStartScrollTop - (e.clientY - panStartY) } function onCanvasPanEnd (e: PointerEvent): void { + // Guard: only release the pointer if we actually captured it. A pointerup + // bubbling from a child element that was excluded by the pan-handler + // exclusion list (e.g. resize-handle, drag-grip) shouldn't reach + // releasePointerCapture, but browsers throw `InvalidStateError` if the + // element isn't actually capturing the given pointerId. Codex review-4 + // 2026-05-11. + if (!panning) return panning = false - ;(e.currentTarget as HTMLElement).releasePointerCapture(e.pointerId) + const el = e.currentTarget as HTMLElement + if (typeof el.hasPointerCapture === 'function' && el.hasPointerCapture(e.pointerId)) { + el.releasePointerCapture(e.pointerId) + } } // Drag-resize the sidebar. @@ -994,11 +1015,8 @@
{/if} {#if issue.startDate !== null && issue.dueDate !== null} - {@const days = - Math.round( - (Math.max(issue.dueDate, issue.startDate) - Math.min(issue.dueDate, issue.startDate)) / 86_400_000 - ) + 1} -
Duration: {days} day{days === 1 ? '' : 's'}
+ {@const days = Math.round((Math.max(issue.dueDate, issue.startDate) - Math.min(issue.dueDate, issue.startDate)) / 86_400_000) + 1} +
{/if} {/if}
diff --git a/plugins/tracker-resources/src/components/gantt/lib/__tests__/time-scale.test.ts b/plugins/tracker-resources/src/components/gantt/lib/__tests__/time-scale.test.ts index e58c9b9736d..03d8b689edc 100644 --- a/plugins/tracker-resources/src/components/gantt/lib/__tests__/time-scale.test.ts +++ b/plugins/tracker-resources/src/components/gantt/lib/__tests__/time-scale.test.ts @@ -76,3 +76,38 @@ describe('createTimeScale', () => { } }) }) + +describe('time-scale — secondary label (year/month supra row)', () => { + const DAY = 86_400_000 + + it('day-zoom: secondaryLabel set on 1st of month and on first visible tick', () => { + const scale = createTimeScale('day', Date.UTC(2026, 0, 1)) + // Span 2 months: Jan 28 – Feb 5 + const ticks = scale.ticks([Date.UTC(2026, 0, 28), Date.UTC(2026, 1, 5)]) + const withSecondary = ticks.filter((t) => t.secondaryLabel !== undefined) + // Expect: first visible tick (Jan 28) + Feb 1 + expect(withSecondary).toHaveLength(2) + expect(withSecondary[0].secondaryLabel).toMatch(/jan/i) + expect(new Date(withSecondary[1].date).getUTCDate()).toBe(1) + expect(withSecondary[1].secondaryLabel).toMatch(/feb/i) + }) + + it('week-zoom: secondaryLabel = year on first visible week + first week of new year', () => { + const scale = createTimeScale('week', Date.UTC(2026, 11, 1)) + // Span across the 2026/2027 year boundary + const ticks = scale.ticks([Date.UTC(2026, 11, 1), Date.UTC(2027, 0, 31)]) + const withSecondary = ticks.filter((t) => t.secondaryLabel !== undefined) + expect(withSecondary.length).toBeGreaterThanOrEqual(2) + expect(withSecondary[0].secondaryLabel).toBe('2026') + expect(withSecondary[1].secondaryLabel).toBe('2027') + }) + + it('quarter-zoom: label is "Qn" only, year goes to secondaryLabel', () => { + const scale = createTimeScale('quarter', Date.UTC(2026, 0, 1)) + const ticks = scale.ticks([Date.UTC(2026, 0, 1), Date.UTC(2026, 11, 31)]) + expect(ticks.map((t) => t.label)).toEqual(['Q1', 'Q2', 'Q3', 'Q4']) + expect(ticks[0].secondaryLabel).toBe('2026') + expect(ticks[1].secondaryLabel).toBeUndefined() // Q2 same year + void DAY + }) +}) diff --git a/plugins/tracker-resources/src/components/gantt/lib/menu-actions.ts b/plugins/tracker-resources/src/components/gantt/lib/menu-actions.ts index 9190d092cec..bf0d14a1a9a 100644 --- a/plugins/tracker-resources/src/components/gantt/lib/menu-actions.ts +++ b/plugins/tracker-resources/src/components/gantt/lib/menu-actions.ts @@ -5,12 +5,14 @@ import type { Issue } from '@hcengineering/tracker' import type { Action as UiAction, PopupAlignment } from '@hcengineering/ui' -import { DatePopup, showPopup } from '@hcengineering/ui' +import { DatePopup, NotificationSeverity, addNotification, showPopup } from '@hcengineering/ui' import Calendar from '@hcengineering/ui/src/components/icons/Calendar.svelte' import { getClient } from '@hcengineering/presentation' +import { translate } from '@hcengineering/platform' import type { Timestamp } from '@hcengineering/core' import tracker from '../../../plugin' import { snapToUtcMidnight } from './time-scale' +import GanttHierarchySubmenu from '../GanttHierarchySubmenu.svelte' const DAY_MS = 86_400_000 @@ -49,7 +51,13 @@ export function openSetStartDate (issue: Issue, anchor: PopupAlignment | undefin if (newStart !== null && issue.startDate == null && issue.dueDate == null) { patch.dueDate = newStart + DAY_MS } - void client.updateDoc(issue._class, issue.space, issue._id, patch) + // Surface failures (permission denied, validation, conflict) the same + // way commitDrag does (Codex review-4 2026-05-11) so the user gets + // visible feedback instead of a silent fire-and-forget. + client.updateDoc(issue._class, issue.space, issue._id, patch).catch(async (err) => { + const title = await translate(tracker.string.GanttDragFailed, {}, undefined) + addNotification(title, String(err), undefined as any, undefined, NotificationSeverity.Error) + }) } ) } @@ -75,6 +83,21 @@ export function ganttExtraActions (issue: Issue, anchor: PopupAlignment | undefi action: async () => { openSetStartDate(issue, anchor) } + }, + { + // Hierarchy ▸ submenu: combines SetParent, Add sub-issue, Link existing + // as sub-issue into one Gantt entry. The two existing model actions + // (tracker:action:SetParent, tracker:action:NewSubIssue) are excluded + // from the parent menu via GANTT_MENU_EXCLUDED_ACTIONS in GanttView. + // `action` is required by the ui.Action interface but is a no-op for + // submenu entries — Menu.svelte routes the click to `component` when + // present (showActionPopup at packages/ui/src/components/Menu.svelte:82). + label: tracker.string.Hierarchy, + icon: tracker.icon.Parent, + group: 'associate', + action: async () => { /* submenu — handled by component */ }, + component: GanttHierarchySubmenu, + props: { issue } } ] } diff --git a/plugins/tracker-resources/src/components/gantt/lib/time-scale.ts b/plugins/tracker-resources/src/components/gantt/lib/time-scale.ts index 4ed9458412c..1791f868650 100644 --- a/plugins/tracker-resources/src/components/gantt/lib/time-scale.ts +++ b/plugins/tracker-resources/src/components/gantt/lib/time-scale.ts @@ -46,46 +46,84 @@ export function createTimeScale (zoom: ZoomLevel, origin: number): TimeScale { switch (zoom) { case 'day': { + // Secondary label: month name on the 1st of each month, or on the + // first visible tick (so the user sees a context label even if the + // viewport starts mid-month). + let lastMonth = -1 + let first = true while (cursor <= to) { const d = new Date(cursor) const isMonday = d.getUTCDay() === 1 + const m = d.getUTCMonth() + let secondary: string | undefined + if (first || m !== lastMonth) { + secondary = d.toLocaleString(undefined, { month: 'short', timeZone: 'UTC' }) + lastMonth = m + first = false + } result.push({ date: cursor, label: d.getUTCDate().toString(), - level: isMonday ? 'major' : 'minor' + level: isMonday ? 'major' : 'minor', + secondaryLabel: secondary }) cursor += DAY_MS } break } case 'week': { + // Secondary label: year on the first week of each year (or first + // visible week). Aligns the supra-row with year boundaries. const d = new Date(cursor) const dow = d.getUTCDay() // 0=Sun const offsetToMonday = (1 - dow + 7) % 7 cursor += offsetToMonday * DAY_MS + let lastYear = -1 + let first = true while (cursor <= to) { const c = new Date(cursor) const isFirstWeekOfMonth = c.getUTCDate() <= 7 + const y = c.getUTCFullYear() + let secondary: string | undefined + if (first || y !== lastYear) { + secondary = String(y) + lastYear = y + first = false + } result.push({ date: cursor, label: `W${isoWeekNumber(c)}`, - level: isFirstWeekOfMonth ? 'major' : 'minor' + level: isFirstWeekOfMonth ? 'major' : 'minor', + secondaryLabel: secondary }) cursor += 7 * DAY_MS } break } case 'month': { + // Secondary label: year on January (or first visible month). Was + // entirely missing before — without it, you couldn't tell which year + // a month belonged to in a multi-year span. const start = new Date(cursor) let y = start.getUTCFullYear() let m = start.getUTCMonth() cursor = Date.UTC(y, m, 1) + let lastYear = -1 + let first = true while (cursor <= to) { const c = new Date(cursor) + const yr = c.getUTCFullYear() + let secondary: string | undefined + if (first || yr !== lastYear) { + secondary = String(yr) + lastYear = yr + first = false + } result.push({ date: cursor, label: c.toLocaleString(undefined, { month: 'short', timeZone: 'UTC' }), - level: c.getUTCMonth() === 0 ? 'major' : 'minor' + level: c.getUTCMonth() === 0 ? 'major' : 'minor', + secondaryLabel: secondary }) m += 1 if (m > 11) { @@ -97,17 +135,30 @@ export function createTimeScale (zoom: ZoomLevel, origin: number): TimeScale { break } case 'quarter': { + // Split the year out of the primary label and put it on the supra + // row — previously the label was "Q1 2026" side-by-side, which is + // visually noisy in a dense Quarter view. const start = new Date(cursor) let y = start.getUTCFullYear() let q = Math.floor(start.getUTCMonth() / 3) cursor = Date.UTC(y, q * 3, 1) + let lastYear = -1 + let first = true while (cursor <= to) { const c = new Date(cursor) const qNum = Math.floor(c.getUTCMonth() / 3) + 1 + const yr = c.getUTCFullYear() + let secondary: string | undefined + if (first || yr !== lastYear) { + secondary = String(yr) + lastYear = yr + first = false + } result.push({ date: cursor, - label: `Q${qNum} ${c.getUTCFullYear()}`, - level: qNum === 1 ? 'major' : 'minor' + label: `Q${qNum}`, + level: qNum === 1 ? 'major' : 'minor', + secondaryLabel: secondary }) q += 1 if (q > 3) { diff --git a/plugins/tracker-resources/src/components/gantt/lib/types.ts b/plugins/tracker-resources/src/components/gantt/lib/types.ts index 1a7f8deec24..7164360bf6e 100644 --- a/plugins/tracker-resources/src/components/gantt/lib/types.ts +++ b/plugins/tracker-resources/src/components/gantt/lib/types.ts @@ -11,9 +11,17 @@ export type ZoomLevel = 'day' | 'week' | 'month' | 'quarter' /** A single tick on the time-axis header (vertical gridline + label). */ export interface Tick { - date: number // UTC ms - label: string // pre-formatted, locale-aware + date: number // UTC ms + label: string // pre-formatted, locale-aware (primary row) level: 'major' | 'minor' // major ticks render thicker + with text label + /** + * Optional supra-label rendered on a second header row above `label` when + * the segment changes from the previous tick. Day view sets it to month + * name on the 1st of each month; week view sets it to the year on the + * first week of each year; month view sets it to the year on January; + * quarter view sets it to the year on Q1. + */ + secondaryLabel?: string } /** A row in the flattened layout. May be an issue, milestone, or swimlane header. */ diff --git a/plugins/tracker-resources/src/components/issues/edit/EditIssue.svelte b/plugins/tracker-resources/src/components/issues/edit/EditIssue.svelte index bf7de0a5db4..4bd35c4eced 100644 --- a/plugins/tracker-resources/src/components/issues/edit/EditIssue.svelte +++ b/plugins/tracker-resources/src/components/issues/edit/EditIssue.svelte @@ -37,8 +37,10 @@ Label, createFocusManager, getCurrentResolvedLocation, - navigate + navigate, + showPopup } from '@hcengineering/ui' + import SetParentIssueActionPopup from '../../SetParentIssueActionPopup.svelte' import view from '@hcengineering/view' import { DocNavLink, ParentsNavigator, showMenu, RelationsEditor } from '@hcengineering/view-resources' import ProjectPresenter from '../../projects/ProjectPresenter.svelte' @@ -322,6 +324,19 @@
{/if}
+ {:else if !effectiveReadonly && issue !== undefined} +
+
{/if} + +
+
+ + +
+
+
+ +
+ + diff --git a/plugins/tracker-resources/src/components/gantt/GanttView.svelte b/plugins/tracker-resources/src/components/gantt/GanttView.svelte index 07cce3c1812..27ec7872120 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttView.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttView.svelte @@ -13,6 +13,7 @@ import tracker from '../../plugin' import { canEditIssue } from '../../utils' import GanttCanvas from './GanttCanvas.svelte' + import GanttConfirmCommitPopup from './GanttConfirmCommitPopup.svelte' import GanttHeader from './GanttHeader.svelte' import GanttSidebar from './GanttSidebar.svelte' import { reduce } from './lib/drag-controller' @@ -76,6 +77,14 @@ const activeDrag = writable({ kind: 'idle' }) let editableIssueIds: Set = new Set() + /** + * Click-to-select gate (user feedback 2026-05-11): a bar must be clicked + * once to become "selected" (blue outline) before drag/resize can begin + * on it. Prevents accidentally dragging an issue while panning the + * canvas horizontally. Clicking outside any bar clears the selection. + */ + let selectedIssueId: string | null = null + let canvasViewportLeft = 0 let canvasViewportWidth = 1200 let scrollTop = 0 @@ -96,6 +105,8 @@ $: showIssueCode = (viewOptions as Record)?.ganttShowIssueCode === true $: showTitle = ((viewOptions as Record)?.ganttShowTitle ?? true) !== false $: showStatus = ((viewOptions as Record)?.ganttShowStatus ?? true) !== false + $: confirmMove = ((viewOptions as Record)?.ganttConfirmMove ?? true) !== false + $: confirmResize = ((viewOptions as Record)?.ganttConfirmResize ?? true) !== false function setZoom (z: ZoomLevel): void { zoom = z @@ -302,6 +313,15 @@ // ------------------------------------------------------------------------- function handleBarMouseDown (e: CustomEvent<{ issue: Issue, edge: 'left' | 'right' | 'body', cursorX: number }>): void { + const id = String(e.detail.issue._id) + // Click-to-select gate: if this bar isn't already selected, the first + // mousedown just selects it (no drag starts). User has to mousedown a + // second time on the now-selected bar to actually drag/resize. Codex- + // safe and matches Plane's UX (user feedback 2026-05-11). + if (selectedIssueId !== id) { + selectedIssueId = id + return + } activeDrag.update((s) => reduce(s, { type: 'mousedown-bar', issue: e.detail.issue, @@ -310,6 +330,17 @@ }, timeScale)) } + /** + * Clear selection when the user clicks outside any bar — e.g. on the + * canvas background. Bar mousedowns stopPropagation, so this only fires + * for clicks that didn't land on a bar. + */ + function onBackgroundClick (e: MouseEvent): void { + const target = e.target as HTMLElement | null + if (target?.closest('.bar-wrap') !== null) return + selectedIssueId = null + } + /** * Translate the window-space `MouseEvent.clientX` into the canvas's content * coordinate. Used for `dragging-unscheduled` so the bar lands at the date @@ -335,7 +366,20 @@ const state = $activeDrag activeDrag.set({ kind: 'idle' }) if (state.kind === 'idle' || state.kind === 'hover-bar') return + // Skip the confirmation prompt when the preview didn't actually change + // anything (drag with zero-delta — e.g. mouseup without movement). + const previewDelta = previewChangedFromOrigin(state) + if (!previewDelta) return + // Wrap the commit in the user-configurable confirmation dialog when the + // matching ganttConfirm{Move,Resize} ViewOption is on (default-on). + const needsConfirm = + ((state.kind === 'dragging-body' || state.kind === 'dragging-unscheduled') && confirmMove) || + ((state.kind === 'resizing-left' || state.kind === 'resizing-right') && confirmResize) try { + if (needsConfirm) { + const proceed = await askConfirm(state) + if (!proceed) return + } await commitDrag(state) } catch (err) { const title = await translate(tracker.string.GanttDragFailed, {}, undefined) @@ -343,6 +387,38 @@ } } + /** True when the preview window is different from the origin window. */ + function previewChangedFromOrigin (state: DragState): boolean { + if (state.kind === 'dragging-body' || state.kind === 'dragging-unscheduled') { + return state.previewStart !== state.originStart || state.previewDue !== state.originDue + } + if (state.kind === 'resizing-left') return state.previewStart !== state.originStart + if (state.kind === 'resizing-right') return state.previewDue !== state.originDue + return false + } + + /** + * Open the confirm dialog and resolve true on Apply / false on Cancel. + * The popup dispatches `close` with a boolean payload, which Huly's + * showPopup routes to the 4th-arg resultHandler. + */ + async function askConfirm (state: DragState): Promise { + if (state.kind === 'idle' || state.kind === 'hover-bar') return false + const newStart = (state.kind === 'resizing-right' ? state.originStart : (state as { previewStart: number }).previewStart) + const newDue = (state.kind === 'resizing-left' ? state.originDue : (state as { previewDue: number }).previewDue) + const kind: 'move' | 'resize' = state.kind === 'resizing-left' || state.kind === 'resizing-right' ? 'resize' : 'move' + return await new Promise((resolve) => { + showPopup( + GanttConfirmCommitPopup, + { issue: state.issue, kind, newStart, newDue }, + 'top', + (result: boolean | undefined) => { + resolve(result === true) + } + ) + }) + } + async function commitDrag (state: DragState): Promise { if (state.kind === 'idle' || state.kind === 'hover-bar') return // Guard: an unscheduled-drag that never reached the canvas (e.g. the user @@ -737,8 +813,8 @@ $: loading = loadingIssues || loadingMilestones - -
+ +
{#if loading} {:else} @@ -929,6 +1005,7 @@ {editableIssueIds} {activeDrag} {focusedIssueId} + {selectedIssueId} on:openIssue={onIssueOpen} on:hoverRow={onRowHover} on:barMouseDown={handleBarMouseDown} diff --git a/plugins/tracker-resources/src/components/gantt/lib/__tests__/link-sub-issue-cycle.test.ts b/plugins/tracker-resources/src/components/gantt/lib/__tests__/link-sub-issue-cycle.test.ts new file mode 100644 index 00000000000..0785b9ffa8c --- /dev/null +++ b/plugins/tracker-resources/src/components/gantt/lib/__tests__/link-sub-issue-cycle.test.ts @@ -0,0 +1,97 @@ +// +// Copyright © 2026 Hardcore Engineering Inc. +// SPDX-License-Identifier: EPL-2.0 +// + +/** + * Standalone test for the cycle-safe ignore-set used by + * LinkSubIssueActionPopup. The component itself can't be exercised + * headlessly (it's a Svelte popup with DOM dependencies), but the + * computeIgnoreSet function is pure and worth fencing in jest so a + * future refactor doesn't silently regress the cycle protection. + * + * The function below is a duplicate of the one in + * `LinkSubIssueActionPopup.svelte` — kept in sync deliberately. + * Codex review-5 (2026-05-11) flagged the absence of a cycle test. + */ + +import type { Issue } from '@hcengineering/tracker' +import type { Ref } from '@hcengineering/core' + +function computeIgnoreSet (root: Issue, all: Issue[]): Set> { + const ignored = new Set>([root._id]) + if (Array.isArray(root.parents)) { + for (const p of root.parents as Array<{ parentId: Ref }>) { + if (p?.parentId !== undefined) ignored.add(p.parentId) + } + } + const childrenByParent = new Map, Issue[]>() + for (const i of all) { + const parentId = i.parents?.[0]?.parentId as Ref | undefined + if (parentId === undefined) continue + const bucket = childrenByParent.get(parentId) + if (bucket === undefined) childrenByParent.set(parentId, [i]) + else bucket.push(i) + } + const queue: Issue[] = [...(childrenByParent.get(root._id) ?? [])] + while (queue.length > 0) { + const next = queue.shift() as Issue + if (ignored.has(next._id)) continue + ignored.add(next._id) + const children = childrenByParent.get(next._id) + if (children !== undefined) { + for (const c of children) queue.push(c) + } + } + return ignored +} + +function mk (id: string, parents: string[] = []): Issue { + return { + _id: id as Ref, + parents: parents.map((p) => ({ parentId: p as Ref, parentTitle: '', space: 'sp' })) + } as unknown as Issue +} + +describe('LinkSubIssue — cycle-safe ignore set', () => { + it('excludes self', () => { + const root = mk('r') + const result = computeIgnoreSet(root, [root]) + expect(result.has(root._id)).toBe(true) + }) + + it('excludes direct ancestors via parents[]', () => { + const root = mk('r', ['p', 'gp']) // r is child of p, p is child of gp + const result = computeIgnoreSet(root, [root]) + expect(result.has('p' as Ref)).toBe(true) + expect(result.has('gp' as Ref)).toBe(true) + }) + + it('excludes direct + transitive descendants', () => { + const root = mk('r') + const child = mk('c', ['r']) + const grand = mk('g', ['c', 'r']) // transitive parents — direct = c + const result = computeIgnoreSet(root, [root, child, grand]) + expect(result.has('c' as Ref)).toBe(true) + expect(result.has('g' as Ref)).toBe(true) + }) + + it('does NOT exclude an unrelated sibling of root', () => { + const root = mk('r') + const sibling = mk('s') + const result = computeIgnoreSet(root, [root, sibling]) + expect(result.has('s' as Ref)).toBe(false) + }) + + it('cycle-safe: a self-referential issue does not infinite-loop', () => { + const root = mk('r') + const cyclic = mk('x', ['x']) + expect(() => computeIgnoreSet(root, [root, cyclic])).not.toThrow() + }) + + it('cycle-safe: mutual parent loop (a<->b) terminates', () => { + const a = mk('a', ['b']) + const b = mk('b', ['a']) + expect(() => computeIgnoreSet(a, [a, b])).not.toThrow() + }) +}) diff --git a/plugins/tracker/src/index.ts b/plugins/tracker/src/index.ts index 60b32f03145..73026a04550 100644 --- a/plugins/tracker/src/index.ts +++ b/plugins/tracker/src/index.ts @@ -565,6 +565,13 @@ const pluginState = plugin(trackerId, { SetParentIssueLabel: '' as IntlString, GanttDragToSchedule: '' as IntlString, GanttDurationTooltip: '' as IntlString, + GanttConfirmMove: '' as IntlString, + GanttConfirmResize: '' as IntlString, + GanttConfirmMoveTitle: '' as IntlString, + GanttConfirmResizeTitle: '' as IntlString, + GanttConfirmMoveBody: '' as IntlString, + GanttConfirmResizeBody: '' as IntlString, + GanttConfirmApply: '' as IntlString, GanttDependency: '' as IntlString, GanttLag: '' as IntlString, NewProject: '' as IntlString, From 59097e949c1f3f4b8343200ede674a527cac12b8 Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:39:54 +0000 Subject: [PATCH 57/62] fix(tracker-resources): Gantt parent-drag truth source + canvasX offset + a11y roles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit per explicit user preference for both select-first + confirm-popup default-on): 1. Parent-drag now shifts the FULL descendant tree, not just children that happen to be in the view's filtered `issues` array. Previously a Tracker filter that hid some sub-issues caused them to stay at the old date while their parent moved — silent tree drift. commitDrag and shiftFocused both now run `client.findAll(tracker.class.Issue, { space: issue.space })` to query the full space before walking descendantsWithDates. One extra query per commit, no impact on drag- interactive frame rate. 2. computeCanvasX (unscheduled drag) now offsets by sidebarWidthPx + 5 px instead of just sidebarWidthPx. The 5 px is the resize-cell column between sidebar and canvas (.resize-cell). The hscrollbar has always used this offset (style="padding-left: {sidebarWidthPx + 5}px"); unscheduled-drag was the only consumer that missed it, causing drops to land a few pixels off at high zoom. 3. A11y: the 6 interactive s on GanttBar (regular + summary + resize handles, both branches) now carry role="button", tabindex="-1", and aria-label so screen readers announce them as actionable. The a11y-click-events-have-key-events warning is suppressed per-rect with svelte-ignore plus a banner comment explaining that keyboard support lives at the GanttView level (Tab/ArrowLeft/Right). 94 → 88 warnings. Tests: 5 suites / 60 passed. Signed-off-by: Michael Uray --- .../src/components/gantt/GanttBar.svelte | 32 +++++++++++++++++++ .../src/components/gantt/GanttView.svelte | 22 +++++++++++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/plugins/tracker-resources/src/components/gantt/GanttBar.svelte b/plugins/tracker-resources/src/components/gantt/GanttBar.svelte index 4ceb675caa0..2ab5fd46b0a 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttBar.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttBar.svelte @@ -160,6 +160,15 @@ editable but functionally inert — commitDrag's parent-pulls- children path was unreachable from the UI. --> {#if editable && !isMilestoneSummary} + + {#if w >= 18} + + @@ -223,6 +243,7 @@ {/if} {tooltipText} {:else} + {#if editable && w >= 18} + + diff --git a/plugins/tracker-resources/src/components/gantt/GanttView.svelte b/plugins/tracker-resources/src/components/gantt/GanttView.svelte index 27ec7872120..b0c8d00f345 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttView.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttView.svelte @@ -348,10 +348,17 @@ * the cursor is outside the canvas (e.g., still over the sidebar) so the * reducer keeps its default preview. */ + /** Width of the resize-cell (drag-handle column) between sidebar and canvas. + * The horizontal scrollbar already offsets by `sidebarWidthPx + 5` (see + * .gantt-hscrollbar padding-left), so the canvas content origin is at + * rect.left + sidebarWidthPx + this constant, not just sidebarWidthPx. + * Codex review-6 2026-05-11 caught the off-by-5 in unscheduled drag. */ + const RESIZE_CELL_W = 5 + function computeCanvasX (e: MouseEvent): number | undefined { if (scrollerEl === undefined) return undefined const rect = scrollerEl.getBoundingClientRect() - const sidebarEdge = rect.left + sidebarWidthPx + const sidebarEdge = rect.left + sidebarWidthPx + RESIZE_CELL_W if (e.clientX < sidebarEdge) return undefined return e.clientX - sidebarEdge + canvasViewportLeft } @@ -431,7 +438,12 @@ await ops.update(state.issue, { startDate: state.previewStart, dueDate: state.previewDue }) const delta = state.previewStart - state.originStart if (delta !== 0) { - for (const child of descendantsWithDates(state.issue, issues)) { + // Fetch the full space's issues here rather than reusing the + // view-filtered `issues` array — otherwise children hidden by an + // active Tracker filter wouldn't shift with the parent and the + // tree would drift out of sync. Codex review-6 2026-05-11. + const allInSpace = await client.findAll(tracker.class.Issue, { space: state.issue.space }) + for (const child of descendantsWithDates(state.issue, allInSpace)) { await ops.update(child, { startDate: (child.startDate as number) + delta, dueDate: (child.dueDate as number) + delta @@ -557,7 +569,11 @@ startDate: i.startDate + days * DAY_MS, dueDate: i.dueDate + days * DAY_MS }) - for (const child of descendantsWithDates(i, issues)) { + // Same filter-vs-truth issue as commitDrag: query the full space so + // filter-hidden descendants still shift with the parent (Codex + // review-6 2026-05-11). + const allInSpace = await client.findAll(tracker.class.Issue, { space: i.space }) + for (const child of descendantsWithDates(i, allInSpace)) { await ops.update(child, { startDate: (child.startDate as number) + days * DAY_MS, dueDate: (child.dueDate as number) + days * DAY_MS From ba409850ff3f9ce643f2c7f84e213e6a3dc48e1d Mon Sep 17 00:00:00 2001 From: Michael Uray Date: Fri, 15 May 2026 12:39:54 +0000 Subject: [PATCH 58/62] =?UTF-8?q?chore(tracker-resources):=20Gantt=20polis?= =?UTF-8?q?h=20=E2=80=94=20drop=20stale=20CSS,=20i18n=20ARIA=20labels?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit friction observation about select-first + confirm-popup left as-is per explicit user preference, the parent-drag performance note is a future-large-space concern): 1. .settings-btn / .settings-popover removed from GanttView.svelte. They were leftover from an earlier custom-popover prototype that was replaced by Huly's standard ToggleViewOption pattern in PR2; the CSS was orphaned. Drops 4 svelte-check warnings. 2. Resize handle ARIA labels were hardcoded English ("Resize start" / "Resize end"). Now translated via tracker.string.GanttAriaResizeStart and GanttAriaResizeEnd. Translation resolves async on themeStore language change; falls back to the English default until resolved. 84 warnings (was 88). Signed-off-by: Michael Uray --- plugins/tracker-assets/lang/en.json | 4 +- .../src/components/gantt/GanttBar.svelte | 18 ++++++-- .../src/components/gantt/GanttView.svelte | 42 ++----------------- plugins/tracker/src/index.ts | 2 + 4 files changed, 23 insertions(+), 43 deletions(-) diff --git a/plugins/tracker-assets/lang/en.json b/plugins/tracker-assets/lang/en.json index 7585ceb0263..4657194a3b5 100644 --- a/plugins/tracker-assets/lang/en.json +++ b/plugins/tracker-assets/lang/en.json @@ -329,7 +329,9 @@ "GanttConfirmResizeTitle": "Change issue dates?", "GanttConfirmMoveBody": "Move {title} to {start} – {due}?", "GanttConfirmResizeBody": "Change {title} to {start} – {due}?", - "GanttConfirmApply": "Apply" + "GanttConfirmApply": "Apply", + "GanttAriaResizeStart": "Resize start date", + "GanttAriaResizeEnd": "Resize due date" }, "status": {} } diff --git a/plugins/tracker-resources/src/components/gantt/GanttBar.svelte b/plugins/tracker-resources/src/components/gantt/GanttBar.svelte index 2ab5fd46b0a..5c87af6f5d3 100644 --- a/plugins/tracker-resources/src/components/gantt/GanttBar.svelte +++ b/plugins/tracker-resources/src/components/gantt/GanttBar.svelte @@ -4,8 +4,11 @@