diff --git a/client/src/components/Tours/GpxImportTypeSection.tsx b/client/src/components/Tours/GpxImportTypeSection.tsx
index 85bbb1e8e..8e30ab01d 100644
--- a/client/src/components/Tours/GpxImportTypeSection.tsx
+++ b/client/src/components/Tours/GpxImportTypeSection.tsx
@@ -11,6 +11,7 @@ import { useTranslation } from '../../i18n';
import { LABEL, Segmented } from '../shared/dialogParts';
import { DialogSection } from '../shared/DialogShell';
import type { GpxImportChoicesState } from './gpxImportChoices';
+import { RecordedRideFacts } from './horse/RecordedRideFacts';
import { TourTypeSelect } from './planner/TourTypeSelect';
import { RunProfileField } from './run/RunFields';
import { SkiClassificationFields } from './ski/SkiClassificationFields';
@@ -61,7 +62,8 @@ function PaddleImportFields({ choices }: { choices: GpxImportChoicesState }) {
/**
* The preview's "import as" section: the type, and below it what that type
* names: a bike or run profile, a paddle tour's boat and water, a ski track's
- * discipline and technique (SKI-02).
+ * discipline and technique (SKI-02), and for a ride (HOR-02) what the import
+ * keeps and does not work out.
*/
export function GpxImportTypeSection({ choices }: { choices: GpxImportChoicesState }) {
const { t } = useTranslation();
@@ -86,6 +88,11 @@ export function GpxImportTypeSection({ choices }: { choices: GpxImportChoicesSta
{chosen.type === 'run' && }
{chosen.type === 'kayak' && }
{chosen.type === 'ski' && }
+ {chosen.type === 'horse' && (
+
> = {
@@ -329,6 +330,8 @@ function GpxViewRail({
{tour.tour_type === 'kayak' && (
)}
+ {/* HOR-02: a recorded ride says what the import did not do for it. */}
+ {tour.tour_type === 'horse' && }
} title={t('tours.planner.inspector.title')}>
{analysis ? (
diff --git a/server/tests/e2e/tours-horse-import.e2e.test.ts b/server/tests/e2e/tours-horse-import.e2e.test.ts
new file mode 100644
index 000000000..17cac472f
--- /dev/null
+++ b/server/tests/e2e/tours-horse-import.e2e.test.ts
@@ -0,0 +1,269 @@
+/**
+ * Tours e2e for rides taken from a GPX file (HOR-02): the canonical Tours GPX
+ * import, previewed and then confirmed as a ride, stored with its line as the
+ * file recorded it, its origin and only the measures the file carries, opened
+ * again and put on a day of the trip; a failed import leaves an existing ride
+ * as it was. Real JwtAuthGuard, AddonGuard and TripAccessGuard against a
+ * migrated and seeded temp SQLite db, as in tours-horse.e2e.test.ts; the
+ * permission check is a container spy and the broadcast goes to a
+ * FakeRealtimeService.
+ *
+ * Fixtures: user 1 owns trip 5 with day 3, user 2 is a member of it whom the
+ * permission spy denies 'place_edit'.
+ */
+import { DayAssignments } from '../../src/db/entities/DayAssignments.entity';
+import { Days } from '../../src/db/entities/Days.entity';
+import { Places } from '../../src/db/entities/Places.entity';
+import { Tours } from '../../src/db/entities/Tours.entity';
+import { Trips } from '../../src/db/entities/Trips.entity';
+import { AssignmentsModule } from '../../src/nest/assignments/assignments.module';
+import { TrekExceptionFilter } from '../../src/nest/common/trek-exception.filter';
+import { ZodValidationPipe } from '../../src/nest/common/zod-validation.pipe';
+import { JourneyDomainService } from '../../src/nest/journey/journey-domain.service';
+import { MapsService } from '../../src/nest/maps/maps.service';
+import { OverpassElementsClient } from '../../src/nest/overpass/overpass-elements.service';
+import { PermissionsService } from '../../src/nest/permissions/permissions.service';
+import { RealtimeModule } from '../../src/nest/realtime/realtime.module';
+import { RealtimeService } from '../../src/nest/realtime/realtime.service';
+import { ToursModule } from '../../src/nest/tours/tours.module';
+import { createSnapshotTestDb } from '../helpers/db-mock';
+import { countRows, deleteRows, findRow, insertRows } from '../helpers/factories/rows';
+import { setAddonEnabled } from '../helpers/factories/settings';
+import { addTripMember } from '../helpers/factories/trips';
+import { makeUser } from '../helpers/factories/users';
+import { FakeRealtimeService } from '../helpers/fake-realtime';
+import { createTestMikroOrmModule, createTestOrm, type TestOrm } from '../helpers/test-orm';
+import { TestUnitOfWorkModule } from '../helpers/test-uow';
+import { sessionCookie } from './harness';
+import type { NestExpressApplication } from '@nestjs/platform-express';
+import { Test } from '@nestjs/testing';
+
+import cookieParser from 'cookie-parser';
+import type { Server } from 'http';
+import request from 'supertest';
+import { afterAll, beforeAll, beforeEach, describe, expect, it, vi, type MockInstance } from 'vitest';
+
+vi.mock('../../src/nest/audit/audit-log.logger', () => ({
+ LOG_LEVEL: 'error',
+ logInfo: vi.fn(),
+ logDebug: vi.fn(),
+ logError: vi.fn(),
+ logWarn: vi.fn(),
+}));
+
+const { journeyHooks } = vi.hoisted(() => ({
+ journeyHooks: {
+ reconcileTripSkeletons: vi.fn().mockResolvedValue(undefined),
+ onPlaceCreated: vi.fn().mockResolvedValue(undefined),
+ onPlaceUpdated: vi.fn().mockResolvedValue(undefined),
+ onPlaceDeleted: vi.fn().mockResolvedValue(undefined),
+ },
+}));
+
+const db = createSnapshotTestDb();
+const realtime = new FakeRealtimeService();
+
+let orm: TestOrm;
+let checkPermission: MockInstance;
+
+const OWNER = 1;
+const VIEWER = 2;
+
+/** A ride as a watch records it: a few points, with heights. */
+const RECORDED = [
+ [47, 11, 600],
+ [47.01, 11.01, 640],
+ [47.02, 11.03, 610],
+];
+const RIDE_GPX = `
+Ausritt an der Isar
+${RECORDED.map(([lat, lon, ele]) => `${ele}`).join('\n')}
+`;
+/** One without heights: the import has nothing to say about them. */
+const FLAT_GPX = `
+Feldweg
+
+`;
+
+describe('Rides imported from GPX e2e (real guards + temp SQLite)', () => {
+ let server: Server;
+ let app: Awaited>;
+
+ async function build() {
+ const moduleRef = await Test.createTestingModule({
+ imports: [
+ await TestUnitOfWorkModule.forRoot(db),
+ await createTestMikroOrmModule(db),
+ RealtimeModule,
+ ToursModule,
+ AssignmentsModule,
+ ],
+ })
+ .overrideProvider(RealtimeService)
+ .useValue(realtime)
+ .overrideProvider(JourneyDomainService)
+ .useValue(journeyHooks)
+ .overrideProvider(MapsService)
+ .useValue({ pois: vi.fn() })
+ .overrideProvider(OverpassElementsClient)
+ // An import asks OpenStreetMap nothing: any call here would be a bug.
+ .useValue({ query: vi.fn().mockRejectedValue(new Error('no network in a test')) })
+ .compile();
+ const nest = moduleRef.createNestApplication();
+ nest.use(cookieParser());
+ nest.useGlobalPipes(new ZodValidationPipe());
+ nest.useGlobalFilters(new TrekExceptionFilter());
+ await nest.init();
+ return nest;
+ }
+
+ beforeAll(async () => {
+ orm = await createTestOrm(db);
+ // Pinned ids: the session cookies sign for exactly these users.
+ await makeUser(orm, { id: 1, username: 'owner', email: 'owner@example.test', role: 'user', password_version: 0 });
+ await makeUser(orm, { id: 2, username: 'viewer', email: 'viewer@example.test', role: 'user', password_version: 0 });
+ await insertRows(orm, Trips, [{ id: 5, user: 1, title: 'Isar' }]);
+ await addTripMember(orm, 5, 2);
+ await insertRows(orm, Days, [{ id: 3, trip: 5, day_number: 1, date: '2026-07-10' }]);
+ app = await build();
+ checkPermission = vi.spyOn(app.get(PermissionsService), 'checkPermission');
+ server = app.getHttpServer();
+ });
+
+ beforeEach(async () => {
+ checkPermission.mockImplementation(
+ (action: string, _role: string, _owner: number, userId: number) =>
+ !((action === 'place_edit' || action === 'day_edit') && userId === VIEWER),
+ );
+ await setAddonEnabled(orm, 'tours', true);
+ realtime.broadcastMock.mockClear();
+ await deleteRows(orm, DayAssignments);
+ await deleteRows(orm, Places);
+ });
+
+ afterAll(async () => {
+ await app.close();
+ await orm.close();
+ });
+
+ const upload = (
+ path: 'import/gpx' | 'import/gpx/preview',
+ xml: string,
+ fields: Record = {},
+ userId = OWNER,
+ ) => {
+ let req = request(server).post(`/api/trips/5/tours/${path}`).set('Cookie', sessionCookie(userId));
+ for (const [key, value] of Object.entries(fields)) req = req.field(key, value);
+ return req.attach('file', Buffer.from(xml), { filename: 'ride.gpx', contentType: 'application/gpx+xml' });
+ };
+ const importRide = async (xml = RIDE_GPX) => {
+ const res = await upload('import/gpx', xml, { tour_type: 'horse' });
+ expect(res.status).toBe(201);
+ return res.body.tours[0].place_id as number;
+ };
+
+ it('HORSE-IMPORT-E2E-001: the preview measures the file and stores nothing', async () => {
+ const res = await upload('import/gpx/preview', RIDE_GPX);
+ expect(res.status).toBe(200);
+ expect(res.body.tracks).toHaveLength(1);
+ expect(res.body.tracks[0]).toMatchObject({ name: 'Ausritt an der Isar', point_count: 3, duplicate: false });
+ expect(res.body.tracks[0].elevation_gain_m).toBeCloseTo(40);
+ expect(res.body.tracks[0].elevation_loss_m).toBeCloseTo(30);
+ expect(await countRows(orm, Tours)).toBe(0);
+ expect(await countRows(orm, Places)).toBe(0);
+ });
+
+ it('HORSE-IMPORT-E2E-002: confirmed as a ride, the line stays as recorded with its origin, heights and no riding time', async () => {
+ const placeId = await importRide();
+ const place = await findRow(orm, Places, { id: placeId });
+ expect(JSON.parse(String(place?.route_geometry))).toEqual(RECORDED);
+ expect(await findRow(orm, Tours, { place: placeId })).toMatchObject({
+ tour_type: 'horse',
+ origin: 'gpx',
+ origin_file_name: 'ride.gpx',
+ duration: null,
+ planned_duration_minutes: null,
+ max_hiking_difficulty: null,
+ bike_profile: null,
+ boat_type: null,
+ });
+ expect(realtime.broadcastMock.mock.calls.map((call) => call[1])).toEqual(
+ expect.arrayContaining(['tours:changed', 'place:created']),
+ );
+ });
+
+ it('HORSE-IMPORT-E2E-003: opens again as a ride, naming the file it came from, with nothing routed', async () => {
+ const placeId = await importRide();
+ const res = await request(server).get(`/api/trips/5/tours/${placeId}`).set('Cookie', sessionCookie(VIEWER));
+ expect(res.status).toBe(200);
+ expect(res.body.tour).toMatchObject({ tour_type: 'horse', origin: 'gpx', duration: null, caution: false });
+ expect(res.body.tour.elevation_gain).toBeCloseTo(40);
+ expect(res.body.provenance).toMatchObject({
+ origin: 'gpx',
+ source: { kind: 'gpx', fileName: 'ride.gpx' },
+ plannedOver: false,
+ });
+ // The two ends of the track stand for its points; no leg was planned or taken from a route.
+ expect(res.body.waypoints).toEqual([
+ { lat: 47, lng: 11, role: 'start', sequence: 0 },
+ { lat: 47.02, lng: 11.03, role: 'end', sequence: 1 },
+ ]);
+ });
+
+ it('HORSE-IMPORT-E2E-004: a file without heights keeps them unknown and says so, never zero', async () => {
+ const res = await upload('import/gpx', FLAT_GPX, { tour_type: 'horse' });
+ expect(res.status).toBe(201);
+ expect(res.body.caution).toBe(true);
+ expect(res.body.tours[0]).toMatchObject({
+ tour_type: 'horse',
+ elevation_gain: null,
+ elevation_loss: null,
+ match_confidence: 0.3,
+ });
+ expect(res.body.tours[0].distance).toBeGreaterThan(0);
+ });
+
+ it('HORSE-IMPORT-E2E-005: goes on a day of the trip like any tour', async () => {
+ const placeId = await importRide();
+ const assigned = await request(server)
+ .post('/api/trips/5/days/3/assignments')
+ .set('Cookie', sessionCookie(OWNER))
+ .send({ place_id: placeId });
+ expect(assigned.status).toBe(201);
+ const list = await request(server).get('/api/trips/5/tours').set('Cookie', sessionCookie(OWNER));
+ expect(list.status).toBe(200);
+ expect(list.body.tours.find((tour: { place_id: number }) => tour.place_id === placeId)).toMatchObject({
+ tour_type: 'horse',
+ planned: true,
+ });
+ });
+
+ it('HORSE-IMPORT-E2E-006: a failed import leaves the rides there are as they were', async () => {
+ const placeId = await importRide();
+ const before = await findRow(orm, Tours, { place: placeId });
+ const placeBefore = await findRow(orm, Places, { id: placeId });
+
+ const refusals = [
+ // No track in the file.
+ await upload('import/gpx', '', { tour_type: 'horse' }),
+ // A field of another type on a ride.
+ await upload('import/gpx', FLAT_GPX, { tour_type: 'horse', bike_profile: 'road' }),
+ // A member who may only read.
+ await upload('import/gpx', FLAT_GPX, { tour_type: 'horse' }, VIEWER),
+ ];
+ expect(refusals.map((res) => res.status)).toEqual([400, 400, 403]);
+
+ expect(await countRows(orm, Tours)).toBe(1);
+ expect(await countRows(orm, Places)).toBe(1);
+ expect(await findRow(orm, Tours, { place: placeId })).toEqual(before);
+ expect(await findRow(orm, Places, { id: placeId })).toEqual(placeBefore);
+ });
+
+ it('HORSE-IMPORT-E2E-007: the same recorded ride again is skipped, not stored twice', async () => {
+ await importRide();
+ const again = await upload('import/gpx', RIDE_GPX, { tour_type: 'horse' });
+ expect(again.status).toBe(201);
+ expect(again.body).toEqual({ tours: [], caution: false, skipped: 1 });
+ expect(await countRows(orm, Tours)).toBe(1);
+ });
+});
diff --git a/shared/src/i18n/ar/tours.ts b/shared/src/i18n/ar/tours.ts
index a06bf8cec..f1cab1545 100644
--- a/shared/src/i18n/ar/tours.ts
+++ b/shared/src/i18n/ar/tours.ts
@@ -1095,5 +1095,13 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'مقطع من مسار فروسية معلّم من OpenStreetMap. وصول الخيل: {access}',
'tours.horse.leg.manual': 'يدوي، غير مُتحقق منه',
'tours.horse.leg.manualInfo': 'مرسوم باليد، مستقيم. لم يتحقق منه أي مسار فروسية ولا أي مخطط مسارات.',
+ 'tours.horse.recorded.title': 'جولة مسجّلة',
+ 'tours.horse.recorded.asRecorded': 'كما سُجّلت',
+ 'tours.horse.recorded.asRecordedInfo': 'يبقى المسار كما سجّله الملف. لا يُعاد تخطيط أي جزء منه.',
+ 'tours.horse.recorded.noTime': 'بلا وقت ركوب',
+ 'tours.horse.recorded.noTimeInfo': 'لا يحسب TREK وقت ركوب للجولة: الإيقاع يحدده الحصان والفارس.',
+ 'tours.horse.recorded.accessUnchecked': 'الوصول غير مُتحقق منه',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'لا يتحقق الاستيراد مما إذا كان يُسمح بركوب الطرق. العبرة باللافتات في المكان.',
};
export default tours;
diff --git a/shared/src/i18n/az/tours.ts b/shared/src/i18n/az/tours.ts
index d61282ad4..9693bd0b9 100644
--- a/shared/src/i18n/az/tours.ts
+++ b/shared/src/i18n/az/tours.ts
@@ -1061,5 +1061,13 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'OpenStreetMap-dən nişanlanmış atçılıq marşrutunun hissəsi. At üçün giriş: {access}',
'tours.horse.leg.manual': 'Əl ilə, yoxlanılmayıb',
'tours.horse.leg.manualInfo': 'Əl ilə, düz çəkilib. Nə atçılıq marşrutu, nə də marşrut planlayıcısı yoxlayıb.',
+ 'tours.horse.recorded.title': 'Qeydə alınmış gəzinti',
+ 'tours.horse.recorded.asRecorded': 'Qeydə alındığı kimi',
+ 'tours.horse.recorded.asRecordedInfo': 'Xətt faylın qeydə aldığı kimi qalır. Heç nə yenidən planlanmır.',
+ 'tours.horse.recorded.noTime': 'Sürmə vaxtı yoxdur',
+ 'tours.horse.recorded.noTimeInfo': 'TREK at gəzintisi üçün sürmə vaxtı hesablamır: tempi at və atlı müəyyən edir.',
+ 'tours.horse.recorded.accessUnchecked': 'Giriş yoxlanılmayıb',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'İdxal yollarda at sürməyə icazə olub-olmadığını yoxlamır. Yerdəki lövhələr əsasdır.',
};
export default tours;
diff --git a/shared/src/i18n/br/tours.ts b/shared/src/i18n/br/tours.ts
index 6a023682e..482cd5ce9 100644
--- a/shared/src/i18n/br/tours.ts
+++ b/shared/src/i18n/br/tours.ts
@@ -1071,5 +1071,14 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'Trecho de uma rota equestre sinalizada do OpenStreetMap. Acesso a cavalo: {access}',
'tours.horse.leg.manual': 'Manual, não verificado',
'tours.horse.leg.manualInfo': 'Traçado à mão, em linha reta. Nenhuma rota equestre e nenhum roteador o verificou.',
+ 'tours.horse.recorded.title': 'Passeio gravado',
+ 'tours.horse.recorded.asRecorded': 'Como gravado',
+ 'tours.horse.recorded.asRecordedInfo': 'A linha fica como o arquivo a gravou. Nada é roteado de novo.',
+ 'tours.horse.recorded.noTime': 'Sem tempo a cavalo',
+ 'tours.horse.recorded.noTimeInfo':
+ 'O TREK não calcula tempo a cavalo para um passeio: o ritmo é do cavalo e do cavaleiro.',
+ 'tours.horse.recorded.accessUnchecked': 'Acesso não verificado',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'A importação não verifica se as vias podem ser percorridas a cavalo. Valem as placas no local.',
};
export default tours;
diff --git a/shared/src/i18n/ca/tours.ts b/shared/src/i18n/ca/tours.ts
index 63f75ac88..1a244bff4 100644
--- a/shared/src/i18n/ca/tours.ts
+++ b/shared/src/i18n/ca/tours.ts
@@ -1074,5 +1074,15 @@ const tours: TranslationStrings = {
'tours.horse.leg.manual': 'Manual, sense comprovar',
'tours.horse.leg.manualInfo':
"Traçat a mà, en línia recta. Ni una ruta eqüestre ni un planificador no l'ha comprovat.",
+ 'tours.horse.recorded.title': 'Ruta enregistrada',
+ 'tours.horse.recorded.asRecorded': 'Tal com es va enregistrar',
+ 'tours.horse.recorded.asRecordedInfo':
+ 'La línia queda tal com la va enregistrar el fitxer. No es torna a calcular res.',
+ 'tours.horse.recorded.noTime': 'Sense temps a cavall',
+ 'tours.horse.recorded.noTimeInfo':
+ 'TREK no calcula temps a cavall per a una ruta: el ritme és del cavall i del genet.',
+ 'tours.horse.recorded.accessUnchecked': 'Accés sense comprovar',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'La importació no comprova si es pot anar a cavall pels camins. Valen els senyals sobre el terreny.',
};
export default tours;
diff --git a/shared/src/i18n/cs/tours.ts b/shared/src/i18n/cs/tours.ts
index 6c8c39678..7c3ee6558 100644
--- a/shared/src/i18n/cs/tours.ts
+++ b/shared/src/i18n/cs/tours.ts
@@ -1060,5 +1060,13 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'Úsek značené jezdecké trasy z OpenStreetMap. Přístup pro koně: {access}',
'tours.horse.leg.manual': 'Ručně, neověřeno',
'tours.horse.leg.manualInfo': 'Nakresleno ručně, rovně. Neověřila ho žádná jezdecká trasa ani plánovač.',
+ 'tours.horse.recorded.title': 'Zaznamenaná vyjížďka',
+ 'tours.horse.recorded.asRecorded': 'Jak bylo zaznamenáno',
+ 'tours.horse.recorded.asRecordedInfo': 'Trasa zůstává tak, jak ji soubor zaznamenal. Nic se znovu neplánuje.',
+ 'tours.horse.recorded.noTime': 'Bez doby jízdy',
+ 'tours.horse.recorded.noTimeInfo': 'TREK pro vyjížďku nepočítá dobu jízdy: tempo určuje kůň a jezdec.',
+ 'tours.horse.recorded.accessUnchecked': 'Přístup neověřen',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'Import neověřuje, zda se po cestách smí jezdit na koni. Platí značení na místě.',
};
export default tours;
diff --git a/shared/src/i18n/de/tours.ts b/shared/src/i18n/de/tours.ts
index 1a8b35c23..584d3a7b3 100644
--- a/shared/src/i18n/de/tours.ts
+++ b/shared/src/i18n/de/tours.ts
@@ -1077,6 +1077,16 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'Abschnitt einer ausgeschilderten Reitroute aus OpenStreetMap. Reitzugang: {access}',
'tours.horse.leg.manual': 'Manuell, ungeprüft',
'tours.horse.leg.manualInfo': 'Von Hand gezogen, gerade. Weder eine Reitroute noch ein Router hat ihn geprüft.',
+ 'tours.horse.recorded.title': 'Aufgezeichneter Ausritt',
+ 'tours.horse.recorded.asRecorded': 'Wie aufgezeichnet',
+ 'tours.horse.recorded.asRecordedInfo':
+ 'Die Linie bleibt, wie die Datei sie aufgezeichnet hat. Nichts wird neu geplant.',
+ 'tours.horse.recorded.noTime': 'Keine Reitzeit',
+ 'tours.horse.recorded.noTimeInfo':
+ 'TREK berechnet für einen Ausritt keine Reitzeit: Das Tempo bestimmen Pferd und Reiter.',
+ 'tours.horse.recorded.accessUnchecked': 'Zugang nicht geprüft',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'Der Import prüft nicht, ob die Wege geritten werden dürfen. Es gilt die Beschilderung vor Ort.',
};
export default tours;
diff --git a/shared/src/i18n/en/tours.ts b/shared/src/i18n/en/tours.ts
index 3a4e0c3de..a6093ce12 100644
--- a/shared/src/i18n/en/tours.ts
+++ b/shared/src/i18n/en/tours.ts
@@ -1048,5 +1048,14 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'A section of a signposted horse route from OpenStreetMap. Riding access: {access}',
'tours.horse.leg.manual': 'Manual, unchecked',
'tours.horse.leg.manualInfo': 'Drawn by hand, straight. No horse route and no router checked it.',
+ 'tours.horse.recorded.title': 'Recorded ride',
+ 'tours.horse.recorded.asRecorded': 'As recorded',
+ 'tours.horse.recorded.asRecordedInfo': 'The line stays as the file recorded it. Nothing is routed again.',
+ 'tours.horse.recorded.noTime': 'No riding time',
+ 'tours.horse.recorded.noTimeInfo':
+ "TREK works out no riding time for a ride: the pace is the horse's and the rider's.",
+ 'tours.horse.recorded.accessUnchecked': 'Access not checked',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'The import does not check whether the ways may be ridden. The signs on site count.',
};
export default tours;
diff --git a/shared/src/i18n/es/tours.ts b/shared/src/i18n/es/tours.ts
index 290ab5576..15738b901 100644
--- a/shared/src/i18n/es/tours.ts
+++ b/shared/src/i18n/es/tours.ts
@@ -1069,5 +1069,14 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'Tramo de una ruta ecuestre señalizada de OpenStreetMap. Acceso a caballo: {access}',
'tours.horse.leg.manual': 'Manual, sin comprobar',
'tours.horse.leg.manualInfo': 'Trazado a mano, en línea recta. Ni una ruta ecuestre ni un planificador lo comprobó.',
+ 'tours.horse.recorded.title': 'Ruta grabada',
+ 'tours.horse.recorded.asRecorded': 'Tal como se grabó',
+ 'tours.horse.recorded.asRecordedInfo': 'La línea queda tal como la grabó el archivo. No se vuelve a calcular nada.',
+ 'tours.horse.recorded.noTime': 'Sin tiempo a caballo',
+ 'tours.horse.recorded.noTimeInfo':
+ 'TREK no calcula tiempo a caballo para una ruta: el ritmo es del caballo y del jinete.',
+ 'tours.horse.recorded.accessUnchecked': 'Acceso sin comprobar',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'La importación no comprueba si se puede ir a caballo por las vías. Valen las señales sobre el terreno.',
};
export default tours;
diff --git a/shared/src/i18n/et/tours.ts b/shared/src/i18n/et/tours.ts
index 9d3f5dc74..9d4b1ca16 100644
--- a/shared/src/i18n/et/tours.ts
+++ b/shared/src/i18n/et/tours.ts
@@ -1056,5 +1056,13 @@ const tours: TranslationStrings = {
'tours.horse.leg.manual': 'Käsitsi, kontrollimata',
'tours.horse.leg.manualInfo':
'Käsitsi joonistatud, sirge. Seda ei kontrollinud ükski ratsarada ega marsruudiplaneerija.',
+ 'tours.horse.recorded.title': 'Salvestatud ratsamatk',
+ 'tours.horse.recorded.asRecorded': 'Nagu salvestatud',
+ 'tours.horse.recorded.asRecordedInfo': 'Joon jääb selliseks, nagu fail selle salvestas. Midagi ei planeerita uuesti.',
+ 'tours.horse.recorded.noTime': 'Ratsutamisaega pole',
+ 'tours.horse.recorded.noTimeInfo': 'TREK ei arvuta ratsamatkale ratsutamisaega: tempo määravad hobune ja ratsanik.',
+ 'tours.horse.recorded.accessUnchecked': 'Ligipääs kontrollimata',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'Import ei kontrolli, kas teedel tohib ratsutada. Kohapeal kehtivad sildid.',
};
export default tours;
diff --git a/shared/src/i18n/fr/tours.ts b/shared/src/i18n/fr/tours.ts
index 1dd7798db..bd91598e1 100644
--- a/shared/src/i18n/fr/tours.ts
+++ b/shared/src/i18n/fr/tours.ts
@@ -1090,5 +1090,14 @@ const tours: TranslationStrings = {
'tours.horse.leg.manual': 'Manuel, non vérifié',
'tours.horse.leg.manualInfo':
"Tracé à la main, en ligne droite. Ni un itinéraire équestre ni un calculateur d'itinéraire ne l'a vérifié.",
+ 'tours.horse.recorded.title': 'Sortie enregistrée',
+ 'tours.horse.recorded.asRecorded': 'Tel qu’enregistré',
+ 'tours.horse.recorded.asRecordedInfo': "Le tracé reste tel que le fichier l'a enregistré. Rien n'est recalculé.",
+ 'tours.horse.recorded.noTime': 'Pas de temps à cheval',
+ 'tours.horse.recorded.noTimeInfo':
+ 'TREK ne calcule aucun temps à cheval pour une sortie : le rythme est celui du cheval et du cavalier.',
+ 'tours.horse.recorded.accessUnchecked': 'Accès non vérifié',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ "L'import ne vérifie pas si les voies peuvent être empruntées à cheval. Les panneaux sur place font foi.",
};
export default tours;
diff --git a/shared/src/i18n/gr/tours.ts b/shared/src/i18n/gr/tours.ts
index fc20d4c77..2385d7058 100644
--- a/shared/src/i18n/gr/tours.ts
+++ b/shared/src/i18n/gr/tours.ts
@@ -1089,5 +1089,14 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'Τμήμα σηματοδοτημένης ιππικής διαδρομής από το OpenStreetMap. Πρόσβαση με άλογο: {access}',
'tours.horse.leg.manual': 'Χειροκίνητο, χωρίς έλεγχο',
'tours.horse.leg.manualInfo': 'Σχεδιασμένο με το χέρι, ευθύ. Ούτε ιππική διαδρομή ούτε δρομολογητής το έλεγξε.',
+ 'tours.horse.recorded.title': 'Καταγεγραμμένη βόλτα',
+ 'tours.horse.recorded.asRecorded': 'Όπως καταγράφηκε',
+ 'tours.horse.recorded.asRecordedInfo': 'Η γραμμή μένει όπως την κατέγραψε το αρχείο. Τίποτα δεν δρομολογείται ξανά.',
+ 'tours.horse.recorded.noTime': 'Χωρίς χρόνο ιππασίας',
+ 'tours.horse.recorded.noTimeInfo':
+ 'Το TREK δεν υπολογίζει χρόνο ιππασίας για μια βόλτα: τον ρυθμό τον ορίζουν το άλογο και ο αναβάτης.',
+ 'tours.horse.recorded.accessUnchecked': 'Πρόσβαση χωρίς έλεγχο',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'Η εισαγωγή δεν ελέγχει αν επιτρέπεται η ιππασία στους δρόμους. Ισχύουν οι πινακίδες επί τόπου.',
};
export default tours;
diff --git a/shared/src/i18n/hu/tours.ts b/shared/src/i18n/hu/tours.ts
index f65e9bce0..3a51286c2 100644
--- a/shared/src/i18n/hu/tours.ts
+++ b/shared/src/i18n/hu/tours.ts
@@ -1071,5 +1071,14 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'Jelzett lovas útvonal szakasza az OpenStreetMapből. Lovas hozzáférés: {access}',
'tours.horse.leg.manual': 'Kézi, ellenőrizetlen',
'tours.horse.leg.manualInfo': 'Kézzel, egyenesen húzva. Sem lovas útvonal, sem útvonaltervező nem ellenőrizte.',
+ 'tours.horse.recorded.title': 'Rögzített lovastúra',
+ 'tours.horse.recorded.asRecorded': 'Ahogy rögzítették',
+ 'tours.horse.recorded.asRecordedInfo': 'A vonal úgy marad, ahogy a fájl rögzítette. Semmit nem tervez újra.',
+ 'tours.horse.recorded.noTime': 'Nincs lovaglási idő',
+ 'tours.horse.recorded.noTimeInfo':
+ 'A TREK nem számol lovaglási időt egy lovastúrához: a tempót a ló és a lovas adja.',
+ 'tours.horse.recorded.accessUnchecked': 'Hozzáférés ellenőrizetlen',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'Az importálás nem ellenőrzi, hogy szabad-e lovagolni az utakon. A helyszíni táblák a mérvadók.',
};
export default tours;
diff --git a/shared/src/i18n/id/tours.ts b/shared/src/i18n/id/tours.ts
index 93200dd7f..7cdecb267 100644
--- a/shared/src/i18n/id/tours.ts
+++ b/shared/src/i18n/id/tours.ts
@@ -1053,5 +1053,14 @@ const tours: TranslationStrings = {
'tours.horse.leg.manual': 'Manual, belum diperiksa',
'tours.horse.leg.manualInfo':
'Digambar tangan, lurus. Tidak ada rute berkuda maupun perencana rute yang memeriksanya.',
+ 'tours.horse.recorded.title': 'Tur berkuda terekam',
+ 'tours.horse.recorded.asRecorded': 'Sesuai rekaman',
+ 'tours.horse.recorded.asRecordedInfo': 'Garis tetap seperti yang direkam berkas. Tidak ada yang dirutekan ulang.',
+ 'tours.horse.recorded.noTime': 'Tanpa waktu berkuda',
+ 'tours.horse.recorded.noTimeInfo':
+ 'TREK tidak menghitung waktu berkuda untuk tur berkuda: lajunya milik kuda dan penunggangnya.',
+ 'tours.horse.recorded.accessUnchecked': 'Akses belum diperiksa',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'Impor tidak memeriksa apakah jalan boleh dilalui dengan berkuda. Rambu di lokasi yang berlaku.',
};
export default tours;
diff --git a/shared/src/i18n/it/tours.ts b/shared/src/i18n/it/tours.ts
index 864a07804..3e8987adf 100644
--- a/shared/src/i18n/it/tours.ts
+++ b/shared/src/i18n/it/tours.ts
@@ -1079,5 +1079,14 @@ const tours: TranslationStrings = {
'tours.horse.leg.manual': 'Manuale, non verificato',
'tours.horse.leg.manualInfo':
'Tracciato a mano, dritto. Né un itinerario equestre né un pianificatore lo ha verificato.',
+ 'tours.horse.recorded.title': 'Escursione registrata',
+ 'tours.horse.recorded.asRecorded': 'Come registrato',
+ 'tours.horse.recorded.asRecordedInfo': 'Il tracciato resta come lo ha registrato il file. Nulla viene ricalcolato.',
+ 'tours.horse.recorded.noTime': 'Nessun tempo a cavallo',
+ 'tours.horse.recorded.noTimeInfo':
+ 'TREK non calcola un tempo a cavallo per un’escursione: il ritmo è quello del cavallo e del cavaliere.',
+ 'tours.horse.recorded.accessUnchecked': 'Accesso non verificato',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'L’importazione non verifica se le strade si possono percorrere a cavallo. Valgono i cartelli sul posto.',
};
export default tours;
diff --git a/shared/src/i18n/ja/tours.ts b/shared/src/i18n/ja/tours.ts
index bd0e5d21f..3261fe948 100644
--- a/shared/src/i18n/ja/tours.ts
+++ b/shared/src/i18n/ja/tours.ts
@@ -1024,5 +1024,13 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'OpenStreetMap の標識付き乗馬ルートの区間です。乗馬でのアクセス: {access}',
'tours.horse.leg.manual': '手動、未確認',
'tours.horse.leg.manualInfo': '手で直線に引いた区間です。乗馬ルートもルーターも確認していません。',
+ 'tours.horse.recorded.title': '記録された乗馬',
+ 'tours.horse.recorded.asRecorded': '記録のまま',
+ 'tours.horse.recorded.asRecordedInfo': '線はファイルに記録されたままです。ルートを計算し直すことはありません。',
+ 'tours.horse.recorded.noTime': '乗馬時間なし',
+ 'tours.horse.recorded.noTimeInfo': 'TREK は乗馬ツアーの乗馬時間を計算しません。ペースは馬と乗り手次第です。',
+ 'tours.horse.recorded.accessUnchecked': '通行可否は未確認',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'インポートでは、道を馬で通れるかどうかを確認しません。現地の標識が優先されます。',
};
export default tours;
diff --git a/shared/src/i18n/ko/tours.ts b/shared/src/i18n/ko/tours.ts
index e51b39657..dc767af57 100644
--- a/shared/src/i18n/ko/tours.ts
+++ b/shared/src/i18n/ko/tours.ts
@@ -1021,5 +1021,14 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'OpenStreetMap의 표지가 있는 승마 루트의 구간입니다. 말 통행: {access}',
'tours.horse.leg.manual': '수동, 확인되지 않음',
'tours.horse.leg.manualInfo': '손으로 그은 직선 구간입니다. 승마 루트도 경로 계산기도 확인하지 않았습니다.',
+ 'tours.horse.recorded.title': '기록된 승마',
+ 'tours.horse.recorded.asRecorded': '기록된 그대로',
+ 'tours.horse.recorded.asRecordedInfo': '선은 파일에 기록된 그대로 유지됩니다. 경로를 다시 계산하지 않습니다.',
+ 'tours.horse.recorded.noTime': '승마 시간 없음',
+ 'tours.horse.recorded.noTimeInfo':
+ 'TREK은 승마 투어의 승마 시간을 계산하지 않습니다. 속도는 말과 기수에게 달려 있습니다.',
+ 'tours.horse.recorded.accessUnchecked': '통행 여부 미확인',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ '가져오기는 길을 말로 지나가도 되는지 확인하지 않습니다. 현장 표지판을 따르세요.',
};
export default tours;
diff --git a/shared/src/i18n/nl/tours.ts b/shared/src/i18n/nl/tours.ts
index 17f42fd76..3b2f70ab2 100644
--- a/shared/src/i18n/nl/tours.ts
+++ b/shared/src/i18n/nl/tours.ts
@@ -1074,5 +1074,14 @@ const tours: TranslationStrings = {
'tours.horse.leg.manual': 'Handmatig, niet gecontroleerd',
'tours.horse.leg.manualInfo':
'Met de hand getrokken, recht. Geen ruiterroute en geen routeplanner heeft het gecontroleerd.',
+ 'tours.horse.recorded.title': 'Opgenomen rit',
+ 'tours.horse.recorded.asRecorded': 'Zoals opgenomen',
+ 'tours.horse.recorded.asRecordedInfo':
+ 'De lijn blijft zoals het bestand haar heeft opgenomen. Er wordt niets opnieuw gepland.',
+ 'tours.horse.recorded.noTime': 'Geen rijtijd',
+ 'tours.horse.recorded.noTimeInfo': 'TREK berekent geen rijtijd voor een rit: het tempo is aan paard en ruiter.',
+ 'tours.horse.recorded.accessUnchecked': 'Toegang niet gecontroleerd',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'De import controleert niet of de wegen bereden mogen worden. Ter plekke gelden de borden.',
};
export default tours;
diff --git a/shared/src/i18n/pl/tours.ts b/shared/src/i18n/pl/tours.ts
index c0fe5ac3e..875c79b67 100644
--- a/shared/src/i18n/pl/tours.ts
+++ b/shared/src/i18n/pl/tours.ts
@@ -1100,5 +1100,13 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'Odcinek oznakowanego szlaku konnego z OpenStreetMap. Dostęp dla koni: {access}',
'tours.horse.leg.manual': 'Ręczny, niesprawdzony',
'tours.horse.leg.manualInfo': 'Narysowany ręcznie, prosto. Nie sprawdził go żaden szlak konny ani planer tras.',
+ 'tours.horse.recorded.title': 'Nagrana przejażdżka',
+ 'tours.horse.recorded.asRecorded': 'Tak jak nagrano',
+ 'tours.horse.recorded.asRecordedInfo': 'Linia pozostaje taka, jak zapisał ją plik. Nic nie jest wyznaczane ponownie.',
+ 'tours.horse.recorded.noTime': 'Bez czasu jazdy',
+ 'tours.horse.recorded.noTimeInfo': 'TREK nie oblicza czasu jazdy dla przejażdżki: tempo zależy od konia i jeźdźca.',
+ 'tours.horse.recorded.accessUnchecked': 'Dostęp niesprawdzony',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'Import nie sprawdza, czy po drogach wolno jeździć konno. Obowiązują znaki na miejscu.',
};
export default tours;
diff --git a/shared/src/i18n/ru/tours.ts b/shared/src/i18n/ru/tours.ts
index 78ec9587d..fac9e4dd9 100644
--- a/shared/src/i18n/ru/tours.ts
+++ b/shared/src/i18n/ru/tours.ts
@@ -1104,5 +1104,15 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'Участок маркированного конного маршрута из OpenStreetMap. Доступ для лошадей: {access}',
'tours.horse.leg.manual': 'Вручную, не проверено',
'tours.horse.leg.manualInfo': 'Нарисован вручную, по прямой. Ни конный маршрут, ни маршрутизатор его не проверяли.',
+ 'tours.horse.recorded.title': 'Записанная прогулка',
+ 'tours.horse.recorded.asRecorded': 'Как записано',
+ 'tours.horse.recorded.asRecordedInfo':
+ 'Линия остаётся такой, какой её записал файл. Ничего не прокладывается заново.',
+ 'tours.horse.recorded.noTime': 'Без времени в седле',
+ 'tours.horse.recorded.noTimeInfo':
+ 'TREK не рассчитывает время в седле для конной прогулки: темп задают лошадь и всадник.',
+ 'tours.horse.recorded.accessUnchecked': 'Доступ не проверен',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'Импорт не проверяет, можно ли ехать по этим дорогам верхом. На месте действуют знаки.',
};
export default tours;
diff --git a/shared/src/i18n/sk/tours.ts b/shared/src/i18n/sk/tours.ts
index 314ef241f..56199e441 100644
--- a/shared/src/i18n/sk/tours.ts
+++ b/shared/src/i18n/sk/tours.ts
@@ -1063,5 +1063,13 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'Úsek značenej jazdeckej trasy z OpenStreetMap. Prístup pre kone: {access}',
'tours.horse.leg.manual': 'Ručne, neoverené',
'tours.horse.leg.manualInfo': 'Nakreslené ručne, rovno. Neoverila ho žiadna jazdecká trasa ani plánovač.',
+ 'tours.horse.recorded.title': 'Zaznamenaná vychádzka',
+ 'tours.horse.recorded.asRecorded': 'Ako bolo zaznamenané',
+ 'tours.horse.recorded.asRecordedInfo': 'Trasa zostáva tak, ako ju súbor zaznamenal. Nič sa znova neplánuje.',
+ 'tours.horse.recorded.noTime': 'Bez času jazdy',
+ 'tours.horse.recorded.noTimeInfo': 'TREK pre vychádzku nepočíta čas jazdy: tempo určuje kôň a jazdec.',
+ 'tours.horse.recorded.accessUnchecked': 'Prístup neoverený',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'Import neoveruje, či sa po cestách smie jazdiť na koni. Platí značenie na mieste.',
};
export default tours;
diff --git a/shared/src/i18n/sv/tours.ts b/shared/src/i18n/sv/tours.ts
index 475c5032d..729d2ed99 100644
--- a/shared/src/i18n/sv/tours.ts
+++ b/shared/src/i18n/sv/tours.ts
@@ -1052,5 +1052,14 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'Delsträcka av en skyltad ridled från OpenStreetMap. Tillträde för häst: {access}',
'tours.horse.leg.manual': 'Manuell, okontrollerad',
'tours.horse.leg.manualInfo': 'Dragen för hand, rakt. Ingen ridled och ingen ruttplanerare har kontrollerat den.',
+ 'tours.horse.recorded.title': 'Inspelad ridtur',
+ 'tours.horse.recorded.asRecorded': 'Som inspelad',
+ 'tours.horse.recorded.asRecordedInfo': 'Linjen förblir som filen spelade in den. Inget planeras om.',
+ 'tours.horse.recorded.noTime': 'Ingen ridtid',
+ 'tours.horse.recorded.noTimeInfo':
+ 'TREK räknar inte ut någon ridtid för en ridtur: takten bestäms av hästen och ryttaren.',
+ 'tours.horse.recorded.accessUnchecked': 'Tillträde okontrollerat',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'Importen kontrollerar inte om vägarna får ridas. Skyltarna på plats gäller.',
};
export default tours;
diff --git a/shared/src/i18n/th/tours.ts b/shared/src/i18n/th/tours.ts
index 122bc37b4..d62a5dd54 100644
--- a/shared/src/i18n/th/tours.ts
+++ b/shared/src/i18n/th/tours.ts
@@ -1008,5 +1008,13 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'ช่วงหนึ่งของเส้นทางขี่ม้าที่มีป้ายบอกจาก OpenStreetMap การเข้าถึงสำหรับม้า: {access}',
'tours.horse.leg.manual': 'วาดเอง ยังไม่ตรวจสอบ',
'tours.horse.leg.manualInfo': 'วาดด้วยมือเป็นเส้นตรง ไม่มีเส้นทางขี่ม้าหรือตัววางเส้นทางใดตรวจสอบ',
+ 'tours.horse.recorded.title': 'ทริปขี่ม้าที่บันทึกไว้',
+ 'tours.horse.recorded.asRecorded': 'ตามที่บันทึก',
+ 'tours.horse.recorded.asRecordedInfo': 'เส้นยังคงเป็นไปตามที่ไฟล์บันทึกไว้ ไม่มีการวางเส้นทางใหม่',
+ 'tours.horse.recorded.noTime': 'ไม่มีเวลาขี่ม้า',
+ 'tours.horse.recorded.noTimeInfo': 'TREK ไม่คำนวณเวลาขี่ม้าให้ทริปขี่ม้า จังหวะขึ้นอยู่กับม้าและผู้ขี่',
+ 'tours.horse.recorded.accessUnchecked': 'ยังไม่ตรวจสอบสิทธิ์ผ่าน',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'การนำเข้าไม่ได้ตรวจสอบว่าขี่ม้าผ่านเส้นทางได้หรือไม่ ให้ถือป้ายในพื้นที่เป็นหลัก',
};
export default tours;
diff --git a/shared/src/i18n/tours-locales.spec.ts b/shared/src/i18n/tours-locales.spec.ts
index b5983820b..9a32f7cd0 100644
--- a/shared/src/i18n/tours-locales.spec.ts
+++ b/shared/src/i18n/tours-locales.spec.ts
@@ -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 = 952;
+const GENERAL_KEY_COUNT = 959;
function literalKeys(source: string): string[] {
const tree = ts.createSourceFile('locale.ts', source, ts.ScriptTarget.Latest, true);
diff --git a/shared/src/i18n/tr/tours.ts b/shared/src/i18n/tr/tours.ts
index 0e1df6378..c37286410 100644
--- a/shared/src/i18n/tr/tours.ts
+++ b/shared/src/i18n/tr/tours.ts
@@ -1060,5 +1060,13 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': "OpenStreetMap'teki işaretli bir binicilik rotasının bölümü. At erişimi: {access}",
'tours.horse.leg.manual': 'Elle, denetlenmemiş',
'tours.horse.leg.manualInfo': 'Elle, düz çizildi. Ne bir binicilik rotası ne de bir rota planlayıcı denetledi.',
+ 'tours.horse.recorded.title': 'Kaydedilmiş at gezisi',
+ 'tours.horse.recorded.asRecorded': 'Kaydedildiği gibi',
+ 'tours.horse.recorded.asRecordedInfo': 'Çizgi, dosyanın kaydettiği gibi kalır. Hiçbir şey yeniden rotalanmaz.',
+ 'tours.horse.recorded.noTime': 'Sürüş süresi yok',
+ 'tours.horse.recorded.noTimeInfo': 'TREK at gezisi için sürüş süresi hesaplamaz: tempoyu at ve binici belirler.',
+ 'tours.horse.recorded.accessUnchecked': 'Erişim denetlenmedi',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'İçe aktarma, yollarda ata binilip binilemeyeceğini denetlemez. Yerindeki tabelalar geçerlidir.',
};
export default tours;
diff --git a/shared/src/i18n/uk/tours.ts b/shared/src/i18n/uk/tours.ts
index 32c58de0d..5cc176c74 100644
--- a/shared/src/i18n/uk/tours.ts
+++ b/shared/src/i18n/uk/tours.ts
@@ -1093,5 +1093,14 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'Ділянка маркованого кінного маршруту з OpenStreetMap. Доступ для коней: {access}',
'tours.horse.leg.manual': 'Вручну, не перевірено',
'tours.horse.leg.manualInfo': 'Намальовано вручну, по прямій. Ні кінний маршрут, ні маршрутизатор її не перевіряли.',
+ 'tours.horse.recorded.title': 'Записана прогулянка',
+ 'tours.horse.recorded.asRecorded': 'Як записано',
+ 'tours.horse.recorded.asRecordedInfo': 'Лінія залишається такою, як її записав файл. Нічого не прокладається заново.',
+ 'tours.horse.recorded.noTime': 'Без часу в сідлі',
+ 'tours.horse.recorded.noTimeInfo':
+ 'TREK не розраховує час у сідлі для кінної прогулянки: темп задають кінь і вершник.',
+ 'tours.horse.recorded.accessUnchecked': 'Доступ не перевірено',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'Імпорт не перевіряє, чи можна їхати цими дорогами верхи. На місці діють знаки.',
};
export default tours;
diff --git a/shared/src/i18n/vi/tours.ts b/shared/src/i18n/vi/tours.ts
index 25eac445c..f3ef7eb85 100644
--- a/shared/src/i18n/vi/tours.ts
+++ b/shared/src/i18n/vi/tours.ts
@@ -1044,5 +1044,14 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': 'Một đoạn của tuyến cưỡi ngựa có biển chỉ dẫn từ OpenStreetMap. Quyền đi ngựa: {access}',
'tours.horse.leg.manual': 'Thủ công, chưa kiểm tra',
'tours.horse.leg.manualInfo': 'Vẽ tay, đường thẳng. Không tuyến cưỡi ngựa hay công cụ dẫn đường nào kiểm tra.',
+ 'tours.horse.recorded.title': 'Chuyến cưỡi ngựa đã ghi',
+ 'tours.horse.recorded.asRecorded': 'Như đã ghi',
+ 'tours.horse.recorded.asRecordedInfo': 'Đường đi giữ nguyên như tệp đã ghi. Không có gì được dẫn đường lại.',
+ 'tours.horse.recorded.noTime': 'Không có thời gian cưỡi ngựa',
+ 'tours.horse.recorded.noTimeInfo':
+ 'TREK không tính thời gian cưỡi ngựa cho chuyến cưỡi ngựa: nhịp độ là của ngựa và người cưỡi.',
+ 'tours.horse.recorded.accessUnchecked': 'Chưa kiểm tra quyền đi',
+ 'tours.horse.recorded.accessUncheckedInfo':
+ 'Việc nhập không kiểm tra liệu có được cưỡi ngựa trên các con đường hay không. Biển báo tại chỗ mới là căn cứ.',
};
export default tours;
diff --git a/shared/src/i18n/zh-TW/tours.ts b/shared/src/i18n/zh-TW/tours.ts
index 01e8b47f7..01ff457e5 100644
--- a/shared/src/i18n/zh-TW/tours.ts
+++ b/shared/src/i18n/zh-TW/tours.ts
@@ -970,5 +970,12 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': '來自 OpenStreetMap 有標示騎馬路線的一段。馬匹通行:{access}',
'tours.horse.leg.manual': '手動,未經檢查',
'tours.horse.leg.manualInfo': '手動繪製的直線。沒有任何騎馬路線或路線規劃器檢查過它。',
+ 'tours.horse.recorded.title': '已記錄的騎馬遊',
+ 'tours.horse.recorded.asRecorded': '依記錄保留',
+ 'tours.horse.recorded.asRecordedInfo': '路線維持檔案記錄時的樣子,不會重新規劃。',
+ 'tours.horse.recorded.noTime': '無騎乘時間',
+ 'tours.horse.recorded.noTimeInfo': 'TREK 不為騎馬遊計算騎乘時間:節奏取決於馬和騎手。',
+ 'tours.horse.recorded.accessUnchecked': '通行未經檢查',
+ 'tours.horse.recorded.accessUncheckedInfo': '匯入不會檢查這些道路是否允許騎馬通行。以現場標誌為準。',
};
export default tours;
diff --git a/shared/src/i18n/zh/tours.ts b/shared/src/i18n/zh/tours.ts
index cad229d9e..37d5c65f4 100644
--- a/shared/src/i18n/zh/tours.ts
+++ b/shared/src/i18n/zh/tours.ts
@@ -971,5 +971,12 @@ const tours: TranslationStrings = {
'tours.horse.leg.info': '来自 OpenStreetMap 有标识骑马路线的一段。马匹通行:{access}',
'tours.horse.leg.manual': '手动,未经检查',
'tours.horse.leg.manualInfo': '手动绘制的直线。没有任何骑马路线或路线规划器检查过它。',
+ 'tours.horse.recorded.title': '已记录的骑马游',
+ 'tours.horse.recorded.asRecorded': '按记录保留',
+ 'tours.horse.recorded.asRecordedInfo': '路线保持文件记录时的样子,不会重新规划。',
+ 'tours.horse.recorded.noTime': '无骑行时间',
+ 'tours.horse.recorded.noTimeInfo': 'TREK 不为骑马游计算骑行时间:节奏取决于马和骑手。',
+ 'tours.horse.recorded.accessUnchecked': '通行未经检查',
+ 'tours.horse.recorded.accessUncheckedInfo': '导入不会检查这些道路是否允许骑马通行。以现场标志为准。',
};
export default tours;