Playing with new translations, merging branches

This commit is contained in:
Pieter Vander Vennet 2020-07-21 01:13:51 +02:00
commit 6f8c29d401
32 changed files with 609 additions and 163 deletions

View file

@ -50,7 +50,7 @@ export class LayerDefinition {
/**
* This UIElement is rendered as title element in the popup
*/
title: TagRenderingOptions;
title: TagRenderingOptions | UIElement;
/**
* These are the questions/shown attributes in the popup
*/

View file

@ -5,12 +5,15 @@ import * as L from "leaflet";
import FixedText from "../Questions/FixedText";
import ParkingType from "../Questions/bike/ParkingType";
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
import BikeStationOperator from "../Questions/bike/StationOperator";
import Translations from "../../UI/i18n/Translations";
import ParkingOperator from "../Questions/bike/ParkingOperator";
export default class BikeParkings extends LayerDefinition {
constructor() {
super();
this.name = "bike parking";
this.name = Translations.t.cyclofix.parking.name.txt;
this.icon = "./assets/bike/parking.svg";
this.overpassFilter = new Tag("amenity", "bicycle_parking");
this.newElementTags = [
@ -20,10 +23,10 @@ export default class BikeParkings extends LayerDefinition {
this.minzoom = 13;
this.style = this.generateStyleFunction();
this.title = new FixedText("Bicycle parking");
this.title = new FixedText(Translations.t.cyclofix.parking.title)
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
// new OperatorTag(),
//new ParkingOperator(),
new ParkingType()
];

View file

@ -0,0 +1,50 @@
import { LayerDefinition } from "../LayerDefinition";
import Translations from "../../UI/i18n/Translations";
import { Tag } from "../../Logic/TagsFilter";
import FixedText from "../Questions/FixedText";
import { ImageCarouselWithUploadConstructor } from "../../UI/Image/ImageCarouselWithUpload";
import * as L from "leaflet";
import ShopRetail from "../Questions/bike/ShopRetail";
import ShopPump from "../Questions/bike/ShopPump";
import ShopRental from "../Questions/bike/ShopRental";
import ShopRepair from "../Questions/bike/ShopRepair";
export default class BikeShops extends LayerDefinition {
constructor() {
super();
this.name = Translations.t.cyclofix.shop.name.txt;
this.icon = "./assets/bike/shop.svg";
this.overpassFilter = new Tag("shop", "bicycle");
this.newElementTags = [
new Tag("shop", "bicycle"),
];
this.maxAllowedOverlapPercentage = 10;
this.minzoom = 13;
this.style = this.generateStyleFunction();
this.title = new FixedText(Translations.t.cyclofix.shop.title.txt)
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
//new ParkingOperator(),
new ShopRetail(),
new ShopRental(),
new ShopRepair(),
new ShopPump(),
];
}
private generateStyleFunction() {
const self = this;
return function (properties: any) {
return {
color: "#00bb00",
icon: L.icon({
iconUrl: self.icon,
iconSize: [50, 50]
})
};
};
}
}

View file

@ -12,6 +12,7 @@ import PumpManometer from "../Questions/bike/PumpManometer";
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
import PumpOperational from "../Questions/bike/PumpOperational";
import PumpValves from "../Questions/bike/PumpValves";
import Translations from "../../UI/i18n/Translations";
export default class BikeStations extends LayerDefinition {
@ -22,7 +23,7 @@ export default class BikeStations extends LayerDefinition {
constructor() {
super();
this.name = "bike station or pump";
this.name = Translations.t.cyclofix.station.name.txt;
this.icon = "./assets/wrench.svg";
this.overpassFilter = new And([
@ -36,7 +37,7 @@ export default class BikeStations extends LayerDefinition {
this.minzoom = 13;
this.style = this.generateStyleFunction();
this.title = new FixedText("Bike station");
this.title = new FixedText(Translations.t.cyclofix.station.title.txt)
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
@ -50,7 +51,7 @@ export default class BikeStations extends LayerDefinition {
new PumpValves().OnlyShowIf(this.pump),
new PumpOperational().OnlyShowIf(this.pump),
new BikeStationOperator(),
// new BikeStationOperator(),
// new BikeStationBrand() DISABLED
];
}

View file

@ -1,6 +1,7 @@
import {Layout} from "../Layout";
import BikeParkings from "../Layers/BikeParkings";
import BikeServices from "../Layers/BikeStations";
import BikeShops from "../Layers/BikeShops";
import {GhostBike} from "../Layers/GhostBike";
import Translations from "../../UI/i18n/Translations";
import {DrinkingWater} from "../Layers/DrinkingWater";
@ -12,14 +13,14 @@ export default class Cyclofix extends Layout {
super(
"pomp",
["en", "nl", "fr"],
Translations.cylofix.title,
Translations.t.cyclofix.title,
[new BikeServices(), new BikeShop(), new DrinkingWater(), new BikeParkings()],
16,
50.8465573,
4.3516970,
"<h3>" + Translations.cylofix.title.Render() + "</h3>\n" +
"<h3>" + Translations.t.cyclofix.title.Render() + "</h3>\n" +
"\n" +
`<p>${Translations.cylofix.description.Render()}</p>`
`<p>${Translations.t.cyclofix.description.Render()}</p>`
,
"", "");
}

View file

@ -1,7 +1,8 @@
import { TagRenderingOptions } from "../TagRendering";
import {UIElement} from "../../UI/UIElement";
export default class FixedText extends TagRenderingOptions {
constructor(category: string) {
constructor(category: string | UIElement) {
super({
mappings: [
{

View file

@ -0,0 +1,27 @@
import {TagRenderingOptions} from "../../TagRendering";
import {Tag, And} from "../../../Logic/TagsFilter";
import Translations from "../../../UI/i18n/Translations";
export default class ParkingOperator extends TagRenderingOptions {
constructor() {
const to = Translations.t.cyclofix.parking.operator
super({
priority: 15,
question: to.question.Render(),
freeform: {
key: "operator",
template: to.template.txt,
renderTemplate: to.render.txt,
placeholder: Translations.t.cyclofix.freeFormPlaceholder.txt
},
mappings: [
{k: new Tag("operator", "KU Leuven"), txt: "KU Leuven"},
{k: new Tag("operator", "Stad Halle"), txt: "Stad Halle"},
{k: new Tag("operator", "Saint Gilles - Sint Gillis"), txt: "Saint Gilles - Sint Gillis"},
{k: new Tag("operator", "Jette"), txt: "Jette"},
{k: new And([new Tag("operator", ""), new Tag("operator:type", "private")]), txt: to.private.Render()}
]
});
}
}

View file

@ -1,37 +1,37 @@
import {TagRenderingOptions} from "../../TagRendering";
import {Tag} from "../../../Logic/TagsFilter";
import Translations from "../../../UI/i18n/Translations";
export default class ParkingType extends TagRenderingOptions {
private static images = {
stands: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Bike_racks_at_north-west_of_Westfield_-_geograph.org.uk_-_1041057.jpg/100px-Bike_racks_at_north-west_of_Westfield_-_geograph.org.uk_-_1041057.jpg",
wall_loops: "https://wiki.openstreetmap.org/w/images/thumb/c/c2/Bike-parking-wheelbender.jpg/100px-Bike-parking-wheelbender.jpg",
handlebar_holder: "https://upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Bicycle_parking_handlebar_holder.jpg/100px-Bicycle_parking_handlebar_holder.jpg",
shed: "https://wiki.openstreetmap.org/w/images/thumb/b/b2/Bike-shelter.jpg/100px-Bike-shelter.jpg",
"two-tier": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Bicis_a_l%27estaci%C3%B3_de_Leiden.JPG/100px-Bicis_a_l%27estaci%C3%B3_de_Leiden.JPG"
}
private static toImgTxt(url: string) {
return `<img src=${url}>`
}
constructor() {
const images = {
stands: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Bike_racks_at_north-west_of_Westfield_-_geograph.org.uk_-_1041057.jpg/100px-Bike_racks_at_north-west_of_Westfield_-_geograph.org.uk_-_1041057.jpg",
loops: "https://wiki.openstreetmap.org/w/images/thumb/c/c2/Bike-parking-wheelbender.jpg/100px-Bike-parking-wheelbender.jpg",
handlebar: "https://upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Bicycle_parking_handlebar_holder.jpg/100px-Bicycle_parking_handlebar_holder.jpg",
shed: "https://wiki.openstreetmap.org/w/images/thumb/b/b2/Bike-shelter.jpg/100px-Bike-shelter.jpg",
rack: "https://wiki.openstreetmap.org/w/images/thumb/4/41/Triton_Bike_Rack.png/100px-Triton_Bike_Rack.png",
double: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Bicis_a_l%27estaci%C3%B3_de_Leiden.JPG/100px-Bicis_a_l%27estaci%C3%B3_de_Leiden.JPG"
}
const toImg = (url) => `<img src=${url}>`
const to = Translations.t.cyclofix.parking.type
super({
priority: 5,
question: "Van welk type is deze fietsenparking?",
question: to.question.Render(),
freeform: {
key: "bicycle_parking",
extraTags: new Tag("fixme", "Freeform bicycle_parking= tag used: possibly a wrong value"),
template: "Iets anders: $$$",
renderTemplate: "Dit is een fietsenparking van het type: {bicycle_parking}",
placeholder: "Specifieer"
template: to.template.txt,
renderTemplate: to.render.txt,
placeholder: Translations.t.cyclofix.freeFormPlaceholder.txt,
},
mappings: [
{k: new Tag("bicycle_parking", "stands"), txt: ParkingType.toImgTxt(ParkingType.images.stands)},
{k: new Tag("bicycle_parking", "wall_loops"), txt: ParkingType.toImgTxt(ParkingType.images.wall_loops)},
{k: new Tag("bicycle_parking", "handlebar_holder"), txt: ParkingType.toImgTxt(ParkingType.images.handlebar_holder)},
{k: new Tag("bicycle_parking", "shed"), txt: ParkingType.toImgTxt(ParkingType.images.shed)},
{k: new Tag("bicycle_parking", "two-tier"), txt: ParkingType.toImgTxt(ParkingType.images["two-tier"])}
{k: new Tag("bicycle_parking", "stands"), txt: `${to.stands.Render()}, bijvoorbeeld: ${toImg(images.stands)}`},
{k: new Tag("bicycle_parking", "wall_loops"), txt: `${to.loops.Render()}, bijvoorbeeld: ${toImg(images.loops)}`},
{k: new Tag("bicycle_parking", "handlebar_holder"), txt: `${to.handlebar.Render()}, bijvoorbeeld: ${toImg(images.handlebar)}`},
{k: new Tag("bicycle_parking", "shed"), txt: `${to.shed.Render()}, bijvoorbeeld: ${toImg(images.shed)}`},
{k: new Tag("bicycle_parking", "rack"), txt: `${to.rack.Render()}, bijvoorbeeld: ${toImg(images.rack)}`},
{k: new Tag("bicycle_parking", "two-tier"), txt: `${to.double.Render()}, bijvoorbeeld: ${toImg(images.double)}`}
]
});
}

View file

@ -1,16 +1,18 @@
import {TagRenderingOptions} from "../../TagRendering";
import {Tag} from "../../../Logic/TagsFilter";
import Translations from "../../../UI/i18n/Translations";
export default class PumpManometer extends TagRenderingOptions {
constructor() {
const to = Translations.t.cyclofix.station.manometer
super({
question: "Does the pump have a pressure indicator or manometer?",
question: to.question.Render(),
mappings: [
{k: new Tag("manometer", "yes"), txt: "Yes, there is a manometer"},
{k: new Tag("manometer","broken"), txt: "Yes, but it is broken"},
{k: new Tag("manometer", "yes"), txt: "No"}
{k: new Tag("manometer", "yes"), txt: to.yes.Render()},
{k: new Tag("manometer", "no"), txt: to.no.Render()},
{k: new Tag("manometer", "broken"), txt: to.broken.Render()}
]
});
}
}
}

View file

@ -1,15 +1,17 @@
import {TagRenderingOptions} from "../../TagRendering";
import {Tag} from "../../../Logic/TagsFilter";
import Translations from "../../../UI/i18n/Translations";
export default class PumpManual extends TagRenderingOptions {
constructor() {
const to = Translations.t.cyclofix.station.electric
super({
priority: 5,
question: "Is this an electric bike pump?",
question: to.question.Render(),
mappings: [
{k: new Tag("manual", "yes"), txt: "Manual pump"},
{k: new Tag("manual", "no"), txt: "Electric pump"}
{k: new Tag("manual", "yes"), txt: to.manual.Render()},
{k: new Tag("manual", "no"), txt: to.electric.Render()}
]
});
}

View file

@ -1,14 +1,16 @@
import {TagRenderingOptions} from "../../TagRendering";
import {Tag} from "../../../Logic/TagsFilter";
import Translations from "../../../UI/i18n/Translations";
export default class PumpOperational extends TagRenderingOptions {
constructor() {
const to = Translations.t.cyclofix.station.operational
super({
question: "Is the bicycle pump still operational?",
question: to.question.Render(),
mappings: [
{k: new Tag("service:bicycle:pump:operational_status","broken"), txt: "This pump is broken"},
{k: new Tag("service:bicycle:pump:operational_status",""), txt: "This pump is operational"}
{k: new Tag("service:bicycle:pump:operational_status","broken"), txt: to.broken.txt},
{k: new Tag("service:bicycle:pump:operational_status",""), txt: to.operational.txt}
]
});
}

View file

@ -1,24 +1,27 @@
import {TagRenderingOptions} from "../../TagRendering";
import {Tag} from "../../../Logic/TagsFilter";
import Translations from "../../../UI/i18n/Translations";
export default class PumpValves extends TagRenderingOptions{
constructor() {
const to = Translations.t.cyclofix.station.valves
super({
question: "What valves are supported?",
question: to.question.Render(),
mappings: [
{
k: new Tag("valves", " sclaverand;schrader;dunlop"),
txt: "There is a default head, so Presta, Dunlop and Auto"
txt: to.default.Render()
},
{k: new Tag("valves", "dunlop"), txt: "Only dunlop"},
{k: new Tag("valves", "sclaverand"), txt: "Only Sclaverand (also known as Dunlop)"},
{k: new Tag("valves", "auto"), txt: "Only auto"},
{k: new Tag("valves", "dunlop"), txt: to.dunlop.Render()},
{k: new Tag("valves", "sclaverand"), txt: to.sclaverand.Render()},
{k: new Tag("valves", "auto"), txt: to.auto.Render()},
],
freeform: {
extraTags: new Tag("fixme", "Freeform valves= tag used: possibly a wrong value"),
key: "valves",
template: "Supported valves are $$$",
renderTemplate: "Supported valves are {valves}"
template: to.template.txt,
renderTemplate: to.render.txt
}
});
}

View file

@ -0,0 +1,19 @@
import {TagRenderingOptions} from "../../TagRendering";
import {Tag} from "../../../Logic/TagsFilter";
import Translations from "../../../UI/i18n/Translations";
export default class ShopPump extends TagRenderingOptions {
constructor() {
const key = 'service:bicycle:pump'
const to = Translations.t.cyclofix.shop.pump
super({
priority: 5,
question: to.question.Render(),
mappings: [
{k: new Tag(key, "yes"), txt: to.yes.Render()},
{k: new Tag(key, "no"), txt: to.no.Render()},
]
});
}
}

View file

@ -0,0 +1,19 @@
import {TagRenderingOptions} from "../../TagRendering";
import {Tag} from "../../../Logic/TagsFilter";
import Translations from "../../../UI/i18n/Translations";
export default class ShopRental extends TagRenderingOptions {
constructor() {
const key = 'service:bicycle:rental'
const to = Translations.t.cyclofix.shop.rental
super({
priority: 5,
question: to.question.Render(),
mappings: [
{k: new Tag(key, "yes"), txt: to.yes.Render()},
{k: new Tag(key, "no"), txt: to.no.Render()},
]
});
}
}

View file

@ -0,0 +1,19 @@
import {TagRenderingOptions} from "../../TagRendering";
import {Tag} from "../../../Logic/TagsFilter";
import Translations from "../../../UI/i18n/Translations";
export default class ShopRepair extends TagRenderingOptions {
constructor() {
const key = 'service:bicycle:repair'
const to = Translations.t.cyclofix.shop.repair
super({
priority: 5,
question: to.question.Render(),
mappings: [
{k: new Tag(key, "yes"), txt: to.yes.Render()},
{k: new Tag(key, "no"), txt: to.no.Render()},
]
});
}
}

View file

@ -0,0 +1,19 @@
import {TagRenderingOptions} from "../../TagRendering";
import {Tag} from "../../../Logic/TagsFilter";
import Translations from "../../../UI/i18n/Translations";
export default class ShopRetail extends TagRenderingOptions {
constructor() {
const key = 'service:bicycle:retail'
const to = Translations.t.cyclofix.shop.retail
super({
priority: 5,
question: to.question,
mappings: [
{k: new Tag(key, "yes"), txt: to.yes},
{k: new Tag(key, "no"), txt: to.no},
]
});
}
}

View file

@ -4,6 +4,8 @@ import {Tag} from "../../../Logic/TagsFilter";
/**
* Currently not used in Cyclofix because it's a little vague
*
* TODO: Translations
*/
export default class BikeStationBrand extends TagRenderingOptions {
private static options = {

View file

@ -1,15 +1,17 @@
import {TagRenderingOptions} from "../../TagRendering";
import {Tag} from "../../../Logic/TagsFilter";
import Translations from "../../../UI/i18n/Translations";
export default class StationChain extends TagRenderingOptions {
constructor() {
const to = Translations.t.cyclofix.station.chain
super({
priority: 5,
question: "Does this bike station have a special tool to repair your bike chain?",
question: to.question.Render(),
mappings: [
{k: new Tag("service:bicycle:chain_tool", "yes"), txt: "There is a chain tool."},
{k: new Tag("service:bicycle:chain_tool", "no"), txt: "There is no chain tool."},
{k: new Tag("service:bicycle:chain_tool", "yes"), txt: to.yes.Render()},
{k: new Tag("service:bicycle:chain_tool", "no"), txt: to.no.Render()},
]
});
}

View file

@ -1,25 +1,27 @@
import {TagRenderingOptions} from "../../TagRendering";
import {Tag} from "../../../Logic/TagsFilter";
import Translations from "../../../UI/i18n/Translations";
export default class BikeStationOperator extends TagRenderingOptions {
constructor() {
const to = Translations.t.cyclofix.station.operator
super({
priority: 15,
question: "Who operates this bike station (name of university, shop, city...)?",
freeform: {
key: "operator",
template: "This bike station is operated by $$$",
renderTemplate: "This bike station is operated by {operator}",
placeholder: "organisatie"
},
question: to.question,
mappings: [
{k: new Tag("operator", "KU Leuven"), txt: "KU Leuven"},
{k: new Tag("operator", "Stad Halle"), txt: "Stad Halle"},
{k: new Tag("operator", "Saint Gilles - Sint Gillis"), txt: "Saint Gilles - Sint Gillis"},
{k: new Tag("operator", "Jette"), txt: "Jette"},
{k: new Tag("operator", "private"), txt: "Operated by a private individual"}
]
{k: new Tag("operator", "private"), txt: to.private}
],
freeform: {
key: "operator",
template: to.template,
renderTemplate: to.render,
placeholder: "organisatie"
}
});
}
}

View file

@ -1,16 +1,18 @@
import {TagRenderingOptions} from "../../TagRendering";
import {Tag, And} from "../../../Logic/TagsFilter";
import Translations from "../../../UI/i18n/Translations";
export default class BikeStationPumpTools extends TagRenderingOptions {
constructor() {
const to = Translations.t.cyclofix.station.services
super({
priority: 15,
question: "Which services are available here?",
question: to.question,
mappings: [
{k: new And([new Tag("service:bicycle:tools", "no"), new Tag("service:bicycle:pump", "yes")]), txt: "There is only a pump available."},
{k: new And([new Tag("service:bicycle:tools", "yes"), new Tag("service:bicycle:pump", "no")]), txt: "There are only tools (screwdrivers, pliers...) available."},
{k: new And([new Tag("service:bicycle:tools", "yes"), new Tag("service:bicycle:pump", "yes")]), txt: "There are both tools and a pump available."}
{k: new And([new Tag("service:bicycle:tools", "no"), new Tag("service:bicycle:pump", "yes")]), txt: to.pump},
{k: new And([new Tag("service:bicycle:tools", "yes"), new Tag("service:bicycle:pump", "no")]), txt: to.tools},
{k: new And([new Tag("service:bicycle:tools", "yes"), new Tag("service:bicycle:pump", "yes")]), txt: to.both}
]
});
}

View file

@ -1,14 +1,16 @@
import {TagRenderingOptions} from "../../TagRendering";
import {Tag} from "../../../Logic/TagsFilter";
import Translations from "../../../UI/i18n/Translations";
export default class BikeStationStand extends TagRenderingOptions {
constructor() {
const to = Translations
super({
priority: 10,
question: "Does this bike station have a hook to suspend your bike with or a stand to elevate it?",
mappings: [
{k: new Tag("service:bicycle:stand", "yes"), txt: "There is a hook or stand."},
{k: new Tag("service:bicycle:stand", "yes"), txt: "There is a hook or stand"},
{k: new Tag("service:bicycle:stand", "no"), txt: "There is no hook or stand"},
]
});

View file

@ -1,6 +1,7 @@
import {UIElement} from "./UIElement";
import {UIEventSource} from "./UIEventSource";
import {OsmConnection} from "../Logic/OsmConnection";
import Translations from "./i18n/Translations";
export class CenterMessageBox extends UIElement {
@ -40,11 +41,11 @@ export class CenterMessageBox extends UIElement {
return this._centermessage.data;
}
if (this._queryRunning.data) {
return "Data is loading...";
return Translations.t.centerMessage.loadingData.txt;
} else if (this._zoomInMore.data) {
return "Zoom in more to see the data";
return Translations.t.centerMessage.zoomIn.txt;
}
return "Done!";
return Translations.t.centerMessage.ready.txt;
}

View file

@ -30,7 +30,7 @@ export class FeatureInfoBox extends UIElement {
constructor(
tagsES: UIEventSource<any>,
title: TagRenderingOptions,
title: TagRenderingOptions | UIElement,
elementsToShow: TagDependantUIElementConstructor[],
changes: Changes,
userDetails: UIEventSource<UserDetails>
@ -56,10 +56,14 @@ export class FeatureInfoBox extends UIElement {
}
)
this._title = new TagRenderingOptions(title.options).construct(deps);
this._osmLink =new OsmLink().construct(deps);
if (title instanceof UIElement) {
this._title = title;
} else {
this._title = new TagRenderingOptions(title.options).construct(deps);
}
this._osmLink = new OsmLink().construct(deps);
this._wikipedialink = new WikipediaLink().construct(deps);
}

View file

@ -31,12 +31,11 @@ export class ImageUploadFlow extends UIElement {
this._uploadOptions = uploadOptions;
this.ListenTo(this._isUploading);
const licensePicker = new DropDown(
Translations.general.picture.licenseIntro,
const licensePicker = new DropDown(Translations.t.image.willBePublished,
[
{value: "CC0", shown: Translations.general.picture.publicDomain},
{value: "CC-BY-SA 4.0", shown:Translations.general.picture.ccbysa},
{value: "CC-BY 4.0", shown:Translations.general.picture.ccby}
{value: "CC0", shown: Translations.t.image.cco},
{value: "CC-BY-SA 4.0", shown: Translations.t.image.ccbs},
{value: "CC-BY 4.0", shown: Translations.t.image.ccb}
],
preferedLicense
);
@ -50,12 +49,12 @@ export class ImageUploadFlow extends UIElement {
InnerRender(): string {
if (!this._userdetails.data.loggedIn) {
return "<div class='activate-osm-authentication'>Please log in to add a picture</div>";
return `<div class='activate-osm-authentication'>${Translations.t.image.pleaseLogin.Render()}</div>`;
}
let uploadingMessage = "";
if (this._isUploading.data == 1) {
uploadingMessage = "<b>Uploading a picture...</b>"
return `<b>${Translations.t.image.uploadingPicture.Render()}</b>`
}
if (this._isUploading.data > 0) {
uploadingMessage = "<b>Uploading multiple pictures, " + this._isUploading.data + " left...</b>"
@ -68,8 +67,8 @@ export class ImageUploadFlow extends UIElement {
"<div class='imageflow-file-input-wrapper'>" +
"<img src='./assets/camera-plus.svg' alt='upload image'/> " +
"<span class='imageflow-add-picture'>"+Translations.general.picture.uploadAPicture.R()+"</span>" +
"<div class='break'></div>" +
`<span class='imageflow-add-picture'>${Translations.t.image.addPicture.R()}</span>` +
"<div class='break'></div>"+
"</div>" +
this._licensePicker.Render() + "<br/>" +

View file

@ -12,7 +12,7 @@ import Translations from "./i18n/Translations";
export class SearchAndGo extends UIElement {
private _placeholder = new UIEventSource<Translation>(Translations.general.search.search)
private _placeholder = new UIEventSource<Translation>(Translations.t.general.search.search)
private _searchField = new TextField<string>({
placeholder: new VariableUiElement(
this._placeholder.map(uiElement => uiElement.InnerRender(), [Locale.language])
@ -46,12 +46,12 @@ export class SearchAndGo extends UIElement {
private RunSearch() {
const searchString = this._searchField.GetValue().data;
this._searchField.Clear();
this._placeholder.setData(Translations.general.search.searching);
this._placeholder.setData(Translations.t.general.search.searching);
const self = this;
Geocoding.Search(searchString, this._map, (result) => {
if (result.length == 0) {
this._placeholder.setData(Translations.general.search.nothing);
this._placeholder.setData(Translations.t.general.search.nothing);
return;
}
@ -61,10 +61,10 @@ export class SearchAndGo extends UIElement {
[bb[1], bb[3]]
]
self._map.map.fitBounds(bounds);
this._placeholder.setData(Translations.general.search.search);
this._placeholder.setData(Translations.t.general.search.search);
},
() => {
this._placeholder.setData(Translations.general.search.error);
this._placeholder.setData(Translations.t.general.search.error);
});
}

View file

@ -64,7 +64,7 @@ export class UserBadge extends UIElement {
InnerRender(): string {
const user = this._userDetails.data;
if (!user.loggedIn) {
return "<div class='activate-osm-authentication'>" + Translations.general.loginWithOpenStreetMap.R()+ "</div>";
return "<div class='activate-osm-authentication'>" + Translations.t.general.loginWithOpenStreetMap.R()+ "</div>";
}

View file

@ -3,7 +3,7 @@ import {OsmConnection} from "../../Logic/OsmConnection";
export default class Locale {
public static language: UIEventSource<string> = Locale.getInitialLanguage()
public static language: UIEventSource<string> = Locale.getInitialLanguage();
private static getInitialLanguage() {
// The key to save in local storage
@ -12,13 +12,13 @@ export default class Locale {
const lng = new UIEventSource("en");
const saved = localStorage.getItem(LANGUAGE_KEY);
lng.setData(saved);
lng.addCallback(data => {
console.log("Selected language", data);
localStorage.setItem(LANGUAGE_KEY, data)
});
return lng;
}
}

View file

@ -4,6 +4,19 @@ import {FixedUiElement} from "../Base/FixedUiElement";
export default class Translation extends UIElement {
get txt(): string {
const txt = this.translations[Locale.language.data];
if (txt !== undefined) {
return txt;
}
const en = this.translations["en"];
console.warn("No translation for language ", Locale.language.data, "for", en);
return en;
}
InnerRender(): string {
return this.txt
}
public readonly translations: object
@ -12,19 +25,11 @@ export default class Translation extends UIElement {
this.translations = translations
}
public R(): string {
return new Translation(this.translations).Render();
}
InnerRender(): string {
const txt = this.translations[Locale.language.data];
if (txt !== undefined) {
return txt;
}
const en = this.translations["en"];
console.warn("No translation for language ", Locale.language.data, "for",en);
return en;
}
}

View file

@ -1,73 +1,321 @@
import Translation from "./Translation";
import T from "./Translation";
import {UIElement} from "../UIElement";
import {FixedUiElement} from "../Base/FixedUiElement";
export default class Translations {
static cylofix = {
title: new Translation({
en: 'Cyclofix bicycle infrastructure',
nl: 'Cyclofix fietsinfrastructuur',
fr: 'TODO: FRENCH TRANSLATION'
}),
description: new Translation({
en: "On this map we want to collect data about the whereabouts of bicycle pumps and public racks in Brussels." +
"As a result, cyclists will be able to quickly find the nearest infrastructure for their needs.",
nl: "Op deze kaart willen we gegevens verzamelen over de locatie van fietspompen en openbare stelplaatsen in Brussel." +
"Hierdoor kunnen fietsers snel de dichtstbijzijnde infrastructuur vinden die voldoet aan hun behoeften.",
fr: "Sur cette carte, nous voulons collecter des données sur la localisation des pompes à vélo et des supports publics à Bruxelles." +
"Les cyclistes pourront ainsi trouver rapidement l'infrastructure la plus proche de leurs besoins."
})
};
static general = {
loginWithOpenStreetMap: new Translation({
en: "Click here to login with OpenStreetMap",
nl: "Klik hier op je aan te melden met OpenStreetMap"
}),
search: {
search: new Translation({
en: "Search a location",
nl: "Zoek naar een locatie"
static t = {
cyclofix: {
title: new T({
en: 'Cyclofix bicycle infrastructure',
nl: 'Cyclofix fietsinfrastructuur',
fr: 'TODO: FRENCH TRANSLATION'
}),
searching: new Translation({
en: "Searching...",
nl: "Aan het zoeken..."
description: new T({
en: "On this map we want to collect data about the whereabouts of bicycle pumps and public racks in Brussels." +
"As a result, cyclists will be able to quickly find the nearest infrastructure for their needs.",
nl: "Op deze kaart willen we gegevens verzamelen over de locatie van fietspompen en openbare stelplaatsen in Brussel." +
"Hierdoor kunnen fietsers snel de dichtstbijzijnde infrastructuur vinden die voldoet aan hun behoeften.",
fr: "Sur cette carte, nous voulons collecter des données sur la localisation des pompes à vélo et des supports publics à Bruxelles." +
"Les cyclistes pourront ainsi trouver rapidement l'infrastructure la plus proche de leurs besoins."
}),
nothing: new Translation({
en: "Nothing found...",
nl: "Niet gevonden..."
}),
error: new Translation({
en: "Something went wrong...",
nl: "Niet gelukt..."
})
freeFormPlaceholder: new T({en: 'specify', nl: 'specifieer', fr: 'TODO: fr'}),
parking: {
name: new T({en: 'bike parking', nl: 'fietsparking', fr: 'TODO: fr'}),
title: new T({en: 'Bike parking', nl: 'Fietsparking', fr: 'TODO: fr'}),
type: {
render: new T({
en: 'This is a bicycle parking of the type: {bicycle_parking}',
nl: 'Dit is een fietsenparking van het type: {bicycle_parking}',
fr: 'TODO: fr'
}),
template: new T({en: 'Some other type: $$$', nl: 'Een ander type: $$$', fr: 'TODO: fr'}),
question: new T({
en: 'What is the type of this bicycle parking?',
nl: 'Van welk type is deze fietsenparking?',
fr: 'TODO: fr'
}),
stands: new T({en: 'Staple racks', nl: 'Nietjes', fr: 'TODO: fr'}),
loops: new T({en: 'Wheel rack/loops', nl: 'Wielrek/lussen', fr: 'TODO: fr'}),
handlebar: new T({en: 'Handlebar holder', nl: 'Stuurhouder', fr: 'TODO: fr'}),
shed: new T({en: 'Shed', nl: 'Schuur', fr: 'TODO: fr'}),
rack: new T({en: 'Rack', nl: 'Rek', fr: 'TODO: fr'}),
double: new T({en: 'Two-tiered', nl: 'Dubbel (twee verdiepingen)', fr: 'TODO: fr'}),
},
operator: {
render: new T({
en: 'This bike parking is operated by {operator}',
nl: 'Deze fietsenparking wordt beheerd door {operator}',
fr: 'TODO: fr'
}),
template: new T({en: 'A different operator: $$$', nl: 'Een andere beheerder: $$$', fr: 'TODO: fr'}),
question: new T({
en: 'Who operates this bike station (name of university, shop, city...)?',
nl: 'Wie beheert deze fietsenparking (naam universiteit, winkel, stad...)?',
fr: 'TODO: fr'
}),
private: new T({
en: 'Operated by a private person',
nl: 'Wordt beheerd door een privépersoon',
fr: 'TODO: fr'
}),
}
},
station: {
name: new T({
en: 'bike station (repair, pump or both)',
nl: 'fietsstation (herstel, pomp of allebei)',
fr: 'TODO: fr'
}),
title: new T({en: 'Bike station', nl: 'Fietsstation', fr: 'TODO: fr'}),
manometer: {
question: new T({
en: 'Does the pump have a pressure indicator or manometer?',
nl: 'Heeft deze pomp een luchtdrukmeter?',
fr: 'TODO: fr'
}),
yes: new T({en: 'There is a manometer', nl: 'Er is een luchtdrukmeter', fr: 'TODO: fr'}),
no: new T({en: 'There is no manometer', nl: 'Er is geen luchtdrukmeter', fr: 'TODO: fr'}),
broken: new T({
en: 'There is manometer but it is broken',
nl: 'Er is een luchtdrukmeter maar die is momenteel defect',
fr: 'TODO: fr'
})
},
electric: {
question: new T({
en: 'Is this an electric bike pump?',
nl: 'Is dit een electrische fietspomp?',
fr: 'TODO: fr'
}),
manual: new T({en: 'Manual pump', nl: 'Manuele pomp', fr: 'TODO: fr'}),
electric: new T({en: 'Electrical pump', nl: 'Electrische pomp', fr: 'TODO: fr'})
},
operational: {
question: new T({
en: 'Is the bike pump still operational?',
nl: 'Werkt de fietspomp nog?',
fr: 'TODO: fr'
}),
operational: new T({
en: 'The bike pump is operational',
nl: 'De fietspomp werkt nog',
fr: 'TODO: fr'
}),
broken: new T({en: 'The bike pump is broken', nl: 'De fietspomp is kapot', fr: 'TODO: fr'})
},
valves: {
question: new T({
en: 'What valves are supported?',
nl: 'Welke ventielen werken er met de pomp?',
fr: 'TODO: fr'
}),
default: new T({
en: 'There is a default head, so Dunlop, Sclaverand and auto',
nl: 'Er is een standaard aansluiting, die dus voor Dunlop, Sclaverand en auto\'s werkt',
fr: 'TODO: fr'
}),
dunlop: new T({en: 'Only Dunlop', nl: 'Enkel Dunlop', fr: 'TODO: fr'}),
sclaverand: new T({
en: 'Only Sclaverand (also known as Presta)',
nl: 'Enkel Sclaverand (ook gekend als Presta)',
fr: 'TODO: fr'
}),
auto: new T({en: 'Only for cars', nl: 'Enkel voor auto\'s', fr: 'TODO: fr'}),
render: new T({
en: 'This pump supports the following valves: {valves}',
nl: 'Deze pomp werkt met de volgende ventielen: {valves}',
fr: 'TODO: fr'
}),
template: new T({
en: 'Some other valve(s): $$$',
nl: 'Een ander type ventiel(en): $$$',
fr: 'TODO: fr'
})
},
chain: {
question: new T({
en: 'Does this bike station have a special tool to repair your bike chain?',
nl: 'Heeft dit fietsstation een speciale reparatieset voor je ketting?',
fr: 'TODO: fr'
}),
yes: new T({
en: 'There is a chain tool',
nl: 'Er is een reparatieset voor je ketting',
fr: 'TODO: fr'
}),
no: new T({
en: 'There is no chain tool',
nl: 'Er is geen reparatieset voor je ketting',
fr: 'TODO: fr'
}),
},
operator: {
render: new T({
en: 'This bike station is operated by {operator}',
nl: 'Dit fietsstation wordt beheerd door {operator}',
fr: 'TODO: fr'
}),
template: new T({en: 'A different operator: $$$', nl: 'Een andere beheerder: $$$', fr: 'TODO: fr'}),
question: new T({
en: 'Who operates this bike station (name of university, shop, city...)?',
nl: 'Wie beheert dit fietsstation (naam universiteit, winkel, stad...)?',
fr: 'TODO: fr'
}),
private: new T({
en: 'Operated by a private person',
nl: 'Wordt beheerd door een privépersoon',
fr: 'TODO: fr'
}),
},
services: {
question: new T({
en: 'Which services are available at this bike station?',
nl: 'Welke functies biedt dit fietsstation?',
fr: 'TODO: fr'
}),
pump: new T({
en: 'There is only a pump available',
nl: 'Er is enkel een pomp beschikbaar',
fr: 'TODO: fr'
}),
tools: new T({
en: 'There are only tools (screwdrivers, pliers...) available',
nl: 'Er is enkel gereedschap beschikbaar (schroevendraaier, tang...)',
fr: 'TODO: fr'
}),
both: new T({
en: 'There are both tools and a pump available',
nl: 'Er is zowel een pomp als gereedschap beschikbaar',
fr: 'TODO: fr'
}),
},
stand: {
question: new T({
en: 'Does this bike station have a hook to suspend your bike with or a stand to elevate it?',
nl: 'Heeft dit fietsstation een haak of standaard om je fiets op te hangen/zetten?',
fr: 'TODO: fr'
}),
yes: new T({en: 'There is a hook or stand', nl: 'Er is een haak of standaard', fr: 'TODO: fr'}),
no: new T({en: 'There is no hook or stand', nl: 'Er is geen haak of standaard', fr: 'TODO: fr'}),
}
},
shop: {
name: new T({en: 'bike shop', nl: 'fietswinkel', fr: 'TODO: fr'}),
title: new T({en: 'Bike shop', nl: 'Fietswinkel', fr: 'TODO: fr'}),
retail: {
question: new T({
en: 'Does this shop sell bikes?',
nl: 'Verkoopt deze winkel fietsen?',
fr: 'TODO: fr'
}),
yes: new T({en: 'This shop sells bikes', nl: 'Deze winkel verkoopt fietsen', fr: 'TODO: fr'}),
no: new T({
en: 'This shop doesn\'t sell bikes',
nl: 'Deze winkel verkoopt geen fietsen',
fr: 'TODO: fr'
}),
},
repair: {
question: new T({
en: 'Does this shop repair bikes?',
nl: 'Verkoopt deze winkel fietsen?',
fr: 'TODO: fr'
}),
yes: new T({en: 'This shop repairs bikes', nl: 'Deze winkel herstelt fietsen', fr: 'TODO: fr'}),
no: new T({
en: 'This shop doesn\'t repair bikes',
nl: 'Deze winkel herstelt geen fietsen',
fr: 'TODO: fr'
}),
},
rental: {
question: new T({
en: 'Does this shop rent out bikes?',
nl: 'Verhuurt deze winkel fietsen?',
fr: 'TODO: fr'
}),
yes: new T({en: 'This shop rents out bikes', nl: 'Deze winkel verhuurt fietsen', fr: 'TODO: fr'}),
no: new T({
en: 'This shop doesn\'t rent out bikes',
nl: 'Deze winkel verhuurt geen fietsen',
fr: 'TODO: fr'
}),
},
pump: {
question: new T({
en: 'Does this shop offer a bike pump for use by anyone?',
nl: 'Biedt deze winkel een fietspomp aan voor iedereen?',
fr: 'TODO: fr'
}),
yes: new T({
en: 'This shop offers a bike pump for anyone',
nl: 'Deze winkel biedt geen fietspomp aan voor eender wie',
fr: 'TODO: fr'
}),
no: new T({
en: 'This shop doesn\'t offer a bike pump for anyone',
nl: 'Deze winkel biedt een fietspomp aan voor iedereen',
fr: 'TODO: fr'
}),
}
}
},
image: {
addPicture: new T({en: 'Add picture', nl: 'Voeg foto toe', fr: 'TODO: fr'}),
uploadingPicture: new T({
en: 'Uploading your picture...',
nl: 'Bezig met een foto te uploaden...',
fr: 'TODO: fr'
}),
pleaseLogin: new T({
en: 'Please login to add a picure or to answer questions',
nl: 'Gelieve je aan te melden om een foto toe te voegen of vragen te beantwoorden',
fr: 'TODO: fr'
}),
willBePublished: new T({
en: 'Your picture will be published: ',
nl: 'Jouw foto wordt gepubliceerd: ',
fr: 'TODO: fr'
}),
cco: new T({en: 'in the public domain', nl: 'in het publiek domein', fr: 'TODO: fr'}),
ccbs: new T({en: 'under the CC-BY-SA-license', nl: 'onder de CC-BY-SA-licentie', fr: 'TODO: fr'}),
ccb: new T({en: 'under the CC-BY-license', nl: 'onder de CC-BY-licentie', fr: 'TODO: fr'})
},
centerMessage: {
loadingData: new T({en: 'Loading data...', nl: 'Data wordt geladen...', fr: 'TODO: fr'}),
zoomIn: new T({
en: 'Zoom in to view or edit the data',
nl: 'Zoom in om de data te zien en te bewerken',
fr: 'TODO: fr'
}),
ready: new T({en: 'Done!', nl: 'Klaar!', fr: 'TODO: fr'}),
},
general: {
loginWithOpenStreetMap: new T({en: "Login with OpenStreetMap", nl: "Aanmelden met OpenStreetMap"})
picture: {
uploadAPicture: new Translation({
en: "Add a picture",
nl: "Voeg een foto toe"
,
search: {
search: new Translation({
en: "Search a location",
nl: "Zoek naar een locatie"
}),
searching: new Translation({
en: "Searching...",
nl: "Aan het zoeken..."
}),
nothing: new Translation({
en: "Nothing found...",
nl: "Niet gevonden..."
}),
error: new Translation({
en: "Something went wrong...",
nl: "Niet gelukt..."
})
}),
licenseIntro: new Translation({
en: "Your picture is published",
nl: "Je foto wordt gepubliceerd"
}),
publicDomain: new Translation({
en: "in the public domain",
nl: "in het publiek domein"
}),
ccby: new Translation({
en: "with a CC-BY license",
nl: "met een CC-BY licentie"
}),
ccbysa: new Translation({
en: "with a CC-BY-SA license",
nl: "met een CC-BY-SA licentie"
})
}
}
}
}
public static W(s: string | UIElement): UIElement {

View file

@ -1,6 +1,6 @@
<svg width="97" height="123" viewBox="0 0 97 123" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M52.1412 111.419C50.4633 115.605 44.5366 115.605 42.8588 111.419L24.7014 66.1099C23.385 62.8252 25.8039 59.25 29.3426 59.25L65.6574 59.25C69.1962 59.25 71.615 62.8252 70.2986 66.11L52.1412 111.419Z" fill="#1647F8"/>
<ellipse cx="48.5" cy="47.5" rx="48.5" ry="47.5" fill="#1647F8"/>
<path d="M52.1412 111.419C50.4633 115.605 44.5366 115.605 42.8588 111.419L24.7014 66.1099C23.385 62.8252 25.8039 59.25 29.3426 59.25L65.6574 59.25C69.1962 59.25 71.615 62.8252 70.2986 66.11L52.1412 111.419Z" fill="#5675DF"/>
<ellipse cx="48.5" cy="47.5" rx="48.5" ry="47.5" fill="#5675DF"/>
<g filter="url(#filter0_d)">
<path d="M42.2812 53.1875V71H36.2812V25.5H53.0625C58.0417 25.5 61.9375 26.7708 64.75 29.3125C67.5833 31.8542 69 35.2188 69 39.4062C69 43.8229 67.6146 47.2292 64.8438 49.625C62.0938 52 58.1458 53.1875 53 53.1875H42.2812ZM42.2812 48.2812H53.0625C56.2708 48.2812 58.7292 47.5312 60.4375 46.0312C62.1458 44.5104 63 42.3229 63 39.4688C63 36.7604 62.1458 34.5938 60.4375 32.9688C58.7292 31.3438 56.3854 30.5 53.4062 30.4375H42.2812V48.2812Z" fill="white"/>
</g>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -241,6 +241,9 @@ form {
#language-select {
pointer-events: all;
cursor: pointer;
position: absolute;
margin-left: 2em;
margin-top: 0.5em;
}
#messagesbox-wrapper {

View file

@ -29,6 +29,7 @@ import {Layout} from "./Customizations/Layout";
import {DropDown} from "./UI/Input/DropDown";
import {FixedInputElement} from "./UI/Input/FixedInputElement";
import {FixedUiElement} from "./UI/Base/FixedUiElement";
import ParkingType from "./Customizations/Questions/bike/ParkingType";
// --------------------- Read the URL parameters -----------------
@ -314,4 +315,11 @@ new GeoLocationHandler(bm).AttachTo("geolocate-button");
locationControl.ping();
messageBox.update();
/*
const eLanguageSelect = document.getElementById('language-select') as HTMLOptionElement
eLanguageSelect.addEventListener('input', e => {
// @ts-ignore
const selectedLanguage = e.target.value as string
Locale.language.setData(selectedLanguage.toLowerCase())
})
*/