From 03615d7c3f63780131bc5ce0a8fe9e68b1c8b329 Mon Sep 17 00:00:00 2001 From: seppesantens Date: Mon, 12 Jul 2021 19:39:16 +0000 Subject: [PATCH 01/26] Translated using Weblate (Dutch) Currently translated at 57.7% (235 of 407 strings) Translation: MapComplete/themes Translate-URL: https://hosted.weblate.org/projects/mapcomplete/themes/nl/ --- langs/themes/nl.json | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/langs/themes/nl.json b/langs/themes/nl.json index ca29b7880..c2c585cbd 100644 --- a/langs/themes/nl.json +++ b/langs/themes/nl.json @@ -329,7 +329,8 @@ "render": "{name}", "question": "Wat is de naam van dit Klimzaal?" } - } + }, + "description": "Een klimzaal" }, "2": { "name": "Klimroute", @@ -359,6 +360,11 @@ "question": "Hoe moeilijk is deze klimroute volgens het Franse/Belgische systeem?", "render": "De klimmoeilijkheid is {climbing:grade:french} volgens het Franse/Belgische systeem" } + }, + "presets": { + "0": { + "title": "Klimroute" + } } }, "3": { @@ -422,6 +428,9 @@ "then": "Klimmen is hier niet toegelaten" } } + }, + "1": { + "render": "{name}" } } } @@ -1033,10 +1042,30 @@ "title": { "render": "Oplaadpunt" }, - "name": "Oplaadpunten" + "name": "Oplaadpunten", + "tagRenderings": { + "6": { + "mappings": { + "3": { + "then": "eVgo" + }, + "2": { + "then": "Blink" + }, + "1": { + "then": "AeroVironment" + }, + "0": { + "then": "Maakt geen deel uit van een netwerk" + } + }, + "render": "{network}" + } + } } }, - "title": "Oplaadpunten" + "title": "Oplaadpunten", + "shortDescription": "Een wereldwijde kaart van oplaadpunten" }, "shops": { "layers": { From 3a6727f7eb02c544ab7dbe866b582f949d27ca20 Mon Sep 17 00:00:00 2001 From: Irina Date: Tue, 13 Jul 2021 11:28:21 +0000 Subject: [PATCH 02/26] Translated using Weblate (Russian) Currently translated at 52.8% (215 of 407 strings) Translation: MapComplete/themes Translate-URL: https://hosted.weblate.org/projects/mapcomplete/themes/ru/ --- langs/themes/ru.json | 217 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 196 insertions(+), 21 deletions(-) diff --git a/langs/themes/ru.json b/langs/themes/ru.json index c2d70c10f..a6eec34f2 100644 --- a/langs/themes/ru.json +++ b/langs/themes/ru.json @@ -278,7 +278,19 @@ } }, "6": { - "question": "Кто может использовать эту станцию утилизации?" + "question": "Кто может использовать эту станцию утилизации?", + "mappings": { + "3": { + "then": "Любой может воспользоваться этой станцией утилизации" + }, + "2": { + "then": "Любой может воспользоваться этой станцией утилизации" + } + } + }, + "7": { + "question": "К какой сети относится эта станция? (пропустите, если неприменимо)", + "render": "Эта станция - часть сети {network}" } } } @@ -301,7 +313,7 @@ }, "6": { "render": "{network}", - "question": "К какой сети относится эта станция?", + "question": "К какой сети относится эта зарядная станция?", "mappings": { "0": { "then": "Не является частью более крупной сети" @@ -335,6 +347,12 @@ "0": { "render": "{name}" } + }, + "presets": { + "0": { + "description": "Клуб скалолазания", + "title": "Клуб скалолазания" + } } }, "1": { @@ -376,6 +394,16 @@ "then": "Спортивное скалолазание здесь невозможно" } } + }, + "2": { + "mappings": { + "3": { + "then": "Только членам клуба" + } + } + }, + "0": { + "question": "Есть ли (неофициальный) веб-сайт с более подробной информацией (напр., topos)?" } } }, @@ -383,7 +411,8 @@ "title": "Cyclofix - открытая карта для велосипедистов" }, "drinking_water": { - "title": "Питьевая вода" + "title": "Питьевая вода", + "description": "На этой карте показываются и могут быть легко добавлены общедоступные точки питьевой воды" }, "facadegardens": { "layers": { @@ -391,6 +420,26 @@ "tagRenderings": { "4": { "render": "Дата строительства сада: {start_date}" + }, + "7": { + "question": "Дополнительная информация о саде (если требуется или еще не указана выше)", + "render": "Подробнее: {description}" + }, + "6": { + "question": "Какие виды растений обитают здесь?" + }, + "3": { + "mappings": { + "1": { + "then": "Нет бочки с дождевой водой" + }, + "0": { + "then": "Есть бочка с дождевой водой" + } + } + }, + "2": { + "question": "Сад расположен на солнечной стороне или в тени?" } } } @@ -401,7 +450,18 @@ "0": { "tagRenderings": { "3": { - "render": "{website}" + "render": "{website}", + "question": "Какой веб-сайт у этого магазина?" + }, + "8": { + "mappings": { + "1": { + "then": "Приносить свою тару не разрешено" + } + } + }, + "4": { + "question": "Какой телефон?" } } } @@ -419,20 +479,73 @@ "mappings": { "3": { "then": " Тип стены." + }, + "0": { + "then": "Тип гидранта не определён." + } + }, + "question": "К какому типу относится этот гидрант?" + }, + "2": { + "mappings": { + "2": { + "then": "Гидрант демонтирован." + }, + "0": { + "then": "Гидрант (полностью или частично) в рабочем состоянии." } } + }, + "0": { + "mappings": { + "2": { + "then": "Гидрант красного цвета." + }, + "1": { + "then": "Гидрант жёлтого цвета." + }, + "0": { + "then": "Цвет гидранта не определён." + } + }, + "render": "Цвет гидранта {colour}", + "question": "Какого цвета гидрант?" } }, "presets": { "0": { "title": "Пожарный гидрант" } - } + }, + "description": "Слой карты, отображающий пожарные гидранты.", + "name": "Карта пожарных гидрантов" }, "1": { "title": { "render": "Огнетушители" - } + }, + "presets": { + "0": { + "description": "Огнетушитель - небольшое переносное устройство для тушения огня", + "title": "Огнетушитель" + } + }, + "tagRenderings": { + "0": { + "mappings": { + "1": { + "then": "Снаружи." + }, + "0": { + "then": "Внутри." + } + }, + "question": "Где это расположено?", + "render": "Местоположение: {location}" + } + }, + "description": "Слой карты, отображающий огнетушители.", + "name": "Карта огнетушителей." }, "2": { "title": { @@ -440,9 +553,25 @@ }, "tagRenderings": { "0": { - "question": "Как называется пожарная часть?" + "question": "Как называется эта пожарная часть?", + "render": "Эта часть называется {name}." + }, + "2": { + "render": "Эта часть расположена в {addr:place}.", + "question": "Где расположена часть? (напр., название населённого пункта)" + }, + "1": { + "render": "Часть расположена вдоль шоссе {addr:street}.", + "question": " По какому адресу расположена эта часть?" } - } + }, + "presets": { + "0": { + "title": "Пожарная часть" + } + }, + "description": "Слой карты, отображающий пожарные части.", + "name": "Карта пожарных частей" }, "3": { "title": { @@ -450,16 +579,28 @@ }, "tagRenderings": { "0": { - "question": "Как называется станция скорой помощи?" + "question": "Как называется эта станция скорой помощи?", + "render": "Эта станция называется {name}." + }, + "2": { + "question": "Где расположена станция? (напр., название населённого пункта)" + }, + "1": { + "render": "Эта станция расположена вдоль шоссе {addr:street}.", + "question": " По какому адресу расположена эта станция?" } }, "presets": { "0": { - "title": "Станция скорой помощи" + "title": "Станция скорой помощи", + "description": "Добавить станцию скорой помощи на карту" } - } + }, + "name": "Карта станций скорой помощи" } - } + }, + "shortDescription": "Карта пожарных гидрантов, огнетушителей, пожарных станций и станций скорой помощи.", + "title": "Пожарные гидранты, огнетушители, пожарные станции и станции скорой помощи." }, "shops": { "layers": { @@ -478,7 +619,7 @@ }, "tagRenderings": { "1": { - "question": "Как называется магазин?" + "question": "Как называется этот магазин?" }, "2": { "mappings": { @@ -494,19 +635,24 @@ "6": { "then": "Автосалон" } - } + }, + "question": "Что продаётся в этом магазине?" }, "3": { - "render": "{phone}" + "render": "{phone}", + "question": "Какой телефон?" }, "4": { - "render": "{website}" + "render": "{website}", + "question": "Какой веб-сайт у этого магазина?" }, "5": { - "render": "{email}" + "render": "{email}", + "question": "Каков адрес электронной почты этого магазина?" }, "6": { - "render": "{opening_hours_table(opening_hours)}" + "render": "{opening_hours_table(opening_hours)}", + "question": "Каковы часы работы этого магазина?" } }, "presets": { @@ -514,15 +660,44 @@ "title": "Магазин", "description": "Добавить новый магазин" } - } + }, + "description": "Магазин" } - } + }, + "title": "Открыть карту магазинов" }, "toilets": { "title": "Открытая карта туалетов", "description": "Карта общественных туалетов" }, "trees": { - "title": "Деревья" + "title": "Деревья", + "description": "Нанесите все деревья на карту!", + "shortDescription": "Карта деревьев" + }, + "sport_pitches": { + "shortDescription": "Карта, отображающая спортивные площадки", + "title": "Спортивные площадки" + }, + "playgrounds": { + "description": "На этой карте можно найти игровые площадки и добавить дополнительную информацию", + "shortDescription": "Карта игровых площадок", + "title": "Игровые площадки" + }, + "personal": { + "description": "Создать персональную тему на основе доступных слоёв тем" + }, + "maps": { + "title": "Карта карт" + }, + "fietsstraten": { + "layers": { + "2": { + "title": { + "render": "Улица" + }, + "name": "Все улицы" + } + } } } From 7deb9b5d53bdc594b5d04ea76148fa7e64bb2766 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Wed, 14 Jul 2021 16:05:50 +0200 Subject: [PATCH 03/26] Refactoring of AvailableBaseLayer --- InitUiElements.ts | 2 +- Logic/Actors/AvailableBaseLayers.ts | 95 ++++++++++++++++++++--------- UI/Base/Minimap.ts | 2 +- UI/BigComponents/SimpleAddUI.ts | 22 ++++--- UI/Input/LocationInput.ts | 48 ++------------- 5 files changed, 90 insertions(+), 79 deletions(-) diff --git a/InitUiElements.ts b/InitUiElements.ts index 0f1143eba..0dbc7eaac 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -341,7 +341,7 @@ export class InitUiElements { private static InitBaseMap() { - State.state.availableBackgroundLayers = new AvailableBaseLayers(State.state.locationControl).availableEditorLayers; + State.state.availableBackgroundLayers = AvailableBaseLayers.AvailableLayersAt(State.state.locationControl); State.state.backgroundLayer = State.state.backgroundLayerId .map((selectedId: string) => { diff --git a/Logic/Actors/AvailableBaseLayers.ts b/Logic/Actors/AvailableBaseLayers.ts index 52b1c12de..e84ecc635 100644 --- a/Logic/Actors/AvailableBaseLayers.ts +++ b/Logic/Actors/AvailableBaseLayers.ts @@ -7,7 +7,6 @@ import {UIEventSource} from "../UIEventSource"; import {GeoOperations} from "../GeoOperations"; import {Utils} from "../../Utils"; import Loc from "../../Models/Loc"; -import {isBoolean} from "util"; /** * Calculates which layers are available at the current location @@ -31,42 +30,82 @@ export default class AvailableBaseLayers { category: "osmbasedmap" } - public static layerOverview = AvailableBaseLayers.LoadRasterIndex().concat(AvailableBaseLayers.LoadProviderIndex()); - public availableEditorLayers: UIEventSource; - constructor(location: UIEventSource) { - const self = this; - this.availableEditorLayers = - location.map( - (currentLocation) => { + public static AvailableLayersAt(location: UIEventSource): UIEventSource { + const source = location.map( + (currentLocation) => { - if (currentLocation === undefined) { - return AvailableBaseLayers.layerOverview; - } + if (currentLocation === undefined) { + return AvailableBaseLayers.layerOverview; + } - const currentLayers = self.availableEditorLayers?.data; - const newLayers = AvailableBaseLayers.AvailableLayersAt(currentLocation?.lon, currentLocation?.lat); + const currentLayers = source?.data; // A bit unorthodox - I know + const newLayers = AvailableBaseLayers.CalculateAvailableLayersAt(currentLocation?.lon, currentLocation?.lat); - if (currentLayers === undefined) { + if (currentLayers === undefined) { + return newLayers; + } + if (newLayers.length !== currentLayers.length) { + return newLayers; + } + for (let i = 0; i < newLayers.length; i++) { + if (newLayers[i].name !== currentLayers[i].name) { return newLayers; } - if (newLayers.length !== currentLayers.length) { - return newLayers; - } - for (let i = 0; i < newLayers.length; i++) { - if (newLayers[i].name !== currentLayers[i].name) { - return newLayers; - } - } - - return currentLayers; - }); - + } + return currentLayers; + }); + return source; } - private static AvailableLayersAt(lon: number, lat: number): BaseLayer[] { + public static SelectBestLayerAccordingTo(location: UIEventSource, preferedCategory: UIEventSource): UIEventSource { + return AvailableBaseLayers.AvailableLayersAt(location).map(available => { + // First float all 'best layers' to the top + available.sort((a, b) => { + if (a.isBest && b.isBest) { + return 0; + } + if (!a.isBest) { + return 1 + } + + return -1; + } + ) + + if (preferedCategory.data === undefined) { + return available[0] + } + + let prefered: string [] + if (typeof preferedCategory.data === "string") { + prefered = [preferedCategory.data] + } else { + prefered = preferedCategory.data; + } + + prefered.reverse(); + for (const category of prefered) { + //Then sort all 'photo'-layers to the top. Stability of the sorting will force a 'best' photo layer on top + available.sort((a, b) => { + if (a.category === category && b.category === category) { + return 0; + } + if (a.category !== category) { + return 1 + } + + return -1; + } + ) + } + return available[0] + }) + } + + private static CalculateAvailableLayersAt(lon: number, lat: number): BaseLayer[] { const availableLayers = [AvailableBaseLayers.osmCarto] const globalLayers = []; for (const layerOverviewItem of AvailableBaseLayers.layerOverview) { @@ -146,7 +185,7 @@ export default class AvailableBaseLayers { layer: leafletLayer, feature: layer, isBest: props.best ?? false, - category: props.category + category: props.category }); } return layers; diff --git a/UI/Base/Minimap.ts b/UI/Base/Minimap.ts index 73bf2354a..2c38e8b74 100644 --- a/UI/Base/Minimap.ts +++ b/UI/Base/Minimap.ts @@ -52,7 +52,7 @@ export default class Minimap extends BaseUIElement { return wrapper; } - + private InitMap() { if (this._constructedHtmlElement === undefined) { // This element isn't initialized yet diff --git a/UI/BigComponents/SimpleAddUI.ts b/UI/BigComponents/SimpleAddUI.ts index 05fb52c64..9d1fd1475 100644 --- a/UI/BigComponents/SimpleAddUI.ts +++ b/UI/BigComponents/SimpleAddUI.ts @@ -19,6 +19,7 @@ import {Translation} from "../i18n/Translation"; import LocationInput from "../Input/LocationInput"; import {InputElement} from "../Input/InputElement"; import Loc from "../../Models/Loc"; +import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers"; /* * The SimpleAddUI is a single panel, which can have multiple states: @@ -115,14 +116,21 @@ export default class SimpleAddUI extends Toggle { let location = State.state.LastClickLocation; let preciseInput: InputElement = undefined if (preset.preciseInput !== undefined) { + const locationSrc = new UIEventSource({ + lat: location.data.lat, + lon: location.data.lon, + zoom: 19 + }); + + let backgroundLayer = undefined; + if(preset.preciseInput.preferredBackground){ + backgroundLayer= AvailableBaseLayers.SelectBestLayerAccordingTo(locationSrc, new UIEventSource(preset.preciseInput.preferredBackground)) + } + preciseInput = new LocationInput({ - preferCategory: preset.preciseInput.preferredBackground ?? State.state.backgroundLayer, - centerLocation: - new UIEventSource({ - lat: location.data.lat, - lon: location.data.lon, - zoom: 19 - }) + mapBackground: backgroundLayer, + centerLocation:locationSrc + }) preciseInput.SetClass("h-32 rounded-xl overflow-hidden border border-gray").SetStyle("height: 12rem;") } diff --git a/UI/Input/LocationInput.ts b/UI/Input/LocationInput.ts index cee2f5cbf..d568e4443 100644 --- a/UI/Input/LocationInput.ts +++ b/UI/Input/LocationInput.ts @@ -2,30 +2,27 @@ import {InputElement} from "./InputElement"; import Loc from "../../Models/Loc"; import {UIEventSource} from "../../Logic/UIEventSource"; import Minimap from "../Base/Minimap"; -import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers"; import BaseLayer from "../../Models/BaseLayer"; import Combine from "../Base/Combine"; import Svg from "../../Svg"; +import State from "../../State"; export default class LocationInput extends InputElement { IsSelected: UIEventSource = new UIEventSource(false); private _centerLocation: UIEventSource; - private readonly preferCategory; + private readonly mapBackground : UIEventSource; constructor(options?: { + mapBackground?: UIEventSource, centerLocation?: UIEventSource, - preferCategory?: string | UIEventSource, }) { super(); options = options ?? {} options.centerLocation = options.centerLocation ?? new UIEventSource({lat: 0, lon: 0, zoom: 1}) this._centerLocation = options.centerLocation; - if(typeof options.preferCategory === "string"){ - options.preferCategory = new UIEventSource(options.preferCategory); - } - this.preferCategory = options.preferCategory ?? new UIEventSource(undefined) + this.mapBackground = options.mapBackground ?? State.state.backgroundLayer this.SetClass("block h-full") } @@ -38,43 +35,10 @@ export default class LocationInput extends InputElement { } protected InnerConstructElement(): HTMLElement { - const layer: UIEventSource = new AvailableBaseLayers(this._centerLocation).availableEditorLayers.map(allLayers => { - // First float all 'best layers' to the top - allLayers.sort((a, b) => { - if (a.isBest && b.isBest) { - return 0; - } - if (!a.isBest) { - return 1 - } - - return -1; - } - ) - if (this.preferCategory) { - const self = this; - //Then sort all 'photo'-layers to the top. Stability of the sorting will force a 'best' photo layer on top - allLayers.sort((a, b) => { - const preferred = self.preferCategory.data - if (a.category === preferred && b.category === preferred) { - return 0; - } - if (a.category !== preferred) { - return 1 - } - - return -1; - } - ) - } - return allLayers[0] - }, [this.preferCategory] - ) - layer.addCallbackAndRunD(layer => console.log(layer)) const map = new Minimap( { location: this._centerLocation, - background: layer + background: this.mapBackground } ) map.leafletMap.addCallbackAndRunD(leaflet => { @@ -84,7 +48,7 @@ export default class LocationInput extends InputElement { ) }) - layer.map(layer => { + this.mapBackground.map(layer => { const leaflet = map.leafletMap.data if (leaflet === undefined || layer === undefined) { From b68bf7b95029a3161b5471daebf12997c767349f Mon Sep 17 00:00:00 2001 From: Arno Deceuninck Date: Thu, 15 Jul 2021 09:34:00 +0200 Subject: [PATCH 04/26] Download cached features as geojson --- InitUiElements.ts | 2 ++ State.ts | 2 ++ UI/BigComponents/LayerSelection.ts | 5 +++++ UI/GeoJsonExport.ts | 15 +++++++++++++++ Utils.ts | 8 ++++++++ 5 files changed, 32 insertions(+) create mode 100644 UI/GeoJsonExport.ts diff --git a/InitUiElements.ts b/InitUiElements.ts index 0f1143eba..97dd2b02c 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -427,6 +427,8 @@ export class InitUiElements { state.locationControl, state.selectedElement); + State.state.featurePipeline = source; + new ShowDataLayer(source.features, State.state.leafletMap, State.state.layoutToUse); const selectedFeatureHandler = new SelectedFeatureHandler(Hash.hash, State.state.selectedElement, source, State.state.osmApiFeatureSource); diff --git a/State.ts b/State.ts index 8e4322d65..7793485aa 100644 --- a/State.ts +++ b/State.ts @@ -19,6 +19,7 @@ import TitleHandler from "./Logic/Actors/TitleHandler"; import PendingChangesUploader from "./Logic/Actors/PendingChangesUploader"; import {Relation} from "./Logic/Osm/ExtractRelations"; import OsmApiFeatureSource from "./Logic/FeatureSource/OsmApiFeatureSource"; +import FeaturePipeline from "./Logic/FeatureSource/FeaturePipeline"; /** * Contains the global state: a bunch of UI-event sources @@ -95,6 +96,7 @@ export default class State { public readonly featureSwitchIsDebugging: UIEventSource; public readonly featureSwitchShowAllQuestions: UIEventSource; public readonly featureSwitchApiURL: UIEventSource; + public readonly featurePipeline: FeaturePipeline; /** diff --git a/UI/BigComponents/LayerSelection.ts b/UI/BigComponents/LayerSelection.ts index e28294709..11237fa32 100644 --- a/UI/BigComponents/LayerSelection.ts +++ b/UI/BigComponents/LayerSelection.ts @@ -7,6 +7,8 @@ import Translations from "../i18n/Translations"; import LayerConfig from "../../Customizations/JSON/LayerConfig"; import BaseUIElement from "../BaseUIElement"; import {Translation} from "../i18n/Translation"; +import {SubtleButton} from "../Base/SubtleButton"; +import {exportAsGeoJson} from "../GeoJsonExport"; /** * Shows the panel with all layers and a toggle for each of them @@ -74,6 +76,9 @@ export default class LayerSelection extends Combine { ); } + const downloadButton = new SubtleButton("./assets/svg/floppy.svg", "Download visible data as geojson") + downloadButton.onClick(() => exportAsGeoJson(State.state.featurePipeline)) // TODO: Define this + checkboxes.push(downloadButton) super(checkboxes) this.SetStyle("display:flex;flex-direction:column;") diff --git a/UI/GeoJsonExport.ts b/UI/GeoJsonExport.ts new file mode 100644 index 000000000..c18baed17 --- /dev/null +++ b/UI/GeoJsonExport.ts @@ -0,0 +1,15 @@ +import FeaturePipeline from "../Logic/FeatureSource/FeaturePipeline"; +import {Utils} from "../Utils"; + +export function exportAsGeoJson(featurePipeline: FeaturePipeline, options?: {metadata?: boolean}) { + let defaults = { + metadata: false + } + options = Utils.setDefaults(options, defaults); + // Select all features, ignore the freshness and other data + // TODO: Remove mapcomplete metadata (starting with underscore) + let featureList: JSON[] = featurePipeline? featurePipeline.features.data.map((feature) => feature.feature) : ["I'm empty"]; + let geojson = {type: "FeatureCollection", features: featureList} + + Utils.offerContentsAsDownloadableFile(JSON.stringify(geojson), "Geodata.json"); +} diff --git a/Utils.ts b/Utils.ts index 05ebcbaab..418f1d111 100644 --- a/Utils.ts +++ b/Utils.ts @@ -447,6 +447,14 @@ export class Utils { b: parseInt(hex.substr(5, 2), 16), } } + + public static setDefaults(options, defaults){ + let result = {}; + for (let key of defaults){ + result[key] = key in options ? options[key] : defaults[key]; + } + return result; + } } export interface TileRange { From bd07eed4824afb03d09ebf98c2fab4ce7a8b7f91 Mon Sep 17 00:00:00 2001 From: Arno Deceuninck Date: Thu, 15 Jul 2021 09:58:17 +0200 Subject: [PATCH 05/26] Remove MapComplete metadata from featurelist --- UI/GeoJsonExport.ts | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/UI/GeoJsonExport.ts b/UI/GeoJsonExport.ts index c18baed17..68037eee3 100644 --- a/UI/GeoJsonExport.ts +++ b/UI/GeoJsonExport.ts @@ -1,14 +1,31 @@ import FeaturePipeline from "../Logic/FeatureSource/FeaturePipeline"; import {Utils} from "../Utils"; -export function exportAsGeoJson(featurePipeline: FeaturePipeline, options?: {metadata?: boolean}) { +export function exportAsGeoJson(featurePipeline: FeaturePipeline, options?: { metadata?: boolean }) { let defaults = { metadata: false } options = Utils.setDefaults(options, defaults); // Select all features, ignore the freshness and other data - // TODO: Remove mapcomplete metadata (starting with underscore) - let featureList: JSON[] = featurePipeline? featurePipeline.features.data.map((feature) => feature.feature) : ["I'm empty"]; + let featureList: JSON[] = featurePipeline ? featurePipeline.features.data.map((feature) => feature.feature) : ["I'm empty"]; + + function removeMetaData(featureList: JSON[]) { + for (let i=0; i < featureList.length; i++) { + let feature = featureList[i]; + for (let property in feature.properties) { + if (property[0] == "_") { + delete featureList[i]["properties"][property]; + } + } + } + return featureList; + } + + // Remove the metadata of MapComplete (all properties starting with an underscore) + if (!options.metadata) { + removeMetaData(featureList); + } + let geojson = {type: "FeatureCollection", features: featureList} Utils.offerContentsAsDownloadableFile(JSON.stringify(geojson), "Geodata.json"); From e7ef2fb6d8116fae7edfea16b0488b00d56395c8 Mon Sep 17 00:00:00 2001 From: Arno Deceuninck Date: Thu, 15 Jul 2021 10:56:30 +0200 Subject: [PATCH 06/26] Updated documentation --- UI/BigComponents/LayerSelection.ts | 2 +- UI/GeoJsonExport.ts | 21 ++++++++++++++------- Utils.ts | 7 +++---- tslint.json | 2 +- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/UI/BigComponents/LayerSelection.ts b/UI/BigComponents/LayerSelection.ts index 11237fa32..900be9348 100644 --- a/UI/BigComponents/LayerSelection.ts +++ b/UI/BigComponents/LayerSelection.ts @@ -77,7 +77,7 @@ export default class LayerSelection extends Combine { } const downloadButton = new SubtleButton("./assets/svg/floppy.svg", "Download visible data as geojson") - downloadButton.onClick(() => exportAsGeoJson(State.state.featurePipeline)) // TODO: Define this + downloadButton.onClick(() => exportAsGeoJson(State.state.featurePipeline)) checkboxes.push(downloadButton) super(checkboxes) diff --git a/UI/GeoJsonExport.ts b/UI/GeoJsonExport.ts index 68037eee3..d3e5dc5d6 100644 --- a/UI/GeoJsonExport.ts +++ b/UI/GeoJsonExport.ts @@ -1,14 +1,25 @@ import FeaturePipeline from "../Logic/FeatureSource/FeaturePipeline"; import {Utils} from "../Utils"; -export function exportAsGeoJson(featurePipeline: FeaturePipeline, options?: { metadata?: boolean }) { +/** + * Exports given featurePipeline as a geojson FeatureLists (downloads as a json) + * @param featurePipeline The FeaturePipeline you want to export + * @param options The options object + * @param options.metadata True if you want to include the MapComplete metadata, false otherwise + */ +export function exportAsGeoJson(featurePipeline: FeaturePipeline, options: { metadata?: boolean} = {}) { let defaults = { - metadata: false + metadata: false, } options = Utils.setDefaults(options, defaults); + // Select all features, ignore the freshness and other data let featureList: JSON[] = featurePipeline ? featurePipeline.features.data.map((feature) => feature.feature) : ["I'm empty"]; + /** + * Removes the metadata of MapComplete (all properties starting with an underscore) + * @param featureList JsonList containing features, output object + */ function removeMetaData(featureList: JSON[]) { for (let i=0; i < featureList.length; i++) { let feature = featureList[i]; @@ -18,13 +29,9 @@ export function exportAsGeoJson(featurePipeline: FeaturePipeline, options?: { me } } } - return featureList; } - // Remove the metadata of MapComplete (all properties starting with an underscore) - if (!options.metadata) { - removeMetaData(featureList); - } + if (!options.metadata) removeMetaData(featureList); let geojson = {type: "FeatureCollection", features: featureList} diff --git a/Utils.ts b/Utils.ts index 418f1d111..683e7a8f9 100644 --- a/Utils.ts +++ b/Utils.ts @@ -449,11 +449,10 @@ export class Utils { } public static setDefaults(options, defaults){ - let result = {}; - for (let key of defaults){ - result[key] = key in options ? options[key] : defaults[key]; + for (let key in defaults){ + if (!(key in options)) options[key] = defaults[key]; } - return result; + return options; } } diff --git a/tslint.json b/tslint.json index 6a204a045..85c7437ac 100644 --- a/tslint.json +++ b/tslint.json @@ -1,5 +1,5 @@ { - "defaultSeverity": "error", + "defaultSeverity": "warn", "extends": [ "tslint:recommended", "tslint-no-circular-imports" From 62925a89ba333eb654ac67bb5084788e466050f0 Mon Sep 17 00:00:00 2001 From: Arno Deceuninck Date: Thu, 15 Jul 2021 11:13:00 +0200 Subject: [PATCH 07/26] Text in translation file + refactor --- {UI => Logic/FeatureSource}/GeoJsonExport.ts | 4 ++-- UI/BigComponents/LayerSelection.ts | 4 ++-- langs/en.json | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) rename {UI => Logic/FeatureSource}/GeoJsonExport.ts (93%) diff --git a/UI/GeoJsonExport.ts b/Logic/FeatureSource/GeoJsonExport.ts similarity index 93% rename from UI/GeoJsonExport.ts rename to Logic/FeatureSource/GeoJsonExport.ts index d3e5dc5d6..541e10373 100644 --- a/UI/GeoJsonExport.ts +++ b/Logic/FeatureSource/GeoJsonExport.ts @@ -1,5 +1,5 @@ -import FeaturePipeline from "../Logic/FeatureSource/FeaturePipeline"; -import {Utils} from "../Utils"; +import FeaturePipeline from "./FeaturePipeline"; +import {Utils} from "../../Utils"; /** * Exports given featurePipeline as a geojson FeatureLists (downloads as a json) diff --git a/UI/BigComponents/LayerSelection.ts b/UI/BigComponents/LayerSelection.ts index 900be9348..c48b36163 100644 --- a/UI/BigComponents/LayerSelection.ts +++ b/UI/BigComponents/LayerSelection.ts @@ -8,7 +8,7 @@ import LayerConfig from "../../Customizations/JSON/LayerConfig"; import BaseUIElement from "../BaseUIElement"; import {Translation} from "../i18n/Translation"; import {SubtleButton} from "../Base/SubtleButton"; -import {exportAsGeoJson} from "../GeoJsonExport"; +import {exportAsGeoJson} from "../../Logic/FeatureSource/GeoJsonExport"; /** * Shows the panel with all layers and a toggle for each of them @@ -76,7 +76,7 @@ export default class LayerSelection extends Combine { ); } - const downloadButton = new SubtleButton("./assets/svg/floppy.svg", "Download visible data as geojson") + const downloadButton = new SubtleButton("./assets/svg/floppy.svg", Translations.t.general.layerSelection.downloadGeojson.Clone()) downloadButton.onClick(() => exportAsGeoJson(State.state.featurePipeline)) checkboxes.push(downloadButton) diff --git a/langs/en.json b/langs/en.json index 7f327653c..b604850f8 100644 --- a/langs/en.json +++ b/langs/en.json @@ -147,7 +147,8 @@ "loginOnlyNeededToEdit": "if you want to edit the map", "layerSelection": { "zoomInToSeeThisLayer": "Zoom in to see this layer", - "title": "Select layers" + "title": "Select layers", + "downloadGeojson": "Download layer features as geojson" }, "weekdays": { "abbreviations": { From 46d57edea0dd7a3f4bab5b5febbda033eb2f43e4 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Thu, 15 Jul 2021 21:01:10 +0200 Subject: [PATCH 08/26] Translation sync --- assets/themes/artwork/artwork.json | 2 +- assets/themes/bicycle_library/bicycle_library.json | 6 ++++-- assets/themes/openwindpowermap/openwindpowermap.json | 11 ++++++----- langs/themes/de.json | 8 ++++---- langs/themes/en.json | 7 +++++++ langs/themes/nl.json | 7 +++++++ 6 files changed, 29 insertions(+), 12 deletions(-) diff --git a/assets/themes/artwork/artwork.json b/assets/themes/artwork/artwork.json index 7b8cc876c..c3b7b7c55 100644 --- a/assets/themes/artwork/artwork.json +++ b/assets/themes/artwork/artwork.json @@ -374,7 +374,7 @@ "en": "Is there a website with more information about this artwork?", "nl": "Op welke website kan men meer informatie vinden over dit kunstwerk?", "fr": "Sur quel site web pouvons-nous trouver plus d'informations sur cette œuvre d'art?", - "de": "Auf welcher Website gibt es mehr Informationen über dieses Kunstwerk?", + "de": "Gibt es eine Website mit weiteren Informationen über dieses Kunstwerk?", "it": "Esiste un sito web con maggiori informazioni su quest’opera?", "ru": "Есть ли сайт с более подробной информацией об этой работе?", "ja": "この作品についての詳しい情報はどのウェブサイトにありますか?", diff --git a/assets/themes/bicycle_library/bicycle_library.json b/assets/themes/bicycle_library/bicycle_library.json index 437020a3f..6d0cf61e2 100644 --- a/assets/themes/bicycle_library/bicycle_library.json +++ b/assets/themes/bicycle_library/bicycle_library.json @@ -10,7 +10,8 @@ "ja", "fr", "zh_Hant", - "nb_NO" + "nb_NO", + "de" ], "title": { "en": "Bicycle libraries", @@ -20,7 +21,8 @@ "ja": "自転車ライブラリ", "fr": "Vélothèques", "zh_Hant": "單車圖書館", - "nb_NO": "Sykkelbibliotek" + "nb_NO": "Sykkelbibliotek", + "de": "Fahrradbibliothek" }, "description": { "nl": "Een fietsbibliotheek is een plaats waar men een fiets kan lenen, vaak voor een klein bedrag per jaar. Een typisch voorbeeld zijn kinderfietsbibliotheken, waar men een fiets op maat van het kind kan lenen. Is het kind de fiets ontgroeid, dan kan het te kleine fietsje omgeruild worden voor een grotere.", diff --git a/assets/themes/openwindpowermap/openwindpowermap.json b/assets/themes/openwindpowermap/openwindpowermap.json index b1e4ecaa7..22bba27ef 100644 --- a/assets/themes/openwindpowermap/openwindpowermap.json +++ b/assets/themes/openwindpowermap/openwindpowermap.json @@ -56,7 +56,7 @@ "tagRenderings": [ { "render": { - "en": "The power output of this wind turbine is {canonical(generator:output:electricity)}." + "en": "The power output of this wind turbine is {generator:output:electricity}." }, "question": { "en": "What is the power output of this wind turbine? (e.g. 2.3 MW)" @@ -79,7 +79,7 @@ }, { "render": { - "en": "The total height (including rotor radius) of this wind turbine is {canonical(height)}." + "en": "The total height (including rotor radius) of this wind turbine is {height} metres." }, "question": { "en": "What is the total height of this wind turbine (including rotor radius), in metres?" @@ -91,7 +91,7 @@ }, { "render": { - "en": "The rotor diameter of this wind turbine is {canonical(rotor:diameter)}." + "en": "The rotor diameter of this wind turbine is {rotor:diameter} metres." }, "question": { "en": "What is the rotor diameter of this wind turbine, in metres?" @@ -129,7 +129,7 @@ } ], "units": [ - { + { "appliesToKey": [ "generator:output:electricity" ], @@ -183,7 +183,8 @@ }, { "appliesToKey": [ - "height","rotor:diameter" + "height", + "rotor:diameter" ], "applicableUnits": [ { diff --git a/langs/themes/de.json b/langs/themes/de.json index 95abb60b1..6a0b29fad 100644 --- a/langs/themes/de.json +++ b/langs/themes/de.json @@ -87,6 +87,9 @@ "shortDescription": "Eine Karte aller Sitzbänke", "description": "Diese Karte zeigt alle Sitzbänke, die in OpenStreetMap eingetragen sind: Einzeln stehende Bänke und Bänke, die zu Haltestellen oder Unterständen gehören. Mit einem OpenStreetMap-Account können Sie neue Bänke eintragen oder Detailinformationen existierender Bänke bearbeiten." }, + "bicyclelib": { + "title": "Fahrradbibliothek" + }, "bookcases": { "title": "Öffentliche Bücherschränke Karte", "description": "Ein öffentlicher Bücherschrank ist ein kleiner Bücherschrank am Straßenrand, ein Kasten, eine alte Telefonzelle oder andere Gegenstände, in denen Bücher aufbewahrt werden. Jeder kann ein Buch hinstellen oder mitnehmen. Diese Karte zielt darauf ab, all diese Bücherschränke zu sammeln. Sie können neue Bücherschränke in der Nähe entdecken und mit einem kostenlosen OpenStreetMap-Account schnell Ihre Lieblingsbücherschränke hinzufügen." @@ -327,8 +330,5 @@ "toilets": { "title": "Offene Toilette Karte", "description": "Eine Karte der öffentlichen Toiletten" - }, - "bicyclelib": { - "title": "Fahrradbibliothek" } -} +} \ No newline at end of file diff --git a/langs/themes/en.json b/langs/themes/en.json index 48852d5a4..f5db488b9 100644 --- a/langs/themes/en.json +++ b/langs/themes/en.json @@ -1143,6 +1143,13 @@ "human": " gigawatts" } } + }, + "1": { + "applicableUnits": { + "0": { + "human": " meter" + } + } } } }, diff --git a/langs/themes/nl.json b/langs/themes/nl.json index 7966e9e2d..44bf09b5f 100644 --- a/langs/themes/nl.json +++ b/langs/themes/nl.json @@ -919,6 +919,13 @@ "human": " gigawatt" } } + }, + "1": { + "applicableUnits": { + "0": { + "human": " meter" + } + } } } }, From 294bdbfd9247ef99f5798881cbb5fadb76f0bad4 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Fri, 16 Jul 2021 00:49:50 +0200 Subject: [PATCH 09/26] Add missing license info --- assets/svg/license_info.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/assets/svg/license_info.json b/assets/svg/license_info.json index 1ef8f94c8..db044b683 100644 --- a/assets/svg/license_info.json +++ b/assets/svg/license_info.json @@ -582,5 +582,15 @@ "sources": [ "https://www.mapillary.com/" ] + }, + { + "authors": [ + "The Tango! Desktop Project" + ], + "path": "floppy.svg", + "license": "CC0", + "sources": [ + "https://commons.wikimedia.org/wiki/File:Media-floppy.svg" + ] } ] \ No newline at end of file From 0af3a91fde5c9a72457d565d5a061145eb112eaa Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Fri, 16 Jul 2021 00:57:33 +0200 Subject: [PATCH 10/26] Fix licenses, small improvement to icon --- assets/svg/crosshair-locked.svg | 69 ++++++++++++++++----------------- assets/svg/license_info.json | 14 ++++++- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/assets/svg/crosshair-locked.svg b/assets/svg/crosshair-locked.svg index b1a741c28..d8d04340c 100644 --- a/assets/svg/crosshair-locked.svg +++ b/assets/svg/crosshair-locked.svg @@ -25,9 +25,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="2.8284271" - inkscape:cx="67.47399" - inkscape:cy="29.788021" + inkscape:zoom="5.6568542" + inkscape:cx="27.044982" + inkscape:cy="77.667126" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" @@ -68,40 +68,39 @@ inkscape:groupmode="layer" id="layer1" transform="translate(0,-270.54165)"> - - - - - + id="g827"> + + inkscape:connector-curvature="0" + id="path817" + d="M 3.2841366,283.77082 H 1.0418969" + style="fill:none;stroke:#5555ec;stroke-width:2.09723878;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529" /> + + + + diff --git a/assets/svg/license_info.json b/assets/svg/license_info.json index 1ef8f94c8..f82b5fb71 100644 --- a/assets/svg/license_info.json +++ b/assets/svg/license_info.json @@ -162,6 +162,18 @@ "license": "CC0; trivial", "sources": [] }, + { + "authors": [], + "path": "crosshair-empty.svg", + "license": "CC0; trivial", + "sources": [] + }, + { + "authors": [], + "path": "crosshair-locked.svg", + "license": "CC0; trivial", + "sources": [] + }, { "authors": [ "Dave Gandy" @@ -204,7 +216,7 @@ "license": "CC0", "sources": [ "https://commons.wikimedia.org/wiki/File:Media-floppy.svg", - " http://tango.freedesktop.org/Tango_Desktop_Project" + "http://tango.freedesktop.org/Tango_Desktop_Project" ] }, { From abd7db100dd290e9f5a826532bfe7cffb717c116 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Fri, 16 Jul 2021 01:42:09 +0200 Subject: [PATCH 11/26] Finish the export functionality: move logic around a bit, add license information for reusers, wire the functionality as feature switch --- Customizations/JSON/LayoutConfig.ts | 2 ++ Customizations/JSON/LayoutConfigJson.ts | 2 ++ Logic/FeatureSource/FeatureSource.ts | 38 +++++++++++++++++++++++- Logic/FeatureSource/GeoJsonExport.ts | 39 ------------------------- State.ts | 10 +++++-- Svg.ts | 2 +- UI/BigComponents/ExportDataButton.ts | 21 +++++++++++++ UI/BigComponents/LayerControlPanel.ts | 36 ++++++++++++++--------- UI/BigComponents/LayerSelection.ts | 6 ---- langs/en.json | 7 +++-- 10 files changed, 98 insertions(+), 65 deletions(-) delete mode 100644 Logic/FeatureSource/GeoJsonExport.ts create mode 100644 UI/BigComponents/ExportDataButton.ts diff --git a/Customizations/JSON/LayoutConfig.ts b/Customizations/JSON/LayoutConfig.ts index 12b9d5f76..e76c68ac8 100644 --- a/Customizations/JSON/LayoutConfig.ts +++ b/Customizations/JSON/LayoutConfig.ts @@ -42,6 +42,7 @@ export default class LayoutConfig { public readonly enableGeolocation: boolean; public readonly enableBackgroundLayerSelection: boolean; public readonly enableShowAllQuestions: boolean; + public readonly enableExportButton: boolean; public readonly customCss?: string; /* How long is the cache valid, in seconds? @@ -152,6 +153,7 @@ export default class LayoutConfig { this.enableAddNewPoints = json.enableAddNewPoints ?? true; this.enableBackgroundLayerSelection = json.enableBackgroundLayerSelection ?? true; this.enableShowAllQuestions = json.enableShowAllQuestions ?? false; + this.enableExportButton = json.enableExportButton ?? false; this.customCss = json.customCss; this.cacheTimeout = json.cacheTimout ?? (60 * 24 * 60 * 60) diff --git a/Customizations/JSON/LayoutConfigJson.ts b/Customizations/JSON/LayoutConfigJson.ts index 374de70e0..d36a8463d 100644 --- a/Customizations/JSON/LayoutConfigJson.ts +++ b/Customizations/JSON/LayoutConfigJson.ts @@ -15,6 +15,7 @@ import UnitConfigJson from "./UnitConfigJson"; * General remark: a type (string | any) indicates either a fixed or a translatable string. */ export interface LayoutConfigJson { + /** * The id of this layout. * @@ -335,4 +336,5 @@ export interface LayoutConfigJson { enableGeolocation?: boolean; enableBackgroundLayerSelection?: boolean; enableShowAllQuestions?: boolean; + enableExportButton?: boolean; } diff --git a/Logic/FeatureSource/FeatureSource.ts b/Logic/FeatureSource/FeatureSource.ts index ba568271e..171db39f6 100644 --- a/Logic/FeatureSource/FeatureSource.ts +++ b/Logic/FeatureSource/FeatureSource.ts @@ -1,9 +1,45 @@ import {UIEventSource} from "../UIEventSource"; +import {Utils} from "../../Utils"; export default interface FeatureSource { - features: UIEventSource<{feature: any, freshness: Date}[]>; + features: UIEventSource<{ feature: any, freshness: Date }[]>; /** * Mainly used for debuging */ name: string; +} + +export class FeatureSourceUtils { + + /** + * Exports given featurePipeline as a geojson FeatureLists (downloads as a json) + * @param featurePipeline The FeaturePipeline you want to export + * @param options The options object + * @param options.metadata True if you want to include the MapComplete metadata, false otherwise + */ + public static extractGeoJson(featurePipeline: FeatureSource, options: { metadata?: boolean } = {}) { + let defaults = { + metadata: false, + } + options = Utils.setDefaults(options, defaults); + + // Select all features, ignore the freshness and other data + let featureList: any[] = featurePipeline.features.data.map((feature) => feature.feature); + + if (!options.metadata) { + for (let i = 0; i < featureList.length; i++) { + let feature = featureList[i]; + for (let property in feature.properties) { + if (property[0] == "_") { + delete featureList[i]["properties"][property]; + } + } + } + } + return {type: "FeatureCollection", features: featureList} + + + } + + } \ No newline at end of file diff --git a/Logic/FeatureSource/GeoJsonExport.ts b/Logic/FeatureSource/GeoJsonExport.ts deleted file mode 100644 index 541e10373..000000000 --- a/Logic/FeatureSource/GeoJsonExport.ts +++ /dev/null @@ -1,39 +0,0 @@ -import FeaturePipeline from "./FeaturePipeline"; -import {Utils} from "../../Utils"; - -/** - * Exports given featurePipeline as a geojson FeatureLists (downloads as a json) - * @param featurePipeline The FeaturePipeline you want to export - * @param options The options object - * @param options.metadata True if you want to include the MapComplete metadata, false otherwise - */ -export function exportAsGeoJson(featurePipeline: FeaturePipeline, options: { metadata?: boolean} = {}) { - let defaults = { - metadata: false, - } - options = Utils.setDefaults(options, defaults); - - // Select all features, ignore the freshness and other data - let featureList: JSON[] = featurePipeline ? featurePipeline.features.data.map((feature) => feature.feature) : ["I'm empty"]; - - /** - * Removes the metadata of MapComplete (all properties starting with an underscore) - * @param featureList JsonList containing features, output object - */ - function removeMetaData(featureList: JSON[]) { - for (let i=0; i < featureList.length; i++) { - let feature = featureList[i]; - for (let property in feature.properties) { - if (property[0] == "_") { - delete featureList[i]["properties"][property]; - } - } - } - } - - if (!options.metadata) removeMetaData(featureList); - - let geojson = {type: "FeatureCollection", features: featureList} - - Utils.offerContentsAsDownloadableFile(JSON.stringify(geojson), "Geodata.json"); -} diff --git a/State.ts b/State.ts index 7793485aa..90289bcab 100644 --- a/State.ts +++ b/State.ts @@ -96,6 +96,10 @@ export default class State { public readonly featureSwitchIsDebugging: UIEventSource; public readonly featureSwitchShowAllQuestions: UIEventSource; public readonly featureSwitchApiURL: UIEventSource; + public readonly featureSwitchEnableExport: UIEventSource; + + + public readonly featurePipeline: FeaturePipeline; @@ -127,7 +131,7 @@ export default class State { public welcomeMessageOpenedTab = QueryParameters.GetQueryParameter("tab", "0", `The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >${Constants.userJourney.mapCompleteHelpUnlock} changesets)`).map( str => isNaN(Number(str)) ? 0 : Number(str), [], n => "" + n ); - + constructor(layoutToUse: LayoutConfig) { const self = this; @@ -201,6 +205,8 @@ export default class State { "Disables/Enables the geolocation button"); this.featureSwitchShowAllQuestions = featSw("fs-all-questions", (layoutToUse) => layoutToUse?.enableShowAllQuestions ?? false, "Always show all questions"); + this.featureSwitchEnableExport = featSw("fs-export",(layoutToUse) => layoutToUse?.enableExportButton ?? false, + "If set, enables the 'download'-button to download everything as geojson") this.featureSwitchIsTesting = QueryParameters.GetQueryParameter("test", "false", "If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org") @@ -212,7 +218,7 @@ export default class State { this.featureSwitchApiURL = QueryParameters.GetQueryParameter("backend","osm", "The OSM backend to use - can be used to redirect mapcomplete to the testing backend when using 'osm-test'") - + } { // Some other feature switches diff --git a/Svg.ts b/Svg.ts index 0266e43e8..5684fc4b5 100644 --- a/Svg.ts +++ b/Svg.ts @@ -94,7 +94,7 @@ export default class Svg { public static crosshair_empty_svg() { return new Img(Svg.crosshair_empty, true);} public static crosshair_empty_ui() { return new FixedUiElement(Svg.crosshair_empty_img);} - public static crosshair_locked = " image/svg+xml " + public static crosshair_locked = " image/svg+xml " public static crosshair_locked_img = Img.AsImageElement(Svg.crosshair_locked) public static crosshair_locked_svg() { return new Img(Svg.crosshair_locked, true);} public static crosshair_locked_ui() { return new FixedUiElement(Svg.crosshair_locked_img);} diff --git a/UI/BigComponents/ExportDataButton.ts b/UI/BigComponents/ExportDataButton.ts new file mode 100644 index 000000000..9a161de9f --- /dev/null +++ b/UI/BigComponents/ExportDataButton.ts @@ -0,0 +1,21 @@ +import {SubtleButton} from "../Base/SubtleButton"; +import Svg from "../../Svg"; +import Translations from "../i18n/Translations"; +import State from "../../State"; +import {FeatureSourceUtils} from "../../Logic/FeatureSource/FeatureSource"; +import {Utils} from "../../Utils"; +import Combine from "../Base/Combine"; + +export class ExportDataButton extends Combine { + constructor() { + const t = Translations.t.general.download + const button = new SubtleButton(Svg.floppy_ui(), t.downloadGeojson.Clone().SetClass("font-bold")) + .onClick(() => { + const geojson = FeatureSourceUtils.extractGeoJson(State.state.featurePipeline) + const name = State.state.layoutToUse.data.id; + Utils.offerContentsAsDownloadableFile(JSON.stringify(geojson), `MapComplete_${name}_export_${new Date().toISOString().substr(0,19)}.geojson`); + }) + + super([button, t.licenseInfo.Clone().SetClass("link-underline")]) + } +} \ No newline at end of file diff --git a/UI/BigComponents/LayerControlPanel.ts b/UI/BigComponents/LayerControlPanel.ts index 42a3eda12..c8837fbcc 100644 --- a/UI/BigComponents/LayerControlPanel.ts +++ b/UI/BigComponents/LayerControlPanel.ts @@ -2,11 +2,12 @@ import State from "../../State"; import BackgroundSelector from "./BackgroundSelector"; import LayerSelection from "./LayerSelection"; import Combine from "../Base/Combine"; -import {FixedUiElement} from "../Base/FixedUiElement"; import ScrollableFullScreen from "../Base/ScrollableFullScreen"; import Translations from "../i18n/Translations"; import {UIEventSource} from "../../Logic/UIEventSource"; import BaseUIElement from "../BaseUIElement"; +import Toggle from "../Input/Toggle"; +import {ExportDataButton} from "./ExportDataButton"; export default class LayerControlPanel extends ScrollableFullScreen { @@ -14,27 +15,34 @@ export default class LayerControlPanel extends ScrollableFullScreen { super(LayerControlPanel.GenTitle, LayerControlPanel.GeneratePanel, "layers", isShown); } - private static GenTitle():BaseUIElement { + private static GenTitle(): BaseUIElement { return Translations.t.general.layerSelection.title.Clone().SetClass("text-2xl break-words font-bold p-2") } - private static GeneratePanel() : BaseUIElement { - let layerControlPanel: BaseUIElement = new FixedUiElement(""); + private static GeneratePanel(): BaseUIElement { + const elements: BaseUIElement[] = [] + if (State.state.layoutToUse.data.enableBackgroundLayerSelection) { - layerControlPanel = new BackgroundSelector(); - layerControlPanel.SetStyle("margin:1em"); - layerControlPanel.onClick(() => { + const backgroundSelector = new BackgroundSelector(); + backgroundSelector.SetStyle("margin:1em"); + backgroundSelector.onClick(() => { }); + elements.push(backgroundSelector) } - if (State.state.filteredLayers.data.length > 1) { - const layerSelection = new LayerSelection(State.state.filteredLayers); - layerSelection.onClick(() => { - }); - layerControlPanel = new Combine([layerSelection, "
", layerControlPanel]); - } + elements.push(new Toggle( + new LayerSelection(State.state.filteredLayers), + undefined, + State.state.filteredLayers.map(layers => layers.length > 1) + )) - return layerControlPanel; + elements.push(new Toggle( + new ExportDataButton(), + undefined, + State.state.featureSwitchEnableExport + )) + + return new Combine(elements).SetClass("flex flex-col") } } \ No newline at end of file diff --git a/UI/BigComponents/LayerSelection.ts b/UI/BigComponents/LayerSelection.ts index c48b36163..3c7f108e8 100644 --- a/UI/BigComponents/LayerSelection.ts +++ b/UI/BigComponents/LayerSelection.ts @@ -7,8 +7,6 @@ import Translations from "../i18n/Translations"; import LayerConfig from "../../Customizations/JSON/LayerConfig"; import BaseUIElement from "../BaseUIElement"; import {Translation} from "../i18n/Translation"; -import {SubtleButton} from "../Base/SubtleButton"; -import {exportAsGeoJson} from "../../Logic/FeatureSource/GeoJsonExport"; /** * Shows the panel with all layers and a toggle for each of them @@ -76,10 +74,6 @@ export default class LayerSelection extends Combine { ); } - const downloadButton = new SubtleButton("./assets/svg/floppy.svg", Translations.t.general.layerSelection.downloadGeojson.Clone()) - downloadButton.onClick(() => exportAsGeoJson(State.state.featurePipeline)) - checkboxes.push(downloadButton) - super(checkboxes) this.SetStyle("display:flex;flex-direction:column;") diff --git a/langs/en.json b/langs/en.json index b604850f8..aac35335c 100644 --- a/langs/en.json +++ b/langs/en.json @@ -147,8 +147,11 @@ "loginOnlyNeededToEdit": "if you want to edit the map", "layerSelection": { "zoomInToSeeThisLayer": "Zoom in to see this layer", - "title": "Select layers", - "downloadGeojson": "Download layer features as geojson" + "title": "Select layers" + }, + "download": { + "downloadGeojson": "Download visible data as geojson", + "licenseInfo": "

Copyright notice

The provided is available under ODbL. Reusing this data is free for any purpose, but
  • the attribution © OpenStreetMap contributors
  • Any change to this data must be republished under the same license
. Please see the full copyright notice for details" }, "weekdays": { "abbreviations": { From 3bcd2553111e3cb91d470c75abefc389b097c361 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Fri, 16 Jul 2021 02:06:33 +0200 Subject: [PATCH 12/26] Add fake user switch to mimick a logged in user; fixes #432 --- Docs/URL_Parameters.md | 248 +++++++++++++++++++++---------------- Logic/Osm/OsmConnection.ts | 20 ++- State.ts | 39 +++--- preferences.ts | 2 +- test/OsmConnection.spec.ts | 2 +- 5 files changed, 182 insertions(+), 129 deletions(-) diff --git a/Docs/URL_Parameters.md b/Docs/URL_Parameters.md index 6f299adcf..5c3158fd7 100644 --- a/Docs/URL_Parameters.md +++ b/Docs/URL_Parameters.md @@ -20,126 +20,158 @@ the URL-parameters are stated in the part between the `?` and the `#`. There are Finally, the URL-hash is the part after the `#`. It is `node/1234` in this case. - layer-control-toggle ----------------------- - - Whether or not the layer control is shown The default value is _false_ - - - tab ------ - - The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >50 changesets) The default value is _0_ - - - z ---- - - The initial/current zoom level The default value is _0_ - - - lat ------ - - The initial/current latitude The default value is _0_ - - - lon ------ - - The initial/current longitude of the app The default value is _0_ - - - fs-userbadge --------------- - - Disables/Enables the user information pill (userbadge) at the top left. Disabling this disables logging in and thus disables editing all together, effectively putting MapComplete into read-only mode. The default value is _true_ - - - fs-search ------------ - - Disables/Enables the search bar The default value is _true_ - - - fs-layers ------------ - - Disables/Enables the layer control The default value is _true_ - - - fs-add-new ------------- - - Disables/Enables the 'add new feature'-popup. (A theme without presets might not have it in the first place) The default value is _true_ - - - fs-welcome-message --------------------- - - Disables/enables the help menu or welcome message The default value is _true_ - - - fs-iframe ------------ - - Disables/Enables the iframe-popup The default value is _false_ - - - fs-more-quests ----------------- - - Disables/Enables the 'More Quests'-tab in the welcome message The default value is _true_ - - - fs-share-screen ------------------ - - Disables/Enables the 'Share-screen'-tab in the welcome message The default value is _true_ - - - fs-geolocation ----------------- - - Disables/Enables the geolocation button The default value is _true_ - - - fs-all-questions ------------------- - - Always show all questions The default value is _false_ - - - test ------- - - If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org The default value is _false_ - - - debug -------- - - If true, shows some extra debugging help such as all the available tags on every object The default value is _false_ - - - backend +backend --------- - The OSM backend to use - can be used to redirect mapcomplete to the testing backend when using 'osm-test' The default value is _osm_ +The OSM backend to use - can be used to redirect mapcomplete to the testing backend when using 'osm-test' The default value is _osm_ - custom-css +test +------ + +If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org The default value is _false_ + + +layout +-------- + +The layout to load into MapComplete The default value is __ + + +userlayout ------------ - If specified, the custom css from the given link will be loaded additionaly The default value is __ +If not 'false', a custom (non-official) theme is loaded. This custom layout can be done in multiple ways: + +- The hash of the URL contains a base64-encoded .json-file containing the theme definition +- The hash of the URL contains a lz-compressed .json-file, as generated by the custom theme generator +- The parameter itself is an URL, in which case that URL will be downloaded. It should point to a .json of a theme The default value is _false_ - background +layer-control-toggle +---------------------- + +Whether or not the layer control is shown The default value is _false_ + + +tab +----- + +The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >50 changesets) The default value is _0_ + + +z +--- + +The initial/current zoom level The default value is _14_ + + +lat +----- + +The initial/current latitude The default value is _51.2095_ + + +lon +----- + +The initial/current longitude of the app The default value is _3.2228_ + + +fs-userbadge +-------------- + +Disables/Enables the user information pill (userbadge) at the top left. Disabling this disables logging in and thus disables editing all together, effectively putting MapComplete into read-only mode. The default value is _true_ + + +fs-search +----------- + +Disables/Enables the search bar The default value is _true_ + + +fs-layers +----------- + +Disables/Enables the layer control The default value is _true_ + + +fs-add-new ------------ - The id of the background layer to start with The default value is _osm_ +Disables/Enables the 'add new feature'-popup. (A theme without presets might not have it in the first place) The default value is _true_ +fs-welcome-message +-------------------- + +Disables/enables the help menu or welcome message The default value is _true_ + + +fs-iframe +----------- + +Disables/Enables the iframe-popup The default value is _false_ + + +fs-more-quests +---------------- + +Disables/Enables the 'More Quests'-tab in the welcome message The default value is _true_ + + +fs-share-screen +----------------- + +Disables/Enables the 'Share-screen'-tab in the welcome message The default value is _true_ + + +fs-geolocation +---------------- + +Disables/Enables the geolocation button The default value is _true_ + + +fs-all-questions +------------------ + +Always show all questions The default value is _false_ + + +fs-export +----------- + +If set, enables the 'download'-button to download everything as geojson The default value is _false_ + + +fake-user +----------- + +If true, 'dryrun' mode is activated and a fake user account is loaded The default value is _false_ + + +debug +------- + +If true, shows some extra debugging help such as all the available tags on every object The default value is _false_ + + +custom-css +------------ + +If specified, the custom css from the given link will be loaded additionaly The default value is __ + + +background +------------ + +The id of the background layer to start with The default value is _osm_ + + +oauth_token +------------- + +Used to complete the login No default value set layer- ------------------ diff --git a/Logic/Osm/OsmConnection.ts b/Logic/Osm/OsmConnection.ts index 37c8fa1d2..92a0823f6 100644 --- a/Logic/Osm/OsmConnection.ts +++ b/Logic/Osm/OsmConnection.ts @@ -47,6 +47,7 @@ export class OsmConnection { public auth; public userDetails: UIEventSource; public isLoggedIn: UIEventSource + private fakeUser: boolean; _dryRun: boolean; public preferencesHandler: OsmPreferences; public changesetHandler: ChangesetHandler; @@ -59,12 +60,15 @@ export class OsmConnection { url: string }; - constructor(dryRun: boolean, oauth_token: UIEventSource, + constructor(dryRun: boolean, + fakeUser: boolean, + oauth_token: UIEventSource, // Used to keep multiple changesets open and to write to the correct changeset layoutName: string, singlePage: boolean = true, osmConfiguration: "osm" | "osm-test" = 'osm' ) { + this.fakeUser = fakeUser; this._singlePage = singlePage; this._oauth_config = OsmConnection.oauth_configs[osmConfiguration] ?? OsmConnection.oauth_configs.osm; console.debug("Using backend", this._oauth_config.url) @@ -72,7 +76,15 @@ export class OsmConnection { this._iframeMode = Utils.runningFromConsole ? false : window !== window.top; this.userDetails = new UIEventSource(new UserDetails(this._oauth_config.url), "userDetails"); - this.userDetails.data.dryRun = dryRun; + this.userDetails.data.dryRun = dryRun || fakeUser; + if(fakeUser){ + const ud = this.userDetails.data; + ud.csCount = 5678 + ud.loggedIn= true; + ud.unreadMessages = 0 + ud.name = "Fake user" + ud.totalMessages = 42; + } const self =this; this.isLoggedIn = this.userDetails.map(user => user.loggedIn).addCallback(isLoggedIn => { if(self.userDetails.data.loggedIn == false && isLoggedIn == true){ @@ -138,6 +150,10 @@ export class OsmConnection { } public AttemptLogin() { + if(this.fakeUser){ + console.log("AttemptLogin called, but ignored as fakeUser is set") + return; + } const self = this; console.log("Trying to log in..."); this.updateAuthObject(); diff --git a/State.ts b/State.ts index 90289bcab..a5bad6706 100644 --- a/State.ts +++ b/State.ts @@ -59,8 +59,8 @@ export default class State { public favouriteLayers: UIEventSource; public layerUpdater: OverpassFeatureSource; - - public osmApiFeatureSource : OsmApiFeatureSource ; + + public osmApiFeatureSource: OsmApiFeatureSource; public filteredLayers: UIEventSource<{ @@ -81,7 +81,7 @@ export default class State { * Keeps track of relations: which way is part of which other way? * Set by the overpass-updater; used in the metatagging */ - public readonly knownRelations = new UIEventSource>(undefined, "Relation memberships") + public readonly knownRelations = new UIEventSource>(undefined, "Relation memberships") public readonly featureSwitchUserbadge: UIEventSource; public readonly featureSwitchSearch: UIEventSource; @@ -96,8 +96,8 @@ export default class State { public readonly featureSwitchIsDebugging: UIEventSource; public readonly featureSwitchShowAllQuestions: UIEventSource; public readonly featureSwitchApiURL: UIEventSource; - public readonly featureSwitchEnableExport: UIEventSource; - + public readonly featureSwitchEnableExport: UIEventSource; + public readonly featureSwitchFakeUser: UIEventSource; public readonly featurePipeline: FeaturePipeline; @@ -131,7 +131,7 @@ export default class State { public welcomeMessageOpenedTab = QueryParameters.GetQueryParameter("tab", "0", `The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >${Constants.userJourney.mapCompleteHelpUnlock} changesets)`).map( str => isNaN(Number(str)) ? 0 : Number(str), [], n => "" + n ); - + constructor(layoutToUse: LayoutConfig) { const self = this; @@ -205,20 +205,24 @@ export default class State { "Disables/Enables the geolocation button"); this.featureSwitchShowAllQuestions = featSw("fs-all-questions", (layoutToUse) => layoutToUse?.enableShowAllQuestions ?? false, "Always show all questions"); - this.featureSwitchEnableExport = featSw("fs-export",(layoutToUse) => layoutToUse?.enableExportButton ?? false, + this.featureSwitchEnableExport = featSw("fs-export", (layoutToUse) => layoutToUse?.enableExportButton ?? false, "If set, enables the 'download'-button to download everything as geojson") this.featureSwitchIsTesting = QueryParameters.GetQueryParameter("test", "false", "If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org") .map(str => str === "true", [], b => "" + b); - - this.featureSwitchIsDebugging = QueryParameters.GetQueryParameter("debug","false", + + this.featureSwitchFakeUser = QueryParameters.GetQueryParameter("fake-user", "false", + "If true, 'dryrun' mode is activated and a fake user account is loaded") + .map(str => str === "true", [], b => "" + b); + + this.featureSwitchIsDebugging = QueryParameters.GetQueryParameter("debug", "false", "If true, shows some extra debugging help such as all the available tags on every object") .map(str => str === "true", [], b => "" + b) - this.featureSwitchApiURL = QueryParameters.GetQueryParameter("backend","osm", + this.featureSwitchApiURL = QueryParameters.GetQueryParameter("backend", "osm", "The OSM backend to use - can be used to redirect mapcomplete to the testing backend when using 'osm-test'") - + } { // Some other feature switches @@ -229,18 +233,19 @@ export default class State { this.backgroundLayerId = QueryParameters.GetQueryParameter("background", - layoutToUse?.defaultBackgroundId ?? "osm", - "The id of the background layer to start with") + layoutToUse?.defaultBackgroundId ?? "osm", + "The id of the background layer to start with") } - - - if(Utils.runningFromConsole){ + + + if (Utils.runningFromConsole) { return; } this.osmConnection = new OsmConnection( this.featureSwitchIsTesting.data, + this.featureSwitchFakeUser.data, QueryParameters.GetQueryParameter("oauth_token", undefined, "Used to complete the login"), layoutToUse?.id, @@ -253,7 +258,7 @@ export default class State { this.allElements = new ElementStorage(); this.changes = new Changes(); this.osmApiFeatureSource = new OsmApiFeatureSource() - + new PendingChangesUploader(this.changes, this.selectedElement); this.mangroveIdentity = new MangroveIdentity( diff --git a/preferences.ts b/preferences.ts index 1c1773a14..a7ae07ded 100644 --- a/preferences.ts +++ b/preferences.ts @@ -12,7 +12,7 @@ import BaseUIElement from "./UI/BaseUIElement"; import Table from "./UI/Base/Table"; -const connection = new OsmConnection(false, new UIEventSource(undefined), ""); +const connection = new OsmConnection(false, false, new UIEventSource(undefined), ""); let rendered = false; diff --git a/test/OsmConnection.spec.ts b/test/OsmConnection.spec.ts index ffcb4840c..2253e56c3 100644 --- a/test/OsmConnection.spec.ts +++ b/test/OsmConnection.spec.ts @@ -15,7 +15,7 @@ export default class OsmConnectionSpec extends T { super("OsmConnectionSpec-test", [ ["login on dev", () => { - const osmConn = new OsmConnection(false, + const osmConn = new OsmConnection(false,false, new UIEventSource(undefined), "Unit test", true, From d0293fb2320123548c10fb6dc555fc2880887852 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Fri, 16 Jul 2021 02:13:41 +0200 Subject: [PATCH 13/26] Fix chrome styling bug --- UI/Popup/FeatureInfoBox.ts | 2 +- UI/Popup/TagRenderingAnswer.ts | 38 +++++++++++++++++----------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/UI/Popup/FeatureInfoBox.ts b/UI/Popup/FeatureInfoBox.ts index f35f73ceb..b456c0ab9 100644 --- a/UI/Popup/FeatureInfoBox.ts +++ b/UI/Popup/FeatureInfoBox.ts @@ -36,7 +36,7 @@ export default class FeatureInfoBox extends ScrollableFullScreen { .SetClass("break-words font-bold sm:p-0.5 md:p-1 sm:p-1.5 md:p-2"); const titleIcons = new Combine( layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon, - "block w-8 h-8 align-baseline box-content sm:p-0.5") + "block w-8 h-8 align-baseline box-content sm:p-0.5", "width: 2rem;") )) .SetClass("flex flex-row flex-wrap pt-0.5 sm:pt-1 items-center mr-2") diff --git a/UI/Popup/TagRenderingAnswer.ts b/UI/Popup/TagRenderingAnswer.ts index 6c8fd257e..c8953dd01 100644 --- a/UI/Popup/TagRenderingAnswer.ts +++ b/UI/Popup/TagRenderingAnswer.ts @@ -16,31 +16,31 @@ export default class TagRenderingAnswer extends VariableUiElement { throw "Trying to generate a tagRenderingAnswer without configuration..." } super(tagsSource.map(tags => { - if(tags === undefined){ + if (tags === undefined) { return undefined; } - - if(configuration.condition){ - if(!configuration.condition.matchesProperties(tags)){ + + if (configuration.condition) { + if (!configuration.condition.matchesProperties(tags)) { return undefined; } } - - const trs = Utils.NoNull(configuration.GetRenderValues(tags)); - if(trs.length === 0){ - return undefined; - } - - const valuesToRender: BaseUIElement[] = trs.map(tr => new SubstitutedTranslation(tr, tagsSource)) - if(valuesToRender.length === 1){ - return valuesToRender[0]; - }else if(valuesToRender.length > 1){ - return new List(valuesToRender) - } - return undefined; - }).map((element : BaseUIElement) => element?.SetClass(contentClasses)?.SetStyle(contentStyle))) - this.SetClass("flex items-center flex-row text-lg link-underline tag-renering-answer") + const trs = Utils.NoNull(configuration.GetRenderValues(tags)); + if (trs.length === 0) { + return undefined; + } + + const valuesToRender: BaseUIElement[] = trs.map(tr => new SubstitutedTranslation(tr, tagsSource)) + if (valuesToRender.length === 1) { + return valuesToRender[0]; + } else if (valuesToRender.length > 1) { + return new List(valuesToRender) + } + return undefined; + }).map((element: BaseUIElement) => element?.SetClass(contentClasses)?.SetStyle(contentStyle))) + + this.SetClass("flex items-center flex-row text-lg link-underline") this.SetStyle("word-wrap: anywhere;"); } From d8287ba1c5b95dde22de0b11089ea00433eb86ed Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Fri, 16 Jul 2021 02:24:27 +0200 Subject: [PATCH 14/26] Fix minimaps --- UI/Base/Minimap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/Base/Minimap.ts b/UI/Base/Minimap.ts index 2c38e8b74..a7066c9ee 100644 --- a/UI/Base/Minimap.ts +++ b/UI/Base/Minimap.ts @@ -82,7 +82,7 @@ export default class Minimap extends BaseUIElement { doubleClickZoom: this._allowMoving, keyboard: this._allowMoving, touchZoom: this._allowMoving, - zoomAnimation: this._allowMoving, + // Disabling this breaks the geojson layer - don't ask me why! zoomAnimation: this._allowMoving, fadeAnimation: this._allowMoving }); From 1caf70ca96f4e2b8319ef85ca616a866a8fd88ef Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sun, 18 Jul 2021 15:06:36 +0200 Subject: [PATCH 15/26] Add level indication to bike pumps, fixes #434 --- .../bike_repair_station.json | 1 + assets/tagRenderings/questions.json | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/assets/layers/bike_repair_station/bike_repair_station.json b/assets/layers/bike_repair_station/bike_repair_station.json index cc08a9acf..3ad5e5c37 100644 --- a/assets/layers/bike_repair_station/bike_repair_station.json +++ b/assets/layers/bike_repair_station/bike_repair_station.json @@ -249,6 +249,7 @@ } ] }, + "level", { "question": { "en": "Does this bike repair station have a special tool to repair your bike chain?", diff --git a/assets/tagRenderings/questions.json b/assets/tagRenderings/questions.json index 7bff3270a..dd729eafd 100644 --- a/assets/tagRenderings/questions.json +++ b/assets/tagRenderings/questions.json @@ -123,5 +123,41 @@ "all_tags": { "#": "Prints all the tags", "render": "{all_tags()}" + }, + "level": { + "question": { + "nl": "Op welke verdieping bevindt dit punt zich?", + "en": "On what level is this feature located?" + }, + "render": { + "en": "Located on the {level}th floor", + "nl": "Bevindt zich op de {level}de verdieping" + }, +"freeform": { + "key": "level", + "type": "float" +}, + "mappings": [ + { + "if": "location=underground", + "then": { + "en": "Located underground", + "nl": "Bevindt zich ondergrounds" + }, + "hideInAnswer": true + },{ + "if": "level=0", + "then": { + "en": "Located on the ground floor", + "nl": "Bevindt zich gelijkvloers" + } + },{ + "if": "level=1", + "then": { + "en": "Located on the first floor", + "nl": "Bevindt zich op de eerste verdieping" + } + } + ] } } \ No newline at end of file From 0e9e1f87968a9c89c684c4450445b8a864313c48 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sun, 18 Jul 2021 15:07:20 +0200 Subject: [PATCH 16/26] Version bump --- Models/Constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Models/Constants.ts b/Models/Constants.ts index 34859e614..6747a64a3 100644 --- a/Models/Constants.ts +++ b/Models/Constants.ts @@ -2,7 +2,7 @@ import { Utils } from "../Utils"; export default class Constants { - public static vNumber = "0.8.3e"; + public static vNumber = "0.8.3f"; // The user journey states thresholds when a new feature gets unlocked public static userJourney = { From bd89e66acab46a81b2690bf869810f514bf8cdd3 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sun, 18 Jul 2021 18:02:17 +0200 Subject: [PATCH 17/26] Translation sync, move new question to the bottom --- assets/layers/bench/bench.json | 66 ++- assets/layers/bench_at_pt/bench_at_pt.json | 6 +- .../bicycle_library/bicycle_library.json | 3 +- assets/layers/bike_cafe/bike_cafe.json | 27 +- .../bike_monitoring_station.json | 3 +- assets/layers/bike_parking/bike_parking.json | 18 +- .../bike_repair_station.json | 16 +- assets/layers/bike_shop/bike_shop.json | 36 +- .../layers/defibrillator/defibrillator.json | 3 +- assets/layers/ghost_bike/ghost_bike.json | 6 +- assets/layers/picnic_table/picnic_table.json | 9 +- assets/layers/playground/playground.json | 36 +- .../public_bookcase/public_bookcase.json | 29 +- assets/layers/sport_pitch/sport_pitch.json | 51 ++- .../surveillance_camera.json | 15 +- assets/layers/toilet/toilet.json | 24 +- assets/layers/tree_node/tree_node.json | 33 +- assets/tagRenderings/questions.json | 14 +- assets/themes/artwork/artwork.json | 2 +- .../bicycle_library/bicycle_library.json | 6 +- assets/themes/campersites/campersites.json | 54 ++- .../charging_stations/charging_stations.json | 33 +- assets/themes/climbing/climbing.json | 21 +- assets/themes/cyclestreets/cyclestreets.json | 9 +- .../themes/drinking_water/drinking_water.json | 3 +- .../themes/facadegardens/facadegardens.json | 18 +- assets/themes/fritures/fritures.json | 9 +- assets/themes/hailhydrant/hailhydrant.json | 109 +++-- assets/themes/maps/maps.json | 6 +- .../openwindpowermap/openwindpowermap.json | 344 +++++++------- .../themes/personalLayout/personalLayout.json | 6 +- assets/themes/playgrounds/playgrounds.json | 12 +- assets/themes/shops/shops.json | 52 ++- .../themes/sport_pitches/sport_pitches.json | 9 +- assets/themes/trees/trees.json | 6 +- langs/layers/fi.json | 172 +++---- langs/layers/ru.json | 432 +++++++++--------- langs/shared-questions/en.json | 15 + langs/shared-questions/nl.json | 15 + langs/themes/de.json | 8 +- langs/themes/en.json | 62 +++ langs/themes/nl.json | 240 +++++----- langs/themes/ru.json | 262 +++++------ scripts/generateTranslations.ts | 4 + 44 files changed, 1343 insertions(+), 961 deletions(-) diff --git a/assets/layers/bench/bench.json b/assets/layers/bench/bench.json index 2ba7c0358..312b21cfc 100644 --- a/assets/layers/bench/bench.json +++ b/assets/layers/bench/bench.json @@ -12,7 +12,8 @@ "ru": "Скамейки", "zh_Hans": "长椅", "zh_Hant": "長椅", - "nb_NO": "Benker" + "nb_NO": "Benker", + "fi": "Penkit" }, "minzoom": 14, "source": { @@ -31,7 +32,8 @@ "ru": "Скамейка", "zh_Hans": "长椅", "zh_Hant": "長椅", - "nb_NO": "Benk" + "nb_NO": "Benk", + "fi": "Penkki" } }, "tagRenderings": [ @@ -49,7 +51,8 @@ "ru": "Спинка", "zh_Hans": "靠背", "zh_Hant": "靠背", - "nb_NO": "Rygglene" + "nb_NO": "Rygglene", + "fi": "Selkänoja" }, "freeform": { "key": "backrest" @@ -69,7 +72,8 @@ "ru": "Со спинкой", "zh_Hans": "靠背:有", "zh_Hant": "靠背:有", - "nb_NO": "Rygglene: Ja" + "nb_NO": "Rygglene: Ja", + "fi": "Selkänoja: kyllä" } }, { @@ -86,7 +90,8 @@ "ru": "Без спинки", "zh_Hans": "靠背:无", "zh_Hant": "靠背:無", - "nb_NO": "Rygglene: Nei" + "nb_NO": "Rygglene: Nei", + "fi": "Selkänoja: ei" } } ], @@ -149,7 +154,8 @@ "ru": "Материал: {material}", "zh_Hans": "材质: {material}", "zh_Hant": "材質:{material}", - "nb_NO": "Materiale: {material}" + "nb_NO": "Materiale: {material}", + "fi": "Materiaali: {material}" }, "freeform": { "key": "material", @@ -170,7 +176,8 @@ "zh_Hans": "材质:木", "nb_NO": "Materiale: tre", "zh_Hant": "材質:木頭", - "pt_BR": "Material: madeira" + "pt_BR": "Material: madeira", + "fi": "Materiaali: puu" } }, { @@ -203,7 +210,8 @@ "zh_Hans": "材质:石头", "nb_NO": "Materiale: stein", "zh_Hant": "材質:石頭", - "pt_BR": "Material: pedra" + "pt_BR": "Material: pedra", + "fi": "Materiaali: kivi" } }, { @@ -220,7 +228,8 @@ "zh_Hans": "材质:混凝土", "nb_NO": "Materiale: betong", "zh_Hant": "材質:水泥", - "pt_BR": "Material: concreto" + "pt_BR": "Material: concreto", + "fi": "Materiaali: betoni" } }, { @@ -237,7 +246,8 @@ "zh_Hans": "材质:塑料", "nb_NO": "Materiale: plastikk", "zh_Hant": "材質:塑膠", - "pt_BR": "Material: plástico" + "pt_BR": "Material: plástico", + "fi": "Materiaali: muovi" } }, { @@ -254,7 +264,8 @@ "zh_Hans": "材质:不锈钢", "nb_NO": "Materiale: stål", "zh_Hant": "材質:鋼鐵", - "pt_BR": "Material: aço" + "pt_BR": "Material: aço", + "fi": "Materiaali: teräs" } } ], @@ -313,7 +324,8 @@ "zh_Hans": "颜色: {colour}", "zh_Hant": "顏色:{colour}", "nb_NO": "Farge: {colour}", - "pt_BR": "Cor: {colour}" + "pt_BR": "Cor: {colour}", + "fi": "Väri: {colour}" }, "question": { "en": "Which colour does this bench have?", @@ -345,7 +357,8 @@ "zh_Hans": "颜色:棕", "zh_Hant": "顏色:棕色", "nb_NO": "Farge: brun", - "pt_BR": "Cor: marrom" + "pt_BR": "Cor: marrom", + "fi": "Väri: ruskea" } }, { @@ -361,7 +374,8 @@ "zh_Hans": "颜色:绿", "zh_Hant": "顏色:綠色", "nb_NO": "Farge: grønn", - "pt_BR": "Cor: verde" + "pt_BR": "Cor: verde", + "fi": "Väri: vihreä" } }, { @@ -377,7 +391,8 @@ "zh_Hans": "颜色:灰", "zh_Hant": "顏色:灰色", "nb_NO": "Farge: grå", - "pt_BR": "Cor: cinza" + "pt_BR": "Cor: cinza", + "fi": "Väri: harmaa" } }, { @@ -393,7 +408,8 @@ "zh_Hans": "颜色:白", "zh_Hant": "顏色:白色", "nb_NO": "Farge: hvit", - "pt_BR": "Cor: branco" + "pt_BR": "Cor: branco", + "fi": "Väri: valkoinen" } }, { @@ -409,7 +425,8 @@ "zh_Hans": "颜色:红", "zh_Hant": "顏色:紅色", "nb_NO": "Farge: rød", - "pt_BR": "Cor: vermelho" + "pt_BR": "Cor: vermelho", + "fi": "Väri: punainen" } }, { @@ -425,7 +442,8 @@ "zh_Hans": "颜色:黑", "zh_Hant": "顏色:黑色", "nb_NO": "Farge: svart", - "pt_BR": "Cor: preto" + "pt_BR": "Cor: preto", + "fi": "Väri: musta" } }, { @@ -441,7 +459,8 @@ "zh_Hans": "颜色:蓝", "zh_Hant": "顏色:藍色", "nb_NO": "Farge: blå", - "pt_BR": "Cor: azul" + "pt_BR": "Cor: azul", + "fi": "Väri: sininen" } }, { @@ -457,7 +476,8 @@ "zh_Hans": "颜色:黄", "zh_Hant": "顏色:黃色", "nb_NO": "Farge: gul", - "pt_BR": "Cor: amarelo" + "pt_BR": "Cor: amarelo", + "fi": "Väri: keltainen" } } ] @@ -528,7 +548,8 @@ "zh_Hans": "长椅", "nb_NO": "Benk", "zh_Hant": "長椅", - "pt_BR": "Banco" + "pt_BR": "Banco", + "fi": "Penkki" }, "description": { "en": "Add a new bench", @@ -542,7 +563,8 @@ "zh_Hans": "增加一个新的长椅", "nb_NO": "Legg til en ny benk", "zh_Hant": "新增長椅", - "pt_BR": "Adicionar um novo banco" + "pt_BR": "Adicionar um novo banco", + "fi": "Lisää uusi penkki" } } ] diff --git a/assets/layers/bench_at_pt/bench_at_pt.json b/assets/layers/bench_at_pt/bench_at_pt.json index 85cadb86e..bb2661e25 100644 --- a/assets/layers/bench_at_pt/bench_at_pt.json +++ b/assets/layers/bench_at_pt/bench_at_pt.json @@ -37,7 +37,8 @@ "zh_Hans": "长椅", "nb_NO": "Benk", "zh_Hant": "長椅", - "pt_BR": "Banco" + "pt_BR": "Banco", + "fi": "Penkki" }, "mappings": [ { @@ -96,7 +97,8 @@ "id": "{name}", "zh_Hans": "{name}", "zh_Hant": "{name}", - "pt_BR": "{name}" + "pt_BR": "{name}", + "fi": "{name}" }, "freeform": { "key": "name" diff --git a/assets/layers/bicycle_library/bicycle_library.json b/assets/layers/bicycle_library/bicycle_library.json index cb6cb2f2e..d56f3bc42 100644 --- a/assets/layers/bicycle_library/bicycle_library.json +++ b/assets/layers/bicycle_library/bicycle_library.json @@ -145,7 +145,8 @@ "fr": "Emprunter un vélo coûte 20 €/an et 20 € de garantie", "it": "Il prestito di una bicicletta costa 20 €/anno più 20 € di garanzia", "de": "Das Ausleihen eines Fahrrads kostet 20€ pro Jahr und 20€ Gebühr", - "zh_Hant": "租借單車價錢 €20/year 與 €20 保證金" + "zh_Hant": "租借單車價錢 €20/year 與 €20 保證金", + "ru": "Прокат велосипеда стоит €20/год и €20 залог" } } ] diff --git a/assets/layers/bike_cafe/bike_cafe.json b/assets/layers/bike_cafe/bike_cafe.json index 77b582395..30dcb1760 100644 --- a/assets/layers/bike_cafe/bike_cafe.json +++ b/assets/layers/bike_cafe/bike_cafe.json @@ -117,7 +117,8 @@ "de": "Dieses Fahrrad-Café bietet eine Fahrradpumpe an, die von jedem benutzt werden kann", "it": "Questo caffè in bici offre una pompa per bici liberamente utilizzabile", "zh_Hans": "这家自行车咖啡为每个人提供打气筒", - "zh_Hant": "這個單車咖啡廳有提供給任何人都能使用的單車打氣甬" + "zh_Hant": "這個單車咖啡廳有提供給任何人都能使用的單車打氣甬", + "ru": "В этом велосипедном кафе есть велосипедный насос для всеобщего использования" } }, { @@ -130,7 +131,8 @@ "de": "Dieses Fahrrad-Café bietet keine Fahrradpumpe an, die von jedem benutzt werden kann", "it": "Questo caffè in bici non offre una pompa per bici liberamente utilizzabile", "zh_Hans": "这家自行车咖啡不为每个人提供打气筒", - "zh_Hant": "這個單車咖啡廳並沒有為所有人提供單車打氣甬" + "zh_Hant": "這個單車咖啡廳並沒有為所有人提供單車打氣甬", + "ru": "В этом велосипедном кафе нет велосипедного насоса для всеобщего использования" } } ] @@ -144,7 +146,8 @@ "de": "Gibt es hier Werkzeuge, um das eigene Fahrrad zu reparieren?", "it": "Ci sono degli strumenti per riparare la propria bicicletta?", "zh_Hans": "这里有供你修车用的工具吗?", - "zh_Hant": "這裡是否有工具修理你的單車嗎?" + "zh_Hant": "這裡是否有工具修理你的單車嗎?", + "ru": "Есть ли здесь инструменты для починки вашего велосипеда?" }, "mappings": [ { @@ -157,7 +160,8 @@ "de": "Dieses Fahrrad-Café bietet Werkzeuge für die selbständige Reparatur an", "it": "Questo caffè in bici fornisce degli attrezzi per la riparazione fai-da-te", "zh_Hans": "这家自行车咖啡为DIY修理者提供工具", - "zh_Hant": "這個單車咖啡廳提供工具讓你修理" + "zh_Hant": "這個單車咖啡廳提供工具讓你修理", + "ru": "В этом велосипедном кафе есть инструменты для починки своего велосипеда" } }, { @@ -170,7 +174,8 @@ "de": "Dieses Fahrrad-Café bietet keine Werkzeuge für die selbständige Reparatur an", "it": "Questo caffè in bici non fornisce degli attrezzi per la riparazione fai-da-te", "zh_Hans": "这家自行车咖啡不为DIY修理者提供工具", - "zh_Hant": "這個單車咖啡廳並沒有提供工具讓你修理" + "zh_Hant": "這個單車咖啡廳並沒有提供工具讓你修理", + "ru": "В этом велосипедном кафе нет инструментов для починки своего велосипеда" } } ] @@ -184,7 +189,8 @@ "de": "Repariert dieses Fahrrad-Café Fahrräder?", "it": "Questo caffè in bici ripara le bici?", "zh_Hans": "这家自行车咖啡t提供修车服务吗?", - "zh_Hant": "這個單車咖啡廳是否能修理單車?" + "zh_Hant": "這個單車咖啡廳是否能修理單車?", + "ru": "Есть ли услуги ремонта велосипедов в этом велосипедном кафе?" }, "mappings": [ { @@ -197,7 +203,8 @@ "de": "Dieses Fahrrad-Café repariert Fahrräder", "it": "Questo caffè in bici ripara le bici", "zh_Hans": "这家自行车咖啡可以修车", - "zh_Hant": "這個單車咖啡廳修理單車" + "zh_Hant": "這個單車咖啡廳修理單車", + "ru": "В этом велосипедном кафе есть услуги ремонта велосипедов" } }, { @@ -210,7 +217,8 @@ "de": "Dieses Fahrrad-Café repariert keine Fahrräder", "it": "Questo caffè in bici non ripara le bici", "zh_Hans": "这家自行车咖啡不能修车", - "zh_Hant": "這個單車咖啡廳並不修理單車" + "zh_Hant": "這個單車咖啡廳並不修理單車", + "ru": "В этом велосипедном кафе нет услуг ремонта велосипедов" } } ] @@ -275,7 +283,8 @@ "fr": "Quand ce Café vélo est-t-il ouvert ?", "it": "Quando è aperto questo caffè in bici?", "zh_Hans": "这家自行车咖啡什么时候开门营业?", - "zh_Hant": "何時這個單車咖啡廳營運?" + "zh_Hant": "何時這個單車咖啡廳營運?", + "ru": "Каков режим работы этого велосипедного кафе?" }, "render": "{opening_hours_table(opening_hours)}", "freeform": { diff --git a/assets/layers/bike_monitoring_station/bike_monitoring_station.json b/assets/layers/bike_monitoring_station/bike_monitoring_station.json index 0f54f36de..34b4d1b63 100644 --- a/assets/layers/bike_monitoring_station/bike_monitoring_station.json +++ b/assets/layers/bike_monitoring_station/bike_monitoring_station.json @@ -5,7 +5,8 @@ "nl": "Telstation", "fr": "Stations de contrôle", "it": "Stazioni di monitoraggio", - "zh_Hant": "監視站" + "zh_Hant": "監視站", + "ru": "Станции мониторинга" }, "minzoom": 12, "source": { diff --git a/assets/layers/bike_parking/bike_parking.json b/assets/layers/bike_parking/bike_parking.json index 368931aa8..be24e0a6d 100644 --- a/assets/layers/bike_parking/bike_parking.json +++ b/assets/layers/bike_parking/bike_parking.json @@ -77,7 +77,8 @@ "de": "Dies ist ein Fahrrad-Parkplatz der Art: {bicycle_parking}", "hu": "Ez egy {bicycle_parking} típusú kerékpáros parkoló", "it": "È un parcheggio bici del tipo: {bicycle_parking}", - "zh_Hant": "這個單車停車場的類型是:{bicycle_parking}" + "zh_Hant": "這個單車停車場的類型是:{bicycle_parking}", + "ru": "Это велопарковка типа {bicycle_parking}" }, "freeform": { "key": "bicycle_parking", @@ -288,7 +289,8 @@ "fr": "Ce parking est couvert (il a un toit)", "hu": "A parkoló fedett", "it": "È un parcheggio coperto (ha un tetto)", - "zh_Hant": "這個停車場有遮蔽 (有屋頂)" + "zh_Hant": "這個停車場有遮蔽 (有屋頂)", + "ru": "Это крытая парковка (есть крыша/навес)" } }, { @@ -301,7 +303,8 @@ "fr": "Ce parking n'est pas couvert", "hu": "A parkoló nem fedett", "it": "Non è un parcheggio coperto", - "zh_Hant": "這個停車場沒有遮蔽" + "zh_Hant": "這個停車場沒有遮蔽", + "ru": "Это открытая парковка" } } ] @@ -324,7 +327,8 @@ "gl": "Lugar para {capacity} bicicletas", "de": "Platz für {capacity} Fahrräder", "it": "Posti per {capacity} bici", - "zh_Hant": "{capacity} 單車的地方" + "zh_Hant": "{capacity} 單車的地方", + "ru": "Место для {capacity} велосипеда(ов)" }, "freeform": { "key": "capacity", @@ -339,7 +343,8 @@ "fr": "Qui peut utiliser ce parking à vélo ?", "it": "Chi può usare questo parcheggio bici?", "de": "Wer kann diesen Fahrradparplatz nutzen?", - "zh_Hant": "誰可以使用這個單車停車場?" + "zh_Hant": "誰可以使用這個單車停車場?", + "ru": "Кто может пользоваться этой велопарковкой?" }, "render": { "en": "{access}", @@ -349,7 +354,8 @@ "it": "{access}", "ru": "{access}", "id": "{access}", - "zh_Hant": "{access}" + "zh_Hant": "{access}", + "fi": "{access}" }, "freeform": { "key": "access", diff --git a/assets/layers/bike_repair_station/bike_repair_station.json b/assets/layers/bike_repair_station/bike_repair_station.json index 3ad5e5c37..6f59d8a5c 100644 --- a/assets/layers/bike_repair_station/bike_repair_station.json +++ b/assets/layers/bike_repair_station/bike_repair_station.json @@ -218,7 +218,8 @@ "en": "When is this bicycle repair point open?", "fr": "Quand ce point de réparation de vélo est-il ouvert ?", "it": "Quando è aperto questo punto riparazione bici?", - "de": "Wann ist diese Fahrradreparaturstelle geöffnet?" + "de": "Wann ist diese Fahrradreparaturstelle geöffnet?", + "ru": "Когда работает эта точка обслуживания велосипедов?" }, "render": "{opening_hours_table()}", "freeform": { @@ -233,7 +234,8 @@ "en": "Always open", "fr": "Ouvert en permanence", "it": "Sempre aperto", - "de": "Immer geöffnet" + "de": "Immer geöffnet", + "ru": "Всегда открыто" } }, { @@ -249,7 +251,6 @@ } ] }, - "level", { "question": { "en": "Does this bike repair station have a special tool to repair your bike chain?", @@ -507,13 +508,15 @@ } } ] - } + }, + "level" ], "icon": { "render": { "en": "./assets/layers/bike_repair_station/repair_station.svg", "ru": "./assets/layers/bike_repair_station/repair_station.svg", - "it": "./assets/layers/bike_repair_station/repair_station.svg" + "it": "./assets/layers/bike_repair_station/repair_station.svg", + "fi": "./assets/layers/bike_repair_station/repair_station.svg" }, "mappings": [ { @@ -585,7 +588,8 @@ "gl": "Bomba de ar", "de": "Fahrradpumpe", "it": "Pompa per bici", - "ru": "Велосипедный насос" + "ru": "Велосипедный насос", + "fi": "Pyöräpumppu" }, "tags": [ "amenity=bicycle_repair_station", diff --git a/assets/layers/bike_shop/bike_shop.json b/assets/layers/bike_shop/bike_shop.json index 72ced485e..7f60ced89 100644 --- a/assets/layers/bike_shop/bike_shop.json +++ b/assets/layers/bike_shop/bike_shop.json @@ -6,7 +6,8 @@ "fr": "Magasin ou réparateur de vélo", "gl": "Tenda/arranxo de bicicletas", "de": "Fahrradwerkstatt/geschäft", - "it": "Venditore/riparatore bici" + "it": "Venditore/riparatore bici", + "ru": "Обслуживание велосипедов/магазин" }, "minzoom": 13, "source": { @@ -54,7 +55,8 @@ "fr": "Magasin ou réparateur de vélo", "gl": "Tenda/arranxo de bicicletas", "de": "Fahrradwerkstatt/geschäft", - "it": "Venditore/riparatore bici" + "it": "Venditore/riparatore bici", + "ru": "Обслуживание велосипедов/магазин" }, "mappings": [ { @@ -207,7 +209,8 @@ "fr": "Ce magasin s'appelle {name}", "gl": "Esta tenda de bicicletas chámase {name}", "de": "Dieses Fahrradgeschäft heißt {name}", - "it": "Questo negozio di biciclette è chiamato {name}" + "it": "Questo negozio di biciclette è chiamato {name}", + "ru": "Этот магазин велосипедов называется {name}" }, "freeform": { "key": "name" @@ -284,7 +287,8 @@ "fr": "Est-ce que ce magasin vend des vélos ?", "gl": "Esta tenda vende bicicletas?", "de": "Verkauft dieser Laden Fahrräder?", - "it": "Questo negozio vende bici?" + "it": "Questo negozio vende bici?", + "ru": "Продаются ли велосипеды в этом магазине?" }, "mappings": [ { @@ -368,7 +372,8 @@ "fr": "Ce magasin ne répare seulement des marques spécifiques", "gl": "Esta tenda só arranxa bicicletas dunha certa marca", "de": "Dieses Geschäft repariert nur Fahrräder einer bestimmten Marke", - "it": "Questo negozio ripara solo le biciclette di una certa marca" + "it": "Questo negozio ripara solo le biciclette di una certa marca", + "ru": "В этом магазине обслуживают велосипеды определённого бренда" } } ] @@ -466,7 +471,8 @@ "fr": "Est-ce que ce magasin offre une pompe en accès libre ?", "gl": "Esta tenda ofrece unha bomba de ar para uso de calquera persoa?", "de": "Bietet dieses Geschäft eine Fahrradpumpe zur Benutzung für alle an?", - "it": "Questo negozio offre l’uso a chiunque di una pompa per bici?" + "it": "Questo negozio offre l’uso a chiunque di una pompa per bici?", + "ru": "Предлагается ли в этом магазине велосипедный насос для всеобщего пользования?" }, "mappings": [ { @@ -477,7 +483,8 @@ "fr": "Ce magasin offre une pompe en acces libre", "gl": "Esta tenda ofrece unha bomba de ar para uso de calquera persoa", "de": "Dieses Geschäft bietet eine Fahrradpumpe für alle an", - "it": "Questo negozio offre l’uso pubblico di una pompa per bici" + "it": "Questo negozio offre l’uso pubblico di una pompa per bici", + "ru": "В этом магазине есть велосипедный насос для всеобщего пользования" } }, { @@ -488,7 +495,8 @@ "fr": "Ce magasin n'offre pas de pompe en libre accès", "gl": "Esta tenda non ofrece unha bomba de ar para uso de calquera persoa", "de": "Dieses Geschäft bietet für niemanden eine Fahrradpumpe an", - "it": "Questo negozio non offre l’uso pubblico di una pompa per bici" + "it": "Questo negozio non offre l’uso pubblico di una pompa per bici", + "ru": "В этом магазине нет велосипедного насоса для всеобщего пользования" } }, { @@ -509,7 +517,8 @@ "fr": "Est-ce qu'il y a des outils pour réparer son vélo dans ce magasin ?", "gl": "Hai ferramentas aquí para arranxar a túa propia bicicleta?", "de": "Gibt es hier Werkzeuge, um das eigene Fahrrad zu reparieren?", - "it": "Sono presenti degli attrezzi per riparare la propria bici?" + "it": "Sono presenti degli attrezzi per riparare la propria bici?", + "ru": "Есть ли здесь инструменты для починки собственного велосипеда?" }, "mappings": [ { @@ -541,7 +550,8 @@ "nl": "Het gereedschap aan om je fiets zelf te herstellen is enkel voor als je de fiets er kocht of huurt", "fr": "Des outils d'auto-réparation sont disponibles uniquement si vous avez acheté ou loué le vélo dans ce magasin", "it": "Gli attrezzi per la riparazione fai-da-te sono disponibili solamente se hai acquistato/noleggiato la bici nel negozio", - "de": "Werkzeuge für die Selbstreparatur sind nur verfügbar, wenn Sie das Fahrrad im Laden gekauft/gemietet haben" + "de": "Werkzeuge für die Selbstreparatur sind nur verfügbar, wenn Sie das Fahrrad im Laden gekauft/gemietet haben", + "ru": "Инструменты для починки доступны только при покупке/аренде велосипеда в магазине" } } ] @@ -563,7 +573,8 @@ "nl": "Deze winkel biedt fietsschoonmaak aan", "fr": "Ce magasin lave les vélos", "it": "Questo negozio lava le biciclette", - "de": "Dieses Geschäft reinigt Fahrräder" + "de": "Dieses Geschäft reinigt Fahrräder", + "ru": "В этом магазине оказываются услуги мойки/чистки велосипедов" } }, { @@ -583,7 +594,8 @@ "nl": "Deze winkel biedt geen fietsschoonmaak aan", "fr": "Ce magasin ne fait pas le nettoyage de vélo", "it": "Questo negozio non offre la pulizia della bicicletta", - "de": "Dieser Laden bietet keine Fahrradreinigung an" + "de": "Dieser Laden bietet keine Fahrradreinigung an", + "ru": "В этом магазине нет услуг мойки/чистки велосипедов" } } ] diff --git a/assets/layers/defibrillator/defibrillator.json b/assets/layers/defibrillator/defibrillator.json index 04e3d2925..4074ee963 100644 --- a/assets/layers/defibrillator/defibrillator.json +++ b/assets/layers/defibrillator/defibrillator.json @@ -567,7 +567,8 @@ "nl": "Extra informatie voor OpenStreetMap experts: {fixme}", "fr": "Informations supplémentaires pour les experts d'OpenStreetMap : {fixme}", "it": "Informazioni supplementari per gli esperti di OpenStreetMap: {fixme}", - "de": "Zusätzliche Informationen für OpenStreetMap-Experten: {fixme}" + "de": "Zusätzliche Informationen für OpenStreetMap-Experten: {fixme}", + "ru": "Дополнительная информация для экспертов OpenStreetMap: {fixme}" }, "question": { "en": "Is there something wrong with how this is mapped, that you weren't able to fix here? (leave a note to OpenStreetMap experts)", diff --git a/assets/layers/ghost_bike/ghost_bike.json b/assets/layers/ghost_bike/ghost_bike.json index b7951da3d..2a2b8342d 100644 --- a/assets/layers/ghost_bike/ghost_bike.json +++ b/assets/layers/ghost_bike/ghost_bike.json @@ -76,7 +76,8 @@ "nl": "Ter nagedachtenis van {name}", "de": "Im Gedenken an {name}", "it": "In ricordo di {name}", - "fr": "En souvenir de {name}" + "fr": "En souvenir de {name}", + "ru": "В знак памяти о {name}" }, "freeform": { "key": "name" @@ -149,7 +150,8 @@ "nl": "Geplaatst op {start_date}", "en": "Placed on {start_date}", "it": "Piazzata in data {start_date}", - "fr": "Placé le {start_date}" + "fr": "Placé le {start_date}", + "ru": "Установлен {start_date}" }, "freeform": { "key": "start_date", diff --git a/assets/layers/picnic_table/picnic_table.json b/assets/layers/picnic_table/picnic_table.json index e5be9d077..672e41f07 100644 --- a/assets/layers/picnic_table/picnic_table.json +++ b/assets/layers/picnic_table/picnic_table.json @@ -26,7 +26,8 @@ "en": "The layer showing picnic tables", "nl": "Deze laag toont picnictafels", "it": "Il livello che mostra i tavoli da picnic", - "fr": "La couche montrant les tables de pique-nique" + "fr": "La couche montrant les tables de pique-nique", + "ru": "Слой, отображающий столы для пикника" }, "tagRenderings": [ { @@ -34,13 +35,15 @@ "en": "What material is this picnic table made of?", "nl": "Van welk materiaal is deze picnictafel gemaakt?", "it": "Di che materiale è fatto questo tavolo da picnic?", - "de": "Aus welchem Material besteht dieser Picknicktisch?" + "de": "Aus welchem Material besteht dieser Picknicktisch?", + "ru": "Из чего изготовлен этот стол для пикника?" }, "render": { "en": "This picnic table is made of {material}", "nl": "Deze picnictafel is gemaakt van {material}", "it": "Questo tavolo da picnic è fatto di {material}", - "de": "Dieser Picknicktisch besteht aus {material}" + "de": "Dieser Picknicktisch besteht aus {material}", + "ru": "Этот стол для пикника сделан из {material}" }, "freeform": { "key": "material" diff --git a/assets/layers/playground/playground.json b/assets/layers/playground/playground.json index 54afa9a4c..ec97eca2b 100644 --- a/assets/layers/playground/playground.json +++ b/assets/layers/playground/playground.json @@ -93,7 +93,8 @@ "nl": "De ondergrond bestaat uit houtsnippers", "en": "The surface consist of woodchips", "it": "La superficie consiste di trucioli di legno", - "de": "Die Oberfläche besteht aus Holzschnitzeln" + "de": "Die Oberfläche besteht aus Holzschnitzeln", + "ru": "Покрытие из щепы" } }, { @@ -154,7 +155,8 @@ "en": "Is this playground lit at night?", "it": "È illuminato di notte questo parco giochi?", "fr": "Ce terrain de jeux est-il éclairé la nuit ?", - "de": "Ist dieser Spielplatz nachts beleuchtet?" + "de": "Ist dieser Spielplatz nachts beleuchtet?", + "ru": "Эта игровая площадка освещается ночью?" }, "mappings": [ { @@ -163,7 +165,8 @@ "nl": "Deze speeltuin is 's nachts verlicht", "en": "This playground is lit at night", "it": "Questo parco giochi è illuminato di notte", - "de": "Dieser Spielplatz ist nachts beleuchtet" + "de": "Dieser Spielplatz ist nachts beleuchtet", + "ru": "Эта детская площадка освещается ночью" } }, { @@ -172,7 +175,8 @@ "nl": "Deze speeltuin is 's nachts niet verlicht", "en": "This playground is not lit at night", "it": "Questo parco giochi non è illuminato di notte", - "de": "Dieser Spielplatz ist nachts nicht beleuchtet" + "de": "Dieser Spielplatz ist nachts nicht beleuchtet", + "ru": "Эта детская площадка не освещается ночью" } } ] @@ -189,7 +193,8 @@ "nl": "Wat is de minimale leeftijd om op deze speeltuin te mogen?", "en": "What is the minimum age required to access this playground?", "it": "Qual è l’età minima per accedere a questo parco giochi?", - "fr": "Quel est l'âge minimal requis pour accéder à ce terrain de jeux ?" + "fr": "Quel est l'âge minimal requis pour accéder à ce terrain de jeux ?", + "ru": "С какого возраста доступна эта детская площадка?" }, "freeform": { "key": "min_age", @@ -201,7 +206,8 @@ "nl": "Toegankelijk tot {max_age}", "en": "Accessible to kids of at most {max_age}", "it": "Accessibile ai bambini di età inferiore a {max_age}", - "fr": "Accessible aux enfants de {max_age} au maximum" + "fr": "Accessible aux enfants de {max_age} au maximum", + "ru": "Доступно детям до {max_age}" }, "question": { "nl": "Wat is de maximaal toegestane leeftijd voor deze speeltuin?", @@ -340,7 +346,8 @@ "en": "Is this playground accessible to wheelchair users?", "fr": "Ce terrain de jeux est-il accessible aux personnes en fauteuil roulant ?", "de": "Ist dieser Spielplatz für Rollstuhlfahrer zugänglich?", - "it": "Il campetto è accessibile a persone in sedia a rotelle?" + "it": "Il campetto è accessibile a persone in sedia a rotelle?", + "ru": "Доступна ли детская площадка пользователям кресел-колясок?" }, "mappings": [ { @@ -350,7 +357,8 @@ "en": "Completely accessible for wheelchair users", "fr": "Entièrement accessible aux personnes en fauteuil roulant", "de": "Vollständig zugänglich für Rollstuhlfahrer", - "it": "Completamente accessibile in sedia a rotelle" + "it": "Completamente accessibile in sedia a rotelle", + "ru": "Полностью доступна пользователям кресел-колясок" } }, { @@ -360,7 +368,8 @@ "en": "Limited accessibility for wheelchair users", "fr": "Accessibilité limitée pour les personnes en fauteuil roulant", "de": "Eingeschränkte Zugänglichkeit für Rollstuhlfahrer", - "it": "Accesso limitato in sedia a rotelle" + "it": "Accesso limitato in sedia a rotelle", + "ru": "Частично доступна пользователям кресел-колясок" } }, { @@ -370,7 +379,8 @@ "en": "Not accessible for wheelchair users", "fr": "Non accessible aux personnes en fauteuil roulant", "de": "Nicht zugänglich für Rollstuhlfahrer", - "it": "Non accessibile in sedia a rotelle" + "it": "Non accessibile in sedia a rotelle", + "ru": "Недоступна пользователям кресел-колясок" } } ] @@ -385,7 +395,8 @@ "nl": "Op welke uren is deze speeltuin toegankelijk?", "en": "When is this playground accessible?", "fr": "Quand ce terrain de jeux est-il accessible ?", - "it": "Quando si può accedere a questo campetto?" + "it": "Quando si può accedere a questo campetto?", + "ru": "Когда открыта эта игровая площадка?" }, "mappings": [ { @@ -394,7 +405,8 @@ "nl": "Van zonsopgang tot zonsondergang", "en": "Accessible from sunrise till sunset", "fr": "Accessible du lever au coucher du soleil", - "it": "Si può accedere dall'alba al tramonto" + "it": "Si può accedere dall'alba al tramonto", + "ru": "Открыто от рассвета до заката" } }, { diff --git a/assets/layers/public_bookcase/public_bookcase.json b/assets/layers/public_bookcase/public_bookcase.json index 896f97cea..b2a03e4c8 100644 --- a/assets/layers/public_bookcase/public_bookcase.json +++ b/assets/layers/public_bookcase/public_bookcase.json @@ -13,7 +13,8 @@ "nl": "Een straatkastje met boeken voor iedereen", "de": "Ein Bücherschrank am Straßenrand mit Büchern, für jedermann zugänglich", "fr": "Une armoire ou une boite contenant des livres en libre accès", - "it": "Una vetrinetta ai bordi della strada contenente libri, aperta al pubblico" + "it": "Una vetrinetta ai bordi della strada contenente libri, aperta al pubblico", + "ru": "Уличный шкаф с книгами, доступными для всех" }, "source": { "osmTags": "amenity=public_bookcase" @@ -94,7 +95,7 @@ "nl": "Wat is de naam van dit boekenuilkastje?", "de": "Wie heißt dieser öffentliche Bücherschrank?", "fr": "Quel est le nom de cette microbibliothèque ?", - "ru": "Как называется общественный книжный шкаф?", + "ru": "Как называется этот общественный книжный шкаф?", "it": "Come si chiama questa microbiblioteca pubblica?" }, "freeform": { @@ -125,7 +126,8 @@ "nl": "Er passen {capacity} boeken", "de": "{capacity} Bücher passen in diesen Bücherschrank", "fr": "{capacity} livres peuvent entrer dans cette microbibliothèque", - "it": "Questa microbiblioteca può contenere fino a {capacity} libri" + "it": "Questa microbiblioteca può contenere fino a {capacity} libri", + "ru": "{capacity} книг помещается в этот книжный шкаф" }, "question": { "en": "How many books fit into this public bookcase?", @@ -146,7 +148,8 @@ "nl": "Voor welke doelgroep zijn de meeste boeken in dit boekenruilkastje?", "de": "Welche Art von Büchern sind in diesem öffentlichen Bücherschrank zu finden?", "fr": "Quel type de livres peut-on dans cette microbibliothèque ?", - "it": "Che tipo di libri si possono trovare in questa microbiblioteca?" + "it": "Che tipo di libri si possono trovare in questa microbiblioteca?", + "ru": "Какие книги можно найти в этом общественном книжном шкафу?" }, "mappings": [ { @@ -178,7 +181,8 @@ "nl": "Boeken voor zowel kinderen als volwassenen", "de": "Sowohl Bücher für Kinder als auch für Erwachsene", "fr": "Livres pour enfants et adultes également", - "it": "Sia libri per l'infanzia, sia per l'età adulta" + "it": "Sia libri per l'infanzia, sia per l'età adulta", + "ru": "Книги и для детей, и для взрослых" } } ] @@ -231,7 +235,8 @@ "nl": "Is dit boekenruilkastje publiek toegankelijk?", "de": "Ist dieser öffentliche Bücherschrank frei zugänglich?", "fr": "Cette microbibliothèque est-elle librement accèssible ?", - "it": "Questa microbiblioteca è ad accesso libero?" + "it": "Questa microbiblioteca è ad accesso libero?", + "ru": "Имеется ли свободный доступ к этому общественному книжному шкафу?" }, "condition": "indoor=yes", "mappings": [ @@ -241,7 +246,8 @@ "nl": "Publiek toegankelijk", "de": "Öffentlich zugänglich", "fr": "Accèssible au public", - "it": "È ad accesso libero" + "it": "È ad accesso libero", + "ru": "Свободный доступ" }, "if": "access=yes" }, @@ -373,14 +379,16 @@ "nl": "Op welke dag werd dit boekenruilkastje geinstalleerd?", "de": "Wann wurde dieser öffentliche Bücherschrank installiert?", "fr": "Quand a été installée cette microbibliothèque ?", - "it": "Quando è stata inaugurata questa microbiblioteca?" + "it": "Quando è stata inaugurata questa microbiblioteca?", + "ru": "Когда был установлен этот общественный книжный шкаф?" }, "render": { "en": "Installed on {start_date}", "nl": "Geplaatst op {start_date}", "de": "Installiert am {start_date}", "fr": "Installée le {start_date}", - "it": "È stata inaugurata il {start_date}" + "it": "È stata inaugurata il {start_date}", + "ru": "Установлен {start_date}" }, "freeform": { "key": "start_date", @@ -401,7 +409,8 @@ "nl": "Is er een website over dit boekenruilkastje?", "de": "Gibt es eine Website mit weiteren Informationen über diesen öffentlichen Bücherschrank?", "fr": "Y a-t-il un site web avec plus d'informations sur cette microbibliothèque ?", - "it": "C'è un sito web con maggiori informazioni su questa microbiblioteca?" + "it": "C'è un sito web con maggiori informazioni su questa microbiblioteca?", + "ru": "Есть ли веб-сайт с более подробной информацией об этом общественном книжном шкафе?" }, "freeform": { "key": "website", diff --git a/assets/layers/sport_pitch/sport_pitch.json b/assets/layers/sport_pitch/sport_pitch.json index efb49a0b2..140e222b2 100644 --- a/assets/layers/sport_pitch/sport_pitch.json +++ b/assets/layers/sport_pitch/sport_pitch.json @@ -32,7 +32,8 @@ "nl": "Een sportterrein", "fr": "Un terrain de sport", "en": "A sport pitch", - "it": "Un campo sportivo" + "it": "Un campo sportivo", + "ru": "Спортивная площадка" }, "tagRenderings": [ "images", @@ -64,7 +65,8 @@ "nl": "Hier kan men basketbal spelen", "fr": "Ici, on joue au basketball", "en": "Basketball is played here", - "it": "Qui si gioca a basket" + "it": "Qui si gioca a basket", + "ru": "Здесь можно играть в баскетбол" } }, { @@ -77,7 +79,8 @@ "nl": "Hier kan men voetbal spelen", "fr": "Ici, on joue au football", "en": "Soccer is played here", - "it": "Qui si gioca a calcio" + "it": "Qui si gioca a calcio", + "ru": "Здесь можно играть в футбол" } }, { @@ -104,7 +107,8 @@ "nl": "Hier kan men tennis spelen", "fr": "Ici, on joue au tennis", "en": "Tennis is played here", - "it": "Qui si gioca a tennis" + "it": "Qui si gioca a tennis", + "ru": "Здесь можно играть в теннис" } }, { @@ -117,7 +121,8 @@ "nl": "Hier kan men korfbal spelen", "fr": "Ici, on joue au korfball", "en": "Korfball is played here", - "it": "Qui si gioca a korfball" + "it": "Qui si gioca a korfball", + "ru": "Здесь можно играть в корфбол" } }, { @@ -130,7 +135,8 @@ "nl": "Hier kan men basketbal beoefenen", "fr": "Ici, on joue au basketball", "en": "Basketball is played here", - "it": "Qui si gioca a basket" + "it": "Qui si gioca a basket", + "ru": "Здесь можно играть в баскетбол" }, "hideInAnswer": true } @@ -141,7 +147,8 @@ "nl": "Wat is de ondergrond van dit sportveld?", "fr": "De quelle surface est fait ce terrain de sport ?", "en": "Which is the surface of this sport pitch?", - "it": "Qual è la superficie di questo campo sportivo?" + "it": "Qual è la superficie di questo campo sportivo?", + "ru": "Какое покрытие на этой спортивной площадке?" }, "render": { "nl": "De ondergrond is {surface}", @@ -211,7 +218,8 @@ "nl": "Is dit sportterrein publiek toegankelijk?", "fr": "Est-ce que ce terrain de sport est accessible au public ?", "en": "Is this sport pitch publicly accessible?", - "it": "Questo campo sportivo è aperto al pubblico?" + "it": "Questo campo sportivo è aperto al pubblico?", + "ru": "Есть ли свободный доступ к этой спортивной площадке?" }, "mappings": [ { @@ -220,7 +228,8 @@ "nl": "Publiek toegankelijk", "fr": "Accessible au public", "en": "Public access", - "it": "Aperto al pubblico" + "it": "Aperto al pubblico", + "ru": "Свободный доступ" } }, { @@ -229,7 +238,8 @@ "nl": "Beperkt toegankelijk (enkel na reservatie, tijdens bepaalde uren, ...)", "fr": "Accès limité (par exemple uniquement sur réservation, à certains horaires…)", "en": "Limited access (e.g. only with an appointment, during certain hours, ...)", - "it": "Accesso limitato (p.es. solo con prenotazione, in certi orari, ...)" + "it": "Accesso limitato (p.es. solo con prenotazione, in certi orari, ...)", + "ru": "Ограниченный доступ (напр., только по записи, в определённые часы, ...)" } }, { @@ -238,7 +248,8 @@ "nl": "Enkel toegankelijk voor leden van de bijhorende sportclub", "fr": "Accessible uniquement aux membres du club", "en": "Only accessible for members of the club", - "it": "Accesso limitato ai membri dell'associazione" + "it": "Accesso limitato ai membri dell'associazione", + "ru": "Доступ только членам клуба" } }, { @@ -257,7 +268,8 @@ "nl": "Moet men reserveren om gebruik te maken van dit sportveld?", "fr": "Doit-on réserver pour utiliser ce terrain de sport ?", "en": "Does one have to make an appointment to use this sport pitch?", - "it": "È necessario prenotarsi per usare questo campo sportivo?" + "it": "È necessario prenotarsi per usare questo campo sportivo?", + "ru": "Нужна ли предварительная запись для доступа на эту спортивную площадку?" }, "condition": { "and": [ @@ -282,7 +294,8 @@ "nl": "Reserveren is sterk aangeraden om gebruik te maken van dit sportterrein", "fr": "Il est recommendé de réserver pour utiliser ce terrain de sport", "en": "Making an appointment is recommended when using this sport pitch", - "it": "La prenotazione è consigliata per usare questo campo sportivo" + "it": "La prenotazione è consigliata per usare questo campo sportivo", + "ru": "Желательна предварительная запись для доступа на эту спортивную площадку" } }, { @@ -291,7 +304,8 @@ "nl": "Reserveren is mogelijk, maar geen voorwaarde", "fr": "Il est possible de réserver, mais ce n'est pas nécéssaire pour utiliser ce terrain de sport", "en": "Making an appointment is possible, but not necessary to use this sport pitch", - "it": "La prenotazione è consentita, ma non è obbligatoria per usare questo campo sportivo" + "it": "La prenotazione è consentita, ma non è obbligatoria per usare questo campo sportivo", + "ru": "Предварительная запись для доступа на эту спортивную площадку возможна, но не обязательна" } }, { @@ -300,7 +314,8 @@ "nl": "Reserveren is niet mogelijk", "fr": "On ne peut pas réserver", "en": "Making an appointment is not possible", - "it": "Non è possibile prenotare" + "it": "Non è possibile prenotare", + "ru": "Невозможна предварительная запись" } } ] @@ -336,7 +351,8 @@ "nl": "Wanneer is dit sportveld toegankelijk?", "fr": "Quand ce terrain est-il accessible ?", "en": "When is this pitch accessible?", - "it": "Quando è aperto questo campo sportivo?" + "it": "Quando è aperto questo campo sportivo?", + "ru": "В какое время доступна эта площадка?" }, "render": "Openingsuren: {opening_hours_table()}", "freeform": { @@ -446,7 +462,8 @@ "nl": "Ping-pong tafel", "fr": "Table de ping-pong", "en": "Tabletennis table", - "it": "Tavolo da tennistavolo" + "it": "Tavolo da tennistavolo", + "ru": "Стол для настольного тенниса" }, "tags": [ "leisure=pitch", diff --git a/assets/layers/surveillance_camera/surveillance_camera.json b/assets/layers/surveillance_camera/surveillance_camera.json index e5c872be2..20f1e77bf 100644 --- a/assets/layers/surveillance_camera/surveillance_camera.json +++ b/assets/layers/surveillance_camera/surveillance_camera.json @@ -39,7 +39,8 @@ "en": "What kind of camera is this?", "nl": "Wat voor soort camera is dit?", "fr": "Quel genre de caméra est-ce ?", - "it": "Di che tipo di videocamera si tratta?" + "it": "Di che tipo di videocamera si tratta?", + "ru": "Какая это камера?" }, "mappings": [ { @@ -65,7 +66,8 @@ "en": "A dome camera (which can turn)", "nl": "Een dome (bolvormige camera die kan draaien)", "fr": "Une caméra dôme (qui peut tourner)", - "it": "Una videocamera a cupola (che può ruotare)" + "it": "Una videocamera a cupola (che può ruotare)", + "ru": "Камера с поворотным механизмом" } }, { @@ -230,7 +232,8 @@ "en": "This camera is located outdoors", "nl": "Deze camera bevindt zich buiten", "fr": "Cette caméra est située à l'extérieur", - "it": "Questa videocamera si trova all'aperto" + "it": "Questa videocamera si trova all'aperto", + "ru": "Эта камера расположена снаружи" } }, { @@ -239,7 +242,8 @@ "en": "This camera is probably located outdoors", "nl": "Deze camera bevindt zich waarschijnlijk buiten", "fr": "Cette caméra est probablement située à l'extérieur", - "it": "Questa videocamera si trova probabilmente all'esterno" + "it": "Questa videocamera si trova probabilmente all'esterno", + "ru": "Возможно, эта камера расположена снаружи" }, "hideInAnswer": true } @@ -374,7 +378,8 @@ "en": "How is this camera placed?", "nl": "Hoe is deze camera geplaatst?", "fr": "Comment cette caméra est-elle placée ?", - "it": "Com'è posizionata questa telecamera?" + "it": "Com'è posizionata questa telecamera?", + "ru": "Как расположена эта камера?" }, "render": { "en": "Mounting method: {mount}", diff --git a/assets/layers/toilet/toilet.json b/assets/layers/toilet/toilet.json index 06ea04860..a33ddf742 100644 --- a/assets/layers/toilet/toilet.json +++ b/assets/layers/toilet/toilet.json @@ -57,7 +57,8 @@ "de": "Eine öffentlich zugängliche Toilette", "fr": "Des toilettes", "nl": "Een publieke toilet", - "it": "Servizi igienici aperti al pubblico" + "it": "Servizi igienici aperti al pubblico", + "ru": "Туалет или комната отдыха со свободным доступом" } }, { @@ -66,7 +67,8 @@ "de": "Toiletten mit rollstuhlgerechter Toilette", "fr": "Toilettes accessible aux personnes à mobilité réduite", "nl": "Een rolstoeltoegankelijke toilet", - "it": "Servizi igienici accessibili per persone in sedia a rotelle" + "it": "Servizi igienici accessibili per persone in sedia a rotelle", + "ru": "Туалет с доступом для пользователей кресел-колясок" }, "tags": [ "amenity=toilets", @@ -89,7 +91,8 @@ "de": "Sind diese Toiletten öffentlich zugänglich?", "fr": "Ces toilettes sont-elles accessibles au public ?", "nl": "Zijn deze toiletten publiek toegankelijk?", - "it": "Questi servizi igienici sono aperti al pubblico?" + "it": "Questi servizi igienici sono aperti al pubblico?", + "ru": "Есть ли свободный доступ к этим туалетам?" }, "render": { "en": "Access is {access}", @@ -112,7 +115,8 @@ "de": "Öffentlicher Zugang", "fr": "Accès publique", "nl": "Publiek toegankelijk", - "it": "Accesso pubblico" + "it": "Accesso pubblico", + "ru": "Свободный доступ" } }, { @@ -186,14 +190,16 @@ "de": "Wie viel muss man für diese Toiletten bezahlen?", "fr": "Quel est le prix d'accès de ces toilettes ?", "nl": "Hoeveel moet men betalen om deze toiletten te gebruiken?", - "it": "Quanto costa l'accesso a questi servizi igienici?" + "it": "Quanto costa l'accesso a questi servizi igienici?", + "ru": "Сколько стоит посещение туалета?" }, "render": { "en": "The fee is {charge}", "de": "Die Gebühr beträgt {charge}", "fr": "Le prix est {charge}", "nl": "De toiletten gebruiken kost {charge}", - "it": "La tariffa è {charge}" + "it": "La tariffa è {charge}", + "ru": "Стоимость {charge}" }, "condition": "fee=yes", "freeform": { @@ -227,7 +233,8 @@ "de": "Kein Zugang für Rollstuhlfahrer", "fr": "Non accessible aux personnes à mobilité réduite", "nl": "Niet toegankelijk voor rolstoelgebruikers", - "it": "Non accessibile in sedia a rotelle" + "it": "Non accessibile in sedia a rotelle", + "ru": "Недоступно пользователям кресел-колясок" } } ] @@ -238,7 +245,8 @@ "de": "Welche Art von Toiletten sind das?", "fr": "De quel type sont ces toilettes ?", "nl": "Welke toiletten zijn dit?", - "it": "Di che tipo di servizi igienici si tratta?" + "it": "Di che tipo di servizi igienici si tratta?", + "ru": "Какие это туалеты?" }, "mappings": [ { diff --git a/assets/layers/tree_node/tree_node.json b/assets/layers/tree_node/tree_node.json index a95bfdb01..1f3cc7fde 100644 --- a/assets/layers/tree_node/tree_node.json +++ b/assets/layers/tree_node/tree_node.json @@ -230,7 +230,8 @@ "question": { "nl": "Is deze boom groenblijvend of bladverliezend?", "en": "Is this tree evergreen or deciduous?", - "it": "È un sempreverde o caduco?" + "it": "È un sempreverde o caduco?", + "ru": "Это дерево вечнозелёное или листопадное?" }, "mappings": [ { @@ -242,7 +243,8 @@ "then": { "nl": "Bladverliezend: de boom is een periode van het jaar kaal.", "en": "Deciduous: the tree loses its leaves for some time of the year.", - "it": "Caduco: l’albero perde le sue foglie per un periodo dell’anno." + "it": "Caduco: l’albero perde le sue foglie per un periodo dell’anno.", + "ru": "Листопадное: у дерева опадают листья в определённое время года." } }, { @@ -255,7 +257,8 @@ "nl": "Groenblijvend.", "en": "Evergreen.", "it": "Sempreverde.", - "fr": "À feuilles persistantes." + "fr": "À feuilles persistantes.", + "ru": "Вечнозелёное." } } ], @@ -278,7 +281,8 @@ "nl": "Heeft de boom een naam?", "en": "Does the tree have a name?", "it": "L’albero ha un nome?", - "fr": "L'arbre a-t-il un nom ?" + "fr": "L'arbre a-t-il un nom ?", + "ru": "Есть ли у этого дерева название?" }, "freeform": { "key": "name", @@ -298,7 +302,8 @@ "nl": "De boom heeft geen naam.", "en": "The tree does not have a name.", "it": "L’albero non ha un nome.", - "fr": "L'arbre n'a pas de nom." + "fr": "L'arbre n'a pas de nom.", + "ru": "У этого дерева нет названия." } } ], @@ -399,7 +404,8 @@ "render": { "nl": "\"\"/ Onroerend Erfgoed-ID: {ref:OnroerendErfgoed}", "en": "\"\"/ Onroerend Erfgoed ID: {ref:OnroerendErfgoed}", - "it": "\"\"/ Onroerend Erfgoed ID: {ref:OnroerendErfgoed}" + "it": "\"\"/ Onroerend Erfgoed ID: {ref:OnroerendErfgoed}", + "ru": "\"\"/ Onroerend Erfgoed ID: {ref:OnroerendErfgoed}" }, "question": { "nl": "Wat is het ID uitgegeven door Onroerend Erfgoed Vlaanderen?", @@ -421,7 +427,8 @@ "render": { "nl": "\"\"/ Wikidata: {wikidata}", "en": "\"\"/ Wikidata: {wikidata}", - "it": "\"\"/ Wikidata: {wikidata}" + "it": "\"\"/ Wikidata: {wikidata}", + "ru": "\"\"/ Wikidata: {wikidata}" }, "question": { "nl": "Wat is het Wikidata-ID van deze boom?", @@ -484,7 +491,8 @@ "nl": "Loofboom", "en": "Broadleaved tree", "it": "Albero latifoglia", - "fr": "Arbre feuillu" + "fr": "Arbre feuillu", + "ru": "Лиственное дерево" }, "description": { "nl": "Een boom van een soort die blaadjes heeft, bijvoorbeeld eik of populier.", @@ -501,12 +509,14 @@ "title": { "nl": "Naaldboom", "en": "Needleleaved tree", - "it": "Albero aghifoglia" + "it": "Albero aghifoglia", + "ru": "Хвойное дерево" }, "description": { "nl": "Een boom van een soort met naalden, bijvoorbeeld den of spar.", "en": "A tree of a species with needles, such as pine or spruce.", - "it": "Un albero di una specie con aghi come il pino o l’abete." + "it": "Un albero di una specie con aghi come il pino o l’abete.", + "ru": "Дерево с хвоей (иглами), например, сосна или ель." } }, { @@ -524,7 +534,8 @@ "nl": "Wanneer je niet zeker bent of het nu een loof- of naaldboom is.", "en": "If you're not sure whether it's a broadleaved or needleleaved tree.", "it": "Qualora non si sia sicuri se si tratta di un albero latifoglia o aghifoglia.", - "fr": "Si vous n'êtes pas sûr(e) de savoir s'il s'agit d'un arbre à feuilles larges ou à aiguilles." + "fr": "Si vous n'êtes pas sûr(e) de savoir s'il s'agit d'un arbre à feuilles larges ou à aiguilles.", + "ru": "Если вы не уверены в том, лиственное это дерево или хвойное." } } ] diff --git a/assets/tagRenderings/questions.json b/assets/tagRenderings/questions.json index dd729eafd..3fabc4deb 100644 --- a/assets/tagRenderings/questions.json +++ b/assets/tagRenderings/questions.json @@ -133,10 +133,10 @@ "en": "Located on the {level}th floor", "nl": "Bevindt zich op de {level}de verdieping" }, -"freeform": { - "key": "level", - "type": "float" -}, + "freeform": { + "key": "level", + "type": "float" + }, "mappings": [ { "if": "location=underground", @@ -145,13 +145,15 @@ "nl": "Bevindt zich ondergrounds" }, "hideInAnswer": true - },{ + }, + { "if": "level=0", "then": { "en": "Located on the ground floor", "nl": "Bevindt zich gelijkvloers" } - },{ + }, + { "if": "level=1", "then": { "en": "Located on the first floor", diff --git a/assets/themes/artwork/artwork.json b/assets/themes/artwork/artwork.json index 7b8cc876c..c3b7b7c55 100644 --- a/assets/themes/artwork/artwork.json +++ b/assets/themes/artwork/artwork.json @@ -374,7 +374,7 @@ "en": "Is there a website with more information about this artwork?", "nl": "Op welke website kan men meer informatie vinden over dit kunstwerk?", "fr": "Sur quel site web pouvons-nous trouver plus d'informations sur cette œuvre d'art?", - "de": "Auf welcher Website gibt es mehr Informationen über dieses Kunstwerk?", + "de": "Gibt es eine Website mit weiteren Informationen über dieses Kunstwerk?", "it": "Esiste un sito web con maggiori informazioni su quest’opera?", "ru": "Есть ли сайт с более подробной информацией об этой работе?", "ja": "この作品についての詳しい情報はどのウェブサイトにありますか?", diff --git a/assets/themes/bicycle_library/bicycle_library.json b/assets/themes/bicycle_library/bicycle_library.json index 437020a3f..6d0cf61e2 100644 --- a/assets/themes/bicycle_library/bicycle_library.json +++ b/assets/themes/bicycle_library/bicycle_library.json @@ -10,7 +10,8 @@ "ja", "fr", "zh_Hant", - "nb_NO" + "nb_NO", + "de" ], "title": { "en": "Bicycle libraries", @@ -20,7 +21,8 @@ "ja": "自転車ライブラリ", "fr": "Vélothèques", "zh_Hant": "單車圖書館", - "nb_NO": "Sykkelbibliotek" + "nb_NO": "Sykkelbibliotek", + "de": "Fahrradbibliothek" }, "description": { "nl": "Een fietsbibliotheek is een plaats waar men een fiets kan lenen, vaak voor een klein bedrag per jaar. Een typisch voorbeeld zijn kinderfietsbibliotheken, waar men een fiets op maat van het kind kan lenen. Is het kind de fiets ontgroeid, dan kan het te kleine fietsje omgeruild worden voor een grotere.", diff --git a/assets/themes/campersites/campersites.json b/assets/themes/campersites/campersites.json index 76039862d..cc248f278 100644 --- a/assets/themes/campersites/campersites.json +++ b/assets/themes/campersites/campersites.json @@ -23,7 +23,8 @@ "it": "Questo sito raccoglie tutti i luoghi ufficiali dove sostare con il camper e aree dove è possibile scaricare acque grigie e nere. Puoi aggiungere dettagli riguardanti i servizi forniti e il loro costo. Aggiungi foto e recensioni. Questo è al contempo un sito web e una web app. I dati sono memorizzati su OpenStreetMap in modo tale che siano per sempre liberi e riutilizzabili da qualsiasi app.", "ru": "На этом сайте собраны все официальные места остановки кемперов и места, где можно сбросить серую и черную воду. Вы можете добавить подробную информацию о предоставляемых услугах и их стоимости. Добавлять фотографии и отзывы. Это веб-сайт и веб-приложение. Данные хранятся в OpenStreetMap, поэтому они будут бесплатными всегда и могут быть повторно использованы любым приложением.", "ja": "このWebサイトでは、すべてのキャンピングカーの公式停車場所と、汚水を捨てることができる場所を収集します。提供されるサービスとコストに関する詳細を追加できます。写真とレビューを追加します。これはウェブサイトとウェブアプリです。データはOpenStreetMapに保存されるので、永遠に無料で、どんなアプリからでも再利用できます。", - "zh_Hant": "這個網站收集所有官方露營地點,以及那邊能排放廢水。你可以加上詳細的服務項目與價格,加上圖片以及評價。這是網站與網路 app,資料則是存在開放街圖,因此會永遠免費,而且可以被所有 app 再利用。" + "zh_Hant": "這個網站收集所有官方露營地點,以及那邊能排放廢水。你可以加上詳細的服務項目與價格,加上圖片以及評價。這是網站與網路 app,資料則是存在開放街圖,因此會永遠免費,而且可以被所有 app 再利用。", + "nl": "Deze website verzamelt en toont alle officiële plaatsen waar een camper mag overnachten en afvalwater kan lozen. Ook jij kan extra gegevens toevoegen, zoals welke services er geboden worden en hoeveel dit kot, ook afbeeldingen en reviews kan je toevoegen. De data wordt op OpenStreetMap opgeslaan en is dus altijd gratis te hergebruiken, ook door andere applicaties." }, "language": [ "en", @@ -53,7 +54,8 @@ "ru": "Площадки для кемпинга", "ja": "キャンプサイト", "fr": "Campings", - "zh_Hant": "露營地" + "zh_Hant": "露營地", + "nl": "Camperplaatsen" }, "minzoom": 10, "source": { @@ -71,7 +73,8 @@ "ru": "Место для кемпинга {name}", "ja": "キャンプサイト {name}", "fr": "Camping {name}", - "zh_Hant": "露營地 {name}" + "zh_Hant": "露營地 {name}", + "nl": "Camperplaats {name}" }, "mappings": [ { @@ -86,7 +89,8 @@ "ru": "Место для кемпинга без названия", "ja": "無名のキャンプサイト", "fr": "Camping sans nom", - "zh_Hant": "沒有名稱的露營地" + "zh_Hant": "沒有名稱的露營地", + "nl": "Camper site" } } ] @@ -97,7 +101,8 @@ "ru": "площадки для кемпинга", "ja": "キャンプサイト", "fr": "campings", - "zh_Hant": "露營地" + "zh_Hant": "露營地", + "nl": "camperplaatsen" }, "tagRenderings": [ "images", @@ -108,7 +113,8 @@ "ru": "Это место называется {name}", "ja": "この場所は {name} と呼ばれています", "fr": "Cet endroit s'appelle {nom}", - "zh_Hant": "這個地方叫做 {name}" + "zh_Hant": "這個地方叫做 {name}", + "nl": "Deze plaats heet {name}" }, "question": { "en": "What is this place called?", @@ -117,7 +123,8 @@ "it": "Come viene chiamato questo luogo?", "ja": "ここは何というところですか?", "fr": "Comment s'appelle cet endroit ?", - "zh_Hant": "這個地方叫做什麼?" + "zh_Hant": "這個地方叫做什麼?", + "nl": "Wat is de naam van deze plaats?" }, "freeform": { "key": "name" @@ -130,7 +137,8 @@ "ru": "Взимается ли в этом месте плата?", "ja": "ここは有料ですか?", "fr": "Cet endroit est-il payant ?", - "zh_Hant": "這個地方收費嗎?" + "zh_Hant": "這個地方收費嗎?", + "nl": "Moet men betalen om deze camperplaats te gebruiken?" }, "mappings": [ { @@ -144,7 +152,8 @@ "it": "Devi pagare per usarlo", "ru": "За использование нужно платить", "ja": "使用料を支払う必要がある", - "zh_Hant": "你要付費才能使用" + "zh_Hant": "你要付費才能使用", + "nl": "Gebruik is betalend" } }, { @@ -162,7 +171,8 @@ "ja": "無料で使用可能", "fr": "Peut être utilisé gratuitement", "nb_NO": "Kan brukes gratis", - "zh_Hant": "可以免費使用" + "zh_Hant": "可以免費使用", + "nl": "Kan gratis gebruikt worden" } }, { @@ -179,7 +189,8 @@ "ru": "Это место взимает {charge}", "ja": "この場所は{charge} が必要", "nb_NO": "Dette stedet tar {charge}", - "zh_Hant": "這個地方收費 {charge}" + "zh_Hant": "這個地方收費 {charge}", + "nl": "Deze plaats vraagt {charge}" }, "question": { "en": "How much does this place charge?", @@ -188,7 +199,8 @@ "ja": "ここはいくらかかりますか?", "fr": "Combien coûte cet endroit ?", "nb_NO": "pø", - "zh_Hant": "這個地方收多少費用?" + "zh_Hant": "這個地方收多少費用?", + "nl": "Hoeveel kost deze plaats?" }, "freeform": { "key": "charge" @@ -415,7 +427,8 @@ "it": "Sito web ufficiale: {website}", "ja": "公式Webサイト: {website}", "nb_NO": "Offisiell nettside: {website}", - "zh_Hant": "官方網站:{website}" + "zh_Hant": "官方網站:{website}", + "nl": "Officiële website: : {website}" }, "freeform": { "type": "url", @@ -774,7 +787,8 @@ "question": { "en": "Who can use this dump station?", "ja": "このゴミ捨て場は誰が使えるんですか?", - "it": "Chi può utilizzare questo luogo di sversamento?" + "it": "Chi può utilizzare questo luogo di sversamento?", + "ru": "Кто может использовать эту станцию утилизации?" }, "mappings": [ { @@ -810,7 +824,8 @@ "then": { "en": "Anyone can use this dump station", "ja": "誰でもこのゴミ捨て場を使用できます", - "it": "Chiunque può farne uso" + "it": "Chiunque può farne uso", + "ru": "Любой может воспользоваться этой станцией утилизации" }, "hideInAnswer": true }, @@ -823,7 +838,8 @@ "then": { "en": "Anyone can use this dump station", "ja": "誰でもこのゴミ捨て場を使用できます", - "it": "Chiunque può farne uso" + "it": "Chiunque può farne uso", + "ru": "Любой может воспользоваться этой станцией утилизации" } } ] @@ -832,12 +848,14 @@ "render": { "en": "This station is part of network {network}", "ja": "このステーションはネットワーク{network}の一部です", - "it": "Questo luogo è parte della rete {network}" + "it": "Questo luogo è parte della rete {network}", + "ru": "Эта станция - часть сети {network}" }, "question": { "en": "What network is this place a part of? (skip if none)", "ja": "ここは何のネットワークの一部ですか?(なければスキップ)", - "it": "Di quale rete fa parte questo luogo? (se non fa parte di nessuna rete, salta)" + "it": "Di quale rete fa parte questo luogo? (se non fa parte di nessuna rete, salta)", + "ru": "К какой сети относится эта станция? (пропустите, если неприменимо)" }, "freeform": { "key": "network" diff --git a/assets/themes/charging_stations/charging_stations.json b/assets/themes/charging_stations/charging_stations.json index fc5040c6c..16bc12786 100644 --- a/assets/themes/charging_stations/charging_stations.json +++ b/assets/themes/charging_stations/charging_stations.json @@ -6,14 +6,16 @@ "ru": "Зарядные станции", "ja": "充電ステーション", "zh_Hant": "充電站", - "it": "Stazioni di ricarica" + "it": "Stazioni di ricarica", + "nl": "Oplaadpunten" }, "shortDescription": { "en": "A worldwide map of charging stations", "ru": "Карта зарядных станций по всему миру", "ja": "充電ステーションの世界地図", "zh_Hant": "全世界的充電站地圖", - "it": "Una mappa mondiale delle stazioni di ricarica" + "it": "Una mappa mondiale delle stazioni di ricarica", + "nl": "Een wereldwijde kaart van oplaadpunten" }, "description": { "en": "On this open map, one can find and mark information about charging stations", @@ -29,6 +31,7 @@ "ja", "zh_Hant", "it", + "nl", "nb_NO" ], "maintainer": "", @@ -48,7 +51,8 @@ "ja": "充電ステーション", "zh_Hant": "充電站", "nb_NO": "Ladestasjoner", - "it": "Stazioni di ricarica" + "it": "Stazioni di ricarica", + "nl": "Oplaadpunten" }, "minzoom": 10, "source": { @@ -65,7 +69,8 @@ "ja": "充電ステーション", "zh_Hant": "充電站", "nb_NO": "Ladestasjon", - "it": "Stazione di ricarica" + "it": "Stazione di ricarica", + "nl": "Oplaadpunt" } }, "description": { @@ -74,7 +79,8 @@ "ja": "充電ステーション", "zh_Hant": "充電站", "nb_NO": "En ladestasjon", - "it": "Una stazione di ricarica" + "it": "Una stazione di ricarica", + "nl": "Een oplaadpunt" }, "tagRenderings": [ "images", @@ -224,11 +230,12 @@ "ja": "{network}", "zh_Hant": "{network}", "nb_NO": "{network}", - "it": "{network}" + "it": "{network}", + "nl": "{network}" }, "question": { "en": "What network of this charging station under?", - "ru": "К какой сети относится эта станция?", + "ru": "К какой сети относится эта зарядная станция?", "ja": "この充電ステーションの運営チェーンはどこですか?", "zh_Hant": "充電站所屬的網路是?", "it": "A quale rete appartiene questa stazione di ricarica?" @@ -248,7 +255,8 @@ "ru": "Не является частью более крупной сети", "ja": "大規模な運営チェーンの一部ではない", "zh_Hant": "不屬於大型網路", - "it": "Non appartiene a una rete" + "it": "Non appartiene a una rete", + "nl": "Maakt geen deel uit van een netwerk" } }, { @@ -262,7 +270,8 @@ "ru": "AeroVironment", "ja": "AeroVironment", "zh_Hant": "AeroVironment", - "it": "AeroVironment" + "it": "AeroVironment", + "nl": "AeroVironment" } }, { @@ -276,7 +285,8 @@ "ru": "Blink", "ja": "Blink", "zh_Hant": "Blink", - "it": "Blink" + "it": "Blink", + "nl": "Blink" } }, { @@ -290,7 +300,8 @@ "ru": "eVgo", "ja": "eVgo", "zh_Hant": "eVgo", - "it": "eVgo" + "it": "eVgo", + "nl": "eVgo" } } ] diff --git a/assets/themes/climbing/climbing.json b/assets/themes/climbing/climbing.json index 72a53780b..71a841e54 100644 --- a/assets/themes/climbing/climbing.json +++ b/assets/themes/climbing/climbing.json @@ -171,14 +171,16 @@ "en": "Climbing club", "nl": "Klimclub", "ja": "クライミングクラブ", - "nb_NO": "Klatreklubb" + "nb_NO": "Klatreklubb", + "ru": "Клуб скалолазания" }, "description": { "de": "Ein Kletterverein", "nl": "Een klimclub", "en": "A climbing club", "ja": "クライミングクラブ", - "nb_NO": "En klatreklubb" + "nb_NO": "En klatreklubb", + "ru": "Клуб скалолазания" } }, { @@ -241,7 +243,8 @@ "description": { "de": "Eine Kletterhalle", "en": "A climbing gym", - "ja": "クライミングジム" + "ja": "クライミングジム", + "nl": "Een klimzaal" }, "tagRenderings": [ "images", @@ -484,7 +487,8 @@ "presets": [ { "title": { - "en": "Climbing route" + "en": "Climbing route", + "nl": "Klimroute" }, "tags": [ "sport=climbing", @@ -790,7 +794,8 @@ "fr": "{name}", "id": "{name}", "ru": "{name}", - "ja": "{name}" + "ja": "{name}", + "nl": "{name}" }, "condition": "name~*" }, @@ -897,7 +902,8 @@ "en": "Is there a (unofficial) website with more informations (e.g. topos)?", "de": "Gibt es eine (inoffizielle) Website mit mehr Informationen (z.B. Topos)?", "ja": "もっと情報のある(非公式の)ウェブサイトはありますか(例えば、topos)?", - "nl": "Is er een (onofficiële) website met meer informatie (b.v. met topos)?" + "nl": "Is er een (onofficiële) website met meer informatie (b.v. met topos)?", + "ru": "Есть ли (неофициальный) веб-сайт с более подробной информацией (напр., topos)?" }, "condition": { "and": [ @@ -976,7 +982,8 @@ { "if": "access=members", "then": { - "en": "Only club members" + "en": "Only club members", + "ru": "Только членам клуба" } }, { diff --git a/assets/themes/cyclestreets/cyclestreets.json b/assets/themes/cyclestreets/cyclestreets.json index 8a5956cd1..b3b3abbf4 100644 --- a/assets/themes/cyclestreets/cyclestreets.json +++ b/assets/themes/cyclestreets/cyclestreets.json @@ -27,7 +27,8 @@ "ja", "zh_Hant", "nb_NO", - "it" + "it", + "ru" ], "startLat": 51.2095, "startZoom": 14, @@ -222,7 +223,8 @@ "en": "All streets", "ja": "すべての道路", "nb_NO": "Alle gater", - "it": "Tutte le strade" + "it": "Tutte le strade", + "ru": "Все улицы" }, "description": { "nl": "Laag waar je een straat als fietsstraat kan markeren", @@ -247,7 +249,8 @@ "nl": "Straat", "en": "Street", "ja": "ストリート", - "it": "Strada" + "it": "Strada", + "ru": "Улица" }, "mappings": [ { diff --git a/assets/themes/drinking_water/drinking_water.json b/assets/themes/drinking_water/drinking_water.json index da21f5296..9dee5a8a3 100644 --- a/assets/themes/drinking_water/drinking_water.json +++ b/assets/themes/drinking_water/drinking_water.json @@ -15,7 +15,8 @@ "fr": "Cette carte affiche les points d'accès public à de l'eau potable, et permet d'en ajouter facilement", "ja": "この地図には、一般にアクセス可能な飲料水スポットが示されており、簡単に追加することができる", "zh_Hant": "在這份地圖上,公共可及的飲水點可以顯示出來,也能輕易的增加", - "it": "Questa mappa mostra tutti i luoghi in cui è disponibile acqua potabile ed è possibile aggiungerne di nuovi" + "it": "Questa mappa mostra tutti i luoghi in cui è disponibile acqua potabile ed è possibile aggiungerne di nuovi", + "ru": "На этой карте показываются и могут быть легко добавлены общедоступные точки питьевой воды" }, "language": [ "en", diff --git a/assets/themes/facadegardens/facadegardens.json b/assets/themes/facadegardens/facadegardens.json index b472fdf05..8cc936981 100644 --- a/assets/themes/facadegardens/facadegardens.json +++ b/assets/themes/facadegardens/facadegardens.json @@ -165,7 +165,8 @@ "nl": "Ligt de tuin in zon/half schaduw of schaduw?", "en": "Is the garden shaded or sunny?", "ja": "庭は日陰ですか、日当たりがいいですか?", - "it": "Il giardino è al sole o in ombra?" + "it": "Il giardino è al sole o in ombra?", + "ru": "Сад расположен на солнечной стороне или в тени?" } }, { @@ -185,7 +186,8 @@ "nl": "Er is een regenton", "en": "There is a rain barrel", "ja": "雨樽がある", - "it": "C'è un contenitore per raccogliere la pioggia" + "it": "C'è un contenitore per raccogliere la pioggia", + "ru": "Есть бочка с дождевой водой" } }, { @@ -198,7 +200,8 @@ "nl": "Er is geen regenton", "en": "There is no rain barrel", "ja": "雨樽はありません", - "it": "Non c'è un contenitore per raccogliere la pioggia" + "it": "Non c'è un contenitore per raccogliere la pioggia", + "ru": "Нет бочки с дождевой водой" } } ] @@ -263,7 +266,8 @@ "nl": "Wat voor planten staan hier?", "en": "What kinds of plants grow here?", "ja": "ここではどんな植物が育つんですか?", - "it": "Che tipi di piante sono presenti qui?" + "it": "Che tipi di piante sono presenti qui?", + "ru": "Какие виды растений обитают здесь?" }, "mappings": [ { @@ -310,13 +314,15 @@ "nl": "Meer details: {description}", "en": "More details: {description}", "ja": "詳細情報: {description}", - "it": "Maggiori dettagli: {description}" + "it": "Maggiori dettagli: {description}", + "ru": "Подробнее: {description}" }, "question": { "nl": "Aanvullende omschrijving van de tuin (indien nodig, en voor zover nog niet omschreven hierboven)", "en": "Extra describing info about the garden (if needed and not yet described above)", "ja": "庭園に関する追加の説明情報(必要な場合でまだ上記に記載されていない場合)", - "it": "Altre informazioni per descrivere il giardino (se necessarie e non riportate qui sopra)" + "it": "Altre informazioni per descrivere il giardino (se necessarie e non riportate qui sopra)", + "ru": "Дополнительная информация о саде (если требуется или еще не указана выше)" }, "freeform": { "key": "description", diff --git a/assets/themes/fritures/fritures.json b/assets/themes/fritures/fritures.json index 36cef08a0..3f3c51f42 100644 --- a/assets/themes/fritures/fritures.json +++ b/assets/themes/fritures/fritures.json @@ -118,7 +118,8 @@ "nl": "Wat is de website van deze frituur?", "fr": "Quel est le site web de cette friterie?", "ja": "このお店のホームページは何ですか?", - "it": "Qual è il sito web di questo negozio?" + "it": "Qual è il sito web di questo negozio?", + "ru": "Какой веб-сайт у этого магазина?" }, "freeform": { "key": "website", @@ -136,7 +137,8 @@ "fr": "Quel est le numéro de téléphone de cette friterie?", "ja": "電話番号は何番ですか?", "nb_NO": "Hva er telefonnummeret?", - "it": "Qual è il numero di telefono?" + "it": "Qual è il numero di telefono?", + "ru": "Какой телефон?" }, "freeform": { "key": "phone", @@ -275,7 +277,8 @@ "then": { "nl": "Je mag geen eigen containers meenemen om je bestelling in mee te nemen", "en": "Bringing your own container is not allowed", - "ja": "独自の容器を持参することはできません" + "ja": "独自の容器を持参することはできません", + "ru": "Приносить свою тару не разрешено" } }, { diff --git a/assets/themes/hailhydrant/hailhydrant.json b/assets/themes/hailhydrant/hailhydrant.json index fef5c8ab2..d465b72eb 100644 --- a/assets/themes/hailhydrant/hailhydrant.json +++ b/assets/themes/hailhydrant/hailhydrant.json @@ -3,12 +3,14 @@ "title": { "en": "Hydrants, Extinguishers, Fire stations, and Ambulance stations.", "ja": "消火栓、消火器、消防署、救急ステーションです。", - "zh_Hant": "消防栓、滅火器、消防隊、以及急救站。" + "zh_Hant": "消防栓、滅火器、消防隊、以及急救站。", + "ru": "Пожарные гидранты, огнетушители, пожарные станции и станции скорой помощи." }, "shortDescription": { "en": "Map to show hydrants, extinguishers, fire stations, and ambulance stations.", "ja": "消火栓、消火器、消防署消火栓、消火器、消防署、および救急ステーションを表示します。", - "zh_Hant": "顯示消防栓、滅火器、消防隊與急救站的地圖。" + "zh_Hant": "顯示消防栓、滅火器、消防隊與急救站的地圖。", + "ru": "Карта пожарных гидрантов, огнетушителей, пожарных станций и станций скорой помощи." }, "description": { "en": "On this map you can find and update hydrants, fire stations, ambulance stations, and extinguishers in your favorite neighborhoods. \n\nYou can track your precise location (mobile only) and select layers that are relevant for you in the bottom left corner. You can also use this tool to add or edit pins (points of interest) to the map and provide additional details by answering available questions. \n\nAll changes you make will automatically be saved in the global database of OpenStreetMap and can be freely re-used by others.", @@ -39,7 +41,8 @@ "en": "Map of hydrants", "ja": "消火栓の地図", "zh_Hant": "消防栓地圖", - "nb_NO": "Kart over brannhydranter" + "nb_NO": "Kart over brannhydranter", + "ru": "Карта пожарных гидрантов" }, "minzoom": 14, "source": { @@ -61,19 +64,22 @@ "en": "Map layer to show fire hydrants.", "ja": "消火栓を表示するマップレイヤ。", "zh_Hant": "顯示消防栓的地圖圖層。", - "nb_NO": "Kartlag for å vise brannhydranter." + "nb_NO": "Kartlag for å vise brannhydranter.", + "ru": "Слой карты, отображающий пожарные гидранты." }, "tagRenderings": [ { "question": { "en": "What color is the hydrant?", "ja": "消火栓の色は何色ですか?", - "nb_NO": "Hvilken farge har brannhydranten?" + "nb_NO": "Hvilken farge har brannhydranten?", + "ru": "Какого цвета гидрант?" }, "render": { "en": "The hydrant color is {colour}", "ja": "消火栓の色は{color}です", - "nb_NO": "Brannhydranter er {colour}" + "nb_NO": "Brannhydranter er {colour}", + "ru": "Цвет гидранта {colour}" }, "freeform": { "key": "colour" @@ -87,7 +93,8 @@ }, "then": { "en": "The hydrant color is unknown.", - "ja": "消火栓の色は不明です。" + "ja": "消火栓の色は不明です。", + "ru": "Цвет гидранта не определён." }, "hideInAnswer": true }, @@ -99,7 +106,8 @@ }, "then": { "en": "The hydrant color is yellow.", - "ja": "消火栓の色は黄色です。" + "ja": "消火栓の色は黄色です。", + "ru": "Гидрант жёлтого цвета." } }, { @@ -111,7 +119,8 @@ "then": { "en": "The hydrant color is red.", "ja": "消火栓の色は赤です。", - "it": "L'idrante è rosso." + "it": "L'idrante è rosso.", + "ru": "Гидрант красного цвета." } } ] @@ -120,7 +129,8 @@ "question": { "en": "What type of hydrant is it?", "ja": "どんな消火栓なんですか?", - "it": "Di che tipo è questo idrante?" + "it": "Di che tipo è questo idrante?", + "ru": "К какому типу относится этот гидрант?" }, "freeform": { "key": "fire_hydrant:type" @@ -141,7 +151,8 @@ "then": { "en": "The hydrant type is unknown.", "ja": "消火栓の種類は不明です。", - "it": "Il tipo di idrante è sconosciuto." + "it": "Il tipo di idrante è sconosciuto.", + "ru": "Тип гидранта не определён." }, "hideInAnswer": true }, @@ -214,7 +225,8 @@ }, "then": { "en": "The hydrant is (fully or partially) working.", - "ja": "消火栓は(完全にまたは部分的に)機能しています。" + "ja": "消火栓は(完全にまたは部分的に)機能しています。", + "ru": "Гидрант (полностью или частично) в рабочем состоянии." } }, { @@ -238,7 +250,8 @@ }, "then": { "en": "The hydrant has been removed.", - "ja": "消火栓が撤去されました。" + "ja": "消火栓が撤去されました。", + "ru": "Гидрант демонтирован." } } ] @@ -282,7 +295,8 @@ "name": { "en": "Map of fire extinguishers.", "ja": "消火器の地図です。", - "nb_NO": "Kart over brannhydranter" + "nb_NO": "Kart over brannhydranter", + "ru": "Карта огнетушителей." }, "minzoom": 14, "source": { @@ -304,17 +318,20 @@ "en": "Map layer to show fire hydrants.", "ja": "消火栓を表示するマップレイヤ。", "zh_Hant": "顯示消防栓的地圖圖層。", - "nb_NO": "Kartlag for å vise brannslokkere." + "nb_NO": "Kartlag for å vise brannslokkere.", + "ru": "Слой карты, отображающий огнетушители." }, "tagRenderings": [ { "render": { "en": "Location: {location}", - "ja": "場所:{location}" + "ja": "場所:{location}", + "ru": "Местоположение: {location}" }, "question": { "en": "Where is it positioned?", - "ja": "どこにあるんですか?" + "ja": "どこにあるんですか?", + "ru": "Где это расположено?" }, "mappings": [ { @@ -325,7 +342,8 @@ }, "then": { "en": "Found indoors.", - "ja": "屋内にある。" + "ja": "屋内にある。", + "ru": "Внутри." } }, { @@ -336,7 +354,8 @@ }, "then": { "en": "Found outdoors.", - "ja": "屋外にある。" + "ja": "屋外にある。", + "ru": "Снаружи." } } ], @@ -367,11 +386,13 @@ "title": { "en": "Fire extinguisher", "ja": "消火器", - "nb_NO": "Brannslukker" + "nb_NO": "Brannslukker", + "ru": "Огнетушитель" }, "description": { "en": "A fire extinguisher is a small, portable device used to stop a fire", - "ja": "消火器は、火災を止めるために使用される小型で携帯可能な装置である" + "ja": "消火器は、火災を止めるために使用される小型で携帯可能な装置である", + "ru": "Огнетушитель - небольшое переносное устройство для тушения огня" } } ], @@ -383,7 +404,8 @@ "en": "Map of fire stations", "ja": "消防署の地図", "nb_NO": "Kart over brannstasjoner", - "it": "Mappa delle caserme dei vigili del fuoco" + "it": "Mappa delle caserme dei vigili del fuoco", + "ru": "Карта пожарных частей" }, "minzoom": 12, "source": { @@ -406,7 +428,8 @@ "description": { "en": "Map layer to show fire stations.", "ja": "消防署を表示するためのマップレイヤ。", - "it": "Livello che mostra le caserme dei vigili del fuoco." + "it": "Livello che mostra le caserme dei vigili del fuoco.", + "ru": "Слой карты, отображающий пожарные части." }, "tagRenderings": [ { @@ -416,13 +439,14 @@ "question": { "en": "What is the name of this fire station?", "ja": "この消防署の名前は何ですか?", - "ru": "Как называется пожарная часть?", + "ru": "Как называется эта пожарная часть?", "it": "Come si chiama questa caserma dei vigili del fuoco?" }, "render": { "en": "This station is called {name}.", "ja": "このステーションの名前は{name}です。", - "it": "Questa caserma si chiama {name}." + "it": "Questa caserma si chiama {name}.", + "ru": "Эта часть называется {name}." } }, { @@ -432,24 +456,28 @@ "question": { "en": " What is the street name where the station located?", "ja": " 救急ステーションの所在地はどこですか?", - "it": " Qual è il nome della via in cui si trova la caserma?" + "it": " Qual è il nome della via in cui si trova la caserma?", + "ru": " По какому адресу расположена эта часть?" }, "render": { "en": "This station is along a highway called {addr:street}.", - "ja": "{addr:street} 沿いにあります。" + "ja": "{addr:street} 沿いにあります。", + "ru": "Часть расположена вдоль шоссе {addr:street}." } }, { "question": { "en": "Where is the station located? (e.g. name of neighborhood, villlage, or town)", - "ja": "このステーションの住所は?(例: 地区、村、または町の名称)" + "ja": "このステーションの住所は?(例: 地区、村、または町の名称)", + "ru": "Где расположена часть? (напр., название населённого пункта)" }, "freeform": { "key": "addr:place" }, "render": { "en": "This station is found within {addr:place}.", - "ja": "このステーションは{addr:place}にあります。" + "ja": "このステーションは{addr:place}にあります。", + "ru": "Эта часть расположена в {addr:place}." } }, { @@ -560,7 +588,8 @@ ], "title": { "en": "Fire station", - "ja": "消防署" + "ja": "消防署", + "ru": "Пожарная часть" }, "description": { "en": "A fire station is a place where the fire trucks and firefighters are located when not in operation.", @@ -573,7 +602,8 @@ "id": "ambulancestation", "name": { "en": "Map of ambulance stations", - "ja": "救急ステーションの地図" + "ja": "救急ステーションの地図", + "ru": "Карта станций скорой помощи" }, "minzoom": 12, "source": { @@ -602,11 +632,12 @@ "question": { "en": "What is the name of this ambulance station?", "ja": "この救急ステーションの名前は何ですか?", - "ru": "Как называется станция скорой помощи?" + "ru": "Как называется эта станция скорой помощи?" }, "render": { "en": "This station is called {name}.", - "ja": "このステーションの名前は{name}です。" + "ja": "このステーションの名前は{name}です。", + "ru": "Эта станция называется {name}." } }, { @@ -615,17 +646,20 @@ }, "question": { "en": " What is the street name where the station located?", - "ja": " 救急ステーションの所在地はどこですか?" + "ja": " 救急ステーションの所在地はどこですか?", + "ru": " По какому адресу расположена эта станция?" }, "render": { "en": "This station is along a highway called {addr:street}.", - "ja": "{addr:street} 沿いにあります。" + "ja": "{addr:street} 沿いにあります。", + "ru": "Эта станция расположена вдоль шоссе {addr:street}." } }, { "question": { "en": "Where is the station located? (e.g. name of neighborhood, villlage, or town)", - "ja": "このステーションの住所は?(例: 地区、村、または町の名称)" + "ja": "このステーションの住所は?(例: 地区、村、または町の名称)", + "ru": "Где расположена станция? (напр., название населённого пункта)" }, "freeform": { "key": "addr:place" @@ -735,7 +769,8 @@ }, "description": { "en": "Add an ambulance station to the map", - "ja": "救急ステーション(消防署)をマップに追加する" + "ja": "救急ステーション(消防署)をマップに追加する", + "ru": "Добавить станцию скорой помощи на карту" } } ], diff --git a/assets/themes/maps/maps.json b/assets/themes/maps/maps.json index cc0d114e3..e34cdce30 100644 --- a/assets/themes/maps/maps.json +++ b/assets/themes/maps/maps.json @@ -5,7 +5,8 @@ "nl": "Een kaart met Kaarten", "fr": "Carte des cartes", "ja": "マップのマップ", - "zh_Hant": "地圖的地圖" + "zh_Hant": "地圖的地圖", + "ru": "Карта карт" }, "shortDescription": { "en": "This theme shows all (touristic) maps that OpenStreetMap knows of", @@ -26,7 +27,8 @@ "nl", "fr", "ja", - "zh_Hant" + "zh_Hant", + "ru" ], "maintainer": "MapComplete", "icon": "./assets/themes/maps/logo.svg", diff --git a/assets/themes/openwindpowermap/openwindpowermap.json b/assets/themes/openwindpowermap/openwindpowermap.json index 39c2baa41..2330b885e 100644 --- a/assets/themes/openwindpowermap/openwindpowermap.json +++ b/assets/themes/openwindpowermap/openwindpowermap.json @@ -1,165 +1,185 @@ { - "id": "openwindpowermap", - "title": { - "en": "OpenWindPowerMap" - }, - "maintainer": "Seppe Santens", - "icon": "./assets/themes/openwindpowermap/wind_turbine.svg", - "description": { - "en": "A map for showing and editing wind turbines." - }, - "language": [ - "en" - ], - "version": "2021-06-18", - "startLat": 50.520, - "startLon": 4.643, - "startZoom": 8, - "clustering": { + "id": "openwindpowermap", + "title": { + "en": "OpenWindPowerMap" + }, + "maintainer": "Seppe Santens", + "icon": "./assets/themes/openwindpowermap/wind_turbine.svg", + "description": { + "en": "A map for showing and editing wind turbines." + }, + "language": [ + "en", + "nl" + ], + "version": "2021-06-18", + "startLat": 50.52, + "startLon": 4.643, + "startZoom": 8, + "clustering": { "maxZoom": 8 }, - "layers": [ - { - "id": "windturbine", - "name": { - "en": "wind turbine" - }, - "source": { - "osmTags": "generator:source=wind" - }, - "minzoom": 10, - "wayHandling": 1, - "title": { - "render": { - "en": "wind turbine" - }, - "mappings": [ - { - "if": "name~*", - "then": { - "en": "{name}" - } - } - ] - }, - "icon": "./assets/themes/openwindpowermap/wind_turbine.svg", - "iconSize": "40, 40, bottom", - "label": { - "mappings": [ - { - "if": "generator:output:electricity~^[0-9]+.*[W]$", - "then": "
{generator:output:electricity}
" - } - ] - }, - "tagRenderings": [ - { - "render": { - "en": "The power output of this wind turbine is {generator:output:electricity}." - }, - "question": { - "en": "What is the power output of this wind turbine? (e.g. 2.3 MW)" - }, - "freeform": { - "key": "generator:output:electricity" - } - }, - { - "render": { - "en": "This wind turbine is operated by {operator}." - }, - "question": { - "en": "Who operates this wind turbine?" - }, - "freeform": { - "key": "operator" - } - }, - { - "render": { - "en": "The total height (including rotor radius) of this wind turbine is {height} metres." - }, - "question": { - "en": "What is the total height of this wind turbine (including rotor radius), in metres?" - }, - "freeform": { - "key": "height", - "type": "float" - } - }, - { - "render": { - "en": "The rotor diameter of this wind turbine is {rotor:diameter} metres." - }, - "question": { - "en": "What is the rotor diameter of this wind turbine, in metres?" - }, - "freeform": { - "key": "rotor:diameter", - "type": "float" - } - }, - { - "render": { - "en": "This wind turbine went into operation on/in {start_date}." - }, - "question": { - "en": "When did this wind turbine go into operation?" - }, - "freeform": { - "key": "start_date", - "type": "date" - } - }, - "images" - ], - "presets": [ - { - "tags": [ - "power=generator", - "generator:source=wind" - ], - "title": { - "en": "wind turbine" - } - } - ] - } - ], - "units": [ - { - "appliesToKey": ["generator:output:electricity"], - "applicableUnits": [{ - "canonicalDenomination": "MW", - "alternativeDenomination": ["megawatts","megawatt"], - "human": { - "en": " megawatts", - "nl": " megawatt" - } - },{ - "canonicalDenomination": "kW", - "alternativeDenomination": ["kilowatts","kilowatt"], - "human": { - "en": " kilowatts", - "nl": " kilowatt" - } - },{ - "canonicalDenomination": "W", - "alternativeDenomination": ["watts","watt"], - "human": { - "en": " watts", - "nl": " watt" - } - },{ - "canonicalDenomination": "GW", - "alternativeDenomination": ["gigawatts","gigawatt"], - "human": { - "en": " gigawatts", - "nl": " gigawatt" - } - }], - "eraseInvalidValues": true - } - ], - "defaultBackgroundId": "CartoDB.Voyager" -} + "layers": [ + { + "id": "windturbine", + "name": { + "en": "wind turbine" + }, + "source": { + "osmTags": "generator:source=wind" + }, + "minzoom": 10, + "wayHandling": 1, + "title": { + "render": { + "en": "wind turbine" + }, + "mappings": [ + { + "if": "name~*", + "then": { + "en": "{name}" + } + } + ] + }, + "icon": "./assets/themes/openwindpowermap/wind_turbine.svg", + "iconSize": "40, 40, bottom", + "label": { + "mappings": [ + { + "if": "generator:output:electricity~^[0-9]+.*[W]$", + "then": "
{generator:output:electricity}
" + } + ] + }, + "tagRenderings": [ + { + "render": { + "en": "The power output of this wind turbine is {generator:output:electricity}." + }, + "question": { + "en": "What is the power output of this wind turbine? (e.g. 2.3 MW)" + }, + "freeform": { + "key": "generator:output:electricity" + } + }, + { + "render": { + "en": "This wind turbine is operated by {operator}." + }, + "question": { + "en": "Who operates this wind turbine?" + }, + "freeform": { + "key": "operator" + } + }, + { + "render": { + "en": "The total height (including rotor radius) of this wind turbine is {height} metres." + }, + "question": { + "en": "What is the total height of this wind turbine (including rotor radius), in metres?" + }, + "freeform": { + "key": "height", + "type": "float" + } + }, + { + "render": { + "en": "The rotor diameter of this wind turbine is {rotor:diameter} metres." + }, + "question": { + "en": "What is the rotor diameter of this wind turbine, in metres?" + }, + "freeform": { + "key": "rotor:diameter", + "type": "float" + } + }, + { + "render": { + "en": "This wind turbine went into operation on/in {start_date}." + }, + "question": { + "en": "When did this wind turbine go into operation?" + }, + "freeform": { + "key": "start_date", + "type": "date" + } + }, + "images" + ], + "presets": [ + { + "tags": [ + "power=generator", + "generator:source=wind" + ], + "title": { + "en": "wind turbine" + } + } + ] + } + ], + "units": [ + { + "appliesToKey": [ + "generator:output:electricity" + ], + "applicableUnits": [ + { + "canonicalDenomination": "MW", + "alternativeDenomination": [ + "megawatts", + "megawatt" + ], + "human": { + "en": " megawatts", + "nl": " megawatt" + } + }, + { + "canonicalDenomination": "kW", + "alternativeDenomination": [ + "kilowatts", + "kilowatt" + ], + "human": { + "en": " kilowatts", + "nl": " kilowatt" + } + }, + { + "canonicalDenomination": "W", + "alternativeDenomination": [ + "watts", + "watt" + ], + "human": { + "en": " watts", + "nl": " watt" + } + }, + { + "canonicalDenomination": "GW", + "alternativeDenomination": [ + "gigawatts", + "gigawatt" + ], + "human": { + "en": " gigawatts", + "nl": " gigawatt" + } + } + ], + "eraseInvalidValues": true + } + ], + "defaultBackgroundId": "CartoDB.Voyager" +} \ No newline at end of file diff --git a/assets/themes/personalLayout/personalLayout.json b/assets/themes/personalLayout/personalLayout.json index b834fbdc3..02e26cdbd 100644 --- a/assets/themes/personalLayout/personalLayout.json +++ b/assets/themes/personalLayout/personalLayout.json @@ -20,7 +20,8 @@ "fr": "Crée un thème personnalisé basé sur toutes les couches disponibles de tous les thèmes", "de": "Erstellen Sie ein persönliches Thema auf der Grundlage aller verfügbaren Ebenen aller Themen", "ja": "すべてのテーマの使用可能なすべてのレイヤーに基づいて個人用テーマを作成する", - "zh_Hant": "從所有可用的主題圖層創建個人化主題" + "zh_Hant": "從所有可用的主題圖層創建個人化主題", + "ru": "Создать персональную тему на основе доступных слоёв тем" }, "language": [ "en", @@ -31,7 +32,8 @@ "fr", "de", "ja", - "zh_Hant" + "zh_Hant", + "ru" ], "maintainer": "MapComplete", "icon": "./assets/svg/addSmall.svg", diff --git a/assets/themes/playgrounds/playgrounds.json b/assets/themes/playgrounds/playgrounds.json index ce3a2b398..418aa36bc 100644 --- a/assets/themes/playgrounds/playgrounds.json +++ b/assets/themes/playgrounds/playgrounds.json @@ -5,28 +5,32 @@ "en": "Playgrounds", "fr": "Aires de jeux", "ja": "遊び場", - "zh_Hant": "遊樂場" + "zh_Hant": "遊樂場", + "ru": "Игровые площадки" }, "shortDescription": { "nl": "Een kaart met speeltuinen", "en": "A map with playgrounds", "fr": "Une carte des aires de jeux", "ja": "遊び場のある地図", - "zh_Hant": "遊樂場的地圖" + "zh_Hant": "遊樂場的地圖", + "ru": "Карта игровых площадок" }, "description": { "nl": "Op deze kaart vind je speeltuinen en kan je zelf meer informatie en foto's toevoegen", "en": "On this map, you find playgrounds and can add more information", "fr": "Cette carte affiche les aires de jeux et permet d'ajouter plus d'informations", "ja": "この地図では遊び場を見つけ情報を追加することができます", - "zh_Hant": "在這份地圖上,你可以尋找遊樂場以及其相關資訊" + "zh_Hant": "在這份地圖上,你可以尋找遊樂場以及其相關資訊", + "ru": "На этой карте можно найти игровые площадки и добавить дополнительную информацию" }, "language": [ "nl", "en", "fr", "ja", - "zh_Hant" + "zh_Hant", + "ru" ], "maintainer": "", "icon": "./assets/themes/playgrounds/playground.svg", diff --git a/assets/themes/shops/shops.json b/assets/themes/shops/shops.json index e50029a62..571d0e1b6 100644 --- a/assets/themes/shops/shops.json +++ b/assets/themes/shops/shops.json @@ -4,7 +4,8 @@ "en": "Open Shop Map", "fr": "Carte des magasins", "ja": "オープン ショップ マップ", - "zh_Hant": "開放商店地圖" + "zh_Hant": "開放商店地圖", + "ru": "Открыть карту магазинов" }, "shortDescription": { "en": "An editable map with basic shop information", @@ -23,6 +24,7 @@ "ja", "zh_Hant", "ru", + "nl", "ca", "id" ], @@ -41,7 +43,8 @@ "en": "Shop", "fr": "Magasin", "ru": "Магазин", - "ja": "店" + "ja": "店", + "nl": "Winkel" }, "minzoom": 16, "source": { @@ -56,7 +59,8 @@ "en": "Shop", "fr": "Magasin", "ru": "Магазин", - "ja": "店" + "ja": "店", + "nl": "Winkel" }, "mappings": [ { @@ -90,7 +94,9 @@ "description": { "en": "A shop", "fr": "Un magasin", - "ja": "ショップ" + "ja": "ショップ", + "nl": "Een winkel", + "ru": "Магазин" }, "tagRenderings": [ "images", @@ -98,8 +104,9 @@ "question": { "en": "What is the name of this shop?", "fr": "Qu'est-ce que le nom de ce magasin?", - "ru": "Как называется магазин?", - "ja": "このお店の名前は何ですか?" + "ru": "Как называется этот магазин?", + "ja": "このお店の名前は何ですか?", + "nl": "Wat is de naam van deze winkel?" }, "render": "This shop is called {name}", "freeform": { @@ -115,7 +122,8 @@ "question": { "en": "What does this shop sell?", "fr": "Que vends ce magasin ?", - "ja": "このお店では何を売っていますか?" + "ja": "このお店では何を売っていますか?", + "ru": "Что продаётся в этом магазине?" }, "freeform": { "key": "shop" @@ -143,7 +151,8 @@ "en": "Supermarket", "fr": "Supermarché", "ru": "Супермаркет", - "ja": "スーパーマーケット" + "ja": "スーパーマーケット", + "nl": "Supermarkt" } }, { @@ -169,7 +178,8 @@ "en": "Hairdresser", "fr": "Coiffeur", "ru": "Парикмахерская", - "ja": "理容師" + "ja": "理容師", + "nl": "Kapper" } }, { @@ -181,7 +191,8 @@ "then": { "en": "Bakery", "fr": "Boulangerie", - "ja": "ベーカリー" + "ja": "ベーカリー", + "nl": "Bakkerij" } }, { @@ -223,7 +234,9 @@ "question": { "en": "What is the phone number?", "fr": "Quel est le numéro de téléphone ?", - "ja": "電話番号は何番ですか?" + "ja": "電話番号は何番ですか?", + "nl": "Wat is het telefoonnummer?", + "ru": "Какой телефон?" }, "freeform": { "key": "phone", @@ -242,7 +255,9 @@ "question": { "en": "What is the website of this shop?", "fr": "Quel est le site internet de ce magasin ?", - "ja": "このお店のホームページは何ですか?" + "ja": "このお店のホームページは何ですか?", + "nl": "Wat is de website van deze winkel?", + "ru": "Какой веб-сайт у этого магазина?" }, "freeform": { "key": "website", @@ -260,7 +275,8 @@ "question": { "en": "What is the email address of this shop?", "fr": "Quelle est l'adresse électronique de ce magasin ?", - "ja": "このお店のメールアドレスは何ですか?" + "ja": "このお店のメールアドレスは何ですか?", + "ru": "Каков адрес электронной почты этого магазина?" }, "freeform": { "key": "email", @@ -277,7 +293,9 @@ "question": { "en": "What are the opening hours of this shop?", "fr": "Quels sont les horaires d'ouverture de ce magasin ?", - "ja": "この店の営業時間は何時から何時までですか?" + "ja": "この店の営業時間は何時から何時までですか?", + "nl": "Wat zijn de openingsuren van deze winkel?", + "ru": "Каковы часы работы этого магазина?" }, "freeform": { "key": "opening_hours", @@ -316,13 +334,15 @@ "en": "Shop", "fr": "Magasin", "ru": "Магазин", - "ja": "店" + "ja": "店", + "nl": "Winkel" }, "description": { "en": "Add a new shop", "fr": "Ajouter un nouveau magasin", "ru": "Добавить новый магазин", - "ja": "新しい店を追加する" + "ja": "新しい店を追加する", + "nl": "Voeg een nieuwe winkel toe" } } ], diff --git a/assets/themes/sport_pitches/sport_pitches.json b/assets/themes/sport_pitches/sport_pitches.json index 5d872c8dc..7f1fdeebd 100644 --- a/assets/themes/sport_pitches/sport_pitches.json +++ b/assets/themes/sport_pitches/sport_pitches.json @@ -5,14 +5,16 @@ "fr": "Terrains de sport", "en": "Sport pitches", "ja": "スポーツ競技場", - "zh_Hant": "運動場地" + "zh_Hant": "運動場地", + "ru": "Спортивные площадки" }, "shortDescription": { "nl": "Deze kaart toont sportvelden", "fr": "Une carte montrant les terrains de sport", "en": "A map showing sport pitches", "ja": "スポーツ競技場を示す地図", - "zh_Hant": "顯示運動場地的地圖" + "zh_Hant": "顯示運動場地的地圖", + "ru": "Карта, отображающая спортивные площадки" }, "description": { "nl": "Een sportveld is een ingerichte plaats met infrastructuur om een sport te beoefenen", @@ -26,7 +28,8 @@ "fr", "en", "ja", - "zh_Hant" + "zh_Hant", + "ru" ], "maintainer": "", "icon": "./assets/layers/sport_pitch/table_tennis.svg", diff --git a/assets/themes/trees/trees.json b/assets/themes/trees/trees.json index daf26fe5b..8545caa9a 100644 --- a/assets/themes/trees/trees.json +++ b/assets/themes/trees/trees.json @@ -15,7 +15,8 @@ "fr": "Carte des arbres", "it": "Mappa tutti gli alberi", "ja": "すべての樹木をマッピングする", - "zh_Hant": "所有樹木的地圖" + "zh_Hant": "所有樹木的地圖", + "ru": "Карта деревьев" }, "description": { "nl": "Breng bomen in kaart!", @@ -23,7 +24,8 @@ "fr": "Cartographions tous les arbres !", "it": "Mappa tutti gli alberi!", "ja": "すべての樹木をマッピングします!", - "zh_Hant": "繪製所有樹木!" + "zh_Hant": "繪製所有樹木!", + "ru": "Нанесите все деревья на карту!" }, "language": [ "nl", diff --git a/langs/layers/fi.json b/langs/layers/fi.json index 09fd6f9a8..71e6a3ca1 100644 --- a/langs/layers/fi.json +++ b/langs/layers/fi.json @@ -1,12 +1,86 @@ { - "bike_repair_station": { - "presets": { - "0": { - "title": "Pyöräpumppu" + "bench": { + "name": "Penkit", + "title": { + "render": "Penkki" + }, + "tagRenderings": { + "1": { + "render": "Selkänoja", + "mappings": { + "0": { + "then": "Selkänoja: kyllä" + }, + "1": { + "then": "Selkänoja: ei" + } + } + }, + "3": { + "render": "Materiaali: {material}", + "mappings": { + "0": { + "then": "Materiaali: puu" + }, + "2": { + "then": "Materiaali: kivi" + }, + "3": { + "then": "Materiaali: betoni" + }, + "4": { + "then": "Materiaali: muovi" + }, + "5": { + "then": "Materiaali: teräs" + } + } + }, + "5": { + "render": "Väri: {colour}", + "mappings": { + "0": { + "then": "Väri: ruskea" + }, + "1": { + "then": "Väri: vihreä" + }, + "2": { + "then": "Väri: harmaa" + }, + "3": { + "then": "Väri: valkoinen" + }, + "4": { + "then": "Väri: punainen" + }, + "5": { + "then": "Väri: musta" + }, + "6": { + "then": "Väri: sininen" + }, + "7": { + "then": "Väri: keltainen" + } + } } }, - "icon": { - "render": "./assets/layers/bike_repair_station/repair_station.svg" + "presets": { + "0": { + "title": "Penkki", + "description": "Lisää uusi penkki" + } + } + }, + "bench_at_pt": { + "title": { + "render": "Penkki" + }, + "tagRenderings": { + "1": { + "render": "{name}" + } } }, "bike_parking": { @@ -16,88 +90,14 @@ } } }, - "bench_at_pt": { - "tagRenderings": { - "1": { - "render": "{name}" - } + "bike_repair_station": { + "icon": { + "render": "./assets/layers/bike_repair_station/repair_station.svg" }, - "title": { - "render": "Penkki" - } - }, - "bench": { "presets": { "0": { - "description": "Lisää uusi penkki", - "title": "Penkki" + "title": "Pyöräpumppu" } - }, - "tagRenderings": { - "5": { - "mappings": { - "7": { - "then": "Väri: keltainen" - }, - "6": { - "then": "Väri: sininen" - }, - "5": { - "then": "Väri: musta" - }, - "4": { - "then": "Väri: punainen" - }, - "3": { - "then": "Väri: valkoinen" - }, - "2": { - "then": "Väri: harmaa" - }, - "1": { - "then": "Väri: vihreä" - }, - "0": { - "then": "Väri: ruskea" - } - }, - "render": "Väri: {colour}" - }, - "3": { - "mappings": { - "5": { - "then": "Materiaali: teräs" - }, - "4": { - "then": "Materiaali: muovi" - }, - "3": { - "then": "Materiaali: betoni" - }, - "2": { - "then": "Materiaali: kivi" - }, - "0": { - "then": "Materiaali: puu" - } - }, - "render": "Materiaali: {material}" - }, - "1": { - "mappings": { - "1": { - "then": "Selkänoja: ei" - }, - "0": { - "then": "Selkänoja: kyllä" - } - }, - "render": "Selkänoja" - } - }, - "title": { - "render": "Penkki" - }, - "name": "Penkit" + } } -} +} \ No newline at end of file diff --git a/langs/layers/ru.json b/langs/layers/ru.json index b97d98281..0cd328a6a 100644 --- a/langs/layers/ru.json +++ b/langs/layers/ru.json @@ -204,11 +204,33 @@ "2": { "question": "Есть ли в этом велосипедном кафе велосипедный насос для всеобщего использования?", "mappings": { - "1": { - "then": "В этом велосипедном кафе нет велосипедного насоса для всеобщего использования" - }, "0": { "then": "В этом велосипедном кафе есть велосипедный насос для всеобщего использования" + }, + "1": { + "then": "В этом велосипедном кафе нет велосипедного насоса для всеобщего использования" + } + } + }, + "3": { + "question": "Есть ли здесь инструменты для починки вашего велосипеда?", + "mappings": { + "0": { + "then": "В этом велосипедном кафе есть инструменты для починки своего велосипеда" + }, + "1": { + "then": "В этом велосипедном кафе нет инструментов для починки своего велосипеда" + } + } + }, + "4": { + "question": "Есть ли услуги ремонта велосипедов в этом велосипедном кафе?", + "mappings": { + "0": { + "then": "В этом велосипедном кафе есть услуги ремонта велосипедов" + }, + "1": { + "then": "В этом велосипедном кафе нет услуг ремонта велосипедов" } } }, @@ -223,28 +245,6 @@ }, "8": { "question": "Каков режим работы этого велосипедного кафе?" - }, - "4": { - "mappings": { - "1": { - "then": "В этом велосипедном кафе нет услуг ремонта велосипедов" - }, - "0": { - "then": "В этом велосипедном кафе есть услуги ремонта велосипедов" - } - }, - "question": "Есть ли услуги ремонта велосипедов в этом велосипедном кафе?" - }, - "3": { - "mappings": { - "1": { - "then": "В этом велосипедном кафе нет инструментов для починки своего велосипеда" - }, - "0": { - "then": "В этом велосипедном кафе есть инструменты для починки своего велосипеда" - } - }, - "question": "Есть ли здесь инструменты для починки вашего велосипеда?" } }, "presets": { @@ -253,6 +253,9 @@ } } }, + "bike_monitoring_station": { + "name": "Станции мониторинга" + }, "bike_parking": { "tagRenderings": { "1": { @@ -272,22 +275,22 @@ } } }, - "5": { - "render": "{access}", - "question": "Кто может пользоваться этой велопарковкой?" + "3": { + "mappings": { + "0": { + "then": "Это крытая парковка (есть крыша/навес)" + }, + "1": { + "then": "Это открытая парковка" + } + } }, "4": { "render": "Место для {capacity} велосипеда(ов)" }, - "3": { - "mappings": { - "1": { - "then": "Это открытая парковка" - }, - "0": { - "then": "Это крытая парковка (есть крыша/навес)" - } - } + "5": { + "question": "Кто может пользоваться этой велопарковкой?", + "render": "{access}" } } }, @@ -303,6 +306,14 @@ } }, "tagRenderings": { + "3": { + "question": "Когда работает эта точка обслуживания велосипедов?", + "mappings": { + "0": { + "then": "Всегда открыто" + } + } + }, "6": { "question": "Велосипедный насос все еще работает?", "mappings": { @@ -348,14 +359,6 @@ "then": "Есть манометр, но он сломан" } } - }, - "3": { - "question": "Когда работает эта точка обслуживания велосипедов?", - "mappings": { - "0": { - "then": "Всегда открыто" - } - } } }, "icon": { @@ -368,7 +371,9 @@ } }, "bike_shop": { + "name": "Обслуживание велосипедов/магазин", "title": { + "render": "Обслуживание велосипедов/магазин", "mappings": { "0": { "then": "Магазин спортивного инвентаря {name}" @@ -382,8 +387,7 @@ "4": { "then": "Магазин велосипедов {name}" } - }, - "render": "Обслуживание велосипедов/магазин" + } }, "description": "Магазин, специализирующийся на продаже велосипедов или сопутствующих товаров", "tagRenderings": { @@ -401,6 +405,7 @@ "question": "Какой адрес электронной почты у {name}?" }, "9": { + "question": "Продаются ли велосипеды в этом магазине?", "mappings": { "0": { "then": "В этом магазине продаются велосипеды" @@ -408,8 +413,7 @@ "1": { "then": "В этом магазине не продают велосипеды" } - }, - "question": "Продаются ли велосипеды в этом магазине?" + } }, "10": { "question": "В этом магазине ремонтируют велосипеды?", @@ -453,38 +457,37 @@ } } }, - "15": { - "question": "Здесь моют велосипеды?", - "mappings": { - "2": { - "then": "В этом магазине нет услуг мойки/чистки велосипедов" - }, - "0": { - "then": "В этом магазине оказываются услуги мойки/чистки велосипедов" - } - } - }, "13": { "question": "Предлагается ли в этом магазине велосипедный насос для всеобщего пользования?", "mappings": { - "1": { - "then": "В этом магазине нет велосипедного насоса для всеобщего пользования" - }, "0": { "then": "В этом магазине есть велосипедный насос для всеобщего пользования" + }, + "1": { + "then": "В этом магазине нет велосипедного насоса для всеобщего пользования" } } }, "14": { + "question": "Есть ли здесь инструменты для починки собственного велосипеда?", "mappings": { "2": { "then": "Инструменты для починки доступны только при покупке/аренде велосипеда в магазине" } - }, - "question": "Есть ли здесь инструменты для починки собственного велосипеда?" + } + }, + "15": { + "question": "Здесь моют велосипеды?", + "mappings": { + "0": { + "then": "В этом магазине оказываются услуги мойки/чистки велосипедов" + }, + "2": { + "then": "В этом магазине нет услуг мойки/чистки велосипедов" + } + } } - }, - "name": "Обслуживание велосипедов/магазин" + } }, "defibrillator": { "name": "Дефибрилляторы", @@ -539,6 +542,9 @@ }, "ghost_bike": { "tagRenderings": { + "2": { + "render": "В знак памяти о {name}" + }, "3": { "render": "Доступна более подробная информация" }, @@ -547,9 +553,6 @@ }, "5": { "render": "Установлен {start_date}" - }, - "2": { - "render": "В знак памяти о {name}" } } }, @@ -600,8 +603,11 @@ "title": { "render": "Стол для пикника" }, + "description": "Слой, отображающий столы для пикника", "tagRenderings": { "0": { + "question": "Из чего изготовлен этот стол для пикника?", + "render": "Этот стол для пикника сделан из {material}", "mappings": { "0": { "then": "Это деревянный стол для пикника" @@ -609,17 +615,14 @@ "1": { "then": "Это бетонный стол для пикника" } - }, - "render": "Этот стол для пикника сделан из {material}", - "question": "Из чего изготовлен этот стол для пикника?" + } } }, "presets": { "0": { "title": "Стол для пикника" } - }, - "description": "Слой, отображающий столы для пикника" + } }, "playground": { "name": "Детские площадки", @@ -642,6 +645,9 @@ "1": { "then": "Поверхность - песок" }, + "2": { + "then": "Покрытие из щепы" + }, "3": { "then": "Поверхность - брусчатка" }, @@ -650,9 +656,17 @@ }, "5": { "then": "Поверхность - бетон" + } + } + }, + "2": { + "question": "Эта игровая площадка освещается ночью?", + "mappings": { + "0": { + "then": "Эта детская площадка освещается ночью" }, - "2": { - "then": "Покрытие из щепы" + "1": { + "then": "Эта детская площадка не освещается ночью" } } }, @@ -660,6 +674,9 @@ "render": "Доступно для детей старше {min_age} лет", "question": "С какого возраста доступна эта детская площадка?" }, + "4": { + "render": "Доступно детям до {max_age}" + }, "6": { "mappings": { "4": { @@ -673,47 +690,33 @@ "8": { "render": "{phone}" }, - "10": { - "mappings": { - "1": { - "then": "Всегда доступен" - }, - "2": { - "then": "Всегда доступен" - }, - "0": { - "then": "Открыто от рассвета до заката" - } - }, - "question": "Когда открыта эта игровая площадка?" - }, "9": { + "question": "Доступна ли детская площадка пользователям кресел-колясок?", "mappings": { - "2": { - "then": "Недоступна пользователям кресел-колясок" + "0": { + "then": "Полностью доступна пользователям кресел-колясок" }, "1": { "then": "Частично доступна пользователям кресел-колясок" }, - "0": { - "then": "Полностью доступна пользователям кресел-колясок" + "2": { + "then": "Недоступна пользователям кресел-колясок" } - }, - "question": "Доступна ли детская площадка пользователям кресел-колясок?" + } }, - "4": { - "render": "Доступно детям до {max_age}" - }, - "2": { + "10": { + "question": "Когда открыта эта игровая площадка?", "mappings": { - "1": { - "then": "Эта детская площадка не освещается ночью" - }, "0": { - "then": "Эта детская площадка освещается ночью" + "then": "Открыто от рассвета до заката" + }, + "1": { + "then": "Всегда доступен" + }, + "2": { + "then": "Всегда доступен" } - }, - "question": "Эта игровая площадка освещается ночью?" + } } }, "presets": { @@ -724,6 +727,7 @@ }, "public_bookcase": { "name": "Книжные шкафы", + "description": "Уличный шкаф с книгами, доступными для всех", "title": { "render": "Книжный шкаф", "mappings": { @@ -748,10 +752,11 @@ } }, "3": { - "question": "Сколько книг помещается в этом общественном книжном шкафу?", - "render": "{capacity} книг помещается в этот книжный шкаф" + "render": "{capacity} книг помещается в этот книжный шкаф", + "question": "Сколько книг помещается в этом общественном книжном шкафу?" }, "4": { + "question": "Какие книги можно найти в этом общественном книжном шкафу?", "mappings": { "0": { "then": "В основном детские книги" @@ -762,27 +767,25 @@ "2": { "then": "Книги и для детей, и для взрослых" } - }, - "question": "Какие книги можно найти в этом общественном книжном шкафу?" - }, - "11": { - "render": "Более подробная информация на сайте", - "question": "Есть ли веб-сайт с более подробной информацией об этом общественном книжном шкафе?" - }, - "10": { - "render": "Установлен {start_date}", - "question": "Когда был установлен этот общественный книжный шкаф?" + } }, "6": { + "question": "Имеется ли свободный доступ к этому общественному книжному шкафу?", "mappings": { "0": { "then": "Свободный доступ" } - }, - "question": "Имеется ли свободный доступ к этому общественному книжному шкафу?" + } + }, + "10": { + "question": "Когда был установлен этот общественный книжный шкаф?", + "render": "Установлен {start_date}" + }, + "11": { + "render": "Более подробная информация на сайте", + "question": "Есть ли веб-сайт с более подробной информацией об этом общественном книжном шкафе?" } - }, - "description": "Уличный шкаф с книгами, доступными для всех" + } }, "slow_roads": { "tagRenderings": { @@ -816,30 +819,32 @@ "title": { "render": "Спортивная площадка" }, + "description": "Спортивная площадка", "tagRenderings": { "1": { "mappings": { - "2": { - "then": "Это стол для пинг-понга" - }, - "5": { + "0": { "then": "Здесь можно играть в баскетбол" }, - "4": { - "then": "Здесь можно играть в корфбол" - }, - "3": { - "then": "Здесь можно играть в теннис" - }, "1": { "then": "Здесь можно играть в футбол" }, - "0": { + "2": { + "then": "Это стол для пинг-понга" + }, + "3": { + "then": "Здесь можно играть в теннис" + }, + "4": { + "then": "Здесь можно играть в корфбол" + }, + "5": { "then": "Здесь можно играть в баскетбол" } } }, "2": { + "question": "Какое покрытие на этой спортивной площадке?", "render": "Поверхность - {surface}", "mappings": { "0": { @@ -857,55 +862,53 @@ "4": { "then": "Поверхность - бетон" } - }, - "question": "Какое покрытие на этой спортивной площадке?" - }, - "7": { - "mappings": { - "1": { - "then": "Всегда доступен" - } - }, - "question": "В какое время доступна эта площадка?" - }, - "4": { - "mappings": { - "1": { - "then": "Желательна предварительная запись для доступа на эту спортивную площадку" - }, - "3": { - "then": "Невозможна предварительная запись" - }, - "2": { - "then": "Предварительная запись для доступа на эту спортивную площадку возможна, но не обязательна" - } - }, - "question": "Нужна ли предварительная запись для доступа на эту спортивную площадку?" + } }, "3": { + "question": "Есть ли свободный доступ к этой спортивной площадке?", "mappings": { - "2": { - "then": "Доступ только членам клуба" + "0": { + "then": "Свободный доступ" }, "1": { "then": "Ограниченный доступ (напр., только по записи, в определённые часы, ...)" }, - "0": { - "then": "Свободный доступ" + "2": { + "then": "Доступ только членам клуба" } - }, - "question": "Есть ли свободный доступ к этой спортивной площадке?" + } + }, + "4": { + "question": "Нужна ли предварительная запись для доступа на эту спортивную площадку?", + "mappings": { + "1": { + "then": "Желательна предварительная запись для доступа на эту спортивную площадку" + }, + "2": { + "then": "Предварительная запись для доступа на эту спортивную площадку возможна, но не обязательна" + }, + "3": { + "then": "Невозможна предварительная запись" + } + } + }, + "7": { + "question": "В какое время доступна эта площадка?", + "mappings": { + "1": { + "then": "Всегда доступен" + } + } } }, "presets": { - "1": { - "title": "Спортивная площадка" - }, "0": { "title": "Стол для настольного тенниса" + }, + "1": { + "title": "Спортивная площадка" } - }, - "description": "Спортивная площадка" + } }, "surveillance_camera": { "name": "Камеры наблюдения", @@ -914,28 +917,28 @@ }, "tagRenderings": { "1": { + "question": "Какая это камера?", "mappings": { - "2": { - "then": "Панорамная камера" - }, "1": { "then": "Камера с поворотным механизмом" + }, + "2": { + "then": "Панорамная камера" } - }, - "question": "Какая это камера?" - }, - "8": { - "question": "Как расположена эта камера?" + } }, "5": { "mappings": { - "2": { - "then": "Возможно, эта камера расположена снаружи" - }, "1": { "then": "Эта камера расположена снаружи" + }, + "2": { + "then": "Возможно, эта камера расположена снаружи" } } + }, + "8": { + "question": "Как расположена эта камера?" } } }, @@ -955,15 +958,15 @@ }, "tagRenderings": { "1": { + "question": "Есть ли свободный доступ к этим туалетам?", "mappings": { - "2": { - "then": "Недоступно" - }, "0": { "then": "Свободный доступ" + }, + "2": { + "then": "Недоступно" } - }, - "question": "Есть ли свободный доступ к этим туалетам?" + } }, "2": { "mappings": { @@ -972,8 +975,9 @@ } } }, - "5": { - "question": "Какие это туалеты?" + "3": { + "question": "Сколько стоит посещение туалета?", + "render": "Стоимость {charge}" }, "4": { "mappings": { @@ -982,9 +986,8 @@ } } }, - "3": { - "render": "Стоимость {charge}", - "question": "Сколько стоит посещение туалета?" + "5": { + "question": "Какие это туалеты?" } } }, @@ -1007,44 +1010,44 @@ } } }, + "4": { + "question": "Это дерево вечнозелёное или листопадное?", + "mappings": { + "0": { + "then": "Листопадное: у дерева опадают листья в определённое время года." + }, + "1": { + "then": "Вечнозелёное." + } + } + }, "5": { "render": "Название: {name}", + "question": "Есть ли у этого дерева название?", "mappings": { "0": { "then": "У этого дерева нет названия." } - }, - "question": "Есть ли у этого дерева название?" - }, - "8": { - "render": "\"\"/ Wikidata: {wikidata}" + } }, "7": { "render": "\"\"/ Onroerend Erfgoed ID: {ref:OnroerendErfgoed}" }, - "4": { - "mappings": { - "1": { - "then": "Вечнозелёное." - }, - "0": { - "then": "Листопадное: у дерева опадают листья в определённое время года." - } - }, - "question": "Это дерево вечнозелёное или листопадное?" + "8": { + "render": "\"\"/ Wikidata: {wikidata}" } }, "presets": { + "0": { + "title": "Лиственное дерево" + }, + "1": { + "title": "Хвойное дерево", + "description": "Дерево с хвоей (иглами), например, сосна или ель." + }, "2": { "title": "Дерево", "description": "Если вы не уверены в том, лиственное это дерево или хвойное." - }, - "1": { - "description": "Дерево с хвоей (иглами), например, сосна или ель.", - "title": "Хвойное дерево" - }, - "0": { - "title": "Лиственное дерево" } } }, @@ -1062,8 +1065,5 @@ "question": "Вы хотите добавить описание?" } } - }, - "bike_monitoring_station": { - "name": "Станции мониторинга" } -} +} \ No newline at end of file diff --git a/langs/shared-questions/en.json b/langs/shared-questions/en.json index a8b983d9e..d11785526 100644 --- a/langs/shared-questions/en.json +++ b/langs/shared-questions/en.json @@ -15,6 +15,21 @@ "opening_hours": { "question": "What are the opening hours of {name}?", "render": "

Opening hours

{opening_hours_table(opening_hours)}" + }, + "level": { + "question": "On what level is this feature located?", + "render": "Located on the {level}th floor", + "mappings": { + "0": { + "then": "Located underground" + }, + "1": { + "then": "Located on the ground floor" + }, + "2": { + "then": "Located on the first floor" + } + } } } } \ No newline at end of file diff --git a/langs/shared-questions/nl.json b/langs/shared-questions/nl.json index 2e50d77b1..201608c40 100644 --- a/langs/shared-questions/nl.json +++ b/langs/shared-questions/nl.json @@ -15,6 +15,21 @@ "opening_hours": { "question": "Wat zijn de openingsuren van {name}?", "render": "

Openingsuren

{opening_hours_table(opening_hours)}" + }, + "level": { + "question": "Op welke verdieping bevindt dit punt zich?", + "render": "Bevindt zich op de {level}de verdieping", + "mappings": { + "0": { + "then": "Bevindt zich ondergrounds" + }, + "1": { + "then": "Bevindt zich gelijkvloers" + }, + "2": { + "then": "Bevindt zich op de eerste verdieping" + } + } } } } \ No newline at end of file diff --git a/langs/themes/de.json b/langs/themes/de.json index 95abb60b1..6a0b29fad 100644 --- a/langs/themes/de.json +++ b/langs/themes/de.json @@ -87,6 +87,9 @@ "shortDescription": "Eine Karte aller Sitzbänke", "description": "Diese Karte zeigt alle Sitzbänke, die in OpenStreetMap eingetragen sind: Einzeln stehende Bänke und Bänke, die zu Haltestellen oder Unterständen gehören. Mit einem OpenStreetMap-Account können Sie neue Bänke eintragen oder Detailinformationen existierender Bänke bearbeiten." }, + "bicyclelib": { + "title": "Fahrradbibliothek" + }, "bookcases": { "title": "Öffentliche Bücherschränke Karte", "description": "Ein öffentlicher Bücherschrank ist ein kleiner Bücherschrank am Straßenrand, ein Kasten, eine alte Telefonzelle oder andere Gegenstände, in denen Bücher aufbewahrt werden. Jeder kann ein Buch hinstellen oder mitnehmen. Diese Karte zielt darauf ab, all diese Bücherschränke zu sammeln. Sie können neue Bücherschränke in der Nähe entdecken und mit einem kostenlosen OpenStreetMap-Account schnell Ihre Lieblingsbücherschränke hinzufügen." @@ -327,8 +330,5 @@ "toilets": { "title": "Offene Toilette Karte", "description": "Eine Karte der öffentlichen Toiletten" - }, - "bicyclelib": { - "title": "Fahrradbibliothek" } -} +} \ No newline at end of file diff --git a/langs/themes/en.json b/langs/themes/en.json index ff61b8782..48852d5a4 100644 --- a/langs/themes/en.json +++ b/langs/themes/en.json @@ -1084,6 +1084,68 @@ "shortDescription": "This theme shows all (touristic) maps that OpenStreetMap knows of", "description": "On this map you can find all maps OpenStreetMap knows - typically a big map on an information board showing the area, city or region, e.g. a tourist map on the back of a billboard, a map of a nature reserve, a map of cycling networks in the region, ...)

