diff --git a/babel.cfg b/babel.cfg new file mode 100644 index 000000000..de88eeba2 --- /dev/null +++ b/babel.cfg @@ -0,0 +1,8 @@ +[extractors] +yaml = ohsome_quality_api.utils:pybabel_yaml_extractor + +[python: **.py] + +[yaml: **.yaml] +keys = name,description,red,yellow,green,undefined,result_description +encoding = utf-8 diff --git a/docs/i18n.md b/docs/i18n.md new file mode 100644 index 000000000..d2cc83fcb --- /dev/null +++ b/docs/i18n.md @@ -0,0 +1,17 @@ +# Internationalization (I18N) and Localization (I10N) + +## Babel + +Add a new locale: +```bash +poetry run pybabel extract -F babel.cfg -o messages.pot . +pybabel init -i messages.pot -d ohsome_quality_api/locale -l de +pybabel compile -d ohsome_quality_api/locale +``` + +Update a existing locale: +```bash +poetry run pybabel extract -F babel.cfg -o messages.pot . +pybabel update -i messages.pot -d ohsome_quality_api/locale +pybabel compile -d ohsome_quality_api/locale +``` diff --git a/ohsome_quality_api/api/api.py b/ohsome_quality_api/api/api.py index 2f5494a4d..a6c8f171e 100644 --- a/ohsome_quality_api/api/api.py +++ b/ohsome_quality_api/api/api.py @@ -3,7 +3,7 @@ import os from typing import Any, Union -from fastapi import FastAPI, HTTPException, Request, status +from fastapi import Depends, FastAPI, HTTPException, Request, status from fastapi.encoders import jsonable_encoder from fastapi.exceptions import RequestValidationError from fastapi.middleware.cors import CORSMiddleware @@ -13,6 +13,7 @@ get_swagger_ui_oauth2_redirect_html, ) from fastapi.responses import JSONResponse +from fastapi_i18n import i18n from geojson import FeatureCollection from starlette.exceptions import HTTPException as StarletteHTTPException from starlette.staticfiles import StaticFiles @@ -114,6 +115,7 @@ openapi_tags=TAGS_METADATA, docs_url=None, redoc_url=None, + dependencies=[Depends(i18n)], ) app.add_middleware( diff --git a/ohsome_quality_api/indicators/attribute_completeness/indicator.py b/ohsome_quality_api/indicators/attribute_completeness/indicator.py index 2decf9d55..cccb47a02 100644 --- a/ohsome_quality_api/indicators/attribute_completeness/indicator.py +++ b/ohsome_quality_api/indicators/attribute_completeness/indicator.py @@ -98,17 +98,17 @@ def calculate(self) -> None: if self.result.value >= self.threshold_yellow: self.result.class_ = 5 self.result.description = ( - self.description + self.templates.label_description["green"] + self.description + self.templates.label_description.green ) elif self.threshold_yellow > self.result.value >= self.threshold_red: self.result.class_ = 3 self.result.description = ( - self.description + self.templates.label_description["yellow"] + self.description + self.templates.label_description.yellow ) else: self.result.class_ = 1 self.result.description = ( - self.description + self.templates.label_description["red"] + self.description + self.templates.label_description.red ) def create_description(self): diff --git a/ohsome_quality_api/indicators/base.py b/ohsome_quality_api/indicators/base.py index 03505bcfb..5a144771b 100644 --- a/ohsome_quality_api/indicators/base.py +++ b/ohsome_quality_api/indicators/base.py @@ -37,7 +37,7 @@ def __init__( self.topic: Topic = topic self.feature: Feature = feature self.result: Result = Result( - description=self.templates.label_description["undefined"], + description=self.templates.label_description.undefined ) self._get_default_figure() diff --git a/ohsome_quality_api/indicators/building_comparison/indicator.py b/ohsome_quality_api/indicators/building_comparison/indicator.py index 6cf5be9b1..87b66bb1c 100644 --- a/ohsome_quality_api/indicators/building_comparison/indicator.py +++ b/ohsome_quality_api/indicators/building_comparison/indicator.py @@ -130,13 +130,19 @@ def calculate(self) -> None: self.result.class_ = 3 elif self.th_low > self.result.value >= 0: self.result.class_ = 1 - label_description = self.templates.label_description[self.result.label] + label_description = getattr( + self.templates.label_description, self.result.label + ) self.result.description = " ".join((label_description, result_description)) elif major_edge_case: - label_description = self.templates.label_description[self.result.label] + label_description = getattr( + self.templates.label_description, self.result.label + ) self.result.description = " ".join((label_description, result_description)) else: - label_description = self.templates.label_description[self.result.label] + label_description = getattr( + self.templates.label_description, self.result.label + ) edge_case = ( "OSM has substantivly more buildings than the reference datasets. The " "reference dataset is likely to miss many buildings." diff --git a/ohsome_quality_api/indicators/currentness/indicator.py b/ohsome_quality_api/indicators/currentness/indicator.py index 454d5360c..0fa356a1a 100644 --- a/ohsome_quality_api/indicators/currentness/indicator.py +++ b/ohsome_quality_api/indicators/currentness/indicator.py @@ -158,7 +158,7 @@ def calculate(self): else: self.result.class_ = 1 - label_description = self.templates.label_description[self.result.label] + label_description = getattr(self.templates.label_description, self.result.label) self.result.description += Template( self.templates.result_description ).substitute( diff --git a/ohsome_quality_api/indicators/density/indicator.py b/ohsome_quality_api/indicators/density/indicator.py index 82ade018c..f15502653 100644 --- a/ohsome_quality_api/indicators/density/indicator.py +++ b/ohsome_quality_api/indicators/density/indicator.py @@ -46,18 +46,18 @@ def calculate(self) -> None: if self.result.value >= self.threshold_yellow: self.result.class_ = 5 self.result.description = ( - description + self.templates.label_description["green"] + description + self.templates.label_description.green ) else: if self.result.value > self.threshold_red: self.result.class_ = 3 self.result.description = ( - description + self.templates.label_description["yellow"] + description + self.templates.label_description.yellow ) else: self.result.class_ = 1 self.result.description = ( - description + self.templates.label_description["red"] + description + self.templates.label_description.red ) def create_figure(self) -> None: diff --git a/ohsome_quality_api/indicators/mapping_saturation/indicator.py b/ohsome_quality_api/indicators/mapping_saturation/indicator.py index d8a6478c1..5f68eb28b 100644 --- a/ohsome_quality_api/indicators/mapping_saturation/indicator.py +++ b/ohsome_quality_api/indicators/mapping_saturation/indicator.py @@ -151,8 +151,8 @@ def calculate(self) -> None: # noqa: C901 description = Template(self.templates.result_description).substitute( saturation=round(self.result.value * 100, 2) ) - self.result.description = ( - description + self.templates.label_description[self.result.label] + self.result.description = description + getattr( + self.templates.label_description, self.result.label ) def create_figure(self) -> None: diff --git a/ohsome_quality_api/indicators/minimal/indicator.py b/ohsome_quality_api/indicators/minimal/indicator.py index 001487e65..688ec3874 100644 --- a/ohsome_quality_api/indicators/minimal/indicator.py +++ b/ohsome_quality_api/indicators/minimal/indicator.py @@ -25,9 +25,7 @@ async def preprocess(self) -> None: def calculate(self) -> None: description = Template(self.templates.result_description).substitute() self.result.value = 1.0 - self.result.description = ( - description + self.templates.label_description["green"] - ) + self.result.description = description + self.templates.label_description.green def create_figure(self) -> None: # Do nothing ... diff --git a/ohsome_quality_api/indicators/models.py b/ohsome_quality_api/indicators/models.py index ab7418210..fdf2423ea 100644 --- a/ohsome_quality_api/indicators/models.py +++ b/ohsome_quality_api/indicators/models.py @@ -1,7 +1,8 @@ from datetime import datetime, timezone from typing import Literal -from pydantic import BaseModel, ConfigDict, Field, computed_field +from fastapi_i18n import _ +from pydantic import BaseModel, ConfigDict, Field, computed_field, field_validator from ohsome_quality_api.projects.definitions import ProjectEnum from ohsome_quality_api.quality_dimensions.definitions import QualityDimensionEnum @@ -23,13 +24,35 @@ class IndicatorMetadata(BaseModel): populate_by_name=True, ) + @field_validator("name", "description", mode="before") + @classmethod + def translate(cls, value: str) -> str: + return _(value) + + +class LabelDescription(BaseModel): + green: str + yellow: str + red: str + undefined: str + + @field_validator("green", "yellow", "red", "undefined", mode="before") + @classmethod + def translate(cls, value: str) -> str: + return _(value) + class IndicatorTemplates(BaseModel): """Result text templates of an indicator as defined in the templates.yaml file.""" - label_description: dict[str, str] + label_description: LabelDescription result_description: str + @field_validator("result_description", mode="before") + @classmethod + def translate(cls, value: str) -> str: + return _(value) + class Result(BaseModel): """The result of the Indicator. diff --git a/ohsome_quality_api/indicators/road_comparison/indicator.py b/ohsome_quality_api/indicators/road_comparison/indicator.py index 08270700b..ab06b48d0 100644 --- a/ohsome_quality_api/indicators/road_comparison/indicator.py +++ b/ohsome_quality_api/indicators/road_comparison/indicator.py @@ -138,7 +138,7 @@ def calculate(self) -> None: elif self.th_low > self.result.value >= 0: self.result.class_ = 1 - label_description = self.templates.label_description[self.result.label] + label_description = getattr(self.templates.label_description, self.result.label) self.result.description += label_description # remove double white spaces self.result.description = " ".join(self.result.description.split()) diff --git a/ohsome_quality_api/locale/de/LC_MESSAGES/messages.po b/ohsome_quality_api/locale/de/LC_MESSAGES/messages.po new file mode 100644 index 000000000..823a6c2c2 --- /dev/null +++ b/ohsome_quality_api/locale/de/LC_MESSAGES/messages.po @@ -0,0 +1,1025 @@ +# German translations for PROJECT. +# Copyright (C) 2025 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2025. +# +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2025-03-12 14:17+1300\n" +"PO-Revision-Date: 2025-03-12 14:17+1300\n" +"Last-Translator: FULL NAME \n" +"Language: de\n" +"Language-Team: de \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.17.0\n" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Height of Buildings" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +#: ohsome_quality_api/projects/projects.yaml +msgid "TODO" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "House Number" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Street Address" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "City Address" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Postcode Address" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Country Address" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "State Address" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Suburb Address" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "District Address" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Levels of Buildings" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Shape of Roofs" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Levels of Roofs" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Material of Buildings" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Material of Roofs" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Colour of Roofs" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Colour of Buildings" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Source" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Public transport platform" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Bus stop area" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "shelter" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Birthing centre" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Blood donation" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Rehabilitation" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Vaccination centre" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Opening Hours" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Specialty" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Phone Number" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Name" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Website" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Emergency" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Fitness" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Swimming" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Weightlifting" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Sport" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Leaf Type" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Playground" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Winery" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Shop Name" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Theme park" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Lit" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Surface" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Access" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Tunnel" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Subway stop area" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Brand" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Tram stop area" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Type of Leaves" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Road Name" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Sidewalk" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Crossing" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Cycleway" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Cycleway Share Busway" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Parking" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Maxspeed" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Oneway" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Lanes" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Shelter" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Bench" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Trash Bin" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Tactile Paving" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Wheelchair Accessibility" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Bus Lines" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "List of all bus lines stopping at a certain stop" +msgstr "" + +#: ohsome_quality_api/attributes/attributes.yaml +msgid "Departures Board" +msgstr "" + +#: ohsome_quality_api/indicators/indicators.yaml +msgid "Mapping Saturation" +msgstr "" + +#: ohsome_quality_api/indicators/indicators.yaml +msgid "" +"Calculate if mapping has saturated. High saturation has been reached if " +"the growth of the fitted curve is minimal." +msgstr "Berechne ob das Kartieren gesättigt ist. Bei hohe Sättigung ist die Steigung der Kurve minimal." + +#: ohsome_quality_api/indicators/indicators.yaml +msgid "Density" +msgstr "" + +#: ohsome_quality_api/indicators/indicators.yaml +msgid "" +"The density of features. It is calculated by the number of features " +"divided by the area in square-kilometers." +msgstr "" + +#: ohsome_quality_api/indicators/indicators.yaml +#: ohsome_quality_api/quality_dimensions/quality_dimensions.yaml +#: ohsome_quality_api/topics/presets.yaml +msgid "Minimal" +msgstr "" + +#: ohsome_quality_api/indicators/indicators.yaml +msgid "An minimal Indicator for testing purposes." +msgstr "" + +#: ohsome_quality_api/indicators/indicators.yaml +#: ohsome_quality_api/quality_dimensions/quality_dimensions.yaml +msgid "Currentness" +msgstr "" + +#: ohsome_quality_api/indicators/indicators.yaml +msgid "" +"Estimate currentness of features by classifying contributions based on " +"topic specific temporal thresholds into three groups: up-to-date, in-" +"between and out-of-date." +msgstr "" + +#: ohsome_quality_api/indicators/indicators.yaml +msgid "Road Comparison" +msgstr "" + +#: ohsome_quality_api/indicators/indicators.yaml +msgid "" +"Compare the road length of OSM roads with the road length of reference " +"data." +msgstr "" + +#: ohsome_quality_api/indicators/indicators.yaml +msgid "Building Comparison" +msgstr "" + +#: ohsome_quality_api/indicators/indicators.yaml +msgid "Comparison of OSM buildings with the buildings of reference datasets." +msgstr "" + +#: ohsome_quality_api/indicators/indicators.yaml +msgid "Attribute Completeness" +msgstr "" + +#: ohsome_quality_api/indicators/indicators.yaml +msgid "" +"Derive the ratio of OSM features compared to features which match " +"additional expected tags (e.g. amenity=hospital vs amenity=hospital and " +"wheelchair=yes)." +msgstr "" + +#: ohsome_quality_api/indicators/attribute_completeness/templates.yaml +msgid "The attribute completeness is low (<25%)." +msgstr "" + +#: ohsome_quality_api/indicators/attribute_completeness/templates.yaml +#, python-format +msgid "The attribute completeness is medium (25%-75%)." +msgstr "" + +#: ohsome_quality_api/indicators/attribute_completeness/templates.yaml +msgid "The attribute completeness is high (>75%)." +msgstr "" + +#: ohsome_quality_api/indicators/attribute_completeness/templates.yaml +#: ohsome_quality_api/indicators/currentness/templates.yaml +#: ohsome_quality_api/indicators/density/templates.yaml +#: ohsome_quality_api/indicators/minimal/templates.yaml +msgid "The quality level could not be calculated for this indicator." +msgstr "" + +#: ohsome_quality_api/indicators/attribute_completeness/templates.yaml +#, python-format +msgid "" +"$result% of all \"$topic\" features (all: $all) in your area of interest " +"have the selected additional $tags (matched: $matched). " +msgstr "" + +#: ohsome_quality_api/indicators/building_comparison/datasets.yaml +msgid "EUBUCCO" +msgstr "" + +#: ohsome_quality_api/indicators/building_comparison/datasets.yaml +msgid "" +"EUBUCCO is a dataset of building footprints for Europe. It is derived " +"from administrative datasets." +msgstr "" + +#: ohsome_quality_api/indicators/building_comparison/datasets.yaml +msgid "Microsoft Building Footprints" +msgstr "" + +#: ohsome_quality_api/indicators/building_comparison/datasets.yaml +msgid "" +"Microsoft Building Footprints is a dataset of building footprints for the" +" world. It is derived from satellite imagery." +msgstr "" + +#: ohsome_quality_api/indicators/building_comparison/templates.yaml +msgid "The completeness of OSM buildings in your area-of-interest is low." +msgstr "" + +#: ohsome_quality_api/indicators/building_comparison/templates.yaml +msgid "The completeness of OSM buildings in your area-of-interest is medium." +msgstr "" + +#: ohsome_quality_api/indicators/building_comparison/templates.yaml +msgid "The completeness of OSM buildings in your area-of-interest is high." +msgstr "" + +#: ohsome_quality_api/indicators/building_comparison/templates.yaml +#: ohsome_quality_api/indicators/road_comparison/templates.yaml +msgid "Comparison could not be made." +msgstr "" + +#: ohsome_quality_api/indicators/building_comparison/templates.yaml +msgid "The completeness in comparison to $dataset is $ratio%." +msgstr "" + +#: ohsome_quality_api/indicators/currentness/templates.yaml +msgid "Many features are out-of-date." +msgstr "" + +#: ohsome_quality_api/indicators/currentness/templates.yaml +msgid "Some features are up-to-date and some features are out-of-date." +msgstr "" + +#: ohsome_quality_api/indicators/currentness/templates.yaml +msgid "Most features are up-to-date." +msgstr "" + +#: ohsome_quality_api/indicators/currentness/templates.yaml +#, python-format +msgid "" +"In the area of interest $up_to_date_contrib_rel% of the $num_of_elements " +"features were edited (created or modified) for the last time in the " +"period between $from_timestamp and $to_timestamp." +msgstr "" + +#: ohsome_quality_api/indicators/density/templates.yaml +msgid "" +"It is probably hard to orientate on OSM-based sketchmaps of this region." +" There are just few orientation providing features available, you " +"should explore, if participants can orientate properly." +msgstr "" + +#: ohsome_quality_api/indicators/density/templates.yaml +msgid "" +"It might be difficult to orientate on OSM-based sketchmaps of this " +"region. There are not many orientation providing features available, you" +" should explore, if participants can orientate properly." +msgstr "" + +#: ohsome_quality_api/indicators/density/templates.yaml +msgid "It is probably easy to orientate on OSM-based sketchmaps of this region." +msgstr "" + +#: ohsome_quality_api/indicators/density/templates.yaml +msgid "" +"The density of landmarks (points of reference, e.g. waterbodies, " +"supermarkets, churches, bus stops) is $result features per sqkm." +msgstr "" + +#: ohsome_quality_api/indicators/mapping_saturation/templates.yaml +msgid "No saturation identified (Saturation ≤ 30%)." +msgstr "Kein Sättigung erkannt (Sättigung ≤ 30%)." + +#: ohsome_quality_api/indicators/mapping_saturation/templates.yaml +msgid "Saturation is in progress (30% < Saturation ≤ 97%)." +msgstr "Sättigung fortschreitend (30% < Sättigung ≤ 97%)." + +#: ohsome_quality_api/indicators/mapping_saturation/templates.yaml +msgid "High saturation has been reached (97% < Saturation ≤ 100%)." +msgstr "Hohe Sättigung ereicht (97% < Sättigung ≤ 100%)." + +#: ohsome_quality_api/indicators/mapping_saturation/templates.yaml +msgid "Saturation could not be calculated." +msgstr "Sättigung konnte nicht berechnet werden." + +#: ohsome_quality_api/indicators/mapping_saturation/templates.yaml +msgid "The saturation of the last 3 years is $saturation%." +msgstr "Die Sättigung der letzten 3 Jahre ist $saturation%." + +#: ohsome_quality_api/indicators/minimal/templates.yaml +msgid "Bad data quality." +msgstr "Schlechte Datenqualität" + +#: ohsome_quality_api/indicators/minimal/templates.yaml +msgid "Medium data quality." +msgstr "Mittlere Datenqualität." + +#: ohsome_quality_api/indicators/minimal/templates.yaml +msgid "Good data quality." +msgstr "Gute Datenqualität." + +#: ohsome_quality_api/indicators/minimal/templates.yaml +msgid "Some description of the result." +msgstr "Eine Beschreibung der Ergebnisse." + +#: ohsome_quality_api/indicators/road_comparison/datasets.yaml +msgid "Microsoft Roads" +msgstr "" + +#: ohsome_quality_api/indicators/road_comparison/datasets.yaml +msgid "" +"Microsoft Road Detections is a dataset of road world-wide. It is derived " +"from satellite imagery." +msgstr "" + +#: ohsome_quality_api/indicators/road_comparison/templates.yaml +msgid "The completeness of OSM roads in your area-of-interest is low." +msgstr "" + +#: ohsome_quality_api/indicators/road_comparison/templates.yaml +msgid "The completeness of OSM roads in your area-of-interest is medium." +msgstr "" + +#: ohsome_quality_api/indicators/road_comparison/templates.yaml +msgid "The completeness of OSM roads in your area-of-interest is high." +msgstr "" + +#: ohsome_quality_api/indicators/road_comparison/templates.yaml +msgid "" +"The completeness in comparison to $dataset is $ratio%. $dataset have a " +"total length of $length_total. $length_matched of $dataset are covered by" +" OSM roads." +msgstr "" + +#: ohsome_quality_api/projects/projects.yaml +msgid "something that is still a TODO" +msgstr "" + +#: ohsome_quality_api/quality_dimensions/quality_dimensions.yaml +msgid "Completeness" +msgstr "" + +#: ohsome_quality_api/quality_dimensions/quality_dimensions.yaml +msgid "" +"The degree to which subject data associated with an entity has values for" +" all expected attributes and related entity instances in a specific " +"context of use." +msgstr "" + +#: ohsome_quality_api/quality_dimensions/quality_dimensions.yaml +msgid "" +"The degree to which data has attributes that are of the right age in a " +"specific context of use." +msgstr "" + +#: ohsome_quality_api/quality_dimensions/quality_dimensions.yaml +msgid "A minimal quality dimension definition for testing purposes." +msgstr "" + +#: ohsome_quality_api/quality_dimensions/quality_dimensions.yaml +msgid "None" +msgstr "" + +#: ohsome_quality_api/quality_dimensions/quality_dimensions.yaml +msgid "No specific quality dimension" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Buildings (count)" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "All buildings as defined by all objects tagged with 'building=*'." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Buildings (area)" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Roads (all highways)" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "" +"All linear OSM features holding the prinicipal tag `highway=*`. The road " +"network defined by all objects which hold the principal tags for the road" +" network and their link roads as defined in the OSM Wiki`:` " +"https://wiki.openstreetmap.org/wiki/Key:highway" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Roads (cars)" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "" +"All linear OSM features referring to a road usable by vehicles (i.e. " +"cars). The road network defined by all objects which hold the principal " +"tags for the road network and their link roads as defined in the OSM " +"Wiki`:` https://wiki.openstreetmap.org/wiki/Highways#Roads_and_tracks" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Railways" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Railway networks." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "POI" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Points of interest" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Schools" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of schools." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Kindergartens" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of kindergarten." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Clinics" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of clinics." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Doctors" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of doctors." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Bus Stops" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of bus stops." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Tram Stops" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of tram stops." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Public Transport Stops" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of public transport stops." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Subway Stations" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of subway stops." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Supermarkets" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of supermarkets." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Marketplaces" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of marketplaces." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Parks" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of parks." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Sports Pitches" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "" +"Count of sports pitches (an area designed for practising a particular " +"sport)" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Forests" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of forests." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Industrial Landuse (count)" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Industrial landsites" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Industrial Landuse (area)" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Industrial areas" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Fitness Centres" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of fitness centres." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Fire Stations" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of firestations." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Hospitals" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of hospitals." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "UNICEF Roads" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "The road network usable for routing as defined for the UNICEF Project." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Primary Healthcare facilities for UNICEF Project" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Amenities" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "All features with the amenities key." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Landmarks for Orientation" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "" +"Landmarks for orientation in a city such as natural features, public " +"transport stations and amenities." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "MapAction Settlements Count" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Number of settlements (cities)" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "MapAction Capital City Count" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Number of capital cities" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "MapAction Rail Length" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Length of objects identified as rails (large railways)" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "MapAction Major Roads length" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Length of objects identified as major roads (primary, motorway and trunk)" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "MapAction Lakes Count" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Number of objects identified as lakes, lagoons and reservoirs" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "MapAction Lakes Area" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Area of objects identified as lakes, lagoons and reservoirs" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "MapAction Rivers Length" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Length of objects identified as rivers (or riverbanks)" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Land Use and Land Cover" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "" +"Features related to land use and land cover. This definition includes " +"well established tags for coherent areas at the most atomic level " +"available. This definition therefore excludes areas with the keys " +"aeroway, highway, leisure and tourism which can be found in other " +"sources. For further details please contact us." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Local food shops" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of local food shops" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Fast food restaurants" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of fast food restaurants" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Restaurants" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of restaurants" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Convenience stores" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of convenience stores" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Pubs and biergartens" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of pubs and biergartens" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Alcohol and beverages" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of shops selling alcohol" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Sweets and pasteries" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Count of shops selling sweets and pasteries" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Arable Land CLC" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "" +"Selected features for Corine Land Cover Category \"Arable Land\" (level " +"2) in Agriculture." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Permanent Crops CLC" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "" +"Selected features for Corine Land Cover Category \"Permanent Crops\" " +"(level 2) in Agriculture." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Pastures CLC" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "" +"Selected features for Corine Land Cover Category \"Pastures\" (level 2) " +"in Agriculture." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Forests CLC" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "" +"Selected features for Corine Land Cover Category \"Forests\" (level 2) in" +" Seminatural Land." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Leaf Types of Forests CLC" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "" +"frequency of forests according to Corine Land Cover Category \"Forests\" " +"(level 2) tagged with Leaf Type." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Shrubs CLC" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "" +"Selected features for Corine Land Cover Category \"Shrubs\" (level 2) in " +"Seminatural Land." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Open Spaces CLC" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "" +"Selected features for Corine Land Cover Category \"Open Spaces\" (level " +"2) in Seminatural Land." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Wetlands CLC" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Selected features for Corine Land Cover Category \"Wetlands\" (level 1)." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Water CLC" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "" +"Selected features for Corine Land Cover Category \"Water\" (level 1), " +"excluding waterways." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Waterways CLC" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "" +"Selected features for Corine Land Cover Category \"Waterways\" (level 2) " +"in Water." +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "A minimal topic definition for testing purposes" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Infrastructure Lines" +msgstr "" + +#: ohsome_quality_api/topics/presets.yaml +msgid "Line objects related to infrastructure" +msgstr "" + diff --git a/ohsome_quality_api/utils/__init__.py b/ohsome_quality_api/utils/__init__.py index e69de29bb..9edd4a8ef 100644 --- a/ohsome_quality_api/utils/__init__.py +++ b/ohsome_quality_api/utils/__init__.py @@ -0,0 +1,3 @@ +from .pybabel_yaml_extractor import pybabel_yaml_extractor + +__all__ = ("pybabel_yaml_extractor",) diff --git a/ohsome_quality_api/utils/helper.py b/ohsome_quality_api/utils/helper.py index 4bab9577b..3de3b5a47 100644 --- a/ohsome_quality_api/utils/helper.py +++ b/ohsome_quality_api/utils/helper.py @@ -118,22 +118,6 @@ def write_geojson(outfile: str, geojson_object: Feature | FeatureCollection) -> logging.info("Output file written:\t" + str(outfile)) -def flatten_sequence(input_seq: dict | list | tuple | set) -> list: - """Returns the given input sequence as a list. - - If the input is a dict, it returns all values. - """ - output = [] - if isinstance(input_seq, dict): - input_seq = input_seq.values() - for val in input_seq: - if isinstance(val, dict | list | tuple | set): - output += flatten_sequence(val) - else: - output.append(val) - return output - - def get_project_root() -> Path: """Get root of the Python project.""" return Path(__file__).resolve().parent.parent.parent.resolve() diff --git a/ohsome_quality_api/utils/pybabel_yaml_extractor.py b/ohsome_quality_api/utils/pybabel_yaml_extractor.py new file mode 100644 index 000000000..3548c2e74 --- /dev/null +++ b/ohsome_quality_api/utils/pybabel_yaml_extractor.py @@ -0,0 +1,61 @@ +from typing import Iterator + +import yaml + + +def flatten_sequence(input_seq: dict | list | tuple | set) -> list: + """Returns the given input sequence as a list. + + If the input is a dict, it returns all values. + """ + output = [] + if isinstance(input_seq, dict): + input_seq = input_seq.values() + for val in input_seq: + if isinstance(val, dict | list | tuple | set): + output += flatten_sequence(val) + else: + output.append(val) + return output + + +def filter_dictonary_by_keys(dictonary: dict, whitelist: list | tuple) -> dict: + if not isinstance(dictonary, dict): + return dictonary + result = {} + for key, value in dictonary.items(): + if key in whitelist: + if isinstance(value, dict): + result[key] = filter_dictonary_by_keys(value, whitelist) + else: + result[key] = value + elif isinstance(value, dict): + filtered_value = filter_dictonary_by_keys(value, whitelist) + if filtered_value: + result[key] = filtered_value + return result + + +def pybabel_yaml_extractor( + fileobj, + keywords, + comment_tags, + options: dict, +) -> Iterator[tuple[str, str, str, str]]: + """Method for extracting localizable text from YAML files. + + Usage: + pybabel_yaml_extractor(fileobj, options={"keys": "name,description"}) + + Complies with the following interface: + https://babel.readthedocs.io/en/latest/messages.html#writing-extraction-methods + """ + if "keys" in options.keys(): + keys = options["keys"].split(",") + else: + raise ValueError("Options should contain non-empty `keys` item.") + content = yaml.safe_load(fileobj) + filtered = filter_dictonary_by_keys(content, keys) + flattened = flatten_sequence(filtered) + for string in flattened: + yield ("", "", string, "") diff --git a/poetry.lock b/poetry.lock index cae00d089..298aceb0f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -172,6 +172,20 @@ docs = ["Sphinx (>=8.1.3,<8.2.0)", "sphinx-rtd-theme (>=1.2.2)"] gssauth = ["gssapi", "sspilib"] test = ["distro (>=1.9.0,<1.10.0)", "flake8 (>=6.1,<7.0)", "flake8-pyi (>=24.1.0,<24.2.0)", "gssapi", "k5test", "mypy (>=1.8.0,<1.9.0)", "sspilib", "uvloop (>=0.15.3)"] +[[package]] +name = "babel" +version = "2.17.0" +description = "Internationalization utilities" +optional = false +python-versions = ">=3.8" +files = [ + {file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"}, + {file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"}, +] + +[package.extras] +dev = ["backports.zoneinfo", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata"] + [[package]] name = "beautifulsoup4" version = "4.12.3" @@ -568,6 +582,25 @@ typing-extensions = ">=4.8.0" [package.extras] all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +[[package]] +name = "fastapi-i18n" +version = "0.3.0" +description = "Add your description here" +optional = false +python-versions = ">=3.10" +files = [] +develop = false + +[package.dependencies] +fastapi = ">=0.109.2" +httpx = ">=0.23.0" + +[package.source] +type = "git" +url = "https://gitlab.heigit.org/mschaub/fastapi-i18n.git" +reference = "HEAD" +resolved_reference = "65b3c608313528d67022da8898bf66ebd72610a1" + [[package]] name = "filelock" version = "3.16.1" @@ -2150,4 +2183,4 @@ propcache = ">=0.2.0" [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "1e0dae8aedea1d37eed68299069e9f99e3951f5c9ed42cd8e0e010ce6ad3952b" +content-hash = "ea14dea75d3fabfb6c858e7ba51b5431e4c7e68412a8162e9122d459fd57c0dc" diff --git a/pyproject.toml b/pyproject.toml index 2f9aabd5f..4ab4651da 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,6 +46,7 @@ plotly = "^5.16.1" psycopg = {extras = ["binary"], version = "^3.1"} async-lru = "^2.0.4" approvaltests = "^12.1.0" +fastapi-i18n = {git = "https://gitlab.heigit.org/mschaub/fastapi-i18n.git"} [tool.poetry.dev-dependencies] pre-commit = "^3.2.1" @@ -58,6 +59,7 @@ pytest-mock = "^3.11.1" [tool.poetry.group.dev.dependencies] ruff = "^0.7.3" +babel = "^2.17.0" [build-system] requires = ["poetry-core"] diff --git a/tests/conftest.py b/tests/conftest.py index cbd3c66c9..20492d107 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,6 +4,7 @@ import geojson import pytest +from fastapi_i18n.main import Translator, translator from geojson import Feature, FeatureCollection, Polygon from ohsome_quality_api.attributes.models import Attribute @@ -265,3 +266,14 @@ def metadata_indicator_minimal() -> dict[str, IndicatorMetadata]: @pytest.fixture def indicators_metadata() -> dict[str, IndicatorMetadata]: return get_indicator_metadata() + + +@pytest.fixture +def locale_de(monkeypatch): + monkeypatch.setenv( + "FASTAPI_I18N_LOCALE_DIR", + "/home/matthias/work/projects/oqapi/ohsome_quality_api/locale", + ) + token = translator.set(Translator(locale="de")) + yield + translator.reset(token) diff --git a/tests/integrationtests/api/test_i18n.py b/tests/integrationtests/api/test_i18n.py new file mode 100644 index 000000000..6f932b218 --- /dev/null +++ b/tests/integrationtests/api/test_i18n.py @@ -0,0 +1,44 @@ +import pytest +from approvaltests import verify + +from tests.integrationtests.utils import PytestNamer, oqapi_vcr + +ENDPOINT = "/indicators/" + +# TODO: Remove and recreate VCR cassette for this test + + +@pytest.fixture +@oqapi_vcr.use_cassette +def indicator(client, bpolys, monkeypatch): + monkeypatch.setenv( + "FASTAPI_I18N_LOCALE_DIR", + "/home/matthias/work/projects/oqapi/ohsome_quality_api/locale", + ) + endpoint = "/indicators/mapping-saturation" + parameters = { + "bpolys": bpolys, + "topic": "building-count", + } + response = client.post( + endpoint, + json=parameters, + headers={ + "Accept-Language": "de", + "accept": "application/json", + }, + ) + return response.json() + + +def test_translation_indicator_metadata_description(indicator): + verify(indicator["result"][0]["metadata"]["description"], namer=PytestNamer()) + + +def test_translation_indicator_result_description(indicator): + """Test successful translation of result description. + + Result description are string templates. This tests checks if translations + of string templates is working as expected. + """ + verify(indicator["result"][0]["result"]["description"], namer=PytestNamer()) diff --git a/tests/integrationtests/approved/api/test_i18n.py-test_translation_indicator_metadata_description.approved.txt b/tests/integrationtests/approved/api/test_i18n.py-test_translation_indicator_metadata_description.approved.txt new file mode 100644 index 000000000..e7457dd1c --- /dev/null +++ b/tests/integrationtests/approved/api/test_i18n.py-test_translation_indicator_metadata_description.approved.txt @@ -0,0 +1 @@ +Berechne ob das Kartieren gesättigt ist. Bei hohe Sättigung ist die Steigung der Kurve minimal. diff --git a/tests/integrationtests/approved/api/test_i18n.py-test_translation_indicator_result_description.approved.txt b/tests/integrationtests/approved/api/test_i18n.py-test_translation_indicator_result_description.approved.txt new file mode 100644 index 000000000..7f97fb4b6 --- /dev/null +++ b/tests/integrationtests/approved/api/test_i18n.py-test_translation_indicator_result_description.approved.txt @@ -0,0 +1 @@ +Die Sättigung der letzten 3 Jahre ist 99.5%.Hohe Sättigung ereicht (97% < Sättigung ≤ 100%). diff --git a/tests/integrationtests/approved/indicators/test_mapping_saturation.py-TestCalculation-test_calculate.approved.txt b/tests/integrationtests/approved/indicators/test_mapping_saturation.py-TestCalculation-test_calculate.approved.txt new file mode 100644 index 000000000..7f97fb4b6 --- /dev/null +++ b/tests/integrationtests/approved/indicators/test_mapping_saturation.py-TestCalculation-test_calculate.approved.txt @@ -0,0 +1 @@ +Die Sättigung der letzten 3 Jahre ist 99.5%.Hohe Sättigung ereicht (97% < Sättigung ≤ 100%). diff --git a/tests/integrationtests/approved/unittests/test_indicators_definitions.py-test_get_indicator_de.approved.txt b/tests/integrationtests/approved/unittests/test_indicators_definitions.py-test_get_indicator_de.approved.txt new file mode 100644 index 000000000..76840719c --- /dev/null +++ b/tests/integrationtests/approved/unittests/test_indicators_definitions.py-test_get_indicator_de.approved.txt @@ -0,0 +1,16 @@ +{ + "name": "Mapping Saturation", + "description": "Berechne ob das Kartieren gesättigt ist. Bei hohe Sättigung ist die Steigung der Kurve minimal.", + "projects": [ + "core", + "corine-land-cover", + "expanse", + "experimental", + "idealvgi", + "mapaction", + "sketchmap", + "bkg", + "unicef" + ], + "quality_dimension": "completeness" +} diff --git a/tests/integrationtests/fixtures/vcr_cassettes/api/test_i18n.yaml b/tests/integrationtests/fixtures/vcr_cassettes/api/test_i18n.yaml new file mode 100644 index 000000000..51ce55852 --- /dev/null +++ b/tests/integrationtests/fixtures/vcr_cassettes/api/test_i18n.yaml @@ -0,0 +1,264 @@ +interactions: +- request: + body: filter=building%3D%2A+and+building%21%3Dno+and+geometry%3Apolygon&bpolys=%7B%22type%22%3A+%22FeatureCollection%22%2C+%22features%22%3A+%5B%7B%22type%22%3A+%22Feature%22%2C+%22geometry%22%3A+%7B%22type%22%3A+%22Polygon%22%2C+%22coordinates%22%3A+%5B%5B%5B8.573179%2C+49.4236%5D%2C+%5B8.573244%2C+49.423266%5D%2C+%5B8.573517%2C+49.421746%5D%2C+%5B8.573602%2C+49.421029%5D%2C+%5B8.57363%2C+49.420766%5D%2C+%5B8.573618%2C+49.420478%5D%2C+%5B8.573575%2C+49.420208%5D%2C+%5B8.573487%2C+49.419852%5D%2C+%5B8.573253%2C+49.419103%5D%2C+%5B8.57328%2C+49.418634%5D%2C+%5B8.573262%2C+49.41846%5D%2C+%5B8.573244%2C+49.418239%5D%2C+%5B8.573233%2C+49.418026%5D%2C+%5B8.573211%2C+49.417562%5D%2C+%5B8.573206%2C+49.417217%5D%2C+%5B8.573223%2C+49.416902%5D%2C+%5B8.573288%2C+49.416518%5D%2C+%5B8.57343%2C+49.415763%5D%2C+%5B8.573622%2C+49.415734%5D%2C+%5B8.57398%2C+49.414723%5D%2C+%5B8.574098%2C+49.414422%5D%2C+%5B8.574905%2C+49.412659%5D%2C+%5B8.575126%2C+49.41262%5D%2C+%5B8.575952%2C+49.412479%5D%2C+%5B8.576355%2C+49.412403%5D%2C+%5B8.576806%2C+49.412309%5D%2C+%5B8.577418%2C+49.412162%5D%2C+%5B8.578871%2C+49.411816%5D%2C+%5B8.580327%2C+49.411477%5D%2C+%5B8.580548%2C+49.411425%5D%2C+%5B8.581021%2C+49.411314%5D%2C+%5B8.581467%2C+49.411198%5D%2C+%5B8.582126%2C+49.411021%5D%2C+%5B8.58281%2C+49.410831%5D%2C+%5B8.583621%2C+49.410604%5D%2C+%5B8.584256%2C+49.41041%5D%2C+%5B8.584461%2C+49.410598%5D%2C+%5B8.584601%2C+49.41074%5D%2C+%5B8.58466%2C+49.410809%5D%2C+%5B8.584729%2C+49.410896%5D%2C+%5B8.584841%2C+49.411043%5D%2C+%5B8.584893%2C+49.411041%5D%2C+%5B8.590664%2C+49.410551%5D%2C+%5B8.592504%2C+49.410392%5D%2C+%5B8.59249%2C+49.410325%5D%2C+%5B8.592557%2C+49.410316%5D%2C+%5B8.592992%2C+49.410285%5D%2C+%5B8.594295%2C+49.410194%5D%2C+%5B8.595027%2C+49.410131%5D%2C+%5B8.595718%2C+49.41008%5D%2C+%5B8.596457%2C+49.410013%5D%2C+%5B8.597109%2C+49.409948%5D%2C+%5B8.597817%2C+49.409869%5D%2C+%5B8.598479%2C+49.409799%5D%2C+%5B8.59864%2C+49.409784%5D%2C+%5B8.600522%2C+49.409526%5D%2C+%5B8.603393%2C+49.409127%5D%2C+%5B8.60354%2C+49.409104%5D%2C+%5B8.603638%2C+49.409079%5D%2C+%5B8.6052%2C+49.408456%5D%2C+%5B8.608794%2C+49.407045%5D%2C+%5B8.610673%2C+49.405949%5D%2C+%5B8.611461%2C+49.405467%5D%2C+%5B8.612437%2C+49.406203%5D%2C+%5B8.616606%2C+49.407383%5D%2C+%5B8.622553%2C+49.409046%5D%2C+%5B8.622627%2C+49.40901%5D%2C+%5B8.622648%2C+49.408953%5D%2C+%5B8.62272%2C+49.408975%5D%2C+%5B8.622722%2C+49.408976%5D%2C+%5B8.622791%2C+49.409015%5D%2C+%5B8.622851%2C+49.409049%5D%2C+%5B8.623189%2C+49.409236%5D%2C+%5B8.624498%2C+49.409957%5D%2C+%5B8.62459%2C+49.410009%5D%2C+%5B8.625101%2C+49.410294%5D%2C+%5B8.625378%2C+49.410448%5D%2C+%5B8.625911%2C+49.410745%5D%2C+%5B8.626324%2C+49.410975%5D%2C+%5B8.626979%2C+49.411341%5D%2C+%5B8.628263%2C+49.412032%5D%2C+%5B8.62859%2C+49.412213%5D%2C+%5B8.629072%2C+49.412486%5D%2C+%5B8.630034%2C+49.413176%5D%2C+%5B8.630959%2C+49.413833%5D%2C+%5B8.632078%2C+49.414583%5D%2C+%5B8.632707%2C+49.415007%5D%2C+%5B8.632748%2C+49.415035%5D%2C+%5B8.632938%2C+49.414961%5D%2C+%5B8.633025%2C+49.414928%5D%2C+%5B8.633075%2C+49.414807%5D%2C+%5B8.63406%2C+49.412449%5D%2C+%5B8.634446%2C+49.411487%5D%2C+%5B8.634737%2C+49.410763%5D%2C+%5B8.635407%2C+49.409092%5D%2C+%5B8.635873%2C+49.407932%5D%2C+%5B8.636033%2C+49.40753%5D%2C+%5B8.636136%2C+49.407242%5D%2C+%5B8.636215%2C+49.406957%5D%2C+%5B8.636379%2C+49.406391%5D%2C+%5B8.636465%2C+49.406041%5D%2C+%5B8.636591%2C+49.405566%5D%2C+%5B8.636667%2C+49.405073%5D%2C+%5B8.636706%2C+49.404806%5D%2C+%5B8.636743%2C+49.404552%5D%2C+%5B8.636827%2C+49.403969%5D%2C+%5B8.6369%2C+49.403462%5D%2C+%5B8.636926%2C+49.403268%5D%2C+%5B8.637017%2C+49.402596%5D%2C+%5B8.637222%2C+49.401141%5D%2C+%5B8.63755%2C+49.3988%5D%2C+%5B8.638008%2C+49.395648%5D%2C+%5B8.638186%2C+49.393813%5D%2C+%5B8.638295%2C+49.39272%5D%2C+%5B8.638521%2C+49.392746%5D%2C+%5B8.640722%2C+49.393021%5D%2C+%5B8.64343%2C+49.393381%5D%2C+%5B8.643512%2C+49.393194%5D%2C+%5B8.643527%2C+49.39316%5D%2C+%5B8.645535%2C+49.390884%5D%2C+%5B8.64636%2C+49.389866%5D%2C+%5B8.6475%2C+49.388537%5D%2C+%5B8.645357%2C+49.388044%5D%2C+%5B8.643807%2C+49.387609%5D%2C+%5B8.642091%2C+49.387149%5D%2C+%5B8.641038%2C+49.386841%5D%2C+%5B8.639916%2C+49.386498%5D%2C+%5B8.639667%2C+49.386434%5D%2C+%5B8.639387%2C+49.386413%5D%2C+%5B8.638662%2C+49.386411%5D%2C+%5B8.638086%2C+49.386573%5D%2C+%5B8.636604%2C+49.38704%5D%2C+%5B8.634926%2C+49.387313%5D%2C+%5B8.633683%2C+49.387185%5D%2C+%5B8.633598%2C+49.387174%5D%2C+%5B8.633542%2C+49.386897%5D%2C+%5B8.633434%2C+49.386227%5D%2C+%5B8.633401%2C+49.385899%5D%2C+%5B8.633366%2C+49.385891%5D%2C+%5B8.630199%2C+49.385201%5D%2C+%5B8.629858%2C+49.385107%5D%2C+%5B8.629436%2C+49.384945%5D%2C+%5B8.628851%2C+49.384706%5D%2C+%5B8.628366%2C+49.384445%5D%2C+%5B8.627801%2C+49.38413%5D%2C+%5B8.627122%2C+49.383729%5D%2C+%5B8.62646%2C+49.38335%5D%2C+%5B8.625986%2C+49.383068%5D%2C+%5B8.625383%2C+49.382699%5D%2C+%5B8.624878%2C+49.382387%5D%2C+%5B8.624241%2C+49.38199%5D%2C+%5B8.623785%2C+49.381668%5D%2C+%5B8.624382%2C+49.38067%5D%2C+%5B8.621112%2C+49.380011%5D%2C+%5B8.620378%2C+49.379843%5D%2C+%5B8.617932%2C+49.379283%5D%2C+%5B8.616155%2C+49.379158%5D%2C+%5B8.615294%2C+49.378918%5D%2C+%5B8.614545%2C+49.378758%5D%2C+%5B8.613751%2C+49.378528%5D%2C+%5B8.612581%2C+49.378202%5D%2C+%5B8.610866%2C+49.378017%5D%2C+%5B8.610186%2C+49.377919%5D%2C+%5B8.609757%2C+49.37785%5D%2C+%5B8.609403%2C+49.377756%5D%2C+%5B8.609066%2C+49.377649%5D%2C+%5B8.608678%2C+49.377505%5D%2C+%5B8.607916%2C+49.37721%5D%2C+%5B8.607342%2C+49.376972%5D%2C+%5B8.606882%2C+49.376751%5D%2C+%5B8.60681%2C+49.376163%5D%2C+%5B8.607222%2C+49.374986%5D%2C+%5B8.607484%2C+49.37429%5D%2C+%5B8.607333%2C+49.373851%5D%2C+%5B8.606536%2C+49.371886%5D%2C+%5B8.605798%2C+49.370097%5D%2C+%5B8.605168%2C+49.370272%5D%2C+%5B8.60321%2C+49.368377%5D%2C+%5B8.601004%2C+49.366203%5D%2C+%5B8.604393%2C+49.365577%5D%2C+%5B8.604307%2C+49.365419%5D%2C+%5B8.605479%2C+49.365214%5D%2C+%5B8.605885%2C+49.365159%5D%2C+%5B8.607155%2C+49.365004%5D%2C+%5B8.607562%2C+49.364962%5D%2C+%5B8.607787%2C+49.364932%5D%2C+%5B8.608004%2C+49.364857%5D%2C+%5B8.60823%2C+49.364779%5D%2C+%5B8.608521%2C+49.364676%5D%2C+%5B8.608763%2C+49.364589%5D%2C+%5B8.608975%2C+49.364526%5D%2C+%5B8.60924%2C+49.364461%5D%2C+%5B8.609518%2C+49.364418%5D%2C+%5B8.609797%2C+49.364361%5D%2C+%5B8.610128%2C+49.3643%5D%2C+%5B8.610354%2C+49.364251%5D%2C+%5B8.610605%2C+49.364179%5D%2C+%5B8.610995%2C+49.364053%5D%2C+%5B8.611555%2C+49.363849%5D%2C+%5B8.612129%2C+49.363662%5D%2C+%5B8.613637%2C+49.363103%5D%2C+%5B8.615444%2C+49.362414%5D%2C+%5B8.61635%2C+49.362058%5D%2C+%5B8.617043%2C+49.361767%5D%2C+%5B8.617591%2C+49.361529%5D%2C+%5B8.618237%2C+49.361201%5D%2C+%5B8.618957%2C+49.360849%5D%2C+%5B8.619443%2C+49.360653%5D%2C+%5B8.619975%2C+49.360461%5D%2C+%5B8.620625%2C+49.360206%5D%2C+%5B8.621086%2C+49.360044%5D%2C+%5B8.621364%2C+49.359916%5D%2C+%5B8.621823%2C+49.359713%5D%2C+%5B8.622089%2C+49.35959%5D%2C+%5B8.622436%2C+49.35947%5D%2C+%5B8.623627%2C+49.359191%5D%2C+%5B8.624466%2C+49.359063%5D%2C+%5B8.623282%2C+49.35746%5D%2C+%5B8.623019%2C+49.357581%5D%2C+%5B8.621335%2C+49.355497%5D%2C+%5B8.620215%2C+49.354073%5D%2C+%5B8.620484%2C+49.354038%5D%2C+%5B8.620686%2C+49.354007%5D%2C+%5B8.621085%2C+49.353877%5D%2C+%5B8.623323%2C+49.35288%5D%2C+%5B8.625019%2C+49.352119%5D%2C+%5B8.62524%2C+49.35203%5D%2C+%5B8.625625%2C+49.352003%5D%2C+%5B8.627988%2C+49.352082%5D%2C+%5B8.628566%2C+49.352102%5D%2C+%5B8.629102%2C+49.352103%5D%2C+%5B8.629641%2C+49.352094%5D%2C+%5B8.630762%2C+49.352065%5D%2C+%5B8.630787%2C+49.352734%5D%2C+%5B8.631513%2C+49.352774%5D%2C+%5B8.631909%2C+49.352796%5D%2C+%5B8.632002%2C+49.352809%5D%2C+%5B8.632227%2C+49.352816%5D%2C+%5B8.632605%2C+49.35284%5D%2C+%5B8.632903%2C+49.352846%5D%2C+%5B8.633112%2C+49.352836%5D%2C+%5B8.633234%2C+49.352838%5D%2C+%5B8.633289%2C+49.353939%5D%2C+%5B8.633355%2C+49.355012%5D%2C+%5B8.633367%2C+49.355489%5D%2C+%5B8.63355%2C+49.355781%5D%2C+%5B8.633757%2C+49.3561%5D%2C+%5B8.633974%2C+49.356482%5D%2C+%5B8.634167%2C+49.356808%5D%2C+%5B8.634287%2C+49.357126%5D%2C+%5B8.634421%2C+49.357445%5D%2C+%5B8.634503%2C+49.357686%5D%2C+%5B8.634859%2C+49.358095%5D%2C+%5B8.635396%2C+49.358765%5D%2C+%5B8.636103%2C+49.359671%5D%2C+%5B8.636657%2C+49.360357%5D%2C+%5B8.636737%2C+49.360538%5D%2C+%5B8.636888%2C+49.361037%5D%2C+%5B8.637136%2C+49.36199%5D%2C+%5B8.637264%2C+49.362635%5D%2C+%5B8.637304%2C+49.362804%5D%2C+%5B8.637443%2C+49.363191%5D%2C+%5B8.637664%2C+49.36361%5D%2C+%5B8.637986%2C+49.364357%5D%2C+%5B8.638362%2C+49.365323%5D%2C+%5B8.638797%2C+49.36638%5D%2C+%5B8.639105%2C+49.3671%5D%2C+%5B8.639672%2C+49.368535%5D%2C+%5B8.640274%2C+49.369977%5D%2C+%5B8.64095%2C+49.36962%5D%2C+%5B8.642835%2C+49.368655%5D%2C+%5B8.644035%2C+49.369071%5D%2C+%5B8.644716%2C+49.369324%5D%2C+%5B8.644987%2C+49.369459%5D%2C+%5B8.645246%2C+49.369621%5D%2C+%5B8.645609%2C+49.369857%5D%2C+%5B8.645945%2C+49.370086%5D%2C+%5B8.646206%2C+49.370303%5D%2C+%5B8.646365%2C+49.370464%5D%2C+%5B8.647363%2C+49.369711%5D%2C+%5B8.647775%2C+49.369395%5D%2C+%5B8.64813%2C+49.369156%5D%2C+%5B8.648616%2C+49.368856%5D%2C+%5B8.649147%2C+49.368515%5D%2C+%5B8.649775%2C+49.368118%5D%2C+%5B8.650491%2C+49.367685%5D%2C+%5B8.650841%2C+49.367478%5D%2C+%5B8.650529%2C+49.366984%5D%2C+%5B8.650281%2C+49.366573%5D%2C+%5B8.650115%2C+49.36627%5D%2C+%5B8.649942%2C+49.365978%5D%2C+%5B8.651691%2C+49.364976%5D%2C+%5B8.651847%2C+49.365094%5D%2C+%5B8.652197%2C+49.364902%5D%2C+%5B8.652915%2C+49.364549%5D%2C+%5B8.653519%2C+49.364273%5D%2C+%5B8.654112%2C+49.36402%5D%2C+%5B8.654768%2C+49.363737%5D%2C+%5B8.655407%2C+49.363473%5D%2C+%5B8.656377%2C+49.363115%5D%2C+%5B8.657142%2C+49.362813%5D%2C+%5B8.657764%2C+49.363277%5D%2C+%5B8.658185%2C+49.363054%5D%2C+%5B8.658651%2C+49.362837%5D%2C+%5B8.659164%2C+49.362571%5D%2C+%5B8.658051%2C+49.361776%5D%2C+%5B8.657009%2C+49.360179%5D%2C+%5B8.656454%2C+49.35929%5D%2C+%5B8.655814%2C+49.358138%5D%2C+%5B8.655354%2C+49.357298%5D%2C+%5B8.654879%2C+49.356558%5D%2C+%5B8.654787%2C+49.35643%5D%2C+%5B8.654561%2C+49.356112%5D%2C+%5B8.653362%2C+49.356263%5D%2C+%5B8.652987%2C+49.35577%5D%2C+%5B8.652544%2C+49.355287%5D%2C+%5B8.652104%2C+49.35458%5D%2C+%5B8.651277%2C+49.353254%5D%2C+%5B8.651454%2C+49.353204%5D%2C+%5B8.651636%2C+49.353188%5D%2C+%5B8.65183%2C+49.353191%5D%2C+%5B8.652046%2C+49.353203%5D%2C+%5B8.652348%2C+49.353246%5D%2C+%5B8.652615%2C+49.353273%5D%2C+%5B8.652844%2C+49.353279%5D%2C+%5B8.653124%2C+49.353277%5D%2C+%5B8.653474%2C+49.353258%5D%2C+%5B8.653742%2C+49.353245%5D%2C+%5B8.654053%2C+49.353215%5D%2C+%5B8.654541%2C+49.353146%5D%2C+%5B8.655319%2C+49.353021%5D%2C+%5B8.656788%2C+49.352777%5D%2C+%5B8.657594%2C+49.352635%5D%2C+%5B8.657702%2C+49.352622%5D%2C+%5B8.657803%2C+49.352609%5D%2C+%5B8.658004%2C+49.352578%5D%2C+%5B8.658147%2C+49.352565%5D%2C+%5B8.657938%2C+49.35276%5D%2C+%5B8.657306%2C+49.353303%5D%2C+%5B8.657404%2C+49.353355%5D%2C+%5B8.656818%2C+49.353732%5D%2C+%5B8.656362%2C+49.354017%5D%2C+%5B8.656689%2C+49.35436%5D%2C+%5B8.657243%2C+49.355195%5D%2C+%5B8.658874%2C+49.354938%5D%2C+%5B8.660099%2C+49.354864%5D%2C+%5B8.660662%2C+49.354831%5D%2C+%5B8.660554%2C+49.35385%5D%2C+%5B8.661186%2C+49.353988%5D%2C+%5B8.661529%2C+49.354066%5D%2C+%5B8.662499%2C+49.354314%5D%2C+%5B8.663203%2C+49.354396%5D%2C+%5B8.663578%2C+49.353585%5D%2C+%5B8.664184%2C+49.353663%5D%2C+%5B8.665018%2C+49.353769%5D%2C+%5B8.664862%2C+49.354592%5D%2C+%5B8.664516%2C+49.356424%5D%2C+%5B8.664343%2C+49.35714%5D%2C+%5B8.664257%2C+49.357496%5D%2C+%5B8.664523%2C+49.357548%5D%2C+%5B8.664876%2C+49.357593%5D%2C+%5B8.667029%2C+49.35798%5D%2C+%5B8.66801%2C+49.358065%5D%2C+%5B8.668543%2C+49.358111%5D%2C+%5B8.668764%2C+49.358127%5D%2C+%5B8.669807%2C+49.358003%5D%2C+%5B8.671465%2C+49.357805%5D%2C+%5B8.67168%2C+49.357818%5D%2C+%5B8.671905%2C+49.359187%5D%2C+%5B8.672189%2C+49.360595%5D%2C+%5B8.672443%2C+49.361521%5D%2C+%5B8.6742%2C+49.361218%5D%2C+%5B8.675834%2C+49.360668%5D%2C+%5B8.675955%2C+49.360221%5D%2C+%5B8.677248%2C+49.360356%5D%2C+%5B8.678227%2C+49.360428%5D%2C+%5B8.67875%2C+49.360442%5D%2C+%5B8.679817%2C+49.360427%5D%2C+%5B8.679921%2C+49.360425%5D%2C+%5B8.682084%2C+49.360389%5D%2C+%5B8.682014%2C+49.359907%5D%2C+%5B8.684247%2C+49.359817%5D%2C+%5B8.684378%2C+49.359781%5D%2C+%5B8.68706%2C+49.359824%5D%2C+%5B8.687067%2C+49.35976%5D%2C+%5B8.687186%2C+49.359138%5D%2C+%5B8.687237%2C+49.35886%5D%2C+%5B8.689029%2C+49.3589%5D%2C+%5B8.689213%2C+49.358942%5D%2C+%5B8.690288%2C+49.358929%5D%2C+%5B8.690684%2C+49.358899%5D%2C+%5B8.691469%2C+49.358787%5D%2C+%5B8.691399%2C+49.358492%5D%2C+%5B8.692384%2C+49.358415%5D%2C+%5B8.692438%2C+49.358513%5D%2C+%5B8.692875%2C+49.358386%5D%2C+%5B8.692904%2C+49.358507%5D%2C+%5B8.693627%2C+49.358371%5D%2C+%5B8.693654%2C+49.35848%5D%2C+%5B8.694136%2C+49.358357%5D%2C+%5B8.694369%2C+49.358679%5D%2C+%5B8.69466%2C+49.358603%5D%2C+%5B8.694621%2C+49.358537%5D%2C+%5B8.694444%2C+49.358239%5D%2C+%5B8.6964%2C+49.357749%5D%2C+%5B8.696686%2C+49.357789%5D%2C+%5B8.696953%2C+49.358039%5D%2C+%5B8.698234%2C+49.357421%5D%2C+%5B8.699042%2C+49.357005%5D%2C+%5B8.699133%2C+49.357005%5D%2C+%5B8.699224%2C+49.357003%5D%2C+%5B8.699468%2C+49.356867%5D%2C+%5B8.70005%2C+49.356571%5D%2C+%5B8.700092%2C+49.35655%5D%2C+%5B8.700541%2C+49.356327%5D%2C+%5B8.701206%2C+49.356063%5D%2C+%5B8.701769%2C+49.355846%5D%2C+%5B8.701847%2C+49.355815%5D%2C+%5B8.70249%2C+49.355716%5D%2C+%5B8.703321%2C+49.355722%5D%2C+%5B8.703979%2C+49.355745%5D%2C+%5B8.704667%2C+49.355786%5D%2C+%5B8.705234%2C+49.355848%5D%2C+%5B8.705404%2C+49.355871%5D%2C+%5B8.705776%2C+49.35592%5D%2C+%5B8.706353%2C+49.356042%5D%2C+%5B8.706882%2C+49.356123%5D%2C+%5B8.708303%2C+49.356341%5D%2C+%5B8.70964%2C+49.35658%5D%2C+%5B8.71027%2C+49.355542%5D%2C+%5B8.710889%2C+49.35511%5D%2C+%5B8.711249%2C+49.35521%5D%2C+%5B8.7114%2C+49.35534%5D%2C+%5B8.711683%2C+49.355525%5D%2C+%5B8.711946%2C+49.355618%5D%2C+%5B8.712513%2C+49.355659%5D%2C+%5B8.71339%2C+49.355695%5D%2C+%5B8.71423%2C+49.355746%5D%2C+%5B8.715084%2C+49.355951%5D%2C+%5B8.715987%2C+49.35624%5D%2C+%5B8.716396%2C+49.356342%5D%2C+%5B8.718652%2C+49.356379%5D%2C+%5B8.71896%2C+49.356351%5D%2C+%5B8.719342%2C+49.356762%5D%2C+%5B8.719472%2C+49.357065%5D%2C+%5B8.71971%2C+49.357302%5D%2C+%5B8.720122%2C+49.357284%5D%2C+%5B8.721267%2C+49.357192%5D%2C+%5B8.721461%2C+49.357173%5D%2C+%5B8.722389%2C+49.357253%5D%2C+%5B8.723668%2C+49.357439%5D%2C+%5B8.724196%2C+49.357602%5D%2C+%5B8.724937%2C+49.357921%5D%2C+%5B8.72524%2C+49.358308%5D%2C+%5B8.725498%2C+49.358663%5D%2C+%5B8.725599%2C+49.358803%5D%2C+%5B8.726016%2C+49.359476%5D%2C+%5B8.726055%2C+49.360045%5D%2C+%5B8.726094%2C+49.360374%5D%2C+%5B8.727113%2C+49.361989%5D%2C+%5B8.727202%2C+49.362889%5D%2C+%5B8.727423%2C+49.364132%5D%2C+%5B8.727717%2C+49.365509%5D%2C+%5B8.728446%2C+49.366441%5D%2C+%5B8.728671%2C+49.366705%5D%2C+%5B8.728942%2C+49.366897%5D%2C+%5B8.730404%2C+49.367933%5D%2C+%5B8.729929%2C+49.368208%5D%2C+%5B8.728541%2C+49.368817%5D%2C+%5B8.72836%2C+49.368682%5D%2C+%5B8.726259%2C+49.369455%5D%2C+%5B8.725357%2C+49.370066%5D%2C+%5B8.725576%2C+49.37022%5D%2C+%5B8.725009%2C+49.371211%5D%2C+%5B8.724729%2C+49.37225%5D%2C+%5B8.724401%2C+49.373496%5D%2C+%5B8.724479%2C+49.373747%5D%2C+%5B8.724841%2C+49.373956%5D%2C+%5B8.727404%2C+49.375554%5D%2C+%5B8.72822%2C+49.374821%5D%2C+%5B8.729138%2C+49.374009%5D%2C+%5B8.730155%2C+49.373179%5D%2C+%5B8.730385%2C+49.373252%5D%2C+%5B8.730507%2C+49.373311%5D%2C+%5B8.731437%2C+49.372716%5D%2C+%5B8.732328%2C+49.372224%5D%2C+%5B8.733929%2C+49.372675%5D%2C+%5B8.735724%2C+49.372956%5D%2C+%5B8.736319%2C+49.373324%5D%2C+%5B8.737564%2C+49.374161%5D%2C+%5B8.738416%2C+49.374491%5D%2C+%5B8.740049%2C+49.374553%5D%2C+%5B8.740729%2C+49.374442%5D%2C+%5B8.741468%2C+49.373924%5D%2C+%5B8.742963%2C+49.373108%5D%2C+%5B8.744141%2C+49.372795%5D%2C+%5B8.745571%2C+49.37295%5D%2C+%5B8.746882%2C+49.373148%5D%2C+%5B8.747531%2C+49.373299%5D%2C+%5B8.747803%2C+49.373403%5D%2C+%5B8.74801%2C+49.373481%5D%2C+%5B8.749031%2C+49.373788%5D%2C+%5B8.749349%2C+49.373809%5D%2C+%5B8.749506%2C+49.373874%5D%2C+%5B8.749682%2C+49.374157%5D%2C+%5B8.749784%2C+49.374269%5D%2C+%5B8.749979%2C+49.37486%5D%2C+%5B8.750254%2C+49.375234%5D%2C+%5B8.750486%2C+49.375439%5D%2C+%5B8.751287%2C+49.375853%5D%2C+%5B8.751986%2C+49.376167%5D%2C+%5B8.752481%2C+49.376371%5D%2C+%5B8.75318%2C+49.376893%5D%2C+%5B8.753542%2C+49.377091%5D%2C+%5B8.754226%2C+49.377357%5D%2C+%5B8.754767%2C+49.377572%5D%2C+%5B8.754718%2C+49.377723%5D%2C+%5B8.754876%2C+49.377766%5D%2C+%5B8.75543%2C+49.377841%5D%2C+%5B8.756198%2C+49.37791%5D%2C+%5B8.756906%2C+49.377922%5D%2C+%5B8.75795%2C+49.377906%5D%2C+%5B8.758486%2C+49.377899%5D%2C+%5B8.758903%2C+49.377943%5D%2C+%5B8.759138%2C+49.377807%5D%2C+%5B8.759187%2C+49.377808%5D%2C+%5B8.759786%2C+49.377905%5D%2C+%5B8.760544%2C+49.378024%5D%2C+%5B8.762615%2C+49.378444%5D%2C+%5B8.763084%2C+49.378532%5D%2C+%5B8.763661%2C+49.378542%5D%2C+%5B8.76537%2C+49.378518%5D%2C+%5B8.766125%2C+49.378539%5D%2C+%5B8.766754%2C+49.378608%5D%2C+%5B8.76849%2C+49.379027%5D%2C+%5B8.76883%2C+49.379193%5D%2C+%5B8.768381%2C+49.379612%5D%2C+%5B8.767516%2C+49.380685%5D%2C+%5B8.766845%2C+49.381341%5D%2C+%5B8.766279%2C+49.382016%5D%2C+%5B8.765944%2C+49.3827%5D%2C+%5B8.76528%2C+49.383389%5D%2C+%5B8.764256%2C+49.384184%5D%2C+%5B8.763735%2C+49.384783%5D%2C+%5B8.76338%2C+49.385218%5D%2C+%5B8.763158%2C+49.385451%5D%2C+%5B8.762978%2C+49.385762%5D%2C+%5B8.762909%2C+49.385993%5D%2C+%5B8.762887%2C+49.386438%5D%2C+%5B8.762991%2C+49.386902%5D%2C+%5B8.762978%2C+49.387249%5D%2C+%5B8.762899%2C+49.387516%5D%2C+%5B8.763192%2C+49.387952%5D%2C+%5B8.764231%2C+49.387498%5D%2C+%5B8.766654%2C+49.387178%5D%2C+%5B8.767235%2C+49.387062%5D%2C+%5B8.767759%2C+49.386865%5D%2C+%5B8.768178%2C+49.386789%5D%2C+%5B8.768518%2C+49.386845%5D%2C+%5B8.768945%2C+49.386974%5D%2C+%5B8.76931%2C+49.387141%5D%2C+%5B8.769787%2C+49.387254%5D%2C+%5B8.770146%2C+49.387651%5D%2C+%5B8.771331%2C+49.388121%5D%2C+%5B8.771843%2C+49.388408%5D%2C+%5B8.772677%2C+49.388667%5D%2C+%5B8.772941%2C+49.388877%5D%2C+%5B8.773016%2C+49.389213%5D%2C+%5B8.773661%2C+49.389392%5D%2C+%5B8.773463%2C+49.389673%5D%2C+%5B8.773409%2C+49.390055%5D%2C+%5B8.77366%2C+49.390523%5D%2C+%5B8.773878%2C+49.390825%5D%2C+%5B8.774229%2C+49.390979%5D%2C+%5B8.774594%2C+49.391209%5D%2C+%5B8.775114%2C+49.391654%5D%2C+%5B8.775375%2C+49.392035%5D%2C+%5B8.775841%2C+49.392457%5D%2C+%5B8.775179%2C+49.393053%5D%2C+%5B8.776011%2C+49.393547%5D%2C+%5B8.776472%2C+49.394054%5D%2C+%5B8.776103%2C+49.394241%5D%2C+%5B8.775839%2C+49.394462%5D%2C+%5B8.775613%2C+49.394778%5D%2C+%5B8.775432%2C+49.39513%5D%2C+%5B8.775357%2C+49.395498%5D%2C+%5B8.775351%2C+49.39589%5D%2C+%5B8.775405%2C+49.396353%5D%2C+%5B8.77561%2C+49.396942%5D%2C+%5B8.775853%2C+49.397499%5D%2C+%5B8.77627%2C+49.398226%5D%2C+%5B8.776723%2C+49.39895%5D%2C+%5B8.777297%2C+49.399896%5D%2C+%5B8.777925%2C+49.401157%5D%2C+%5B8.778345%2C+49.40224%5D%2C+%5B8.779285%2C+49.402018%5D%2C+%5B8.78048%2C+49.4018%5D%2C+%5B8.781842%2C+49.401604%5D%2C+%5B8.783078%2C+49.401452%5D%2C+%5B8.783982%2C+49.401369%5D%2C+%5B8.784682%2C+49.401329%5D%2C+%5B8.785426%2C+49.40138%5D%2C+%5B8.78645%2C+49.401532%5D%2C+%5B8.787479%2C+49.40178%5D%2C+%5B8.789244%2C+49.402355%5D%2C+%5B8.790122%2C+49.40271%5D%2C+%5B8.7907%2C+49.403068%5D%2C+%5B8.791436%2C+49.403734%5D%2C+%5B8.792046%2C+49.404237%5D%2C+%5B8.792756%2C+49.404675%5D%2C+%5B8.793315%2C+49.405004%5D%2C+%5B8.793591%2C+49.405187%5D%2C+%5B8.793708%2C+49.405634%5D%2C+%5B8.793657%2C+49.406063%5D%2C+%5B8.793701%2C+49.40635%5D%2C+%5B8.793964%2C+49.406931%5D%2C+%5B8.79405%2C+49.40719%5D%2C+%5B8.793454%2C+49.408909%5D%2C+%5B8.79312%2C+49.409948%5D%2C+%5B8.793072%2C+49.410423%5D%2C+%5B8.792942%2C+49.411043%5D%2C+%5B8.792821%2C+49.411647%5D%2C+%5B8.792762%2C+49.411853%5D%2C+%5B8.792359%2C+49.412349%5D%2C+%5B8.790377%2C+49.414782%5D%2C+%5B8.790199%2C+49.414964%5D%2C+%5B8.790132%2C+49.415286%5D%2C+%5B8.789943%2C+49.416379%5D%2C+%5B8.78948%2C+49.417608%5D%2C+%5B8.789429%2C+49.418818%5D%2C+%5B8.789394%2C+49.419256%5D%2C+%5B8.789554%2C+49.419831%5D%2C+%5B8.789819%2C+49.420577%5D%2C+%5B8.789964%2C+49.421041%5D%2C+%5B8.790162%2C+49.421213%5D%2C+%5B8.791171%2C+49.42288%5D%2C+%5B8.791273%2C+49.423259%5D%2C+%5B8.790903%2C+49.424051%5D%2C+%5B8.789978%2C+49.425944%5D%2C+%5B8.789643%2C+49.42708%5D%2C+%5B8.78907%2C+49.430067%5D%2C+%5B8.78834%2C+49.431146%5D%2C+%5B8.786537%2C+49.432578%5D%2C+%5B8.779296%2C+49.432764%5D%2C+%5B8.777773%2C+49.432907%5D%2C+%5B8.777268%2C+49.433012%5D%2C+%5B8.776973%2C+49.433155%5D%2C+%5B8.776765%2C+49.433357%5D%2C+%5B8.775986%2C+49.434071%5D%2C+%5B8.774992%2C+49.43454%5D%2C+%5B8.774022%2C+49.434993%5D%2C+%5B8.773641%2C+49.435318%5D%2C+%5B8.773252%2C+49.435419%5D%2C+%5B8.772923%2C+49.435463%5D%2C+%5B8.77217%2C+49.435536%5D%2C+%5B8.77045%2C+49.435737%5D%2C+%5B8.769482%2C+49.436046%5D%2C+%5B8.766398%2C+49.437365%5D%2C+%5B8.766515%2C+49.440274%5D%2C+%5B8.766223%2C+49.440275%5D%2C+%5B8.76637%2C+49.441863%5D%2C+%5B8.766334%2C+49.443584%5D%2C+%5B8.764728%2C+49.446047%5D%2C+%5B8.761766%2C+49.448135%5D%2C+%5B8.761703%2C+49.450618%5D%2C+%5B8.761818%2C+49.450806%5D%2C+%5B8.762051%2C+49.450947%5D%2C+%5B8.763169%2C+49.451433%5D%2C+%5B8.764276%2C+49.451893%5D%2C+%5B8.765277%2C+49.452469%5D%2C+%5B8.766319%2C+49.453103%5D%2C+%5B8.767107%2C+49.453699%5D%2C+%5B8.767706%2C+49.454192%5D%2C+%5B8.765332%2C+49.455547%5D%2C+%5B8.763575%2C+49.456368%5D%2C+%5B8.76329%2C+49.456467%5D%2C+%5B8.762939%2C+49.456488%5D%2C+%5B8.76055%2C+49.456573%5D%2C+%5B8.758634%2C+49.456662%5D%2C+%5B8.757555%2C+49.456702%5D%2C+%5B8.757041%2C+49.457473%5D%2C+%5B8.756618%2C+49.457934%5D%2C+%5B8.756062%2C+49.458405%5D%2C+%5B8.755408%2C+49.458854%5D%2C+%5B8.754686%2C+49.459468%5D%2C+%5B8.754705%2C+49.459642%5D%2C+%5B8.753986%2C+49.459693%5D%2C+%5B8.753099%2C+49.459548%5D%2C+%5B8.75158%2C+49.459204%5D%2C+%5B8.750438%2C+49.458958%5D%2C+%5B8.750091%2C+49.459072%5D%2C+%5B8.748992%2C+49.459252%5D%2C+%5B8.747833%2C+49.459441%5D%2C+%5B8.746352%2C+49.459567%5D%2C+%5B8.74547%2C+49.459614%5D%2C+%5B8.745235%2C+49.459571%5D%2C+%5B8.744884%2C+49.459434%5D%2C+%5B8.744315%2C+49.459159%5D%2C+%5B8.743336%2C+49.458648%5D%2C+%5B8.74322%2C+49.458497%5D%2C+%5B8.74324%2C+49.458378%5D%2C+%5B8.743121%2C+49.458305%5D%2C+%5B8.742643%2C+49.45808%5D%2C+%5B8.741969%2C+49.45777%5D%2C+%5B8.741674%2C+49.457558%5D%2C+%5B8.741746%2C+49.457041%5D%2C+%5B8.741807%2C+49.456563%5D%2C+%5B8.741842%2C+49.456478%5D%2C+%5B8.742048%2C+49.4564%5D%2C+%5B8.74257%2C+49.456328%5D%2C+%5B8.74305%2C+49.456335%5D%2C+%5B8.743558%2C+49.456352%5D%2C+%5B8.744051%2C+49.456283%5D%2C+%5B8.744436%2C+49.456168%5D%2C+%5B8.744628%2C+49.456101%5D%2C+%5B8.744776%2C+49.456069%5D%2C+%5B8.744954%2C+49.456089%5D%2C+%5B8.745101%2C+49.456082%5D%2C+%5B8.745388%2C+49.455974%5D%2C+%5B8.745895%2C+49.455754%5D%2C+%5B8.746052%2C+49.455642%5D%2C+%5B8.746083%2C+49.455363%5D%2C+%5B8.746078%2C+49.455054%5D%2C+%5B8.746063%2C+49.454896%5D%2C+%5B8.745975%2C+49.454771%5D%2C+%5B8.745912%2C+49.454691%5D%2C+%5B8.745943%2C+49.454522%5D%2C+%5B8.746025%2C+49.45416%5D%2C+%5B8.746118%2C+49.453701%5D%2C+%5B8.746201%2C+49.453499%5D%2C+%5B8.746235%2C+49.453234%5D%2C+%5B8.745966%2C+49.452626%5D%2C+%5B8.745586%2C+49.451991%5D%2C+%5B8.744871%2C+49.451023%5D%2C+%5B8.744719%2C+49.450685%5D%2C+%5B8.744556%2C+49.450429%5D%2C+%5B8.744724%2C+49.450278%5D%2C+%5B8.74472%2C+49.450033%5D%2C+%5B8.744778%2C+49.449761%5D%2C+%5B8.745026%2C+49.449477%5D%2C+%5B8.745437%2C+49.449085%5D%2C+%5B8.745681%2C+49.448824%5D%2C+%5B8.745748%2C+49.448674%5D%2C+%5B8.745808%2C+49.448379%5D%2C+%5B8.745854%2C+49.448142%5D%2C+%5B8.745742%2C+49.447418%5D%2C+%5B8.7457%2C+49.446891%5D%2C+%5B8.739206%2C+49.446386%5D%2C+%5B8.739212%2C+49.44694%5D%2C+%5B8.738431%2C+49.448017%5D%2C+%5B8.738008%2C+49.448423%5D%2C+%5B8.737318%2C+49.44906%5D%2C+%5B8.737083%2C+49.449171%5D%2C+%5B8.736852%2C+49.449237%5D%2C+%5B8.736541%2C+49.449242%5D%2C+%5B8.735799%2C+49.449127%5D%2C+%5B8.735152%2C+49.448956%5D%2C+%5B8.734623%2C+49.44883%5D%2C+%5B8.732748%2C+49.448569%5D%2C+%5B8.730015%2C+49.448373%5D%2C+%5B8.726439%2C+49.448213%5D%2C+%5B8.725438%2C+49.448206%5D%2C+%5B8.724195%2C+49.448452%5D%2C+%5B8.723635%2C+49.448579%5D%2C+%5B8.722897%2C+49.448821%5D%2C+%5B8.722459%2C+49.449016%5D%2C+%5B8.722077%2C+49.449185%5D%2C+%5B8.721853%2C+49.449345%5D%2C+%5B8.721696%2C+49.449503%5D%2C+%5B8.721441%2C+49.449815%5D%2C+%5B8.721023%2C+49.450238%5D%2C+%5B8.720491%2C+49.450545%5D%2C+%5B8.720086%2C+49.450745%5D%2C+%5B8.719614%2C+49.451065%5D%2C+%5B8.718989%2C+49.451482%5D%2C+%5B8.718324%2C+49.451829%5D%2C+%5B8.717828%2C+49.452039%5D%2C+%5B8.717415%2C+49.452118%5D%2C+%5B8.716995%2C+49.452187%5D%2C+%5B8.716368%2C+49.452291%5D%2C+%5B8.715647%2C+49.452383%5D%2C+%5B8.715174%2C+49.45242%5D%2C+%5B8.714813%2C+49.452338%5D%2C+%5B8.714396%2C+49.452172%5D%2C+%5B8.714027%2C+49.451964%5D%2C+%5B8.713729%2C+49.451763%5D%2C+%5B8.713448%2C+49.451547%5D%2C+%5B8.71308%2C+49.451414%5D%2C+%5B8.712981%2C+49.451337%5D%2C+%5B8.712907%2C+49.451188%5D%2C+%5B8.712618%2C+49.450635%5D%2C+%5B8.712221%2C+49.450263%5D%2C+%5B8.712063%2C+49.450181%5D%2C+%5B8.711923%2C+49.450062%5D%2C+%5B8.711712%2C+49.449848%5D%2C+%5B8.711383%2C+49.449483%5D%2C+%5B8.710697%2C+49.449013%5D%2C+%5B8.709519%2C+49.447725%5D%2C+%5B8.709467%2C+49.447501%5D%2C+%5B8.709412%2C+49.446647%5D%2C+%5B8.709325%2C+49.446198%5D%2C+%5B8.708958%2C+49.446156%5D%2C+%5B8.708062%2C+49.445948%5D%2C+%5B8.707527%2C+49.44589%5D%2C+%5B8.706733%2C+49.445857%5D%2C+%5B8.706043%2C+49.445872%5D%2C+%5B8.705379%2C+49.445924%5D%2C+%5B8.704486%2C+49.446022%5D%2C+%5B8.703989%2C+49.446%5D%2C+%5B8.703226%2C+49.44592%5D%2C+%5B8.702235%2C+49.445819%5D%2C+%5B8.700441%2C+49.445474%5D%2C+%5B8.698009%2C+49.445025%5D%2C+%5B8.696864%2C+49.444866%5D%2C+%5B8.696436%2C+49.444666%5D%2C+%5B8.695967%2C+49.444555%5D%2C+%5B8.695515%2C+49.444586%5D%2C+%5B8.693686%2C+49.444206%5D%2C+%5B8.692734%2C+49.444117%5D%2C+%5B8.692166%2C+49.444018%5D%2C+%5B8.691707%2C+49.443845%5D%2C+%5B8.691244%2C+49.44365%5D%2C+%5B8.690496%2C+49.443236%5D%2C+%5B8.68937%2C+49.443263%5D%2C+%5B8.687857%2C+49.443212%5D%2C+%5B8.687569%2C+49.443035%5D%2C+%5B8.687363%2C+49.443008%5D%2C+%5B8.686799%2C+49.443048%5D%2C+%5B8.686065%2C+49.443213%5D%2C+%5B8.685572%2C+49.443319%5D%2C+%5B8.685446%2C+49.443329%5D%2C+%5B8.68496%2C+49.443355%5D%2C+%5B8.684607%2C+49.44354%5D%2C+%5B8.6843%2C+49.443671%5D%2C+%5B8.683887%2C+49.443768%5D%2C+%5B8.683496%2C+49.443878%5D%2C+%5B8.682964%2C+49.444%5D%2C+%5B8.682677%2C+49.443971%5D%2C+%5B8.682335%2C+49.443862%5D%2C+%5B8.682116%2C+49.443773%5D%2C+%5B8.681657%2C+49.443692%5D%2C+%5B8.681244%2C+49.443675%5D%2C+%5B8.680796%2C+49.443534%5D%2C+%5B8.680393%2C+49.443483%5D%2C+%5B8.67967%2C+49.443133%5D%2C+%5B8.679113%2C+49.44302%5D%2C+%5B8.679192%2C+49.442698%5D%2C+%5B8.678359%2C+49.442592%5D%2C+%5B8.678334%2C+49.442624%5D%2C+%5B8.677207%2C+49.442494%5D%2C+%5B8.677012%2C+49.442391%5D%2C+%5B8.676933%2C+49.442349%5D%2C+%5B8.676097%2C+49.442199%5D%2C+%5B8.675185%2C+49.442035%5D%2C+%5B8.674777%2C+49.441968%5D%2C+%5B8.673293%2C+49.441504%5D%2C+%5B8.672861%2C+49.441253%5D%2C+%5B8.67274%2C+49.441326%5D%2C+%5B8.672341%2C+49.441125%5D%2C+%5B8.671575%2C+49.440834%5D%2C+%5B8.670761%2C+49.441343%5D%2C+%5B8.67033%2C+49.441494%5D%2C+%5B8.669915%2C+49.441467%5D%2C+%5B8.668932%2C+49.441262%5D%2C+%5B8.667104%2C+49.440835%5D%2C+%5B8.666264%2C+49.440772%5D%2C+%5B8.665848%2C+49.44064%5D%2C+%5B8.665677%2C+49.440536%5D%2C+%5B8.665516%2C+49.440349%5D%2C+%5B8.665451%2C+49.4403%5D%2C+%5B8.665403%2C+49.440276%5D%2C+%5B8.665344%2C+49.440267%5D%2C+%5B8.665214%2C+49.440227%5D%2C+%5B8.663494%2C+49.439941%5D%2C+%5B8.663245%2C+49.439948%5D%2C+%5B8.663238%2C+49.439857%5D%2C+%5B8.663046%2C+49.43963%5D%2C+%5B8.662637%2C+49.439686%5D%2C+%5B8.662439%2C+49.439689%5D%2C+%5B8.662374%2C+49.439664%5D%2C+%5B8.661735%2C+49.439538%5D%2C+%5B8.66046%2C+49.439285%5D%2C+%5B8.658385%2C+49.438873%5D%2C+%5B8.658267%2C+49.439039%5D%2C+%5B8.657003%2C+49.438758%5D%2C+%5B8.656308%2C+49.438606%5D%2C+%5B8.65531%2C+49.439943%5D%2C+%5B8.653394%2C+49.439318%5D%2C+%5B8.649054%2C+49.437866%5D%2C+%5B8.648862%2C+49.437785%5D%2C+%5B8.648968%2C+49.437693%5D%2C+%5B8.648204%2C+49.437252%5D%2C+%5B8.647218%2C+49.436878%5D%2C+%5B8.646552%2C+49.436626%5D%2C+%5B8.646193%2C+49.436973%5D%2C+%5B8.646016%2C+49.437132%5D%2C+%5B8.645786%2C+49.437345%5D%2C+%5B8.645488%2C+49.437604%5D%2C+%5B8.645159%2C+49.437851%5D%2C+%5B8.644754%2C+49.438187%5D%2C+%5B8.644168%2C+49.438623%5D%2C+%5B8.643741%2C+49.438944%5D%2C+%5B8.643149%2C+49.439309%5D%2C+%5B8.64261%2C+49.43961%5D%2C+%5B8.642565%2C+49.439635%5D%2C+%5B8.642246%2C+49.439785%5D%2C+%5B8.641292%2C+49.440204%5D%2C+%5B8.64031%2C+49.440607%5D%2C+%5B8.639305%2C+49.44098%5D%2C+%5B8.638212%2C+49.441336%5D%2C+%5B8.637172%2C+49.441631%5D%2C+%5B8.636078%2C+49.441893%5D%2C+%5B8.634983%2C+49.442126%5D%2C+%5B8.633858%2C+49.442342%5D%2C+%5B8.632702%2C+49.442524%5D%2C+%5B8.631601%2C+49.44272%5D%2C+%5B8.630453%2C+49.442879%5D%2C+%5B8.629367%2C+49.443018%5D%2C+%5B8.628703%2C+49.443115%5D%2C+%5B8.628211%2C+49.441976%5D%2C+%5B8.628012%2C+49.44157%5D%2C+%5B8.627351%2C+49.440827%5D%2C+%5B8.626819%2C+49.440265%5D%2C+%5B8.626616%2C+49.440059%5D%2C+%5B8.626743%2C+49.439998%5D%2C+%5B8.626134%2C+49.439394%5D%2C+%5B8.62331%2C+49.436631%5D%2C+%5B8.623037%2C+49.436356%5D%2C+%5B8.622925%2C+49.436225%5D%2C+%5B8.622831%2C+49.436102%5D%2C+%5B8.62272%2C+49.435915%5D%2C+%5B8.622619%2C+49.43575%5D%2C+%5B8.622521%2C+49.435595%5D%2C+%5B8.622406%2C+49.435412%5D%2C+%5B8.622309%2C+49.435279%5D%2C+%5B8.622204%2C+49.435144%5D%2C+%5B8.621395%2C+49.434225%5D%2C+%5B8.621165%2C+49.433964%5D%2C+%5B8.621049%2C+49.433843%5D%2C+%5B8.620927%2C+49.433893%5D%2C+%5B8.619493%2C+49.432264%5D%2C+%5B8.61626%2C+49.428621%5D%2C+%5B8.615974%2C+49.428303%5D%2C+%5B8.61531%2C+49.427884%5D%2C+%5B8.609952%2C+49.424382%5D%2C+%5B8.609733%2C+49.424242%5D%2C+%5B8.605472%2C+49.425826%5D%2C+%5B8.599884%2C+49.427972%5D%2C+%5B8.598382%2C+49.428508%5D%2C+%5B8.59849%2C+49.428044%5D%2C+%5B8.59823%2C+49.428143%5D%2C+%5B8.593259%2C+49.430025%5D%2C+%5B8.592963%2C+49.430133%5D%2C+%5B8.590778%2C+49.427735%5D%2C+%5B8.59045%2C+49.427367%5D%2C+%5B8.590054%2C+49.427347%5D%2C+%5B8.589757%2C+49.427329%5D%2C+%5B8.589435%2C+49.427296%5D%2C+%5B8.588442%2C+49.427151%5D%2C+%5B8.587764%2C+49.427038%5D%2C+%5B8.58724%2C+49.426958%5D%2C+%5B8.587079%2C+49.426934%5D%2C+%5B8.586232%2C+49.426846%5D%2C+%5B8.584079%2C+49.4266%5D%2C+%5B8.583508%2C+49.426541%5D%2C+%5B8.582919%2C+49.426506%5D%2C+%5B8.582023%2C+49.426473%5D%2C+%5B8.581379%2C+49.42645%5D%2C+%5B8.579833%2C+49.426199%5D%2C+%5B8.577791%2C+49.425274%5D%2C+%5B8.577288%2C+49.425085%5D%2C+%5B8.575385%2C+49.424356%5D%2C+%5B8.57529%2C+49.424422%5D%2C+%5B8.574243%2C+49.424021%5D%2C+%5B8.573179%2C+49.4236%5D%5D%5D%7D%2C+%22properties%22%3A+%7B%7D%2C+%22id%22%3A+0%7D%5D%7D&time=2008-01-01%2F%2FP1M + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '30335' + content-type: + - application/x-www-form-urlencoded + host: + - api.ohsome.org + user-agent: + - ohsome-quality-api/1.9.0 + method: POST + uri: https://api.ohsome.org/v1/elements/count + response: + content: "{\n \"attribution\" : {\n \"url\" : \"https://ohsome.org/copyrights\",\n + \ \"text\" : \"\xA9 OpenStreetMap contributors\"\n },\n \"apiVersion\" : + \"1.10.4\",\n \"result\" : [ {\n \"timestamp\" : \"2008-01-01T00:00:00Z\",\n + \ \"value\" : 1.0\n }, {\n \"timestamp\" : \"2008-02-01T00:00:00Z\",\n + \ \"value\" : 1.0\n }, {\n \"timestamp\" : \"2008-03-01T00:00:00Z\",\n + \ \"value\" : 1.0\n }, {\n \"timestamp\" : \"2008-04-01T00:00:00Z\",\n + \ \"value\" : 1.0\n }, {\n \"timestamp\" : \"2008-05-01T00:00:00Z\",\n + \ \"value\" : 1.0\n }, {\n \"timestamp\" : \"2008-06-01T00:00:00Z\",\n + \ \"value\" : 4.0\n }, {\n \"timestamp\" : \"2008-07-01T00:00:00Z\",\n + \ \"value\" : 44.0\n }, {\n \"timestamp\" : \"2008-08-01T00:00:00Z\",\n + \ \"value\" : 114.0\n }, {\n \"timestamp\" : \"2008-09-01T00:00:00Z\",\n + \ \"value\" : 226.0\n }, {\n \"timestamp\" : \"2008-10-01T00:00:00Z\",\n + \ \"value\" : 240.0\n }, {\n \"timestamp\" : \"2008-11-01T00:00:00Z\",\n + \ \"value\" : 250.0\n }, {\n \"timestamp\" : \"2008-12-01T00:00:00Z\",\n + \ \"value\" : 264.0\n }, {\n \"timestamp\" : \"2009-01-01T00:00:00Z\",\n + \ \"value\" : 270.0\n }, {\n \"timestamp\" : \"2009-02-01T00:00:00Z\",\n + \ \"value\" : 273.0\n }, {\n \"timestamp\" : \"2009-03-01T00:00:00Z\",\n + \ \"value\" : 277.0\n }, {\n \"timestamp\" : \"2009-04-01T00:00:00Z\",\n + \ \"value\" : 296.0\n }, {\n \"timestamp\" : \"2009-05-01T00:00:00Z\",\n + \ \"value\" : 304.0\n }, {\n \"timestamp\" : \"2009-06-01T00:00:00Z\",\n + \ \"value\" : 305.0\n }, {\n \"timestamp\" : \"2009-07-01T00:00:00Z\",\n + \ \"value\" : 424.0\n }, {\n \"timestamp\" : \"2009-08-01T00:00:00Z\",\n + \ \"value\" : 428.0\n }, {\n \"timestamp\" : \"2009-09-01T00:00:00Z\",\n + \ \"value\" : 470.0\n }, {\n \"timestamp\" : \"2009-10-01T00:00:00Z\",\n + \ \"value\" : 480.0\n }, {\n \"timestamp\" : \"2009-11-01T00:00:00Z\",\n + \ \"value\" : 496.0\n }, {\n \"timestamp\" : \"2009-12-01T00:00:00Z\",\n + \ \"value\" : 500.0\n }, {\n \"timestamp\" : \"2010-01-01T00:00:00Z\",\n + \ \"value\" : 541.0\n }, {\n \"timestamp\" : \"2010-02-01T00:00:00Z\",\n + \ \"value\" : 553.0\n }, {\n \"timestamp\" : \"2010-03-01T00:00:00Z\",\n + \ \"value\" : 555.0\n }, {\n \"timestamp\" : \"2010-04-01T00:00:00Z\",\n + \ \"value\" : 605.0\n }, {\n \"timestamp\" : \"2010-05-01T00:00:00Z\",\n + \ \"value\" : 608.0\n }, {\n \"timestamp\" : \"2010-06-01T00:00:00Z\",\n + \ \"value\" : 629.0\n }, {\n \"timestamp\" : \"2010-07-01T00:00:00Z\",\n + \ \"value\" : 635.0\n }, {\n \"timestamp\" : \"2010-08-01T00:00:00Z\",\n + \ \"value\" : 653.0\n }, {\n \"timestamp\" : \"2010-09-01T00:00:00Z\",\n + \ \"value\" : 658.0\n }, {\n \"timestamp\" : \"2010-10-01T00:00:00Z\",\n + \ \"value\" : 693.0\n }, {\n \"timestamp\" : \"2010-11-01T00:00:00Z\",\n + \ \"value\" : 693.0\n }, {\n \"timestamp\" : \"2010-12-01T00:00:00Z\",\n + \ \"value\" : 1009.0\n }, {\n \"timestamp\" : \"2011-01-01T00:00:00Z\",\n + \ \"value\" : 5662.0\n }, {\n \"timestamp\" : \"2011-02-01T00:00:00Z\",\n + \ \"value\" : 7188.0\n }, {\n \"timestamp\" : \"2011-03-01T00:00:00Z\",\n + \ \"value\" : 8545.0\n }, {\n \"timestamp\" : \"2011-04-01T00:00:00Z\",\n + \ \"value\" : 8721.0\n }, {\n \"timestamp\" : \"2011-05-01T00:00:00Z\",\n + \ \"value\" : 8918.0\n }, {\n \"timestamp\" : \"2011-06-01T00:00:00Z\",\n + \ \"value\" : 8971.0\n }, {\n \"timestamp\" : \"2011-07-01T00:00:00Z\",\n + \ \"value\" : 9216.0\n }, {\n \"timestamp\" : \"2011-08-01T00:00:00Z\",\n + \ \"value\" : 9335.0\n }, {\n \"timestamp\" : \"2011-09-01T00:00:00Z\",\n + \ \"value\" : 9593.0\n }, {\n \"timestamp\" : \"2011-10-01T00:00:00Z\",\n + \ \"value\" : 9644.0\n }, {\n \"timestamp\" : \"2011-11-01T00:00:00Z\",\n + \ \"value\" : 9657.0\n }, {\n \"timestamp\" : \"2011-12-01T00:00:00Z\",\n + \ \"value\" : 9696.0\n }, {\n \"timestamp\" : \"2012-01-01T00:00:00Z\",\n + \ \"value\" : 9991.0\n }, {\n \"timestamp\" : \"2012-02-01T00:00:00Z\",\n + \ \"value\" : 10337.0\n }, {\n \"timestamp\" : \"2012-03-01T00:00:00Z\",\n + \ \"value\" : 10441.0\n }, {\n \"timestamp\" : \"2012-04-01T00:00:00Z\",\n + \ \"value\" : 10457.0\n }, {\n \"timestamp\" : \"2012-05-01T00:00:00Z\",\n + \ \"value\" : 10674.0\n }, {\n \"timestamp\" : \"2012-06-01T00:00:00Z\",\n + \ \"value\" : 10760.0\n }, {\n \"timestamp\" : \"2012-07-01T00:00:00Z\",\n + \ \"value\" : 10876.0\n }, {\n \"timestamp\" : \"2012-08-01T00:00:00Z\",\n + \ \"value\" : 11396.0\n }, {\n \"timestamp\" : \"2012-09-01T00:00:00Z\",\n + \ \"value\" : 11448.0\n }, {\n \"timestamp\" : \"2012-10-01T00:00:00Z\",\n + \ \"value\" : 11636.0\n }, {\n \"timestamp\" : \"2012-11-01T00:00:00Z\",\n + \ \"value\" : 11685.0\n }, {\n \"timestamp\" : \"2012-12-01T00:00:00Z\",\n + \ \"value\" : 11847.0\n }, {\n \"timestamp\" : \"2013-01-01T00:00:00Z\",\n + \ \"value\" : 11933.0\n }, {\n \"timestamp\" : \"2013-02-01T00:00:00Z\",\n + \ \"value\" : 12159.0\n }, {\n \"timestamp\" : \"2013-03-01T00:00:00Z\",\n + \ \"value\" : 12438.0\n }, {\n \"timestamp\" : \"2013-04-01T00:00:00Z\",\n + \ \"value\" : 13211.0\n }, {\n \"timestamp\" : \"2013-05-01T00:00:00Z\",\n + \ \"value\" : 13883.0\n }, {\n \"timestamp\" : \"2013-06-01T00:00:00Z\",\n + \ \"value\" : 14785.0\n }, {\n \"timestamp\" : \"2013-07-01T00:00:00Z\",\n + \ \"value\" : 14874.0\n }, {\n \"timestamp\" : \"2013-08-01T00:00:00Z\",\n + \ \"value\" : 14991.0\n }, {\n \"timestamp\" : \"2013-09-01T00:00:00Z\",\n + \ \"value\" : 15171.0\n }, {\n \"timestamp\" : \"2013-10-01T00:00:00Z\",\n + \ \"value\" : 15479.0\n }, {\n \"timestamp\" : \"2013-11-01T00:00:00Z\",\n + \ \"value\" : 15886.0\n }, {\n \"timestamp\" : \"2013-12-01T00:00:00Z\",\n + \ \"value\" : 17034.0\n }, {\n \"timestamp\" : \"2014-01-01T00:00:00Z\",\n + \ \"value\" : 18142.0\n }, {\n \"timestamp\" : \"2014-02-01T00:00:00Z\",\n + \ \"value\" : 19207.0\n }, {\n \"timestamp\" : \"2014-03-01T00:00:00Z\",\n + \ \"value\" : 20021.0\n }, {\n \"timestamp\" : \"2014-04-01T00:00:00Z\",\n + \ \"value\" : 20698.0\n }, {\n \"timestamp\" : \"2014-05-01T00:00:00Z\",\n + \ \"value\" : 21002.0\n }, {\n \"timestamp\" : \"2014-06-01T00:00:00Z\",\n + \ \"value\" : 21114.0\n }, {\n \"timestamp\" : \"2014-07-01T00:00:00Z\",\n + \ \"value\" : 21305.0\n }, {\n \"timestamp\" : \"2014-08-01T00:00:00Z\",\n + \ \"value\" : 22057.0\n }, {\n \"timestamp\" : \"2014-09-01T00:00:00Z\",\n + \ \"value\" : 22262.0\n }, {\n \"timestamp\" : \"2014-10-01T00:00:00Z\",\n + \ \"value\" : 22424.0\n }, {\n \"timestamp\" : \"2014-11-01T00:00:00Z\",\n + \ \"value\" : 22602.0\n }, {\n \"timestamp\" : \"2014-12-01T00:00:00Z\",\n + \ \"value\" : 22655.0\n }, {\n \"timestamp\" : \"2015-01-01T00:00:00Z\",\n + \ \"value\" : 22893.0\n }, {\n \"timestamp\" : \"2015-02-01T00:00:00Z\",\n + \ \"value\" : 22943.0\n }, {\n \"timestamp\" : \"2015-03-01T00:00:00Z\",\n + \ \"value\" : 23010.0\n }, {\n \"timestamp\" : \"2015-04-01T00:00:00Z\",\n + \ \"value\" : 23054.0\n }, {\n \"timestamp\" : \"2015-05-01T00:00:00Z\",\n + \ \"value\" : 23104.0\n }, {\n \"timestamp\" : \"2015-06-01T00:00:00Z\",\n + \ \"value\" : 23124.0\n }, {\n \"timestamp\" : \"2015-07-01T00:00:00Z\",\n + \ \"value\" : 23195.0\n }, {\n \"timestamp\" : \"2015-08-01T00:00:00Z\",\n + \ \"value\" : 23217.0\n }, {\n \"timestamp\" : \"2015-09-01T00:00:00Z\",\n + \ \"value\" : 23358.0\n }, {\n \"timestamp\" : \"2015-10-01T00:00:00Z\",\n + \ \"value\" : 23385.0\n }, {\n \"timestamp\" : \"2015-11-01T00:00:00Z\",\n + \ \"value\" : 23440.0\n }, {\n \"timestamp\" : \"2015-12-01T00:00:00Z\",\n + \ \"value\" : 23527.0\n }, {\n \"timestamp\" : \"2016-01-01T00:00:00Z\",\n + \ \"value\" : 23595.0\n }, {\n \"timestamp\" : \"2016-02-01T00:00:00Z\",\n + \ \"value\" : 24197.0\n }, {\n \"timestamp\" : \"2016-03-01T00:00:00Z\",\n + \ \"value\" : 24201.0\n }, {\n \"timestamp\" : \"2016-04-01T00:00:00Z\",\n + \ \"value\" : 24352.0\n }, {\n \"timestamp\" : \"2016-05-01T00:00:00Z\",\n + \ \"value\" : 24530.0\n }, {\n \"timestamp\" : \"2016-06-01T00:00:00Z\",\n + \ \"value\" : 25042.0\n }, {\n \"timestamp\" : \"2016-07-01T00:00:00Z\",\n + \ \"value\" : 25084.0\n }, {\n \"timestamp\" : \"2016-08-01T00:00:00Z\",\n + \ \"value\" : 25261.0\n }, {\n \"timestamp\" : \"2016-09-01T00:00:00Z\",\n + \ \"value\" : 25641.0\n }, {\n \"timestamp\" : \"2016-10-01T00:00:00Z\",\n + \ \"value\" : 25651.0\n }, {\n \"timestamp\" : \"2016-11-01T00:00:00Z\",\n + \ \"value\" : 25699.0\n }, {\n \"timestamp\" : \"2016-12-01T00:00:00Z\",\n + \ \"value\" : 25716.0\n }, {\n \"timestamp\" : \"2017-01-01T00:00:00Z\",\n + \ \"value\" : 25842.0\n }, {\n \"timestamp\" : \"2017-02-01T00:00:00Z\",\n + \ \"value\" : 25935.0\n }, {\n \"timestamp\" : \"2017-03-01T00:00:00Z\",\n + \ \"value\" : 25939.0\n }, {\n \"timestamp\" : \"2017-04-01T00:00:00Z\",\n + \ \"value\" : 25978.0\n }, {\n \"timestamp\" : \"2017-05-01T00:00:00Z\",\n + \ \"value\" : 26076.0\n }, {\n \"timestamp\" : \"2017-06-01T00:00:00Z\",\n + \ \"value\" : 26146.0\n }, {\n \"timestamp\" : \"2017-07-01T00:00:00Z\",\n + \ \"value\" : 26317.0\n }, {\n \"timestamp\" : \"2017-08-01T00:00:00Z\",\n + \ \"value\" : 26306.0\n }, {\n \"timestamp\" : \"2017-09-01T00:00:00Z\",\n + \ \"value\" : 26350.0\n }, {\n \"timestamp\" : \"2017-10-01T00:00:00Z\",\n + \ \"value\" : 26389.0\n }, {\n \"timestamp\" : \"2017-11-01T00:00:00Z\",\n + \ \"value\" : 26415.0\n }, {\n \"timestamp\" : \"2017-12-01T00:00:00Z\",\n + \ \"value\" : 26642.0\n }, {\n \"timestamp\" : \"2018-01-01T00:00:00Z\",\n + \ \"value\" : 26729.0\n }, {\n \"timestamp\" : \"2018-02-01T00:00:00Z\",\n + \ \"value\" : 27613.0\n }, {\n \"timestamp\" : \"2018-03-01T00:00:00Z\",\n + \ \"value\" : 28067.0\n }, {\n \"timestamp\" : \"2018-04-01T00:00:00Z\",\n + \ \"value\" : 28128.0\n }, {\n \"timestamp\" : \"2018-05-01T00:00:00Z\",\n + \ \"value\" : 28173.0\n }, {\n \"timestamp\" : \"2018-06-01T00:00:00Z\",\n + \ \"value\" : 28176.0\n }, {\n \"timestamp\" : \"2018-07-01T00:00:00Z\",\n + \ \"value\" : 28181.0\n }, {\n \"timestamp\" : \"2018-08-01T00:00:00Z\",\n + \ \"value\" : 28182.0\n }, {\n \"timestamp\" : \"2018-09-01T00:00:00Z\",\n + \ \"value\" : 28182.0\n }, {\n \"timestamp\" : \"2018-10-01T00:00:00Z\",\n + \ \"value\" : 28185.0\n }, {\n \"timestamp\" : \"2018-11-01T00:00:00Z\",\n + \ \"value\" : 28231.0\n }, {\n \"timestamp\" : \"2018-12-01T00:00:00Z\",\n + \ \"value\" : 28273.0\n }, {\n \"timestamp\" : \"2019-01-01T00:00:00Z\",\n + \ \"value\" : 28317.0\n }, {\n \"timestamp\" : \"2019-02-01T00:00:00Z\",\n + \ \"value\" : 28335.0\n }, {\n \"timestamp\" : \"2019-03-01T00:00:00Z\",\n + \ \"value\" : 28346.0\n }, {\n \"timestamp\" : \"2019-04-01T00:00:00Z\",\n + \ \"value\" : 28388.0\n }, {\n \"timestamp\" : \"2019-05-01T00:00:00Z\",\n + \ \"value\" : 28411.0\n }, {\n \"timestamp\" : \"2019-06-01T00:00:00Z\",\n + \ \"value\" : 28480.0\n }, {\n \"timestamp\" : \"2019-07-01T00:00:00Z\",\n + \ \"value\" : 28479.0\n }, {\n \"timestamp\" : \"2019-08-01T00:00:00Z\",\n + \ \"value\" : 28476.0\n }, {\n \"timestamp\" : \"2019-09-01T00:00:00Z\",\n + \ \"value\" : 28495.0\n }, {\n \"timestamp\" : \"2019-10-01T00:00:00Z\",\n + \ \"value\" : 28505.0\n }, {\n \"timestamp\" : \"2019-11-01T00:00:00Z\",\n + \ \"value\" : 28509.0\n }, {\n \"timestamp\" : \"2019-12-01T00:00:00Z\",\n + \ \"value\" : 28529.0\n }, {\n \"timestamp\" : \"2020-01-01T00:00:00Z\",\n + \ \"value\" : 28538.0\n }, {\n \"timestamp\" : \"2020-02-01T00:00:00Z\",\n + \ \"value\" : 28542.0\n }, {\n \"timestamp\" : \"2020-03-01T00:00:00Z\",\n + \ \"value\" : 28556.0\n }, {\n \"timestamp\" : \"2020-04-01T00:00:00Z\",\n + \ \"value\" : 28585.0\n }, {\n \"timestamp\" : \"2020-05-01T00:00:00Z\",\n + \ \"value\" : 28614.0\n }, {\n \"timestamp\" : \"2020-06-01T00:00:00Z\",\n + \ \"value\" : 28709.0\n }, {\n \"timestamp\" : \"2020-07-01T00:00:00Z\",\n + \ \"value\" : 28731.0\n }, {\n \"timestamp\" : \"2020-08-01T00:00:00Z\",\n + \ \"value\" : 28756.0\n }, {\n \"timestamp\" : \"2020-09-01T00:00:00Z\",\n + \ \"value\" : 28759.0\n }, {\n \"timestamp\" : \"2020-10-01T00:00:00Z\",\n + \ \"value\" : 28814.0\n }, {\n \"timestamp\" : \"2020-11-01T00:00:00Z\",\n + \ \"value\" : 28828.0\n }, {\n \"timestamp\" : \"2020-12-01T00:00:00Z\",\n + \ \"value\" : 28838.0\n }, {\n \"timestamp\" : \"2021-01-01T00:00:00Z\",\n + \ \"value\" : 28835.0\n }, {\n \"timestamp\" : \"2021-02-01T00:00:00Z\",\n + \ \"value\" : 28845.0\n }, {\n \"timestamp\" : \"2021-03-01T00:00:00Z\",\n + \ \"value\" : 28905.0\n }, {\n \"timestamp\" : \"2021-04-01T00:00:00Z\",\n + \ \"value\" : 28900.0\n }, {\n \"timestamp\" : \"2021-05-01T00:00:00Z\",\n + \ \"value\" : 28900.0\n }, {\n \"timestamp\" : \"2021-06-01T00:00:00Z\",\n + \ \"value\" : 28965.0\n }, {\n \"timestamp\" : \"2021-07-01T00:00:00Z\",\n + \ \"value\" : 28973.0\n }, {\n \"timestamp\" : \"2021-08-01T00:00:00Z\",\n + \ \"value\" : 28979.0\n }, {\n \"timestamp\" : \"2021-09-01T00:00:00Z\",\n + \ \"value\" : 29004.0\n }, {\n \"timestamp\" : \"2021-10-01T00:00:00Z\",\n + \ \"value\" : 29007.0\n }, {\n \"timestamp\" : \"2021-11-01T00:00:00Z\",\n + \ \"value\" : 28999.0\n }, {\n \"timestamp\" : \"2021-12-01T00:00:00Z\",\n + \ \"value\" : 29074.0\n }, {\n \"timestamp\" : \"2022-01-01T00:00:00Z\",\n + \ \"value\" : 29150.0\n }, {\n \"timestamp\" : \"2022-02-01T00:00:00Z\",\n + \ \"value\" : 29234.0\n }, {\n \"timestamp\" : \"2022-03-01T00:00:00Z\",\n + \ \"value\" : 29312.0\n }, {\n \"timestamp\" : \"2022-04-01T00:00:00Z\",\n + \ \"value\" : 29480.0\n }, {\n \"timestamp\" : \"2022-05-01T00:00:00Z\",\n + \ \"value\" : 29513.0\n }, {\n \"timestamp\" : \"2022-06-01T00:00:00Z\",\n + \ \"value\" : 29537.0\n }, {\n \"timestamp\" : \"2022-07-01T00:00:00Z\",\n + \ \"value\" : 29563.0\n }, {\n \"timestamp\" : \"2022-08-01T00:00:00Z\",\n + \ \"value\" : 29574.0\n }, {\n \"timestamp\" : \"2022-09-01T00:00:00Z\",\n + \ \"value\" : 29601.0\n }, {\n \"timestamp\" : \"2022-10-01T00:00:00Z\",\n + \ \"value\" : 29602.0\n }, {\n \"timestamp\" : \"2022-11-01T00:00:00Z\",\n + \ \"value\" : 29607.0\n }, {\n \"timestamp\" : \"2022-12-01T00:00:00Z\",\n + \ \"value\" : 29615.0\n }, {\n \"timestamp\" : \"2023-01-01T00:00:00Z\",\n + \ \"value\" : 29628.0\n }, {\n \"timestamp\" : \"2023-02-01T00:00:00Z\",\n + \ \"value\" : 29650.0\n }, {\n \"timestamp\" : \"2023-03-01T00:00:00Z\",\n + \ \"value\" : 29658.0\n }, {\n \"timestamp\" : \"2023-04-01T00:00:00Z\",\n + \ \"value\" : 29775.0\n }, {\n \"timestamp\" : \"2023-05-01T00:00:00Z\",\n + \ \"value\" : 29721.0\n }, {\n \"timestamp\" : \"2023-06-01T00:00:00Z\",\n + \ \"value\" : 29786.0\n }, {\n \"timestamp\" : \"2023-07-01T00:00:00Z\",\n + \ \"value\" : 29870.0\n }, {\n \"timestamp\" : \"2023-08-01T00:00:00Z\",\n + \ \"value\" : 29934.0\n }, {\n \"timestamp\" : \"2023-09-01T00:00:00Z\",\n + \ \"value\" : 29942.0\n }, {\n \"timestamp\" : \"2023-10-01T00:00:00Z\",\n + \ \"value\" : 29936.0\n }, {\n \"timestamp\" : \"2023-11-01T00:00:00Z\",\n + \ \"value\" : 29947.0\n }, {\n \"timestamp\" : \"2023-12-01T00:00:00Z\",\n + \ \"value\" : 29948.0\n }, {\n \"timestamp\" : \"2024-01-01T00:00:00Z\",\n + \ \"value\" : 29957.0\n }, {\n \"timestamp\" : \"2024-02-01T00:00:00Z\",\n + \ \"value\" : 29964.0\n }, {\n \"timestamp\" : \"2024-03-01T00:00:00Z\",\n + \ \"value\" : 29969.0\n }, {\n \"timestamp\" : \"2024-04-01T00:00:00Z\",\n + \ \"value\" : 29981.0\n }, {\n \"timestamp\" : \"2024-05-01T00:00:00Z\",\n + \ \"value\" : 30034.0\n }, {\n \"timestamp\" : \"2024-06-01T00:00:00Z\",\n + \ \"value\" : 30070.0\n }, {\n \"timestamp\" : \"2024-07-01T00:00:00Z\",\n + \ \"value\" : 30093.0\n }, {\n \"timestamp\" : \"2024-08-01T00:00:00Z\",\n + \ \"value\" : 30077.0\n }, {\n \"timestamp\" : \"2024-09-01T00:00:00Z\",\n + \ \"value\" : 30093.0\n }, {\n \"timestamp\" : \"2024-10-01T00:00:00Z\",\n + \ \"value\" : 30100.0\n }, {\n \"timestamp\" : \"2024-11-01T00:00:00Z\",\n + \ \"value\" : 30259.0\n }, {\n \"timestamp\" : \"2024-12-01T00:00:00Z\",\n + \ \"value\" : 30263.0\n }, {\n \"timestamp\" : \"2025-01-01T00:00:00Z\",\n + \ \"value\" : 30258.0\n }, {\n \"timestamp\" : \"2025-02-01T00:00:00Z\",\n + \ \"value\" : 30337.0\n } ]\n}" + headers: + access-control-allow-credentials: + - 'true' + access-control-allow-headers: + - Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization + access-control-allow-methods: + - POST, GET + access-control-allow-origin: + - '*' + access-control-max-age: + - '3600' + cache-control: + - no-cache, no-store, must-revalidate + connection: + - Keep-Alive + content-encoding: + - gzip + content-type: + - application/json + date: + - Wed, 19 Mar 2025 20:23:17 GMT + keep-alive: + - timeout=5, max=100 + server: + - Apache/2.4.58 (Ubuntu) + strict-transport-security: + - max-age=63072000; includeSubdomains; + transfer-encoding: + - chunked + vary: + - accept-encoding + http_version: HTTP/1.1 + status_code: 200 +version: 1 diff --git a/tests/integrationtests/indicators/test_mapping_saturation.py b/tests/integrationtests/indicators/test_mapping_saturation.py index 6565df8e1..855b8b876 100644 --- a/tests/integrationtests/indicators/test_mapping_saturation.py +++ b/tests/integrationtests/indicators/test_mapping_saturation.py @@ -5,11 +5,12 @@ import plotly.graph_objects as pgo import plotly.io as pio import pytest +from approvaltests import verify from ohsome_quality_api.indicators.mapping_saturation.indicator import ( MappingSaturation, ) -from tests.integrationtests.utils import oqapi_vcr +from tests.integrationtests.utils import PytestNamer, oqapi_vcr class TestCheckEdgeCases: @@ -61,9 +62,10 @@ def test_preprocess(self, topic_building_count, feature_germany_heidelberg): class TestCalculation: + # TODO: scope conflict @pytest.fixture(scope="class") @oqapi_vcr.use_cassette - def indicator(self, topic_building_count, feature_germany_heidelberg): + def indicator(self, topic_building_count, feature_germany_heidelberg, locale_de): i = MappingSaturation(topic_building_count, feature_germany_heidelberg) asyncio.run(i.preprocess()) i.calculate() @@ -79,7 +81,7 @@ def test_calculate(self, indicator): assert indicator.result.value >= 0.0 assert indicator.result.label in ["green", "yellow", "red", "undefined"] - assert indicator.result.description is not None + verify(indicator.result.description, namer=PytestNamer()) assert isinstance(indicator.result.timestamp_osm, datetime) assert isinstance(indicator.result.timestamp, datetime) diff --git a/tests/integrationtests/test_base_indicator.py b/tests/integrationtests/test_base_indicator.py index 838c3eaf9..8c83de7b8 100644 --- a/tests/integrationtests/test_base_indicator.py +++ b/tests/integrationtests/test_base_indicator.py @@ -1,5 +1,6 @@ import asyncio +from approvaltests import verify import plotly.graph_objects as pgo import pytest from geojson import Feature @@ -10,7 +11,7 @@ Result, ) -from .utils import get_geojson_fixture, get_topic_fixture +from .utils import PytestNamer, get_geojson_fixture, get_topic_fixture class TestBaseIndicator: @@ -94,6 +95,14 @@ def test_get_template(self, feature, topic): assert isinstance(indicator.result, Result) + def test_get_template_translated(self, feature, topic, locale_de): + indicator = Minimal(feature=feature, topic=topic) + indicator.get_template() + assert isinstance(indicator.templates, IndicatorTemplates) + assert isinstance(indicator.result, Result) + verify(indicator.templates.model_dump_json(indent=2), namer=PytestNamer()) + + class TestBaseResult: def test_label(self): result = Result(description="") diff --git a/tests/unittests/test_helper.py b/tests/unittests/test_helper.py index 770b4090a..69803329d 100644 --- a/tests/unittests/test_helper.py +++ b/tests/unittests/test_helper.py @@ -13,7 +13,6 @@ ) from ohsome_quality_api.utils.helper import ( camel_to_hyphen, - flatten_sequence, get_class_from_key, get_project_root, hyphen_to_camel, @@ -46,18 +45,6 @@ def test_name_to_class(self): get_class_from_key(class_type="indicator", key=indicator_name) ) - # TODO: add tests for other input than dict - def test_flatten_seq(self): - input_seq = { - "regions": {"default": "ogc_fid"}, - "gadm": { - "default": "uid", # ISO 3166-1 alpha-3 country code - "other": (("name_1", "name_2"), ("id_1", "id_2")), - }, - } - output_seq = ["ogc_fid", "uid", "name_1", "name_2", "id_1", "id_2"] - self.assertListEqual(flatten_sequence(input_seq), output_seq) - def test_json_serialize_valid_input_datetime(self): self.assertIsInstance(json_serialize(datetime.datetime.now()), str) diff --git a/tests/unittests/test_indicators_definitions.py b/tests/unittests/test_indicators_definitions.py index 4cc92922a..f734048db 100644 --- a/tests/unittests/test_indicators_definitions.py +++ b/tests/unittests/test_indicators_definitions.py @@ -3,9 +3,11 @@ import geojson import pytest +from approvaltests import verify from geojson import Feature, Polygon from ohsome_quality_api.indicators import definitions, models +from tests.integrationtests.utils import PytestNamer @pytest.fixture(scope="class") @@ -61,6 +63,12 @@ def test_get_indicator(metadata_indicator_minimal): assert indicator == metadata_indicator_minimal["minimal"] +@pytest.mark.usefixtures("locale_de") +def test_get_indicator_de(): + indicator = definitions.get_indicator("mapping-saturation") + verify(indicator.model_dump_json(indent=2), namer=PytestNamer()) + + def test_get_coverage(mock_get_reference_coverage): coverage = asyncio.run( definitions.get_coverage("building-comparison", inverse=False) diff --git a/tests/unittests/test_utils_pybabel_yaml_extractor.py b/tests/unittests/test_utils_pybabel_yaml_extractor.py new file mode 100644 index 000000000..62691bd01 --- /dev/null +++ b/tests/unittests/test_utils_pybabel_yaml_extractor.py @@ -0,0 +1,97 @@ +import pytest +import yaml + +from ohsome_quality_api.utils.pybabel_yaml_extractor import ( + filter_dictonary_by_keys, + flatten_sequence, + pybabel_yaml_extractor, +) + + +def test_flatten_seq(): + input_seq = { + "regions": {"default": "ogc_fid"}, + "gadm": { + "default": "uid", # ISO 3166-1 alpha-3 country code + "other": (("name_1", "name_2"), ("id_1", "id_2")), + }, + } + output_seq = ["ogc_fid", "uid", "name_1", "name_2", "id_1", "id_2"] + assert flatten_sequence(input_seq) == output_seq + + +def test_filter_dictonary_by_keys(): + input = { + "regions": {"default": "ogc_fid"}, + "gadm": { + "default": "uid", # ISO 3166-1 alpha-3 country code + "other": (("name_1", "name_2"), ("id_1", "id_2")), + }, + } + output = filter_dictonary_by_keys(input, ["other"]) + assert output == {"gadm": {"other": (("name_1", "name_2"), ("id_1", "id_2"))}} + + +def test_no_keys(tmp_path): + path = tmp_path / "foo.yaml" + with open(path, "w") as file: + file.write( + yaml.dump( + { + "name": "Silenthand Olleander", + "race": "Human", + "traits": ["ONE_HAND", "ONE_EYE"], + } + ) + ) + options = {} + with open(path, "r") as file: + with pytest.raises(ValueError): + list(pybabel_yaml_extractor(file, None, None, options)) + + +def test_flat(tmp_path): + path = tmp_path / "foo.yaml" + with open(path, "w") as file: + file.write( + yaml.dump( + { + "name": "Silenthand Olleander", + "race": "Human", + "traits": ["ONE_HAND", "ONE_EYE"], + } + ) + ) + options = {"keys": "name,traits"} + with open(path, "r") as file: + result = list(pybabel_yaml_extractor(file, None, None, options)) + assert result == [ + ("", "", "Silenthand Olleander", ""), + ("", "", "ONE_HAND", ""), + ("", "", "ONE_EYE", ""), + ] + + +def test_nested(tmp_path): + path = tmp_path / "foo.yaml" + with open(path, "w") as file: + file.write( + yaml.dump( + { + "hero": { + "hp": 34, + "sp": 8, + "level": 4, + }, + "orc": { + "hp": 12, + "sp": 0, + "level": 2, + }, + } + ) + ) + options = {"keys": "hp"} + with open(path, "r") as file: + result = list(pybabel_yaml_extractor(file, None, None, options)) + assert result == [("", "", 34, ""), ("", "", 12, "")]