diff --git a/Docs/Making_Your_Own_Theme.md b/Docs/Making_Your_Own_Theme.md index a16889da02..3db8fe6bf7 100644 --- a/Docs/Making_Your_Own_Theme.md +++ b/Docs/Making_Your_Own_Theme.md @@ -33,7 +33,7 @@ You can create your own theme at https://mapcomplete.org/studio What is a good theme? --------------------- -A **theme** (or _layout_) is a single map showing one or more layers. +A **theme** is a single map showing one or more layers. The layers should work together in such a way that they serve a certain **audience**. You should be able to state in a few sentences whom would be the user of such a map, e.g. @@ -294,12 +294,12 @@ There are three important levels in the JSON file: Every field is documented in the source code itself - you can find them here: -- [The top level `LayoutConfig`](/src/Models/ThemeConfig/Json/LayoutConfigJson.ts) +- [The top level `ThemeConfig`](/src/Models/ThemeConfig/Json/ThemeConfigJson.ts) - [A layer object `LayerConfig`](/src/Models/ThemeConfig/Json/LayerConfigJson.ts) - [The `TagRendering`](/src/Models/ThemeConfig/Json/TagRenderingConfigJson.ts) - At last, the exact semantics of tags are documented [here](Tags_format.md) -A JSON schema file is available in `Docs/Schemas` - use `LayoutConfig.schema.json` to validate a theme file. +A JSON schema file is available in `Docs/Schemas` - use `ThemeConfig.schema.json` to validate a theme file. ### MetaTags diff --git a/assets/layers/bike_parking/bike_parking.json b/assets/layers/bike_parking/bike_parking.json index 9e36565216..1855ba6666 100644 --- a/assets/layers/bike_parking/bike_parking.json +++ b/assets/layers/bike_parking/bike_parking.json @@ -354,6 +354,13 @@ "nl": "Een fietskluis waar één of enkele fietsen staan en op slot kan en die te klein is om in recht te staan.", "de": "Ein Schließfach - Fahrräder werden einzeln oder mit mehreren Fahrrädern zusammen eingeschlossen. Der Schrank ist zu klein für eine stehende Person." } + }, + { + "if": "bicycle_parking=lean_and_stick", + "then": { + "en": "A lean-to bracket with possibility to use a lock through eyelet. The seat tube can be held by the stand by an anchor", + "nl": "Een aanleunbeugel met klem waarbij je de zadelbuis in een anker kan vastklikken. Er is meestal een oog om een slot door te steken" + } } ], "id": "Bicycle parking type" @@ -667,18 +674,8 @@ { "if": "access=private", "then": { - "en": "Access is limited to members of a school, company or organisation", - "nl": "Private fietsenstalling van een school, een bedrijf, ...", - "fr": "Accès limité aux membres d'une école, entreprise ou organisation", - "it": "Accesso limitato ai membri di una scuola, una compagnia o un’organizzazione", - "zh_Hant": "通行性僅限學校、公司或組織的成員", - "pt_BR": "Acesso é limitado aos membros de uma escola, companhia ou organização", - "de": "Der Parkplatz darf nur von Mitgliedern einer Schule, Firma oder Organisation genutzt werden", - "pt": "Acesso é limitado aos membros de uma escola, companhia ou organização", - "es": "El acceso se limita a miembros de una escuela, compañía u organización", - "da": "Adgangen er begrænset til medlemmer af en skole, virksomhed eller organisation", - "cs": "Přístup je omezen na členy školy, společnosti nebo organizace", - "ca": "L'accés està limitat a membres d'una escola, companyia o organització" + "en": "Private bicycle parking which is never available to the public, also not via a membership fee", + "nl": "Private fietsenstalling die niet voor het grote publiek toegankelijk is (dus ook niet met bv. een abonnement)" } } ], diff --git a/assets/layers/shops/shops.json b/assets/layers/shops/shops.json index 785fd43dc9..b825129b5f 100644 --- a/assets/layers/shops/shops.json +++ b/assets/layers/shops/shops.json @@ -567,6 +567,7 @@ "service:bicycle:retail~*", "shop=outdoor", "shop=sport", + "shop=sports", "shop=diy", "shop=doityourself" ] @@ -677,6 +678,7 @@ "or": [ "service:bicycle:repair~*", "shop=sport", + "shop=sports", "shop=outdoor", "shop=bicycle", "service:bicycle:retail=yes", @@ -782,6 +784,7 @@ "service:bicycle:rental~*", "shop=bicycle", "shop=sport", + "shop=sports", "shop=bicycle_repair", "shop=outdoor", "shop=rental" diff --git a/assets/themes/bag/bag.json b/assets/themes/bag/bag.json index 0af44dc154..03dfae4fe3 100644 --- a/assets/themes/bag/bag.json +++ b/assets/themes/bag/bag.json @@ -61,7 +61,7 @@ "minzoom": 18, "isCounted": false, "calculatedTags": [ - "_surface:strict:=feat(get)('_surface')" + "_surface:strict:=get(feat)('_surface')" ], "tagRenderings": [ { @@ -224,19 +224,19 @@ "minzoom": 18, "calculatedTags": [ "_overlaps_with_buildings=overlapWith(feat)('osm_buildings').filter(f => f.feat.properties.id.indexOf('-') < 0)", - "_overlaps_with=feat(get)('_overlaps_with_buildings').find(f => f.overlap > 1 /* square meter */ )", - "_overlaps_with_properties=feat(get)('_overlaps_with')?.feat?.properties", - "_overlap_percentage=Math.round(100 * (feat(get)('_overlaps_with')?.overlap / feat(get)('_overlaps_with_properties')['_surface:strict']))", - "_reverse_overlap_percentage=Math.round(100 * (feat(get)('_overlaps_with')?.overlap / feat(get)('_surface')))", + "_overlaps_with=get(feat)('_overlaps_with_buildings').find(f => f.overlap > 1 /* square meter */ )", + "_overlaps_with_properties=get(feat)('_overlaps_with')?.feat?.properties", + "_overlap_percentage=Math.round(100 * (get(feat)('_overlaps_with')?.overlap / get(feat)('_overlaps_with_properties')['_surface:strict']))", + "_reverse_overlap_percentage=Math.round(100 * (get(feat)('_overlaps_with')?.overlap / get(feat)('_surface')))", "_bag_obj:in_construction=feat.properties.status.startsWith('Bouwvergunning verleend') || feat.properties.status.startsWith('Bouw gestart')", "_bag_obj:construction=(feat.properties.gebruiksdoel == 'woonfunctie') ? ((Number(feat.properties.aantal_verblijfsobjecten) == 1) ? 'house' : 'apartments') : 'yes'", "_bag_obj:building=(feat.properties.status.startsWith('Bouwvergunning verleend') || feat.properties.status.startsWith('Bouw gestart')) ? 'construction' : feat.properties['_bag_obj:construction']", "_bag_obj:ref:bag=Number(feat.properties.identificatie)", "_bag_obj:source:date=new Date().toISOString().split('T')[0]", "_bag_obj:start_date=feat.properties.bouwjaar", - "_osm_obj:id=feat(get)('_overlaps_with_properties')?.id", - "_osm_obj:building=feat(get)('_overlaps_with_properties')?.building", - "_imported_osm_object_found:=Number(feat.properties.identificatie)==Number(feat(get)('_overlaps_with_properties')['ref:bag'])" + "_osm_obj:id=get(feat)('_overlaps_with_properties')?.id", + "_osm_obj:building=get(feat)('_overlaps_with_properties')?.building", + "_imported_osm_object_found:=Number(feat.properties.identificatie)==Number(get(feat)('_overlaps_with_properties')['ref:bag'])" ], "tagRenderings": [ { @@ -435,11 +435,11 @@ "_bag_obj:addr:housenumber=`${feat.properties.huisnummer}${feat.properties.huisletter}${(feat.properties.toevoeging != '') ? '-' : ''}${feat.properties.toevoeging}`", "_bag_obj:ref:bag=Number(feat.properties.identificatie)", "_bag_obj:source:date=new Date().toISOString().split('T')[0]", - "_osm_obj:addr:city:=feat(get)('_closed_osm_addr')['addr:city']", - "_osm_obj:addr:housenumber:=feat(get)('_closed_osm_addr')['addr:housenumber']", - "_osm_obj:addr:postcode:=feat(get)('_closed_osm_addr')['addr:postcode']", - "_osm_obj:addr:street:=feat(get)('_closed_osm_addr')['addr:street']", - "_imported_osm_object_found:=(feat.properties.woonplaats==feat(get)('_closed_osm_addr')['addr:city'])&&(feat(get)('_bag_obj:addr:housenumber')==feat(get)('_closed_osm_addr')['addr:housenumber'])&&(feat.properties.postcode==feat(get)('_closed_osm_addr')['addr:postcode'])&&(feat.properties.openbare_ruimte==feat(get)('_closed_osm_addr')['addr:street'])" + "_osm_obj:addr:city:=get(feat)('_closed_osm_addr')['addr:city']", + "_osm_obj:addr:housenumber:=get(feat)('_closed_osm_addr')['addr:housenumber']", + "_osm_obj:addr:postcode:=get(feat)('_closed_osm_addr')['addr:postcode']", + "_osm_obj:addr:street:=get(feat)('_closed_osm_addr')['addr:street']", + "_imported_osm_object_found:=(feat.properties.woonplaats==get(feat)('_closed_osm_addr')['addr:city'])&&(get(feat)('_bag_obj:addr:housenumber')==get(feat)('_closed_osm_addr')['addr:housenumber'])&&(feat.properties.postcode==get(feat)('_closed_osm_addr')['addr:postcode'])&&(feat.properties.openbare_ruimte==get(feat)('_closed_osm_addr')['addr:street'])" ], "tagRenderings": [ { diff --git a/assets/themes/cycle_infra/cycle_infra.json b/assets/themes/cycle_infra/cycle_infra.json index d76465476e..638efa2abc 100644 --- a/assets/themes/cycle_infra/cycle_infra.json +++ b/assets/themes/cycle_infra/cycle_infra.json @@ -61,6 +61,8 @@ "crossings", "bicycle_counter" ], - "enableDownload": true, - "widenFactor": 1.5 -} \ No newline at end of file + "overrideAll": { + "minzoom": 16 + }, + "enableDownload": true +} diff --git a/assets/themes/velopark/velopark.json b/assets/themes/velopark/velopark.json index a27ccf7b02..818a0ecbcf 100644 --- a/assets/themes/velopark/velopark.json +++ b/assets/themes/velopark/velopark.json @@ -34,6 +34,7 @@ "geoJson": "https://maproulette.org/api/v2/challenge/view/43282", "idKey": "mr_taskId" }, + "isShown": "ref:velopark!~https://data.velopark.be/data/NMBS.*", "title": { "render": "Velopark parking {mr_velopark_id}" }, diff --git a/langs/ca.json b/langs/ca.json index 1f3b8c3e86..523576aad3 100644 --- a/langs/ca.json +++ b/langs/ca.json @@ -716,4 +716,4 @@ "description": "Un identificador de Wikidata" } } -} +} \ No newline at end of file diff --git a/langs/cs.json b/langs/cs.json index 7456c1fdcd..926b9e4bfd 100644 --- a/langs/cs.json +++ b/langs/cs.json @@ -890,4 +890,4 @@ "startsWithQ": "Identifikátor wikidat začíná písmenem Q a následuje za ním číslo" } } -} +} \ No newline at end of file diff --git a/langs/da.json b/langs/da.json index 6f144dfc91..a5e17c221a 100644 --- a/langs/da.json +++ b/langs/da.json @@ -588,4 +588,4 @@ "description": "En Wikidata identifier" } } -} +} \ No newline at end of file diff --git a/langs/de.json b/langs/de.json index a2d2d8703d..eabf6ad495 100644 --- a/langs/de.json +++ b/langs/de.json @@ -898,4 +898,4 @@ "startsWithQ": "Ein Wikidata-Identifikator beginnt mit Q und wird von einer Zahl gefolgt" } } -} +} \ No newline at end of file diff --git a/langs/en.json b/langs/en.json index c4fba2678b..4c371afe24 100644 --- a/langs/en.json +++ b/langs/en.json @@ -898,4 +898,4 @@ "startsWithQ": "A wikidata identifier starts with Q and is followed by a number" } } -} +} \ No newline at end of file diff --git a/langs/es.json b/langs/es.json index 8ee55be7c1..d9427e6c16 100644 --- a/langs/es.json +++ b/langs/es.json @@ -897,4 +897,4 @@ "startsWithQ": "Un identificador wikidata comienza con Q y es seguido por un número" } } -} +} \ No newline at end of file diff --git a/langs/fi.json b/langs/fi.json index c7f3b4a7bb..ad4194fb59 100644 --- a/langs/fi.json +++ b/langs/fi.json @@ -707,4 +707,4 @@ "description": "Wikidata-tunniste" } } -} +} \ No newline at end of file diff --git a/langs/hu.json b/langs/hu.json index 81aa65ef66..ab0dfac335 100644 --- a/langs/hu.json +++ b/langs/hu.json @@ -898,4 +898,4 @@ "startsWithQ": "A Wikidata-azonosító Q-val kezdődik, amelyet egy szám követ" } } -} +} \ No newline at end of file diff --git a/langs/it.json b/langs/it.json index 4560f7eb0a..fecd93e449 100644 --- a/langs/it.json +++ b/langs/it.json @@ -531,4 +531,4 @@ "feedback": "Questo non è un numero di telefono valido" } } -} +} \ No newline at end of file diff --git a/langs/layers/ca.json b/langs/layers/ca.json index db60778564..e6a5d6c347 100644 --- a/langs/layers/ca.json +++ b/langs/layers/ca.json @@ -115,16 +115,6 @@ }, "question": "Com canvien els anuncis d'aquest element?" }, - "historic": { - "mappings": { - "0": { - "then": "Açò és un cartell publicitari històric (un anunci per a un negoci que ja no existeix o un cartell amb un gran valor patrimonial)" - }, - "1": { - "then": "Aquest cartell publicitari no té valor històric (el negoci encara existeix i no té valor patrimonial)" - } - } - }, "luminous_or_lit_advertising": { "override": { "+mappings": { @@ -188,9 +178,6 @@ "10": { "then": "Açò és una paret pintada" }, - "11": { - "then": "Açò és un mosaic - la publicitat està pintada en rajoles" - }, "2": { "then": "Açò és una columna" }, @@ -1223,9 +1210,6 @@ }, "2": { "then": "L'accés està limitat a membres d'una escola, companyia o organització" - }, - "3": { - "then": "L'accés està limitat a membres d'una escola, companyia o organització" } }, "question": "Qui pot utilitzar aquest aparcament de bicicletes?", @@ -9621,4 +9605,4 @@ "render": "Turbina eòlica" } } -} +} \ No newline at end of file diff --git a/langs/layers/cs.json b/langs/layers/cs.json index f57c9de42c..9f7157c6e0 100644 --- a/langs/layers/cs.json +++ b/langs/layers/cs.json @@ -1509,9 +1509,6 @@ }, "2": { "then": "Přístup je omezen na členy školy, společnosti nebo organizace" - }, - "3": { - "then": "Přístup je omezen na členy školy, společnosti nebo organizace" } }, "question": "Kdo může parkoviště pro jízdní kola využívat?", @@ -10085,4 +10082,4 @@ "render": "větrná turbína" } } -} +} \ No newline at end of file diff --git a/langs/layers/da.json b/langs/layers/da.json index 734fdea3ac..b792b89add 100644 --- a/langs/layers/da.json +++ b/langs/layers/da.json @@ -652,9 +652,6 @@ }, "2": { "then": "Adgangen er begrænset til medlemmer af en skole, virksomhed eller organisation" - }, - "3": { - "then": "Adgangen er begrænset til medlemmer af en skole, virksomhed eller organisation" } }, "question": "Hvem kan bruge denne cykelparkering?", @@ -3064,4 +3061,4 @@ "render": "vindmølle" } } -} +} \ No newline at end of file diff --git a/langs/layers/de.json b/langs/layers/de.json index 6ea95d7587..a90f1cf083 100644 --- a/langs/layers/de.json +++ b/langs/layers/de.json @@ -263,7 +263,7 @@ } }, "aerialway": { - "description": "Alle Arten von seil- oder drahtgestütztem Personen- oder Gütertransport, wie Seilbahnen, Gondeln, Sessellifte, Schlepplifte.", + "description": "Alle Arten von seil- oder drahtgestütztem Personen- oder Gütertransport, wie Seilbahnen, Gondeln, Sessellifte, Schlepplifte. ", "name": "Seilbahnen", "pointRendering": { "1": { @@ -302,10 +302,10 @@ "then": "Es handelt sich um eine Seilbahn, bei der die Kabine auf demselben Seil nach oben und wieder nach unten fährt." }, "1": { - "then": "Es handelt sich um eine Seilbahn, bei der die Kabinen in ständigen Kreisen fahren." + "then": "Es handelt sich um eine Seilbahn, bei der die Kabinen in ständigen Kreisen fahren" }, "10": { - "then": "Eine Seilrutsche. (Eine Touristenattraktion, bei der abenteuerlustige Menschen mit hoher Geschwindigkeit hinunterfahren)" + "then": "Eine Seilrutsche. (Eine Touristenattraktion, bei der abenteuerlustige Menschen mit hoher Geschwindigkeit hinunterfahren) " }, "2": { "then": "Ein offener Sessellift mit Sitzgelegenheiten und Zugang zur Außenluft." @@ -389,7 +389,7 @@ } }, "animal_shelter": { - "description": "Ein Tierheim ist eine Einrichtung, in die notleidende Tiere gebracht werden und wo das Personal (ob freiwillig oder nicht) sie füttert und pflegt, sie rehabilitiert und bei Bedarf heilt. Diese Definition umfasst Zwinger für ausgesetzte Hunde, Katzenheime für ausgesetzte Katzen, Unterkünfte für andere ausgesetzte Haustiere und Wildtier-Auffangstationen.", + "description": "Ein Tierheim ist eine Einrichtung, in die notleidende Tiere gebracht werden und wo das Personal (ob freiwillig oder nicht) sie füttert und pflegt, sie rehabilitiert und bei Bedarf heilt. Diese Definition umfasst Zwinger für ausgesetzte Hunde, Katzenheime für ausgesetzte Katzen, Unterkünfte für andere ausgesetzte Haustiere und Wildtier-Auffangstationen. ", "name": "Tierheime", "presets": { "0": { @@ -410,7 +410,7 @@ "then": "Tiere werden hier bis zum Ende Ihres Lebens untergebracht" }, "2": { - "then": "Tiere werden hier untergebracht und gepflegt bis sie wieder in freier Natur ausgesetzt werden können" + "then": "Tiere werden hier untergebracht und gepflegt bis sie wieder in freier Natur ausgesetzt werden können " } }, "question": "Was ist der Zweck des Tierheims?" @@ -512,7 +512,7 @@ "render": "Dies ist ein {artwork_type}" }, "artwork-website": { - "question": "Auf welcher offiziellen Webseite gibt es weitere Informationen zum Kunstwerk?", + "question": "Auf welcher Webseite gibt es weitere Informationen zum Kunstwerk?", "render": { "special": { "text": "Weitere Informationen auf dieser Webseite" @@ -559,7 +559,7 @@ } }, "assembly_point": { - "description": "Diese Ebene enthält Sammelplätze und Wartebereiche, in denen sich Mitarbeiter, Fahrgäste oder eine große Menschenmenge im Notfall versammeln.", + "description": "Diese Ebene enthält Sammelplätze und Wartebereiche, in denen sich alle Mitarbeiter, Fahrgäste oder eine große Menschenmenge im Notfall versammeln.", "name": "Notfallsammelplätze", "presets": { "0": { @@ -598,7 +598,7 @@ } }, "assisted_repair": { - "description": "Eine Selbsthilfewerkstatt ist ein Ort, an dem Menschen ihre Gegenstände mit Hilfe von Freiwilligen und verfügbaren Werkzeugen reparieren können. Ein Repair-Café ist eine Art von Veranstaltung, die regelmäßig nach denselben Prinzipien organisiert wird.", + "description": "Eine Selbsthilfewerkstatt ist ein Ort, an dem Menschen ihre Gegenstände mit Hilfe von Freiwilligen und den vor Ort verfügbaren Werkzeugen reparieren können. Ein Repair-Café ist eine Art von Veranstaltung, die regelmäßig nach denselben Prinzipien organisiert wird.", "name": "Repair-Cafés und unterstützte Reparaturwerkstätten", "presets": { "0": { @@ -838,7 +838,7 @@ "then": "Dreifach, drei Barrieren hintereinander" }, "3": { - "then": "Durchfahrtsbeschränkung - die Durchfahrtsbreite ist oben kleiner als unten" + "then": "Eine Durchfahrtsbeschränkung, Durchfahrtsbreite ist oben kleiner als unten" } }, "question": "Um welche Art Fahrradhindernis handelt es sich?" @@ -915,7 +915,7 @@ "then": "Privat" }, "3": { - "then": "Zugang bis auf Widerruf (Erlaubt)" + "then": "Zugang bis auf Widerruf" }, "4": { "then": "Zugang nur für Kunden" @@ -1148,7 +1148,7 @@ } } }, - "description": "Eine Ebene mit allen Haltestellen des Öffentlichen Verkehrs mit Sitzbank", + "description": "Eine Ebene mit allen Haltestellen des öffentlichen Nahverkehrs, die über eine Sitzbank verfügen", "name": "Sitzbänke an Haltestellen", "tagRenderings": { "bench_at_pt-bench_type": { @@ -1371,7 +1371,7 @@ "then": "Dies ist eine automatisierte Radstation, bei der ein Fahrrad mechanisch an einer Struktur befestigt wird" }, "4": { - "then": "Dies ist ein Automat, der Schlüssel nach Authentifizierung und/oder Bezahlung ausgibt und annimmt. Die Fahrräder sind in der Nähe geparkt" + "then": "Dies ist ein Automat, der Schlüssel ausgibt und annimmt, eventuell nach Authentifizierung und/oder Bezahlung. Die Fahrräder sind in der Nähe geparkt" }, "5": { "then": "Dies ist ein Rückgabepunkt, z.B. ein reservierter Parkplatz, um die Fahrräder abzustellen, die eindeutig als nur für den Verleih gekennzeichnet sind" @@ -1423,7 +1423,7 @@ } }, "bike_cafe": { - "description": "Ein Fahrradcafé ist ein Café, das auf Radfahrer ausgerichtet ist, zum Beispiel mit Dienstleistungen wie einer Pumpe und mit fahrradbezogener Dekoration.", + "description": "Ein Fahrradcafé ist ein Café, das auf Radfahrer ausgerichtet ist, zum Beispiel mit Dienstleistungen wie einer Pumpe, mit viel fahrradbezogener Dekoration, …", "name": "Fahrrad-Cafés", "presets": { "0": { @@ -1545,9 +1545,6 @@ }, "2": { "then": "Der Parkplatz darf nur von Mitgliedern einer Schule, Firma oder Organisation genutzt werden" - }, - "3": { - "then": "Der Parkplatz darf nur von Mitgliedern einer Schule, Firma oder Organisation genutzt werden" } }, "question": "Wer darf den Parkplatz nutzen?", @@ -1591,7 +1588,7 @@ }, "Capacity": { "question": "Wie viele Fahrräder passen auf diesen Fahrrad-Parkplatz?", - "questionHint": "Dazu gehören alle Fahrradtypen - reguläre Fahrräder, Lastenräder, Elektrofahrräder etc.", + "questionHint": "Dazu gehören reguläre Fahrräder, Lasträder, Ebikes,...", "render": "Der Parkplatz bietet Platz für {capacity} Fahrräder" }, "Cargo bike capacity?": { @@ -1659,7 +1656,7 @@ "then": "Die Nutzung ist kostenlos" } }, - "question": "Kann man hier kostenlos Fahrräder abstellen?" + "question": "Sind die Fahrradparkplätze kostenlos zu benutzen?" }, "maxstay": { "question": "Was ist die maximal erlaubte Parkdauer?", @@ -1675,7 +1672,7 @@ }, "operator_phone": { "question": "Wie lautet die Telefonnummer des Betreibers dieses Fahrradparkplatzes?", - "questionHint": "Man könnte diese Nummer anrufen, wenn es Probleme gibt, z. B. um herrenlose Fahrräder zu entfernen" + "questionHint": "Man könnte diese Nummer anrufen, wenn es Probleme gibt, z. B. um nicht gewartete Fahrräder zu entfernen" }, "operator_website": { "question": "Wie lautet die Nummer auf der Website des Betreibers dieses Fahrradparkplatzes?" @@ -1787,16 +1784,16 @@ "bike_repair_station-manometer": { "mappings": { "0": { - "then": "Es gibt ein Druckmessgerät" + "then": "Es gibt ein Manometer" }, "1": { - "then": "Es gibt kein Druckmessgerät" + "then": "Es gibt kein Manometer" }, "2": { - "then": "Es gibt ein Druckmessgerät, aber es ist kaputt" + "then": "Es gibt ein Manometer, aber es ist kaputt" } }, - "question": "Verfügt die Pumpe über ein Druckmessgerät?" + "question": "Verfügt die Pumpe über einen Druckanzeiger oder ein Manometer?" }, "bike_repair_station-operator": { "question": "Wer betreibt die Reparaturstation?", @@ -1817,8 +1814,8 @@ "then": "Schrader-Ventile (für Autos und Mountainbikes)" } }, - "question": "Welche Ventile stehen zur Verfügung?", - "render": "Die Pumpe hat folgende Ventile: {valves}" + "question": "Welche Ventile werden unterstützt?", + "render": "Diese Pumpe unterstützt die folgenden Ventile: {valves}" }, "opening_hours_24_7": { "override": { @@ -2034,7 +2031,7 @@ } }, "brothel": { - "description": "Eine Einrichtung, die speziell der Prostitution gewidmet ist.", + "description": "Eine Einrichtung, die speziell der Prostitution gewidmet ist. ", "name": "Bordelle", "presets": { "0": { @@ -2059,7 +2056,7 @@ } } }, - "description": "Eine Ebene mit Cafés und Kneipen, in denen man sich auf ein Getränk treffen kann.", + "description": "Eine Ebene mit Cafés und Kneipen, in denen man sich auf ein Getränk treffen kann. Die Ebene fragt nach einigen relevanten Eigenschaften", "name": "Cafés und Kneipen", "presets": { "0": { @@ -2071,7 +2068,7 @@ "title": "eine Bar" }, "2": { - "description": "Ein Café, um in ruhiger Umgebung Tee, Kaffee oder alkoholische Getränke zu trinken", + "description": "Ein Café, um in ruhiger Umgebung Tee, Kaffee oder ein alkoholisches Getränk zu trinken", "title": "ein Café" }, "3": { @@ -2089,13 +2086,13 @@ "then": "Eine modernere und kommerzielle Bar, möglicherweise mit einer Musik- und Lichtinstallation" }, "2": { - "then": "Ein Café, um in ruhiger Umgebung Tee, Kaffee oder alkoholische Getränke zu trinken" + "then": "Ein Café, um in ruhiger Umgebung Tee, Kaffee oder ein alkoholisches Getränk zu trinken" }, "3": { "then": "Ein Restaurant, in dem man ordentlich essen kann" }, "4": { - "then": "Ein Biergarten mit Außenbereich mit Bierausschank, typischerweise in Deutschland" + "then": "Ein Außenbereich mit Bierausschank, typischerweise in Deutschland" }, "5": { "then": "Dies ist ein Club oder eine Disco mit Fokus auf Tanzen, Musik von einem DJ mit begleitender Lichtshow und einer Bar, an der man (alkoholische) Getränke bekommt" @@ -2158,7 +2155,7 @@ "name": "Wohnmobilstellplätze", "presets": { "0": { - "description": "Eine Ebene mit (offiziellen) Wohnmobilstellplätzen. Dies sind ausgewiesene Plätze, an denen Sie mit Ihrem Wohnmobil übernachten können. Sie können wie ein richtiger Campingplatz aussehen oder nur wie ein Parkplatz. Möglicherweise sind sie gar nicht ausgeschildert, sondern nur in einem kommunalen Beschluss festgelegt.", + "description": "Fügen Sie einen neuen offiziellen Wohnmobilstellplatz hinzu. Dies sind ausgewiesene Plätze, an denen Sie in Ihrem Wohnmobil übernachten können. Sie können wie ein richtiger Campingplatz oder nur wie ein Parkplatz aussehen. Möglicherweise sind sie gar nicht ausgeschildert, sondern nur in einem Gemeindebeschluss festgelegt. Ein normaler Parkplatz für Wohnmobile, auf dem übernachten nicht zulässig ist, zählt nicht als Wohnmobilstellplatz. ", "title": "ein Wohnmobilstellplatz" } }, @@ -2370,8 +2367,8 @@ }, "tagRenderings": { "Auth phone": { - "question": "An welche Telefonnummer kann man sich wenden, um sich zu authentifizieren (Anruf oder SMS)?", - "render": "Authentifizierung per Anruf oder SMS an {authentication:phone_call:number}" + "question": "Wie lautet die Telefonnummer für den Authentifizierungsanruf oder die SMS?", + "render": "Authentifiziere dich, indem du anrufst oder eine SMS sendest an {authentication:phone_call:number}" }, "Authentication": { "mappings": { @@ -2385,7 +2382,7 @@ "then": "Authentifizierung per Anruf ist möglich" }, "3": { - "then": "Authentifizierung per SMS" + "then": "Authentifizierung per SMS ist möglich" }, "4": { "then": "Authentifizierung per NFC ist möglich" @@ -2588,7 +2585,7 @@ "then": "Während des Ladens ist eine zusätzliche Parkgebühr zu entrichten" } }, - "question": "Ist während des Ladens eine Parkgebühr zu bezahlen?" + "question": "Muss man während des Ladens eine Parkgebühr bezahlen?" }, "Type": { "mappings": { @@ -2800,7 +2797,7 @@ } }, "cinema": { - "description": "Ein Ort, an dem Filme gezeigt werden, die der Öffentlichkeit gegen Gebühr zugänglich sind", + "description": " Ein Ort, an dem Filme gezeigt werden, die der Öffentlichkeit gegen Gebühr zugänglich sind", "name": "Kino", "tagRenderings": { "cinema_type": { @@ -3220,7 +3217,7 @@ "then": "Diese Uhr zeigt wahrscheinlich nicht den Luftdruck an" } }, - "question": "Zeigt diese Uhr auch den Luftdruck an? (Barometer)" + "question": "Zeigt diese Uhr auch den Luftdruck an?" }, "date": { "mappings": { @@ -3336,11 +3333,11 @@ } }, "crossings": { - "description": "Übergänge für Fußgänger und/oder Radfahrer", + "description": "Übergänge für Fußgänger und Radfahrer", "name": "Kreuzungen", "presets": { "0": { - "description": "Eine Ebene die Überwege für Fußgänger und/oder Radfahrer zeigt", + "description": "Kreuzung für Fußgänger und/oder Radfahrer", "title": "eine Kreuzung" }, "1": { @@ -3469,7 +3466,7 @@ "then": "Diese Kreuzung hat kein Blindenleitsystem" }, "2": { - "then": "Der Überweg ist mit taktilem Pflaster ausgestattet, das jedoch nicht den Vorschriften entspricht" + "then": "Diese Kreuzung hat taktile Pflasterung, ist aber nicht korrekt" } }, "question": "Gibt es an dieser Kreuzung ein Blindenleitsystem?" @@ -12499,4 +12496,4 @@ "render": "Windrad" } } -} +} \ No newline at end of file diff --git a/langs/layers/en.json b/langs/layers/en.json index 295e83ae98..99f89f4e50 100644 --- a/langs/layers/en.json +++ b/langs/layers/en.json @@ -37,7 +37,7 @@ "title": "a billboard mounted to a wall" }, "10": { - "title": "a screen mounted on a transport shelter" + "title": "a screen mounted on a transit shelter" }, "11": { "description": "A piece of waterproof textile with a printed message, permanently anchored on a wall", @@ -63,10 +63,10 @@ "title": "a poster box mounted on a wall" }, "4": { - "title": "a poster box that is part of a public transport shelter" + "title": "a poster box part of a public transport shelter" }, "5": { - "description": "Small billboard for neighbourhood advertising, generally targetting pedestrians", + "description": "Small billboard for neighbourhood advertising, generally intended for pedestrians", "title": "a board" }, "6": { @@ -93,7 +93,7 @@ "then": "This object has advertisements on both sides" } }, - "question": "How many sides display advertisements?" + "question": "From how many sides you can watch advertisments?" }, "animated": { "mappings": { @@ -175,7 +175,7 @@ "render": "Operated by {operator}" }, "ref": { - "question": "What is the reference number?", + "question": "Wich is the reference number?", "render": "Reference number is {ref}" }, "type": { @@ -263,7 +263,7 @@ } }, "aerialway": { - "description": "Various forms of transport for passengers and goods that use wires, including cable cars, gondolas, chair lifts, drag lifts, and zip lines.", + "description": "Various forms of transport for passengers and goods that use wires, including cable cars, gondolas, chair lifts, drag lifts, and zip lines. ", "name": "Aerialways", "pointRendering": { "1": { @@ -274,16 +274,16 @@ }, "tagRenderings": { "duration": { - "question": "How long does a single journey take on this elevator?", + "question": "How long takes a single journey with this elevator?", "questionHint": "This excludes the waiting time.", "render": "A single journey takes {duration} minutes" }, "length": { - "render": "This aerialway is {_length:km} kilometers long" + "render": "This aerialway is {_length:km} kilometer long" }, "occupancy": { - "question": "How many people fit in a single carriage?", - "render": "{aerialway:occupancy} people fit in a single carriage" + "question": "How many people fit a single carriage?", + "render": "{aerialway:occupancy} people fit a single carriage" }, "oneway": { "mappings": { @@ -302,10 +302,10 @@ "then": "This is a cable car where the car goes up and down again on the same cable." }, "1": { - "then": "This is a gondola where the cars loop around once reaching the end." + "then": "This is a gondola where the cars go around in continuous circles" }, "10": { - "then": "A zip line. (A tourist attraction where adventurous people go down at high speeds)" + "then": "A zip line. (A touristical attraction where adventurous people go down at high speeds) " }, "2": { "then": "An open chairlift with seats to sit on and open to the outside air." @@ -326,7 +326,7 @@ "then": "A drag lift with a platter to drag a single passenger at a time" }, "8": { - "then": "A tow line which which drags skiers" + "then": "A tow line which which drags skieers" }, "9": { "then": "A magic carpet (a conveyor belt on the ground)" @@ -389,7 +389,7 @@ } }, "animal_shelter": { - "description": "An animal shelter is a facility where animals in trouble are brought and facility staff (volunteers or not) feeds and cares for them, rehabilitating and healing them if necessary. This definition includes kennels for abandoned dogs, catteries for abandoned cats, shelters for other abandoned pets and wildlife recovery centres.", + "description": "An animal shelter is a facility where animals in trouble are brought and facility's staff (volunteers or not) feeds them and cares of them, rehabilitating and healing them if necessary. This definition includes kennels for abandoned dogs, catteries for abandoned cats, shelters for other abandoned pets and wildlife recovery centres. ", "name": "Animal shelters", "presets": { "0": { @@ -410,7 +410,7 @@ "then": "Animals are taken care of for the rest of their lives" }, "2": { - "then": "Injured animals are rehabilitated here until they can be released in nature again" + "then": "Injured animals are rehabilitated here until they can be released in nature again " } }, "question": "What is the purpose of the animal shelter?" @@ -447,7 +447,7 @@ } }, "artwork": { - "description": "An open map of statues, busts, graffiti and other artworks all over the world", + "description": "An open map of statues, busts, graffitis and other artwork all over the world", "name": "Artworks", "presets": { "0": { @@ -508,11 +508,11 @@ "then": "Relief" } }, - "question": "What type of artwork is this?", + "question": "What is the type of this artwork?", "render": "This is a {artwork_type}" }, "artwork-website": { - "question": "Is there an official website with more information about this artwork?", + "question": "Is there a website with more information about this artwork?", "render": { "special": { "text": "More information on this website" @@ -559,7 +559,7 @@ } }, "assembly_point": { - "description": "This layer shows assembly points and waiting areas, where employees, passengers or a large crowd assemble in case of an emergency.", + "description": "This layer contains assembly points and waiting areas where all employees, passengers or a large crowd assemble in case of an emergency.", "name": "Emergency assembly points", "presets": { "0": { @@ -598,7 +598,7 @@ } }, "assisted_repair": { - "description": "A self-assisted workshop is a location where people can repair their goods with help of volunteers and provided tools. A repair café is a type of event organized regularly along the same principles.", + "description": "A self-assisted workshop is a location where people can come and repair their goods with help of volunteers and with the tools available at the given location. A repair café is a type of event organized regularly along the same principles.", "name": "Repair cafés and assisted repair workshops", "presets": { "0": { @@ -838,7 +838,7 @@ "then": "Triple, three barriers behind each other" }, "3": { - "then": "Squeeze gate - the gap is smaller at the top than at the bottom" + "then": "Squeeze gate, gap is smaller at top, than at the bottom" } }, "question": "What kind of cycling barrier is this?" @@ -915,7 +915,7 @@ "then": "Private" }, "3": { - "then": "Access until revoked (Permissive)" + "then": "Access until revoked" }, "4": { "then": "Access only for customers" @@ -952,7 +952,7 @@ "then": "Gas" } }, - "question": "How is the grill fuelled?" + "question": "How ist the grill fueled?" } }, "title": { @@ -993,7 +993,7 @@ "bench-armrest": { "mappings": { "0": { - "then": "This bench has one or more armrests" + "then": "This bench does have one or more armrests" }, "1": { "then": "This bench does not have any armrests" @@ -1144,11 +1144,11 @@ }, "nonDeleteMappings": { "0": { - "then": "This bus stop does not have a bench (there never was one, or it has been removed)" + "then": "This bus stop does not have a bench (there never was one or it has been removed)" } } }, - "description": "A layer showing all public transport stops that have a bench", + "description": "A layer showing all public-transport-stops which do have a bench", "name": "Benches at public transport stops", "tagRenderings": { "bench_at_pt-bench_type": { @@ -1217,10 +1217,10 @@ }, "name": { "freeform": { - "placeholder": "Name of the monitored location" + "placeholder": "Name of the counted location" }, - "question": "What is the name of the monitored location?", - "render": "Name of the monitored location: {name}" + "question": "What is the name of the counted location?", + "render": "Name of the counted location: {name}" }, "ref": { "freeform": { @@ -1254,7 +1254,7 @@ } }, "bicycle_library": { - "description": "A facility where bicycles can be lent for a longer period of time", + "description": "A facility where bicycles can be lent for longer period of times", "name": "Bicycle library", "presets": { "0": { @@ -1266,13 +1266,13 @@ "bicycle-library-target-group": { "mappings": { "0": { - "then": "Bikes for children are available" + "then": "Bikes for children available" }, "1": { - "then": "Bikes for adults are available" + "then": "Bikes for adult available" }, "2": { - "then": "Bikes for disabled people available" + "then": "Bikes for disabled persons available" } }, "question": "Who can loan bicycles here?" @@ -1307,7 +1307,7 @@ }, "nonDeleteMappings": { "0": { - "then": "This bicycle shop used to rent out bikes, but no longer does" + "then": "This bicycle shop used to rent out bikes but doesn't rent out bikes anymore" } } }, @@ -1335,10 +1335,10 @@ "then": "BMX bikes can be rented here" }, "3": { - "then": "Mountain bikes can be rented here" + "then": "Mountainbikes can be rented here" }, "4": { - "then": "Children's bikes can be rented here" + "then": "Bikes for children can be rented here" }, "5": { "then": "Tandem bicycles can be rented here" @@ -1371,7 +1371,7 @@ "then": "This is an automated docking station, where a bicycle is mechanically locked to a structure" }, "4": { - "then": "A machine is present which dispenses and accepts keys after authentication and/or payment. The bicycles are parked nearby" + "then": "A machine is present which dispenses and accepts keys, eventually after authentication and/or payment. The bicycles are parked nearby" }, "5": { "then": "This is a dropoff point, e.g. a reserved parking to place the bicycles clearly marked as being for the rental service only" @@ -1395,13 +1395,13 @@ "1": "electrical bikes" }, "2": { - "1": "Children's bikes" + "1": "bikes for children" }, "3": { "1": "BMX bikes" }, "4": { - "1": "mountain bikes" + "1": "mountainbikes" }, "5": { "1": "bicycle panniers" @@ -1423,64 +1423,64 @@ } }, "bike_cafe": { - "description": "A bike café is a café geared towards cyclists, for example with services such as a pump, and with bicycle-related decoration.", - "name": "Bike café", + "description": "A bike café is a café geared towards cyclists, for example with services such as a pump, with lots of bicycle-related decoration, …", + "name": "Bike cafe", "presets": { "0": { - "title": "a bike café" + "title": "a bike cafe" } }, "tagRenderings": { "bike_cafe-bike-pump": { "mappings": { "0": { - "then": "This bike café offers a bike pump for anyone" + "then": "This bike cafe offers a bike pump for anyone" }, "1": { - "then": "This bike café doesn't offer a bike pump for anyone" + "then": "This bike cafe doesn't offer a bike pump for anyone" } }, - "question": "Does this bike café offer a bike pump for use by anyone?" + "question": "Does this bike cafe offer a bike pump for use by anyone?" }, "bike_cafe-name": { - "question": "What is the name of this bike café?", - "render": "This bike café is called {name}" + "question": "What is the name of this bike cafe?", + "render": "This bike cafe is called {name}" }, "bike_cafe-repair-service": { "mappings": { "0": { - "then": "This bike café repairs bikes" + "then": "This bike cafe repairs bikes" }, "1": { - "then": "This bike café doesn't repair bikes" + "then": "This bike cafe doesn't repair bikes" } }, - "question": "Does this bike café repair bikes?" + "question": "Does this bike cafe repair bikes?" }, "bike_cafe-repair-tools": { "mappings": { "0": { - "then": "This bike café offers tools for DIY repair" + "then": "This bike cafe offers tools for DIY repair" }, "1": { - "then": "This bike café doesn't offer tools for DIY repair" + "then": "This bike cafe doesn't offer tools for DIY repair" } }, "question": "Are tools offered to repair your own bike?" }, "opening_hours": { "override": { - "question": "When is this bike café open?" + "question": "When it this bike café opened?" } } }, "title": { "mappings": { "0": { - "then": "Bike café {name}" + "then": "Bike cafe {name}" } }, - "render": "Bike café" + "render": "Bike cafe" } }, "bike_cleaning": { @@ -1547,7 +1547,7 @@ "then": "Access is limited to members of a school, company or organisation" }, "3": { - "then": "Access is limited to members of a school, company or organisation" + "then": "Private bicycle parking which is never available to the public, also not via a membership fee" } }, "question": "Who can use this bicycle parking?", @@ -1591,7 +1591,7 @@ }, "Capacity": { "question": "How many bicycles fit in this bicycle parking?", - "questionHint": "This includes all types of bicycle - regular, cargo, ebike etc.", + "questionHint": "This includes regular bicycles, cargo bikes, ebikes, ...", "render": "Place for {capacity} bikes" }, "Cargo bike capacity?": { @@ -1659,11 +1659,11 @@ "then": "Free to use" } }, - "question": "Is it free to park a bicycle here?" + "question": "Are these bicycle parkings free to use?" }, "maxstay": { "question": "What is the maximum allowed parking duration?", - "questionHint": "If the bicycle is parked for longer, it might be removed by the operator", + "questionHint": "If the bicycle is parked for a longer amount, it might be removed by the operator", "render": "A bike can be parked here for at most {canonical(maxstay)}" }, "operator": { @@ -1675,7 +1675,7 @@ }, "operator_phone": { "question": "What is the phone number of the operator of this bicycle parking?", - "questionHint": "One might be able to call this number in case of problems, e.g. to remove abandoned bicycles" + "questionHint": "One might be able to call this number in case of problems, e.g. to remove unmaintained bicycles" }, "operator_website": { "question": "What is the website number of the operator of this bicycle parking?" @@ -1690,15 +1690,15 @@ "name": "Bicycle pump and repair", "presets": { "0": { - "description": "A device to inflate your tires in a fixed location in a public space.", + "description": "A device to inflate your tires on a fixed location in the public space.", "title": "a bike pump" }, "1": { - "description": "A bicycle pump and tools to repair your bike in a public space. The tools are often secured with chains against theft.", + "description": "A bicycle pump and tools to repair your bike in the public space. The tools are often secured with chains against theft.", "title": "a bike repair station and pump" }, "2": { - "description": "Tools to repair your bike in a public space (without pump). The tools are secured against theft.", + "description": "Tools to repair your bike in the public space (without pump). The tools are secured against theft.", "title": "a bike repair station without pump" } }, @@ -1787,16 +1787,16 @@ "bike_repair_station-manometer": { "mappings": { "0": { - "then": "There is a pressure gauge" + "then": "There is a manometer" }, "1": { - "then": "There is no pressure gauge" + "then": "There is no manometer" }, "2": { - "then": "There is a pressure gauge but it is broken" + "then": "There is manometer but it is broken" } }, - "question": "Does the pump have a pressure gauge?" + "question": "Does the pump have a pressure indicator or manometer?" }, "bike_repair_station-operator": { "question": "Who maintains this cycle pump?", @@ -1814,11 +1814,11 @@ "then": "Dunlop" }, "2": { - "then": "Schrader (cars and mountain bikes)" + "then": "Schrader (cars and mountainbikes)" } }, - "question": "What valves are available?", - "render": "This pump has the following valves: {valves}" + "question": "What valves are supported?", + "render": "This pump supports the following valves: {valves}" }, "opening_hours_24_7": { "override": { @@ -1905,7 +1905,7 @@ } }, "bike_themed_object": { - "description": "A layer with bike-themed objects that don't match any other layer", + "description": "A layer with bike-themed objects but who don't match any other layer", "name": "Bike-related object", "title": { "mappings": { @@ -1922,7 +1922,7 @@ "presets": { "0": { "description": "A telescope or pair of binoculars mounted on a pole, available to the public to look around. ", - "title": "binoculars" + "title": "a binocular" } }, "tagRenderings": { @@ -1997,10 +1997,10 @@ "then": "There are special provisions for wheelchair users" }, "1": { - "then": "A wheelchair user can easily use this bird hide" + "then": "A wheelchair can easily use this birdhide" }, "2": { - "then": "This bird hide is accessible in a wheelchair, but it is not easy" + "then": "This birdhide is reachable by wheelchair, but it is not easy" }, "3": { "then": "Not accessible to wheelchair users" @@ -2034,7 +2034,7 @@ } }, "brothel": { - "description": "An establishment specifically dedicated to prostitution.", + "description": "An establishment specifically dedicated to prostitution. ", "name": "Brothels", "presets": { "0": { @@ -2059,11 +2059,11 @@ } } }, - "description": "A layer showing cafés and pubs where one can gather around a drink.", + "description": "A layer showing cafés and pubs where one can gather around a drink. The layer asks for some relevant questions", "name": "Cafés and pubs", "presets": { "0": { - "description": "A pub, mostly for drinking beer in a warm, relaxed interior", + "description": "A pub, mostly for drinking beers in a warm, relaxed interior", "title": "a pub" }, "1": { @@ -2071,11 +2071,11 @@ "title": "a bar" }, "2": { - "description": "A café to drink tea, coffee or an alcoholic beverage in a quiet environment", - "title": "a café" + "description": "A cafe to drink tea, coffee or an alcoholical bevarage in a quiet environment", + "title": "a cafe" }, "3": { - "description": "A nightclub or disco with a focus on dancing, music by a DJ with accompanying light show and a bar to get alcoholic) drinks", + "description": "A nightclub or disco with a focus on dancing, music by a DJ with accompanying light show and a bar to get (alcoholic) drinks", "title": "a nightclub or disco" } }, @@ -2083,25 +2083,25 @@ "Classification": { "mappings": { "0": { - "then": "A pub, mostly for drinking beer in a warm, relaxed interior" + "then": "A pub, mostly for drinking beers in a warm, relaxed interior" }, "1": { "then": "A more modern and commercial bar, possibly with a music and light installation" }, "2": { - "then": "A café to drink tea, coffee or an alcoholic beverage in a quiet environment" + "then": "A cafe to drink tea, coffee or an alcoholical bevarage in a quiet environment" }, "3": { "then": "A restaurant where one can get a proper meal" }, "4": { - "then": "This is a beer garden: an open-air space where beer is served, typically seen in Germany" + "then": "An open space where beer is served, typically seen in Germany" }, "5": { "then": "This is a nightclub or disco with a focus on dancing, music by a DJ with accompanying light show and a bar to get (alcoholic) drinks" } }, - "question": "What kind of café is this?" + "question": "What kind of cafe is this?" }, "Name": { "question": "What is the name of this business?", @@ -2117,7 +2117,7 @@ "then": "Bar" }, "2": { - "then": "Café" + "then": "Cafe" }, "3": { "then": "Nightclub" @@ -2154,18 +2154,18 @@ } }, "caravansites": { - "description": "caravan sites", - "name": "Caravan sites", + "description": "camper sites", + "name": "Camper sites", "presets": { "0": { - "description": "A layer showing (official) campervan sites. These are designated places to stay overnight with your camper. They might look like a real site or just look like parking. They may not be signposted at all, but just be defined in a municipal decision.", - "title": "a caravan site" + "description": "Add a new official camper site. These are designated places to stay overnight with your camper. They might look like a real camping or just look like a parking. They might not be signposted at all, but just be defined in a municipal decision. A regular parking intended for campers where it is not expected to spend the night, is -not- a camper site ", + "title": "a camper site" } }, "tagRenderings": { "caravansites-capacity": { - "question": "How many caravans can stay here? (skip if there is no obvious number of spaces or allowed vehicles)", - "render": "{capacity} caravans can use this place at the same time" + "question": "How many campers can stay here? (skip if there is no obvious number of spaces or allowed vehicles)", + "render": "{capacity} campers can use this place at the same time" }, "caravansites-charge": { "question": "How much does this place charge?", @@ -2259,10 +2259,10 @@ "title": { "mappings": { "0": { - "then": "Unnamed caravan site" + "then": "Unnamed camper site" } }, - "render": "Caravan site {name}" + "render": "Camper site {name}" } }, "charging_station": { @@ -2370,22 +2370,22 @@ }, "tagRenderings": { "Auth phone": { - "question": "What phone number should you contact to authenticate (call or text)?", - "render": "Authenticate by calling or texting {authentication:phone_call:number}" + "question": "What's the phone number for authentication call or SMS?", + "render": "Authenticate by calling or SMS'ing to {authentication:phone_call:number}" }, "Authentication": { "mappings": { "0": { - "then": "Authentication with a membership card" + "then": "Authentication by a membership card" }, "1": { - "then": "Authentication with an app" + "then": "Authentication by an app" }, "2": { "then": "Authentication via phone call is available" }, "3": { - "then": "Authentication via text message is available" + "then": "Authentication via SMS is available" }, "4": { "then": "Authentication via NFC is available" @@ -2547,7 +2547,7 @@ }, "OH": { "override": { - "question": "When is this charging station open?" + "question": "When is this charging station opened?" } }, "Operational status": { @@ -2588,7 +2588,7 @@ "then": "An additional parking fee should be paid while charging" } }, - "question": "Do you have to pay a parking fee while charging?" + "question": "Does one have to pay a parking fee while charging?" }, "Type": { "mappings": { @@ -2622,7 +2622,7 @@ "then": "Only customers of the place this station belongs to can use this charging station
E.g. a charging station operated by hotel which is only usable by their guests" }, "3": { - "then": "A key must be requested to access this charging station
E.g. a charging station operated by hotel which is only usable by their guests, who receive a key from the reception to unlock the charging station" + "then": "A key must be requested to access this charging station
E.g. a charging station operated by hotel which is only usable by their guests, which receive a key from the reception to unlock the charging station" }, "4": { "then": "Not accessible to the general public (e.g. only accessible to the owners, employees, ...)" @@ -2635,11 +2635,11 @@ "render": "Access is {access}" }, "capacity": { - "question": "How many vehicles can be charged here at the same time?", + "question": "How much vehicles can be charged here at the same time?", "render": "{capacity} vehicles can be charged here at the same time" }, "charge": { - "question": "How much do you have to pay to use this charging station?", + "question": "How much does one have to pay to use this charging station?", "render": "Using this charging station costs {charge}" }, "email": { @@ -2658,7 +2658,7 @@ "then": "Free to use" }, "3": { - "then": "Paid use, but free for customers of the hotel/pub/hospital/... which operates the charging station" + "then": "Paid use, but free for customers of the hotel/pub/hospital/... who operates the charging station" }, "4": { "then": "Paid use" @@ -2669,14 +2669,14 @@ "maxstay": { "mappings": { "0": { - "then": "No time limit on leaving your vehicle here" + "then": "No timelimit on leaving your vehicle here" } }, - "question": "What is the maximum amount of time you are allowed to stay here?", + "question": "What is the maximum amount of time one is allowed to stay here?", "render": "One can stay at most {canonical(maxstay)}" }, "phone": { - "question": "What number can you call if there is a problem with this charging station?", + "question": "What number can one call if there is a problem with this charging station?", "render": "In case of problems, call {phone}" }, "questions-technical": { @@ -2689,7 +2689,7 @@ "rewritten-questions": { "renderings": { "0": { - "question": "How many plugs of type {{description}} are available here?", + "question": "How much plugs of type {{description}} are available here?", "render": "There are {{{key}}} plugs of type {{description}} available here" }, "1": { @@ -2800,7 +2800,7 @@ } }, "cinema": { - "description": "A place showing movies (films), generally open to the public for a fee. Commonly referred to as a movie theater in the US", + "description": " A place showing movies (films), generally open to the public for a fee. Commonly referred to as a movie theater in the US", "name": "Cinema", "tagRenderings": { "cinema_type": { @@ -2820,7 +2820,7 @@ } }, "climbing": { - "description": "A dummy layer which contains tag renderings, shared among the climbing layers", + "description": "A dummy layer which contains tagrenderings, shared among the climbing layers", "tagRenderings": { "average_length": { "question": "What is the (average) length of the routes in meters?", @@ -2846,7 +2846,7 @@ "fee": { "mappings": { "0": { - "then": "It's free to climb here" + "then": "Climbing here is free of charge" }, "1": { "then": "Paying a fee is required to climb here" @@ -2911,7 +2911,7 @@ "questionHint": "Using your own gear, e.g. chocks" }, "website": { - "question": "Is there a (unofficial) website with more information (e.g. topos)?" + "question": "Is there a (unofficial) website with more informations (e.g. topos)?" } } }, @@ -3195,7 +3195,7 @@ } }, "clock": { - "description": "Layer showing public clocks", + "description": "Layer with public clocks", "name": "Clocks", "presets": { "0": { @@ -3217,10 +3217,10 @@ "then": "This clock does not display the air pressure" }, "2": { - "then": "This clock probably doesn't display the air pressure" + "then": "This clock does probably not display the air pressure" } }, - "question": "Does this clock also display the air pressure? (barometer)" + "question": "Does this clock also display the air pressure?" }, "date": { "mappings": { @@ -3231,7 +3231,7 @@ "then": "This clock does not display the date" }, "2": { - "then": "This clock probably doesn't display the date" + "then": "This clock does probably not display the date" } }, "question": "Does this clock also display the date?" @@ -3280,7 +3280,7 @@ "then": "This clock does not display the humidity" }, "2": { - "then": "This clock probably doesn't display the humidity" + "then": "This clock does probably not display the humidity" } }, "question": "Does this clock also display the humidity?" @@ -3311,7 +3311,7 @@ "then": "This clock does not display the temperature" }, "2": { - "then": "This clock probably doesn't display the temperature" + "then": "This clock does probably not display the temperature" } }, "question": "Does this clock also display the temperature?" @@ -3336,11 +3336,11 @@ } }, "crossings": { - "description": "Crossings for pedestrians and/or cyclists", + "description": "Crossings for pedestrians and cyclists", "name": "Crossings", "presets": { "0": { - "description": "Layer showing crossings for pedestrians and/or cyclists", + "description": "Crossing for pedestrians and/or cyclists", "title": "a crossing" }, "1": { @@ -3374,13 +3374,13 @@ "crossing-button": { "mappings": { "0": { - "then": "This traffic light has a button to request a green light" + "then": "This traffic light has a button to request green light" }, "1": { - "then": "This traffic light does not have a button to request a green light" + "then": "This traffic light does not have a button to request green light" } }, - "question": "Does this traffic light have a button to request a green light?" + "question": "Does this traffic light have a button to request green light?" }, "crossing-continue-through-red": { "mappings": { @@ -3469,7 +3469,7 @@ "then": "This crossing does not have tactile paving" }, "2": { - "then": "This crossing has tactile paving, but it doesn't meet regulations" + "then": "This crossing has tactile paving, but is not correct" } }, "question": "Does this crossing have tactile paving?" @@ -5174,7 +5174,7 @@ "then": "This is actually a pub" }, "1": { - "then": "This is actually a café" + "then": "This is actually a cafe" } } }, @@ -5550,7 +5550,7 @@ } }, "ghost_bike": { - "description": "A layer showing memorials for cyclists killed in road accidents", + "description": "A layer showing memorials for cyclists, killed in road accidents", "name": "Ghost bikes", "presets": { "0": { @@ -6186,7 +6186,7 @@ } }, "information_board": { - "description": "A layer showing touristic, road side information boards (e.g. giving information about the landscape, a building, a feature, a map, …)", + "description": "A layer showing touristical, road side information boards (e.g. giving information about the landscape, a building, a feature, a map, …)", "name": "Information boards", "presets": { "0": { @@ -7186,7 +7186,7 @@ } }, "outdoor_seating": { - "description": "Outdoor seating areas, usually located near cafés and restaurants.", + "description": "Outdoor seating areas, usually located near cafes and restaurants.", "name": "Outdoor Seating", "tagRenderings": { "access": { @@ -9652,8 +9652,8 @@ } }, "slow_roads": { - "description": "All car-free roads", - "name": "Paths, car-free and slow roads", + "description": "All carfree roads", + "name": "Paths, carfree and slow roads", "tagRenderings": { "explanation": { "mappings": { @@ -9661,7 +9661,7 @@ "then": "This is a living street" }, "1": { - "then": "This is a wide, car-free street" + "then": "This is a wide, carfree street" }, "2": { "then": "This is a footway" @@ -12499,4 +12499,4 @@ "render": "wind turbine" } } -} +} \ No newline at end of file diff --git a/langs/layers/eo.json b/langs/layers/eo.json index 04629a910e..7d3920b249 100644 --- a/langs/layers/eo.json +++ b/langs/layers/eo.json @@ -275,4 +275,4 @@ } } } -} +} \ No newline at end of file diff --git a/langs/layers/es.json b/langs/layers/es.json index 6409c955d1..5b7a46c72d 100644 --- a/langs/layers/es.json +++ b/langs/layers/es.json @@ -190,7 +190,7 @@ "then": "Esto es una pared pintada" }, "11": { - "then": "Esto es un mosaico - la publicidad está pintada en azulejos" + "then": "Esto es un azulejería - la publicidad está pintada en azulejos" }, "12": { "then": "Esto es un alivio" @@ -1387,9 +1387,6 @@ }, "2": { "then": "El acceso se limita a miembros de una escuela, compañía u organización" - }, - "3": { - "then": "El acceso se limita a miembros de una escuela, compañía u organización" } }, "question": "¿Quién puede utilizar este aparcamiento de bicicletas?", @@ -5364,4 +5361,4 @@ } } } -} +} \ No newline at end of file diff --git a/langs/layers/eu.json b/langs/layers/eu.json index c4ebc07d3c..a4c4ae6550 100644 --- a/langs/layers/eu.json +++ b/langs/layers/eu.json @@ -364,4 +364,4 @@ } } } -} +} \ No newline at end of file diff --git a/langs/layers/fr.json b/langs/layers/fr.json index cf31945f3e..cecf248b82 100644 --- a/langs/layers/fr.json +++ b/langs/layers/fr.json @@ -1113,9 +1113,6 @@ }, "2": { "then": "Accès limité aux membres d'une école, entreprise ou organisation" - }, - "3": { - "then": "Accès limité aux membres d'une école, entreprise ou organisation" } }, "question": "Qui peut utiliser ce parking à vélo ?", @@ -7545,4 +7542,4 @@ "render": "éolienne" } } -} +} \ No newline at end of file diff --git a/langs/layers/gl.json b/langs/layers/gl.json index c839468c59..580bc7503c 100644 --- a/langs/layers/gl.json +++ b/langs/layers/gl.json @@ -387,4 +387,4 @@ } } } -} +} \ No newline at end of file diff --git a/langs/layers/he.json b/langs/layers/he.json index 8aa56d69c7..0a846d94e7 100644 --- a/langs/layers/he.json +++ b/langs/layers/he.json @@ -484,4 +484,4 @@ } } } -} +} \ No newline at end of file diff --git a/langs/layers/hu.json b/langs/layers/hu.json index aff07f09b3..ed474dcea4 100644 --- a/langs/layers/hu.json +++ b/langs/layers/hu.json @@ -24,63 +24,13 @@ "render": "Ismert cím" } }, - "advertising": { - "name": "Reklámhordozók", - "presets": { - "0": { - "title": "óriásplakát" - }, - "1": { - "title": "falra erősített óriásplakát" - }, - "10": { - "title": "tömegközlekedési megállóban lévő képernyő" - }, - "11": { - "title": "ponyva" - }, - "13": { - "title": "tábla" - }, - "14": { - "title": "szobor" - }, - "15": { - "title": "falfestmény" - }, - "2": { - "title": "megállítótábla" - }, - "3": { - "title": "falra szerelt posztertartó" - }, - "4": { - "title": "tömegközlekedési megállóban lévő posztertartó" - }, - "6": { - "title": "oszlop" - }, - "7": { - "title": "zászló" - }, - "8": { - "title": "képernyő" - }, - "9": { - "title": "falra szerelt képernyő" - } - } - }, - "aerialway": { - "name": "Kötélpályák" - }, "ambulancestation": { "description": "A mentőállomás olyan terület, ahol mentőautókat, orvosi felszereléseket, egyéni védőfelszereléseket és egyéb orvosi felszereléseket tárolnak.", "name": "Mentőállomás-térkép", "presets": { "0": { "description": "Mentőállomás hozzáadása a térképhez", - "title": "mentőállomás" + "title": "Mentőállomás" } }, "tagRenderings": { @@ -123,28 +73,12 @@ "render": "Mentőállomás" } }, - "animal_shelter": { - "name": "Állatmenhelyek", - "presets": { - "0": { - "title": "állatmenhely" - } - }, - "tagRenderings": { - "2": { - "render": "Az állatmenhely neve: {name}" - } - } - }, "artwork": { "description": "Szobrok, mellszobrok, graffitik és egyéb műalkotások nyílt világtérképe", "name": "Műalkotások", "presets": { "0": { - "title": "műalkotás" - }, - "1": { - "title": "falon lévő műalkotás" + "title": "Műalkotás" } }, "tagRenderings": { @@ -212,47 +146,17 @@ "render": "Műalkotás" } }, - "assembly_point": { - "name": "Vészhelyzeti gyülekezőhely", - "presets": { - "0": { - "title": "gyülekezőhely" - } - }, - "tagRenderings": { - "assembly_point_name": { - "question": "Mi a neve ennek a gyülekezőhelynek?", - "render": "A gyülekezőhely neve: {name}" - } - } - }, - "assisted_repair": { - "tagRenderings": { - "name": { - "question": "Mi a neve ennek a szerelőműhelynek?", - "render": "A szerelőműhely neve: {name}" - } - } - }, - "atm": { - "name": "Bankautomaták", - "presets": { - "0": { - "title": "bankautomata" - } - } - }, "barrier": { "description": "Kerékpározás közbeni akadályok, például terelőoszlopok és kerékpárakadályok", "name": "Akadályok", "presets": { "0": { "description": "Terelőoszlop az úton", - "title": "terelőoszlop" + "title": "Terelőoszlop" }, "1": { "description": "A kerékpáros sebességét csökkentő kerékpárakadály", - "title": "kerékpárakadály" + "title": "Kerékpárakadály" } }, "tagRenderings": { @@ -332,20 +236,8 @@ } } }, - "bbq": { - "presets": { - "0": { - "title": "grillezőhely" - } - } - }, "bench": { "name": "Padok", - "presets": { - "0": { - "title": "pad" - } - }, "tagRenderings": { "bench-backrest": { "mappings": { @@ -444,25 +336,8 @@ "render": "Pad" } }, - "bicycle_counter": { - "presets": { - "0": { - "title": "kerékpárszámláló" - } - }, - "tagRenderings": { - "name": { - "question": "Mi a neve a megfigyelt helynek?" - } - } - }, "bicycle_library": { "description": "Létesítmény, ahonnan kerékpár kölcsönözhető hosszabb időre", - "presets": { - "0": { - "title": "kerékpárkönyvtár" - } - }, "tagRenderings": { "bicycle-library-target-group": { "question": "Ki kölcsönözhet itt kerékpárt?" @@ -475,21 +350,10 @@ }, "question": "Mennyibe kerül egy kerékpár kölcsönzése?", "render": "Egy kerékpár kölcsönzése {charge}" - }, - "bicycle_library-name": { - "question": "Mi a neve ennek a kerékpárkönyvtárnak?" } } }, "bicycle_rental": { - "presets": { - "0": { - "title": "kerékpárkölcsönző üzlet" - }, - "1": { - "title": "kerékpárkölcsönző" - } - }, "tagRenderings": { "bicycle_rental_type": { "mappings": { @@ -500,30 +364,11 @@ } } }, - "bike_cafe": { - "presets": { - "0": { - "title": "kerékpároskávézó" - } - }, - "tagRenderings": { - "bike_cafe-name": { - "question": "Mi a neve ennek a kerékpároskávézónak?" - } - } - }, - "bike_cleaning": { - "presets": { - "0": { - "title": "kerékpártisztító" - } - } - }, "bike_parking": { "name": "Kerékpártároló", "presets": { "0": { - "title": "kerékpártároló" + "title": "Kerékpártároló" } }, "tagRenderings": { @@ -574,46 +419,6 @@ "render": "Kerékpártároló" } }, - "bike_repair_station": { - "presets": { - "0": { - "title": "kerékpárpumpa" - }, - "1": { - "title": "kerékpárszerelő pont pumpával" - }, - "2": { - "title": "kerékpárszerelő pont pumpa nélkül" - } - } - }, - "bike_shop": { - "presets": { - "0": { - "title": "kerékpárszerelő /-bolt" - } - } - }, - "binocular": { - "presets": { - "0": { - "title": "távcső" - } - } - }, - "brothel": { - "presets": { - "0": { - "title": "bordélyház" - } - }, - "tagRenderings": { - "name": { - "question": "Mi a neve ennek a bordélynak?", - "render": "A bordélyház neve: {name}" - } - } - }, "cafe_pub": { "description": "Egy olyan réteg, amely kávézókat és kocsmákat jelenít meg, ahol össze lehet gyűlni egy ital köré. A réteg néhány lényeges kérdést tesz fel", "name": "Kávézók és kocsmák", @@ -626,9 +431,6 @@ }, "2": { "title": "kávézó" - }, - "3": { - "title": "night club vagy diszkó" } }, "tagRenderings": { @@ -636,23 +438,11 @@ "question": "Milyen fajta kávézó ez?" }, "Name": { - "question": "Mi a neve ennek a vállalkozásnak?", + "question": "Mi a neve ennek a kocsmának?", "render": "A kocsma neve: {name}" } } }, - "car_rental": { - "presets": { - "0": { - "title": "autókölcsönző" - } - }, - "tagRenderings": { - "name": { - "question": "Mi a neve ennek az autókölcsönzőnek?" - } - } - }, "caravansites": { "description": "Lakóautós megállóhelyek", "name": "Lakóautós megállóhely", @@ -663,9 +453,6 @@ } }, "tagRenderings": { - "caravansites-name": { - "question": "Mi a neve ennek a helynek?" - }, "caravansites-toilets": { "mappings": { "0": { @@ -679,16 +466,6 @@ } } }, - "charging_station": { - "presets": { - "0": { - "title": "e-kerékpár-töltő" - }, - "1": { - "title": "gépkocsitöltő" - } - } - }, "climbing": { "tagRenderings": { "sportclimbing": { @@ -703,33 +480,13 @@ } } }, - "climbing_area": { - "presets": { - "0": { - "title": "falmászó létesítmény" - } - }, - "title": { - "mappings": { - "0": { - "then": "A mászófal neve: {name}" - }, - "1": { - "then": "A mászóhely neve: {name}" - }, - "3": { - "then": "A mászólétesítmény neve: {name}" - } - } - } - }, "climbing_club": { "description": "Mászóegyesület vagy -szervezet", "name": "Mászóegyesület", "presets": { "0": { "description": "Egy mászóegyesület", - "title": "mászóegyesület" + "title": "Mászóegyesület" }, "1": { "description": "Mászással foglalkozó civil szervezet", @@ -750,105 +507,12 @@ } } }, - "climbing_gym": { - "presets": { - "0": { - "title": "falmászó sportcsarnok" - } - } - }, - "climbing_route": { - "presets": { - "0": { - "title": "mászóútvonal" - } - } - }, - "clock": { - "presets": { - "0": { - "title": "óra" - }, - "1": { - "title": "falra szerelt óra" - } - } - }, - "crossings": { - "presets": { - "0": { - "title": "gyalogosátkelő" - }, - "1": { - "title": "jelzőlámpa" - } - } - }, - "defibrillator": { - "presets": { - "0": { - "title": "defibrillátor" - }, - "1": { - "title": "falra szerelt defibrillátor" - } - } - }, - "dentist": { - "presets": { - "0": { - "title": "fogorvosi rendelő" - } - }, - "tagRenderings": { - "name": { - "question": "Mi a neve ennek a fogorvosnak?" - } - } - }, - "disaster_response": { - "presets": { - "0": { - "title": "katasztrófaelhárító szervezet" - } - }, - "tagRenderings": { - "disaster_response_name": { - "question": "Mi a neve ennek a szervezetnek?", - "render": "A szervezet neve: {name}" - } - } - }, - "doctors": { - "presets": { - "0": { - "title": "orvosi rendelő" - } - }, - "tagRenderings": { - "name": { - "question": "Mi a neve ennek az orvosi rendelőnek?" - } - } - }, - "dogpark": { - "presets": { - "0": { - "title": "kutyafuttató" - } - }, - "tagRenderings": { - "Name": { - "question": "Mi a neve ennek a kutyafuttatónak?" - } - } - }, "drinking_water": { "description": "Ivóvizet adó kutakat megjelenítő réteg", "name": "Ivóvíz", "presets": { "0": { - "title": "ivóvízcsap" + "title": "ivóvíz" } }, "tagRenderings": { @@ -906,40 +570,9 @@ } } }, - "elevator": { - "presets": { - "0": { - "title": "lift" - } - } - }, - "elongated_coin": { - "presets": { - "0": { - "title": "érmenyújtó prés" - } - } - }, - "entrance": { - "presets": { - "0": { - "title": "bejárat" - }, - "1": { - "title": "beltéri ajtó" - } - } - }, "etymology": { "description": "Minden olyan objektum, amelynél ismert a nevének az eredete" }, - "extinguisher": { - "presets": { - "0": { - "title": "tűzoltó készülék" - } - } - }, "filters": { "filter": { "0": { @@ -951,61 +584,7 @@ } } }, - "fire_station": { - "presets": { - "0": { - "title": "tűzoltóság" - } - }, - "tagRenderings": { - "station-name": { - "question": "Mi a neve ennek a tűzoltóságnak?" - } - } - }, - "firepit": { - "presets": { - "0": { - "title": "tűzrakóhely" - } - } - }, - "fitness_centre": { - "presets": { - "0": { - "title": "edzőterem" - } - }, - "tagRenderings": { - "name": { - "question": "Mi a neve ennek az edzőteremnek?" - } - } - }, - "fitness_station": { - "presets": { - "0": { - "title": "fitneszpark" - } - }, - "tagRenderings": { - "name": { - "question": "Mi a neve ennek a fitneszparknak?" - } - } - }, "food": { - "presets": { - "0": { - "title": "étterem" - }, - "1": { - "title": "büfé, gyorsétterem" - }, - "2": { - "title": "sültkrumpliárus" - } - }, "tagRenderings": { "Fastfood vs restaurant": { "mappings": { @@ -1013,17 +592,6 @@ "then": "Ez egy gyorsétterem (büfé), amely a gyors kiszolgálásra összpontosít. Ha vannak is ülőhelyek, ezek meglehetősen korlátozottak és funkcionálisak." } } - }, - "Name": { - "question": "Mi a neve ennek a vállalkozásnak?" - } - } - }, - "food_courts": { - "tagRenderings": { - "name": { - "question": "Mi a neve ennek az étkezőtérnek?", - "render": "Az étkezőtér neve: {name}." } } }, @@ -1031,57 +599,20 @@ "name": "Emlékkerékpárok", "presets": { "0": { - "title": "szellemkerékpár" - } - }, - "tagRenderings": { - "ghost_bike-name": { - "question": "Mi a neve ennek a szellemkerékpárnak?" + "title": "Emlékkerékpár" } }, "title": { "render": "Emlékkerékpár" } }, - "governments": { - "presets": { - "0": { - "title": "kormányzati hivatal" - } - }, - "tagRenderings": { - "name": { - "question": "Mi a neve ennek a hivatalnak?" - } - } - }, - "grave": { - "presets": { - "0": { - "title": "sírkő" - } - }, - "tagRenderings": { - "name": { - "question": "Ki van itt eltemetve?", - "render": "Itt van eltemetve {name}" - } - } - }, - "guidepost": { - "presets": { - "0": { - "title": "útirányjelző tábla" - } - } - }, "hackerspace": { "description": "Hackerspace", "name": "Hackerspace", "presets": { "0": { "description": "A hackerspace egy olyan hely, ahol szoftverek iránt érdeklő emberek találkoznak", - "title": "hackerspace" + "title": "Hackerspace" }, "1": { "description": "A makerspace olyan hely, ahol a barkácsolás szerelmesei találkoznak, hogy olyan elektronikai eszközökkel kísérletezzenek, mint például az Arduino vagy a LEDstrips…", @@ -1089,10 +620,6 @@ } }, "tagRenderings": { - "hackerspaces-name": { - "question": "Mi a neve ennek a hackerspace-nek?", - "render": "A hackerspace neve: {name}" - }, "is_makerspace": { "mappings": { "0": { @@ -1114,69 +641,6 @@ "render": "Hackerspace" } }, - "hospital": { - "tagRenderings": { - "name": { - "question": "Mi a neve ennek a kórháznak?" - } - } - }, - "hydrant": { - "presets": { - "0": { - "title": "tűzcsap" - } - } - }, - "ice_cream": { - "presets": { - "0": { - "title": "fagylaltos bódé" - } - }, - "tagRenderings": { - "1": { - "render": "A fagylaltozó neve: {name}" - } - } - }, - "indoors": { - "tagRenderings": { - "name": { - "question": "Mi a neve ennek a helyiségnek?" - } - } - }, - "information_board": { - "presets": { - "0": { - "title": "tájékoztató tábla" - } - } - }, - "kerbs": { - "presets": { - "0": { - "title": "járdaszegély" - } - } - }, - "kindergarten_childcare": { - "presets": { - "0": { - "title": "óvoda" - }, - "1": { - "title": "bölcsőde" - } - }, - "tagRenderings": { - "name": { - "question": "Mi a neve ennek a létesítménynek?", - "render": "A létesítmény neve: {name}" - } - } - }, "last_click": { "pointRendering": { "0": { @@ -1186,154 +650,6 @@ } } }, - "lighthouse": { - "presets": { - "0": { - "title": "világítótorony" - } - } - }, - "love_hotel": { - "presets": { - "0": { - "title": "love hotel" - } - }, - "tagRenderings": { - "name": { - "question": "Mi a neve ennek a love hotelnek?", - "render": "A love hotel neve: {name}" - } - } - }, - "map": { - "presets": { - "0": { - "title": "térkép" - } - } - }, - "memorial": { - "presets": { - "0": { - "title": "emlékmű" - } - } - }, - "mountain_rescue": { - "presets": { - "0": { - "title": "hegyimentő-állomás" - } - } - }, - "nature_reserve": { - "presets": { - "0": { - "title": "természetvédelmi terület" - } - } - }, - "observation_tower": { - "tagRenderings": { - "name": { - "question": "Mi a neve ennek a toronynak?", - "render": "A torony neve: {name}" - } - }, - "title": { - "mappings": { - "0": { - "then": "{name}" - } - } - } - }, - "parcel_lockers": { - "presets": { - "0": { - "title": "csomagautomata" - } - } - }, - "parking": { - "presets": { - "0": { - "title": "parkoló" - } - } - }, - "parking_ticket_machine": { - "presets": { - "0": { - "title": "parkolójegy-automata" - } - } - }, - "pharmacy": { - "presets": { - "0": { - "title": "gyógyszertár" - } - }, - "tagRenderings": { - "name": { - "question": "Mi a neve ennek a patikának?" - } - } - }, - "physiotherapist": { - "presets": { - "0": { - "title": "gyógytornászrendelő" - } - }, - "tagRenderings": { - "name": { - "question": "Mi a neve ennek a gyógytornász-rendelőnek?" - } - } - }, - "picnic_table": { - "presets": { - "0": { - "title": "piknikezőasztal" - } - } - }, - "playground": { - "presets": { - "0": { - "title": "játszótér" - } - } - }, - "playground_equipment": { - "presets": { - "0": { - "title": "játszótéri játék" - } - } - }, - "police": { - "presets": { - "0": { - "title": "rendőrség" - }, - "1": { - "title": "rendőrségi ellenőrzőpont" - }, - "2": { - "title": "igazgatási célú rendőrségi iroda" - } - }, - "tagRenderings": { - "police_name": { - "question": "Mi a neve ennek a rendőrségi létesítménynek?", - "render": "{name}" - } - } - }, "postboxes": { "description": "Postaládákat megjelenítő réteg.", "name": "Postaládák", @@ -1351,7 +667,7 @@ "name": "Posták", "presets": { "0": { - "title": "posta" + "title": "Posta" } }, "tagRenderings": { @@ -1379,7 +695,7 @@ "name": "Könyvespolcok", "presets": { "0": { - "title": "könyvespolc" + "title": "Könyvespolc" } }, "tagRenderings": { @@ -1612,260 +928,8 @@ } } }, - "rainbow_crossings": { - "presets": { - "0": { - "title": "gyalogosátkelő" - } - } - }, - "recycling": { - "presets": { - "0": { - "title": "szelektív hulladékgyűjtő konténer" - }, - "1": { - "title": "hulladékudvar" - } - }, - "tagRenderings": { - "recycling-centre-name": { - "question": "Mi a neve ennek a hulladékudvarnak?", - "render": "A hulladékudva neve: {name}" - } - } - }, - "route_marker": { - "presets": { - "0": { - "title": "turistaútjelzés" - } - } - }, - "school": { - "presets": { - "0": { - "title": "általános vagy középiskola" - } - }, - "tagRenderings": { - "school-name": { - "question": "Mi a neve ennek az iskolának?" - } - } - }, "shops": { - "description": "Egy bolt", - "presets": { - "0": { - "title": "üzlet" - } - }, - "tagRenderings": { - "shops-name": { - "question": "Mi a neve ennek a boltnak?" - } - } - }, - "shower": { - "presets": { - "0": { - "title": "zuhanyzó" - } - } - }, - "souvenir_coin": { - "presets": { - "0": { - "title": "emlékérme-automata" - } - } - }, - "souvenir_note": { - "presets": { - "0": { - "title": "emlékbankjegy-automata" - } - } - }, - "speed_camera": { - "presets": { - "0": { - "title": "traffipax" - } - } - }, - "speed_display": { - "presets": { - "0": { - "title": "sebességkijelző" - } - } - }, - "sport_pitch": { - "presets": { - "0": { - "title": "pingpongasztal" - }, - "1": { - "title": "sportpálya" - } - } - }, - "sports_centre": { - "presets": { - "0": { - "title": "sportközpont" - } - } - }, - "street_lamps": { - "presets": { - "0": { - "title": "utcai lámpa" - } - } - }, - "stripclub": { - "presets": { - "0": { - "title": "sztriptízbár" - } - }, - "tagRenderings": { - "name": { - "question": "Mi a neve ennek a sztriptízbárnak?", - "render": "A sztriptízbár neve: {name}" - } - } - }, - "surveillance_camera": { - "presets": { - "0": { - "title": "térfigyelő kamera" - }, - "1": { - "title": "falra szerelt térfigyelő kamera" - }, - "2": { - "title": "automatikus rendszámfelismerő kamera" - }, - "3": { - "title": "falra szerelt automatikus rendszámfelismerő kamera" - } - } - }, - "tertiary_education": { - "presets": { - "0": { - "title": "egyetem" - } - } - }, - "ticket_machine": { - "presets": { - "0": { - "title": "jegyautomata" - } - } - }, - "ticket_validator": { - "presets": { - "0": { - "title": "jegyérvényesítő" - } - } - }, - "toilet": { - "presets": { - "0": { - "title": "nyilvános WC" - }, - "1": { - "title": "akadálymentes illemhellyel is rendelkező WC" - } - } - }, - "tool_library": { - "presets": { - "0": { - "title": "szerszámkönyvtár" - } - } - }, - "tourism_accomodation": { - "presets": { - "0": { - "title": "szálloda" - }, - "1": { - "title": "turistaszálló" - }, - "2": { - "title": "apartman" - }, - "3": { - "title": "nyaralóház" - }, - "4": { - "title": "motel" - }, - "5": { - "title": "panzió" - }, - "6": { - "title": "kis léptékű szálláshely, amelyet jellemzően a tulajdonos üzemeltet" - }, - "7": { - "title": "kemping vagy sátrazóhely" - } - }, - "tagRenderings": { - "name": { - "question": "Mi a neve ennek: {title}?" - } - } - }, - "trail": { - "tagRenderings": { - "Name": { - "question": "Mi a neve ennek az útnak?", - "render": "Az út neve: {name}" - } - } - }, - "transit_stops": { - "tagRenderings": { - "stop_name": { - "question": "Mi a neve ennek a megállónak?", - "render": "A megálló neve: {name}" - } - } - }, - "tree_node": { - "presets": { - "0": { - "title": "lombos fa" - }, - "1": { - "title": "tűlevelű fa" - }, - "2": { - "title": "fa" - } - }, - "tagRenderings": { - "tree_node-name": { - "question": "Van-e neve ennek a fának?" - } - } - }, - "trolley_bay": { - "presets": { - "0": { - "title": "bevásárlókocsi-tároló" - } - } + "description": "Egy bolt" }, "unit": { "units": { @@ -1895,11 +959,6 @@ } }, "vending_machine": { - "presets": { - "0": { - "title": "árusító automata" - } - }, "tagRenderings": { "operational_status": { "mappings": { @@ -1916,45 +975,14 @@ } } }, - "veterinary": { - "presets": { - "0": { - "title": "állatorvos" - } - }, - "tagRenderings": { - "vetName": { - "question": "Mi a neve ennek az állatorvosnak?" - } - } - }, - "viewpoint": { - "presets": { - "0": { - "title": "kilátóhely" - } - } - }, "waste_basket": { - "description": "Ez egy nyilvános szemétkosár vagy kuka, ahová kidobhatod a szemetedet.", - "presets": { - "0": { - "title": "szemétkosár" - } - } - }, - "waste_disposal": { - "presets": { - "0": { - "title": "szemeteskonténer" - } - } + "description": "Ez egy nyilvános szemétkosár vagy kuka, ahová kidobhatod a szemetedet." }, "windturbine": { "name": "Szélerőmű", "presets": { "0": { - "title": "szélerőmű" + "title": "Szélerőmű" } }, "tagRenderings": { @@ -1983,4 +1011,4 @@ "render": "szélerőmű" } } -} +} \ No newline at end of file diff --git a/langs/layers/id.json b/langs/layers/id.json index 53d1a894ed..a9705aa622 100644 --- a/langs/layers/id.json +++ b/langs/layers/id.json @@ -1015,4 +1015,4 @@ "render": "turbin angin" } } -} +} \ No newline at end of file diff --git a/langs/layers/it.json b/langs/layers/it.json index e396c3f005..a14974143a 100644 --- a/langs/layers/it.json +++ b/langs/layers/it.json @@ -600,9 +600,6 @@ }, "2": { "then": "Accesso limitato ai membri di una scuola, una compagnia o un’organizzazione" - }, - "3": { - "then": "Accesso limitato ai membri di una scuola, una compagnia o un’organizzazione" } }, "question": "Chi può usare questo parcheggio bici?", @@ -3352,4 +3349,4 @@ "render": "pala eolica" } } -} +} \ No newline at end of file diff --git a/langs/layers/ja.json b/langs/layers/ja.json index e897e9fe0e..680606f46b 100644 --- a/langs/layers/ja.json +++ b/langs/layers/ja.json @@ -843,4 +843,4 @@ "render": "店" } } -} +} \ No newline at end of file diff --git a/langs/layers/nb_NO.json b/langs/layers/nb_NO.json index eb6996b648..c397555539 100644 --- a/langs/layers/nb_NO.json +++ b/langs/layers/nb_NO.json @@ -993,4 +993,4 @@ } } } -} +} \ No newline at end of file diff --git a/langs/layers/nl.json b/langs/layers/nl.json index 271de343be..de0432aafb 100644 --- a/langs/layers/nl.json +++ b/langs/layers/nl.json @@ -1049,7 +1049,7 @@ "then": "Private fietsenstalling van een school, een bedrijf, ..." }, "3": { - "then": "Private fietsenstalling van een school, een bedrijf, ..." + "then": "Private fietsenstalling die niet voor het grote publiek toegankelijk is (dus ook niet met bv. een abonnement)" } }, "question": "Wie mag er deze fietsenstalling gebruiken?", @@ -9893,4 +9893,4 @@ "render": "windturbine" } } -} +} \ No newline at end of file diff --git a/langs/layers/pa_PK.json b/langs/layers/pa_PK.json index 8a76bba11b..9d40b11da6 100644 --- a/langs/layers/pa_PK.json +++ b/langs/layers/pa_PK.json @@ -309,4 +309,4 @@ } } } -} +} \ No newline at end of file diff --git a/langs/layers/pl.json b/langs/layers/pl.json index 28868c5a37..e7ae159eca 100644 --- a/langs/layers/pl.json +++ b/langs/layers/pl.json @@ -3714,4 +3714,4 @@ "render": "turbina wiatrowa" } } -} +} \ No newline at end of file diff --git a/langs/layers/pt.json b/langs/layers/pt.json index 7b56120e35..258334e121 100644 --- a/langs/layers/pt.json +++ b/langs/layers/pt.json @@ -1140,9 +1140,6 @@ }, "2": { "then": "Acesso é limitado aos membros de uma escola, companhia ou organização" - }, - "3": { - "then": "Acesso é limitado aos membros de uma escola, companhia ou organização" } }, "question": "Quem pode usar este estacionamento de bicicletas?", @@ -2039,4 +2036,4 @@ } } } -} +} \ No newline at end of file diff --git a/langs/layers/pt_BR.json b/langs/layers/pt_BR.json index 970fd55e58..329bc33fd3 100644 --- a/langs/layers/pt_BR.json +++ b/langs/layers/pt_BR.json @@ -1134,9 +1134,6 @@ }, "2": { "then": "Acesso é limitado aos membros de uma escola, companhia ou organização" - }, - "3": { - "then": "Acesso é limitado aos membros de uma escola, companhia ou organização" } }, "question": "Quem pode usar este estacionamento de bicicletas?", @@ -1712,4 +1709,4 @@ } } } -} +} \ No newline at end of file diff --git a/langs/layers/ru.json b/langs/layers/ru.json index 781aedf1cb..24d5ea5108 100644 --- a/langs/layers/ru.json +++ b/langs/layers/ru.json @@ -34,30 +34,6 @@ } } }, - "aerialway": { - "tagRenderings": { - "duration": { - "question": "Сколько времени занимает один подъем на этом подъемнике?" - }, - "length": { - "render": "Длина этой воздушной трассы составляет {_length:km} километра" - }, - "oneway": { - "mappings": { - "0": { - "then": "По этой канатной дороге можно подняться только на самый верх" - } - } - }, - "type": { - "mappings": { - "8": { - "then": "Буксировочный трос, который тащит лыжников" - } - } - } - } - }, "ambulancestation": { "description": "Станция скорой помощи это полигон для хранения транспорта, медицинского оборудования, средств индивидуальной защиты и других медицинских принадлежностей.", "name": "Карта станций скорой помощи", @@ -2229,4 +2205,4 @@ } } } -} +} \ No newline at end of file diff --git a/langs/layers/uk.json b/langs/layers/uk.json index ce922ae038..e25e13aae4 100644 --- a/langs/layers/uk.json +++ b/langs/layers/uk.json @@ -196,695 +196,9 @@ } } }, - "ambulancestation": { - "tagRenderings": { - "ambulance-place": { - "question": "Де розташована станція? (наприклад, назва району, села чи міста)" - }, - "ambulance-street": { - "question": "Як називається вулиця, на якій розташована станція?" - } - } - }, "artwork": { "description": "Відкрита карта статуй, бюстів, графіті та інших творів мистецтва по всьому світу" }, - "assisted_repair": { - "tagRenderings": { - "name": { - "render": "Ця майстерня називається {name}" - } - } - }, - "bench": { - "presets": { - "0": { - "title": "лавка" - } - }, - "tagRenderings": { - "bench-armrest": { - "mappings": { - "0": { - "then": "Ця лавка має один або кілька підлокітників" - }, - "1": { - "then": "Ця лавка не має підлокітників" - } - }, - "question": "Чи має ця лавка один або кілька підлокітників?" - } - } - }, - "bicycle_counter": { - "name": "Стійки для велосипедів" - }, - "bicycle_library": { - "name": "Велосипедна бібліотека" - }, - "bike_cafe": { - "name": "Велокафе", - "tagRenderings": { - "opening_hours": { - "override": { - "question": "Коли працює велокафе?" - } - } - } - }, - "bike_cleaning": { - "name": "Послуга з чищення велосипедів" - }, - "bike_parking": { - "name": "Велопарковка" - }, - "bike_repair_station": { - "name": "Велосипедний насос і ремонт", - "tagRenderings": { - "Operational status": { - "mappings": { - "0": { - "then": "Велосипедний насос зламаний" - }, - "1": { - "then": "Велосипедний насос працює" - } - } - }, - "bike_repair_station-available-services": { - "mappings": { - "0": { - "then": "Присутній тільки насос" - }, - "1": { - "then": "Присутні лише інструменти (викрутки, плоскогубці, ...)" - }, - "2": { - "then": "Присутні як інструменти, так і насос" - } - }, - "question": "Які послуги доступні в цьому місці?" - }, - "bike_repair_station-bike-stand": { - "mappings": { - "0": { - "then": "Є гачок або підставка" - }, - "1": { - "then": "Немає гачка або підставки" - } - }, - "question": "Чи є на цій станції гачок, на який можна повісити велосипед, або підставка для його підйому?" - }, - "opening_hours_24_7": { - "override": { - "question": "Коли працює цей пункт ремонту велосипедів?" - } - }, - "send_email_about_broken_pump": { - "render": { - "special": { - "body": "Доброго дня,\n\nЦим листом хочу повідомити, що велосипедний насос, розташований за адресою https://mapcomplete.org/cyclofix?lat={_lat}&lon={_lon}&z=18#{id}, вийшов з ладу.\n\n З повагою" - } - } - } - } - }, - "bike_shop": { - "filter": { - "0": { - "options": { - "0": { - "question": "Продаж вживаних велосипедів" - } - } - }, - "1": { - "options": { - "0": { - "question": "Пропонує ремонт велосипедів власноруч" - } - } - } - }, - "name": "Ремонт/продаж велосипедів" - }, - "bike_themed_object": { - "name": "Об'єкт, пов'язаний з велосипедом" - }, - "crossings": { - "tagRenderings": { - "crossing-vibration": { - "question": "Чи має цей світлофор вібраційні сигнали для полегшення переходу? (зазвичай розташовані внизу кнопки переходу)" - } - } - }, - "defibrillator": { - "tagRenderings": { - "opening_hours_24_7": { - "override": { - "question": "В який час цей дефібрилятор доступний?" - } - } - } - }, - "drinking_water": { - "name": "Питна вода", - "tagRenderings": { - "Still in use?": { - "mappings": { - "0": { - "then": "Ця питна вода працює" - }, - "1": { - "then": "Цей пункт питної води зламаний" - }, - "2": { - "then": "Ця пункт питної води закритий" - }, - "3": { - "then": "Цей пункт питної води постійно закритий" - } - }, - "question": "Чи працює цей пункт з питною водою?", - "render": "Операційний статус - {operational_status}" - }, - "bench-artwork": { - "mappings": { - "0": { - "then": "Цей пункт питної води має інтегрований арт-об'єкт" - }, - "1": { - "then": "Цей пункт питної води не має інтегрованого художнього оформлення" - } - }, - "question": "Чи має цей фонтан питної води мистецьку складову?", - "questionHint": "Наприклад, він має вбудовану статую або іншу нетривіальну, креативну роботу" - }, - "opening_hours_24_7": { - "override": { - "+mappings": { - "0": { - "then": "У цьому сезоні фонтан з питною водою закритий. Тому години роботи не вказані." - } - }, - "questionHint": "Це години роботи фонтанчика з питною водою, якщо він працює." - } - }, - "render-closest-drinking-water": { - "render": "На відстані {_closest_other_drinking_water_distance} метрів є ще один фонтан із питною водою" - }, - "type": { - "mappings": { - "0": { - "then": "Це барботажний фонтан. Струмінь води, з якого можна пити, спрямовується вгору, зазвичай керується кнопкою." - }, - "1": { - "then": "Це пункт наповнення пляшок, де вода спрямовується вниз, як правило, за допомогою кнопки або датчика руху. Пити безпосередньо зі струмка може бути дуже важко або неможливо." - }, - "2": { - "then": "Це водопровідний кран. Вода тече вниз, а керує потоком вентиль або кнопка." - } - }, - "question": "Що це за тип пункту питної води?" - } - } - }, - "elongated_coin": { - "tagRenderings": { - "indoor": { - "mappings": { - "0": { - "then": "Цей копійчаний прес розташований у приміщенні." - }, - "1": { - "then": "Цей копійчаний прес розташований на відкритому повітрі." - } - } - } - } - }, - "etymology": { - "tagRenderings": { - "street-name-sign-image": { - "render": "{image_carousel(image:streetsign)}
{image_upload(image:streetsign, Додати зображення таблички з назвою вулиці)}" - }, - "wikipedia-etymology": { - "render": "

Стаття у Вікіпедії про давача імені

{wikipedia(name:etymology:wikidata):max-height:20rem}" - } - } - }, - "filters": { - "filter": { - "0": { - "options": { - "0": { - "question": "Відчинено" - } - } - }, - "10": { - "options": { - "0": { - "question": "Не надає переваги собакам" - } - } - }, - "8": { - "options": { - "0": { - "question": "Має органічні продукти" - } - } - } - } - }, - "fire_station": { - "presets": { - "0": { - "description": "Пожежна станція - це місце, де знаходяться пожежні машини та пожежники, коли вони не працюють." - } - }, - "tagRenderings": { - "station-agency": { - "question": "Яке відомство управляє цією станцією?" - }, - "station-name": { - "render": "Ця станція називається {name}." - }, - "station-operator": { - "mappings": { - "0": { - "then": "Станція знаходиться в управлінні держави." - }, - "1": { - "then": "Станція управляється громадською або неформальною організацією." - }, - "2": { - "then": "Станцію обслуговує офіційна група волонтерів." - }, - "3": { - "then": "Станція знаходиться в приватному управлінні." - } - }, - "question": "Як класифікується оператор станції?" - }, - "station-place": { - "question": "Де розташована станція? (наприклад, назва району, села чи міста)" - }, - "station-street": { - "question": " Як називається вулиця, на якій розташована станція?", - "render": "Ця станція знаходиться вздовж вулиці під назвою {addr:street}." - } - } - }, - "food": { - "filter": { - "1": { - "options": { - "0": { - "question": "Бронювання не потрібно" - } - } - }, - "3": { - "options": { - "0": { - "question": "Має вегетаріанське меню" - } - } - }, - "4": { - "options": { - "0": { - "question": "Має веганське меню" - } - } - }, - "5": { - "options": { - "0": { - "question": "Має халяльне меню" - } - } - } - }, - "tagRenderings": { - "Cuisine": { - "question": "Яку їжу тут подають?" - }, - "Fastfood vs restaurant": { - "mappings": { - "0": { - "then": "Це бізнес швидкого харчування, орієнтований на швидке обслуговування. Якщо місця для сидіння і є, то вони досить обмежені та функціональні." - }, - "1": { - "then": "Ресторан, орієнтований на створення приємних вражень, коли вас обслуговують за столом" - } - }, - "question": "Що це за бізнес?" - }, - "Name": { - "question": "Як називається цей бізнес?", - "render": "Назва цього бізнесу - {name}" - }, - "add-menu-image": { - "render": { - "special": { - "label": "Додати зображення з меню" - } - } - } - } - }, - "food_courts": { - "tagRenderings": { - "name": { - "question": "Як називається цей фудкорт?", - "render": "Цей фудкорт називається {name}." - } - } - }, - "gps_track": { - "name": "Твій пройдений шлях" - }, - "hackerspace": { - "tagRenderings": { - "is_makerspace": { - "mappings": { - "2": { - "then": "Це хак-лабораторія, яка здебільшого зосереджена на базових комп'ютерних навичках, використовує перероблені пристрої та/або надає доступ до Інтернету громаді. Зазвичай вони розташовані в автономних приміщеннях, сквотах або соціальних об'єктах" - } - } - }, - "opening_hours_24_7": { - "override": { - "question": "Коли відкривається цей хакерський простір?" - } - } - } - }, - "hydrant": { - "tagRenderings": { - "hydrant-color": { - "mappings": { - "0": { - "then": "Колір гідранта - жовтий." - }, - "1": { - "then": "Колір гідранта - червоний." - } - }, - "question": "Якого кольору гідрант?" - }, - "hydrant-diameter": { - "question": "Який діаметр труби цього гідранта?" - }, - "hydrant-type": { - "mappings": { - "0": { - "then": "Стовповий тип." - }, - "1": { - "then": "Тип труби." - }, - "2": { - "then": "Настінний тип." - }, - "3": { - "then": "Підземного типу." - } - }, - "question": "Який це тип гідранта?" - } - } - }, - "kindergarten_childcare": { - "tagRenderings": { - "opening_hours": { - "override": { - "question": "Коли відкривається цей дитячий садок?" - } - } - } - }, - "picnic_table": { - "tagRenderings": { - "picnic_table-material": { - "mappings": { - "0": { - "then": "Це дерев'яний стіл для пікніка" - }, - "1": { - "then": "Це бетонний стіл для пікніка" - }, - "2": { - "then": "Цей стіл для пікніка виготовлений з (переробленого) пластику" - }, - "3": { - "then": "Цей стіл для пікніка виготовлений з металу" - } - }, - "question": "З якого матеріалу виготовлений цей стіл для пікніка?" - } - } - }, - "playground": { - "tagRenderings": { - "fee": { - "mappings": { - "0": { - "then": "Вільне використання" - }, - "1": { - "then": "Платний дитячий майданчик" - } - } - }, - "playground-lit": { - "mappings": { - "0": { - "then": "Цей майданчик освітлюється вночі" - }, - "1": { - "then": "Цей майданчик не освітлюється вночі" - } - }, - "question": "Чи освітлюється цей майданчик вночі?" - }, - "playground-min_age": { - "question": "Який мінімальний вік, необхідний для доступу до цього дитячого майданчика?", - "render": "Доступно для дітей старше {min_age} років" - }, - "playground-opening_hours": { - "mappings": { - "0": { - "then": "Доступний від сходу до заходу сонця" - }, - "1": { - "then": "Завжди доступні" - } - }, - "question": "Коли цей майданчик доступний?" - }, - "playground-surface": { - "mappings": { - "0": { - "then": "Поверхня - трава" - }, - "1": { - "then": "Поверхня - пісок" - }, - "10": { - "then": "Поверхня - дрібний гравій (менше 2 см на камінь)" - }, - "2": { - "then": "Поверхня складається з деревної стружки" - }, - "3": { - "then": "Покриття - бруківка" - }, - "4": { - "then": "Покриття - асфальт" - }, - "5": { - "then": "Поверхня - бетон" - }, - "8": { - "then": "Покриття - тартан - синтетична, пружна поверхня, яку зазвичай можна побачити на спортивних трасах" - }, - "9": { - "then": "Поверхня зроблена з гуми, наприклад, гумова плитка, гумова мульча або велика гумова площа" - } - }, - "question": "Яка поверхня цього дитячого майданчика?", - "questionHint": "Якщо їх декілька, виберіть найпоширеніший" - } - } - }, - "postoffices": { - "tagRenderings": { - "opening_hours": { - "override": { - "question": "Які години роботи цього поштового відділення?" - } - } - } - }, - "questions": { - "tagRenderings": { - "opening_hours": { - "mappings": { - "0": { - "then": "Позначений як закритий на невизначений час" - } - }, - "question": "Які години роботи {title()}?", - "render": "

