mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-24 07:53:09 +00:00
fix(tours): restoring a recorded track and saving a copy wait for the tour's queued edits
Both go straight to the server. While an edit of the same tour still waited in the queue, the restore went out first and its answer replaced the cached edit, and the edit replayed afterwards planned the track over again. A copy copied the server's older line instead of the one on screen. Both now wait the way the actual track writes do: offline, behind a queued write of the tour, or for a tour the server has not got yet they refuse with OnlineOnlyError, and the planner says a connection is needed and the waiting changes go first, in all 27 languages.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import type { TourListItem } from '@trek/shared';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { OnlineOnlyError } from '../../repo/onlineOnly';
|
||||
import type { TourPlannerController } from './planner/useTourPlanner';
|
||||
import { useRecordedTrack } from './useRecordedTrack';
|
||||
|
||||
@@ -87,4 +88,21 @@ describe('useRecordedTrack', () => {
|
||||
expect(controller.returnToNeutral).not.toHaveBeenCalled();
|
||||
expect(onRestored).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('says it needs a connection when it is offline or behind an edit of the tour still waiting', async () => {
|
||||
repo.restoreRecorded.mockRejectedValueOnce(new OnlineOnlyError());
|
||||
const controller = planner(7);
|
||||
const onRestored = vi.fn();
|
||||
const { result } = renderHook(() =>
|
||||
useRecordedTrack({ tripId: 1, planner: controller, tours: [replaced], canEdit: true, onRestored })
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.restore();
|
||||
});
|
||||
|
||||
expect(toast.error).toHaveBeenCalledWith('tours.recorded.offline');
|
||||
expect(controller.returnToNeutral).not.toHaveBeenCalled();
|
||||
expect(onRestored).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { TourListItem } from '@trek/shared';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useTranslation } from '../../i18n';
|
||||
import { OnlineOnlyError } from '../../repo/onlineOnly';
|
||||
import { tourRepo } from '../../repo/tourRepo';
|
||||
import { useToast } from '../shared/Toast';
|
||||
import type { TourPlannerController } from './planner/useTourPlanner';
|
||||
@@ -36,8 +37,9 @@ export function useRecordedTrack({ tripId, planner, tours, canEdit, onRestored }
|
||||
returnToNeutral();
|
||||
await onRestored(result.tour);
|
||||
toast.success(t('tours.recorded.restored'));
|
||||
} catch {
|
||||
toast.error(t('tours.recorded.failed'));
|
||||
} catch (err: unknown) {
|
||||
// Offline, or behind an edit of the tour still waiting to be sent: said as such, not as a failure.
|
||||
toast.error(t(err instanceof OnlineOnlyError ? 'tours.recorded.offline' : 'tours.recorded.failed'));
|
||||
} finally {
|
||||
setRestoring(false);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
// P2D-XD-01: from a tour's packing link to the trip's Lists tab, the tour's detail closed on the way.
|
||||
// P2C-07: a tour saved as a new one, and why not when it cannot be.
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import type { TourListItem } from '@trek/shared';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { useListsSubTab } from '../../hooks/useListsSubTab';
|
||||
import { OnlineOnlyError } from '../../repo/onlineOnly';
|
||||
import { useTourDetailActions } from './useTourDetailActions';
|
||||
import type { useTripPlanner } from './useTripPlanner';
|
||||
|
||||
const repo = vi.hoisted(() => ({ copy: vi.fn() }));
|
||||
vi.mock('../../repo/tourRepo', () => ({ tourRepo: repo }));
|
||||
|
||||
describe('useTourDetailActions', () => {
|
||||
const planner = () => ({ tripId: 5, setSelectedPlaceId: vi.fn(), handleTabChange: vi.fn() });
|
||||
const actions = (p: ReturnType<typeof planner>) =>
|
||||
@@ -31,4 +37,19 @@ describe('useTourDetailActions', () => {
|
||||
act(() => a.onOpenPacking());
|
||||
expect(lists.result.current[0]).toBe('packing');
|
||||
});
|
||||
|
||||
it('FE-TOUR-DETAIL-ACTIONS-004: a copy that cannot go out says it needs a connection, any other failure that it failed', async () => {
|
||||
const toast = { success: vi.fn(), error: vi.fn() };
|
||||
const p = { ...planner(), t: (key: string) => key, toast };
|
||||
const ridge = { place_id: 40, name: 'Ridge walk' } as TourListItem;
|
||||
const a = actions(p);
|
||||
repo.copy.mockRejectedValueOnce(new OnlineOnlyError());
|
||||
await act(() => a.onSaveAsNew(ridge));
|
||||
expect(repo.copy).toHaveBeenCalledWith(5, 40, 'tours.copy.name');
|
||||
expect(toast.error).toHaveBeenLastCalledWith('tours.copy.offline');
|
||||
repo.copy.mockRejectedValueOnce(new Error('Server error'));
|
||||
await act(() => a.onSaveAsNew(ridge));
|
||||
expect(toast.error).toHaveBeenLastCalledWith('tours.copy.failed');
|
||||
expect(toast.success).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { TourListItem } from '@trek/shared';
|
||||
import { rememberListsSubTab } from '../../hooks/useListsSubTab';
|
||||
import { OnlineOnlyError } from '../../repo/onlineOnly';
|
||||
import { tourRepo } from '../../repo/tourRepo';
|
||||
import { useTripStore } from '../../store/tripStore';
|
||||
import type { Place } from '../../types';
|
||||
@@ -49,8 +50,9 @@ export function useTourDetailActions(planner: ReturnType<typeof useTripPlanner>)
|
||||
const { tour: copy } = await tourRepo.copy(tripId, tour.place_id, name);
|
||||
await takeIn(copy);
|
||||
toast.success(t('tours.copy.saved'));
|
||||
} catch {
|
||||
toast.error(t('tours.copy.failed'));
|
||||
} catch (err: unknown) {
|
||||
// Offline, or behind an edit of the tour still waiting to be sent, which the copy would leave out.
|
||||
toast.error(t(err instanceof OnlineOnlyError ? 'tours.copy.offline' : 'tours.copy.failed'));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// FE-REPO-TOUR-001 to FE-REPO-TOUR-014, FE-REPO-TOUR-042 to FE-REPO-TOUR-047
|
||||
// FE-REPO-TOUR-001 to FE-REPO-TOUR-014, FE-REPO-TOUR-042 to FE-REPO-TOUR-048
|
||||
// Tours through the offline core: read-through to Dexie, offline create and
|
||||
// edit written there and queued, and the online paths keeping the copy fresh.
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
||||
@@ -502,6 +502,43 @@ describe('tourRepo provenance and copies (P2C-02, P2C-07)', () => {
|
||||
expect(cached?.activity_tracks).toEqual([{ id: 5, track_place_id: 41, assignment_id: null }])
|
||||
})
|
||||
|
||||
it('FE-REPO-TOUR-048: the restore of a recorded track and a copy wait for a queued edit of the tour, and go out neither offline nor for a tour the server has not got', async () => {
|
||||
let sent = 0
|
||||
server.use(
|
||||
http.post('/api/trips/3/tours/40/restore-recorded', () => {
|
||||
sent++
|
||||
return HttpResponse.json({ tour: tour({ name: 'Recorded', has_waypoints: false }), waypoints: [] })
|
||||
}),
|
||||
http.post('/api/trips/3/tours/40/copy', () => {
|
||||
sent++
|
||||
return HttpResponse.json({ tour: tour({ place_id: 41, name: 'Ridge walk (copy)' }), waypoints: [] }, { status: 201 })
|
||||
}),
|
||||
)
|
||||
// An edit made here offline whose replay failed and waits: it would plan the restored track over again.
|
||||
await offlineDb.tours.put({ ...tour({ name: 'Edited here' }), trip_id: 3 })
|
||||
await offlineDb.mutationQueue.put({
|
||||
id: 'queued-tour', tripId: 3, method: 'PUT', url: '/trips/3/tours/40', body, createdAt: 1,
|
||||
status: 'failed', attempts: 3, lastError: 'Server error', resource: 'tours', entityId: 40,
|
||||
})
|
||||
await expect(tourRepo.restoreRecorded(3, 40)).rejects.toBeInstanceOf(OnlineOnlyError)
|
||||
await expect(tourRepo.copy(3, 40, 'Ridge walk (copy)')).rejects.toBeInstanceOf(OnlineOnlyError)
|
||||
expect(sent).toBe(0)
|
||||
expect((await offlineDb.tours.get(40))?.name).toBe('Edited here')
|
||||
await offlineDb.mutationQueue.clear()
|
||||
|
||||
setOnline(false)
|
||||
await expect(tourRepo.restoreRecorded(3, 40)).rejects.toBeInstanceOf(OnlineOnlyError)
|
||||
await expect(tourRepo.copy(3, 40, 'Ridge walk (copy)')).rejects.toBeInstanceOf(OnlineOnlyError)
|
||||
setOnline(true)
|
||||
await expect(tourRepo.copy(3, -7, 'Draft (copy)')).rejects.toBeInstanceOf(OnlineOnlyError)
|
||||
expect(sent).toBe(0)
|
||||
|
||||
// Once nothing waits, the restore goes out and the cache takes the restored tour in.
|
||||
await tourRepo.restoreRecorded(3, 40)
|
||||
expect(sent).toBe(1)
|
||||
expect(await offlineDb.tours.get(40)).toMatchObject({ name: 'Recorded', has_waypoints: false })
|
||||
})
|
||||
|
||||
it('FE-REPO-TOUR-021: a copy is asked of the server under its name and cached as a tour of the trip', async () => {
|
||||
let sent: unknown = null
|
||||
server.use(http.post('/api/trips/3/tours/40/copy', async ({ request }) => {
|
||||
|
||||
@@ -18,10 +18,13 @@ import { OnlineOnlyError } from './onlineOnly'
|
||||
import type { Place } from '../types'
|
||||
|
||||
/**
|
||||
* ACT-01: an assignment change goes out only for a tour the server has, while
|
||||
* no older write of it waits in the queue; `mustQueue` is true offline too.
|
||||
* A write only the server can make (ACT-01's assignments, the restore of a
|
||||
* recorded track, a copy) goes out only for a tour the server has, while no
|
||||
* older write of it waits in the queue: its answer is the server's tour from
|
||||
* before that write, and the write replayed after it would undo this one.
|
||||
* `mustQueue` is true offline too.
|
||||
*/
|
||||
async function requireActivityWrite(placeId: number): Promise<void> {
|
||||
async function requireServerWrite(placeId: number): Promise<void> {
|
||||
if (placeId < 0 || (await mutationQueue.mustQueue('tours', placeId))) throw new OnlineOnlyError()
|
||||
}
|
||||
|
||||
@@ -350,8 +353,13 @@ export const tourRepo = {
|
||||
return result
|
||||
},
|
||||
|
||||
/** Online only, like the import: the recorded track is kept on the server, not in the cache. */
|
||||
/**
|
||||
* Online only, like the import: the recorded track is kept on the server,
|
||||
* not in the cache. Held back behind a queued edit of the tour, which would
|
||||
* plan it over again once replayed.
|
||||
*/
|
||||
async restoreRecorded(tripId: number | string, placeId: number): Promise<TourDetailResponse> {
|
||||
await requireServerWrite(placeId)
|
||||
const result = await recordedTrackApi.restore(tripId, placeId)
|
||||
await cacheTourAnswer(Number(tripId), result)
|
||||
return result
|
||||
@@ -367,7 +375,7 @@ export const tourRepo = {
|
||||
* changes, so only the recordings of the cached tour take the answer in.
|
||||
*/
|
||||
async assignActivity(tripId: number | string, placeId: number, body: TourActivityAssignRequest): Promise<TourDetailResponse> {
|
||||
await requireActivityWrite(placeId)
|
||||
await requireServerWrite(placeId)
|
||||
const result = await tourActivitiesApi.assign(tripId, placeId, body)
|
||||
await cacheActivities(tripId, placeId, result)
|
||||
return result
|
||||
@@ -375,7 +383,7 @@ export const tourRepo = {
|
||||
|
||||
/** ACT-01: a recorded track taken off the tour again; online only and held back like the assignment. */
|
||||
async unassignActivity(tripId: number | string, placeId: number, activityId: number): Promise<TourDetailResponse> {
|
||||
await requireActivityWrite(placeId)
|
||||
await requireServerWrite(placeId)
|
||||
const result = await tourActivitiesApi.unassign(tripId, placeId, activityId)
|
||||
await cacheActivities(tripId, placeId, result)
|
||||
return result
|
||||
@@ -397,9 +405,11 @@ export const tourRepo = {
|
||||
|
||||
/**
|
||||
* P2C-07, online only like the restore: the copy is made from the server's
|
||||
* stored line and control points, so it needs the server to answer.
|
||||
* stored line and control points, so it needs the server to answer, and
|
||||
* waits for a queued edit of the tour so that it copies what the user sees.
|
||||
*/
|
||||
async copy(tripId: number | string, placeId: number, name: string): Promise<TourCreateResponse> {
|
||||
await requireServerWrite(placeId)
|
||||
const result = await tourCopiesApi.copy(tripId, placeId, { name })
|
||||
await cacheTourAnswer(Number(tripId), result)
|
||||
return result
|
||||
|
||||
@@ -65,6 +65,7 @@ const tours: TranslationStrings = {
|
||||
'تُحذف نقاط المرور والخط المحسوب، وتعرض الجولة مجددًا الأثر الذي سُجّلت به. تبقى أيامها وملاحظاتها.',
|
||||
'tours.recorded.restored': 'تمت استعادة الأثر المسجّل',
|
||||
'tours.recorded.failed': 'تعذّرت استعادة الأثر المسجّل.',
|
||||
'tours.recorded.offline': 'استعادة الأثر المسجّل تحتاج إلى اتصال، وتُرسَل التغييرات المنتظرة لهذه الجولة أولًا.',
|
||||
'tours.conversion.analyze': 'تخطيط نسخة قابلة للتعديل',
|
||||
'tours.conversion.analyzing': 'جارٍ حساب المسار عبر {count} نقطة تحكم…',
|
||||
'tours.conversion.analyzing.zero': 'جارٍ حساب المسار دون نقاط تحكم…',
|
||||
@@ -668,6 +669,7 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (نسخة)',
|
||||
'tours.copy.saved': 'تم الحفظ كجولة جديدة',
|
||||
'tours.copy.failed': 'تعذّر نسخ الجولة.',
|
||||
'tours.copy.offline': 'الحفظ كجولة جديدة يحتاج إلى اتصال، وتُرسَل التغييرات المنتظرة لهذه الجولة أولًا.',
|
||||
'tours.gpxExport.action': 'تنزيل GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'ينزّل الجولة المحفوظة كملف GPX: المسار كاملًا مع الارتفاعات المتوفرة، لتطبيق ملاحة أو جهاز GPS.',
|
||||
|
||||
@@ -54,6 +54,8 @@ const tours: TranslationStrings = {
|
||||
'Yol nöqtələri və hesablanmış xətt silinir, tur yenidən qeydə alındığı izi göstərir. Günləri və qeydləri qalır.',
|
||||
'tours.recorded.restored': 'Qeydə alınmış iz bərpa edildi',
|
||||
'tours.recorded.failed': 'Qeydə alınmış izi bərpa etmək mümkün olmadı.',
|
||||
'tours.recorded.offline':
|
||||
'Qeydə alınmış izi bərpa etmək üçün bağlantı lazımdır və bu turun gözləyən dəyişiklikləri əvvəlcə göndərilir.',
|
||||
'tours.conversion.analyze': 'Redaktə edilə bilən versiya planlaşdır',
|
||||
'tours.conversion.analyzing': '{count} nəzarət nöqtəsi üzərindən marşrut hesablanır…',
|
||||
'tours.conversion.analyzing.one': '{count} nəzarət nöqtəsi üzərindən marşrut hesablanır…',
|
||||
@@ -662,6 +664,8 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (surət)',
|
||||
'tours.copy.saved': 'Yeni tur kimi saxlanıldı',
|
||||
'tours.copy.failed': 'Turu kopyalamaq olmadı.',
|
||||
'tours.copy.offline':
|
||||
'Yeni tur kimi saxlamaq üçün bağlantı lazımdır və bu turun gözləyən dəyişiklikləri əvvəlcə göndərilir.',
|
||||
'tours.gpxExport.action': 'GPX yüklə',
|
||||
'tours.gpxExport.hint':
|
||||
'Saxlanmış turu GPX faylı kimi endirir: bütün marşrut mövcud hündürlüklərlə, naviqasiya tətbiqi və ya GPS cihazı üçün.',
|
||||
|
||||
@@ -55,6 +55,8 @@ const tours: TranslationStrings = {
|
||||
'Os pontos de passagem e a linha calculada são descartados, e o passeio volta a mostrar o traçado com que foi gravado. Os dias e as notas permanecem.',
|
||||
'tours.recorded.restored': 'Traçado gravado restaurado',
|
||||
'tours.recorded.failed': 'Não foi possível restaurar o traçado gravado.',
|
||||
'tours.recorded.offline':
|
||||
'Restaurar o traçado gravado precisa de conexão, e as alterações pendentes deste passeio vão primeiro.',
|
||||
'tours.conversion.analyze': 'Planejar uma versão editável',
|
||||
'tours.conversion.analyzing': 'Calculando a rota por {count} pontos de controle…',
|
||||
'tours.conversion.analyzing.one': 'Calculando a rota por {count} ponto de controle…',
|
||||
@@ -671,6 +673,8 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (cópia)',
|
||||
'tours.copy.saved': 'Salvo como novo passeio',
|
||||
'tours.copy.failed': 'Não foi possível copiar o passeio.',
|
||||
'tours.copy.offline':
|
||||
'Salvar como novo passeio precisa de conexão, e as alterações pendentes deste passeio vão primeiro.',
|
||||
'tours.gpxExport.action': 'Baixar GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'Baixa o passeio salvo como arquivo GPX: a rota inteira com as altitudes disponíveis, para um app de navegação ou um aparelho GPS.',
|
||||
|
||||
@@ -55,6 +55,8 @@ const tours: TranslationStrings = {
|
||||
"Els punts de pas i la línia calculada es descarten, i l'excursió torna a mostrar la traça amb què es va enregistrar. Els dies i les notes es mantenen.",
|
||||
'tours.recorded.restored': 'Traça enregistrada restaurada',
|
||||
'tours.recorded.failed': "No s'ha pogut restaurar la traça enregistrada.",
|
||||
'tours.recorded.offline':
|
||||
'Restaurar la traça enregistrada necessita connexió, i els canvis pendents d’aquesta excursió van primer.',
|
||||
'tours.conversion.analyze': 'Planifica una versió editable',
|
||||
'tours.conversion.analyzing': "S'està calculant la ruta per {count} punts de control…",
|
||||
'tours.conversion.analyzing.one': "S'està calculant la ruta per {count} punt de control…",
|
||||
@@ -675,6 +677,8 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (còpia)',
|
||||
'tours.copy.saved': 'Desada com a excursió nova',
|
||||
'tours.copy.failed': 'No s’ha pogut copiar l’excursió.',
|
||||
'tours.copy.offline':
|
||||
'Desar com a excursió nova necessita connexió, i els canvis pendents d’aquesta excursió van primer.',
|
||||
'tours.gpxExport.action': 'Baixa el GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'Baixa l’excursió desada com a fitxer GPX: tota la ruta amb les altituds que té, per a una aplicació de navegació o un GPS.',
|
||||
|
||||
@@ -57,6 +57,7 @@ const tours: TranslationStrings = {
|
||||
'Průjezdní body a vypočtená linie budou zahozeny a výlet bude opět zobrazovat stopu, se kterou byl zaznamenán. Jeho dny a poznámky zůstanou.',
|
||||
'tours.recorded.restored': 'Zaznamenaná stopa obnovena',
|
||||
'tours.recorded.failed': 'Zaznamenanou stopu se nepodařilo obnovit.',
|
||||
'tours.recorded.offline': 'Obnovení zaznamenané stopy potřebuje připojení a čekající změny této túry jdou první.',
|
||||
'tours.conversion.analyze': 'Naplánovat upravitelnou verzi',
|
||||
'tours.conversion.analyzing': 'Výpočet trasy přes {count} kontrolních bodů…',
|
||||
'tours.conversion.analyzing.one': 'Výpočet trasy přes {count} kontrolní bod…',
|
||||
@@ -659,6 +660,7 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (kopie)',
|
||||
'tours.copy.saved': 'Uloženo jako nová túra',
|
||||
'tours.copy.failed': 'Túru se nepodařilo zkopírovat.',
|
||||
'tours.copy.offline': 'Uložení jako nové túry potřebuje připojení a čekající změny této túry jdou první.',
|
||||
'tours.gpxExport.action': 'Stáhnout GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'Stáhne uloženou túru jako soubor GPX: celou trasu s dostupnými výškami, pro navigační aplikaci nebo GPS přístroj.',
|
||||
|
||||
@@ -55,6 +55,8 @@ const tours: TranslationStrings = {
|
||||
'Die Wegpunkte und die geroutete Linie werden verworfen, und die Tour zeigt wieder die Strecke, mit der sie aufgezeichnet wurde. Ihre Tage und Notizen bleiben.',
|
||||
'tours.recorded.restored': 'Aufgezeichnete Strecke wiederhergestellt',
|
||||
'tours.recorded.failed': 'Die aufgezeichnete Strecke konnte nicht wiederhergestellt werden.',
|
||||
'tours.recorded.offline':
|
||||
'Die aufgezeichnete Strecke wiederherzustellen braucht eine Verbindung, und die wartenden Änderungen dieser Tour gehen vor.',
|
||||
'tours.conversion.analyze': 'Bearbeitbare Version planen',
|
||||
'tours.conversion.analyzing': 'Route durch {count} Kontrollpunkte wird berechnet…',
|
||||
'tours.conversion.analyzing.one': 'Route durch {count} Kontrollpunkt wird berechnet…',
|
||||
@@ -677,6 +679,8 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (Kopie)',
|
||||
'tours.copy.saved': 'Als neue Tour gespeichert',
|
||||
'tours.copy.failed': 'Die Tour konnte nicht kopiert werden.',
|
||||
'tours.copy.offline':
|
||||
'Als neue Tour zu speichern braucht eine Verbindung, und die wartenden Änderungen dieser Tour gehen vor.',
|
||||
'tours.gpxExport.action': 'GPX herunterladen',
|
||||
'tours.gpxExport.hint':
|
||||
'Lädt die gespeicherte Tour als GPX-Datei herunter: die ganze Route mit den vorhandenen Höhen, für eine Navigations-App oder ein GPS-Gerät.',
|
||||
|
||||
@@ -54,6 +54,8 @@ const tours: TranslationStrings = {
|
||||
'The waypoints and the routed line are dropped, and the tour shows the track it was recorded with again. Its days and notes stay.',
|
||||
'tours.recorded.restored': 'Recorded track restored',
|
||||
'tours.recorded.failed': 'The recorded track could not be restored.',
|
||||
'tours.recorded.offline':
|
||||
'Restoring the recorded track needs a connection, and this tour’s waiting changes go first.',
|
||||
'tours.conversion.analyze': 'Plan an editable version',
|
||||
'tours.conversion.analyzing': 'Routing through {count} control points…',
|
||||
'tours.conversion.analyzing.one': 'Routing through {count} control point…',
|
||||
@@ -658,6 +660,7 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (copy)',
|
||||
'tours.copy.saved': 'Saved as a new tour',
|
||||
'tours.copy.failed': 'The tour could not be copied.',
|
||||
'tours.copy.offline': 'Saving as a new tour needs a connection, and this tour’s waiting changes go first.',
|
||||
'tours.gpxExport.action': 'Download GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'Downloads the saved tour as a GPX file: its whole route with the heights it has, for a navigation app or a GPS device.',
|
||||
|
||||
@@ -55,6 +55,8 @@ const tours: TranslationStrings = {
|
||||
'Los puntos de paso y la línea calculada se descartan, y la excursión vuelve a mostrar el track con el que se grabó. Sus días y notas se mantienen.',
|
||||
'tours.recorded.restored': 'Track grabado restaurado',
|
||||
'tours.recorded.failed': 'No se ha podido restaurar el track grabado.',
|
||||
'tours.recorded.offline':
|
||||
'Restaurar el track grabado necesita conexión, y los cambios pendientes de esta excursión van primero.',
|
||||
'tours.conversion.analyze': 'Planificar una versión editable',
|
||||
'tours.conversion.analyzing': 'Calculando la ruta por {count} puntos de control…',
|
||||
'tours.conversion.analyzing.one': 'Calculando la ruta por {count} punto de control…',
|
||||
@@ -673,6 +675,8 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (copia)',
|
||||
'tours.copy.saved': 'Guardada como nueva excursión',
|
||||
'tours.copy.failed': 'No se pudo copiar la excursión.',
|
||||
'tours.copy.offline':
|
||||
'Guardar como nueva excursión necesita conexión, y los cambios pendientes de esta excursión van primero.',
|
||||
'tours.gpxExport.action': 'Descargar GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'Descarga la excursión guardada como archivo GPX: toda la ruta con las altitudes disponibles, para una app de navegación o un GPS.',
|
||||
|
||||
@@ -54,6 +54,8 @@ const tours: TranslationStrings = {
|
||||
'Teekonnapunktid ja arvutatud joon eemaldatakse ning retk näitab taas rada, millega see salvestati. Selle päevad ja märkmed jäävad alles.',
|
||||
'tours.recorded.restored': 'Salvestatud rada taastatud',
|
||||
'tours.recorded.failed': 'Salvestatud rada ei õnnestunud taastada.',
|
||||
'tours.recorded.offline':
|
||||
'Salvestatud raja taastamiseks on vaja ühendust ja selle matka ootel muudatused lähevad enne.',
|
||||
'tours.conversion.analyze': 'Planeeri muudetav versioon',
|
||||
'tours.conversion.analyzing': 'Marsruudi arvutamine {count} kontrollpunkti kaudu…',
|
||||
'tours.conversion.analyzing.one': 'Marsruudi arvutamine {count} kontrollpunkti kaudu…',
|
||||
@@ -662,6 +664,7 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (koopia)',
|
||||
'tours.copy.saved': 'Salvestatud uue matkana',
|
||||
'tours.copy.failed': 'Matka ei õnnestunud kopeerida.',
|
||||
'tours.copy.offline': 'Uue matkana salvestamiseks on vaja ühendust ja selle matka ootel muudatused lähevad enne.',
|
||||
'tours.gpxExport.action': 'Laadi GPX alla',
|
||||
'tours.gpxExport.hint':
|
||||
'Laadib salvestatud matka alla GPX-failina: kogu marsruut olemasolevate kõrgustega, navigatsioonirakenduse või GPS-seadme jaoks.',
|
||||
|
||||
@@ -55,6 +55,8 @@ const tours: TranslationStrings = {
|
||||
'Les points de passage et la ligne calculée sont supprimés, et la sortie affiche de nouveau la trace avec laquelle elle a été enregistrée. Ses jours et ses notes sont conservés.',
|
||||
'tours.recorded.restored': 'Trace enregistrée restaurée',
|
||||
'tours.recorded.failed': "La trace enregistrée n'a pas pu être restaurée.",
|
||||
'tours.recorded.offline':
|
||||
'Restaurer la trace enregistrée demande une connexion, et les modifications en attente de cette sortie passent d’abord.',
|
||||
'tours.conversion.analyze': 'Planifier une version modifiable',
|
||||
'tours.conversion.analyzing': "Calcul de l'itinéraire par {count} points de contrôle…",
|
||||
'tours.conversion.analyzing.one': "Calcul de l'itinéraire par {count} point de contrôle…",
|
||||
@@ -684,6 +686,8 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (copie)',
|
||||
'tours.copy.saved': 'Enregistrée comme nouvelle sortie',
|
||||
'tours.copy.failed': 'La sortie n’a pas pu être copiée.',
|
||||
'tours.copy.offline':
|
||||
'Enregistrer comme nouvelle sortie demande une connexion, et les modifications en attente de cette sortie passent d’abord.',
|
||||
'tours.gpxExport.action': 'Télécharger le GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'Télécharge la sortie enregistrée en fichier GPX : tout l’itinéraire avec les altitudes disponibles, pour une app de navigation ou un GPS.',
|
||||
|
||||
@@ -55,6 +55,8 @@ const tours: TranslationStrings = {
|
||||
'Τα σημεία διέλευσης και η δρομολογημένη γραμμή απορρίπτονται, και η εκδρομή δείχνει ξανά το ίχνος με το οποίο καταγράφηκε. Οι ημέρες και οι σημειώσεις της μένουν.',
|
||||
'tours.recorded.restored': 'Το καταγεγραμμένο ίχνος επανήλθε',
|
||||
'tours.recorded.failed': 'Δεν ήταν δυνατή η επαναφορά του καταγεγραμμένου ίχνους.',
|
||||
'tours.recorded.offline':
|
||||
'Η επαναφορά του καταγεγραμμένου ίχνους χρειάζεται σύνδεση, και οι εκκρεμείς αλλαγές αυτής της εκδρομής στέλνονται πρώτα.',
|
||||
'tours.conversion.analyze': 'Σχεδιασμός επεξεργάσιμης έκδοσης',
|
||||
'tours.conversion.analyzing': 'Δρομολόγηση μέσω {count} σημείων ελέγχου…',
|
||||
'tours.conversion.analyzing.one': 'Δρομολόγηση μέσω {count} σημείου ελέγχου…',
|
||||
@@ -688,6 +690,8 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (αντίγραφο)',
|
||||
'tours.copy.saved': 'Αποθηκεύτηκε ως νέα εκδρομή',
|
||||
'tours.copy.failed': 'Η εκδρομή δεν αντιγράφηκε.',
|
||||
'tours.copy.offline':
|
||||
'Η αποθήκευση ως νέα εκδρομή χρειάζεται σύνδεση, και οι εκκρεμείς αλλαγές αυτής της εκδρομής στέλνονται πρώτα.',
|
||||
'tours.gpxExport.action': 'Λήψη GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'Κατεβάζει την αποθηκευμένη εκδρομή ως αρχείο GPX: όλη τη διαδρομή με τα διαθέσιμα υψόμετρα, για εφαρμογή πλοήγησης ή συσκευή GPS.',
|
||||
|
||||
@@ -54,6 +54,8 @@ const tours: TranslationStrings = {
|
||||
'Az útvonalpontok és a tervezett vonal törlődnek, a túra pedig ismét azt a nyomvonalat mutatja, amellyel rögzítették. A napjai és jegyzetei megmaradnak.',
|
||||
'tours.recorded.restored': 'Rögzített nyomvonal visszaállítva',
|
||||
'tours.recorded.failed': 'A rögzített nyomvonalat nem sikerült visszaállítani.',
|
||||
'tours.recorded.offline':
|
||||
'A rögzített nyomvonal visszaállításához kapcsolat kell, és a túra várakozó módosításai mennek előbb.',
|
||||
'tours.conversion.analyze': 'Szerkeszthető változat tervezése',
|
||||
'tours.conversion.analyzing': 'Útvonaltervezés {count} ellenőrzőponton át…',
|
||||
'tours.conversion.analyzing.one': 'Útvonaltervezés {count} ellenőrzőponton át…',
|
||||
@@ -672,6 +674,7 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (másolat)',
|
||||
'tours.copy.saved': 'Új túraként mentve',
|
||||
'tours.copy.failed': 'A túrát nem sikerült másolni.',
|
||||
'tours.copy.offline': 'Az új túraként való mentéshez kapcsolat kell, és a túra várakozó módosításai mennek előbb.',
|
||||
'tours.gpxExport.action': 'GPX letöltése',
|
||||
'tours.gpxExport.hint':
|
||||
'Letölti a mentett túrát GPX-fájlként: a teljes útvonalat a meglévő magasságokkal, navigációs apphoz vagy GPS-készülékhez.',
|
||||
|
||||
@@ -52,6 +52,8 @@ const tours: TranslationStrings = {
|
||||
'Titik lintasan dan garis rute akan dihapus, dan tur kembali menampilkan jejak yang digunakan saat merekamnya. Hari dan catatannya tetap ada.',
|
||||
'tours.recorded.restored': 'Jejak yang direkam dipulihkan',
|
||||
'tours.recorded.failed': 'Jejak yang direkam tidak dapat dipulihkan.',
|
||||
'tours.recorded.offline':
|
||||
'Memulihkan jejak yang direkam memerlukan koneksi, dan perubahan tur ini yang masih menunggu dikirim lebih dulu.',
|
||||
'tours.conversion.analyze': 'Rencanakan versi yang dapat diedit',
|
||||
'tours.conversion.analyzing': 'Merutekan melalui {count} titik kontrol…',
|
||||
'tours.conversion.failedTrack': 'Jejak ini terlalu pendek untuk direncanakan menjadi tur.',
|
||||
@@ -669,6 +671,8 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (salinan)',
|
||||
'tours.copy.saved': 'Disimpan sebagai tur baru',
|
||||
'tours.copy.failed': 'Tur tidak dapat disalin.',
|
||||
'tours.copy.offline':
|
||||
'Menyimpan sebagai tur baru memerlukan koneksi, dan perubahan tur ini yang masih menunggu dikirim lebih dulu.',
|
||||
'tours.gpxExport.action': 'Unduh GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'Mengunduh tur yang disimpan sebagai file GPX: seluruh rute dengan ketinggian yang tersedia, untuk aplikasi navigasi atau perangkat GPS.',
|
||||
|
||||
@@ -55,6 +55,8 @@ const tours: TranslationStrings = {
|
||||
"I punti di passaggio e la linea calcolata vengono eliminati, e l'escursione mostra di nuovo la traccia con cui è stata registrata. I suoi giorni e le note restano.",
|
||||
'tours.recorded.restored': 'Traccia registrata ripristinata',
|
||||
'tours.recorded.failed': 'Impossibile ripristinare la traccia registrata.',
|
||||
'tours.recorded.offline':
|
||||
'Per ripristinare la traccia registrata serve una connessione, e le modifiche in attesa di questo tour vanno prima.',
|
||||
'tours.conversion.analyze': 'Pianifica una versione modificabile',
|
||||
'tours.conversion.analyzing': 'Calcolo del percorso attraverso {count} punti di controllo…',
|
||||
'tours.conversion.analyzing.one': 'Calcolo del percorso attraverso {count} punto di controllo…',
|
||||
@@ -677,6 +679,8 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (copia)',
|
||||
'tours.copy.saved': 'Salvato come nuovo tour',
|
||||
'tours.copy.failed': 'Non è stato possibile copiare il tour.',
|
||||
'tours.copy.offline':
|
||||
'Per salvare come nuovo tour serve una connessione, e le modifiche in attesa di questo tour vanno prima.',
|
||||
'tours.gpxExport.action': 'Scarica GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'Scarica il tour salvato come file GPX: tutto il percorso con le quote disponibili, per un’app di navigazione o un GPS.',
|
||||
|
||||
@@ -52,6 +52,8 @@ const tours: TranslationStrings = {
|
||||
'ルート上の地点と引き直した線は破棄され、ツアーには記録時のトラックが再び表示されます。日程とメモはそのまま残ります。',
|
||||
'tours.recorded.restored': '記録されたトラックを復元しました',
|
||||
'tours.recorded.failed': '記録されたトラックを復元できませんでした。',
|
||||
'tours.recorded.offline':
|
||||
'記録されたトラックを復元するには接続が必要です。このツアーの未送信の変更が先に送られます。',
|
||||
'tours.conversion.analyze': '編集可能なバージョンを計画',
|
||||
'tours.conversion.analyzing': '{count}個のコントロールポイントを通るルートを計算中…',
|
||||
'tours.conversion.failedTrack': 'このトラックは短すぎるため、ツアーを計画できません。',
|
||||
@@ -651,6 +653,7 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name}(コピー)',
|
||||
'tours.copy.saved': '新しいツアーとして保存しました',
|
||||
'tours.copy.failed': 'ツアーをコピーできませんでした。',
|
||||
'tours.copy.offline': '新しいツアーとして保存するには接続が必要です。このツアーの未送信の変更が先に送られます。',
|
||||
'tours.gpxExport.action': 'GPXをダウンロード',
|
||||
'tours.gpxExport.hint':
|
||||
'保存したツアーをGPXファイルとしてダウンロードします。ルート全体と記録されている標高を含み、ナビアプリやGPS機器で使えます。',
|
||||
|
||||
@@ -51,6 +51,7 @@ const tours: TranslationStrings = {
|
||||
'경로 지점과 계산된 선이 삭제되고, 투어에 기록 당시의 트랙이 다시 표시됩니다. 일정과 메모는 그대로 유지됩니다.',
|
||||
'tours.recorded.restored': '기록된 트랙을 복원했습니다',
|
||||
'tours.recorded.failed': '기록된 트랙을 복원하지 못했습니다.',
|
||||
'tours.recorded.offline': '기록된 트랙을 복원하려면 연결이 필요하며, 이 투어의 대기 중인 변경이 먼저 전송됩니다.',
|
||||
'tours.conversion.analyze': '편집 가능한 버전 계획',
|
||||
'tours.conversion.analyzing': '제어 지점 {count}개를 지나는 경로 계산 중…',
|
||||
'tours.conversion.failedTrack': '이 트랙은 너무 짧아 투어를 계획할 수 없습니다.',
|
||||
@@ -646,6 +647,7 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (사본)',
|
||||
'tours.copy.saved': '새 투어로 저장했습니다',
|
||||
'tours.copy.failed': '투어를 복사하지 못했습니다.',
|
||||
'tours.copy.offline': '새 투어로 저장하려면 연결이 필요하며, 이 투어의 대기 중인 변경이 먼저 전송됩니다.',
|
||||
'tours.gpxExport.action': 'GPX 다운로드',
|
||||
'tours.gpxExport.hint':
|
||||
'저장된 투어를 GPX 파일로 다운로드합니다. 경로 전체와 있는 고도 정보를 담아 내비게이션 앱이나 GPS 기기에서 쓸 수 있습니다.',
|
||||
|
||||
@@ -55,6 +55,8 @@ const tours: TranslationStrings = {
|
||||
'De routepunten en de gerouteerde lijn worden verwijderd, en de tocht toont weer de track waarmee hij is opgenomen. De dagen en notities blijven.',
|
||||
'tours.recorded.restored': 'Opgenomen track hersteld',
|
||||
'tours.recorded.failed': 'De opgenomen track kon niet worden hersteld.',
|
||||
'tours.recorded.offline':
|
||||
'De opgenomen track herstellen vraagt een verbinding, en de wachtende wijzigingen van deze tocht gaan voor.',
|
||||
'tours.conversion.analyze': 'Een bewerkbare versie plannen',
|
||||
'tours.conversion.analyzing': 'Route berekenen via {count} controlepunten…',
|
||||
'tours.conversion.analyzing.one': 'Route berekenen via {count} controlepunt…',
|
||||
@@ -674,6 +676,8 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (kopie)',
|
||||
'tours.copy.saved': 'Opgeslagen als nieuwe tocht',
|
||||
'tours.copy.failed': 'De tocht kon niet worden gekopieerd.',
|
||||
'tours.copy.offline':
|
||||
'Opslaan als nieuwe tocht vraagt een verbinding, en de wachtende wijzigingen van deze tocht gaan voor.',
|
||||
'tours.gpxExport.action': 'GPX downloaden',
|
||||
'tours.gpxExport.hint':
|
||||
'Downloadt de opgeslagen tocht als GPX-bestand: de hele route met de beschikbare hoogtes, voor een navigatie-app of een gps-apparaat.',
|
||||
|
||||
@@ -61,6 +61,8 @@ const tours: TranslationStrings = {
|
||||
'Punkty trasy i wyznaczona linia zostaną usunięte, a wycieczka znów pokaże ślad, z którym została zarejestrowana. Jej dni i notatki zostają.',
|
||||
'tours.recorded.restored': 'Przywrócono zarejestrowany ślad',
|
||||
'tours.recorded.failed': 'Nie udało się przywrócić zarejestrowanego śladu.',
|
||||
'tours.recorded.offline':
|
||||
'Przywrócenie zarejestrowanego śladu wymaga połączenia, a oczekujące zmiany tej trasy idą najpierw.',
|
||||
'tours.conversion.analyze': 'Zaplanuj wersję do edycji',
|
||||
'tours.conversion.analyzing': 'Wyznaczanie trasy przez {count} punktu kontrolnego…',
|
||||
'tours.conversion.analyzing.one': 'Wyznaczanie trasy przez {count} punkt kontrolny…',
|
||||
@@ -678,6 +680,7 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (kopia)',
|
||||
'tours.copy.saved': 'Zapisano jako nową trasę',
|
||||
'tours.copy.failed': 'Nie udało się skopiować trasy.',
|
||||
'tours.copy.offline': 'Zapisanie jako nowej trasy wymaga połączenia, a oczekujące zmiany tej trasy idą najpierw.',
|
||||
'tours.gpxExport.action': 'Pobierz GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'Pobiera zapisaną trasę jako plik GPX: cały przebieg z dostępnymi wysokościami, do aplikacji nawigacyjnej lub urządzenia GPS.',
|
||||
|
||||
@@ -60,6 +60,8 @@ const tours: TranslationStrings = {
|
||||
'Путевые точки и проложенная линия будут удалены, и тур снова покажет трек, с которым он был записан. Его дни и заметки сохраняются.',
|
||||
'tours.recorded.restored': 'Записанный трек восстановлен',
|
||||
'tours.recorded.failed': 'Не удалось восстановить записанный трек.',
|
||||
'tours.recorded.offline':
|
||||
'Для восстановления записанного трека нужно подключение, и сначала отправляются ожидающие изменения этого похода.',
|
||||
'tours.conversion.analyze': 'Спланировать редактируемую версию',
|
||||
'tours.conversion.analyzing': 'Прокладка маршрута через {count} контрольной точки…',
|
||||
'tours.conversion.analyzing.one': 'Прокладка маршрута через {count} контрольную точку…',
|
||||
@@ -682,6 +684,8 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (копия)',
|
||||
'tours.copy.saved': 'Сохранено как новый поход',
|
||||
'tours.copy.failed': 'Не удалось скопировать поход.',
|
||||
'tours.copy.offline':
|
||||
'Для сохранения как нового похода нужно подключение, и сначала отправляются ожидающие изменения этого похода.',
|
||||
'tours.gpxExport.action': 'Скачать GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'Скачивает сохранённый поход как файл GPX: весь маршрут с имеющимися высотами, для навигационного приложения или GPS-устройства.',
|
||||
|
||||
@@ -58,6 +58,7 @@ const tours: TranslationStrings = {
|
||||
'Body trasy a vypočítaná línia sa zahodia a túra bude opäť zobrazovať stopu, s ktorou bola zaznamenaná. Jej dni a poznámky zostanú.',
|
||||
'tours.recorded.restored': 'Zaznamenaná stopa obnovená',
|
||||
'tours.recorded.failed': 'Zaznamenanú stopu sa nepodarilo obnoviť.',
|
||||
'tours.recorded.offline': 'Obnovenie zaznamenanej stopy potrebuje pripojenie a čakajúce zmeny tejto túry idú prvé.',
|
||||
'tours.conversion.analyze': 'Naplánovať upraviteľnú verziu',
|
||||
'tours.conversion.analyzing': 'Výpočet trasy cez {count} kontrolných bodov…',
|
||||
'tours.conversion.analyzing.one': 'Výpočet trasy cez {count} kontrolný bod…',
|
||||
@@ -661,6 +662,7 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (kópia)',
|
||||
'tours.copy.saved': 'Uložené ako nová túra',
|
||||
'tours.copy.failed': 'Túru sa nepodarilo skopírovať.',
|
||||
'tours.copy.offline': 'Uloženie ako novej túry potrebuje pripojenie a čakajúce zmeny tejto túry idú prvé.',
|
||||
'tours.gpxExport.action': 'Stiahnuť GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'Stiahne uloženú túru ako súbor GPX: celú trasu s dostupnými výškami, pre navigačnú aplikáciu alebo GPS zariadenie.',
|
||||
|
||||
@@ -54,6 +54,8 @@ const tours: TranslationStrings = {
|
||||
'Ruttpunkterna och den ruttade linjen tas bort, och turen visar åter spåret den spelades in med. Dess dagar och anteckningar finns kvar.',
|
||||
'tours.recorded.restored': 'Inspelat spår återställt',
|
||||
'tours.recorded.failed': 'Det inspelade spåret kunde inte återställas.',
|
||||
'tours.recorded.offline':
|
||||
'Att återställa det inspelade spåret kräver en anslutning, och turens väntande ändringar skickas först.',
|
||||
'tours.conversion.analyze': 'Planera en redigerbar version',
|
||||
'tours.conversion.analyzing': 'Beräknar rutt genom {count} kontrollpunkter…',
|
||||
'tours.conversion.analyzing.one': 'Beräknar rutt genom {count} kontrollpunkt…',
|
||||
@@ -657,6 +659,7 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (kopia)',
|
||||
'tours.copy.saved': 'Sparad som ny tur',
|
||||
'tours.copy.failed': 'Turen kunde inte kopieras.',
|
||||
'tours.copy.offline': 'Att spara som ny tur kräver en anslutning, och turens väntande ändringar skickas först.',
|
||||
'tours.gpxExport.action': 'Ladda ner GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'Laddar ner den sparade turen som GPX-fil: hela rutten med de höjder som finns, för en navigeringsapp eller en GPS-enhet.',
|
||||
|
||||
@@ -50,6 +50,8 @@ const tours: TranslationStrings = {
|
||||
'จุดแวะและเส้นที่คำนวณไว้จะถูกลบ และทัวร์จะแสดงแทร็กที่ใช้บันทึกอีกครั้ง วันและบันทึกจะยังคงอยู่',
|
||||
'tours.recorded.restored': 'กู้คืนแทร็กที่บันทึกไว้แล้ว',
|
||||
'tours.recorded.failed': 'ไม่สามารถกู้คืนแทร็กที่บันทึกไว้ได้',
|
||||
'tours.recorded.offline':
|
||||
'การกู้คืนแทร็กที่บันทึกไว้ต้องใช้การเชื่อมต่อ และการเปลี่ยนแปลงที่รอส่งของทัวร์นี้จะถูกส่งก่อน',
|
||||
'tours.conversion.analyze': 'วางแผนเวอร์ชันที่แก้ไขได้',
|
||||
'tours.conversion.analyzing': 'กำลังคำนวณเส้นทางผ่านจุดควบคุม {count} จุด…',
|
||||
'tours.conversion.failedTrack': 'แทร็กนี้สั้นเกินกว่าจะใช้วางแผนทัวร์ได้',
|
||||
@@ -637,6 +639,7 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (สำเนา)',
|
||||
'tours.copy.saved': 'บันทึกเป็นทัวร์ใหม่แล้ว',
|
||||
'tours.copy.failed': 'คัดลอกทัวร์ไม่สำเร็จ',
|
||||
'tours.copy.offline': 'การบันทึกเป็นทัวร์ใหม่ต้องใช้การเชื่อมต่อ และการเปลี่ยนแปลงที่รอส่งของทัวร์นี้จะถูกส่งก่อน',
|
||||
'tours.gpxExport.action': 'ดาวน์โหลด GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'ดาวน์โหลดทัวร์ที่บันทึกไว้เป็นไฟล์ GPX ทั้งเส้นทางพร้อมความสูงที่มี สำหรับแอปนำทางหรืออุปกรณ์ GPS',
|
||||
|
||||
@@ -20,7 +20,7 @@ const toursModules = import.meta.glob<{ default: TranslationStrings }>('./*/tour
|
||||
const TOUR_DOMAINS: { file: string; generalKeyCount: number; modules: DomainModules }[] = [
|
||||
{
|
||||
file: 'tours',
|
||||
generalKeyCount: 1347,
|
||||
generalKeyCount: 1349,
|
||||
modules: toursModules,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -54,6 +54,8 @@ const tours: TranslationStrings = {
|
||||
'Rota noktaları ve rotalanmış çizgi kaldırılır, tur yeniden kaydedildiği izi gösterir. Günleri ve notları kalır.',
|
||||
'tours.recorded.restored': 'Kaydedilmiş iz geri yüklendi',
|
||||
'tours.recorded.failed': 'Kaydedilmiş iz geri yüklenemedi.',
|
||||
'tours.recorded.offline':
|
||||
'Kaydedilmiş izi geri yüklemek bağlantı gerektirir ve bu turun bekleyen değişiklikleri önce gönderilir.',
|
||||
'tours.conversion.analyze': 'Düzenlenebilir sürüm planla',
|
||||
'tours.conversion.analyzing': '{count} kontrol noktası üzerinden rota hesaplanıyor…',
|
||||
'tours.conversion.analyzing.one': '{count} kontrol noktası üzerinden rota hesaplanıyor…',
|
||||
@@ -661,6 +663,8 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (kopya)',
|
||||
'tours.copy.saved': 'Yeni tur olarak kaydedildi',
|
||||
'tours.copy.failed': 'Tur kopyalanamadı.',
|
||||
'tours.copy.offline':
|
||||
'Yeni tur olarak kaydetmek bağlantı gerektirir ve bu turun bekleyen değişiklikleri önce gönderilir.',
|
||||
'tours.gpxExport.action': 'GPX indir',
|
||||
'tours.gpxExport.hint':
|
||||
'Kayıtlı turu GPX dosyası olarak indirir: mevcut yükseltileriyle tüm rota, bir navigasyon uygulaması ya da GPS cihazı için.',
|
||||
|
||||
@@ -60,6 +60,8 @@ const tours: TranslationStrings = {
|
||||
'Маршрутні точки та прокладену лінію буде видалено, і тур знову показуватиме трек, з яким його було записано. Його дні та нотатки залишаються.',
|
||||
'tours.recorded.restored': 'Записаний трек відновлено',
|
||||
'tours.recorded.failed': 'Не вдалося відновити записаний трек.',
|
||||
'tours.recorded.offline':
|
||||
'Для відновлення записаного треку потрібне підключення, і спершу надсилаються зміни цього походу, що очікують.',
|
||||
'tours.conversion.analyze': 'Спланувати редаговану версію',
|
||||
'tours.conversion.analyzing': 'Прокладання маршруту через {count} контрольної точки…',
|
||||
'tours.conversion.analyzing.one': 'Прокладання маршруту через {count} контрольну точку…',
|
||||
@@ -675,6 +677,8 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (копія)',
|
||||
'tours.copy.saved': 'Збережено як новий похід',
|
||||
'tours.copy.failed': 'Не вдалося скопіювати похід.',
|
||||
'tours.copy.offline':
|
||||
'Для збереження як нового походу потрібне підключення, і спершу надсилаються зміни цього походу, що очікують.',
|
||||
'tours.gpxExport.action': 'Завантажити GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'Завантажує збережений похід як файл GPX: увесь маршрут із наявними висотами, для навігаційного застосунку чи GPS-пристрою.',
|
||||
|
||||
@@ -53,6 +53,8 @@ const tours: TranslationStrings = {
|
||||
'Các điểm trên tuyến và đường đã định tuyến sẽ bị xóa, chuyến tham quan sẽ hiển thị lại vệt hành trình đã ghi. Các ngày và ghi chú được giữ nguyên.',
|
||||
'tours.recorded.restored': 'Đã khôi phục vệt hành trình đã ghi',
|
||||
'tours.recorded.failed': 'Không thể khôi phục vệt hành trình đã ghi.',
|
||||
'tours.recorded.offline':
|
||||
'Khôi phục vệt hành trình đã ghi cần kết nối mạng, và các thay đổi đang chờ của chuyến này được gửi trước.',
|
||||
'tours.conversion.analyze': 'Lên kế hoạch phiên bản có thể chỉnh sửa',
|
||||
'tours.conversion.analyzing': 'Đang định tuyến qua {count} điểm kiểm soát…',
|
||||
'tours.conversion.failedTrack': 'Vệt hành trình này quá ngắn để lên kế hoạch chuyến tham quan.',
|
||||
@@ -660,6 +662,8 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name} (bản sao)',
|
||||
'tours.copy.saved': 'Đã lưu thành chuyến đi bộ mới',
|
||||
'tours.copy.failed': 'Không thể sao chép chuyến đi bộ.',
|
||||
'tours.copy.offline':
|
||||
'Lưu thành chuyến đi bộ mới cần kết nối mạng, và các thay đổi đang chờ của chuyến này được gửi trước.',
|
||||
'tours.gpxExport.action': 'Tải GPX',
|
||||
'tours.gpxExport.hint':
|
||||
'Tải chuyến đi bộ đã lưu dưới dạng tệp GPX: toàn bộ tuyến đường kèm độ cao hiện có, dùng cho ứng dụng dẫn đường hoặc thiết bị GPS.',
|
||||
|
||||
@@ -48,6 +48,7 @@ const tours: TranslationStrings = {
|
||||
'tours.recorded.confirmBody': '路線點和規劃的線條將被移除,遊程會重新顯示錄製時的軌跡。它的日程和備註會保留。',
|
||||
'tours.recorded.restored': '已還原錄製的軌跡',
|
||||
'tours.recorded.failed': '無法還原錄製的軌跡。',
|
||||
'tours.recorded.offline': '還原錄製的軌跡需要網路連線,此遊程待傳送的變更會先傳送。',
|
||||
'tours.conversion.analyze': '規劃可編輯版本',
|
||||
'tours.conversion.analyzing': '正在規劃經過 {count} 個控制點的路線…',
|
||||
'tours.conversion.failedTrack': '這條軌跡太短,無法據此規劃遊程。',
|
||||
@@ -615,6 +616,7 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name}(副本)',
|
||||
'tours.copy.saved': '已另存為新遊程',
|
||||
'tours.copy.failed': '無法複製遊程。',
|
||||
'tours.copy.offline': '另存為新遊程需要網路連線,此遊程待傳送的變更會先傳送。',
|
||||
'tours.gpxExport.action': '下載 GPX',
|
||||
'tours.gpxExport.hint': '將已儲存的遊程下載為 GPX 檔案:包含完整路線與現有的海拔資料,可用於導航 App 或 GPS 裝置。',
|
||||
'tours.gpxExport.saveFirst': '請先儲存遊程,再下載為 GPX',
|
||||
|
||||
@@ -49,6 +49,7 @@ const tours: TranslationStrings = {
|
||||
'tours.recorded.confirmBody': '路线点和规划的线路将被删除,游览路线会重新显示录制时的轨迹。它的日程和备注保持不变。',
|
||||
'tours.recorded.restored': '已恢复录制的轨迹',
|
||||
'tours.recorded.failed': '无法恢复录制的轨迹。',
|
||||
'tours.recorded.offline': '恢复录制的轨迹需要网络连接,此路线待发送的更改会先发送。',
|
||||
'tours.conversion.analyze': '规划可编辑版本',
|
||||
'tours.conversion.analyzing': '正在规划经过 {count} 个控制点的路线…',
|
||||
'tours.conversion.failedTrack': '此轨迹太短,无法据此规划游览路线。',
|
||||
@@ -616,6 +617,7 @@ const tours: TranslationStrings = {
|
||||
'tours.copy.name': '{name}(副本)',
|
||||
'tours.copy.saved': '已另存为新路线',
|
||||
'tours.copy.failed': '无法复制路线。',
|
||||
'tours.copy.offline': '另存为新路线需要网络连接,此路线待发送的更改会先发送。',
|
||||
'tours.gpxExport.action': '下载 GPX',
|
||||
'tours.gpxExport.hint': '将已保存的路线下载为 GPX 文件:包含完整路线和已有的海拔数据,可用于导航应用或 GPS 设备。',
|
||||
'tours.gpxExport.saveFirst': '请先保存路线,再下载为 GPX',
|
||||
|
||||
Reference in New Issue
Block a user