diff --git a/components/calendar/__tests__/calendar-week-view-all-day-cap.test.tsx b/components/calendar/__tests__/calendar-week-view-all-day-cap.test.tsx new file mode 100644 index 000000000..1fc4014fd --- /dev/null +++ b/components/calendar/__tests__/calendar-week-view-all-day-cap.test.tsx @@ -0,0 +1,188 @@ +import { render, screen, fireEvent, cleanup } from '@testing-library/react'; +import { describe, it, expect, vi, afterEach } from 'vitest'; +import { CalendarWeekView } from '../calendar-week-view'; +import type { CalendarEvent, Calendar, CalendarTask } from '@/lib/jmap/types'; + +const calendars = [{ id: 'cal-1', name: 'Work', color: '#123456' }] as unknown as Calendar[]; + +function makeTask(id: string, due: string, overrides: Partial = {}): CalendarTask { + return { + id, + '@type': 'Task', + uid: id, + title: 'Task ' + id, + description: '', + due, + start: null, + duration: null, + timeZone: null, + showWithoutTime: true, + progress: 'needs-action', + priority: 0, + privacy: 'public', + keywords: null, + categories: null, + color: null, + created: null, + updated: '2026-09-01T00:00:00Z', + recurrenceRules: null, + alerts: null, + relatedTo: null, + calendarIds: { 'cal-1': true }, + ...overrides, + }; +} + +function makeAllDayEvent(id: string, start: string): CalendarEvent { + return { + id, + '@type': 'Event', + uid: id, + title: 'Event ' + id, + start, + duration: 'P1D', + showWithoutTime: true, + calendarIds: { 'cal-1': true }, + } as unknown as CalendarEvent; +} + +type Props = React.ComponentProps; + +function renderView(overrides: Partial = {}) { + const props: Props = { + focus: { date: new Date(2026, 8, 9), nonce: 0 }, + windowKey: 'week:2026-09-07', + // Monday 7 Sep to Sunday 13 Sep 2026 + rangeStart: new Date(2026, 8, 7), + rangeEnd: new Date(2026, 8, 13), + selectedDate: new Date(2026, 8, 9), + events: [], + calendars, + onSelectDate: vi.fn(), + onSelectEvent: vi.fn(), + onCreateAtTime: vi.fn(), + ...overrides, + }; + return { props, ...render() }; +} + +function chipSlot(taskId: string): HTMLElement { + const chip = document.querySelector(`[data-calendar-task="${taskId}"]`); + if (!chip?.parentElement) throw new Error(`no chip for ${taskId}`); + return chip.parentElement; +} + +describe('CalendarWeekView all-day and tasks height cap', () => { + afterEach(() => { + cleanup(); + }); + + it('stacks tasks directly below events of their own day instead of global allDayRowCount', () => { + // Monday 2026-09-07 has 2 all-day events + // Tuesday 2026-09-08 has NO events, but 1 task + renderView({ + events: [ + makeAllDayEvent('e1', '2026-09-07'), + makeAllDayEvent('e2', '2026-09-07'), + ], + tasks: [ + makeTask('t-tue', '2026-09-08'), + ], + }); + + // Tuesday's task must start at row 0 (top: 2px), NOT pushed down to row 2 (top: 50px) + const tueSlot = chipSlot('t-tue'); + expect(tueSlot.style.top).toBe('2px'); + }); + + it('caps all-day height to default max rows (3 rows = 76px) and provides an expand toggle when crowded', () => { + // Monday 2026-09-07 has 5 tasks (rows 0..4) + renderView({ + tasks: [ + makeTask('t1', '2026-09-07'), + makeTask('t2', '2026-09-07'), + makeTask('t3', '2026-09-07'), + makeTask('t4', '2026-09-07'), + makeTask('t5', '2026-09-07'), + ], + }); + + const toggle = screen.getByRole('button', { name: /all-day-expand/i }); + expect(toggle).toBeInTheDocument(); + expect(toggle).toHaveAttribute('aria-expanded', 'false'); + + // Default height is capped to 3 rows (3 * 24 + 4 = 76px) + const allDayGrid = document.querySelector('[data-testid="all-day-grid"]'); + expect(allDayGrid).toBeInTheDocument(); + expect(allDayGrid?.style.height).toBe('76px'); + + // Click toggle to expand + fireEvent.click(toggle); + expect(toggle).toHaveAttribute('aria-expanded', 'true'); + expect(allDayGrid?.style.height).toBe('124px'); // 5 * 24 + 4 + }); + + it('sizes the all-day area from the visible week, not from other loaded weeks (#1293)', () => { + // Three weeks loaded (free scrolling), the focused first week is empty; + // a crowded day two weeks later must not add height or a toggle here. + renderView({ + rangeStart: new Date(2026, 8, 7), + rangeEnd: new Date(2026, 8, 27), + windowKey: 'week:2026-09-07:3w', + events: [ + makeAllDayEvent('e1', '2026-09-23'), + makeAllDayEvent('e2', '2026-09-23'), + makeAllDayEvent('e3', '2026-09-23'), + makeAllDayEvent('e4', '2026-09-23'), + ], + }); + + expect(screen.queryByRole('button', { name: /all-day-expand/i })).toBeNull(); + expect(document.querySelector('[data-testid="all-day-grid"]')).toBeNull(); + }); + + it('still sizes the all-day area from entries in the visible week (#1293)', () => { + renderView({ + rangeStart: new Date(2026, 8, 7), + rangeEnd: new Date(2026, 8, 27), + windowKey: 'week:2026-09-07:3w', + events: [ + makeAllDayEvent('e1', '2026-09-08'), + makeAllDayEvent('e2', '2026-09-23'), + makeAllDayEvent('e3', '2026-09-23'), + makeAllDayEvent('e4', '2026-09-23'), + ], + }); + + const allDayGrid = document.querySelector('[data-testid="all-day-grid"]'); + expect(allDayGrid?.style.height).toBe('28px'); + expect(screen.queryByRole('button', { name: /all-day-expand/i })).toBeNull(); + }); + + it('resizes the all-day area when scrolling to a crowded week (#1293)', async () => { + renderView({ + rangeStart: new Date(2026, 8, 7), + rangeEnd: new Date(2026, 8, 27), + windowKey: 'week:2026-09-07:3w', + events: [ + makeAllDayEvent('e1', '2026-09-23'), + makeAllDayEvent('e2', '2026-09-23'), + makeAllDayEvent('e3', '2026-09-23'), + makeAllDayEvent('e4', '2026-09-23'), + ], + }); + expect(document.querySelector('[data-testid="all-day-grid"]')).toBeNull(); + + // Scroll the strip to Monday 21 Sep: 14 columns of the measured width + const strip = document.querySelector('[role="grid"]')!; + const columns = document.querySelector('[style*="grid-template-columns"]')!; + const colWidth = parseInt(/(\d+)px/.exec(columns.style.gridTemplateColumns)![1], 10); + strip.scrollLeft = 14 * colWidth; + fireEvent.scroll(strip); + await new Promise((r) => requestAnimationFrame(() => r(null))); + + const allDayGrid = await screen.findByTestId('all-day-grid'); + expect(allDayGrid.style.height).toBe('76px'); + expect(screen.getByRole('button', { name: /all-day-expand/i })).toBeInTheDocument(); + }); +}); diff --git a/components/calendar/calendar-week-view.tsx b/components/calendar/calendar-week-view.tsx index 733bb2a5d..9060c7482 100644 --- a/components/calendar/calendar-week-view.tsx +++ b/components/calendar/calendar-week-view.tsx @@ -100,15 +100,22 @@ export function CalendarWeekView({ return Math.max(MIN_COL_WIDTH, Math.floor((root.clientWidth - gutterWidth) / 7)); }, [isMobile, gutterWidth]); const [colWidth, setColWidth] = useState(MOBILE_COL_WIDTH); + const [viewportWidth, setViewportWidth] = useState(0); + // First day in view, reported by the scroll handler below (#1293) + const [visibleDayKey, setVisibleDayKey] = useState(null); useLayoutEffect(() => { const root = rootRef.current; if (!root) return; - setColWidth(measureColWidth(root)); + const measure = () => { + setColWidth(measureColWidth(root)); + setViewportWidth(Math.max(0, root.clientWidth - gutterWidth)); + }; + measure(); if (typeof ResizeObserver === "undefined") return; - const observer = new ResizeObserver(() => setColWidth(measureColWidth(root))); + const observer = new ResizeObserver(measure); observer.observe(root); return () => observer.disconnect(); - }, [measureColWidth]); + }, [measureColWidth, gutterWidth]); // Every scroll offset is computed with the column width that is rendered. // When that width changes (first measurement, resize) keep the same day at @@ -177,26 +184,55 @@ export function CalendarWeekView({ return packWeekSegments([...explicitAllDay, ...timedFullDay]); }, [events, days]); - const allDayRowCount = useMemo(() => { - return allDaySegments.reduce((maxRows, segment) => Math.max(maxRows, segment.row + 1), 0); - }, [allDaySegments]); - const tasksByDay = useMemo(() => groupTasksByDueDay(tasks), [tasks]); - // Max tasks on any single loaded day - const taskRowCount = useMemo(() => { + // Tasks stack under the events of their own day rather than globally (#1107, #1270) + const dayEventRows = useMemo(() => { + return days.map((_, dayIndex) => + allDaySegments.reduce( + (rows, segment) => + dayIndex >= segment.startIndex && dayIndex < segment.startIndex + segment.span + ? Math.max(rows, segment.row + 1) + : rows, + 0, + ) + ); + }, [days, allDaySegments]); + + // The strip holds weeks to months of days (#759), but the all-day area is + // sized from the columns in view: a crowded day in another week must not + // add empty rows or an expand toggle here (#1293). The first visible day is + // tracked by date, so columns prepended while loading do not shift it. + const visibleStartIndex = useMemo(() => { + const tracked = visibleDayKey ? days.findIndex((d) => dayKey(d) === visibleDayKey) : -1; + if (tracked >= 0) return tracked; + const target = isMobile ? focus.date : startOfWeek(focus.date, { weekStartsOn: weekStart }); + return Math.max(0, Math.min(days.length - 1, differenceInCalendarDays(target, rangeStart))); + }, [visibleDayKey, days, isMobile, focus.date, weekStart, rangeStart]); + const visibleColumns = isMobile ? Math.max(1, Math.ceil(viewportWidth / colWidth)) : 7; + + // Max combined rows (events + tasks) across the visible days + const maxContentRows = useMemo(() => { let max = 0; - for (const day of days) { - const key = format(day, "yyyy-MM-dd"); - const count = tasksByDay.get(key)?.length ?? 0; - if (count > max) max = count; + const end = Math.min(days.length, visibleStartIndex + visibleColumns); + for (let i = visibleStartIndex; i < end; i++) { + const key = format(days[i], "yyyy-MM-dd"); + const taskCount = tasksByDay.get(key)?.length ?? 0; + const total = dayEventRows[i] + taskCount; + if (total > max) max = total; } return max; - }, [tasksByDay, days]); + }, [days, dayEventRows, tasksByDay, visibleStartIndex, visibleColumns]); const hasAllDay = useMemo(() => { - return allDaySegments.length > 0 || taskRowCount > 0; - }, [allDaySegments, taskRowCount]); + return maxContentRows > 0; + }, [maxContentRows]); + + const DEFAULT_ALL_DAY_MAX_ROWS = 3; + const [isAllDayExpanded, setIsAllDayExpanded] = useState(false); + const isExpandable = maxContentRows > DEFAULT_ALL_DAY_MAX_ROWS; + const visibleRows = isAllDayExpanded ? maxContentRows : Math.min(DEFAULT_ALL_DAY_MAX_ROWS, maxContentRows); + const allDayHeight = Math.max(28, visibleRows * 24 + 4); useEffect(() => { if (rootRef.current) { @@ -258,6 +294,7 @@ export function CalendarWeekView({ const key = dayKey(day); if (key === visibleKeyRef.current) return; visibleKeyRef.current = key; + setVisibleDayKey(key); onVisibleDateChange?.(day); }); }, [colWidth, colCount, days, onVisibleDateChange]); @@ -323,14 +360,34 @@ export function CalendarWeekView({ {hasAllDay && (
- {t("events.all_day")} + {t("events.all_day")} + {isExpandable && ( + + )}
{days.map((day) => (
- {/* Task chips in all-day area */} - {taskRowCount > 0 && ( -
- {days.map((day, dayIndex) => { - const key = format(day, "yyyy-MM-dd"); - const dayTasks = tasksByDay.get(key) || []; - return dayTasks.map((task, taskIndex) => ( -
- task.calendarIds[c.id])} - onToggleComplete={onToggleTaskComplete} - onSelect={onSelectTask} - /> -
- )); - })} -
- )} + {/* Task chips in all-day area, stacked under events of their day (#1107, #1270) */} +
+ {days.map((day, dayIndex) => { + const key = format(day, "yyyy-MM-dd"); + const dayTasks = tasksByDay.get(key) || []; + const baseRow = dayEventRows[dayIndex]; + return dayTasks.map((task, taskIndex) => ( +
+ task.calendarIds[c.id])} + onToggleComplete={onToggleTaskComplete} + onSelect={onSelectTask} + /> +
+ )); + })} +
)} diff --git a/locales/ar/common.json b/locales/ar/common.json index 9ef279ff4..f07e856ab 100644 --- a/locales/ar/common.json +++ b/locales/ar/common.json @@ -2852,6 +2852,8 @@ "no_events": "لا توجد أحداث", "all_day": "طوال اليوم", "more": "+{count} أخرى", + "show_more": "إظهار المزيد", + "show_less": "إظهار أقل", "no_title": "(بلا عنوان)", "resize": "تغيير حجم الحدث", "duplicate": "تكرار", diff --git a/locales/ca/common.json b/locales/ca/common.json index aa7883070..1ad7d4c0f 100644 --- a/locales/ca/common.json +++ b/locales/ca/common.json @@ -2852,6 +2852,8 @@ "no_events": "Cap esdeveniment", "all_day": "Tot el dia", "more": "+{count} més", + "show_more": "Mostra'n més", + "show_less": "Mostra'n menys", "no_title": "(Sense títol)", "resize": "Redimensiona l'esdeveniment", "duplicate": "Duplica", diff --git a/locales/cs/common.json b/locales/cs/common.json index 8f956a352..b4e8a633a 100644 --- a/locales/cs/common.json +++ b/locales/cs/common.json @@ -2852,6 +2852,8 @@ "no_events": "Žádné události", "all_day": "Celý den", "more": "+{count} dalších", + "show_more": "Zobrazit více", + "show_less": "Zobrazit méně", "no_title": "(Bez názvu)", "resize": "Změnit velikost události", "duplicate": "Duplikovat", diff --git a/locales/da/common.json b/locales/da/common.json index 554724505..c9b7a83b3 100644 --- a/locales/da/common.json +++ b/locales/da/common.json @@ -2852,6 +2852,8 @@ "no_events": "Ingen begivenheder", "all_day": "Hele dagen", "more": "+{count} mere", + "show_more": "Vis mere", + "show_less": "Vis mindre", "no_title": "(Ingen titel)", "resize": "Tilpas størrelse på begivenhed", "duplicate": "Duplikér", diff --git a/locales/de/common.json b/locales/de/common.json index d64090f9d..3386f9a12 100644 --- a/locales/de/common.json +++ b/locales/de/common.json @@ -2852,6 +2852,8 @@ "no_events": "Keine Termine", "all_day": "Ganztägig", "more": "+{count} weitere", + "show_more": "Mehr anzeigen", + "show_less": "Weniger anzeigen", "no_title": "(Kein Titel)", "resize": "Termingröße ändern", "duplicate": "Duplizieren", diff --git a/locales/en/common.json b/locales/en/common.json index 2809d04cc..b341d07e2 100644 --- a/locales/en/common.json +++ b/locales/en/common.json @@ -2852,6 +2852,8 @@ "no_events": "No events", "all_day": "All day", "more": "+{count} more", + "show_more": "Show more", + "show_less": "Show less", "no_title": "(No title)", "resize": "Resize event", "duplicate": "Duplicate", diff --git a/locales/es/common.json b/locales/es/common.json index a0b739895..a3d431dcf 100644 --- a/locales/es/common.json +++ b/locales/es/common.json @@ -2852,6 +2852,8 @@ "no_events": "Sin eventos", "all_day": "Todo el día", "more": "+{count} más", + "show_more": "Mostrar más", + "show_less": "Mostrar menos", "no_title": "(Sin título)", "resize": "Redimensionar evento", "duplicate": "Duplicar", diff --git a/locales/fa/common.json b/locales/fa/common.json index 3bb08736d..2602162f8 100644 --- a/locales/fa/common.json +++ b/locales/fa/common.json @@ -2852,6 +2852,8 @@ "no_events": "رویدادی نیست", "all_day": "تمام روز", "more": "+{count} بیشتر", + "show_more": "نمایش بیشتر", + "show_less": "نمایش کمتر", "no_title": "(بدون عنوان)", "resize": "تغییر اندازه رویداد", "duplicate": "کپی", diff --git a/locales/fr/common.json b/locales/fr/common.json index 6a019896c..3a71d53ba 100644 --- a/locales/fr/common.json +++ b/locales/fr/common.json @@ -2852,6 +2852,8 @@ "no_events": "Aucun événement", "all_day": "Toute la journée", "more": "+{count} de plus", + "show_more": "Afficher plus", + "show_less": "Afficher moins", "no_title": "(Sans titre)", "resize": "Redimensionner l'événement", "duplicate": "Dupliquer", diff --git a/locales/he/common.json b/locales/he/common.json index fc76b08dc..97fd062be 100644 --- a/locales/he/common.json +++ b/locales/he/common.json @@ -2776,6 +2776,8 @@ "no_events": "אין אירועים", "all_day": "כל היום", "more": "+{count}נוספים", + "show_more": "הצג עוד", + "show_less": "הצג פחות", "no_title": "(ללא כותרת)", "resize": "שנה את גודל האירוע", "duplicate": "שכפול", diff --git a/locales/hu/common.json b/locales/hu/common.json index dd02e3e8d..a31947216 100644 --- a/locales/hu/common.json +++ b/locales/hu/common.json @@ -2852,6 +2852,8 @@ "no_events": "Nincs esemény", "all_day": "Egész napos", "more": "+{count} további", + "show_more": "Több mutatása", + "show_less": "Kevesebb mutatása", "no_title": "(Nincs cím)", "resize": "Esemény átméretezése", "duplicate": "Duplikálás", diff --git a/locales/it/common.json b/locales/it/common.json index 1341bb3bb..7a7f90ebb 100644 --- a/locales/it/common.json +++ b/locales/it/common.json @@ -2852,6 +2852,8 @@ "no_events": "Nessun evento", "all_day": "Tutto il giorno", "more": "+{count} altri", + "show_more": "Mostra di più", + "show_less": "Mostra meno", "no_title": "(Senza titolo)", "resize": "Ridimensiona evento", "duplicate": "Duplica", diff --git a/locales/ja/common.json b/locales/ja/common.json index 3ec22af17..425292617 100644 --- a/locales/ja/common.json +++ b/locales/ja/common.json @@ -2852,6 +2852,8 @@ "no_events": "予定なし", "all_day": "終日", "more": "他{count}件", + "show_more": "展開する", + "show_less": "折りたたむ", "no_title": "(タイトルなし)", "resize": "イベントのサイズ変更", "duplicate": "複製", diff --git a/locales/ko/common.json b/locales/ko/common.json index 8f7b1099b..17cbb4626 100644 --- a/locales/ko/common.json +++ b/locales/ko/common.json @@ -2852,6 +2852,8 @@ "no_events": "일정이 없어요", "all_day": "하루 종일", "more": "+{count}개 더보기", + "show_more": "더 보기", + "show_less": "간략히 보기", "no_title": "(제목 없음)", "resize": "일정 크기 조절", "duplicate": "복제", diff --git a/locales/lv/common.json b/locales/lv/common.json index 4a4fb86be..5b20f5f05 100644 --- a/locales/lv/common.json +++ b/locales/lv/common.json @@ -2851,6 +2851,8 @@ "no_events": "Nav pasākumu", "all_day": "Visa diena", "more": "vēl {count}", + "show_more": "Rādīt vairāk", + "show_less": "Rādīt mazāk", "no_title": "(Bez virsraksta)", "resize": "Mainīt pasākuma laiku", "duplicate": "Dublēt", diff --git a/locales/mn/common.json b/locales/mn/common.json index bb0f5f776..ad131c9d4 100644 --- a/locales/mn/common.json +++ b/locales/mn/common.json @@ -2852,6 +2852,8 @@ "no_events": "Үйл явдал байхгүй", "all_day": "Бүтэн өдөр", "more": "+{count} дэлгэрэнгүй", + "show_more": "Илүү харуулах", + "show_less": "Бага харуулах", "no_title": "(Гарчиггүй)", "resize": "Үйл явдлын хэмжээг өөрчлөх", "duplicate": "Давхардсан", diff --git a/locales/nb/common.json b/locales/nb/common.json index 38af63e16..e98753a24 100644 --- a/locales/nb/common.json +++ b/locales/nb/common.json @@ -2852,6 +2852,8 @@ "no_events": "Ingen hendelser", "all_day": "Hele dagen", "more": "+{count} til", + "show_more": "Vis flere", + "show_less": "Vis færre", "no_title": "(Ingen tittel)", "resize": "Endre størrelsen på hendelsen", "duplicate": "Dupliser", diff --git a/locales/nl/common.json b/locales/nl/common.json index ae19c61a2..fdc6dd3de 100644 --- a/locales/nl/common.json +++ b/locales/nl/common.json @@ -2852,6 +2852,8 @@ "no_events": "Geen evenementen", "all_day": "Hele dag", "more": "+{count} meer", + "show_more": "Meer tonen", + "show_less": "Minder tonen", "no_title": "(Geen titel)", "resize": "Evenement formaat wijzigen", "duplicate": "Dupliceren", diff --git a/locales/pl/common.json b/locales/pl/common.json index c33c3ab5a..98501d3d5 100644 --- a/locales/pl/common.json +++ b/locales/pl/common.json @@ -2852,6 +2852,8 @@ "no_events": "Brak wydarzeń", "all_day": "Cały dzień", "more": "+{count} więcej", + "show_more": "Pokaż więcej", + "show_less": "Pokaż mniej", "no_title": "(Bez tytułu)", "resize": "Zmień rozmiar wydarzenia", "duplicate": "Duplikuj", diff --git a/locales/pt/common.json b/locales/pt/common.json index 9f9f80462..65c3c2b89 100644 --- a/locales/pt/common.json +++ b/locales/pt/common.json @@ -2852,6 +2852,8 @@ "no_events": "Nenhum evento", "all_day": "Dia inteiro", "more": "+{count} mais", + "show_more": "Mostrar mais", + "show_less": "Mostrar menos", "no_title": "(Sem título)", "resize": "Redimensionar evento", "duplicate": "Duplicar", diff --git a/locales/ro/common.json b/locales/ro/common.json index d68f480cd..3734636ba 100644 --- a/locales/ro/common.json +++ b/locales/ro/common.json @@ -2852,6 +2852,8 @@ "no_events": "Fără evenimente", "all_day": "Toată ziua", "more": "+{count} mai multe", + "show_more": "Afișați mai mult", + "show_less": "Afișați mai puțin", "no_title": "(Fără titlu)", "resize": "Eveniment de redimensionare", "duplicate": "Duplicare", diff --git a/locales/ru/common.json b/locales/ru/common.json index 3ed1b4ff7..8b9115b2b 100644 --- a/locales/ru/common.json +++ b/locales/ru/common.json @@ -2852,6 +2852,8 @@ "no_events": "Нет событий", "all_day": "Весь день", "more": "ещё {count}", + "show_more": "Развернуть", + "show_less": "Свернуть", "no_title": "(Без названия)", "resize": "Изменить размер события", "duplicate": "Дублировать", diff --git a/locales/sk/common.json b/locales/sk/common.json index d8417d1e0..35e13eb32 100644 --- a/locales/sk/common.json +++ b/locales/sk/common.json @@ -2852,6 +2852,8 @@ "no_events": "Žiadne udalosti", "all_day": "Celý deň", "more": "+{count} ďalších", + "show_more": "Zobraziť viac", + "show_less": "Zobraziť menej", "no_title": "(Bez názvu)", "resize": "Zmeniť veľkosť udalosti", "duplicate": "Duplikovať", diff --git a/locales/tr/common.json b/locales/tr/common.json index dd3d29f14..a378f3255 100644 --- a/locales/tr/common.json +++ b/locales/tr/common.json @@ -2852,6 +2852,8 @@ "no_events": "Etkinlik yok", "all_day": "Tüm gün", "more": "+{count} daha", + "show_more": "Daha fazla göster", + "show_less": "Daha az göster", "no_title": "(Başlık yok)", "resize": "Etkinliği yeniden boyutlandır", "duplicate": "Çoğalt", diff --git a/locales/uk/common.json b/locales/uk/common.json index 30ed763f0..1dc84ec59 100644 --- a/locales/uk/common.json +++ b/locales/uk/common.json @@ -2852,6 +2852,8 @@ "no_events": "Подій немає", "all_day": "Весь день", "more": "+ ще {count}", + "show_more": "Показувати більше", + "show_less": "Показувати менше", "no_title": "(Без назви)", "resize": "Змінити розмір події", "duplicate": "дублікат", diff --git a/locales/zh-TW/common.json b/locales/zh-TW/common.json index 90254617a..4ab5edeff 100644 --- a/locales/zh-TW/common.json +++ b/locales/zh-TW/common.json @@ -2852,6 +2852,8 @@ "no_events": "沒有活動", "all_day": "全天", "more": "另有 {count} 個", + "show_more": "顯示更多", + "show_less": "顯示較少", "no_title": "(無標題)", "resize": "調整活動大小", "duplicate": "建立副本", diff --git a/locales/zh/common.json b/locales/zh/common.json index 642ca25ca..3a2773c5b 100644 --- a/locales/zh/common.json +++ b/locales/zh/common.json @@ -2852,6 +2852,8 @@ "no_events": "没有活动", "all_day": "全天", "more": "+{count} 更多", + "show_more": "展开", + "show_less": "收起", "no_title": "(无标题)", "resize": "调整事件大小", "duplicate": "复制",