Години роботи

{opening_hours_table(opening_hours)}" - }, - "opening_hours_24_7": { - "override": { - "+mappings": { - "0": { - "then": "Працює 24/7 (включаючи святкові дні)" - } - } - } - }, - "opening_hours_by_appointment": { - "override": { - "+mappings": { - "0": { - "then": "Тільки за попереднім записом" - }, - "1": { - "then": "Тільки за попереднім записом" - } - } - } - }, - "single_level": { - "mappings": { - "0": { - "then": "Розташований під землею" - }, - "1": { - "then": "Розташований на рівні землі" - }, - "2": { - "then": "Розташований на рівні землі" - }, - "3": { - "then": "Розташований на першому поверсі" - }, - "4": { - "then": "Розташований на першому підвальному поверсі" - } - }, - "question": "На якому поверсі знаходиться цей об'єкт?", - "render": "Розташований на {level} поверсі" - } - } - }, - "recycling": { - "tagRenderings": { - "container-location": { - "mappings": { - "1": { - "then": "Цей контейнер знаходиться в приміщенні" - }, - "2": { - "then": "Цей контейнер розташований на відкритому повітрі" - } - } - }, - "opening_hours_24_7": { - "override": { - "question": "Які години роботи цього об'єкту з переробки?" - } - } - } - }, - "shops": { - "tagRenderings": { - "brand": { - "mappings": { - "0": { - "then": "Цей магазин не має певного бренду, він не є частиною великої мережі" - } - }, - "question": "Який бренд цього магазину?" - }, - "shops-name": { - "question": "Як називається цей магазин?", - "render": "Цей магазин називається {name}" - } - } - }, - "sport_pitch": { - "tagRenderings": { - "sport_pitch-opening_hours": { - "mappings": { - "0": { - "then": "Завжди доступні" - }, - "1": { - "then": "Завжди доступні" - } - }, - "question": "Коли цей майданчик доступний?" - } - } - }, - "toilet": { - "tagRenderings": { - "menstrual_products_location": { - "mappings": { - "0": { - "then": "Безкоштовні менструальні засоби знаходяться в туалеті для жінок" - }, - "1": { - "then": "Безкоштовні менструальні засоби знаходяться в туалеті для чоловіків" - }, - "2": { - "then": "Безкоштовні менструальні засоби знаходяться в туалеті для людей на візках" - } - }, - "question": "Де знаходяться безкоштовні менструальні засоби?" - }, - "opening_hours_24_7": { - "override": { - "question": "Коли відкриваються ці туалети?" - } - }, - "toilet-changing_table:location": { - "question": "Де знаходиться пеленальний столик?" - }, - "toilets-wheelchair": { - "mappings": { - "0": { - "then": "Є спеціальний туалет для людей на інвалідних візках" - }, - "1": { - "then": "Немає доступу для інвалідних візків" - }, - "2": { - "then": "Є лише спеціальний туалет для людей на візках" - } - }, - "question": "Чи є спеціальний туалет для людей на візках?" - } - } - }, - "toilet_at_amenity": { - "tagRenderings": { - "opening_hours": { - "override": { - "question": "Коли відкрито приміщення, де розташовані ці туалети?" - } - } - } - }, "usersettings": { "description": "Спеціальний шар, який не призначений для відображення на карті, але використовується для встановлення користувацьких налаштувань", "tagRenderings": { @@ -953,175 +267,8 @@ "5": { "then": "Використовувати фоновий шар {mapcomplete-preferred-background-layer} як фон за замовчуванням" } - }, - "question": "Який фоновий шар показувати за замовчуванням?", - "questionHint": "Щоб встановити певний фон за замовчуванням, спочатку виберіть його в меню фону, після чого він з'явиться тут." - }, - "cscount-thanks": { - "mappings": { - "0": { - "then": "Ви вносили зміни {_csCount} разів! Це чудово!" - } - } - }, - "debug-title": { - "render": "

