2022-04-01 12:51:55 +02:00
|
|
|
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 {UIEventSource} from "../../Logic/UIEventSource";
|
|
|
|
import {SubtleButton} from "../Base/SubtleButton";
|
|
|
|
import Svg from "../../Svg";
|
|
|
|
|
|
|
|
|
|
|
|
class TranslatorsPanelContent extends Combine {
|
|
|
|
constructor(layout: LayoutConfig, isTranslator: UIEventSource<boolean>) {
|
|
|
|
const t = Translations.t.translations
|
|
|
|
|
2022-04-01 21:17:27 +02:00
|
|
|
const {completeness, untranslated, total} = TranslatorsPanel.MissingTranslationsFor(layout)
|
2022-04-01 12:51:55 +02:00
|
|
|
|
|
|
|
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)
|
|
|
|
})
|
|
|
|
|
|
|
|
const missingTranslationsFor = (ln: string) => Utils.NoNull(untranslated.get(ln) ?? [])
|
2022-04-03 23:42:35 +02:00
|
|
|
.filter(ctx => ctx.indexOf(":") >= 0)
|
2022-04-01 12:51:55 +02:00
|
|
|
.map(ctx => ctx.replace(/note_import_[a-zA-Z0-9_]*/, "note_import"))
|
|
|
|
.map(context => new Link(context, LinkToWeblate.hrefToWeblate(ln, context), true))
|
|
|
|
|
|
|
|
|
2022-04-01 21:17:27 +02:00
|
|
|
// "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)
|
|
|
|
})
|
|
|
|
|
2022-04-01 12:51:55 +02:00
|
|
|
super([
|
|
|
|
new Title(
|
|
|
|
Translations.t.translations.activateButton,
|
|
|
|
),
|
|
|
|
new Toggle(t.isTranslator.SetClass("thanks block"), undefined, isTranslator),
|
|
|
|
t.help,
|
|
|
|
translated,
|
2022-04-01 21:17:27 +02:00
|
|
|
/*Disable button:*/
|
|
|
|
new SubtleButton(undefined, t.deactivate)
|
|
|
|
.onClick(() => {
|
|
|
|
Locale.showLinkToWeblate.setData(false)
|
|
|
|
}),
|
|
|
|
|
2022-04-01 12:51:55 +02:00
|
|
|
new VariableUiElement(Locale.language.map(ln => {
|
|
|
|
|
|
|
|
const missing = missingTranslationsFor(ln)
|
|
|
|
if (missing.length === 0) {
|
|
|
|
return undefined
|
|
|
|
}
|
|
|
|
return new Toggleable(
|
|
|
|
new Title(Translations.t.translations.missing.Subs({count: missing.length})),
|
|
|
|
new Combine(missing).SetClass("flex flex-col")
|
|
|
|
)
|
|
|
|
}))
|
|
|
|
])
|
|
|
|
|
|
|
|
}
|
2022-04-01 21:17:27 +02:00
|
|
|
|
2022-04-01 12:51:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
).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")
|
|
|
|
|
|
|
|
}
|
2022-04-01 21:17:27 +02:00
|
|
|
|
|
|
|
|
|
|
|
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){
|
|
|
|
return
|
|
|
|
}
|
|
|
|
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 => {
|
|
|
|
const trans = translation.translations
|
|
|
|
if (trans["*"] !== undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (trans[ln] === undefined) {
|
|
|
|
if (!untranslated.has(ln)) {
|
|
|
|
untranslated.set(ln, [])
|
|
|
|
}
|
|
|
|
untranslated.get(ln).push(translation.context)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
if(translation.translations["*"] === undefined){
|
|
|
|
total++
|
|
|
|
}
|
|
|
|
}, o => {
|
|
|
|
if (o === undefined || o === null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return o instanceof Translation;
|
|
|
|
})
|
|
|
|
|
|
|
|
return {completeness, untranslated, total}
|
|
|
|
}
|
2022-04-01 12:51:55 +02:00
|
|
|
}
|