forked from MapComplete/MapComplete
Translations
This commit is contained in:
parent
615bbec05d
commit
369c19a58a
34 changed files with 287 additions and 173 deletions
|
@ -34,7 +34,7 @@ export class CenterMessageBox extends UIElement {
|
|||
|
||||
}
|
||||
|
||||
protected InnerRender(): string {
|
||||
InnerRender(): string {
|
||||
|
||||
if (this._centermessage.data != "") {
|
||||
return this._centermessage.data;
|
||||
|
|
|
@ -10,7 +10,7 @@ import {TagRenderingOptions} from "../Customizations/TagRendering";
|
|||
import {OsmLink} from "../Customizations/Questions/OsmLink";
|
||||
import {WikipediaLink} from "../Customizations/Questions/WikipediaLink";
|
||||
import {And} from "../Logic/TagsFilter";
|
||||
import {TagDependantUIElement} from "../Customizations/UIElementConstructor";
|
||||
import {TagDependantUIElement, TagDependantUIElementConstructor} from "../Customizations/UIElementConstructor";
|
||||
|
||||
export class FeatureInfoBox extends UIElement {
|
||||
|
||||
|
@ -31,7 +31,7 @@ export class FeatureInfoBox extends UIElement {
|
|||
constructor(
|
||||
tagsES: UIEventSource<any>,
|
||||
title: TagRenderingOptions,
|
||||
elementsToShow: TagRenderingOptions[],
|
||||
elementsToShow: TagDependantUIElementConstructor[],
|
||||
changes: Changes,
|
||||
userDetails: UIEventSource<UserDetails>
|
||||
) {
|
||||
|
|
|
@ -34,14 +34,14 @@ class ImageCarouselWithUpload extends TagDependantUIElement {
|
|||
const changes = dependencies.changes;
|
||||
this._imageElement = new ImageCarousel(tags, changes);
|
||||
const userDetails = changes.login.userDetails;
|
||||
const license = changes.login.GetPreference( "mapcomplete-pictures-license");
|
||||
const license = changes.login.GetPreference( "pictures-license");
|
||||
this._pictureUploader = new OsmImageUploadHandler(tags,
|
||||
userDetails, license,
|
||||
changes, this._imageElement.slideshow).getUI();
|
||||
|
||||
}
|
||||
|
||||
protected InnerRender(): string {
|
||||
InnerRender(): string {
|
||||
return this._imageElement.Render() +
|
||||
this._pictureUploader.Render();
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import {Imgur} from "../Logic/Imgur";
|
|||
import {UserDetails} from "../Logic/OsmConnection";
|
||||
import {DropDown} from "./Input/DropDown";
|
||||
import {VariableUiElement} from "./Base/VariableUIElement";
|
||||
import Translations from "./i18n/Translations";
|
||||
|
||||
export class ImageUploadFlow extends UIElement {
|
||||
private _licensePicker: UIElement;
|
||||
|
@ -66,7 +67,7 @@ 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'>Add a picture</span>" +
|
||||
"<span class='imageflow-add-picture'>"+Translations.general.uploadAPicture.R()+"</span>" +
|
||||
"<div class='break'></div>" +
|
||||
"</div>" +
|
||||
|
||||
|
|
|
@ -50,7 +50,10 @@ export class DropDown<T> extends InputElement<T> {
|
|||
|
||||
|
||||
InnerRender(): string {
|
||||
|
||||
if(this._values.length <=1){
|
||||
return "";
|
||||
}
|
||||
|
||||
let options = "";
|
||||
for (let i = 0; i < this._values.length; i++) {
|
||||
options += "<option value='" + i + "'>" + this._values[i].shown.InnerRender() + "</option>"
|
||||
|
@ -65,8 +68,12 @@ export class DropDown<T> extends InputElement<T> {
|
|||
}
|
||||
|
||||
protected InnerUpdate(element) {
|
||||
|
||||
|
||||
var e = document.getElementById("dropdown-" + this.id);
|
||||
if(e === null){
|
||||
return;
|
||||
}
|
||||
const self = this;
|
||||
e.onchange = (() => {
|
||||
// @ts-ignore
|
||||
|
|
|
@ -105,7 +105,6 @@ export class TextField<T> extends InputElement<T> {
|
|||
}
|
||||
|
||||
IsValid(t: T): boolean {
|
||||
console.log("TXT IS valid?",t,this._toString(t))
|
||||
if(t === undefined || t === null){
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ import {UIElement} from "./UIElement";
|
|||
import {VariableUiElement} from "./Base/VariableUIElement";
|
||||
|
||||
export class MessageBoxHandler {
|
||||
private _uielement: UIEventSource<() => UIElement>;
|
||||
private _uielement: UIEventSource<UIElement>;
|
||||
|
||||
constructor(uielement: UIEventSource<() => UIElement>,
|
||||
constructor(uielement: UIEventSource<UIElement>,
|
||||
onClear: (() => void)) {
|
||||
this._uielement = uielement;
|
||||
this.listenTo(uielement);
|
||||
|
@ -22,14 +22,13 @@ export class MessageBoxHandler {
|
|||
}
|
||||
}
|
||||
|
||||
new VariableUiElement(new UIEventSource<string>("<h2>Return to the map</h2>"),
|
||||
() => {
|
||||
document.getElementById("to-the-map").onclick = function () {
|
||||
uielement.setData(undefined);
|
||||
onClear();
|
||||
}
|
||||
}
|
||||
).AttachTo("to-the-map");
|
||||
new VariableUiElement(new UIEventSource<string>("<h2>Return to the map</h2>"))
|
||||
.onClick(() => {
|
||||
console.log("Clicked 'return to the map'")
|
||||
uielement.setData(undefined);
|
||||
onClear();
|
||||
})
|
||||
.AttachTo("to-the-map");
|
||||
|
||||
|
||||
}
|
||||
|
@ -55,7 +54,7 @@ export class MessageBoxHandler {
|
|||
location.hash = "#element"
|
||||
wrapper.classList.remove("hidden");
|
||||
|
||||
gen()
|
||||
gen
|
||||
?.HideOnEmpty(true)
|
||||
?.AttachTo("messagesboxmobile")
|
||||
?.Activate();
|
||||
|
|
|
@ -21,7 +21,7 @@ export class PendingChanges extends UIElement {
|
|||
})
|
||||
}
|
||||
|
||||
protected InnerRender(): string {
|
||||
InnerRender(): string {
|
||||
if (this._isSaving.data) {
|
||||
return "<span class='alert'>Saving</span>";
|
||||
}
|
||||
|
|
|
@ -37,11 +37,10 @@ export abstract class UIElement {
|
|||
|
||||
Update(): void {
|
||||
let element = document.getElementById(this.id);
|
||||
if (element === null || element === undefined) {
|
||||
if (element === undefined || element === null) {
|
||||
// The element is not painted
|
||||
return;
|
||||
}
|
||||
|
||||
element.innerHTML = this.InnerRender();
|
||||
if (this._hideIfEmpty) {
|
||||
if (element.innerHTML === "") {
|
||||
|
|
|
@ -66,5 +66,16 @@ export class UIEventSource<T>{
|
|||
|
||||
}
|
||||
|
||||
|
||||
public syncWith(otherSource: UIEventSource<T>){
|
||||
this.addCallback((latest) => otherSource.setData(latest));
|
||||
const self = this;
|
||||
otherSource.addCallback((latest) => self.setData(latest));
|
||||
if(this.data === undefined){
|
||||
this.setData(otherSource.data);
|
||||
}else{
|
||||
otherSource.setData(this.data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -5,6 +5,7 @@ import {Basemap} from "../Logic/Basemap";
|
|||
import L from "leaflet";
|
||||
import {FixedUiElement} from "./Base/FixedUiElement";
|
||||
import {VariableUiElement} from "./Base/VariableUIElement";
|
||||
import Translations from "./i18n/Translations";
|
||||
|
||||
/**
|
||||
* Handles and updates the user badge
|
||||
|
@ -15,13 +16,15 @@ export class UserBadge extends UIElement {
|
|||
private _logout: UIElement;
|
||||
private _basemap: Basemap;
|
||||
private _homeButton: UIElement;
|
||||
private _languagePicker: UIElement;
|
||||
|
||||
|
||||
constructor(userDetails: UIEventSource<UserDetails>,
|
||||
pendingChanges: UIElement,
|
||||
languagePicker: UIElement,
|
||||
basemap: Basemap) {
|
||||
super(userDetails);
|
||||
|
||||
this._languagePicker = languagePicker;
|
||||
this._userDetails = userDetails;
|
||||
this._pendingChanges = pendingChanges;
|
||||
this._basemap = basemap;
|
||||
|
@ -61,7 +64,7 @@ export class UserBadge extends UIElement {
|
|||
InnerRender(): string {
|
||||
const user = this._userDetails.data;
|
||||
if (!user.loggedIn) {
|
||||
return "<div class='activate-osm-authentication'>Login with OpenStreetMap</div>";
|
||||
return "<div class='activate-osm-authentication'>" + Translations.general.loginWithOpenStreetMap.R()+ "</div>";
|
||||
}
|
||||
|
||||
|
||||
|
@ -114,6 +117,7 @@ export class UserBadge extends UIElement {
|
|||
" <a href='https://www.openstreetmap.org/user/" + user.name + "/history' target='_blank'><img class='small-userbadge-icon' src='./assets/star.svg' alt='star'/> " + user.csCount +
|
||||
"</a></span> " +
|
||||
this._logout.Render() +
|
||||
this._languagePicker.Render() +
|
||||
this._pendingChanges.Render() +
|
||||
"</p>" +
|
||||
|
||||
|
|
|
@ -1,18 +1,24 @@
|
|||
import { UIEventSource } from "../UIEventSource";
|
||||
import {UIEventSource} from "../UIEventSource";
|
||||
import {OsmConnection} from "../../Logic/OsmConnection";
|
||||
|
||||
|
||||
const LANGUAGE_KEY = 'language'
|
||||
|
||||
export default class Locale {
|
||||
public static language: UIEventSource<string> = new UIEventSource(Locale.getInitialLanguage())
|
||||
|
||||
public static init() {
|
||||
Locale.language.addCallback(data => {
|
||||
localStorage.setItem(LANGUAGE_KEY, data)
|
||||
})
|
||||
}
|
||||
public static language: UIEventSource<string> = Locale.getInitialLanguage()
|
||||
|
||||
private static getInitialLanguage() {
|
||||
return localStorage.getItem(LANGUAGE_KEY)
|
||||
// The key to save in local storage
|
||||
const LANGUAGE_KEY = 'language'
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,30 @@
|
|||
import { UIElement } from "../UIElement"
|
||||
import Locale from "./Locale"
|
||||
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||
|
||||
|
||||
export default class Translation extends UIElement{
|
||||
protected InnerRender(): string {
|
||||
return this.translations[Locale.language.data]
|
||||
}
|
||||
export default class Translation extends UIElement {
|
||||
|
||||
public readonly translations: object
|
||||
|
||||
|
||||
constructor(translations: object) {
|
||||
super(Locale.language)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,18 +1,42 @@
|
|||
import Translation from "./Translation";
|
||||
import {UIElement} from "../UIElement";
|
||||
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||
|
||||
|
||||
export default class Translations {
|
||||
static t = {
|
||||
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 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"
|
||||
}),
|
||||
uploadAPicture: new Translation({
|
||||
en: "Add a picture",
|
||||
nl: "Voeg een foto toe"
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
public static W(s: string | UIElement):
|
||||
UIElement {
|
||||
if (s instanceof UIElement) {
|
||||
return s;
|
||||
}
|
||||
return new FixedUiElement(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue