mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-20 05:56:53 +00:00
feat(tours): plan a city walk with its stops, stays, importance and protection (CW-01, CW-02, CW-10)
City walk is a type of the planner: routed on foot without a hiking limit, on the standard map. Each stop is edited in its own dialog, its name, its stay (empty is not known, 0 a point passed through), its importance and whether a proposed change must leave it; none of it plans the route again. The walk's time is walking plus the stays, at least that much while a stay is unknown, with no breaks on top.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Utensils, Coffee, Wine, BedDouble, Camera, Landmark, Trees, Ticket, Fuel, Zap, ParkingSquare, Tent, Binoculars, Mountain, Warehouse, Droplet, Toilet, Sandwich, Anchor, Sailboat, Wrench, type LucideIcon } from 'lucide-react'
|
||||
import { Utensils, Coffee, Wine, BedDouble, Camera, Landmark, Trees, Ticket, Fuel, Zap, ParkingSquare, Tent, Binoculars, Mountain, Warehouse, Droplet, Toilet, Sandwich, Anchor, Sailboat, Wrench, Store, type LucideIcon } from 'lucide-react'
|
||||
import type { TourPoiCategory } from '@trek/shared'
|
||||
import { parsePluginPoiCategoryKey, type PluginPoiDetail } from '@trek/shared'
|
||||
// The road-trip kinds take their colour from the one place that defines it, so the
|
||||
@@ -62,6 +62,12 @@ export const TOUR_POI_LOOKS: Record<TourPoiCategory, PoiCategory> = {
|
||||
slipway: { key: 'slipway', labelKey: 'tours.poi.cat.slipway', Icon: Anchor, color: coreColor('museum') },
|
||||
boat_rental: { key: 'boat_rental', labelKey: 'tours.poi.cat.boat_rental', Icon: Sailboat, color: coreColor('cafe') },
|
||||
bike_repair: { key: 'bike_repair', labelKey: 'tours.poi.cat.bike_repair', Icon: Wrench, color: coreColor('activity') },
|
||||
// CW-05: a city walk's own, each in the colour of the explore category it comes from.
|
||||
museum: { key: 'museum', labelKey: 'tours.poi.cat.museum', Icon: Landmark, color: coreColor('museum') },
|
||||
park: { key: 'park', labelKey: 'tours.poi.cat.park', Icon: Trees, color: coreColor('nature') },
|
||||
cafe: { key: 'cafe', labelKey: 'tours.poi.cat.cafe', Icon: Coffee, color: coreColor('cafe') },
|
||||
restaurant: { key: 'restaurant', labelKey: 'tours.poi.cat.restaurant', Icon: Utensils, color: coreColor('restaurant') },
|
||||
market: { key: 'market', labelKey: 'tours.poi.cat.market', Icon: Store, color: coreColor('shopping') },
|
||||
}
|
||||
|
||||
// A Map rather than an object, so a category named after an Object.prototype member
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
import type { StationImportance } from '@trek/shared';
|
||||
import { MapPin, ShieldCheck } from 'lucide-react';
|
||||
import { useId, useState } from 'react';
|
||||
import { useTranslation } from '../../../i18n';
|
||||
import ToggleSwitch from '../../Settings/ToggleSwitch';
|
||||
import { EditorField, INPUT, LABEL, Segmented } from '../../shared/dialogParts';
|
||||
import {
|
||||
DialogButton,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogShell,
|
||||
DialogTile,
|
||||
FooterSpacer,
|
||||
NEUTRAL_TINT,
|
||||
fs,
|
||||
} from '../../shared/DialogShell';
|
||||
import { parseStay, withStationFields } from './stationModel';
|
||||
import type { TourPlannerWaypoint } from './tourPlannerWaypoints';
|
||||
|
||||
type Importance = StationImportance | 'normal';
|
||||
const IMPORTANCES: readonly Importance[] = ['normal', 'optional', 'must'];
|
||||
|
||||
/**
|
||||
* CW-02, CW-03, CW-10: one station of a city walk, as a dialog: its name, how
|
||||
* long it is stayed at (empty is unknown, 0 a point passed through), how much
|
||||
* it matters and whether a proposed change must leave it. Saving is one step
|
||||
* of the history; nothing here plans the route again.
|
||||
*/
|
||||
export function StationDialog({
|
||||
point,
|
||||
fallbackName,
|
||||
onSave,
|
||||
onClose,
|
||||
}: {
|
||||
point: TourPlannerWaypoint;
|
||||
/** The name the row shows while the station has none of its own. */
|
||||
fallbackName?: string;
|
||||
onSave: (next: TourPlannerWaypoint) => void;
|
||||
onClose: () => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const labelId = useId();
|
||||
const nameId = useId();
|
||||
const stayId = useId();
|
||||
const [name, setName] = useState(point.name ?? '');
|
||||
const [stay, setStay] = useState(point.stayMinutes == null ? '' : String(point.stayMinutes));
|
||||
const [importance, setImportance] = useState<Importance>(point.importance ?? 'normal');
|
||||
const [protectedStation, setProtectedStation] = useState(point.protected === true);
|
||||
const stayMinutes = parseStay(stay);
|
||||
const stayInvalid = stayMinutes === undefined;
|
||||
|
||||
const save = () => {
|
||||
if (stayInvalid) return;
|
||||
onSave(
|
||||
withStationFields(point, {
|
||||
name,
|
||||
stayMinutes,
|
||||
importance: importance === 'normal' ? null : importance,
|
||||
protected: protectedStation,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<DialogShell
|
||||
onClose={onClose}
|
||||
labelledBy={labelId}
|
||||
width="narrow"
|
||||
onSubmit={save}
|
||||
header={
|
||||
<DialogHeader
|
||||
tile={
|
||||
<DialogTile>
|
||||
<MapPin size={16} strokeWidth={2} />
|
||||
</DialogTile>
|
||||
}
|
||||
tint={NEUTRAL_TINT}
|
||||
labelId={labelId}
|
||||
onClose={onClose}
|
||||
eyebrow={t('tours.walk.station.eyebrow')}
|
||||
title={name.trim() || fallbackName || t('tours.walk.station.unnamed')}
|
||||
/>
|
||||
}
|
||||
footer={
|
||||
<DialogFooter>
|
||||
<FooterSpacer />
|
||||
<DialogButton onClick={onClose}>{t('common.cancel')}</DialogButton>
|
||||
<DialogButton variant="primary" type="submit" disabled={stayInvalid} data-testid="station-save">
|
||||
{t('common.save')}
|
||||
</DialogButton>
|
||||
</DialogFooter>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-col gap-4" data-testid="station-dialog">
|
||||
<EditorField label={t('tours.walk.station.name')} htmlFor={nameId}>
|
||||
<input
|
||||
id={nameId}
|
||||
className={INPUT}
|
||||
value={name}
|
||||
maxLength={200}
|
||||
placeholder={fallbackName ?? t('tours.walk.station.namePlaceholder')}
|
||||
onChange={(event) => setName(event.target.value)}
|
||||
/>
|
||||
</EditorField>
|
||||
<EditorField
|
||||
label={t('tours.walk.station.stay')}
|
||||
htmlFor={stayId}
|
||||
hint={t('tours.walk.station.stayHint')}
|
||||
error={stayInvalid ? t('tours.walk.station.stayInvalid') : undefined}
|
||||
>
|
||||
<input
|
||||
id={stayId}
|
||||
className={INPUT}
|
||||
inputMode="numeric"
|
||||
value={stay}
|
||||
placeholder={t('tours.walk.station.stayUnknown')}
|
||||
onChange={(event) => setStay(event.target.value)}
|
||||
/>
|
||||
</EditorField>
|
||||
<div className="min-w-0">
|
||||
<span className={LABEL}>{t('tours.walk.station.importance')}</span>
|
||||
<Segmented<Importance>
|
||||
value={importance}
|
||||
onChange={setImportance}
|
||||
label={t('tours.walk.station.importance')}
|
||||
fill
|
||||
options={IMPORTANCES.map((value) => ({ value, label: t(`tours.walk.importance.${value}`) }))}
|
||||
/>
|
||||
<span className="mt-1.5 block text-content-faint" style={fs(11, 'body')}>
|
||||
{t(`tours.walk.importanceHint.${importance}`)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-2.5">
|
||||
<ShieldCheck size={15} strokeWidth={2} className="mt-0.5 flex-none text-content-faint" />
|
||||
<span className="flex min-w-0 flex-1 flex-col">
|
||||
<span className="font-semibold text-content" style={fs(12.5, 'body')}>
|
||||
{t('tours.walk.station.protected')}
|
||||
</span>
|
||||
<span className="leading-snug text-content-faint" style={fs(11, 'body')}>
|
||||
{t('tours.walk.station.protectedHint')}
|
||||
</span>
|
||||
</span>
|
||||
<ToggleSwitch
|
||||
on={protectedStation}
|
||||
onToggle={() => setProtectedStation((value) => !value)}
|
||||
label={t('tours.walk.station.protected')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</DialogShell>
|
||||
);
|
||||
}
|
||||
@@ -157,31 +157,34 @@ function TourTimeFields({ planner, locked }: TourFieldProps) {
|
||||
const manual = planner.plannedDurationMinutes != null;
|
||||
return (
|
||||
<div data-testid="tour-planner-time-grid" className="grid grid-cols-2 gap-3">
|
||||
<div className="min-w-0">
|
||||
<FieldLabel
|
||||
htmlFor="tour-planner-breaks"
|
||||
aside={
|
||||
<InfoDot
|
||||
label={t('tours.planner.breaksAdditionalInfoLabel')}
|
||||
description={t('tours.planner.breaksAdditionalInfo')}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{t('tours.planner.breaksShort')}
|
||||
</FieldLabel>
|
||||
<TourDurationInput
|
||||
id="tour-planner-breaks"
|
||||
label={t('tours.planner.breaksAdditional')}
|
||||
value={planner.breakAdditionalMinutes}
|
||||
invalid={planner.breakAdditionalInvalid}
|
||||
errorId="tour-planner-breaks-error"
|
||||
locked={locked}
|
||||
onCommit={planner.setBreakAdditionalMinutes}
|
||||
/>
|
||||
{planner.breakAdditionalInvalid && (
|
||||
<FieldError id="tour-planner-breaks-error">{t('tours.planner.timeValueInvalid')}</FieldError>
|
||||
)}
|
||||
</div>
|
||||
{/* CW-02: a city walk stops at its stations; their stays take the place of breaks. */}
|
||||
{planner.tourType !== 'walk' && (
|
||||
<div className="min-w-0">
|
||||
<FieldLabel
|
||||
htmlFor="tour-planner-breaks"
|
||||
aside={
|
||||
<InfoDot
|
||||
label={t('tours.planner.breaksAdditionalInfoLabel')}
|
||||
description={t('tours.planner.breaksAdditionalInfo')}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{t('tours.planner.breaksShort')}
|
||||
</FieldLabel>
|
||||
<TourDurationInput
|
||||
id="tour-planner-breaks"
|
||||
label={t('tours.planner.breaksAdditional')}
|
||||
value={planner.breakAdditionalMinutes}
|
||||
invalid={planner.breakAdditionalInvalid}
|
||||
errorId="tour-planner-breaks-error"
|
||||
locked={locked}
|
||||
onCommit={planner.setBreakAdditionalMinutes}
|
||||
/>
|
||||
{planner.breakAdditionalInvalid && (
|
||||
<FieldError id="tour-planner-breaks-error">{t('tours.planner.timeValueInvalid')}</FieldError>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="min-w-0">
|
||||
<FieldLabel
|
||||
htmlFor="tour-planner-planned-duration"
|
||||
|
||||
@@ -612,6 +612,7 @@ const ESTIMATE_KEYS = {
|
||||
hike: { labelKey: 'tours.planner.walkingEstimated', shortKey: 'tours.planner.walkingEstimatedShort', infoLabelKey: 'tours.planner.walkingEstimatedInfoLabel', infoKey: 'tours.planner.walkingEstimatedInfo' },
|
||||
bike: { labelKey: 'tours.bike.timeEstimated', shortKey: 'tours.bike.timeEstimatedShort', infoLabelKey: 'tours.bike.timeEstimatedInfoLabel', infoKey: 'tours.bike.timeEstimatedInfo' },
|
||||
kayak: { labelKey: 'tours.paddle.timeEstimated', shortKey: 'tours.paddle.timeEstimatedShort', infoLabelKey: 'tours.paddle.timeEstimatedInfoLabel', infoKey: 'tours.paddle.timeEstimatedInfo' },
|
||||
walk: { labelKey: 'tours.walk.timeEstimated', shortKey: 'tours.walk.timeEstimatedShort', infoLabelKey: 'tours.walk.timeEstimatedInfoLabel', infoKey: 'tours.walk.timeEstimatedInfo' },
|
||||
} as const
|
||||
|
||||
/**
|
||||
@@ -645,6 +646,7 @@ function UnreachableNotice({ planner }: { planner: TourPlannerController }) {
|
||||
/** The time facts of the overview: the estimate (walking, riding or paddling), the breaks and the planned total. */
|
||||
function plannerTimeFields(planner: TourPlannerController, t: Translate) {
|
||||
const keys = ESTIMATE_KEYS[planner.tourType]
|
||||
const stays = planner.stationStays
|
||||
return [
|
||||
{
|
||||
label: t(keys.labelKey),
|
||||
@@ -654,13 +656,25 @@ function plannerTimeFields(planner: TourPlannerController, t: Translate) {
|
||||
? t('tours.planner.walkingTimeUnknown')
|
||||
: formatPlannedTourDuration(planner.walkingDurationMinutes),
|
||||
},
|
||||
{
|
||||
label: t('tours.planner.breaksShort'),
|
||||
value: planner.breakAdditionalMinutes == null ? '—' : formatPlannedTourDuration(planner.breakAdditionalMinutes),
|
||||
},
|
||||
stays
|
||||
? {
|
||||
// CW-02: a city walk's stays in place of breaks, the unknown ones named, never counted as nothing.
|
||||
label: t('tours.walk.stays'),
|
||||
value: stays.unknownStays > 0
|
||||
? t('tours.walk.totalAtLeast', { time: formatPlannedTourDuration(stays.stayMinutes) })
|
||||
: formatPlannedTourDuration(stays.stayMinutes),
|
||||
}
|
||||
: {
|
||||
label: t('tours.planner.breaksShort'),
|
||||
value: planner.breakAdditionalMinutes == null ? '—' : formatPlannedTourDuration(planner.breakAdditionalMinutes),
|
||||
},
|
||||
{
|
||||
label: `${t('tours.planner.plannedShort')}${planner.plannedDurationMinutes != null ? ` (${t('tours.planner.plannedTotalManual')})` : ''}`,
|
||||
value: planner.plannedTotalMinutes == null ? t('tours.planner.walkingTimeUnknown') : formatPlannedTourDuration(planner.plannedTotalMinutes),
|
||||
value: planner.plannedTotalMinutes == null
|
||||
? t('tours.planner.walkingTimeUnknown')
|
||||
: stays?.partial && planner.plannedDurationMinutes == null
|
||||
? t('tours.walk.totalAtLeast', { time: formatPlannedTourDuration(planner.plannedTotalMinutes) })
|
||||
: formatPlannedTourDuration(planner.plannedTotalMinutes),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
Navigation,
|
||||
RefreshCw,
|
||||
Repeat,
|
||||
SquarePen,
|
||||
Spline,
|
||||
Trash2,
|
||||
Unlink,
|
||||
@@ -46,6 +47,8 @@ import { usePaddleRegionLoad } from '../paddle/usePaddleRegionLoad';
|
||||
import { usePaddleWaypointActions } from '../paddle/usePaddleWaypointActions';
|
||||
import { usePortageRouting, usePortageWay } from '../paddle/usePortageRouting';
|
||||
import { RailCard } from '../tourParts';
|
||||
import { StationDialog } from './StationDialog';
|
||||
import { StationPills } from './stationParts';
|
||||
import { paddlePlanPoints, paddleRolesById } from './paddlePlanOf';
|
||||
import type { PaddleLegFailure } from './paddleRouting';
|
||||
import { lineLengthM } from './tourFixedLegs';
|
||||
@@ -297,6 +300,7 @@ function WaypointRowLabel({
|
||||
loopEnd,
|
||||
paddleRole,
|
||||
linked = false,
|
||||
station = false,
|
||||
}: {
|
||||
point: TourPlannerController['waypoints'][number];
|
||||
placeName: string | undefined;
|
||||
@@ -305,10 +309,12 @@ function WaypointRowLabel({
|
||||
paddleRole?: PaddleRole | null;
|
||||
/** PR1-10: the point stands for this place of the trip, named after it. */
|
||||
linked?: boolean;
|
||||
/** CW-01: a city walk's station, which shows its stay, importance and protection. */
|
||||
station?: boolean;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const coordinates = `${point.lat.toFixed(5)}, ${point.lng.toFixed(5)}`;
|
||||
const name = loopEnd ? t('tours.planner.loopEnd') : placeName;
|
||||
const name = loopEnd ? t('tours.planner.loopEnd') : (point.name ?? placeName);
|
||||
return (
|
||||
<>
|
||||
<span className="flex w-full min-w-0 items-center gap-1.5">
|
||||
@@ -332,6 +338,7 @@ function WaypointRowLabel({
|
||||
)}
|
||||
{point.auto && <AutoPointPill />}
|
||||
</span>
|
||||
{station && !loopEnd && <StationPills point={point} />}
|
||||
{linked && !loopEnd ? (
|
||||
// A stop standing for a place of the trip says so where the coordinates would be (PR1-10).
|
||||
<Tooltip label={t('tours.placePicker.linkedHint')}>
|
||||
@@ -451,6 +458,7 @@ function WaypointRowActions({
|
||||
selected,
|
||||
isSaving,
|
||||
onUnlink,
|
||||
stationName,
|
||||
}: {
|
||||
planner: TourPlannerController;
|
||||
point: WaypointPoint;
|
||||
@@ -460,11 +468,21 @@ function WaypointRowActions({
|
||||
isSaving: boolean;
|
||||
/** PR1-10: given for a point that stands for a place; the place itself stays. */
|
||||
onUnlink?: () => void;
|
||||
/** CW-01: the name the row shows, for a station without one of its own. */
|
||||
stationName?: string;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const menu = useContextMenu();
|
||||
const paddle = usePaddleWaypointActions(planner);
|
||||
const [stationOpen, setStationOpen] = useState(false);
|
||||
const station = planner.tourType === 'walk' && !point.shaping;
|
||||
const items: MenuItems = [
|
||||
...(station
|
||||
? [
|
||||
{ label: t('tours.walk.station.edit'), icon: SquarePen, onClick: () => setStationOpen(true) },
|
||||
{ divider: true } as const,
|
||||
]
|
||||
: []),
|
||||
{
|
||||
label: t('tours.planner.moveUp'),
|
||||
icon: ArrowUp,
|
||||
@@ -505,6 +523,17 @@ function WaypointRowActions({
|
||||
<Trash2 size={13} strokeWidth={2} />
|
||||
</WaypointAction>
|
||||
<ContextMenu menu={menu.menu} onClose={menu.close} />
|
||||
{stationOpen && (
|
||||
<StationDialog
|
||||
point={point}
|
||||
fallbackName={stationName}
|
||||
onClose={() => setStationOpen(false)}
|
||||
onSave={(next) => {
|
||||
planner.editWaypoints((current) => current.map((item) => (item.id === next.id ? next : item)));
|
||||
setStationOpen(false);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -927,6 +956,7 @@ export default function TourWaypointList({
|
||||
loopEnd={loopEnd}
|
||||
paddleRole={paddleRoleOf(point.id)}
|
||||
linked={!!linkedPlace}
|
||||
station={planner.tourType === 'walk' && !point.shaping}
|
||||
/>
|
||||
</button>
|
||||
{canEdit && (
|
||||
@@ -938,6 +968,7 @@ export default function TourWaypointList({
|
||||
selected={selected}
|
||||
isSaving={isSaving}
|
||||
onUnlink={point.linkedPlaceId ? () => tripPlaces.unlink(point.id) : undefined}
|
||||
stationName={linkedPlace?.name ?? placeNames[point.id]}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import type { TourPlannerWaypoint } from './tourPlannerWaypoints';
|
||||
|
||||
/**
|
||||
* CW-02: a city walk's time, walking and staying kept apart. A stay nobody
|
||||
* entered is unknown, never nothing: the total then counts only what is
|
||||
* known and says it is at least that much. A point passed through is a stay
|
||||
* of 0, entered on purpose.
|
||||
*/
|
||||
export interface WalkTimes {
|
||||
walkingMinutes: number | null;
|
||||
/** The stays entered, summed. */
|
||||
stayMinutes: number;
|
||||
/** Stations whose stay nobody entered. */
|
||||
unknownStays: number;
|
||||
/** Walking and the known stays; null while the walking time is unknown. */
|
||||
totalMinutes: number | null;
|
||||
/** The total leaves out a stay or the walking time that is not known. */
|
||||
partial: boolean;
|
||||
}
|
||||
|
||||
/** The stations of a city walk: its points that are no shaping points. */
|
||||
export function stationsOf(points: readonly TourPlannerWaypoint[]): TourPlannerWaypoint[] {
|
||||
return points.filter((point) => !point.shaping);
|
||||
}
|
||||
|
||||
export function walkTimes(points: readonly TourPlannerWaypoint[], walkingMinutes: number | null): WalkTimes {
|
||||
const stations = stationsOf(points);
|
||||
const stayMinutes = stations.reduce((sum, station) => sum + (station.stayMinutes ?? 0), 0);
|
||||
const unknownStays = stations.filter((station) => station.stayMinutes == null).length;
|
||||
return {
|
||||
walkingMinutes,
|
||||
stayMinutes,
|
||||
unknownStays,
|
||||
totalMinutes: walkingMinutes === null ? null : walkingMinutes + stayMinutes,
|
||||
partial: unknownStays > 0,
|
||||
};
|
||||
}
|
||||
|
||||
/** What the station dialog edits; the rest of the point stays as it is. */
|
||||
export type StationFields = Pick<TourPlannerWaypoint, 'name' | 'stayMinutes' | 'importance' | 'protected'>;
|
||||
|
||||
/** The point with the fields as edited, each one left out where it is empty. */
|
||||
export function withStationFields(point: TourPlannerWaypoint, fields: StationFields): TourPlannerWaypoint {
|
||||
const { name: _name, stayMinutes: _stay, importance: _importance, protected: _protected, ...rest } = point;
|
||||
const name = fields.name?.trim();
|
||||
return {
|
||||
...rest,
|
||||
...(name ? { name } : {}),
|
||||
...(fields.stayMinutes != null ? { stayMinutes: fields.stayMinutes } : {}),
|
||||
...(fields.importance ? { importance: fields.importance } : {}),
|
||||
...(fields.protected ? { protected: true } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
/** A stay as typed: empty is unknown, a whole number from 0 to a day is minutes, anything else is not taken. */
|
||||
export function parseStay(text: string): number | null | undefined {
|
||||
const trimmed = text.trim();
|
||||
if (trimmed === '') return null;
|
||||
if (!/^\d{1,4}$/.test(trimmed)) return undefined;
|
||||
const minutes = Number(trimmed);
|
||||
return minutes <= 24 * 60 ? minutes : undefined;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { Clock, ShieldCheck } from 'lucide-react';
|
||||
import { useTranslation } from '../../../i18n';
|
||||
import { SoftPill } from '../../Planner/planParts';
|
||||
import { Tooltip } from '../../shared/Tooltip';
|
||||
import { formatPlannedTourDuration } from '../tourPresentation';
|
||||
import type { TourPlannerWaypoint } from './tourPlannerWaypoints';
|
||||
|
||||
/**
|
||||
* CW-02, CW-03, CW-10: what a city walk's station row says besides its name:
|
||||
* the stay (or that it is not known), an importance other than normal, and a
|
||||
* protection, each a quiet pill.
|
||||
*/
|
||||
export function StationPills({ point }: { point: TourPlannerWaypoint }) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<span className="flex flex-wrap items-center gap-1" data-testid="station-pills">
|
||||
<SoftPill icon={<Clock size={10} strokeWidth={2.2} aria-hidden="true" />}>
|
||||
{point.stayMinutes == null
|
||||
? t('tours.walk.station.stayUnknownShort')
|
||||
: point.stayMinutes === 0
|
||||
? t('tours.walk.station.passThrough')
|
||||
: formatPlannedTourDuration(point.stayMinutes)}
|
||||
</SoftPill>
|
||||
{point.importance && (
|
||||
<SoftPill tone={point.importance === 'must' ? 'warning' : undefined}>
|
||||
{t(`tours.walk.importance.${point.importance}`)}
|
||||
</SoftPill>
|
||||
)}
|
||||
{point.protected && (
|
||||
<Tooltip label={t('tours.walk.station.protectedHint')}>
|
||||
<span className="inline-flex" aria-label={t('tours.walk.station.protected')}>
|
||||
<SoftPill icon={<ShieldCheck size={10} strokeWidth={2.2} aria-hidden="true" />} />
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -52,6 +52,8 @@ export interface TourPlannerFactsInput {
|
||||
/** A paddle tour's estimate on the water; null for a hike. */
|
||||
paddleEstimate: { waterMinutes: number | null; estimateMinutes: number | null } | null;
|
||||
routeAnalysis: RouteGeometryAnalysis | null;
|
||||
/** CW-02: a city walk's stays, summed as far as they are known; null for any other type, which takes its breaks. */
|
||||
stationStayMinutes?: number | null;
|
||||
/** The router's own time, seconds: a bike tour's riding time; stands in for a hike until the heights are in. */
|
||||
durationSeconds: number | null;
|
||||
}
|
||||
@@ -69,7 +71,8 @@ function invalidMinutes(value: number | null): boolean {
|
||||
function movingMinutes(input: TourPlannerFactsInput, routerMinutes: number | null): number | null {
|
||||
const { paddleEstimate, routeAnalysis } = input;
|
||||
if (paddleEstimate) return paddleEstimate.waterMinutes === null ? null : paddleEstimate.estimateMinutes;
|
||||
if (input.tourType === 'bike') return routerMinutes;
|
||||
// A bike tour is timed by the router for its profile, a city walk by the router on foot.
|
||||
if (input.tourType === 'bike' || input.tourType === 'walk') return routerMinutes;
|
||||
return routeAnalysis?.gain != null && routeAnalysis.loss != null
|
||||
? hikingTimeMinutes(routeAnalysis.distanceKm, routeAnalysis.gain, routeAnalysis.loss)
|
||||
: routerMinutes;
|
||||
@@ -92,16 +95,17 @@ function typeFieldsOf(input: TourPlannerFactsInput) {
|
||||
hiking_preferences: null,
|
||||
};
|
||||
}
|
||||
const isHike = input.tourType === 'hike';
|
||||
return {
|
||||
tour_type: input.tourType,
|
||||
max_hiking_difficulty: isBike ? null : input.maxHikingDifficulty,
|
||||
max_hiking_difficulty: isHike ? input.maxHikingDifficulty : null,
|
||||
bike_profile: isBike ? input.bikeProfile : null,
|
||||
boat_type: null,
|
||||
water_context: null,
|
||||
paddle_speed_kmh: null,
|
||||
portage_speed_kmh: null,
|
||||
paddle_lake_style: null,
|
||||
hiking_preferences: isBike ? null : input.hikingPreferences,
|
||||
hiking_preferences: isHike ? input.hikingPreferences : null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -114,8 +118,9 @@ export function tourPlannerFacts(input: TourPlannerFactsInput) {
|
||||
const { durationSeconds, breakAdditionalMinutes, plannedDurationMinutes } = input;
|
||||
const routerMinutes = durationSeconds === null ? null : Math.round(durationSeconds / 60);
|
||||
const walkingDurationMinutes = movingMinutes(input, routerMinutes);
|
||||
const automaticPlannedTotalMinutes =
|
||||
walkingDurationMinutes === null ? null : walkingDurationMinutes + (breakAdditionalMinutes ?? 0);
|
||||
// A city walk's stops are its stays; it has no breaks on top, so nothing counts twice.
|
||||
const onTop = input.tourType === 'walk' ? (input.stationStayMinutes ?? 0) : (breakAdditionalMinutes ?? 0);
|
||||
const automaticPlannedTotalMinutes = walkingDurationMinutes === null ? null : walkingDurationMinutes + onTop;
|
||||
const { boatType, waterContext } = input.paddle;
|
||||
return {
|
||||
isPaddle,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { PaddleLock, TourFixedLeg, TourWaypoint, TourWaypointRole } from '@trek/shared';
|
||||
import type { PaddleLock, PlannableTourType, StationImportance, TourFixedLeg, TourWaypoint, TourWaypointRole } from '@trek/shared';
|
||||
import type { AutoBase } from './paddleRouting';
|
||||
import { keepJoinedFixedLegs } from './tourFixedLegs';
|
||||
import { alignFreeLegs } from './tourRouteActions';
|
||||
@@ -21,6 +21,18 @@ export interface TourPlannerWaypoint {
|
||||
carryNext?: boolean;
|
||||
/** PR1-10: the place of the trip this point stands for, chosen on purpose; the point keeps its own spot. */
|
||||
linkedPlaceId?: number;
|
||||
/** CW-03: the point's saved key, the same across saves, which a city walk's visits hang on. */
|
||||
key?: string;
|
||||
/** The point's own name: a city walk's station, a place found along the route. */
|
||||
name?: string | null;
|
||||
/** CW-02: a station's stay; null not known, 0 a point passed through. */
|
||||
stayMinutes?: number | null;
|
||||
/** CW-03: how much a station matters; absent is normal. */
|
||||
importance?: StationImportance | null;
|
||||
/** CW-10: a station a proposed change must leave where it is. */
|
||||
protected?: boolean;
|
||||
/** CW-04: the station's opening hours as OpenStreetMap writes them. */
|
||||
openingHours?: string | null;
|
||||
}
|
||||
|
||||
/** A saved tour's waypoints as the editor holds them, each under a fresh id. */
|
||||
@@ -34,6 +46,12 @@ export function plannerWaypointsOf(saved: readonly TourWaypoint[], newId: () =>
|
||||
...(point.lock ? { lock: point.lock } : {}),
|
||||
...(point.shaping ? { shaping: true } : {}),
|
||||
...(point.linked_place_id ? { linkedPlaceId: point.linked_place_id } : {}),
|
||||
...(point.key ? { key: point.key } : {}),
|
||||
...(point.name ? { name: point.name } : {}),
|
||||
...(point.stay_minutes != null ? { stayMinutes: point.stay_minutes } : {}),
|
||||
...(point.importance ? { importance: point.importance } : {}),
|
||||
...(point.protected ? { protected: true } : {}),
|
||||
...(point.opening_hours ? { openingHours: point.opening_hours } : {}),
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -42,7 +60,9 @@ export function plannerWaypointsOf(saved: readonly TourWaypoint[], newId: () =>
|
||||
* keeps and nothing of the editor's own (ids, automatic marks, a portage
|
||||
* waiting for its next point).
|
||||
*/
|
||||
export function savedWaypointsOf(points: readonly TourPlannerWaypoint[]): TourWaypoint[] {
|
||||
export function savedWaypointsOf(points: readonly TourPlannerWaypoint[], tourType?: PlannableTourType): TourWaypoint[] {
|
||||
// A stay, an importance and a protection belong to a city walk's stations; another type sends none.
|
||||
const walk = tourType === 'walk';
|
||||
return points.map((point, sequence) => ({
|
||||
lat: point.lat,
|
||||
lng: point.lng,
|
||||
@@ -52,6 +72,12 @@ export function savedWaypointsOf(points: readonly TourPlannerWaypoint[]): TourWa
|
||||
...(point.lock ? { lock: point.lock } : {}),
|
||||
...(point.shaping ? { shaping: true } : {}),
|
||||
...(point.linkedPlaceId ? { linked_place_id: point.linkedPlaceId } : {}),
|
||||
...(point.key ? { key: point.key } : {}),
|
||||
...(point.name ? { name: point.name } : {}),
|
||||
...(walk && point.stayMinutes != null ? { stay_minutes: point.stayMinutes } : {}),
|
||||
...(walk && point.importance ? { importance: point.importance } : {}),
|
||||
...(walk && point.protected ? { protected: true } : {}),
|
||||
...(point.openingHours ? { opening_hours: point.openingHours } : {}),
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,18 @@ export async function routeWalkingTour(
|
||||
}, signal)
|
||||
}
|
||||
|
||||
/**
|
||||
* CW-01: a city walk, on foot between its stations. No hiking limit is sent,
|
||||
* so the router keeps to the ways it takes for walking anyway (T1), and no
|
||||
* route choice of a hike.
|
||||
*/
|
||||
export async function routeCityWalk(
|
||||
waypoints: LandWaypoint[],
|
||||
signal?: AbortSignal,
|
||||
): Promise<TourRouteResult | TourRouteUnreachable | null> {
|
||||
return routeOnLand(waypoints, 'walking', {}, signal)
|
||||
}
|
||||
|
||||
/** BIK-01: a bike tour, routed for its profile; a leg drawn by hand is kept as drawn. */
|
||||
export async function routeBikeTour(
|
||||
waypoints: LandWaypoint[],
|
||||
|
||||
@@ -5,6 +5,7 @@ import { tourRepo } from '../../../repo/tourRepo'
|
||||
import { randomId } from '../../../utils/randomId'
|
||||
import { analyzeRouteGeometry, type RouteProfileFocus } from '../../../utils/routeGeometry'
|
||||
import { closeLoop, isClosedLoop, reverseRoute, toggleFreeLeg, withPointAppended } from './tourRouteActions'
|
||||
import { walkTimes } from './stationModel'
|
||||
import { hasCompleteElevation, useTourRoute } from './useTourRoute'
|
||||
import { normalizePlannerWaypoints, plannerWaypointsOf, ridablePoints, sameWaypointSnapshot, savedWaypointsOf, unlinkedPoint, type TourPlannerWaypoint } from './tourPlannerWaypoints'
|
||||
import { openedTourFields, tourPlannerFacts } from './tourPlannerFacts'
|
||||
@@ -478,12 +479,14 @@ export function useTourPlanner({ tripId, active = true, onSaved, canEdit: editPe
|
||||
const routedLegLengths = paddleRoute && routeCurrent ? paddleRoute.legLengths : undefined
|
||||
const paddleEstimate = useMemo(() => isPaddle ? paddleEstimateOf(waypoints, { effectiveSpeedKmh, portageSpeedKmh }, paddleSpeedInvalid, routedLegLengths) : null,
|
||||
[effectiveSpeedKmh, isPaddle, paddleSpeedInvalid, portageSpeedKmh, routedLegLengths, waypoints])
|
||||
// CW-02: a city walk's stays, what of them is known.
|
||||
const stationStays = useMemo(() => (tourType === 'walk' ? walkTimes(waypoints, null) : null), [tourType, waypoints])
|
||||
const facts = useMemo(() => tourPlannerFacts({
|
||||
tourType, maxHikingDifficulty, hikingPreferences, bikeProfile, website, plannedDurationMinutes, breakAdditionalMinutes,
|
||||
paddle: { boatType, waterContext, speedKmh, portageSpeedKmh, lakeStyle },
|
||||
paddleSpeedInvalid, paddleEstimate, routeAnalysis, durationSeconds,
|
||||
paddleSpeedInvalid, paddleEstimate, routeAnalysis, durationSeconds, stationStayMinutes: stationStays?.stayMinutes ?? null,
|
||||
}), [bikeProfile, boatType, breakAdditionalMinutes, durationSeconds, hikingPreferences, lakeStyle, maxHikingDifficulty, paddleEstimate, paddleSpeedInvalid,
|
||||
plannedDurationMinutes, portageSpeedKmh, routeAnalysis, speedKmh, tourType, waterContext, website])
|
||||
plannedDurationMinutes, portageSpeedKmh, routeAnalysis, speedKmh, stationStays, tourType, waterContext, website])
|
||||
const { websiteInvalid, plannedDurationInvalid, breakAdditionalInvalid, paddleIncomplete, walkingDurationMinutes,
|
||||
plannedTotalMinutes, plannedTotalInvalid, savedDurationSeconds, typeFields } = facts
|
||||
|
||||
@@ -774,7 +777,7 @@ export function useTourPlanner({ tripId, active = true, onSaved, canEdit: editPe
|
||||
website: parsedWebsiteOrNull(website),
|
||||
...typeFields,
|
||||
route_geometry: enrichedGeometry.map(point => [point[0], point[1], point[2]]),
|
||||
waypoints: savedWaypointsOf(waypoints),
|
||||
waypoints: savedWaypointsOf(waypoints, tourType),
|
||||
duration_seconds: savedDurationSeconds,
|
||||
planned_duration_minutes: plannedDurationMinutes,
|
||||
break_additional_minutes: breakAdditionalMinutes,
|
||||
@@ -834,7 +837,7 @@ export function useTourPlanner({ tripId, active = true, onSaved, canEdit: editPe
|
||||
description, setDescription, website, setWebsite, websiteInvalid,
|
||||
plannedDurationMinutes, setPlannedDurationMinutes, plannedDurationInvalid,
|
||||
breakAdditionalMinutes, setBreakAdditionalMinutes, breakAdditionalInvalid,
|
||||
walkingDurationMinutes, plannedTotalMinutes, plannedTotalInvalid,
|
||||
walkingDurationMinutes, plannedTotalMinutes, plannedTotalInvalid, stationStays,
|
||||
waypoints, selectedWaypointId, setSelectedWaypointId,
|
||||
addWaypoint, appendFixedLeg, setWaypointPosition, removeWaypoint, moveWaypoint, reorderWaypoint, editWaypoints: commitWaypoints,
|
||||
reverse, returnToStart, isLoop: isClosedLoop(waypoints), toggleWaypointFreeLeg, editPaddlePoints, amendWaypoints, paddleEstimate,
|
||||
|
||||
@@ -14,6 +14,7 @@ import { isTourRoute, type TourRouteUnreachable } from './tourRouteOutcome';
|
||||
import {
|
||||
enrichTourElevations,
|
||||
routeBikeTour,
|
||||
routeCityWalk,
|
||||
routeWalkingTour,
|
||||
type TourElevationPoint,
|
||||
type TourRoutePart,
|
||||
@@ -104,7 +105,9 @@ async function routeOnLand({ inputs, plannedKey, signal, stale, setPlanned, setU
|
||||
const routed =
|
||||
tourType === 'bike'
|
||||
? await routeBikeTour(waypoints, bikeProfile, signal)
|
||||
: await routeWalkingTour(waypoints, signal, maxHikingDifficulty, hikingPreferences);
|
||||
: tourType === 'walk'
|
||||
? await routeCityWalk(waypoints, signal)
|
||||
: await routeWalkingTour(waypoints, signal, maxHikingDifficulty, hikingPreferences);
|
||||
if (stale()) return;
|
||||
if (!isTourRoute(routed)) {
|
||||
setUnreachable(routed);
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { TourStationVisitsStatus } from '../../../src/db/entities/TourStationVisits.entity';
|
||||
import { TourWaypointsImportance } from '../../../src/db/entities/TourWaypoints.entity';
|
||||
import { STATION_IMPORTANCES, TOUR_VISIT_STATUSES } from '@trek/shared';
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
/**
|
||||
* CW-03: a station's importance and a visit's status are CHECK lists
|
||||
* (migration 045300) the entities carry as enums, and the contract holds its
|
||||
* own. A value one side knows and the other refuses would be a station the
|
||||
* planner can save and the database cannot store.
|
||||
*/
|
||||
describe('city walk columns match the contract', () => {
|
||||
it('knows the same importances as the station contract', () => {
|
||||
expect(Object.values(TourWaypointsImportance).sort()).toEqual([...STATION_IMPORTANCES].sort());
|
||||
});
|
||||
|
||||
it('knows the same visit statuses as the visit contract', () => {
|
||||
expect(Object.values(TourStationVisitsStatus).sort()).toEqual([...TOUR_VISIT_STATUSES].sort());
|
||||
});
|
||||
});
|
||||
@@ -467,6 +467,38 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'الدرج فقط حيث لا يوجد طريق بديل.',
|
||||
'tours.preferences.avoid_ferries': 'تجنّب العبّارات',
|
||||
'tours.preferences.avoid_ferriesHint': 'عبر البر حيث يوجد طريق بديل، حتى لو كان أطول.',
|
||||
'tours.planner.tourTypeHint.walk': 'سيرًا من محطة إلى محطة، دون حد للمشي الجبلي',
|
||||
'tours.poi.cat.museum': 'متاحف ومعارض',
|
||||
'tours.poi.cat.park': 'حدائق ومنتزهات',
|
||||
'tours.poi.cat.cafe': 'مقاهٍ',
|
||||
'tours.poi.cat.restaurant': 'مطاعم',
|
||||
'tours.poi.cat.market': 'أسواق',
|
||||
'tours.walk.station.eyebrow': 'محطة',
|
||||
'tours.walk.station.unnamed': 'محطة بلا اسم',
|
||||
'tours.walk.station.name': 'الاسم',
|
||||
'tours.walk.station.namePlaceholder': 'ما الموجود هنا',
|
||||
'tours.walk.station.stay': 'مدة البقاء بالدقائق',
|
||||
'tours.walk.station.stayHint': 'الفارغ يعني غير معروف بعد؛ 0 لنقطة تمر بها فقط.',
|
||||
'tours.walk.station.stayInvalid': 'أدخل دقائق كاملة، حتى يوم واحد.',
|
||||
'tours.walk.station.stayUnknown': 'غير معروف بعد',
|
||||
'tours.walk.station.stayUnknownShort': 'مدة غير معروفة',
|
||||
'tours.walk.station.passThrough': 'مرور فقط',
|
||||
'tours.walk.station.importance': 'الأهمية',
|
||||
'tours.walk.station.protected': 'محمية',
|
||||
'tours.walk.station.protectedHint': 'أي تعديل مقترح يُبقي هذه المحطة مكانها. لا يزال بإمكانك تعديلها بنفسك.',
|
||||
'tours.walk.station.edit': 'تعديل المحطة',
|
||||
'tours.walk.importance.normal': 'عادية',
|
||||
'tours.walk.importance.optional': 'اختيارية',
|
||||
'tours.walk.importance.must': 'لا بد من زيارتها',
|
||||
'tours.walk.importanceHint.normal': 'تُزار ضمن سير الجولة.',
|
||||
'tours.walk.importanceHint.optional': 'يمكن تجاوزها إذا ضاق الوقت.',
|
||||
'tours.walk.importanceHint.must': 'أي تعديل مقترح لاحقًا يُبقيها في الجولة.',
|
||||
'tours.walk.timeEstimated': 'وقت المشي التقديري',
|
||||
'tours.walk.timeEstimatedShort': 'المشي',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'كيف يُحسب وقت المشي',
|
||||
'tours.walk.timeEstimatedInfo': 'وقت المسار سيرًا بين المحطات، دون مدد البقاء.',
|
||||
'tours.walk.stays': 'مدد البقاء',
|
||||
'tours.walk.totalAtLeast': '{time} على الأقل',
|
||||
'tours.planner.tourType': 'نوع الجولة',
|
||||
'tours.paddle.boat': 'القارب',
|
||||
'tours.paddle.boat.kayak': 'كاياك',
|
||||
|
||||
@@ -461,6 +461,39 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Pilləkən yalnız dolama yol olmayan yerdə.',
|
||||
'tours.preferences.avoid_ferries': 'Bərələrdən qaç',
|
||||
'tours.preferences.avoid_ferriesHint': 'Dolama yol varsa, daha uzun olsa da quru ilə.',
|
||||
'tours.planner.tourTypeHint.walk': 'Dayanacaqdan dayanacağa piyada, yürüyüş həddi olmadan',
|
||||
'tours.poi.cat.museum': 'Muzeylər və qalereyalar',
|
||||
'tours.poi.cat.park': 'Parklar və bağlar',
|
||||
'tours.poi.cat.cafe': 'Kafelər',
|
||||
'tours.poi.cat.restaurant': 'Yemək yerləri',
|
||||
'tours.poi.cat.market': 'Bazarlar',
|
||||
'tours.walk.station.eyebrow': 'Dayanacaq',
|
||||
'tours.walk.station.unnamed': 'Adsız dayanacaq',
|
||||
'tours.walk.station.name': 'Ad',
|
||||
'tours.walk.station.namePlaceholder': 'Burada nə var',
|
||||
'tours.walk.station.stay': 'Qalma müddəti, dəqiqə',
|
||||
'tours.walk.station.stayHint': 'Boş hələ məlum deyil deməkdir; yalnız keçdiyin nöqtə üçün 0.',
|
||||
'tours.walk.station.stayInvalid': 'Tam dəqiqə daxil et, ən çox bir gün.',
|
||||
'tours.walk.station.stayUnknown': 'Hələ məlum deyil',
|
||||
'tours.walk.station.stayUnknownShort': 'Müddət bilinmir',
|
||||
'tours.walk.station.passThrough': 'Keçid',
|
||||
'tours.walk.station.importance': 'Əhəmiyyət',
|
||||
'tours.walk.station.protected': 'Qorunur',
|
||||
'tours.walk.station.protectedHint':
|
||||
'Təklif olunan dəyişiklik bu dayanacağı yerində saxlayır. Özün yenə də redaktə edə bilərsən.',
|
||||
'tours.walk.station.edit': 'Dayanacağı redaktə et',
|
||||
'tours.walk.importance.normal': 'Adi',
|
||||
'tours.walk.importance.optional': 'İstəyə bağlı',
|
||||
'tours.walk.importance.must': 'Mütləq baxılmalı',
|
||||
'tours.walk.importanceHint.normal': 'Gəzinti boyunca ziyarət olunur.',
|
||||
'tours.walk.importanceHint.optional': 'Vaxt az olanda buraxıla bilər.',
|
||||
'tours.walk.importanceHint.must': 'Sonradan təklif olunan dəyişiklik onu gəzintidə saxlayır.',
|
||||
'tours.walk.timeEstimated': 'Təxmini yürüş vaxtı',
|
||||
'tours.walk.timeEstimatedShort': 'Yürüş',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Yürüş vaxtı necə hesablanır',
|
||||
'tours.walk.timeEstimatedInfo': 'Dayanacaqlar arasında marşrutlaşdırıcının piyada vaxtı, qalma müddətləri olmadan.',
|
||||
'tours.walk.stays': 'Qalmalar',
|
||||
'tours.walk.totalAtLeast': 'ən azı {time}',
|
||||
'tours.planner.tourType': 'Tur növü',
|
||||
'tours.paddle.boat': 'Qayıq',
|
||||
'tours.paddle.boat.kayak': 'Kayak', // same-as-en
|
||||
|
||||
@@ -468,6 +468,38 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Escadas só onde não há caminho alternativo.',
|
||||
'tours.preferences.avoid_ferries': 'Evitar balsas',
|
||||
'tours.preferences.avoid_ferriesHint': 'Por terra onde houver caminho alternativo, mesmo mais longo.',
|
||||
'tours.planner.tourTypeHint.walk': 'A pé de parada em parada, sem limite de trilha',
|
||||
'tours.poi.cat.museum': 'Museus e galerias',
|
||||
'tours.poi.cat.park': 'Parques e jardins',
|
||||
'tours.poi.cat.cafe': 'Cafeterias',
|
||||
'tours.poi.cat.restaurant': 'Lugares para comer',
|
||||
'tours.poi.cat.market': 'Feiras',
|
||||
'tours.walk.station.eyebrow': 'Parada',
|
||||
'tours.walk.station.unnamed': 'Parada sem nome',
|
||||
'tours.walk.station.name': 'Nome',
|
||||
'tours.walk.station.namePlaceholder': 'O que há aqui',
|
||||
'tours.walk.station.stay': 'Permanência em minutos',
|
||||
'tours.walk.station.stayHint': 'Vazio significa ainda desconhecido; 0 para um ponto pelo qual você só passa.',
|
||||
'tours.walk.station.stayInvalid': 'Informe minutos inteiros, até um dia.',
|
||||
'tours.walk.station.stayUnknown': 'Ainda desconhecido',
|
||||
'tours.walk.station.stayUnknownShort': 'Permanência em aberto',
|
||||
'tours.walk.station.passThrough': 'Só de passagem',
|
||||
'tours.walk.station.importance': 'Importância',
|
||||
'tours.walk.station.protected': 'Protegida',
|
||||
'tours.walk.station.protectedHint': 'Uma alteração proposta mantém esta parada onde está. Você ainda pode editá-la.',
|
||||
'tours.walk.station.edit': 'Editar parada',
|
||||
'tours.walk.importance.normal': 'Comum',
|
||||
'tours.walk.importance.optional': 'Opcional',
|
||||
'tours.walk.importance.must': 'Imperdível',
|
||||
'tours.walk.importanceHint.normal': 'Visitada conforme o passeio segue.',
|
||||
'tours.walk.importanceHint.optional': 'Pode ficar de fora se faltar tempo.',
|
||||
'tours.walk.importanceHint.must': 'Uma alteração proposta depois a mantém no passeio.',
|
||||
'tours.walk.timeEstimated': 'Tempo de caminhada estimado',
|
||||
'tours.walk.timeEstimatedShort': 'Caminhada',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Como o tempo de caminhada é calculado',
|
||||
'tours.walk.timeEstimatedInfo': 'O tempo a pé do roteador entre as paradas, sem as permanências.',
|
||||
'tours.walk.stays': 'Permanências',
|
||||
'tours.walk.totalAtLeast': 'pelo menos {time}',
|
||||
'tours.planner.tourType': 'Tipo de passeio',
|
||||
'tours.paddle.boat': 'Embarcação',
|
||||
'tours.paddle.boat.kayak': 'Caiaque',
|
||||
|
||||
@@ -469,6 +469,38 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Escales només on no hi ha cap volta possible.',
|
||||
'tours.preferences.avoid_ferries': 'Evita transbordadors',
|
||||
'tours.preferences.avoid_ferriesHint': 'Per terra on hi hagi una volta, encara que sigui més llarga.',
|
||||
'tours.planner.tourTypeHint.walk': "A peu de parada en parada, sense límit d'excursionisme",
|
||||
'tours.poi.cat.museum': 'Museus i galeries',
|
||||
'tours.poi.cat.park': 'Parcs i jardins',
|
||||
'tours.poi.cat.cafe': 'Cafeteries',
|
||||
'tours.poi.cat.restaurant': 'Llocs per menjar',
|
||||
'tours.poi.cat.market': 'Mercats',
|
||||
'tours.walk.station.eyebrow': 'Parada',
|
||||
'tours.walk.station.unnamed': 'Parada sense nom',
|
||||
'tours.walk.station.name': 'Nom',
|
||||
'tours.walk.station.namePlaceholder': 'Què hi ha aquí',
|
||||
'tours.walk.station.stay': 'Estada en minuts',
|
||||
'tours.walk.station.stayHint': 'Buit vol dir encara desconegut; 0 per a un punt pel qual només passes.',
|
||||
'tours.walk.station.stayInvalid': 'Introdueix minuts sencers, fins a un dia.',
|
||||
'tours.walk.station.stayUnknown': 'Encara desconegut',
|
||||
'tours.walk.station.stayUnknownShort': 'Estada oberta',
|
||||
'tours.walk.station.passThrough': 'Només de pas',
|
||||
'tours.walk.station.importance': 'Importància',
|
||||
'tours.walk.station.protected': 'Protegida',
|
||||
'tours.walk.station.protectedHint': 'Un canvi proposat manté aquesta parada on és. Tu encara la pots editar.',
|
||||
'tours.walk.station.edit': 'Edita la parada',
|
||||
'tours.walk.importance.normal': 'Habitual',
|
||||
'tours.walk.importance.optional': 'Opcional',
|
||||
'tours.walk.importance.must': 'Imprescindible',
|
||||
'tours.walk.importanceHint.normal': 'Es visita segons avança la ruta.',
|
||||
'tours.walk.importanceHint.optional': 'Es pot ometre si falta temps.',
|
||||
'tours.walk.importanceHint.must': 'Un canvi proposat més endavant la manté a la ruta.',
|
||||
'tours.walk.timeEstimated': 'Temps a peu estimat',
|
||||
'tours.walk.timeEstimatedShort': 'A peu',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Com es calcula el temps a peu',
|
||||
'tours.walk.timeEstimatedInfo': 'El temps a peu del càlcul de ruta entre parades, sense les estades.',
|
||||
'tours.walk.stays': 'Estades',
|
||||
'tours.walk.totalAtLeast': 'com a mínim {time}',
|
||||
'tours.planner.tourType': 'Tipus de ruta',
|
||||
'tours.paddle.boat': 'Embarcació',
|
||||
'tours.paddle.boat.kayak': 'Caiac',
|
||||
|
||||
@@ -459,6 +459,38 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Schody jen tam, kde není cesta kolem.',
|
||||
'tours.preferences.avoid_ferries': 'Vyhnout se přívozům',
|
||||
'tours.preferences.avoid_ferriesHint': 'Po souši, kde vede cesta kolem, i když je delší.',
|
||||
'tours.planner.tourTypeHint.walk': 'Pěšky od zastávky k zastávce, bez turistického limitu',
|
||||
'tours.poi.cat.museum': 'Muzea a galerie',
|
||||
'tours.poi.cat.park': 'Parky a zahrady',
|
||||
'tours.poi.cat.cafe': 'Kavárny',
|
||||
'tours.poi.cat.restaurant': 'Kde se najíst',
|
||||
'tours.poi.cat.market': 'Trhy',
|
||||
'tours.walk.station.eyebrow': 'Zastávka',
|
||||
'tours.walk.station.unnamed': 'Zastávka bez názvu',
|
||||
'tours.walk.station.name': 'Název',
|
||||
'tours.walk.station.namePlaceholder': 'Co tu je',
|
||||
'tours.walk.station.stay': 'Pobyt v minutách',
|
||||
'tours.walk.station.stayHint': 'Prázdné znamená zatím neznámé; 0 pro místo, kterým jen projdeš.',
|
||||
'tours.walk.station.stayInvalid': 'Zadej celé minuty, nejvýše jeden den.',
|
||||
'tours.walk.station.stayUnknown': 'Zatím neznámé',
|
||||
'tours.walk.station.stayUnknownShort': 'Pobyt neznámý',
|
||||
'tours.walk.station.passThrough': 'Jen průchod',
|
||||
'tours.walk.station.importance': 'Důležitost',
|
||||
'tours.walk.station.protected': 'Chráněná',
|
||||
'tours.walk.station.protectedHint': 'Navržená změna nechá tuto zastávku na místě. Sám ji upravit můžeš dál.',
|
||||
'tours.walk.station.edit': 'Upravit zastávku',
|
||||
'tours.walk.importance.normal': 'Běžná',
|
||||
'tours.walk.importance.optional': 'Volitelná',
|
||||
'tours.walk.importance.must': 'Musíš vidět',
|
||||
'tours.walk.importanceHint.normal': 'Navštíví se během procházky.',
|
||||
'tours.walk.importanceHint.optional': 'Lze vynechat, když dochází čas.',
|
||||
'tours.walk.importanceHint.must': 'Pozdější navržená změna ji v procházce ponechá.',
|
||||
'tours.walk.timeEstimated': 'Odhadovaná doba chůze',
|
||||
'tours.walk.timeEstimatedShort': 'Chůze',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Jak se počítá doba chůze',
|
||||
'tours.walk.timeEstimatedInfo': 'Doba chůze mezi zastávkami podle plánovače trasy, bez pobytů.',
|
||||
'tours.walk.stays': 'Pobyty',
|
||||
'tours.walk.totalAtLeast': 'nejméně {time}',
|
||||
'tours.planner.tourType': 'Typ túry',
|
||||
'tours.paddle.boat': 'Loď',
|
||||
'tours.paddle.boat.kayak': 'Kajak',
|
||||
|
||||
@@ -472,6 +472,39 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Treppen nur, wo es keinen Weg außen herum gibt.',
|
||||
'tours.preferences.avoid_ferries': 'Fähren meiden',
|
||||
'tours.preferences.avoid_ferriesHint': 'Über Land, wo es einen Weg außen herum gibt, auch wenn er länger ist.',
|
||||
'tours.planner.tourTypeHint.walk': 'Zu Fuß von Station zu Station, ohne Wanderlimit',
|
||||
'tours.poi.cat.museum': 'Museen und Galerien',
|
||||
'tours.poi.cat.park': 'Parks und Gärten',
|
||||
'tours.poi.cat.cafe': 'Cafés',
|
||||
'tours.poi.cat.restaurant': 'Gaststätten',
|
||||
'tours.poi.cat.market': 'Märkte',
|
||||
'tours.walk.station.eyebrow': 'Station',
|
||||
'tours.walk.station.unnamed': 'Station ohne Namen',
|
||||
'tours.walk.station.name': 'Bezeichnung',
|
||||
'tours.walk.station.namePlaceholder': 'Was hier ist',
|
||||
'tours.walk.station.stay': 'Aufenthalt in Minuten',
|
||||
'tours.walk.station.stayHint': 'Leer heißt noch unbekannt; 0 für einen Punkt, den du nur passierst.',
|
||||
'tours.walk.station.stayInvalid': 'Ganze Minuten eingeben, höchstens einen Tag.',
|
||||
'tours.walk.station.stayUnknown': 'Noch unbekannt',
|
||||
'tours.walk.station.stayUnknownShort': 'Aufenthalt offen',
|
||||
'tours.walk.station.passThrough': 'Durchgang',
|
||||
'tours.walk.station.importance': 'Wichtigkeit',
|
||||
'tours.walk.station.protected': 'Geschützt',
|
||||
'tours.walk.station.protectedHint':
|
||||
'Ein Änderungsvorschlag lässt diese Station, wo sie ist. Du selbst kannst sie weiter bearbeiten.',
|
||||
'tours.walk.station.edit': 'Station bearbeiten',
|
||||
'tours.walk.importance.normal': 'Standard',
|
||||
'tours.walk.importance.optional': 'Kann entfallen',
|
||||
'tours.walk.importance.must': 'Unbedingt besuchen',
|
||||
'tours.walk.importanceHint.normal': 'Wird besucht, wie der Weg es ergibt.',
|
||||
'tours.walk.importanceHint.optional': 'Kann entfallen, wenn die Zeit knapp wird.',
|
||||
'tours.walk.importanceHint.must': 'Ein späterer Änderungsvorschlag behält sie im Walk.',
|
||||
'tours.walk.timeEstimated': 'Gehzeit (geschätzt)',
|
||||
'tours.walk.timeEstimatedShort': 'Gehzeit',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Wie die Gehzeit entsteht',
|
||||
'tours.walk.timeEstimatedInfo': 'Die Zeit des Routers zu Fuß zwischen den Stationen, ohne die Aufenthalte.',
|
||||
'tours.walk.stays': 'Aufenthalte',
|
||||
'tours.walk.totalAtLeast': 'mindestens {time}',
|
||||
'tours.planner.tourType': 'Tourtyp',
|
||||
'tours.paddle.boat': 'Boot',
|
||||
'tours.paddle.boat.kayak': 'Kajak',
|
||||
|
||||
@@ -460,6 +460,38 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Steps and stairs only where there is no way round.',
|
||||
'tours.preferences.avoid_ferries': 'Avoid ferries',
|
||||
'tours.preferences.avoid_ferriesHint': 'Over land where there is a way round, even when it is longer.',
|
||||
'tours.planner.tourTypeHint.walk': 'On foot from stop to stop, without a hiking limit',
|
||||
'tours.poi.cat.museum': 'Museums and galleries',
|
||||
'tours.poi.cat.park': 'Parks and gardens',
|
||||
'tours.poi.cat.cafe': 'Coffee shops',
|
||||
'tours.poi.cat.restaurant': 'Places to eat',
|
||||
'tours.poi.cat.market': 'Markets',
|
||||
'tours.walk.station.eyebrow': 'Stop',
|
||||
'tours.walk.station.unnamed': 'Unnamed stop',
|
||||
'tours.walk.station.name': 'Label',
|
||||
'tours.walk.station.namePlaceholder': 'What is here',
|
||||
'tours.walk.station.stay': 'Stay in minutes',
|
||||
'tours.walk.station.stayHint': 'Empty means not known yet; 0 for a point you only pass.',
|
||||
'tours.walk.station.stayInvalid': 'Enter whole minutes, up to a day.',
|
||||
'tours.walk.station.stayUnknown': 'Not known yet',
|
||||
'tours.walk.station.stayUnknownShort': 'Stay unknown',
|
||||
'tours.walk.station.passThrough': 'Passing through',
|
||||
'tours.walk.station.importance': 'Importance',
|
||||
'tours.walk.station.protected': 'Protected',
|
||||
'tours.walk.station.protectedHint': 'A proposed change keeps this stop where it is. You can still edit it yourself.',
|
||||
'tours.walk.station.edit': 'Edit stop',
|
||||
'tours.walk.importance.normal': 'Regular',
|
||||
'tours.walk.importance.optional': 'Optional',
|
||||
'tours.walk.importance.must': 'Must see',
|
||||
'tours.walk.importanceHint.normal': 'Visited as the walk goes.',
|
||||
'tours.walk.importanceHint.optional': 'Can be left out when time runs short.',
|
||||
'tours.walk.importanceHint.must': 'A change proposed later keeps it in the walk.',
|
||||
'tours.walk.timeEstimated': 'Est. walking time',
|
||||
'tours.walk.timeEstimatedShort': 'Walking',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'How the walking time is worked out',
|
||||
'tours.walk.timeEstimatedInfo': "The router's time on foot between the stops, without the stays.",
|
||||
'tours.walk.stays': 'Stays',
|
||||
'tours.walk.totalAtLeast': 'at least {time}',
|
||||
'tours.planner.tourType': 'Tour type',
|
||||
'tours.paddle.boat': 'Boat',
|
||||
'tours.paddle.boat.kayak': 'Kayak',
|
||||
|
||||
@@ -467,6 +467,38 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Escaleras solo donde no hay forma de rodearlas.',
|
||||
'tours.preferences.avoid_ferries': 'Evitar ferris',
|
||||
'tours.preferences.avoid_ferriesHint': 'Por tierra donde haya una forma de rodear, aunque sea más larga.',
|
||||
'tours.planner.tourTypeHint.walk': 'A pie de parada en parada, sin límite de senderismo',
|
||||
'tours.poi.cat.museum': 'Museos y galerías',
|
||||
'tours.poi.cat.park': 'Parques y jardines',
|
||||
'tours.poi.cat.cafe': 'Cafeterías',
|
||||
'tours.poi.cat.restaurant': 'Sitios para comer',
|
||||
'tours.poi.cat.market': 'Mercados',
|
||||
'tours.walk.station.eyebrow': 'Parada',
|
||||
'tours.walk.station.unnamed': 'Parada sin nombre',
|
||||
'tours.walk.station.name': 'Nombre',
|
||||
'tours.walk.station.namePlaceholder': 'Qué hay aquí',
|
||||
'tours.walk.station.stay': 'Estancia en minutos',
|
||||
'tours.walk.station.stayHint': 'Vacío significa aún desconocido; 0 para un punto por el que solo pasas.',
|
||||
'tours.walk.station.stayInvalid': 'Introduce minutos enteros, hasta un día.',
|
||||
'tours.walk.station.stayUnknown': 'Aún desconocido',
|
||||
'tours.walk.station.stayUnknownShort': 'Estancia abierta',
|
||||
'tours.walk.station.passThrough': 'Solo de paso',
|
||||
'tours.walk.station.importance': 'Importancia',
|
||||
'tours.walk.station.protected': 'Protegida',
|
||||
'tours.walk.station.protectedHint': 'Un cambio propuesto deja esta parada donde está. Tú aún puedes editarla.',
|
||||
'tours.walk.station.edit': 'Editar parada',
|
||||
'tours.walk.importance.normal': 'Habitual',
|
||||
'tours.walk.importance.optional': 'Opcional',
|
||||
'tours.walk.importance.must': 'Imprescindible',
|
||||
'tours.walk.importanceHint.normal': 'Se visita según avanza el paseo.',
|
||||
'tours.walk.importanceHint.optional': 'Se puede omitir si falta tiempo.',
|
||||
'tours.walk.importanceHint.must': 'Un cambio propuesto más tarde la mantiene en el paseo.',
|
||||
'tours.walk.timeEstimated': 'Tiempo a pie estimado',
|
||||
'tours.walk.timeEstimatedShort': 'A pie',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Cómo se calcula el tiempo a pie',
|
||||
'tours.walk.timeEstimatedInfo': 'El tiempo a pie del planificador entre paradas, sin las estancias.',
|
||||
'tours.walk.stays': 'Estancias',
|
||||
'tours.walk.totalAtLeast': 'al menos {time}',
|
||||
'tours.planner.tourType': 'Tipo de ruta',
|
||||
'tours.paddle.boat': 'Embarcación',
|
||||
'tours.paddle.boat.kayak': 'Kayak', // same-as-en
|
||||
|
||||
@@ -462,6 +462,38 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Trepid ainult seal, kus ringi minna ei saa.',
|
||||
'tours.preferences.avoid_ferries': 'Väldi praame',
|
||||
'tours.preferences.avoid_ferriesHint': 'Mööda maad, kus saab ringi minna, isegi kui see on pikem.',
|
||||
'tours.planner.tourTypeHint.walk': 'Jalgsi peatusest peatusesse, ilma matkapiiranguta',
|
||||
'tours.poi.cat.museum': 'Muuseumid ja galeriid',
|
||||
'tours.poi.cat.park': 'Pargid ja aiad',
|
||||
'tours.poi.cat.cafe': 'Kohvikud',
|
||||
'tours.poi.cat.restaurant': 'Söögikohad',
|
||||
'tours.poi.cat.market': 'Turud',
|
||||
'tours.walk.station.eyebrow': 'Peatus',
|
||||
'tours.walk.station.unnamed': 'Nimetu peatus',
|
||||
'tours.walk.station.name': 'Nimi',
|
||||
'tours.walk.station.namePlaceholder': 'Mis siin on',
|
||||
'tours.walk.station.stay': 'Peatumine minutites',
|
||||
'tours.walk.station.stayHint': 'Tühi tähendab veel teadmata; 0 punkti jaoks, millest ainult möödud.',
|
||||
'tours.walk.station.stayInvalid': 'Sisesta täisminutid, kuni üks päev.',
|
||||
'tours.walk.station.stayUnknown': 'Veel teadmata',
|
||||
'tours.walk.station.stayUnknownShort': 'Peatus teadmata',
|
||||
'tours.walk.station.passThrough': 'Läbisõit',
|
||||
'tours.walk.station.importance': 'Tähtsus',
|
||||
'tours.walk.station.protected': 'Kaitstud',
|
||||
'tours.walk.station.protectedHint': 'Pakutud muudatus jätab selle peatuse paika. Ise saad seda endiselt muuta.',
|
||||
'tours.walk.station.edit': 'Muuda peatust',
|
||||
'tours.walk.importance.normal': 'Tavaline',
|
||||
'tours.walk.importance.optional': 'Valikuline',
|
||||
'tours.walk.importance.must': 'Kindlasti näha',
|
||||
'tours.walk.importanceHint.normal': 'Külastatakse jalutuse käigus.',
|
||||
'tours.walk.importanceHint.optional': 'Võib ära jätta, kui aega jääb väheks.',
|
||||
'tours.walk.importanceHint.must': 'Hilisem muudatusettepanek jätab selle jalutusse.',
|
||||
'tours.walk.timeEstimated': 'Hinnanguline kõndimisaeg',
|
||||
'tours.walk.timeEstimatedShort': 'Kõnd',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Kuidas kõndimisaeg arvutatakse',
|
||||
'tours.walk.timeEstimatedInfo': 'Marsruutija kõndimisaeg peatuste vahel, ilma peatumisteta.',
|
||||
'tours.walk.stays': 'Peatumised',
|
||||
'tours.walk.totalAtLeast': 'vähemalt {time}',
|
||||
'tours.planner.tourType': 'Matka tüüp',
|
||||
'tours.paddle.boat': 'Paat',
|
||||
'tours.paddle.boat.kayak': 'Süst',
|
||||
|
||||
@@ -476,6 +476,39 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Des escaliers seulement là où on ne peut pas les contourner.',
|
||||
'tours.preferences.avoid_ferries': 'Éviter les bacs',
|
||||
'tours.preferences.avoid_ferriesHint': 'Par voie terrestre là où on peut contourner, même si c’est plus long.',
|
||||
'tours.planner.tourTypeHint.walk': "À pied d'étape en étape, sans limite de randonnée",
|
||||
'tours.poi.cat.museum': 'Musées et galeries',
|
||||
'tours.poi.cat.park': 'Parcs et jardins',
|
||||
'tours.poi.cat.cafe': 'Salons de café',
|
||||
'tours.poi.cat.restaurant': 'Où manger',
|
||||
'tours.poi.cat.market': 'Marchés',
|
||||
'tours.walk.station.eyebrow': 'Étape',
|
||||
'tours.walk.station.unnamed': 'Étape sans nom',
|
||||
'tours.walk.station.name': 'Intitulé',
|
||||
'tours.walk.station.namePlaceholder': "Ce qu'il y a ici",
|
||||
'tours.walk.station.stay': 'Arrêt en minutes',
|
||||
'tours.walk.station.stayHint': 'Vide signifie encore inconnu ; 0 pour un point où tu ne fais que passer.',
|
||||
'tours.walk.station.stayInvalid': "Saisis des minutes entières, jusqu'à une journée.",
|
||||
'tours.walk.station.stayUnknown': 'Encore inconnu',
|
||||
'tours.walk.station.stayUnknownShort': 'Arrêt inconnu',
|
||||
'tours.walk.station.passThrough': 'Simple passage',
|
||||
'tours.walk.station.importance': "Importance de l'étape",
|
||||
'tours.walk.station.protected': 'Protégée',
|
||||
'tours.walk.station.protectedHint':
|
||||
'Une modification proposée laisse cette étape à sa place. Tu peux toujours la modifier toi-même.',
|
||||
'tours.walk.station.edit': "Modifier l'étape",
|
||||
'tours.walk.importance.normal': 'Normale',
|
||||
'tours.walk.importance.optional': 'Facultative',
|
||||
'tours.walk.importance.must': 'Incontournable',
|
||||
'tours.walk.importanceHint.normal': 'Visitée au fil de la balade.',
|
||||
'tours.walk.importanceHint.optional': 'Peut sauter si le temps manque.',
|
||||
'tours.walk.importanceHint.must': 'Une modification proposée plus tard la garde dans la balade.',
|
||||
'tours.walk.timeEstimated': 'Temps de marche estimé',
|
||||
'tours.walk.timeEstimatedShort': 'Marche',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Comment le temps de marche est calculé',
|
||||
'tours.walk.timeEstimatedInfo': "Le temps à pied du calcul d'itinéraire entre les étapes, sans les arrêts.",
|
||||
'tours.walk.stays': 'Arrêts',
|
||||
'tours.walk.totalAtLeast': 'au moins {time}',
|
||||
'tours.planner.tourType': 'Type de sortie',
|
||||
'tours.paddle.boat': 'Embarcation',
|
||||
'tours.paddle.boat.kayak': 'Kayak', // same-as-en
|
||||
|
||||
@@ -476,6 +476,39 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Σκαλοπάτια μόνο όπου δεν υπάρχει παράκαμψη.',
|
||||
'tours.preferences.avoid_ferries': 'Αποφυγή πορθμείων',
|
||||
'tours.preferences.avoid_ferriesHint': 'Από ξηράς όπου υπάρχει παράκαμψη, ακόμη κι αν είναι μεγαλύτερη.',
|
||||
'tours.planner.tourTypeHint.walk': 'Με τα πόδια από στάση σε στάση, χωρίς όριο πεζοπορίας',
|
||||
'tours.poi.cat.museum': 'Μουσεία και γκαλερί',
|
||||
'tours.poi.cat.park': 'Πάρκα και κήποι',
|
||||
'tours.poi.cat.cafe': 'Καφετέριες',
|
||||
'tours.poi.cat.restaurant': 'Μέρη για φαγητό',
|
||||
'tours.poi.cat.market': 'Αγορές',
|
||||
'tours.walk.station.eyebrow': 'Στάση',
|
||||
'tours.walk.station.unnamed': 'Στάση χωρίς όνομα',
|
||||
'tours.walk.station.name': 'Όνομα',
|
||||
'tours.walk.station.namePlaceholder': 'Τι υπάρχει εδώ',
|
||||
'tours.walk.station.stay': 'Παραμονή σε λεπτά',
|
||||
'tours.walk.station.stayHint': 'Κενό σημαίνει άγνωστο ακόμη· 0 για σημείο από το οποίο απλώς περνάς.',
|
||||
'tours.walk.station.stayInvalid': 'Δώσε ακέραια λεπτά, έως μία ημέρα.',
|
||||
'tours.walk.station.stayUnknown': 'Άγνωστο ακόμη',
|
||||
'tours.walk.station.stayUnknownShort': 'Παραμονή άγνωστη',
|
||||
'tours.walk.station.passThrough': 'Απλή διέλευση',
|
||||
'tours.walk.station.importance': 'Σημασία',
|
||||
'tours.walk.station.protected': 'Προστατευμένη',
|
||||
'tours.walk.station.protectedHint':
|
||||
'Μια προτεινόμενη αλλαγή αφήνει αυτή τη στάση στη θέση της. Εσύ μπορείς ακόμη να την επεξεργαστείς.',
|
||||
'tours.walk.station.edit': 'Επεξεργασία στάσης',
|
||||
'tours.walk.importance.normal': 'Κανονική',
|
||||
'tours.walk.importance.optional': 'Προαιρετική',
|
||||
'tours.walk.importance.must': 'Οπωσδήποτε',
|
||||
'tours.walk.importanceHint.normal': 'Επισκέπτεται καθώς προχωρά η βόλτα.',
|
||||
'tours.walk.importanceHint.optional': 'Μπορεί να παραλειφθεί αν πιέζει ο χρόνος.',
|
||||
'tours.walk.importanceHint.must': 'Μια μεταγενέστερη προτεινόμενη αλλαγή την κρατά στη βόλτα.',
|
||||
'tours.walk.timeEstimated': 'Εκτιμώμενος χρόνος περπατήματος',
|
||||
'tours.walk.timeEstimatedShort': 'Περπάτημα',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Πώς υπολογίζεται ο χρόνος περπατήματος',
|
||||
'tours.walk.timeEstimatedInfo': 'Ο χρόνος με τα πόδια του δρομολογητή ανάμεσα στις στάσεις, χωρίς τις παραμονές.',
|
||||
'tours.walk.stays': 'Παραμονές',
|
||||
'tours.walk.totalAtLeast': 'τουλάχιστον {time}',
|
||||
'tours.planner.tourType': 'Τύπος διαδρομής',
|
||||
'tours.paddle.boat': 'Σκάφος',
|
||||
'tours.paddle.boat.kayak': 'Καγιάκ',
|
||||
|
||||
@@ -468,6 +468,39 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Lépcső csak ott, ahol nincs kerülőút.',
|
||||
'tours.preferences.avoid_ferries': 'Kompok kerülése',
|
||||
'tours.preferences.avoid_ferriesHint': 'Szárazföldön, ahol van kerülőút, akkor is, ha hosszabb.',
|
||||
'tours.planner.tourTypeHint.walk': 'Gyalog megállóról megállóra, túrakorlát nélkül',
|
||||
'tours.poi.cat.museum': 'Múzeumok és galériák',
|
||||
'tours.poi.cat.park': 'Parkok és kertek',
|
||||
'tours.poi.cat.cafe': 'Kávézók',
|
||||
'tours.poi.cat.restaurant': 'Étkezőhelyek',
|
||||
'tours.poi.cat.market': 'Piacok',
|
||||
'tours.walk.station.eyebrow': 'Megálló',
|
||||
'tours.walk.station.unnamed': 'Névtelen megálló',
|
||||
'tours.walk.station.name': 'Megnevezés',
|
||||
'tours.walk.station.namePlaceholder': 'Mi van itt',
|
||||
'tours.walk.station.stay': 'Tartózkodás percben',
|
||||
'tours.walk.station.stayHint': 'Üres: még nem ismert; 0 egy pontnál, amelyen csak áthaladsz.',
|
||||
'tours.walk.station.stayInvalid': 'Egész perceket adj meg, legfeljebb egy napot.',
|
||||
'tours.walk.station.stayUnknown': 'Még nem ismert',
|
||||
'tours.walk.station.stayUnknownShort': 'Tartózkodás nyitott',
|
||||
'tours.walk.station.passThrough': 'Csak áthaladás',
|
||||
'tours.walk.station.importance': 'Fontosság',
|
||||
'tours.walk.station.protected': 'Védett',
|
||||
'tours.walk.station.protectedHint':
|
||||
'Egy javasolt változtatás a helyén hagyja ezt a megállót. Te továbbra is szerkesztheted.',
|
||||
'tours.walk.station.edit': 'Megálló szerkesztése',
|
||||
'tours.walk.importance.normal': 'Szokásos',
|
||||
'tours.walk.importance.optional': 'Elhagyható',
|
||||
'tours.walk.importance.must': 'Kihagyhatatlan',
|
||||
'tours.walk.importanceHint.normal': 'A séta során meglátogatjuk.',
|
||||
'tours.walk.importanceHint.optional': 'Kimaradhat, ha szűkül az idő.',
|
||||
'tours.walk.importanceHint.must': 'Egy későbbi javasolt változtatás bent hagyja a sétában.',
|
||||
'tours.walk.timeEstimated': 'Becsült gyaloglási idő',
|
||||
'tours.walk.timeEstimatedShort': 'Gyaloglás',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Hogyan számoljuk a gyaloglási időt',
|
||||
'tours.walk.timeEstimatedInfo': 'Az útvonaltervező gyalogos ideje a megállók között, a tartózkodások nélkül.',
|
||||
'tours.walk.stays': 'Tartózkodások',
|
||||
'tours.walk.totalAtLeast': 'legalább {time}',
|
||||
'tours.planner.tourType': 'Túratípus',
|
||||
'tours.paddle.boat': 'Hajó',
|
||||
'tours.paddle.boat.kayak': 'Kajak',
|
||||
|
||||
@@ -460,6 +460,39 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Tangga hanya jika tidak ada jalan memutar.',
|
||||
'tours.preferences.avoid_ferries': 'Hindari feri',
|
||||
'tours.preferences.avoid_ferriesHint': 'Lewat darat jika ada jalan memutar, meski lebih panjang.',
|
||||
'tours.planner.tourTypeHint.walk': 'Berjalan dari titik ke titik, tanpa batas pendakian',
|
||||
'tours.poi.cat.museum': 'Museum dan galeri',
|
||||
'tours.poi.cat.park': 'Taman dan kebun',
|
||||
'tours.poi.cat.cafe': 'Kedai kopi',
|
||||
'tours.poi.cat.restaurant': 'Tempat makan',
|
||||
'tours.poi.cat.market': 'Pasar',
|
||||
'tours.walk.station.eyebrow': 'Titik singgah',
|
||||
'tours.walk.station.unnamed': 'Titik tanpa nama',
|
||||
'tours.walk.station.name': 'Nama',
|
||||
'tours.walk.station.namePlaceholder': 'Apa yang ada di sini',
|
||||
'tours.walk.station.stay': 'Lama singgah dalam menit',
|
||||
'tours.walk.station.stayHint': 'Kosong berarti belum diketahui; 0 untuk titik yang hanya kamu lewati.',
|
||||
'tours.walk.station.stayInvalid': 'Masukkan menit bulat, paling lama satu hari.',
|
||||
'tours.walk.station.stayUnknown': 'Belum diketahui',
|
||||
'tours.walk.station.stayUnknownShort': 'Lama singgah belum ada',
|
||||
'tours.walk.station.passThrough': 'Hanya lewat',
|
||||
'tours.walk.station.importance': 'Tingkat penting',
|
||||
'tours.walk.station.protected': 'Dilindungi',
|
||||
'tours.walk.station.protectedHint':
|
||||
'Perubahan yang diusulkan membiarkan titik ini di tempatnya. Kamu tetap bisa mengeditnya.',
|
||||
'tours.walk.station.edit': 'Edit titik singgah',
|
||||
'tours.walk.importance.normal': 'Biasa',
|
||||
'tours.walk.importance.optional': 'Opsional',
|
||||
'tours.walk.importance.must': 'Wajib dikunjungi',
|
||||
'tours.walk.importanceHint.normal': 'Dikunjungi sesuai jalannya rute.',
|
||||
'tours.walk.importanceHint.optional': 'Bisa dilewati jika waktu mepet.',
|
||||
'tours.walk.importanceHint.must': 'Perubahan yang diusulkan nanti tetap menyertakannya.',
|
||||
'tours.walk.timeEstimated': 'Perkiraan waktu jalan',
|
||||
'tours.walk.timeEstimatedShort': 'Berjalan',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Cara waktu jalan dihitung',
|
||||
'tours.walk.timeEstimatedInfo': 'Waktu jalan kaki dari perute di antara titik singgah, tanpa lama singgah.',
|
||||
'tours.walk.stays': 'Lama singgah',
|
||||
'tours.walk.totalAtLeast': 'setidaknya {time}',
|
||||
'tours.planner.tourType': 'Jenis tur',
|
||||
'tours.paddle.boat': 'Perahu',
|
||||
'tours.paddle.boat.kayak': 'Kayak', // same-as-en
|
||||
|
||||
@@ -468,6 +468,38 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Scale solo dove non c’è modo di aggirarle.',
|
||||
'tours.preferences.avoid_ferries': 'Evita i traghetti',
|
||||
'tours.preferences.avoid_ferriesHint': 'Via terra dove c’è un modo di aggirare, anche se più lungo.',
|
||||
'tours.planner.tourTypeHint.walk': 'A piedi di tappa in tappa, senza limite escursionistico',
|
||||
'tours.poi.cat.museum': 'Musei e gallerie',
|
||||
'tours.poi.cat.park': 'Parchi e giardini',
|
||||
'tours.poi.cat.cafe': 'Caffetterie',
|
||||
'tours.poi.cat.restaurant': 'Dove mangiare',
|
||||
'tours.poi.cat.market': 'Mercati',
|
||||
'tours.walk.station.eyebrow': 'Tappa',
|
||||
'tours.walk.station.unnamed': 'Tappa senza nome',
|
||||
'tours.walk.station.name': 'Denominazione',
|
||||
'tours.walk.station.namePlaceholder': "Cosa c'è qui",
|
||||
'tours.walk.station.stay': 'Sosta in minuti',
|
||||
'tours.walk.station.stayHint': 'Vuoto significa ancora sconosciuto; 0 per un punto da cui passi soltanto.',
|
||||
'tours.walk.station.stayInvalid': 'Inserisci minuti interi, fino a un giorno.',
|
||||
'tours.walk.station.stayUnknown': 'Ancora sconosciuto',
|
||||
'tours.walk.station.stayUnknownShort': 'Sosta da definire',
|
||||
'tours.walk.station.passThrough': 'Solo di passaggio',
|
||||
'tours.walk.station.importance': 'Importanza',
|
||||
'tours.walk.station.protected': 'Protetta',
|
||||
'tours.walk.station.protectedHint': "Una modifica proposta lascia questa tappa dov'è. Tu puoi comunque modificarla.",
|
||||
'tours.walk.station.edit': 'Modifica tappa',
|
||||
'tours.walk.importance.normal': 'Normale',
|
||||
'tours.walk.importance.optional': 'Facoltativa',
|
||||
'tours.walk.importance.must': 'Da non perdere',
|
||||
'tours.walk.importanceHint.normal': 'Si visita lungo il percorso.',
|
||||
'tours.walk.importanceHint.optional': 'Si può saltare se il tempo stringe.',
|
||||
'tours.walk.importanceHint.must': 'Una modifica proposta più avanti la mantiene nel percorso.',
|
||||
'tours.walk.timeEstimated': 'Tempo a piedi stimato',
|
||||
'tours.walk.timeEstimatedShort': 'A piedi',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Come si calcola il tempo a piedi',
|
||||
'tours.walk.timeEstimatedInfo': 'Il tempo a piedi del calcolo percorso tra le tappe, senza le soste.',
|
||||
'tours.walk.stays': 'Soste',
|
||||
'tours.walk.totalAtLeast': 'almeno {time}',
|
||||
'tours.planner.tourType': 'Tipo di tour',
|
||||
'tours.paddle.boat': 'Imbarcazione',
|
||||
'tours.paddle.boat.kayak': 'Kayak', // same-as-en
|
||||
|
||||
@@ -452,6 +452,39 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': '回り道がない場所だけ階段を通ります。',
|
||||
'tours.preferences.avoid_ferries': 'フェリーを避ける',
|
||||
'tours.preferences.avoid_ferriesHint': '回り道があれば、長くても陸路を通ります。',
|
||||
'tours.planner.tourTypeHint.walk': '立ち寄り先から立ち寄り先へ徒歩で。ハイキングの難易度制限なし',
|
||||
'tours.poi.cat.museum': '美術館・博物館',
|
||||
'tours.poi.cat.park': '公園と庭園',
|
||||
'tours.poi.cat.cafe': 'カフェ',
|
||||
'tours.poi.cat.restaurant': '食事処',
|
||||
'tours.poi.cat.market': '市場',
|
||||
'tours.walk.station.eyebrow': '立ち寄り先',
|
||||
'tours.walk.station.unnamed': '名前のない立ち寄り先',
|
||||
'tours.walk.station.name': '名前',
|
||||
'tours.walk.station.namePlaceholder': 'ここにあるもの',
|
||||
'tours.walk.station.stay': '滞在時間(分)',
|
||||
'tours.walk.station.stayHint': '空欄はまだ不明、通過するだけの地点は 0。',
|
||||
'tours.walk.station.stayInvalid': '整数の分で入力してください(最大1日)。',
|
||||
'tours.walk.station.stayUnknown': 'まだ不明',
|
||||
'tours.walk.station.stayUnknownShort': '滞在時間未定',
|
||||
'tours.walk.station.passThrough': '通過のみ',
|
||||
'tours.walk.station.importance': '重要度',
|
||||
'tours.walk.station.protected': '保護',
|
||||
'tours.walk.station.protectedHint':
|
||||
'提案された変更でもこの立ち寄り先はそのまま残ります。自分では引き続き編集できます。',
|
||||
'tours.walk.station.edit': '立ち寄り先を編集',
|
||||
'tours.walk.importance.normal': '通常',
|
||||
'tours.walk.importance.optional': '任意',
|
||||
'tours.walk.importance.must': '必見',
|
||||
'tours.walk.importanceHint.normal': '歩く流れで立ち寄ります。',
|
||||
'tours.walk.importanceHint.optional': '時間が足りなければ省けます。',
|
||||
'tours.walk.importanceHint.must': '後から提案される変更でも外されません。',
|
||||
'tours.walk.timeEstimated': '推定歩行時間',
|
||||
'tours.walk.timeEstimatedShort': '歩行',
|
||||
'tours.walk.timeEstimatedInfoLabel': '歩行時間の求め方',
|
||||
'tours.walk.timeEstimatedInfo': 'ルート計算による立ち寄り先間の徒歩時間。滞在時間は含みません。',
|
||||
'tours.walk.stays': '滞在',
|
||||
'tours.walk.totalAtLeast': '{time} 以上',
|
||||
'tours.planner.tourType': 'ツアーの種類',
|
||||
'tours.paddle.boat': 'ボート',
|
||||
'tours.paddle.boat.kayak': 'カヤック',
|
||||
|
||||
@@ -449,6 +449,38 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': '돌아갈 길이 없을 때만 계단을 지납니다.',
|
||||
'tours.preferences.avoid_ferries': '페리 피하기',
|
||||
'tours.preferences.avoid_ferriesHint': '돌아가는 길이 있으면 더 길어도 육로로 갑니다.',
|
||||
'tours.planner.tourTypeHint.walk': '정류지에서 정류지로 도보 이동, 하이킹 제한 없음',
|
||||
'tours.poi.cat.museum': '박물관과 갤러리',
|
||||
'tours.poi.cat.park': '공원과 정원',
|
||||
'tours.poi.cat.cafe': '카페',
|
||||
'tours.poi.cat.restaurant': '식당',
|
||||
'tours.poi.cat.market': '시장',
|
||||
'tours.walk.station.eyebrow': '정류지',
|
||||
'tours.walk.station.unnamed': '이름 없는 정류지',
|
||||
'tours.walk.station.name': '이름',
|
||||
'tours.walk.station.namePlaceholder': '이곳에 있는 것',
|
||||
'tours.walk.station.stay': '머무는 시간(분)',
|
||||
'tours.walk.station.stayHint': '비워 두면 아직 모름, 지나가기만 하는 곳은 0.',
|
||||
'tours.walk.station.stayInvalid': '정수 분으로 입력하세요(최대 하루).',
|
||||
'tours.walk.station.stayUnknown': '아직 모름',
|
||||
'tours.walk.station.stayUnknownShort': '머무는 시간 미정',
|
||||
'tours.walk.station.passThrough': '지나가기만',
|
||||
'tours.walk.station.importance': '중요도',
|
||||
'tours.walk.station.protected': '보호됨',
|
||||
'tours.walk.station.protectedHint': '제안된 변경에서도 이 정류지는 그대로 유지됩니다. 직접 수정하는 것은 가능합니다.',
|
||||
'tours.walk.station.edit': '정류지 편집',
|
||||
'tours.walk.importance.normal': '보통',
|
||||
'tours.walk.importance.optional': '선택',
|
||||
'tours.walk.importance.must': '꼭 방문',
|
||||
'tours.walk.importanceHint.normal': '걷는 흐름에 따라 들릅니다.',
|
||||
'tours.walk.importanceHint.optional': '시간이 부족하면 건너뛸 수 있습니다.',
|
||||
'tours.walk.importanceHint.must': '나중에 제안되는 변경에서도 유지됩니다.',
|
||||
'tours.walk.timeEstimated': '예상 도보 시간',
|
||||
'tours.walk.timeEstimatedShort': '도보',
|
||||
'tours.walk.timeEstimatedInfoLabel': '도보 시간 계산 방법',
|
||||
'tours.walk.timeEstimatedInfo': '경로 계산기가 낸 정류지 사이 도보 시간이며, 머무는 시간은 빠져 있습니다.',
|
||||
'tours.walk.stays': '머무는 시간',
|
||||
'tours.walk.totalAtLeast': '최소 {time}',
|
||||
'tours.planner.tourType': '투어 유형',
|
||||
'tours.paddle.boat': '보트',
|
||||
'tours.paddle.boat.kayak': '카약',
|
||||
|
||||
@@ -470,6 +470,39 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Trappen alleen waar er geen weg omheen is.',
|
||||
'tours.preferences.avoid_ferries': 'Veerponten vermijden',
|
||||
'tours.preferences.avoid_ferriesHint': 'Over land waar er een weg omheen is, ook als die langer is.',
|
||||
'tours.planner.tourTypeHint.walk': 'Te voet van stop naar stop, zonder wandelgrens',
|
||||
'tours.poi.cat.museum': 'Musea en galerieën',
|
||||
'tours.poi.cat.park': 'Parken en tuinen',
|
||||
'tours.poi.cat.cafe': 'Koffiezaken',
|
||||
'tours.poi.cat.restaurant': 'Eetgelegenheden',
|
||||
'tours.poi.cat.market': 'Markten',
|
||||
'tours.walk.station.eyebrow': 'Halte',
|
||||
'tours.walk.station.unnamed': 'Halte zonder naam',
|
||||
'tours.walk.station.name': 'Benaming',
|
||||
'tours.walk.station.namePlaceholder': 'Wat hier is',
|
||||
'tours.walk.station.stay': 'Verblijf in minuten',
|
||||
'tours.walk.station.stayHint': 'Leeg betekent nog onbekend; 0 voor een punt waar je alleen langs loopt.',
|
||||
'tours.walk.station.stayInvalid': 'Vul hele minuten in, tot een dag.',
|
||||
'tours.walk.station.stayUnknown': 'Nog onbekend',
|
||||
'tours.walk.station.stayUnknownShort': 'Verblijf open',
|
||||
'tours.walk.station.passThrough': 'Alleen doorgaan',
|
||||
'tours.walk.station.importance': 'Belang',
|
||||
'tours.walk.station.protected': 'Beschermd',
|
||||
'tours.walk.station.protectedHint':
|
||||
'Een voorgestelde wijziging laat deze halte waar hij is. Zelf kun je hem nog bewerken.',
|
||||
'tours.walk.station.edit': 'Halte bewerken',
|
||||
'tours.walk.importance.normal': 'Gewoon',
|
||||
'tours.walk.importance.optional': 'Optioneel',
|
||||
'tours.walk.importance.must': 'Niet missen',
|
||||
'tours.walk.importanceHint.normal': 'Wordt bezocht zoals de wandeling loopt.',
|
||||
'tours.walk.importanceHint.optional': 'Kan wegvallen als de tijd krap wordt.',
|
||||
'tours.walk.importanceHint.must': 'Een later voorgestelde wijziging houdt hem in de wandeling.',
|
||||
'tours.walk.timeEstimated': 'Geschatte looptijd',
|
||||
'tours.walk.timeEstimatedShort': 'Lopen',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Hoe de looptijd wordt berekend',
|
||||
'tours.walk.timeEstimatedInfo': 'De looptijd van de routeplanner tussen de haltes, zonder het verblijf.',
|
||||
'tours.walk.stays': 'Verblijven',
|
||||
'tours.walk.totalAtLeast': 'minstens {time}',
|
||||
'tours.planner.tourType': 'Soort tocht',
|
||||
'tours.paddle.boat': 'Boot',
|
||||
'tours.paddle.boat.kayak': 'Kajak',
|
||||
|
||||
@@ -475,6 +475,39 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Schody tylko tam, gdzie nie da się ich obejść.',
|
||||
'tours.preferences.avoid_ferries': 'Unikaj promów',
|
||||
'tours.preferences.avoid_ferriesHint': 'Lądem, gdzie da się obejść, nawet jeśli dłużej.',
|
||||
'tours.planner.tourTypeHint.walk': 'Pieszo od przystanku do przystanku, bez limitu szlaku',
|
||||
'tours.poi.cat.museum': 'Muzea i galerie',
|
||||
'tours.poi.cat.park': 'Parki i ogrody',
|
||||
'tours.poi.cat.cafe': 'Kawiarnie',
|
||||
'tours.poi.cat.restaurant': 'Gdzie zjeść',
|
||||
'tours.poi.cat.market': 'Targi',
|
||||
'tours.walk.station.eyebrow': 'Przystanek',
|
||||
'tours.walk.station.unnamed': 'Przystanek bez nazwy',
|
||||
'tours.walk.station.name': 'Nazwa',
|
||||
'tours.walk.station.namePlaceholder': 'Co tu jest',
|
||||
'tours.walk.station.stay': 'Pobyt w minutach',
|
||||
'tours.walk.station.stayHint': 'Puste oznacza jeszcze nieznane; 0 dla punktu, przez który tylko przechodzisz.',
|
||||
'tours.walk.station.stayInvalid': 'Wpisz pełne minuty, maksymalnie jeden dzień.',
|
||||
'tours.walk.station.stayUnknown': 'Jeszcze nieznane',
|
||||
'tours.walk.station.stayUnknownShort': 'Pobyt nieznany',
|
||||
'tours.walk.station.passThrough': 'Tylko przejście',
|
||||
'tours.walk.station.importance': 'Ważność',
|
||||
'tours.walk.station.protected': 'Chroniony',
|
||||
'tours.walk.station.protectedHint':
|
||||
'Proponowana zmiana zostawia ten przystanek na miejscu. Ty nadal możesz go edytować.',
|
||||
'tours.walk.station.edit': 'Edytuj przystanek',
|
||||
'tours.walk.importance.normal': 'Zwykły',
|
||||
'tours.walk.importance.optional': 'Opcjonalny',
|
||||
'tours.walk.importance.must': 'Koniecznie',
|
||||
'tours.walk.importanceHint.normal': 'Odwiedzany po drodze.',
|
||||
'tours.walk.importanceHint.optional': 'Można pominąć, gdy brakuje czasu.',
|
||||
'tours.walk.importanceHint.must': 'Późniejsza proponowana zmiana zostawi go w trasie.',
|
||||
'tours.walk.timeEstimated': 'Szacowany czas marszu',
|
||||
'tours.walk.timeEstimatedShort': 'Marsz',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Jak liczony jest czas marszu',
|
||||
'tours.walk.timeEstimatedInfo': 'Czas marszu między przystankami według planera trasy, bez postojów.',
|
||||
'tours.walk.stays': 'Postoje',
|
||||
'tours.walk.totalAtLeast': 'co najmniej {time}',
|
||||
'tours.planner.tourType': 'Rodzaj wycieczki',
|
||||
'tours.paddle.boat': 'Łódź',
|
||||
'tours.paddle.boat.kayak': 'Kajak',
|
||||
|
||||
@@ -478,6 +478,39 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Лестницы только там, где их не обойти.',
|
||||
'tours.preferences.avoid_ferries': 'Избегать паромов',
|
||||
'tours.preferences.avoid_ferriesHint': 'По суше, где есть обход, даже если он длиннее.',
|
||||
'tours.planner.tourTypeHint.walk': 'Пешком от остановки к остановке, без ограничения по сложности',
|
||||
'tours.poi.cat.museum': 'Музеи и галереи',
|
||||
'tours.poi.cat.park': 'Парки и сады',
|
||||
'tours.poi.cat.cafe': 'Кафе',
|
||||
'tours.poi.cat.restaurant': 'Где поесть',
|
||||
'tours.poi.cat.market': 'Рынки',
|
||||
'tours.walk.station.eyebrow': 'Остановка',
|
||||
'tours.walk.station.unnamed': 'Остановка без названия',
|
||||
'tours.walk.station.name': 'Название',
|
||||
'tours.walk.station.namePlaceholder': 'Что здесь',
|
||||
'tours.walk.station.stay': 'Остановка в минутах',
|
||||
'tours.walk.station.stayHint': 'Пусто значит пока неизвестно; 0 для точки, которую ты только проходишь.',
|
||||
'tours.walk.station.stayInvalid': 'Введи целые минуты, не больше суток.',
|
||||
'tours.walk.station.stayUnknown': 'Пока неизвестно',
|
||||
'tours.walk.station.stayUnknownShort': 'Остановка неизвестна',
|
||||
'tours.walk.station.passThrough': 'Только мимо',
|
||||
'tours.walk.station.importance': 'Важность',
|
||||
'tours.walk.station.protected': 'Защищена',
|
||||
'tours.walk.station.protectedHint':
|
||||
'Предложенное изменение оставит эту остановку на месте. Сам ты по-прежнему можешь её править.',
|
||||
'tours.walk.station.edit': 'Изменить остановку',
|
||||
'tours.walk.importance.normal': 'Обычная',
|
||||
'tours.walk.importance.optional': 'Необязательная',
|
||||
'tours.walk.importance.must': 'Обязательно',
|
||||
'tours.walk.importanceHint.normal': 'Посещается по ходу прогулки.',
|
||||
'tours.walk.importanceHint.optional': 'Можно пропустить, если не хватает времени.',
|
||||
'tours.walk.importanceHint.must': 'Предложенное позже изменение оставит её в прогулке.',
|
||||
'tours.walk.timeEstimated': 'Расчётное время в пути',
|
||||
'tours.walk.timeEstimatedShort': 'Пешком',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Как считается время в пути',
|
||||
'tours.walk.timeEstimatedInfo': 'Время пешком между остановками по расчёту маршрута, без остановок на месте.',
|
||||
'tours.walk.stays': 'Остановки',
|
||||
'tours.walk.totalAtLeast': 'не меньше {time}',
|
||||
'tours.planner.tourType': 'Тип тура',
|
||||
'tours.paddle.boat': 'Лодка',
|
||||
'tours.paddle.boat.kayak': 'Каяк',
|
||||
|
||||
@@ -461,6 +461,38 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Schody len tam, kde nie je cesta okolo.',
|
||||
'tours.preferences.avoid_ferries': 'Vyhnúť sa prievozom',
|
||||
'tours.preferences.avoid_ferriesHint': 'Po súši, kde vedie cesta okolo, aj keď je dlhšia.',
|
||||
'tours.planner.tourTypeHint.walk': 'Pešo od zastávky k zastávke, bez turistického limitu',
|
||||
'tours.poi.cat.museum': 'Múzeá a galérie',
|
||||
'tours.poi.cat.park': 'Parky a záhrady',
|
||||
'tours.poi.cat.cafe': 'Kaviarne',
|
||||
'tours.poi.cat.restaurant': 'Kde sa najesť',
|
||||
'tours.poi.cat.market': 'Trhy',
|
||||
'tours.walk.station.eyebrow': 'Zastávka',
|
||||
'tours.walk.station.unnamed': 'Zastávka bez názvu',
|
||||
'tours.walk.station.name': 'Názov',
|
||||
'tours.walk.station.namePlaceholder': 'Čo je tu',
|
||||
'tours.walk.station.stay': 'Pobyt v minútach',
|
||||
'tours.walk.station.stayHint': 'Prázdne znamená zatiaľ neznáme; 0 pre miesto, ktorým len prejdeš.',
|
||||
'tours.walk.station.stayInvalid': 'Zadaj celé minúty, najviac jeden deň.',
|
||||
'tours.walk.station.stayUnknown': 'Zatiaľ neznáme',
|
||||
'tours.walk.station.stayUnknownShort': 'Pobyt neznámy',
|
||||
'tours.walk.station.passThrough': 'Len prechod',
|
||||
'tours.walk.station.importance': 'Dôležitosť',
|
||||
'tours.walk.station.protected': 'Chránená',
|
||||
'tours.walk.station.protectedHint': 'Navrhovaná zmena nechá túto zastávku na mieste. Sám ju môžeš ďalej upravovať.',
|
||||
'tours.walk.station.edit': 'Upraviť zastávku',
|
||||
'tours.walk.importance.normal': 'Bežná',
|
||||
'tours.walk.importance.optional': 'Voliteľná',
|
||||
'tours.walk.importance.must': 'Musíš vidieť',
|
||||
'tours.walk.importanceHint.normal': 'Navštívi sa počas prechádzky.',
|
||||
'tours.walk.importanceHint.optional': 'Dá sa vynechať, keď chýba čas.',
|
||||
'tours.walk.importanceHint.must': 'Neskoršia navrhovaná zmena ju v prechádzke ponechá.',
|
||||
'tours.walk.timeEstimated': 'Odhadovaný čas chôdze',
|
||||
'tours.walk.timeEstimatedShort': 'Chôdza',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Ako sa počíta čas chôdze',
|
||||
'tours.walk.timeEstimatedInfo': 'Čas chôdze medzi zastávkami podľa plánovača trasy, bez pobytov.',
|
||||
'tours.walk.stays': 'Pobyty',
|
||||
'tours.walk.totalAtLeast': 'najmenej {time}',
|
||||
'tours.planner.tourType': 'Typ túry',
|
||||
'tours.paddle.boat': 'Loď',
|
||||
'tours.paddle.boat.kayak': 'Kajak',
|
||||
|
||||
@@ -459,6 +459,39 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Trappor bara där det inte finns någon väg runt.',
|
||||
'tours.preferences.avoid_ferries': 'Undvik färjor',
|
||||
'tours.preferences.avoid_ferriesHint': 'Över land där det finns en väg runt, även om den är längre.',
|
||||
'tours.planner.tourTypeHint.walk': 'Till fots från stopp till stopp, utan vandringsgräns',
|
||||
'tours.poi.cat.museum': 'Museer och gallerier',
|
||||
'tours.poi.cat.park': 'Parker och trädgårdar',
|
||||
'tours.poi.cat.cafe': 'Kaféer',
|
||||
'tours.poi.cat.restaurant': 'Matställen',
|
||||
'tours.poi.cat.market': 'Torghandel',
|
||||
'tours.walk.station.eyebrow': 'Stopp',
|
||||
'tours.walk.station.unnamed': 'Namnlöst stopp',
|
||||
'tours.walk.station.name': 'Benämning',
|
||||
'tours.walk.station.namePlaceholder': 'Vad som finns här',
|
||||
'tours.walk.station.stay': 'Vistelse i minuter',
|
||||
'tours.walk.station.stayHint': 'Tomt betyder ännu okänt; 0 för en punkt du bara passerar.',
|
||||
'tours.walk.station.stayInvalid': 'Ange hela minuter, högst ett dygn.',
|
||||
'tours.walk.station.stayUnknown': 'Ännu okänt',
|
||||
'tours.walk.station.stayUnknownShort': 'Vistelse okänd',
|
||||
'tours.walk.station.passThrough': 'Bara förbi',
|
||||
'tours.walk.station.importance': 'Vikt',
|
||||
'tours.walk.station.protected': 'Skyddad',
|
||||
'tours.walk.station.protectedHint':
|
||||
'Ett föreslaget ändringsförslag låter stoppet vara kvar. Du kan fortfarande redigera det själv.',
|
||||
'tours.walk.station.edit': 'Redigera stopp',
|
||||
'tours.walk.importance.normal': 'Vanlig',
|
||||
'tours.walk.importance.optional': 'Valfri',
|
||||
'tours.walk.importance.must': 'Måste ses',
|
||||
'tours.walk.importanceHint.normal': 'Besöks under promenaden.',
|
||||
'tours.walk.importanceHint.optional': 'Kan strykas om tiden blir knapp.',
|
||||
'tours.walk.importanceHint.must': 'Ett senare förslag behåller den i promenaden.',
|
||||
'tours.walk.timeEstimated': 'Beräknad gångtid',
|
||||
'tours.walk.timeEstimatedShort': 'Gång',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Hur gångtiden räknas fram',
|
||||
'tours.walk.timeEstimatedInfo': 'Ruttplanerarens gångtid mellan stoppen, utan vistelserna.',
|
||||
'tours.walk.stays': 'Vistelser',
|
||||
'tours.walk.totalAtLeast': 'minst {time}',
|
||||
'tours.planner.tourType': 'Turtyp',
|
||||
'tours.paddle.boat': 'Båt',
|
||||
'tours.paddle.boat.kayak': 'Kajak',
|
||||
|
||||
@@ -443,6 +443,38 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'ผ่านบันไดเฉพาะเมื่อไม่มีทางอ้อม',
|
||||
'tours.preferences.avoid_ferries': 'หลีกเลี่ยงเรือข้ามฟาก',
|
||||
'tours.preferences.avoid_ferriesHint': 'ไปทางบกเมื่อมีทางอ้อม แม้จะไกลกว่า',
|
||||
'tours.planner.tourTypeHint.walk': 'เดินเท้าจากจุดแวะหนึ่งไปอีกจุด ไม่มีขีดจำกัดเส้นทางเดินป่า',
|
||||
'tours.poi.cat.museum': 'พิพิธภัณฑ์และแกลเลอรี',
|
||||
'tours.poi.cat.park': 'สวนสาธารณะและสวน',
|
||||
'tours.poi.cat.cafe': 'ร้านกาแฟ',
|
||||
'tours.poi.cat.restaurant': 'ร้านอาหาร',
|
||||
'tours.poi.cat.market': 'ตลาด',
|
||||
'tours.walk.station.eyebrow': 'จุดแวะ',
|
||||
'tours.walk.station.unnamed': 'จุดแวะที่ไม่มีชื่อ',
|
||||
'tours.walk.station.name': 'ชื่อ',
|
||||
'tours.walk.station.namePlaceholder': 'ที่นี่มีอะไร',
|
||||
'tours.walk.station.stay': 'เวลาแวะพัก (นาที)',
|
||||
'tours.walk.station.stayHint': 'เว้นว่างหมายถึงยังไม่ทราบ ใส่ 0 สำหรับจุดที่แค่เดินผ่าน',
|
||||
'tours.walk.station.stayInvalid': 'กรอกเป็นนาทีเต็ม ไม่เกินหนึ่งวัน',
|
||||
'tours.walk.station.stayUnknown': 'ยังไม่ทราบ',
|
||||
'tours.walk.station.stayUnknownShort': 'ยังไม่ระบุเวลาแวะ',
|
||||
'tours.walk.station.passThrough': 'แค่เดินผ่าน',
|
||||
'tours.walk.station.importance': 'ความสำคัญ',
|
||||
'tours.walk.station.protected': 'ป้องกันไว้',
|
||||
'tours.walk.station.protectedHint': 'การเปลี่ยนแปลงที่เสนอจะคงจุดแวะนี้ไว้ที่เดิม คุณยังแก้ไขเองได้',
|
||||
'tours.walk.station.edit': 'แก้ไขจุดแวะ',
|
||||
'tours.walk.importance.normal': 'ปกติ',
|
||||
'tours.walk.importance.optional': 'ไม่บังคับ',
|
||||
'tours.walk.importance.must': 'ต้องไป',
|
||||
'tours.walk.importanceHint.normal': 'แวะตามเส้นทางเดิน',
|
||||
'tours.walk.importanceHint.optional': 'ข้ามได้หากเวลาไม่พอ',
|
||||
'tours.walk.importanceHint.must': 'การเปลี่ยนแปลงที่เสนอภายหลังจะคงไว้ในทริป',
|
||||
'tours.walk.timeEstimated': 'เวลาเดินโดยประมาณ',
|
||||
'tours.walk.timeEstimatedShort': 'เดิน',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'วิธีคำนวณเวลาเดิน',
|
||||
'tours.walk.timeEstimatedInfo': 'เวลาเดินระหว่างจุดแวะจากตัวคำนวณเส้นทาง ไม่รวมเวลาแวะพัก',
|
||||
'tours.walk.stays': 'เวลาแวะพัก',
|
||||
'tours.walk.totalAtLeast': 'อย่างน้อย {time}',
|
||||
'tours.planner.tourType': 'ประเภททริป',
|
||||
'tours.paddle.boat': 'เรือ',
|
||||
'tours.paddle.boat.kayak': 'เรือคายัก',
|
||||
|
||||
@@ -20,7 +20,7 @@ const tokens = (value: string) => [...value.matchAll(/\{[^{}]+\}/g)].map((match)
|
||||
// placeholder spec; here only the general keys are.
|
||||
const groups = pluralGroups(Object.keys(english));
|
||||
const generalKeys = (keys: string[]) => keys.filter((key) => !pluralFormOf(key, groups));
|
||||
const GENERAL_KEY_COUNT = 703;
|
||||
const GENERAL_KEY_COUNT = 735;
|
||||
|
||||
function literalKeys(source: string): string[] {
|
||||
const tree = ts.createSourceFile('locale.ts', source, ts.ScriptTarget.Latest, true);
|
||||
|
||||
@@ -462,6 +462,39 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Merdiven yalnızca dolaşacak yol yoksa.',
|
||||
'tours.preferences.avoid_ferries': 'Feribotlardan kaçın',
|
||||
'tours.preferences.avoid_ferriesHint': 'Dolaşacak yol varsa daha uzun olsa da karadan.',
|
||||
'tours.planner.tourTypeHint.walk': 'Duraktan durağa yürüyerek, yürüyüş sınırı olmadan',
|
||||
'tours.poi.cat.museum': 'Müzeler ve galeriler',
|
||||
'tours.poi.cat.park': 'Parklar ve bahçeler',
|
||||
'tours.poi.cat.cafe': 'Kafeler',
|
||||
'tours.poi.cat.restaurant': 'Yemek yerleri',
|
||||
'tours.poi.cat.market': 'Pazarlar',
|
||||
'tours.walk.station.eyebrow': 'Durak',
|
||||
'tours.walk.station.unnamed': 'Adsız durak',
|
||||
'tours.walk.station.name': 'Ad',
|
||||
'tours.walk.station.namePlaceholder': 'Burada ne var',
|
||||
'tours.walk.station.stay': 'Kalış süresi (dakika)',
|
||||
'tours.walk.station.stayHint': 'Boş, henüz bilinmiyor demektir; yalnızca geçtiğin bir nokta için 0.',
|
||||
'tours.walk.station.stayInvalid': 'Tam dakika gir, en fazla bir gün.',
|
||||
'tours.walk.station.stayUnknown': 'Henüz bilinmiyor',
|
||||
'tours.walk.station.stayUnknownShort': 'Kalış belirsiz',
|
||||
'tours.walk.station.passThrough': 'Sadece geçiş',
|
||||
'tours.walk.station.importance': 'Önem',
|
||||
'tours.walk.station.protected': 'Korunuyor',
|
||||
'tours.walk.station.protectedHint':
|
||||
'Önerilen bir değişiklik bu durağı yerinde bırakır. Sen yine de düzenleyebilirsin.',
|
||||
'tours.walk.station.edit': 'Durağı düzenle',
|
||||
'tours.walk.importance.normal': 'Olağan',
|
||||
'tours.walk.importance.optional': 'İsteğe bağlı',
|
||||
'tours.walk.importance.must': 'Mutlaka görülmeli',
|
||||
'tours.walk.importanceHint.normal': 'Yürüyüş akışında uğranır.',
|
||||
'tours.walk.importanceHint.optional': 'Zaman daralırsa atlanabilir.',
|
||||
'tours.walk.importanceHint.must': 'Sonradan önerilen bir değişiklik onu yürüyüşte tutar.',
|
||||
'tours.walk.timeEstimated': 'Tahmini yürüme süresi',
|
||||
'tours.walk.timeEstimatedShort': 'Yürüme',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Yürüme süresi nasıl hesaplanır',
|
||||
'tours.walk.timeEstimatedInfo': 'Rota hesaplayıcının duraklar arasındaki yürüme süresi, kalışlar hariç.',
|
||||
'tours.walk.stays': 'Kalışlar',
|
||||
'tours.walk.totalAtLeast': 'en az {time}',
|
||||
'tours.planner.tourType': 'Tur türü',
|
||||
'tours.paddle.boat': 'Tekne',
|
||||
'tours.paddle.boat.kayak': 'Kano (kayak)',
|
||||
|
||||
@@ -474,6 +474,39 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Сходи лише там, де їх не обійти.',
|
||||
'tours.preferences.avoid_ferries': 'Уникати поромів',
|
||||
'tours.preferences.avoid_ferriesHint': 'Суходолом, де є обхід, навіть якщо він довший.',
|
||||
'tours.planner.tourTypeHint.walk': 'Пішки від зупинки до зупинки, без обмеження за складністю',
|
||||
'tours.poi.cat.museum': 'Музеї та галереї',
|
||||
'tours.poi.cat.park': 'Парки та сади',
|
||||
'tours.poi.cat.cafe': "Кав'ярні",
|
||||
'tours.poi.cat.restaurant': 'Де поїсти',
|
||||
'tours.poi.cat.market': 'Ринки',
|
||||
'tours.walk.station.eyebrow': 'Зупинка',
|
||||
'tours.walk.station.unnamed': 'Зупинка без назви',
|
||||
'tours.walk.station.name': 'Назва',
|
||||
'tours.walk.station.namePlaceholder': 'Що тут',
|
||||
'tours.walk.station.stay': 'Перебування у хвилинах',
|
||||
'tours.walk.station.stayHint': 'Порожньо означає поки невідомо; 0 для точки, яку ти лише проходиш.',
|
||||
'tours.walk.station.stayInvalid': 'Введи цілі хвилини, не більше доби.',
|
||||
'tours.walk.station.stayUnknown': 'Поки невідомо',
|
||||
'tours.walk.station.stayUnknownShort': 'Перебування невідоме',
|
||||
'tours.walk.station.passThrough': 'Лише мимо',
|
||||
'tours.walk.station.importance': 'Важливість',
|
||||
'tours.walk.station.protected': 'Захищена',
|
||||
'tours.walk.station.protectedHint':
|
||||
'Запропонована зміна залишить цю зупинку на місці. Сам ти все ще можеш її редагувати.',
|
||||
'tours.walk.station.edit': 'Редагувати зупинку',
|
||||
'tours.walk.importance.normal': 'Звичайна',
|
||||
'tours.walk.importance.optional': "Необов'язкова",
|
||||
'tours.walk.importance.must': "Обов'язково",
|
||||
'tours.walk.importanceHint.normal': 'Відвідується по ходу прогулянки.',
|
||||
'tours.walk.importanceHint.optional': 'Можна пропустити, якщо бракує часу.',
|
||||
'tours.walk.importanceHint.must': 'Запропонована пізніше зміна залишить її у прогулянці.',
|
||||
'tours.walk.timeEstimated': 'Орієнтовний час ходьби',
|
||||
'tours.walk.timeEstimatedShort': 'Ходьба',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Як рахується час ходьби',
|
||||
'tours.walk.timeEstimatedInfo': 'Час пішки між зупинками за розрахунком маршруту, без перебування.',
|
||||
'tours.walk.stays': 'Перебування',
|
||||
'tours.walk.totalAtLeast': 'щонайменше {time}',
|
||||
'tours.planner.tourType': 'Тип туру',
|
||||
'tours.paddle.boat': 'Човен',
|
||||
'tours.paddle.boat.kayak': 'Каяк',
|
||||
|
||||
@@ -460,6 +460,38 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': 'Chỉ đi bậc thang khi không có đường vòng.',
|
||||
'tours.preferences.avoid_ferries': 'Tránh phà',
|
||||
'tours.preferences.avoid_ferriesHint': 'Đi đường bộ nơi có đường vòng, kể cả khi dài hơn.',
|
||||
'tours.planner.tourTypeHint.walk': 'Đi bộ từ điểm dừng này sang điểm dừng khác, không giới hạn leo núi',
|
||||
'tours.poi.cat.museum': 'Bảo tàng và phòng tranh',
|
||||
'tours.poi.cat.park': 'Công viên và vườn',
|
||||
'tours.poi.cat.cafe': 'Quán cà phê',
|
||||
'tours.poi.cat.restaurant': 'Chỗ ăn uống',
|
||||
'tours.poi.cat.market': 'Chợ',
|
||||
'tours.walk.station.eyebrow': 'Điểm dừng',
|
||||
'tours.walk.station.unnamed': 'Điểm dừng chưa đặt tên',
|
||||
'tours.walk.station.name': 'Tên',
|
||||
'tours.walk.station.namePlaceholder': 'Ở đây có gì',
|
||||
'tours.walk.station.stay': 'Thời gian dừng (phút)',
|
||||
'tours.walk.station.stayHint': 'Để trống nghĩa là chưa biết; nhập 0 cho điểm chỉ đi ngang qua.',
|
||||
'tours.walk.station.stayInvalid': 'Nhập số phút nguyên, tối đa một ngày.',
|
||||
'tours.walk.station.stayUnknown': 'Chưa biết',
|
||||
'tours.walk.station.stayUnknownShort': 'Chưa rõ thời gian dừng',
|
||||
'tours.walk.station.passThrough': 'Chỉ đi qua',
|
||||
'tours.walk.station.importance': 'Mức độ quan trọng',
|
||||
'tours.walk.station.protected': 'Được bảo vệ',
|
||||
'tours.walk.station.protectedHint': 'Thay đổi được đề xuất sẽ giữ nguyên điểm dừng này. Bạn vẫn có thể tự chỉnh sửa.',
|
||||
'tours.walk.station.edit': 'Sửa điểm dừng',
|
||||
'tours.walk.importance.normal': 'Bình thường',
|
||||
'tours.walk.importance.optional': 'Tùy chọn',
|
||||
'tours.walk.importance.must': 'Nhất định phải đến',
|
||||
'tours.walk.importanceHint.normal': 'Ghé thăm theo lộ trình đi bộ.',
|
||||
'tours.walk.importanceHint.optional': 'Có thể bỏ qua khi thiếu thời gian.',
|
||||
'tours.walk.importanceHint.must': 'Thay đổi đề xuất sau này vẫn giữ điểm này.',
|
||||
'tours.walk.timeEstimated': 'Thời gian đi bộ ước tính',
|
||||
'tours.walk.timeEstimatedShort': 'Đi bộ',
|
||||
'tours.walk.timeEstimatedInfoLabel': 'Cách tính thời gian đi bộ',
|
||||
'tours.walk.timeEstimatedInfo': 'Thời gian đi bộ giữa các điểm dừng do bộ định tuyến tính, không gồm thời gian dừng.',
|
||||
'tours.walk.stays': 'Thời gian dừng',
|
||||
'tours.walk.totalAtLeast': 'ít nhất {time}',
|
||||
'tours.planner.tourType': 'Loại chuyến',
|
||||
'tours.paddle.boat': 'Thuyền',
|
||||
'tours.paddle.boat.kayak': 'Thuyền kayak',
|
||||
|
||||
@@ -428,6 +428,38 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': '只在無法繞行時經過階梯。',
|
||||
'tours.preferences.avoid_ferries': '避開渡輪',
|
||||
'tours.preferences.avoid_ferriesHint': '有繞行陸路時走陸路,即使更遠。',
|
||||
'tours.planner.tourTypeHint.walk': '從一站步行到下一站,不設健行難度限制',
|
||||
'tours.poi.cat.museum': '博物館和畫廊',
|
||||
'tours.poi.cat.park': '公園和花園',
|
||||
'tours.poi.cat.cafe': '咖啡館',
|
||||
'tours.poi.cat.restaurant': '餐館',
|
||||
'tours.poi.cat.market': '市集',
|
||||
'tours.walk.station.eyebrow': '站點',
|
||||
'tours.walk.station.unnamed': '未命名站點',
|
||||
'tours.walk.station.name': '名稱',
|
||||
'tours.walk.station.namePlaceholder': '這裡有什麼',
|
||||
'tours.walk.station.stay': '停留時間(分鐘)',
|
||||
'tours.walk.station.stayHint': '留空表示尚不清楚;只經過的地點填 0。',
|
||||
'tours.walk.station.stayInvalid': '請輸入整數分鐘,最多一天。',
|
||||
'tours.walk.station.stayUnknown': '尚不清楚',
|
||||
'tours.walk.station.stayUnknownShort': '停留時間未定',
|
||||
'tours.walk.station.passThrough': '僅經過',
|
||||
'tours.walk.station.importance': '重要程度',
|
||||
'tours.walk.station.protected': '受保護',
|
||||
'tours.walk.station.protectedHint': '提議的變更會保留此站點原位。你自己仍可編輯。',
|
||||
'tours.walk.station.edit': '編輯站點',
|
||||
'tours.walk.importance.normal': '普通',
|
||||
'tours.walk.importance.optional': '可選',
|
||||
'tours.walk.importance.must': '必去',
|
||||
'tours.walk.importanceHint.normal': '按路線順路遊覽。',
|
||||
'tours.walk.importanceHint.optional': '時間緊時可以跳過。',
|
||||
'tours.walk.importanceHint.must': '之後提議的變更會保留它。',
|
||||
'tours.walk.timeEstimated': '預估步行時間',
|
||||
'tours.walk.timeEstimatedShort': '步行',
|
||||
'tours.walk.timeEstimatedInfoLabel': '步行時間如何計算',
|
||||
'tours.walk.timeEstimatedInfo': '路線規劃給出的站點間步行時間,不含停留時間。',
|
||||
'tours.walk.stays': '停留',
|
||||
'tours.walk.totalAtLeast': '至少 {time}',
|
||||
'tours.planner.tourType': '路線類型',
|
||||
'tours.paddle.boat': '船隻',
|
||||
'tours.paddle.boat.kayak': '獨木舟(Kayak)',
|
||||
|
||||
@@ -429,6 +429,38 @@ const tours: TranslationStrings = {
|
||||
'tours.preferences.avoid_stepsHint': '只在无法绕行时经过台阶。',
|
||||
'tours.preferences.avoid_ferries': '避开渡轮',
|
||||
'tours.preferences.avoid_ferriesHint': '有绕行陆路时走陆路,即使更远。',
|
||||
'tours.planner.tourTypeHint.walk': '从一站步行到下一站,不设徒步难度限制',
|
||||
'tours.poi.cat.museum': '博物馆和画廊',
|
||||
'tours.poi.cat.park': '公园和花园',
|
||||
'tours.poi.cat.cafe': '咖啡馆',
|
||||
'tours.poi.cat.restaurant': '餐馆',
|
||||
'tours.poi.cat.market': '集市',
|
||||
'tours.walk.station.eyebrow': '站点',
|
||||
'tours.walk.station.unnamed': '未命名站点',
|
||||
'tours.walk.station.name': '名称',
|
||||
'tours.walk.station.namePlaceholder': '这里有什么',
|
||||
'tours.walk.station.stay': '停留时间(分钟)',
|
||||
'tours.walk.station.stayHint': '留空表示尚不清楚;只经过的地点填 0。',
|
||||
'tours.walk.station.stayInvalid': '请输入整数分钟,最多一天。',
|
||||
'tours.walk.station.stayUnknown': '尚不清楚',
|
||||
'tours.walk.station.stayUnknownShort': '停留时间未定',
|
||||
'tours.walk.station.passThrough': '仅经过',
|
||||
'tours.walk.station.importance': '重要程度',
|
||||
'tours.walk.station.protected': '受保护',
|
||||
'tours.walk.station.protectedHint': '提议的更改会保留此站点原位。你自己仍可编辑。',
|
||||
'tours.walk.station.edit': '编辑站点',
|
||||
'tours.walk.importance.normal': '普通',
|
||||
'tours.walk.importance.optional': '可选',
|
||||
'tours.walk.importance.must': '必去',
|
||||
'tours.walk.importanceHint.normal': '按路线顺路游览。',
|
||||
'tours.walk.importanceHint.optional': '时间紧时可以跳过。',
|
||||
'tours.walk.importanceHint.must': '之后提议的更改会保留它。',
|
||||
'tours.walk.timeEstimated': '预计步行时间',
|
||||
'tours.walk.timeEstimatedShort': '步行',
|
||||
'tours.walk.timeEstimatedInfoLabel': '步行时间如何计算',
|
||||
'tours.walk.timeEstimatedInfo': '路线规划给出的站点间步行时间,不含停留时间。',
|
||||
'tours.walk.stays': '停留',
|
||||
'tours.walk.totalAtLeast': '至少 {time}',
|
||||
'tours.planner.tourType': '路线类型',
|
||||
'tours.paddle.boat': '船只',
|
||||
'tours.paddle.boat.kayak': '皮划艇',
|
||||
|
||||
Reference in New Issue
Block a user