Опції налагодження

" - }, - "fixate-north": { - "mappings": { - "0": { - "then": "Дозволити обертати карту" - }, - "1": { - "then": "Завжди тримати північ угорі" - } - }, - "question": "Чи завжди північ має бути вгорі?" - }, - "more_privacy": { - "mappings": { - "0": { - "then": "Вносячи зміни до OpenStreetMap, не вказуйте, як далеко ви знаходилися від змінених об'єктів." - }, - "1": { - "then": "Вносячи зміни до OpenStreetMap, приблизно вказуйте, як далеко ви знаходилися від змінених об'єктів. Це допоможе іншим учасникам зрозуміти, як ви внесли зміни" - } - }, - "question": "Вносячи зміни, чи потрібно приблизно вказувати, як далеко ви знаходилися від об'єкта?", - "questionHint": "Якщо ви вносите зміни до одного або декількох об'єктів і ввімкнули функцію визначення вашого місцезнаходження, буде збережено приблизну інформацію про те, де ви перебували: чи були ви ближче 25 м, 500 м, 5 км або далі 5 км від об'єкта. Це допомагає картографам зрозуміти ваш контекст при внесенні змін, але дає уявлення про те, де ви були в цей час. " - }, - "scalebar": { - "mappings": { - "0": { - "then": "Показати масштабну лінійку" - }, - "1": { - "then": "Приховати лінійку масштабу" - } - }, - "question": "Чи потрібно показувати масштабну лінійку на карті?" - }, - "show_crosshair": { - "question": "Чи потрібно показувати перехрестя в центрі дисплея?", - "questionHint": "Це може допомогти точно позиціонувати новий об'єкт" - }, - "show_debug": { - "mappings": { - "0": { - "then": "Показати інформацію про налагодження" - }, - "2": { - "then": "Не показувати інформацію про налагодження" - } - }, - "question": "Показувати інформацію про налагодження налаштувань користувача?" - }, - "show_tags": { - "mappings": { - "0": { - "then": "Ніколи не показувати теги." - }, - "1": { - "then": "Показати теги, які будуть застосовані після того, як я зроблю {__userjourney_tagsVisibleAt} пакет правок" - }, - "2": { - "then": "Показати теги, які будуть застосовані при внесенні змін" - }, - "3": { - "then": "Показати теги, які будуть застосовані при внесенні змін, і показати таблицю тегів для кожного об'єкта" - } - }, - "question": "Показувати необроблені OpenStreetMap-теги?", - "questionHint": "Теги – це атрибути, які має кожен об'єкт. Це технічні дані, які зберігаються в базі даних. Вам не потрібна ця інформація для редагування за допомогою MapComplete, але досвідчені користувачі можуть використовувати її як довідку." - }, - "sync-visited-locations": { - "mappings": { - "0": { - "then": "Зберігайте місця, які ви шукаєте, переглядайте та синхронізуйте їх через openstreetmap.org. OpenStreetMap та всі програми, якими ви користуєтесь, можуть бачити цю історію" - }, - "1": { - "then": "Зберігайте місця, які ви шукаєте та перевіряєте, на моєму пристрої" - }, - "2": { - "then": "Не зберігайте місця, які ви шукаєте та перевіряєте " - } - }, - "question": "Чи варто запам'ятовувати місця, які ви шукаєте та оглядаєте?", - "questionHint": "Ці локації будуть запропоновані в меню пошуку" - }, - "sync-visited-themes": { - "mappings": { - "0": { - "then": "Зберігайте відвідані тематичні карти та синхронізуйте їх через openstreetmap.org. OpenStreetMap та всі програми, якими ви користуєтесь, можуть бачити цю історію" - }, - "1": { - "then": "Зберегти відвідані тематичні карти на моєму пристрої" - }, - "2": { - "then": "Не зберігайте відвідані тематичні мапи" - } - }, - "question": "Чи потрібно зберігати тематичні карти, які ви відвідуєте?", - "questionHint": "Якщо ви відвідуєте мапу на певну тему, MapComplete може запам'ятати це і запропонувати її як підказку." - }, - "title-editing": { - "render": "

Редагування налаштувань

" - }, - "title-id": { - "render": "

Керування ідентифікатором Mangrove

" - }, - "title-privacy-legal": { - "render": "

Приватність і законність

" - }, - "translation-completeness": { - "render": "Переклади {_theme} {_language} становлять {_translation_percentage}%: {_translation_translated_count} рядків із {_translation_total} перекладено" - }, - "translation-help": { - "mappings": { - "0": { - "then": "Натисніть на іконку \"перекласти\" поруч з рядком, щоб ввести або оновити фрагмент тексту. Для цього вам потрібен обліковий запис Weblate. Створіть його з вашим OSM-іменем користувача, щоб автоматично розблокувати режим перекладу." - } - } - }, - "translation-mode": { - "mappings": { - "0": { - "then": "Не показувати кнопку для швидкої зміни перекладу" - }, - "2": { - "then": "Завжди показуйте кнопки перекладу, в тому числі на мобільних пристроях" - } - }, - "question": "Ви хочете допомогти з перекладом MapComplete?" - } - }, - "title": { - "render": "Налаштування" - } - }, - "vending_machine": { - "tagRenderings": { - "operational_status": { - "mappings": { - "3": { - "then": "Операційний статус - {operational_status}" - } - } - } - } - }, - "waste_disposal": { - "tagRenderings": { - "disposal-location": { - "mappings": { - "1": { - "then": "Цей контейнер знаходиться в приміщенні" - }, - "2": { - "then": "Цей контейнер розташований на відкритому повітрі" - } } } } } -} +} \ No newline at end of file diff --git a/langs/layers/zgh.json b/langs/layers/zgh.json index 7b34b5c4d7..4f6fcb1993 100644 --- a/langs/layers/zgh.json +++ b/langs/layers/zgh.json @@ -6,4 +6,4 @@ "artwork": { "description": "ⵢⴰⵜ ⵜⴽⴰⵕⴹⴰ ⵉⵕⵥⵎⵏ ⵅⴼ ⵉⵙⴼⵔⵉⵙⵏ, ⵉⵖⵔⴰⵙⵏ ⴷ ⵜⵡⵓⵔⵉⵡⵉⵏ ⵜⵉⵏⴰⵥⵓⵕⵉⵏ ⵢⴰⴹⵏⵉⵏ ⴳ ⵓⵎⴰⴹⴰⵍ" } -} +} \ No newline at end of file diff --git a/langs/layers/zh_Hans.json b/langs/layers/zh_Hans.json index ab86f12eb8..bb86f5113c 100644 --- a/langs/layers/zh_Hans.json +++ b/langs/layers/zh_Hans.json @@ -686,4 +686,4 @@ } } } -} +} \ No newline at end of file diff --git a/langs/layers/zh_Hant.json b/langs/layers/zh_Hant.json index cb747c87e6..513e0c6c09 100644 --- a/langs/layers/zh_Hant.json +++ b/langs/layers/zh_Hant.json @@ -380,9 +380,6 @@ }, "2": { "then": "通行性僅限學校、公司或組織的成員" - }, - "3": { - "then": "通行性僅限學校、公司或組織的成員" } }, "question": "誰可以使用這個單車停車場?", @@ -1161,4 +1158,4 @@ "render": "風機" } } -} +} \ No newline at end of file diff --git a/langs/nl.json b/langs/nl.json index 551052bde1..ec591161f9 100644 --- a/langs/nl.json +++ b/langs/nl.json @@ -728,4 +728,4 @@ "description": "Een Wikidata-code" } } -} +} \ No newline at end of file diff --git a/langs/pl.json b/langs/pl.json index 43f0c90333..eaabe52bfb 100644 --- a/langs/pl.json +++ b/langs/pl.json @@ -668,4 +668,4 @@ "description": "Identyfikator Wikidanych" } } -} +} \ No newline at end of file diff --git a/langs/pt.json b/langs/pt.json index 6572135ae4..01d2beba7b 100644 --- a/langs/pt.json +++ b/langs/pt.json @@ -830,4 +830,4 @@ "startsWithQ": "Um identificador wikidata começa por Q e é seguido de um número" } } -} +} \ No newline at end of file diff --git a/langs/themes/ca.json b/langs/themes/ca.json index 36f9e2cce5..5be8957e08 100644 --- a/langs/themes/ca.json +++ b/langs/themes/ca.json @@ -1075,4 +1075,4 @@ "shortDescription": "Un mapa amb papereres", "title": "Papepera" } -} +} \ No newline at end of file diff --git a/langs/themes/cs.json b/langs/themes/cs.json index 78623aa7ff..64d803b61c 100644 --- a/langs/themes/cs.json +++ b/langs/themes/cs.json @@ -1413,4 +1413,4 @@ "shortDescription": "Mapa odpadkových košů", "title": "Odpadkové koše" } -} +} \ No newline at end of file diff --git a/langs/themes/da.json b/langs/themes/da.json index ec2a068e7d..f780a079f1 100644 --- a/langs/themes/da.json +++ b/langs/themes/da.json @@ -846,4 +846,4 @@ "shortDescription": "Et kort over skraldespande", "title": "Skraldespande" } -} +} \ No newline at end of file diff --git a/langs/themes/de.json b/langs/themes/de.json index 7ceb3419e8..92ea365483 100644 --- a/langs/themes/de.json +++ b/langs/themes/de.json @@ -1415,4 +1415,4 @@ "shortDescription": "Eine Karte mit Abfalleimern", "title": "Abfalleimer" } -} +} \ No newline at end of file diff --git a/langs/themes/en.json b/langs/themes/en.json index cc65dd6718..bbe70782a6 100644 --- a/langs/themes/en.json +++ b/langs/themes/en.json @@ -9,7 +9,7 @@ "title": "Defibrillators" }, "artwork": { - "description": "An open map of statues, busts, graffiti and other artworks all over the world", + "description": "An open map of statues, busts, graffitis and other artwork all over the world", "title": "Artwork" }, "atm": { @@ -1415,4 +1415,4 @@ "shortDescription": "A map with waste baskets", "title": "Waste Baskets" } -} +} \ No newline at end of file diff --git a/langs/themes/es.json b/langs/themes/es.json index ba2d80621b..3ff3860783 100644 --- a/langs/themes/es.json +++ b/langs/themes/es.json @@ -1368,4 +1368,4 @@ "shortDescription": "Un mapa con papeleras", "title": "Papeleras" } -} +} \ No newline at end of file diff --git a/langs/themes/eu.json b/langs/themes/eu.json index 0ff070ae62..3f9fad545e 100644 --- a/langs/themes/eu.json +++ b/langs/themes/eu.json @@ -216,4 +216,4 @@ "waste": { "title": "Hondakinak eta birziklapena" } -} +} \ No newline at end of file diff --git a/langs/themes/fr.json b/langs/themes/fr.json index 0680da154b..fdffc95311 100644 --- a/langs/themes/fr.json +++ b/langs/themes/fr.json @@ -1004,4 +1004,4 @@ "shortDescription": "Une carte des poubelles", "title": "Poubelles" } -} +} \ No newline at end of file diff --git a/langs/themes/hu.json b/langs/themes/hu.json index 0ed9ff4cb9..ffc4238bf2 100644 --- a/langs/themes/hu.json +++ b/langs/themes/hu.json @@ -530,4 +530,4 @@ "shortDescription": "Szemeteskosarakat ábrázoló térkép", "title": "Kukatérkép" } -} +} \ No newline at end of file diff --git a/langs/themes/id.json b/langs/themes/id.json index 4ca3265388..98d1b35479 100644 --- a/langs/themes/id.json +++ b/langs/themes/id.json @@ -90,4 +90,4 @@ "waste_basket": { "title": "Keranjang Sampah" } -} +} \ No newline at end of file diff --git a/langs/themes/it.json b/langs/themes/it.json index a5a8e35937..016494c805 100644 --- a/langs/themes/it.json +++ b/langs/themes/it.json @@ -674,4 +674,4 @@ "shortDescription": "Una cartina dei cestini dei rifiuti", "title": "Cestino dei rifiuti" } -} +} \ No newline at end of file diff --git a/langs/themes/nb_NO.json b/langs/themes/nb_NO.json index 894e96209e..70228236d0 100644 --- a/langs/themes/nb_NO.json +++ b/langs/themes/nb_NO.json @@ -582,4 +582,4 @@ "shortDescription": "Oversikt over søppelkurver", "title": "Søppelkurv" } -} +} \ No newline at end of file diff --git a/langs/themes/nl.json b/langs/themes/nl.json index 789dd4c40f..12a1b877dc 100644 --- a/langs/themes/nl.json +++ b/langs/themes/nl.json @@ -1149,4 +1149,4 @@ "shortDescription": "Een kaart met vuilnisbakken", "title": "Vuilnisbakken" } -} +} \ No newline at end of file diff --git a/langs/themes/pl.json b/langs/themes/pl.json index 9fd09501a4..347bf3fdd9 100644 --- a/langs/themes/pl.json +++ b/langs/themes/pl.json @@ -1035,4 +1035,4 @@ "shortDescription": "Mapa koszy na śmieci", "title": "Kosz na śmieci" } -} +} \ No newline at end of file diff --git a/langs/themes/pt.json b/langs/themes/pt.json index 3a08ba8180..f4e2e485a1 100644 --- a/langs/themes/pt.json +++ b/langs/themes/pt.json @@ -36,4 +36,4 @@ "description": "Mapeie todas as árvores!", "title": "Árvores" } -} +} \ No newline at end of file diff --git a/langs/themes/pt_BR.json b/langs/themes/pt_BR.json index 0538ac11f8..f731577585 100644 --- a/langs/themes/pt_BR.json +++ b/langs/themes/pt_BR.json @@ -41,4 +41,4 @@ "description": "Mapeie todas as árvores!", "title": "Árvores" } -} +} \ No newline at end of file diff --git a/langs/themes/uk.json b/langs/themes/uk.json index 73db15c21d..f9072856a3 100644 --- a/langs/themes/uk.json +++ b/langs/themes/uk.json @@ -277,209 +277,5 @@ } } } - }, - "cyclestreets": { - "shortDescription": "Карта велодоріжок", - "title": "Велодоріжки" - }, - "cyclofix": { - "description": "Карта, на якій велосипедисти можуть знайти відповідну інфраструктуру для своїх потреб, наприклад, велосипедні насоси, питну воду, веломагазини, ремонтні станції або парковки.", - "title": "Cyclofix - карта для велосипедистів" - }, - "disaster_response": { - "title": "Реагування на стихійні лиха та аварійні служби" - }, - "drinking_water": { - "title": "Питна вода" - }, - "education": { - "title": "Освіта" - }, - "etymology": { - "layers": { - "1": { - "override": { - "=name": "Вулиці без етимологічної інформації" - } - }, - "2": { - "override": { - "=name": "Парки та ліси без етимологічної інформації" - } - }, - "3": { - "override": { - "=name": "Навчальні заклади без етимологічної інформації" - } - }, - "4": { - "override": { - "=name": "Культурні місця без етимологічної інформації" - } - }, - "5": { - "override": { - "=name": "Туристичні місця без інформації про етимологію" - } - }, - "6": { - "override": { - "=name": "Медичні та соціальні заклади без етимологічної інформації" - } - }, - "7": { - "override": { - "=name": "Спортивні місця без етимологічної інформації" - } - } - }, - "shortDescription": "Звідки походить топонім?", - "title": "Етимологія - на честь чого названо місце?" - }, - "facadegardens": { - "shortDescription": "На цій карті показані фасадні сади з фотографіями та корисною інформацією про орієнтацію, сонячне освітлення та типи рослин.", - "title": "Фасадні сади" - }, - "fireplace": { - "title": "Вогнища та барбекю" - }, - "food": { - "title": "Ресторани та фаст-фуд" - }, - "fritures": { - "title": "Картопля фрі" - }, - "ghostbikes": { - "title": "Примарні велосипеди" - }, - "ghostsigns": { - "title": "Примарні знаки" - }, - "guideposts": { - "title": "Вказівники" - }, - "hackerspaces": { - "shortDescription": "Карта хакерських просторів", - "title": "Хакерспейси та мейкерспейси" - }, - "hailhydrant": { - "shortDescription": "Мапа, що показує гідранти, вогнегасники, пожежні станції та станції швидкої допомоги.", - "title": "Гідранти, вогнегасники, пожежні станції та станції швидкої допомоги" - }, - "healthcare": { - "title": "Охорона здоров'я" - }, - "hotels": { - "title": "Готелі" - }, - "icecream": { - "title": "Морозиво" - }, - "indoors": { - "title": "У приміщенні" - }, - "kerbs_and_crossings": { - "title": "Бордюри та переходи" - }, - "lactosefree": { - "title": "Магазини та ресторани без лактози" - }, - "lighthouses": { - "title": "Маяки" - }, - "maps": { - "shortDescription": "Ця тема показує всі (туристичні) мапи, які відомі OpenStreetMap", - "title": "Карта карт" - }, - "maxspeed": { - "shortDescription": "Ця карта показує дозволену законом максимальну швидкість на кожній дорозі.", - "title": "Максимальна швидкість" - }, - "memorials": { - "title": "Меморіали" - }, - "nature": { - "shortDescription": "Карта для любителів природи, з цікавими об'єктами POI", - "title": "На природі" - }, - "notes": { - "title": "Нотатки OpenStreetMap" - }, - "observation_towers": { - "shortDescription": "Загальнодоступні вежі, з яких можна насолоджуватися краєвидом", - "title": "Спостережні вежі" - }, - "onwheels": { - "title": "На колесах" - }, - "openwindpowermap": { - "title": "Вітрогенератори" - }, - "osm_community_index": { - "title": "Індекс спільноти OSM" - }, - "parkings": { - "shortDescription": "На цій карті показані різні місця для паркування", - "title": "Парковки" - }, - "personal": { - "title": "Особиста тема" - }, - "pets": { - "title": "Ветеринари, собачі парки та інші зручності для домашніх тварин" - }, - "playgrounds": { - "description": "На цій карті ви знайдете дитячі майданчики і зможете додати додаткову інформацію", - "shortDescription": "Карта з дитячими майданчиками", - "title": "Дитячі майданчики" - }, - "postboxes": { - "shortDescription": "Мапа з позначенням поштових скриньок та поштових відділень", - "title": "Поштові скриньки та карта поштових відділень" - }, - "rainbow_crossings": { - "title": "Веселкові пішохідні переходи" - }, - "shops": { - "shortDescription": "Редагована карта з основною інформацією про магазин", - "title": "Магазини" - }, - "ski": { - "title": "Гірськолижні траси та аеродроми" - }, - "sport_pitches": { - "shortDescription": "Карта з позначенням спортивних майданчиків", - "title": "Спортивні майданчики" - }, - "sports": { - "shortDescription": "Карта з позначенням спортивних об'єктів.", - "title": "Спорт" - }, - "street_lighting": { - "title": "Вуличне освітлення" - }, - "surveillance": { - "shortDescription": "Камери спостереження та інші засоби спостереження", - "title": "Нагляд під наглядом" - }, - "toilets": { - "title": "Громадські туалети" - }, - "transit": { - "title": "Автобусні маршрути" - }, - "trees": { - "shortDescription": "Нанесіть на карту всі дерева", - "title": "Дерева" - }, - "vending_machine": { - "title": "Торгові автомати" - }, - "waste": { - "title": "Відходи" - }, - "waste_basket": { - "shortDescription": "Мапа зі сміттєвими кошиками", - "title": "Кошики для сміття" } -} +} \ No newline at end of file diff --git a/langs/themes/zgh.json b/langs/themes/zgh.json index 81f94eda60..6bb8556981 100644 --- a/langs/themes/zgh.json +++ b/langs/themes/zgh.json @@ -30,4 +30,4 @@ } } } -} +} \ No newline at end of file diff --git a/langs/themes/zh_Hans.json b/langs/themes/zh_Hans.json index d0599e8cd9..0c6302b084 100644 --- a/langs/themes/zh_Hans.json +++ b/langs/themes/zh_Hans.json @@ -129,4 +129,4 @@ "campersite": { "description": "该网站汇总了所有官方的露营车停留点以及可以倾倒灰水和黑水的地点。你可以添加有关提供的服务和费用的详细信息,并且可以上传图片和撰写评论。" } -} +} \ No newline at end of file diff --git a/langs/themes/zh_Hant.json b/langs/themes/zh_Hant.json index 6643da7eb6..a76a102df0 100644 --- a/langs/themes/zh_Hant.json +++ b/langs/themes/zh_Hant.json @@ -491,4 +491,4 @@ "shortDescription": "垃圾筒的地圖", "title": "垃圾筒" } -} +} \ No newline at end of file diff --git a/langs/uk.json b/langs/uk.json index 5d5f1378cd..b063c6c321 100644 --- a/langs/uk.json +++ b/langs/uk.json @@ -257,4 +257,4 @@ "userinfo": { "gotoSettings": "Перейдіть до своїх налаштувань на OpenStreetMap.org" } -} +} \ No newline at end of file diff --git a/langs/zh_Hant.json b/langs/zh_Hant.json index c8a747652c..2027183fcc 100644 --- a/langs/zh_Hant.json +++ b/langs/zh_Hant.json @@ -848,4 +848,4 @@ "startsWithQ": "維基數據編號以 Q 開頭後面接數字" } } -} +} \ No newline at end of file diff --git a/scripts/ScriptUtils.ts b/scripts/ScriptUtils.ts index 7eb369a3a0..ac3a915bbf 100644 --- a/scripts/ScriptUtils.ts +++ b/scripts/ScriptUtils.ts @@ -2,7 +2,7 @@ import * as fs from "fs" import { existsSync, lstatSync, readdirSync, readFileSync } from "fs" import { Utils } from "../src/Utils" import { https } from "follow-redirects" -import { LayoutConfigJson } from "../src/Models/ThemeConfig/Json/LayoutConfigJson" +import { ThemeConfigJson } from "../src/Models/ThemeConfig/Json/ThemeConfigJson" import { LayerConfigJson } from "../src/Models/ThemeConfig/Json/LayerConfigJson" import xml2js from "xml2js" @@ -111,7 +111,7 @@ export default class ScriptUtils { } public static getThemeFiles(useTranslationPaths = false): { - parsed: LayoutConfigJson; + parsed: ThemeConfigJson; path: string; raw: string }[] { diff --git a/scripts/generateDocs.ts b/scripts/generateDocs.ts index c06a3c449d..ab6ccc6802 100644 --- a/scripts/generateDocs.ts +++ b/scripts/generateDocs.ts @@ -8,7 +8,7 @@ import QueryParameterDocumentation from "../src/UI/QueryParameterDocumentation" import ScriptUtils from "./ScriptUtils" import Translations from "../src/UI/i18n/Translations" import themeOverview from "../src/assets/generated/theme_overview.json" -import LayoutConfig from "../src/Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../src/Models/ThemeConfig/ThemeConfig" import bookcases from "../src/assets/generated/themes/bookcases.json" import fakedom from "fake-dom" import unit from "../src/assets/generated/layers/unit.json" @@ -253,7 +253,7 @@ export class GenerateDocs extends Script { } private generateHotkeyDocs() { - new ThemeViewState(new LayoutConfig(bookcases), new Set()) + new ThemeViewState(new ThemeConfig(bookcases), new Set()) this.WriteMarkdownFile("./Docs/Hotkeys.md", Hotkeys.generateDocumentation(), [ "src/UI/Base/Hotkeys.ts", ]) @@ -455,7 +455,7 @@ export class GenerateDocs extends Script { ) } - private generateForTheme(theme: LayoutConfig): void { + private generateForTheme(theme: ThemeConfig): void { const allLayers = AllSharedLayers.getSharedLayersConfigs() const layersToShow = theme.layers.filter( (l) => diff --git a/scripts/generateLayerOverview.ts b/scripts/generateLayerOverview.ts index 3924ec5604..61301eeeb9 100644 --- a/scripts/generateLayerOverview.ts +++ b/scripts/generateLayerOverview.ts @@ -1,7 +1,7 @@ import ScriptUtils from "./ScriptUtils" import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs" import licenses from "../src/assets/generated/license_info.json" -import { LayoutConfigJson } from "../src/Models/ThemeConfig/Json/LayoutConfigJson" +import { ThemeConfigJson } from "../src/Models/ThemeConfig/Json/ThemeConfigJson" import { LayerConfigJson } from "../src/Models/ThemeConfig/Json/LayerConfigJson" import Constants from "../src/Models/Constants" import { @@ -29,7 +29,7 @@ import LayerConfig from "../src/Models/ThemeConfig/LayerConfig" import PointRenderingConfig from "../src/Models/ThemeConfig/PointRenderingConfig" import { ConversionContext } from "../src/Models/ThemeConfig/Conversion/ConversionContext" import { GenerateFavouritesLayer } from "./generateFavouritesLayer" -import LayoutConfig, { MinimalLayoutInformation } from "../src/Models/ThemeConfig/LayoutConfig" +import ThemeConfig, { MinimalThemeInformation } from "../src/Models/ThemeConfig/ThemeConfig" import Translations from "../src/UI/i18n/Translations" import { Translatable } from "../src/Models/ThemeConfig/Json/Translatable" import { ValidateThemeAndLayers } from "../src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers" @@ -148,14 +148,14 @@ class LayerOverviewUtils extends Script { super("Reviews and generates the compiled themes") } - private static publicLayerIdsFrom(themefiles: LayoutConfigJson[]): Set { + private static publicLayerIdsFrom(themefiles: ThemeConfigJson[]): Set { const publicThemes = [].concat(...themefiles.filter((th) => !th.hideFromOverview)) return new Set([].concat(...publicThemes.map((th) => this.extractLayerIdsFrom(th)))) } private static extractLayerIdsFrom( - themeFile: LayoutConfigJson, + themeFile: ThemeConfigJson, includeInlineLayers = true, ): string[] { const publicLayerIds: string[] = [] @@ -295,7 +295,7 @@ class LayerOverviewUtils extends Script { layerKeywords[id] = this.layerKeywords(layer) }) - const perId = new Map() + const perId = new Map() for (const theme of themes) { const keywords: Record = {} @@ -308,7 +308,7 @@ class LayerOverviewUtils extends Script { } - const data = { + const data = { id: theme.id, title: theme.title, shortDescription: LayerOverviewUtils.cleanTranslation(theme.shortDescription), @@ -342,7 +342,7 @@ class LayerOverviewUtils extends Script { ) } - writeTheme(theme: LayoutConfigJson) { + writeTheme(theme: ThemeConfigJson) { if (!existsSync(LayerOverviewUtils.themePath)) { mkdirSync(LayerOverviewUtils.themePath) } @@ -519,7 +519,7 @@ class LayerOverviewUtils extends Script { ) new ValidateThemeEnsemble().convertStrict( - Array.from(sharedThemes.values()).map((th) => new LayoutConfig(th, true)), + Array.from(sharedThemes.values()).map((th) => new ThemeConfig(th, true)), ) if (recompiledThemes.length > 0) { @@ -545,7 +545,7 @@ class LayerOverviewUtils extends Script { if: "theme=" + th.id, then: th.icon, })) - const proto: LayoutConfigJson = JSON.parse( + const proto: ThemeConfigJson = JSON.parse( readFileSync("./assets/themes/mapcomplete-changes/mapcomplete-changes.proto.json", { encoding: "utf8", }), @@ -689,7 +689,7 @@ class LayerOverviewUtils extends Script { * @param themeFile * @private */ - private extractJavascriptCode(themeFile: LayoutConfigJson) { + private extractJavascriptCode(themeFile: ThemeConfigJson) { const allCode = [ "import {Feature} from 'geojson'", "import { ExtraFuncType } from \"../../../Logic/ExtraFunctions\";", @@ -804,10 +804,10 @@ class LayerOverviewUtils extends Script { recompiledThemes: string[], forceReload: boolean, whitelist: Set, - ): Map { + ): Map { console.log(" ---------- VALIDATING BUILTIN THEMES ---------") const themeFiles = ScriptUtils.getThemeFiles() - const fixed = new Map() + const fixed = new Map() const publicLayers = LayerOverviewUtils.publicLayerIdsFrom( themeFiles.map((th) => th.parsed), diff --git a/scripts/generateLayouts.ts b/scripts/generateLayouts.ts index fb57fc7606..4066360bc2 100644 --- a/scripts/generateLayouts.ts +++ b/scripts/generateLayouts.ts @@ -3,8 +3,8 @@ import Locale from "../src/UI/i18n/Locale" import Translations from "../src/UI/i18n/Translations" import { Translation } from "../src/UI/i18n/Translation" import all_known_layouts from "../src/assets/generated/known_themes.json" -import { LayoutConfigJson } from "../src/Models/ThemeConfig/Json/LayoutConfigJson" -import LayoutConfig from "../src/Models/ThemeConfig/LayoutConfig" +import { ThemeConfigJson } from "../src/Models/ThemeConfig/Json/ThemeConfigJson" +import ThemeConfig from "../src/Models/ThemeConfig/ThemeConfig" import xml2js from "xml2js" import ScriptUtils from "./ScriptUtils" import { Utils } from "../src/Utils" @@ -100,7 +100,7 @@ class GenerateLayouts extends Script { return newname } - async createSocialImage(layout: LayoutConfig, template: "" | "Wide"): Promise { + async createSocialImage(layout: ThemeConfig, template: "" | "Wide"): Promise { if (!layout.icon.endsWith(".svg")) { console.warn( "Not creating a social image for " + @@ -160,7 +160,7 @@ class GenerateLayouts extends Script { } async createManifest( - layout: LayoutConfig, + layout: ThemeConfig, alreadyWritten: string[] ): Promise<{ manifest: any @@ -319,8 +319,8 @@ class GenerateLayouts extends Script { } async generateCsp( - layout: LayoutConfig, - layoutJson: LayoutConfigJson, + layout: ThemeConfig, + layoutJson: ThemeConfigJson, options: { scriptSrcs: string[] } @@ -441,8 +441,8 @@ class GenerateLayouts extends Script { } async createLandingPage( - layout: LayoutConfig, - layoutJson: LayoutConfigJson, + layout: ThemeConfig, + layoutJson: ThemeConfigJson, whiteIcons, alreadyWritten ) { @@ -456,7 +456,7 @@ class GenerateLayouts extends Script { .replace(/"/g, '\\"') let ogImage = layout.socialImage let twitterImage = ogImage - if (ogImage === LayoutConfig.defaultSocialImage && layout.official) { + if (ogImage === ThemeConfig.defaultSocialImage && layout.official) { try { ogImage = (await this.createSocialImage(layout, "")) ?? layout.socialImage twitterImage = (await this.createSocialImage(layout, "Wide")) ?? layout.socialImage @@ -573,7 +573,7 @@ class GenerateLayouts extends Script { ) } - async createIndexFor(theme: LayoutConfig) { + async createIndexFor(theme: ThemeConfig) { const filename = "index_" + theme.id + ".ts" const imports = [ @@ -628,18 +628,18 @@ class GenerateLayouts extends Script { "theme", ] // @ts-ignore - const all: LayoutConfigJson[] = all_known_layouts.themes + const all: ThemeConfigJson[] = all_known_layouts.themes const args = process.argv const theme = args[2] if (theme !== undefined) { console.warn("Only generating layout " + theme) } for (const i in all) { - const layoutConfigJson: LayoutConfigJson = all[i] + const layoutConfigJson: ThemeConfigJson = all[i] if (theme !== undefined && layoutConfigJson.id !== theme) { continue } - const layout = new LayoutConfig(layoutConfigJson, true) + const layout = new ThemeConfig(layoutConfigJson, true) const layoutName = layout.id if (blacklist.indexOf(layoutName.toLowerCase()) >= 0) { console.log(`Skipping a layout with name ${layoutName}, it is on the blacklist`) @@ -668,7 +668,7 @@ class GenerateLayouts extends Script { } const { manifest } = await this.createManifest( - new LayoutConfig({ + new ThemeConfig({ icon: "./assets/svg/mapcomplete_logo.svg", id: "index", layers: [], diff --git a/scripts/generateTaginfoProjectFiles.ts b/scripts/generateTaginfoProjectFiles.ts index e5ebe88829..ce6cad2c6e 100644 --- a/scripts/generateTaginfoProjectFiles.ts +++ b/scripts/generateTaginfoProjectFiles.ts @@ -2,7 +2,7 @@ import { AllKnownLayouts } from "../src/Customizations/AllKnownLayouts" import Locale from "../src/UI/i18n/Locale" import { Translation } from "../src/UI/i18n/Translation" import { readFileSync, writeFileSync } from "fs" -import LayoutConfig from "../src/Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../src/Models/ThemeConfig/ThemeConfig" import LayerConfig from "../src/Models/ThemeConfig/LayerConfig" import { Utils } from "../src/Utils" @@ -33,7 +33,7 @@ function generateTagOverview( return overview } -function generateLayerUsage(layer: LayerConfig, layout: LayoutConfig): any[] { +function generateLayerUsage(layer: LayerConfig, layout: ThemeConfig): any[] { if (layer.name === undefined) { return [] // Probably a duplicate or irrelevant layer } @@ -124,7 +124,7 @@ function generateLayerUsage(layer: LayerConfig, layout: LayoutConfig): any[] { * Generates the JSON-object representing the theme for inclusion on taginfo * @param layout */ -function generateTagInfoEntry(layout: LayoutConfig): any { +function generateTagInfoEntry(layout: ThemeConfig): any { const usedTags = [] for (const layer of layout.layers) { if (layer.source === null) { diff --git a/scripts/handleErrors.ts b/scripts/handleErrors.ts index 8247e11755..ae5a437966 100644 --- a/scripts/handleErrors.ts +++ b/scripts/handleErrors.ts @@ -15,7 +15,7 @@ type ErrorMessage = { message: { stacktrace: string message: string - layout: string + theme: string version: string language: string username: string @@ -40,7 +40,7 @@ class HandleErrors extends Script { ) { console.log( parsed.message.username, - parsed.message.layout, + parsed.message.theme, parsed.message.message, parsed.date ) @@ -82,7 +82,7 @@ class HandleErrors extends Script { } = changesObj.CreateChangesetObjects(toUpload, objects, true) const changeset = Changes.buildChangesetXML("", changes) - const path = "error_changeset_" + parsed.index + "_" + e.layout + "_" + e.username + ".osc" + const path = "error_changeset_" + parsed.index + "_" + e.theme + "_" + e.username + ".osc" if ( changeset === `` diff --git a/src/Customizations/AllKnownLayouts.ts b/src/Customizations/AllKnownLayouts.ts index 5882b3135f..c4004e2dad 100644 --- a/src/Customizations/AllKnownLayouts.ts +++ b/src/Customizations/AllKnownLayouts.ts @@ -1,7 +1,7 @@ import known_themes from "../assets/generated/known_themes.json" -import LayoutConfig from "../Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../Models/ThemeConfig/ThemeConfig" import favourite from "../assets/generated/layers/favourite.json" -import { LayoutConfigJson } from "../Models/ThemeConfig/Json/LayoutConfigJson" +import { ThemeConfigJson } from "../Models/ThemeConfig/Json/ThemeConfigJson" import { AllSharedLayers } from "./AllSharedLayers" import Constants from "../Models/Constants" @@ -9,8 +9,8 @@ import Constants from "../Models/Constants" * Somewhat of a dictionary, which lazily parses needed themes */ export class AllKnownLayoutsLazy { - private readonly raw: Map = new Map() - private readonly dict: Map = new Map() + private readonly raw: Map = new Map() + private readonly dict: Map = new Map() constructor(includeFavouriteLayer = true) { for (const layoutConfigJson of known_themes["themes"]) { @@ -32,7 +32,7 @@ export class AllKnownLayoutsLazy { } } - public getConfig(key: string): LayoutConfigJson { + public getConfig(key: string): ThemeConfigJson { return this.raw.get(key) } @@ -40,13 +40,13 @@ export class AllKnownLayoutsLazy { return this.raw.size } - public get(key: string): LayoutConfig { + public get(key: string): ThemeConfig { const cached = this.dict.get(key) if (cached !== undefined) { return cached } - const layout = new LayoutConfig(this.getConfig(key)) + const layout = new ThemeConfig(this.getConfig(key)) this.dict.set(key, layout) return layout } diff --git a/src/Logic/Actors/InitialMapPositioning.ts b/src/Logic/Actors/InitialMapPositioning.ts index f62a11fd88..d61ab3803d 100644 --- a/src/Logic/Actors/InitialMapPositioning.ts +++ b/src/Logic/Actors/InitialMapPositioning.ts @@ -1,5 +1,5 @@ import { ImmutableStore, Store, UIEventSource } from "../UIEventSource" -import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig" import { LocalStorageSource } from "../Web/LocalStorageSource" import { QueryParameters } from "../Web/QueryParameters" import Hash from "../Web/Hash" @@ -25,7 +25,7 @@ export default class InitialMapPositioning { public location: UIEventSource<{ lon: number; lat: number }> public useTerrain: Store - constructor(layoutToUse: LayoutConfig, geolocationState: GeoLocationState) { + constructor(layoutToUse: ThemeConfig, geolocationState: GeoLocationState) { function localStorageSynced( key: string, deflt: number, diff --git a/src/Logic/Actors/NoElementsInViewDetector.ts b/src/Logic/Actors/NoElementsInViewDetector.ts index bc5148335a..46e24e494b 100644 --- a/src/Logic/Actors/NoElementsInViewDetector.ts +++ b/src/Logic/Actors/NoElementsInViewDetector.ts @@ -14,7 +14,7 @@ export default class NoElementsInViewDetector { constructor(themeViewState: ThemeViewState) { const state = themeViewState const minZoom = Math.min( - ...themeViewState.layout.layers + ...themeViewState.theme.layers .filter((l) => Constants.priviliged_layers.indexOf(l.id) < 0) .map((l) => l.minzoom) ) @@ -43,7 +43,7 @@ export default class NoElementsInViewDetector { // Nope, no data loaded continue } - const layer = themeViewState.layout.getLayer(layerName) + const layer = themeViewState.theme.getLayer(layerName) if (mapProperties.zoom.data < layer.minzoom) { minzoomWithData = Math.min(layer.minzoom) continue @@ -67,7 +67,7 @@ export default class NoElementsInViewDetector { continue } - const layer = themeViewState.layout.getLayer(layerName) + const layer = themeViewState.theme.getLayer(layerName) if (mapProperties.zoom.data < layer.minzoom) { continue } diff --git a/src/Logic/Actors/SelectedElementTagsUpdater.ts b/src/Logic/Actors/SelectedElementTagsUpdater.ts index 9472d29b31..218b665e70 100644 --- a/src/Logic/Actors/SelectedElementTagsUpdater.ts +++ b/src/Logic/Actors/SelectedElementTagsUpdater.ts @@ -34,7 +34,7 @@ export default class SelectedElementTagsUpdater { public static applyUpdate(latestTags: OsmTags, id: string, state: SpecialVisualizationState) { try { - const leftRightSensitive = state.layout.isLeftRightSensitive() + const leftRightSensitive = state.theme.isLeftRightSensitive() if (leftRightSensitive) { SimpleMetaTagger.removeBothTagging(latestTags) @@ -111,7 +111,7 @@ export default class SelectedElementTagsUpdater { } private invalidateCache(s: Feature) { const state = this.state - const wasPartOfLayer = state.layout.getMatchingLayer(s.properties) + const wasPartOfLayer = state.theme.getMatchingLayer(s.properties) state.toCacheSavers?.get(wasPartOfLayer.id)?.invalidateCacheAround(BBox.get(s)) } private installCallback() { diff --git a/src/Logic/Actors/TitleHandler.ts b/src/Logic/Actors/TitleHandler.ts index aa26c61e28..387aab8988 100644 --- a/src/Logic/Actors/TitleHandler.ts +++ b/src/Logic/Actors/TitleHandler.ts @@ -12,11 +12,11 @@ export default class TitleHandler { const currentTitle: Store = selectedElement.map( (selected) => { const lng = Locale.language.data - const defaultTitle = state.layout?.title?.textFor(lng) ?? "MapComplete" + const defaultTitle = state.theme?.title?.textFor(lng) ?? "MapComplete" if (selected === undefined) { return defaultTitle } - const layer = state.layout.getMatchingLayer(selected.properties) + const layer = state.theme.getMatchingLayer(selected.properties) if (layer === undefined) { return defaultTitle } diff --git a/src/Logic/DetermineLayout.ts b/src/Logic/DetermineTheme.ts similarity index 65% rename from src/Logic/DetermineLayout.ts rename to src/Logic/DetermineTheme.ts index 9a4e5f4e29..0fe9b5906a 100644 --- a/src/Logic/DetermineLayout.ts +++ b/src/Logic/DetermineTheme.ts @@ -1,10 +1,8 @@ -import LayoutConfig from "../Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../Models/ThemeConfig/ThemeConfig" import { QueryParameters } from "./Web/QueryParameters" import { AllKnownLayouts } from "../Customizations/AllKnownLayouts" import { FixedUiElement } from "../UI/Base/FixedUiElement" import { Utils } from "../Utils" -import { UIEventSource } from "./UIEventSource" -import { LocalStorageSource } from "./Web/LocalStorageSource" import LZString from "lz-string" import { FixLegacyTheme } from "../Models/ThemeConfig/Conversion/LegacyJsonConvert" import { LayerConfigJson } from "../Models/ThemeConfig/Json/LayerConfigJson" @@ -19,42 +17,30 @@ import { DesugaringContext } from "../Models/ThemeConfig/Conversion/Conversion" import { TagRenderingConfigJson } from "../Models/ThemeConfig/Json/TagRenderingConfigJson" import Hash from "./Web/Hash" import { QuestionableTagRenderingConfigJson } from "../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson" -import { LayoutConfigJson } from "../Models/ThemeConfig/Json/LayoutConfigJson" +import { ThemeConfigJson } from "../Models/ThemeConfig/Json/ThemeConfigJson" import { ValidateThemeAndLayers } from "../Models/ThemeConfig/Conversion/ValidateThemeAndLayers" -export default class DetermineLayout { +export default class DetermineTheme { private static readonly _knownImages = new Set(Array.from(licenses).map((l) => l.path)) private static readonly loadCustomThemeParam = QueryParameters.GetQueryParameter( "userlayout", "false", - "If not 'false', a custom (non-official) theme is loaded. This custom layout can be done in multiple ways: \n\n- The hash of the URL contains a base64-encoded .json-file containing the theme definition\n- The hash of the URL contains a lz-compressed .json-file, as generated by the custom theme generator\n- The parameter itself is an URL, in which case that URL will be downloaded. It should point to a .json of a theme" + "If the parameter is an URL, it should point to a .json of a theme which will be loaded and used" ) public static getCustomDefinition(): string { - const layoutFromBase64 = decodeURIComponent(DetermineLayout.loadCustomThemeParam.data) + const layoutFromBase64 = decodeURIComponent(DetermineTheme.loadCustomThemeParam.data) if (layoutFromBase64.startsWith("http")) { return layoutFromBase64 } - if (layoutFromBase64 !== "false") { - // We have to load something from the hash (or from disk) - const hash = Hash.hash.data - try { - JSON.parse(atob(hash)) - return atob(hash) - } catch (e) { - // We try to decode with lz-string - JSON.parse(Utils.UnMinify(LZString.decompressFromBase64(hash))) - return Utils.UnMinify(LZString.decompressFromBase64(hash)) - } - } return undefined } private static async expandRemoteLayers( - layoutConfig: LayoutConfigJson - ): Promise { + layoutConfig: ThemeConfigJson + ): Promise { if (!layoutConfig.layers) { // This is probably a layer in 'layer-only-mode' return layoutConfig @@ -67,8 +53,7 @@ export default class DetermineLayout { try { new URL(l) console.log("Downloading remote layer " + l) - const layerConfig = await Utils.downloadJson(l) - layoutConfig.layers[i] = layerConfig + layoutConfig.layers[i] = await Utils.downloadJson(l) } catch (_) { continue } @@ -79,16 +64,11 @@ export default class DetermineLayout { /** * Gets the correct layout for this website */ - public static async GetLayout(): Promise { - const layoutFromBase64 = decodeURIComponent(DetermineLayout.loadCustomThemeParam.data) + public static async getTheme(): Promise { + const layoutFromBase64 = decodeURIComponent(DetermineTheme.loadCustomThemeParam.data) if (layoutFromBase64.startsWith("http")) { - return await DetermineLayout.LoadRemoteTheme(layoutFromBase64) - } - - if (layoutFromBase64 !== "false") { - // We have to load something from the hash (or from disk) - return await DetermineLayout.LoadLayoutFromHash(DetermineLayout.loadCustomThemeParam) + return await DetermineTheme.LoadRemoteTheme(layoutFromBase64) } let layoutId: string = undefined @@ -125,48 +105,11 @@ export default class DetermineLayout { return layouts.get(id) } - public static async LoadLayoutFromHash( - userLayoutParam: UIEventSource - ): Promise { - let hash = location.hash.substr(1) - let json: any - - // layoutFromBase64 contains the name of the theme. This is partly to do tracking with goat counter - const dedicatedHashFromLocalStorage = LocalStorageSource.get( - "user-layout-" + userLayoutParam.data?.replace(" ", "_") - ) - if (dedicatedHashFromLocalStorage.data?.length < 10) { - dedicatedHashFromLocalStorage.setData(undefined) - } - - const hashFromLocalStorage = LocalStorageSource.get("last-loaded-user-layout") - if (hash.length < 10) { - hash = dedicatedHashFromLocalStorage.data ?? hashFromLocalStorage.data - } else { - console.log("Saving hash to local storage") - hashFromLocalStorage.setData(hash) - dedicatedHashFromLocalStorage.setData(hash) - } - - try { - json = JSON.parse(atob(hash)) - } catch (e) { - // We try to decode with lz-string - json = JSON.parse(Utils.UnMinify(LZString.decompressFromBase64(hash))) - } - - json = await this.expandRemoteLayers(json) - - const layoutToUse = DetermineLayout.prepCustomTheme(json) - userLayoutParam.setData(layoutToUse.id) - return layoutToUse - } - private static getSharedTagRenderings(): Map { const dict = new Map() for (const tagRendering of questions.tagRenderings) { - dict.set(tagRendering.id, tagRendering) + dict.set(tagRendering.id, tagRendering) } return dict @@ -176,7 +119,7 @@ export default class DetermineLayout { return questions.tagRenderings.map((tr) => tr.id) } - private static prepCustomTheme(json: any, sourceUrl?: string, forceId?: string): LayoutConfig { + private static prepCustomTheme(json: any, sourceUrl?: string, forceId?: string): ThemeConfig { if (json.layers === undefined && json.tagRenderings !== undefined) { // We got fed a layer instead of a theme const layerConfig = json @@ -224,15 +167,15 @@ export default class DetermineLayout { knownLayersDict.set(layer.id, layer) } const convertState: DesugaringContext = { - tagRenderings: DetermineLayout.getSharedTagRenderings(), - tagRenderingOrder: DetermineLayout.getSharedTagRenderingOrder(), + tagRenderings: DetermineTheme.getSharedTagRenderings(), + tagRenderingOrder: DetermineTheme.getSharedTagRenderingOrder(), sharedLayers: knownLayersDict, publicLayers: new Set(), } json = new FixLegacyTheme().convertStrict(json) const raw = json - json = new FixImages(DetermineLayout._knownImages).convertStrict(json) + json = new FixImages(DetermineTheme._knownImages).convertStrict(json) json.enableNoteImports = json.enableNoteImports ?? false json = new PrepareTheme(convertState).convertStrict(json) console.log("The layoutconfig is ", json) @@ -249,20 +192,20 @@ export default class DetermineLayout { false ).convertStrict(json) } - return new LayoutConfig(json, false, { + return new ThemeConfig(json, false, { definitionRaw: JSON.stringify(raw, null, " "), definedAtUrl: sourceUrl, }) } - private static async LoadRemoteTheme(link: string): Promise { + private static async LoadRemoteTheme(link: string): Promise { console.log("Downloading map theme from ", link) new FixedUiElement(`Downloading the theme from the link...`).AttachTo( "maindiv" ) - let parsed = await Utils.downloadJson(link) + let parsed = await Utils.downloadJson(link) let forcedId = parsed.id const url = new URL(link) if (!(url.hostname === "localhost" || url.hostname === "127.0.0.1")) { @@ -270,6 +213,6 @@ export default class DetermineLayout { } console.log("Loaded remote link:", link) parsed = await this.expandRemoteLayers(parsed) - return DetermineLayout.prepCustomTheme(parsed, link, forcedId) + return DetermineTheme.prepCustomTheme(parsed, link, forcedId) } } diff --git a/src/Logic/FeatureSource/Sources/FavouritesFeatureSource.ts b/src/Logic/FeatureSource/Sources/FavouritesFeatureSource.ts index 595c1def3b..5c48ac7907 100644 --- a/src/Logic/FeatureSource/Sources/FavouritesFeatureSource.ts +++ b/src/Logic/FeatureSource/Sources/FavouritesFeatureSource.ts @@ -49,7 +49,7 @@ export default class FavouritesFeatureSource extends StaticFeatureSource { const featuresWithoutAlreadyPresent = features.map((features) => features.filter( - (feat) => !state.layout.layers.some((l) => l.id === feat.properties._orig_layer) + (feat) => !state.theme.layers.some((l) => l.id === feat.properties._orig_layer) ) ) diff --git a/src/Logic/FeatureSource/Sources/LastClickFeatureSource.ts b/src/Logic/FeatureSource/Sources/LastClickFeatureSource.ts index 830d203332..46b4fbb563 100644 --- a/src/Logic/FeatureSource/Sources/LastClickFeatureSource.ts +++ b/src/Logic/FeatureSource/Sources/LastClickFeatureSource.ts @@ -1,4 +1,4 @@ -import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig" import { ImmutableStore, Store, UIEventSource } from "../../UIEventSource" import { Feature, Point } from "geojson" import { TagUtils } from "../../Tags/TagUtils" @@ -22,7 +22,7 @@ export class LastClickFeatureSource implements FeatureSource { private _usermode: UIEventSource private _enabledAddMorePoints: UIEventSource constructor( - layout: LayoutConfig, + layout: ThemeConfig, clickSource: Store<{ lon: number; lat: number; mode: "left" | "right" | "middle" }>, usermode?: UIEventSource, enabledAddMorePoints?: UIEventSource diff --git a/src/Logic/FeatureSource/Sources/LayoutSource.ts b/src/Logic/FeatureSource/Sources/ThemeSource.ts similarity index 93% rename from src/Logic/FeatureSource/Sources/LayoutSource.ts rename to src/Logic/FeatureSource/Sources/ThemeSource.ts index 196f926fcd..9c7b5008c9 100644 --- a/src/Logic/FeatureSource/Sources/LayoutSource.ts +++ b/src/Logic/FeatureSource/Sources/ThemeSource.ts @@ -18,7 +18,7 @@ import FeatureSourceMerger from "./FeatureSourceMerger" * * Note that special layers (with `source=null` will be ignored) */ -export default class LayoutSource extends FeatureSourceMerger { +export default class ThemeSource extends FeatureSourceMerger { /** * Indicates if a data source is loading something */ @@ -51,7 +51,7 @@ export default class LayoutSource extends FeatureSourceMerger { const src = new LocalStorageFeatureSource( backend, layer, - LayoutSource.fromCacheZoomLevel, + ThemeSource.fromCacheZoomLevel, mapProperties, { isActive: isDisplayed(layer.id), @@ -63,13 +63,13 @@ export default class LayoutSource extends FeatureSourceMerger { } const mvtSources: UpdatableFeatureSource[] = osmLayers .filter((f) => mvtAvailableLayers.has(f.id)) - .map((l) => LayoutSource.setupMvtSource(l, mapProperties, isDisplayed(l.id))) + .map((l) => ThemeSource.setupMvtSource(l, mapProperties, isDisplayed(l.id))) const nonMvtSources = [] const nonMvtLayers = osmLayers.filter((l) => !mvtAvailableLayers.has(l.id)) const isLoading = new UIEventSource(false) - const osmApiSource = LayoutSource.setupOsmApiSource( + const osmApiSource = ThemeSource.setupOsmApiSource( osmLayers, bounds, zoom, @@ -86,7 +86,7 @@ export default class LayoutSource extends FeatureSourceMerger { nonMvtLayers.map((l) => l.id), " cannot be fetched from the cache server, defaulting to overpass/OSM-api" ) - overpassSource = LayoutSource.setupOverpass(osmLayers, bounds, zoom, featureSwitches) + overpassSource = ThemeSource.setupOverpass(osmLayers, bounds, zoom, featureSwitches) nonMvtSources.push(overpassSource) supportsForceDownload.push(overpassSource) } @@ -100,7 +100,7 @@ export default class LayoutSource extends FeatureSourceMerger { osmApiSource?.isRunning?.addCallbackAndRun(() => setIsLoading()) const geojsonSources: UpdatableFeatureSource[] = geojsonlayers.map((l) => - LayoutSource.setupGeojsonSource(l, mapProperties, isDisplayed(l.id)) + ThemeSource.setupGeojsonSource(l, mapProperties, isDisplayed(l.id)) ) super(...geojsonSources, ...Array.from(fromCache.values()), ...mvtSources, ...nonMvtSources) @@ -198,7 +198,7 @@ export default class LayoutSource extends FeatureSourceMerger { zoom, bounds, layers: osmLayers, - widenFactor: featureSwitches.layoutToUse.widenFactor, + widenFactor: 1.5, overpassUrl: featureSwitches.overpassUrl, overpassTimeout: featureSwitches.overpassTimeout, overpassMaxZoom: featureSwitches.overpassMaxZoom, diff --git a/src/Logic/ImageProviders/ImageUploadManager.ts b/src/Logic/ImageProviders/ImageUploadManager.ts index ed4ba8b505..0f0ac1a9df 100644 --- a/src/Logic/ImageProviders/ImageUploadManager.ts +++ b/src/Logic/ImageProviders/ImageUploadManager.ts @@ -2,7 +2,7 @@ import { ImageUploader, UploadResult } from "./ImageUploader" import LinkImageAction from "../Osm/Actions/LinkImageAction" import FeaturePropertiesStore from "../FeatureSource/Actors/FeaturePropertiesStore" import { OsmId, OsmTags } from "../../Models/OsmFeature" -import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig" import { Store, UIEventSource } from "../UIEventSource" import { OsmConnection } from "../Osm/OsmConnection" import { Changes } from "../Osm/Changes" @@ -17,7 +17,7 @@ import { GeoOperations } from "../GeoOperations" export class ImageUploadManager { private readonly _uploader: ImageUploader private readonly _featureProperties: FeaturePropertiesStore - private readonly _layout: LayoutConfig + private readonly _theme: ThemeConfig private readonly _indexedFeatures: IndexedFeatureSource private readonly _gps: Store private readonly _uploadStarted: Map> = new Map() @@ -31,7 +31,7 @@ export class ImageUploadManager { private readonly _reportError: (message: (string | Error | XMLHttpRequest), extramessage?: string) => Promise constructor( - layout: LayoutConfig, + layout: ThemeConfig, uploader: ImageUploader, featureProperties: FeaturePropertiesStore, osmConnection: OsmConnection, @@ -42,7 +42,7 @@ export class ImageUploadManager { ) { this._uploader = uploader this._featureProperties = featureProperties - this._layout = layout + this._theme = layout this._osmConnection = osmConnection this._changes = changes this._indexedFeatures = allFeatures @@ -131,7 +131,7 @@ export class ImageUploadManager { const properties = this._featureProperties.getStore(featureId) const action = new LinkImageAction(featureId, uploadResult. key, uploadResult . value, properties, { - theme: tags?.data?.["_orig_theme"] ?? this._layout.id, + theme: tags?.data?.["_orig_theme"] ?? this._theme.id, changeType: "add-image", }) diff --git a/src/Logic/MetaTagging.ts b/src/Logic/MetaTagging.ts index 3e5a239a05..b93acc30bb 100644 --- a/src/Logic/MetaTagging.ts +++ b/src/Logic/MetaTagging.ts @@ -3,7 +3,7 @@ import { ExtraFuncParams, ExtraFunctions, ExtraFuncType } from "./ExtraFunctions import LayerConfig from "../Models/ThemeConfig/LayerConfig" import { Feature } from "geojson" import FeaturePropertiesStore from "./FeatureSource/Actors/FeaturePropertiesStore" -import LayoutConfig from "../Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../Models/ThemeConfig/ThemeConfig" import { GeoIndexedStoreForLayer } from "./FeatureSource/Actors/GeoIndexedStore" import { IndexedFeatureSource } from "./FeatureSource/FeatureSource" import OsmObjectDownloader from "./Osm/OsmObjectDownloader" @@ -27,7 +27,7 @@ export default class MetaTagging { >() private state: { readonly selectedElement: Store - readonly layout: LayoutConfig + readonly theme: ThemeConfig readonly osmObjectDownloader: OsmObjectDownloader readonly perLayer: ReadonlyMap readonly indexedFeatures: IndexedFeatureSource @@ -40,7 +40,7 @@ export default class MetaTagging { constructor(state: { readonly selectedElement: Store - readonly layout: LayoutConfig + readonly theme: ThemeConfig readonly osmObjectDownloader: OsmObjectDownloader readonly perLayer: ReadonlyMap readonly indexedFeatures: IndexedFeatureSource @@ -48,7 +48,7 @@ export default class MetaTagging { }) { this.state = state const params = (this.params = MetaTagging.createExtraFuncParams(state)) - for (const layer of state.layout.layers) { + for (const layer of state.theme.layers) { if (layer.source === null) { continue } @@ -69,7 +69,7 @@ export default class MetaTagging { features, params, layer, - state.layout, + state.theme, state.osmObjectDownloader, state.featureProperties ) @@ -115,7 +115,7 @@ export default class MetaTagging { return } const state = this.state - const layer = state.layout.getMatchingLayer(feature.properties) + const layer = state.theme.getMatchingLayer(feature.properties) if (!layer) { return } @@ -124,7 +124,7 @@ export default class MetaTagging { [feature], this.params, layer, - state.layout, + state.theme, state.osmObjectDownloader, state.featureProperties, { @@ -161,7 +161,7 @@ export default class MetaTagging { features: Feature[], params: ExtraFuncParams, layer: LayerConfig, - layout: LayoutConfig, + theme: ThemeConfig, osmObjectDownloader: OsmObjectDownloader, featurePropertiesStores?: FeaturePropertiesStore, options?: { @@ -190,7 +190,7 @@ export default class MetaTagging { // The calculated functions - per layer - which add the new keys // Calculated functions are defined by the layer const layerFuncs = this.createRetaggingFunc(layer, ExtraFunctions.constructHelpers(params)) - const state: MetataggingState = { layout, osmObjectDownloader } + const state: MetataggingState = { theme: theme, osmObjectDownloader } let atLeastOneFeatureChanged = false let strictlyEvaluated = 0 @@ -424,7 +424,7 @@ export default class MetaTagging { } } - if (!window.location.pathname.endsWith("theme.html")) { + if (!Utils.runningFromConsole && !window.location.pathname.endsWith("theme.html")) { console.warn( "Static MetataggingObject for theme is not set; using `new Function` (aka `eval`) to get calculated tags. This might trip up the CSP" ) diff --git a/src/Logic/Osm/Actions/CreateMultiPolygonWithPointReuseAction.ts b/src/Logic/Osm/Actions/CreateMultiPolygonWithPointReuseAction.ts index 7b259e6385..14582d4059 100644 --- a/src/Logic/Osm/Actions/CreateMultiPolygonWithPointReuseAction.ts +++ b/src/Logic/Osm/Actions/CreateMultiPolygonWithPointReuseAction.ts @@ -7,7 +7,7 @@ import CreateWayWithPointReuseAction, { MergePointConfig } from "./CreateWayWith import { And } from "../../Tags/And" import { TagUtils } from "../../Tags/TagUtils" import { FeatureSource, IndexedFeatureSource } from "../../FeatureSource/FeatureSource" -import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig" import { Position } from "geojson" import FullNodeDatabaseSource from "../../FeatureSource/TiledFeatureSource/FullNodeDatabaseSource" @@ -32,7 +32,7 @@ export default class CreateMultiPolygonWithPointReuseAction outerRingCoordinates: Position[], innerRingsCoordinates: Position[][], state: { - layout: LayoutConfig + theme: ThemeConfig changes: Changes indexedFeatures: IndexedFeatureSource fullNodeDatabase?: FullNodeDatabaseSource @@ -43,7 +43,7 @@ export default class CreateMultiPolygonWithPointReuseAction super(null, true) this._tags = [...tags, new Tag("type", "multipolygon")] this.changeType = changeType - this.theme = state?.layout?.id ?? "" + this.theme = state?.theme?.id ?? "" this.createOuterWay = new CreateWayWithPointReuseAction( [], <[number, number][]>outerRingCoordinates, @@ -55,7 +55,7 @@ export default class CreateMultiPolygonWithPointReuseAction new CreateNewWayAction( [], ringCoordinates.map(([lon, lat]) => ({ lat, lon })), - { theme: state?.layout?.id } + { theme: state?.theme?.id } ) ) diff --git a/src/Logic/Osm/Actions/CreateWayWithPointReuseAction.ts b/src/Logic/Osm/Actions/CreateWayWithPointReuseAction.ts index 9a87f7589f..eba4275ecb 100644 --- a/src/Logic/Osm/Actions/CreateWayWithPointReuseAction.ts +++ b/src/Logic/Osm/Actions/CreateWayWithPointReuseAction.ts @@ -9,7 +9,7 @@ import { FeatureSource, IndexedFeatureSource } from "../../FeatureSource/Feature import StaticFeatureSource from "../../FeatureSource/Sources/StaticFeatureSource" import CreateNewNodeAction from "./CreateNewNodeAction" import CreateNewWayAction from "./CreateNewWayAction" -import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig" import FullNodeDatabaseSource from "../../FeatureSource/TiledFeatureSource/FullNodeDatabaseSource" import { Position } from "geojson" @@ -69,7 +69,7 @@ export default class CreateWayWithPointReuseAction */ private readonly _coordinateInfo: CoordinateInfo[] private readonly _state: { - layout: LayoutConfig + theme: ThemeConfig changes: Changes indexedFeatures: IndexedFeatureSource fullNodeDatabase?: FullNodeDatabaseSource @@ -80,7 +80,7 @@ export default class CreateWayWithPointReuseAction tags: Tag[], coordinates: Position[], state: { - layout: LayoutConfig + theme: ThemeConfig changes: Changes indexedFeatures: IndexedFeatureSource fullNodeDatabase?: FullNodeDatabaseSource @@ -203,7 +203,7 @@ export default class CreateWayWithPointReuseAction } public async CreateChangeDescriptions(changes: Changes): Promise { - const theme = this._state?.layout?.id + const theme = this._state?.theme?.id const allChanges: ChangeDescription[] = [] const nodeIdsToUse: { lat: number; lon: number; nodeId?: number }[] = [] for (let i = 0; i < this._coordinateInfo.length; i++) { diff --git a/src/Logic/Osm/Actions/ReplaceGeometryAction.ts b/src/Logic/Osm/Actions/ReplaceGeometryAction.ts index 07be721fbf..9ea6f820b1 100644 --- a/src/Logic/Osm/Actions/ReplaceGeometryAction.ts +++ b/src/Logic/Osm/Actions/ReplaceGeometryAction.ts @@ -217,7 +217,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr const url = `${ this.state.osmConnection?._oauth_config?.url ?? "https://api.openstreetmap.org" }/api/0.6/${this.wayToReplaceId}/full` - const rawData = await Utils.downloadJsonCached(url, 1000) + const rawData = await Utils.downloadJsonCached<{elements: any[]}>(url, 1000) parsed = OsmObject.ParseObjects(rawData.elements) } const allNodes = parsed.filter((o) => o.type === "node") diff --git a/src/Logic/Search/FilterSearch.ts b/src/Logic/Search/FilterSearch.ts index a08b0bb5c9..35711f3ccf 100644 --- a/src/Logic/Search/FilterSearch.ts +++ b/src/Logic/Search/FilterSearch.ts @@ -4,7 +4,7 @@ import Constants from "../../Models/Constants" import FilterConfig, { FilterConfigOption } from "../../Models/ThemeConfig/FilterConfig" import LayerConfig from "../../Models/ThemeConfig/LayerConfig" import LayerState from "../State/LayerState" -import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig" export type FilterSearchResult = { option: FilterConfigOption, filter: FilterConfig, layer: LayerConfig, index: number } @@ -13,9 +13,9 @@ export type FilterSearchResult = { option: FilterConfigOption, filter: FilterCon * Searches matching filters */ export default class FilterSearch { - private readonly _state: {layerState: LayerState, layout: LayoutConfig} + private readonly _state: {layerState: LayerState, theme: ThemeConfig} - constructor(state: {layerState: LayerState, layout: LayoutConfig}) { + constructor(state: {layerState: LayerState, theme: ThemeConfig}) { this._state = state } @@ -30,7 +30,7 @@ export default class FilterSearch { return query }).filter(q => q.length > 0) const possibleFilters: FilterSearchResult[] = [] - for (const layer of this._state.layout.layers) { + for (const layer of this._state.theme.layers) { if (!Array.isArray(layer.filters)) { continue } diff --git a/src/Logic/Search/LayerSearch.ts b/src/Logic/Search/LayerSearch.ts index 60ffbacb1e..9397c0ee4c 100644 --- a/src/Logic/Search/LayerSearch.ts +++ b/src/Logic/Search/LayerSearch.ts @@ -1,17 +1,17 @@ import SearchUtils from "./SearchUtils" import ThemeSearch from "./ThemeSearch" import LayerConfig from "../../Models/ThemeConfig/LayerConfig" -import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig" import { Utils } from "../../Utils" export default class LayerSearch { - private readonly _layout: LayoutConfig + private readonly _theme: ThemeConfig private readonly _layerWhitelist: Set - constructor(layout: LayoutConfig) { - this._layout = layout - this._layerWhitelist = new Set(layout.layers + constructor(theme: ThemeConfig) { + this._theme = theme + this._layerWhitelist = new Set(theme.layers .filter(l => l.isNormal()) .map(l => l.id)) } @@ -29,8 +29,7 @@ export default class LayerSearch { continue } const keywords = ThemeSearch.officialThemes.layers[id] - const distance = Math.min(...queryParts.map(q => SearchUtils.scoreKeywords(q, keywords))) - result[id] = distance + result[id] = Math.min(...queryParts.map(q => SearchUtils.scoreKeywords(q, keywords))) } return result } @@ -44,7 +43,7 @@ export default class LayerSearch { const asList: ({ layer: LayerConfig, score: number })[] = [] for (const layer in scores) { asList.push({ - layer: this._layout.getLayer(layer), + layer: this._theme.getLayer(layer), score: scores[layer], }) } diff --git a/src/Logic/Search/ThemeSearch.ts b/src/Logic/Search/ThemeSearch.ts index 30b4d25eb5..3c4ef6be43 100644 --- a/src/Logic/Search/ThemeSearch.ts +++ b/src/Logic/Search/ThemeSearch.ts @@ -1,4 +1,4 @@ -import LayoutConfig, { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig" +import ThemeConfig, { MinimalThemeInformation } from "../../Models/ThemeConfig/ThemeConfig" import { Store } from "../UIEventSource" import UserRelatedState from "../State/UserRelatedState" import { Utils } from "../../Utils" @@ -10,7 +10,7 @@ import { OsmConnection } from "../Osm/OsmConnection" type ThemeSearchScore = { - theme: MinimalLayoutInformation, + theme: MinimalThemeInformation, lowest: number, perLayer?: Record, other: number, @@ -20,10 +20,10 @@ type ThemeSearchScore = { export default class ThemeSearch { public static readonly officialThemes: { - themes: MinimalLayoutInformation[], + themes: MinimalThemeInformation[], layers: Record> } = themeOverview - public static readonly officialThemesById: Map = new Map() + public static readonly officialThemesById: Map = new Map() static { for (const th of ThemeSearch.officialThemes.themes ?? []) { ThemeSearch.officialThemesById.set(th.id, th) @@ -33,17 +33,17 @@ export default class ThemeSearch { private readonly _knownHiddenThemes: Store> private readonly _layersToIgnore: string[] - private readonly _otherThemes: MinimalLayoutInformation[] + private readonly _otherThemes: MinimalThemeInformation[] - constructor(state: {osmConnection: OsmConnection, layout: LayoutConfig}) { - this._layersToIgnore = state.layout.layers.filter(l => l.isNormal()).map(l => l.id) + constructor(state: {osmConnection: OsmConnection, theme: ThemeConfig}) { + this._layersToIgnore = state.theme.layers.filter(l => l.isNormal()).map(l => l.id) this._knownHiddenThemes = UserRelatedState.initDiscoveredHiddenThemes(state.osmConnection).map(list => new Set(list)) this._otherThemes = ThemeSearch.officialThemes.themes - .filter(th => th.id !== state.layout.id) + .filter(th => th.id !== state.theme.id) } - public search(query: string, limit: number, threshold: number = 3): MinimalLayoutInformation[] { + public search(query: string, limit: number, threshold: number = 3): MinimalThemeInformation[] { if (query.length < 1) { return [] } @@ -101,7 +101,7 @@ export default class ThemeSearch { * @param ignoreLayers * @private */ - private static scoreThemes(query: string, themes: MinimalLayoutInformation[], ignoreLayers: string[] = undefined): Record { + private static scoreThemes(query: string, themes: MinimalThemeInformation[], ignoreLayers: string[] = undefined): Record { if (query?.length < 1) { return undefined } @@ -147,13 +147,13 @@ export default class ThemeSearch { return results } - public static sortedByLowestScores(search: string, themes: MinimalLayoutInformation[], ignoreLayers: string[] = []): ThemeSearchScore[] { + public static sortedByLowestScores(search: string, themes: MinimalThemeInformation[], ignoreLayers: string[] = []): ThemeSearchScore[] { const scored = Object.values(this.scoreThemes(search, themes, ignoreLayers)) scored.sort((a, b) => a.lowest - b.lowest) return scored } - public static sortedByLowest(search: string, themes: MinimalLayoutInformation[], ignoreLayers: string[] = []): MinimalLayoutInformation[] { + public static sortedByLowest(search: string, themes: MinimalThemeInformation[], ignoreLayers: string[] = []): MinimalThemeInformation[] { return this.sortedByLowestScores(search, themes, ignoreLayers) .map(th => th.theme) } diff --git a/src/Logic/SimpleMetaTagger.ts b/src/Logic/SimpleMetaTagger.ts index 611207a47a..3e0595b38c 100644 --- a/src/Logic/SimpleMetaTagger.ts +++ b/src/Logic/SimpleMetaTagger.ts @@ -8,7 +8,7 @@ import { TagUtils } from "./Tags/TagUtils" import { Feature, LineString } from "geojson" import { OsmTags } from "../Models/OsmFeature" import { UIEventSource } from "./UIEventSource" -import LayoutConfig from "../Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../Models/ThemeConfig/ThemeConfig" import OsmObjectDownloader from "./Osm/OsmObjectDownloader" import countryToCurrency from "country-to-currency" @@ -16,7 +16,7 @@ import countryToCurrency from "country-to-currency" * All elements that are needed to perform metatagging */ export interface MetataggingState { - layout: LayoutConfig + theme: ThemeConfig osmObjectDownloader: OsmObjectDownloader } @@ -399,7 +399,7 @@ export default class SimpleMetaTaggers { }, (feature, _, __, state) => { const units = Utils.NoNull( - [].concat(...(state?.layout?.layers?.map((layer) => layer.units) ?? [])) + [].concat(...(state?.theme?.layers?.map((layer) => layer.units) ?? [])) ) if (units.length == 0) { return diff --git a/src/Logic/State/FeatureSwitchState.ts b/src/Logic/State/FeatureSwitchState.ts index 054d9c8416..e7d39702ef 100644 --- a/src/Logic/State/FeatureSwitchState.ts +++ b/src/Logic/State/FeatureSwitchState.ts @@ -1,7 +1,7 @@ /** - * The part of the global state which initializes the feature switches, based on default values and on the layoutToUse + * The part of the global state which initializes the feature switches, based on default values and on the theme */ -import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig" import { UIEventSource } from "../UIEventSource" import { QueryParameters } from "../Web/QueryParameters" import Constants from "../../Models/Constants" @@ -45,10 +45,6 @@ export class OsmConnectionFeatureSwitches { } export default class FeatureSwitchState extends OsmConnectionFeatureSwitches { - /** - * The layout that is being used in this run - */ - public readonly layoutToUse: LayoutConfig public readonly featureSwitchEnableLogin: UIEventSource public readonly featureSwitchSearch: UIEventSource @@ -74,9 +70,8 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches { public readonly featureSwitchMorePrivacy: UIEventSource public readonly featureSwitchLayerDefault: UIEventSource - public constructor(layoutToUse?: LayoutConfig) { + public constructor(theme?: ThemeConfig) { super() - this.layoutToUse = layoutToUse const legacyRewrite: Record = { "fs-userbadge": "fs-enable-login", @@ -102,7 +97,7 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches { this.featureSwitchEnableLogin = FeatureSwitchUtils.initSwitch( "fs-enable-login", - layoutToUse?.enableUserBadge ?? true, + theme?.enableUserBadge ?? true, "Disables/Enables logging in and thus disables editing all together. This effectively puts MapComplete into read-only mode." ) { @@ -117,18 +112,18 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches { this.featureSwitchSearch = FeatureSwitchUtils.initSwitch( "fs-search", - layoutToUse?.enableSearch ?? true, + theme?.enableSearch ?? true, "Disables/Enables the search bar" ) this.featureSwitchBackgroundSelection = FeatureSwitchUtils.initSwitch( "fs-background", - layoutToUse?.enableBackgroundLayerSelection ?? true, + theme?.enableBackgroundLayerSelection ?? true, "Disables/Enables the background layer control where a user can enable e.g. aerial imagery" ) this.featureSwitchFilter = FeatureSwitchUtils.initSwitch( "fs-filter", - layoutToUse?.enableLayers ?? true, + theme?.enableLayers ?? true, "Disables/Enables the filter view where a user can enable/disable MapComplete-layers or filter for certain properties" ) @@ -149,17 +144,17 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches { ) this.featureSwitchBackToThemeOverview = FeatureSwitchUtils.initSwitch( "fs-homepage-link", - layoutToUse?.enableMoreQuests ?? true, + theme?.enableMoreQuests ?? true, "Disables/Enables the various links which go back to the index page with the theme overview" ) this.featureSwitchShareScreen = FeatureSwitchUtils.initSwitch( "fs-share-screen", - layoutToUse?.enableShareScreen ?? true, + theme?.enableShareScreen ?? true, "Disables/Enables the 'Share-screen'-tab in the welcome message" ) this.featureSwitchGeolocation = FeatureSwitchUtils.initSwitch( "fs-geolocation", - layoutToUse?.enableGeolocation ?? true, + theme?.enableGeolocation ?? true, "Disables/Enables the geolocation button" ) @@ -170,19 +165,19 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches { ) this.featureSwitchShowAllQuestions = FeatureSwitchUtils.initSwitch( "fs-all-questions", - layoutToUse?.enableShowAllQuestions ?? false, + theme?.enableShowAllQuestions ?? false, "Always show all questions" ) this.featureSwitchEnableExport = FeatureSwitchUtils.initSwitch( "fs-export", - layoutToUse?.enableExportButton ?? true, + theme?.enableExportButton ?? true, "Enable the export as GeoJSON and CSV button" ) this.featureSwitchCache = FeatureSwitchUtils.initSwitch( "fs-cache", - layoutToUse?.enableCache ?? true, + theme?.enableCache ?? true, "Enable/disable caching from localStorage" ) @@ -209,13 +204,13 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches { this.featureSwitchMorePrivacy = QueryParameters.GetBooleanQueryParameter( "moreprivacy", - layoutToUse.enableMorePrivacy, + theme.enableMorePrivacy, "If true, the location distance indication will not be written to the changeset and other privacy enhancing measures might be taken." ) this.overpassUrl = QueryParameters.GetQueryParameter( "overpassUrl", - (layoutToUse?.overpassUrl ?? Constants.defaultOverpassUrls).join(","), + (theme?.overpassUrl ?? Constants.defaultOverpassUrls).join(","), "Point mapcomplete to a different overpass-instance. Example: https://overpass-api.de/api/interpreter" ).sync( (param) => param?.split(","), @@ -226,7 +221,7 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches { this.overpassTimeout = UIEventSource.asInt( QueryParameters.GetQueryParameter( "overpassTimeout", - "" + layoutToUse?.overpassTimeout, + "" + theme?.overpassTimeout, "Set a different timeout (in seconds) for queries in overpass" ) ) @@ -234,7 +229,7 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches { this.overpassMaxZoom = UIEventSource.asFloat( QueryParameters.GetQueryParameter( "overpassMaxZoom", - "" + layoutToUse?.overpassMaxZoom, + "" + theme?.overpassMaxZoom, " point to switch between OSM-api and overpass" ) ) @@ -242,14 +237,14 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches { this.osmApiTileSize = UIEventSource.asInt( QueryParameters.GetQueryParameter( "osmApiTileSize", - "" + layoutToUse?.osmApiTileSize, + "" + theme?.osmApiTileSize, "Tilesize when the OSM-API is used to fetch data within a BBOX" ) ) this.backgroundLayerId = QueryParameters.GetQueryParameter( "background", - layoutToUse?.defaultBackgroundId, + theme?.defaultBackgroundId, [ "When set, load this raster layer (or a layer of this category) as background layer instead of using the default background. This is as if the user opened the background selection menu and selected the layer with the given id or category.", "Most raster layers are based on the [editor layer index](https://github.com/osmlab/editor-layer-index)", diff --git a/src/Logic/State/SearchState.ts b/src/Logic/State/SearchState.ts index 68f6d5427e..5e2310cf3c 100644 --- a/src/Logic/State/SearchState.ts +++ b/src/Logic/State/SearchState.ts @@ -8,7 +8,7 @@ import ThemeSearch from "../Search/ThemeSearch" import OpenStreetMapIdSearch from "../Search/OpenStreetMapIdSearch" import PhotonSearch from "../Search/PhotonSearch" import ThemeViewState from "../../Models/ThemeViewState" -import type { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig" +import type { MinimalThemeInformation } from "../../Models/ThemeConfig/ThemeConfig" import { Translation } from "../../UI/i18n/Translation" import GeocodingFeatureSource from "../Search/GeocodingFeatureSource" import LayerSearch from "../Search/LayerSearch" @@ -23,7 +23,7 @@ export default class SearchState { public readonly searchIsFocused = new UIEventSource(false) public readonly suggestions: Store public readonly filterSuggestions: Store - public readonly themeSuggestions: Store + public readonly themeSuggestions: Store public readonly layerSuggestions: Store public readonly locationSearchers: ReadonlyArray @@ -64,7 +64,7 @@ export default class SearchState { const themeSearch = new ThemeSearch(state) this.themeSuggestions = this.searchTerm.mapD(query => themeSearch.search(query, 3)) - const layerSearch = new LayerSearch(state.layout) + const layerSearch = new LayerSearch(state.theme) this.layerSuggestions = this.searchTerm.mapD(query => layerSearch.search(query, 5)) const filterSearch = new FilterSearch(state) diff --git a/src/Logic/State/UserRelatedState.ts b/src/Logic/State/UserRelatedState.ts index d958c3cf42..0d3d4eae0a 100644 --- a/src/Logic/State/UserRelatedState.ts +++ b/src/Logic/State/UserRelatedState.ts @@ -1,4 +1,4 @@ -import LayoutConfig, { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig" +import ThemeConfig, { MinimalThemeInformation } from "../../Models/ThemeConfig/ThemeConfig" import { OsmConnection } from "../Osm/OsmConnection" import { MangroveIdentity } from "../Web/MangroveReviews" import { Store, Stores, UIEventSource } from "../UIEventSource" @@ -183,7 +183,7 @@ export default class UserRelatedState { constructor( osmConnection: OsmConnection, - layout?: LayoutConfig, + layout?: ThemeConfig, featureSwitches?: FeatureSwitchState, mapProperties?: MapProperties, ) { @@ -277,14 +277,14 @@ export default class UserRelatedState { * * @param themeInfo note that themeInfo.id should be the URL where it was found */ - public addUnofficialTheme(themeInfo: MinimalLayoutInformation) { + public addUnofficialTheme(themeInfo: MinimalThemeInformation) { const pref = this.osmConnection.getPreference("unofficial-theme-" + themeInfo.id) this.osmConnection.isLoggedIn.when( () => pref.set(JSON.stringify(themeInfo)) ) } - public getUnofficialTheme(id: string): MinimalLayoutInformation | undefined { + public getUnofficialTheme(id: string): MinimalThemeInformation | undefined { const pref = this.osmConnection.getPreference("unofficial-theme-" + id) const str = pref.data @@ -307,7 +307,7 @@ export default class UserRelatedState { } } - public markLayoutAsVisited(layout: LayoutConfig) { + public markLayoutAsVisited(layout: ThemeConfig) { if (!layout) { console.error("Trying to mark a layout as visited, but ", layout, " got passed") return @@ -399,7 +399,7 @@ export default class UserRelatedState { * This is inherently a dirty and chaotic method, as it shoves many properties into this EventSource * */ private initAmendedPrefs( - layout?: LayoutConfig, + layout?: ThemeConfig, featureSwitches?: FeatureSwitchState, ): UIEventSource> { const amendedPrefs = new UIEventSource>({ diff --git a/src/Logic/Web/LocalStorageSource.ts b/src/Logic/Web/LocalStorageSource.ts index e1453597e8..310830a002 100644 --- a/src/Logic/Web/LocalStorageSource.ts +++ b/src/Logic/Web/LocalStorageSource.ts @@ -1,4 +1,5 @@ import { UIEventSource } from "../UIEventSource" +import { Utils } from "../../Utils" /** * UIEventsource-wrapper around localStorage @@ -30,13 +31,16 @@ export class LocalStorageSource { return cached } let saved = defaultValue - try { - saved = localStorage.getItem(key) - if (saved === "undefined") { - saved = undefined + if (!Utils.runningFromConsole) { + + try { + saved = localStorage.getItem(key) + if (saved === "undefined") { + saved = undefined + } + } catch (e) { + console.error("Could not get value", key, "from local storage") } - } catch (e) { - console.error("Could not get value", key, "from local storage") } const source = new UIEventSource(saved ?? defaultValue, "localstorage:" + key) diff --git a/src/Models/Constants.ts b/src/Models/Constants.ts index afefc9ceff..ddc05165c1 100644 --- a/src/Models/Constants.ts +++ b/src/Models/Constants.ts @@ -55,7 +55,7 @@ export default class Constants { // The user journey states thresholds when a new feature gets unlocked public static userJourney = { moreScreenUnlock: 1, - personalLayoutUnlock: 5, + personalThemeUnlock: 5, historyLinkVisible: 10, deletePointsOfOthersUnlock: 20, tagsVisibleAt: 25, diff --git a/src/Models/ThemeConfig/Conversion/FixImages.ts b/src/Models/ThemeConfig/Conversion/FixImages.ts index 50c67153b7..331e3d02e0 100644 --- a/src/Models/ThemeConfig/Conversion/FixImages.ts +++ b/src/Models/ThemeConfig/Conversion/FixImages.ts @@ -1,5 +1,5 @@ import { Conversion, DesugaringStep } from "./Conversion" -import { LayoutConfigJson } from "../Json/LayoutConfigJson" +import { ThemeConfigJson } from "../Json/ThemeConfigJson" import { Utils } from "../../../Utils" import metapaths from "../../../assets/schemas/layoutconfigmeta.json" import tagrenderingmetapaths from "../../../assets/schemas/questionabletagrenderingconfigmeta.json" @@ -9,7 +9,7 @@ import { parse as parse_html } from "node-html-parser" import { ConversionContext } from "./ConversionContext" export class ExtractImages extends Conversion< - LayoutConfigJson, + ThemeConfigJson, { path: string; context: string }[] > { private static readonly layoutMetaPaths = metapaths.filter((mp) => { @@ -109,7 +109,7 @@ export class ExtractImages extends Conversion< * */ convert( - json: LayoutConfigJson, + json: ThemeConfigJson, context: ConversionContext ): { path: string; context: string }[] { const allFoundImages: { path: string; context: string }[] = [] @@ -243,7 +243,7 @@ export class ExtractImages extends Conversion< } } -export class FixImages extends DesugaringStep { +export class FixImages extends DesugaringStep { private readonly _knownImages: Set constructor(knownImages: Set) { @@ -289,7 +289,7 @@ export class FixImages extends DesugaringStep { * fixed.layers[0]["pointRendering"][0].marker[0].icon // => "https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/TS_bolt.svg" * fixed.layers[0]["pointRendering"][0].iconBadges[0].then.mappings[0].then // => "https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/Something.svg" */ - convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { + convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson { let url: URL try { url = new URL(json.id) diff --git a/src/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts b/src/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts index 18c78ccf29..b7187a7c8b 100644 --- a/src/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts +++ b/src/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts @@ -1,4 +1,4 @@ -import { LayoutConfigJson } from "../Json/LayoutConfigJson" +import { ThemeConfigJson } from "../Json/ThemeConfigJson" import { Utils } from "../../../Utils" import LineRenderingConfigJson from "../Json/LineRenderingConfigJson" import { LayerConfigJson } from "../Json/LayerConfigJson" @@ -257,12 +257,12 @@ export class UpdateLegacyLayer extends DesugaringStep< } } -class UpdateLegacyTheme extends DesugaringStep { +class UpdateLegacyTheme extends DesugaringStep { constructor() { super("Small fixes in the theme config", ["roamingRenderings"], "UpdateLegacyTheme") } - convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { + convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson { const oldThemeConfig = { ...json } if (oldThemeConfig.socialImage === "") { @@ -311,7 +311,7 @@ class UpdateLegacyTheme extends DesugaringStep { } } -export class FixLegacyTheme extends Fuse { +export class FixLegacyTheme extends Fuse { constructor() { super( "Fixes a legacy theme to the modern JSON format geared to humans. Syntactic sugars are kept (i.e. no tagRenderings are expandend, no dependencies are automatically gathered)", diff --git a/src/Models/ThemeConfig/Conversion/PrepareTheme.ts b/src/Models/ThemeConfig/Conversion/PrepareTheme.ts index 825f8c3db7..21518a730d 100644 --- a/src/Models/ThemeConfig/Conversion/PrepareTheme.ts +++ b/src/Models/ThemeConfig/Conversion/PrepareTheme.ts @@ -1,5 +1,5 @@ import { Concat, Conversion, DesugaringContext, DesugaringStep, Each, Fuse, On, Pass, SetDefault } from "./Conversion" -import { LayoutConfigJson } from "../Json/LayoutConfigJson" +import { ThemeConfigJson } from "../Json/ThemeConfigJson" import { PrepareLayer } from "./PrepareLayer" import { LayerConfigJson } from "../Json/LayerConfigJson" import { Utils } from "../../../Utils" @@ -165,7 +165,7 @@ class SubstituteLayer extends Conversion { +class AddDefaultLayers extends DesugaringStep { private readonly _state: DesugaringContext constructor(state: DesugaringContext) { @@ -177,7 +177,7 @@ class AddDefaultLayers extends DesugaringStep { this._state = state } - convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { + convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson { const state = this._state json.layers = Utils.NoNull([...(json.layers ?? [])]) const alreadyLoaded = new Set(json.layers.map((l) => l["id"])) @@ -209,7 +209,7 @@ class AddDefaultLayers extends DesugaringStep { } } -class AddContextToTranslationsInLayout extends DesugaringStep { +class AddContextToTranslationsInLayout extends DesugaringStep { constructor() { 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", @@ -218,8 +218,8 @@ class AddContextToTranslationsInLayout extends DesugaringStep ) } - convert(json: LayoutConfigJson): LayoutConfigJson { - const conversion = new AddContextToTranslations("themes:") + convert(json: ThemeConfigJson): ThemeConfigJson { + const conversion = new AddContextToTranslations("themes:") // The context is used to generate the 'context' in the translation .It _must_ be `json.id` to correctly link into weblate return conversion.convert( json, @@ -228,7 +228,7 @@ class AddContextToTranslationsInLayout extends DesugaringStep } } -class ApplyOverrideAll extends DesugaringStep { +class ApplyOverrideAll extends DesugaringStep { constructor() { super( "Applies 'overrideAll' onto every 'layer'. The 'overrideAll'-field is removed afterwards", @@ -237,7 +237,7 @@ class ApplyOverrideAll extends DesugaringStep { ) } - convert(json: LayoutConfigJson, ctx: ConversionContext): LayoutConfigJson { + convert(json: ThemeConfigJson, ctx: ConversionContext): ThemeConfigJson { const overrideAll = json.overrideAll if (overrideAll === undefined) { return json @@ -278,7 +278,7 @@ class ApplyOverrideAll extends DesugaringStep { } } -class AddDependencyLayersToTheme extends DesugaringStep { +class AddDependencyLayersToTheme extends DesugaringStep { private readonly _state: DesugaringContext constructor(state: DesugaringContext) { @@ -390,7 +390,7 @@ class AddDependencyLayersToTheme extends DesugaringStep { return dependenciesToAdd } - convert(theme: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { + convert(theme: ThemeConfigJson, context: ConversionContext): ThemeConfigJson { const state = this._state const allKnownLayers: Map = state.sharedLayers const knownTagRenderings: Map = state.tagRenderings @@ -428,7 +428,7 @@ class AddDependencyLayersToTheme extends DesugaringStep { } } -class PreparePersonalTheme extends DesugaringStep { +class PreparePersonalTheme extends DesugaringStep { private readonly _state: DesugaringContext constructor(state: DesugaringContext) { @@ -436,7 +436,7 @@ class PreparePersonalTheme extends DesugaringStep { this._state = state } - convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { + convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson { if (json.id !== "personal") { return json } @@ -452,7 +452,7 @@ class PreparePersonalTheme extends DesugaringStep { } } -class WarnForUnsubstitutedLayersInTheme extends DesugaringStep { +class WarnForUnsubstitutedLayersInTheme extends DesugaringStep { constructor() { super( "Generates a warning if a theme uses an unsubstituted layer", @@ -461,7 +461,7 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep ) } - convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { + convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson { if (json.hideFromOverview === true) { return json } @@ -503,7 +503,7 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep } } -class PostvalidateTheme extends DesugaringStep { +class PostvalidateTheme extends DesugaringStep { private readonly _state: DesugaringContext constructor(state: DesugaringContext) { @@ -511,7 +511,7 @@ class PostvalidateTheme extends DesugaringStep { this._state = state } - convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { + convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson { for (const l of json.layers) { const layer = l const basedOn = layer["_basedOn"] @@ -582,7 +582,7 @@ class PostvalidateTheme extends DesugaringStep { } } -export class PrepareTheme extends Fuse { +export class PrepareTheme extends Fuse { private state: DesugaringContext constructor( @@ -616,7 +616,7 @@ export class PrepareTheme extends Fuse { this.state = state } - convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { + convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson { const result = super.convert(json, context) if ((this.state.publicLayers?.size ?? 0) === 0) { // THis is a bootstrapping run, no need to already set this flag diff --git a/src/Models/ThemeConfig/Conversion/ValidateTheme.ts b/src/Models/ThemeConfig/Conversion/ValidateTheme.ts index d5aee78bbb..dc89de0296 100644 --- a/src/Models/ThemeConfig/Conversion/ValidateTheme.ts +++ b/src/Models/ThemeConfig/Conversion/ValidateTheme.ts @@ -1,13 +1,13 @@ import { DesugaringStep } from "./Conversion" -import { LayoutConfigJson } from "../Json/LayoutConfigJson" +import { ThemeConfigJson } from "../Json/ThemeConfigJson" import { AvailableRasterLayers } from "../../RasterLayers" import { ExtractImages } from "./FixImages" import { ConversionContext } from "./ConversionContext" -import LayoutConfig from "../LayoutConfig" +import ThemeConfig from "../ThemeConfig" import { Utils } from "../../../Utils" import { DetectDuplicatePresets, DoesImageExist, ValidateLanguageCompleteness } from "./Validation" -export class ValidateTheme extends DesugaringStep { +export class ValidateTheme extends DesugaringStep { /** * The paths where this layer is originally saved. Triggers some extra checks * @private @@ -33,8 +33,8 @@ export class ValidateTheme extends DesugaringStep { } } - convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { - const theme = new LayoutConfig(json, this._isBuiltin) + convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson { + const theme = new ThemeConfig(json, this._isBuiltin) { // Legacy format checks if (this._isBuiltin) { diff --git a/src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers.ts b/src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers.ts index 556f3f37d6..52b504d022 100644 --- a/src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers.ts +++ b/src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers.ts @@ -1,10 +1,10 @@ import { Bypass, Each, Fuse, On } from "./Conversion" -import { LayoutConfigJson } from "../Json/LayoutConfigJson" +import { ThemeConfigJson } from "../Json/ThemeConfigJson" import Constants from "../../Constants" import { DoesImageExist, ValidateLayerConfig } from "./Validation" import { ValidateTheme } from "./ValidateTheme" -export class ValidateThemeAndLayers extends Fuse { +export class ValidateThemeAndLayers extends Fuse { constructor( doesImageExist: DoesImageExist, path: string, diff --git a/src/Models/ThemeConfig/Conversion/Validation.ts b/src/Models/ThemeConfig/Conversion/Validation.ts index 6309d08661..dc0b557184 100644 --- a/src/Models/ThemeConfig/Conversion/Validation.ts +++ b/src/Models/ThemeConfig/Conversion/Validation.ts @@ -4,8 +4,8 @@ import LayerConfig from "../LayerConfig" import { Utils } from "../../../Utils" import Constants from "../../Constants" import { Translation } from "../../../UI/i18n/Translation" -import { LayoutConfigJson } from "../Json/LayoutConfigJson" -import LayoutConfig from "../LayoutConfig" +import { ThemeConfigJson } from "../Json/ThemeConfigJson" +import ThemeConfig from "../ThemeConfig" import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson" import { TagUtils } from "../../../Logic/Tags/TagUtils" import { And } from "../../../Logic/Tags/And" @@ -23,7 +23,7 @@ import { PrevalidateLayer } from "./PrevalidateLayer" import { AvailableRasterLayers } from "../../RasterLayers" import { eliCategory } from "../../RasterLayerProperties" -export class ValidateLanguageCompleteness extends DesugaringStep { +export class ValidateLanguageCompleteness extends DesugaringStep { private readonly _languages: string[] constructor(...languages: string[]) { @@ -35,7 +35,7 @@ export class ValidateLanguageCompleteness extends DesugaringStep { this._languages = languages ?? ["en"] } - convert(obj: LayoutConfig, context: ConversionContext): LayoutConfig { + convert(obj: ThemeConfig, context: ConversionContext): ThemeConfig { const origLayers = obj.layers obj.layers = [...obj.layers].filter((l) => l["id"] !== "favourite") const translations = Translation.ExtractAllTranslationsFrom(obj) @@ -128,7 +128,7 @@ export class DoesImageExist extends DesugaringStep { } } -class OverrideShadowingCheck extends DesugaringStep { +class OverrideShadowingCheck extends DesugaringStep { constructor() { super( "Checks that an 'overrideAll' does not override a single override", @@ -137,7 +137,7 @@ class OverrideShadowingCheck extends DesugaringStep { ) } - convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { + convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson { const overrideAll = json.overrideAll if (overrideAll === undefined) { return json @@ -170,12 +170,12 @@ class OverrideShadowingCheck extends DesugaringStep { } } -class MiscThemeChecks extends DesugaringStep { +class MiscThemeChecks extends DesugaringStep { constructor() { super("Miscelleanous checks on the theme", [], "MiscThemesChecks") } - convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { + convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson { if (json.id !== "personal" && (json.layers === undefined || json.layers.length === 0)) { context.err("The theme " + json.id + " has no 'layers' defined") } @@ -240,7 +240,7 @@ class MiscThemeChecks extends DesugaringStep { } } -export class PrevalidateTheme extends Fuse { +export class PrevalidateTheme extends Fuse { constructor() { super( "Various consistency checks on the raw JSON", @@ -905,7 +905,7 @@ export class ValidateFilter extends DesugaringStep { export class DetectDuplicateFilters extends DesugaringStep<{ layers: LayerConfigJson[] - themes: LayoutConfigJson[] + themes: ThemeConfigJson[] }> { constructor() { super( @@ -916,15 +916,15 @@ export class DetectDuplicateFilters extends DesugaringStep<{ } convert( - json: { layers: LayerConfigJson[]; themes: LayoutConfigJson[] }, + json: { layers: LayerConfigJson[]; themes: ThemeConfigJson[] }, context: ConversionContext, - ): { layers: LayerConfigJson[]; themes: LayoutConfigJson[] } { + ): { layers: LayerConfigJson[]; themes: ThemeConfigJson[] } { const { layers, themes } = json const perOsmTag = new Map< string, { layer: LayerConfigJson - layout: LayoutConfigJson | undefined + theme: ThemeConfigJson | undefined filter: FilterConfigJson }[] >() @@ -955,10 +955,10 @@ export class DetectDuplicateFilters extends DesugaringStep<{ return } let msg = "Possible duplicate filter: " + key - for (const { filter, layer, layout } of value) { + for (const { filter, layer, theme } of value) { let id = "" - if (layout !== undefined) { - id = layout.id + ":" + if (theme !== undefined) { + id = theme.id + ":" } msg += `\n - ${id}${layer.id}.${filter.id}` } @@ -977,11 +977,11 @@ export class DetectDuplicateFilters extends DesugaringStep<{ string, { layer: LayerConfigJson - layout: LayoutConfigJson | undefined + theme: ThemeConfigJson | undefined filter: FilterConfigJson }[] >, - layout?: LayoutConfigJson | undefined, + theme?: ThemeConfigJson | undefined, ): void { if (layer.filter === undefined || layer.filter === null) { return @@ -1009,14 +1009,14 @@ export class DetectDuplicateFilters extends DesugaringStep<{ perOsmTag.get(key).push({ layer, filter, - layout, + theme, }) } } } } -export class DetectDuplicatePresets extends DesugaringStep { +export class DetectDuplicatePresets extends DesugaringStep { constructor() { super( "Detects mappings which have identical (english) names or identical mappings.", @@ -1025,7 +1025,7 @@ export class DetectDuplicatePresets extends DesugaringStep { ) } - convert(json: LayoutConfig, context: ConversionContext): LayoutConfig { + convert(json: ThemeConfig, context: ConversionContext): ThemeConfig { const presets: PresetConfig[] = [].concat(...json.layers.map((l) => l.presets)) const enNames = presets.map((p) => p.title.textFor("en")) @@ -1074,7 +1074,7 @@ export class DetectDuplicatePresets extends DesugaringStep { } export class ValidateThemeEnsemble extends Conversion< - LayoutConfig[], + ThemeConfig[], Map< string, { @@ -1093,7 +1093,7 @@ export class ValidateThemeEnsemble extends Conversion< } convert( - json: LayoutConfig[], + json: ThemeConfig[], context: ConversionContext, ): Map< string, diff --git a/src/Models/ThemeConfig/FilterConfig.ts b/src/Models/ThemeConfig/FilterConfig.ts index 73eea02972..b44ff6558f 100644 --- a/src/Models/ThemeConfig/FilterConfig.ts +++ b/src/Models/ThemeConfig/FilterConfig.ts @@ -62,7 +62,7 @@ export default class FilterConfig { const fields: { name: string; type: ValidatorType }[] = (option.fields ?? []).map((f, i) => { const type = f.type ?? "regex" if(Validators.availableTypes.indexOf(type) < 0){ - throw `Invalid filter: type is not a valid validator. Did you mean one of ${Utils.sortedByLevenshteinDistance(type, Validators.availableTypes, x => x).slice(0, 3)}` + throw `Invalid filter: type is not a valid validator. Did you mean one of ${Utils.sortedByLevenshteinDistance(type, >Validators.availableTypes, x => x).slice(0, 3)}` } // Type is validated against 'ValidatedTextField' in Validation.ts, in ValidateFilterConfig if (f.name === undefined || f.name === "" || f.name.match(/[a-z0-9_-]+/) == null) { diff --git a/src/Models/ThemeConfig/Json/LayoutConfigJson.ts b/src/Models/ThemeConfig/Json/ThemeConfigJson.ts similarity index 99% rename from src/Models/ThemeConfig/Json/LayoutConfigJson.ts rename to src/Models/ThemeConfig/Json/ThemeConfigJson.ts index b3449ad014..cbdeef07b2 100644 --- a/src/Models/ThemeConfig/Json/LayoutConfigJson.ts +++ b/src/Models/ThemeConfig/Json/ThemeConfigJson.ts @@ -16,7 +16,7 @@ import { Translatable } from "./Translatable" * * General remark: a type (string | any) indicates either a fixed or a translatable string. */ -export interface LayoutConfigJson { +export interface ThemeConfigJson { /** * question: What is the id of this layout? * diff --git a/src/Models/ThemeConfig/LayoutConfig.ts b/src/Models/ThemeConfig/ThemeConfig.ts similarity index 96% rename from src/Models/ThemeConfig/LayoutConfig.ts rename to src/Models/ThemeConfig/ThemeConfig.ts index 2680a62afd..b60375e12a 100644 --- a/src/Models/ThemeConfig/LayoutConfig.ts +++ b/src/Models/ThemeConfig/ThemeConfig.ts @@ -1,5 +1,5 @@ import { Translation } from "../../UI/i18n/Translation" -import { LayoutConfigJson } from "./Json/LayoutConfigJson" +import { ThemeConfigJson } from "./Json/ThemeConfigJson" import LayerConfig from "./LayerConfig" import { LayerConfigJson } from "./Json/LayerConfigJson" import Constants from "../Constants" @@ -13,7 +13,7 @@ import { Translatable } from "./Json/Translatable" /** * Minimal information about a theme **/ -export class MinimalLayoutInformation { +export class MinimalThemeInformation { id: string icon: string title: Translatable @@ -27,7 +27,7 @@ export class MinimalLayoutInformation { /** * Minimal information about a theme **/ -export class LayoutInformation { +export class ThemeInformation { id: string icon: string title: Translatable | Translation @@ -39,7 +39,7 @@ export class LayoutInformation { } -export default class LayoutConfig implements LayoutInformation { +export default class ThemeConfig implements ThemeInformation { public static readonly defaultSocialImage = "assets/SocialImage.png" public readonly id: string public readonly credits?: string @@ -57,7 +57,6 @@ export default class LayoutConfig implements LayoutInformation { public readonly startZoom: number public readonly startLat: number public readonly startLon: number - public widenFactor: number public defaultBackgroundId?: string public layers: LayerConfig[] public tileLayerSources: (RasterLayerProperties & { defaultState?: true | boolean })[] @@ -92,11 +91,11 @@ export default class LayoutConfig implements LayoutInformation { public readonly definitionRaw?: string private readonly layersDict: Map - private readonly source: LayoutConfigJson + private readonly source: ThemeConfigJson public readonly enableCache: boolean constructor( - json: LayoutConfigJson, + json: ThemeConfigJson, official = true, options?: { definedAtUrl?: string @@ -167,7 +166,7 @@ export default class LayoutConfig implements LayoutInformation { ? undefined : new Translation(json.descriptionTail, "themes:" + context + ".descriptionTail") this.icon = json.icon - this.socialImage = json.socialImage ?? LayoutConfig.defaultSocialImage + this.socialImage = json.socialImage ?? ThemeConfig.defaultSocialImage if (this.socialImage === "") { if (official) { throw "Theme " + json.id + " has empty string as social image" @@ -176,7 +175,6 @@ export default class LayoutConfig implements LayoutInformation { this.startZoom = json.startZoom this.startLat = json.startLat this.startLon = json.startLon - this.widenFactor = 1.5 this.defaultBackgroundId = json.defaultBackgroundId this.tileLayerSources = json.tileLayerSources ?? [] diff --git a/src/Models/ThemeViewState.ts b/src/Models/ThemeViewState.ts index 933215c920..839b23b572 100644 --- a/src/Models/ThemeViewState.ts +++ b/src/Models/ThemeViewState.ts @@ -1,4 +1,4 @@ -import LayoutConfig from "./ThemeConfig/LayoutConfig" +import ThemeConfig from "./ThemeConfig/ThemeConfig" import { SpecialVisualizationState } from "../UI/SpecialVisualization" import { Changes } from "../Logic/Osm/Changes" import { Store, UIEventSource } from "../Logic/UIEventSource" @@ -18,7 +18,7 @@ import UserRelatedState from "../Logic/State/UserRelatedState" import LayerConfig from "./ThemeConfig/LayerConfig" import GeoLocationHandler from "../Logic/Actors/GeoLocationHandler" import { AvailableRasterLayers, RasterLayerPolygon, RasterLayerUtils } from "./RasterLayers" -import LayoutSource from "../Logic/FeatureSource/Sources/LayoutSource" +import ThemeSource from "../Logic/FeatureSource/Sources/ThemeSource" import StaticFeatureSource from "../Logic/FeatureSource/Sources/StaticFeatureSource" import FeaturePropertiesStore from "../Logic/FeatureSource/Actors/FeaturePropertiesStore" import PerLayerFeatureSourceSplitter from "../Logic/FeatureSource/PerLayerFeatureSourceSplitter" @@ -80,7 +80,7 @@ import { PanoramaxUploader } from "../Logic/ImageProviders/Panoramax" * It ties up all the needed elements and starts some actors. */ export default class ThemeViewState implements SpecialVisualizationState { - readonly layout: LayoutConfig + readonly theme: ThemeConfig readonly map: UIEventSource readonly changes: Changes readonly featureSwitches: FeatureSwitchState @@ -104,7 +104,7 @@ export default class ThemeViewState implements SpecialVisualizationState { readonly fullNodeDatabase?: FullNodeDatabaseSource readonly historicalUserLocations: WritableFeatureSource> - readonly indexedFeatures: IndexedFeatureSource & LayoutSource + readonly indexedFeatures: IndexedFeatureSource & ThemeSource readonly currentView: FeatureSource> readonly featuresInView: FeatureSource readonly favourites: FavouritesFeatureSource @@ -160,9 +160,9 @@ export default class ThemeViewState implements SpecialVisualizationState { */ public readonly featureSummary: SummaryTileSourceRewriter - constructor(layout: LayoutConfig, mvtAvailableLayers: Set) { + constructor(layout: ThemeConfig, mvtAvailableLayers: Set) { Utils.initDomPurify() - this.layout = layout + this.theme = layout this.featureSwitches = new FeatureSwitchState(layout) this.guistate = new MenuState( this.featureSwitches.featureSwitchWelcomeMessage.data, @@ -218,7 +218,7 @@ export default class ThemeViewState implements SpecialVisualizationState { { const overlayLayerStates = new Map }>() - for (const rasterInfo of this.layout.tileLayerSources) { + for (const rasterInfo of this.theme.tileLayerSources) { const isDisplayed = QueryParameters.GetBooleanQueryParameter( "overlay-" + rasterInfo.id, rasterInfo.defaultState ?? true, @@ -236,11 +236,11 @@ export default class ThemeViewState implements SpecialVisualizationState { * A bit tricky, as this is heavily intertwined with the 'changes'-element, which generates a stream of new and changed features too */ - if (this.layout.layers.some((l) => l._needsFullNodeDatabase)) { + if (this.theme.layers.some((l) => l._needsFullNodeDatabase)) { this.fullNodeDatabase = new FullNodeDatabaseSource() } - const layoutSource = new LayoutSource( + const layoutSource = new ThemeSource( layout.layers, this.featureSwitches, this.mapProperties, @@ -340,7 +340,7 @@ export default class ThemeViewState implements SpecialVisualizationState { }) this.lastClickObject = new LastClickFeatureSource( - this.layout, + this.theme, this.mapProperties.lastClickLocation, this.userRelatedState.addNewFeatureMode, ) @@ -414,7 +414,7 @@ export default class ThemeViewState implements SpecialVisualizationState { const storage = new SaveFeatureSourceToLocalStorage( this.osmConnection.Backend(), fs.layer.layerDef.id, - LayoutSource.fromCacheZoomLevel, + ThemeSource.fromCacheZoomLevel, fs, this.featureProperties, fs.layer.layerDef.maxAgeOfCache, @@ -509,7 +509,7 @@ export default class ThemeViewState implements SpecialVisualizationState { } }) - this.userRelatedState.markLayoutAsVisited(this.layout) + this.userRelatedState.markLayoutAsVisited(this.theme) this.selectedElement.addCallback((selected) => { if (selected === undefined) { @@ -517,8 +517,8 @@ export default class ThemeViewState implements SpecialVisualizationState { } }) - if (this.layout.customCss !== undefined && window.location.pathname.indexOf("theme") >= 0) { - Utils.LoadCustomCss(this.layout.customCss) + if (this.theme.customCss !== undefined && window.location.pathname.indexOf("theme") >= 0) { + Utils.LoadCustomCss(this.theme.customCss) } Hash.hash.addCallbackAndRunD((hash) => { @@ -738,11 +738,11 @@ export default class ThemeViewState implements SpecialVisualizationState { /** * MaxZoom for the summary layer */ - const normalLayers = this.layout.layers.filter(l => l.isNormal()) + const normalLayers = this.theme.layers.filter(l => l.isNormal()) const maxzoom = Math.min(...normalLayers.map((l) => l.minzoom)) - const layers = this.layout.layers.filter( + const layers = this.theme.layers.filter( (l) => Constants.priviliged_layers.indexOf(l.id) < 0 && l.source.geojsonSource === undefined && @@ -796,8 +796,8 @@ export default class ThemeViewState implements SpecialVisualizationState { this.closestFeatures.registerSource(specialLayers.favourite, "favourite") - if (this.layout?.lockLocation) { - const bbox = new BBox(this.layout.lockLocation) + if (this.theme?.lockLocation) { + const bbox = new BBox(this.theme.lockLocation) this.mapProperties.maxbounds.setData(bbox) ShowDataLayer.showRange( this.map, @@ -805,7 +805,7 @@ export default class ThemeViewState implements SpecialVisualizationState { this.featureSwitches.featureSwitchIsTesting, ) } - const currentViewLayer = this.layout.layers.find((l) => l.id === "current_view") + const currentViewLayer = this.theme.layers.find((l) => l.id === "current_view") if (currentViewLayer?.tagRenderings?.length > 0) { const params = MetaTagging.createExtraFuncParams(this) this.featureProperties.trackFeatureSource(specialLayers.current_view) @@ -814,7 +814,7 @@ export default class ThemeViewState implements SpecialVisualizationState { features, params, currentViewLayer, - this.layout, + this.theme, this.osmObjectDownloader, this.featureProperties, ) @@ -909,9 +909,9 @@ export default class ThemeViewState implements SpecialVisualizationState { */ private initActors() { - if (!this.layout.official) { + if (!this.theme.official) { // Add custom themes to the "visited custom themes" - const th = this.layout + const th = this.theme this.userRelatedState.addUnofficialTheme({ id: th.id, icon: th.icon, @@ -945,7 +945,7 @@ export default class ThemeViewState implements SpecialVisualizationState { this.selectedElement.addCallbackD(selected => { const [osm_type, osm_id] = selected.properties.id.split("/") const [lon, lat] = GeoOperations.centerpointCoordinates(selected) - const layer = this.layout.getMatchingLayer(selected.properties) + const layer = this.theme.getMatchingLayer(selected.properties) const nameOptions = [ selected?.properties?.name, @@ -987,7 +987,7 @@ export default class ThemeViewState implements SpecialVisualizationState { } /** - * Searches the appropriate layer - will first try if a special layer matches; if not, a normal layer will be used by delegating to the layout + * Searches the appropriate layer - will first try if a special layer matches; if not, a normal layer will be used by delegating to the theme */ public getMatchingLayer(properties: Record) { @@ -1002,15 +1002,15 @@ export default class ThemeViewState implements SpecialVisualizationState { return UserRelatedState.usersettingsConfig } if (id.startsWith(LastClickFeatureSource.newPointElementId)) { - return this.layout.layers.find((l) => l.id === "last_click") + return this.theme.layers.find((l) => l.id === "last_click") } if (id.startsWith("search_result")) { return GeocodingUtils.searchLayer } if (id === "location_track") { - return this.layout.layers.find((l) => l.id === "gps_track") + return this.theme.layers.find((l) => l.id === "gps_track") } - return this.layout.getMatchingLayer(properties) + return this.theme.getMatchingLayer(properties) } public async reportError(message: string | Error | XMLHttpRequest, extramessage: string = "") { @@ -1059,7 +1059,7 @@ export default class ThemeViewState implements SpecialVisualizationState { body: JSON.stringify({ stacktrace, message: "" + message, - layout: this.layout.id, + theme: this.theme.id, version: Constants.vNumber, language: this.userRelatedState.language.data, username: this.osmConnection.userDetails.data?.name, diff --git a/src/UI/AllThemesGui.svelte b/src/UI/AllThemesGui.svelte index ab6575b32b..4a66b37c88 100644 --- a/src/UI/AllThemesGui.svelte +++ b/src/UI/AllThemesGui.svelte @@ -12,7 +12,7 @@ import Constants from "../Models/Constants" import { ImmutableStore, Store, Stores, UIEventSource } from "../Logic/UIEventSource" import ThemesList from "./BigComponents/ThemesList.svelte" - import { MinimalLayoutInformation } from "../Models/ThemeConfig/LayoutConfig" + import { MinimalThemeInformation } from "../Models/ThemeConfig/ThemeConfig" import Eye from "../assets/svg/Eye.svelte" import LoginButton from "./Base/LoginButton.svelte" import Mastodon from "../assets/svg/Mastodon.svelte" @@ -46,16 +46,16 @@ let searchIsFocused = new UIEventSource(true) - const officialThemes: MinimalLayoutInformation[] = ThemeSearch.officialThemes.themes.filter(th => th.hideFromOverview === false) - const hiddenThemes: MinimalLayoutInformation[] = ThemeSearch.officialThemes.themes.filter(th => th.hideFromOverview === true) - let visitedHiddenThemes: Store = UserRelatedState.initDiscoveredHiddenThemes(state.osmConnection) + const officialThemes: MinimalThemeInformation[] = ThemeSearch.officialThemes.themes.filter(th => th.hideFromOverview === false) + const hiddenThemes: MinimalThemeInformation[] = ThemeSearch.officialThemes.themes.filter(th => th.hideFromOverview === true) + let visitedHiddenThemes: Store = UserRelatedState.initDiscoveredHiddenThemes(state.osmConnection) .map((knownIds) => hiddenThemes.filter((theme) => knownIds.indexOf(theme.id) >= 0 || state.osmConnection.userDetails.data.name === "Pieter Vander Vennet" )) - const customThemes: Store = Stores.ListStabilized(state.installedUserThemes) + const customThemes: Store = Stores.ListStabilized(state.installedUserThemes) .mapD(stableIds => Utils.NoNullInplace(stableIds.map(id => state.getUnofficialTheme(id)))) - function filtered(themes: Store): Store { + function filtered(themes: Store): Store { return searchStable.map(search => { if (!search) { return themes.data @@ -74,9 +74,9 @@ } - let officialSearched : Store= filtered(new ImmutableStore(officialThemes)) - let hiddenSearched: Store = filtered(visitedHiddenThemes) - let customSearched: Store = filtered(customThemes) + let officialSearched : Store= filtered(new ImmutableStore(officialThemes)) + let hiddenSearched: Store = filtered(visitedHiddenThemes) + let customSearched: Store = filtered(customThemes) let searchIsFocussed = new UIEventSource(false) diff --git a/src/UI/BigComponents/CopyrightAllIcons.svelte b/src/UI/BigComponents/CopyrightAllIcons.svelte index 78dd6c1290..a408bcfa21 100644 --- a/src/UI/BigComponents/CopyrightAllIcons.svelte +++ b/src/UI/BigComponents/CopyrightAllIcons.svelte @@ -6,7 +6,7 @@ export let state: SpecialVisualizationState - let layoutToUse = state.layout + let layoutToUse = state.theme let iconAttributions: string[] = layoutToUse.getUsedImages() const allLicenses = {} diff --git a/src/UI/BigComponents/CopyrightPanel.svelte b/src/UI/BigComponents/CopyrightPanel.svelte index 67410dba7e..893b568829 100644 --- a/src/UI/BigComponents/CopyrightPanel.svelte +++ b/src/UI/BigComponents/CopyrightPanel.svelte @@ -18,7 +18,7 @@ export let state: SpecialVisualizationState const t = Translations.t.general.attribution - const layoutToUse = state.layout + const layoutToUse = state.theme let maintainer: Translation = undefined if (layoutToUse.credits !== undefined && layoutToUse.credits !== "") { @@ -122,7 +122,7 @@ {/if} {#if maintainer !== undefined}
- +
{/if} diff --git a/src/UI/BigComponents/ExtraLinkButton.svelte b/src/UI/BigComponents/ExtraLinkButton.svelte index eba6f3406c..0c1c2bcbab 100644 --- a/src/UI/BigComponents/ExtraLinkButton.svelte +++ b/src/UI/BigComponents/ExtraLinkButton.svelte @@ -9,8 +9,8 @@ import Icon from "../Map/Icon.svelte" export let state: SpecialVisualizationState - let theme = state.layout?.id ?? "" - let config: ExtraLinkConfig = state.layout.extraLink + let theme = state.theme?.id ?? "" + let config: ExtraLinkConfig = state.theme.extraLink let basepath = window.location.host let showWelcomeMessageSwitch = state.featureSwitches.featureSwitchWelcomeMessage const isIframe = Utils.isIframe @@ -42,7 +42,7 @@ {#if config.text} {:else} - + {/if} diff --git a/src/UI/BigComponents/FilterPage.svelte b/src/UI/BigComponents/FilterPage.svelte index fb3301c8d1..693c6ad3da 100644 --- a/src/UI/BigComponents/FilterPage.svelte +++ b/src/UI/BigComponents/FilterPage.svelte @@ -14,7 +14,7 @@ export let state: ThemeViewState export let onlyLink: boolean - let layout = state.layout + let theme = state.theme let allEnabled: boolean let allDisabled: boolean @@ -70,7 +70,7 @@ - {#each layout.layers as layer} + {#each theme.layers as layer} {/each} - {#each layout.tileLayerSources as tilesource} + {#each theme.tileLayerSources as tilesource} usersettings, "usersettings", true) - let layout = state.layout + let theme = state.theme let featureSwitches = state.featureSwitches let showHome = featureSwitches.featureSwitchBackToThemeOverview let pg = state.guistate.pageStates @@ -108,7 +108,7 @@
- +
@@ -161,12 +161,12 @@ - + - - + + @@ -193,25 +193,25 @@ {/if} - {#if layout.official} + {#if theme.official} - + - + {/if} diff --git a/src/UI/BigComponents/ShareScreen.svelte b/src/UI/BigComponents/ShareScreen.svelte index 8c3160e66d..e4c91b1427 100644 --- a/src/UI/BigComponents/ShareScreen.svelte +++ b/src/UI/BigComponents/ShareScreen.svelte @@ -25,8 +25,8 @@ * In some cases (local deploys, custom themes), we need to set the URL to `/theme.html?layout=xyz` instead of `/xyz?...` * Note that the 'layout='-param will be included automatically */ - let needsThemeRedirect = url.port !== "" || url.hostname.match(/^[0-9]/) || !state.layout.official - let layoutId = state.layout.id + let needsThemeRedirect = url.port !== "" || url.hostname.match(/^[0-9]/) || !state.theme.official + let layoutId = state.theme.id let baseLink = `${url.protocol}//${url.host}/${needsThemeRedirect ? "theme.html" : layoutId}?` let showWelcomeMessage = true @@ -44,7 +44,7 @@ enableBackground: boolean, enableGeolocation: boolean ) { - const layout = state.layout + const layout = state.theme let excluded = Utils.NoNull([ showWelcomeMessage ? undefined : "fs-welcome-message", enableLogin ? undefined : "fs-enable-login", @@ -99,7 +99,7 @@ ${ enableGeolocation ? 'allow="geolocation"' : "" } width="100%" height="100%" style="min-width: 250px; min-height: 250px" - title="${state.layout.title?.txt ?? "MapComplete"} with MapComplete"> + title="${state.theme.title?.txt ?? "MapComplete"} with MapComplete"> ` Array.from(state.layerState.filteredLayers.values()).forEach((flayer) => @@ -163,7 +163,7 @@ state.guistate.filtersPanelIsOpened.set(true)} + on:click={() => state.guistate.pageStates.filter.set(true)} > diff --git a/src/UI/BigComponents/Summary.svelte b/src/UI/BigComponents/Summary.svelte index b1b765594b..1b10aebee3 100644 --- a/src/UI/BigComponents/Summary.svelte +++ b/src/UI/BigComponents/Summary.svelte @@ -10,7 +10,7 @@ export let i: number = undefined let id = feature.properties.id let tags = state.featureProperties.getStore(id) - let layer: LayerConfig = state.layout.getMatchingLayer(tags.data) + let layer: LayerConfig = state.theme.getMatchingLayer(tags.data) diff --git a/src/UI/BigComponents/ThemeButton.svelte b/src/UI/BigComponents/ThemeButton.svelte index 7acb3ad3a3..5f06e68c61 100644 --- a/src/UI/BigComponents/ThemeButton.svelte +++ b/src/UI/BigComponents/ThemeButton.svelte @@ -1,12 +1,12 @@ diff --git a/src/UI/Popup/MarkAsFavouriteMini.svelte b/src/UI/Popup/MarkAsFavouriteMini.svelte index 3f9a5648fd..67d4f18996 100644 --- a/src/UI/Popup/MarkAsFavouriteMini.svelte +++ b/src/UI/Popup/MarkAsFavouriteMini.svelte @@ -20,7 +20,7 @@ const t = Translations.t.favouritePoi function markFavourite(isFavourite: boolean) { - state.favourites.markAsFavourite(feature, layer.id, state.layout.id, tags, isFavourite) + state.favourites.markAsFavourite(feature, layer.id, state.theme.id, tags, isFavourite) } diff --git a/src/UI/Popup/MinimapViz.svelte b/src/UI/Popup/MinimapViz.svelte index 8cdba14400..e18a269e40 100644 --- a/src/UI/Popup/MinimapViz.svelte +++ b/src/UI/Popup/MinimapViz.svelte @@ -72,7 +72,7 @@ ShowDataLayer.showMultipleLayers( mlmap, new StaticFeatureSource(featuresToShow), - state.layout.layers, + state.theme.layers, { zoomToFeatures: true } ) diff --git a/src/UI/Popup/MoveWizardState.ts b/src/UI/Popup/MoveWizardState.ts index 23dbc8c975..c463b6747f 100644 --- a/src/UI/Popup/MoveWizardState.ts +++ b/src/UI/Popup/MoveWizardState.ts @@ -94,7 +94,7 @@ export class MoveWizardState { const matchingPresets = this.layer.presets.filter(preset => preset.preciseInput.snapToLayers && new And(preset.tags).matchesProperties(tags)) const matchingPreset = matchingPresets.flatMap(pr => pr.preciseInput?.snapToLayers) for (const layerId of matchingPreset) { - const snapOntoLayer = this._state.layout.getLayer(layerId) + const snapOntoLayer = this._state.theme.getLayer(layerId) const text = t.reasons.reasonSnapTo.PartialSubsTr("name", snapOntoLayer.snapName) reasons.push({ text, @@ -133,7 +133,7 @@ export class MoveWizardState { snappedTo, { reason: reason.changesetCommentValue, - theme: state.layout.id, + theme: state.theme.id, }), ) featureToMove.properties._lat = loc.lat @@ -152,7 +152,7 @@ export class MoveWizardState { featureToMove.properties, { changeType: "relocated", - theme: state.layout.id, + theme: state.theme.id, }, ), ) diff --git a/src/UI/Popup/MultiApply.ts b/src/UI/Popup/MultiApply.ts index ca0a5382b6..7ab22ee0c0 100644 --- a/src/UI/Popup/MultiApply.ts +++ b/src/UI/Popup/MultiApply.ts @@ -64,7 +64,7 @@ class MultiApplyExecutor { const keysToChange = this.params.keysToApply const overwrite = this.params.overwrite const selfTags = this.params.tagsSource.data - const theme = this.params.state.layout.id + const theme = this.params.state.theme.id for (const id of featuresToChange) { const tagsToApply: Tag[] = [] const otherFeatureTags = allElements.getStore(id).data diff --git a/src/UI/Popup/Notes/CreateNewNote.svelte b/src/UI/Popup/Notes/CreateNewNote.svelte index 9bc1437ad9..ab1a74c4ac 100644 --- a/src/UI/Popup/Notes/CreateNewNote.svelte +++ b/src/UI/Popup/Notes/CreateNewNote.svelte @@ -47,7 +47,7 @@ return } const loc = coordinate.data - txt += "\n\n #MapComplete #" + state?.layout?.id + txt += "\n\n #MapComplete #" + state?.theme?.id const id = await state?.osmConnection?.openNote(loc.lat, loc.lon, txt) console.log("Created a note, got id", id) const feature = >{ diff --git a/src/UI/Popup/PlantNetDetectionViz.ts b/src/UI/Popup/PlantNetDetectionViz.ts index 101f37ec62..595a8262ec 100644 --- a/src/UI/Popup/PlantNetDetectionViz.ts +++ b/src/UI/Popup/PlantNetDetectionViz.ts @@ -49,7 +49,7 @@ export class PlantNetDetectionViz implements SpecialVisualization { ]), tags.data, { - theme: state.layout.id, + theme: state.theme.id, changeType: "plantnet-ai-detection", } ) diff --git a/src/UI/Popup/QrCode.svelte b/src/UI/Popup/QrCode.svelte index ddaa095bfc..f1c12d172e 100644 --- a/src/UI/Popup/QrCode.svelte +++ b/src/UI/Popup/QrCode.svelte @@ -17,7 +17,7 @@ let [lon, lat] = GeoOperations.centerpointCoordinates(feature) const includeLayout = window.location.pathname.split("/").at(-1).startsWith("theme") - const layout = includeLayout ? "layout=" + state.layout.id + "&" : "" + const layout = includeLayout ? "layout=" + state.theme.id + "&" : "" let id: Store = tags.mapD((tags) => tags.id) let url = id.mapD( (id) => diff --git a/src/UI/Popup/ShareLinkViz.ts b/src/UI/Popup/ShareLinkViz.ts index f243c3cf8b..123883c636 100644 --- a/src/UI/Popup/ShareLinkViz.ts +++ b/src/UI/Popup/ShareLinkViz.ts @@ -30,9 +30,9 @@ export class ShareLinkViz implements SpecialVisualization { const text = args[1] const generateShareData = () => { - const title = state?.layout?.title?.txt ?? "MapComplete" + const title = state?.theme?.title?.txt ?? "MapComplete" - let matchingLayer: LayerConfig = state?.layout?.getMatchingLayer(tagSource?.data) + let matchingLayer: LayerConfig = state?.theme?.getMatchingLayer(tagSource?.data) let name = matchingLayer?.title?.GetRenderValue(tagSource.data)?.Subs(tagSource.data)?.txt ?? tagSource.data?.name ?? @@ -49,7 +49,7 @@ export class ShareLinkViz implements SpecialVisualization { return { title: name, url: url, - text: state?.layout?.shortDescription?.txt ?? "MapComplete", + text: state?.theme?.shortDescription?.txt ?? "MapComplete", } } diff --git a/src/UI/Popup/SplitRoadWizard.svelte b/src/UI/Popup/SplitRoadWizard.svelte index ac0a705ede..48017e175f 100644 --- a/src/UI/Popup/SplitRoadWizard.svelte +++ b/src/UI/Popup/SplitRoadWizard.svelte @@ -58,7 +58,7 @@ id, splitPoints.data.map((ff) => <[number, number]>(ff.geometry).coordinates), { - theme: state?.layout?.id, + theme: state?.theme?.id, }, 5 ) diff --git a/src/UI/Popup/TagApplyButton.ts b/src/UI/Popup/TagApplyButton.ts index c42d0debdd..7389dd0de4 100644 --- a/src/UI/Popup/TagApplyButton.ts +++ b/src/UI/Popup/TagApplyButton.ts @@ -144,7 +144,7 @@ export default class TagApplyButton implements AutoAction, SpecialVisualization new And(tagsToApply.data), tags.data, // We pass in the tags of the selected element, not the tags of the target element! { - theme: state.layout.id, + theme: state.theme.id, changeType: "answer", } ) diff --git a/src/UI/Popup/TagRendering/TagRenderingQuestion.svelte b/src/UI/Popup/TagRendering/TagRenderingQuestion.svelte index 4d87e56cb8..510a0a6170 100644 --- a/src/UI/Popup/TagRendering/TagRenderingQuestion.svelte +++ b/src/UI/Popup/TagRendering/TagRenderingQuestion.svelte @@ -283,7 +283,7 @@ } dispatch("saved", { config, applied: selectedTags }) const change = new ChangeTagAction(tags.data.id, selectedTags, tags.data, { - theme: tags.data["_orig_theme"] ?? state.layout.id, + theme: tags.data["_orig_theme"] ?? state.theme.id, changeType: "answer", }) freeformInput.set(undefined) @@ -327,7 +327,7 @@ function clearAnswer() { const tagsToSet = settableKeys.data.map(k => new Tag(k, "")) const change = new ChangeTagAction(tags.data.id, new And(tagsToSet), tags.data, { - theme: tags.data["_orig_theme"] ?? state.layout.id, + theme: tags.data["_orig_theme"] ?? state.theme.id, changeType: "answer", }) freeformInput.set(undefined) diff --git a/src/UI/QueryParameterDocumentation.ts b/src/UI/QueryParameterDocumentation.ts index 37c3dc87ff..f95ca4de04 100644 --- a/src/UI/QueryParameterDocumentation.ts +++ b/src/UI/QueryParameterDocumentation.ts @@ -5,7 +5,7 @@ import List from "./Base/List" import Translations from "./i18n/Translations" import { QueryParameters } from "../Logic/Web/QueryParameters" import FeatureSwitchState from "../Logic/State/FeatureSwitchState" -import LayoutConfig from "../Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../Models/ThemeConfig/ThemeConfig" import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor" import MarkdownUtils from "../Utils/MarkdownUtils" @@ -27,7 +27,7 @@ export default class QueryParameterDocumentation { ] public static UrlParamDocs(): Map { - const dummyLayout = new LayoutConfig({ + const dummyLayout = new ThemeConfig({ id: ">theme<", title: { en: "" }, description: "A theme to generate docs with", diff --git a/src/UI/Search/GeocodeResult.svelte b/src/UI/Search/GeocodeResult.svelte index 5addea02c5..d5add5893e 100644 --- a/src/UI/Search/GeocodeResult.svelte +++ b/src/UI/Search/GeocodeResult.svelte @@ -20,7 +20,7 @@ let tags: UIEventSource> let descriptionTr: TagRenderingConfig = undefined if (entry.feature?.properties?.id) { - layer = state.layout.getMatchingLayer(entry.feature.properties) + layer = state.theme.getMatchingLayer(entry.feature.properties) tags = state.featureProperties.getStore(entry.feature.properties.id) descriptionTr = layer?.tagRenderings?.find(tr => tr.labels.indexOf("description") >= 0) } diff --git a/src/UI/Search/ThemeResult.svelte b/src/UI/Search/ThemeResult.svelte index 9e1f93127c..c1d94aa5c2 100644 --- a/src/UI/Search/ThemeResult.svelte +++ b/src/UI/Search/ThemeResult.svelte @@ -1,11 +1,11 @@ {#if entry} diff --git a/src/UI/Search/ThemeResults.svelte b/src/UI/Search/ThemeResults.svelte index 6b87516d94..5cb9d79b17 100644 --- a/src/UI/Search/ThemeResults.svelte +++ b/src/UI/Search/ThemeResults.svelte @@ -14,7 +14,7 @@ export let state: SpecialVisualizationState let searchTerm = state.searchState.searchTerm - let recentThemes = state.userRelatedState.recentlyVisitedThemes.value.map(themes => themes.filter(th => th !== state.layout.id).slice(0, 6)) + let recentThemes = state.userRelatedState.recentlyVisitedThemes.value.map(themes => themes.filter(th => th !== state.theme.id).slice(0, 6)) let themeResults = state.searchState.themeSuggestions const t =Translations.t.general.search diff --git a/src/UI/SpecialVisualization.ts b/src/UI/SpecialVisualization.ts index 561a349cbf..2a9f6dabd5 100644 --- a/src/UI/SpecialVisualization.ts +++ b/src/UI/SpecialVisualization.ts @@ -1,6 +1,6 @@ import { Store, UIEventSource } from "../Logic/UIEventSource" import BaseUIElement from "./BaseUIElement" -import LayoutConfig from "../Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../Models/ThemeConfig/ThemeConfig" import { FeatureSource, IndexedFeatureSource, WritableFeatureSource } from "../Logic/FeatureSource/FeatureSource" import { OsmConnection } from "../Logic/Osm/OsmConnection" import { Changes } from "../Logic/Osm/Changes" @@ -19,7 +19,7 @@ import FavouritesFeatureSource from "../Logic/FeatureSource/Sources/FavouritesFe import { ProvidedImage } from "../Logic/ImageProviders/ImageProvider" import GeoLocationHandler from "../Logic/Actors/GeoLocationHandler" import { SummaryTileSourceRewriter } from "../Logic/FeatureSource/TiledFeatureSource/SummaryTileSource" -import LayoutSource from "../Logic/FeatureSource/Sources/LayoutSource" +import ThemeSource from "../Logic/FeatureSource/Sources/ThemeSource" import { Map as MlMap } from "maplibre-gl" import ShowDataLayer from "./Map/ShowDataLayer" import { CombinedFetcher } from "../Logic/Web/NearbyImagesSearch" @@ -33,13 +33,13 @@ import FeaturePropertiesStore from "../Logic/FeatureSource/Actors/FeaturePropert */ export interface SpecialVisualizationState { readonly guistate: MenuState - readonly layout: LayoutConfig + readonly theme: ThemeConfig readonly featureSwitches: FeatureSwitchState readonly layerState: LayerState readonly featureProperties: FeaturePropertiesStore - readonly indexedFeatures: IndexedFeatureSource & LayoutSource + readonly indexedFeatures: IndexedFeatureSource & ThemeSource /** * Some features will create a new element that should be displayed. * These can be injected by appending them to this featuresource (and pinging it) diff --git a/src/UI/SpecialVisualizations.ts b/src/UI/SpecialVisualizations.ts index f79c117a30..5d848f48c0 100644 --- a/src/UI/SpecialVisualizations.ts +++ b/src/UI/SpecialVisualizations.ts @@ -164,7 +164,7 @@ class StealViz implements SpecialVisualization { const tagRenderings: [LayerConfig, TagRenderingConfig][] = [] for (const layerAndTagRenderingId of layerAndtagRenderingIds.split(";")) { const [layerId, tagRenderingId] = layerAndTagRenderingId.trim().split(".") - const layer = state.layout.layers.find((l) => l.id === layerId) + const layer = state.theme.layers.find((l) => l.id === layerId) const tagRendering = layer.tagRenderings.find((tr) => tr.id === tagRenderingId) tagRenderings.push([layer, tagRendering]) } @@ -444,7 +444,7 @@ export default class SpecialVisualizations { Locale.showLinkToWeblate.map((showTranslations) => { const languages = showTranslations ? LanguageUtils.usedLanguagesSorted - : state.layout.language + : state.theme.language return new SvelteUIElement(LanguagePicker, { assignTo: state.userRelatedState.language, availableLanguages: languages, @@ -971,7 +971,7 @@ export default class SpecialVisualizations { return undefined } const allUnits: Unit[] = [].concat( - ...(state?.layout?.layers?.map((lyr) => lyr.units) ?? []) + ...(state?.theme?.layers?.map((lyr) => lyr.units) ?? []) ) const unit = allUnits.filter((unit) => unit.isApplicableToKey(key) @@ -1125,7 +1125,7 @@ export default class SpecialVisualizations { ) => new VariableUiElement( tagsSource.map((tags) => { - if (state.layout === undefined) { + if (state.theme === undefined) { return "" } const title = layer?.title?.GetRenderValue(tags) @@ -1276,7 +1276,7 @@ export default class SpecialVisualizations { constr: (state) => { return new Combine( - state.layout.layers + state.theme.layers .filter( (l) => l.name !== null && @@ -1995,7 +1995,7 @@ export default class SpecialVisualizations { layer: LayerConfig ): BaseUIElement { const translation = tagSource.map((tags) => { - const layer = state.layout.getMatchingLayer(tags) + const layer = state.theme.getMatchingLayer(tags) return layer?.getMostMatchingPreset(tags)?.description }) return new VariableUiElement(translation) diff --git a/src/UI/StatisticsGUI.ts b/src/UI/StatisticsGUI.ts index 297c95eb23..8051efdba8 100644 --- a/src/UI/StatisticsGUI.ts +++ b/src/UI/StatisticsGUI.ts @@ -11,7 +11,7 @@ import BaseUIElement from "./BaseUIElement" import Title from "./Base/Title" import { FixedUiElement } from "./Base/FixedUiElement" import List from "./Base/List" -import LayoutConfig from "../Models/ThemeConfig/LayoutConfig" +import ThemeConfig from "../Models/ThemeConfig/ThemeConfig" import mcChanges from "../../src/assets/generated/themes/mapcomplete-changes.json" import SvelteUIElement from "./Base/SvelteUIElement" import Filterview from "./BigComponents/Filterview.svelte" @@ -24,7 +24,7 @@ import { Feature } from "geojson" class StatsticsForOverviewFile extends Combine { constructor(homeUrl: string, paths: string[]) { paths = paths.filter((p) => !p.endsWith("file-overview.json")) - const layer = new LayoutConfig(mcChanges, true).layers[0] + const layer = new ThemeConfig(mcChanges, true).layers[0] const filteredLayer = new FilteredLayer(layer) const filterPanel = new Combine([ new Title("Filters"), diff --git a/src/UI/Studio/EditLayerState.ts b/src/UI/Studio/EditLayerState.ts index 33cde48855..df80ef7dac 100644 --- a/src/UI/Studio/EditLayerState.ts +++ b/src/UI/Studio/EditLayerState.ts @@ -18,7 +18,7 @@ import { OsmConnection } from "../../Logic/Osm/OsmConnection" import { OsmTags } from "../../Models/OsmFeature" import { Feature, Point } from "geojson" import LayerConfig from "../../Models/ThemeConfig/LayerConfig" -import { LayoutConfigJson } from "../../Models/ThemeConfig/Json/LayoutConfigJson" +import { ThemeConfigJson } from "../../Models/ThemeConfig/Json/ThemeConfigJson" import { PrepareTheme } from "../../Models/ThemeConfig/Conversion/PrepareTheme" import { ConversionContext } from "../../Models/ThemeConfig/Conversion/ConversionContext" import { LocalStorageSource } from "../../Logic/Web/LocalStorageSource" @@ -334,7 +334,7 @@ export default class EditLayerState extends EditJsonState { return 0 } } - public readonly layout: { getMatchingLayer: (key: any) => LayerConfig } + public readonly theme: { getMatchingLayer: (key: any) => LayerConfig } public readonly featureSwitches: { featureSwitchIsDebugging: UIEventSource } @@ -359,7 +359,7 @@ export default class EditLayerState extends EditJsonState { options: { expertMode: UIEventSource } ) { super(schema, server, "layers", osmConnection, options) - this.layout = { + this.theme = { getMatchingLayer: () => { try { return new LayerConfig(this.configuration.data, "dynamic") @@ -458,7 +458,8 @@ export default class EditLayerState extends EditJsonState { } const state: DesugaringContext = { tagRenderings: sharedQuestions, - sharedLayers: layers + sharedLayers: layers, + tagRenderingOrder: [] } const prepare = this.buildValidation(state) const context = ConversionContext.construct([], ["prepare"]) @@ -472,7 +473,7 @@ export default class EditLayerState extends EditJsonState { } } -export class EditThemeState extends EditJsonState { +export class EditThemeState extends EditJsonState { constructor( schema: ConfigMeta[], server: StudioServer, @@ -483,7 +484,7 @@ export class EditThemeState extends EditJsonState { this.setupFixers() } - protected buildValidation(state: DesugaringContext): Conversion { + protected buildValidation(state: DesugaringContext): Conversion { return new Pipe( new PrevalidateTheme(), new Pipe( @@ -513,7 +514,7 @@ export class EditThemeState extends EditJsonState { }) } - protected async validate(configuration: Partial) { + protected async validate(configuration: Partial) { const layers = AllSharedLayers.getSharedLayersConfigs() for (const l of configuration.layers ?? []) { @@ -534,7 +535,8 @@ export class EditThemeState extends EditJsonState { } const state: DesugaringContext = { tagRenderings: sharedQuestions, - sharedLayers: layers + sharedLayers: layers, + tagRenderingOrder: [] } const prepare = this.buildValidation(state) const context = ConversionContext.construct([], ["prepare"]) @@ -542,7 +544,7 @@ export class EditThemeState extends EditJsonState { Utils.NoNullInplace(configuration.layers) } try { - prepare.convert(configuration, context) + prepare.convert(configuration, context) } catch (e) { console.error(e) context.err(e) diff --git a/src/UI/Studio/StudioServer.ts b/src/UI/Studio/StudioServer.ts index 216c22b186..bf6ad5ca27 100644 --- a/src/UI/Studio/StudioServer.ts +++ b/src/UI/Studio/StudioServer.ts @@ -2,7 +2,7 @@ import { Utils } from "../../Utils" import Constants from "../../Models/Constants" import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson" import { Store, UIEventSource } from "../../Logic/UIEventSource" -import { LayoutConfigJson } from "../../Models/ThemeConfig/Json/LayoutConfigJson" +import { ThemeConfigJson } from "../../Models/ThemeConfig/Json/ThemeConfigJson" /** * A small class wrapping around the Server API. @@ -71,12 +71,12 @@ export default class StudioServer { } async fetch(layerId: string, category: "layers", uid?: number): Promise - async fetch(layerId: string, category: "themes", uid?: number): Promise + async fetch(layerId: string, category: "themes", uid?: number): Promise async fetch( layerId: string, category: "layers" | "themes", uid?: number - ): Promise { + ): Promise { try { return await Utils.downloadJson(this.urlFor(layerId, category, uid)) } catch (e) { diff --git a/src/UI/ThemeViewGUI.svelte b/src/UI/ThemeViewGUI.svelte index f14ca14f8d..e9b103de99 100644 --- a/src/UI/ThemeViewGUI.svelte +++ b/src/UI/ThemeViewGUI.svelte @@ -53,7 +53,7 @@ export let state: ThemeViewState - let layout = state.layout + let theme = state.theme let maplibremap: UIEventSource = state.map let state_selectedElement = state.selectedElement let selectedElement: UIEventSource = new UIEventSource(undefined) @@ -65,7 +65,7 @@ let gpsButtonAriaLabel = state.geolocation.geolocationState.gpsStateExplanation let debug = state.featureSwitches.featureSwitchIsDebugging let featureSwitches: FeatureSwitchState = state.featureSwitches - let currentViewLayer: LayerConfig = layout.layers.find((l) => l.id === "current_view") + let currentViewLayer: LayerConfig = theme.layers.find((l) => l.id === "current_view") let rasterLayer: Store = state.mapProperties.rasterLayer let currentZoom = state.mapProperties.zoom let showCrosshair = state.userRelatedState.showCrosshair @@ -213,7 +213,7 @@
- {#if $addNewFeatureMode.indexOf("button") >= 0 && ((state.layout.hasPresets() && state.layout.enableAddNewPoints) || state.layout.hasNoteLayer())} + {#if $addNewFeatureMode.indexOf("button") >= 0 && ((state.theme.hasPresets() && state.theme.enableAddNewPoints) || state.theme.hasNoteLayer())}