From 79a88401dc57f802b133128a3f1a942fe20630fb Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Thu, 9 Feb 2023 02:45:19 +0100 Subject: [PATCH] Move 'translators'-logic into UserSettings --- Logic/State/UserRelatedState.ts | 115 +++++++------- Models/ThemeConfig/LayoutConfig.ts | 18 ++- UI/Base/LinkToWeblate.ts | 11 +- UI/Base/ScrollableFullScreen.ts | 4 +- UI/BigComponents/ActionButtons.ts | 12 +- UI/BigComponents/TranslatorsPanel.ts | 148 ----------------- UI/BigComponents/UserInformation.ts | 56 ++++++- UI/SpecialVisualizations.ts | 4 +- UI/i18n/Locale.ts | 4 + assets/layers/usersettings/usersettings.json | 158 ++++++++++++++++++- css/index-tailwind-output.css | 30 ++-- langs/ca.json | 4 - langs/da.json | 4 - langs/de.json | 4 - langs/en.json | 4 - langs/es.json | 4 - langs/fr.json | 3 - langs/id.json | 2 - langs/nb_NO.json | 3 - langs/nl.json | 4 - langs/pl.json | 2 - langs/zh_Hant.json | 4 - 22 files changed, 321 insertions(+), 277 deletions(-) delete mode 100644 UI/BigComponents/TranslatorsPanel.ts diff --git a/Logic/State/UserRelatedState.ts b/Logic/State/UserRelatedState.ts index fa6c5b6afd..ba5f4cab60 100644 --- a/Logic/State/UserRelatedState.ts +++ b/Logic/State/UserRelatedState.ts @@ -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 = + 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 { - 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 { + 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)) + ) + } } diff --git a/Models/ThemeConfig/LayoutConfig.ts b/Models/ThemeConfig/LayoutConfig.ts index 8fe75183e2..fdca8d638f 100644 --- a/Models/ThemeConfig/LayoutConfig.ts +++ b/Models/ThemeConfig/LayoutConfig.ts @@ -237,13 +237,11 @@ export default class LayoutConfig { } public missingTranslations(): { - completeness: Map untranslated: Map total: number } { const layout = this let total = 0 - const completeness = new Map() const untranslated = new Map() 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) { diff --git a/UI/Base/LinkToWeblate.ts b/UI/Base/LinkToWeblate.ts index 8b36089c39..73afabb563 100644 --- a/UI/Base/LinkToWeblate.ts +++ b/UI/Base/LinkToWeblate.ts @@ -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") + } + }) } /** diff --git a/UI/Base/ScrollableFullScreen.ts b/UI/Base/ScrollableFullScreen.ts index 9dd6a83c81..6a9261d94a 100644 --- a/UI/Base/ScrollableFullScreen.ts +++ b/UI/Base/ScrollableFullScreen.ts @@ -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" ) } diff --git a/UI/BigComponents/ActionButtons.ts b/UI/BigComponents/ActionButtons.ts index cb492a80b5..2382791790 100644 --- a/UI/BigComponents/ActionButtons.ts +++ b/UI/BigComponents/ActionButtons.ts @@ -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") } diff --git a/UI/BigComponents/TranslatorsPanel.ts b/UI/BigComponents/TranslatorsPanel.ts deleted file mode 100644 index 2fed2dde8a..0000000000 --- a/UI/BigComponents/TranslatorsPanel.ts +++ /dev/null @@ -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) { - 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:.layers.0.tagRenderings..., or "layers:.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 }, - 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") - } -} diff --git a/UI/BigComponents/UserInformation.ts b/UI/BigComponents/UserInformation.ts index 5791f12e6e..7acc9110a9 100644 --- a/UI/BigComponents/UserInformation.ts +++ b/UI/BigComponents/UserInformation.ts @@ -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 ) { 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>({}) const usersettingsConfig = new LayerConfig(usersettings, "userinformationpanel") - const amendedPrefs = new UIEventSource({}) + const amendedPrefs = new UIEventSource({ _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] diff --git a/UI/SpecialVisualizations.ts b/UI/SpecialVisualizations.ts index 67349cdf17..b9b16a878f 100644 --- a/UI/SpecialVisualizations.ts +++ b/UI/SpecialVisualizations.ts @@ -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 door of width {entrance:width}", + tagrendering: { + en: "The building containing this feature has a door of width {entrance:width}", }, }, }, diff --git a/UI/i18n/Locale.ts b/UI/i18n/Locale.ts index c88a655c73..d989db3b37 100644 --- a/UI/i18n/Locale.ts +++ b/UI/i18n/Locale.ts @@ -5,6 +5,10 @@ import { QueryParameters } from "../../Logic/Web/QueryParameters" export default class Locale { public static showLinkToWeblate: UIEventSource = new UIEventSource(false) + /** + * Indicates that -if showLinkToWeblate is true- a link on mobile mode is shown as well + */ + public static showLinkOnMobile: UIEventSource = new UIEventSource(false) public static language: UIEventSource = Locale.setup() private static setup() { diff --git a/assets/layers/usersettings/usersettings.json b/assets/layers/usersettings/usersettings.json index a02ee467a9..830f6d0d90 100644 --- a/assets/layers/usersettings/usersettings.json +++ b/assets/layers/usersettings/usersettings.json @@ -62,6 +62,118 @@ } ] }, + { + "id": "translations-title", + "group": "translations", + "render": "

Translating MapComplete

" + }, + { + "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": "Translate entries of {id}" + } + } + }, { "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 -} \ No newline at end of file +} diff --git a/css/index-tailwind-output.css b/css/index-tailwind-output.css index 1b42e5aca7..628a27c371 100644 --- a/css/index-tailwind-output.css +++ b/css/index-tailwind-output.css @@ -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)); diff --git a/langs/ca.json b/langs/ca.json index 2ca085f7e8..3931b80674 100644 --- a/langs/ca.json +++ b/langs/ca.json @@ -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" }, diff --git a/langs/da.json b/langs/da.json index 37bb0ed6a5..cf9c5716f3 100644 --- a/langs/da.json +++ b/langs/da.json @@ -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" }, diff --git a/langs/de.json b/langs/de.json index 307d9f21f1..bc0bfd25ba 100644 --- a/langs/de.json +++ b/langs/de.json @@ -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" }, diff --git a/langs/en.json b/langs/en.json index f51f486a26..aa08ff1c16 100644 --- a/langs/en.json +++ b/langs/en.json @@ -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" }, diff --git a/langs/es.json b/langs/es.json index ca373fdace..b5c09434c8 100644 --- a/langs/es.json +++ b/langs/es.json @@ -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" }, diff --git a/langs/fr.json b/langs/fr.json index aa9248a75e..778c22efd9 100644 --- a/langs/fr.json +++ b/langs/fr.json @@ -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 d’une personne de l’équipe de traduction", "missing": "{count} segments non traduits" }, "userinfo": { diff --git a/langs/id.json b/langs/id.json index 0e79525777..9bc317537a 100644 --- a/langs/id.json +++ b/langs/id.json @@ -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": { diff --git a/langs/nb_NO.json b/langs/nb_NO.json index 27578a9b7d..7c4bea6043 100644 --- a/langs/nb_NO.json +++ b/langs/nb_NO.json @@ -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." }, diff --git a/langs/nl.json b/langs/nl.json index 4ca58aed98..f6177c851a 100644 --- a/langs/nl.json +++ b/langs/nl.json @@ -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" }, diff --git a/langs/pl.json b/langs/pl.json index 4a3054fd11..4e95bf8f8d 100644 --- a/langs/pl.json +++ b/langs/pl.json @@ -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": { diff --git a/langs/zh_Hant.json b/langs/zh_Hant.json index 7e5ad6cc7e..1bc0a8a25d 100644 --- a/langs/zh_Hant.json +++ b/langs/zh_Hant.json @@ -720,10 +720,6 @@ "translations": { "activateButton": "協助翻譯 MapComplete", "allMissing": "還沒有翻譯", - "completeness": "{theme} 的 {language} 翻譯目前是 {percentage}%:{total} 中的 {translated} 已經翻譯了", - "deactivate": "關閉翻譯按鈕", - "help": "點字串旁邊的 'translate'-icon 來輸入或是更新一段文字。你需要 Weblate 帳號。用你 OSM 帳號名稱來創建帳號,並且自動解鎖翻譯模式。", - "isTranslator": "翻譯模式已經啟用,你的名字符合前一位翻譯者的名字", "missing": "{count} 未翻譯字串", "notImmediate": "翻譯不會直接更新,通常會需要幾天時間" },