forked from MapComplete/MapComplete
		
	Merge branch 'master' into develop
This commit is contained in:
		
						commit
						34e7233498
					
				
					 19 changed files with 706 additions and 46 deletions
				
			
		
							
								
								
									
										4
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -49,3 +49,7 @@ error_changeset_* | ||||||
| public/*.webmanifest | public/*.webmanifest | ||||||
| public/assets/generated/ | public/assets/generated/ | ||||||
| public/assets/langs/* | public/assets/langs/* | ||||||
|  | 
 | ||||||
|  | android/ | ||||||
|  | dist-full/ | ||||||
|  | public/assets/icons/*.webp | ||||||
|  |  | ||||||
|  | @ -596,10 +596,33 @@ | ||||||
|             "seeNearby": "Bilder in der Nähe durchsuchen", |             "seeNearby": "Bilder in der Nähe durchsuchen", | ||||||
|             "title": "Straßenbilder in der Nähe" |             "title": "Straßenbilder in der Nähe" | ||||||
|         }, |         }, | ||||||
|  |         "panoramax": { | ||||||
|  |             "deletionRequested": "Der Bericht wurde abgeschickt. Ein Moderator wird sich in Kürze darum kümmern", | ||||||
|  |             "freeform": "Gibt es weitere relevante Informationen?", | ||||||
|  |             "otherFreeform": "Bitte gib an, warum dieses Bild entfernt werden soll:", | ||||||
|  |             "placeholder": "Erkläre, warum das Bild gelöscht werden sollte", | ||||||
|  |             "report": { | ||||||
|  |                 "blur_excess": "Zu viel ist unscharf und macht das Bild unbrauchbar", | ||||||
|  |                 "blur_missing": "Ein Gesicht oder Nummernschild ist auf diesem Bild nicht unscharf", | ||||||
|  |                 "copyright": "Das Bild enthält urheberrechtlich geschützte Inhalte", | ||||||
|  |                 "inappropriate": "Dieses Bild ist unangemessen (es enthält Nacktheit, ruft nach Hass oder ist nicht Streetview)", | ||||||
|  |                 "mislocated": "Das Bild ist von einem anderen Ort", | ||||||
|  |                 "other": "Ein weiterer Grund, bitte angeben", | ||||||
|  |                 "picture_low_quality": "Das Bild ist von geringer Qualität", | ||||||
|  |                 "privacy": "Das Bild zeigt eine private Immobilie" | ||||||
|  |             }, | ||||||
|  |             "requestDeletion": "Bildlöschung beantragen", | ||||||
|  |             "title": "Warum sollte dieses Bild dauerhaft gelöscht werden?" | ||||||
|  |         }, | ||||||
|         "pleaseLogin": "Bitte anmelden, um ein Bild hinzuzufügen", |         "pleaseLogin": "Bitte anmelden, um ein Bild hinzuzufügen", | ||||||
|         "processing": "Der Server verarbeitet das Bild", |         "processing": "Der Server verarbeitet das Bild", | ||||||
|         "respectPrivacy": "Laden Sie keine Bilder von Google Maps, Google Streetview oder anderen urheberrechtlich geschützten Quellen hoch.", |         "respectPrivacy": "Laden Sie keine Bilder von Google Maps, Google Streetview oder anderen urheberrechtlich geschützten Quellen hoch.", | ||||||
|         "toBig": "Ihr Bild ist mit {actual_size} zu groß. Die maximale Bildgröße ist {max_size}", |         "toBig": "Ihr Bild ist mit {actual_size} zu groß. Die maximale Bildgröße ist {max_size}", | ||||||
|  |         "unlink": { | ||||||
|  |             "button": "Bild entkoppeln", | ||||||
|  |             "explanation": "Wenn du die Verknüpfung dieses Bildes aufhebst, wird das Bild nicht mehr mit diesem Objekt angezeigt. Es wird aber weiterhin in den Nachbarschaftsbildern und möglicherweise in anderen Objekten angezeigt.", | ||||||
|  |             "title": "Dieses Bild entkoppeln?" | ||||||
|  |         }, | ||||||
|         "upload": { |         "upload": { | ||||||
|             "failReasons": "Keine Internetverbindung", |             "failReasons": "Keine Internetverbindung", | ||||||
|             "failReasonsAdvanced": "Alternativ dazu können Sie einstellen, dass Ihr Browser und Ihre Erweiterungen die APIs von Drittanbietern nicht blockieren.", |             "failReasonsAdvanced": "Alternativ dazu können Sie einstellen, dass Ihr Browser und Ihre Erweiterungen die APIs von Drittanbietern nicht blockieren.", | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								langs/el.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								langs/el.json
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | {} | ||||||
|  | @ -596,10 +596,33 @@ | ||||||
|             "seeNearby": "Ver imágenes cercanas", |             "seeNearby": "Ver imágenes cercanas", | ||||||
|             "title": "Imágenes a nivel calle cercanas" |             "title": "Imágenes a nivel calle cercanas" | ||||||
|         }, |         }, | ||||||
|  |         "panoramax": { | ||||||
|  |             "deletionRequested": "El informe ha sido enviado. Un moderador lo examinará en breve", | ||||||
|  |             "freeform": "¿Hay alguna otra información pertinente?", | ||||||
|  |             "otherFreeform": "Por favor, especifique por qué debe eliminarse esta imagen:", | ||||||
|  |             "placeholder": "Explicar por qué la imagen debe ser eliminada", | ||||||
|  |             "report": { | ||||||
|  |                 "blur_excess": "Demasiado borrosa, haciendo la imagen inútil", | ||||||
|  |                 "blur_missing": "Una cara o placa de matrícula no está borrosa en esta imagen", | ||||||
|  |                 "copyright": "La imagen contiene contenido protegido por derechos de autor", | ||||||
|  |                 "inappropriate": "Esta imagen es inapropiada (contiene desnudez, incita al odio o no es streetview)", | ||||||
|  |                 "mislocated": "La imagen es de una ubicación diferente", | ||||||
|  |                 "other": "Otra razón, por favor especifíquese", | ||||||
|  |                 "picture_low_quality": "La imagen es de baja calidad", | ||||||
|  |                 "privacy": "La imagen muestra una propiedad privada" | ||||||
|  |             }, | ||||||
|  |             "requestDeletion": "Solicitar la eliminación de una imagen", | ||||||
|  |             "title": "¿Por qué debería esta imagen ser eliminada permanentemente?" | ||||||
|  |         }, | ||||||
|         "pleaseLogin": "Por favor, inicia sesión para agregar una imagen", |         "pleaseLogin": "Por favor, inicia sesión para agregar una imagen", | ||||||
|         "processing": "El servidor está procesando tu imagen", |         "processing": "El servidor está procesando tu imagen", | ||||||
|         "respectPrivacy": "No subas imágenes de Google Maps, Google Street View u otras fuentes con derechos de autor.", |         "respectPrivacy": "No subas imágenes de Google Maps, Google Street View u otras fuentes con derechos de autor.", | ||||||
|         "toBig": "Tu imagen es demasiado grande, tiene {actual_size}. Por favor, usa imágenes de como máximo {max_size}", |         "toBig": "Tu imagen es demasiado grande, tiene {actual_size}. Por favor, usa imágenes de como máximo {max_size}", | ||||||
|  |         "unlink": { | ||||||
|  |             "button": "Desvincular imagen", | ||||||
|  |             "explanation": "Al desvincular esta imagen, esta imagen ya no se mostrará con este objeto. Todavía aparecerá en las imágenes cercanas y posiblemente otros objetos.", | ||||||
|  |             "title": "¿Desvincular esta imagen?" | ||||||
|  |         }, | ||||||
|         "upload": { |         "upload": { | ||||||
|             "failReasons": "Podrías haber perdido la conexión a internet", |             "failReasons": "Podrías haber perdido la conexión a internet", | ||||||
|             "failReasonsAdvanced": "Alternativamente, asegúrate de que tu navegador y extensiones no bloqueen las API de terceros.", |             "failReasonsAdvanced": "Alternativamente, asegúrate de que tu navegador y extensiones no bloqueen las API de terceros.", | ||||||
|  | @ -781,7 +804,7 @@ | ||||||
|         "title": "{count} reseñas", |         "title": "{count} reseñas", | ||||||
|         "title_singular": "Una reseña", |         "title_singular": "Una reseña", | ||||||
|         "too_long": "Se permiten como máximo {max} caracteres. Tu reseña tiene {amount} caracteres.", |         "too_long": "Se permiten como máximo {max} caracteres. Tu reseña tiene {amount} caracteres.", | ||||||
|         "tos": "Si creas una reseña, aceptas <a href='https://mangrove.reviews/terms' target='_blank'>los T&C y la política de privacidad de Mangrove.reviews</a>", |         "tos": "Si creas una revisión, aceptas <a href='https://mangrove.reviews/terms' target='_blank'>los TOS y la política de privacidad de Mangrove.reviews</a>", | ||||||
|         "write_a_comment": "Deja una reseña…", |         "write_a_comment": "Deja una reseña…", | ||||||
|         "your_reviews": "Tus reseñas anteriores", |         "your_reviews": "Tus reseñas anteriores", | ||||||
|         "your_reviews_empty": "No pudimos encontrar ninguna de tus reseñas anteriores" |         "your_reviews_empty": "No pudimos encontrar ninguna de tus reseñas anteriores" | ||||||
|  |  | ||||||
|  | @ -596,10 +596,33 @@ | ||||||
|             "seeNearby": "Közeli képek böngészése", |             "seeNearby": "Közeli képek böngészése", | ||||||
|             "title": "Közeli utcakép" |             "title": "Közeli utcakép" | ||||||
|         }, |         }, | ||||||
|  |         "panoramax": { | ||||||
|  |             "deletionRequested": "A jelentés be lett küldve; egy moderátor rövidesen megvizsgálja", | ||||||
|  |             "freeform": "Van-e további lényeges információ?", | ||||||
|  |             "otherFreeform": "Írd le, miért kellene eltávolítani ezt a képet:", | ||||||
|  |             "placeholder": "Fejtsd ki, miért kellene törölni ezt a képet", | ||||||
|  |             "report": { | ||||||
|  |                 "blur_excess": "A kép használhatatlan, mert túl nagy része homályos", | ||||||
|  |                 "blur_missing": "A képen nincs elhomályosítva egy arc vagy egy rendszámtábla", | ||||||
|  |                 "copyright": "A kép szerzői jog hatálya alá tartozó tartalmat jelenít meg", | ||||||
|  |                 "inappropriate": "A kép nem megfelelő (meztelenséget tartalmaz, gyűlöletre hív vagy nem utcakép)", | ||||||
|  |                 "mislocated": "A kép egy másik helyet ábrázol", | ||||||
|  |                 "other": "Más ok, kérjük, fejtsd ki", | ||||||
|  |                 "picture_low_quality": "A kép gyatra minőségű", | ||||||
|  |                 "privacy": "A kép magánterületet ábrázol" | ||||||
|  |             }, | ||||||
|  |             "requestDeletion": "Képtörlés kérése", | ||||||
|  |             "title": "Miért kellene ezt a képet véglegesen törölni?" | ||||||
|  |         }, | ||||||
|         "pleaseLogin": "Kép hozzáadásához be kell jelentkezni", |         "pleaseLogin": "Kép hozzáadásához be kell jelentkezni", | ||||||
|         "processing": "A szerver feldolgozza a képet", |         "processing": "A szerver feldolgozza a képet", | ||||||
|         "respectPrivacy": "Ne tölts fel képet a Google térképről, a Google Streetview-ról (utcaképről) és egyéb szerzői jog által védett forrásokból.", |         "respectPrivacy": "Ne tölts fel képet a Google térképről, a Google Streetview-ról (utcaképről) és egyéb szerzői jog által védett forrásokból.", | ||||||
|         "toBig": "A kép túl nagy ({actual_size}). Kérjük, legfeljebb {max_size} méretű képeket használj", |         "toBig": "A kép túl nagy ({actual_size}). Kérjük, legfeljebb {max_size} méretű képeket használj", | ||||||
|  |         "unlink": { | ||||||
|  |             "button": "Kép leválasztása", | ||||||
|  |             "explanation": "A kép belinkeltségének feloldásával ez a kép nem jelenik meg többé ezzel az objektummal együtt. A közeli képek között és esetleg más objektumokban azonban továbbra is meg fog jelenni.", | ||||||
|  |             "title": "Megszűnjék a kép belinkelése?" | ||||||
|  |         }, | ||||||
|         "upload": { |         "upload": { | ||||||
|             "failReasons": "Lehet, hogy megszakadt az internetkapcsolatod", |             "failReasons": "Lehet, hogy megszakadt az internetkapcsolatod", | ||||||
|             "failReasonsAdvanced": "Másik lehetőségként győződj meg arról, hogy a böngésződ vagy bővítményei nem blokkolnak-e harmadik féltől származó API-kat.", |             "failReasonsAdvanced": "Másik lehetőségként győződj meg arról, hogy a böngésződ vagy bővítményei nem blokkolnak-e harmadik féltől származó API-kat.", | ||||||
|  |  | ||||||
|  | @ -1492,6 +1492,17 @@ | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         "tagRenderings": { |         "tagRenderings": { | ||||||
|  |             "automated": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "0": { | ||||||
|  |                         "then": "Dies ist eine manuelle Fahrradwaschanlage" | ||||||
|  |                     }, | ||||||
|  |                     "1": { | ||||||
|  |                         "then": "Dies ist eine automatische Fahrradwaschanlage" | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 "question": "Ist dieser Fahrradreinigungsdienst automatisiert?" | ||||||
|  |             }, | ||||||
|             "bike_cleaning-charge": { |             "bike_cleaning-charge": { | ||||||
|                 "mappings": { |                 "mappings": { | ||||||
|                     "0": { |                     "0": { | ||||||
|  | @ -1515,6 +1526,17 @@ | ||||||
|                 }, |                 }, | ||||||
|                 "question": "Wie viel kostet die Nutzung des Reinigungsdienstes?", |                 "question": "Wie viel kostet die Nutzung des Reinigungsdienstes?", | ||||||
|                 "render": "Der Reinigungsservice kostet {service:bicycle:cleaning:charge}" |                 "render": "Der Reinigungsservice kostet {service:bicycle:cleaning:charge}" | ||||||
|  |             }, | ||||||
|  |             "self_service": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "0": { | ||||||
|  |                         "then": "Die Reinigung erfolgt selbständig" | ||||||
|  |                     }, | ||||||
|  |                     "1": { | ||||||
|  |                         "then": "Dieser Reinigungsdienst wird von einem Angestellten betrieben" | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 "question": "Muss die Reinigung selbständig erfolgen?" | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         "title": { |         "title": { | ||||||
|  | @ -3208,6 +3230,10 @@ | ||||||
|             "1": { |             "1": { | ||||||
|                 "description": "Eine öffentlich sichtbare Uhr an einer Wand", |                 "description": "Eine öffentlich sichtbare Uhr an einer Wand", | ||||||
|                 "title": "eine an der Wand montierte Uhr" |                 "title": "eine an der Wand montierte Uhr" | ||||||
|  |             }, | ||||||
|  |             "2": { | ||||||
|  |                 "description": "Eine öffentlich sichtbare Uhr, die direkt an einer Wand angebracht ist", | ||||||
|  |                 "title": "eine Wanduhr, die direkt an der Wand angebracht ist" | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         "tagRenderings": { |         "tagRenderings": { | ||||||
|  | @ -3288,13 +3314,29 @@ | ||||||
|                 }, |                 }, | ||||||
|                 "question": "Zeigt diese Uhr auch die Luftfeuchtigkeit an?" |                 "question": "Zeigt diese Uhr auch die Luftfeuchtigkeit an?" | ||||||
|             }, |             }, | ||||||
|  |             "indoor": { | ||||||
|  |                 "override": { | ||||||
|  |                     "mappings": { | ||||||
|  |                         "0": { | ||||||
|  |                             "then": "Diese Uhr befindet sich in Innenräumen" | ||||||
|  |                         }, | ||||||
|  |                         "1": { | ||||||
|  |                             "then": "Diese Uhr ist im Freien" | ||||||
|  |                         } | ||||||
|  |                     }, | ||||||
|  |                     "question": "Befindet sich diese Uhr in Innenräumen?" | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|             "support": { |             "support": { | ||||||
|                 "mappings": { |                 "mappings": { | ||||||
|                     "0": { |                     "0": { | ||||||
|                         "then": "Diese Uhr ist auf einem Mast montiert" |                         "then": "Diese Uhr ist auf einem Mast montiert" | ||||||
|                     }, |                     }, | ||||||
|                     "1": { |                     "1": { | ||||||
|                         "then": "Diese Uhr ist an einer Wand montiert" |                         "then": "Diese Uhr wird an der Wand befestigt, in der Regel durch einen Träger, der senkrecht zur Wand steht" | ||||||
|  |                     }, | ||||||
|  |                     "2": { | ||||||
|  |                         "then": "Diese Uhr ist direkt an einer Wand montiert" | ||||||
|                     }, |                     }, | ||||||
|                     "3": { |                     "3": { | ||||||
|                         "then": "Diese Uhr ist Teil einer Werbetafel" |                         "then": "Diese Uhr ist Teil einer Werbetafel" | ||||||
|  | @ -3493,6 +3535,57 @@ | ||||||
|                     } |                     } | ||||||
|                 }, |                 }, | ||||||
|                 "question": "Gibt die Ampel ein Vibrationssignal, um das Überqueren zu erleichtern? (in der Regel am unteren Ende der Ampeltaste)" |                 "question": "Gibt die Ampel ein Vibrationssignal, um das Überqueren zu erleichtern? (in der Regel am unteren Ende der Ampeltaste)" | ||||||
|  |             }, | ||||||
|  |             "markings": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "0": { | ||||||
|  |                         "then": "Diese Kreuzung hat keine Markierungen" | ||||||
|  |                     }, | ||||||
|  |                     "1": { | ||||||
|  |                         "then": "Dieser Übergang ist mit Zebrastreifen markiert" | ||||||
|  |                     }, | ||||||
|  |                     "10": { | ||||||
|  |                         "then": "Dieser Übergang hat Zebrastreifen in wechselnden Farben" | ||||||
|  |                     }, | ||||||
|  |                     "11": { | ||||||
|  |                         "then": "Dieser Übergang hat doppelte Zebrastreifen" | ||||||
|  |                     }, | ||||||
|  |                     "12": { | ||||||
|  |                         "then": "Diese Kreuzung hat Piktogramme auf der Straße" | ||||||
|  |                     }, | ||||||
|  |                     "13": { | ||||||
|  |                         "then": "Diese Kreuzung hat Linien auf beiden Seiten der Kreuzung und Balken, die sie verbinden, mit einer Unterbrechung in jedem Balken" | ||||||
|  |                     }, | ||||||
|  |                     "14": { | ||||||
|  |                         "then": "Dieser Übergang hat doppelte Linien auf beiden Seiten des Übergangs" | ||||||
|  |                     }, | ||||||
|  |                     "2": { | ||||||
|  |                         "then": "Dieser Übergang weist Markierungen unbekannter Art auf" | ||||||
|  |                     }, | ||||||
|  |                     "3": { | ||||||
|  |                         "then": "Dieser Übergang hat Linien auf beiden Seiten des Übergangs" | ||||||
|  |                     }, | ||||||
|  |                     "4": { | ||||||
|  |                         "then": "Diese Kreuzung hat Linien auf beiden Seiten der Kreuzung, zusammen mit Stangen, die sie verbinden" | ||||||
|  |                     }, | ||||||
|  |                     "5": { | ||||||
|  |                         "then": "Dieser Übergang hat gestrichelte Linien auf beiden Seiten des Übergangs" | ||||||
|  |                     }, | ||||||
|  |                     "6": { | ||||||
|  |                         "then": "Dieser Übergang hat gestrichelte Linien auf beiden Seiten des Übergangs" | ||||||
|  |                     }, | ||||||
|  |                     "7": { | ||||||
|  |                         "then": "Dieser Übergang wird durch eine andersfarbige Oberfläche gekennzeichnet" | ||||||
|  |                     }, | ||||||
|  |                     "8": { | ||||||
|  |                         "then": "Diese Kreuzung hat Linien auf beiden Seiten der Kreuzung, zusammen mit abgewinkelten Stangen, die sie verbinden" | ||||||
|  |                     }, | ||||||
|  |                     "9": { | ||||||
|  |                         "then": "Dieser Übergang hat Zebrastreifen mit einer Unterbrechung in jedem Balken" | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 "question": "Welche Art von Markierungen gibt es an diesem Übergang?", | ||||||
|  |                 "render": "Dieser Übergang hat {crossing:markings} Markierungen" | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         "title": { |         "title": { | ||||||
|  | @ -3908,6 +4001,57 @@ | ||||||
|             "render": "Weg" |             "render": "Weg" | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  |     "cyclist_waiting_aid": { | ||||||
|  |         "description": "Verschiedene Infrastruktureinrichtungen, die Radfahrern helfen, während sie an einer Ampel warten.", | ||||||
|  |         "name": "Radfahrer-Wartehilfen", | ||||||
|  |         "presets": { | ||||||
|  |             "0": { | ||||||
|  |                 "description": "Eine Fußstütze, ein Handlauf oder ein anderes Hilfsmittel zur Verbesserung des Komforts beim Warten an der Ampel", | ||||||
|  |                 "title": "eine Radfahrer-Wartehilfe" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "tagRenderings": { | ||||||
|  |             "direction": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "0": { | ||||||
|  |                         "then": "Diese Wartehilfe kann bei der Weiterfahrt auf diesem Weg genutzt werden" | ||||||
|  |                     }, | ||||||
|  |                     "1": { | ||||||
|  |                         "then": "Diese Wartehilfe kann beim Rückwärtsfahren auf diesem Weg benutzt werden" | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 "render": "Diese Wartehilfe kann in Fahrtrichtung {direction} benutzt werden" | ||||||
|  |             }, | ||||||
|  |             "side": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "0": { | ||||||
|  |                         "then": "Diese Wartehilfe befindet sich auf der linken Seite" | ||||||
|  |                     }, | ||||||
|  |                     "1": { | ||||||
|  |                         "then": "Diese Wartehilfe befindet sich auf der rechten Seite" | ||||||
|  |                     }, | ||||||
|  |                     "2": { | ||||||
|  |                         "then": "Auf beiden Seiten der Straße gibt es Wartehilfen" | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 "question": "Auf welcher Straßenseite befindet sich dies?" | ||||||
|  |             }, | ||||||
|  |             "type": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "0": { | ||||||
|  |                         "then": "Hier gibt es ein Brett oder einen Pflock zum Abstützen des Fußes" | ||||||
|  |                     }, | ||||||
|  |                     "1": { | ||||||
|  |                         "then": "Hier gibt es eine Schiene oder einen Griff zum Festhalten" | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 "question": "Aus welchen Bestandteilen besteht diese Wartehilfe?" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "title": { | ||||||
|  |             "render": "Radfahrer-Wartehilfe" | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|     "defibrillator": { |     "defibrillator": { | ||||||
|         "description": "Eine Ebene mit Defibrillatoren, die in Notfällen eingesetzt werden können. Diese Ebene enthält öffentliche Defibrillatoren, aber auch Defibrillatoren, bei denen möglicherweise Personal benötigt wird, um das Gerät zu holen", |         "description": "Eine Ebene mit Defibrillatoren, die in Notfällen eingesetzt werden können. Diese Ebene enthält öffentliche Defibrillatoren, aber auch Defibrillatoren, bei denen möglicherweise Personal benötigt wird, um das Gerät zu holen", | ||||||
|         "name": "Defibrillatoren", |         "name": "Defibrillatoren", | ||||||
|  | @ -7891,6 +8035,15 @@ | ||||||
|         "presets": { |         "presets": { | ||||||
|             "0": { |             "0": { | ||||||
|                 "title": "ein Briefkasten" |                 "title": "ein Briefkasten" | ||||||
|  |             }, | ||||||
|  |             "1": { | ||||||
|  |                 "title": "ein Briefkasten an einer Wand" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "tagRenderings": { | ||||||
|  |             "operator": { | ||||||
|  |                 "question": "Wer betreibt diesen Briefkasten?", | ||||||
|  |                 "render": "Dieser Briefkasten wird von <b>{operator}</b> betrieben" | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         "title": { |         "title": { | ||||||
|  | @ -8386,6 +8539,17 @@ | ||||||
|                 }, |                 }, | ||||||
|                 "question": "Verkauft das Geschäft glutenfreie Produkte?" |                 "question": "Verkauft das Geschäft glutenfreie Produkte?" | ||||||
|             }, |             }, | ||||||
|  |             "indoor": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "0": { | ||||||
|  |                         "then": "Dieses Objekt befindet sich in einem Innenraum" | ||||||
|  |                     }, | ||||||
|  |                     "1": { | ||||||
|  |                         "then": "Dieses Objekt befindet sich im Freien" | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 "question": "Befindet sich das Objekt in einem Innenraum?" | ||||||
|  |             }, | ||||||
|             "induction-loop": { |             "induction-loop": { | ||||||
|                 "mappings": { |                 "mappings": { | ||||||
|                     "0": { |                     "0": { | ||||||
|  | @ -10476,6 +10640,133 @@ | ||||||
|             "render": "Überwachungskamera" |             "render": "Überwachungskamera" | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  |     "tactile_map": { | ||||||
|  |         "description": "Ebene mit taktilen Karten, die von sehbehinderten Menschen zur Navigation in der Stadt verwendet werden können.", | ||||||
|  |         "name": "Taktile Karten", | ||||||
|  |         "presets": { | ||||||
|  |             "0": { | ||||||
|  |                 "description": "Eine taktile Karte, die durch Berühren gelesen werden kann. Im Gegensatz zu einem taktilen Modell ist diese Karte relativ flach und enthält keine dreidimensionalen Gebäude oder ähnliches.", | ||||||
|  |                 "title": "eine taktile Karte" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "tagRenderings": { | ||||||
|  |             "braille": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "0": { | ||||||
|  |                         "then": "Diese taktile Karte hat einen Text in Blindenschrift." | ||||||
|  |                     }, | ||||||
|  |                     "1": { | ||||||
|  |                         "then": "Diese taktile Karte hat keinen Text in Blindenschrift." | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 "question": "Gibt es einen Text in Blindenschrift auf dieser taktilen Karte?" | ||||||
|  |             }, | ||||||
|  |             "braille_languages": { | ||||||
|  |                 "render": { | ||||||
|  |                     "special": { | ||||||
|  |                         "question": "In welchen Sprachen ist der Text in Blindenschrift auf dieser taktilen Karte?", | ||||||
|  |                         "render_list_item": "Diese Karte hat Text in Blindenschrift in {language}", | ||||||
|  |                         "render_single_language": "Diese Karte hat Text in Blindenschrift in {language}" | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             "description": { | ||||||
|  |                 "freeform": { | ||||||
|  |                     "placeholder": "z.B. Taktile Karte des Stadtzentrums" | ||||||
|  |                 }, | ||||||
|  |                 "question": "Was zeigt diese taktile Karte?", | ||||||
|  |                 "render": "Beschreibung: {blind:description:en}." | ||||||
|  |             }, | ||||||
|  |             "embossed_letters": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "0": { | ||||||
|  |                         "then": "Diese taktile Karte hat geprägte Buchstaben." | ||||||
|  |                     }, | ||||||
|  |                     "1": { | ||||||
|  |                         "then": "Diese taktile Karte hat keine geprägten Buchstaben." | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 "question": "Gibt es auf dieser taktilen Karte geprägte Buchstaben?" | ||||||
|  |             }, | ||||||
|  |             "embossed_letters_languages": { | ||||||
|  |                 "render": { | ||||||
|  |                     "special": { | ||||||
|  |                         "question": "In welchen Sprachen sind die geprägten Buchstaben auf dieser taktilen Karte?", | ||||||
|  |                         "render_list_item": "Diese Karte hat geprägte Buchstaben in {language}", | ||||||
|  |                         "render_single_language": "Diese Karte hat geprägte Buchstaben in {language}" | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "title": "Taktile Karte" | ||||||
|  |     }, | ||||||
|  |     "tactile_model": { | ||||||
|  |         "description": "Ebene mit dreidimensionalen ertastbaren Modellen der Umgebung.", | ||||||
|  |         "name": "Taktile Modelle", | ||||||
|  |         "presets": { | ||||||
|  |             "0": { | ||||||
|  |                 "description": "Ein taktiles Modell ist ein dreidimensionales Modell eines Gebiets, das es den Menschen ermöglicht, ein Gebiet durch Berührung zu erkunden/sehen.", | ||||||
|  |                 "title": "ein taktiles Modell" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "tagRenderings": { | ||||||
|  |             "braille": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "0": { | ||||||
|  |                         "then": "Es gibt eine Beschreibung in Blindenschrift." | ||||||
|  |                     }, | ||||||
|  |                     "1": { | ||||||
|  |                         "then": "Es gibt keine Beschreibung in Blindenschrift." | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 "question": "Gibt es eine Beschreibung in Blindenschrift?" | ||||||
|  |             }, | ||||||
|  |             "braille_languages": { | ||||||
|  |                 "render": { | ||||||
|  |                     "special": { | ||||||
|  |                         "question": "In welchen Sprachen gibt es eine Beschreibung in Blindenschrift?", | ||||||
|  |                         "render_list_item": "Dieses Modell hat eine Beschreibung in Brailleschrift in {language()}", | ||||||
|  |                         "render_single_language": "Dieses Modell hat eine Beschreibung in Brailleschrift in {language}" | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             "description": { | ||||||
|  |                 "freeform": { | ||||||
|  |                     "placeholder": "z.B. Taktiles Modell des Stadtzentrums" | ||||||
|  |                 }, | ||||||
|  |                 "question": "Was zeigt dieses taktile Modell?", | ||||||
|  |                 "render": "Beschreibung: {blind:description:en}." | ||||||
|  |             }, | ||||||
|  |             "embossed_letters": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "0": { | ||||||
|  |                         "then": "Das Modell ist mit geprägten Buchstaben beschrieben." | ||||||
|  |                     }, | ||||||
|  |                     "1": { | ||||||
|  |                         "then": "Es gibt keine eingeprägten Buchstaben, die das Modell beschreiben." | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 "question": "Gibt es eingeprägte Buchstaben, die das Modell beschreiben?" | ||||||
|  |             }, | ||||||
|  |             "embossed_letters_languages": { | ||||||
|  |                 "render": { | ||||||
|  |                     "special": { | ||||||
|  |                         "question": "In welchen Sprachen gibt es geprägte Buchstaben?", | ||||||
|  |                         "render_list_item": "Dieses Modell hat geprägte Buchstaben in {language()}", | ||||||
|  |                         "render_single_language": "Dieses Modell hat geprägte Buchstaben in {language}" | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             "scale": { | ||||||
|  |                 "freeform": { | ||||||
|  |                     "placeholder": "z.B. 1:1000" | ||||||
|  |                 }, | ||||||
|  |                 "question": "Welchen Maßstab hat das Modell?", | ||||||
|  |                 "render": "Der Maßstab dieses Modells ist {scale}." | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "title": "Taktiles Modell" | ||||||
|  |     }, | ||||||
|     "tertiary_education": { |     "tertiary_education": { | ||||||
|         "name": "Hochschulen und Universitäten", |         "name": "Hochschulen und Universitäten", | ||||||
|         "presets": { |         "presets": { | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								langs/layers/el.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								langs/layers/el.json
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | {} | ||||||
|  | @ -3294,12 +3294,15 @@ | ||||||
|                         "then": "Este reloj está montado en un poste" |                         "then": "Este reloj está montado en un poste" | ||||||
|                     }, |                     }, | ||||||
|                     "1": { |                     "1": { | ||||||
|                         "then": "Este reloj está montado en una pared" |                         "then": "Este reloj está montado en una pared, generalmente a través de un soporte perpendicular a la pared" | ||||||
|                     }, |                     }, | ||||||
|                     "2": { |                     "2": { | ||||||
|                         "then": "Este reloj forma parte de una cartelera" |                         "then": "Este reloj está montado directamente en una pared" | ||||||
|                     }, |                     }, | ||||||
|                     "3": { |                     "3": { | ||||||
|  |                         "then": "Este reloj es parte de un cartel" | ||||||
|  |                     }, | ||||||
|  |                     "4": { | ||||||
|                         "then": "Este reloj está en el suelo" |                         "then": "Este reloj está en el suelo" | ||||||
|                     }, |                     }, | ||||||
|                     "4": { |                     "4": { | ||||||
|  |  | ||||||
|  | @ -291,6 +291,28 @@ | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  |     "assisted_repair": { | ||||||
|  |         "tagRenderings": { | ||||||
|  |             "item:repair": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "0": { | ||||||
|  |                         "then": "Тут ремонтують мобільні телефони" | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     "atm": { | ||||||
|  |         "tagRenderings": { | ||||||
|  |             "speech_output": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "0": { | ||||||
|  |                         "then": "Цей банкомат має мовний вихід, зазвичай доступний через роз'єм для навушників" | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|     "bench": { |     "bench": { | ||||||
|         "tagRenderings": { |         "tagRenderings": { | ||||||
|             "bench-armrest": { |             "bench-armrest": { | ||||||
|  | @ -468,7 +490,8 @@ | ||||||
|                 "question": "Яка електронна адреса оператора цієї велопарковки?" |                 "question": "Яка електронна адреса оператора цієї велопарковки?" | ||||||
|             }, |             }, | ||||||
|             "operator_phone": { |             "operator_phone": { | ||||||
|                 "question": "Який номер телефону оператора цієї велопарковки?" |                 "question": "Який номер телефону оператора цієї велопарковки?", | ||||||
|  |                 "questionHint": "За цим номером можна буде зателефонувати у разі виникнення проблем, наприклад, щоб прибрати недоглянуті велосипеди" | ||||||
|             }, |             }, | ||||||
|             "operator_website": { |             "operator_website": { | ||||||
|                 "question": "Яка адреса веб-сайту оператора цієї велопарковки?" |                 "question": "Яка адреса веб-сайту оператора цієї велопарковки?" | ||||||
|  | @ -587,7 +610,37 @@ | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|     "charging_station": { |     "charging_station": { | ||||||
|  |         "filter": { | ||||||
|  |             "2": { | ||||||
|  |                 "options": { | ||||||
|  |                     "14": { | ||||||
|  |                         "question": "Має <div style='display: inline-block'><b><b>USB</b> для зарядки телефонів і малої електроніки</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/usb_port.svg'/></div> роз'єм" | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|         "tagRenderings": { |         "tagRenderings": { | ||||||
|  |             "Auth phone": { | ||||||
|  |                 "question": "Який номер телефону для аутентифікаційного дзвінка або SMS?", | ||||||
|  |                 "render": "Авторизуйтесь, зателефонувавши або надіславши SMS на <a href='tel:{authentication:phone_call:number}'>{authentication:phone_call:number}</a>" | ||||||
|  |             }, | ||||||
|  |             "Authentication": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "2": { | ||||||
|  |                         "then": "Доступна автентифікація за допомогою телефонного дзвінка" | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             "Available_charging_stations (generated)": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "26": { | ||||||
|  |                         "then": "<b>USB</b> для зарядки телефонів і дрібної електроніки" | ||||||
|  |                     }, | ||||||
|  |                     "27": { | ||||||
|  |                         "then": "<b>USB</b> для зарядки телефонів і дрібної електроніки" | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|             "Network": { |             "Network": { | ||||||
|                 "mappings": { |                 "mappings": { | ||||||
|                     "0": { |                     "0": { | ||||||
|  | @ -605,6 +658,19 @@ | ||||||
|             }, |             }, | ||||||
|             "email": { |             "email": { | ||||||
|                 "question": "Яка електронна адреса оператора?" |                 "question": "Яка електронна адреса оператора?" | ||||||
|  |             }, | ||||||
|  |             "phone": { | ||||||
|  |                 "question": "За яким номером можна зателефонувати, якщо виникла проблема з цією зарядною станцією?", | ||||||
|  |                 "render": "У разі виникнення проблем телефонуйте <a href='tel:{phone}'>{phone}</a>" | ||||||
|  |             }, | ||||||
|  |             "rewritten-questions": { | ||||||
|  |                 "rewrite": { | ||||||
|  |                     "into": { | ||||||
|  |                         "13": { | ||||||
|  |                             "2": "<b>USB</b> для зарядки телефонів і дрібної електроніки" | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  | @ -644,6 +710,10 @@ | ||||||
|         "tagRenderings": { |         "tagRenderings": { | ||||||
|             "defibrillator-access": { |             "defibrillator-access": { | ||||||
|                 "render": "Доступ – {access}" |                 "render": "Доступ – {access}" | ||||||
|  |             }, | ||||||
|  |             "defibrillator-phone": { | ||||||
|  |                 "question": "Який номер телефону для запитань щодо цього дефібрилятора?", | ||||||
|  |                 "render": "Телефонуйте з питань щодо цього дефібрилятора: <a href='tel:{phone}'>{phone}</a>" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  | @ -896,6 +966,26 @@ | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  |     "icons": { | ||||||
|  |         "tagRenderings": { | ||||||
|  |             "phonelink": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "0": { | ||||||
|  |                         "then": { | ||||||
|  |                             "special": { | ||||||
|  |                                 "arialabel": "телефон" | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 "render": { | ||||||
|  |                     "special": { | ||||||
|  |                         "arialabel": "телефон" | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|     "indoors": { |     "indoors": { | ||||||
|         "tagRenderings": { |         "tagRenderings": { | ||||||
|             "name": { |             "name": { | ||||||
|  | @ -941,6 +1031,10 @@ | ||||||
|         "tagRenderings": { |         "tagRenderings": { | ||||||
|             "Access tag": { |             "Access tag": { | ||||||
|                 "render": "Доступ до цього природного заповідника: {access:description}" |                 "render": "Доступ до цього природного заповідника: {access:description}" | ||||||
|  |             }, | ||||||
|  |             "phone": { | ||||||
|  |                 "question": "За яким номером телефону можна звертатися з питаннями та проблемами, пов'язаними з цим заповідником?", | ||||||
|  |                 "questionHint": "Поважайте приватність - вказуйте особистий номер телефону лише в тому випадку, якщо він є загальнодоступним" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  | @ -981,7 +1075,8 @@ | ||||||
|                 "question": "Яка електронна адреса доглядача дитячого майданчика?" |                 "question": "Яка електронна адреса доглядача дитячого майданчика?" | ||||||
|             }, |             }, | ||||||
|             "playground-phone": { |             "playground-phone": { | ||||||
|                 "question": "Який номер телефону доглядача дитячого майданчика?" |                 "question": "Який номер телефону доглядача дитячого майданчика?", | ||||||
|  |                 "render": "<a href='tel:{phone}'>{phone}</a>" | ||||||
|             }, |             }, | ||||||
|             "playground-surface": { |             "playground-surface": { | ||||||
|                 "mappings": { |                 "mappings": { | ||||||
|  | @ -1073,6 +1168,9 @@ | ||||||
|                         "then": "Ця локація пропонує послуги для bpost" |                         "then": "Ця локація пропонує послуги для bpost" | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |             }, | ||||||
|  |             "post_offic_brand": { | ||||||
|  |                 "render": "Це поштове відділення {brand}" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  | @ -1151,7 +1249,43 @@ | ||||||
|                 "question": "Які години роботи {title()}?", |                 "question": "Які години роботи {title()}?", | ||||||
|                 "render": "<h3>Години роботи</h3>{opening_hours_table(opening_hours)}" |                 "render": "<h3>Години роботи</h3>{opening_hours_table(opening_hours)}" | ||||||
|             }, |             }, | ||||||
|  |             "opening_hours_24_7": { | ||||||
|  |                 "override": { | ||||||
|  |                     "+mappings": { | ||||||
|  |                         "0": { | ||||||
|  |                             "then": "Працює 24/7 (включаючи святкові дні)" | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             "payment-options": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "2": { | ||||||
|  |                         "then": "Оплата за допомогою QR-коду можлива тут" | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 "question": "Які способи оплати тут приймаються?" | ||||||
|  |             }, | ||||||
|  |             "payment-options-split": { | ||||||
|  |                 "override": { | ||||||
|  |                     "mappings+": { | ||||||
|  |                         "0": { | ||||||
|  |                             "then": "Монети приймаються тут" | ||||||
|  |                         }, | ||||||
|  |                         "1": { | ||||||
|  |                             "then": "Тут приймаються банкноти" | ||||||
|  |                         }, | ||||||
|  |                         "2": { | ||||||
|  |                             "then": "Тут приймаються дебетові картки" | ||||||
|  |                         }, | ||||||
|  |                         "3": { | ||||||
|  |                             "then": "Тут приймаються кредитні картки" | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|             "phone": { |             "phone": { | ||||||
|  |                 "editButtonAriaLabel": "Редагувати номер телефону", | ||||||
|                 "question": "Який номер телефону {title()}?" |                 "question": "Який номер телефону {title()}?" | ||||||
|             }, |             }, | ||||||
|             "qr_code": { |             "qr_code": { | ||||||
|  | @ -1886,18 +2020,137 @@ | ||||||
|     }, |     }, | ||||||
|     "vending_machine": { |     "vending_machine": { | ||||||
|         "tagRenderings": { |         "tagRenderings": { | ||||||
|  |             "indoor": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "1": { | ||||||
|  |                         "then": "Цей торговий автомат знаходиться в приміщенні" | ||||||
|  |                     }, | ||||||
|  |                     "2": { | ||||||
|  |                         "then": "Цей торговий автомат знаходиться на відкритому повітрі" | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 "question": "Цей торговий автомат знаходиться в приміщенні?" | ||||||
|  |             }, | ||||||
|             "operational_status": { |             "operational_status": { | ||||||
|                 "mappings": { |                 "mappings": { | ||||||
|  |                     "0": { | ||||||
|  |                         "then": "Цей торговий автомат працює" | ||||||
|  |                     }, | ||||||
|  |                     "1": { | ||||||
|  |                         "then": "Цей торговий автомат несправний" | ||||||
|  |                     }, | ||||||
|  |                     "2": { | ||||||
|  |                         "then": "Цей торговий автомат закрито" | ||||||
|  |                     }, | ||||||
|                     "3": { |                     "3": { | ||||||
|                         "then": "Робочий стан - це <i>{operational_status}</i>" |                         "then": "Робочий стан - це <i>{operational_status}</i>" | ||||||
|                     } |                     } | ||||||
|                 } |                 }, | ||||||
|  |                 "question": "Чи працює цей торговий автомат досі?" | ||||||
|  |             }, | ||||||
|  |             "operator": { | ||||||
|  |                 "question": "Хто керує цим автоматом?", | ||||||
|  |                 "render": "Цим торговим автоматом керує {operator}" | ||||||
|             }, |             }, | ||||||
|             "phone": { |             "phone": { | ||||||
|                 "override": { |                 "override": { | ||||||
|                     "question": "Який номер телефону оператора цього торгового автомата?" |                     "question": "Який номер телефону оператора цього торгового автомата?", | ||||||
|  |                     "questionHint": "Це номер, за яким ви можете зателефонувати у разі виникнення проблем з торговим автоматом" | ||||||
|                 } |                 } | ||||||
|  |             }, | ||||||
|  |             "vending": { | ||||||
|  |                 "mappings": { | ||||||
|  |                     "0": { | ||||||
|  |                         "then": "Напої" | ||||||
|  |                     }, | ||||||
|  |                     "1": { | ||||||
|  |                         "then": "Солодощі" | ||||||
|  |                     }, | ||||||
|  |                     "10": { | ||||||
|  |                         "then": "Хліб" | ||||||
|  |                     }, | ||||||
|  |                     "11": { | ||||||
|  |                         "then": "Яйця" | ||||||
|  |                     }, | ||||||
|  |                     "12": { | ||||||
|  |                         "then": "Морозиво" | ||||||
|  |                     }, | ||||||
|  |                     "13": { | ||||||
|  |                         "then": "Твердий сир" | ||||||
|  |                     }, | ||||||
|  |                     "14": { | ||||||
|  |                         "then": "Мед" | ||||||
|  |                     }, | ||||||
|  |                     "15": { | ||||||
|  |                         "then": "Картопля" | ||||||
|  |                     }, | ||||||
|  |                     "16": { | ||||||
|  |                         "then": "М'ясо" | ||||||
|  |                     }, | ||||||
|  |                     "17": { | ||||||
|  |                         "then": "Фрукти" | ||||||
|  |                     }, | ||||||
|  |                     "18": { | ||||||
|  |                         "then": "Полуниця" | ||||||
|  |                     }, | ||||||
|  |                     "19": { | ||||||
|  |                         "then": "Квіти" | ||||||
|  |                     }, | ||||||
|  |                     "2": { | ||||||
|  |                         "then": "Продукти харчування" | ||||||
|  |                     }, | ||||||
|  |                     "20": { | ||||||
|  |                         "then": "Паркувальні талони" | ||||||
|  |                     }, | ||||||
|  |                     "21": { | ||||||
|  |                         "then": "Пресовані монети" | ||||||
|  |                     }, | ||||||
|  |                     "22": { | ||||||
|  |                         "then": "Квитки на громадський транспорт" | ||||||
|  |                     }, | ||||||
|  |                     "23": { | ||||||
|  |                         "then": "Велосипедні ліхтарі" | ||||||
|  |                     }, | ||||||
|  |                     "24": { | ||||||
|  |                         "then": "Рукавички" | ||||||
|  |                     }, | ||||||
|  |                     "25": { | ||||||
|  |                         "then": "Набори для ремонту велосипедів" | ||||||
|  |                     }, | ||||||
|  |                     "26": { | ||||||
|  |                         "then": "Велосипедні насоси" | ||||||
|  |                     }, | ||||||
|  |                     "27": { | ||||||
|  |                         "then": "Велосипедні замки" | ||||||
|  |                     }, | ||||||
|  |                     "3": { | ||||||
|  |                         "then": "Сигарети" | ||||||
|  |                     }, | ||||||
|  |                     "4": { | ||||||
|  |                         "then": "Презервативи" | ||||||
|  |                     }, | ||||||
|  |                     "5": { | ||||||
|  |                         "then": "Кава" | ||||||
|  |                     }, | ||||||
|  |                     "6": { | ||||||
|  |                         "then": "Питна вода" | ||||||
|  |                     }, | ||||||
|  |                     "7": { | ||||||
|  |                         "then": "Газети" | ||||||
|  |                     }, | ||||||
|  |                     "8": { | ||||||
|  |                         "then": "Велосипедні внутрішні трубки" | ||||||
|  |                     }, | ||||||
|  |                     "9": { | ||||||
|  |                         "then": "Молоко" | ||||||
|                     } |                     } | ||||||
|  |                 }, | ||||||
|  |                 "question": "Що продає цей автомат?", | ||||||
|  |                 "render": "Цей торговий автомат продає {vending}" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "title": { | ||||||
|  |             "render": "Торговий автомат" | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|     "waste_disposal": { |     "waste_disposal": { | ||||||
|  |  | ||||||
|  | @ -1,9 +1,10 @@ | ||||||
| { | { | ||||||
|     "advanced": { |     "advanced": { | ||||||
|         "title": "Advanced features" |         "title": "高级功能" | ||||||
|     }, |     }, | ||||||
|     "centerMessage": { |     "centerMessage": { | ||||||
|         "allFilteredAway": "当前视图中没有满足过滤条件的要素" |         "allFilteredAway": "当前视图中没有满足过滤条件的要素", | ||||||
|  |         "loadingData": "加载数据…" | ||||||
|     }, |     }, | ||||||
|     "validation": { |     "validation": { | ||||||
|         "wikidata": { |         "wikidata": { | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								langs/themes/el.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								langs/themes/el.json
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | {} | ||||||
|  | @ -49,14 +49,15 @@ export default class OverpassFeatureSource implements UpdatableFeatureSource { | ||||||
|         }, |         }, | ||||||
|         options?: { |         options?: { | ||||||
|             padToTiles?: Store<number> |             padToTiles?: Store<number> | ||||||
|             isActive?: Store<boolean> |             isActive?: Store<boolean>, | ||||||
|  |             ignoreZoom?: boolean | ||||||
|         } |         } | ||||||
|     ) { |     ) { | ||||||
|         this.state = state |         this.state = state | ||||||
|         this._isActive = options?.isActive ?? new ImmutableStore(true) |         this._isActive = options?.isActive ?? new ImmutableStore(true) | ||||||
|         this.padToZoomLevel = options?.padToTiles |         this.padToZoomLevel = options?.padToTiles | ||||||
|         const self = this |         const self = this | ||||||
|         this._layersToDownload = state.zoom.map((zoom) => this.layersToDownload(zoom)) |         this._layersToDownload = options?.ignoreZoom? new ImmutableStore(state.layers) : state.zoom.map((zoom) => this.layersToDownload(zoom)) | ||||||
| 
 | 
 | ||||||
|         state.bounds.mapD( |         state.bounds.mapD( | ||||||
|             (_) => { |             (_) => { | ||||||
|  | @ -103,7 +104,7 @@ export default class OverpassFeatureSource implements UpdatableFeatureSource { | ||||||
|      * Download the relevant data from overpass. Attempt to use a different server if one fails; only downloads the relevant layers |      * Download the relevant data from overpass. Attempt to use a different server if one fails; only downloads the relevant layers | ||||||
|      * @private |      * @private | ||||||
|      */ |      */ | ||||||
|     public async updateAsync(): Promise<void> { |     public async updateAsync(overrideBounds?: BBox): Promise<void> { | ||||||
|         let data: any = undefined |         let data: any = undefined | ||||||
|         let lastUsed = 0 |         let lastUsed = 0 | ||||||
|         const start = new Date() |         const start = new Date() | ||||||
|  | @ -122,7 +123,7 @@ export default class OverpassFeatureSource implements UpdatableFeatureSource { | ||||||
|         let bounds: BBox |         let bounds: BBox | ||||||
|         do { |         do { | ||||||
|             try { |             try { | ||||||
|                 bounds = this.state.bounds.data |                 bounds = overrideBounds ?? this.state.bounds.data | ||||||
|                     ?.pad(this.state.widenFactor) |                     ?.pad(this.state.widenFactor) | ||||||
|                     ?.expandToTileBounds(this.padToZoomLevel?.data) |                     ?.expandToTileBounds(this.padToZoomLevel?.data) | ||||||
|                 if (!bounds) { |                 if (!bounds) { | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ import { FeatureSource, UpdatableFeatureSource } from "../FeatureSource" | ||||||
| import { Or } from "../../Tags/Or" | import { Or } from "../../Tags/Or" | ||||||
| import FeatureSwitchState from "../../State/FeatureSwitchState" | import FeatureSwitchState from "../../State/FeatureSwitchState" | ||||||
| import OverpassFeatureSource from "./OverpassFeatureSource" | import OverpassFeatureSource from "./OverpassFeatureSource" | ||||||
| import { Store, UIEventSource } from "../../UIEventSource" | import { ImmutableStore, Store, UIEventSource } from "../../UIEventSource" | ||||||
| import OsmFeatureSource from "./OsmFeatureSource" | import OsmFeatureSource from "./OsmFeatureSource" | ||||||
| import DynamicGeoJsonTileSource from "../TiledFeatureSource/DynamicGeoJsonTileSource" | import DynamicGeoJsonTileSource from "../TiledFeatureSource/DynamicGeoJsonTileSource" | ||||||
| import { BBox } from "../../BBox" | import { BBox } from "../../BBox" | ||||||
|  | @ -28,6 +28,13 @@ export default class ThemeSource extends FeatureSourceMerger { | ||||||
| 
 | 
 | ||||||
|     public static readonly fromCacheZoomLevel = 15 |     public static readonly fromCacheZoomLevel = 15 | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * This source is _only_ triggered when the data is downloaded for CSV export | ||||||
|  |      * @private | ||||||
|  |      */ | ||||||
|  |     private readonly _downloadAll: OverpassFeatureSource | ||||||
|  |     private readonly _mapBounds: Store<BBox> | ||||||
|  | 
 | ||||||
|     constructor( |     constructor( | ||||||
|         layers: LayerConfig[], |         layers: LayerConfig[], | ||||||
|         featureSwitches: FeatureSwitchState, |         featureSwitches: FeatureSwitchState, | ||||||
|  | @ -35,7 +42,7 @@ export default class ThemeSource extends FeatureSourceMerger { | ||||||
|         backend: string, |         backend: string, | ||||||
|         isDisplayed: (id: string) => Store<boolean>, |         isDisplayed: (id: string) => Store<boolean>, | ||||||
|         mvtAvailableLayers: Set<string>, |         mvtAvailableLayers: Set<string>, | ||||||
|         fullNodeDatabaseSource?: FullNodeDatabaseSource |         fullNodeDatabaseSource?: FullNodeDatabaseSource, | ||||||
|     ) { |     ) { | ||||||
|         const supportsForceDownload: UpdatableFeatureSource[] = [] |         const supportsForceDownload: UpdatableFeatureSource[] = [] | ||||||
| 
 | 
 | ||||||
|  | @ -56,7 +63,7 @@ export default class ThemeSource extends FeatureSourceMerger { | ||||||
|                     { |                     { | ||||||
|                         isActive: isDisplayed(layer.id), |                         isActive: isDisplayed(layer.id), | ||||||
|                         maxAge: layer.maxAgeOfCache, |                         maxAge: layer.maxAgeOfCache, | ||||||
|                     } |                     }, | ||||||
|                 ) |                 ) | ||||||
|                 fromCache.set(layer.id, src) |                 fromCache.set(layer.id, src) | ||||||
|             } |             } | ||||||
|  | @ -75,7 +82,7 @@ export default class ThemeSource extends FeatureSourceMerger { | ||||||
|             zoom, |             zoom, | ||||||
|             backend, |             backend, | ||||||
|             featureSwitches, |             featureSwitches, | ||||||
|             fullNodeDatabaseSource |             fullNodeDatabaseSource, | ||||||
|         ) |         ) | ||||||
|         nonMvtSources.push(osmApiSource) |         nonMvtSources.push(osmApiSource) | ||||||
| 
 | 
 | ||||||
|  | @ -84,13 +91,14 @@ export default class ThemeSource extends FeatureSourceMerger { | ||||||
|             console.log( |             console.log( | ||||||
|                 "Layers ", |                 "Layers ", | ||||||
|                 nonMvtLayers.map((l) => l.id), |                 nonMvtLayers.map((l) => l.id), | ||||||
|                 " cannot be fetched from the cache server, defaulting to overpass/OSM-api" |                 " cannot be fetched from the cache server, defaulting to overpass/OSM-api", | ||||||
|             ) |             ) | ||||||
|             overpassSource = ThemeSource.setupOverpass(osmLayers, bounds, zoom, featureSwitches) |             overpassSource = ThemeSource.setupOverpass(osmLayers, bounds, zoom, featureSwitches) | ||||||
|             nonMvtSources.push(overpassSource) |             nonMvtSources.push(overpassSource) | ||||||
|             supportsForceDownload.push(overpassSource) |             supportsForceDownload.push(overpassSource) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|         function setIsLoading() { |         function setIsLoading() { | ||||||
|             const loading = overpassSource?.runningQuery?.data || osmApiSource?.isRunning?.data |             const loading = overpassSource?.runningQuery?.data || osmApiSource?.isRunning?.data | ||||||
|             isLoading.setData(loading) |             isLoading.setData(loading) | ||||||
|  | @ -100,21 +108,40 @@ export default class ThemeSource extends FeatureSourceMerger { | ||||||
|         osmApiSource?.isRunning?.addCallbackAndRun(() => setIsLoading()) |         osmApiSource?.isRunning?.addCallbackAndRun(() => setIsLoading()) | ||||||
| 
 | 
 | ||||||
|         const geojsonSources: UpdatableFeatureSource[] = geojsonlayers.map((l) => |         const geojsonSources: UpdatableFeatureSource[] = geojsonlayers.map((l) => | ||||||
|             ThemeSource.setupGeojsonSource(l, mapProperties, isDisplayed(l.id)) |             ThemeSource.setupGeojsonSource(l, mapProperties, isDisplayed(l.id)), | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         super(...geojsonSources, ...Array.from(fromCache.values()), ...mvtSources, ...nonMvtSources) |         const downloadAllBounds: UIEventSource<BBox> = new UIEventSource<BBox>(undefined) | ||||||
|  |        const downloadAll=  new OverpassFeatureSource({ | ||||||
|  |             layers: layers.filter(l => l.isNormal()), | ||||||
|  |             bounds: mapProperties.bounds, | ||||||
|  |             zoom: mapProperties.zoom, | ||||||
|  |             overpassUrl: featureSwitches.overpassUrl, | ||||||
|  |             overpassTimeout: featureSwitches.overpassTimeout, | ||||||
|  |             overpassMaxZoom: new ImmutableStore(99), | ||||||
|  |             widenFactor: 0, | ||||||
|  |         },{ | ||||||
|  |           ignoreZoom: true | ||||||
|  |       }) | ||||||
|  | 
 | ||||||
|  |         super(...geojsonSources, ...Array.from(fromCache.values()), ...mvtSources, ...nonMvtSources, downloadAll) | ||||||
| 
 | 
 | ||||||
|         this.isLoading = isLoading |         this.isLoading = isLoading | ||||||
|         supportsForceDownload.push(...geojsonSources) |         supportsForceDownload.push(...geojsonSources) | ||||||
|         supportsForceDownload.push(...mvtSources) // Non-mvt sources are handled by overpass
 |         supportsForceDownload.push(...mvtSources) // Non-mvt sources are handled by overpass
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         this._mapBounds = mapProperties.bounds | ||||||
|  |         this._downloadAll = downloadAll | ||||||
|  | 
 | ||||||
|         this.supportsForceDownload = supportsForceDownload |         this.supportsForceDownload = supportsForceDownload | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static setupMvtSource( |     private static setupMvtSource( | ||||||
|         layer: LayerConfig, |         layer: LayerConfig, | ||||||
|         mapProperties: { zoom: Store<number>; bounds: Store<BBox> }, |         mapProperties: { zoom: Store<number>; bounds: Store<BBox> }, | ||||||
|         isActive?: Store<boolean> |         isActive?: Store<boolean>, | ||||||
|     ): UpdatableFeatureSource { |     ): UpdatableFeatureSource { | ||||||
|         return new DynamicMvtileSource(layer, mapProperties, { isActive }) |         return new DynamicMvtileSource(layer, mapProperties, { isActive }) | ||||||
|     } |     } | ||||||
|  | @ -122,12 +149,12 @@ export default class ThemeSource extends FeatureSourceMerger { | ||||||
|     private static setupGeojsonSource( |     private static setupGeojsonSource( | ||||||
|         layer: LayerConfig, |         layer: LayerConfig, | ||||||
|         mapProperties: { zoom: Store<number>; bounds: Store<BBox> }, |         mapProperties: { zoom: Store<number>; bounds: Store<BBox> }, | ||||||
|         isActiveByFilter?: Store<boolean> |         isActiveByFilter?: Store<boolean>, | ||||||
|     ): UpdatableFeatureSource { |     ): UpdatableFeatureSource { | ||||||
|         const source = layer.source |         const source = layer.source | ||||||
|         const isActive = mapProperties.zoom.map( |         const isActive = mapProperties.zoom.map( | ||||||
|             (z) => (isActiveByFilter?.data ?? true) && z >= layer.minzoom, |             (z) => (isActiveByFilter?.data ?? true) && z >= layer.minzoom, | ||||||
|             [isActiveByFilter] |             [isActiveByFilter], | ||||||
|         ) |         ) | ||||||
|         if (source.geojsonZoomLevel === undefined) { |         if (source.geojsonZoomLevel === undefined) { | ||||||
|             // This is a 'load everything at once' geojson layer
 |             // This is a 'load everything at once' geojson layer
 | ||||||
|  | @ -143,7 +170,7 @@ export default class ThemeSource extends FeatureSourceMerger { | ||||||
|         zoom: Store<number>, |         zoom: Store<number>, | ||||||
|         backend: string, |         backend: string, | ||||||
|         featureSwitches: FeatureSwitchState, |         featureSwitches: FeatureSwitchState, | ||||||
|         fullNodeDatabase: FullNodeDatabaseSource |         fullNodeDatabase: FullNodeDatabaseSource, | ||||||
|     ): OsmFeatureSource | undefined { |     ): OsmFeatureSource | undefined { | ||||||
|         if (osmLayers.length == 0) { |         if (osmLayers.length == 0) { | ||||||
|             return undefined |             return undefined | ||||||
|  | @ -177,7 +204,7 @@ export default class ThemeSource extends FeatureSourceMerger { | ||||||
|         osmLayers: LayerConfig[], |         osmLayers: LayerConfig[], | ||||||
|         bounds: Store<BBox>, |         bounds: Store<BBox>, | ||||||
|         zoom: Store<number>, |         zoom: Store<number>, | ||||||
|         featureSwitches: FeatureSwitchState |         featureSwitches: FeatureSwitchState, | ||||||
|     ): OverpassFeatureSource | undefined { |     ): OverpassFeatureSource | undefined { | ||||||
|         if (osmLayers.length == 0) { |         if (osmLayers.length == 0) { | ||||||
|             return undefined |             return undefined | ||||||
|  | @ -206,13 +233,14 @@ export default class ThemeSource extends FeatureSourceMerger { | ||||||
|             { |             { | ||||||
|                 padToTiles: zoom.map((zoom) => Math.min(15, zoom + 1)), |                 padToTiles: zoom.map((zoom) => Math.min(15, zoom + 1)), | ||||||
|                 isActive, |                 isActive, | ||||||
|             } |             }, | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public async downloadAll() { |     public async downloadAll() { | ||||||
|         console.log("Downloading all data") |         console.log("Downloading all data:") | ||||||
|         await Promise.all(this.supportsForceDownload.map((i) => i.updateAsync())) |         await this._downloadAll.updateAsync(this._mapBounds.data) | ||||||
|  |        // await Promise.all(this.supportsForceDownload.map((i) => i.updateAsync()))
 | ||||||
|         console.log("Done") |         console.log("Done") | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -371,6 +371,10 @@ export default class LinkedDataLoader { | ||||||
|             const match = maxstay.match(/P([0-9]+)D/) |             const match = maxstay.match(/P([0-9]+)D/) | ||||||
|             if (match) { |             if (match) { | ||||||
|                 const days = Number(match[1]) |                 const days = Number(match[1]) | ||||||
|  |                 if(days === 30){ | ||||||
|  |                     // 30 is the default which is set if velopark didn't know the actual value
 | ||||||
|  |                     return undefined | ||||||
|  |                 } | ||||||
|                 if (days === 1) { |                 if (days === 1) { | ||||||
|                     return "1 day" |                     return "1 day" | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  | @ -17,7 +17,7 @@ export default class VeloparkLoader { | ||||||
| 
 | 
 | ||||||
|     private static readonly coder = new CountryCoder( |     private static readonly coder = new CountryCoder( | ||||||
|         Constants.countryCoderEndpoint, |         Constants.countryCoderEndpoint, | ||||||
|         Utils.downloadJson |         Utils.downloadJson, | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     public static convert(veloparkData: VeloparkData): Feature { |     public static convert(veloparkData: VeloparkData): Feature { | ||||||
|  | @ -46,14 +46,14 @@ export default class VeloparkLoader { | ||||||
| 
 | 
 | ||||||
|         if (veloparkData.contactPoint?.email) { |         if (veloparkData.contactPoint?.email) { | ||||||
|             properties["operator:email"] = VeloparkLoader.emailReformatting.reformat( |             properties["operator:email"] = VeloparkLoader.emailReformatting.reformat( | ||||||
|                 veloparkData.contactPoint?.email |                 veloparkData.contactPoint?.email, | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (veloparkData.contactPoint?.telephone) { |         if (veloparkData.contactPoint?.telephone) { | ||||||
|             properties["operator:phone"] = VeloparkLoader.phoneValidator.reformat( |             properties["operator:phone"] = VeloparkLoader.phoneValidator.reformat( | ||||||
|                 veloparkData.contactPoint?.telephone, |                 veloparkData.contactPoint?.telephone, | ||||||
|                 () => "be" |                 () => "be", | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -78,10 +78,13 @@ export default class VeloparkLoader { | ||||||
|             ) { |             ) { | ||||||
|                 const duration = g.maximumParkingDuration.substring( |                 const duration = g.maximumParkingDuration.substring( | ||||||
|                     1, |                     1, | ||||||
|                     g.maximumParkingDuration.length - 1 |                     g.maximumParkingDuration.length - 1, | ||||||
|                 ) |                 ) | ||||||
|  |                 if (duration !== "30") { | ||||||
|  |                     // We don't set maxstay if it is 30, they are the default value that velopark chose for "unknown"
 | ||||||
|                     properties.maxstay = duration + " days" |                     properties.maxstay = duration + " days" | ||||||
|                 } |                 } | ||||||
|  |             } | ||||||
|             properties.access = g.publicAccess ?? "yes" ? "yes" : "no" |             properties.access = g.publicAccess ?? "yes" ? "yes" : "no" | ||||||
|             const prefix = "http://schema.org/" |             const prefix = "http://schema.org/" | ||||||
|             if (g.openingHoursSpecification) { |             if (g.openingHoursSpecification) { | ||||||
|  | @ -94,11 +97,11 @@ export default class VeloparkLoader { | ||||||
|                             const startHour = spec.opens |                             const startHour = spec.opens | ||||||
|                             const endHour = spec.closes === "23:59" ? "24:00" : spec.closes |                             const endHour = spec.closes === "23:59" ? "24:00" : spec.closes | ||||||
|                             const merged = OH.MergeTimes( |                             const merged = OH.MergeTimes( | ||||||
|                                 OH.ParseRule(dayOfWeek + " " + startHour + "-" + endHour) |                                 OH.ParseRule(dayOfWeek + " " + startHour + "-" + endHour), | ||||||
|                             ) |                             ) | ||||||
|                             return OH.ToString(merged) |                             return OH.ToString(merged) | ||||||
|                         }) |                         }) | ||||||
|                         .join("; ") |                         .join("; "), | ||||||
|                 ) |                 ) | ||||||
|                 properties.opening_hours = oh |                 properties.opening_hours = oh | ||||||
|             } |             } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue