Better translators panel

This commit is contained in:
pietervdvn 2022-04-15 00:10:04 +02:00
parent 063ccd2025
commit 7d7abc303b
3 changed files with 58 additions and 30 deletions

View file

@ -4,6 +4,7 @@ import Link from "./Link";
import Svg from "../../Svg";
export default class LinkToWeblate extends VariableUiElement {
private static URI: any;
constructor(context: string, availableTranslations: object) {
super( Locale.language.map(ln => {
if (Locale.showLinkToWeblate.data === false) {
@ -36,4 +37,10 @@ export default class LinkToWeblate extends VariableUiElement {
const baseUrl = "https://hosted.weblate.org/translate/mapcomplete/"
return baseUrl + category + "/" + language + "/?offset=1&q=context%3A%3D%22" + key + "%22"
}
public static hrefToWeblateZen(language: string, category: string, searchKey: string): string{
const baseUrl = "https://hosted.weblate.org/zen/mapcomplete/"
// ?offset=1&q=+state%3A%3Ctranslated+context%3Acampersite&sort_by=-priority%2Cposition&checksum=
return baseUrl + category + "/" + language + "?offset=1&q=+state%3A%3Ctranslated+context%3A"+encodeURIComponent(searchKey)+"&sort_by=-priority%2Cposition&checksum="
}
}

View file

@ -15,6 +15,8 @@ import {UIEventSource} from "../../Logic/UIEventSource";
import {SubtleButton} from "../Base/SubtleButton";
import Svg from "../../Svg";
import * as native_languages from "../../assets/language_native.json"
import * as used_languages from "../../assets/generated/used_languages.json"
import BaseUIElement from "../BaseUIElement";
class TranslatorsPanelContent extends Combine {
constructor(layout: LayoutConfig, isTranslator: UIEventSource<boolean>) {
@ -24,37 +26,53 @@ class TranslatorsPanelContent extends Combine {
const seed = t.completeness
for (const ln of Array.from(completeness.keys())) {
if(ln === "*"){
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)
completenessTr[ln] = "" + (completeness.get(ln) ?? 0)
completenessPercentage[ln] = "" + Math.round(100 * (completeness.get(ln) ?? 0) / total)
})
const missingTranslationsFor = (ln: string) => Utils.NoNull(untranslated.get(ln) ?? [])
.filter(ctx => ctx.indexOf(":") >= 0)
.map(ctx => ctx.replace(/note_import_[a-zA-Z0-9_]*/, "note_import"))
.map(context => new Link(context, LinkToWeblate.hrefToWeblate(ln, context), true))
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 [
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,
const translated = seed.Subs({
total, theme: layout.title,
percentage: new Translation(completenessPercentage),
translated: new Translation(completenessTr),
language: seed.OnEveryLanguage((_, lng) => native_languages[lng])
language: seed.OnEveryLanguage((_, lng) => native_languages[lng] ?? lng)
})
super([
new Title(
Translations.t.translations.activateButton,
Translations.t.translations.activateButton,
),
new Toggle(t.isTranslator.SetClass("thanks block"), undefined, isTranslator),
t.help,
@ -64,15 +82,18 @@ class TranslatorsPanelContent extends Combine {
.onClick(() => {
Locale.showLinkToWeblate.setData(false)
}),
new VariableUiElement(Locale.language.map(ln => {
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(Translations.t.translations.missing.Subs({count: missing.length})),
new Title(title),
new Combine(missing).SetClass("flex flex-col")
)
}))
@ -84,38 +105,37 @@ class TranslatorsPanelContent extends Combine {
export default class TranslatorsPanel extends Toggle {
constructor(state: { layoutToUse: LayoutConfig, isTranslator: UIEventSource<boolean> }, iconStyle?: string) {
const t = Translations.t.translations
super(
new Lazy(() => new TranslatorsPanelContent(state.layoutToUse, state.isTranslator)
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
Locale.showLinkToWeblate
)
this.SetClass("hidden-on-mobile")
}
public static MissingTranslationsFor(layout: LayoutConfig) : {completeness: Map<string, number>, untranslated: Map<string, string[]>, total: number} {
public static MissingTranslationsFor(layout: LayoutConfig): { completeness: Map<string, number>, untranslated: Map<string, string[]>, total: number } {
let total = 0
const completeness = new Map<string, number>()
const untranslated = new Map<string, string[]>()
Utils.WalkObject(layout, (o, path) => {
const translation = <Translation><any>o;
if(translation.translations["*"] !== undefined){
if (translation.translations["*"] !== undefined) {
return
}
if(translation.context === undefined || translation.context.indexOf(":") < 0){
if (translation.context === undefined || translation.context.indexOf(":") < 0) {
// no source given - lets ignore
return
}
for (const lang of translation.SupportedLanguages()) {
completeness.set(lang, 1 + (completeness.get(lang) ?? 0))
}
layout.title.SupportedLanguages().forEach(ln => {
total ++
used_languages.languages.forEach(ln => {
const trans = translation.translations
if (trans["*"] !== undefined) {
return;
@ -125,11 +145,11 @@ export default class TranslatorsPanel extends Toggle {
untranslated.set(ln, [])
}
untranslated.get(ln).push(translation.context)
}else{
completeness.set(ln, 1 + (completeness.get(ln) ?? 0))
}
})
if(translation.translations["*"] === undefined){
total++
}
}, o => {
if (o === undefined || o === null) {
return false;

View file

@ -532,6 +532,7 @@
},
"translations": {
"activateButton": "Help to 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.",