Reformat all files with prettier

This commit is contained in:
Pieter Vander Vennet 2022-09-08 21:40:48 +02:00
parent e22d189376
commit b541d3eab4
382 changed files with 50893 additions and 35566 deletions

View file

@ -1,16 +1,14 @@
import {UIEventSource} from "../../Logic/UIEventSource";
import {LocalStorageSource} from "../../Logic/Web/LocalStorageSource";
import {Utils} from "../../Utils";
import {QueryParameters} from "../../Logic/Web/QueryParameters";
import { UIEventSource } from "../../Logic/UIEventSource"
import { LocalStorageSource } from "../../Logic/Web/LocalStorageSource"
import { Utils } from "../../Utils"
import { QueryParameters } from "../../Logic/Web/QueryParameters"
export default class Locale {
public static showLinkToWeblate: UIEventSource<boolean> = new UIEventSource<boolean>(false)
public static language: UIEventSource<string> = Locale.setup()
public static showLinkToWeblate: UIEventSource<boolean> = new UIEventSource<boolean>(false);
public static language: UIEventSource<string> = Locale.setup();
private static setup() {
const source = LocalStorageSource.Get('language', "en");
const source = LocalStorageSource.Get("language", "en")
if (!Utils.runningFromConsole) {
// @ts-ignore
window.setLanguage = function (language: string) {
@ -18,17 +16,21 @@ export default class Locale {
}
}
source.syncWith(
QueryParameters.GetQueryParameter("language", undefined, "The language to display mapcomplete in. Will be ignored in case a logged-in-user did set their language before. If the specified language does not exist, it will default to the first language in the theme."),
QueryParameters.GetQueryParameter(
"language",
undefined,
"The language to display mapcomplete in. Will be ignored in case a logged-in-user did set their language before. If the specified language does not exist, it will default to the first language in the theme."
),
true
)
QueryParameters.GetBooleanQueryParameter("fs-translation-mode",false,"If set, will show a translation button next to every string.")
.addCallbackAndRunD(tr => {
Locale.showLinkToWeblate.setData(Locale.showLinkToWeblate.data || tr);
QueryParameters.GetBooleanQueryParameter(
"fs-translation-mode",
false,
"If set, will show a translation button next to every string."
).addCallbackAndRunD((tr) => {
Locale.showLinkToWeblate.setData(Locale.showLinkToWeblate.data || tr)
})
return source;
return source
}
}

View file

@ -1,72 +1,82 @@
import Locale from "./Locale";
import {Utils} from "../../Utils";
import BaseUIElement from "../BaseUIElement";
import LinkToWeblate from "../Base/LinkToWeblate";
import Locale from "./Locale"
import { Utils } from "../../Utils"
import BaseUIElement from "../BaseUIElement"
import LinkToWeblate from "../Base/LinkToWeblate"
export class Translation extends BaseUIElement {
public static forcedLanguage = undefined;
public static forcedLanguage = undefined
public readonly translations: Record<string, string>
context?: string;
context?: string
constructor(translations: Record<string, string>, context?: string) {
super()
if (translations === undefined) {
console.error("Translation without content at "+context)
console.error("Translation without content at " + context)
throw `Translation without content (${context})`
}
this.context = translations["_context"] ?? context;
if(translations["_context"] !== undefined){
translations = {...translations}
this.context = translations["_context"] ?? context
if (translations["_context"] !== undefined) {
translations = { ...translations }
delete translations["_context"]
}
if (typeof translations === "string") {
translations = {"*": translations};
translations = { "*": translations }
}
let count = 0;
let count = 0
for (const translationsKey in translations) {
if (!translations.hasOwnProperty(translationsKey)) {
continue
}
if(translationsKey === "_context"){
if (translationsKey === "_context") {
continue
}
count++;
if (typeof (translations[translationsKey]) != "string") {
count++
if (typeof translations[translationsKey] != "string") {
console.error("Non-string object in translation: ", translations[translationsKey])
throw "Error in an object depicting a translation: a non-string object was found. (" + context + ")\n You probably put some other section accidentally in the translation"
throw (
"Error in an object depicting a translation: a non-string object was found. (" +
context +
")\n You probably put some other section accidentally in the translation"
)
}
}
this.translations = translations;
this.translations = translations
if (count === 0) {
console.error("Constructing a translation, but the object containing translations is empty "+context)
console.error(
"Constructing a translation, but the object containing translations is empty " +
context
)
throw `Constructing a translation, but the object containing translations is empty (${context})`
}
}
get txt(): string {
return this.textFor(Translation.forcedLanguage ?? Locale.language.data)
}
public toString(){
return this.txt;
}
static ExtractAllTranslationsFrom(object: any, context = ""): { context: string, tr: Translation }[] {
const allTranslations: { context: string, tr: Translation }[] = []
public toString() {
return this.txt
}
static ExtractAllTranslationsFrom(
object: any,
context = ""
): { context: string; tr: Translation }[] {
const allTranslations: { context: string; tr: Translation }[] = []
for (const key in object) {
const v = object[key]
if (v === undefined || v === null) {
continue
}
if (v instanceof Translation) {
allTranslations.push({context: context + "." + key, tr: v})
allTranslations.push({ context: context + "." + key, tr: v })
continue
}
if (typeof v === "object") {
allTranslations.push(...Translation.ExtractAllTranslationsFrom(v, context + "." + key))
allTranslations.push(
...Translation.ExtractAllTranslationsFrom(v, context + "." + key)
)
}
}
return allTranslations
@ -74,7 +84,7 @@ export class Translation extends BaseUIElement {
static fromMap(transl: Map<string, string>) {
const translations = {}
let hasTranslation = false;
let hasTranslation = false
transl?.forEach((value, key) => {
translations[key] = value
hasTranslation = true
@ -82,38 +92,38 @@ export class Translation extends BaseUIElement {
if (!hasTranslation) {
return undefined
}
return new Translation(translations);
return new Translation(translations)
}
Destroy() {
super.Destroy();
this.isDestroyed = true;
super.Destroy()
this.isDestroyed = true
}
public textFor(language: string): string {
if (this.translations["*"]) {
return this.translations["*"];
return this.translations["*"]
}
const txt = this.translations[language];
const txt = this.translations[language]
if (txt !== undefined) {
return txt;
return txt
}
const en = this.translations["en"];
const en = this.translations["en"]
if (en !== undefined) {
return en;
return en
}
for (const i in this.translations) {
if (!this.translations.hasOwnProperty(i)) {
continue;
continue
}
return this.translations[i]; // Return a random language
return this.translations[i] // Return a random language
}
console.error("Missing language ", Locale.language.data, "for", this.translations)
return "";
return ""
}
/**
*
*
* // Should actually change the content based on the current language
* const tr = new Translation({"en":"English", nl: "Nederlands"})
* Locale.language.setData("en")
@ -121,7 +131,7 @@ export class Translation extends BaseUIElement {
* html.innerHTML // => "English"
* Locale.language.setData("nl")
* html.innerHTML // => "Nederlands"
*
*
* // Should include a link to weblate if context is set
* const tr = new Translation({"en":"English"}, "core:test.xyz")
* Locale.language.setData("nl")
@ -135,88 +145,87 @@ export class Translation extends BaseUIElement {
el.innerHTML = self.txt
if (self.translations["*"] !== undefined) {
return el;
return el
}
Locale.language.addCallback(_ => {
Locale.language.addCallback((_) => {
if (self.isDestroyed) {
return true
}
el.innerHTML = self.txt
})
if(self.context === undefined || self.context?.indexOf(":") < 0){
return el;
if (self.context === undefined || self.context?.indexOf(":") < 0) {
return el
}
const linkToWeblate = new LinkToWeblate(self.context, self.translations)
const wrapper = document.createElement("span")
wrapper.appendChild(el)
Locale.showLinkToWeblate.addCallbackAndRun(doShow => {
Locale.showLinkToWeblate.addCallbackAndRun((doShow) => {
if (!doShow) {
return;
return
}
wrapper.appendChild(linkToWeblate.ConstructElement())
return true;
return true
})
return wrapper ;
return wrapper
}
public SupportedLanguages(): string[] {
const langs = []
for (const translationsKey in this.translations) {
if (!this.translations.hasOwnProperty(translationsKey)) {
continue;
continue
}
if (translationsKey === "#") {
continue;
continue
}
if (!this.translations.hasOwnProperty(translationsKey)) {
continue
}
langs.push(translationsKey)
}
return langs;
return langs
}
public AllValues(): string[] {
return this.SupportedLanguages().map(lng => this.translations[lng]);
return this.SupportedLanguages().map((lng) => this.translations[lng])
}
/**
* Constructs a new Translation where every contained string has been modified
*/
public OnEveryLanguage(f: (s: string, language: string) => string, context?: string): Translation {
const newTranslations = {};
public OnEveryLanguage(
f: (s: string, language: string) => string,
context?: string
): Translation {
const newTranslations = {}
for (const lang in this.translations) {
if (!this.translations.hasOwnProperty(lang)) {
continue;
continue
}
newTranslations[lang] = f(this.translations[lang], lang);
newTranslations[lang] = f(this.translations[lang], lang)
}
return new Translation(newTranslations, context ?? this.context);
return new Translation(newTranslations, context ?? this.context)
}
/**
* Replaces the given string with the given text in the language.
* Other substitutions are left in place
*
*
* const tr = new Translation(
* {"nl": "Een voorbeeldtekst met {key} en {key1}, en nogmaals {key}",
* {"nl": "Een voorbeeldtekst met {key} en {key1}, en nogmaals {key}",
* "en": "Just a single {key}"})
* const r = tr.replace("{key}", "value")
* r.textFor("nl") // => "Een voorbeeldtekst met value en {key1}, en nogmaals value"
* r.textFor("en") // => "Just a single value"
*
*
*/
public replace(a: string, b: string) {
return this.OnEveryLanguage(str => str.replace(new RegExp(a, "g"), b))
return this.OnEveryLanguage((str) => str.replace(new RegExp(a, "g"), b))
}
public Clone() {
@ -224,24 +233,23 @@ export class Translation extends BaseUIElement {
}
FirstSentence() {
const tr = {};
const tr = {}
for (const lng in this.translations) {
if (!this.translations.hasOwnProperty(lng)) {
continue
}
let txt = this.translations[lng];
txt = txt.replace(/\..*/, "");
txt = Utils.EllipsesAfter(txt, 255);
tr[lng] = txt;
let txt = this.translations[lng]
txt = txt.replace(/\..*/, "")
txt = Utils.EllipsesAfter(txt, 255)
tr[lng] = txt
}
return new Translation(tr);
return new Translation(tr)
}
/**
* Extracts all images (including HTML-images) from all the embedded translations
*
*
* // should detect sources of <img>
* const tr = new Translation({en: "XYZ <img src='a.svg'/> XYZ <img src=\"some image.svg\"></img> XYZ <img src=b.svg/>"})
* new Set<string>(tr.ExtractImages(false)) // new Set(["a.svg", "b.svg", "some image.svg"])
@ -250,18 +258,22 @@ export class Translation extends BaseUIElement {
const allIcons: string[] = []
for (const key in this.translations) {
if (!this.translations.hasOwnProperty(key)) {
continue;
continue
}
const render = this.translations[key]
if (isIcon) {
const icons = render.split(";").filter(part => part.match(/(\.svg|\.png|\.jpg)$/) != null)
const icons = render
.split(";")
.filter((part) => part.match(/(\.svg|\.png|\.jpg)$/) != null)
allIcons.push(...icons)
} else if (!Utils.runningFromConsole) {
// This might be a tagrendering containing some img as html
const htmlElement = document.createElement("div")
htmlElement.innerHTML = render
const images = Array.from(htmlElement.getElementsByTagName("img")).map(img => img.src)
const images = Array.from(htmlElement.getElementsByTagName("img")).map(
(img) => img.src
)
allIcons.push(...images)
} else {
// We are running this in ts-node (~= nodejs), and can not access document
@ -269,9 +281,12 @@ export class Translation extends BaseUIElement {
try {
const matches = render.match(/<img[^>]+>/g)
if (matches != null) {
const sources = matches.map(img => img.match(/src=("[^"]+"|'[^']+'|[^/ ]+)/))
.filter(match => match != null)
.map(match => match[1].trim().replace(/^['"]/, '').replace(/['"]$/, ''));
const sources = matches
.map((img) => img.match(/src=("[^"]+"|'[^']+'|[^/ ]+)/))
.filter((match) => match != null)
.map((match) =>
match[1].trim().replace(/^['"]/, "").replace(/['"]$/, "")
)
allIcons.push(...sources)
}
} catch (e) {
@ -280,18 +295,17 @@ export class Translation extends BaseUIElement {
}
}
}
return allIcons.filter(icon => icon != undefined)
return allIcons.filter((icon) => icon != undefined)
}
AsMarkdown(): string {
return this.txt
}
}
export class TypedTranslation<T> extends Translation {
constructor(translations: Record<string, string>, context?: string) {
super(translations, context);
super(translations, context)
}
/**
@ -307,29 +321,30 @@ export class TypedTranslation<T> extends Translation {
* const subbed = tr.Subs({part: subpart})
* subbed.textFor("en") // => "Full sentence with subpart"
* subbed.textFor("nl") // => "Volledige zin met onderdeel"
*
*
*/
Subs(text: T, context?: string): Translation {
return this.OnEveryLanguage((template, lang) => {
if(lang === "_context"){
if (lang === "_context") {
return template
}
return Utils.SubstituteKeys(template, text, lang);
return Utils.SubstituteKeys(template, text, lang)
}, context)
}
PartialSubs<X extends string>(text: Partial<T> & Record<X, string>): TypedTranslation<Omit<T, X>> {
const newTranslations : Record<string, string> = {}
PartialSubs<X extends string>(
text: Partial<T> & Record<X, string>
): TypedTranslation<Omit<T, X>> {
const newTranslations: Record<string, string> = {}
for (const lang in this.translations) {
const template = this.translations[lang]
if(lang === "_context"){
newTranslations[lang] = template
if (lang === "_context") {
newTranslations[lang] = template
continue
}
newTranslations[lang] = Utils.SubstituteKeys(template, text, lang)
}
return new TypedTranslation<Omit<T, X>>(newTranslations, this.context)
}
}
}

View file

@ -1,117 +1,124 @@
import {FixedUiElement} from "../Base/FixedUiElement";
import {Translation, TypedTranslation} from "./Translation";
import BaseUIElement from "../BaseUIElement";
import { FixedUiElement } from "../Base/FixedUiElement"
import { Translation, TypedTranslation } from "./Translation"
import BaseUIElement from "../BaseUIElement"
import * as known_languages from "../../assets/generated/used_languages.json"
import CompiledTranslations from "../../assets/generated/CompiledTranslations";
import CompiledTranslations from "../../assets/generated/CompiledTranslations"
export default class Translations {
static readonly t : typeof CompiledTranslations.t & Readonly<typeof CompiledTranslations.t> = CompiledTranslations.t;
static readonly t: typeof CompiledTranslations.t & Readonly<typeof CompiledTranslations.t> =
CompiledTranslations.t
private static knownLanguages = new Set(known_languages.languages)
constructor() {
throw "Translations is static. If you want to intitialize a new translation, use the singular form"
}
public static W(s: string | number | BaseUIElement): BaseUIElement {
if (typeof (s) === "string") {
return new FixedUiElement(s);
if (typeof s === "string") {
return new FixedUiElement(s)
}
if (typeof s === "number") {
return new FixedUiElement("" + s)
}
return s;
return s
}
/**
* Converts a string or an object into a typed translation.
* Translation objects ('Translation' and 'TypedTranslation') are converted/returned
*
*
* Translations.T("some text") // => new TypedTranslation({"*": "some text"})
* Translations.T("some text").txt // => "some text"
*
* const t = new Translation({"nl": "vertaling", "en": "translation"})
* Translations.T(t) // => new TypedTranslation<object>({"nl": "vertaling", "en": "translation"})
*
*
* const t = new TypedTranslation({"nl": "vertaling", "en": "translation"})
* Translations.T(t) // => t
*
*
* const json: any = {"en": "English", "nl": "Nederlands"};
* const translation = Translations.T(new Translation(json));
* translation.textFor("en") // => "English"
* translation.textFor("nl") // => "Nederlands"
*
*
*/
static T(t: string | any, context = undefined): TypedTranslation<object> {
if (t === undefined || t === null) {
return undefined;
return undefined
}
if (typeof t === "number") {
t = "" + t
}
if (typeof t === "string") {
return new TypedTranslation<object>({"*": t}, context);
return new TypedTranslation<object>({ "*": t }, context)
}
if (t.render !== undefined) {
const msg = "Creating a translation, but this object contains a 'render'-field. Use the translation directly"
console.error(msg, t);
const msg =
"Creating a translation, but this object contains a 'render'-field. Use the translation directly"
console.error(msg, t)
throw msg
}
if (t instanceof TypedTranslation) {
return t;
return t
}
if(t instanceof Translation){
if (t instanceof Translation) {
return new TypedTranslation<object>(t.translations)
}
return new TypedTranslation<object>(t, context);
return new TypedTranslation<object>(t, context)
}
public static CountTranslations() {
const queue: any = [Translations.t];
const tr: Translation[] = [];
const queue: any = [Translations.t]
const tr: Translation[] = []
while (queue.length > 0) {
const item = queue.pop();
const item = queue.pop()
if (item instanceof Translation || item.translations !== undefined) {
tr.push(item);
} else if (typeof (item) === "string") {
console.warn("Got single string in translationgs file: ", item);
tr.push(item)
} else if (typeof item === "string") {
console.warn("Got single string in translationgs file: ", item)
} else {
for (const t in item) {
const x = item[t];
const x = item[t]
queue.push(x)
}
}
}
const langaugeCounts = {};
const langaugeCounts = {}
for (const translation of tr) {
for (const language in translation.translations) {
if (langaugeCounts[language] === undefined) {
langaugeCounts[language] = 1
} else {
langaugeCounts[language]++;
langaugeCounts[language]++
}
}
}
for (const language in langaugeCounts) {
console.log("Total translations in ", language, langaugeCounts[language], "/", tr.length)
console.log(
"Total translations in ",
language,
langaugeCounts[language],
"/",
tr.length
)
}
}
static isProbablyATranslation(transl: any) {
if(typeof transl !== "object"){
return false;
if (typeof transl !== "object") {
return false
}
if(Object.keys(transl).length == 0){
if (Object.keys(transl).length == 0) {
// No translations found; not a translation
return false
}
// is a weird key found?
if(Object.keys(transl).some(key => key !== '_context' && !this.knownLanguages.has(key))){
if (
Object.keys(transl).some((key) => key !== "_context" && !this.knownLanguages.has(key))
) {
return false
}
return true;
return true
}
}