mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-24 07:53:09 +00:00
feat(journey): make the linked trips' GPX tracks a switch, off by default
#1260 drew the GPX tracks of every trip behind a journey onto its map, with nothing to switch off — the reasoning being that a route imported into a linked trip is part of the journey's story. For a trip carrying a season of recorded drives it is instead a map nobody asked for, drawn from places that never became an entry. So it becomes a journey-level setting, owner-only like the other Journey Settings, and it starts off: a journal should show what its author put in it, and #1260's set is everything the linked trips happen to contain. The switch gates the request, not just the rendering — the endpoint ships full unthinned geometry, which is megabytes fetched on every journey open for a map nobody wanted. `journeyTracks()` itself is deliberately untouched, so TREK Studio keeps the set its saved books were laid out with. Also fixes what the reporter's screenshot actually shows: JourneyMap fed track coordinates into `fitBounds`, so one drive across a country zoomed the journey map out until the entries were specks. Tracks now only frame the map when there is nothing else to frame, which is what JourneyMapGL already did — the same journey used to open at two different zooms depending on the renderer. Closes #2194 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S5VwmiBQ9sPCJwfmpv64r3
This commit is contained in:
@@ -77,6 +77,21 @@ export function JourneySettingsDialog({ journey, onClose, onSaved, onOpenInvite,
|
||||
}
|
||||
}
|
||||
|
||||
// Saved on the spot rather than on Save, like the archive switch above it:
|
||||
// it is a view setting, and the point of it is seeing the map change (#2194).
|
||||
const [savingTracks, setSavingTracks] = useState(false)
|
||||
const handleTracksToggle = async () => {
|
||||
setSavingTracks(true)
|
||||
try {
|
||||
await updateJourney(journey.id, { show_trip_tracks: !journey.show_trip_tracks })
|
||||
onSaved()
|
||||
} catch {
|
||||
toast.error(t('journey.settings.saveFailed'))
|
||||
} finally {
|
||||
setSavingTracks(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleDelete = async () => {
|
||||
try {
|
||||
await deleteJourney(journey.id)
|
||||
@@ -141,6 +156,30 @@ export function JourneySettingsDialog({ journey, onClose, onSaved, onOpenInvite,
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Trip GPX tracks on the journey map (#2194) */}
|
||||
<div>
|
||||
<label className="text-[10px] font-semibold tracking-[0.12em] uppercase text-zinc-500 block mb-1.5">{t('journey.settings.tracks')}</label>
|
||||
<button
|
||||
type="button"
|
||||
role="switch"
|
||||
aria-checked={!!journey.show_trip_tracks}
|
||||
disabled={savingTracks}
|
||||
onClick={handleTracksToggle}
|
||||
className="w-full flex items-center gap-3 px-3.5 py-2.5 border border-zinc-200 dark:border-zinc-700 rounded-xl bg-white dark:bg-zinc-800 text-left disabled:opacity-60"
|
||||
>
|
||||
<span className="flex-1 min-w-0">
|
||||
<span className="block text-[14px] text-zinc-900 dark:text-white">{t('journey.settings.showTripTracks')}</span>
|
||||
<span className="block text-[11px] text-zinc-500">{t('journey.settings.showTripTracksHint')}</span>
|
||||
</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className={`w-9 h-5 rounded-full flex-shrink-0 p-0.5 transition-colors ${journey.show_trip_tracks ? 'bg-emerald-500' : 'bg-zinc-300 dark:bg-zinc-600'}`}
|
||||
>
|
||||
<span className={`block w-4 h-4 rounded-full bg-white transition-transform ${journey.show_trip_tracks ? 'translate-x-4' : ''}`} />
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Right column */}
|
||||
|
||||
@@ -268,6 +268,18 @@ function JourneyMap(
|
||||
itemsRef.current = items
|
||||
|
||||
const allCoords: L.LatLngTuple[] = []
|
||||
/**
|
||||
* Track geometry is kept OUT of the fit set (#2194) and used only when there
|
||||
* is nothing else to frame.
|
||||
*
|
||||
* A journey's opening viewport should show the journey — its entries and the
|
||||
* trail between them. Letting a recorded GPX into the bounds meant one drive
|
||||
* across a country zoomed the map out until the entries were specks, which
|
||||
* is what the reporter's screenshot shows. JourneyMapGL already fits on
|
||||
* entries + trail alone (JourneyMapGL.tsx), so this also ends an asymmetry
|
||||
* where the same journey framed differently per renderer.
|
||||
*/
|
||||
const trackCoords: L.LatLngTuple[] = []
|
||||
|
||||
if (stableTrail.length > 1) {
|
||||
const coords = stableTrail.map(p => [p.lat, p.lng] as L.LatLngTuple)
|
||||
@@ -293,7 +305,7 @@ function JourneyMap(
|
||||
// becomes innerHTML, and a track name is a place name off a shared trip.
|
||||
if (track.name) line.bindTooltip(escapeHtml(track.name), { sticky: true, direction: 'top', className: 'map-tooltip' })
|
||||
line.addTo(map)
|
||||
coords.forEach(c => allCoords.push(c))
|
||||
coords.forEach(c => trackCoords.push(c))
|
||||
}
|
||||
|
||||
// route polyline — only in non-fullscreen (sidebar map) mode
|
||||
@@ -341,9 +353,12 @@ function JourneyMap(
|
||||
if (!mapRef.current) return
|
||||
try {
|
||||
map.invalidateSize()
|
||||
if (allCoords.length > 0) {
|
||||
// Tracks only get a say when the journey has nothing located of its own —
|
||||
// a world view would be worse than framing the one thing on the map.
|
||||
const fitCoords = allCoords.length > 0 ? allCoords : trackCoords
|
||||
if (fitCoords.length > 0) {
|
||||
const pb = paddingBottom || 50
|
||||
map.fitBounds(L.latLngBounds(allCoords), { paddingTopLeft: [50, 50], paddingBottomRight: [50, pb], maxZoom: 16 })
|
||||
map.fitBounds(L.latLngBounds(fitCoords), { paddingTopLeft: [50, 50], paddingBottomRight: [50, pb], maxZoom: 16 })
|
||||
} else {
|
||||
map.setView([30, 0], 2)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,9 @@ import { lockBodyScroll } from '../../utils/bodyScrollLock'
|
||||
import type { JourneyEntry } from '../../store/journeyStore'
|
||||
import { createDraftJourneyEntry } from './JourneyDetailPage.helpers'
|
||||
|
||||
/** Stable identity for "this journey draws no trip tracks" (#2194). */
|
||||
const NO_TRACKS: JourneyTrack[] = []
|
||||
|
||||
/**
|
||||
* Journey detail page logic — owns the journey load + WebSocket live sync, the
|
||||
* timeline/gallery view state, the entry editor/viewer/delete/lightbox dialogs,
|
||||
@@ -71,18 +74,31 @@ export function useJourneyDetail() {
|
||||
if (id) loadJourney(Number(id)).catch(() => {})
|
||||
}, [id])
|
||||
|
||||
// GPX tracks of the trips behind this journey (#1260). Loaded separately from the
|
||||
// journey itself: a journey without tracks is the common case, and a failed lookup
|
||||
// should cost the map its lines, not the whole page.
|
||||
const [tracks, setTracks] = useState<JourneyTrack[]>([])
|
||||
// GPX tracks of the trips behind this journey (#1260), drawn only when the
|
||||
// journey asks for them (#2194). Loaded separately from the journey itself: a
|
||||
// journey without tracks is the common case, and a failed lookup should cost
|
||||
// the map its lines, not the whole page.
|
||||
//
|
||||
// The switch gates the REQUEST, not just the rendering: the endpoint ships
|
||||
// full unthinned geometry, which for a trip carrying a season of recorded
|
||||
// drives is megabytes fetched on every journey open for a map nobody asked
|
||||
// for. It stays untouched on the server so TREK Studio, which freezes the
|
||||
// same endpoint's output into a saved book, keeps the set it laid out with.
|
||||
const [tracks, setTracks] = useState<JourneyTrack[]>(NO_TRACKS)
|
||||
const showTripTracks = !!current?.show_trip_tracks
|
||||
useEffect(() => {
|
||||
if (!id) return
|
||||
if (!id || !showTripTracks) {
|
||||
// A stable empty array: a fresh literal here would be a new reference on
|
||||
// every toggle and re-render the map for nothing.
|
||||
setTracks(NO_TRACKS)
|
||||
return
|
||||
}
|
||||
let cancelled = false
|
||||
journeyApi.listTracks(Number(id))
|
||||
.then(res => { if (!cancelled) setTracks(res.tracks ?? []) })
|
||||
.catch(() => { if (!cancelled) setTracks([]) })
|
||||
.then(res => { if (!cancelled) setTracks(res.tracks ?? NO_TRACKS) })
|
||||
.catch(() => { if (!cancelled) setTracks(NO_TRACKS) })
|
||||
return () => { cancelled = true }
|
||||
}, [id])
|
||||
}, [id, showTripTracks])
|
||||
|
||||
useEffect(() => {
|
||||
if (current?.hide_skeletons !== undefined) setHideSkeletons(current.hide_skeletons)
|
||||
|
||||
@@ -11,6 +11,12 @@ export interface Journey {
|
||||
cover_gradient?: string | null
|
||||
cover_image?: string | null
|
||||
status: 'draft' | 'active' | 'completed' | 'archived'
|
||||
/**
|
||||
* Draw the GPX tracks of the journey's linked trips on its map (#2194).
|
||||
* Off unless the owner asks for it — see the migration for why the default
|
||||
* flipped. Optional so a cached pre-#2194 journey still parses.
|
||||
*/
|
||||
show_trip_tracks?: boolean
|
||||
created_at: number
|
||||
updated_at: number
|
||||
}
|
||||
|
||||
@@ -4191,6 +4191,29 @@ function runMigrations(db: Database.Database): void {
|
||||
() => {
|
||||
db.prepare("UPDATE addons SET type = 'integration' WHERE id = 'naver_list_import'").run();
|
||||
},
|
||||
/**
|
||||
* Whether a journey's map draws the GPX tracks of the trips behind it (#2194).
|
||||
*
|
||||
* #1260 added those tracks unconditionally and with nothing to switch off,
|
||||
* on the reasoning that a route imported into a linked trip is part of the
|
||||
* journey's story. For a trip carrying a season of recorded drives it is
|
||||
* instead a map nobody asked for, drawn from places that never became an
|
||||
* entry — so it becomes a journey-level setting.
|
||||
*
|
||||
* DEFAULT 0, i.e. off: the tracks are opt-in from here on. That is a
|
||||
* deliberate behaviour change rather than a preserved default — a journal
|
||||
* should show what its author put in it, and #1260's set is everything the
|
||||
* linked trips happen to contain. Owners who want them back have one
|
||||
* switch in Journey Settings.
|
||||
*
|
||||
* Appended LAST: the array is index-addressed against schema_version.
|
||||
*/
|
||||
() => {
|
||||
const cols = db.prepare("SELECT name FROM pragma_table_info('journeys')").all() as Array<{ name: string }>;
|
||||
if (!cols.some(c => c.name === 'show_trip_tracks')) {
|
||||
db.exec('ALTER TABLE journeys ADD COLUMN show_trip_tracks INTEGER NOT NULL DEFAULT 0');
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
if (currentVersion < migrations.length) {
|
||||
|
||||
@@ -329,6 +329,7 @@ export class JourneyDomainService {
|
||||
cover_gradient: string;
|
||||
cover_image: string;
|
||||
status: string;
|
||||
show_trip_tracks: boolean | number;
|
||||
}>,
|
||||
): Journey | null {
|
||||
// Journey-level settings (title, cover, status) are owner-only — editors
|
||||
@@ -336,14 +337,17 @@ export class JourneyDomainService {
|
||||
if (!this.isOwner(journeyId, userId)) return null;
|
||||
|
||||
const ALLOWED_STATUSES = ['draft', 'active', 'completed', 'archived'];
|
||||
const allowed = ['title', 'subtitle', 'cover_gradient', 'cover_image', 'status'];
|
||||
const allowed = ['title', 'subtitle', 'cover_gradient', 'cover_image', 'status', 'show_trip_tracks'];
|
||||
// Stored as INTEGER, and better-sqlite3 refuses to bind a JS boolean, so the
|
||||
// one flag on this table is coerced rather than passed through.
|
||||
const BOOLEAN_FIELDS = new Set(['show_trip_tracks']);
|
||||
const fields: string[] = [];
|
||||
const values: unknown[] = [];
|
||||
for (const [key, val] of Object.entries(data)) {
|
||||
if (val !== undefined && allowed.includes(key)) {
|
||||
if (key === 'status' && !ALLOWED_STATUSES.includes(val as string)) continue;
|
||||
fields.push(`${key} = ?`);
|
||||
values.push(val);
|
||||
values.push(BOOLEAN_FIELDS.has(key) ? (val ? 1 : 0) : val);
|
||||
}
|
||||
}
|
||||
if (fields.length === 0) return this.db.prepare('SELECT * FROM journeys WHERE id = ?').get(journeyId) as Journey;
|
||||
|
||||
@@ -356,6 +356,8 @@ export interface Journey {
|
||||
cover_gradient?: string | null;
|
||||
cover_image?: string | null;
|
||||
status: 'draft' | 'active' | 'completed' | 'archived';
|
||||
/** Draw the linked trips' GPX tracks on this journey's map (#2194). 0 by default. */
|
||||
show_trip_tracks?: number;
|
||||
created_at: number;
|
||||
updated_at: number;
|
||||
}
|
||||
|
||||
@@ -356,6 +356,30 @@ describe('updateJourney', () => {
|
||||
expect(result).not.toBeNull();
|
||||
expect(result!.status).toBe('active');
|
||||
});
|
||||
|
||||
it('JOURNEY-SVC-021d: trip GPX tracks are off until the owner switches them on (#2194)', () => {
|
||||
const { user } = createUser(testDb);
|
||||
const journey = createJourney(testDb, user.id, { title: 'Norway' });
|
||||
|
||||
// #1260 drew the linked trips' tracks unconditionally; they are opt-in now.
|
||||
expect(svc.updateJourney(journey.id, user.id, {})!.show_trip_tracks).toBe(0);
|
||||
|
||||
// A JS boolean has to survive the trip into an INTEGER column —
|
||||
// better-sqlite3 refuses to bind one, so this would throw uncoerced.
|
||||
expect(svc.updateJourney(journey.id, user.id, { show_trip_tracks: true })!.show_trip_tracks).toBe(1);
|
||||
expect(svc.updateJourney(journey.id, user.id, { show_trip_tracks: false })!.show_trip_tracks).toBe(0);
|
||||
});
|
||||
|
||||
it('JOURNEY-SVC-021e: an editor cannot switch the trip tracks on (#2194)', () => {
|
||||
const { user } = createUser(testDb);
|
||||
const { user: editor } = createUser(testDb, { username: 'tracks-editor' });
|
||||
const journey = createJourney(testDb, user.id, { title: 'Norway' });
|
||||
testDb.prepare("INSERT INTO journey_contributors (journey_id, user_id, role, added_at) VALUES (?, ?, 'editor', 0)")
|
||||
.run(journey.id, editor.id);
|
||||
|
||||
// Journey-level settings stay owner-only, same as title and status.
|
||||
expect(svc.updateJourney(journey.id, editor.id, { show_trip_tracks: true })).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteJourney', () => {
|
||||
|
||||
@@ -216,6 +216,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Name', // en-fallback
|
||||
'journey.settings.subtitle': 'Subtitle', // en-fallback
|
||||
'journey.settings.subtitlePlaceholder': 'e.g. Thailand, Vietnam & Cambodia', // en-fallback
|
||||
'journey.settings.tracks': 'مسارات GPX',
|
||||
'journey.settings.showTripTracks': 'إظهار جميع مسارات GPX للرحلات',
|
||||
'journey.settings.showTripTracksHint': 'يرسم على الخريطة المسارات المسجَّلة من الرحلات المرتبطة.',
|
||||
'journey.settings.delete': 'Delete', // en-fallback
|
||||
'journey.settings.deleteJourney': 'Delete Journey', // en-fallback
|
||||
'journey.settings.deleteMessage': 'Delete "{title}"? All entries and photos will be lost.', // en-fallback
|
||||
|
||||
@@ -190,6 +190,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Nome',
|
||||
'journey.settings.subtitle': 'Subtítulo',
|
||||
'journey.settings.subtitlePlaceholder': 'ex. Tailândia, Vietnã e Camboja',
|
||||
'journey.settings.tracks': 'Trilhas GPX',
|
||||
'journey.settings.showTripTracks': 'Mostrar todas as trilhas GPX das viagens',
|
||||
'journey.settings.showTripTracksHint': 'Desenha no mapa as rotas gravadas das viagens vinculadas.',
|
||||
'journey.settings.endJourney': 'Arquivar Jornada',
|
||||
'journey.settings.reopenJourney': 'Restaurar Jornada',
|
||||
'journey.settings.archived': 'Jornada arquivada',
|
||||
|
||||
@@ -190,6 +190,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Nom',
|
||||
'journey.settings.subtitle': 'Subtítol',
|
||||
'journey.settings.subtitlePlaceholder': 'p. ex. Tailàndia, Vietnam i Cambodja',
|
||||
'journey.settings.tracks': 'Traces GPX',
|
||||
'journey.settings.showTripTracks': 'Mostra totes les traces GPX dels viatges',
|
||||
'journey.settings.showTripTracksHint': 'Dibuixa al mapa les rutes enregistrades dels viatges enllaçats.',
|
||||
'journey.settings.endJourney': 'Arxiva el viatge',
|
||||
'journey.settings.reopenJourney': 'Restaura el viatge',
|
||||
'journey.settings.archived': 'Viatge arxivat',
|
||||
|
||||
@@ -190,6 +190,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Název',
|
||||
'journey.settings.subtitle': 'Podtitul',
|
||||
'journey.settings.subtitlePlaceholder': 'např. Thajsko, Vietnam a Kambodža',
|
||||
'journey.settings.tracks': 'Stopy GPX',
|
||||
'journey.settings.showTripTracks': 'Zobrazit všechny GPX stopy z cest',
|
||||
'journey.settings.showTripTracksHint': 'Vykreslí na mapě zaznamenané trasy z propojených cest.',
|
||||
'journey.settings.endJourney': 'Archivovat cestu',
|
||||
'journey.settings.reopenJourney': 'Obnovit cestu',
|
||||
'journey.settings.archived': 'Cesta archivována',
|
||||
|
||||
@@ -194,6 +194,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Name',
|
||||
'journey.settings.subtitle': 'Untertitel',
|
||||
'journey.settings.subtitlePlaceholder': 'z.B. Thailand, Vietnam & Kambodscha',
|
||||
'journey.settings.tracks': 'GPX-Tracks',
|
||||
'journey.settings.showTripTracks': 'Alle GPX-Tracks der Reisen anzeigen',
|
||||
'journey.settings.showTripTracksHint': 'Zeichnet die aufgezeichneten Routen der verknüpften Reisen auf die Karte.',
|
||||
'journey.settings.endJourney': 'Reise archivieren',
|
||||
'journey.settings.reopenJourney': 'Reise wiederherstellen',
|
||||
'journey.settings.archived': 'Reise archiviert',
|
||||
|
||||
@@ -202,6 +202,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Name',
|
||||
'journey.settings.subtitle': 'Subtitle',
|
||||
'journey.settings.subtitlePlaceholder': 'e.g. Thailand, Vietnam & Cambodia',
|
||||
'journey.settings.tracks': 'GPX Tracks',
|
||||
'journey.settings.showTripTracks': 'Show all trip GPX tracks',
|
||||
'journey.settings.showTripTracksHint': 'Draws the recorded routes from the linked trips on the map.',
|
||||
'journey.settings.endJourney': 'Archive Journey',
|
||||
'journey.settings.reopenJourney': 'Restore Journey',
|
||||
'journey.settings.archived': 'Journey archived',
|
||||
|
||||
@@ -190,6 +190,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Nombre',
|
||||
'journey.settings.subtitle': 'Subtítulo',
|
||||
'journey.settings.subtitlePlaceholder': 'p. ej. Tailandia, Vietnam y Camboya',
|
||||
'journey.settings.tracks': 'Rutas GPX',
|
||||
'journey.settings.showTripTracks': 'Mostrar todas las rutas GPX de los viajes',
|
||||
'journey.settings.showTripTracksHint': 'Dibuja en el mapa las rutas grabadas de los viajes vinculados.',
|
||||
'journey.settings.endJourney': 'Archivar viaje',
|
||||
'journey.settings.reopenJourney': 'Restaurar viaje',
|
||||
'journey.settings.archived': 'Viaje archivado',
|
||||
|
||||
@@ -191,6 +191,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Nom',
|
||||
'journey.settings.subtitle': 'Sous-titre',
|
||||
'journey.settings.subtitlePlaceholder': 'ex. Thaïlande, Vietnam et Cambodge',
|
||||
'journey.settings.tracks': 'Traces GPX',
|
||||
'journey.settings.showTripTracks': 'Afficher toutes les traces GPX des voyages',
|
||||
'journey.settings.showTripTracksHint': 'Trace sur la carte les itinéraires enregistrés des voyages liés.',
|
||||
'journey.settings.endJourney': 'Archiver le journal',
|
||||
'journey.settings.reopenJourney': 'Restaurer le journal',
|
||||
'journey.settings.archived': 'Journal archivé',
|
||||
|
||||
@@ -197,6 +197,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Όνομα',
|
||||
'journey.settings.subtitle': 'Υπότιτλος',
|
||||
'journey.settings.subtitlePlaceholder': 'π.χ. Ταϊλάνδη, Βιετνάμ & Καμπότζη',
|
||||
'journey.settings.tracks': 'Διαδρομές GPX',
|
||||
'journey.settings.showTripTracks': 'Εμφάνιση όλων των διαδρομών GPX των ταξιδιών',
|
||||
'journey.settings.showTripTracksHint': 'Σχεδιάζει στον χάρτη τις καταγεγραμμένες διαδρομές από τα συνδεδεμένα ταξίδια.',
|
||||
'journey.settings.endJourney': 'Αρχειοθέτηση Ταξιδιού',
|
||||
'journey.settings.reopenJourney': 'Επαναφορά Ταξιδιού',
|
||||
'journey.settings.archived': 'Το ταξίδι αρχειοθετήθηκε',
|
||||
|
||||
@@ -190,6 +190,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Név',
|
||||
'journey.settings.subtitle': 'Alcím',
|
||||
'journey.settings.subtitlePlaceholder': 'pl. Thaiföld, Vietnam és Kambodzsa',
|
||||
'journey.settings.tracks': 'GPX-nyomvonalak',
|
||||
'journey.settings.showTripTracks': 'Az utazások összes GPX-nyomvonalának megjelenítése',
|
||||
'journey.settings.showTripTracksHint': 'A kapcsolt utazások rögzített útvonalait rajzolja a térképre.',
|
||||
'journey.settings.endJourney': 'Út archiválása',
|
||||
'journey.settings.reopenJourney': 'Út visszaállítása',
|
||||
'journey.settings.archived': 'Út archiválva',
|
||||
|
||||
@@ -189,6 +189,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Nama',
|
||||
'journey.settings.subtitle': 'Subjudul',
|
||||
'journey.settings.subtitlePlaceholder': 'mis. Thailand, Vietnam & Kamboja',
|
||||
'journey.settings.tracks': 'Jalur GPX',
|
||||
'journey.settings.showTripTracks': 'Tampilkan semua jalur GPX perjalanan',
|
||||
'journey.settings.showTripTracksHint': 'Menggambar rute terekam dari perjalanan yang tertaut pada peta.',
|
||||
'journey.settings.endJourney': 'Arsipkan Perjalanan',
|
||||
'journey.settings.reopenJourney': 'Pulihkan Perjalanan',
|
||||
'journey.settings.archived': 'Perjalanan diarsipkan',
|
||||
|
||||
@@ -190,6 +190,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Nome',
|
||||
'journey.settings.subtitle': 'Sottotitolo',
|
||||
'journey.settings.subtitlePlaceholder': 'es. Thailandia, Vietnam e Cambogia',
|
||||
'journey.settings.tracks': 'Tracce GPX',
|
||||
'journey.settings.showTripTracks': 'Mostra tutte le tracce GPX dei viaggi',
|
||||
'journey.settings.showTripTracksHint': 'Disegna sulla mappa i percorsi registrati dei viaggi collegati.',
|
||||
'journey.settings.endJourney': 'Archivia il viaggio',
|
||||
'journey.settings.reopenJourney': 'Ripristina il viaggio',
|
||||
'journey.settings.archived': 'Viaggio archiviato',
|
||||
|
||||
@@ -192,6 +192,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': '名前',
|
||||
'journey.settings.subtitle': 'サブタイトル',
|
||||
'journey.settings.subtitlePlaceholder': '例:タイ・ベトナム・カンボジア',
|
||||
'journey.settings.tracks': 'GPXトラック',
|
||||
'journey.settings.showTripTracks': '旅行のGPXトラックをすべて表示',
|
||||
'journey.settings.showTripTracksHint': 'リンクされた旅行の記録済みルートを地図に描画します。',
|
||||
'journey.settings.endJourney': '日記をアーカイブ',
|
||||
'journey.settings.reopenJourney': '日記を復元',
|
||||
'journey.settings.archived': '日記をアーカイブしました',
|
||||
|
||||
@@ -191,6 +191,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': '이름',
|
||||
'journey.settings.subtitle': '부제목',
|
||||
'journey.settings.subtitlePlaceholder': '예: 태국, 베트남 & 캄보디아',
|
||||
'journey.settings.tracks': 'GPX 트랙',
|
||||
'journey.settings.showTripTracks': '여행의 모든 GPX 트랙 표시',
|
||||
'journey.settings.showTripTracksHint': '연결된 여행의 기록된 경로를 지도에 그립니다.',
|
||||
'journey.settings.endJourney': 'Journey 보관',
|
||||
'journey.settings.reopenJourney': 'Journey 복원',
|
||||
'journey.settings.archived': 'Journey가 보관되었습니다',
|
||||
|
||||
@@ -191,6 +191,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Naam',
|
||||
'journey.settings.subtitle': 'Ondertitel',
|
||||
'journey.settings.subtitlePlaceholder': 'bijv. Thailand, Vietnam & Cambodja',
|
||||
'journey.settings.tracks': 'GPX-tracks',
|
||||
'journey.settings.showTripTracks': 'Alle GPX-tracks van reizen tonen',
|
||||
'journey.settings.showTripTracksHint': 'Tekent de opgenomen routes van de gekoppelde reizen op de kaart.',
|
||||
'journey.settings.endJourney': 'Reis archiveren',
|
||||
'journey.settings.reopenJourney': 'Reis herstellen',
|
||||
'journey.settings.archived': 'Reis gearchiveerd',
|
||||
|
||||
@@ -190,6 +190,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Nazwa',
|
||||
'journey.settings.subtitle': 'Podtytuł',
|
||||
'journey.settings.subtitlePlaceholder': 'np. Tajlandia, Wietnam i Kambodża',
|
||||
'journey.settings.tracks': 'Ślady GPX',
|
||||
'journey.settings.showTripTracks': 'Pokaż wszystkie ślady GPX z podróży',
|
||||
'journey.settings.showTripTracksHint': 'Rysuje na mapie zapisane trasy z powiązanych podróży.',
|
||||
'journey.settings.endJourney': 'Archiwizuj podróż',
|
||||
'journey.settings.reopenJourney': 'Przywróć podróż',
|
||||
'journey.settings.archived': 'Podróż zarchiwizowana',
|
||||
|
||||
@@ -190,6 +190,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Название',
|
||||
'journey.settings.subtitle': 'Подзаголовок',
|
||||
'journey.settings.subtitlePlaceholder': 'напр. Таиланд, Вьетнам и Камбоджа',
|
||||
'journey.settings.tracks': 'GPX-треки',
|
||||
'journey.settings.showTripTracks': 'Показывать все GPX-треки поездок',
|
||||
'journey.settings.showTripTracksHint': 'Рисует на карте записанные маршруты из связанных поездок.',
|
||||
'journey.settings.endJourney': 'Архивировать путешествие',
|
||||
'journey.settings.reopenJourney': 'Восстановить путешествие',
|
||||
'journey.settings.archived': 'Путешествие архивировано',
|
||||
|
||||
@@ -195,6 +195,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Namn',
|
||||
'journey.settings.subtitle': 'Undertext',
|
||||
'journey.settings.subtitlePlaceholder': 't.ex. Thailand, Vietnam och Kambodja',
|
||||
'journey.settings.tracks': 'GPX-spår',
|
||||
'journey.settings.showTripTracks': 'Visa alla GPX-spår från resor',
|
||||
'journey.settings.showTripTracksHint': 'Ritar de inspelade rutterna från de länkade resorna på kartan.',
|
||||
'journey.settings.endJourney': 'Arkivera Journey',
|
||||
'journey.settings.reopenJourney': 'Återställ Journey',
|
||||
'journey.settings.archived': 'Journey arkiverad',
|
||||
|
||||
@@ -192,6 +192,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'İsim',
|
||||
'journey.settings.subtitle': 'Alt başlık',
|
||||
'journey.settings.subtitlePlaceholder': 'örn. Tayland, Vietnam ve Kamboçya',
|
||||
'journey.settings.tracks': 'GPX İzleri',
|
||||
'journey.settings.showTripTracks': 'Tüm gezi GPX izlerini göster',
|
||||
'journey.settings.showTripTracksHint': 'Bağlı gezilerdeki kayıtlı rotaları haritaya çizer.',
|
||||
'journey.settings.endJourney': "Journey'i Arşivle",
|
||||
'journey.settings.reopenJourney': "Journey'i geri aç",
|
||||
'journey.settings.archived': 'Journey arşivlendi',
|
||||
|
||||
@@ -192,6 +192,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Назва',
|
||||
'journey.settings.subtitle': 'Підзаголовок',
|
||||
'journey.settings.subtitlePlaceholder': 'наприклад Таїланд, В’єтнам і Камбоджа',
|
||||
'journey.settings.tracks': 'GPX-треки',
|
||||
'journey.settings.showTripTracks': 'Показувати всі GPX-треки подорожей',
|
||||
'journey.settings.showTripTracksHint': 'Малює на карті записані маршрути зі зв’язаних подорожей.',
|
||||
'journey.settings.endJourney': 'Архівувати подорож',
|
||||
'journey.settings.reopenJourney': 'Відновити подорож',
|
||||
'journey.settings.archived': 'Подорож архівовано',
|
||||
|
||||
@@ -195,6 +195,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': 'Tên',
|
||||
'journey.settings.subtitle': 'Phụ đề',
|
||||
'journey.settings.subtitlePlaceholder': 'ví dụ. Thái Lan, Việt Nam và Campuchia',
|
||||
'journey.settings.tracks': 'Tuyến GPX',
|
||||
'journey.settings.showTripTracks': 'Hiện tất cả tuyến GPX của chuyến đi',
|
||||
'journey.settings.showTripTracksHint': 'Vẽ lên bản đồ các tuyến đường đã ghi từ những chuyến đi được liên kết.',
|
||||
'journey.settings.endJourney': 'Hành trình lưu trữ',
|
||||
'journey.settings.reopenJourney': 'Khôi phục hành trình',
|
||||
'journey.settings.archived': 'Đã lưu trữ hành trình',
|
||||
|
||||
@@ -188,6 +188,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': '名稱',
|
||||
'journey.settings.subtitle': '副標題',
|
||||
'journey.settings.subtitlePlaceholder': '例如 泰國、越南和柬埔寨',
|
||||
'journey.settings.tracks': 'GPX 軌跡',
|
||||
'journey.settings.showTripTracks': '顯示所有行程的 GPX 軌跡',
|
||||
'journey.settings.showTripTracksHint': '在地圖上繪製關聯行程中的已記錄路線。',
|
||||
'journey.settings.endJourney': '封存旅程',
|
||||
'journey.settings.reopenJourney': '還原旅程',
|
||||
'journey.settings.archived': '旅程已封存',
|
||||
|
||||
@@ -188,6 +188,9 @@ const journey: TranslationStrings = {
|
||||
'journey.settings.name': '名称',
|
||||
'journey.settings.subtitle': '副标题',
|
||||
'journey.settings.subtitlePlaceholder': '例如 泰国、越南和柬埔寨',
|
||||
'journey.settings.tracks': 'GPX 轨迹',
|
||||
'journey.settings.showTripTracks': '显示所有行程的 GPX 轨迹',
|
||||
'journey.settings.showTripTracksHint': '在地图上绘制关联行程中的已记录路线。',
|
||||
'journey.settings.endJourney': '归档旅程',
|
||||
'journey.settings.reopenJourney': '恢复旅程',
|
||||
'journey.settings.archived': '旅程已归档',
|
||||
|
||||
Reference in New Issue
Block a user