diff --git a/client/scripts/feature-pairs.json b/client/scripts/feature-pairs.json index 74d26cc5f..3d3ec7809 100644 --- a/client/scripts/feature-pairs.json +++ b/client/scripts/feature-pairs.json @@ -586,6 +586,12 @@ "desktop": ["src/components/Planner/DayPlanSidebar.tsx"], "mobile": ["src/mobile/screens/trip/plan/useMPlanTimeline.ts"] }, + { + "feature": "A tour's start and end in the day plan, its end worked out from its time, and an end that runs into the next timed item", + "hooks": ["src/components/Tours/tourDayTime.ts"], + "desktop": ["src/components/Planner/DayPlanSidebar.tsx"], + "mobile": ["src/mobile/screens/trip/plan/useMPlanTimeline.ts"] + }, { "feature": "Reservation form incl. hotel accommodation creation", "hooks": ["src/components/Planner/reservationFormModel.ts", "src/components/Planner/useReservationForm.ts"], diff --git a/client/src/components/Planner/DayPlanPlaceSubline.tsx b/client/src/components/Planner/DayPlanPlaceSubline.tsx index 2a63720aa..7fe30f007 100644 --- a/client/src/components/Planner/DayPlanPlaceSubline.tsx +++ b/client/src/components/Planner/DayPlanPlaceSubline.tsx @@ -9,6 +9,7 @@ import { fs } from '../shared/DialogShell'; import { stageNumberOf } from '../Tours/stages/stageNames'; import { TourStageDayPills } from '../Tours/stages/TourStageDayPills'; import { TourDayRowPills } from '../Tours/TourDayRowFacts'; +import { TourDayTimeText } from '../Tours/TourDayTimeParts'; import { movingTimeLabel } from '../Tours/tourFacts'; import { formatPlannedTourDuration, plannedTotalText, type TourPlannedTimes } from '../Tours/tourPresentation'; import { WalkProgressPill } from '../Tours/walk/WalkStations'; @@ -120,7 +121,16 @@ export function DayPlanPlaceSubline({ // One line like the row's name: when the hover controls come out, the description // gives way and the pills keep their place instead of wrapping onto a second line.
- {place.place_time && ( + {place.place_time && dayRowTour && ( + // TIME-02: a tour's end, typed or worked out from its start and its time. + + + + )} + {place.place_time && !dayRowTour && ( {formatTime(place.place_time, locale, timeFormat)} {place.end_time ? ` – ${formatTime(place.end_time, locale, timeFormat)}` : ''} diff --git a/client/src/components/Planner/DayPlanSidebar.tours.test.tsx b/client/src/components/Planner/DayPlanSidebar.tours.test.tsx index 6f327caef..b50a2e2b5 100644 --- a/client/src/components/Planner/DayPlanSidebar.tours.test.tsx +++ b/client/src/components/Planner/DayPlanSidebar.tours.test.tsx @@ -394,7 +394,12 @@ function walkTour(place: { id: number; name: string }, overrides: Partial void }) { +function walkDayProps(extra: { + reservations?: Reservation[]; + withCafe?: boolean; + onPlanTransitLeg?: () => void; + firstWalk?: Partial; +}) { const day = buildDay({ id: 10, date: '2025-06-01', title: 'Day 1' }); const assignments = { '10': [ @@ -415,7 +420,7 @@ function walkDayProps(extra: { reservations?: Reservation[]; withCafe?: boolean; ...(extra.withCafe ? [buildAssignment({ id: 203, day_id: 10, order_index: 2, place: cafe })] : []), ], }; - const tours = [walkTour(oldTown), walkTour(harbour)]; + const tours = [walkTour(oldTown, extra.firstWalk), walkTour(harbour)]; return makeDefaultProps({ days: [day], places: [oldTown, harbour, cafe], @@ -559,4 +564,20 @@ describe('DayPlanSidebar, public transit between two city walks (CW-08)', () => expect(screen.getByTestId('transit-walk-late')).toHaveTextContent('Arrives after Harbour starts at 13:00'); expect(onPlanTransitLeg).not.toHaveBeenCalled(); }); + + it('TIME-02-017: a tour with a start shows its end worked out from its time, and nothing runs over', () => { + render(); + + const ends = screen.getAllByTestId('tour-day-end-worked-out'); + expect(ends[0]).toHaveTextContent('12:15'); + expect(ends[0]).toHaveAccessibleName('Ends at 12:15, worked out from the start and the tour time of 2 h 15 min'); + expect(screen.queryByTestId('tour-day-overrun')).not.toBeInTheDocument(); + }); + + it('TIME-02-018: an end that runs past the start of the next timed item is said under the tour, nothing moved', () => { + render(); + + expect(screen.getAllByTestId('tour-day-end-worked-out')[0]).toHaveTextContent('14:00'); + expect(screen.getByTestId('tour-day-overrun')).toHaveTextContent('Ends at 14:00, after Harbour starts at 13:00'); + }); }); diff --git a/client/src/components/Planner/DayPlanSidebar.tsx b/client/src/components/Planner/DayPlanSidebar.tsx index f02c09473..0c04bc74b 100644 --- a/client/src/components/Planner/DayPlanSidebar.tsx +++ b/client/src/components/Planner/DayPlanSidebar.tsx @@ -11,6 +11,8 @@ import { ChevronDown, ChevronRight, ChevronUp, Compass, RotateCcw, ExternalLink, import type { PlannedTransitLeg } from './transitLeg' import { useTransitLegPlanner } from './useTransitLegPlanner' import { WalkLateLine } from '../Tours/walk/WalkTransitNote' +import { TourOverrunLine } from '../Tours/TourDayTimeParts' +import { dayItemOverrun } from '../Tours/tourDayTime' import { optimizeRoute, generateGoogleMapsUrl, generateCoMapsUrl } from '../Map/RouteCalculator' import { dayViaLookup, type ViasByDay } from '../../utils/dayRouteVias' import { routeLeg, type LegEnd } from '../Map/dayRouteLeg' @@ -1414,8 +1416,9 @@ const DayPlanSidebar = React.memo(function DayPlanSidebar(props: DayPlanSidebarP // The extra connector-menu entry (#1281 follow-up): public transit for this leg while a handler is wired (day has // dates); between two city walks from the end of the one it leaves, `originId`, as two can end at one spot (CW-08). + const tourOfPlace = (placeId: number) => props.plannedTourDurations?.get(placeId)?.tour const transitLegs = useTransitLegPlanner({ tripId, assignments, accommodations, reservations, places, toursEnabled, - onPlan: onPlanTransitLeg, tourOf: placeId => props.plannedTourDurations?.get(placeId)?.tour }) + onPlan: onPlanTransitLeg, tourOf: tourOfPlace }) const transitLegPlanner = (dayId: number, seg?: RouteSegment, originId?: number) => { const leg = transitLegs.legFor(dayId, seg) return leg ? () => transitLegs.plan(dayId, leg, originId) : undefined @@ -2034,6 +2037,8 @@ const DayPlanSidebar = React.memo(function DayPlanSidebar(props: DayPlanSidebarP )}
+ {/* TIME-02: the tour's end runs past the start of the day's next timed item. */} + {dayRowTour && } {assignment.notes && ( // Day-specific note on this stop (#2163) — one muted // caption line so the timeline shows the note exists diff --git a/client/src/components/Planner/PlaceFormModal.tsx b/client/src/components/Planner/PlaceFormModal.tsx index 4fb97c966..fa33afb50 100644 --- a/client/src/components/Planner/PlaceFormModal.tsx +++ b/client/src/components/Planner/PlaceFormModal.tsx @@ -1,5 +1,5 @@ import { useState, useEffect, useRef, useMemo, useCallback, useId, type ReactNode } from 'react' -import type { RoadtripStopType } from '@trek/shared' +import type { RoadtripStopType, TourListItem } from '@trek/shared' import NoteFormatToolbar from '../shared/NoteFormatToolbar' import { useAuthStore } from '../../store/authStore' import { useAddonStore } from '../../store/addonStore' @@ -43,6 +43,7 @@ import { import { EditorField, GRID_2, INPUT, LABEL, PANEL, PillSelect, TEXTAREA } from '../shared/dialogParts' import { SoftPill, tintOf } from './planParts' import { WHITE_BUTTON } from './placeDialogParts' +import { TourEndHint } from '../Tours/TourDayTimeParts' // The submit payload mirrors the form, but lat/lng are parsed to numbers and // category_id is normalised, plus any files chosen before the place existed. @@ -85,6 +86,8 @@ interface PlaceFormModalProps { serviceStop?: ServiceStopMode | null /** Road trip mode is on, where a visit's End is when the drive leaves it. */ roadtripActive?: boolean + /** TIME-02: the tour this place is, whose end the time fields work out from its start; absent for a plain place. */ + tour?: TourListItem | null } @@ -843,6 +846,7 @@ export default function PlaceFormModal(props: PlaceFormModalProps) { dayAssignments={S.dayAssignments} hasTimeError={hasTimeError} endIsLeave={!!props.roadtripActive} + tour={props.tour} t={t} /> @@ -1166,10 +1170,11 @@ interface TimeSectionProps { /** On a road trip the End is when the drive leaves, which the field says. In Days it * stays the plain label it has always been: nothing is scheduled off it there. */ endIsLeave: boolean + tour?: TourListItem | null t: Translate } -function TimeSection({ form, handleChange, assignmentId, dayAssignments, hasTimeError, endIsLeave, t }: TimeSectionProps) { +function TimeSection({ form, handleChange, assignmentId, dayAssignments, hasTimeError, endIsLeave, tour, t }: TimeSectionProps) { const collisions = useMemo( () => timeCollisions(assignmentId, dayAssignments, form.place_time, form.end_time), [assignmentId, dayAssignments, form.place_time, form.end_time], @@ -1196,6 +1201,7 @@ function TimeSection({ form, handleChange, assignmentId, dayAssignments, hasTime /> + a.id === assignmentId)} tour={tour} /> {hasTimeError && (
)} + {chrome.editing && ( diff --git a/client/src/mobile/screens/trip/plan/useMPlanTimeline.ts b/client/src/mobile/screens/trip/plan/useMPlanTimeline.ts index d8fa847a5..1c88767e3 100644 --- a/client/src/mobile/screens/trip/plan/useMPlanTimeline.ts +++ b/client/src/mobile/screens/trip/plan/useMPlanTimeline.ts @@ -11,6 +11,7 @@ import { getDisplayTimeForDay, getMergedItems, getTransportForDay, hasCarrierEnd import { dayCoMapsUrl, dayExportStops, dayGoogleMapsUrl, optimizeDayOrder, type DayCarrier } from '../../../../components/Planner/dayRoute' import type { PlannedTransitLeg, TransitLeg } from '../../../../components/Planner/transitLeg' import { useTransitLegPlanner } from '../../../../components/Planner/useTransitLegPlanner' +import { dayItemOverrun } from '../../../../components/Tours/tourDayTime' import { buildPlanRows, breaksChronology, findUpNext, hotelChipsForDay, hotelLegsForDay, itemHasTime, type HotelLegs, type PlanRow, type TransportEntry, @@ -377,6 +378,9 @@ export function useMPlanTimeline(planner: TripPlanner) { // A saved journey that now arrives after the walk it leads to starts (CW-08). const journeyLate = useCallback((item: MergedItem) => (day ? lateBefore(day, item.data, merged.slice(merged.indexOf(item) + 1)) : null), [day, lateBefore, merged]) + // A tour whose end runs past the start of the day's next timed item (TIME-02). + const tourOverrun = useCallback((item: MergedItem) => + (day ? dayItemOverrun(merged, merged.indexOf(item), day.id, tourOf) : null), [day, merged, tourOf]) return { day, rows, hotelLegs, merged, hotelChips, weather, weatherTemp, upNext, @@ -387,7 +391,7 @@ export function useMPlanTimeline(planner: TripPlanner) { moveRowTo, addPlace, addBooking, addTransport, optimize, canExportRoute, exportGoogleMaps, exportCoMaps, renameDay, fullPlaceOf, - routeModeOptions, setLegMode, transitLegFor, planTransitLeg, journeyLate, + routeModeOptions, setLegMode, transitLegFor, planTransitLeg, journeyLate, tourOverrun, } } diff --git a/client/src/mobile/screens/trip/sheets/PlTimeFields.tsx b/client/src/mobile/screens/trip/sheets/PlTimeFields.tsx index 6e63f8b26..cb5e8c180 100644 --- a/client/src/mobile/screens/trip/sheets/PlTimeFields.tsx +++ b/client/src/mobile/screens/trip/sheets/PlTimeFields.tsx @@ -4,6 +4,7 @@ import { Eyebrow } from './PlSheetChrome' import CustomTimePicker from '../../../../components/shared/CustomTimePicker' import { timeCollisions } from '../../../../components/Planner/PlaceFormModal.helpers' import type { Assignment } from '../../../../types' +import { TourEndHint } from '../../../../components/Tours/TourDayTimeParts' import type { TripPlanner } from '../MTripShell' interface PlTimeFieldsProps { @@ -39,6 +40,9 @@ export default function PlTimeFields({ () => timeCollisions(assignmentId, dayAssignments, startTime, endTime), [assignmentId, dayAssignments, startTime, endTime], ) + // TIME-02: a tour's end follows from its start and its time while none is typed. + const assignment = dayAssignments.find(a => a.id === assignmentId) + const tour = assignment ? planner.tours.find(item => item.place_id === assignment.place_id) : undefined return (
@@ -55,6 +59,7 @@ export default function PlTimeFields({ )}
+ {hasTimeError && (
diff --git a/client/src/pages/TripPlannerPage.tsx b/client/src/pages/TripPlannerPage.tsx index fd28cb067..87c791f83 100644 --- a/client/src/pages/TripPlannerPage.tsx +++ b/client/src/pages/TripPlannerPage.tsx @@ -831,7 +831,7 @@ function TripPlannerPageDesktop(): React.ReactElement | null { /> )} - { setShowPlaceForm(false); setEditingPlace(null); setEditingAssignmentId(null); setPrefillCoords(null); setServiceStopForm(false) }} onSave={handleSavePlace} place={editingPlace} prefillCoords={prefillCoords} assignmentId={editingAssignmentId} dayAssignments={editingPlace ? Object.values(assignments).flat() : []} tripId={tripId} categories={categories} onCategoryCreated={cat => tripActions.addCategory?.(cat)} isMobile={isMobile} onOpenExpense={openBookingExpense} serviceStop={serviceStopMode} roadtripActive={roadtripActive} /> + { setShowPlaceForm(false); setEditingPlace(null); setEditingAssignmentId(null); setPrefillCoords(null); setServiceStopForm(false) }} onSave={handleSavePlace} place={editingPlace} prefillCoords={prefillCoords} assignmentId={editingAssignmentId} dayAssignments={editingPlace ? Object.values(assignments).flat() : []} tripId={tripId} categories={categories} onCategoryCreated={cat => tripActions.addCategory?.(cat)} isMobile={isMobile} onOpenExpense={openBookingExpense} serviceStop={serviceStopMode} roadtripActive={roadtripActive} tour={editingPlace ? tours.find(item => item.place_id === editingPlace.id) ?? null : null} /> setShowTripForm(false)} diff --git a/client/tests/unit/mobile/trip/MPlanTimeline.test.tsx b/client/tests/unit/mobile/trip/MPlanTimeline.test.tsx index fe1599d42..e49008147 100644 --- a/client/tests/unit/mobile/trip/MPlanTimeline.test.tsx +++ b/client/tests/unit/mobile/trip/MPlanTimeline.test.tsx @@ -124,6 +124,7 @@ function buildTl(over: Record = {}): MPlanTimelineController { transitLegFor: vi.fn(() => null), planTransitLeg: vi.fn(), journeyLate: vi.fn(() => null), + tourOverrun: vi.fn(() => null), ...over, } as unknown as MPlanTimelineController } @@ -391,6 +392,14 @@ describe('MPlanTimeline', () => { renderTimeline({ rows: [row], merged: [item], upNext: null }, { toursEnabled: false }) expect(screen.queryByText('tours.dayRoute.endpointUnknown')).not.toBeInTheDocument() }) + + it('TIME-02-020: a tour row says when its end runs into the next timed item, read from the shared timeline logic', () => { + const validRow: PlanRow = { ...row, invalidTour: false } + const tourOverrun = vi.fn(() => ({ name: 'Lunch', time: '12:00', end: '13:00' })) + renderTimeline({ rows: [validRow], merged: [item], upNext: null, tourOverrun }, { toursEnabled: true, tours: [] }) + expect(tourOverrun).toHaveBeenCalledWith(item) + expect(screen.getByTestId('tour-day-overrun')).toBeInTheDocument() + }) }) describe('per-segment travel mode', () => { diff --git a/client/tests/unit/mobile/trip/PlTimeFields.test.tsx b/client/tests/unit/mobile/trip/PlTimeFields.test.tsx index 7bfa12667..815f60fb5 100644 --- a/client/tests/unit/mobile/trip/PlTimeFields.test.tsx +++ b/client/tests/unit/mobile/trip/PlTimeFields.test.tsx @@ -7,7 +7,7 @@ import { seedStore } from '../../../helpers/store' import { buildSettings } from '../../../helpers/factories' import { useSettingsStore } from '../../../../src/store/settingsStore' -// FE-MOB-PLTIME-001 to FE-MOB-PLTIME-015 +// FE-MOB-PLTIME-001 to FE-MOB-PLTIME-017 const planner = buildPlanner() @@ -171,4 +171,40 @@ describe('PlTimeFields', () => { setup() expect(screen.queryByText('roadtrip.stop.endIsLeave')).not.toBeInTheDocument() }) + + // TIME-02: an imported hike of 12 km, 300 m up and 500 m down, estimated at 4 h. + const hike = { + place_id: 1, name: 'Museum ridge', tour_type: 'hike', distance: 12, elevation_gain: 300, elevation_loss: 500, + duration: null, planned_duration_minutes: null, break_additional_minutes: null, difficulty: null, wanderer_ref: null, + match_confidence: 1, max_hiking_difficulty: null, planned: true, caution: false, + } + + function renderTour(startTime: string, endTime: string) { + seedStore(useSettingsStore, { settings: buildSettings({ time_format: '24h' }) }) + return render( + , + ) + } + + it('FE-MOB-PLTIME-016: a tour without a typed end says the end its start and its time work out to', () => { + renderTour('09:00', '') + expect(screen.getByTestId('tour-day-end-hint')).toHaveTextContent('13:00') + expect(screen.getByTestId('tour-day-end-hint')).toHaveTextContent('≈ 4 h') + }) + + it('FE-MOB-PLTIME-017: before a start it says one will set the end, and a typed end needs no hint', () => { + const view = renderTour('', '') + expect(screen.getByTestId('tour-day-end-hint')).toHaveTextContent('≈ 4 h') + view.unmount() + renderTour('09:00', '15:00') + expect(screen.queryByTestId('tour-day-end-hint')).not.toBeInTheDocument() + }) }) diff --git a/client/tests/unit/mobile/trip/useMPlanTimeline.transit.test.tsx b/client/tests/unit/mobile/trip/useMPlanTimeline.transit.test.tsx index 6cfdb74cb..9e04c6eb4 100644 --- a/client/tests/unit/mobile/trip/useMPlanTimeline.transit.test.tsx +++ b/client/tests/unit/mobile/trip/useMPlanTimeline.transit.test.tsx @@ -115,4 +115,19 @@ describe('useMPlanTimeline, public transit between two city walks (CW-08)', () = if (!item) throw new Error('no journey on the day') expect(result.current.journeyLate(item)).toEqual({ walk: 'Harbour', time: '13:00' }) }) + + it('FE-MOB-PLTL-HOOK-005: says a walk whose end runs past the next walk start, the desktop rule (TIME-02)', () => { + const late = buildPlanner({ + ...walkPlanner(), + tours: [{ ...walk(oldTown), planned_duration_minutes: 240 }, walk(harbour)], + } as never) + const { result } = renderHook(() => useMPlanTimeline(late)) + + const [first, second] = result.current.merged + expect(result.current.tourOverrun(first)).toEqual({ name: 'Harbour', time: '13:00', end: '14:00' }) + expect(result.current.tourOverrun(second)).toBeNull() + // In time, nothing is said. + const { result: inTime } = renderHook(() => useMPlanTimeline(walkPlanner())) + expect(inTime.current.tourOverrun(inTime.current.merged[0])).toBeNull() + }) }) diff --git a/shared/src/i18n/ar/tours.ts b/shared/src/i18n/ar/tours.ts index 0d547eda5..e91f94ecc 100644 --- a/shared/src/i18n/ar/tours.ts +++ b/shared/src/i18n/ar/tours.ts @@ -1370,5 +1370,11 @@ const tours: TranslationStrings = { 'tours.estimate.noHeights': 'لا يحتوي المسار على ارتفاعات، لذا لا يمكن تقدير وقته.', 'tours.estimate.basisDin': 'محسوب من المسافة والصعود والنزول وفق قاعدة لافتات المشي (DIN 33466)، دون استراحات.', 'tours.estimate.basisPace': 'محسوب من المسافة بالوتيرة المُدخلة.', + 'tours.dayTime.workedOut': 'ينتهي عند {time}، محسوبًا من البداية ومدة الجولة {total}', + 'tours.dayTime.workedOutNextDay': 'ينتهي في اليوم التالي عند {time}، محسوبًا من البداية ومدة الجولة {total}', + 'tours.dayTime.overrun': 'ينتهي عند {end}، بعد بدء {name} عند {time}', + 'tours.dayTime.nextItem': 'العنصر التالي', + 'tours.dayTime.formHint': 'إذا تُرك فارغًا تُحسب النهاية: {time}، أي البداية مضافًا إليها مدة الجولة {total}.', + 'tours.dayTime.formNoStart': 'مع وقت البداية تُحسب النهاية من مدة الجولة {total}.', }; export default tours; diff --git a/shared/src/i18n/az/tours.ts b/shared/src/i18n/az/tours.ts index ed1fa43f1..85c2bf5c8 100644 --- a/shared/src/i18n/az/tours.ts +++ b/shared/src/i18n/az/tours.ts @@ -1311,5 +1311,12 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Məsafə, qalxma və enmədən piyada nişanları qaydası ilə (DIN 33466) hesablanıb, fasilələr daxil deyil.', 'tours.estimate.basisPace': 'Məsafədən daxil edilmiş templə hesablanıb.', + 'tours.dayTime.workedOut': '{time} radələrində bitir, başlanğıc və {total} tur vaxtından hesablanıb', + 'tours.dayTime.workedOutNextDay': + 'Növbəti gün {time} radələrində bitir, başlanğıc və {total} tur vaxtından hesablanıb', + 'tours.dayTime.overrun': '{end} radələrində bitir, {name} {time} radələrində başladıqdan sonra', + 'tours.dayTime.nextItem': 'növbəti element', + 'tours.dayTime.formHint': 'Boş qalsa, son hesablanır: {time}, başlanğıc üstəgəl {total} tur vaxtı.', + 'tours.dayTime.formNoStart': 'Başlanğıc vaxtı ilə son {total} tur vaxtından hesablanır.', }; export default tours; diff --git a/shared/src/i18n/br/tours.ts b/shared/src/i18n/br/tours.ts index d269719a3..d6d62307c 100644 --- a/shared/src/i18n/br/tours.ts +++ b/shared/src/i18n/br/tours.ts @@ -1324,5 +1324,12 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Calculado pela distância, subida e descida segundo a regra das placas de trilha (DIN 33466), sem pausas.', 'tours.estimate.basisPace': 'Calculado pela distância no ritmo informado.', + 'tours.dayTime.workedOut': 'Termina às {time}, calculado pelo início e pela duração de {total}', + 'tours.dayTime.workedOutNextDay': + 'Termina no dia seguinte às {time}, calculado pelo início e pela duração de {total}', + 'tours.dayTime.overrun': 'Termina às {end}, depois que {name} começa às {time}', + 'tours.dayTime.nextItem': 'o próximo item', + 'tours.dayTime.formHint': 'Se ficar vazio, o fim é calculado: {time}, o início mais a duração de {total}.', + 'tours.dayTime.formNoStart': 'Com um horário de início, o fim é calculado pela duração de {total}.', }; export default tours; diff --git a/shared/src/i18n/ca/tours.ts b/shared/src/i18n/ca/tours.ts index d2b422495..9b5f921b2 100644 --- a/shared/src/i18n/ca/tours.ts +++ b/shared/src/i18n/ca/tours.ts @@ -1330,5 +1330,11 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Calculat a partir de la distància, la pujada i la baixada segons la regla dels senyals excursionistes (DIN 33466), sense pauses.', 'tours.estimate.basisPace': 'Calculat a partir de la distància al ritme introduït.', + 'tours.dayTime.workedOut': 'Acaba a les {time}, calculat a partir de l’inici i la durada de {total}', + 'tours.dayTime.workedOutNextDay': 'Acaba l’endemà a les {time}, calculat a partir de l’inici i la durada de {total}', + 'tours.dayTime.overrun': 'Acaba a les {end}, després que {name} comenci a les {time}', + 'tours.dayTime.nextItem': 'l’element següent', + 'tours.dayTime.formHint': 'Si es deixa buit, el final es calcula: {time}, l’inici més la durada de {total}.', + 'tours.dayTime.formNoStart': 'Amb una hora d’inici, el final es calcula a partir de la durada de {total}.', }; export default tours; diff --git a/shared/src/i18n/cs/tours.ts b/shared/src/i18n/cs/tours.ts index 6ecc24212..d5823517a 100644 --- a/shared/src/i18n/cs/tours.ts +++ b/shared/src/i18n/cs/tours.ts @@ -1315,5 +1315,11 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Vypočteno ze vzdálenosti, stoupání a klesání podle pravidla turistických rozcestníků (DIN 33466), bez přestávek.', 'tours.estimate.basisPace': 'Vypočteno ze vzdálenosti při zadaném tempu.', + 'tours.dayTime.workedOut': 'Končí v {time}, vypočteno ze začátku a doby túry {total}', + 'tours.dayTime.workedOutNextDay': 'Končí další den v {time}, vypočteno ze začátku a doby túry {total}', + 'tours.dayTime.overrun': 'Končí v {end}, až po začátku {name} v {time}', + 'tours.dayTime.nextItem': 'další položka', + 'tours.dayTime.formHint': 'Když zůstane prázdný, konec se vypočte: {time}, začátek plus doba túry {total}.', + 'tours.dayTime.formNoStart': 'Se začátkem se konec vypočte z doby túry {total}.', }; export default tours; diff --git a/shared/src/i18n/de/tours.ts b/shared/src/i18n/de/tours.ts index 51b05cf58..8f275aa96 100644 --- a/shared/src/i18n/de/tours.ts +++ b/shared/src/i18n/de/tours.ts @@ -1342,6 +1342,13 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Aus Strecke, Auf- und Abstieg nach der Wegweiser-Regel (DIN 33466) berechnet, ohne Pausen.', 'tours.estimate.basisPace': 'Aus der Strecke beim eingegebenen Tempo berechnet.', + 'tours.dayTime.workedOut': 'Endet um {time}, berechnet aus dem Start und der Tourzeit von {total}', + 'tours.dayTime.workedOutNextDay': + 'Endet am nächsten Tag um {time}, berechnet aus dem Start und der Tourzeit von {total}', + 'tours.dayTime.overrun': 'Endet um {end}, nach dem Start von {name} um {time}', + 'tours.dayTime.nextItem': 'dem nächsten Eintrag', + 'tours.dayTime.formHint': 'Leer gelassen, wird das Ende berechnet: {time}, der Start plus die Tourzeit von {total}.', + 'tours.dayTime.formNoStart': 'Mit einer Startzeit wird das Ende aus der Tourzeit von {total} berechnet.', }; export default tours; diff --git a/shared/src/i18n/en/tours.ts b/shared/src/i18n/en/tours.ts index f79c43309..52c21a41d 100644 --- a/shared/src/i18n/en/tours.ts +++ b/shared/src/i18n/en/tours.ts @@ -1297,5 +1297,12 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Worked out from distance, ascent and descent by the hiking signpost rule (DIN 33466), without breaks.', 'tours.estimate.basisPace': 'Worked out from the distance at the pace entered.', + 'tours.dayTime.workedOut': 'Ends at {time}, worked out from the start and the tour time of {total}', + 'tours.dayTime.workedOutNextDay': + 'Ends at {time} on the next day, worked out from the start and the tour time of {total}', + 'tours.dayTime.overrun': 'Ends at {end}, after {name} starts at {time}', + 'tours.dayTime.nextItem': 'the next item', + 'tours.dayTime.formHint': 'Left empty, the end is worked out: {time}, the start plus the tour time of {total}.', + 'tours.dayTime.formNoStart': 'With a start time, the end is worked out from the tour time of {total}.', }; export default tours; diff --git a/shared/src/i18n/es/tours.ts b/shared/src/i18n/es/tours.ts index 81c6909a6..48fdc1d24 100644 --- a/shared/src/i18n/es/tours.ts +++ b/shared/src/i18n/es/tours.ts @@ -1323,5 +1323,12 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Calculado a partir de la distancia, el ascenso y el descenso según la regla de las señales de senderismo (DIN 33466), sin pausas.', 'tours.estimate.basisPace': 'Calculado a partir de la distancia al ritmo introducido.', + 'tours.dayTime.workedOut': 'Termina a las {time}, calculado a partir del inicio y la duración de {total}', + 'tours.dayTime.workedOutNextDay': + 'Termina al día siguiente a las {time}, calculado a partir del inicio y la duración de {total}', + 'tours.dayTime.overrun': 'Termina a las {end}, después de que {name} empiece a las {time}', + 'tours.dayTime.nextItem': 'el siguiente elemento', + 'tours.dayTime.formHint': 'Si se deja vacío, el final se calcula: {time}, el inicio más la duración de {total}.', + 'tours.dayTime.formNoStart': 'Con una hora de inicio, el final se calcula a partir de la duración de {total}.', }; export default tours; diff --git a/shared/src/i18n/et/tours.ts b/shared/src/i18n/et/tours.ts index daaef2522..341f7403a 100644 --- a/shared/src/i18n/et/tours.ts +++ b/shared/src/i18n/et/tours.ts @@ -1306,5 +1306,11 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Arvutatud vahemaa, tõusu ja laskumise järgi matkaviitade reegli (DIN 33466) alusel, pausideta.', 'tours.estimate.basisPace': 'Arvutatud vahemaast sisestatud tempoga.', + 'tours.dayTime.workedOut': 'Lõpeb kell {time}, arvutatud algusest ja matka ajast {total}', + 'tours.dayTime.workedOutNextDay': 'Lõpeb järgmisel päeval kell {time}, arvutatud algusest ja matka ajast {total}', + 'tours.dayTime.overrun': 'Lõpeb kell {end}, pärast seda kui {name} algab kell {time}', + 'tours.dayTime.nextItem': 'järgmine punkt', + 'tours.dayTime.formHint': 'Tühjaks jättes arvutatakse lõpp: {time}, algus pluss matka aeg {total}.', + 'tours.dayTime.formNoStart': 'Algusajaga arvutatakse lõpp matka ajast {total}.', }; export default tours; diff --git a/shared/src/i18n/fr/tours.ts b/shared/src/i18n/fr/tours.ts index 416c81179..f2f46a173 100644 --- a/shared/src/i18n/fr/tours.ts +++ b/shared/src/i18n/fr/tours.ts @@ -1350,5 +1350,12 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Calculé à partir de la distance, du dénivelé positif et négatif selon la règle des panneaux de randonnée (DIN 33466), sans pauses.', 'tours.estimate.basisPace': 'Calculé à partir de la distance à l’allure saisie.', + 'tours.dayTime.workedOut': 'Se termine à {time}, calculé à partir du départ et de la durée de {total}', + 'tours.dayTime.workedOutNextDay': + 'Se termine le lendemain à {time}, calculé à partir du départ et de la durée de {total}', + 'tours.dayTime.overrun': 'Se termine à {end}, après le début de {name} à {time}', + 'tours.dayTime.nextItem': 'l’élément suivant', + 'tours.dayTime.formHint': 'Laissée vide, la fin est calculée : {time}, le départ plus la durée de {total}.', + 'tours.dayTime.formNoStart': 'Avec une heure de départ, la fin est calculée à partir de la durée de {total}.', }; export default tours; diff --git a/shared/src/i18n/gr/tours.ts b/shared/src/i18n/gr/tours.ts index bbe937af5..60cb9e5e5 100644 --- a/shared/src/i18n/gr/tours.ts +++ b/shared/src/i18n/gr/tours.ts @@ -1352,5 +1352,12 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Υπολογισμένος από απόσταση, ανάβαση και κατάβαση με τον κανόνα των πινακίδων πεζοπορίας (DIN 33466), χωρίς διαλείμματα.', 'tours.estimate.basisPace': 'Υπολογισμένος από την απόσταση με τον ρυθμό που δόθηκε.', + 'tours.dayTime.workedOut': 'Τελειώνει στις {time}, υπολογισμένο από την έναρξη και τη διάρκεια {total}', + 'tours.dayTime.workedOutNextDay': + 'Τελειώνει την επόμενη μέρα στις {time}, υπολογισμένο από την έναρξη και τη διάρκεια {total}', + 'tours.dayTime.overrun': 'Τελειώνει στις {end}, μετά την έναρξη του {name} στις {time}', + 'tours.dayTime.nextItem': 'το επόμενο στοιχείο', + 'tours.dayTime.formHint': 'Αν μείνει κενό, το τέλος υπολογίζεται: {time}, η έναρξη συν τη διάρκεια {total}.', + 'tours.dayTime.formNoStart': 'Με ώρα έναρξης, το τέλος υπολογίζεται από τη διάρκεια {total}.', }; export default tours; diff --git a/shared/src/i18n/hu/tours.ts b/shared/src/i18n/hu/tours.ts index 7bc13fae7..4cc9f2f63 100644 --- a/shared/src/i18n/hu/tours.ts +++ b/shared/src/i18n/hu/tours.ts @@ -1329,5 +1329,11 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'A távból, emelkedésből és lejtésből számolva a turistaútjelzők szabálya szerint (DIN 33466), szünetek nélkül.', 'tours.estimate.basisPace': 'A távból számolva a megadott tempóval.', + 'tours.dayTime.workedOut': 'Vége: {time}, a kezdésből és a túra {total} idejéből számolva', + 'tours.dayTime.workedOutNextDay': 'Vége másnap {time}-kor, a kezdésből és a túra {total} idejéből számolva', + 'tours.dayTime.overrun': 'Vége: {end}, miután {name} {time}-kor kezdődik', + 'tours.dayTime.nextItem': 'a következő tétel', + 'tours.dayTime.formHint': 'Üresen hagyva a vég kiszámolódik: {time}, a kezdés plusz a túra {total} ideje.', + 'tours.dayTime.formNoStart': 'Kezdési időponttal a vég a túra {total} idejéből számolódik.', }; export default tours; diff --git a/shared/src/i18n/id/tours.ts b/shared/src/i18n/id/tours.ts index a73ad0d4f..eb3107934 100644 --- a/shared/src/i18n/id/tours.ts +++ b/shared/src/i18n/id/tours.ts @@ -1303,5 +1303,11 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Dihitung dari jarak, tanjakan, dan turunan menurut aturan papan penunjuk pendakian (DIN 33466), tanpa istirahat.', 'tours.estimate.basisPace': 'Dihitung dari jarak dengan kecepatan yang dimasukkan.', + 'tours.dayTime.workedOut': 'Selesai pukul {time}, dihitung dari mulai dan waktu tur {total}', + 'tours.dayTime.workedOutNextDay': 'Selesai keesokan harinya pukul {time}, dihitung dari mulai dan waktu tur {total}', + 'tours.dayTime.overrun': 'Selesai pukul {end}, setelah {name} dimulai pukul {time}', + 'tours.dayTime.nextItem': 'item berikutnya', + 'tours.dayTime.formHint': 'Jika dibiarkan kosong, akhir dihitung: {time}, waktu mulai ditambah waktu tur {total}.', + 'tours.dayTime.formNoStart': 'Dengan waktu mulai, akhir dihitung dari waktu tur {total}.', }; export default tours; diff --git a/shared/src/i18n/it/tours.ts b/shared/src/i18n/it/tours.ts index 54f6d02da..6cb24e79d 100644 --- a/shared/src/i18n/it/tours.ts +++ b/shared/src/i18n/it/tours.ts @@ -1337,5 +1337,12 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Calcolato da distanza, salita e discesa secondo la regola dei cartelli escursionistici (DIN 33466), senza pause.', 'tours.estimate.basisPace': 'Calcolato dalla distanza al ritmo inserito.', + 'tours.dayTime.workedOut': 'Finisce alle {time}, calcolato dalla partenza e dalla durata di {total}', + 'tours.dayTime.workedOutNextDay': + 'Finisce il giorno dopo alle {time}, calcolato dalla partenza e dalla durata di {total}', + 'tours.dayTime.overrun': 'Finisce alle {end}, dopo l’inizio di {name} alle {time}', + 'tours.dayTime.nextItem': 'la voce successiva', + 'tours.dayTime.formHint': 'Se lasciata vuota, la fine viene calcolata: {time}, la partenza più la durata di {total}.', + 'tours.dayTime.formNoStart': 'Con un orario di partenza, la fine viene calcolata dalla durata di {total}.', }; export default tours; diff --git a/shared/src/i18n/ja/tours.ts b/shared/src/i18n/ja/tours.ts index 6d48601ff..6ffbb758e 100644 --- a/shared/src/i18n/ja/tours.ts +++ b/shared/src/i18n/ja/tours.ts @@ -1271,5 +1271,11 @@ const tours: TranslationStrings = { 'tours.estimate.noHeights': 'トラックに標高データがないため、時間を推定できません。', 'tours.estimate.basisDin': '距離・登り・下りから登山道標識の基準(DIN 33466)で算出、休憩は含みません。', 'tours.estimate.basisPace': '距離と入力したペースから算出。', + 'tours.dayTime.workedOut': '{time}に終了(開始時刻とツアー時間{total}から算出)', + 'tours.dayTime.workedOutNextDay': '翌日{time}に終了(開始時刻とツアー時間{total}から算出)', + 'tours.dayTime.overrun': '{end}に終了、{name}の開始{time}より後です', + 'tours.dayTime.nextItem': '次の項目', + 'tours.dayTime.formHint': '空欄のままなら終了時刻を算出します:{time}(開始時刻+ツアー時間{total})。', + 'tours.dayTime.formNoStart': '開始時刻を入れると、ツアー時間{total}から終了時刻を算出します。', }; export default tours; diff --git a/shared/src/i18n/ko/tours.ts b/shared/src/i18n/ko/tours.ts index 603b5c965..b0f5f3f14 100644 --- a/shared/src/i18n/ko/tours.ts +++ b/shared/src/i18n/ko/tours.ts @@ -1268,5 +1268,11 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': '거리, 오르막, 내리막으로 등산로 표지 규칙(DIN 33466)에 따라 계산했으며 휴식은 포함하지 않습니다.', 'tours.estimate.basisPace': '거리와 입력한 페이스로 계산했습니다.', + 'tours.dayTime.workedOut': '{time}에 종료, 시작 시각과 투어 시간 {total}으로 계산', + 'tours.dayTime.workedOutNextDay': '다음 날 {time}에 종료, 시작 시각과 투어 시간 {total}으로 계산', + 'tours.dayTime.overrun': '{end}에 종료, {name}이(가) {time}에 시작한 뒤입니다', + 'tours.dayTime.nextItem': '다음 항목', + 'tours.dayTime.formHint': '비워 두면 종료 시각을 계산합니다: {time}, 시작 시각에 투어 시간 {total}을 더한 값입니다.', + 'tours.dayTime.formNoStart': '시작 시각을 입력하면 투어 시간 {total}으로 종료 시각을 계산합니다.', }; export default tours; diff --git a/shared/src/i18n/nl/tours.ts b/shared/src/i18n/nl/tours.ts index ca08dd44c..d3057064b 100644 --- a/shared/src/i18n/nl/tours.ts +++ b/shared/src/i18n/nl/tours.ts @@ -1333,5 +1333,12 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Berekend uit afstand, stijging en daling volgens de regel van de wandelwegwijzers (DIN 33466), zonder pauzes.', 'tours.estimate.basisPace': 'Berekend uit de afstand bij het ingevoerde tempo.', + 'tours.dayTime.workedOut': 'Eindigt om {time}, berekend uit de start en de tourtijd van {total}', + 'tours.dayTime.workedOutNextDay': + 'Eindigt de volgende dag om {time}, berekend uit de start en de tourtijd van {total}', + 'tours.dayTime.overrun': 'Eindigt om {end}, nadat {name} om {time} begint', + 'tours.dayTime.nextItem': 'het volgende onderdeel', + 'tours.dayTime.formHint': 'Leeg gelaten wordt het einde berekend: {time}, de start plus de tourtijd van {total}.', + 'tours.dayTime.formNoStart': 'Met een starttijd wordt het einde berekend uit de tourtijd van {total}.', }; export default tours; diff --git a/shared/src/i18n/pl/tours.ts b/shared/src/i18n/pl/tours.ts index 5816666ff..616b6a801 100644 --- a/shared/src/i18n/pl/tours.ts +++ b/shared/src/i18n/pl/tours.ts @@ -1366,5 +1366,11 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Wyliczony z dystansu, podejść i zejść według reguły drogowskazów turystycznych (DIN 33466), bez przerw.', 'tours.estimate.basisPace': 'Wyliczony z dystansu przy podanym tempie.', + 'tours.dayTime.workedOut': 'Kończy się o {time}, wyliczone ze startu i czasu trasy {total}', + 'tours.dayTime.workedOutNextDay': 'Kończy się następnego dnia o {time}, wyliczone ze startu i czasu trasy {total}', + 'tours.dayTime.overrun': 'Kończy się o {end}, po rozpoczęciu {name} o {time}', + 'tours.dayTime.nextItem': 'następny punkt', + 'tours.dayTime.formHint': 'Puste pole: koniec zostanie wyliczony, {time}, czyli start plus czas trasy {total}.', + 'tours.dayTime.formNoStart': 'Po podaniu startu koniec zostanie wyliczony z czasu trasy {total}.', }; export default tours; diff --git a/shared/src/i18n/ru/tours.ts b/shared/src/i18n/ru/tours.ts index c701a7099..ad5d9915b 100644 --- a/shared/src/i18n/ru/tours.ts +++ b/shared/src/i18n/ru/tours.ts @@ -1372,5 +1372,12 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Рассчитано по расстоянию, набору и сбросу высоты по правилу туристических указателей (DIN 33466), без перерывов.', 'tours.estimate.basisPace': 'Рассчитано по расстоянию при введённом темпе.', + 'tours.dayTime.workedOut': 'Заканчивается в {time}, рассчитано по началу и времени тура {total}', + 'tours.dayTime.workedOutNextDay': + 'Заканчивается на следующий день в {time}, рассчитано по началу и времени тура {total}', + 'tours.dayTime.overrun': 'Заканчивается в {end}, после начала {name} в {time}', + 'tours.dayTime.nextItem': 'следующий пункт', + 'tours.dayTime.formHint': 'Если оставить пустым, конец рассчитывается: {time}, начало плюс время тура {total}.', + 'tours.dayTime.formNoStart': 'Со временем начала конец рассчитывается по времени тура {total}.', }; export default tours; diff --git a/shared/src/i18n/sk/tours.ts b/shared/src/i18n/sk/tours.ts index 22ed453a1..7f454ddf9 100644 --- a/shared/src/i18n/sk/tours.ts +++ b/shared/src/i18n/sk/tours.ts @@ -1319,5 +1319,11 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Vypočítané zo vzdialenosti, stúpania a klesania podľa pravidla turistických smerovníkov (DIN 33466), bez prestávok.', 'tours.estimate.basisPace': 'Vypočítané zo vzdialenosti pri zadanom tempe.', + 'tours.dayTime.workedOut': 'Končí o {time}, vypočítané zo začiatku a času túry {total}', + 'tours.dayTime.workedOutNextDay': 'Končí na druhý deň o {time}, vypočítané zo začiatku a času túry {total}', + 'tours.dayTime.overrun': 'Končí o {end}, až po začiatku {name} o {time}', + 'tours.dayTime.nextItem': 'ďalšia položka', + 'tours.dayTime.formHint': 'Ak zostane prázdny, koniec sa vypočíta: {time}, začiatok plus čas túry {total}.', + 'tours.dayTime.formNoStart': 'So začiatkom sa koniec vypočíta z času túry {total}.', }; export default tours; diff --git a/shared/src/i18n/sv/tours.ts b/shared/src/i18n/sv/tours.ts index 2acfa6aaf..a4ad4fe14 100644 --- a/shared/src/i18n/sv/tours.ts +++ b/shared/src/i18n/sv/tours.ts @@ -1302,5 +1302,11 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Beräknad från sträcka, stigning och nedstigning enligt vandringsskyltarnas regel (DIN 33466), utan pauser.', 'tours.estimate.basisPace': 'Beräknad från sträckan i angivet tempo.', + 'tours.dayTime.workedOut': 'Slutar {time}, beräknat från starten och turens tid på {total}', + 'tours.dayTime.workedOutNextDay': 'Slutar nästa dag {time}, beräknat från starten och turens tid på {total}', + 'tours.dayTime.overrun': 'Slutar {end}, efter att {name} börjar {time}', + 'tours.dayTime.nextItem': 'nästa punkt', + 'tours.dayTime.formHint': 'Lämnas tomt beräknas slutet: {time}, starten plus turens tid på {total}.', + 'tours.dayTime.formNoStart': 'Med en starttid beräknas slutet från turens tid på {total}.', }; export default tours; diff --git a/shared/src/i18n/th/tours.ts b/shared/src/i18n/th/tours.ts index 736f0fcde..f2b34d114 100644 --- a/shared/src/i18n/th/tours.ts +++ b/shared/src/i18n/th/tours.ts @@ -1246,5 +1246,11 @@ const tours: TranslationStrings = { 'tours.estimate.noHeights': 'เส้นทางไม่มีข้อมูลความสูง จึงประมาณเวลาไม่ได้', 'tours.estimate.basisDin': 'คำนวณจากระยะทาง ระยะขึ้นและลงตามกฎป้ายบอกทางเดินป่า (DIN 33466) ไม่รวมเวลาพัก', 'tours.estimate.basisPace': 'คำนวณจากระยะทางตามเพซที่กรอกไว้', + 'tours.dayTime.workedOut': 'สิ้นสุดเวลา {time} คำนวณจากเวลาเริ่มและเวลาทัวร์ {total}', + 'tours.dayTime.workedOutNextDay': 'สิ้นสุดวันถัดไปเวลา {time} คำนวณจากเวลาเริ่มและเวลาทัวร์ {total}', + 'tours.dayTime.overrun': 'สิ้นสุดเวลา {end} หลังจาก {name} เริ่มเวลา {time}', + 'tours.dayTime.nextItem': 'รายการถัดไป', + 'tours.dayTime.formHint': 'หากเว้นว่างไว้ ระบบจะคำนวณเวลาสิ้นสุด: {time} คือเวลาเริ่มบวกเวลาทัวร์ {total}', + 'tours.dayTime.formNoStart': 'เมื่อมีเวลาเริ่ม ระบบจะคำนวณเวลาสิ้นสุดจากเวลาทัวร์ {total}', }; export default tours; diff --git a/shared/src/i18n/tours-locales.spec.ts b/shared/src/i18n/tours-locales.spec.ts index 6ac0e97d0..4ce8227f6 100644 --- a/shared/src/i18n/tours-locales.spec.ts +++ b/shared/src/i18n/tours-locales.spec.ts @@ -20,7 +20,7 @@ const toursModules = import.meta.glob<{ default: TranslationStrings }>('./*/tour const TOUR_DOMAINS: { file: string; generalKeyCount: number; modules: DomainModules }[] = [ { file: 'tours', - generalKeyCount: 1183, + generalKeyCount: 1189, modules: toursModules, }, { diff --git a/shared/src/i18n/tr/tours.ts b/shared/src/i18n/tr/tours.ts index 72fc35315..1c1cbb125 100644 --- a/shared/src/i18n/tr/tours.ts +++ b/shared/src/i18n/tr/tours.ts @@ -1309,5 +1309,11 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Mesafe, tırmanış ve inişten yürüyüş tabelası kuralına (DIN 33466) göre hesaplandı, molalar hariç.', 'tours.estimate.basisPace': 'Mesafeden, girilen tempoyla hesaplandı.', + 'tours.dayTime.workedOut': '{time} saatinde biter, başlangıç ve {total} tur süresinden hesaplandı', + 'tours.dayTime.workedOutNextDay': 'Ertesi gün {time} saatinde biter, başlangıç ve {total} tur süresinden hesaplandı', + 'tours.dayTime.overrun': '{end} saatinde biter, {name} {time} saatinde başladıktan sonra', + 'tours.dayTime.nextItem': 'sonraki öğe', + 'tours.dayTime.formHint': 'Boş bırakılırsa bitiş hesaplanır: {time}, başlangıç artı {total} tur süresi.', + 'tours.dayTime.formNoStart': 'Bir başlangıç saatiyle bitiş, {total} tur süresinden hesaplanır.', }; export default tours; diff --git a/shared/src/i18n/uk/tours.ts b/shared/src/i18n/uk/tours.ts index 624c43861..358cf7469 100644 --- a/shared/src/i18n/uk/tours.ts +++ b/shared/src/i18n/uk/tours.ts @@ -1358,5 +1358,12 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Розраховано за відстанню, набором і скиданням висоти за правилом туристичних вказівників (DIN 33466), без перерв.', 'tours.estimate.basisPace': 'Розраховано за відстанню при введеному темпі.', + 'tours.dayTime.workedOut': 'Закінчується о {time}, розраховано за початком і часом туру {total}', + 'tours.dayTime.workedOutNextDay': + 'Закінчується наступного дня о {time}, розраховано за початком і часом туру {total}', + 'tours.dayTime.overrun': 'Закінчується о {end}, після початку {name} о {time}', + 'tours.dayTime.nextItem': 'наступний пункт', + 'tours.dayTime.formHint': 'Якщо залишити порожнім, кінець розраховується: {time}, початок плюс час туру {total}.', + 'tours.dayTime.formNoStart': 'З часом початку кінець розраховується за часом туру {total}.', }; export default tours; diff --git a/shared/src/i18n/vi/tours.ts b/shared/src/i18n/vi/tours.ts index 6f051f920..950f62595 100644 --- a/shared/src/i18n/vi/tours.ts +++ b/shared/src/i18n/vi/tours.ts @@ -1291,5 +1291,11 @@ const tours: TranslationStrings = { 'tours.estimate.basisDin': 'Tính từ quãng đường, độ cao lên và xuống theo quy tắc biển chỉ dẫn leo núi (DIN 33466), không tính nghỉ.', 'tours.estimate.basisPace': 'Tính từ quãng đường theo tốc độ đã nhập.', + 'tours.dayTime.workedOut': 'Kết thúc lúc {time}, tính từ giờ bắt đầu và thời gian tour {total}', + 'tours.dayTime.workedOutNextDay': 'Kết thúc lúc {time} ngày hôm sau, tính từ giờ bắt đầu và thời gian tour {total}', + 'tours.dayTime.overrun': 'Kết thúc lúc {end}, sau khi {name} bắt đầu lúc {time}', + 'tours.dayTime.nextItem': 'mục tiếp theo', + 'tours.dayTime.formHint': 'Để trống thì giờ kết thúc được tính: {time}, giờ bắt đầu cộng thời gian tour {total}.', + 'tours.dayTime.formNoStart': 'Khi có giờ bắt đầu, giờ kết thúc được tính từ thời gian tour {total}.', }; export default tours; diff --git a/shared/src/i18n/zh-TW/tours.ts b/shared/src/i18n/zh-TW/tours.ts index 039448b33..9d1c3770f 100644 --- a/shared/src/i18n/zh-TW/tours.ts +++ b/shared/src/i18n/zh-TW/tours.ts @@ -1209,5 +1209,11 @@ const tours: TranslationStrings = { 'tours.estimate.noHeights': '軌跡沒有海拔資料,無法估算時間。', 'tours.estimate.basisDin': '依健行路標規則(DIN 33466)由距離、爬升與下降計算,不含休息。', 'tours.estimate.basisPace': '依距離與輸入的配速計算。', + 'tours.dayTime.workedOut': '{time} 結束,依開始時間與行程時間 {total} 推算', + 'tours.dayTime.workedOutNextDay': '隔天 {time} 結束,依開始時間與行程時間 {total} 推算', + 'tours.dayTime.overrun': '{end} 結束,晚於 {name} 的開始時間 {time}', + 'tours.dayTime.nextItem': '下一項', + 'tours.dayTime.formHint': '留空時會推算結束時間:{time},即開始時間加上行程時間 {total}。', + 'tours.dayTime.formNoStart': '填入開始時間後,會依行程時間 {total} 推算結束時間。', }; export default tours; diff --git a/shared/src/i18n/zh/tours.ts b/shared/src/i18n/zh/tours.ts index e04470bb6..a89417981 100644 --- a/shared/src/i18n/zh/tours.ts +++ b/shared/src/i18n/zh/tours.ts @@ -1210,5 +1210,11 @@ const tours: TranslationStrings = { 'tours.estimate.noHeights': '轨迹没有海拔数据,无法估算用时。', 'tours.estimate.basisDin': '按徒步路标规则(DIN 33466)根据距离、爬升和下降计算,不含休息。', 'tours.estimate.basisPace': '按距离和输入的配速计算。', + 'tours.dayTime.workedOut': '{time} 结束,根据开始时间和行程用时 {total} 推算', + 'tours.dayTime.workedOutNextDay': '次日 {time} 结束,根据开始时间和行程用时 {total} 推算', + 'tours.dayTime.overrun': '{end} 结束,晚于 {name} 的开始时间 {time}', + 'tours.dayTime.nextItem': '下一项', + 'tours.dayTime.formHint': '留空时会推算结束时间:{time},即开始时间加上行程用时 {total}。', + 'tours.dayTime.formNoStart': '填写开始时间后,会根据行程用时 {total} 推算结束时间。', }; export default tours;