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