Move 'translators'-logic into UserSettings

This commit is contained in:
Pieter Vander Vennet 2023-02-09 02:45:19 +01:00
parent fad62a2877
commit 79a88401dc
22 changed files with 321 additions and 277 deletions

View file

@ -1,7 +1,7 @@
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
import { OsmConnection } from "../Osm/OsmConnection"
import { MangroveIdentity } from "../Web/MangroveReviews"
import { Store } from "../UIEventSource"
import { Store, UIEventSource } from "../UIEventSource"
import { QueryParameters } from "../Web/QueryParameters"
import Locale from "../../UI/i18n/Locale"
import ElementsState from "./ElementsState"
@ -9,7 +9,6 @@ import SelectedElementTagsUpdater from "../Actors/SelectedElementTagsUpdater"
import { Changes } from "../Osm/Changes"
import ChangeToElementsActor from "../Actors/ChangeToElementsActor"
import PendingChangesUploader from "../Actors/PendingChangesUploader"
import translators from "../../assets/translators.json"
import Maproulette from "../Maproulette"
/**
@ -53,29 +52,25 @@ export default class UserRelatedState extends ElementsState {
osmConfiguration: <"osm" | "osm-test">this.featureSwitchApiURL.data,
attemptLogin: options?.attemptLogin,
})
const translationMode = this.osmConnection.GetPreference("translation-mode").sync(
(str) => (str === undefined ? undefined : str === "true"),
[],
(b) => (b === undefined ? undefined : b + "")
)
translationMode.syncWith(Locale.showLinkToWeblate)
this.isTranslator = this.osmConnection.userDetails.map((ud) => {
if (!ud.loggedIn) {
return false
}
const name = ud.name.toLowerCase().replace(/\s+/g, "")
return translators.contributors.some(
(c) => c.contributor.toLowerCase().replace(/\s+/g, "") === name
)
})
this.isTranslator.addCallbackAndRunD((ud) => {
if (ud) {
Locale.showLinkToWeblate.setData(true)
}
})
{
const translationMode: UIEventSource<undefined | "true" | "false" | "mobile" | string> =
this.osmConnection.GetPreference("translation-mode")
translationMode.addCallbackAndRunD((mode) => {
mode = mode.toLowerCase()
if (mode === "true" || mode === "yes") {
Locale.showLinkOnMobile.setData(false)
Locale.showLinkToWeblate.setData(true)
} else if (mode === "false" || mode === "no") {
Locale.showLinkToWeblate.setData(false)
} else if (mode === "mobile") {
Locale.showLinkOnMobile.setData(true)
Locale.showLinkToWeblate.setData(true)
} else {
Locale.showLinkOnMobile.setData(false)
Locale.showLinkToWeblate.setData(false)
}
})
}
this.changes = new Changes(this, layoutToUse?.isLeftRightSensitive() ?? false)
@ -117,41 +112,6 @@ export default class UserRelatedState extends ElementsState {
this.installedUserThemes = this.InitInstalledUserThemes()
}
private InitializeLanguage() {
const layoutToUse = this.layoutToUse
Locale.language.syncWith(this.osmConnection.GetPreference("language"))
Locale.language.addCallback((currentLanguage) => {
if (layoutToUse === undefined) {
return
}
if (Locale.showLinkToWeblate.data) {
return true // Disable auto switching as we are in translators mode
}
if (this.layoutToUse.language.indexOf(currentLanguage) < 0) {
console.log(
"Resetting language to",
layoutToUse.language[0],
"as",
currentLanguage,
" is unsupported"
)
// The current language is not supported -> switch to a supported one
Locale.language.setData(layoutToUse.language[0])
}
})
Locale.language.ping()
}
private InitInstalledUserThemes(): Store<string[]> {
const prefix = "mapcomplete-unofficial-theme-"
const postfix = "-combined-length"
return this.osmConnection.preferencesHandler.preferences.map((prefs) =>
Object.keys(prefs)
.filter((k) => k.startsWith(prefix) && k.endsWith(postfix))
.map((k) => k.substring(prefix.length, k.length - postfix.length))
)
}
public GetUnofficialTheme(id: string):
| {
id: string
@ -193,4 +153,39 @@ export default class UserRelatedState extends ElementsState {
return undefined
}
}
private InitializeLanguage() {
const layoutToUse = this.layoutToUse
Locale.language.syncWith(this.osmConnection.GetPreference("language"))
Locale.language.addCallback((currentLanguage) => {
if (layoutToUse === undefined) {
return
}
if (Locale.showLinkToWeblate.data) {
return true // Disable auto switching as we are in translators mode
}
if (this.layoutToUse.language.indexOf(currentLanguage) < 0) {
console.log(
"Resetting language to",
layoutToUse.language[0],
"as",
currentLanguage,
" is unsupported"
)
// The current language is not supported -> switch to a supported one
Locale.language.setData(layoutToUse.language[0])
}
})
Locale.language.ping()
}
private InitInstalledUserThemes(): Store<string[]> {
const prefix = "mapcomplete-unofficial-theme-"
const postfix = "-combined-length"
return this.osmConnection.preferencesHandler.preferences.map((prefs) =>
Object.keys(prefs)
.filter((k) => k.startsWith(prefix) && k.endsWith(postfix))
.map((k) => k.substring(prefix.length, k.length - postfix.length))
)
}
}

View file

@ -237,13 +237,11 @@ export default class LayoutConfig {
}
public missingTranslations(): {
completeness: Map<string, number>
untranslated: Map<string, string[]>
total: number
} {
const layout = this
let total = 0
const completeness = new Map<string, number>()
const untranslated = new Map<string, string[]>()
Utils.WalkObject(
@ -264,13 +262,21 @@ export default class LayoutConfig {
if (trans["*"] !== undefined) {
return
}
if (translation.context.indexOf(":") < 0) {
return
}
if (trans[ln] === undefined) {
if (!untranslated.has(ln)) {
untranslated.set(ln, [])
}
untranslated.get(ln).push(translation.context)
} else {
completeness.set(ln, 1 + (completeness.get(ln) ?? 0))
untranslated
.get(ln)
.push(
translation.context.replace(
/^note_import_[a-zA-Z0-9_]*/,
"note_import"
)
)
}
})
},
@ -282,7 +288,7 @@ export default class LayoutConfig {
}
)
return { completeness, untranslated, total }
return { untranslated, total }
}
public getMatchingLayer(tags: any): LayerConfig | undefined {
if (tags === undefined) {

View file

@ -2,6 +2,7 @@ import { VariableUiElement } from "./VariableUIElement"
import Locale from "../i18n/Locale"
import Link from "./Link"
import Svg from "../../Svg"
import show = Mocha.reporters.Base.cursor.show
/**
* The little 'translate'-icon next to every icon + some static helper functions
@ -31,7 +32,15 @@ export default class LinkToWeblate extends VariableUiElement {
[Locale.showLinkToWeblate]
)
)
this.SetClass("enable-links hidden-on-mobile")
this.SetClass("enable-links")
const self = this
Locale.showLinkOnMobile.addCallbackAndRunD((showOnMobile) => {
if (showOnMobile) {
self.RemoveClass("hidden-on-mobile")
} else {
self.SetClass("hidden-on-mobile")
}
})
}
/**

View file

@ -143,7 +143,7 @@ export default class ScrollableFullScreen {
)
const contentWrapper = new Combine([content]).SetClass(
"block p-2 md:pt-4 w-full h-full overflow-y-auto desktop:max-h-65vh"
"block p-2 md:pt-4 w-full h-full overflow-y-auto"
)
this._resetScrollSignal.addCallback((_) => {
@ -159,7 +159,7 @@ export default class ScrollableFullScreen {
// We add an ornament which takes around 5em. This is in order to make sure the Web UI doesn't hide
]).SetClass("flex flex-col h-full relative bg-white"),
]).SetClass(
"fixed top-0 left-0 right-0 h-screen w-screen desktop:max-h-65vh md:w-auto md:relative z-above-controls md:rounded-xl overflow-hidden"
"fixed top-0 left-0 right-0 h-screen w-screen md:w-auto md:relative z-above-controls md:rounded-xl overflow-hidden"
)
}

View file

@ -9,9 +9,10 @@ import { SubtleButton } from "../Base/SubtleButton"
import Svg from "../../Svg"
import { Utils } from "../../Utils"
import { MapillaryLink } from "./MapillaryLink"
import TranslatorsPanel from "./TranslatorsPanel"
import { OpenIdEditor, OpenJosm } from "./CopyrightPanel"
import Toggle from "../Input/Toggle"
import ScrollableFullScreen from "../Base/ScrollableFullScreen"
import { DefaultGuiState } from "../DefaultGuiState"
export class BackToThemeOverview extends Toggle {
constructor(
@ -77,7 +78,14 @@ export class ActionButtons extends Combine {
new OpenIdEditor(state, iconStyle),
new MapillaryLink(state, iconStyle),
new OpenJosm(state, iconStyle).SetClass("hidden-on-mobile"),
new TranslatorsPanel(state, iconStyle),
new SubtleButton(
Svg.translate_ui().SetStyle(iconStyle),
Translations.t.translations.activateButton
).onClick(() => {
ScrollableFullScreen.collapse()
DefaultGuiState.state.userInfoIsOpened.setData(true)
DefaultGuiState.state.userInfoFocusedQuestion.setData("translation-mode")
}),
])
this.SetClass("block w-full link-no-underline")
}

View file

@ -1,148 +0,0 @@
import Toggle from "../Input/Toggle"
import Lazy from "../Base/Lazy"
import { Utils } from "../../Utils"
import Translations from "../i18n/Translations"
import Combine from "../Base/Combine"
import Locale from "../i18n/Locale"
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
import { Translation } from "../i18n/Translation"
import { VariableUiElement } from "../Base/VariableUIElement"
import Link from "../Base/Link"
import LinkToWeblate from "../Base/LinkToWeblate"
import Toggleable from "../Base/Toggleable"
import Title from "../Base/Title"
import { Store } from "../../Logic/UIEventSource"
import { SubtleButton } from "../Base/SubtleButton"
import Svg from "../../Svg"
import native_languages from "../../assets/language_native.json"
import BaseUIElement from "../BaseUIElement"
class TranslatorsPanelContent extends Combine {
constructor(layout: LayoutConfig, isTranslator: Store<boolean>) {
const t = Translations.t.translations
const { completeness, untranslated, total } = layout.missingTranslations()
const seed = t.completeness
for (const ln of Array.from(completeness.keys())) {
if (ln === "*") {
continue
}
if (seed.translations[ln] === undefined) {
seed.translations[ln] = seed.translations["en"]
}
}
const completenessTr = {}
const completenessPercentage = {}
seed.SupportedLanguages().forEach((ln) => {
completenessTr[ln] = "" + (completeness.get(ln) ?? 0)
completenessPercentage[ln] =
"" + Math.round((100 * (completeness.get(ln) ?? 0)) / total)
})
function missingTranslationsFor(language: string): BaseUIElement[] {
// e.g. "themes:<themename>.layers.0.tagRenderings..., or "layers:<layername>.description
const missingKeys = Utils.NoNull(untranslated.get(language) ?? [])
.filter((ctx) => ctx.indexOf(":") >= 0)
.map((ctx) => ctx.replace(/note_import_[a-zA-Z0-9_]*/, "note_import"))
const hasMissingTheme = missingKeys.some((k) => k.startsWith("themes:"))
const missingLayers = Utils.Dedup(
missingKeys
.filter((k) => k.startsWith("layers:"))
.map((k) => k.slice("layers:".length).split(".")[0])
)
console.log(
"Getting untranslated string for",
language,
"raw:",
missingKeys,
"hasMissingTheme:",
hasMissingTheme,
"missingLayers:",
missingLayers
)
return Utils.NoNull([
hasMissingTheme
? new Link(
"themes:" + layout.id + ".* (zen mode)",
LinkToWeblate.hrefToWeblateZen(language, "themes", layout.id),
true
)
: undefined,
...missingLayers.map(
(id) =>
new Link(
"layer:" + id + ".* (zen mode)",
LinkToWeblate.hrefToWeblateZen(language, "layers", id),
true
)
),
...missingKeys.map(
(context) =>
new Link(context, LinkToWeblate.hrefToWeblate(language, context), true)
),
])
}
// "translationCompleteness": "Translations for {theme} in {language} are at {percentage}: {translated} out of {total}",
const translated = seed.Subs({
total,
theme: layout.title,
percentage: new Translation(completenessPercentage),
translated: new Translation(completenessTr),
language: seed.OnEveryLanguage((_, lng) => native_languages[lng] ?? lng),
})
super([
new Title(Translations.t.translations.activateButton),
new Toggle(t.isTranslator.SetClass("thanks block"), undefined, isTranslator),
t.help,
translated,
/*Disable button:*/
new SubtleButton(undefined, t.deactivate).onClick(() => {
Locale.showLinkToWeblate.setData(false)
}),
new VariableUiElement(
Locale.language.map((ln) => {
const missing = missingTranslationsFor(ln)
if (missing.length === 0) {
return undefined
}
let title = Translations.t.translations.allMissing
if (untranslated.get(ln) !== undefined) {
title = Translations.t.translations.missing.Subs({
count: untranslated.get(ln).length,
})
}
return new Toggleable(
new Title(title),
new Combine(missing).SetClass("flex flex-col")
)
})
),
])
}
}
export default class TranslatorsPanel extends Toggle {
constructor(
state: { layoutToUse: LayoutConfig; isTranslator: Store<boolean> },
iconStyle?: string
) {
const t = Translations.t.translations
super(
new Lazy(
() => new TranslatorsPanelContent(state.layoutToUse, state.isTranslator)
).SetClass("flex flex-col"),
new SubtleButton(Svg.translate_ui().SetStyle(iconStyle), t.activateButton).onClick(() =>
Locale.showLinkToWeblate.setData(true)
),
Locale.showLinkToWeblate
)
this.SetClass("hidden-on-mobile")
}
}

View file

@ -24,6 +24,9 @@ import { LoginToggle } from "../Popup/LoginButton"
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import translators from "../../assets/translators.json"
import codeContributors from "../../assets/contributors.json"
import Locale from "../i18n/Locale"
import { Utils } from "../../Utils"
import LinkToWeblate from "../Base/LinkToWeblate"
export class ImportViewerLinks extends VariableUiElement {
constructor(osmConnection: OsmConnection) {
@ -53,7 +56,7 @@ class SingleUserSettingsPanel extends EditableTagRendering {
userInfoFocusedQuestion?: UIEventSource<string>
) {
const editMode = new UIEventSource(false)
// Isolate the preferences. THey'll be updated explicitely later on anyway
// Isolate the preferences. They'll be updated explicitely later on anyway
super(
amendedPrefs,
config,
@ -68,6 +71,9 @@ class SingleUserSettingsPanel extends EditableTagRendering {
TagUtils.FlattenAnd(store.data, amendedPrefs.data)
).asChange(amendedPrefs.data)
for (const kv of selection) {
if (kv.k.startsWith("_")) {
continue
}
osmConnection.GetPreference(kv.k, "", "").setData(kv.v)
}
@ -104,13 +110,59 @@ class UserInformationMainPanel extends VariableUiElement {
const settings = new UIEventSource<Record<string, BaseUIElement>>({})
const usersettingsConfig = new LayerConfig(usersettings, "userinformationpanel")
const amendedPrefs = new UIEventSource<any>({})
const amendedPrefs = new UIEventSource<any>({ _theme: layout?.id })
osmConnection.preferencesHandler.preferences.addCallback((newPrefs) => {
for (const k in newPrefs) {
amendedPrefs.data[k] = newPrefs[k]
}
amendedPrefs.ping()
})
const translationMode = osmConnection.GetPreference("translation-mode")
Locale.language.mapD(
(language) => {
amendedPrefs.data["_language"] = language
const trmode = translationMode.data
if (trmode === "true" || trmode === "mobile") {
const missing = layout.missingTranslations()
const total = missing.total
const untranslated = missing.untranslated.get(language) ?? []
const hasMissingTheme = untranslated.some((k) => k.startsWith("themes:"))
const missingLayers = Utils.Dedup(
untranslated
.filter((k) => k.startsWith("layers:"))
.map((k) => k.slice("layers:".length).split(".")[0])
)
const zenLinks: { link: string; id: string }[] = Utils.NoNull([
hasMissingTheme
? {
id: "theme:" + layout.id,
link: LinkToWeblate.hrefToWeblateZen(
language,
"themes",
layout.id
),
}
: undefined,
...missingLayers.map((id) => ({
id: "layer:" + id,
link: LinkToWeblate.hrefToWeblateZen(language, "layers", id),
})),
])
const untranslated_count = untranslated.length
amendedPrefs.data["_translation_total"] = "" + total
amendedPrefs.data["_translation_translated_count"] =
"" + (total - untranslated_count)
amendedPrefs.data["_translation_percentage"] =
"" + Math.floor((100 * (total - untranslated_count)) / total)
console.log("Setting zenLinks", zenLinks)
amendedPrefs.data["_translation_links"] = JSON.stringify(zenLinks)
}
amendedPrefs.ping()
},
[translationMode]
)
osmConnection.userDetails.addCallback((userDetails) => {
for (const k in userDetails) {
amendedPrefs.data["_" + k] = "" + userDetails[k]

View file

@ -612,8 +612,8 @@ export default class SpecialVisualizations {
special: {
type: "multi",
key: "_doors_from_building_properties",
tagRendering: {
render: "The building containing this feature has a <a href='#{id}'>door</a> of width {entrance:width}",
tagrendering: {
en: "The building containing this feature has a <a href='#{id}'>door</a> of width {entrance:width}",
},
},
},

View file

@ -5,6 +5,10 @@ import { QueryParameters } from "../../Logic/Web/QueryParameters"
export default class Locale {
public static showLinkToWeblate: UIEventSource<boolean> = new UIEventSource<boolean>(false)
/**
* Indicates that -if showLinkToWeblate is true- a link on mobile mode is shown as well
*/
public static showLinkOnMobile: UIEventSource<boolean> = new UIEventSource<boolean>(false)
public static language: UIEventSource<string> = Locale.setup()
private static setup() {

View file

@ -62,6 +62,118 @@
}
]
},
{
"id": "translations-title",
"group": "translations",
"render": "<h3>Translating MapComplete</h3>"
},
{
"group": "translations",
"id": "translation-mode",
"question": {
"en": "Do you want to help translating MapComplete?"
},
"mappings": [
{
"if": "mapcomplete-translation-mode=false",
"then": {
"en": "Don't show a button to quickly change translations"
}
},
{
"if": "mapcomplete-translation-mode=true",
"then": {
"en": "Show a button to quickly open translations when using MapComplete on a big screen"
}
},
{
"if": "mapcomplete-translation-mode=mobile",
"then": {
"en": "Always show the translation buttons, including on mobile"
}
}
]
},
{
"group": "translations",
"id": "translation-help",
"mappings": [
{
"if": {
"or": [
"mapcomplete-translation-mode=yes",
"mapcomplete-translation-mode=true",
"mapcomplete-translation-mode=mobile"
]
},
"then": {
"ca": "Fes clic a la icona 'tradueix' al costat d'una cadena per introduir o actualitzar un fragment de text. Necessites un compte de Weblate per a això. Crea'n un amb el teu nom d'usuari OSM per desbloquejar automàticament el mode de traducció.",
"da": "Klik på 'oversæt'-ikonet ved siden af en streng for at indtaste eller opdatere et stykke tekst. Du skal have en Weblate-konto for at kunne gøre dette. Opret en med dit OSM-brugernavn for automatisk at låse oversættelsestilstanden op.",
"de": "Klicken Sie auf das Übersetzungssymbol neben einer Zeichenfolge, um den Übersetzungstext einzugeben oder zu aktualisieren. Dazu benötigen Sie ein Weblate-Konto. Erstellen Sie eines mit Ihrem OSM-Benutzernamen, um den Übersetzungsmodus automatisch freizuschalten.",
"en": "Click the 'translate'-icon next to a string to enter or update a piece of text. You need a Weblate-account for this. Create one with your OSM-username to automatically unlock translation mode.",
"es": "Haz clic en el icono 'traducir' al lado de una cadena para introducir o actualizar un texto. Necesitas una cuenta de Weblate para esto. Crea una con tu usuario de OSM para desbloquear el modo de traducción automáticamente.",
"fr": "Cliquez sur l'icône \"traduire\" à côté d'une chaîne de caractères pour saisir ou mettre à jour la chaine de texte. Vous aurez besoin d'un compte Weblate pour cela. Créez-en un avec votre nom d'utilisateur OSM pour déverrouiller automatiquement le mode traduction.",
"nl": "Klik op het 'vertaal'-icoontje die naast een stukje tekst staat om deze tekst te vertalen of aan te passen. Hiervoor heb je een (gratis) Weblate-account nodig. Indien je jouw account maakt met dezelfde naam als je OSM-gebruikersnaam, dan zullen de vertaalknoppen automatisch verschijnen.",
"zh_Hant": "點字串旁邊的 'translate'-icon 來輸入或是更新一段文字。你需要 Weblate 帳號。用你 OSM 帳號名稱來創建帳號,並且自動解鎖翻譯模式。"
},
"icon": "translate"
}
]
},
{
"group": "translations",
"id": "translation-completeness",
"render": {
"ca": "Les traduccions de {_theme} en {_language} tenen un {_translation_percentage}%: {_translation_translated_count} cadenes de {_translation_total} estan traduïdes",
"da": "Oversættelser for {_theme} i {_language} er på {_translation_percentage}%: {_translation_translated_count} strenge ud af {_translation_total} er oversat",
"de": "Die Übersetzung für {_theme} in {_language} ist zu {_translation_percentage}% vollständig: {_translation_translated_count} Zeichenfolgen von {_translation_total} sind übersetzt",
"en": "Translations for {_theme} in {_language} are at {_translation_percentage}%: {_translation_translated_count} strings out of {_translation_total} are translated",
"es": "Las traducciones para {_theme} en {_language} están al {_translation_percentage}%: {_translation_translated_count} cadenas de {_translation_total} están traducidas",
"id": "Terjemahan untuk {_theme} dalam {_language} masih {_translation_percentage}%: {_translation_translated_count} string dari {_translation_total} diterjemahkan",
"nb_NO": "Oversettelsen for {_theme} i {_language} har {_translation_percentage}% dekning: {_translation_translated_count} strenger av {_translation_total} har blitt oversatt",
"nl": "Vertalingen voor {_theme} in {_language} zijn momenteel op {_translation_percentage}%: van {_translation_total} teksten zijn er reeds {_translation_translated_count} vertaald",
"zh_Hant": "{_theme} 的 {_language} 翻譯目前是 {_translation_percentage}%{_translation_total} 中的 {_translation_translated_count} 已經翻譯了"
},
"condition": {
"or": [
"mapcomplete-translation-mode=yes",
"mapcomplete-translation-mode=true",
"mapcomplete-translation-mode=mobile"
]
},
"mappings": [
{
"if": "_translation_percentage=100",
"icon": "confirm",
"then": {
"en": "Completely translated",
"nl": "Volledig vertaald"
}
}
]
},
{
"id": "translation-links",
"group": "translations",
"condition": {
"and": [
"_translation_links~*",
{
"or": [
"mapcomplete-translation-mode=true",
"mapcomplete-translation-mode=mobile"
]
}
]
},
"render": {
"special": {
"type": "multi",
"key": "_translation_links",
"tagrendering": "<a href='{link}' target='_blank'>Translate entries of {id}</a>"
}
}
},
{
"id": "verified-mastodon",
"mappings": [
@ -85,6 +197,18 @@
}
]
},
{
"id": "cscount-thanks",
"mappings": [
{
"if": "_csCount>0",
"then": {
"en": "You have made changes on {_csCount} different occasions! That is awesome!"
},
"icon": "party"
}
]
},
{
"id": "translation-thanks",
"mappings": [
@ -110,15 +234,43 @@
"de": "Sie haben Code zu MapComplete mit {_code_contributions} Commits beigetragen! Das ist großartig!",
"nl": "Je hebt mee geprogrammeerd aan MapComplete met {_code_contributions} commits! Das supercool van je! Bedankt hiervoor!"
},
"icon": "party"
"icon": "party",
"hideInAnswer": true
}
]
},
{
"id": "show_debug",
"question": {
"en": "Show user settings debug info?"
},
"mappings": [
{
"if": "mapcomplete-show_debug=yes",
"then": {
"en": "Show debug info"
}
},
{
"if": "mapcomplete-show_debug=no",
"then": {
"en": "Don't show debug info"
}
},
{
"if": "mapcomplete-show_debug=",
"then": {
"en": "Don't show debug info"
},
"hideInAnswer": true
}
]
},
{
"id": "debug",
"condition": "_name=Pieter Vander Vennet",
"condition": "mapcomplete-show_debug=yes",
"render": "{all_tags()}"
}
],
"mapRendering": null
}
}

View file

@ -862,6 +862,10 @@ video {
margin-bottom: 6rem;
}
.ml-1 {
margin-left: 0.25rem;
}
.mb-2 {
margin-bottom: 0.5rem;
}
@ -910,10 +914,6 @@ video {
margin-bottom: 2rem;
}
.ml-1 {
margin-left: 0.25rem;
}
.mb-1 {
margin-bottom: 0.25rem;
}
@ -1027,6 +1027,10 @@ video {
height: 50%;
}
.h-3 {
height: 0.75rem;
}
.h-screen {
height: 100vh;
}
@ -1047,10 +1051,6 @@ video {
height: 0px;
}
.h-3 {
height: 0.75rem;
}
.h-48 {
height: 12rem;
}
@ -1115,6 +1115,10 @@ video {
width: 0px;
}
.w-3 {
width: 0.75rem;
}
.w-screen {
width: 100vw;
}
@ -1422,11 +1426,6 @@ video {
border-color: rgb(0 0 0 / var(--tw-border-opacity));
}
.border-gray-400 {
--tw-border-opacity: 1;
border-color: rgb(156 163 175 / var(--tw-border-opacity));
}
.border-gray-300 {
--tw-border-opacity: 1;
border-color: rgb(209 213 219 / var(--tw-border-opacity));
@ -1437,6 +1436,11 @@ video {
border-color: rgb(252 165 165 / var(--tw-border-opacity));
}
.border-gray-400 {
--tw-border-opacity: 1;
border-color: rgb(156 163 175 / var(--tw-border-opacity));
}
.border-blue-500 {
--tw-border-opacity: 1;
border-color: rgb(59 130 246 / var(--tw-border-opacity));

View file

@ -586,10 +586,6 @@
},
"translations": {
"activateButton": "Ajudar a traduir MapComplete",
"completeness": "Les traduccions de {theme} en {language} tenen un {percentage}%: {translated} cadenes de {total} estan traduïdes",
"deactivate": "Deshabilitar els botons de traducció",
"help": "Fes clic a la icona 'tradueix' al costat d'una cadena per introduir o actualitzar un fragment de text. Necessites un compte de Weblate per a això. Crea'n un amb el teu nom d'usuari OSM per desbloquejar automàticament el mode de traducció.",
"isTranslator": "El mode de traducció està actiu, ja que el vostre nom d'usuari coincideix amb el nom d'un traductor anterior",
"missing": "{count} cadenes sense traduir",
"notImmediate": "Les traduccions no s'actualitzen directament. Això sol trigar uns quants dies"
},

View file

@ -803,10 +803,6 @@
"translations": {
"activateButton": "Hjælp med at oversætte MapComplete",
"allMissing": "Ingen oversættelser endnu",
"completeness": "Oversættelser for {theme} i {language} er på {percentage}%: {translated} strenge ud af {total} er oversat",
"deactivate": "Slå oversættelsesknapper fra",
"help": "Klik på 'oversæt'-ikonet ved siden af en streng for at indtaste eller opdatere et stykke tekst. Du skal have en Weblate-konto for at kunne gøre dette. Opret en med dit OSM-brugernavn for automatisk at låse oversættelsestilstanden op.",
"isTranslator": "Oversættelsestilstanden er slået til, da dit brugernavn svarer til navnet på en tidligere oversætter",
"missing": "{count} uoversatte strenge",
"notImmediate": "Oversættelser opdateres ikke direkte. Det tager typisk et par dage"
},

View file

@ -928,10 +928,6 @@
"translations": {
"activateButton": "MapComplete übersetzen",
"allMissing": "Noch keine Übersetzungen",
"completeness": "Die Übersetzung für {theme} in {language} ist zu {percentage}% vollständig: {translated} Zeichenfolgen von {total} sind übersetzt",
"deactivate": "Übersetzungssymbol ausblenden",
"help": "Klicken Sie auf das Übersetzungssymbol neben einer Zeichenfolge, um den Übersetzungstext einzugeben oder zu aktualisieren. Dazu benötigen Sie ein Weblate-Konto. Erstellen Sie eines mit Ihrem OSM-Benutzernamen, um den Übersetzungsmodus automatisch freizuschalten.",
"isTranslator": "Der Übersetzungsmodus ist aktiv, da Ihr Benutzername mit dem Namen eines früheren Übersetzers übereinstimmt",
"missing": "{count} nicht übersetzte Zeichenfolgen",
"notImmediate": "Die Übersetzung wird nicht direkt aktualisiert. Dies dauert in der Regel ein paar Tage"
},

View file

@ -931,10 +931,6 @@
"translations": {
"activateButton": "Help translate MapComplete",
"allMissing": "No translations yet",
"completeness": "Translations for {theme} in {language} are at {percentage}%: {translated} strings out of {total} are translated",
"deactivate": "Disable translation buttons",
"help": "Click the 'translate'-icon next to a string to enter or update a piece of text. You need a Weblate-account for this. Create one with your OSM-username to automatically unlock translation mode.",
"isTranslator": "Translation mode is active as your username matches the name of a previous translator",
"missing": "{count} untranslated strings",
"notImmediate": "Translations are not updated directly. This typically takes a few days"
},

View file

@ -708,10 +708,6 @@
"translations": {
"activateButton": "Ayuda a traducir MapComplete",
"allMissing": "Aún sin traducciónes",
"completeness": "Las traducciones para {theme} en {language} están al {percentage}%: {translated} cadenas de {total} están traducidas",
"deactivate": "Deshabilitar los botones de traducción",
"help": "Haz clic en el icono 'traducir' al lado de una cadena para introducir o actualizar un texto. Necesitas una cuenta de Weblate para esto. Crea una con tu usuario de OSM para desbloquear el modo de traducción automáticamente.",
"isTranslator": "El modo de traducción está activo si tu nombre de usuario coincide con el nombre de un traductor anterior",
"missing": "{count} cadenas sin traducir",
"notImmediate": "Las traducciones no se actualizan directamente. Habitualmente esto lleva unos días"
},

View file

@ -473,9 +473,6 @@
},
"translations": {
"activateButton": "Aidez à traduire MapComplete",
"deactivate": "Désactiver les boutons de traduction",
"help": "Cliquez sur l'icône \"traduire\" à côté d'une chaîne de caractères pour saisir ou mettre à jour la chaine de texte. Vous aurez besoin d'un compte Weblate pour cela. Créez-en un avec votre nom d'utilisateur OSM pour déverrouiller automatiquement le mode traduction.",
"isTranslator": "Mode traduction activé, votre pseudo correspond à celui dune personne de léquipe de traduction",
"missing": "{count} segments non traduits"
},
"userinfo": {

View file

@ -265,8 +265,6 @@
},
"translations": {
"allMissing": "Belum ada terjemahan",
"completeness": "Terjemahan untuk {theme} dalam {language} masih {percentage}%: {translated} string dari {total} diterjemahkan",
"isTranslator": "Mode terjemahan aktif karena nama pengguna Anda cocok dengan nama penerjemah sebelumnya",
"notImmediate": "Terjemahan tidak diperbarui secara langsung. Biasanya memakan waktu beberapa hari"
},
"validation": {

View file

@ -689,9 +689,6 @@
"translations": {
"activateButton": "Bistå oversettelsen av MapComplete",
"allMissing": "Ingen oversettelser enda",
"completeness": "Oversettelsen for {theme} i {language} har {percentage}% dekning: {translated} strenger av {total} har blitt oversatt",
"deactivate": "Skru av oversettelsesknapper",
"isTranslator": "Oversettelsesmodus er aktivt siden brukernavnet ditt samsvarer med navnet på forrige oversetter",
"missing": "{count} uoversatte strenger",
"notImmediate": "Oversettelser oppdateres ikke direkte. Dette tar typisk et par dager."
},

View file

@ -928,10 +928,6 @@
"translations": {
"activateButton": "Help met het vertalen van MapComplete",
"allMissing": "Nog geen vertalingen",
"completeness": "Vertalingen voor {theme} in {language} zijn momenteel op {percentage}%: van {total} teksten zijn er reeds {translated} vertaald",
"deactivate": "Verberg de vertaalknoppen",
"help": "Klik op het 'vertaal'-icoontje die naast een stukje tekst staat om deze tekst te vertalen of aan te passen. Hiervoor heb je een (gratis) Weblate-account nodig. Indien je jouw account maakt met dezelfde naam als je OSM-gebruikersnaam, dan zullen de vertaalknoppen automatisch verschijnen.",
"isTranslator": "Vertaalmode is actief: je gebruikersnaam is dezelfde als van een vertaler. We gaan er dus vanuit dat jij die vertaler bent",
"missing": "{count} niet-vertaalde teksten",
"notImmediate": "Vertalingen worden niet onmiddelijk geupdate. Dit duurt gemiddeld enkele dagen"
},

View file

@ -189,8 +189,6 @@
"translations": {
"activateButton": "Pomóż przetłumaczyć MapComplete",
"allMissing": "Brak tłumaczeń",
"deactivate": "Wyłącz przyciski tłumaczenia",
"isTranslator": "Tryb tłumaczenia jest aktywny, ponieważ Twoja nazwa użytkownika odpowiada nazwisku poprzedniego tłumacza",
"notImmediate": "Tłumaczenia nie są aktualizowane bezpośrednio. Zwykle trwa to kilka dni"
},
"userinfo": {

View file

@ -720,10 +720,6 @@
"translations": {
"activateButton": "協助翻譯 MapComplete",
"allMissing": "還沒有翻譯",
"completeness": "{theme} 的 {language} 翻譯目前是 {percentage}%{total} 中的 {translated} 已經翻譯了",
"deactivate": "關閉翻譯按鈕",
"help": "點字串旁邊的 'translate'-icon 來輸入或是更新一段文字。你需要 Weblate 帳號。用你 OSM 帳號名稱來創建帳號,並且自動解鎖翻譯模式。",
"isTranslator": "翻譯模式已經啟用,你的名字符合前一位翻譯者的名字",
"missing": "{count} 未翻譯字串",
"notImmediate": "翻譯不會直接更新,通常會需要幾天時間"
},