If a map is missing, you can easily map this map on OpenStreetMap." }, + "openwindpowermap": { + "title": "OpenWindPowerMap", + "description": "A map for showing and editing wind turbines.", + "layers": { + "0": { + "name": "wind turbine", + "title": { + "render": "wind turbine", + "mappings": { + "0": { + "then": "{name}" + } + } + }, + "tagRenderings": { + "0": { + "render": "The power output of this wind turbine is {generator:output:electricity}.", + "question": "What is the power output of this wind turbine? (e.g. 2.3 MW)" + }, + "1": { + "render": "This wind turbine is operated by {operator}.", + "question": "Who operates this wind turbine?" + }, + "2": { + "render": "The total height (including rotor radius) of this wind turbine is {height} metres.", + "question": "What is the total height of this wind turbine (including rotor radius), in metres?" + }, + "3": { + "render": "The rotor diameter of this wind turbine is {rotor:diameter} metres.", + "question": "What is the rotor diameter of this wind turbine, in metres?" + }, + "4": { + "render": "This wind turbine went into operation on/in {start_date}.", + "question": "When did this wind turbine go into operation?" + } + }, + "presets": { + "0": { + "title": "wind turbine" + } + } + } + }, + "units": { + "0": { + "applicableUnits": { + "0": { + "human": " megawatts" + }, + "1": { + "human": " kilowatts" + }, + "2": { + "human": " watts" + }, + "3": { + "human": " gigawatts" + } + } + } + } + }, "personal": { "title": "Personal theme", "description": "Create a personal theme based on all the available layers of all themes" diff --git a/langs/themes/nl.json b/langs/themes/nl.json index c2c585cbd..2d8dbe299 100644 --- a/langs/themes/nl.json +++ b/langs/themes/nl.json @@ -241,45 +241,77 @@ "campersite": { "title": "Kampeersite", "shortDescription": "Vind locaties waar je de nacht kan doorbrengen met je mobilehome", + "description": "Deze website verzamelt en toont alle officiële plaatsen waar een camper mag overnachten en afvalwater kan lozen. Ook jij kan extra gegevens toevoegen, zoals welke services er geboden worden en hoeveel dit kot, ook afbeeldingen en reviews kan je toevoegen. De data wordt op OpenStreetMap opgeslaan en is dus altijd gratis te hergebruiken, ook door andere applicaties.", "layers": { "0": { "name": "Camperplaatsen", - "tagRenderings": { - "3": { - "question": "Hoeveel kost deze plaats?", - "render": "Deze plaats vraagt {charge}" - }, - "2": { - "mappings": { - "1": { - "then": "Kan gratis gebruikt worden" - }, - "0": { - "then": "Gebruik is betalend" - } - }, - "question": "Moet men betalen om deze camperplaats te gebruiken?" - }, - "1": { - "question": "Wat is de naam van deze plaats?", - "render": "Deze plaats heet {name}" - }, - "9": { - "render": "Officiële website: : {website}" - } - }, - "description": "camperplaatsen", "title": { + "render": "Camperplaats {name}", "mappings": { "0": { "then": "Camper site" } + } + }, + "description": "camperplaatsen", + "tagRenderings": { + "1": { + "render": "Deze plaats heet {name}", + "question": "Wat is de naam van deze plaats?" }, - "render": "Camperplaats {name}" + "2": { + "question": "Moet men betalen om deze camperplaats te gebruiken?", + "mappings": { + "0": { + "then": "Gebruik is betalend" + }, + "1": { + "then": "Kan gratis gebruikt worden" + } + } + }, + "3": { + "render": "Deze plaats vraagt {charge}", + "question": "Hoeveel kost deze plaats?" + }, + "9": { + "render": "Officiële website: : {website}" + } } } - }, - "description": "Deze website verzamelt en toont alle officiële plaatsen waar een camper mag overnachten en afvalwater kan lozen. Ook jij kan extra gegevens toevoegen, zoals welke services er geboden worden en hoeveel dit kot, ook afbeeldingen en reviews kan je toevoegen. De data wordt op OpenStreetMap opgeslaan en is dus altijd gratis te hergebruiken, ook door andere applicaties." + } + }, + "charging_stations": { + "title": "Oplaadpunten", + "shortDescription": "Een wereldwijde kaart van oplaadpunten", + "layers": { + "0": { + "name": "Oplaadpunten", + "title": { + "render": "Oplaadpunt" + }, + "description": "Een oplaadpunt", + "tagRenderings": { + "6": { + "render": "{network}", + "mappings": { + "0": { + "then": "Maakt geen deel uit van een netwerk" + }, + "1": { + "then": "AeroVironment" + }, + "2": { + "then": "Blink" + }, + "3": { + "then": "eVgo" + } + } + } + } + } + } }, "climbing": { "title": "Open Klimkaart", @@ -324,13 +356,13 @@ } } }, + "description": "Een klimzaal", "tagRenderings": { "3": { "render": "{name}", "question": "Wat is de naam van dit Klimzaal?" } - }, - "description": "Een klimzaal" + } }, "2": { "name": "Klimroute", @@ -416,6 +448,9 @@ }, "description": "Een klimgelegenheid?", "tagRenderings": { + "1": { + "render": "{name}" + }, "2": { "mappings": { "0": { @@ -428,9 +463,6 @@ "then": "Klimmen is hier niet toegelaten" } } - }, - "1": { - "render": "{name}" } } } @@ -902,6 +934,26 @@ "shortDescription": "Deze kaart bevat informatie voor natuurliefhebbers", "description": "Op deze kaart vind je informatie voor natuurliefhebbers, zoals info over het natuurgebied waar je inzit, vogelkijkhutten, informatieborden, ..." }, + "openwindpowermap": { + "units": { + "0": { + "applicableUnits": { + "0": { + "human": " megawatt" + }, + "1": { + "human": " kilowatt" + }, + "2": { + "human": " watt" + }, + "3": { + "human": " gigawatt" + } + } + } + } + }, "personal": { "title": "Persoonlijk thema", "description": "Stel je eigen thema samen door lagen te combineren van alle andere themas" @@ -916,6 +968,50 @@ "shortDescription": "Een kaart met speeltuinen", "description": "Op deze kaart vind je speeltuinen en kan je zelf meer informatie en foto's toevoegen" }, + "shops": { + "layers": { + "0": { + "name": "Winkel", + "title": { + "render": "Winkel" + }, + "description": "Een winkel", + "tagRenderings": { + "1": { + "question": "Wat is de naam van deze winkel?" + }, + "2": { + "mappings": { + "1": { + "then": "Supermarkt" + }, + "3": { + "then": "Kapper" + }, + "4": { + "then": "Bakkerij" + } + } + }, + "3": { + "question": "Wat is het telefoonnummer?" + }, + "4": { + "question": "Wat is de website van deze winkel?" + }, + "6": { + "question": "Wat zijn de openingsuren van deze winkel?" + } + }, + "presets": { + "0": { + "title": "Winkel", + "description": "Voeg een nieuwe winkel toe" + } + } + } + } + }, "speelplekken": { "title": "Welkom bij de groendoener!", "shortDescription": "Speelplekken in de Antwerpse Zuidrand", @@ -1034,81 +1130,5 @@ } } } - }, - "charging_stations": { - "layers": { - "0": { - "description": "Een oplaadpunt", - "title": { - "render": "Oplaadpunt" - }, - "name": "Oplaadpunten", - "tagRenderings": { - "6": { - "mappings": { - "3": { - "then": "eVgo" - }, - "2": { - "then": "Blink" - }, - "1": { - "then": "AeroVironment" - }, - "0": { - "then": "Maakt geen deel uit van een netwerk" - } - }, - "render": "{network}" - } - } - } - }, - "title": "Oplaadpunten", - "shortDescription": "Een wereldwijde kaart van oplaadpunten" - }, - "shops": { - "layers": { - "0": { - "tagRenderings": { - "4": { - "question": "Wat is de website van deze winkel?" - }, - "3": { - "question": "Wat is het telefoonnummer?" - }, - "2": { - "mappings": { - "4": { - "then": "Bakkerij" - }, - "3": { - "then": "Kapper" - }, - "1": { - "then": "Supermarkt" - } - } - }, - "1": { - "question": "Wat is de naam van deze winkel?" - }, - "6": { - "question": "Wat zijn de openingsuren van deze winkel?" - } - }, - "description": "Een winkel", - "title": { - "render": "Winkel" - }, - "name": "Winkel", - "presets": { - "0": { - "title": "Winkel", - "description": "Voeg een nieuwe winkel toe" - } - } - } - } } -} +} \ No newline at end of file diff --git a/langs/themes/ru.json b/langs/themes/ru.json index a6eec34f2..74f15b875 100644 --- a/langs/themes/ru.json +++ b/langs/themes/ru.json @@ -280,17 +280,17 @@ "6": { "question": "Кто может использовать эту станцию утилизации?", "mappings": { - "3": { + "2": { "then": "Любой может воспользоваться этой станцией утилизации" }, - "2": { + "3": { "then": "Любой может воспользоваться этой станцией утилизации" } } }, "7": { - "question": "К какой сети относится эта станция? (пропустите, если неприменимо)", - "render": "Эта станция - часть сети {network}" + "render": "Эта станция - часть сети {network}", + "question": "К какой сети относится эта станция? (пропустите, если неприменимо)" } } } @@ -350,8 +350,8 @@ }, "presets": { "0": { - "description": "Клуб скалолазания", - "title": "Клуб скалолазания" + "title": "Клуб скалолазания", + "description": "Клуб скалолазания" } } }, @@ -385,6 +385,16 @@ } }, "roamingRenderings": { + "0": { + "question": "Есть ли (неофициальный) веб-сайт с более подробной информацией (напр., topos)?" + }, + "2": { + "mappings": { + "3": { + "then": "Только членам клуба" + } + } + }, "9": { "mappings": { "0": { @@ -394,16 +404,16 @@ "then": "Спортивное скалолазание здесь невозможно" } } - }, + } + } + }, + "fietsstraten": { + "layers": { "2": { - "mappings": { - "3": { - "then": "Только членам клуба" - } + "name": "Все улицы", + "title": { + "render": "Улица" } - }, - "0": { - "question": "Есть ли (неофициальный) веб-сайт с более подробной информацией (напр., topos)?" } } }, @@ -418,28 +428,28 @@ "layers": { "0": { "tagRenderings": { + "2": { + "question": "Сад расположен на солнечной стороне или в тени?" + }, + "3": { + "mappings": { + "0": { + "then": "Есть бочка с дождевой водой" + }, + "1": { + "then": "Нет бочки с дождевой водой" + } + } + }, "4": { "render": "Дата строительства сада: {start_date}" }, - "7": { - "question": "Дополнительная информация о саде (если требуется или еще не указана выше)", - "render": "Подробнее: {description}" - }, "6": { "question": "Какие виды растений обитают здесь?" }, - "3": { - "mappings": { - "1": { - "then": "Нет бочки с дождевой водой" - }, - "0": { - "then": "Есть бочка с дождевой водой" - } - } - }, - "2": { - "question": "Сад расположен на солнечной стороне или в тени?" + "7": { + "render": "Подробнее: {description}", + "question": "Дополнительная информация о саде (если требуется или еще не указана выше)" } } } @@ -453,127 +463,130 @@ "render": "{website}", "question": "Какой веб-сайт у этого магазина?" }, + "4": { + "question": "Какой телефон?" + }, "8": { "mappings": { "1": { "then": "Приносить свою тару не разрешено" } } - }, - "4": { - "question": "Какой телефон?" } } } } }, "hailhydrant": { + "title": "Пожарные гидранты, огнетушители, пожарные станции и станции скорой помощи.", + "shortDescription": "Карта пожарных гидрантов, огнетушителей, пожарных станций и станций скорой помощи.", "layers": { "0": { + "name": "Карта пожарных гидрантов", "title": { "render": "Гидрант" }, + "description": "Слой карты, отображающий пожарные гидранты.", "tagRenderings": { - "1": { - "render": " Тип гидранта: {fire_hydrant:type}", - "mappings": { - "3": { - "then": " Тип стены." - }, - "0": { - "then": "Тип гидранта не определён." - } - }, - "question": "К какому типу относится этот гидрант?" - }, - "2": { - "mappings": { - "2": { - "then": "Гидрант демонтирован." - }, - "0": { - "then": "Гидрант (полностью или частично) в рабочем состоянии." - } - } - }, "0": { + "question": "Какого цвета гидрант?", + "render": "Цвет гидранта {colour}", "mappings": { - "2": { - "then": "Гидрант красного цвета." + "0": { + "then": "Цвет гидранта не определён." }, "1": { "then": "Гидрант жёлтого цвета." }, - "0": { - "then": "Цвет гидранта не определён." + "2": { + "then": "Гидрант красного цвета." } - }, - "render": "Цвет гидранта {colour}", - "question": "Какого цвета гидрант?" + } + }, + "1": { + "question": "К какому типу относится этот гидрант?", + "render": " Тип гидранта: {fire_hydrant:type}", + "mappings": { + "0": { + "then": "Тип гидранта не определён." + }, + "3": { + "then": " Тип стены." + } + } + }, + "2": { + "mappings": { + "0": { + "then": "Гидрант (полностью или частично) в рабочем состоянии." + }, + "2": { + "then": "Гидрант демонтирован." + } + } } }, "presets": { "0": { "title": "Пожарный гидрант" } - }, - "description": "Слой карты, отображающий пожарные гидранты.", - "name": "Карта пожарных гидрантов" + } }, "1": { + "name": "Карта огнетушителей.", "title": { "render": "Огнетушители" }, - "presets": { - "0": { - "description": "Огнетушитель - небольшое переносное устройство для тушения огня", - "title": "Огнетушитель" - } - }, + "description": "Слой карты, отображающий огнетушители.", "tagRenderings": { "0": { + "render": "Местоположение: {location}", + "question": "Где это расположено?", "mappings": { - "1": { - "then": "Снаружи." - }, "0": { "then": "Внутри." + }, + "1": { + "then": "Снаружи." } - }, - "question": "Где это расположено?", - "render": "Местоположение: {location}" + } } }, - "description": "Слой карты, отображающий огнетушители.", - "name": "Карта огнетушителей." + "presets": { + "0": { + "title": "Огнетушитель", + "description": "Огнетушитель - небольшое переносное устройство для тушения огня" + } + } }, "2": { + "name": "Карта пожарных частей", "title": { "render": "Пожарная часть" }, + "description": "Слой карты, отображающий пожарные части.", "tagRenderings": { "0": { "question": "Как называется эта пожарная часть?", "render": "Эта часть называется {name}." }, - "2": { - "render": "Эта часть расположена в {addr:place}.", - "question": "Где расположена часть? (напр., название населённого пункта)" - }, "1": { - "render": "Часть расположена вдоль шоссе {addr:street}.", - "question": " По какому адресу расположена эта часть?" + "question": " По какому адресу расположена эта часть?", + "render": "Часть расположена вдоль шоссе {addr:street}." + }, + "2": { + "question": "Где расположена часть? (напр., название населённого пункта)", + "render": "Эта часть расположена в {addr:place}." } }, "presets": { "0": { "title": "Пожарная часть" } - }, - "description": "Слой карты, отображающий пожарные части.", - "name": "Карта пожарных частей" + } }, "3": { + "name": "Карта станций скорой помощи", "title": { "render": "Станция скорой помощи" }, @@ -582,12 +595,12 @@ "question": "Как называется эта станция скорой помощи?", "render": "Эта станция называется {name}." }, + "1": { + "question": " По какому адресу расположена эта станция?", + "render": "Эта станция расположена вдоль шоссе {addr:street}." + }, "2": { "question": "Где расположена станция? (напр., название населённого пункта)" - }, - "1": { - "render": "Эта станция расположена вдоль шоссе {addr:street}.", - "question": " По какому адресу расположена эта станция?" } }, "presets": { @@ -595,14 +608,23 @@ "title": "Станция скорой помощи", "description": "Добавить станцию скорой помощи на карту" } - }, - "name": "Карта станций скорой помощи" + } } - }, - "shortDescription": "Карта пожарных гидрантов, огнетушителей, пожарных станций и станций скорой помощи.", - "title": "Пожарные гидранты, огнетушители, пожарные станции и станции скорой помощи." + } + }, + "maps": { + "title": "Карта карт" + }, + "personal": { + "description": "Создать персональную тему на основе доступных слоёв тем" + }, + "playgrounds": { + "title": "Игровые площадки", + "shortDescription": "Карта игровых площадок", + "description": "На этой карте можно найти игровые площадки и добавить дополнительную информацию" }, "shops": { + "title": "Открыть карту магазинов", "layers": { "0": { "name": "Магазин", @@ -617,11 +639,13 @@ } } }, + "description": "Магазин", "tagRenderings": { "1": { "question": "Как называется этот магазин?" }, "2": { + "question": "Что продаётся в этом магазине?", "mappings": { "1": { "then": "Супермаркет" @@ -635,8 +659,7 @@ "6": { "then": "Автосалон" } - }, - "question": "Что продаётся в этом магазине?" + } }, "3": { "render": "{phone}", @@ -660,11 +683,13 @@ "title": "Магазин", "description": "Добавить новый магазин" } - }, - "description": "Магазин" + } } - }, - "title": "Открыть карту магазинов" + } + }, + "sport_pitches": { + "title": "Спортивные площадки", + "shortDescription": "Карта, отображающая спортивные площадки" }, "toilets": { "title": "Открытая карта туалетов", @@ -672,32 +697,7 @@ }, "trees": { "title": "Деревья", - "description": "Нанесите все деревья на карту!", - "shortDescription": "Карта деревьев" - }, - "sport_pitches": { - "shortDescription": "Карта, отображающая спортивные площадки", - "title": "Спортивные площадки" - }, - "playgrounds": { - "description": "На этой карте можно найти игровые площадки и добавить дополнительную информацию", - "shortDescription": "Карта игровых площадок", - "title": "Игровые площадки" - }, - "personal": { - "description": "Создать персональную тему на основе доступных слоёв тем" - }, - "maps": { - "title": "Карта карт" - }, - "fietsstraten": { - "layers": { - "2": { - "title": { - "render": "Улица" - }, - "name": "Все улицы" - } - } + "shortDescription": "Карта деревьев", + "description": "Нанесите все деревья на карту!" } -} +} \ No newline at end of file diff --git a/scripts/generateTranslations.ts b/scripts/generateTranslations.ts index 492a669e9..9f957553e 100644 --- a/scripts/generateTranslations.ts +++ b/scripts/generateTranslations.ts @@ -212,6 +212,7 @@ function generateTranslationsObjectFrom(objects: { path: string, parsed: { id: s } function MergeTranslation(source: any, target: any, language: string, context: string = "") { + for (const key in source) { if (!source.hasOwnProperty(key)) { continue @@ -220,6 +221,9 @@ function MergeTranslation(source: any, target: any, language: string, context: s const targetV = target[key] if (typeof sourceV === "string") { if(targetV === undefined){ + if(typeof target === "string"){ + throw "Trying to merge a translation into a fixed string at "+context+" for key "+key; + } target[key] = source[key]; continue; } From 1d01238973b21a8f3cdff87a15754afee90efff7 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sun, 18 Jul 2021 18:20:52 +0200 Subject: [PATCH 18/26] Fix play forests in temporary speelplekken-layer --- .../speelplekken/speelplekken_temp.json | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/assets/themes/speelplekken/speelplekken_temp.json b/assets/themes/speelplekken/speelplekken_temp.json index f18fbbad1..d81c33b91 100644 --- a/assets/themes/speelplekken/speelplekken_temp.json +++ b/assets/themes/speelplekken/speelplekken_temp.json @@ -28,7 +28,7 @@ "builtin": "play_forest", "override": { "source": { - "geoJson": "https://pietervdvn.github.io/speelplekken_cache/speelplekken_{z}_{x}_{y}.geojson", + "geoJson": "https://pietervdvn.github.io/speelplekken_cache/speelplekken_{layer}_{z}_{x}_{y}.geojson", "geoJsonZoomLevel": 14, "isOsmCache": true }, @@ -235,21 +235,22 @@ "maxZoom": 16, "minNeededElements": 100 }, - "roamingRenderings": [ - { - "render": "Maakt deel uit van {_part_of_walking_routes}", - "condition": "_part_of_walking_routes~*" - }, - { - "render": "Een kinder-reportage vinden jullie hier", - "freeform": { - "key": "video", - "type": "url" - }, - "question": "Wat is de link naar de video-reportage?" - } - ], "overrideAll": { + "+tagRenderings":[ + { + "render": "Maakt deel uit van {_part_of_walking_routes}", + "condition": "_part_of_walking_routes~*" + }, + { + "render": "Een kinder-reportage vinden jullie hier", + "freeform": { + "key": "video", + "type": "url" + }, + "question": "Wat is de link naar de video-reportage?" + } + ], + "isShown": { "render": "yes", "mappings": [ From c6a4ad45e139ef9ba22c85019de0b8828e14094d Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sun, 18 Jul 2021 18:29:15 +0200 Subject: [PATCH 19/26] Fix update cache script --- scripts/ScriptUtils.ts | 3 ++- scripts/generateCache.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/ScriptUtils.ts b/scripts/ScriptUtils.ts index ccf230275..facf7f934 100644 --- a/scripts/ScriptUtils.ts +++ b/scripts/ScriptUtils.ts @@ -56,7 +56,8 @@ export default class ScriptUtils { const urlObj = new URL(url) https.get({ host: urlObj.host, - path: urlObj.pathname, + path: urlObj.pathname + urlObj.search, + port: urlObj.port, headers: { "accept": "application/json" diff --git a/scripts/generateCache.ts b/scripts/generateCache.ts index 77dfa8653..b106ff05f 100644 --- a/scripts/generateCache.ts +++ b/scripts/generateCache.ts @@ -93,7 +93,8 @@ async function downloadRaw(targetdir: string, r: TileRange, overpass: Overpass)/ } ) .catch(err => { - console.log("Could not download - probably hit the rate limit; waiting a bit") + console.log(url) + console.log("Could not download - probably hit the rate limit; waiting a bit. ("+err+")") failed++; return ScriptUtils.sleep(60000).then(() => console.log("Waiting is done")) }) From 1af57e6efef629a70b68509dab72fa8b11ce7bcd Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sun, 18 Jul 2021 18:31:42 +0200 Subject: [PATCH 20/26] Add question for private access --- .../speelplekken/speelplekken_temp.json | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/assets/themes/speelplekken/speelplekken_temp.json b/assets/themes/speelplekken/speelplekken_temp.json index d81c33b91..cf5eedfe5 100644 --- a/assets/themes/speelplekken/speelplekken_temp.json +++ b/assets/themes/speelplekken/speelplekken_temp.json @@ -105,19 +105,36 @@ { "builtin": "slow_roads", "override": { - "calculatedTags": [ - "_part_of_walking_routes=Array.from(new Set(feat.memberships().map(r => \"\" + r.relation.tags.name + \"\"))).join(', ')", - "_is_shadowed=feat.overlapWith('shadow').length > 0 ? 'yes': ''" - ], - "minzoom": 9, - "source": { - "geoJsonLocal": "http://127.0.0.1:8080/speelplekken_{layer}_{z}_{x}_{y}.geojson", - "geoJson": "https://pietervdvn.github.io/speelplekken_cache/speelplekken_{layer}_{z}_{x}_{y}.geojson", - "geoJsonZoomLevel": 14, - "isOsmCache": true + "+tagRenderings": { + "question": "Is dit een publiek toegankelijk pad?", + "mappings": [ + { + "if": "access=private", + "then": "Dit is een privaat pad" + }, + { + "if": "access=no", + "then": "Dit is een privaat pad", + "hideInAnswer": true + }, + { + "if": "access=permissive", + "then": "Dit pad is duidelijk in private eigendom, maar er hangen geen verbodsborden dus mag men erover" + } + ], + "calculatedTags": [ + "_part_of_walking_routes=Array.from(new Set(feat.memberships().map(r => \"\" + r.relation.tags.name + \"\"))).join(', ')", + "_is_shadowed=feat.overlapWith('shadow').length > 0 ? 'yes': ''" + ], + "minzoom": 18, + "source": { + "geoJsonLocal": "http://127.0.0.1:8080/speelplekken_{layer}_{z}_{x}_{y}.geojson", + "geoJson": "https://pietervdvn.github.io/speelplekken_cache/speelplekken_{layer}_{z}_{x}_{y}.geojson", + "geoJsonZoomLevel": 14, + "isOsmCache": true + } } - } - }, + }, { "id": "walking_routes", "name": { @@ -236,7 +253,7 @@ "minNeededElements": 100 }, "overrideAll": { - "+tagRenderings":[ + "+tagRenderings": [ { "render": "Maakt deel uit van {_part_of_walking_routes}", "condition": "_part_of_walking_routes~*" @@ -250,7 +267,6 @@ "question": "Wat is de link naar de video-reportage?" } ], - "isShown": { "render": "yes", "mappings": [ From ac7c3d837d63cab7e432239c083981313b9d6411 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sun, 18 Jul 2021 18:50:50 +0200 Subject: [PATCH 21/26] Fix typo in nl --- langs/shared-questions/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/langs/shared-questions/nl.json b/langs/shared-questions/nl.json index 201608c40..fd5a2a9b6 100644 --- a/langs/shared-questions/nl.json +++ b/langs/shared-questions/nl.json @@ -21,7 +21,7 @@ "render": "Bevindt zich op de {level}de verdieping", "mappings": { "0": { - "then": "Bevindt zich ondergrounds" + "then": "Bevindt zich ondergronds" }, "1": { "then": "Bevindt zich gelijkvloers" From 1815227fe678807b8ec1ac4c800ee6d6427b91f0 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sun, 18 Jul 2021 18:51:34 +0200 Subject: [PATCH 22/26] Dump result to console in case of an error --- scripts/ScriptUtils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/ScriptUtils.ts b/scripts/ScriptUtils.ts index facf7f934..174b1d3df 100644 --- a/scripts/ScriptUtils.ts +++ b/scripts/ScriptUtils.ts @@ -75,6 +75,7 @@ export default class ScriptUtils { try { resolve(JSON.parse(result)) } catch (e) { + console.error("Could not parse the following as JSON:", result) reject(e) } }); From 973cd7ada381a6b7cd2b4e9ab351a367694476aa Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sun, 18 Jul 2021 20:07:08 +0200 Subject: [PATCH 23/26] Fix speelplekken-temp --- .../speelplekken/speelplekken_temp.json | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/assets/themes/speelplekken/speelplekken_temp.json b/assets/themes/speelplekken/speelplekken_temp.json index cf5eedfe5..052c219ba 100644 --- a/assets/themes/speelplekken/speelplekken_temp.json +++ b/assets/themes/speelplekken/speelplekken_temp.json @@ -121,20 +121,21 @@ "if": "access=permissive", "then": "Dit pad is duidelijk in private eigendom, maar er hangen geen verbodsborden dus mag men erover" } - ], - "calculatedTags": [ - "_part_of_walking_routes=Array.from(new Set(feat.memberships().map(r => \"\" + r.relation.tags.name + \"\"))).join(', ')", - "_is_shadowed=feat.overlapWith('shadow').length > 0 ? 'yes': ''" - ], - "minzoom": 18, - "source": { - "geoJsonLocal": "http://127.0.0.1:8080/speelplekken_{layer}_{z}_{x}_{y}.geojson", - "geoJson": "https://pietervdvn.github.io/speelplekken_cache/speelplekken_{layer}_{z}_{x}_{y}.geojson", - "geoJsonZoomLevel": 14, - "isOsmCache": true - } + ] + }, + "calculatedTags": [ + "_part_of_walking_routes=Array.from(new Set(feat.memberships().map(r => \"\" + r.relation.tags.name + \"\"))).join(', ')", + "_is_shadowed=feat.overlapWith('shadow').length > 0 ? 'yes': ''" + ], + "minzoom": 18, + "source": { + "geoJsonLocal": "http://127.0.0.1:8080/speelplekken_{layer}_{z}_{x}_{y}.geojson", + "geoJson": "https://pietervdvn.github.io/speelplekken_cache/speelplekken_{layer}_{z}_{x}_{y}.geojson", + "geoJsonZoomLevel": 14, + "isOsmCache": true } - }, + } + }, { "id": "walking_routes", "name": { From 76fa147670a596c718ebaa5298513c6489ac6df3 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sun, 18 Jul 2021 20:16:28 +0200 Subject: [PATCH 24/26] Fix deployment (once more) --- assets/tagRenderings/questions.json | 2 +- .../speelplekken/speelplekken_temp.json | 38 ++++++++++--------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/assets/tagRenderings/questions.json b/assets/tagRenderings/questions.json index 3fabc4deb..66d034cdc 100644 --- a/assets/tagRenderings/questions.json +++ b/assets/tagRenderings/questions.json @@ -142,7 +142,7 @@ "if": "location=underground", "then": { "en": "Located underground", - "nl": "Bevindt zich ondergrounds" + "nl": "Bevindt zich ondergronds" }, "hideInAnswer": true }, diff --git a/assets/themes/speelplekken/speelplekken_temp.json b/assets/themes/speelplekken/speelplekken_temp.json index 052c219ba..bf3975dc3 100644 --- a/assets/themes/speelplekken/speelplekken_temp.json +++ b/assets/themes/speelplekken/speelplekken_temp.json @@ -105,24 +105,26 @@ { "builtin": "slow_roads", "override": { - "+tagRenderings": { - "question": "Is dit een publiek toegankelijk pad?", - "mappings": [ - { - "if": "access=private", - "then": "Dit is een privaat pad" - }, - { - "if": "access=no", - "then": "Dit is een privaat pad", - "hideInAnswer": true - }, - { - "if": "access=permissive", - "then": "Dit pad is duidelijk in private eigendom, maar er hangen geen verbodsborden dus mag men erover" - } - ] - }, + "+tagRenderings": [ + { + "question": "Is dit een publiek toegankelijk pad?", + "mappings": [ + { + "if": "access=private", + "then": "Dit is een privaat pad" + }, + { + "if": "access=no", + "then": "Dit is een privaat pad", + "hideInAnswer": true + }, + { + "if": "access=permissive", + "then": "Dit pad is duidelijk in private eigendom, maar er hangen geen verbodsborden dus mag men erover" + } + ] + } + ], "calculatedTags": [ "_part_of_walking_routes=Array.from(new Set(feat.memberships().map(r => \"\" + r.relation.tags.name + \"\"))).join(', ')", "_is_shadowed=feat.overlapWith('shadow').length > 0 ? 'yes': ''" From 186405784e789d230f83b22b5f35b21225376ce7 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sun, 18 Jul 2021 20:24:08 +0200 Subject: [PATCH 25/26] Add translation file --- langs/shared-questions/nl.json | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 langs/shared-questions/nl.json diff --git a/langs/shared-questions/nl.json b/langs/shared-questions/nl.json new file mode 100644 index 000000000..fd5a2a9b6 --- /dev/null +++ b/langs/shared-questions/nl.json @@ -0,0 +1,35 @@ +{ + "undefined": { + "phone": { + "question": "Wat is het telefoonnummer van {name}?" + }, + "email": { + "question": "Wat is het email-adres van {name}?" + }, + "website": { + "question": "Wat is de website van {name}?" + }, + "description": { + "question": "Zijn er extra zaken die je niet in de bovenstaande vragen kwijt kon? Zet deze in de descriptionHerhaal geen antwoorden die je reeds gaf" + }, + "opening_hours": { + "question": "Wat zijn de openingsuren van {name}?", + "render": "

Openingsuren

{opening_hours_table(opening_hours)}" + }, + "level": { + "question": "Op welke verdieping bevindt dit punt zich?", + "render": "Bevindt zich op de {level}de verdieping", + "mappings": { + "0": { + "then": "Bevindt zich ondergronds" + }, + "1": { + "then": "Bevindt zich gelijkvloers" + }, + "2": { + "then": "Bevindt zich op de eerste verdieping" + } + } + } + } +} \ No newline at end of file From 219895191d1ef3742961804a27f439a9d396dcc9 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sun, 18 Jul 2021 21:48:11 +0200 Subject: [PATCH 26/26] Disable adding new elements-popup if the userbadge is disabled; add small cosmetic changes --- Logic/Actors/StrayClickHandler.ts | 7 ++++++- State.ts | 6 ++++++ UI/ShowDataLayer.ts | 4 +++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Logic/Actors/StrayClickHandler.ts b/Logic/Actors/StrayClickHandler.ts index b4d630070..3e7609fd4 100644 --- a/Logic/Actors/StrayClickHandler.ts +++ b/Logic/Actors/StrayClickHandler.ts @@ -47,7 +47,12 @@ export default class StrayClickHandler { popupAnchor: [0, -45] }) }); - const popup = L.popup().setContent("
"); + const popup = L.popup({ + autoPan: true, + autoPanPaddingTopLeft: [15,15], + closeOnEscapeKey: true, + autoClose: true + }).setContent("
"); self._lastMarker.addTo(leafletMap.data); self._lastMarker.bindPopup(popup); diff --git a/State.ts b/State.ts index a5bad6706..418657266 100644 --- a/State.ts +++ b/State.ts @@ -193,6 +193,12 @@ export default class State { "Disables/Enables the layer control"); this.featureSwitchAddNew = featSw("fs-add-new", (layoutToUse) => layoutToUse?.enableAddNewPoints ?? true, "Disables/Enables the 'add new feature'-popup. (A theme without presets might not have it in the first place)"); + this.featureSwitchUserbadge.addCallbackAndRun(userbadge => { + if (!userbadge) { + this.featureSwitchAddNew.setData(false) + } + }) + this.featureSwitchWelcomeMessage = featSw("fs-welcome-message", () => true, "Disables/enables the help menu or welcome message"); this.featureSwitchIframe = featSw("fs-iframe", () => false, diff --git a/UI/ShowDataLayer.ts b/UI/ShowDataLayer.ts index df45af45e..59225640f 100644 --- a/UI/ShowDataLayer.ts +++ b/UI/ShowDataLayer.ts @@ -146,7 +146,9 @@ export default class ShowDataLayer { const popup = L.popup({ autoPan: true, closeOnEscapeKey: true, - closeButton: false + closeButton: false, + autoPanPaddingTopLeft: [15,15], + }, leafletLayer); leafletLayer.bindPopup(popup);