forked from MapComplete/MapComplete
Move 'translators'-logic into UserSettings
This commit is contained in:
parent
fad62a2877
commit
79a88401dc
22 changed files with 321 additions and 277 deletions
|
@ -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")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
|
@ -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]
|
||||
|
|
|
@ -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}",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue