mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-10-27 02:27:18 +00:00
create route file action
This commit is contained in:
1 parent
764d0b233a
commit
0f957fb1f2
60 files changed
+211
-85
No files matched your search
@@ -148,21 +148,30 @@ pub fn redo<H: History>(engine: &mut Engine<H>) -> Outcome {
|
|||||||
|
|
||||||
// Files
|
// Files
|
||||||
|
|
||||||
/// Creates a file and selects it. With `lng` and `lat`, it starts with a track and a segment that
|
/// Creates a file and selects it. With `route`, it starts with a route. With `lng` and `lat`, it
|
||||||
/// hold that trackpoint (at `ele`, 0 by default).
|
/// starts with a segment that holds that trackpoint (at `ele`, 0 by default): the one of its route
|
||||||
|
/// with `route`, of a track otherwise.
|
||||||
pub fn new_file<H: History>(
|
pub fn new_file<H: History>(
|
||||||
engine: &mut Engine<H>,
|
engine: &mut Engine<H>,
|
||||||
name: &str,
|
name: &str,
|
||||||
lng: Option<f64>,
|
lng: Option<f64>,
|
||||||
lat: Option<f64>,
|
lat: Option<f64>,
|
||||||
ele: Option<f64>,
|
ele: Option<f64>,
|
||||||
|
route: bool,
|
||||||
) -> Outcome {
|
) -> Outcome {
|
||||||
let trackpoint = lng.zip(lat).map(|(lng, lat)| engine::NewTrackpoint {
|
let trackpoint = lng.zip(lat).map(|(lng, lat)| engine::NewTrackpoint {
|
||||||
lng,
|
lng,
|
||||||
lat,
|
lat,
|
||||||
ele: ele.unwrap_or_default(),
|
ele: ele.unwrap_or_default(),
|
||||||
});
|
});
|
||||||
edit(engine, Command::New(engine::New { name, trackpoint }))
|
edit(
|
||||||
|
engine,
|
||||||
|
Command::New(engine::New {
|
||||||
|
name,
|
||||||
|
trackpoint,
|
||||||
|
route,
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads files as a single command (one undo step). The files are in `data`, one after the other,
|
/// Loads files as a single command (one undo step). The files are in `data`, one after the other,
|
||||||
|
|||||||
@@ -59,12 +59,14 @@ mod tests {
|
|||||||
New {
|
New {
|
||||||
name: "first",
|
name: "first",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
New {
|
New {
|
||||||
name: "second",
|
name: "second",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap(); // now selected
|
.unwrap(); // now selected
|
||||||
@@ -122,6 +124,7 @@ mod tests {
|
|||||||
New {
|
New {
|
||||||
name: "file",
|
name: "file",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ mod tests {
|
|||||||
New {
|
New {
|
||||||
name: "file",
|
name: "file",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ mod tests {
|
|||||||
New {
|
New {
|
||||||
name: "file",
|
name: "file",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -77,6 +78,7 @@ mod tests {
|
|||||||
New {
|
New {
|
||||||
name: "file",
|
name: "file",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ mod tests {
|
|||||||
New {
|
New {
|
||||||
name: "file",
|
name: "file",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ mod tests {
|
|||||||
crate::New {
|
crate::New {
|
||||||
name: "keep",
|
name: "keep",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -280,6 +281,7 @@ mod tests {
|
|||||||
crate::New {
|
crate::New {
|
||||||
name: "keep",
|
name: "keep",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@@ -31,12 +31,14 @@ mod tests {
|
|||||||
crate::New {
|
crate::New {
|
||||||
name: "a",
|
name: "a",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
crate::New {
|
crate::New {
|
||||||
name: "b",
|
name: "b",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@@ -217,6 +217,7 @@ mod tests {
|
|||||||
crate::New {
|
crate::New {
|
||||||
name,
|
name,
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ mod tests {
|
|||||||
crate::New {
|
crate::New {
|
||||||
name: "keep",
|
name: "keep",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -140,6 +141,7 @@ mod tests {
|
|||||||
crate::New {
|
crate::New {
|
||||||
name: "before",
|
name: "before",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -189,6 +191,7 @@ mod tests {
|
|||||||
crate::New {
|
crate::New {
|
||||||
name: "keep",
|
name: "keep",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
use crate::{Apply, CommandError, File, LngLat, State, Track, TrackSegment, Trackpoint, produce};
|
use crate::{
|
||||||
|
Apply, CommandError, File, LngLat, Route, State, Track, TrackSegment, Trackpoint, produce,
|
||||||
|
};
|
||||||
|
|
||||||
/// Creates an empty file and selects it. With a `trackpoint`, the file starts with a track and a
|
/// Creates an empty file and selects it. With `route`, the file starts with a route, which is
|
||||||
/// segment that hold it: it is how the routing tool starts a route on an empty map, in a single
|
/// empty. With a `trackpoint`, the file starts with a segment that holds it, the one of its route
|
||||||
/// undo step.
|
/// with `route` or of a track otherwise: it is how the routing tool starts a route on an empty map,
|
||||||
|
/// in a single undo step.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct New<'a> {
|
pub struct New<'a> {
|
||||||
pub name: &'a str,
|
pub name: &'a str,
|
||||||
pub trackpoint: Option<NewTrackpoint>,
|
pub trackpoint: Option<NewTrackpoint>,
|
||||||
|
pub route: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
@@ -21,8 +25,8 @@ impl Apply for New<'_> {
|
|||||||
produce(state, |_| {
|
produce(state, |_| {
|
||||||
let mut file = File::default();
|
let mut file = File::default();
|
||||||
file.info.name = self.name.to_owned();
|
file.info.name = self.name.to_owned();
|
||||||
|
let mut segment = TrackSegment::default();
|
||||||
if let Some(point) = self.trackpoint {
|
if let Some(point) = self.trackpoint {
|
||||||
let mut segment = TrackSegment::default();
|
|
||||||
// the ends of a segment are anchors of the routing tool
|
// the ends of a segment are anchors of the routing tool
|
||||||
segment.splice(
|
segment.splice(
|
||||||
0,
|
0,
|
||||||
@@ -36,6 +40,13 @@ impl Apply for New<'_> {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
}],
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
if self.route {
|
||||||
|
file.rte.push(Route {
|
||||||
|
seg: segment,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
} else if self.trackpoint.is_some() {
|
||||||
file.trk.push(Track {
|
file.trk.push(Track {
|
||||||
trkseg: vec![segment],
|
trkseg: vec![segment],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -59,7 +70,8 @@ mod tests {
|
|||||||
assert!(
|
assert!(
|
||||||
New {
|
New {
|
||||||
name: "new",
|
name: "new",
|
||||||
trackpoint: None
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.is_ok()
|
.is_ok()
|
||||||
@@ -83,6 +95,7 @@ mod tests {
|
|||||||
New {
|
New {
|
||||||
name: "new",
|
name: "new",
|
||||||
trackpoint: Some(point),
|
trackpoint: Some(point),
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -98,4 +111,38 @@ mod tests {
|
|||||||
assert_eq!(segment[0].anchor, Some(0));
|
assert_eq!(segment[0].anchor, Some(0));
|
||||||
assert_eq!(fx.selected_files(), [file.id].into());
|
assert_eq!(fx.selected_files(), [file.id].into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_new_with_a_route() {
|
||||||
|
let mut fx = Fixture::default();
|
||||||
|
New {
|
||||||
|
name: "new",
|
||||||
|
trackpoint: None,
|
||||||
|
route: true,
|
||||||
|
}
|
||||||
|
.apply(&mut fx.state())
|
||||||
|
.unwrap();
|
||||||
|
let file = fx.files.values().next().unwrap();
|
||||||
|
assert_eq!((file.rte.len(), file.trk.len()), (1, 0));
|
||||||
|
assert!(file.rte[0].seg.is_empty());
|
||||||
|
assert_eq!(fx.selected_files(), [file.id].into());
|
||||||
|
|
||||||
|
// the trackpoint goes to the route
|
||||||
|
let mut fx = Fixture::default();
|
||||||
|
New {
|
||||||
|
name: "new",
|
||||||
|
trackpoint: Some(NewTrackpoint {
|
||||||
|
lng: 1.0,
|
||||||
|
lat: 2.0,
|
||||||
|
ele: 3.0,
|
||||||
|
}),
|
||||||
|
route: true,
|
||||||
|
}
|
||||||
|
.apply(&mut fx.state())
|
||||||
|
.unwrap();
|
||||||
|
let file = fx.files.values().next().unwrap();
|
||||||
|
assert_eq!((file.rte.len(), file.trk.len()), (1, 0));
|
||||||
|
assert_eq!(file.rte[0].seg.len(), 1);
|
||||||
|
assert_eq!(file.rte[0].seg[0].anchor, Some(0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -80,6 +80,7 @@ mod tests {
|
|||||||
New {
|
New {
|
||||||
name,
|
name,
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@@ -119,12 +119,14 @@ mod tests {
|
|||||||
New {
|
New {
|
||||||
name: "a",
|
name: "a",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
New {
|
New {
|
||||||
name: "b",
|
name: "b",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -170,6 +172,7 @@ mod tests {
|
|||||||
New {
|
New {
|
||||||
name: "a",
|
name: "a",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -197,6 +200,7 @@ mod tests {
|
|||||||
New {
|
New {
|
||||||
name,
|
name,
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -235,6 +239,7 @@ mod tests {
|
|||||||
New {
|
New {
|
||||||
name: "a",
|
name: "a",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -251,6 +256,7 @@ mod tests {
|
|||||||
New {
|
New {
|
||||||
name: "a",
|
name: "a",
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state())
|
.apply(&mut fx.state())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ fn new(engine: &mut TestEngine, name: &str) -> bool {
|
|||||||
Command::New(New {
|
Command::New(New {
|
||||||
name,
|
name,
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1489,6 +1490,7 @@ mod per_file_history {
|
|||||||
.execute(Action::Edit(Command::New(New {
|
.execute(Action::Edit(Command::New(New {
|
||||||
name,
|
name,
|
||||||
trackpoint: None,
|
trackpoint: None,
|
||||||
|
route: false,
|
||||||
})))
|
})))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
*engine.order().last().unwrap()
|
*engine.order().last().unwrap()
|
||||||
|
|||||||
@@ -16,10 +16,16 @@ pub fn new_file(
|
|||||||
lng: Option<f64>,
|
lng: Option<f64>,
|
||||||
lat: Option<f64>,
|
lat: Option<f64>,
|
||||||
ele: Option<f64>,
|
ele: Option<f64>,
|
||||||
|
route: Option<bool>,
|
||||||
folder: Option<PathBuf>,
|
folder: Option<PathBuf>,
|
||||||
) -> api::Outcome {
|
) -> api::Outcome {
|
||||||
|
let route = route.unwrap_or_default();
|
||||||
// in `folder` if it is given, otherwise like the selected file, otherwise in the open folder
|
// in `folder` if it is given, otherwise like the selected file, otherwise in the open folder
|
||||||
state.core(move |core| core.creating(folder, true, |e| api::new_file(e, &name, lng, lat, ele)))
|
state.core(move |core| {
|
||||||
|
core.creating(folder, true, |e| {
|
||||||
|
api::new_file(e, &name, lng, lat, ele, route)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The files are in the body, one after the other, the headers `lengths` and `names` (JSON,
|
/// The files are in the body, one after the other, the headers `lengths` and `names` (JSON,
|
||||||
|
|||||||
+1
-1
@@ -483,7 +483,7 @@ fn files_made_from_a_file_of_the_open_folder_are_written_next_to_it_at_once() {
|
|||||||
assert_eq!(opened.added().len(), 1);
|
assert_eq!(opened.added().len(), 1);
|
||||||
let copy = core.creating(None, false, gpx_engine::api::duplicate);
|
let copy = core.creating(None, false, gpx_engine::api::duplicate);
|
||||||
let fresh = core.creating(None, true, |e| {
|
let fresh = core.creating(None, true, |e| {
|
||||||
gpx_engine::api::new_file(e, "fresh", None, None, None)
|
gpx_engine::api::new_file(e, "fresh", None, None, None, false)
|
||||||
});
|
});
|
||||||
// a copy of the file goes next to it, a new file with nothing selected in the selection
|
// a copy of the file goes next to it, a new file with nothing selected in the selection
|
||||||
// of the file that was just made
|
// of the file that was just made
|
||||||
|
|||||||
@@ -1247,7 +1247,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn a_file_that_is_not_on_the_disk_is_unsaved_until_it_is_given_a_place() {
|
fn a_file_that_is_not_on_the_disk_is_unsaved_until_it_is_given_a_place() {
|
||||||
let mut fx = Fixture::new();
|
let mut fx = Fixture::new();
|
||||||
api::new_file(&mut fx.engine, "fresh", None, None, None);
|
api::new_file(&mut fx.engine, "fresh", None, None, None, false);
|
||||||
let id = fx.ids()[0];
|
let id = fx.ids()[0];
|
||||||
assert!(fx.workspace.is_dirty(&fx.engine, id));
|
assert!(fx.workspace.is_dirty(&fx.engine, id));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -1272,9 +1272,9 @@ mod tests {
|
|||||||
fn several_files_without_a_place_go_in_a_folder_with_names_that_are_free() {
|
fn several_files_without_a_place_go_in_a_folder_with_names_that_are_free() {
|
||||||
let mut fx = Fixture::new();
|
let mut fx = Fixture::new();
|
||||||
fx.write("fresh.gpx", "already there");
|
fx.write("fresh.gpx", "already there");
|
||||||
api::new_file(&mut fx.engine, "fresh", None, None, None);
|
api::new_file(&mut fx.engine, "fresh", None, None, None, false);
|
||||||
api::new_file(&mut fx.engine, "a/b: c", None, None, None);
|
api::new_file(&mut fx.engine, "a/b: c", None, None, None, false);
|
||||||
api::new_file(&mut fx.engine, "fresh", None, None, None);
|
api::new_file(&mut fx.engine, "fresh", None, None, None, false);
|
||||||
let ids = fx.ids();
|
let ids = fx.ids();
|
||||||
let folder = fx.folder.clone();
|
let folder = fx.folder.clone();
|
||||||
fx.workspace
|
fx.workspace
|
||||||
@@ -1697,7 +1697,7 @@ mod tests {
|
|||||||
fx.open_folder();
|
fx.open_folder();
|
||||||
let a = fx.ids()[0];
|
let a = fx.ids()[0];
|
||||||
fx.rename(a, "edited");
|
fx.rename(a, "edited");
|
||||||
api::new_file(&mut fx.engine, "fresh", None, None, None);
|
api::new_file(&mut fx.engine, "fresh", None, None, None, false);
|
||||||
let fresh = fx.id_named("fresh");
|
let fresh = fx.id_named("fresh");
|
||||||
fx.workspace.close_files(&mut fx.engine, &[a, fresh], true);
|
fx.workspace.close_files(&mut fx.engine, &[a, fresh], true);
|
||||||
assert!(fx.ids().is_empty());
|
assert!(fx.ids().is_empty());
|
||||||
@@ -1713,7 +1713,7 @@ mod tests {
|
|||||||
let mut fx = Fixture::new();
|
let mut fx = Fixture::new();
|
||||||
fx.write("a.gpx", "a");
|
fx.write("a.gpx", "a");
|
||||||
fx.open_folder();
|
fx.open_folder();
|
||||||
api::new_file(&mut fx.engine, "fresh", None, None, None);
|
api::new_file(&mut fx.engine, "fresh", None, None, None, false);
|
||||||
assert_eq!(fx.ids().len(), 2);
|
assert_eq!(fx.ids().len(), 2);
|
||||||
|
|
||||||
// the new file has nowhere to go: it has to be discarded
|
// the new file has nowhere to go: it has to be discarded
|
||||||
|
|||||||
@@ -10,11 +10,18 @@ use crate::ts::*;
|
|||||||
|
|
||||||
// File commands
|
// File commands
|
||||||
|
|
||||||
/// Creates a file and selects it. With `lng` and `lat`, it starts with a track and a segment that
|
/// Creates a file and selects it. With `route`, it starts with a route. With `lng` and `lat`, it
|
||||||
/// hold that trackpoint (at `ele`, 0 by default).
|
/// starts with a segment that holds that trackpoint (at `ele`, 0 by default): the one of its route
|
||||||
|
/// with `route`, of a track otherwise.
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn new_file(name: &str, lng: Option<f64>, lat: Option<f64>, ele: Option<f64>) -> Outcome {
|
pub fn new_file(
|
||||||
run(|e| api::new_file(e, name, lng, lat, ele))
|
name: &str,
|
||||||
|
lng: Option<f64>,
|
||||||
|
lat: Option<f64>,
|
||||||
|
ele: Option<f64>,
|
||||||
|
route: bool,
|
||||||
|
) -> Outcome {
|
||||||
|
run(|e| api::new_file(e, name, lng, lat, ele, route))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads files as a single command (one undo step). The files are in `data`, one after the
|
/// Loads files as a single command (one undo step). The files are in `data`, one after the
|
||||||
|
|||||||
+17
-7
@@ -84,7 +84,7 @@ fn uuid_bytes(ids: &[String]) -> Vec<u8> {
|
|||||||
fn test_new_file_is_listed_and_selected() {
|
fn test_new_file_is_listed_and_selected() {
|
||||||
start();
|
start();
|
||||||
assert!(run(crate::command::files::new_file(
|
assert!(run(crate::command::files::new_file(
|
||||||
"route", None, None, None
|
"route", None, None, None, false
|
||||||
)));
|
)));
|
||||||
assert_eq!(last_error(), None);
|
assert_eq!(last_error(), None);
|
||||||
|
|
||||||
@@ -198,7 +198,9 @@ fn test_the_reason_of_a_failure_can_be_read() {
|
|||||||
assert!(!run(crate::command::tools::reverse()));
|
assert!(!run(crate::command::tools::reverse()));
|
||||||
assert_eq!(last_error().as_deref(), Some("nothing to do"));
|
assert_eq!(last_error().as_deref(), Some("nothing to do"));
|
||||||
// the next call starts afresh
|
// the next call starts afresh
|
||||||
assert!(run(crate::command::files::new_file("a", None, None, None)));
|
assert!(run(crate::command::files::new_file(
|
||||||
|
"a", None, None, None, false
|
||||||
|
)));
|
||||||
assert_eq!(last_error(), None);
|
assert_eq!(last_error(), None);
|
||||||
|
|
||||||
// invalid data
|
// invalid data
|
||||||
@@ -251,7 +253,9 @@ fn test_the_reason_of_a_failure_can_be_read() {
|
|||||||
assert!(last_error().is_some());
|
assert!(last_error().is_some());
|
||||||
|
|
||||||
// answers are not failures
|
// answers are not failures
|
||||||
assert!(run(crate::command::files::new_file("b", None, None, None)));
|
assert!(run(crate::command::files::new_file(
|
||||||
|
"b", None, None, None, false
|
||||||
|
)));
|
||||||
assert!(!crate::command::files::can_paste());
|
assert!(!crate::command::files::can_paste());
|
||||||
assert_eq!(last_error(), None);
|
assert_eq!(last_error(), None);
|
||||||
}
|
}
|
||||||
@@ -260,7 +264,9 @@ fn test_the_reason_of_a_failure_can_be_read() {
|
|||||||
fn test_undo_and_redo() {
|
fn test_undo_and_redo() {
|
||||||
started_with(&[]);
|
started_with(&[]);
|
||||||
assert!(!can_undo() && !can_redo());
|
assert!(!can_undo() && !can_redo());
|
||||||
assert!(run(crate::command::files::new_file("a", None, None, None)));
|
assert!(run(crate::command::files::new_file(
|
||||||
|
"a", None, None, None, false
|
||||||
|
)));
|
||||||
assert!(can_undo() && !can_redo());
|
assert!(can_undo() && !can_redo());
|
||||||
assert!(run(undo()));
|
assert!(run(undo()));
|
||||||
assert!(order().is_empty());
|
assert!(order().is_empty());
|
||||||
@@ -386,7 +392,7 @@ fn test_move_elements_takes_js_objects() {
|
|||||||
fn test_waypoints() {
|
fn test_waypoints() {
|
||||||
started_with(&[]);
|
started_with(&[]);
|
||||||
assert!(run(crate::command::files::new_file(
|
assert!(run(crate::command::files::new_file(
|
||||||
"file", None, None, None
|
"file", None, None, None, false
|
||||||
)));
|
)));
|
||||||
let file = order().remove(0);
|
let file = order().remove(0);
|
||||||
assert!(run(crate::command::waypoints::new_waypoint(
|
assert!(run(crate::command::waypoints::new_waypoint(
|
||||||
@@ -490,7 +496,9 @@ fn test_editing_tools_change_the_statistics() {
|
|||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn test_last_update_describes_the_last_call_only() {
|
fn test_last_update_describes_the_last_call_only() {
|
||||||
started_with(&[]);
|
started_with(&[]);
|
||||||
assert!(run(crate::command::files::new_file("a", None, None, None)));
|
assert!(run(crate::command::files::new_file(
|
||||||
|
"a", None, None, None, false
|
||||||
|
)));
|
||||||
let update = last_outcome();
|
let update = last_outcome();
|
||||||
assert_eq!(array(get(&update, "added")).length(), 1);
|
assert_eq!(array(get(&update, "added")).length(), 1);
|
||||||
assert_eq!(get(&update, "orderChanged").as_bool(), Some(true));
|
assert_eq!(get(&update, "orderChanged").as_bool(), Some(true));
|
||||||
@@ -502,7 +510,9 @@ fn test_last_update_describes_the_last_call_only() {
|
|||||||
assert_eq!(get(&update, "orderChanged").as_bool(), Some(false));
|
assert_eq!(get(&update, "orderChanged").as_bool(), Some(false));
|
||||||
assert_eq!(get(&update, "selectionChanged").as_bool(), Some(false));
|
assert_eq!(get(&update, "selectionChanged").as_bool(), Some(false));
|
||||||
|
|
||||||
assert!(run(crate::command::files::new_file("b", None, None, None)));
|
assert!(run(crate::command::files::new_file(
|
||||||
|
"b", None, None, None, false
|
||||||
|
)));
|
||||||
assert!(!run(crate::command::tools::crop(3, 1)));
|
assert!(!run(crate::command::tools::crop(3, 1)));
|
||||||
let update = last_outcome();
|
let update = last_outcome();
|
||||||
assert_eq!(array(get(&update, "added")).length(), 0);
|
assert_eq!(array(get(&update, "added")).length(), 0);
|
||||||
|
|||||||
@@ -20,6 +20,12 @@ export function createFile() {
|
|||||||
currentTool.set(Tool.ROUTING);
|
currentTool.set(Tool.ROUTING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Creates a file that starts with an empty route, which the routing tool then draws. */
|
||||||
|
export function createRouteFile() {
|
||||||
|
engine.newFile(newFileName(), undefined, true);
|
||||||
|
currentTool.set(Tool.ROUTING);
|
||||||
|
}
|
||||||
|
|
||||||
/** Asks for the files to open: with the file picker of the system in the desktop app. */
|
/** Asks for the files to open: with the file picker of the system in the desktop app. */
|
||||||
export async function openFiles() {
|
export async function openFiles() {
|
||||||
if (get(engine.workspace)) {
|
if (get(engine.workspace)) {
|
||||||
|
|||||||
@@ -68,6 +68,7 @@
|
|||||||
closeFiles,
|
closeFiles,
|
||||||
closeFolder,
|
closeFolder,
|
||||||
createFile,
|
createFile,
|
||||||
|
createRouteFile,
|
||||||
loadFiles,
|
loadFiles,
|
||||||
openFiles,
|
openFiles,
|
||||||
openFolder,
|
openFolder,
|
||||||
@@ -160,9 +161,13 @@
|
|||||||
<Menubar.Content class="border-none">
|
<Menubar.Content class="border-none">
|
||||||
<Menubar.Item onclick={createFile}>
|
<Menubar.Item onclick={createFile}>
|
||||||
<Plus size="16" />
|
<Plus size="16" />
|
||||||
{i18n._('menu.new')}
|
{i18n._('menu.new_file')}
|
||||||
<Shortcut key="+" ctrl={true} />
|
<Shortcut key="+" ctrl={true} />
|
||||||
</Menubar.Item>
|
</Menubar.Item>
|
||||||
|
<Menubar.Item onclick={createRouteFile}>
|
||||||
|
<Plus size="16" />
|
||||||
|
{i18n._('menu.new_route_file')}
|
||||||
|
</Menubar.Item>
|
||||||
<Menubar.Separator />
|
<Menubar.Separator />
|
||||||
<Menubar.Item onclick={openFiles}>
|
<Menubar.Item onclick={openFiles}>
|
||||||
<FolderOpen size="16" />
|
<FolderOpen size="16" />
|
||||||
|
|||||||
@@ -116,12 +116,16 @@
|
|||||||
/** The folder where what is made from the menu goes: the folder of the row. */
|
/** The folder where what is made from the menu goes: the folder of the row. */
|
||||||
let folder = $derived(kind === 'file' ? undefined : path);
|
let folder = $derived(kind === 'file' ? undefined : path);
|
||||||
|
|
||||||
/** Asks for the name of a file or a folder to make in the folder of the row (see `creating`). */
|
/**
|
||||||
function create(what: 'file' | 'folder') {
|
* Asks for the name of a file or a folder to make in the folder of the row (see `creating`).
|
||||||
|
* With `route`, the file starts with an empty route.
|
||||||
|
*/
|
||||||
|
function create(what: 'file' | 'folder', route = false) {
|
||||||
if (folder === undefined) return;
|
if (folder === undefined) return;
|
||||||
// where what is being named is shown
|
// where what is being named is shown
|
||||||
folders.open(folder);
|
folders.open(folder);
|
||||||
creating.kind = what;
|
creating.kind = what;
|
||||||
|
creating.route = route;
|
||||||
creating.parent = folder;
|
creating.parent = folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,6 +290,10 @@
|
|||||||
<Plus size="16" />
|
<Plus size="16" />
|
||||||
{i18n._('menu.explorer_menu.new_file')}
|
{i18n._('menu.explorer_menu.new_file')}
|
||||||
</ContextMenu.Item>
|
</ContextMenu.Item>
|
||||||
|
<ContextMenu.Item onclick={() => create('file', true)}>
|
||||||
|
<Plus size="16" />
|
||||||
|
{i18n._('menu.explorer_menu.new_route_file')}
|
||||||
|
</ContextMenu.Item>
|
||||||
<ContextMenu.Item onclick={() => create('folder')}>
|
<ContextMenu.Item onclick={() => create('folder')}>
|
||||||
<Plus size="16" />
|
<Plus size="16" />
|
||||||
{i18n._('menu.explorer_menu.new_folder')}
|
{i18n._('menu.explorer_menu.new_folder')}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { CollapsibleTreeNode } from '$lib/components/collapsible-tree/index';
|
import { CollapsibleTreeNode } from '$lib/components/collapsible-tree/index';
|
||||||
import { FileText, Folder } from '@lucide/svelte';
|
import { FileText, Folder, Route } from '@lucide/svelte';
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { get } from 'svelte/store';
|
import { get } from 'svelte/store';
|
||||||
import { toast } from 'svelte-sonner';
|
import { toast } from 'svelte-sonner';
|
||||||
@@ -45,6 +45,7 @@
|
|||||||
async function create(value: string, retry: boolean) {
|
async function create(value: string, retry: boolean) {
|
||||||
const kind = pending;
|
const kind = pending;
|
||||||
const parent = folder;
|
const parent = folder;
|
||||||
|
const route = creating.route;
|
||||||
if (kind === undefined || parent === undefined) return;
|
if (kind === undefined || parent === undefined) return;
|
||||||
const name = value.trim();
|
const name = value.trim();
|
||||||
const taken = entries.some(
|
const taken = entries.some(
|
||||||
@@ -60,7 +61,7 @@
|
|||||||
if (name === '' || taken) return;
|
if (name === '' || taken) return;
|
||||||
let created: string | undefined;
|
let created: string | undefined;
|
||||||
if (kind === 'file') {
|
if (kind === 'file') {
|
||||||
const id = await engine.newFileIn(name, parent);
|
const id = await engine.newFileIn(name, parent, route);
|
||||||
created = id === undefined ? undefined : get(workspace)?.files[id]?.path;
|
created = id === undefined ? undefined : get(workspace)?.files[id]?.path;
|
||||||
if (created !== undefined) {
|
if (created !== undefined) {
|
||||||
currentTool.set(Tool.ROUTING);
|
currentTool.set(Tool.ROUTING);
|
||||||
@@ -94,14 +95,20 @@
|
|||||||
<!-- the name of what is being made, which it is made with -->
|
<!-- the name of what is being made, which it is made with -->
|
||||||
{#snippet named(kind: 'file' | 'folder')}
|
{#snippet named(kind: 'file' | 'folder')}
|
||||||
<div class="flex flex-row items-center h-7 pl-1 pr-1 {kind === 'file' ? 'gap-1.5' : 'gap-1'}">
|
<div class="flex flex-row items-center h-7 pl-1 pr-1 {kind === 'file' ? 'gap-1.5' : 'gap-1'}">
|
||||||
{#if kind === 'file'}
|
{#if kind === 'file' && creating.route}
|
||||||
|
<Route size="16" class="shrink-0" />
|
||||||
|
{:else if kind === 'file'}
|
||||||
<FileText size="16" class="shrink-0" />
|
<FileText size="16" class="shrink-0" />
|
||||||
{:else}
|
{:else}
|
||||||
<Folder size="16" class="shrink-0" />
|
<Folder size="16" class="shrink-0" />
|
||||||
{/if}
|
{/if}
|
||||||
<NameInput
|
<NameInput
|
||||||
placeholder={i18n._(
|
placeholder={i18n._(
|
||||||
kind === 'file' ? 'menu.explorer_menu.new_file' : 'menu.explorer_menu.new_folder'
|
kind === 'folder'
|
||||||
|
? 'menu.explorer_menu.new_folder'
|
||||||
|
: creating.route
|
||||||
|
? 'menu.explorer_menu.new_route_file'
|
||||||
|
: 'menu.explorer_menu.new_file'
|
||||||
)}
|
)}
|
||||||
oncommit={create}
|
oncommit={create}
|
||||||
oncancel={() => (creating.parent = undefined)}
|
oncancel={() => (creating.parent = undefined)}
|
||||||
|
|||||||
@@ -15,12 +15,14 @@ export const renaming: { path: string | undefined } = $state({ path: undefined }
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The file or folder that is being made in a folder (`parent`) of the explorer: it is only made once
|
* The file or folder that is being made in a folder (`parent`) of the explorer: it is only made once
|
||||||
* the user gave it a name.
|
* the user gave it a name. With `route`, the file starts with an empty route.
|
||||||
*/
|
*/
|
||||||
export const creating: { parent: string | undefined; kind: 'file' | 'folder' } = $state({
|
export const creating: { parent: string | undefined; kind: 'file' | 'folder'; route: boolean } =
|
||||||
parent: undefined,
|
$state({
|
||||||
kind: 'file',
|
parent: undefined,
|
||||||
});
|
kind: 'file',
|
||||||
|
route: false,
|
||||||
|
});
|
||||||
|
|
||||||
/** What is dragged in the explorer, and the folder it would be dropped in. */
|
/** What is dragged in the explorer, and the folder it would be dropped in. */
|
||||||
export const dragging: { paths: string[]; target: string | undefined } = $state({
|
export const dragging: { paths: string[]; target: string | undefined } = $state({
|
||||||
|
|||||||
@@ -54,7 +54,8 @@ export async function createTauriBackend(): Promise<Backend> {
|
|||||||
cut: () => invoke('cut'),
|
cut: () => invoke('cut'),
|
||||||
paste: () => invoke('paste'),
|
paste: () => invoke('paste'),
|
||||||
|
|
||||||
new_file: (name, lng, lat, ele) => invoke('new_file', { name, lng, lat, ele }),
|
new_file: (name, lng, lat, ele, route) =>
|
||||||
|
invoke('new_file', { name, lng, lat, ele, route }),
|
||||||
load_files: (files) => {
|
load_files: (files) => {
|
||||||
const data = new Uint8Array(files.reduce((sum, file) => sum + file.data.length, 0));
|
const data = new Uint8Array(files.reduce((sum, file) => sum + file.data.length, 0));
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
@@ -225,7 +226,7 @@ export async function createTauriBackend(): Promise<Backend> {
|
|||||||
invoke<boolean>('export_files', { fileIds, options }),
|
invoke<boolean>('export_files', { fileIds, options }),
|
||||||
listFolder: (path) => invoke<FolderEntry[]>('list_folder', { path }),
|
listFolder: (path) => invoke<FolderEntry[]>('list_folder', { path }),
|
||||||
openUrl: (url) => invoke('open_url', { url }),
|
openUrl: (url) => invoke('open_url', { url }),
|
||||||
newFile: (name, folder) => invoke<Outcome>('new_file', { name, folder }),
|
newFile: (name, folder, route) => invoke<Outcome>('new_file', { name, folder, route }),
|
||||||
createFolder: (parent, name) => invoke<string>('create_folder', { parent, name }),
|
createFolder: (parent, name) => invoke<string>('create_folder', { parent, name }),
|
||||||
renamePath: (path, name) => invoke<Outcome>('rename_path', { path, name }),
|
renamePath: (path, name) => invoke<Outcome>('rename_path', { path, name }),
|
||||||
movePaths: (paths, folder) => invoke('move_paths', { paths, folder }),
|
movePaths: (paths, folder) => invoke('move_paths', { paths, folder }),
|
||||||
|
|||||||
@@ -100,8 +100,11 @@ export interface DesktopFiles {
|
|||||||
listFolder(path?: string): Promise<FolderEntry[]>;
|
listFolder(path?: string): Promise<FolderEntry[]>;
|
||||||
/** Opens a web page (or an email to write) in the app of the system for it. */
|
/** Opens a web page (or an email to write) in the app of the system for it. */
|
||||||
openUrl(url: string): Promise<void>;
|
openUrl(url: string): Promise<void>;
|
||||||
/** Makes a new file, written at once in `folder` (a folder of the open folder), and selects it. */
|
/**
|
||||||
newFile(name: string, folder: string): Promise<Outcome>;
|
* Makes a new file, written at once in `folder` (a folder of the open folder), and selects it.
|
||||||
|
* With `route`, it starts with an empty route.
|
||||||
|
*/
|
||||||
|
newFile(name: string, folder: string, route: boolean): Promise<Outcome>;
|
||||||
/** Makes a folder in a folder of the open folder (numbered if the name is taken): its path. */
|
/** Makes a folder in a folder of the open folder (numbered if the name is taken): its path. */
|
||||||
createFolder(parent: string, name: string): Promise<string>;
|
createFolder(parent: string, name: string): Promise<string>;
|
||||||
/**
|
/**
|
||||||
@@ -165,7 +168,13 @@ export interface Backend {
|
|||||||
paste(): Promise<Outcome>;
|
paste(): Promise<Outcome>;
|
||||||
|
|
||||||
// Files
|
// Files
|
||||||
new_file(name: string, lng?: number, lat?: number, ele?: number): Promise<Outcome>;
|
new_file(
|
||||||
|
name: string,
|
||||||
|
lng: number | undefined,
|
||||||
|
lat: number | undefined,
|
||||||
|
ele: number | undefined,
|
||||||
|
route: boolean
|
||||||
|
): Promise<Outcome>;
|
||||||
load_files(files: { data: Uint8Array; name: string }[]): Promise<Outcome>;
|
load_files(files: { data: Uint8Array; name: string }[]): Promise<Outcome>;
|
||||||
duplicate(): Promise<Outcome>;
|
duplicate(): Promise<Outcome>;
|
||||||
delete(wholeFiles: boolean): Promise<Outcome>;
|
delete(wholeFiles: boolean): Promise<Outcome>;
|
||||||
|
|||||||
@@ -204,6 +204,15 @@ describe('selection', () => {
|
|||||||
assert.equal(fileStates()[0].structure.routes.length, 3);
|
assert.equal(fileStates()[0].structure.routes.length, 3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('creates a file that starts with an empty route', async () => {
|
||||||
|
assert.equal(await engine.newFile('routes', undefined, true), true);
|
||||||
|
const [state] = fileStates();
|
||||||
|
assert.equal(state.structure.routes.length, 1);
|
||||||
|
assert.equal(state.structure.routes[0].segment.length, 0);
|
||||||
|
assert.equal(state.structure.tracks.length, 0);
|
||||||
|
assert.deepEqual(get(engine.selection), { type: 'file', fileIds: [state.structure.id] });
|
||||||
|
});
|
||||||
|
|
||||||
it('ignores what does not exist', async () => {
|
it('ignores what does not exist', async () => {
|
||||||
await load('simple');
|
await load('simple');
|
||||||
const before = get(engine.selection);
|
const before = get(engine.selection);
|
||||||
|
|||||||
@@ -251,11 +251,18 @@ class Engine {
|
|||||||
// Edits of the files
|
// Edits of the files
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a file, which gets selected. With a `trackpoint`, the file starts with a track and a
|
* Creates a file, which gets selected. With `route`, the file starts with a route. With a
|
||||||
* segment that hold it, in the same undo step.
|
* `trackpoint`, the file starts with a segment that holds it, the one of its route with `route`
|
||||||
|
* or of a track otherwise, in the same undo step.
|
||||||
*/
|
*/
|
||||||
newFile(name: string, trackpoint?: { lng: number; lat: number; ele?: number }) {
|
newFile(
|
||||||
return this.run((b) => b.new_file(name, trackpoint?.lng, trackpoint?.lat, trackpoint?.ele));
|
name: string,
|
||||||
|
trackpoint?: { lng: number; lat: number; ele?: number },
|
||||||
|
route: boolean = false
|
||||||
|
) {
|
||||||
|
return this.run((b) =>
|
||||||
|
b.new_file(name, trackpoint?.lng, trackpoint?.lat, trackpoint?.ele, route)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -606,10 +613,10 @@ class Engine {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a new file in a folder of the open folder, which is written there at once and selected.
|
* Makes a new file in a folder of the open folder, which is written there at once and selected.
|
||||||
* Resolves to its id.
|
* With `route`, it starts with an empty route. Resolves to its id.
|
||||||
*/
|
*/
|
||||||
async newFileIn(name: string, folder: string): Promise<string | undefined> {
|
async newFileIn(name: string, folder: string, route = false): Promise<string | undefined> {
|
||||||
const [id] = await this.addedBy((b) => b.desktop!.newFile(name, folder), true);
|
const [id] = await this.addedBy((b) => b.desktop!.newFile(name, folder, route), true);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "View, edit, and create GPX files online with advanced route planning capabilities and file processing tools, beautiful maps and detailed data visualizations."
|
"description": "View, edit, and create GPX files online with advanced route planning capabilities and file processing tools, beautiful maps and detailed data visualizations."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "New",
|
|
||||||
"new_file": "Стварыць новы файл",
|
"new_file": "Стварыць новы файл",
|
||||||
"new_track": "Стварыць маршрут",
|
"new_track": "Стварыць маршрут",
|
||||||
"new_segment": "Стварыць сегмент",
|
"new_segment": "Стварыць сегмент",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Visualitza, edita i crea fitxers GPX en línia amb capacitats avançades de planificació de rutes i eines de processament de fitxers, mapes bonics i visualitzacions de dades detallades."
|
"description": "Visualitza, edita i crea fitxers GPX en línia amb capacitats avançades de planificació de rutes i eines de processament de fitxers, mapes bonics i visualitzacions de dades detallades."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Nou",
|
|
||||||
"new_file": "Nou fitxer",
|
"new_file": "Nou fitxer",
|
||||||
"new_track": "Nou trac",
|
"new_track": "Nou trac",
|
||||||
"new_segment": "Nou segment",
|
"new_segment": "Nou segment",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Zobrazujte, upravujte a vytvářejte GPX soubory online s pokročilými možnostmi plánování tras a nástroji ke zpracování souborů, krásnými mapami a podrobnými vizualizacemi dat."
|
"description": "Zobrazujte, upravujte a vytvářejte GPX soubory online s pokročilými možnostmi plánování tras a nástroji ke zpracování souborů, krásnými mapami a podrobnými vizualizacemi dat."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Nový",
|
|
||||||
"new_file": "Nový soubor",
|
"new_file": "Nový soubor",
|
||||||
"new_track": "Nová trasa",
|
"new_track": "Nová trasa",
|
||||||
"new_segment": "Nový úsek",
|
"new_segment": "Nový úsek",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "View, edit, and create GPX files online with advanced route planning capabilities and file processing tools, beautiful maps and detailed data visualizations."
|
"description": "View, edit, and create GPX files online with advanced route planning capabilities and file processing tools, beautiful maps and detailed data visualizations."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "New",
|
|
||||||
"new_file": "New file",
|
"new_file": "New file",
|
||||||
"new_track": "New track",
|
"new_track": "New track",
|
||||||
"new_segment": "New segment",
|
"new_segment": "New segment",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "GPX-Dateien online anzeigen, bearbeiten und erstellen mit erweiterten Routenplanungs- und Dateiverarbeitungswerkzeugen, schönen Karten und detaillierten Datenvisualisierungen."
|
"description": "GPX-Dateien online anzeigen, bearbeiten und erstellen mit erweiterten Routenplanungs- und Dateiverarbeitungswerkzeugen, schönen Karten und detaillierten Datenvisualisierungen."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Neu",
|
|
||||||
"new_file": "Neue Datei",
|
"new_file": "Neue Datei",
|
||||||
"new_track": "Neue Route",
|
"new_track": "Neue Route",
|
||||||
"new_segment": "Neues Segment",
|
"new_segment": "Neues Segment",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "View, edit, and create GPX files online with advanced route planning capabilities and file processing tools, beautiful maps and detailed data visualizations."
|
"description": "View, edit, and create GPX files online with advanced route planning capabilities and file processing tools, beautiful maps and detailed data visualizations."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "New",
|
|
||||||
"new_file": "New file",
|
"new_file": "New file",
|
||||||
"new_track": "New track",
|
"new_track": "New track",
|
||||||
"new_segment": "New segment",
|
"new_segment": "New segment",
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
"description": "View, edit, and create GPX files online with advanced route planning capabilities and file processing tools, beautiful maps and detailed data visualizations."
|
"description": "View, edit, and create GPX files online with advanced route planning capabilities and file processing tools, beautiful maps and detailed data visualizations."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "New",
|
|
||||||
"new_file": "New file",
|
"new_file": "New file",
|
||||||
|
"new_route_file": "New route file",
|
||||||
"new_track": "New track",
|
"new_track": "New track",
|
||||||
"new_route": "New route",
|
"new_route": "New route",
|
||||||
"convert_to_route": "Convert to route",
|
"convert_to_route": "Convert to route",
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
"explorer_menu": {
|
"explorer_menu": {
|
||||||
"open": "Open",
|
"open": "Open",
|
||||||
"new_file": "New file...",
|
"new_file": "New file...",
|
||||||
|
"new_route_file": "New route file...",
|
||||||
"new_folder": "New folder...",
|
"new_folder": "New folder...",
|
||||||
"rename": "Rename...",
|
"rename": "Rename...",
|
||||||
"reveal_finder": "Reveal in Finder",
|
"reveal_finder": "Reveal in Finder",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Visualiza, edita y crea archivos GPX online con planificación avanzada de rutas y herramientas de procesamiento de archivos, bonitos mapas y visualizaciones detalladas de datos."
|
"description": "Visualiza, edita y crea archivos GPX online con planificación avanzada de rutas y herramientas de procesamiento de archivos, bonitos mapas y visualizaciones detalladas de datos."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Nuevo",
|
|
||||||
"new_file": "Nuevo archivo",
|
"new_file": "Nuevo archivo",
|
||||||
"new_track": "Nuevo recorrido",
|
"new_track": "Nuevo recorrido",
|
||||||
"new_segment": "Nuevo segmento",
|
"new_segment": "Nuevo segmento",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Ikusi, editatu eta sortu GPX fitxategiak bideak bilatzeko aukera aurreratuarekin eta fitxategiak prozesatzeko tresnekin, mapa ederrekin eta datuak ikusteko xehetasun handiarekin."
|
"description": "Ikusi, editatu eta sortu GPX fitxategiak bideak bilatzeko aukera aurreratuarekin eta fitxategiak prozesatzeko tresnekin, mapa ederrekin eta datuak ikusteko xehetasun handiarekin."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Berria",
|
|
||||||
"new_file": "Fitxategi berria",
|
"new_file": "Fitxategi berria",
|
||||||
"new_track": "Arrasto berria",
|
"new_track": "Arrasto berria",
|
||||||
"new_segment": "Segmentu berria",
|
"new_segment": "Segmentu berria",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Katsele, muokkaa ja luo GPX-tiedostoja verkossa edistyneitä reittisuunnittelutyökaluja, näyttäviä karttoja ja yksityiskohtaisia esityksiä hyödyntäen."
|
"description": "Katsele, muokkaa ja luo GPX-tiedostoja verkossa edistyneitä reittisuunnittelutyökaluja, näyttäviä karttoja ja yksityiskohtaisia esityksiä hyödyntäen."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Uusi",
|
|
||||||
"new_file": "Uusi tiedosto",
|
"new_file": "Uusi tiedosto",
|
||||||
"new_track": "Uusi reitti",
|
"new_track": "Uusi reitti",
|
||||||
"new_segment": "Uusi osio",
|
"new_segment": "Uusi osio",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Affichez, éditez et créez des fichiers GPX en ligne avec des outils avancés de planification et de traitement de fichiers, de magnifiques cartes et des visualisations de données détaillées."
|
"description": "Affichez, éditez et créez des fichiers GPX en ligne avec des outils avancés de planification et de traitement de fichiers, de magnifiques cartes et des visualisations de données détaillées."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Nouveau",
|
|
||||||
"new_file": "Nouveau fichier",
|
"new_file": "Nouveau fichier",
|
||||||
"new_track": "Nouvelle piste",
|
"new_track": "Nouvelle piste",
|
||||||
"new_segment": "Nouveau segment",
|
"new_segment": "Nouveau segment",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "View, edit, and create GPX files online with advanced route planning capabilities and file processing tools, beautiful maps and detailed data visualizations."
|
"description": "View, edit, and create GPX files online with advanced route planning capabilities and file processing tools, beautiful maps and detailed data visualizations."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "חדש",
|
|
||||||
"new_file": "קובץ חדש",
|
"new_file": "קובץ חדש",
|
||||||
"new_track": "New track",
|
"new_track": "New track",
|
||||||
"new_segment": "קטע חדש",
|
"new_segment": "קטע חדש",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "GPX fájlok online szerkesztése és létrehozása fejlett útvonal tervezési képességekkel és fájlfeldolgozó eszközökkel, gyönyörű térképekkel és részletekkel."
|
"description": "GPX fájlok online szerkesztése és létrehozása fejlett útvonal tervezési képességekkel és fájlfeldolgozó eszközökkel, gyönyörű térképekkel és részletekkel."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Új.",
|
|
||||||
"new_file": "Új fájl ",
|
"new_file": "Új fájl ",
|
||||||
"new_track": "Új útvonal",
|
"new_track": "Új útvonal",
|
||||||
"new_segment": "Új szakasz",
|
"new_segment": "Új szakasz",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Lihat, edit, dan buat berkas GPX secara online dengan fitur perencanaan rute canggih dan alat pemrosesan berkas, peta yang indah, dan visualisasi data yang detail."
|
"description": "Lihat, edit, dan buat berkas GPX secara online dengan fitur perencanaan rute canggih dan alat pemrosesan berkas, peta yang indah, dan visualisasi data yang detail."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Baru",
|
|
||||||
"new_file": "Berkas baru",
|
"new_file": "Berkas baru",
|
||||||
"new_track": "Trek baru",
|
"new_track": "Trek baru",
|
||||||
"new_segment": "Segmen Baru",
|
"new_segment": "Segmen Baru",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Visualizza, modifica e genera file GPX online con avanzate funzionalità di pianificazione del percorso e strumenti di elaborazione dei file, mappe eleganti e visualizzazione dettagliata dei dati."
|
"description": "Visualizza, modifica e genera file GPX online con avanzate funzionalità di pianificazione del percorso e strumenti di elaborazione dei file, mappe eleganti e visualizzazione dettagliata dei dati."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Nuova",
|
|
||||||
"new_file": "Nuovo file",
|
"new_file": "Nuovo file",
|
||||||
"new_track": "Nuova traccia",
|
"new_track": "Nuova traccia",
|
||||||
"new_segment": "Nuovo segmento",
|
"new_segment": "Nuovo segmento",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "고급 경로 계획과 파일 처리 도구를 이용하여 온라인에서 GPX 파일을 확인하고, 편집하고, 생성하세요. 아름다운 지도와 정밀한 데이터 시각화도 지원합니다."
|
"description": "고급 경로 계획과 파일 처리 도구를 이용하여 온라인에서 GPX 파일을 확인하고, 편집하고, 생성하세요. 아름다운 지도와 정밀한 데이터 시각화도 지원합니다."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "새 파일",
|
|
||||||
"new_file": "새 파일",
|
"new_file": "새 파일",
|
||||||
"new_track": "새 트랙",
|
"new_track": "새 트랙",
|
||||||
"new_segment": "새 세그먼트",
|
"new_segment": "새 세그먼트",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Peržiūrėkite, redaguokite ir kurkite GPX failus internete naudodami išplėstines maršruto planavimo galimybes ir failų apdorojimo įrankius, gražius žemėlapius ir išsamias duomenų vizualizacijas."
|
"description": "Peržiūrėkite, redaguokite ir kurkite GPX failus internete naudodami išplėstines maršruto planavimo galimybes ir failų apdorojimo įrankius, gražius žemėlapius ir išsamias duomenų vizualizacijas."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Naujas",
|
|
||||||
"new_file": "Naujas failas",
|
"new_file": "Naujas failas",
|
||||||
"new_track": "Nauja trasa",
|
"new_track": "Nauja trasa",
|
||||||
"new_segment": "Naujas segmentas",
|
"new_segment": "Naujas segmentas",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "View, edit, and create GPX files online with advanced route planning capabilities and file processing tools, beautiful maps and detailed data visualizations."
|
"description": "View, edit, and create GPX files online with advanced route planning capabilities and file processing tools, beautiful maps and detailed data visualizations."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "New",
|
|
||||||
"new_file": "New file",
|
"new_file": "New file",
|
||||||
"new_track": "New track",
|
"new_track": "New track",
|
||||||
"new_segment": "New segment",
|
"new_segment": "New segment",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Bekijk, bewerk en maak GPX-bestanden met geavanceerde mogelijkheden voor route planning en nabewerkingsmogelijkheden, prachtige kaarten en gedetailleerde visualisaties."
|
"description": "Bekijk, bewerk en maak GPX-bestanden met geavanceerde mogelijkheden voor route planning en nabewerkingsmogelijkheden, prachtige kaarten en gedetailleerde visualisaties."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Nieuw",
|
|
||||||
"new_file": "Nieuw bestand",
|
"new_file": "Nieuw bestand",
|
||||||
"new_track": "Nieuwe route",
|
"new_track": "Nieuwe route",
|
||||||
"new_segment": "Nieuw segment",
|
"new_segment": "Nieuw segment",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Vis, rediger og opprett GPX-filer online med avansert ruteplanlegging og filbehandling, vakre kart og detaljert visualisering."
|
"description": "Vis, rediger og opprett GPX-filer online med avansert ruteplanlegging og filbehandling, vakre kart og detaljert visualisering."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Ny",
|
|
||||||
"new_file": "Ny fil",
|
"new_file": "Ny fil",
|
||||||
"new_track": "Nytt spor",
|
"new_track": "Nytt spor",
|
||||||
"new_segment": "Nytt segment",
|
"new_segment": "Nytt segment",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Przeglądaj, edytuj i twórz pliki GPX online z zaawansowanymi możliwościami planowania trasy i narzędziami do przetwarzania plików, pięknymi mapami i szczegółowymi wizualizacjami danych."
|
"description": "Przeglądaj, edytuj i twórz pliki GPX online z zaawansowanymi możliwościami planowania trasy i narzędziami do przetwarzania plików, pięknymi mapami i szczegółowymi wizualizacjami danych."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Nowy",
|
|
||||||
"new_file": "Nowy plik",
|
"new_file": "Nowy plik",
|
||||||
"new_track": "Nowa ścieżka",
|
"new_track": "Nowa ścieżka",
|
||||||
"new_segment": "Nowy segment",
|
"new_segment": "Nowy segment",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Visualizar, editar e criar arquivos GPX online com capacidade de roteamento avançado e ferramentas de processamento de arquivos, belos mapas e visualização de dados detalhados."
|
"description": "Visualizar, editar e criar arquivos GPX online com capacidade de roteamento avançado e ferramentas de processamento de arquivos, belos mapas e visualização de dados detalhados."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Novo",
|
|
||||||
"new_file": "Novo arquivo",
|
"new_file": "Novo arquivo",
|
||||||
"new_track": "Novo percurso",
|
"new_track": "Novo percurso",
|
||||||
"new_segment": "Novo segmento",
|
"new_segment": "Novo segmento",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Visualizar, editar, e criar arquivos GPX \"online\" com capacidades avançadas de planeamento de rotas"
|
"description": "Visualizar, editar, e criar arquivos GPX \"online\" com capacidades avançadas de planeamento de rotas"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Novo",
|
|
||||||
"new_file": "Novo arquivo",
|
"new_file": "Novo arquivo",
|
||||||
"new_track": "Novo percurso",
|
"new_track": "Novo percurso",
|
||||||
"new_segment": "Novo segmento",
|
"new_segment": "Novo segmento",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Vizualizați, editați și creați fișiere GPX online cu capacități avansate de planificare a rutelor și instrumente de procesare a fișierelor, hărți frumoase și vizualizări de date detaliate."
|
"description": "Vizualizați, editați și creați fișiere GPX online cu capacități avansate de planificare a rutelor și instrumente de procesare a fișierelor, hărți frumoase și vizualizări de date detaliate."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Nou",
|
|
||||||
"new_file": "Fișier nou",
|
"new_file": "Fișier nou",
|
||||||
"new_track": "Traseu nou",
|
"new_track": "Traseu nou",
|
||||||
"new_segment": "Segment nou",
|
"new_segment": "Segment nou",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Просматривайте, редактируйте, создавайте GPX файлы онлайн с расширенными возможностями планирования маршрутов и инструментами обработки файлов, красивыми картами и детальной визуализацией данных."
|
"description": "Просматривайте, редактируйте, создавайте GPX файлы онлайн с расширенными возможностями планирования маршрутов и инструментами обработки файлов, красивыми картами и детальной визуализацией данных."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Новый",
|
|
||||||
"new_file": "Новый файл",
|
"new_file": "Новый файл",
|
||||||
"new_track": "Новый трек",
|
"new_track": "Новый трек",
|
||||||
"new_segment": "Новый сегмент",
|
"new_segment": "Новый сегмент",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Pregledajte, uređujte i kreirajte GPX datoteke uz napredne mogućnosti planiranja ruta i alatima za obradu datoteka, prelepim mapama i detaljnim vizualizacijama podataka."
|
"description": "Pregledajte, uređujte i kreirajte GPX datoteke uz napredne mogućnosti planiranja ruta i alatima za obradu datoteka, prelepim mapama i detaljnim vizualizacijama podataka."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Novo",
|
|
||||||
"new_file": "Nova datoteka",
|
"new_file": "Nova datoteka",
|
||||||
"new_track": "Nova ruta",
|
"new_track": "Nova ruta",
|
||||||
"new_segment": "Novi segment",
|
"new_segment": "Novi segment",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Visa, redigera och skapa GPX-filer online med avancerade ruttplaneringsfunktioner, verktyg för filhantering, tilltalande kartor och detaljerade datavisualiseringar."
|
"description": "Visa, redigera och skapa GPX-filer online med avancerade ruttplaneringsfunktioner, verktyg för filhantering, tilltalande kartor och detaljerade datavisualiseringar."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Nytt",
|
|
||||||
"new_file": "Ny fil",
|
"new_file": "Ny fil",
|
||||||
"new_track": "Nytt spår",
|
"new_track": "Nytt spår",
|
||||||
"new_segment": "Nytt segment",
|
"new_segment": "Nytt segment",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "View, edit, and create GPX files online with advanced route planning capabilities and file processing tools, beautiful maps and detailed data visualizations."
|
"description": "View, edit, and create GPX files online with advanced route planning capabilities and file processing tools, beautiful maps and detailed data visualizations."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "New",
|
|
||||||
"new_file": "New file",
|
"new_file": "New file",
|
||||||
"new_track": "New track",
|
"new_track": "New track",
|
||||||
"new_segment": "New segment",
|
"new_segment": "New segment",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Gelişmiş rota planlama özellikleri ve dosya işleme araçları, harika haritalar ve ayrıntılı veri görselleştirmeleri ile GPX dosyalarını çevrimiçi görüntüleyin, düzenleyin ve oluşturun."
|
"description": "Gelişmiş rota planlama özellikleri ve dosya işleme araçları, harika haritalar ve ayrıntılı veri görselleştirmeleri ile GPX dosyalarını çevrimiçi görüntüleyin, düzenleyin ve oluşturun."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Yeni",
|
|
||||||
"new_file": "Yeni dosya",
|
"new_file": "Yeni dosya",
|
||||||
"new_track": "Yeni yol",
|
"new_track": "Yeni yol",
|
||||||
"new_segment": "Yeni kısım",
|
"new_segment": "Yeni kısım",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Переглядайте, редагуйте та створюйте GPX-файли онлайн за допомогою розширених можливостей планування маршрутів та інструментів обробки файлів, красивих карт і детальної візуалізації даних."
|
"description": "Переглядайте, редагуйте та створюйте GPX-файли онлайн за допомогою розширених можливостей планування маршрутів та інструментів обробки файлів, красивих карт і детальної візуалізації даних."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Новий",
|
|
||||||
"new_file": "Новий файл",
|
"new_file": "Новий файл",
|
||||||
"new_track": "Новий трек",
|
"new_track": "Новий трек",
|
||||||
"new_segment": "Новий сегмент",
|
"new_segment": "Новий сегмент",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "Xem, chỉnh sửa và tạo tệp tin GPX trực tuyến với các tính năng vẽ bản đồ nâng cao cùng với nhiều công cụ trợ giúp, bản đồ đa dạng và dữ liệu trực quan."
|
"description": "Xem, chỉnh sửa và tạo tệp tin GPX trực tuyến với các tính năng vẽ bản đồ nâng cao cùng với nhiều công cụ trợ giúp, bản đồ đa dạng và dữ liệu trực quan."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "Mới",
|
|
||||||
"new_file": "Tạo tệp tin mới",
|
"new_file": "Tạo tệp tin mới",
|
||||||
"new_track": "Tạo tuyến đường mới",
|
"new_track": "Tạo tuyến đường mới",
|
||||||
"new_segment": "Tạo đoạn đường mới",
|
"new_segment": "Tạo đoạn đường mới",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "線上查看、編輯和建立 GPX 檔案,包含高級路線規劃、檔案管理器、精美的地圖和詳細的資料可視化功能。"
|
"description": "線上查看、編輯和建立 GPX 檔案,包含高級路線規劃、檔案管理器、精美的地圖和詳細的資料可視化功能。"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "新建",
|
|
||||||
"new_file": "新增檔案",
|
"new_file": "新增檔案",
|
||||||
"new_track": "新增路徑",
|
"new_track": "新增路徑",
|
||||||
"new_segment": "新增路段",
|
"new_segment": "新增路段",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"description": "在线查看、编辑和创建 GPX 文件,包含高级路线规划、文件管理器、精美的地图和详细的数据可视化功能。"
|
"description": "在线查看、编辑和创建 GPX 文件,包含高级路线规划、文件管理器、精美的地图和详细的数据可视化功能。"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"new": "新建",
|
|
||||||
"new_file": "新建文件",
|
"new_file": "新建文件",
|
||||||
"new_track": "新建轨迹",
|
"new_track": "新建轨迹",
|
||||||
"new_segment": "新建路段",
|
"new_segment": "新建路段",
|
||||||
|
|||||||
Reference in new issue
Block a user