l'avís de drets de còpia per més detalls.",
"noDataLoaded": "No s'han carregat dades. La baixada estarà disponible aviat",
- "pdf": {},
"title": "Descarrega",
"uploadGpx": "Pujar la teva traça a OpenStreetMap"
},
@@ -342,6 +348,13 @@
},
"useSearch": "Utilitzeu la cerca de dalt per veure els valors predefinits",
"useSearchForMore": "Utilitzeu la funció de cerca per cercar dins de {total} valors més…",
+ "visualFeedback": {
+ "directionsRelative": {
+ "left": "esquerra",
+ "right": "dreta"
+ },
+ "fromGps": "{distance} {direction} de la seva ubicació"
+ },
"waitingForGeopermission": "Esperant al vostre permís per a utilitzar la geolocalització…",
"waitingForLocation": "Buscant la vostra ubicació actual…",
"weekdays": {
@@ -620,6 +633,11 @@
"description": "un número",
"feedback": "No és un nombre"
},
+ "id": {
+ "description": "un identificador",
+ "invalidCharacter": "Un identificador només pot contenir lletres, dígits i guions baixos",
+ "shouldBeLonger": "Un identificador ha de tenir almenys 3 caràcters"
+ },
"int": {
"description": "un número sencer"
},
@@ -644,6 +662,10 @@
"description": "un número sencer, positiu",
"noZero": "No es permet el zero"
},
+ "slope": {
+ "inputExplanation": "Poseu el telèfon a terra amb la part superior del telèfon apuntant cap a la part superior del pendent.",
+ "inputIncorrect": "Per a les mesures correctes, assegureu-vos que la fletxa està dins de la zona verda."
+ },
"string": {
"description": "un tros de text"
},
diff --git a/langs/fi.json b/langs/fi.json
index ce7c82368f..5ae0f8515d 100644
--- a/langs/fi.json
+++ b/langs/fi.json
@@ -22,13 +22,18 @@
"delete": "Poista",
"explanations": {
"hardDelete": "Tämä kohde poistetaan OpenStreetMapistä. Kokenut kartoittaja voi palauttaa sen.",
+ "retagNoOtherThemes": "Tämä kohde luokitellaan uudelleen ja piilotetaan tältä sovellukselta",
+ "retagOtherThemes": "Tämän kohteen ominaisuustietoja muutetaan, ja se ilmestyy näkyviin teemoissa {otherThemes}",
"selectReason": "Valitse, miksi tämä kohde pitäisi poistaa",
"softDelete": "Tämä kohde päivitetään ja piilotetaan tässä sovelluksessa. {reason}"
},
"isDeleted": "Tämä kohde on poistettu",
+ "isntAPoint": "Vain pisteitä voi poistaa. Valittu kohde on viiva, alue tai relaatio.",
+ "loading": "Tutkitaan ominaisuuksista, voiko tämän kohteen poistaa.",
"loginToDelete": "Kohteen poistamiseksi täytyy kirjautua",
"notEnoughExperience": "Tämän kohteen loi joku muu.",
"onlyEditedByLoggedInUser": "Tätä kohdetta ei ole muokannut kukaan muu kuin sinä, joten sen voi huoletta poistaa.",
+ "partOfOthers": "Tämä piste on osa viivaa tai relaatiota eikä sitä voi poistaa suoraan.",
"readMessages": "Sinulle on lukemattomia viestejä. Lue ne ennen kuin poistat kohteen – joku on saattanut lähettää palautetta",
"reasons": {
"disused": "Tämä kohde on poistettu käytöstä tai poistettu",
@@ -37,18 +42,23 @@
"test": "Tämä oli testikohde – kohdetta ei ollut ikinä olemassa"
},
"safeDelete": "Tämä kohde voidaan turvallisesti poistaa.",
+ "useSomethingElse": "Poista se toisella OpenStreetMap-editorilla",
"whyDelete": "Miksi tämä kohde pitäisi poistaa?"
},
"favourite": {
+ "loginNeeded": "Kirjaudu sisään
Oma asettelu on saatavilla vain OpenStreetMap-käyttäjille",
+ "panelIntro": "Oma teema
Käytä suosikkitasojasi kaikista virallisista teemoista",
"reload": "Lataa data uudelleen"
},
"favouritePoi": {
"button": {
+ "isFavourite": "Tämä paikka on merkitty suosikiksi ja näkyy kaikilla MapCompleten teemakartoilla, joita katselet.",
"isMarkedShort": "Merkitty suosikkisijainniksi",
"isNotMarkedShort": "Ei merkitty suosikiksi",
"markAsFavouriteTitle": "Merkitse tämä paikka suosikkisijainniksi",
- "markDescription": "Lisää tämä paikka henkilökohtaiselle suosikkilistalle",
- "unmark": "Poista henkilökohtaiselta suosikkilistalta"
+ "markDescription": "Lisää tämä paikka omalle suosikkilistalle",
+ "unmark": "Poista omalta suosikkilistalta",
+ "unmarkNotDeleted": "Tätä pistettä ei poisteta ja se pysyy näkyvissä kartoilla sinulle ja muille"
},
"downloadGeojson": "Lataa suosikkisi geojson-muodossa",
"downloadGpx": "Lataa suosikkisi GPX-muodossa",
@@ -59,39 +69,109 @@
"title": "Suosikkisijaintisi"
},
"flyer": {
+ "aerial": "Tämä kartta käyttää eri taustaa, joka on ilmakuva taholta Agentschap Informatie Vlaanderen",
"callToAction": "Kokeile sitä osoitteessa mapcomplete.org",
+ "cyclofix": "Pyöränpumput, korjausasemat, juomavesi ja pyöräkaupat ovat CycloFixissä",
+ "description": "Vaakasuuntainen A4-lentolehtinen MapCompleten mainostamiseen",
"editing": {
+ "ex": "Alla on yksinkertainen esimerkki siitä, miltä tämä näyttää luonnonsuojelualueella.",
+ "intro": "Käyttäjää tervehtii kartta, jolla on kohteita. Kun kohde valitaan, sen tiedot näytetään.",
"title": "Miltä käyttöliittymä näyttää?"
},
+ "examples": "MapCompletessa on paljon teemakarttoja. Muutamia niistä näkyy tässä.\n\nVerkossa on vielä lisää teemakarttoja aiheista: terveydenhuolto, sisänavigointi, esteettömyydes pyörätuolilla, jätteenkäsittelylaitokset, julkiset kirjahyllyt, sateenkaaren väreissä olevat suojatiet, … Löydä ne kaikki mapcomplete.org-sivustolta",
"fakeui": {
- "add_images": "Lisää kuvia muutamalla napsautuksella"
+ "add_images": "Lisää kuvia muutamalla napsautuksella",
+ "attributes": "Näyttää ominaisuudet ystävällisellä tavalla",
+ "edit": "Väärää tai vanhentunutta tietoa? Muokkauspainike on käden ulottuvilla.",
+ "question": "Jos ominaisuus ei ole vielä tiedossa, MapComplete esittää kysymyksen",
+ "see_images": "Näyttää kuvia aiemmilta tekijöiltä, Wikipediasta, Mapillarystä, …",
+ "wikipedia": "Linkitetyt Wikipedia-artikkelit näytetään"
},
+ "frontParagraph": "MapComplete on helppokäyttöinen verkkosovellus, jolla voi kerätä paikkatietoa OpenStreetMapiin. Sen avulla voi kerätä ja hallita olennaista tietoa avoimella, joukkoistetulla ja uudelleenkäytettävällä tavalla.\n\nUusia luokkia ja ominaisuuksia voi lisätä pyydettäessä.",
+ "lines_too": "Viivat ja monikulmiot näytetään myös. Lisäksi niiden ominaisuuksia ja kuvia voi muokata ja päivittää.",
"mapcomplete": {
+ "customize": "MapCompleten voi räätälöidä tarpeisiisi. Siihen voi lisätä uusia karttatasoja, uutta toiminnallisuutta tai sen voi tyylitellä käyttämään organisaatiosi väerjä ja fontteja.\nMeillä on myös kokemusta paikkatiedon joukkoistamiskampanjoiden aloittamisesta.\nPyydä tarjous ottamalla yhteyttä osoitteeseen pietervdvn@posteo.net.",
+ "intro": "MapComplete on sivusto, jolla on {mapCount} vuorovaikutteista karttaa. Jokaiselle kartalle voi lisätä ja päivittää tietoja. Siinä on paljon ominaisuuksia:",
+ "li0": "Näytä, missä on kiinnostavia paikkoja",
+ "li1": "Lisää uusia pisteitä ja päivitä nykyisten tietoja",
+ "li2": "Lisää yhteystietoja ja aukioloaikoja helposti",
+ "li3": "Voidaan lisätä muille verkkosivuille iFramen muodossa",
+ "li4": "Osa OpenStreetMap-ekosysteemiä, johon kuuluu paljon työkaluja",
+ "li5": "Mahdollisuus tuota olemassa olevia aineistoja",
+ "li6": "Paljon kehittyneitä ominaisuuksia, kuten puiden tunnistus ja kehittyneet syöttömenetelmät",
+ "li7": "Avoimen lähdekoodin ohjelmisto (GPL-lisenssillä) ja ilmainen käyttää",
"title": "Mikä MapComplete on?"
},
+ "onwheels": "Myös sisätilakartat pyörätuolillä liikkuville on käytettävissä.",
+ "osm": "OpenStreetMap on verkkokartta, jota voi muokata ja uudelleenkäyttää kuka tahansa mihin tahansa tarkoitukseen, kunhan lähde nimetään asianmukaisesti sekä data pidetään avoimena.\n\nSe on maailman suurin paikkatietokanta, ja sitä käytetään tuhansissa sovelluksissa ja verkkosivustoissa.",
"tagline": "Kerää paikkatietoa OpenStreetMapillä",
"title": "mapcomplete.org",
+ "toerisme_vlaanderen": "”Pin your point” -hanke tehtiin yhteistyössä Visit Flandersin kanssa. Yli 160 kartoittajaa lisäsi muutama tuhat penkkiä ja piknikpöytää sekä löysi 100 latausasemaa polkupyörille.",
"whatIsOsm": "Mikä OpenStreetMap on?"
},
"general": {
"404": "Tätä sivua ei ole olemassa",
+ "about": "Muokkaa ja lisää tiettyyn teemaan liittyviä tietoja OpenStreetMapiin helposti",
+ "aboutMapComplete": {
+ "intro": "MapCompletea voi käyttää lisäämään tietoja OpenStreetMapiin yhdestä teemasta. Vastaa kysymyksiin, niin muutoksesi ovat käytettävissä kaikkialla minuuttien kuluessa. Useimmissa teemoissa voi lisätä kuvia tai jopa jättää arvostelun. Teeman ylläpitäjä määrittelee teeman kohteet, kysymykset ja kielet."
+ },
"add": {
"addNew": "Lisää {category}",
+ "backToSelect": "Valitse toinen luokka",
+ "confirmButton": "Lisää {category}
Lisäyksesi näkyy kaikille
",
"confirmLocation": "Vahvista tämä sijainti",
"confirmTitle": "Lisätäänkö {title}?",
- "title": "Lisää uusi kohde"
+ "confirmWarning": "Täällä luomasi kohde näkyy kaikille. Ole hyvä ja lisää kartalle vain kohteita, jotka ovat oikeasti olemassa. Monet sovellukset käyttävät tätä tietoa.",
+ "disableFilters": "Poista käytöstä kaikki suodattimet",
+ "disableFiltersExplanation": "Jotkin kohteet saattavat olla piilossa suodattimen takia",
+ "enableLayer": "Ota käyttöön taso {name}",
+ "hasBeenImported": "Tämä kohde on jo tuotu",
+ "import": {
+ "hasBeenImported": "Tämä kohde on tuotu",
+ "howToTest": "Testaa lisäämällä test=true tai backend=osm-test URL-osoitteeseen. Muutoskokoelma tulostetaan konsoliin. Ole hyvä ja avaa pull request, jotta tämä teema voidaan virallistaa ja tuontipainike ottaa käyttöön.",
+ "importTags": "Kohteelle kirjataan {tags}",
+ "officialThemesOnly": "Tuontipainike ei ole käytössä epävirallisille teemoille vahinkojen välttämiseksi",
+ "wrongType": "Tämä kohde ei ole piste eikä viiva eikä sitä voida tuoda",
+ "wrongTypeToConflate": "Tämä kohde ei ole piste eikä viiva eikä sitä voida yhdistää",
+ "zoomInMore": "Lähennä karttaa lisää, jotta tämän kohteen voi tuoda"
+ },
+ "importTags": "Kohteelle kirjataan {tags}",
+ "intro": "Painoit kohtaa, jolle ei ole vielä tietoa.
",
+ "layerNotEnabled": "Taso {layer} ei ole käytössä. Ota taso käyttöön, jotta voit lisätä kohteen",
+ "openLayerControl": "Avaa tason hallintaikkuna",
+ "pleaseLogin": "Kirjaudu sisään, jotta voit lisätä uuden kohteen",
+ "presetInfo": "Uudelle pisteelle kirjataan {tags}",
+ "stillLoading": "Data latautuu vielä. Odota hetki ennen kuin lisäät uuden kohteen.",
+ "title": "Lisää uusi kohde",
+ "warnVisibleForEveryone": "Lisäyksesi näkyy kaikille",
+ "wrongType": "Tämä kohde ei ole piste eikä viiva eikä sitä voida tuoda",
+ "zoomInFurther": "Lähennä karttaa lisää, jotta kohteen voi lisätä.",
+ "zoomInMore": "Lähennä karttaa lisää, jotta voit tuoda tämän kohteen"
+ },
+ "apply_button": {
+ "appliedOnAnotherObject": "Kohteelle {id} kirjataan {tags}",
+ "isApplied": "Muutokset otetaan käyttöön"
},
"attribution": {
+ "attributionBackgroundLayer": "Nykyinen taustataso on {name}",
+ "attributionBackgroundLayerWithCopyright": "Nykyinen taustataso on {name}: {copyright}",
+ "attributionContent": "Kaiken datan tarjoaa OpenStreetMap, vapaasti uudelleenkäytettävissä Open Database Licensen mukaisesti.
",
+ "attributionTitle": "Kiitokset",
"donate": "Tue MapCompletea rahallisesti",
"editId": "Avaa OpenStreetMap-verkkoeditori tänne",
"editJosm": "Muokkaa täällä JOSM:illa",
"followOnMastodon": "Seuraa MapCompletea Mastodonissa",
+ "iconAttribution": {
+ "title": "Käytetyt kuvakkeet"
+ },
"josmOpened": "JOSM on avattu",
"openIssueTracker": "Ilmoita ohjelmavirheestä",
- "openMapillary": "Avaa Mapillary tänne"
+ "openMapillary": "Avaa Mapillary tänne",
+ "title": "Tekijänoikeudet ja alkuperä"
},
"backToIndex": "Palaa kaikkien teemakarttojen yleiskuvaan",
- "backgroundMap": "Taustakartta",
+ "backgroundMap": "Valitse taustataso",
+ "backgroundSwitch": "Vaihda taustaa",
"cancel": "Peruuta",
"download": {
"title": "Lataa"
@@ -112,12 +192,14 @@
"loginWithOpenStreetMap": "Kirjaudu sisään OpenStreetMapilla",
"logout": "Kirjaudu ulos",
"menu": {
- "aboutMapComplete": "Tietoa MapCompletesta"
+ "aboutMapComplete": "Tietoa MapCompletesta",
+ "filter": "Suodata dataa"
},
"morescreen": {
+ "createYourOwnTheme": "Luo oma MapComplete-teema alusta asti",
"noSearch": "Näytä kaikki teemat",
"searchForATheme": "Etsi teemaa",
- "streetcomplete": "Toinen, samanlainen sovellus on StreetComplete."
+ "streetcomplete": "Toinen, samankaltainen sovellus on StreetComplete."
},
"number": "numero",
"openTheMap": "Avaa kartta",
@@ -126,9 +208,12 @@
"loadingCountry": "Määritetään maata…",
"ph_closed": "suljettu",
"ph_not_known": " ",
- "ph_open": "avattu"
+ "ph_open": "auki"
},
- "pickLanguage": "Valitse kieli: ",
+ "pdf": {
+ "attrBackground": "Taustataso: {background}"
+ },
+ "pickLanguage": "Valitse kieli",
"questionBox": {
"answeredMultiple": "Vastasit {answered} kysymykseen",
"answeredOne": "Vastasit yhteen kysymykseen",
@@ -143,6 +228,7 @@
"search": {
"nothing": "Mitään ei löytynyt…",
"search": "Etsi paikkaa",
+ "searchShort": "Etsi…",
"searching": "Etsitään…"
},
"sharescreen": {
@@ -180,13 +266,24 @@
},
"hotkeyDocumentation": {
"action": "Toiminto",
- "key": "Näppäinyhdistelmä"
+ "key": "Näppäinyhdistelmä",
+ "openLayersPanel": "Avaa taustatasojen paneelin",
+ "selectAerial": "Asettaa taustaksi joko ilma- tai satelliittikuvan. Vaihtaa kahden parhaimman, saatavilla olevan tason välillä",
+ "selectMap": "Asettaa taustaksi kartan ulkoisesta lähteestä. Vaihtaa kahden parhaimman, saatavilla olevan tason välillä",
+ "selectMapnik": "Aseta taustatasoksi OpenStreetMap-carto",
+ "selectOsmbasedmap": "Aseta taustatasoksi OpenStreetMap-pohjainen kartta (tai poista käytöstä rasterimuotoinen taustataso)"
},
"image": {
"addPicture": "Lisää kuva",
+ "currentLicense": "Kuvasi julkaistaan lisenssillä {license}",
"doDelete": "Poista kuva",
"dontDelete": "Peruuta",
"isDeleted": "Poistettu",
+ "nearby": {
+ "link": "Tämä kuva näyttää kohteen",
+ "seeNearby": "Selaa ja linkitä läheisiä kuvia",
+ "title": "Läheiset katukuvat"
+ },
"pleaseLogin": "Kirjaudu sisään, jotta voit lisätä kuvan",
"respectPrivacy": "Älä valokuvaa ihmisiä tai rekisterikilpiä. Älä lähetä kuvia Google Mapsistä, Google Streetview’stä tai muista tekijänoikeuden alaisista lähteistä.",
"uploadDone": "Kuvasi on lisätty. Kiitoksia avusta!",
@@ -198,6 +295,15 @@
"pickTheme": "Aloita valitsemalla teema alta.",
"title": "Tervetuloa MapCompleteen"
},
+ "move": {
+ "inviteToMove": {
+ "generic": "Siirrä tätä pistettä"
+ },
+ "whyMove": "Miksi haluat siirtää tätä pistettä?"
+ },
+ "multi_apply": {
+ "autoApply": "Kun ominaisuuksia {attr_names} muutetaan, nämä ominaisuudet muuttuvat automaattisesti myös {count} muussa kohteessa"
+ },
"plantDetection": {
"tryAgain": "Valitse eri laji"
},
diff --git a/langs/layers/ca.json b/langs/layers/ca.json
index 10e1191bb3..f89d20f614 100644
--- a/langs/layers/ca.json
+++ b/langs/layers/ca.json
@@ -284,6 +284,45 @@
"render": "Estació d'Ambulàncies"
}
},
+ "animal_shelter": {
+ "name": "Refugis d'animals",
+ "presets": {
+ "0": {
+ "title": "un refugi d'animals"
+ }
+ },
+ "tagRenderings": {
+ "2": {
+ "question": "Quin nom té aquest refugi d'animals?"
+ },
+ "6": {
+ "mappings": {
+ "0": {
+ "then": "Els animals romanen ací fins que son adoptats per un nou propietari"
+ },
+ "1": {
+ "then": "Els animals reben cures per a la resta de la seva vida"
+ },
+ "2": {
+ "then": "Els animals ferits es rehabiliten aquí fins que puguen ser alliberats de nou a la natura "
+ }
+ },
+ "question": "Quina és la finalitat del refugi d'animals?"
+ },
+ "7": {
+ "question": "Quan està obert aquest refugi d'animals?",
+ "render": "{opening_hours_table()}"
+ }
+ },
+ "title": {
+ "mappings": {
+ "0": {
+ "then": "{name}"
+ }
+ },
+ "render": "Refugi d'animals"
+ }
+ },
"artwork": {
"description": "Un mapa obert d'estàtues, busts, grafitis i altres obres d'art del tot el món",
"name": "Obres d'art",
@@ -1226,7 +1265,7 @@
"Bicycle parking type": {
"mappings": {
"0": {
- "then": "Bastidors de grapes"
+ "then": "Bastidors"
},
"1": {
"then": "Portarodes/bucles"
@@ -1856,6 +1895,216 @@
},
"charging_station": {
"tagRenderings": {
+ "Authentication": {
+ "mappings": {
+ "4": {
+ "then": "L'autenticació mitjançant NFC està disponible"
+ },
+ "5": {
+ "then": "L'autenticació mitjançant targeta de pagament està disponible"
+ },
+ "6": {
+ "then": "L'autenticació mitjançant targeta de debit està disponible"
+ },
+ "7": {
+ "then": "Carregar aquí (també) és possible sense autenticació"
+ }
+ },
+ "question": "Quin tipus d'autenticació hi ha disponible a l'estació de càrrega?"
+ },
+ "Available_charging_stations (generated)": {
+ "mappings": {
+ "0": {
+ "then": "Endoll de paret Schuko sense pin a terra (CEE7/4 tipus F)"
+ },
+ "1": {
+ "then": "Endoll de paret Schuko sense pin a terra (CEE7/4 tipus F)"
+ },
+ "2": {
+ "then": "Endoll de paret Europeu amb pin a terra (CEE7/4 tipus E)"
+ },
+ "3": {
+ "then": "Endoll de paret Europeu amb pin a terra (CEE7/4 tipus E)"
+ },
+ "4": {
+ "then": "CHAdeMo"
+ },
+ "5": {
+ "then": "CHAdeMo"
+ },
+ "6": {
+ "then": "Tipus 1 amb cable"
+ },
+ "7": {
+ "then": "Tipus 1 amb cable"
+ },
+ "8": {
+ "then": "Tipus 1 sense cable"
+ },
+ "9": {
+ "then": "Tipus 1 sense cable(J1772)"
+ },
+ "10": {
+ "then": "CSS Tipus 1 (també conegut com a Tipus 1 Combo)"
+ },
+ "11": {
+ "then": "CSS Tipus 1 (també conegut com a Tipus 1 Combo)"
+ },
+ "12": {
+ "then": "Supercarregador de Tesla"
+ },
+ "13": {
+ "then": "Supercarregador de Tesla"
+ },
+ "14": {
+ "then": "Tipus 2 (mennekes)"
+ },
+ "15": {
+ "then": "Tipus 2 (mennekes)"
+ },
+ "16": {
+ "then": "CSS Tipus 2 (mennekes)"
+ },
+ "17": {
+ "then": "CSS Tipus 2 (mennekes)"
+ }
+ }
+ },
+ "Network": {
+ "question": "Aquesta estació de càrrega forma part d'una xarxa?",
+ "render": "Part de la xarxa {network}"
+ },
+ "OH": {
+ "override": {
+ "question": "Quan està oberta aquesta estació de càrrega?"
+ }
+ },
+ "Operational status": {
+ "mappings": {
+ "0": {
+ "then": "Aquesta estació de càrrega funciona"
+ },
+ "1": {
+ "then": "Aquesta estació de carrega està trencada"
+ },
+ "2": {
+ "then": "Aquí està prevista una estació de recàrrega"
+ },
+ "4": {
+ "then": "Aquesta estació de recàrrega s'ha desactivat permanentment i ja no s'utilitza, però encara és visible"
+ }
+ },
+ "question": "Està en ús aquest punt de càrrega?"
+ },
+ "Operator": {
+ "mappings": {
+ "0": {
+ "then": "De fet, {operator} és la xarxa"
+ }
+ },
+ "question": "Qui és l'operadora d'aquesta estació de càrrega?",
+ "render": "Aquesta estació de càrrega l'opera {operator}"
+ },
+ "Parking:fee": {
+ "mappings": {
+ "0": {
+ "then": "No cal pagar una taxa addicional mentres carrega"
+ },
+ "1": {
+ "then": "Cal pagar una taxa addicional d'aparcament mentres carrega"
+ }
+ },
+ "question": "Cal pagar una taxa d'aparcament mentre es carrega?"
+ },
+ "Type": {
+ "mappings": {
+ "0": {
+ "then": "Aquí es poden carregar bicicletes"
+ },
+ "1": {
+ "then": "Aquí es poden carregar cotxes"
+ },
+ "2": {
+ "then": "Aquí es poden carregar Scooters"
+ },
+ "3": {
+ "then": "Aquí es poden carregar camions o trailers"
+ },
+ "4": {
+ "then": "Aquí es poden carregar autobusos"
+ }
+ },
+ "question": "Quins vehicles tenen permesa la càrrega aquí?"
+ },
+ "access": {
+ "mappings": {
+ "0": {
+ "then": "Qualsevol persona pot utilitzar aquesta estació de recàrrega (pot ser calgui un pagament)"
+ },
+ "1": {
+ "then": "Qualsevol persona pot utilitzar aquesta estació de recàrrega (pot ser calgui un pagament)"
+ },
+ "2": {
+ "then": "Sols clientes del lloc al que pertany aquest punt de càrrega poden utilitzar-lo
p.e. un punt de càrrega d'un hotel que sols poden utilizar-los els hostes"
+ },
+ "3": {
+ "then": "S'ha de sol·licitar una clau per a utilitzar aquest punt de càrrega
p.e un punt de càrrega operat per un hotel nomes utilitzable pel seus hostes, els quals reben una clau des de recepció per a desbloquejar el punt de càrrega"
+ },
+ "4": {
+ "then": "No accessible per al públic general (p.e. només accessible pels propietaris, empleats, ...)"
+ },
+ "5": {
+ "then": "Aquesta estació de càrrega és accessible al públic durant certes hores o condicions. Es poden aplicar restriccions, però es permet l'ús general."
+ }
+ },
+ "question": "Qui pot utilitzar aquesta estació de càrrega?",
+ "render": "L'accés està {access}"
+ },
+ "capacity": {
+ "question": "Quants vehicles poden carregar a la vegada?",
+ "render": "Aquí poden carregar {capacity} vehicles a l'hora"
+ },
+ "charge": {
+ "question": "Quant cal pagar per utilitzar aquesta estació de càrrega?",
+ "render": "Utilitzar aquesta estació de càrrega costa {charge}"
+ },
+ "email": {
+ "question": "Quin és el correu electrònic de l'operadora?",
+ "render": "En cas de problemes, envia un email a {email}"
+ },
+ "fee": {
+ "mappings": {
+ "0": {
+ "then": "Ús gratuït (sense autentificació)"
+ },
+ "1": {
+ "then": "Ús gratuït, però un s'ha d'autentificar"
+ },
+ "2": {
+ "then": "Ús gratuït"
+ },
+ "3": {
+ "then": "De pagament, però gratuït per als clients de l'hotel/bar/hospital/... que gestiona l'estació de càrrega"
+ },
+ "4": {
+ "then": "Ús de pagament"
+ }
+ },
+ "question": "Hi ha que pagar per utilitzar aquest punt de càrrega?"
+ },
+ "maxstay": {
+ "mappings": {
+ "0": {
+ "then": "No hi ha límit de temps per a deixar el teu vehicle aquí"
+ }
+ },
+ "question": "Quina és la quantitat màxima de temps que es permet permaneixer aquí?",
+ "render": "Un pot quedar-se com a màxim {canonical(maxstay)}"
+ },
+ "phone": {
+ "question": "A quin número es pot cridar si hi ha algun problema amb aquest punt de càrrega?",
+ "render": "En cas de problemes, truqueu a {phone}"
+ },
"rewritten-questions": {
"renderings": {
"0": {
@@ -3653,7 +3902,7 @@
"then": "Aquesta és una botiga de kebabs"
},
"4": {
- "then": "Això és un sandvitxeria"
+ "then": "Això és una botiga d'entrepans"
},
"5": {
"then": "Aquí es serveixen hamburgueses"
@@ -3686,13 +3935,13 @@
"then": "Aquí es serveixen plats tailandesos"
}
},
- "question": "Quin menjar es serveix aquí?",
+ "question": "Quin tipus de menjar es serveix aquí?",
"render": "Aquest lloc serveix principalment {cuisine}"
},
"Fastfood vs restaurant": {
"mappings": {
"0": {
- "then": "Aquest és un negoci de menjar ràpid, centrat en el servei ràpid. Si hi han seients disponibles, aquests seràn limitats i funcionals."
+ "then": "Aquest és un negoci de menjar ràpid, centrat en el servei ràpid. Si hi han seients disponibles, aquests seran limitats i funcionals."
},
"1": {
"then": "Un restaurant, centrat en crear una bona experiència on es serveix a taula"
@@ -6665,7 +6914,7 @@
"name": "Botiga",
"presets": {
"0": {
- "description": "Afegir una botiga nova",
+ "description": "Podeu especificar més endavant el que ven aquesta botiga.",
"title": "una botiga"
}
},
@@ -6906,6 +7155,20 @@
}
},
"tagRenderings": {
+ "basketball-hoops": {
+ "mappings": {
+ "1": {
+ "then": "Aquest camp de bàsquet té dos cèrcols"
+ },
+ "2": {
+ "then": "Aquest camp de bàsquet té quatre cèrcols"
+ },
+ "3": {
+ "then": "Aquest camp de bàsquet té {hoops} cèrcols"
+ }
+ },
+ "question": "Quants cèrcols té aquesta pista?"
+ },
"sport-pitch-access": {
"mappings": {
"0": {
@@ -6919,6 +7182,9 @@
},
"3": {
"then": "Privat - no accessible al públic"
+ },
+ "4": {
+ "then": "Accés públic"
}
},
"question": "Aquesta pista d'esports és accessible públicament?"
@@ -6947,6 +7213,9 @@
"mappings": {
"0": {
"then": "Sempre accesible"
+ },
+ "1": {
+ "then": "Sempre accesible"
}
}
},
@@ -6970,6 +7239,9 @@
"4": {
"then": "Aquí es juga al corfbol"
},
+ "5": {
+ "then": "Aquí es juga bàsquet"
+ },
"6": {
"then": "Açò és un skatepark"
}
@@ -6993,6 +7265,12 @@
},
"4": {
"then": "La superfície és formigó"
+ },
+ "5": {
+ "then": "La superfície és grava fina"
+ },
+ "6": {
+ "then": "La superfície d'aquesta pista és Tartan, una superfície sintètica, lleugerament molla i porosa"
}
},
"question": "Quina és la superfície d'aquest camp esportiu?",
@@ -7043,6 +7321,18 @@
},
"question": "Aquestes escales tenen un passamà?"
},
+ "incline": {
+ "mappings": {
+ "0": {
+ "then": "La direcció ascendent és {direction_absolute()}"
+ },
+ "1": {
+ "then": "La direcció descendent és {direction_absolute()}"
+ }
+ },
+ "question": "Quina és la inclinació d'aquestes escales?",
+ "render": "Aquestes escales tenen una inclinació de {incline}"
+ },
"multilevels": {
"override": {
"question": "Entre quines plantes estan aquestes escales?",
@@ -7765,6 +8055,7 @@
}
},
"trail": {
+ "description": "Rutes marcades",
"name": "Camins",
"tagRenderings": {
"Color": {
@@ -7781,6 +8072,19 @@
"3": {
"then": "Ruta groga"
}
+ },
+ "question": "Quin és el color de referència d'aquest sender?",
+ "render": "El color de referència és {colour}"
+ },
+ "Name": {
+ "question": "Quin és el nom d'aquest sender?",
+ "render": "Aquest sender s'anomena {name}"
+ },
+ "Operator tag": {
+ "mappings": {
+ "0": {
+ "then": "Aquest sender és mantingut per Natuurpunt"
+ }
}
},
"trail-length": {
@@ -8110,16 +8414,26 @@
}
}
},
+ "2": {
+ "applicableUnits": {
+ "0": {
+ "human": "{quantity} A"
+ }
+ }
+ },
"3": {
"applicableUnits": {
"0": {
- "human": "{quantity} metre"
+ "human": "{quantity} metre",
+ "humanSingular": "un metre"
},
"1": {
- "human": "{quantity} centimetre"
+ "human": "{quantity} centimetre",
+ "humanSingular": "un centímetre"
},
"2": {
- "human": "{quantity} mil·límetres"
+ "human": "{quantity} mil·límetres",
+ "humanSingular": "un mil·límetre"
},
"3": {
"human": "{quantity} peus"
@@ -8137,12 +8451,37 @@
"humanShort": "{quantity} mph"
}
}
+ },
+ "5": {
+ "applicableUnits": {
+ "0": {
+ "human": "{quantity} minuts",
+ "humanSingular": "un minut"
+ },
+ "1": {
+ "human": "{quantity} hores",
+ "humanSingular": "una hora"
+ },
+ "2": {
+ "human": "{quantity} dies"
+ }
+ }
}
}
},
"usersettings": {
"description": "Una capa especial que no està pensada per mostrar-se en un mapa, però que s'utilitza per configurar la configuració de l'usuari",
"tagRenderings": {
+ "a11y-features": {
+ "mappings": {
+ "0": {
+ "then": "Activar les funcions d'accessibilitat quan s'utilitzen les tecles de fletxa per navegar pel mapa"
+ },
+ "1": {
+ "then": "Sempre habilita les característiques d'accessibilitat"
+ }
+ }
+ },
"all-questions-at-once": {
"mappings": {
"0": {
@@ -8217,7 +8556,7 @@
"1": {
"then": {
"special": {
- "text": "Tens {_unreadMessages}
Open your inbox"
+ "text": "Tens {_unreadMessages} missatges
Obri la safata d'entrada"
}
}
}
@@ -8226,7 +8565,7 @@
"language_picker": {
"mappings": {
"0": {
- "then": "L'idioma es va establir mitjançant un paràmetre d'URL i l'usuari no pot definir-lo.²"
+ "then": "L'idioma es va establir mitjançant un paràmetre d'URL i l'usuari no pot definir-lo."
}
}
},
@@ -8262,6 +8601,9 @@
}
}
},
+ "show_crosshair": {
+ "questionHint": "Això pot ajudar a posicionar amb precisió un nou element"
+ },
"show_debug": {
"mappings": {
"0": {
@@ -8402,22 +8744,37 @@
"question": "Venda de productes carnis"
},
"17": {
- "question": "Venda de flors"
+ "question": "Venda de fruites"
},
"18": {
- "question": "Venda de tiquets d'aparcament"
+ "question": "Venda de maduixes"
},
"19": {
"question": "Venda de flors"
},
"20": {
- "question": "Venda de bitllets de transport públic"
+ "question": "Venda de tiquets d'aparcament"
},
"21": {
"question": "Venda de monedes premsades"
},
"22": {
"question": "Venda de bitllets de transport públic"
+ },
+ "23": {
+ "question": "Venda de llums de bicicletes"
+ },
+ "24": {
+ "question": "Venda de guants"
+ },
+ "25": {
+ "question": "Venda de kits de reparació de bicicletes"
+ },
+ "26": {
+ "question": "Venda de bombes de bicicletes"
+ },
+ "27": {
+ "question": "Venda de cadenat per a bicicletes"
}
}
}
@@ -8506,6 +8863,12 @@
"15": {
"then": "Es venen productes carnis"
},
+ "16": {
+ "then": "Es ven fruita"
+ },
+ "17": {
+ "then": "Es venen maduixes"
+ },
"18": {
"then": "Es venen flors"
},
@@ -8517,6 +8880,21 @@
},
"21": {
"then": "Es venen bitllets de transport públic"
+ },
+ "22": {
+ "then": "Es venen llums per a bicicletes"
+ },
+ "23": {
+ "then": "Es venen guants"
+ },
+ "24": {
+ "then": "Es venen kits de reparació de bicicletes"
+ },
+ "25": {
+ "then": "Es venen bombes de bicicletes"
+ },
+ "26": {
+ "then": "Es venen cadenats per a bicicletes"
}
},
"question": "Que ven aquesta màquina expenedora?",
diff --git a/langs/layers/en.json b/langs/layers/en.json
index 4642248a74..688ca1679b 100644
--- a/langs/layers/en.json
+++ b/langs/layers/en.json
@@ -5042,6 +5042,30 @@
"2": {
"1": "a CNC drill",
"2": "CNC drill"
+ },
+ "3": {
+ "1": "a multimedia studio",
+ "2": "multimedia studio"
+ },
+ "4": {
+ "1": "a sewing machine",
+ "2": "sewing machine"
+ },
+ "5": {
+ "1": "a woodworking workshop",
+ "2": "woodworking workshop"
+ },
+ "6": {
+ "1": "a ceramics workshop",
+ "2": "ceramics workshop"
+ },
+ "7": {
+ "1": "a metal workshop",
+ "2": "metal workshop"
+ },
+ "8": {
+ "1": "a bicycle repair workshop",
+ "2": "bicycle repair workshop"
}
}
}
diff --git a/langs/layers/nl.json b/langs/layers/nl.json
index 2be3d0cfa2..c7045b56b2 100644
--- a/langs/layers/nl.json
+++ b/langs/layers/nl.json
@@ -27,6 +27,9 @@
"advertising": {
"name": "Reclame",
"presets": {
+ "12": {
+ "title": "een muurschildering"
+ },
"3": {
"description": "Een klein uithangbord voor buurtadvertenties, meestal gericht op voetgangers",
"title": "een uithangbord"
@@ -47,9 +50,6 @@
"8": {
"description": "Een stuk groot, weerbestendig textiel met opgedrukte reclameboodschap die permanent aan de muur hangt",
"title": "een spandoek"
- },
- "12": {
- "title": "een muurschildering"
}
},
"tagRenderings": {
@@ -107,6 +107,9 @@
},
"title": {
"mappings": {
+ "10": {
+ "then": "Muurschildering"
+ },
"3": {
"then": "Aanplakzuil"
},
@@ -124,9 +127,6 @@
},
"9": {
"then": "Aanplakzuil"
- },
- "10": {
- "then": "Muurschildering"
}
}
}
@@ -208,6 +208,15 @@
"1": {
"then": "Muurschildering"
},
+ "10": {
+ "then": "Azulejo (Spaanse siertegels)"
+ },
+ "11": {
+ "then": "Tegelwerk"
+ },
+ "12": {
+ "then": "Houtsculptuur"
+ },
"2": {
"then": "Schilderij"
},
@@ -231,15 +240,6 @@
},
"9": {
"then": "Reliëf"
- },
- "10": {
- "then": "Azulejo (Spaanse siertegels)"
- },
- "11": {
- "then": "Tegelwerk"
- },
- "12": {
- "then": "Houtsculptuur"
}
},
"question": "Wat voor soort kunstwerk is dit?",
@@ -1791,6 +1791,27 @@
"1": {
"question": "Heeft een Schuko stekker zonder aardingspin (CEE7/4 type F) 
"
},
+ "10": {
+ "question": "Heeft een Type 2 met kabel (J1772) 
"
+ },
+ "11": {
+ "question": "Heeft een Tesla Supercharger CCS (een type2 CCS met Tesla-logo) 
"
+ },
+ "12": {
+ "question": "Heeft een Tesla Supercharger (destination) 
"
+ },
+ "13": {
+ "question": "Heeft een Tesla supercharger (destination (Een Type 2 met kabel en Tesla-logo) 
"
+ },
+ "14": {
+ "question": "Heeft een USB om GSMs en kleine electronica op te laden 
"
+ },
+ "15": {
+ "question": "Heeft een Bosch Active Connect met 3 pinnen aan een kabel 
"
+ },
+ "16": {
+ "question": "Heeft een Bosch Active Connect met 5 pinnen aan een kabel 
"
+ },
"2": {
"question": "Heeft een Europese stekker met aardingspin (CEE7/4 type E) 
"
},
@@ -1814,27 +1835,6 @@
},
"9": {
"question": "Heeft een Type 2 CCS (mennekes) 
"
- },
- "10": {
- "question": "Heeft een Type 2 met kabel (J1772) 
"
- },
- "11": {
- "question": "Heeft een Tesla Supercharger CCS (een type2 CCS met Tesla-logo) 
"
- },
- "12": {
- "question": "Heeft een Tesla Supercharger (destination) 
"
- },
- "13": {
- "question": "Heeft een Tesla supercharger (destination (Een Type 2 met kabel en Tesla-logo) 
"
- },
- "14": {
- "question": "Heeft een USB om GSMs en kleine electronica op te laden 
"
- },
- "15": {
- "question": "Heeft een Bosch Active Connect met 3 pinnen aan een kabel 
"
- },
- "16": {
- "question": "Heeft een Bosch Active Connect met 5 pinnen aan een kabel 
"
}
}
}
@@ -1890,30 +1890,6 @@
"1": {
"then": "Schuko stekker zonder aardingspin (CEE7/4 type F)"
},
- "2": {
- "then": "Europese stekker met aardingspin (CEE7/4 type E)"
- },
- "3": {
- "then": "Europese stekker met aardingspin (CEE7/4 type E)"
- },
- "4": {
- "then": "Chademo"
- },
- "5": {
- "then": "Chademo"
- },
- "6": {
- "then": "Type 1 met kabel (J1772)"
- },
- "7": {
- "then": "Type 1 met kabel (J1772)"
- },
- "8": {
- "then": "Type 1 zonder kabel (J1772)"
- },
- "9": {
- "then": "Type 1 zonder kabel (J1772)"
- },
"10": {
"then": "Type 1 CCS (ook gekend als Type 1 Combo)"
},
@@ -1944,6 +1920,9 @@
"19": {
"then": "Type 2 met kabel (J1772)"
},
+ "2": {
+ "then": "Europese stekker met aardingspin (CEE7/4 type E)"
+ },
"20": {
"then": "Tesla Supercharger CCS (een type2 CCS met Tesla-logo)"
},
@@ -1974,11 +1953,32 @@
"29": {
"then": "Bosch Active Connect met 3 pinnen aan een kabel"
},
+ "3": {
+ "then": "Europese stekker met aardingspin (CEE7/4 type E)"
+ },
"30": {
"then": "Bosch Active Connect met 5 pinnen aan een kabel"
},
"31": {
"then": "Bosch Active Connect met 5 pinnen aan een kabel"
+ },
+ "4": {
+ "then": "Chademo"
+ },
+ "5": {
+ "then": "Chademo"
+ },
+ "6": {
+ "then": "Type 1 met kabel (J1772)"
+ },
+ "7": {
+ "then": "Type 1 met kabel (J1772)"
+ },
+ "8": {
+ "then": "Type 1 zonder kabel (J1772)"
+ },
+ "9": {
+ "then": "Type 1 zonder kabel (J1772)"
}
},
"question": "Welke aansluitingen zijn hier beschikbaar?"
@@ -2172,6 +2172,24 @@
"1": {
"2": "Europese stekker met aardingspin (CEE7/4 type E)"
},
+ "10": {
+ "2": "Tesla Supercharger CCS (een type2 CCS met Tesla-logo)"
+ },
+ "11": {
+ "2": "Tesla Supercharger (destination)"
+ },
+ "12": {
+ "2": "Tesla supercharger (destination (Een Type 2 met kabel en Tesla-logo)"
+ },
+ "13": {
+ "2": "USB om GSMs en kleine electronica op te laden"
+ },
+ "14": {
+ "2": "Bosch Active Connect met 3 pinnen aan een kabel"
+ },
+ "15": {
+ "2": "Bosch Active Connect met 5 pinnen aan een kabel"
+ },
"2": {
"2": "Chademo"
},
@@ -2195,24 +2213,6 @@
},
"9": {
"2": "Type 2 met kabel (J1772)"
- },
- "10": {
- "2": "Tesla Supercharger CCS (een type2 CCS met Tesla-logo)"
- },
- "11": {
- "2": "Tesla Supercharger (destination)"
- },
- "12": {
- "2": "Tesla supercharger (destination (Een Type 2 met kabel en Tesla-logo)"
- },
- "13": {
- "2": "USB om GSMs en kleine electronica op te laden"
- },
- "14": {
- "2": "Bosch Active Connect met 3 pinnen aan een kabel"
- },
- "15": {
- "2": "Bosch Active Connect met 5 pinnen aan een kabel"
}
}
}
@@ -2978,6 +2978,15 @@
"1": {
"then": "Dit fietspad is geplaveid"
},
+ "10": {
+ "then": "Dit fietspad is gemaakt van fijn grind"
+ },
+ "11": {
+ "then": "Dit fietspad is gemaakt van kiezelsteentjes"
+ },
+ "12": {
+ "then": "Dit fietspad is gemaakt van aarde"
+ },
"2": {
"then": "Dit fietspad is gemaakt van asfalt"
},
@@ -3001,15 +3010,6 @@
},
"9": {
"then": "Dit fietspad is gemaakt van grind"
- },
- "10": {
- "then": "Dit fietspad is gemaakt van fijn grind"
- },
- "11": {
- "then": "Dit fietspad is gemaakt van kiezelsteentjes"
- },
- "12": {
- "then": "Dit fietspad is gemaakt van aarde"
}
},
"question": "Waaruit is het oppervlak van het fietspad van gemaakt?",
@@ -3058,6 +3058,15 @@
"1": {
"then": "Dit fietspad is geplaveid"
},
+ "10": {
+ "then": "Dit fietspad is gemaakt van fijn grind"
+ },
+ "11": {
+ "then": "Dit fietspad is gemaakt van kiezelsteentjes"
+ },
+ "12": {
+ "then": "Dit fietspad is gemaakt van aarde"
+ },
"2": {
"then": "Dit fietspad is gemaakt van asfalt"
},
@@ -3081,15 +3090,6 @@
},
"9": {
"then": "Dit fietspad is gemaakt van grind"
- },
- "10": {
- "then": "Dit fietspad is gemaakt van fijn grind"
- },
- "11": {
- "then": "Dit fietspad is gemaakt van kiezelsteentjes"
- },
- "12": {
- "then": "Dit fietspad is gemaakt van aarde"
}
},
"question": "Waaruit is het oppervlak van de straat gemaakt?",
@@ -4138,6 +4138,21 @@
"1": {
"then": "Dit is een frituur"
},
+ "10": {
+ "then": "Dit is een Chinees restaurant"
+ },
+ "11": {
+ "then": "Dit is een Grieks restaurant"
+ },
+ "12": {
+ "then": "Dit is een Indisch restaurant"
+ },
+ "13": {
+ "then": "Dit is een Turks restaurant (dat meer dan enkel kebab verkoopt)"
+ },
+ "14": {
+ "then": "Dit is een Thaïs restaurant"
+ },
"2": {
"then": "Dit is een pastazaak"
},
@@ -4161,21 +4176,6 @@
},
"9": {
"then": "Dit is een Frans restaurant"
- },
- "10": {
- "then": "Dit is een Chinees restaurant"
- },
- "11": {
- "then": "Dit is een Grieks restaurant"
- },
- "12": {
- "then": "Dit is een Indisch restaurant"
- },
- "13": {
- "then": "Dit is een Turks restaurant (dat meer dan enkel kebab verkoopt)"
- },
- "14": {
- "then": "Dit is een Thaïs restaurant"
}
},
"question": "Welk soort gerechten worden hier geserveerd?",
@@ -4516,6 +4516,30 @@
"2": {
"1": "een CNC-boormachine",
"2": "CNC-boormachine"
+ },
+ "3": {
+ "1": "een multimedia-studio",
+ "2": "multimedia-studio"
+ },
+ "4": {
+ "1": "een naaimachine",
+ "2": "naaimachine"
+ },
+ "5": {
+ "1": "een houtbewerkingsatelier",
+ "2": "houtbewerkingsatelier"
+ },
+ "6": {
+ "1": "een keramiekatelier",
+ "2": "keramiekatelier"
+ },
+ "7": {
+ "1": "een metaalatelier",
+ "2": "metaalatelier"
+ },
+ "8": {
+ "1": "een fietsherstelplaats",
+ "2": "fietsherstelplaats"
}
}
}
@@ -5322,6 +5346,19 @@
}
}
},
+ "10": {
+ "options": {
+ "0": {
+ "question": "Alle Notes"
+ },
+ "1": {
+ "question": "Verberg import Notes"
+ },
+ "2": {
+ "question": "Toon enkel import Notes"
+ }
+ }
+ },
"2": {
"options": {
"0": {
@@ -5377,19 +5414,6 @@
"question": "Toon enkel open Notes"
}
}
- },
- "10": {
- "options": {
- "0": {
- "question": "Alle Notes"
- },
- "1": {
- "question": "Verberg import Notes"
- },
- "2": {
- "question": "Toon enkel import Notes"
- }
- }
}
},
"name": "OpenStreetMap Notes",
@@ -5681,6 +5705,21 @@
"1": {
"then": "Dit is een normale parkeerplek."
},
+ "10": {
+ "then": "Deze parkeerplek is gereserveerd voor ouders met kinderen."
+ },
+ "11": {
+ "then": "Deze parkeerplek is gereserveerd voor personeel."
+ },
+ "12": {
+ "then": "Deze parkeerplek is gereserveerd voor taxis."
+ },
+ "13": {
+ "then": "Deze parkeerplek is gereserveerd voor voertuigen met een aanhanger."
+ },
+ "14": {
+ "then": "Deze parkeerplek is gereserveerd voor autodelen."
+ },
"2": {
"then": "Dit is een gehandicaptenparkeerplaats."
},
@@ -5704,21 +5743,6 @@
},
"9": {
"then": "Deze parkeerplek is gereserveerd voor motoren."
- },
- "10": {
- "then": "Deze parkeerplek is gereserveerd voor ouders met kinderen."
- },
- "11": {
- "then": "Deze parkeerplek is gereserveerd voor personeel."
- },
- "12": {
- "then": "Deze parkeerplek is gereserveerd voor taxis."
- },
- "13": {
- "then": "Deze parkeerplek is gereserveerd voor voertuigen met een aanhanger."
- },
- "14": {
- "then": "Deze parkeerplek is gereserveerd voor autodelen."
}
},
"question": "Wat voor parkeerplek is dit?"
@@ -6285,6 +6309,21 @@
"1": {
"then": "Munten van 2 cent worden geaccepteerd"
},
+ "10": {
+ "then": "Munten van 20 rappen worden geaccepteerd"
+ },
+ "11": {
+ "then": "Munten van ½ frank worden geaccepteerd"
+ },
+ "12": {
+ "then": "Munten van 1 frank worden geaccepteerd"
+ },
+ "13": {
+ "then": "Munten van 2 frank worden geaccepteerd"
+ },
+ "14": {
+ "then": "Munten van 5 frank worden geaccepteerd"
+ },
"2": {
"then": "Munten van 5 cent worden geaccepteerd"
},
@@ -6308,21 +6347,6 @@
},
"9": {
"then": "Munten van 10 rappen worden geaccepteerd"
- },
- "10": {
- "then": "Munten van 20 rappen worden geaccepteerd"
- },
- "11": {
- "then": "Munten van ½ frank worden geaccepteerd"
- },
- "12": {
- "then": "Munten van 1 frank worden geaccepteerd"
- },
- "13": {
- "then": "Munten van 2 frank worden geaccepteerd"
- },
- "14": {
- "then": "Munten van 5 frank worden geaccepteerd"
}
},
"question": "Met welke munten kan je hier betalen?"
@@ -6335,6 +6359,15 @@
"1": {
"then": "Biljetten van 10 euro worden geaccepteerd"
},
+ "10": {
+ "then": "Biljetten van 100 frank worden geaccepteerd"
+ },
+ "11": {
+ "then": "Biljetten van 200 frank worden geaccepteerd"
+ },
+ "12": {
+ "then": "Biljetten van 1000 frank worden geaccepteerd"
+ },
"2": {
"then": "Biljetten van 20 euro worden geaccepteerd"
},
@@ -6358,15 +6391,6 @@
},
"9": {
"then": "Biljetten van 50 frank worden geaccepteerd"
- },
- "10": {
- "then": "Biljetten van 100 frank worden geaccepteerd"
- },
- "11": {
- "then": "Biljetten van 200 frank worden geaccepteerd"
- },
- "12": {
- "then": "Biljetten van 1000 frank worden geaccepteerd"
}
},
"question": "Met welke bankbiljetten kan je hier betalen?"
@@ -6685,30 +6709,6 @@
"1": {
"question": "Recycling van batterijen"
},
- "2": {
- "question": "Recycling van drankpakken"
- },
- "3": {
- "question": "Recycling van blikken"
- },
- "4": {
- "question": "Recycling van kleding"
- },
- "5": {
- "question": "Recycling van frituurvet"
- },
- "6": {
- "question": "Recycling van motorolie"
- },
- "7": {
- "question": "Recycling van tl-buizen"
- },
- "8": {
- "question": "Recycling van groen afval"
- },
- "9": {
- "question": "Recycling van glazen flessen"
- },
"10": {
"question": "Recycling van glas"
},
@@ -6739,11 +6739,35 @@
"19": {
"question": "Recycling van restafval"
},
+ "2": {
+ "question": "Recycling van drankpakken"
+ },
"20": {
"question": "Recycling van inktpatronen"
},
"21": {
"question": "Recycling van fietsen"
+ },
+ "3": {
+ "question": "Recycling van blikken"
+ },
+ "4": {
+ "question": "Recycling van kleding"
+ },
+ "5": {
+ "question": "Recycling van frituurvet"
+ },
+ "6": {
+ "question": "Recycling van motorolie"
+ },
+ "7": {
+ "question": "Recycling van tl-buizen"
+ },
+ "8": {
+ "question": "Recycling van groen afval"
+ },
+ "9": {
+ "question": "Recycling van glazen flessen"
}
}
},
@@ -6811,30 +6835,6 @@
"1": {
"then": "Drankpakken kunnen hier gerecycled worden"
},
- "2": {
- "then": "Blikken kunnen hier gerecycled worden"
- },
- "3": {
- "then": "Kleren kunnen hier gerecycled worden"
- },
- "4": {
- "then": "Frituurvet kan hier gerecycled worden"
- },
- "5": {
- "then": "Motorolie kan hier gerecycled worden"
- },
- "6": {
- "then": "TL-buizen kunnen hier gerecycled worden"
- },
- "7": {
- "then": "Groen afval kan hier gerecycled worden"
- },
- "8": {
- "then": "Organisch afval kan hier gerecycled worden"
- },
- "9": {
- "then": "Glazen flessen kunnen hier gerecycled worden"
- },
"10": {
"then": "Glas kan hier gerecycled worden"
},
@@ -6865,6 +6865,9 @@
"19": {
"then": "Schoenen kunnen hier gerecycled worden"
},
+ "2": {
+ "then": "Blikken kunnen hier gerecycled worden"
+ },
"20": {
"then": "Kleine elektrische apparaten kunnen hier gerecycled worden"
},
@@ -6879,6 +6882,27 @@
},
"24": {
"then": "Fietsen (en fietswrakken) kunnen hier gerecycled worden"
+ },
+ "3": {
+ "then": "Kleren kunnen hier gerecycled worden"
+ },
+ "4": {
+ "then": "Frituurvet kan hier gerecycled worden"
+ },
+ "5": {
+ "then": "Motorolie kan hier gerecycled worden"
+ },
+ "6": {
+ "then": "TL-buizen kunnen hier gerecycled worden"
+ },
+ "7": {
+ "then": "Groen afval kan hier gerecycled worden"
+ },
+ "8": {
+ "then": "Organisch afval kan hier gerecycled worden"
+ },
+ "9": {
+ "then": "Glazen flessen kunnen hier gerecycled worden"
}
},
"question": "Wat kan hier gerecycled worden?"
@@ -7600,6 +7624,12 @@
"1": {
"then": "Deze lantaarn gebruikt LEDs"
},
+ "10": {
+ "then": "Deze lantaarn gebruikt hogedruknatriumlampen (oranje met wit)"
+ },
+ "11": {
+ "then": "Deze lantaarn wordt verlicht met gas"
+ },
"2": {
"then": "Deze lantaarn gebruikt gloeilampen"
},
@@ -7623,12 +7653,6 @@
},
"9": {
"then": "Deze lantaarn gebruikt lagedruknatriumlampen (monochroom oranje)"
- },
- "10": {
- "then": "Deze lantaarn gebruikt hogedruknatriumlampen (oranje met wit)"
- },
- "11": {
- "then": "Deze lantaarn wordt verlicht met gas"
}
},
"question": "Wat voor verlichting gebruikt deze lantaarn?"
@@ -8541,6 +8565,20 @@
"usersettings": {
"description": "Een speciale lag die niet getoond wordt op de kaart, maar die de instellingen van de gebruiker weergeeft",
"tagRenderings": {
+ "a11y-features": {
+ "mappings": {
+ "0": {
+ "then": "Schakel toegankelijkheidsmode aan wanneer op de pijltjestoetsen wordt geduwd om de kaart te bewegen"
+ },
+ "1": {
+ "then": "Schakel de toegankelijkheidsmode altijd aan"
+ },
+ "2": {
+ "then": "Gebruik geen toegankelijkheidsmode"
+ }
+ },
+ "question": "Wanneer moet de toegankelijkheidsmode ingeschakeld worden?"
+ },
"all-questions-at-once": {
"mappings": {
"0": {
@@ -8596,8 +8634,12 @@
"mappings": {
"0": {
"then": "Sta kaartrotatie toe"
+ },
+ "1": {
+ "then": "Hou het noorden altijd naar boven"
}
- }
+ },
+ "question": "Moet het noorden altijd naar boven getoond worden?"
},
"inbox": {
"mappings": {
@@ -8607,12 +8649,29 @@
"text": "Ga naar je inbox"
}
}
+ },
+ "1": {
+ "then": {
+ "special": {
+ "text": "Je hebt {_unreadMessages} ongelezen berichten
Ga naar je inbox"
+ }
+ }
+ }
+ }
+ },
+ "language_picker": {
+ "mappings": {
+ "0": {
+ "then": "De taal werd ingesteld via een URL-parameter en kan niet manueel ingesteld worden."
}
}
},
"mangrove-keys": {
"render": {
- "after": "Iedereen die dit bestand bezit, kan met jouw identiteit wijzigingen maken"
+ "after": "Iedereen die dit bestand bezit, kan met jouw identiteit wijzigingen maken",
+ "special": {
+ "text": "Download de private sleutel van je Mangrove-account"
+ }
}
},
"picture-license": {
@@ -8632,7 +8691,15 @@
},
"question": "Met welke licentie wil je je afbeeldingen toevoegen?"
},
+ "settings-link": {
+ "render": {
+ "special": {
+ "text": "Open je instellingen op OpenStreetMap.org"
+ }
+ }
+ },
"show_crosshair": {
+ "question": "Moet er een kruisje getoond worden in het centrum van je display?",
"questionHint": "Dit kan helpen om nieuwe elementen accuraat te plaatsen"
},
"show_debug": {
@@ -8729,30 +8796,6 @@
"1": {
"question": "Verkoop van dranken"
},
- "2": {
- "question": "Verkoop van snoep"
- },
- "3": {
- "question": "Verkoop van eten"
- },
- "4": {
- "question": "Verkoop van sigaretten"
- },
- "5": {
- "question": "Verkoop van condooms"
- },
- "6": {
- "question": "Verkoop van koffie"
- },
- "7": {
- "question": "Verkoop van water"
- },
- "8": {
- "question": "Verkoop van kranten"
- },
- "9": {
- "question": "Verkoop van fietsbinnenbanden"
- },
"10": {
"question": "Verkoop van melk"
},
@@ -8783,6 +8826,9 @@
"19": {
"question": "Verkoop van bloemen"
},
+ "2": {
+ "question": "Verkoop van snoep"
+ },
"23": {
"question": "Verkoop van fietslampjes"
},
@@ -8797,6 +8843,27 @@
},
"27": {
"question": "Verkoop van fietssloten"
+ },
+ "3": {
+ "question": "Verkoop van eten"
+ },
+ "4": {
+ "question": "Verkoop van sigaretten"
+ },
+ "5": {
+ "question": "Verkoop van condooms"
+ },
+ "6": {
+ "question": "Verkoop van koffie"
+ },
+ "7": {
+ "question": "Verkoop van water"
+ },
+ "8": {
+ "question": "Verkoop van kranten"
+ },
+ "9": {
+ "question": "Verkoop van fietsbinnenbanden"
}
}
}
@@ -8837,30 +8904,6 @@
"1": {
"then": "Snoep wordt verkocht"
},
- "2": {
- "then": "Eten wordt verkocht"
- },
- "3": {
- "then": "Sigaretten worden verkocht"
- },
- "4": {
- "then": "Condooms worden verkocht"
- },
- "5": {
- "then": "Koffie wordt verkocht"
- },
- "6": {
- "then": "Drinkwater wordt verkocht"
- },
- "7": {
- "then": "Kranten worden verkocht"
- },
- "8": {
- "then": "Binnenbanden voor fietsen worden verkocht"
- },
- "9": {
- "then": "Melk wordt verkocht"
- },
"10": {
"then": "Brood wordt verkocht"
},
@@ -8891,6 +8934,9 @@
"19": {
"then": "Parkeerkaarten worden verkocht"
},
+ "2": {
+ "then": "Eten wordt verkocht"
+ },
"21": {
"then": "Openbaar vervoerkaartjes worden verkocht"
},
@@ -8908,6 +8954,27 @@
},
"26": {
"then": "Fietssloten worden verkocht"
+ },
+ "3": {
+ "then": "Sigaretten worden verkocht"
+ },
+ "4": {
+ "then": "Condooms worden verkocht"
+ },
+ "5": {
+ "then": "Koffie wordt verkocht"
+ },
+ "6": {
+ "then": "Drinkwater wordt verkocht"
+ },
+ "7": {
+ "then": "Kranten worden verkocht"
+ },
+ "8": {
+ "then": "Binnenbanden voor fietsen worden verkocht"
+ },
+ "9": {
+ "then": "Melk wordt verkocht"
}
},
"question": "Wat verkoopt deze verkoopautomaat?",
@@ -9200,4 +9267,4 @@
"render": "windturbine"
}
}
-}
\ No newline at end of file
+}
diff --git a/langs/themes/ca.json b/langs/themes/ca.json
index 53f08009d6..933eb133c3 100644
--- a/langs/themes/ca.json
+++ b/langs/themes/ca.json
@@ -464,7 +464,7 @@
"description": "Aquest mapa mostra xarxes de nodes ciclistes i et permet afegir-ne de nous de manera senzilla",
"layers": {
"0": {
- "name": "enllaços node a node",
+ "name": "Enllaços node a node",
"tagRenderings": {
"node2node-survey:date": {
"override": {
@@ -483,12 +483,21 @@
}
},
"1": {
- "name": "nodes",
+ "name": "Nodes",
+ "presets": {
+ "0": {
+ "title": "un node ciclista"
+ }
+ },
"tagRenderings": {
"node-expected_rcn_route_relations": {
"question": "A quants altes nodes ciclistes enllaça aquest node?",
"render": "Aquest node enllaça a {expected_rcn_route_relations} altres nodes ciclistes."
},
+ "node-rxn_ref": {
+ "question": "Quin és el número de referència d'aquest node ciclista?",
+ "render": "Aquest node ciclista té la referència número {rcn_ref}"
+ },
"node-survey:date": {
"override": {
"question": "Quan va ser sondejat aquest node ciclista per última vegada?",
@@ -746,6 +755,18 @@
"layers": {
"0": {
"override": {
+ "filter+": {
+ "0": {
+ "options": {
+ "1": {
+ "question": "Només mostra freiduries que utilitzen oli vegetal"
+ },
+ "2": {
+ "question": "Només mostra freiduries que utilitzen oli animal"
+ }
+ }
+ }
+ },
"name": "Botigues de patates"
}
}
@@ -785,6 +806,9 @@
}
}
},
+ "guideposts": {
+ "title": "Pal guia"
+ },
"hackerspaces": {
"description": "En aquest mapa podeu veure els hackerspaces, afegir un nou hackerspace o actualitzar les dades directament",
"shortDescription": "Un mapa dels hackerspaces",
@@ -820,6 +844,10 @@
"description": "En aquest mapa trobareu hotels a la vostra zona",
"title": "Hotels"
},
+ "icecream": {
+ "description": "Un mapa que mostra les gelateries i les màquines expenedores de gelats",
+ "title": "Gelat"
+ },
"indoors": {
"description": "En aquest mapa es mostren els llocs interiors accessibles al públic",
"title": "Interiors"
@@ -840,6 +868,111 @@
},
"title": "Vorals i encreuaments"
},
+ "mapcomplete-changes": {
+ "description": "Aquest mapa mostra tots els canvis fets amb MapComplete",
+ "layers": {
+ "0": {
+ "description": "Mostra tots els canvis de MapComplete",
+ "filter": {
+ "0": {
+ "options": {
+ "0": {
+ "question": "El nom del tema conté {search}"
+ }
+ }
+ },
+ "2": {
+ "options": {
+ "0": {
+ "question": "Fet pel col·laborador {search}"
+ }
+ }
+ },
+ "3": {
+ "options": {
+ "0": {
+ "question": "No fet pel col·laborador {search}"
+ }
+ }
+ },
+ "4": {
+ "options": {
+ "0": {
+ "question": "Fet abans de {search}"
+ }
+ }
+ },
+ "5": {
+ "options": {
+ "0": {
+ "question": "Fet després de {search}"
+ }
+ }
+ },
+ "6": {
+ "options": {
+ "0": {
+ "question": "Idioma de l'usuari (codi iso) {search}"
+ }
+ }
+ },
+ "7": {
+ "options": {
+ "0": {
+ "question": "Fet amb l'amfitrió {search}"
+ }
+ }
+ },
+ "8": {
+ "options": {
+ "0": {
+ "question": "El conjunt de canvis ha afegit almenys una imatge"
+ }
+ }
+ }
+ },
+ "tagRenderings": {
+ "contributor": {
+ "question": "Quin col·laborador va fer aquest canvi?",
+ "render": "Canvi fet per {user}"
+ },
+ "host": {
+ "question": "Amb quin amfitrió (lloc web) es va fer aquest canvi?",
+ "render": "Canviat amb {host}"
+ },
+ "locale": {
+ "question": "Amb quina configuració regional (idioma) s'ha fet aquest canvi?",
+ "render": "La configuració regional de l'usuari és {locale}"
+ },
+ "show_changeset_id": {
+ "render": "Conjunt de canvi {id}"
+ },
+ "theme-id": {
+ "question": "Quin tema es va utilitzar per fer aquest canvi?",
+ "render": "Canvi amb el tema {theme}"
+ },
+ "version": {
+ "question": "Quina versió de MapComplete es va utilitzar per fer aquest canvi?",
+ "render": "Fet amb {editor}"
+ }
+ },
+ "title": {
+ "render": "Conjunt de canvis per a {theme}"
+ }
+ },
+ "1": {
+ "override": {
+ "tagRenderings+": {
+ "0": {
+ "render": "Es pot trobar més estadística aquí"
+ }
+ }
+ }
+ }
+ },
+ "shortDescription": "Mostra els canvis fets amb MapComplete",
+ "title": "Canvis fets amb MapComplete"
+ },
"maproulette": {
"description": "Tema que mostra les tasques de MapRoulette, que us permet cercar-les, filtrar-les i solucionar-les.",
"title": "Tasques de MapRoulette"
diff --git a/package-lock.json b/package-lock.json
index 853d7611f3..92b0f86d27 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "mapcomplete",
- "version": "0.36.11",
+ "version": "0.36.12",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "mapcomplete",
- "version": "0.36.11",
+ "version": "0.36.12",
"license": "GPL-3.0-or-later",
"dependencies": {
"@rgossiaux/svelte-headlessui": "^1.0.2",
@@ -83,6 +83,7 @@
"@types/xml2js": "^0.4.9",
"@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^6.1.0",
+ "@vitejs/plugin-basic-ssl": "^1.0.2",
"assert": "^2.0.0",
"chai": "^4.3.6",
"dependency-cruiser": "^10.4.0",
@@ -4608,6 +4609,18 @@
"resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
"integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q=="
},
+ "node_modules/@vitejs/plugin-basic-ssl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.0.2.tgz",
+ "integrity": "sha512-DKHKVtpI+eA5fvObVgQ3QtTGU70CcCnedalzqmGSR050AzKZMdUzgC8KmlOneHWH8dF2hJ3wkC9+8FDVAaDRCw==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.6.0"
+ },
+ "peerDependencies": {
+ "vite": "^3.0.0 || ^4.0.0 || ^5.0.0"
+ }
+ },
"node_modules/@vitest/expect": {
"version": "0.28.3",
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.28.3.tgz",
@@ -17096,6 +17109,13 @@
"resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
"integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q=="
},
+ "@vitejs/plugin-basic-ssl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.0.2.tgz",
+ "integrity": "sha512-DKHKVtpI+eA5fvObVgQ3QtTGU70CcCnedalzqmGSR050AzKZMdUzgC8KmlOneHWH8dF2hJ3wkC9+8FDVAaDRCw==",
+ "dev": true,
+ "requires": {}
+ },
"@vitest/expect": {
"version": "0.28.3",
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.28.3.tgz",
diff --git a/package.json b/package.json
index c50c85c3a3..71f0b38be0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "mapcomplete",
- "version": "0.36.11",
+ "version": "0.36.12",
"repository": "https://github.com/pietervdvn/MapComplete",
"description": "A small website to edit OSM easily",
"bugs": "https://github.com/pietervdvn/MapComplete/issues",
@@ -16,11 +16,18 @@
"Alternatively, you can override the `osm` credentials using the environment variables `VITE_OSM_OAUTH_CLIENT_ID` and `VITE_OSM_OAUTH_SECRET`"
],
"oauth_credentials": {
- "#": "This client-id is registered by 'MapComplete' on osm.org",
+ "#": "This client-id is registered by 'MapComplete' on OpenStreetMap.org",
"oauth_client_id": "K93H1d8ve7p-tVLE1ZwsQ4lAFLQk8INx5vfTLMu5DWk",
"oauth_secret": "NBWGhWDrD3QDB35xtVuxv4aExnmIt4FA_WgeLtwxasg",
"url": "https://www.openstreetmap.org"
},
+ "disabled:oauth_credentials": {
+ "##": "DEV",
+ "#": "This client-id is registered by 'MapComplete' on https://master.apis.dev.openstreetmap.org/",
+ "oauth_client_id": "BAPPMRuojjFsY__0APmScr1hbebYj1GlDbV6S5TsUbo",
+ "oauth_secret": "Lq1UKYAySRfQfwgFctGvlGrfxbGHQwggheE52HIGrO8",
+ "url": "https://master.apis.dev.openstreetmap.org"
+ },
"api_keys": {
"#": "Various API-keys for various services. Feel free to reuse those in another MapComplete-hosted version",
"imgur": "7070e7167f0a25a",
@@ -36,8 +43,9 @@
},
"scripts": {
"start": "npm run generate:layeroverview && npm run strt",
+ "#strt:https": "Start in HTTPS mode. Makes a few things a bit harder, but allows to debug on Android with logging in",
+ "strt:https": "vite --host | sed 's/localhost:/127.0.0.1:/g'",
"strt": "vite --host | sed 's/localhost:/127.0.0.1:/g'",
- "strttest": "export NODE_OPTIONS=--max_old_space_size=8364 && parcel serve test.html assets/templates/*.svg assets/templates/fonts/*.ttf",
"watch:css": "tailwindcss -i src/index.css -o public/css/index-tailwind-output.css --watch",
"generate:css": "tailwindcss -i src/index.css -o public/css/index-tailwind-output.css",
"generate:doctests": "doctest-ts-improved . --ignore .*.spec.ts --ignore .*ConfigJson.ts",
@@ -72,9 +80,10 @@
"generate:charging-stations": "cd ./assets/layers/charging_station && vite-node csvToJson.ts && cd -",
"prepare-deploy": "npm run generate:service-worker && ./scripts/prepare-build.sh && npm run build",
"build": "./scripts/build.sh",
- "lint": "npm run lint:prettier && npm run lint:eslint",
+ "lint": "npm run lint:prettier && npm run lint:eslint && npm run lint:themes",
"lint:eslint": "eslint ./src",
"lint:prettier": "prettier --check '**/*.ts' '**/*.svelte'",
+ "lint:themes": "vite-node scripts/lint.ts",
"format": "prettier --write '**/*.ts' '**/*.svelte'",
"clean:tests": "find . -type f -name \"*.doctest.ts\" | xargs -r rm",
"clean": "rm -rf .cache/ && (find *.html | grep -v \"^\\(404\\|index\\|land\\|privacy\\|test\\|studio\\|theme\\|style_test\\|statistics\\|leaderboard\\).html\" | xargs -r rm) && (ls | grep \"^index_[a-zA-Z_-]\\+\\.ts$\" | xargs -r rm)",
@@ -172,6 +181,7 @@
"@types/xml2js": "^0.4.9",
"@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^6.1.0",
+ "@vitejs/plugin-basic-ssl": "^1.0.2",
"assert": "^2.0.0",
"chai": "^4.3.6",
"dependency-cruiser": "^10.4.0",
diff --git a/public/css/index-tailwind-output.css b/public/css/index-tailwind-output.css
index 96988f98f9..4848be7249 100644
--- a/public/css/index-tailwind-output.css
+++ b/public/css/index-tailwind-output.css
@@ -777,6 +777,10 @@ video {
float: left;
}
+.m-8 {
+ margin: 2rem;
+}
+
.m-4 {
margin: 1rem;
}
@@ -789,10 +793,6 @@ video {
margin: 0px;
}
-.m-8 {
- margin: 2rem;
-}
-
.m-2 {
margin: 0.5rem;
}
@@ -1059,6 +1059,10 @@ video {
display: contents;
}
+.\!contents {
+ display: contents !important;
+}
+
.list-item {
display: list-item;
}
@@ -1106,6 +1110,10 @@ video {
height: fit-content;
}
+.h-16 {
+ height: 4rem;
+}
+
.h-0 {
height: 0px;
}
@@ -1134,10 +1142,6 @@ video {
height: 1.25rem;
}
-.h-16 {
- height: 4rem;
-}
-
.h-48 {
height: 12rem;
}
@@ -1202,6 +1206,10 @@ video {
width: 1.5rem;
}
+.w-16 {
+ width: 4rem;
+}
+
.w-screen {
width: 100vw;
}
@@ -1236,14 +1244,14 @@ video {
width: 2.75rem;
}
-.w-16 {
- width: 4rem;
-}
-
.w-64 {
width: 16rem;
}
+.w-1\/2 {
+ width: 50%;
+}
+
.w-auto {
width: auto;
}
@@ -2249,6 +2257,9 @@ video {
--catch-detail-foregroundcolor: white;
--catch-detail-color-contrast: #fb3afb;
--image-carousel-height: 350px;
+ /** Technical value, used by icon.svelte
+ */
+ --svg-color: #000000;
}
/***********************************************************************\
@@ -2794,6 +2805,10 @@ a.link-underline {
overflow: visible !important;
}
+svg.apply-fill path {
+ fill: var(--svg-color)
+}
+
.compass_arrow {
width: calc( 2.5rem - 1px ) ;
height: calc( 2.5rem - 1px )
diff --git a/public/css/tagrendering.css b/public/css/tagrendering.css
index 4c63a909b2..ce1d6c3b88 100644
--- a/public/css/tagrendering.css
+++ b/public/css/tagrendering.css
@@ -66,7 +66,7 @@
width: 3rem;
max-height: 3rem;
margin-right: 1rem;
- margin-left: 1rem;
+ margin-left: 0.5rem;
}
.mapping-icon-large {
@@ -76,7 +76,7 @@
margin-top: 0.5rem;
margin-bottom: 0.5rem;
margin-right: 1.5rem;
- margin-left: 1.5rem;
+ margin-left: 0.5rem;
}
diff --git a/scripts/fixSchemas.ts b/scripts/fixSchemas.ts
index 3acfec8eec..8d26dc7209 100644
--- a/scripts/fixSchemas.ts
+++ b/scripts/fixSchemas.ts
@@ -6,6 +6,7 @@ import { Utils } from "../src/Utils"
import Validators from "../src/UI/InputElement/Validators"
import { AllKnownLayouts } from "../src/Customizations/AllKnownLayouts"
import { AllSharedLayers } from "../src/Customizations/AllSharedLayers"
+import Constants from "../src/Models/Constants"
const metainfo = {
type: "One of the inputValidator types",
@@ -199,11 +200,12 @@ function extractHintsFrom(
if (hints["suggestions"]) {
const suggestions = hints["suggestions"]
- const f = new Function("{ layers, themes, validators }", suggestions)
+ const f = new Function("{ layers, themes, validators, Constants }", suggestions)
hints["suggestions"] = f({
layers: AllSharedLayers.sharedLayers,
themes: AllKnownLayouts.allKnownLayouts,
validators: Validators,
+ Constants: Constants
})
}
return hints
diff --git a/scripts/generateImageAnalysis.ts b/scripts/generateImageAnalysis.ts
index 55095efc23..87f876d52e 100644
--- a/scripts/generateImageAnalysis.ts
+++ b/scripts/generateImageAnalysis.ts
@@ -13,6 +13,11 @@ import { Utils } from "../src/Utils"
import Constants from "../src/Models/Constants"
export default class GenerateImageAnalysis extends Script {
+ /**
+ * Max N in `image:N`-keys and `imageN` keys
+ * @private
+ */
+ private static readonly maxImageIndex = 31
constructor() {
super(
[
@@ -57,8 +62,9 @@ export default class GenerateImageAnalysis extends Script {
}
await this.fetchImages("image", datapath, refresh)
await this.fetchImages("image:streetsign", datapath, refresh)
- for (let i = 0; i < 5; i++) {
+ for (let i = 0; i < GenerateImageAnalysis.maxImageIndex; i++) {
await this.fetchImages("image:" + i, datapath, refresh)
+ await this.fetchImages("image" + i, datapath, refresh)
}
}
@@ -120,11 +126,16 @@ export default class GenerateImageAnalysis extends Script {
imageSource[feature.properties["image:streetsign"]] =
feature.properties.id + " (streetsign)"
- for (let i = 0; i < 10; i++) {
+ for (let i = 0; i < GenerateImageAnalysis.maxImageIndex; i++) {
allImages.add(feature.properties["image:" + i])
imageSource[
feature.properties["image:" + i]
] = `${feature.properties.id} (image:${i})`
+
+ allImages.add(feature.properties["image" + i])
+ imageSource[
+ feature.properties["image" + i]
+ ] = `${feature.properties.id} (image${i})`
}
}
allImages.delete(undefined)
@@ -442,7 +453,7 @@ export default class GenerateImageAnalysis extends Script {
const imageBackupPath = args[0]
await this.downloadData(datapath, cached)
- await this.downloadViews(datapath)
+ // await this.downloadViews(datapath)
await this.downloadMetadata(datapath)
await this.downloadAllImages(datapath, imageBackupPath)
this.analyze(datapath)
diff --git a/scripts/generateIncludedImages.ts b/scripts/generateIncludedImages.ts
index a497d58acc..0798c7fe32 100644
--- a/scripts/generateIncludedImages.ts
+++ b/scripts/generateIncludedImages.ts
@@ -6,68 +6,99 @@ function genImages(dryrun = false) {
const blacklist: string[] = [
"add",
"addSmall",
+ "back",
+ "blocked",
+ "brick_wall",
+ "brick_wall_raw",
+ "brick_wall_round",
"brick_wall_square",
+ "bug",
+ "center",
+ "checkmark",
"clock",
+ "close",
"community",
+ "compass",
+ "compass_arrow",
+ "confirm",
"copyright",
"cross",
"cross_bottom_right",
+ "crosshair",
"crosshair_locked",
+ "crosshair-locked",
"delete_not_allowed",
"direction_gradient",
"direction_stroke",
"duplicate",
"elevator",
"elevator_wheelchair",
- "liberapay",
- "length_crosshair",
- "speech_bubble_black_outline",
- "square",
- "star_half",
- "star_outline",
- "star",
- "osm_logo_us",
- "triangle",
- "teardrop_with_hole_green",
- "SocialImageForeground",
- "wikipedia",
- "Upload",
- "pin",
- "mapillary_black",
- "plantnet_logo",
- "mastodon",
- "move-arrows",
- "mapcomplete_logo",
- "logo",
- "logout",
- "hand",
- "help",
- "home",
- "reload",
- "min",
- "plus",
- "not_found",
- "osm_logo_us",
- "party",
+ "eye",
"filter",
"filter_disable",
"floppy",
- "eye",
"gear",
"gender_bi",
- "compass",
- "blocked",
- "brick_wall",
- "brick_wall_raw",
- "brick_wall_round",
- "bug",
- "back",
+ "gender_inter",
+ "gender_female",
+ "gender_male",
+ "gender_trans",
+ "gender_queer",
+ "generic_map",
+ "gps_arrow",
+ "hand",
+ "help",
+ "home",
+ "length_crosshair",
+ "length-crosshair",
+ "liberapay",
+ "location",
+ "location_empty",
+ "location_locked",
+ "location_refused",
+ "location-refused",
+ "location_unlocked",
+ "logo",
+ "logout",
+ "mapcomplete_logo",
+ "mapillary",
+ "mapillary_black",
+ "mastodon",
+ "min",
+ "move-arrows",
+ "move_confirm",
+ "move_not_allowed",
+ "not_found",
+ "osm_logo_us",
+ "osm-logo-us",
+ "party",
"person",
+ "pin",
+ "plantnet_logo",
+ "plus",
+ "reload",
+ "ring",
+ "robot",
+ "SocialImageForeground",
+ "speech_bubble_black_outline",
+ "square",
+ "star",
+ "star_half",
+ "star_outline",
+ "teardrop",
+ "teardrop_with_hole_green",
+ "translate",
+ "triangle",
+ "Upload",
+ "wikidata",
+ "wikimedia-commons-white",
+ "wikimedia_commons_white",
+ "wikipedia",
].map((s) => s.toLowerCase())
const dir = fs.readdirSync("./assets/svg")
let module =
- 'import Img from "./UI/Base/Img";\nimport {FixedUiElement} from "./UI/Base/FixedUiElement";\n\n/* @deprecated */\nexport default class Svg {\n\n\n'
+ 'import Img from "./UI/Base/Img";\n\n/* @deprecated */\nexport default class Svg {\n\n\n'
for (const path of dir) {
if (path.endsWith("license_info.json")) {
continue
diff --git a/scripts/prepare-build.sh b/scripts/prepare-build.sh
index 125003744f..8b35f308ec 100755
--- a/scripts/prepare-build.sh
+++ b/scripts/prepare-build.sh
@@ -16,9 +16,9 @@ export NODE_OPTIONS="--max-old-space-size=16384"
npm run generate:editor-layer-index &&
npm run prep:layeroverview &&
npm run generate && # includes a single "refresh:layeroverview". Resetting the files is unnecessary as they are not in there in the first place
+npm run generate:mapcomplete-changes-theme &&
npm run refresh:layeroverview && # run refresh:layeroverview a second time to propagate all calls
npm run refresh:layeroverview && # run refresh:layeroverview a third time to fix some issues with the favourite layer all calls
-npm run generate:mapcomplete-changes-theme &&
npm run generate:layouts
diff --git a/src/Logic/Actors/GeoLocationHandler.ts b/src/Logic/Actors/GeoLocationHandler.ts
index 152b12979c..9d32dead4a 100644
--- a/src/Logic/Actors/GeoLocationHandler.ts
+++ b/src/Logic/Actors/GeoLocationHandler.ts
@@ -153,11 +153,7 @@ export default class GeoLocationHandler {
const features: UIEventSource = new UIEventSource([])
this.currentUserLocation = new StaticFeatureSource(features)
let i = 0
- this.geolocationState.currentGPSLocation.addCallbackAndRun((location) => {
- if (location === undefined) {
- return
- }
-
+ this.geolocationState.currentGPSLocation.addCallbackAndRunD((location) => {
const properties = {
id: "gps-" + i,
"user:location": "yes",
@@ -200,7 +196,6 @@ export default class GeoLocationHandler {
)
})
features.ping()
- let i = 0
this.currentUserLocation?.features?.addCallbackAndRunD(([location]: [Feature]) => {
if (location === undefined) {
return
@@ -231,7 +226,6 @@ export default class GeoLocationHandler {
const feature = JSON.parse(JSON.stringify(location))
feature.properties.id = "gps/" + features.data.length
- i++
features.data.push(feature)
features.ping()
})
diff --git a/src/Logic/ImageProviders/WikidataImageProvider.ts b/src/Logic/ImageProviders/WikidataImageProvider.ts
index 19dcbcbf58..6de5039b41 100644
--- a/src/Logic/ImageProviders/WikidataImageProvider.ts
+++ b/src/Logic/ImageProviders/WikidataImageProvider.ts
@@ -1,13 +1,11 @@
import ImageProvider, { ProvidedImage } from "./ImageProvider"
import BaseUIElement from "../../UI/BaseUIElement"
-import Svg from "../../Svg"
import { WikimediaImageProvider } from "./WikimediaImageProvider"
import Wikidata from "../Web/Wikidata"
+import SvelteUIElement from "../../UI/Base/SvelteUIElement"
+import * as Wikidata_icon from "../../assets/svg/Wikidata.svelte"
export class WikidataImageProvider extends ImageProvider {
- public apiUrls(): string[] {
- return Wikidata.neededUrls
- }
public static readonly singleton = new WikidataImageProvider()
public readonly defaultKeyPrefixes = ["wikidata"]
@@ -15,8 +13,12 @@ export class WikidataImageProvider extends ImageProvider {
super()
}
+ public apiUrls(): string[] {
+ return Wikidata.neededUrls
+ }
+
public SourceIcon(): BaseUIElement {
- return Svg.wikidata_svg()
+ return new SvelteUIElement(Wikidata_icon)
}
public async ExtractUrls(key: string, value: string): Promise[]> {
diff --git a/src/Logic/ImageProviders/WikimediaImageProvider.ts b/src/Logic/ImageProviders/WikimediaImageProvider.ts
index b2c82dc9ee..cc0d1dadda 100644
--- a/src/Logic/ImageProviders/WikimediaImageProvider.ts
+++ b/src/Logic/ImageProviders/WikimediaImageProvider.ts
@@ -4,6 +4,8 @@ import Svg from "../../Svg"
import { Utils } from "../../Utils"
import { LicenseInfo } from "./LicenseInfo"
import Wikimedia from "../Web/Wikimedia"
+import SvelteUIElement from "../../UI/Base/SvelteUIElement"
+import Wikimedia_commons_white from "../../assets/svg/Wikimedia_commons_white.svelte"
/**
* This module provides endpoints for wikimedia and others
@@ -70,7 +72,7 @@ export class WikimediaImageProvider extends ImageProvider {
}
SourceIcon(): BaseUIElement {
- return Svg.wikimedia_commons_white_svg().SetStyle("width:2em;height: 2em")
+ return new SvelteUIElement(Wikimedia_commons_white).SetStyle("width:2em;height: 2em")
}
public PrepUrl(value: string): ProvidedImage {
diff --git a/src/Logic/Osm/OsmConnection.ts b/src/Logic/Osm/OsmConnection.ts
index 1c92f07e06..a6295bd8d4 100644
--- a/src/Logic/Osm/OsmConnection.ts
+++ b/src/Logic/Osm/OsmConnection.ts
@@ -399,11 +399,12 @@ export class OsmConnection {
return id
}
+ public static GpxTrackVisibility = ["private", "public", "trackable", "identifiable"] as const
public async uploadGpxTrack(
gpx: string,
options: {
description: string
- visibility: "private" | "public" | "trackable" | "identifiable"
+ visibility: (typeof OsmConnection.GpxTrackVisibility)[number]
filename?: string
/**
* Some words to give some properties;
@@ -425,11 +426,14 @@ export class OsmConnection {
const contents = {
file: gpx,
- description: options.description ?? "",
+ description: options.description,
tags: options.labels?.join(",") ?? "",
visibility: options.visibility,
}
+ if (!contents.description) {
+ throw "The description of a GPS-trace cannot be the empty string, undefined or null"
+ }
const extras = {
file:
'; filename="' +
diff --git a/src/Logic/SimpleMetaTagger.ts b/src/Logic/SimpleMetaTagger.ts
index 856de326bb..a425596ac9 100644
--- a/src/Logic/SimpleMetaTagger.ts
+++ b/src/Logic/SimpleMetaTagger.ts
@@ -487,12 +487,6 @@ export default class SimpleMetaTaggers {
feature.properties._isOpen = "yes"
return true
}
- console.log(
- "Calculating opening hours for",
- feature.properties.name,
- ":",
- feature.properties.opening_hours
- )
// _isOpen is calculated dynamically on every call
Object.defineProperty(feature.properties, "_isOpen", {
diff --git a/src/Logic/Web/ThemeViewStateHashActor.ts b/src/Logic/Web/ThemeViewStateHashActor.ts
index 8527d8d796..df38edce1e 100644
--- a/src/Logic/Web/ThemeViewStateHashActor.ts
+++ b/src/Logic/Web/ThemeViewStateHashActor.ts
@@ -50,6 +50,11 @@ export default class ThemeViewStateHashActor {
if (!!hash) {
// There is still a hash
// We _only_ have to (at most) close the overlays in this case
+ if (state.previewedImage.data) {
+ state.previewedImage.setData(undefined)
+ return
+ }
+
const parts = hash.split(";")
if (parts.indexOf("background") < 0) {
state.guistate.backgroundLayerSelectionIsOpened.setData(false)
@@ -176,6 +181,10 @@ export default class ThemeViewStateHashActor {
private back() {
const state = this._state
+ if (state.previewedImage.data) {
+ state.previewedImage.setData(undefined)
+ return
+ }
// history.pushState(null, null, window.location.pathname);
if (state.selectedElement.data) {
state.selectedElement.setData(undefined)
diff --git a/src/Models/Constants.ts b/src/Models/Constants.ts
index f2d6f43b29..f2c058c66b 100644
--- a/src/Models/Constants.ts
+++ b/src/Models/Constants.ts
@@ -116,28 +116,42 @@ export default class Constants {
* These are the values that are allowed to use as 'backdrop' icon for a map pin
*/
private static readonly _defaultPinIcons = [
+ "pin",
"square",
"circle",
- "none",
- "pin",
- "person",
- "plus",
- "ring",
- "star",
- "teardrop",
- "triangle",
+ "checkmark",
+ "clock",
+ "close",
"crosshair",
+ "help",
+ "home",
+ "invalid",
+ "location",
+ "location_empty",
+ "location_locked",
+ "note",
+ "resolved",
+ "ring",
+ "scissors",
+ "teardrop",
+ "teardrop_with_hole_green",
+ "triangle",
"brick_wall_square",
"brick_wall_round",
"gps_arrow",
"checkmark",
"help",
- "clock",
- "invalid",
"close",
+ "invalid",
"heart",
"heart_outline",
"link",
+ "confirm",
+ "direction",
+ "not_found",
+ "mastodon",
+ "party",
+ "addSmall",
] as const
public static readonly defaultPinIcons: string[] = Constants._defaultPinIcons
diff --git a/src/Models/MenuState.ts b/src/Models/MenuState.ts
index 55a9084e7b..b3ef6ac2e2 100644
--- a/src/Models/MenuState.ts
+++ b/src/Models/MenuState.ts
@@ -3,6 +3,7 @@ import { UIEventSource } from "../Logic/UIEventSource"
import UserRelatedState from "../Logic/State/UserRelatedState"
import { Utils } from "../Utils"
import { LocalStorageSource } from "../Logic/Web/LocalStorageSource"
+import Zoomcontrol from "../UI/Zoomcontrol"
export type ThemeViewTabStates = (typeof MenuState._themeviewTabs)[number]
export type MenuViewTabStates = (typeof MenuState._menuviewTabs)[number]
@@ -114,7 +115,36 @@ export class MenuState {
name: "background",
showOverOthers: true,
},
+ {
+ toggle: this.communityIndexPanelIsOpened,
+ name: "community",
+ showOverOthers: true,
+ },
+ {
+ toggle: this.privacyPanelIsOpened,
+ name: "privacy",
+ showOverOthers: true,
+ },
+ {
+ toggle: this.filtersPanelIsOpened,
+ name: "filters",
+ showOverOthers: true,
+ },
]
+ for (const toggle of this.allToggles) {
+ toggle.toggle.addCallback((isOpen) => {
+ if (!isOpen) {
+ this.resetZoomIfAllClosed()
+ }
+ })
+ }
+ }
+
+ private resetZoomIfAllClosed() {
+ if (this.isSomethingOpen()) {
+ return
+ }
+ Zoomcontrol.resetzoom()
}
public openFilterView(highlightLayer?: LayerConfig | string) {
@@ -146,27 +176,23 @@ export class MenuState {
this.highlightedUserSetting.setData(highlightTagRendering)
}
+ public isSomethingOpen(): boolean {
+ return this.allToggles.some((t) => t.toggle.data)
+ }
+
/**
* Close all floatOvers.
* Returns 'true' if at least one menu was opened
*/
public closeAll(): boolean {
- const toggles = [
- this.communityIndexPanelIsOpened,
- this.privacyPanelIsOpened,
- this.backgroundLayerSelectionIsOpened,
- this.filtersPanelIsOpened,
- this.menuIsOpened,
- this.themeIsOpened,
- ]
- let somethingIsOpen = false
- for (const t of toggles) {
- somethingIsOpen = t.data
- t.setData(false)
- if (somethingIsOpen) {
+ let somethingWasOpen = false
+ for (const t of this.allToggles) {
+ somethingWasOpen = t.toggle.data
+ t.toggle.setData(false)
+ if (somethingWasOpen) {
break
}
}
- return somethingIsOpen
+ return somethingWasOpen
}
}
diff --git a/src/Models/ThemeConfig/Conversion/PrepareTheme.ts b/src/Models/ThemeConfig/Conversion/PrepareTheme.ts
index c369ec378e..7ffa505ce6 100644
--- a/src/Models/ThemeConfig/Conversion/PrepareTheme.ts
+++ b/src/Models/ThemeConfig/Conversion/PrepareTheme.ts
@@ -1,14 +1,4 @@
-import {
- Concat,
- Conversion,
- DesugaringContext,
- DesugaringStep,
- Each,
- Fuse,
- On,
- Pass,
- SetDefault,
-} from "./Conversion"
+import { Concat, Conversion, DesugaringContext, DesugaringStep, Each, Fuse, On, Pass, SetDefault } from "./Conversion"
import { LayoutConfigJson } from "../Json/LayoutConfigJson"
import { PrepareLayer } from "./PrepareLayer"
import { LayerConfigJson } from "../Json/LayerConfigJson"
@@ -27,9 +17,9 @@ class SubstituteLayer extends Conversion 0
) {
context.err(
- `When overriding a layer, an override is not allowed to override into tagRenderings. Use "+tagRenderings" or "tagRenderings+" instead to prepend or append some questions.`
+ `When overriding a layer, an override is not allowed to override into tagRenderings. Use "+tagRenderings" or "tagRenderings+" instead to prepend or append some questions.`,
)
}
try {
+
+ const trPlus = json["override"]["tagRenderings+"]
+ if(trPlus){
+ let index = found.tagRenderings.findIndex(tr => tr["id"] === "leftover-questions")
+ if(index < 0){
+ index = found.tagRenderings.length
+ }
+ found.tagRenderings.splice(index, 0, ...trPlus)
+ delete json["override"]["tagRenderings+"]
+ }
+
Utils.Merge(json["override"], found)
layers.push(found)
} catch (e) {
context.err(
`Could not apply an override due to: ${e}.\nThe override is: ${JSON.stringify(
- json["override"]
- )}`
+ json["override"],
+ )}`,
)
}
if (json["hideTagRenderingsWithLabels"]) {
+ if (typeof json["hideTagRenderingsWithLabels"] === "string") {
+ throw "At " + context + ".hideTagRenderingsWithLabels should be a list containing strings, you specified a string"
+ }
const hideLabels: Set = new Set(json["hideTagRenderingsWithLabels"])
// These labels caused at least one deletion
const usedLabels: Set = new Set()
@@ -107,9 +111,9 @@ class SubstituteLayer extends Conversion 0) {
context.err(
"This theme specifies that certain tagrenderings have to be removed based on forbidden layers. One or more of these layers did not match any tagRenderings and caused no deletions: " +
- unused.join(", ") +
- "\n This means that this label can be removed or that the original tagRendering that should be deleted does not have this label anymore"
+ unused.join(", ") +
+ "\n This means that this label can be removed or that the original tagRendering that should be deleted does not have this label anymore",
)
}
found.tagRenderings = filtered
@@ -159,7 +163,7 @@ class AddDefaultLayers extends DesugaringStep {
super(
"Adds the default layers, namely: " + Constants.added_by_default.join(", "),
["layers"],
- "AddDefaultLayers"
+ "AddDefaultLayers",
)
this._state = state
}
@@ -183,10 +187,10 @@ class AddDefaultLayers extends DesugaringStep {
if (alreadyLoaded.has(v.id)) {
context.warn(
"Layout " +
- context +
- " already has a layer with name " +
- v.id +
- "; skipping inclusion of this builtin layer"
+ context +
+ " already has a layer with name " +
+ v.id +
+ "; skipping inclusion of this builtin layer",
)
continue
}
@@ -202,14 +206,14 @@ class AddImportLayers extends DesugaringStep {
super(
"For every layer in the 'layers'-list, create a new layer which'll import notes. (Note that priviliged layers and layers which have a geojson-source set are ignored)",
["layers"],
- "AddImportLayers"
+ "AddImportLayers",
)
}
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
if (!(json.enableNoteImports ?? true)) {
context.info(
- "Not creating a note import layers for theme " + json.id + " as they are disabled"
+ "Not creating a note import layers for theme " + json.id + " as they are disabled",
)
return json
}
@@ -244,7 +248,7 @@ class AddImportLayers extends DesugaringStep {
try {
const importLayerResult = creator.convert(
layer,
- context.inOperation(this.name).enter(i1)
+ context.inOperation(this.name).enter(i1),
)
if (importLayerResult !== undefined) {
json.layers.push(importLayerResult)
@@ -263,7 +267,7 @@ class AddContextToTranslationsInLayout extends DesugaringStep
super(
"Adds context to translations, including the prefix 'themes:json.id'; this is to make sure terms in an 'overrides' or inline layer are linkable too",
["_context"],
- "AddContextToTranlationsInLayout"
+ "AddContextToTranlationsInLayout",
)
}
@@ -278,7 +282,7 @@ class ApplyOverrideAll extends DesugaringStep {
super(
"Applies 'overrideAll' onto every 'layer'. The 'overrideAll'-field is removed afterwards",
["overrideAll", "layers"],
- "ApplyOverrideAll"
+ "ApplyOverrideAll",
)
}
@@ -292,9 +296,29 @@ class ApplyOverrideAll extends DesugaringStep {
delete json.overrideAll
const newLayers = []
+
+ let tagRenderingsPlus = undefined
+ if (overrideAll["tagRenderings+"] !== undefined) {
+ tagRenderingsPlus = overrideAll["tagRenderings+"]
+ delete overrideAll["tagRenderings+"]
+ }
+
for (let layer of json.layers) {
layer = Utils.Clone(layer)
Utils.Merge(overrideAll, layer)
+ if (tagRenderingsPlus) {
+ if (!layer.tagRenderings) {
+ layer.tagRenderings = tagRenderingsPlus
+ } else {
+
+ let index = layer.tagRenderings.findIndex(tr => tr["id"] === "leftover-questions")
+ if (index < 0) {
+ index = layer.tagRenderings.length - 1
+ }
+ layer.tagRenderings.splice(index, 0, ...tagRenderingsPlus)
+ }
+ }
+
newLayers.push(layer)
}
json.layers = newLayers
@@ -314,7 +338,7 @@ class AddDependencyLayersToTheme extends DesugaringStep {
Some layers (e.g. \`all_buildings_and_walls\' or \'streets_with_a_name\') are invisible, so by default, \'force_load\' is set too.
`,
["layers"],
- "AddDependencyLayersToTheme"
+ "AddDependencyLayersToTheme",
)
this._state = state
}
@@ -322,7 +346,7 @@ class AddDependencyLayersToTheme extends DesugaringStep {
private static CalculateDependencies(
alreadyLoaded: LayerConfigJson[],
allKnownLayers: Map,
- themeId: string
+ themeId: string,
): { config: LayerConfigJson; reason: string }[] {
const dependenciesToAdd: { config: LayerConfigJson; reason: string }[] = []
const loadedLayerIds: Set = new Set(alreadyLoaded.map((l) => l.id))
@@ -345,7 +369,7 @@ class AddDependencyLayersToTheme extends DesugaringStep {
for (const layerConfig of alreadyLoaded) {
try {
const layerDeps = DependencyCalculator.getLayerDependencies(
- new LayerConfig(layerConfig, themeId + "(dependencies)")
+ new LayerConfig(layerConfig, themeId + "(dependencies)"),
)
dependencies.push(...layerDeps)
} catch (e) {
@@ -382,10 +406,10 @@ class AddDependencyLayersToTheme extends DesugaringStep {
if (dep === undefined) {
const message = [
"Loading a dependency failed: layer " +
- unmetDependency.neededLayer +
- " is not found, neither as layer of " +
- themeId +
- " nor as builtin layer.",
+ unmetDependency.neededLayer +
+ " is not found, neither as layer of " +
+ themeId +
+ " nor as builtin layer.",
reason,
"Loaded layers are: " + alreadyLoaded.map((l) => l.id).join(","),
]
@@ -401,7 +425,7 @@ class AddDependencyLayersToTheme extends DesugaringStep {
})
loadedLayerIds.add(dep.id)
unmetDependencies = unmetDependencies.filter(
- (d) => d.neededLayer !== unmetDependency.neededLayer
+ (d) => d.neededLayer !== unmetDependency.neededLayer,
)
}
} while (unmetDependencies.length > 0)
@@ -422,14 +446,14 @@ class AddDependencyLayersToTheme extends DesugaringStep {
const dependencies = AddDependencyLayersToTheme.CalculateDependencies(
layers,
allKnownLayers,
- theme.id
+ theme.id,
)
for (const dependency of dependencies) {
}
if (dependencies.length > 0) {
for (const dependency of dependencies) {
context.info(
- "Added " + dependency.config.id + " to the theme. " + dependency.reason
+ "Added " + dependency.config.id + " to the theme. " + dependency.reason,
)
}
}
@@ -471,7 +495,7 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep
super(
"Generates a warning if a theme uses an unsubstituted layer",
["layers"],
- "WarnForUnsubstitutedLayersInTheme"
+ "WarnForUnsubstitutedLayersInTheme",
)
}
@@ -483,7 +507,7 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep
context
.enter("layers")
.err(
- "No layers are defined. You must define at least one layer to have a valid theme"
+ "No layers are defined. You must define at least one layer to have a valid theme",
)
return json
}
@@ -507,10 +531,10 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep
context.warn(
"The theme " +
- json.id +
- " has an inline layer: " +
- layer["id"] +
- ". This is discouraged."
+ json.id +
+ " has an inline layer: " +
+ layer["id"] +
+ ". This is discouraged.",
)
}
return json
@@ -519,11 +543,12 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep
export class PrepareTheme extends Fuse {
private state: DesugaringContext
+
constructor(
state: DesugaringContext,
options?: {
skipDefaultLayers: false | boolean
- }
+ },
) {
super(
"Fully prepares and expands a theme",
@@ -536,6 +561,7 @@ export class PrepareTheme extends Fuse {
// We expand all tagrenderings first...
new On("layers", new Each(new PrepareLayer(state))),
// Then we apply the override all. We must first expand everything in case that we override something in an expanded tag
+ // Note that it'll cheat with tagRenderings+
new ApplyOverrideAll(),
// And then we prepare all the layers _again_ in case that an override all contained unexpanded tagrenderings!
new On("layers", new Each(new PrepareLayer(state))),
@@ -543,7 +569,7 @@ export class PrepareTheme extends Fuse {
? new Pass("AddDefaultLayers is disabled due to the set flag")
: new AddDefaultLayers(state),
new AddDependencyLayersToTheme(state),
- new AddImportLayers()
+ new AddImportLayers(),
)
this.state = state
}
@@ -558,13 +584,13 @@ export class PrepareTheme extends Fuse {
const needsNodeDatabase = result.layers?.some((l: LayerConfigJson) =>
l.tagRenderings?.some((tr) =>
ValidationUtils.getSpecialVisualisations(tr)?.some(
- (special) => special.needsNodeDatabase
- )
- )
+ (special) => special.needsNodeDatabase,
+ ),
+ ),
)
if (needsNodeDatabase) {
context.info(
- "Setting 'enableNodeDatabase' as this theme uses a special visualisation which needs to keep track of _all_ nodes"
+ "Setting 'enableNodeDatabase' as this theme uses a special visualisation which needs to keep track of _all_ nodes",
)
result.enableNodeDatabase = true
}
diff --git a/src/Models/ThemeConfig/Conversion/Validation.ts b/src/Models/ThemeConfig/Conversion/Validation.ts
index 89235b9b0c..549d8da32e 100644
--- a/src/Models/ThemeConfig/Conversion/Validation.ts
+++ b/src/Models/ThemeConfig/Conversion/Validation.ts
@@ -24,6 +24,7 @@ import { ConversionContext } from "./ConversionContext"
import * as eli from "../../../assets/editor-layer-index.json"
import { AvailableRasterLayers } from "../../RasterLayers"
import Back from "../../../assets/svg/Back.svelte"
+import PointRenderingConfigJson from "../Json/PointRenderingConfigJson"
class ValidateLanguageCompleteness extends DesugaringStep {
private readonly _languages: string[]
@@ -177,6 +178,9 @@ export class ValidateTheme extends DesugaringStep {
if (!json.title) {
context.enter("title").err(`The theme ${json.id} does not have a title defined.`)
}
+ if(!json.icon){
+ context.enter("icon").err("A theme should have an icon")
+ }
if (this._isBuiltin && this._extractImages !== undefined) {
// Check images: are they local, are the licenses there, is the theme icon square, ...
const images = this._extractImages.convert(json, context.inOperation("ValidateTheme"))
@@ -243,7 +247,8 @@ export class ValidateTheme extends DesugaringStep {
new ValidateLanguageCompleteness("en").convert(theme, context)
}
} catch (e) {
- context.err(e)
+ console.error(e)
+ context.err("Could not validate the theme due to: " + e)
}
if (theme.id !== "personal") {
@@ -411,7 +416,7 @@ export class DetectConflictingAddExtraTags extends DesugaringStep {
*/
private readonly _path: string
private readonly _studioValidations: boolean
+ private readonly _validatePointRendering = new ValidatePointRendering()
constructor(path: string, isBuiltin, doesImageExist, studioValidations) {
super("Runs various checks against common mistakes for a layer", [], "PrevalidateLayer")
@@ -1105,6 +1111,8 @@ export class PrevalidateLayer extends DesugaringStep {
context.enter("pointRendering").err("There are no pointRenderings at all...")
}
+ json.pointRendering?.forEach((pr,i) => this._validatePointRendering.convert(pr, context.enters("pointeRendering", i)))
+
if (json["mapRendering"]) {
context.enter("mapRendering").err("This layer has a legacy 'mapRendering'")
}
@@ -1409,13 +1417,40 @@ export class ValidateLayerConfig extends DesugaringStep {
}
}
+class ValidatePointRendering extends DesugaringStep {
+ constructor() {
+ super("Various checks for pointRenderings", [], "ValidatePOintRendering")
+ }
+
+ convert(json: PointRenderingConfigJson, context: ConversionContext): PointRenderingConfigJson {
+ if (json.marker === undefined && json.label === undefined) {
+ context.err(`A point rendering should define at least an marker or a label`)
+ }
+
+ if (json["markers"]) {
+ context.enter("markers").err(`Detected a field 'markerS' in pointRendering. It is written as a singular case`)
+ }
+ if (json.marker && !Array.isArray(json.marker)) {
+ context.enter("marker").err(
+ "The marker in a pointRendering should be an array"
+ )
+ }
+ if (json.location.length == 0) {
+ context.enter("location").err (
+ "A pointRendering should have at least one 'location' to defined where it should be rendered. "
+ )
+ }
+ return json
+
+
+ }
+}
export class ValidateLayer extends Conversion<
LayerConfigJson,
{ parsed: LayerConfig; raw: LayerConfigJson }
> {
private readonly _skipDefaultLayers: boolean
private readonly _prevalidation: PrevalidateLayer
-
constructor(
path: string,
isBuiltin: boolean,
diff --git a/src/Models/ThemeConfig/Json/LayerConfigJson.ts b/src/Models/ThemeConfig/Json/LayerConfigJson.ts
index b161e87278..ef3b431961 100644
--- a/src/Models/ThemeConfig/Json/LayerConfigJson.ts
+++ b/src/Models/ThemeConfig/Json/LayerConfigJson.ts
@@ -506,7 +506,7 @@ export interface LayerConfigJson {
* If the way is part of a relation, MapComplete will attempt to update this relation as well
* question: Should the contributor be able to split ways using this layer?
* iftrue: enable the 'split-roads'-component
- * iffalse: don't enable the split-roads componenet
+ * iffalse: don't enable the split-roads component
* ifunset: don't enable the split-roads component
* group: editing
*/
diff --git a/src/Models/ThemeConfig/Json/PointRenderingConfigJson.ts b/src/Models/ThemeConfig/Json/PointRenderingConfigJson.ts
index d4b69157f2..96e94481b7 100644
--- a/src/Models/ThemeConfig/Json/PointRenderingConfigJson.ts
+++ b/src/Models/ThemeConfig/Json/PointRenderingConfigJson.ts
@@ -5,7 +5,7 @@ export interface IconConfigJson {
/**
* question: What icon should be used?
* type: icon
- * suggestions: return ["pin","square","circle","checkmark","clock","close","crosshair","help","home","invalid","location","location_empty","location_locked","note","resolved","ring","scissors","teardrop","teardrop_with_hole_green","triangle"].map(i => ({if: "value="+i, then: i, icon: i}))
+ * suggestions: return Constants.defaultPinIcons.map(i => ({if: "value="+i, then: i, icon: i}))
*/
icon: string | MinimalTagRenderingConfigJson | { builtin: string; override: any }
/**
diff --git a/src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson.ts b/src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson.ts
index 4c6211cc71..db6c00346f 100644
--- a/src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson.ts
+++ b/src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson.ts
@@ -106,8 +106,12 @@ export interface MappingConfigJson {
hideInAnswer?: boolean | TagConfigJson
/**
+ * question: In what other cases should this item be rendered?
+ *
* Also show this 'then'-option if the feature matches these tags.
- * Ideal for outdated tags.
+ * Ideal for outdated tags or default assumptions. The tags from this options will not be set if the option is chosen!
+ *
+ * ifunset: No other cases when this text is shown
*/
alsoShowIf?: TagConfigJson
diff --git a/src/Models/ThemeConfig/PointRenderingConfig.ts b/src/Models/ThemeConfig/PointRenderingConfig.ts
index 84a4ecfe45..a522c45a74 100644
--- a/src/Models/ThemeConfig/PointRenderingConfig.ts
+++ b/src/Models/ThemeConfig/PointRenderingConfig.ts
@@ -79,23 +79,7 @@ export default class PointRenderingConfig extends WithContextLoader {
}
})
- if (json.marker === undefined && json.label === undefined) {
- throw `At ${context}: A point rendering should define at least an marker or a label`
- }
- if (json["markers"]) {
- throw `At ${context}.markers: detected a field 'markerS' in pointRendering. It is written as a singular case`
- }
- if (json.marker && !Array.isArray(json.marker)) {
- throw `At ${context}.marker: the marker in a pointRendering should be an array`
- }
- if (this.location.size == 0) {
- throw (
- "A pointRendering should have at least one 'location' to defined where it should be rendered. (At " +
- context +
- ".location)"
- )
- }
this.marker = (json.marker ?? []).map((m) => new IconConfig(m))
if (json.css !== undefined) {
this.cssDef = this.tr("css", undefined)
diff --git a/src/Models/ThemeConfig/TagRenderingConfig.ts b/src/Models/ThemeConfig/TagRenderingConfig.ts
index 7286446025..0f70b80b0a 100644
--- a/src/Models/ThemeConfig/TagRenderingConfig.ts
+++ b/src/Models/ThemeConfig/TagRenderingConfig.ts
@@ -15,7 +15,6 @@ import {
QuestionableTagRenderingConfigJson,
} from "./Json/QuestionableTagRenderingConfigJson"
import { FixedUiElement } from "../../UI/Base/FixedUiElement"
-import { Paragraph } from "../../UI/Base/Paragraph"
import Validators, { ValidatorType } from "../../UI/InputElement/Validators"
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
import Constants from "../Constants"
@@ -371,20 +370,9 @@ export default class TagRenderingConfig {
let iconClass = commonSize
if (!!mapping.icon) {
if (typeof mapping.icon === "string" && mapping.icon !== "") {
- let stripped = mapping.icon
- if (stripped.endsWith(".svg")) {
- stripped = stripped.substring(0, stripped.length - 4)
- }
- if (Constants.defaultPinIcons.indexOf(stripped) >= 0) {
- icon = "./assets/svg/" + mapping.icon
- if (!icon.endsWith(".svg")) {
- icon += ".svg"
- }
- } else {
- icon = mapping.icon
- }
+ icon = mapping.icon.trim()
} else if (mapping.icon["path"]) {
- icon = mapping.icon["path"]
+ icon = mapping.icon["path"].trim()
iconClass = mapping.icon["class"] ?? iconClass
}
}
@@ -754,12 +742,10 @@ export default class TagRenderingConfig {
withRender = [
`This rendering asks information about the property `,
Link.OsmWiki(this.freeform.key),
- new Paragraph(
- new Combine([
- "This is rendered with ",
- new FixedUiElement(this.render.txt).SetClass("code font-bold"),
- ])
- ),
+ new Combine([
+ "This is rendered with ",
+ new FixedUiElement(this.render.txt).SetClass("code font-bold"),
+ ]),
]
}
diff --git a/src/Models/ThemeViewState.ts b/src/Models/ThemeViewState.ts
index 41515bb2fa..011cf335a4 100644
--- a/src/Models/ThemeViewState.ts
+++ b/src/Models/ThemeViewState.ts
@@ -61,6 +61,7 @@ import NearbyFeatureSource from "../Logic/FeatureSource/Sources/NearbyFeatureSou
import FavouritesFeatureSource from "../Logic/FeatureSource/Sources/FavouritesFeatureSource"
import { ProvidedImage } from "../Logic/ImageProviders/ImageProvider"
import { GeolocationControlState } from "../UI/BigComponents/GeolocationControl"
+import Zoomcontrol from "../UI/Zoomcontrol"
/**
*
@@ -481,6 +482,12 @@ export default class ThemeViewState implements SpecialVisualizationState {
this.lastClickObject.features.setData([])
})
+ this.selectedElement.addCallback((selected) => {
+ if (selected === undefined) {
+ Zoomcontrol.resetzoom()
+ }
+ })
+
if (this.layout.customCss !== undefined && window.location.pathname.indexOf("theme") >= 0) {
Utils.LoadCustomCss(this.layout.customCss)
}
@@ -524,7 +531,10 @@ export default class ThemeViewState implements SpecialVisualizationState {
}
this.selectedElement.setData(undefined)
this.guistate.closeAll()
- this.focusOnMap()
+ if (!this.guistate.isSomethingOpen()) {
+ Zoomcontrol.resetzoom()
+ this.focusOnMap()
+ }
})
Hotkeys.RegisterHotkey({ nomod: "f" }, docs.selectFavourites, () => {
diff --git a/src/UI/Base/FileSelector.svelte b/src/UI/Base/FileSelector.svelte
index 17c75f8cc0..a8d423e0cd 100644
--- a/src/UI/Base/FileSelector.svelte
+++ b/src/UI/Base/FileSelector.svelte
@@ -1,5 +1,5 @@